1
0
KF2-Dev-Scripts/KFGame/Classes/KFWeaponAmbientEchoHandler.uc
2020-12-13 18:01:13 +03:00

272 lines
9.7 KiB
Ucode

class KFWeaponAmbientEchoHandler extends Object
within KFPawn;
enum EEchoDirection
{
EED_Front,
EED_Right,
EED_Left,
EED_Rear,
EED_Max
};
struct native EchoSet
{
/** Components to play events on */
var AkComponent Components[4];
/** Echo events to play */
var AKEvent Events[4];
/** Time that echo should start playing (allows for delay) */
var float EchoStartTimes[4];
/** Time that echo should stop playing (allows for delay) */
var float EchoStopTimes[4];
/** Whether echo loop has been started (bool arrays aren't allowed) */
var byte Started[4];
/** Whether echo loop has been stopped (bool arrays aren't allowed) */
var byte Stopped[4];
};
/** Array of currently-playing looping echo sounds (each set has four direction echoes) */
var array< EchoSet > EchoSets;
/**
* Starts the chain of starting/stopping looping echo sounds for looping fire weapons
* On fire, a set of four directional echoes is grabbed from the audio device, and each echo is given a delay time to start
* On stop fire, each echo is given a delay time to stop, and then they are returned to the audio device
* @param NewAmbientSound the sound that was played that we want to handle echoes for
*/
simulated function HandleEchoes(AkEvent NewAmbientSound)
{
if ( WorldInfo.NetMode == NM_DedicatedServer )
{
return;
}
StopAllEchoes();
if ( NewAmbientSound != None)
{
StartEchoSet( NewAmbientSound );
}
}
/*
* Create a set of four directional echoes and give them a start delay based on location within reverb volume
*/
simulated function StartEchoSet( AkEvent NewAmbientSound )
{
local vector FrontLocation, RightLocation, LeftLocation, RearLocation, ViewLocation;
local float EchoDistance, EchoDelay, ViewDist;
local PlayerController LocalPC;
local rotator ViewRotation;
local ReverbVolume EchoVolume;
local int EchoIdx;
LocalPC = GetALocalPlayerController();
if( LocalPC != none )
{
LocalPC.GetPlayerViewPoint( ViewLocation, ViewRotation );
}
else
{
`log(GetFuncName()@"called with no local PC!");
return;
}
ViewDist = VSizeSq(ViewLocation-Location);
class'KFReverbVolume'.static.CalculateEchoVolumeAndDistance( WorldInfo, Location, EchoVolume, EchoDistance );
EchoSets.Add( 1 );
// Play all 4 positional echoes if the listener is within the echo distance
if( EchoDistance == 0 || (ViewDist < EchoDistance * EchoDistance) )
{
// For the purposes of placing the echo locations, we need an echo distance of at least 1.0
if( EchoDistance < 1.0 )
{
EchoDistance = 1.0;
}
class'KFReverbVolume'.static.CalculateEchoLocationAndDelay( EchoVolume, Location, vect(1,0,0) >> Rotation, EchoDistance, FrontLocation, EchoDelay );
DelayedStartEcho( EED_Front, FrontLocation, NewAmbientSound.EchoFront, WorldInfo.TimeSeconds + EchoDelay );
class'KFReverbVolume'.static.CalculateEchoLocationAndDelay( EchoVolume, Location, vect(0,-1,0) >> Rotation, EchoDistance, LeftLocation, EchoDelay );
DelayedStartEcho( EED_Left, LeftLocation, NewAmbientSound.EchoRight, WorldInfo.TimeSeconds + EchoDelay );
class'KFReverbVolume'.static.CalculateEchoLocationAndDelay( EchoVolume, Location, vect(0,1,0) >> Rotation, EchoDistance, RightLocation, EchoDelay );
DelayedStartEcho( EED_Right, RightLocation, NewAmbientSound.EchoLeft, WorldInfo.TimeSeconds + EchoDelay );
class'KFReverbVolume'.static.CalculateEchoLocationAndDelay( EchoVolume, Location, vect(-1,0,0) >> Rotation, EchoDistance, RearLocation, EchoDelay );
DelayedStartEcho( EED_Rear, RearLocation, NewAmbientSound.EchoRear, WorldInfo.TimeSeconds + EchoDelay );
//FlushPersistentDebugLines();
//DrawDebugSphere( FrontLocation, 8, 10, 255, 0, 0, true );
//DrawDebugSphere( LeftLocation, 8, 10, 255, 0, 0, true );
//DrawDebugSphere( RightLocation, 8, 10, 255, 0, 0, true );
//DrawDebugSphere( RearLocation, 8, 10, 255, 0, 0, true );
}
else
{
// Set the echo to play based on the looping fire sound that was played
DelayedStartEcho( EED_Front, Location, NewAmbientSound.EchoMono, WorldInfo.TimeSeconds + EchoDelay );
// "stop" the rest so that echo set is removed in tick
EchoIdx = EchoSets.Length - 1;
EchoSets[EchoIdx].Stopped[EED_Left] = 1;
EchoSets[EchoIdx].Stopped[EED_Right] = 1;
EchoSets[EchoIdx].Stopped[EED_Rear] = 1;
}
if( EchoDelay == 0 )
{
// possibly start echoes now instead of next frame
TickEchoes();
}
}
/*
* Sets up single echo and gives it an AkComponent from the audio device
*/
simulated function DelayedStartEcho( EEchoDirection EDir, vector EchoLocation, AkEvent EchoSound, float EchoStartTime )
{
local int EchoSetIndex;
local KFPlayerController LocalKFPC;
LocalKFPC = KFPlayerController( GetALocalPlayerController() );
if( LocalKFPC != none )
{
EchoSetIndex = EchoSets.Length - 1;
EchoSets[ EchoSetIndex ].Components[ EDir ] = LocalKFPC.GetPooledAkComponent();
EchoSets[ EchoSetIndex ].Components[ EDir ].Location = EchoLocation;
EchoSets[ EchoSetIndex ].Components[ EDir ].bStopWhenOwnerDestroyed = true;
EchoSets[ EchoSetIndex ].Events[ EDir ] = EchoSound;
EchoSets[ EchoSetIndex ].EchoStartTimes[ EDir ] = EchoStartTime;
}
}
/*
* Determines when all direction echoes for an echo set should stop being played
*/
simulated function StopEchoSet( optional int EchoSetIndex = -1, optional bool bStopImmediate = false )
{
local float EchoDistance, EchoDelay;
local ReverbVolume EchoVolume;
local vector EchoLocation;
if( EchoSetIndex < 0 )
{
EchoSetIndex = EchoSets.Length - 1;
}
if( EchoSetIndex < 0 || EchoSetIndex >= EchoSets.Length )
{
return;
}
if( bStopImmediate )
{
// stop echoes now instead of next frame
StopEcho(EchoSetIndex, EED_Front);
StopEcho(EchoSetIndex, EED_Left);
StopEcho(EchoSetIndex, EED_Right);
StopEcho(EchoSetIndex, EED_Rear);
EchoSets.Remove( EchoSetIndex, 1 );
}
else
{
class'KFReverbVolume'.static.CalculateEchoVolumeAndDistance( WorldInfo, Location, EchoVolume, EchoDistance );
class'KFReverbVolume'.static.CalculateEchoLocationAndDelay( EchoVolume, Location, vect(1,0,0) >> Rotation, EchoDistance, EchoLocation, EchoDelay );
EchoSets[ EchoSetIndex ].EchoStopTimes[ EED_Front ] = WorldInfo.TimeSeconds + EchoDelay;
class'KFReverbVolume'.static.CalculateEchoLocationAndDelay( EchoVolume, Location, vect(0,-1,0) >> Rotation, EchoDistance, EchoLocation, EchoDelay );
EchoSets[ EchoSetIndex ].EchoStopTimes[ EED_Left ] = WorldInfo.TimeSeconds + EchoDelay;
class'KFReverbVolume'.static.CalculateEchoLocationAndDelay( EchoVolume, Location, vect(0,1,0) >> Rotation, EchoDistance, EchoLocation, EchoDelay );
EchoSets[ EchoSetIndex ].EchoStopTimes[ EED_Right ] = WorldInfo.TimeSeconds + EchoDelay;
class'KFReverbVolume'.static.CalculateEchoLocationAndDelay( EchoVolume, Location, vect(-1,0,0) >> Rotation, EchoDistance, EchoLocation, EchoDelay );
EchoSets[ EchoSetIndex ].EchoStopTimes[ EED_Rear ] = WorldInfo.TimeSeconds + EchoDelay;
}
}
/*
* Determines stop time for all echoes in all echo sets
@param bImmediate - tells echoes to stop immediately, otherwise they will stop after a delay determined by the reverb volume
*/
simulated function StopAllEchoes( optional bool bImmediate )
{
local int i;
for( i = EchoSets.Length - 1; i >= 0; i-- )
{
// stop/delay stop all echo sets that haven't been scheduled to stop, in case there are more than one (could happen due to flaky server connection)
if( bImmediate || EchoSets[i].EchoStopTimes[EED_Front] == 0 )
{
StopEchoSet( i, bImmediate );
}
}
}
/*
* Updates echo sets (starts them after start delay, stops them after stop delay, cleans them up when finished)
*/
simulated function TickEchoes()
{
local int i, j, NumStoppedEchoes;
local float WorldTimeSeconds;
WorldTimeSeconds = WorldInfo.TimeSeconds;
for( i = 0; i < EchoSets.Length; ++i )
{
NumStoppedEchoes = 0;
for( j = 0; j < EED_Max; ++j )
{
if( EchoSets[i].Stopped[j] == 0 )
{
if( EchoSets[i].Started[j] == 0 && EchoSets[i].EchoStartTimes[j] > 0 && WorldTimeSeconds > EchoSets[i].EchoStartTimes[j] )
{
StartEcho( i , j );
}
else if( EchoSets[i].Started[j] > 0 && EchoSets[i].EchoStopTimes[j] > 0 && WorldTimeSeconds > EchoSets[i].EchoStopTimes[j] )
{
StopEcho( i , j );
++NumStoppedEchoes;
}
}
else
{
++NumStoppedEchoes;
}
}
// if all echoes in an echo set have been stopped, then the set is finished -- remove it
if( NumStoppedEchoes == EED_Max )
{
EchoSets.Remove( i--, 1 );
}
}
}
/*
* Plays a single echo
*/
simulated function StartEcho( int EchoSetIndex, int EchoIndex )
{
EchoSets[ EchoSetIndex ].Started[ EchoIndex ] = 1;
EchoSets[ EchoSetIndex ].Components[ EchoIndex ].PlayEvent( EchoSets[EchoSetIndex].Events[EchoIndex] );
}
/*
* Stops a single echo
*/
simulated function StopEcho( int EchoSetIndex, int EchoIndex )
{
EchoSets[ EchoSetIndex ].Stopped[ EchoIndex ] = 1;
if( EchoSets[EchoSetIndex].Components[EchoIndex] != none )
{
EchoSets[ EchoSetIndex ].Components[ EchoIndex ].StopEvents();
}
}