aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/server/game/Combat/HostileRefManager.cpp7
-rwxr-xr-xsrc/server/game/Combat/ThreatManager.cpp16
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.cpp32
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.h2
-rwxr-xr-xsrc/server/game/Spells/Spell.cpp45
-rw-r--r--src/server/game/Spells/SpellInfo.h2
-rwxr-xr-xsrc/server/game/Spells/SpellMgr.cpp55
-rwxr-xr-xsrc/server/game/Spells/SpellMgr.h11
8 files changed, 111 insertions, 59 deletions
diff --git a/src/server/game/Combat/HostileRefManager.cpp b/src/server/game/Combat/HostileRefManager.cpp
index 5d9e7d671c8..47e9a1d2508 100755
--- a/src/server/game/Combat/HostileRefManager.cpp
+++ b/src/server/game/Combat/HostileRefManager.cpp
@@ -40,10 +40,9 @@ void HostileRefManager::threatAssist(Unit* victim, float baseThreat, SpellInfo c
threat /= getSize();
while (ref)
{
- if (victim == getOwner())
- ref->addThreat(threat); // It is faster to modify the threat durectly if possible
- else
- ref->getSource()->addThreat(victim, threat);
+ if (ThreatCalcHelper::isValidProcess(victim, ref->getSource()->getOwner(), threatSpell))
+ ref->getSource()->doAddThreat(victim, threat);
+
ref = ref->next();
}
}
diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp
index bf3650f611e..858ef057baf 100755
--- a/src/server/game/Combat/ThreatManager.cpp
+++ b/src/server/game/Combat/ThreatManager.cpp
@@ -36,8 +36,14 @@ float ThreatCalcHelper::calcThreat(Unit* hatedUnit, Unit* /*hatingUnit*/, float
{
if (threatSpell)
{
- if (threatSpell->AttributesEx & SPELL_ATTR1_NO_THREAT)
- return 0.0f;
+ if (SpellThreatEntry const* threatEntry = sSpellMgr->GetSpellThreatEntry(threatSpell->Id))
+ if (threatEntry->pctMod != 1.0f)
+ threat *= threatEntry->pctMod;
+
+ // Energize is not affected by Mods
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; i++)
+ if (threatSpell->Effects[i].Effect == SPELL_EFFECT_ENERGIZE || threatSpell->Effects[i].ApplyAuraName == SPELL_AURA_PERIODIC_ENERGIZE)
+ return threat;
if (Player* modOwner = hatedUnit->GetSpellModOwner())
modOwner->ApplySpellMod(threatSpell->Id, SPELLMOD_THREAT, threat);
@@ -46,7 +52,7 @@ float ThreatCalcHelper::calcThreat(Unit* hatedUnit, Unit* /*hatingUnit*/, float
return hatedUnit->ApplyTotalThreatModifier(threat, schoolMask);
}
-bool ThreatCalcHelper::isValidProcess(Unit* hatedUnit, Unit* hatingUnit, SpellInfo const* /*threatSpell*/)
+bool ThreatCalcHelper::isValidProcess(Unit* hatedUnit, Unit* hatingUnit, SpellInfo const* threatSpell)
{
//function deals with adding threat and adding players and pets into ThreatList
//mobs, NPCs, guards have ThreatList and HateOfflineList
@@ -68,6 +74,10 @@ bool ThreatCalcHelper::isValidProcess(Unit* hatedUnit, Unit* hatingUnit, SpellIn
if (!hatedUnit->isAlive() || !hatingUnit->isAlive())
return false;
+ // spell not causing threat
+ if (threatSpell && threatSpell->AttributesEx & SPELL_ATTR1_NO_THREAT)
+ return false;
+
ASSERT(hatingUnit->GetTypeId() == TYPEID_UNIT);
return true;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 4cea8f56005..1b3217a02e0 100755
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -791,12 +791,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
victim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE, spellProto ? spellProto->Id : 0);
if (victim->GetTypeId() != TYPEID_PLAYER)
- {
- if (spellProto && IsDamageToThreatSpell(spellProto))
- victim->AddThreat(this, damage * 2.0f, damageSchoolMask, spellProto);
- else
victim->AddThreat(this, (float)damage, damageSchoolMask, spellProto);
- }
else // victim is a player
{
// random durability for items (HIT TAKEN)
@@ -10334,6 +10329,9 @@ void Unit::EnergizeBySpell(Unit* victim, uint32 spellID, uint32 damage, Powers p
SendEnergizeSpellLog(victim, spellID, damage, powerType);
// needs to be called after sending spell log
victim->ModifyPower(powerType, damage);
+
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID);
+ victim->getHostileRefManager().threatAssist(this, float(damage) * 0.5f, spellInfo);
}
uint32 Unit::SpellDamageBonus(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack)
@@ -11622,30 +11620,6 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) cons
return false;
}
-bool Unit::IsDamageToThreatSpell(SpellInfo const* spellInfo) const
-{
- if (!spellInfo)
- return false;
-
- switch(spellInfo->SpellFamilyName)
- {
- case SPELLFAMILY_WARLOCK:
- if (spellInfo->SpellFamilyFlags[0] == 0x100) // Searing Pain
- return true;
- break;
- case SPELLFAMILY_SHAMAN:
- if (spellInfo->SpellFamilyFlags[0] == SPELLFAMILYFLAG_SHAMAN_FROST_SHOCK)
- return true;
- break;
- case SPELLFAMILY_DEATHKNIGHT:
- if (spellInfo->SpellFamilyFlags[1] == 0x20000000) // Rune Strike
- return true;
- break;
- }
-
- return false;
-}
-
void Unit::MeleeDamageBonus(Unit* victim, uint32 *pdamage, WeaponAttackType attType, SpellInfo const* spellProto)
{
if (!victim)
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index e777f16b99a..fb41914d6f7 100755
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1572,8 +1572,6 @@ class Unit : public WorldObject
void SendPlaySpellVisual(uint32 id);
void SendPlaySpellImpact(uint64 guid, uint32 id);
- bool IsDamageToThreatSpell(SpellInfo const* spellInfo) const;
-
void DeMorph();
void SendAttackStateUpdate(CalcDamageInfo *damageInfo);
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index ed36a4ae208..bae14ed26bf 100755
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -4536,20 +4536,53 @@ void Spell::TakeReagents()
void Spell::HandleThreatSpells()
{
- if (!m_targets.GetUnitTarget())
+ if (m_UniqueTargetInfo.empty())
return;
- if (!m_targets.GetUnitTarget()->CanHaveThreatList())
+ if ((m_spellInfo->AttributesEx & SPELL_ATTR1_NO_THREAT) ||
+ (m_spellInfo->AttributesEx3 & SPELL_ATTR3_NO_INITIAL_AGGRO))
return;
- uint16 threat = sSpellMgr->GetSpellThreat(m_spellInfo->Id);
+ float threat = 0.0f;
+ if (SpellThreatEntry const* threatEntry = sSpellMgr->GetSpellThreatEntry(m_spellInfo->Id))
+ {
+ if (threatEntry->apPctMod != 0.0f)
+ threat += threatEntry->apPctMod * m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
+
+ threat += threatEntry->flatMod;
+ }
+ else if ((m_spellInfo->AttributesCu & SPELL_ATTR0_CU_NO_INITIAL_THREAT) == 0)
+ threat += m_spellInfo->SpellLevel;
- if (!threat)
+ // past this point only multiplicative effects occur
+ if (threat == 0.0f)
return;
- m_targets.GetUnitTarget()->AddThreat(m_caster, float(threat));
+ // since 2.0.1 threat from positive effects also is distributed among all targets, so the overall caused threat is at most the defined bonus
+ threat /= m_UniqueTargetInfo.size();
+
+ for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
+ {
+ if (ihit->missCondition != SPELL_MISS_NONE)
+ continue;
+
+ Unit* target = ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID);
+ if (!target)
+ continue;
+
+ // positive spells distribute threat among all units that are in combat with target, like healing
+ if (m_spellInfo->_IsPositiveSpell())
+ target->getHostileRefManager().threatAssist(m_caster, threat, m_spellInfo);
+ // for negative spells threat gets distributed among affected targets
+ else
+ {
+ if (!target->CanHaveThreatList())
+ continue;
- sLog->outStaticDebug("Spell %u, rank %u, added an additional %i threat", m_spellInfo->Id, m_spellInfo->GetRank(), threat);
+ target->AddThreat(m_caster, threat, m_spellInfo->GetSchoolMask(), m_spellInfo);
+ }
+ }
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell %u, added an additional %f threat for %s %u target(s)", m_spellInfo->Id, threat, m_spellInfo->_IsPositiveSpell() ? "assisting" : "harming", uint32(m_UniqueTargetInfo.size()));
}
void Spell::HandleEffects(Unit *pUnitTarget, Item *pItemTarget, GameObject *pGOTarget, uint32 i)
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index 69f160cbb0f..584c41fdddd 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -186,7 +186,7 @@ enum SpellCustomAttributes
SPELL_ATTR0_CU_CONE_BACK = 0x00000002,
SPELL_ATTR0_CU_CONE_LINE = 0x00000004,
SPELL_ATTR0_CU_SHARE_DAMAGE = 0x00000008,
- SPELL_ATTR0_CU_NONE1 = 0x00000010, // UNUSED
+ SPELL_ATTR0_CU_NO_INITIAL_THREAT = 0x00000010,
SPELL_ATTR0_CU_NONE2 = 0x00000020, // UNUSED
SPELL_ATTR0_CU_AURA_CC = 0x00000040,
SPELL_ATTR0_CU_DIRECT_DAMAGE = 0x00000100,
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 3b546a94bfa..b44c7f58ef5 100755
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -965,13 +965,19 @@ SpellBonusEntry const* SpellMgr::GetSpellBonusData(uint32 spellId) const
return NULL;
}
-uint16 SpellMgr::GetSpellThreat(uint32 spellid) const
+SpellThreatEntry const* SpellMgr::GetSpellThreatEntry(uint32 spellID) const
{
- SpellThreatMap::const_iterator itr = mSpellThreatMap.find(spellid);
- if (itr == mSpellThreatMap.end())
- return 0;
-
- return itr->second;
+ SpellThreatMap::const_iterator itr = mSpellThreatMap.find(spellID);
+ if (itr != mSpellThreatMap.end())
+ return &itr->second;
+ else
+ {
+ uint32 firstSpell = GetFirstSpellInChain(spellID);
+ SpellThreatMap::const_iterator itr = mSpellThreatMap.find(firstSpell);
+ if (itr != mSpellThreatMap.end())
+ return &itr->second;
+ }
+ return NULL;
}
SkillLineAbilityMapBounds SpellMgr::GetSkillLineAbilityMapBounds(uint32 spell_id) const
@@ -1940,8 +1946,8 @@ void SpellMgr::LoadSpellThreats()
uint32 count = 0;
- // 0 1
- QueryResult result = WorldDatabase.Query("SELECT entry, Threat FROM spell_threat");
+ // 0 1 2 3
+ QueryResult result = WorldDatabase.Query("SELECT entry, flatMod, pctMod, apPctMod FROM spell_threat");
if (!result)
{
sLog->outString(">> Loaded 0 aggro generating spells");
@@ -1954,7 +1960,6 @@ void SpellMgr::LoadSpellThreats()
Field *fields = result->Fetch();
uint32 entry = fields[0].GetUInt32();
- uint16 Threat = fields[1].GetUInt16();
if (!GetSpellInfo(entry))
{
@@ -1962,12 +1967,16 @@ void SpellMgr::LoadSpellThreats()
continue;
}
- mSpellThreatMap[entry] = Threat;
+ SpellThreatEntry ste;
+ ste.flatMod = fields[1].GetInt16();
+ ste.pctMod = fields[2].GetFloat();
+ ste.apPctMod = fields[3].GetFloat();
- ++count;
+ mSpellThreatMap[entry] = ste;
+ count++;
} while (result->NextRow());
- sLog->outString(">> Loaded %u aggro generating spells in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+ sLog->outString(">> Loaded %u SpellThreatEntries in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
sLog->outString();
}
@@ -2634,6 +2643,18 @@ void SpellMgr::LoadSpellCustomAttr()
case SPELL_AURA_MOD_STUN:
spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
break;
+ case SPELL_AURA_PERIODIC_HEAL:
+ case SPELL_AURA_PERIODIC_DAMAGE:
+ case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
+ case SPELL_AURA_PERIODIC_LEECH:
+ case SPELL_AURA_PERIODIC_MANA_LEECH:
+ case SPELL_AURA_PERIODIC_HEALTH_FUNNEL:
+ case SPELL_AURA_PERIODIC_ENERGIZE:
+ case SPELL_AURA_OBS_MOD_HEALTH:
+ case SPELL_AURA_OBS_MOD_POWER:
+ case SPELL_AURA_POWER_BURN_MANA:
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT;
+ break;
}
switch (spellInfo->Effects[j].Effect)
@@ -2646,6 +2667,16 @@ void SpellMgr::LoadSpellCustomAttr()
case SPELL_EFFECT_HEAL:
spellInfo->AttributesCu |= SPELL_ATTR0_CU_DIRECT_DAMAGE;
break;
+ case SPELL_EFFECT_POWER_DRAIN:
+ case SPELL_EFFECT_POWER_BURN:
+ case SPELL_EFFECT_HEAL_MAX_HEALTH:
+ case SPELL_EFFECT_HEALTH_LEECH:
+ case SPELL_EFFECT_HEAL_PCT:
+ case SPELL_EFFECT_ENERGIZE_PCT:
+ case SPELL_EFFECT_ENERGIZE:
+ case SPELL_EFFECT_HEAL_MECHANICAL:
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT;
+ break;
case SPELL_EFFECT_CHARGE:
case SPELL_EFFECT_CHARGE_DEST:
case SPELL_EFFECT_JUMP:
diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h
index e8ac3ce9862..64d21b7c3a5 100755
--- a/src/server/game/Spells/SpellMgr.h
+++ b/src/server/game/Spells/SpellMgr.h
@@ -349,7 +349,14 @@ enum SpellGroupStackRule
typedef std::map<SpellGroup, SpellGroupStackRule> SpellGroupStackMap;
-typedef std::map<uint32, uint16> SpellThreatMap;
+struct SpellThreatEntry
+{
+ int32 flatMod; // flat threat-value for this Spell - default: 0
+ float pctMod; // threat-multiplier for this Spell - default: 1.0f
+ float apPctMod; // Pct of AP that is added as Threat - default: 0.0f
+};
+
+typedef std::map<uint32, SpellThreatEntry> SpellThreatMap;
// Spell script target related declarations (accessed using SpellMgr functions)
enum SpellScriptTargetType
@@ -603,7 +610,7 @@ class SpellMgr
SpellBonusEntry const* GetSpellBonusData(uint32 spellId) const;
// Spell threat table
- uint16 GetSpellThreat(uint32 spellid) const;
+ SpellThreatEntry const* GetSpellThreatEntry(uint32 spellID) const;
SkillLineAbilityMapBounds GetSkillLineAbilityMapBounds(uint32 spell_id) const;