1692 lines
60 KiB
C++
1692 lines
60 KiB
C++
//
|
|
// audio/trainaudioentity.cpp
|
|
//
|
|
// Copyright (C) 1999-2006 Rockstar Games. All Rights Reserved.
|
|
//
|
|
|
|
#include "northaudioengine.h"
|
|
#include "vehicleaudioentity.h"
|
|
#include "policescanner.h"
|
|
#include "radioaudioentity.h"
|
|
#include "trainaudioentity.h"
|
|
|
|
#include "animation/animbones.h"
|
|
#include "audioengine/engine.h"
|
|
#include "audioengine/engineutil.h"
|
|
#include "audiohardware/driverdefs.h"
|
|
#include "audiohardware/driverutil.h"
|
|
#include "audiosoundtypes/sound.h"
|
|
#include "audiosoundtypes/soundcontrol.h"
|
|
#include "game/zones.h"
|
|
#include "crskeleton/skeleton.h"
|
|
#include "debug/debugglobals.h"
|
|
#include "grcore/debugdraw.h"
|
|
#include "modelinfo/vehiclemodelinfo.h"
|
|
#include "phbound/boundcomposite.h"
|
|
#include "physics/gtaMaterialManager.h"
|
|
#include "fwsys/timer.h"
|
|
#include "vehicles/automobile.h"
|
|
#include "vehicles/heli.h"
|
|
#include "vehicles/train.h"
|
|
#include "vehicles/vehicle.h"
|
|
#include "math/simplemath.h"
|
|
#include "debugaudio.h"
|
|
|
|
AUDIO_VEHICLES_OPTIMISATIONS()
|
|
|
|
#define AUD_TRAINANNOUNCER_ENABLED (NA_POLICESCANNER_ENABLED&&0)
|
|
|
|
const f32 g_audTrainMinDoubleWheelSpeed = 1.0f;
|
|
f32 g_CableCarClunkSpeed = 0.015f;
|
|
f32 g_MinTautWireSpeed = 0.4f;
|
|
f32 g_MaxTautWireSpeed = 0.9f;
|
|
u32 g_MinTautWireTime = 1500;
|
|
u32 g_MaxTautWireTime = 2000;
|
|
s32 g_NextTrainStartOffset = 0;
|
|
f32 g_AngleSmootherRate = 0.1f;
|
|
f32 g_BrakeVolSmootherIncreaseRate = 0.1f;
|
|
f32 g_BrakeVolSmootherDecreaseRate = 0.05f;
|
|
f32 g_TrainActivationRangeTimeScale = 2.0f;
|
|
u32 g_MaxRealTrains = 5;
|
|
f32 g_TrainActivationRange2 = 400.0f * 400.0f;
|
|
f32 g_TrainDistanceFactorMaxDist = 300.0f;
|
|
|
|
audCurve audTrainAudioEntity::sm_TrainDistanceToAttackTime;
|
|
u32 audTrainAudioEntity::sm_NumTrainsInActivationRange = 0u;
|
|
f32 audTrainAudioEntity::sm_TrainActivationRangeScale = 1.0f;
|
|
u8 audTrainAudioEntity::sm_TrackUpdateRumbleFrameIndex = 0;
|
|
|
|
extern RegdEnt g_AudioDebugEntity;
|
|
extern CTrainTrack gTrainTracks[MAX_TRAIN_TRACKS_PER_LEVEL];
|
|
extern TrainStation *g_audTrainStations[MAX_TRAIN_TRACKS_PER_LEVEL][MAX_NUM_STATIONS];
|
|
extern u32 g_SuperDummyRadiusSq;
|
|
|
|
BANK_ONLY(bool g_DebugTrain = false;)
|
|
BANK_ONLY(bool g_DebugActiveCarriages = false;)
|
|
BANK_ONLY(bool g_DebugBrakeSounds = false;)
|
|
BANK_ONLY(bool g_ForceCableCar = false;)
|
|
BANK_ONLY(f32 g_DrawCarriageInfoScroll = 0.0f;)
|
|
BANK_ONLY(f32 g_RumbleVolumeTrim = 0.0f;)
|
|
BANK_ONLY(f32 g_GrindVolumeTrim = 0.0f;)
|
|
BANK_ONLY(f32 g_SquealVolumeTrim = 0.0f;)
|
|
BANK_ONLY(f32 g_CarriageVolumeTrim = 0.0f;)
|
|
BANK_ONLY(f32 g_BrakeVolumeTrim = 0.0f;)
|
|
|
|
// ----------------------------------------------------------------
|
|
// audTrainAudioEntity constructor
|
|
// ----------------------------------------------------------------
|
|
audTrainAudioEntity::audTrainAudioEntity() : audVehicleAudioEntity()
|
|
{
|
|
m_VehicleType = AUD_VEHICLE_TRAIN;
|
|
m_TrainCarriage = m_TrainDriveTone = m_TrainDriveToneSynth = m_TrainGrind = m_TrainSqueal = NULL;
|
|
m_TrainIdle = m_TrainRumble = m_TrainBrakes = m_ApproachingTrainRumble = NULL;
|
|
m_AngleSmoother.Init(g_AngleSmootherRate);
|
|
m_TrainDistanceFactorSmoother.Init(0.05f);
|
|
m_BrakeVolumeSmoother.Init(g_BrakeVolSmootherIncreaseRate, g_BrakeVolSmootherDecreaseRate);
|
|
m_TrackRumbleUpdateFrame = 0;
|
|
m_ShockwaveId = kInvalidShockwaveId;
|
|
m_VehicleLOD = AUD_VEHICLE_LOD_DISABLED;
|
|
}
|
|
audTrainAudioEntity::~audTrainAudioEntity()
|
|
{
|
|
if(m_ShockwaveId != kInvalidShockwaveId)
|
|
{
|
|
audNorthAudioEngine::GetGtaEnvironment()->FreeShockwave(m_ShockwaveId);
|
|
m_ShockwaveId = kInvalidShockwaveId;
|
|
}
|
|
}
|
|
// ----------------------------------------------------------------
|
|
// audTrainAudioEntity reset
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::Reset()
|
|
{
|
|
audVehicleAudioEntity::Reset();
|
|
m_TrainSpeed = 0.0f;
|
|
m_TrainDistance = 0.0f;
|
|
m_TrainAcceleration = 0.0f;
|
|
m_TrainAudioSettings = NULL;
|
|
m_TrainBrakeReleaseNextTriggerTime = 0;
|
|
m_NumTrackNodesSearched = 0;
|
|
m_TrainAirHornNextTriggerTime = 0;
|
|
m_TimeElapsedTrainTurn = 0.0f;
|
|
m_TrainLastWheelTriggerTime = 0;
|
|
m_LastTrainAnnouncement = 0;
|
|
m_FramesAtDesiredLOD = 0;
|
|
m_DesiredLODLastFrame = AUD_VEHICLE_LOD_DISABLED;
|
|
m_LastStationAnnounced = ~0U;
|
|
m_AnnouncedCurrentStation = m_AnnouncedNextStation = -1;
|
|
m_TrainEngine = false;
|
|
m_LinkedBackwards = false;
|
|
m_LinkedTrainValid = false;
|
|
m_LinkedTrainMatrixCol0 = Vec3V(V_ZERO);
|
|
m_LinkedTrainMatrixCol1 = Vec3V(V_ZERO);
|
|
m_ClosestCarriageToListenerPos = Vec3V(V_ZERO);
|
|
m_ClosestPointOnTrainToListener.Zero();
|
|
m_RumblePositioningLineValid = false;
|
|
m_HasPlayedBigBrakeRelease = true;
|
|
m_TimeAtCurrentLOD = 1.0f;
|
|
m_TrainDistanceFactorSmoother.Reset();
|
|
m_AngleSmoother.Reset();
|
|
m_BrakeVolumeSmoother.Reset();
|
|
m_VehicleLOD = AUD_VEHICLE_LOD_DISABLED;
|
|
if(m_ShockwaveId != kInvalidShockwaveId)
|
|
{
|
|
audNorthAudioEngine::GetGtaEnvironment()->FreeShockwave(m_ShockwaveId);
|
|
m_ShockwaveId = kInvalidShockwaveId;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Initialise the train class
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::InitClass()
|
|
{
|
|
StaticConditionalWarning(sm_TrainDistanceToAttackTime.Init(ATSTRINGHASH("TRAIN_DISTANCE_TO_ATTACK_TIME", 0x169D5852)), "Invalid TRAIN_DISTANCE_TO_ATTACK_TIME");
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Initialise our train settings
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::InitTrainSettings()
|
|
{
|
|
// Init train audio settings
|
|
m_TrainAudioSettings = GetTrainAudioSettings();
|
|
|
|
if(m_TrainAudioSettings)
|
|
{
|
|
// Init curves for train audio entity
|
|
ConditionalWarning(m_CarriagePitchCurve.Init(m_TrainAudioSettings->CarriagePitchCurve), "Invalid m_CarriagePitchCurve");
|
|
ConditionalWarning(m_CarriageVolumeCurve.Init(m_TrainAudioSettings->CarriageVolumeCurve), "Invalid m_CarriagePitchCurve");
|
|
ConditionalWarning(m_DriveTonePitchCurve.Init(m_TrainAudioSettings->DriveTonePitchCurve), "Invalid m_DriveTonePitchCurve");
|
|
ConditionalWarning(m_DriveToneVolumeCurve.Init(m_TrainAudioSettings->DriveToneVolumeCurve), "Invalid m_DriveToneVolumeCurve");
|
|
ConditionalWarning(m_DriveToneSynthPitchCurve.Init(m_TrainAudioSettings->DriveToneSynthPitchCurve), "Invalid m_DriveToneSynthPitchCurve");
|
|
ConditionalWarning(m_DriveToneSynthVolumeCurve.Init(m_TrainAudioSettings->DriveToneSynthVolumeCurve), "Invalid m_DriveToneSynthVolumeCurve");
|
|
ConditionalWarning(m_GrindPitchCurve.Init(m_TrainAudioSettings->GrindPitchCurve), "Invalid m_GrindPitchCurve");
|
|
ConditionalWarning(m_GrindVolumeCurve.Init(m_TrainAudioSettings->GrindVolumeCurve), "Invalid m_GrindVolumeCurve");
|
|
ConditionalWarning(m_TrainIdlePitchCurve.Init(m_TrainAudioSettings->TrainIdlePitchCurve), "Invalid m_IdlePitchCurve");
|
|
ConditionalWarning(m_TrainIdleVolumeCurve.Init(m_TrainAudioSettings->TrainIdleVolumeCurve), "Invalid m_IdleVolumeCurve");
|
|
ConditionalWarning(m_SquealPitchCurve.Init(m_TrainAudioSettings->SquealPitchCurve), "Invalid m_SquealPitchCurve");
|
|
ConditionalWarning(m_SquealVolumeCurve.Init(m_TrainAudioSettings->SquealVolumeCurve), "Invalid m_SquealVolumeCurve");
|
|
ConditionalWarning(m_ScrapeSpeedVolumeCurve.Init(m_TrainAudioSettings->ScrapeSpeedVolumeCurve), "Invalid m_ScrapeSpeedVolumeCurve");
|
|
ConditionalWarning(m_WheelVolumeCurve.Init(m_TrainAudioSettings->WheelVolumeCurve), "Invalid m_WheelVolumeCurve");
|
|
ConditionalWarning(m_WheelDelayCurve.Init(m_TrainAudioSettings->WheelVolumeCurve), "Invalid m_WheelDelayCurve");
|
|
ConditionalWarning(m_RumbleVolumeCurve.Init(m_TrainAudioSettings->RumbleVolumeCurve), "Invalid m_RumbleVolumeCurve");
|
|
ConditionalWarning(m_BrakeVelocityPitchCurve.Init(m_TrainAudioSettings->BrakeVelocityPitchCurve), "Invalid sm_BrakeVelocityPitchCurve");
|
|
ConditionalWarning(m_BrakeVelocityVolumeCurve.Init(m_TrainAudioSettings->BrakeVelocityVolumeCurve), "Invalid sm_BrakeVelocityVolumeCurve");
|
|
ConditionalWarning(m_BrakeAccelerationPitchCurve.Init(m_TrainAudioSettings->BrakeAccelerationPitchCurve), "Invalid sm_BrakeAccelerationPitchCurve");
|
|
ConditionalWarning(m_BrakeAccelerationVolumeCurve.Init(m_TrainAudioSettings->BrakeAccelerationVolumeCurve), "Invalid sm_BrakeAccelerationVolumeCurve");
|
|
ConditionalWarning(m_ApproachingRumbleDistanceToIntensity.Init(m_TrainAudioSettings->TrackRumbleDistanceToIntensity), "Invalid TrackRumbleDistanceToIntensityCurve");
|
|
ConditionalWarning(m_TrainDistanceToRollOff.Init(m_TrainAudioSettings->TrainDistanceToRollOffScale), "Invalid TrainDistanceToRollOffScale");
|
|
m_VehicleHornHash = m_TrainAudioSettings->AirHornOneShot;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Init anything train specific
|
|
// ----------------------------------------------------------------
|
|
bool audTrainAudioEntity::InitVehicleSpecific()
|
|
{
|
|
CTrain *train = (CTrain*)m_Vehicle;
|
|
|
|
InitTrainSettings();
|
|
|
|
if(!m_TrainAudioSettings)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// no radio for trains
|
|
NA_RADIO_ENABLED_ONLY(m_RadioType = RADIO_TYPE_NONE);
|
|
|
|
// See if we're the front one
|
|
m_TrainEngine = train->IsEngine();
|
|
|
|
if(m_TrainEngine)
|
|
{
|
|
m_TrackRumbleUpdateFrame = sm_TrackUpdateRumbleFrameIndex;
|
|
sm_TrackUpdateRumbleFrameIndex++;
|
|
|
|
if(sm_TrackUpdateRumbleFrameIndex > 31)
|
|
{
|
|
sm_TrackUpdateRumbleFrameIndex = 0;
|
|
}
|
|
}
|
|
|
|
SetEnvironmentGroupSettings(false, audNorthAudioEngine::GetOcclusionManager()->GetMaxOcclusionPathDepth());
|
|
|
|
#if 0
|
|
f32 innerMap[5][3] = { { 0.0f, 0.0f, 0.0f},
|
|
{ 1.8f, 8.0f, 0.0f},
|
|
{ 1.8f, -8.0f, 0.0f},
|
|
{-1.8f, 8.0f, 0.0f},
|
|
{-1.8f, -8.0f, 0.0f}};
|
|
|
|
f32 outerMap[8][3] = { { 2.5f, 10.0f, 2.0f},
|
|
{ 2.5f, -10.0f, 2.0f},
|
|
{-2.5f, 10.0f, 2.0f},
|
|
{-2.5f, -10.0f, 2.0f},
|
|
{ 2.5f, 10.0f, -2.0f},
|
|
{ 2.5f, -10.0f, -2.0f},
|
|
{-2.5f, 10.0f, -2.0f},
|
|
{-2.5f, -10.0f, -2.0f}};
|
|
|
|
if (m_OcclusionGroup)
|
|
{
|
|
m_OcclusionGroup->SetBounds(innerMap, outerMap);
|
|
}
|
|
#endif
|
|
|
|
m_TrainStartOffset = g_NextTrainStartOffset;
|
|
g_NextTrainStartOffset += 25;
|
|
if(g_NextTrainStartOffset >= 100)
|
|
{
|
|
g_NextTrainStartOffset = 0;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Post update
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::PostUpdate()
|
|
{
|
|
audVehicleAudioEntity::PostUpdate();
|
|
|
|
if(m_Vehicle)
|
|
{
|
|
CTrain *train = (CTrain*)m_Vehicle;
|
|
CTrain* linkedTrain = NULL;
|
|
|
|
m_LinkedBackwards = true;
|
|
m_LinkedTrainValid = false;
|
|
|
|
if (train->GetLinkedToBackward())
|
|
{
|
|
linkedTrain = train->GetLinkedToBackward();
|
|
}
|
|
else if (train->GetLinkedToForward())
|
|
{
|
|
linkedTrain = train->GetLinkedToForward();
|
|
m_LinkedBackwards = false;
|
|
}
|
|
|
|
if(linkedTrain)
|
|
{
|
|
m_LinkedTrainValid = true;
|
|
m_LinkedTrainMatrixCol0 = linkedTrain->GetTransform().GetA();
|
|
m_LinkedTrainMatrixCol1 = linkedTrain->GetTransform().GetB();
|
|
}
|
|
|
|
if(m_TrainEngine && train->GetTrackIndex() >= 0)
|
|
{
|
|
CTrainTrack* trainTrack = CTrain::GetTrainTrack(train->GetTrackIndex());
|
|
Vector3 listenerPos = VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetVolumeListenerPosition());
|
|
CTrain* closestTrain = FindClosestLinkedCarriage(listenerPos);
|
|
|
|
if(closestTrain)
|
|
{
|
|
m_ClosestCarriageToListenerPos = closestTrain->GetTransform().GetPosition();
|
|
|
|
Vector3 closestPoint;
|
|
Vector3 forward = VEC3V_TO_VECTOR3(closestTrain->GetMatrix().b());
|
|
Vector3 vehiclePosition = VEC3V_TO_VECTOR3(closestTrain->GetVehiclePosition());
|
|
f32 vehicleLength = closestTrain->GetBoundSphere().GetRadiusf();
|
|
|
|
// Carriages can be different heights (eg. engine vs. freight) so ensure that we move smoothly between them
|
|
f32 trainHeightEnd = closestTrain->GetVehiclePosition().GetZf();
|
|
f32 trainHeightStart = closestTrain->GetLinkedToBackward()? closestTrain->GetLinkedToBackward()->GetVehiclePosition().GetZf() : trainHeightEnd;
|
|
fwGeom::fwLine positioningLine = fwGeom::fwLine(vehiclePosition - (forward * vehicleLength), vehiclePosition + (forward * vehicleLength));
|
|
positioningLine.m_start.SetZ(trainHeightStart);
|
|
positioningLine.m_end.SetZ(trainHeightEnd);
|
|
positioningLine.FindClosestPointOnLine(listenerPos, m_ClosestPointOnTrainToListener);
|
|
|
|
// Train tracks can be pretty long, and no need to be super accurate here so no point searching through them every frame
|
|
if((fwTimer::GetSystemFrameCount() & 31) == m_TrackRumbleUpdateFrame)
|
|
{
|
|
if(trainTrack)
|
|
{
|
|
s32 closestNode = CTrain::FindClosestNodeOnTrack(listenerPos, CTrainTrack::GetTrackIndex(trainTrack), closestTrain->GetCurrentNode(), g_TrainDistanceFactorMaxDist, m_NumTrackNodesSearched);
|
|
|
|
if(closestNode >= 0)
|
|
{
|
|
s32 prevNode = closestNode - 1;
|
|
s32 nextNode = closestNode + 1;
|
|
|
|
if(prevNode < 0)
|
|
{
|
|
prevNode = trainTrack->m_numNodes - 1;
|
|
}
|
|
|
|
if(nextNode >= trainTrack->m_numNodes)
|
|
{
|
|
nextNode = 0;
|
|
}
|
|
|
|
// We know the closest node, work out the 2nd closest, and the line between the two as our positioning line
|
|
Vector3 trackCoords = trainTrack->GetNode(closestNode)->GetCoors();
|
|
Vector3 prevCoords = trainTrack->GetNode(prevNode)->GetCoors();
|
|
Vector3 nextCoords = trainTrack->GetNode(nextNode)->GetCoors();
|
|
m_TrackRumblePositioningLine.Set(trackCoords, prevCoords.Dist2(listenerPos) < nextCoords.Dist2(listenerPos) ? prevCoords : nextCoords);
|
|
|
|
// Push the start and end points back a bit. We're not updating the positioning line every frame so need it to have a bit of slack
|
|
Vector3 normalisedVector = m_TrackRumblePositioningLine.m_end - m_TrackRumblePositioningLine.m_start;
|
|
normalisedVector.NormalizeFast();
|
|
normalisedVector *= 20.0f;
|
|
|
|
m_TrackRumblePositioningLine.m_end += normalisedVector;
|
|
m_TrackRumblePositioningLine.m_start -= normalisedVector;
|
|
m_RumblePositioningLineValid = true;
|
|
}
|
|
else
|
|
{
|
|
m_RumblePositioningLineValid = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update anything train specific
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::UpdateVehicleSpecific(audVehicleVariables& vehicleVariables, audVehicleDSPSettings& UNUSED_PARAM(variables))
|
|
{
|
|
if (!g_AudioEngine.IsAudioEnabled())
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if __BANK
|
|
m_AngleSmoother.SetRate(g_AngleSmootherRate);
|
|
m_BrakeVolumeSmoother.SetRates(g_BrakeVolSmootherIncreaseRate, g_BrakeVolSmootherDecreaseRate);
|
|
#endif
|
|
|
|
CTrain *train = (CTrain*)m_Vehicle;
|
|
m_TimeAtCurrentLOD += fwTimer::GetTimeStep();
|
|
audVehicleLOD desiredLod = AUD_VEHICLE_LOD_DISABLED;
|
|
|
|
u32 vehicleLODDistance = vehicleVariables.visibleBySniper? Min(vehicleVariables.distFromListenerSq, GetDistance2FromSniperAimVector()) : vehicleVariables.distFromListenerSq;
|
|
|
|
if(vehicleLODDistance < g_TrainActivationRange2 * sm_TrainActivationRangeScale || m_TrainEngine)
|
|
{
|
|
if(!m_TrainEngine)
|
|
{
|
|
sm_NumTrainsInActivationRange++;
|
|
}
|
|
|
|
desiredLod = AUD_VEHICLE_LOD_REAL;
|
|
}
|
|
|
|
if(desiredLod == m_DesiredLODLastFrame)
|
|
{
|
|
m_FramesAtDesiredLOD++;
|
|
}
|
|
else
|
|
{
|
|
m_FramesAtDesiredLOD = 0;
|
|
}
|
|
|
|
if(desiredLod != m_VehicleLOD &&
|
|
m_FramesAtDesiredLOD > 3 &&
|
|
(m_TimeAtCurrentLOD > 1.0f || desiredLod > m_VehicleLOD))
|
|
{
|
|
SetLOD(desiredLod);
|
|
m_TimeAtCurrentLOD = 0.0f;
|
|
}
|
|
|
|
m_DesiredLODLastFrame = desiredLod;
|
|
|
|
if(!IsDisabled())
|
|
{
|
|
m_TrainDistance = Dist(m_Vehicle->GetVehiclePosition(), g_AudioEngine.GetEnvironment().GetVolumeListenerPosition()).Getf();
|
|
f32 rollOffScalar = 1.0f;
|
|
|
|
if(m_TrainDistanceToRollOff.IsValid())
|
|
{
|
|
rollOffScalar = m_TrainDistanceToRollOff.CalculateValue(m_TrainDistance);
|
|
}
|
|
|
|
if (train->CarriagesAreSuspended() BANK_ONLY(|| g_ForceCableCar))
|
|
{
|
|
UpdateCableCarSounds();
|
|
}
|
|
else
|
|
{
|
|
UpdateTrainAmbientSounds(rollOffScalar);
|
|
}
|
|
|
|
if (!train->CarriagesAreSuspended() && m_TrainEngine)
|
|
{
|
|
UpdateTrainEngineSounds(rollOffScalar);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StopTrainAmbientSounds(2000);
|
|
StopTrainEngineSounds(2000);
|
|
}
|
|
|
|
#if __BANK
|
|
UpdateDebug();
|
|
#endif
|
|
|
|
bool shouldTriggerShockwave = false;
|
|
|
|
// trigger shockwave loops for surrounding environment
|
|
if(m_TrainEngine && train->GetTrackIndex() >= 0)
|
|
{
|
|
Vector3 listenerPos = VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetVolumeListenerPosition());
|
|
|
|
if(m_RumblePositioningLineValid || m_ApproachingTrainRumble)
|
|
{
|
|
Vector3 closestPoint;
|
|
m_TrackRumblePositioningLine.FindClosestPointOnLine(listenerPos, closestPoint);
|
|
f32 speedFactor = Clamp(Abs(train->m_trackForwardSpeed- 1.0f)/10.0f, 0.0f, 1.0f);
|
|
f32 trainDistance = closestPoint.Dist(VEC3V_TO_VECTOR3(m_ClosestCarriageToListenerPos));
|
|
f32 distanceFactor = m_TrainDistanceFactorSmoother.CalculateValue(m_ApproachingRumbleDistanceToIntensity.CalculateValue(trainDistance));
|
|
|
|
shouldTriggerShockwave = !m_Vehicle->GetIsInInterior();
|
|
CPed* pPlayer = CGameWorld::FindLocalPlayer();
|
|
shouldTriggerShockwave = shouldTriggerShockwave || (m_Vehicle->GetIsInInterior() && pPlayer && pPlayer->GetIsInInterior() && m_Vehicle->GetAudioInteriorLocation().IsSameLocation(pPlayer->GetAudioInteriorLocation()));
|
|
if(shouldTriggerShockwave)
|
|
{
|
|
// Shockwave is positioned at the closest point on the tracks, and scales up in intensity as the train approaches
|
|
f32 distanceIntensityFactor = trainDistance/ naEnvironment::sm_TrainDistanceThreshold;
|
|
distanceIntensityFactor = 1.f - Min (distanceIntensityFactor, 1.f);
|
|
audShockwave shockwave;
|
|
shockwave.radius = naEnvironment::sm_TrainShockwaveRadius;
|
|
shockwave.centre = closestPoint;
|
|
shockwave.intensity = Clamp((train->m_trackForwardSpeed/10.f) * distanceIntensityFactor, 0.0f, 1.0f);
|
|
shockwave.centered = true;
|
|
audNorthAudioEngine::GetGtaEnvironment()->UpdateShockwave(m_ShockwaveId, shockwave);
|
|
}
|
|
|
|
if(!m_ApproachingTrainRumble && m_RumblePositioningLineValid)
|
|
{
|
|
CreateAndPlaySound_Persistent(m_TrainAudioSettings->TrainApproachTrackRumble, &m_ApproachingTrainRumble);
|
|
}
|
|
|
|
f32 volumeLin = speedFactor * distanceFactor;
|
|
|
|
if(m_ApproachingTrainRumble)
|
|
{
|
|
if(volumeLin > 0.0f)
|
|
{
|
|
m_ApproachingTrainRumble->SetReleaseTime(2000);
|
|
m_ApproachingTrainRumble->SetRequestedPosition(closestPoint);
|
|
m_ApproachingTrainRumble->SetRequestedVolume(audDriverUtil::ComputeDbVolumeFromLinear(volumeLin));
|
|
m_ApproachingTrainRumble->SetRequestedDopplerFactor(0.0f);
|
|
}
|
|
else
|
|
{
|
|
StopAndForgetSounds(m_ApproachingTrainRumble);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !shouldTriggerShockwave && m_ShockwaveId != kInvalidShockwaveId)
|
|
{
|
|
audNorthAudioEngine::GetGtaEnvironment()->FreeShockwave(m_ShockwaveId);
|
|
m_ShockwaveId = kInvalidShockwaveId;
|
|
}
|
|
|
|
if(train->m_nTrainFlags.bEngine && train->AnnouncesStations())
|
|
{
|
|
if(!train->m_nTrainFlags.bAtStation && ((m_Vehicle->GetRandomSeed() + fwTimer::GetSystemFrameCount()) & 15) && train->m_nextStation > 0 && (train->m_trackIndex >= 0) && train->m_nextStation < gTrainTracks[train->m_trackIndex].m_numStations)
|
|
{
|
|
bool shouldAnnounce = (train->m_trackIndex >= 0) && (train->IsLocalPlayerSeatedInAnyCarriage() || ((VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetVolumeListenerPosition()) - gTrainTracks[train->m_trackIndex].m_aStationCoors[train->m_nextStation]).Mag2() < (50.f * 50.f)));
|
|
if(shouldAnnounce)
|
|
{
|
|
s32 nextStation = train->m_nextStation;
|
|
f32 stationPosOnTrack = gTrainTracks[train->m_trackIndex].m_aStationDistFromStart[nextStation];
|
|
|
|
//grcDebugDraw::AddDebugOutput("%d %f", train->m_nextStation, (stationPosOnTrack - train->m_trackPosFront) / train->m_linearSpeed);
|
|
if(m_LastStationAnnounced != nextStation)
|
|
{
|
|
// roughly how long till we get there?
|
|
f32 time = (stationPosOnTrack - train->m_trackPosFront) / train->m_trackForwardSpeed;
|
|
|
|
// announce 12s before arrival
|
|
if(time > 4.f && time < 12.f)
|
|
{
|
|
m_LastStationAnnounced = nextStation;
|
|
AnnounceNextStation(nextStation);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if(train->IsLocalPlayerSeatedInThisCarriage())
|
|
// {
|
|
//#if DEBUG_DRAW
|
|
// if(train->m_trackIndex >= 0)
|
|
// {
|
|
// grcDebugDraw::AddDebugOutput("current station: %s [%d] next station: %s [%d] Time til next station: %d", train->GetStationName(train->GetCurrentStation()), train->GetCurrentStation(), train->GetStationName(train->GetNextStation()), train->GetNextStation(), train->GetTimeTilNextStation());
|
|
// }
|
|
//#endif // DEBUG_DRAW
|
|
// }
|
|
|
|
SetEnvironmentGroupSettings(false, audNorthAudioEngine::GetOcclusionManager()->GetMaxOcclusionPathDepth());
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Find the closest linked carriage to the given position
|
|
// ----------------------------------------------------------------
|
|
CTrain* audTrainAudioEntity::FindClosestLinkedCarriage(Vector3::Param position)
|
|
{
|
|
CTrain* thisTrain = (CTrain*) m_Vehicle;
|
|
CTrain* closestTrain = thisTrain;
|
|
f32 closestDistSq = VEC3V_TO_VECTOR3(thisTrain->GetTransform().GetPosition()).Dist2(position);
|
|
u32 numCarriages = thisTrain->GetNumCarriages();
|
|
u32 iterations = 0;
|
|
|
|
while(thisTrain->GetLinkedToForward() && iterations < numCarriages)
|
|
{
|
|
thisTrain = thisTrain->GetLinkedToForward();
|
|
f32 distSq = VEC3V_TO_VECTOR3(thisTrain->GetTransform().GetPosition()).Dist2(position);
|
|
|
|
if(distSq < closestDistSq)
|
|
{
|
|
closestDistSq = distSq;
|
|
closestTrain = thisTrain;
|
|
}
|
|
|
|
iterations++;
|
|
}
|
|
|
|
thisTrain = (CTrain*) m_Vehicle;
|
|
iterations = 0;
|
|
|
|
while(thisTrain->GetLinkedToBackward() && iterations < numCarriages)
|
|
{
|
|
thisTrain = thisTrain->GetLinkedToBackward();
|
|
f32 distSq = VEC3V_TO_VECTOR3(thisTrain->GetTransform().GetPosition()).Dist2(position);
|
|
|
|
if(distSq < closestDistSq)
|
|
{
|
|
closestDistSq = distSq;
|
|
closestTrain = thisTrain;
|
|
}
|
|
|
|
iterations++;
|
|
}
|
|
|
|
return closestTrain;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update activation ranges for trains
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::UpdateActivationRanges()
|
|
{
|
|
if(sm_NumTrainsInActivationRange > g_MaxRealTrains)
|
|
{
|
|
sm_TrainActivationRangeScale -= fwTimer::GetTimeStep() * g_TrainActivationRangeTimeScale;
|
|
}
|
|
else if(sm_NumTrainsInActivationRange < g_MaxRealTrains)
|
|
{
|
|
sm_TrainActivationRangeScale += fwTimer::GetTimeStep() * g_TrainActivationRangeTimeScale;
|
|
}
|
|
|
|
sm_TrainActivationRangeScale = Clamp(sm_TrainActivationRangeScale, 0.01f, 1.0f);
|
|
sm_NumTrainsInActivationRange = 0;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger a door open sound
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::TriggerDoorOpenSound(eHierarchyId doorId)
|
|
{
|
|
TriggerDoorSound(ATSTRINGHASH("VEHICLES_TRAIN_SUBWAY_DOORS_OPEN", 0x11302684), doorId);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger a door shut sound
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::TriggerDoorCloseSound(eHierarchyId doorId, const bool UNUSED_PARAM(isBroken))
|
|
{
|
|
TriggerDoorSound(ATSTRINGHASH("VEHICLES_TRAIN_SUBWAY_DOORS_CLOSE", 0x8C0B7A92), doorId);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Generic start sequence for train sounds
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::StartTrainSound(u32 soundID, audSound** sound, audSoundInitParams* initParams, u32 releaseTime)
|
|
{
|
|
if (!(*sound))
|
|
{
|
|
CreateSound_PersistentReference(soundID, sound, initParams);
|
|
|
|
if(*sound)
|
|
{
|
|
(*sound)->SetReleaseTime(releaseTime);
|
|
(*sound)->PrepareAndPlay();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update train sounds
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::UpdateTrainEngineSounds(f32 rolloffScalar)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.Tracker = m_Vehicle->GetPlaceableTracker();
|
|
initParams.UpdateEntity = true;
|
|
initParams.AttackTime = (u32)(sm_TrainDistanceToAttackTime.CalculateValue(m_TrainDistance) * 1000.0f);
|
|
|
|
if(!m_TrainDriveTone)
|
|
{
|
|
StartTrainSound(m_TrainAudioSettings->DriveTone, &m_TrainDriveTone, &initParams, 2000);
|
|
}
|
|
|
|
if(!m_TrainDriveToneSynth)
|
|
{
|
|
StartTrainSound(m_TrainAudioSettings->DriveToneSynth, &m_TrainDriveToneSynth, &initParams, 2000);
|
|
}
|
|
|
|
if(!m_TrainIdle)
|
|
{
|
|
StartTrainSound(m_TrainAudioSettings->IdleLoop, &m_TrainIdle, &initParams, 2000);
|
|
}
|
|
|
|
if(!m_TrainRumble)
|
|
{
|
|
initParams.Tracker = NULL;
|
|
StartTrainSound(m_TrainAudioSettings->AmbientRumble, &m_TrainRumble, &initParams, 2000);
|
|
}
|
|
|
|
if(!m_TrainBrakes)
|
|
{
|
|
initParams.Tracker = NULL;
|
|
StartTrainSound(m_TrainAudioSettings->Brakes, &m_TrainBrakes, &initParams, 2000);
|
|
}
|
|
|
|
// Work out our speed
|
|
CTrain* train = (CTrain*)m_Vehicle;
|
|
f32 trainSpeed = 0.0f;
|
|
|
|
trainSpeed = train->m_trackForwardSpeed;
|
|
|
|
// m_linearSpeed is the speed along the positive direction of the trackIndex. We are interested
|
|
// in the speed in the direction of the train however.
|
|
if (!(train->m_nTrainFlags.bDirectionTrackForward))
|
|
{
|
|
trainSpeed = -trainSpeed;
|
|
}
|
|
|
|
if(m_TrainDriveTone)
|
|
{
|
|
f32 driveToneVolume = m_DriveToneVolumeCurve.CalculateValue(trainSpeed);
|
|
f32 driveTonePitch = m_DriveTonePitchCurve.CalculateValue(trainSpeed);
|
|
m_TrainDriveTone->SetRequestedVolume(driveToneVolume);
|
|
m_TrainDriveTone->SetRequestedPitch((s32)driveTonePitch);
|
|
m_TrainDriveTone->SetRequestedVolumeCurveScale(rolloffScalar);
|
|
}
|
|
|
|
if(m_TrainDriveToneSynth)
|
|
{
|
|
f32 driveToneSynthVolume = m_DriveToneSynthVolumeCurve.CalculateValue(trainSpeed);
|
|
f32 driveToneSynthPitch = m_DriveToneSynthPitchCurve.CalculateValue(trainSpeed);
|
|
m_TrainDriveToneSynth->SetRequestedVolume(driveToneSynthVolume);
|
|
m_TrainDriveToneSynth->SetRequestedPitch((s32)driveToneSynthPitch);
|
|
m_TrainDriveToneSynth->SetRequestedVolumeCurveScale(rolloffScalar);
|
|
}
|
|
|
|
if(m_TrainIdle)
|
|
{
|
|
f32 idleVolume = m_TrainIdleVolumeCurve.CalculateValue(trainSpeed);
|
|
f32 idlePitch = m_TrainIdlePitchCurve.CalculateValue(trainSpeed);
|
|
m_TrainIdle->SetRequestedVolume(idleVolume);
|
|
m_TrainIdle->SetRequestedPitch((s32)idlePitch);
|
|
m_TrainIdle->SetRequestedVolumeCurveScale(rolloffScalar);
|
|
}
|
|
|
|
if(m_TrainBrakes)
|
|
{
|
|
f32 brakeVolume = m_BrakeAccelerationVolumeCurve.CalculateValue(m_TrainAcceleration) + m_BrakeVelocityVolumeCurve.CalculateValue(m_TrainSpeed);
|
|
f32 brakePitch = m_BrakeAccelerationPitchCurve.CalculateValue(m_TrainAcceleration) + m_BrakeVelocityPitchCurve.CalculateValue(m_TrainSpeed);
|
|
f32 brakeVolumeLin = m_BrakeVolumeSmoother.CalculateValue(audDriverUtil::ComputeLinearVolumeFromDb(brakeVolume));
|
|
m_TrainBrakes->SetRequestedVolume(audDriverUtil::ComputeDbVolumeFromLinear(brakeVolumeLin) BANK_ONLY(+ g_BrakeVolumeTrim));
|
|
m_TrainBrakes->SetRequestedPitch((s32)brakePitch);
|
|
m_TrainBrakes->SetRequestedPosition(m_ClosestPointOnTrainToListener);
|
|
|
|
#if __BANK
|
|
if(g_DebugBrakeSounds)
|
|
{
|
|
grcDebugDraw::Sphere(m_ClosestPointOnTrainToListener, 3.f, Color32(255,255,0,255));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if(m_TrainRumble)
|
|
{
|
|
f32 rumbleVolume = m_RumbleVolumeCurve.CalculateValue(trainSpeed);
|
|
|
|
#if __BANK
|
|
rumbleVolume += g_RumbleVolumeTrim;
|
|
#endif
|
|
|
|
m_TrainRumble->SetRequestedVolume(rumbleVolume);
|
|
m_TrainRumble->SetRequestedVolumeCurveScale(rolloffScalar);
|
|
m_TrainRumble->SetRequestedPosition(m_ClosestPointOnTrainToListener);
|
|
}
|
|
|
|
// See if we should play a one-shot big brake release - do it as soon as we come to a big halt
|
|
if (Abs(trainSpeed) < 0.01f && !m_HasPlayedBigBrakeRelease)
|
|
{
|
|
m_HasPlayedBigBrakeRelease = true;
|
|
audSoundInitParams initParams;
|
|
initParams.Tracker = m_Vehicle->GetPlaceableTracker();
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound(m_TrainAudioSettings->BigBrakeRelease, &initParams);
|
|
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(m_TrainAudioSettings->BigBrakeRelease, &initParams, m_Vehicle, m_Vehicle));
|
|
}
|
|
|
|
if (Abs(trainSpeed) > 1.0f)
|
|
{
|
|
m_HasPlayedBigBrakeRelease = false;
|
|
}
|
|
else
|
|
{
|
|
// If we're stationary, ensure that we don't play the airhorn as soon as we start moving
|
|
m_TrainAirHornNextTriggerTime = 90000;
|
|
}
|
|
|
|
// Play the air horn sound, if we've not played it in a while and the train is moving.
|
|
if (!m_IsPlayerDrivingVehicle && m_IsHornEnabled && Abs(trainSpeed) > 1.0f && m_TrainAirHornNextTriggerTime < fwTimer::GetTimeInMilliseconds() REPLAY_ONLY(&& !CReplayMgr::IsEditorActive()))
|
|
{
|
|
// Time to play it again
|
|
m_TrainAirHornNextTriggerTime = fwTimer::GetTimeInMilliseconds() +
|
|
audEngineUtil::GetRandomNumberInRange(30000, 90000);
|
|
audSoundInitParams initParams;
|
|
initParams.UpdateEntity = true;
|
|
initParams.u32ClientVar = AUD_VEHICLE_SOUND_HORN;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound(m_TrainAudioSettings->AirHornOneShot, &initParams);
|
|
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(m_TrainAudioSettings->AirHornOneShot, &initParams, m_Vehicle));
|
|
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update train ambient sounds
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::UpdateTrainAmbientSounds(f32 rolloffScalar)
|
|
{
|
|
// Work out our speed
|
|
CTrain* train = (CTrain*)m_Vehicle;
|
|
f32 trainSpeed = 0.0f;
|
|
|
|
trainSpeed = train->m_trackForwardSpeed;
|
|
|
|
// m_linearSpeed is the speed along the positive direction of the trackIndex. We are interested
|
|
// in the speed in the direction of the train however.
|
|
if (!(train->m_nTrainFlags.bDirectionTrackForward))
|
|
{
|
|
trainSpeed = -trainSpeed;
|
|
}
|
|
|
|
// See how much we're braking
|
|
f32 trainAcceleration = (trainSpeed - m_TrainSpeed) / fwTimer::GetTimeStep();
|
|
m_TrainSpeed = trainSpeed;
|
|
m_TrainAcceleration = trainAcceleration;
|
|
|
|
f32 carriageVolume = m_CarriageVolumeCurve.CalculateValue(Abs(trainSpeed));
|
|
f32 carriagePitch = m_CarriagePitchCurve.CalculateValue(Abs(trainSpeed));
|
|
|
|
// Work out how much we're turning - see the angle to the next carriage. This obviously won't work
|
|
// if we only have one carriage - will change it if that ever actually happens. Looks forwards, then
|
|
// back, so the final one isn't quieter - does mean we'll have two identical squeal params.
|
|
f32 angle = 0.0f;
|
|
|
|
if (m_LinkedTrainValid)
|
|
{
|
|
Vector3 ourDirection = VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetA());
|
|
ourDirection.NormalizeFast(ourDirection);
|
|
Vector3 nextDirection = VEC3V_TO_VECTOR3(m_LinkedTrainMatrixCol0);
|
|
nextDirection.NormalizeFast(nextDirection);
|
|
f32 dotAngle = ourDirection.Dot(nextDirection);
|
|
angle = RtoD * AcosfSafe(dotAngle);
|
|
|
|
// Spot any stupid angles and reverse them. This is caused by a carriage being attached backwards (eg. the driver carriages at either
|
|
// end of a subway train)
|
|
if(angle >= 120)
|
|
{
|
|
angle = Abs(angle - 180);
|
|
}
|
|
|
|
Vector3 linkedLeftDirection = VEC3V_TO_VECTOR3(m_LinkedTrainMatrixCol1);
|
|
linkedLeftDirection.NormalizeFast(linkedLeftDirection);
|
|
f32 dotLeft = ourDirection.Dot(linkedLeftDirection);
|
|
bool turningRight = dotLeft<0.0f;
|
|
if (!m_LinkedBackwards)
|
|
{
|
|
turningRight = !turningRight;
|
|
}
|
|
train->m_nTrainFlags.bIsCarriageTurningRight = turningRight;
|
|
}
|
|
|
|
angle = m_AngleSmoother.CalculateValue(angle);
|
|
f32 grindVolume = m_GrindVolumeCurve.CalculateValue(angle);
|
|
f32 squealVolume = m_SquealVolumeCurve.CalculateValue(angle);
|
|
f32 grindPitch = m_GrindPitchCurve.CalculateValue(angle);
|
|
f32 squealPitch = m_SquealPitchCurve.CalculateValue(angle);
|
|
f32 scrapeVolume = m_ScrapeSpeedVolumeCurve.CalculateValue(Abs(trainSpeed));
|
|
|
|
#if __BANK
|
|
carriageVolume += g_CarriageVolumeTrim;
|
|
grindVolume += g_GrindVolumeTrim;
|
|
squealVolume += g_SquealVolumeTrim;
|
|
#endif
|
|
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.Tracker = m_Vehicle->GetPlaceableTracker();
|
|
initParams.StartOffset = m_TrainStartOffset;
|
|
initParams.IsStartOffsetPercentage = true;
|
|
initParams.UpdateEntity = true;
|
|
initParams.AttackTime = (u32)(sm_TrainDistanceToAttackTime.CalculateValue(m_TrainDistance) * 1000.0f);
|
|
|
|
if(!m_TrainCarriage)
|
|
{
|
|
StartTrainSound(m_TrainAudioSettings->AmbientCarriage, &m_TrainCarriage, &initParams, 2000);
|
|
}
|
|
|
|
if(m_TrainCarriage)
|
|
{
|
|
m_TrainCarriage->SetRequestedVolume(carriageVolume);
|
|
m_TrainCarriage->SetRequestedPitch((s32)carriagePitch);
|
|
m_TrainCarriage->SetRequestedVolumeCurveScale(rolloffScalar);
|
|
}
|
|
|
|
if(grindVolume + scrapeVolume > g_SilenceVolume)
|
|
{
|
|
if(!m_TrainGrind)
|
|
{
|
|
initParams.AttackTime = 100;
|
|
CreateAndPlaySound_Persistent(m_TrainAudioSettings->AmbientGrind, &m_TrainGrind, &initParams);
|
|
}
|
|
|
|
if(m_TrainGrind)
|
|
{
|
|
m_TrainGrind->SetRequestedVolume(grindVolume+scrapeVolume);
|
|
m_TrainGrind->SetRequestedPitch((s32)grindPitch);
|
|
m_TrainGrind->SetRequestedVolumeCurveScale(rolloffScalar);
|
|
}
|
|
}
|
|
else if(m_TrainGrind)
|
|
{
|
|
m_TrainGrind->StopAndForget();
|
|
}
|
|
|
|
if(squealVolume + scrapeVolume > g_SilenceVolume)
|
|
{
|
|
if(!m_TrainSqueal)
|
|
{
|
|
initParams.AttackTime = 100;
|
|
CreateAndPlaySound_Persistent(m_TrainAudioSettings->AmbientSqueal, &m_TrainSqueal, &initParams);
|
|
}
|
|
|
|
if(m_TrainSqueal)
|
|
{
|
|
m_TrainSqueal->SetRequestedVolume(squealVolume+scrapeVolume);
|
|
m_TrainSqueal->SetRequestedPitch((s32)squealPitch);
|
|
m_TrainSqueal->SetRequestedVolumeCurveScale(rolloffScalar);
|
|
}
|
|
}
|
|
else if(m_TrainSqueal)
|
|
{
|
|
m_TrainSqueal->StopAndForget();
|
|
}
|
|
|
|
// Set the squeal intensity for the particle effects
|
|
train->m_wheelSquealIntensity = audDriverUtil::ComputeLinearVolumeFromDb(grindVolume+scrapeVolume);
|
|
|
|
// Also play the brake release sound, if we've not played it in a while
|
|
if (m_TrainBrakeReleaseNextTriggerTime < fwTimer::GetTimeInMilliseconds())
|
|
{
|
|
// Time to play it again
|
|
m_TrainBrakeReleaseNextTriggerTime = fwTimer::GetTimeInMilliseconds() + audEngineUtil::GetRandomNumberInRange(12000, 24000);
|
|
|
|
if(Abs(trainSpeed) > 1.0f)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.Tracker = m_Vehicle->GetPlaceableTracker();
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound(m_TrainAudioSettings->BrakeRelease, &initParams);
|
|
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(m_TrainAudioSettings->BrakeRelease, &initParams, m_Vehicle, m_Vehicle));
|
|
}
|
|
}
|
|
}
|
|
|
|
#if __BANK
|
|
// ----------------------------------------------------------------
|
|
// Update debug info
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::UpdateDebug()
|
|
{
|
|
CTrain* train = (CTrain*)m_Vehicle;
|
|
const Vector3 vTrainPosition = VEC3V_TO_VECTOR3(train->GetTransform().GetPosition());
|
|
|
|
if(g_DebugActiveCarriages)
|
|
{
|
|
Color32 colour;
|
|
|
|
if(IsDummy())
|
|
{
|
|
colour = Color32(0,0,255,128);
|
|
}
|
|
else if(IsDisabled())
|
|
{
|
|
colour = Color32(255,0,0,128);
|
|
}
|
|
else
|
|
{
|
|
colour = Color32(0,255,0,128);
|
|
}
|
|
|
|
grcDebugDraw::Sphere(vTrainPosition, 6.f, colour);
|
|
}
|
|
|
|
if (g_DebugTrain)
|
|
{
|
|
const f32 listenerDist2 = (VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetVolumeListenerPosition())-vTrainPosition).Mag2();
|
|
|
|
// only do it for nearby trains, or there might be more than one
|
|
if(listenerDist2 < (500.0f*500.0f))
|
|
{
|
|
char trainDebug[256] = "";
|
|
|
|
if(m_TrainEngine)
|
|
{
|
|
formatf(trainDebug, "%d nodes found", m_NumTrackNodesSearched);
|
|
grcDebugDraw::Text(Vector2(0.5f, 0.15f), Color32(255,255,255), trainDebug);
|
|
}
|
|
|
|
f32 right = 0.0f;
|
|
if (train->m_nTrainFlags.bIsCarriageTurningRight)
|
|
{
|
|
right = 1.0f;
|
|
}
|
|
|
|
u32 carriageIndex = 0;
|
|
const f32 carriageSpacing = 0.26f;
|
|
f32 carriageScroll = -1.0f * g_DrawCarriageInfoScroll;
|
|
CTrain* linkedTrain = train->GetLinkedToForward();
|
|
|
|
while(linkedTrain)
|
|
{
|
|
carriageIndex++;
|
|
linkedTrain = linkedTrain->GetLinkedToForward();
|
|
}
|
|
|
|
sprintf(trainDebug, "Train Info:");
|
|
grcDebugDraw::Text(Vector2(0.1f, 0.1f + carriageScroll), Color32(255,255,255), trainDebug);
|
|
|
|
sprintf(trainDebug, " Carriage: %d", carriageIndex + 1);
|
|
grcDebugDraw::Text(Vector2(0.1f, 0.12f + carriageScroll + (carriageSpacing * carriageIndex)), Color32(255,255,255), trainDebug);
|
|
|
|
sprintf(trainDebug, " Speed: %f", m_TrainSpeed);
|
|
grcDebugDraw::Text(Vector2(0.1f, 0.14f + carriageScroll + (carriageSpacing * carriageIndex)), Color32(255,255,255), trainDebug);
|
|
|
|
sprintf(trainDebug, " Angle: %f", m_AngleSmoother.GetLastValue());
|
|
grcDebugDraw::Text(Vector2(0.1f, 0.16f + carriageScroll + (carriageSpacing * carriageIndex)), Color32(255,255,255), trainDebug);
|
|
|
|
sprintf(trainDebug, " Intensity: %f", train->m_wheelSquealIntensity);
|
|
grcDebugDraw::Text(Vector2(0.1f, 0.18f + carriageScroll + (carriageSpacing * carriageIndex)), Color32(255,255,255), trainDebug);
|
|
|
|
sprintf(trainDebug, " Right: %02f", right);
|
|
grcDebugDraw::Text(Vector2(0.1f, 0.2f + carriageScroll + (carriageSpacing * carriageIndex)), Color32(255,255,255), trainDebug);
|
|
|
|
sprintf(trainDebug, " Acc: %f", m_TrainAcceleration);
|
|
grcDebugDraw::Text(Vector2(0.1f, 0.22f + carriageScroll + (carriageSpacing * carriageIndex)), Color32(255,255,255), trainDebug);
|
|
|
|
if(m_TrainGrind)
|
|
{
|
|
sprintf(trainDebug, " Grind Sound - Vol: %02f Pitch: %d", m_TrainGrind->GetRequestedVolume(), m_TrainGrind->GetRequestedPitch());
|
|
grcDebugDraw::Text(Vector2(0.1f, 0.24f + carriageScroll + (carriageSpacing * carriageIndex)), Color32(255,255,255), trainDebug);
|
|
}
|
|
|
|
if(m_TrainSqueal)
|
|
{
|
|
sprintf(trainDebug, " Squeal Sound - Vol: %02f Pitch: %d", m_TrainSqueal->GetRequestedVolume(), m_TrainSqueal->GetRequestedPitch());
|
|
grcDebugDraw::Text(Vector2(0.1f, 0.26f + carriageScroll + (carriageSpacing * carriageIndex)), Color32(255,255,255), trainDebug);
|
|
}
|
|
|
|
if(m_TrainRumble)
|
|
{
|
|
sprintf(trainDebug, " Rumble Sound - Vol: %02f", m_TrainRumble->GetRequestedVolume());
|
|
grcDebugDraw::Text(Vector2(0.1f, 0.28f + carriageScroll + (carriageSpacing * carriageIndex)), Color32(255,255,255), trainDebug);
|
|
}
|
|
|
|
if(m_TrainCarriage)
|
|
{
|
|
sprintf(trainDebug, " Carriage Sound - Vol: %02f Pitch: %d", m_TrainCarriage->GetRequestedVolume(), m_TrainCarriage->GetRequestedPitch());
|
|
grcDebugDraw::Text(Vector2(0.1f, 0.30f + carriageScroll + (carriageSpacing * carriageIndex)), Color32(255,255,255), trainDebug);
|
|
}
|
|
|
|
if(m_TrainBrakes)
|
|
{
|
|
sprintf(trainDebug, " Brake Sound - Vol: %02f Pitch: %d", m_TrainBrakes->GetRequestedVolume(), m_TrainBrakes->GetRequestedPitch());
|
|
grcDebugDraw::Text(Vector2(0.1f, 0.32f + carriageScroll + (carriageSpacing * carriageIndex)), Color32(255,255,255), trainDebug);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update cable car sounds
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::UpdateCableCarSounds()
|
|
{
|
|
// Work out our speed
|
|
CTrain* train = (CTrain*)m_Vehicle;
|
|
f32 trainSpeed = Abs(train->m_trackForwardSpeed);
|
|
|
|
// See how much we're braking
|
|
f32 trainAcceleration = (trainSpeed - m_TrainSpeed) / fwTimer::GetTimeStep();
|
|
m_TrainSpeed = trainSpeed;
|
|
m_TrainAcceleration = trainAcceleration;
|
|
|
|
// should we play taut-wire stuff - do it with velocity
|
|
if (m_TrainSpeed > g_MinTautWireSpeed && m_TrainSpeed < g_MaxTautWireSpeed)
|
|
{
|
|
// Play the taught-wire sound, if we've not played it in a while - use brake release vars
|
|
if (m_TrainBrakeReleaseNextTriggerTime < fwTimer::GetTimeInMilliseconds())
|
|
{
|
|
// Time to play it again
|
|
m_TrainBrakeReleaseNextTriggerTime = fwTimer::GetTimeInMilliseconds() +
|
|
audEngineUtil::GetRandomNumberInRange((s32)g_MinTautWireTime, (s32)g_MaxTautWireTime);
|
|
audSoundInitParams initParams;
|
|
initParams.Tracker = m_Vehicle->GetPlaceableTracker();
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound(ATSTRINGHASH("CABLE_CAR_TAUT_CABLE", 0xE3C41DE7), &initParams);
|
|
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(ATSTRINGHASH("CABLE_CAR_TAUT_CABLE", 0xE3C41DE7), &initParams, m_Vehicle, m_Vehicle));
|
|
}
|
|
}
|
|
|
|
// See if we should play a one-shot bang - do it as soon as we come to a big halt, and use same logic/vars as big train brake release
|
|
if (Abs(m_TrainSpeed) < g_CableCarClunkSpeed && !m_HasPlayedBigBrakeRelease)
|
|
{
|
|
m_HasPlayedBigBrakeRelease = true;
|
|
audSoundInitParams initParams;
|
|
initParams.Tracker = m_Vehicle->GetPlaceableTracker();
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound(ATSTRINGHASH("CABLE_CAR_CLUNK", 0xF35B9BC8), &initParams);
|
|
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(ATSTRINGHASH("CABLE_CAR_CLUNK", 0xF35B9BC8), &initParams, m_Vehicle, m_Vehicle));
|
|
}
|
|
if (Abs(trainSpeed) > 1.0f)
|
|
{
|
|
m_HasPlayedBigBrakeRelease = false;
|
|
}
|
|
// DEBUG!
|
|
#if __BANK
|
|
if (g_DebugTrain && m_Vehicle == g_AudioDebugEntity)
|
|
{
|
|
char trainDebug[256] = "";
|
|
sprintf(trainDebug, "speed: %f;", trainSpeed);
|
|
grcDebugDraw::PrintToScreenCoors(trainDebug, 5,30);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Stop train engine sounds
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::StopTrainEngineSounds(u32 releaseTime)
|
|
{
|
|
if(m_TrainDriveTone)
|
|
{
|
|
m_TrainDriveTone->SetReleaseTime(releaseTime);
|
|
}
|
|
|
|
if(m_TrainDriveToneSynth)
|
|
{
|
|
m_TrainDriveToneSynth->SetReleaseTime(releaseTime);
|
|
}
|
|
|
|
if(m_TrainIdle)
|
|
{
|
|
m_TrainIdle->SetReleaseTime(releaseTime);
|
|
}
|
|
|
|
if(m_TrainRumble)
|
|
{
|
|
m_TrainRumble->SetReleaseTime(releaseTime);
|
|
}
|
|
|
|
if(m_TrainBrakes)
|
|
{
|
|
m_TrainBrakes->SetReleaseTime(releaseTime);
|
|
}
|
|
|
|
StopAndForgetSounds(m_TrainDriveTone, m_TrainDriveToneSynth, m_TrainRumble, m_TrainIdle, m_TrainBrakes);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Stop train ambient sounds
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::StopTrainAmbientSounds(u32 releaseTime)
|
|
{
|
|
if(m_TrainCarriage)
|
|
{
|
|
m_TrainCarriage->SetReleaseTime(releaseTime);
|
|
}
|
|
|
|
if(m_TrainGrind)
|
|
{
|
|
m_TrainGrind->SetReleaseTime(releaseTime);
|
|
}
|
|
|
|
if(m_TrainSqueal)
|
|
{
|
|
m_TrainSqueal->SetReleaseTime(releaseTime);
|
|
}
|
|
|
|
StopAndForgetSounds(m_TrainCarriage, m_TrainGrind, m_TrainSqueal);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Called when moving track nodes
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::TrainHasMovedTrackNode()
|
|
{
|
|
CTrain* train = (CTrain*)m_Vehicle;
|
|
|
|
if(!m_TrainAudioSettings)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// No clacks for dummy carriages
|
|
if(GetVehicleLOD() != AUD_VEHICLE_LOD_REAL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// We're maybe triggering these way too much (like every frame) - presumably due to a bug somewhere else. So check when we last triggered.
|
|
u32 timeInMs = fwTimer::GetTimeInMilliseconds();
|
|
if (timeInMs < (m_TrainLastWheelTriggerTime + 2000))
|
|
{
|
|
return;
|
|
}
|
|
m_TrainLastWheelTriggerTime = timeInMs;
|
|
|
|
// Work out our speed
|
|
f32 trainSpeed = 0.0f;
|
|
|
|
trainSpeed = train->m_trackForwardSpeed;
|
|
|
|
// m_linearSpeed is the speed along the positive direction of the trackIndex. We are interested
|
|
// in the speed in the direction of the train however.
|
|
if (!(train->m_nTrainFlags.bDirectionTrackForward))
|
|
{
|
|
trainSpeed = -trainSpeed;
|
|
}
|
|
f32 wheelVolume = m_WheelVolumeCurve.CalculateValue(trainSpeed);
|
|
audSoundInitParams initParams;
|
|
initParams.Tracker = m_Vehicle->GetPlaceableTracker();
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.Volume = wheelVolume;
|
|
CreateAndPlaySound(m_TrainAudioSettings->WheelDry, &initParams);
|
|
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(m_TrainAudioSettings->WheelDry, &initParams, m_Vehicle, m_Vehicle));
|
|
|
|
// We want to play that characteristic two-wheels close together thing, with the gap decreasing with speed;
|
|
// But don't do it if we're traveling TOO slowly, as we might have stopped altogether by the time of the second one.
|
|
if (trainSpeed>g_audTrainMinDoubleWheelSpeed)
|
|
{
|
|
f32 wheelDelay = m_WheelDelayCurve.CalculateValue(trainSpeed);
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.Tracker = m_Vehicle->GetPlaceableTracker();
|
|
initParams.Volume = wheelVolume;
|
|
initParams.Predelay = (s32)wheelDelay;
|
|
CreateAndPlaySound(m_TrainAudioSettings->WheelDry, &initParams);
|
|
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(m_TrainAudioSettings->WheelDry, &initParams, m_Vehicle, m_Vehicle));
|
|
|
|
train->SignalTrainPadShake((u32)wheelDelay);
|
|
}
|
|
else
|
|
{
|
|
train->SignalTrainPadShake();
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Set the train rolloff
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::SetTrainRolloff(f32 rolloff)
|
|
{
|
|
if (m_EnvironmentGroup)
|
|
{
|
|
m_EnvironmentGroup->GetEnvironmentGameMetric().SetRolloffFactor(rolloff);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Check if the train should play station announcements
|
|
// ----------------------------------------------------------------
|
|
bool audTrainAudioEntity::ShouldPlayStationAnnouncements()
|
|
{
|
|
bool isInteriorASubway;
|
|
f32 playerInteriorRatio;
|
|
bool isInInterior = audNorthAudioEngine::GetGtaEnvironment()->AreWeInAnInterior(&isInteriorASubway, &playerInteriorRatio);
|
|
bool isInMahattan = false; // CMapAreas::IsPositionInNamedArea(g_AudioEngine.GetEnvironment().GetVolumeListenerPosition()), atStringhash("Manhattan"));
|
|
|
|
const Vector3 northwoodCoors(-368.f, 1414.f, 28.f);
|
|
return ((isInMahattan && isInInterior && isInteriorASubway) ||
|
|
(!isInMahattan && !isInInterior) ||
|
|
(isInMahattan && !isInInterior && (VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetVolumeListenerPosition())-northwoodCoors).Mag2() < (70.f*70.f)));
|
|
}
|
|
|
|
u32 audTrainAudioEntity::GetVehicleHornSoundHash(bool UNUSED_PARAM(ignoreMods))
|
|
{
|
|
return m_VehicleHornHash;
|
|
};
|
|
|
|
// ----------------------------------------------------------------
|
|
// Announce the train arriving at a station
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::AnnounceTrainAtStation()
|
|
{
|
|
#if AUD_TRAINANNOUNCER_ENABLED
|
|
Assert(((CTrain*)m_Vehicle)->m_trackIndex >= 0);
|
|
|
|
CTrain *train = (CTrain*)m_Vehicle;
|
|
naCErrorf(train->m_nTrainFlags.bEngine, "Carrige other than the engine is attempting to announce the train is at the station");
|
|
// update last station announced regardless of player
|
|
m_LastStationAnnounced = train->m_nextStation;
|
|
if(m_AnnouncedCurrentStation != train->m_nextStation)
|
|
{
|
|
m_AnnouncedCurrentStation = train->m_nextStation;
|
|
if(train->AnnouncesStations() && train->IsLocalPlayerSeatedInAnyCarriage())
|
|
{
|
|
s32 stationId = train->m_nextStation;
|
|
if(stationId != -1)
|
|
{
|
|
TrainStation *station = g_audTrainStations[train->m_trackIndex][stationId];
|
|
if(station)
|
|
{
|
|
audScannerSentence *sentence = g_AudioScannerManager.AllocateSentence();
|
|
InitScannerSentenceForTrain(sentence);
|
|
|
|
u32 idx = 0;
|
|
|
|
sentence->sentenceSubType = 1;
|
|
sentence->phrases[idx].postDelay = 0;
|
|
sentence->phrases[idx].slot = g_AudioScannerManager.GetNextScannerSlot(*sentence); //SCANNER_SLOT_3;
|
|
sentence->phrases[idx].sound = NULL;
|
|
sentence->phrases[idx++].soundHash = ATSTRINGHASH("ANNOUNCE_ARRIVED", 0xF3ED0B0E);
|
|
|
|
sentence->phrases[idx].postDelay = 0;
|
|
sentence->phrases[idx].slot = g_AudioScannerManager.GetNextScannerSlot(*sentence); //SCANNER_SLOT_2;
|
|
sentence->phrases[idx].sound = NULL;
|
|
sentence->phrases[idx++].soundHash = station->StationNameSound;
|
|
|
|
sentence->numPhrases = idx;
|
|
sentence->isPositioned = false;
|
|
sentence->timeRequested = fwTimer::GetTimeInMilliseconds() + 1000;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif // NA_POLICECSANNER_ENABLED
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Announce the train leaving a station
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::AnnounceTrainLeavingStation()
|
|
{
|
|
#if AUD_TRAINANNOUNCER_ENABLED
|
|
|
|
Assert(((CTrain*)m_Vehicle)->m_trackIndex >= 0);
|
|
|
|
// TRAIN_LEAVING_STATION
|
|
CTrain *engineTrain = (CTrain*)m_Vehicle;
|
|
if(!engineTrain->m_nTrainFlags.bDisableNextStationAnnouncements && engineTrain->AnnouncesStations() && fwTimer::GetTimeInMilliseconds() > m_LastTrainAnnouncement + 10000)
|
|
{
|
|
audScannerSentence *sentence = g_AudioScannerManager.AllocateSentence();
|
|
InitScannerSentenceForTrain(sentence);
|
|
|
|
u32 idx = 0;
|
|
|
|
sentence->phrases[idx].postDelay = 0;
|
|
sentence->phrases[idx].slot = g_AudioScannerManager.GetNextScannerSlot(*sentence); //SCANNER_SLOT_1;
|
|
sentence->phrases[idx].sound = NULL;
|
|
sentence->phrases[idx++].soundHash = ATSTRINGHASH("TRAIN_LEAVING_STATION", 0x44C98442);
|
|
|
|
sentence->timeRequested = fwTimer::GetTimeInMilliseconds() + 2000;
|
|
sentence->numPhrases = idx;
|
|
// position at the train
|
|
sentence->tracker = m_Vehicle->GetPlaceableTracker();
|
|
sentence->occlusionGroup = m_EnvironmentGroup;
|
|
sentence->isPositioned = true;
|
|
|
|
m_LastTrainAnnouncement = fwTimer::GetTimeInMilliseconds();
|
|
|
|
|
|
if(engineTrain->IsLocalPlayerSeatedInAnyCarriage())
|
|
{
|
|
f32 posOnTrack;
|
|
s32 stationId;
|
|
engineTrain->FindNextStationPositionInDirection(engineTrain->m_nTrainFlags.bDirectionTrackForward, engineTrain->m_trackPosFront, &posOnTrack, &stationId);
|
|
|
|
if(stationId != -1)
|
|
{
|
|
TrainStation *station = g_audTrainStations[engineTrain->m_trackIndex][stationId];
|
|
|
|
if(station)
|
|
{
|
|
m_AnnouncedNextStation = stationId;
|
|
|
|
audScannerSentence *sentence = g_AudioScannerManager.AllocateSentence();
|
|
InitScannerSentenceForTrain(sentence);
|
|
|
|
u32 idx = 0;
|
|
|
|
|
|
if(station->Letter != g_NullSoundHash)
|
|
{
|
|
sentence->phrases[idx].postDelay = 750;
|
|
sentence->phrases[idx].slot = g_AudioScannerManager.GetNextScannerSlot(*sentence); //SCANNER_SLOT_1;
|
|
sentence->phrases[idx].sound = NULL;
|
|
sentence->phrases[idx++].soundHash = station->Letter;
|
|
}
|
|
|
|
sentence->sentenceSubType = 1;
|
|
sentence->phrases[idx].postDelay = 0;
|
|
sentence->phrases[idx].slot = g_AudioScannerManager.GetNextScannerSlot(*sentence); //SCANNER_SLOT_3;
|
|
sentence->phrases[idx].sound = NULL;
|
|
sentence->phrases[idx++].soundHash = ATSTRINGHASH("ANNOUNCE_NEXT_STOP", 0x5FE7B7DE);
|
|
|
|
sentence->phrases[idx].postDelay = 0;
|
|
sentence->phrases[idx].slot = g_AudioScannerManager.GetNextScannerSlot(*sentence); //SCANNER_SLOT_2;
|
|
sentence->phrases[idx].sound = NULL;
|
|
sentence->phrases[idx++].soundHash = station->StationNameSound;
|
|
|
|
sentence->numPhrases = idx;
|
|
sentence->isPositioned = false;
|
|
|
|
sentence->timeRequested = fwTimer::GetTimeInMilliseconds();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif // AUD_TRAINANNOUNCER_ENABLED
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Announce an upcoming station
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::AnnounceNextStation(s32 UNUSED_PARAM(stationId))
|
|
{
|
|
#if AUD_TRAINANNOUNCER_ENABLED
|
|
Assert(((CTrain*)m_Vehicle)->m_trackIndex >= 0);
|
|
|
|
CTrain *train = (CTrain*)m_Vehicle;
|
|
TrainStation *station = g_audTrainStations[train->m_trackIndex][stationId];
|
|
|
|
if(train->AnnouncesStations() && station)
|
|
{
|
|
if(train->IsLocalPlayerSeatedInAnyCarriage())
|
|
{
|
|
audScannerSentence *sentence = g_AudioScannerManager.AllocateSentence();
|
|
InitScannerSentenceForTrain(sentence);
|
|
|
|
u32 idx = 0;
|
|
|
|
sentence->sentenceSubType = 1;
|
|
sentence->phrases[idx].postDelay = 0;
|
|
sentence->phrases[idx].slot = g_AudioScannerManager.GetNextScannerSlot(*sentence); //SCANNER_SLOT_3;
|
|
sentence->phrases[idx].sound = NULL;
|
|
sentence->phrases[idx++].soundHash = ATSTRINGHASH("ANNOUNCE_APPROACHING", 0x1C60D164);
|
|
|
|
sentence->phrases[idx].postDelay = 0;
|
|
sentence->phrases[idx].slot = g_AudioScannerManager.GetNextScannerSlot(*sentence); //SCANNER_SLOT_2;
|
|
sentence->phrases[idx].sound = NULL;
|
|
sentence->phrases[idx++].soundHash = station->StationNameSound;
|
|
|
|
if(station->TransferSound != g_NullSoundHash)
|
|
{
|
|
sentence->phrases[idx-1].postDelay = 800;
|
|
|
|
sentence->phrases[idx].postDelay = 0;
|
|
sentence->phrases[idx].slot = g_AudioScannerManager.GetNextScannerSlot(*sentence); //SCANNER_SLOT_1;
|
|
sentence->phrases[idx].sound = NULL;
|
|
sentence->phrases[idx++].soundHash = station->TransferSound;
|
|
}
|
|
sentence->numPhrases = idx;
|
|
sentence->isPositioned = false;
|
|
sentence->timeRequested = fwTimer::GetTimeInMilliseconds();
|
|
}
|
|
else
|
|
{
|
|
if(ShouldPlayStationAnnouncements())
|
|
{
|
|
s32 prevStationId = stationId + (train->m_nTrainFlags.bDirectionTrackForward?-1:1);
|
|
s32 nextStationId = stationId + (train->m_nTrainFlags.bDirectionTrackForward?1:-1);
|
|
if(prevStationId == -1)
|
|
{
|
|
prevStationId = gTrainTracks[train->m_trackIndex].m_numStations-1;
|
|
}
|
|
if(prevStationId >= gTrainTracks[train->m_trackIndex].m_numStations)
|
|
{
|
|
prevStationId = 0;
|
|
}
|
|
if(nextStationId == -1)
|
|
{
|
|
nextStationId = gTrainTracks[train->m_trackIndex].m_numStations-1;
|
|
}
|
|
if(nextStationId >= gTrainTracks[train->m_trackIndex].m_numStations)
|
|
{
|
|
nextStationId = 0;
|
|
}
|
|
naCErrorf(stationId != prevStationId, "While announcing the next station, current and previous stations are the same");
|
|
naCErrorf(stationId != nextStationId, "While announcing the next station, current and next stations are the same");
|
|
|
|
TrainStation *prevStation = g_audTrainStations[train->m_trackIndex][prevStationId];
|
|
TrainStation *nextStation = g_audTrainStations[train->m_trackIndex][nextStationId];
|
|
if(prevStation && nextStation)
|
|
{
|
|
audScannerSentence *sentence = g_AudioScannerManager.AllocateSentence();
|
|
InitScannerSentenceForTrain(sentence);
|
|
u32 idx = 0;
|
|
|
|
sentence->phrases[idx].postDelay = 0;
|
|
sentence->phrases[idx].slot = g_AudioScannerManager.GetNextScannerSlot(*sentence); //SCANNER_SLOT_3;
|
|
sentence->phrases[idx].sound = NULL;
|
|
sentence->phrases[idx++].soundHash = station->ApproachingStation;
|
|
|
|
sentence->phrases[idx].postDelay = 0;
|
|
sentence->phrases[idx].slot = g_AudioScannerManager.GetNextSmallScannerSlot(*sentence); //SCANNER_SMALL_SLOT_1;
|
|
sentence->phrases[idx].sound = NULL;
|
|
sentence->phrases[idx++].soundHash = ATSTRINGHASH("ANNOUNCE_BOUND_FOR", 0x49E7982);
|
|
|
|
sentence->phrases[idx].postDelay = 0;
|
|
sentence->phrases[idx].slot = g_AudioScannerManager.GetNextScannerSlot(*sentence); //SCANNER_SLOT_2;
|
|
sentence->phrases[idx].sound = NULL;
|
|
sentence->phrases[idx++].soundHash = nextStation->StationNameSound;
|
|
|
|
sentence->numPhrases = idx;
|
|
sentence->isPositioned = true;
|
|
sentence->fakeEchoTime = 100;
|
|
sentence->position = gTrainTracks[train->m_trackIndex].m_aStationCoors[stationId];
|
|
sentence->position.z += 1.5f;
|
|
sentence->occlusionGroup = NULL;
|
|
|
|
sentence->timeRequested = fwTimer::GetTimeInMilliseconds();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif // AUD_TRAINANNOUNCER_ENABLED
|
|
}
|
|
|
|
#if AUD_TRAINANNOUNCER_ENABLED
|
|
// ----------------------------------------------------------------
|
|
// audTrainAudioEntity::InitScannerSentenceForTrain
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::InitScannerSentenceForTrain(audScannerSentence *sentence)
|
|
{
|
|
sentence->areaHash = 0;
|
|
sentence->backgroundSFXHash = g_NullSoundHash;
|
|
sentence->currentPhrase = 0;
|
|
sentence->shouldDuckRadio = false;
|
|
sentence->predelay = 0;
|
|
sentence->inUse = true;
|
|
sentence->isPositioned = false;
|
|
sentence->sentenceType = AUD_SCANNER_TRAIN;
|
|
sentence->sentenceSubType = 0;
|
|
sentence->priority = AUD_SCANNER_PRIO_CRITICAL;
|
|
sentence->tracker = NULL;
|
|
sentence->category = g_AudioEngine.GetCategoryManager().GetCategoryPtr(ATSTRINGHASH("GENERAL_TRAIN_ANNOUNCER", 0x354F997A));
|
|
sentence->fakeEchoTime = 0;
|
|
sentence->useRadioVolOffset = false;
|
|
for(u32 i = 0; i < g_MaxPhrasesPerSentence; i++)
|
|
{
|
|
sentence->phrases[i].echoSound = sentence->phrases[i].sound = NULL;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audTrainAudioEntity::UpdateAmbientTrainStations
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::UpdateAmbientTrainStations()
|
|
{
|
|
u32 dist2[MAX_TRAIN_TRACKS_PER_LEVEL][MAX_NUM_STATIONS];
|
|
|
|
if(!ShouldPlayStationAnnouncements())
|
|
{
|
|
return;
|
|
}
|
|
|
|
Vector3 listenerPos = g_AudioEngine.GetEnvironment().GetVolumeListenerPosition();
|
|
// only search bronx and queens tracks
|
|
for(s8 trackIndex = 0; trackIndex < MAX_TRAIN_TRACKS_PER_LEVEL; trackIndex+=2)
|
|
{
|
|
for(s32 station = 0; station < gTrainTracks[trackIndex].m_numStations; station++)
|
|
{
|
|
dist2[trackIndex][station] = static_cast<u32>((listenerPos - gTrainTracks[trackIndex].m_aStationCoors[station]).Mag2());
|
|
}
|
|
}
|
|
|
|
u32 minDist2 = ~0U;
|
|
s32 nearestStation = -1;
|
|
s32 nearestTrackIndex = -1;
|
|
for(s8 trackIndex = 0; trackIndex < MAX_TRAIN_TRACKS_PER_LEVEL; trackIndex+=2)
|
|
{
|
|
for(s32 station = 0; station < gTrainTracks[trackIndex].m_numStations; station++)
|
|
{
|
|
if(dist2[trackIndex][station] < minDist2)
|
|
{
|
|
minDist2 = dist2[trackIndex][station];
|
|
nearestStation = station;
|
|
nearestTrackIndex = trackIndex;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(minDist2 < (100*100))
|
|
{
|
|
audScannerSentence *sentence = g_AudioScannerManager.AllocateSentence();
|
|
InitScannerSentenceForTrain(sentence);
|
|
u32 idx = 0;
|
|
|
|
if(!g_audTrainStations[nearestTrackIndex][nearestStation] || audEngineUtil::ResolveProbability(0.7f))
|
|
{
|
|
sentence->phrases[idx].postDelay = 0;
|
|
sentence->phrases[idx].slot = g_AudioScannerManager.GetNextScannerSlot(*sentence); //SCANNER_SLOT_1;
|
|
sentence->phrases[idx].sound = NULL;
|
|
s32 var = audEngineUtil::GetRandomNumberInRange(1, 15);
|
|
char soundName[96];
|
|
formatf(soundName, sizeof(soundName), "POLICE_SCANNER_WARNINGS_SUBWAY_WARNING_%02d", var);
|
|
sentence->phrases[idx++].soundHash = atStringHash(soundName);
|
|
}
|
|
else
|
|
{
|
|
sentence->phrases[idx].postDelay = 0;
|
|
sentence->phrases[idx].slot = g_AudioScannerManager.GetNextScannerSlot(*sentence); //SCANNER_SLOT_3;
|
|
sentence->phrases[idx].sound = NULL;
|
|
sentence->phrases[idx++].soundHash = ATSTRINGHASH("ANNOUNCE_ARRIVED", 0xF3ED0B0E);
|
|
|
|
|
|
sentence->phrases[idx].postDelay = 0;
|
|
sentence->phrases[idx].slot = g_AudioScannerManager.GetNextScannerSlot(*sentence); //SCANNER_SLOT_2;
|
|
sentence->phrases[idx].sound = NULL;
|
|
sentence->phrases[idx++].soundHash = g_audTrainStations[nearestTrackIndex][nearestStation]->StationNameSound;
|
|
|
|
}
|
|
|
|
sentence->numPhrases = idx;
|
|
sentence->isPositioned = true;
|
|
sentence->fakeEchoTime = 100;
|
|
sentence->position = gTrainTracks[nearestTrackIndex].m_aStationCoors[nearestStation];
|
|
sentence->position.z += 1.5f;
|
|
sentence->occlusionGroup = NULL;
|
|
//sentence->priority = AUD_SCANNER_PRIO_NORMAL;
|
|
|
|
sentence->timeRequested = fwTimer::GetTimeInMilliseconds();
|
|
}
|
|
}
|
|
#endif // AUD_TRAINANNOUNCER_ENABLED
|
|
|
|
// ----------------------------------------------------------------
|
|
// audTrainAudioEntity::GetTrainAudioSettings
|
|
// ----------------------------------------------------------------
|
|
TrainAudioSettings * audTrainAudioEntity::GetTrainAudioSettings()
|
|
{
|
|
if(!g_AudioEngine.IsAudioEnabled())
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
naAssertf(m_Vehicle->InheritsFromTrain(), "Trying to get a train settings from a vehicle that doesn't have a train");
|
|
TrainAudioSettings *settings = NULL;
|
|
|
|
if(m_ForcedGameObject != 0u)
|
|
{
|
|
settings = audNorthAudioEngine::GetObject<TrainAudioSettings>(m_ForcedGameObject);
|
|
m_ForcedGameObject = 0u;
|
|
}
|
|
|
|
if(!settings)
|
|
{
|
|
if(m_Vehicle->GetVehicleModelInfo()->GetAudioNameHash() != 0)
|
|
{
|
|
settings = audNorthAudioEngine::GetObject<TrainAudioSettings>(m_Vehicle->GetVehicleModelInfo()->GetAudioNameHash());
|
|
}
|
|
|
|
if(!settings)
|
|
{
|
|
settings = audNorthAudioEngine::GetObject<TrainAudioSettings>(GetVehicleModelNameHash());
|
|
}
|
|
}
|
|
|
|
if(!settings)
|
|
{
|
|
if(!audVerifyf(settings, "Couldn't find train settings for train: %s", GetVehicleModelName()))
|
|
{
|
|
settings = audNorthAudioEngine::GetObject<TrainAudioSettings>(ATSTRINGHASH("SUBWAY_TRAIN", 0xE6C118FD));
|
|
}
|
|
}
|
|
|
|
return settings;
|
|
}
|
|
|
|
VehicleCollisionSettings* audTrainAudioEntity::GetVehicleCollisionSettings() const
|
|
{
|
|
if(m_TrainAudioSettings)
|
|
{
|
|
return audNorthAudioEngine::GetObject<VehicleCollisionSettings>(m_TrainAudioSettings->VehicleCollisions);
|
|
}
|
|
|
|
return audVehicleAudioEntity::GetVehicleCollisionSettings();
|
|
}
|
|
|
|
#if __BANK
|
|
// ----------------------------------------------------------------
|
|
// Add widgets to RAG tool
|
|
// ----------------------------------------------------------------
|
|
void audTrainAudioEntity::AddWidgets(bkBank &bank)
|
|
{
|
|
bank.PushGroup("Trains",false);
|
|
bank.AddToggle("Debug Train", &g_DebugTrain);
|
|
bank.AddToggle("Show Active Carriages", &g_DebugActiveCarriages);
|
|
bank.AddToggle("Show Brake Sounds", &g_DebugBrakeSounds);
|
|
bank.AddToggle("Force Cable Car", &g_ForceCableCar);
|
|
bank.AddSlider("Max Real Trains", &g_MaxRealTrains, 0, 20, 1);
|
|
bank.AddSlider("Activation Range Time Scaler", &g_TrainActivationRangeTimeScale, 0.0f, 10.0f, 0.01f);
|
|
bank.AddSlider("Debug Scroll", &g_DrawCarriageInfoScroll, 0.0f, 1.0f, 0.1f, NullCB, "Use this to scroll the carriage list" );
|
|
bank.AddSlider("Grind Volume Trim", &g_GrindVolumeTrim, -100.0f, 100.f, 0.1f);
|
|
bank.AddSlider("Squeal Volume Trim", &g_SquealVolumeTrim, -100.0f, 100.f, 0.1f);
|
|
bank.AddSlider("Rumble Volume Trim", &g_RumbleVolumeTrim, -100.0f, 100.f, 0.1f);
|
|
bank.AddSlider("Carriage Volume Trim", &g_CarriageVolumeTrim, -100.0f, 100.f, 0.1f);
|
|
bank.AddSlider("Brake Volume Trim", &g_BrakeVolumeTrim, -100.0f, 100.f, 0.1f);
|
|
bank.AddSlider("Angle Smoothing Rate", &g_AngleSmootherRate, 0.0f, 10.0f, 0.01f);
|
|
bank.AddSlider("Brake Volume Smoothing Increase Rate", &g_BrakeVolSmootherIncreaseRate, 0.0f, 10.0f, 0.01f);
|
|
bank.AddSlider("Brake Volume Smoothing Decrease Rate", &g_BrakeVolSmootherDecreaseRate, 0.0f, 10.0f, 0.01f);
|
|
bank.AddSlider("g_CableCarClunkSpeed", &g_CableCarClunkSpeed, 0.0f, 1.0f, 0.001f);
|
|
bank.AddSlider("g_MinTautWireSpeed", &g_MinTautWireSpeed, 0.0f, 10.0f, 0.01f);
|
|
bank.AddSlider("g_MaxTautWireSpeed", &g_MaxTautWireSpeed, 0.0f, 10.0f, 0.01f);
|
|
bank.AddSlider("g_MinTautWireTime", &g_MinTautWireTime, 0, 10000, 1);
|
|
bank.AddSlider("g_MaxTautWireTime", &g_MaxTautWireTime, 0, 10000, 1);
|
|
bank.PopGroup();
|
|
}
|
|
#endif
|