375 Commits

Author SHA1 Message Date
Kelsi
90b3d6f13b refactor(targeting): one ray picker instead of three copies
Left-click targeting, the right-click world picker and the hover cursor each
carried their own copy of the same traversal — build a hit sphere per entity,
ray-test it, rank units against objects by distance to the entity centre,
prefer a hostile. Around ninety lines apiece, agreeing on everything that
matters and requiring lockstep edits to stay that way. The corpse fix before
this had to be applied twice for exactly that reason, and the hover copy was
already out of step: it had no critter case, so the cursor promised a click
on something a click would miss.

pickScene does the traversal once and returns what it found; each caller
applies its own rules to the result. What genuinely differs is now stated as
parameters — the right-click picker's taller, tighter fallback sphere and its
chair skip — and what only one caller collects (a hooked bobber, quest
objective objects) comes through a per-hit callback rather than a third copy
of the loop.

Net 265 lines out of game_screen.cpp. The two fixed-radius bobber tests stay
where they are: those aim at one known GUID rather than searching the scene.
2026-07-31 18:12:31 -07:00
Kelsi
2d5b29c77c perf(ui): decode the login background off the main thread
The auth screen decoded its background on the frame it first appeared: a
1408x768 PNG in a 2.4MB file, which is 2.4MB of zlib inflate plus the GPU
upload, measured at ~190ms. Start the decode on a worker when the screen
first renders and upload on whichever frame it lands; the existing
descriptor-set guard already skips drawing the background until then, so
the screen simply appears without it for a moment.

The GPU half stays on the main thread, since that is where it has to be —
loadBackgroundImage becomes uploadBackgroundImage and takes pixels the
worker already decoded.

Honest note on value: this is a static screen, so the hitch was hard to
perceive. The loading screen decodes its own image the same way and is
left alone, being a screen that is already a wait.
2026-07-31 10:39:35 -07:00
Kelsi
f90a2c0320 fix: show random property stats in auction house tooltips
Auction results carry the rolled random property separately from the item
template, so browse-tab tooltips rendered only base stats. Build an
instance-aware ItemDef from the query response plus the auction's
randomPropertyId/suffixFactor, using the same bonus folding as inventory
tooltips, so "of the ..." suffix stats are visible before bidding.

Makes the ItemDef overload of renderItemTooltip public so callers outside
InventoryScreen can use it.
2026-07-24 18:10:41 -07:00
Kelsi
fa6faffad8 feat: Max Out Character quick action in GM screen
Add a 'Max Out Character' panel to the GM command screen that detects
your class + active expansion and queues a GM command sequence: set max
level (60/70/80), learn all class spells + talents, max skills, optional
1000g, and add a class/expansion-appropriate gear kit. Commands drain one
per frame to avoid server chat-flood protection. Per-slot toggles let you
pick which parts to apply. Gear lists live in bis_gear_data.cpp — a
curated, easily-extended starter set (anchored on class legendaries);
the server validates each .additem so unknown IDs are skipped.
2026-07-24 04:19:47 -07:00
Kelsi
c08d2f0493 feat: GM screen argument forms + more commands
Parse each command's syntax into labeled form fields instead of an
editable raw string: #x -> numeric input, $x -> text input, a/b ->
dropdown, [word] -> optional flag checkbox. Shows a live 'Will send'
preview, defaults player/name fields to the current target when blank,
and keeps an 'Edit manually' escape hatch. Add 12 commonly-used commands
(reset level/stats/spells/talents/achievements/all, repairitems,
additemset, modify arenapoints/drunk/faction/xp/phase) and de-duplicate
the scattered reset entries.
2026-07-24 03:09:46 -07:00
Kelsi
529f0e7712 feat: GM command screen
Add a searchable GM command browser (micro-menu 'GM' button) over the
existing 195-entry kGmCommands reference. Left pane lists commands
grouped by first token (flat filtered list while searching) with a
max-permission-level filter; right pane shows syntax/description, a
security badge, and an editable command line. Send (or Enter) dispatches
the command to the server as a SAY chat message ('.' prefix, AzerothCore
convention) — the server enforces the real permission level.
2026-07-24 02:52:23 -07:00
Kelsi
4ca3da8caf fix: persist bank 'Combine bags' view; guild bank shows full slot grid
- The bank 'Combine bags' (contiguous vs per-bag sections) toggle was a
  function-local static, so it reset to split on every relaunch. Make it
  a persisted WindowManager member (bank_combine_bags in settings.cfg),
  saved on toggle and loaded at startup.
