Commit graph

1070 commits

Author SHA1 Message Date
Kelsi
2e879fe354 fix: sync item cooldowns to action bar slots on login
The cooldown sync after SMSG_ACTION_BUTTONS and SMSG_INITIAL_SPELLS
only handled SPELL-type action bar slots. ITEM-type slots (potions,
trinkets, engineering items) were skipped, so items on the action bar
showed no cooldown overlay after login even if their on-use spell was
on cooldown. Now looks up each item's on-use spell IDs from the item
info cache and syncs any matching spellCooldowns entries.
2026-03-20 08:01:54 -07:00
Kelsi
5172c07e15 fix: include category cooldowns in initial spell cooldown tracking
SMSG_INITIAL_SPELLS cooldown entries have both cooldownMs (individual)
and categoryCooldownMs (shared, e.g. potions). The handler only checked
cooldownMs, so spells with category-only cooldowns (cooldownMs=0,
categoryCooldownMs=120000) were not tracked. Now uses the maximum of
both values, ensuring potion and similar shared cooldowns show on the
action bar after login.
2026-03-20 07:02:57 -07:00
Kelsi
533831e18d fix: sync pending spell cooldowns to action bar after login
SMSG_SPELL_COOLDOWN arrives before SMSG_ACTION_BUTTONS during login,
so cooldown times were stored in spellCooldowns but never applied to
the newly populated action bar slots. Players would see all abilities
as ready immediately after login even if spells were on cooldown.
Now applies pending cooldowns from the spellCooldowns map to each
matching slot when the action bar is first populated.
2026-03-20 06:59:23 -07:00
Kelsi
bc2085b0fc fix: increase compressed UPDATE_OBJECT decompressed size limit to 5MB
Capital cities and large raids can produce UPDATE_OBJECT packets that
decompress to more than 1MB. The real WoW client handles up to ~10MB.
Bump the limit from 1MB to 5MB to avoid silently dropping entity
updates in densely populated areas like Dalaran or 40-man raids.
2026-03-20 05:59:11 -07:00
Kelsi
595ea466c2 fix: update local equipment set GUID on save confirmation and auto-request played time on login
SMSG_EQUIPMENT_SET_SAVED now updates the local set's GUID from the
server response, preventing duplicate set creation when clicking
"Update" on a newly-saved set. New sets are also added to the local
list immediately so the UI reflects them without a relog.

