Commit graph

1298 commits

Author SHA1 Message Date
Kelsi
962c640ff5 ui: add raid frames, quest log scroll-to-quest, and quest tracking polish
Raid frames:
- When groupType=1 (raid), render compact grid-style raid frames instead
  of the vertical party list that would overflow for 25/40-man groups
- Members organized by subgroup (G1-G8), up to 5 rows per subgroup column
- Each cell shows: name, health bar (green/yellow/red), power bar (class color)
- Clicking a cell targets the member; border highlight for current target
- Frames anchored above action bar area, centered horizontally

Quest log scroll-to-quest:
- openAndSelectQuest(questId) selects the quest AND scrolls the list pane
  to show it (SetScrollHereY on the first render frame after open)
- One-shot scroll: scrollToSelected_ cleared after first use so normal
  scroll behavior is unaffected afterward

Quest tracker:
- Clicking a tracked quest now calls openAndSelectQuest() — opens the log
  AND jumps to that specific quest rather than just opening to top
2026-03-10 05:26:16 -07:00
Kelsi
fb80b125bd Fix post-hearthstone asset gaps and add quest tracker interactivity
Hearthstone post-teleport fix:
- Expand same-map hearthstone precache from 5x5 to 9x9 tiles so workers
  have more tiles parsed before the player arrives at the bind point
- After same-map teleport arrival, enqueue the full load-radius tile grid
  (17x17 = 289 tiles) at the new position so background workers immediately
  start loading all WMOs/M2s visible from the new location

Quest tracker improvements:
- Clicking a quest in the tracker now opens the Quest Log (L)
- Remove NoInputs flag so the tracker window receives mouse events
- Show only tracked quests in tracker; fall back to all quests if none tracked
- Add Track/Untrack button in Quest Log details panel
- Abandoning a quest automatically untracks it
- Track state stored in GameHandler::trackedQuestIds_ (per-session)
2026-03-10 05:18:45 -07:00
Kelsi
682f47f66b game: downgrade high-frequency per-interaction LOG_INFO/WARNING to LOG_DEBUG
Demote parse-level diagnostic logs that fire on every game interaction:
- TBC/Classic gossip, quest details, quest rewards: LOG_INFO → LOG_DEBUG
- WotLK gossip, quest details/reward/request-items: LOG_INFO → LOG_DEBUG
- Attack start/stop, XP gain, loot, name query, vendor, party: LOG_INFO → LOG_DEBUG
- TBC SMSG_UPDATE_OBJECT has_transport fallback: LOG_WARNING → LOG_DEBUG
- TBC parseAuraUpdate not-in-TBC diagnostic: LOG_WARNING → LOG_DEBUG
- Turtle SMSG_MONSTER_MOVE WotLK fallback: LOG_WARNING → LOG_DEBUG

These all fire multiple times per second during normal gameplay.
2026-03-10 05:09:43 -07:00
Kelsi
f0233c092b game: downgrade false-positive LOG_WARNING calls for normal game events
SMSG_SHOW_BANK and SMSG_BUY_BANK_SLOT_RESULT are normal interactions
that were incorrectly logged at WARNING level. LOGIN_VERIFY_WORLD coord
dump is diagnostic detail, not a warning condition. Downgraded:
- SMSG_SHOW_BANK: LOG_WARNING → LOG_INFO
- SMSG_BUY_BANK_SLOT_RESULT: LOG_WARNING → LOG_INFO
- SMSG_TRANSFER_PENDING: LOG_WARNING → LOG_INFO (from previous session)
- SMSG_NEW_WORLD: LOG_WARNING → LOG_INFO (from previous session)
- LOGIN_VERIFY_WORLD coord dump: LOG_WARNING → LOG_DEBUG
2026-03-10 04:56:42 -07:00
Kelsi
4dab5daf79 game: remove duplicate initial-spells LOG_INFO and downgrade debug spell list
- world_packets.cpp::InitialSpellsParser::parse already logs spell count
  at LOG_INFO; remove the duplicate count from handleInitialSpells()
- Downgrade verbose format-detection LOG_INFO to LOG_DEBUG (packet size,
  format name, first-10 spell IDs) — these are diagnostic details that
  clutter INFO output without adding operational value
2026-03-10 04:52:22 -07:00
Kelsi
4972472b2a security+game: downgrade auth credential and high-frequency LOG_INFO to LOG_DEBUG
- AUTH HASH logs (sessionKey, hash input, digest): session key material
  must never appear in production logs at INFO level — downgrade to DEBUG
- SMSG_AUTH_CHALLENGE field details (seeds, unknown1): downgrade to DEBUG;
  keep one INFO line with format name for connection diagnostics
- SMSG_MOTD per-line content: downgrade to DEBUG; keep INFO line count
- Transport position update per-entity: fires on every update for each
  entity riding a transport — downgrade to DEBUG
