Revert "Core/Spells: Implementation of QAston proc system"
This reverts commit a70e4e26b3.
This commit is contained in:
1 parent
f9ebb50a8a
commit
57d0a5d16d
22 files changed
+3878
-1188
No files matched your search
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+2921
-208
File diff suppressed because it is too large.
Load diff
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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 ||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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...");
|
||||
|
||||
Reference in new issue
Block a user