- Buff bar was at Y=140 which overlaps the minimap (Y=10 to Y=210);
moved to Y=215 (just below minimap bottom edge) with 8 icons per row
- Quest tracker moved from Y=200 (inside minimap area) to Y=320 to
leave space for up to 3 rows of buffs between minimap and tracker
- Both are right-anchored and no longer conflict with the minimap or
each other in typical usage (up to ~20 active auras)
- Relocates buff bar from top-left Y=145 (overlapping party frames) to
top-right (screenW - barW - 10, 140) where it doesn't conflict with
party/raid frames anchored on the left side
- Increases max shown auras from 16 to 40 (WotLK supports 48 slots)
- Two-pass rendering: buffs shown first, debuffs below with a spacing gap
between them; both still use green/red borders for visual distinction
- Widens row to 12 icons for better horizontal use of screen space
Right-clicking a party member name in the 5-man party frame opens
a context menu with: Target, Set Focus, Whisper, Trade, Inspect.
- Whisper switches chat type to WHISPER and pre-fills the target name
- Trade calls GameHandler::initiateTrade(guid)
- Inspect sets target then calls GameHandler::inspectTarget()
- Uses BeginPopupContextItem tied to the Selectable widget
- Party frames: gold star prefix and gold name color for group leader;
LFG role badges [T]/[H]/[D] shown inline after member name
- Raid frames: leader name rendered in gold with a corner star marker;
role letter (T/H/D) drawn in bottom-right corner of each compact cell;
uses partyData.leaderGuid already present in the function scope
- Minimap party dots already use gold for leader (unchanged)
- Add latency indicator below minimap (color-coded: green/yellow/orange/red)
using the lastLatency value measured via CMSG_PING/SMSG_PONG
- Add BG queue status indicator below minimap when in WAIT_QUEUE
(abbreviated name: AV/WSG/AB/EotS etc.)
- Target-of-Target frame: add level display and click-to-target support
- Expose getLatencyMs() accessor on GameHandler
Add a compact focus target frame on the right side of the screen
when the player has a focus target set via /focus.
- Shows [Focus] label, name (colored by hostility/level diff), level
- HP bar with green→yellow→red coloring; power bar with type colors
- Cast bar showing spell name and remaining time when focus is casting
- Clicking the frame targets the focus entity
- Clears automatically when focus is lost (/clearfocus)
Replace the text-only "/join to enter" message with an interactive
popup that shows the BG name, a live countdown progress bar, and
Enter/Leave Queue buttons.
- Parse STATUS_WAIT_JOIN timeout from SMSG_BATTLEFIELD_STATUS
- Store inviteReceivedTime (steady_clock) on the queue slot
- BgQueueSlot moved to public section so UI can read invite details
- Add declineBattlefield() that sends CMSG_BATTLEFIELD_PORT(action=0)
- acceptBattlefield() optimistically sets statusId=3 to dismiss popup
- renderBgInvitePopup: colored countdown bar (green→yellow→red),
named BG (Alterac Valley, Warsong Gulch, etc.), auto-dismisses on expiry
- Vendor window: replace manual stat-only tooltip with full renderItemTooltip
(now shows bind type, slot, weapon stats, armor, extra stats, spell effects,
flavor text, and sell price — consistent with inventory)
- Loot-roll popup: add item icon and hover tooltip via renderItemTooltip
- Loot-roll: pre-fetch item info via queryItemInfo when roll prompt appears
- Parse SMSG_ALL_ACHIEVEMENT_DATA on login to populate earnedAchievements_ set
- Pass achievement name through callback so toast shows name instead of ID
- Add renderItemTooltip(ItemQueryResponseData) overload for loot/non-inventory contexts
- Loot window now shows full item tooltip on hover (stats, sell price, bind type, etc.)
Fallback sphere for GameObjects without a loaded renderer instance was 2.5f,
causing invisible/unloaded chairs in Goldshire Inn to be accidentally targeted
during camera right-drag. This sent CMSG_GAMEOBJ_USE which set server stand
state to SIT, trapping the player until a stand-up packet was sent.
Reduce fallback radius to 1.2f and height offset to 1.0f so only deliberate
close-range direct clicks register on unloaded GO geometry.
Camera controller / sitting:
- Any movement key (WASD/QE/Space) pressed while sitting now clears the
sitting flag immediately, matching WoW's sit-to-stand-on-move behaviour
- Added StandUpCallback: when the player stands up via local input the
callback fires setStandState(0) → CMSG_STAND_STATE_CHANGE(STAND) so
the server releases the sit lock and restores normal movement
- Fixes character getting stuck in sit state after accidentally
right-clicking a chair GO in Goldshire Inn (or similar)
Nameplates:
- Use getRenderPositionForGuid() (renderer visual position) as primary
source for nameplate anchor, falling back to entity X/Y/Z only when
no render instance exists yet; keeps health bars in sync with the
rendered model instead of the parallel entity interpolator
Player buff bar and target debuff bar icons now show full spell tooltip
(school, cost, cast time, range, description) on hover, matching the
action bar and spellbook. Falls back to plain spell name if DBC is not
loaded. Remaining aura duration is shown below the spell body.
Expose SpellbookScreen::renderSpellInfoTooltip() as a public method,
then use it in the action bar slot tooltip. Action bar spell tooltips
now show the same full tooltip as the spellbook: spell school (colored),
mana/rage/energy cost, cast time, range, cooldown, and description.
Falls back to a plain spell name if DBC data is not yet loaded.
Hearthstone location note is appended after the rich body.
Cooldown text moved inside each branch for consistent styling.
- Use getQualityColor() for consistent quality coloring (choice+fixed)
- Show item icons for fixed rewards (previously text-only)
- Replace useless "Reward option" tooltip with real item name+description
- Render icon before selectable label (not after) for choice rewards
- Call ensureItemInfo for all reward items to trigger async fetch
- Use structured bindings (C++17) to unify icon+color resolution
Replace flat white coloring with item quality colors and add hover tooltips
showing item name (quality-colored) and description for quest acceptance window.
Extract renderQuestRewardItem lambda to eliminate code duplication between
choice and fixed reward item rendering.
Parse and store reward items (choice and fixed) from SMSG_QUESTGIVER_QUEST_DETAILS
in both WotLK (QuestDetailsParser) and TBC/Classic (TbcPacketParsers) parsers.
Show item icons, names, and counts in the quest acceptance dialog alongside XP/money.
Move QuestRewardItem before QuestDetailsData in header to fix forward-reference.
- Use isPetSpellAutocast() instead of parsing the slot value high byte for
autocast detection; the authoritative source is the SMSG_PET_SPELLS spell
list activeFlags, not the action bar slot value.
- Fix tooltip mapping: actionId==2 maps to "Follow", actionId==5 to "Attack",
others to "Stay" (removed erroneous duplicate Follow case for actionId==4).
- Update spellbook comment: TBC Spell.dbc has ~220+ fields (not ~167).
Show the 10 SMSG_PET_SPELLS action slots as clickable icon/text buttons
in the pet frame. Spell slots with icons render as ImageButtons; built-in
commands (Attack/Follow/Stay) render as text buttons. Autocast-on slots
are tinted green. Clicking a spell slot sends CMSG_PET_ACTION with the
current target GUID; built-in commands send without a target. Tooltips
show the spell name on hover.
- Add ITEM_FIELD_DURABILITY (60) and ITEM_FIELD_MAXDURABILITY (61) to
update_field_table.hpp enum and wotlk/update_fields.json
- Add curDurability/maxDurability to OnlineItemInfo and ItemDef structs
- Parse durability fields in OBJECT_CREATE and OBJECT_VALUES handlers;
preserve existing values on partial updates (fixes stale durability
being reset to 0 on stack-count-only updates)
- Propagate durability to ItemDef in all 5 rebuildOnlineInventory() paths
- Implement GameHandler::repairItem() and repairAll() via CMSG_REPAIR_ITEM
(itemGuid=0 repairs all equipped items per WotLK protocol)
- Add canRepair flag to ListInventoryData; set it when player selects
GOSSIP_OPTION_ARMORER in gossip window
- Show "Repair All" button in vendor window header when canRepair=true
- Display color-coded durability in item tooltip (green >50%, yellow
>25%, red <=25%)
- application.cpp creature sync loop: use entity->isEntityMoving() alongside
planarDist to detect movement; entities > 150u have stale getX/Y/Z (distance
culled in GameHandler::update) but isEntityMoving() correctly reflects active
startMoveTo paths from SMSG_MONSTER_MOVE. Fixes distant NPCs playing Stand
while creatureMoveCallback drives their renderer to Run.
- Switch sync loop to getLatestX/Y/Z (server-authoritative destination) for
both the distance check and renderPos so creature positions are never stale
from cull lag, and don't call moveInstanceTo when only entityIsMoving (no
planarDist): the renderer's spline-driven move from creatureMoveCallback is
already correct and shouldn't be cancelled by the per-frame sync.
- game_screen.cpp: replace scratch-built ring-burst level-up overlay with a
simple "You have reached level X!" centered text (WoW style). The actual 3D
visual is already handled by Renderer::triggerLevelUpEffect (LevelUp.m2).
Action bars:
- Expand from 2 bars (24 slots) to 4 bars (48 slots)
- Bar 2: right-edge vertical bar (slots 24-35), off by default
- Bar 3: left-edge vertical bar (slots 36-47), off by default
- New "Interface" settings tab with toggles and offset sliders for all bars
- XP bar Y position now tracks bar 2 visibility and vertical offset
HUD resize fix:
- All HUD elements (action bars, bag bar, XP bar, cast bar, mirror timers)
now use ImGui::GetIO().DisplaySize instead of window->getWidth/Height()
- DisplaySize is always in sync with the current frame — eliminates the
one-frame lag that caused bars to misalign after window resize
Player nameplates:
- Show player name only on nameplate (no level number clutter)
- Fall back to "Player (level)" while name query is pending
- NPC nameplates unchanged (still show "level Name")
XP bar rest state:
- isResting_ now set from PLAYER_BYTES_2 byte 3 bit 0 (rest state flag)
on both CREATE and VALUES update object handlers
- playerRestedXp_ was missing from VALUES handler — now tracked there too
- Eliminates dependency on SMSG_SET_REST_START (wrong in WotLK opcodes.json)
Interface settings:
- New "Interface" tab in Settings window
- "Show Second Action Bar" toggle (default: on)
- Horizontal/vertical position offset sliders for bar 2
- Settings persisted to/from save file
- Add BG_SYSTEM_NEUTRAL/ALLIANCE/HORDE chat types (0x52-0x54) and reclassify
them as SYSTEM in the parser — prevents bogus [Say] prefix on arena/BG
system messages
- Remove fallback [TypeName] bracket for sender-less SAY/YELL/WHISPER messages;
only group-channel types (Party/Guild/Raid/BG) show brackets without a sender
- Remove factionTemplate != 0 guard — units with FT=0 now get setHostile() like
any other unit (defaulting to hostile from the map default), fixing NPCs that
appeared friendly due to unset faction template
- Enable CMSG_LOOT for WotLK type=3 (chest) game objects in addition to
CMSG_GAMEOBJ_USE — fixes Milly's Harvest and other quest gather objects on
AzerothCore WotLK servers
When SMSG_MESSAGECHAT arrives before the entity has spawned or its
name is cached, senderName is empty and messages fell through to the
generic '[Say] message' branch. Fix:
- GameHandler::lookupName(guid): checks playerNameCache then entity
manager (Unit subclass cast) at call time
- Chat display: resolves senderName via lookupName() at render time
so messages show "Name says: msg" even if the name was unavailable
when the packet was first parsed
- Display <GM>, <AFK>, <DND> prefix before sender name in all chat
message formats based on the chatTag bitmask byte (0x04=GM, 0x01=AFK,
0x02=DND) from SMSG_MESSAGECHAT
- Apply tagPrefix consistently across SAY/YELL/WHISPER/EMOTE/CHANNEL
and the generic bracket-type fallback
- getChatTypeName: use WoW-style mixed-case names (Party/Guild/Raid/etc.)
instead of all-caps (PARTY/GUILD/RAID)
- WHISPER_INFORM: display "To Name: message" instead of "[To] Name: message"
using receiverName when available, falling back to senderName
- wmo_renderer: pass character position (not camera position) to portal
visibility traversal — the 3rd-person camera can orbit outside a WMO
while the character is inside, causing interior groups to cull; render()
now accepts optional viewerPos that defaults to camPos for compatibility
- renderer: pass &characterPosition to wmoRenderer->render() at both
main and single-threaded call sites; reflection pass keeps camPos
- renderer: apply mount pitch/roll to rider during all flight, not just
taxiFlight_ (fixes zero rider tilt during player-controlled flying)
- game_screen: format SAY/YELL/WHISPER/EMOTE using WoW-style "Name says:"
instead of "[SAY] Name:" bracket prefix
- SMSG_IGNORE_LIST was silently consumed; now parses guid+name pairs to
populate ignoreCache so /unignore works correctly for pre-existing
ignores loaded at login.
- MSG_TALENT_WIPE_CONFIRM was discarded without responding; now parses
the NPC GUID and cost, shows a confirm dialog, and sends the required
response packet when the player confirms. Without this, talent reset
via Talent Master NPC was completely broken.
CMSG_LFG_SET_BOOT_VOTE was defined in the opcode table but never sent.
- Add GameHandler::lfgSetBootVote(bool) which sends the packet
- Fix handleLfgBootProposalUpdate() to set lfgState_=Boot while the
vote is in progress and return to InDungeon when it ends
- Add Yes/No vote buttons to the Dungeon Finder window when in Boot state
Quest kill count tracker in the HUD now resolves creature names from the
cached creature query results and displays them as "Name: x/y" instead
of bare "x/y". The system chat progress message on kill also includes
the creature name when available, matching retail client behavior.
- Track PLAYER_REST_STATE_EXPERIENCE update field for all expansions
(WotLK=636, Classic=718, TBC=928, Turtle=718)
- Set isResting_ flag from SMSG_SET_REST_START packet
- XP bar shows rested bonus as a lighter purple overlay extending
beyond the current fill to (currentXp + restedXp) position
- Tooltip text changes to "%u / %u XP (+%u rested)" when bonus exists
- "zzz" indicator shown at bar right edge while resting
- Nameplates: player names always rendered regardless of V-key toggle;
separate cull distance 40u (players/target) vs 20u (NPCs); cyan name
color for other players; fade alpha scales with cull distance
- Level-up: add expanding golden ring burst (3 staggered waves, 420u
max radius) + full-screen flash to renderDingEffect(); M2 LevelUp.m2
is still attempted as a bonus on top
- Vanilla tile loading: add AssetManager::setBaseFallbackPath() so that
when the primary manifest is an expansion-specific DBC-only subset
(e.g. Data/expansions/vanilla/), world terrain files fall back to
the base Data/ extraction; wired in Application::initialize()
- Warden: map a null guard page at address 0x0 in the Unicorn emulator
so NULL-pointer reads in the module don't crash with UC_ERR_MAP;
execution continues past the NULL read for better diagnostics
The selection circle was positioned using the entity's game-logic
interpolator (entity->getX/Y/Z), while the actual M2 model is
positioned by CharacterRenderer's independent interpolator (moveInstanceTo).
These two systems can drift apart during movement, causing the circle
to appear under the wrong position relative to the visible model.
Fix: add CharacterRenderer::getInstancePosition / Application::getRenderPositionForGuid
and use the renderer's inst.position for XY (with footZ override for Z)
so the circle always tracks the rendered model exactly. Falls back to
the entity game-logic position when no CharacterRenderer instance exists.
Parse the full and single-update variants of MSG_RAID_TARGET_UPDATE to
track which guid carries each of the 8 raid icons (Star/Circle/Diamond/
Triangle/Moon/Square/Cross/Skull). Marks are cleared on world transfer.
The target frame now shows the Unicode symbol for the target's raid mark
in its faction color to the left of the name. Nameplates show the same
symbol to the left of the unit name for all nearby marked units.
Expand action bar from 12 to 24 slots (2 bars × 12). Bar 2 is rendered
above bar 1 and loaded from SMSG_ACTION_BUTTONS slots 12-23. Pressing
Shift+number activates the corresponding bar-2 slot. Drag-and-drop,
cooldown overlays, and tooltips work identically on both bars. Bar 2
fades slightly when all its slots are empty to minimize visual noise.
Draws the current zone name centered above the minimap circle using a
gold-colored 12pt label with drop shadow. This gives players a constant
location reference without needing to trigger the full-screen zone flash.
Uses getForegroundDrawList so it renders above the minimap texture.
Left-clicking anywhere within a nameplate's bounding box (name text +
health bar) calls setTarget() for that unit. Uses manual mouse position
hit testing since nameplates are drawn on the background DrawList rather
than as ImGui widgets. Click is ignored when ImGui has captured the mouse
(e.g. when a window is open).
Store structured friend data (online status, level, area, class) that
was previously discarded in handleFriendList/handleContactList. New
ContactEntry struct lives in game_handler.hpp; getContacts() exposes it.
UI: the O-key Social window (formerly guild-only) now has a Friends tab.
- Shows online/offline status dot, name, level, and AFK/DND label
- Pressing O when not in a guild opens Social directly on the Friends tab
- The window title changed from "Guild" to "Social" for accuracy
- Non-guild players no longer get a "not in a guild" rejection on O press
The V toggle previously only rendered a nameplate for the currently
targeted unit. Now all nearby units get a nameplate when nameplates are
enabled, matching WoW's native behaviour:
- Target: nameplate shown up to 40 units, gold border highlight
- All other units: shown up to 20 units, dark border (no highlight)
- Fade-out range, hostility colour, level label, and health bar logic
are all unchanged — only the per-entity distance culling changes
Replace the plain yellow text cooldown overlay with a proper clock-sweep:
- Dark fan spanning the elapsed fraction of the cooldown, sweeping
clockwise from 12 o'clock (matches WoW's native cooldown look)
- White remaining-time text with drop-shadow centered on the icon
- Minutes shown as "Xm" for cooldowns >= 60s, seconds otherwise
- Fan radius set to 1.5× the icon half-width to cover corners on the
square icon; works for both icon and empty (label-only) slots
Draw a dot for each online party member that has reported a position via
SMSG_PARTY_MEMBER_STATS. Leader gets a gold dot, others get blue. A
white outline ring is drawn around each dot, and hovering over it shows
the member's name as a tooltip. Out-of-range members are silently
skipped by the existing projectToMinimap clamp logic.
Axis mapping follows the same convention as minimap pings: server posX
(east/west) → canonical Y, server posY (north/south) → canonical X.
Raid frames:
- When groupType=1 (raid), render compact grid-style raid frames instead
of the vertical party list that would overflow for 25/40-man groups
- Members organized by subgroup (G1-G8), up to 5 rows per subgroup column
- Each cell shows: name, health bar (green/yellow/red), power bar (class color)
- Clicking a cell targets the member; border highlight for current target
- Frames anchored above action bar area, centered horizontally
Quest log scroll-to-quest:
- openAndSelectQuest(questId) selects the quest AND scrolls the list pane
to show it (SetScrollHereY on the first render frame after open)
- One-shot scroll: scrollToSelected_ cleared after first use so normal
scroll behavior is unaffected afterward
Quest tracker:
- Clicking a tracked quest now calls openAndSelectQuest() — opens the log
AND jumps to that specific quest rather than just opening to top
Hearthstone post-teleport fix:
- Expand same-map hearthstone precache from 5x5 to 9x9 tiles so workers
have more tiles parsed before the player arrives at the bind point
- After same-map teleport arrival, enqueue the full load-radius tile grid
(17x17 = 289 tiles) at the new position so background workers immediately
start loading all WMOs/M2s visible from the new location
Quest tracker improvements:
- Clicking a quest in the tracker now opens the Quest Log (L)
- Remove NoInputs flag so the tracker window receives mouse events
- Show only tracked quests in tracker; fall back to all quests if none tracked
- Add Track/Untrack button in Quest Log details panel
- Abandoning a quest automatically untracks it
- Track state stored in GameHandler::trackedQuestIds_ (per-session)
- Handle MSG_CHANNEL_START: populate unitCastStates_ for both the local
player and any non-player caster (boss/mob channeled spells); use
full uint64 GUIDs for TBC/Classic, packed GUIDs for WotLK
- Handle MSG_CHANNEL_UPDATE: sync remaining channel time; clear cast
state on channel completion (remainingMs == 0)
- Fix SMSG_RESUME_CAST_BAR: also resumes non-player units' cast bars
(previously only resumed the player's own bar after zone transitions)
- Add party member cast bars in renderPartyFrames: golden progress bar
appears beneath the power bar when a party member is casting,
leveraging the existing unitCastStates_ per-GUID map
Previously the target cast bar tracked a single target using 4 private
fields. This replaces that with unitCastStates_ (unordered_map<uint64_t,
UnitCastState>), tracking cast state for every non-player unit whose
SMSG_SPELL_START we receive.
Changes:
- GameHandler::UnitCastState struct: casting, spellId, timeRemaining,
timeTotal
- getUnitCastState(guid) → returns cast state for any tracked unit
- isTargetCasting(), getTargetCastSpellId(), getTargetCastProgress(),
getTargetCastTimeRemaining() now delegate to getUnitCastState(targetGuid)
- handleSpellStart: tracks all non-player casters (not just the target)
- handleSpellGo: erases caster from map when spell lands
- update loop: ticks down all unit cast states, erasing expired entries
- unitCastStates_ cleared on world reset
- renderBossFrames: shows red cast progress bar per boss slot with
spell name + remaining seconds — critical for instance interrupt play
Adds 5 gold/grey dot indicators below the power bar in the player frame
for Rogue (class 4) and Druid (class 11), showing the current combo
point count from SMSG_UPDATE_COMBO_POINTS. Active points are bright gold;
empty slots are dark grey. Dots are centered in the frame width.
The display is always shown for Rogues; for Druids it only appears when
combo points are non-zero (they only accumulate in Cat Form).
SMSG_SPELL_START fires for all units, not just the player. Previously only
the player's own cast was tracked; now we also track when the current
target is casting, enabling interrupt decisions.
- GameHandler: track targetCasting_/targetCastSpellId_/targetCastTimeTotal_
/targetCastTimeRemaining_ — updated by SMSG_SPELL_START for the current
target and ticked down in the update loop each frame
- Target cast cleared when: target changes (setTarget), target's spell
lands (SMSG_SPELL_GO), or cast timer expires naturally
- game_screen: renderTargetFrame shows a red cast progress bar between
the power bar and distance line when the target is casting, with
spell name + remaining seconds
- Public accessors: isTargetCasting(), getTargetCastSpellId(),
getTargetCastProgress(), getTargetCastTimeRemaining()
Renders a compact top-centre overlay showing Alliance vs Horde scores
when the player is in a recognised battleground map. Score values are
read directly from the world state map maintained by SMSG_INIT_WORLD_STATES
and SMSG_UPDATE_WORLD_STATE, so no extra server packets are needed.
Supported maps:
489 – Warsong Gulch (flag captures, max 3)
529 – Arathi Basin (resources, max 1600)
30 – Alterac Valley (reinforcements, max 600)
566 – Eye of the Storm (resources, max 1600)
607 – Strand of Ancients
When a player releases spirit, the server sends SMSG_DEATH_RELEASE_LOC
with the corpse map and position. Store this so the ghost can reclaim.
New flow:
- SMSG_DEATH_RELEASE_LOC now stores corpseMapId_/corpseX_/Y_/Z_ instead
of logging and discarding
- canReclaimCorpse(): true when ghost is on same map within 40 yards of
stored corpse position
- reclaimCorpse(): sends CMSG_RECLAIM_CORPSE (no payload)
- renderReclaimCorpseButton(): shows "Resurrect from Corpse" button at
bottom-center when canReclaimCorpse() is true