Commit graph

721 commits

Author SHA1 Message Date
Kelsi
528b796dff game: fix Classic 1.12 SMSG_AUCTION_LIST_RESULT enchant slot count
Classic 1.12 auction entries contain only 1 enchant slot (3 uint32s),
while TBC and WotLK expanded this to 3 enchant slots (9 uint32s). Parsing
Classic auction results with the WotLK parser consumed 24 extra bytes per
entry (two extra enchant slots), corrupting randomPropertyId, stackCount,
ownerGuid, pricing and expiry data for every auction item.

- AuctionListResultParser::parse() gains a numEnchantSlots parameter (default 3)
- Classic path reads 1 enchant slot; TBC/WotLK read 3
- handleAuctionListResult/OwnerList/BidderList pass isClassicLikeExpansion()?1:3
2026-03-10 01:25:27 -07:00
Kelsi
8dd4bc80ec game: fix Classic 1.12 SMSG_TRAINER_LIST per-spell field layout
Classic 1.12 trainer list entries lack the profDialog and profButton
uint32 fields (8 bytes) that TBC/WotLK added before reqLevel. Instead,
reqLevel immediately follows spellCost, and a trailing unk uint32 appears
at the end of each entry. Parsing the WotLK format for Classic caused
misalignment from the third field onward, corrupting state, cost, level,
skill, and chain data for all trainer spells.

- TrainerListParser::parse() gains a isClassic bool parameter (default false)
- Classic path: cost(4) → reqLevel(1) → reqSkill... → chainNode3 → unk(4)
- WotLK/TBC path: cost(4) → profDialog(4) → profButton(4) → reqLevel(1) → reqSkill...
- handleTrainerList() passes isClassicLikeExpansion() as the flag
2026-03-10 01:20:41 -07:00
Kelsi
23878e530f game: implement Classic SMSG_FRIEND_LIST and full SMSG_CONTACT_LIST parsing
Classic 1.12 and TBC use SMSG_FRIEND_LIST (not SMSG_CONTACT_LIST) to send
the initial friend list at login. Previously this packet was silently dropped,
leaving friendsCache empty and breaking /friend remove and note operations
for Classic players.

- Add handleFriendList(): parses Classic format (u8 count, then per-entry:
  u64 guid + u8 status + optional area/level/class if online)
- Add handleContactList(): fully parses WotLK SMSG_CONTACT_LIST entries
  (previously only read mask+count header and dropped all entries)
- Both handlers populate friendGuids_ and call queryPlayerName() for unknown
  GUIDs; handleNameQueryResponse() now backfills friendsCache when a name
  resolves for a known friend GUID
- Clear friendGuids_ on disconnect alongside playerNameCache
2026-03-10 01:15:51 -07:00
Kelsi
ab0828a4ce game: fix Classic 1.12 SMSG_WHO missing gender byte alignment
Vanilla 1.12 SMSG_WHO per-player format:
  name(CString) + guild(CString) + level(u32) + class(u32) + race(u32) + zone(u32)

WotLK 3.3.5a added a gender(u8) byte between race and zone. The previous
handleWho always read the gender byte, causing a one-byte misalignment for
Classic/TBC: the first byte of zoneId was consumed as gender, then zoneId
read from the next 4 bytes (spanning into the next player entry).

Now only reads the gender byte for WotLK (isActiveExpansion("wotlk")), and
adds bounds checks to prevent out-of-bounds reads on truncated packets.
2026-03-10 01:08:13 -07:00
Kelsi
c19edd407a game: fix Classic/TBC SMSG_TEXT_EMOTE field order
Classic 1.12 and TBC 2.4.3 send SMSG_TEXT_EMOTE with the field order:
  textEmoteId(u32) + emoteNum(u32) + senderGuid(u64) + nameLen(u32) + name

WotLK 3.3.5a swapped senderGuid to the front:
  senderGuid(u64) + textEmoteId(u32) + emoteNum(u32) + nameLen(u32) + name

The previous TextEmoteParser always used the WotLK order, causing senderGuid
to be read as a mashup of textEmoteId+emoteNum for Classic/TBC. Emote
animations and chat entries were associated with wrong GUIDs.

