Revert "Core/Spells: Implementation of QAston proc system"

This reverts commit a70e4e26b3.
This commit is contained in:
Aokromes committed 2016-10-21 07:27:04 +02:00
1 parent f9ebb50a8a
commit 57d0a5d16d
22 files changed
+3878 -1188

No files matched your search

+1 -1
View File
@@ -602,7 +602,7 @@ enum RBACPermissions
RBAC_PERM_COMMAND_RELOAD_SPELL_LOOT_TEMPLATE = 695,
RBAC_PERM_COMMAND_RELOAD_SPELL_LINKED_SPELL = 696,
RBAC_PERM_COMMAND_RELOAD_SPELL_PET_AURAS = 697,
// 698 - reuse
RBAC_PERM_COMMAND_RELOAD_SPELL_PROC_EVENT = 698,
RBAC_PERM_COMMAND_RELOAD_SPELL_PROC = 699,
RBAC_PERM_COMMAND_RELOAD_SPELL_SCRIPTS = 700,
RBAC_PERM_COMMAND_RELOAD_SPELL_TARGET_POSITION = 701,
+1 -1
View File
@@ -44,7 +44,7 @@ float ThreatCalcHelper::calcThreat(Unit* hatedUnit, Unit* /*hatingUnit*/, float
return threat;
if (Player* modOwner = hatedUnit->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_THREAT>(threatSpell->Id, threat);
modOwner->ApplySpellMod(threatSpell->Id, SPELLMOD_THREAT, threat);
}
return hatedUnit->ApplyTotalThreatModifier(threat, schoolMask);
+106 -63
View File
@@ -8184,10 +8184,8 @@ void Player::UpdateEquipSpellsAtFormChange()
}
}
}
void Player::CastItemCombatSpell(DamageInfo const& damageInfo)
void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx)
{
Unit* target = damageInfo.GetVictim();
if (!target || !target->IsAlive() || target == this)
return;
@@ -8195,9 +8193,7 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo)
{
// If usable, try to cast item spell
if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
if (!item->IsBroken() && CanUseAttackType(damageInfo.GetAttackType()))
{
if (!item->IsBroken() && CanUseAttackType(attType))
if (ItemTemplate const* proto = item->GetTemplate())
{
// Additional check for weapons
@@ -8205,42 +8201,31 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo)
{
// offhand item cannot proc from main hand hit etc
EquipmentSlots slot;
switch (damageInfo.GetAttackType())
switch (attType)
{
case BASE_ATTACK:
slot = EQUIPMENT_SLOT_MAINHAND;
break;
case OFF_ATTACK:
slot = EQUIPMENT_SLOT_OFFHAND;
break;
case RANGED_ATTACK:
slot = EQUIPMENT_SLOT_RANGED;
break;
default:
slot = EQUIPMENT_SLOT_END;
break;
case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
default: slot = EQUIPMENT_SLOT_END; break;
}
if (slot != i)
continue;
// Check if item is useable (forms or disarm)
if (damageInfo.GetAttackType() == BASE_ATTACK)
if (attType == BASE_ATTACK)
if (!IsUseEquipedWeapon(true) && !IsInFeralForm())
continue;
}
CastItemCombatSpell(damageInfo, item, proto);
CastItemCombatSpell(target, attType, procVictim, procEx, item, proto);
}
}
}
}
}
void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemTemplate const* proto)
void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item* item, ItemTemplate const* proto)
{
// Can do effect if any damage done to target
// 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) {
if (procVictim & PROC_FLAG_TAKEN_DAMAGE)
//if (damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE)
{
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
_Spell const& spellData = proto->Spells[i];
@@ -8269,14 +8254,14 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT
if (proto->SpellPPMRate)
{
uint32 WeaponSpeed = GetAttackTime(damageInfo.GetAttackType());
uint32 WeaponSpeed = GetAttackTime(attType);
chance = GetPPMProcChance(WeaponSpeed, proto->SpellPPMRate, spellInfo);
}
else if (chance > 100.0f)
chance = GetWeaponProcChance();
if (roll_chance_f(chance))
CastSpell(damageInfo.GetVictim(), spellInfo->Id, true, item);
CastSpell(target, spellInfo->Id, true, item);
}
}
@@ -8297,17 +8282,18 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT
continue;
SpellEnchantProcEntry const* entry = sSpellMgr->GetSpellEnchantProcEvent(enchant_id);
if (entry && entry->procEx)
{
// Check hit/crit/dodge/parry requirement
if ((entry->procEx & damageInfo.GetHitMask()) == 0)
if ((entry->procEx & procEx) == 0)
continue;
}
else
{
// Can do effect if any damage done to target
// for done procs allow normal + critical + absorbs by default
if (!canTrigger)
if (!(procVictim & PROC_FLAG_TAKEN_DAMAGE))
//if (!(damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE))
continue;
}
@@ -8320,6 +8306,7 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT
}
float chance = pEnchant->amount[s] != 0 ? float(pEnchant->amount[s]) : GetWeaponProcChance();
if (entry)
{
if (entry->PPMChance)
@@ -8329,7 +8316,7 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT
}
// Apply spell mods
ApplySpellMod<SPELLMOD_CHANCE_OF_SUCCESS>(pEnchant->spellid[s], chance);
ApplySpellMod(pEnchant->spellid[s], SPELLMOD_CHANCE_OF_SUCCESS, chance);
// Shiv has 100% chance to apply the poison
if (FindCurrentSpellBySpellId(5938) && e_slot == TEMP_ENCHANTMENT_SLOT)
@@ -8340,7 +8327,7 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT
if (spellInfo->IsPositive())
CastSpell(this, spellInfo, true, item);
else
CastSpell(damageInfo.GetVictim(), spellInfo, true, item);
CastSpell(target, spellInfo, true, item);
}
}
}
@@ -21201,8 +21188,8 @@ bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod
if (!mod || !spellInfo)
return false;
// 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))
// Mod out of charges
if (spell && mod->charges == -1 && spell->m_appliedMods.find(mod->ownerAura) == spell->m_appliedMods.end())
return false;
// +duration to infinite duration spells making them limited
@@ -21225,18 +21212,18 @@ void Player::AddSpellMod(SpellModifier* mod, bool apply)
size_t writePos = data.wpos();
data << uint32(modTypeCount);
data << uint8(mod->op);
for (int32 eff = 0; eff < 96; ++eff)
for (int eff = 0; eff < 96; ++eff)
{
if (eff != 0 && (eff % 32) == 0)
_mask[i++] = 0;
_mask[i] = uint32(1) << (eff - (32 * i));
if ((mod->mask & _mask))
if (mod->mask & _mask)
{
int32 val = 0;
for (SpellModifier* spellMod : m_spellMods[mod->op])
if (spellMod->type == mod->type && (spellMod->mask & _mask))
val += spellMod->value;
for (SpellModList::iterator itr = m_spellMods[mod->op].begin(); itr != m_spellMods[mod->op].end(); ++itr)
if ((*itr)->type == mod->type && (*itr)->mask & _mask)
val += (*itr)->value;
val += apply ? mod->value : -(mod->value);
data << uint8(eff);
@@ -21247,31 +21234,36 @@ void Player::AddSpellMod(SpellModifier* mod, bool apply)
data.put<uint32>(writePos, modTypeCount);
SendDirectMessage(&data);
if (apply)
m_spellMods[mod->op].insert(mod);
m_spellMods[mod->op].push_back(mod);
else
m_spellMods[mod->op].erase(mod);
{
m_spellMods[mod->op].remove(mod);
// mods bound to aura will be removed in AuraEffect::~AuraEffect
if (!mod->ownerAura)
delete mod;
}
}
// Restore spellmods in case of failed cast
void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId /*= 0*/, Aura* aura /*= nullptr*/)
void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId, Aura* aura)
{
if (!spell || spell->m_appliedMods.empty())
return;
std::list<Aura*> aurasQueue;
for (uint8 i = 0; i < MAX_SPELLMOD; ++i)
for (uint8 i=0; i<MAX_SPELLMOD; ++i)
{
for (auto itr = m_spellMods[i].begin(); itr != m_spellMods[i].end(); ++itr)
for (SpellModList::iterator itr = m_spellMods[i].begin(); itr != m_spellMods[i].end(); ++itr)
{
SpellModifier* mod = *itr;
// Spellmods without charged aura cannot be charged
if (!mod->ownerAura->IsUsingCharges())
// Spellmods without aura set cannot be charged
if (!mod->ownerAura || !mod->ownerAura->IsUsingCharges())
continue;
// Restore only specific owner aura mods
if (ownerAuraId && mod->spellId != ownerAuraId)
if (ownerAuraId && (ownerAuraId != mod->ownerAura->GetSpellInfo()->Id))
continue;
if (aura && mod->ownerAura != aura)
@@ -21292,33 +21284,84 @@ void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId /*= 0*/, Aura* au
// only see the first of its modifier restored)
aurasQueue.push_back(mod->ownerAura);
// add charges back to aura
mod->ownerAura->ModCharges(1);
// 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);
}
}
for (Aura* aura : aurasQueue)
spell->m_appliedMods.erase(aura);
for (std::list<Aura*>::iterator itr = aurasQueue.begin(); itr != aurasQueue.end(); ++itr)
{
Spell::UsedSpellMods::iterator iterMod = spell->m_appliedMods.find(*itr);
if (iterMod != spell->m_appliedMods.end())
spell->m_appliedMods.erase(iterMod);
}
}
void Player::RestoreAllSpellMods(uint32 ownerAuraId /*= 0*/, Aura* aura /*= nullptr*/)
void Player::RestoreAllSpellMods(uint32 ownerAuraId, Aura* aura)
{
for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i)
if (Spell* spell = m_currentSpells[i])
RestoreSpellMods(spell, ownerAuraId, aura);
if (m_currentSpells[i])
RestoreSpellMods(m_currentSpells[i], ownerAuraId, aura);
}
void Player::ApplyModToSpell(SpellModifier* mod, Spell* spell)
void Player::RemoveSpellMods(Spell* spell)
{
if (!spell)
return;
// don't do anything with no charges
if (mod->ownerAura->IsUsingCharges() && !mod->ownerAura->GetCharges())
if (spell->m_appliedMods.empty())
return;
// register inside spell, proc system uses this to drop charges
spell->m_appliedMods.insert(mod->ownerAura);
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
spell->m_appliedMods.erase(iterMod);
if (mod->ownerAura->DropCharge(AURA_REMOVE_BY_EXPIRE))
itr = m_spellMods[i].begin();
}
}
}
void Player::DropModCharge(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 && mod->ownerAura && mod->charges > 0)
{
if (--mod->charges == 0)
mod->charges = -1;
spell->m_appliedMods.insert(mod->ownerAura);
}
}
void Player::SetSpellModTakingSpell(Spell* spell, bool apply)
@@ -21329,7 +21372,7 @@ void Player::SetSpellModTakingSpell(Spell* spell, bool apply)
if (apply && spell->getState() == SPELL_STATE_FINISHED)
return;
m_spellModTakingSpell = apply ? spell : nullptr;
m_spellModTakingSpell = apply ? spell : NULL;
}
// send Proficiency
+34 -90
View File
@@ -67,10 +67,10 @@ typedef std::deque<Mail*> PlayerMails;
#define PLAYER_EXPLORED_ZONES_SIZE 156
// Note: SPELLMOD_* values is aura types in fact
enum SpellModType : uint8
enum SpellModType
{
SPELLMOD_FLAT = SPELL_AURA_ADD_FLAT_MODIFIER,
SPELLMOD_PCT = SPELL_AURA_ADD_PCT_MODIFIER
SPELLMOD_FLAT = 107, // SPELL_AURA_ADD_FLAT_MODIFIER
SPELLMOD_PCT = 108 // 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
@@ -155,11 +155,10 @@ enum TalentTree // talent tabs
// Spell modifier (used for modify other spells)
struct SpellModifier
{
SpellModifier(Aura* _ownerAura) : op(SPELLMOD_DAMAGE), type(SPELLMOD_FLAT), value(0), mask(), spellId(0), ownerAura(_ownerAura) { }
SpellModOp op;
SpellModType type;
SpellModifier(Aura* _ownerAura = nullptr) : op(SPELLMOD_DAMAGE), type(SPELLMOD_FLAT), charges(0), value(0), mask(), spellId(0), ownerAura(_ownerAura) { }
SpellModOp op : 8;
SpellModType type : 8;
int16 charges : 16;
int32 value;
flag96 mask;
uint32 spellId;
@@ -183,7 +182,7 @@ struct PlayerCurrency
typedef std::unordered_map<uint32, PlayerTalent*> PlayerTalentMap;
typedef std::unordered_map<uint32, PlayerSpell*> PlayerSpellMap;
typedef std::unordered_set<SpellModifier*> SpellModContainer;
typedef std::list<SpellModifier*> SpellModList;
typedef std::unordered_map<uint32, PlayerCurrency> PlayerCurrenciesMap;
/// Maximum number of CompactUnitFrames profiles
@@ -1833,12 +1832,13 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
PlayerSpellMap & GetSpellMap() { return m_spells; }
void AddSpellMod(SpellModifier* mod, bool apply);
static bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = nullptr);
template <SpellModOp op, class T>
void ApplySpellMod(uint32 spellId, T& basevalue, Spell* spell = nullptr) const;
bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = nullptr);
template <class T>
void ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell = nullptr);
void RemoveSpellMods(Spell* spell);
void RestoreSpellMods(Spell* spell, uint32 ownerAuraId = 0, Aura* aura = nullptr);
void RestoreAllSpellMods(uint32 ownerAuraId = 0, Aura* aura = nullptr);
static void ApplyModToSpell(SpellModifier* mod, Spell* spell);
void DropModCharge(SpellModifier* mod, Spell* spell);
void SetSpellModTakingSpell(Spell* spell, bool apply);
void RemoveArenaSpellCooldowns(bool removeActivePetCooldowns = false);
@@ -2186,9 +2186,9 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
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(DamageInfo const& damageInfo);
void CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemTemplate const* proto);
void CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx);
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);
@@ -2708,7 +2708,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
uint32 m_baseHealthRegen;
int32 m_spellPenetrationItemMod;
SpellModContainer m_spellMods[MAX_SPELLMOD];
SpellModList m_spellMods[MAX_SPELLMOD];
EnchantDurationList m_enchantDuration;
ItemDurationList m_itemDuration;
@@ -2879,8 +2879,8 @@ TC_GAME_API void AddItemsSetItem(Player* player, Item* item);
TC_GAME_API void RemoveItemsSetItem(Player* player, ItemTemplate const* proto);
// "the bodies of template functions must be made available in a header file"
template <SpellModOp op, class T>
void Player::ApplySpellMod(uint32 spellId, T& basevalue, Spell* spell /*= nullptr*/) const
template <class T>
void Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell /*= nullptr*/)
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo)
@@ -2892,89 +2892,33 @@ void Player::ApplySpellMod(uint32 spellId, T& basevalue, Spell* spell /*= nullpt
if (m_spellModTakingSpell)
spell = m_spellModTakingSpell;
switch (op)
for (SpellModList::iterator itr = m_spellMods[op].begin(); itr != m_spellMods[op].end(); ++itr)
{
// special case, if a mod makes spell instant, only consume that mod
case SPELLMOD_CASTING_TIME:
{
SpellModifier* modInstantSpell = nullptr;
for (SpellModifier* mod : m_spellMods[SPELLMOD_CASTING_TIME])
{
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
continue;
SpellModifier* mod = *itr;
if (mod->type == SPELLMOD_PCT && basevalue < T(10000) && mod->value <= -100)
{
modInstantSpell = mod;
break;
}
}
// Charges can be set only for mods with auras
if (!mod->ownerAura)
ASSERT(mod->charges == 0);
if (modInstantSpell)
{
Player::ApplyModToSpell(modInstantSpell, spell);
basevalue = T(0);
return;
}
break;
}
// special case if two mods apply 100% critical chance, only consume one
case SPELLMOD_CRITICAL_CHANCE:
{
SpellModifier* modCritical = nullptr;
for (SpellModifier* 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;
}
for (SpellModifier* mod : m_spellMods[op])
{
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
continue;
switch (mod->type)
if (mod->type == SPELLMOD_FLAT)
totalflat += mod->value;
else if (mod->type == SPELLMOD_PCT)
{
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;
// skip percent mods for null basevalue (most important for spell mods with charges)
if (basevalue == T(0))
continue;
// special case (skip > 10sec spell casts for instant cast setting)
if (op == SPELLMOD_CASTING_TIME)
{
if (mod->value <= -100 && basevalue >= T(10000))
continue;
}
// special case (skip > 10sec spell casts for instant cast setting)
if (mod->op == SPELLMOD_CASTING_TIME && basevalue >= T(10000) && mod->value <= -100)
continue;
totalmul += CalculatePct(1.0f, mod->value);
break;
}
totalmul += CalculatePct(1.0f, mod->value);
}
Player::ApplyModToSpell(mod, spell);
DropModCharge(mod, spell);
}
basevalue = T(float(basevalue + totalflat) * totalmul);
}
File diff suppressed because it is too large. Load diff
+151 -146
View File
@@ -82,43 +82,43 @@ enum SpellAuraInterruptFlags
AURA_INTERRUPT_FLAG_NOT_VICTIM = (AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_TAKE_DAMAGE | AURA_INTERRUPT_FLAG_DIRECT_DAMAGE)
};
enum SpellModOp : uint8
enum SpellModOp
{
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_SPELL_COST_REFUND_ON_FAIL = 30,
MAX_SPELLMOD
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
};
#define MAX_SPELLMOD 32
enum SpellValueMod
{
SPELLVALUE_BASE_POINT0,
@@ -432,7 +432,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
// reuse 0x00020000
TRIGGERED_DISALLOW_PROC_EVENTS = 0x00020000, //! Disallows proc events from triggered spell (default)
TRIGGERED_DONT_REPORT_CAST_ERROR = 0x00040000, //! Will return SPELL_FAILED_DONT_REPORT in CheckCast functions
TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT = 0x00080000, //! Will ignore equipped item requirements
TRIGGERED_IGNORE_TARGET_CHECK = 0x00100000, //! Will ignore most target checks (mostly DBC target checks)
@@ -823,13 +823,13 @@ struct DiminishingReturn
: DRGroup(group), stack(0), hitTime(t), hitCount(count)
{ }
DiminishingGroup DRGroup;
uint16 stack;
DiminishingGroup DRGroup:16;
uint16 stack:16;
uint32 hitTime;
uint32 hitCount;
};
enum MeleeHitOutcome : uint8
enum MeleeHitOutcome
{
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
@@ -837,18 +837,21 @@ enum MeleeHitOutcome : uint8
class DispelInfo
{
public:
explicit DispelInfo(Unit* dispeller, uint32 dispellerSpellId, uint8 chargesRemoved) :
_dispellerUnit(dispeller), _dispellerSpell(dispellerSpellId), _chargesRemoved(chargesRemoved) { }
public:
explicit DispelInfo(Unit* dispeller, uint32 dispellerSpellId, uint8 chargesRemoved) :
_dispellerUnit(dispeller), _dispellerSpell(dispellerSpellId), _chargesRemoved(chargesRemoved) { }
Unit* GetDispeller() const { return _dispellerUnit; }
uint32 GetDispellerSpellId() const { return _dispellerSpell; }
uint8 GetRemovedCharges() const { return _chargesRemoved; }
void SetRemovedCharges(uint8 amount) { _chargesRemoved = amount; }
private:
Unit* _dispellerUnit;
uint32 _dispellerSpell;
uint8 _chargesRemoved;
Unit* GetDispeller() const { return _dispellerUnit; }
uint32 GetDispellerSpellId() const { return _dispellerSpell; }
uint8 GetRemovedCharges() const { return _chargesRemoved; }
void SetRemovedCharges(uint8 amount)
{
_chargesRemoved = amount;
}
private:
Unit* _dispellerUnit;
uint32 _dispellerSpell;
uint8 _chargesRemoved;
};
struct CleanDamage
@@ -863,110 +866,105 @@ struct CleanDamage
MeleeHitOutcome hitOutCome;
};
struct SpellNonMeleeDamage;
struct CalcDamageInfo;
class TC_GAME_API DamageInfo
{
private:
Unit* const m_attacker;
Unit* const m_victim;
uint32 m_damage;
SpellInfo const* const m_spellInfo;
SpellSchoolMask const m_schoolMask;
DamageEffectType const m_damageType;
WeaponAttackType m_attackType;
uint32 m_absorb;
uint32 m_resist;
uint32 m_block;
uint32 m_hitMask;
public:
DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType);
explicit DamageInfo(CalcDamageInfo const& dmgInfo);
DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType, uint32 hitMask);
private:
Unit* const m_attacker;
Unit* const m_victim;
uint32 m_damage;
SpellInfo const* const m_spellInfo;
SpellSchoolMask const m_schoolMask;
DamageEffectType const m_damageType;
WeaponAttackType m_attackType;
uint32 m_absorb;
uint32 m_resist;
uint32 m_block;
uint32 m_hitMask;
public:
DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType);
explicit DamageInfo(CalcDamageInfo const& dmgInfo);
DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType);
void ModifyDamage(int32 amount);
void AbsorbDamage(uint32 amount);
void ResistDamage(uint32 amount);
void BlockDamage(uint32 amount);
void ModifyDamage(int32 amount);
void AbsorbDamage(uint32 amount);
void ResistDamage(uint32 amount);
void BlockDamage(uint32 amount);
Unit* GetAttacker() const { return m_attacker; }
Unit* GetVictim() const { return m_victim; }
SpellInfo const* GetSpellInfo() const { return m_spellInfo; }
SpellSchoolMask GetSchoolMask() const { return m_schoolMask; }
DamageEffectType GetDamageType() const { return m_damageType; }
WeaponAttackType GetAttackType() const { return m_attackType; }
uint32 GetDamage() const { return m_damage; }
uint32 GetAbsorb() const { return m_absorb; }
uint32 GetResist() const { return m_resist; }
uint32 GetBlock() const { return m_block; }
Unit* GetAttacker() const { return m_attacker; }
Unit* GetVictim() const { return m_victim; }
SpellInfo const* GetSpellInfo() const { return m_spellInfo; }
SpellSchoolMask GetSchoolMask() const { return m_schoolMask; }
DamageEffectType GetDamageType() const { return m_damageType; }
WeaponAttackType GetAttackType() const { return m_attackType; }
uint32 GetDamage() const { return m_damage; }
uint32 GetAbsorb() const { return m_absorb; }
uint32 GetResist() const { return m_resist; }
uint32 GetBlock() const { return m_block; }
uint32 GetHitMask() const;
uint32 GetHitMask() const;
};
class TC_GAME_API HealInfo
{
private:
Unit* const _healer;
Unit* const _target;
uint32 _heal;
uint32 _effectiveHeal;
uint32 _absorb;
SpellInfo const* const _spellInfo;
SpellSchoolMask const _schoolMask;
uint32 _hitMask;
private:
Unit* const _healer;
Unit* const _target;
uint32 _heal;
uint32 _absorb;
SpellInfo const* const _spellInfo;
SpellSchoolMask const _schoolMask;
uint32 _hitMask;
public:
HealInfo(Unit* healer, Unit* target, uint32 heal, SpellInfo const* spellInfo, SpellSchoolMask schoolMask);
public:
explicit HealInfo(Unit* healer, Unit* target, uint32 heal, SpellInfo const* spellInfo, SpellSchoolMask schoolMask);
void AbsorbHeal(uint32 amount);
void SetEffectiveHeal(uint32 amount) { _effectiveHeal = amount; }
void AbsorbHeal(uint32 amount);
Unit* GetHealer() const { return _healer; }
Unit* GetTarget() const { return _target; }
uint32 GetHeal() const { return _heal; }
uint32 GetEffectiveHeal() const { return _effectiveHeal; }
uint32 GetAbsorb() const { return _absorb; }
SpellInfo const* GetSpellInfo() const { return _spellInfo; };
SpellSchoolMask GetSchoolMask() const { return _schoolMask; };
Unit* GetHealer() const { return _healer; }
Unit* GetTarget() const { return _target; }
uint32 GetHeal() const { return _heal; }
uint32 GetAbsorb() const { return _absorb; }
SpellInfo const* GetSpellInfo() const { return _spellInfo; };
SpellSchoolMask GetSchoolMask() const { return _schoolMask; };
uint32 GetHitMask() const;
uint32 GetHitMask() const;
};
class TC_GAME_API ProcEventInfo
{
public:
ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask,
uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask,
Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo);
public:
ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask,
uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask,
Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo);
Unit* GetActor() { return _actor; }
Unit* GetActionTarget() const { return _actionTarget; }
Unit* GetProcTarget() const { return _procTarget; }
Unit* GetActor() { return _actor; }
Unit* GetActionTarget() const { return _actionTarget; }
Unit* GetProcTarget() const { return _procTarget; }
uint32 GetTypeMask() const { return _typeMask; }
uint32 GetSpellTypeMask() const { return _spellTypeMask; }
uint32 GetSpellPhaseMask() const { return _spellPhaseMask; }
uint32 GetHitMask() const { return _hitMask; }
uint32 GetTypeMask() const { return _typeMask; }
uint32 GetSpellTypeMask() const { return _spellTypeMask; }
uint32 GetSpellPhaseMask() const { return _spellPhaseMask; }
uint32 GetHitMask() const { return _hitMask; }
SpellInfo const* GetSpellInfo() const;
SpellSchoolMask GetSchoolMask() const;
SpellInfo const* GetSpellInfo() const;
SpellSchoolMask GetSchoolMask() const;
DamageInfo* GetDamageInfo() const { return _damageInfo; }
HealInfo* GetHealInfo() const { return _healInfo; }
DamageInfo* GetDamageInfo() const { return _damageInfo; }
HealInfo* GetHealInfo() const { return _healInfo; }
Spell const* GetProcSpell() const { return _spell; }
private:
Unit* const _actor;
Unit* const _actionTarget;
Unit* const _procTarget;
uint32 _typeMask;
uint32 _spellTypeMask;
uint32 _spellPhaseMask;
uint32 _hitMask;
Spell* _spell;
DamageInfo* _damageInfo;
HealInfo* _healInfo;
private:
Unit* const _actor;
Unit* const _actionTarget;
Unit* const _procTarget;
uint32 _typeMask;
uint32 _spellTypeMask;
uint32 _spellPhaseMask;
uint32 _hitMask;
Spell* _spell;
DamageInfo* _damageInfo;
HealInfo* _healInfo;
};
// Struct for use in Unit::CalculateMeleeDamage
@@ -986,6 +984,7 @@ struct CalcDamageInfo
WeaponAttackType attackType; //
uint32 procAttacker;
uint32 procVictim;
uint32 procEx;
uint32 cleanDamage; // Used only for rage calculation
MeleeHitOutcome hitOutCome; /// @todo remove this field (need use TargetState)
};
@@ -1028,7 +1027,7 @@ struct SpellPeriodicAuraLogInfo
bool critical;
};
uint32 createProcHitMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition);
uint32 createProcExtendMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition);
struct RedirectThreatInfo
{
@@ -1253,6 +1252,8 @@ enum PlayerTotemType
#define ATTACK_DISPLAY_DELAY 200
#define MAX_PLAYER_STEALTH_DETECT_RANGE 30.0f // max distance for detection targets by player
struct SpellProcEventEntry; // used only privately
class TC_GAME_API Unit : public WorldObject
{
public:
@@ -1275,8 +1276,6 @@ class TC_GAME_API Unit : public WorldObject
typedef std::list<AuraApplication *> AuraApplicationList;
typedef std::list<DiminishingReturn> Diminishing;
typedef std::deque<std::pair<uint8 /*procEffectMask*/, AuraApplication*>> AuraApplicationProcContainer;
typedef std::map<uint8, AuraApplication*> VisibleAuraMap;
virtual ~Unit();
@@ -1456,18 +1455,18 @@ class TC_GAME_API Unit : public WorldObject
uint32 DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDamage = NULL, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* spellProto = NULL, bool durabilityLoss = true);
void Kill(Unit* victim, bool durabilityLoss = true);
void KillSelf(bool durabilityLoss = true) { Kill(this, durabilityLoss); }
void DealHeal(HealInfo& healInfo);
int32 DealHeal(Unit* victim, uint32 addhealth);
void ProcSkillsAndAuras(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget,
uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell,
DamageInfo* damageInfo, HealInfo* healInfo);
void ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellInfo const* procSpell = NULL, SpellInfo const* procAura = NULL);
void ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpell, uint32 damage, SpellInfo const* procAura = NULL);
void GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer& aurasTriggeringProc, AuraApplicationList* procAuras, ProcEventInfo& eventInfo);
void GetProcAurasTriggeredOnEvent(AuraApplicationList& aurasTriggeringProc, AuraApplicationList* procAuras, ProcEventInfo eventInfo);
void TriggerAurasProcOnEvent(CalcDamageInfo& damageInfo);
void TriggerAurasProcOnEvent(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget,
void TriggerAurasProcOnEvent(AuraApplicationList* myProcAuras, AuraApplicationList* targetProcAuras,
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 TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationList& procAuras);
void HandleEmoteCommand(uint32 anim_id);
void AttackerStateUpdate (Unit* victim, WeaponAttackType attType = BASE_ATTACK, bool extra = false);
@@ -1561,8 +1560,8 @@ class TC_GAME_API Unit : public WorldObject
virtual void UpdateUnderwaterState(Map* m, float x, float y, float z);
bool isInAccessiblePlaceFor(Creature const* c) const;
void SendHealSpellLog(HealInfo& healInfo, bool critical = false);
int32 HealBySpell(HealInfo& healInfo, bool critical = false);
void SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical = false);
int32 HealBySpell(Unit* victim, SpellInfo const* spellInfo, uint32 addHealth, bool critical = false);
void SendEnergizeSpellLog(Unit* victim, uint32 spellID, int32 damage, Powers powertype);
void EnergizeBySpell(Unit* victim, uint32 SpellID, int32 Damage, Powers powertype);
uint32 SpellNonMeleeDamageLog(Unit* victim, uint32 spellID, uint32 damage);
@@ -2035,7 +2034,7 @@ class TC_GAME_API Unit : public WorldObject
uint32 CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = MAX_ATTACK);
uint32 CalcSpellResistance(Unit* victim, SpellSchoolMask schoolMask, SpellInfo const* spellInfo) const;
void CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, uint32 const damage, uint32* absorb, uint32* resist, SpellInfo const* spellInfo = NULL);
void CalcHealAbsorb(HealInfo& healInfo);
void CalcHealAbsorb(Unit* victim, SpellInfo const* spellInfo, uint32& healAmount, uint32& absorb);
void UpdateSpeed(UnitMoveType mtype);
float GetSpeed(UnitMoveType mtype) const;
@@ -2098,7 +2097,7 @@ class TC_GAME_API Unit : public WorldObject
void UpdateAuraForGroup(uint8 slot);
// proc trigger system
bool CanProc() const { return !m_procDeep; }
bool CanProc() const {return !m_procDeep;}
void SetCantProc(bool apply);
// pet auras
@@ -2269,8 +2268,16 @@ class TC_GAME_API Unit : public WorldObject
bool IsAlwaysDetectableFor(WorldObject const* seer) const override;
void DisableSpline();
private:
bool IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, SpellInfo const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent);
bool RollProcResult(Unit* victim, Aura* aura, WeaponAttackType attType, bool isVictim, SpellProcEventEntry const* spellProcEvent);
bool HandleAuraProcOnPowerAmount(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
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);
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();
@@ -2279,8 +2286,6 @@ class TC_GAME_API Unit : public WorldObject
float GetCombatRatingReduction(CombatRating cr) const;
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);
@@ -3599,7 +3599,7 @@ enum DiminishingReturnsType
};
// Diminishing Return Groups
enum DiminishingGroup : uint16
enum DiminishingGroup
{
DIMINISHING_NONE = 0,
DIMINISHING_BANISH = 1,
+32 -124
View File
@@ -100,8 +100,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 AuraEffect::HandleProc
&AuraEffect::HandleNoImmediateEffect, // 43 SPELL_AURA_PROC_TRIGGER_DAMAGE implemented in AuraEffect::HandleProc
&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::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)
@@ -320,7 +320,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleUnused, //259 unused (4.3.4) old SPELL_AURA_MOD_HOT_PCT
&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::CheckCast
&AuraEffect::HandleNoImmediateEffect, //262 SPELL_AURA_ABILITY_IGNORE_AURASTATE implemented in spell::cancast
&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 (4.3.4)
@@ -634,7 +634,7 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool resetPeriodicTimer /*= tru
{
// Apply periodic time mod
if (modOwner)
modOwner->ApplySpellMod<SPELLMOD_ACTIVATION_TIME>(GetId(), m_amplitude);
modOwner->ApplySpellMod(GetId(), SPELLMOD_ACTIVATION_TIME, m_amplitude);
if (caster)
{
@@ -683,6 +683,7 @@ void AuraEffect::CalculateSpellMod()
m_spellmod->type = SpellModType(uint32(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;
@@ -1059,50 +1060,6 @@ 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_MECHANIC_IMMUNITY:
case SPELL_AURA_MOD_MECHANIC_RESISTANCE:
// compare mechanic
if (!spellInfo || static_cast<int32>(spellInfo->Mechanic) != GetMiscValue())
result = false;
break;
case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK:
// skip melee hits and instant cast spells
if (!spellInfo || !spellInfo->CalcCastTime())
result = false;
break;
case SPELL_AURA_MOD_DAMAGE_FROM_CASTER:
// Compare casters
if (GetCasterGUID() != eventInfo.GetActor()->GetGUID())
result = 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
result = false;
break;
case SPELL_AURA_REFLECT_SPELLS_SCHOOL:
// Skip melee hits and spells with wrong school
if (!spellInfo || !(spellInfo->GetSchoolMask() & GetMiscValue()))
result = false;
break;
default:
break;
}
return result;
}
void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
{
bool prevented = GetBase()->CallScriptEffectProcHandlers(this, aurApp, eventInfo);
@@ -1111,16 +1068,6 @@ void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
switch (GetAuraType())
{
// CC Auras which use their amount to drop
// Are there any 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;
@@ -4776,6 +4723,10 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool
if (caster)
target->GetMotionMaster()->MoveFall();
break;
case 71563:
if (Aura* newAura = target->AddAura(71564, target))
newAura->SetStackAmount(newAura->GetSpellInfo()->StackAmount);
break;
}
}
// AT REMOVE
@@ -5563,10 +5514,8 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster)
if (caster)
{
int32 heal = caster->CountPctFromMaxHealth(10);
HealInfo healInfo(caster, target, heal, auraSpellInfo, auraSpellInfo->GetSchoolMask());
caster->HealBySpell(healInfo);
caster->HealBySpell(target, auraSpellInfo, heal);
/// @todo: should proc other auras?
if (int32 mana = caster->GetMaxPower(POWER_MANA))
{
mana /= 10;
@@ -5877,7 +5826,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
damage = std::max(int32(damage * GetDonePct()), 0);
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_DOT>(GetSpellInfo()->Id, damage);
modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, damage);
damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
@@ -5926,14 +5875,12 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
damage = uint32(target->CountPctFromMaxHealth(damage));
if (!m_spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
{
if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || isAreaAura)
{
damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask));
if (caster->GetTypeId() != TYPEID_PLAYER)
damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask));
}
}
bool crit = false;
@@ -5959,7 +5906,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
// Set trigger flag
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
uint32 hitMask = crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL;
uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_DOT;
damage = (damage <= absorb+resist) ? 0 : (damage-absorb-resist);
if (damage)
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
@@ -5971,8 +5918,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
SpellPeriodicAuraLogInfo pInfo(this, damage, overkill, absorb, resist, 0.0f, crit);
target->SendPeriodicAuraLog(&pInfo);
DamageInfo damageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK);
caster->ProcSkillsAndAuras(target, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &damageInfo, nullptr);
caster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo());
caster->DealDamage(target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true);
}
@@ -6049,17 +5995,12 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
// Set trigger flag
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
uint32 hitMask = crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL;
uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_DOT;
damage = (damage <= absorb+resist) ? 0 : (damage-absorb-resist);
if (damage)
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
if (caster->IsAlive())
{
DamageInfo damageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK);
caster->ProcSkillsAndAuras(target, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &damageInfo, nullptr);
}
caster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo());
int32 new_damage = caster->DealDamage(target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), false);
if (caster->IsAlive())
{
@@ -6068,11 +6009,8 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
uint32 heal = uint32(caster->SpellHealingBonusDone(caster, GetSpellInfo(), uint32(new_damage * gainMultiplier), DOT, GetBase()->GetStackAmount()));
heal = uint32(caster->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT, GetBase()->GetStackAmount()));
HealInfo healInfo(caster, caster, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
caster->HealBySpell(healInfo);
caster->getHostileRefManager().threatAssist(caster, healInfo.GetEffectiveHeal() * 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);
int32 gain = caster->HealBySpell(caster, GetSpellInfo(), heal);
caster->getHostileRefManager().threatAssist(caster, gain * 0.5f, GetSpellInfo());
}
}
@@ -6101,9 +6039,7 @@ void AuraEffect::HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster)
damage = int32(damage * gainMultiplier);
HealInfo healInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
caster->HealBySpell(healInfo);
caster->ProcSkillsAndAuras(target, PROC_FLAG_DONE_PERIODIC, PROC_FLAG_TAKEN_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, PROC_HIT_NORMAL, nullptr, nullptr, &healInfo);
caster->HealBySpell(target, GetSpellInfo(), damage);
}
void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
@@ -6176,7 +6112,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
damage = std::max(int32(damage * GetDonePct()), 0);
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_DOT>(GetSpellInfo()->Id, damage);
modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, damage);
damage = target->SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
}
@@ -6192,16 +6128,15 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
TC_LOG_DEBUG("spells.periodic", "PeriodicTick: %s heal of %s for %u health inflicted by %u",
GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), damage, GetId());
uint32 absorb = 0;
uint32 heal = damage;
caster->CalcHealAbsorb(target, GetSpellInfo(), heal, absorb);
int32 gain = caster->DealHeal(target, heal);
HealInfo healInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
caster->CalcHealAbsorb(healInfo);
caster->DealHeal(healInfo);
SpellPeriodicAuraLogInfo pInfo(this, heal, heal - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), 0, 0.0f, crit);
SpellPeriodicAuraLogInfo pInfo(this, heal, heal - gain, absorb, 0, 0.0f, crit);
target->SendPeriodicAuraLog(&pInfo);
target->getHostileRefManager().threatAssist(caster, float(healInfo.GetEffectiveHeal()) * 0.5f, GetSpellInfo());
target->getHostileRefManager().threatAssist(caster, float(gain) * 0.5f, GetSpellInfo());
bool haveCastItem = !GetBase()->GetCastItemGUID().IsEmpty();
@@ -6211,8 +6146,8 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
{
uint32 funnelDamage = GetSpellInfo()->ManaPerSecond; // damage is not affected by spell power
if (funnelDamage > healInfo.GetEffectiveHeal() && healInfo.GetEffectiveHeal())
funnelDamage = healInfo.GetEffectiveHeal();
if ((int32)funnelDamage > gain && gain > 0)
funnelDamage = gain;
uint32 funnelAbsorb = 0;
caster->DealDamageMods(caster, funnelDamage, &funnelAbsorb);
@@ -6224,10 +6159,10 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
uint32 hitMask = crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL;
uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_HOT;
// ignore item heals
if (!haveCastItem)
caster->ProcSkillsAndAuras(target, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, hitMask, nullptr, nullptr, &healInfo);
caster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo());
}
void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) const
@@ -6398,41 +6333,15 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con
// Set trigger flag
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
uint32 hitMask = createProcHitMask(&damageInfo, SPELL_MISS_NONE);
uint32 spellTypeMask = PROC_SPELL_TYPE_NO_DMG_HEAL;
uint32 procEx = createProcExtendMask(&damageInfo, SPELL_MISS_NONE) | PROC_EX_INTERNAL_DOT;
if (damageInfo.damage)
{
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
spellTypeMask |= PROC_SPELL_TYPE_DAMAGE;
}
DamageInfo dotDamageInfo(damageInfo, DOT, BASE_ATTACK, hitMask);
caster->ProcSkillsAndAuras(target, procAttacker, procVictim, spellTypeMask, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &dotDamageInfo, nullptr);
caster->ProcDamageAndSpell(damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto);
caster->DealSpellDamage(&damageInfo, true);
}
void AuraEffect::HandleBreakableCCAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
{
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
if (!damageInfo)
return;
// aura own damage at apply won't break CC
if (eventInfo.GetSpellPhaseMask() & PROC_SPELL_PHASE_CAST)
{
if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
if (spellInfo == GetSpellInfo())
return;
}
int32 damageLeft = GetAmount();
if (damageLeft < int32(damageInfo->GetDamage()))
aurApp->GetTarget()->RemoveAura(aurApp);
else
SetAmount(damageLeft - damageInfo->GetDamage());
}
void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
{
Unit* triggerCaster = aurApp->GetTarget();
@@ -6445,8 +6354,7 @@ void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEve
triggerCaster->CastSpell(triggerTarget, triggeredSpellInfo, true, NULL, this);
}
else
TC_LOG_ERROR("spells","AuraEffect::HandleProcTriggerSpellAuraProc: Could not trigger spell %u from aura %u proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
TC_LOG_DEBUG("spells","AuraEffect::HandleProcTriggerSpellAuraProc: Could not trigger spell %u from aura %u proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
}
void AuraEffect::HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
@@ -6462,7 +6370,7 @@ void AuraEffect::HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp
triggerCaster->CastCustomSpell(triggerTarget, triggerSpellId, &basepoints0, NULL, NULL, true, NULL, this);
}
else
TC_LOG_ERROR("spells","AuraEffect::HandleProcTriggerSpellWithValueAuraProc: Could not trigger spell %u from aura %u proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
TC_LOG_DEBUG("spells","AuraEffect::HandleProcTriggerSpellWithValueAuraProc: Could not trigger spell %u from aura %u proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
}
void AuraEffect::HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
@@ -41,6 +41,7 @@ class TC_GAME_API AuraEffect
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 { return m_spellInfo->Id; }
@@ -89,9 +90,8 @@ class TC_GAME_API AuraEffect
bool HasSpellClassMask() const { return m_spellInfo->Effects[m_effIndex].SpellClassMask; }
void SendTickImmune(Unit* target, Unit* caster) const;
void PeriodicTick(AuraApplication* aurApp, Unit* caster) const;
bool CheckEffectProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) const;
void PeriodicTick(AuraApplication * aurApp, Unit* caster) const;
void HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
void CleanupTriggeredSpells(Unit* target);
@@ -309,7 +309,6 @@ class TC_GAME_API AuraEffect
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);
+39 -88
View File
@@ -738,7 +738,7 @@ int32 Aura::CalcMaxDuration(Unit* caster) const
// IsPermanent() checks max duration (which we are supposed to calculate here)
if (maxDuration != -1 && modOwner)
modOwner->ApplySpellMod<SPELLMOD_DURATION>(GetId(), maxDuration);
modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, maxDuration);
return maxDuration;
}
@@ -748,7 +748,7 @@ void Aura::SetDuration(int32 duration, bool withMods)
if (withMods)
if (Unit* caster = GetCaster())
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_DURATION>(GetId(), duration);
modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, duration);
m_duration = duration;
SetNeedClientUpdateForTargets();
@@ -819,7 +819,7 @@ uint8 Aura::CalcMaxCharges(Unit* caster) const
if (caster)
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_CHARGES>(GetId(), maxProcCharges);
modOwner->ApplySpellMod(GetId(), SPELLMOD_CHARGES, maxProcCharges);
return uint8(maxProcCharges);
}
@@ -925,6 +925,12 @@ bool Aura::ModStackAmount(int32 num, AuraRemoveMode removeMode)
// 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();
}
SetNeedClientUpdateForTargets();
@@ -1059,7 +1065,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<SPELLMOD_RESIST_DISPEL_CHANCE>(GetId(), resistChance);
modOwner->ApplySpellMod(GetId(), SPELLMOD_RESIST_DISPEL_CHANCE, resistChance);
// Dispel resistance from target SPELL_AURA_MOD_DISPEL_RESIST
// Only affects offensive dispels
@@ -1116,7 +1122,7 @@ void Aura::HandleAllEffects(AuraApplication * aurApp, uint8 mode, bool apply)
m_effects[i]->HandleEffect(aurApp, mode, apply);
}
void Aura::GetApplicationList(Unit::AuraApplicationList& applicationList) const
void Aura::GetApplicationList(std::list<AuraApplication*> & applicationList) const
{
for (Aura::ApplicationMap::const_iterator appIter = m_applications.begin(); appIter != m_applications.end(); ++appIter)
{
@@ -1713,76 +1719,49 @@ void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInf
}
SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId());
ASSERT(procEntry);
// cooldowns should be added to the whole aura (see 51698 area aura)
AddProcCooldown(procEntry->Cooldown);
}
uint8 Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const
bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) const
{
SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId());
// only auras with spell proc entry can trigger proc
if (!procEntry)
return 0;
return false;
// check if we have charges to proc with
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;
}
if (IsUsingCharges() && !GetCharges())
return false;
// check proc cooldown
if (IsProcOnCooldown())
return 0;
return false;
/// @todo
// something about triggered spells triggering, and add extra attack effect
// do checks against db data
if (!sSpellMgr->CanSpellTriggerProcOnEvent(*procEntry, eventInfo))
return 0;
// check if aura can proc when spell is triggered
if (!(procEntry->AttributesMask & PROC_ATTR_TRIGGERED_CAN_PROC))
if (Spell const* spell = eventInfo.GetProcSpell())
if (spell->IsTriggered())
if (!GetSpellInfo()->HasAttribute(SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED))
return 0;
return false;
// do checks using conditions table
if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_SPELL_PROC, GetId(), eventInfo.GetActor(), eventInfo.GetActionTarget()))
return 0;
return false;
// AuraScript Hook
bool check = const_cast<Aura*>(this)->CallScriptCheckProcHandlers(aurApp, eventInfo);
if (!check)
return 0;
// At least one effect has to pass checks to proc aura
uint8 procEffectMask = 0;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if (aurApp->HasEffect(i))
if (GetEffect(i)->CheckEffectProc(aurApp, eventInfo))
procEffectMask |= (1 << i);
if (!procEffectMask)
return 0;
return false;
/// @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 spell 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
@@ -1792,12 +1771,12 @@ uint8 Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& event
if (GetSpellInfo()->EquippedItemClass == ITEM_CLASS_WEAPON)
{
if (target->ToPlayer()->IsInFeralForm())
return 0;
return false;
if (DamageInfo* damageInfo = eventInfo.GetDamageInfo())
if (eventInfo.GetDamageInfo())
{
WeaponAttackType attType = damageInfo->GetAttackType();
Item* item = nullptr;
WeaponAttackType attType = eventInfo.GetDamageInfo()->GetAttackType();
Item* item = NULL;
if (attType == BASE_ATTACK)
item = target->ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
else if (attType == OFF_ATTACK)
@@ -1805,23 +1784,20 @@ uint8 Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& event
else
item = target->ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
if (!item || item->IsBroken() || item->GetTemplate()->Class != ITEM_CLASS_WEAPON || !((1 << item->GetTemplate()->SubClass) & GetSpellInfo()->EquippedItemSubClassMask))
return 0;
if (!item || item->IsBroken() || item->GetTemplate()->Class != ITEM_CLASS_WEAPON || !((1<<item->GetTemplate()->SubClass) & GetSpellInfo()->EquippedItemSubClassMask))
return false;
}
}
else if (GetSpellInfo()->EquippedItemClass == ITEM_CLASS_ARMOR)
{
// Check if player is wearing shield
Item* item = target->ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
if (!item || item->IsBroken() || item->GetTemplate()->Class != ITEM_CLASS_ARMOR || !((1 << item->GetTemplate()->SubClass) & GetSpellInfo()->EquippedItemSubClassMask))
return 0;
if (!item || item->IsBroken() || item->GetTemplate()->Class != ITEM_CLASS_ARMOR || !((1<<item->GetTemplate()->SubClass) & GetSpellInfo()->EquippedItemSubClassMask))
return false;
}
}
if (roll_chance_f(CalcProcChance(*procEntry, eventInfo)))
return procEffectMask;
return 0;
return roll_chance_f(CalcProcChance(*procEntry, eventInfo));
}
float Aura::CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const
@@ -1839,29 +1815,21 @@ float Aura::CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& event
}
// apply chance modifer aura, applies also to ppm chance (see improved judgement of light spell)
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_CHANCE_OF_SUCCESS>(GetId(), chance);
modOwner->ApplySpellMod(GetId(), SPELLMOD_CHANCE_OF_SUCCESS, chance);
}
return chance;
}
void Aura::TriggerProcOnEvent(uint8 procEffectMask, AuraApplication* aurApp, ProcEventInfo& eventInfo)
void Aura::TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo)
{
bool prevented = CallScriptProcHandlers(aurApp, eventInfo);
if (!prevented)
{
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
if (!(procEffectMask & (1 << i)))
continue;
CallScriptProcHandlers(aurApp, eventInfo);
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if (aurApp->HasEffect(i))
// OnEffectProc / AfterEffectProc hooks handled in AuraEffect::HandleProc()
if (aurApp->HasEffect(i))
GetEffect(i)->HandleProc(aurApp, eventInfo);
}
GetEffect(i)->HandleProc(aurApp, eventInfo);
CallScriptAfterProcHandlers(aurApp, eventInfo);
}
CallScriptAfterProcHandlers(aurApp, eventInfo);
// Remove aura if we've used last charge to proc
if (IsUsingCharges() && !GetCharges())
@@ -2219,23 +2187,6 @@ 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;
+6 -3
View File
@@ -199,14 +199,18 @@ class TC_GAME_API Aura
bool CheckAreaTarget(Unit* target);
bool CanStackWith(Aura const* existingAura) 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(Milliseconds msec);
bool IsUsingCharges() const { return m_isUsingCharges; }
void SetUsingCharges(bool val) { m_isUsingCharges = val; }
void PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo);
uint8 IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const;
bool IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) const;
float CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const;
void TriggerProcOnEvent(uint8 procEffectMask, AuraApplication* aurApp, ProcEventInfo& eventInfo);
void TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo);
// AuraScript
void LoadScripts();
@@ -229,7 +233,6 @@ class TC_GAME_API Aura
void CallScriptEffectSplitHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo & dmgInfo, uint32 & splitAmount);
// Spell Proc Hooks
bool CallScriptCheckProcHandlers(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);
+118 -133
View File
@@ -594,7 +594,7 @@ m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerO
m_healing = 0;
m_procAttacker = 0;
m_procVictim = 0;
m_hitMask = 0;
m_procEx = 0;
focusObject = NULL;
m_cast_count = 0;
m_glyphIndex = 0;
@@ -1474,7 +1474,7 @@ void Spell::SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTarg
{
uint32 maxTargets = m_spellInfo->Effects[effIndex].ChainTarget;
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_JUMP_TARGETS>(m_spellInfo->Id, maxTargets, this);
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, maxTargets, this);
if (maxTargets > 1)
{
@@ -1943,11 +1943,12 @@ GameObject* Spell::SearchSpellFocus()
return focus;
}
void Spell::prepareDataForTriggerSystem()
void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
{
//==========================================================================================
// Now fill data for trigger system, need know:
// Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_hitMask)
// can spell trigger another or not (m_canTrigger)
// Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_procEx)
//==========================================================================================
m_procVictim = m_procAttacker = 0;
@@ -1977,7 +1978,7 @@ void Spell::prepareDataForTriggerSystem()
break;
default:
if (m_spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON &&
m_spellInfo->EquippedItemSubClassMask & (1 << ITEM_SUBCLASS_WEAPON_WAND)
m_spellInfo->EquippedItemSubClassMask & (1<<ITEM_SUBCLASS_WEAPON_WAND)
&& m_spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG)) // Wands auto attack
{
m_procAttacker = PROC_FLAG_DONE_RANGED_AUTO_ATTACK;
@@ -1986,7 +1987,7 @@ void Spell::prepareDataForTriggerSystem()
// For other spells trigger procflags are set in Spell::DoAllEffectOnTarget
// Because spell positivity is dependant on target
}
m_hitMask = PROC_HIT_NONE;
m_procEx = PROC_EX_NONE;
// Hunter trap spells - activation proc for Lock and Load, Entrapment and Misdirection
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER &&
@@ -1997,12 +1998,29 @@ void Spell::prepareDataForTriggerSystem()
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 */
// Hellfire Effect - trigger as DOT
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags[0] & 0x00000040)
{
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_TRIGGERED_CAN_TRIGGER_PROC) ||
m_spellInfo->HasAttribute(SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2)))
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->IsTotem() && m_caster->IsControlledByPlayer())
m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY;
}
void Spell::CleanupTargetList()
@@ -2013,32 +2031,6 @@ void Spell::CleanupTargetList()
m_delayMoment = 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*/, Position const* losPosition /*= nullptr*/)
{
for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
@@ -2122,20 +2114,20 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
targetInfo.timeDelay = uint64(m_spellInfo->Speed * 1000.0f);
// Calculate minimum incoming time
if (!m_delayMoment || m_delayMoment > targetInfo.timeDelay)
if (m_delayMoment == 0 || m_delayMoment > targetInfo.timeDelay)
m_delayMoment = targetInfo.timeDelay;
}
else
targetInfo.timeDelay = 0ULL;
targetInfo.timeDelay = 0LL;
// 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, false); // can't reflect twice
targetInfo.reflectResult = m_caster->SpellHitResult(m_caster, m_spellInfo, m_canReflect);
// 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));
if (targetInfo.reflectResult == SPELL_MISS_REFLECT) // Impossible reflect again, so simply deflect spell
targetInfo.reflectResult = SPELL_MISS_PARRY;
// Increase time interval for reflected spells by 1.5
targetInfo.timeDelay += targetInfo.timeDelay >> 1;
@@ -2157,14 +2149,14 @@ void Spell::AddGOTarget(GameObject* go, uint32 effectMask)
{
switch (m_spellInfo->Effects[effIndex].Effect)
{
case SPELL_EFFECT_GAMEOBJECT_DAMAGE:
case SPELL_EFFECT_GAMEOBJECT_REPAIR:
case SPELL_EFFECT_GAMEOBJECT_SET_DESTRUCTION_STATE:
if (go->GetGoType() != GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING)
effectMask &= ~(1 << effIndex);
break;
default:
break;
case SPELL_EFFECT_GAMEOBJECT_DAMAGE:
case SPELL_EFFECT_GAMEOBJECT_REPAIR:
case SPELL_EFFECT_GAMEOBJECT_SET_DESTRUCTION_STATE:
if (go->GetGoType() != GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING)
effectMask &= ~(1 << effIndex);
break;
default:
break;
}
}
}
@@ -2204,7 +2196,7 @@ void Spell::AddGOTarget(GameObject* go, uint32 effectMask)
else
target.timeDelay = uint64(m_spellInfo->Speed * 1000.0f);
if (!m_delayMoment || m_delayMoment > target.timeDelay)
if (m_delayMoment == 0 || m_delayMoment > target.timeDelay)
m_delayMoment = target.timeDelay;
}
else
@@ -2312,13 +2304,13 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
// Fill base trigger info
uint32 procAttacker = m_procAttacker;
uint32 procVictim = m_procVictim;
uint32 hitMask = m_hitMask;
uint32 procEx = m_procEx;
m_spellAura = nullptr; // Set aura to null for every target-make sure that pointer is not used for unit without aura applied
m_spellAura = NULL; // Set aura to null for every target-make sure that pointer is not used for unit without aura applied
// Spells with this flag cannot trigger if effect is cast on self
bool canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_CANT_TRIGGER_PROC) && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE || missInfo == SPELL_MISS_IMMUNE2);
Unit* spellHitTarget = nullptr;
//Spells with this flag cannot trigger if effect is cast on self
bool canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_CANT_TRIGGER_PROC) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE || missInfo == SPELL_MISS_IMMUNE2);
Unit* spellHitTarget = NULL;
if (missInfo == SPELL_MISS_NONE) // In case spell hit target, do all effect on that target
spellHitTarget = unit;
@@ -2346,15 +2338,23 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (missInfo2 != SPELL_MISS_MISS)
m_caster->SendSpellMiss(unit, m_spellInfo->Id, missInfo2);
m_damage = 0;
spellHitTarget = nullptr;
spellHitTarget = NULL;
}
}
// Do not take combo points on dodge and miss
if (missInfo != SPELL_MISS_NONE && m_needComboPoints && m_targets.GetUnitTargetGUID() == target->targetGUID)
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);
}
// 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;
@@ -2401,20 +2401,19 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
uint32 addhealth = m_healing;
if (crit)
{
hitMask |= PROC_HIT_CRITICAL;
addhealth = caster->SpellCriticalHealingBonus(m_spellInfo, addhealth, nullptr);
procEx |= PROC_EX_CRITICAL_HIT;
addhealth = caster->SpellCriticalHealingBonus(m_spellInfo, addhealth, NULL);
}
else
hitMask |= PROC_HIT_NORMAL;
procEx |= PROC_EX_NORMAL_HIT;
HealInfo healInfo(caster, unitTarget, addhealth, m_spellInfo, m_spellInfo->GetSchoolMask());
caster->HealBySpell(healInfo, crit);
unitTarget->getHostileRefManager().threatAssist(caster, float(healInfo.GetEffectiveHeal()) * 0.5f, m_spellInfo);
m_healing = healInfo.GetEffectiveHeal();
int32 gain = caster->HealBySpell(unitTarget, m_spellInfo, addhealth, crit);
unitTarget->getHostileRefManager().threatAssist(caster, float(gain) * 0.5f, m_spellInfo);
m_healing = gain;
// Do triggers for unit
if (canEffectTrigger)
caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, nullptr, &healInfo);
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)
caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
}
// Do damage and triggers
else if (m_damage > 0)
@@ -2429,18 +2428,16 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
// Send log damage message to client
caster->SendSpellNonMeleeDamageLog(&damageInfo);
hitMask |= createProcHitMask(&damageInfo, missInfo);
procEx |= createProcExtendMask(&damageInfo, missInfo);
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
// Do triggers for unit
if (canEffectTrigger)
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)
{
DamageInfo spellDamageInfo(damageInfo, SPELL_DIRECT_DAMAGE, m_attackType, hitMask);
caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, this, &spellDamageInfo, nullptr);
if (caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) &&
(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
caster->ToPlayer()->CastItemCombatSpell(spellDamageInfo);
caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
if (caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) == 0 &&
(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim, procEx);
}
m_damage = damageInfo.damage;
@@ -2452,17 +2449,10 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
{
// Fill base damage struct (unitTarget - is real spell target)
SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask);
hitMask |= createProcHitMask(&damageInfo, missInfo);
// Do triggers for unit
if (canEffectTrigger)
{
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);
if (caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) &&
(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
caster->ToPlayer()->CastItemCombatSpell(spellNoDamageInfo);
}
procEx |= createProcExtendMask(&damageInfo, missInfo);
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)
caster->ProcDamageAndSpell(unit, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
// Failed Pickpocket, reveal rogue
if (missInfo == SPELL_MISS_RESIST && m_spellInfo->HasAttribute(SPELL_ATTR0_CU_PICKPOCKET) && unitTarget->GetTypeId() == TYPEID_UNIT)
@@ -2829,7 +2819,7 @@ bool Spell::UpdateChanneledTargetList()
{
range = m_spellInfo->GetMaxRange(m_spellInfo->IsPositive());
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_RANGE>(m_spellInfo->Id, range, this);
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
}
for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
@@ -2971,7 +2961,7 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered
}
// Prepare data for triggers
prepareDataForTriggerSystem();
prepareDataForTriggerSystem(triggeredByAura);
if (Player* player = m_caster->ToPlayer())
{
@@ -3083,6 +3073,10 @@ void Spell::cancel()
SendInterrupted(0);
SendCastResult(SPELL_FAILED_INTERRUPTED);
// spell is canceled-take mods and clear list
if (m_caster->GetTypeId() == TYPEID_PLAYER)
m_caster->ToPlayer()->RemoveSpellMods(this);
m_appliedMods.clear();
break;
@@ -3316,25 +3310,7 @@ void Spell::cast(bool skipCheck)
SetExecutedCurrently(false);
if (Creature* creatureCaster = m_caster->ToCreature())
if (!m_originalCaster)
return;
// Handle procs on cast
uint32 procAttacker = m_procAttacker;
if (!procAttacker)
{
if (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC)
procAttacker = m_spellInfo->IsPositive() ? PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG;
else
procAttacker = m_spellInfo->IsPositive() ? PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG;
}
uint32 hitMask = m_hitMask;
if (!(hitMask & PROC_HIT_CRITICAL))
hitMask |= PROC_HIT_NORMAL;
m_originalCaster->ProcSkillsAndAuras(nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr);
creatureCaster->ReleaseFocus(this);
}
void Spell::handle_immediate()
@@ -3348,7 +3324,7 @@ void Spell::handle_immediate()
// First mod_duration then haste - see Missile Barrage
// Apply duration mod
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_DURATION>(m_spellInfo->Id, duration);
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
// Apply haste mods
m_caster->ModSpellDurationTime(m_spellInfo, duration, this);
@@ -3491,8 +3467,22 @@ void Spell::_handle_immediate_phase()
}
// process items
for (std::list<ItemTargetInfo>::iterator ihit = m_UniqueItemInfo.begin(); ihit != m_UniqueItemInfo.end(); ++ihit)
for (std::list<ItemTargetInfo>::iterator ihit= m_UniqueItemInfo.begin(); ihit != m_UniqueItemInfo.end(); ++ihit)
DoAllEffectOnTarget(&(*ihit));
if (!m_originalCaster)
return;
// Handle procs on cast
/// @todo finish new proc system:P
if (m_UniqueTargetInfo.empty() && m_targets.HasDst())
{
uint32 procAttacker = m_procAttacker;
if (!procAttacker)
procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS;
// Proc the spells that have DEST target
m_originalCaster->ProcDamageAndSpell(NULL, procAttacker, 0, m_procEx | PROC_EX_NORMAL_HIT, 0, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell);
}
}
void Spell::_handle_finish_phase()
@@ -3519,24 +3509,7 @@ void Spell::_handle_finish_phase()
m_caster->m_extraAttacks = 0;
}
// Handle procs on finish
if (!m_originalCaster)
return;
uint32 procAttacker = m_procAttacker;
if (!procAttacker)
{
if (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC)
procAttacker = m_spellInfo->IsPositive() ? PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG;
else
procAttacker = m_spellInfo->IsPositive() ? PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG;
}
uint32 hitMask = m_hitMask;
if (!(hitMask & PROC_HIT_CRITICAL))
hitMask |= PROC_HIT_NORMAL;
m_originalCaster->ProcSkillsAndAuras(nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_FINISH, hitMask, this, nullptr, nullptr);
/// @todo trigger proc phase finish here
}
void Spell::SendSpellCooldown()
@@ -3702,6 +3675,18 @@ void Spell::finish(bool ok)
m_caster->ToPlayer()->UpdatePotionCooldown(this);
}
if (Player* modOwner = m_caster->GetSpellModOwner())
{
// triggered spell pointer can be not set in some cases
// this is needed for proper apply of triggered spell mods
modOwner->SetSpellModTakingSpell(this, true);
// 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
modOwner->RemoveSpellMods(this);
modOwner->SetSpellModTakingSpell(this, false);
}
// Stop Attack for some spells
if (m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET))
m_caster->AttackStop();
@@ -4440,7 +4425,7 @@ void Spell::TakePower()
hit = false;
//lower spell cost on fail (by talent aura)
if (Player* modOwner = m_caster->ToPlayer()->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_SPELL_COST_REFUND_ON_FAIL>(m_spellInfo->Id, m_powerCost);
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_SPELL_COST_REFUND_ON_FAIL, m_powerCost);
}
break;
}
@@ -4529,7 +4514,7 @@ SpellCastResult Spell::CheckRuneCost(uint32 runeCostID)
{
runeCost[i] = src->RuneCost[i];
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_COST>(m_spellInfo->Id, runeCost[i], this);
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i], this);
}
runeCost[RUNE_DEATH] = MAX_RUNES; // calculated later
@@ -4569,7 +4554,7 @@ void Spell::TakeRunePower(bool didHit)
{
runeCost[i] = runeCostData->RuneCost[i];
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_COST>(m_spellInfo->Id, runeCost[i], this);
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i], this);
}
// Let's say we use a skill that requires a Frost rune. This is the order:
@@ -6015,7 +6000,7 @@ SpellCastResult Spell::CheckRange(bool strict)
maxRange *= ranged->GetTemplate()->RangedModRange * 0.01f;
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_RANGE>(m_spellInfo->Id, maxRange, this);
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, maxRange, this);
maxRange += rangeMod;
@@ -6545,7 +6530,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<SPELLMOD_NOT_LOSE_CASTING_TIME>(m_spellInfo->Id, delayReduce, this);
m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this);
delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
if (delayReduce >= 100)
return;
@@ -6583,7 +6568,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<SPELLMOD_NOT_LOSE_CASTING_TIME>(m_spellInfo->Id, delayReduce, this);
m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this);
delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
if (delayReduce >= 100)
return;
@@ -7506,8 +7491,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 (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_GLOBAL_COOLDOWN>(m_spellInfo->Id, gcd, this);
if (m_caster->GetTypeId() == TYPEID_PLAYER)
m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_GLOBAL_COOLDOWN, gcd, this);
bool isMeleeOrRangedSpell = m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE ||
m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED ||
+3 -3
View File
@@ -359,7 +359,7 @@ class TC_GAME_API Spell
void EffectUpdatePlayerPhase(SpellEffIndex effIndex);
void EffectUpdateZoneAurasAndPhases(SpellEffIndex effIndex);
typedef std::unordered_set<Aura*> UsedSpellMods;
typedef std::set<Aura*> UsedSpellMods;
Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID = ObjectGuid::Empty, bool skipCheck = false);
~Spell();
@@ -584,8 +584,8 @@ class TC_GAME_API Spell
// ******************************************
uint32 m_procAttacker; // Attacker trigger flags
uint32 m_procVictim; // Victim trigger flags
uint32 m_hitMask;
void prepareDataForTriggerSystem();
uint32 m_procEx;
void prepareDataForTriggerSystem(AuraEffect const* triggeredByAura);
// *****************************************
// Spell target subsystem
+19 -20
View File
@@ -1343,8 +1343,7 @@ void Spell::EffectHealthLeech(SpellEffIndex effIndex)
healthGain = m_caster->SpellHealingBonusDone(m_caster, m_spellInfo, healthGain, HEAL);
healthGain = m_caster->SpellHealingBonusTaken(m_caster, m_spellInfo, healthGain, HEAL);
HealInfo healInfo(m_caster, m_caster, healthGain, m_spellInfo, m_spellSchoolMask);
m_caster->HealBySpell(healInfo);
m_caster->HealBySpell(m_caster, m_spellInfo, uint32(healthGain));
}
}
@@ -2033,7 +2032,7 @@ void Spell::EffectSummonType(SpellEffIndex effIndex)
int32 duration = m_spellInfo->GetDuration();
if (Player* modOwner = m_originalCaster->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_DURATION>(m_spellInfo->Id, duration);
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
TempSummon* summon = NULL;
@@ -5181,8 +5180,18 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex)
m_runesState = m_caster->ToPlayer()->GetRunesState();
uint32 count = damage;
if (count == 0)
count = 1;
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);
--count;
}
}
// Blood Tap
if (m_spellInfo->Id == 45529 && count > 0)
@@ -5190,12 +5199,11 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex)
for (uint32 l = 0; l + 1 < 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->GetBaseRune(l) == RUNE_BLOOD) && (player->GetRuneCooldown(l + 1) && player->GetBaseRune(l + 1) == RUNE_BLOOD))
if ((player->GetRuneCooldown(l) && player->GetBaseRune(l) == RuneType(m_spellInfo->Effects[effIndex].MiscValueB)) && (player->GetRuneCooldown(l+1) && player->GetBaseRune(l+1) == RuneType(m_spellInfo->Effects[effIndex].MiscValueB)))
{
// Should always update the rune with the lowest cd
if (l + 1 < MAX_RUNES && player->GetRuneCooldown(l) >= player->GetRuneCooldown(l + 1))
++l;
if (l + 1 < MAX_RUNES && player->GetRuneCooldown(l) >= player->GetRuneCooldown(l+1))
l++;
player->SetRuneCooldown(l, 0);
--count;
// is needed to push through to the client that the rune is active
@@ -5206,15 +5214,6 @@ 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)
{
@@ -5224,7 +5223,7 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex)
for (uint32 i = 0; i < MAX_RUNES; ++i)
{
if (player->GetRuneCooldown(i) && (player->GetBaseRune(i) == RUNE_FROST))
if (player->GetRuneCooldown(i) && (player->GetCurrentRune(i) == RUNE_FROST || player->GetCurrentRune(i) == RUNE_DEATH))
player->SetRuneCooldown(i, 0);
}
}
@@ -5358,7 +5357,7 @@ void Spell::SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const*
int32 duration = m_spellInfo->GetDuration();
if (Player* modOwner = m_originalCaster->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_DURATION>(m_spellInfo->Id, duration);
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
//TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
Map* map = caster->GetMap();
+2 -2
View File
@@ -305,10 +305,10 @@ void SpellHistory::StartCooldown(SpellInfo const* spellInfo, uint32 itemId, Spel
if (Player* modOwner = _owner->GetSpellModOwner())
{
if (cooldown > 0)
modOwner->ApplySpellMod<SPELLMOD_COOLDOWN>(spellInfo->Id, cooldown, spell);
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, cooldown, spell);
if (categoryCooldown > 0 && !spellInfo->HasAttribute(SPELL_ATTR6_IGNORE_CATEGORY_COOLDOWN_MODS))
modOwner->ApplySpellMod<SPELLMOD_COOLDOWN>(spellInfo->Id, categoryCooldown, spell);
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, categoryCooldown, spell);
}
if (_owner->HasAuraTypeWithAffectMask(SPELL_AURA_MOD_SPELL_COOLDOWN_BY_HASTE, spellInfo))
+6 -6
View File
@@ -592,7 +592,7 @@ float SpellEffectInfo::CalcValueMultiplier(Unit* caster, Spell* spell) const
{
float multiplier = ValueMultiplier;
if (Player* modOwner = (caster ? caster->GetSpellModOwner() : NULL))
modOwner->ApplySpellMod<SPELLMOD_VALUE_MULTIPLIER>(_spellInfo->Id, multiplier, spell);
modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_VALUE_MULTIPLIER, multiplier, spell);
return multiplier;
}
@@ -600,7 +600,7 @@ float SpellEffectInfo::CalcDamageMultiplier(Unit* caster, Spell* spell) const
{
float multiplierPercent = DamageMultiplier * 100.0f;
if (Player* modOwner = (caster ? caster->GetSpellModOwner() : NULL))
modOwner->ApplySpellMod<SPELLMOD_DAMAGE_MULTIPLIER>(_spellInfo->Id, multiplierPercent, spell);
modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_DAMAGE_MULTIPLIER, multiplierPercent, spell);
return multiplierPercent / 100.0f;
}
@@ -629,7 +629,7 @@ float SpellEffectInfo::CalcRadius(Unit* caster, Spell* spell) const
radius += entry->RadiusPerLevel * caster->getLevel();
radius = std::min(radius, entry->RadiusMax);
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_RADIUS>(_spellInfo->Id, radius, spell);
modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_RADIUS, radius, spell);
}
return radius;
@@ -2295,7 +2295,7 @@ float SpellInfo::GetMaxRange(bool positive, Unit* caster, Spell* spell) const
range = RangeEntry->maxRangeHostile;
if (caster)
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_RANGE>(Id, range, spell);
modOwner->ApplySpellMod(Id, SPELLMOD_RANGE, range, spell);
return range;
}
@@ -2461,7 +2461,7 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) c
// Apply cost mod by spell
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod<SPELLMOD_COST>(Id, powerCost);
modOwner->ApplySpellMod(Id, SPELLMOD_COST, powerCost);
if (!caster->IsControlledByPlayer())
{
@@ -2643,7 +2643,7 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const
}
break;
case SPELLFAMILY_MAGE:
// Impact
// Ignite
if (SpellIconID == 45)
return true;
break;
+364 -258
View File
@@ -18,7 +18,6 @@
#include "SpellMgr.h"
#include "SpellInfo.h"
#include "Spell.h"
#include "ObjectMgr.h"
#include "SpellAuraDefines.h"
#include "SharedDefines.h"
@@ -783,6 +782,171 @@ SpellGroupStackRule SpellMgr::GetSpellGroupStackRule(SpellGroup group) const
return SPELL_GROUP_STACK_RULE_DEFAULT;
}
SpellProcEventEntry const* SpellMgr::GetSpellProcEvent(uint32 spellId) const
{
SpellProcEventMap::const_iterator itr = mSpellProcEventMap.find(spellId);
if (itr != mSpellProcEventMap.end())
return &itr->second;
return NULL;
}
bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, SpellInfo const* procSpell, uint32 procFlags, uint32 procExtra, bool active) const
{
// No extra req need
uint32 procEvent_procEx = PROC_EX_NONE;
// check prockFlags for condition
if ((procFlags & EventProcFlag) == 0)
return false;
bool hasFamilyMask = false;
/**
* @brief Check auras procced by periodics
*Only damaging Dots can proc auras with PROC_FLAG_TAKEN_DAMAGE
*Only Dots can proc if ONLY has PROC_FLAG_DONE_PERIODIC or PROC_FLAG_TAKEN_PERIODIC.
*Hots can proc if ONLY has PROC_FLAG_DONE_PERIODIC and spellfamily != 0
*Only Dots can proc auras with PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG or PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG
*Only Hots can proc auras with PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS or PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS
*Only Dots can proc auras with PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG or PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG
*Only Hots can proc auras with PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS or PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS
* @param procSpell the spell proccing the aura
* @param procFlags proc_flags of spellProc
* @param procExtra proc_EX of procSpell
* @param EventProcFlag proc_flags of aura to be procced
* @param spellProto SpellInfo of aura to be procced
*/
/// Quick Check - If PROC_FLAG_TAKEN_DAMAGE is set for aura and procSpell dealt damage, proc no matter what kind of spell that deals the damage.
if (procFlags & PROC_FLAG_TAKEN_DAMAGE && EventProcFlag & PROC_FLAG_TAKEN_DAMAGE)
return true;
if (procFlags & PROC_FLAG_DONE_PERIODIC && EventProcFlag & 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)))
return false;
}
if (procFlags & PROC_FLAG_TAKEN_PERIODIC && EventProcFlag & 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;
// Always trigger for this
if (procFlags & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH))
return true;
if (spellProcEvent) // Exist event data
{
// Store extra req
procEvent_procEx = spellProcEvent->procEx;
// For melee triggers
if (procSpell == NULL)
{
// Check (if set) for school (melee attack has 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 & procSpell->SchoolMask) == 0)
return false;
// Check (if set) for spellFamilyName
if (spellProcEvent->spellFamilyName && (spellProcEvent->spellFamilyName != procSpell->SpellFamilyName))
return false;
// spellFamilyName is Ok need check for spellFamilyMask if present
if (spellProcEvent->spellFamilyMask)
{
if (!(spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags))
return false;
hasFamilyMask = true;
// Some spells are not considered as active even with spellfamilyflags set
if (!(procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL))
active = true;
}
}
}
if (procExtra & (PROC_EX_INTERNAL_REQ_FAMILY))
{
if (!hasFamilyMask)
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);
@@ -803,31 +967,10 @@ bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcE
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
if (!(procEntry.AttributesMask & PROC_ATTR_TRIGGERED_CAN_PROC))
{
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))
return false;
@@ -1762,72 +1905,94 @@ void SpellMgr::LoadSpellGroupStackRules()
TC_LOG_INFO("server.loading", ">> Loaded %u spell group stack rules in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
// Used for prepare can/can't triggr aura
static bool InitTriggerAuraData();
// Define can trigger auras
static bool isTriggerAura[TOTAL_AURAS];
// Triggered always, even from triggered spells
static bool isAlwaysTriggeredAura[TOTAL_AURAS];
// Prepare lists
static bool procPrepared = InitTriggerAuraData();
// List of auras that CAN be trigger but may not exist in spell_proc_event
// in most case need for drop charges
// in some types of aura need do additional check
// for example SPELL_AURA_MECHANIC_IMMUNITY - need check for mechanic
bool InitTriggerAuraData()
void SpellMgr::LoadSpellProcEvents()
{
for (uint16 i = 0; i < TOTAL_AURAS; ++i)
uint32 oldMSTime = getMSTime();
mSpellProcEventMap.clear(); // need for reload case
// 0 1 2 3 4 5 6 7 8 9 10
QueryResult result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, procFlags, procEx, ppmRate, CustomChance, Cooldown FROM spell_proc_event");
if (!result)
{
isTriggerAura[i] = false;
isAlwaysTriggeredAura[i] = false;
TC_LOG_INFO("server.loading", ">> Loaded 0 spell proc event conditions. DB table `spell_proc_event` is empty.");
return;
}
isTriggerAura[SPELL_AURA_DUMMY] = true; // Most dummy auras should require scripting. Remove?
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_FEAR] = true;
isAlwaysTriggeredAura[SPELL_AURA_MOD_ROOT] = true;
isAlwaysTriggeredAura[SPELL_AURA_MOD_STUN] = true;
isAlwaysTriggeredAura[SPELL_AURA_TRANSFORM] = true;
isAlwaysTriggeredAura[SPELL_AURA_SPELL_MAGNET] = true;
isAlwaysTriggeredAura[SPELL_AURA_SCHOOL_ABSORB] = true;
isAlwaysTriggeredAura[SPELL_AURA_MOD_STEALTH] = true;
uint32 count = 0;
return true;
do
{
Field* fields = result->Fetch();
int32 spellId = fields[0].GetInt32();
bool allRanks = false;
if (spellId < 0)
{
allRanks = true;
spellId = -spellId;
}
SpellInfo const* spellInfo = GetSpellInfo(spellId);
if (!spellInfo)
{
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc_event` does not exist.", spellId);
continue;
}
if (allRanks)
{
if (!spellInfo->IsRanked())
TC_LOG_ERROR("sql.sql", "The spell %u is listed in `spell_proc_event` with all ranks, but spell has no ranks.", spellId);
if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId))
{
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc_event` is not first rank of spell.", spellId);
continue;
}
}
SpellProcEventEntry spellProcEvent;
spellProcEvent.schoolMask = fields[1].GetInt8();
spellProcEvent.spellFamilyName = fields[2].GetUInt16();
spellProcEvent.spellFamilyMask[0] = fields[3].GetUInt32();
spellProcEvent.spellFamilyMask[1] = fields[4].GetUInt32();
spellProcEvent.spellFamilyMask[2] = fields[5].GetUInt32();
spellProcEvent.procFlags = fields[6].GetUInt32();
spellProcEvent.procEx = fields[7].GetUInt32();
spellProcEvent.ppmRate = fields[8].GetFloat();
spellProcEvent.customChance = fields[9].GetFloat();
spellProcEvent.cooldown = fields[10].GetUInt32();
while (spellInfo)
{
if (mSpellProcEventMap.find(spellInfo->Id) != mSpellProcEventMap.end())
{
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc_event` already has its first rank in table.", spellInfo->Id);
break;
}
if (!spellInfo->ProcFlags && !spellProcEvent.procFlags)
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc_event` is probably not a triggered spell.", spellInfo->Id);
mSpellProcEventMap[spellInfo->Id] = spellProcEvent;
if (allRanks)
spellInfo = spellInfo->GetNextRankSpell();
else
break;
}
++count;
}
while (result->NextRow());
TC_LOG_INFO("server.loading", ">> Loaded %u extra spell proc event conditions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
+void SpellMgr::LoadSpellProcs()
void SpellMgr::LoadSpellProcs()
{
uint32 oldMSTime = getMSTime();
@@ -1838,199 +2003,126 @@ bool InitTriggerAuraData()
// 6 7 8 9 10 11 12 13 14
"ProcFlags, SpellTypeMask, SpellPhaseMask, HitMask, AttributesMask, ProcsPerMinute, Chance, Cooldown, Charges FROM spell_proc");
uint32 count = 0;
if (result)
if (!result)
{
do
{
Field* fields = result->Fetch();
int32 spellId = fields[0].GetInt32();
bool allRanks = false;
if (spellId < 0)
{
allRanks = true;
spellId = -spellId;
}
SpellInfo const* spellInfo = GetSpellInfo(spellId);
if (!spellInfo)
{
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` does not exist", spellId);
continue;
}
if (allRanks)
{
if (!spellInfo->IsRanked())
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` with all ranks, but spell has no ranks.", spellId);
if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId))
{
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` is not the first rank of the spell.", spellId);
continue;
}
}
SpellProcEntry baseProcEntry;
baseProcEntry.SchoolMask = fields[1].GetInt8();
baseProcEntry.SpellFamilyName = fields[2].GetUInt16();
baseProcEntry.SpellFamilyMask[0] = fields[3].GetUInt32();
baseProcEntry.SpellFamilyMask[1] = fields[4].GetUInt32();
baseProcEntry.SpellFamilyMask[2] = fields[5].GetUInt32();
baseProcEntry.ProcFlags = fields[6].GetUInt32();
baseProcEntry.SpellTypeMask = fields[7].GetUInt32();
baseProcEntry.SpellPhaseMask = fields[8].GetUInt32();
baseProcEntry.HitMask = fields[9].GetUInt32();
baseProcEntry.AttributesMask = fields[10].GetUInt32();
baseProcEntry.ProcsPerMinute = fields[11].GetFloat();
baseProcEntry.Chance = fields[12].GetFloat();
baseProcEntry.Cooldown = Milliseconds(fields[13].GetUInt32());
baseProcEntry.Charges = fields[14].GetUInt8();
while (spellInfo)
{
if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end())
{
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` already has its first rank in the table.", spellInfo->Id);
break;
}
SpellProcEntry procEntry = SpellProcEntry(baseProcEntry);
// take defaults from dbcs
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)
TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SchoolMask` set: %u", spellInfo->Id, procEntry.SchoolMask);
if (procEntry.SpellFamilyName && (procEntry.SpellFamilyName < SPELLFAMILY_MAGE || procEntry.SpellFamilyName > SPELLFAMILY_PET || procEntry.SpellFamilyName == 14 || procEntry.SpellFamilyName == 16))
TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SpellFamilyName` set: %u", spellInfo->Id, procEntry.SpellFamilyName);
if (procEntry.Chance < 0)
{
TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `Chance` field", spellInfo->Id);
procEntry.Chance = 0;
}
if (procEntry.ProcsPerMinute < 0)
{
TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `ProcsPerMinute` field", spellInfo->Id);
procEntry.ProcsPerMinute = 0;
}
if (!procEntry.ProcFlags)
TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u doesn't have any `ProcFlags` value defined, proc will not be triggered.", spellInfo->Id);
if (procEntry.SpellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL)
TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SpellTypeMask` set: %u", spellInfo->Id, procEntry.SpellTypeMask);
if (procEntry.SpellTypeMask && !(procEntry.ProcFlags & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK)))
TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has `SpellTypeMask` value defined, but it will not be used for the defined `ProcFlags` value.", spellInfo->Id);
if (!procEntry.SpellPhaseMask && procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK)
TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u doesn't have any `SpellPhaseMask` value defined, but it is required for the defined `ProcFlags` value. Proc will not be triggered.", spellInfo->Id);
if (procEntry.SpellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL)
TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has wrong `SpellPhaseMask` set: %u", spellInfo->Id, procEntry.SpellPhaseMask);
if (procEntry.SpellPhaseMask && !(procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK))
TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has a `SpellPhaseMask` value defined, but it will not be used for the defined `ProcFlags` value.", spellInfo->Id);
if (procEntry.HitMask & ~PROC_HIT_MASK_ALL)
TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has wrong `HitMask` set: %u", spellInfo->Id, 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)))))
TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has `HitMask` value defined, but it will not be used for defined `ProcFlags` and `SpellPhaseMask` values.", spellInfo->Id);
mSpellProcMap[spellInfo->Id] = procEntry;
if (allRanks)
spellInfo = spellInfo->GetNextRankSpell();
else
break;
}
++count;
} while (result->NextRow());
}
else
TC_LOG_INFO("server.loading", ">> Loaded 0 spell proc conditions and data. DB table `spell_proc` is empty.");
return;
}
TC_LOG_INFO("server.loading", ">> Loaded %u spell proc conditions and data in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
// This generates default procs to retain compatibility with previous proc system
TC_LOG_INFO("server.loading", "Generating spell proc data from SpellMap...");
count = 0;
oldMSTime = getMSTime();
for (SpellInfo const* spellInfo : mSpellInfoMap)
uint32 count = 0;
do
{
if (!spellInfo)
continue;
Field* fields = result->Fetch();
if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end())
continue;
int32 spellId = fields[0].GetInt32();
bool found = false, addTriggerFlag = false;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
bool allRanks = false;
if (spellId < 0)
{
if (!spellInfo->Effects[i].IsEffect())
continue;
uint32 auraName = spellInfo->Effects[i].ApplyAuraName;
if (!auraName)
continue;
if (!isTriggerAura[auraName])
continue;
found = true;
if (!addTriggerFlag && isAlwaysTriggeredAura[auraName])
addTriggerFlag = true;
break;
allRanks = true;
spellId = -spellId;
}
if (!found)
continue;
if (!spellInfo->ProcFlags)
continue;
SpellProcEntry procEntry;
procEntry.SchoolMask = 0;
procEntry.SpellFamilyName = spellInfo->SpellFamilyName;
procEntry.ProcFlags = spellInfo->ProcFlags;
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;
procEntry.SpellTypeMask = PROC_SPELL_TYPE_MASK_ALL;
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)
SpellInfo const* spellInfo = GetSpellInfo(spellId);
if (!spellInfo)
{
if (spellInfo->Effects[i].IsAura(SPELL_AURA_REFLECT_SPELLS) || spellInfo->Effects[i].IsAura(SPELL_AURA_REFLECT_SPELLS_SCHOOL))
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` does not exist", spellId);
continue;
}
if (allRanks)
{
if (!spellInfo->IsRanked())
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` with all ranks, but spell has no ranks.", spellId);
if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId))
{
procEntry.HitMask = PROC_HIT_REFLECT;
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` is not the first rank of the spell.", spellId);
continue;
}
}
SpellProcEntry baseProcEntry;
baseProcEntry.SchoolMask = fields[1].GetInt8();
baseProcEntry.SpellFamilyName = fields[2].GetUInt16();
baseProcEntry.SpellFamilyMask[0] = fields[3].GetUInt32();
baseProcEntry.SpellFamilyMask[1] = fields[4].GetUInt32();
baseProcEntry.SpellFamilyMask[2] = fields[5].GetUInt32();
baseProcEntry.ProcFlags = fields[6].GetUInt32();
baseProcEntry.SpellTypeMask = fields[7].GetUInt32();
baseProcEntry.SpellPhaseMask = fields[8].GetUInt32();
baseProcEntry.HitMask = fields[9].GetUInt32();
baseProcEntry.AttributesMask = fields[10].GetUInt32();
baseProcEntry.ProcsPerMinute = fields[11].GetFloat();
baseProcEntry.Chance = fields[12].GetFloat();
baseProcEntry.Cooldown = Milliseconds(fields[13].GetUInt32());
baseProcEntry.Charges = fields[14].GetUInt8();
while (spellInfo)
{
if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end())
{
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` already has its first rank in the table.", spellInfo->Id);
break;
}
SpellProcEntry procEntry = SpellProcEntry(baseProcEntry);
// take defaults from dbcs
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)
TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SchoolMask` set: %u", spellInfo->Id, procEntry.SchoolMask);
if (procEntry.SpellFamilyName && (procEntry.SpellFamilyName < 3 || procEntry.SpellFamilyName > 17 || procEntry.SpellFamilyName == 14 || procEntry.SpellFamilyName == 16))
TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SpellFamilyName` set: %u", spellInfo->Id, procEntry.SpellFamilyName);
if (procEntry.Chance < 0)
{
TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `Chance` field", spellInfo->Id);
procEntry.Chance = 0;
}
if (procEntry.ProcsPerMinute < 0)
{
TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `ProcsPerMinute` field", spellInfo->Id);
procEntry.ProcsPerMinute = 0;
}
if (procEntry.Chance == 0 && procEntry.ProcsPerMinute == 0)
TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u doesn't have any `Chance` and `ProcsPerMinute` values defined, proc will not be triggered", spellInfo->Id);
if (!procEntry.ProcFlags)
TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u doesn't have any `ProcFlags` value defined, proc will not be triggered.", spellInfo->Id);
if (procEntry.SpellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL)
TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SpellTypeMask` set: %u", spellInfo->Id, procEntry.SpellTypeMask);
if (procEntry.SpellTypeMask && !(procEntry.ProcFlags & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK)))
TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has `SpellTypeMask` value defined, but it will not be used for the defined `ProcFlags` value.", spellInfo->Id);
if (!procEntry.SpellPhaseMask && procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK)
TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u doesn't have any `SpellPhaseMask` value defined, but it is required for the defined `ProcFlags` value. Proc will not be triggered.", spellInfo->Id);
if (procEntry.SpellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL)
TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has wrong `SpellPhaseMask` set: %u", spellInfo->Id, procEntry.SpellPhaseMask);
if (procEntry.SpellPhaseMask && !(procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK))
TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has a `SpellPhaseMask` value defined, but it will not be used for the defined `ProcFlags` value.", spellInfo->Id);
if (procEntry.HitMask & ~PROC_HIT_MASK_ALL)
TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has wrong `HitMask` set: %u", spellInfo->Id, 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)))))
TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has `HitMask` value defined, but it will not be used for defined `ProcFlags` and `SpellPhaseMask` values.", spellInfo->Id);
mSpellProcMap[spellInfo->Id] = procEntry;
if (allRanks)
spellInfo = spellInfo->GetNextRankSpell();
else
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;
}
while (result->NextRow());
TC_LOG_INFO("server.loading", ">> Generated spell proc data for %u spells in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
TC_LOG_INFO("server.loading", ">> Loaded %u spell proc conditions and data in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
void SpellMgr::LoadSpellBonusess()
@@ -3007,7 +3099,7 @@ void SpellMgr::LoadSpellInfoCorrections()
case 59725: // Improved Spell Reflection - aoe aura
// Target entry seems to be wrong for this spell :/
spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER_AREA_PARTY);
spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_20_YARDS);
spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_10_YARDS_2);
break;
case 43265: // Death and Decay
// We need access to the targets of the dynaura to correctly apply the damage spell
@@ -3100,12 +3192,23 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->MaxAffectedTargets = 1;
spellInfo->Effects[EFFECT_0].TriggerSpell = 33760;
break;
case 17941: // Shadow Trance
case 22008: // Netherwind Focus
case 34477: // Misdirection
case 34936: // Backlash
case 48108: // Hot Streak
case 51124: // Killing Machine
case 54741: // Firestarter
case 57761: // Fireball!
case 64823: // Item - Druid T8 Balance 4P Bonus
case 88819: // Daybreak
case 18820: // Insight
spellInfo->ProcCharges = 1;
break;
case 44544: // Fingers of Frost
spellInfo->Effects[EFFECT_0].SpellClassMask = flag96(685904631, 1151048, 0);
break;
case 74396: // Fingers of Frost visual buff
case 53257: // Cobra Strikes
spellInfo->ProcCharges = 2;
spellInfo->StackAmount = 0;
@@ -3115,6 +3218,9 @@ void SpellMgr::LoadSpellInfoCorrections()
case 56612:
spellInfo->Effects[EFFECT_0].SpellClassMask = flag96(0x02000000, 0, 0);
break;
case 28200: // Ascendance (Talisman of Ascendance trinket)
spellInfo->ProcCharges = 6;
break;
case 47201: // Everlasting Affliction (1)
case 47202: // Everlasting Affliction (2)
case 47203: // Everlasting Affliction (3)
+58 -4
View File
@@ -192,6 +192,43 @@ 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 al 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
// 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,
@@ -232,12 +269,23 @@ enum ProcFlagsHit
enum ProcAttributes
{
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
PROC_ATTR_REQ_EXP_OR_HONOR = 0x0000010
};
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)
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_
};
typedef std::unordered_map<uint32, SpellProcEventEntry> SpellProcEventMap;
struct SpellProcEntry
{
uint32 SchoolMask; // if nonzero - bitmask for matching proc condition based on spell's school
@@ -610,6 +658,10 @@ class TC_GAME_API SpellMgr
SpellGroupStackRule CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2) const;
SpellGroupStackRule GetSpellGroupStackRule(SpellGroup groupid) const;
// Spell proc event table
SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const;
bool IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, SpellInfo const* procSpell, uint32 procFlags, uint32 procExtra, bool active) const;
// Spell proc table
SpellProcEntry const* GetSpellProcEntry(uint32 spellId) const;
bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const;
@@ -668,6 +720,7 @@ class TC_GAME_API SpellMgr
void LoadSpellTargetPositions();
void LoadSpellGroups();
void LoadSpellGroupStackRules();
void LoadSpellProcEvents();
void LoadSpellProcs();
void LoadSpellBonusess();
void LoadSpellThreats();
@@ -696,6 +749,7 @@ class TC_GAME_API SpellMgr
SpellSpellGroupMap mSpellSpellGroup;
SpellGroupSpellMap mSpellGroupSpell;
SpellGroupStackMap mSpellGroupStack;
SpellProcEventMap mSpellProcEventMap;
SpellProcMap mSpellProcMap;
SpellBonusMap mSpellBonusMap;
SpellThreatMap mSpellThreatMap;
-16
View File
@@ -720,10 +720,6 @@ bool AuraScript::_Validate(SpellInfo const* entry)
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
TC_LOG_ERROR("scripts", "Spell `%u` of script `%s` 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))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `DoCheckEffectProc` of AuraScript won't be executed", entry->Id, itr->ToString().c_str(), m_scriptName->c_str());
for (std::list<AuraProcHandler>::iterator itr = DoPrepareProc.begin(); itr != DoPrepareProc.end(); ++itr)
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
TC_LOG_ERROR("scripts", "Spell `%u` of script `%s` does not have apply aura effect - handler bound to hook `DoPrepareProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
@@ -891,17 +887,6 @@ 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;
@@ -1163,7 +1148,6 @@ 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_PREPARE_PROC:
case AURA_SCRIPT_HOOK_PROC:
case AURA_SCRIPT_HOOK_AFTER_PROC:
-17
View File
@@ -468,7 +468,6 @@ enum AuraScriptHookType
AURA_SCRIPT_HOOK_AFTER_DISPEL,
// Spell Proc Hooks
AURA_SCRIPT_HOOK_CHECK_PROC,
AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC,
AURA_SCRIPT_HOOK_PREPARE_PROC,
AURA_SCRIPT_HOOK_PROC,
AURA_SCRIPT_HOOK_EFFECT_PROC,
@@ -500,7 +499,6 @@ class TC_GAME_API AuraScript : public _SpellScript
typedef void(CLASSNAME::*AuraEffectAbsorbFnType)(AuraEffect*, DamageInfo &, uint32 &); \
typedef void(CLASSNAME::*AuraEffectSplitFnType)(AuraEffect*, DamageInfo &, uint32 &); \
typedef bool(CLASSNAME::*AuraCheckProcFnType)(ProcEventInfo&); \
typedef bool(CLASSNAME::*AuraCheckEffectProcFnType)(AuraEffect const*, ProcEventInfo&); \
typedef void(CLASSNAME::*AuraProcFnType)(ProcEventInfo&); \
typedef void(CLASSNAME::*AuraEffectProcFnType)(AuraEffect const*, ProcEventInfo&); \
@@ -610,14 +608,6 @@ class TC_GAME_API AuraScript : public _SpellScript
private:
AuraCheckProcFnType _HandlerScript;
};
class TC_GAME_API CheckEffectProcHandler : public EffectBase
{
public:
CheckEffectProcHandler(AuraCheckEffectProcFnType handlerScript, uint8 effIndex, uint16 effName);
bool Call(AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo);
private:
AuraCheckEffectProcFnType _HandlerScript;
};
class TC_GAME_API AuraProcHandler
{
public:
@@ -648,7 +638,6 @@ class TC_GAME_API AuraScript : public _SpellScript
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 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) { } }
@@ -787,12 +776,6 @@ class TC_GAME_API AuraScript : public _SpellScript
HookList<CheckProcHandler> DoCheckProc;
#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);
+3
View File
@@ -1560,6 +1560,9 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading Spell Learn Spells...");
sSpellMgr->LoadSpellLearnSpells();
TC_LOG_INFO("server.loading", "Loading Spell Proc Event conditions...");
sSpellMgr->LoadSpellProcEvents();
TC_LOG_INFO("server.loading", "Loading Spell Proc conditions and data...");
sSpellMgr->LoadSpellProcs();
+10
View File
@@ -142,6 +142,7 @@ public:
{ "spell_loot_template", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_LOOT_TEMPLATE, true, &HandleReloadLootTemplatesSpellCommand, "" },
{ "spell_linked_spell", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_LINKED_SPELL, true, &HandleReloadSpellLinkedSpellCommand, "" },
{ "spell_pet_auras", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_PET_AURAS, true, &HandleReloadSpellPetAurasCommand, "" },
{ "spell_proc_event", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_PROC_EVENT, true, &HandleReloadSpellProcEventCommand, "" },
{ "spell_proc", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_PROC, true, &HandleReloadSpellProcsCommand, "" },
{ "spell_scripts", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_SCRIPTS, true, &HandleReloadSpellScriptsCommand, "" },
{ "spell_target_position", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_TARGET_POSITION, true, &HandleReloadSpellTargetPositionCommand, "" },
@@ -273,6 +274,7 @@ public:
HandleReloadSpellGroupsCommand(handler, "a");
HandleReloadSpellLearnSpellCommand(handler, "a");
HandleReloadSpellLinkedSpellCommand(handler, "a");
HandleReloadSpellProcEventCommand(handler, "a");
HandleReloadSpellProcsCommand(handler, "a");
HandleReloadSpellBonusesCommand(handler, "a");
HandleReloadSpellTargetPositionCommand(handler, "a");
@@ -807,6 +809,14 @@ public:
return true;
}
static bool HandleReloadSpellProcEventCommand(ChatHandler* handler, const char* /*args*/)
{
TC_LOG_INFO("misc", "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, const char* /*args*/)
{
TC_LOG_INFO("misc", "Re-Loading Spell Proc conditions and data...");