Additionally, CMSG_PLAYED_TIME is now auto-sent on initial world entry
(with sendToChat=false) so the character Stats tab shows total and
level time immediately without requiring /played.
2026-03-20 05:17:27 -07:00
Kelsi
e68a1fa2ec fix: guard equipment set packets against unsupported expansions
Classic and TBC lack equipment set opcodes, so sending save/use/delete
packets would transmit wire opcode 0xFFFF and potentially disconnect the
client. Now all three methods check wireOpcode != 0xFFFF before sending,
and the Outfits tab is only shown when the expansion supports equipment
sets (via supportsEquipmentSets() check).
2026-03-20 05:12:24 -07:00
Kelsi
9600dd40e3 fix: correct CMSG_EQUIPMENT_SET_USE packet format
The packet previously sent only a uint32 setId, which does not match
the WotLK protocol. AzerothCore/TrinityCore expect 19 iterations of
(PackedGuid itemGuid + uint8 srcBag + uint8 srcSlot). Now looks up the
equipment set's target item GUIDs and searches equipment, backpack, and
extra bags to provide correct source locations for each item.
2026-03-20 05:01:21 -07:00
Kelsi
1ae4cfaf3f fix: auto-acknowledge cinematic and movie triggers to prevent server hangs
Send CMSG_NEXT_CINEMATIC_CAMERA in response to SMSG_TRIGGER_CINEMATIC
and CMSG_COMPLETE_MOVIE in response to SMSG_TRIGGER_MOVIE. Some WotLK
servers block further packets or disconnect clients that don't respond
to these triggers, especially during the intro cinematic on first login.
2026-03-20 04:53:54 -07:00
Kelsi
f4d705738b fix: send CMSG_SET_WATCHED_FACTION when tracking a reputation
setWatchedFactionId() previously only stored the faction locally.
Now it also sends CMSG_SET_WATCHED_FACTION with the correct repListId
to the server, so the tracked faction persists across sessions.
2026-03-20 04:50:49 -07:00
Kelsi
ae56f2eb80 feat: implement equipment set save, update, and delete
Add saveEquipmentSet() and deleteEquipmentSet() methods that send
CMSG_EQUIPMENT_SET_SAVE and CMSG_DELETEEQUIPMENT_SET packets. The save
packet captures all 19 equipment slot GUIDs via packed GUID encoding.
The Outfits tab now always shows (not just when sets exist), with an
input field to create new sets and Update/Delete buttons per set.
2026-03-20 04:43:46 -07:00
Kelsi
f88d90ee88 feat: track and display honor/arena points from update fields
Add PLAYER_FIELD_HONOR_CURRENCY and PLAYER_FIELD_ARENA_CURRENCY to the
update field system for WotLK (indices 1422/1423) and TBC (1505/1506).
Parse values from both CREATE_OBJECT and VALUES update paths, and show
them in the character Stats tab under a PvP Currency section.
2026-03-20 04:36:30 -07:00
Kelsi
86cc6e16a4 fix: correct PET_CAST_FAILED expansion format and parse LFG role choices
SMSG_PET_CAST_FAILED: Classic/TBC omit the castCount byte (matching
SMSG_CAST_FAILED pattern). Without this fix, TBC parsing reads garbage.
SMSG_LFG_ROLE_CHOSEN: surface role selection messages in chat during
dungeon finder role checks.
2026-03-18 12:40:20 -07:00
Kelsi
d149255c58 feat: implement petition signing flow for guild charter creation
Parse SMSG_PETITION_QUERY_RESPONSE, SMSG_PETITION_SHOW_SIGNATURES,
and SMSG_PETITION_SIGN_RESULTS. Add UI to view signatures, sign
petitions, and turn in completed charters. Send CMSG_PETITION_SIGN
and CMSG_TURN_IN_PETITION packets.
2026-03-18 12:31:48 -07:00
Kelsi
41e15349c5 feat: improve arena team UI with names, types, and roster requests
Store team name and type (2v2/3v3/5v5) from SMSG_ARENA_TEAM_QUERY_RESPONSE.
Display proper team labels instead of raw IDs. Add Load/Refresh roster
buttons and CMSG_ARENA_TEAM_ROSTER request support.
2026-03-18 12:26:23 -07:00
Kelsi
aed8c94544 feat: add instance difficulty indicator on minimap
Show Normal/Heroic/25-Man difficulty badge below zone name when inside
a dungeon or raid instance. Orange-highlighted for heroic modes.
2026-03-18 12:21:41 -07:00
Kelsi
801f29f043 fix: sync player appearance after barber shop or polymorph
PLAYER_BYTES and PLAYER_BYTES_2 changes in SMSG_UPDATE_OBJECT now
update the Character struct's appearanceBytes and facialFeatures,
and fire an appearance-changed callback that resets the inventory
screen preview so it reloads with the new hair/face values.
2026-03-18 12:17:00 -07:00
Kelsi
2e134b686d fix: correct BattlemasterList.dbc IDs for arenas and Isle of Conquest
Arena and BG type IDs now match actual 3.3.5a BattlemasterList.dbc:
Nagrand Arena=4, Blade's Edge=5, Ruins of Lordaeron=8, Dalaran
Sewers=10, Ring of Valor=11, Isle of Conquest=30, Random BG=32.
2026-03-18 12:04:38 -07:00
Kelsi
5d5083683f fix: correct Eye of the Storm bgTypeId and simplify BG invite popup
Eye of the Storm uses bgTypeId 7 (from BattlemasterList.dbc), not 6.
BG invite popup now uses the stored bgName from the queue slot instead
of re-deriving the name with a duplicate switch statement.
2026-03-18 12:03:36 -07:00
Kelsi
64fd7eddf8 feat: implement barber shop UI with hair/facial customization
Adds a functional barber shop window triggered by SMSG_ENABLE_BARBER_SHOP.
Players can adjust hair style, hair color, and facial features using
sliders bounded by race/gender max values. Sends CMSG_ALTER_APPEARANCE
on confirm; server result closes the window on success. Escape key
also closes the barber shop.
2026-03-18 11:58:01 -07:00
Kelsi
9b32a328c3 feat: add item stack splitting via Shift+right-click
Implements CMSG_SPLIT_ITEM (0x10E) with a slider popup for choosing
split count. Auto-finds empty destination slot across backpack and bags.
Shift+right-click on stackable items (count > 1) opens split dialog;
non-stackable items still get the destroy confirmation.
2026-03-18 11:07:27 -07:00
Kelsi
7f2ee8aa7e fix: add error sound on cast failure and AFK/DND whisper auto-reply
Play UI error sound on SMSG_CAST_FAILED for consistent audio feedback,
matching other error handlers (vendor, inventory, trainer).
Auto-reply to incoming whispers with AFK/DND message when player has
set /afk or /dnd status.
2026-03-18 10:50:42 -07:00
Kelsi
209f60031e feat: respect loot roll voteMask for button visibility
Store the voteMask from SMSG_LOOT_START_ROLL and use it to conditionally
show Need/Greed/Disenchant/Pass buttons. Previously all four buttons were
always shown regardless of the server's allowed roll types.
2026-03-18 10:01:53 -07:00
Kelsi
02a1b5cbf3 fix: show reflected spell name in combat text
SMSG_SPELL_MISS_LOG REFLECT entries include a reflectSpellId field that
was parsed but discarded. Now store it in SpellMissLogEntry and pass it
to addCombatText, so floating combat text shows the actual reflected
spell name instead of the original cast spell.
2026-03-18 09:59:54 -07:00
Kelsi
63b4394e3e feat: world-space floating combat text above entities
Combat text (damage, heals, misses, crits, etc.) now floats above the
target entity in 3D space instead of appearing at fixed screen positions.
Text rises upward from the entity's head, with random horizontal stagger
to prevent stacking. HUD-only types (XP, Honor, Procs) and entries
without a valid entity anchor fall back to the original screen overlay.
2026-03-18 09:54:52 -07:00
Kelsi
e572cdfb4a feat: show guild names on player nameplates
Read PLAYER_GUILDID from entity update fields (UNIT_END + 3) and query
guild names via CMSG_GUILD_QUERY. Cache results in guildNameCache_ so
each guild ID is queried only once. Display <Guild Name> in grey below
the player name on nameplates. Fix handleGuildQueryResponse to not
overwrite the local player's guild data when querying other guilds.
2026-03-18 09:44:43 -07:00
Kelsi
003ad8b20c fix: read WotLK periodic damage isCrit byte in SMSG_PERIODICAURALOG
The WotLK periodic damage format includes an isCrit byte after resisted
(21 bytes total, not 20). Missing this byte caused parse misalignment
for multi-effect periodicauralog packets. Also use the already-read
isCrit on periodic heals to display critical HoT ticks distinctly.
2026-03-18 09:17:00 -07:00
Kelsi
100d66d18b fix: play death/attack animations for online players, not just NPCs
Death, respawn, and melee swing callbacks only checked
creatureInstances_, so online players never played death animation when
killed, never returned to idle on resurrect, and never showed attack
swings. Extended all three callbacks to also check playerInstances_.

