Core/Spells: Rename SpellAttr2 to use official attribute names
* Corrected implementation of SPELL_ATTR1_ALLOW_WHILE_STEALTHED * Implemented SPELL_ATTR2_RETAIN_ITEM_CAST * Implemented SPELL_ATTR2_ALLOW_WHILE_INVISIBLE * Implemented SPELL_ATTR0_PROC_FAILURE_BURNS_CHARGE * Implemented SPELL_ATTR2_PROC_COOLDOWN_ON_FAILURE * Implemented SPELL_ATTR2_NO_TARGET_PER_SECOND_COSTS * Implemented SPELL_ATTR2_DO_NOT_REPORT_SPELL_FAILURE * Implemented SPELL_ATTR1_REQUIRE_ALL_TARGETS * Implemented SPELL_ATTR2_CHAIN_FROM_CASTER * Implemented SPELL_ATTR2_NO_ACTIVE_PETS * Implemented SPELL_ATTR2_ENCHANT_OWN_ITEM_ONLY
This commit is contained in:
@@ -2364,7 +2364,7 @@ void WorldObject::ModSpellCastTime(SpellInfo const* spellInfo, int32& castTime,
|
||||
if (!(spellInfo->HasAttribute(SPELL_ATTR0_IS_ABILITY) || spellInfo->HasAttribute(SPELL_ATTR0_IS_TRADESKILL) || spellInfo->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS)) &&
|
||||
((GetTypeId() == TYPEID_PLAYER && spellInfo->SpellFamilyName) || GetTypeId() == TYPEID_UNIT))
|
||||
castTime = unitCaster->CanInstantCast() ? 0 : int32(float(castTime) * unitCaster->m_unitData->ModCastingSpeed);
|
||||
else if (spellInfo->HasAttribute(SPELL_ATTR0_USES_RANGED_SLOT) && !spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG))
|
||||
else if (spellInfo->HasAttribute(SPELL_ATTR0_USES_RANGED_SLOT) && !spellInfo->HasAttribute(SPELL_ATTR2_AUTO_REPEAT))
|
||||
castTime = int32(float(castTime) * unitCaster->m_modAttackSpeedPct[RANGED_ATTACK]);
|
||||
else if (IsPartOfSkillLine(SKILL_COOKING, spellInfo->Id) && unitCaster->HasAura(67556)) // cooking with Chef Hat.
|
||||
castTime = 500;
|
||||
@@ -2389,7 +2389,7 @@ void WorldObject::ModSpellDurationTime(SpellInfo const* spellInfo, int32& durati
|
||||
if (!(spellInfo->HasAttribute(SPELL_ATTR0_IS_ABILITY) || spellInfo->HasAttribute(SPELL_ATTR0_IS_TRADESKILL) || spellInfo->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS)) &&
|
||||
((GetTypeId() == TYPEID_PLAYER && spellInfo->SpellFamilyName) || GetTypeId() == TYPEID_UNIT))
|
||||
duration = int32(float(duration) * unitCaster->m_unitData->ModCastingSpeed);
|
||||
else if (spellInfo->HasAttribute(SPELL_ATTR0_USES_RANGED_SLOT) && !spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG))
|
||||
else if (spellInfo->HasAttribute(SPELL_ATTR0_USES_RANGED_SLOT) && !spellInfo->HasAttribute(SPELL_ATTR2_AUTO_REPEAT))
|
||||
duration = int32(float(duration) * unitCaster->m_modAttackSpeedPct[RANGED_ATTACK]);
|
||||
}
|
||||
|
||||
@@ -2775,6 +2775,15 @@ SpellCastResult WorldObject::CastSpell(CastSpellTargetArg const& targets, uint32
|
||||
if (args.OriginalCastItemLevel)
|
||||
spell->m_castItemLevel = *args.OriginalCastItemLevel;
|
||||
|
||||
if (!spell->m_CastItem && info->HasAttribute(SPELL_ATTR2_RETAIN_ITEM_CAST))
|
||||
{
|
||||
if (args.TriggeringSpell)
|
||||
spell->m_CastItem = args.TriggeringSpell->m_CastItem;
|
||||
else if (args.TriggeringAura && !args.TriggeringAura->GetBase()->GetCastItemGUID().IsEmpty())
|
||||
if (Player const* triggeringAuraCaster = Object::ToPlayer(args.TriggeringAura->GetCaster()))
|
||||
spell->m_CastItem = triggeringAuraCaster->GetItemByGuid(args.TriggeringAura->GetBase()->GetCastItemGUID());
|
||||
}
|
||||
|
||||
return spell->prepare(*targets.Targets, args.TriggeringAura);
|
||||
}
|
||||
|
||||
|
||||
@@ -3132,7 +3132,7 @@ bool Player::HandlePassiveSpellLearn(SpellInfo const* spellInfo)
|
||||
// talent dependent passives activated at form apply have proper stance data
|
||||
ShapeshiftForm form = GetShapeshiftForm();
|
||||
bool need_cast = (!spellInfo->Stances || (form && (spellInfo->Stances & (UI64LIT(1) << (form - 1)))) ||
|
||||
(!form && (spellInfo->HasAttribute(SPELL_ATTR2_NOT_NEED_SHAPESHIFT))));
|
||||
(!form && (spellInfo->HasAttribute(SPELL_ATTR2_ALLOW_WHILE_NOT_SHAPESHIFTED_CASTER_FORM))));
|
||||
|
||||
// Check EquippedItemClass
|
||||
// passive spells which apply aura and have an item requirement are to be added manually, instead of casted
|
||||
@@ -5465,7 +5465,7 @@ bool Player::UpdateCraftSkill(SpellInfo const* spellInfo)
|
||||
uint32 SkillValue = GetPureSkillValue(_spell_idx->second->SkillupSkillLineID);
|
||||
|
||||
// Alchemy Discoveries here
|
||||
if (spellInfo && spellInfo->Mechanic == MECHANIC_DISCOVERY)
|
||||
if (spellInfo->Mechanic == MECHANIC_DISCOVERY)
|
||||
{
|
||||
if (uint32 discoveredSpell = GetSkillDiscoverySpell(_spell_idx->second->SkillupSkillLineID, spellInfo->Id, this))
|
||||
LearnSpell(discoveredSpell, false);
|
||||
@@ -24758,7 +24758,7 @@ void Player::ApplyEquipCooldown(Item* pItem)
|
||||
continue;
|
||||
|
||||
if (Aura* itemAura = GetAura(effectData->SpellID, GetGUID(), pItem->GetGUID()))
|
||||
itemAura->AddProcCooldown(now + procEntry->Cooldown);
|
||||
itemAura->AddProcCooldown(procEntry, now);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -759,10 +759,10 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons
|
||||
if (spellProto)
|
||||
{
|
||||
if (!spellProto->HasAttribute(SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS))
|
||||
victim->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Damage, spellProto->Id);
|
||||
victim->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Damage, spellProto);
|
||||
}
|
||||
else
|
||||
victim->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Damage, 0);
|
||||
victim->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Damage);
|
||||
|
||||
if (!damage && damagetype != DOT && cleanDamage && cleanDamage->absorbed_damage)
|
||||
if (victim != attacker && victim->GetTypeId() == TYPEID_PLAYER)
|
||||
@@ -956,7 +956,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons
|
||||
victim->ModifyHealth(-(int32)damage);
|
||||
|
||||
if (damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE)
|
||||
victim->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::NonPeriodicDamage, spellProto ? spellProto->Id : 0);
|
||||
victim->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::NonPeriodicDamage, spellProto);
|
||||
|
||||
if (victim->GetTypeId() != TYPEID_PLAYER)
|
||||
{
|
||||
@@ -2950,7 +2950,7 @@ bool Unit::IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled, bool skipAu
|
||||
{
|
||||
if (!skipInstant || m_currentSpells[CURRENT_GENERIC_SPELL]->GetCastTime())
|
||||
{
|
||||
if (!isAutoshoot || !(m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS)))
|
||||
if (!isAutoshoot || !(m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS)))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2958,7 +2958,7 @@ bool Unit::IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled, bool skipAu
|
||||
if (!skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
|
||||
(m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED))
|
||||
{
|
||||
if (!isAutoshoot || !(m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS)))
|
||||
if (!isAutoshoot || !(m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS)))
|
||||
return true;
|
||||
}
|
||||
// autorepeat spells may be finished or delayed, but they are still considered cast
|
||||
@@ -3921,19 +3921,38 @@ void Unit::RemoveNotOwnSingleTargetAuras(bool onPhaseChange /*= false*/)
|
||||
}
|
||||
|
||||
template<typename InterruptFlag>
|
||||
bool IsInterruptFlagIgnoredForSpell(InterruptFlag /*flag*/, Unit const* /*unit*/, SpellInfo const* /*spellInfo*/)
|
||||
bool IsInterruptFlagIgnoredForSpell(InterruptFlag /*flag*/, Unit const* /*unit*/, SpellInfo const* /*auraSpellInfo*/, SpellInfo const* /*interruptSource*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags flag, Unit const* unit, SpellInfo const* spellInfo)
|
||||
bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags flag, Unit const* unit, SpellInfo const* auraSpellInfo, SpellInfo const* interruptSource)
|
||||
{
|
||||
return flag == SpellAuraInterruptFlags::Moving && unit->CanCastSpellWhileMoving(spellInfo);
|
||||
switch (flag)
|
||||
{
|
||||
case SpellAuraInterruptFlags::Moving:
|
||||
return unit->CanCastSpellWhileMoving(auraSpellInfo);
|
||||
case SpellAuraInterruptFlags::Action:
|
||||
case SpellAuraInterruptFlags::ActionDelayed:
|
||||
if (interruptSource)
|
||||
{
|
||||
if (interruptSource->HasAttribute(SPELL_ATTR1_ALLOW_WHILE_STEALTHED) && auraSpellInfo->HasAura(SPELL_AURA_MOD_STEALTH))
|
||||
return true;
|
||||
|
||||
if (interruptSource->HasAttribute(SPELL_ATTR2_ALLOW_WHILE_INVISIBLE) && auraSpellInfo->HasAura(SPELL_AURA_MOD_INVISIBILITY))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename InterruptFlags>
|
||||
void Unit::RemoveAurasWithInterruptFlags(InterruptFlags flag, uint32 except)
|
||||
void Unit::RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const* source)
|
||||
{
|
||||
if (!HasInterruptFlag(flag))
|
||||
return;
|
||||
@@ -3944,8 +3963,8 @@ void Unit::RemoveAurasWithInterruptFlags(InterruptFlags flag, uint32 except)
|
||||
Aura* aura = (*iter)->GetBase();
|
||||
++iter;
|
||||
if (aura->GetSpellInfo()->HasAuraInterruptFlag(flag)
|
||||
&& (!except || aura->GetId() != except)
|
||||
&& !IsInterruptFlagIgnoredForSpell(flag, this, aura->GetSpellInfo()))
|
||||
&& (!source || aura->GetId() != source->Id)
|
||||
&& !IsInterruptFlagIgnoredForSpell(flag, this, aura->GetSpellInfo(), source))
|
||||
{
|
||||
uint32 removedAuras = m_removedAurasCount;
|
||||
RemoveAura(aura, AURA_REMOVE_BY_INTERRUPT);
|
||||
@@ -3958,15 +3977,15 @@ void Unit::RemoveAurasWithInterruptFlags(InterruptFlags flag, uint32 except)
|
||||
if (Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL])
|
||||
if (spell->getState() == SPELL_STATE_CASTING
|
||||
&& spell->GetSpellInfo()->HasChannelInterruptFlag(flag)
|
||||
&& spell->GetSpellInfo()->Id != except
|
||||
&& !IsInterruptFlagIgnoredForSpell(flag, this, spell->GetSpellInfo()))
|
||||
&& (!source || spell->GetSpellInfo()->Id != source->Id)
|
||||
&& !IsInterruptFlagIgnoredForSpell(flag, this, spell->GetSpellInfo(), source))
|
||||
InterruptNonMeleeSpells(false);
|
||||
|
||||
UpdateInterruptMask();
|
||||
}
|
||||
|
||||
template TC_GAME_API void Unit::RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags flag, uint32 except);
|
||||
template TC_GAME_API void Unit::RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2 flag, uint32 except);
|
||||
template TC_GAME_API void Unit::RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags flag, SpellInfo const* source);
|
||||
template TC_GAME_API void Unit::RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2 flag, SpellInfo const* source);
|
||||
|
||||
void Unit::RemoveAurasWithFamily(SpellFamilyNames family, flag128 const& familyFlag, ObjectGuid casterGUID)
|
||||
{
|
||||
@@ -7169,7 +7188,7 @@ bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) const
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) && spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
|
||||
return false;
|
||||
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) || spellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) || spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
|
||||
return false;
|
||||
|
||||
if (uint32 schoolMask = spellInfo->GetSchoolMask())
|
||||
@@ -7321,7 +7340,7 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo co
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!spellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
|
||||
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
|
||||
{
|
||||
// Check for immune to application of harmful magical effects
|
||||
AuraEffectList const& immuneAuraApply = GetAuraEffectsByType(SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL);
|
||||
@@ -9805,30 +9824,44 @@ void Unit::GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer& aurasTrigg
|
||||
{
|
||||
TimePoint now = GameTime::Now();
|
||||
|
||||
auto processAuraApplication = [&](AuraApplication* aurApp)
|
||||
{
|
||||
if (uint32 procEffectMask = aurApp->GetBase()->GetProcEffectMask(aurApp, eventInfo, now))
|
||||
{
|
||||
aurApp->GetBase()->PrepareProcToTrigger(aurApp, eventInfo, now);
|
||||
aurasTriggeringProc.emplace_back(procEffectMask, aurApp);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (aurApp->GetBase()->GetSpellInfo()->HasAttribute(SPELL_ATTR0_PROC_FAILURE_BURNS_CHARGE))
|
||||
{
|
||||
if (SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(aurApp->GetBase()->GetSpellInfo()))
|
||||
{
|
||||
aurApp->GetBase()->PrepareProcChargeDrop(procEntry, eventInfo);
|
||||
aurApp->GetBase()->ConsumeProcCharges(procEntry);
|
||||
}
|
||||
}
|
||||
|
||||
if (aurApp->GetBase()->GetSpellInfo()->HasAttribute(SPELL_ATTR2_PROC_COOLDOWN_ON_FAILURE))
|
||||
if (SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(aurApp->GetBase()->GetSpellInfo()))
|
||||
aurApp->GetBase()->AddProcCooldown(procEntry, now);
|
||||
}
|
||||
};
|
||||
|
||||
// use provided list of auras which can proc
|
||||
if (procAuras)
|
||||
{
|
||||
for (AuraApplication* aurApp : *procAuras)
|
||||
{
|
||||
ASSERT(aurApp->GetTarget() == this);
|
||||
if (uint32 procEffectMask = aurApp->GetBase()->GetProcEffectMask(aurApp, eventInfo, now))
|
||||
{
|
||||
aurApp->GetBase()->PrepareProcToTrigger(aurApp, eventInfo, now);
|
||||
aurasTriggeringProc.emplace_back(procEffectMask, aurApp);
|
||||
}
|
||||
processAuraApplication(aurApp);
|
||||
}
|
||||
}
|
||||
// or generate one on our own
|
||||
else
|
||||
{
|
||||
for (AuraApplicationMap::iterator itr = GetAppliedAuras().begin(); itr != GetAppliedAuras().end(); ++itr)
|
||||
{
|
||||
if (uint32 procEffectMask = itr->second->GetBase()->GetProcEffectMask(itr->second, eventInfo, now))
|
||||
{
|
||||
itr->second->GetBase()->PrepareProcToTrigger(itr->second, eventInfo, now);
|
||||
aurasTriggeringProc.emplace_back(procEffectMask, itr->second);
|
||||
}
|
||||
}
|
||||
processAuraApplication(itr->second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9878,12 +9911,8 @@ void Unit::TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationProc
|
||||
if (disableProcs)
|
||||
SetCantProc(true);
|
||||
|
||||
for (auto const& aurAppProc : aurasTriggeringProc)
|
||||
for (auto const& [procEffectMask, aurApp] : aurasTriggeringProc)
|
||||
{
|
||||
AuraApplication* aurApp;
|
||||
uint32 procEffectMask;
|
||||
std::tie(procEffectMask, aurApp) = aurAppProc;
|
||||
|
||||
if (aurApp->GetRemoveMode())
|
||||
continue;
|
||||
|
||||
@@ -11563,7 +11592,7 @@ Aura* Unit::AddAura(SpellInfo const* spellInfo, uint32 effMask, Unit* target)
|
||||
if (!spellInfo)
|
||||
return nullptr;
|
||||
|
||||
if (!target->IsAlive() && !spellInfo->IsPassive() && !spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_DEAD))
|
||||
if (!target->IsAlive() && !spellInfo->IsPassive() && !spellInfo->HasAttribute(SPELL_ATTR2_ALLOW_DEAD_TARGET))
|
||||
return nullptr;
|
||||
|
||||
if (target->IsImmunedToSpell(spellInfo, this))
|
||||
|
||||
@@ -1382,7 +1382,7 @@ class TC_GAME_API Unit : public WorldObject
|
||||
void RemoveAurasByType(AuraType auraType, ObjectGuid casterGUID = ObjectGuid::Empty, Aura* except = nullptr, bool negative = true, bool positive = true);
|
||||
void RemoveNotOwnSingleTargetAuras(bool onPhaseChange = false);
|
||||
template <typename InterruptFlags>
|
||||
void RemoveAurasWithInterruptFlags(InterruptFlags flag, uint32 except = 0);
|
||||
void RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const* source = nullptr);
|
||||
void RemoveAurasWithAttribute(uint32 flags);
|
||||
void RemoveAurasWithFamily(SpellFamilyNames family, flag128 const& familyFlag, ObjectGuid casterGUID);
|
||||
void RemoveAurasWithMechanic(uint32 mechanic_mask, AuraRemoveMode removemode = AURA_REMOVE_BY_DEFAULT, uint32 except = 0);
|
||||
|
||||
@@ -404,7 +404,7 @@ uint32 constexpr QuestDifficultyColors[MAX_QUEST_DIFFICULTY] =
|
||||
// EnumUtils: DESCRIBE THIS
|
||||
enum SpellAttr0 : uint32
|
||||
{
|
||||
SPELL_ATTR0_PROC_FAILURE_BURNS_CHARGE = 0x00000001, /*NYI*/ // TITLE Proc Failure Burns Charge
|
||||
SPELL_ATTR0_PROC_FAILURE_BURNS_CHARGE = 0x00000001, /*NYI, proc failure includes missed roll*/ // TITLE Proc Failure Burns Charge
|
||||
SPELL_ATTR0_USES_RANGED_SLOT = 0x00000002, // TITLE Uses Ranged Slot DESCRIPTION Use ammo, ranged attack range modifiers, ranged haste, etc.
|
||||
SPELL_ATTR0_ON_NEXT_SWING_NO_DAMAGE = 0x00000004, // TITLE On Next Swing (No Damage) DESCRIPTION Both "on next swing" attributes have identical handling in server & client
|
||||
SPELL_ATTR0_DO_NOT_LOG_IMMUNE_MISSES = 0x00000008, // TITLE Do Not Log Immune Misses (client only)
|
||||
@@ -415,7 +415,7 @@ enum SpellAttr0 : uint32
|
||||
SPELL_ATTR0_DO_NOT_LOG = 0x00000100, // TITLE Do Not Log (client only) DESCRIPTION Spell will not appear in combat logs
|
||||
SPELL_ATTR0_HELD_ITEM_ONLY = 0x00000200, // TITLE Held Item Only (client only) DESCRIPTION Client will automatically select main-hand item as cast target
|
||||
SPELL_ATTR0_ON_NEXT_SWING = 0x00000400, // TITLE On Next Swing DESCRIPTION Both "on next swing" attributes have identical handling in server & client
|
||||
SPELL_ATTR0_WEARER_CASTS_PROC_TRIGGER = 0x00000800, /*NYI*/ // TITLE Wearer Casts Proc Trigger
|
||||
SPELL_ATTR0_WEARER_CASTS_PROC_TRIGGER = 0x00000800, // TITLE Wearer Casts Proc Trigger DESCRIPTION Just a marker attribute to show auras that trigger another spell (either directly or with a script)
|
||||
SPELL_ATTR0_SERVER_ONLY = 0x00001000, // TITLE Server Only
|
||||
SPELL_ATTR0_ALLOW_ITEM_SPELL_IN_PVP = 0x00002000, // TITLE Allow Item Spell In PvP
|
||||
SPELL_ATTR0_ONLY_INDOORS = 0x00004000, // TITLE Only Indoors
|
||||
@@ -467,7 +467,7 @@ enum SpellAttr1 : uint32
|
||||
SPELL_ATTR1_IGNORE_OWNERS_DEATH = 0x00800000, /*NYI*/ // TITLE Ignore Owner's Death
|
||||
SPELL_ATTR1_SPECIAL_SKILLUP = 0x01000000, // TITLE Special Skillup
|
||||
SPELL_ATTR1_AURA_STAYS_AFTER_COMBAT = 0x02000000, // TITLE Aura Stays After Combat
|
||||
SPELL_ATTR1_REQUIRE_ALL_TARGETS = 0x04000000, /*NYI, UNK*/ // TITLE Require All Targets
|
||||
SPELL_ATTR1_REQUIRE_ALL_TARGETS = 0x04000000, // TITLE Require All Targets
|
||||
SPELL_ATTR1_DISCOUNT_POWER_ON_MISS = 0x08000000, // TITLE Discount Power On Miss
|
||||
SPELL_ATTR1_NO_AURA_ICON = 0x10000000, // TITLE No Aura Icon (client only)
|
||||
SPELL_ATTR1_NAME_IN_CHANNEL_BAR = 0x20000000, // TITLE Name in Channel Bar (client only)
|
||||
@@ -478,38 +478,38 @@ enum SpellAttr1 : uint32
|
||||
// EnumUtils: DESCRIBE THIS
|
||||
enum SpellAttr2 : uint32
|
||||
{
|
||||
SPELL_ATTR2_CAN_TARGET_DEAD = 0x00000001, // TITLE Can target dead players or corpses
|
||||
SPELL_ATTR2_UNK1 = 0x00000002, // TITLE Unknown attribute 1@Attr2
|
||||
SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS = 0x00000004, // TITLE Ignore Line of Sight
|
||||
SPELL_ATTR2_UNK3 = 0x00000008, // TITLE Ignore aura scaling
|
||||
SPELL_ATTR2_DISPLAY_IN_STANCE_BAR = 0x00000010, // TITLE Show in stance bar (client only)
|
||||
SPELL_ATTR2_AUTOREPEAT_FLAG = 0x00000020, // TITLE Ranged auto-attack spell
|
||||
SPELL_ATTR2_CANT_TARGET_TAPPED = 0x00000040, // TITLE Cannot target others' tapped units DESCRIPTION Can only target untapped units, or those tapped by caster
|
||||
SPELL_ATTR2_UNK7 = 0x00000080, // TITLE Unknown attribute 7@Attr2
|
||||
SPELL_ATTR2_UNK8 = 0x00000100, // TITLE Unknown attribute 8@Attr2
|
||||
SPELL_ATTR2_UNK9 = 0x00000200, // TITLE Unknown attribute 9@Attr2
|
||||
SPELL_ATTR2_UNK10 = 0x00000400, // TITLE Unknown attribute 10@Attr2 DESCRIPTION Related to taming?
|
||||
SPELL_ATTR2_HEALTH_FUNNEL = 0x00000800, // TITLE Health Funnel
|
||||
SPELL_ATTR2_UNK12 = 0x00001000, // TITLE Unknown attribute 12@Attr2
|
||||
SPELL_ATTR2_PRESERVE_ENCHANT_IN_ARENA = 0x00002000, // TITLE Enchant persists when entering arena
|
||||
SPELL_ATTR2_UNK14 = 0x00004000, // TITLE Unknown attribute 14@Attr2
|
||||
SPELL_ATTR2_UNK15 = 0x00008000, // TITLE Unknown attribute 15@Attr2
|
||||
SPELL_ATTR2_TAME_BEAST = 0x00010000, // TITLE Tame Beast
|
||||
SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS = 0x00020000, // TITLE Don't reset swing timer DESCRIPTION Does not reset melee/ranged autoattack timer on cast
|
||||
SPELL_ATTR2_REQ_DEAD_PET = 0x00040000, // TITLE Requires dead pet
|
||||
SPELL_ATTR2_NOT_NEED_SHAPESHIFT = 0x00080000, // TITLE Also allow outside shapeshift DESCRIPTION Even if Stances are nonzero, allow spell to be cast outside of shapeshift (though not in a different shapeshift)
|
||||
SPELL_ATTR2_UNK20 = 0x00100000, // TITLE Unknown attribute 20@Attr2
|
||||
SPELL_ATTR2_DAMAGE_REDUCED_SHIELD = 0x00200000, // TITLE Damage reduction ability DESCRIPTION Causes BG flags to be dropped if combined with ATTR1_DISPEL_AURAS_ON_IMMUNITY
|
||||
SPELL_ATTR2_UNK22 = 0x00400000, // TITLE Unknown attribute 22@Attr2
|
||||
SPELL_ATTR2_IS_ARCANE_CONCENTRATION = 0x00800000, // TITLE Arcane Concentration
|
||||
SPELL_ATTR2_UNK24 = 0x01000000, // TITLE Unknown attribute 24@Attr2
|
||||
SPELL_ATTR2_UNK25 = 0x02000000, // TITLE Unknown attribute 25@Attr2
|
||||
SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE = 0x04000000, // TITLE Pierce aura application immunities DESCRIPTION Allow aura to be applied despite target being immune to new aura applications
|
||||
SPELL_ATTR2_UNK27 = 0x08000000, // TITLE Unknown attribute 27@Attr2
|
||||
SPELL_ATTR2_IGNORE_ACTION_AURA_INTERRUPT_FLAGS= 0x10000000,// TITLE Not an Action
|
||||
SPELL_ATTR2_CANT_CRIT = 0x20000000, // TITLE Cannot critically strike
|
||||
SPELL_ATTR2_ACTIVE_THREAT = 0x40000000, // TITLE Active Threat
|
||||
SPELL_ATTR2_FOOD_BUFF = 0x80000000 // TITLE Food buff (client only)
|
||||
SPELL_ATTR2_ALLOW_DEAD_TARGET = 0x00000001, // TITLE Allow Dead Target
|
||||
SPELL_ATTR2_NO_SHAPESHIFT_UI = 0x00000002, // TITLE No shapeshift UI (client only) DESCRIPTION Does not replace action bar when shapeshifted
|
||||
SPELL_ATTR2_IGNORE_LINE_OF_SIGHT = 0x00000004, // TITLE Ignore Line of Sight
|
||||
SPELL_ATTR2_ALLOW_LOW_LEVEL_BUFF = 0x00000008, // TITLE Allow Low Level Buff
|
||||
SPELL_ATTR2_USE_SHAPESHIFT_BAR = 0x00000010, // TITLE Use Shapeshift Bar (client only)
|
||||
SPELL_ATTR2_AUTO_REPEAT = 0x00000020, // TITLE Auto Repeat
|
||||
SPELL_ATTR2_CANNOT_CAST_ON_TAPPED = 0x00000040, // TITLE Cannot cast on tapped DESCRIPTION Can only target untapped units, or those tapped by caster
|
||||
SPELL_ATTR2_DO_NOT_REPORT_SPELL_FAILURE = 0x00000080, // TITLE Do Not Report Spell Failure
|
||||
SPELL_ATTR2_INCLUDE_IN_ADVANCED_COMBAT_LOG = 0x00000100, // TITLE Include In Advanced Combat Log (client only) DESCRIPTION Determines whether to include this aura in list of auras in SMSG_ENCOUNTER_START
|
||||
SPELL_ATTR2_ALWAYS_CAST_AS_UNIT = 0x00000200, /*NYI, UNK*/ // TITLE Always Cast As Unit
|
||||
SPELL_ATTR2_SPECIAL_TAMING_FLAG = 0x00000400, // TITLE Special Taming Flag DESCRIPTION Related to taming?
|
||||
SPELL_ATTR2_NO_TARGET_PER_SECOND_COSTS = 0x00000800, // TITLE No Target Per-Second Costs
|
||||
SPELL_ATTR2_CHAIN_FROM_CASTER = 0x00001000, // TITLE Chain From Caster
|
||||
SPELL_ATTR2_ENCHANT_OWN_ITEM_ONLY = 0x00002000, // TITLE Enchant own item only
|
||||
SPELL_ATTR2_ALLOW_WHILE_INVISIBLE = 0x00004000, // TITLE Allow While Invisible
|
||||
SPELL_ATTR2_DO_NOT_CONSUME_IF_GAINED_DURING_CAST = 0x00008000, // TITLE Do Not Consume if Gained During Cast
|
||||
SPELL_ATTR2_NO_ACTIVE_PETS = 0x00010000, // TITLE No Active Pets
|
||||
SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS = 0x00020000, // TITLE Do Not Reset Combat Timers DESCRIPTION Does not reset melee/ranged autoattack timer on cast
|
||||
SPELL_ATTR2_NO_JUMP_WHILE_CAST_PENDING = 0x00040000, // TITLE No Jump While Cast Pending (client only)
|
||||
SPELL_ATTR2_ALLOW_WHILE_NOT_SHAPESHIFTED_CASTER_FORM = 0x00080000, // TITLE Allow While Not Shapeshifted (caster form) DESCRIPTION Even if Stances are nonzero, allow spell to be cast outside of shapeshift (though not in a different shapeshift)
|
||||
SPELL_ATTR2_INITIATE_COMBAT_POST_CAST_ENABLES_AUTO_ATTACK = 0x00100000, // TITLE Initiate Combat Post-Cast (Enables Auto-Attack)
|
||||
SPELL_ATTR2_FAIL_ON_ALL_TARGETS_IMMUNE = 0x00200000, // TITLE Fail on all targets immune DESCRIPTION Causes BG flags to be dropped if combined with ATTR1_DISPEL_AURAS_ON_IMMUNITY
|
||||
SPELL_ATTR2_NO_INITIAL_THREAT = 0x00400000, // TITLE No Initial Threat
|
||||
SPELL_ATTR2_PROC_COOLDOWN_ON_FAILURE = 0x00800000, // TITLE Proc Cooldown On Failure
|
||||
SPELL_ATTR2_ITEM_CAST_WITH_OWNER_SKILL = 0x01000000, // TITLE Item Cast With Owner Skill
|
||||
SPELL_ATTR2_DONT_BLOCK_MANA_REGEN = 0x02000000, // TITLE Don't Block Mana Regen
|
||||
SPELL_ATTR2_NO_SCHOOL_IMMUNITIES = 0x04000000, // TITLE No School Immunities DESCRIPTION Allow aura to be applied despite target being immune to new aura applications
|
||||
SPELL_ATTR2_IGNORE_WEAPONSKILL = 0x08000000, // TITLE Ignore Weaponskill
|
||||
SPELL_ATTR2_NOT_AN_ACTION = 0x10000000, // TITLE Not an Action
|
||||
SPELL_ATTR2_CANT_CRIT = 0x20000000, // TITLE Can't Crit
|
||||
SPELL_ATTR2_ACTIVE_THREAT = 0x40000000, // TITLE Active Threat
|
||||
SPELL_ATTR2_RETAIN_ITEM_CAST = 0x80000000 // TITLE Retain Item Cast DESCRIPTION passes m_CastItem to triggered spells
|
||||
};
|
||||
|
||||
// EnumUtils: DESCRIBE THIS
|
||||
|
||||
@@ -258,7 +258,7 @@ TC_API_EXPORT EnumText EnumUtils<SpellAttr0>::ToString(SpellAttr0 value)
|
||||
case SPELL_ATTR0_DO_NOT_LOG: return { "SPELL_ATTR0_DO_NOT_LOG", "Do Not Log (client only)", "Spell will not appear in combat logs" };
|
||||
case SPELL_ATTR0_HELD_ITEM_ONLY: return { "SPELL_ATTR0_HELD_ITEM_ONLY", "Held Item Only (client only)", "Client will automatically select main-hand item as cast target" };
|
||||
case SPELL_ATTR0_ON_NEXT_SWING: return { "SPELL_ATTR0_ON_NEXT_SWING", "On Next Swing", "Both \042on next swing\042 attributes have identical handling in server & client" };
|
||||
case SPELL_ATTR0_WEARER_CASTS_PROC_TRIGGER: return { "SPELL_ATTR0_WEARER_CASTS_PROC_TRIGGER", "Wearer Casts Proc Trigger", "" };
|
||||
case SPELL_ATTR0_WEARER_CASTS_PROC_TRIGGER: return { "SPELL_ATTR0_WEARER_CASTS_PROC_TRIGGER", "Wearer Casts Proc Trigger", "Just a marker attribute to show auras that trigger another spell (either directly or with a script)" };
|
||||
case SPELL_ATTR0_SERVER_ONLY: return { "SPELL_ATTR0_SERVER_ONLY", "Server Only", "" };
|
||||
case SPELL_ATTR0_ALLOW_ITEM_SPELL_IN_PVP: return { "SPELL_ATTR0_ALLOW_ITEM_SPELL_IN_PVP", "Allow Item Spell In PvP", "" };
|
||||
case SPELL_ATTR0_ONLY_INDOORS: return { "SPELL_ATTR0_ONLY_INDOORS", "Only Indoors", "" };
|
||||
@@ -505,38 +505,38 @@ TC_API_EXPORT EnumText EnumUtils<SpellAttr2>::ToString(SpellAttr2 value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case SPELL_ATTR2_CAN_TARGET_DEAD: return { "SPELL_ATTR2_CAN_TARGET_DEAD", "Can target dead players or corpses", "" };
|
||||
case SPELL_ATTR2_UNK1: return { "SPELL_ATTR2_UNK1", "Unknown attribute 1@Attr2", "" };
|
||||
case SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS: return { "SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS", "Ignore Line of Sight", "" };
|
||||
case SPELL_ATTR2_UNK3: return { "SPELL_ATTR2_UNK3", "Ignore aura scaling", "" };
|
||||
case SPELL_ATTR2_DISPLAY_IN_STANCE_BAR: return { "SPELL_ATTR2_DISPLAY_IN_STANCE_BAR", "Show in stance bar (client only)", "" };
|
||||
case SPELL_ATTR2_AUTOREPEAT_FLAG: return { "SPELL_ATTR2_AUTOREPEAT_FLAG", "Ranged auto-attack spell", "" };
|
||||
case SPELL_ATTR2_CANT_TARGET_TAPPED: return { "SPELL_ATTR2_CANT_TARGET_TAPPED", "Cannot target others' tapped units", "Can only target untapped units, or those tapped by caster" };
|
||||
case SPELL_ATTR2_UNK7: return { "SPELL_ATTR2_UNK7", "Unknown attribute 7@Attr2", "" };
|
||||
case SPELL_ATTR2_UNK8: return { "SPELL_ATTR2_UNK8", "Unknown attribute 8@Attr2", "" };
|
||||
case SPELL_ATTR2_UNK9: return { "SPELL_ATTR2_UNK9", "Unknown attribute 9@Attr2", "" };
|
||||
case SPELL_ATTR2_UNK10: return { "SPELL_ATTR2_UNK10", "Unknown attribute 10@Attr2", "Related to taming?" };
|
||||
case SPELL_ATTR2_HEALTH_FUNNEL: return { "SPELL_ATTR2_HEALTH_FUNNEL", "Health Funnel", "" };
|
||||
case SPELL_ATTR2_UNK12: return { "SPELL_ATTR2_UNK12", "Unknown attribute 12@Attr2", "" };
|
||||
case SPELL_ATTR2_PRESERVE_ENCHANT_IN_ARENA: return { "SPELL_ATTR2_PRESERVE_ENCHANT_IN_ARENA", "Enchant persists when entering arena", "" };
|
||||
case SPELL_ATTR2_UNK14: return { "SPELL_ATTR2_UNK14", "Unknown attribute 14@Attr2", "" };
|
||||
case SPELL_ATTR2_UNK15: return { "SPELL_ATTR2_UNK15", "Unknown attribute 15@Attr2", "" };
|
||||
case SPELL_ATTR2_TAME_BEAST: return { "SPELL_ATTR2_TAME_BEAST", "Tame Beast", "" };
|
||||
case SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS: return { "SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS", "Don't reset swing timer", "Does not reset melee/ranged autoattack timer on cast" };
|
||||
case SPELL_ATTR2_REQ_DEAD_PET: return { "SPELL_ATTR2_REQ_DEAD_PET", "Requires dead pet", "" };
|
||||
case SPELL_ATTR2_NOT_NEED_SHAPESHIFT: return { "SPELL_ATTR2_NOT_NEED_SHAPESHIFT", "Also allow outside shapeshift", "Even if Stances are nonzero, allow spell to be cast outside of shapeshift (though not in a different shapeshift)" };
|
||||
case SPELL_ATTR2_UNK20: return { "SPELL_ATTR2_UNK20", "Unknown attribute 20@Attr2", "" };
|
||||
case SPELL_ATTR2_DAMAGE_REDUCED_SHIELD: return { "SPELL_ATTR2_DAMAGE_REDUCED_SHIELD", "Damage reduction ability", "Causes BG flags to be dropped if combined with ATTR1_DISPEL_AURAS_ON_IMMUNITY" };
|
||||
case SPELL_ATTR2_UNK22: return { "SPELL_ATTR2_UNK22", "Unknown attribute 22@Attr2", "" };
|
||||
case SPELL_ATTR2_IS_ARCANE_CONCENTRATION: return { "SPELL_ATTR2_IS_ARCANE_CONCENTRATION", "Arcane Concentration", "" };
|
||||
case SPELL_ATTR2_UNK24: return { "SPELL_ATTR2_UNK24", "Unknown attribute 24@Attr2", "" };
|
||||
case SPELL_ATTR2_UNK25: return { "SPELL_ATTR2_UNK25", "Unknown attribute 25@Attr2", "" };
|
||||
case SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE: return { "SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE", "Pierce aura application immunities", "Allow aura to be applied despite target being immune to new aura applications" };
|
||||
case SPELL_ATTR2_UNK27: return { "SPELL_ATTR2_UNK27", "Unknown attribute 27@Attr2", "" };
|
||||
case SPELL_ATTR2_IGNORE_ACTION_AURA_INTERRUPT_FLAGS: return { "SPELL_ATTR2_IGNORE_ACTION_AURA_INTERRUPT_FLAGS", "Not an Action", "" };
|
||||
case SPELL_ATTR2_CANT_CRIT: return { "SPELL_ATTR2_CANT_CRIT", "Cannot critically strike", "" };
|
||||
case SPELL_ATTR2_ALLOW_DEAD_TARGET: return { "SPELL_ATTR2_ALLOW_DEAD_TARGET", "Allow Dead Target", "" };
|
||||
case SPELL_ATTR2_NO_SHAPESHIFT_UI: return { "SPELL_ATTR2_NO_SHAPESHIFT_UI", "No shapeshift UI (client only)", "Does not replace action bar when shapeshifted" };
|
||||
case SPELL_ATTR2_IGNORE_LINE_OF_SIGHT: return { "SPELL_ATTR2_IGNORE_LINE_OF_SIGHT", "Ignore Line of Sight", "" };
|
||||
case SPELL_ATTR2_ALLOW_LOW_LEVEL_BUFF: return { "SPELL_ATTR2_ALLOW_LOW_LEVEL_BUFF", "Allow Low Level Buff", "" };
|
||||
case SPELL_ATTR2_USE_SHAPESHIFT_BAR: return { "SPELL_ATTR2_USE_SHAPESHIFT_BAR", "Use Shapeshift Bar (client only)", "" };
|
||||
case SPELL_ATTR2_AUTO_REPEAT: return { "SPELL_ATTR2_AUTO_REPEAT", "Auto Repeat", "" };
|
||||
case SPELL_ATTR2_CANNOT_CAST_ON_TAPPED: return { "SPELL_ATTR2_CANNOT_CAST_ON_TAPPED", "Cannot cast on tapped", "Can only target untapped units, or those tapped by caster" };
|
||||
case SPELL_ATTR2_DO_NOT_REPORT_SPELL_FAILURE: return { "SPELL_ATTR2_DO_NOT_REPORT_SPELL_FAILURE", "Do Not Report Spell Failure", "" };
|
||||
case SPELL_ATTR2_INCLUDE_IN_ADVANCED_COMBAT_LOG: return { "SPELL_ATTR2_INCLUDE_IN_ADVANCED_COMBAT_LOG", "Include In Advanced Combat Log (client only)", "Determines whether to include this aura in list of auras in SMSG_ENCOUNTER_START" };
|
||||
case SPELL_ATTR2_ALWAYS_CAST_AS_UNIT: return { "SPELL_ATTR2_ALWAYS_CAST_AS_UNIT", "Always Cast As Unit", "" };
|
||||
case SPELL_ATTR2_SPECIAL_TAMING_FLAG: return { "SPELL_ATTR2_SPECIAL_TAMING_FLAG", "Special Taming Flag", "Related to taming?" };
|
||||
case SPELL_ATTR2_NO_TARGET_PER_SECOND_COSTS: return { "SPELL_ATTR2_NO_TARGET_PER_SECOND_COSTS", "No Target Per-Second Costs", "" };
|
||||
case SPELL_ATTR2_CHAIN_FROM_CASTER: return { "SPELL_ATTR2_CHAIN_FROM_CASTER", "Chain From Caster", "" };
|
||||
case SPELL_ATTR2_ENCHANT_OWN_ITEM_ONLY: return { "SPELL_ATTR2_ENCHANT_OWN_ITEM_ONLY", "Enchant own item only", "" };
|
||||
case SPELL_ATTR2_ALLOW_WHILE_INVISIBLE: return { "SPELL_ATTR2_ALLOW_WHILE_INVISIBLE", "Allow While Invisible", "" };
|
||||
case SPELL_ATTR2_DO_NOT_CONSUME_IF_GAINED_DURING_CAST: return { "SPELL_ATTR2_DO_NOT_CONSUME_IF_GAINED_DURING_CAST", "Do Not Consume if Gained During Cast", "" };
|
||||
case SPELL_ATTR2_NO_ACTIVE_PETS: return { "SPELL_ATTR2_NO_ACTIVE_PETS", "No Active Pets", "" };
|
||||
case SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS: return { "SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS", "Do Not Reset Combat Timers", "Does not reset melee/ranged autoattack timer on cast" };
|
||||
case SPELL_ATTR2_NO_JUMP_WHILE_CAST_PENDING: return { "SPELL_ATTR2_NO_JUMP_WHILE_CAST_PENDING", "No Jump While Cast Pending (client only)", "" };
|
||||
case SPELL_ATTR2_ALLOW_WHILE_NOT_SHAPESHIFTED_CASTER_FORM: return { "SPELL_ATTR2_ALLOW_WHILE_NOT_SHAPESHIFTED_CASTER_FORM", "Allow While Not Shapeshifted (caster form)", "Even if Stances are nonzero, allow spell to be cast outside of shapeshift (though not in a different shapeshift)" };
|
||||
case SPELL_ATTR2_INITIATE_COMBAT_POST_CAST_ENABLES_AUTO_ATTACK: return { "SPELL_ATTR2_INITIATE_COMBAT_POST_CAST_ENABLES_AUTO_ATTACK", "Initiate Combat Post-Cast (Enables Auto-Attack)", "" };
|
||||
case SPELL_ATTR2_FAIL_ON_ALL_TARGETS_IMMUNE: return { "SPELL_ATTR2_FAIL_ON_ALL_TARGETS_IMMUNE", "Fail on all targets immune", "Causes BG flags to be dropped if combined with ATTR1_DISPEL_AURAS_ON_IMMUNITY" };
|
||||
case SPELL_ATTR2_NO_INITIAL_THREAT: return { "SPELL_ATTR2_NO_INITIAL_THREAT", "No Initial Threat", "" };
|
||||
case SPELL_ATTR2_PROC_COOLDOWN_ON_FAILURE: return { "SPELL_ATTR2_PROC_COOLDOWN_ON_FAILURE", "Proc Cooldown On Failure", "" };
|
||||
case SPELL_ATTR2_ITEM_CAST_WITH_OWNER_SKILL: return { "SPELL_ATTR2_ITEM_CAST_WITH_OWNER_SKILL", "Item Cast With Owner Skill", "" };
|
||||
case SPELL_ATTR2_DONT_BLOCK_MANA_REGEN: return { "SPELL_ATTR2_DONT_BLOCK_MANA_REGEN", "Don't Block Mana Regen", "" };
|
||||
case SPELL_ATTR2_NO_SCHOOL_IMMUNITIES: return { "SPELL_ATTR2_NO_SCHOOL_IMMUNITIES", "No School Immunities", "Allow aura to be applied despite target being immune to new aura applications" };
|
||||
case SPELL_ATTR2_IGNORE_WEAPONSKILL: return { "SPELL_ATTR2_IGNORE_WEAPONSKILL", "Ignore Weaponskill", "" };
|
||||
case SPELL_ATTR2_NOT_AN_ACTION: return { "SPELL_ATTR2_NOT_AN_ACTION", "Not an Action", "" };
|
||||
case SPELL_ATTR2_CANT_CRIT: return { "SPELL_ATTR2_CANT_CRIT", "Can't Crit", "" };
|
||||
case SPELL_ATTR2_ACTIVE_THREAT: return { "SPELL_ATTR2_ACTIVE_THREAT", "Active Threat", "" };
|
||||
case SPELL_ATTR2_FOOD_BUFF: return { "SPELL_ATTR2_FOOD_BUFF", "Food buff (client only)", "" };
|
||||
case SPELL_ATTR2_RETAIN_ITEM_CAST: return { "SPELL_ATTR2_RETAIN_ITEM_CAST", "Retain Item Cast", "passes m_CastItem to triggered spells" };
|
||||
default: throw std::out_of_range("value");
|
||||
}
|
||||
}
|
||||
@@ -549,38 +549,38 @@ TC_API_EXPORT SpellAttr2 EnumUtils<SpellAttr2>::FromIndex(size_t index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return SPELL_ATTR2_CAN_TARGET_DEAD;
|
||||
case 1: return SPELL_ATTR2_UNK1;
|
||||
case 2: return SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS;
|
||||
case 3: return SPELL_ATTR2_UNK3;
|
||||
case 4: return SPELL_ATTR2_DISPLAY_IN_STANCE_BAR;
|
||||
case 5: return SPELL_ATTR2_AUTOREPEAT_FLAG;
|
||||
case 6: return SPELL_ATTR2_CANT_TARGET_TAPPED;
|
||||
case 7: return SPELL_ATTR2_UNK7;
|
||||
case 8: return SPELL_ATTR2_UNK8;
|
||||
case 9: return SPELL_ATTR2_UNK9;
|
||||
case 10: return SPELL_ATTR2_UNK10;
|
||||
case 11: return SPELL_ATTR2_HEALTH_FUNNEL;
|
||||
case 12: return SPELL_ATTR2_UNK12;
|
||||
case 13: return SPELL_ATTR2_PRESERVE_ENCHANT_IN_ARENA;
|
||||
case 14: return SPELL_ATTR2_UNK14;
|
||||
case 15: return SPELL_ATTR2_UNK15;
|
||||
case 16: return SPELL_ATTR2_TAME_BEAST;
|
||||
case 17: return SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS;
|
||||
case 18: return SPELL_ATTR2_REQ_DEAD_PET;
|
||||
case 19: return SPELL_ATTR2_NOT_NEED_SHAPESHIFT;
|
||||
case 20: return SPELL_ATTR2_UNK20;
|
||||
case 21: return SPELL_ATTR2_DAMAGE_REDUCED_SHIELD;
|
||||
case 22: return SPELL_ATTR2_UNK22;
|
||||
case 23: return SPELL_ATTR2_IS_ARCANE_CONCENTRATION;
|
||||
case 24: return SPELL_ATTR2_UNK24;
|
||||
case 25: return SPELL_ATTR2_UNK25;
|
||||
case 26: return SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE;
|
||||
case 27: return SPELL_ATTR2_UNK27;
|
||||
case 28: return SPELL_ATTR2_IGNORE_ACTION_AURA_INTERRUPT_FLAGS;
|
||||
case 0: return SPELL_ATTR2_ALLOW_DEAD_TARGET;
|
||||
case 1: return SPELL_ATTR2_NO_SHAPESHIFT_UI;
|
||||
case 2: return SPELL_ATTR2_IGNORE_LINE_OF_SIGHT;
|
||||
case 3: return SPELL_ATTR2_ALLOW_LOW_LEVEL_BUFF;
|
||||
case 4: return SPELL_ATTR2_USE_SHAPESHIFT_BAR;
|
||||
case 5: return SPELL_ATTR2_AUTO_REPEAT;
|
||||
case 6: return SPELL_ATTR2_CANNOT_CAST_ON_TAPPED;
|
||||
case 7: return SPELL_ATTR2_DO_NOT_REPORT_SPELL_FAILURE;
|
||||
case 8: return SPELL_ATTR2_INCLUDE_IN_ADVANCED_COMBAT_LOG;
|
||||
case 9: return SPELL_ATTR2_ALWAYS_CAST_AS_UNIT;
|
||||
case 10: return SPELL_ATTR2_SPECIAL_TAMING_FLAG;
|
||||
case 11: return SPELL_ATTR2_NO_TARGET_PER_SECOND_COSTS;
|
||||
case 12: return SPELL_ATTR2_CHAIN_FROM_CASTER;
|
||||
case 13: return SPELL_ATTR2_ENCHANT_OWN_ITEM_ONLY;
|
||||
case 14: return SPELL_ATTR2_ALLOW_WHILE_INVISIBLE;
|
||||
case 15: return SPELL_ATTR2_DO_NOT_CONSUME_IF_GAINED_DURING_CAST;
|
||||
case 16: return SPELL_ATTR2_NO_ACTIVE_PETS;
|
||||
case 17: return SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS;
|
||||
case 18: return SPELL_ATTR2_NO_JUMP_WHILE_CAST_PENDING;
|
||||
case 19: return SPELL_ATTR2_ALLOW_WHILE_NOT_SHAPESHIFTED_CASTER_FORM;
|
||||
case 20: return SPELL_ATTR2_INITIATE_COMBAT_POST_CAST_ENABLES_AUTO_ATTACK;
|
||||
case 21: return SPELL_ATTR2_FAIL_ON_ALL_TARGETS_IMMUNE;
|
||||
case 22: return SPELL_ATTR2_NO_INITIAL_THREAT;
|
||||
case 23: return SPELL_ATTR2_PROC_COOLDOWN_ON_FAILURE;
|
||||
case 24: return SPELL_ATTR2_ITEM_CAST_WITH_OWNER_SKILL;
|
||||
case 25: return SPELL_ATTR2_DONT_BLOCK_MANA_REGEN;
|
||||
case 26: return SPELL_ATTR2_NO_SCHOOL_IMMUNITIES;
|
||||
case 27: return SPELL_ATTR2_IGNORE_WEAPONSKILL;
|
||||
case 28: return SPELL_ATTR2_NOT_AN_ACTION;
|
||||
case 29: return SPELL_ATTR2_CANT_CRIT;
|
||||
case 30: return SPELL_ATTR2_ACTIVE_THREAT;
|
||||
case 31: return SPELL_ATTR2_FOOD_BUFF;
|
||||
case 31: return SPELL_ATTR2_RETAIN_ITEM_CAST;
|
||||
default: throw std::out_of_range("index");
|
||||
}
|
||||
}
|
||||
@@ -590,38 +590,38 @@ TC_API_EXPORT size_t EnumUtils<SpellAttr2>::ToIndex(SpellAttr2 value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case SPELL_ATTR2_CAN_TARGET_DEAD: return 0;
|
||||
case SPELL_ATTR2_UNK1: return 1;
|
||||
case SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS: return 2;
|
||||
case SPELL_ATTR2_UNK3: return 3;
|
||||
case SPELL_ATTR2_DISPLAY_IN_STANCE_BAR: return 4;
|
||||
case SPELL_ATTR2_AUTOREPEAT_FLAG: return 5;
|
||||
case SPELL_ATTR2_CANT_TARGET_TAPPED: return 6;
|
||||
case SPELL_ATTR2_UNK7: return 7;
|
||||
case SPELL_ATTR2_UNK8: return 8;
|
||||
case SPELL_ATTR2_UNK9: return 9;
|
||||
case SPELL_ATTR2_UNK10: return 10;
|
||||
case SPELL_ATTR2_HEALTH_FUNNEL: return 11;
|
||||
case SPELL_ATTR2_UNK12: return 12;
|
||||
case SPELL_ATTR2_PRESERVE_ENCHANT_IN_ARENA: return 13;
|
||||
case SPELL_ATTR2_UNK14: return 14;
|
||||
case SPELL_ATTR2_UNK15: return 15;
|
||||
case SPELL_ATTR2_TAME_BEAST: return 16;
|
||||
case SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS: return 17;
|
||||
case SPELL_ATTR2_REQ_DEAD_PET: return 18;
|
||||
case SPELL_ATTR2_NOT_NEED_SHAPESHIFT: return 19;
|
||||
case SPELL_ATTR2_UNK20: return 20;
|
||||
case SPELL_ATTR2_DAMAGE_REDUCED_SHIELD: return 21;
|
||||
case SPELL_ATTR2_UNK22: return 22;
|
||||
case SPELL_ATTR2_IS_ARCANE_CONCENTRATION: return 23;
|
||||
case SPELL_ATTR2_UNK24: return 24;
|
||||
case SPELL_ATTR2_UNK25: return 25;
|
||||
case SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE: return 26;
|
||||
case SPELL_ATTR2_UNK27: return 27;
|
||||
case SPELL_ATTR2_IGNORE_ACTION_AURA_INTERRUPT_FLAGS: return 28;
|
||||
case SPELL_ATTR2_ALLOW_DEAD_TARGET: return 0;
|
||||
case SPELL_ATTR2_NO_SHAPESHIFT_UI: return 1;
|
||||
case SPELL_ATTR2_IGNORE_LINE_OF_SIGHT: return 2;
|
||||
case SPELL_ATTR2_ALLOW_LOW_LEVEL_BUFF: return 3;
|
||||
case SPELL_ATTR2_USE_SHAPESHIFT_BAR: return 4;
|
||||
case SPELL_ATTR2_AUTO_REPEAT: return 5;
|
||||
case SPELL_ATTR2_CANNOT_CAST_ON_TAPPED: return 6;
|
||||
case SPELL_ATTR2_DO_NOT_REPORT_SPELL_FAILURE: return 7;
|
||||
case SPELL_ATTR2_INCLUDE_IN_ADVANCED_COMBAT_LOG: return 8;
|
||||
case SPELL_ATTR2_ALWAYS_CAST_AS_UNIT: return 9;
|
||||
case SPELL_ATTR2_SPECIAL_TAMING_FLAG: return 10;
|
||||
case SPELL_ATTR2_NO_TARGET_PER_SECOND_COSTS: return 11;
|
||||
case SPELL_ATTR2_CHAIN_FROM_CASTER: return 12;
|
||||
case SPELL_ATTR2_ENCHANT_OWN_ITEM_ONLY: return 13;
|
||||
case SPELL_ATTR2_ALLOW_WHILE_INVISIBLE: return 14;
|
||||
case SPELL_ATTR2_DO_NOT_CONSUME_IF_GAINED_DURING_CAST: return 15;
|
||||
case SPELL_ATTR2_NO_ACTIVE_PETS: return 16;
|
||||
case SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS: return 17;
|
||||
case SPELL_ATTR2_NO_JUMP_WHILE_CAST_PENDING: return 18;
|
||||
case SPELL_ATTR2_ALLOW_WHILE_NOT_SHAPESHIFTED_CASTER_FORM: return 19;
|
||||
case SPELL_ATTR2_INITIATE_COMBAT_POST_CAST_ENABLES_AUTO_ATTACK: return 20;
|
||||
case SPELL_ATTR2_FAIL_ON_ALL_TARGETS_IMMUNE: return 21;
|
||||
case SPELL_ATTR2_NO_INITIAL_THREAT: return 22;
|
||||
case SPELL_ATTR2_PROC_COOLDOWN_ON_FAILURE: return 23;
|
||||
case SPELL_ATTR2_ITEM_CAST_WITH_OWNER_SKILL: return 24;
|
||||
case SPELL_ATTR2_DONT_BLOCK_MANA_REGEN: return 25;
|
||||
case SPELL_ATTR2_NO_SCHOOL_IMMUNITIES: return 26;
|
||||
case SPELL_ATTR2_IGNORE_WEAPONSKILL: return 27;
|
||||
case SPELL_ATTR2_NOT_AN_ACTION: return 28;
|
||||
case SPELL_ATTR2_CANT_CRIT: return 29;
|
||||
case SPELL_ATTR2_ACTIVE_THREAT: return 30;
|
||||
case SPELL_ATTR2_FOOD_BUFF: return 31;
|
||||
case SPELL_ATTR2_RETAIN_ITEM_CAST: return 31;
|
||||
default: throw std::out_of_range("value");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1774,7 +1774,7 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
|
||||
}
|
||||
|
||||
if (!shapeInfo->GetFlags().HasFlag(SpellShapeshiftFormFlags::Stance))
|
||||
target->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Shapeshifting, GetId());
|
||||
target->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Shapeshifting, GetSpellInfo());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3218,7 +3218,7 @@ void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint
|
||||
|
||||
// remove all flag auras (they are positive, but they must be removed when you are immune)
|
||||
if (GetSpellInfo()->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT)
|
||||
&& GetSpellInfo()->HasAttribute(SPELL_ATTR2_DAMAGE_REDUCED_SHIELD))
|
||||
&& GetSpellInfo()->HasAttribute(SPELL_ATTR2_FAIL_ON_ALL_TARGETS_IMMUNE))
|
||||
target->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::StealthOrInvis);
|
||||
}
|
||||
|
||||
@@ -5499,10 +5499,6 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
|
||||
return;
|
||||
}
|
||||
|
||||
// heal for caster damage (must be alive)
|
||||
if (target != caster && GetSpellInfo()->HasAttribute(SPELL_ATTR2_HEALTH_FUNNEL) && (!caster || !caster->IsAlive()))
|
||||
return;
|
||||
|
||||
// don't regen when permanent aura target has full power
|
||||
if (GetBase()->IsPermanent() && target->IsFullHealth())
|
||||
return;
|
||||
|
||||
@@ -809,7 +809,7 @@ void Aura::Update(uint32 diff, Unit* caster)
|
||||
{
|
||||
if (m_timeCla > int32(diff))
|
||||
m_timeCla -= diff;
|
||||
else if (caster)
|
||||
else if (caster && (caster == GetOwner() || !GetSpellInfo()->HasAttribute(SPELL_ATTR2_NO_TARGET_PER_SECOND_COSTS)))
|
||||
{
|
||||
if (!m_periodicCosts.empty())
|
||||
{
|
||||
@@ -1114,7 +1114,7 @@ bool Aura::IsRemovedOnShapeLost(Unit* target) const
|
||||
{
|
||||
return GetCasterGUID() == target->GetGUID()
|
||||
&& m_spellInfo->Stances
|
||||
&& !m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_NEED_SHAPESHIFT)
|
||||
&& !m_spellInfo->HasAttribute(SPELL_ATTR2_ALLOW_WHILE_NOT_SHAPESHIFTED_CASTER_FORM)
|
||||
&& !m_spellInfo->HasAttribute(SPELL_ATTR0_NOT_SHAPESHIFTED);
|
||||
}
|
||||
|
||||
@@ -1711,9 +1711,15 @@ bool Aura::IsProcOnCooldown(TimePoint now) const
|
||||
return m_procCooldown > now;
|
||||
}
|
||||
|
||||
void Aura::AddProcCooldown(TimePoint cooldownEnd)
|
||||
void Aura::AddProcCooldown(SpellProcEntry const* procEntry, TimePoint now)
|
||||
{
|
||||
m_procCooldown = cooldownEnd;
|
||||
// cooldowns should be added to the whole aura (see 51698 area aura)
|
||||
int32 procCooldown = procEntry->Cooldown.count();
|
||||
if (Unit* caster = GetCaster())
|
||||
if (Player* modOwner = caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(GetSpellInfo(), SpellModOp::ProcCooldown, procCooldown);
|
||||
|
||||
m_procCooldown = now + Milliseconds(procCooldown);
|
||||
}
|
||||
|
||||
void Aura::ResetProcCooldown()
|
||||
@@ -1730,22 +1736,36 @@ void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInf
|
||||
SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetSpellInfo());
|
||||
ASSERT(procEntry);
|
||||
|
||||
PrepareProcChargeDrop(procEntry, eventInfo);
|
||||
|
||||
// cooldowns should be added to the whole aura (see 51698 area aura)
|
||||
AddProcCooldown(procEntry, now);
|
||||
|
||||
SetLastProcSuccessTime(now);
|
||||
}
|
||||
|
||||
void Aura::PrepareProcChargeDrop(SpellProcEntry const* procEntry, ProcEventInfo const& eventInfo)
|
||||
{
|
||||
// take one charge, aura expiration will be handled in Aura::TriggerProcOnEvent (if needed)
|
||||
if (!(procEntry->AttributesMask & PROC_ATTR_USE_STACKS_FOR_CHARGES) && IsUsingCharges() && (!eventInfo.GetSpellInfo() || !eventInfo.GetSpellInfo()->HasAttribute(SPELL_ATTR6_DO_NOT_CONSUME_RESOURCES)))
|
||||
{
|
||||
--m_procCharges;
|
||||
SetNeedClientUpdateForTargets();
|
||||
}
|
||||
}
|
||||
|
||||
// cooldowns should be added to the whole aura (see 51698 area aura)
|
||||
int32 procCooldown = procEntry->Cooldown.count();
|
||||
if (Unit* caster = GetCaster())
|
||||
if (Player* modOwner = caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(GetSpellInfo(), SpellModOp::ProcCooldown, procCooldown);
|
||||
|
||||
AddProcCooldown(now + Milliseconds(procCooldown));
|
||||
|
||||
SetLastProcSuccessTime(now);
|
||||
void Aura::ConsumeProcCharges(SpellProcEntry const* procEntry)
|
||||
{
|
||||
// Remove aura if we've used last charge to proc
|
||||
if (procEntry->AttributesMask & PROC_ATTR_USE_STACKS_FOR_CHARGES)
|
||||
{
|
||||
ModStackAmount(-1);
|
||||
}
|
||||
else if (IsUsingCharges())
|
||||
{
|
||||
if (!GetCharges())
|
||||
Remove();
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Aura::GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, TimePoint now) const
|
||||
@@ -1913,16 +1933,7 @@ void Aura::TriggerProcOnEvent(uint32 procEffectMask, AuraApplication* aurApp, Pr
|
||||
CallScriptAfterProcHandlers(aurApp, eventInfo);
|
||||
}
|
||||
|
||||
// Remove aura if we've used last charge to proc
|
||||
if (ASSERT_NOTNULL(sSpellMgr->GetSpellProcEntry(m_spellInfo))->AttributesMask & PROC_ATTR_USE_STACKS_FOR_CHARGES)
|
||||
{
|
||||
ModStackAmount(-1);
|
||||
}
|
||||
else if (IsUsingCharges())
|
||||
{
|
||||
if (!GetCharges())
|
||||
Remove();
|
||||
}
|
||||
ConsumeProcCharges(ASSERT_NOTNULL(sSpellMgr->GetSpellProcEntry(GetSpellInfo())));
|
||||
}
|
||||
|
||||
float Aura::CalcPPMProcChance(Unit* actor) const
|
||||
|
||||
@@ -247,11 +247,13 @@ class TC_GAME_API Aura
|
||||
bool CanStackWith(Aura const* existingAura) const;
|
||||
|
||||
bool IsProcOnCooldown(TimePoint now) const;
|
||||
void AddProcCooldown(TimePoint cooldownEnd);
|
||||
void AddProcCooldown(SpellProcEntry const* procEntry, TimePoint now);
|
||||
void ResetProcCooldown();
|
||||
bool IsUsingCharges() const { return m_isUsingCharges; }
|
||||
void SetUsingCharges(bool val) { m_isUsingCharges = val; }
|
||||
void PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo, TimePoint now);
|
||||
void PrepareProcChargeDrop(SpellProcEntry const* procEntry, ProcEventInfo const& eventInfo);
|
||||
void ConsumeProcCharges(SpellProcEntry const* procEntry);
|
||||
uint32 GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, TimePoint now) const;
|
||||
float CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const;
|
||||
void TriggerProcOnEvent(uint32 procEffectMask, AuraApplication* aurApp, ProcEventInfo& eventInfo);
|
||||
|
||||
@@ -540,6 +540,10 @@ m_spellValue(new SpellValue(m_spellInfo, caster)), _spellEvent(nullptr)
|
||||
|
||||
m_spellState = SPELL_STATE_NULL;
|
||||
_triggeredCastFlags = triggerFlags;
|
||||
|
||||
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))
|
||||
_triggeredCastFlags = TriggerCastFlags(uint32(_triggeredCastFlags) | TRIGGERED_IGNORE_CAST_IN_PROGRESS);
|
||||
|
||||
@@ -754,6 +758,41 @@ void Spell::SelectSpellTargets()
|
||||
if (m_targets.HasDst())
|
||||
AddDestTarget(*m_targets.GetDst(), spellEffectInfo.EffectIndex);
|
||||
|
||||
if (spellEffectInfo.TargetA.GetObjectType() == TARGET_OBJECT_TYPE_UNIT
|
||||
|| spellEffectInfo.TargetA.GetObjectType() == TARGET_OBJECT_TYPE_UNIT_AND_DEST
|
||||
|| spellEffectInfo.TargetB.GetObjectType() == TARGET_OBJECT_TYPE_UNIT
|
||||
|| spellEffectInfo.TargetB.GetObjectType() == TARGET_OBJECT_TYPE_UNIT_AND_DEST)
|
||||
{
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR1_REQUIRE_ALL_TARGETS))
|
||||
{
|
||||
bool noTargetFound = std::none_of(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [effectMask = 1u << spellEffectInfo.EffectIndex](TargetInfo const& target)
|
||||
{
|
||||
return target.EffectMask & effectMask;
|
||||
});
|
||||
|
||||
if (noTargetFound)
|
||||
{
|
||||
SendCastResult(m_spellInfo->Id == 51690 ? SPELL_FAILED_OUT_OF_RANGE : SPELL_FAILED_BAD_TARGETS);
|
||||
finish(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR2_FAIL_ON_ALL_TARGETS_IMMUNE))
|
||||
{
|
||||
bool anyNonImmuneTargetFound = std::any_of(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [effectMask = 1u << spellEffectInfo.EffectIndex](TargetInfo const& target)
|
||||
{
|
||||
return target.EffectMask & effectMask && target.MissCondition != SPELL_MISS_IMMUNE && target.MissCondition != SPELL_MISS_IMMUNE2;
|
||||
});
|
||||
|
||||
if (!anyNonImmuneTargetFound)
|
||||
{
|
||||
SendCastResult(SPELL_FAILED_IMMUNE);
|
||||
finish(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_spellInfo->IsChanneled())
|
||||
{
|
||||
// maybe do this for all spells?
|
||||
@@ -2048,8 +2087,9 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar
|
||||
if (isBouncingFar)
|
||||
searchRadius *= chainTargets;
|
||||
|
||||
WorldObject* chainSource = m_spellInfo->HasAttribute(SPELL_ATTR2_CHAIN_FROM_CASTER) ? m_caster : target;
|
||||
std::list<WorldObject*> tempTargets;
|
||||
SearchAreaTargets(tempTargets, searchRadius, target, m_caster, objectType, selectType, condList);
|
||||
SearchAreaTargets(tempTargets, searchRadius, chainSource, m_caster, objectType, selectType, condList);
|
||||
tempTargets.remove(target);
|
||||
|
||||
// remove targets which are always invalid for chain spells
|
||||
@@ -2077,7 +2117,7 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar
|
||||
if (Unit* unit = (*itr)->ToUnit())
|
||||
{
|
||||
uint32 deficit = unit->GetMaxHealth() - unit->GetHealth();
|
||||
if ((deficit > maxHPDeficit || foundItr == tempTargets.end()) && target->IsWithinDist(unit, jumpRadius) && target->IsWithinLOSInMap(unit, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
|
||||
if ((deficit > maxHPDeficit || foundItr == tempTargets.end()) && chainSource->IsWithinDist(unit, jumpRadius) && chainSource->IsWithinLOSInMap(unit, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
|
||||
{
|
||||
foundItr = itr;
|
||||
maxHPDeficit = deficit;
|
||||
@@ -2092,19 +2132,22 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar
|
||||
{
|
||||
if (foundItr == tempTargets.end())
|
||||
{
|
||||
if ((!isBouncingFar || target->IsWithinDist(*itr, jumpRadius)) && target->IsWithinLOSInMap(*itr, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
|
||||
if ((!isBouncingFar || chainSource->IsWithinDist(*itr, jumpRadius)) && chainSource->IsWithinLOSInMap(*itr, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
|
||||
foundItr = itr;
|
||||
}
|
||||
else if (target->GetDistanceOrder(*itr, *foundItr) && target->IsWithinLOSInMap(*itr, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
|
||||
else if (chainSource->GetDistanceOrder(*itr, *foundItr) && chainSource->IsWithinLOSInMap(*itr, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
|
||||
foundItr = itr;
|
||||
}
|
||||
}
|
||||
// not found any valid target - chain ends
|
||||
if (foundItr == tempTargets.end())
|
||||
break;
|
||||
target = *foundItr;
|
||||
|
||||
if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CHAIN_FROM_CASTER))
|
||||
chainSource = *foundItr;
|
||||
|
||||
targets.push_back(*foundItr);
|
||||
tempTargets.erase(foundItr);
|
||||
targets.push_back(target);
|
||||
--chainTargets;
|
||||
}
|
||||
}
|
||||
@@ -2139,7 +2182,7 @@ void Spell::prepareDataForTriggerSystem()
|
||||
break;
|
||||
case SPELL_DAMAGE_CLASS_RANGED:
|
||||
// Auto attack
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG))
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR2_AUTO_REPEAT))
|
||||
{
|
||||
m_procAttacker = PROC_FLAG_DEAL_RANGED_ATTACK;
|
||||
m_procVictim = PROC_FLAG_TAKE_RANGED_ATTACK;
|
||||
@@ -2153,7 +2196,7 @@ void Spell::prepareDataForTriggerSystem()
|
||||
default:
|
||||
if (m_spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON &&
|
||||
m_spellInfo->EquippedItemSubClassMask & (1 << ITEM_SUBCLASS_WEAPON_WAND)
|
||||
&& m_spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG)) // Wands auto attack
|
||||
&& m_spellInfo->HasAttribute(SPELL_ATTR2_AUTO_REPEAT)) // Wands auto attack
|
||||
{
|
||||
m_procAttacker = PROC_FLAG_DEAL_RANGED_ATTACK;
|
||||
m_procVictim = PROC_FLAG_TAKE_RANGED_ATTACK;
|
||||
@@ -3328,8 +3371,8 @@ SpellCastResult Spell::prepare(SpellCastTargets const& targets, AuraEffect const
|
||||
{
|
||||
// stealth must be removed at cast starting (at show channel bar)
|
||||
// skip triggered spell (item equip spell casting and other not explicit character casts/item uses)
|
||||
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_INTERRUPT_FLAGS) && m_spellInfo->IsBreakingStealth() && !m_spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_ACTION_AURA_INTERRUPT_FLAGS))
|
||||
unitCaster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Action);
|
||||
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_INTERRUPT_FLAGS) && !m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_AN_ACTION))
|
||||
unitCaster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Action, m_spellInfo);
|
||||
|
||||
// Do not register as current spell when requested to ignore cast in progress
|
||||
// We don't want to interrupt that other spell with cast time
|
||||
@@ -3707,8 +3750,8 @@ void Spell::_cast(bool skipCheck)
|
||||
if (!(hitMask & PROC_HIT_CRITICAL))
|
||||
hitMask |= PROC_HIT_NORMAL;
|
||||
|
||||
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_INTERRUPT_FLAGS) && !m_spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_ACTION_AURA_INTERRUPT_FLAGS))
|
||||
m_originalCaster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::ActionDelayed);
|
||||
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_INTERRUPT_FLAGS) && !m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_AN_ACTION))
|
||||
m_originalCaster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::ActionDelayed, m_spellInfo);
|
||||
|
||||
Unit::ProcSkillsAndAuras(m_originalCaster, nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr);
|
||||
|
||||
@@ -4137,7 +4180,7 @@ void Spell::finish(bool ok)
|
||||
|
||||
if (IsAutoActionResetSpell())
|
||||
{
|
||||
if (!m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS))
|
||||
if (!m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS))
|
||||
{
|
||||
unitCaster->resetAttackTimer(BASE_ATTACK);
|
||||
if (unitCaster->haveOffhandWeapon())
|
||||
@@ -5356,7 +5399,7 @@ SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR0_USES_RANGED_SLOT)
|
||||
|| m_spellInfo->IsNextMeleeSwingSpell()
|
||||
|| m_spellInfo->HasAttribute(SPELL_ATTR1_INITIATES_COMBAT_ENABLES_AUTO_ATTACK)
|
||||
|| m_spellInfo->HasAttribute(SPELL_ATTR2_UNK20)
|
||||
|| m_spellInfo->HasAttribute(SPELL_ATTR2_INITIATE_COMBAT_POST_CAST_ENABLES_AUTO_ATTACK)
|
||||
|| m_spellInfo->HasEffect(SPELL_EFFECT_ATTACK)
|
||||
|| m_spellInfo->HasEffect(SPELL_EFFECT_NORMALIZED_WEAPON_DMG)
|
||||
|| m_spellInfo->HasEffect(SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL)
|
||||
@@ -5570,7 +5613,7 @@ SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32
|
||||
if (DynamicObject* dynObj = m_caster->ToUnit()->GetDynObject(m_triggeredByAuraSpell->Id))
|
||||
losTarget = dynObj;
|
||||
|
||||
if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && !m_spellInfo->HasAttribute(SPELL_ATTR5_ALWAYS_AOE_LINE_OF_SIGHT) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, nullptr, SPELL_DISABLE_LOS) && !target->IsWithinLOSInMap(losTarget, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
|
||||
if (!m_spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_LINE_OF_SIGHT) && !m_spellInfo->HasAttribute(SPELL_ATTR5_ALWAYS_AOE_LINE_OF_SIGHT) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, nullptr, SPELL_DISABLE_LOS) && !target->IsWithinLOSInMap(losTarget, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
|
||||
return SPELL_FAILED_LINE_OF_SIGHT;
|
||||
}
|
||||
}
|
||||
@@ -5582,13 +5625,17 @@ SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32
|
||||
float x, y, z;
|
||||
m_targets.GetDstPos()->GetPosition(x, y, z);
|
||||
|
||||
if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && !m_spellInfo->HasAttribute(SPELL_ATTR5_ALWAYS_AOE_LINE_OF_SIGHT) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, nullptr, SPELL_DISABLE_LOS) && !m_caster->IsWithinLOS(x, y, z, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
|
||||
if (!m_spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_LINE_OF_SIGHT) && !m_spellInfo->HasAttribute(SPELL_ATTR5_ALWAYS_AOE_LINE_OF_SIGHT) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, nullptr, SPELL_DISABLE_LOS) && !m_caster->IsWithinLOS(x, y, z, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
|
||||
return SPELL_FAILED_LINE_OF_SIGHT;
|
||||
}
|
||||
|
||||
// check pet presence
|
||||
if (Unit* unitCaster = m_caster->ToUnit())
|
||||
{
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR2_NO_ACTIVE_PETS))
|
||||
if (!unitCaster->GetPetGUID().IsEmpty())
|
||||
return SPELL_FAILED_ALREADY_HAVE_PET;
|
||||
|
||||
for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
|
||||
{
|
||||
if (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_PET)
|
||||
@@ -6458,6 +6505,9 @@ SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32
|
||||
if (m_CastItem)
|
||||
return SPELL_FAILED_ITEM_ENCHANT_TRADE_WINDOW;
|
||||
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR2_ENCHANT_OWN_ITEM_ONLY))
|
||||
return SPELL_FAILED_ITEM_ENCHANT_TRADE_WINDOW;
|
||||
|
||||
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
||||
return SPELL_FAILED_NOT_TRADING;
|
||||
|
||||
@@ -7730,7 +7780,7 @@ bool Spell::CheckEffectTarget(Unit const* target, SpellEffectInfo const& spellEf
|
||||
}
|
||||
|
||||
// check for ignore LOS on the effect itself
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) || DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, nullptr, SPELL_DISABLE_LOS))
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_LINE_OF_SIGHT) || DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, nullptr, SPELL_DISABLE_LOS))
|
||||
return true;
|
||||
|
||||
// check if gameobject ignores LOS
|
||||
@@ -7739,7 +7789,7 @@ bool Spell::CheckEffectTarget(Unit const* target, SpellEffectInfo const& spellEf
|
||||
return true;
|
||||
|
||||
// if spell is triggered, need to check for LOS disable on the aura triggering it and inherit that behaviour
|
||||
if (IsTriggered() && m_triggeredByAuraSpell && (m_triggeredByAuraSpell->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) || DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_triggeredByAuraSpell->Id, nullptr, SPELL_DISABLE_LOS)))
|
||||
if (IsTriggered() && m_triggeredByAuraSpell && (m_triggeredByAuraSpell->HasAttribute(SPELL_ATTR2_IGNORE_LINE_OF_SIGHT) || DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_triggeredByAuraSpell->Id, nullptr, SPELL_DISABLE_LOS)))
|
||||
return true;
|
||||
|
||||
/// @todo shit below shouldn't be here, but it's temporary
|
||||
@@ -8925,6 +8975,7 @@ CastSpellTargetArg::CastSpellTargetArg(WorldObject* target)
|
||||
|
||||
CastSpellExtraArgs& CastSpellExtraArgs::SetTriggeringSpell(Spell const* triggeringSpell)
|
||||
{
|
||||
TriggeringSpell = triggeringSpell;
|
||||
if (triggeringSpell)
|
||||
{
|
||||
OriginalCastItemLevel = triggeringSpell->m_castItemLevel;
|
||||
|
||||
@@ -454,6 +454,7 @@ struct TC_GAME_API CastSpellExtraArgs
|
||||
|
||||
TriggerCastFlags TriggerFlags = TRIGGERED_NONE;
|
||||
Item* CastItem = nullptr;
|
||||
Spell const* TriggeringSpell = nullptr;
|
||||
AuraEffect const* TriggeringAura = nullptr;
|
||||
ObjectGuid OriginalCaster = ObjectGuid::Empty;
|
||||
Difficulty CastDifficulty = Difficulty(0);
|
||||
@@ -472,6 +473,12 @@ struct TC_GAME_API CastSpellExtraArgs
|
||||
|
||||
std::vector<std::pair<SpellValueMod, int32>> data;
|
||||
} SpellValueOverrides;
|
||||
|
||||
CastSpellExtraArgs(CastSpellExtraArgs const&) = delete;
|
||||
CastSpellExtraArgs(CastSpellExtraArgs&&) = delete;
|
||||
|
||||
CastSpellExtraArgs& operator=(CastSpellExtraArgs const&) = delete;
|
||||
CastSpellExtraArgs& operator=(CastSpellExtraArgs&&) = delete;
|
||||
};
|
||||
|
||||
struct SpellCastVisual
|
||||
|
||||
@@ -641,18 +641,24 @@ void Spell::EffectTriggerSpell()
|
||||
if (effectInfo->Effect == SPELL_EFFECT_TRIGGER_SPELL)
|
||||
delay = Milliseconds(effectInfo->MiscValue);
|
||||
|
||||
CastSpellExtraArgs args(TRIGGERED_FULL_MASK);
|
||||
args.SetOriginalCaster(m_originalCasterGUID);
|
||||
args.SetTriggeringSpell(this);
|
||||
// set basepoints for trigger with value effect
|
||||
if (effectInfo->Effect == SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE)
|
||||
for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
args.AddSpellMod(SpellValueMod(SPELLVALUE_BASE_POINT0 + i), damage);
|
||||
|
||||
m_caster->m_Events.AddEventAtOffset([caster = m_caster, targets, triggered_spell_id, args]() mutable
|
||||
m_caster->m_Events.AddEventAtOffset([caster = m_caster, targets, originalCaster = m_originalCasterGUID, castItemGuid = m_castItemGUID, originalCastId = m_castId,
|
||||
spellEffectInfo = effectInfo, value = damage, itemLevel = m_castItemLevel]() mutable
|
||||
{
|
||||
// original caster guid only for GO cast
|
||||
caster->CastSpell(std::move(targets), triggered_spell_id, args);
|
||||
CastSpellExtraArgs args(TRIGGERED_FULL_MASK);
|
||||
args.SetOriginalCaster(originalCaster);
|
||||
args.OriginalCastId = originalCastId;
|
||||
args.OriginalCastItemLevel = itemLevel;
|
||||
if (!castItemGuid.IsEmpty() && sSpellMgr->AssertSpellInfo(spellEffectInfo->TriggerSpell, caster->GetMap()->GetDifficultyID())->HasAttribute(SPELL_ATTR2_RETAIN_ITEM_CAST))
|
||||
if (Player const* triggeringAuraCaster = Object::ToPlayer(args.TriggeringAura->GetCaster()))
|
||||
args.CastItem = triggeringAuraCaster->GetItemByGuid(castItemGuid);
|
||||
|
||||
// set basepoints for trigger with value effect
|
||||
if (spellEffectInfo->Effect == SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE)
|
||||
for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
args.AddSpellMod(SpellValueMod(SPELLVALUE_BASE_POINT0 + i), value);
|
||||
|
||||
caster->CastSpell(std::move(targets), spellEffectInfo->TriggerSpell, args);
|
||||
}, delay);
|
||||
}
|
||||
|
||||
|
||||
@@ -1593,7 +1593,7 @@ bool SpellInfo::IsRequiringDeadTarget() const
|
||||
|
||||
bool SpellInfo::IsAllowingDeadTarget() const
|
||||
{
|
||||
if (HasAttribute(SPELL_ATTR2_CAN_TARGET_DEAD) || Targets & (TARGET_FLAG_CORPSE_ALLY | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_UNIT_DEAD))
|
||||
if (HasAttribute(SPELL_ATTR2_ALLOW_DEAD_TARGET) || Targets & (TARGET_FLAG_CORPSE_ALLY | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_UNIT_DEAD))
|
||||
return true;
|
||||
|
||||
for (SpellEffectInfo const& effect : GetEffects())
|
||||
@@ -1661,11 +1661,6 @@ bool SpellInfo::IsNextMeleeSwingSpell() const
|
||||
return HasAttribute(SpellAttr0(SPELL_ATTR0_ON_NEXT_SWING_NO_DAMAGE | SPELL_ATTR0_ON_NEXT_SWING));
|
||||
}
|
||||
|
||||
bool SpellInfo::IsBreakingStealth() const
|
||||
{
|
||||
return !HasAttribute(SPELL_ATTR1_ALLOW_WHILE_STEALTHED);
|
||||
}
|
||||
|
||||
bool SpellInfo::IsRangedWeaponSpell() const
|
||||
{
|
||||
return (SpellFamilyName == SPELLFAMILY_HUNTER && !(SpellFamilyFlags[1] & 0x10000000)) // for 53352, cannot find better way
|
||||
@@ -1675,12 +1670,12 @@ bool SpellInfo::IsRangedWeaponSpell() const
|
||||
|
||||
bool SpellInfo::IsAutoRepeatRangedSpell() const
|
||||
{
|
||||
return HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG);
|
||||
return HasAttribute(SPELL_ATTR2_AUTO_REPEAT);
|
||||
}
|
||||
|
||||
bool SpellInfo::HasInitialAggro() const
|
||||
{
|
||||
return !(HasAttribute(SPELL_ATTR1_NO_THREAT) || HasAttribute(SPELL_ATTR3_NO_INITIAL_AGGRO));
|
||||
return !(HasAttribute(SPELL_ATTR1_NO_THREAT) || HasAttribute(SPELL_ATTR2_NO_INITIAL_THREAT));
|
||||
}
|
||||
|
||||
bool SpellInfo::HasHitDelay() const
|
||||
@@ -1784,7 +1779,7 @@ bool SpellInfo::CanPierceImmuneAura(SpellInfo const* auraSpellInfo) const
|
||||
return true;
|
||||
|
||||
// these spells (Cyclone for example) can pierce all...
|
||||
if (HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) || HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
|
||||
if (HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) || HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
|
||||
{
|
||||
// ...but not these (Divine shield, Ice block, Cyclone and Banish for example)
|
||||
if (auraSpellInfo->Mechanic != MECHANIC_IMMUNE_SHIELD &&
|
||||
@@ -1812,7 +1807,7 @@ bool SpellInfo::CanDispelAura(SpellInfo const* auraSpellInfo) const
|
||||
|
||||
// These auras (Cyclone for example) are not dispelable
|
||||
if ((auraSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) && auraSpellInfo->Mechanic != MECHANIC_NONE)
|
||||
|| auraSpellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
|
||||
|| auraSpellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -1929,7 +1924,7 @@ SpellCastResult SpellInfo::CheckShapeshift(uint32 form) const
|
||||
else
|
||||
{
|
||||
// needs shapeshift
|
||||
if (!HasAttribute(SPELL_ATTR2_NOT_NEED_SHAPESHIFT) && Stances != 0)
|
||||
if (!HasAttribute(SPELL_ATTR2_ALLOW_WHILE_NOT_SHAPESHIFTED_CASTER_FORM) && Stances != 0)
|
||||
return SPELL_FAILED_ONLY_SHAPESHIFT;
|
||||
}
|
||||
|
||||
@@ -2138,7 +2133,7 @@ SpellCastResult SpellInfo::CheckTarget(WorldObject const* caster, WorldObject co
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
// Do not allow these spells to target creatures not tapped by us (Banish, Polymorph, many quest spells)
|
||||
if (HasAttribute(SPELL_ATTR2_CANT_TARGET_TAPPED))
|
||||
if (HasAttribute(SPELL_ATTR2_CANNOT_CAST_ON_TAPPED))
|
||||
if (Creature const* targetCreature = unitTarget->ToCreature())
|
||||
if (targetCreature->hasLootRecipient() && !targetCreature->isTappedBy(caster->ToPlayer()))
|
||||
return SPELL_FAILED_CANT_CAST_ON_TAPPED;
|
||||
@@ -3600,7 +3595,7 @@ bool SpellInfo::CanSpellProvideImmunityAgainstAura(SpellInfo const* auraSpellInf
|
||||
|
||||
ImmunityInfo const& immuneInfo = effectInfo.GetImmunityInfo();
|
||||
|
||||
if (!auraSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) && !auraSpellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
|
||||
if (!auraSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) && !auraSpellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
|
||||
{
|
||||
if (uint32 schoolImmunity = immuneInfo.SchoolImmuneMask)
|
||||
if ((auraSpellInfo->SchoolMask & schoolImmunity) != 0)
|
||||
@@ -3646,7 +3641,7 @@ bool SpellInfo::CanSpellProvideImmunityAgainstAura(SpellInfo const* auraSpellInf
|
||||
if (auraImmuneItr != immuneInfo.AuraTypeImmune.cend())
|
||||
isImmuneToAuraEffectApply = true;
|
||||
|
||||
if (!isImmuneToAuraEffectApply && !auraSpellInfo->IsPositiveEffect(auraSpellEffectInfo.EffectIndex) && !auraSpellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
|
||||
if (!isImmuneToAuraEffectApply && !auraSpellInfo->IsPositiveEffect(auraSpellEffectInfo.EffectIndex) && !auraSpellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
|
||||
{
|
||||
if (uint32 applyHarmfulAuraImmunityMask = immuneInfo.ApplyHarmfulAuraImmuneMask)
|
||||
if ((auraSpellInfo->GetSchoolMask() & applyHarmfulAuraImmunityMask) != 0)
|
||||
@@ -3692,7 +3687,7 @@ bool SpellInfo::SpellCancelsAuraEffect(AuraEffect const* aurEff) const
|
||||
break;
|
||||
case SPELL_AURA_SCHOOL_IMMUNITY:
|
||||
case SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL:
|
||||
if (aurEff->GetSpellInfo()->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE) || !(aurEff->GetSpellInfo()->SchoolMask & miscValue))
|
||||
if (aurEff->GetSpellInfo()->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES) || !(aurEff->GetSpellInfo()->SchoolMask & miscValue))
|
||||
continue;
|
||||
break;
|
||||
case SPELL_AURA_DISPEL_IMMUNITY:
|
||||
@@ -4268,7 +4263,7 @@ SpellInfo const* SpellInfo::GetAuraRankForLevel(uint8 level) const
|
||||
return this;
|
||||
|
||||
// Client ignores spell with these attributes (sub_53D9D0)
|
||||
if (HasAttribute(SPELL_ATTR0_AURA_IS_DEBUFF) || HasAttribute(SPELL_ATTR2_UNK3) || HasAttribute(SPELL_ATTR3_DRAIN_SOUL))
|
||||
if (HasAttribute(SPELL_ATTR0_AURA_IS_DEBUFF) || HasAttribute(SPELL_ATTR2_ALLOW_LOW_LEVEL_BUFF) || HasAttribute(SPELL_ATTR3_DRAIN_SOUL))
|
||||
return this;
|
||||
|
||||
bool needRankSelection = false;
|
||||
|
||||
@@ -515,7 +515,6 @@ class TC_GAME_API SpellInfo
|
||||
bool IsMoveAllowedChannel() const;
|
||||
bool NeedsComboPoints() const;
|
||||
bool IsNextMeleeSwingSpell() const;
|
||||
bool IsBreakingStealth() const;
|
||||
bool IsRangedWeaponSpell() const;
|
||||
bool IsAutoRepeatRangedSpell() const;
|
||||
bool HasInitialAggro() const;
|
||||
|
||||
@@ -4418,7 +4418,7 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
ApplySpellFix({ 75509 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->AttributesEx6 |= SPELL_ATTR6_CAN_TARGET_INVISIBLE;
|
||||
spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS;
|
||||
spellInfo->AttributesEx2 |= SPELL_ATTR2_IGNORE_LINE_OF_SIGHT;
|
||||
});
|
||||
|
||||
// Awaken Flames
|
||||
@@ -4442,7 +4442,7 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
{
|
||||
// All spells work even without these changes. The LOS attribute is due to problem
|
||||
// from collision between maps & gos with active destroyed state.
|
||||
spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS;
|
||||
spellInfo->AttributesEx2 |= SPELL_ATTR2_IGNORE_LINE_OF_SIGHT;
|
||||
});
|
||||
|
||||
// Arcane Barrage (cast by players and NONMELEEDAMAGELOG with caster Scion of Eternity (original caster)).
|
||||
@@ -4581,7 +4581,7 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
ApplySpellFix({ 42525 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->AttributesEx3 |= SPELL_ATTR3_DEATH_PERSISTENT;
|
||||
spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_DEAD;
|
||||
spellInfo->AttributesEx2 |= SPELL_ATTR2_ALLOW_DEAD_TARGET;
|
||||
});
|
||||
|
||||
// Soul Sickness (Forge of Souls)
|
||||
|
||||
@@ -1242,8 +1242,10 @@ class spell_sha_mastery_elemental_overload : public AuraScript
|
||||
caster->m_Events.AddEventAtOffset([caster,
|
||||
targets = CastSpellTargetArg(procInfo.GetProcTarget()),
|
||||
overloadSpellId = GetTriggeredSpellId(procInfo.GetSpellInfo()->Id),
|
||||
args = CastSpellExtraArgs(procInfo.GetProcSpell())]()
|
||||
originalCastId = procInfo.GetProcSpell()->m_castId]()
|
||||
{
|
||||
CastSpellExtraArgs args;
|
||||
args.OriginalCastId = originalCastId;
|
||||
caster->CastSpell(targets, overloadSpellId, args);
|
||||
}, 400ms);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user