Replace all glGenTextures/glTexImage2D calls in UI code with Vulkan texture
uploads via new VkContext::uploadImGuiTexture() helper. This fixes segfaults
from calling OpenGL functions without a GL context (null GLEW function pointers).
- Add uploadImGuiTexture() to VkContext with staging buffer upload pattern
- Convert game_screen, inventory_screen, spellbook_screen, talent_screen
from GLuint/GL calls to VkDescriptorSet/Vulkan uploads
- Fix loading_screen clearValueCount (was 1, needs 2 or 3 for MSAA)
- gate selection-circle rendering to UNIT and PLAYER targets only
- clear selection circle for non-unit target types (including gameobjects)
- keep target position updates unchanged for facing/interaction logic
- reduce per-tile ground clutter generation pressure and enforce tighter caps to avoid spikes
- remove expensive detail dedupe scans from the hot render path
- add progressive/lazy clutter updates around player movement to smooth frame pacing
- lower noisy runtime INFO logging to DEBUG/throttled paths
- keep terrain/game screen updates responsive while preserving existing behavior
- normalize humanoid NPC clothing geosets at spawn time to avoid conflicting overlays\n- force pants-first selection for group 13 to prevent robe/kilt meshes on trouser NPCs\n- hide cloak groups for NPCs unless a renderable cape texture can actually be resolved\n- avoid falling back to missing equipment texture paths during region compositing\n- stop model-scope type-2 cape texture writes that could leak cape/white textures across shared model IDs\n- add group texture override usage in character renderer draw path\n- update character preview equipment application to reuse preview applyEquipment path\n- keep hand-only keybone fallback for attachments to prevent helmet/anchor misbinds
- make tab-target accept units that are either faction-hostile or actively aggressive toward the player\n- fix cases where enemies remain un-tab-targetable after combat starts due to stale/friendly faction state\n- prefer hostile UNIT picks over nearby GAMEOBJECT picks for both left-click target and right-click interact flows\n- keep existing dead-unit filtering and interaction behavior intact while improving combat target acquisition
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.
- Keep WotLK chest flow stock-like by relying on GAMEOBJ_USE/REPORT_USE instead of forcing eager CMSG_LOOT.
- Preserve fallback eager-loot behavior for Classic/Turtle paths with bounded retries.
- Improve GO targeting usability by allowing gameobject pick/retarget in world click logic.
- Remove temporary loot/chest diagnostic LOG_INFO traces added during chest-open debugging.
Allow equipped bags to be moved through the shared inventory pickup/drop flow, including dragging from bag contents to bag bar and back from bag bar into bag/backpack slots.
Changes:
- Add InventoryScreen APIs to begin pickup from an equipment slot and drop held item into a target equipment slot.
- Treat inventory type 18 (bags) as valid drops on BAG1-BAG4 during slot validation.
- Route equipment placement in online mode through swapContainerItems with explicit src/dst addressing for deterministic bag slot moves.
- Update bag bar hover-drop path to use InventoryScreen drop API instead of direct local slot mutation.
- On bag bar drag start, hand off to inventory held-item drag when inventory/character UI is open so drops into bag/backpack slots work.
- Use interpolated moveInstanceTo() for normal server NPC position deltas so walk/run animations play instead of visual sliding
- Keep hard snaps only for dead units and large corrections/teleports
- Add per-creature render position cache to drive interpolation safely across frames and clear it on spawn/despawn/reset
- Keep minimap controls visible regardless of quest-status availability
- Correct minimap NPC/quest marker projection mapping to match minimap shader transform
- Add optional nearby NPC minimap dots setting (default OFF), exposed in Gameplay > Interface and persisted in settings
- Right-click attack fallback for non-interactable hostile creatures
- Robust creature skin path resolution for WotLK/non-humanoid display skin fields
- Strengthened client-side anti-overlap spacing for active melee targets (including wolf/worg models)
- Minimap questgiver markers now use live minimap view radius and exact minimap center to prevent player-relative drift
Selection ring rendering has been upgraded to better match WoW-like target feedback and remain readable across complex geometry.
Visual updates:
- Reworked ring mesh/shader from a simple two-band strip to a unit-disc + radial fragment shaping.
- Implemented a thinner outer ring profile.
- Added an inward color/alpha gradient that fades from the ring toward the center.
Placement/anchoring updates:
- Added CharacterRenderer::getInstanceFootZ() to query model foot plane from instance bounds.
- Added Application::getRenderFootZForGuid() to resolve per-GUID foot height via live instance mapping.
- Updated GameScreen target selection placement to anchor the effect at target foot Z.
Ground/surface stability:
- In renderSelectionCircle(), added floor clamping against terrain, WMO, and M2 floor probes at target XY.
- Raised final placement offset to reduce residual clipping on uneven surfaces.
Depth/visibility behavior:
- Added polygon offset during ring draw to reduce z-fighting.
- Disabled depth testing for the selection effect draw pass (with state restore) so the ring remains visible through terrain/WMO occluders, per requested behavior.
State safety:
- Restored modified GL state after selection pass (depth test / polygon offset / depth mask / cull).
Build validation:
- Verified with cmake build target "wowee" after each stage; final build succeeds.
Combat state/UI:
- Split attack intent from server-confirmed auto attack in GameHandler.
- Add explicit combat state helpers (intent, confirmed, combat-with-target).
- Update player/target frame and renderer in-combat indicators to use confirmed combat.
- Add intent-only visual state in UI to avoid false combat feedback.
Animation correctness:
- Correct combat-ready animation IDs to canonical ready stances (22/23/24/25).
- Remove hit/wound-like stance behavior caused by incorrect ready IDs.
Classic/TBC/Turtle melee reliability:
- Tighten melee sync while attack intent is active: faster swing resend, tighter facing threshold, and faster facing cadence for classic-like expansions.
- Send immediate movement heartbeat after facing corrections and during stationary melee sync windows.
- Handle melee error opcodes explicitly (NOTINRANGE/BADFACING/NOTSTANDING/CANT_ATTACK) and immediately resync facing/swing where appropriate.
- On ATTACKSTOP with persistent intent, immediately reassert ATTACKSWING.
- Increase movement heartbeat cadence during active classic-like melee intent.
Server compatibility/anti-cheat stability:
- Restrict legacy force-movement/speed/teleport ACK behavior for classic-like flows to avoid unsolicited order acknowledgements.
- Preserve local movement state updates while preventing bad-order ACK noise.
Bag bar: left-click drag bags to swap positions using CMSG_SWAP_ITEM
with INVENTORY_SLOT_BAG_0 (255). Local optimistic swap for instant
feedback. Camera controller now respects ImGui WantCaptureMouse.
Vendor auto-open bags only triggers once per session.
Fix opcodes: CMSG_GAMEOBJECT_USE 0x01B→0x0B1 (typo caused
SMSG_FORCEACTIONSHOW spam), CMSG_CANCEL_AURA 0x033→0x136,
SMSG_SELL_ITEM 0x1A4→0x1A1.
Replace 2D screen-space ding rings with real WoW LevelUp.m2 particle/geometry
effect. Fix FBlock particle color parsing (C3Vector floats, not CImVector bytes)
which was producing blue/red instead of golden yellow. Spell effect models bypass
particle dampeners, glow sprite conversion, Mod→Additive blend override, and all
collision (floor/wall/camera) to prevent camera zoom-in. Other players' level-ups
trigger the 3D effect at their position with group chat notification. F7 hotkey
for testing.
- getSpellCastResultString now returns "Not enough rage/energy/focus/runic power" based on player power type instead of always "Not enough mana"
- Fix NPC combat messages concatenating onto previous lines by combining prefix+body into single renderTextWithLinks call instead of TextWrapped+SameLine
- Improve generic error strings to be more WoW-authentic (Invalid target, Target not in line of sight, etc.)
The character stats panel was showing Armor: 0 because summing armor
from item query responses is fragile (depends on correct BuyCount/damage
block parsing). Instead, read the server-authoritative total armor
directly from UNIT_FIELD_RESISTANCES (physical resistance, index 0)
in the player entity update fields.
Added UNIT_FIELD_RESISTANCES to the UF enum and all four expansion
JSON files with correct wire indices:
WotLK 3.3.5a: 99 (NPC_FLAGS=82 + emotestate + stat×5 + posstat×5 + negstat×5)
TBC 2.4.3: 185 (NPC_FLAGS=168 + same relative layout)
Classic 1.12: 154 (NPC_FLAGS=147 + emotestate + stat×5, no posstat/negstat)
Turtle WoW: 154 (same as Classic)
Stats panel uses server armor when > 0, falls back to summed item-query
armor otherwise. Armor rating resets to 0 on world entry and is updated
from both CREATE_OBJECT and VALUES update blocks.
Warriors (rage) and rogues/druids (energy) had no power bar rendered
when maxPower was 0 — the server often omits UNIT_FIELD_MAXPOWER1 for
rage-based classes since rage starts at 0. Rage and energy always cap
at 100, so default maxPower to 100 when the server sends 0 for those
power types. Also unified bar height to 18px (matching health bar) and
added proper power-type colour to the target frame bar (was always blue).
SMSG_ITEM_QUERY_SINGLE_RESPONSE in WotLK 3.3.5a sends BuyCount as a
separate field before BuyPrice. The parser was skipping only one of the
two fields, shifting every subsequent read by 4 bytes. This caused
statsCount to be read from ContainerSlots (always 0 for non-bags) so
no stat pairs were parsed, and the armor field was read from the wrong
offset in the damage block — leaving all stat bonuses and armor at 0.
Also moved armor above stat bonuses in the item tooltip to match WoW's
canonical tooltip layout (armor, then green stat lines).
- game_handler.cpp: use-after-move on node.id after std::move(node)
(save nodeId before the move)
- tcp_socket.cpp, world_socket.cpp: virtual call in destructor bypasses
dispatch; use qualified TCPSocket::disconnect() / WorldSocket::disconnect()
to make intent explicit
- wmo_renderer.cpp: float loop counters risk precision drift; replace with
integer step counts and reconstruct float from index
- game_screen.cpp: (float + 0.5) cast to int is incorrect rounding;
use std::lround instead
- use interpolated target position (getX/Y/Z) for selection circle placement
- avoids drawing circle at movement destination before creature arrives
- keeps previous target interpolation update guarantees
- use movement animation (prefer run, fallback walk) for server-driven creature moves
- synthesize short movement duration for duration-less movement deltas to avoid glide/attack-pose sliding
- return to idle after both walk/run movement states
- drive target circle from entity latest position and always interpolate selected/engaged targets
- propagate item damage range and delay into ItemDef during inventory rebuild
- show weapon damage, speed, and DPS in inventory/character slot tooltips
- fix online spawn camera pitch sign so third-person camera starts above ground
- parse and cache item class/subclass, damage range, and attack delay from item query responses
- render weapon damage, speed, and DPS in the shared item-link tooltip
- render weapon damage, speed, and DPS in vendor hover tooltips
- keep armor and primary stat lines intact
PushID(item.slot) causes conflicting IDs when the server sends items with
duplicate or zero slot values. Use the loop index instead, which is always
unique regardless of what the server puts in the slot field.
Auto-detect whether SMSG_LIST_INVENTORY has 7 fields (28 bytes/item, no
extendedCost) or 8 fields (32 bytes/item) per item from packet size. Servers
that omit extendedCost caused every item after the first to have garbage prices
due to misaligned field reads.
Also remove the [+Tokens] hybrid indicator; only show [Tokens] on pure
token-purchased items (buyPrice==0 && extendedCost!=0).
- Trigger ding when UNIT_FIELD_LEVEL increases for player: plays LevelUp sound,
cheer emote animation, and shows screen overlay
- renderDingEffect(): 3 expanding golden rings + "LEVEL X!" / "DING!" text
drawn via ImDrawList foreground (3s duration, fades out last 0.8s)
- triggerDing() wires sound (UiSoundManager::playLevelUp) + emote + overlay
- LevelUpCallback in GameHandler fires on genuine level increase (newLevel > oldLevel)
- "Test: Level Up" button in escape menu triggers ding at current player level
Checkbox in Settings > Gameplay > Loot section. When enabled, all items
are automatically sent CMSG_AUTOSTORE_LOOT_ITEM on loot response (same
as right-click looting each item). Gold always auto-loots regardless.
Setting persists in settings.cfg as auto_loot=0/1.
- Mute button: small [M] button alongside minimap zoom controls, turns red when active; directly sets AudioEngine master volume to 0, restores on unmute; persists in settings.cfg
- Original Soundtrack: checkbox in Settings > Audio that controls whether custom original music tracks (file: prefix) are included in zone music rotation; when disabled, only WoW MPQ tracks play; persists in settings.cfg
- ZoneManager.getRandomMusic() now filters file: paths when OST is disabled, falling back to full list if zone has no non-file tracks
- Handle uppercase \$N in replaceGenderPlaceholders (WoW servers send \$N for player name, we only handled \$n)
- Fix SMSG_QUESTGIVER_REQUEST_ITEMS required item field order: packet sends [displayInfoId, count, itemId] not [itemId, count, displayInfoId], causing wrong items to display (e.g. Ring of Pure Silver instead of Tough Wolf Meat)