2026-03-10 04:51:01 -07:00
Kelsi
dd8c2cbb20 game: downgrade per-item-query LOG_INFO to LOG_DEBUG in game_handler
queryItemInfo and handleItemQueryResponse fire for every item in
inventory, loot windows, vendor lists, and mail — potentially dozens
of times at login or when any container is opened.  Downgrade to
LOG_DEBUG to reduce noise.  Also downgrade useItemById search traces
to LOG_DEBUG; the final warning (item not found) stays at LOG_WARNING.
2026-03-10 04:48:33 -07:00
Kelsi
f22845b238 game: downgrade trainer/initial-spells diagnostic LOG_INFO to LOG_DEBUG
Debug-labeled LOG_INFO calls in handleTrainerList and handleInitialSpells
fire every time the trainer window opens or the player logs in, producing
noisy output that obscures meaningful events.

- handleTrainerList: known spells list dump, hardcoded prerequisite checks
  (527/25312), and per-spell detail lines → LOG_DEBUG
  Keep one LOG_INFO for the spell count summary (meaningful lifecycle event)
- handleInitialSpells: hardcoded spell presence checks (527/988/1180) →
  LOG_DEBUG; replace with a single LOG_INFO for spell count summary
2026-03-10 04:46:42 -07:00
Kelsi
31ae689b2c game: fix TBC SMSG_QUESTGIVER_QUEST_DETAILS parsing by promoting Classic override to TbcPacketParsers
TBC 2.4.3 and Classic 1.12 share the same SMSG_QUESTGIVER_QUEST_DETAILS
format.  WotLK 3.3.5a adds three extra fields (informUnit u64, flags u32,
isFinished u8) that the base QuestDetailsParser::parse handles.  TBC had no
override, so it fell through to the WotLK heuristic which read flags+isFinished
as if they were TBC fields, misaligning choiceCount, rewardMoney, and rewardXp.

Fix: move parseQuestDetails from ClassicPacketParsers to TbcPacketParsers.
Classic inherits it unchanged (formats are identical).  Both expansions now
correctly parse: no informUnit, activateAccept(u8), suggestedPlayers(u32),
emote section, variable choice/reward item counts, rewardMoney, and rewardXp.
2026-03-10 04:37:03 -07:00
Kelsi
475e0c213c rendering: downgrade per-NPC-spawn LOG_INFO spam to LOG_DEBUG in application.cpp
Model batch submesh IDs and NPC geoset lists fire on every NPC spawn and
produce excessive log noise in normal gameplay. Downgrade to LOG_DEBUG.
Also downgrade per-equipment-slot DBC lookups from LOG_INFO to LOG_DEBUG.
2026-03-10 04:30:01 -07:00
Kelsi
f533373050 game: downgrade combat/charEnum per-entry LOG_INFO to LOG_DEBUG in WotLK parsers
Consistent with the same cleanup for Classic/TBC parsers. Melee hit, spell
damage, and spell heal logs fire on every combat event and belong at DEBUG
level. Per-character detail lines in the WotLK CharEnum parser are also
consolidated to a single DEBUG line per character.
2026-03-10 04:25:45 -07:00
Kelsi
d7ef40c9d7 game: downgrade combat/charEnum per-entry LOG_INFO to LOG_DEBUG in Classic/TBC parsers
Combat event logs (melee hit, spell damage, spell heal) fire on every combat
event and should be DEBUG-level. The per-character detail lines in parseCharEnum
are also moved to DEBUG — the summary line stays at INFO.
2026-03-10 04:23:54 -07:00
Kelsi
3bee0882cc game: fix Classic parseQuestDetails missing rewardXp field
Vanilla 1.12 SMSG_QUESTGIVER_QUEST_DETAILS includes rewardXp (uint32)
after rewardMoney, same as WotLK. Without this read the XP reward was
always 0 in the quest accept dialog for Classic.
2026-03-10 04:20:13 -07:00
Kelsi
5c830216be Remove debug LOG_INFO spam from applyEquipment; use DBC layout for texture fields
The verbose diagnostic logs added in 16cdde8 for Classic equipment debugging
are no longer needed now that the CSV string-detection bug is fixed. Remove
them to eliminate log spam on every character screen open.

Also replace the hardcoded `14 + region` texture field lookup with the same
DBC-layout-aware array pattern used in game_screen.cpp::updateCharacterTextures,
so texture field indices are correctly resolved per expansion.
2026-03-10 04:16:27 -07:00
Kelsi
b31a2a66b6 tools: fix DBC string-column detection false positives in both dbc_to_csv and asset_extract
The string-column auto-detector in both tools had two gaps that caused small
integer fields (RaceID=1, SexID=0/1, BaseSection, ColorIndex) to be falsely
classified as string columns, corrupting the generated CSVs:

