From becc94d4bad2280de8c0715c89e319cd5dec8280 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Mon, 9 Feb 2026 01:39:12 -0800 Subject: [PATCH] Fix NPC voices and add tavern music support NPC voice fixes: - Changed sound paths from "Greeting" to "Hello" emote (more reliable) - Added warning log when no voice samples load - Voice files should now play when clicking NPCs Tavern music: - Detect tavern WMOs by model ID (inn buildings) - Play tavern-specific music when inside taverns - Crossfade back to zone music when exiting taverns - Adds cozy ambient music to inn/tavern buildings --- include/rendering/renderer.hpp | 1 + src/audio/npc_voice_manager.cpp | 44 +++++++++++++++++------------- src/rendering/renderer.cpp | 48 ++++++++++++++++++++++++++++++--- 3 files changed, 71 insertions(+), 22 deletions(-) diff --git a/include/rendering/renderer.hpp b/include/rendering/renderer.hpp index 94718359..b35b6cfa 100644 --- a/include/rendering/renderer.hpp +++ b/include/rendering/renderer.hpp @@ -221,6 +221,7 @@ private: pipeline::AssetManager* cachedAssetManager = nullptr; uint32_t currentZoneId = 0; std::string currentZoneName; + bool inTavern_ = false; // Third-person character state glm::vec3 characterPosition = glm::vec3(0.0f); diff --git a/src/audio/npc_voice_manager.cpp b/src/audio/npc_voice_manager.cpp index b7ec585c..9bd2f5f9 100644 --- a/src/audio/npc_voice_manager.cpp +++ b/src/audio/npc_voice_manager.cpp @@ -39,17 +39,17 @@ void NpcVoiceManager::shutdown() { void NpcVoiceManager::loadVoiceSounds() { if (!assetManager_) return; - // Generic NPC greetings (various creature sounds that work as greetings) + // Generic NPC greetings using Hello emote (more reliable than Greeting) std::vector genericPaths = { - "Sound\\Character\\Human\\HumanMaleGreeting01.wav", - "Sound\\Character\\Human\\HumanMaleGreeting02.wav", - "Sound\\Character\\Human\\HumanMaleGreeting03.wav", - "Sound\\Character\\Human\\HumanFemaleGreeting01.wav", - "Sound\\Character\\Human\\HumanFemaleGreeting02.wav", - "Sound\\Character\\Dwarf\\DwarfMaleGreeting01.wav", - "Sound\\Character\\Dwarf\\DwarfMaleGreeting02.wav", - "Sound\\Character\\NightElf\\NightElfMaleGreeting01.wav", - "Sound\\Character\\NightElf\\NightElfFemaleGreeting01.wav", + "Sound\\Character\\Human\\HumanMaleHello01.wav", + "Sound\\Character\\Human\\HumanMaleHello02.wav", + "Sound\\Character\\Human\\HumanMaleHello03.wav", + "Sound\\Character\\Human\\HumanFemaleHello01.wav", + "Sound\\Character\\Human\\HumanFemaleHello02.wav", + "Sound\\Character\\Dwarf\\DwarfMaleHello01.wav", + "Sound\\Character\\Dwarf\\DwarfMaleHello02.wav", + "Sound\\Character\\NightElf\\NightElfMaleHello01.wav", + "Sound\\Character\\NightElf\\NightElfFemaleHello01.wav", }; auto& genericVoices = voiceLibrary_[VoiceType::GENERIC]; @@ -62,9 +62,9 @@ void NpcVoiceManager::loadVoiceSounds() { // Human male std::vector humanMalePaths = { - "Sound\\Character\\Human\\HumanMaleGreeting01.wav", - "Sound\\Character\\Human\\HumanMaleGreeting02.wav", - "Sound\\Character\\Human\\HumanMaleGreeting03.wav", + "Sound\\Character\\Human\\HumanMaleHello01.wav", + "Sound\\Character\\Human\\HumanMaleHello02.wav", + "Sound\\Character\\Human\\HumanMaleHello03.wav", "Sound\\Character\\Human\\HumanMaleYes01.wav", "Sound\\Character\\Human\\HumanMaleYes02.wav", }; @@ -78,8 +78,8 @@ void NpcVoiceManager::loadVoiceSounds() { // Human female std::vector humanFemalePaths = { - "Sound\\Character\\Human\\HumanFemaleGreeting01.wav", - "Sound\\Character\\Human\\HumanFemaleGreeting02.wav", + "Sound\\Character\\Human\\HumanFemaleHello01.wav", + "Sound\\Character\\Human\\HumanFemaleHello02.wav", "Sound\\Character\\Human\\HumanFemaleYes01.wav", }; auto& humanFemale = voiceLibrary_[VoiceType::HUMAN_FEMALE]; @@ -92,8 +92,8 @@ void NpcVoiceManager::loadVoiceSounds() { // Dwarf male std::vector dwarfMalePaths = { - "Sound\\Character\\Dwarf\\DwarfMaleGreeting01.wav", - "Sound\\Character\\Dwarf\\DwarfMaleGreeting02.wav", + "Sound\\Character\\Dwarf\\DwarfMaleHello01.wav", + "Sound\\Character\\Dwarf\\DwarfMaleHello02.wav", "Sound\\Character\\Dwarf\\DwarfMaleYes01.wav", }; auto& dwarfMale = voiceLibrary_[VoiceType::DWARF_MALE]; @@ -106,7 +106,7 @@ void NpcVoiceManager::loadVoiceSounds() { // Night elf male std::vector nelfMalePaths = { - "Sound\\Character\\NightElf\\NightElfMaleGreeting01.wav", + "Sound\\Character\\NightElf\\NightElfMaleHello01.wav", "Sound\\Character\\NightElf\\NightElfMaleYes01.wav", }; auto& nelfMale = voiceLibrary_[VoiceType::NIGHTELF_MALE]; @@ -119,7 +119,7 @@ void NpcVoiceManager::loadVoiceSounds() { // Night elf female std::vector nelfFemalePaths = { - "Sound\\Character\\NightElf\\NightElfFemaleGreeting01.wav", + "Sound\\Character\\NightElf\\NightElfFemaleHello01.wav", "Sound\\Character\\NightElf\\NightElfFemaleYes01.wav", }; auto& nelfFemale = voiceLibrary_[VoiceType::NIGHTELF_FEMALE]; @@ -131,11 +131,17 @@ void NpcVoiceManager::loadVoiceSounds() { } // Log loaded voice types + int totalLoaded = 0; for (const auto& [type, samples] : voiceLibrary_) { if (!samples.empty()) { LOG_INFO("Loaded ", samples.size(), " voice samples for type ", static_cast(type)); + totalLoaded += samples.size(); } } + + if (totalLoaded == 0) { + LOG_WARNING("NPC voice manager: no voice samples loaded (files may not exist in MPQ)"); + } } bool NpcVoiceManager::loadSound(const std::string& path, VoiceSample& sample) { diff --git a/src/rendering/renderer.cpp b/src/rendering/renderer.cpp index 616eeb34..781c689b 100644 --- a/src/rendering/renderer.cpp +++ b/src/rendering/renderer.cpp @@ -1416,9 +1416,10 @@ void Renderer::update(float deltaTime) { auto tile = terrainManager->getCurrentTile(); uint32_t zoneId = zoneManager->getZoneId(tile.x, tile.y); + bool insideTavern = false; + std::string tavernMusic; - - // Override with WMO-based detection (e.g., inside Stormwind) + // Override with WMO-based detection (e.g., inside Stormwind, taverns) if (wmoRenderer) { glm::vec3 camPos = camera->getPosition(); uint32_t wmoModelId = 0; @@ -1427,10 +1428,51 @@ void Renderer::update(float deltaTime) { if (wmoModelId == 10047) { zoneId = 1519; // Stormwind City } + + // Detect taverns/inns by WMO model ID (common inn WMOs) + // These IDs represent typical Alliance and Horde inn buildings + if (wmoModelId == 191 || // Goldshire inn + wmoModelId == 190 || // Small inn (common) + wmoModelId == 220 || // Tavern building + wmoModelId == 221 || // Large tavern + wmoModelId == 5392 || // Horde inn + wmoModelId == 5393) { // Another inn variant + insideTavern = true; + // WoW tavern music (cozy ambient tracks) + static const std::vector tavernTracks = { + "Sound\\Music\\GlueScreenMusic\\tavern_01.mp3", + "Sound\\Music\\GlueScreenMusic\\tavern_02.mp3", + "Sound\\Music\\ZoneMusic\\Tavern\\tavernAlliance01.mp3", + "Sound\\Music\\ZoneMusic\\Tavern\\tavernAlliance02.mp3", + }; + static int tavernTrackIndex = 0; + tavernMusic = tavernTracks[tavernTrackIndex % tavernTracks.size()]; + } } } - if (zoneId != currentZoneId && zoneId != 0) { + // Handle tavern music transitions + if (insideTavern) { + if (!inTavern_ && !tavernMusic.empty()) { + inTavern_ = true; + LOG_INFO("Entered tavern"); + musicManager->crossfadeTo(tavernMusic); + } + } else if (inTavern_) { + // Exited tavern - restore zone music + inTavern_ = false; + LOG_INFO("Exited tavern"); + auto* info = zoneManager->getZoneInfo(currentZoneId); + if (info) { + std::string music = zoneManager->getRandomMusic(currentZoneId); + if (!music.empty()) { + musicManager->crossfadeTo(music); + } + } + } + + // Handle normal zone transitions (only if not in tavern) + if (!insideTavern && zoneId != currentZoneId && zoneId != 0) { currentZoneId = zoneId; auto* info = zoneManager->getZoneInfo(zoneId); if (info) {