From cfb64f1d247a8148b12748d8b3040afa97b2b4db Mon Sep 17 00:00:00 2001 From: Kelsi Date: Mon, 9 Feb 2026 16:25:59 -0800 Subject: [PATCH] Add bell tolls for major cities marking time Implemented periodic bell chimes that add atmosphere to major cities: Bell types by faction: - Alliance bell: Stormwind, Ironforge - Night Elf bell: Darnassus - Horde bell: Orgrimmar, Undercity - Tribal bell: Thunder Bluff Technical details: - Loads 4 bell toll sound files from Sound\Doodad - Plays every 120-180 seconds (2-3 minutes) with random variation - First bell toll 60-90 seconds after entering city - Volume at 0.5 for noticeable but not overpowering effect - Only plays when currentCity_ is set (not in wilderness) - Each city uses faction-appropriate bell sound - Separate timer (bellTollTime_) from regular city ambience - State logging for debugging bell events --- include/audio/ambient_sound_manager.hpp | 8 ++++ src/audio/ambient_sound_manager.cpp | 60 +++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/include/audio/ambient_sound_manager.hpp b/include/audio/ambient_sound_manager.hpp index fb880584..c55d53df 100644 --- a/include/audio/ambient_sound_manager.hpp +++ b/include/audio/ambient_sound_manager.hpp @@ -152,6 +152,12 @@ private: std::vector thunderbluffDaySounds_; std::vector thunderbluffNightSounds_; + // City bell sounds + std::vector bellAllianceSounds_; + std::vector bellHordeSounds_; + std::vector bellNightElfSounds_; + std::vector bellTribalSounds_; + // Active emitters std::vector emitters_; uint64_t nextEmitterId_ = 1; @@ -167,6 +173,7 @@ private: float oceanLoopTime_ = 0.0f; float zoneLoopTime_ = 0.0f; float cityLoopTime_ = 0.0f; + float bellTollTime_ = 0.0f; bool wasIndoor_ = false; bool wasBlacksmith_ = false; bool wasSwimming_ = false; @@ -191,6 +198,7 @@ private: void updateWaterAmbience(float deltaTime, bool isSwimming); void updateZoneAmbience(float deltaTime, bool isIndoor); void updateCityAmbience(float deltaTime); + void updateBellTolls(float deltaTime); bool loadSound(const std::string& path, AmbientSample& sample, pipeline::AssetManager* assets); // Time of day helpers diff --git a/src/audio/ambient_sound_manager.cpp b/src/audio/ambient_sound_manager.cpp index 61925e2f..a75514f5 100644 --- a/src/audio/ambient_sound_manager.cpp +++ b/src/audio/ambient_sound_manager.cpp @@ -183,6 +183,19 @@ bool AmbientSoundManager::initialize(pipeline::AssetManager* assets) { thunderbluffNightSounds_.resize(1); bool thunderbluffNightLoaded = loadSound("Sound\\Ambience\\WMOAmbience\\ThunderBluffNight.wav", thunderbluffNightSounds_[0], assets); + // Load bell toll sounds + bellAllianceSounds_.resize(1); + bool bellAllianceLoaded = loadSound("Sound\\Doodad\\BellTollAlliance.wav", bellAllianceSounds_[0], assets); + + bellHordeSounds_.resize(1); + bool bellHordeLoaded = loadSound("Sound\\Doodad\\BellTollHorde.wav", bellHordeSounds_[0], assets); + + bellNightElfSounds_.resize(1); + bool bellNightElfLoaded = loadSound("Sound\\Doodad\\BellTollNightElf.wav", bellNightElfSounds_[0], assets); + + bellTribalSounds_.resize(1); + bool bellTribalLoaded = loadSound("Sound\\Doodad\\BellTollTribal.wav", bellTribalSounds_[0], assets); + LOG_INFO("AmbientSoundManager: Wind loaded: ", windLoaded ? "YES" : "NO", ", Tavern loaded: ", tavernLoaded ? "YES" : "NO", ", Blacksmith loaded: ", blacksmithLoaded ? "YES" : "NO"); @@ -196,6 +209,10 @@ bool AmbientSoundManager::initialize(pipeline::AssetManager* assets) { LOG_INFO("AmbientSoundManager: City sounds - Stormwind: ", (stormwindDayLoaded && stormwindNightLoaded) ? "YES" : "NO", ", Ironforge: ", ironforgeLoaded ? "YES" : "NO", ", Orgrimmar: ", (orgrimmarDayLoaded && orgrimmarNightLoaded) ? "YES" : "NO"); + LOG_INFO("AmbientSoundManager: Bell tolls - Alliance: ", bellAllianceLoaded ? "YES" : "NO", + ", Horde: ", bellHordeLoaded ? "YES" : "NO", + ", NightElf: ", bellNightElfLoaded ? "YES" : "NO", + ", Tribal: ", bellTribalLoaded ? "YES" : "NO"); // Initialize timers with random offsets birdTimer_ = randomFloat(0.0f, 5.0f); @@ -258,6 +275,7 @@ void AmbientSoundManager::update(float deltaTime, const glm::vec3& cameraPos, bo updateWaterAmbience(deltaTime, isSwimming); updateZoneAmbience(deltaTime, isIndoor); updateCityAmbience(deltaTime); + updateBellTolls(deltaTime); // Track indoor state changes wasIndoor_ = isIndoor; @@ -522,6 +540,7 @@ void AmbientSoundManager::setCityType(CityType type) { " to ", static_cast(type)); currentCity_ = type; cityLoopTime_ = 12.0f; // Play city ambience soon after entering + bellTollTime_ = randomFloat(60.0f, 90.0f); // First bell toll after 1-1.5 minutes } } @@ -700,5 +719,46 @@ void AmbientSoundManager::updateCityAmbience(float deltaTime) { } } +void AmbientSoundManager::updateBellTolls(float deltaTime) { + // Only play bells when in a city + if (currentCity_ == CityType::NONE) return; + + bellTollTime_ += deltaTime; + + // Select appropriate bell sound based on city faction + const std::vector* bellLibrary = nullptr; + + switch (currentCity_) { + case CityType::STORMWIND: + case CityType::IRONFORGE: + bellLibrary = &bellAllianceSounds_; + break; + case CityType::DARNASSUS: + bellLibrary = &bellNightElfSounds_; + break; + case CityType::ORGRIMMAR: + case CityType::UNDERCITY: + bellLibrary = &bellHordeSounds_; + break; + case CityType::THUNDERBLUFF: + bellLibrary = &bellTribalSounds_; + break; + default: + return; + } + + // Play bell toll every 120-180 seconds (2-3 minutes) with random variation + float bellInterval = randomFloat(120.0f, 180.0f); + + if (bellLibrary && !bellLibrary->empty() && (*bellLibrary)[0].loaded) { + if (bellTollTime_ >= bellInterval) { + float volume = 0.5f * volumeScale_; // Bell tolls at moderate-high volume + AudioEngine::instance().playSound2D((*bellLibrary)[0].data, volume, 1.0f); + LOG_INFO("Bell toll ringing in city: type ", static_cast(currentCity_)); + bellTollTime_ = 0.0f; + } + } +} + } // namespace audio } // namespace wowee