1. No boundary check: a value of N was accepted as a valid string offset even
   when N landed inside a longer string (e.g. offset 3 inside "Character\...").
   Fix: precompute valid string-start boundaries (offset 0 plus every position
   immediately after a null byte); reject offsets that are not boundaries.

2. No diversity check: a column whose only non-zero value is 1 would pass the
   boundary test because offset 1 is always a valid boundary (it follows the
   mandatory null at offset 0). Fix: require at least 2 distinct non-empty
   string values before marking a column as a string column. Columns like
   SexID (all values are 0 or 1, resolving to "" and the same path fragment)
   are integer fields, not string fields.

Both dbc_to_csv and asset_extract now produce correct column metadata,
e.g. CharSections.dbc yields "strings=6,7,8" instead of "strings=0,1,...,9".
2026-03-10 03:49:06 -07:00
Kelsi
5b06a62d91 game: fix Classic/TBC movement ACKs silently dropped by isClassicLikeExpansion guard
Five movement control response handlers (speed change, move-root, move-flag
change, knock-back, teleport) had guards of the form !isClassicLikeExpansion()
or isClassicLikeExpansion() that prevented ACKs from ever being sent on
Classic/Turtle.  Each handler already contained correct legacyGuidAck logic
(full uint64 for Classic/TBC, packed GUID for WotLK) that was unreachable
due to the outer guard.

Classic servers (CMaNGOS/VMaNGOS/ChromieCraft) expect all of these ACKs.
Without them the server stalls the player's speed update, keeps root state
desynced, or generates movement hacks.  Fix by removing the erroneous
expansion guard and relying on the existing legacyGuidAck path.

Affected: handleForceSpeedChange, handleForceMoveRootState,
          handleForceMoveFlagChange, handleMoveKnockBack, handleTeleport.
2026-03-10 03:30:24 -07:00
Kelsi
4a213d8da8 tools/game: fix dbc_to_csv false-positive string detection + clear DBC cache on expansion switch
dbc_to_csv: The string-column auto-detector would mark integer fields (e.g.
RaceID=1, SexID=0, BaseSection=0-4) as string columns whenever their small
values were valid string-block offsets that happened to land inside longer
strings.  Fix by requiring that an offset point to a string *boundary* (offset
0 or immediately after a null byte) rather than any valid position — this
eliminates false positives from integer fields whose values accidentally alias
path substrings.  Affected CSVs (CharSections, ItemDisplayInfo for Classic/TBC)
can now be regenerated correctly.

game_handler: clearDBCCache() is already called by application.cpp before
resetDbcCaches(), but also add it inside resetDbcCaches() as a defensive
measure so that future callers of resetDbcCaches() alone also flush stale
expansion-specific DBC data (CharSections, ItemDisplayInfo, etc.).
2026-03-10 03:27:30 -07:00
Kelsi
29ca9809b1 game: fix Classic parseQuestDetails missing emote section before reward items
Some checks are pending
Build / Build (arm64) (push) Waiting to run
Build / Build (x86-64) (push) Waiting to run
Build / Build (macOS arm64) (push) Waiting to run
Build / Build (windows-arm64) (push) Waiting to run
Build / Build (windows-x86-64) (push) Waiting to run
Security / CodeQL (C/C++) (push) Waiting to run
Security / Semgrep (push) Waiting to run
Security / Sanitizer Build (ASan/UBSan) (push) Waiting to run
Vanilla 1.12 SMSG_QUESTGIVER_QUEST_DETAILS includes an emote section
between suggestedPlayers and the choice/reward item lists:
  activateAccept(u8) + suggestedPlayers(u32) +
  emoteCount(u32) + [delay(u32) + type(u32)] × emoteCount +
  choiceCount(u32) + choices + rewardCount(u32) + rewards + money(u32)

The parser was skipping the emote section, causing the emote count to
be misread as the choice item count. Quests with emotes would show
zero choice items and shifted/missing reward and money data.
2026-03-10 03:09:12 -07:00
Kelsi
16cdde82b3 rendering: add diagnostic logging to applyEquipment for Classic equipment debugging
Log each equipment item's displayModel, inventoryType, and DBC lookup result
to help identify why Classic character equipment does not render correctly.
Also log ItemDisplayInfo.dbc field count, found texture names per region,
and missing texture paths so the exact failure point is visible in logs.
2026-03-10 02:23:54 -07:00
Kelsi
967cedba0e game: fix Classic/TBC SMSG_QUESTGIVER_QUEST_LIST quest title and questCount parsing
Classic 1.12 and TBC 2.4.3 don't include questFlags(u32) + isRepeatable(u8)
before each quest title in SMSG_QUESTGIVER_QUEST_LIST. WotLK 3.3.5a added
those 5 bytes. The previous code read them speculatively for all expansions
and only rewound on empty title, which failed for any non-empty title.

