playOneShot() spawns an external ffplay process that bypasses the
miniaudio engine master volume. Now checks getMasterVolume() before
spawning the process.
Water splash and swimming sounds were bypassing mute because
ma_engine_set_volume(0) didn't fully prevent sound creation.
Now playSound2D and playSound3D early-return when masterVolume
is zero.
Audio was being scaled by master volume multiple times: once via
ma_engine_set_volume, again per-sound in AudioEngine, and again
via pre-multiplication in the UI. Removed redundant master volume
multiplications so each channel volume is independent and master
applies once through the engine. Added About tab to settings with
developer info and GitHub link.
- Use authoritative playerRace/playerGender at spawn for voice profiles
instead of unreliable model name parsing
- Support nonbinary gender with useFemaleModel body type fallback
- Move voice setup into spawnPlayerCharacter() for all spawn paths
- Remove legacy single-player default Human Male clip preloading
- Make loading screen text black and move progress bar to top
Add configurable fade-in support to MusicManager playback paths and use it for auth/login intro tracks to avoid abrupt starts. Apply a login-only 20% music attenuation while the auth screen is active, then restore the previous music volume when leaving login so in-game volume remains unchanged.
Use actual WoW 3.3.5a PlayerExertions and Vox sound paths from MPQ
manifests for attack grunts, wounds, and death sounds. Handle Blizzard
naming quirks (HumanFeamle typo, OrcMale no Final suffix, Scourge→Undead).
Add COMBAT_IDLE animation state with ready weapon stance between swings.
Restore deleted MPQ sound manifest docs.
Wire CombatSoundManager into SMSG_ATTACKERSTATEUPDATE for weapon swing,
impact, and miss sounds. Add attack grunt and wound vocalizations to
ActivitySoundManager using correct WoW MPQ PC-suffix paths. Trigger
attack animation on SMSG_SPELL_GO for warrior melee abilities. Add
client-side melee range and facing checks to prevent server rejections.
Snap charge arrival to target's current position for reliable melee range.
Add AssetManager hookup to AudioEngine so the path-based playSound2D/3D
overloads can load files on demand rather than requiring preloading.
- Add setAssetManager() to AudioEngine (called during world load alongside
other audio manager initializations)
- playSound2D(mpqPath) now calls assetManager->readFile() then delegates
to the vector<uint8_t> overload (removes the "not yet implemented" warning)
- playSound3D(mpqPath, position) same — delegates to the fully spatialized
vector overload (was previously silently falling back to 2D)
Re-send CMSG_ATTACKSWING every second while auto-attacking so combat
resumes automatically when the server pauses the attack loop (out of
range, etc). Previously the client kept autoAttacking=true but never
re-engaged, requiring the player to manually right-click again.
Also remove leftover single-player/offline references from comments.
- audio_engine.cpp: cache key was based on vector pointer address, not
content — cache never hit since each asset load produces a new
allocation. Replace with FNV-1a over head+tail bytes + size, giving
correct content-based identity at O(1) cost. Add 256-entry cap with
eviction to prevent unbounded growth over long sessions.
- game_handler.hpp/cpp, spellbook_screen, game_screen: knownSpells was
a std::vector with O(n) std::find lookups scattered across packet
handlers and UI code. Switch to std::unordered_set for O(1) insert,
erase, and membership checks. Update all push_back/erase-remove/find
call sites to use set operations.
- Add TurtlePacketParsers with dedicated movement block parser (Classic format + transport timestamp)
- Fix quest giver status: read uint32 and translate vanilla enum values for Classic/Turtle
- Fix quest accept packet: remove trailing uint32 that vanilla servers reject
- Fix quest details parser: auto-detect vanilla vs WotLK format (informUnit field)
- Fix spellbook and action bar icons: fallback to WotLK DBC field indices when expansion layout fails
- Fix spell cast failure messages: translate vanilla SpellCastResult codes (+1 offset)
- Fix realm list: correct type values (6=RP, 8=RP-PvP) and population thresholds
- Fix music: disable looping for zone music, auto-advance to next random track when finished
- Add music anti-repeat: avoid playing the same track back-to-back
- Make TBC update block parsing resilient (keep parsed blocks on failure instead of aborting)
- Add right-click attack on hostile mobs
- Add name query diagnostic logging
11 original tracks in assets/Original Music/ now play on the login
screen and in thematically matched zones across Eastern Kingdoms and
Kalimdor. Added crossfadeToFile to MusicManager for local file
playback during zone transitions. New zones: Tirisfal, Undercity,
Barrens, STV, Duskwood, Burning Steppes, Searing Gorge, Ironforge,
Loch Modan, Orgrimmar, Durotar, Mulgore, Thunder Bluff, Darkshore,
Teldrassil, Darnassus.
- Per-family mount sounds (kodo, tallstrider, mechanostrider, etc.) detected from M2 model path
- Skip WMO groups with SHOW_SKYBOX flag or all-untextured batches (grey mesh in Orgrimmar)
- Freeze physics during taxi landing until terrain loads to prevent falling through void
- Disable bone animations on tropical vegetation (palm, bamboo, banana, etc.) to fix wiggling
- Snap player to final taxi waypoint on flight completion
- Extract mount aura spell ID from classic UNIT_FIELD_AURAS for CMSG_CANCEL_AURA dismount
- Increase /unstuck forward nudge to 5 units
Removed jump/land sounds (attack/wound sounds had pained growls).
Made fidget discovery much stricter to exclude jerky battle animations.
Changes:
- Disabled playJumpSound for ground mounts (attack sounds too aggressive)
- Disabled playLandSound for ground mounts (wound sounds have growls)
- Fidget criteria now requires BOTH frequency AND replay (not OR)
- Excluded IDs 11-15 (attacks) in addition to 16-21 (combat)
- Only animations with proper idle metadata will be selected
Created specific idle sound pool using only horse snorts and whinnies.
Re-enabled idle sounds with much longer interval (20-40 seconds).
Changes:
- Added horseIdleSounds_ pool: mHorseStand3A (snort) + mHorseAggroA (whinny)
- Updated playIdleSound() to use dedicated pool instead of mixed breath sounds
- Increased idle sound interval from 8-15s to 20-40s (less frequent)
- Removed flying mount idle sounds (too aggressive)
- Increased volume slightly (0.35x) for better audibility
Implements WoW-style mount idle behavior when player is stationary:
- Fidget animations: discovered via property search (non-looping, 500-1500ms, stationary, IDs 1-10)
- Triggers random fidget every 6-12 seconds when standing still
- Ambient idle sounds: snorts/breaths for ground mounts, soft wing sounds for flyers
- Triggers random idle sound every 8-15 seconds when stationary
- Both systems reset timers on movement to avoid triggering while riding
Mount Sound System:
- Use actual creature sounds from MPQ (Horse, Ram, Wolf, Tiger, Dragons)
- Separate sound pools: jump (attack), landing (wound), rear-up (aggro)
- Mount family detection: HORSE, RAM, WOLF, TIGER, RAPTOR, DRAGON
- Family logged on mount for future per-family sound selection
Sound Mappings:
- Flying mounts: Dragon wing flaps + DragonHawk screeches
- Ground mounts: Horse attack (jump), wound (land), aggro (rear-up)
- Ready for family-specific sound selection (TODO)
Mount Lean:
- Procedural lean into turns for ground mounts
- Physics-based: turn rate × 0.15, max ±14°, 6x/sec blend
- Returns to upright when not turning or when flying
- Rider follows mount roll automatically via bone attachment
Mount Animation System:
- Property-based jump animation discovery using sequence metadata
- Chain linkage scoring (nextAnimation/aliasNext) for accurate detection
- Correct loop detection: flags & 0x01 == 0 means looping
- Avoids brake/stop animations via blendTime penalties
- Works on any mount model without hardcoded animation IDs
Mount Physics:
- Physics-based jump height: vz = sqrt(2 * g * h)
- Configurable MOUNT_JUMP_HEIGHT constant (1.0m default)
- Procedural lean into turns for ground mounts
- Smooth roll based on turn rate (±14° max, 6x/sec blend)
Audio Improvements:
- State-machine driven mount sounds (jump, land, rear-up)
- Semantic sound methods (no animation ID dependencies)
- Debug logging for missing sound files
Bug Fixes:
- Fixed mount animation sequencing (JumpStart → JumpLoop → JumpEnd)
- Fixed animation loop flag interpretation (0x20 vs 0x21)
- Rider bone attachment working correctly during all mount actions
Added detailed logging in spawnOnlineGameObject() to help identify duplicate
game object spawns. Logs displayId, guid, model path, and position for both
new spawns and position updates. This will help diagnose the floating
cathedral model issue in Stormwind by showing which GUIDs are being spawned
and their coordinates.
- Added GOBLIN_MALE and GOBLIN_FEMALE to VoiceType enum
- Load greeting, farewell, vendor, and pissed sounds for goblin NPCs
- Prevents goblins from falling back to generic voice flag
- Uses proper goblin sound files from Goblin character folder
Settings Changes:
- All settings now apply immediately without Apply button
- Each slider/checkbox instantly updates the game state and saves
- Escape key closes settings window if open (no longer shows escape menu behind it)
- Restore Defaults buttons now also apply settings immediately
Audio Changes:
- Increased NPC voice volume from 0.6 to 1.0 (60% to 100% base volume)
- Helper lambda in Audio tab for efficient volume application
- Master volume multiplier applied to all audio systems in real-time
UX Improvements:
- Removed redundant Apply button
- Settings save automatically on every change
- More intuitive settings flow - see changes instantly
- Cleaner escape key handling priority
Implemented player combat vocals for Blood Elf and Draenei races:
Player vocal types:
- Attack grunts: Multiple variations per race/gender
- Wound sounds: Pain reactions when hit
- Wound crits: Special sounds for critical hits taken
- Death cries: Final sounds when player dies
Race coverage (60+ voice lines):
- Blood Elf Male: 9 attacks, 8 wounds, 3 crit wounds, 2 deaths
- Blood Elf Female: 5 attacks, 7 wounds, 1 death
- Draenei Male: 7 attacks, 8 wounds, 3 crit wounds, 2 deaths
- Draenei Female: 7 attacks, 4 wounds, 3 crit wounds, 1 death
Technical details:
- Loads 60+ vocal sound files from Sound\Character\*PC folders
- Simple API: playPlayerAttackGrunt(race), playPlayerWound(race, crit), playPlayerDeath(race)
- Random variation selection for immersion
- Volume at 0.9-1.1 depending on sound type
- Crit wounds play 1.1x louder for emphasis
- Extensible design ready for other races
- Only BC races have dedicated PC vocal folders in WotLK 3.3.5a
Usage examples:
```cpp
combatSoundManager->playPlayerAttackGrunt(PlayerRace::BLOOD_ELF_MALE);
combatSoundManager->playPlayerWound(PlayerRace::DRAENEI_FEMALE, true); // Crit
combatSoundManager->playPlayerDeath(PlayerRace::BLOOD_ELF_FEMALE);
```
This adds essential combat immersion with player character reactions!
Changed bell tolls from random intervals to proper timekeeping mechanism:
How it works:
- Bells now toll at the top of every hour (minute == 0)
- Number of tolls indicates the hour in 12-hour format:
* 1 AM/PM = 1 toll
* 2 AM/PM = 2 tolls
* 12 AM/PM = 12 tolls
- 1.5 second delay between individual tolls
- Uses system time (server time for single-player mode)
Technical details:
- Detects hour changes via std::chrono and localtime()
- Tracks lastHourTolled_ to prevent duplicate tolling
- remainingTolls_ counter for sequential toll playback
- bellTollDelay_ for 1.5s spacing between tolls
- Only tolls when currentCity_ is set (in a city)
- Resets bell state when changing cities
- Converts 24-hour to 12-hour format (0 and 12 both become 12)
Example: At 3:00 PM in Stormwind, the Alliance bell will toll 3 times
with 1.5s between each toll, marking the hour like a real clock tower.
This makes bells actually useful for tracking real time while playing!
Implemented fountain sounds as positional audio emitters:
Technical details:
- Added fountainSounds_ library (FountainSmallMediumLoop.wav)
- Fountain type already existed in AmbientType enum but was unused
- 6 second loop interval for fountain sounds
- Volume at 0.8x water volume for gentle bubbling effect
- Max distance: 35 units (same as other water sources)
- Counted in activeWaterCount limit (max 3 water sources at once)
- Spatial 3D audio based on fountain position
- Can be placed via addEmitter(position, AmbientType::FOUNTAIN)
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
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
Implemented three new ambient audio systems with automatic day/night transitions:
Weather ambience:
- Rain sounds (light/medium/heavy intensity based on weather system)
- Snow sounds (light/medium/heavy intensity)
- Automatically syncs with visual weather system in renderer
- Different loop intervals based on intensity (18-30s)
- Disabled indoors
Water ambience:
- Underwater swimming sounds (18s loop)
- Ocean surface sounds
- State tracking for entering/exiting water
Zone ambience:
- Forest (normal and snow variants)
- Beach sounds
- Grasslands
- Jungle
- Marsh/swamp
- Desert (canyon and plains variants)
- All zones have separate day/night sound files
- 30s loop interval for subtle background atmosphere
- Disabled indoors
Technical details:
- Added WeatherType enum (NONE, RAIN/SNOW LIGHT/MEDIUM/HEAVY)
- Added ZoneType enum (NONE, FOREST_NORMAL, FOREST_SNOW, BEACH, GRASSLANDS, JUNGLE, MARSH, DESERT_CANYON, DESERT_PLAINS)
- Loads 26 new sound files from Sound\Ambience\Weather and Sound\Ambience\ZoneAmbience
- Weather intensity thresholds: <0.33 = light, 0.33-0.66 = medium, >0.66 = heavy
- Renderer automatically converts Weather::Type + intensity to AmbientSoundManager::WeatherType
- All ambience respects volumeScale_ and indoor state
- State change logging for debugging transitions
Replaces the pitch-shifted weapon hit sound hack with the official
Sound\Ambience\WMOAmbience\BlackSmith.wav ambience loop. This provides
authentic blacksmith atmosphere with natural hammer strikes and anvil sounds.
Changes:
- Use proper blacksmith ambience file instead of modified weapon sounds
- Remove pitch shifting (1.6x) - use natural sound at 1.0x pitch
- Adjust volume to 0.6 (from 0.25) for ambient loop
- Play every 15 seconds (from 2.5s) for natural atmosphere
- Single loop file replaces 3 random weapon hit sounds
Implements full NPC voice interaction system supporting 6 different sound categories
for all playable races/genders. System loads ~450+ voice clips from MPQ archives.
Voice Categories:
- Greeting: Play on NPC right-click interaction
- Farewell: Play when closing gossip/dialog windows
- Vendor: Play when opening merchant/vendor windows
- Pissed: Play after clicking NPC 5+ times (spam protection)
- Aggro: Play when NPC enters combat with player
- Flee: Play when NPC is fleeing (ready for low-health triggers)
Features:
- Race/gender detection from NPC display IDs via CreatureDisplayInfoExtra.dbc
- Intelligent click tracking for pissed sounds
- Combat sounds use player character vocal files for humanoid NPCs
- Cooldown system prevents voice spam (2s default, combat sounds bypass)
- Generic fallback voices for unsupported NPC types
- 3D positional audio support
Voice Support:
- All playable races: Human, Dwarf, Gnome, Night Elf, Orc, Tauren, Troll, Undead
- Male and female variants for each race
- StandardNPC sounds for social interactions
- Character vocal sounds for combat
Technical Changes:
- Refactored NpcVoiceManager to support multiple sound categories
- Added callbacks: NpcFarewell, NpcVendor, NpcAggro
- Extended voice loading to parse both StandardNPC and Character vocal paths
- Integrated with GameHandler for gossip, vendor, and combat events
- Added detailed voice detection logging for debugging
Also includes:
- Sound manifest files added to docs/ for reference
- Blacksmith hammer pitch increased to 1.6x (was 1.4x)
- Blacksmith volume reduced 30% to 0.25 (was 0.35)
WotLK 3.3.5a uses .wav files for NPC voices, not .ogg as shown in retail Wowhead. Fixed audio engine to preserve original sample rate from WAV files (preventing chipmunk playback). Implemented race/gender detection using CreatureDisplayInfo.dbc and CreatureDisplayInfoExtra.dbc to play correct voice types for each NPC.
MPQs may store files internally with forward slashes. Testing both:
- Sound/Creature/... (forward slashes)
- Sound\Creature\... (backslashes)
This should help identify the correct path format for accessing files.
Tests various path structures to find where voice files actually exist:
- Wowhead StandardNPC paths
- Lowercase variations
- PC voice files (HumanVocMale/Female - player emotes)
- VO/Voice directories
- Simpler creature paths
This will help identify which files actually exist in the 3.3.5a MPQs.
NPC sounds are in Sound\Creature\[npctype]\ not Sound\Character\.
Changed to use correct paths like humanmalestandardnpc/humanfemalestandardnpc
with .ogg extension. This matches actual WoW 3.3.5a structure.