- Guild bank showed no items or slots: the grid only iterated the slots
  the server sent (sparse, often just occupied ones — nothing for an
  empty tab). Render a fixed 98-slot grid (14x7) and look items up by
  slotId, so slots always appear and items land in the right cells.
2026-07-24 02:22:06 -07:00
Kelsi
82337d71d8 feat: guild bank item deposit + active-tab sync
- Right-clicking a bag item while the guild bank is open now deposits it
  into the first free slot of the viewed tab (guildBankDepositFromInventory).
  Bags auto-open when the guild bank opens so items are reachable, and a
  hint line documents left-click withdraw / right-click deposit.
- Fix latent bug: clicking a guild bank tab only sent a query and never
  updated the active tab, so withdraw/deposit always targeted tab 0. Sync
  guildBankActiveTab_ from each SMSG_GUILD_BANK_LIST (server tags it).
- Add ESC-to-close for the guild bank window.
2026-07-24 02:03:46 -07:00
Kelsi
9b999aa3c7 fix: bank right-click withdraw, guild bank open, craft pane splitter
- Bank: right-clicking a bank item now withdraws it to the bags. The
  bank slot renderer had left-click drag and shift-link but no
  right-click handler, so right-clicks did nothing. Routes through
  withdrawItem(), which now uses CMSG_AUTOSTORE_BANK_ITEM so the server
  places it in any free bag slot (retail), not just the backpack.
- Guild bank: interacting with a guild-vault GameObject (type 34) now
  opens it. Nothing called openGuildBank(), and openGuildBank() never
  sent CMSG_GUILD_BANKER_ACTIVATE (only queried a tab), so no bank list
  arrived. Detect type 34 in interactWithGameObject and send the
  activate; also mark the window open when SMSG_GUILD_BANK_LIST arrives.
- Crafting: the recipe list pane is now a draggable splitter (was fixed
  width, then a fixed proportion) so long recipe names can be read.
2026-07-24 01:33:33 -07:00
Kelsi
9b2931ea87 feat: show real achievement icons in the achievements window
Load Achievement.dbc's IconID (added to the WotLK DBC layout, field 42) into
the achievement cache and resolve it through SpellIcon.dbc to the artwork.
The earned list now renders a bordered 32px icon with the name and points
beside it, replacing the gold-star glyph; a star placeholder fills the slot
while an icon streams in or when one is absent. Icon textures are lazily
BLP-loaded and cached in WindowManager with a per-frame upload cap.
2026-07-23 19:26:28 -07:00
Kelsi
e7fc875d69 fix: resolve spell $-tokens everywhere and prefer the full Description
Move the WoW description token resolver onto GameHandler::formatSpellDescription
and route buff/aura tooltips, the spellbook, and item Use/Equip effect lines
through it, so 'increased by $s1' etc. no longer render raw. Add the $/N;
division token used by food regen ('Restores $/5;s1 health per second').

Prefer Spell.dbc's full Description column over the short Tooltip in both the
spell_handler cache and the spellbook loader, so food tooltips include the
'become well fed and gain N Stamina and Spirit' clause instead of a bare
one-liner. The talent screen now delegates to the shared formatter.
2026-07-23 19:16:06 -07:00
Kelsi
56c309e306 fix: correct Spell Tooltip/Rank columns and resolve talent description tokens
WotLK Tooltip (139->187) and TBC Rank (136->144) / Tooltip (154->178)
layout indices assumed the wrong locale-block stride and landed on empty
columns; point them at the verified enUS strings.

Rework the talent description formatter into a real $-token resolver: it
handles $s/$o/$m/$M base points and $d durations with cross-spell
$<spellId> references (e.g. $14201d), plus $l/$g plural/gender forms,
using live spell data via GameHandler. Unresolvable tokens ($h proc chance,
$t period) are stripped cleanly instead of rendering raw, so Enrage now
reads 'a 4% damage bonus for 12 sec' rather than '$14201s1% ... $14201d'.
2026-07-23 18:36:38 -07:00
Kelsi
b69a679fdc feat: talent tooltips show substituted effect descriptions
The talent panel read Spell.dbc's Tooltip column, which the layouts pointed
at an empty locale field, so hovering a talent showed only name and rank. Add
the correct Description column to every expansion's DBC layout (verified
against each Spell.dbc's string blocks) and read it in the talent screen,
substituting $s/$o magnitude tokens with the rank's EffectBasePoints so
descriptions read with concrete numbers. Unlearned talents show their rank-1
effect under 'Effect:'.
2026-07-23 18:26:21 -07:00
Kelsi
c6562bb071 fix: auction item picker includes equipped bags, posts by GUID
The Create Auction dropdown only iterated the 16-slot base backpack, hiding
every item held in an equipped bag. It now enumerates the backpack plus all
equipped bags and posts the selected item by its server GUID via the new
auctionSellItemByGuid path, so any container can be listed.
2026-07-23 18:16:43 -07:00
Kelsi
9807a69d7c feat: park the DPS meter under the target frame and let it be dragged
It sat near the bottom of the screen, far from the combat it describes,
and was pinned there by NoMove/NoInputs. It now follows the bottom edge of
the target frame, and the first drag latches a position that persists
across sessions; right-click sends it home.
2026-07-23 00:18:59 -07:00
Kelsi
e87d2f612c fix: draw raid target markers as icons floating above the unit
The marks were text symbols, but the ImGui font has no code points for
skull, cross, moon and most of the others, so they rendered as '?' boxes
beside the name. Load Blizzard's UI-RaidTargetingIcon art instead and hang
it over the unit's head like the original client, with the same textures
reused at small size in the target, focus, minimap and party displays.
2026-07-23 00:14:01 -07:00
Kelsi
64fc75395d feat: make the keyring interactive and always visible when enabled
Keyring slots were rendered with placeholder backpack addressing
(SlotKind::BACKPACK, index -1), so keys could not be picked up, moved, or
used. Add a real SlotKind::KEYRING / HeldSource::KEYRING with correct wire
addressing (bag 0xFF, slot 86+i) wired through pickup, place, swap-source,
cancel, and right-click-use paths across all inventory view modes. Also
show at least one keyring row whenever Show Key Ring is enabled so it stays
visible (and a drop target) even when empty, instead of hiding when it
holds no keys.
2026-07-22 02:47:07 -07:00
Kelsi
368d54af12 feat: AddOns manager on character select with enable/disable
Add an AddOns button to the character-select footer that opens a window listing
every installed addon (title, version, author, notes) with a per-addon
enable/disable checkbox. Enabled state persists to <config>/addons.cfg and is
honored by loadAllAddons (disabled addons are skipped and hidden from the Lua
VM); /reload picks up changes. Toggles apply on the next world enter, matching
retail behavior.
2026-07-21 22:45:31 -07:00
Kelsi
17272519cb fix: don't auto-attack when right-drag rotating the camera near a mob
Right-click interact/attack fired on button press with no drag detection, so
pressing RMB to rotate the view would raypick a nearby hostile unit and start
auto-attacking it. Mirror the left-click tap/drag pattern: record the press
position and only interact/attack on release when the cursor moved <5px (a tap),
treating a larger move as a camera rotate.
2026-07-21 19:34:22 -07:00
Kelsi
80ce3a61b0 fix: action bar drag empties source slot and swaps correctly
Pickup now removes the action from its slot so it visibly rides the cursor
instead of staying put. Fix a reference-invalidation bug in the swap where the
live slot reference was mutated before the displaced action was read, causing
the existing item to stay and the carried one to be lost. Displaced actions now
fall back into the emptied origin; cancel/off-bar paths restore or delete safely.
2026-07-21 19:24:06 -07:00
Kelsi
ee0eb34929 feat: quest tracker current-zone filter, default to it
Add a 'Zone' filter mode to the on-screen quest tracker that shows only quests
whose zoneOrSort matches the player's current zone (getWorldStateZoneId), and
make it the default. Falls back to showing all quests when the zone isn't known
yet. Filter now cycles All / Active / Done / Zone.
2026-07-21 19:08:25 -07:00
Kelsi
8be5567bb7 fix: make chat window resizable and target frame auto-fit its content
Chat window resize was gated behind unlocking (locked forced NoResize); resize is
now decoupled from lock so the grips always work — locking only pins position and
blocks moving. Size persists in either state. Target frame now auto-sizes to its
widest line (name, subtitle, guild, level/classification row) with a 250px floor
instead of a fixed width that clipped the level line.
2026-07-21 19:02:21 -07:00
Kelsi
969f757cdb feat: press-and-hold to reorganize action bar slots
Hold left-click on a filled slot for 0.6s to lift its action onto the cursor
(a rising fill shows the charge); a quick click still casts/uses. While carried,
click another slot to swap, click the source again or empty space to cancel, or
right-click off the bar to remove. Wires up the previously dormant drag state.
2026-07-21 19:02:21 -07:00
Kelsi
b058e8edd9 feat: resizable persistent chat window and auto-widening target frame
Chat window size is now captured while unlocked and persisted (chat_window_w/h),
so a resized window keeps its size after locking or restart; a size constraint
keeps it from collapsing. Target frame grows to fit long names, guild tags, and
creature subtitles instead of clipping at a fixed 250px.
2026-07-21 18:39:50 -07:00
Kelsi
2de06c267a add map trackers and fix spell and mount state 2026-07-21 02:23:51 -07:00
Kelsi
56d7c6e71b feat: rare tracker — mark nearby spawned rares on the world map
Adds an opt-in world-map layer that marks every rare (rank 4) and rare-elite
(rank 2) creature the client currently has loaded, so a rare that is out shows
as a gold/silver diamond with its name in the current zone. Entities only exist
near the player, so a marker means that rare is genuinely spawned right now.

New RareTrackerLayer follows the existing overlay-layer pattern; the HUD feeds it
the filtered live units each frame. Gated behind a new 'Show Rare Tracker'
Interface setting (persisted), off by default.
2026-07-20 20:56:39 -07:00
Kelsi
958c426b4f feat: add equipment-slot filter and client-side buyout/max-price refinements to auction house
Adds a server-side inventory-type (slot) filter carried in the
CMSG_AUCTION_LIST_ITEMS auctionSlotID field, plus buyout-only and
max-price page filters applied client-side to the current results page.
Auction item tooltips now compare against the equipped slot item.
2026-07-19 22:17:48 -07:00
Kelsi
bd83587077 confirm bind-on-equip items before equipping 2026-07-18 13:47:39 -07:00
Kelsi
7d87d0d86f redesign character selection screens 2026-07-17 15:33:59 -07:00
Kelsi
3007ee6b60 fix responsive character preview 2026-07-17 14:53:44 -07:00
Kelsi
4a39f9c5cc add adjustable UI window scaling 2026-07-17 14:39:23 -07:00
Kelsi
328fa11c7f fix indoor ambience and whisper parsing 2026-07-17 13:58:33 -07:00
Kelsi
dbc81d3838 tune mount and city bell audio 2026-07-17 13:47:53 -07:00
Kelsi
799ab3c72d fix(gameplay): repair barber, unstuck mounts and terrain seams 2026-07-16 21:28:12 -07:00
Kelsi
949cf1d923 fix(ui): correct character creation appearance and preview controls 2026-07-16 18:10:24 -07:00
Josh Anderson
d57433990b fix(auth): fall back for Turtle security extensions 2026-07-15 17:20:50 -05:00
Kelsi
aa3cab9917 feat(spells): name the missing crafting station in spell focus errors
SMSG_CAST_RESULT and SMSG_CAST_FAILED append the SpellFocusObject id on
requires-spell-focus failures, but the parsers stopped at the result
byte, leaving only a generic 'Requires spell focus' message. Read the
trailing id on all three expansion parsers, resolve it through
SpellFocusObject.dbc, and report 'Requires Cooking Fire nearby.' /
'Requires Anvil nearby.' etc., with a clearer fallback when the id is
unavailable.
2026-07-14 21:38:48 -07:00
Kelsi
51e99a5c18 feat(ui): standalone crafting window opened by profession spells
Casting a profession spell (Cooking, First Aid, Alchemy, Smelting, ...)
from the spellbook, action bar, or /cast now opens a dedicated crafting
window instead of sending a no-op cast. The window shows a skill progress
bar, recipes with item icons colored orange/yellow/green/gray by
difficulty, can-make counts, search and have-reagents filters, reagent
have/need lists, and quantity + Create All controls backed by the craft
queue. Trainer panel difficulty lambdas now delegate to the shared
recipeDifficultyColor/Label helpers.
2026-07-14 21:03:24 -07:00
Kelsi
9ec2a26a5b feat(settings): add configurable view distance
Also remove decorative punctuation from the resurrection notification.
2026-07-14 19:53:37 -07:00
Kelsi
bc1ceb802d fix(ui): make quest and minimap overlays opt-in 2026-07-14 19:28:09 -07:00
Kelsi
35cf55305b fix(macos): correct display settings and hide FidelityFX 2026-07-14 18:52:00 -07:00
Kelsi
512305692c refactor(ui): extract buff bar layout arithmetic and test it
renderBuffBar is ~400 lines and the layout maths was buried in the middle of it,
which is exactly where a silent bug lives: the row does not wrap, so it has a hard
capacity, and it has to stay clear of the minimap at every resolution and scale.

The arithmetic moves to buff_bar_layout.hpp as a pure function and combat_ui.cpp
calls it, so the tested maths is the maths that runs. 408 assertions sweep
resolutions from 1280x720 to 4K and scales from 0.75x to 1.5x, checking the row
never overlaps the minimap, never runs off screen, drops overflow rather than
wrapping, and always gives weapon enchants their slots before auras.
2026-07-14 15:08:45 -07:00
Kelsi
c085d41820 fix(ui): rename UI Scale to Buff Bar Scale
The slider only scales the buff bar, so the name overpromised. Renamed the
setting, its label and its config key (ui_scale -> buff_bar_scale), and moved it
under a Buff Bar heading in Settings > Interface.
2026-07-14 14:00:54 -07:00
Kelsi
18c57cc236 feat(ui): move the buff bar to a single top-right row and add a UI scale setting
The player effects bar now sits along the top of the screen, right of centre, as
one long row: it is right-aligned to end just left of the minimap and grows
leftwards as auras are gained, so buffs and debuffs no longer wrap onto extra
rows. Icons are 25% larger (32px -> 40px at the 1080p reference) and now scale
with the window size, with a new UI Scale slider in Settings > Interface layered
on top and persisted to the config.
2026-07-14 13:50:50 -07:00
Kelsi
17ced9399c feat(audio): add character error speech responses gated by settings checkbox
New PlayerVoiceManager plays the player's spoken error lines ("Not enough
mana", "I'm out of range", ...) on cast failures, inventory/buy/trainer
errors, loaded lazily per race/gender and toggled via the Character Speech
checkbox in audio settings.
2026-07-14 11:49:43 -07:00
Kelsi
2722ee4af9 feat(ui): add hide button collapsing quest tracker to a floating bubble
The bubble shows the quest count, shares the tracker's right-edge anchor,
can be dragged without expanding, and the collapsed state persists in
settings.
2026-07-14 01:53:24 -07:00
Kelsi
92830be032 feat(ui): overhaul quest tracker with progress, filter, and level sorting
Show every required objective with current/required counts (including
0-progress ones from quest query data), add a per-quest untrack button and
an All/Active/Done filter, sort entries lowest level first with the level
shown in the title, and normalize $b text tokens at all quest-log text
entry points so markers no longer leak into titles and objectives.
2026-07-14 01:48:28 -07:00
Kelsi
64ece68aa4 feat(auth): fall back to the other vanilla auth protocol on mismatch
Vanilla 1.12 servers disagree on the auth protocol byte — vmangos-derived
realms speak 8, stock mangos/cmangos speak 3 — and a profile can only name
one, so pointing the classic profile at the other kind hard-failed at login.
Classic/Turtle now retry once on the alternate byte when the failure looks
protocol-shaped (unparseable handshake, version rejection, drop during
challenge) and never when credentials were rejected, so a wrong password
can't trigger a second lockout-provoking attempt.

Also fixes the realm-list recovery heuristic from #100: it only fired when
the shifted parse left a non-empty address, so vanilla realms sending flags=0
(both name and address parse empty) silently produced garbage fields instead.
Keyed on the empty name alone, and covered by new realm-list parser tests.
2026-07-14 01:29:37 -07:00
Kelsi
200fa2d51b feat(ui): overhaul chat window for discoverability and quick switching
Tabs get tooltips, right-click mark-as-read, Ctrl+wheel cycling, and now sync
the input to their destination (Whispers/Guild/Trade). Adds a history search
filter, an inline quick-settings menu, a colored availability-aware chat type
picker, Tab-cycling of chat types on an empty input, contextual input hints,
and numbered channel picker; message context menus show time and channel.
2026-07-14 01:03:32 -07:00
Kelsi
9e3d13c9dd fix(ui): add Sort Bags to combined window and mark special container slots
Share the backpack footer (Sort Bags + money) with the All Bags window, flag
quivers/ammo pouches/profession bags via Inventory::isBagSpecial so sorting
skips them, and tint/label their slots so restricted space isn't mistaken for
general-purpose slots. Also name container/quiver subclasses in tooltips.
2026-07-13 17:08:47 -07:00