aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2022-05-01 20:01:13 +0200
committerShauren <shauren.trinity@gmail.com>2022-05-01 20:01:13 +0200
commit8d16a79dea4c0100d36e13b068c42499a3a48154 (patch)
treeb7eb987d783e46e9fb74da6bec06dc1b91e29f14
parent524d14a162e8d032ad3324acf7cd2ebea5c29fc6 (diff)
Core/Spells: Rename SpellAttr4 to use official attribute names
* Corrected implementation of SPELL_ATTR4_CLASS_TRIGGER_ONLY_ON_TARGET * Implemented SPELL_ATTR4_NO_HELPFUL_THREAT * Implemented SPELL_ATTR4_NO_PARTIAL_IMMUNITY * Implemented SPELL_ATTR4_ALLOW_PROC_WHILE_SITTING * Implemented SPELL_ATTR4_USE_FACING_FROM_SPELL * Implemented SPELL_ATTR4_BOUNCY_CHAIN_MISSILES * Implemented SPELL_ATTR4_AURA_NEVER_BOUNCES * Implemented SPELL_ATTR4_AURA_BOUNCE_FAILS_SPELL * Implemented SPELL_ATTR4_AURA_IS_BUFF * Implemented SPELL_ATTR5_MELEE_CHAIN_TARGETING * Implemented SpellEffectAttributes::ChainFromInitialTarget
-rw-r--r--src/server/game/Combat/ThreatManager.cpp2
-rw-r--r--src/server/game/DataStores/DBCEnums.h1
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp21
-rw-r--r--src/server/game/Entities/Creature/Creature.h1
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp23
-rw-r--r--src/server/game/Entities/Unit/Unit.h2
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h66
-rw-r--r--src/server/game/Miscellaneous/enuminfo_SharedDefines.cpp186
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp11
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp4
-rw-r--r--src/server/game/Spells/Spell.cpp138
-rw-r--r--src/server/game/Spells/Spell.h6
-rw-r--r--src/server/game/Spells/SpellEffects.cpp2
-rw-r--r--src/server/game/Spells/SpellInfo.cpp9
-rw-r--r--src/server/game/Spells/SpellMgr.cpp8
15 files changed, 257 insertions, 223 deletions
diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp
index 2e0c0f7eba3..ea41b10e61e 100644
--- a/src/server/game/Combat/ThreatManager.cpp
+++ b/src/server/game/Combat/ThreatManager.cpp
@@ -661,7 +661,7 @@ void ThreatManager::ProcessAIUpdates()
void ThreatManager::ForwardThreatForAssistingMe(Unit* assistant, float baseAmount, SpellInfo const* spell, bool ignoreModifiers)
{
- if (spell && spell->HasAttribute(SPELL_ATTR1_NO_THREAT)) // shortcut, none of the calls would do anything
+ if (spell && (spell->HasAttribute(SPELL_ATTR1_NO_THREAT) || spell->HasAttribute(SPELL_ATTR4_NO_HELPFUL_THREAT))) // shortcut, none of the calls would do anything
return;
if (_threatenedByMe.empty())
return;
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h
index d8fdd7b5237..bd6b9d4cb15 100644
--- a/src/server/game/DataStores/DBCEnums.h
+++ b/src/server/game/DataStores/DBCEnums.h
@@ -1499,6 +1499,7 @@ enum class SpellEffectAttributes
None = 0,
UnaffectedByInvulnerability = 0x000001, // not cancelled by immunities
NoScaleWithStack = 0x000040,
+ ChainFromInitialTarget = 0x000080,
StackAuraAmountOnRecast = 0x008000, // refreshing periodic auras with this attribute will add remaining damage to new aura
AllowAnyExplicitTarget = 0x100000,
IgnoreDuringCooldownTimeRateCalculation = 0x800000
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index baba65fca1d..818b09ca171 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -2357,27 +2357,6 @@ void Creature::LoadTemplateImmunities()
}
}
-bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster) const
-{
- if (!spellInfo)
- return false;
-
- bool immunedToAllEffects = true;
- for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
- {
- if (spellEffectInfo.IsEffect() && !IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster))
- {
- immunedToAllEffects = false;
- break;
- }
- }
-
- if (immunedToAllEffects)
- return true;
-
- return Unit::IsImmunedToSpell(spellInfo, caster);
-}
-
bool Creature::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster) const
{
if (GetCreatureTemplate()->type == CREATURE_TYPE_MECHANICAL && spellEffectInfo.IsEffect(SPELL_EFFECT_HEAL))
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 2c5b1820f4b..a746021f3d3 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -150,7 +150,6 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
bool CanResetTalents(Player* player) const;
bool CanCreatureAttack(Unit const* victim, bool force = true) const;
void LoadTemplateImmunities();
- bool IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster) const override;
bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster) const override;
bool isElite() const;
bool isWorldBoss() const;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 7aca0596c47..2dd429741f4 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -758,7 +758,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons
// interrupting auras with SpellAuraInterruptFlags::Damage before checking !damage (absorbed damage breaks that type of auras)
if (spellProto)
{
- if (!spellProto->HasAttribute(SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS))
+ if (!spellProto->HasAttribute(SPELL_ATTR4_REACTIVE_DAMAGE_PROC))
victim->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Damage, spellProto);
}
else
@@ -964,7 +964,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons
if (damagetype != DOT && damage > 0 && !victim->GetOwnerGUID().IsPlayer() && (!spellProto || !spellProto->HasAura(SPELL_AURA_DAMAGE_SHIELD)))
victim->ToCreature()->SetLastDamagedTime(GameTime::GetGameTime() + MAX_AGGRO_RESET_TIME);
- if (attacker)
+ if (attacker && (!spellProto || !spellProto->HasAttribute(SPELL_ATTR4_NO_HARMFUL_THREAT)))
victim->GetThreatManager().AddThreat(attacker, float(damage), spellProto);
}
else // victim is a player
@@ -1082,8 +1082,8 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama
SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask);
- // Spells with SPELL_ATTR4_FIXED_DAMAGE ignore resilience because their damage is based off another spell's damage.
- if (!spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
+ // Spells with SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS ignore resilience because their damage is based off another spell's damage.
+ if (!spellInfo->HasAttribute(SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS))
{
if (Unit::IsDamageReducedByArmor(damageSchoolMask, spellInfo))
damage = Unit::CalcArmorReducedDamage(damageInfo->attacker, victim, damage, spellInfo, attackType);
@@ -1647,13 +1647,6 @@ void Unit::HandleEmoteCommand(Emote emoteId, Player* target /*=nullptr*/, Trinit
if ((schoolMask & SPELL_SCHOOL_MASK_HOLY) && victim->GetTypeId() != TYPEID_UNIT)
return 0;
- // Ignore spells that can't be resisted
- if (spellInfo)
- {
- if (spellInfo->HasAttribute(SPELL_ATTR4_IGNORE_RESISTANCES))
- return 0;
- }
-
float const averageResist = Unit::CalculateAverageResistReduction(attacker, schoolMask, victim, spellInfo);
float discreteResistProbability[11] = { };
if (averageResist <= 0.1f)
@@ -4151,7 +4144,7 @@ void Unit::RemoveArenaAuras()
RemoveAppliedAuras([](AuraApplication const* aurApp)
{
Aura const* aura = aurApp->GetBase();
- return (!aura->GetSpellInfo()->HasAttribute(SPELL_ATTR4_DONT_REMOVE_IN_ARENA) // don't remove stances, shadowform, pally/hunter auras
+ return (!aura->GetSpellInfo()->HasAttribute(SPELL_ATTR4_ALLOW_ENTERING_ARENA) // don't remove stances, shadowform, pally/hunter auras
&& !aura->IsPassive() // don't remove passive auras
&& (aurApp->IsPositive() || !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD))) || // not negative death persistent auras
aura->GetSpellInfo()->HasAttribute(SPELL_ATTR5_REMOVE_ENTERING_ARENA); // special marker, always remove
@@ -6634,8 +6627,8 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui
if (cheatDeath->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
AddPct(TakenTotalMod, cheatDeath->GetAmount());
- // Spells with SPELL_ATTR4_FIXED_DAMAGE should only benefit from mechanic damage mod auras.
- if (!spellProto->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
+ // Spells with SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS should only benefit from mechanic damage mod auras.
+ if (!spellProto->HasAttribute(SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS))
{
// Versatility
if (Player* modOwner = GetSpellModOwner())
@@ -7256,6 +7249,8 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caste
immuneToAllEffects = false;
break;
}
+ if (spellInfo->HasAttribute(SPELL_ATTR4_NO_PARTIAL_IMMUNITY))
+ return true;
}
if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects.
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 1a19d0d1fde..273ce6cd4be 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1708,7 +1708,7 @@ class TC_GAME_API Unit : public WorldObject
static uint32 SpellCriticalHealingBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim);
void ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply);
- virtual bool IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster) const;
+ bool IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster) const;
uint32 GetSchoolImmunityMask() const;
uint32 GetDamageImmunityMask() const;
uint32 GetMechanicImmunityMask() const;
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index d42987d37c4..af4eecebde0 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -552,38 +552,38 @@ enum SpellAttr3 : uint32
// EnumUtils: DESCRIBE THIS
enum SpellAttr4 : uint32
{
- SPELL_ATTR4_IGNORE_RESISTANCES = 0x00000001, // TITLE Cannot be resisted
- SPELL_ATTR4_PROC_ONLY_ON_CASTER = 0x00000002, // TITLE Only proc on self-cast
- SPELL_ATTR4_AURA_EXPIRES_OFFLINE = 0x00000004, // TITLE Aura Expires Offline DESCRIPTION Debuffs (except Resurrection Sickness) will automatically do this
- SPELL_ATTR4_UNK3 = 0x00000008, // TITLE Unknown attribute 3@Attr4
- SPELL_ATTR4_UNK4 = 0x00000010, // TITLE Treat as delayed spell
- SPELL_ATTR4_UNK5 = 0x00000020, // TITLE Unknown attribute 5@Attr4
- SPELL_ATTR4_NOT_STEALABLE = 0x00000040, // TITLE Aura cannot be stolen
- SPELL_ATTR4_CAN_CAST_WHILE_CASTING = 0x00000080, // TITLE Can be cast while casting DESCRIPTION Ignores already in-progress cast and still casts
- SPELL_ATTR4_FIXED_DAMAGE = 0x00000100, // TITLE Deals fixed damage
- SPELL_ATTR4_TRIGGER_ACTIVATE = 0x00000200, // TITLE Spell is initially disabled (client only)
- SPELL_ATTR4_SPELL_VS_EXTEND_COST = 0x00000400, // TITLE Attack speed modifies cost DESCRIPTION Adds 10 to power cost for each 1s of weapon speed
- SPELL_ATTR4_UNK11 = 0x00000800, // TITLE Unknown attribute 11@Attr4
- SPELL_ATTR4_UNK12 = 0x00001000, // TITLE Unknown attribute 12@Attr4
- SPELL_ATTR4_COMBAT_LOG_NO_CASTER = 0x00002000, // TITLE Do Not Log Caster
- SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS = 0x00004000, // TITLE Damage does not break auras
- SPELL_ATTR4_HIDDEN_IN_SPELLBOOK = 0x00008000, // TITLE Not In Spellbook
- SPELL_ATTR4_NOT_USABLE_IN_ARENA_OR_RATED_BG = 0x00010000, // TITLE Not In Arena or Rated Battleground DESCRIPTION Makes spell unusable despite CD <= 10min
- SPELL_ATTR4_USABLE_IN_ARENA = 0x00020000, // TITLE Usable in arena DESCRIPTION Makes spell usable despite CD > 10min
- SPELL_ATTR4_AREA_TARGET_CHAIN = 0x00040000, // TITLE Chain area targets DESCRIPTION [NYI] Hits area targets over time instead of all at once
- SPELL_ATTR4_UNK19 = 0x00080000, // TITLE Unknown attribute 19@Attr4
- SPELL_ATTR4_NOT_CHECK_SELFCAST_POWER = 0x00100000, // TITLE Allow self-cast to override stronger aura (client only)
- SPELL_ATTR4_DONT_REMOVE_IN_ARENA = 0x00200000, // TITLE Allow Entering Arena
- SPELL_ATTR4_UNK22 = 0x00400000, // TITLE Unknown attribute 22@Attr4
- SPELL_ATTR4_SUPPRESS_WEAPON_PROCS = 0x00800000, // TITLE Suppress Weapon Procs
- SPELL_ATTR4_UNK24 = 0x01000000, // TITLE Unknown attribute 24@Attr4 DESCRIPTION Shoot-type spell?
- SPELL_ATTR4_IS_PET_SCALING = 0x02000000, // TITLE Pet Scaling aura
- SPELL_ATTR4_CAST_ONLY_IN_OUTLAND = 0x04000000, // TITLE Only in Outland/Northrend
- SPELL_ATTR4_UNK27 = 0x08000000, // TITLE Unknown attribute 27@Attr4
- SPELL_ATTR4_UNK28 = 0x10000000, // TITLE Unknown attribute 28@Attr4
- SPELL_ATTR4_UNK29 = 0x20000000, // TITLE Unknown attribute 29@Attr4
- SPELL_ATTR4_UNK30 = 0x40000000, // TITLE Unknown attribute 30@Attr4
- SPELL_ATTR4_UNK31 = 0x80000000 // TITLE Unknown attribute 31@Attr4
+ SPELL_ATTR4_NO_CAST_LOG = 0x00000001, // TITLE No Cast Log
+ SPELL_ATTR4_CLASS_TRIGGER_ONLY_ON_TARGET = 0x00000002, // TITLE Class Trigger Only On Target
+ SPELL_ATTR4_AURA_EXPIRES_OFFLINE = 0x00000004, // TITLE Aura Expires Offline DESCRIPTION Debuffs (except Resurrection Sickness) will automatically do this
+ SPELL_ATTR4_NO_HELPFUL_THREAT = 0x00000008, // TITLE No Helpful Threat
+ SPELL_ATTR4_NO_HARMFUL_THREAT = 0x00000010, // TITLE No Harmful Threat
+ SPELL_ATTR4_ALLOW_CLIENT_TARGETING = 0x00000020, // TITLE Allow Client Targeting DESCRIPTION Allows client to send spell targets for this spell. Applies only to pet spells, without this attribute CMSG_PET_ACTION is sent instead of CMSG_PET_CAST_SPELL
+ SPELL_ATTR4_CANNOT_BE_STOLEN = 0x00000040, // TITLE Cannot Be Stolen
+ SPELL_ATTR4_ALLOW_CAST_WHILE_CASTING = 0x00000080, // TITLE Allow Cast While Casting DESCRIPTION Ignores already in-progress cast and still casts
+ SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS = 0x00000100, // TITLE Ignore Damage Taken Modifiers
+ SPELL_ATTR4_COMBAT_FEEDBACK_WHEN_USABLE = 0x00000200, // TITLE Combat Feedback When Usable (client only)
+ SPELL_ATTR4_WEAPON_SPEED_COST_SCALING = 0x00000400, // TITLE Weapon Speed Cost Scaling DESCRIPTION Adds 10 to power cost for each 1s of weapon speed
+ SPELL_ATTR4_NO_PARTIAL_IMMUNITY = 0x00000800, // TITLE No Partial Immunity
+ SPELL_ATTR4_AURA_IS_BUFF = 0x00001000, // TITLE Aura Is Buff
+ SPELL_ATTR4_DO_NOT_LOG_CASTER = 0x00002000, // TITLE Do Not Log Caster
+ SPELL_ATTR4_REACTIVE_DAMAGE_PROC = 0x00004000, // TITLE Reactive Damage Proc DESCRIPTION Damage from spells with this attribute doesn't break auras that normally break on damage taken
+ SPELL_ATTR4_NOT_IN_SPELLBOOK = 0x00008000, // TITLE Not In Spellbook
+ SPELL_ATTR4_NOT_IN_ARENA_OR_RATED_BATTLEGROUND = 0x00010000, // TITLE Not In Arena or Rated Battleground DESCRIPTION Makes spell unusable despite CD <= 10min
+ SPELL_ATTR4_IGNORE_DEFAULT_ARENA_RESTRICTIONS = 0x00020000, // TITLE Ignore Default Arena Restrictions DESCRIPTION Makes spell usable despite CD > 10min
+ SPELL_ATTR4_BOUNCY_CHAIN_MISSILES = 0x00040000, // TITLE Bouncy Chain Missiles DESCRIPTION Hits area targets over time instead of all at once
+ SPELL_ATTR4_ALLOW_PROC_WHILE_SITTING = 0x00080000, // TITLE Allow Proc While Sitting
+ SPELL_ATTR4_AURA_NEVER_BOUNCES = 0x00100000, // TITLE Aura Never Bounces
+ SPELL_ATTR4_ALLOW_ENTERING_ARENA = 0x00200000, // TITLE Allow Entering Arena
+ SPELL_ATTR4_PROC_SUPPRESS_SWING_ANIM = 0x00400000, // TITLE Proc Suppress Swing Anim
+ SPELL_ATTR4_SUPPRESS_WEAPON_PROCS = 0x00800000, // TITLE Suppress Weapon Procs
+ SPELL_ATTR4_AUTO_RANGED_COMBAT = 0x01000000, // TITLE Auto Ranged Combat
+ SPELL_ATTR4_OWNER_POWER_SCALING = 0x02000000, // TITLE Owner Power Scaling
+ SPELL_ATTR4_ONLY_FLYING_AREAS = 0x04000000, // TITLE Only Flying Areas
+ SPELL_ATTR4_FORCE_DISPLAY_CASTBAR = 0x08000000, // TITLE Force Display Castbar
+ SPELL_ATTR4_IGNORE_COMBAT_TIMER = 0x10000000, // TITLE Ignore Combat Timer
+ SPELL_ATTR4_AURA_BOUNCE_FAILS_SPELL = 0x20000000, // TITLE Aura Bounce Fails Spell
+ SPELL_ATTR4_OBSOLETE = 0x40000000, // TITLE Obsolete
+ SPELL_ATTR4_USE_FACING_FROM_SPELL = 0x80000000 // TITLE Use Facing From Spell
};
// EnumUtils: DESCRIBE THIS
@@ -601,7 +601,7 @@ enum SpellAttr5 : uint32
SPELL_ATTR5_START_PERIODIC_AT_APPLY = 0x00000200, // TITLE Immediately do periodic tick on apply
SPELL_ATTR5_HIDE_DURATION = 0x00000400, // TITLE Do not send aura duration to client
SPELL_ATTR5_ALLOW_TARGET_OF_TARGET_AS_TARGET = 0x00000800, // TITLE Auto-target target of target (client only)
- SPELL_ATTR5_UNK12 = 0x00001000, // TITLE Unknown attribute 12@Attr5 DESCRIPTION Cleave related?
+ SPELL_ATTR5_MELEE_CHAIN_TARGETING = 0x00001000, // TITLE Unknown attribute 12@Attr5 DESCRIPTION Cleave related?
SPELL_ATTR5_HASTE_AFFECT_DURATION = 0x00002000, // TITLE Duration scales with Haste Rating
SPELL_ATTR5_NOT_USABLE_WHILE_CHARMED = 0x00004000, // TITLE Not Available While Charmed
SPELL_ATTR5_UNK15 = 0x00008000, // TITLE Unknown attribute 15@Attr5 DESCRIPTION Related to multi-target spells?
diff --git a/src/server/game/Miscellaneous/enuminfo_SharedDefines.cpp b/src/server/game/Miscellaneous/enuminfo_SharedDefines.cpp
index d10ba44c58d..865018aa03c 100644
--- a/src/server/game/Miscellaneous/enuminfo_SharedDefines.cpp
+++ b/src/server/game/Miscellaneous/enuminfo_SharedDefines.cpp
@@ -763,38 +763,38 @@ TC_API_EXPORT EnumText EnumUtils<SpellAttr4>::ToString(SpellAttr4 value)
{
switch (value)
{
- case SPELL_ATTR4_IGNORE_RESISTANCES: return { "SPELL_ATTR4_IGNORE_RESISTANCES", "Cannot be resisted", "" };
- case SPELL_ATTR4_PROC_ONLY_ON_CASTER: return { "SPELL_ATTR4_PROC_ONLY_ON_CASTER", "Only proc on self-cast", "" };
+ case SPELL_ATTR4_NO_CAST_LOG: return { "SPELL_ATTR4_NO_CAST_LOG", "No Cast Log", "" };
+ case SPELL_ATTR4_CLASS_TRIGGER_ONLY_ON_TARGET: return { "SPELL_ATTR4_CLASS_TRIGGER_ONLY_ON_TARGET", "Class Trigger Only On Target", "" };
case SPELL_ATTR4_AURA_EXPIRES_OFFLINE: return { "SPELL_ATTR4_AURA_EXPIRES_OFFLINE", "Aura Expires Offline", "Debuffs (except Resurrection Sickness) will automatically do this" };
- case SPELL_ATTR4_UNK3: return { "SPELL_ATTR4_UNK3", "Unknown attribute 3@Attr4", "" };
- case SPELL_ATTR4_UNK4: return { "SPELL_ATTR4_UNK4", "Treat as delayed spell", "" };
- case SPELL_ATTR4_UNK5: return { "SPELL_ATTR4_UNK5", "Unknown attribute 5@Attr4", "" };
- case SPELL_ATTR4_NOT_STEALABLE: return { "SPELL_ATTR4_NOT_STEALABLE", "Aura cannot be stolen", "" };
- case SPELL_ATTR4_CAN_CAST_WHILE_CASTING: return { "SPELL_ATTR4_CAN_CAST_WHILE_CASTING", "Can be cast while casting", "Ignores already in-progress cast and still casts" };
- case SPELL_ATTR4_FIXED_DAMAGE: return { "SPELL_ATTR4_FIXED_DAMAGE", "Deals fixed damage", "" };
- case SPELL_ATTR4_TRIGGER_ACTIVATE: return { "SPELL_ATTR4_TRIGGER_ACTIVATE", "Spell is initially disabled (client only)", "" };
- case SPELL_ATTR4_SPELL_VS_EXTEND_COST: return { "SPELL_ATTR4_SPELL_VS_EXTEND_COST", "Attack speed modifies cost", "Adds 10 to power cost for each 1s of weapon speed" };
- case SPELL_ATTR4_UNK11: return { "SPELL_ATTR4_UNK11", "Unknown attribute 11@Attr4", "" };
- case SPELL_ATTR4_UNK12: return { "SPELL_ATTR4_UNK12", "Unknown attribute 12@Attr4", "" };
- case SPELL_ATTR4_COMBAT_LOG_NO_CASTER: return { "SPELL_ATTR4_COMBAT_LOG_NO_CASTER", "Do Not Log Caster", "" };
- case SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS: return { "SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS", "Damage does not break auras", "" };
- case SPELL_ATTR4_HIDDEN_IN_SPELLBOOK: return { "SPELL_ATTR4_HIDDEN_IN_SPELLBOOK", "Not In Spellbook", "" };
- case SPELL_ATTR4_NOT_USABLE_IN_ARENA_OR_RATED_BG: return { "SPELL_ATTR4_NOT_USABLE_IN_ARENA_OR_RATED_BG", "Not In Arena or Rated Battleground", "Makes spell unusable despite CD <= 10min" };
- case SPELL_ATTR4_USABLE_IN_ARENA: return { "SPELL_ATTR4_USABLE_IN_ARENA", "Usable in arena", "Makes spell usable despite CD > 10min" };
- case SPELL_ATTR4_AREA_TARGET_CHAIN: return { "SPELL_ATTR4_AREA_TARGET_CHAIN", "Chain area targets", "[NYI] Hits area targets over time instead of all at once" };
- case SPELL_ATTR4_UNK19: return { "SPELL_ATTR4_UNK19", "Unknown attribute 19@Attr4", "" };
- case SPELL_ATTR4_NOT_CHECK_SELFCAST_POWER: return { "SPELL_ATTR4_NOT_CHECK_SELFCAST_POWER", "Allow self-cast to override stronger aura (client only)", "" };
- case SPELL_ATTR4_DONT_REMOVE_IN_ARENA: return { "SPELL_ATTR4_DONT_REMOVE_IN_ARENA", "Allow Entering Arena", "" };
- case SPELL_ATTR4_UNK22: return { "SPELL_ATTR4_UNK22", "Unknown attribute 22@Attr4", "" };
+ case SPELL_ATTR4_NO_HELPFUL_THREAT: return { "SPELL_ATTR4_NO_HELPFUL_THREAT", "No Helpful Threat", "" };
+ case SPELL_ATTR4_NO_HARMFUL_THREAT: return { "SPELL_ATTR4_NO_HARMFUL_THREAT", "No Harmful Threat", "" };
+ case SPELL_ATTR4_ALLOW_CLIENT_TARGETING: return { "SPELL_ATTR4_ALLOW_CLIENT_TARGETING", "Allow Client Targeting", "Allows client to send spell targets for this spell. Applies only to pet spells, without this attribute CMSG_PET_ACTION is sent instead of CMSG_PET_CAST_SPELL" };
+ case SPELL_ATTR4_CANNOT_BE_STOLEN: return { "SPELL_ATTR4_CANNOT_BE_STOLEN", "Cannot Be Stolen", "" };
+ case SPELL_ATTR4_ALLOW_CAST_WHILE_CASTING: return { "SPELL_ATTR4_ALLOW_CAST_WHILE_CASTING", "Allow Cast While Casting", "Ignores already in-progress cast and still casts" };
+ case SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS: return { "SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS", "Ignore Damage Taken Modifiers", "" };
+ case SPELL_ATTR4_COMBAT_FEEDBACK_WHEN_USABLE: return { "SPELL_ATTR4_COMBAT_FEEDBACK_WHEN_USABLE", "Combat Feedback When Usable (client only)", "" };
+ case SPELL_ATTR4_WEAPON_SPEED_COST_SCALING: return { "SPELL_ATTR4_WEAPON_SPEED_COST_SCALING", "Weapon Speed Cost Scaling", "Adds 10 to power cost for each 1s of weapon speed" };
+ case SPELL_ATTR4_NO_PARTIAL_IMMUNITY: return { "SPELL_ATTR4_NO_PARTIAL_IMMUNITY", "No Partial Immunity", "" };
+ case SPELL_ATTR4_AURA_IS_BUFF: return { "SPELL_ATTR4_AURA_IS_BUFF", "Aura Is Buff", "" };
+ case SPELL_ATTR4_DO_NOT_LOG_CASTER: return { "SPELL_ATTR4_DO_NOT_LOG_CASTER", "Do Not Log Caster", "" };
+ case SPELL_ATTR4_REACTIVE_DAMAGE_PROC: return { "SPELL_ATTR4_REACTIVE_DAMAGE_PROC", "Reactive Damage Proc", "Damage from spells with this attribute doesn't break auras that normally break on damage taken" };
+ case SPELL_ATTR4_NOT_IN_SPELLBOOK: return { "SPELL_ATTR4_NOT_IN_SPELLBOOK", "Not In Spellbook", "" };
+ case SPELL_ATTR4_NOT_IN_ARENA_OR_RATED_BATTLEGROUND: return { "SPELL_ATTR4_NOT_IN_ARENA_OR_RATED_BATTLEGROUND", "Not In Arena or Rated Battleground", "Makes spell unusable despite CD <= 10min" };
+ case SPELL_ATTR4_IGNORE_DEFAULT_ARENA_RESTRICTIONS: return { "SPELL_ATTR4_IGNORE_DEFAULT_ARENA_RESTRICTIONS", "Ignore Default Arena Restrictions", "Makes spell usable despite CD > 10min" };
+ case SPELL_ATTR4_BOUNCY_CHAIN_MISSILES: return { "SPELL_ATTR4_BOUNCY_CHAIN_MISSILES", "Bouncy Chain Missiles", "Hits area targets over time instead of all at once" };
+ case SPELL_ATTR4_ALLOW_PROC_WHILE_SITTING: return { "SPELL_ATTR4_ALLOW_PROC_WHILE_SITTING", "Allow Proc While Sitting", "" };
+ case SPELL_ATTR4_AURA_NEVER_BOUNCES: return { "SPELL_ATTR4_AURA_NEVER_BOUNCES", "Aura Never Bounces", "" };
+ case SPELL_ATTR4_ALLOW_ENTERING_ARENA: return { "SPELL_ATTR4_ALLOW_ENTERING_ARENA", "Allow Entering Arena", "" };
+ case SPELL_ATTR4_PROC_SUPPRESS_SWING_ANIM: return { "SPELL_ATTR4_PROC_SUPPRESS_SWING_ANIM", "Proc Suppress Swing Anim", "" };
case SPELL_ATTR4_SUPPRESS_WEAPON_PROCS: return { "SPELL_ATTR4_SUPPRESS_WEAPON_PROCS", "Suppress Weapon Procs", "" };
- case SPELL_ATTR4_UNK24: return { "SPELL_ATTR4_UNK24", "Unknown attribute 24@Attr4", "Shoot-type spell?" };
- case SPELL_ATTR4_IS_PET_SCALING: return { "SPELL_ATTR4_IS_PET_SCALING", "Pet Scaling aura", "" };
- case SPELL_ATTR4_CAST_ONLY_IN_OUTLAND: return { "SPELL_ATTR4_CAST_ONLY_IN_OUTLAND", "Only in Outland/Northrend", "" };
- case SPELL_ATTR4_UNK27: return { "SPELL_ATTR4_UNK27", "Unknown attribute 27@Attr4", "" };
- case SPELL_ATTR4_UNK28: return { "SPELL_ATTR4_UNK28", "Unknown attribute 28@Attr4", "" };
- case SPELL_ATTR4_UNK29: return { "SPELL_ATTR4_UNK29", "Unknown attribute 29@Attr4", "" };
- case SPELL_ATTR4_UNK30: return { "SPELL_ATTR4_UNK30", "Unknown attribute 30@Attr4", "" };
- case SPELL_ATTR4_UNK31: return { "SPELL_ATTR4_UNK31", "Unknown attribute 31@Attr4", "" };
+ case SPELL_ATTR4_AUTO_RANGED_COMBAT: return { "SPELL_ATTR4_AUTO_RANGED_COMBAT", "Auto Ranged Combat", "" };
+ case SPELL_ATTR4_OWNER_POWER_SCALING: return { "SPELL_ATTR4_OWNER_POWER_SCALING", "Owner Power Scaling", "" };
+ case SPELL_ATTR4_ONLY_FLYING_AREAS: return { "SPELL_ATTR4_ONLY_FLYING_AREAS", "Only Flying Areas", "" };
+ case SPELL_ATTR4_FORCE_DISPLAY_CASTBAR: return { "SPELL_ATTR4_FORCE_DISPLAY_CASTBAR", "Force Display Castbar", "" };
+ case SPELL_ATTR4_IGNORE_COMBAT_TIMER: return { "SPELL_ATTR4_IGNORE_COMBAT_TIMER", "Ignore Combat Timer", "" };
+ case SPELL_ATTR4_AURA_BOUNCE_FAILS_SPELL: return { "SPELL_ATTR4_AURA_BOUNCE_FAILS_SPELL", "Aura Bounce Fails Spell", "" };
+ case SPELL_ATTR4_OBSOLETE: return { "SPELL_ATTR4_OBSOLETE", "Obsolete", "" };
+ case SPELL_ATTR4_USE_FACING_FROM_SPELL: return { "SPELL_ATTR4_USE_FACING_FROM_SPELL", "Use Facing From Spell", "" };
default: throw std::out_of_range("value");
}
}
@@ -807,38 +807,38 @@ TC_API_EXPORT SpellAttr4 EnumUtils<SpellAttr4>::FromIndex(size_t index)
{
switch (index)
{
- case 0: return SPELL_ATTR4_IGNORE_RESISTANCES;
- case 1: return SPELL_ATTR4_PROC_ONLY_ON_CASTER;
+ case 0: return SPELL_ATTR4_NO_CAST_LOG;
+ case 1: return SPELL_ATTR4_CLASS_TRIGGER_ONLY_ON_TARGET;
case 2: return SPELL_ATTR4_AURA_EXPIRES_OFFLINE;
- case 3: return SPELL_ATTR4_UNK3;
- case 4: return SPELL_ATTR4_UNK4;
- case 5: return SPELL_ATTR4_UNK5;
- case 6: return SPELL_ATTR4_NOT_STEALABLE;
- case 7: return SPELL_ATTR4_CAN_CAST_WHILE_CASTING;
- case 8: return SPELL_ATTR4_FIXED_DAMAGE;
- case 9: return SPELL_ATTR4_TRIGGER_ACTIVATE;
- case 10: return SPELL_ATTR4_SPELL_VS_EXTEND_COST;
- case 11: return SPELL_ATTR4_UNK11;
- case 12: return SPELL_ATTR4_UNK12;
- case 13: return SPELL_ATTR4_COMBAT_LOG_NO_CASTER;
- case 14: return SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS;
- case 15: return SPELL_ATTR4_HIDDEN_IN_SPELLBOOK;
- case 16: return SPELL_ATTR4_NOT_USABLE_IN_ARENA_OR_RATED_BG;
- case 17: return SPELL_ATTR4_USABLE_IN_ARENA;
- case 18: return SPELL_ATTR4_AREA_TARGET_CHAIN;
- case 19: return SPELL_ATTR4_UNK19;
- case 20: return SPELL_ATTR4_NOT_CHECK_SELFCAST_POWER;
- case 21: return SPELL_ATTR4_DONT_REMOVE_IN_ARENA;
- case 22: return SPELL_ATTR4_UNK22;
+ case 3: return SPELL_ATTR4_NO_HELPFUL_THREAT;
+ case 4: return SPELL_ATTR4_NO_HARMFUL_THREAT;
+ case 5: return SPELL_ATTR4_ALLOW_CLIENT_TARGETING;
+ case 6: return SPELL_ATTR4_CANNOT_BE_STOLEN;
+ case 7: return SPELL_ATTR4_ALLOW_CAST_WHILE_CASTING;
+ case 8: return SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS;
+ case 9: return SPELL_ATTR4_COMBAT_FEEDBACK_WHEN_USABLE;
+ case 10: return SPELL_ATTR4_WEAPON_SPEED_COST_SCALING;
+ case 11: return SPELL_ATTR4_NO_PARTIAL_IMMUNITY;
+ case 12: return SPELL_ATTR4_AURA_IS_BUFF;
+ case 13: return SPELL_ATTR4_DO_NOT_LOG_CASTER;
+ case 14: return SPELL_ATTR4_REACTIVE_DAMAGE_PROC;
+ case 15: return SPELL_ATTR4_NOT_IN_SPELLBOOK;
+ case 16: return SPELL_ATTR4_NOT_IN_ARENA_OR_RATED_BATTLEGROUND;
+ case 17: return SPELL_ATTR4_IGNORE_DEFAULT_ARENA_RESTRICTIONS;
+ case 18: return SPELL_ATTR4_BOUNCY_CHAIN_MISSILES;
+ case 19: return SPELL_ATTR4_ALLOW_PROC_WHILE_SITTING;
+ case 20: return SPELL_ATTR4_AURA_NEVER_BOUNCES;
+ case 21: return SPELL_ATTR4_ALLOW_ENTERING_ARENA;
+ case 22: return SPELL_ATTR4_PROC_SUPPRESS_SWING_ANIM;
case 23: return SPELL_ATTR4_SUPPRESS_WEAPON_PROCS;
- case 24: return SPELL_ATTR4_UNK24;
- case 25: return SPELL_ATTR4_IS_PET_SCALING;
- case 26: return SPELL_ATTR4_CAST_ONLY_IN_OUTLAND;
- case 27: return SPELL_ATTR4_UNK27;
- case 28: return SPELL_ATTR4_UNK28;
- case 29: return SPELL_ATTR4_UNK29;
- case 30: return SPELL_ATTR4_UNK30;
- case 31: return SPELL_ATTR4_UNK31;
+ case 24: return SPELL_ATTR4_AUTO_RANGED_COMBAT;
+ case 25: return SPELL_ATTR4_OWNER_POWER_SCALING;
+ case 26: return SPELL_ATTR4_ONLY_FLYING_AREAS;
+ case 27: return SPELL_ATTR4_FORCE_DISPLAY_CASTBAR;
+ case 28: return SPELL_ATTR4_IGNORE_COMBAT_TIMER;
+ case 29: return SPELL_ATTR4_AURA_BOUNCE_FAILS_SPELL;
+ case 30: return SPELL_ATTR4_OBSOLETE;
+ case 31: return SPELL_ATTR4_USE_FACING_FROM_SPELL;
default: throw std::out_of_range("index");
}
}
@@ -848,38 +848,38 @@ TC_API_EXPORT size_t EnumUtils<SpellAttr4>::ToIndex(SpellAttr4 value)
{
switch (value)
{
- case SPELL_ATTR4_IGNORE_RESISTANCES: return 0;
- case SPELL_ATTR4_PROC_ONLY_ON_CASTER: return 1;
+ case SPELL_ATTR4_NO_CAST_LOG: return 0;
+ case SPELL_ATTR4_CLASS_TRIGGER_ONLY_ON_TARGET: return 1;
case SPELL_ATTR4_AURA_EXPIRES_OFFLINE: return 2;
- case SPELL_ATTR4_UNK3: return 3;
- case SPELL_ATTR4_UNK4: return 4;
- case SPELL_ATTR4_UNK5: return 5;
- case SPELL_ATTR4_NOT_STEALABLE: return 6;
- case SPELL_ATTR4_CAN_CAST_WHILE_CASTING: return 7;
- case SPELL_ATTR4_FIXED_DAMAGE: return 8;
- case SPELL_ATTR4_TRIGGER_ACTIVATE: return 9;
- case SPELL_ATTR4_SPELL_VS_EXTEND_COST: return 10;
- case SPELL_ATTR4_UNK11: return 11;
- case SPELL_ATTR4_UNK12: return 12;
- case SPELL_ATTR4_COMBAT_LOG_NO_CASTER: return 13;
- case SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS: return 14;
- case SPELL_ATTR4_HIDDEN_IN_SPELLBOOK: return 15;
- case SPELL_ATTR4_NOT_USABLE_IN_ARENA_OR_RATED_BG: return 16;
- case SPELL_ATTR4_USABLE_IN_ARENA: return 17;
- case SPELL_ATTR4_AREA_TARGET_CHAIN: return 18;
- case SPELL_ATTR4_UNK19: return 19;
- case SPELL_ATTR4_NOT_CHECK_SELFCAST_POWER: return 20;
- case SPELL_ATTR4_DONT_REMOVE_IN_ARENA: return 21;
- case SPELL_ATTR4_UNK22: return 22;
+ case SPELL_ATTR4_NO_HELPFUL_THREAT: return 3;
+ case SPELL_ATTR4_NO_HARMFUL_THREAT: return 4;
+ case SPELL_ATTR4_ALLOW_CLIENT_TARGETING: return 5;
+ case SPELL_ATTR4_CANNOT_BE_STOLEN: return 6;
+ case SPELL_ATTR4_ALLOW_CAST_WHILE_CASTING: return 7;
+ case SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS: return 8;
+ case SPELL_ATTR4_COMBAT_FEEDBACK_WHEN_USABLE: return 9;
+ case SPELL_ATTR4_WEAPON_SPEED_COST_SCALING: return 10;
+ case SPELL_ATTR4_NO_PARTIAL_IMMUNITY: return 11;
+ case SPELL_ATTR4_AURA_IS_BUFF: return 12;
+ case SPELL_ATTR4_DO_NOT_LOG_CASTER: return 13;
+ case SPELL_ATTR4_REACTIVE_DAMAGE_PROC: return 14;
+ case SPELL_ATTR4_NOT_IN_SPELLBOOK: return 15;
+ case SPELL_ATTR4_NOT_IN_ARENA_OR_RATED_BATTLEGROUND: return 16;
+ case SPELL_ATTR4_IGNORE_DEFAULT_ARENA_RESTRICTIONS: return 17;
+ case SPELL_ATTR4_BOUNCY_CHAIN_MISSILES: return 18;
+ case SPELL_ATTR4_ALLOW_PROC_WHILE_SITTING: return 19;
+ case SPELL_ATTR4_AURA_NEVER_BOUNCES: return 20;
+ case SPELL_ATTR4_ALLOW_ENTERING_ARENA: return 21;
+ case SPELL_ATTR4_PROC_SUPPRESS_SWING_ANIM: return 22;
case SPELL_ATTR4_SUPPRESS_WEAPON_PROCS: return 23;
- case SPELL_ATTR4_UNK24: return 24;
- case SPELL_ATTR4_IS_PET_SCALING: return 25;
- case SPELL_ATTR4_CAST_ONLY_IN_OUTLAND: return 26;
- case SPELL_ATTR4_UNK27: return 27;
- case SPELL_ATTR4_UNK28: return 28;
- case SPELL_ATTR4_UNK29: return 29;
- case SPELL_ATTR4_UNK30: return 30;
- case SPELL_ATTR4_UNK31: return 31;
+ case SPELL_ATTR4_AUTO_RANGED_COMBAT: return 24;
+ case SPELL_ATTR4_OWNER_POWER_SCALING: return 25;
+ case SPELL_ATTR4_ONLY_FLYING_AREAS: return 26;
+ case SPELL_ATTR4_FORCE_DISPLAY_CASTBAR: return 27;
+ case SPELL_ATTR4_IGNORE_COMBAT_TIMER: return 28;
+ case SPELL_ATTR4_AURA_BOUNCE_FAILS_SPELL: return 29;
+ case SPELL_ATTR4_OBSOLETE: return 30;
+ case SPELL_ATTR4_USE_FACING_FROM_SPELL: return 31;
default: throw std::out_of_range("value");
}
}
@@ -904,7 +904,7 @@ TC_API_EXPORT EnumText EnumUtils<SpellAttr5>::ToString(SpellAttr5 value)
case SPELL_ATTR5_START_PERIODIC_AT_APPLY: return { "SPELL_ATTR5_START_PERIODIC_AT_APPLY", "Immediately do periodic tick on apply", "" };
case SPELL_ATTR5_HIDE_DURATION: return { "SPELL_ATTR5_HIDE_DURATION", "Do not send aura duration to client", "" };
case SPELL_ATTR5_ALLOW_TARGET_OF_TARGET_AS_TARGET: return { "SPELL_ATTR5_ALLOW_TARGET_OF_TARGET_AS_TARGET", "Auto-target target of target (client only)", "" };
- case SPELL_ATTR5_UNK12: return { "SPELL_ATTR5_UNK12", "Unknown attribute 12@Attr5", "Cleave related?" };
+ case SPELL_ATTR5_MELEE_CHAIN_TARGETING: return { "SPELL_ATTR5_MELEE_CHAIN_TARGETING", "Unknown attribute 12@Attr5", "Cleave related?" };
case SPELL_ATTR5_HASTE_AFFECT_DURATION: return { "SPELL_ATTR5_HASTE_AFFECT_DURATION", "Duration scales with Haste Rating", "" };
case SPELL_ATTR5_NOT_USABLE_WHILE_CHARMED: return { "SPELL_ATTR5_NOT_USABLE_WHILE_CHARMED", "Not Available While Charmed", "" };
case SPELL_ATTR5_UNK15: return { "SPELL_ATTR5_UNK15", "Unknown attribute 15@Attr5", "Related to multi-target spells?" };
@@ -948,7 +948,7 @@ TC_API_EXPORT SpellAttr5 EnumUtils<SpellAttr5>::FromIndex(size_t index)
case 9: return SPELL_ATTR5_START_PERIODIC_AT_APPLY;
case 10: return SPELL_ATTR5_HIDE_DURATION;
case 11: return SPELL_ATTR5_ALLOW_TARGET_OF_TARGET_AS_TARGET;
- case 12: return SPELL_ATTR5_UNK12;
+ case 12: return SPELL_ATTR5_MELEE_CHAIN_TARGETING;
case 13: return SPELL_ATTR5_HASTE_AFFECT_DURATION;
case 14: return SPELL_ATTR5_NOT_USABLE_WHILE_CHARMED;
case 15: return SPELL_ATTR5_UNK15;
@@ -989,7 +989,7 @@ TC_API_EXPORT size_t EnumUtils<SpellAttr5>::ToIndex(SpellAttr5 value)
case SPELL_ATTR5_START_PERIODIC_AT_APPLY: return 9;
case SPELL_ATTR5_HIDE_DURATION: return 10;
case SPELL_ATTR5_ALLOW_TARGET_OF_TARGET_AS_TARGET: return 11;
- case SPELL_ATTR5_UNK12: return 12;
+ case SPELL_ATTR5_MELEE_CHAIN_TARGETING: return 12;
case SPELL_ATTR5_HASTE_AFFECT_DURATION: return 13;
case SPELL_ATTR5_NOT_USABLE_WHILE_CHARMED: return 14;
case SPELL_ATTR5_UNK15: return 15;
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 326e33e1808..3d9bec79654 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -5309,14 +5309,14 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
damage = damageReducedArmor;
}
- if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
+ if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS))
{
if (GetSpellEffectInfo().IsTargetingArea() || GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA))
damage = target->CalculateAOEAvoidance(damage, m_spellInfo->SchoolMask, GetBase()->GetCasterGUID());
}
int32 dmg = damage;
- if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE) && caster && caster->CanApplyResilience())
+ if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS) && caster && caster->CanApplyResilience())
Unit::ApplyResilience(target, &dmg);
damage = dmg;
@@ -5398,14 +5398,14 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
damage = damageReducedArmor;
}
- if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
+ if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS))
{
if (GetSpellEffectInfo().IsTargetingArea() || GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA))
damage = target->CalculateAOEAvoidance(damage, m_spellInfo->SchoolMask, GetBase()->GetCasterGUID());
}
int32 dmg = damage;
- if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE) && caster && caster->CanApplyResilience())
+ if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS) && caster && caster->CanApplyResilience())
Unit::ApplyResilience(target, &dmg);
damage = dmg;
@@ -5581,7 +5581,8 @@ void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) con
{
gainedAmount = caster->ModifyPower(powerType, gainAmount);
// energize is not modified by threat modifiers
- target->GetThreatManager().AddThreat(caster, float(gainedAmount) * 0.5f, GetSpellInfo(), true);
+ if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_NO_HELPFUL_THREAT))
+ target->GetThreatManager().AddThreat(caster, float(gainedAmount) * 0.5f, GetSpellInfo(), true);
}
// Drain Mana - Mana Feed effect
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 995a697fac1..7e8c66b2015 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -1884,6 +1884,10 @@ uint32 Aura::GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo
if (target->GetGUID() != GetCasterGUID())
return 0;
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR4_ALLOW_PROC_WHILE_SITTING))
+ if (!target->IsStandState())
+ return 0;
+
bool success = roll_chance_f(CalcProcChance(*procEntry, eventInfo));
const_cast<Aura*>(this)->SetLastProcAttemptTime(now);
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index e11e5f2aadd..3a1817b611b 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -544,7 +544,7 @@ m_spellValue(new SpellValue(m_spellInfo, caster)), _spellEvent(nullptr)
if (info->HasAttribute(SPELL_ATTR2_DO_NOT_REPORT_SPELL_FAILURE))
_triggeredCastFlags = TriggerCastFlags(uint32(_triggeredCastFlags) | TRIGGERED_DONT_REPORT_CAST_ERROR);
- if (info->HasAttribute(SPELL_ATTR4_CAN_CAST_WHILE_CASTING))
+ if (info->HasAttribute(SPELL_ATTR4_ALLOW_CAST_WHILE_CASTING))
_triggeredCastFlags = TriggerCastFlags(uint32(_triggeredCastFlags) | TRIGGERED_IGNORE_CAST_IN_PROGRESS);
m_CastItem = nullptr;
@@ -1012,6 +1012,9 @@ void Spell::SelectImplicitChannelTargets(SpellEffectInfo const& spellEffectInfo,
if (target)
{
SpellDestination dest(*target);
+ if (m_spellInfo->HasAttribute(SPELL_ATTR4_USE_FACING_FROM_SPELL))
+ dest._position.SetOrientation(spellEffectInfo.PositionFacing);
+
CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
m_targets.SetDst(dest);
}
@@ -1023,6 +1026,9 @@ void Spell::SelectImplicitChannelTargets(SpellEffectInfo const& spellEffectInfo,
case TARGET_DEST_CHANNEL_CASTER:
{
SpellDestination dest(*channeledSpell->GetCaster());
+ if (m_spellInfo->HasAttribute(SPELL_ATTR4_USE_FACING_FROM_SPELL))
+ dest._position.SetOrientation(spellEffectInfo.PositionFacing);
+
CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
m_targets.SetDst(dest);
break;
@@ -1089,6 +1095,9 @@ void Spell::SelectImplicitNearbyTargets(SpellEffectInfo const& spellEffectInfo,
if (focusObject)
{
SpellDestination dest(*focusObject);
+ if (m_spellInfo->HasAttribute(SPELL_ATTR4_USE_FACING_FROM_SPELL))
+ dest._position.SetOrientation(spellEffectInfo.PositionFacing);
+
CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
m_targets.SetDst(dest);
}
@@ -1161,6 +1170,9 @@ void Spell::SelectImplicitNearbyTargets(SpellEffectInfo const& spellEffectInfo,
case TARGET_OBJECT_TYPE_DEST:
{
SpellDestination dest(*target);
+ if (m_spellInfo->HasAttribute(SPELL_ATTR4_USE_FACING_FROM_SPELL))
+ dest._position.SetOrientation(spellEffectInfo.PositionFacing);
+
CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
m_targets.SetDst(dest);
break;
@@ -1320,6 +1332,8 @@ void Spell::SelectImplicitAreaTargets(SpellEffectInfo const& spellEffectInfo, Sp
if (targetType.GetObjectType() == TARGET_OBJECT_TYPE_UNIT_AND_DEST)
{
SpellDestination dest(*referer);
+ if (m_spellInfo->HasAttribute(SPELL_ATTR4_USE_FACING_FROM_SPELL))
+ dest._position.SetOrientation(spellEffectInfo.PositionFacing);
CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
@@ -1517,6 +1531,9 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffectInfo const& spellEffectIn
}
}
+ if (m_spellInfo->HasAttribute(SPELL_ATTR4_USE_FACING_FROM_SPELL))
+ dest._position.SetOrientation(spellEffectInfo.PositionFacing);
+
CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
m_targets.SetDst(dest);
}
@@ -1549,6 +1566,9 @@ void Spell::SelectImplicitTargetDestTargets(SpellEffectInfo const& spellEffectIn
}
}
+ if (m_spellInfo->HasAttribute(SPELL_ATTR4_USE_FACING_FROM_SPELL))
+ dest._position.SetOrientation(spellEffectInfo.PositionFacing);
+
CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
m_targets.SetDst(dest);
}
@@ -1588,6 +1608,9 @@ void Spell::SelectImplicitDestDestTargets(SpellEffectInfo const& spellEffectInfo
}
}
+ if (m_spellInfo->HasAttribute(SPELL_ATTR4_USE_FACING_FROM_SPELL))
+ dest._position.SetOrientation(spellEffectInfo.PositionFacing);
+
CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
m_targets.ModDst(dest);
}
@@ -1696,14 +1719,21 @@ void Spell::SelectImplicitChainTargets(SpellEffectInfo const& spellEffectInfo, S
std::list<WorldObject*> targets;
SearchChainTargets(targets, maxTargets - 1, target, targetType.GetObjectType(), targetType.GetCheckType()
- , spellEffectInfo.ImplicitTargetConditions, targetType.GetTarget() == TARGET_UNIT_TARGET_CHAINHEAL_ALLY);
+ , spellEffectInfo, targetType.GetTarget() == TARGET_UNIT_TARGET_CHAINHEAL_ALLY);
// Chain primary target is added earlier
CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
+ Position const* losPosition = m_spellInfo->HasAttribute(SPELL_ATTR2_CHAIN_FROM_CASTER) ? m_caster : target;
+
for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
+ {
if (Unit* unit = (*itr)->ToUnit())
- AddUnitTarget(unit, effMask, false);
+ AddUnitTarget(unit, effMask, false, true, losPosition);
+
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CHAIN_FROM_CASTER) && !spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes::ChainFromInitialTarget))
+ losPosition = *itr;
+ }
}
}
@@ -1797,6 +1827,9 @@ void Spell::SelectImplicitTrajTargets(SpellEffectInfo const& spellEffectInfo, Sp
float z = m_targets.GetSrcPos()->m_positionZ + bestDist * (a * bestDist + b);
SpellDestination dest(x, y, z, unitCaster->GetOrientation());
+ if (m_spellInfo->HasAttribute(SPELL_ATTR4_USE_FACING_FROM_SPELL))
+ dest._position.SetOrientation(spellEffectInfo.PositionFacing);
+
CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
m_targets.ModDst(dest);
}
@@ -2049,7 +2082,7 @@ void Spell::SearchAreaTargets(std::list<WorldObject*>& targets, float range, Pos
SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellAreaTargetCheck> > (searcher, containerTypeMask, m_caster, position, range);
}
-void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, ConditionContainer* condList, bool isChainHeal)
+void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, SpellEffectInfo const& spellEffectInfo, bool isChainHeal)
{
// max dist for jump target selection
float jumpRadius = 0.0f;
@@ -2077,31 +2110,31 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo, SpellModOp::ChainJumpDistance, jumpRadius, this);
- // chain lightning/heal spells and similar - allow to jump at larger distance and go out of los
- bool isBouncingFar = (m_spellInfo->HasAttribute(SPELL_ATTR4_AREA_TARGET_CHAIN)
- || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_NONE
- || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC);
-
// max dist which spell can reach
- float searchRadius = jumpRadius;
- if (isBouncingFar)
- searchRadius *= chainTargets;
+ float searchRadius = [&]()
+ {
+ if (m_spellInfo->HasAttribute(SPELL_ATTR2_CHAIN_FROM_CASTER))
+ return GetMinMaxRange(false).second;
+
+ if (spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes::ChainFromInitialTarget))
+ return jumpRadius;
+
+ return jumpRadius * chainTargets;
+ }();
WorldObject* chainSource = m_spellInfo->HasAttribute(SPELL_ATTR2_CHAIN_FROM_CASTER) ? m_caster : target;
std::list<WorldObject*> tempTargets;
- SearchAreaTargets(tempTargets, searchRadius, chainSource, m_caster, objectType, selectType, condList);
+ SearchAreaTargets(tempTargets, searchRadius, chainSource, m_caster, objectType, selectType, spellEffectInfo.ImplicitTargetConditions);
tempTargets.remove(target);
// remove targets which are always invalid for chain spells
// for some spells allow only chain targets in front of caster (swipe for example)
- if (!isBouncingFar)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR5_MELEE_CHAIN_TARGETING))
{
- for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end();)
+ tempTargets.remove_if([&](WorldObject* object)
{
- std::list<WorldObject*>::iterator checkItr = itr++;
- if (!m_caster->HasInArc(static_cast<float>(M_PI), *checkItr))
- tempTargets.erase(checkItr);
- }
+ return !m_caster->HasInArc(static_cast<float>(M_PI), object);
+ });
}
while (chainTargets)
@@ -2132,7 +2165,7 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar
{
if (foundItr == tempTargets.end())
{
- if ((!isBouncingFar || chainSource->IsWithinDist(*itr, jumpRadius)) && chainSource->IsWithinLOSInMap(*itr, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
+ if (chainSource->IsWithinDist(*itr, jumpRadius) && chainSource->IsWithinLOSInMap(*itr, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
foundItr = itr;
}
else if (chainSource->GetDistanceOrder(*itr, *foundItr) && chainSource->IsWithinLOSInMap(*itr, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
@@ -2143,7 +2176,7 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar
if (foundItr == tempTargets.end())
break;
- if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CHAIN_FROM_CASTER))
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CHAIN_FROM_CASTER) && !spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes::ChainFromInitialTarget))
chainSource = *foundItr;
targets.push_back(*foundItr);
@@ -2290,17 +2323,35 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
if (m_caster != target)
{
float hitDelay = m_spellInfo->LaunchDelay;
+ WorldObject const* missileSource = m_caster;
+ if (m_spellInfo->HasAttribute(SPELL_ATTR4_BOUNCY_CHAIN_MISSILES))
+ {
+ auto previousTargetItr = std::find_if(m_UniqueTargetInfo.rbegin(), m_UniqueTargetInfo.rend(), [effectMask](TargetInfo const& target)
+ {
+ return (target.EffectMask & effectMask) != 0;
+ });
+ if (previousTargetItr != std::rend(m_UniqueTargetInfo))
+ {
+ hitDelay = 0.0f; // this is not the first target in chain, LaunchDelay was already included
+
+ if (WorldObject* previousTarget = ObjectAccessor::GetWorldObject(*m_caster, previousTargetItr->TargetGUID))
+ missileSource = previousTarget;
+
+ targetInfo.TimeDelay += previousTargetItr->TimeDelay;
+ }
+ }
+
if (m_spellInfo->HasAttribute(SPELL_ATTR9_SPECIAL_DELAY_CALCULATION))
hitDelay += m_spellInfo->Speed;
else if (m_spellInfo->Speed > 0.0f)
{
// calculate spell incoming interval
/// @todo this is a hack
- float dist = std::max(m_caster->GetDistance(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()), 5.0f);
+ float dist = std::max(missileSource->GetDistance(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()), 5.0f);
hitDelay += dist / m_spellInfo->Speed;
}
- targetInfo.TimeDelay = uint64(std::floor(hitDelay * 1000.0f));
+ targetInfo.TimeDelay += uint64(std::floor(hitDelay * 1000.0f));
}
else
targetInfo.TimeDelay = 0ULL;
@@ -2603,8 +2654,7 @@ void Spell::TargetInfo::DoDamageAndTriggers(Spell* spell)
// Spells with this flag cannot trigger if effect is cast on self
bool const canEffectTrigger = (!spell->m_spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_CASTER_PROCS) || !spell->m_spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_TARGET_PROCS))
- && spell->unitTarget->CanProc()
- && (spell->CanExecuteTriggersOnHit(EffectMask) || MissCondition == SPELL_MISS_IMMUNE || MissCondition == SPELL_MISS_IMMUNE2);
+ && spell->unitTarget->CanProc();
// Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now
if (canEffectTrigger && !procAttacker && !procVictim)
@@ -2834,7 +2884,7 @@ void Spell::TargetInfo::DoDamageAndTriggers(Spell* spell)
}
// Needs to be called after dealing damage/healing to not remove breaking on damage auras
- spell->DoTriggersOnSpellHit(_spellHitTarget, EffectMask);
+ spell->DoTriggersOnSpellHit(_spellHitTarget);
}
if (_enablePVP)
@@ -3099,7 +3149,7 @@ void Spell::DoSpellEffectHit(Unit* unit, SpellEffectInfo const& spellEffectInfo,
_spellAura = nullptr;
}
-void Spell::DoTriggersOnSpellHit(Unit* unit, uint32 effMask)
+void Spell::DoTriggersOnSpellHit(Unit* unit)
{
// handle SPELL_AURA_ADD_TARGET_TRIGGER auras
// this is executed after spell proc spells on target hit
@@ -3110,7 +3160,7 @@ void Spell::DoTriggersOnSpellHit(Unit* unit, uint32 effMask)
int32 _duration = 0;
for (auto i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i)
{
- if (CanExecuteTriggersOnHit(effMask, i->triggeredByAura) && roll_chance_i(i->chance))
+ if (CanExecuteTriggersOnHit(unit, i->triggeredByAura) && roll_chance_i(i->chance))
{
m_caster->CastSpell(unit, i->triggeredSpell->Id, CastSpellExtraArgs(TRIGGERED_FULL_MASK)
.SetTriggeringSpell(this)
@@ -3668,7 +3718,7 @@ void Spell::_cast(bool skipCheck)
creatureCaster->ReleaseSpellFocus(this);
// Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
- if ((m_spellInfo->HasHitDelay() && !m_spellInfo->IsChanneled()) || m_spellInfo->HasAttribute(SPELL_ATTR4_UNK4))
+ if ((m_spellInfo->HasHitDelay() && !m_spellInfo->IsChanneled()) || m_spellInfo->HasAttribute(SPELL_ATTR4_NO_HARMFUL_THREAT))
{
// Remove used for cast item if need (it can be already NULL after TakeReagents call
// in case delayed spell remove item at cast delay start
@@ -6500,7 +6550,10 @@ SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32
}
// check if target already has the same type, but more powerful aura
- if (!nonAuraEffectMask && (approximateAuraEffectMask & (1 << spellEffectInfo.EffectIndex)) && !m_spellInfo->IsTargetingArea())
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR4_AURA_NEVER_BOUNCES)
+ && (!nonAuraEffectMask || m_spellInfo->HasAttribute(SPELL_ATTR4_AURA_BOUNCE_FAILS_SPELL))
+ && (approximateAuraEffectMask & (1 << spellEffectInfo.EffectIndex))
+ && !m_spellInfo->IsTargetingArea())
if (Unit* target = m_targets.GetUnitTarget())
if (!target->IsHighestExclusiveAuraEffect(m_spellInfo, spellEffectInfo.ApplyAuraName,
spellEffectInfo.CalcValue(m_caster, &m_spellValue->EffectBasePoints[spellEffectInfo.EffectIndex], nullptr, nullptr, m_castItemEntry, m_castItemLevel),
@@ -6786,11 +6839,11 @@ SpellCastResult Spell::CheckArenaAndRatedBattlegroundCastRules()
if (isRatedBattleground && m_spellInfo->HasAttribute(SPELL_ATTR9_USABLE_IN_RATED_BATTLEGROUNDS))
return SPELL_CAST_OK;
- if (isArena && m_spellInfo->HasAttribute(SPELL_ATTR4_USABLE_IN_ARENA))
+ if (isArena && m_spellInfo->HasAttribute(SPELL_ATTR4_IGNORE_DEFAULT_ARENA_RESTRICTIONS))
return SPELL_CAST_OK;
// check NOT_USABLE attributes
- if (m_spellInfo->HasAttribute(SPELL_ATTR4_NOT_USABLE_IN_ARENA_OR_RATED_BG))
+ if (m_spellInfo->HasAttribute(SPELL_ATTR4_NOT_IN_ARENA_OR_RATED_BATTLEGROUND))
return isArena ? SPELL_FAILED_NOT_IN_ARENA : SPELL_FAILED_NOT_IN_RATED_BATTLEGROUND;
if (isArena && m_spellInfo->HasAttribute(SPELL_ATTR9_NOT_USABLE_IN_ARENA))
@@ -8530,15 +8583,20 @@ bool Spell::CheckScriptEffectImplicitTargets(uint32 effIndex, uint32 effIndexToC
return true;
}
-bool Spell::CanExecuteTriggersOnHit(uint32 effMask, SpellInfo const* triggeredByAura /*= nullptr*/) const
+bool Spell::CanExecuteTriggersOnHit(Unit* unit, SpellInfo const* triggeredByAura /*= nullptr*/) const
{
- bool only_on_caster = (triggeredByAura && (triggeredByAura->HasAttribute(SPELL_ATTR4_PROC_ONLY_ON_CASTER)));
- // If triggeredByAura has SPELL_ATTR4_PROC_ONLY_ON_CASTER then it can only proc on a cast spell with TARGET_UNIT_CASTER
- for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
- {
- if ((effMask & (1 << spellEffectInfo.EffectIndex)) && (!only_on_caster || (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_CASTER)))
- return true;
- }
+ bool onlyOnTarget = (triggeredByAura && (triggeredByAura->HasAttribute(SPELL_ATTR4_CLASS_TRIGGER_ONLY_ON_TARGET)));
+ if (!onlyOnTarget)
+ return true;
+
+ // If triggeredByAura has SPELL_ATTR4_CLASS_TRIGGER_ONLY_ON_TARGET then it can only proc on either noncaster units...
+ if (unit != m_caster)
+ return true;
+
+ // ... or caster if it is the only target
+ if (m_UniqueTargetInfo.size() == 1)
+ return true;
+
return false;
}
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 64f7b6db188..23e044c30e2 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -433,7 +433,7 @@ class TC_GAME_API Spell
WorldObject* SearchNearbyTarget(float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer* condList = nullptr);
void SearchAreaTargets(std::list<WorldObject*>& targets, float range, Position const* position, WorldObject* referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer* condList);
- void SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, ConditionContainer* condList, bool isChainHeal);
+ void SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, SpellEffectInfo const& spellEffectInfo, bool isChainHeal);
GameObject* SearchSpellFocus();
@@ -805,7 +805,7 @@ class TC_GAME_API Spell
SpellMissInfo PreprocessSpellHit(Unit* unit, TargetInfo& targetInfo);
void DoSpellEffectHit(Unit* unit, SpellEffectInfo const& spellEffectInfo, TargetInfo& targetInfo);
- void DoTriggersOnSpellHit(Unit* unit, uint32 effMask);
+ void DoTriggersOnSpellHit(Unit* unit);
bool UpdateChanneledTargetList();
bool IsValidDeadOrAliveTarget(Unit const* target) const;
void HandleLaunchPhase();
@@ -846,7 +846,7 @@ class TC_GAME_API Spell
int32 chance;
};
- bool CanExecuteTriggersOnHit(uint32 effMask, SpellInfo const* triggeredByAura = nullptr) const;
+ bool CanExecuteTriggersOnHit(Unit* unit, SpellInfo const* triggeredByAura = nullptr) const;
void PrepareTriggersExecutedOnHit();
typedef std::vector<HitTriggerSpell> HitTriggerSpellList;
HitTriggerSpellList m_hitTriggerSpells;
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 38e0661c9d9..ec7104c0561 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -4590,7 +4590,7 @@ void Spell::EffectStealBeneficialBuff()
if ((aura->GetSpellInfo()->GetDispelMask()) & dispelMask)
{
// Need check for passive? this
- if (!aurApp->IsPositive() || aura->IsPassive() || aura->GetSpellInfo()->HasAttribute(SPELL_ATTR4_NOT_STEALABLE))
+ if (!aurApp->IsPositive() || aura->IsPassive() || aura->GetSpellInfo()->HasAttribute(SPELL_ATTR4_CANNOT_BE_STOLEN))
continue;
// 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 23c1b9c670c..b362e91621c 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -1675,7 +1675,7 @@ bool SpellInfo::IsAutoRepeatRangedSpell() const
bool SpellInfo::HasInitialAggro() const
{
- return !(HasAttribute(SPELL_ATTR1_NO_THREAT) || HasAttribute(SPELL_ATTR2_NO_INITIAL_THREAT));
+ return !(HasAttribute(SPELL_ATTR1_NO_THREAT) || HasAttribute(SPELL_ATTR2_NO_INITIAL_THREAT) || HasAttribute(SPELL_ATTR4_NO_HARMFUL_THREAT));
}
bool SpellInfo::HasHitDelay() const
@@ -1952,7 +1952,7 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a
}
// continent limitation (virtual continent)
- if (HasAttribute(SPELL_ATTR4_CAST_ONLY_IN_OUTLAND))
+ if (HasAttribute(SPELL_ATTR4_ONLY_FLYING_AREAS))
{
uint32 mountFlags = 0;
if (player && player->HasAuraType(SPELL_AURA_MOUNT_RESTRICTIONS))
@@ -3943,7 +3943,7 @@ Optional<SpellPowerCost> SpellInfo::CalcPowerCost(SpellPowerEntry const* power,
bool initiallyNegative = powerCost < 0;
// Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost)
- if (HasAttribute(SPELL_ATTR4_SPELL_VS_EXTEND_COST))
+ if (HasAttribute(SPELL_ATTR4_WEAPON_SPEED_COST_SCALING))
{
uint32 speed = 0;
if (SpellShapeshiftFormEntry const* ss = sSpellShapeshiftFormStore.LookupEntry(unitCaster->GetShapeshiftForm()))
@@ -4407,6 +4407,9 @@ bool _isPositiveEffectImpl(SpellInfo const* spellInfo, SpellEffectInfo const& ef
if (spellInfo->HasAttribute(SPELL_ATTR0_AURA_IS_DEBUFF))
return false;
+ if (spellInfo->HasAttribute(SPELL_ATTR4_AURA_IS_BUFF))
+ return true;
+
visited.insert({ spellInfo, effect.EffectIndex });
//We need scaling level info for some auras that compute bp 0 or positive but should be debuffs
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index b67cbed7112..8b56ff8b98a 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3478,7 +3478,7 @@ void SpellMgr::LoadSpellInfoCorrections()
60864 // Jaws of Death
}, [](SpellInfo* spellInfo)
{
- spellInfo->AttributesEx4 |= SPELL_ATTR4_FIXED_DAMAGE;
+ spellInfo->AttributesEx4 |= SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS;
});
// Howl of Azgalor
@@ -4144,12 +4144,6 @@ void SpellMgr::LoadSpellInfoCorrections()
});
});
- // Coldflame (Lord Marrowgar)
- ApplySpellFix({ 69146 }, [](SpellInfo* spellInfo)
- {
- spellInfo->AttributesEx4 &= ~SPELL_ATTR4_IGNORE_RESISTANCES;
- });
-
// Shadow's Fate
ApplySpellFix({ 71169 }, [](SpellInfo* spellInfo)
{