Also fix questCount always reading as uint8 (all WoW versions use u8 here).
The old u32/u8 heuristic could misread 4 bytes instead of 1, misaligning all
subsequent quest item reads.
2026-03-10 01:54:01 -07:00
Kelsi
7270a4e690 game: fix TBC 2.4.3 SMSG_CAST_FAILED missing parseCastFailed override
TBC 2.4.3 SMSG_CAST_FAILED format is spellId(u32) + result(u8), same as
Classic. WotLK added a castCount(u8) prefix before spellId. TbcPacketParsers
lacked a parseCastFailed override, so it fell through to the WotLK base
which read one extra byte as castCount, shifting the spellId read by one
byte and corrupting the spell ID and result for every failed cast on TBC.

- Add TbcPacketParsers::parseCastFailed override: reads spellId(4)+result(1)
- ClassicPacketParsers already overrides this (enum shift +1), so Classic unaffected
2026-03-10 01:30:06 -07:00
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
04f22376ce game: fix Classic 1.12 SMSG_NAME_QUERY_RESPONSE race/gender/class parsing
Classic 1.12 servers (vmangos/cmangos-classic) send:
  uint64 guid + CString name + CString realmName + uint32 race + uint32 gender + uint32 class

TBC's Variant A (which Classic inherited) skipped the realmName CString,
causing the null terminator of the empty realmName to be absorbed into the
low byte of the uint32 race read, producing race=0 and shifted gender/class.

Adds a ClassicPacketParsers::parseNameQueryResponse override that correctly
reads the realmName CString before the race/gender/class uint32 fields.
2026-03-10 00:53:03 -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
cb0dfddf59 game: add Classic 1.12 parseAuraUpdate override to restore aura tracking
Classic 1.12 sends SMSG_AURA_UPDATE/SMSG_AURA_UPDATE_ALL, but ClassicPacketParsers
inherited TBC's override which returns false (TBC uses a different aura system
and doesn't send SMSG_AURA_UPDATE at all).

Classic aura format differs from WotLK in two key ways:
- DURATION flag bit is 0x10 in Vanilla, not 0x20 as in WotLK; reading with the
  WotLK parser would incorrectly gate duration reads and misparse aura fields
- No caster GUID field in Classic; WotLK parser tries to read one (gated by 0x08)
  which would consume spell ID or flag bytes from the next aura slot

With this override, player/target aura bars and buff tracking work correctly
on Classic 1.12 connections for the first time.
2026-03-10 00:30:28 -07:00
Kelsi
b15a21a957 game: add Classic 1.12 overrides for melee/spell damage log packets
Vanilla 1.12 SMSG_ATTACKERSTATEUPDATE, SMSG_SPELLNONMELEEDAMAGELOG, and
SMSG_SPELLHEALLOG use PackedGuid for all entity GUIDs, not full uint64
as TBC and WotLK do.

Without these overrides Classic inherited TBC's implementations, which
over-read PackedGuid fields as fixed 8-byte GUIDs, misaligning all
subsequent damage/heal fields and making combat parsing unusable on
Classic servers.

The Classic override logic is identical to TBC except for the GUID
reads, so combat text, damage numbers, and kill tracking now work
correctly on Vanilla 1.12 connections.
2026-03-10 00:27:08 -07:00
Kelsi
5f06c18a54 game: add Classic 1.12 overrides for parseSpellStart and parseSpellGo
Vanilla 1.12 SMSG_SPELL_START and SMSG_SPELL_GO use:
- PackedGuid (variable-length) for caster and target GUIDs, not full uint64
- uint16 castFlags, not uint32 as in TBC/WotLK
- uint16 targetFlags in SpellCastTargets, not uint32

Without these overrides Classic inherited TBC's implementations which
read 8 bytes for each GUID (over-reading the PackedGuid) and then 4
bytes for castFlags instead of 2, misaligning all subsequent fields
and producing garbage spell IDs, cast times, and target GUIDs.

Hit and miss target GUIDs in SMSG_SPELL_GO are also PackedGuid in
Vanilla (vs full uint64 in TBC), handled by the new parseSpellGo.
2026-03-10 00:24:16 -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
1c85b7a46d ui: add combo point display to player frame (Rogue/Druid)
Adds 5 gold/grey dot indicators below the power bar in the player frame
for Rogue (class 4) and Druid (class 11), showing the current combo
point count from SMSG_UPDATE_COMBO_POINTS. Active points are bright gold;
empty slots are dark grey. Dots are centered in the frame width.
The display is always shown for Rogues; for Druids it only appears when
combo points are non-zero (they only accumulate in Cat Form).
2026-03-09 23:09:58 -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