diff options
author | ariel- <ariel-@users.noreply.github.com> | 2018-01-14 09:23:34 -0300 |
---|---|---|
committer | ariel- <ariel-@users.noreply.github.com> | 2018-01-14 09:23:34 -0300 |
commit | f1986c6aafdf2457902a7a4cc7acc903cbbdc7bb (patch) | |
tree | 16d186ec1f2ace71ab3611a06f3c7ff5fe346f18 /src | |
parent | 24cf532557b07dbcd90180dea098fa2c86576152 (diff) |
Core/Entities: implement secondary damage for some weapons and removal of old voodoo
- Fixed correct Retaliation damage spell according to sniffs is 20240
- CalcArmorReducedDamage insisted on dealing a minimum of 1 damage even if damage was 0
- CalculateDamage was zero-phobic too: it defaulted to arbitrary max 5 damage
Closes #19081
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Creature/Creature.h | 4 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 57 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 4 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/StatSystem.cpp | 57 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 477 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 58 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 27 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_misc.cpp | 2 | ||||
-rw-r--r-- | src/server/scripts/Spells/spell_pet.cpp | 3 | ||||
-rw-r--r-- | src/server/scripts/Spells/spell_warrior.cpp | 13 |
10 files changed, 445 insertions, 257 deletions
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 89cf8596042..f9c25399f02 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -145,7 +145,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma uint32 GetShieldBlockValue() const override; - SpellSchoolMask GetMeleeDamageSchoolMask() const override { return m_meleeDamageSchoolMask; } + SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType /*attackType*/ = BASE_ATTACK, uint8 /*damageIndex*/ = 0) const override { return m_meleeDamageSchoolMask; } void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = SpellSchoolMask(1 << school); } bool HasSpell(uint32 spellID) const override; @@ -161,7 +161,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma 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) const override; + void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex) const override; void SetCanDualWield(bool value) override; int8 GetOriginalEquipmentId() const { return m_originalEquipmentId; } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index e70f8d626cc..7fc57c2f305 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -7562,7 +7562,6 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply 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) { @@ -7583,7 +7582,6 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingStatValuesEntry const* ssv, bool apply) { WeaponAttackType attType = BASE_ATTACK; - float damage = 0.0f; if (slot == EQUIPMENT_SLOT_RANGED && ( proto->InventoryType == INVTYPE_RANGED || proto->InventoryType == INVTYPE_THROWN || @@ -7596,31 +7594,40 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingSt attType = OFF_ATTACK; } - float minDamage = proto->Damage[0].DamageMin; - float maxDamage = proto->Damage[0].DamageMax; - - // If set dpsMod in ScalingStatValue use it for min (70% from average), max (130% from average) damage - if (ssv) + for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i) { - int32 extraDPS = ssv->getDPSMod(proto->ScalingStatValue); - if (extraDPS) + 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 && i == 0) // scaling stats only for first damage { - float average = extraDPS * proto->Delay / 1000.0f; - minDamage = 0.7f * average; - maxDamage = 1.3f * average; + int32 extraDPS = ssv->getDPSMod(proto->ScalingStatValue); + if (extraDPS) + { + float average = extraDPS * proto->Delay / 1000.0f; + minDamage = 0.7f * average; + maxDamage = 1.3f * average; + } } - } - if (minDamage > 0) - { - damage = apply ? minDamage : BASE_MINDAMAGE; - SetBaseWeaponDamage(attType, MINDAMAGE, damage); + if (apply) + { + if (minDamage > 0.f) + SetBaseWeaponDamage(attType, MINDAMAGE, minDamage, i); + + if (maxDamage > 0.f) + SetBaseWeaponDamage(attType, MAXDAMAGE, maxDamage, i); + } } - if (maxDamage > 0) + if (!apply) { - damage = apply ? maxDamage : BASE_MAXDAMAGE; - SetBaseWeaponDamage(attType, MAXDAMAGE, damage); + SetBaseWeaponDamage(attType, MINDAMAGE, BASE_MINDAMAGE, 0); + SetBaseWeaponDamage(attType, MAXDAMAGE, BASE_MAXDAMAGE, 0); + + SetBaseWeaponDamage(attType, MINDAMAGE, 0.f, 1); + SetBaseWeaponDamage(attType, MAXDAMAGE, 0.f, 1); } if (proto->Delay && !IsInFeralForm()) @@ -7637,10 +7644,18 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingSt if (IsInFeralForm()) return; - if (CanModifyStats() && (damage || proto->Delay)) + if (CanModifyStats() && (GetWeaponDamageRange(attType, MAXDAMAGE) || proto->Delay)) UpdateDamagePhysical(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::CastAllObtainSpells() { for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < INVENTORY_SLOT_ITEM_END; ++slot) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 271cd465709..fd9c4230ca9 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1579,7 +1579,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void UpdateRating(CombatRating cr); void UpdateAllRatings(); - void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) const override; + void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex) const override; void UpdateDefenseBonusesMod(); void RecalculateRating(CombatRating cr) { ApplyRatingMod(cr, 0, true);} @@ -1810,6 +1810,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void ResetAllPowers(); + SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType = BASE_ATTACK, uint8 damageIndex = 0) const override; + void CastAllObtainSpells(); void ApplyItemObtainSpells(Item* item, bool apply); diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index 7fadbb97db9..fdaa892acb4 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -62,25 +62,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); + float tmpMin, tmpMax; + for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i) + { + 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; } } @@ -509,7 +515,7 @@ void Player::UpdateShieldBlockValue() SetUInt32Value(PLAYER_SHIELD_BLOCK, GetShieldBlockValue()); } -void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) const +void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex) const { UnitMods unitMod; @@ -529,16 +535,27 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo float const attackPowerMod = std::max(GetAPMultiplier(attType, normalized), 0.25f); - float baseValue = GetFlatModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * attackPowerMod; + float baseValue = GetFlatModifierValue(unitMod, BASE_VALUE); + if (damageIndex == 0) // apply AP bonus only to primary weapon damage + baseValue += GetTotalAttackPowerValue(attType) / 14.0f * attackPowerMod; + float basePct = GetPctModifierValue(unitMod, BASE_PCT); float totalValue = GetFlatModifierValue(unitMod, TOTAL_VALUE); float totalPct = addTotalPct ? GetPctModifierValue(unitMod, TOTAL_PCT) : 1.0f; - float weaponMinDamage = GetWeaponDamageRange(attType, MINDAMAGE); - float weaponMaxDamage = GetWeaponDamageRange(attType, MAXDAMAGE); + float weaponMinDamage = GetWeaponDamageRange(attType, MINDAMAGE, damageIndex); + float weaponMaxDamage = GetWeaponDamageRange(attType, MAXDAMAGE, damageIndex); - if (IsInFeralForm()) // check if player is druid and in cat or bear forms + // check if player is druid and in cat or bear forms (only primary damage) + if (IsInFeralForm()) { + if (damageIndex != 0) + { + minDamage = 0.f; + maxDamage = 0.f; + return; + } + uint8 lvl = getLevel(); if (lvl > 60) lvl = 60; @@ -549,16 +566,18 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo else if (!CanUseAttackType(attType)) // check if player not in form but still can't use (disarm case) { // cannot use ranged/off attack, set values to 0 - if (attType != BASE_ATTACK) + // set secondary damages to 0 by default + if (damageIndex != 0 || attType != BASE_ATTACK) { - minDamage = 0; - maxDamage = 0; + minDamage = 0.f; + maxDamage = 0.f; return; } + weaponMinDamage = BASE_MINDAMAGE; weaponMaxDamage = BASE_MAXDAMAGE; } - else if (attType == RANGED_ATTACK) // add ammo DPS to ranged damage + else if (damageIndex == 0 && attType == RANGED_ATTACK) // add ammo DPS to ranged primary damage { weaponMinDamage += GetAmmoDPS() * attackPowerMod; weaponMaxDamage += GetAmmoDPS() * attackPowerMod; @@ -1047,7 +1066,7 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged) } } -void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) const +void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 /*damageIndex*/) const { float variance = 1.0f; UnitMods unitMod; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 53be3a350bb..77271475cab 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -103,9 +103,19 @@ DamageInfo::DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo co { } -DamageInfo::DamageInfo(CalcDamageInfo const& 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), m_hitMask(0) +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), m_hitMask(dmg1.m_hitMask | dmg2.m_hitMask) +{ +} + +DamageInfo::DamageInfo(CalcDamageInfo const& dmgInfo) : DamageInfo(DamageInfo(dmgInfo, 0), DamageInfo(dmgInfo, 1)) +{ +} + +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), m_hitMask(0) { switch (dmgInfo.TargetState) { @@ -128,7 +138,7 @@ DamageInfo::DamageInfo(CalcDamageInfo const& dmgInfo) bool const damageNullified = (dmgInfo.HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 || (m_hitMask & (PROC_HIT_IMMUNE | PROC_HIT_FULL_BLOCK)) != 0; - switch (dmgInfo.hitOutCome) + switch (dmgInfo.HitOutCome) { case MELEE_HIT_MISS: m_hitMask |= PROC_HIT_MISS; @@ -332,8 +342,11 @@ Unit::Unit(bool 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) @@ -1115,23 +1128,28 @@ 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) -{ - damageInfo->attacker = this; - damageInfo->target = victim; - damageInfo->damageSchoolMask = GetMeleeDamageSchoolMask(); - damageInfo->attackType = attackType; - damageInfo->damage = 0; - damageInfo->cleanDamage = 0; - damageInfo->absorb = 0; - damageInfo->resist = 0; - damageInfo->blocked_amount = 0; +void Unit::CalculateMeleeDamage(Unit* victim, CalcDamageInfo* damageInfo, WeaponAttackType attackType) +{ + damageInfo->Attacker = this; + damageInfo->Target = victim; - damageInfo->TargetState = 0; + 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->Blocked = 0; damageInfo->HitInfo = 0; - damageInfo->procAttacker = PROC_FLAG_NONE; - damageInfo->procVictim = PROC_FLAG_NONE; - damageInfo->hitOutCome = MELEE_HIT_EVADE; + damageInfo->TargetState = 0; + + damageInfo->AttackType = attackType; + damageInfo->ProcAttacker = PROC_FLAG_NONE; + damageInfo->ProcVictim = PROC_FLAG_NONE; + damageInfo->CleanDamage = 0; + damageInfo->HitOutCome = MELEE_HIT_EVADE; if (!victim) return; @@ -1143,61 +1161,78 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam switch (attackType) { case BASE_ATTACK: - damageInfo->procAttacker = PROC_FLAG_DONE_MELEE_AUTO_ATTACK | PROC_FLAG_DONE_MAINHAND_ATTACK; - damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK; + damageInfo->ProcAttacker = PROC_FLAG_DONE_MELEE_AUTO_ATTACK | PROC_FLAG_DONE_MAINHAND_ATTACK; + damageInfo->ProcVictim = PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK; break; case OFF_ATTACK: - damageInfo->procAttacker = PROC_FLAG_DONE_MELEE_AUTO_ATTACK | PROC_FLAG_DONE_OFFHAND_ATTACK; - damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK; + damageInfo->ProcAttacker = PROC_FLAG_DONE_MELEE_AUTO_ATTACK | PROC_FLAG_DONE_OFFHAND_ATTACK; + damageInfo->ProcVictim = PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK; damageInfo->HitInfo = HITINFO_OFFHAND; break; default: return; } - // Physical Immune check - if (damageInfo->target->IsImmunedToDamage(SpellSchoolMask(damageInfo->damageSchoolMask))) - { - damageInfo->HitInfo |= HITINFO_NORMALSWING; - damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE; + // Physical Immune check (must immune to all damages) + uint8 immunedMask = 0; + for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i) + if (damageInfo->Target->IsImmunedToDamage(SpellSchoolMask(damageInfo->Damages[i].DamageSchoolMask))) + immunedMask |= (1 << i); - damageInfo->damage = 0; - damageInfo->cleanDamage = 0; - return; + if (immunedMask == ((1 << 0) | (1 << 1))) + { + damageInfo->HitInfo |= HITINFO_NORMALSWING; + damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE; + damageInfo->CleanDamage = 0; + return; } - damage += CalculateDamage(damageInfo->attackType, false, true); - // Add melee damage bonus - damage = MeleeDamageBonusDone(damageInfo->target, damage, damageInfo->attackType); - damage = damageInfo->target->MeleeDamageBonusTaken(this, damage, damageInfo->attackType); + for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i) + { + if (immunedMask & (1 << i)) + continue; + + SpellSchoolMask schoolMask = SpellSchoolMask(damageInfo->Damages[i].DamageSchoolMask); + bool const addPctMods = (schoolMask & SPELL_SCHOOL_MASK_NORMAL); - // Script Hook For CalculateMeleeDamage -- Allow scripts to change the Damage pre class mitigation calculations - sScriptMgr->ModifyMeleeDamage(damageInfo->target, damageInfo->attacker, damage); + uint32 damage = 0; + damage += CalculateDamage(damageInfo->AttackType, false, addPctMods, (1 << i)); + // Add melee damage bonus + damage = MeleeDamageBonusDone(damageInfo->Target, damage, damageInfo->AttackType, nullptr, schoolMask); + damage = damageInfo->Target->MeleeDamageBonusTaken(this, damage, damageInfo->AttackType, nullptr, schoolMask); - // Calculate armor reduction - if (Unit::IsDamageReducedByArmor((SpellSchoolMask)(damageInfo->damageSchoolMask))) - { - damageInfo->damage = Unit::CalcArmorReducedDamage(damageInfo->attacker, damageInfo->target, damage, nullptr, damageInfo->attackType); - damageInfo->cleanDamage += damage - damageInfo->damage; + // 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 (Unit::IsDamageReducedByArmor(SpellSchoolMask(damageInfo->Damages[i].DamageSchoolMask))) + { + damageInfo->Damages[i].Damage = Unit::CalcArmorReducedDamage(damageInfo->Attacker, damageInfo->Target, damage, nullptr, damageInfo->AttackType); + damageInfo->CleanDamage += damage - damageInfo->Damages[i].Damage; + } + else + damageInfo->Damages[i].Damage = damage; } - else - damageInfo->damage = damage; - damageInfo->hitOutCome = RollMeleeOutcomeAgainst(damageInfo->target, damageInfo->attackType); + damageInfo->HitOutCome = RollMeleeOutcomeAgainst(damageInfo->Target, damageInfo->AttackType); - switch (damageInfo->hitOutCome) + switch (damageInfo->HitOutCome) { case MELEE_HIT_EVADE: damageInfo->HitInfo |= HITINFO_MISS | HITINFO_SWINGNOHITSOUND; damageInfo->TargetState = VICTIMSTATE_EVADES; - damageInfo->damage = 0; - damageInfo->cleanDamage = 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->damage = 0; - damageInfo->cleanDamage = 0; + + for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i) + damageInfo->Damages[i].Damage = 0; + damageInfo->CleanDamage = 0; break; case MELEE_HIT_NORMAL: damageInfo->TargetState = VICTIMSTATE_HIT; @@ -1208,51 +1243,86 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam damageInfo->TargetState = VICTIMSTATE_HIT; // Crit bonus calc - damageInfo->damage += damageInfo->damage; - 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); + 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; + // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS + mod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, damageInfo->Damages[i].DamageSchoolMask) - 1.0f) * 100; - uint32 crTypeMask = damageInfo->target->GetCreatureTypeMask(); + uint32 crTypeMask = damageInfo->Target->GetCreatureTypeMask(); - // 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); + // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS + mod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask); + if (mod != 0) + AddPct(damageInfo->Damages[i].Damage, mod); + } break; } case MELEE_HIT_PARRY: damageInfo->TargetState = VICTIMSTATE_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->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->blocked_amount = damageInfo->target->GetShieldBlockValue(); + damageInfo->Blocked = damageInfo->Target->GetShieldBlockValue(); // double blocked amount if block is critical - if (damageInfo->target->isBlockCritical()) - damageInfo->blocked_amount += damageInfo->blocked_amount; - if (damageInfo->blocked_amount >= damageInfo->damage) + if (damageInfo->Target->isBlockCritical()) + damageInfo->Blocked *= 2; + + uint32 remainingBlock = damageInfo->Blocked; + uint8 fullBlockMask = 0; + for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i) { - damageInfo->TargetState = VICTIMSTATE_BLOCKS; - damageInfo->blocked_amount = damageInfo->damage; + 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->CleanDamage += remainingBlock; + damageInfo->Damages[i].Damage -= remainingBlock; + remainingBlock = 0; + } } - damageInfo->damage -= damageInfo->blocked_amount; - damageInfo->cleanDamage += damageInfo->blocked_amount; + // full block + if (fullBlockMask == ((1 << 0) | (1 << 1))) + { + damageInfo->TargetState = VICTIMSTATE_BLOCKS; + damageInfo->Blocked -= remainingBlock; + } break; + } case MELEE_HIT_GLANCING: { damageInfo->HitInfo |= HITINFO_GLANCING; @@ -1266,15 +1336,22 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam int32 const reductionMax = leveldif * 10; int32 const reductionMin = reductionMax - 10; float reducePercent = 1.f - irand(reductionMin, reductionMax) / 100.0f; - 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; + // 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; @@ -1284,39 +1361,62 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam if (!(damageInfo->HitInfo & HITINFO_MISS)) damageInfo->HitInfo |= HITINFO_AFFECTS_VICTIM; - int32 resilienceReduction = damageInfo->damage; - // attackType is checked already for BASE_ATTACK or OFF_ATTACK so it can't be RANGED_ATTACK here - if (CanApplyResilience()) - Unit::ApplyResilience(victim, nullptr, &resilienceReduction, (damageInfo->hitOutCome == MELEE_HIT_CRIT), CR_CRIT_TAKEN_MELEE); - resilienceReduction = damageInfo->damage - resilienceReduction; - damageInfo->damage -= resilienceReduction; - damageInfo->cleanDamage += resilienceReduction; + uint32 tmpHitInfo[MAX_ITEM_PROTO_DAMAGES] = { }; - // Calculate absorb resist - if (int32(damageInfo->damage) > 0) + for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i) { - damageInfo->procVictim |= PROC_FLAG_TAKEN_DAMAGE; - // Calculate absorb & resists - DamageInfo dmgInfo(*damageInfo); - Unit::CalcAbsorbResist(dmgInfo); - damageInfo->absorb = dmgInfo.GetAbsorb(); - damageInfo->resist = dmgInfo.GetResist(); + int32 resilienceReduction = damageInfo->Damages[i].Damage; + // attackType is checked already for BASE_ATTACK or OFF_ATTACK so it can't be RANGED_ATTACK here + if (CanApplyResilience()) + Unit::ApplyResilience(victim, nullptr, &resilienceReduction, (damageInfo->HitOutCome == MELEE_HIT_CRIT), CR_CRIT_TAKEN_MELEE); + resilienceReduction = damageInfo->Damages[i].Damage - resilienceReduction; + damageInfo->Damages[i].Damage -= resilienceReduction; + damageInfo->CleanDamage += resilienceReduction; - if (damageInfo->absorb) - damageInfo->HitInfo |= (damageInfo->damage - damageInfo->absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB); + // Calculate absorb resist + if (int32(damageInfo->Damages[i].Damage) > 0) + { + damageInfo->ProcVictim |= PROC_FLAG_TAKEN_DAMAGE; + // Calculate absorb & resists + DamageInfo dmgInfo(*damageInfo, i); + Unit::CalcAbsorbResist(dmgInfo); + damageInfo->Damages[i].Absorb = dmgInfo.GetAbsorb(); + damageInfo->Damages[i].Resist = dmgInfo.GetResist(); - if (damageInfo->resist) - damageInfo->HitInfo |= (damageInfo->damage - damageInfo->resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST); + if (damageInfo->Damages[i].Absorb) + tmpHitInfo[i] |= (damageInfo->Damages[i].Damage - damageInfo->Damages[i].Absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB); - damageInfo->damage = dmgInfo.GetDamage(); + if (damageInfo->Damages[i].Resist) + tmpHitInfo[i] |= (damageInfo->Damages[i].Damage - damageInfo->Damages[i].Resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST); + + damageInfo->CleanDamage += damageInfo->Damages[i].Damage - dmgInfo.GetDamage(); + damageInfo->Damages[i].Damage = dmgInfo.GetDamage(); + } + else // Impossible get negative result but.... + damageInfo->Damages[i].Damage = 0; } - else // Impossible get negative result but.... - damageInfo->damage = 0; + + // set proper HitInfo flags + if ((tmpHitInfo[0] & HITINFO_FULL_ABSORB) != 0) + { + // only set full absorb whenever both damages were fully absorbed + damageInfo->HitInfo |= ((tmpHitInfo[1] & HITINFO_FULL_ABSORB) != 0) ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB; + } + else + damageInfo->HitInfo |= (tmpHitInfo[0] & HITINFO_PARTIAL_ABSORB); + + if (tmpHitInfo[0] == HITINFO_FULL_RESIST) + { + // only set full resist whenever both damages were fully resisted + damageInfo->HitInfo |= ((tmpHitInfo[1] & HITINFO_FULL_RESIST) != 0) ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST; + } + else + damageInfo->HitInfo |= (tmpHitInfo[0] & HITINFO_FULL_RESIST); } void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) { - Unit* victim = damageInfo->target; + Unit* victim = damageInfo->Target; if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks())) return; @@ -1324,7 +1424,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) // Hmmmm dont like this emotes client must by self do all animations if (damageInfo->HitInfo & HITINFO_CRITICALHIT) victim->HandleEmoteCommand(EMOTE_ONESHOT_WOUND_CRITICAL); - if (damageInfo->blocked_amount && damageInfo->TargetState != VICTIMSTATE_BLOCKS) + if (damageInfo->Blocked && damageInfo->TargetState != VICTIMSTATE_BLOCKS) victim->HandleEmoteCommand(EMOTE_ONESHOT_PARRY_SHIELD); if (damageInfo->TargetState == VICTIMSTATE_PARRY && @@ -1360,12 +1460,15 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) } } - // 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); + for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i) + { + // Call default DealDamage + 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->hitOutCome == MELEE_HIT_CRIT || damageInfo->hitOutCome == MELEE_HIT_CRUSHING || damageInfo->hitOutCome == MELEE_HIT_NORMAL || damageInfo->hitOutCome == MELEE_HIT_GLANCING) && + if ((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(float(M_PI), this) && (victim->GetTypeId() == TYPEID_PLAYER || !victim->ToCreature()->isWorldBoss())&& !victim->IsVehicle()) { @@ -1394,7 +1497,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) } // 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 @@ -1540,7 +1643,7 @@ void Unit::HandleEmoteCommand(uint32 anim_id) damageReduction /= (1.0f + damageReduction); RoundToInterval(damageReduction, 0.f, 0.75f); - return std::max<uint32>(damage * (1.0f - damageReduction), 1); + return std::max<uint32>(damage * (1.0f - damageReduction), 0); } /*static*/ uint32 Unit::CalcSpellResistedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const* spellInfo) @@ -1991,22 +2094,24 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr victim = GetMeleeHitRedirectTarget(victim); CalcDamageInfo damageInfo; - CalculateMeleeDamage(victim, 0, &damageInfo, attType); + CalculateMeleeDamage(victim, &damageInfo, attType); // 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); DealMeleeDamage(&damageInfo, true); DamageInfo dmgInfo(damageInfo); - Unit::ProcSkillsAndAuras(damageInfo.attacker, damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr); + Unit::ProcSkillsAndAuras(damageInfo.Attacker, damageInfo.Target, damageInfo.ProcAttacker, damageInfo.ProcVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr); if (GetTypeId() == TYPEID_PLAYER) TC_LOG_DEBUG("entities.unit", "AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.", - GetGUID().GetCounter(), victim->GetGUID().GetCounter(), victim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist); + GetGUID().GetCounter(), victim->GetGUID().GetCounter(), victim->GetTypeId(), dmgInfo.GetDamage(), dmgInfo.GetAbsorb(), dmgInfo.GetBlock(), dmgInfo.GetResist()); else TC_LOG_DEBUG("entities.unit", "AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.", - GetGUID().GetCounter(), victim->GetGUID().GetCounter(), victim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist); + GetGUID().GetCounter(), victim->GetGUID().GetCounter(), victim->GetTypeId(), dmgInfo.GetDamage(), dmgInfo.GetAbsorb(), dmgInfo.GetBlock(), dmgInfo.GetResist()); } } @@ -2031,24 +2136,29 @@ void Unit::FakeAttackerStateUpdate(Unit* victim, WeaponAttackType attType /*= BA SetFacingToObject(victim, false); // update client side facing to face the target (prevents visual glitches when casting untargeted spells) CalcDamageInfo damageInfo; - damageInfo.attacker = this; - damageInfo.target = victim; - damageInfo.damageSchoolMask = GetMeleeDamageSchoolMask(); - damageInfo.attackType = attType; - damageInfo.damage = 0; - damageInfo.cleanDamage = 0; - damageInfo.absorb = 0; - damageInfo.resist = 0; - damageInfo.blocked_amount = 0; + damageInfo.Attacker = this; + damageInfo.Target = victim; + + for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) + { + damageInfo.Damages[i].DamageSchoolMask = GetMeleeDamageSchoolMask(attType, i); + damageInfo.Damages[i].Damage = 0; + damageInfo.Damages[i].Absorb = 0; + damageInfo.Damages[i].Resist = 0; + } + + damageInfo.AttackType = attType; + damageInfo.CleanDamage = 0; + damageInfo.Blocked = 0; damageInfo.TargetState = VICTIMSTATE_HIT; damageInfo.HitInfo = HITINFO_AFFECTS_VICTIM | HITINFO_NORMALSWING | HITINFO_FAKE_DAMAGE; if (attType == OFF_ATTACK) damageInfo.HitInfo |= HITINFO_OFFHAND; - damageInfo.procAttacker = PROC_FLAG_NONE; - damageInfo.procVictim = PROC_FLAG_NONE; - damageInfo.hitOutCome = MELEE_HIT_NORMAL; + damageInfo.ProcAttacker = PROC_FLAG_NONE; + damageInfo.ProcVictim = PROC_FLAG_NONE; + damageInfo.HitOutCome = MELEE_HIT_NORMAL; SendAttackStateUpdate(&damageInfo); } @@ -2190,13 +2300,28 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(Unit const* victim, WeaponAttackTy return MELEE_HIT_NORMAL; } -uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct) const +uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, uint8 itemDamagesMask /*= 0*/) const { 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) @@ -2224,9 +2349,6 @@ uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool add if (minDamage > maxDamage) std::swap(minDamage, maxDamage); - if (maxDamage == 0.0f) - maxDamage = 5.0f; - return urand(uint32(minDamage), uint32(maxDamage)); } @@ -5338,36 +5460,39 @@ void Unit::SendSpellDamageImmune(Unit* target, uint32 spellId) void Unit::SendAttackStateUpdate(CalcDamageInfo* damageInfo) { - TC_LOG_DEBUG("entities.unit", "WORLD: Sending SMSG_ATTACKERSTATEUPDATE"); + uint32 count = 1; + if (damageInfo->Damages[1].Damage || damageInfo->Damages[1].Absorb || damageInfo->Damages[1].Resist) + ++count; + + // guess size + size_t const maxsize = 4+5+5+4+4+1+(4+4+4)*2+4*2+4*2+1+4+4+4+4+4*12; + WorldPacket data(SMSG_ATTACKERSTATEUPDATE, maxsize); - uint32 const count = 1; - size_t const maxsize = 4+5+5+4+4+1+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(damageInfo->damage); // Full damage - int32 overkill = damageInfo->damage - damageInfo->target->GetHealth(); + data << damageInfo->Attacker->GetPackGUID(); + data << damageInfo->Target->GetPackGUID(); + data << uint32(damageInfo->Damages[0].Damage + damageInfo->Damages[1].Damage); // Full damage + int32 overkill = damageInfo->Damages[0].Damage + damageInfo->Damages[1].Damage - 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(damageInfo->damage); // sub damage - data << uint32(damageInfo->damage); // Sub Damage + data << uint32(damageInfo->Damages[i].DamageSchoolMask); // School of sub damage + data << float(damageInfo->Damages[i].Damage); // sub damage + data << uint32(damageInfo->Damages[i].Damage); // Sub Damage } if (damageInfo->HitInfo & (HITINFO_FULL_ABSORB | HITINFO_PARTIAL_ABSORB)) { for (uint32 i = 0; i < count; ++i) - data << uint32(damageInfo->absorb); // Absorb + data << uint32(damageInfo->Damages[i].Absorb); // 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); @@ -5375,7 +5500,7 @@ void Unit::SendAttackStateUpdate(CalcDamageInfo* damageInfo) data << uint32(0); // Melee spellid if (damageInfo->HitInfo & HITINFO_BLOCK) - data << uint32(damageInfo->blocked_amount); + data << uint32(damageInfo->Blocked); if (damageInfo->HitInfo & HITINFO_RAGE_GAIN) data << uint32(0); @@ -5404,14 +5529,21 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType { CalcDamageInfo dmgInfo; 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.Attacker = this; + dmgInfo.Target = target; + + 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; + dmgInfo.Blocked = BlockedAmount; SendAttackStateUpdate(&dmgInfo); } @@ -8103,7 +8235,7 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit 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 /*= nullptr*/, SpellSchoolMask damageSchoolMask /*= SPELL_SCHOOL_MASK_NORMAL*/) { if (!victim || pdamage == 0) return 0; @@ -8146,21 +8278,23 @@ 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 && !spellProto->HasAttribute(SPELL_ATTR6_LIMIT_PCT_DAMAGE_MODS)) + SpellSchoolMask schoolMask = spellProto ? spellProto->GetSchoolMask() : damageSchoolMask; + + // mods for SPELL_SCHOOL_MASK_NORMAL are already factored in base melee damage calculation + if (!(schoolMask & SPELL_SCHOOL_MASK_NORMAL)) { - // mods for SPELL_SCHOOL_MASK_NORMAL are already factored in base melee damage calculation - if (!(spellProto->GetSchoolMask() & SPELL_SCHOOL_MASK_NORMAL)) + // Some spells don't benefit from pct done mods + if (!spellProto || !spellProto->HasAttribute(SPELL_ATTR6_LIMIT_PCT_DAMAGE_MODS)) { float maxModDamagePercentSchool = 0.0f; if (GetTypeId() == TYPEID_PLAYER) { for (uint32 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) - if (spellProto->GetSchoolMask() & (1 << i)) + if (schoolMask & (1 << i)) maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, GetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT + i)); } else - maxModDamagePercentSchool = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, spellProto->GetSchoolMask()); + maxModDamagePercentSchool = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, schoolMask); DoneTotalMod *= maxModDamagePercentSchool; } @@ -8264,7 +8398,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; @@ -8351,7 +8485,7 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT // Sanctified Wrath (bypass damage reduction) if (attacker && TakenTotalMod < 1.0f) { - SpellSchoolMask const attackSchoolMask = spellProto ? spellProto->GetSchoolMask() : SPELL_SCHOOL_MASK_NORMAL; + SpellSchoolMask const attackSchoolMask = spellProto ? spellProto->GetSchoolMask() : damageSchoolMask; float damageReduction = 1.0f - TakenTotalMod; Unit::AuraEffectList const& casterIgnoreResist = attacker->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST); @@ -10042,12 +10176,12 @@ float Unit::GetTotalAttackPowerValue(WeaponAttackType attType) const } } -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]; } bool Unit::CanFreeMove() const @@ -10851,12 +10985,6 @@ void Unit::GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer& aurasTrigg } } -void Unit::TriggerAurasProcOnEvent(CalcDamageInfo& damageInfo) -{ - DamageInfo dmgInfo = DamageInfo(damageInfo); - TriggerAurasProcOnEvent(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr); -} - void Unit::TriggerAurasProcOnEvent(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo) { // prepare data for self trigger @@ -10923,11 +11051,6 @@ void Unit::TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationProc SetCantProc(false); } -SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const -{ - return SPELL_SCHOOL_MASK_NORMAL; -} - ObjectGuid Unit::GetCharmerOrOwnerGUID() const { return GetCharmerGUID() ? GetCharmerGUID() : GetOwnerGUID(); diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 7c74d7fa58f..bf4a4038ccb 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -403,9 +403,14 @@ class TC_GAME_API DamageInfo uint32 m_resist; uint32 m_block; uint32 m_hitMask; + + // amalgamation constructor (used for proc) + DamageInfo(DamageInfo const& dmg1, DamageInfo const& dmg2); + public: DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType); - explicit DamageInfo(CalcDamageInfo const& dmgInfo); + explicit DamageInfo(CalcDamageInfo const& dmgInfo); // amalgamation wrapper + DamageInfo(CalcDamageInfo const& dmgInfo, uint8 damageIndex); DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType, uint32 hitMask); void ModifyDamage(int32 amount); @@ -497,21 +502,27 @@ class TC_GAME_API ProcEventInfo // Need create structure like in SMSG_ATTACKERSTATEUPDATE opcode struct CalcDamageInfo { - Unit *attacker; // Attacker - Unit *target; // Target for damage - uint32 damageSchoolMask; - uint32 damage; - uint32 absorb; - uint32 resist; - uint32 blocked_amount; + Unit* Attacker; + Unit* Target; + + struct + { + uint32 DamageSchoolMask; + uint32 Damage; + uint32 Absorb; + uint32 Resist; + } Damages[2]; + + uint32 Blocked; uint32 HitInfo; uint32 TargetState; -// Helper - WeaponAttackType attackType; // - uint32 procAttacker; - uint32 procVictim; - uint32 cleanDamage; // Used only for rage calculation - MeleeHitOutcome hitOutCome; /// @todo remove this field (need use TargetState) + + // Helpers + WeaponAttackType AttackType; + uint32 ProcAttacker; + uint32 ProcVictim; + uint32 CleanDamage; // Used only for rage calculation + MeleeHitOutcome HitOutCome; /// @todo remove this field (need use TargetState) }; // Spell damage info structure based on structure sending in SMSG_SPELLNONMELEEDAMAGELOG opcode @@ -785,7 +796,7 @@ class TC_GAME_API Unit : public WorldObject bool IsWithinCombatRange(Unit const* obj, float dist2compare) const; bool IsWithinMeleeRange(Unit const* obj) const; float GetMeleeRange(Unit const* target) const; - virtual SpellSchoolMask GetMeleeDamageSchoolMask() const; + virtual SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType = BASE_ATTACK, uint8 damageIndex = 0) const = 0; void GetRandomContactPoint(Unit const* target, float& x, float& y, float& z, float distance2dMin, float distance2dMax) const; uint32 m_extraAttacks; bool m_canDualWield; @@ -932,7 +943,6 @@ class TC_GAME_API Unit : public WorldObject DamageInfo* damageInfo, HealInfo* healInfo); void GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer& aurasTriggeringProc, AuraApplicationList* procAuras, ProcEventInfo& eventInfo); - void TriggerAurasProcOnEvent(CalcDamageInfo& damageInfo); void TriggerAurasProcOnEvent(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo); @@ -942,7 +952,7 @@ class TC_GAME_API Unit : public WorldObject void AttackerStateUpdate (Unit* victim, WeaponAttackType attType = BASE_ATTACK, bool extra = false); void FakeAttackerStateUpdate(Unit* victim, WeaponAttackType attType = BASE_ATTACK); - void CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK); + void CalculateMeleeDamage(Unit* victim, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK); void DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss); void HandleProcExtraAttackFor(Unit* victim); @@ -1445,10 +1455,10 @@ class TC_GAME_API Unit : public WorldObject virtual void UpdateAttackPowerAndDamage(bool ranged = false) = 0; virtual void UpdateDamagePhysical(WeaponAttackType attType); float GetTotalAttackPowerValue(WeaponAttackType attType) const; - 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) const = 0; - uint32 CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct) const; + 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) const = 0; + uint32 CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, uint8 itemDamagesMask = 0) const; float GetAPMultiplier(WeaponAttackType attType, bool normalized) const; bool isInFrontInMap(Unit const* target, float distance, float arc = float(M_PI)) const; @@ -1514,8 +1524,8 @@ class TC_GAME_API Unit : public WorldObject float SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const; uint32 SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1) const; - 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(); @@ -1753,7 +1763,7 @@ class TC_GAME_API Unit : public WorldObject float m_auraFlatModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_FLAT_END]; float m_auraPctModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_PCT_END]; - float m_weaponDamage[MAX_ATTACK][2]; + float m_weaponDamage[MAX_ATTACK][2][2]; bool m_canModifyStats; VisibleAuraMap m_visibleAuras; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 11848bf9a93..05ac456ec59 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -613,8 +613,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); else @@ -629,12 +635,18 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) // Hammer of the Righteous if (m_spellInfo->SpellFamilyFlags[1]&0x00040000) { - float min_damage = m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE); - float max_damage = m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE); - if (Player* player = m_caster->ToPlayer()) // UNIT_FIELD_MINDAMAGE/MAXDAMAGE already include damage bonuses, so try to get them without damage bonuses - player->CalculateMinMaxDamage(BASE_ATTACK, false, false, min_damage, max_damage); + float minTotal = 0.f; + float maxTotal = 0.f; - float average = (min_damage + max_damage) / 2; + float tmpMin, tmpMax; + for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i) + { + m_caster->CalculateMinMaxDamage(BASE_ATTACK, false, false, tmpMin, tmpMax, i); + minTotal += tmpMin; + maxTotal += tmpMax; + } + + float average = (minTotal + maxTotal) / 2; // Add main hand dps * effect[2] amount int32 count = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, EFFECT_2); damage += count * int32(average * IN_MILLISECONDS) / m_caster->GetAttackTime(BASE_ATTACK); @@ -3336,7 +3348,6 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) // Add melee damage bonuses (also check for negative) uint32 damageBonusDone = m_caster->MeleeDamageBonusDone(unitTarget, eff_damage, m_attackType, m_spellInfo); - m_damage += unitTarget->MeleeDamageBonusTaken(m_caster, damageBonusDone, m_attackType, m_spellInfo); } diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index aa6f1c7b5f3..459aed93621 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -2336,7 +2336,7 @@ public: { Unit::DealDamage(handler->GetSession()->GetPlayer(), target, damage, nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); if (target != handler->GetSession()->GetPlayer()) - handler->GetSession()->GetPlayer()->SendAttackStateUpdate (HITINFO_AFFECTS_VICTIM, target, 1, SPELL_SCHOOL_MASK_NORMAL, damage, 0, 0, VICTIMSTATE_HIT, 0); + handler->GetSession()->GetPlayer()->SendAttackStateUpdate(HITINFO_AFFECTS_VICTIM, target, 1, SPELL_SCHOOL_MASK_NORMAL, damage, 0, 0, VICTIMSTATE_HIT, 0); return true; } diff --git a/src/server/scripts/Spells/spell_pet.cpp b/src/server/scripts/Spells/spell_pet.cpp index 8f7ad770517..e909e9f0780 100644 --- a/src/server/scripts/Spells/spell_pet.cpp +++ b/src/server/scripts/Spells/spell_pet.cpp @@ -1724,7 +1724,8 @@ public: if (pet->IsGuardian()) ((Guardian*)pet)->SetBonusDamage(owner->GetTotalAttackPowerValue(BASE_ATTACK)); - amount += owner->CalculateDamage(BASE_ATTACK, true, true); + for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i) + amount += owner->CalculateDamage(BASE_ATTACK, true, true, i); } } diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index 9c303319037..ac3ddb25e6f 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -22,6 +22,7 @@ */ #include "ScriptMgr.h" +#include "ItemTemplate.h" #include "Optional.h" #include "Player.h" #include "Random.h" @@ -50,7 +51,7 @@ enum WarriorSpells SPELL_WARRIOR_JUGGERNAUT_CRIT_BONUS_BUFF = 65156, SPELL_WARRIOR_JUGGERNAUT_CRIT_BONUS_TALENT = 64976, SPELL_WARRIOR_LAST_STAND_TRIGGERED = 12976, - SPELL_WARRIOR_RETALIATION_DAMAGE = 22858, + SPELL_WARRIOR_RETALIATION_DAMAGE = 20240, SPELL_WARRIOR_SLAM = 50783, SPELL_WARRIOR_SLAM_GCD_REDUCED = 71072, SPELL_WARRIOR_SUDDEN_DEATH_R1 = 29723, @@ -743,8 +744,14 @@ class spell_warr_rend : public SpellScriptLoader // $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)); |