272 lines
9.7 KiB
Ucode
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();
|
|
}
|
|
}
|