Also extended the game_handler death/respawn callback triggers to fire
for PLAYER entities (not just UNIT), and added spawn-time death
detection for players that are already dead when first seen.
2026-03-18 08:43:19 -07:00
Kelsi
e54ed1d46f fix: pass correct offset to setPlayerOnTransport on transport boarding
Both CREATE_OBJECT and MOVEMENT update paths called
setPlayerOnTransport(guid, vec3(0)) then immediately overwrote
playerTransportOffset_ on the next line. This left a one-frame window
where the composed world position used (0,0,0) as the local offset,
causing the player to visually snap to the transport origin. Compute the
canonical offset first and pass it directly.
2026-03-18 08:39:35 -07:00
Kelsi
0b33bcbe53 fix: reject oversized MonsterMove spline and fix loot format comment
Change WotLK MonsterMove pointCount > 1000 from cap-to-1000 to return
false. Capping caused the parser to read only 1000 of N points, leaving
the remaining point data unread and misaligning subsequent reads.

Also correct misleading loot response comment: Classic/TBC DO include
randomSuffix and randomPropertyId (22 bytes/item, same as WotLK). The
only WotLK difference is the quest item list appended after regular
items.
2026-03-18 08:18:21 -07:00
Kelsi
c8922e4826 fix: stop player movement before game object interaction
Servers may reject CMSG_GAMEOBJ_USE or cancel the resulting pickup
spell cast if movement flags are still active. Now sends MSG_MOVE_STOP
to clear directional movement before the interaction packet. Also adds
diagnostic logging for GO interactions to help trace collection issues.
2026-03-18 06:49:43 -07:00
Kelsi
25138b5648 fix: use CMSG_OPEN_ITEM for locked containers (lockboxes)
Right-clicking a locked container (e.g. Dead-Tooth's Strong Box) was
sending CMSG_USE_ITEM with spellId=0, which the server rejects. Locked
containers (itemClass==1, inventoryType==0) now send CMSG_OPEN_ITEM
instead, letting the server auto-check the keyring for the required key.
2026-03-18 06:06:29 -07:00
Kelsi
90843ea989 fix: don't set releasedSpirit_ optimistically in releaseSpirit()
Setting releasedSpirit_=true immediately on CMSG_REPOP_REQUEST raced
with PLAYER_FLAGS field updates that arrive from the server before it
processes the repop: the PLAYER_FLAGS handler saw wasGhost=true /
nowGhost=false and fired the 'ghost cleared' path, wiping corpseMapId_
and corpseGuid_ — so the minimap skull marker and the Resurrect from
Corpse dialog never appeared.

Ghost state is now driven entirely by the server-confirmed PLAYER_FLAGS
GHOST bit (and the login-as-ghost path), eliminating the race.
2026-03-18 05:35:23 -07:00
Kelsi
e7fe35c1f9 feat: add right-click pet spell autocast toggle via CMSG_PET_SPELL_AUTOCAST
Right-clicking a castable pet ability (actionId > 6) in the pet action
bar now sends CMSG_PET_SPELL_AUTOCAST to toggle the spell's autocast
state. The local petAutocastSpells_ set is updated optimistically and
the tooltip shows the current state with a right-click hint.
2026-03-18 05:08:10 -07:00
Kelsi
277a26b351 feat: flash action bar button red when spell cast fails
Add SpellCastFailedCallback to GameHandler, fired from SMSG_CAST_RESULT
when result != 0. GameScreen registers the callback and records each failed
spellId in actionFlashEndTimes_ (keyed by spell ID, value = expiry time).

During action bar rendering, if a slot's spell has an active flash entry,
an AddRectFilled overlay is drawn over the button with alpha proportional
to remaining time (1.0→0.0 over 0.5 s), giving the same error-red flash
visual feedback as the original WoW client.
2026-03-18 04:30:33 -07:00
Kelsi
c1765b6b39 fix: defer loot item notification until item name is known from server query
When SMSG_ITEM_PUSH_RESULT arrives for an item not yet in the cache, store
a PendingItemPushNotif and fire the 'Received: [item]' chat message only
after SMSG_ITEM_QUERY_SINGLE_RESPONSE resolves the name and quality, so the
notification always shows a proper item link instead of 'item #12345'.

Notifications that are already cached emit immediately as before; multiple
pending notifs for the same item are all flushed on the single response.
2026-03-18 04:25:37 -07:00
Kelsi
09b0bea981 feat: add /stopmacro support and low durability warning for equipped items
- /stopmacro [conditions] halts remaining macro commands; supports all existing
  macro conditionals ([combat], [nocombat], [mod:shift], etc.) via the sentinel
  action trick on evaluateMacroConditionals
- macroStopped_ flag in GameScreen; executeMacroText resets and checks it after
  each command so /stopmacro mid-macro skips all subsequent lines
- Emit a "X is about to break!" UI error + system chat when an equipped item's
  durability drops below 20% via SMSG_UPDATE_OBJECT field delta; warning fires
  once per threshold crossing (prevDur >= maxDur/5, newDur < maxDur/5)
2026-03-18 04:14:44 -07:00
Kelsi
d7c377292e feat: show socket gems and consolidate enchant name DBC cache in item tooltips
Extends OnlineItemInfo to track gem enchant IDs (socket slots 2-4) from item
update fields; socket display now shows inserted gem name inline (e.g.
"Red Socket: Bold Scarlet Ruby"). Consolidates redundant SpellItemEnchantment
DBC loads into one shared static per tooltip variant.
2026-03-18 04:04:23 -07:00
Kelsi
1fd3d5fdc8 feat: display permanent and temporary enchants in item tooltips for equipped items
Tracks ITEM_ENCHANTMENT_SLOT 0 (permanent) and 1 (temporary) from item update
fields in OnlineItemInfo, then looks up names from SpellItemEnchantment.dbc and
renders them in both ItemDef and ItemQueryResponseData tooltip variants.
2026-03-18 03:50:24 -07:00
Kelsi
ed3bca3d17 fix: escape newlines in macro cfg persistence; execute all macro lines
- Macro text is now escaped (\\n, \\\\) on save and unescaped on load,
  fixing multiline macros silently truncating after the first line in
  the character config file.
- executeMacroText() runs every non-comment line of a macro body in
  sequence (WoW behaviour), replacing the firstMacroCommand() approach
  that only fired the first actionable line. The server still enforces
  one spell-cast per click; non-cast commands (target, equip, pet, etc.)
  now all execute correctly in the same macro activation.
2026-03-18 02:44:28 -07:00
Kelsi
2c86fb4fa6 feat: implement client-side macro text storage and execution
Macros in WoW are client-side — the server sends only a macro index via
SMSG_ACTION_BUTTONS, never the text. This commit adds local storage and
a UI so macro slots are actually usable.

- GameHandler: getMacroText/setMacroText accessors backed by macros_ map;
  text is persisted to the character .cfg file as macro_N_text= entries
- Action bar left-click: MACRO slot executes first line of macro text as
  a chat/slash command (same path as /cast, /use, etc.)
- Context menu: "Execute" and "Edit" items for MACRO slots; "Edit" opens
  a multiline modal editor (320×80 px, up to 255 chars) with Save/Cancel
- Tooltip: shows macro text body below the index; hints "right-click to
  Edit" when no text is set yet
2026-03-18 02:07:59 -07:00
Kelsi
1588c1029a fix: add user feedback for ATTACKSWING_NOTSTANDING and CANT_ATTACK
Both handlers silently cleared state with no visible message, leaving the
player unsure why their attack failed.  Split the shared case block:

- NOTSTANDING: show "You need to stand up to fight." (rate-limited to 1.25s
  via the existing autoAttackRangeWarnCooldown_ guard), keep auto-attack
  active so it fires once the player stands.

- CANT_ATTACK: call stopAutoAttack() to end the attack loop (target is a
  critter, civilian, or already dead — no point retrying), then show "You
  can't attack that." with the same rate limiter.
2026-03-18 01:46:19 -07:00
Kelsi
7a0c7241ba fix: parse macro action bar slots from SMSG_ACTION_BUTTONS
Macro slots (type 0x40 / 64) were silently dropped by the default branch
of the SMSG_ACTION_BUTTONS type switch, leaving the bar empty for any slot
a player had set to a macro.  ActionBarSlot::MACRO already existed and the
UI already rendered it; only the parser was missing the case.  Add
case 0x40 to map to ActionBarSlot::MACRO for Classic (type=64), TBC, and
WotLK formats, which all share the same 0x40 encoding for macros.
2026-03-18 01:35:39 -07:00
Kelsi
5801af41bc fix: correct Turtle WoW SMSG_INIT_WORLD_STATES format and remove dead minRepeatMs branch
Turtle WoW is Classic 1.12-based and uses the Classic packet format for
SMSG_INIT_WORLD_STATES (no areaId uint32 field before count), not WotLK
format.  Including it in the WotLK branch caused the parser to consume 4
bytes of the count+first-key as a phantom areaId, misaligning all world
state key/value pairs (BG scores, zone events, flag states).

Also remove the dead `turtleMode ? 150 : 150` branch in
performGameObjectInteractionNow — both arms were identical so the ternary
had no effect; replace with a constexpr constant.
2026-03-18 01:30:20 -07:00
Kelsi
57b44d2347 fix: clear craft queue on spell failure and all cast reset paths
craftQueueSpellId_ and craftQueueRemaining_ were already cleared in
cancelCast(), stopCasting(), and SMSG_CAST_RESULT failure, but were
missing from five other cast-abort paths:

- SMSG_SPELL_FAILURE (mid-cast interrupt): queue persisted after
  combat interruption, risking a ghost re-cast on the next SMSG_SPELL_GO
- handleCastFailed() (SMSG_CAST_FAILED): queue persisted if the server
  rejected a craft before it started
- Player login state reset: leftover queue from prior session survived
  into the new world session
- Same-map resurrection (SMSG_NEW_WORLD): queue persisted through
  spirit-healer resurrection teleport
- Regular world transfer (SMSG_NEW_WORLD): queue persisted across zone
  changes and dungeon portals
2026-03-18 01:15:04 -07:00
Kelsi
6be695078b fix: clear spell queue in stopCasting; fix SMSG_SPELL_DELAYED castTimeTotal; clear cast on same-map res
- stopCasting() (invoked by /stopcasting) now clears queuedSpellId_/
  queuedSpellTarget_ and craftQueueSpellId_/craftQueueRemaining_ so a
  queued spell cannot fire silently after the player explicitly cancels.
- SMSG_SPELL_DELAYED now extends castTimeTotal alongside castTimeRemaining
  for the local player, matching the existing other-unit handling and
  keeping the cast bar progress percentage accurate after server-imposed
  cast delays.
- Same-map resurrection path (SMSG_NEW_WORLD same-map) now resets casting,
  castIsChannel, currentCastSpellId, castTimeRemaining, and the spell queue
  as a defensive measure (player is dead and cannot be casting, but this
  ensures state is clean on respawn).
2026-03-18 00:59:15 -07:00
Kelsi
60d5edf97f fix: cancel timed cast immediately on movement start
When the player starts moving (forward/backward/strafe/jump) while a
timed non-channeled cast is in progress, call cancelCast() before
sending the movement packet.  Previously the cast bar kept counting
down until the server sent SMSG_SPELL_FAILED, causing a visible lag.

Channeled spells are excluded (server ends those via MSG_CHANNEL_UPDATE).
Turning opcodes are excluded (turning while casting is allowed in WoW).
2026-03-18 00:25:04 -07:00
Kelsi
4907f4124b feat: implement spell queue window (400ms pre-cast)
When castSpell() is called while a timed cast is in progress and
castTimeRemaining <= 0.4s, store the spell in queuedSpellId_ instead
of silently dropping it.  handleSpellGo() fires the queued spell
immediately after clearing the cast state, matching the ~400ms spell
queue window in Blizzlike WoW clients.

Queue is cleared on all cancel/interrupt paths: cancelCast(),
handleCastFailed(), SMSG_CAST_RESULT failure, SMSG_SPELL_FAILED,
world-teardown, and worldport ACK.  Channeled casts never queue
(cancelling a channel should remain explicit).
2026-03-18 00:21:46 -07:00
Kelsi
0f8852d290 fix: clear selfResAvailable_ when player releases spirit 2026-03-18 00:09:22 -07:00
Kelsi
5a5c2dcda3 feat: implement self-resurrection (Reincarnation/Twisting Nether)
SMSG_PRE_RESURRECT was silently discarded; Shamans with Reincarnation
and Warlocks with Twisting Nether could never see or use the self-res
ability. Now:

- SMSG_PRE_RESURRECT sets selfResAvailable_ flag when addressed to the
  local player
- Death dialog gains a "Use Self-Resurrection" button (blue, shown above
  Release Spirit) when the flag is set
- Clicking it sends CMSG_SELF_RES (empty body) and clears the flag
- selfResAvailable_ is cleared on all resurrection and session-reset
  paths so it never bleeds across deaths or logins
2026-03-18 00:06:39 -07:00
Kelsi
395a8f77c4 fix: clear corpse reclaim delay on world reset and resurrection
Reset corpseReclaimAvailableMs_ to 0 in both world-teardown/re-login
and ghost-flag-cleared paths so the PvP delay countdown never bleeds
into subsequent deaths or sessions.
2026-03-17 23:57:47 -07:00