Fix spell targeting, item query parsing, loot UI, hair/skin textures, and attack animations

Fix spell cast target fallback using selected target instead of no-op tautology.
Fix SMSG_ITEM_QUERY_SINGLE_RESPONSE to always read 10 stat pairs (server sends
all 10 regardless of statsCount), fixing misaligned armor/stat reads. Fix XP gain
parser to read float groupRate + uint8 RAF instead of bogus uint32 groupBonus.
Add item icons and quality-colored names to loot window. Use actual character
appearance bytes for CharSections.dbc skin/face/hair lookups instead of hardcoded
defaults. Add weapon-type-aware attack animation selection (2H prioritizes anim 18).
Add readable spell cast failure messages and vendor sell hint.
This commit is contained in:
Kelsi 2026-02-06 15:41:29 -08:00
parent f0aad5e97f
commit 2ddef93f52
9 changed files with 338 additions and 54 deletions

View file

@ -3309,7 +3309,7 @@ void GameHandler::castSpell(uint32_t spellId, uint64_t targetGuid) {
if (casting) return; // Already casting
uint64_t target = targetGuid != 0 ? targetGuid : targetGuid;
uint64_t target = targetGuid != 0 ? targetGuid : this->targetGuid;
auto packet = CastSpellPacket::build(spellId, target, ++castCount);
socket->send(packet);
LOG_INFO("Casting spell: ", spellId, " on 0x", std::hex, target, std::dec);
@ -3389,11 +3389,16 @@ void GameHandler::handleCastFailed(network::Packet& packet) {
currentCastSpellId = 0;
castTimeRemaining = 0.0f;
// Add system message about failed cast
// Add system message about failed cast with readable reason
const char* reason = getSpellCastResultString(data.result);
MessageChatData msg;
msg.type = ChatType::SYSTEM;
msg.language = ChatLanguage::UNIVERSAL;
msg.message = "Spell cast failed (error " + std::to_string(data.result) + ")";
if (reason) {
msg.message = reason;
} else {
msg.message = "Spell cast failed (error " + std::to_string(data.result) + ")";
}
addLocalChatMessage(msg);
}
@ -4310,8 +4315,8 @@ void GameHandler::simulateXpGain(uint64_t victimGuid, uint32_t totalXp) {
packet.writeUInt64(victimGuid);
packet.writeUInt32(totalXp);
packet.writeUInt8(0); // kill XP
packet.writeFloat(0.0f);
packet.writeUInt32(0); // group bonus
packet.writeFloat(1.0f); // group rate (1.0 = solo, no bonus)
packet.writeUInt8(0); // RAF flag
handleXpGain(packet);
}