diff --git a/source/Base.h b/source/Base.h index fc3f70d885..4a15d17275 100644 --- a/source/Base.h +++ b/source/Base.h @@ -153,6 +153,27 @@ T& StaticRef(uintptr addr) { return *reinterpret_cast(addr); } +/*! + * @brief Use for scoped static variables (That is, static variables that are initialized in functions) + * @brief See `CAEGlobalWeaponAudioEntity::ServiceAmbientGunFire` for examples) + * @tparam T The type of the var + * @param varAddr + * @param flagsAddr + * @param flagsMask + * @param initVal + * @return + */ +template +T& ScopedStaticRef(uintptr varAddr, uintptr flagsAddr, uint32 flagsMask, T&& initVal) { + auto& var = StaticRef(varAddr); + auto& flags = StaticRef(flagsAddr); + if (!(flags & flagsMask)) { + flags |= flagsMask; + var = initVal; + } + return var; +} + // TODO: Replace this with the one above template T& StaticRef() { diff --git a/source/extensions/utility.hpp b/source/extensions/utility.hpp index e7521f5fa7..23539e9278 100644 --- a/source/extensions/utility.hpp +++ b/source/extensions/utility.hpp @@ -184,9 +184,14 @@ constexpr auto IsFixBugs() { } /// Predicate to check if `value` is null -template - requires(std::is_pointer_v) -bool IsNull(T value) { return value == nullptr; } +struct IsNull { + template + requires(std::is_pointer_v) + bool operator()(T ptr) { return ptr == nullptr; } +}; +//template +// requires(std::is_pointer_v) +//bool IsNull(T value) { return value == nullptr; } /// Negate another predicate function template diff --git a/source/game_sa/Audio/AEAudioEnvironment.cpp b/source/game_sa/Audio/AEAudioEnvironment.cpp index 4bf03900b5..cf419c5545 100644 --- a/source/game_sa/Audio/AEAudioEnvironment.cpp +++ b/source/game_sa/Audio/AEAudioEnvironment.cpp @@ -2,7 +2,8 @@ #include "AEAudioEnvironment.h" sReverbEnvironment (&gAudioZoneToReverbEnvironmentMap)[NUM_AUDIO_ENVIRONMENTS] = *(sReverbEnvironment(*)[NUM_AUDIO_ENVIRONMENTS])0x8AD670; -float (&gSoundDistAttenuationTable)[NUM_SOUND_DIST_ATTENUATION_ENTRIES] = *(float(*)[NUM_SOUND_DIST_ATTENUATION_ENTRIES])0x8AC270; + +#include "data/SoundAttenuationTable.h" void CAEAudioEnvironment::InjectHooks() { RH_ScopedClass(CAEAudioEnvironment); @@ -17,29 +18,30 @@ void CAEAudioEnvironment::InjectHooks() { } // 0x4D7E40 -float CAEAudioEnvironment::GetDopplerRelativeFrequency(float prevDist, float curDist, uint32 prevTime, uint32 curTime, float timeScale) { - const auto fDistDiff = curDist - prevDist; - if (TheCamera.Get_Just_Switched_Status()) +float CAEAudioEnvironment::GetDopplerRelativeFrequency(float prevDist, float curDist, uint32 prevTime, uint32 curTime, float dopplerScale) { + if (TheCamera.Get_Just_Switched_Status()) { return 1.0F; + } - if (timeScale == 0.0F || fDistDiff == 0.0F || curTime <= prevTime) + const auto deltaDist = curDist - prevDist; + if (dopplerScale == 0.0F || deltaDist == 0.0F || curTime <= prevTime) { return 1.0F; + } - const auto fDoppler = fDistDiff * 1000.0F / static_cast(curTime - prevTime) * timeScale; - if (std::fabs(fDoppler) >= 340.0F) + const auto doppler = deltaDist * 1000.0F / (float)(curTime - prevTime) * dopplerScale; + if (std::fabs(doppler) >= 340.0F) { return 1.0F; + } - const auto fClamped = std::clamp(fDoppler, -35.0F, 35.0F); - return 340.0F / (fClamped + 340.0F); + return 340.0F / (std::clamp(doppler, -35.0F, 35.0F) + 340.0F); } // 0x4D7F20 float CAEAudioEnvironment::GetDistanceAttenuation(float dist) { - if (dist >= 128.0F) - return -100.0F; - - auto iArrIndex = static_cast(std::floor(dist * 10.0F)); - return gSoundDistAttenuationTable[iArrIndex]; + assert(dist >= 0.f); + return dist < ATTENUATION_TABLE_MAX_DIST + ? gSoundDistAttenuationTable[(uint32)std::floor(dist / ATTENUATION_TABLE_RESOLUTION)] + : -100.f; } // 0x4D7F60 diff --git a/source/game_sa/Audio/AEAudioEnvironment.h b/source/game_sa/Audio/AEAudioEnvironment.h index 9dbef84d59..5753648a44 100644 --- a/source/game_sa/Audio/AEAudioEnvironment.h +++ b/source/game_sa/Audio/AEAudioEnvironment.h @@ -13,7 +13,7 @@ class CAEAudioEnvironment { public: static void InjectHooks(); - static float GetDopplerRelativeFrequency(float prevDist, float curDist, uint32 prevTime, uint32 curTime, float timeScale); + static float GetDopplerRelativeFrequency(float prevDist, float curDist, uint32 prevTime, uint32 curTime, float dopplerScale); static float GetDistanceAttenuation(float dist); static float GetDirectionalMikeAttenuation(const CVector& soundDir); static void GetReverbEnvironmentAndDepth(int8* reverbEnv, int32* depth); @@ -23,6 +23,3 @@ class CAEAudioEnvironment { static constexpr int32 NUM_AUDIO_ENVIRONMENTS = 68; extern sReverbEnvironment (&gAudioZoneToReverbEnvironmentMap)[NUM_AUDIO_ENVIRONMENTS]; - -static constexpr int32 NUM_SOUND_DIST_ATTENUATION_ENTRIES = 1280; -extern float (&gSoundDistAttenuationTable)[NUM_SOUND_DIST_ATTENUATION_ENTRIES]; diff --git a/source/game_sa/Audio/AEAudioUtility.cpp b/source/game_sa/Audio/AEAudioUtility.cpp index 57e4c696a9..467eca320f 100644 --- a/source/game_sa/Audio/AEAudioUtility.cpp +++ b/source/game_sa/Audio/AEAudioUtility.cpp @@ -4,7 +4,8 @@ #include "AEAudioUtility.h" -uint64& CAEAudioUtility::startTimeMs = *reinterpret_cast(0xb610f8); +auto& Frequency = StaticRef(0xB610F0); +uint64& startTimeMs = *reinterpret_cast(0xb610f8); float (&CAEAudioUtility::m_sfLogLookup)[50][2] = *reinterpret_cast(0xb61100); // NOTE: For me all values were 0... The below values should be the correct ones: @@ -84,16 +85,23 @@ float CAEAudioUtility::GetPiecewiseLinear(float x, int16 dataCount, float (*data // 0x4d9e50 float CAEAudioUtility::AudioLog10(float p) { - return 0.00001f <= p ? std::log10f(p) : -5.0f; + return p >= 0.00001f + ? std::log10f(p) + : -5.0f; } // REFACTORED // 0x4d9e80 uint64 CAEAudioUtility::GetCurrentTimeInMS() { using namespace std::chrono; - auto nowMs = time_point_cast(high_resolution_clock::now()); - auto value = duration_cast(nowMs.time_since_epoch()); - return static_cast(value.count()); + const auto nowMs = time_point_cast(high_resolution_clock::now()); + const auto value = duration_cast(nowMs.time_since_epoch()); + return static_cast(value.count()) - startTimeMs; + + //For some reason this doesn't work (original code): + //LARGE_INTEGER counter; + //QueryPerformanceCounter(&counter); + //return counter.QuadPart / Frequency.QuadPart * 1000 - startTimeMs; } // 0x4d9ef0 @@ -122,6 +130,7 @@ void CAEAudioUtility::StaticInitialise() { m_sfLogLookup[1][1] = log10f(v); } + VERIFY(QueryPerformanceFrequency(&Frequency)); startTimeMs = GetCurrentTimeInMS(); } diff --git a/source/game_sa/Audio/AEAudioUtility.h b/source/game_sa/Audio/AEAudioUtility.h index 60b6cde89e..9ba91dc9a7 100644 --- a/source/game_sa/Audio/AEAudioUtility.h +++ b/source/game_sa/Audio/AEAudioUtility.h @@ -40,7 +40,6 @@ class CAEAudioUtility { } private: - static uint64& startTimeMs; static float (&m_sfLogLookup)[50][2]; private: diff --git a/source/game_sa/Audio/AESound.cpp b/source/game_sa/Audio/AESound.cpp index 449fc6003d..b47c4d26a4 100644 --- a/source/game_sa/Audio/AESound.cpp +++ b/source/game_sa/Audio/AESound.cpp @@ -42,7 +42,7 @@ CAESound::CAESound(CAESound& sound) { m_nSoundIdInSlot = sound.m_nSoundIdInSlot; m_pBaseAudio = sound.m_pBaseAudio; m_nEvent = sound.m_nEvent; - m_fMaxVolume = sound.m_fMaxVolume; + m_ClientVariable = sound.m_ClientVariable; m_fVolume = sound.m_fVolume; m_fSoundDistance = sound.m_fSoundDistance; m_fSpeed = sound.m_fSpeed; @@ -80,7 +80,7 @@ CAESound::CAESound(int16 bankSlotId, int16 sfxId, CAEAudioEntity* baseAudio, CVe m_pBaseAudio = baseAudio; m_vecPrevPosn = CVector(0.0f, 0.0f, 0.0f); m_pPhysicalEntity = nullptr; - m_fMaxVolume = -1.0F; + m_ClientVariable = -1.0F; m_nEvent = AE_UNDEFINED; m_nLastFrameUpdate = 0; @@ -116,7 +116,7 @@ CAESound& CAESound::operator=(const CAESound& sound) { m_nSoundIdInSlot = sound.m_nSoundIdInSlot; m_pBaseAudio = sound.m_pBaseAudio; m_nEvent = sound.m_nEvent; - m_fMaxVolume = sound.m_fMaxVolume; + m_ClientVariable = sound.m_ClientVariable; m_fVolume = sound.m_fVolume; m_fSoundDistance = sound.m_fSoundDistance; m_fSpeed = sound.m_fSpeed; @@ -295,34 +295,35 @@ void CAESound::CalculateVolume() { } // 0x4EFE50 -void CAESound::Initialise(int16 bankSlotId, int16 sfxId, CAEAudioEntity* baseAudio, CVector posn, float volume, float maxDistance, float speed, float timeScale, - uint8 ignoredServiceCycles, eSoundEnvironment environmentFlags, float speedVariability, int16 currPlayPosn) +void CAESound::Initialise( + int16 bankSlotId, int16 soundID, CAEAudioEntity* audioEntity, CVector pos, float volume, float rollOffFactor, float relativeFrequency, float doppler, + uint8 frameDelay, uint32 flags, float frequencyVariance, int16 playTime) { UnregisterWithPhysicalEntity(); - m_nSoundIdInSlot = sfxId; + m_nSoundIdInSlot = soundID; m_nBankSlotId = bankSlotId; - m_pBaseAudio = baseAudio; + m_pBaseAudio = audioEntity; m_fVolume = volume; - m_fSoundDistance = maxDistance; - m_fSpeed = speed; - m_fSpeedVariability = speedVariability; + m_fSoundDistance = rollOffFactor; + m_fSpeed = relativeFrequency; + m_fSpeedVariability = frequencyVariance; m_vecPrevPosn .Set(0.0F, 0.0F, 0.0F); m_nEvent = AE_UNDEFINED; - m_fMaxVolume = -1.0F; + m_ClientVariable = -1.0F; m_nLastFrameUpdate = 0; - SetPosition(posn); + SetPosition(pos); - m_fTimeScale = timeScale; + m_fTimeScale = doppler; m_nSoundLength = -1; m_nHasStarted = 0; m_nPlayingState = eSoundState::SOUND_ACTIVE; m_fSoundHeadRoom = 0.0F; - m_nIgnoredServiceCycles = ignoredServiceCycles; - m_nEnvironmentFlags = environmentFlags; + m_nIgnoredServiceCycles = frameDelay; + m_nEnvironmentFlags = flags; m_nIsUsed = 1; - m_nCurrentPlayPosition = currPlayPosn; + m_nCurrentPlayPosition = playTime; m_fFinalVolume = -100.0F; m_fFrequency = 1.0F; } diff --git a/source/game_sa/Audio/AESound.h b/source/game_sa/Audio/AESound.h index d6f5170f98..e2cb879655 100644 --- a/source/game_sa/Audio/AESound.h +++ b/source/game_sa/Audio/AESound.h @@ -11,6 +11,8 @@ class CAEAudioEntity; class CEntity; +using tSoundID = int16; + enum eSoundEnvironment : uint16 { SOUND_DEFAULT = 0x0, SOUND_FRONT_END = 0x1, @@ -39,8 +41,8 @@ class CAESound { int16 m_nSoundIdInSlot; CAEAudioEntity* m_pBaseAudio; CEntity* m_pPhysicalEntity; - eAudioEvents m_nEvent; - float m_fMaxVolume; + int32 m_nEvent; // Not necessarily `eAudioEvents`, for ex. see `CAEWeaponAudioEntity` + float m_ClientVariable; float m_fVolume; float m_fSoundDistance; float m_fSpeed; @@ -98,14 +100,20 @@ class CAESound { CAESound& operator=(const CAESound& sound); - void Initialise(int16 bankSlotId, int16 sfxId, CAEAudioEntity* baseAudio, CVector posn, float volume, - float maxDistance = 1.0f, - float speed = 1.0f, - float timeScale = 1.0f, - uint8 ignoredServiceCycles = 0, - eSoundEnvironment environmentFlags = static_cast(0), - float speedVariability = 0, - int16 currPlayPosn = 0); + void Initialise( + int16 bankSlotId, + int16 soundID, + CAEAudioEntity* audioEntity, + CVector pos, + float volume, + float rollOffFactor = 1.f, + float relativeFrequency = 1.f, // Speed + float doppler = 1.f, + uint8 frameDelay = 0, + uint32 flags = 0, + float frequencyVariance = 0.f, + int16 playTime = 0 + ); void UnregisterWithPhysicalEntity(); void StopSound(); diff --git a/source/game_sa/Audio/AudioEngine.cpp b/source/game_sa/Audio/AudioEngine.cpp index 9c2f0966b7..bb020c672e 100644 --- a/source/game_sa/Audio/AudioEngine.cpp +++ b/source/game_sa/Audio/AudioEngine.cpp @@ -105,6 +105,9 @@ void CAudioEngine::InjectHooks() { bool CAudioEngine::Initialise() { CLoadingScreen::Pause(); + // NOTSA: Initialize AudioUtility before `AEAudioHardware` to avoid crash (Division by zero in `GetCurrentTimeInMS`) + CAEAudioUtility::StaticInitialise(); + if (!AEAudioHardware.Initialise()) { NOTSA_LOG_ERR("Failed to initialise Audio Hardware"); return false; @@ -138,7 +141,7 @@ bool CAudioEngine::Initialise() { m_FrontendAE.Initialise(); CAudioEngine::SetEffectsFaderScalingFactor(0.0f); - CAEAudioUtility::StaticInitialise(); + //CAEAudioUtility::StaticInitialise(); // Initialized above CAEPedAudioEntity::StaticInitialise(); CAEPedSpeechAudioEntity::StaticInitialise(); CAEVehicleAudioEntity::StaticInitialise(); diff --git a/source/game_sa/Audio/Enums/SoundIDs.h b/source/game_sa/Audio/Enums/SoundIDs.h new file mode 100644 index 0000000000..ef9884d37b --- /dev/null +++ b/source/game_sa/Audio/Enums/SoundIDs.h @@ -0,0 +1,96 @@ +#pragma once + +using tSoundID = int16; + +enum eGenrlWeaponSoundID : tSoundID { // GENRL_WEAPONS + SND_GENRL_WEAPONS_UNK = -1, + SND_GENRL_WEAPONS_9MM1SHOT_L = 0x0, + SND_GENRL_WEAPONS_9MM1SHOT_R = 0x1, + SND_GENRL_WEAPONS_9MM1TAIL = 0x2, + SND_GENRL_WEAPONS_AK_SHOT_L = 0x3, + SND_GENRL_WEAPONS_AK_SHOT_R = 0x4, + SND_GENRL_WEAPONS_AK_TAIL_L = 0x5, + SND_GENRL_WEAPONS_EAGLE_SHOT_L = 0x6, + SND_GENRL_WEAPONS_EAGLE_SHOT_R = 0x7, + SND_GENRL_WEAPONS_EAGLE_TAIL_L = 0x8, + SND_GENRL_WEAPONS_FIRE_EXT = 0x9, + SND_GENRL_WEAPONS_GAS_LOOP = 0xA, + SND_GENRL_WEAPONS_MINIGUN_SHOT_L = 0xB, + SND_GENRL_WEAPONS_MINIGUN_SHOT_R = 0xC, + SND_GENRL_WEAPONS_MINIGUN_TAIL = 0xD, + SND_GENRL_WEAPONS_MINIGUNEMPTY = 0xE, + SND_GENRL_WEAPONS_MINIGUNHIGHS = 0xF, + SND_GENRL_WEAPONS_MINIGUNLOWS = 0x10, + SND_GENRL_WEAPONS_MP5SHOT_L = 0x11, + SND_GENRL_WEAPONS_MP5SHOT_R = 0x12, + SND_GENRL_WEAPONS_PARACHUTE_WIND_LOOP_A = 0x13, + SND_GENRL_WEAPONS_PARACHUTE_WIND_LOOP_B = 0x14, + SND_GENRL_WEAPONS_SHOTGUN_SHOT_L = 0x15, + SND_GENRL_WEAPONS_SHOTGUN_SHOT_R = 0x16, + SND_GENRL_WEAPONS_SHOTGUN_TAIL_R = 0x17, + SND_GENRL_WEAPONS_SILENCED_SHOT_L = 0x18, + SND_GENRL_WEAPONS_SILENCED_SHOT_R = 0x19, + SND_GENRL_WEAPONS_SNIPER_SHOT_L = 0x1A, + SND_GENRL_WEAPONS_SNIPER_SHOT_R = 0x1B, + SND_GENRL_WEAPONS_SPRAY_PAINT = 0x1C, + SND_GENRL_WEAPONS_9MM1DRY = 0x1D, + SND_GENRL_WEAPONS_9MM1LOWS = 0x1E, + SND_GENRL_WEAPONS_AK_A = 0x1F, + SND_GENRL_WEAPONS_AK_B = 0x20, + SND_GENRL_WEAPONS_AK_DRYFIRE = 0x21, + SND_GENRL_WEAPONS_BASEBALL_BAT = 0x22, + SND_GENRL_WEAPONS_BAT_STRIKE = 0x23, + SND_GENRL_WEAPONS_BODY_PUNCH1 = 0x24, + SND_GENRL_WEAPONS_BODY_PUNCH2 = 0x25, + SND_GENRL_WEAPONS_BODY_PUNCH3 = 0x26, + SND_GENRL_WEAPONS_BODY_PUNCH4 = 0x27, + SND_GENRL_WEAPONS_BOX_FACE1 = 0x28, + SND_GENRL_WEAPONS_BOX_FACE2 = 0x29, + SND_GENRL_WEAPONS_BOX_FACE3 = 0x2A, + SND_GENRL_WEAPONS_BOX_FACE4 = 0x2B, + SND_GENRL_WEAPONS_BRASS_KNUCKLES = 0x2C, + SND_GENRL_WEAPONS_CAMERA = 0x2D, + SND_GENRL_WEAPONS_CANE_STRIKE = 0x2E, + SND_GENRL_WEAPONS_CANE_SWISH = 0x2F, + SND_GENRL_WEAPONS_CLUB_STRIKE = 0x30, + SND_GENRL_WEAPONS_DETONATOR_BEEP = 0x31, + SND_GENRL_WEAPONS_DILDO = 0x32, + SND_GENRL_WEAPONS_EAGLE_B = 0x33, + SND_GENRL_WEAPONS_EAGLE_DRYFIRE = 0x34, + SND_GENRL_WEAPONS_EAGLE_LOWS = 0x35, + SND_GENRL_WEAPONS_FLOWER_STRIKE = 0x36, + SND_GENRL_WEAPONS_HANDGUN_A = 0x37, + SND_GENRL_WEAPONS_KATANA_SWORD = 0x38, + SND_GENRL_WEAPONS_KNIFE = 0x39, + SND_GENRL_WEAPONS_KNUCKLE = 0x3A, + SND_GENRL_WEAPONS_MARTIAL_STRIKE1 = 0x3B, + SND_GENRL_WEAPONS_MARTIAL_STRIKE2 = 0x3C, + SND_GENRL_WEAPONS_MARTIAL_STRIKE3 = 0x3D, + SND_GENRL_WEAPONS_MARTIAL_STRIKE4 = 0x3E, + SND_GENRL_WEAPONS_MINIGUNOFF = 0x3F, + SND_GENRL_WEAPONS_NIGHT_VISION = 0x40, + SND_GENRL_WEAPONS_PARACHUTE_OPEN = 0x41, + SND_GENRL_WEAPONS_PISTOL_B = 0x42, + SND_GENRL_WEAPONS_POOLCUE = 0x43, + SND_GENRL_WEAPONS_ROCKET_LAUNCH = 0x44, + SND_GENRL_WEAPONS_SAWNOFF_A = 0x45, + SND_GENRL_WEAPONS_SAWNOFF_B = 0x46, + SND_GENRL_WEAPONS_SHOTGUN_A = 0x47, + SND_GENRL_WEAPONS_SHOTGUN_B = 0x48, + SND_GENRL_WEAPONS_SHOTGUN_DRYFIRE = 0x49, + SND_GENRL_WEAPONS_SHOTGUN_LOWS = 0x4A, + SND_GENRL_WEAPONS_SHOVEL = 0x4B, + SND_GENRL_WEAPONS_SILENCED_DRYFIRE = 0x4C, + SND_GENRL_WEAPONS_SILENCED_LOWS = 0x4D, + SND_GENRL_WEAPONS_SMACK_1 = 0x4E, + SND_GENRL_WEAPONS_SMACK_2 = 0x4F, + SND_GENRL_WEAPONS_SMACK_3 = 0x50, + SND_GENRL_WEAPONS_STAB = 0x51, + SND_GENRL_WEAPONS_STOMP1 = 0x52, + SND_GENRL_WEAPONS_TRIGGER = 0x53, + SND_GENRL_WEAPONS_UZI_A = 0x54, + SND_GENRL_WEAPONS_UZI_B = 0x55, + SND_GENRL_WEAPONS_WEAPON_SWIPE = 0x56, + SND_GENRL_WEAPONS_WEAPON_SWIPE_FIST = 0x57, + SND_GENRL_WEAPONS_WEAPON_SWIPE_METAL = 0x58, +}; diff --git a/source/game_sa/Audio/data/SoundAttenuationTable.h b/source/game_sa/Audio/data/SoundAttenuationTable.h new file mode 100644 index 0000000000..76037e5a6d --- /dev/null +++ b/source/game_sa/Audio/data/SoundAttenuationTable.h @@ -0,0 +1,136 @@ +// +// NOTE: This header should only be included in .cpp files! +// + +constexpr auto ATTENUATION_TABLE_RESOLUTION = 0.1f; +constexpr auto ATTENUATION_TABLE_MAX_DIST = 128.f; +constexpr std::array gSoundDistAttenuationTable{ // 0x8AC270 + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, // 0-1 + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, // 1 + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, // 2 + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, // 3 + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, // 4 + -0.38f, -0.75999999f, -1.13f, -1.49f, -1.86f, -2.21f, -2.5599999f, -2.9100001f, -3.25f, -3.5799999f, // 5 + -3.9100001f, -4.2399998f, -4.5599999f, -4.8800001f, -5.1999998f, -5.5100002f, -5.8200002f, -6.1199999f, -6.4200001f, -6.7199998f, // 6 + -7.0100002f, -7.3000002f, -7.5900002f, -7.8699999f, -8.1499996f, -8.4300003f, -8.71f, -8.9799995f, -9.25f, -9.5100002f, // 7 + -9.7799997f, -10.04f, -10.3f, -10.55f, -10.81f, -11.06f, -11.31f, -11.55f, -11.8f, -12.04f, // 8 + -12.28f, -12.52f, -12.75f, -12.99f, -13.22f, -13.45f, -13.68f, -13.9f, -14.13f, -14.35f, // 9 + -14.57f, -14.79f, -15.01f, -15.22f, -15.44f, -15.65f, -15.86f, -16.07f, -16.27f, -16.48f, // 10 + -16.68f, -16.889999f, -17.09f, -17.290001f, -17.49f, -17.68f, -17.879999f, -18.07f, -18.27f, -18.459999f, // 11 + -18.65f, -18.84f, -19.02f, -19.209999f, -19.389999f, -19.58f, -19.76f, -19.940001f, -20.120001f, -20.299999f, // 12 + -20.48f, -20.66f, -20.83f, -21.01f, -21.18f, -21.360001f, -21.530001f, -21.700001f, -21.870001f, -22.040001f, // 13 + -22.200001f, -22.370001f, -22.540001f, -22.700001f, -22.860001f, -23.030001f, -23.190001f, -23.35f, -23.51f, -23.67f, // 14 + -23.83f, -23.99f, -24.139999f, -24.299999f, -24.450001f, -24.610001f, -24.76f, -24.91f, -25.07f, -25.219999f, // 15 + -25.370001f, -25.52f, -25.66f, -25.809999f, -25.959999f, -26.110001f, -26.25f, -26.4f, -26.540001f, -26.68f, // 16 + -26.83f, -26.969999f, -27.110001f, -27.25f, -27.389999f, -27.530001f, -27.67f, -27.809999f, -27.950001f, -28.08f, // 17 + -28.219999f, -28.35f, -28.49f, -28.620001f, -28.76f, -28.889999f, -29.02f, -29.16f, -29.290001f, -29.42f, // 18 + -29.549999f, -29.68f, -29.809999f, -29.940001f, -30.059999f, -30.190001f, -30.32f, -30.440001f, -30.57f, -30.700001f, // 19 + -30.82f, -30.940001f, -31.07f, -31.190001f, -31.309999f, -31.440001f, -31.559999f, -31.68f, -31.799999f, -31.92f, // 20 + -32.040001f, -32.16f, -32.279999f, -32.400002f, -32.52f, -32.630001f, -32.75f, -32.869999f, -32.98f, -33.099998f, // 21 + -33.209999f, -33.330002f, -33.439999f, -33.560001f, -33.669998f, -33.779999f, -33.900002f, -34.009998f, -34.119999f, -34.23f, // 22 + -34.34f, -34.450001f, -34.560001f, -34.669998f, -34.779999f, -34.889999f, -35.0f, -35.110001f, -35.220001f, -35.330002f, // 23 + -35.43f, -35.540001f, -35.650002f, -35.75f, -35.860001f, -35.959999f, -36.07f, -36.169998f, -36.279999f, -36.380001f, // 24 + -36.490002f, -36.59f, -36.689999f, -36.790001f, -36.900002f, -37.0f, -37.099998f, -37.200001f, -37.299999f, -37.400002f, // 25 + -37.5f, -37.599998f, -37.700001f, -37.799999f, -37.900002f, -38.0f, -38.099998f, -38.200001f, -38.290001f, -38.389999f, // 26 + -38.490002f, -38.580002f, -38.68f, -38.779999f, -38.869999f, -38.970001f, -39.060001f, -39.16f, -39.25f, -39.349998f, // 27 + -39.439999f, -39.540001f, -39.630001f, -39.720001f, -39.82f, -39.91f, -40.0f, -40.09f, -40.189999f, -40.279999f, // 28 + -40.369999f, -40.459999f, -40.549999f, -40.639999f, -40.73f, -40.82f, -40.91f, -41.0f, -41.09f, -41.18f, // 29 + -41.27f, -41.360001f, -41.450001f, -41.529999f, -41.619999f, -41.709999f, -41.799999f, -41.889999f, -41.970001f, -42.060001f, // 30 + -42.150002f, -42.23f, -42.32f, -42.400002f, -42.490002f, -42.57f, -42.66f, -42.740002f, -42.830002f, -42.91f, // 31 + -43.0f, -43.080002f, -43.16f, -43.25f, -43.330002f, -43.41f, -43.5f, -43.580002f, -43.66f, -43.740002f, // 32 + -43.830002f, -43.91f, -43.990002f, -44.07f, -44.150002f, -44.23f, -44.310001f, -44.389999f, -44.48f, -44.560001f, // 33 + -44.639999f, -44.720001f, -44.790001f, -44.869999f, -44.950001f, -45.029999f, -45.110001f, -45.189999f, -45.27f, -45.349998f, // 34 + -45.419998f, -45.5f, -45.580002f, -45.66f, -45.73f, -45.810001f, -45.889999f, -45.970001f, -46.040001f, -46.119999f, // 35 + -46.189999f, -46.27f, -46.349998f, -46.419998f, -46.5f, -46.57f, -46.650002f, -46.720001f, -46.799999f, -46.869999f, // 36 + -46.950001f, -47.02f, -47.09f, -47.169998f, -47.240002f, -47.32f, -47.389999f, -47.459999f, -47.540001f, -47.610001f, // 37 + -47.68f, -47.75f, -47.830002f, -47.900002f, -47.970001f, -48.040001f, -48.110001f, -48.189999f, -48.259998f, -48.330002f, // 38 + -48.400002f, -48.470001f, -48.540001f, -48.610001f, -48.68f, -48.75f, -48.82f, -48.889999f, -48.959999f, -49.029999f, // 39 + -49.099998f, -49.169998f, -49.240002f, -49.310001f, -49.380001f, -49.450001f, -49.52f, -49.59f, -49.66f, -49.720001f, // 40 + -49.790001f, -49.860001f, -49.93f, -50.0f, -50.060001f, -50.130001f, -50.200001f, -50.27f, -50.330002f, -50.400002f, // 41 + -50.470001f, -50.529999f, -50.599998f, -50.669998f, -50.73f, -50.799999f, -50.869999f, -50.93f, -51.0f, -51.060001f, // 42 + -51.130001f, -51.189999f, -51.259998f, -51.32f, -51.389999f, -51.450001f, -51.52f, -51.580002f, -51.650002f, -51.709999f, // 43 + -51.779999f, -51.84f, -51.900002f, -51.970001f, -52.029999f, -52.099998f, -52.16f, -52.220001f, -52.290001f, -52.349998f, // 44 + -52.41f, -52.470001f, -52.540001f, -52.599998f, -52.66f, -52.720001f, -52.790001f, -52.849998f, -52.91f, -52.970001f, // 45 + -53.040001f, -53.099998f, -53.16f, -53.220001f, -53.279999f, -53.34f, -53.400002f, -53.470001f, -53.529999f, -53.59f, // 46 + -53.650002f, -53.709999f, -53.77f, -53.830002f, -53.889999f, -53.950001f, -54.009998f, -54.07f, -54.130001f, -54.189999f, // 47 + -54.25f, -54.310001f, -54.369999f, -54.43f, -54.490002f, -54.549999f, -54.599998f, -54.66f, -54.720001f, -54.779999f, // 48 + -54.84f, -54.900002f, -54.959999f, -55.009998f, -55.07f, -55.130001f, -55.189999f, -55.25f, -55.299999f, -55.360001f, // 49 + -55.419998f, -55.48f, -55.529999f, -55.59f, -55.650002f, -55.709999f, -55.759998f, -55.82f, -55.880001f, -55.93f, // 50 + -55.990002f, -56.049999f, -56.099998f, -56.16f, -56.220001f, -56.27f, -56.330002f, -56.380001f, -56.439999f, -56.5f, // 51 + -56.549999f, -56.610001f, -56.66f, -56.720001f, -56.77f, -56.830002f, -56.880001f, -56.939999f, -56.990002f, -57.049999f, // 52 + -57.099998f, -57.16f, -57.209999f, -57.27f, -57.32f, -57.380001f, -57.43f, -57.48f, -57.540001f, -57.59f, // 53 + -57.650002f, -57.700001f, -57.75f, -57.810001f, -57.860001f, -57.91f, -57.970001f, -58.02f, -58.07f, -58.130001f, // 54 + -58.18f, -58.23f, -58.290001f, -58.34f, -58.389999f, -58.450001f, -58.5f, -58.549999f, -58.599998f, -58.66f, // 55 + -58.709999f, -58.759998f, -58.810001f, -58.860001f, -58.919998f, -58.970001f, -59.02f, -59.07f, -59.119999f, -59.169998f, // 56 + -59.23f, -59.279999f, -59.330002f, -59.380001f, -59.43f, -59.48f, -59.529999f, -59.580002f, -59.630001f, -59.689999f, // 57 + -59.740002f, -59.790001f, -59.84f, -59.889999f, -59.939999f, -59.990002f, -60.040001f, -60.09f, -60.139999f, -60.189999f, // 58 + -60.240002f, -60.290001f, -60.34f, -60.389999f, -60.439999f, -60.490002f, -60.540001f, -60.59f, -60.639999f, -60.689999f, // 59 + -60.740002f, -60.779999f, -60.830002f, -60.880001f, -60.93f, -60.98f, -61.029999f, -61.080002f, -61.130001f, -61.18f, // 60 + -61.220001f, -61.27f, -61.32f, -61.369999f, -61.419998f, -61.470001f, -61.509998f, -61.560001f, -61.610001f, -61.66f, // 61 + -61.709999f, -61.75f, -61.799999f, -61.849998f, -61.900002f, -61.939999f, -61.990002f, -62.040001f, -62.09f, -62.130001f, // 62 + -62.18f, -62.23f, -62.279999f, -62.32f, -62.369999f, -62.419998f, -62.459999f, -62.509998f, -62.560001f, -62.599998f, // 63 + -62.650002f, -62.700001f, -62.740002f, -62.790001f, -62.84f, -62.880001f, -62.93f, -62.970001f, -63.02f, -63.07f, // 64 + -63.110001f, -63.16f, -63.200001f, -63.25f, -63.299999f, -63.34f, -63.389999f, -63.43f, -63.48f, -63.52f, // 65 + -63.57f, -63.610001f, -63.66f, -63.709999f, -63.75f, -63.799999f, -63.84f, -63.889999f, -63.93f, -63.98f, // 66 + -64.019997f, -64.059998f, -64.110001f, -64.150002f, -64.199997f, -64.239998f, -64.290001f, -64.330002f, -64.379997f, -64.419998f, // 67 + -64.459999f, -64.510002f, -64.550003f, -64.599998f, -64.639999f, -64.690002f, -64.730003f, -64.769997f, -64.82f, -64.860001f, // 68 + -64.900002f, -64.949997f, -64.989998f, -65.029999f, -65.080002f, -65.120003f, -65.169998f, -65.209999f, -65.25f, -65.290001f, // 69 + -65.339996f, -65.379997f, -65.419998f, -65.470001f, -65.510002f, -65.550003f, -65.599998f, -65.639999f, -65.68f, -65.720001f, // 70 + -65.769997f, -65.809998f, -65.849998f, -65.889999f, -65.940002f, -65.980003f, -66.019997f, -66.059998f, -66.110001f, -66.150002f, // 71 + -66.190002f, -66.230003f, -66.269997f, -66.32f, -66.360001f, -66.400002f, -66.440002f, -66.480003f, -66.519997f, -66.57f, // 72 + -66.610001f, -66.650002f, -66.690002f, -66.730003f, -66.769997f, -66.82f, -66.860001f, -66.900002f, -66.940002f, -66.980003f, // 73 + -67.019997f, -67.059998f, -67.099998f, -67.139999f, -67.190002f, -67.230003f, -67.269997f, -67.309998f, -67.349998f, -67.389999f, // 74 + -67.43f, -67.470001f, -67.510002f, -67.550003f, -67.589996f, -67.629997f, -67.669998f, -67.709999f, -67.75f, -67.790001f, // 75 + -67.830002f, -67.870003f, -67.910004f, -67.949997f, -67.989998f, -68.029999f, -68.07f, -68.110001f, -68.150002f, -68.190002f, // 76 + -68.230003f, -68.269997f, -68.309998f, -68.349998f, -68.389999f, -68.43f, -68.470001f, -68.510002f, -68.550003f, -68.589996f, // 77 + -68.629997f, -68.669998f, -68.709999f, -68.75f, -68.790001f, -68.82f, -68.860001f, -68.900002f, -68.940002f, -68.980003f, // 78 + -69.019997f, -69.059998f, -69.099998f, -69.139999f, -69.169998f, -69.209999f, -69.25f, -69.290001f, -69.330002f, -69.370003f, // 79 + -69.410004f, -69.440002f, -69.480003f, -69.519997f, -69.559998f, -69.599998f, -69.639999f, -69.669998f, -69.709999f, -69.75f, // 80 + -69.790001f, -69.830002f, -69.860001f, -69.900002f, -69.940002f, -69.980003f, -70.010002f, -70.050003f, -70.089996f, -70.129997f, // 81 + -70.169998f, -70.199997f, -70.239998f, -70.279999f, -70.32f, -70.349998f, -70.389999f, -70.43f, -70.470001f, -70.5f, // 82 + -70.540001f, -70.580002f, -70.610001f, -70.650002f, -70.690002f, -70.730003f, -70.760002f, -70.800003f, -70.839996f, -70.870003f, // 83 + -70.910004f, -70.949997f, -70.980003f, -71.019997f, -71.059998f, -71.089996f, -71.129997f, -71.169998f, -71.199997f, -71.239998f, // 84 + -71.279999f, -71.309998f, -71.349998f, -71.389999f, -71.419998f, -71.459999f, -71.489998f, -71.529999f, -71.57f, -71.599998f, // 85 + -71.639999f, -71.68f, -71.709999f, -71.75f, -71.779999f, -71.82f, -71.860001f, -71.889999f, -71.93f, -71.959999f, // 86 + -72.0f, -72.029999f, -72.07f, -72.110001f, -72.139999f, -72.18f, -72.209999f, -72.25f, -72.279999f, -72.32f, // 87 + -72.349998f, -72.389999f, -72.419998f, -72.459999f, -72.5f, -72.529999f, -72.57f, -72.599998f, -72.639999f, -72.669998f, // 88 + -72.709999f, -72.739998f, -72.779999f, -72.809998f, -72.849998f, -72.879997f, -72.919998f, -72.949997f, -72.989998f, -73.019997f, // 89 + -73.050003f, -73.089996f, -73.120003f, -73.160004f, -73.190002f, -73.230003f, -73.260002f, -73.300003f, -73.330002f, -73.370003f, // 90 + -73.400002f, -73.43f, -73.470001f, -73.5f, -73.540001f, -73.57f, -73.610001f, -73.639999f, -73.669998f, -73.709999f, // 91 + -73.739998f, -73.779999f, -73.809998f, -73.839996f, -73.879997f, -73.910004f, -73.949997f, -73.980003f, -74.010002f, -74.050003f, // 92 + -74.080002f, -74.110001f, -74.150002f, -74.18f, -74.220001f, -74.25f, -74.279999f, -74.32f, -74.349998f, -74.379997f, // 93 + -74.419998f, -74.449997f, -74.480003f, -74.519997f, -74.550003f, -74.580002f, -74.620003f, -74.650002f, -74.68f, -74.720001f, // 94 + -74.75f, -74.779999f, -74.82f, -74.849998f, -74.879997f, -74.910004f, -74.949997f, -74.980003f, -75.010002f, -75.050003f, // 95 + -75.080002f, -75.110001f, -75.139999f, -75.18f, -75.209999f, -75.239998f, -75.279999f, -75.309998f, -75.339996f, -75.370003f, // 96 + -75.410004f, -75.440002f, -75.470001f, -75.5f, -75.540001f, -75.57f, -75.599998f, -75.629997f, -75.669998f, -75.699997f, // 97 + -75.730003f, -75.760002f, -75.790001f, -75.830002f, -75.860001f, -75.889999f, -75.919998f, -75.949997f, -75.989998f, -76.019997f, // 98 + -76.050003f, -76.080002f, -76.110001f, -76.150002f, -76.18f, -76.209999f, -76.239998f, -76.269997f, -76.309998f, -76.339996f, // 99 + -76.370003f, -76.400002f, -76.43f, -76.459999f, -76.5f, -76.529999f, -76.559998f, -76.589996f, -76.620003f, -76.650002f, // 100 + -76.68f, -76.720001f, -76.75f, -76.779999f, -76.809998f, -76.839996f, -76.870003f, -76.900002f, -76.93f, -76.970001f, // 101 + -77.0f, -77.029999f, -77.059998f, -77.089996f, -77.120003f, -77.150002f, -77.18f, -77.209999f, -77.239998f, -77.279999f, // 102 + -77.309998f, -77.339996f, -77.370003f, -77.400002f, -77.43f, -77.459999f, -77.489998f, -77.519997f, -77.550003f, -77.580002f, // 103 + -77.610001f, -77.639999f, -77.68f, -77.709999f, -77.739998f, -77.769997f, -77.800003f, -77.830002f, -77.860001f, -77.889999f, // 104 + -77.919998f, -77.949997f, -77.980003f, -78.010002f, -78.040001f, -78.07f, -78.099998f, -78.129997f, -78.160004f, -78.190002f, // 105 + -78.220001f, -78.25f, -78.279999f, -78.309998f, -78.339996f, -78.370003f, -78.400002f, -78.43f, -78.459999f, -78.489998f, // 106 + -78.519997f, -78.550003f, -78.580002f, -78.610001f, -78.639999f, -78.669998f, -78.699997f, -78.730003f, -78.760002f, -78.790001f, // 107 + -78.82f, -78.849998f, -78.879997f, -78.910004f, -78.940002f, -78.970001f, -79.0f, -79.029999f, -79.050003f, -79.080002f, // 108 + -79.110001f, -79.139999f, -79.169998f, -79.199997f, -79.230003f, -79.260002f, -79.290001f, -79.32f, -79.349998f, -79.379997f, // 109 + -79.410004f, -79.440002f, -79.459999f, -79.489998f, -79.519997f, -79.550003f, -79.580002f, -79.610001f, -79.639999f, -79.669998f, // 110 + -79.699997f, -79.730003f, -79.75f, -79.779999f, -79.809998f, -79.839996f, -79.870003f, -79.900002f, -79.93f, -79.959999f, // 111 + -79.980003f, -80.010002f, -80.040001f, -80.07f, -80.099998f, -80.129997f, -80.160004f, -80.18f, -80.209999f, -80.239998f, // 112 + -80.269997f, -80.300003f, -80.330002f, -80.360001f, -80.379997f, -80.410004f, -80.440002f, -80.470001f, -80.5f, -80.529999f, // 113 + -80.550003f, -80.580002f, -80.610001f, -80.639999f, -80.669998f, -80.699997f, -80.720001f, -80.75f, -80.779999f, -80.809998f, // 114 + -80.839996f, -80.860001f, -80.889999f, -80.919998f, -80.949997f, -80.980003f, -81.0f, -81.029999f, -81.059998f, -81.089996f, // 115 + -81.120003f, -81.139999f, -81.169998f, -81.199997f, -81.230003f, -81.25f, -81.279999f, -81.309998f, -81.339996f, -81.360001f, // 116 + -81.389999f, -81.419998f, -81.449997f, -81.480003f, -81.5f, -81.529999f, -81.559998f, -81.589996f, -81.610001f, -81.639999f, // 117 + -81.669998f, -81.699997f, -81.720001f, -81.75f, -81.779999f, -81.800003f, -81.830002f, -81.860001f, -81.889999f, -81.910004f, // 118 + -81.940002f, -81.970001f, -82.0f, -82.019997f, -82.050003f, -82.080002f, -82.099998f, -82.129997f, -82.160004f, -82.190002f, // 119 + -82.209999f, -82.239998f, -82.269997f, -82.290001f, -82.32f, -82.349998f, -82.370003f, -82.400002f, -82.43f, -82.449997f, // 120 + -82.480003f, -82.510002f, -82.540001f, -82.559998f, -82.589996f, -82.620003f, -82.639999f, -82.669998f, -82.699997f, -82.720001f, // 121 + -82.75f, -82.779999f, -82.800003f, -82.830002f, -82.860001f, -82.879997f, -82.910004f, -82.93f, -82.959999f, -82.989998f, // 122 + -83.010002f, -83.040001f, -83.07f, -83.089996f, -83.120003f, -83.150002f, -83.169998f, -83.199997f, -83.230003f, -83.25f, // 123 + -83.279999f, -83.300003f, -83.330002f, -83.360001f, -83.379997f, -83.410004f, -83.440002f, -83.459999f, -83.489998f, -83.510002f, // 124 + -83.540001f, -83.57f, -83.589996f, -83.620003f, -83.639999f, -83.669998f, -83.699997f, -83.720001f, -83.75f, -83.769997f, // 125 + -83.800003f, -83.830002f, -83.849998f, -83.879997f, -83.900002f, -83.93f, -83.949997f, -83.980003f, -84.010002f, -84.029999f, // 126 + -84.059998f, -84.080002f, -84.110001f, -84.129997f, -84.160004f, -84.190002f, -84.209999f, -84.239998f, -84.260002f, -84.290001f, // 127 +}; diff --git a/source/game_sa/Audio/entities/AECollisionAudioEntity.cpp b/source/game_sa/Audio/entities/AECollisionAudioEntity.cpp index a619061130..920d69a8e4 100644 --- a/source/game_sa/Audio/entities/AECollisionAudioEntity.cpp +++ b/source/game_sa/Audio/entities/AECollisionAudioEntity.cpp @@ -205,7 +205,7 @@ void CAECollisionAudioEntity::ReportGlassCollisionEvent(eAudioEvents glassSoundT if (time) { auto& snd = m_tempSound; - snd.m_fMaxVolume = (float)(time + CTimer::GetTimeInMS()); + snd.m_ClientVariable = (float)(time + CTimer::GetTimeInMS()); snd.m_nEvent = glassSoundType; snd.m_bRequestUpdates = true; } @@ -248,7 +248,7 @@ void CAECollisionAudioEntity::ReportWaterSplash(CVector posn, float volume) { SOUND_REQUEST_UPDATES ); m_tempSound.m_nEvent = AE_FRONTEND_BACK; - m_tempSound.m_fMaxVolume = static_cast(CTimer::GetTimeInMS() + 166); + m_tempSound.m_ClientVariable = static_cast(CTimer::GetTimeInMS() + 166); } // 0x4DAE40 diff --git a/source/game_sa/Audio/entities/AEExplosionAudioEntity.cpp b/source/game_sa/Audio/entities/AEExplosionAudioEntity.cpp index 4d47d7f07d..85ccdbf382 100644 --- a/source/game_sa/Audio/entities/AEExplosionAudioEntity.cpp +++ b/source/game_sa/Audio/entities/AEExplosionAudioEntity.cpp @@ -50,7 +50,7 @@ void CAEExplosionAudioEntity::AddAudioEvent(eAudioEvents audioEvent, CVector& po speed_b = gfExplosionFrequencyVariations[m_Speed] * sqrt(sqrt(2.0f)); } - auto vol1 = CAEAudioEnvironment::GetDistanceAttenuation(CAEAudioEnvironment::GetPositionRelativeToCamera(posn).Magnitude() * (1.0f / 12.0f)) + vol0 - 3.0f; + auto vol1 = CAEAudioEnvironment::GetDistanceAttenuation(CAEAudioEnvironment::GetPositionRelativeToCamera(posn).Magnitude() / 12.0f) + vol0 - 3.0f; auto flags = static_cast(SOUND_FORCED_FRONT | SOUND_ROLLED_OFF | SOUND_REQUEST_UPDATES | SOUND_FRONT_END); sound.Initialise(4, 1, this, { -1.0f, 0.0f, 0.0f }, vol1, 12.0f, speed_a, 1.0f, 0, flags, 0.0f, 0); diff --git a/source/game_sa/Audio/entities/AEFireAudioEntity.cpp b/source/game_sa/Audio/entities/AEFireAudioEntity.cpp index ab0c56c01c..357c2c4ad1 100644 --- a/source/game_sa/Audio/entities/AEFireAudioEntity.cpp +++ b/source/game_sa/Audio/entities/AEFireAudioEntity.cpp @@ -77,7 +77,7 @@ void CAEFireAudioEntity::PlayFireSounds(eAudioEvents audioId, CVector& posn) { 0.0f, 0 ); - sound.m_fMaxVolume = volume + 3.0f; + sound.m_ClientVariable = volume + 3.0f; sound.m_nEvent = AE_FRONTEND_SELECT; AESoundManager.RequestNewSound(&sound); } @@ -117,10 +117,10 @@ void CAEFireAudioEntity::UpdateParameters(CAESound* sound, int16 curPlayPos) { switch (sound->m_nEvent) { case AE_FRONTEND_SELECT: - if (sound->m_fVolume >= sound->m_fMaxVolume) { + if (sound->m_fVolume >= sound->m_ClientVariable) { sound->m_nEvent = AE_FRONTEND_BACK; } else { - sound->m_fVolume = std::min(sound->m_fVolume + 2.0f, sound->m_fMaxVolume); + sound->m_fVolume = std::min(sound->m_fVolume + 2.0f, sound->m_ClientVariable); } break; case AE_FRONTEND_BACK: diff --git a/source/game_sa/Audio/entities/AEGlobalWeaponAudioEntity.cpp b/source/game_sa/Audio/entities/AEGlobalWeaponAudioEntity.cpp index 648f77d5db..77c834ed44 100644 --- a/source/game_sa/Audio/entities/AEGlobalWeaponAudioEntity.cpp +++ b/source/game_sa/Audio/entities/AEGlobalWeaponAudioEntity.cpp @@ -1,5 +1,6 @@ #include "StdInc.h" +#include "AEAudioUtility.h" #include "AEGlobalWeaponAudioEntity.h" #include "AEAudioHardware.h" @@ -35,23 +36,17 @@ void CAEGlobalWeaponAudioEntity::UpdateParameters(CAESound* sound, int16 curPlay // 0x4DFAA0 void CAEGlobalWeaponAudioEntity::AddAudioEvent(eAudioEvents audioId, eWeaponType weaponType, CPhysical* entity) { - if (!entity) + if (!entity) { return; + } switch (audioId) { case AE_WEAPON_FIRE: - case AE_WEAPON_FIRE_PLANE: - WeaponFire(weaponType, entity, audioId); - break; + case AE_WEAPON_FIRE_PLANE: return WeaponFire(weaponType, entity, audioId); case AE_WEAPON_RELOAD_A: - case AE_WEAPON_RELOAD_B: - WeaponReload(weaponType, entity, audioId); - break; - case AE_PROJECTILE_FIRE: - ProjectileFire(weaponType, entity, audioId); - break; - default: - return; + case AE_WEAPON_RELOAD_B: return WeaponReload(weaponType, entity, audioId); + case AE_PROJECTILE_FIRE: return ProjectileFire(weaponType, entity, audioId); + default: return; } } @@ -65,33 +60,242 @@ void CAEGlobalWeaponAudioEntity::ProjectileFire(eWeaponType weaponType, CPhysica return; } - static float gfRocketFrequencyVariations[] = { 1.08f, 1.0f, 0.92f, 3.3f } ;// 0x8AE5AC - m_FrequencyVariation = (m_FrequencyVariation + 1) % 3; - - if (!AEAudioHardware.IsSoundBankLoaded(143, 5) && !AudioEngine.IsLoadingTuneActive()) { - AEAudioHardware.LoadSoundBank(143, 5); - } + constexpr float gfRocketFrequencyVariations[] = { 1.08f, 1.0f, 0.92f, 3.3f };// 0x8AE5AC + m_FrequencyVariation = (m_FrequencyVariation + 1) % (std::size(gfRocketFrequencyVariations) - 1); - const auto volume = GetDefaultVolume(event); - const auto speed0 = gfRocketFrequencyVariations[m_FrequencyVariation]; - const auto speed1 = speed0 * 1.25f; + const auto PlayRocketSound = [&](int16 bankSlotID, tSoundID soundID, float speedMult, float volumeOffsetdB) { + AESoundManager.PlaySound({ + .BankSlotID = bankSlotID, + .SoundID = soundID, + .AudioEntity = this, + .Pos = physical->GetPosition(), + .Volume = GetDefaultVolume(event) + volumeOffsetdB, + .RollOffFactor = 3.0f, + .Speed = gfRocketFrequencyVariations[m_FrequencyVariation] * speedMult, + .Flags = SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY, + .FrequencyVariance = 0.02f, + .RegisterWithEntity = physical + }); + }; - m_tempSound.Initialise(5, 68, this, physical->GetPosition(), volume - 8.0f, 3.0f, speed0, 1.0f, 0, SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY, 0.02f); - m_tempSound.RegisterWithPhysicalEntity(physical); - AESoundManager.RequestNewSound(&m_tempSound); + if (!AEAudioHardware.IsSoundBankLoaded(143, 5)) { + if (!AudioEngine.IsLoadingTuneActive()) { + AEAudioHardware.LoadSoundBank(143, 5); + } + return; + } + PlayRocketSound(5, 68, 1.f, -8.f); if (!AEAudioHardware.IsSoundBankLoaded(138, 19)) { AEAudioHardware.LoadSoundBank(138, 19); return; } - m_tempSound.Initialise(19, 26, this, physical->GetPosition(), volume, 3.0f, speed1, 1.0f, 0, SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY, 0.02f); - m_tempSound.RegisterWithPhysicalEntity(physical); - AESoundManager.RequestNewSound(&m_tempSound); + PlayRocketSound(19, 26, 1.25f, 0.f); } // 0x4DF210 void CAEGlobalWeaponAudioEntity::ServiceAmbientGunFire() { - plugin::CallMethod<0x4DF210, CAEGlobalWeaponAudioEntity*>(this); + constexpr CVector s_FogHornPositions[]{ + {-2683.f, 1445.f, 37.f}, // 0x4DF271 + {-2683.f, 1804.f, 69.f}, // 0x4DF29F + }; + constexpr int32 FOGHORN_FADE_OUT_DELAY = 5000; + constexpr int32 FOGHORN_STOP_DELAY = 5000; // time to live + + constexpr CVector s_WaterfallPositions[]{ + {2075.3f, 1925.9f, 13.0f}, // 0x4DF2C9 + {2085.8f, 1905.5f, 11.3f}, // 0x4DF2FD + {2091.5f, 1888.9f, 11.1f}, // 0x4DF31D + }; + + enum eState : int32 { + INITIAL, + GUNSHOTS, + FOGHORN_0, + STATE_3, + FOGHORN_1, + WATERFALL_LV, // Only in LV + }; + static auto& s_State = StaticRef(0xB61324); + + static auto& s_GunShots = StaticRef(0xB61318); + static auto& s_WeaponType = StaticRef(0xB6131C); + static auto& s_Delay = StaticRef(0xB61320); + static auto& s_LastTime = ScopedStaticRef(0xB61364, 0xB61368, 0x1, CTimer::GetTimeInMS()); + + switch (s_State) { + case eState::INITIAL: { + switch (CWeather::WeatherRegion) { + case eWeatherRegion::WEATHER_REGION_LA: { // 0x4DF35A + if (CTimer::GetFrameCounter() % 1024) { // TODO: Maybe use a timer or something? + return; + } + + const auto a = CGeneral::GetRandomNumberInRange(0.f, TWO_PI); + const auto r = CGeneral::GetRandomNumberInRange(40.f, 80.f); + CVector pos = TheCamera.GetPosition() + CVector{ std::cos(a) * r, std::sin(a) * r, 0.f }; + pos.z = std::min(pos.z, 20.f); + m_Physical->SetPosn(pos); + + PickAmbientGunFire(s_GunShots, s_WeaponType, s_Delay); + + s_State = eState::GUNSHOTS; + + break; + } + case WEATHER_REGION_LV: { // 0x4DF580 + if (!AEAudioHardware.IsSoundBankLoaded(39u, 2)) { + return; + } + if (!rng::all_of(pWaterfall, notsa::IsNull{})) { + return; + } + if (CVector::DistSqr(s_WaterfallPositions[1], TheCamera.GetPosition()) >= sq(100.f)) { + return; + } + const auto PlayWaterfallSound = [&](int32 i, float speed) { + pWaterfall[i] = AESoundManager.PlaySound({ + .BankSlotID = 2, + .SoundID = 3, + .AudioEntity = this, + .Pos = s_WaterfallPositions[i], + .Volume = -3.f, + .RollOffFactor = 2.5f, + .Speed = speed, + .Flags = SOUND_REQUEST_UPDATES + }); + }; + constexpr auto SPEED_BASE = 1.f; + constexpr auto SPEED_VAR = 0.01f; + PlayWaterfallSound(0, SPEED_BASE); + PlayWaterfallSound(1, SPEED_BASE + SPEED_VAR); + PlayWaterfallSound(2, SPEED_BASE - SPEED_VAR); + + s_State = eState::WATERFALL_LV; + + break; + } + case WEATHER_CLOUDY_LA: { + break; + } + default: { // 0x4DF490 + if (CWeather::Foggyness_SF < 0.5) { + return; + } + if (CTimer::GetFrameCounter() % 1024) { // TODO: Maybe use a timer or something? + return; + } + if (CVector::DistSqr(TheCamera.GetPosition(), s_FogHornPositions[0]) > sq(2000.f)) { + return; + } + if (pFogHorn) { + return; + } + + pFogHorn = AESoundManager.PlaySound({ + .BankSlotID = 17, + .SoundID = 13, + .AudioEntity = this, + .Pos = s_FogHornPositions[0], + .RollOffFactor = 60.f, + .Flags = SOUND_REQUEST_UPDATES + }); + + s_State = eState::FOGHORN_0; + s_LastTime = CTimer::GetTimeInMS(); + + break; + } + } + break; + } + case eState::GUNSHOTS: { // 0x4DF769 + if (s_LastTime + s_Delay >= CTimer::GetTimeInMS()) { + return; + } + + if (CVector::DistSqr(FindPlayerCoors(), m_Physical->GetPosition()) <= sq(24.f)) { + m_Physical->SetType(ENTITY_TYPE_NOTINPOOLS); + AudioEngine.ReportWeaponEvent(AE_WEAPON_FIRE, s_WeaponType, m_Physical); + + if (--s_GunShots) { // 0x4DF862 + assert(s_WeaponType == WEAPON_PISTOL || s_WeaponType == WEAPON_AK47); // See `PickAmbientGunFire` + s_Delay = s_WeaponType == WEAPON_PISTOL + ? CAEAudioUtility::GetRandomNumberInRange(500, 1200) + : CAEAudioUtility::GetRandomNumberInRange(90, 450); + } else if (CGeneral::RandomBool(60.f)) { // 0x4DF7E9 + s_State = eState::INITIAL; + } else { // 0x4DF849 + PickAmbientGunFire(s_GunShots, s_WeaponType, s_Delay); + } + } else { + s_State = eState::INITIAL; + } + s_LastTime = CTimer::GetTimeInMS(); + + break; + } + case eState::FOGHORN_0: // 0x4DF8A4 + case eState::FOGHORN_1: { // 0x4DF98A + if (CTimer::GetTimeInMS() > s_LastTime + FOGHORN_STOP_DELAY) { + if (pFogHorn) { + pFogHorn->StopSound(); + } + s_State = s_State == eState::FOGHORN_0 + ? eState::STATE_3 // FOGHORN_0 -> S3 + : eState::INITIAL; // FOGHORN_1 -> S0 + } else if (CTimer::GetTimeInMS() > s_LastTime + FOGHORN_FADE_OUT_DELAY) { // BUG: Since `FOGHORN_TTL` and `FOGHORN_FADE_OUT_DELAY` are both 5000 the `if` here will never be true. + if (pFogHorn) { + pFogHorn->m_fVolume -= 3.3f; + } + } + break; + } + case eState::STATE_3: { // 0x4DF8D1 + if (s_LastTime + 6500 < CTimer::GetTimeInMS()) { + return; + } + if (!AEAudioHardware.IsSoundBankLoaded(59, 0)) { // BUG: Pretty sure the `bankSlotId` param should be 17 here + return; + } + if (!pFogHorn) { + pFogHorn = AESoundManager.PlaySound({ + .BankSlotID = 17, + .SoundID = 13, + .AudioEntity = this, + .Pos = s_FogHornPositions[1], + .RollOffFactor = 60.f, + .Speed = 1.2f, + .Flags = SOUND_REQUEST_UPDATES + }); + + s_State = eState::FOGHORN_1; + s_LastTime = CTimer::GetTimeInMS(); + } + break; + } + case eState::WATERFALL_LV: { // 0x4DF9D8 + if (CWeather::WeatherRegion != eWeatherRegion::WEATHER_REGION_LV || CVector::DistSqr(TheCamera.GetPosition(), s_WaterfallPositions[1]) > sq(100.f)) { + for (auto& s : pWaterfall) { + if (s) { + std::exchange(s, nullptr)->StopSound(); + } + } + s_State = eState::INITIAL; + } + break; + } + default: + NOTSA_UNREACHABLE(); + } +} + +void CAEGlobalWeaponAudioEntity::PickAmbientGunFire(int32& gunShots, eWeaponType& weaponType, uint32& delay) { + const auto b = CGeneral::DoCoinFlip(); + gunShots = b ? CAEAudioUtility::GetRandomNumberInRange(2, 4) : CAEAudioUtility::GetRandomNumberInRange(4, 14); + weaponType = b ? WEAPON_PISTOL : WEAPON_AK47; + delay = b ? CAEAudioUtility::GetRandomNumberInRange(500, 1'200) : CAEAudioUtility::GetRandomNumberInRange(90, 350); + } void CAEGlobalWeaponAudioEntity::InjectHooks() { @@ -103,7 +307,7 @@ void CAEGlobalWeaponAudioEntity::InjectHooks() { RH_ScopedInstall(UpdateParameters, 0x4DEF90); RH_ScopedInstall(AddAudioEvent, 0x4DFAA0); RH_ScopedInstall(ProjectileFire, 0x4DF060); - RH_ScopedInstall(ServiceAmbientGunFire, 0x4DF210, { .reversed = false }); + RH_ScopedInstall(ServiceAmbientGunFire, 0x4DF210); } CAEGlobalWeaponAudioEntity* CAEGlobalWeaponAudioEntity::Constructor() { diff --git a/source/game_sa/Audio/entities/AEGlobalWeaponAudioEntity.h b/source/game_sa/Audio/entities/AEGlobalWeaponAudioEntity.h index 53f460a360..c9731f99ed 100644 --- a/source/game_sa/Audio/entities/AEGlobalWeaponAudioEntity.h +++ b/source/game_sa/Audio/entities/AEGlobalWeaponAudioEntity.h @@ -12,6 +12,7 @@ class NOTSA_EXPORT_VTABLE CAEGlobalWeaponAudioEntity : public CAEWeaponAudioEnti void AddAudioEvent(eAudioEvents audioId, eWeaponType weaponType, CPhysical* entity); void ProjectileFire(eWeaponType weaponType, CPhysical* physical, eAudioEvents event); void ServiceAmbientGunFire(); + void PickAmbientGunFire(int32& gunShots, eWeaponType& weaponType, uint32& delay); private: CPhysical* m_Physical; diff --git a/source/game_sa/Audio/entities/AEPedAudioEntity.cpp b/source/game_sa/Audio/entities/AEPedAudioEntity.cpp index 122a0dfebe..427d6f01de 100644 --- a/source/game_sa/Audio/entities/AEPedAudioEntity.cpp +++ b/source/game_sa/Audio/entities/AEPedAudioEntity.cpp @@ -309,7 +309,7 @@ void CAEPedAudioEntity::UpdateParameters(CAESound* sound, int16 curPlayPos) { case AE_PED_JACKED_CAR_KICK: case AE_PED_JACKED_BIKE: case AE_PED_JACKED_DOZER: - if (CTimer::GetTimeInMS() < (uint32)sound->m_fMaxVolume) + if (CTimer::GetTimeInMS() < (uint32)sound->m_ClientVariable) return; sound->m_fSpeed = 1.0f; return; diff --git a/source/game_sa/Audio/entities/AEPoliceScannerAudioEntity.cpp b/source/game_sa/Audio/entities/AEPoliceScannerAudioEntity.cpp index 84cd3e65d3..f87cd2ce7b 100644 --- a/source/game_sa/Audio/entities/AEPoliceScannerAudioEntity.cpp +++ b/source/game_sa/Audio/entities/AEPoliceScannerAudioEntity.cpp @@ -204,7 +204,7 @@ void CAEPoliceScannerAudioEntity::PlayLoadedDialogue() { auto volume = GetDefaultVolume(AE_CRIME_COMMITTED) + s_fVolumeOffset; CAESound sound; sound.Initialise(i + 33, s_pCurrentSlots[i].sfxId, this, { 0.0, 1.0f, 0.0f }, volume, 1.0f, 1.0f, 1.0f, 0, SOUND_DEFAULT, 0.0f, 0); - sound.m_fMaxVolume = (float)i; + sound.m_ClientVariable = (float)i; sound.m_nEnvironmentFlags = SOUND_FRONT_END | SOUND_UNCANCELLABLE | SOUND_REQUEST_UPDATES | SOUND_UNDUCKABLE; sound.m_nEvent = AE_CRIME_COMMITTED; diff --git a/source/game_sa/Audio/entities/AEWeaponAudioEntity.cpp b/source/game_sa/Audio/entities/AEWeaponAudioEntity.cpp index 033f4e0bb2..39a605323f 100644 --- a/source/game_sa/Audio/entities/AEWeaponAudioEntity.cpp +++ b/source/game_sa/Audio/entities/AEWeaponAudioEntity.cpp @@ -8,20 +8,43 @@ #include "StdInc.h" #include "AEWeaponAudioEntity.h" - +#include "AEAudioEnvironment.h" #include "AESoundManager.h" #include "AEAudioHardware.h" #include "AEAudioUtility.h" -// 0x507560 -CAEWeaponAudioEntity::CAEWeaponAudioEntity() { - Clear(); +constexpr std::array gfWeaponPlaneFrequencyVariations{ 1.08f, 1.0f }; + +void CAEWeaponAudioEntity::InjectHooks() { + RH_ScopedVirtualClass(CAEWeaponAudioEntity, 0x86C2AC, 2); + RH_ScopedCategory("Audio/Entities"); + + RH_ScopedInstall(Constructor, 0x5DE990); + RH_ScopedInstall(Destructor, 0x507560); + RH_ScopedInstall(Initialise, 0x503450); + RH_ScopedInstall(Reset, 0x503490); + RH_ScopedInstall(Terminate, 0x503480); + RH_ScopedInstall(WeaponFire, 0x504F80); + RH_ScopedInstall(WeaponReload, 0x503690); + RH_ScopedInstall(PlayChainsawStopSound, 0x504AA0); + RH_ScopedInstall(PlayMiniGunStopSound, 0x504960); + RH_ScopedInstall(PlayMiniGunFireSounds, 0x5047C0); + RH_ScopedInstall(PlayCameraSound, 0x5046F0); + RH_ScopedInstall(PlayWeaponLoopSound, 0x504610); + RH_ScopedInstall(PlayFlameThrowerSounds, 0x504470); + RH_ScopedInstall(PlayGunSounds, 0x503CE0); + RH_ScopedInstall(ReportStealthKill, 0x503B20); + RH_ScopedInstall(ReportChainsawEvent, 0x503910); + RH_ScopedInstall(PlayFlameThrowerIdleGasLoop, 0x503870); + RH_ScopedInstall(PlayGoggleSound, 0x503500); + RH_ScopedInstall(StopFlameThrowerIdleGasLoop, 0x5034E0); + RH_ScopedVMTInstall(UpdateParameters, 0x504B70); } // 0x503450 void CAEWeaponAudioEntity::Initialise() { - m_nState = 3; - m_nChainsawSoundState = 4; + m_MiniGunState = eMiniGunState::STOPPED; + m_ChainsawState = eChainsawState::STOPPED; if (!AudioEngine.IsLoadingTuneActive()) { AEAudioHardware.LoadSoundBank(143, 5); } @@ -39,81 +62,194 @@ void CAEWeaponAudioEntity::Reset() { } // 0x504F80 -void CAEWeaponAudioEntity::WeaponFire(eWeaponType type, CPhysical* entity, eAudioEvents audioEventId) { - if (!entity) +void CAEWeaponAudioEntity::WeaponFire(eWeaponType weaponType, CPhysical* parent, eAudioEvents audioEvent) { + if (!parent) { return; + } - switch (type) { + switch (weaponType) { case WEAPON_PISTOL: - return PlayGunSounds(entity, 52, 53, 6, 7, 8, audioEventId, 0.0f, 1.41421f, 1.0f); - + return PlayGunSounds( + parent, + SND_GENRL_WEAPONS_EAGLE_DRYFIRE, + SND_GENRL_WEAPONS_EAGLE_LOWS, + SND_GENRL_WEAPONS_EAGLE_SHOT_L, + SND_GENRL_WEAPONS_EAGLE_SHOT_R, + SND_GENRL_WEAPONS_EAGLE_TAIL_L, + audioEvent, + 0.0f, + 1.41421f + ); case WEAPON_PISTOL_SILENCED: - return PlayGunSounds(entity, 76, 77, 24, 24, -1, audioEventId, -7.0f, 1.0f, 1.0f); - + return PlayGunSounds( + parent, + SND_GENRL_WEAPONS_SILENCED_DRYFIRE, + SND_GENRL_WEAPONS_SILENCED_LOWS, + SND_GENRL_WEAPONS_SILENCED_SHOT_L, + SND_GENRL_WEAPONS_SILENCED_SHOT_L, + SND_GENRL_WEAPONS_UNK, + audioEvent, + -7.f + ); case WEAPON_DESERT_EAGLE: - return PlayGunSounds(entity, 52, 53, 6, 7, 8, audioEventId, 0.0f, 0.94387001f, 1.0f); - + return PlayGunSounds( + parent, + SND_GENRL_WEAPONS_EAGLE_DRYFIRE, + SND_GENRL_WEAPONS_EAGLE_LOWS, + SND_GENRL_WEAPONS_EAGLE_SHOT_L, + SND_GENRL_WEAPONS_EAGLE_SHOT_R, + SND_GENRL_WEAPONS_EAGLE_TAIL_L, + audioEvent, + 0.f, + 0.94387001f + ); case WEAPON_SHOTGUN: case WEAPON_SPAS12_SHOTGUN: - return PlayGunSounds(entity, 73, 74, 21, 22, 23, audioEventId, 0.0f, 1.0f, 1.0f); - + return PlayGunSounds( + parent, + SND_GENRL_WEAPONS_SHOTGUN_DRYFIRE, + SND_GENRL_WEAPONS_SHOTGUN_LOWS, + SND_GENRL_WEAPONS_SHOTGUN_SHOT_L, + SND_GENRL_WEAPONS_SHOTGUN_SHOT_R, + SND_GENRL_WEAPONS_SHOTGUN_TAIL_R, + audioEvent, + 0.f + ); case WEAPON_SAWNOFF_SHOTGUN: - return PlayGunSounds(entity, 73, 74, 21, 22, 23, audioEventId, 0.0f, 0.79369998f, 0.93f); - + return PlayGunSounds( + parent, + SND_GENRL_WEAPONS_SHOTGUN_DRYFIRE, + SND_GENRL_WEAPONS_SHOTGUN_LOWS, + SND_GENRL_WEAPONS_SHOTGUN_SHOT_L, + SND_GENRL_WEAPONS_SHOTGUN_SHOT_R, + SND_GENRL_WEAPONS_SHOTGUN_TAIL_R, + audioEvent, + 0.0f, + 0.79369998f, + 0.93f + ); case WEAPON_MICRO_UZI: - return PlayGunSounds(entity, 29, 30, 0, 1, 2, audioEventId, 0.0f, 1.0f, 1.0f); - + return PlayGunSounds( + parent, + SND_GENRL_WEAPONS_9MM1DRY, + SND_GENRL_WEAPONS_9MM1LOWS, + SND_GENRL_WEAPONS_9MM1SHOT_L, + SND_GENRL_WEAPONS_9MM1SHOT_R, + SND_GENRL_WEAPONS_9MM1TAIL, + audioEvent + ); case WEAPON_MP5: - return PlayGunSounds(entity, 29, 30, 17, 18, 2, audioEventId, 0.0f, 1.0f, 1.0f); - + return PlayGunSounds( + parent, + SND_GENRL_WEAPONS_9MM1DRY, + SND_GENRL_WEAPONS_9MM1LOWS, + SND_GENRL_WEAPONS_MP5SHOT_L, + SND_GENRL_WEAPONS_MP5SHOT_R, + SND_GENRL_WEAPONS_9MM1TAIL, + audioEvent + ); case WEAPON_AK47: case WEAPON_M4: - return PlayGunSounds(entity, 33, 53, 3, 4, 5, audioEventId, 0.0f, 1.0f, 1.0f); - + return PlayGunSounds( + parent, + SND_GENRL_WEAPONS_AK_DRYFIRE, + SND_GENRL_WEAPONS_EAGLE_LOWS, + SND_GENRL_WEAPONS_AK_SHOT_L, + SND_GENRL_WEAPONS_AK_SHOT_R, + SND_GENRL_WEAPONS_AK_TAIL_L, + audioEvent + ); case WEAPON_TEC9: - return PlayGunSounds(entity, 29, 30, 0, 1, 2, audioEventId, 0.0f, 1.25992f, 1.0f); - + return PlayGunSounds( + parent, + SND_GENRL_WEAPONS_9MM1DRY, + SND_GENRL_WEAPONS_9MM1LOWS, + SND_GENRL_WEAPONS_9MM1SHOT_L, + SND_GENRL_WEAPONS_9MM1SHOT_R, + SND_GENRL_WEAPONS_9MM1TAIL, + audioEvent, + 0.0f, + 1.25992f + ); case WEAPON_COUNTRYRIFLE: - return PlayGunSounds(entity, 52, 53, 26, 27, 23, audioEventId, 0.0f, 0.89f, 1.0f); - + return PlayGunSounds( + parent, + SND_GENRL_WEAPONS_EAGLE_DRYFIRE, + SND_GENRL_WEAPONS_EAGLE_LOWS, + SND_GENRL_WEAPONS_SNIPER_SHOT_L, + SND_GENRL_WEAPONS_SNIPER_SHOT_R, + SND_GENRL_WEAPONS_SHOTGUN_TAIL_R, + audioEvent, + 0.0f, + 0.89f + ); case WEAPON_SNIPERRIFLE: - return PlayGunSounds(entity, 52, 53, 26, 27, 23, audioEventId, 0.0f, 1.0f, 1.0f); - - case WEAPON_FLAMETHROWER: - if (!m_nFlameThrowerLastPlayedTime) - PlayFlameThrowerSounds(entity, 83, 26, audioEventId, -14.0f, 1.0f); - m_nFlameThrowerLastPlayedTime = CTimer::GetTimeInMS(); + return PlayGunSounds( + parent, + SND_GENRL_WEAPONS_EAGLE_DRYFIRE, + SND_GENRL_WEAPONS_EAGLE_LOWS, + SND_GENRL_WEAPONS_SNIPER_SHOT_L, + SND_GENRL_WEAPONS_SNIPER_SHOT_R, + SND_GENRL_WEAPONS_SHOTGUN_TAIL_R, + audioEvent + ); + case WEAPON_FLAMETHROWER: { + if (!std::exchange(m_LastFlameThrowerFireTimeMs, CTimer::GetTimeInMS())) { + PlayFlameThrowerSounds( + parent, + SND_GENRL_WEAPONS_TRIGGER, + SND_GENRL_WEAPONS_SNIPER_SHOT_L, + audioEvent, + -14.f, + 1.f + ); + } break; - + } case WEAPON_MINIGUN: - return PlayMiniGunFireSounds(entity, audioEventId); - + return PlayMiniGunFireSounds(parent, audioEvent); case WEAPON_DETONATOR: - return PlayGunSounds(entity, 49, -1, -1, -1, -1, audioEventId, -14.0f, 1.0f, 1.0f); - + return PlayGunSounds( + parent, + SND_GENRL_WEAPONS_DETONATOR_BEEP, + SND_GENRL_WEAPONS_UNK, + SND_GENRL_WEAPONS_UNK, + SND_GENRL_WEAPONS_UNK, + SND_GENRL_WEAPONS_UNK, + audioEvent, + -14.0f + ); case WEAPON_SPRAYCAN: - if (!m_nSpraycanLastPlayedTime) - PlayWeaponLoopSound(entity, 28, audioEventId, -20.0f, 1.0f, AE_FRONTEND_HIGHLIGHT); - - m_nSpraycanLastPlayedTime = CTimer::GetTimeInMS(); + if (!std::exchange(m_LastSprayCanFireTimeMs, CTimer::GetTimeInMS())) { + PlayWeaponLoopSound( + parent, + SND_GENRL_WEAPONS_SPRAY_PAINT, + audioEvent, + -20.0, + 1.0f, + AE_WEAPON_SOUND_CAT_SPRAY + ); + } break; - case WEAPON_EXTINGUISHER: - if (!m_nExtinguisherLastPlayedTime) - PlayWeaponLoopSound(entity, 9, audioEventId, -20.0f, 0.79369998f, AE_FRONTEND_ERROR); - - m_nExtinguisherLastPlayedTime = CTimer::GetTimeInMS(); + if (!std::exchange(m_LastFireExtFireTimeMs, CTimer::GetTimeInMS())) { + PlayWeaponLoopSound( + parent, + SND_GENRL_WEAPONS_FIRE_EXT, + audioEvent, + -20.0, + 0.79369998f, + AE_WEAPON_SOUND_CAT_EXT + ); + } break; - case WEAPON_CAMERA: - return PlayCameraSound(entity, audioEventId, -14.0); - + return PlayCameraSound(parent, audioEvent, -14.0); case WEAPON_NIGHTVISION: case WEAPON_INFRARED: - return PlayGoggleSound(64, audioEventId); - + return PlayGoggleSound(SND_GENRL_WEAPONS_NIGHT_VISION, audioEvent); default: - return; + NOTSA_UNREACHABLE(); } } @@ -129,60 +265,233 @@ void CAEWeaponAudioEntity::WeaponReload(eWeaponType type, CPhysical* entity, eAu return; } - int16 soundType; - float volumeOffset = 0.0f; + const auto PlaySound = [&](tSoundID soundID, float volumeOffsetdB = 0.f) { + CAESound s; + s.Initialise( + 5, + soundID, + this, + entity->GetPosition(), + GetDefaultVolume(event) + volumeOffsetdB, + 2.f / 3.f, + 1.0f, + 1.0f, + 0, + SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY + ); + s.RegisterWithPhysicalEntity(entity); + AESoundManager.RequestNewSound(&s); + }; switch (type) { case WEAPON_PISTOL: case WEAPON_PISTOL_SILENCED: - soundType = event != AE_WEAPON_RELOAD_A ? 66 : 55; - break; + return PlaySound(event == AE_WEAPON_RELOAD_A ? 55 : 66); case WEAPON_DESERT_EAGLE: - soundType = 4 * (event == AE_WEAPON_RELOAD_A) + 51; - break; + return PlaySound(event == AE_WEAPON_RELOAD_A ? 55 : 51); case WEAPON_SHOTGUN: case WEAPON_SPAS12_SHOTGUN: - soundType = (event != AE_WEAPON_RELOAD_A) + 71; - break; + return PlaySound(event == AE_WEAPON_RELOAD_A ? 72 : 71); case WEAPON_SAWNOFF_SHOTGUN: - soundType = (event != AE_WEAPON_RELOAD_A) + 69; - break; + return PlaySound(event == AE_WEAPON_RELOAD_A ? 70 : 69); case WEAPON_MICRO_UZI: case WEAPON_MP5: case WEAPON_TEC9: - soundType = (event != AE_WEAPON_RELOAD_A) + 84; - break; + return PlaySound(event == AE_WEAPON_RELOAD_A ? 85 : 84); case WEAPON_AK47: case WEAPON_M4: - soundType = (event != AE_WEAPON_RELOAD_A) + 31; - break; + return PlaySound(event == AE_WEAPON_RELOAD_A ? 32 : 31); case WEAPON_COUNTRYRIFLE: - if (event != AE_WEAPON_RELOAD_A) - return; - soundType = 32; - volumeOffset = -6.0f; + if (event == AE_WEAPON_RELOAD_A) { + return PlaySound(32, -6.f); + } break; case WEAPON_SNIPERRIFLE: - soundType = event != AE_WEAPON_RELOAD_A ? 32 : 55; - break; - default: + return PlaySound(event == AE_WEAPON_RELOAD_A ? 55 : 32); + } +} + + +// 0x503CE0 +void CAEWeaponAudioEntity::PlayGunSounds( + CPhysical* entity, + int16 dryFireSfxID, + int16 subSfxID, + int16 mainLeftSfxID, + int16 mainRightSfxID, + int16 tailSfxID, + eAudioEvents audioEvent, + float volumeOffsetdB, + float primarySpeed, + float tailFrequencyScalingFactor +) { + if (!AEAudioHardware.IsSoundBankLoaded(143u, 5)) { + if (!AudioEngine.IsLoadingTuneActive()) { + AEAudioHardware.LoadSoundBank(143, 5); + } return; } - const auto volume = GetDefaultVolume(event) + volumeOffset; + if (CTimer::GetTimeInMS() < m_LastGunFireTimeMs + 25) { + return; + } + m_LastGunFireTimeMs = CTimer::GetTimeInMS(); + + auto baseVolume = GetDefaultVolume(audioEvent) + volumeOffsetdB; + auto [baseRollOffFactor, baseSpeed] = [&]() -> std::pair { + switch (audioEvent) { + case AE_WEAPON_FIRE_PLANE: { + m_LastWeaponPlaneFrequencyIndex = (m_LastWeaponPlaneFrequencyIndex + 1) % 2; + return {1.6f, gfWeaponPlaneFrequencyVariations[m_LastWeaponPlaneFrequencyIndex] * primarySpeed * 0.7937f}; + } + case AE_WEAPON_FIRE_MINIGUN_PLANE: { + return {1.8f, primarySpeed * 0.7937f}; + } + default: { + return {1.f, primarySpeed}; + } + } + }(); + + const auto PlaySound = [&](int16 sfxID, CVector pos, float volume, float rollOffFactor, float speed, uint32 flags, eAudioEvents audioEventOverride = AE_UNDEFINED) { + CAESound s; + s.Initialise( + 5, + sfxID, + this, + pos, + volume, + rollOffFactor, + speed, + 0.f, + 0, + flags + ); + if (flags & SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY) { + s.RegisterWithPhysicalEntity(entity); + } + if (audioEventOverride == AE_UNDEFINED) { + switch (audioEvent) { + case AE_WEAPON_FIRE_MINIGUN_PLANE: + case AE_WEAPON_FIRE_MINIGUN_AMMO: + s.m_nEvent = AE_FRONTEND_PICKUP_WEAPON; + } + } else { + s.m_nEvent = audioEventOverride; + } + AESoundManager.RequestNewSound(&s); + }; + + if (dryFireSfxID != -1) { // 0x503DFF + PlaySound( + dryFireSfxID, + entity->GetPosition(), + baseVolume, + baseRollOffFactor * (2.f / 3.f), + baseSpeed, + SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY | SOUND_REQUEST_UPDATES + ); + } + if (subSfxID != -1) { // 0x503E93 + PlaySound( + subSfxID, + entity->GetPosition(), + baseVolume, + baseRollOffFactor * 0.9f, + baseSpeed, + SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY | SOUND_REQUEST_UPDATES + ); + } + + // 0x503F21 + float frontEndVolume = -100.f; + if (!notsa::contains({ AE_WEAPON_FIRE_PLANE, AE_WEAPON_FIRE_MINIGUN_PLANE }, audioEvent)) { + const auto dist = CAEAudioEnvironment::GetPositionRelativeToCamera(entity).Magnitude() / (baseRollOffFactor * 1.25f); + if (dist < (5.f / baseRollOffFactor)) { // Inverted + baseVolume -= 3.f; + frontEndVolume = baseVolume + CAEAudioEnvironment::GetDistanceAttenuation(dist); + } else if (dist < (12.f / baseRollOffFactor)) { + const auto t = ((12.f / baseRollOffFactor) - dist) / (12.f / baseRollOffFactor) - (5.f / baseRollOffFactor); + frontEndVolume = baseVolume + CAEAudioEnvironment::GetDistanceAttenuation(dist) + std::log10f(t * (SQRT_2 / 2.f)) * 20.f; + baseVolume += std::log10f(((1.f - t) * 0.2929f) + (SQRT_2 / 2.f)) * 20.f; + } + } - m_tempSound.Initialise(5, soundType, this, entity->GetPosition(), volume, 0.66f, 1.0f, 1.0f, 0, SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY, 0.0f, 0); - m_tempSound.RegisterWithPhysicalEntity(entity); - AESoundManager.RequestNewSound(&m_tempSound); + const auto PlayMainSound = [ + &, + mainSoundSpeed = (CAEAudioUtility::GetRandomNumberInRange(-0.02f, 0.02f) + 1.f) * baseSpeed + ](int16 sfxID, bool isRight) { + PlaySound( + sfxID, + CVector{isRight ? 1.f : -1.f, 0.f, 0.f}, + frontEndVolume, + baseRollOffFactor * 1.25f, + mainSoundSpeed, + SOUND_FORCED_FRONT | SOUND_REQUEST_UPDATES | SOUND_FRONT_END + ); + PlaySound( + sfxID, + entity->GetPosition(), + baseVolume, + baseRollOffFactor * 1.25f, + mainSoundSpeed, + SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY | SOUND_REQUEST_UPDATES + ); + }; + if (mainLeftSfxID != -1) { // 0x5040DC + 0x5041DF + PlayMainSound(mainLeftSfxID, false); + } + if (mainRightSfxID != -1) { // 0x504153 + 0x504218 + PlayMainSound(mainRightSfxID, true); + } + + if (tailSfxID != -1 && !notsa::contains({AE_WEAPON_FIRE_PLANE, AE_WEAPON_FIRE_MINIGUN_PLANE}, audioEvent)) { + const auto tailSoundRollOff = baseRollOffFactor * 3.5f; + const auto tailSoundVolume = CAEAudioEnvironment::GetDistanceAttenuation(CAEAudioEnvironment::GetPositionRelativeToCamera(entity).Magnitude() / tailSoundRollOff) + baseVolume - 20.f; + const auto tailSoundAudioEvent = audioEvent == AE_WEAPON_FIRE_MINIGUN_AMMO + ? AE_FRONTEND_PICKUP_MONEY + : AE_FRONTEND_SELECT; + const auto PlayTailSound = [&](bool isRight, float speedMult) { + PlaySound( + tailSfxID, + CVector{ isRight ? 1.f : -1, 0.f, 0.f }, + tailSoundVolume, + tailSoundRollOff, + tailFrequencyScalingFactor * speedMult, + SOUND_FORCED_FRONT | SOUND_ROLLED_OFF | SOUND_REQUEST_UPDATES | SOUND_FRONT_END, + tailSoundAudioEvent + ); + }; + float speedMultA = 1.f, + speedMultB = 1.1892101f; + if (CAEAudioUtility::ResolveProbability(0.5f)) { + std::swap(speedMultA, speedMultB); + } + PlayTailSound(false, speedMultA); + PlayTailSound(true, speedMultB); + } } // 0x503B20 void CAEWeaponAudioEntity::ReportStealthKill(eWeaponType type, CPhysical* entity, eAudioEvents event) { - if (type != WEAPON_KNIFE) + if (type != WEAPON_KNIFE) { return; + } - const auto vol = GetDefaultVolume(event); - const auto flags = static_cast(SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY | SOUND_REQUEST_UPDATES); + const auto PlayStealthKillSound = [&](int16 bankSlotID, tSoundID soundID, float volumeOffsetdB, int32 eventID) { + AESoundManager.PlaySound({ + .BankSlotID = bankSlotID, + .SoundID = soundID, + .AudioEntity = this, + .Pos = entity->GetPosition(), + .Volume = GetDefaultVolume(event) + volumeOffsetdB, + .Speed = 0.0f, // ??? + .Flags = SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY | SOUND_REQUEST_UPDATES, + .RegisterWithEntity = entity, + .EventID = eventID, + .ClientVariable = (float)CTimer::GetTimeInMS(), + }); + }; if (!AEAudioHardware.IsSoundBankLoaded(143, 5)) { if (!AudioEngine.IsLoadingTuneActive()) { @@ -190,11 +499,7 @@ void CAEWeaponAudioEntity::ReportStealthKill(eWeaponType type, CPhysical* entity } return; } - m_tempSound.Initialise(5, 81, this, entity->GetPosition(), vol - 6.0f, 1.0f, 0.0f, 1.0f, 0); - m_tempSound.RegisterWithPhysicalEntity(entity); - m_tempSound.m_nEvent = AE_FRONTEND_PICKUP_COLLECTABLE1; - m_tempSound.m_fMaxVolume = (float)CTimer::m_snTimeInMilliseconds; - AESoundManager.RequestNewSound(&m_tempSound); + PlayStealthKillSound(5, 81, -6.f, AE_WEAPON_SOUND_CAT_STEALTH_KNIFE_IN); if (!AEAudioHardware.IsSoundBankLoaded(39, 2)) { if (!AudioEngine.IsLoadingTuneActive()) { @@ -202,44 +507,109 @@ void CAEWeaponAudioEntity::ReportStealthKill(eWeaponType type, CPhysical* entity } return; } - m_tempSound.Initialise(2, 47, this, entity->GetPosition(), vol, 1.0f, 0.0f, 1.0f, 0, flags); - m_tempSound.RegisterWithPhysicalEntity(entity); - m_tempSound.m_nEvent = AE_FRONTEND_CAR_NO_CASH; - m_tempSound.m_fMaxVolume = (float)CTimer::GetTimeInMS(); - AESoundManager.RequestNewSound(&m_tempSound); + PlayStealthKillSound(2, 471, 0.f, AE_WEAPON_SOUND_CAT_STEALTH_KNIFE_OUT); } // 0x503910 -void CAEWeaponAudioEntity::ReportChainsawEvent(CPhysical* entity, int32 audioEventId) { - plugin::CallMethod<0x503910, CAEWeaponAudioEntity*, CPhysical*, int32>(this, entity, audioEventId); +void CAEWeaponAudioEntity::ReportChainsawEvent(CPhysical* entity, eAudioEvents audioEvent) { + if (!AEAudioHardware.IsSoundBankLoaded(36, 40)) { + if (AESoundManager.AreSoundsPlayingInBankSlot(40)) { + AESoundManager.CancelSoundsInBankSlot(40, false); + } + AEAudioHardware.LoadSoundBank(36, 40); + return; + } + + const auto PlaySoundIfNotPlaying = [&](int16 sfxID, float rollOffFactor, eWeaponSoundCategories soundCat) { + if (AESoundManager.AreSoundsOfThisEventPlayingForThisEntity(soundCat, this) != SOUND_NOT_PLAYING) { + return; + } + CAESound s; + s.Initialise( + 40, + sfxID, + this, + entity->GetPosition(), + GetDefaultVolume(audioEvent), + rollOffFactor, + 1.f, + 0.f, + 0, + SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY | SOUND_REQUEST_UPDATES + ); + s.m_nEvent = soundCat; + s.RegisterWithPhysicalEntity(entity); + AESoundManager.RequestNewSound(&s); + }; + + switch (audioEvent) { + case AE_WEAPON_CHAINSAW_IDLE: { // 0x503A6E + switch (m_ChainsawState) { + case eChainsawState::STOPPED: + case eChainsawState::IDLE: { + PlaySoundIfNotPlaying(1, 2.f / 3.f, AE_WEAPON_SOUND_CAT_CHAINSAW_IDLE); + + m_ChainsawState = eChainsawState::IDLE; + m_LastChainsawEventTimeMs = CTimer::GetTimeInMS(); + } + } + break; + } + case AE_WEAPON_CHAINSAW_ACTIVE: { // 0x5039C0 + switch (m_ChainsawState) { + case eChainsawState::STOPPING: + case eChainsawState::ACTIVE: + case eChainsawState::IDLE: { + PlaySoundIfNotPlaying(0, 1.25f, AE_WEAPON_SOUND_CAT_CHAINSAW_ACTIVE); + + m_ChainsawState = eChainsawState::ACTIVE; + m_LastChainsawEventTimeMs = CTimer::GetTimeInMS(); + } + } + break; + } + case AE_WEAPON_CHAINSAW_CUTTING: { // 0x503996 + switch (m_ChainsawState) { + case eChainsawState::ACTIVE: + case eChainsawState::CUTTING: { + m_ChainsawState = eChainsawState::CUTTING; + m_LastChainsawEventTimeMs = CTimer::GetTimeInMS(); + } + } + break; + } + } } // 0x504610 -void CAEWeaponAudioEntity::PlayWeaponLoopSound(CPhysical* entity, int16 sfxId, eAudioEvents startEvent, float audability, float speed, eAudioEvents endEvent) { +void CAEWeaponAudioEntity::PlayWeaponLoopSound(CPhysical* entity, int16 sfxId, eAudioEvents startEvent, float volumeOffsetdB, float speed, eWeaponSoundCategories soundCat) { if (!AEAudioHardware.IsSoundBankLoaded(143u, 5)) { if (!AudioEngine.IsLoadingTuneActive()) { AEAudioHardware.LoadSoundBank(143, 5); } return; } - - const auto volume = GetDefaultVolume(startEvent) + audability; - const auto flags = static_cast(SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY | SOUND_START_PERCENTAGE | SOUND_REQUEST_UPDATES); - m_tempSound.Initialise(5, sfxId, this, entity->GetPosition(), volume, 1.0f, speed, 1.0f, 0, flags); - m_tempSound.RegisterWithPhysicalEntity(entity); - m_tempSound.m_nEvent = endEvent; - AESoundManager.RequestNewSound(&m_tempSound); + AESoundManager.PlaySound({ + .BankSlotID = 5, + .SoundID = sfxId, + .AudioEntity = this, + .Pos = entity->GetPosition(), + .Volume = GetDefaultVolume(startEvent) + volumeOffsetdB, + .Speed = speed, + .Flags = SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY | SOUND_START_PERCENTAGE | SOUND_REQUEST_UPDATES, + .RegisterWithEntity = entity, + .EventID = soundCat, + }); } // 0x504960 void CAEWeaponAudioEntity::PlayMiniGunStopSound(CPhysical* entity) { if (!entity) { - m_nState = 3; + m_MiniGunState = eMiniGunState::STOPPED; return; } - if (m_nState == 2) { // todo: figure out what is that - m_nState = 2; + if (m_MiniGunState == eMiniGunState::STOPPING) { return; } @@ -250,101 +620,195 @@ void CAEWeaponAudioEntity::PlayMiniGunStopSound(CPhysical* entity) { return; } - const auto [distMult, speed] = [&] { - if (entity->IsVehicle() && entity->AsVehicle()->IsSubPlane()) { - return std::make_pair(1.8f, 0.7937f); - } else { - return std::make_pair(1.0f, 1.0f); - } - }(); - const auto dist = distMult * 0.66f; - const auto volume = CAEAudioEntity::GetDefaultVolume(AE_WEAPON_FIRE_MINIGUN_STOP); - const auto flags = static_cast(SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY | SOUND_REQUEST_UPDATES); - m_tempSound.Initialise(5, 63, this, entity->GetPosition(), volume, dist, speed, 1.0f, 0, flags); - m_tempSound.RegisterWithPhysicalEntity(entity); - m_tempSound.m_nEvent = AE_FRONTEND_PICKUP_HEALTH; - AESoundManager.RequestNewSound(&m_tempSound); - m_nState = 2; + const auto PlayMiniGunFireStopSound = [&](float speed, float maxDist) { + CAESound s; + s.Initialise( + 5, + 63, + this, + entity->GetPosition(), + GetDefaultVolume(AE_WEAPON_FIRE_MINIGUN_STOP), + maxDist * 2.f / 3.f, // *0.66f....f + speed, + 1.0f, + 0, + SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY | SOUND_REQUEST_UPDATES + ); + s.RegisterWithPhysicalEntity(entity); + s.m_nEvent = AE_FRONTEND_PICKUP_HEALTH; // ??? + AESoundManager.RequestNewSound(&s); + }; + if (entity->IsVehicle() && entity->AsVehicle()->IsSubPlane()) { + PlayMiniGunFireStopSound(1.8f, 0.7937f); + } else { + PlayMiniGunFireStopSound(1.f, 1.f); + } + m_MiniGunState = eMiniGunState::STOPPING; } // 0x5047C0 -void CAEWeaponAudioEntity::PlayMiniGunFireSounds(CPhysical* entity, int32 audioEventId) { - plugin::CallMethod<0x5047C0, CAEWeaponAudioEntity*, CPhysical*, int32>(this, entity, audioEventId); -} - -// 0x503CE0 -void CAEWeaponAudioEntity::PlayGunSounds(CPhysical* entity, int16 emptySfxId, int16 farSfxId2, int16 highPitchSfxId3, int16 lowPitchSfxId4, int16 echoSfxId5, int32 audioEventId, float volumeChange, float speed1, float speed2) { - plugin::CallMethod<0x503CE0, CAEWeaponAudioEntity*, CPhysical*, int16, int16, int16, int16, int16, int32, float, float, float>( - this, entity, emptySfxId, farSfxId2, highPitchSfxId3, lowPitchSfxId4, echoSfxId5, audioEventId, volumeChange, speed1, speed2); +void CAEWeaponAudioEntity::PlayMiniGunFireSounds(CPhysical* entity, eAudioEvents audioEvent) { + const auto PlayMiniGunFireSound = [&](eAudioEvents gunFireAE) { + m_MiniGunState = eMiniGunState::FIRING; + if (!std::exchange(m_IsMiniGunFireActive, true)) { + PlayGunSounds(entity, 15, 16, 11, 12, 13, gunFireAE, 0.f, 1.f, 1.f); + } + }; + switch (audioEvent) { + case AE_WEAPON_FIRE: + case AE_WEAPON_FIRE_MINIGUN_AMMO: { // 0x504912 + PlayMiniGunFireSound(AE_WEAPON_FIRE_MINIGUN_AMMO); + break; + } + case AE_WEAPON_FIRE_PLANE: { // 0x5047E6 + PlayMiniGunFireSound(AE_WEAPON_FIRE_MINIGUN_PLANE); + break; + } + case AE_WEAPON_FIRE_MINIGUN_NO_AMMO: { // 0x5048FC - Minigun is just spinning + if (!m_IsMiniGunSpinActive) { + if (!AEAudioHardware.IsSoundBankLoaded(143, 5)) { // SND_BANK_GENRL_WEAPONS, SND_BANK_SLOT_WEAPON_GEN + if (!AudioEngine.IsLoadingTuneActive()) { + AEAudioHardware.LoadSoundBank(143, 5); + } + break; + } + AESoundManager.PlaySound({ + .BankSlotID = 5, + .SoundID = 14, + .AudioEntity = this, + .Pos = entity->GetPosition(), + .Volume = GetDefaultVolume(AE_WEAPON_FIRE_MINIGUN_NO_AMMO), + .RollOffFactor = 2.f / 3.f, + .Speed = 1.f, + .Doppler = 0.f, + .Flags = SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY | SOUND_REQUEST_UPDATES, + .RegisterWithEntity = entity, + .EventID = AE_WEAPON_SOUND_CAT_MINIGUN_SPIN + }); + m_IsMiniGunSpinActive = true; + } + m_MiniGunState = eMiniGunState::SPINNING; + break; + } + } + m_LastMiniGunFireTimeMs = CTimer::GetTimeInMS(); } // 0x503500 void CAEWeaponAudioEntity::PlayGoggleSound(int16 sfxId, eAudioEvents event) { - const auto volume = GetDefaultVolume(event); if (!AEAudioHardware.IsSoundBankLoaded(143u, 5)) { if (!AudioEngine.IsLoadingTuneActive()) { AEAudioHardware.LoadSoundBank(143, 5); } return; } - - const auto [speed0, speed1] = [] { - if (CAEAudioUtility::ResolveProbability(0.5f)) { - return std::make_pair(1.1892101f, 1.0f); - } else { - return std::make_pair(1.0f, 1.1892101f); - } - }(); - const auto vol = volume - 9.0f; - - m_tempSound.Initialise(5, sfxId, this, { -1.0f, 0.0f, 0.0f }, vol, 1.0f, speed0, 1.0f, 0, SOUND_DEFAULT); - m_tempSound.m_nEnvironmentFlags = SOUND_FRONT_END | SOUND_FORCED_FRONT; - AESoundManager.RequestNewSound(&m_tempSound); - - m_tempSound.Initialise(5, sfxId, this, { +1.0f, 0.0f, 0.0f }, vol, 1.0f, speed1, 1.0f, 0, SOUND_DEFAULT); - m_tempSound.m_nEnvironmentFlags = SOUND_FRONT_END | SOUND_FORCED_FRONT; - AESoundManager.RequestNewSound(&m_tempSound); + const auto PlaySound = [&](float offsetX, float speed) { + CAESound s; + s.Initialise(5, sfxId, this, { offsetX, 0.0f, 0.0f }, GetDefaultVolume(event) - 9.f, 1.0f, speed, 1.0f, 0, SOUND_DEFAULT); + s.m_nEnvironmentFlags = SOUND_FRONT_END | SOUND_FORCED_FRONT; + AESoundManager.RequestNewSound(&s); + }; + const auto r = CAEAudioUtility::ResolveProbability(0.5f); + PlaySound(-1.0f, r ? 1.1892101f : 1.f); + PlaySound(+1.0f, r ? 1.f : 1.1892101f); } // 0x504470 -void CAEWeaponAudioEntity::PlayFlameThrowerSounds(CPhysical* entity, int16 sfx1, int16 sfx2, int32 audioEventId, float audability, float speed) { - plugin::CallMethod<0x504470, CAEWeaponAudioEntity*, CPhysical*, int16, int16, int32, float, float>(this, entity, sfx1, sfx2, audioEventId, audability, speed); +void CAEWeaponAudioEntity::PlayFlameThrowerSounds(CPhysical* entity, int16 dryFireSfxID, int16 flameSfxID, eAudioEvents audioEvent, float volumeOffsetdB, float speed) { + const auto PlaySound = [&](int16 bankSlotID, int16 sfxID, float sfxVolumeOffsetdB, float rollOffFactor, float sfxSpeed, float sfxFreqVariance, eAudioEvents sfxAE) { + CAESound s; + s.Initialise( + bankSlotID, + sfxID, + this, + entity->GetPosition(), + GetDefaultVolume(audioEvent) + volumeOffsetdB + sfxVolumeOffsetdB, + rollOffFactor, + sfxSpeed, + 1.f, + 0, + SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY|SOUND_REQUEST_UPDATES, + sfxFreqVariance + ); + s.m_nEvent = sfxAE; + s.RegisterWithPhysicalEntity(entity); + AESoundManager.RequestNewSound(&s); + }; + + if (!AEAudioHardware.IsSoundBankLoaded(143u, 5)) { + if (!AudioEngine.IsLoadingTuneActive()) { + AEAudioHardware.LoadSoundBank(143, 5); + } + return; + } + PlaySound( + 5, + dryFireSfxID, + -6.f, + 2.f / 3.f, + speed, + 0.02f, + AE_UNDEFINED + ); + + if (!AEAudioHardware.IsSoundBankLoaded(138, 19)) { + AEAudioHardware.LoadSoundBank(138, 19); + return; + } + PlaySound( + 19, + flameSfxID, + -20.f, + 2.f, + speed * 0.79369998f, + 0.f, + AE_FRONTEND_BACK + ); } // 0x503870 void CAEWeaponAudioEntity::PlayFlameThrowerIdleGasLoop(CPhysical* entity) { - if (m_FlameThrowerSound != nullptr) + if (m_FlameThrowerIdleGasLoopSound != nullptr) { return; - - const auto volume = GetDefaultVolume(AE_FLAMETHROWER_IDLE); - const auto flags = static_cast(SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY | SOUND_REQUEST_UPDATES); - m_tempSound.Initialise(5, 10, this, entity->GetPosition(), volume, 0.66f, 1.0f, 1.0f, 0, flags); - m_tempSound.RegisterWithPhysicalEntity(entity); - m_FlameThrowerSound = AESoundManager.RequestNewSound(&m_tempSound); + } + m_FlameThrowerIdleGasLoopSound = AESoundManager.PlaySound({ + .BankSlotID = 5, + .SoundID = 10, + .AudioEntity = this, + .Pos = entity->GetPosition(), + .Volume = GetDefaultVolume(AE_FLAMETHROWER_IDLE), + .RollOffFactor = 2.f / 3.f, + .Flags = SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY | SOUND_REQUEST_UPDATES, + .RegisterWithEntity = entity + }); } // 0x5034E0 void CAEWeaponAudioEntity::StopFlameThrowerIdleGasLoop() { - if (m_FlameThrowerSound) { - m_FlameThrowerSound->StopSoundAndForget(); - m_FlameThrowerSound = nullptr; + if (auto* const s = std::exchange(m_FlameThrowerIdleGasLoopSound, nullptr)) { + s->StopSoundAndForget(); } } // 0x504AA0 void CAEWeaponAudioEntity::PlayChainsawStopSound(CPhysical* entity) { - if (entity && AEAudioHardware.IsSoundBankLoaded(0x24u, 40)) { - if (m_nChainsawSoundState != 3) { - const auto volume = GetDefaultVolume(AE_WEAPON_CHAINSAW_ACTIVE); - const auto flags = static_cast(SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY | SOUND_REQUEST_UPDATES); - m_tempSound.Initialise(40, 2, this, entity->GetPosition(), volume, 0.66f, 1.0f, 1.0f, 0, flags); - m_tempSound.RegisterWithPhysicalEntity(entity); - m_tempSound.m_nEvent = AE_FRONTEND_PICKUP_DRUGS; - AESoundManager.RequestNewSound(&m_tempSound); - } - m_nChainsawSoundState = 3; + if (entity && AEAudioHardware.IsSoundBankLoaded(36, 40)) { + if (m_ChainsawState != eChainsawState::STOPPING) { + AESoundManager.PlaySound({ + .BankSlotID = 40, + .SoundID = 2, + .AudioEntity = this, + .Pos = entity->GetPosition(), + .Volume = GetDefaultVolume(AE_WEAPON_CHAINSAW_ACTIVE), + .RollOffFactor = 2.f / 3.f, + .Flags = SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY | SOUND_REQUEST_UPDATES, + .RegisterWithEntity = entity, + .EventID = AE_WEAPON_SOUND_CAT_CHAINSAW_STOP + }); + } + m_ChainsawState = eChainsawState::STOPPING; } else { - m_nChainsawSoundState = 4; + m_ChainsawState = eChainsawState::STOPPED; } } @@ -356,54 +820,164 @@ void CAEWeaponAudioEntity::PlayCameraSound(CPhysical* entity, eAudioEvents event } return; } - - const auto vol = GetDefaultVolume(event) + audability; - const auto flags = static_cast(SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY | SOUND_UNPAUSABLE); - m_tempSound.Initialise(5, 45, this, entity->GetPosition(), vol, 0.66f, 1.0f, 1.0f, 0, flags); - m_tempSound.RegisterWithPhysicalEntity(entity); - AESoundManager.RequestNewSound(&m_tempSound); + AESoundManager.PlaySound({ + .BankSlotID = 5, + .SoundID = 45, + .AudioEntity = this, + .Pos = entity->GetPosition(), + .Volume = GetDefaultVolume(event), + .RollOffFactor = 2.f / 3.f, + .Flags = SOUND_LIFESPAN_TIED_TO_PHYSICAL_ENTITY | SOUND_UNPAUSABLE, // NOTE/BUG: `UNPAUSABLE` typo? + .RegisterWithEntity = entity, + .EventID = AE_WEAPON_SOUND_CAT_CHAINSAW_STOP + }); } // 0x504B70 -void CAEWeaponAudioEntity::UpdateParameters(CAESound *sound, int16 curPlayPos) { - plugin::CallMethod<0x504B70, CAEWeaponAudioEntity*, CAESound*, int16>(this, sound, curPlayPos); +void CAEWeaponAudioEntity::UpdateParameters(CAESound* sound, int16 curPlayPos) { + if (curPlayPos == -1) { + if (sound == m_FlameThrowerIdleGasLoopSound) { + m_FlameThrowerIdleGasLoopSound = nullptr; + } else if (sound->m_nEvent == AE_WEAPON_SOUND_CAT_MINIGUN_STOP && m_MiniGunState == eMiniGunState::STOPPING) { + m_MiniGunState = eMiniGunState::STOPPED; + } + return; + } + + switch (sound->m_nEvent) { + case AE_WEAPON_SOUND_CAT_TAIL: { // 0x504BAA + if (!CGame::CanSeeOutSideFromCurrArea()) { + sound->m_fVolume -= 1.f; + } + break; + } + case AE_WEAPON_SOUND_CAT_FLAME: { // 0x504BC3 + if (m_LastFlameThrowerFireTimeMs + 300 >= CTimer::GetTimeInMS()) { + sound->m_fVolume = std::max(GetDefaultVolume(AE_WEAPON_FIRE), sound->m_fVolume + 2.f); // TODO: Use TimeStep + } else { + sound->StopSoundAndForget(); + m_LastFlameThrowerFireTimeMs = 0; + } + break; + } + case AE_WEAPON_SOUND_CAT_SPRAY: { // 0x504C38 + if (m_LastSprayCanFireTimeMs + 300 < CTimer::GetTimeInMS()) { + sound->StopSoundAndForget(); + m_LastSprayCanFireTimeMs = 0; + } + break; + } + case AE_WEAPON_SOUND_CAT_EXT: { // 0x504C5F + if (m_LastFireExtFireTimeMs + 300 >= CTimer::GetTimeInMS()) { + sound->m_fSpeed = std::max(0.85f, sound->m_fSpeed + 0.01f); // TODO: Use TimeStep + } else { + sound->StopSoundAndForget(); + m_LastFireExtFireTimeMs = 0; + } + break; + } + case AE_WEAPON_SOUND_CAT_MINIGUN_SPIN: { // 0x504CBC + if (m_LastMiniGunFireTimeMs + 300 < CTimer::GetTimeInMS()) { + PlayMiniGunStopSound(sound->m_pPhysicalEntity->AsPhysical()); + } + switch (m_MiniGunState) { + case eMiniGunState::STOPPING: + case eMiniGunState::STOPPED: { + sound->StopSoundAndForget(); + m_IsMiniGunSpinActive = 0; + } + } + break; + } + case AE_WEAPON_SOUND_CAT_MINIGUN_FIRE: { // 0x504CFB + if (m_LastMiniGunFireTimeMs + 300 < CTimer::GetTimeInMS()) { + PlayMiniGunStopSound(sound->m_pPhysicalEntity->AsPhysical()); + } + if (m_MiniGunState != eMiniGunState::FIRING) { + sound->StopSoundAndForget(); + m_IsMiniGunFireActive = 0; + } + break; + } + case AE_WEAPON_SOUND_CAT_MINIGUN_TAIL: { // 0x504D31 + if (m_MiniGunState != eMiniGunState::FIRING) { + if (sound->m_fVolume <= -30.0) { + sound->StopSoundAndForget(); + } else { + sound->m_fVolume -= 1.5f; + } + } + break; + } + case AE_WEAPON_SOUND_CAT_CHAINSAW_IDLE: { // 0x504D6B + if (m_LastChainsawEventTimeMs + 300 < CTimer::GetTimeInMS()) { + m_ChainsawState = eChainsawState::STOPPED; + } + if (m_ChainsawState != eChainsawState::IDLE) { + sound->StopSoundAndForget(); + } + break; + } + case AE_WEAPON_SOUND_CAT_CHAINSAW_ACTIVE: { // 0x504D9B + switch (m_ChainsawState) { + case eChainsawState::CUTTING: { // 0x504DA5 + if (m_LastChainsawEventTimeMs + 400 >= CTimer::m_snTimeInMilliseconds) { + sound->m_fSpeed = std::max(0.85f, sound->m_fSpeed - 0.15f); // TODO: Use TimeStep + } else { + m_LastChainsawEventTimeMs = CTimer::m_snTimeInMilliseconds; + m_ChainsawState = eChainsawState::ACTIVE; + } + break; + } + case eChainsawState::ACTIVE: { // 0x504E0E + sound->m_fSpeed = std::min(1.f, sound->m_fSpeed + 0.03f); // TODO: Use TimeStep + if (m_LastChainsawEventTimeMs + 300 < CTimer::GetTimeInMS()) { + PlayChainsawStopSound(sound->m_pPhysicalEntity->AsPhysical()); + } + break; + } + default: { + sound->StopSoundAndForget(); + break; + } + } + break; + } + case AE_WEAPON_SOUND_CAT_CHAINSAW_STOP: { // 0x504E66 + if (m_ChainsawState == eChainsawState::STOPPING && curPlayPos > 1'000) { + m_ChainsawState = eChainsawState::IDLE; + } + break; + } + case AE_WEAPON_SOUND_CAT_STEALTH_KNIFE_IN: { // 0x504E8B + if ((uint32)sound->m_ClientVariable + 820 < CTimer::GetTimeInMS()) { + sound->m_fSpeed = 0.84f; + } + break; + } + case AE_WEAPON_SOUND_CAT_STEALTH_KNIFE_OUT: { // 0x504EBF + if ((uint32)sound->m_ClientVariable + 2200 < CTimer::GetTimeInMS()) { + sound->m_fSpeed = 1.f; + } + break; + } + default: { // 0x504ECD + sound->m_fVolume = std::max(0.f, sound->m_fVolume - 2.5f); + break; + } + } } -void CAEWeaponAudioEntity::InjectHooks() { - RH_ScopedClass(CAEWeaponAudioEntity); - RH_ScopedCategory("Audio/Entities"); - - RH_ScopedInstall(Constructor, 0x5DE990); - RH_ScopedInstall(Destructor, 0x507560); - RH_ScopedInstall(Initialise, 0x503450); - RH_ScopedInstall(Reset, 0x503490); - RH_ScopedInstall(Terminate, 0x503480); - RH_ScopedInstall(WeaponFire, 0x504F80); - RH_ScopedInstall(WeaponReload, 0x503690); - RH_ScopedInstall(PlayChainsawStopSound, 0x504AA0); - RH_ScopedInstall(PlayMiniGunStopSound, 0x504960); - RH_ScopedInstall(PlayMiniGunFireSounds, 0x5047C0, { .reversed = false }); - RH_ScopedInstall(PlayCameraSound, 0x5046F0); - RH_ScopedInstall(PlayWeaponLoopSound, 0x504610); - RH_ScopedInstall(PlayFlameThrowerSounds, 0x504470, { .reversed = false }); - RH_ScopedInstall(PlayGunSounds, 0x503CE0, { .reversed = false }); - RH_ScopedInstall(ReportStealthKill, 0x503B20); - RH_ScopedInstall(ReportChainsawEvent, 0x503910, { .reversed = false }); - RH_ScopedInstall(PlayFlameThrowerIdleGasLoop, 0x503870); - RH_ScopedInstall(PlayGoggleSound, 0x503500); - RH_ScopedInstall(StopFlameThrowerIdleGasLoop, 0x5034E0); - RH_ScopedInstall(UpdateParameters, 0x504B70, { .reversed = false }); - +void CAEWeaponAudioEntity::Clear() { + *this = CAEWeaponAudioEntity{}; } CAEWeaponAudioEntity* CAEWeaponAudioEntity::Constructor() { - this->CAEWeaponAudioEntity::CAEWeaponAudioEntity(); + CAEWeaponAudioEntity::CAEWeaponAudioEntity(); return this; } CAEWeaponAudioEntity* CAEWeaponAudioEntity::Destructor() { - this->CAEWeaponAudioEntity::~CAEWeaponAudioEntity(); + CAEWeaponAudioEntity::~CAEWeaponAudioEntity(); return this; } - -// 0x504B70 \ No newline at end of file diff --git a/source/game_sa/Audio/entities/AEWeaponAudioEntity.h b/source/game_sa/Audio/entities/AEWeaponAudioEntity.h index 811b17da3f..abfb7f8b76 100644 --- a/source/game_sa/Audio/entities/AEWeaponAudioEntity.h +++ b/source/game_sa/Audio/entities/AEWeaponAudioEntity.h @@ -8,6 +8,7 @@ #include "AEAudioEntity.h" #include "AESound.h" +#include