mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-03 00:03:50 +00:00
Add major city ambient audio with day/night variations
Implemented city-specific ambient soundscapes for all six major cities: Alliance cities: - Stormwind: day/night crowd and marketplace sounds - Ironforge: underground forge ambience (no day/night) - Darnassus: day/night elven city sounds Horde cities: - Orgrimmar: day/night orcish city atmosphere - Undercity: underground undead ambience (no day/night) - Thunder Bluff: day/night tauren plateau sounds Technical details: - Added CityType enum (NONE, STORMWIND, IRONFORGE, DARNASSUS, ORGRIMMAR, UNDERCITY, THUNDERBLUFF) - Loads 12 city sound files from Sound\Ambience\WMOAmbience - Underground cities (Ironforge, Undercity) use single sound without day/night variants - 20s loop interval for city ambience (more frequent than zone ambience) - Volume at 0.4 for noticeable but not overwhelming urban atmosphere - Cities take priority over zone ambience to prevent mixing - updateZoneAmbience() now checks for active city and skips if in city - State change logging for debugging city transitions
This commit is contained in:
parent
979d5db602
commit
d8e2e51f49
2 changed files with 121 additions and 3 deletions
|
|
@ -45,6 +45,19 @@ public:
|
||||||
void setZoneType(ZoneType type);
|
void setZoneType(ZoneType type);
|
||||||
ZoneType getCurrentZone() const { return currentZone_; }
|
ZoneType getCurrentZone() const { return currentZone_; }
|
||||||
|
|
||||||
|
// City ambience control
|
||||||
|
enum class CityType {
|
||||||
|
NONE,
|
||||||
|
STORMWIND,
|
||||||
|
IRONFORGE,
|
||||||
|
DARNASSUS,
|
||||||
|
ORGRIMMAR,
|
||||||
|
UNDERCITY,
|
||||||
|
THUNDERBLUFF
|
||||||
|
};
|
||||||
|
void setCityType(CityType type);
|
||||||
|
CityType getCurrentCity() const { return currentCity_; }
|
||||||
|
|
||||||
// Emitter management
|
// Emitter management
|
||||||
enum class AmbientType {
|
enum class AmbientType {
|
||||||
FIREPLACE_SMALL,
|
FIREPLACE_SMALL,
|
||||||
|
|
@ -127,6 +140,18 @@ private:
|
||||||
std::vector<AmbientSample> desertPlainsDaySounds_;
|
std::vector<AmbientSample> desertPlainsDaySounds_;
|
||||||
std::vector<AmbientSample> desertPlainsNightSounds_;
|
std::vector<AmbientSample> desertPlainsNightSounds_;
|
||||||
|
|
||||||
|
// City ambience libraries (day and night versions)
|
||||||
|
std::vector<AmbientSample> stormwindDaySounds_;
|
||||||
|
std::vector<AmbientSample> stormwindNightSounds_;
|
||||||
|
std::vector<AmbientSample> ironforgeSounds_; // No separate day/night
|
||||||
|
std::vector<AmbientSample> darnassusDaySounds_;
|
||||||
|
std::vector<AmbientSample> darnassusNightSounds_;
|
||||||
|
std::vector<AmbientSample> orgrimmarDaySounds_;
|
||||||
|
std::vector<AmbientSample> orgrimmarNightSounds_;
|
||||||
|
std::vector<AmbientSample> undercitySounds_; // No separate day/night (underground)
|
||||||
|
std::vector<AmbientSample> thunderbluffDaySounds_;
|
||||||
|
std::vector<AmbientSample> thunderbluffNightSounds_;
|
||||||
|
|
||||||
// Active emitters
|
// Active emitters
|
||||||
std::vector<AmbientEmitter> emitters_;
|
std::vector<AmbientEmitter> emitters_;
|
||||||
uint64_t nextEmitterId_ = 1;
|
uint64_t nextEmitterId_ = 1;
|
||||||
|
|
@ -141,12 +166,14 @@ private:
|
||||||
float weatherLoopTime_ = 0.0f;
|
float weatherLoopTime_ = 0.0f;
|
||||||
float oceanLoopTime_ = 0.0f;
|
float oceanLoopTime_ = 0.0f;
|
||||||
float zoneLoopTime_ = 0.0f;
|
float zoneLoopTime_ = 0.0f;
|
||||||
|
float cityLoopTime_ = 0.0f;
|
||||||
bool wasIndoor_ = false;
|
bool wasIndoor_ = false;
|
||||||
bool wasBlacksmith_ = false;
|
bool wasBlacksmith_ = false;
|
||||||
bool wasSwimming_ = false;
|
bool wasSwimming_ = false;
|
||||||
bool initialized_ = false;
|
bool initialized_ = false;
|
||||||
WeatherType currentWeather_ = WeatherType::NONE;
|
WeatherType currentWeather_ = WeatherType::NONE;
|
||||||
ZoneType currentZone_ = ZoneType::NONE;
|
ZoneType currentZone_ = ZoneType::NONE;
|
||||||
|
CityType currentCity_ = CityType::NONE;
|
||||||
|
|
||||||
// Active audio tracking
|
// Active audio tracking
|
||||||
struct ActiveSound {
|
struct ActiveSound {
|
||||||
|
|
@ -163,6 +190,7 @@ private:
|
||||||
void updateWeatherAmbience(float deltaTime, bool isIndoor);
|
void updateWeatherAmbience(float deltaTime, bool isIndoor);
|
||||||
void updateWaterAmbience(float deltaTime, bool isSwimming);
|
void updateWaterAmbience(float deltaTime, bool isSwimming);
|
||||||
void updateZoneAmbience(float deltaTime, bool isIndoor);
|
void updateZoneAmbience(float deltaTime, bool isIndoor);
|
||||||
|
void updateCityAmbience(float deltaTime);
|
||||||
bool loadSound(const std::string& path, AmbientSample& sample, pipeline::AssetManager* assets);
|
bool loadSound(const std::string& path, AmbientSample& sample, pipeline::AssetManager* assets);
|
||||||
|
|
||||||
// Time of day helpers
|
// Time of day helpers
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,37 @@ bool AmbientSoundManager::initialize(pipeline::AssetManager* assets) {
|
||||||
desertPlainsNightSounds_.resize(1);
|
desertPlainsNightSounds_.resize(1);
|
||||||
bool desertPlainsNightLoaded = loadSound("Sound\\Ambience\\ZoneAmbience\\PlainsDesertNight.wav", desertPlainsNightSounds_[0], assets);
|
bool desertPlainsNightLoaded = loadSound("Sound\\Ambience\\ZoneAmbience\\PlainsDesertNight.wav", desertPlainsNightSounds_[0], assets);
|
||||||
|
|
||||||
|
// Load city ambience sounds (day and night where available)
|
||||||
|
stormwindDaySounds_.resize(1);
|
||||||
|
bool stormwindDayLoaded = loadSound("Sound\\Ambience\\WMOAmbience\\StormwindDay.wav", stormwindDaySounds_[0], assets);
|
||||||
|
|
||||||
|
stormwindNightSounds_.resize(1);
|
||||||
|
bool stormwindNightLoaded = loadSound("Sound\\Ambience\\WMOAmbience\\StormwindNight.wav", stormwindNightSounds_[0], assets);
|
||||||
|
|
||||||
|
ironforgeSounds_.resize(1);
|
||||||
|
bool ironforgeLoaded = loadSound("Sound\\Ambience\\WMOAmbience\\Ironforge.wav", ironforgeSounds_[0], assets);
|
||||||
|
|
||||||
|
darnassusDaySounds_.resize(1);
|
||||||
|
bool darnassusDayLoaded = loadSound("Sound\\Ambience\\WMOAmbience\\DarnassusDay.wav", darnassusDaySounds_[0], assets);
|
||||||
|
|
||||||
|
darnassusNightSounds_.resize(1);
|
||||||
|
bool darnassusNightLoaded = loadSound("Sound\\Ambience\\WMOAmbience\\DarnassusNight.wav", darnassusNightSounds_[0], assets);
|
||||||
|
|
||||||
|
orgrimmarDaySounds_.resize(1);
|
||||||
|
bool orgrimmarDayLoaded = loadSound("Sound\\Ambience\\WMOAmbience\\OrgrimmarDay.wav", orgrimmarDaySounds_[0], assets);
|
||||||
|
|
||||||
|
orgrimmarNightSounds_.resize(1);
|
||||||
|
bool orgrimmarNightLoaded = loadSound("Sound\\Ambience\\WMOAmbience\\OrgrimmarNight.wav", orgrimmarNightSounds_[0], assets);
|
||||||
|
|
||||||
|
undercitySounds_.resize(1);
|
||||||
|
bool undercityLoaded = loadSound("Sound\\Ambience\\WMOAmbience\\Undercity.wav", undercitySounds_[0], assets);
|
||||||
|
|
||||||
|
thunderbluffDaySounds_.resize(1);
|
||||||
|
bool thunderbluffDayLoaded = loadSound("Sound\\Ambience\\WMOAmbience\\ThunderBluffDay.wav", thunderbluffDaySounds_[0], assets);
|
||||||
|
|
||||||
|
thunderbluffNightSounds_.resize(1);
|
||||||
|
bool thunderbluffNightLoaded = loadSound("Sound\\Ambience\\WMOAmbience\\ThunderBluffNight.wav", thunderbluffNightSounds_[0], assets);
|
||||||
|
|
||||||
LOG_INFO("AmbientSoundManager: Wind loaded: ", windLoaded ? "YES" : "NO",
|
LOG_INFO("AmbientSoundManager: Wind loaded: ", windLoaded ? "YES" : "NO",
|
||||||
", Tavern loaded: ", tavernLoaded ? "YES" : "NO",
|
", Tavern loaded: ", tavernLoaded ? "YES" : "NO",
|
||||||
", Blacksmith loaded: ", blacksmithLoaded ? "YES" : "NO");
|
", Blacksmith loaded: ", blacksmithLoaded ? "YES" : "NO");
|
||||||
|
|
@ -162,6 +193,9 @@ bool AmbientSoundManager::initialize(pipeline::AssetManager* assets) {
|
||||||
LOG_INFO("AmbientSoundManager: Zone sounds - Forest: ", (forestDayLoaded && forestNightLoaded) ? "YES" : "NO",
|
LOG_INFO("AmbientSoundManager: Zone sounds - Forest: ", (forestDayLoaded && forestNightLoaded) ? "YES" : "NO",
|
||||||
", Beach: ", (beachDayLoaded && beachNightLoaded) ? "YES" : "NO",
|
", Beach: ", (beachDayLoaded && beachNightLoaded) ? "YES" : "NO",
|
||||||
", Desert: ", (desertCanyonDayLoaded && desertPlainsDayLoaded) ? "YES" : "NO");
|
", Desert: ", (desertCanyonDayLoaded && desertPlainsDayLoaded) ? "YES" : "NO");
|
||||||
|
LOG_INFO("AmbientSoundManager: City sounds - Stormwind: ", (stormwindDayLoaded && stormwindNightLoaded) ? "YES" : "NO",
|
||||||
|
", Ironforge: ", ironforgeLoaded ? "YES" : "NO",
|
||||||
|
", Orgrimmar: ", (orgrimmarDayLoaded && orgrimmarNightLoaded) ? "YES" : "NO");
|
||||||
|
|
||||||
// Initialize timers with random offsets
|
// Initialize timers with random offsets
|
||||||
birdTimer_ = randomFloat(0.0f, 5.0f);
|
birdTimer_ = randomFloat(0.0f, 5.0f);
|
||||||
|
|
@ -219,10 +253,11 @@ void AmbientSoundManager::update(float deltaTime, const glm::vec3& cameraPos, bo
|
||||||
updateWindAmbience(deltaTime, isIndoor);
|
updateWindAmbience(deltaTime, isIndoor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update weather, water, and zone ambience
|
// Update weather, water, zone, and city ambience
|
||||||
updateWeatherAmbience(deltaTime, isIndoor);
|
updateWeatherAmbience(deltaTime, isIndoor);
|
||||||
updateWaterAmbience(deltaTime, isSwimming);
|
updateWaterAmbience(deltaTime, isSwimming);
|
||||||
updateZoneAmbience(deltaTime, isIndoor);
|
updateZoneAmbience(deltaTime, isIndoor);
|
||||||
|
updateCityAmbience(deltaTime);
|
||||||
|
|
||||||
// Track indoor state changes
|
// Track indoor state changes
|
||||||
wasIndoor_ = isIndoor;
|
wasIndoor_ = isIndoor;
|
||||||
|
|
@ -481,6 +516,15 @@ void AmbientSoundManager::setZoneType(ZoneType type) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AmbientSoundManager::setCityType(CityType type) {
|
||||||
|
if (currentCity_ != type) {
|
||||||
|
LOG_INFO("AmbientSoundManager: City changed from ", static_cast<int>(currentCity_),
|
||||||
|
" to ", static_cast<int>(type));
|
||||||
|
currentCity_ = type;
|
||||||
|
cityLoopTime_ = 12.0f; // Play city ambience soon after entering
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AmbientSoundManager::updateWeatherAmbience(float deltaTime, bool isIndoor) {
|
void AmbientSoundManager::updateWeatherAmbience(float deltaTime, bool isIndoor) {
|
||||||
// Don't play weather sounds when indoors
|
// Don't play weather sounds when indoors
|
||||||
if (isIndoor || currentWeather_ == WeatherType::NONE) return;
|
if (isIndoor || currentWeather_ == WeatherType::NONE) return;
|
||||||
|
|
@ -559,8 +603,8 @@ void AmbientSoundManager::updateWaterAmbience(float deltaTime, bool isSwimming)
|
||||||
}
|
}
|
||||||
|
|
||||||
void AmbientSoundManager::updateZoneAmbience(float deltaTime, bool isIndoor) {
|
void AmbientSoundManager::updateZoneAmbience(float deltaTime, bool isIndoor) {
|
||||||
// Don't play zone ambience when indoors
|
// Don't play zone ambience when indoors or in cities
|
||||||
if (isIndoor || currentZone_ == ZoneType::NONE) return;
|
if (isIndoor || currentZone_ == ZoneType::NONE || currentCity_ != CityType::NONE) return;
|
||||||
|
|
||||||
zoneLoopTime_ += deltaTime;
|
zoneLoopTime_ += deltaTime;
|
||||||
|
|
||||||
|
|
@ -610,5 +654,51 @@ void AmbientSoundManager::updateZoneAmbience(float deltaTime, bool isIndoor) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AmbientSoundManager::updateCityAmbience(float deltaTime) {
|
||||||
|
// Only play city ambience when actually in a city
|
||||||
|
if (currentCity_ == CityType::NONE) return;
|
||||||
|
|
||||||
|
cityLoopTime_ += deltaTime;
|
||||||
|
|
||||||
|
// Select appropriate sound library based on city type and time of day
|
||||||
|
const std::vector<AmbientSample>* cityLibrary = nullptr;
|
||||||
|
bool isDay = isDaytime();
|
||||||
|
|
||||||
|
switch (currentCity_) {
|
||||||
|
case CityType::STORMWIND:
|
||||||
|
cityLibrary = isDay ? &stormwindDaySounds_ : &stormwindNightSounds_;
|
||||||
|
break;
|
||||||
|
case CityType::IRONFORGE:
|
||||||
|
cityLibrary = &ironforgeSounds_; // No day/night (underground)
|
||||||
|
break;
|
||||||
|
case CityType::DARNASSUS:
|
||||||
|
cityLibrary = isDay ? &darnassusDaySounds_ : &darnassusNightSounds_;
|
||||||
|
break;
|
||||||
|
case CityType::ORGRIMMAR:
|
||||||
|
cityLibrary = isDay ? &orgrimmarDaySounds_ : &orgrimmarNightSounds_;
|
||||||
|
break;
|
||||||
|
case CityType::UNDERCITY:
|
||||||
|
cityLibrary = &undercitySounds_; // No day/night (underground)
|
||||||
|
break;
|
||||||
|
case CityType::THUNDERBLUFF:
|
||||||
|
cityLibrary = isDay ? &thunderbluffDaySounds_ : &thunderbluffNightSounds_;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play city ambience sound if library is loaded and timer expired
|
||||||
|
if (cityLibrary && !cityLibrary->empty() && (*cityLibrary)[0].loaded) {
|
||||||
|
// Play every 20 seconds for city ambience (moderate intervals for urban atmosphere)
|
||||||
|
if (cityLoopTime_ >= 20.0f) {
|
||||||
|
float volume = 0.4f * volumeScale_; // City ambience at moderate volume
|
||||||
|
AudioEngine::instance().playSound2D((*cityLibrary)[0].data, volume, 1.0f);
|
||||||
|
LOG_INFO("Playing city ambience: type ", static_cast<int>(currentCity_),
|
||||||
|
" (", isDay ? "day" : "night", ")");
|
||||||
|
cityLoopTime_ = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace audio
|
} // namespace audio
|
||||||
} // namespace wowee
|
} // namespace wowee
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue