5320 Commits

Author SHA1 Message Date
Kelsi
c24f88265d fix(water): capture refraction before the UI is drawn
The refraction history was copied from the swapchain after ImGui had
rendered into it, so every panel, bag and nameplate on screen was part of
the image the water sampled and appeared smeared across the surface.

The copy cannot run inside a render pass, so close the scene pass after
post-processing, take the capture there, and reopen a render-pass-
compatible overlay pass that loads the swapchain instead of clearing it
for the UI. Compatibility means the ImGui pipelines are unaffected, and
the capture already restores PRESENT_SRC, which is exactly what the
overlay pass expects to load.

The overlay pass is not created under MSAA, where a second pass would
have to resolve again and could not preserve the resolved image; that
configuration keeps the old post-UI capture.
2026-07-31 06:48:27 -07:00
Kelsi
41c14d90d2 fix(audio): no landing grunt when leaving the water
isFalling() was !grounded && verticalVelocity <= 0, which holds for a
swimming character: not on the ground and not rising. Reaching the shore
therefore looked like a fall arriving at the ground, so SfxStateDriver
played a landing — with prevFalling set it took the hard-landing path and
the character grunted on every water exit.

Exclude swimming from isFalling(), and skip the landing entirely when the
previous frame was swimming: wading ashore is marked by the water-exit
splash that already plays, not by a landing thud.
2026-07-31 06:41:52 -07:00
Kelsi
2079b7ea4d fix(movement): add hysteresis to the swim/walk threshold
Both swim checks decided the state from a single 1.0 yard water depth, so
a character at the boundary flipped between swimming and walking from one
frame to the next. Each flip restarts the locomotion animation — the FSM
leaves SWIM for WALK the moment the flag clears, with no debounce — and
sends a START_SWIM/STOP_SWIM pair, which is the stutter seen walking out
of water.

Require 1.15 yards to start swimming and keep swimming until depth drops
below 0.85, so the boundary has a band rather than a point. The bounds
sit either side of the old threshold, leaving where swimming begins and
ends essentially unchanged.
2026-07-31 06:39:12 -07:00
Kelsi
be33fbe2cc fix(gameobjects): drive animation freezing from game object type
Freezing was decided by matching model paths against a list of portal
names, so every game object with a looping idle sat in its bind pose
unless someone had thought to name it — fishing pools were the reported
case, but braziers, banners and waterwheels were frozen the same way.

Freeze only the types whose pose is server state (door, button, chest,
trap, goober, destructible building, trapdoor) and let everything else
play its idle, which is what retail does. A game object's model spawns
from its display id before its type is known, so an object that spawns
with the query still in flight is frozen conservatively and revisited
when GAMEOBJECT_QUERY_RESPONSE arrives, via a new info callback.
2026-07-31 06:32:26 -07:00
Kelsi
6988f71961 fix(gameobjects): let fishing pools keep animating
Server game objects are frozen to their bind pose at spawn unless they
match the animated-effect allowlist, which covered portals, transports
and totems. A fishing pool's fish circle inside the model on a looping
idle, so freezing it left a school of motionless fish in the water.
Add fishschool to the allowlist — it matches all eleven pool variants
and nothing else in the tradeskill enabler set.
2026-07-31 06:27:09 -07:00
Kelsi
27be06fc56 fix(character): read bone indices as unsigned, fixing vertex explosions
CharVertexGPU stores bone indices as uint8_t, but all three character
pipelines declared the attribute VK_FORMAT_R8G8B8A8_SINT and both
character shaders read it as ivec4. Any index of 128 or above therefore
arrived sign-extended — bone 177 became -79 — and indexed outside the
bone storage buffer, so every vertex weighted to a high bone was
transformed by garbage and thrown across the world. Creatures with more
than 128 bones showed it as spikes radiating from the model;
waterelemental.m2 has 177.

Declare the attribute UINT and the shader inputs uvec4, and clamp to
MAX_BONES - 1. The buffer's unused slots are already identity-filled, so
a stray index now leaves its vertex at the bind pose rather than reading
past the allocation.
2026-07-31 06:23:22 -07:00
Kelsi
bd9ffafb96 feat(m2): add render diagnostics for isolating visual artifacts
WOWEE_M2_NO_PARTICLES, WOWEE_M2_NO_RIBBONS and WOWEE_M2_NO_SKINNING each
drop one subsystem's draws so an artifact can be attributed to the system
that produces it rather than guessed at from a screenshot. M2Renderer
logs which are active at init, which also identifies whether a running
build contains a given change.
2026-07-31 06:16:28 -07:00
Kelsi
209e534e7c fix(m2): stop truncating high bone counts, fixing vertex explosions
computeBoneMatrices capped every model at 128 bones and the mega bone
SSBO gave each instance a fixed 128-matrix slot, but the vertex shader
indexed bones[boneBase + boneIndex] unbounded. A model with more bones
than that — waterelemental.m2 has 177, and 14214 of the 48466 shipped
models exceed 128, topping out at 315 — had its upper bones read into the
neighbouring instance's matrices, throwing spikes across the world.

Pack per-instance bone ranges at each model's true bone count instead of
a fixed stride, raise the ceiling to 512, and clamp the shader's indices
to the range the instance owns. Packing more than pays for the taller
models: the median model has 3 bones and the mean 64, so the same 32 MB
budget now holds roughly 8200 average instances against the old 4096
fixed slots.
2026-07-31 05:45:24 -07:00
Kelsi
e324f2a7f5 fix(quests): allow abandoning quests that are marked complete
The quest log detail pane, the quest row context menu and the quest
tracker context menu all hid "Abandon Quest" behind !complete, so a
quest that finished its objectives but had not been turned in could not
be dropped. Retail gates only the reward hand-in on completion, not the
abandon, and CMSG_QUESTLOG_REMOVE_QUEST works for those slots either way
(the slot lookup reads the quest id field, which is independent of
completion state).
2026-07-31 05:39:04 -07:00
Kelsi
bb83939c6c fix(warrior): reject Charge on game objects and corpse targets
Mining nodes, herb nodes and chests can be the current target in this
client, but GameObject derives from Entity rather than Unit, so the
dynamic_pointer_cast that guarded every attackability check failed for
them and Charge ran straight through to the charge callback. Require a
UNIT or PLAYER target up front so non-unit targets get the standard
"You cannot attack that target." rejection instead.
2026-07-31 05:32:16 -07:00
Kelsi
60f59b3e4f chore(fsr3): bump FidelityFX-SDK to regenerated Vulkan permutations
Points the submodule at cdaf18c, which regenerates the Vulkan shader
permutations with FidelityFX-SC and adds R16G16B16A16_UNORM surface
format support used by the frame generation path.
2026-07-31 04:36:27 -07:00
Kelsi
9d6f7bfde9 fix: footprints rendered three times life size
CreatureModelData's FootprintTextureLength/Width are inches, but the loader
divided them by 12 -- inches to feet -- and used the result as world units,
which are yards. The decal quad is unit-sized and scaled directly by those
values, so a human's footprint drew a full yard long.

Convert by /36, and rescale the fallback profiles, which were authored
against the broken scale (BIPED 1.0 x 0.83 is exactly raw 12 x 10 over 12)
and would otherwise have stayed oversized for every creature without a DBC
profile.

Foot spacing is a body dimension rather than a print-size one, so the stance
coefficient absorbs the 3x and the trail stays as wide as before. The
degenerate-row guard now tests raw inches so the correction doesn't also
raise the cutoff and drop small creatures that resolve a profile today.
2026-07-24 18:59:58 -07:00
Kelsi
3139896401 docs: changelog entries for v2.0.30-preview and v2.0.31-preview
The open v2.0.29-preview section had been collecting entries as work
landed, but stopped at the terrain-seam fix; everything after it went
unrecorded. Adds the two missing sections: rendering (brightness multiply
over water, FSR3 16-bit storage, validation-layer env var), bank and guild
bank, crafting, quests, GM tools, and the two changes since.

