refactor(Core/Spells): Implement QAston Proc System (#11079)

* .

* sql

* .

* .

* 1

* 2

* 3

* 4

* 5

* 6

* 7

* 8

* 9

* 10

* 11

* 12

* 13

* 14

* 15

* Update spell_item.cpp

* Update Unit.cpp

* 16

* 17

* 18

* 19

* 20

* 21

* Update Unit.cpp

* REVERT UltraNIX Commit

* 22

* 23

* .

* .

* .

* warrior

* warlock

* shaman rogue priest paladin mage

* spell item

* hunter

* druid

* dk

* war

* error style

* Update rev_1647677899565690722.sql

* Update rev_1647677899565690722.sql

* Update rev_1647677899565690722.sql

* .

* DOND DEL ME WAD DO DO

* error 2

* .

* .

* .

* FIX

* Update SpellInfoCorrections.cpp

* Update SpellInfoCorrections.cpp

* .

* ja genau

* Update .gitignore

* .

* .

* .,

* .

* .

* .

* .

* Update Unit.cpp
This commit is contained in:
IntelligentQuantum 2022-10-02 21:09:34 +03:30 committed by GitHub
parent 5189b43a28
commit cbd3fd0967
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
54 changed files with 9126 additions and 5957 deletions

1
.gitignore vendored
View file

@ -66,6 +66,7 @@ nbproject/
cmake-build-debug/*
cmake-build-debug-coverage/*
cmake-build-debug-event-trace/*
cmake-build-debug-visual-studio/*
coverage-report/
#

File diff suppressed because it is too large Load diff

View file

@ -46,7 +46,7 @@ float ThreatCalcHelper::calcThreat(Unit* hatedUnit, float threat, SpellSchoolMas
return threat;
if (Player* modOwner = hatedUnit->GetSpellModOwner())
modOwner->ApplySpellMod(threatSpell->Id, SPELLMOD_THREAT, threat);
modOwner->ApplySpellMod<SPELLMOD_THREAT>(threatSpell->Id, threat);
}
return hatedUnit->ApplyTotalThreatModifier(threat, schoolMask);

View file

@ -2751,8 +2751,8 @@ void Creature::AddSpellCooldown(uint32 spell_id, uint32 /*itemid*/, uint32 end_t
uint32 categorycooldown = categoryId ? spellInfo->CategoryRecoveryTime : 0;
if (Player* modOwner = GetSpellModOwner())
{
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, spellcooldown);
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, categorycooldown);
modOwner->ApplySpellMod<SPELLMOD_COOLDOWN>(spellInfo->Id, spellcooldown);
modOwner->ApplySpellMod<SPELLMOD_COOLDOWN>(spellInfo->Id, categorycooldown);
}
SpellCategoryStore::const_iterator i_scstore = sSpellsByCategoryStore.find(categoryId);

View file

@ -764,7 +764,7 @@ uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage)
case DAMAGE_LAVA:
case DAMAGE_SLIME:
{
DamageInfo dmgInfo(this, this, damage, nullptr, type == DAMAGE_LAVA ? SPELL_SCHOOL_MASK_FIRE : SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE);
DamageInfo dmgInfo(this, this, damage, nullptr, type == DAMAGE_LAVA ? SPELL_SCHOOL_MASK_FIRE : SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE, BASE_ATTACK);
Unit::CalcAbsorbResist(dmgInfo);
absorb = dmgInfo.GetAbsorb();
resist = dmgInfo.GetResist();
@ -7058,21 +7058,22 @@ void Player::ApplyEquipSpell(SpellInfo const* spellInfo, Item* item, bool apply,
}
}
void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx)
void Player::CastItemCombatSpell(DamageInfo const& damageInfo)
{
Unit* target = damageInfo.GetVictim();
if (!target || !target->IsAlive() || target == this)
return;
// Xinef: do not use disarmed weapons, special exception - shaman ghost wolf form
// Xinef: normal forms proc on hit enchants / built in item bonuses
if (!CanUseAttackType(attType) || GetShapeshiftForm() == FORM_GHOSTWOLF)
if (!CanUseAttackType(damageInfo.GetAttackType()) || GetShapeshiftForm() == FORM_GHOSTWOLF)
return;
for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)
{
// If usable, try to cast item spell
if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
if (!item->IsBroken())
if (!item->IsBroken() && CanUseAttackType(damageInfo.GetAttackType()))
if (ItemTemplate const* proto = item->GetTemplate())
{
// Additional check for weapons
@ -7080,7 +7081,7 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
{
// offhand item cannot proc from main hand hit etc
EquipmentSlots slot;
switch (attType)
switch (damageInfo.GetAttackType())
{
case BASE_ATTACK:
slot = EQUIPMENT_SLOT_MAINHAND;
@ -7099,19 +7100,20 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
continue;
}
CastItemCombatSpell(target, attType, procVictim, procEx, item, proto);
CastItemCombatSpell(damageInfo, item, proto);
}
}
}
void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item* item, ItemTemplate const* proto)
void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemTemplate const* proto)
{
if (!sScriptMgr->CanCastItemCombatSpell(this, target, attType, procVictim, procEx, item, proto))
return;
// if (!sScriptMgr->CanCastItemCombatSpell(this, target, attType, procVictim, procEx, item, proto))
// return;
// Can do effect if any damage done to target
if (procVictim & PROC_FLAG_TAKEN_DAMAGE)
//if (damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE)
// for done procs allow normal + critical + absorbs by default
bool canTrigger = (damageInfo.GetHitMask() & (PROC_HIT_NORMAL | PROC_HIT_CRITICAL | PROC_HIT_ABSORB)) != 0;
if (canTrigger)
{
for (uint8 i = 0; i < MAX_ITEM_SPELLS; ++i)
{
@ -7132,11 +7134,15 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
continue;
}
// not allow proc extra attack spell at extra attack
if (m_extraAttacks && spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS))
return;
float chance = (float)spellInfo->ProcChance;
if (spellData.SpellPPMRate)
{
uint32 WeaponSpeed = GetAttackTime(attType);
uint32 WeaponSpeed = GetAttackTime(damageInfo.GetAttackType());
chance = GetPPMProcChance(WeaponSpeed, spellData.SpellPPMRate, spellInfo);
}
else if (chance > 100.0f)
@ -7144,8 +7150,8 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
chance = GetWeaponProcChance();
}
if (roll_chance_f(chance) && sScriptMgr->OnCastItemCombatSpell(this, target, spellInfo, item))
CastSpell(target, spellInfo->Id, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD), item);
if (roll_chance_f(chance)/* && sScriptMgr->OnCastItemCombatSpell(this, target, spellInfo, item)*/)
CastSpell(damageInfo.GetVictim(), spellInfo->Id, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD), item);
}
}
@ -7167,14 +7173,14 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
if (entry && entry->procEx)
{
// Check hit/crit/dodge/parry requirement
if ((entry->procEx & procEx) == 0)
if ((entry->procEx & damageInfo.GetHitMask()) == 0)
continue;
}
else
{
// Can do effect if any damage done to target
if (!(procVictim & PROC_FLAG_TAKEN_DAMAGE))
//if (!(damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE))
// for done procs allow normal + critical + absorbs by default
if (!canTrigger)
continue;
}
@ -7197,7 +7203,7 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
}
// Apply spell mods
ApplySpellMod(pEnchant->spellid[s], SPELLMOD_CHANCE_OF_SUCCESS, chance);
ApplySpellMod<SPELLMOD_CHANCE_OF_SUCCESS>(pEnchant->spellid[s], chance);
// Shiv has 100% chance to apply the poison
if (FindCurrentSpellBySpellId(5938) && e_slot == TEMP_ENCHANTMENT_SLOT)
@ -7220,7 +7226,7 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
if (spellInfo->IsPositive())
CastSpell(this, spellInfo, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD), item);
else
CastSpell(target, spellInfo, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD), item);
CastSpell(damageInfo.GetVictim(), spellInfo, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD), item);
}
}
}
@ -9565,9 +9571,11 @@ bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod
if (!mod || !spellInfo)
return false;
// Mod out of charges
if (spell && mod->charges == -1 && spell->m_appliedMods.find(mod->ownerAura) == spell->m_appliedMods.end())
// First time this aura applies a mod to us and is out of charges
if (spell && mod->ownerAura->IsUsingCharges() && !mod->ownerAura->GetCharges() && !spell->m_appliedMods.count(mod->ownerAura))
{
return false;
}
// +duration to infinite duration spells making them limited
if (mod->op == SPELLMOD_DURATION && spellInfo->GetDuration() == -1)
@ -9609,50 +9617,46 @@ void Player::AddSpellMod(SpellModifier* mod, bool apply)
LOG_DEBUG("spells.aura", "Player::AddSpellMod {}", mod->spellId);
uint16 Opcode = (mod->type == SPELLMOD_FLAT) ? SMSG_SET_FLAT_SPELL_MODIFIER : SMSG_SET_PCT_SPELL_MODIFIER;
int i = 0;
flag96 _mask = 0;
for (int eff = 0; eff < 96; ++eff)
flag96 modMask;
for (uint8 i = 0; i < 3; ++i)
{
if (eff != 0 && eff % 32 == 0)
_mask[i++] = 0;
_mask[i] = uint32(1) << (eff - (32 * i));
if (mod->mask & _mask)
for (uint32 eff = 0; eff < 32; ++eff)
{
int32 val = 0;
for (SpellModList::iterator itr = m_spellMods[mod->op].begin(); itr != m_spellMods[mod->op].end(); ++itr)
modMask[i] = uint32(1) << eff;
if ((mod->mask & modMask))
{
if ((*itr)->type == mod->type && (*itr)->mask & _mask)
val += (*itr)->value;
int32 val = 0;
for (SpellModifier* spellMod : m_spellMods[mod->op])
{
if (spellMod->type == mod->type && (spellMod->mask & modMask))
{
val += spellMod->value;
}
}
val += apply ? mod->value : -(mod->value);
WorldPacket data(Opcode, (1 + 1 + 4));
data << uint8(eff + 32 * i);
data << uint8(mod->op);
data << int32(val);
SendDirectMessage(&data);
}
val += apply ? mod->value : -(mod->value);
WorldPacket data(Opcode, (1 + 1 + 4));
data << uint8(eff);
data << uint8(mod->op);
data << int32(val);
SendDirectMessage(&data);
}
modMask[i] = 0;
}
if (apply)
{
m_spellMods[mod->op].push_back(mod);
if (getClass() == CLASS_MAGE)
m_spellMods[mod->op].sort(MageSpellModPred());
else
m_spellMods[mod->op].sort(SpellModPred());
m_spellMods[mod->op].insert(mod);
}
else
{
m_spellMods[mod->op].remove(mod);
// mods bound to aura will be removed in AuraEffect::~AuraEffect
if (!mod->ownerAura)
delete mod;
m_spellMods[mod->op].erase(mod);
}
}
// Restore spellmods in case of failed cast
void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId, Aura* aura)
void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId /*= 0*/, Aura* aura /*= nullptr*/)
{
if (!spell || spell->m_appliedMods.empty())
return;
@ -9661,16 +9665,16 @@ void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId, Aura* aura)
for (uint8 i = 0; i < MAX_SPELLMOD; ++i)
{
for (SpellModList::iterator itr = m_spellMods[i].begin(); itr != m_spellMods[i].end(); ++itr)
for (auto itr = m_spellMods[i].begin(); itr != m_spellMods[i].end(); ++itr)
{
SpellModifier* mod = *itr;
// Spellmods without aura set cannot be charged
if (!mod->ownerAura || !mod->ownerAura->IsUsingCharges())
// Spellmods without charged aura set cannot be charged
if (!mod->ownerAura->IsUsingCharges())
continue;
// Restore only specific owner aura mods
if (ownerAuraId && (ownerAuraId != mod->ownerAura->GetSpellInfo()->Id))
if (ownerAuraId && mod->spellId != ownerAuraId)
continue;
if (aura && mod->ownerAura != aura)
@ -9691,27 +9695,14 @@ void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId, Aura* aura)
// only see the first of its modifier restored)
aurasQueue.push_back(mod->ownerAura);
// add mod charges back to mod
if (mod->charges == -1)
mod->charges = 1;
else
mod->charges++;
// Do not set more spellmods than available
if (mod->ownerAura->GetCharges() < mod->charges)
mod->charges = mod->ownerAura->GetCharges();
// Skip this check for now - aura charges may change due to various reason
/// @todo track these changes correctly
//ASSERT (mod->ownerAura->GetCharges() <= mod->charges);
// add charges back to aura
mod->ownerAura->ModCharges(1);
}
}
for (std::list<Aura*>::iterator itr = aurasQueue.begin(); itr != aurasQueue.end(); ++itr)
for (Aura* aura : aurasQueue)
{
Spell::UsedSpellMods::iterator iterMod = spell->m_appliedMods.find(*itr);
if (iterMod != spell->m_appliedMods.end())
spell->m_appliedMods.erase(iterMod);
spell->m_appliedMods.erase(aura);
}
// Xinef: clear the list just do be sure
@ -9719,77 +9710,32 @@ void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId, Aura* aura)
spell->m_appliedMods.clear();
}
void Player::RestoreAllSpellMods(uint32 ownerAuraId, Aura* aura)
void Player::RestoreAllSpellMods(uint32 ownerAuraId /*= 0*/, Aura* aura /*= nullptr*/)
{
for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i)
if (m_currentSpells[i])
RestoreSpellMods(m_currentSpells[i], ownerAuraId, aura);
if (Spell* spell = m_currentSpells[i])
RestoreSpellMods(spell, ownerAuraId, aura);
}
void Player::RemoveSpellMods(Spell* spell)
void Player::ApplyModToSpell(SpellModifier* mod, Spell* spell)
{
if (!spell)
return;
if (spell->m_appliedMods.empty())
// don't do anything with no charges
if (mod->ownerAura->IsUsingCharges() && !mod->ownerAura->GetCharges())
return;
SpellInfo const* const spellInfo = spell->m_spellInfo;
for (uint8 i = 0; i < MAX_SPELLMOD; ++i)
{
for (SpellModList::const_iterator itr = m_spellMods[i].begin(); itr != m_spellMods[i].end();)
{
SpellModifier* mod = *itr;
++itr;
// spellmods without aura set cannot be charged
if (!mod->ownerAura || !mod->ownerAura->IsUsingCharges())
continue;
// check if mod affected this spell
Spell::UsedSpellMods::iterator iterMod = spell->m_appliedMods.find(mod->ownerAura);
if (iterMod == spell->m_appliedMods.end())
continue;
// remove from list
// leave this here, if spell have two mods it will remove 2 charges - wrong
spell->m_appliedMods.erase(iterMod);
// MAGE T8P4 BONUS
if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE )
{
SpellInfo const* sp = mod->ownerAura->GetSpellInfo();
// Missile Barrage, Hot Streak, Brain Freeze (trigger spell - Fireball!)
if( sp->SpellIconID == 3261 || sp->SpellIconID == 2999 || sp->SpellIconID == 2938 )
if( AuraEffect* aurEff = GetAuraEffectDummy(64869) )
if( roll_chance_i(aurEff->GetAmount()) )
{
mod->charges = 1;
continue;
}
}
if (mod->ownerAura->DropCharge(AURA_REMOVE_BY_EXPIRE))
itr = m_spellMods[i].begin();
}
}
// register inside spell, proc system uses this to drop charges
spell->m_appliedMods.insert(mod->ownerAura);
}
void Player::DropModCharge(SpellModifier* mod, Spell* spell)
bool Player::HasSpellModApplied(SpellModifier* mod, Spell* spell)
{
// don't handle spells with proc_event entry defined
// this is a temporary workaround, because all spellmods should be handled like that
if (sSpellMgr->GetSpellProcEvent(mod->spellId))
return;
if (!spell)
return false;
if (spell && mod->ownerAura && mod->charges > 0)
{
if (--mod->charges == 0)
mod->charges = -1;
spell->m_appliedMods.insert(mod->ownerAura);
}
return spell->m_appliedMods.count(mod->ownerAura) != 0;
}
void Player::SetSpellModTakingSpell(Spell* spell, bool apply)
@ -10687,7 +10633,7 @@ void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 ite
if (rec > 0)
{
int32 oldRec = rec;
ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, rec, spell);
ApplySpellMod<SPELLMOD_COOLDOWN>(spellInfo->Id, rec, spell);
if (oldRec != rec)
{
useSpellCooldown = true;
@ -10696,7 +10642,7 @@ void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 ite
if (catrec > 0 && !spellInfo->HasAttribute(SPELL_ATTR6_NO_CATEGORY_COOLDOWN_MODS))
{
ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, catrec, spell);
ApplySpellMod<SPELLMOD_COOLDOWN>(spellInfo->Id, catrec, spell);
}
if (int32 cooldownMod = GetTotalAuraModifier(SPELL_AURA_MOD_COOLDOWN))
@ -11472,6 +11418,7 @@ void Player::ApplyEquipCooldown(Item* pItem)
if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_NO_EQUIP_COOLDOWN))
return;
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
_Spell const& spellData = pItem->GetTemplate()->Spells[i];
@ -11480,11 +11427,15 @@ void Player::ApplyEquipCooldown(Item* pItem)
if (!spellData.SpellId)
continue;
// xinef: apply hidden cooldown for procs
// apply proc cooldown to equip auras if we have any
if (spellData.SpellTrigger == ITEM_SPELLTRIGGER_ON_EQUIP)
{
// xinef: uint32(-1) special marker for proc cooldowns
AddSpellCooldown(spellData.SpellId, uint32(-1), 30 * IN_MILLISECONDS);
SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(spellData.SpellId);
if (!procEntry)
continue;
if (Aura* itemAura = GetAura(spellData.SpellId, GetGUID(), pItem->GetGUID()))
itemAura->AddProcCooldown(now + procEntry->Cooldown);
continue;
}

View file

@ -89,10 +89,10 @@ typedef void(*bgZoneRef)(Battleground*, WorldPacket&);
#define MAKE_SKILL_BONUS(t, p) MAKE_PAIR32(t, p)
// Note: SPELLMOD_* values is aura types in fact
enum SpellModType
enum SpellModType : uint8
{
SPELLMOD_FLAT = 107, // SPELL_AURA_ADD_FLAT_MODIFIER
SPELLMOD_PCT = 108 // SPELL_AURA_ADD_PCT_MODIFIER
SPELLMOD_FLAT = SPELL_AURA_ADD_FLAT_MODIFIER,
SPELLMOD_PCT = SPELL_AURA_ADD_PCT_MODIFIER
};
// 2^n values, Player::m_isunderwater is a bitmask. These are Trinity internal values, they are never send to any client
@ -180,10 +180,9 @@ enum TalentTree // talent tabs
// Spell modifier (used for modify other spells)
struct SpellModifier
{
SpellModifier(Aura* _ownerAura = nullptr) : op(SPELLMOD_DAMAGE), type(SPELLMOD_FLAT), charges(0), mask(), ownerAura(_ownerAura) {}
SpellModOp op : 8;
SpellModType type : 8;
int16 charges : 16;
SpellModifier(Aura* _ownerAura = nullptr) : op(SPELLMOD_DAMAGE), type(SPELLMOD_FLAT), mask(), ownerAura(_ownerAura) {}
SpellModOp op;
SpellModType type;
int32 value{0};
flag96 mask;
uint32 spellId{0};
@ -192,7 +191,7 @@ struct SpellModifier
typedef std::unordered_map<uint32, PlayerTalent*> PlayerTalentMap;
typedef std::unordered_map<uint32, PlayerSpell*> PlayerSpellMap;
typedef std::list<SpellModifier*> SpellModList;
typedef std::unordered_set<SpellModifier*> SpellModContainer;
typedef GuidList WhisperListContainer;
@ -1730,13 +1729,14 @@ public:
SpellCooldowns& GetSpellCooldownMap() { return m_spellCooldowns; }
void AddSpellMod(SpellModifier* mod, bool apply);
bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = nullptr);
static bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = nullptr);
bool HasSpellMod(SpellModifier* mod, Spell* spell);
template <class T> T ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell = nullptr, bool temporaryPet = false);
void RemoveSpellMods(Spell* spell);
template <SpellModOp op, class T>
void ApplySpellMod(uint32 spellId, T& basevalue, Spell* spell = nullptr) const;
void RestoreSpellMods(Spell* spell, uint32 ownerAuraId = 0, Aura* aura = nullptr);
void RestoreAllSpellMods(uint32 ownerAuraId = 0, Aura* aura = nullptr);
void DropModCharge(SpellModifier* mod, Spell* spell);
static void ApplyModToSpell(SpellModifier* mod, Spell* spell);
static bool HasSpellModApplied(SpellModifier* mod, Spell* spell);
void SetSpellModTakingSpell(Spell* spell, bool apply);
[[nodiscard]] bool HasSpellCooldown(uint32 spell_id) const override;
@ -2166,9 +2166,9 @@ public:
void ApplyItemEquipSpell(Item* item, bool apply, bool form_change = false);
void ApplyEquipSpell(SpellInfo const* spellInfo, Item* item, bool apply, bool form_change = false);
void UpdateEquipSpellsAtFormChange();
void CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx);
void CastItemCombatSpell(DamageInfo const& damageInfo);
void CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemTemplate const* proto);
void CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8 cast_count, uint32 glyphIndex);
void CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item* item, ItemTemplate const* proto);
void SendEquipmentSetList();
void SetEquipmentSet(uint32 index, EquipmentSet eqset);
@ -2551,7 +2551,7 @@ public:
// mt maps
[[nodiscard]] const PlayerTalentMap& GetTalentMap() const { return m_talents; }
[[nodiscard]] uint32 GetNextSave() const { return m_nextSave; }
[[nodiscard]] SpellModList const& GetSpellModList(uint32 type) const { return m_spellMods[type]; }
[[nodiscard]] SpellModContainer const& GetSpellModContainer(uint32 type) const { return m_spellMods[type]; }
void SetServerSideVisibility(ServerSideVisibilityType type, AccountTypes sec);
void SetServerSideVisibilityDetect(ServerSideVisibilityType type, AccountTypes sec);
@ -2756,7 +2756,7 @@ public:
uint32 m_baseHealthRegen;
int32 m_spellPenetrationItemMod;
SpellModList m_spellMods[MAX_SPELLMOD];
SpellModContainer m_spellMods[MAX_SPELLMOD];
//uint32 m_pad;
// Spell* m_spellModTakingSpell; // Spell for which charges are dropped in spell::finish
@ -2940,130 +2940,132 @@ void AddItemsSetItem(Player* player, Item* item);
void RemoveItemsSetItem(Player* player, ItemTemplate const* proto);
// "the bodies of template functions must be made available in a header file"
template <class T> T Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell, bool temporaryPet)
template <SpellModOp op, class T>
void Player::ApplySpellMod(uint32 spellId, T& basevalue, Spell* spell) const
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo)
{
return 0;
}
return;
float totalmul = 1.0f;
float totalmul = 1.f;
int32 totalflat = 0;
auto calculateSpellMod = [&](SpellModifier* mod)
{
// xinef: temporary pets cannot use charged mods of owner, needed for mirror image QQ they should use their own auras
if (temporaryPet && mod->charges != 0)
{
return;
}
if (mod->type == SPELLMOD_FLAT)
{
// xinef: do not allow to consume more than one 100% crit increasing spell
if (mod->op == SPELLMOD_CRITICAL_CHANCE && totalflat >= 100)
{
return;
}
int32 flatValue = mod->value;
// SPELL_MOD_THREAT - divide by 100 (in packets we send threat * 100)
if (mod->op == SPELLMOD_THREAT)
{
flatValue /= 100;
}
totalflat += flatValue;
}
else if (mod->type == SPELLMOD_PCT)
{
// skip percent mods for null basevalue (most important for spell mods with charges)
if (basevalue == T(0) || totalmul == 0.0f)
{
return;
}
// special case (skip > 10sec spell casts for instant cast setting)
if (mod->op == SPELLMOD_CASTING_TIME && basevalue >= T(10000) && mod->value <= -100)
{
return;
}
// xinef: special exception for surge of light, dont affect crit chance if previous mods were not applied
else if (mod->op == SPELLMOD_CRITICAL_CHANCE && spell && !HasSpellMod(mod, spell))
{
return;
}
// xinef: special case for backdraft gcd reduce with backlast time reduction, dont affect gcd if cast time was not applied
else if (mod->op == SPELLMOD_GLOBAL_COOLDOWN && spell && !HasSpellMod(mod, spell))
{
return;
}
// xinef: those two mods should be multiplicative (Glyph of Renew)
if (mod->op == SPELLMOD_DAMAGE || mod->op == SPELLMOD_DOT)
{
totalmul *= CalculatePct(1.0f, 100.0f + mod->value);
}
else
{
totalmul += CalculatePct(1.0f, mod->value);
}
}
DropModCharge(mod, spell);
};
// Drop charges for triggering spells instead of triggered ones
if (m_spellModTakingSpell)
{
spell = m_spellModTakingSpell;
}
SpellModifier* chargedMod = nullptr;
for (auto mod : m_spellMods[op])
switch (op)
{
// Charges can be set only for mods with auras
if (!mod->ownerAura)
// special case, if a mod makes spell instant, only consume that mod
case SPELLMOD_CASTING_TIME:
{
ASSERT(!mod->charges);
}
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
{
continue;
}
if (mod->ownerAura->IsUsingCharges())
{
if (!chargedMod || (chargedMod->ownerAura->GetSpellInfo()->SpellPriority < mod->ownerAura->GetSpellInfo()->SpellPriority))
SpellModifier* modInstantSpell = nullptr;
for (SpellModifier* mod : m_spellMods[SPELLMOD_CASTING_TIME])
{
chargedMod = mod;
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
{
continue;
}
if (mod->type == SPELLMOD_PCT && basevalue < T(10000) && mod->value <= -100)
{
modInstantSpell = mod;
break;
}
}
continue;
if (modInstantSpell)
{
Player::ApplyModToSpell(modInstantSpell, spell);
basevalue = T(0);
return;
}
break;
}
calculateSpellMod(mod);
// special case if two mods apply 100% critical chance, only consume one
case SPELLMOD_CRITICAL_CHANCE:
{
SpellModifier* modCritical = nullptr;
for (auto mod : m_spellMods[SPELLMOD_CRITICAL_CHANCE])
{
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
{
continue;
}
if (mod->type == SPELLMOD_FLAT && mod->value >= 100)
{
modCritical = mod;
break;
}
}
if (modCritical)
{
Player::ApplyModToSpell(modCritical, spell);
basevalue = T(100);
return;
}
break;
}
default:
break;
}
if (chargedMod)
for (auto mod : m_spellMods[op])
{
calculateSpellMod(chargedMod);
}
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
continue;
switch (mod->type)
{
case SPELLMOD_FLAT:
totalflat += mod->value;
break;
case SPELLMOD_PCT:
{
// skip percent mods for null basevalue (most important for spell mods with charges)
if (basevalue == T(0))
{
continue;
}
// special case (skip > 10s spell casts for instant cast setting)
if (op == SPELLMOD_CASTING_TIME)
{
if (mod->value <= -100 && basevalue >= T(10000))
{
continue;
}
}
totalmul += CalculatePct(1.f, mod->value);
break;
}
}
/*// xinef: special exception for surge of light, dont affect crit chance if previous mods were not applied
else if (mod->op == SPELLMOD_CRITICAL_CHANCE && spell && !HasSpellMod(mod, spell))
continue;
// xinef: special case for backdraft gcd reduce with backlast time reduction, dont affect gcd if cast time was not applied
else if (mod->op == SPELLMOD_GLOBAL_COOLDOWN && spell && !HasSpellMod(mod, spell))
continue;
// xinef: those two mods should be multiplicative (Glyph of Renew)
if (mod->op == SPELLMOD_DAMAGE || mod->op == SPELLMOD_DOT)
totalmul *= CalculatePct(1.0f, 100.0f + mod->value);
else
totalmul += CalculatePct(1.0f, mod->value);*/
Player::ApplyModToSpell(mod, spell);
}
float diff = 0.0f;
if (op == SPELLMOD_CASTING_TIME || op == SPELLMOD_DURATION)
{
diff = ((float)basevalue + totalflat) * (totalmul - 1.0f) + (float)totalflat;
}
else
{
diff = (float)basevalue * (totalmul - 1.0f) + (float)totalflat;
}
basevalue = T((float)basevalue + diff);
return T(diff);
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -702,13 +702,13 @@ struct DiminishingReturn
: DRGroup(group), stack(0), hitTime(t), hitCount(count)
{}
DiminishingGroup DRGroup: 16;
uint16 stack: 16;
DiminishingGroup DRGroup;
uint16 stack;
uint32 hitTime;
uint32 hitCount;
};
enum MeleeHitOutcome
enum MeleeHitOutcome : uint8
{
MELEE_HIT_EVADE, MELEE_HIT_MISS, MELEE_HIT_DODGE, MELEE_HIT_BLOCK, MELEE_HIT_PARRY,
MELEE_HIT_GLANCING, MELEE_HIT_CRIT, MELEE_HIT_CRUSHING, MELEE_HIT_NORMAL
@ -761,11 +761,12 @@ private:
uint32 m_absorb;
uint32 m_resist;
uint32 m_block;
uint32 m_hitMask;
uint32 m_cleanDamage;
public:
explicit DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellInfo const* _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType, uint32 cleanDamage = 0);
DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType, uint32 cleanDamage = 0);
explicit DamageInfo(CalcDamageInfo& dmgInfo);
DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType);
DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType, uint32 hitMask);
void ModifyDamage(int32 amount);
void AbsorbDamage(uint32 amount);
@ -784,6 +785,7 @@ public:
[[nodiscard]] uint32 GetBlock() const { return m_block; };
[[nodiscard]] uint32 GetUnmitigatedDamage() const;
[[nodiscard]] uint32 GetHitMask() const;
};
class HealInfo
@ -792,33 +794,33 @@ private:
Unit* const m_healer;
Unit* const m_target;
uint32 m_heal;
uint32 m_effectiveHeal;
uint32 m_absorb;
SpellInfo const* const m_spellInfo;
SpellSchoolMask const m_schoolMask;
uint32 m_hitMask;
public:
explicit HealInfo(Unit* _healer, Unit* _target, uint32 _heal, SpellInfo const* _spellInfo, SpellSchoolMask _schoolMask)
: m_healer(_healer), m_target(_target), m_heal(_heal), m_spellInfo(_spellInfo), m_schoolMask(_schoolMask)
{
m_absorb = 0;
}
void AbsorbHeal(uint32 amount)
{
amount = std::min(amount, GetHeal());
m_absorb += amount;
m_heal -= amount;
}
explicit HealInfo(Unit* healer, Unit* target, uint32 heal, SpellInfo const* spellInfo, SpellSchoolMask schoolMask);
void AbsorbHeal(uint32 amount);
void SetHeal(uint32 amount)
{
m_heal = amount;
}
void SetEffectiveHeal(uint32 amount)
{
m_effectiveHeal = amount;
}
[[nodiscard]] Unit* GetHealer() const { return m_healer; }
[[nodiscard]] Unit* GetTarget() const { return m_target; }
[[nodiscard]] uint32 GetHeal() const { return m_heal; }
[[nodiscard]] uint32 GetEffectiveHeal() const { return m_effectiveHeal; }
[[nodiscard]] uint32 GetAbsorb() const { return m_absorb; }
[[nodiscard]] SpellInfo const* GetSpellInfo() const { return m_spellInfo; };
[[nodiscard]] SpellSchoolMask GetSchoolMask() const { return m_schoolMask; };
[[nodiscard]] uint32 GetHitMask() const;
};
class ProcEventInfo
@ -923,7 +925,7 @@ struct SpellPeriodicAuraLogInfo
};
void createProcFlags(SpellInfo const* spellInfo, WeaponAttackType attackType, bool positive, uint32& procAttacker, uint32& procVictim);
uint32 createProcExtendMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition);
uint32 createProcHitMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition);
struct RedirectThreatInfo
{
@ -1288,6 +1290,7 @@ public:
typedef std::list<Aura*> AuraList;
typedef std::list<AuraApplication*> AuraApplicationList;
typedef std::list<DiminishingReturn> Diminishing;
typedef std::vector<std::pair<uint8 /*procEffectMask*/, AuraApplication*>> AuraApplicationProcContainer;
typedef GuidUnorderedSet ComboPointHolderSet;
typedef std::map<uint8, AuraApplication*> VisibleAuraMap;
@ -1439,10 +1442,10 @@ public:
void setPowerType(Powers power);
[[nodiscard]] uint32 GetPower(Powers power) const { return GetUInt32Value(static_cast<uint16>(UNIT_FIELD_POWER1) + power); }
[[nodiscard]] uint32 GetMaxPower(Powers power) const { return GetUInt32Value(static_cast<uint16>(UNIT_FIELD_MAXPOWER1) + power); }
void SetPower(Powers power, uint32 val, bool withPowerUpdate = true);
void SetPower(Powers power, uint32 val);
void SetMaxPower(Powers power, uint32 val);
// returns the change in power
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate = true);
int32 ModifyPower(Powers power, int32 val);
int32 ModifyPowerPct(Powers power, float pct, bool apply = true);
[[nodiscard]] uint32 GetAttackTime(WeaponAttackType att) const
@ -1526,16 +1529,15 @@ public:
uint16 GetMaxSkillValueForLevel(Unit const* target = nullptr) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; }
static void DealDamageMods(Unit const* victim, uint32& damage, uint32* absorb);
static uint32 DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage = nullptr, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* spellProto = nullptr, bool durabilityLoss = true, bool allowGM = false, Spell const* spell = nullptr);
static void Kill(Unit* killer, Unit* victim, bool durabilityLoss = true, WeaponAttackType attackType = BASE_ATTACK, SpellInfo const* spellProto = nullptr, Spell const* spell = nullptr);
static int32 DealHeal(Unit* healer, Unit* victim, uint32 addhealth);
static void Kill(Unit* killer, Unit* victim, bool durabilityLoss = true, WeaponAttackType attackType = BASE_ATTACK, SpellInfo const* spellProto = nullptr);
static void DealHeal(HealInfo& healInfo);
static void ProcDamageAndSpell(Unit* actor, Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellInfo const* procSpellInfo = nullptr, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr, uint32 procPhase = 2 /*PROC_SPELL_PHASE_HIT*/);
void ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpellInfo, uint32 damage, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr, uint32 procPhase = 2 /*PROC_SPELL_PHASE_HIT*/);
void ProcSkillsAndAuras(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo);
void GetProcAurasTriggeredOnEvent(std::list<AuraApplication*>& aurasTriggeringProc, std::list<AuraApplication*>* procAuras, ProcEventInfo eventInfo);
void GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer& aurasTriggeringProc, AuraApplicationList* procAuras, ProcEventInfo& eventInfo);
void TriggerAurasProcOnEvent(CalcDamageInfo& damageInfo);
void TriggerAurasProcOnEvent(std::list<AuraApplication*>* myProcAuras, std::list<AuraApplication*>* targetProcAuras, Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo);
void TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, std::list<AuraApplication*>& procAuras);
void TriggerAurasProcOnEvent(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo);
void TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationProcContainer& procAuras);
void HandleEmoteCommand(uint32 emoteId);
void AttackerStateUpdate (Unit* victim, WeaponAttackType attType = BASE_ATTACK, bool extra = false, bool ignoreCasting = false);
@ -1543,12 +1545,7 @@ public:
void CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK, const bool sittingVictim = false);
void DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss);
void HandleProcExtraAttackFor(Unit* victim, uint32 count);
void SetLastExtraAttackSpell(uint32 spellId) { _lastExtraAttackSpell = spellId; }
[[nodiscard]] uint32 GetLastExtraAttackSpell() const { return _lastExtraAttackSpell; }
void AddExtraAttacks(uint32 count);
void SetLastDamagedTargetGuid(ObjectGuid const& guid) { _lastDamagedTargetGuid = guid; }
[[nodiscard]] ObjectGuid const& GetLastDamagedTargetGuid() const { return _lastDamagedTargetGuid; }
void HandleProcExtraAttackFor(Unit* victim);
void CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = BASE_ATTACK, bool crit = false);
void DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss, Spell const* spell = nullptr);
@ -1700,7 +1697,7 @@ public:
[[nodiscard]] virtual bool IsUnderWater() const;
bool isInAccessiblePlaceFor(Creature const* c) const;
void SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical = false);
void SendHealSpellLog(HealInfo& healInfo, bool critical = false);
int32 HealBySpell(HealInfo& healInfo, bool critical = false);
void SendEnergizeSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, Powers powertype);
void EnergizeBySpell(Unit* victim, uint32 SpellID, uint32 Damage, Powers powertype);
@ -2515,14 +2512,6 @@ protected:
bool _instantCast;
private:
bool IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent, ProcEventInfo const& eventInfo);
bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, Spell const* spellProc = nullptr);
bool HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, bool* handled);
bool HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, uint32 procPhase, ProcEventInfo& eventInfo);
bool HandleOverrideClassScriptAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 cooldown);
bool HandleAuraRaidProcFromChargeWithValue(AuraEffect* triggeredByAura);
bool HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura);
void UpdateSplineMovement(uint32 t_diff);
void UpdateSplinePosition();
@ -2530,6 +2519,8 @@ private:
[[nodiscard]] float GetCombatRatingReduction(CombatRating cr) const;
[[nodiscard]] uint32 GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const;
void ProcSkillsAndReactives(bool isVictim, Unit* procTarget, uint32 typeMask, uint32 hitMask, WeaponAttackType attType);
protected:
void SetFeared(bool apply);
void SetConfused(bool apply);
@ -2563,10 +2554,6 @@ private:
bool _isWalkingBeforeCharm; ///< Are we walking before we were charmed?
[[nodiscard]] float processDummyAuras(float TakenTotalMod) const;
uint32 _lastExtraAttackSpell;
std::unordered_map<ObjectGuid /*guid*/, uint32 /*count*/> extraAttacksTargets;
ObjectGuid _lastDamagedTargetGuid;
};
namespace Acore

View file

@ -1186,7 +1186,7 @@ void WorldSession::HandlePlayerLoginToCharInWorld(Player* pCurrChar)
{
int32 i = 0;
flag96 _mask = 0;
SpellModList const& spellMods = pCurrChar->GetSpellModList(opType);
SpellModContainer const& spellMods = pCurrChar->GetSpellModContainer(opType);
if (spellMods.empty())
continue;

View file

@ -103,8 +103,8 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS] =
&AuraEffect::HandleAuraModSchoolImmunity, // 39 SPELL_AURA_SCHOOL_IMMUNITY
&AuraEffect::HandleAuraModDmgImmunity, // 40 SPELL_AURA_DAMAGE_IMMUNITY
&AuraEffect::HandleAuraModDispelImmunity, // 41 SPELL_AURA_DISPEL_IMMUNITY
&AuraEffect::HandleNoImmediateEffect, // 42 SPELL_AURA_PROC_TRIGGER_SPELL implemented in Unit::ProcDamageAndSpellFor and Unit::HandleProcTriggerSpell
&AuraEffect::HandleNoImmediateEffect, // 43 SPELL_AURA_PROC_TRIGGER_DAMAGE implemented in Unit::ProcDamageAndSpellFor
&AuraEffect::HandleNoImmediateEffect, // 42 SPELL_AURA_PROC_TRIGGER_SPELL implemented in AuraEffect::HandleProc
&AuraEffect::HandleNoImmediateEffect, // 43 SPELL_AURA_PROC_TRIGGER_DAMAGE implemented in AuraEffect::HandleProc
&AuraEffect::HandleAuraTrackCreatures, // 44 SPELL_AURA_TRACK_CREATURES
&AuraEffect::HandleAuraTrackResources, // 45 SPELL_AURA_TRACK_RESOURCES
&AuraEffect::HandleNULL, // 46 SPELL_AURA_46 (used in test spells 54054 and 54058, and spell 48050) (3.0.8a)
@ -323,7 +323,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS] =
&AuraEffect::HandleNoImmediateEffect, //259 SPELL_AURA_MOD_HOT_PCT implemented in Unit::SpellHealingBonus
&AuraEffect::HandleNoImmediateEffect, //260 SPELL_AURA_SCREEN_EFFECT (miscvalue = id in ScreenEffect.dbc) not required any code
&AuraEffect::HandlePhase, //261 SPELL_AURA_PHASE
&AuraEffect::HandleNoImmediateEffect, //262 SPELL_AURA_ABILITY_IGNORE_AURASTATE implemented in spell::cancast
&AuraEffect::HandleNoImmediateEffect, //262 SPELL_AURA_ABILITY_IGNORE_AURASTATE implemented in Spell::CheckCast
&AuraEffect::HandleAuraAllowOnlyAbility, //263 SPELL_AURA_ALLOW_ONLY_ABILITY player can use only abilities set in SpellClassMask
&AuraEffect::HandleUnused, //264 unused (3.2.0)
&AuraEffect::HandleUnused, //265 unused (3.2.0)
@ -631,7 +631,7 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool create, bool load)
{
// Apply periodic time mod
if (modOwner)
modOwner->ApplySpellMod(GetId(), SPELLMOD_ACTIVATION_TIME, m_amplitude);
modOwner->ApplySpellMod<SPELLMOD_ACTIVATION_TIME>(GetId(), m_amplitude);
if (caster)
{
@ -689,7 +689,6 @@ void AuraEffect::CalculateSpellMod()
m_spellmod->type = SpellModType(GetAuraType()); // SpellModType value == spell aura types
m_spellmod->spellId = GetId();
m_spellmod->mask = GetSpellInfo()->Effects[GetEffIndex()].SpellClassMask;
m_spellmod->charges = GetBase()->GetCharges();
}
m_spellmod->value = GetAmount();
break;
@ -1072,14 +1071,11 @@ bool AuraEffect::IsAffectedOnSpell(SpellInfo const* spell) const
{
if (!spell)
return false;
// Check family name
if (spell->SpellFamilyName != m_spellInfo->SpellFamilyName)
// Check family name and EffectClassMask
if (!spell->IsAffected(m_spellInfo->SpellFamilyName, m_spellInfo->Effects[m_effIndex].SpellClassMask))
return false;
// Check EffectClassMask
if (m_spellInfo->Effects[m_effIndex].SpellClassMask & spell->SpellFamilyFlags)
return true;
return false;
return true;
}
bool AuraEffect::HasSpellClassMask() const
@ -1146,6 +1142,99 @@ void AuraEffect::PeriodicTick(AuraApplication* aurApp, Unit* caster) const
}
}
bool AuraEffect::CheckEffectProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) const
{
bool result = GetBase()->CallScriptCheckEffectProcHandlers(this, aurApp, eventInfo);
if (!result)
return false;
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
switch (GetAuraType())
{
case SPELL_AURA_MOD_CONFUSE:
case SPELL_AURA_MOD_FEAR:
case SPELL_AURA_MOD_STUN:
case SPELL_AURA_MOD_ROOT:
case SPELL_AURA_TRANSFORM:
{
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
if (!damageInfo || !damageInfo->GetDamage())
{
return false;
}
// Spell own damage at apply won't break CC
if (spellInfo && spellInfo == eventInfo.GetSpellInfo())
{
Aura* aura = GetBase();
// called from spellcast, should not have ticked yet
if (aura->GetDuration() == aura->GetMaxDuration())
{
return false;
}
}
break;
}
break;
case SPELL_AURA_MECHANIC_IMMUNITY:
case SPELL_AURA_MOD_MECHANIC_RESISTANCE:
// Compare mechanic
if (!spellInfo || static_cast<int32>(spellInfo->Mechanic) != GetMiscValue())
{
return false;
}
break;
case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK:
// Skip melee hits and instant cast spells
if (!spellInfo || !spellInfo->CalcCastTime())
{
return false;
}
break;
case SPELL_AURA_MOD_DAMAGE_FROM_CASTER:
// Compare casters
if (GetCasterGUID() != eventInfo.GetActor()->GetGUID())
{
return false;
}
break;
case SPELL_AURA_MOD_POWER_COST_SCHOOL:
case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT:
// Skip melee hits and spells with wrong school or zero cost
if (!spellInfo || (!spellInfo->ManaCost && !spellInfo->ManaCostPercentage) || // Cost Check
!(spellInfo->GetSchoolMask() & GetMiscValue())) // School Check
{
return false;
}
break;
case SPELL_AURA_REFLECT_SPELLS_SCHOOL:
// Skip melee hits and spells with wrong school
if (!spellInfo || !(spellInfo->GetSchoolMask() & GetMiscValue()))
{
return false;
}
break;
case SPELL_AURA_PROC_TRIGGER_SPELL:
case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE:
{
// Don't proc extra attacks while already processing extra attack spell
uint32 triggerSpellId = GetSpellInfo()->Effects[GetEffIndex()].TriggerSpell;
if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId))
{
if (aurApp->GetTarget()->m_extraAttacks && triggeredSpellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS))
{
return false;
}
}
break;
}
default:
break;
}
return result;
}
void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
{
bool prevented = GetBase()->CallScriptEffectProcHandlers(this, aurApp, eventInfo);
@ -1154,6 +1243,16 @@ void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
switch (GetAuraType())
{
// CC Auras which use their amount to drop
// Are there anyu more auras which need this?
case SPELL_AURA_MOD_CONFUSE:
case SPELL_AURA_MOD_FEAR:
case SPELL_AURA_MOD_STUN:
case SPELL_AURA_MOD_ROOT:
case SPELL_AURA_TRANSFORM:
HandleBreakableCCAuraProc(aurApp, eventInfo);
break;
case SPELL_AURA_DUMMY:
case SPELL_AURA_PROC_TRIGGER_SPELL:
HandleProcTriggerSpellAuraProc(aurApp, eventInfo);
break;
@ -2878,7 +2977,6 @@ void AuraEffect::HandleAuraMounted(AuraApplication const* aurApp, uint8 mode, bo
displayId = 0;
}
}
}
target->Mount(displayId, vehicleId, GetMiscValue());
}
@ -5116,12 +5214,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool
if (target->GetTypeId() == TYPEID_PLAYER)
target->ToPlayer()->RemoveAmmo(); // not use ammo and not allow use
break;
case 71563:
{
if (Aura* newAura = target->AddAura(71564, target))
newAura->SetStackAmount(newAura->GetSpellInfo()->StackAmount);
return;
}
}
}
// AT REMOVE
@ -6354,10 +6446,8 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
mitigatedDamage += resilienceReduction;
}
damage = std::max(0, dmg);
cleanDamage.mitigated_damage = std::max(0, mitigatedDamage);
DamageInfo dmgInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK, cleanDamage.mitigated_damage);
DamageInfo dmgInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, cleanDamage.mitigated_damage);
Unit::CalcAbsorbResist(dmgInfo);
uint32 absorb = dmgInfo.GetAbsorb();
@ -6371,12 +6461,15 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
// Set trigger flag
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_DOT;
uint32 hitMask = dmgInfo.GetHitMask();
if (absorb > 0)
procEx |= PROC_EX_ABSORB;
hitMask |= PROC_HIT_ABSORB;
if (damage)
{
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
hitMask = crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL;
}
int32 overkill = damage - target->GetHealth();
if (overkill < 0)
@ -6387,7 +6480,8 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true);
Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo);
// allow null caster to call this function
caster->ProcSkillsAndAuras(target, caster ? procAttacker : 0, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &dmgInfo, nullptr);
}
void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) const
@ -6440,10 +6534,8 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
cleanDamageAmount += resilienceReduction;
}
damage = std::max(0, dmg);
cleanDamage.mitigated_damage = std::max(0, cleanDamageAmount);
DamageInfo dmgInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK, cleanDamage.mitigated_damage);
DamageInfo dmgInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, cleanDamage.mitigated_damage);
Unit::CalcAbsorbResist(dmgInfo);
uint32 absorb = dmgInfo.GetAbsorb();
@ -6453,12 +6545,15 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
// Set trigger flag
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_DOT;
uint32 hitMask = dmgInfo.GetHitMask();
if (absorb > 0)
procEx |= PROC_EX_ABSORB;
hitMask |= PROC_HIT_ABSORB;
if (dmgInfo.GetDamage())
{
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
hitMask |= crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL;
}
if (target->GetHealth() < dmgInfo.GetDamage())
{
@ -6476,7 +6571,8 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
new_damage = Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), false);
Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo);
// allow null caster to call this function
caster->ProcSkillsAndAuras(target, caster ? procAttacker : 0, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, nullptr, &dmgInfo, nullptr);
if (!caster || !caster->IsAlive())
return;
@ -6489,6 +6585,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
HealInfo healInfo(caster, caster, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
int32 gain = caster->HealBySpell(healInfo);
caster->getHostileRefMgr().threatAssist(caster, gain * 0.5f, GetSpellInfo());
caster->ProcSkillsAndAuras(caster, PROC_FLAG_DONE_PERIODIC, PROC_FLAG_TAKEN_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, hitMask, nullptr, nullptr, &healInfo);
}
void AuraEffect::HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster) const
@ -6622,13 +6719,13 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
HealInfo healInfo(caster, target, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
Unit::CalcHealAbsorb(healInfo);
int32 gain = Unit::DealHeal(caster, target, healInfo.GetHeal());
Unit::DealHeal(healInfo);
SpellPeriodicAuraLogInfo pInfo(this, healInfo.GetHeal(), healInfo.GetHeal() - gain, healInfo.GetAbsorb(), 0, 0.0f, crit);
SpellPeriodicAuraLogInfo pInfo(this, healInfo.GetHeal(), healInfo.GetHeal() - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), 0, 0.0f, crit);
target->SendPeriodicAuraLog(&pInfo);
if (caster)
target->getHostileRefMgr().threatAssist(caster, float(gain) * 0.5f, GetSpellInfo());
target->getHostileRefMgr().threatAssist(caster, float(healInfo.GetEffectiveHeal()) * 0.5f, GetSpellInfo());
bool haveCastItem = GetBase()->GetCastItemGUID();
@ -6638,9 +6735,9 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
if (target != caster && GetSpellInfo()->HasAttribute(SPELL_ATTR2_NO_TARGET_PER_SECOND_COST))
{
uint32 manaPerSecond = GetSpellInfo()->ManaPerSecond;
if ((int32)manaPerSecond > gain && gain > 0)
if (manaPerSecond > healInfo.GetEffectiveHeal() && healInfo.GetEffectiveHeal() > 0)
{
manaPerSecond = gain;
manaPerSecond = healInfo.GetEffectiveHeal();
}
uint32 absorb2 = 0;
@ -6652,13 +6749,15 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_HOT;
uint32 hitMask = (crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL);
if (healInfo.GetAbsorb() > 0)
procEx |= PROC_EX_ABSORB;
{
hitMask |= PROC_HIT_ABSORB;
}
// ignore item heals
if (!haveCastItem && GetAuraType() != SPELL_AURA_OBS_MOD_HEALTH) // xinef: dont allow obs_mod_health to proc spells, this is passive regeneration and not hot
Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, heal, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, nullptr, &healInfo);
caster->ProcSkillsAndAuras(target, caster ? procAttacker : 0, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, hitMask, nullptr, nullptr, &healInfo);
}
void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) const
@ -6839,14 +6938,32 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con
// Set trigger flag
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
uint32 procEx = createProcExtendMask(&damageInfo, SPELL_MISS_NONE) | PROC_EX_INTERNAL_DOT;
uint32 hitMask = createProcHitMask(&damageInfo, SPELL_MISS_NONE);
uint32 spellTypeMask = PROC_SPELL_TYPE_NO_DMG_HEAL;
if (damageInfo.damage)
{
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
spellTypeMask |= PROC_SPELL_TYPE_DAMAGE;
}
caster->DealSpellDamage(&damageInfo, true);
DamageInfo dmgInfo(damageInfo, DOT);
Unit::ProcDamageAndSpell(caster, damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto, nullptr, GetEffIndex(), nullptr, &dmgInfo);
DamageInfo dmgInfo(damageInfo, DOT, BASE_ATTACK, hitMask);
caster->ProcSkillsAndAuras(target, procAttacker, procVictim, spellTypeMask, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &dmgInfo, nullptr);
}
void AuraEffect::HandleBreakableCCAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
{
int32 const damageLeft = GetAmount() - static_cast<int32>(eventInfo.GetDamageInfo()->GetDamage());
if (damageLeft <= 0)
{
aurApp->GetTarget()->RemoveAura(aurApp);
}
else
{
SetAmount(damageLeft);
}
}
void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
@ -6862,7 +6979,7 @@ void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEve
}
else
{
LOG_DEBUG("spells.aura", "AuraEffect::HandleProcTriggerSpellAuraProc: Could not trigger spell {} from aura {} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
LOG_ERROR("spells.aura", "AuraEffect::HandleProcTriggerSpellAuraProc: Could not trigger spell {} from aura {} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
}
}
@ -6883,7 +7000,7 @@ void AuraEffect::HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp
}
else
{
LOG_DEBUG("spells.aura", "AuraEffect::HandleProcTriggerSpellWithValueAuraProc: Could not trigger spell {} from aura {} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
LOG_ERROR("spells.aura", "AuraEffect::HandleProcTriggerSpellWithValueAuraProc: Could not trigger spell {} from aura {} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
}
}

View file

@ -49,7 +49,6 @@ public:
Aura* GetBase() const { return m_base; }
void GetTargetList(std::list<Unit*>& targetList) const;
void GetApplicationList(std::list<AuraApplication*>& applicationList) const;
SpellModifier* GetSpellModifier() const { return m_spellmod; }
SpellInfo const* GetSpellInfo() const { return m_spellInfo; }
uint32 GetId() const;
@ -96,6 +95,7 @@ public:
void SendTickImmune(Unit* target, Unit* caster) const;
void PeriodicTick(AuraApplication* aurApp, Unit* caster) const;
bool CheckEffectProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) const;
void HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
void CleanupTriggeredSpells(Unit* target);
@ -333,6 +333,7 @@ public:
void HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) const;
// aura effect proc handlers
void HandleBreakableCCAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
void HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
void HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
void HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);

View file

@ -411,7 +411,7 @@ Aura::Aura(SpellInfo const* spellproto, WorldObject* owner, Unit* caster, Item*
m_castItemGuid(itemGUID ? itemGUID : castItem ? castItem->GetGUID() : ObjectGuid::Empty), m_castItemEntry(castItem ? castItem->GetEntry() : 0), m_applyTime(GameTime::GetGameTime().count()),
m_owner(owner), m_timeCla(0), m_updateTargetMapInterval(0),
m_casterLevel(caster ? caster->getLevel() : m_spellInfo->SpellLevel), m_procCharges(0), m_stackAmount(1),
m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_triggeredByAuraSpellInfo(nullptr)
m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_procCooldown(std::chrono::steady_clock::time_point::min()), m_triggeredByAuraSpellInfo(nullptr)
{
if ((m_spellInfo->ManaPerSecond || m_spellInfo->ManaPerSecondPerLevel) && !m_spellInfo->HasAttribute(SPELL_ATTR2_NO_TARGET_PER_SECOND_COST))
m_timeCla = 1 * IN_MILLISECONDS;
@ -875,7 +875,7 @@ int32 Aura::CalcMaxDuration(Unit* caster) const
// IsPermanent() checks max duration (which we are supposed to calculate here)
if (maxDuration != -1 && modOwner)
modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, maxDuration);
modOwner->ApplySpellMod<SPELLMOD_DURATION>(GetId(), maxDuration);
return maxDuration;
}
@ -885,7 +885,7 @@ void Aura::SetDuration(int32 duration, bool withMods)
{
if (Unit* caster = GetCaster())
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, duration);
modOwner->ApplySpellMod<SPELLMOD_DURATION>(GetId(), duration);
}
m_duration = duration;
SetNeedClientUpdateForTargets();
@ -976,11 +976,11 @@ uint8 Aura::CalcMaxCharges(Unit* caster) const
{
uint32 maxProcCharges = m_spellInfo->ProcCharges;
if (SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId()))
maxProcCharges = procEntry->charges;
maxProcCharges = procEntry->Charges;
if (caster)
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(GetId(), SPELLMOD_CHARGES, maxProcCharges);
modOwner->ApplySpellMod<SPELLMOD_CHARGES>(GetId(), maxProcCharges);
return maxProcCharges;
}
@ -1062,12 +1062,6 @@ bool Aura::ModStackAmount(int32 num, AuraRemoveMode removeMode, bool periodicRes
// reset charges
SetCharges(CalcMaxCharges());
// FIXME: not a best way to synchronize charges, but works
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if (AuraEffect* aurEff = GetEffect(i))
if (aurEff->GetAuraType() == SPELL_AURA_ADD_FLAT_MODIFIER || aurEff->GetAuraType() == SPELL_AURA_ADD_PCT_MODIFIER)
if (SpellModifier* mod = aurEff->GetSpellModifier())
mod->charges = GetCharges();
}
SetStackAmount(stackAmount);
@ -1202,7 +1196,7 @@ int32 Aura::CalcDispelChance(Unit* auraTarget, bool offensive) const
// Apply dispel mod from aura caster
if (Unit* caster = GetCaster())
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(GetId(), SPELLMOD_RESIST_DISPEL_CHANCE, resistChance);
modOwner->ApplySpellMod<SPELLMOD_RESIST_DISPEL_CHANCE>(GetId(), resistChance);
// Dispel resistance from target SPELL_AURA_MOD_DISPEL_RESIST
// Only affects offensive dispels
@ -1260,7 +1254,7 @@ void Aura::HandleAllEffects(AuraApplication* aurApp, uint8 mode, bool apply)
m_effects[i]->HandleEffect(aurApp, mode, apply);
}
void Aura::GetApplicationList(std::list<AuraApplication*>& applicationList) const
void Aura::GetApplicationList(Unit::AuraApplicationList& applicationList) const
{
for (Aura::ApplicationMap::const_iterator appIter = m_applications.begin(); appIter != m_applications.end(); ++appIter)
{
@ -1439,6 +1433,9 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
}
break;
case 44544: // Fingers of Frost
// Refresh or add visual aura
target->CastCustomSpell(74396, SPELLVALUE_AURA_STACK, sSpellMgr->AssertSpellInfo(74396)->StackAmount, (Unit*)nullptr, true);
break;
{
// See if we already have the indicator aura. If not, create one.
if (Aura* aur = target->GetAura(74396))
@ -1663,10 +1660,6 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
target->CastSpell(target, 32612, true, nullptr, GetEffect(1));
target->CombatStop();
break;
case 74396: // Fingers of Frost
// Remove the IGNORE_AURASTATE aura
target->RemoveAurasDueToSpell(44544);
break;
case 44401: // Missile Barrage
case 48108: // Hot Streak
case 57761: // Fireball!
@ -2192,22 +2185,17 @@ bool Aura::CanStackWith(Aura const* existingAura, bool remove) const
return true;
}
bool Aura::IsProcOnCooldown() const
bool Aura::IsProcOnCooldown(std::chrono::steady_clock::time_point now) const
{
/*if (m_procCooldown)
{
if (m_procCooldown > GameTime::GetGameTime().count())
return true;
}*/
return false;
return m_procCooldown > now;
}
void Aura::AddProcCooldown(uint32 /*msec*/)
void Aura::AddProcCooldown(std::chrono::steady_clock::time_point cooldownEnd)
{
//m_procCooldown = GameTime::GetGameTime().count() + msec;
m_procCooldown = cooldownEnd;
}
void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo)
void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now)
{
bool prepare = CallScriptPrepareProcHandlers(aurApp, eventInfo);
if (!prepare)
@ -2225,47 +2213,101 @@ void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInf
ASSERT(procEntry);
// cooldowns should be added to the whole aura (see 51698 area aura)
AddProcCooldown(procEntry->cooldown);
AddProcCooldown(now + procEntry->Cooldown);
}
bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) const
uint8 Aura::GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const
{
SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId());
// only auras with spell proc entry can trigger proc
if (!procEntry)
return false;
return 0;
// check spell triggering us
if (Spell const* spell = eventInfo.GetProcSpell())
{
// Do not allow auras to proc from effect triggered from itself
if (spell->IsTriggeredByAura(m_spellInfo))
return 0;
// check if aura can proc when spell is triggered (exception for hunter auto shot & wands)
if (spell->IsTriggered() && !(procEntry->AttributesMask & PROC_ATTR_TRIGGERED_CAN_PROC) && !(eventInfo.GetTypeMask() & AUTO_ATTACK_PROC_FLAG_MASK))
if (!GetSpellInfo()->HasAttribute(SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED))
return 0;
}
// check don't break stealth attr present
if (m_spellInfo->HasAura(SPELL_AURA_MOD_STEALTH))
{
if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
if (spellInfo->HasAttribute(SPELL_ATTR0_CU_DONT_BREAK_STEALTH))
return 0;
}
// check if we have charges to proc with
if (IsUsingCharges() && !GetCharges())
return false;
if (IsUsingCharges())
{
if (!GetCharges())
return 0;
if (procEntry->AttributesMask & PROC_ATTR_REQ_SPELLMOD)
{
if (Spell const* spell = eventInfo.GetProcSpell())
{
if (!spell->m_appliedMods.count(const_cast<Aura*>(this)))
{
return 0;
}
}
}
}
// check proc cooldown
if (IsProcOnCooldown())
return false;
// TODO:
// something about triggered spells triggering, and add extra attack effect
if (IsProcOnCooldown(now))
return 0;
// do checks against db data
if (!sSpellMgr->CanSpellTriggerProcOnEvent(*procEntry, eventInfo))
return false;
if (!SpellMgr::CanSpellTriggerProcOnEvent(*procEntry, eventInfo))
return 0;
// do checks using conditions table
ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_PROC, GetId());
ConditionSourceInfo condInfo = ConditionSourceInfo(eventInfo.GetActor(), eventInfo.GetActionTarget());
if (!sConditionMgr->IsObjectMeetToConditions(condInfo, conditions))
return false;
return 0;
// AuraScript Hook
bool check = const_cast<Aura*>(this)->CallScriptCheckProcHandlers(aurApp, eventInfo);
if (!check)
return false;
return 0;
// At least one effect has to pass checks to proc aura
uint8 procEffectMask = aurApp->GetEffectMask();
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
if (procEffectMask & (1 << i))
if ((procEntry->AttributesMask & (PROC_ATTR_DISABLE_EFF_0 << i)) || !GetEffect(i)->CheckEffectProc(aurApp, eventInfo))
procEffectMask &= ~(1 << i);
}
if (!procEffectMask)
return 0;
// TODO:
// do allow additional requirements for procs
// this is needed because this is the last moment in which you can prevent aura charge drop on proc
// and possibly a way to prevent default checks (if there're going to be any)
// Aura added by spoell can't trigger from self (prevent drop charges/do triggers)
// But except periodic and kill triggers (can triggered from self)
if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
{
if (spellInfo->Id == GetId() && !(eventInfo.GetTypeMask() & (PROC_FLAG_TAKEN_PERIODIC | PROC_FLAG_KILL)))
{
return 0;
}
}
// Check if current equipment meets aura requirements
// do that only for passive spells
// TODO: this needs to be unified for all kinds of auras
@ -2278,7 +2320,7 @@ bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventI
if (GetSpellInfo()->EquippedItemClass == ITEM_CLASS_WEAPON)
{
if (target->ToPlayer()->IsInFeralForm())
return false;
return 0;
if (DamageInfo const* damageInfo = eventInfo.GetDamageInfo())
{
@ -2309,39 +2351,50 @@ bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventI
}
}
return roll_chance_f(CalcProcChance(*procEntry, eventInfo));
if (roll_chance_f(CalcProcChance(*procEntry, eventInfo)))
return procEffectMask;
return 0;
}
float Aura::CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const
{
float chance = procEntry.chance;
float chance = procEntry.Chance;
// calculate chances depending on unit with caster's data
// so talents modifying chances and judgements will have properly calculated proc chance
if (Unit* caster = GetCaster())
{
// calculate ppm chance if present and we're using weapon
if (eventInfo.GetDamageInfo() && procEntry.ratePerMinute != 0)
if (eventInfo.GetDamageInfo() && procEntry.ProcsPerMinute != 0)
{
uint32 WeaponSpeed = caster->GetAttackTime(eventInfo.GetDamageInfo()->GetAttackType());
chance = caster->GetPPMProcChance(WeaponSpeed, procEntry.ratePerMinute, GetSpellInfo());
chance = caster->GetPPMProcChance(WeaponSpeed, procEntry.ProcsPerMinute, GetSpellInfo());
}
// apply chance modifer aura, applies also to ppm chance (see improved judgement of light spell)
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(GetId(), SPELLMOD_CHANCE_OF_SUCCESS, chance);
modOwner->ApplySpellMod<SPELLMOD_CHANCE_OF_SUCCESS>(GetId(), chance);
}
return chance;
}
void Aura::TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo)
void Aura::TriggerProcOnEvent(uint8 procEffectMask, AuraApplication* aurApp, ProcEventInfo& eventInfo)
{
CallScriptProcHandlers(aurApp, eventInfo);
bool prevented = CallScriptProcHandlers(aurApp, eventInfo);
if (!prevented)
{
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
if (!(procEffectMask & (1 << i)))
continue;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if (aurApp->HasEffect(i))
// OnEffectProc / AfterEffectProc hooks handled in AuraEffect::HandleProc()
GetEffect(i)->HandleProc(aurApp, eventInfo);
if (aurApp->HasEffect(i))
GetEffect(i)->HandleProc(aurApp, eventInfo);
}
CallScriptAfterProcHandlers(aurApp, eventInfo);
CallScriptAfterProcHandlers(aurApp, eventInfo);
}
// Remove aura if we've used last charge to proc
if (IsUsingCharges() && !GetCharges())
@ -2637,30 +2690,14 @@ void Aura::CallScriptEffectSplitHandlers(AuraEffect* aurEff, AuraApplication con
bool Aura::CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
{
bool result = true;
for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
for (auto & m_loadedScript : m_loadedScripts)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_PROC, aurApp);
std::list<AuraScript::CheckProcHandler>::iterator hookItrEnd = (*scritr)->DoCheckProc.end(), hookItr = (*scritr)->DoCheckProc.begin();
m_loadedScript->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_PROC, aurApp);
auto hookItrEnd = m_loadedScript->DoCheckProc.end(), hookItr = m_loadedScript->DoCheckProc.begin();
for (; hookItr != hookItrEnd; ++hookItr)
result &= hookItr->Call(*scritr, eventInfo);
result &= hookItr->Call(m_loadedScript, eventInfo);
(*scritr)->_FinishScriptCall();
}
return result;
}
bool Aura::CallScriptCheckAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
{
bool result = true;
for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_AFTER_PROC, aurApp);
std::list<AuraScript::CheckProcHandler>::iterator hookItrEnd = (*scritr)->DoCheckAfterProc.end(), hookItr = (*scritr)->DoCheckAfterProc.begin();
for (; hookItr != hookItrEnd; ++hookItr)
result &= hookItr->Call(*scritr, eventInfo);
(*scritr)->_FinishScriptCall();
m_loadedScript->_FinishScriptCall();
}
return result;
@ -2715,6 +2752,26 @@ void Aura::CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventI
}
}
bool Aura::CallScriptCheckEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo)
{
bool result = true;
for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC, aurApp);
std::list<AuraScript::CheckEffectProcHandler>::iterator hookItrEnd = (*scritr)->DoCheckEffectProc.end(), hookItr = (*scritr)->DoCheckEffectProc.begin();
for (; hookItr != hookItrEnd; ++hookItr)
{
if (hookItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
result &= hookItr->Call(*scritr, aurEff, eventInfo);
}
(*scritr)->_FinishScriptCall();
}
return result;
}
bool Aura::CallScriptEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo)
{
bool preventDefault = false;

View file

@ -191,18 +191,14 @@ public:
bool CanStackWith(Aura const* checkAura, bool remove) const;
bool IsAuraStronger(Aura const* newAura) const;
// Proc system
// this subsystem is not yet in use - the core of it is functional, but still some research has to be done
// and some dependant problems fixed before it can replace old proc system (for example cooldown handling)
// currently proc system functionality is implemented in Unit::ProcDamageAndSpell
bool IsProcOnCooldown() const;
void AddProcCooldown(uint32 msec);
bool IsProcOnCooldown(std::chrono::steady_clock::time_point now) const;
void AddProcCooldown(std::chrono::steady_clock::time_point cooldownEnd);
bool IsUsingCharges() const { return m_isUsingCharges; }
void SetUsingCharges(bool val) { m_isUsingCharges = val; }
void PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo);
bool IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) const;
void PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now);
uint8 GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const;
float CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const;
void TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo);
void TriggerProcOnEvent(uint8 procEffectMask, AuraApplication* aurApp, ProcEventInfo& eventInfo);
// AuraScript
void LoadScripts();
@ -226,7 +222,7 @@ public:
// Spell Proc Hooks
bool CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
bool CallScriptCheckAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
bool CallScriptCheckEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo);
bool CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
bool CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
void CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
@ -269,6 +265,8 @@ protected:
bool m_isSingleTarget: 1; // true if it's a single target spell and registered at caster - can change at spell steal for example
bool m_isUsingCharges: 1;
std::chrono::steady_clock::time_point m_procCooldown;
private:
Unit::AuraApplicationList m_removedApplications;

View file

@ -640,7 +640,7 @@ Spell::Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags,
m_healing = 0;
m_procAttacker = 0;
m_procVictim = 0;
m_procEx = 0;
m_hitMask = 0;
focusObject = nullptr;
m_cast_count = 0;
m_glyphIndex = 0;
@ -1811,7 +1811,7 @@ void Spell::SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTarg
{
uint32 maxTargets = m_spellInfo->Effects[effIndex].ChainTarget;
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, maxTargets, this);
modOwner->ApplySpellMod<SPELLMOD_JUMP_TARGETS>(m_spellInfo->Id, maxTargets, this);
if (maxTargets > 1)
{
@ -2273,12 +2273,11 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar
}
}
void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
void Spell::prepareDataForTriggerSystem()
{
//==========================================================================================
// Now fill data for trigger system, need know:
// can spell trigger another or not (m_canTrigger)
// Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_procEx)
// Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_hitMask)
//==========================================================================================
m_procVictim = m_procAttacker = 0;
@ -2317,7 +2316,7 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
// For other spells trigger procflags are set in Spell::DoAllEffectOnTarget
// Because spell positivity is dependant on target
}
m_procEx = PROC_EX_NONE;
m_hitMask = PROC_HIT_NONE;
// Hunter trap spells - activation proc for Lock and Load, Entrapment and Misdirection
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER &&
@ -2326,10 +2325,11 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
m_spellInfo->SpellFamilyFlags[2] & 0x00064000)) // Explosive and Immolation Trap
{
m_procAttacker |= PROC_FLAG_DONE_TRAP_ACTIVATION;
}
/* Effects which are result of aura proc from triggered spell cannot proc
to prevent chain proc of these spells */
// also fill up other flags (DoAllEffectOnTarget only fills up flag if both are not set)
m_procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG;
m_procVictim |= PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG;
}
// Hellfire Effect - trigger as DOT
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags[0] & 0x00000040)
@ -2337,20 +2337,6 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
m_procAttacker = PROC_FLAG_DONE_PERIODIC;
m_procVictim = PROC_FLAG_TAKEN_PERIODIC;
}
// Ranged autorepeat attack is set as triggered spell - ignore it
if (!(m_procAttacker & PROC_FLAG_DONE_RANGED_AUTO_ATTACK))
{
if (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS &&
(m_spellInfo->HasAttribute(SPELL_ATTR2_ACTIVE_THREAT) ||
m_spellInfo->HasAttribute(SPELL_ATTR3_NOT_A_PROC)))
m_procEx |= PROC_EX_INTERNAL_CANT_PROC;
else if (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS)
m_procEx |= PROC_EX_INTERNAL_TRIGGERED;
}
// Totem casts require spellfamilymask defined in spell_proc_event to proc
if (m_originalCaster && m_caster != m_originalCaster && m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsTotem() && m_caster->IsControlledByPlayer())
m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY;
}
void Spell::CleanupTargetList()
@ -2362,6 +2348,32 @@ void Spell::CleanupTargetList()
m_delayTrajectory = 0;
}
class ProcReflectDelayed : public BasicEvent
{
public:
ProcReflectDelayed(Unit* owner, ObjectGuid casterGuid) : _victim(owner), _casterGuid(casterGuid) { }
bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override
{
Unit* caster = ObjectAccessor::GetUnit(*_victim, _casterGuid);
if (!caster)
return true;
uint32 const typeMaskActor = PROC_FLAG_NONE;
uint32 const typeMaskActionTarget = PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG;
uint32 const spellTypeMask = PROC_SPELL_TYPE_DAMAGE | PROC_SPELL_TYPE_NO_DMG_HEAL;
uint32 const spellPhaseMask = PROC_SPELL_PHASE_NONE;
uint32 const hitMask = PROC_HIT_REFLECT;
caster->ProcSkillsAndAuras(_victim, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, nullptr, nullptr, nullptr);
return true;
}
private:
Unit* _victim;
ObjectGuid _casterGuid;
};
void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= true*/, bool implicit /*= true*/)
{
for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
@ -2373,11 +2385,8 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
return;
if (checkIfValid)
{
SpellCastResult res = m_spellInfo->CheckTarget(m_caster, target, implicit);
if (res != SPELL_CAST_OK)
if (m_spellInfo->CheckTarget(m_caster, target, implicit) != SPELL_CAST_OK) // skip stealth checks for AOE
return;
}
// Check for effect immune skip if immuned
for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
@ -2448,23 +2457,22 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
targetInfo.timeDelay = (uint64) floor(dist / m_spellInfo->Speed * 1000.0f);
// Calculate minimum incoming time
if (m_delayMoment == 0 || m_delayMoment > targetInfo.timeDelay)
if (!m_delayMoment || m_delayMoment > targetInfo.timeDelay)
m_delayMoment = targetInfo.timeDelay;
}
else
targetInfo.timeDelay = 0LL;
targetInfo.timeDelay = 0ULL;
// If target reflect spell back to caster
if (targetInfo.missCondition == SPELL_MISS_REFLECT)
{
// Calculate reflected spell result on caster
targetInfo.reflectResult = m_caster->SpellHitResult(m_caster, m_spellInfo, m_canReflect);
targetInfo.reflectResult = m_caster->SpellHitResult(m_caster, m_spellInfo, false); // can't reflect twice
if (targetInfo.reflectResult == SPELL_MISS_REFLECT) // Impossible reflect again, so simply deflect spell
targetInfo.reflectResult = SPELL_MISS_PARRY;
// Proc spell reflect aura when missile hits the original target
target->m_Events.AddEvent(new ProcReflectDelayed(target, m_originalCasterGUID), target->m_Events.CalculateTime(targetInfo.timeDelay));
// Increase time interval for reflected spells by 1.5
m_caster->m_Events.AddEvent(new ReflectEvent(m_caster, targetInfo.targetGUID, m_spellInfo), m_caster->m_Events.CalculateTime(targetInfo.timeDelay));
targetInfo.timeDelay += targetInfo.timeDelay >> 1;
m_spellFlags |= SPELL_FLAG_REFLECTED;
@ -2545,7 +2553,7 @@ void Spell::AddGOTarget(GameObject* go, uint32 effectMask)
if (dist < 5.0f)
dist = 5.0f;
target.timeDelay = uint64(floor(dist / m_spellInfo->Speed * 1000.0f));
if (m_delayMoment == 0 || m_delayMoment > target.timeDelay)
if (!m_delayMoment || m_delayMoment > target.timeDelay)
m_delayMoment = target.timeDelay;
}
else
@ -2660,8 +2668,8 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
PrepareScriptHitHandlers();
CallScriptBeforeHitHandlers(missInfo);
//Spells with this flag cannot trigger if effect is casted on self
bool canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_SUPRESS_CASTER_PROCS) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE2);
// Spells with this flag cannot trigger if effect is casted on self
bool const canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_SUPRESS_CASTER_PROCS) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE2);
bool reflectedSpell = missInfo == SPELL_MISS_REFLECT;
Unit* spellHitTarget = nullptr;
@ -2699,18 +2707,14 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (missInfo != SPELL_MISS_NONE && m_needComboPoints && m_targets.GetUnitTargetGUID() == target->targetGUID)
{
m_needComboPoints = false;
// Restore spell mods for a miss/dodge/parry Cold Blood
// TODO: check how broad this rule should be
if (m_caster->GetTypeId() == TYPEID_PLAYER && (missInfo == SPELL_MISS_MISS || missInfo == SPELL_MISS_DODGE || missInfo == SPELL_MISS_PARRY))
m_caster->ToPlayer()->RestoreSpellMods(this, 14177);
}
// Fill base trigger info
uint32 procAttacker = m_procAttacker;
uint32 procVictim = m_procVictim;
uint32 procEx = m_procEx;
uint32 hitMask = m_hitMask;
// Trigger info was not filled in spell::preparedatafortriggersystem - we do it now
// Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now
if (canEffectTrigger && !procAttacker && !procVictim)
{
bool positive = true;
@ -2766,11 +2770,11 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (crit)
{
procEx |= PROC_EX_CRITICAL_HIT;
hitMask |= PROC_HIT_CRITICAL;
addhealth = Unit::SpellCriticalHealingBonus(caster, m_spellInfo, addhealth, nullptr);
}
else
procEx |= PROC_EX_NORMAL_HIT;
hitMask |= PROC_HIT_NORMAL;
HealInfo healInfo(caster, unitTarget, addhealth, m_spellInfo, m_spellInfo->GetSchoolMask());
@ -2778,27 +2782,20 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (GetSpellValue()->ForcedCritResult)
{
crit = true;
procEx |= PROC_EX_CRITICAL_HIT;
hitMask |= PROC_HIT_CRITICAL;
}
int32 gain = caster->HealBySpell(healInfo, crit);
unitTarget->getHostileRefMgr().threatAssist(caster, float(gain) * 0.5f, m_spellInfo);
m_healing = gain;
// Xinef: if heal acutally healed something, add no overheal flag
if (m_healing)
procEx |= PROC_EX_NO_OVERHEAL;
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
// Do triggers for unit
if (canEffectTrigger)
Unit::ProcDamageAndSpell(caster, unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
m_triggeredByAuraSpell.effectIndex, this, nullptr, &healInfo);
caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, nullptr, &healInfo);
}
// Do damage and triggers
else if (m_damage > 0)
{
caster->SetLastDamagedTargetGuid(unitTarget->GetGUID());
// Fill base damage struct (unitTarget - is real spell target)
SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo, m_spellSchoolMask);
@ -2858,7 +2855,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (reflectedSpell)
effectUnit->SendSpellNonMeleeReflectLog(&damageInfo, effectUnit);
procEx |= createProcExtendMask(&damageInfo, missInfo);
hitMask |= createProcHitMask(&damageInfo, missInfo);
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
caster->DealSpellDamage(&damageInfo, true, this);
@ -2866,16 +2863,15 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
// do procs after damage, eg healing effects
// no need to check if target is alive, done in procdamageandspell
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
// Do triggers for unit
if (canEffectTrigger)
{
DamageInfo dmgInfo(damageInfo, SPELL_DIRECT_DAMAGE);
Unit::ProcDamageAndSpell(caster, unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
m_triggeredByAuraSpell.effectIndex, this, &dmgInfo);
DamageInfo dmgInfo(damageInfo, SPELL_DIRECT_DAMAGE, m_attackType, hitMask);
caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, this, &dmgInfo, nullptr);
if (caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) == 0 &&
m_spellInfo->HasAttribute(SPELL_ATTR4_SUPRESS_WEAPON_PROCS) == 0 && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim, procEx);
caster->ToPlayer()->CastItemCombatSpell(dmgInfo);
}
m_damage = damageInfo.damage;
@ -2885,19 +2881,16 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
{
// Fill base damage struct (unitTarget - is real spell target)
SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo, m_spellSchoolMask);
procEx |= createProcExtendMask(&damageInfo, missInfo);
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
hitMask |= createProcHitMask(&damageInfo, missInfo);
// Do triggers for unit
if (canEffectTrigger)
{
DamageInfo dmgInfo(damageInfo, NODAMAGE);
Unit::ProcDamageAndSpell(caster, unitTarget, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
m_triggeredByAuraSpell.effectIndex, this, &dmgInfo);
DamageInfo spellNoDamageInfo(damageInfo, NODAMAGE, m_attackType, hitMask);
caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_NO_DMG_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, &spellNoDamageInfo, nullptr);
// Xinef: eg. rogue poisons can proc off cheap shot, etc. so this block should be here also
// Xinef: ofc count only spells that HIT the target, little hack used to fool the system
if ((procEx & PROC_EX_NORMAL_HIT || procEx & PROC_EX_CRITICAL_HIT) && caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) == 0 &&
m_spellInfo->HasAttribute(SPELL_ATTR4_SUPRESS_WEAPON_PROCS) == 0 && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim | PROC_FLAG_TAKEN_DAMAGE, procEx);
if (caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) &&
!m_spellInfo->HasAttribute(SPELL_ATTR4_SUPRESS_WEAPON_PROCS) && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
caster->ToPlayer()->CastItemCombatSpell(spellNoDamageInfo);
}
// Failed Pickpocket, reveal rogue
@ -3121,10 +3114,6 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
m_spellAura = Aura::TryRefreshStackOrCreate(aurSpellInfo, effectMask, unit, m_originalCaster,
(aurSpellInfo == m_spellInfo) ? &m_spellValue->EffectBasePoints[0] : &basePoints[0], m_CastItem, ObjectGuid::Empty, &refresh, refreshPeriodic);
// xinef: if aura was not refreshed, add proc ex
if (!refresh)
m_procEx |= PROC_EX_NO_AURA_REFRESH;
if (m_spellAura)
{
// Set aura stack amount to desired value
@ -3253,8 +3242,8 @@ void Spell::DoTriggersOnSpellHit(Unit* unit, uint8 effMask)
// info confirmed with retail sniffs of permafrost and shadow weaving
if (!m_hitTriggerSpells.empty())
{
int _duration = 0;
for (HitTriggerSpellList::const_iterator i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i)
int32 _duration = 0;
for (auto i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i)
{
if (CanExecuteTriggersOnHit(effMask, i->triggeredByAura) && roll_chance_i(i->chance))
{
@ -3380,7 +3369,7 @@ bool Spell::UpdateChanneledTargetList()
}
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
modOwner->ApplySpellMod<SPELLMOD_RANGE>(m_spellInfo->Id, range, this);
// xinef: add little tolerance level
range += std::min(3.0f, range * 0.1f); // 10% but no more than 3yd
@ -3543,7 +3532,7 @@ SpellCastResult Spell::prepare(SpellCastTargets const* targets, AuraEffect const
}
// Prepare data for triggers
prepareDataForTriggerSystem(triggeredByAura);
prepareDataForTriggerSystem();
// calculate cast time (calculated after first CheckCast check to prevent charge counting for first CheckCast fail)
m_casttime = (_triggeredCastFlags & TRIGGERED_CAST_DIRECTLY) ? 0 : m_spellInfo->CalcCastTime(m_caster, this);
@ -3727,10 +3716,6 @@ void Spell::cancel(bool bySelf)
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->NeedSendSpectatorData())
ArenaSpectator::SendCommand_Spell(m_caster->FindMap(), m_caster->GetGUID(), "SPE", m_spellInfo->Id, bySelf ? 99998 : 99999);
// spell is canceled-take mods and clear list
if (Player* player = m_caster->GetSpellModOwner())
player->RemoveSpellMods(this);
m_appliedMods.clear();
break;
default:
@ -3955,26 +3940,14 @@ void Spell::_cast(bool skipCheck)
}
}
uint32 procEx = PROC_EX_NORMAL_HIT;
uint32 hitMask = m_hitMask;
for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
if (!(hitMask & PROC_HIT_CRITICAL))
{
if (ihit->missCondition != SPELL_MISS_NONE)
{
continue;
}
if (!ihit->crit)
{
continue;
}
procEx |= PROC_EX_CRITICAL_HIT;
break;
hitMask |= PROC_HIT_NORMAL;
}
Unit::ProcDamageAndSpell(m_originalCaster, m_originalCaster, procAttacker, PROC_FLAG_NONE, procEx, 1, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
m_triggeredByAuraSpell.effectIndex, this, nullptr, nullptr, PROC_SPELL_PHASE_CAST);
m_originalCaster->ProcSkillsAndAuras(m_originalCaster, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr);
}
if (modOwner)
@ -3995,11 +3968,6 @@ void Spell::_cast(bool skipCheck)
if (m_caster->HasUnitState(UNIT_STATE_CASTING) && !m_caster->IsNonMeleeSpellCast(false, false, true))
m_caster->ClearUnitState(UNIT_STATE_CASTING);
// remove all applied mods at this point
// dont allow user to use them twice in case spell did not reach current target
if (modOwner)
modOwner->RemoveSpellMods(this);
// Xinef: why do we keep focus after spell is sent to air?
// Xinef: Because of this, in the middle of some animation after setting targetguid to 0 etc
// Xinef: we get focused to it out of nowhere...
@ -4092,7 +4060,7 @@ void Spell::handle_immediate()
// First mod_duration then haste - see Missile Barrage
// Apply duration mod
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
modOwner->ApplySpellMod<SPELLMOD_DURATION>(m_spellInfo->Id, duration);
// Apply haste mods
if (m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, m_spellInfo) || m_spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC))
@ -4264,10 +4232,8 @@ void Spell::_handle_finish_phase()
m_caster->AddComboPoints(m_comboTarget, m_comboPointGain);
}
if (m_spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS))
{
m_caster->SetLastExtraAttackSpell(m_spellInfo->Id);
}
if (m_caster->m_extraAttacks && GetSpellInfo()->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS))
m_caster->HandleProcExtraAttackFor(m_caster->GetVictim());
if (!IsAutoRepeat() && !IsNextMeleeSwingSpell())
if (m_caster->GetCharmerOrOwnerPlayerOrPlayerItself())
@ -4296,25 +4262,13 @@ void Spell::_handle_finish_phase()
}
}
uint32 procEx = PROC_EX_NORMAL_HIT;
for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
uint32 hitMask = m_hitMask;
if (!(hitMask & PROC_HIT_CRITICAL))
{
if (ihit->missCondition != SPELL_MISS_NONE)
{
continue;
}
if (!ihit->crit)
{
continue;
}
procEx |= PROC_EX_CRITICAL_HIT;
break;
hitMask |= PROC_HIT_NORMAL;
}
Unit::ProcDamageAndSpell(m_originalCaster, m_originalCaster, procAttacker, PROC_FLAG_NONE, procEx, 1, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
m_triggeredByAuraSpell.effectIndex, this, nullptr, nullptr, PROC_SPELL_PHASE_FINISH);
m_originalCaster->ProcSkillsAndAuras(m_originalCaster, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_FINISH, hitMask, this, nullptr, nullptr);
}
}
@ -4504,11 +4458,6 @@ void Spell::finish(bool ok)
if (m_caster->GetTypeId() == TYPEID_PLAYER && !m_triggeredByAuraSpell)
m_caster->ToPlayer()->UpdatePotionCooldown(this);
// Take mods after trigger spell (needed for 14177 to affect 48664)
// mods are taken only on succesfull cast and independantly from targets of the spell
if (Player* player = m_caster->GetSpellModOwner())
player->RemoveSpellMods(this);
// xinef: clear reactive auras states after spell cast
if (m_spellInfo->CasterAuraState == AURA_STATE_DEFENSE || m_spellInfo->CasterAuraState == AURA_STATE_HUNTER_PARRY)
m_caster->ModifyAuraState(AuraStateType(m_spellInfo->CasterAuraState), false);
@ -5293,7 +5242,7 @@ void Spell::TakePower()
hit = false;
//lower spell cost on fail (by talent aura)
if (Player* modOwner = m_caster->ToPlayer()->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_SPELL_COST_REFUND_ON_FAIL, m_powerCost, this);
modOwner->ApplySpellMod<SPELLMOD_SPELL_COST_REFUND_ON_FAIL>(m_spellInfo->Id, m_powerCost, this);
}
break;
}
@ -5394,7 +5343,7 @@ SpellCastResult Spell::CheckRuneCost(uint32 RuneCostID)
{
runeCost[i] = src->RuneCost[i];
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i], this);
modOwner->ApplySpellMod<SPELLMOD_COST>(m_spellInfo->Id, runeCost[i], this);
}
runeCost[RUNE_DEATH] = MAX_RUNES; // calculated later
@ -5434,7 +5383,7 @@ void Spell::TakeRunePower(bool didHit)
{
runeCost[i] = runeCostData->RuneCost[i];
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i], this);
modOwner->ApplySpellMod<SPELLMOD_COST>(m_spellInfo->Id, runeCost[i], this);
}
runeCost[RUNE_DEATH] = 0; // calculated later
@ -5831,7 +5780,11 @@ SpellCastResult Spell::CheckCast(bool strict)
// Xinef: do not check explicit target for triggered spell casted on self with targetflag enemy
if (!m_triggeredByAuraSpell || m_targets.GetUnitTarget() != m_caster || !(m_spellInfo->GetExplicitTargetMask() & TARGET_FLAG_UNIT_ENEMY))
{
SpellCastResult castResult = m_spellInfo->CheckExplicitTarget((m_originalCaster && m_caster->GetEntry() != WORLD_TRIGGER) ? m_originalCaster : m_caster, m_targets.GetObjectTarget(), m_targets.GetItemTarget());
Unit* caster = m_caster;
if (m_originalCaster && m_caster->GetEntry() != WORLD_TRIGGER) // Do a simplified check for gameobject casts
caster = m_originalCaster;
SpellCastResult castResult = m_spellInfo->CheckExplicitTarget(caster, m_targets.GetObjectTarget(), m_targets.GetItemTarget());
if (castResult != SPELL_CAST_OK)
return castResult;
}
@ -5839,7 +5792,7 @@ SpellCastResult Spell::CheckCast(bool strict)
if (Unit* target = m_targets.GetUnitTarget())
{
SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, false);
SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, m_caster->GetEntry() == WORLD_TRIGGER); // skip stealth checks for GO casts
if (castResult != SPELL_CAST_OK)
return castResult;
@ -7035,7 +6988,7 @@ SpellCastResult Spell::CheckRange(bool strict)
range_type = SPELL_RANGE_RANGED;
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, max_range, this);
modOwner->ApplySpellMod<SPELLMOD_RANGE>(m_spellInfo->Id, max_range, this);
// xinef: dont check max_range to strictly after cast
if (range_type != SPELL_RANGE_MELEE && !strict)
@ -7749,7 +7702,7 @@ void Spell::Delayed() // only called in DealDamage()
//check pushback reduce
int32 delaytime = 500; // spellcasting delay is normally 500ms
int32 delayReduce = 100; // must be initialized to 100 for percent modifiers
m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this);
m_caster->ToPlayer()->ApplySpellMod<SPELLMOD_NOT_LOSE_CASTING_TIME>(m_spellInfo->Id, delayReduce, this);
delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
if (delayReduce >= 100)
return;
@ -7787,7 +7740,7 @@ void Spell::DelayedChannel()
int32 delaytime = CalculatePct(duration, 25); // channeling delay is normally 25% of its time per hit
int32 delayReduce = 100; // must be initialized to 100 for percent modifiers
m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this);
m_caster->ToPlayer()->ApplySpellMod<SPELLMOD_NOT_LOSE_CASTING_TIME>(m_spellInfo->Id, delayReduce, this);
delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
if (delayReduce >= 100)
return;
@ -8167,14 +8120,6 @@ bool SpellEvent::IsDeletable() const
return m_Spell->IsDeletable();
}
bool ReflectEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
{
Unit* target = ObjectAccessor::GetUnit(*_caster, _targetGUID);
if (target && _caster->IsInMap(target))
Unit::ProcDamageAndSpell(_caster, target, PROC_FLAG_NONE, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_EX_REFLECT, 1, BASE_ATTACK, _spellInfo);
return true;
}
bool Spell::IsValidDeadOrAliveTarget(Unit const* target) const
{
if (target->IsAlive())
@ -8750,26 +8695,24 @@ void Spell::PrepareTriggersExecutedOnHit()
// save auras which were present on spell caster on cast, to prevent triggered auras from affecting caster
// and to correctly calculate proc chance when combopoints are present
Unit::AuraEffectList const& targetTriggers = m_caster->GetAuraEffectsByType(SPELL_AURA_ADD_TARGET_TRIGGER);
for (Unit::AuraEffectList::const_iterator i = targetTriggers.begin(); i != targetTriggers.end(); ++i)
for (AuraEffect const* aurEff : targetTriggers)
{
if (!(*i)->IsAffectedOnSpell(m_spellInfo))
if (!aurEff->IsAffectedOnSpell(m_spellInfo))
continue;
SpellInfo const* auraSpellInfo = (*i)->GetSpellInfo();
uint32 auraSpellIdx = (*i)->GetEffIndex();
SpellInfo const* auraSpellInfo = aurEff->GetSpellInfo();
uint32 auraSpellIdx = aurEff->GetEffIndex();
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(auraSpellInfo->Effects[auraSpellIdx].TriggerSpell))
{
// calculate the chance using spell base amount, because aura amount is not updated on combo-points change
// this possibly needs fixing
int32 auraBaseAmount = (*i)->GetBaseAmount();
int32 auraBaseAmount = aurEff->GetBaseAmount();
// proc chance is stored in effect amount
int32 chance = m_caster->CalculateSpellDamage(nullptr, auraSpellInfo, auraSpellIdx, &auraBaseAmount);
chance *= aurEff->GetBase()->GetStackAmount();
// build trigger and add to the list
HitTriggerSpell spellTriggerInfo;
spellTriggerInfo.triggeredSpell = spellInfo;
spellTriggerInfo.triggeredByAura = auraSpellInfo;
spellTriggerInfo.triggeredByEffIdx = (*i)->GetEffIndex();
spellTriggerInfo.chance = chance * (*i)->GetBase()->GetStackAmount();
m_hitTriggerSpells.push_back(spellTriggerInfo);
m_hitTriggerSpells.emplace_back(spellInfo, auraSpellInfo, chance);
}
}
}
@ -8814,8 +8757,8 @@ void Spell::TriggerGlobalCooldown()
if (m_spellInfo->StartRecoveryTime >= MIN_GCD && m_spellInfo->StartRecoveryTime <= MAX_GCD)
{
// gcd modifier auras are applied only to own spells and only players have such mods
if (m_caster->GetTypeId() == TYPEID_PLAYER)
m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_GLOBAL_COOLDOWN, gcd, this);
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_GLOBAL_COOLDOWN>(m_spellInfo->Id, gcd, this);
// Apply haste rating
if (m_spellInfo->StartRecoveryCategory == 133 && m_spellInfo->StartRecoveryTime == 1500 && m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE &&
@ -8824,10 +8767,7 @@ void Spell::TriggerGlobalCooldown()
gcd = int32(float(gcd) * m_caster->GetFloatValue(UNIT_MOD_CAST_SPEED));
}
if (gcd < MIN_GCD)
gcd = MIN_GCD;
else if (gcd > MAX_GCD)
gcd = MAX_GCD;
RoundToInterval<int32>(gcd, MIN_GCD, MAX_GCD);
}
// Only players or controlled units have global cooldown

View file

@ -414,7 +414,7 @@ public:
void EffectCastButtons(SpellEffIndex effIndex);
void EffectRechargeManaGem(SpellEffIndex effIndex);
typedef std::set<Aura*> UsedSpellMods;
typedef std::unordered_set<Aura*> UsedSpellMods;
void InitExplicitTargets(SpellCastTargets const& targets);
void SelectExplicitTargets();
@ -554,6 +554,8 @@ public:
bool IsAutoActionResetSpell() const;
bool IsIgnoringCooldowns() const;
bool IsTriggeredByAura(SpellInfo const* auraSpellInfo) const { return (auraSpellInfo == m_triggeredByAuraSpell.spellInfo); }
bool IsDeletable() const { return !m_referencedFromCurrentSpell && !m_executedCurrently; }
void SetReferencedFromCurrent(bool yes) { m_referencedFromCurrentSpell = yes; }
bool IsInterruptable() const { return !m_executedCurrently; }
@ -670,8 +672,8 @@ public:
// ******************************************
uint32 m_procAttacker; // Attacker trigger flags
uint32 m_procVictim; // Victim trigger flags
uint32 m_procEx;
void prepareDataForTriggerSystem(AuraEffect const* triggeredByAura);
uint32 m_hitMask;
void prepareDataForTriggerSystem();
// *****************************************
// Spell target subsystem
@ -739,6 +741,9 @@ public:
struct HitTriggerSpell
{
HitTriggerSpell(SpellInfo const* spellInfo, SpellInfo const* auraSpellInfo, int32 procChance) :
triggeredSpell(spellInfo), triggeredByAura(auraSpellInfo), chance(procChance) { }
SpellInfo const* triggeredSpell;
SpellInfo const* triggeredByAura;
uint8 triggeredByEffIdx;
@ -747,7 +752,7 @@ public:
bool CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* triggeredByAura = nullptr) const;
void PrepareTriggersExecutedOnHit();
typedef std::list<HitTriggerSpell> HitTriggerSpellList;
typedef std::vector<HitTriggerSpell> HitTriggerSpellList;
HitTriggerSpellList m_hitTriggerSpells;
// effect helpers
@ -838,17 +843,4 @@ namespace Acore
}
typedef void(Spell::*pEffect)(SpellEffIndex effIndex);
class ReflectEvent : public BasicEvent
{
public:
ReflectEvent(Unit* caster, ObjectGuid targetGUID, SpellInfo const* spellInfo) : _caster(caster), _targetGUID(targetGUID), _spellInfo(spellInfo) { }
bool Execute(uint64 e_time, uint32 p_time) override;
protected:
Unit* _caster;
ObjectGuid _targetGUID;
SpellInfo const* _spellInfo;
};
#endif

View file

@ -72,38 +72,38 @@ enum SpellAuraInterruptFlags
AURA_INTERRUPT_FLAG_NOT_VICTIM = (AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_TAKE_DAMAGE | AURA_INTERRUPT_FLAG_DIRECT_DAMAGE),
};
enum SpellModOp
enum SpellModOp : uint8
{
SPELLMOD_DAMAGE = 0,
SPELLMOD_DURATION = 1,
SPELLMOD_THREAT = 2,
SPELLMOD_EFFECT1 = 3,
SPELLMOD_CHARGES = 4,
SPELLMOD_RANGE = 5,
SPELLMOD_RADIUS = 6,
SPELLMOD_CRITICAL_CHANCE = 7,
SPELLMOD_ALL_EFFECTS = 8,
SPELLMOD_NOT_LOSE_CASTING_TIME = 9,
SPELLMOD_CASTING_TIME = 10,
SPELLMOD_COOLDOWN = 11,
SPELLMOD_EFFECT2 = 12,
SPELLMOD_IGNORE_ARMOR = 13,
SPELLMOD_COST = 14,
SPELLMOD_CRIT_DAMAGE_BONUS = 15,
SPELLMOD_RESIST_MISS_CHANCE = 16,
SPELLMOD_JUMP_TARGETS = 17,
SPELLMOD_CHANCE_OF_SUCCESS = 18,
SPELLMOD_ACTIVATION_TIME = 19,
SPELLMOD_DAMAGE_MULTIPLIER = 20,
SPELLMOD_GLOBAL_COOLDOWN = 21,
SPELLMOD_DOT = 22,
SPELLMOD_EFFECT3 = 23,
SPELLMOD_BONUS_MULTIPLIER = 24,
SPELLMOD_DAMAGE = 0,
SPELLMOD_DURATION = 1,
SPELLMOD_THREAT = 2,
SPELLMOD_EFFECT1 = 3,
SPELLMOD_CHARGES = 4,
SPELLMOD_RANGE = 5,
SPELLMOD_RADIUS = 6,
SPELLMOD_CRITICAL_CHANCE = 7,
SPELLMOD_ALL_EFFECTS = 8,
SPELLMOD_NOT_LOSE_CASTING_TIME = 9,
SPELLMOD_CASTING_TIME = 10,
SPELLMOD_COOLDOWN = 11,
SPELLMOD_EFFECT2 = 12,
SPELLMOD_IGNORE_ARMOR = 13,
SPELLMOD_COST = 14,
SPELLMOD_CRIT_DAMAGE_BONUS = 15,
SPELLMOD_RESIST_MISS_CHANCE = 16,
SPELLMOD_JUMP_TARGETS = 17,
SPELLMOD_CHANCE_OF_SUCCESS = 18,
SPELLMOD_ACTIVATION_TIME = 19,
SPELLMOD_DAMAGE_MULTIPLIER = 20,
SPELLMOD_GLOBAL_COOLDOWN = 21,
SPELLMOD_DOT = 22,
SPELLMOD_EFFECT3 = 23,
SPELLMOD_BONUS_MULTIPLIER = 24,
// spellmod 25
SPELLMOD_PROC_PER_MINUTE = 26,
SPELLMOD_VALUE_MULTIPLIER = 27,
SPELLMOD_RESIST_DISPEL_CHANCE = 28,
SPELLMOD_CRIT_DAMAGE_BONUS_2 = 29, //one not used spell
SPELLMOD_PROC_PER_MINUTE = 26,
SPELLMOD_VALUE_MULTIPLIER = 27,
SPELLMOD_RESIST_DISPEL_CHANCE = 28,
SPELLMOD_CRIT_DAMAGE_BONUS_2 = 29, //one not used spell
SPELLMOD_SPELL_COST_REFUND_ON_FAIL = 30
};
@ -143,7 +143,7 @@ enum TriggerCastFlags
TRIGGERED_IGNORE_CASTER_AURASTATE = 0x00000800, //! Will ignore caster aura states including combat requirements and death state
TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE = 0x00002000, //! Will ignore mounted/on vehicle restrictions
TRIGGERED_IGNORE_CASTER_AURAS = 0x00010000, //! Will ignore caster aura restrictions or requirements
TRIGGERED_DISALLOW_PROC_EVENTS = 0x00020000, //! Disallows proc events from triggered spell (default)
// reuse 0x00020000
TRIGGERED_DONT_REPORT_CAST_ERROR = 0x00040000, //! Will return SPELL_FAILED_DONT_REPORT in CheckCast functions
TRIGGERED_FULL_MASK = 0x0007FFFF, //! Used when doing CastSpell with triggered == true
TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT = 0x00080000, //! Will ignore equipped item requirements

View file

@ -310,7 +310,7 @@ void Spell::EffectEnvironmentalDMG(SpellEffIndex /*effIndex*/)
unitTarget->ToPlayer()->EnvironmentalDamage(DAMAGE_FIRE, damage);
else
{
DamageInfo dmgInfo(m_caster, unitTarget, damage, m_spellInfo, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE);
DamageInfo dmgInfo(m_caster, unitTarget, damage, m_spellInfo, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, BASE_ATTACK);
uint32 absorb = dmgInfo.GetAbsorb();
uint32 resist = dmgInfo.GetResist();
@ -2342,7 +2342,7 @@ void Spell::EffectSummonType(SpellEffIndex effIndex)
int32 duration = m_spellInfo->GetDuration();
if (Player* modOwner = m_originalCaster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
modOwner->ApplySpellMod<SPELLMOD_DURATION>(m_spellInfo->Id, duration);
TempSummon* summon = nullptr;
@ -3148,7 +3148,7 @@ void Spell::EffectSummonPet(SpellEffIndex effIndex)
int32 duration = m_spellInfo->GetDuration();
if(Player* modOwner = m_originalCaster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
modOwner->ApplySpellMod<SPELLMOD_DURATION>(m_spellInfo->Id, duration);
Player* owner = m_originalCaster->ToPlayer();
if (!owner && m_originalCaster->ToCreature()->IsTotem())
@ -3722,6 +3722,7 @@ void Spell::EffectInterruptCast(SpellEffIndex effIndex)
{
int32 duration = m_originalCaster->ModSpellDuration(m_spellInfo, unitTarget, m_originalCaster->CalcSpellDuration(m_spellInfo), false, 1 << effIndex);
unitTarget->ProhibitSpellSchool(curSpellInfo->GetSchoolMask(), duration/*spellInfo->GetDuration()*/);
m_originalCaster->ProcSkillsAndAuras(unitTarget, PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_HIT, PROC_HIT_INTERRUPT, nullptr, nullptr, nullptr);
}
ExecuteLogEffectInterruptCast(effIndex, unitTarget, curSpellInfo->Id);
unitTarget->InterruptSpell(CurrentSpellTypes(i), false);
@ -4682,18 +4683,17 @@ void Spell::EffectResurrect(SpellEffIndex effIndex)
void Spell::EffectAddExtraAttacks(SpellEffIndex effIndex)
{
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
{
return;
}
if (!unitTarget || !unitTarget->IsAlive())
{
if (!unitTarget || !unitTarget->IsAlive() || !unitTarget->GetVictim())
return;
}
unitTarget->AddExtraAttacks(damage);
if (unitTarget->m_extraAttacks)
return;
ExecuteLogEffectExtraAttacks(effIndex, unitTarget, damage);
unitTarget->m_extraAttacks = damage;
ExecuteLogEffectExtraAttacks(effIndex, unitTarget->GetVictim(), damage);
}
void Spell::EffectParry(SpellEffIndex /*effIndex*/)
@ -5816,19 +5816,8 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex)
m_runesState = m_caster->ToPlayer()->GetRunesState();
uint32 count = damage;
if (count == 0) count = 1;
for (uint32 j = 0; j < MAX_RUNES && count > 0; ++j)
{
if (player->GetRuneCooldown(j) && player->GetCurrentRune(j) == RuneType(m_spellInfo->Effects[effIndex].MiscValue))
{
if (m_spellInfo->Id == 45529)
if (player->GetBaseRune(j) != RuneType(m_spellInfo->Effects[effIndex].MiscValueB))
continue;
player->SetRuneCooldown(j, 0);
player->SetGracePeriod(j, player->IsInCombat()); // xinef: reset grace period
--count;
}
}
if (count == 0)
count = 1;
// Blood Tap
if (m_spellInfo->Id == 45529 && count > 0)
@ -5836,10 +5825,10 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex)
for (uint32 l = 0; l < MAX_RUNES && count > 0; ++l)
{
// Check if both runes are on cd as that is the only time when this needs to come into effect
if ((player->GetRuneCooldown(l) && player->GetCurrentRune(l) == RuneType(m_spellInfo->Effects[effIndex].MiscValueB)) && (player->GetRuneCooldown(l + 1) && player->GetCurrentRune(l + 1) == RuneType(m_spellInfo->Effects[effIndex].MiscValueB)))
if ((player->GetRuneCooldown(l) && player->GetCurrentRune(l) == RUNE_BLOOD) && (player->GetRuneCooldown(l + 1) && player->GetCurrentRune(l + 1) == RUNE_BLOOD))
{
// Should always update the rune with the lowest cd
if (player->GetRuneCooldown(l) >= player->GetRuneCooldown(l + 1))
if (l + 1 < MAX_RUNES && player->GetRuneCooldown(l) >= player->GetRuneCooldown(l + 1))
l++;
player->SetRuneCooldown(l, 0);
player->SetGracePeriod(l, player->IsInCombat()); // xinef: reset grace period
@ -5850,6 +5839,15 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex)
}
}
for (uint32 j = 0; j < MAX_RUNES && count > 0; ++j)
{
if (player->GetRuneCooldown(j) && player->GetCurrentRune(j) == RuneType(m_spellInfo->Effects[effIndex].MiscValue))
{
player->SetRuneCooldown(j, 0);
--count;
}
}
// Empower rune weapon
if (m_spellInfo->Id == 47568)
{
@ -5859,7 +5857,7 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex)
for (uint32 i = 0; i < MAX_RUNES; ++i)
{
if (player->GetRuneCooldown(i) && (player->GetCurrentRune(i) == RUNE_FROST || player->GetCurrentRune(i) == RUNE_DEATH))
if (player->GetRuneCooldown(i) && (player->GetCurrentRune(i) == RUNE_FROST))
{
player->SetRuneCooldown(i, 0);
player->SetGracePeriod(i, player->IsInCombat()); // xinef: reset grace period
@ -6061,7 +6059,7 @@ void Spell::SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const*
int32 duration = m_spellInfo->GetDuration();
if (Player* modOwner = m_originalCaster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
modOwner->ApplySpellMod<SPELLMOD_DURATION>(m_spellInfo->Id, duration);
//TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
Map* map = caster->GetMap();

View file

@ -524,7 +524,7 @@ float SpellEffectInfo::CalcValueMultiplier(Unit* caster, Spell* spell) const
{
float multiplier = ValueMultiplier;
if (Player* modOwner = (caster ? caster->GetSpellModOwner() : nullptr))
modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_VALUE_MULTIPLIER, multiplier, spell);
modOwner->ApplySpellMod<SPELLMOD_VALUE_MULTIPLIER>(_spellInfo->Id, multiplier, spell);
return multiplier;
}
@ -532,7 +532,7 @@ float SpellEffectInfo::CalcDamageMultiplier(Unit* caster, Spell* spell) const
{
float multiplier = DamageMultiplier;
if (Player* modOwner = (caster ? caster->GetSpellModOwner() : nullptr))
modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_DAMAGE_MULTIPLIER, multiplier, spell);
modOwner->ApplySpellMod<SPELLMOD_DAMAGE_MULTIPLIER>(_spellInfo->Id, multiplier, spell);
return multiplier;
}
@ -552,7 +552,7 @@ float SpellEffectInfo::CalcRadius(Unit* caster, Spell* spell) const
radius += RadiusEntry->RadiusPerLevel * caster->getLevel();
radius = std::min(radius, RadiusEntry->RadiusMax);
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_RADIUS, radius, spell);
modOwner->ApplySpellMod<SPELLMOD_RADIUS>(_spellInfo->Id, radius, spell);
}
return radius;
@ -831,7 +831,7 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry)
SpellVisual = spellEntry->SpellVisual;
SpellIconID = spellEntry->SpellIconID;
ActiveIconID = spellEntry->ActiveIconID;
SpellPriority = spellEntry->SpellPriority;
Priority = spellEntry->SpellPriority;
SpellName = spellEntry->SpellName;
Rank = spellEntry->Rank;
MaxTargetLevel = spellEntry->MaxTargetLevel;
@ -1268,6 +1268,26 @@ bool SpellInfo::IsAutoRepeatRangedSpell() const
return AttributesEx2 & SPELL_ATTR2_AUTO_REPEAT;
}
bool SpellInfo::IsAffected(uint32 familyName, flag96 const& familyFlags) const
{
if (!familyName)
{
return true;
}
if (familyName != SpellFamilyName)
{
return false;
}
if (familyFlags && !(familyFlags & SpellFamilyFlags))
{
return false;
}
return true;
}
bool SpellInfo::IsAffectedBySpellMods() const
{
return !(AttributesEx3 & SPELL_ATTR3_IGNORE_CASTER_MODIFIERS);
@ -1292,15 +1312,7 @@ bool SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod) const
return true;
}
// False if affect_spell == nullptr or spellFamily not equal
if (affectSpell->SpellFamilyName != SpellFamilyName)
return false;
// true
if (mod->mask & SpellFamilyFlags)
return true;
return false;
return IsAffected(affectSpell->SpellFamilyName, mod->mask);
}
bool SpellInfo::CanPierceImmuneAura(SpellInfo const* aura) const
@ -2311,7 +2323,7 @@ float SpellInfo::GetMaxRange(bool positive, Unit* caster, Spell* spell) const
range = RangeEntry->RangeMax[0];
if (caster)
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(Id, SPELLMOD_RANGE, range, spell);
modOwner->ApplySpellMod<SPELLMOD_RANGE>(Id, range, spell);
return range;
}
@ -2446,7 +2458,7 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, S
// Apply cost mod by spell
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(Id, SPELLMOD_COST, powerCost, spell);
modOwner->ApplySpellMod<SPELLMOD_COST>(Id, powerCost, spell);
if (!caster->IsControlledByPlayer())
{

View file

@ -377,7 +377,7 @@ public:
std::array<uint32, 2> SpellVisual;
uint32 SpellIconID;
uint32 ActiveIconID;
uint32 SpellPriority;
uint32 Priority;
std::array<char const*, 16> SpellName;
std::array<char const*, 16> Rank;
uint32 MaxTargetLevel;
@ -463,6 +463,8 @@ public:
bool IsRangedWeaponSpell() const;
bool IsAutoRepeatRangedSpell() const;
bool IsAffected(uint32 familyName, flag96 const& familyFlags) const;
bool IsAffectedBySpellMods() const;
bool IsAffectedBySpellMod(SpellModifier const* mod) const;

View file

@ -171,7 +171,7 @@ void SpellMgr::LoadSpellInfoCorrections()
53232, // Rapid Killing (Rank 2)
}, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_FROM_PROCS; // Entries were not updated after spell effect change, we have to do that manually
spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED; // Entries were not updated after spell effect change, we have to do that manually
});
ApplySpellFix({
@ -257,7 +257,7 @@ void SpellMgr::LoadSpellInfoCorrections()
ApplySpellFix({ 57761 }, [](SpellInfo* spellInfo)
{
spellInfo->ProcCharges = 1;
spellInfo->SpellPriority = 50;
spellInfo->Priority = 50;
});
// Tidal Wave
@ -272,10 +272,10 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->AttributesEx3 |= SPELL_ATTR3_DOT_STACKING_RULE;
});
// Ascendance (Talisman of Ascendance trinket)
ApplySpellFix({ 28200 }, [](SpellInfo* spellInfo)
// Death and Decay
ApplySpellFix({ 52212 }, [](SpellInfo* spellInfo)
{
spellInfo->ProcCharges = 6;
spellInfo->AttributesEx6 |= SPELL_ATTR6_IGNORE_PHASE_SHIFT;
});
// The Eye of Acherus (no spawn in phase 2 in db)

View file

@ -727,166 +727,6 @@ void SpellMgr::GetSetOfSpellsInSpellGroupWithFlag(uint32 group_id, SpellGroupSpe
availableElixirs.insert(itr->first); // insert spell id
}
SpellProcEventEntry const* SpellMgr::GetSpellProcEvent(uint32 spellId) const
{
SpellProcEventMap::const_iterator itr = mSpellProcEventMap.find(spellId);
if (itr != mSpellProcEventMap.end())
return &itr->second;
return nullptr;
}
bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, ProcEventInfo const& eventInfo, bool active) const
{
// No extra req need
uint32 procEvent_procEx = PROC_EX_NONE;
uint32 procEvent_procPhase = PROC_SPELL_PHASE_HIT;
uint32 procFlags = eventInfo.GetTypeMask();
uint32 procExtra = eventInfo.GetHitMask();
uint32 procPhase = eventInfo.GetSpellPhaseMask();
SpellInfo const* procSpellInfo = eventInfo.GetSpellInfo();
// check prockFlags for condition
if ((procFlags & EventProcFlag) == 0)
return false;
// Xinef: Always trigger for this, including TAKEN_DAMAGE
if (EventProcFlag & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH | PROC_FLAG_TAKEN_DAMAGE))
return true;
bool hasFamilyMask = false;
if (procFlags & PROC_FLAG_DONE_PERIODIC)
{
if (procExtra & PROC_EX_INTERNAL_HOT)
{
if (EventProcFlag == PROC_FLAG_DONE_PERIODIC)
{
/// no aura with only PROC_FLAG_DONE_PERIODIC and spellFamilyName == 0 can proc from a HOT.
if (!spellProto->SpellFamilyName)
return false;
}
/// Aura must have positive procflags for a HOT to proc
else if (!(EventProcFlag & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS)))
return false;
}
/// Aura must have negative or neutral(PROC_FLAG_DONE_PERIODIC only) procflags for a DOT to proc
else if (EventProcFlag != PROC_FLAG_DONE_PERIODIC)
if (!(EventProcFlag & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG | PROC_FLAG_DONE_TRAP_ACTIVATION)))
return false;
}
if (procFlags & PROC_FLAG_TAKEN_PERIODIC)
{
if (procExtra & PROC_EX_INTERNAL_HOT)
{
/// No aura that only has PROC_FLAG_TAKEN_PERIODIC can proc from a HOT.
if (EventProcFlag == PROC_FLAG_TAKEN_PERIODIC)
return false;
/// Aura must have positive procflags for a HOT to proc
if (!(EventProcFlag & (PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS)))
return false;
}
/// Aura must have negative or neutral(PROC_FLAG_TAKEN_PERIODIC only) procflags for a DOT to proc
else if (EventProcFlag != PROC_FLAG_TAKEN_PERIODIC)
if (!(EventProcFlag & (PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG)))
return false;
}
// Trap casts are active by default
if (procFlags & PROC_FLAG_DONE_TRAP_ACTIVATION)
active = true;
if (spellProcEvent) // Exist event data
{
// Store extra req
procEvent_procEx = spellProcEvent->procEx;
procEvent_procPhase = spellProcEvent->procPhase;
// For melee triggers
if (!procSpellInfo)
{
// Check (if set) for school (melee attack have Normal school)
if (spellProcEvent->schoolMask && (spellProcEvent->schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
return false;
}
else // For spells need check school/spell family/family mask
{
// Check (if set) for school
if (spellProcEvent->schoolMask && (spellProcEvent->schoolMask & procSpellInfo->SchoolMask) == 0)
return false;
// Check (if set) for spellFamilyName
if (spellProcEvent->spellFamilyName && (spellProcEvent->spellFamilyName != procSpellInfo->SpellFamilyName))
return false;
// spellFamilyName is Ok need check for spellFamilyMask if present
if (spellProcEvent->spellFamilyMask)
{
if (!(spellProcEvent->spellFamilyMask & procSpellInfo->SpellFamilyFlags))
return false;
hasFamilyMask = true;
// Some spells are not considered as active even with have spellfamilyflags
if (!(procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL))
active = true;
}
// Check tick numbers
if (procEvent_procEx & PROC_EX_ONLY_FIRST_TICK)
{
if (Spell const* procSpell = eventInfo.GetProcSpell())
{
if (procSpell->GetTriggeredByAuraTickNumber() > 1)
{
return false;
}
}
}
}
}
if (procExtra & (PROC_EX_INTERNAL_REQ_FAMILY))
{
if (!hasFamilyMask)
return false;
}
if (!(procEvent_procPhase & procPhase))
{
return false;
}
// Check for extra req (if none) and hit/crit
if (procEvent_procEx == PROC_EX_NONE)
{
// No extra req, so can trigger only for hit/crit - spell has to be active
if ((procExtra & (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT)) && active)
return true;
}
else // Passive spells hits here only if resist/reflect/immune/evade
{
if (procExtra & AURA_SPELL_PROC_EX_MASK)
{
// if spell marked as procing only from not active spells
if (active && procEvent_procEx & PROC_EX_NOT_ACTIVE_SPELL)
return false;
// if spell marked as procing only from active spells
if (!active && procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL)
return false;
// Exist req for PROC_EX_EX_TRIGGER_ALWAYS
if (procEvent_procEx & PROC_EX_EX_TRIGGER_ALWAYS)
return true;
// PROC_EX_NOT_ACTIVE_SPELL and PROC_EX_ONLY_ACTIVE_SPELL flags handle: if passed checks before
if ((procExtra & (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT)) && ((procEvent_procEx & (AURA_SPELL_PROC_EX_MASK)) == 0))
return true;
}
// Check Extra Requirement like (hit/crit/miss/resist/parry/dodge/block/immune/reflect/absorb and other)
if (procEvent_procEx & procExtra)
return true;
}
return false;
}
SpellProcEntry const* SpellMgr::GetSpellProcEntry(uint32 spellId) const
{
SpellProcMap::const_iterator itr = mSpellProcMap.find(spellId);
@ -895,54 +735,78 @@ SpellProcEntry const* SpellMgr::GetSpellProcEntry(uint32 spellId) const
return nullptr;
}
bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const
bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo)
{
// proc type doesn't match
if (!(eventInfo.GetTypeMask() & procEntry.typeMask))
if (!(eventInfo.GetTypeMask() & procEntry.ProcFlags))
return false;
// check XP or honor target requirement
if (procEntry.attributesMask & PROC_ATTR_REQ_EXP_OR_HONOR)
if (procEntry.AttributesMask & PROC_ATTR_REQ_EXP_OR_HONOR)
if (Player* actor = eventInfo.GetActor()->ToPlayer())
if (eventInfo.GetActionTarget() && !actor->isHonorOrXPTarget(eventInfo.GetActionTarget()))
return false;
// check mana requirement
if (procEntry.AttributesMask & PROC_ATTR_REQ_MANA_COST)
if (SpellInfo const* eventSpellInfo = eventInfo.GetSpellInfo())
if (!eventSpellInfo->ManaCost && !eventSpellInfo->ManaCostPercentage)
return false;
// always trigger for these types
if (eventInfo.GetTypeMask() & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH))
return true;
// do triggered cast checks
// Do not consider autoattacks as triggered spells
if (!(procEntry.AttributesMask & PROC_ATTR_TRIGGERED_CAN_PROC) && !(eventInfo.GetTypeMask() & AUTO_ATTACK_PROC_FLAG_MASK))
{
if (Spell const* spell = eventInfo.GetProcSpell())
{
if (spell->IsTriggered())
{
SpellInfo const* spellInfo = spell->GetSpellInfo();
if (!spellInfo->HasAttribute(SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2) &&
!spellInfo->HasAttribute(SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC))
return false;
}
}
}
// check school mask (if set) for other trigger types
if (procEntry.schoolMask && !(eventInfo.GetSchoolMask() & procEntry.schoolMask))
if (procEntry.SchoolMask && !(eventInfo.GetSchoolMask() & procEntry.SchoolMask))
return false;
// check spell family name/flags (if set) for spells
if (eventInfo.GetTypeMask() & (PERIODIC_PROC_FLAG_MASK | SPELL_PROC_FLAG_MASK | PROC_FLAG_DONE_TRAP_ACTIVATION))
if (eventInfo.GetTypeMask() & (PERIODIC_PROC_FLAG_MASK | SPELL_PROC_FLAG_MASK))
{
if (procEntry.spellFamilyName && (procEntry.spellFamilyName != eventInfo.GetSpellInfo()->SpellFamilyName))
return false;
if (procEntry.spellFamilyMask && !(procEntry.spellFamilyMask & eventInfo.GetSpellInfo()->SpellFamilyFlags))
return false;
if (SpellInfo const* eventSpellInfo = eventInfo.GetSpellInfo())
{
if (!eventSpellInfo->IsAffected(procEntry.SpellFamilyName, procEntry.SpellFamilyMask))
{
return false;
}
}
}
// check spell type mask (if set)
if (eventInfo.GetTypeMask() & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK))
{
if (procEntry.spellTypeMask && !(eventInfo.GetSpellTypeMask() & procEntry.spellTypeMask))
if (procEntry.SpellTypeMask && !(eventInfo.GetSpellTypeMask() & procEntry.SpellTypeMask))
return false;
}
// check spell phase mask
if (eventInfo.GetTypeMask() & REQ_SPELL_PHASE_PROC_FLAG_MASK)
{
if (!(eventInfo.GetSpellPhaseMask() & procEntry.spellPhaseMask))
if (!(eventInfo.GetSpellPhaseMask() & procEntry.SpellPhaseMask))
return false;
}
// check hit mask (on taken hit or on done hit, but not on spell cast phase)
if ((eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK) || ((eventInfo.GetTypeMask() & DONE_HIT_PROC_FLAG_MASK) && !(eventInfo.GetSpellPhaseMask() & PROC_SPELL_PHASE_CAST)))
{
uint32 hitMask = procEntry.hitMask;
uint32 hitMask = procEntry.HitMask;
// get default values if hit mask not set
if (!hitMask)
{
@ -1733,111 +1597,17 @@ void SpellMgr::LoadSpellGroupStackRules()
LOG_INFO("server.loading", " ");
}
void SpellMgr::LoadSpellProcEvents()
{
uint32 oldMSTime = getMSTime();
mSpellProcEventMap.clear(); // need for reload case
// 0 1 2 3 4 5 6 7 8 9 10 11
QueryResult result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, procFlags, procEx, procPhase, ppmRate, CustomChance, Cooldown FROM spell_proc_event");
if (!result)
{
LOG_WARN("server.loading", ">> Loaded 0 spell proc event conditions. DB table `spell_proc_event` is empty.");
return;
}
uint32 count = 0;
do
{
Field* fields = result->Fetch();
int32 spellId = fields[0].Get<int32>();
bool allRanks = false;
if (spellId < 0)
{
allRanks = true;
spellId = -spellId;
}
SpellInfo const* spellInfo = GetSpellInfo(spellId);
if (!spellInfo)
{
LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` does not exist", spellId);
continue;
}
if (allRanks)
{
if (!spellInfo->IsRanked())
LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` with all ranks, but spell has no ranks.", spellId);
if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId))
{
LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` is not first rank of spell.", spellId);
continue;
}
}
SpellProcEventEntry spellProcEvent;
spellProcEvent.schoolMask = fields[1].Get<int8>();
spellProcEvent.spellFamilyName = fields[2].Get<uint16>();
spellProcEvent.spellFamilyMask[0] = fields[3].Get<uint32>();
spellProcEvent.spellFamilyMask[1] = fields[4].Get<uint32>();
spellProcEvent.spellFamilyMask[2] = fields[5].Get<uint32>();
spellProcEvent.procFlags = fields[6].Get<uint32>();
spellProcEvent.procEx = fields[7].Get<uint32>();
spellProcEvent.procPhase = fields[8].Get<uint32>();
spellProcEvent.ppmRate = fields[9].Get<float>();
spellProcEvent.customChance = fields[10].Get<float>();
spellProcEvent.cooldown = fields[11].Get<uint32>();
// PROC_SPELL_PHASE_NONE is by default PROC_SPELL_PHASE_HIT
if (spellProcEvent.procPhase == PROC_SPELL_PHASE_NONE)
{
spellProcEvent.procPhase = PROC_SPELL_PHASE_HIT;
}
while (spellInfo)
{
if (mSpellProcEventMap.find(spellInfo->Id) != mSpellProcEventMap.end())
{
LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` already has its first rank in table.", spellInfo->Id);
break;
}
if (!spellInfo->ProcFlags && !spellProcEvent.procFlags)
LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` probally not triggered spell", spellInfo->Id);
mSpellProcEventMap[spellInfo->Id] = spellProcEvent;
if (allRanks)
spellInfo = spellInfo->GetNextRankSpell();
else
break;
}
++count;
} while (result->NextRow());
LOG_INFO("server.loading", ">> Loaded {} Extra Spell Proc Event Conditions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
}
void SpellMgr::LoadSpellProcs()
{
uint32 oldMSTime = getMSTime();
mSpellProcMap.clear(); // need for reload case
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
QueryResult result = WorldDatabase.Query("SELECT spellId, schoolMask, spellFamilyName, spellFamilyMask0, spellFamilyMask1, spellFamilyMask2, typeMask, spellTypeMask, spellPhaseMask, hitMask, attributesMask, ratePerMinute, chance, cooldown, charges FROM spell_proc");
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
QueryResult result = WorldDatabase.Query("SELECT SpellId, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, ProcFlags, SpellTypeMask, SpellPhaseMask, HitMask, AttributesMask, ProcsPerMinute, Chance, Cooldown, Charges FROM spell_proc");
if (!result)
{
LOG_WARN("server.loading", ">> Loaded 0 Spell Proc Conditions And Data. DB table `spell_proc` Is Empty.");
LOG_INFO("server.loading", ">> Loaded 0 spell proc conditions and data. DB table `spell_proc` is empty.");
LOG_INFO("server.loading", " ");
return;
}
@ -1874,21 +1644,20 @@ void SpellMgr::LoadSpellProcs()
SpellProcEntry baseProcEntry;
baseProcEntry.schoolMask = fields[1].Get<int8>();
baseProcEntry.spellFamilyName = fields[2].Get<uint16>();
baseProcEntry.spellFamilyMask[0] = fields[3].Get<uint32>();
baseProcEntry.spellFamilyMask[1] = fields[4].Get<uint32>();
baseProcEntry.spellFamilyMask[2] = fields[5].Get<uint32>();
baseProcEntry.typeMask = fields[6].Get<uint32>();
baseProcEntry.spellTypeMask = fields[7].Get<uint32>();
baseProcEntry.spellPhaseMask = fields[8].Get<uint32>();
baseProcEntry.hitMask = fields[9].Get<uint32>();
baseProcEntry.attributesMask = fields[10].Get<uint32>();
baseProcEntry.ratePerMinute = fields[11].Get<float>();
baseProcEntry.chance = fields[12].Get<float>();
float cooldown = fields[13].Get<float>();
baseProcEntry.cooldown = uint32(cooldown);
baseProcEntry.charges = fields[14].Get<uint32>();
baseProcEntry.SchoolMask = fields[1].Get<int8>();
baseProcEntry.SpellFamilyName = fields[2].Get<uint16>();
baseProcEntry.SpellFamilyMask[0] = fields[3].Get<uint32>();
baseProcEntry.SpellFamilyMask[1] = fields[4].Get<uint32>();
baseProcEntry.SpellFamilyMask[2] = fields[5].Get<uint32>();
baseProcEntry.ProcFlags = fields[6].Get<uint32>();
baseProcEntry.SpellTypeMask = fields[7].Get<uint32>();
baseProcEntry.SpellPhaseMask = fields[8].Get<uint32>();
baseProcEntry.HitMask = fields[9].Get<uint32>();
baseProcEntry.AttributesMask = fields[10].Get<uint32>();
baseProcEntry.ProcsPerMinute = fields[11].Get<float>();
baseProcEntry.Chance = fields[12].Get<float>();
baseProcEntry.Cooldown = Milliseconds(fields[13].Get<uint32>());
baseProcEntry.Charges = fields[14].Get<uint8>();
while (spellInfo)
{
@ -1900,56 +1669,54 @@ void SpellMgr::LoadSpellProcs()
SpellProcEntry procEntry = SpellProcEntry(baseProcEntry);
// take defaults from dbcs
if (!procEntry.typeMask)
procEntry.typeMask = spellInfo->ProcFlags;
if (!procEntry.charges)
procEntry.charges = spellInfo->ProcCharges;
if (!procEntry.chance && !procEntry.ratePerMinute)
procEntry.chance = float(spellInfo->ProcChance);
if (!procEntry.ProcFlags)
procEntry.ProcFlags = spellInfo->ProcFlags;
if (!procEntry.Charges)
procEntry.Charges = spellInfo->ProcCharges;
if (!procEntry.Chance && !procEntry.ProcsPerMinute)
procEntry.Chance = float(spellInfo->ProcChance);
// validate data
if (procEntry.schoolMask & ~SPELL_SCHOOL_MASK_ALL)
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `schoolMask` set: {}", spellId, procEntry.schoolMask);
if (procEntry.spellFamilyName && (procEntry.spellFamilyName < 3 || procEntry.spellFamilyName > 17 || procEntry.spellFamilyName == 14 || procEntry.spellFamilyName == 16))
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `spellFamilyName` set: {}", spellId, procEntry.spellFamilyName);
if (procEntry.chance < 0)
if (procEntry.SchoolMask & ~SPELL_SCHOOL_MASK_ALL)
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SchoolMask` set: {}", spellId, procEntry.SchoolMask);
if (procEntry.SpellFamilyName && (procEntry.SpellFamilyName < 3 || procEntry.SpellFamilyName > 17 || procEntry.SpellFamilyName == 14 || procEntry.SpellFamilyName == 16))
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SpellFamilyName` set: {}", spellId, procEntry.SpellFamilyName);
if (procEntry.Chance < 0)
{
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in `chance` field", spellId);
procEntry.chance = 0;
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has negative value in `Chance` field", spellId);
procEntry.Chance = 0;
}
if (procEntry.ratePerMinute < 0)
if (procEntry.ProcsPerMinute < 0)
{
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in `ratePerMinute` field", spellId);
procEntry.ratePerMinute = 0;
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has negative value in `ProcsPerMinute` field", spellId);
procEntry.ProcsPerMinute = 0;
}
if (cooldown < 0)
if (procEntry.Chance == 0 && procEntry.ProcsPerMinute == 0)
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} doesn't have `Chance` and `ProcsPerMinute` values defined, proc will not be triggered", spellId);
if (procEntry.Charges > 99)
{
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in `cooldown` field", spellId);
procEntry.cooldown = 0;
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has too big value in `Charges` field", spellId);
procEntry.Charges = 99;
}
if (procEntry.chance == 0 && procEntry.ratePerMinute == 0)
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} doesn't have `chance` and `ratePerMinute` values defined, proc will not be triggered", spellId);
if (procEntry.charges > 99)
{
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has too big value in `charges` field", spellId);
procEntry.charges = 99;
}
if (!procEntry.typeMask)
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} doesn't have `typeMask` value defined, proc will not be triggered", spellId);
if (procEntry.spellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL)
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `spellTypeMask` set: {}", spellId, procEntry.spellTypeMask);
if (procEntry.spellTypeMask && !(procEntry.typeMask & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK)))
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has `spellTypeMask` value defined, but it won't be used for defined `typeMask` value", spellId);
if (!procEntry.spellPhaseMask && procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK)
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} doesn't have `spellPhaseMask` value defined, but it's required for defined `typeMask` value, proc will not be triggered", spellId);
if (procEntry.spellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL)
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `spellPhaseMask` set: {}", spellId, procEntry.spellPhaseMask);
if (procEntry.spellPhaseMask && !(procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK))
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has `spellPhaseMask` value defined, but it won't be used for defined `typeMask` value", spellId);
if (procEntry.hitMask & ~PROC_HIT_MASK_ALL)
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `hitMask` set: {}", spellId, procEntry.hitMask);
if (procEntry.hitMask && !(procEntry.typeMask & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.typeMask & DONE_HIT_PROC_FLAG_MASK && (!procEntry.spellPhaseMask || procEntry.spellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH)))))
LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has `hitMask` value defined, but it won't be used for defined `typeMask` and `spellPhaseMask` values", spellId);
if (!procEntry.ProcFlags)
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} doesn't have `ProcFlags` value defined, proc will not be triggered", spellId);
if (procEntry.SpellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL)
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SpellTypeMask` set: {}", spellId, procEntry.SpellTypeMask);
if (procEntry.SpellTypeMask && !(procEntry.ProcFlags & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK)))
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has `SpellTypeMask` value defined, but it won't be used for defined `ProcFlags` value", spellId);
if (!procEntry.SpellPhaseMask && procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK)
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} doesn't have `SpellPhaseMask` value defined, but it's required for defined `ProcFlags` value, proc will not be triggered", spellId);
if (procEntry.SpellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL)
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SpellPhaseMask` set: {}", spellId, procEntry.SpellPhaseMask);
if (procEntry.SpellPhaseMask && !(procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK))
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has `SpellPhaseMask` value defined, but it won't be used for defined `ProcFlags` value", spellId);
if (procEntry.HitMask & ~PROC_HIT_MASK_ALL)
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `HitMask` set: {}", spellId, procEntry.HitMask);
if (procEntry.HitMask && !(procEntry.ProcFlags & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.ProcFlags & DONE_HIT_PROC_FLAG_MASK && (!procEntry.SpellPhaseMask || procEntry.SpellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH)))))
LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has `HitMask` value defined, but it won't be used for defined `ProcFlags` and `SpellPhaseMask` values", spellId);
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if ((procEntry.AttributesMask & (PROC_ATTR_DISABLE_EFF_0 << i)) && !spellInfo->Effects[i].IsAura())
LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId {} has Attribute PROC_ATTR_DISABLE_EFF_{}, but effect {} is not an aura effect", spellInfo->Id, static_cast<uint32>(i), static_cast<uint32>(i));
mSpellProcMap[spellInfo->Id] = procEntry;
@ -1961,8 +1728,175 @@ void SpellMgr::LoadSpellProcs()
++count;
} while (result->NextRow());
LOG_INFO("server.loading", ">> Loaded {} spell proc conditions and data in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", ">> Loaded {} Extra Spell Proc Event Conditions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
// Define can trigger auras
bool isTriggerAura[TOTAL_AURAS];
// Triggered always, even from triggered spells
bool isAlwaysTriggeredAura[TOTAL_AURAS];
// SpellTypeMask to add to the proc
uint32 spellTypeMask[TOTAL_AURAS];
// List of auras that CAN trigger but may not exist in spell_proc
// in most cases needed to drop charges
// some aura types need additional checks (eg SPELL_AURA_MECHANIC_IMMUNITY needs mechanic check)
// see AuraEffect::CheckEffectProc
for (uint16 i = 0; i < TOTAL_AURAS; ++i)
{
isTriggerAura[i] = false;
isAlwaysTriggeredAura[i] = false;
spellTypeMask[i] = PROC_SPELL_TYPE_MASK_ALL;
}
isTriggerAura[SPELL_AURA_DUMMY] = true; // Most dummy auras should require scripting, but there are some exceptions (ie 12311)
isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true; // "Any direct damaging attack will revive targets"
isTriggerAura[SPELL_AURA_MOD_THREAT] = true; // Only one spell: 28762 part of Mage T3 8p bonus
isTriggerAura[SPELL_AURA_MOD_STUN] = true; // Aura does not have charges but needs to be removed on trigger
isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true;
isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true;
isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true;
isTriggerAura[SPELL_AURA_MOD_STEALTH] = true;
isTriggerAura[SPELL_AURA_MOD_FEAR] = true; // Aura does not have charges but needs to be removed on trigger
isTriggerAura[SPELL_AURA_MOD_ROOT] = true;
isTriggerAura[SPELL_AURA_TRANSFORM] = true;
isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true;
isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true;
isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true;
isTriggerAura[SPELL_AURA_PROC_TRIGGER_DAMAGE] = true;
isTriggerAura[SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK] = true;
isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT] = true;
isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL] = true;
isTriggerAura[SPELL_AURA_REFLECT_SPELLS_SCHOOL] = true;
isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN] = true;
isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER] = true;
isTriggerAura[SPELL_AURA_ADD_CASTER_HIT_TRIGGER] = true;
isTriggerAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
isTriggerAura[SPELL_AURA_MOD_MELEE_HASTE] = true;
isTriggerAura[SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE] = true;
isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE] = true;
isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE] = true;
isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true;
isTriggerAura[SPELL_AURA_MOD_SPELL_CRIT_CHANCE] = true;
isTriggerAura[SPELL_AURA_ADD_FLAT_MODIFIER] = true;
isTriggerAura[SPELL_AURA_ADD_PCT_MODIFIER] = true;
isTriggerAura[SPELL_AURA_ABILITY_IGNORE_AURASTATE] = true;
isAlwaysTriggeredAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
isAlwaysTriggeredAura[SPELL_AURA_MOD_STEALTH] = true;
isAlwaysTriggeredAura[SPELL_AURA_MOD_CONFUSE] = true;
isAlwaysTriggeredAura[SPELL_AURA_MOD_FEAR] = true;
isAlwaysTriggeredAura[SPELL_AURA_MOD_ROOT] = true;
isAlwaysTriggeredAura[SPELL_AURA_MOD_STUN] = true;
isAlwaysTriggeredAura[SPELL_AURA_TRANSFORM] = true;
spellTypeMask[SPELL_AURA_MOD_STEALTH] = PROC_SPELL_TYPE_DAMAGE | PROC_SPELL_TYPE_NO_DMG_HEAL;
spellTypeMask[SPELL_AURA_MOD_CONFUSE] = PROC_SPELL_TYPE_DAMAGE;
spellTypeMask[SPELL_AURA_MOD_FEAR] = PROC_SPELL_TYPE_DAMAGE;
spellTypeMask[SPELL_AURA_MOD_ROOT] = PROC_SPELL_TYPE_DAMAGE;
spellTypeMask[SPELL_AURA_MOD_STUN] = PROC_SPELL_TYPE_DAMAGE;
spellTypeMask[SPELL_AURA_TRANSFORM] = PROC_SPELL_TYPE_DAMAGE;
// This generates default procs to retain compatibility with previous proc system
LOG_INFO("server.loading", "Generating spell proc data from SpellMap...");
count = 0;
oldMSTime = getMSTime();
for (SpellInfo const* spellInfo : mSpellInfoMap)
{
if (!spellInfo)
continue;
// Data already present in DB, overwrites default proc
if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end())
continue;
// Nothing to do if no flags set
if (!spellInfo->ProcFlags)
continue;
bool addTriggerFlag = false;
uint32 procSpellTypeMask = PROC_SPELL_TYPE_NONE;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
if (!spellInfo->Effects[i].IsEffect())
continue;
uint32 auraName = spellInfo->Effects[i].ApplyAuraName;
if (!auraName)
continue;
if (!isTriggerAura[auraName])
continue;
procSpellTypeMask |= spellTypeMask[auraName];
if (isAlwaysTriggeredAura[auraName])
addTriggerFlag = true;
// many proc auras with taken procFlag mask don't have attribute "can proc with triggered"
// they should proc nevertheless (example mage armor spells with judgement)
if (!addTriggerFlag && (spellInfo->ProcFlags & TAKEN_HIT_PROC_FLAG_MASK) != 0)
{
switch (auraName)
{
case SPELL_AURA_PROC_TRIGGER_SPELL:
case SPELL_AURA_PROC_TRIGGER_DAMAGE:
addTriggerFlag = true;
break;
default:
break;
}
}
break;
}
if (!procSpellTypeMask)
continue;
SpellProcEntry procEntry;
procEntry.SchoolMask = 0;
procEntry.ProcFlags = spellInfo->ProcFlags;
procEntry.SpellFamilyName = 0;
for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if (spellInfo->Effects[i].IsEffect() && isTriggerAura[spellInfo->Effects[i].ApplyAuraName])
procEntry.SpellFamilyMask |= spellInfo->Effects[i].SpellClassMask;
if (procEntry.SpellFamilyMask)
procEntry.SpellFamilyName = spellInfo->SpellFamilyName;
procEntry.SpellTypeMask = procSpellTypeMask;
procEntry.SpellPhaseMask = PROC_SPELL_PHASE_HIT;
procEntry.HitMask = PROC_HIT_NONE; // uses default proc @see SpellMgr::CanSpellTriggerProcOnEvent
// Reflect auras should only proc off reflects
for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
if (spellInfo->Effects[i].IsAura(SPELL_AURA_REFLECT_SPELLS) || spellInfo->Effects[i].IsAura(SPELL_AURA_REFLECT_SPELLS_SCHOOL))
{
procEntry.HitMask = PROC_HIT_REFLECT;
break;
}
}
procEntry.AttributesMask = 0;
if (spellInfo->ProcFlags & PROC_FLAG_KILL)
procEntry.AttributesMask |= PROC_ATTR_REQ_EXP_OR_HONOR;
if (addTriggerFlag)
procEntry.AttributesMask |= PROC_ATTR_TRIGGERED_CAN_PROC;
procEntry.ProcsPerMinute = 0;
procEntry.Chance = spellInfo->ProcChance;
procEntry.Cooldown = Milliseconds::zero();
procEntry.Charges = spellInfo->ProcCharges;
mSpellProcMap[spellInfo->Id] = procEntry;
++count;
}
LOG_INFO("server.loading", ">> Generated spell proc data for {} spells in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
}
void SpellMgr::LoadSpellBonuses()

View file

@ -154,13 +154,15 @@ enum ProcFlags
| PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS,
SPELL_PROC_FLAG_MASK = PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_MELEE_DMG_CLASS
| PROC_FLAG_DONE_RANGED_AUTO_ATTACK | PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK
| PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS
| PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS
| PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG
| PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS
| PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG,
| PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG
| PROC_FLAG_DONE_TRAP_ACTIVATION,
SPELL_CAST_PROC_FLAG_MASK = SPELL_PROC_FLAG_MASK | PROC_FLAG_DONE_TRAP_ACTIVATION | RANGED_PROC_FLAG_MASK,
SPELL_CAST_PROC_FLAG_MASK = SPELL_PROC_FLAG_MASK | PROC_FLAG_DONE_TRAP_ACTIVATION,
PERIODIC_PROC_FLAG_MASK = PROC_FLAG_DONE_PERIODIC | PROC_FLAG_TAKEN_PERIODIC,
@ -168,7 +170,8 @@ enum ProcFlags
| PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS | PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS
| PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG
| PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG
| PROC_FLAG_DONE_PERIODIC | PROC_FLAG_DONE_MAINHAND_ATTACK | PROC_FLAG_DONE_OFFHAND_ATTACK,
| PROC_FLAG_DONE_PERIODIC | PROC_FLAG_DONE_TRAP_ACTIVATION
| PROC_FLAG_DONE_MAINHAND_ATTACK | PROC_FLAG_DONE_OFFHAND_ATTACK,
TAKEN_HIT_PROC_FLAG_MASK = PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK | PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK
| PROC_FLAG_TAKEN_SPELL_MELEE_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS
@ -188,46 +191,6 @@ enum ProcFlags
PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | \
PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS)
enum ProcFlagsExLegacy
{
PROC_EX_NONE = 0x0000000, // If none can tigger on Hit/Crit only (passive spells MUST defined by SpellFamily flag)
PROC_EX_NORMAL_HIT = 0x0000001, // If set only from normal hit (only damage spells)
PROC_EX_CRITICAL_HIT = 0x0000002,
PROC_EX_MISS = 0x0000004,
PROC_EX_RESIST = 0x0000008,
PROC_EX_DODGE = 0x0000010,
PROC_EX_PARRY = 0x0000020,
PROC_EX_BLOCK = 0x0000040,
PROC_EX_EVADE = 0x0000080,
PROC_EX_IMMUNE = 0x0000100,
PROC_EX_DEFLECT = 0x0000200,
PROC_EX_ABSORB = 0x0000400,
PROC_EX_REFLECT = 0x0000800,
PROC_EX_INTERRUPT = 0x0001000, // Melee hit result can be Interrupt (not used)
PROC_EX_FULL_BLOCK = 0x0002000, // block all attack damage
PROC_EX_RESERVED2 = 0x0004000,
PROC_EX_NOT_ACTIVE_SPELL = 0x0008000, // Spell mustn't do damage/heal to proc
PROC_EX_EX_TRIGGER_ALWAYS = 0x0010000, // If set trigger always no matter of hit result
PROC_EX_EX_ONE_TIME_TRIGGER = 0x0020000, // If set trigger always but only one time (not implemented yet)
PROC_EX_ONLY_ACTIVE_SPELL = 0x0040000, // Spell has to do damage/heal to proc
PROC_EX_NO_OVERHEAL = 0x0080000, // Proc if heal did some work
PROC_EX_NO_AURA_REFRESH = 0x0100000, // Proc if aura was not refreshed
PROC_EX_ONLY_FIRST_TICK = 0x0200000, // Proc only on first tick (in case of periodic spells)
// Flags for internal use - do not use these in db!
PROC_EX_INTERNAL_CANT_PROC = 0x0800000,
PROC_EX_INTERNAL_DOT = 0x1000000,
PROC_EX_INTERNAL_HOT = 0x2000000,
PROC_EX_INTERNAL_TRIGGERED = 0x4000000,
PROC_EX_INTERNAL_REQ_FAMILY = 0x8000000
};
#define AURA_SPELL_PROC_EX_MASK \
(PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT | PROC_EX_MISS | \
PROC_EX_RESIST | PROC_EX_DODGE | PROC_EX_PARRY | PROC_EX_BLOCK | \
PROC_EX_EVADE | PROC_EX_IMMUNE | PROC_EX_DEFLECT | \
PROC_EX_ABSORB | PROC_EX_REFLECT | PROC_EX_INTERRUPT)
enum ProcFlagsSpellType
{
PROC_SPELL_TYPE_NONE = 0x0000000,
@ -261,45 +224,37 @@ enum ProcFlagsHit
PROC_HIT_DEFLECT = 0x0000200,
PROC_HIT_ABSORB = 0x0000400, // partial or full absorb
PROC_HIT_REFLECT = 0x0000800,
PROC_HIT_INTERRUPT = 0x0001000, // (not used atm)
PROC_HIT_INTERRUPT = 0x0001000,
PROC_HIT_FULL_BLOCK = 0x0002000,
PROC_HIT_MASK_ALL = 0x2FFF,
PROC_HIT_MASK_ALL = 0x0002FFF,
};
enum ProcAttributes
{
PROC_ATTR_REQ_EXP_OR_HONOR = 0x0000010,
};
PROC_ATTR_REQ_EXP_OR_HONOR = 0x0000001, // requires proc target to give exp or honor for aura proc
PROC_ATTR_TRIGGERED_CAN_PROC = 0x0000002, // aura can proc even with triggered spells
PROC_ATTR_REQ_MANA_COST = 0x0000004, // requires triggering spell to have a mana cost for aura proc
PROC_ATTR_REQ_SPELLMOD = 0x0000008, // requires triggering spell to be affected by proccing aura to drop charges
struct SpellProcEventEntry
{
uint32 schoolMask; // if nonzero - bit mask for matching proc condition based on spell candidate's school: Fire=2, Mask=1<<(2-1)=2
uint32 spellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyNamer value
flag96 spellFamilyMask; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyFlags (like auras 107 and 108 do)
uint32 procFlags; // bitmask for matching proc event
uint32 procEx; // proc Extend info (see ProcFlagsEx)
uint32 procPhase; // proc phase (see ProcFlagsSpellPhase)
float ppmRate; // for melee (ranged?) damage spells - proc rate per minute. if zero, falls back to flat chance from Spell.dbc
float customChance; // Owerride chance (in most cases for debug only)
uint32 cooldown; // hidden cooldown used for some spell proc events, applied to _triggered_spell_
PROC_ATTR_DISABLE_EFF_0 = 0x0000010, // explicitly disables aura proc from effects, USE ONLY IF 100% SURE AURA SHOULDN'T PROC
PROC_ATTR_DISABLE_EFF_1 = 0x0000020, // used to avoid a console error if the spell has invalid trigger spell and handled elsewhere
PROC_ATTR_DISABLE_EFF_2 = 0x0000040 // or handling not needed
};
typedef std::unordered_map<uint32, SpellProcEventEntry> SpellProcEventMap;
struct SpellProcEntry
{
uint32 schoolMask; // if nonzero - bitmask for matching proc condition based on spell's school
uint32 spellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyName
flag96 spellFamilyMask; // if nonzero - bitmask for matching proc condition based on candidate spell's SpellFamilyFlags
uint32 typeMask; // if nonzero - owerwrite procFlags field for given Spell.dbc entry, bitmask for matching proc condition, see enum ProcFlags
uint32 spellTypeMask; // if nonzero - bitmask for matching proc condition based on candidate spell's damage/heal effects, see enum ProcFlagsSpellType
uint32 spellPhaseMask; // if nonzero - bitmask for matching phase of a spellcast on which proc occurs, see enum ProcFlagsSpellPhase
uint32 hitMask; // if nonzero - bitmask for matching proc condition based on hit result, see enum ProcFlagsHit
uint32 attributesMask; // bitmask, see ProcAttributes
float ratePerMinute; // if nonzero - chance to proc is equal to value * aura caster's weapon speed / 60
float chance; // if nonzero - owerwrite procChance field for given Spell.dbc entry, defines chance of proc to occur, not used if perMinuteRate set
uint32 cooldown; // if nonzero - cooldown in secs for aura proc, applied to aura
uint32 charges; // if nonzero - owerwrite procCharges field for given Spell.dbc entry, defines how many times proc can occur before aura remove, 0 - infinite
uint32 SchoolMask; // if nonzero - bitmask for matching proc condition based on spell's school
uint32 SpellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyName
flag96 SpellFamilyMask; // if nonzero - bitmask for matching proc condition based on candidate spell's SpellFamilyFlags
uint32 ProcFlags; // if nonzero - owerwrite procFlags field for given Spell.dbc entry, bitmask for matching proc condition, see enum ProcFlags
uint32 SpellTypeMask; // if nonzero - bitmask for matching proc condition based on candidate spell's damage/heal effects, see enum ProcFlagsSpellType
uint32 SpellPhaseMask; // if nonzero - bitmask for matching phase of a spellcast on which proc occurs, see enum ProcFlagsSpellPhase
uint32 HitMask; // if nonzero - bitmask for matching proc condition based on hit result, see enum ProcFlagsHit
uint32 AttributesMask; // bitmask, see ProcAttributes
float ProcsPerMinute; // if nonzero - chance to proc is equal to value * aura caster's weapon speed / 60
float Chance; // if nonzero - owerwrite procChance field for given Spell.dbc entry, defines chance of proc to occur, not used if perMinuteRate set
Milliseconds Cooldown; // if nonzero - cooldown in secs for aura proc, applied to aura
uint32 Charges; // if nonzero - owerwrite procCharges field for given Spell.dbc entry, defines how many times proc can occur before aura remove, 0 - infinite
};
typedef std::unordered_map<uint32, SpellProcEntry> SpellProcMap;
@ -669,13 +624,9 @@ public:
SpellGroupStackFlags CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2, bool remove, bool areaAura) const;
void GetSetOfSpellsInSpellGroupWithFlag(uint32 group_id, SpellGroupSpecialFlags flag, std::set<uint32>& availableElixirs) const;
// Spell proc event table
[[nodiscard]] SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const;
bool IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, ProcEventInfo const& eventInfo, bool active) const;
// Spell proc table
[[nodiscard]] SpellProcEntry const* GetSpellProcEntry(uint32 spellId) const;
bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const;
static bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo);
// Spell bonus data table
[[nodiscard]] SpellBonusEntry const* GetSpellBonusData(uint32 spellId) const;
@ -750,7 +701,6 @@ public:
void LoadSpellTargetPositions();
void LoadSpellGroups();
void LoadSpellGroupStackRules();
void LoadSpellProcEvents();
void LoadSpellProcs();
void LoadSpellBonuses();
void LoadSpellThreats();
@ -779,7 +729,6 @@ private:
SpellTargetPositionMap mSpellTargetPositions;
SpellGroupMap mSpellGroupMap;
SpellGroupStackMap mSpellGroupStackMap;
SpellProcEventMap mSpellProcEventMap;
SpellProcMap mSpellProcMap;
SpellBonusMap mSpellBonusMap;
SpellThreatMap mSpellThreatMap;

View file

@ -733,6 +733,9 @@ bool AuraScript::_Validate(SpellInfo const* entry)
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
LOG_ERROR("spells.scripts", "Spell `{}` of script `{}` does not have apply aura effect - handler bound to hook `DoCheckProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
for (std::list<CheckEffectProcHandler>::iterator itr = DoCheckEffectProc.begin(); itr != DoCheckEffectProc.end(); ++itr)
if (!itr->GetAffectedEffectsMask(entry))
LOG_ERROR("spells.scripts", "Spell `{}` Effect `{}` of script `{}` did not match dbc effect data - handler bound to hook `DoCheckEffectProc` of AuraScript won't be executed", entry->Id, (*itr).ToString(), m_scriptName->c_str());
for (std::list<CheckProcHandler>::iterator itr = DoCheckAfterProc.begin(); itr != DoCheckAfterProc.end(); ++itr)
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
LOG_ERROR("spells.scripts", "Spell `{}` of script `{}` does not have apply aura effect - handler bound to hook `DoCheckAfterProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
@ -906,6 +909,17 @@ bool AuraScript::CheckProcHandler::Call(AuraScript* auraScript, ProcEventInfo& e
return (auraScript->*_HandlerScript)(eventInfo);
}
AuraScript::CheckEffectProcHandler::CheckEffectProcHandler(AuraCheckEffectProcFnType handlerScript, uint8 effIndex, uint16 effName)
: AuraScript::EffectBase(effIndex, effName)
{
_HandlerScript = handlerScript;
}
bool AuraScript::CheckEffectProcHandler::Call(AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
return (auraScript->*_HandlerScript)(aurEff, eventInfo);
}
AuraScript::AuraProcHandler::AuraProcHandler(AuraProcFnType handlerScript)
{
_HandlerScript = handlerScript;
@ -1167,6 +1181,7 @@ Unit* AuraScript::GetTarget() const
case AURA_SCRIPT_HOOK_EFFECT_AFTER_MANASHIELD:
case AURA_SCRIPT_HOOK_EFFECT_SPLIT:
case AURA_SCRIPT_HOOK_CHECK_PROC:
case AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC:
case AURA_SCRIPT_HOOK_CHECK_AFTER_PROC:
case AURA_SCRIPT_HOOK_PREPARE_PROC:
case AURA_SCRIPT_HOOK_PROC:

View file

@ -499,6 +499,7 @@ enum AuraScriptHookType
AURA_SCRIPT_HOOK_AFTER_DISPEL,
// Spell Proc Hooks
AURA_SCRIPT_HOOK_CHECK_PROC,
AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC,
AURA_SCRIPT_HOOK_CHECK_AFTER_PROC,
AURA_SCRIPT_HOOK_PREPARE_PROC,
AURA_SCRIPT_HOOK_PROC,
@ -529,7 +530,8 @@ public:
typedef void(CLASSNAME::*AuraEffectCalcSpellModFnType)(AuraEffect const*, SpellModifier* &); \
typedef void(CLASSNAME::*AuraEffectAbsorbFnType)(AuraEffect*, DamageInfo &, uint32 &); \
typedef void(CLASSNAME::*AuraEffectSplitFnType)(AuraEffect*, DamageInfo &, uint32 &); \
typedef bool(CLASSNAME::*AuraCheckProcFnType)(ProcEventInfo&); \
typedef bool(CLASSNAME::*AuraCheckProcFnType)(ProcEventInfo&); \
typedef bool(CLASSNAME::*AuraCheckEffectProcFnType)(AuraEffect const*, ProcEventInfo&); \
typedef void(CLASSNAME::*AuraProcFnType)(ProcEventInfo&); \
typedef void(CLASSNAME::*AuraEffectProcFnType)(AuraEffect const*, ProcEventInfo&); \
@ -639,6 +641,14 @@ public:
private:
AuraCheckProcFnType _HandlerScript;
};
class CheckEffectProcHandler : public EffectBase
{
public:
CheckEffectProcHandler(AuraCheckEffectProcFnType handlerScript, uint8 effIndex, uint16 effName);
bool Call(AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo);
private:
AuraCheckEffectProcFnType _HandlerScript;
};
class AuraProcHandler
{
public:
@ -668,8 +678,9 @@ public:
class EffectAbsorbFunction : public AuraScript::EffectAbsorbHandler { public: EffectAbsorbFunction(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectAbsorbHandler((AuraScript::AuraEffectAbsorbFnType)_pEffectHandlerScript, _effIndex) {} }; \
class EffectManaShieldFunction : public AuraScript::EffectManaShieldHandler { public: EffectManaShieldFunction(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectManaShieldHandler((AuraScript::AuraEffectAbsorbFnType)_pEffectHandlerScript, _effIndex) {} }; \
class EffectSplitFunction : public AuraScript::EffectSplitHandler { public: EffectSplitFunction(AuraEffectSplitFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectSplitHandler((AuraScript::AuraEffectSplitFnType)_pEffectHandlerScript, _effIndex) {} }; \
class CheckProcHandlerFunction : public AuraScript::CheckProcHandler { public: CheckProcHandlerFunction(AuraCheckProcFnType handlerScript) : AuraScript::CheckProcHandler((AuraScript::AuraCheckProcFnType)handlerScript) {} }; \
class AuraProcHandlerFunction : public AuraScript::AuraProcHandler { public: AuraProcHandlerFunction(AuraProcFnType handlerScript) : AuraScript::AuraProcHandler((AuraScript::AuraProcFnType)handlerScript) {} }; \
class CheckProcHandlerFunction : public AuraScript::CheckProcHandler { public: CheckProcHandlerFunction(AuraCheckProcFnType handlerScript) : AuraScript::CheckProcHandler((AuraScript::AuraCheckProcFnType)handlerScript) {} }; \
class CheckEffectProcHandlerFunction : public AuraScript::CheckEffectProcHandler { public: CheckEffectProcHandlerFunction(AuraCheckEffectProcFnType handlerScript, uint8 effIndex, uint16 effName) : AuraScript::CheckEffectProcHandler((AuraScript::AuraCheckEffectProcFnType)handlerScript, effIndex, effName) { } }; \
class AuraProcHandlerFunction : public AuraScript::AuraProcHandler { public: AuraProcHandlerFunction(AuraProcFnType handlerScript) : AuraScript::AuraProcHandler((AuraScript::AuraProcFnType)handlerScript) {} }; \
class EffectProcHandlerFunction : public AuraScript::EffectProcHandler { public: EffectProcHandlerFunction(AuraEffectProcFnType effectHandlerScript, uint8 effIndex, uint16 effName) : AuraScript::EffectProcHandler((AuraScript::AuraEffectProcFnType)effectHandlerScript, effIndex, effName) {} }; \
#define PrepareAuraScript(CLASSNAME) AURASCRIPT_FUNCTION_TYPE_DEFINES(CLASSNAME) AURASCRIPT_FUNCTION_CAST_DEFINES(CLASSNAME)
@ -811,6 +822,12 @@ public:
HookList<CheckProcHandler> DoCheckAfterProc;
#define AuraCheckProcFn(F) CheckProcHandlerFunction(&F)
// executed when aura effect checks if it can proc the aura
// example: DoCheckEffectProc += AuraCheckEffectProcFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier);
// where function is bool function (AuraEffect const* aurEff, ProcEventInfo& eventInfo);
HookList<CheckEffectProcHandler> DoCheckEffectProc;
#define AuraCheckEffectProcFn(F, I, N) CheckEffectProcHandlerFunction(&F, I, N)
// executed before aura procs (possibility to prevent charge drop/cooldown)
// example: DoPrepareProc += AuraProcFn(class::function);
// where function is: void function (ProcEventInfo& eventInfo);

View file

@ -1663,10 +1663,7 @@ void World::SetInitialWorldSettings()
LOG_INFO("server.loading", "Loading Spell Learn Skills...");
sSpellMgr->LoadSpellLearnSkills(); // must be after LoadSpellRanks
LOG_INFO("server.loading", "Loading Spell Proc Event Conditions...");
sSpellMgr->LoadSpellProcEvents();
LOG_INFO("server.loading", "Loading Spell Proc Conditions and Data...");
LOG_INFO("server.loading", "Loading Spell Proc conditions and data...");
sSpellMgr->LoadSpellProcs();
LOG_INFO("server.loading", "Loading Spell Bonus Data...");

View file

@ -154,7 +154,6 @@ public:
{ "spell_loot_template", HandleReloadLootTemplatesSpellCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "spell_linked_spell", HandleReloadSpellLinkedSpellCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "spell_pet_auras", HandleReloadSpellPetAurasCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "spell_proc_event", HandleReloadSpellProcEventCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "spell_proc", HandleReloadSpellProcsCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "spell_scripts", HandleReloadSpellScriptsCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "spell_target_position", HandleReloadSpellTargetPositionCommand, SEC_ADMINISTRATOR, Console::Yes },
@ -296,7 +295,6 @@ public:
HandleReloadSpellAreaCommand(handler);
HandleReloadSpellGroupsCommand(handler);
HandleReloadSpellLinkedSpellCommand(handler);
HandleReloadSpellProcEventCommand(handler);
HandleReloadSpellProcsCommand(handler);
HandleReloadSpellBonusesCommand(handler);
HandleReloadSpellTargetPositionCommand(handler);
@ -853,14 +851,6 @@ public:
return true;
}
static bool HandleReloadSpellProcEventCommand(ChatHandler* handler)
{
LOG_INFO("server.loading", "Re-Loading Spell Proc Event conditions...");
sSpellMgr->LoadSpellProcEvents();
handler->SendGlobalGMSysMessage("DB table `spell_proc_event` (spell proc trigger requirements) reloaded.");
return true;
}
static bool HandleReloadSpellProcsCommand(ChatHandler* handler)
{
LOG_INFO("server.loading", "Re-Loading Spell Proc conditions and data...");

View file

@ -17,17 +17,19 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "hyjal.h"
#include "hyjal_trash.h"
enum Spells
{
SPELL_CARRION_SWARM = 31306,
SPELL_SLEEP = 31298,
SPELL_VAMPIRIC_AURA = 38196,
SPELL_INFERNO = 31299,
SPELL_IMMOLATION = 31303,
SPELL_INFERNO_EFFECT = 31302,
SPELL_CARRION_SWARM = 31306,
SPELL_SLEEP = 31298,
SPELL_VAMPIRIC_AURA = 38196,
SPELL_VAMPIRIC_AURA_HEAL = 31285,
SPELL_INFERNO = 31299,
SPELL_IMMOLATION = 31303,
SPELL_INFERNO_EFFECT = 31302
};
enum Texts
@ -265,8 +267,48 @@ public:
};
};
class spell_anetheron_vampiric_aura : public SpellScriptLoader
{
public:
spell_anetheron_vampiric_aura() : SpellScriptLoader("spell_anetheron_vampiric_aura") { }
class spell_anetheron_vampiric_aura_AuraScript : public AuraScript
{
PrepareAuraScript(spell_anetheron_vampiric_aura_AuraScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_VAMPIRIC_AURA_HEAL))
return false;
return true;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
if (!damageInfo || !damageInfo->GetDamage())
return;
int32 bp = damageInfo->GetDamage() * 3;
eventInfo.GetActor()->CastCustomSpell(SPELL_VAMPIRIC_AURA_HEAL, SPELLVALUE_BASE_POINT0, bp, eventInfo.GetActor(), true, nullptr, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_anetheron_vampiric_aura_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_anetheron_vampiric_aura_AuraScript();
}
};
void AddSC_boss_anetheron()
{
new boss_anetheron();
new npc_towering_infernal();
new spell_anetheron_vampiric_aura();
}

View file

@ -857,7 +857,7 @@ public:
resilienceReduction = damage - resilienceReduction;
damage -= resilienceReduction;
uint32 mitigated_damage = resilienceReduction;
DamageInfo dmgInfo(caster, plr, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, mitigated_damage);
DamageInfo dmgInfo(caster, plr, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK, mitigated_damage);
Unit::CalcAbsorbResist(dmgInfo);
Unit::DealDamageMods(plr, damage, &absorb);
int32 overkill = damage - plr->GetHealth();

View file

@ -1589,6 +1589,26 @@ public:
{
return new spell_taldaram_ball_of_inferno_flame_SpellScript();
}
class spell_taldaram_ball_of_inferno_flame_AuraScript : public AuraScript
{
PrepareAuraScript(spell_taldaram_ball_of_inferno_flame_AuraScript);
void HandleStackDrop(ProcEventInfo& /*eventInfo*/)
{
ModStackAmount(-1);
}
void Register() override
{
OnProc += AuraProcFn(spell_taldaram_ball_of_inferno_flame_AuraScript::HandleStackDrop);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_taldaram_ball_of_inferno_flame_AuraScript();
}
};
class spell_valanar_kinetic_bomb : public SpellScriptLoader

View file

@ -1061,7 +1061,7 @@ public:
{
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
SpellInfo const* procSpell = eventInfo.GetSpellInfo();
return eventInfo.GetActor() && eventInfo.GetActionTarget() && ((damageInfo && damageInfo->GetDamage()) || eventInfo.GetHitMask() & PROC_EX_ABSORB) && procSpell && procSpell->SpellIconID != 2731; // Xinef: Mark of the Fallen Champion
return eventInfo.GetActor() && eventInfo.GetActionTarget() && ((damageInfo && damageInfo->GetDamage()) || eventInfo.GetHitMask() & PROC_HIT_ABSORB) && procSpell && procSpell->SpellIconID != 2731; // Xinef: Mark of the Fallen Champion
}
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
@ -1115,7 +1115,7 @@ public:
{
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
SpellInfo const* procSpell = eventInfo.GetSpellInfo();
return eventInfo.GetActor() && eventInfo.GetActionTarget() && ((damageInfo && damageInfo->GetDamage()) || eventInfo.GetHitMask() & PROC_EX_ABSORB) && (!procSpell || procSpell->SpellIconID != 2731); // Xinef: Mark of the Fallen Champion
return eventInfo.GetActor() && eventInfo.GetActionTarget() && ((damageInfo && damageInfo->GetDamage()) || eventInfo.GetHitMask() & PROC_HIT_ABSORB) && (!procSpell || procSpell->SpellIconID != 2731); // Xinef: Mark of the Fallen Champion
}
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
@ -1404,6 +1404,41 @@ public:
}
};
// 72176 - Blood Beast's Blood Link
class spell_deathbringer_blood_beast_blood_link : public SpellScriptLoader
{
public:
spell_deathbringer_blood_beast_blood_link() : SpellScriptLoader("spell_deathbringer_blood_beast_blood_link") { }
class spell_deathbringer_blood_beast_blood_link_AuraScript : public AuraScript
{
PrepareAuraScript(spell_deathbringer_blood_beast_blood_link_AuraScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_BLOOD_LINK_DUMMY))
return false;
return true;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
eventInfo.GetProcTarget()->CastCustomSpell(SPELL_BLOOD_LINK_DUMMY, SPELLVALUE_BASE_POINT0, 3, (Unit*)nullptr, true, nullptr, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_deathbringer_blood_beast_blood_link_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_deathbringer_blood_beast_blood_link_AuraScript();
}
};
void AddSC_boss_deathbringer_saurfang()
{
new boss_deathbringer_saurfang();
@ -1418,4 +1453,5 @@ void AddSC_boss_deathbringer_saurfang()
new spell_deathbringer_boiling_blood();
new achievement_ive_gone_and_made_a_mess();
new npc_icc_blood_beast();
new spell_deathbringer_blood_beast_blood_link();
}

View file

@ -1076,9 +1076,23 @@ public:
caster->CastCustomSpell(SPELL_GASEOUS_BLOAT, SPELLVALUE_AURA_STACK, 10, caster, false);*/
}
void HandleProc(ProcEventInfo& eventInfo)
{
uint32 stack = GetStackAmount();
Unit* caster = eventInfo.GetActor();
int32 const mod = caster->GetMap()->Is25ManRaid() ? 1500 : 1250;
int32 dmg = 0;
for (uint8 i = 1; i <= stack; ++i)
dmg += mod * i;
caster->CastCustomSpell(SPELL_EXPUNGED_GAS, SPELLVALUE_BASE_POINT0, dmg);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_putricide_gaseous_bloat_AuraScript::HandleExtraEffect, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE);
OnProc += AuraProcFn(spell_putricide_gaseous_bloat_AuraScript::HandleProc);
}
};
@ -1707,6 +1721,45 @@ public:
}
};
// 71770 - Ooze Spell Tank Protection
class spell_putricide_ooze_tank_protection : public SpellScriptLoader
{
public:
spell_putricide_ooze_tank_protection() : SpellScriptLoader("spell_putricide_ooze_tank_protection") { }
class spell_putricide_ooze_tank_protection_AuraScript : public AuraScript
{
PrepareAuraScript(spell_putricide_ooze_tank_protection_AuraScript);
bool Validate(SpellInfo const* spellInfo) override
{
if (!sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_0].TriggerSpell) ||
!sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_1].TriggerSpell))
return false;
return true;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* actionTarget = eventInfo.GetActionTarget();
actionTarget->CastSpell((Unit*)nullptr, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true, nullptr, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_putricide_ooze_tank_protection_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
OnEffectProc += AuraEffectProcFn(spell_putricide_ooze_tank_protection_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_putricide_ooze_tank_protection_AuraScript();
}
};
void AddSC_boss_professor_putricide()
{
new boss_professor_putricide();
@ -1731,4 +1784,5 @@ void AddSC_boss_professor_putricide()
new spell_putricide_mutated_transformation_dmg();
new spell_putricide_eat_ooze();
new spell_putricide_regurgitated_ooze();
new spell_putricide_ooze_tank_protection();
}

View file

@ -952,7 +952,7 @@ public:
}
else
{
Unit::DealHeal(me, me, me->CountPctFromMaxHealth(3));
me->ModifyHealth(me->CountPctFromMaxHealth(5));
_events.ScheduleEvent(EVENT_HEALTH_CHECK, 1000);
}
break;

View file

@ -2987,6 +2987,8 @@ public:
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
if (!damageInfo || !damageInfo->GetDamage())

View file

@ -89,6 +89,57 @@ public:
};
};
enum SecondWind
{
SPELL_SECOND_WIND_TRIGGER = 42771
};
// 42770 - Second Wind
class spell_uk_second_wind : public SpellScriptLoader
{
public:
spell_uk_second_wind() : SpellScriptLoader("spell_uk_second_wind") { }
class spell_uk_second_wind_AuraScript : public AuraScript
{
PrepareAuraScript(spell_uk_second_wind_AuraScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_SECOND_WIND_TRIGGER))
return false;
return true;
}
bool CheckProc(ProcEventInfo& eventInfo)
{
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo)
return false;
return (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_STUN))) != 0;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActionTarget();
caster->CastSpell(caster, SPELL_SECOND_WIND_TRIGGER, true, nullptr, aurEff);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_uk_second_wind_AuraScript::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_uk_second_wind_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_uk_second_wind_AuraScript();
}
};
enum EnslavedProtoDrake
{
TYPE_PROTODRAKE_AT = 28,
@ -247,4 +298,5 @@ void AddSC_utgarde_keep()
new npc_enslaved_proto_drake();
new spell_ticking_time_bomb();
new spell_uk_second_wind();
}

View file

@ -0,0 +1,58 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "SpellMgr.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
#include "Unit.h"
enum Spells
{
SPELL_MARK_OF_MALICE_TRIGGERED = 33494
};
// 33493 - Mark of Malice
class spell_mark_of_malice : public AuraScript
{
PrepareAuraScript(spell_mark_of_malice);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_MARK_OF_MALICE_TRIGGERED });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
{
PreventDefaultAction();
// just drop charges
if (aurEff->GetBase()->GetCharges() > 1)
return;
GetTarget()->CastSpell(GetTarget(), SPELL_MARK_OF_MALICE_TRIGGERED, true, nullptr, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_mark_of_malice::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
void AddSC_shadow_labyrinth()
{
RegisterSpellScript(spell_mark_of_malice);
}

View file

@ -33,16 +33,17 @@ enum Texts
enum Spells
{
SPELL_SHADOW_VOLLEY = 32963,
SPELL_CLEAVE = 31779,
SPELL_THUNDERCLAP = 36706,
SPELL_VOID_BOLT = 39329,
SPELL_MARK_OF_KAZZAK = 32960,
SPELL_MARK_OF_KAZZAK_DAMAGE = 32961,
SPELL_ENRAGE = 32964,
SPELL_CAPTURE_SOUL = 32966,
SPELL_TWISTED_REFLECTION = 21063,
SPELL_BERSERK = 32965,
SPELL_SHADOW_VOLLEY = 32963,
SPELL_CLEAVE = 31779,
SPELL_THUNDERCLAP = 36706,
SPELL_VOID_BOLT = 39329,
SPELL_MARK_OF_KAZZAK = 32960,
SPELL_MARK_OF_KAZZAK_DAMAGE = 32961,
SPELL_ENRAGE = 32964,
SPELL_CAPTURE_SOUL = 32966,
SPELL_TWISTED_REFLECTION = 21063,
SPELL_TWISTED_REFLECTION_HEAL = 21064,
SPELL_BERSERK = 32965,
};
enum Events
@ -219,8 +220,47 @@ public:
}
};
class spell_twisted_reflection : public SpellScriptLoader
{
public:
spell_twisted_reflection() : SpellScriptLoader("spell_twisted_reflection") { }
class spell_twisted_reflection_AuraScript : public AuraScript
{
PrepareAuraScript(spell_twisted_reflection_AuraScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_TWISTED_REFLECTION_HEAL))
return false;
return true;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
if (!damageInfo || !damageInfo->GetDamage())
return;
eventInfo.GetActionTarget()->CastSpell(eventInfo.GetActor(), SPELL_TWISTED_REFLECTION_HEAL, true, nullptr, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_twisted_reflection_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_twisted_reflection_AuraScript();
}
};
void AddSC_boss_doomlordkazzak()
{
new boss_doomlord_kazzak();
new spell_mark_of_kazzak();
new spell_twisted_reflection();
}

View file

@ -29,6 +29,7 @@ void AddSC_boss_ambassador_hellmaw();
void AddSC_boss_blackheart_the_inciter();
void AddSC_boss_grandmaster_vorpil();
void AddSC_boss_murmur();
void AddSC_shadow_labyrinth();
void AddSC_boss_illidan(); //Black Temple
void AddSC_boss_shade_of_akama();
void AddSC_boss_supremus();
@ -122,6 +123,7 @@ void AddOutlandScripts()
AddSC_boss_blackheart_the_inciter();
AddSC_boss_grandmaster_vorpil();
AddSC_boss_murmur();
AddSC_shadow_labyrinth();
AddSC_boss_illidan(); //Black Temple
AddSC_boss_shade_of_akama();
AddSC_boss_supremus();

View file

@ -21,7 +21,11 @@
*/
#include "ScriptMgr.h"
#include "CreatureAIImpl.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
#include "TemporarySummon.h"
enum HunterSpells
{
@ -32,6 +36,26 @@ enum HunterSpells
SPELL_HUNTER_PET_SCALING = 62915
};
enum HunterCreatures
{
NPC_HUNTER_VIPER = 19921
};
enum PetSpellsMisc
{
SPELL_PET_GUARD_DOG_HAPPINESS = 54445,
SPELL_PET_SILVERBACK_RANK_1 = 62800,
SPELL_PET_SILVERBACK_RANK_2 = 62801,
SPELL_PET_SWOOP = 52825,
SPELL_PET_CHARGE = 61685,
PET_ICON_ID_GROWL = 201,
PET_ICON_ID_CLAW = 262,
PET_ICON_ID_BITE = 1680,
PET_ICON_ID_SMACK = 473
};
struct npc_pet_hunter_snake_trap : public ScriptedAI
{
npc_pet_hunter_snake_trap(Creature* creature) : ScriptedAI(creature) { _init = false; }
@ -138,7 +162,156 @@ private:
uint32 _spellTimer;
};
// 57627 - Charge
class spell_pet_charge : public AuraScript
{
PrepareAuraScript(spell_pet_charge);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_PET_SWOOP,
SPELL_PET_CHARGE
});
}
void HandleDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
// Remove +% AP aura
Unit* pet = eventInfo.GetActor();
Aura* aura = pet->GetAura(SPELL_PET_SWOOP, pet->GetGUID());
if (!aura)
aura = pet->GetAura(SPELL_PET_CHARGE, pet->GetGUID());
if (!aura)
return;
aura->DropCharge(AURA_REMOVE_BY_EXPIRE);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pet_charge::HandleDummy, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -53178 - Guard Dog
class spell_pet_guard_dog : public AuraScript
{
PrepareAuraScript(spell_pet_guard_dog);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PET_GUARD_DOG_HAPPINESS });
}
bool CheckProc(ProcEventInfo& eventInfo)
{
// Growl shares family flags with other spells
// filter by spellIcon instead
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo || spellInfo->SpellIconID != PET_ICON_ID_GROWL)
return false;
return true;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActor();
caster->CastSpell((Unit*)nullptr, SPELL_PET_GUARD_DOG_HAPPINESS, true);
float addThreat = CalculatePct(eventInfo.GetSpellInfo()->Effects[EFFECT_0].CalcValue(caster), aurEff->GetAmount());
eventInfo.GetProcTarget()->AddThreat(caster, addThreat);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_pet_guard_dog::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_pet_guard_dog::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -62764 - Silverback
class spell_pet_silverback : public AuraScript
{
PrepareAuraScript(spell_pet_silverback);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PET_GUARD_DOG_HAPPINESS });
}
bool CheckProc(ProcEventInfo& eventInfo)
{
// Growl shares family flags with other spells
// filter by spellIcon instead
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo || spellInfo->SpellIconID != PET_ICON_ID_GROWL)
return false;
return true;
}
void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo)
{
static uint32 const triggerSpell[2] = { SPELL_PET_SILVERBACK_RANK_1, SPELL_PET_SILVERBACK_RANK_2 };
PreventDefaultAction();
uint32 spellId = triggerSpell[GetSpellInfo()->GetRank() - 1];
eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_pet_silverback::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_pet_silverback::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -61680 - Culling the Herd
class spell_pet_culling_the_herd : public AuraScript
{
PrepareAuraScript(spell_pet_culling_the_herd);
bool CheckProc(ProcEventInfo& eventInfo)
{
// Claw, Bite and Smack share FamilyFlags with other spells
// filter by spellIcon instead
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo)
return false;
switch (spellInfo->SpellIconID)
{
case PET_ICON_ID_CLAW:
case PET_ICON_ID_BITE:
case PET_ICON_ID_SMACK:
break;
default:
return false;
}
return true;
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_pet_culling_the_herd::CheckProc);
}
};
void AddSC_hunter_pet_scripts()
{
RegisterCreatureAI(npc_pet_hunter_snake_trap);
RegisterSpellScript(spell_pet_charge);
RegisterSpellScript(spell_pet_guard_dog);
RegisterSpellScript(spell_pet_silverback);
RegisterSpellScript(spell_pet_culling_the_herd);
}

View file

@ -29,7 +29,7 @@
enum PriestSpells
{
SPELL_PRIEST_GLYPH_OF_SHADOWFIEND = 58228,
SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA = 58227,
SPELL_PRIEST_SHADOWFIEND_DEATH = 57989,
SPELL_PRIEST_SHADOWFIEND_DODGE = 8273,
SPELL_PRIEST_LIGHTWELL_CHARGES = 59907
};
@ -67,12 +67,10 @@ struct npc_pet_pri_shadowfiend : public PetAI
AttackStart(target);
}
void JustDied(Unit* /*killer*/) override
void IsSummonedBy(Unit* summoner) override
{
if (me->IsSummon())
if (Unit* owner = me->ToTempSummon()->GetSummonerUnit())
if (owner->HasAura(SPELL_PRIEST_GLYPH_OF_SHADOWFIEND))
owner->CastSpell(owner, SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA, true);
if (summoner->HasAura(SPELL_PRIEST_GLYPH_OF_SHADOWFIEND))
DoCastAOE(SPELL_PRIEST_SHADOWFIEND_DEATH);
}
};

View file

@ -33,6 +33,13 @@
enum DeathKnightSpells
{
SPELL_DK_ACCLIMATION_HOLY = 50490,
SPELL_DK_ACCLIMATION_FIRE = 50362,
SPELL_DK_ACCLIMATION_FROST = 50485,
SPELL_DK_ACCLIMATION_ARCANE = 50486,
SPELL_DK_ACCLIMATION_SHADOW = 50489,
SPELL_DK_ACCLIMATION_NATURE = 50488,
SPELL_DK_ADVANTAGE_T10_4P_MELEE = 70657,
SPELL_DK_DEATH_AND_DECAY_TRIGGER = 52212,
SPELL_DK_GLYPH_OF_SCOURGE_STRIKE = 58642,
SPELL_DK_WANDERING_PLAGUE_TRIGGER = 50526,
@ -59,6 +66,7 @@ enum DeathKnightSpells
SPELL_DK_IMPROVED_BLOOD_PRESENCE_R1 = 50365,
SPELL_DK_IMPROVED_FROST_PRESENCE_R1 = 50384,
SPELL_DK_IMPROVED_UNHOLY_PRESENCE_R1 = 50391,
SPELL_DK_IMPROVED_BLOOD_PRESENCE_HEAL = 50475,
SPELL_DK_IMPROVED_BLOOD_PRESENCE_TRIGGERED = 63611,
SPELL_DK_IMPROVED_UNHOLY_PRESENCE_TRIGGERED = 63622,
SPELL_DK_ITEM_SIGIL_VENGEFUL_HEART = 64962,
@ -72,7 +80,23 @@ enum DeathKnightSpells
SPELL_DK_UNHOLY_PRESENCE = 48265,
SPELL_DK_UNHOLY_PRESENCE_TRIGGERED = 49772,
SPELL_DK_WILL_OF_THE_NECROPOLIS_TALENT_R1 = 49189,
SPELL_DK_WILL_OF_THE_NECROPOLIS_AURA_R1 = 52284
SPELL_DK_WILL_OF_THE_NECROPOLIS_AURA_R1 = 52284,
SPELL_DK_GLYPH_OF_SCOURGE_STRIKE_SCRIPT = 69961,
SPELL_DK_BUTCHERY_RUNIC_POWER = 50163,
SPELL_DK_MARK_OF_BLOOD_HEAL = 61607,
SPELL_DK_UNHOLY_BLIGHT_DAMAGE = 50536,
SPELL_DK_GLYPH_OF_UNHOLY_BLIGHT = 63332,
SPELL_DK_VENDETTA_HEAL = 50181,
SPELL_DK_NECROSIS_DAMAGE = 51460,
SPELL_DK_OBLITERATE_OFF_HAND_R1 = 66198,
SPELL_DK_FROST_STRIKE_OFF_HAND_R1 = 66196,
SPELL_DK_PLAGUE_STRIKE_OFF_HAND_R1 = 66216,
SPELL_DK_DEATH_STRIKE_OFF_HAND_R1 = 66188,
SPELL_DK_RUNE_STRIKE_OFF_HAND_R1 = 66217,
SPELL_DK_BLOOD_STRIKE_OFF_HAND_R1 = 66215,
SPELL_DK_RUNIC_RETURN = 61258,
SPELL_DK_WANDERING_PLAGUE_DAMAGE = 50526,
SPELL_DK_DEATH_COIL_R1 = 47541,
};
enum DeathKnightSpellIcons
@ -82,7 +106,130 @@ enum DeathKnightSpellIcons
enum Misc
{
NPC_DK_GHOUL = 26125
NPC_DK_GHOUL = 26125,
NPC_DK_DANCING_RUNE_WEAPON = 27893,
SPELL_CATEGORY_HOWLING_BLAST = 1248
};
// -49200 - Acclimation
class spell_dk_acclimation : public AuraScript
{
PrepareAuraScript(spell_dk_acclimation);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_DK_ACCLIMATION_HOLY) ||
!sSpellMgr->GetSpellInfo(SPELL_DK_ACCLIMATION_FIRE) ||
!sSpellMgr->GetSpellInfo(SPELL_DK_ACCLIMATION_FROST) ||
!sSpellMgr->GetSpellInfo(SPELL_DK_ACCLIMATION_NATURE) ||
!sSpellMgr->GetSpellInfo(SPELL_DK_ACCLIMATION_SHADOW) ||
!sSpellMgr->GetSpellInfo(SPELL_DK_ACCLIMATION_ARCANE))
return false;
return true;
}
bool CheckProc(ProcEventInfo& eventInfo)
{
if (eventInfo.GetDamageInfo())
{
switch (GetFirstSchoolInMask(eventInfo.GetDamageInfo()->GetSchoolMask()))
{
case SPELL_SCHOOL_HOLY:
case SPELL_SCHOOL_FIRE:
case SPELL_SCHOOL_NATURE:
case SPELL_SCHOOL_FROST:
case SPELL_SCHOOL_SHADOW:
case SPELL_SCHOOL_ARCANE:
return true;
default:
break;
}
}
return false;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
uint32 triggerspell = 0;
switch (GetFirstSchoolInMask(eventInfo.GetDamageInfo()->GetSchoolMask()))
{
case SPELL_SCHOOL_HOLY:
triggerspell = SPELL_DK_ACCLIMATION_HOLY;
break;
case SPELL_SCHOOL_FIRE:
triggerspell = SPELL_DK_ACCLIMATION_FIRE;
break;
case SPELL_SCHOOL_NATURE:
triggerspell = SPELL_DK_ACCLIMATION_NATURE;
break;
case SPELL_SCHOOL_FROST:
triggerspell = SPELL_DK_ACCLIMATION_FROST;
break;
case SPELL_SCHOOL_SHADOW:
triggerspell = SPELL_DK_ACCLIMATION_SHADOW;
break;
case SPELL_SCHOOL_ARCANE:
triggerspell = SPELL_DK_ACCLIMATION_ARCANE;
break;
default:
return;
}
if (Unit* target = eventInfo.GetActionTarget())
{
target->CastSpell(target, triggerspell, true, nullptr, aurEff);
}
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_dk_acclimation::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_dk_acclimation::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
// 70656 - Advantage (T10 4P Melee Bonus)
class spell_dk_advantage_t10_4p : public AuraScript
{
PrepareAuraScript(spell_dk_advantage_t10_4p);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_DK_ADVANTAGE_T10_4P_MELEE))
return false;
return true;
}
bool CheckProc(ProcEventInfo& eventInfo)
{
if (Unit* caster = eventInfo.GetActor())
{
if (caster->GetTypeId() != TYPEID_PLAYER || caster->getClass() != CLASS_DEATH_KNIGHT)
{
return false;
}
for (uint8 i = 0; i < MAX_RUNES; ++i)
{
if (caster->ToPlayer()->GetRuneCooldown(i) == 0)
{
return false;
}
}
return true;
}
return false;
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_dk_advantage_t10_4p::CheckProc);
}
};
// 50526 - Wandering Plague
@ -438,19 +585,38 @@ class spell_dk_summon_gargoyle : public SpellScript
}
};
// 63611 - Improved Blood Presence
// 63611 - Improved Blood Presence Triggered
class spell_dk_improved_blood_presence_proc : public AuraScript
{
PrepareAuraScript(spell_dk_improved_blood_presence_proc);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_DK_IMPROVED_BLOOD_PRESENCE_HEAL))
return false;
return true;
}
bool CheckProc(ProcEventInfo& eventInfo)
{
return eventInfo.GetDamageInfo() && eventInfo.GetDamageInfo()->GetDamage();
if (eventInfo.GetActor()->GetTypeId() == TYPEID_PLAYER)
return true;
return false;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
if (DamageInfo* dmgInfo = eventInfo.GetDamageInfo())
eventInfo.GetActor()->CastCustomSpell(SPELL_DK_IMPROVED_BLOOD_PRESENCE_HEAL, SPELLVALUE_BASE_POINT0, CalculatePct(int32(dmgInfo->GetDamage()), aurEff->GetAmount()),
eventInfo.GetActor(), true, nullptr, aurEff);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_dk_improved_blood_presence_proc::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_dk_improved_blood_presence_proc::HandleProc, EFFECT_1, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
@ -693,7 +859,7 @@ class spell_dk_scent_of_blood_trigger : public AuraScript
bool CheckProc(ProcEventInfo& eventInfo)
{
return (eventInfo.GetHitMask() & (PROC_EX_DODGE | PROC_EX_PARRY)) || (eventInfo.GetDamageInfo() && eventInfo.GetDamageInfo()->GetDamage());
return (eventInfo.GetHitMask() & (PROC_HIT_DODGE | PROC_HIT_PARRY)) || (eventInfo.GetDamageInfo() && eventInfo.GetDamageInfo()->GetDamage());
}
void Register() override
@ -2135,8 +2301,287 @@ class spell_dk_will_of_the_necropolis : public AuraScript
}
};
// -49182 - Blade Barrier
class spell_dk_blade_barrier : public AuraScript
{
PrepareAuraScript(spell_dk_blade_barrier);
bool CheckProc(ProcEventInfo& eventInfo)
{
if (eventInfo.GetSpellInfo() != nullptr)
if (Player* player = eventInfo.GetActor()->ToPlayer())
if (player->getClass() == CLASS_DEATH_KNIGHT && player->IsBaseRuneSlotsOnCooldown(RUNE_BLOOD))
return true;
return false;
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_dk_blade_barrier::CheckProc);
}
};
// -48979 - Butchery
class spell_dk_butchery : public AuraScript
{
PrepareAuraScript(spell_dk_butchery);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_DK_BUTCHERY_RUNIC_POWER });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
eventInfo.GetActor()->CastCustomSpell(SPELL_DK_BUTCHERY_RUNIC_POWER, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), (Unit*)nullptr, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_dk_butchery::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 58642 - Glyph of Scourge Strike
class spell_dk_glyph_of_scourge_strike : public AuraScript
{
PrepareAuraScript(spell_dk_glyph_of_scourge_strike);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_DK_GLYPH_OF_SCOURGE_STRIKE_SCRIPT });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DK_GLYPH_OF_SCOURGE_STRIKE_SCRIPT, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_dk_glyph_of_scourge_strike::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 61257 - Runic Power Back on Snare/Root
class spell_dk_pvp_4p_bonus : public AuraScript
{
PrepareAuraScript(spell_dk_pvp_4p_bonus);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_DK_RUNIC_RETURN });
}
bool CheckProc(ProcEventInfo& eventInfo)
{
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo)
return false;
return (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_SNARE))) != 0;
}
void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
eventInfo.GetActionTarget()->CastSpell((Unit*)nullptr, SPELL_DK_RUNIC_RETURN, true);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_dk_pvp_4p_bonus::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_dk_pvp_4p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 49005 - Mark of Blood
class spell_dk_mark_of_blood : public AuraScript
{
PrepareAuraScript(spell_dk_mark_of_blood);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_DK_MARK_OF_BLOOD_HEAL });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DK_MARK_OF_BLOOD_HEAL, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_dk_mark_of_blood::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -51459 - Necrosis
class spell_dk_necrosis : public AuraScript
{
PrepareAuraScript(spell_dk_necrosis);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_DK_NECROSIS_DAMAGE });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
if (!damageInfo || !damageInfo->GetDamage())
return;
int32 amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount());
eventInfo.GetActor()->CastCustomSpell(SPELL_DK_NECROSIS_DAMAGE, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_dk_necrosis::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -49018 - Sudden Doom
class spell_dk_sudden_doom : public AuraScript
{
PrepareAuraScript(spell_dk_sudden_doom);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_DK_DEATH_COIL_R1 });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActor();
SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_DK_DEATH_COIL_R1);
uint32 spellId = 0;
while (spellInfo)
{
if (!caster->HasSpell(spellInfo->Id))
break;
spellId = spellInfo->Id;
spellInfo = spellInfo->GetNextRankSpell();
}
if (!spellId)
return;
caster->CastSpell(eventInfo.GetProcTarget(), spellId, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_dk_sudden_doom::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -65661 Threat of Thassarian
class spell_dk_threat_of_thassarian : public AuraScript
{
PrepareAuraScript(spell_dk_threat_of_thassarian);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_DK_OBLITERATE_OFF_HAND_R1,
SPELL_DK_FROST_STRIKE_OFF_HAND_R1,
SPELL_DK_PLAGUE_STRIKE_OFF_HAND_R1,
SPELL_DK_DEATH_STRIKE_OFF_HAND_R1,
SPELL_DK_RUNE_STRIKE_OFF_HAND_R1,
SPELL_DK_BLOOD_STRIKE_OFF_HAND_R1
});
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
if (!roll_chance_i(aurEff->GetAmount()))
return;
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo)
return;
// Must dual wield
Unit* caster = eventInfo.GetActor();
if (!caster->haveOffhandWeapon())
return;
uint32 spellId = 0;
// Plague Strike
if (spellInfo->SpellFamilyFlags[0] & 0x00000001)
spellId = SPELL_DK_PLAGUE_STRIKE_OFF_HAND_R1;
// Death Strike
else if (spellInfo->SpellFamilyFlags[0] & 0x00000010)
spellId = SPELL_DK_DEATH_STRIKE_OFF_HAND_R1;
// Blood Strike
else if (spellInfo->SpellFamilyFlags[0] & 0x00400000)
spellId = SPELL_DK_BLOOD_STRIKE_OFF_HAND_R1;
// Frost Strike
else if (spellInfo->SpellFamilyFlags[1] & 0x00000004)
spellId = SPELL_DK_FROST_STRIKE_OFF_HAND_R1;
// Obliterate
else if (spellInfo->SpellFamilyFlags[1] & 0x00020000)
spellId = SPELL_DK_OBLITERATE_OFF_HAND_R1;
// Rune Strike
else if (spellInfo->SpellFamilyFlags[1] & 0x20000000)
spellId = SPELL_DK_RUNE_STRIKE_OFF_HAND_R1;
if (!spellId)
return;
spellId = sSpellMgr->GetSpellWithRank(spellId, spellInfo->GetRank());
caster->CastSpell(eventInfo.GetProcTarget(), spellId, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_dk_threat_of_thassarian::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -49015 - Vendetta
class spell_dk_vendetta : public AuraScript
{
PrepareAuraScript(spell_dk_vendetta);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_DK_VENDETTA_HEAL });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActor();
int32 amount = caster->CountPctFromMaxHealth(aurEff->GetAmount());
caster->CastCustomSpell(SPELL_DK_VENDETTA_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_dk_vendetta::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
void AddSC_deathknight_spell_scripts()
{
RegisterSpellScript(spell_dk_acclimation);
RegisterSpellScript(spell_dk_advantage_t10_4p);
RegisterSpellScript(spell_dk_wandering_plague);
RegisterSpellScript(spell_dk_raise_ally);
RegisterSpellScript(spell_dk_raise_ally_trigger);
@ -2181,4 +2626,13 @@ void AddSC_deathknight_spell_scripts()
RegisterSpellScript(spell_dk_spell_deflection);
RegisterSpellScript(spell_dk_vampiric_blood);
RegisterSpellScript(spell_dk_will_of_the_necropolis);
RegisterSpellScript(spell_dk_blade_barrier);
RegisterSpellScript(spell_dk_butchery);
RegisterSpellScript(spell_dk_glyph_of_scourge_strike);
RegisterSpellScript(spell_dk_pvp_4p_bonus);
RegisterSpellScript(spell_dk_mark_of_blood);
RegisterSpellScript(spell_dk_necrosis);
RegisterSpellScript(spell_dk_sudden_doom);
RegisterSpellScript(spell_dk_threat_of_thassarian);
RegisterSpellScript(spell_dk_vendetta);
}

View file

@ -55,12 +55,45 @@ enum DruidSpells
SPELL_DRUID_SURVIVAL_INSTINCTS = 50322,
SPELL_DRUID_SAVAGE_ROAR = 62071,
SPELL_DRUID_TIGER_S_FURY_ENERGIZE = 51178,
SPELL_DRUID_T9_FERAL_RELIC_BEAR = 67354,
SPELL_DRUID_T9_FERAL_RELIC_CAT = 67355,
SPELL_DRUID_ITEM_T8_BALANCE_RELIC = 64950,
SPELL_DRUID_BEAR_FORM_PASSIVE = 1178,
SPELL_DRUID_DIRE_BEAR_FORM_PASSIVE = 9635,
SPELL_DRUID_FORMS_TRINKET_BEAR = 37340,
SPELL_DRUID_FORMS_TRINKET_CAT = 37341,
SPELL_DRUID_FORMS_TRINKET_MOONKIN = 37343,
SPELL_DRUID_FORMS_TRINKET_NONE = 37344,
SPELL_DRUID_FORMS_TRINKET_TREE = 37342,
SPELL_DRUID_ENRAGE = 5229,
SPELL_DRUID_ENRAGED_DEFENSE = 70725,
SPELL_DRUID_ITEM_T10_FERAL_4P_BONUS = 70726,
SPELL_DRUID_T3_PROC_ENERGIZE_MANA = 28722,
SPELL_DRUID_T3_PROC_ENERGIZE_RAGE = 28723,
SPELL_DRUID_T3_PROC_ENERGIZE_ENERGY = 28724,
SPELL_DRUID_BLESSING_OF_THE_CLAW = 28750,
SPELL_DRUID_REVITALIZE_ENERGIZE_MANA = 48542,
SPELL_DRUID_REVITALIZE_ENERGIZE_RAGE = 48541,
SPELL_DRUID_REVITALIZE_ENERGIZE_ENERGY = 48540,
SPELL_DRUID_REVITALIZE_ENERGIZE_RP = 48543,
SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN = 54833,
SPELL_DRUID_GLYPH_OF_STARFIRE_SCRIPT = 54846,
SPELL_DRUID_GLYPH_OF_RIP = 54818,
SPELL_DRUID_RIP_DURATION_LACERATE_DMG = 60141,
SPELL_DRUID_GLYPH_OF_RAKE_TRIGGERED = 54820,
SPELL_DRUID_IMP_LEADER_OF_THE_PACK_R1 = 34297,
SPELL_DRUID_IMP_LEADER_OF_THE_PACK_HEAL = 34299,
SPELL_DRUID_IMP_LEADER_OF_THE_PACK_MANA = 68285,
SPELL_DRUID_EXHILARATE = 28742,
SPELL_DRUID_GLYPH_OF_REJUVENATION_HEAL = 54755,
SPELL_DRUID_INFUSION = 37238,
SPELL_DRUID_BLESSING_OF_REMULOS = 40445,
SPELL_DRUID_BLESSING_OF_ELUNE = 40446,
SPELL_DRUID_BLESSING_OF_CENARIUS = 40452,
SPELL_DRUID_LANGUISH = 71023,
SPELL_DRUID_REJUVENATION_T10_PROC = 70691,
SPELL_DRUID_BALANCE_T10_BONUS = 70718,
SPELL_DRUID_BALANCE_T10_BONUS_PROC = 70721
};
// 1178 - Bear Form (Passive)
@ -239,7 +272,7 @@ class spell_dru_brambles_treant : public AuraScript
{
int32 amount = 0;
if (player->HasAura(SPELL_DRUID_BARKSKIN, player->GetGUID()))
player->ApplySpellMod(SPELL_DRUID_BARKSKIN, SPELLMOD_CHANCE_OF_SUCCESS, amount);
player->ApplySpellMod<SPELLMOD_CHANCE_OF_SUCCESS>(SPELL_DRUID_BARKSKIN, amount);
return roll_chance_i(amount);
}
@ -254,7 +287,7 @@ class spell_dru_brambles_treant : public AuraScript
if (GetUnitOwner()->IsSummon())
if (Unit* owner = GetUnitOwner()->ToTempSummon()->GetSummonerUnit())
if (Player* player = owner->GetSpellModOwner())
player->ApplySpellMod(SPELL_DRUID_BARKSKIN, SPELLMOD_CHANCE_OF_SUCCESS, amount);
player->ApplySpellMod<SPELLMOD_CHANCE_OF_SUCCESS>(SPELL_DRUID_BARKSKIN, amount);
}
void Register() override
@ -445,6 +478,80 @@ class spell_dru_enrage : public AuraScript
}
};
// 37336 - Druid Forms Trinket
class spell_dru_forms_trinket : public AuraScript
{
PrepareAuraScript(spell_dru_forms_trinket);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_FORMS_TRINKET_BEAR) ||
!sSpellMgr->GetSpellInfo(SPELL_DRUID_FORMS_TRINKET_CAT) ||
!sSpellMgr->GetSpellInfo(SPELL_DRUID_FORMS_TRINKET_MOONKIN) ||
!sSpellMgr->GetSpellInfo(SPELL_DRUID_FORMS_TRINKET_NONE) ||
!sSpellMgr->GetSpellInfo(SPELL_DRUID_FORMS_TRINKET_TREE))
return false;
return true;
}
bool CheckProc(ProcEventInfo& eventInfo)
{
Unit* target = eventInfo.GetActor();
switch (target->GetShapeshiftForm())
{
case FORM_BEAR:
case FORM_DIREBEAR:
case FORM_CAT:
case FORM_MOONKIN:
case FORM_NONE:
case FORM_TREE:
return true;
default:
break;
}
return false;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* target = eventInfo.GetActor();
uint32 triggerspell = 0;
switch (target->GetShapeshiftForm())
{
case FORM_BEAR:
case FORM_DIREBEAR:
triggerspell = SPELL_DRUID_FORMS_TRINKET_BEAR;
break;
case FORM_CAT:
triggerspell = SPELL_DRUID_FORMS_TRINKET_CAT;
break;
case FORM_MOONKIN:
triggerspell = SPELL_DRUID_FORMS_TRINKET_MOONKIN;
break;
case FORM_NONE:
triggerspell = SPELL_DRUID_FORMS_TRINKET_NONE;
break;
case FORM_TREE:
triggerspell = SPELL_DRUID_FORMS_TRINKET_TREE;
break;
default:
return;
}
target->CastSpell(target, triggerspell, true, nullptr, aurEff);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_dru_forms_trinket::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_dru_forms_trinket::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
// 54846 - Glyph of Starfire
class spell_dru_glyph_of_starfire : public SpellScript
{
@ -797,35 +904,27 @@ class spell_dru_rip : public AuraScript
}
};
// 62606 - Savage Defense
// 62600 - Savage Defense
class spell_dru_savage_defense : public AuraScript
{
PrepareAuraScript(spell_dru_savage_defense);
uint32 absorbPct;
bool Load() override
bool Validate(SpellInfo const* spellInfo) override
{
absorbPct = GetSpellInfo()->Effects[EFFECT_0].CalcValue(GetCaster());
return true;
return ValidateSpellInfo({ spellInfo->GetEffect(EFFECT_0).TriggerSpell });
}
void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
// Set absorbtion amount to unlimited
amount = -1;
}
void Absorb(AuraEffect* aurEff, DamageInfo& /*dmgInfo*/, uint32& absorbAmount)
{
absorbAmount = uint32(CalculatePct(GetTarget()->GetTotalAttackPowerValue(BASE_ATTACK), absorbPct));
aurEff->SetAmount(0);
PreventDefaultAction();
Unit* caster = eventInfo.GetActor();
int32 amount = static_cast<int32>(CalculatePct(caster->GetTotalAttackPowerValue(BASE_ATTACK), aurEff->GetAmount()));
caster->CastCustomSpell(GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true);
}
void Register() override
{
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dru_savage_defense::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB);
OnEffectAbsorb += AuraEffectAbsorbFn(spell_dru_savage_defense::Absorb, EFFECT_0);
OnEffectProc += AuraEffectProcFn(spell_dru_savage_defense::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
@ -1033,6 +1132,66 @@ class spell_dru_typhoon : public SpellScript
}
};
// 67353 - T9 Feral Relic (Idol of Mutilation)
class spell_dru_t9_feral_relic : public AuraScript
{
PrepareAuraScript(spell_dru_t9_feral_relic);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_T9_FERAL_RELIC_BEAR) ||
!sSpellMgr->GetSpellInfo(SPELL_DRUID_T9_FERAL_RELIC_CAT))
return false;
return true;
}
bool CheckProc(ProcEventInfo& eventInfo)
{
Unit* target = eventInfo.GetActor();
switch (target->GetShapeshiftForm())
{
case FORM_BEAR:
case FORM_DIREBEAR:
case FORM_CAT:
return true;
default:
break;
}
return false;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
uint32 triggerspell = 0;
Unit* target = eventInfo.GetActor();
switch (target->GetShapeshiftForm())
{
case FORM_BEAR:
case FORM_DIREBEAR:
triggerspell = SPELL_DRUID_T9_FERAL_RELIC_BEAR;
break;
case FORM_CAT:
triggerspell = SPELL_DRUID_T9_FERAL_RELIC_CAT;
break;
default:
return;
}
target->CastSpell(target, triggerspell, true, nullptr, aurEff);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_dru_t9_feral_relic::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_dru_t9_feral_relic::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
// 70691 - Rejuvenation
class spell_dru_t10_restoration_4p_bonus : public SpellScript
{
@ -1150,6 +1309,441 @@ class spell_dru_berserk : public SpellScript
}
};
// 54832 - Glyph of Innervate
class spell_dru_glyph_of_innervate : public AuraScript
{
PrepareAuraScript(spell_dru_glyph_of_innervate);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActor();
SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN);
int32 amount = CalculatePct(static_cast<int32>(caster->GetCreatePowers(POWER_MANA)), aurEff->GetAmount());
amount /= spellInfo->GetMaxTicks();
caster->CastCustomSpell(SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_innervate::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 54821 - Glyph of Rake
class spell_dru_glyph_of_rake : public AuraScript
{
PrepareAuraScript(spell_dru_glyph_of_rake);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_DRUID_GLYPH_OF_RAKE_TRIGGERED });
}
bool CheckProc(ProcEventInfo& eventInfo)
{
return eventInfo.GetProcTarget()->GetTypeId() == TYPEID_UNIT;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_GLYPH_OF_RAKE_TRIGGERED, aurEff);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_dru_glyph_of_rake::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_rake::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 54754 - Glyph of Rejuvenation
class spell_dru_glyph_of_rejuvenation : public AuraScript
{
PrepareAuraScript(spell_dru_glyph_of_rejuvenation);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_DRUID_GLYPH_OF_REJUVENATION_HEAL });
}
bool CheckProc(ProcEventInfo& eventInfo)
{
return eventInfo.GetProcTarget()->HealthBelowPct(50);
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
HealInfo* healInfo = eventInfo.GetHealInfo();
if (!healInfo || !healInfo->GetHeal())
return;
int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount());
eventInfo.GetActor()->CastCustomSpell(SPELL_DRUID_GLYPH_OF_REJUVENATION_HEAL, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_dru_glyph_of_rejuvenation::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_rejuvenation::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 54815 - Glyph of Shred
class spell_dru_glyph_of_shred : public AuraScript
{
PrepareAuraScript(spell_dru_glyph_of_shred);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_DRUID_GLYPH_OF_RIP,
SPELL_DRUID_RIP_DURATION_LACERATE_DMG
});
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActor();
// try to find spell Rip on the target
if (AuraEffect const* rip = eventInfo.GetProcTarget()->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00800000, 0x0, 0x0, caster->GetGUID()))
{
// Rip's max duration, note: spells which modifies Rip's duration also counted like Glyph of Rip
uint32 countMin = rip->GetBase()->GetMaxDuration();
// just Rip's max duration without other spells
uint32 countMax = rip->GetSpellInfo()->GetMaxDuration();
// add possible auras' and Glyph of Shred's max duration
countMax += 3 * aurEff->GetAmount() * IN_MILLISECONDS; // Glyph of Shred -> +6 seconds
countMax += caster->HasAura(SPELL_DRUID_GLYPH_OF_RIP) ? 4 * IN_MILLISECONDS : 0; // Glyph of Rip -> +4 seconds
countMax += caster->HasAura(SPELL_DRUID_RIP_DURATION_LACERATE_DMG) ? 4 * IN_MILLISECONDS : 0; // T7 set bonus -> +4 seconds
// if min < max -> that means caster didn't cast 3 shred yet
// so set Rip's duration and max duration
if (countMin < countMax)
{
rip->GetBase()->SetDuration(rip->GetBase()->GetDuration() + aurEff->GetAmount() * IN_MILLISECONDS);
rip->GetBase()->SetMaxDuration(countMin + aurEff->GetAmount() * IN_MILLISECONDS);
}
}
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_shred::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 54845 - Glyph of Starfire
class spell_dru_glyph_of_starfire_dummy : public AuraScript
{
PrepareAuraScript(spell_dru_glyph_of_starfire_dummy);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_DRUID_GLYPH_OF_STARFIRE_SCRIPT });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_GLYPH_OF_STARFIRE_SCRIPT, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_starfire_dummy::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -48539 - Revitalize
class spell_dru_revitalize : public AuraScript
{
PrepareAuraScript(spell_dru_revitalize);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_DRUID_REVITALIZE_ENERGIZE_MANA,
SPELL_DRUID_REVITALIZE_ENERGIZE_RAGE,
SPELL_DRUID_REVITALIZE_ENERGIZE_ENERGY,
SPELL_DRUID_REVITALIZE_ENERGIZE_RP
});
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
if (!roll_chance_i(aurEff->GetAmount()))
return;
Unit* target = eventInfo.GetProcTarget();
uint32 spellId;
switch (target->getPowerType())
{
case POWER_MANA:
spellId = SPELL_DRUID_REVITALIZE_ENERGIZE_MANA;
break;
case POWER_RAGE:
spellId = SPELL_DRUID_REVITALIZE_ENERGIZE_RAGE;
break;
case POWER_ENERGY:
spellId = SPELL_DRUID_REVITALIZE_ENERGIZE_ENERGY;
break;
case POWER_RUNIC_POWER:
spellId = SPELL_DRUID_REVITALIZE_ENERGIZE_RP;
break;
default:
return;
}
eventInfo.GetActor()->CastSpell(target, spellId, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_dru_revitalize::HandleProc, EFFECT_0, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
}
};
// 28716 - Rejuvenation
class spell_dru_t3_2p_bonus : public AuraScript
{
PrepareAuraScript(spell_dru_t3_2p_bonus);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_DRUID_T3_PROC_ENERGIZE_MANA,
SPELL_DRUID_T3_PROC_ENERGIZE_RAGE,
SPELL_DRUID_T3_PROC_ENERGIZE_ENERGY
});
}
bool CheckProc(ProcEventInfo& /*eventInfo*/)
{
if (!roll_chance_i(50))
return false;
return true;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* target = eventInfo.GetProcTarget();
uint32 spellId;
switch (target->getPowerType())
{
case POWER_MANA:
spellId = SPELL_DRUID_T3_PROC_ENERGIZE_MANA;
break;
case POWER_RAGE:
spellId = SPELL_DRUID_T3_PROC_ENERGIZE_RAGE;
break;
case POWER_ENERGY:
spellId = SPELL_DRUID_T3_PROC_ENERGIZE_ENERGY;
break;
default:
return;
}
eventInfo.GetActor()->CastSpell(target, spellId, aurEff);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_dru_t3_2p_bonus::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_dru_t3_2p_bonus::HandleProc, EFFECT_0, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
}
};
// 28744 - Regrowth
class spell_dru_t3_6p_bonus : public AuraScript
{
PrepareAuraScript(spell_dru_t3_6p_bonus);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_DRUID_BLESSING_OF_THE_CLAW });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_BLESSING_OF_THE_CLAW, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_dru_t3_6p_bonus::HandleProc, EFFECT_0, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
}
};
// 28719 - Healing Touch
class spell_dru_t3_8p_bonus : public AuraScript
{
PrepareAuraScript(spell_dru_t3_8p_bonus);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_DRUID_EXHILARATE });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo)
return;
Unit* caster = eventInfo.GetActor();
int32 amount = CalculatePct(spellInfo->CalcPowerCost(caster, spellInfo->GetSchoolMask()), aurEff->GetAmount());
caster->CastCustomSpell(SPELL_DRUID_EXHILARATE, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_dru_t3_8p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 37288 - Mana Restore
// 37295 - Mana Restore
class spell_dru_t4_2p_bonus : public AuraScript
{
PrepareAuraScript(spell_dru_t4_2p_bonus);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_DRUID_INFUSION });
}
void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_DRUID_INFUSION, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_dru_t4_2p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 40442 - Druid Tier 6 Trinket
class spell_dru_item_t6_trinket : public AuraScript
{
PrepareAuraScript(spell_dru_item_t6_trinket);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_DRUID_BLESSING_OF_REMULOS,
SPELL_DRUID_BLESSING_OF_ELUNE,
SPELL_DRUID_BLESSING_OF_CENARIUS
});
}
void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo)
return;
uint32 spellId;
int32 chance;
// Starfire
if (spellInfo->SpellFamilyFlags[0] & 0x00000004)
{
spellId = SPELL_DRUID_BLESSING_OF_REMULOS;
chance = 25;
}
// Rejuvenation
else if (spellInfo->SpellFamilyFlags[0] & 0x00000010)
{
spellId = SPELL_DRUID_BLESSING_OF_ELUNE;
chance = 25;
}
// Mangle (Bear) and Mangle (Cat)
else if (spellInfo->SpellFamilyFlags[1] & 0x00000440)
{
spellId = SPELL_DRUID_BLESSING_OF_CENARIUS;
chance = 40;
} else
return;
if (roll_chance_i(chance))
eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_dru_item_t6_trinket::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 70664 - Druid T10 Restoration 4P Bonus (Rejuvenation)
class spell_dru_t10_restoration_4p_bonus_dummy : public AuraScript
{
PrepareAuraScript(spell_dru_t10_restoration_4p_bonus_dummy);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_DRUID_REJUVENATION_T10_PROC });
}
bool CheckProc(ProcEventInfo& eventInfo)
{
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo || spellInfo->Id == SPELL_DRUID_REJUVENATION_T10_PROC)
return false;
HealInfo* healInfo = eventInfo.GetHealInfo();
if (!healInfo || !healInfo->GetHeal())
return false;
Player* caster = eventInfo.GetActor()->ToPlayer();
if (!caster)
return false;
return caster->GetGroup() || caster != eventInfo.GetProcTarget();
}
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
int32 amount = static_cast<int32>(eventInfo.GetHealInfo()->GetHeal());
eventInfo.GetActor()->CastCustomSpell(SPELL_DRUID_REJUVENATION_T10_PROC, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_dru_t10_restoration_4p_bonus_dummy::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_dru_t10_restoration_4p_bonus_dummy::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 24905 - Moonkin Form (Passive)
class spell_dru_moonkin_form_passive_proc : public AuraScript
{
@ -1184,6 +1778,7 @@ void AddSC_druid_spell_scripts()
RegisterSpellScript(spell_dru_berserk);
RegisterSpellScript(spell_dru_dash);
RegisterSpellScript(spell_dru_enrage);
RegisterSpellScript(spell_dru_forms_trinket);
RegisterSpellScript(spell_dru_glyph_of_starfire);
RegisterSpellScript(spell_dru_idol_lifebloom);
RegisterSpellScript(spell_dru_innervate);
@ -1204,7 +1799,20 @@ void AddSC_druid_spell_scripts()
RegisterSpellScript(spell_dru_swift_flight_passive);
RegisterSpellScript(spell_dru_tiger_s_fury);
RegisterSpellScript(spell_dru_typhoon);
RegisterSpellScript(spell_dru_t9_feral_relic);
RegisterSpellScript(spell_dru_t10_restoration_4p_bonus);
RegisterSpellScript(spell_dru_wild_growth);
RegisterSpellScript(spell_dru_glyph_of_innervate);
RegisterSpellScript(spell_dru_glyph_of_rake);
RegisterSpellScript(spell_dru_glyph_of_rejuvenation);
RegisterSpellScript(spell_dru_glyph_of_shred);
RegisterSpellScript(spell_dru_glyph_of_starfire_dummy);
RegisterSpellScript(spell_dru_revitalize);
RegisterSpellScript(spell_dru_t3_2p_bonus);
RegisterSpellScript(spell_dru_t3_6p_bonus);
RegisterSpellScript(spell_dru_t3_8p_bonus);
RegisterSpellScript(spell_dru_t4_2p_bonus);
RegisterSpellScript(spell_dru_item_t6_trinket);
RegisterSpellScript(spell_dru_t10_restoration_4p_bonus_dummy);
RegisterSpellScript(spell_dru_moonkin_form_passive_proc);
}

View file

@ -848,8 +848,7 @@ class spell_gen_fixate_aura : public AuraScript
}
};
/* 64440 - Blade Warding
64568 - Blood Reserve */
// 64440 - Blade Warding
class spell_gen_proc_above_75 : public AuraScript
{
PrepareAuraScript(spell_gen_proc_above_75);
@ -3634,6 +3633,53 @@ class spell_gen_bandage : public SpellScript
}
};
// Blood Reserve - 64568
enum BloodReserve
{
SPELL_GEN_BLOOD_RESERVE_AURA = 64568,
SPELL_GEN_BLOOD_RESERVE_HEAL = 64569
};
class spell_gen_blood_reserve : public AuraScript
{
PrepareAuraScript(spell_gen_blood_reserve);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_GEN_BLOOD_RESERVE_HEAL))
return false;
return true;
}
bool CheckProc(ProcEventInfo& eventInfo)
{
if (Unit* caster = eventInfo.GetActionTarget())
{
if (caster->HealthBelowPct(35))
{
return true;
}
}
return false;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActionTarget();
caster->CastCustomSpell(SPELL_GEN_BLOOD_RESERVE_HEAL, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), caster, TRIGGERED_FULL_MASK, nullptr, aurEff);
caster->RemoveAura(SPELL_GEN_BLOOD_RESERVE_AURA);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_gen_blood_reserve::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_gen_blood_reserve::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
enum ParalyticPoison
{
SPELL_PARALYSIS = 35202

View file

@ -61,15 +61,25 @@ enum HunterSpells
SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_TRIGGERED = 54114,
SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_DEBUFF = 55711,
SPELL_HUNTER_PET_CARRION_FEEDER_TRIGGERED = 54045,
SPELL_HUNTER_PIERCING_SHOTS = 63468,
SPELL_HUNTER_READINESS = 23989,
SPELL_HUNTER_SNIPER_TRAINING_R1 = 53302,
SPELL_HUNTER_SNIPER_TRAINING_BUFF_R1 = 64418,
SPELL_HUNTER_T9_4P_GREATNESS = 68130,
SPELL_HUNTER_VICIOUS_VIPER = 61609,
SPELL_HUNTER_VIPER_ATTACK_SPEED = 60144,
SPELL_DRAENEI_GIFT_OF_THE_NAARU = 59543,
SPELL_HUNTER_GLYPH_OF_ARCANE_SHOT = 61389,
SPELL_LOCK_AND_LOAD_TRIGGER = 56453,
SPELL_LOCK_AND_LOAD_MARKER = 67544
SPELL_LOCK_AND_LOAD_MARKER = 67544,
SPELL_HUNTER_LOCK_AND_LOAD_TRIGGER = 56453,
SPELL_HUNTER_LOCK_AND_LOAD_MARKER = 67544,
SPELL_HUNTER_KILL_COMMAND_HUNTER = 34027,
SPELL_HUNTER_THRILL_OF_THE_HUNT_MANA = 34720,
SPELL_REPLENISHMENT = 57669,
SPELL_HUNTER_RAPID_RECUPERATION_MANA_R1 = 56654,
SPELL_HUNTER_RAPID_RECUPERATION_MANA_R2 = 58882,
SPELL_HUNTER_GLYPH_OF_MEND_PET_HAPPINESS = 57894
};
class spell_hun_check_pet_los : public SpellScript
@ -416,7 +426,7 @@ class spell_hun_ascpect_of_the_viper : public AuraScript
}
};
// 53209 Chimera Shot
// 53209 - Chimera Shot
class spell_hun_chimera_shot : public SpellScript
{
PrepareSpellScript(spell_hun_chimera_shot);
@ -433,8 +443,8 @@ class spell_hun_chimera_shot : public SpellScript
{
uint32 spellId = 0;
int32 basePoint = 0;
Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras();
for (Unit::AuraApplicationMap::iterator i = Auras.begin(); i != Auras.end(); ++i)
Unit::AuraApplicationMap const& auras = unitTarget->GetAppliedAuras();
for (Unit::AuraApplicationMap::const_iterator i = auras.begin(); i != auras.end(); ++i)
{
Aura* aura = i->second->GetBase();
if (aura->GetCasterGUID() != caster->GetGUID())
@ -444,53 +454,47 @@ class spell_hun_chimera_shot : public SpellScript
flag96 familyFlag = aura->GetSpellInfo()->SpellFamilyFlags;
if (!(familyFlag[1] & 0x00000080 || familyFlag[0] & 0x0000C000))
continue;
if (AuraEffect* aurEff = aura->GetEffect(0))
if (AuraEffect const* aurEff = aura->GetEffect(EFFECT_0))
{
// Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting.
if (familyFlag[0] & 0x4000)
{
int32 TickCount = aurEff->GetTotalTicks();
spellId = SPELL_HUNTER_CHIMERA_SHOT_SERPENT;
basePoint = aurEff->GetAmount();
ApplyPct(basePoint, TickCount * 40);
basePoint = unitTarget->SpellDamageBonusTaken(caster, aura->GetSpellInfo(), basePoint, DOT, aura->GetStackAmount());
// calculate damage of basic tick (bonuses are already factored in AuraEffect)
basePoint = aurEff->GetAmount() * aurEff->GetTotalTicks();
ApplyPct(basePoint, 40);
}
// Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting.
// Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting.
else if (familyFlag[1] & 0x00000080)
{
int32 TickCount = aura->GetEffect(0)->GetTotalTicks();
spellId = SPELL_HUNTER_CHIMERA_SHOT_VIPER;
// Amount of one aura tick
basePoint = int32(CalculatePct(unitTarget->GetMaxPower(POWER_MANA), aurEff->GetAmount()));
int32 casterBasePoint = aurEff->GetAmount() * unitTarget->GetMaxPower(POWER_MANA) / 50; // TODO: Caster uses unitTarget?
if (basePoint > casterBasePoint)
basePoint = casterBasePoint;
ApplyPct(basePoint, TickCount * 60);
// % of mana drained in max duration
basePoint = aurEff->GetAmount() * aurEff->GetTotalTicks();
// max value
int32 maxManaReturn = CalculatePct(static_cast<int32>(caster->GetMaxPower(POWER_MANA)), basePoint * 2);
ApplyPct(basePoint, unitTarget->GetMaxPower(POWER_MANA));
if (basePoint > maxManaReturn)
basePoint = maxManaReturn;
ApplyPct(basePoint, 60);
}
// Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute.
// Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute.
else if (familyFlag[0] & 0x00008000)
{
if (caster->ToPlayer()) // Scorpid Sting - Add 1 minute cooldown
{
if (caster->ToPlayer()->HasSpellCooldown(SPELL_HUNTER_CHIMERA_SHOT_SCORPID))
break;
caster->ToPlayer()->AddSpellCooldown(SPELL_HUNTER_CHIMERA_SHOT_SCORPID, 0, 60000);
}
spellId = SPELL_HUNTER_CHIMERA_SHOT_SCORPID;
}
// Refresh aura duration
aura->RefreshDuration();
aurEff->ChangeAmount(aurEff->CalculateAmount(caster), false);
}
break;
}
if (spellId)
{
caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, true);
}
}
}
@ -808,6 +812,49 @@ class spell_hun_pet_heart_of_the_phoenix : public SpellScript
}
};
// -53234 - Piercing Shots
class spell_hun_piercing_shots : public AuraScript
{
PrepareAuraScript(spell_hun_piercing_shots);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_PIERCING_SHOTS))
return false;
return true;
}
bool CheckProc(ProcEventInfo& eventInfo)
{
if (eventInfo.GetActionTarget())
return true;
return false;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActor();
Unit* target = eventInfo.GetActionTarget();
if (DamageInfo* dmgInfo = eventInfo.GetDamageInfo())
{
SpellInfo const* piercingShots = sSpellMgr->AssertSpellInfo(SPELL_HUNTER_PIERCING_SHOTS);
uint32 dmg = dmgInfo->GetDamage();
uint32 bp = CalculatePct(int32(dmg), aurEff->GetAmount()) / static_cast<int32>(piercingShots->GetMaxTicks());
caster->CastCustomSpell(SPELL_HUNTER_PIERCING_SHOTS, SPELLVALUE_BASE_POINT0, bp, target, true, nullptr, aurEff);
}
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_hun_piercing_shots::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_hun_piercing_shots::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
// 54044 - Pet Carrion Feeder
class spell_hun_pet_carrion_feeder : public SpellScript
{
@ -1008,6 +1055,43 @@ class spell_hun_tame_beast : public SpellScript
}
};
// 67151 - T9 4P Bonus
class spell_hun_t9_4p_bonus : public AuraScript
{
PrepareAuraScript(spell_hun_t9_4p_bonus);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_T9_4P_GREATNESS))
return false;
return true;
}
bool CheckProc(ProcEventInfo& eventInfo)
{
if (eventInfo.GetActor()->GetTypeId() == TYPEID_PLAYER && eventInfo.GetActor()->ToPlayer()->GetPet())
{
return true;
}
return false;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActor();
caster->CastSpell(caster->ToPlayer()->GetPet(), SPELL_HUNTER_T9_4P_GREATNESS, true, nullptr, aurEff);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_hun_t9_4p_bonus::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_hun_t9_4p_bonus::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
// 60144 - Viper Attack Speed
class spell_hun_viper_attack_speed : public AuraScript
{
@ -1308,6 +1392,172 @@ class spell_hun_bestial_wrath : public SpellScript
}
};
// 57870 - Glyph of Mend Pet
class spell_hun_glyph_of_mend_pet : public AuraScript
{
PrepareAuraScript(spell_hun_glyph_of_mend_pet);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_HUNTER_GLYPH_OF_MEND_PET_HAPPINESS });
}
void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_HUNTER_GLYPH_OF_MEND_PET_HAPPINESS, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_hun_glyph_of_mend_pet::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -53290 - Hunting Party
class spell_hun_hunting_party : public AuraScript
{
PrepareAuraScript(spell_hun_hunting_party);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_REPLENISHMENT });
}
void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_hun_hunting_party::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 58914 - Kill Command
class spell_hun_kill_command_pet : public AuraScript
{
PrepareAuraScript(spell_hun_kill_command_pet);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_HUNTER_KILL_COMMAND_HUNTER });
}
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
{
// prevent charge drop (aura has both proc charge and stacks)
PreventDefaultAction();
if (Unit* owner = eventInfo.GetActor()->GetOwner())
owner->RemoveAuraFromStack(SPELL_HUNTER_KILL_COMMAND_HUNTER);
ModStackAmount(-1);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_hun_kill_command_pet::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -53228 - Rapid Recuperation (talent aura)
class spell_hun_rapid_recuperation_trigger : public AuraScript
{
PrepareAuraScript(spell_hun_rapid_recuperation_trigger);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_HUNTER_RAPID_RECUPERATION_MANA_R1,
SPELL_HUNTER_RAPID_RECUPERATION_MANA_R2
});
}
void HandleRapidFireProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
{
// Proc only from Rapid Fire
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo || !(spellInfo->SpellFamilyFlags[0] & 0x00000020))
{
PreventDefaultAction();
return;
}
}
void HandleRapidKillingProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo)
{
static uint32 const triggerSpells[2] = { SPELL_HUNTER_RAPID_RECUPERATION_MANA_R1, SPELL_HUNTER_RAPID_RECUPERATION_MANA_R2 };
PreventDefaultAction();
// Proc only from Rapid Killing
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo || !(spellInfo->SpellFamilyFlags[1] & 0x01000000))
return;
uint8 rank = GetSpellInfo()->GetRank();
uint32 spellId = triggerSpells[rank - 1];
eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_hun_rapid_recuperation_trigger::HandleRapidFireProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
OnEffectProc += AuraEffectProcFn(spell_hun_rapid_recuperation_trigger::HandleRapidKillingProc, EFFECT_1, SPELL_AURA_DUMMY);
}
};
// -34497 - Thrill of the Hunt
class spell_hun_thrill_of_the_hunt : public AuraScript
{
PrepareAuraScript(spell_hun_thrill_of_the_hunt);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_HUNTER_THRILL_OF_THE_HUNT_MANA });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo)
return;
Unit* caster = eventInfo.GetActor();
int32 amount = 0;
// Explosive Shot
if (spellInfo->SpellFamilyFlags[2] & 0x200)
{
if (AuraEffect const* explosiveShot = eventInfo.GetProcTarget()->GetAuraEffect(SPELL_AURA_PERIODIC_DUMMY, SPELLFAMILY_HUNTER, 0x00000000, 0x80000000, 0x00000000, caster->GetGUID()))
{
// due to Lock and Load SpellInfo::CalcPowerCost might return 0, so just calculate it manually
amount = CalculatePct(static_cast<int32>(CalculatePct(caster->GetCreateMana(), explosiveShot->GetSpellInfo()->ManaCostPercentage)), aurEff->GetAmount());
ASSERT(explosiveShot->GetSpellInfo()->GetMaxTicks() > 0);
amount /= explosiveShot->GetSpellInfo()->GetMaxTicks();
}
}
else
amount = CalculatePct(static_cast<int32>(spellInfo->CalcPowerCost(caster, spellInfo->GetSchoolMask())), aurEff->GetAmount());
if (!amount)
return;
caster->CastCustomSpell(SPELL_HUNTER_THRILL_OF_THE_HUNT_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_hun_thrill_of_the_hunt::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
void AddSC_hunter_spell_scripts()
{
RegisterSpellScript(spell_hun_check_pet_los);
@ -1329,13 +1579,20 @@ void AddSC_hunter_spell_scripts()
RegisterSpellScript(spell_hun_misdirection_proc);
RegisterSpellScript(spell_hun_pet_carrion_feeder);
RegisterSpellScript(spell_hun_pet_heart_of_the_phoenix);
RegisterSpellScript(spell_hun_piercing_shots);
RegisterSpellScript(spell_hun_readiness);
RegisterSpellScript(spell_hun_scatter_shot);
RegisterSpellScript(spell_hun_sniper_training);
RegisterSpellScript(spell_hun_tame_beast);
RegisterSpellScript(spell_hun_t9_4p_bonus);
RegisterSpellScript(spell_hun_viper_attack_speed);
RegisterSpellScript(spell_hun_volley_trigger);
RegisterSpellScript(spell_hun_lock_and_load);
RegisterSpellScript(spell_hun_intimidation);
RegisterSpellScript(spell_hun_bestial_wrath);
RegisterSpellScript(spell_hun_glyph_of_mend_pet);
RegisterSpellScript(spell_hun_hunting_party);
RegisterSpellScript(spell_hun_kill_command_pet);
RegisterSpellScript(spell_hun_rapid_recuperation_trigger);
RegisterSpellScript(spell_hun_thrill_of_the_hunt);
}

File diff suppressed because it is too large Load diff

View file

@ -31,12 +31,11 @@
enum MageSpells
{
// Ours
SPELL_MAGE_BLAZING_SPEED = 31643,
SPELL_MAGE_BURNOUT_TRIGGER = 44450,
SPELL_MAGE_IMPROVED_BLIZZARD_CHILLED = 12486,
SPELL_MAGE_COMBUSTION = 11129,
// Theirs
SPELL_MAGE_COLD_SNAP = 11958,
SPELL_MAGE_FOCUS_MAGIC_PROC = 54648,
SPELL_MAGE_FROST_WARDING_R1 = 11189,
@ -55,9 +54,49 @@ enum MageSpells
SPELL_MAGE_SUMMON_WATER_ELEMENTAL_PERMANENT = 70908,
SPELL_MAGE_SUMMON_WATER_ELEMENTAL_TEMPORARY = 70907,
SPELL_MAGE_GLYPH_OF_BLAST_WAVE = 62126,
SPELL_MAGE_CHILLED = 12484,
SPELL_MAGE_MANA_SURGE = 37445,
SPELL_MAGE_MAGIC_ABSORPTION_MANA = 29442,
SPELL_MAGE_ARCANE_POTENCY_RANK_1 = 57529,
SPELL_MAGE_ARCANE_POTENCY_RANK_2 = 57531,
SPELL_MAGE_HOT_STREAK_PROC = 48108,
SPELL_MAGE_ARCANE_SURGE = 37436,
SPELL_MAGE_COMBUSTION_PROC = 28682,
SPELL_MAGE_EMPOWERED_FIRE_PROC = 67545,
SPELL_MAGE_T10_2P_BONUS = 70752,
SPELL_MAGE_T10_2P_BONUS_EFFECT = 70753,
SPELL_MAGE_T8_4P_BONUS = 64869,
SPELL_MAGE_MISSILE_BARRAGE = 44401,
SPELL_MAGE_FINGERS_OF_FROST_AURASTATE_AURA = 44544,
SPELL_MAGE_FINGERS_OF_FROST = 44543
};
// -31641 - Blazing Speed
class spell_mage_blazing_speed : public AuraScript
{
PrepareAuraScript(spell_mage_blazing_speed);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_MAGE_BLAZING_SPEED });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
if (Unit* target = eventInfo.GetActionTarget())
{
target->CastSpell(target, SPELL_MAGE_BLAZING_SPEED, true, nullptr, aurEff);
}
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_mage_blazing_speed::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
class spell_mage_arcane_blast : public SpellScript
{
PrepareSpellScript(spell_mage_arcane_blast);
@ -100,7 +139,7 @@ class spell_mage_burning_determination : public AuraScript
return false;
// Xinef: immuned effect should just eat charge
if (eventInfo.GetHitMask() & PROC_EX_IMMUNE)
if (eventInfo.GetHitMask() & PROC_HIT_IMMUNE)
{
eventInfo.GetActionTarget()->RemoveAurasDueToSpell(54748);
return false;
@ -933,6 +972,349 @@ class spell_mage_summon_water_elemental : public SpellScript
}
};
// -31571 - Arcane Potency
class spell_mage_arcane_potency : public AuraScript
{
PrepareAuraScript(spell_mage_arcane_potency);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_MAGE_ARCANE_POTENCY_RANK_1,
SPELL_MAGE_ARCANE_POTENCY_RANK_2
});
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
static uint32 const triggerSpell[2] = { SPELL_MAGE_ARCANE_POTENCY_RANK_1, SPELL_MAGE_ARCANE_POTENCY_RANK_2 };
PreventDefaultAction();
Unit* caster = eventInfo.GetActor();
uint32 spellId = triggerSpell[GetSpellInfo()->GetRank() - 1];
caster->CastSpell(caster, spellId, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_mage_arcane_potency::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 11129 - Combustion
class spell_mage_combustion : public AuraScript
{
PrepareAuraScript(spell_mage_combustion);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_MAGE_COMBUSTION_PROC });
}
bool CheckProc(ProcEventInfo& eventInfo)
{
// Do not take charges, add a stack of crit buff
if (!(eventInfo.GetHitMask() & PROC_HIT_CRITICAL))
{
eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_MAGE_COMBUSTION_PROC, true);
return false;
}
return true;
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_mage_combustion::CheckProc);
}
};
// -11185 - Improved Blizzard
class spell_mage_imp_blizzard : public AuraScript
{
PrepareAuraScript(spell_mage_imp_blizzard);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_MAGE_CHILLED });
}
void HandleChill(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
uint32 triggerSpellId = sSpellMgr->GetSpellWithRank(SPELL_MAGE_CHILLED, GetSpellInfo()->GetRank());
eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), triggerSpellId, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_mage_imp_blizzard::HandleChill, EFFECT_0, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
}
};
// 37447 - Improved Mana Gems
// 61062 - Improved Mana Gems
class spell_mage_imp_mana_gems : public AuraScript
{
PrepareAuraScript(spell_mage_imp_mana_gems);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_MAGE_MANA_SURGE });
}
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_MAGE_MANA_SURGE, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_mage_imp_mana_gems::HandleProc, EFFECT_1, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
}
};
// -31656 - Empowered Fire
class spell_mage_empowered_fire : public AuraScript
{
PrepareAuraScript(spell_mage_empowered_fire);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_MAGE_EMPOWERED_FIRE_PROC });
}
bool CheckProc(ProcEventInfo& eventInfo)
{
if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
if (spellInfo->Id == SPELL_MAGE_IGNITE)
return true;
return false;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
{
PreventDefaultAction();
Unit* target = GetTarget();
int32 bp0 = int32(CalculatePct(target->GetCreateMana(), aurEff->GetAmount()));
target->CastCustomSpell(SPELL_MAGE_EMPOWERED_FIRE_PROC, SPELLVALUE_BASE_POINT0, bp0, target, true, nullptr, aurEff);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_mage_empowered_fire::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_mage_empowered_fire::HandleProc, EFFECT_0, SPELL_AURA_ADD_FLAT_MODIFIER);
}
};
// 74396 - Fingers of Frost
class spell_mage_fingers_of_frost : public AuraScript
{
PrepareAuraScript(spell_mage_fingers_of_frost);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_MAGE_FINGERS_OF_FROST_AURASTATE_AURA });
}
void HandleDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
eventInfo.GetActor()->RemoveAuraFromStack(GetId());
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetTarget()->RemoveAurasDueToSpell(SPELL_MAGE_FINGERS_OF_FROST_AURASTATE_AURA);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_mage_fingers_of_frost::HandleDummy, EFFECT_0, SPELL_AURA_DUMMY);
AfterEffectRemove += AuraEffectRemoveFn(spell_mage_fingers_of_frost::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
// 48108 - Hot Streak
// 57761 - Fireball!
class spell_mage_gen_extra_effects : public AuraScript
{
PrepareAuraScript(spell_mage_gen_extra_effects);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_MAGE_T10_2P_BONUS,
SPELL_MAGE_T10_2P_BONUS_EFFECT,
SPELL_MAGE_T8_4P_BONUS
});
}
bool CheckProc(ProcEventInfo& eventInfo)
{
Unit* caster = eventInfo.GetActor();
// Prevent double proc for Arcane missiles
if (caster == eventInfo.GetProcTarget())
return false;
// Proc chance is unknown, we'll just use dummy aura amount
if (AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_MAGE_T8_4P_BONUS, EFFECT_0))
if (roll_chance_i(aurEff->GetAmount()))
return false;
return true;
}
void HandleProc(ProcEventInfo& eventInfo)
{
Unit* caster = eventInfo.GetActor();
if (caster->HasAura(SPELL_MAGE_T10_2P_BONUS))
caster->CastSpell((Unit*)nullptr, SPELL_MAGE_T10_2P_BONUS_EFFECT, true);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_mage_gen_extra_effects::CheckProc);
OnProc += AuraProcFn(spell_mage_gen_extra_effects::HandleProc);
}
};
// 56375 - Glyph of Polymorph
class spell_mage_glyph_of_polymorph : public AuraScript
{
PrepareAuraScript(spell_mage_glyph_of_polymorph);
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* target = eventInfo.GetProcTarget();
target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE, ObjectGuid::Empty, target->GetAura(32409)); // SW:D shall not be removed.
target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
target->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_mage_glyph_of_polymorph::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 56374 - Glyph of Icy Veins
class spell_mage_glyph_of_icy_veins : public AuraScript
{
PrepareAuraScript(spell_mage_glyph_of_icy_veins);
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActor();
caster->RemoveAurasByType(SPELL_AURA_HASTE_SPELLS, ObjectGuid::Empty, 0, true, false);
caster->RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_mage_glyph_of_icy_veins::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -44445 - Hot Streak
class spell_mage_hot_streak : public AuraScript
{
PrepareAuraScript(spell_mage_hot_streak);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_MAGE_HOT_STREAK_PROC });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
AuraEffect* counter = GetEffect(EFFECT_1);
if (!counter)
return;
// Count spell criticals in a row in second aura
if (eventInfo.GetHitMask() & PROC_HIT_CRITICAL)
{
counter->SetAmount(counter->GetAmount() * 2);
if (counter->GetAmount() < 100) // not enough
return;
// roll chance
if (!roll_chance_i(aurEff->GetAmount()))
return;
Unit* caster = eventInfo.GetActor();
caster->CastSpell(caster, SPELL_MAGE_HOT_STREAK_PROC, aurEff);
}
// reset counter
counter->SetAmount(25);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_mage_hot_streak::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -29441 - Magic Absorption
class spell_mage_magic_absorption : public AuraScript
{
PrepareAuraScript(spell_mage_magic_absorption);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_MAGE_MAGIC_ABSORPTION_MANA });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActionTarget();
int32 bp = CalculatePct(static_cast<int32>(caster->GetMaxPower(POWER_MANA)), aurEff->GetAmount());
caster->CastCustomSpell(SPELL_MAGE_MAGIC_ABSORPTION_MANA, SPELLVALUE_BASE_POINT0, bp, caster, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_mage_magic_absorption::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -44404 - Missile Barrage
class spell_mage_missile_barrage : public AuraScript
{
PrepareAuraScript(spell_mage_missile_barrage);
bool CheckProc(ProcEventInfo& eventInfo)
{
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo)
return false;
// Arcane Blast - full chance
if (spellInfo->SpellFamilyFlags[0] & 0x20000000)
return true;
// Rest of spells have half chance
return roll_chance_i(50);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_mage_missile_barrage::CheckProc);
}
};
#define FingersOfFrostScriptName "spell_mage_fingers_of_frost_proc_aura"
class spell_mage_fingers_of_frost_proc_aura : public AuraScript
{ PrepareAuraScript(spell_mage_fingers_of_frost_proc_aura);
@ -1043,6 +1425,7 @@ class spell_mage_fingers_of_frost_proc : public AuraScript
void AddSC_mage_spell_scripts()
{
RegisterSpellScript(spell_mage_blazing_speed);
RegisterSpellScript(spell_mage_arcane_blast);
RegisterSpellScript(spell_mage_burning_determination);
RegisterSpellScript(spell_mage_molten_armor);
@ -1064,6 +1447,18 @@ void AddSC_mage_spell_scripts()
RegisterSpellScript(spell_mage_master_of_elements);
RegisterSpellScript(spell_mage_polymorph_cast_visual);
RegisterSpellScript(spell_mage_summon_water_elemental);
RegisterSpellScript(spell_mage_arcane_potency);
RegisterSpellScript(spell_mage_combustion);
RegisterSpellScript(spell_mage_imp_blizzard);
RegisterSpellScript(spell_mage_imp_mana_gems);
RegisterSpellScript(spell_mage_empowered_fire);
RegisterSpellScript(spell_mage_fingers_of_frost);
RegisterSpellScript(spell_mage_gen_extra_effects);
RegisterSpellScript(spell_mage_glyph_of_polymorph);
RegisterSpellScript(spell_mage_glyph_of_icy_veins);
RegisterSpellScript(spell_mage_hot_streak);
RegisterSpellScript(spell_mage_magic_absorption);
RegisterSpellScript(spell_mage_missile_barrage);
RegisterSpellScript(spell_mage_fingers_of_frost_proc_aura);
RegisterSpellScript(spell_mage_fingers_of_frost_proc);
}

View file

@ -28,6 +28,7 @@
#include "SpellMgr.h"
#include "SpellScript.h"
#include "UnitAI.h"
#include "GameTime.h"
enum PaladinSpells
{
@ -38,6 +39,7 @@ enum PaladinSpells
SPELL_PALADIN_HOLY_SHOCK_R1 = 20473,
SPELL_PALADIN_HOLY_SHOCK_R1_DAMAGE = 25912,
SPELL_PALADIN_HOLY_SHOCK_R1_HEALING = 25914,
SPELL_PALADIN_ILLUMINATION_ENERGIZE = 20272,
SPELL_PALADIN_BLESSING_OF_LOWER_CITY_DRUID = 37878,
SPELL_PALADIN_BLESSING_OF_LOWER_CITY_PALADIN = 37879,
@ -81,7 +83,44 @@ enum PaladinSpells
SPELL_PALADIN_AURA_MASTERY_IMMUNE = 64364,
SPELL_GENERIC_ARENA_DAMPENING = 74410,
SPELL_GENERIC_BATTLEGROUND_DAMPENING = 74411
SPELL_GENERIC_BATTLEGROUND_DAMPENING = 74411,
SPELL_PALADIN_SACRED_SHIELD = 53601,
SPELL_PALADIN_T9_HOLY_4P_BONUS = 67191,
SPELL_PALADIN_FLASH_OF_LIGHT_PROC = 66922,
SPELL_PALADIN_JUDGEMENTS_OF_THE_JUST_PROC = 68055,
SPELL_PALADIN_GLYPH_OF_DIVINITY_PROC = 54986,
SPELL_PALADIN_JUDGEMENTS_OF_THE_WISE_MANA = 31930,
SPELL_REPLENISHMENT = 57669,
SPELL_PALADIN_RIGHTEOUS_VENGEANCE_DAMAGE = 61840,
SPELL_PALADIN_SHEATH_OF_LIGHT_HEAL = 54203,
SPELL_PALADIN_SACRED_SHIELD_TRIGGER = 58597,
SPELL_PALADIN_T8_HOLY_4P_BONUS = 64895,
SPELL_PALADIN_HEART_OF_THE_CRUSADER_EFF_R1 = 21183,
SPELL_PALADIN_HOLY_POWER_ARMOR = 28790,
SPELL_PALADIN_HOLY_POWER_ATTACK_POWER = 28791,
SPELL_PALADIN_HOLY_POWER_SPELL_POWER = 28793,
SPELL_PALADIN_HOLY_POWER_MP5 = 28795,
SPELL_PALADIN_HOLY_VENGEANCE = 31803,
SPELL_PALADIN_SEAL_OF_VENGEANCE_DAMAGE = 42463,
SPELL_PALADIN_BLOOD_CORRUPTION = 53742,
SPELL_PALADIN_SEAL_OF_CORRUPTION_DAMAGE = 53739,
SPELL_PALADIN_SPIRITUAL_ATTUNEMENT_MANA = 31786,
SPELL_PALADIN_ENDURING_LIGHT = 40471,
SPELL_PALADIN_ENDURING_JUDGEMENT = 40472,
SPELL_PALADIN_GLYPH_OF_HOLY_LIGHT_HEAL = 54968,
SPELL_PALADIN_HOLY_MENDING = 64891,
SPELL_PALADIN_JUDGEMENT_OF_LIGHT_HEAL = 20267,
SPELL_PALADIN_JUDGEMENT_OF_WISDOM_MANA = 20268
};
enum PaladinSpellIcons
@ -218,13 +257,6 @@ class spell_pal_sacred_shield_base : public AuraScript
}
}
bool CheckProc(ProcEventInfo& eventInfo)
{
HealInfo* healinfo = eventInfo.GetHealInfo();
DamageInfo* damageinfo = eventInfo.GetDamageInfo();
return !(eventInfo.GetHitMask() & PROC_EX_INTERNAL_HOT) && ((healinfo && healinfo->GetHeal() > 0) || (damageinfo && damageinfo->GetDamage() > 0));
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
@ -280,7 +312,6 @@ class spell_pal_sacred_shield_base : public AuraScript
void Register() override
{
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_pal_sacred_shield_base::CalculateAmount, EFFECT_0, SPELL_AURA_DUMMY);
DoCheckProc += AuraCheckProcFn(spell_pal_sacred_shield_base::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_pal_sacred_shield_base::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
@ -838,6 +869,51 @@ class spell_pal_holy_shock : public SpellScript
}
};
// -20210 - Illumination
class spell_pal_illumination : public AuraScript
{
PrepareAuraScript(spell_pal_illumination);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PALADIN_HOLY_SHOCK_R1_HEALING, SPELL_PALADIN_ILLUMINATION_ENERGIZE, SPELL_PALADIN_HOLY_SHOCK_R1 });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
// this script is valid only for the Holy Shock procs of illumination
if (eventInfo.GetHealInfo() && eventInfo.GetHealInfo()->GetSpellInfo())
{
SpellInfo const* originalSpell = nullptr;
// if proc comes from the Holy Shock heal, need to get mana cost of original spell - else it's the original heal itself
if (eventInfo.GetHealInfo()->GetSpellInfo()->SpellFamilyFlags[1] & 0x00010000)
{
originalSpell = sSpellMgr->GetSpellInfo(sSpellMgr->GetSpellWithRank(SPELL_PALADIN_HOLY_SHOCK_R1, eventInfo.GetHealInfo()->GetSpellInfo()->GetRank()));
}
else
{
originalSpell = eventInfo.GetHealInfo()->GetSpellInfo();
}
if (originalSpell && aurEff->GetSpellInfo())
{
Unit* target = eventInfo.GetActor(); // Paladin is the target of the energize
uint32 bp = CalculatePct(originalSpell->CalcPowerCost(target, originalSpell->GetSchoolMask()), aurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue());
target->CastCustomSpell(SPELL_PALADIN_ILLUMINATION_ENERGIZE, SPELLVALUE_BASE_POINT0, bp, target, true, nullptr, aurEff);
}
}
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pal_illumination::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
// 53407 - Judgement of Justice
// 20271 - Judgement of Light
// 53408 - Judgement of Wisdom
@ -1043,7 +1119,7 @@ class spell_pal_seal_of_righteousness : public AuraScript
return false;
}
return target->IsAlive() && !eventInfo.GetTriggerAuraSpell() && (damageInfo->GetDamage() || (eventInfo.GetHitMask() & PROC_EX_ABSORB));
return target->IsAlive() && !eventInfo.GetTriggerAuraSpell() && (damageInfo->GetDamage() || (eventInfo.GetHitMask() & PROC_HIT_ABSORB));
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
@ -1071,6 +1147,593 @@ class spell_pal_seal_of_righteousness : public AuraScript
}
};
// -31871 - Divine Purpose
class spell_pal_divine_purpose : public AuraScript
{
PrepareAuraScript(spell_pal_divine_purpose);
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
if (!roll_chance_i(aurEff->GetAmount()))
return;
eventInfo.GetProcTarget()->RemoveAurasWithMechanic(1 << MECHANIC_STUN, AURA_REMOVE_BY_ENEMY_SPELL);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pal_divine_purpose::HandleProc, EFFECT_2, SPELL_AURA_DUMMY);
}
};
// 54939 - Glyph of Divinity
class spell_pal_glyph_of_divinity : public AuraScript
{
PrepareAuraScript(spell_pal_glyph_of_divinity);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PALADIN_GLYPH_OF_DIVINITY_PROC });
}
void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
// Lay on Hands (Rank 1) does not have mana effect
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo || spellInfo->Effects[EFFECT_1].Effect != SPELL_EFFECT_ENERGIZE)
return;
Unit* caster = eventInfo.GetActor();
if (caster == eventInfo.GetProcTarget())
return;
int32 mana = spellInfo->Effects[EFFECT_1].CalcValue() * 2;
caster->CastCustomSpell(SPELL_PALADIN_GLYPH_OF_DIVINITY_PROC, SPELLVALUE_BASE_POINT1, mana, (Unit*)nullptr, true, nullptr, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pal_glyph_of_divinity::OnProc, EFFECT_0, SPELL_AURA_ADD_PCT_MODIFIER);
}
};
// 54937 - Glyph of Holy Light (dummy aura)
class spell_pal_glyph_of_holy_light_dummy : public AuraScript
{
PrepareAuraScript(spell_pal_glyph_of_holy_light_dummy);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PALADIN_GLYPH_OF_HOLY_LIGHT_HEAL });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
HealInfo* healInfo = eventInfo.GetHealInfo();
if (!healInfo || !healInfo->GetHeal())
return;
Unit* caster = eventInfo.GetActor();
Unit* target = eventInfo.GetProcTarget();
int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount());
caster->CastCustomSpell(SPELL_PALADIN_GLYPH_OF_HOLY_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pal_glyph_of_holy_light_dummy::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -20335 - Heart of the Crusader
class spell_pal_heart_of_the_crusader : public AuraScript
{
PrepareAuraScript(spell_pal_heart_of_the_crusader);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PALADIN_HEART_OF_THE_CRUSADER_EFF_R1 });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
uint32 spellId = sSpellMgr->GetSpellWithRank(SPELL_PALADIN_HEART_OF_THE_CRUSADER_EFF_R1, GetSpellInfo()->GetRank());
eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pal_heart_of_the_crusader::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -20234 - Improved Lay on Hands
class spell_pal_improved_lay_of_hands : public AuraScript
{
PrepareAuraScript(spell_pal_improved_lay_of_hands);
bool Validate(SpellInfo const* spellInfo) override
{
return ValidateSpellInfo({ spellInfo->GetEffect(EFFECT_0).TriggerSpell });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
eventInfo.GetActionTarget()->CastSpell(eventInfo.GetActionTarget(), GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true, nullptr, aurEff, GetTarget()->GetGUID());
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pal_improved_lay_of_hands::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
// -53569 - Infusion of Light
class spell_pal_infusion_of_light : public AuraScript
{
PrepareAuraScript(spell_pal_infusion_of_light);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_PALADIN_SACRED_SHIELD,
SPELL_PALADIN_T9_HOLY_4P_BONUS,
SPELL_PALADIN_FLASH_OF_LIGHT_PROC
});
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
{
// Flash of Light HoT on Flash of Light when Sacred Shield active
if (spellInfo->SpellFamilyFlags[0] & 0x40000000 && spellInfo->SpellIconID == 242)
{
PreventDefaultAction();
HealInfo* healInfo = eventInfo.GetHealInfo();
if (!healInfo || !healInfo->GetHeal())
return;
Unit* procTarget = eventInfo.GetActionTarget();
if (procTarget && procTarget->HasAura(SPELL_PALADIN_SACRED_SHIELD))
{
Unit* target = GetTarget();
int32 duration = sSpellMgr->AssertSpellInfo(SPELL_PALADIN_FLASH_OF_LIGHT_PROC)->GetMaxDuration() / 1000;
int32 pct = GetSpellInfo()->Effects[EFFECT_2].CalcValue();
int32 bp0 = CalculatePct(healInfo->GetHeal() / duration, pct);
// Item - Paladin T9 Holy 4P Bonus
if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_PALADIN_T9_HOLY_4P_BONUS, 0))
AddPct(bp0, aurEff->GetAmount());
target->CastCustomSpell(SPELL_PALADIN_FLASH_OF_LIGHT_PROC, SPELLVALUE_BASE_POINT0, bp0, procTarget, true, nullptr, aurEff);
}
}
// but should not proc on non-critical Holy Shocks
else if ((spellInfo->SpellFamilyFlags[0] & 0x200000 || spellInfo->SpellFamilyFlags[1] & 0x10000) && !(eventInfo.GetHitMask() & PROC_HIT_CRITICAL))
PreventDefaultAction();
}
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pal_infusion_of_light::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
// 40470 - Paladin Tier 6 Trinket
class spell_pal_item_t6_trinket : public AuraScript
{
PrepareAuraScript(spell_pal_item_t6_trinket);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_PALADIN_ENDURING_LIGHT,
SPELL_PALADIN_ENDURING_JUDGEMENT
});
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo)
return;
uint32 spellId;
int32 chance;
// Holy Light & Flash of Light
if (spellInfo->SpellFamilyFlags[0] & 0xC0000000)
{
spellId = SPELL_PALADIN_ENDURING_LIGHT;
chance = 15;
}
// Judgements
else if (spellInfo->SpellFamilyFlags[0] & 0x00800000)
{
spellId = SPELL_PALADIN_ENDURING_JUDGEMENT;
chance = 50;
}
else
return;
if (roll_chance_i(chance))
eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pal_item_t6_trinket::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 20185 - Judgement of Light
class spell_pal_judgement_of_light_heal : public AuraScript
{
PrepareAuraScript(spell_pal_judgement_of_light_heal);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PALADIN_JUDGEMENT_OF_LIGHT_HEAL });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetProcTarget();
int32 amount = static_cast<int32>(caster->CountPctFromMaxHealth(aurEff->GetAmount()));
caster->CastCustomSpell(SPELL_PALADIN_JUDGEMENT_OF_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pal_judgement_of_light_heal::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 20186 - Judgement of Wisdom
class spell_pal_judgement_of_wisdom_mana : public AuraScript
{
PrepareAuraScript(spell_pal_judgement_of_wisdom_mana);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PALADIN_JUDGEMENT_OF_WISDOM_MANA });
}
bool CheckProc(ProcEventInfo& eventInfo)
{
return eventInfo.GetProcTarget()->getPowerType() == POWER_MANA;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetProcTarget();
int32 amount = CalculatePct(static_cast<int32>(caster->GetCreateMana()), aurEff->GetAmount());
caster->CastCustomSpell(SPELL_PALADIN_JUDGEMENT_OF_WISDOM_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_pal_judgement_of_wisdom_mana::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_pal_judgement_of_wisdom_mana::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -53695 - Judgements of the Just
class spell_pal_judgements_of_the_just : public AuraScript
{
PrepareAuraScript(spell_pal_judgements_of_the_just);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PALADIN_JUDGEMENTS_OF_THE_JUST_PROC });
}
void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
GetTarget()->CastSpell(eventInfo.GetActionTarget(), SPELL_PALADIN_JUDGEMENTS_OF_THE_JUST_PROC, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pal_judgements_of_the_just::OnProc, EFFECT_0, SPELL_AURA_ADD_FLAT_MODIFIER);
}
};
// -31876 - Judgements of the Wise
class spell_pal_judgements_of_the_wise : public AuraScript
{
PrepareAuraScript(spell_pal_judgements_of_the_wise);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_REPLENISHMENT,
SPELL_PALADIN_JUDGEMENTS_OF_THE_WISE_MANA
});
}
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActor();
caster->CastSpell((Unit*)nullptr, SPELL_PALADIN_JUDGEMENTS_OF_THE_WISE_MANA, true);
caster->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pal_judgements_of_the_wise::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 53601 - Sacred Shield (dummy)
class spell_pal_sacred_shield_dummy : public AuraScript
{
PrepareAuraScript(spell_pal_sacred_shield_dummy);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_PALADIN_SACRED_SHIELD_TRIGGER,
SPELL_PALADIN_T8_HOLY_4P_BONUS
});
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = GetCaster();
if (!caster)
return;
TimePoint now = GameTime::Now();
if (_cooldownEnd > now)
return;
Seconds cooldown(aurEff->GetAmount());
if (AuraEffect const* bonus = caster->GetAuraEffect(SPELL_PALADIN_T8_HOLY_4P_BONUS, EFFECT_0, caster->GetGUID()))
cooldown = Seconds(bonus->GetAmount());
_cooldownEnd = now + cooldown;
caster->CastSpell(eventInfo.GetActionTarget(), SPELL_PALADIN_SACRED_SHIELD_TRIGGER, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pal_sacred_shield_dummy::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
// Cooldown tracking can't be done in DB because of T8 bonus
TimePoint _cooldownEnd = std::chrono::steady_clock::time_point::min();
};
// 31801 - Seal of Vengeance
// 53736 - Seal of Corruption
template <uint32 DoTSpellId, uint32 DamageSpellId>
class spell_pal_seal_of_vengeance : public SpellScriptLoader
{
public:
spell_pal_seal_of_vengeance(char const* ScriptName) : SpellScriptLoader(ScriptName) { }
template <uint32 DoTSpell, uint32 DamageSpell>
class spell_pal_seal_of_vengeance_AuraScript : public AuraScript
{
PrepareAuraScript(spell_pal_seal_of_vengeance_AuraScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
DoTSpell,
DamageSpell
});
}
/*
When an auto-attack lands (does not dodge/parry/miss) that can proc a seal the of the following things happen independently of each other (see 2 roll system).
1) A "hidden strike" which uses melee combat mechanics occurs. If it lands it refreshes/stacks SoV DoT. Only white swings can trigger a refresh or stack. (This hidden strike mechanic can also proc things like berserking..)
2) A weapon damage based proc will occur if you used a special (CS/DS/judge) or if you have a 5 stack (from auto attacks). This attack can not be avoided.
Remember #2 happens regardless of #1 landing, it just requires the initial attack (autos, cs, etc) to land.
Stack Number % of Weapon Damage % with SotP
0 0% 0%
1 6.6% 7.6%
2 13.2% 15.2%
3 19.8% 22.8%
4 26.4% 30.4%
5 33% 38%
*/
void HandleApplyDoT(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
if (!(eventInfo.GetTypeMask() & PROC_FLAG_DONE_MELEE_AUTO_ATTACK))
return;
// don't cast triggered, spell already has SPELL_ATTR4_CAN_CAST_WHILE_CASTING attr
eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), DoTSpell, false);
}
void HandleSeal(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActor();
Unit* target = eventInfo.GetProcTarget();
AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PALADIN, 0x00000000, 0x00000800, 0x00000000, caster->GetGUID());
if (!aurEff)
return;
uint8 stacks = aurEff->GetBase()->GetStackAmount();
uint8 maxStacks = aurEff->GetSpellInfo()->StackAmount;
if (stacks < maxStacks && !(eventInfo.GetTypeMask() & PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS))
return;
SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(DamageSpell);
int32 amount = spellInfo->Effects[EFFECT_0].CalcValue();
amount *= stacks;
amount /= maxStacks;
caster->CastCustomSpell(DamageSpell, SPELLVALUE_BASE_POINT0, amount, target, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pal_seal_of_vengeance_AuraScript::HandleApplyDoT, EFFECT_0, SPELL_AURA_DUMMY);
OnEffectProc += AuraEffectProcFn(spell_pal_seal_of_vengeance_AuraScript::HandleSeal, EFFECT_0, SPELL_AURA_DUMMY);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_pal_seal_of_vengeance_AuraScript<DoTSpellId, DamageSpellId>();
}
};
// 20375 - Seal of Command
// 21084 - Seal of Righteousness
// 31801 - Seal of Vengeance
// 31892 - Seal of Blood
// 33127 - Seal of Command
// 38008 - Seal of Blood
// 41459 - Seal of Blood
// 53720 - Seal of the Martyr
// 53736 - Seal of Corruption
class spell_pal_seals : public AuraScript
{
PrepareAuraScript(spell_pal_seals);
// Effect 2 is used by Judgement code, we prevent the proc to avoid console logging of unknown spell trigger
bool CheckDummyProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
{
return false;
}
void Register() override
{
DoCheckEffectProc += AuraCheckEffectProcFn(spell_pal_seals::CheckDummyProc, EFFECT_2, SPELL_AURA_DUMMY);
}
};
// -31785 - Spiritual Attunement
class spell_pal_spiritual_attunement : public AuraScript
{
PrepareAuraScript(spell_pal_spiritual_attunement);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PALADIN_SPIRITUAL_ATTUNEMENT_MANA });
}
bool CheckProc(ProcEventInfo& eventInfo)
{
// "when healed by other friendly targets' spells"
if (eventInfo.GetProcTarget() == eventInfo.GetActionTarget())
return false;
return eventInfo.GetHealInfo() && eventInfo.GetHealInfo()->GetEffectiveHeal();
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
HealInfo* healInfo = eventInfo.GetHealInfo();
int32 amount = CalculatePct(static_cast<int32>(healInfo->GetEffectiveHeal()), aurEff->GetAmount());
eventInfo.GetActionTarget()->CastCustomSpell(SPELL_PALADIN_SPIRITUAL_ATTUNEMENT_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_pal_spiritual_attunement::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_pal_spiritual_attunement::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 28789 - Holy Power
class spell_pal_t3_6p_bonus : public AuraScript
{
PrepareAuraScript(spell_pal_t3_6p_bonus);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_PALADIN_HOLY_POWER_ARMOR,
SPELL_PALADIN_HOLY_POWER_ATTACK_POWER,
SPELL_PALADIN_HOLY_POWER_SPELL_POWER,
SPELL_PALADIN_HOLY_POWER_MP5
});
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
uint32 spellId;
Unit* caster = eventInfo.GetActor();
Unit* target = eventInfo.GetProcTarget();
switch (target->getClass())
{
case CLASS_PALADIN:
case CLASS_PRIEST:
case CLASS_SHAMAN:
case CLASS_DRUID:
spellId = SPELL_PALADIN_HOLY_POWER_MP5;
break;
case CLASS_MAGE:
case CLASS_WARLOCK:
spellId = SPELL_PALADIN_HOLY_POWER_SPELL_POWER;
break;
case CLASS_HUNTER:
case CLASS_ROGUE:
spellId = SPELL_PALADIN_HOLY_POWER_ATTACK_POWER;
break;
case CLASS_WARRIOR:
spellId = SPELL_PALADIN_HOLY_POWER_ARMOR;
break;
default:
return;
}
caster->CastSpell(target, spellId, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pal_t3_6p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
void AddSC_paladin_spell_scripts()
{
RegisterSpellAndAuraScriptPair(spell_pal_seal_of_command, spell_pal_seal_of_command_aura);
@ -1091,6 +1754,7 @@ void AddSC_paladin_spell_scripts()
RegisterSpellAndAuraScriptPair(spell_pal_hand_of_sacrifice, spell_pal_hand_of_sacrifice_aura);
RegisterSpellScript(spell_pal_hand_of_salvation);
RegisterSpellScript(spell_pal_holy_shock);
RegisterSpellScript(spell_pal_illumination);
RegisterSpellScriptWithArgs(spell_pal_judgement, "spell_pal_judgement_of_justice", SPELL_PALADIN_JUDGEMENT_OF_JUSTICE);
RegisterSpellScriptWithArgs(spell_pal_judgement, "spell_pal_judgement_of_light", SPELL_PALADIN_JUDGEMENT_OF_LIGHT);
RegisterSpellScriptWithArgs(spell_pal_judgement, "spell_pal_judgement_of_wisdom", SPELL_PALADIN_JUDGEMENT_OF_WISDOM);
@ -1098,4 +1762,21 @@ void AddSC_paladin_spell_scripts()
RegisterSpellScript(spell_pal_lay_on_hands);
RegisterSpellScript(spell_pal_righteous_defense);
RegisterSpellScript(spell_pal_seal_of_righteousness);
RegisterSpellScript(spell_pal_divine_purpose);
RegisterSpellScript(spell_pal_glyph_of_divinity);
RegisterSpellScript(spell_pal_glyph_of_holy_light_dummy);
RegisterSpellScript(spell_pal_heart_of_the_crusader);
RegisterSpellScript(spell_pal_improved_lay_of_hands);
RegisterSpellScript(spell_pal_infusion_of_light);
RegisterSpellScript(spell_pal_item_t6_trinket);
RegisterSpellScript(spell_pal_judgement_of_light_heal);
RegisterSpellScript(spell_pal_judgement_of_wisdom_mana);
RegisterSpellScript(spell_pal_judgements_of_the_just);
RegisterSpellScript(spell_pal_judgements_of_the_wise);
RegisterSpellScript(spell_pal_sacred_shield_dummy);
new spell_pal_seal_of_vengeance<SPELL_PALADIN_HOLY_VENGEANCE, SPELL_PALADIN_SEAL_OF_VENGEANCE_DAMAGE>("spell_pal_seal_of_vengeance");
new spell_pal_seal_of_vengeance<SPELL_PALADIN_BLOOD_CORRUPTION, SPELL_PALADIN_SEAL_OF_CORRUPTION_DAMAGE>("spell_pal_seal_of_corruption");
RegisterSpellScript(spell_pal_seals);
RegisterSpellScript(spell_pal_spiritual_attunement);
RegisterSpellScript(spell_pal_t3_6p_bonus);
}

View file

@ -31,6 +31,7 @@
enum PriestSpells
{
SPELL_PRIEST_BLESSED_RECOVERY_R1 = 27813,
SPELL_PRIEST_DIVINE_AEGIS = 47753,
SPELL_PRIEST_EMPOWERED_RENEW = 63544,
SPELL_PRIEST_GLYPH_OF_CIRCLE_OF_HEALING = 55675,
@ -53,7 +54,22 @@ enum PriestSpells
SPELL_GENERIC_BATTLEGROUND_DAMPENING = 74411,
SPELL_PRIEST_TWIN_DISCIPLINE_R1 = 47586,
SPELL_PRIEST_SPIRITUAL_HEALING_R1 = 14898,
SPELL_PRIEST_DIVINE_PROVIDENCE_R1 = 47562
SPELL_PRIEST_DIVINE_PROVIDENCE_R1 = 47562,
SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA = 58227,
SPELL_REPLENISHMENT = 57669,
SPELL_PRIEST_BODY_AND_SOUL_POISON_TRIGGER = 64136,
SPELL_PRIEST_ABOLISH_DISEASE = 552,
SPELL_PRIEST_VAMPIRIC_EMBRACE_HEAL = 15290,
SPELL_PRIEST_DIVINE_BLESSING = 40440,
SPELL_PRIEST_DIVINE_WRATH = 40441,
SPELL_PRIEST_GLYPH_OF_DISPEL_MAGIC_HEAL = 56131,
SPELL_PRIEST_ORACULAR_HEAL = 26170,
SPELL_PRIEST_ARMOR_OF_FAITH = 28810,
SPELL_PRIEST_BLESSED_HEALING = 70772,
SPELL_PRIEST_MIND_BLAST_R1 = 8092,
SPELL_PRIEST_SHADOW_WORD_DEATH_R1 = 32379,
SPELL_PRIEST_MIND_FLAY_DAMAGE = 58381
};
enum PriestSpellIcons
@ -149,6 +165,41 @@ class spell_pri_shadowfiend_scaling : public AuraScript
}
};
// -27811 - Blessed Recovery
class spell_pri_blessed_recovery : public AuraScript
{
PrepareAuraScript(spell_pri_blessed_recovery);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PRIEST_BLESSED_RECOVERY_R1 });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
DamageInfo* dmgInfo = eventInfo.GetDamageInfo();
if (!dmgInfo || !dmgInfo->GetDamage())
return;
Unit* target = eventInfo.GetActionTarget();
uint32 triggerSpell = sSpellMgr->GetSpellWithRank(SPELL_PRIEST_BLESSED_RECOVERY_R1, aurEff->GetSpellInfo()->GetRank());
SpellInfo const* triggerInfo = sSpellMgr->AssertSpellInfo(triggerSpell);
int32 bp = CalculatePct(static_cast<int32>(dmgInfo->GetDamage()), aurEff->GetAmount());
ASSERT(triggerInfo->GetMaxTicks() > 0);
bp /= triggerInfo->GetMaxTicks();
target->CastCustomSpell(triggerSpell, SPELLVALUE_BASE_POINT0, bp, target, true, nullptr, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pri_blessed_recovery::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
// -34861 - Circle of Healing
class spell_pri_circle_of_healing : public SpellScript
{
@ -349,15 +400,6 @@ class spell_pri_item_greater_heal_refund : public AuraScript
return ValidateSpellInfo({ SPELL_PRIEST_ITEM_EFFICIENCY });
}
bool CheckProc(ProcEventInfo& eventInfo)
{
if (HealInfo* healInfo = eventInfo.GetHealInfo())
if (Unit* healTarget = healInfo->GetTarget())
if (eventInfo.GetHitMask() & PROC_EX_NO_OVERHEAL && healTarget->IsFullHealth())
return true;
return false;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
{
PreventDefaultAction();
@ -366,7 +408,6 @@ class spell_pri_item_greater_heal_refund : public AuraScript
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_pri_item_greater_heal_refund::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_pri_item_greater_heal_refund::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
@ -522,6 +563,33 @@ class spell_pri_mind_sear : public SpellScript
}
};
// -47580 - Pain and Suffering (dummy aura)
class spell_pri_pain_and_suffering_dummy : public SpellScriptLoader
{
public:
spell_pri_pain_and_suffering_dummy() : SpellScriptLoader("spell_pri_pain_and_suffering_dummy") { }
class spell_pri_pain_and_suffering_dummy_AuraScript : public AuraScript
{
PrepareAuraScript(spell_pri_pain_and_suffering_dummy_AuraScript);
bool CheckDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
{
return false;
}
void Register() override
{
DoCheckEffectProc += AuraCheckEffectProcFn(spell_pri_pain_and_suffering_dummy_AuraScript::CheckDummy, EFFECT_1, SPELL_AURA_DUMMY);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_pri_pain_and_suffering_dummy_AuraScript;
}
};
// 47948 - Pain and Suffering (Proc)
class spell_pri_pain_and_suffering_proc : public SpellScript
{
@ -926,9 +994,326 @@ class spell_pri_mind_control : public AuraScript
}
};
// 26169 - Oracle Healing Bonus
class spell_pri_aq_3p_bonus : public AuraScript
{
PrepareAuraScript(spell_pri_aq_3p_bonus);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PRIEST_ORACULAR_HEAL });
}
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActor();
if (caster == eventInfo.GetProcTarget())
return;
HealInfo* healInfo = eventInfo.GetHealInfo();
if (!healInfo || !healInfo->GetHeal())
return;
int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), 10);
caster->CastCustomSpell(SPELL_PRIEST_ORACULAR_HEAL, SPELLVALUE_BASE_POINT0, amount, caster, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pri_aq_3p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -64127 - Body and Soul
class spell_pri_body_and_soul : public AuraScript
{
PrepareAuraScript(spell_pri_body_and_soul);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_PRIEST_BODY_AND_SOUL_POISON_TRIGGER,
SPELL_PRIEST_ABOLISH_DISEASE
});
}
void HandleProcTriggerSpell(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
{
// Proc only on Power Word: Shield
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo || !(spellInfo->SpellFamilyFlags[0] & 0x00000001))
{
PreventDefaultAction();
return;
}
}
void HandleProcDummy(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
// Proc only on self casted abolish disease
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo)
return;
Unit* caster = eventInfo.GetActor();
if (spellInfo->Id != SPELL_PRIEST_ABOLISH_DISEASE || caster != eventInfo.GetProcTarget())
return;
if (roll_chance_i(aurEff->GetAmount()))
caster->CastSpell(caster, SPELL_PRIEST_BODY_AND_SOUL_POISON_TRIGGER, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pri_body_and_soul::HandleProcTriggerSpell, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
OnEffectProc += AuraEffectProcFn(spell_pri_body_and_soul::HandleProcDummy, EFFECT_1, SPELL_AURA_DUMMY);
}
};
// 55677 - Glyph of Dispel Magic
class spell_pri_glyph_of_dispel_magic : public AuraScript
{
PrepareAuraScript(spell_pri_glyph_of_dispel_magic);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PRIEST_GLYPH_OF_DISPEL_MAGIC_HEAL });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
// Dispel Magic shares spellfamilyflag with abolish disease
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo || spellInfo->SpellIconID != 74)
return;
Unit* caster = eventInfo.GetActor();
Unit* target = eventInfo.GetProcTarget();
int32 amount = static_cast<int32>(target->CountPctFromMaxHealth(aurEff->GetAmount()));
caster->CastCustomSpell(SPELL_PRIEST_GLYPH_OF_DISPEL_MAGIC_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pri_glyph_of_dispel_magic::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -47569 - Improved Shadowform
class spell_pri_imp_shadowform : public AuraScript
{
PrepareAuraScript(spell_pri_imp_shadowform);
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
if (roll_chance_i(aurEff->GetAmount()))
eventInfo.GetActor()->RemoveMovementImpairingAuras(true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pri_imp_shadowform::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -15337 - Improved Spirit Tap
class spell_pri_improved_spirit_tap : public AuraScript
{
PrepareAuraScript(spell_pri_improved_spirit_tap);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_PRIEST_SHADOW_WORD_DEATH_R1,
SPELL_PRIEST_MIND_BLAST_R1
});
}
bool CheckProc(ProcEventInfo& eventInfo)
{
if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
{
if (spellInfo->IsRankOf(sSpellMgr->AssertSpellInfo(SPELL_PRIEST_SHADOW_WORD_DEATH_R1)) ||
spellInfo->IsRankOf(sSpellMgr->AssertSpellInfo(SPELL_PRIEST_MIND_BLAST_R1)))
return true;
else if (spellInfo->Id == SPELL_PRIEST_MIND_FLAY_DAMAGE)
return roll_chance_i(50);
}
return false;
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_pri_improved_spirit_tap::CheckProc);
}
};
// 40438 - Priest Tier 6 Trinket
class spell_pri_item_t6_trinket : public AuraScript
{
PrepareAuraScript(spell_pri_item_t6_trinket);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_PRIEST_DIVINE_BLESSING,
SPELL_PRIEST_DIVINE_WRATH
});
}
void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActor();
if (eventInfo.GetSpellTypeMask() & PROC_SPELL_TYPE_HEAL)
caster->CastSpell((Unit*)nullptr, SPELL_PRIEST_DIVINE_BLESSING, true);
if (eventInfo.GetSpellTypeMask() & PROC_SPELL_TYPE_DAMAGE)
caster->CastSpell((Unit*)nullptr, SPELL_PRIEST_DIVINE_WRATH, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pri_item_t6_trinket::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 57989 - Shadowfiend Death
class spell_pri_shadowfiend_death : public AuraScript
{
PrepareAuraScript(spell_pri_shadowfiend_death);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA });
}
bool CheckProc(ProcEventInfo& eventInfo)
{
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
if (!damageInfo || !damageInfo->GetDamage())
return false;
Unit* shadowfiend = eventInfo.GetActionTarget();
if (!shadowfiend->GetOwner())
return false;
return shadowfiend->HealthBelowPctDamaged(1, damageInfo->GetDamage());
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActionTarget()->GetOwner();
caster->CastSpell(caster, SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA, aurEff);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_pri_shadowfiend_death::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_pri_shadowfiend_death::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 15286 - Vampiric Embrace
class spell_pri_vampiric_embrace : public AuraScript
{
PrepareAuraScript(spell_pri_vampiric_embrace);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PRIEST_VAMPIRIC_EMBRACE_HEAL });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
if (!damageInfo || !damageInfo->GetDamage())
return;
int32 selfHeal = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount());
int32 partyHeal = selfHeal / 5;
Unit* caster = eventInfo.GetActor();
caster->CastCustomSpell((Unit*)nullptr, SPELL_PRIEST_VAMPIRIC_EMBRACE_HEAL, &partyHeal, &selfHeal, nullptr, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pri_vampiric_embrace::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 28809 - Greater Heal
class spell_pri_t3_4p_bonus : public AuraScript
{
PrepareAuraScript(spell_pri_t3_4p_bonus);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PRIEST_ARMOR_OF_FAITH });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_PRIEST_ARMOR_OF_FAITH, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pri_t3_4p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 37594 - Greater Heal Refund
class spell_pri_t5_heal_2p_bonus : public AuraScript
{
PrepareAuraScript(spell_pri_t5_heal_2p_bonus);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PRIEST_ITEM_EFFICIENCY });
}
bool CheckProc(ProcEventInfo& eventInfo)
{
if (HealInfo* healInfo = eventInfo.GetHealInfo())
if (Unit* healTarget = healInfo->GetTarget())
if (healInfo->GetEffectiveHeal())
if (healTarget->GetHealth() >= healTarget->GetMaxHealth())
return true;
return false;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
{
PreventDefaultAction();
GetTarget()->CastSpell(GetTarget(), SPELL_PRIEST_ITEM_EFFICIENCY, aurEff);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_pri_t5_heal_2p_bonus::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_pri_t5_heal_2p_bonus::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
void AddSC_priest_spell_scripts()
{
RegisterSpellScript(spell_pri_shadowfiend_scaling);
RegisterSpellScript(spell_pri_blessed_recovery);
RegisterSpellScript(spell_pri_circle_of_healing);
RegisterSpellScript(spell_pri_divine_aegis);
RegisterSpellScript(spell_pri_divine_hymn);
@ -941,6 +1326,7 @@ void AddSC_priest_spell_scripts()
RegisterSpellScript(spell_pri_mana_burn);
RegisterSpellScript(spell_pri_mana_leech);
RegisterSpellScript(spell_pri_mind_sear);
new spell_pri_pain_and_suffering_dummy();
RegisterSpellScript(spell_pri_pain_and_suffering_proc);
RegisterSpellScript(spell_pri_penance);
RegisterSpellAndAuraScriptPair(spell_pri_power_word_shield, spell_pri_power_word_shield_aura);
@ -949,4 +1335,14 @@ void AddSC_priest_spell_scripts()
RegisterSpellScript(spell_pri_shadow_word_death);
RegisterSpellScript(spell_pri_vampiric_touch);
RegisterSpellScript(spell_pri_mind_control);
RegisterSpellScript(spell_pri_aq_3p_bonus);
RegisterSpellScript(spell_pri_body_and_soul);
RegisterSpellScript(spell_pri_glyph_of_dispel_magic);
RegisterSpellScript(spell_pri_imp_shadowform);
RegisterSpellScript(spell_pri_improved_spirit_tap);
RegisterSpellScript(spell_pri_item_t6_trinket);
RegisterSpellScript(spell_pri_shadowfiend_death);
RegisterSpellScript(spell_pri_vampiric_embrace);
RegisterSpellScript(spell_pri_t3_4p_bonus);
RegisterSpellScript(spell_pri_t5_heal_2p_bonus);
}

View file

@ -42,6 +42,9 @@ enum RogueSpells
SPELL_ROGUE_SHIV_TRIGGERED = 5940,
SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST = 57933,
SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC = 59628,
SPELL_ROGUE_GLYPH_OF_BACKSTAB_TRIGGER = 63975,
SPELL_ROGUE_QUICK_RECOVERY_ENERGY = 31663,
SPELL_ROGUE_CRIPPLING_POISON = 3409
};
class spell_rog_savage_combat : public AuraScript
@ -126,7 +129,7 @@ class spell_rog_blade_flurry : public AuraScript
CustomSpellValues values;
values.AddSpellMod(SPELLVALUE_BASE_POINT0, damage);
values.AddSpellMod(SPELLVALUE_FORCED_CRIT_RESULT, int32(eventInfo.GetHitMask() & PROC_EX_CRITICAL_HIT));
values.AddSpellMod(SPELLVALUE_FORCED_CRIT_RESULT, int32(eventInfo.GetHitMask() & PROC_HIT_CRITICAL));
GetTarget()->CastCustomSpell(SPELL_ROGUE_BLADE_FLURRY_EXTRA_ATTACK, values, procTarget, TRIGGERED_FULL_MASK, nullptr, aurEff);
}
}
@ -675,6 +678,154 @@ class spell_rog_tricks_of_the_trade_proc : public AuraScript
}
};
// -51664 - Cut to the Chase
class spell_rog_cut_to_the_chase : public AuraScript
{
PrepareAuraScript(spell_rog_cut_to_the_chase);
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
// "refresh your Slice and Dice duration to its 5 combo point maximum"
Unit* caster = eventInfo.GetActor();
// lookup Slice and Dice
if (AuraEffect const* snd = caster->GetAuraEffect(SPELL_AURA_MOD_MELEE_HASTE, SPELLFAMILY_ROGUE, 0x00040000, 0x00000000, 0x00000000, caster->GetGUID()))
{
// Max 5 cp duration
uint32 countMax = snd->GetSpellInfo()->GetMaxDuration();
snd->GetBase()->SetDuration(countMax, true);
snd->GetBase()->SetMaxDuration(snd->GetBase()->GetDuration());
}
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_rog_cut_to_the_chase::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -51625 - Deadly Brew
class spell_rog_deadly_brew : public AuraScript
{
PrepareAuraScript(spell_rog_deadly_brew);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_ROGUE_CRIPPLING_POISON });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_ROGUE_CRIPPLING_POISON, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_rog_deadly_brew::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -31244 - Quick Recovery
class spell_rog_quick_recovery : public AuraScript
{
PrepareAuraScript(spell_rog_quick_recovery);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_ROGUE_QUICK_RECOVERY_ENERGY });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo)
return;
Unit* caster = eventInfo.GetActor();
int32 amount = CalculatePct(spellInfo->CalcPowerCost(caster, spellInfo->GetSchoolMask()), aurEff->GetAmount());
caster->CastCustomSpell(SPELL_ROGUE_QUICK_RECOVERY_ENERGY, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_rog_quick_recovery::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 56800 - Glyph of Backstab (dummy)
class spell_rog_glyph_of_backstab : public AuraScript
{
PrepareAuraScript(spell_rog_glyph_of_backstab);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_ROGUE_GLYPH_OF_BACKSTAB_TRIGGER });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_ROGUE_GLYPH_OF_BACKSTAB_TRIGGER, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_rog_glyph_of_backstab::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -13983 - Setup
class spell_rog_setup : public AuraScript
{
PrepareAuraScript(spell_rog_setup);
bool CheckProc(ProcEventInfo& eventInfo)
{
if (Player* target = GetTarget()->ToPlayer())
if (eventInfo.GetActor() == target->GetSelectedUnit())
return true;
return false;
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_rog_setup::CheckProc);
}
};
// -51627 - Turn the Tables
class spell_rog_turn_the_tables : public AuraScript
{
PrepareAuraScript(spell_rog_turn_the_tables);
bool Validate(SpellInfo const* spellInfo) override
{
return ValidateSpellInfo({ spellInfo->GetEffect(EFFECT_0).TriggerSpell });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
{
PreventDefaultAction();
Unit* caster = GetCaster();
if (!caster)
return;
Unit* target = GetTarget();
target->CastSpell((Unit*)nullptr, GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true, nullptr, aurEff, caster->GetGUID());
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_rog_turn_the_tables::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
void AddSC_rogue_spell_scripts()
{
RegisterSpellScript(spell_rog_savage_combat);
@ -690,4 +841,10 @@ void AddSC_rogue_spell_scripts()
RegisterSpellScript(spell_rog_shiv);
RegisterSpellScript(spell_rog_tricks_of_the_trade);
RegisterSpellScript(spell_rog_tricks_of_the_trade_proc);
RegisterSpellScript(spell_rog_cut_to_the_chase);
RegisterSpellScript(spell_rog_deadly_brew);
RegisterSpellScript(spell_rog_quick_recovery);
RegisterSpellScript(spell_rog_glyph_of_backstab);
RegisterSpellScript(spell_rog_setup);
RegisterSpellScript(spell_rog_turn_the_tables);
}

File diff suppressed because it is too large Load diff

View file

@ -43,6 +43,7 @@ enum WarlockSpells
SPELL_WARLOCK_DEMONIC_EMPOWERMENT_FELGUARD = 54508,
SPELL_WARLOCK_DEMONIC_EMPOWERMENT_FELHUNTER = 54509,
SPELL_WARLOCK_DEMONIC_EMPOWERMENT_IMP = 54444,
SPELL_WARLOCK_DEMONIC_PACT_PROC = 48090,
SPELL_WARLOCK_FEL_SYNERGY_HEAL = 54181,
SPELL_WARLOCK_GLYPH_OF_DRAIN_SOUL_AURA = 58070,
SPELL_WARLOCK_GLYPH_OF_DRAIN_SOUL_PROC = 58068,
@ -58,17 +59,38 @@ enum WarlockSpells
SPELL_WARLOCK_IMPROVED_HEALTH_FUNNEL_BUFF_R2 = 60956,
SPELL_WARLOCK_LIFE_TAP_ENERGIZE = 31818,
SPELL_WARLOCK_LIFE_TAP_ENERGIZE_2 = 32553,
SPELL_WARLOCK_NETHER_PROTECTION_HOLY = 54370,
SPELL_WARLOCK_NETHER_PROTECTION_FIRE = 54371,
SPELL_WARLOCK_NETHER_PROTECTION_FROST = 54372,
SPELL_WARLOCK_NETHER_PROTECTION_ARCANE = 54373,
SPELL_WARLOCK_NETHER_PROTECTION_SHADOW = 54374,
SPELL_WARLOCK_NETHER_PROTECTION_NATURE = 54375,
SPELL_WARLOCK_SOULSHATTER = 32835,
SPELL_WARLOCK_SIPHON_LIFE_HEAL = 63106,
SPELL_WARLOCK_UNSTABLE_AFFLICTION_DISPEL = 31117,
SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_R1 = 18213,
SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_PROC = 18371
SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_PROC = 18371,
SPELL_WARLOCK_GLYPH_OF_LIFE_TAP_TRIGGERED = 63321,
SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R1 = 27285,
SPELL_WARLOCK_SEED_OF_CORRUPTION_GENERIC = 32865,
SPELL_WARLOCK_SHADOW_TRANCE = 17941,
SPELL_WARLOCK_SOUL_LEECH_HEAL = 30294,
SPELL_WARLOCK_IMP_SOUL_LEECH_R1 = 54117,
SPELL_WARLOCK_SOUL_LEECH_PET_MANA_1 = 54607,
SPELL_WARLOCK_SOUL_LEECH_PET_MANA_2 = 59118,
SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_1 = 54300,
SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_2 = 59117,
SPELL_REPLENISHMENT = 57669,
SPELL_WARLOCK_SHADOWFLAME = 37378,
SPELL_WARLOCK_FLAMESHADOW = 37379,
SPELL_WARLOCK_GLYPH_OF_SUCCUBUS = 56250
};
enum WarlockSpellIcons
{
WARLOCK_ICON_ID_IMPROVED_LIFE_TAP = 208,
WARLOCK_ICON_ID_MANA_FEED = 1982
WARLOCK_ICON_ID_MANA_FEED = 1982,
WARLOCK_ICON_ID_DEMONIC_PACT = 3220
};
class spell_warl_eye_of_kilrogg : public AuraScript
@ -637,6 +659,42 @@ class spell_warl_everlasting_affliction : public SpellScript
}
};
// 54909, 53646 - Demonic Pact
class spell_warl_demonic_pact : public AuraScript
{
PrepareAuraScript(spell_warl_demonic_pact);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_WARLOCK_DEMONIC_PACT_PROC });
}
bool CheckProc(ProcEventInfo& eventInfo)
{
return eventInfo.GetActor() && eventInfo.GetActor()->IsPet();
}
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
if (Unit* owner = eventInfo.GetActor()->GetOwner())
{
if (AuraEffect* aurEff = owner->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, WARLOCK_ICON_ID_DEMONIC_PACT, EFFECT_0))
{
int32 bp0 = static_cast<int32>((aurEff->GetAmount() * owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_MAGIC) + 100.0f) / 100.0f);
owner->CastCustomSpell(SPELL_WARLOCK_DEMONIC_PACT_PROC, SPELLVALUE_BASE_POINT0, bp0, (Unit*)nullptr, true, nullptr, aurEff);
}
}
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_warl_demonic_pact::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_warl_demonic_pact::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
// 18541 - Ritual of Doom Effect
class spell_warl_ritual_of_doom_effect : public SpellScript
{
@ -654,6 +712,92 @@ class spell_warl_ritual_of_doom_effect : public SpellScript
}
};
// -27243 - Seed of Corruption
class spell_warl_seed_of_corruption_dummy : public AuraScript
{
PrepareAuraScript(spell_warl_seed_of_corruption_dummy);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R1 });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
if (!damageInfo || !damageInfo->GetDamage())
return;
int32 amount = aurEff->GetAmount() - damageInfo->GetDamage();
if (amount > 0)
{
const_cast<AuraEffect*>(aurEff)->SetAmount(amount);
if (!GetTarget()->HealthBelowPctDamaged(1, damageInfo->GetDamage()))
return;
}
Remove();
Unit* caster = GetCaster();
if (!caster)
return;
uint32 spellId = sSpellMgr->GetSpellWithRank(SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R1, GetSpellInfo()->GetRank());
caster->CastSpell(eventInfo.GetActionTarget(), spellId, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_warl_seed_of_corruption_dummy::HandleProc, EFFECT_1, SPELL_AURA_DUMMY);
}
};
// 32863 - Seed of Corruption
// 36123 - Seed of Corruption
// 38252 - Seed of Corruption
// 39367 - Seed of Corruption
// 44141 - Seed of Corruption
// 70388 - Seed of Corruption
// Monster spells, triggered only on amount drop (not on death)
class spell_warl_seed_of_corruption_generic : public AuraScript
{
PrepareAuraScript(spell_warl_seed_of_corruption_generic);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_WARLOCK_SEED_OF_CORRUPTION_GENERIC });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
if (!damageInfo || !damageInfo->GetDamage())
return;
int32 amount = aurEff->GetAmount() - damageInfo->GetDamage();
if (amount > 0)
{
const_cast<AuraEffect*>(aurEff)->SetAmount(amount);
return;
}
Remove();
Unit* caster = GetCaster();
if (!caster)
return;
caster->CastSpell(eventInfo.GetActionTarget(), SPELL_WARLOCK_SEED_OF_CORRUPTION_GENERIC, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_warl_seed_of_corruption_generic::HandleProc, EFFECT_1, SPELL_AURA_DUMMY);
}
};
// -27285 - Seed of Corruption
class spell_warl_seed_of_corruption : public SpellScript
{
@ -684,6 +828,61 @@ class spell_warl_seed_of_corruption : public SpellScript
}
};
// -30293 - Soul Leech
class spell_warl_soul_leech : public AuraScript
{
PrepareAuraScript(spell_warl_soul_leech);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_WARLOCK_SOUL_LEECH_HEAL,
SPELL_WARLOCK_IMP_SOUL_LEECH_R1,
SPELL_WARLOCK_SOUL_LEECH_PET_MANA_1,
SPELL_WARLOCK_SOUL_LEECH_PET_MANA_2,
SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_1,
SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_2,
SPELL_REPLENISHMENT
});
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
static uint32 const casterMana[2] = { SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_1, SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_2 };
static uint32 const petMana[2] = { SPELL_WARLOCK_SOUL_LEECH_PET_MANA_1, SPELL_WARLOCK_SOUL_LEECH_PET_MANA_2 };
PreventDefaultAction();
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
if (!damageInfo || !damageInfo->GetDamage())
return;
Unit* caster = eventInfo.GetActor();
int32 bp = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount());
caster->CastCustomSpell(SPELL_WARLOCK_SOUL_LEECH_HEAL, SPELLVALUE_BASE_POINT0, bp, caster, true);
// Improved Soul Leech code below
AuraEffect const* impSoulLeech = GetTarget()->GetAuraEffectOfRankedSpell(SPELL_WARLOCK_IMP_SOUL_LEECH_R1, EFFECT_1, aurEff->GetCasterGUID());
if (!impSoulLeech)
return;
uint8 impSoulLeechRank = impSoulLeech->GetSpellInfo()->GetRank();
uint32 selfSpellId = casterMana[impSoulLeechRank - 1];
uint32 petSpellId = petMana[impSoulLeechRank - 1];
caster->CastSpell((Unit*)nullptr, selfSpellId, true);
caster->CastSpell((Unit*)nullptr, petSpellId, true);
if (roll_chance_i(impSoulLeech->GetAmount()))
caster->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_warl_soul_leech::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 29858 - Soulshatter
class spell_warl_soulshatter : public SpellScript
{
@ -813,6 +1012,97 @@ class spell_warl_life_tap : public SpellScript
}
};
// -30299 - Nether Protection
class spell_warl_nether_protection : public AuraScript
{
PrepareAuraScript(spell_warl_nether_protection);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_WARLOCK_NETHER_PROTECTION_HOLY, SPELL_WARLOCK_NETHER_PROTECTION_FIRE, SPELL_WARLOCK_NETHER_PROTECTION_FROST, SPELL_WARLOCK_NETHER_PROTECTION_ARCANE, SPELL_WARLOCK_NETHER_PROTECTION_SHADOW, SPELL_WARLOCK_NETHER_PROTECTION_NATURE });
}
bool CheckProc(ProcEventInfo& eventInfo)
{
if (eventInfo.GetDamageInfo())
{
switch (GetFirstSchoolInMask(eventInfo.GetDamageInfo()->GetSchoolMask()))
{
case SPELL_SCHOOL_HOLY:
case SPELL_SCHOOL_FIRE:
case SPELL_SCHOOL_NATURE:
case SPELL_SCHOOL_FROST:
case SPELL_SCHOOL_SHADOW:
case SPELL_SCHOOL_ARCANE:
return true;
default:
break;
}
}
return false;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
uint32 triggerspell = 0;
switch (GetFirstSchoolInMask(eventInfo.GetDamageInfo()->GetSchoolMask()))
{
case SPELL_SCHOOL_HOLY:
triggerspell = SPELL_WARLOCK_NETHER_PROTECTION_HOLY;
break;
case SPELL_SCHOOL_FIRE:
triggerspell = SPELL_WARLOCK_NETHER_PROTECTION_FIRE;
break;
case SPELL_SCHOOL_NATURE:
triggerspell = SPELL_WARLOCK_NETHER_PROTECTION_NATURE;
break;
case SPELL_SCHOOL_FROST:
triggerspell = SPELL_WARLOCK_NETHER_PROTECTION_FROST;
break;
case SPELL_SCHOOL_SHADOW:
triggerspell = SPELL_WARLOCK_NETHER_PROTECTION_SHADOW;
break;
case SPELL_SCHOOL_ARCANE:
triggerspell = SPELL_WARLOCK_NETHER_PROTECTION_ARCANE;
break;
default:
return;
}
if (Unit* target = eventInfo.GetActionTarget())
target->CastSpell(target, triggerspell, true, nullptr, aurEff);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_warl_nether_protection::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_warl_nether_protection::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
// -63156 - Decimation
class spell_warl_decimation : public AuraScript
{
PrepareAuraScript(spell_warl_decimation);
bool CheckProc(ProcEventInfo& eventInfo)
{
if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
if (eventInfo.GetActionTarget()->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellInfo, eventInfo.GetActor()))
return true;
return false;
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_warl_decimation::CheckProc);
}
};
// 48018 - Demonic Circle: Summon
class spell_warl_demonic_circle_summon : public AuraScript
{
@ -968,6 +1258,31 @@ class spell_warl_haunt_aura : public AuraScript
}
};
// 37377 - Shadowflame
// 39437 - Shadowflame Hellfire and RoF
template <uint32 TriggerSpellId>
class spell_warl_t4_2p_bonus : public AuraScript
{
PrepareAuraScript(spell_warl_t4_2p_bonus);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ TriggerSpellId });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActor();
caster->CastSpell(caster, TriggerSpellId, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_warl_t4_2p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// -30108 - Unstable Affliction
class spell_warl_unstable_affliction : public AuraScript
{
@ -1098,6 +1413,53 @@ class spell_warl_shadow_ward : public AuraScript
}
};
// -18094 - Nightfall
// 56218 - Glyph of Corruption
class spell_warl_glyph_of_corruption_nightfall : public AuraScript
{
PrepareAuraScript(spell_warl_glyph_of_corruption_nightfall);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_WARLOCK_SHADOW_TRANCE });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActor();
caster->CastSpell(caster, SPELL_WARLOCK_SHADOW_TRANCE, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_warl_glyph_of_corruption_nightfall::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 63320 - Glyph of Life Tap
class spell_warl_glyph_of_life_tap : public AuraScript
{
PrepareAuraScript(spell_warl_glyph_of_life_tap);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_WARLOCK_GLYPH_OF_LIFE_TAP_TRIGGERED });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActor();
caster->CastSpell(caster, SPELL_WARLOCK_GLYPH_OF_LIFE_TAP_TRIGGERED, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_warl_glyph_of_life_tap::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 63310 - Glyph of Shadowflame
class spell_warl_glyph_of_shadowflame : public AuraScript
{
@ -1292,6 +1654,7 @@ void AddSC_warlock_spell_scripts()
RegisterSpellAndAuraScriptPair(spell_warl_haunt, spell_warl_haunt_aura);
RegisterSpellScript(spell_warl_health_funnel);
RegisterSpellScript(spell_warl_life_tap);
RegisterSpellScript(spell_warl_nether_protection);
RegisterSpellScript(spell_warl_ritual_of_doom_effect);
RegisterSpellScript(spell_warl_seed_of_corruption);
RegisterSpellScript(spell_warl_shadow_ward);
@ -1299,6 +1662,15 @@ void AddSC_warlock_spell_scripts()
RegisterSpellScript(spell_warl_soulshatter);
RegisterSpellScript(spell_warl_unstable_affliction);
RegisterSpellScript(spell_warl_drain_soul);
RegisterSpellScript(spell_warl_demonic_pact);
RegisterSpellScript(spell_warl_decimation);
RegisterSpellScript(spell_warl_seed_of_corruption_dummy);
RegisterSpellScript(spell_warl_seed_of_corruption_generic);
RegisterSpellScript(spell_warl_soul_leech);
RegisterSpellScriptWithArgs(spell_warl_t4_2p_bonus<SPELL_WARLOCK_FLAMESHADOW>, "spell_warl_t4_2p_bonus_shadow");
RegisterSpellScriptWithArgs(spell_warl_t4_2p_bonus<SPELL_WARLOCK_SHADOWFLAME>, "spell_warl_t4_2p_bonus_fire");
RegisterSpellScript(spell_warl_glyph_of_corruption_nightfall);
RegisterSpellScript(spell_warl_glyph_of_life_tap);
RegisterSpellScript(spell_warl_shadowburn);
RegisterSpellScript(spell_warl_glyph_of_felguard);
}

View file

@ -35,6 +35,7 @@ enum WarriorSpells
SPELL_WARRIOR_IMPROVED_SPELL_REFLECTION_TRIGGER = 59725,
SPELL_WARRIOR_BLOODTHIRST = 23885,
SPELL_WARRIOR_BLOODTHIRST_DAMAGE = 23881,
SPELL_WARRIOR_BLOODSURGE_R1 = 29723,
SPELL_WARRIOR_CHARGE = 34846,
SPELL_WARRIOR_DAMAGE_SHIELD_DAMAGE = 59653,
SPELL_WARRIOR_DEEP_WOUNDS_RANK_1 = 12162,
@ -42,6 +43,8 @@ enum WarriorSpells
SPELL_WARRIOR_DEEP_WOUNDS_RANK_3 = 12868,
SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC = 12721,
SPELL_WARRIOR_EXECUTE = 20647,
SPELL_WARRIOR_EXECUTE_GCD_REDUCED = 71069,
SPELL_WARRIOR_EXTRA_CHARGE = 70849,
SPELL_WARRIOR_GLYPH_OF_EXECUTION = 58367,
SPELL_WARRIOR_GLYPH_OF_VIGILANCE = 63326,
SPELL_WARRIOR_JUGGERNAUT_CRIT_BONUS_BUFF = 65156,
@ -49,6 +52,8 @@ enum WarriorSpells
SPELL_WARRIOR_LAST_STAND_TRIGGERED = 12976,
SPELL_WARRIOR_RETALIATION_DAMAGE = 22858,
SPELL_WARRIOR_SLAM = 50783,
SPELL_WARRIOR_SLAM_GCD_REDUCED = 71072,
SPELL_WARRIOR_SUDDEN_DEATH_R1 = 46913,
SPELL_WARRIOR_SUNDER_ARMOR = 58567,
SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK_1 = 12723,
SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK_2 = 26654,
@ -59,6 +64,11 @@ enum WarriorSpells
SPELL_WARRIOR_UNRELENTING_ASSAULT_TRIGGER_2 = 64850,
SPELL_WARRIOR_VIGILANCE_PROC = 50725,
SPELL_WARRIOR_VIGILANCE_REDIRECT_THREAT = 59665,
SPELL_WARRIOR_SECOND_WIND_TRIGGER_1 = 29841,
SPELL_WARRIOR_SECOND_WIND_TRIGGER_2 = 29842,
SPELL_WARRIOR_GLYPH_OF_BLOCKING = 58374,
SPELL_WARRIOR_STOICISM = 70845,
SPELL_WARRIOR_T10_MELEE_4P_BONUS = 70847,
SPELL_WARRIOR_WHIRLWIND_OFF = 44949
};
@ -73,6 +83,7 @@ enum MiscSpells
SPELL_PALADIN_GREATER_BLESSING_OF_SANCTUARY = 25899,
SPELL_PRIEST_RENEWED_HOPE = 63944,
SPELL_GEN_DAMAGE_REDUCTION_AURA = 68066,
SPELL_CATEGORY_SHIELD_SLAM = 1209
};
class spell_warr_mocking_blow : public SpellScript
@ -224,6 +235,31 @@ class spell_warr_improved_spell_reflection_trigger_aura : public AuraScript
}
};
// 70844 - Item - Warrior T10 Protection 4P Bonus
class spell_warr_item_t10_prot_4p_bonus : public AuraScript
{
PrepareAuraScript(spell_warr_item_t10_prot_4p_bonus);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_WARRIOR_STOICISM });
}
void HandleProc(ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* target = eventInfo.GetActionTarget();
int32 bp0 = CalculatePct(target->GetMaxHealth(), GetSpellInfo()->Effects[EFFECT_1].CalcValue());
target->CastCustomSpell(SPELL_WARRIOR_STOICISM, SPELLVALUE_BASE_POINT0, bp0, (Unit*)nullptr, true);
}
void Register() override
{
OnProc += AuraProcFn(spell_warr_item_t10_prot_4p_bonus::HandleProc);
}
};
// 12975 - Last Stand
class spell_warr_last_stand : public SpellScript
{
@ -254,7 +290,13 @@ class spell_warr_deep_wounds : public SpellScript
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC });
return ValidateSpellInfo(
{
SPELL_WARRIOR_DEEP_WOUNDS_RANK_1,
SPELL_WARRIOR_DEEP_WOUNDS_RANK_2,
SPELL_WARRIOR_DEEP_WOUNDS_RANK_3,
SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC
});
}
void HandleDummy(SpellEffIndex /*effIndex*/)
@ -269,7 +311,7 @@ class spell_warr_deep_wounds : public SpellScript
ApplyPct(damage, 16.0f * GetSpellInfo()->GetRank() / 6.0f);
target->CastDelayedSpellWithPeriodicAmount(caster, SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC, SPELL_AURA_PERIODIC_DAMAGE, damage, EFFECT_0);
//caster->CastCustomSpell(target, SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC, &damage, nullptr, nullptr, true);
caster->CastCustomSpell(target, SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC, &damage, nullptr, nullptr, true);
}
}
@ -373,6 +415,47 @@ class spell_warr_damage_shield : public AuraScript
}
};
// -12834 - Deep Wounds Aura
class spell_warr_deep_wounds_aura : public AuraScript
{
PrepareAuraScript(spell_warr_deep_wounds_aura);
bool Validate(SpellInfo const* spellInfo) override
{
return ValidateSpellInfo({ spellInfo->GetEffect(EFFECT_0).TriggerSpell });
}
bool CheckProc(ProcEventInfo& eventInfo)
{
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
if (!damageInfo)
return false;
return eventInfo.GetActor()->GetTypeId() == TYPEID_PLAYER;
}
void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* actor = eventInfo.GetActor();
float damage = 0.f;
if (eventInfo.GetDamageInfo()->GetAttackType() == OFF_ATTACK)
damage = (actor->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + actor->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE)) / 2.f;
else
damage = (actor->GetFloatValue(UNIT_FIELD_MINDAMAGE) + actor->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2.f;
actor->CastCustomSpell(GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, SPELLVALUE_BASE_POINT0, int32(damage), eventInfo.GetProcTarget(), true, nullptr, aurEff);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_warr_deep_wounds_aura::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_warr_deep_wounds_aura::OnProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
// -5308 - Execute
class spell_warr_execute : public SpellScript
{
@ -430,6 +513,71 @@ class spell_warr_execute : public SpellScript
}
};
// -29723 - Sudden Death
// -46913 - Bloodsurge
class spell_warr_extra_proc : public AuraScript
{
PrepareAuraScript(spell_warr_extra_proc);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_WARRIOR_T10_MELEE_4P_BONUS,
SPELL_WARRIOR_EXTRA_CHARGE,
SPELL_WARRIOR_SLAM_GCD_REDUCED,
SPELL_WARRIOR_EXECUTE_GCD_REDUCED
});
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
{
Unit* target = GetTarget();
AuraEffect const* bonusAurEff = target->GetAuraEffect(SPELL_WARRIOR_T10_MELEE_4P_BONUS, EFFECT_0);
if (!bonusAurEff)
return;
if (!roll_chance_i(bonusAurEff->GetAmount()))
return;
target->CastSpell((Unit*)nullptr, SPELL_WARRIOR_EXTRA_CHARGE, true, nullptr, aurEff);
SpellInfo const* auraInfo = aurEff->GetSpellInfo();
if (auraInfo->IsRankOf(sSpellMgr->AssertSpellInfo(SPELL_WARRIOR_BLOODSURGE_R1)))
target->CastSpell((Unit*)nullptr, SPELL_WARRIOR_SLAM_GCD_REDUCED, true, nullptr, aurEff);
else if (auraInfo->IsRankOf(sSpellMgr->AssertSpellInfo(SPELL_WARRIOR_SUDDEN_DEATH_R1)))
target->CastSpell((Unit*)nullptr, SPELL_WARRIOR_EXECUTE_GCD_REDUCED, true, nullptr, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_warr_extra_proc::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
// 58375 - Glyph of Blocking
class spell_warr_glyph_of_blocking : public AuraScript
{
PrepareAuraScript(spell_warr_glyph_of_blocking);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_WARRIOR_GLYPH_OF_BLOCKING });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
Unit* caster = eventInfo.GetActor();
caster->CastSpell(caster, SPELL_WARRIOR_GLYPH_OF_BLOCKING, aurEff);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_warr_glyph_of_blocking::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 12809 - Concussion Blow
class spell_warr_concussion_blow : public SpellScript
{
@ -588,6 +736,46 @@ class spell_warr_rend : public AuraScript
}
};
// -29834 - Second Wind
class spell_warr_second_wind : public AuraScript
{
PrepareAuraScript(spell_warr_second_wind);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_WARRIOR_SECOND_WIND_TRIGGER_1,
SPELL_WARRIOR_SECOND_WIND_TRIGGER_2
});
}
bool CheckProc(ProcEventInfo& eventInfo)
{
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo)
return false;
return (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_STUN))) != 0;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
static uint32 const triggeredSpells[2] = { SPELL_WARRIOR_SECOND_WIND_TRIGGER_1, SPELL_WARRIOR_SECOND_WIND_TRIGGER_2 };
PreventDefaultAction();
Unit* caster = eventInfo.GetActionTarget();
uint32 spellId = triggeredSpells[GetSpellInfo()->GetRank() - 1];
caster->CastSpell(caster, spellId, aurEff);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_warr_second_wind::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_warr_second_wind::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 64380, 65941 - Shattering Throw
class spell_warr_shattering_throw : public SpellScript
{
@ -678,6 +866,30 @@ private:
Unit* _procTarget = nullptr;
};
// 28845 - Cheat Death
class spell_warr_t3_prot_8p_bonus : public AuraScript
{
PrepareAuraScript(spell_warr_t3_prot_8p_bonus);
bool CheckProc(ProcEventInfo& eventInfo)
{
if (eventInfo.GetActionTarget()->HealthBelowPct(20))
return true;
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
if (damageInfo && damageInfo->GetDamage())
if (GetTarget()->HealthBelowPctDamaged(20, damageInfo->GetDamage()))
return true;
return false;
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_warr_t3_prot_8p_bonus::CheckProc);
}
};
// 50720 - Vigilance
class spell_warr_vigilance : public AuraScript
{
@ -812,38 +1024,6 @@ class spell_warr_glyph_of_sunder_armor : public AuraScript
}
};
// Spell 28845 - Cheat Death
enum CheatDeath
{
SPELL_CHEAT_DEATH_TRIGGER = 28846
};
class spell_warr_t3_prot_8p_bonus : public AuraScript
{
PrepareAuraScript(spell_warr_t3_prot_8p_bonus);
bool CheckProc(ProcEventInfo& eventInfo)
{
return eventInfo.GetActionTarget() && eventInfo.GetActionTarget()->GetHealthPct() <= 20.0f;
}
void HandleEffectProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
if (Unit* target = eventInfo.GetActionTarget())
{
target->CastSpell(target, SPELL_CHEAT_DEATH_TRIGGER, true);
}
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_warr_t3_prot_8p_bonus::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_warr_t3_prot_8p_bonus::HandleEffectProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
// 20230 - Retaliation
class spell_warr_retaliation : public AuraScript
{
@ -904,4 +1084,10 @@ void AddSC_warrior_spell_scripts()
RegisterSpellScript(spell_warr_vigilance);
RegisterSpellScript(spell_warr_vigilance_trigger);
RegisterSpellScript(spell_warr_t3_prot_8p_bonus);
RegisterSpellScript(spell_warr_item_t10_prot_4p_bonus);
RegisterSpellScript(spell_warr_deep_wounds_aura);
RegisterSpellScript(spell_warr_extra_proc);
RegisterSpellScript(spell_warr_glyph_of_blocking);
RegisterSpellScript(spell_warr_second_wind);
RegisterSpellScript(spell_warr_t3_prot_8p_bonus);
}

View file

@ -1676,7 +1676,7 @@ struct SpellEntry
std::array<uint32, 2> SpellVisual; // 131-132 m_spellVisualID
uint32 SpellIconID; // 133 m_spellIconID
uint32 ActiveIconID; // 134 m_activeIconID
uint32 SpellPriority; // 135 not used
uint32 SpellPriority; // 135
std::array<char const*, 16> SpellName; // 136-151 m_name_lang
//uint32 SpellNameFlag; // 152 not used
std::array<char const*, 16> Rank; // 153-168 m_nameSubtext_lang

View file

@ -455,7 +455,7 @@ enum SpellAttr2 : uint32
SPELL_ATTR2_IGNORE_WEAPONSKILL = 0x08000000, // TITLE Unknown attribute 27@Attr2
SPELL_ATTR2_NOT_AN_ACTION = 0x10000000, // TITLE Unknown attribute 28@Attr2
SPELL_ATTR2_CANT_CRIT = 0x20000000, // TITLE Cannot critically strike
SPELL_ATTR2_ACTIVE_THREAT = 0x40000000, // TITLE Allow triggered spell to trigger (type 1) DESCRIPTION Without this attribute, any triggered spell will be unable to trigger other auras' procs
SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC = 0x40000000, // TITLE Allow triggered spell to trigger (type 1) DESCRIPTION Without this attribute, any triggered spell will be unable to trigger other auras' procs
SPELL_ATTR2_RETAIN_ITEM_CAST = 0x80000000 // TITLE Food buff (client only)
};
@ -471,7 +471,7 @@ enum SpellAttr3 : uint32
SPELL_ATTR3_NO_AVOIDANCE = 0x00000040, // TITLE Unknown attribute 6@Attr3
SPELL_ATTR3_DOT_STACKING_RULE = 0x00000080, // TITLE Stack separately for each caster
SPELL_ATTR3_ONLY_ON_PLAYER = 0x00000100, // TITLE Can only target players
SPELL_ATTR3_NOT_A_PROC = 0x00000200, // TITLE Allow triggered spell to trigger (type 2) DESCRIPTION Without this attribute, any triggered spell will be unable to trigger other auras' procs
SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2 = 0x00000200, // TITLE Allow triggered spell to trigger (type 2) DESCRIPTION Without this attribute, any triggered spell will be unable to trigger other auras' procs
SPELL_ATTR3_REQUIRES_MAIN_HAND_WEAPON = 0x00000400, // TITLE Require main hand weapon
SPELL_ATTR3_ONLY_BATTLEGROUNDS = 0x00000800, // TITLE Can only be cast in battleground
SPELL_ATTR3_ONLY_ON_GHOSTS = 0x00001000, // TITLE Can only target ghost players
@ -481,14 +481,14 @@ enum SpellAttr3 : uint32
SPELL_ATTR3_SUPRESS_CASTER_PROCS = 0x00010000, // TITLE Cannot trigger procs
SPELL_ATTR3_SUPRESS_TARGET_PROCS = 0x00020000, // TITLE No initial aggro
SPELL_ATTR3_ALWAYS_HIT = 0x00040000, // TITLE Ignore hit result DESCRIPTION Spell cannot miss, or be dodged/parried/blocked
SPELL_ATTR3_INSTANT_TARGET_PROCS = 0x00080000, // TITLE Cannot trigger spells during aura proc
SPELL_ATTR3_DISABLE_PROC = 0x00080000, // TITLE Cannot trigger spells during aura proc
SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD = 0x00100000, // TITLE Persists through death
SPELL_ATTR3_ONLY_PROC_OUTDOORS = 0x00200000, // TITLE Unknown attribute 21@Attr3
SPELL_ATTR3_CASTING_CANCELS_AUTOREPEAT = 0x00400000, // TITLE Requires equipped Wand (Mainline: Do Not Trigger Target Stand)
SPELL_ATTR3_NO_DAMAGE_HISTORY = 0x00800000, // TITLE Unknown attribute 23@Attr3
SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON = 0x01000000, // TITLE Requires offhand weapon
SPELL_ATTR3_TREAT_AS_PERIODIC = 0x02000000, // TITLE Treat as periodic effect
SPELL_ATTR3_CAN_PROC_FROM_PROCS = 0x04000000, // TITLE Can trigger from triggered spells
SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED = 0x04000000, // TITLE Can trigger from triggered spells
SPELL_ATTR3_ONLY_PROC_ON_CASTER = 0x08000000, // TITLE Drain Soul
SPELL_ATTR3_IGNORE_CASTER_AND_TARGET_RESTRICTIONS = 0x10000000, // TITLE Unknown attribute 28@Attr3
SPELL_ATTR3_IGNORE_CASTER_MODIFIERS = 0x20000000, // TITLE Damage dealt is unaffected by modifiers
@ -3225,7 +3225,7 @@ enum DiminishingReturnsType
};
// Diminishing Return Groups
enum DiminishingGroup
enum DiminishingGroup : uint16
{
DIMINISHING_NONE = 0,
DIMINISHING_BANISH = 1,

View file

@ -445,7 +445,7 @@ AC_API_EXPORT EnumText EnumUtils<SpellAttr2>::ToString(SpellAttr2 value)
case SPELL_ATTR2_IGNORE_WEAPONSKILL: return { "SPELL_ATTR2_IGNORE_WEAPONSKILL", "Unknown attribute 27@Attr2", "" };
case SPELL_ATTR2_NOT_AN_ACTION: return { "SPELL_ATTR2_NOT_AN_ACTION", "Unknown attribute 28@Attr2", "" };
case SPELL_ATTR2_CANT_CRIT: return { "SPELL_ATTR2_CANT_CRIT", "Cannot critically strike", "" };
case SPELL_ATTR2_ACTIVE_THREAT: return { "SPELL_ATTR2_ACTIVE_THREAT", "Allow triggered spell to trigger (type 1)", "Without this attribute, any triggered spell will be unable to trigger other auras' procs" };
case SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC: return { "SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC", "Allow triggered spell to trigger (type 1)", "Without this attribute, any triggered spell will be unable to trigger other auras' procs" };
case SPELL_ATTR2_RETAIN_ITEM_CAST: return { "SPELL_ATTR2_RETAIN_ITEM_CAST", "Food buff (client only)", "" };
default: throw std::out_of_range("value");
}
@ -489,7 +489,7 @@ AC_API_EXPORT SpellAttr2 EnumUtils<SpellAttr2>::FromIndex(size_t index)
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 30: return SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC;
case 31: return SPELL_ATTR2_RETAIN_ITEM_CAST;
default: throw std::out_of_range("index");
}
@ -530,7 +530,7 @@ AC_API_EXPORT size_t EnumUtils<SpellAttr2>::ToIndex(SpellAttr2 value)
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_TRIGGERED_CAN_TRIGGER_PROC: return 30;
case SPELL_ATTR2_RETAIN_ITEM_CAST: return 31;
default: throw std::out_of_range("value");
}
@ -553,7 +553,7 @@ AC_API_EXPORT EnumText EnumUtils<SpellAttr3>::ToString(SpellAttr3 value)
case SPELL_ATTR3_NO_AVOIDANCE: return { "SPELL_ATTR3_NO_AVOIDANCE", "Unknown attribute 6@Attr3", "" };
case SPELL_ATTR3_DOT_STACKING_RULE: return { "SPELL_ATTR3_DOT_STACKING_RULE", "Stack separately for each caster", "" };
case SPELL_ATTR3_ONLY_ON_PLAYER: return { "SPELL_ATTR3_ONLY_ON_PLAYER", "Can only target players", "" };
case SPELL_ATTR3_NOT_A_PROC: return { "SPELL_ATTR3_NOT_A_PROC", "Allow triggered spell to trigger (type 2)", "Without this attribute, any triggered spell will be unable to trigger other auras' procs" };
case SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2: return { "SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2", "Allow triggered spell to trigger (type 2)", "Without this attribute, any triggered spell will be unable to trigger other auras' procs" };
case SPELL_ATTR3_REQUIRES_MAIN_HAND_WEAPON: return { "SPELL_ATTR3_REQUIRES_MAIN_HAND_WEAPON", "Require main hand weapon", "" };
case SPELL_ATTR3_ONLY_BATTLEGROUNDS: return { "SPELL_ATTR3_ONLY_BATTLEGROUNDS", "Can only be cast in battleground", "" };
case SPELL_ATTR3_ONLY_ON_GHOSTS: return { "SPELL_ATTR3_ONLY_ON_GHOSTS", "Can only target ghost players", "" };
@ -563,14 +563,14 @@ AC_API_EXPORT EnumText EnumUtils<SpellAttr3>::ToString(SpellAttr3 value)
case SPELL_ATTR3_SUPRESS_CASTER_PROCS: return { "SPELL_ATTR3_SUPRESS_CASTER_PROCS", "Cannot trigger procs", "" };
case SPELL_ATTR3_SUPRESS_TARGET_PROCS: return { "SPELL_ATTR3_SUPRESS_TARGET_PROCS", "No initial aggro", "" };
case SPELL_ATTR3_ALWAYS_HIT: return { "SPELL_ATTR3_ALWAYS_HIT", "Ignore hit result", "Spell cannot miss, or be dodged/parried/blocked" };
case SPELL_ATTR3_INSTANT_TARGET_PROCS: return { "SPELL_ATTR3_INSTANT_TARGET_PROCS", "Cannot trigger spells during aura proc", "" };
case SPELL_ATTR3_DISABLE_PROC: return { "SPELL_ATTR3_DISABLE_PROC", "Cannot trigger spells during aura proc", "" };
case SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD: return { "SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD", "Persists through death", "" };
case SPELL_ATTR3_ONLY_PROC_OUTDOORS: return { "SPELL_ATTR3_ONLY_PROC_OUTDOORS", "Unknown attribute 21@Attr3", "" };
case SPELL_ATTR3_CASTING_CANCELS_AUTOREPEAT: return { "SPELL_ATTR3_CASTING_CANCELS_AUTOREPEAT", "Requires equipped Wand (Mainline: Do Not Trigger Target Stand)", "" };
case SPELL_ATTR3_NO_DAMAGE_HISTORY: return { "SPELL_ATTR3_NO_DAMAGE_HISTORY", "Unknown attribute 23@Attr3", "" };
case SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON: return { "SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON", "Requires offhand weapon", "" };
case SPELL_ATTR3_TREAT_AS_PERIODIC: return { "SPELL_ATTR3_TREAT_AS_PERIODIC", "Treat as periodic effect", "" };
case SPELL_ATTR3_CAN_PROC_FROM_PROCS: return { "SPELL_ATTR3_CAN_PROC_FROM_PROCS", "Can trigger from triggered spells", "" };
case SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED: return { "SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED", "Can trigger from triggered spells", "" };
case SPELL_ATTR3_ONLY_PROC_ON_CASTER: return { "SPELL_ATTR3_ONLY_PROC_ON_CASTER", "Drain Soul", "" };
case SPELL_ATTR3_IGNORE_CASTER_AND_TARGET_RESTRICTIONS: return { "SPELL_ATTR3_IGNORE_CASTER_AND_TARGET_RESTRICTIONS", "Unknown attribute 28@Attr3", "" };
case SPELL_ATTR3_IGNORE_CASTER_MODIFIERS: return { "SPELL_ATTR3_IGNORE_CASTER_MODIFIERS", "Damage dealt is unaffected by modifiers", "" };
@ -597,7 +597,7 @@ AC_API_EXPORT SpellAttr3 EnumUtils<SpellAttr3>::FromIndex(size_t index)
case 6: return SPELL_ATTR3_NO_AVOIDANCE;
case 7: return SPELL_ATTR3_DOT_STACKING_RULE;
case 8: return SPELL_ATTR3_ONLY_ON_PLAYER;
case 9: return SPELL_ATTR3_NOT_A_PROC;
case 9: return SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2;
case 10: return SPELL_ATTR3_REQUIRES_MAIN_HAND_WEAPON;
case 11: return SPELL_ATTR3_ONLY_BATTLEGROUNDS;
case 12: return SPELL_ATTR3_ONLY_ON_GHOSTS;
@ -607,14 +607,14 @@ AC_API_EXPORT SpellAttr3 EnumUtils<SpellAttr3>::FromIndex(size_t index)
case 16: return SPELL_ATTR3_SUPRESS_CASTER_PROCS;
case 17: return SPELL_ATTR3_SUPRESS_TARGET_PROCS;
case 18: return SPELL_ATTR3_ALWAYS_HIT;
case 19: return SPELL_ATTR3_INSTANT_TARGET_PROCS;
case 19: return SPELL_ATTR3_DISABLE_PROC;
case 20: return SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD;
case 21: return SPELL_ATTR3_ONLY_PROC_OUTDOORS;
case 22: return SPELL_ATTR3_CASTING_CANCELS_AUTOREPEAT;
case 23: return SPELL_ATTR3_NO_DAMAGE_HISTORY;
case 24: return SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON;
case 25: return SPELL_ATTR3_TREAT_AS_PERIODIC;
case 26: return SPELL_ATTR3_CAN_PROC_FROM_PROCS;
case 26: return SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED;
case 27: return SPELL_ATTR3_ONLY_PROC_ON_CASTER;
case 28: return SPELL_ATTR3_IGNORE_CASTER_AND_TARGET_RESTRICTIONS;
case 29: return SPELL_ATTR3_IGNORE_CASTER_MODIFIERS;
@ -638,7 +638,7 @@ AC_API_EXPORT size_t EnumUtils<SpellAttr3>::ToIndex(SpellAttr3 value)
case SPELL_ATTR3_NO_AVOIDANCE: return 6;
case SPELL_ATTR3_DOT_STACKING_RULE: return 7;
case SPELL_ATTR3_ONLY_ON_PLAYER: return 8;
case SPELL_ATTR3_NOT_A_PROC: return 9;
case SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2: return 9;
case SPELL_ATTR3_REQUIRES_MAIN_HAND_WEAPON: return 10;
case SPELL_ATTR3_ONLY_BATTLEGROUNDS: return 11;
case SPELL_ATTR3_ONLY_ON_GHOSTS: return 12;
@ -648,14 +648,14 @@ AC_API_EXPORT size_t EnumUtils<SpellAttr3>::ToIndex(SpellAttr3 value)
case SPELL_ATTR3_SUPRESS_CASTER_PROCS: return 16;
case SPELL_ATTR3_SUPRESS_TARGET_PROCS: return 17;
case SPELL_ATTR3_ALWAYS_HIT: return 18;
case SPELL_ATTR3_INSTANT_TARGET_PROCS: return 19;
case SPELL_ATTR3_DISABLE_PROC: return 19;
case SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD: return 20;
case SPELL_ATTR3_ONLY_PROC_OUTDOORS: return 21;
case SPELL_ATTR3_CASTING_CANCELS_AUTOREPEAT: return 22;
case SPELL_ATTR3_NO_DAMAGE_HISTORY: return 23;
case SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON: return 24;
case SPELL_ATTR3_TREAT_AS_PERIODIC: return 25;
case SPELL_ATTR3_CAN_PROC_FROM_PROCS: return 26;
case SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED: return 26;
case SPELL_ATTR3_ONLY_PROC_ON_CASTER: return 27;
case SPELL_ATTR3_IGNORE_CASTER_AND_TARGET_RESTRICTIONS: return 28;
case SPELL_ATTR3_IGNORE_CASTER_MODIFIERS: return 29;