TextEmoteParser::parse now takes a legacyFormat parameter; handleTextEmote
passes it based on expansion detection.
2026-03-10 01:05:23 -07:00
Kelsi
a0979b9cd8 game: fix Classic/TBC SMSG_GROUP_LIST parsing - missing roles byte
WotLK 3.3.5a added a group-level and per-member roles byte (tank/healer/dps)
for the Dungeon Finder system. Classic 1.12 and TBC 2.4.3 do not send this byte.

The previous GroupListParser always read the roles byte, causing a one-byte
misalignment in Classic/TBC group lists that corrupted member GUID reads and
all subsequent fields (loot method, leader GUID, etc.).

GroupListParser::parse now takes a hasRoles parameter (default true for
backward compatibility). handleGroupList passes hasRoles=isActiveExpansion("wotlk").
Also adds range-checking throughout to prevent out-of-bounds reads on
malformed or unexpectedly short group list packets.
2026-03-10 00:58:56 -07:00
Kelsi
d3ec230cec game: fix Classic 1.12 packed GUID for SMSG_PARTY_MEMBER_STATS
Classic/Vanilla uses ObjectGuid::WriteAsPacked() for party member stats
packets (same packed format as WotLK), not full uint64 as TBC does.
Reading 8 fixed bytes for the GUID over-read the packed GUID field,
misaligning updateFlags and all subsequent stat fields, breaking party
frame HP/mana display in Classic.
2026-03-10 00:42:52 -07:00
Kelsi
8014f2650c game: fix Classic 1.12 GUID format for health/power/aura/energize packets
Classic 1.12 sends packed GUIDs (byte mask + non-zero bytes) for these
server packets, not full uint64 as TBC does. The previous fixes incorrectly
grouped Classic with TBC, causing the GUID readers to over-read 8 bytes
from what were 2-4 byte packed GUIDs, corrupting health values and spell
IDs parsed from subsequent bytes.

Verified from vmangos/cmangos-classic source code:
  SMSG_HEALTH_UPDATE:     data << GetPackGUID()
  SMSG_POWER_UPDATE:      data << GetPackGUID()
  SMSG_UPDATE_COMBO_POINTS: data << combotarget->GetPackGUID()
  SMSG_PERIODICAURALOG:   data << victim->GetPackGUID() + caster->GetPackGUID()
  SMSG_SPELLENERGIZELOG:  data << victim->GetPackGUID() + caster->GetPackGUID()

TBC continues to use full uint64 for these packets. WotLK and Classic
both use packed GUIDs. The branching now correctly distinguishes TBC
from the rest.
2026-03-10 00:38:47 -07:00
Kelsi
c011d724c6 game: implement SMSG_RESISTLOG combat text (resist/miss display for all expansions) 2026-03-10 00:16:13 -07:00
Kelsi
5d2bc9503d game: fix expansion-gated GUID for FORCE_MOVE_ROOT/UNROOT 2026-03-10 00:06:11 -07:00
Kelsi
9cf331fdab game: fix expansion-gated GUIDs for RESUME_CAST_BAR, TALENTS_INFO, and TELEPORT_ACK 2026-03-10 00:00:21 -07:00
Kelsi
3d2bade521 game: fix expansion-gated GUIDs for movement handlers (FORCE_SPEED, FORCE_FLAG, KNOCK_BACK, other-player relayed moves) 2026-03-09 23:58:15 -07:00
Kelsi
deea701222 game: fix expansion-gated GUIDs for PARTY_MEMBER_STATS and MINIMAP_PING 2026-03-09 23:53:43 -07:00
Kelsi
e122d725f6 game: fix expansion-gated GUIDs for HEALTH_UPDATE, POWER_UPDATE, COMBO_POINTS 2026-03-09 23:51:01 -07:00
Kelsi
abf9ef0b5f game: fix expansion-gated GUIDs for PERIODICAURALOG, SPELLENERGIZELOG, SPELL_DELAYED; separate FEATURE_SYSTEM_STATUS/SPELL_MODIFIER from SPELL_DELAYED case 2026-03-09 23:48:06 -07:00
Kelsi
e11d0956fb game: fix TBC/Classic GUID format for SPELLLOGMISS, IMMUNE, and SPELLDISPELLOG 2026-03-09 23:45:10 -07:00
Kelsi
011b1c8295 game: fix SMSG_SPELL_DELAYED to also extend non-player cast bars
Previously SMSG_SPELL_DELAYED only adjusted the local player's cast bar.
Now it also extends unitCastStates_ for any non-player caster (e.g.
boss cast bar extends correctly when hit by a tank during cast).
2026-03-09 23:39:22 -07:00
Kelsi
f31fa29616 game/ui: add channeled spell cast tracking and party cast bars
- 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
2026-03-09 23:36:14 -07:00
Kelsi
d72912714b game: fix SMSG_SPELL_FAILURE GUID format for TBC/Classic vs WotLK
WotLK uses packed GUIDs in SMSG_SPELL_FAILURE / SMSG_SPELL_FAILED_OTHER.
TBC 2.4.3 and Classic 1.12 use full uint64 GUIDs. The previous fix used
UpdateObjectParser::readPackedGuid for all expansions, which would
mis-parse the caster GUID on TBC/Classic servers, leaving stale cast
bars and potentially corrupting subsequent packet reads.