Also narrows a comment in macos_platform.hpp -- W takes no diacritics.
v2.0.31-preview
2026-07-24 18:25:51 -07:00
Kelsi
af2c6bb280 fix: disable macOS press-and-hold accent popup during play
SDL2 leaves text input enabled for the whole session, so AppKit routes key
events through NSTextInputContext even in normal gameplay. Holding a key
with diacritics -- W, A, S, E -- opened the accent chooser over the game
instead of repeating the key.

Register ApplePressAndHoldEnabled=NO before SDL_Init brings up
NSApplication. The registration domain is process-scoped, so the user's
saved preferences are untouched; if a global setting explicitly enables
press-and-hold, fall back to this application's own domain, which outranks
NSGlobalDomain.

Needs an Objective-C++ shim, wired into both wowee and wowee_editor since
both compile window.cpp.
2026-07-24 18:10:58 -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
505173421e feat: opt-in Vulkan validation env var; FSR3 device features
Add WOWEE_VULKAN_VALIDATION=1 to enable the Khronos validation layer in a
release build, routing its messages to the log (used to diagnose the FSR3
frame-gen rc=3 as SDK-side invalid Vulkan shaders: 4KB push constants vs
256 limit, NV-only SPIR-V extensions, descriptor type/binding mismatches).
Keep the FSR2/FSR3 device-feature enables added while diagnosing
(shaderSubgroupExtendedTypes, 16-bit storage, shaderInt8) — gated on
support, correct regardless.
v2.0.30-preview
2026-07-24 05:50:46 -07:00
Kelsi
7569a07c11 fix: enable 16-bit storage so FSR3 SDK upscale context creates
'Path C upscale failed rc 3' = the AMD FFX ffxApi Vulkan backend returned
FFX_API_RETURN_ERROR_RUNTIME_ERROR creating the FSR3 upscale context (which
frame generation depends on). The device enabled shaderFloat16 (fp16 math)
but not the 16-bit *storage* features the FSR3 SDK shaders need to pack fp16
into buffers, so the backend's compute pipelines failed to build. Enable
storageBuffer16BitAccess + uniformAndStorageBuffer16BitAccess (and shaderInt8)
when supported. Gated on device support, so no effect where unavailable.
2026-07-24 05:07:11 -07:00
Kelsi
cc86d05884 fix: true multiply brightness, compensated in water refraction
Re-apply the multiplicative brightness overlay (scene*br, no white washout)
and stop it compounding through water refraction. Water refraction samples
a scene-history image captured from the final swapchain, which has the
display brightness baked in; re-applying brightness on the water each frame
fed back through that temporal capture and blew out (a multiply diverges
where the old white-lerp converged). Pass the brightness factor to the
water shader and divide it back out of the refraction sample, so refraction
sees the un-brightened scene and the display still gets a true multiply.
This also fixes the latent darkening feedback (water creeping to black).
No pass restructuring; localized to the overlay + water shader.
2026-07-24 04:55:54 -07:00
Kelsi
e65c3e8ddc Revert "fix: brightness scales luminance instead of washing to white"
This reverts commit dc817bead0.
2026-07-24 04:43:47 -07:00
Kelsi
dc817bead0 fix: brightness scales luminance instead of washing to white
Brightness > 1 was implemented as a white fullscreen overlay at alpha
(br-1), so the whole image lerped toward white — desaturating and washing
everything out (fully white at max). Add a multiplicative brightness
pipeline to OverlaySystem using a dst-color blend
(result = dst*src + dst, src = br-1) so the scene is multiplied by br —
true brightening that saturates highlights but keeps color, like a real
brightness/gamma control. Darkening already used a black overlay, which is
a correct scene*br multiply, so it's unchanged.
2026-07-24 04:38:48 -07:00
Kelsi
0fc2c5e68b fix: steam tonk/tank never classified as steam VFX
The 'steam' substring matches SteamTonk vehicle models. A prior fix gated
it on low-poly geometry (verts <= 200), but the TBC/Turtle SteamTonk
overlay models are tiny proxies that slip under that threshold, so with a
smoke emitter they were mis-classified as additive spell effects again
(glowing translucent). Exclude any 'tonk'/'tank' name outright — those are
vehicles, never steam VFX (real ones are steam/steamgeyser/lavasteam/etc.,
which never carry those tokens). Add a classifier regression test.
2026-07-24 04:28:02 -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
089ab1baa8 fix: cape texture read from both model-texture fields (in-world)
The in-world player model read the cloak texture only from
ItemDisplayInfo LeftModelTexture, but some cloaks (e.g. Jaina's
Radiance) store it only in the right field. The character-preview screen
already checks both, which is why the cloak was textured in the paperdoll
but blank in the world. Read left + right (gender-ordered) and try both,
matching the preview.
2026-07-24 04:03:34 -07:00
Kelsi
96134fd8a7 fix: .gm fly enables flight (drive flight physics from CAN_FLY)
.gm fly on sets only the CAN_FLY movement flag, but flight physics were
gated on isPlayerFlying() which also requires FLYING (only set once
already airborne) — a chicken-and-egg that left the player unable to take
off. Drive setFlyingActive() from a new canFly() (CAN_FLY set) instead,
and ungate the descend key (X) so it works on foot, not just on a flying
mount. Space ascends, X descends, gravity off while CAN_FLY is set.
2026-07-24 03:16:21 -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
0963cc79ca fix: bank deposit sees all bank bags; guild bank item transfer
- Deposit (right-click bag item at bank) now uses CMSG_AUTOBANK_ITEM so
  the server places it in any free bank slot including the purchased bank
  bags. The old path scanned only the main bank slots and reported 'Bank
  is full' once those filled, ignoring bank-bag space.
