aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorariel- <ariel-@users.noreply.github.com>2016-10-17 01:52:40 -0300
committerariel- <ariel-@users.noreply.github.com>2016-10-17 01:52:40 -0300
commit9b0fa51022fba3d5ece96dd0ac8399be01ea5b0f (patch)
treeaec7c19fea709094e28d287154dff6ae6168b6ef
parentf4a10571f74450daf26a5b0c5bd0f3114c231120 (diff)
Core/Globals: compute aura diminishing return info at startup and cache it
Core/Entities: Save diminish return on an array instead of a linked list
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp99
-rw-r--r--src/server/game/Entities/Unit/Unit.h24
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h4
-rw-r--r--src/server/game/Spells/Spell.cpp27
-rw-r--r--src/server/game/Spells/Spell.h4
-rw-r--r--src/server/game/Spells/SpellInfo.cpp333
-rw-r--r--src/server/game/Spells/SpellInfo.h419
-rw-r--r--src/server/game/Spells/SpellMgr.cpp311
-rw-r--r--src/server/game/Spells/SpellMgr.h8
-rw-r--r--src/server/game/World/World.cpp3
10 files changed, 648 insertions, 584 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 95f16a88c80..370600861ef 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -9756,63 +9756,56 @@ void Unit::ModSpellDurationTime(SpellInfo const* spellInfo, int32 & duration, Sp
DiminishingLevels Unit::GetDiminishing(DiminishingGroup group)
{
- for (Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
- {
- if (i->DRGroup != group)
- continue;
-
- if (!i->hitCount)
- return DIMINISHING_LEVEL_1;
+ DiminishingReturn& diminish = m_Diminishing[group];
+ if (!diminish.hitCount)
+ return DIMINISHING_LEVEL_1;
- if (!i->hitTime)
- return DIMINISHING_LEVEL_1;
+ if (!diminish.hitTime)
+ return DIMINISHING_LEVEL_1;
- // If last spell was cast more than 15 seconds ago - reset the count.
- if (i->stack == 0 && getMSTimeDiff(i->hitTime, getMSTime()) > 15000)
- {
- i->hitCount = DIMINISHING_LEVEL_1;
- return DIMINISHING_LEVEL_1;
- }
- // or else increase the count.
- else
- return DiminishingLevels(i->hitCount);
+ // If last spell was cast more than 15 seconds ago - reset the count.
+ if (!diminish.stack && GetMSTimeDiffToNow(diminish.hitTime) > 15000)
+ {
+ diminish.hitCount = DIMINISHING_LEVEL_1;
+ return DIMINISHING_LEVEL_1;
}
- return DIMINISHING_LEVEL_1;
+
+ return DiminishingLevels(diminish.hitCount);
}
-void Unit::IncrDiminishing(DiminishingGroup group)
+void Unit::IncrDiminishing(SpellInfo const* auraSpellInfo, bool triggered)
{
+ DiminishingGroup const group = auraSpellInfo->GetDiminishingReturnsGroupForSpell(triggered);
+ DiminishingLevels const maxLevel = auraSpellInfo->GetDiminishingReturnsMaxLevel(triggered);
+
// Checking for existing in the table
- for (Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
- {
- if (i->DRGroup != group)
- continue;
- if (int32(i->hitCount) < GetDiminishingReturnsMaxLevel(group))
- i->hitCount += 1;
- return;
- }
- m_Diminishing.push_back(DiminishingReturn(group, getMSTime(), DIMINISHING_LEVEL_2));
+ DiminishingReturn& diminish = m_Diminishing[group];
+ if (static_cast<int32>(diminish.hitCount) < maxLevel)
+ ++diminish.hitCount;
}
-float Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration, Unit* caster, DiminishingLevels Level, int32 limitduration)
+float Unit::ApplyDiminishingToDuration(SpellInfo const* auraSpellInfo, bool triggered, int32& duration, Unit* caster, DiminishingLevels previousLevel)
{
+ DiminishingGroup const group = auraSpellInfo->GetDiminishingReturnsGroupForSpell(triggered);
if (duration == -1 || group == DIMINISHING_NONE)
return 1.0f;
+ int32 const limitDuration = auraSpellInfo->GetDiminishingReturnsLimitDuration(triggered);
+
// test pet/charm masters instead pets/charmeds
- Unit const* tarGetOwner = GetCharmerOrOwner();
+ Unit const* targetOwner = GetCharmerOrOwner();
Unit const* casterOwner = caster->GetCharmerOrOwner();
// Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
- if (limitduration > 0 && duration > limitduration)
+ if (limitDuration > 0 && duration > limitDuration)
{
- Unit const* target = tarGetOwner ? tarGetOwner : this;
+ Unit const* target = targetOwner ? targetOwner : this;
Unit const* source = casterOwner ? casterOwner : caster;
if ((target->GetTypeId() == TYPEID_PLAYER
|| target->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_ALL_DIMINISH)
&& source->GetTypeId() == TYPEID_PLAYER)
- duration = limitduration;
+ duration = limitDuration;
}
float mod = 1.0f;
@@ -9821,7 +9814,7 @@ float Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,
{
if (GetTypeId() == TYPEID_UNIT && (ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_TAUNT_DIMINISH))
{
- DiminishingLevels diminish = Level;
+ DiminishingLevels diminish = previousLevel;
switch (diminish)
{
case DIMINISHING_LEVEL_1: break;
@@ -9834,12 +9827,12 @@ float Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,
}
}
// Some diminishings applies to mobs too (for example, Stun)
- else if ((GetDiminishingReturnsGroupType(group) == DRTYPE_PLAYER
- && ((tarGetOwner ? (tarGetOwner->GetTypeId() == TYPEID_PLAYER) : (GetTypeId() == TYPEID_PLAYER))
+ else if ((auraSpellInfo->GetDiminishingReturnsGroupType(triggered) == DRTYPE_PLAYER
+ && ((targetOwner ? (targetOwner->GetTypeId() == TYPEID_PLAYER) : (GetTypeId() == TYPEID_PLAYER))
|| (GetTypeId() == TYPEID_UNIT && ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_ALL_DIMINISH)))
- || GetDiminishingReturnsGroupType(group) == DRTYPE_ALL)
+ || auraSpellInfo->GetDiminishingReturnsGroupType(triggered) == DRTYPE_ALL)
{
- DiminishingLevels diminish = Level;
+ DiminishingLevels diminish = previousLevel;
switch (diminish)
{
case DIMINISHING_LEVEL_1: break;
@@ -9857,24 +9850,26 @@ float Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,
void Unit::ApplyDiminishingAura(DiminishingGroup group, bool apply)
{
// Checking for existing in the table
- for (Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
+ DiminishingReturn& diminish = m_Diminishing[group];
+
+ if (apply)
+ ++diminish.stack;
+ else if (diminish.stack)
{
- if (i->DRGroup != group)
- continue;
+ --diminish.stack;
- if (apply)
- i->stack += 1;
- else if (i->stack)
- {
- i->stack -= 1;
- // Remember time after last aura from group removed
- if (i->stack == 0)
- i->hitTime = getMSTime();
- }
- break;
+ // Remember time after last aura from group removed
+ if (!diminish.stack)
+ diminish.hitTime = getMSTime();
}
}
+void Unit::ClearDiminishings()
+{
+ for (uint32 i = 0; i < DIMINISHING_MAX; ++i)
+ m_Diminishing[i].Clear();
+}
+
float Unit::GetSpellMaxRangeForTarget(Unit const* target, SpellInfo const* spellInfo) const
{
if (!spellInfo->RangeEntry)
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 06aa2db8e0b..92c9554800a 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -802,11 +802,15 @@ namespace Movement{
struct DiminishingReturn
{
- DiminishingReturn(DiminishingGroup group, uint32 t, uint32 count)
- : DRGroup(group), stack(0), hitTime(t), hitCount(count)
- { }
+ DiminishingReturn() : stack(0), hitTime(0), hitCount(DIMINISHING_LEVEL_1) { }
+
+ void Clear()
+ {
+ stack = 0;
+ hitTime = 0;
+ hitCount = DIMINISHING_LEVEL_1;
+ }
- DiminishingGroup DRGroup;
uint16 stack;
uint32 hitTime;
uint32 hitCount;
@@ -1256,7 +1260,7 @@ class TC_GAME_API Unit : public WorldObject
typedef std::list<AuraEffect*> AuraEffectList;
typedef std::list<Aura*> AuraList;
typedef std::list<AuraApplication *> AuraApplicationList;
- typedef std::list<DiminishingReturn> Diminishing;
+ typedef std::array<DiminishingReturn, DIMINISHING_MAX> Diminishing;
typedef std::deque<std::pair<uint8 /*procEffectMask*/, AuraApplication*>> AuraApplicationProcContainer;
@@ -1273,11 +1277,11 @@ class TC_GAME_API Unit : public WorldObject
void CleanupBeforeRemoveFromMap(bool finalCleanup);
void CleanupsBeforeDelete(bool finalCleanup = true) override; // used in ~Creature/~Player (or before mass creature delete to remove cross-references to already deleted units)
- DiminishingLevels GetDiminishing(DiminishingGroup group);
- void IncrDiminishing(DiminishingGroup group);
- float ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration, Unit* caster, DiminishingLevels Level, int32 limitduration);
- void ApplyDiminishingAura(DiminishingGroup group, bool apply);
- void ClearDiminishings() { m_Diminishing.clear(); }
+ DiminishingLevels GetDiminishing(DiminishingGroup group);
+ void IncrDiminishing(SpellInfo const* auraSpellInfo, bool triggered);
+ float ApplyDiminishingToDuration(SpellInfo const* auraSpellInfo, bool triggered, int32& duration, Unit* caster, DiminishingLevels previousLevel);
+ void ApplyDiminishingAura(DiminishingGroup group, bool apply);
+ void ClearDiminishings();
// target dependent range checks
float GetSpellMaxRangeForTarget(Unit const* target, SpellInfo const* spellInfo) const;
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index f7c440ce8bc..ce0c749c294 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -3136,7 +3136,9 @@ enum DiminishingGroup : uint16
DIMINISHING_SLEEP = 17,
DIMINISHING_TAUNT = 18,
DIMINISHING_LIMITONLY = 19,
- DIMINISHING_DRAGONS_BREATH = 20
+ DIMINISHING_DRAGONS_BREATH = 20,
+
+ DIMINISHING_MAX
};
enum SummonCategory
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 22456c90d7f..3e7783cfc62 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -586,8 +586,6 @@ m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerO
destTarget = NULL;
damage = 0;
effectHandleMode = SPELL_EFFECT_HANDLE_LAUNCH;
- m_diminishLevel = DIMINISHING_LEVEL_1;
- m_diminishGroup = DIMINISHING_NONE;
m_damage = 0;
m_healing = 0;
m_procAttacker = 0;
@@ -2588,16 +2586,19 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
aura_effmask |= 1 << i;
// Get Data Needed for Diminishing Returns, some effects may have multiple auras, so this must be done on spell hit, not aura add
- m_diminishGroup = GetDiminishingReturnsGroupForSpell(m_spellInfo, m_triggeredByAuraSpell != nullptr);
- if (m_diminishGroup && aura_effmask)
+ bool const triggered = m_triggeredByAuraSpell != nullptr;
+ DiminishingGroup const diminishGroup = m_spellInfo->GetDiminishingReturnsGroupForSpell(triggered);
+
+ DiminishingLevels diminishLevel = DIMINISHING_LEVEL_1;
+ if (diminishGroup && aura_effmask)
{
- m_diminishLevel = unit->GetDiminishing(m_diminishGroup);
- DiminishingReturnsType type = GetDiminishingReturnsGroupType(m_diminishGroup);
+ diminishLevel = unit->GetDiminishing(diminishGroup);
+ DiminishingReturnsType type = m_spellInfo->GetDiminishingReturnsGroupType(triggered);
// Increase Diminishing on unit, current informations for actually casts will use values above
if ((type == DRTYPE_PLAYER &&
(unit->GetCharmerOrOwnerPlayerOrPlayerItself() || (unit->GetTypeId() == TYPEID_UNIT && unit->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_ALL_DIMINISH))) ||
type == DRTYPE_ALL)
- unit->IncrDiminishing(m_diminishGroup);
+ unit->IncrDiminishing(m_spellInfo, triggered);
}
if (aura_effmask)
@@ -2640,8 +2641,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
// Now Reduce spell duration using data received at spell hit
int32 duration = m_spellAura->GetMaxDuration();
- int32 limitduration = GetDiminishingReturnsLimitDuration(m_diminishGroup, aurSpellInfo);
- float diminishMod = unit->ApplyDiminishingToDuration(m_diminishGroup, duration, m_originalCaster, m_diminishLevel, limitduration);
+ float diminishMod = unit->ApplyDiminishingToDuration(aurSpellInfo, triggered, duration, m_originalCaster, diminishLevel);
// unit is immune to aura if it was diminished to 0 duration
if (diminishMod == 0.0f)
@@ -2656,7 +2656,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
}
else
{
- ((UnitAura*)m_spellAura)->SetDiminishGroup(m_diminishGroup);
+ ((UnitAura*)m_spellAura)->SetDiminishGroup(diminishGroup);
bool positive = m_spellAura->GetSpellInfo()->IsPositive();
if (AuraApplication* aurApp = m_spellAura->GetApplicationOfTarget(m_originalCaster->GetGUID()))
@@ -3457,9 +3457,6 @@ uint64 Spell::handle_delayed(uint64 t_offset)
void Spell::_handle_immediate_phase()
{
m_spellAura = NULL;
- // initialize Diminishing Returns Data
- m_diminishLevel = DIMINISHING_LEVEL_1;
- m_diminishGroup = DIMINISHING_NONE;
// handle some immediate features of the spell here
HandleThreatSpells();
@@ -4692,7 +4689,7 @@ void Spell::HandleThreatSpells()
continue;
// positive spells distribute threat among all units that are in combat with target, like healing
- if (m_spellInfo->_IsPositiveSpell())
+ if (m_spellInfo->IsPositive())
target->getHostileRefManager().threatAssist(m_caster, threatToAdd, m_spellInfo);
// for negative spells threat gets distributed among affected targets
else
@@ -4703,7 +4700,7 @@ void Spell::HandleThreatSpells()
target->AddThreat(m_caster, threatToAdd, m_spellInfo->GetSchoolMask(), m_spellInfo);
}
}
- TC_LOG_DEBUG("spells", "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()));
+ TC_LOG_DEBUG("spells", "Spell %u, added an additional %f threat for %s %u target(s)", m_spellInfo->Id, threat, m_spellInfo->IsPositive() ? "assisting" : "harming", uint32(m_UniqueTargetInfo.size()));
}
void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOTarget, uint32 i, SpellEffectHandleMode mode)
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 5823ea72dbd..5087ececa09 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -561,10 +561,6 @@ class TC_GAME_API Spell
// used in effects handlers
Aura* m_spellAura;
- // this is set in Spell Hit, but used in Apply Aura handler
- DiminishingLevels m_diminishLevel;
- DiminishingGroup m_diminishGroup;
-
// -------------------------------------------
GameObject* focusObject;
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index ff5cd925c8c..8589a8bc98e 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -2108,6 +2108,339 @@ void SpellInfo::_LoadSpellSpecific()
}();
}
+void SpellInfo::_LoadSpellDiminishInfo()
+{
+ auto diminishingGroupCompute = [this](bool triggered) -> DiminishingGroup
+ {
+ if (IsPositive())
+ return DIMINISHING_NONE;
+
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if (Effects[i].ApplyAuraName == SPELL_AURA_MOD_TAUNT)
+ return DIMINISHING_TAUNT;
+ }
+
+ // Explicit Diminishing Groups
+ switch (SpellFamilyName)
+ {
+ case SPELLFAMILY_GENERIC:
+ {
+ // Pet charge effects (Infernal Awakening, Demon Charge)
+ if (SpellVisual[0] == 2816 && SpellIconID == 15)
+ return DIMINISHING_CONTROLLED_STUN;
+ // Frost Tomb
+ else if (Id == 48400)
+ return DIMINISHING_NONE;
+ // Gnaw
+ else if (Id == 47481)
+ return DIMINISHING_CONTROLLED_STUN;
+ // ToC Icehowl Arctic Breath
+ else if (SpellVisual[0] == 14153)
+ return DIMINISHING_NONE;
+ // Black Plague
+ else if (Id == 64155)
+ return DIMINISHING_NONE;
+ // Screams of the Dead (King Ymiron)
+ else if (Id == 51750)
+ return DIMINISHING_NONE;
+ break;
+ }
+ // Event spells
+ case SPELLFAMILY_UNK1:
+ return DIMINISHING_NONE;
+ case SPELLFAMILY_MAGE:
+ {
+ // Frostbite
+ if (SpellFamilyFlags[1] & 0x80000000)
+ return DIMINISHING_ROOT;
+ // Shattered Barrier
+ else if (SpellVisual[0] == 12297)
+ return DIMINISHING_ROOT;
+ // Deep Freeze
+ else if (SpellIconID == 2939 && SpellVisual[0] == 9963)
+ return DIMINISHING_CONTROLLED_STUN;
+ // Frost Nova / Freeze (Water Elemental)
+ else if (SpellIconID == 193)
+ return DIMINISHING_CONTROLLED_ROOT;
+ // Dragon's Breath
+ else if (SpellFamilyFlags[0] & 0x800000)
+ return DIMINISHING_DRAGONS_BREATH;
+ break;
+ }
+ case SPELLFAMILY_WARRIOR:
+ {
+ // Hamstring - limit duration to 10s in PvP
+ if (SpellFamilyFlags[0] & 0x2)
+ return DIMINISHING_LIMITONLY;
+ // Charge Stun (own diminishing)
+ else if (SpellFamilyFlags[0] & 0x01000000)
+ return DIMINISHING_CHARGE;
+ break;
+ }
+ case SPELLFAMILY_WARLOCK:
+ {
+ // Curses/etc
+ if ((SpellFamilyFlags[0] & 0x80000000) || (SpellFamilyFlags[1] & 0x200))
+ return DIMINISHING_LIMITONLY;
+ // Seduction
+ else if (SpellFamilyFlags[1] & 0x10000000)
+ return DIMINISHING_FEAR;
+ break;
+ }
+ case SPELLFAMILY_DRUID:
+ {
+ // Pounce
+ if (SpellFamilyFlags[0] & 0x20000)
+ return DIMINISHING_OPENING_STUN;
+ // Cyclone
+ else if (SpellFamilyFlags[1] & 0x20)
+ return DIMINISHING_CYCLONE;
+ // Entangling Roots
+ // Nature's Grasp
+ else if (SpellFamilyFlags[0] & 0x00000200)
+ return DIMINISHING_CONTROLLED_ROOT;
+ // Faerie Fire
+ else if (SpellFamilyFlags[0] & 0x400)
+ return DIMINISHING_LIMITONLY;
+ break;
+ }
+ case SPELLFAMILY_ROGUE:
+ {
+ // Gouge
+ if (SpellFamilyFlags[0] & 0x8)
+ return DIMINISHING_DISORIENT;
+ // Blind
+ else if (SpellFamilyFlags[0] & 0x1000000)
+ return DIMINISHING_FEAR;
+ // Cheap Shot
+ else if (SpellFamilyFlags[0] & 0x400)
+ return DIMINISHING_OPENING_STUN;
+ // Crippling poison - Limit to 10 seconds in PvP (No SpellFamilyFlags)
+ else if (SpellIconID == 163)
+ return DIMINISHING_LIMITONLY;
+ break;
+ }
+ case SPELLFAMILY_HUNTER:
+ {
+ // Hunter's Mark
+ if ((SpellFamilyFlags[0] & 0x400) && SpellIconID == 538)
+ return DIMINISHING_LIMITONLY;
+ // Scatter Shot (own diminishing)
+ else if ((SpellFamilyFlags[0] & 0x40000) && SpellIconID == 132)
+ return DIMINISHING_SCATTER_SHOT;
+ // Entrapment (own diminishing)
+ else if (SpellVisual[0] == 7484 && SpellIconID == 20)
+ return DIMINISHING_ENTRAPMENT;
+ // Wyvern Sting mechanic is MECHANIC_SLEEP but the diminishing is DIMINISHING_DISORIENT
+ else if ((SpellFamilyFlags[1] & 0x1000) && SpellIconID == 1721)
+ return DIMINISHING_DISORIENT;
+ // Freezing Arrow
+ else if (SpellFamilyFlags[0] & 0x8)
+ return DIMINISHING_DISORIENT;
+ break;
+ }
+ case SPELLFAMILY_PALADIN:
+ {
+ // Judgement of Justice - limit duration to 10s in PvP
+ if (SpellFamilyFlags[0] & 0x100000)
+ return DIMINISHING_LIMITONLY;
+ // Turn Evil
+ else if ((SpellFamilyFlags[1] & 0x804000) && SpellIconID == 309)
+ return DIMINISHING_FEAR;
+ break;
+ }
+ case SPELLFAMILY_SHAMAN:
+ {
+ // Storm, Earth and Fire - Earthgrab
+ if (SpellFamilyFlags[2] & 0x4000)
+ return DIMINISHING_NONE;
+ break;
+ }
+ case SPELLFAMILY_DEATHKNIGHT:
+ {
+ // Hungering Cold (no flags)
+ if (SpellIconID == 2797)
+ return DIMINISHING_DISORIENT;
+ // Mark of Blood
+ else if ((SpellFamilyFlags[0] & 0x10000000) && SpellIconID == 2285)
+ return DIMINISHING_LIMITONLY;
+ break;
+ }
+ default:
+ break;
+ }
+
+ // Lastly - Set diminishing depending on mechanic
+ uint32 mechanic = GetAllEffectsMechanicMask();
+ if (mechanic & (1 << MECHANIC_CHARM))
+ return DIMINISHING_MIND_CONTROL;
+ if (mechanic & (1 << MECHANIC_SILENCE))
+ return DIMINISHING_SILENCE;
+ if (mechanic & (1 << MECHANIC_SLEEP))
+ return DIMINISHING_SLEEP;
+ if (mechanic & ((1 << MECHANIC_SAPPED) | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_SHACKLE)))
+ return DIMINISHING_DISORIENT;
+ // Mechanic Knockout, except Blast Wave
+ if (mechanic & (1 << MECHANIC_KNOCKOUT) && SpellIconID != 292)
+ return DIMINISHING_DISORIENT;
+ if (mechanic & (1 << MECHANIC_DISARM))
+ return DIMINISHING_DISARM;
+ if (mechanic & (1 << MECHANIC_FEAR))
+ return DIMINISHING_FEAR;
+ if (mechanic & (1 << MECHANIC_STUN))
+ return triggered ? DIMINISHING_STUN : DIMINISHING_CONTROLLED_STUN;
+ if (mechanic & (1 << MECHANIC_BANISH))
+ return DIMINISHING_BANISH;
+ if (mechanic & (1 << MECHANIC_ROOT))
+ return triggered ? DIMINISHING_ROOT : DIMINISHING_CONTROLLED_ROOT;
+ if (mechanic & (1 << MECHANIC_HORROR))
+ return DIMINISHING_HORROR;
+
+ return DIMINISHING_NONE;
+ };
+
+ auto diminishingTypeCompute = [](DiminishingGroup group) -> DiminishingReturnsType
+ {
+ switch (group)
+ {
+ case DIMINISHING_TAUNT:
+ case DIMINISHING_CONTROLLED_STUN:
+ case DIMINISHING_STUN:
+ case DIMINISHING_OPENING_STUN:
+ case DIMINISHING_CYCLONE:
+ case DIMINISHING_CHARGE:
+ return DRTYPE_ALL;
+ case DIMINISHING_LIMITONLY:
+ case DIMINISHING_NONE:
+ return DRTYPE_NONE;
+ default:
+ return DRTYPE_PLAYER;
+ }
+ };
+
+ auto diminishingMaxLevelCompute = [](DiminishingGroup group) -> DiminishingLevels
+ {
+ switch (group)
+ {
+ case DIMINISHING_TAUNT:
+ return DIMINISHING_LEVEL_TAUNT_IMMUNE;
+ default:
+ return DIMINISHING_LEVEL_IMMUNE;
+ }
+ };
+
+ auto diminishingLimitDurationCompute = [this](DiminishingGroup group) -> int32
+ {
+ auto isGroupDurationLimited = [group]() -> bool
+ {
+ switch (group)
+ {
+ case DIMINISHING_BANISH:
+ case DIMINISHING_CONTROLLED_STUN:
+ case DIMINISHING_CONTROLLED_ROOT:
+ case DIMINISHING_CYCLONE:
+ case DIMINISHING_DISORIENT:
+ case DIMINISHING_ENTRAPMENT:
+ case DIMINISHING_FEAR:
+ case DIMINISHING_HORROR:
+ case DIMINISHING_MIND_CONTROL:
+ case DIMINISHING_OPENING_STUN:
+ case DIMINISHING_ROOT:
+ case DIMINISHING_STUN:
+ case DIMINISHING_SLEEP:
+ case DIMINISHING_LIMITONLY:
+ return true;
+ default:
+ return false;
+ }
+ };
+
+ if (!isGroupDurationLimited())
+ return 0;
+
+ // Explicit diminishing duration
+ switch (SpellFamilyName)
+ {
+ case SPELLFAMILY_DRUID:
+ {
+ // Faerie Fire - limit to 40 seconds in PvP (3.1)
+ if (SpellFamilyFlags[0] & 0x400)
+ return 40 * IN_MILLISECONDS;
+ break;
+ }
+ case SPELLFAMILY_HUNTER:
+ {
+ // Wyvern Sting
+ if (SpellFamilyFlags[1] & 0x1000)
+ return 6 * IN_MILLISECONDS;
+ // Hunter's Mark
+ if (SpellFamilyFlags[0] & 0x400)
+ return 120 * IN_MILLISECONDS;
+ break;
+ }
+ case SPELLFAMILY_PALADIN:
+ {
+ // Repentance - limit to 6 seconds in PvP
+ if (SpellFamilyFlags[0] & 0x4)
+ return 6 * IN_MILLISECONDS;
+ break;
+ }
+ case SPELLFAMILY_WARLOCK:
+ {
+ // Banish - limit to 6 seconds in PvP
+ if (SpellFamilyFlags[1] & 0x8000000)
+ return 6 * IN_MILLISECONDS;
+ // Curse of Tongues - limit to 12 seconds in PvP
+ else if (SpellFamilyFlags[2] & 0x800)
+ return 12 * IN_MILLISECONDS;
+ // Curse of Elements - limit to 120 seconds in PvP
+ else if (SpellFamilyFlags[1] & 0x200)
+ return 120 * IN_MILLISECONDS;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return 10 * IN_MILLISECONDS;
+ };
+
+ SpellDiminishInfo triggeredInfo, normalInfo;
+ triggeredInfo.DiminishGroup = diminishingGroupCompute(true);
+ triggeredInfo.DiminishReturnType = diminishingTypeCompute(triggeredInfo.DiminishGroup);
+ triggeredInfo.DiminishMaxLevel = diminishingMaxLevelCompute(triggeredInfo.DiminishGroup);
+ triggeredInfo.DiminishDurationLimit = diminishingLimitDurationCompute(triggeredInfo.DiminishGroup);
+
+ normalInfo.DiminishGroup = diminishingGroupCompute(false);
+ normalInfo.DiminishReturnType = diminishingTypeCompute(normalInfo.DiminishGroup);
+ normalInfo.DiminishMaxLevel = diminishingMaxLevelCompute(normalInfo.DiminishGroup);
+ normalInfo.DiminishDurationLimit = diminishingLimitDurationCompute(normalInfo.DiminishGroup);
+
+ _diminishInfoTriggered = triggeredInfo;
+ _diminishInfoNonTriggered = normalInfo;
+}
+
+DiminishingGroup SpellInfo::GetDiminishingReturnsGroupForSpell(bool triggered) const
+{
+ return triggered ? _diminishInfoTriggered.DiminishGroup : _diminishInfoNonTriggered.DiminishGroup;
+}
+
+DiminishingReturnsType SpellInfo::GetDiminishingReturnsGroupType(bool triggered) const
+{
+ return triggered ? _diminishInfoTriggered.DiminishReturnType : _diminishInfoNonTriggered.DiminishReturnType;
+}
+
+DiminishingLevels SpellInfo::GetDiminishingReturnsMaxLevel(bool triggered) const
+{
+ return triggered ? _diminishInfoTriggered.DiminishMaxLevel : _diminishInfoNonTriggered.DiminishMaxLevel;
+}
+
+int32 SpellInfo::GetDiminishingReturnsLimitDuration(bool triggered) const
+{
+ return triggered ? _diminishInfoTriggered.DiminishDurationLimit : _diminishInfoNonTriggered.DiminishDurationLimit;
+}
+
float SpellInfo::GetMinRange(bool positive) const
{
if (!RangeEntry)
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index 2f94555e493..b2566ecf533 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -28,6 +28,7 @@ class Unit;
class Player;
class Item;
class Spell;
+class SpellMgr;
class SpellInfo;
struct SpellChainNode;
struct SpellTargetPosition;
@@ -291,207 +292,227 @@ private:
static StaticData _data[TOTAL_SPELL_EFFECTS];
};
-class TC_GAME_API SpellInfo
+struct TC_GAME_API SpellDiminishInfo
{
-public:
- uint32 Id;
- SpellCategoryEntry const* CategoryEntry;
- uint32 Dispel;
- uint32 Mechanic;
- uint32 Attributes;
- uint32 AttributesEx;
- uint32 AttributesEx2;
- uint32 AttributesEx3;
- uint32 AttributesEx4;
- uint32 AttributesEx5;
- uint32 AttributesEx6;
- uint32 AttributesEx7;
- uint32 AttributesCu;
- uint64 Stances;
- uint64 StancesNot;
- uint32 Targets;
- uint32 TargetCreatureType;
- uint32 RequiresSpellFocus;
- uint32 FacingCasterFlags;
- uint32 CasterAuraState;
- uint32 TargetAuraState;
- uint32 CasterAuraStateNot;
- uint32 TargetAuraStateNot;
- uint32 CasterAuraSpell;
- uint32 TargetAuraSpell;
- uint32 ExcludeCasterAuraSpell;
- uint32 ExcludeTargetAuraSpell;
- SpellCastTimesEntry const* CastTimeEntry;
- uint32 RecoveryTime;
- uint32 CategoryRecoveryTime;
- uint32 StartRecoveryCategory;
- uint32 StartRecoveryTime;
- uint32 InterruptFlags;
- uint32 AuraInterruptFlags;
- uint32 ChannelInterruptFlags;
- uint32 ProcFlags;
- uint32 ProcChance;
- uint32 ProcCharges;
- uint32 MaxLevel;
- uint32 BaseLevel;
- uint32 SpellLevel;
- SpellDurationEntry const* DurationEntry;
- uint32 PowerType;
- uint32 ManaCost;
- uint32 ManaCostPerlevel;
- uint32 ManaPerSecond;
- uint32 ManaPerSecondPerLevel;
- uint32 ManaCostPercentage;
- uint32 RuneCostID;
- SpellRangeEntry const* RangeEntry;
- float Speed;
- uint32 StackAmount;
- uint32 Totem[2];
- int32 Reagent[MAX_SPELL_REAGENTS];
- uint32 ReagentCount[MAX_SPELL_REAGENTS];
- int32 EquippedItemClass;
- int32 EquippedItemSubClassMask;
- int32 EquippedItemInventoryTypeMask;
- uint32 TotemCategory[2];
- uint32 SpellVisual[2];
- uint32 SpellIconID;
- uint32 ActiveIconID;
- char* SpellName[16];
- char* Rank[16];
- uint32 MaxTargetLevel;
- uint32 MaxAffectedTargets;
- uint32 SpellFamilyName;
- flag96 SpellFamilyFlags;
- uint32 DmgClass;
- uint32 PreventionType;
- int32 AreaGroupId;
- uint32 SchoolMask;
- SpellEffectInfo Effects[MAX_SPELL_EFFECTS];
- uint32 ExplicitTargetMask;
- SpellChainNode const* ChainEntry;
-
- SpellInfo(SpellEntry const* spellEntry);
- ~SpellInfo();
-
- uint32 GetCategory() const;
- bool HasEffect(SpellEffects effect) const;
- bool HasAura(AuraType aura) const;
- bool HasAreaAuraEffect() const;
-
- inline bool HasAttribute(SpellAttr0 attribute) const { return !!(Attributes & attribute); }
- inline bool HasAttribute(SpellAttr1 attribute) const { return !!(AttributesEx & attribute); }
- inline bool HasAttribute(SpellAttr2 attribute) const { return !!(AttributesEx2 & attribute); }
- inline bool HasAttribute(SpellAttr3 attribute) const { return !!(AttributesEx3 & attribute); }
- inline bool HasAttribute(SpellAttr4 attribute) const { return !!(AttributesEx4 & attribute); }
- inline bool HasAttribute(SpellAttr5 attribute) const { return !!(AttributesEx5 & attribute); }
- inline bool HasAttribute(SpellAttr6 attribute) const { return !!(AttributesEx6 & attribute); }
- inline bool HasAttribute(SpellAttr7 attribute) const { return !!(AttributesEx7 & attribute); }
- inline bool HasAttribute(SpellCustomAttributes customAttribute) const { return !!(AttributesCu & customAttribute); }
-
- bool IsExplicitDiscovery() const;
- bool IsLootCrafting() const;
- bool IsQuestTame() const;
- bool IsProfessionOrRiding() const;
- bool IsProfession() const;
- bool IsPrimaryProfession() const;
- bool IsPrimaryProfessionFirstRank() const;
- bool IsAbilityLearnedWithProfession() const;
- bool IsAbilityOfSkillType(uint32 skillType) const;
-
- bool IsAffectingArea() const;
- bool IsTargetingArea() const;
- bool NeedsExplicitUnitTarget() const;
- bool NeedsToBeTriggeredByCaster(SpellInfo const* triggeringSpell) const;
-
- bool IsPassive() const;
- bool IsAutocastable() const;
- bool IsStackableWithRanks() const;
- bool IsPassiveStackableWithRanks() const;
- bool IsMultiSlotAura() const;
- bool IsStackableOnOneSlotWithDifferentCasters() const;
- bool IsCooldownStartedOnEvent() const;
- bool IsDeathPersistent() const;
- bool IsRequiringDeadTarget() const;
- bool IsAllowingDeadTarget() const;
- bool IsGroupBuff() const;
- bool CanBeUsedInCombat() const;
- bool IsPositive() const;
- bool IsPositiveEffect(uint8 effIndex) const;
- bool IsChanneled() const;
- bool NeedsComboPoints() const;
- bool IsBreakingStealth() const;
- bool IsRangedWeaponSpell() const;
- bool IsAutoRepeatRangedSpell() const;
- bool HasInitialAggro() const;
-
- bool IsAffectedBySpellMods() const;
- bool IsAffectedBySpellMod(SpellModifier const* mod) const;
-
- bool CanPierceImmuneAura(SpellInfo const* aura) const;
- bool CanDispelAura(SpellInfo const* aura) const;
-
- bool IsSingleTarget() const;
- bool IsAuraExclusiveBySpecificWith(SpellInfo const* spellInfo) const;
- bool IsAuraExclusiveBySpecificPerCasterWith(SpellInfo const* spellInfo) const;
-
- SpellCastResult CheckShapeshift(uint32 form) const;
- SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL) const;
- SpellCastResult CheckTarget(Unit const* caster, WorldObject const* target, bool implicit = true) const;
- SpellCastResult CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget = NULL) const;
- SpellCastResult CheckVehicle(Unit const* caster) const;
- bool CheckTargetCreatureType(Unit const* target) const;
-
- SpellSchoolMask GetSchoolMask() const;
- uint32 GetAllEffectsMechanicMask() const;
- uint32 GetEffectMechanicMask(uint8 effIndex) const;
- uint32 GetSpellMechanicMaskByEffectMask(uint32 effectMask) const;
- Mechanics GetEffectMechanic(uint8 effIndex) const;
- bool HasAnyEffectMechanic() const;
- uint32 GetDispelMask() const;
- static uint32 GetDispelMask(DispelType type);
- uint32 GetExplicitTargetMask() const;
-
- AuraStateType GetAuraState() const;
- SpellSpecificType GetSpellSpecific() const;
-
- float GetMinRange(bool positive = false) const;
- float GetMaxRange(bool positive = false, Unit* caster = NULL, Spell* spell = NULL) const;
-
- int32 GetDuration() const;
- int32 GetMaxDuration() const;
-
- uint32 GetMaxTicks() const;
-
- uint32 CalcCastTime(Spell* spell = NULL) const;
- uint32 GetRecoveryTime() const;
-
- int32 CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) const;
-
- bool IsRanked() const;
- uint8 GetRank() const;
- SpellInfo const* GetFirstRankSpell() const;
- SpellInfo const* GetLastRankSpell() const;
- SpellInfo const* GetNextRankSpell() const;
- SpellInfo const* GetPrevRankSpell() const;
- SpellInfo const* GetAuraRankForLevel(uint8 level) const;
- bool IsRankOf(SpellInfo const* spellInfo) const;
- bool IsDifferentRankOf(SpellInfo const* spellInfo) const;
- bool IsHighRankOf(SpellInfo const* spellInfo) const;
-
- // loading helpers
- void _InitializeExplicitTargetMask();
- bool _IsPositiveEffect(uint8 effIndex, bool deep) const;
- bool _IsPositiveSpell() const;
- static bool _IsPositiveTarget(uint32 targetA, uint32 targetB);
- void _LoadSpellSpecific();
- void _LoadAuraState();
-
- // unloading helpers
- void _UnloadImplicitTargetConditionLists();
+ DiminishingGroup DiminishGroup = DIMINISHING_NONE;
+ DiminishingReturnsType DiminishReturnType = DRTYPE_NONE;
+ DiminishingLevels DiminishMaxLevel = DIMINISHING_LEVEL_IMMUNE;
+ int32 DiminishDurationLimit = 0;
+};
-private:
- SpellSpecificType _spellSpecific;
- AuraStateType _auraState;
+class TC_GAME_API SpellInfo
+{
+ friend class SpellMgr;
+
+ public:
+ uint32 Id;
+ SpellCategoryEntry const* CategoryEntry;
+ uint32 Dispel;
+ uint32 Mechanic;
+ uint32 Attributes;
+ uint32 AttributesEx;
+ uint32 AttributesEx2;
+ uint32 AttributesEx3;
+ uint32 AttributesEx4;
+ uint32 AttributesEx5;
+ uint32 AttributesEx6;
+ uint32 AttributesEx7;
+ uint32 AttributesCu;
+ uint64 Stances;
+ uint64 StancesNot;
+ uint32 Targets;
+ uint32 TargetCreatureType;
+ uint32 RequiresSpellFocus;
+ uint32 FacingCasterFlags;
+ uint32 CasterAuraState;
+ uint32 TargetAuraState;
+ uint32 CasterAuraStateNot;
+ uint32 TargetAuraStateNot;
+ uint32 CasterAuraSpell;
+ uint32 TargetAuraSpell;
+ uint32 ExcludeCasterAuraSpell;
+ uint32 ExcludeTargetAuraSpell;
+ SpellCastTimesEntry const* CastTimeEntry;
+ uint32 RecoveryTime;
+ uint32 CategoryRecoveryTime;
+ uint32 StartRecoveryCategory;
+ uint32 StartRecoveryTime;
+ uint32 InterruptFlags;
+ uint32 AuraInterruptFlags;
+ uint32 ChannelInterruptFlags;
+ uint32 ProcFlags;
+ uint32 ProcChance;
+ uint32 ProcCharges;
+ uint32 MaxLevel;
+ uint32 BaseLevel;
+ uint32 SpellLevel;
+ SpellDurationEntry const* DurationEntry;
+ uint32 PowerType;
+ uint32 ManaCost;
+ uint32 ManaCostPerlevel;
+ uint32 ManaPerSecond;
+ uint32 ManaPerSecondPerLevel;
+ uint32 ManaCostPercentage;
+ uint32 RuneCostID;
+ SpellRangeEntry const* RangeEntry;
+ float Speed;
+ uint32 StackAmount;
+ uint32 Totem[2];
+ int32 Reagent[MAX_SPELL_REAGENTS];
+ uint32 ReagentCount[MAX_SPELL_REAGENTS];
+ int32 EquippedItemClass;
+ int32 EquippedItemSubClassMask;
+ int32 EquippedItemInventoryTypeMask;
+ uint32 TotemCategory[2];
+ uint32 SpellVisual[2];
+ uint32 SpellIconID;
+ uint32 ActiveIconID;
+ char* SpellName[16];
+ char* Rank[16];
+ uint32 MaxTargetLevel;
+ uint32 MaxAffectedTargets;
+ uint32 SpellFamilyName;
+ flag96 SpellFamilyFlags;
+ uint32 DmgClass;
+ uint32 PreventionType;
+ int32 AreaGroupId;
+ uint32 SchoolMask;
+ SpellEffectInfo Effects[MAX_SPELL_EFFECTS];
+ uint32 ExplicitTargetMask;
+ SpellChainNode const* ChainEntry;
+
+ SpellInfo(SpellEntry const* spellEntry);
+ ~SpellInfo();
+
+ uint32 GetCategory() const;
+ bool HasEffect(SpellEffects effect) const;
+ bool HasAura(AuraType aura) const;
+ bool HasAreaAuraEffect() const;
+
+ inline bool HasAttribute(SpellAttr0 attribute) const { return !!(Attributes & attribute); }
+ inline bool HasAttribute(SpellAttr1 attribute) const { return !!(AttributesEx & attribute); }
+ inline bool HasAttribute(SpellAttr2 attribute) const { return !!(AttributesEx2 & attribute); }
+ inline bool HasAttribute(SpellAttr3 attribute) const { return !!(AttributesEx3 & attribute); }
+ inline bool HasAttribute(SpellAttr4 attribute) const { return !!(AttributesEx4 & attribute); }
+ inline bool HasAttribute(SpellAttr5 attribute) const { return !!(AttributesEx5 & attribute); }
+ inline bool HasAttribute(SpellAttr6 attribute) const { return !!(AttributesEx6 & attribute); }
+ inline bool HasAttribute(SpellAttr7 attribute) const { return !!(AttributesEx7 & attribute); }
+ inline bool HasAttribute(SpellCustomAttributes customAttribute) const { return !!(AttributesCu & customAttribute); }
+
+ bool IsExplicitDiscovery() const;
+ bool IsLootCrafting() const;
+ bool IsQuestTame() const;
+ bool IsProfessionOrRiding() const;
+ bool IsProfession() const;
+ bool IsPrimaryProfession() const;
+ bool IsPrimaryProfessionFirstRank() const;
+ bool IsAbilityLearnedWithProfession() const;
+ bool IsAbilityOfSkillType(uint32 skillType) const;
+
+ bool IsAffectingArea() const;
+ bool IsTargetingArea() const;
+ bool NeedsExplicitUnitTarget() const;
+ bool NeedsToBeTriggeredByCaster(SpellInfo const* triggeringSpell) const;
+
+ bool IsPassive() const;
+ bool IsAutocastable() const;
+ bool IsStackableWithRanks() const;
+ bool IsPassiveStackableWithRanks() const;
+ bool IsMultiSlotAura() const;
+ bool IsStackableOnOneSlotWithDifferentCasters() const;
+ bool IsCooldownStartedOnEvent() const;
+ bool IsDeathPersistent() const;
+ bool IsRequiringDeadTarget() const;
+ bool IsAllowingDeadTarget() const;
+ bool IsGroupBuff() const;
+ bool CanBeUsedInCombat() const;
+ bool IsPositive() const;
+ bool IsPositiveEffect(uint8 effIndex) const;
+ bool IsChanneled() const;
+ bool NeedsComboPoints() const;
+ bool IsBreakingStealth() const;
+ bool IsRangedWeaponSpell() const;
+ bool IsAutoRepeatRangedSpell() const;
+ bool HasInitialAggro() const;
+
+ bool IsAffectedBySpellMods() const;
+ bool IsAffectedBySpellMod(SpellModifier const* mod) const;
+
+ bool CanPierceImmuneAura(SpellInfo const* aura) const;
+ bool CanDispelAura(SpellInfo const* aura) const;
+
+ bool IsSingleTarget() const;
+ bool IsAuraExclusiveBySpecificWith(SpellInfo const* spellInfo) const;
+ bool IsAuraExclusiveBySpecificPerCasterWith(SpellInfo const* spellInfo) const;
+
+ SpellCastResult CheckShapeshift(uint32 form) const;
+ SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL) const;
+ SpellCastResult CheckTarget(Unit const* caster, WorldObject const* target, bool implicit = true) const;
+ SpellCastResult CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget = NULL) const;
+ SpellCastResult CheckVehicle(Unit const* caster) const;
+ bool CheckTargetCreatureType(Unit const* target) const;
+
+ SpellSchoolMask GetSchoolMask() const;
+ uint32 GetAllEffectsMechanicMask() const;
+ uint32 GetEffectMechanicMask(uint8 effIndex) const;
+ uint32 GetSpellMechanicMaskByEffectMask(uint32 effectMask) const;
+ Mechanics GetEffectMechanic(uint8 effIndex) const;
+ bool HasAnyEffectMechanic() const;
+ uint32 GetDispelMask() const;
+ static uint32 GetDispelMask(DispelType type);
+ uint32 GetExplicitTargetMask() const;
+
+ AuraStateType GetAuraState() const;
+ SpellSpecificType GetSpellSpecific() const;
+
+ float GetMinRange(bool positive = false) const;
+ float GetMaxRange(bool positive = false, Unit* caster = NULL, Spell* spell = NULL) const;
+
+ int32 GetDuration() const;
+ int32 GetMaxDuration() const;
+
+ uint32 GetMaxTicks() const;
+
+ uint32 CalcCastTime(Spell* spell = NULL) const;
+ uint32 GetRecoveryTime() const;
+
+ int32 CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) const;
+
+ bool IsRanked() const;
+ uint8 GetRank() const;
+ SpellInfo const* GetFirstRankSpell() const;
+ SpellInfo const* GetLastRankSpell() const;
+ SpellInfo const* GetNextRankSpell() const;
+ SpellInfo const* GetPrevRankSpell() const;
+ SpellInfo const* GetAuraRankForLevel(uint8 level) const;
+ bool IsRankOf(SpellInfo const* spellInfo) const;
+ bool IsDifferentRankOf(SpellInfo const* spellInfo) const;
+ bool IsHighRankOf(SpellInfo const* spellInfo) const;
+
+ // spell diminishing returns
+ DiminishingGroup GetDiminishingReturnsGroupForSpell(bool triggered) const;
+ DiminishingReturnsType GetDiminishingReturnsGroupType(bool triggered) const;
+ DiminishingLevels GetDiminishingReturnsMaxLevel(bool triggered) const;
+ int32 GetDiminishingReturnsLimitDuration(bool triggered) const;
+
+ private:
+ // loading helpers
+ void _InitializeExplicitTargetMask();
+ bool _IsPositiveEffect(uint8 effIndex, bool deep) const;
+ bool _IsPositiveSpell() const;
+ static bool _IsPositiveTarget(uint32 targetA, uint32 targetB);
+ void _LoadSpellSpecific();
+ void _LoadAuraState();
+ void _LoadSpellDiminishInfo();
+
+ // unloading helpers
+ void _UnloadImplicitTargetConditionLists();
+
+ SpellSpecificType _spellSpecific;
+ AuraStateType _auraState;
+
+ SpellDiminishInfo _diminishInfoNonTriggered;
+ SpellDiminishInfo _diminishInfoTriggered;
};
#endif // _SPELLINFO_H
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index badb5fc4997..3e42b62f9bb 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -51,302 +51,6 @@ bool IsPartOfSkillLine(uint32 skillId, uint32 spellId)
return false;
}
-DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto, bool triggered)
-{
- if (spellproto->IsPositive())
- return DIMINISHING_NONE;
-
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- {
- if (spellproto->Effects[i].ApplyAuraName == SPELL_AURA_MOD_TAUNT)
- return DIMINISHING_TAUNT;
- }
-
- // Explicit Diminishing Groups
- switch (spellproto->SpellFamilyName)
- {
- case SPELLFAMILY_GENERIC:
- {
- // Pet charge effects (Infernal Awakening, Demon Charge)
- if (spellproto->SpellVisual[0] == 2816 && spellproto->SpellIconID == 15)
- return DIMINISHING_CONTROLLED_STUN;
- // Frost Tomb
- else if (spellproto->Id == 48400)
- return DIMINISHING_NONE;
- // Gnaw
- else if (spellproto->Id == 47481)
- return DIMINISHING_CONTROLLED_STUN;
- // ToC Icehowl Arctic Breath
- else if (spellproto->SpellVisual[0] == 14153)
- return DIMINISHING_NONE;
- // Black Plague
- else if (spellproto->Id == 64155)
- return DIMINISHING_NONE;
- // Screams of the Dead (King Ymiron)
- else if (spellproto->Id == 51750)
- return DIMINISHING_NONE;
- break;
- }
- // Event spells
- case SPELLFAMILY_UNK1:
- return DIMINISHING_NONE;
- case SPELLFAMILY_MAGE:
- {
- // Frostbite
- if (spellproto->SpellFamilyFlags[1] & 0x80000000)
- return DIMINISHING_ROOT;
- // Shattered Barrier
- else if (spellproto->SpellVisual[0] == 12297)
- return DIMINISHING_ROOT;
- // Deep Freeze
- else if (spellproto->SpellIconID == 2939 && spellproto->SpellVisual[0] == 9963)
- return DIMINISHING_CONTROLLED_STUN;
- // Frost Nova / Freeze (Water Elemental)
- else if (spellproto->SpellIconID == 193)
- return DIMINISHING_CONTROLLED_ROOT;
- // Dragon's Breath
- else if (spellproto->SpellFamilyFlags[0] & 0x800000)
- return DIMINISHING_DRAGONS_BREATH;
- break;
- }
- case SPELLFAMILY_WARRIOR:
- {
- // Hamstring - limit duration to 10s in PvP
- if (spellproto->SpellFamilyFlags[0] & 0x2)
- return DIMINISHING_LIMITONLY;
- // Charge Stun (own diminishing)
- else if (spellproto->SpellFamilyFlags[0] & 0x01000000)
- return DIMINISHING_CHARGE;
- break;
- }
- case SPELLFAMILY_WARLOCK:
- {
- // Curses/etc
- if ((spellproto->SpellFamilyFlags[0] & 0x80000000) || (spellproto->SpellFamilyFlags[1] & 0x200))
- return DIMINISHING_LIMITONLY;
- // Seduction
- else if (spellproto->SpellFamilyFlags[1] & 0x10000000)
- return DIMINISHING_FEAR;
- break;
- }
- case SPELLFAMILY_DRUID:
- {
- // Pounce
- if (spellproto->SpellFamilyFlags[0] & 0x20000)
- return DIMINISHING_OPENING_STUN;
- // Cyclone
- else if (spellproto->SpellFamilyFlags[1] & 0x20)
- return DIMINISHING_CYCLONE;
- // Entangling Roots
- // Nature's Grasp
- else if (spellproto->SpellFamilyFlags[0] & 0x00000200)
- return DIMINISHING_CONTROLLED_ROOT;
- // Faerie Fire
- else if (spellproto->SpellFamilyFlags[0] & 0x400)
- return DIMINISHING_LIMITONLY;
- break;
- }
- case SPELLFAMILY_ROGUE:
- {
- // Gouge
- if (spellproto->SpellFamilyFlags[0] & 0x8)
- return DIMINISHING_DISORIENT;
- // Blind
- else if (spellproto->SpellFamilyFlags[0] & 0x1000000)
- return DIMINISHING_FEAR;
- // Cheap Shot
- else if (spellproto->SpellFamilyFlags[0] & 0x400)
- return DIMINISHING_OPENING_STUN;
- // Crippling poison - Limit to 10 seconds in PvP (No SpellFamilyFlags)
- else if (spellproto->SpellIconID == 163)
- return DIMINISHING_LIMITONLY;
- break;
- }
- case SPELLFAMILY_HUNTER:
- {
- // Hunter's Mark
- if ((spellproto->SpellFamilyFlags[0] & 0x400) && spellproto->SpellIconID == 538)
- return DIMINISHING_LIMITONLY;
- // Scatter Shot (own diminishing)
- else if ((spellproto->SpellFamilyFlags[0] & 0x40000) && spellproto->SpellIconID == 132)
- return DIMINISHING_SCATTER_SHOT;
- // Entrapment (own diminishing)
- else if (spellproto->SpellVisual[0] == 7484 && spellproto->SpellIconID == 20)
- return DIMINISHING_ENTRAPMENT;
- // Wyvern Sting mechanic is MECHANIC_SLEEP but the diminishing is DIMINISHING_DISORIENT
- else if ((spellproto->SpellFamilyFlags[1] & 0x1000) && spellproto->SpellIconID == 1721)
- return DIMINISHING_DISORIENT;
- // Freezing Arrow
- else if (spellproto->SpellFamilyFlags[0] & 0x8)
- return DIMINISHING_DISORIENT;
- break;
- }
- case SPELLFAMILY_PALADIN:
- {
- // Judgement of Justice - limit duration to 10s in PvP
- if (spellproto->SpellFamilyFlags[0] & 0x100000)
- return DIMINISHING_LIMITONLY;
- // Turn Evil
- else if ((spellproto->SpellFamilyFlags[1] & 0x804000) && spellproto->SpellIconID == 309)
- return DIMINISHING_FEAR;
- break;
- }
- case SPELLFAMILY_SHAMAN:
- {
- // Storm, Earth and Fire - Earthgrab
- if (spellproto->SpellFamilyFlags[2] & 0x4000)
- return DIMINISHING_NONE;
- break;
- }
- case SPELLFAMILY_DEATHKNIGHT:
- {
- // Hungering Cold (no flags)
- if (spellproto->SpellIconID == 2797)
- return DIMINISHING_DISORIENT;
- // Mark of Blood
- else if ((spellproto->SpellFamilyFlags[0] & 0x10000000) && spellproto->SpellIconID == 2285)
- return DIMINISHING_LIMITONLY;
- break;
- }
- default:
- break;
- }
-
- // Lastly - Set diminishing depending on mechanic
- uint32 mechanic = spellproto->GetAllEffectsMechanicMask();
- if (mechanic & (1 << MECHANIC_CHARM))
- return DIMINISHING_MIND_CONTROL;
- if (mechanic & (1 << MECHANIC_SILENCE))
- return DIMINISHING_SILENCE;
- if (mechanic & (1 << MECHANIC_SLEEP))
- return DIMINISHING_SLEEP;
- if (mechanic & ((1 << MECHANIC_SAPPED) | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_SHACKLE)))
- return DIMINISHING_DISORIENT;
- // Mechanic Knockout, except Blast Wave
- if (mechanic & (1 << MECHANIC_KNOCKOUT) && spellproto->SpellIconID != 292)
- return DIMINISHING_DISORIENT;
- if (mechanic & (1 << MECHANIC_DISARM))
- return DIMINISHING_DISARM;
- if (mechanic & (1 << MECHANIC_FEAR))
- return DIMINISHING_FEAR;
- if (mechanic & (1 << MECHANIC_STUN))
- return triggered ? DIMINISHING_STUN : DIMINISHING_CONTROLLED_STUN;
- if (mechanic & (1 << MECHANIC_BANISH))
- return DIMINISHING_BANISH;
- if (mechanic & (1 << MECHANIC_ROOT))
- return triggered ? DIMINISHING_ROOT : DIMINISHING_CONTROLLED_ROOT;
- if (mechanic & (1 << MECHANIC_HORROR))
- return DIMINISHING_HORROR;
-
- return DIMINISHING_NONE;
-}
-
-DiminishingReturnsType GetDiminishingReturnsGroupType(DiminishingGroup group)
-{
- switch (group)
- {
- case DIMINISHING_TAUNT:
- case DIMINISHING_CONTROLLED_STUN:
- case DIMINISHING_STUN:
- case DIMINISHING_OPENING_STUN:
- case DIMINISHING_CYCLONE:
- case DIMINISHING_CHARGE:
- return DRTYPE_ALL;
- case DIMINISHING_LIMITONLY:
- case DIMINISHING_NONE:
- return DRTYPE_NONE;
- default:
- return DRTYPE_PLAYER;
- }
-}
-
-DiminishingLevels GetDiminishingReturnsMaxLevel(DiminishingGroup group)
-{
- switch (group)
- {
- case DIMINISHING_TAUNT:
- return DIMINISHING_LEVEL_TAUNT_IMMUNE;
- default:
- return DIMINISHING_LEVEL_IMMUNE;
- }
-}
-
-int32 GetDiminishingReturnsLimitDuration(DiminishingGroup group, SpellInfo const* spellproto)
-{
- if (!IsDiminishingReturnsGroupDurationLimited(group))
- return 0;
-
- // Explicit diminishing duration
- switch (spellproto->SpellFamilyName)
- {
- case SPELLFAMILY_DRUID:
- {
- // Faerie Fire - limit to 40 seconds in PvP (3.1)
- if (spellproto->SpellFamilyFlags[0] & 0x400)
- return 40 * IN_MILLISECONDS;
- break;
- }
- case SPELLFAMILY_HUNTER:
- {
- // Wyvern Sting
- if (spellproto->SpellFamilyFlags[1] & 0x1000)
- return 6 * IN_MILLISECONDS;
- // Hunter's Mark
- if (spellproto->SpellFamilyFlags[0] & 0x400)
- return 120 * IN_MILLISECONDS;
- break;
- }
- case SPELLFAMILY_PALADIN:
- {
- // Repentance - limit to 6 seconds in PvP
- if (spellproto->SpellFamilyFlags[0] & 0x4)
- return 6 * IN_MILLISECONDS;
- break;
- }
- case SPELLFAMILY_WARLOCK:
- {
- // Banish - limit to 6 seconds in PvP
- if (spellproto->SpellFamilyFlags[1] & 0x8000000)
- return 6 * IN_MILLISECONDS;
- // Curse of Tongues - limit to 12 seconds in PvP
- else if (spellproto->SpellFamilyFlags[2] & 0x800)
- return 12 * IN_MILLISECONDS;
- // Curse of Elements - limit to 120 seconds in PvP
- else if (spellproto->SpellFamilyFlags[1] & 0x200)
- return 120 * IN_MILLISECONDS;
- break;
- }
- default:
- break;
- }
-
- return 10 * IN_MILLISECONDS;
-}
-
-bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group)
-{
- switch (group)
- {
- case DIMINISHING_BANISH:
- case DIMINISHING_CONTROLLED_STUN:
- case DIMINISHING_CONTROLLED_ROOT:
- case DIMINISHING_CYCLONE:
- case DIMINISHING_DISORIENT:
- case DIMINISHING_ENTRAPMENT:
- case DIMINISHING_FEAR:
- case DIMINISHING_HORROR:
- case DIMINISHING_MIND_CONTROL:
- case DIMINISHING_OPENING_STUN:
- case DIMINISHING_ROOT:
- case DIMINISHING_STUN:
- case DIMINISHING_SLEEP:
- case DIMINISHING_LIMITONLY:
- return true;
- default:
- return false;
- }
-}
-
SpellMgr::SpellMgr() { }
SpellMgr::~SpellMgr()
@@ -3769,3 +3473,18 @@ void SpellMgr::LoadSpellInfoSpellSpecificAndAuraState()
TC_LOG_INFO("server.loading", ">> Loaded SpellInfo SpellSpecific and AuraState in %u ms", GetMSTimeDiffToNow(oldMSTime));
}
+
+void SpellMgr::LoadSpellInfoDiminishing()
+{
+ uint32 oldMSTime = getMSTime();
+
+ for (SpellInfo* spellInfo : mSpellInfoMap)
+ {
+ if (!spellInfo)
+ continue;
+
+ spellInfo->_LoadSpellDiminishInfo();
+ }
+
+ TC_LOG_INFO("server.loading", ">> Loaded SpellInfo diminishing infos in %u ms", GetMSTimeDiffToNow(oldMSTime));
+}
diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h
index 60af9bd94bf..f119d164789 100644
--- a/src/server/game/Spells/SpellMgr.h
+++ b/src/server/game/Spells/SpellMgr.h
@@ -547,13 +547,6 @@ inline bool IsProfessionOrRidingSkill(uint32 skill)
bool IsPartOfSkillLine(uint32 skillId, uint32 spellId);
-// spell diminishing returns
-TC_GAME_API DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto, bool triggered);
-TC_GAME_API DiminishingReturnsType GetDiminishingReturnsGroupType(DiminishingGroup group);
-TC_GAME_API DiminishingLevels GetDiminishingReturnsMaxLevel(DiminishingGroup group);
-TC_GAME_API int32 GetDiminishingReturnsLimitDuration(DiminishingGroup group, SpellInfo const* spellproto);
-TC_GAME_API bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group);
-
class TC_GAME_API SpellMgr
{
// Constructors
@@ -686,6 +679,7 @@ class TC_GAME_API SpellMgr
void LoadSpellInfoCustomAttributes();
void LoadSpellInfoCorrections();
void LoadSpellInfoSpellSpecificAndAuraState();
+ void LoadSpellInfoDiminishing();
private:
SpellDifficultySearcherMap mSpellDifficultySearcherMap;
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 443d0c63efa..59a1e757183 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1452,6 +1452,9 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading SpellInfo SpellSpecific and AuraState...");
sSpellMgr->LoadSpellInfoSpellSpecificAndAuraState();
+ TC_LOG_INFO("server.loading", "Loading SpellInfo diminishing infos...");
+ sSpellMgr->LoadSpellInfoDiminishing();
+
TC_LOG_INFO("server.loading", "Loading GameObject models...");
LoadGameObjectModelList(m_dataPath);