Files
GTASource/game/audio/weaponaudioentity.cpp

4913 lines
170 KiB
C++
Raw Permalink Normal View History

2025-02-23 17:40:52 +08:00
//
// audio/weaponaudioentity.cpp
//
// Copyright (C) 1999-2006 Rockstar Games. All Rights Reserved.
//
#include "weaponaudioentity.h"
#include "debugaudio.h"
#include "ambience/ambientaudioentity.h"
// Rage headers
#include "grcore/debugdraw.h"
#include "audioengine/engine.h"
#include "audioengine/engineutil.h"
#include "audiosoundtypes/soundcontrol.h"
#include "audiosoundtypes/simplesound.h"
#include "Peds/PedIntelligence.h"
#include "spatialdata/sphere.h"
#include "task/Combat/TaskCombatMelee.h"
// Framework headers
#include "fwmaths/geomutil.h"
// Game headers
#include "audio/frontendaudioentity.h"
#include "audio/northaudioengine.h"
#include "audio/environment/microphones.h"
#include "Control/Replay/Replay.h"
#include "Control/Replay/Audio/WeaponAudioPacket.h"
#include "Control/Replay/Audio/BulletByAudioPacket.h"
#include "camera/CamInterface.h"
#include "vehicles/vehicle.h"
#include "vehicles/Boat.h"
#include "camera/caminterface.h"
#include "debugaudio.h"
#include "objects/object.h"
#include "peds/ped.h"
#include "peds/ped.h"
#include "camera/replay/ReplayDirector.h"
#include "scene/RefMacros.h"
#include "weapons/info/weaponinfo.h"
#include "weapons/weapon.h"
AUDIO_WEAPONS_OPTIMISATIONS()
namespace rage
{
XPARAM(noaudio);
}
XPARAM(noaudiohardware);
class audOcclusionGroup;
static u8 g_MaxWeaponFiresPlayedPerFrame = 1;
static u32 s_AutoFireReleaseTime = 200;
REPLAY_ONLY(static u32 s_ReplayAutoFireReleaseTime = 500;)
static f32 g_BulletBySphereRadius = 1.0f;
static s32 g_BulletByMinTimeMs = 100, g_BulletByMaxTimeMs = 450;
static f32 g_ExplosionBulletByDistance = 10.0f;
static s32 g_ExplosionBulletByPredelay = 200;
static u32 g_AudNumPlayerWeaponSlots = 0;
f32 audWeaponAudioEntity::sm_InteriorSilencedWeaponWetness = 0.1f;
#if 1 //__BANK ...We want to make this bank again when the interior metrics are hooked up to meaningful values
bool g_ForceUseInteriorMetrics = false;
bool g_DebugInteriorMetrics = false;
float g_DebugInteriorWetness = 0.f;
float g_DebugOutsideVisability = 0.2f;
u32 g_DebugInteriorLpf = 24000;
u32 g_DebugInteriorPredelay = 0;
float g_DebugInteriorHold = 0.f;
#endif
f32 g_InteriorTransitionTime = 0.5f;
bool g_DisableTightSpotInteriorGuns = true;
bool g_PositionReportOppositeEcho = true;
bool g_PlayBothEchos = false;
waterCannonHitInfo audWeaponAudioEntity::sm_WaterCannonOnPedsInfo;
waterCannonHitInfo audWeaponAudioEntity::sm_WaterCannonOnVehInfo;
bool audWeaponAudioEntity::sm_IsWaitingOnEquippedWeaponLoad = false;
bool audWeaponAudioEntity::sm_UseBackupWeapons = false;
bool audWeaponAudioEntity::sm_IsWaitingOnNextWeaponLoad = false;
bool audWeaponAudioEntity::sm_WantsToLoadPlayerEquippedWeapon = false;
bool audWeaponAudioEntity::sm_UsingPlayerDistanceCam = false;
bool audWeaponAudioEntity::sm_Smooth = true;
f32 audWeaponAudioEntity::sm_TimeToMuteWaterCannon = 950.f;
bool audWeaponAudioEntity::sm_PlayerGunDampingOn = false;
u32 audWeaponAudioEntity::sm_LastTimePlayerGunFired = 0;
u32 audWeaponAudioEntity::sm_LastTimePlayerNotFiredGunForAWhile = 0; // this is the last time the player had gone g_NotFiredForAWhileTime without shooting.
f32 audWeaponAudioEntity::sm_PlayerGunDuckingAttenuation = 0.0f;
f32 audWeaponAudioEntity::sm_NpcReportIntensity = 0.f;
f32 audWeaponAudioEntity::sm_NpcReportIntensityDecreaseRate = 0.25f;
f32 audWeaponAudioEntity::sm_NpcReportCullingDistanceSq = 20.f*20.f;
f32 audWeaponAudioEntity::sm_IntensityForNpcReportDistanceCulling = 8.f;
f32 audWeaponAudioEntity::sm_IntensityForNpcReportFullCulling = 8.f;
u32 audWeaponAudioEntity::sm_PlayerHitBoostHoldTime = 1000;
f32 audWeaponAudioEntity::sm_PlayerhitBoostSmoothTime = 0.25f;
float audWeaponAudioEntity::sm_PlayerHitBoostVol = 0.f;
float audWeaponAudioEntity::sm_PlayerHitBoostRolloff = 1.f;
bool audWeaponAudioEntity::sm_SkipMinigunSpinUp = false;
u32 audWeaponAudioEntity::sm_BlockWeaponSpinFrame = 0;
u32 audWeaponAudioEntity::sm_WeaponAnimTimeFilter = 100;
u32 audWeaponAudioEntity::sm_AutoEmptyShotTimeFilter = 150;
audSoundSet audWeaponAudioEntity::sm_WaterCannonSounds;
audSoundSet audWeaponAudioEntity::sm_BulletByUnderwaterSounds;
audSoundSet audWeaponAudioEntity::sm_BulletByGeneralSounds;
audWaveSlotManager audWeaponAudioEntity::sm_PlayerWeaponSlotManager;
audPlayerWeaponSlot audWeaponAudioEntity::sm_PlayerEquippedWeaponSlot;
audPlayerWeaponSlot audWeaponAudioEntity::sm_ScriptWeaponSlot;
audPlayerWeaponSlot audWeaponAudioEntity::sm_PlayerNextWeaponSlot;
u32 audWeaponAudioEntity::sm_EmptyShotFilter = 50;
audCategory * g_WeaponCategory;
u32 audWeaponAudioEntity::sm_LastTimeSomeoneNearbyFiredAGun = 0;
u32 audWeaponAudioEntity::sm_LastTimeEnemyNearbyFiredAGun = 0;
f32 audWeaponAudioEntity::sm_GunfireFactor = 0.0f;
u32 g_TimeSinceSomeoneNearbyFiredToReduceFactor = 500;
f32 g_GunFiredFactorIncrease = 0.05f;
f32 g_GunNotFiredFactorDecrease = -0.025f;
f32 g_MaxDistanceToCountTowardFactor = 60.0f;
f32 g_EchoVolumeDrop = 0.0f;
u32 g_EchoDepth = 1;
u32 g_maxAutoSoundHoldTime = 500;
u32 g_MinAutoEchoLoopCount = 2;
u32 g_MinAutoEchoLoopCountIgnoreTime = 200;
f32 g_DefaultGunPostSubmixAttenuation = -3.0f;
u32 g_NotFiredForAWhileTime = 5000;
u32 g_BeenFiringForAWhileTime = 2000;
f32 g_DuckingAttenuationPerShot = -0.1f;
#if __BANK
bool g_PlayerGunNeverDamped = false;
bool g_PlayerGunAlwaysDamped = false;
bool g_AuditionWeaponFire = false;
bool g_bForceWeaponEchoSettings = false;
f32 g_fWeaponEchoAttenuation = -6.0f;
u32 g_uWeaponEchoPredelay = 50;
f32 g_ForceWaitForPlayerEquippedWeapon = 0.f;
u32 g_ForceWaitForPlayerEquippedWeaponTime = 0;
#endif
bool g_DebugWeaponTimings = false;
bool g_PlayerUsesNpcWeapons = false;
const u32 g_PedUpperBodyClothes = ATSTRINGHASH("PED_CLOTHING_UPPER", 0x0a1bf01c7);
const u32 g_PedLowerBodyClothes = ATSTRINGHASH("PED_CLOTHING_LOWER", 0x0a32e0d03);
const u32 g_CarPedInside = ATSTRINGHASH("CAR_PED_INSIDE", 0x06ae40991);
const u32 g_HeliPedInside = ATSTRINGHASH("HELI_PED_INSIDE", 0x0a3e70e3c);
const u32 g_HeliWeaponOn = ATSTRINGHASH("HELI_WEAPON_ON", 0x08296d80e);
const u32 g_BoatPedInside = ATSTRINGHASH("BOAT_PED_INSIDE", 0x0a4b96b67);
const u32 g_MotorbikePedInside = ATSTRINGHASH("MOTORBIKE_PED_INSIDE", 0x018ca9b44);
const u32 g_PedWeapon = ATSTRINGHASH("PED_WEAPON", 0x0bfa06c78);
audSoundSet audWeaponAudioEntity::sm_CodeSounds;
audSound * audWeaponAudioEntity::sm_ThermalGoggleSound;
audSound * audWeaponAudioEntity::sm_ThermalGoggleOffSound;
bool audWeaponAudioEntity::sm_ThermalGogglesOn;
u32 audWeaponAudioEntity::sm_PlayThermalGogglesSound = 0; // 0 = nosound, soundhash = play the sound
audWeaponFireEvent audWeaponAudioEntity::sm_WeaponFireEventList[g_MaxWeaponFireEventsPerFrame];
audWeaponAutoFireEvent audWeaponAudioEntity::sm_AutoWeaponsFiringList[g_MaxWeaponFireEventsPerFrame];
audWeaponFireEvent audWeaponAudioEntity::sm_LastWeaponFireEventPlayed;
audWeaponFireEvent audWeaponAudioEntity::sm_LastWeaponFireEventPlayedAgainstPlayer;
u8 audWeaponAudioEntity::sm_NumWeaponFireEventsThisFrame = 0;
// a global weapon audio entity for use with projectiles, script triggered weapon fire etc
audWeaponAudioEntity g_WeaponAudioEntity;
PF_PAGE(PlayerGunVolumePage, "PlayerGunVolume");
PF_GROUP(PlayerGunVolumeGroup);
PF_LINK(PlayerGunVolumePage, PlayerGunVolumeGroup);
PF_VALUE_FLOAT(PlayerGunVolume, PlayerGunVolumeGroup);
PF_VALUE_FLOAT(GunfireFactor, PlayerGunVolumeGroup);
PARAM(noweaponecho, "disables gun reports");
PARAM(rdrreportaudio, "turns on testing of RDR report system");
atRangeArray<weaponAnimEvent, WEAPON_AUDENTITY_NUM_ANIM_EVENTS> audWeaponAudioEntity::sm_WeaponAnimEvents;
atRangeArray<waterCannonHitInfo, NUM_MATERIALTYPE> audWeaponAudioEntity::sm_WaterCannonHitMapInfo;
atRangeArray<f32, 8> audWeaponAudioEntity::sm_ReportGoodness;
atRangeArray<Vector3, 24> audWeaponAudioEntity::sm_RelativeScanPositions;
atFixedArray<audProjectileData, g_MaxAudProjectileEvents> audWeaponAudioEntity::sm_ProjectileEvents;
atRangeArray<audWeaponSpinEvent, g_MaxAudWeaponSpinEvents> audWeaponAudioEntity::sm_WeaponSpinEvents;
atRangeArray<audProjectileCookEvent, g_MaxAudCookProjectileEvents> audWeaponAudioEntity::sm_ProjectileCookEvents;
audCurve audWeaponAudioEntity::sm_ReportGoodnessToAttenuationCurve;
audCurve audWeaponAudioEntity::sm_ReportGoodnessToPredelayCurve;
audCurve audWeaponAudioEntity::sm_ConductorEmphasizeFactorToVol;
audCurve audWeaponAudioEntity::sm_InteriorWetShotVolumeCurve;
audCurve audWeaponAudioEntity::sm_InteriorDryShotVolumeCurve;
audCurve audWeaponAudioEntity::sm_OutsideVisibilityReportVolumeCurve;
audCurve audWeaponAudioEntity::sm_StickyBombImpulseVolumeCurve;
bool audWeaponAudioEntity::sm_bIsReportStuffInited = false;
bool g_ShouldDrawReportGoodness = false;
f32 g_MaxDistanceForEnemyReport = 30.0f;
#if __BANK
bool g_DebugPlayerWeaponSlots = false;
#endif
#define REPLAY_SUPER_SLOW_MO_MARKER_SPEED_THRESHOLD 0.06f
#define REPLAY_SLOW_MO_MARKER_SPEED_THRESHOLD 0.21f
void audWeaponFireInfo::PopulatePresuckInfo(const WeaponSettings *settings, audWeaponFireInfo::PresuckInfo &presuckInfo)
{
if(!settings)
{
presuckInfo.presuckSound = g_NullSoundHash;
presuckInfo.presuckTime = 0;
presuckInfo.presuckScene = NULL_HASH;
return;
}
f32 markerSpeed = 1.0f;
#if GTA_REPLAY
if(audNorthAudioEngine::IsInSlowMoVideoEditor() || audNorthAudioEngine::IsSuperSlowVideoEditor())
{
markerSpeed = CReplayMgr::GetMarkerSpeed();
#if __BANK
if(audNorthAudioEngine::IsForcingSlowMoVideoEditor())
markerSpeed = 0.2f;
if(audNorthAudioEngine::IsForcingSuperSlowMoVideoEditor())
markerSpeed = 0.05f;
#endif
}
#endif
bool cienmaticSlowMo = audNorthAudioEngine::IsInCinematicSlowMo();
if(isSuppressed && settings->SuppressedFireSound != g_NullSoundHash)
{
presuckInfo.presuckSound = g_NullSoundHash;
if((cienmaticSlowMo || markerSpeed <= REPLAY_SLOW_MO_MARKER_SPEED_THRESHOLD) && settings->SlowMoSuppressedFireSoundPresuck != g_NullSoundHash)
{
presuckInfo.presuckSound = settings->SlowMoSuppressedFireSoundPresuck;
}
if(markerSpeed <= 0.06f && settings->SuperSlowMoSuppressedFireSoundPresuck != g_NullSoundHash)
{
presuckInfo.presuckSound = settings->SuperSlowMoSuppressedFireSoundPresuck;
}
presuckInfo.presuckTime = 0;
if(cienmaticSlowMo || markerSpeed <= REPLAY_SLOW_MO_MARKER_SPEED_THRESHOLD)
{
presuckInfo.presuckTime = settings->SlowMoSuppressedFireSoundPresuckTime;
}
if(markerSpeed <= 0.06f && settings->SuperSlowMoSuppressedFireSoundPresuckTime != 9999)
{
presuckInfo.presuckTime = settings->SuperSlowMoSuppressedFireSoundPresuckTime;
}
}
else
{
presuckInfo.presuckSound = g_NullSoundHash;
if((cienmaticSlowMo || markerSpeed <= REPLAY_SLOW_MO_MARKER_SPEED_THRESHOLD) && settings->SlowMoFireSoundPresuck != g_NullSoundHash)
{
presuckInfo.presuckSound = settings->SlowMoFireSoundPresuck;
}
if(markerSpeed <= REPLAY_SUPER_SLOW_MO_MARKER_SPEED_THRESHOLD && settings->SuperSlowMoFireSoundPresuck != g_NullSoundHash)
{
presuckInfo.presuckSound = settings->SuperSlowMoFireSoundPresuck;
}
presuckInfo.presuckTime = 0;
if(cienmaticSlowMo || markerSpeed <= REPLAY_SLOW_MO_MARKER_SPEED_THRESHOLD)
{
presuckInfo.presuckTime = settings->SlowMoFireSoundPresuckTime;
}
if(markerSpeed <= REPLAY_SUPER_SLOW_MO_MARKER_SPEED_THRESHOLD && settings->SuperSlowMoFireSoundPresuckTime != 9999)
{
presuckInfo.presuckTime = settings->SuperSlowMoFireSoundPresuckTime;
}
}
}
u32 audWeaponFireInfo::GetWeaponFireSound(const WeaponSettings * settings, const bool isLocalPlayer, audWeaponFireInfo::PresuckInfo* presuckInfo, bool isFinalKillShot) const
{
f32 markerSpeed = 1.0f;
#if GTA_REPLAY
if(audNorthAudioEngine::IsInSlowMoVideoEditor() || audNorthAudioEngine::IsSuperSlowVideoEditor())
{
markerSpeed = CReplayMgr::GetMarkerSpeed();
#if __BANK
if(audNorthAudioEngine::IsForcingSlowMoVideoEditor())
markerSpeed = 0.2f;
if(audNorthAudioEngine::IsForcingSuperSlowMoVideoEditor())
markerSpeed = 0.05f;
#endif
}
#endif
bool cienmaticSlowMo = audNorthAudioEngine::IsInCinematicSlowMo();
bool bIsSubmarine = parentEntity && parentEntity->GetIsTypeVehicle() && (((CVehicle*)parentEntity.Get())->InheritsFromSubmarine() || ((CVehicle*)parentEntity.Get())->InheritsFromSubmarineCar());
if(Water::IsCameraUnderwater() && !bIsSubmarine)
{
return g_WeaponAudioEntity.GetUnderWaterFireSound();
}
if(settings)
{
if(settings->FireSound != g_NullSoundHash || settings->AutoSound != g_NullSoundHash)
{
if(isLocalPlayer && (g_FrontendAudioEntity.GetSpecialAbilityMode() == audFrontendAudioEntity::kSpecialAbilityModeMichael || g_FrontendAudioEntity.GetSpecialAbilityMode() == audFrontendAudioEntity::kSpecialAbilityModeMultiplayer))
{
if(settings->FireSound == ATSTRINGHASH("SPL_STUN_MASTER", 0x744173DB))
{
return g_FrontendAudioEntity.GetSpecialAbilityMode() == audFrontendAudioEntity::kSpecialAbilityModeMultiplayer ?
ATSTRINGHASH("GTAO_Special_Ability_MP_Stun_Gun_Master", 0xCE390653) : ATSTRINGHASH("SPECIAL_ABILITY_MICHAEL_STUN_GUN_MASTER", 0x97906B1F);
}
if(audNorthAudioEngine::ShouldTriggerPulseHeadset())
{
return isSuppressed ? ATSTRINGHASH("SPECIAL_ABILITY_MICHAEL_SILENCED_GUN_PULSE", 0xFAF8B723) :
ATSTRINGHASH("SPECIAL_ABILITY_MICHAEL_GUN_PULSE", 0xFB3F431F);
}
if(g_FrontendAudioEntity.GetSpecialAbilityMode() == audFrontendAudioEntity::kSpecialAbilityModeMultiplayer)
{
return isSuppressed ? ATSTRINGHASH("GTAO_Special_Ability_MP_Silencer_Master", 0xD7729D27)
: ATSTRINGHASH("GTAO_Special_Ability_MP_Gun_Master", 0xF8551A1C);
}
else
{
return isSuppressed ? ATSTRINGHASH("SPECIAL_ABILITY_MICHAEL_SILENCER_MASTER", 0x7F7DD4E7)
: ATSTRINGHASH("SPECIAL_ABILITY_MICHAEL_GUN_MASTER", 0xEA3C1868);
}
}
else if(isLocalPlayer && g_FrontendAudioEntity.GetSpecialAbilityMode() == audFrontendAudioEntity::kSpecialAbilityModeTrevor)
{
return ATSTRINGHASH("TREVOR_WEAPON_FIRE_MASTER", 0x56C27B9B);
}
else if(isLocalPlayer && g_FrontendAudioEntity.GetSpecialAbilityMode() == audFrontendAudioEntity::kSpecialAbilityModeFranklin)
{
return ATSTRINGHASH("FRANKLIN_GUN_MASTER", 0xB99335D4);
}
}
if(isSuppressed && settings->SuppressedFireSound != g_NullSoundHash)
{
if(presuckInfo)
{
presuckInfo->presuckSound = g_NullSoundHash;
if((cienmaticSlowMo || markerSpeed <= REPLAY_SLOW_MO_MARKER_SPEED_THRESHOLD) && settings->SlowMoSuppressedFireSoundPresuck != g_NullSoundHash)
{
presuckInfo->presuckSound = settings->SlowMoSuppressedFireSoundPresuck;
}
if(markerSpeed <= REPLAY_SUPER_SLOW_MO_MARKER_SPEED_THRESHOLD && settings->SuperSlowMoSuppressedFireSoundPresuck != g_NullSoundHash)
{
presuckInfo->presuckSound = settings->SuperSlowMoSuppressedFireSoundPresuck;
}
presuckInfo->presuckTime = 0;
if(cienmaticSlowMo || markerSpeed <= REPLAY_SLOW_MO_MARKER_SPEED_THRESHOLD)
{
presuckInfo->presuckTime = settings->SlowMoSuppressedFireSoundPresuckTime;
}
if(markerSpeed <= REPLAY_SUPER_SLOW_MO_MARKER_SPEED_THRESHOLD && settings->SuperSlowMoSuppressedFireSoundPresuckTime != 9999)
{
presuckInfo->presuckTime = settings->SuperSlowMoSuppressedFireSoundPresuckTime;
}
}
if((isFinalKillShot || audNorthAudioEngine::IsInSlowMoVideoEditor() || audNorthAudioEngine::IsSuperSlowVideoEditor()))
{
u32 fireSound = settings->SuppressedFireSound;
if((isFinalKillShot || cienmaticSlowMo || markerSpeed <= REPLAY_SLOW_MO_MARKER_SPEED_THRESHOLD) && settings->SlowMoSuppressedFireSound != g_NullSoundHash)
{
fireSound = settings->SlowMoSuppressedFireSound;
}
if(markerSpeed <= REPLAY_SUPER_SLOW_MO_MARKER_SPEED_THRESHOLD && settings->SuperSlowMoSuppressedFireSound != g_NullSoundHash)
{
fireSound = settings->SuperSlowMoSuppressedFireSound;
}
return fireSound;
}
else
{
return settings->SuppressedFireSound;
}
}
else
{
if(presuckInfo)
{
presuckInfo->presuckSound = g_NullSoundHash;
if((cienmaticSlowMo || markerSpeed <= REPLAY_SLOW_MO_MARKER_SPEED_THRESHOLD) && settings->SlowMoFireSoundPresuck != g_NullSoundHash)
{
presuckInfo->presuckSound = settings->SlowMoFireSoundPresuck;
}
if(markerSpeed <= REPLAY_SUPER_SLOW_MO_MARKER_SPEED_THRESHOLD && settings->SuperSlowMoFireSoundPresuck != g_NullSoundHash)
{
presuckInfo->presuckSound = settings->SuperSlowMoFireSoundPresuck;
}
presuckInfo->presuckTime = 0;
if(cienmaticSlowMo || markerSpeed <= REPLAY_SLOW_MO_MARKER_SPEED_THRESHOLD)
{
presuckInfo->presuckTime = settings->SlowMoFireSoundPresuckTime;
}
if(markerSpeed <= REPLAY_SUPER_SLOW_MO_MARKER_SPEED_THRESHOLD && settings->SuperSlowMoFireSoundPresuckTime != 9999)
{
presuckInfo->presuckTime = settings->SuperSlowMoFireSoundPresuckTime;
}
}
if((isFinalKillShot || audNorthAudioEngine::IsInSlowMoVideoEditor() || audNorthAudioEngine::IsSuperSlowVideoEditor()))
{
u32 fireSound = settings->FireSound;
if((isFinalKillShot || cienmaticSlowMo || markerSpeed <= REPLAY_SLOW_MO_MARKER_SPEED_THRESHOLD) && settings->SlowMoFireSound != g_NullSoundHash)
{
fireSound = settings->SlowMoFireSound;
}
if(markerSpeed <= REPLAY_SUPER_SLOW_MO_MARKER_SPEED_THRESHOLD && settings->SuperSlowMoFireSound != g_NullSoundHash)
{
fireSound = settings->SuperSlowMoFireSound;
}
return fireSound;
}
else
{
return settings->FireSound;
}
}
}
return g_NullSoundHash;
}
const WeaponSettings * audWeaponFireInfo::FindWeaponSettings(bool BANK_ONLY(warnOnBackup))
{
// HL: Somewhat hacky fix for url:bugstar:5518385. This code forces vehicle mounted grenade launchers use the high quality audio *only* if the player is
// driving the vehicle (ie. passengers use resident/NPC assets). Because vehicle grenade launches are just selected from the weapon menu rather than being
// equippable objects, remote players are unaware that the driver has selected them, and so we can't guarantee that the high quality bank will be loaded.
if (parentEntity && parentEntity->GetIsTypeVehicle() && settingsHash == ATSTRINGHASH("AUDIO_ITEM_VEHICLE_WEAPON_GRENADELAUNCHER", 0xF1459D83))
{
CVehicle* parentVehicle = (CVehicle*)parentEntity.Get();
if (parentVehicle->ContainsLocalPlayer() && parentVehicle->GetDriver() != CGameWorld::FindLocalPlayer())
{
return g_WeaponAudioEntity.GetWeaponSettings(audioSettingsRef);
}
}
// End hacky fix
ItemAudioSettings * audioSettings = audNorthAudioEngine::GetMetadataManager().GetObject<ItemAudioSettings>(audioSettingsRef);
if((parentEntity && !g_PlayerUsesNpcWeapons && ((parentEntity->GetIsTypePed() && ((CPed*)parentEntity.Get())->IsLocalPlayer()))) || (parentEntity && parentEntity->GetIsTypeVehicle() && ((CVehicle*)parentEntity.Get())->ContainsLocalPlayer())) //Check if player ped
{
WeaponSettings * playerSettings = g_WeaponAudioEntity.GetWeaponSettings(audioSettingsRef, ATSTRINGHASH("player", 0x6F0783F5));
if(g_WeaponAudioEntity.IsWaitingOnEquippedWeaponLoad() || g_WeaponAudioEntity.ShouldUseBackupWeapons())
{
//In rare cases we can be waiting for a weapon to load but not the equipped one if the latter doesn't need to
//load any audio
if(playerSettings && (playerSettings->BankSound == g_NullSoundHash || playerSettings->BankSound == 0))
{
return playerSettings;
}
#if __BANK
if(warnOnBackup && settingsHash != g_WeaponAudioEntity.GetEquippedWeaponAudioHash())
{
audWarningf("Player weapon audio not loaded for %s, using backup audio", audNorthAudioEngine::GetMetadataManager().GetObjectName(settingsHash));
}
#endif
u32 contextHash = ATSTRINGHASH("player_backup", 0x321e6781);
u32 contextHash2 = ATSTRINGHASH("backup", 0xFD8506AE);
WeaponSettings * backupSettings = NULL;
if(audioSettings)
{
for(int i=0; i < audioSettings->numContextSettings; i++)
{
if(audioSettings->ContextSettings[i].Context == contextHash || audioSettings->ContextSettings[i].Context == contextHash2)
{
backupSettings = audNorthAudioEngine::GetObject<WeaponSettings>(audioSettings->ContextSettings[i].WeaponSettings);
break;
}
}
}
if(backupSettings)
{
return backupSettings;
}
}
return playerSettings;
}
return g_WeaponAudioEntity.GetWeaponSettings(audioSettingsRef);
}
u32 audWeaponFireInfo::GetWeaponEchoSound(const WeaponSettings * settings) const
{
if(isSuppressed && settings->SuppressedEchoSound != g_NullSoundHash)
{
return settings->SuppressedEchoSound;
}
return settings->EchoSound;
}
audWeaponAudioComponent::audWeaponAudioComponent() :
m_AutoFireLoop(NULL)
,m_SpinSound(NULL)
,m_InteriorAutoLoop(NULL)
,m_PulseHeadsetSound(NULL)
,m_SettingsHash(0)
,m_FrameLastEmptyShotFired(0)
,m_TimeLastEmptyShotFired(0)
,m_LastImpactTime(0)
,m_AnimIsAutoFiring(false)
,m_LastHitPlayerTime(0)
,m_LastAnimTime(0)
,m_LastAnimHash(0)
,m_SpecialAbilityMode(audFrontendAudioEntity::kSpecialAbilityModeNone)
,m_SpinBoneIndex(-1)
,m_ForceNPCVersion(false)
{
}
void audWeaponAudioComponent::Init(u32 audioHash, CWeapon * weapon, bool isScriptWeapon)
{
m_ItemSettings = audNorthAudioEngine::GetMetadataManager().GetObjectMetadataRefFromHash(audioHash);
m_Weapon = weapon;
m_SettingsHash = audioHash;
m_IsScriptWeapon = isScriptWeapon;
m_WasDropped = false;
#if __DEV
WeaponSettings * weaponSettings = audWeaponAudioEntity::GetWeaponSettings(audioHash);
g_WeaponAudioEntity.ValidateWeaponSettings(weaponSettings);
#endif
}
void audWeaponAudioComponent::HandleHitPlayer()
{
m_LastHitPlayerTime = g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0);
}
u32 audWeaponAudioEntity::GetPlayerBankIdFromWeaponSettings(WeaponSettings * settings)
{
if(PARAM_noaudio.Get())
{
return AUD_INVALID_BANK_ID;
}
if(settings)
{
// This helper class is passed down to the sound factory's ProcessHierarchy function, and gets called
// on every sound that we encounter in the hierarchy
class WeaponBankIdFn : public audSoundFactory::audSoundProcessHierarchyFn
{
public:
WeaponBankIdFn()
{
m_LoadBankId = AUD_INVALID_BANK_ID;
}
void operator()(u32 classID, const void* soundData)
{
if(classID == SimpleSound::TYPE_ID)
{
const SimpleSound * sound = reinterpret_cast<const SimpleSound*>(soundData);
if(sound)
{
m_LoadBankId = g_AudioEngine.GetSoundManager().GetFactory().GetBankIndexFromMetadataRef(sound->WaveRef.BankName);
}
}
}
u32 m_LoadBankId;
};
WeaponBankIdFn weaponBankIdFinder;
SOUNDFACTORY.ProcessHierarchy(settings->BankSound, weaponBankIdFinder);
return weaponBankIdFinder.m_LoadBankId;
}
return AUD_INVALID_BANK_ID;
}
#if __DEV
//Check that none of our sounds are using banks that we won't load in
void audWeaponAudioEntity::ValidateWeaponSettings(WeaponSettings * settings)
{
if(PARAM_noaudio.Get())
{
return;
}
if(settings)
{
class WeaponBankQueryFn : public audSoundFactory::audSoundProcessHierarchyFn
{
public:
u32 bankID;
WeaponBankQueryFn() { bankID = AUD_INVALID_BANK_ID; }
void operator()(u32 classID, const void* soundData)
{
if (classID == SimpleSound::TYPE_ID)
{
const SimpleSound * sound = reinterpret_cast<const SimpleSound*>(soundData);
bankID = g_AudioEngine.GetSoundManager().GetFactory().GetBankIndexFromMetadataRef(sound->WaveRef.BankName);
}
}
};
// This helper class is passed down to the sound factory's ProcessHierarchy function, and gets called
// on every sound that we encounter in the hierarchy
class WeaponBankValidationFn : public audSoundFactory::audSoundProcessHierarchyFn
{
public:
WeaponBankValidationFn()
{
m_LoadBankId = AUD_INVALID_BANK_ID;
m_HadError = false;
m_CurrentSound = NULL;
m_CurrenSettings = NULL;
}
void operator()(u32 classID, const void* soundData)
{
u32 bankID = AUD_INVALID_BANK_ID;
if(classID == SimpleSound::TYPE_ID)
{
const SimpleSound * sound = reinterpret_cast<const SimpleSound*>(soundData);
if(sound)
{
bankID = g_AudioEngine.GetSoundManager().GetFactory().GetBankIndexFromMetadataRef(sound->WaveRef.BankName);
}
}
if(bankID != AUD_INVALID_BANK_ID)
{
audWaveSlot* waveSlot = audWaveSlot::FindLoadedBankWaveSlot(bankID);
if(!naVerifyf((waveSlot && waveSlot->IsStatic()) || bankID == m_LoadBankId,
"Weapon settings %s contains a wave from bank %s in its %s which is neither static nor the dynamically load bank (%s), slot name: %s see following tty for details", m_CurrenSettings, g_AudioEngine.GetSoundManager().GetFactory().GetBankNameFromIndex(bankID), m_CurrentSound, g_AudioEngine.GetSoundManager().GetFactory().GetBankNameFromIndex(m_LoadBankId), waveSlot ? waveSlot->GetSlotName() : "(no waveslot)"))
{
m_HadError = true;
}
}
}
void SetSoundRefName(const char * soundRefName) {m_CurrentSound = soundRefName;}
void SetSettingsName(const char * settingsName) {m_CurrenSettings = settingsName;}
u32 m_LoadBankId;
bool m_HadError;
const char * m_CurrentSound;
const char * m_CurrenSettings;
};
WeaponBankQueryFn bankQueryFn;
SOUNDFACTORY.ProcessHierarchy(settings->BankSound, bankQueryFn);
u32 loadBankId = bankQueryFn.bankID;
WeaponBankValidationFn weaponBankValidator;
weaponBankValidator.m_LoadBankId = loadBankId;
weaponBankValidator.SetSettingsName(audNorthAudioEngine::GetMetadataManager().GetObjectNameFromNameTableOffset(settings->NameTableOffset));
weaponBankValidator.SetSoundRefName("FireSound");
SOUNDFACTORY.ProcessHierarchy(settings->FireSound, weaponBankValidator);
weaponBankValidator.SetSoundRefName("SuppressedFireSound");
SOUNDFACTORY.ProcessHierarchy(settings->SuppressedFireSound, weaponBankValidator);
weaponBankValidator.SetSoundRefName("AutoSound");
SOUNDFACTORY.ProcessHierarchy(settings->AutoSound, weaponBankValidator);
weaponBankValidator.SetSoundRefName("ReportSound");
SOUNDFACTORY.ProcessHierarchy(settings->ReportSound, weaponBankValidator);
}
}
#endif
WeaponSettings *audWeaponAudioComponent::GetWeaponSettings(const CEntity * parentEntity) const
{
if((parentEntity && ((parentEntity->GetIsTypePed() && ((CPed*)parentEntity)->IsLocalPlayer() && !g_PlayerUsesNpcWeapons))) || (parentEntity && parentEntity->GetIsTypeVehicle() && ((CVehicle*)parentEntity)->ContainsLocalPlayer())) //Check if player ped
{
MicrophoneSettings * mic = audNorthAudioEngine::GetMicrophones().GetMicrophoneSettings();
bool useDistanceMic = false;
if(mic && AUD_GET_TRISTATE_VALUE(mic->Flags, FLAG_ID_MICROPHONESETTINGS_DISTANTPLAYERWEAPONS) == AUD_TRISTATE_TRUE)
{
useDistanceMic = true;
}
if(!useDistanceMic)
{
return g_WeaponAudioEntity.GetWeaponSettings(m_ItemSettings, ATSTRINGHASH("player", 0x6F0783F5));
}
}
return g_WeaponAudioEntity.GetWeaponSettings(m_ItemSettings);
}
audWeaponAudioComponent::~audWeaponAudioComponent()
{
if(m_AutoFireLoop)
{
m_AutoFireLoop->StopAndForget();
}
if(m_SpinSound)
{
m_SpinSound->StopAndForget();
}
if(m_InteriorAutoLoop)
{
m_InteriorAutoLoop->StopAndForget();
}
if(m_PulseHeadsetSound)
{
m_PulseHeadsetSound->StopAndForget();
}
RemoveFromAutoFiringList();
}
audWeaponAudioEntity::audWeaponAudioEntity() :
m_NextBulletByTimeMs(0)
{
}
void audWeaponAudioEntity::Init()
{
//m_WeaponHash = weaponHash; //doesn't seem to be used at all
g_WeaponCategory = g_AudioEngine.GetCategoryManager().GetCategoryPtr(ATSTRINGHASH("WEAPONS", 0x803e392c));
if(!sm_bIsReportStuffInited)
{
for (int i=0; i<24; i++)
{
sm_RelativeScanPositions[i].Zero();
f32 angleInRadians = 2.0f * PI * ((f32)i)/24.0f;
sm_RelativeScanPositions[i].x = rage::Sinf(angleInRadians);
sm_RelativeScanPositions[i].y = rage::Cosf(angleInRadians);
}
for (int i=0; i<8; i++)
{
sm_ReportGoodness[i] = 0.0f;
}
sm_ReportGoodnessToAttenuationCurve.Init(ATSTRINGHASH("REPORT_GOODNESS_TO_ATTENUATION", 0x8B4491F1));
sm_ReportGoodnessToPredelayCurve.Init(ATSTRINGHASH("REPORT_GOODNESS_TO_PREDELAY", 0x5558A5D));
for (u32 i = HOLLOW_METAL ; i < NUM_MATERIALTYPE; i++)
{
sm_WaterCannonHitMapInfo[i].smoother.Init(0.001f,0.001f,0.f,1.f);
sm_WaterCannonHitMapInfo[i].sound = NULL;
sm_WaterCannonHitMapInfo[i].volume = 1.f;
sm_WaterCannonHitMapInfo[i].hitByWaterCannon = false;
}
sm_InteriorWetShotVolumeCurve.Init(ATSTRINGHASH("INTERIOR_WET_SHOT_VOLUME", 0xC20A3148));
sm_InteriorDryShotVolumeCurve.Init(ATSTRINGHASH("INTERIOR_DRY_SHOT_VOLUME", 0xD83C4607));
sm_OutsideVisibilityReportVolumeCurve.Init(ATSTRINGHASH("INTERIOR_OUTSIDE_VISABILITY_REPORT", 0x29BC32B2));
sm_StickyBombImpulseVolumeCurve.Init(ATSTRINGHASH("STICKY_BOMB_IMPULSE_VOLUME", 0x6BEEBD38));
sm_bIsReportStuffInited = true;
}
sm_WaterCannonOnPedsInfo.smoother.Init(0.001f,0.001f,0.f,1.f);
sm_WaterCannonOnVehInfo.smoother.Init(0.001f,0.001f,0.f,1.f);
sm_WaterCannonSounds.Init(ATSTRINGHASH("FIRE_TRUCK_WATER_CANNON_SOUNDSET", 0x46DB7A9E));
sm_BulletByGeneralSounds.Init(ATSTRINGHASH("BULLET_BYS_SOUNDSET", 0xB91BDEFA));
sm_BulletByUnderwaterSounds.Init(ATSTRINGHASH("BULLET_BYS_UNDERWATER_SOUNDSET", 0xD421775));
sm_WaterCannonOnPedsInfo.sound = NULL;
sm_WaterCannonOnVehInfo.sound = NULL;
m_WaterCannonPedHitDistSqd = LARGE_FLOAT;
// Seems SetUpWeapon() which calls Init() on us can be called more than once - which causes audEntity to assert.
if (GetControllerId()==AUD_INVALID_CONTROLLER_ENTITY_ID)
{
naAudioEntity::Init();
audEntity::SetName("audWeaponAudioEntity");
}
#if USE_CONDUCTORS
sm_ConductorEmphasizeFactorToVol.Init(ATSTRINGHASH("GUNFIGHT_CONDUCTOR_TEST", 0x28DABF0E));
m_IntensityFactor = 0.f;
#endif
char slotName[32];
for(u32 i = 0; i < g_AudMaxPlayerWeaponSlots; i++)
{
formatf(slotName, "PLAYER_WEAPON_%d", i);
if(!sm_PlayerWeaponSlotManager.AddWaveSlot(slotName, "PLAYER_WEAPON"))
{
break;
}
g_AudNumPlayerWeaponSlots++;
}
for(u32 i = 0; i < WEAPON_AUDENTITY_NUM_ANIM_EVENTS; i++)
{
sm_WeaponAnimEvents[i].hash = 0;
sm_WeaponAnimEvents[i].weapon = NULL;
}
sm_CodeSounds.Init(ATSTRINGHASH("CODED_WEAPON_SOUNDS", 0xB148A7E7));
sm_ThermalGoggleSound = NULL;
sm_ThermalGogglesOn = false;
sm_PlayThermalGogglesSound = 0;
m_LastDoubleActionWeaponSoundTime = 0;
sm_ProjectileEvents.Reset();
}
bool audWeaponAudioEntity::SuppressorIsVisible(const CWeapon *weapon)
{
if (weapon)
{
return weapon->GetSuppressorComponent() && weapon->GetSuppressorComponent()->GetDrawable() && weapon->GetSuppressorComponent()->GetDrawable()->GetIsVisibleForModule(SETISVISIBLE_MODULE_GAMEPLAY);
}
return false;
}
bool audWeaponAudioEntity::EquippedWeaponIsVisible(const CPed *ped)
{
if (ped)
{
return ped->GetWeaponManager() && ped->GetWeaponManager()->GetEquippedWeaponObject() && ped->GetWeaponManager()->GetEquippedWeaponObject()->GetIsVisibleForModule(SETISVISIBLE_MODULE_GAMEPLAY);
}
return false;
}
void audWeaponAudioEntity::HandleAnimFireEvent(u32 hash, CWeapon *weapon, CPed *ped)
{
audWeaponAudioComponent &weaponAudio = weapon->GetAudioComponent();
bool isSilenced = weapon->GetIsSilenced();
if (isSilenced && weapon->GetSuppressorComponent() && EquippedWeaponIsVisible(ped))
{
isSilenced = SuppressorIsVisible(weapon);
}
switch(hash)
{
case 0xDF8E89EB : //ATSTRINGHASH("WEAPON_FIRE", 0xDF8E89EB)
weaponAudio.PlayWeaponFire(ped, isSilenced);
break;
case 0xC2A57744 : //ATSTRINGHASH("AUTO_FIRE_START", 0xC2A57744)
weaponAudio.PlayWeaponFire(ped, isSilenced);
weaponAudio.SetAnimIsAutoFiring(true);
break;
case 0x3106F0FB : //ATSTRINGHASH("AUTO_FIRE_STOP", 0x3106F0FB)
weaponAudio.SetAnimIsAutoFiring(false);
break;
default:
break;
}
}
void audWeaponAudioEntity::AddWeaponAnimEvent(const audAnimEvent &event,CObject *weapon)
{
BANK_ONLY(bool success = false);
for(u32 i = 0; i < WEAPON_AUDENTITY_NUM_ANIM_EVENTS; i++)
{
if(sm_WeaponAnimEvents[i].hash == 0)
{
sm_WeaponAnimEvents[i].hash = event.hash;
sm_WeaponAnimEvents[i].weapon = weapon;
BANK_ONLY(success = true);
break;
}
}
#if __BANK
if(!success)
{
naAssertf(false,"Run out of slots to add new weapon anim events, please increase the num of events.");
}
#endif
}
void audWeaponAudioEntity::SetEmphasizeFactor(f32 factor)
{
m_IntensityFactor = factor;
}
void audWeaponAudioEntity::GetInteriorMetrics(audWeaponInteriorMetrics & interior, CEntity * parent)
{
if(parent)
{
bool isInterior = parent->GetIsInInterior();
f32 wetness = 0.f;
f32 outsideVisability = 1.f;
u32 lowPass = 24000;
u32 predelay = 0;
f32 hold = 0.f;
if(isInterior)
{
InteriorWeaponMetrics * metrics = audNorthAudioEngine::GetObject<InteriorWeaponMetrics>(ATSTRINGHASH("INTERIOR_WEAPON_LIVINGROOM_LARGE", 0x2EC29F31));
const InteriorSettings* interiorSettings = NULL;
const InteriorRoom* roomSettings = NULL;
audNorthAudioEngine::GetGtaEnvironment()->GetInteriorSettingsForEntity(parent, interiorSettings, roomSettings);
if(interiorSettings && roomSettings)
{
InteriorWeaponMetrics * roomMetrics = audNorthAudioEngine::GetObject<InteriorWeaponMetrics>(roomSettings->WeaponMetrics);
if(roomMetrics)
{
metrics = roomMetrics;
}
else if (parent && CNetwork::IsGameInProgress())
{
const CInteriorInst* intInst = CInteriorInst::GetInteriorForLocation(parent->GetAudioInteriorLocation());
// url:bugstar:6791016 - Sonar Jammer : When player is in the XM17 Sub interior full gun reports play - sounds weird
if (intInst && intInst->GetModelNameHash() == ATSTRINGHASH("xm_x17dlc_int_sub", 0x71F9D1B0))
{
metrics = audNorthAudioEngine::GetObject<InteriorWeaponMetrics>(ATSTRINGHASH("INTERIOR_WEAPON_SUBMARINE", 0x40ABC5BA));
}
}
}
if(metrics)
{
wetness = metrics->Wetness;
outsideVisability = metrics->Visability;
lowPass = metrics->LPF;
predelay = metrics->Predelay;
hold = metrics->Hold;
}
}
#if 1 //__BANK ...We want to make this BANK again when the interior metrics are hooked up to meaningful values
if(g_DebugInteriorMetrics && (isInterior || g_ForceUseInteriorMetrics))
{
wetness = g_DebugInteriorWetness;
outsideVisability = g_DebugOutsideVisability;
lowPass = g_DebugInteriorLpf;
predelay = g_DebugInteriorPredelay;
hold = g_DebugInteriorHold;
}
#endif
f32 smoothingAdd = ((f32)(audNorthAudioEngine::GetCurrentTimeInMs()-interior.LastTimeForCalc))/g_InteriorTransitionTime;
u32 smoothingFilters = (u32)(smoothingAdd*24000);
interior.LastTimeForCalc = audNorthAudioEngine::GetCurrentTimeInMs();
if(wetness != interior.Wetness)
{
f32 smoothedWetness = wetness < interior.Wetness ? Max(wetness, interior.Wetness-smoothingAdd) : Min(wetness, interior.Wetness+smoothingAdd);
interior.Wetness = smoothedWetness;
}
if(outsideVisability != interior.OutsideVisability)
{
f32 smoothedOutside = outsideVisability < interior.OutsideVisability ? Max(outsideVisability, interior.OutsideVisability-smoothingAdd) : Min(outsideVisability, interior.OutsideVisability+smoothingAdd);
interior.OutsideVisability = smoothedOutside;
}
if(lowPass != interior.Lpf)
{
u32 smoothedLpf = lowPass < interior.Lpf ? Max(lowPass, interior.Lpf-smoothingFilters) : Min(lowPass, interior.Lpf+smoothingFilters);
interior.Lpf = smoothedLpf;
}
if(predelay != interior.Predelay)
{
u32 smoothedPredelay = predelay < interior.Predelay ? Max(predelay, interior.Predelay-smoothingFilters) : Min(predelay, interior.Predelay+smoothingFilters);
interior.Predelay = smoothedPredelay;
}
if(hold != interior.Hold)
{
float smoothedHold = hold < interior.Hold ? Max(hold, interior.Hold-smoothingFilters) : Min(hold, interior.Hold+smoothingFilters);
interior.Hold = smoothedHold;
}
}
}
void audWeaponAudioComponent::TriggerEmptyShot(CVehicle* parent, const CVehicleWeapon* vehicleWeapon)
{
if(parent)
{
audVehicleAudioEntity* vehicleAudioEntity = parent->GetVehicleAudioEntity();
if(vehicleAudioEntity && vehicleAudioEntity->IsFocusVehicle())
{
u32 now = g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0);
WeaponSettings * weaponSettings = GetWeaponSettings(parent);
u32 weaponHash = vehicleWeapon->GetHash();
if(weaponSettings)
{
// Special ability forces all auto-fire weapons into single shot
if((((AUD_GET_TRISTATE_VALUE(weaponSettings->Flags, FLAG_ID_WEAPONSETTINGS_ISPLAYERAUTOFIRE)== AUD_TRISTATE_TRUE)) ||
((AUD_GET_TRISTATE_VALUE(weaponSettings->Flags, FLAG_ID_WEAPONSETTINGS_ISNPCAUTOFIRE)== AUD_TRISTATE_TRUE))))
{
if(m_TimeLastEmptyShotFired + audWeaponAudioEntity::sm_AutoEmptyShotTimeFilter < now)
{
m_FrameLastEmptyShotFired = 0;
}
}
}
if(m_FrameLastEmptyShotFired + 1 < fwTimer::GetFrameCount())
{
audSoundSet dryFireSounds;
dryFireSounds.Init(ATSTRINGHASH("EMPTY_WEAPON_SOUNDS", 0x13AC8CD3));
if(dryFireSounds.IsInitialised())
{
audMetadataRef dryFireSound = dryFireSounds.Find(weaponHash);
if(dryFireSound.IsValid())
{
audSoundInitParams initParams;
initParams.Position = VEC3V_TO_VECTOR3(parent->GetTransform().GetPosition());
initParams.TrackEntityPosition = true;
vehicleAudioEntity->CreateAndPlaySound(dryFireSound, &initParams);
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(dryFireSounds.GetNameHash(), weaponHash, &initParams, parent));
}
}
m_TimeLastEmptyShotFired = now;
}
m_FrameLastEmptyShotFired = fwTimer::GetFrameCount();
}
}
}
void audWeaponAudioComponent::TriggerEmptyShot(CPed * ped)
{
u32 now = g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0);
WeaponSettings * weaponSettings = GetWeaponSettings(ped);
if(weaponSettings)
{
// Special ability forces all auto-fire weapons into single shot
if((((AUD_GET_TRISTATE_VALUE(weaponSettings->Flags, FLAG_ID_WEAPONSETTINGS_ISPLAYERAUTOFIRE)== AUD_TRISTATE_TRUE)) ||
((AUD_GET_TRISTATE_VALUE(weaponSettings->Flags, FLAG_ID_WEAPONSETTINGS_ISNPCAUTOFIRE)== AUD_TRISTATE_TRUE))))
{
if(m_TimeLastEmptyShotFired + audWeaponAudioEntity::sm_AutoEmptyShotTimeFilter < now)
{
m_FrameLastEmptyShotFired = 0;
}
}
}
if(m_FrameLastEmptyShotFired + 1 < fwTimer::GetFrameCount())
{
audSoundInitParams initParams;
initParams.Position = VEC3V_TO_VECTOR3(ped->GetTransform().GetPosition());
audSoundSet dryFireSounds;
audMetadataRef dryFireSound;
dryFireSounds.Init(ATSTRINGHASH("EMPTY_WEAPON_SOUNDS", 0x13AC8CD3));
if(dryFireSounds.IsInitialised() && ped && ped->GetWeaponManager())
{
dryFireSound = dryFireSounds.Find(ped->GetWeaponManager()->GetEquippedWeaponHash());
}
if(dryFireSound.IsValid())
{
g_WeaponAudioEntity.CreateAndPlaySound(dryFireSound, &initParams);
#if GTA_REPLAY
if(CReplayMgr::ShouldRecord())
{
CReplayMgr::ReplayRecordSound(ATSTRINGHASH("EMPTY_WEAPON_SOUNDS", 0x13AC8CD3), ped->GetWeaponManager()->GetEquippedWeaponHash(), &initParams, NULL, NULL, eWeaponSoundEntity);
}
#endif
}
else
{
g_WeaponAudioEntity.CreateAndPlaySound(g_WeaponAudioEntity.FindSound(ATSTRINGHASH("EMPTY_FIRE", 0x90b0f84c)), &initParams);
#if GTA_REPLAY
if(CReplayMgr::ShouldRecord())
{
CReplayMgr::ReplayRecordSound(ATSTRINGHASH("CODED_WEAPON_SOUNDS", 0xB148A7E7), ATSTRINGHASH("EMPTY_FIRE", 0x90b0f84c), &initParams, NULL, NULL, eWeaponSoundEntity);
}
#endif
}
m_TimeLastEmptyShotFired = now;
// Apply small trigger rumble effect synced with the sound
CControlMgr::GetMainPlayerControl().ApplyRecoilEffect(50, 0.15f, 0.4f);
}
m_FrameLastEmptyShotFired = fwTimer::GetFrameCount();
}
void audWeaponAudioComponent::PlayWeaponFire(CEntity *parentEntity, bool isSilenced, bool forceSingleShot, bool isKillShot)
{
// In case it's a script weapon
if(m_IsScriptWeapon)
{
return;
}
#if __BANK
if(g_DebugWeaponTimings && parentEntity)
{
grcDebugDraw::Sphere(parentEntity->GetTransform().GetPosition(), 0.5f, Color32(255,255,0), true, 5);
}
#endif
naAssertf(g_WeaponAudioEntity.GetControllerId()!=AUD_INVALID_CONTROLLER_ENTITY_ID, "Invalid controller entity");
if(parentEntity && parentEntity->GetType() == ENTITY_TYPE_PED)
{
const CWeapon* pWeapon = ((CPed*)parentEntity)->GetWeaponManager()->GetEquippedWeapon();
if (isSilenced && pWeapon && pWeapon->GetSuppressorComponent() && g_WeaponAudioEntity.EquippedWeaponIsVisible((CPed*)parentEntity))
{
isSilenced = g_WeaponAudioEntity.SuppressorIsVisible(pWeapon);
}
((CPed*)parentEntity)->GetPedAudioEntity()->HandleWeaponFire(isSilenced);
}
if(GetWeaponSettings(parentEntity) == NULL)
{
return;
}
if(g_WeaponAudioEntity.GetControllerId()!=AUD_INVALID_CONTROLLER_ENTITY_ID && (g_WeaponAudioEntity.sm_NumWeaponFireEventsThisFrame < g_MaxWeaponFireEventsPerFrame))
{
//Cache this weapon fire event so we can decide which ones to play later in the game frame.
g_WeaponAudioEntity.sm_WeaponFireEventList[g_WeaponAudioEntity.sm_NumWeaponFireEventsThisFrame].fireInfo.isSuppressed = isSilenced;
g_WeaponAudioEntity.sm_WeaponFireEventList[g_WeaponAudioEntity.sm_NumWeaponFireEventsThisFrame].fireInfo.audioSettingsRef = m_ItemSettings;
g_WeaponAudioEntity.sm_WeaponFireEventList[g_WeaponAudioEntity.sm_NumWeaponFireEventsThisFrame].fireInfo.parentEntity = parentEntity;
g_WeaponAudioEntity.sm_WeaponFireEventList[g_WeaponAudioEntity.sm_NumWeaponFireEventsThisFrame].fireInfo.forceSingleShot = forceSingleShot;
g_WeaponAudioEntity.sm_WeaponFireEventList[g_WeaponAudioEntity.sm_NumWeaponFireEventsThisFrame].fireInfo.settingsHash = m_SettingsHash;
g_WeaponAudioEntity.sm_WeaponFireEventList[g_WeaponAudioEntity.sm_NumWeaponFireEventsThisFrame].fireInfo.isKillShot = isKillShot;
g_WeaponAudioEntity.sm_WeaponFireEventList[g_WeaponAudioEntity.sm_NumWeaponFireEventsThisFrame].weapon = m_Weapon;
g_WeaponAudioEntity.sm_NumWeaponFireEventsThisFrame++;
}
}
//-------------------------------------------------------------------------------------------------------------------
void audWeaponAudioEntity::CleanWaterCannonMapFlags()
{
for(u32 i = 0; i < NUM_MATERIALTYPE; i++)
{
sm_WaterCannonHitMapInfo[ i].hitByWaterCannon = false;
}
}
//-------------------------------------------------------------------------------------------------------------------
void audWeaponAudioEntity::CleanWaterCannonFlags()
{
sm_WaterCannonOnPedsInfo.hitByWaterCannon = false;
sm_WaterCannonOnVehInfo.hitByWaterCannon = false;
}
//-------------------------------------------------------------------------------------------------------------------
void audWeaponAudioEntity::PlayWaterCannonHit(Vec3V_In hitPosition,const CEntity *hitEntity,phMaterialMgr::Id matId,u16 component)
{
phMaterialMgr::Id unpackedMtlIdA = PGTAMATERIALMGR->UnpackMtlId(matId);
CollisionMaterialSettings * materialSettings = g_CollisionAudioEntity.GetMaterialOverride(hitEntity, g_audCollisionMaterials[(s32)unpackedMtlIdA],component);
MaterialType materialType = (MaterialType)materialSettings->MaterialType;
sm_WaterCannonHitMapInfo[(u32)materialType].volume = 1.f;
sm_WaterCannonHitMapInfo[(u32)materialType].hitByWaterCannon = true;
if(!sm_WaterCannonHitMapInfo[(u32)materialType].sound)
{
audSoundInitParams initParams;
initParams.Position = VEC3V_TO_VECTOR3(hitPosition);
initParams.EnvironmentGroup = hitEntity? hitEntity->GetAudioEnvironmentGroup() : NULL;
CreateAndPlaySound_Persistent(sm_WaterCannonSounds.Find(MaterialType_ToString(materialType)),&sm_WaterCannonHitMapInfo[(u32)materialType].sound,&initParams);
}
else
{
SmoothWaterCannonOnMap(1.f, 1.f,materialType);
sm_WaterCannonHitMapInfo[(u32)materialType].sound->SetRequestedPosition(hitPosition);
}
//naDisplayf("map material: %s, component: %u", audNorthAudioEngine::GetMetadataManager().GetObjectNameFromNameTableOffset(materialSettings->NameTableOffset), component);
}
//-------------------------------------------------------------------------------------------------------------------
void audWeaponAudioEntity::PlayWaterCannonHitVehicle(CVehicle *vehicle, Vec3V_In hitPosition)
{
sm_WaterCannonOnVehInfo.volume = 1.f;
sm_WaterCannonOnVehInfo.hitByWaterCannon = true;
if(!sm_WaterCannonOnVehInfo.sound)
{
audSoundInitParams initParams;
initParams.Position = VEC3V_TO_VECTOR3(hitPosition);
initParams.EnvironmentGroup = vehicle->GetAudioEnvironmentGroup();
CreateAndPlaySound_Persistent(sm_WaterCannonSounds.Find(ATSTRINGHASH("VEHICLES", 0x74B31BE3)),&sm_WaterCannonOnVehInfo.sound,&initParams);
}
else
{
SmoothWaterCannonOnVeh(1.f, 1.f);
sm_WaterCannonOnVehInfo.sound->SetRequestedPosition(hitPosition);
}
}
//-------------------------------------------------------------------------------------------------------------------
void audWeaponAudioEntity::PlayWaterCannonHitPed(CPed *ped, Vec3V_In hitPosition)
{
sm_WaterCannonOnPedsInfo.volume = 1.f;
sm_WaterCannonOnPedsInfo.hitByWaterCannon = true;
if(!sm_WaterCannonOnPedsInfo.sound)
{
audSoundInitParams initParams;
initParams.Position = VEC3V_TO_VECTOR3(hitPosition);
initParams.EnvironmentGroup = ped->GetAudioEnvironmentGroup();
CreateAndPlaySound_Persistent(sm_WaterCannonSounds.Find(ATSTRINGHASH("PEDS", 0x8DA12117)),&sm_WaterCannonOnPedsInfo.sound,&initParams);
}
else
{
SmoothWaterCannonOnPed(1.f, 1.f);
f32 distanceToListenerSqd = g_AudioEngine.GetEnvironment().ComputeSqdDistanceRelativeToVolumeListenerV(hitPosition).Getf();
if(distanceToListenerSqd < m_WaterCannonPedHitDistSqd)
{
// So we only do it once each update.
sm_WaterCannonOnPedsInfo.sound->SetRequestedPosition(hitPosition);
m_WaterCannonPedHitDistSqd = distanceToListenerSqd;
}
}
}
//-------------------------------------------------------------------------------------------------------------------
void audWeaponAudioEntity::TriggerWeaponReloadConfirmation(Vector3& position, const CVehicle* vehicle)
{
if(vehicle && ((CVehicleModelInfo*)(vehicle->GetBaseModelInfo()))->GetModelNameHash() == ATSTRINGHASH("CHERNOBOG", 0xD6BC7523))
{
TriggerVehicleWeaponSound(position, vehicle, ATSTRINGHASH("xm_vehicle_chernobog_missile_reloaded_master", 0xE707186C));
}
}
//-------------------------------------------------------------------------------------------------------------------
void audWeaponAudioEntity::TriggerNotReadyToFireSound(Vector3& position, const CVehicle* vehicle)
{
if(vehicle && ((CVehicleModelInfo*)(vehicle->GetBaseModelInfo()))->GetModelNameHash() == ATSTRINGHASH("CHERNOBOG", 0xD6BC7523))
{
TriggerVehicleWeaponSound(position, vehicle, ATSTRINGHASH("xm_vehicle_chernobog_missile_empty_master", 0xB61DA797));
}
}
//-------------------------------------------------------------------------------------------------------------------
void audWeaponAudioEntity::TriggerVehicleWeaponSound(Vector3& position, const CVehicle* vehicle, const u32 soundNameHash REPLAY_ONLY(, bool record))
{
if(vehicle)
{
audSoundInitParams initParams;
initParams.Position = position;
CreateDeferredSound(soundNameHash, vehicle, &initParams, true);
#if GTA_REPLAY
if(record)
{
CReplayMgr::ReplayRecordSound(soundNameHash, &initParams, vehicle);
}
}
#endif
}
//-------------------------------------------------------------------------------------------------------------------
void audWeaponAudioEntity::ProcessAnimEvents()
{
}
bool IsReloadHash(u32 hash)
{
return hash == ATSTRINGHASH("Reload1", 0xEC423F2D) || hash == ATSTRINGHASH("Reload2", 0xAE97C3CD) || ATSTRINGHASH("Reload3", 0xA0452728);
}
void audWeaponAudioEntity::ProcessWeaponAnimEvents()
{
for(int i=0; i< WEAPON_AUDENTITY_NUM_ANIM_EVENTS; i++)
{
if(sm_WeaponAnimEvents[i].hash != 0)
{
CObject *weapon = sm_WeaponAnimEvents[i].weapon;
if(weapon && weapon->GetWeapon())
{
audMetadataRef soundRef = g_AudioEngine.GetSoundManager().GetFactory().GetMetadataManager().GetObjectMetadataRefFromHash(sm_WeaponAnimEvents[i].hash);
CPed *player = CGameWorld::FindLocalPlayer();
bool isPlayerWeapon = false;
if(player)
{
if(player->GetWeaponManager())
{
CWeapon *pWeapon = weapon->GetWeapon();
CWeapon *playerWeapon = player->GetWeaponManager()->GetEquippedWeapon();
isPlayerWeapon = (pWeapon == playerWeapon);
}
}
u32 now = g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0);
if(sm_WeaponAnimEvents[i].hash == weapon->GetWeapon()->GetAudioComponent().GetLastAnimHash())
{
if(now <= weapon->GetWeapon()->GetAudioComponent().GetLastAnimTime() + sm_WeaponAnimTimeFilter)
{
sm_WeaponAnimEvents[i].hash = 0;
return;
}
}
weapon->GetWeapon()->GetAudioComponent().SetLastAnimTime(now);
weapon->GetWeapon()->GetAudioComponent().SetLastAnimHash(sm_WeaponAnimEvents[i].hash);
WeaponSettings *settings = weapon->GetWeapon()->GetAudioComponent().GetWeaponSettings((isPlayerWeapon ? player : NULL));
if(settings)
{
audSoundSet reloadSoundset;
reloadSoundset.Init(settings->ReloadSounds);
if(reloadSoundset.IsInitialised())
{
audMetadataRef soundSetComp = reloadSoundset.Find(sm_WeaponAnimEvents[i].hash);
if(soundSetComp.IsValid())
{
soundRef = soundSetComp;
}
else
{
// Reset the soundset so that we don't record it into the replay packet
reloadSoundset.Reset();
}
}
audSoundInitParams initParams;
BANK_ONLY(initParams.IsAuditioning = g_AuditionWeaponFire;);
initParams.Tracker = weapon->GetPlaceableTracker();
const CPed* owningPed = weapon->GetWeapon()->GetOwner();
if(owningPed)
{
initParams.EnvironmentGroup = owningPed->GetAudioEnvironmentGroup();
if(owningPed->IsLocalPlayer())
{
bool isFirstPerson = audNorthAudioEngine::IsAFirstPersonCameraActive(CGameWorld::FindLocalPlayer(), false);
if(isFirstPerson)
{
initParams.Tracker = owningPed->GetPlaceableTracker(); // maybe a better tracker or position is needed???
}
}
}
initParams.UpdateEntity = true;
initParams.AllowOrphaned = true;
g_WeaponAudioEntity.CreateAndPlaySound( soundRef , &initParams);
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(reloadSoundset.GetNameHash(), sm_WeaponAnimEvents[i].hash, &initParams, NULL, weapon, eWeaponSoundEntity));
}
}
}
//Reset event
sm_WeaponAnimEvents[i].hash = 0;
sm_WeaponAnimEvents[i].weapon = NULL;
}
}
void audWeaponAudioEntity::PreUpdateService(u32 timeInMs)
{
naAudioEntity::PreUpdateService(timeInMs);
TriggerDeferredProjectileEvents();
if(sm_Smooth)
{
if(sm_WaterCannonOnVehInfo.sound)
{
f32 newVolume = sm_WaterCannonOnVehInfo.smoother.CalculateValue(sm_WaterCannonOnVehInfo.volume, timeInMs);
sm_WaterCannonOnVehInfo.sound->SetRequestedVolume(audDriverUtil::ComputeDbVolumeFromLinear(newVolume));
if(newVolume <= g_SilenceVolumeLin )
{
sm_WaterCannonOnVehInfo.sound->StopAndForget();
}
}
if(sm_WaterCannonOnPedsInfo.sound)
{
f32 newVolume = sm_WaterCannonOnPedsInfo.smoother.CalculateValue(sm_WaterCannonOnPedsInfo.volume, timeInMs);
sm_WaterCannonOnPedsInfo.sound->SetRequestedVolume(audDriverUtil::ComputeDbVolumeFromLinear(newVolume));
if(newVolume <= g_SilenceVolumeLin )
{
sm_WaterCannonOnPedsInfo.sound->StopAndForget();
}
}
for (u32 i = 0; i < NUM_MATERIALTYPE; i++)
{
if(sm_WaterCannonHitMapInfo[i].sound)
{
f32 newVolume = sm_WaterCannonHitMapInfo[i].smoother.CalculateValue(sm_WaterCannonHitMapInfo[i].volume, timeInMs);
sm_WaterCannonHitMapInfo[i].sound->SetRequestedVolume(audDriverUtil::ComputeDbVolumeFromLinear(newVolume));
if(newVolume <= g_SilenceVolumeLin )
{
sm_WaterCannonHitMapInfo[i].sound->StopAndForget();
}
}
}
}
}
void audWeaponAudioEntity::PostUpdate()
{
ProcessWeaponAnimEvents();
for(int i=0; i<g_MaxAudWeaponSpinEvents; i++)
{
sm_WeaponSpinEvents[i].HandleWeaponSpin();
}
for(int i=0; i<g_MaxAudCookProjectileEvents; i++)
{
sm_ProjectileCookEvents[i].HandleCookProjectile();
}
if(sm_NpcReportIntensity > 0.f)
{
sm_NpcReportIntensity = sm_NpcReportIntensity - sm_NpcReportIntensity*sm_NpcReportIntensityDecreaseRate*fwTimer::GetTimeStep();
if(sm_NpcReportIntensity < 1.f)
{
sm_NpcReportIntensity = 0.f;
}
}
if(!sm_WaterCannonOnVehInfo.hitByWaterCannon && sm_WaterCannonOnVehInfo.sound)
{
if(sm_Smooth)
{
SmoothWaterCannonOnVeh(1.f/(sm_TimeToMuteWaterCannon), 0.f);
}
else
{
sm_WaterCannonOnVehInfo.sound->StopAndForget();
}
}
if(!sm_WaterCannonOnPedsInfo.hitByWaterCannon && sm_WaterCannonOnPedsInfo.sound)
{
if(sm_Smooth)
{
SmoothWaterCannonOnPed(1.f/(sm_TimeToMuteWaterCannon), 0.f);
}
else
{
sm_WaterCannonOnPedsInfo.sound->StopAndForget();
}
}
for (u32 i = 0; i < NUM_MATERIALTYPE; i++)
{
if(!sm_WaterCannonHitMapInfo[i].hitByWaterCannon && sm_WaterCannonHitMapInfo[i].sound)
{
if(sm_Smooth)
{
SmoothWaterCannonOnMap(1.f/(sm_TimeToMuteWaterCannon), 0.f,(MaterialType)i);
}
else
{
sm_WaterCannonHitMapInfo[i].sound->StopAndForget();
}
}
}
}
void audWeaponAudioEntity::SmoothWaterCannonOnMap(f32 rate,f32 desireLinVol,MaterialType matType)
{
// Set rates and desire volume
sm_WaterCannonHitMapInfo[matType].volume = desireLinVol;
sm_WaterCannonHitMapInfo[matType].smoother.SetRates(rate,rate);
// If the smoother hasn't been used yet, initialize it with the current volume (1 - desire)
if(!sm_WaterCannonHitMapInfo[matType].smoother.IsInitialized())
{
sm_WaterCannonHitMapInfo[matType].smoother.CalculateValue(1.f-desireLinVol,audNorthAudioEngine::GetCurrentTimeInMs());
}
}
void audWeaponAudioEntity::SmoothWaterCannonOnVeh(f32 rate,f32 desireLinVol)
{
// Set rates and desire volume
sm_WaterCannonOnVehInfo.volume = desireLinVol;
sm_WaterCannonOnVehInfo.smoother.SetRates(rate,rate);
// If the smoother hasn't been used yet, initialize it with the current volume (1 - desire)
if(!sm_WaterCannonOnVehInfo.smoother.IsInitialized())
{
sm_WaterCannonOnVehInfo.smoother.CalculateValue(1.f-desireLinVol,audNorthAudioEngine::GetCurrentTimeInMs());
}
}
void audWeaponAudioEntity::SmoothWaterCannonOnPed(f32 rate,f32 desireLinVol)
{
// Set rates and desire volume
sm_WaterCannonOnPedsInfo.volume = desireLinVol;
sm_WaterCannonOnPedsInfo.smoother.SetRates(rate,rate);
// If the smoother hasn't been used yet, initialize it with the current volume (1 - desire)
if(!sm_WaterCannonOnPedsInfo.smoother.IsInitialized())
{
sm_WaterCannonOnPedsInfo.smoother.CalculateValue(1.f-desireLinVol,audNorthAudioEngine::GetCurrentTimeInMs());
}
}
void audWeaponSpinEvent::HandleWeaponSpin()
{
if(isActive && entity)
{
CWeapon * forcedWeapon = weapon.Get();
if(entity->GetIsTypePed())
{
CPed * ped = (CPed*)entity.Get();
if(ped->GetWeaponManager())
{
CWeapon * weapon = forcedWeapon ? forcedWeapon : ped->GetWeaponManager()->GetEquippedWeapon();
if(weapon && (weapon->GetWeaponHash() == ATSTRINGHASH("weapon_minigun", 0x42BF8A85) || forcedWeapon))
{
bool playerAudioLoaded = g_WeaponAudioEntity.GetEquippedWeaponAudioHash() == ATSTRINGHASH("AUDIO_ITEM_MINIGUN", 0x674A2973) || g_WeaponAudioEntity.GetEquippedWeaponAudioHash() == ATSTRINGHASH("AUDIO_ITEM_VALKYRIE_MINIGUN", 0x967CB54B) || g_WeaponAudioEntity.GetEquippedWeaponAudioHash() == ATSTRINGHASH("AUDIO_ITEM_RAYMINIGUN", 0x142840C6);
//If the equipped weapon has not been set as minigun, we won't have the player waves loaded in e.g. a weapon is being forced but hasn't been equipped on the ped
weapon->GetAudioComponent().SpinUpWeapon(entity, !playerAudioLoaded);
}
}
}
else if(entity->GetIsTypeVehicle())
{
CWeapon * weapon = forcedWeapon;
if(weapon)
{
// Player spin up sound is specific to the minigun weapon bank, so we need to use the NPC version unless we're actually using the minigun
weapon->GetAudioComponent().SpinUpWeapon(entity, weapon->GetWeaponHash() != ATSTRINGHASH("weapon_minigun", 0x42BF8A85), boneIndex);
}
}
else if(entity->GetIsTypeObject())
{
CObject *object = (CObject *)entity.Get();
if(object)
{
CWeapon *weapon = forcedWeapon ? forcedWeapon : object->GetWeapon();
if(weapon)
{
// Player spin up sound is specific to the minigun weapon bank, so we need to use the NPC version unless we're actually using the minigun
weapon->GetAudioComponent().SpinUpWeapon(weapon->GetOwner(), weapon->GetWeaponHash() != ATSTRINGHASH("weapon_minigun", 0x42BF8A85));
}
}
}
}
isActive = false;
entity = NULL;
weapon = NULL;
}
void audProjectileCookEvent::HandleCookProjectile()
{
if(isActive && entity)
{
if(entity->GetIsTypePed())
{
CPed * ped = (CPed*)entity.Get();
if(ped->GetWeaponManager())
{
CWeapon * weapon = ped->GetWeaponManager()->GetEquippedWeapon();
if(weapon)
{
weapon->GetAudioComponent().PlayCookProjectileSound(entity);
}
}
}
else if(entity->GetIsTypeVehicle())
{
CVehicle * vehicle = (CVehicle *)entity.Get();
CPed * ped = vehicle->GetDriver();
if(ped && ped->GetWeaponManager())
{
CWeapon * weapon = ped->GetWeaponManager()->GetEquippedWeapon();
if(weapon)
{
weapon->GetAudioComponent().PlayCookProjectileSound(entity);
}
}
}
}
isActive = false;
entity = NULL;
}
void audWeaponAudioEntity::SpinUpWeapon(const CEntity * parentEntity, CWeapon * weapon, s32 boneIndex)
{
for(int i=0; i < g_MaxAudWeaponSpinEvents; i++)
{
if(!sm_WeaponSpinEvents[i].isActive)
{
sm_WeaponSpinEvents[i].isActive = true;
sm_WeaponSpinEvents[i].entity = parentEntity;
sm_WeaponSpinEvents[i].weapon = weapon;
sm_WeaponSpinEvents[i].boneIndex = boneIndex;
break;
}
}
}
void audWeaponAudioEntity::CookProjectile(const CEntity * parentEntity)
{
for(int i=0; i < g_MaxAudCookProjectileEvents; i++)
{
if(!sm_ProjectileCookEvents[i].isActive)
{
sm_ProjectileCookEvents[i].isActive = true;
sm_ProjectileCookEvents[i].entity = parentEntity;
break;
}
}
}
void audWeaponAudioComponent::SpinUpWeapon(const CEntity * parentEntity, bool forceNPCVersion, s32 boneIndex)
{
if(!m_SpinSound)
{
m_SpinOwner = parentEntity;
m_SpinBoneIndex = boneIndex;
m_ForceNPCVersion = forceNPCVersion;
audWeaponAudioEntity::PlaySpinUpSound(parentEntity, &m_SpinSound, forceNPCVersion, false, boneIndex);
}
}
void audWeaponAudioComponent::CookProjectile(const CEntity * parentEntity)
{
if(!m_SpinSound)
{
g_WeaponAudioEntity.CookProjectile(parentEntity);
}
}
void audWeaponAudioComponent::PlayCookProjectileSound(const CEntity * entity)
{
if(!m_SpinSound && entity && entity->GetAudioEntity())
{ audSoundInitParams initParams;
initParams.TrackEntityPosition = true;
entity->GetAudioEntity()->CreateAndPlaySound_Persistent(g_WeaponAudioEntity.FindSound(ATSTRINGHASH("GrenadeTimeout", 0xD18540C)), &m_SpinSound, &initParams);
}
}
void audWeaponAudioComponent::StopCookProjectile()
{
if(m_SpinSound)
{
m_SpinSound->StopAndForget();
}
}
void audWeaponAudioComponent::SpinDownWeapon()
{
if(m_SpinSound)
{
m_SpinSound->StopAndForget(true);
}
}
void audWeaponAudioComponent::UpdateSpin()
{
#if GTA_REPLAY
if(CReplayMgr::IsRecording() && m_SpinSound && m_SpinOwner)
{
if(CReplayMgr::ShouldRecord())
{
CReplayMgr::RecordPersistantFx<CPacketWeaponSpinUp>(
CPacketWeaponSpinUp(true, m_SpinBoneIndex, m_ForceNPCVersion),
CTrackedEventInfo<tTrackedSoundType>(m_SpinSound),
m_SpinOwner,
true);
}
}
#endif
}
void audWeaponAudioEntity::TriggerFlashlight(const CWeapon* weapon,bool active)
{
if(weapon)
{
audSoundInitParams initParams;
initParams.Position = VEC3V_TO_VECTOR3(weapon->GetEntity()->GetTransform().GetPosition());
initParams.Volume = 0.f;
u32 fieldHash = ATSTRINGHASH("rifleFlashlight", 0x1EEE94D5);
if(weapon->GetWeaponHash() == ATSTRINGHASH("WEAPON_FLASHLIGHT", 0x8BB05FD7))
{
if(active)
{
fieldHash = ATSTRINGHASH("flashlightOn", 0x5EF7274F);
}
else
{
fieldHash = ATSTRINGHASH("flashlightOff", 0x66ECAB94);
}
}
CreateAndPlaySound(FindSound(fieldHash), &initParams);
#if GTA_REPLAY
if(CReplayMgr::ShouldRecord())
{
CReplayMgr::ReplayRecordSound(ATSTRINGHASH("CODED_WEAPON_SOUNDS", 0xB148A7E7), fieldHash, &initParams, NULL, NULL, eWeaponSoundEntity);
}
#endif
}
}
void audWeaponAudioEntity::ToggleThermalVision(bool turnOn, bool forcePlay)
{
if(!turnOn && (sm_ThermalGogglesOn || forcePlay))
{
if(sm_ThermalGoggleSound)
{
sm_ThermalGoggleSound->StopAndForget();
}
sm_PlayThermalGogglesSound = ATSTRINGHASH("ThermalVisionOff", 0x5A1DC4BB); // off sound
#if GTA_REPLAY
if(CReplayMgr::ShouldRecord())
{
CReplayMgr::RecordFx<CPacketThermalScopeAudio>(CPacketThermalScopeAudio(turnOn));
}
#endif
}
else if(turnOn && (!sm_ThermalGogglesOn || forcePlay))
{
if(sm_ThermalGoggleOffSound)
{
sm_ThermalGoggleOffSound->StopAndForget();
}
sm_PlayThermalGogglesSound = ATSTRINGHASH("ThermalVision", 0x655D7D08);
#if GTA_REPLAY
if(CReplayMgr::ShouldRecord())
{
CReplayMgr::RecordFx<CPacketThermalScopeAudio>(CPacketThermalScopeAudio(turnOn));
}
#endif
}
sm_ThermalGogglesOn = turnOn;
}
void audWeaponAudioEntity::UpdateThermalVision()
{
if(sm_PlayThermalGogglesSound != 0)
{
audSoundInitParams initParams;
initParams.Pan = 0;
if(sm_PlayThermalGogglesSound == ATSTRINGHASH("ThermalVisionOff", 0x5A1DC4BB)) // off sound
{
if(sm_ThermalGoggleOffSound)
{
sm_ThermalGoggleOffSound->StopAndForget();
}
CreateAndPlaySound_Persistent(FindSound(sm_PlayThermalGogglesSound), &sm_ThermalGoggleOffSound, &initParams);
}
else if(sm_PlayThermalGogglesSound == ATSTRINGHASH("ThermalVision", 0x655D7D08)) // on sound
{
if(sm_ThermalGoggleSound)
{
sm_ThermalGoggleSound->StopAndForget();
}
CreateAndPlaySound_Persistent(FindSound(sm_PlayThermalGogglesSound), &sm_ThermalGoggleSound, &initParams);
}
sm_PlayThermalGogglesSound = 0;
}
}
void audWeaponAudioEntity::TriggerStickyBombAttatch(Vec3V_In position, CEntity* stuckEntity, u32 stuckComponent, phMaterialMgr::Id matId, float impulse, CEntity* owner, audMetadataRef stickSoundRef)
{
audSoundInitParams initParams;
initParams.Position = VEC3V_TO_VECTOR3(position);
initParams.EnvironmentGroup = g_CollisionAudioEntity.GetOcclusionGroup(position, stuckEntity, matId);
initParams.IsStartOffsetPercentage = true;
initParams.Volume = audDriverUtil::ComputeDbVolumeFromLinear(sm_StickyBombImpulseVolumeCurve.CalculateValue(impulse));
if(!sm_StickyBombImpulseVolumeCurve.IsValid())
{
initParams.Volume = 0.f;
}
audPedAudioEntity * pedAudio = NULL;
if(owner && owner->GetIsTypePed())
{
pedAudio = ((CPed*)owner)->GetPedAudioEntity();
}
static u32 lastAttatchTime = 0;
if(pedAudio)
{
lastAttatchTime = pedAudio->GetLastStickyBombTime();
}
if(lastAttatchTime + 100 > g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0))
{
return;
}
lastAttatchTime = g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0);
if(pedAudio)
{
pedAudio->SetLastStickyBombTime(lastAttatchTime);
}
s32 mati = 0;
if(naVerifyf(PGTAMATERIALMGR->UnpackMtlId(matId)<(phMaterialMgr::Id)g_audCollisionMaterials.GetCount(), "Unpacked mtl id too large"))
{
if(naVerifyf(PGTAMATERIALMGR->UnpackMtlId(matId)<(phMaterialMgr::Id)0xffff, "Unpacked mtl id too big for s32 cast"))
{
mati = static_cast<s32>(PGTAMATERIALMGR->UnpackMtlId(matId));
}
}
CollisionMaterialSettings * hitSettings = g_CollisionAudioEntity.GetMaterialOverride(stuckEntity,g_audCollisionMaterials[mati], stuckComponent);
bool isVehicle = false;
if(stuckEntity && stuckEntity->GetIsTypeVehicle() && stuckEntity->GetAudioEntity())
{
isVehicle = true;
hitSettings = ((audVehicleAudioEntity *)stuckEntity->GetAudioEntity())->GetCollisionAudio().GetVehicleCollisionMaterialSettings();
}
u32 hitSound = g_NullSoundHash, softHitSound = g_NullSoundHash;
//naErrorf("Sticky bomb material %s (base %s)", audNorthAudioEngine::GetMetadataManager().GetObjectNameFromNameTableOffset(hitSettings->NameTableOffset), audNorthAudioEngine::GetMetadataManager().GetObjectNameFromNameTableOffset(g_audCollisionMaterials[mati]->NameTableOffset));
if(hitSettings)
{
if(hitSettings->HardImpact != g_NullSoundHash)
{
hitSound = hitSettings->HardImpact;
}
else
{
hitSound = hitSettings->SolidImpact;
}
softHitSound = hitSettings->SoftImpact;
if(isVehicle)
{
hitSound = hitSettings->BulletImpactSound;
}
CreateAndPlaySound(hitSound, &initParams);
CreateAndPlaySound(softHitSound, &initParams);
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(hitSound, &initParams, NULL, NULL, eWeaponSoundEntity));
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(softHitSound, &initParams, NULL, NULL, eWeaponSoundEntity));
}
//if(initParams.Volume == 0.f)
//{
// audNorthAudioEngine::GetGtaEnvironment()->SpikeResonanceObjects(impulse, VEC3V_TO_VECTOR3(position), 0.5f);
//}
initParams.Volume = 0.f;
CreateAndPlaySound(stickSoundRef, &initParams);
//TODO: need to change this to account for the possibility of having a proximity mine instead of a sticky bomb
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(sm_CodeSounds.GetNameHash(), ATSTRINGHASH("sticky_bomb_hit", 2782906396), &initParams, NULL, NULL, eWeaponSoundEntity));
}
void audWeaponAudioEntity::PlaySpinUpSound(const CEntity * parentEntity, audSound ** spinSound, bool forceNPCVersion, bool skipSpinUp, s32 boneIndex)
{
const audEnvironmentGroupInterface* occlusionGroup = NULL;
Vector3 sourcePosition;
sourcePosition.Zero();
const audTracker *tracker = parentEntity->GetPlaceableTracker();
if(fwTimer::GetFrameCount() == sm_BlockWeaponSpinFrame)
{
return;
}
if(spinSound)
{
if(*spinSound)
{
return;
}
if (parentEntity && parentEntity->GetIsTypePed())
{
occlusionGroup = ((CPed*)parentEntity)->GetWeaponEnvironmentGroup();
}
else if (parentEntity && parentEntity->GetIsTypeVehicle())
{
occlusionGroup = ((CVehicle*)parentEntity)->GetAudioEnvironmentGroup();
}
if(tracker)
{
sourcePosition = tracker->GetPosition();
}
else if(parentEntity)
{
sourcePosition = VEC3V_TO_VECTOR3(parentEntity->GetTransform().GetPosition());
}
audSoundInitParams initParams;
BANK_ONLY(initParams.IsAuditioning = g_AuditionWeaponFire;);
audEntity* audioEntity = &g_WeaponAudioEntity;
if(boneIndex != -1 && parentEntity && parentEntity->GetIsTypeVehicle() && parentEntity->GetAudioEntity())
{
audioEntity = parentEntity->GetAudioEntity();
initParams.UpdateEntity = true;
initParams.u32ClientVar = (u32(AUD_VEHICLE_SOUND_CUSTOM_BONE)&0xffff) | ((u32)boneIndex << 16);
}
else
{
initParams.Tracker = tracker;
initParams.Position = sourcePosition;
}
initParams.EnvironmentGroup = occlusionGroup;
if(sm_PlayerEquippedWeaponSlot.waveSlot && sm_PlayerEquippedWeaponSlot.waveSlot->waveSlot && sm_PlayerEquippedWeaponSlot.waveSlot->IsLoaded())
{
initParams.WaveSlot = sm_PlayerEquippedWeaponSlot.waveSlot->waveSlot;
}
bool isPlayerWeapon = parentEntity && ((parentEntity->GetIsTypePed() && ((CPed*)parentEntity)->IsLocalPlayer()) || (parentEntity->GetIsTypeVehicle() && parentEntity == FindPlayerVehicle()));
bool useTampa3DualMinigunSounds = false;
bool useRaygunSounds = false;
bool useVehicleRaygunSounds = false;
if (parentEntity->GetIsTypePed())
{
const CWeaponInfo *pWeaponInfo = ((CPed*)parentEntity)->GetWeaponManager() ? ((CPed*)parentEntity)->GetWeaponManager()->GetEquippedWeaponInfo() : NULL;
if (pWeaponInfo && pWeaponInfo->GetAudioHash() == ATSTRINGHASH("AUDIO_ITEM_RAYMINIGUN", 0x142840C6))
{
useRaygunSounds = true;
}
else if (pWeaponInfo && pWeaponInfo->GetAudioHash() == ATSTRINGHASH("AUDIO_ITEM_VEHICLE_WEAPON_MINIGUN_LASER", 0x55B60F3))
{
useVehicleRaygunSounds = true;
}
}
if(parentEntity && parentEntity->GetIsTypeVehicle())
{
CVehicle* parentVehicle = (CVehicle*)parentEntity;
CVehicleModelInfo *model = (CVehicleModelInfo*)(parentVehicle->GetBaseModelInfo());
if(model->GetModelNameHash() == ATSTRINGHASH("TAMPA3", 0xB7D9F7F1))
{
const u32 roofModIndex = parentVehicle->GetVariationInstance().GetModIndex(VMT_ROOF);
if(roofModIndex != INVALID_MOD)
{
useTampa3DualMinigunSounds = true;
}
}
else if (model->GetModelNameHash() == ATSTRINGHASH("OPPRESSOR2", 0x7B54A9D3))
{
isPlayerWeapon = false;
}
else if (model->GetModelNameHash() == ATSTRINGHASH("Deathbike2", 0x93F09558))
{
const u32 chassisModIndex = parentVehicle->GetVariationInstance().GetModIndex(VMT_CHASSIS5);
if (chassisModIndex != INVALID_MOD)
{
useVehicleRaygunSounds = true;
}
}
}
if(isPlayerWeapon && !g_PlayerUsesNpcWeapons && !forceNPCVersion)
{
if(sm_SkipMinigunSpinUp || skipSpinUp )
{
if (useVehicleRaygunSounds)
{
audioEntity->CreateAndPlaySound_Persistent(ATSTRINGHASH("w_vehicle_SPL_RAYMINIGUN_SERVO_NOSPINUP_MASTER", 0x22BFA04C), spinSound, &initParams);
}
else if (useRaygunSounds)
{
audioEntity->CreateAndPlaySound_Persistent(ATSTRINGHASH("DLC_AW_SPL_RAYMINIGUN_SERVO_NOSPINUP_MASTER", 0x50A9E6FF), spinSound, &initParams);
}
else if(useTampa3DualMinigunSounds)
{
audioEntity->CreateAndPlaySound_Persistent(ATSTRINGHASH("gr_vehicle_tampa_dualminigun_servo_nospinup_master", 0x2259A591), spinSound, &initParams);
}
else
{
audioEntity->CreateAndPlaySound_Persistent(FindSound(ATSTRINGHASH("MINIGUN_SPIN_NO_INTRO", 0x351B1EDA)), spinSound, &initParams);
}
}
else
{
if (useVehicleRaygunSounds)
{
audioEntity->CreateAndPlaySound_Persistent(ATSTRINGHASH("w_vehicle_SPL_RAYMINIGUN_SERVO_MASTER", 0xDDE02672), spinSound, &initParams);
}
if (useRaygunSounds)
{
audioEntity->CreateAndPlaySound_Persistent(ATSTRINGHASH("DLC_AW_SPL_RAYMINIGUN_SERVO_MASTER", 0x808BC3B3), spinSound, &initParams);
}
else if(useTampa3DualMinigunSounds)
{
audioEntity->CreateAndPlaySound_Persistent(ATSTRINGHASH("gr_vehicle_tampa_dualminigun_servo_spinup_master", 0xC887C2CB), spinSound, &initParams);
}
else
{
audioEntity->CreateAndPlaySound_Persistent(FindSound(ATSTRINGHASH("MINIGUN_SPIN", 0x930026)), spinSound, &initParams);
}
}
}
else
{
if(sm_SkipMinigunSpinUp || skipSpinUp)
{
if (useVehicleRaygunSounds)
{
audioEntity->CreateAndPlaySound_Persistent(ATSTRINGHASH("w_vehicle_SPL_RAYMINIGUN_NPC_SERVO_NOSPINUP_MASTER", 0x100BCCEE), spinSound, &initParams);
}
else if (useRaygunSounds)
{
audioEntity->CreateAndPlaySound_Persistent(ATSTRINGHASH("DLC_AW_SPL_RAYMINIGUN_NPC_SERVO_NOSPINUP_MASTER", 0x9D88B2D9), spinSound, &initParams);
}
else if(useTampa3DualMinigunSounds)
{
audioEntity->CreateAndPlaySound_Persistent(ATSTRINGHASH("gr_vehicle_tampa_dualminigun_npc_servo_nospinup_master", 0x4D4EB33), spinSound, &initParams);
}
else
{
audioEntity->CreateAndPlaySound_Persistent(FindSound(ATSTRINGHASH("MINIGUN_NPC_NO_INTRO", 0x9169397)), spinSound, &initParams);
}
}
else
{
if (useVehicleRaygunSounds)
{
audioEntity->CreateAndPlaySound_Persistent(ATSTRINGHASH("w_vehicle_SPL_RAYMINIGUN_NPC_SERVO_MASTER", 0xF581CBB), spinSound, &initParams);
}
else if (useRaygunSounds)
{
audioEntity->CreateAndPlaySound_Persistent(ATSTRINGHASH("DLC_AW_SPL_RAYMINIGUN_NPC_SERVO_MASTER", 0x1124C582), spinSound, &initParams);
}
else if(useTampa3DualMinigunSounds)
{
audioEntity->CreateAndPlaySound_Persistent(ATSTRINGHASH("gr_vehicle_tampa_dualminigun_npc_servo_spinup_master", 0x682AC498), spinSound, &initParams);
}
else
{
audioEntity->CreateAndPlaySound_Persistent(FindSound(ATSTRINGHASH("MINIGUN_NPC", 0xcb2d3b70)), spinSound, &initParams);
}
}
}
#if GTA_REPLAY
if(CReplayMgr::ShouldRecord())
{
CReplayMgr::RecordPersistantFx<CPacketWeaponSpinUp>(
CPacketWeaponSpinUp(skipSpinUp, boneIndex, forceNPCVersion),
CTrackedEventInfo<tTrackedSoundType>(*spinSound),
(CEntity*)parentEntity,
true);
}
#endif // GTA_REPLAY
}
}
void audWeaponAudioEntity::PlayWeaponReport(audWeaponFireInfo * fireInfo, const audWeaponInteriorMetrics * interior, const WeaponSettings * weaponSettings, float fDist, bool dontPlayEcho)
{
#if !__FINAL
if (PARAM_noweaponecho.Get())
return;
#endif
if(!fireInfo || fireInfo->isSuppressed)
{
return;
}
f32 outsideVisability = interior->OutsideVisability;
f32 interiorVolumeScaling = 1.f;
if(outsideVisability < 1.f)
{
interiorVolumeScaling = sm_OutsideVisibilityReportVolumeCurve.CalculateValue(outsideVisability);
}
if(interiorVolumeScaling == 0.f)
{
return;
}
f32 markerSpeed = 1.0f;
#if GTA_REPLAY
if(audNorthAudioEngine::IsInSlowMoVideoEditor() || audNorthAudioEngine::IsSuperSlowVideoEditor())
{
markerSpeed = CReplayMgr::GetMarkerSpeed();
#if __BANK
if(audNorthAudioEngine::IsForcingSlowMoVideoEditor())
markerSpeed = 0.2f;
if(audNorthAudioEngine::IsForcingSuperSlowMoVideoEditor())
markerSpeed = 0.05f;
#endif
}
#endif
bool cinematicSlowMo = audNorthAudioEngine::IsInCinematicSlowMo();
Vector3 position = VEC3V_TO_VECTOR3(fireInfo->parentEntity->GetTransform().GetPosition());
s8 weaponSlotForCustomEchos = -1;
audSoundInitParams initParams;
if(sm_PlayerEquippedWeaponSlot.waveSlot && sm_PlayerEquippedWeaponSlot.waveSlot->waveSlot && sm_PlayerEquippedWeaponSlot.waveSlot->IsLoaded())
{
initParams.WaveSlot = sm_PlayerEquippedWeaponSlot.waveSlot->waveSlot;
}
BANK_ONLY(initParams.IsAuditioning = g_AuditionWeaponFire;);
initParams.AllowOrphaned = true;
if (fireInfo->parentEntity && fireInfo->parentEntity->GetIsTypePed() && ((CPed*)fireInfo->parentEntity.Get())->GetPedAudioEntity() )
{
initParams.Volume = ((CPed*)fireInfo->parentEntity.Get())->GetPedAudioEntity()->GetGunfightVolumeOffset();
}
if(fireInfo->parentEntity && fireInfo->parentEntity->GetIsTypePed() && ((CPed*)fireInfo->parentEntity.Get())->IsLocalPlayer() && !g_PlayerUsesNpcWeapons)
{
CPed* ped =(CPed*)fireInfo->parentEntity.Get();
if(ped->GetSelectedWeaponInfo())
weaponSlotForCustomEchos = (s8)ped->GetSelectedWeaponInfo()->GetWeaponWheelSlot();
f32 fVolume[4];
s32 sPredelay[4];
Vector3 vPos[4];
u32 bestIndex = 0;
u32 secondBestIndex = 1;
//const sdAudio::GlobalWeaponParams* pGlobalWeaponGameParams = rdrAudioManager::GetGlobalWeaponParams();
f32 scale = 1.f;
if (fDist>=0 && PARAM_rdrreportaudio.Get())
{
f32 fUnClampedScale = 1.0f - (fDist / g_MaxDistanceForEnemyReport /*pGlobalWeaponGameParams->MaxDistanceForEnemyReport*/);
//fUnClampedScale *= 1.0f - rdrAudioManager::GetAudioEnvironment()->GetAmountToOccludeOutsideWorldAfterPortals();
scale = Clamp(fUnClampedScale, 0.0f, 1.0f);
}
GetReportMetrics(fireInfo, weaponSettings, vPos, fVolume, sPredelay, &bestIndex, &secondBestIndex);
Vec3V firePos = fireInfo->parentEntity->GetTransform().GetPosition();
f32 gunfightVolumeOffset = initParams.Volume;
initParams.Volume += audDriverUtil::ComputeDbVolumeFromLinear(audDriverUtil::ComputeLinearVolumeFromDb(fVolume[bestIndex]) * scale * interiorVolumeScaling);
if(initParams.Volume > g_SilenceVolume)
{
Vector3 vFinalPos(vPos[bestIndex]+VEC3V_TO_VECTOR3(firePos));
if(PARAM_rdrreportaudio.Get())
{
vFinalPos.Add(VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetVolumeListenerPosition()));
}
initParams.Position = vFinalPos;
initParams.Predelay = sPredelay[bestIndex];
//if (AUD_GET_TRISTATE_VALUE(pWeaponParams->Flags, sdAudio::FLAG_ID_WEAPONPARAMS_INDIVIDUALMULTIONESHOTS)==AUD_TRISTATE_TRUE)
// PlayIndividualMultiOneshots(pWeaponParams->Player.Rapport, &initParams);
//else
u32 reportSound = weaponSettings->ReportSound;
if(audNorthAudioEngine::IsInSlowMoVideoEditor() || audNorthAudioEngine::IsSuperSlowVideoEditor())
{
if((cinematicSlowMo || markerSpeed <= REPLAY_SLOW_MO_MARKER_SPEED_THRESHOLD) && weaponSettings->SlowMoReportSound != g_NullSoundHash)
{
reportSound = weaponSettings->SlowMoReportSound;
}
if(markerSpeed <= REPLAY_SUPER_SLOW_MO_MARKER_SPEED_THRESHOLD && weaponSettings->SuperSlowMoReportSound != g_NullSoundHash)
{
reportSound = weaponSettings->SuperSlowMoReportSound;
}
}
g_WeaponAudioEntity.CreateAndPlaySound(reportSound, &initParams);
//second report
initParams.Volume = gunfightVolumeOffset + audDriverUtil::ComputeDbVolumeFromLinear(audDriverUtil::ComputeLinearVolumeFromDb(fVolume[secondBestIndex]) * scale * interiorVolumeScaling);
if(initParams.Volume > g_SilenceVolume)
{
//vPos[secondBestIndex].Scale(100.0f);
Vector3 vFinalPos(vPos[secondBestIndex]+VEC3V_TO_VECTOR3(firePos));
if(PARAM_rdrreportaudio.Get())
{
vFinalPos.Add(VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetVolumeListenerPosition()));
}
initParams.Position = vFinalPos;
initParams.Predelay = sPredelay[secondBestIndex];
//if (AUD_GET_TRISTATE_VALUE(pWeaponParams->Flags, sdAudio::FLAG_ID_WEAPONPARAMS_INDIVIDUALMULTIONESHOTS)==AUD_TRISTATE_TRUE)
// PlayIndividualMultiOneshots(pWeaponParams->Player.Rapport, &initParams);
//else
g_WeaponAudioEntity.CreateAndPlaySound(reportSound, &initParams);
}
}
}
else if(fireInfo->parentEntity)
{
if(sm_NpcReportIntensity > sm_IntensityForNpcReportFullCulling)
{
return;
}
initParams.Position = position;
initParams.EnvironmentGroup = fireInfo->parentEntity->GetAudioEnvironmentGroup();
initParams.UpdateEntity = true;
initParams.AllowOrphaned = true;
initParams.Volume += audDriverUtil::ComputeDbVolumeFromLinear(interiorVolumeScaling);
if(initParams.Volume <= g_SilenceVolume)
{
return;
}
if(sm_NpcReportIntensity > sm_IntensityForNpcReportDistanceCulling &&
MagSquared(VECTOR3_TO_VEC3V(position) - g_AudioEngine.GetEnvironment().GetPanningListenerPosition()).Getf() > sm_NpcReportCullingDistanceSq)
{
return;
}
u32 reportSound = weaponSettings->ReportSound;
if((cinematicSlowMo || markerSpeed <= REPLAY_SLOW_MO_MARKER_SPEED_THRESHOLD) && weaponSettings->SlowMoReportSound != g_NullSoundHash)
{
reportSound = weaponSettings->SlowMoReportSound;
}
if(markerSpeed <= REPLAY_SUPER_SLOW_MO_MARKER_SPEED_THRESHOLD && weaponSettings->SuperSlowMoReportSound != g_NullSoundHash)
{
reportSound = weaponSettings->SuperSlowMoReportSound;
}
g_WeaponAudioEntity.CreateAndPlaySound(reportSound, &initParams);
sm_NpcReportIntensity += 1.f;
}
u32 echoSound = fireInfo->GetWeaponEchoSound(weaponSettings);
if(!dontPlayEcho && echoSound && echoSound != g_NullSoundHash && fireInfo->parentEntity && !fireInfo->parentEntity->GetIsInInterior())
{
f32 initialAttenuation = 0.0f;
EnvironmentRule* envRule = g_AmbientAudioEntity.GetAmbientEnvironmentRule();
bool overrideEchos = envRule && AUD_GET_TRISTATE_VALUE(envRule->Flags, FLAG_ID_ENVIRONMENTRULE_OVERRIDEECHOS);
if(envRule && overrideEchos)
{
if(envRule->EchoSoundList != 0 && weaponSlotForCustomEchos != -1)
{
audSoundSet echoSet;
echoSet.Init(envRule->EchoSoundList);
if(echoSet.IsInitialised())
{
u32 customEchoSound = GetCustomEchoSoundForWeapon(echoSet, (eWeaponWheelSlot)weaponSlotForCustomEchos);
if(customEchoSound != 0 && customEchoSound != g_NullSoundHash)
echoSound = customEchoSound;
}
}
initialAttenuation = g_AmbientAudioEntity.GetAmbientEnvironmentRuleScale() * envRule->BaseEchoVolumeModifier;
}
PlayTwoEchos(echoSound, 0, position, initialAttenuation, 0, 0, overrideEchos ? envRule : NULL);
}
}
void audWeaponAudioEntity::SetReportGoodness(u8 index, f32 echoSuitability)
{
if(naVerifyf(index < sm_ReportGoodness.GetMaxCount(), "Inappropriate index value passed into SetReportGoodness"))
{
if(g_PositionReportOppositeEcho)
sm_ReportGoodness[index] = 1.0f - echoSuitability;
else
sm_ReportGoodness[index] = echoSuitability;
sm_ReportGoodness[index] = Clamp(sm_ReportGoodness[index], 0.0f, 1.0f);
}
}
void audWeaponAudioEntity::SetPlayerDoubleActionWeaponPhase(const CWeapon* weapon, f32 prevPhase, f32 currentPhase)
{
if(weapon)
{
u32 soundsetName = 0;
switch(weapon->GetWeaponInfo()->GetHash())
{
case 0x97EA20B8: // WEAPON_DOUBLEACTION
soundsetName = ATSTRINGHASH("PTL_DOUBLEACTION_REVOLVER_PLYR_RELOADS_MONO_SS", 0x3F4A7C77);
break;
case 0xCB96392F: // WEAPON_REVOLVER_MK2
soundsetName = ATSTRINGHASH("PTL_HEAVY_REVOLVER_MK2_PLYR_RELOADS_MONO_SS", 0x727A89DE);
break;
default:
break;
}
if(soundsetName != 0u)
{
const u32 timeMs = fwTimer::GetTimeInMilliseconds();
if(timeMs - m_LastDoubleActionWeaponSoundTime > 200)
{
u32 soundHash = 0;
if(prevPhase == 0.0f && currentPhase > 0.0f)
{
soundHash = ATSTRINGHASH("Hammer_Pull", 0xFABB388);
}
else if(prevPhase > 0.0f && currentPhase == 0.0f)
{
soundHash = ATSTRINGHASH("Hammer_Reset", 0x7AFE17AA);
}
if(soundHash != 0u)
{
audSoundSet soundSet;
if(soundSet.Init(soundsetName))
{
CreateDeferredSound(soundSet.Find(soundHash), weapon->GetEntity(), NULL, true, true);
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(soundSet.GetNameHash(), soundHash, NULL, NULL, weapon->GetEntity(), eWeaponSoundEntity));
m_LastDoubleActionWeaponSoundTime = timeMs;
}
}
}
}
}
}
void audWeaponAudioEntity::GetReportMetrics(const audWeaponFireInfo * fireInfo, const WeaponSettings * settings, Vector3* vPos, f32* fVolume, s32* sPredelay, u32* bestIndex, u32* secondBestIndex)
{
f32 fReportVolumeDelta = settings->ReportVolumeDelta; // -2.0f;
u32 sReportPredelayDelta = settings->ReportPredelayDelta; // 50;
naAssertf(bestIndex && secondBestIndex, "Failed to pass in valid pointers for best indicies.");
f32 fGoodness[4];
f32 fBestGoodness = 0.f;
u8 uBestIndex = 0;
for(u8 i=0; i<4; i++)
{
u8 uMaxIndex = (u8)sm_ReportGoodness.size();
u8 uIndex1=(i*2)%uMaxIndex;
u8 uIndex2=(uIndex1+1)%uMaxIndex;
u8 uIndex3=(uIndex1+2)%uMaxIndex;
vPos[i] = sm_RelativeScanPositions[uIndex2*3];
fGoodness[i] = sm_ReportGoodness[uIndex1] + sm_ReportGoodness[uIndex2] + sm_ReportGoodness[uIndex3];
fGoodness[i] /= 3.0f;
if(fGoodness[i] > fBestGoodness)
{
fBestGoodness = fGoodness[i];
uBestIndex = i;
}
}
Vector3 listenerPosition = VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetPanningListenerPosition());
Vector3 positionOnUnitCircle = VEC3V_TO_VECTOR3(fireInfo->parentEntity->GetTransform().GetPosition()) - listenerPosition;
positionOnUnitCircle.z = 0.0f;
positionOnUnitCircle.NormalizeSafe();
f32 elevation = VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetPanningListenerPosition()).GetZ();
//vPos[0].x = positionOnUnitCircle.x;
//vPos[0].y = positionOnUnitCircle.y;
//vPos[0].z = elevation;
//If we're the player, let's assume the direction is straight ahead.
CEntity * parentEntity = fireInfo->parentEntity;
if(parentEntity && parentEntity->GetIsTypePed() && ((CPed*)parentEntity)->IsLocalPlayer() && !g_PlayerUsesNpcWeapons)
{
vPos[0].Scale(100.0f);
vPos[0].z = elevation;
vPos[1].Scale(100.0f);
vPos[1].z = elevation;
vPos[2].Scale(100.0f);
vPos[2].z = elevation;
vPos[3].Scale(100.0f);
vPos[3].z = elevation;
}
else
{
f32 cosA = positionOnUnitCircle.y;
f32 sinA = -positionOnUnitCircle.x;
f32 cosB = 0; //B is 90...the amount we're going to increment through each step
f32 sinB = 1;
for(int i = 1; i < 4; i++)
{
f32 newCos = cosA*cosB - sinA*sinB;
f32 newSin = cosA*sinB + sinA*cosB;
vPos[i].x = -newSin;
vPos[i].y = newCos;
vPos[i].z = elevation;
cosA = newCos;
sinA = newSin;
}
}
if(bestIndex)
(*bestIndex) = uBestIndex;
u8 uIndex1=uBestIndex;
u8 uIndex2=(uBestIndex+1)%4;
u8 uIndex3=(uBestIndex+2)%4;
u8 uIndex4=(uBestIndex+3)%4;
if(secondBestIndex)
{
if(fGoodness[uIndex2] > fGoodness[uIndex3] && fGoodness[uIndex2] > fGoodness[uIndex4])
(*secondBestIndex) = uIndex2;
else if(fGoodness[uIndex3] > fGoodness[uIndex2] && fGoodness[uIndex3] > fGoodness[uIndex4])
(*secondBestIndex) = uIndex3;
else
(*secondBestIndex) = uIndex4;
}
fVolume[uIndex1] = 0.f; //audNorthAudioEngine::GetGtaEnvironment()->GetReportAttenuationCurve().CalculateValue(fBestGoodness);
sPredelay[uIndex1] = 0; // audNorthAudioEngine::GetGtaEnvironment()->GetReportPredelayCurve().CalculateValue(fBestGoodness);
if(secondBestIndex)
{
fVolume[(*secondBestIndex)] = fVolume[uIndex1] + fReportVolumeDelta;
sPredelay[(*secondBestIndex)] = sPredelay[uIndex1] + sReportPredelayDelta;
}
}
void audWeaponAudioEntity::AddToAutoFiringList(const audWeaponFireInfo * fireInfo, audSound ** autoFireSound, audSound ** interiorAutoSound, audSound ** pulseHeadsetSound)
{
s32 firstEmptySlot = -1;
for(s32 i=0; i < g_MaxWeaponFireEventsPerFrame; i++)
{
u32 autoRelease = s_AutoFireReleaseTime;
#if GTA_REPLAY
if(CReplayMgr::IsEditModeActive() && (audNorthAudioEngine::IsInSlowMoVideoEditor() || audNorthAudioEngine::IsSuperSlowVideoEditor()))
{
autoRelease = s_ReplayAutoFireReleaseTime;
}
#endif // GTA_REPLAY
if(!g_WeaponAudioEntity.sm_AutoWeaponsFiringList[i].m_AutoFireLoop && !g_WeaponAudioEntity.sm_AutoWeaponsFiringList[i].m_InteriorAutoLoop)
{
g_WeaponAudioEntity.sm_AutoWeaponsFiringList[i].m_AutoFireTimeOut = fwTimer::GetTimeInMilliseconds() + autoRelease;
firstEmptySlot = i;
}
if(g_WeaponAudioEntity.sm_AutoWeaponsFiringList[i].fireInfo.parentEntity == fireInfo->parentEntity)
{
sm_AutoWeaponsFiringList[i].fireInfo.lastPlayerHitTime = fireInfo->lastPlayerHitTime;
g_WeaponAudioEntity.sm_AutoWeaponsFiringList[i].m_AutoFireTimeOut = fwTimer::GetTimeInMilliseconds() + autoRelease;
return;
}
}
if(firstEmptySlot != -1)
{
g_WeaponAudioEntity.sm_AutoWeaponsFiringList[firstEmptySlot].m_AutoFireLoop = autoFireSound;
g_WeaponAudioEntity.sm_AutoWeaponsFiringList[firstEmptySlot].m_InteriorAutoLoop = interiorAutoSound;
g_WeaponAudioEntity.sm_AutoWeaponsFiringList[firstEmptySlot].m_PulseHeadsetSound = pulseHeadsetSound;
g_WeaponAudioEntity.sm_AutoWeaponsFiringList[firstEmptySlot].fireInfo.Init(*fireInfo);
}
}
void audWeaponAudioComponent::RemoveFromAutoFiringList()
{
for(s32 i=0; i < g_MaxWeaponFireEventsPerFrame; i++)
{
if(g_WeaponAudioEntity.sm_AutoWeaponsFiringList[i].m_AutoFireLoop == &m_AutoFireLoop)
{
if(m_AutoFireLoop)
{
m_AutoFireLoop->StopAndForget();
}
//naDisplayf("Removing from firing list %d", i);
g_WeaponAudioEntity.sm_AutoWeaponsFiringList[i].m_AutoFireLoop = NULL;
if(m_InteriorAutoLoop)
{
m_InteriorAutoLoop->StopAndForget();
}
if(m_PulseHeadsetSound)
{
m_PulseHeadsetSound->StopAndForget();
}
g_WeaponAudioEntity.sm_AutoWeaponsFiringList[i].m_InteriorAutoLoop = NULL;
g_WeaponAudioEntity.sm_AutoWeaponsFiringList[i].m_PulseHeadsetSound = NULL;
g_WeaponAudioEntity.sm_AutoWeaponsFiringList[i].fireInfo.parentEntity = NULL;
}
}
}
void audWeaponAudioEntity::ProcessCachedWeaponFireEvents(void)
{
UpdateThermalVision();
m_PlayerWeaponLoad.HandlePlayerWeaponLoad();
if(sm_WantsToLoadPlayerEquippedWeapon)
{
AddAllInventoryWeaponsOnPed(CGameWorld::FindLocalPlayer());
}
ProcessEquippedWeapon();
ProcessNextWeapon();
PF_SET(PlayerGunVolume, sm_PlayerGunDuckingAttenuation+6.0f);
u32 timeInMs = fwTimer::GetTimeInMilliseconds();
audWeaponFireEvent *nearestFireEvent;
u32 numNonPriorityFireEventsProcessed = 0;
do
{
f32 distanceToNearestFireEvent = 1000.0f;
nearestFireEvent = NULL;
s32 nearestFireEventIndex = -1;
bool isPriorityEvent = false;
//Find the nearest valid weapon fire event.
for(u8 eventIndex=0; eventIndex<sm_NumWeaponFireEventsThisFrame; eventIndex++)
{
CEntity *parentEntity = sm_WeaponFireEventList[eventIndex].fireInfo.parentEntity;
if(parentEntity)
{
bool isLocalPlayer = false;
bool isLocalPlayerVehicle = false;
bool isAlreadyAutofiring = false;
if(parentEntity->GetIsTypePed())
{
CPed* ped = (CPed*)parentEntity;
isLocalPlayer = ped->IsLocalPlayer() && !g_PlayerUsesNpcWeapons;
isLocalPlayerVehicle = ped->GetVehiclePedInside() == FindPlayerVehicle();
}
else if (parentEntity->GetIsTypeVehicle())
{
isLocalPlayerVehicle = parentEntity == FindPlayerVehicle();
}
isAlreadyAutofiring = (sm_WeaponFireEventList[eventIndex].weapon && sm_WeaponFireEventList[eventIndex].weapon->GetAudioComponent().m_AutoFireLoop != NULL);
if(isLocalPlayer || isLocalPlayerVehicle || isAlreadyAutofiring)
{
nearestFireEventIndex = eventIndex;
isPriorityEvent = true;
break;
}
else
{
if(numNonPriorityFireEventsProcessed < g_MaxWeaponFiresPlayedPerFrame)
{
Vector3 distanceVector = VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetVolumeListenerPosition() -
parentEntity->GetTransform().GetPosition());
f32 distance = distanceVector.Mag();
if(distance < distanceToNearestFireEvent || sm_WeaponFireEventList[eventIndex].fireInfo.isKillShot)
{
if((nearestFireEventIndex == -1) || (nearestFireEventIndex != -1 && !sm_WeaponFireEventList[nearestFireEventIndex].fireInfo.isKillShot) || (sm_WeaponFireEventList[eventIndex].fireInfo.isKillShot && distance < distanceToNearestFireEvent))
{
distanceToNearestFireEvent = distance;
nearestFireEventIndex = eventIndex;
}
}
}
}
}
}
if(nearestFireEventIndex >= 0)
{
nearestFireEvent = &(sm_WeaponFireEventList[nearestFireEventIndex]);
#if __BANK
if(sm_WeaponFireEventList[nearestFireEventIndex].fireInfo.isKillShot)
{
Displayf("We have a kill shot");
}
#endif
CEntity *parentEntity = nearestFireEvent->fireInfo.parentEntity;
CPed* pPlayer = CGameWorld::FindLocalPlayer();
bool enemy = false;
if (naVerifyf(pPlayer,"Can't find local player."))
{
if(parentEntity && parentEntity->GetIsTypePed() && (((CPed*)parentEntity)->GetPedIntelligence()) && (((CPed*)parentEntity)->GetPedIntelligence()->GetQueriableInterface()->GetHostileTarget() == pPlayer))
{
enemy = true;
}
}
// Update our nearby-gunfire factor, if the fire event has a fire sound
if (distanceToNearestFireEvent < g_MaxDistanceToCountTowardFactor && nearestFireEvent->fireInfo.GetWeaponFireSound(nearestFireEvent->fireInfo.FindWeaponSettings(false), pPlayer == nearestFireEvent->fireInfo.parentEntity) != g_NullSoundHash)
{
sm_LastTimeSomeoneNearbyFiredAGun = timeInMs;
if (enemy)
{
sm_LastTimeEnemyNearbyFiredAGun = timeInMs;
}
}
// Store a copy of the last fire event played for the conductors.
if(parentEntity && parentEntity->GetIsTypePed() &&(!((CPed*)parentEntity)->IsLocalPlayer() || g_PlayerUsesNpcWeapons))
{
sm_LastWeaponFireEventPlayed = sm_WeaponFireEventList[nearestFireEventIndex];
if (enemy)
{
sm_LastWeaponFireEventPlayedAgainstPlayer = sm_WeaponFireEventList[nearestFireEventIndex];
}
}
PlayWeaponFireEvent(nearestFireEvent);
#if USE_GUN_TAILS
CEntity *parentEntity = sm_WeaponFireEventList[nearestFireEvent].parentEntity;
if(parentEntity)
{
audNorthAudioEngine::GetGunFireAudioEntity()->AddGunFireEvent(VEC3V_TO_VECTOR3(parentEntity->GetTransform().GetPosition())
,sm_WeaponFireEventList[nearestFireEvent].weaponSettings->TailEnergyValue);
}
#endif
sm_WeaponFireEventList[nearestFireEventIndex].fireInfo.parentEntity = NULL;
if(!isPriorityEvent)
{
numNonPriorityFireEventsProcessed++;
}
}
} while (nearestFireEvent);
bool wasUsingPlayerDistanceCam = sm_UsingPlayerDistanceCam;
MicrophoneSettings * mic = audNorthAudioEngine::GetMicrophones().GetMicrophoneSettings();
if(mic)
{
sm_UsingPlayerDistanceCam = AUD_GET_TRISTATE_VALUE(mic->Flags, FLAG_ID_MICROPHONESETTINGS_DISTANTPLAYERWEAPONS) == AUD_TRISTATE_TRUE;
}
else if(audNorthAudioEngine::GetMicrophones().IsCinematicMicActive())
{
sm_UsingPlayerDistanceCam = true;
}
u32 autoRelease = s_AutoFireReleaseTime;
#if GTA_REPLAY
if(CReplayMgr::IsEditModeActive() && (audNorthAudioEngine::IsInSlowMoVideoEditor() || audNorthAudioEngine::IsSuperSlowVideoEditor()))
{
autoRelease = s_ReplayAutoFireReleaseTime;
}
#endif // GTA_REPLAY
for(s32 i=0; i< g_MaxWeaponFireEventsPerFrame; i++)
{
if(sm_AutoWeaponsFiringList[i].m_AutoFireLoop && sm_AutoWeaponsFiringList[i].fireInfo.parentEntity
&& sm_AutoWeaponsFiringList[i].fireInfo.parentEntity->GetIsTypePed() && *sm_AutoWeaponsFiringList[i].m_AutoFireLoop)
{
CPed * ped = (CPed *)sm_AutoWeaponsFiringList[i].fireInfo.parentEntity.Get();
if(!ped->IsLocalPlayer())
{
const u32 now = g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0);
sm_AutoWeaponsFiringList[i].fireInfo.hitPlayerSmoother.Init(sm_PlayerhitBoostSmoothTime);
f32 applyFactor;
if(sm_AutoWeaponsFiringList[i].fireInfo.lastPlayerHitTime + sm_PlayerHitBoostHoldTime > now )
{
applyFactor = sm_AutoWeaponsFiringList[i].fireInfo.hitPlayerSmoother.CalculateValue(1.f, fwTimer::GetTimeStep());
}
else
{
applyFactor = sm_AutoWeaponsFiringList[i].fireInfo.hitPlayerSmoother.CalculateValue(0.f, fwTimer::GetTimeStep());
}
(*sm_AutoWeaponsFiringList[i].m_AutoFireLoop)->SetRequestedPostSubmixVolumeAttenuation(sm_PlayerHitBoostVol*applyFactor);
(*sm_AutoWeaponsFiringList[i].m_AutoFireLoop)->SetRequestedVolumeCurveScale(1.f+ ((sm_PlayerHitBoostRolloff-1.f)*applyFactor));
if(sm_AutoWeaponsFiringList[i].m_InteriorAutoLoop && *sm_AutoWeaponsFiringList[i].m_InteriorAutoLoop)
{
(*sm_AutoWeaponsFiringList[i].m_InteriorAutoLoop)->SetRequestedPostSubmixVolumeAttenuation(sm_PlayerHitBoostVol*applyFactor);
(*sm_AutoWeaponsFiringList[i].m_InteriorAutoLoop)->SetRequestedVolumeCurveScale(1.f+ ((sm_PlayerHitBoostRolloff-1.f)*applyFactor));
}
}
CWeapon * weapon = ped->GetWeaponManager()->GetEquippedWeapon();
if(weapon && weapon->GetAudioComponent().GetAnimIsAutoFiring())
{
if(ped->IsUsingFiringVariation())
{
sm_AutoWeaponsFiringList[i].m_AutoFireTimeOut = timeInMs + autoRelease;
continue;
}
else
{
weapon->GetAudioComponent().SetAnimIsAutoFiring(false);
}
}
//Let's have at least a frame to play the shots
if(((sm_AutoWeaponsFiringList[i].m_AutoFireTimeOut - autoRelease + 33) > (fwTimer::GetTimeInMilliseconds())))
{
continue;
}
if(ped &&
((!ped->IsFiring()
REPLAY_ONLY(&& (!CReplayMgr::IsPlaying() || !(ped->GetPedAudioEntity() && ped->GetPedAudioEntity()->GetWasFiringforReplay()) || ped->GetPedAudioEntity()->GetTriggerAutoWeaponStopForReplay()))) ||
(ped->IsLocalPlayer() && (wasUsingPlayerDistanceCam != sm_UsingPlayerDistanceCam))))
{
StopAutomaticFire(sm_AutoWeaponsFiringList[i].fireInfo, sm_AutoWeaponsFiringList[i].m_AutoFireLoop, sm_AutoWeaponsFiringList[i].m_InteriorAutoLoop, sm_AutoWeaponsFiringList[i].m_PulseHeadsetSound);
sm_AutoWeaponsFiringList[i].m_AutoFireLoop = NULL;
sm_AutoWeaponsFiringList[i].m_InteriorAutoLoop = NULL;
sm_AutoWeaponsFiringList[i].m_PulseHeadsetSound = NULL;
ped->GetPedAudioEntity()->SetTriggerAutoWeaponStopForReplay(false);
}
}
u32 timeOut = sm_AutoWeaponsFiringList[i].m_AutoFireTimeOut;
#if GTA_REPLAY
bool isMinigun = sm_WeaponFireEventList[i].fireInfo.settingsHash == ATSTRINGHASH("AUDIO_ITEM_MINIGUN", 0x674A2973);
bool isVehicleFlamethrower = sm_AutoWeaponsFiringList[i].fireInfo.settingsHash == ATSTRINGHASH("AUDIO_ITEM_VEHICLE_WEAPON_MINI_FLAMETHROWER", 0xC444739B) || sm_AutoWeaponsFiringList[i].fireInfo.settingsHash == ATSTRINGHASH("AUDIO_ITEM_VEHICLE_WEAPON_FLAMETHROWER_SCIFI", 0xD6B8E406) || sm_AutoWeaponsFiringList[i].fireInfo.settingsHash == ATSTRINGHASH("AUDIO_ITEM_VEHICLE_WEAPON_FLAMETHROWER", 0x58917377);
if((audNorthAudioEngine::IsInSlowMoVideoEditor() || audNorthAudioEngine::IsSuperSlowVideoEditor()) && CReplayMgr::IsPlaying())
{
timeOut -= autoRelease;
timeOut += (u32)(autoRelease*CReplayMgr::GetMarkerSpeed());
}
#endif
//We want to stop automatic/interior auto sounds if they go over the timeout
//But not while playing replay when a ped is firing, or we're in slow mo and not a minigun
if((sm_AutoWeaponsFiringList[i].m_AutoFireLoop || sm_AutoWeaponsFiringList[i].m_InteriorAutoLoop) &&
(timeOut < timeInMs)
REPLAY_ONLY( && (!CReplayMgr::IsPlaying() ||
(!isMinigun && !isVehicleFlamethrower && (audNorthAudioEngine::IsInSlowMoVideoEditor() || audNorthAudioEngine::IsSuperSlowVideoEditor())) ||
(sm_AutoWeaponsFiringList[i].fireInfo.parentEntity && !sm_AutoWeaponsFiringList[i].fireInfo.parentEntity->GetIsTypePed()))))
{
#if RSG_BANK & GTA_REPLAY
if(CReplayMgr::IsPlaying())
{
naDisplayf("Replay: StopAutomaticFire due to timeout on %s at time %u", audNorthAudioEngine::GetMetadataManager().GetObjectName(sm_AutoWeaponsFiringList[i].fireInfo.audioSettingsRef), fwTimer::GetTimeInMilliseconds());
}
#endif
StopAutomaticFire(sm_AutoWeaponsFiringList[i].fireInfo, sm_AutoWeaponsFiringList[i].m_AutoFireLoop, sm_AutoWeaponsFiringList[i].m_InteriorAutoLoop, sm_AutoWeaponsFiringList[i].m_PulseHeadsetSound);
sm_AutoWeaponsFiringList[i].m_AutoFireLoop = NULL;
sm_AutoWeaponsFiringList[i].m_InteriorAutoLoop = NULL;
sm_AutoWeaponsFiringList[i].m_PulseHeadsetSound = NULL;
}
}
//Remove the old registered references.
for(u8 eventIndex=0; eventIndex<sm_NumWeaponFireEventsThisFrame; eventIndex++)
{
sm_WeaponFireEventList[eventIndex].fireInfo.parentEntity = NULL;
}
sm_NumWeaponFireEventsThisFrame = 0;
// Update the nearby gunfire factor
if (sm_LastTimeSomeoneNearbyFiredAGun == timeInMs)
{
// We just fired at least one gun within range
sm_GunfireFactor = Min(sm_GunfireFactor+g_GunFiredFactorIncrease, 1.0f);
}
else if ((sm_LastTimeSomeoneNearbyFiredAGun+g_TimeSinceSomeoneNearbyFiredToReduceFactor) < timeInMs)
{
// We didn't fire a gun within range in the last wee while
sm_GunfireFactor = Max(sm_GunfireFactor+g_GunNotFiredFactorDecrease, 0.0f);
}
PF_SET(GunfireFactor, sm_GunfireFactor);
}
void audWeaponAudioEntity::PlayWeaponFireEvent(audWeaponFireEvent *fireEvent)
{
const WeaponSettings * weaponSettings = fireEvent->fireInfo.FindWeaponSettings();
naAssert(weaponSettings);
if(!weaponSettings)
{
return;
}
#if __BANK
if(g_DebugWeaponTimings && fireEvent->fireInfo.parentEntity)
{
grcDebugDraw::Sphere(fireEvent->fireInfo.parentEntity->GetTransform().GetPosition(), 0.5f, Color32(0,255,0), true, 5);
}
#endif
bool isPlayerGun = false;
if (fireEvent->fireInfo.parentEntity && fireEvent->fireInfo.parentEntity->GetIsTypePed() && (static_cast<CPed*>(fireEvent->fireInfo.parentEntity.Get()))->IsLocalPlayer() && !g_PlayerUsesNpcWeapons)
{
isPlayerGun = true;
}
if(audNorthAudioEngine::GetMicrophones().IsCinematicMicActive())
{
isPlayerGun = false;
}
if(fireEvent->weapon)
{
fireEvent->fireInfo.lastPlayerHitTime = fireEvent->weapon->GetAudioComponent().GetLastPlayerHitTime();
}
else
{
return;
}
bool isVehicleFlamethrower = false;
eWeaponEffectGroup effectGroup = EWEAPONEFFECTGROUP_MAX; // Defaulted to an effectGroup value that we don't care.
if(fireEvent->weapon->GetWeaponInfo())
{
effectGroup = fireEvent->weapon->GetWeaponInfo()->GetEffectGroup();
if (fireEvent->weapon->GetWeaponInfo()->GetAudioHash() == ATSTRINGHASH("AUDIO_ITEM_VEHICLE_WEAPON_FLAMETHROWER_SCIFI", 0xD6B8E406) ||
fireEvent->weapon->GetWeaponInfo()->GetAudioHash() == ATSTRINGHASH("AUDIO_ITEM_VEHICLE_WEAPON_FLAMETHROWER", 0x58917377) ||
fireEvent->weapon->GetWeaponInfo()->GetAudioHash() == ATSTRINGHASH("AUDIO_ITEM_VEHICLE_WEAPON_MINI_FLAMETHROWER", 0xC444739B))
{
isVehicleFlamethrower = true;
}
}
// See url:bugstar:5518617. We should probably do this for all vehicle mounted weapons but being cautious. During replay, the fireEvent explicit position
// is already populated by the replay packet, so we don't want to overwrite it
#if GTA_REPLAY
if(!CReplayMgr::IsEditModeActive())
#endif
{
if (isVehicleFlamethrower && fireEvent && fireEvent->weapon && fireEvent->weapon->GetMuzzleBoneIndex() >= 0)
{
fireEvent->fireInfo.explicitPosition = fireEvent->weapon->GetMuzzleEntity()->TransformIntoWorldSpace(fireEvent->weapon->GetMuzzleEntity()->GetObjectMtx(fireEvent->weapon->GetMuzzleBoneIndex()).d);
}
else
{
fireEvent->fireInfo.explicitPosition.Zero();
}
}
// Special ability and slow-mo video editor forces all auto-fire weapons into single shot
bool replayForceSingleShot = false;
#if GTA_REPLAY
if(audNorthAudioEngine::IsInSlowMoVideoEditor() || audNorthAudioEngine::IsSuperSlowVideoEditor())
{
if(CReplayMgr::GetMarkerSpeed() <= REPLAY_SLOW_MO_MARKER_SPEED_THRESHOLD BANK_ONLY( || audNorthAudioEngine::IsForcingSlowMoVideoEditor() || audNorthAudioEngine::IsForcingSuperSlowMoVideoEditor()))
{
if (!isVehicleFlamethrower)
{
replayForceSingleShot = true;
}
}
}
#endif
bool forceSingleShot = (fireEvent->fireInfo.forceSingleShot && !fireEvent->fireInfo.isSuppressed) ||
replayForceSingleShot || audNorthAudioEngine::IsInCinematicSlowMo() ||
(g_FrontendAudioEntity.GetSpecialAbilityMode() != audFrontendAudioEntity::kSpecialAbilityModeNone && isPlayerGun && weaponSettings->AutoSound != ATSTRINGHASH("SPL_MINIGUN2_PLAYER_MASTER", 0x91ED0FA));
if(!forceSingleShot && ((AUD_GET_TRISTATE_VALUE(weaponSettings->Flags, FLAG_ID_WEAPONSETTINGS_ISPLAYERAUTOFIRE)== AUD_TRISTATE_TRUE) ||
(AUD_GET_TRISTATE_VALUE(weaponSettings->Flags, FLAG_ID_WEAPONSETTINGS_ISNPCAUTOFIRE)== AUD_TRISTATE_TRUE)))
{
audWeaponAudioComponent & weaponAudio = fireEvent->weapon->GetAudioComponent();
if(weaponAudio.m_AutoFireLoop && isPlayerGun &&
g_FrontendAudioEntity.GetSpecialAbilityMode() != weaponAudio.m_SpecialAbilityMode
&& (g_FrontendAudioEntity.GetSpecialAbilityMode() == audFrontendAudioEntity::kSpecialAbilityModeTrevor ||
weaponAudio.m_SpecialAbilityMode == audFrontendAudioEntity::kSpecialAbilityModeTrevor))
{
weaponAudio.m_AutoFireLoop->StopAndForget();
}
weaponAudio.m_SpecialAbilityMode = g_FrontendAudioEntity.GetSpecialAbilityMode();
StartAutomaticFire(fireEvent->fireInfo, &weaponAudio.m_AutoFireLoop, &weaponAudio.m_InteriorAutoLoop,effectGroup, &weaponAudio.m_PulseHeadsetSound);
}
else
{
HandleFire(fireEvent->fireInfo,effectGroup);
}
#if GTA_REPLAY
if(CReplayMgr::ShouldRecord())
{
if(isPlayerGun && fireEvent->fireInfo.parentEntity && fireEvent->fireInfo.parentEntity->GetIsTypePed())
{
CPed* pPed = static_cast<CPed*>(fireEvent->fireInfo.parentEntity.Get());
if(pPed)
{
CPedWeaponManager* weaponManager = pPed->GetWeaponManager();
if(weaponManager)
{
CWeapon* equippedWeapon = weaponManager->GetEquippedWeapon();
if(equippedWeapon)
{
fireEvent->fireInfo.ammo = equippedWeapon->GetAmmoInClip();
}
}
}
}
f32 fGunFightVolumeOffset = 0.0f;
if (fireEvent->fireInfo.parentEntity && fireEvent->fireInfo.parentEntity->GetIsTypePed() && ((CPed*)fireEvent->fireInfo.parentEntity.Get())->GetPedAudioEntity() )
{
fGunFightVolumeOffset = ((CPed*)fireEvent->fireInfo.parentEntity.Get())->GetPedAudioEntity()->GetGunfightVolumeOffset();
}
// In order to get the CWeapon on replay playback for vehicle weapons we need to know which seat the weapon is used from
// We don't have the ped in all cases, loop through the vehicle weapons to find the seat idx.
int seatIdx = -1;
if (fireEvent->fireInfo.parentEntity && fireEvent->fireInfo.parentEntity->GetIsTypeVehicle())
{
CVehicle* pVehicle = static_cast<CVehicle*>(fireEvent->fireInfo.parentEntity.Get());
CVehicleWeaponMgr* pWeaponMgr = pVehicle->GetVehicleWeaponMgr();
if(pWeaponMgr)
{
int weaponIdx = -1;
for(int i = 0; i < pWeaponMgr->GetNumVehicleWeapons() && weaponIdx == -1; ++i)
{
CVehicleWeapon* pWeapon = pWeaponMgr->GetVehicleWeapon(i);
if(!pWeapon)
break;
switch(pWeapon->GetType())
{
case VGT_VEHICLE_WEAPON_BATTERY:
{
CVehicleWeaponBattery* pWeaponBattery = static_cast<CVehicleWeaponBattery*>(pWeapon);
for(int j = 0; j < pWeaponBattery->GetNumWeaponsInBattery(); ++j)
{
CVehicleWeapon* pWeaponFromBattery = pWeaponBattery->GetVehicleWeapon(j);
if( pWeaponFromBattery && pWeaponFromBattery->GetType() == VGT_FIXED_VEHICLE_WEAPON &&
static_cast<CFixedVehicleWeapon*>(pWeaponFromBattery)->GetWeapon() == fireEvent->weapon)
{
weaponIdx = i;
break;
}
}
break;
}
case VGT_FIXED_VEHICLE_WEAPON:
{
if(static_cast<CFixedVehicleWeapon*>(pWeapon)->GetWeapon() == fireEvent->weapon)
{
weaponIdx = i;
}
break;
}
default:
break;
}
}
if(weaponIdx != -1)
seatIdx = pWeaponMgr->GetSeatIndexFromWeaponIdx(weaponIdx);
}
}
CReplayMgr::RecordFx<CPacketWeaponSoundFireEvent>(
CPacketWeaponSoundFireEvent(fireEvent->fireInfo, fGunFightVolumeOffset, fireEvent->weapon->GetWeaponHash(), seatIdx), fireEvent->fireInfo.parentEntity, fireEvent->weapon->GetEntity());
}
#endif // GTA_REPLAY
}
void audWeaponAudioEntity::StartAutomaticFire(audWeaponFireInfo &fireInfo, audSound ** autoFireSound, audSound ** interiorAutoSound,const eWeaponEffectGroup effectGroup, audSound ** pulseHeadsetSound)
{
audEnvironmentGroupInterface* occlusionGroup = NULL;
Vector3 sourcePosition;
sourcePosition.Zero();
audTracker *tracker = fireInfo.parentEntity->GetPlaceableTracker();
audWeaponInteriorMetrics interior;
g_WeaponAudioEntity.GetInteriorMetrics(interior, fireInfo.parentEntity);
const WeaponSettings * settings = fireInfo.FindWeaponSettings();
if(!naVerifyf(settings, "Couldn't find weapon settings from fireinfo with ItemSettings %s",
audNorthAudioEngine::GetMetadataManager().GetObjectName(fireInfo.audioSettingsRef)))
{
return;
}
if (fireInfo.parentEntity && fireInfo.parentEntity->GetIsTypePed())
{
CPed* parentPed = static_cast<CPed*>(fireInfo.parentEntity.Get());
occlusionGroup = parentPed->GetWeaponEnvironmentGroup(true);
if (occlusionGroup)
{
audPedAudioEntity* pedAudioEntity = parentPed->GetPedAudioEntity();
if (pedAudioEntity)
{
pedAudioEntity->ResetEnvironmentGroupLifeTime();
}
}
}
else if (fireInfo.parentEntity && fireInfo.parentEntity->GetIsTypeVehicle())
{
occlusionGroup = ((CVehicle*)(fireInfo.parentEntity).Get())->GetAudioEnvironmentGroup();
}
if (fireInfo.explicitPosition.IsNonZero())
{
sourcePosition = fireInfo.explicitPosition;
tracker = NULL;
}
else if (tracker)
{
sourcePosition = tracker->GetPosition();
}
f32 interiorWetness = interior.Wetness;
if(fireInfo.isSuppressed)
{
interiorWetness*= sm_InteriorSilencedWeaponWetness;
}
f32 interiorDryScaling = sm_InteriorDryShotVolumeCurve.CalculateValue(interiorWetness);
f32 interiorWetScaling = sm_InteriorWetShotVolumeCurve.CalculateValue(interiorWetness);
#if __BANK
if(g_DebugWeaponTimings && fireInfo.parentEntity)
{
grcDebugDraw::Sphere(fireInfo.parentEntity->GetTransform().GetPosition(), 0.5f, Color32(0,255,0), true, 5);
}
#endif
f32 postSubmixAttenuation = g_DefaultGunPostSubmixAttenuation;
bool isPlayerGun = false;
if (fireInfo.parentEntity && fireInfo.parentEntity->GetIsTypePed() && (static_cast<CPed*>(fireInfo.parentEntity.Get()))->IsLocalPlayer() && !g_PlayerUsesNpcWeapons)
{
isPlayerGun = true;
postSubmixAttenuation = PlayerGunFired();
}
// only do loud sound stuff for weapons with fire sounds
if(!fireInfo.isSuppressed )
{
audNorthAudioEngine::RegisterLoudSound(sourcePosition,isPlayerGun);
audNorthAudioEngine::GetGtaEnvironment()->SpikeResonanceObjects(GetWeaponResonanceImpulse( effectGroup), sourcePosition, naEnvironment::sm_WeaponsResonanceDistance);
}
const WeaponSettings* weaponSettings = fireInfo.FindWeaponSettings();
u32 autoRelease = s_AutoFireReleaseTime;
#if GTA_REPLAY
if(CReplayMgr::IsEditModeActive() && (audNorthAudioEngine::IsInSlowMoVideoEditor() || audNorthAudioEngine::IsSuperSlowVideoEditor()))
{
autoRelease = s_ReplayAutoFireReleaseTime;
}
#endif // GTA_REPLAY
u32 fireSound = fireInfo.isSuppressed ? weaponSettings->SuppressedFireSound : weaponSettings->AutoSound;
// B*4191672 - If the weapon swaps from player->NPC while still firing, update the panning so that we at least ensure
// that it fades off at distance correctly instead of being stuck frontend forever. The other option is to just stop
// and start the whole sound in this situation, but this approach sounds much less jarring.
if(CNetwork::IsGameInProgress() && !CReplayMgr::IsEditModeActive())
{
if(*autoFireSound && fireSound != fireInfo.autoFireSound)
{
const Sound* soundMetadataCompressed = g_AudioEngine.GetSoundManager().GetFactory().GetMetadataPtr(fireSound);
if(soundMetadataCompressed)
{
Sound uncompressedMetadata;
audSound::DecompressMetadata_Untyped(soundMetadataCompressed, uncompressedMetadata);
(*autoFireSound)->SetRequestedPan(uncompressedMetadata.Pan);
(*autoFireSound)->SetRequestedShouldAttenuateOverDistance(AUD_GET_TRISTATE_VALUE(uncompressedMetadata.Flags, FLAG_ID_SOUND_DISTANCEATTENUATION));
}
fireSound = fireInfo.autoFireSound;
}
}
for(s32 i=0; i < g_MaxWeaponFireEventsPerFrame; i++)
{
if(g_WeaponAudioEntity.sm_AutoWeaponsFiringList[i].m_AutoFireLoop &&
*g_WeaponAudioEntity.sm_AutoWeaponsFiringList[i].m_AutoFireLoop &&
g_WeaponAudioEntity.sm_AutoWeaponsFiringList[i].fireInfo.parentEntity == fireInfo.parentEntity)
{
g_WeaponAudioEntity.sm_AutoWeaponsFiringList[i].m_AutoFireTimeOut = fwTimer::GetTimeInMilliseconds() + autoRelease;
if (fireInfo.explicitPosition.IsNonZero())
{
if (*autoFireSound)
{
(*autoFireSound)->SetRequestedPosition(fireInfo.explicitPosition);
}
if (*interiorAutoSound)
{
(*interiorAutoSound)->SetRequestedPosition(fireInfo.explicitPosition);
}
}
return;
}
}
f32 markerSpeed = 1.0f;
#if GTA_REPLAY
if(audNorthAudioEngine::IsInSlowMoVideoEditor() || audNorthAudioEngine::IsSuperSlowVideoEditor())
{
markerSpeed = CReplayMgr::GetMarkerSpeed();
#if __BANK
if(audNorthAudioEngine::IsForcingSlowMoVideoEditor())
markerSpeed = 0.2f;
if(audNorthAudioEngine::IsForcingSuperSlowMoVideoEditor())
markerSpeed = 0.05f;
#endif
}
#endif
bool cienmaticSlowMo = audNorthAudioEngine::IsInCinematicSlowMo();
if(*autoFireSound == NULL)
{
audSoundInitParams initParams;
BANK_ONLY(initParams.IsAuditioning = g_AuditionWeaponFire;);
initParams.Tracker = tracker;
initParams.Position = sourcePosition;
initParams.EnvironmentGroup = occlusionGroup;
initParams.UpdateEntity = true;
if(sm_PlayerEquippedWeaponSlot.waveSlot && sm_PlayerEquippedWeaponSlot.waveSlot->waveSlot && sm_PlayerEquippedWeaponSlot.waveSlot->IsLoaded())
{
initParams.WaveSlot = sm_PlayerEquippedWeaponSlot.waveSlot->waveSlot;
}
initParams.Volume = audDriverUtil::ComputeDbVolumeFromLinear(interiorDryScaling);
if (fireInfo.parentEntity && fireInfo.parentEntity->GetIsTypePed() && ((CPed*)fireInfo.parentEntity.Get())->GetPedAudioEntity() )
{
initParams.Volume += ((CPed*)fireInfo.parentEntity.Get())->GetPedAudioEntity()->GetGunfightVolumeOffset();
}
if(g_FrontendAudioEntity.GetSpecialAbilityMode() == audFrontendAudioEntity::kSpecialAbilityModeTrevor && fireSound == ATSTRINGHASH("SPL_MINIGUN2_PLAYER_MASTER", 0x91ED0FA))
{
fireSound = ATSTRINGHASH("TREVOR_MINI_GUN_FIRE_MASTER", 0x2AE131D9);
}
g_WeaponAudioEntity.CreateAndPlaySound_Persistent(fireSound, autoFireSound, &initParams);
fireInfo.autoFireSound = fireSound;
if(isPlayerGun && g_FrontendAudioEntity.GetSpecialAbilityMode() == audFrontendAudioEntity::kSpecialAbilityModeNone && audNorthAudioEngine::ShouldTriggerPulseHeadset() && !*pulseHeadsetSound)
{
if(fireSound == ATSTRINGHASH("SPL_MINIGUN2_PLAYER_MASTER", 0x91ED0FA))
{
CreateAndPlaySound_Persistent(g_FrontendAudioEntity.GetPulseHeadsetSounds().Find(ATSTRINGHASH("Minigun_FireLoop", 0xAB401B5B)), pulseHeadsetSound);
}
else if(fireSound == ATSTRINGHASH("LMG_MG_PLAYER_MASTER", 0x696F4A85))
{
CreateAndPlaySound_Persistent(g_FrontendAudioEntity.GetPulseHeadsetSounds().Find(ATSTRINGHASH("MG_FireLoop", 0xFFE700AE)), pulseHeadsetSound);
}
else if(fireSound == ATSTRINGHASH("LMG_COMBAT2_PLAYER_MASTER", 0x1EA5E048))
{
CreateAndPlaySound_Persistent(g_FrontendAudioEntity.GetPulseHeadsetSounds().Find(ATSTRINGHASH("CombatMG_FireLoop", 0xB002D84E)), pulseHeadsetSound);
}
else if(fireSound == ATSTRINGHASH("LMG_ASSAULT_PLAYER_MASTER", 0x289FE16F))
{
CreateAndPlaySound_Persistent(g_FrontendAudioEntity.GetPulseHeadsetSounds().Find(ATSTRINGHASH("AssaultMG_FireLoop", 0x200945E5)), pulseHeadsetSound);
}
}
#if __BANK
if(g_DebugWeaponTimings)
{
naErrorf("Auto sound %s, time %u", g_AudioEngine.GetSoundManager().GetFactory().GetMetadataManager().GetObjectName(fireSound), fwTimer::GetTimeInMilliseconds());
}
#endif
if(*autoFireSound)
{
//naDisplayf("Setting auto fadeout time to %d, line %d fireevent %p", fireEvent->weaponAudio->m_AutoFireTimeOut, __LINE__, fireEvent);
if(fireInfo.parentEntity && fireInfo.parentEntity->GetIsTypePed())
(static_cast<CPed*>(fireInfo.parentEntity.Get()))->SetLastTimeStartedAutoFireSound(g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0));
AddToAutoFiringList(&fireInfo, autoFireSound, interiorAutoSound, pulseHeadsetSound);
if(interiorWetScaling > 0.f && interiorAutoSound)
{
//Keep the same init params but
audSoundInitParams interiorParams = initParams;
interiorParams.Volume = audDriverUtil::ComputeDbVolumeFromLinear(interiorWetScaling);
if(*interiorAutoSound)
{
(*interiorAutoSound)->StopAndForget();
}
u32 interiorShotSound = weaponSettings->InteriorShotSound;
if((cienmaticSlowMo || markerSpeed <= REPLAY_SLOW_MO_MARKER_SPEED_THRESHOLD) && settings->SlowMoInteriorShotSound != g_NullSoundHash)
{
interiorShotSound = settings->SlowMoInteriorShotSound;
}
if(markerSpeed <= REPLAY_SUPER_SLOW_MO_MARKER_SPEED_THRESHOLD && settings->SuperSlowMoInteriorShotSound != g_NullSoundHash)
{
interiorShotSound = settings->SuperSlowMoInteriorShotSound;
}
g_WeaponAudioEntity.CreateAndPlaySound_Persistent(interiorShotSound, interiorAutoSound, &interiorParams);
if(*interiorAutoSound)
{
(*interiorAutoSound)->FindAndSetVariableValue(ATSTRINGHASH("interior_hold", 0x5BB4EAD3), interior.Hold);
(*interiorAutoSound)->SetRequestedLPFCutoff(interior.Lpf);
(*interiorAutoSound)->FindAndSetVariableValue(ATSTRINGHASH("PreDelay", 1610825783), (f32)interior.Predelay);
}
}
}
}
}
f32 audWeaponAudioEntity::GetWeaponResonanceImpulse(eWeaponEffectGroup effectGroup)
{
if(effectGroup >= WEAPON_EFFECT_GROUP_PUNCH_KICK && effectGroup <=WEAPON_EFFECT_GROUP_MELEE_GENERIC )
{
return naEnvironment::sm_MeleeResoImpulse;
}
else if (effectGroup >= WEAPON_EFFECT_GROUP_PISTOL_SMALL && effectGroup <= WEAPON_EFFECT_GROUP_PISTOL_LARGE)
{
return naEnvironment::sm_PistolResoImpulse;
}
else if (effectGroup >= WEAPON_EFFECT_GROUP_SMG && effectGroup <= WEAPON_EFFECT_GROUP_ROCKET)
{
return naEnvironment::sm_RifleResoImpulse;
}
return 0.f;
}
void audWeaponAudioEntity::StopAutomaticFire(audWeaponFireInfo & fireInfo, audSound ** autoFireLoop, audSound ** interiorAutoLoop, audSound ** pulseHeadsetSound)
{
if(autoFireLoop && *autoFireLoop)
{
(*autoFireLoop)->StopAndForget();
}
audWeaponInteriorMetrics interior;
if(fireInfo.parentEntity)
{
const WeaponSettings *weaponSettings = fireInfo.FindWeaponSettings(false);
GetInteriorMetrics(interior, fireInfo.parentEntity);
PlayWeaponReport(&fireInfo, &interior, weaponSettings, 0.f, true);
u32 timeAutoSoundPlayed = 0;
s8 weaponSlotForCustomEchos = -1;
if(fireInfo.parentEntity->GetIsTypePed())
{
timeAutoSoundPlayed = g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0) - (static_cast<CPed*>(fireInfo.parentEntity.Get()))->GetLastTimeStartedAutoFireSound();
CPed* ped =(CPed*)fireInfo.parentEntity.Get();
if(ped->IsLocalPlayer() && ped->GetSelectedWeaponInfo())
{
weaponSlotForCustomEchos = (s8)ped->GetSelectedWeaponInfo()->GetWeaponWheelSlot();
}
}
u32 echoSound = fireInfo.GetWeaponEchoSound(weaponSettings);
if(echoSound && echoSound != g_NullSoundHash && !fireInfo.parentEntity->GetIsInInterior())
{
f32 initialAttenuation = 0.0f;
EnvironmentRule* envRule = g_AmbientAudioEntity.GetAmbientEnvironmentRule();
bool overrideEchos = envRule && AUD_GET_TRISTATE_VALUE(envRule->Flags, FLAG_ID_ENVIRONMENTRULE_OVERRIDEECHOS);
if(envRule && overrideEchos)
{
if(envRule->EchoSoundList != 0 && weaponSlotForCustomEchos != -1)
{
audSoundSet echoSet;
echoSet.Init(envRule->EchoSoundList);
if(echoSet.IsInitialised())
{
u32 customEchoSound = GetCustomEchoSoundForWeapon(echoSet, (eWeaponWheelSlot)weaponSlotForCustomEchos);
if(customEchoSound != 0 && customEchoSound != g_NullSoundHash)
echoSound = customEchoSound;
}
}
initialAttenuation = g_AmbientAudioEntity.GetAmbientEnvironmentRuleScale() * envRule->BaseEchoVolumeModifier;
}
Vector3 position = VEC3V_TO_VECTOR3(fireInfo.parentEntity->GetTransform().GetPosition());
PlayTwoEchos(echoSound, 0, position, initialAttenuation, 0, timeAutoSoundPlayed, overrideEchos ? envRule : NULL);
}
}
if(interiorAutoLoop && *interiorAutoLoop)
{
(*interiorAutoLoop)->StopAndForget();
}
if(pulseHeadsetSound && *pulseHeadsetSound)
{
(*pulseHeadsetSound)->StopAndForget();
}
#if GTA_REPLAY
if(CReplayMgr::ShouldRecord())
{
CReplayMgr::RecordFx<CPacketWeaponAutoFireStop>(CPacketWeaponAutoFireStop(true), fireInfo.parentEntity);
}
#endif
fireInfo.parentEntity = NULL;
}
void audWeaponAudioEntity::HandleFire(audWeaponFireInfo &fireInfo,const eWeaponEffectGroup effectGroup)
{
audEnvironmentGroupInterface* occlusionGroup = NULL;
Vector3 sourcePosition;
sourcePosition.Zero();
audTracker *tracker = fireInfo.parentEntity->GetPlaceableTracker();
audWeaponInteriorMetrics interiorMetrics;
g_WeaponAudioEntity.GetInteriorMetrics(interiorMetrics, fireInfo.parentEntity);
const WeaponSettings * settings = fireInfo.FindWeaponSettings();
if(!naVerifyf(settings, "Couldn't find weapon settings from fireinfo with ItemSettings %s",
audNorthAudioEngine::GetMetadataManager().GetObjectName(fireInfo.audioSettingsRef)))
{
return;
}
audWeaponFireInfo::PresuckInfo presuckInfo;
u32 fireSound = fireInfo.GetWeaponFireSound(settings,
fireInfo.parentEntity && fireInfo.parentEntity->GetIsTypePed() && ((CPed*)fireInfo.parentEntity.Get())->IsLocalPlayer(), &presuckInfo, fireInfo.isKillShot);
u32 interiorShotSound = settings->InteriorShotSound;
f32 markerSpeed = 1.0f;
#if GTA_REPLAY
if(audNorthAudioEngine::IsInSlowMoVideoEditor() || audNorthAudioEngine::IsSuperSlowVideoEditor())
{
markerSpeed = CReplayMgr::GetMarkerSpeed();
#if __BANK
if(audNorthAudioEngine::IsForcingSlowMoVideoEditor())
markerSpeed = 0.2f;
if(audNorthAudioEngine::IsForcingSuperSlowMoVideoEditor())
markerSpeed = 0.05f;
#endif
}
#endif
bool cienmaticSlowMo = audNorthAudioEngine::IsInCinematicSlowMo();
if((cienmaticSlowMo || markerSpeed <= REPLAY_SLOW_MO_MARKER_SPEED_THRESHOLD) && settings->SlowMoInteriorShotSound != g_NullSoundHash)
{
interiorShotSound = settings->SlowMoInteriorShotSound;
}
if(markerSpeed <= REPLAY_SUPER_SLOW_MO_MARKER_SPEED_THRESHOLD && settings->SuperSlowMoInteriorShotSound != g_NullSoundHash)
{
interiorShotSound = settings->SuperSlowMoInteriorShotSound;
}
if(((AUD_GET_TRISTATE_VALUE(settings->Flags, FLAG_ID_WEAPONSETTINGS_ISPLAYERAUTOFIRE)== AUD_TRISTATE_TRUE) ||
(AUD_GET_TRISTATE_VALUE(settings->Flags, FLAG_ID_WEAPONSETTINGS_ISNPCAUTOFIRE)== AUD_TRISTATE_TRUE)) && settings->SlowMoInteriorShotSound == g_NullSoundHash)
{
interiorShotSound = g_NullSoundHash;
}
//If we have a silenced auto weapon here, something went wrong and there's a chance it could get stuck on
if(settings->AutoSound != g_NullSoundHash && settings->AutoSound != ATSTRINGHASH("SILENCE", 0xD0D7570A) && fireSound == settings->SuppressedFireSound)
{
return;
}
if (fireInfo.parentEntity && fireInfo.parentEntity->GetIsTypePed())
{
occlusionGroup = (static_cast<CPed*>(fireInfo.parentEntity.Get()))->GetWeaponEnvironmentGroup();
}
else if (fireInfo.parentEntity && fireInfo.parentEntity->GetIsTypeVehicle())
{
occlusionGroup = ((CVehicle*)fireInfo.parentEntity.Get())->GetAudioEnvironmentGroup();
}
if(tracker)
{
sourcePosition = tracker->GetPosition();
}
f32 interiorWetness = interiorMetrics.Wetness;
if(fireInfo.isSuppressed)
{
interiorWetness*= sm_InteriorSilencedWeaponWetness;
}
f32 interiorDryScaling = sm_InteriorDryShotVolumeCurve.CalculateValue(interiorWetness);
f32 interiorWetScaling = sm_InteriorWetShotVolumeCurve.CalculateValue(interiorWetness);
#if __BANK
if(g_DebugWeaponTimings && fireInfo.parentEntity)
{
grcDebugDraw::Sphere(fireInfo.parentEntity->GetTransform().GetPosition(), 0.5f, Color32(0,255,0), true, 5);
}
#endif
f32 postSubmixAttenuation = g_DefaultGunPostSubmixAttenuation;
bool isPlayerGun = false;
bool isPlayerVehicle = false;
if (fireInfo.parentEntity && fireInfo.parentEntity->GetIsTypePed() && (static_cast<CPed*>(fireInfo.parentEntity.Get()))->IsLocalPlayer() && !g_PlayerUsesNpcWeapons)
{
isPlayerGun = true;
postSubmixAttenuation = PlayerGunFired();
}
if(fireInfo.parentEntity && fireInfo.parentEntity->GetIsTypeVehicle() && ((CVehicle*)fireInfo.parentEntity.Get())->ContainsLocalPlayer())
{
isPlayerVehicle = true;
}
// only do loud sound stuff for weapons with fire sounds
if(!fireInfo.isSuppressed )
{
audNorthAudioEngine::RegisterLoudSound(sourcePosition,isPlayerGun);
audNorthAudioEngine::GetGtaEnvironment()->SpikeResonanceObjects(GetWeaponResonanceImpulse(effectGroup), sourcePosition, naEnvironment::sm_WeaponsResonanceDistance);
}
audSoundInitParams initParams;
initParams.UpdateEntity = true;
if(sm_PlayerEquippedWeaponSlot.waveSlot && sm_PlayerEquippedWeaponSlot.waveSlot->waveSlot && sm_PlayerEquippedWeaponSlot.waveSlot->IsLoaded())
{
initParams.WaveSlot = sm_PlayerEquippedWeaponSlot.waveSlot->waveSlot;
}
if(fireInfo.isKillShot)
{
tracker = NULL;
sourcePosition = VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetVolumeListenerPosition());
initParams.UpdateEntity = false;
}
BANK_ONLY(initParams.IsAuditioning = g_AuditionWeaponFire;);
initParams.Tracker = tracker;
initParams.Position = sourcePosition;
initParams.EnvironmentGroup = occlusionGroup;
if (fireInfo.parentEntity && fireInfo.parentEntity->GetIsTypePed() && ((CPed*)fireInfo.parentEntity.Get())->GetPedAudioEntity() )
{
initParams.Volume = ((CPed*)fireInfo.parentEntity.Get())->GetPedAudioEntity()->GetGunfightVolumeOffset();
}
if(isPlayerGun && naMicrophones::IsSniping() && AUD_GET_TRISTATE_VALUE(settings->Flags, FLAG_ID_WEAPONSETTINGS_RECOCKWHENSNIPING) == AUD_TRISTATE_TRUE)
{
CreateAndPlaySound(sm_CodeSounds.Find(ATSTRINGHASH("sniper_cock", 0xC9981E7B)), &initParams);
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(sm_CodeSounds.GetNameHash(), ATSTRINGHASH("sniper_cock", 0xC9981E7B), &initParams, NULL, fireInfo.parentEntity, eWeaponSoundEntity));
}
initParams.PostSubmixAttenuation = postSubmixAttenuation;
initParams.Volume += audDriverUtil::ComputeDbVolumeFromLinear(interiorDryScaling);
const u32 now = g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0);
const CrossfadeSound *crossfadeSound = SOUNDFACTORY.DecompressMetadata<CrossfadeSound>(fireSound);
if(fireInfo.lastPlayerHitTime + sm_PlayerHitBoostHoldTime > now )
{
initParams.PostSubmixAttenuation += sm_PlayerHitBoostVol;
initParams.VolumeCurveScale += sm_PlayerHitBoostRolloff;
}
audSound* nearSound = NULL;
audSound* farSound = NULL;
if(crossfadeSound)
{
#if __BANK
if(g_DebugWeaponTimings)
{
naErrorf("Crossfade sound %s time %u", g_AudioEngine.GetSoundManager().GetFactory().GetMetadataManager().GetObjectName(fireSound), fwTimer::GetTimeInMilliseconds());
}
#endif
const f32 dist2ToListener = (sourcePosition - VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetVolumeListenerPosition())).Mag2();
if(dist2ToListener <= crossfadeSound->MinDistance*crossfadeSound->MinDistance)
{
// only play the near sound
g_WeaponAudioEntity.CreateSound_LocalReference(crossfadeSound->NearSoundRef, &nearSound, &initParams);
}
else if(dist2ToListener >= crossfadeSound->MaxDistance*crossfadeSound->MaxDistance)
{
// only play the far sound
g_WeaponAudioEntity.CreateSound_LocalReference(crossfadeSound->FarSoundRef, &farSound, &initParams);
}
else
{
// perform crossfade
const f32 distToListener = sqrtf(dist2ToListener);
const f32 distFactor = (distToListener - crossfadeSound->MinDistance) / (crossfadeSound->MaxDistance-crossfadeSound->MinDistance);
initParams.Volume += audDriverUtil::ComputeDbVolumeFromLinear(1.f - distFactor);
g_WeaponAudioEntity.CreateSound_LocalReference(crossfadeSound->NearSoundRef, &nearSound, &initParams);
initParams.Volume = audDriverUtil::ComputeDbVolumeFromLinear(distFactor);
g_WeaponAudioEntity.CreateSound_LocalReference(crossfadeSound->FarSoundRef, &farSound, &initParams);
}
}
else
{
#if __BANK
if(g_DebugWeaponTimings)
{
naErrorf("Singlefire sound %s time %u", g_AudioEngine.GetSoundManager().GetFactory().GetMetadataManager().GetObjectName(fireSound), fwTimer::GetTimeInMilliseconds());
}
#endif
g_WeaponAudioEntity.CreateSound_LocalReference(fireSound, &nearSound, &initParams);
}
if(isPlayerGun && (audNorthAudioEngine::IsInSlowMoVideoEditor() || audNorthAudioEngine::IsSuperSlowVideoEditor()) && fireInfo.ammo == 0)
{
if(nearSound)
{
nearSound->FindAndSetVariableValue(ATSTRINGHASH("IsFinalBullet", 0xFA41EB98), 1.f);
}
if(farSound)
{
farSound->FindAndSetVariableValue(ATSTRINGHASH("IsFinalBullet", 0xFA41EB98), 1.f);
}
}
if(nearSound)
{
nearSound->PrepareAndPlay();
}
if(farSound)
{
farSound->PrepareAndPlay();
}
if(g_FrontendAudioEntity.GetSpecialAbilityMode() == audFrontendAudioEntity::kSpecialAbilityModeNone && audNorthAudioEngine::ShouldTriggerPulseHeadset())
{
if(isPlayerVehicle && fireSound == ATSTRINGHASH("SPL_TANKSHELL_PLAYER_MASTER", 0x7C8CC967))
{
g_WeaponAudioEntity.CreateAndPlaySound(g_FrontendAudioEntity.GetPulseHeadsetSounds().Find(ATSTRINGHASH("Tank_Fire", 0xBB0AF7FB)));
}
else if(isPlayerGun && fireSound == ATSTRINGHASH("SPL_GRENADE_PLAYER_MASTER", 0xA2A2CF85))
{
g_WeaponAudioEntity.CreateAndPlaySound(g_FrontendAudioEntity.GetPulseHeadsetSounds().Find(ATSTRINGHASH("GrenadeLauncher_Fire", 0x2DEA5398)));
}
}
audSoundInitParams interiorParams = initParams;
bool canDoInteriorSound = true;
if(audNorthAudioEngine::IsInSlowMo() && (((AUD_GET_TRISTATE_VALUE(settings->Flags, FLAG_ID_WEAPONSETTINGS_ISPLAYERAUTOFIRE)== AUD_TRISTATE_TRUE)) ||
((AUD_GET_TRISTATE_VALUE(settings->Flags, FLAG_ID_WEAPONSETTINGS_ISNPCAUTOFIRE)== AUD_TRISTATE_TRUE))))
{
canDoInteriorSound = false;
}
if(canDoInteriorSound)
{
if(interiorWetScaling > 0.f)
{
interiorParams.Volume = audDriverUtil::ComputeDbVolumeFromLinear(interiorWetScaling);
interiorParams.Predelay = interiorMetrics.Predelay;
interiorParams.SetVariableValue(ATSTRINGHASH("interior_hold", 1538583251), interiorMetrics.Hold);
interiorParams.LPFCutoff = interiorMetrics.Lpf;
g_WeaponAudioEntity.CreateAndPlaySound(interiorShotSound, &interiorParams);
}
else if(fireInfo.parentEntity == FindPlayerPed() && !g_DisableTightSpotInteriorGuns)
{
f32 interiorSoundVolume = -100.0f;
f32 interiorSoundHold = 0.0f;
audNorthAudioEngine::GetGtaEnvironment()->GetInteriorGunSoundMetricsForExterior(interiorSoundVolume, interiorSoundHold);
interiorParams.Volume = interiorSoundVolume;
interiorParams.SetVariableValue(ATSTRINGHASH("interior_hold", 0x5BB4EAD3), interiorSoundHold);
g_WeaponAudioEntity.CreateAndPlaySound(interiorShotSound, &interiorParams);
}
}
PlayWeaponReport(&fireInfo, &interiorMetrics, settings, 0.f);
}
f32 audWeaponAudioEntity::PlayerGunFired()
{
#if __BANK
if (g_PlayerGunAlwaysDamped)
{
sm_PlayerGunDuckingAttenuation = g_DefaultGunPostSubmixAttenuation;
sm_PlayerGunDampingOn = true;
}
else if (g_PlayerGunNeverDamped)
{
sm_PlayerGunDuckingAttenuation = 0.0f;
sm_PlayerGunDampingOn = false;
}
#endif
// Update what state we're in, and calculate a current offset volume
u32 timeInMs = fwTimer::GetTimeInMilliseconds();
if (sm_PlayerGunDampingOn)
{
// See if we've gone sufficiently long since the last shot that we should be back up to full volume again.
// (could stay in the ducking state but reduce the attenuation if not quite long enough - see if snapping back is shit)
if ((sm_LastTimePlayerGunFired + g_NotFiredForAWhileTime) < timeInMs)
{
sm_LastTimePlayerGunFired = timeInMs;
sm_PlayerGunDampingOn = false;
sm_PlayerGunDuckingAttenuation = 0.0f;
sm_LastTimePlayerNotFiredGunForAWhile = timeInMs;
return 0.0f;
}
else
{
// continue damping even more, unless we're fully damped
sm_LastTimePlayerGunFired = timeInMs;
sm_PlayerGunDuckingAttenuation = Max(sm_PlayerGunDuckingAttenuation + g_DuckingAttenuationPerShot, g_DefaultGunPostSubmixAttenuation);
return sm_PlayerGunDuckingAttenuation;
}
}
else
{
sm_LastTimePlayerGunFired = timeInMs;
// See how long ago we didn't fire for a while - if it's long enough, we start ducking
if ((sm_LastTimePlayerNotFiredGunForAWhile + g_BeenFiringForAWhileTime) < timeInMs)
{
sm_PlayerGunDampingOn = true; // so next time, we'll start ducking
}
sm_PlayerGunDuckingAttenuation = 0.0f; // don't bother actually ducking for this one
return 0.0f;
}
}
void audWeaponAudioEntity::PlayTwoEchos(u32 echoSound, u32 existingPredelay, Vector3& sourcePosition, f32 existingAttenuation, u32 echoDepth, u32 timeAutoSoundPlayed, EnvironmentRule* envRule)
{
if(envRule)
{
if(echoDepth >= envRule->EchoNumber)
return;
}
else if (echoDepth >= g_EchoDepth)
{
return;
}
existingAttenuation += g_EchoVolumeDrop;
u32 minEchoLoopCount = timeAutoSoundPlayed < g_MinAutoEchoLoopCountIgnoreTime ? 1 : g_MinAutoEchoLoopCount;
u32 loopNumber = 0;
if(timeAutoSoundPlayed != 0)
{
f32 loopScale = Clamp((f32)(timeAutoSoundPlayed)/(f32)(g_maxAutoSoundHoldTime), 0.0f, 1.0f);
loopNumber = (u32)(loopScale * 4) + minEchoLoopCount;
}
s32 bestEcho = -1;
s32 bestOppositeEcho = -1;
bestEcho = audNorthAudioEngine::GetGtaEnvironment()->GetBestEchoForSourcePosition(sourcePosition, &bestOppositeEcho);
if (bestEcho>-1)
{
Vector3 position;
u32 predelay = 0;
f32 attenuation = 0.0f;
audNorthAudioEngine::GetGtaEnvironment()->CalculateEchoDelayAndAttenuation(bestEcho, sourcePosition, &predelay, &attenuation, &position, echoDepth);
#if __BANK
if(g_bForceWeaponEchoSettings)
{
attenuation = g_fWeaponEchoAttenuation;
predelay = g_uWeaponEchoPredelay;
}
#endif
if(envRule)
{
f32 ruleScale = g_AmbientAudioEntity.GetAmbientEnvironmentRuleScale();
attenuation = Min(6.0f, (attenuation * (1.0f -ruleScale)) + (envRule->EchoAttenuation * ruleScale));
u32 ruleEchoDelay = (u32)(ruleScale * envRule->EchoDelay);
u32 ruleEchoDelayVariance = (u32)(ruleScale * audEngineUtil::GetRandomNumberInRange(-1 * envRule->EchoDelayVariance, envRule->EchoDelayVariance));
u32 nonruleEchoDelay = (u32)((1.0f - ruleScale) * predelay);
predelay = Max(0, (s32)(ruleEchoDelay + nonruleEchoDelay + ruleEchoDelayVariance));
}
audSoundInitParams initParams;
BANK_ONLY(initParams.IsAuditioning = g_AuditionWeaponFire;);
initParams.Position = position;
initParams.Volume = Max(-100.0f, attenuation + existingAttenuation);
initParams.Predelay = predelay + existingPredelay;
if(sm_PlayerEquippedWeaponSlot.waveSlot && sm_PlayerEquippedWeaponSlot.waveSlot->waveSlot && sm_PlayerEquippedWeaponSlot.waveSlot->IsLoaded())
{
initParams.WaveSlot = sm_PlayerEquippedWeaponSlot.waveSlot->waveSlot;
}
if(timeAutoSoundPlayed != 0)
{
if(echoDepth == 0)
{
if(timeAutoSoundPlayed >= initParams.Predelay)
initParams.Predelay = 0;
else
initParams.Predelay -= timeAutoSoundPlayed;
}
}
if(timeAutoSoundPlayed != 0)
{
initParams.SetVariableValue(ATSTRINGHASH("AUTO_ECHO_LOOP_COUNT", 0xE53436C4), (f32)loopNumber);
}
g_WeaponAudioEntity.CreateAndPlaySound(echoSound, &initParams);
PlayTwoEchos(echoSound, predelay+existingPredelay, position, existingAttenuation+attenuation, echoDepth+1, 0, envRule);
}
if (g_PlayBothEchos && bestOppositeEcho>-1)
{
Vector3 position;
u32 predelay = 0;
f32 attenuation = 0.0f;
audNorthAudioEngine::GetGtaEnvironment()->CalculateEchoDelayAndAttenuation(bestOppositeEcho, sourcePosition, &predelay, &attenuation, &position, echoDepth);
#if __BANK
if(g_bForceWeaponEchoSettings)
{
attenuation = g_fWeaponEchoAttenuation;
predelay = g_uWeaponEchoPredelay;
}
#endif
if(envRule)
{
f32 ruleScale = g_AmbientAudioEntity.GetAmbientEnvironmentRuleScale();
attenuation = Min(6.0f, (attenuation * (1.0f -ruleScale)) + (envRule->EchoAttenuation * ruleScale));
u32 ruleEchoDelay = (u32)(ruleScale * envRule->EchoDelay);
u32 ruleEchoDelayVariance = (u32)(ruleScale * audEngineUtil::GetRandomNumberInRange(-1 * envRule->EchoDelayVariance, envRule->EchoDelayVariance));
u32 nonruleEchoDelay = (u32)((1.0f - ruleScale) * predelay);
predelay = Max(0, (s32)(ruleEchoDelay + nonruleEchoDelay + ruleEchoDelayVariance));
}
audSoundInitParams initParams;
initParams.Position = position;
BANK_ONLY(initParams.IsAuditioning = g_AuditionWeaponFire;);
initParams.Volume = Max(-100.0f, attenuation + existingAttenuation);
initParams.Predelay = predelay + existingPredelay;
if(sm_PlayerEquippedWeaponSlot.waveSlot && sm_PlayerEquippedWeaponSlot.waveSlot->waveSlot && sm_PlayerEquippedWeaponSlot.waveSlot->IsLoaded())
{
initParams.WaveSlot = sm_PlayerEquippedWeaponSlot.waveSlot->waveSlot;
}
if(timeAutoSoundPlayed != 0)
{
if(echoDepth == 0)
{
if(timeAutoSoundPlayed >= initParams.Predelay)
initParams.Predelay = 0;
else
initParams.Predelay -= timeAutoSoundPlayed;
}
}
if(timeAutoSoundPlayed != 0)
{
initParams.SetVariableValue(ATSTRINGHASH("AUTO_ECHO_LOOP_COUNT", 0xE53436C4), (f32)loopNumber);
}
g_WeaponAudioEntity.CreateAndPlaySound(echoSound, &initParams);
/*Vector3 positionForNextReflection;
Vector3* echoPosition = audNorthAudioEngine::GetGtaEnvironment()->GetEchoPosition();
positionForNextReflection = echoPosition[bestEcho];
Vector3 aWeeBitAway = positionForNextReflection-g_AudioEngine.GetEnvironment().GetVolumeListenerPosition();
aWeeBitAway.NormalizeSafe();
positionForNextReflection.Add(aWeeBitAway);*/
PlayTwoEchos(echoSound, predelay+existingPredelay, position, existingAttenuation+attenuation, echoDepth+1, 0, envRule);
}
}
u32 audWeaponAudioEntity::GetCustomEchoSoundForWeapon(audSoundSet echoSet, eWeaponWheelSlot wheelSlot)
{
switch(wheelSlot)
{
case WEAPON_WHEEL_SLOT_PISTOL:
return echoSet.Find("Pistol").Get();
case WEAPON_WHEEL_SLOT_SMG:
return echoSet.Find("SMG").Get();
case WEAPON_WHEEL_SLOT_RIFLE:
return echoSet.Find("Rifle").Get();
case WEAPON_WHEEL_SLOT_SNIPER:
return echoSet.Find("Sniper").Get();
case WEAPON_WHEEL_SLOT_SHOTGUN:
return echoSet.Find("Shotgun").Get();
case WEAPON_WHEEL_SLOT_HEAVY:
return echoSet.Find("Heavy").Get();
default:
return 0;
}
}
void audWeaponAudioEntity::PlayBulletBy(u32 weaponAudioHash, const Vector3 &vecStart, const Vector3 &vecEnd, const s32 predelay)
{
if (weaponAudioHash == ATSTRINGHASH("AUDIO_ITEM_VEHICLE_WEAPON_FLAMETHROWER", 0x58917377) ||
weaponAudioHash == ATSTRINGHASH("AUDIO_ITEM_VEHICLE_WEAPON_FLAMETHROWER_SCIFI", 0xD6B8E406) ||
weaponAudioHash == ATSTRINGHASH("AUDIO_ITEM_VEHICLE_WEAPON_MINI_FLAMETHROWER", 0xC444739B))
{
return;
}
#if GTA_REPLAY
if(CReplayMgr::ShouldRecord())
{
CReplayMgr::RecordFx<CPacketSoundBulletBy>(CPacketSoundBulletBy(vecStart, vecEnd, predelay, weaponAudioHash));
}
#endif // GTA_REPLAY
if(audNorthAudioEngine::GetMicrophones().GetMicrophoneSettings()
&& AUD_GET_TRISTATE_VALUE(audNorthAudioEngine::GetMicrophones().GetMicrophoneSettings()->Flags,FLAG_ID_MICROPHONESETTINGS_DISABLEBULLETSBY) != AUD_TRISTATE_TRUE)
{
// check to see if this bullet intersects with a sphere in 0.5m front of the camera
Vector3 v1,v2;
Vector3 forwardNorm = VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetPanningListenerMatrix().GetCol1());
forwardNorm.Normalize();
Vector3 centre = VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetPanningListenerPosition()) + (forwardNorm*0.5f);
Vector3 forward = VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetPanningListenerMatrix().GetCol1());
Vector3 right = VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetPanningListenerMatrix().GetCol0());
spdSphere sphere = spdSphere(RCC_VEC3V(centre), ScalarV(g_BulletBySphereRadius));
Vector3 w = (vecEnd - vecStart);
w.Normalize();
if(fwGeom::IntersectSphereRay(sphere, vecStart, w, v1, v2))
{
Vector3 firstIntersectingLine = (v1 - vecStart);
Vector3 secondIntersectingLine = (v2 - vecStart);
f32 origLength2 = (vecEnd - vecStart).Mag2();
// check the intersecting line isn't any longer than the original line, and is same direction as the ray
if(firstIntersectingLine.Mag2() < origLength2 && secondIntersectingLine.Mag2() < origLength2 && DotProduct(v1 - vecStart, w) >= 0.0f && DotProduct(v2 - vecStart, w) >= 0.0f)
{
u32 now = fwTimer::GetTimeInMilliseconds(), nextTimetoPlay = m_NextBulletByTimeMs;
#if GTA_REPLAY
if(CReplayMgr::IsPlaying())
{
now = CReplayMgr::GetGameTimeAtRelativeFrame(0);
if(now + g_BulletByMaxTimeMs < nextTimetoPlay) //looks like the editor has been rewound, let's reset the time
{
nextTimetoPlay = now;
}
}
#endif
if(now >= nextTimetoPlay)
{
m_NextBulletByTimeMs = now + audEngineUtil::GetRandomNumberInRange(g_BulletByMinTimeMs, g_BulletByMaxTimeMs);
// calc vectors from centre of sphere to intersection points, ignoring height
v1 = (v1 - centre);
v1.z = 0.0f;
v1.Normalize();
v2 = (v2 - centre);
v2.z = 0.0f;
v2.Normalize();
// calculate angles between these vectors and camera forward
f32 inDp = DotProduct(v1, forward);
f32 outDp = DotProduct(v2, forward);
f32 inAngle = ( RtoD * rage::AcosfSafe(inDp));
f32 outAngle = ( RtoD * rage::AcosfSafe(outDp));
if(DotProduct(v1, right) < 0.0f)
{
inAngle = 360.f - inAngle;
}
if(DotProduct(v2, right) < 0.0f)
{
outAngle = 360.f - outAngle;
}
//naDisplayf("in dp: %f in angle: %f, out dp: %f out angle: %f", inDp, inAngle, outDp, outAngle);
audSoundInitParams initParams;
BANK_ONLY(initParams.IsAuditioning = g_AuditionWeaponFire;);
initParams.Pan = (s16)inAngle;
initParams.Predelay = predelay;
if (audWeaponAudioEntity::IsRubberBulletGun(weaponAudioHash) || audWeaponAudioEntity::IsRiotShotgun(weaponAudioHash))
{
audSoundSetFieldRef customSoundRef;
customSoundRef.Set(audWeaponAudioEntity::IsRubberBulletGun(weaponAudioHash) ? ATSTRINGHASH("Rubber_Bullet_Sounds", 0x50AB02CD) : ATSTRINGHASH("Riot_Shotgun_Sounds", 0x992CA88C), ATSTRINGHASH("Zip_By", 0x6AAAB67B));
CreateAndPlaySound(customSoundRef.GetMetadataRef(), &initParams);
}
else if (IsRayGun(weaponAudioHash))
{
CreateAndPlaySound(ATSTRINGHASH("Laser_Bullets_Zip_By_Master", 0x786563F2), &initParams);
}
else
{
audSoundSet& soundSet = (Water::GetCameraWaterDepth() > 0.f) ? sm_BulletByUnderwaterSounds : sm_BulletByGeneralSounds;
audMetadataRef soundIn = soundSet.Find(ATSTRINGHASH("BulletByIn", 0x41A9ACE7));
audMetadataRef soundOut = soundSet.Find(ATSTRINGHASH("BulletByOut", 0x13C0C933));
#if GTA_REPLAY
u32 soundInSlowMo = ATSTRINGHASH("BulletByInSlowMo", 0x2674C29A);
u32 soundOutSlowMo = ATSTRINGHASH("BulletByOutSlowMo", 0x3B71DE0D);
u32 soundInSuperSlowMo = ATSTRINGHASH("BulletByInSuperSlowMo", 0xC32FC09B);
u32 soundOutSuperSlowMo = ATSTRINGHASH("BulletByOutSuperSlowMo", 0x4E8611F2);
if (audNorthAudioEngine::IsInSlowMoVideoEditor() || audNorthAudioEngine::IsSuperSlowVideoEditor())
{
float markerSpeed = CReplayMgr::GetMarkerSpeed();
if (markerSpeed <= REPLAY_SLOW_MO_MARKER_SPEED_THRESHOLD)
{
if (soundSet.Find(soundInSlowMo).IsValid())
{
soundIn = soundSet.Find(soundInSlowMo);
}
if (soundSet.Find(soundOutSlowMo).IsValid())
{
soundOut = soundSet.Find(soundOutSlowMo);
}
}
if (markerSpeed <= REPLAY_SUPER_SLOW_MO_MARKER_SPEED_THRESHOLD)
{
if (soundSet.Find(soundInSuperSlowMo).IsValid())
{
soundIn = soundSet.Find(soundInSuperSlowMo);
}
if (soundSet.Find(soundOutSuperSlowMo).IsValid())
{
soundOut = soundSet.Find(soundOutSuperSlowMo);
}
}
}
#endif
CreateAndPlaySound(soundIn, &initParams);
initParams.Pan = (s16)outAngle;
CreateAndPlaySound(soundOut, &initParams);
}
}
}
}
//grcDebugDraw::Sphere(centre, g_BulletBySphereRadius, Color32(255,0,0), false);
}
}
bool audWeaponAudioEntity::IsRayGun(u32 weaponAudioHash)
{
return weaponAudioHash == ATSTRINGHASH("AUDIO_ITEM_RAYMINIGUN", 0x142840C6) ||
weaponAudioHash == ATSTRINGHASH("AUDIO_ITEM_RAYCARBINE", 0x78E492D8) ||
weaponAudioHash == ATSTRINGHASH("AUDIO_ITEM_RAYPISTOL", 0xADEC5478) ||
weaponAudioHash == ATSTRINGHASH("AUDIO_ITEM_VEHICLE_WEAPON_50_CAL_LASER_TURRET", 0xD88BC488) ||
weaponAudioHash == ATSTRINGHASH("AUDIO_ITEM_VEHICLE_WEAPON_DUAL_50_CAL_LASER_TURRET", 0xE05AC7D4) ||
weaponAudioHash == ATSTRINGHASH("AUDIO_ITEM_VEHICLE_WEAPON_MINIGUN_LASER", 0x55B60F3) ||
weaponAudioHash == ATSTRINGHASH("AUDIO_ITEM_VEHICLE_WEAPON_MINITANK_PLASMA_CANNON", 0xEE747AA7);
}
bool audWeaponAudioEntity::IsRubberBulletGun(u32 weaponAudioHash)
{
return weaponAudioHash == ATSTRINGHASH("AUDIO_ITEM_RUBBERGUN", 0x3D4AE4FE);
}
bool audWeaponAudioEntity::IsRiotShotgun(u32 weaponAudioHash)
{
return weaponAudioHash == ATSTRINGHASH("AUDIO_ITEM_RIOT_SHOTGUN", 0x2C7DC065);
}
void audWeaponAudioEntity::PlayExplosionBulletBy(const Vector3 &vecStart)
{
Vector3 forwardNorm = VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetPanningListenerMatrix().GetCol1());
forwardNorm.Normalize();
Vector3 centre = VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetPanningListenerPosition()) + (forwardNorm*0.5f);
// Have the vector go from the explosion, straight through the sphere centre, and out the other side a wee way
Vector3 vecEnd = (centre - vecStart);
if (vecEnd.Mag2() < (g_ExplosionBulletByDistance*g_ExplosionBulletByDistance))
{
vecEnd.Scale(1.5f);
vecEnd.Add(vecStart);
PlayBulletBy(0u, vecStart, vecEnd, g_ExplosionBulletByPredelay);
#if GTA_REPLAY
if(CReplayMgr::ShouldRecord())
{
CReplayMgr::RecordFx<CPacketSoundExplosionBulletBy>(CPacketSoundExplosionBulletBy(vecStart));
}
#endif
}
}
void audWeaponAudioEntity::AttachProjectileLoop(const u32 soundHash, CObject *obj, audSound **sound, const bool underwater)
{
SYS_CS_SYNC(m_ProjectileLock);
if(!sm_ProjectileEvents.IsFull())
{
audProjectileData & projectile = sm_ProjectileEvents.Append();
audSoundSet projectileSounds;
projectileSounds.Init(soundHash);
if(projectileSounds.IsInitialised())
{
projectile.soundKeyHash = underwater ? ATSTRINGHASH("underwater", 0xA2663418) : ATSTRINGHASH("flight", 0x2570A839);
projectile.soundSetHash = soundHash;
projectile.object = obj;
projectile.soundPtr = sound;
projectile.isUnderwater = underwater;
}
}
}
void audWeaponAudioEntity::AttachProjectileLoop(const char * soundName, CObject *obj, audSound **sound, bool underwater)
{
SYS_CS_SYNC(m_ProjectileLock);
if(!sm_ProjectileEvents.IsFull())
{
audProjectileData & projectile = sm_ProjectileEvents.Append();
u32 soundMapKey = atPartialStringHash(soundName);
if(underwater)
{
soundMapKey = atStringHash("_UNDERWATER", soundMapKey);
}
else
{
soundMapKey = atFinalizeHash(soundMapKey);
}
projectile.soundKeyHash = soundMapKey;
projectile.soundSetHash = ATSTRINGHASH("CODED_WEAPON_SOUNDS", 0xB148A7E7);
projectile.object = obj;
projectile.soundPtr = sound;
projectile.isUnderwater = underwater;
}
}
void audWeaponAudioEntity::TriggerDeferredProjectileEvents()
{
SYS_CS_SYNC(m_ProjectileLock);
for(int i=0; i<sm_ProjectileEvents.GetCount(); i++)
{
if(sm_ProjectileEvents[i].object && sm_ProjectileEvents[i].soundPtr)
{
if((*sm_ProjectileEvents[i].soundPtr))
{
(*sm_ProjectileEvents[i].soundPtr)->StopAndForget();
}
audSoundInitParams initParams;
initParams.Tracker = sm_ProjectileEvents[i].object->GetPlaceableTracker();
audSoundSet soundSet;
soundSet.Init(sm_ProjectileEvents[i].soundSetHash);
if(soundSet.IsInitialised())
{
g_WeaponAudioEntity.CreateSound_PersistentReference(soundSet.Find(sm_ProjectileEvents[i].soundKeyHash), sm_ProjectileEvents[i].soundPtr, &initParams);
REPLAY_ONLY(CReplayMgr::ReplayRecordSoundPersistant(sm_ProjectileEvents[i].soundSetHash, sm_ProjectileEvents[i].soundKeyHash, &initParams, *sm_ProjectileEvents[i].soundPtr, NULL, eWeaponSoundEntity);)
if((*sm_ProjectileEvents[i].soundPtr))
{
u32 clientVar = (sm_ProjectileEvents[i].isUnderwater?1:0);
(*sm_ProjectileEvents[i].soundPtr)->SetClientVariable(clientVar);
(*sm_ProjectileEvents[i].soundPtr)->PrepareAndPlay();
}
}
}
}
sm_ProjectileEvents.Reset();
}
void audWeaponAudioEntity::ReleaseScriptWeapon()
{
if(sm_ScriptWeaponSlot.waveSlot)
{
sm_PlayerWeaponSlotManager.FreeWaveSlot(sm_ScriptWeaponSlot.waveSlot);
}
}
bool audWeaponAudioEntity::AddScriptWeapon(u32 itemHash)
{
bool isAlreadyLoaded = false;
audPlayerWeaponSlot * weaponSlot = &sm_ScriptWeaponSlot;
if(!weaponSlot->waveSlot)
{
weaponSlot->Init();
}
else if(weaponSlot->contextHash == itemHash)
{
isAlreadyLoaded = true;
}
else
{
naAssertf(!weaponSlot->waveSlot, "Trying to load weapon audio from script but there's already one loaded; release the previous weapon audio");
return false;
}
if(!isAlreadyLoaded)
{
weaponSlot->contextHash = itemHash;
LoadDynamicWeaponAudio(weaponSlot, itemHash);
return weaponSlot->waveSlot!= NULL && weaponSlot->waveSlot->IsLoaded();
}
return weaponSlot->waveSlot->IsLoaded(); //the wave bank is already loaded eg as a player weapon
}
void audWeaponAudioEntity::ProcessEquippedWeapon()
{
if(IsWaitingOnEquippedWeaponLoad())
{
audPlayerWeaponSlot * equippedSlot = &sm_PlayerEquippedWeaponSlot;
if(equippedSlot->waveSlot)
{
if(equippedSlot->waveSlot->IsLoaded())
{
BANK_ONLY(naDisplayf("Weapon audio for %s loaded. Bank: %s (%u)", audNorthAudioEngine::GetMetadataManager().GetObjectName(equippedSlot->audioHash), equippedSlot->waveSlot->waveSlot->GetLoadedBankName(), __LINE__));
sm_IsWaitingOnEquippedWeaponLoad = false;
sm_UseBackupWeapons = false;
}
return;
}
CPed * player = CGameWorld::FindLocalPlayer();
if(player)
{
CPedWeaponManager * weaponMgr = player->GetWeaponManager();
if(weaponMgr)
{
CWeapon * weapon = weaponMgr->GetEquippedWeapon();
if(weapon)
{
u32 weaponHash = weapon->GetWeaponHash();
CPedInventory * invent = player->GetInventory();
if(invent && invent->GetWeapon(weaponHash) && invent->GetWeapon(weaponHash)->GetInfo())
{
u32 audioHash = invent->GetWeapon(weaponHash)->GetInfo()->GetAudioHash();
HandlePlayerEquippedWeapon(weaponHash, audioHash);
}
}
}
}
}
}
void audWeaponAudioEntity::ProcessNextWeapon()
{
if(sm_IsWaitingOnNextWeaponLoad)
{
CPed * player = CGameWorld::FindLocalPlayer();
if(player)
{
u32 weaponHash = GetNextWeapon(player);
if(weaponHash )
{
audPlayerWeaponSlot * nextSlot = &sm_PlayerNextWeaponSlot;
if(nextSlot->waveSlot && nextSlot->contextHash==weaponHash)
{
if(nextSlot->waveSlot->IsLoaded())
{
sm_IsWaitingOnNextWeaponLoad = false;
}
return;
}
CPedInventory * invent = player->GetInventory();
if(invent)
{
CWeaponItem * weaponItem = invent->GetWeapon(weaponHash);
if(weaponItem && weaponItem->GetInfo())
{
u32 audioHash = weaponItem->GetInfo()->GetAudioHash();
AddNextInventoryWeapon(player, weaponHash, audioHash);
}
}
}
else ///no next weapon so let's not keep trying
{
//sm_IsWaitingOnNextWeaponLoad = false;
}
}
}
}
void audWeaponAudioEntity::AddPlayerInventoryWeapon()
{
//sm_IsWaitingOnNextWeaponLoad = true;
}
void audWeaponAudioEntity::AddNextInventoryWeapon(CPed* player, u32 weaponHash, u32 audioHash)
{
if(!audioHash || !weaponHash)
{
return;
}
if(player && weaponHash == GetNextWeapon(player))
{
bool isAlreadyLoaded = false;
audPlayerWeaponSlot * weaponSlot = &sm_PlayerNextWeaponSlot;
if(!weaponSlot->waveSlot)
{
weaponSlot->Init();
}
else if(weaponSlot->contextHash == weaponHash)
{
isAlreadyLoaded = true;
}
else
{
sm_PlayerWeaponSlotManager.FreeWaveSlot(weaponSlot->waveSlot);
weaponSlot->Init();
}
if(!isAlreadyLoaded)
{
weaponSlot->contextHash = weaponHash;
LoadDynamicWeaponAudio(weaponSlot, audioHash);
}
if(!weaponSlot->waveSlot || weaponSlot->waveSlot->IsLoaded())
{
sm_IsWaitingOnNextWeaponLoad = true;
}
else
{
sm_IsWaitingOnNextWeaponLoad = false;
}
}
}
void audPlayerWeaponLoadEvent::AddPlayerWeaponLoadEvent(u32 inWeaponHash, u32 inAudioHash)
{
weaponHash = inWeaponHash;
audioHash = inAudioHash;
waitingForLoad = true;
}
void audPlayerWeaponLoadEvent::HandlePlayerWeaponLoad()
{
if(waitingForLoad)
{
g_WeaponAudioEntity.HandlePlayerEquippedWeapon(weaponHash, audioHash BANK_ONLY(, true));
waitingForLoad = false;
}
}
void audWeaponAudioEntity::AddPlayerEquippedWeapon(u32 weaponHash, u32 audioHash)
{
#if GTA_REPLAY
if(CReplayMgr::ShouldRecord())
{
CReplayMgr::RecordFx<CPacketSndLoadWeaponData>(CPacketSndLoadWeaponData(weaponHash, audioHash, sm_PlayerEquippedWeaponSlot.audioHash));
}
#endif // GTA_REPLAY
m_PlayerWeaponLoad.AddPlayerWeaponLoadEvent(weaponHash, audioHash);
}
bool audWeaponAudioEntity::HandlePlayerEquippedWeapon(u32 weaponHash, u32 audioHash, bool BANK_ONLY(isEquippingNow))
{
bool isAlreadyLoaded = false;
if(!audioHash || !weaponHash)
{
return true;
}
//First sort out loading our equipped weapon audio
audPlayerWeaponSlot * weaponSlot = &sm_PlayerEquippedWeaponSlot;
if(!weaponSlot->waveSlot)
{
weaponSlot->Init();
}
else if(weaponSlot->contextHash == weaponHash)
{
isAlreadyLoaded = true;
}
else
{
AddPlayerPreviousWeapon(weaponSlot->contextHash, weaponSlot->audioHash);
sm_PlayerWeaponSlotManager.FreeWaveSlot(weaponSlot->waveSlot);
weaponSlot->Init();
}
if(!isAlreadyLoaded)
{
#if __BANK
if(g_ForceWaitForPlayerEquippedWeapon > 0 && isEquippingNow)
{
g_ForceWaitForPlayerEquippedWeaponTime = audNorthAudioEngine::GetCurrentTimeInMs() + (u32)(g_ForceWaitForPlayerEquippedWeapon*1000);
}
#endif
weaponSlot->contextHash = weaponHash;
if(!LoadDynamicWeaponAudio(weaponSlot, audioHash))
{
return false;
}
if(!weaponSlot->waveSlot)
{
#if RSG_BANK
const char * settingsName = audNorthAudioEngine::GetMetadataManager().GetObjectName(audioHash);
if(!settingsName)
{
settingsName = "NO OBJECT";
}
naDisplayf("Failed to create a weapon waveslot for audio settings %s hash %u", settingsName, audioHash);
#endif
}
}
if(!weaponSlot->waveSlot)
{
sm_IsWaitingOnEquippedWeaponLoad = false;
}
else
{
sm_IsWaitingOnEquippedWeaponLoad = true;
}
//If we've forced a weapon wait we won't have a waveslot so need to fake
#if __BANK
if(g_ForceWaitForPlayerEquippedWeaponTime > audNorthAudioEngine::GetCurrentTimeInMs())
{
sm_IsWaitingOnEquippedWeaponLoad = true;
}
#endif
return true;
}
bool audWeaponAudioEntity::IsWaitingOnEquippedWeaponLoad()
{
if(PARAM_noaudiohardware.Get())
{
return false;
}
#if __BANK
if(audNorthAudioEngine::GetCurrentTimeInMs() <= g_ForceWaitForPlayerEquippedWeaponTime)
{
return true;
}
#endif
return sm_IsWaitingOnEquippedWeaponLoad;
}
void audWeaponAudioEntity::AddPlayerPreviousWeapon(u32 weaponHash, u32 audioHash)
{
bool isAlreadyLoaded = false;
if(!audioHash || !weaponHash)
{
return;
}
//First sort out loading our equipped weapon audio
audPlayerWeaponSlot * weaponSlot = &sm_PlayerNextWeaponSlot;
if(!weaponSlot->waveSlot)
{
weaponSlot->Init();
}
else if(weaponSlot->contextHash == weaponHash)
{
isAlreadyLoaded = true;
}
else
{
sm_PlayerWeaponSlotManager.FreeWaveSlot(weaponSlot->waveSlot);
weaponSlot->Init();
}
if(!isAlreadyLoaded)
{
weaponSlot->contextHash = weaponHash;
LoadDynamicWeaponAudio(weaponSlot, audioHash);
}
}
bool audWeaponAudioEntity::LoadDynamicWeaponAudio(audPlayerWeaponSlot * weaponSlot, u32 audioHash)
{
if(!audioHash || !weaponSlot->contextHash || g_PlayerUsesNpcWeapons || PARAM_noaudio.Get())
{
return true;
}
weaponSlot->audioHash = audioHash;
if(!naVerifyf(!weaponSlot->waveSlot, "We should already have freed this wave slot before calling LoadDynamicWeapon audio (audio settings: %s", audNorthAudioEngine::GetMetadataManager().GetObjectName(audioHash)))
{
sm_PlayerWeaponSlotManager.FreeWaveSlot(weaponSlot->waveSlot);
naAssertf(!weaponSlot->waveSlot, "Tried and failed to free weapon waveslot, for settings %s", audNorthAudioEngine::GetMetadataManager().GetObjectName(audioHash));
weaponSlot->waveSlot = NULL;
}
WeaponSettings * settings = GetWeaponSettings(audioHash, ATSTRINGHASH("player", 0x6f0783f5), true);
if(settings BANK_ONLY(&& g_ForceWaitForPlayerEquippedWeaponTime < audNorthAudioEngine::GetCurrentTimeInMs()))
{
BANK_ONLY(naDisplayf("Loading weapon audio from bank sound %s", g_AudioEngine.GetSoundManager().GetFactory().GetMetadataManager().GetObjectName(settings->BankSound));)
u32 bankId = GetPlayerBankIdFromWeaponSettings(settings);
if(bankId < AUD_INVALID_BANK_ID)
{
#if __ASSERT
audWaveSlot* waveSlot = audWaveSlot::FindLoadedBankWaveSlot(bankId);
if(waveSlot && waveSlot->IsStatic())
{
naAssertf(false,"Already found a statically loaded bank :%s on weaponsettings %s for the context :%u",waveSlot->GetBankName(bankId), audNorthAudioEngine::GetMetadataManager().GetObjectNameFromNameTableOffset(settings->NameTableOffset), weaponSlot->contextHash);
}
#endif
weaponSlot->waveSlot = sm_PlayerWeaponSlotManager.LoadBank(bankId, AUD_WAVE_SLOT_ANY, false, NULL, naWaveLoadPriority::PlayerInteractive);
if(!weaponSlot->waveSlot)
{
sm_UseBackupWeapons = true;
BANK_ONLY(naErrorf("Failed to get a waveslot when loading audio for %s", audNorthAudioEngine::GetMetadataManager().GetObjectName(audioHash));)
}
else
{
sm_UseBackupWeapons = false;
BANK_ONLY(naDisplayf("Started loading audio for %s", audNorthAudioEngine::GetMetadataManager().GetObjectName(audioHash));)
}
}
else
{
sm_UseBackupWeapons = false; //Never use backup weapons if this weapon doesn't require a bank load
}
#if __DEV
ValidateWeaponSettings(settings);
#endif
}
else
{
naWarningf("Couldn't get weapon settings from Item %u", audioHash);
}
return true;
}
void audWeaponAudioEntity::RemovePlayerInventoryWeapon(u32 UNUSED_PARAM(weaponHash))
{
//for(u32 i=0; i < g_AudNumPlayerWeaponSlots; i++)
//{
// audPlayerWeaponSlot * slot = &sm_PlayerWeaponSlots[i];
// if(slot->waveSlot)
// {
// if(slot->contextHash == weaponHash)
// {
// /*slot->isInventory = false;
// slot->weaponHash = NULL_HASH;
// slot->lastUsedTime = fwTimer::GetTimeInMilliseconds();
// sm_PlayerWeaponSlotManager.FreeWaveSlot(slot->waveSlot);
// */
// break;
// }
// }
//}
}
void audWeaponAudioEntity::RemoveAllPlayerInventoryWeapons()
{
for(u32 i=0; i < g_AudNumPlayerWeaponSlots; i++)
{
//audPlayerWeaponSlot * slot = &sm_PlayerWeaponSlots[i];
/*if(slot->waveSlot && slot->isInventory)
{
slot->isInventory = false;
slot->weaponHash = NULL_HASH;
slot->lastUsedTime = fwTimer::GetTimeInMilliseconds();
}*/
}
}
void audWeaponAudioEntity::AddAllInventoryWeaponsOnPed(CPed * ped)
{
if(ped->IsLocalPlayer())
{
sm_WantsToLoadPlayerEquippedWeapon = true;
if(ped->GetWeaponManager() && ped->GetWeaponManager()->GetEquippedWeapon())
{
if(HandlePlayerEquippedWeapon(ped->GetWeaponManager()->GetEquippedWeapon()->GetWeaponHash(), ped->GetWeaponManager()->GetEquippedWeapon()->GetWeaponInfo()->GetAudioHash()))
{
sm_WantsToLoadPlayerEquippedWeapon = false;
#if GTA_REPLAY
if(CReplayMgr::IsEditModeActive() == false)
{
CReplayMgr::RecordFx<CPacketSndLoadWeaponData>(CPacketSndLoadWeaponData(ped->GetWeaponManager()->GetEquippedWeapon()->GetWeaponHash(), ped->GetWeaponManager()->GetEquippedWeapon()->GetWeaponInfo()->GetAudioHash(), sm_PlayerEquippedWeaponSlot.audioHash));
}
#endif // GTA_REPLAY
}
}
}
}
u32 audWeaponAudioEntity::GetNextWeapon(CPed * ped, u32 * UNUSED_PARAM(audioHash))
{
const CWeaponInfoBlob::SlotList& slotList = CWeaponInfoManager::GetSlotListBest();
// naCondLogf(!ped, DIAG_SEVERITY_FATAL, "pPed is NULL");
naAssert(ped->GetInventory());
CPedWeaponManager* weaponManager = ped->GetWeaponManager();
if(!weaponManager)
{
return 0;
}
CWeapon * weapon = weaponManager->GetEquippedWeapon();
if(!weapon)
{
return 0;
}
//u32 equippedWeapon = weapon->GetWeaponHash();
//u32 ammoHash = weapon->GetWeaponInfo()->GetAmmoInfo()->GetHash();
for(s32 i = 0; i < slotList.GetCount(); i++)
{
//naErrorf("Looking for weapon hash [%s]", slotList[i].GetCStr());
const CWeaponItem* pItem = ped->GetInventory()->GetWeaponBySlot(slotList[i].GetHash());
if(pItem)
{
//naErrorf("Item info hash %u, ammo %u equipped weapon hash %u amm %u", pItem->GetInfo()->GetHash(), pItem->GetInfo()->GetAmmoInfo()->GetHash(), equippedWeapon, ammoHash);
if(ped->GetWeaponManager()->GetWeaponSelector()->GetIsWeaponValid(ped, pItem->GetInfo(), true, false) && pItem->GetInfo()->GetModelIndex() != ped->GetWeaponManager()->GetEquippedWeapon()->GetWeaponInfo()->GetModelIndex()) // && pItem->GetInfo()->GetAmmoInfo()->GetHash()!= ammoHash)
{
WeaponSettings * settings = GetWeaponSettings( pItem->GetInfo()->GetAudioHash(), ATSTRINGHASH("player", 0x6f0783f5));
if(settings && settings->BankSound != g_NullSoundHash)
{
/*if(audioHash)
{
*audioHash = pItem->GetInfo()->GetAudioHash();
}*/
return pItem->GetInfo()->GetHash();
}
}
}
}
return 0;
}
WeaponSettings * audWeaponAudioEntity::GetWeaponSettings(u32 audioHash, u32 contextHash, bool forceContext)
{
static u32 playerHash = ATSTRINGHASH("player", 0x6f0783f5);
if(contextHash == playerHash && !forceContext)
{
if(audNorthAudioEngine::GetMicrophones().IsCinematicMicActive())
{
contextHash = NULL_HASH;
}
else
{
MicrophoneSettings * mic = audNorthAudioEngine::GetMicrophones().GetMicrophoneSettings();
if(mic && AUD_GET_TRISTATE_VALUE(mic->Flags, FLAG_ID_MICROPHONESETTINGS_DISTANTPLAYERWEAPONS) == AUD_TRISTATE_TRUE)
{
contextHash = NULL_HASH;
}
}
}
if(audioHash)
{
ItemAudioSettings *audioSettings = audNorthAudioEngine::GetObject<ItemAudioSettings>(audioHash);
WeaponSettings * settings = NULL;
if(audioSettings)
{
if(contextHash != NULL_HASH)
{
for(int i=0; i < audioSettings->numContextSettings; i++)
{
if(audioSettings->ContextSettings[i].Context == contextHash)
{
settings = audNorthAudioEngine::GetObject<WeaponSettings>(audioSettings->ContextSettings[i].WeaponSettings);
break;
}
}
}
if(!settings && contextHash != playerHash && contextHash != NULL_HASH)
{
for(int i=0; i < audioSettings->numContextSettings; i++)
{
if(audioSettings->ContextSettings[i].Context == playerHash)
{
settings = audNorthAudioEngine::GetObject<WeaponSettings>(audioSettings->ContextSettings[i].WeaponSettings);
break;
}
}
}
if(!settings)
{
settings = audNorthAudioEngine::GetObject<WeaponSettings>(audioSettings->WeaponSettings);
}
#if __BANK
else if(contextHash == playerHash && settings->BankSound != g_NullSoundHash)
{
if(!sm_PlayerEquippedWeaponSlot.waveSlot)
{
naErrorf("Using player weapon settings %s but there is no equipped weapon waveslot", audNorthAudioEngine::GetMetadataManager().GetObjectNameFromNameTableOffset(settings->NameTableOffset));
}
else if(!sm_PlayerEquippedWeaponSlot.waveSlot->waveSlot)
{
naErrorf("Using player weapon settings %s but equipped weapon waveslot doesn't have a slot set on it", audNorthAudioEngine::GetMetadataManager().GetObjectNameFromNameTableOffset(settings->NameTableOffset));
}
else if(!sm_PlayerEquippedWeaponSlot.waveSlot->IsLoaded())
{
naErrorf("Using player weapon settings %s but waveslot (%s) isn't loaded", audNorthAudioEngine::GetMetadataManager().GetObjectNameFromNameTableOffset(settings->NameTableOffset), sm_PlayerEquippedWeaponSlot.waveSlot->waveSlot->GetLoadedBankName());
}
else if(g_DebugPlayerWeaponSlots)
{
naErrorf("Using player weapon settings %s with waveslot %s (secondary slot: %s) ", audNorthAudioEngine::GetMetadataManager().GetObjectNameFromNameTableOffset(settings->NameTableOffset), sm_PlayerEquippedWeaponSlot.waveSlot->waveSlot->GetLoadedBankName(), sm_PlayerNextWeaponSlot.waveSlot && sm_PlayerNextWeaponSlot.waveSlot->waveSlot ? sm_PlayerNextWeaponSlot.waveSlot->waveSlot->GetLoadedBankName() : "None");
}
}
#endif
}
return settings;
}
return NULL;
}
WeaponSettings * audWeaponAudioEntity::GetWeaponSettings(audMetadataRef settingsRef, u32 contextHash)
{
static u32 playerHash = ATSTRINGHASH("player", 0x6f0783f5);
WeaponSettings * settings = NULL;
if(contextHash == playerHash)
{
if(audNorthAudioEngine::GetMicrophones().IsCinematicMicActive())
{
contextHash = NULL_HASH;
}
else
{
MicrophoneSettings * mic = audNorthAudioEngine::GetMicrophones().GetMicrophoneSettings();
if(mic && AUD_GET_TRISTATE_VALUE(mic->Flags, FLAG_ID_MICROPHONESETTINGS_DISTANTPLAYERWEAPONS) == AUD_TRISTATE_TRUE)
{
contextHash = NULL_HASH;
}
#if GTA_REPLAY
if(CReplayMgr::IsPlaying() && camInterface::GetReplayDirector().IsFreeCamActive())
{
contextHash = NULL_HASH;
}
#endif
}
}
const ItemAudioSettings * audioSettings = audNorthAudioEngine::GetMetadataManager().GetObject<ItemAudioSettings>(settingsRef);
if(audioSettings)
{
if(contextHash != NULL_HASH)
{
for(int i=0; i < audioSettings->numContextSettings; i++)
{
if(audioSettings->ContextSettings[i].Context == contextHash)
{
settings = audNorthAudioEngine::GetObject<WeaponSettings>(audioSettings->ContextSettings[i].WeaponSettings);
break;
}
}
}
if(!settings && contextHash != playerHash && contextHash != NULL_HASH)
{
for(int i=0; i < audioSettings->numContextSettings; i++)
{
if(audioSettings->ContextSettings[i].Context == playerHash)
{
settings = audNorthAudioEngine::GetObject<WeaponSettings>(audioSettings->ContextSettings[i].WeaponSettings);
break;
}
}
}
if(!settings)
{
settings = audNorthAudioEngine::GetObject<WeaponSettings>(audioSettings->WeaponSettings);
}
}
return settings;
}
void audWeaponAudioComponent::SetLastImpactTime()
{
m_LastImpactTime = fwTimer::GetTimeInMilliseconds();
}
#if __DEV
void audWeaponAudioEntity::DebugDraw()
{
if (PARAM_rdrreportaudio.Get())
{
if(g_ShouldDrawReportGoodness)
{
for(int i=0; i<4; ++i)
{
u8 uMaxIndex = (u8)sm_ReportGoodness.size();
u8 uIndex1=(i*2)%uMaxIndex;
u8 uIndex2=(uIndex1+1)%uMaxIndex;
u8 uIndex3=(uIndex1+2)%uMaxIndex;
Vec3V vOffset = RCC_VEC3V(sm_RelativeScanPositions[uIndex2*3]);
vOffset *= ScalarV(V_TEN);
Vec3V vPos = g_AudioEngine.GetEnvironment().GetPanningListenerPosition() + vOffset;
vPos.SetZ(VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetPanningListenerPosition()).GetZ());
f32 fGoodness = sm_ReportGoodness[uIndex1] + sm_ReportGoodness[uIndex2] + sm_ReportGoodness[uIndex3];
fGoodness /= 3.0f;
Vec3V vMinPos(vPos);
Vec3V vMaxPos(vPos);
Vec3V offset(ScalarVFromF32(0.25f + (0.25f * fGoodness)));
vMinPos -= offset;
vMaxPos += offset;
Color32 col(1.0f, 1.0f-fGoodness, fGoodness);
grcDebugDraw::BoxAxisAligned(vMinPos, vMaxPos, col);
}
}
}
if(g_DebugPlayerWeaponSlots)
{
char tempString[256];
audPlayerWeaponSlot * indexSlot = &sm_PlayerEquippedWeaponSlot;
if(indexSlot)
{
const char * audioName = audNorthAudioEngine::GetMetadataManager().GetObjectName(indexSlot->audioHash);
if(!audioName)
{
audioName = "NO_NAME";
}
audDynamicWaveSlot * dynSlot = indexSlot->waveSlot;
audWaveSlot * waveSlot = dynSlot?dynSlot->waveSlot:NULL;
formatf(tempString, "Equipped Slot, waveSlot %p (waveslot %p, state %d), context %u, audioName %s loaded bank id %d, loaded bank name %s", dynSlot, waveSlot, waveSlot?waveSlot->GetBankLoadingStatus(waveSlot->GetLoadedBankId()):-1,
indexSlot->contextHash, audioName, waveSlot?waveSlot->GetLoadedBankId():-1, waveSlot?waveSlot->GetLoadedBankName():"");
grcDebugDraw::Text(Vector2(0.05f, 0.05f), Color32(0,0,255), tempString );
}
indexSlot = &sm_ScriptWeaponSlot;
if(indexSlot)
{
const char * audioName = audNorthAudioEngine::GetMetadataManager().GetObjectName(indexSlot->audioHash);
if(!audioName)
{
audioName = "NO_NAME";
}
audDynamicWaveSlot * dynSlot = indexSlot->waveSlot;
audWaveSlot * waveSlot = dynSlot?dynSlot->waveSlot:NULL;
formatf(tempString, "Script Slot, waveSlot %p (waveslot %p, state %d), context %u, audioName %s, loaded bank id %d, loaded bank name %s"
, dynSlot, waveSlot, waveSlot?waveSlot->GetBankLoadingStatus(waveSlot->GetLoadedBankId()):-1,
indexSlot->contextHash, audioName, waveSlot?waveSlot->GetLoadedBankId():-1, waveSlot?waveSlot->GetLoadedBankName():"");
grcDebugDraw::Text(Vector2(0.05f, 0.05f+0.05f), Color32(0,0,255), tempString );
}
indexSlot = &sm_PlayerNextWeaponSlot;
if(indexSlot)
{
const char * audioName = audNorthAudioEngine::GetMetadataManager().GetObjectName(indexSlot->audioHash);
if(!audioName)
{
audioName = "NO_NAME";
}
audDynamicWaveSlot * dynSlot = indexSlot->waveSlot;
audWaveSlot * waveSlot = dynSlot?dynSlot->waveSlot:NULL;
formatf(tempString, "Next Slot, waveSlot %p (waveslot %p, state %d), context %u, audioName %s, loaded bank id %d, loaded bank name %s",
dynSlot, waveSlot, waveSlot?waveSlot->GetBankLoadingStatus(waveSlot->GetLoadedBankId()):-1,
indexSlot->contextHash, audioName, waveSlot?waveSlot->GetLoadedBankId():-1, waveSlot?waveSlot->GetLoadedBankName():"");
grcDebugDraw::Text(Vector2(0.05f, 0.05f+0.1f), Color32(0,0,255), tempString );
}
}
}
#endif
#if __BANK
extern u32 g_UnderwaterExplosionFilterCutoff;
extern float g_RotaryTurretAudioSpinSpeed;
void audWeaponAudioEntity::AddWidgets(bkBank &bank)
{
bank.PushGroup("Weapons",false);
bank.AddSlider("Min Auto Echo Loop Count", &g_MinAutoEchoLoopCount, 0, 10, 1);
bank.AddSlider("Min Auto Echo Loop Ignore Time", &g_MinAutoEchoLoopCountIgnoreTime, 0, 1000, 10);
bank.AddSlider("Veh rotary gun spin spd", &g_RotaryTurretAudioSpinSpeed, 0.f, 10.f, 0.1f);
bank.AddSlider("Automatic fire timeout", &s_AutoFireReleaseTime, 0, 10000, 10);
bank.AddToggle("g_AuditionWeaponFire", &g_AuditionWeaponFire);
bank.AddSlider("Max weapon fires played per frame", &g_MaxWeaponFiresPlayedPerFrame, 0, g_MaxWeaponFireEventsPerFrame, 1);
bank.AddSlider("Echo volume drop", &g_EchoVolumeDrop, -24.0f, 24.0f, 0.1f);
bank.AddSlider("g_EchoDepth", &g_EchoDepth, 0, 5, 1);
bank.AddToggle("g_PositionReportOppositeEcho", &g_PositionReportOppositeEcho);
bank.AddToggle("g_PlayBothEchos", &g_PlayBothEchos);
bank.AddToggle("Override Weapon Echo Settings", &g_bForceWeaponEchoSettings);
bank.AddSlider("Weapon Echo Attenuation", &g_fWeaponEchoAttenuation, -24.0f, 6.0f, 0.1f);
bank.AddSlider("Weapon Echo Predelay", &g_uWeaponEchoPredelay, 40, 3000, 1);
bank.AddToggle("g_DisableTightSpotInteriorGuns", &g_DisableTightSpotInteriorGuns);
bank.AddSlider("UnderwaterExplosionCutoff", &g_UnderwaterExplosionFilterCutoff, 100, kVoiceFilterLPFMaxCutoff, 1);
bank.AddSlider("g_BulletBySphereRadius", &g_BulletBySphereRadius, 0.0f, 10.0f, 0.1f);
bank.AddSlider("g_BulletByMinTimeMs", &g_BulletByMinTimeMs, 0, 5000, 10);
bank.AddSlider("g_BulletByMaxTimeMs", &g_BulletByMaxTimeMs, 0, 5000, 10);
bank.AddSlider("g_ExplosionBulletByDistance", &g_ExplosionBulletByDistance, 0.0f, 50.0f, 0.1f);
bank.AddSlider("g_ExplosionBulletByPredelay", &g_ExplosionBulletByPredelay, 0, 1000, 1);
bank.AddSlider("g_DefaultGunPostSubmixAttenuation", &g_DefaultGunPostSubmixAttenuation, -20.0f, 0.0f, 0.1f);
bank.AddSlider("g_DuckingAttenuationPerShot", &g_DuckingAttenuationPerShot, -1.0f, 0.0f, 0.01f);
bank.AddSlider("g_NotFiredForAWhileTime", &g_NotFiredForAWhileTime, 0, 30000, 1);
bank.AddSlider("g_BeenFiringForAWhileTime", &g_BeenFiringForAWhileTime, 0, 30000, 1);
bank.AddToggle("g_PlayerGunAlwaysDamped", &g_PlayerGunAlwaysDamped);
bank.AddToggle("g_PlayerGunNeverDamped", &g_PlayerGunNeverDamped);
bank.AddToggle("g_PlayerUsesNpcWeapons", &g_PlayerUsesNpcWeapons);
bank.AddSlider("g_TimeSinceSomeoneNearbyFiredToReduceFactor", &g_TimeSinceSomeoneNearbyFiredToReduceFactor, 0, 10000, 1);
bank.AddSlider("g_GunFiredFactorIncrease", &g_GunFiredFactorIncrease, 0.0f, 1.0f, 0.01f);
bank.AddSlider("g_GunNotFiredFactorDecrease", &g_GunNotFiredFactorDecrease, -1.0f, 0.0f, 0.001f);
bank.AddSlider("g_MaxDistanceToCountTowardFactor", &g_MaxDistanceToCountTowardFactor, 0.0f, 100.0f, 1.0f);
bank.AddToggle("Debug Weapon Timings", &g_DebugWeaponTimings);
bank.AddToggle("Debug PlayerWeapon Slots", &g_DebugPlayerWeaponSlots);
bank.AddSlider("Force wait for equipped weapon (seconds)", &g_ForceWaitForPlayerEquippedWeapon, 0.f, 100.f, 1.f);
bank.AddSlider("Empty weapon shot timing", &sm_EmptyShotFilter, 0, 5000, 10);
bank.PushGroup("Interiors");
bank.AddToggle("Force use interior metrics", &g_ForceUseInteriorMetrics);
bank.AddToggle("Debug Interior Metrics", &g_DebugInteriorMetrics);
bank.AddSlider("Debug Interior Wetness", &g_DebugInteriorWetness, 0.f, 1.f, 0.05f);
bank.AddSlider("Debug Outside Visibility", &g_DebugOutsideVisability, 0.f, 1.f, 0.05f);
bank.AddSlider("Debug Interior LPF", &g_DebugInteriorLpf, 0, 24000, 100);
bank.AddSlider("Debug Interior Predelay", &g_DebugInteriorPredelay, 0, 1000, 10);
bank.AddSlider("Debug Interior Hold variable", &g_DebugInteriorHold, 0.f, 1.f, 0.01f);
bank.AddSlider("Interior silenced Weapon Wetness", &sm_InteriorSilencedWeaponWetness, 0.f, 1.f, 0.05f);
bank.AddSlider("Interior transition time", &g_InteriorTransitionTime, 0.01f, 5.f, 0.01f);
bank.PopGroup();
bank.PushGroup("Water cannon");
bank.AddToggle("sm_Smooth", &sm_Smooth);
bank.AddSlider("sm_TimeToMuteWaterCannonOnVeh (ms)", &sm_TimeToMuteWaterCannon, 0.f, 10000.f, 0.05f);
bank.PopGroup();
bank.AddSlider("NpcReportIntensity", &sm_NpcReportIntensity, 0.f, 100.f, 1.f);
bank.AddSlider("NpcReportIntensitydecreaseRate", &sm_NpcReportIntensityDecreaseRate, 0.f, 10.f, 0.1f);
bank.AddSlider("NpcReportCullingDistanceSq", &sm_NpcReportCullingDistanceSq, 0.f, 10000.f, 1.f);
bank.AddSlider("NpcReportIntensityForDistanceCulling", &sm_IntensityForNpcReportDistanceCulling, 0.f, 100.f, 1.f);
bank.AddSlider("NpcReportIntensityForFullCulling", &sm_IntensityForNpcReportFullCulling, 0.f, 100.f, 1.f);
bank.AddSlider("PlayerHitBoostVol", &sm_PlayerHitBoostVol, 0.f, 24.f, 1.f);
bank.AddSlider("PlayerHitBoostRolloff", &sm_PlayerHitBoostRolloff, 1.f, 10.f, 0.1f);
bank.AddSlider("PlayerHitHoldTime", &sm_PlayerHitBoostHoldTime, 0, 10000, 100);
bank.AddSlider("PlayerHitReleaseTime", &sm_PlayerhitBoostSmoothTime, 0.01f, 10.f, 0.1f);
bank.AddToggle("Skip minigun intro", &sm_SkipMinigunSpinUp);
bank.AddSlider("Anim time filter", &sm_WeaponAnimTimeFilter, 0, 1000, 10);
bank.AddSlider("Auto Empty shot time filter", &sm_AutoEmptyShotTimeFilter, 0, 1000, 10);
bank.PopGroup();
if (PARAM_rdrreportaudio.Get())
{
bank.PushGroup("Report Goodness",false);
bank.AddToggle("Draw Report Goodness", &g_ShouldDrawReportGoodness);
bank.AddSlider("ReportGoodness0", &sm_ReportGoodness[0], 0.0f, 1.0f, 0.1f);
bank.AddSlider("ReportGoodness1", &sm_ReportGoodness[1], 0.0f, 1.0f, 0.1f);
bank.AddSlider("ReportGoodness2", &sm_ReportGoodness[2], 0.0f, 1.0f, 0.1f);
bank.AddSlider("ReportGoodness3", &sm_ReportGoodness[3], 0.0f, 1.0f, 0.1f);
bank.AddSlider("ReportGoodness4", &sm_ReportGoodness[4], 0.0f, 1.0f, 0.1f);
bank.AddSlider("ReportGoodness5", &sm_ReportGoodness[5], 0.0f, 1.0f, 0.1f);
bank.AddSlider("ReportGoodness6", &sm_ReportGoodness[6], 0.0f, 1.0f, 0.1f);
bank.AddSlider("ReportGoodness7", &sm_ReportGoodness[7], 0.0f, 1.0f, 0.1f);
bank.AddSlider("MaxDistForEnemyReport", &g_MaxDistanceForEnemyReport, 0.0f, 100.0f, 1.0f);
bank.PopGroup();
}
}
#endif