- Guild bank item transfer was silently dropped: CMSG_GUILD_BANK_SWAP_ITEMS
  was malformed (missing the toChar direction byte, splitedAmount written
  as a mid-packet u8 instead of a trailing u32, and the deposit variant
  set bankToBank=1 triggering the server's bank-to-bank path). Rewrite
  both builders to the correct 3.3.5a layout; withdraw uses the autoStore
  sub-format so the server auto-places into a free inventory slot.
2026-07-24 01:53:03 -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
84c579ce03 fix: crafting recipe list grows with window width
The left recipe-list pane had a fixed 260px width while the detail pane
absorbed all extra space, so enlarging the window never widened the list
and long recipe names stayed truncated. Size the list as a fraction of
available width (with a floor) so it grows with the window, and add a
hover tooltip with the full name for anything still wider than the pane.
2026-07-24 01:17:20 -07:00
Kelsi
3a5261775f feat: cast-while-mounted dismounts then casts (retail behavior)
Previously pressing any spell while mounted just dismounted without
casting. Match retail: dismount the (ground) mount and send the cast in
the same action. While airborne on a flying mount, block the cast with
'You can't do that while flying' instead of dropping the player out of
the sky. startCraftQueue guards the flying case too so the craft queue
isn't left populated with no cast in flight.
2026-07-24 01:00:12 -07:00
Kelsi
feb83fc77c fix: dismount before crafting so mounted craft no longer stalls
startCraftQueue populated the craft queue and then called castSpell,
which bails early when mounted (dismount-instead-of-cast) and returns
without sending the cast. The queue was left non-empty with nothing in
flight, freezing the crafting UI on 'Crafting... N remaining' until a
manual mount/dismount. Dismount synchronously before queueing so the
cast actually goes out, matching retail (craft while mounted dismounts
then crafts).
2026-07-24 00:56:30 -07:00
Kelsi
40e9066928 feat: auto-track newly accepted quests
Newly accepted quests are now added to the quest tracker automatically
(both normal questgiver accepts and shared-quest accepts). Login/resync
quest loads are untouched, so the tracker's show-all-when-none-tracked
fallback still applies to pre-existing quests.
2026-07-24 00:44:20 -07:00
Kelsi
07443e7535 fix: derive quest collect-item progress from bag contents
3.3.5a servers do not push collect-item objective counts (unlike kill
credit, which arrives in the quest-log update fields), so the tracker
relying solely on SMSG_QUESTUPDATE_ADD_ITEM never advanced when quest
items were looted. Reconcile item objectives against actual bag contents
on every inventory rebuild instead.
2026-07-24 00:40:47 -07:00
Kelsi
701bf71603 Revert "Improve item descriptions"
This reverts commit 9a2310f074.
2026-07-23 20:56:21 -07:00
Kelsi
9a2310f074 Improve item descriptions 2026-07-23 20:40:51 -07:00
Kelsi
94ee231b12 fix: align shared terrain tile edges
Derive terrain vertex XY from one tile-relative grid expression instead of independently subtracting chunk and vertex offsets. Adjacent tiles now calculate their common edge with identical float values, preventing hairline T-junction seams far from the map origin.
2026-07-23 20:17:19 -07:00
Kelsi
a8d7582f8a feat: gate and explain target-aura-state abilities (Execute et al.)
Load Spell.dbc TargetAuraState (added to every expansion layout at its
verified column) into the spell cache with getSpellTargetAuraState. The
action bar now dims abilities whose target isn't in the required aura state
(e.g. Execute below 20% health), with a tooltip naming the requirement, and
SMSG_CAST_FAILED result 111 (Target aurastate) now yields 'Target must be
below 20% health.' instead of the opaque protocol label.
2026-07-23 20:03:06 -07:00
Kelsi
47aa55602c feat: at-war and inactive controls in the reputation panel
Add setFactionAtWar / setFactionInactive senders (CMSG_SET_FACTION_ATWAR /
CMSG_SET_FACTION_INACTIVE) with local flag updates, plus isFactionInactive /
isFactionPeaceForced helpers and the FACTION_FLAG_INACTIVE constant. The
reputation panel's right-click menu now toggles war/peace (disabled when
peace is forced) and inactive state; inactive factions hide behind a 'Show
inactive' checkbox and dim when shown.
2026-07-23 19:55:14 -07:00
Kelsi
6cab5c73eb ci: retry MSYS2 package install on windows-arm64
The windows-arm64 build installed packages via the setup-msys2 action's
'install:' list, which has no retry, so an intermittent ARM mirror/keyring
hiccup failed the whole job at 'Set up MSYS2'. Move the install into a
separate 3-attempt pacman step, mirroring the release workflow.
2026-07-23 19:42:09 -07:00
Kelsi
8532419f4c fix: parse the sold item in auction owner notifications
SMSG_AUCTION_OWNER_NOTIFICATION was read as [auctionId, action, error,
itemEntry], but the WotLK packet is [auctionId, bid, unk, unk2, unk3,
item_template, item_count] with no action field. The item entry lives at
offset 20; the old offset 12 is a zero padding word, so every 'has sold!'
line said 'Item #0'. Read item_template from the right offset; expiry and
outbids already have their own opcodes, so this packet is always a sale.
2026-07-23 19:42:09 -07:00
Kelsi
69bcb10b04 fix: resolve $-tokens in readable item text (letters/notes)
The item-text window rendered the body raw, so quest letters showed literal
markup like '$g himself : herself;'. Route it through the shared
replaceGenderPlaceholders used by quest and chat text so gender, player name,
and line-break tokens fill in.
2026-07-23 19:34:19 -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
82a2dc1771 fix: exempt server game objects from HiZ occlusion culling
A mailbox/chest sits flush against walls where the coarse HiZ depth pyramid
reports false occlusions. The previouslyVisible hysteresis can't recover from
it: once occlusion-culled the prop isn't drawn, so it never regains last-frame
depth to clear the verdict, and it stays invisible in place until the camera
moves. Game object instances now never set the previouslyVisible flag, so the
cull shader skips the occlusion test for them; frustum and distance culling
still bound them.
2026-07-23 18:56:47 -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
7a4052c428 feat: announce new mail with a chat line and sound cue
Route the unread-mail flag through a rising-edge helper that prints
'You have new mail.' and plays a notification sound once when mail arrives
(or is found waiting at login), alongside the existing minimap indicator.
2026-07-23 18:12:55 -07:00