Now checks isClassicLikeExpansion() || isActiveExpansion("tbc") and
reads a raw uint64 for those expansions, matching the TBC/Classic wire
format used in parseSpellStart/parseSpellGo overrides.
2026-03-09 23:20:15 -07:00
Kelsi
640eaacb8c game: clear unit cast bars on SMSG_SPELL_FAILURE and SMSG_SPELL_FAILED_OTHER
When a spell fails or is interrupted, the server sends SMSG_SPELL_FAILURE
(for the caster's own POV) or SMSG_SPELL_FAILED_OTHER (for observers).
Previously these were consumed without updating cast state, leaving stale
cast bars for interrupted enemies. Now:

- SMSG_SPELL_FAILURE: erases unitCastStates_[failGuid] for non-player
  casters (still clears player casting/currentCastSpellId for own casts)
- SMSG_SPELL_FAILED_OTHER: erases unitCastStates_[guid] for the caster
  so boss/enemy cast bars immediately clear on interrupt/kick
2026-03-09 23:16:15 -07:00
Kelsi
07d0485a31 game/ui: generalize cast tracking to per-GUID map; add boss cast bars
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
2026-03-09 23:13:30 -07:00
Kelsi
4d39736d29 game/ui: add target cast bar to target frame (SMSG_SPELL_START tracking)
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()
2026-03-09 23:06:40 -07:00
Kelsi
6951b7803d game: fix SMSG_SPELL_GO miss-entry consumption in WotLK and TBC parsers
Both SpellGoParser::parse (WotLK) and TbcPacketParsers::parseSpellGo
(TBC) read missCount but did not consume the per-miss (guid + missType)
entries that follow, leaving unread bytes in the packet and silently
corrupting any subsequent parsing of cast-flags–gated spell data.

- Add SpellGoMissEntry{targetGuid, missType} and missTargets vector
  to SpellGoData
- WotLK parser now reads packed GUIDs + missType per miss entry
- TBC parser now reads full uint64 GUIDs + missType per miss entry
  (9 bytes per entry, bounds-checked)
- handleSpellGo now shows MISS/DODGE/PARRY/BLOCK combat text
  for each missed target when the local player cast the spell,
  complementing the existing SMSG_SPELLLOGMISS path
- Remove unused foliageLikeModel variable in m2_renderer pass-2 loop
  (fix unused-variable warning)
- Update smoke model comment in m2_renderer to reflect current state
2026-03-09 23:00:21 -07:00
Kelsi
06a628dae2 game: implement SMSG_PET_SPELLS/MODE/BROKEN and pet action plumbing
SMSG_PET_SPELLS: Parse full packet — pet GUID, react/command state,
10 action bar slots, per-spell entries with autocast flags.  Previously
only read the GUID.

SMSG_PET_MODE: Parse petGuid + mode uint32 (command low byte, react
high byte) to keep stance state in sync after server updates.

SMSG_PET_BROKEN: Clear pet state and show "Your pet has died." chat
message.

SMSG_PET_LEARNED_SPELL / SMSG_PET_UNLEARNED_SPELL: Maintain pet spell
list incrementally.

SMSG_PET_CAST_FAILED: Parse and log cast count + spell + reason.

New state accessors: getPetActionSlot(), getPetCommand(), getPetReact(),
getPetSpells(), isPetSpellAutocast().

CMSG_PET_ACTION: Add targetGuid (uint64) field — the wire format
requires petGuid(8)+action(4)+targetGuid(8).  Was sending an 12-byte
packet instead of the required 20 bytes.

sendPetAction(): New method that builds and sends CMSG_PET_ACTION with
the correct target guid.
2026-03-09 22:53:09 -07:00
Kelsi
52c1fed6ab game: implement dual-spec switch via CMSG_SET_ACTIVE_TALENT_GROUP (0x4C3)
switchTalentSpec() was only updating local state without notifying the
server, leaving the server out of sync with the client's active talent
group. Now sends CMSG_SET_ACTIVE_TALENT_GROUP_OBSOLETE (WotLK wire
opcode 0x4C3) with the target group index (0=primary, 1=secondary),
prompting the server to apply the spec swap and respond with a fresh
SMSG_TALENTS_INFO for the newly active group.

Also adds ActivateTalentGroupPacket::build() to world_packets for the
packet construction.
2026-03-09 22:49:23 -07:00
Kelsi
d339734143 game: fix LFG reward money display (copper→gold/silver/copper)
The SMSG_LFG_PLAYER_REWARD handler was printing raw copper value with
a "g" suffix (e.g. "12345g") instead of converting to gold/silver/copper.
Now formats as "1g 23s 45c" matching the standard WoW convention.
2026-03-09 22:45:06 -07:00
Kelsi
f63b75c388 tbc/classic: fix SMSG_RAID_INSTANCE_INFO format (uint32 resetTime, no extended)
TBC 2.4.3 and Classic 1.12 send resetTime as uint32 (seconds) with no
extended byte, while WotLK 3.3.5a sends uint64 timestamp + extended byte.
Parse the correct field widths based on expansion to prevent corrupted
instance lockout data on TBC/Classic realms.
2026-03-09 22:39:08 -07:00
Kelsi
c44477fbee Implement corpse reclaim: store death position and show Resurrect button
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
2026-03-09 22:31:56 -07:00
Kelsi
c6e39707de Fix resurrect: correct packet routing and show caster name in dialog
Two bugs fixed:

1. acceptResurrect() was always sending CMSG_SPIRIT_HEALER_ACTIVATE even
   for player-cast resurrections (Priest/Paladin/Druid). That opcode is
   only the correct response to SMSG_SPIRIT_HEALER_CONFIRM. For
   SMSG_RESURRECT_REQUEST the server expects CMSG_RESURRECT_RESPONSE
   with accept=1. Added resurrectIsSpiritHealer_ to track which path
   triggered the dialog and send the right packet per type.

2. The resurrect dialog showed a generic "Return to life?" string
   regardless of who cast the resurrection. Parse the optional CString
   name from SMSG_RESURRECT_REQUEST (or fall back to playerNameCache)
   and display "X wishes to resurrect you." when the caster is known.
2026-03-09 22:27:24 -07:00
Kelsi
ede380ec60 tbc: implement SMSG_INIT/SET_EXTRA_AURA_INFO_OBSOLETE for buff tracking
TBC 2.4.3 does not have SMSG_AURA_UPDATE (added in WotLK). Instead it
uses SMSG_INIT_EXTRA_AURA_INFO_OBSOLETE (0x3A3) for full aura refresh
on login/zone and SMSG_SET_EXTRA_AURA_INFO_OBSOLETE (0x3A4) for single-
slot updates. Implement handlers for both packets so TBC buff/debuff bars
populate correctly.

Also implement SMSG_CLEAR_EXTRA_AURA_INFO (0x3A6) to remove individual
aura slots when buffs expire or are cancelled server-side.

Format parsed: uint64 targetGuid + uint8 count + per-slot {uint8 slot,
uint32 spellId, uint8 effectIndex, uint8 flags, uint32 durationMs,
uint32 maxDurationMs}. Infinite auras (0xFFFFFFFF) stored as durationMs=-1.
2026-03-09 22:20:47 -07:00
Kelsi
8f0d2cc4ab terrain: pre-load bind point tiles during Hearthstone cast
When the player starts casting Hearthstone (spell IDs 6948/8690),
trigger background terrain loading at the bind point so tiles are
ready when the teleport fires.

- Add HearthstonePreloadCallback to GameHandler, called from
  handleSpellStart when a Hearthstone cast begins.
- Application callback enqueues a 5×5 tile grid around the bind
  point via precacheTiles() (same-map) or starts a file-cache warm
  via startWorldPreload() (cross-map) during the ~10 s cast time.
- On same-map teleport arrival, call processAllReadyTiles() to
  GPU-upload any tiles that finished parsing during the cast before
  the first frame at the new position.

Fixes: player landing in unloaded terrain and falling after Hearthstone.
2026-03-09 21:57:42 -07:00
Kelsi
0a6f88e8ad tbc: fix SMSG_SPELL_START and SMSG_SPELL_GO for TBC 2.4.3
TBC 2.4.3 SMSG_SPELL_START and SMSG_SPELL_GO send full uint64 GUIDs for
casterGuid/casterUnit and hit targets.  WotLK uses packed (variable-length)
GUIDs.  Using readPackedGuid() on a full uint64 reads the first byte as the
bitmask, consuming 1-8 wrong bytes, which shifts all subsequent fields
(spellId, castFlags, castTime) and causes:
  - Cast bar to never show for the player's own spells
  - Sound effects to use the wrong spell ID
  - Hit/miss target tracking to be completely wrong

Additionally, TBC SMSG_SPELL_GO lacks the WotLK timestamp field after
castFlags.

Add TbcPacketParsers::parseSpellStart and ::parseSpellGo using full GUIDs,
add virtual base methods, and route both handlers through virtual dispatch.
2026-03-09 21:48:41 -07:00
Kelsi
921c83df2e tbc: fix SMSG_CAST_RESULT — no castCount prefix in TBC 2.4.3
TBC 2.4.3 SMSG_CAST_RESULT sends spellId(u32) + result(u8) = 5 bytes.
WotLK 3.3.5a added a castCount(u8) prefix making it 6 bytes.  Without
this fix the WotLK parser was reading spellId[0] as castCount, then the
remaining 3 spellId bytes plus result byte as spellId (wrong), and then
whatever follows as result — producing incorrect failure messages and
potentially not clearing the cast bar on TBC.

Add TbcPacketParsers::parseCastResult override and a virtual base method,
then route SMSG_CAST_RESULT through virtual dispatch in the game handler.
2026-03-09 21:46:18 -07:00
Kelsi
1b2c7f595e classic: fix SMSG_CREATURE_QUERY_RESPONSE — no iconName field in 1.12
Classic 1.12 SMSG_CREATURE_QUERY_RESPONSE has no iconName CString between
subName and typeFlags.  The TBC/WotLK parser was reading the typeFlags
uint32 bytes as the iconName string, then reading the remaining bytes as
typeFlags — producing garbage creature type/family/rank values and
corrupting target frame display for all creatures on Classic servers.

Add ClassicPacketParsers::parseCreatureQueryResponse without the iconName
read, and route the game handler through virtual dispatch so the override
is called.
2026-03-09 21:44:07 -07:00
Kelsi
6d21f77d32 game: route aura/spell-list parsing through virtual packet dispatch
AuraUpdateParser and InitialSpellsParser were called as static functions
in the game handler, bypassing the expansion-specific overrides added to
TbcPacketParsers.  Switch them to packetParsers_->parseAuraUpdate() and
packetParsers_->parseInitialSpells() so TBC 2.4.3 servers get the correct
parser for each.
2026-03-09 21:38:14 -07:00
Kelsi
63d8200303 tbc: fix heal log GUID parsing and route combat through virtual dispatch
Add TbcPacketParsers::parseSpellHealLog override using full uint64 GUIDs
(TBC) instead of packed GUIDs (WotLK).  Route handleAttackerStateUpdate,
handleSpellDamageLog, and handleSpellHealLog through the virtual
packetParsers_ interface so expansion-specific overrides are actually
called.  Previously the game handler bypassed virtual dispatch with
direct static parser calls, making all three TBC overrides dead code.
2026-03-09 21:36:12 -07:00
Kelsi
9d1616a11b audio: stop precast sound on spell completion, failure, or interrupt
Add AudioEngine::playSound2DStoppable() + stopSound() so callers can
hold a handle and cancel playback early. SpellSoundManager::playPrecast()
now stores the handle in activePrecastId_; stopPrecast() cuts the sound.

playCast() calls stopPrecast() before playing the release sound, so the
channeling audio never bleeds past cast time. SMSG_SPELL_FAILURE and
SMSG_CAST_FAILED both call stopPrecast() so interrupted casts silence
immediately.
2026-03-09 21:04:24 -07:00
Kelsi
a49c013c89 Fix SMSG_RESUME_CAST_BAR: separate from unrelated opcodes in fallthrough group
SMSG_LOOT_LIST, SMSG_COMPLAIN_RESULT, SMSG_ITEM_REFUND_INFO_RESPONSE,
and SMSG_ITEM_ENCHANT_TIME_UPDATE were incorrectly falling through to the
SMSG_RESUME_CAST_BAR handler, causing those packets to be parsed as
cast bar resume data with a completely different wire format.
2026-03-09 20:40:58 -07:00
Kelsi
3f64f81ec0 Implement MSG_RAID_READY_CHECK_CONFIRM and MSG_RAID_READY_CHECK_FINISHED
Track individual member ready/not-ready responses in chat and summarize
results when all members have responded to the ready check.
2026-03-09 20:38:44 -07:00
Kelsi
95e8fcb88e Implement minimap ping: parse MSG_MINIMAP_PING and render animated ping circles
Parse party member minimap pings (packed GUID + posX + posY), store with
5s lifetime, and render as expanding concentric circles on the minimap.
2026-03-09 20:36:20 -07:00
Kelsi
0562139868 Implement SMSG_LOOT_ITEM_NOTIFY: show party loot notifications in chat
Parse loot item notify packets to display messages like "Thrall loots
[Item Name]." in system chat when a group member loots an item.
2026-03-09 20:31:57 -07:00
Kelsi
cc61732106 Implement SMSG_PARTYKILLLOG: show kill credit messages in chat
- Parse uint64 killerGuid + uint64 victimGuid
- Resolve names from playerNameCache (players) and entity manager (NPCs)
- Show "[Killer] killed [Victim]." as system chat when both names are known
2026-03-09 20:27:02 -07:00
Kelsi
5024e8cb32 Implement SMSG_SET_PROFICIENCY: track weapon/armor proficiency bitmasks
- Parse uint8 itemClass + uint32 subClassMask from SMSG_SET_PROFICIENCY
- Store weaponProficiency_ (itemClass=2) and armorProficiency_ (itemClass=4)
- Expose getWeaponProficiency(), getArmorProficiency(), canUseWeaponSubclass(n),
  canUseArmorSubclass(n) on GameHandler for use by equipment UI
- Enables future equipment slot validation (grey out non-proficient items)
2026-03-09 20:23:38 -07:00
Kelsi
926bcbb50e Implement SMSG_SPELLDISPELLOG dispel feedback and show dispel/steal notifications
- SMSG_SPELLDISPELLOG: parse packed caster/victim + dispel spell + isStolen +
  dispelled spell list; show system message when player dispels or has a buff
  dispelled/stolen (e.g. "Shadow Word: Pain was dispelled." / "You dispelled Renew.")
- SMSG_SPELLSTEALLOG: separated from SPELLDISPELLOG consume group with comment
  explaining the relationship (same wire format, player-facing covered by SPELLDISPELLOG)
2026-03-09 20:20:24 -07:00
Kelsi
151303a20a Implement SMSG_SPELLDAMAGESHIELD, SMSG_SPELLORDAMAGE_IMMUNE; route MSG_MOVE in SMSG_MULTIPLE_MOVES
- SMSG_SPELLDAMAGESHIELD: parse victim/caster/damage fields and show SPELL_DAMAGE
  combat text for player-relevant events (damage shields like Thorns)
- SMSG_SPELLORDAMAGE_IMMUNE: parse packed caster/victim guids and show new
  IMMUNE combat text type when player is involved in an immunity event
- Add CombatTextEntry::IMMUNE type to spell_defines.hpp and render it as
  white "Immune!" in the combat text overlay
- handleCompressedMoves: add MSG_MOVE_* routing so SMSG_MULTIPLE_MOVES
  sub-packets (player movement batches) are dispatched to handleOtherPlayerMovement
  instead of logged as unhandled; fix runtime-opcode lookup (non-static array)
2026-03-09 20:15:34 -07:00
Kelsi
b6dfa8b747 Implement SMSG_RESUME_CAST_BAR, SMSG_THREAT_UPDATE, SMSG_UPDATE_INSTANCE_ENCOUNTER_UNIT
- SMSG_RESUME_CAST_BAR: parse packed_guid caster/target + spellId + remainingMs +
  totalMs; restores cast bar state when server re-syncs a cast in progress
- SMSG_THREAT_UPDATE: properly consume packed_guid host/target + threat entries
  to suppress unhandled packet warnings
- SMSG_UPDATE_INSTANCE_ENCOUNTER_UNIT: track up to 5 boss encounter unit guids
  per slot; expose via getEncounterUnitGuid(slot); clear on world transfer
  These guids identify active boss units for raid/boss frame display.
2026-03-09 19:54:32 -07:00
Kelsi
9f340ef456 Fix SMSG_SPELL_DELAYED/EQUIPMENT_SET_SAVED incorrectly sharing PERIODICAURALOG handler
These two opcodes were accidentally falling through to the PERIODICAURALOG
handler which expects packed_guid+packed_guid+uint32+uint32 — wrong format.
Now:
- SMSG_SPELL_DELAYED: parse caster guid + delayMs, extend castTimeRemaining
  on player cast pushback (spell cast bar stays accurate under pushback)
- SMSG_EQUIPMENT_SET_SAVED: simple acknowledge log (no payload needed)
2026-03-09 19:46:52 -07:00
Kelsi
1d33ebbfe4 Wire SMSG_MULTIPLE_MOVES to handleCompressedMoves and parse SMSG_PROCRESIST
- SMSG_MULTIPLE_MOVES uses the same uint8-size+uint16-opcode format as
  SMSG_COMPRESSED_MOVES; route it to handleCompressedMoves() so bundled
  monster movement updates are processed instead of dropped
- SMSG_PROCRESIST: parse caster/victim GUIDs and show MISS combat text
  when the player's proc was resisted by an enemy spell
2026-03-09 19:42:27 -07:00
Kelsi
e56d3ca7de Add spell impact sounds for player-targeted spells and improve achievement messages
- Play SpellSoundManager::playImpact() with correct school when the player
  is hit by another unit's spell (SMSG_SPELL_GO hitTargets check)
- Show achievement name in SMSG_SERVER_FIRST_ACHIEVEMENT notifications
  using the already-loaded achievementNameCache_
- playImpact was fully implemented but never called; now wired up
2026-03-09 19:36:58 -07:00
Kelsi
63c8dfa304 Show achievement names from Achievement.dbc in chat notifications
Previously "Achievement earned! (ID 1234)" was the only message. Now
loadAchievementNameCache() lazily loads Achievement.dbc (field 4 = Title,
verified against WotLK 3.3.5a binary) on first earned event and shows
"Achievement earned: Level 10" or "Player has earned the achievement: ..."
Falls back to ID if DBC is unavailable or entry is missing.
2026-03-09 19:34:33 -07:00