diff --git a/include/game/spell_defines.hpp b/include/game/spell_defines.hpp index 55759128..67d94c2d 100644 --- a/include/game/spell_defines.hpp +++ b/include/game/spell_defines.hpp @@ -53,7 +53,7 @@ struct CombatTextEntry { MELEE_DAMAGE, SPELL_DAMAGE, HEAL, MISS, DODGE, PARRY, BLOCK, EVADE, CRIT_DAMAGE, CRIT_HEAL, PERIODIC_DAMAGE, PERIODIC_HEAL, ENVIRONMENTAL, ENERGIZE, POWER_DRAIN, XP_GAIN, IMMUNE, ABSORB, RESIST, DEFLECT, REFLECT, PROC_TRIGGER, - DISPEL, STEAL, INTERRUPT, INSTAKILL, HONOR_GAIN + DISPEL, STEAL, INTERRUPT, INSTAKILL, HONOR_GAIN, GLANCING, CRUSHING }; Type type; int32_t amount = 0; diff --git a/include/game/world_packets.hpp b/include/game/world_packets.hpp index c2e92f06..a30194f4 100644 --- a/include/game/world_packets.hpp +++ b/include/game/world_packets.hpp @@ -1719,8 +1719,10 @@ struct AttackerStateUpdateData { uint32_t blocked = 0; bool isValid() const { return attackerGuid != 0; } - bool isCrit() const { return (hitInfo & 0x200) != 0; } - bool isMiss() const { return (hitInfo & 0x10) != 0; } + bool isCrit() const { return (hitInfo & 0x0200) != 0; } + bool isMiss() const { return (hitInfo & 0x0010) != 0; } + bool isGlancing() const { return (hitInfo & 0x0800) != 0; } + bool isCrushing() const { return (hitInfo & 0x1000) != 0; } }; class AttackerStateUpdateParser { diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index a4ec7081..2a16211f 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -17772,7 +17772,15 @@ void GameHandler::handleAttackerStateUpdate(network::Packet& packet) { // VICTIMSTATE_DEFLECT: Attack was deflected (e.g. shield slam reflect). addCombatText(CombatTextEntry::DEFLECT, 0, 0, isPlayerAttacker, 0, data.attackerGuid, data.targetGuid); } else { - auto type = data.isCrit() ? CombatTextEntry::CRIT_DAMAGE : CombatTextEntry::MELEE_DAMAGE; + CombatTextEntry::Type type; + if (data.isCrit()) + type = CombatTextEntry::CRIT_DAMAGE; + else if (data.isCrushing()) + type = CombatTextEntry::CRUSHING; + else if (data.isGlancing()) + type = CombatTextEntry::GLANCING; + else + type = CombatTextEntry::MELEE_DAMAGE; addCombatText(type, data.totalDamage, 0, isPlayerAttacker, 0, data.attackerGuid, data.targetGuid); // Show partial absorb/resist from sub-damage entries uint32_t totalAbsorbed = 0, totalResisted = 0; diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index 277ecf7b..556f3917 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -9273,6 +9273,18 @@ void GameScreen::renderCombatText(game::GameHandler& gameHandler) { snprintf(text, sizeof(text), "+%d Honor", entry.amount); color = ImVec4(1.0f, 0.85f, 0.0f, alpha); // Gold for honor break; + case game::CombatTextEntry::GLANCING: + snprintf(text, sizeof(text), "~%d", entry.amount); + color = outgoing ? + ImVec4(0.75f, 0.75f, 0.5f, alpha) : // Outgoing glancing = muted yellow + ImVec4(0.75f, 0.35f, 0.35f, alpha); // Incoming glancing = muted red + break; + case game::CombatTextEntry::CRUSHING: + snprintf(text, sizeof(text), "%d!", entry.amount); + color = outgoing ? + ImVec4(1.0f, 0.55f, 0.1f, alpha) : // Outgoing crushing = orange + ImVec4(1.0f, 0.15f, 0.15f, alpha); // Incoming crushing = bright red + break; default: snprintf(text, sizeof(text), "%d", entry.amount); color = ImVec4(1.0f, 1.0f, 1.0f, alpha); @@ -9343,6 +9355,8 @@ void GameScreen::renderDPSMeter(game::GameHandler& gameHandler) { case game::CombatTextEntry::SPELL_DAMAGE: case game::CombatTextEntry::CRIT_DAMAGE: case game::CombatTextEntry::PERIODIC_DAMAGE: + case game::CombatTextEntry::GLANCING: + case game::CombatTextEntry::CRUSHING: dpsEncounterDamage_ += static_cast(e.amount); break; case game::CombatTextEntry::HEAL: @@ -9367,6 +9381,8 @@ void GameScreen::renderDPSMeter(game::GameHandler& gameHandler) { case game::CombatTextEntry::SPELL_DAMAGE: case game::CombatTextEntry::CRIT_DAMAGE: case game::CombatTextEntry::PERIODIC_DAMAGE: + case game::CombatTextEntry::GLANCING: + case game::CombatTextEntry::CRUSHING: totalDamage += static_cast(e.amount); break; case game::CombatTextEntry::HEAL: @@ -21218,7 +21234,7 @@ void GameScreen::renderCombatLog(game::GameHandler& gameHandler) { using T = game::CombatTextEntry; return t == T::MELEE_DAMAGE || t == T::SPELL_DAMAGE || t == T::CRIT_DAMAGE || t == T::PERIODIC_DAMAGE || - t == T::ENVIRONMENTAL; + t == T::ENVIRONMENTAL || t == T::GLANCING || t == T::CRUSHING; }; auto isHealType = [](game::CombatTextEntry::Type t) { using T = game::CombatTextEntry; @@ -21492,6 +21508,16 @@ void GameScreen::renderCombatLog(game::GameHandler& gameHandler) { snprintf(desc, sizeof(desc), "You gain %d honor", e.amount); color = ImVec4(1.0f, 0.85f, 0.0f, 1.0f); break; + case T::GLANCING: + snprintf(desc, sizeof(desc), "%s glances %s for %d", src, tgt, e.amount); + color = e.isPlayerSource ? ImVec4(0.75f, 0.75f, 0.5f, 1.0f) + : ImVec4(0.75f, 0.4f, 0.4f, 1.0f); + break; + case T::CRUSHING: + snprintf(desc, sizeof(desc), "%s crushes %s for %d!", src, tgt, e.amount); + color = e.isPlayerSource ? ImVec4(1.0f, 0.55f, 0.1f, 1.0f) + : ImVec4(1.0f, 0.15f, 0.15f, 1.0f); + break; default: snprintf(desc, sizeof(desc), "Combat event (type %d, amount %d)", (int)e.type, e.amount); color = ImVec4(0.7f, 0.7f, 0.7f, 1.0f);