feat(Core/Items): Implemented elemental weapon damage. Source: Trinit… (#13050)

...yCore.
This commit is contained in:
UltraNix
2022-10-08 19:34:52 +02:00
committed by GitHub
parent 02b3f74d6d
commit e390087efd
13 changed files with 778 additions and 287 deletions
@@ -2156,7 +2156,7 @@ void Creature::LoadSpellTemplateImmunity()
}
}
bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo)
bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
{
if (!spellInfo)
return false;
@@ -2178,7 +2178,7 @@ bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo)
if (immunedToAllEffects)
return true;
return Unit::IsImmunedToSpell(spellInfo);
return Unit::IsImmunedToSpell(spellInfo, spell);
}
bool Creature::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const
+3 -3
View File
@@ -96,7 +96,7 @@ public:
[[nodiscard]] bool IsValidTrainerForPlayer(Player* player, uint32* npcFlags = nullptr) const;
bool CanCreatureAttack(Unit const* victim, bool skipDistCheck = false) const;
void LoadSpellTemplateImmunity();
bool IsImmunedToSpell(SpellInfo const* spellInfo) override;
bool IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell = nullptr) override;
[[nodiscard]] bool HasMechanicTemplateImmunity(uint32 mask) const;
// redefine Unit::IsImmunedToSpell
@@ -155,7 +155,7 @@ public:
return (getLevel() / 2 + uint32(GetStat(STAT_STRENGTH) / 20));
}
[[nodiscard]] SpellSchoolMask GetMeleeDamageSchoolMask() const override { return m_meleeDamageSchoolMask; }
[[nodiscard]] SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType /*attackType*/ = BASE_ATTACK, uint8 /*damageIndex*/ = 0) const override { return m_meleeDamageSchoolMask; }
void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = SpellSchoolMask(1 << school); }
void _AddCreatureSpellCooldown(uint32 spell_id, uint16 categoryId, uint32 end_time);
@@ -178,7 +178,7 @@ public:
void UpdateMaxHealth() override;
void UpdateMaxPower(Powers power) override;
void UpdateAttackPowerAndDamage(bool ranged = false) override;
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) override;
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex) override;
void SetCanDualWield(bool value) override;
[[nodiscard]] int8 GetOriginalEquipmentId() const { return m_originalEquipmentId; }
+45 -34
View File
@@ -6740,21 +6740,11 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
if (proto->ArcaneRes)
HandleStatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(proto->ArcaneRes), apply);
WeaponAttackType attType = BASE_ATTACK;
if (slot == EQUIPMENT_SLOT_RANGED && (
proto->InventoryType == INVTYPE_RANGED || proto->InventoryType == INVTYPE_THROWN ||
proto->InventoryType == INVTYPE_RANGEDRIGHT))
uint8 attType = Player::GetAttackBySlot(slot);
if (attType != MAX_ATTACK)
{
attType = RANGED_ATTACK;
}
else if (slot == EQUIPMENT_SLOT_OFFHAND)
{
attType = OFF_ATTACK;
}
if (CanUseAttackType(attType))
_ApplyWeaponDamage(slot, proto, ssv, apply);
}
// Druids get feral AP bonus from weapon dps (also use DPS from ScalingStatValue)
if (getClass() == CLASS_DRUID)
@@ -6797,22 +6787,16 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingSt
ssv = ScalingStatValue ? sScalingStatValuesStore.LookupEntry(ssd_level) : nullptr;
}
WeaponAttackType attType = BASE_ATTACK;
float damage = 0.0f;
if (slot == EQUIPMENT_SLOT_RANGED && (
proto->InventoryType == INVTYPE_RANGED || proto->InventoryType == INVTYPE_THROWN ||
proto->InventoryType == INVTYPE_RANGEDRIGHT))
uint8 attType = Player::GetAttackBySlot(slot);
if (!IsInFeralForm() && apply && !CanUseAttackType(attType))
{
attType = RANGED_ATTACK;
}
else if (slot == EQUIPMENT_SLOT_OFFHAND)
{
attType = OFF_ATTACK;
return;
}
float minDamage = proto->Damage[0].DamageMin;
float maxDamage = proto->Damage[0].DamageMax;
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
float minDamage = proto->Damage[i].DamageMin;
float maxDamage = proto->Damage[i].DamageMax;
// If set dpsMod in ScalingStatValue use it for min (70% from average), max (130% from average) damage
if (ssv)
@@ -6826,16 +6810,33 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingSt
}
}
if (minDamage > 0)
if (apply)
{
damage = apply ? minDamage : BASE_MINDAMAGE;
SetBaseWeaponDamage(attType, MINDAMAGE, damage);
if (minDamage > 0.f)
{
SetBaseWeaponDamage(WeaponAttackType(attType), MINDAMAGE, minDamage, i);
}
if (maxDamage > 0)
if (maxDamage > 0.f)
{
damage = apply ? maxDamage : BASE_MAXDAMAGE;
SetBaseWeaponDamage(attType, MAXDAMAGE, damage);
SetBaseWeaponDamage(WeaponAttackType(attType), MAXDAMAGE, maxDamage, i);
}
}
}
if (!apply)
{
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
SetBaseWeaponDamage(WeaponAttackType(attType), MINDAMAGE, 0.f, i);
SetBaseWeaponDamage(WeaponAttackType(attType), MAXDAMAGE, 0.f, i);
}
if (attType == BASE_ATTACK)
{
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, BASE_MINDAMAGE);
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, BASE_MAXDAMAGE);
}
}
if (proto->Delay && !IsInFeralForm())
@@ -6852,8 +6853,18 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingSt
if (IsInFeralForm())
return;
if (CanModifyStats() && (damage || proto->Delay))
UpdateDamagePhysical(attType);
if (CanModifyStats() && (GetWeaponDamageRange(WeaponAttackType(attType), MAXDAMAGE) || proto->Delay))
UpdateDamagePhysical(WeaponAttackType(attType));
}
SpellSchoolMask Player::GetMeleeDamageSchoolMask(WeaponAttackType attackType /*= BASE_ATTACK*/, uint8 damageIndex /*= 0*/) const
{
if (Item const* weapon = GetWeaponForAttack(attackType, true))
{
return SpellSchoolMask(1 << weapon->GetTemplate()->Damage[damageIndex].DamageType);
}
return SPELL_SCHOOL_MASK_NORMAL;
}
void Player::_ApplyWeaponDependentAuraMods(Item* item, WeaponAttackType attackType, bool apply)
+3 -1
View File
@@ -1905,7 +1905,7 @@ public:
void UpdateRating(CombatRating cr);
void UpdateAllRatings();
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) override;
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex) override;
void UpdateDefenseBonusesMod();
inline void RecalculateRating(CombatRating cr) { ApplyRatingMod(cr, 0, true);}
@@ -2147,6 +2147,8 @@ public:
void ResetAllPowers();
SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType = BASE_ATTACK, uint8 damageIndex = 0) const override;
void _ApplyWeaponDependentAuraMods(Item* item, WeaponAttackType attackType, bool apply);
void _ApplyWeaponDependentAuraCritMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply);
void _ApplyWeaponDependentAuraDamageMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply);
+40 -11
View File
@@ -59,25 +59,31 @@ void Unit::UpdateAllResistances()
void Unit::UpdateDamagePhysical(WeaponAttackType attType)
{
float minDamage = 0.0f;
float maxDamage = 0.0f;
float totalMin = 0.f;
float totalMax = 0.f;
CalculateMinMaxDamage(attType, false, true, minDamage, maxDamage);
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
float tmpMin, tmpMax;
CalculateMinMaxDamage(attType, false, true, tmpMin, tmpMax, i);
totalMin += tmpMin;
totalMax += tmpMax;
}
switch (attType)
{
case BASE_ATTACK:
default:
SetStatFloatValue(UNIT_FIELD_MINDAMAGE, minDamage);
SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxDamage);
SetStatFloatValue(UNIT_FIELD_MINDAMAGE, totalMin);
SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, totalMax);
break;
case OFF_ATTACK:
SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE, minDamage);
SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE, maxDamage);
SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE, totalMin);
SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE, totalMax);
break;
case RANGED_ATTACK:
SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, minDamage);
SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, maxDamage);
SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, totalMin);
SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, totalMax);
break;
}
}
@@ -525,8 +531,23 @@ void Player::UpdateShieldBlockValue()
SetUInt32Value(PLAYER_SHIELD_BLOCK, GetShieldBlockValue());
}
void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage)
void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex)
{
// Only proto damage, not affected by any mods
if (damageIndex != 0)
{
minDamage = 0.0f;
maxDamage = 0.0f;
if (!IsInFeralForm() && CanUseAttackType(attType))
{
minDamage = GetWeaponDamageRange(attType, MINDAMAGE, damageIndex);
maxDamage = GetWeaponDamageRange(attType, MAXDAMAGE, damageIndex);
}
return;
}
UnitMods unitMod;
switch (attType)
@@ -1075,8 +1096,16 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged)
}
}
void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage)
void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex /*= 0*/)
{
// creatures only have one damage
if (damageIndex != 0)
{
minDamage = 0.f;
maxDamage = 0.f;
return;
}
UnitMods unitMod;
float variance = 1.0f;
switch (attType)
+499 -117
View File
@@ -118,9 +118,19 @@ DamageInfo::DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellInfo
m_block = 0;
}
DamageInfo::DamageInfo(CalcDamageInfo& dmgInfo)
: m_attacker(dmgInfo.attacker), m_victim(dmgInfo.target), m_damage(dmgInfo.damage), m_spellInfo(nullptr), m_schoolMask(SpellSchoolMask(dmgInfo.damageSchoolMask)),
m_damageType(DIRECT_DAMAGE), m_attackType(dmgInfo.attackType), m_absorb(dmgInfo.absorb), m_resist(dmgInfo.resist), m_block(dmgInfo.blocked_amount),
DamageInfo::DamageInfo(CalcDamageInfo const& dmgInfo) : DamageInfo(DamageInfo(dmgInfo, 0), DamageInfo(dmgInfo, 1))
{
}
DamageInfo::DamageInfo(DamageInfo const& dmg1, DamageInfo const& dmg2)
: m_attacker(dmg1.m_attacker), m_victim(dmg1.m_victim), m_damage(dmg1.m_damage + dmg2.m_damage), m_spellInfo(dmg1.m_spellInfo), m_schoolMask(SpellSchoolMask(dmg1.m_schoolMask | dmg2.m_schoolMask)),
m_damageType(dmg1.m_damageType), m_attackType(dmg1.m_attackType), m_absorb(dmg1.m_absorb + dmg2.m_absorb), m_resist(dmg1.m_resist + dmg2.m_resist), m_block(dmg1.m_block)
{
}
DamageInfo::DamageInfo(CalcDamageInfo const& dmgInfo, uint8 damageIndex)
: m_attacker(dmgInfo.attacker), m_victim(dmgInfo.target), m_damage(dmgInfo.damages[damageIndex].damage), m_spellInfo(nullptr), m_schoolMask(SpellSchoolMask(dmgInfo.damages[damageIndex].damageSchoolMask)),
m_damageType(DIRECT_DAMAGE), m_attackType(dmgInfo.attackType), m_absorb(dmgInfo.damages[damageIndex].absorb), m_resist(dmgInfo.damages[damageIndex].resist), m_block(dmgInfo.blocked_amount),
m_cleanDamage(dmgInfo.cleanDamage)
{
}
@@ -268,8 +278,11 @@ Unit::Unit(bool isWorldObject) : WorldObject(isWorldObject),
for (uint8 i = 0; i < MAX_ATTACK; ++i)
{
m_weaponDamage[i][MINDAMAGE] = BASE_MINDAMAGE;
m_weaponDamage[i][MAXDAMAGE] = BASE_MAXDAMAGE;
m_weaponDamage[i][MINDAMAGE][0] = BASE_MINDAMAGE;
m_weaponDamage[i][MAXDAMAGE][0] = BASE_MAXDAMAGE;
m_weaponDamage[i][MINDAMAGE][1] = 0.f;
m_weaponDamage[i][MAXDAMAGE][1] = 0.f;
}
for (uint8 i = 0; i < MAX_STATS; ++i)
@@ -1437,16 +1450,21 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss,
}
// TODO for melee need create structure as in
void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType, const bool sittingVictim)
void Unit::CalculateMeleeDamage(Unit* victim, CalcDamageInfo* damageInfo, WeaponAttackType attackType, const bool sittingVictim)
{
damageInfo->attacker = this;
damageInfo->target = victim;
damageInfo->damageSchoolMask = GetMeleeDamageSchoolMask();
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
damageInfo->damages[i].damageSchoolMask = GetMeleeDamageSchoolMask(attackType, i);
damageInfo->damages[i].damage = 0;
damageInfo->damages[i].absorb = 0;
damageInfo->damages[i].resist = 0;
}
damageInfo->attackType = attackType;
damageInfo->damage = 0;
damageInfo->cleanDamage = 0;
damageInfo->absorb = 0;
damageInfo->resist = 0;
damageInfo->blocked_amount = 0;
damageInfo->TargetState = 0;
@@ -1478,8 +1496,25 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
return;
}
// Physical Immune check
if (damageInfo->target->IsImmunedToDamageOrSchool(SpellSchoolMask(damageInfo->damageSchoolMask)))
// School Immune check
uint8 immunedMask = 0;
bool hasNonPhysicalSchoolMask = false;
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
if (damageInfo->target->IsImmunedToDamageOrSchool(SpellSchoolMask(damageInfo->damages[i].damageSchoolMask)))
{
immunedMask |= (1 << i);
if (damageInfo->damages[i].damageSchoolMask != SPELL_SCHOOL_MASK_NORMAL)
{
hasNonPhysicalSchoolMask = true;
}
}
}
// School Immune check
if (immunedMask & ((1 << 0) | (1 << 1)))
{
if (hasNonPhysicalSchoolMask || immunedMask == ((1 << 0) | (1 << 1)))
{
damageInfo->HitInfo |= HITINFO_NORMALSWING;
damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE;
@@ -1487,23 +1522,46 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
damageInfo->procEx |= PROC_EX_IMMUNE;
return;
}
}
damage += CalculateDamage(damageInfo->attackType, false, true);
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
// only players have secondary weapon damage
if (i > 0 && GetTypeId() != TYPEID_PLAYER)
{
break;
}
if (immunedMask & (1 << i))
{
continue;
}
SpellSchoolMask schoolMask = SpellSchoolMask(damageInfo->damages[i].damageSchoolMask);
bool const addPctMods = (schoolMask & SPELL_SCHOOL_MASK_NORMAL);
uint32 damage = 0;
uint8 itemDamagesMask = (GetTypeId() == TYPEID_PLAYER) ? (1 << i) : 0;
damage += CalculateDamage(damageInfo->attackType, false, addPctMods, itemDamagesMask);
// Add melee damage bonus
damage = MeleeDamageBonusDone(damageInfo->target, damage, damageInfo->attackType);
damage = damageInfo->target->MeleeDamageBonusTaken(this, damage, damageInfo->attackType);
damage = MeleeDamageBonusDone(damageInfo->target, damage, damageInfo->attackType, nullptr, schoolMask);
damage = damageInfo->target->MeleeDamageBonusTaken(this, damage, damageInfo->attackType, nullptr, schoolMask);
// Script Hook For CalculateMeleeDamage -- Allow scripts to change the Damage pre class mitigation calculations
sScriptMgr->ModifyMeleeDamage(damageInfo->target, damageInfo->attacker, damage);
// Calculate armor reduction
if (IsDamageReducedByArmor((SpellSchoolMask)(damageInfo->damageSchoolMask)))
if (IsDamageReducedByArmor((SpellSchoolMask)(damageInfo->damages[i].damageSchoolMask)))
{
damageInfo->damage = Unit::CalcArmorReducedDamage(this, damageInfo->target, damage, nullptr, 0, damageInfo->attackType);
damageInfo->cleanDamage += damage - damageInfo->damage;
damageInfo->damages[i].damage = Unit::CalcArmorReducedDamage(this, damageInfo->target, damage, nullptr, 0, damageInfo->attackType);
damageInfo->cleanDamage += damage - damageInfo->damages[i].damage;
}
else
damageInfo->damage = damage;
{
damageInfo->damages[i].damage = damage;
}
}
damageInfo->hitOutCome = RollMeleeOutcomeAgainst(damageInfo->target, damageInfo->attackType);
@@ -1518,14 +1576,23 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
damageInfo->HitInfo |= HITINFO_MISS | HITINFO_SWINGNOHITSOUND;
damageInfo->TargetState = VICTIMSTATE_EVADES;
damageInfo->procEx |= PROC_EX_EVADE;
damageInfo->damage = 0;
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
damageInfo->damages[i].damage = 0;
}
damageInfo->cleanDamage = 0;
return;
case MELEE_HIT_MISS:
damageInfo->HitInfo |= HITINFO_MISS;
damageInfo->TargetState = VICTIMSTATE_INTACT;
damageInfo->procEx |= PROC_EX_MISS;
damageInfo->damage = 0;
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
damageInfo->damages[i].damage = 0;
}
damageInfo->cleanDamage = 0;
break;
case MELEE_HIT_NORMAL:
@@ -1539,17 +1606,22 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
damageInfo->procEx |= PROC_EX_CRITICAL_HIT;
// Crit bonus calc
damageInfo->damage += damageInfo->damage;
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
damageInfo->damages[i].damage *= 2;
float mod = 0.0f;
// Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
if (damageInfo->attackType == RANGED_ATTACK)
{
mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE);
}
else
{
mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
// Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
mod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, damageInfo->damageSchoolMask) - 1.0f) * 100;
mod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, damageInfo->damages[i].damageSchoolMask) - 1.0f) * 100;
}
uint32 crTypeMask = damageInfo->target->GetCreatureTypeMask();
@@ -1557,22 +1629,36 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
// Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
mod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask);
if (mod != 0)
AddPct(damageInfo->damage, mod);
{
AddPct(damageInfo->damages[i].damage, mod);
}
}
break;
}
case MELEE_HIT_PARRY:
damageInfo->TargetState = VICTIMSTATE_PARRY;
damageInfo->procEx |= PROC_EX_PARRY;
damageInfo->cleanDamage += damageInfo->damage;
damageInfo->damage = 0;
damageInfo->cleanDamage = 0;
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
damageInfo->cleanDamage += damageInfo->damages[i].damage;
damageInfo->damages[i].damage = 0;
}
break;
case MELEE_HIT_DODGE:
damageInfo->TargetState = VICTIMSTATE_DODGE;
damageInfo->procEx |= PROC_EX_DODGE;
damageInfo->cleanDamage += damageInfo->damage;
damageInfo->damage = 0;
damageInfo->cleanDamage = 0;
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
damageInfo->cleanDamage += damageInfo->damages[i].damage;
damageInfo->damages[i].damage = 0;
}
break;
case MELEE_HIT_BLOCK:
{
damageInfo->TargetState = VICTIMSTATE_HIT;
damageInfo->HitInfo |= HITINFO_BLOCK;
damageInfo->procEx |= PROC_EX_BLOCK;
@@ -1580,17 +1666,35 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
// double blocked amount if block is critical
if (damageInfo->target->isBlockCritical())
damageInfo->blocked_amount += damageInfo->blocked_amount;
if (damageInfo->blocked_amount >= damageInfo->damage)
uint32 remainingBlock = damageInfo->blocked_amount;
uint8 fullBlockMask = 0;
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
damageInfo->TargetState = VICTIMSTATE_BLOCKS;
damageInfo->blocked_amount = damageInfo->damage;
damageInfo->procEx |= PROC_EX_FULL_BLOCK;
if (remainingBlock && remainingBlock >= damageInfo->damages[i].damage)
{
fullBlockMask |= (1 << i);
remainingBlock -= damageInfo->damages[i].damage;
damageInfo->cleanDamage += damageInfo->damages[i].damage;
damageInfo->damages[i].damage = 0;
}
else
damageInfo->procEx |= PROC_EX_NORMAL_HIT;
damageInfo->damage -= damageInfo->blocked_amount;
damageInfo->cleanDamage += damageInfo->blocked_amount;
{
damageInfo->cleanDamage += remainingBlock;
damageInfo->damages[i].damage -= remainingBlock;
remainingBlock = 0;
}
}
// full block
if (fullBlockMask == ((1 << 0) | (1 << 1)))
{
damageInfo->TargetState = VICTIMSTATE_BLOCKS;
damageInfo->blocked_amount -= remainingBlock;
}
break;
}
case MELEE_HIT_GLANCING:
{
damageInfo->HitInfo |= HITINFO_GLANCING;
@@ -1600,16 +1704,25 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
if (leveldif > 3)
leveldif = 3;
float reducePercent = 1 - leveldif * 0.1f;
damageInfo->cleanDamage += damageInfo->damage - uint32(reducePercent * damageInfo->damage);
damageInfo->damage = uint32(reducePercent * damageInfo->damage);
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
uint32 reducedDamage = uint32(reducePercent * damageInfo->damages[i].damage);
damageInfo->cleanDamage += damageInfo->damages[i].damage - reducedDamage;
damageInfo->damages[i].damage = reducedDamage;
}
break;
}
case MELEE_HIT_CRUSHING:
damageInfo->HitInfo |= HITINFO_CRUSHING;
damageInfo->TargetState = VICTIMSTATE_HIT;
damageInfo->procEx |= PROC_EX_NORMAL_HIT;
// 150% normal damage
damageInfo->damage += (damageInfo->damage / 2);
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
damageInfo->damages[i].damage += (damageInfo->damages[i].damage / 2);
}
break;
default:
break;
@@ -1619,43 +1732,70 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
if (!(damageInfo->HitInfo & HITINFO_MISS))
damageInfo->HitInfo |= HITINFO_AFFECTS_VICTIM;
// attackType is checked already for BASE_ATTACK or OFF_ATTACK so it can't be RANGED_ATTACK here
int32 dmg = damageInfo->damage;
uint32 tmpHitInfo[MAX_ITEM_PROTO_DAMAGES] = { };
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
int32 dmg = damageInfo->damages[i].damage;
int32 cleanDamage = damageInfo->cleanDamage;
// attackType is checked already for BASE_ATTACK or OFF_ATTACK so it can't be RANGED_ATTACK here
if (CanApplyResilience())
{
int32 resilienceReduction = dmg;
int32 resilienceReduction = damageInfo->damages[i].damage;
Unit::ApplyResilience(victim, nullptr, &resilienceReduction, (damageInfo->hitOutCome == MELEE_HIT_CRIT), CR_CRIT_TAKEN_MELEE);
resilienceReduction = dmg - resilienceReduction;
resilienceReduction = damageInfo->damages[i].damage - resilienceReduction;
dmg -= resilienceReduction;
cleanDamage += resilienceReduction;
}
damageInfo->damage = std::max(0, dmg);
damageInfo->damages[i].damage = std::max(0, dmg);
damageInfo->cleanDamage = std::max(0, cleanDamage);
// Calculate absorb resist
if (damageInfo->damage > 0)
if (damageInfo->damages[i].damage > 0)
{
damageInfo->procVictim |= PROC_FLAG_TAKEN_DAMAGE;
// Calculate absorb & resists
DamageInfo dmgInfo(*damageInfo);
DamageInfo dmgInfo(*damageInfo, i);
Unit::CalcAbsorbResist(dmgInfo);
damageInfo->absorb = dmgInfo.GetAbsorb();
damageInfo->resist = dmgInfo.GetResist();
damageInfo->damages[i].absorb = dmgInfo.GetAbsorb();
damageInfo->damages[i].resist = dmgInfo.GetResist();
if (damageInfo->absorb)
if (damageInfo->damages[i].absorb)
{
damageInfo->HitInfo |= (damageInfo->damage - damageInfo->absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB);
damageInfo->procEx |= PROC_EX_ABSORB;
tmpHitInfo[i] |= (damageInfo->damages[i].damage - damageInfo->damages[i].absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB);
}
if (damageInfo->resist)
damageInfo->HitInfo |= (damageInfo->damage - damageInfo->resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST);
if (damageInfo->damages[i].resist)
{
tmpHitInfo[i] |= (damageInfo->damages[i].damage - damageInfo->damages[i].resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST);
}
damageInfo->damage = dmgInfo.GetDamage();
damageInfo->damages[i].damage = dmgInfo.GetDamage();
}
}
// set proper HitInfo flags
if ((tmpHitInfo[0] & HITINFO_FULL_ABSORB) != 0)
{
// set partial absorb when secondary damage isn't full absorbed
damageInfo->HitInfo |= ((tmpHitInfo[1] & HITINFO_PARTIAL_ABSORB) != 0) ? HITINFO_PARTIAL_ABSORB : HITINFO_FULL_ABSORB;
}
else
{
damageInfo->HitInfo |= (tmpHitInfo[0] & HITINFO_PARTIAL_ABSORB);
}
if ((tmpHitInfo[0] & HITINFO_FULL_RESIST) != 0)
{
// set partial resist when secondary damage isn't full resisted
damageInfo->HitInfo |= ((tmpHitInfo[1] & HITINFO_PARTIAL_RESIST) != 0) ? HITINFO_PARTIAL_RESIST : HITINFO_FULL_RESIST;
}
else
{
damageInfo->HitInfo |= (tmpHitInfo[0] & HITINFO_PARTIAL_RESIST);
}
}
@@ -1663,8 +1803,15 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
{
Unit* victim = damageInfo->target;
if (!victim->IsAlive() || victim->IsInFlight() || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
auto canTakeMeleeDamage = [&]()
{
return victim->IsAlive() && !victim->HasUnitState(UNIT_STATE_IN_FLIGHT) && (victim->GetTypeId() != TYPEID_UNIT || !victim->ToCreature()->IsEvadingAttacks());
};
if (!canTakeMeleeDamage())
{
return;
}
// Hmmmm dont like this emotes client must by self do all animations
if (damageInfo->HitInfo & HITINFO_CRITICALHIT)
@@ -1704,12 +1851,20 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
}
}
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
if (!canTakeMeleeDamage() || (!damageInfo->damages[i].damage && !damageInfo->damages[i].absorb && !damageInfo->damages[i].resist))
{
continue;
}
// Call default DealDamage
CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->absorb, damageInfo->attackType, damageInfo->hitOutCome);
Unit::DealDamage(this, victim, damageInfo->damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->damageSchoolMask), nullptr, durabilityLoss);
CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->damages[i].absorb, damageInfo->attackType, damageInfo->hitOutCome);
Unit::DealDamage(this, victim, damageInfo->damages[i].damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->damages[i].damageSchoolMask), nullptr, durabilityLoss);
}
// If this is a creature and it attacks from behind it has a probability to daze it's victim
if (damageInfo->damage && ((damageInfo->hitOutCome == MELEE_HIT_CRIT || damageInfo->hitOutCome == MELEE_HIT_CRUSHING || damageInfo->hitOutCome == MELEE_HIT_NORMAL || damageInfo->hitOutCome == MELEE_HIT_GLANCING) &&
if ((damageInfo->damages[0].damage + damageInfo->damages[1].damage) && ((damageInfo->hitOutCome == MELEE_HIT_CRIT || damageInfo->hitOutCome == MELEE_HIT_CRUSHING || damageInfo->hitOutCome == MELEE_HIT_NORMAL || damageInfo->hitOutCome == MELEE_HIT_GLANCING) &&
GetTypeId() != TYPEID_PLAYER && !ToCreature()->IsControlledByPlayer() && !victim->HasInArc(M_PI, this)
&& (victim->GetTypeId() == TYPEID_PLAYER || !victim->ToCreature()->isWorldBoss()) && !victim->IsVehicle()))
{
@@ -1738,7 +1893,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
ToPlayer()->CastItemCombatSpell(victim, damageInfo->attackType, damageInfo->procVictim, damageInfo->procEx);
// Do effect if any damage done to target
if (damageInfo->damage)
if (damageInfo->damages[0].damage + damageInfo->damages[1].damage)
{
// We're going to call functions which can modify content of the list during iteration over it's elements
// Let's copy the list so we can prevent iterator invalidation
@@ -1826,7 +1981,6 @@ bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* s
uint32 Unit::CalcArmorReducedDamage(Unit const* attacker, Unit const* victim, const uint32 damage, SpellInfo const* spellInfo, uint8 attackerLevel, WeaponAttackType /*attackType*/)
{
uint32 newdamage = 0;
float armor = float(victim->GetArmor());
// Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
@@ -1904,9 +2058,7 @@ uint32 Unit::CalcArmorReducedDamage(Unit const* attacker, Unit const* victim, co
if (tmpvalue > 0.75f)
tmpvalue = 0.75f;
newdamage = uint32(damage - (damage * tmpvalue));
return (newdamage > 1) ? newdamage : 1;
return uint32(std::ceil(std::max(damage * (1.0f - tmpvalue), 0.0f)));
}
float Unit::GetEffectiveResistChance(Unit const* owner, SpellSchoolMask schoolMask, Unit const* victim)
@@ -2414,10 +2566,14 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType /*= BASE_A
// attack can be redirected to another target
victim = GetMeleeHitRedirectTarget(victim);
CalcDamageInfo damageInfo;
CalculateMeleeDamage(victim, 0, &damageInfo, attType, sittingVictim);
CalculateMeleeDamage(victim, &damageInfo, attType, sittingVictim);
// Send log damage message to client
Unit::DealDamageMods(victim, damageInfo.damage, &damageInfo.absorb);
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
Unit::DealDamageMods(victim, damageInfo.damages[i].damage, &damageInfo.damages[i].absorb);
}
SendAttackStateUpdate(&damageInfo);
//TriggerAurasProcOnEvent(damageInfo);
@@ -2427,15 +2583,15 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType /*= BASE_A
DealMeleeDamage(&damageInfo, true);
DamageInfo dmgInfo(damageInfo);
Unit::ProcDamageAndSpell(damageInfo.attacker, damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage,
Unit::ProcDamageAndSpell(damageInfo.attacker, damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, dmgInfo.GetDamage(),
damageInfo.attackType, nullptr, nullptr, -1, nullptr, &dmgInfo);
if (GetTypeId() == TYPEID_PLAYER)
LOG_DEBUG("entities.unit", "AttackerStateUpdate: (Player) {} attacked {} for {} dmg, absorbed {}, blocked {}, resisted {}.",
GetGUID().ToString(), victim->GetGUID().ToString(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist);
GetGUID().ToString(), victim->GetGUID().ToString(), dmgInfo.GetDamage(), dmgInfo.GetAbsorb(), dmgInfo.GetBlock(), dmgInfo.GetResist());
else
LOG_DEBUG("entities.unit", "AttackerStateUpdate: (NPC) {} attacked {} for {} dmg, absorbed {}, blocked {}, resisted {}.",
GetGUID().ToString(), victim->GetGUID().ToString(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist);
GetGUID().ToString(), victim->GetGUID().ToString(), dmgInfo.GetDamage(), dmgInfo.GetAbsorb(), dmgInfo.GetBlock(), dmgInfo.GetResist());
// Let the pet know we've started attacking someting. Handles melee attacks only
// Spells such as auto-shot and others handled in WorldSession::HandleCastSpellOpcode
@@ -2764,13 +2920,30 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(Unit const* victim, WeaponAttackTy
return MELEE_HIT_NORMAL;
}
uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct)
uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, uint8 itemDamagesMask /*= 0*/)
{
float minDamage = 0.0f;
float maxDamage = 0.0f;
if (normalized || !addTotalPct)
CalculateMinMaxDamage(attType, normalized, addTotalPct, minDamage, maxDamage);
if (normalized || !addTotalPct || itemDamagesMask)
{
// get both by default
if (!itemDamagesMask)
{
itemDamagesMask = (1 << 0) | (1 << 1);
}
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
if (itemDamagesMask & (1 << i))
{
float minTmp, maxTmp;
CalculateMinMaxDamage(attType, normalized, addTotalPct, minTmp, maxTmp, i);
minDamage += minTmp;
maxDamage += maxTmp;
}
}
}
else
{
switch (attType)
@@ -2790,14 +2963,15 @@ uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool add
default:
break;
}
// pussywizard: this check only in "else" section, proper check is also in CalculateMinMaxDamage
if (minDamage > maxDamage)
minDamage = maxDamage;
}
if (maxDamage == 0.0f)
maxDamage = 5.0f;
minDamage = std::max(0.f, minDamage);
maxDamage = std::max(0.f, maxDamage);
if (minDamage > maxDamage)
{
std::swap(minDamage, maxDamage);
}
return urand(uint32(minDamage), uint32(maxDamage));
}
@@ -3290,6 +3464,96 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spell, bool Ca
return SPELL_MISS_NONE;
}
SpellMissInfo Unit::SpellHitResult(Unit* victim, Spell const* spell, bool CanReflect)
{
SpellInfo const* spellInfo = spell->GetSpellInfo();
// Check for immune
if (victim->IsImmunedToSpell(spellInfo, spell))
{
return SPELL_MISS_IMMUNE;
}
// All positive spells can`t miss
// TODO: client not show miss log for this spells - so need find info for this in dbc and use it!
if ((spellInfo->IsPositive() || spellInfo->HasEffect(SPELL_EFFECT_DISPEL))
&& (!IsHostileTo(victim))) // prevent from affecting enemy by "positive" spell
{
return SPELL_MISS_NONE;
}
// Check for immune
// xinef: check for school immunity only
if (victim->IsImmunedToSchool(spell))
{
return SPELL_MISS_IMMUNE;
}
if (this == victim)
{
return SPELL_MISS_NONE;
}
// Return evade for units in evade mode
if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks() && !spellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE) &&
!spellInfo->HasAttribute(SPELL_ATTR0_CU_IGNORE_EVADE))
{
return SPELL_MISS_EVADE;
}
// Try victim reflect spell
if (CanReflect)
{
int32 reflectchance = victim->GetTotalAuraModifier(SPELL_AURA_REFLECT_SPELLS);
Unit::AuraEffectList const& mReflectSpellsSchool = victim->GetAuraEffectsByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL);
for (Unit::AuraEffectList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i)
{
if ((*i)->GetMiscValue() & spell->GetSpellSchoolMask())
{
reflectchance += (*i)->GetAmount();
}
}
if (reflectchance > 0 && roll_chance_i(reflectchance))
{
// Start triggers for remove charges if need (trigger only for victim, and mark as active spell)
//ProcDamageAndSpell(victim, PROC_FLAG_NONE, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_EX_REFLECT, 1, BASE_ATTACK, spell);
return SPELL_MISS_REFLECT;
}
}
switch (spellInfo->DmgClass)
{
case SPELL_DAMAGE_CLASS_RANGED:
case SPELL_DAMAGE_CLASS_MELEE:
return MeleeSpellHitResult(victim, spellInfo);
case SPELL_DAMAGE_CLASS_NONE:
{
if (spellInfo->SpellFamilyName)
{
return SPELL_MISS_NONE;
}
// Xinef: apply DAMAGE_CLASS_MAGIC conditions to damaging DAMAGE_CLASS_NONE spells
for (uint8 i = EFFECT_0; i < MAX_SPELL_EFFECTS; ++i)
{
if (spellInfo->Effects[i].Effect && spellInfo->Effects[i].Effect != SPELL_EFFECT_SCHOOL_DAMAGE)
{
if (spellInfo->Effects[i].ApplyAuraName != SPELL_AURA_PERIODIC_DAMAGE)
{
return SPELL_MISS_NONE;
}
}
}
[[fallthrough]];
}
case SPELL_DAMAGE_CLASS_MAGIC:
return MagicSpellHitResult(victim, spellInfo);
}
return SPELL_MISS_NONE;
}
uint32 Unit::GetDefenseSkillValue(Unit const* target) const
{
if (GetTypeId() == TYPEID_PLAYER)
@@ -6078,43 +6342,57 @@ void Unit::SendAttackStateUpdate(CalcDamageInfo* damageInfo)
{
LOG_DEBUG("entities.unit", "WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
uint32 tmpDamage[MAX_ITEM_PROTO_DAMAGES] = { };
uint32 tmpAbsorb[MAX_ITEM_PROTO_DAMAGES] = { };
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
//IF we are in cheat mode we swap absorb with damage and set damage to 0, this way we can still debug damage but our hp bar will not drop
uint32 damage = damageInfo->damage;
uint32 absorb = damageInfo->absorb;
tmpDamage[i] = damageInfo->damages[i].damage;
tmpAbsorb[i] = damageInfo->damages[i].absorb;
if (damageInfo->target->GetTypeId() == TYPEID_PLAYER && damageInfo->target->ToPlayer()->GetCommandStatus(CHEAT_GOD))
{
absorb = damage;
damage = 0;
tmpAbsorb[i] = tmpDamage[i];
tmpDamage[i] = 0;
}
}
uint32 count = 1;
size_t maxsize = 4 + 5 + 5 + 4 + 4 + 1 + 4 + 4 + 4 + 4 + 4 + 1 + 4 + 4 + 4 + 4 + 4 * 12;
if (tmpDamage[1] || tmpAbsorb[1] || damageInfo->damages[1].resist)
{
++count;
}
size_t const maxsize = 4 + 5 + 5 + 4 + 4 + 1 + count * (4 + 4 + 4 + 4 + 4) + 1 + 4 + 4 + 4 + 4 + 4 * 12;
WorldPacket data(SMSG_ATTACKERSTATEUPDATE, maxsize); // we guess size
data << uint32(damageInfo->HitInfo);
data << damageInfo->attacker->GetPackGUID();
data << damageInfo->target->GetPackGUID();
data << uint32(damage); // Full damage
int32 overkill = damage - damageInfo->target->GetHealth();
data << uint32(tmpDamage[0] + tmpDamage[1]); // Full damage
int32 overkill = tmpDamage[0] + tmpDamage[1] - damageInfo->target->GetHealth();
data << uint32(overkill < 0 ? 0 : overkill); // Overkill
data << uint8(count); // Sub damage count
for (uint32 i = 0; i < count; ++i)
{
data << uint32(damageInfo->damageSchoolMask); // School of sub damage
data << float(damage); // sub damage
data << uint32(damage); // Sub Damage
data << uint32(damageInfo->damages[i].damageSchoolMask); // School of sub damage
data << float(tmpDamage[i]); // sub damage
data << uint32(tmpDamage[i]); // Sub Damage
}
if (damageInfo->HitInfo & (HITINFO_FULL_ABSORB | HITINFO_PARTIAL_ABSORB))
{
for (uint32 i = 0; i < count; ++i)
data << uint32(absorb); // Absorb
{
data << uint32(tmpAbsorb[i]); // Absorb
}
}
if (damageInfo->HitInfo & (HITINFO_FULL_RESIST | HITINFO_PARTIAL_RESIST))
{
for (uint32 i = 0; i < count; ++i)
data << uint32(damageInfo->resist); // Resist
{
data << uint32(damageInfo->damages[i].resist); // Resist
}
}
data << uint8(damageInfo->TargetState);
@@ -6153,10 +6431,17 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType
dmgInfo.HitInfo = HitInfo;
dmgInfo.attacker = this;
dmgInfo.target = target;
dmgInfo.damage = Damage - AbsorbDamage - Resist - BlockedAmount;
dmgInfo.damageSchoolMask = damageSchoolMask;
dmgInfo.absorb = AbsorbDamage;
dmgInfo.resist = Resist;
dmgInfo.damages[0].damage = Damage - AbsorbDamage - Resist - BlockedAmount;
dmgInfo.damages[0].damageSchoolMask = damageSchoolMask;
dmgInfo.damages[0].absorb = AbsorbDamage;
dmgInfo.damages[0].resist = Resist;
dmgInfo.damages[1].damage = 0;
dmgInfo.damages[1].damageSchoolMask = 0;
dmgInfo.damages[1].absorb = 0;
dmgInfo.damages[1].resist = 0;
dmgInfo.TargetState = TargetState;
dmgInfo.blocked_amount = BlockedAmount;
SendAttackStateUpdate(&dmgInfo);
@@ -12327,6 +12612,11 @@ int32 Unit::SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask)
bool Unit::IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const
{
if (meleeSchoolMask == SPELL_SCHOOL_MASK_NONE)
{
return false;
}
// If m_immuneToDamage type contain magic, IMMUNE damage.
SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
@@ -12354,6 +12644,11 @@ bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) const
}
uint32 schoolMask = spellInfo->GetSchoolMask();
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
{
return false;
}
// If m_immuneToDamage type contain magic, IMMUNE damage.
SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
@@ -12363,8 +12658,50 @@ bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) const
return false;
}
bool Unit::IsImmunedToDamage(Spell const* spell) const
{
SpellInfo const* spellInfo = spell->GetSpellInfo();
if (!spellInfo)
{
return false;
}
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) && !HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
{
return false;
}
if (spellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) || spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
{
return false;
}
uint32 schoolMask = spell->GetSpellSchoolMask();
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
{
return false;
}
// If m_immuneToDamage type contain magic, IMMUNE damage.
SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
{
if ((itr->type & schoolMask) == schoolMask)
{
return true;
}
}
return false;
}
bool Unit::IsImmunedToSchool(SpellSchoolMask meleeSchoolMask) const
{
if (meleeSchoolMask == SPELL_SCHOOL_MASK_NONE)
{
return false;
}
// If m_immuneToSchool type contain this school type, IMMUNE damage.
SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
@@ -12380,6 +12717,11 @@ bool Unit::IsImmunedToSchool(SpellInfo const* spellInfo) const
return false;
uint32 schoolMask = spellInfo->GetSchoolMask();
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
{
return false;
}
if (spellInfo->Id != 42292 && spellInfo->Id != 59752 && spellInfo->Id != 19574 && spellInfo->Id != 34471)
{
// If m_immuneToSchool type contain this school type, IMMUNE damage.
@@ -12392,8 +12734,43 @@ bool Unit::IsImmunedToSchool(SpellInfo const* spellInfo) const
return false;
}
bool Unit::IsImmunedToSchool(Spell const* spell) const
{
SpellInfo const* spellInfo = spell->GetSpellInfo();
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) && !HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
{
return false;
}
uint32 schoolMask = spell->GetSpellSchoolMask();
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
{
return false;
}
if (spellInfo->Id != 42292 && spellInfo->Id != 59752 && spellInfo->Id != 19574 && spellInfo->Id != 34471)
{
// If m_immuneToSchool type contain this school type, IMMUNE damage.
SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
{
if ((itr->type & schoolMask) == schoolMask && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->spellId)))
{
return true;
}
}
}
return false;
}
bool Unit::IsImmunedToDamageOrSchool(SpellSchoolMask meleeSchoolMask) const
{
if (meleeSchoolMask == SPELL_SCHOOL_MASK_NONE)
{
return false;
}
return IsImmunedToDamage(meleeSchoolMask) || IsImmunedToSchool(meleeSchoolMask);
}
@@ -12402,7 +12779,7 @@ bool Unit::IsImmunedToDamageOrSchool(SpellInfo const* spellInfo) const
return IsImmunedToDamage(spellInfo) || IsImmunedToSchool(spellInfo);
}
bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo)
bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
{
if (!spellInfo)
return false;
@@ -12466,17 +12843,28 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo)
return true;
if (spellInfo->Id != 42292 && spellInfo->Id != 59752 && spellInfo->Id != 19574 && spellInfo->Id != 34471)
{
SpellSchoolMask spellSchoolMask = spellInfo->GetSchoolMask();
if (spell)
{
spellSchoolMask = spell->GetSpellSchoolMask();
}
if (spellSchoolMask != SPELL_SCHOOL_MASK_NONE)
{
SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
{
SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->spellId);
if (((itr->type & spellInfo->GetSchoolMask()) == spellInfo->GetSchoolMask())
if (((itr->type & spellSchoolMask) == spellSchoolMask)
&& (!immuneSpellInfo || immuneSpellInfo->IsPositive()) && !spellInfo->IsPositive()
&& !spellInfo->CanPierceImmuneAura(immuneSpellInfo))
{
return true;
}
}
}
}
return false;
}
@@ -12549,7 +12937,7 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) cons
return false;
}
uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType attType, SpellInfo const* spellProto)
uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType attType, SpellInfo const* spellProto, SpellSchoolMask damageSchoolMask /*= SPELL_SCHOOL_MASK_NORMAL*/)
{
if (!victim || pdamage == 0)
return 0;
@@ -12560,7 +12948,7 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType
if (GetEntry() == 27893)
{
if (Unit* owner = GetOwner())
return owner->MeleeDamageBonusDone(victim, pdamage, attType, spellProto) / 2;
return owner->MeleeDamageBonusDone(victim, pdamage, attType, spellProto, damageSchoolMask) / 2;
}
}
@@ -12618,19 +13006,17 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType
// Done total percent damage auras
float DoneTotalMod = 1.0f;
// Some spells don't benefit from pct done mods
if (spellProto)
// mods for SPELL_SCHOOL_MASK_NORMAL are already factored in base melee damage calculation
if (!(damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL))
{
// Some spells don't benefit from pct done mods
AuraEffectList const& mModDamagePercentDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
for (AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
{
if (!spellProto->ValidateAttribute6SpellDamageMods(this, *i, false))
continue;
if (!sScriptMgr->IsNeedModMeleeDamagePercent(this, *i, DoneTotalMod, spellProto))
continue;
if (((*i)->GetMiscValue() & spellProto->GetSchoolMask()) && !((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
if (!spellProto || (spellProto->ValidateAttribute6SpellDamageMods(this, *i, false) &&
sScriptMgr->IsNeedModMeleeDamagePercent(this, *i, DoneTotalMod, spellProto)))
{
if (((*i)->GetMiscValue() & damageSchoolMask))
{
if ((*i)->GetSpellInfo()->EquippedItemClass == -1)
AddPct(DoneTotalMod, (*i)->GetAmount());
@@ -12641,6 +13027,7 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType
}
}
}
}
AuraEffectList const& mDamageDoneVersus = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS);
for (AuraEffectList::const_iterator i = mDamageDoneVersus.begin(); i != mDamageDoneVersus.end(); ++i)
@@ -12752,7 +13139,7 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType
return uint32(std::max(tmpDamage, 0.0f));
}
uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackType attType, SpellInfo const* spellProto)
uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackType attType, SpellInfo const* spellProto/*= nullptr*/, SpellSchoolMask damageSchoolMask /*= SPELL_SCHOOL_MASK_NORMAL*/)
{
if (pdamage == 0)
return 0;
@@ -12762,7 +13149,7 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT
// ..taken
AuraEffectList const& mDamageTaken = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
for (AuraEffectList::const_iterator i = mDamageTaken.begin(); i != mDamageTaken.end(); ++i)
if ((*i)->GetMiscValue() & (spellProto ? spellProto->GetSchoolMask() : attacker->GetMeleeDamageSchoolMask()))
if ((*i)->GetMiscValue() & damageSchoolMask)
TakenFlatBenefit += (*i)->GetAmount();
if (attType != RANGED_ATTACK)
@@ -12773,7 +13160,7 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT
// Taken total percent damage auras
float TakenTotalMod = 1.0f;
TakenTotalMod *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, spellProto ? spellProto->GetSchoolMask() : attacker->GetMeleeDamageSchoolMask());
TakenTotalMod *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, damageSchoolMask);
// .. taken pct (special attacks)
if (spellProto)
@@ -12839,7 +13226,7 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT
bool addModifier = false;
AuraEffectList const& ResIgnoreAuras = attacker->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
for (AuraEffectList::const_iterator j = ResIgnoreAuras.begin(); j != ResIgnoreAuras.end(); ++j)
if ((*j)->GetMiscValue() & (spellProto ? spellProto->GetSchoolMask() : SPELL_SCHOOL_MASK_NORMAL))
if ((*j)->GetMiscValue() & damageSchoolMask)
{
ApplyPct(ignoreModifier, (*j)->GetAmount());
addModifier = true;
@@ -14881,12 +15268,12 @@ float Unit::GetTotalAttackPowerValue(WeaponAttackType attType, Unit* victim) con
}
}
float Unit::GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type) const
float Unit::GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type, uint8 damageIndex /*= 0*/) const
{
if (attType == OFF_ATTACK && !haveOffhandWeapon())
return 0.0f;
return m_weaponDamage[attType][type];
return m_weaponDamage[attType][type][damageIndex];
}
void Unit::SetLevel(uint8 lvl, bool showLevelChange)
@@ -16253,11 +16640,6 @@ void Unit::TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, std::list<AuraAppli
}
}
SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const
{
return SPELL_SCHOOL_MASK_NORMAL;
}
Player* Unit::GetSpellModOwner() const
{
if (Player* player = const_cast<Unit*>(this)->ToPlayer())
+34 -18
View File
@@ -23,6 +23,7 @@
#include "FollowerRefMgr.h"
#include "FollowerReference.h"
#include "HostileRefMgr.h"
#include "ItemTemplate.h"
#include "MotionMaster.h"
#include "Object.h"
#include "Optional.h"
@@ -251,7 +252,9 @@ enum UnitModifierType
enum WeaponDamageRange
{
MINDAMAGE,
MAXDAMAGE
MAXDAMAGE,
MAX_WEAPON_DAMAGE_RANGE
};
enum UnitMods
@@ -762,9 +765,14 @@ private:
uint32 m_resist;
uint32 m_block;
uint32 m_cleanDamage;
// amalgamation constructor (used for proc)
DamageInfo(DamageInfo const& dmg1, DamageInfo const& dmg2);
public:
explicit DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellInfo const* _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType, uint32 cleanDamage = 0);
explicit DamageInfo(CalcDamageInfo& dmgInfo);
explicit DamageInfo(CalcDamageInfo const& dmgInfo); // amalgamation wrapper
DamageInfo(CalcDamageInfo const& dmgInfo, uint8 damageIndex);
DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType);
void ModifyDamage(int32 amount);
@@ -868,10 +876,15 @@ struct CalcDamageInfo
{
Unit* attacker; // Attacker
Unit* target; // Target for damage
struct
{
uint32 damageSchoolMask;
uint32 damage;
uint32 absorb;
uint32 resist;
} damages[MAX_ITEM_PROTO_DAMAGES];
uint32 blocked_amount;
uint32 HitInfo;
uint32 TargetState;
@@ -1331,7 +1344,7 @@ public:
bool IsWithinCombatRange(Unit const* obj, float dist2compare) const;
bool IsWithinMeleeRange(Unit const* obj, float dist = 0.f) const;
float GetMeleeRange(Unit const* target) const;
[[nodiscard]] virtual SpellSchoolMask GetMeleeDamageSchoolMask() const;
virtual SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType = BASE_ATTACK, uint8 damageIndex = 0) const = 0;
bool GetRandomContactPoint(Unit const* target, float& x, float& y, float& z, bool force = false) const;
uint32 m_extraAttacks;
bool m_canDualWield;
@@ -1540,7 +1553,7 @@ public:
void HandleEmoteCommand(uint32 emoteId);
void AttackerStateUpdate (Unit* victim, WeaponAttackType attType = BASE_ATTACK, bool extra = false, bool ignoreCasting = false);
void CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK, const bool sittingVictim = false);
void CalculateMeleeDamage(Unit* victim, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK, const bool sittingVictim = false);
void DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss);
void HandleProcExtraAttackFor(Unit* victim, uint32 count);
@@ -1570,10 +1583,11 @@ public:
static void ApplyResilience(Unit const* victim, float* crit, int32* damage, bool isCrit, CombatRating type);
float MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const;
SpellMissInfo MeleeSpellHitResult(Unit* victim, SpellInfo const* spell);
SpellMissInfo MagicSpellHitResult(Unit* victim, SpellInfo const* spell);
SpellMissInfo SpellHitResult(Unit* victim, SpellInfo const* spell, bool canReflect = false);
[[nodiscard]] float MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const;
[[nodiscard]] SpellMissInfo MeleeSpellHitResult(Unit* victim, SpellInfo const* spell);
[[nodiscard]] SpellMissInfo MagicSpellHitResult(Unit* victim, SpellInfo const* spell);
[[nodiscard]] SpellMissInfo SpellHitResult(Unit* victim, SpellInfo const* spell, bool canReflect = false);
[[nodiscard]] SpellMissInfo SpellHitResult(Unit* victim, Spell const* spell, bool canReflect = false);
[[nodiscard]] float GetUnitDodgeChance() const;
[[nodiscard]] float GetUnitParryChance() const;
@@ -2091,10 +2105,10 @@ public:
virtual void UpdateAttackPowerAndDamage(bool ranged = false) = 0;
virtual void UpdateDamagePhysical(WeaponAttackType attType);
float GetTotalAttackPowerValue(WeaponAttackType attType, Unit* pVictim = nullptr) const;
[[nodiscard]] float GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type) const;
void SetBaseWeaponDamage(WeaponAttackType attType, WeaponDamageRange damageRange, float value) { m_weaponDamage[attType][damageRange] = value; }
virtual void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) = 0;
uint32 CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct);
[[nodiscard]] float GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type, uint8 damageIndex = 0) const;
void SetBaseWeaponDamage(WeaponAttackType attType, WeaponDamageRange damageRange, float value, uint8 damageIndex = 0) { m_weaponDamage[attType][damageRange][damageIndex] = value; }
virtual void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex = 0) = 0;
uint32 CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, uint8 itemDamagesMask = 0);
float GetAPMultiplier(WeaponAttackType attType, bool normalized);
bool isInFrontInMap(Unit const* target, float distance, float arc = M_PI) const;
@@ -2179,8 +2193,8 @@ public:
uint32 SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint8 effIndex, float TotalMod = 0.0f, uint32 stack = 1);
uint32 SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1);
uint32 MeleeDamageBonusDone(Unit* pVictim, uint32 damage, WeaponAttackType attType, SpellInfo const* spellProto = nullptr);
uint32 MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackType attType, SpellInfo const* spellProto = nullptr);
uint32 MeleeDamageBonusDone(Unit* pVictim, uint32 damage, WeaponAttackType attType, SpellInfo const* spellProto = nullptr, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL);
uint32 MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackType attType, SpellInfo const* spellProto = nullptr, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL);
bool isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttackType attackType = BASE_ATTACK);
bool isBlockCritical();
@@ -2201,12 +2215,14 @@ public:
void ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply, SpellImmuneBlockType blockType = SPELL_BLOCK_TYPE_ALL);
void ApplySpellDispelImmunity(SpellInfo const* spellProto, DispelType type, bool apply);
virtual bool IsImmunedToSpell(SpellInfo const* spellInfo);
virtual bool IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell = nullptr);
// redefined in Creature
[[nodiscard]] bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const;
bool IsImmunedToDamage(SpellInfo const* spellInfo) const;
[[nodiscard]] bool IsImmunedToDamage(SpellInfo const* spellInfo) const;
[[nodiscard]] bool IsImmunedToDamage(Spell const* spell) const;
[[nodiscard]] bool IsImmunedToSchool(SpellSchoolMask meleeSchoolMask) const;
bool IsImmunedToSchool(SpellInfo const* spellInfo) const;
[[nodiscard]] bool IsImmunedToSchool(SpellInfo const* spellInfo) const;
[[nodiscard]] bool IsImmunedToSchool(Spell const* spell) const;
[[nodiscard]] bool IsImmunedToDamageOrSchool(SpellSchoolMask meleeSchoolMask) const;
bool IsImmunedToDamageOrSchool(SpellInfo const* spellInfo) const;
virtual bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const;
@@ -2484,7 +2500,7 @@ protected:
uint32 m_interruptMask;
float m_auraModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_END];
float m_weaponDamage[MAX_ATTACK][2];
float m_weaponDamage[MAX_ATTACK][MAX_WEAPON_DAMAGE_RANGE][MAX_ITEM_PROTO_DAMAGES];
bool m_canModifyStats;
VisibleAuraMap m_visibleAuras;
+7 -3
View File
@@ -2428,10 +2428,12 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
// Calculate hit result
if (m_originalCaster)
{
targetInfo.missCondition = m_originalCaster->SpellHitResult(target, m_spellInfo, m_canReflect);
targetInfo.missCondition = m_originalCaster->SpellHitResult(target, this, m_canReflect);
if (m_skipCheck && targetInfo.missCondition != SPELL_MISS_IMMUNE)
{
targetInfo.missCondition = SPELL_MISS_NONE;
}
}
else
targetInfo.missCondition = SPELL_MISS_EVADE; //SPELL_MISS_NONE;
@@ -2458,7 +2460,7 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
if (targetInfo.missCondition == SPELL_MISS_REFLECT)
{
// Calculate reflected spell result on caster
targetInfo.reflectResult = m_caster->SpellHitResult(m_caster, m_spellInfo, m_canReflect);
targetInfo.reflectResult = m_caster->SpellHitResult(m_caster, this, m_canReflect);
if (targetInfo.reflectResult == SPELL_MISS_REFLECT) // Impossible reflect again, so simply deflect spell
targetInfo.reflectResult = SPELL_MISS_PARRY;
@@ -2971,8 +2973,10 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
return SPELL_MISS_EVADE;
// For delayed spells immunity may be applied between missile launch and hit - check immunity for that case
if (m_spellInfo->Speed && ((m_damage > 0 && unit->IsImmunedToDamage(m_spellInfo)) || unit->IsImmunedToSchool(m_spellInfo) || unit->IsImmunedToSpell(m_spellInfo)))
if (m_spellInfo->Speed && ((m_damage > 0 && unit->IsImmunedToDamage(this)) || unit->IsImmunedToSchool(this) || unit->IsImmunedToSpell(m_spellInfo, this)))
{
return SPELL_MISS_IMMUNE;
}
// disable effects to which unit is immune
SpellMissInfo returnVal = SPELL_MISS_IMMUNE;
+2
View File
@@ -589,6 +589,8 @@ public:
[[nodiscard]] TriggerCastFlags GetTriggeredCastFlags() const { return _triggeredCastFlags; }
[[nodiscard]] SpellSchoolMask GetSpellSchoolMask() const { return m_spellSchoolMask; }
protected:
bool HasGlobalCooldown() const;
void TriggerGlobalCooldown();
+21 -7
View File
@@ -593,8 +593,14 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex)
if (Player* caster = m_caster->ToPlayer())
{
// Add Ammo and Weapon damage plus RAP * 0.1
float dmg_min = caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE);
float dmg_max = caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE);
float dmg_min = 0.f;
float dmg_max = 0.f;
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
dmg_min += caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE, i);
dmg_max += caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE, i);
}
if (dmg_max == 0.0f && dmg_min > dmg_max)
{
damage += int32(dmg_min);
@@ -616,9 +622,17 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex)
// Add main hand dps * effect[2] amount
if (Player* player = m_caster->ToPlayer())
{
float mindamage, maxdamage;
player->CalculateMinMaxDamage(BASE_ATTACK, false, false, mindamage, maxdamage);
float average = (mindamage + maxdamage) / 2;
float minTotal = 0.f;
float maxTotal = 0.f;
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
float tmpMin, tmpMax;
player->CalculateMinMaxDamage(BASE_ATTACK, false, false, tmpMin, tmpMax, i);
minTotal += tmpMin;
maxTotal += tmpMax;
}
float average = (minTotal + maxTotal) / 2;
int32 count = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, EFFECT_2);
damage += count * int32(average * IN_MILLISECONDS) / m_caster->GetAttackTime(BASE_ATTACK);
}
@@ -3644,8 +3658,8 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex)
uint32 eff_damage(std::max(weaponDamage, 0));
// Add melee damage bonuses (also check for negative)
eff_damage = m_caster->MeleeDamageBonusDone(unitTarget, eff_damage, m_attackType, m_spellInfo);
eff_damage = unitTarget->MeleeDamageBonusTaken(m_caster, eff_damage, m_attackType, m_spellInfo);
eff_damage = m_caster->MeleeDamageBonusDone(unitTarget, eff_damage, m_attackType, m_spellInfo, m_spellSchoolMask);
eff_damage = unitTarget->MeleeDamageBonusTaken(m_caster, eff_damage, m_attackType, m_spellInfo, m_spellSchoolMask);
// Meteor like spells (divided damage to targets)
if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_SHARE_DAMAGE))
@@ -15,6 +15,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
@@ -131,13 +132,25 @@ struct boss_viscidus : public BossAI
me->RemoveAurasDueToSpell(SPELL_INVIS_SELF);
}
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType effType, SpellSchoolMask) override
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType effType, SpellSchoolMask spellSchoolMask) override
{
if (me->HealthBelowPct(5))
damage = 0;
if (!attacker || _phase != PHASE_MELEE)
if (!attacker)
{
return;
}
if (_phase != PHASE_MELEE)
{
if (_phase == PHASE_FROST && effType == DIRECT_DAMAGE && (spellSchoolMask & SPELL_SCHOOL_MASK_FROST) != 0)
{
++_hitcounter;
}
return;
}
if (effType == DIRECT_DAMAGE)
++_hitcounter;
@@ -183,14 +196,23 @@ struct boss_viscidus : public BossAI
Talk(EMOTE_CRACK);
}
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
void SpellHit(Unit* caster, SpellInfo const* spellInfo) override
{
if (spell->Id == SPELL_REJOIN_VISCIDUS)
if (spellInfo->Id == SPELL_REJOIN_VISCIDUS)
{
me->RemoveAuraFromStack(SPELL_VISCIDUS_SHRINKS);
}
if ((spell->GetSchoolMask() & SPELL_SCHOOL_MASK_FROST) && _phase == PHASE_FROST)
SpellSchoolMask spellSchoolMask = spellInfo->GetSchoolMask();
if (spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON && spellInfo->EquippedItemSubClassMask & (1 << ITEM_SUBCLASS_WEAPON_WAND))
{
if (Item* pItem = caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK))
{
spellSchoolMask = SpellSchoolMask(1 << pItem->GetTemplate()->Damage[0].DamageType);
}
}
if ((spellSchoolMask & SPELL_SCHOOL_MASK_FROST) && _phase == PHASE_FROST)
{
++_hitcounter;
+6 -3
View File
@@ -648,10 +648,13 @@ class spell_dk_dancing_rune_weapon : public AuraScript
{
target = player->GetMeleeHitRedirectTarget(target);
CalcDamageInfo damageInfo;
player->CalculateMeleeDamage(target, 0, &damageInfo, eventInfo.GetDamageInfo()->GetAttackType());
Unit::DealDamageMods(target, damageInfo.damage, &damageInfo.absorb);
player->CalculateMeleeDamage(target, &damageInfo, eventInfo.GetDamageInfo()->GetAttackType());
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
Unit::DealDamageMods(target, damageInfo.damages[i].damage, &damageInfo.damages[i].absorb);
damageInfo.damages[i].damage /= 2.0f;
}
damageInfo.attacker = dancingRuneWeapon;
damageInfo.damage /= 2.0f;
dancingRuneWeapon->SendAttackStateUpdate(&damageInfo);
dancingRuneWeapon->DealMeleeDamage(&damageInfo, true);
}
+8 -2
View File
@@ -567,8 +567,14 @@ class spell_warr_rend : public AuraScript
// $0.2 * (($MWB + $mwb) / 2 + $AP / 14 * $MWS) bonus per tick
float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 mws = caster->GetAttackTime(BASE_ATTACK);
float mwbMin = caster->GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
float mwbMax = caster->GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
float mwbMin = 0.f;
float mwbMax = 0.f;
for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
mwbMin += caster->GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE, i);
mwbMax += caster->GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE, i);
}
float mwb = ((mwbMin + mwbMax) / 2 + ap * mws / 14000) * 0.2f;
amount += int32(caster->ApplyEffectModifiers(GetSpellInfo(), aurEff->GetEffIndex(), mwb));