NPCs were not spawning when the player first entered the world because
spawnNpcs() was defined but never called. Added call to spawnNpcs() in
Application::update() when in IN_GAME state.
The function has a guard (npcsSpawned flag) so it only runs once. NPCs now
appear immediately at spawn instead of requiring the player to walk away first.
Added logging to help debug spawn preconditions.
PROBLEM:
Canal water surfaces in Stormwind extend spatially beyond their intended
boundaries, causing water to appear in tunnels and buildings where it
shouldn't be visible. This is likely due to oversized water mesh extents
in the original WoW data.
SOLUTION:
Lower Stormwind canal water by 1 unit to hide it below tunnel/building floors
while keeping boats at reasonable floating height:
- Only affects water in Stormwind area (tiles 28-50, 28-52)
- Only affects water above 94 height (canal level)
- Moonwell exclusion: 20-unit radius around (-8755.9, 1108.9, 96.1)
to preserve functional moonwell water
HARDCODED VALUES:
- Stormwind area bounds: tiles (28-50, 28-52)
- Height threshold: >94 units (canal level)
- Moonwell position: (-8755.9, 1108.9, 96.1) with 20-unit exclusion
- Lowering amount: 1 unit
WHY THIS IS HACKY:
- Zone-specific logic hardcoded for Stormwind coordinates
- Position-based moonwell exclusion uses hardcoded world coordinates
- Height threshold is a magic number tuned by trial
- Doesn't fix root cause (oversized water surface meshes)
- Some park water may still be visible
PROPER FIX WOULD BE:
- Trim water surface meshes to actual canal boundaries in ADT/WMO data
- Or implement spatial clipping of water surfaces at render time
This is a pragmatic workaround that improves the situation.
- Filter terrain water in Stormwind area (tiles 28-35, 46-52) to 85-110 height range
- Conservative global WMO water filter (only removes water above 300 or below -100)
- Increase canal water opacity and add distance-based opacity
- Prevents floating/underground water in Stormwind without affecting other zones
- Add carpet/rug name detection in model loading
- Set collisionNoBlock flag for carpet and rug models
- Prevents slipping/sliding on decorative floor coverings
- Player can now walk through carpets without collision
- Increase padding from 1.2x to 2.5x model radius
- Add minimum 5 unit padding for small objects like lamps
- Fixes models disappearing at viewport edges during camera rotation
- Add distance-based + backface culling for STORMWIND.WMO LOD shell groups
- Hide floating cathedral shell when within 185 units of group center
- Enable backface culling for LOD shell to reduce artifacts from inside
- Increase WMO view distance from 160 to 500 units for better visibility
- Extend fog distances to 3000-4000 units for clearer long-range views
- Add fog support to water renderer matching WMO fog settings
Previous threshold (worldZ > 150) was too aggressive and hid Group 95
at worldZ=162 which is legitimate cathedral geometry.
New approach: Only hide groups that are BOTH:
- High: worldZ > 180
- Very tall: sizeZ > 100
This specifically targets ONLY the floating shell:
- Group 92: worldZ=225, sizeZ=251 ✓ culled
- Group 93: worldZ=201, sizeZ=165 ✓ culled
While preserving legitimate geometry:
- Group 95: worldZ=162, sizeZ=131 ✓ kept (Z < 180)
- All other groups: Z < 180 ✓ kept
Identified the floating LOD shell from Z-position analysis:
- Group 92: worldZ=225 (flags=0x7d2, 251.5 units tall!)
- Group 93: worldZ=201.6 (flags=0x7e1, 165.4 units tall!)
These groups are positioned WAY above the normal cathedral geometry
(which sits at worldZ 98-122). They're the simplified distant shell
meant to make the cathedral look impressive from far away.
Fix: Skip rendering groups with worldZ > 150.0
This hides the floating shell while keeping all normal cathedral
geometry visible.
The threshold of 150 sits safely between:
- Normal cathedral: 98-122
- Floating shell: 200-225
Enhanced STORMWIND.WMO logging to show:
- centerZ: local Z position of group center
- sizeZ: height of the group
- worldZ: world Z position after transform
Removed all culling logic to see ALL groups rendering.
This will help identify which groups are positioned HIGH (floating shell).
User reports the shell is 'larger and floating above' the real cathedral,
so we need to find groups with unusually high Z positions.
Changed culling strategy based on observation:
- Previous: Hide groups with <100 verts when close
- New: Hide groups >200 units away when you're <300 units from WMO
The floating cathedral is likely Groups 281/283/284/285 which are:
- High detail (23k-28k verts)
- Far away (200-569 units from camera)
- Meant to show the cathedral from a distance
When you're actually near/inside the cathedral (distToWMO < 300),
these distant views should be hidden and only the close-up geometry
(Group 257 at 20 units) should render.
Added distance-based culling for WMO LOD shell groups:
- Skip groups with <100 vertices when camera is within 500 units
- This hides the simplified 'distant shell' when you're close to buildings
Analysis from STORMWIND.WMO logs revealed:
- LOD shell: Groups 268/269/271/274 (24-72 verts, flags 0x19xx)
- Main cathedral: Group 257 (32,698 verts at 20 units distance)
The LOD shell groups are meant for distant viewing only but were
rendering at all distances, causing the 'floating cathedral' effect.
Fix: Compute distance from camera to each group center and skip
rendering low-vertex groups when close. This preserves performance
(LOD shells still render from far away) while fixing the visual bug.
Added detailed logging when rendering STORMWIND.WMO groups to identify
the distant LOD shell that's causing the floating cathedral:
- Group index
- Group flags (hex) - will reveal which flag marks distant-only groups
- Distance from camera to group center
- Vertex count (helps identify simplified LOD geometry)
Logs once per session to avoid spam. This will help us identify:
1. Which groups are the floating LOD shell
2. What flag value indicates 'distant view only'
3. Proper distance threshold for LOD culling
Next step: Use flag pattern to hide distant groups when camera is close.
Added deduplication for WMO instances based on uniqueId, matching the
existing M2 doodad deduplication logic. This prevents creating multiple
instances of the same WMO when it's referenced from multiple ADT tiles.
Before: STORMWIND.WMO (uniqueId=10047) was being rendered 16 times
(one instance per ADT tile that references it)
After: Only 1 instance is created and shared across all tiles
Changes:
- Added placedWmoIds set to TerrainManager (like placedDoodadIds)
- Check uniqueId before creating WMO instance
- Skip duplicate WMO placements across tile boundaries
- Log dedup statistics: 'X instances, Y dedup skipped'
This should fix the floating cathedral visual issue if it was caused by
rendering artifacts from 16x overdraw, and will massively improve
performance in Stormwind.
Log all MODF placements of STORMWIND.WMO with complete details:
- uniqueId (should be unique per instance)
- position (x, y, z) - to detect duplicate placements at different Z
- rotation (pitch, yaw, roll)
- doodadSet and flags
This will immediately reveal if the floating cathedral is caused by
duplicate MODF placements at different heights vs a renderer issue.
If multiple entries have same XY but different Z, that's the culprit.
Removed condition that suppressed logging when wmoNames.size() == 0.
Now will always show 'Loaded X WMO names from MWMO chunk' to confirm
MWMO parsing is happening and reveal if ADT tiles have empty or missing
WMO name lists. This will help diagnose why cathedral WMOs aren't appearing
in logs.
Changed LOG_DEBUG to LOG_INFO for WMO filenames so they appear in logs
without requiring debug mode. This will show all WMO files loaded from
ADT tiles and make cathedral detection messages visible.
Added detailed logging in ADT loader to identify cathedral WMO duplicates:
- Log all WMO filenames from MWMO chunks with index numbers
- Flag and highlight any WMO containing "cathedral" or "Cathedral"
- Log cathedral placement positions from MODF chunks
This will help identify if both WotLK and classic cathedral models are
being loaded from the same ADT tile, causing the floating duplicate effect:
- World\wmo\Azeroth\Buildings\Stormwind\SW_CathedralDistrict.wmo
- world/wmo/azeroth/stormwind/zClassic/cathedral.wmo
The logs will show which cathedral variants exist and their exact positions
to determine if one should be filtered/hidden.
The issue was that vertex colors (MOCV) were being multiplied directly into
the texture color BEFORE lighting calculation. When MOCV data contained
black (0,0,0) values, this zeroed out the texture color, making all
subsequent lighting multiplication also zero, resulting in pitch black areas
regardless of ambient light settings.
Fixed by:
1. Removed premature vertex color multiplication from texture sampling
2. Applied vertex colors as ambient occlusion AFTER lighting calculation
3. Clamped vertex colors to minimum 0.5 to prevent complete blackout
Now even areas with black MOCV data will render at 50% brightness minimum,
while properly lit areas remain bright. This preserves the AO effect without
causing invisible geometry.
Added detailed logging for WMO vertex data to diagnose pitch black areas:
- Log MOCV (vertex colors) chunk presence and first color value
- Log MONR (normals) chunk presence and first normal vector
- Log WMO group flags to identify interior vs exterior groups
Increased WMO ambient light from (0.4, 0.4, 0.5) to (0.55, 0.55, 0.6) to
make shadowed/dark areas more visible. This addresses pitch black areas in
Stormwind and other locations where diffuse lighting may be insufficient.
The diagnostic output will help identify if black areas are caused by:
- Missing or incorrect vertex color data (MOCV)
- Missing or incorrect normal data (MONR)
- Groups incorrectly flagged as interior (0x2000 flag)
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.
Nonbinary characters can now choose between masculine and feminine body types in character creation, with real-time preview updates and full appearance customization. Body type preference is saved to character config and persists across sessions. Also reduces character preview drag-to-rotate sensitivity from 0.5 to 0.2 for better control.
Adds $n placeholder for player character names in quest and gossip dialog. Enhances documentation for three-option gender placeholders to clarify support for neutral terms like friend/champion/sibling. Player name defaults to 'Adventurer' when character not loaded.
Extends gender system beyond WoW's binary male/female to support nonbinary characters with proper they/them pronouns. Implements client-side gender mapping (nonbinary→male) for 3.3.5a server compatibility while preserving player identity through local config persistence. Adds pronoun placeholders ($p/$o/$s/$S) and three-option gender text parsing ($g<male>:<female>:<nonbinary>;) for inclusive quest and dialog text.
Game objects (wreaths, guild vaults, mailboxes, etc) were being rotated 90 degrees incorrectly due to an unnecessary orientation offset when spawning.
Fixed by removing the glm::radians(90.0f) offset from renderYaw calculation. Objects now use the correct server-provided orientation directly.
Affects both WMO and M2 game object rendering.
- 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.
Loads speech-enUS.MPQ, expansion-speech-enUS.MPQ, and lichking-speech-enUS.MPQ
which contain NPC voice/creature sound files. These MPQs were present but not
being loaded, causing all .ogg NPC greeting sounds to show as NOT FOUND.
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.
These managers were only being initialized in loadTerrainArea (online mode).
Added initialization in loadTestTerrain as well so they work in both modes.
Now the file probing should actually run and show which sound files exist.
The cachedAssetManager was only set in loadTestTerrain() for single-player mode.
In online mode (loadTerrainArea), it was never set, so NPC voice and mount sound
managers never initialized. Now gets asset manager from Application instance if
not already cached. This will enable file probing and voice/sound loading.