mangos/src/game/WorldHandlers/UnitAuraProcHandler.cpp
Nick 2827834b2d Revert "Revert "[Rogue][Talent] Improved sap""
This reverts commit f533f4d379850e59283b8b2f9e2052cdb51695d1.
2015-11-17 20:05:33 +09:00

1439 lines
72 KiB
C++

/**
* MaNGOS is a full featured server for World of Warcraft, supporting
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
*
* Copyright (C) 2005-2015 MaNGOS project <http://getmangos.eu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
* and lore are copyrighted by Blizzard Entertainment, Inc.
*/
#include "Common.h"
#include "Log.h"
#include "ObjectMgr.h"
#include "SpellMgr.h"
#include "Player.h"
#include "Unit.h"
#include "Spell.h"
#include "SpellAuras.h"
#include "Totem.h"
#include "Creature.h"
#include "Formulas.h"
#include "CreatureAI.h"
#include "ScriptMgr.h"
#include "Util.h"
pAuraProcHandler AuraProcHandler[TOTAL_AURAS] =
{
&Unit::HandleNULLProc, // 0 SPELL_AURA_NONE
&Unit::HandleNULLProc, // 1 SPELL_AURA_BIND_SIGHT
&Unit::HandleNULLProc, // 2 SPELL_AURA_MOD_POSSESS
&Unit::HandleNULLProc, // 3 SPELL_AURA_PERIODIC_DAMAGE
&Unit::HandleDummyAuraProc, // 4 SPELL_AURA_DUMMY
&Unit::HandleNULLProc, // 5 SPELL_AURA_MOD_CONFUSE
&Unit::HandleNULLProc, // 6 SPELL_AURA_MOD_CHARM
&Unit::HandleRemoveByDamageChanceProc, // 7 SPELL_AURA_MOD_FEAR
&Unit::HandleNULLProc, // 8 SPELL_AURA_PERIODIC_HEAL
&Unit::HandleNULLProc, // 9 SPELL_AURA_MOD_ATTACKSPEED
&Unit::HandleNULLProc, // 10 SPELL_AURA_MOD_THREAT
&Unit::HandleNULLProc, // 11 SPELL_AURA_MOD_TAUNT
&Unit::HandleNULLProc, // 12 SPELL_AURA_MOD_STUN
&Unit::HandleNULLProc, // 13 SPELL_AURA_MOD_DAMAGE_DONE
&Unit::HandleNULLProc, // 14 SPELL_AURA_MOD_DAMAGE_TAKEN
&Unit::HandleNULLProc, // 15 SPELL_AURA_DAMAGE_SHIELD
&Unit::HandleNULLProc, // 16 SPELL_AURA_MOD_STEALTH
&Unit::HandleNULLProc, // 17 SPELL_AURA_MOD_STEALTH_DETECT
&Unit::HandleInvisibilityAuraProc, // 18 SPELL_AURA_MOD_INVISIBILITY
&Unit::HandleNULLProc, // 19 SPELL_AURA_MOD_INVISIBILITY_DETECTION
&Unit::HandleNULLProc, // 20 SPELL_AURA_OBS_MOD_HEALTH
&Unit::HandleNULLProc, // 21 SPELL_AURA_OBS_MOD_MANA
&Unit::HandleModResistanceAuraProc, // 22 SPELL_AURA_MOD_RESISTANCE
&Unit::HandleNULLProc, // 23 SPELL_AURA_PERIODIC_TRIGGER_SPELL
&Unit::HandleNULLProc, // 24 SPELL_AURA_PERIODIC_ENERGIZE
&Unit::HandleNULLProc, // 25 SPELL_AURA_MOD_PACIFY
&Unit::HandleRemoveByDamageChanceProc, // 26 SPELL_AURA_MOD_ROOT
&Unit::HandleNULLProc, // 27 SPELL_AURA_MOD_SILENCE
&Unit::HandleNULLProc, // 28 SPELL_AURA_REFLECT_SPELLS
&Unit::HandleNULLProc, // 29 SPELL_AURA_MOD_STAT
&Unit::HandleNULLProc, // 30 SPELL_AURA_MOD_SKILL
&Unit::HandleNULLProc, // 31 SPELL_AURA_MOD_INCREASE_SPEED
&Unit::HandleNULLProc, // 32 SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED
&Unit::HandleNULLProc, // 33 SPELL_AURA_MOD_DECREASE_SPEED
&Unit::HandleNULLProc, // 34 SPELL_AURA_MOD_INCREASE_HEALTH
&Unit::HandleNULLProc, // 35 SPELL_AURA_MOD_INCREASE_ENERGY
&Unit::HandleNULLProc, // 36 SPELL_AURA_MOD_SHAPESHIFT
&Unit::HandleNULLProc, // 37 SPELL_AURA_EFFECT_IMMUNITY
&Unit::HandleNULLProc, // 38 SPELL_AURA_STATE_IMMUNITY
&Unit::HandleNULLProc, // 39 SPELL_AURA_SCHOOL_IMMUNITY
&Unit::HandleNULLProc, // 40 SPELL_AURA_DAMAGE_IMMUNITY
&Unit::HandleNULLProc, // 41 SPELL_AURA_DISPEL_IMMUNITY
&Unit::HandleProcTriggerSpellAuraProc, // 42 SPELL_AURA_PROC_TRIGGER_SPELL
&Unit::HandleProcTriggerDamageAuraProc, // 43 SPELL_AURA_PROC_TRIGGER_DAMAGE
&Unit::HandleNULLProc, // 44 SPELL_AURA_TRACK_CREATURES
&Unit::HandleNULLProc, // 45 SPELL_AURA_TRACK_RESOURCES
&Unit::HandleNULLProc, // 46 SPELL_AURA_46
&Unit::HandleNULLProc, // 47 SPELL_AURA_MOD_PARRY_PERCENT
&Unit::HandleNULLProc, // 48 SPELL_AURA_48
&Unit::HandleNULLProc, // 49 SPELL_AURA_MOD_DODGE_PERCENT
&Unit::HandleNULLProc, // 50 SPELL_AURA_MOD_BLOCK_SKILL obsolete?
&Unit::HandleNULLProc, // 51 SPELL_AURA_MOD_BLOCK_PERCENT
&Unit::HandleNULLProc, // 52 SPELL_AURA_MOD_CRIT_PERCENT
&Unit::HandleNULLProc, // 53 SPELL_AURA_PERIODIC_LEECH
&Unit::HandleNULLProc, // 54 SPELL_AURA_MOD_HIT_CHANCE
&Unit::HandleNULLProc, // 55 SPELL_AURA_MOD_SPELL_HIT_CHANCE
&Unit::HandleNULLProc, // 56 SPELL_AURA_TRANSFORM
&Unit::HandleNULLProc, // 57 SPELL_AURA_MOD_SPELL_CRIT_CHANCE
&Unit::HandleNULLProc, // 58 SPELL_AURA_MOD_INCREASE_SWIM_SPEED
&Unit::HandleNULLProc, // 59 SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
&Unit::HandleRemoveByDamageChanceProc, // 60 SPELL_AURA_MOD_PACIFY_SILENCE
&Unit::HandleNULLProc, // 61 SPELL_AURA_MOD_SCALE
&Unit::HandleNULLProc, // 62 SPELL_AURA_PERIODIC_HEALTH_FUNNEL
&Unit::HandleNULLProc, // 63 SPELL_AURA_PERIODIC_MANA_FUNNEL obsolete?
&Unit::HandleNULLProc, // 64 SPELL_AURA_PERIODIC_MANA_LEECH
&Unit::HandleModCastingSpeedNotStackAuraProc, // 65 SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK
&Unit::HandleNULLProc, // 66 SPELL_AURA_FEIGN_DEATH
&Unit::HandleNULLProc, // 67 SPELL_AURA_MOD_DISARM
&Unit::HandleNULLProc, // 68 SPELL_AURA_MOD_STALKED
&Unit::HandleNULLProc, // 69 SPELL_AURA_SCHOOL_ABSORB
&Unit::HandleNULLProc, // 70 SPELL_AURA_EXTRA_ATTACKS Useless, used by only one spell that has only visual effect
&Unit::HandleNULLProc, // 71 SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
&Unit::HandleModPowerCostSchoolAuraProc, // 72 SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT
&Unit::HandleModPowerCostSchoolAuraProc, // 73 SPELL_AURA_MOD_POWER_COST_SCHOOL
&Unit::HandleReflectSpellsSchoolAuraProc, // 74 SPELL_AURA_REFLECT_SPELLS_SCHOOL
&Unit::HandleNULLProc, // 75 SPELL_AURA_MOD_LANGUAGE
&Unit::HandleNULLProc, // 76 SPELL_AURA_FAR_SIGHT
&Unit::HandleMechanicImmuneResistanceAuraProc, // 77 SPELL_AURA_MECHANIC_IMMUNITY
&Unit::HandleNULLProc, // 78 SPELL_AURA_MOUNTED
&Unit::HandleNULLProc, // 79 SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
&Unit::HandleNULLProc, // 80 SPELL_AURA_MOD_PERCENT_STAT
&Unit::HandleNULLProc, // 81 SPELL_AURA_SPLIT_DAMAGE_PCT
&Unit::HandleNULLProc, // 82 SPELL_AURA_WATER_BREATHING
&Unit::HandleNULLProc, // 83 SPELL_AURA_MOD_BASE_RESISTANCE
&Unit::HandleNULLProc, // 84 SPELL_AURA_MOD_REGEN
&Unit::HandleCantTrigger, // 85 SPELL_AURA_MOD_POWER_REGEN
&Unit::HandleNULLProc, // 86 SPELL_AURA_CHANNEL_DEATH_ITEM
&Unit::HandleNULLProc, // 87 SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
&Unit::HandleNULLProc, // 88 SPELL_AURA_MOD_HEALTH_REGEN_PERCENT
&Unit::HandleNULLProc, // 89 SPELL_AURA_PERIODIC_DAMAGE_PERCENT
&Unit::HandleNULLProc, // 90 SPELL_AURA_MOD_RESIST_CHANCE Useless
&Unit::HandleNULLProc, // 91 SPELL_AURA_MOD_DETECT_RANGE
&Unit::HandleNULLProc, // 92 SPELL_AURA_PREVENTS_FLEEING
&Unit::HandleNULLProc, // 93 SPELL_AURA_MOD_UNATTACKABLE
&Unit::HandleNULLProc, // 94 SPELL_AURA_INTERRUPT_REGEN
&Unit::HandleNULLProc, // 95 SPELL_AURA_GHOST
&Unit::HandleNULLProc, // 96 SPELL_AURA_SPELL_MAGNET
&Unit::HandleNULLProc, // 97 SPELL_AURA_MANA_SHIELD
&Unit::HandleNULLProc, // 98 SPELL_AURA_MOD_SKILL_TALENT
&Unit::HandleNULLProc, // 99 SPELL_AURA_MOD_ATTACK_POWER
&Unit::HandleNULLProc, // 100 SPELL_AURA_AURAS_VISIBLE obsolete? all player can see all auras now
&Unit::HandleNULLProc, // 101 SPELL_AURA_MOD_RESISTANCE_PCT
&Unit::HandleNULLProc, // 102 SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS
&Unit::HandleNULLProc, // 103 SPELL_AURA_MOD_TOTAL_THREAT
&Unit::HandleNULLProc, // 104 SPELL_AURA_WATER_WALK
&Unit::HandleNULLProc, // 105 SPELL_AURA_FEATHER_FALL
&Unit::HandleNULLProc, // 106 SPELL_AURA_HOVER
&Unit::HandleNULLProc, // 107 SPELL_AURA_ADD_FLAT_MODIFIER
&Unit::HandleNULLProc, // 108 SPELL_AURA_ADD_PCT_MODIFIER
&Unit::HandleNULLProc, // 109 SPELL_AURA_ADD_TARGET_TRIGGER
&Unit::HandleNULLProc, // 110 SPELL_AURA_MOD_POWER_REGEN_PERCENT
&Unit::HandleNULLProc, // 111 SPELL_AURA_ADD_CASTER_HIT_TRIGGER
&Unit::HandleOverrideClassScriptAuraProc, // 112 SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
&Unit::HandleNULLProc, // 113 SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN
&Unit::HandleNULLProc, // 114 SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT
&Unit::HandleNULLProc, // 115 SPELL_AURA_MOD_HEALING
&Unit::HandleNULLProc, // 116 SPELL_AURA_MOD_REGEN_DURING_COMBAT
&Unit::HandleMechanicImmuneResistanceAuraProc, // 117 SPELL_AURA_MOD_MECHANIC_RESISTANCE
&Unit::HandleNULLProc, // 118 SPELL_AURA_MOD_HEALING_PCT
&Unit::HandleNULLProc, // 119 SPELL_AURA_SHARE_PET_TRACKING useless
&Unit::HandleNULLProc, // 120 SPELL_AURA_UNTRACKABLE
&Unit::HandleNULLProc, // 121 SPELL_AURA_EMPATHY
&Unit::HandleNULLProc, // 122 SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT
&Unit::HandleNULLProc, // 123 SPELL_AURA_MOD_TARGET_RESISTANCE
&Unit::HandleNULLProc, // 124 SPELL_AURA_MOD_RANGED_ATTACK_POWER
&Unit::HandleNULLProc, // 125 SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN
&Unit::HandleNULLProc, // 126 SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT
&Unit::HandleNULLProc, // 127 SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS
&Unit::HandleNULLProc, // 128 SPELL_AURA_MOD_POSSESS_PET
&Unit::HandleNULLProc, // 129 SPELL_AURA_MOD_SPEED_ALWAYS
&Unit::HandleNULLProc, // 130 SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS
&Unit::HandleNULLProc, // 131 SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS
&Unit::HandleNULLProc, // 132 SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT
&Unit::HandleNULLProc, // 133 SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT
&Unit::HandleNULLProc, // 134 SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
&Unit::HandleNULLProc, // 135 SPELL_AURA_MOD_HEALING_DONE
&Unit::HandleNULLProc, // 136 SPELL_AURA_MOD_HEALING_DONE_PERCENT
&Unit::HandleNULLProc, // 137 SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE
&Unit::HandleHasteAuraProc, // 138 SPELL_AURA_MOD_MELEE_HASTE
&Unit::HandleNULLProc, // 139 SPELL_AURA_FORCE_REACTION
&Unit::HandleNULLProc, // 140 SPELL_AURA_MOD_RANGED_HASTE
&Unit::HandleNULLProc, // 141 SPELL_AURA_MOD_RANGED_AMMO_HASTE
&Unit::HandleNULLProc, // 142 SPELL_AURA_MOD_BASE_RESISTANCE_PCT
&Unit::HandleNULLProc, // 143 SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE
&Unit::HandleNULLProc, // 144 SPELL_AURA_SAFE_FALL
&Unit::HandleNULLProc, // 145 SPELL_AURA_CHARISMA obsolete?
&Unit::HandleNULLProc, // 146 SPELL_AURA_PERSUADED obsolete?
&Unit::HandleNULLProc, // 147 SPELL_AURA_MECHANIC_IMMUNITY_MASK
&Unit::HandleNULLProc, // 148 SPELL_AURA_RETAIN_COMBO_POINTS
&Unit::HandleCantTrigger, // 149 SPELL_AURA_RESIST_PUSHBACK
&Unit::HandleNULLProc, // 150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT
&Unit::HandleNULLProc, // 151 SPELL_AURA_TRACK_STEALTHED
&Unit::HandleNULLProc, // 152 SPELL_AURA_MOD_DETECTED_RANGE
&Unit::HandleNULLProc, // 153 SPELL_AURA_SPLIT_DAMAGE_FLAT
&Unit::HandleNULLProc, // 154 SPELL_AURA_MOD_STEALTH_LEVEL
&Unit::HandleNULLProc, // 155 SPELL_AURA_MOD_WATER_BREATHING
&Unit::HandleNULLProc, // 156 SPELL_AURA_MOD_REPUTATION_GAIN
&Unit::HandleNULLProc, // 157 SPELL_AURA_PET_DAMAGE_MULTI (single test like spell 20782, also single for 214 aura)
&Unit::HandleNULLProc, // 158 SPELL_AURA_MOD_SHIELD_BLOCKVALUE
&Unit::HandleNULLProc, // 159 SPELL_AURA_NO_PVP_CREDIT only for Honorless Target spell
&Unit::HandleNULLProc, // 160 SPELL_AURA_MOD_AOE_AVOIDANCE
&Unit::HandleNULLProc, // 161 SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT
&Unit::HandleNULLProc, // 162 SPELL_AURA_POWER_BURN_MANA
&Unit::HandleNULLProc, // 163 SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
&Unit::HandleNULLProc, // 164 useless, only one test spell
&Unit::HandleNULLProc, // 165 SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS
&Unit::HandleNULLProc, // 166 SPELL_AURA_MOD_ATTACK_POWER_PCT
&Unit::HandleNULLProc, // 167 SPELL_AURA_MOD_RANGED_ATTACK_POWER_PCT
&Unit::HandleNULLProc, // 168 SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
&Unit::HandleNULLProc, // 169 SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
&Unit::HandleNULLProc, // 170 SPELL_AURA_DETECT_AMORE only for Detect Amore spell
&Unit::HandleNULLProc, // 171 SPELL_AURA_MOD_SPEED_NOT_STACK
&Unit::HandleNULLProc, // 172 SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
&Unit::HandleNULLProc, // 173 SPELL_AURA_ALLOW_CHAMPION_SPELLS only for Proclaim Champion spell
&Unit::HandleNULLProc, // 174 SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT
&Unit::HandleNULLProc, // 175 SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
&Unit::HandleNULLProc, // 176 SPELL_AURA_SPIRIT_OF_REDEMPTION only for Spirit of Redemption spell, die at aura end
&Unit::HandleNULLProc, // 177 SPELL_AURA_AOE_CHARM
&Unit::HandleNULLProc, // 178 SPELL_AURA_MOD_DEBUFF_RESISTANCE
&Unit::HandleNULLProc, // 179 SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
&Unit::HandleNULLProc, // 180 SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS
&Unit::HandleNULLProc, // 181 SPELL_AURA_MOD_FLAT_SPELL_CRIT_DAMAGE_VERSUS unused
&Unit::HandleNULLProc, // 182 SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT
&Unit::HandleNULLProc, // 183 SPELL_AURA_MOD_CRITICAL_THREAT only used in 28746
&Unit::HandleNULLProc, // 184 SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE
&Unit::HandleNULLProc, // 185 SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE
&Unit::HandleNULLProc, // 186 SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE
&Unit::HandleNULLProc, // 187 SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE
&Unit::HandleNULLProc, // 188 SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE
&Unit::HandleNULLProc, // 189 SPELL_AURA_MOD_RATING
&Unit::HandleNULLProc, // 190 SPELL_AURA_MOD_FACTION_REPUTATION_GAIN
&Unit::HandleNULLProc, // 191 SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
};
bool Unit::IsTriggeredAtSpellProcEvent(Unit* pVictim, SpellAuraHolder* holder, SpellEntry const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, SpellProcEventEntry const*& spellProcEvent)
{
SpellEntry const* spellProto = holder->GetSpellProto();
// Get proc Event Entry
spellProcEvent = sSpellMgr.GetSpellProcEvent(spellProto->Id);
// Get EventProcFlag
uint32 EventProcFlag;
if (spellProcEvent && spellProcEvent->procFlags) // if exist get custom spellProcEvent->procFlags
{ EventProcFlag = spellProcEvent->procFlags; }
else
{ EventProcFlag = spellProto->procFlags; } // else get from spell proto
// Continue if no trigger exist
if (!EventProcFlag)
{ return false; }
// Check spellProcEvent data requirements
if (!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent, EventProcFlag, procSpell, procFlag, procExtra))
{ return false; }
// In most cases req get honor or XP from kill
if (EventProcFlag & PROC_FLAG_KILL && GetTypeId() == TYPEID_PLAYER)
{
bool allow = ((Player*)this)->isHonorOrXPTarget(pVictim);
if (!allow)
{ return false; }
}
// Aura added by spell can`t trigger from self (prevent drop charges/do triggers)
// But except periodic triggers (can triggered from self)
if (procSpell && procSpell->Id == spellProto->Id && !(EventProcFlag & PROC_FLAG_ON_TAKE_PERIODIC))
{ return false; }
// Check if current equipment allows aura to proc
if (!isVictim && GetTypeId() == TYPEID_PLAYER)
{
if (spellProto->EquippedItemClass == ITEM_CLASS_WEAPON)
{
Item* item = NULL;
if (attType == BASE_ATTACK)
{ item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); }
else if (attType == OFF_ATTACK)
{ item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); }
else
{ item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED); }
if (!CanUseEquippedWeapon(attType))
{ return false; }
if (!item || item->IsBroken() || item->GetProto()->Class != ITEM_CLASS_WEAPON || !((1 << item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
{ return false; }
}
else if (spellProto->EquippedItemClass == ITEM_CLASS_ARMOR)
{
// Check if player is wearing shield
Item* item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
if (!item || item->IsBroken() || item->GetProto()->Class != ITEM_CLASS_ARMOR || !((1 << item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
{ return false; }
}
}
// Get chance from spell
float chance = (float)spellProto->procChance;
// If in spellProcEvent exist custom chance, chance = spellProcEvent->customChance;
if (spellProcEvent && spellProcEvent->customChance)
{ chance = spellProcEvent->customChance; }
// If PPM exist calculate chance from PPM
if (!isVictim && spellProcEvent && spellProcEvent->ppmRate != 0)
{
uint32 WeaponSpeed = GetAttackTime(attType);
chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate);
}
// Apply chance modifier aura
if (Player* modOwner = GetSpellModOwner())
{
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CHANCE_OF_SUCCESS, chance);
}
if (!roll_chance_f(chance))
{
// Break stealth on sap if improved sap doesnt proc
if ((procSpell && procSpell->SpellIconID == 249 && procSpell->SpellVisual == 257) && (spellProto->SpellFamilyName == SPELLFAMILY_ROGUE && spellProto->SpellIconID == 249 && spellProto->SpellVisual == 0))
RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
return false;
}
return true;
}
SpellAuraProcResult Unit::HandleHasteAuraProc(Unit* pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
{
SpellEntry const* hasteSpell = triggeredByAura->GetSpellProto();
Item* castItem = triggeredByAura->GetCastItemGuid() && GetTypeId() == TYPEID_PLAYER
? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGuid()) : NULL;
uint32 triggered_spell_id = 0;
Unit* target = pVictim;
int32 basepoints0 = 0;
switch (hasteSpell->SpellFamilyName)
{
case SPELLFAMILY_ROGUE:
{
switch (hasteSpell->Id)
{
// Blade Flurry
case 13877:
{
target = SelectRandomUnfriendlyTarget(pVictim);
if (!target)
{ return SPELL_AURA_PROC_FAILED; }
basepoints0 = damage;
triggered_spell_id = 22482;
break;
}
}
break;
}
}
// processed charge only counting case
if (!triggered_spell_id)
{ return SPELL_AURA_PROC_OK; }
SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
if (!triggerEntry)
{
sLog.outError("Unit::HandleHasteAuraProc: Spell %u have nonexistent triggered spell %u", hasteSpell->Id, triggered_spell_id);
return SPELL_AURA_PROC_FAILED;
}
// default case
if (!target || (target != this && !target->IsAlive()))
{ return SPELL_AURA_PROC_FAILED; }
if (cooldown && GetTypeId() == TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
{ return SPELL_AURA_PROC_FAILED; }
if (basepoints0)
{ CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura); }
else
{ CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura); }
if (cooldown && GetTypeId() == TYPEID_PLAYER)
{ ((Player*)this)->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown); }
return SPELL_AURA_PROC_OK;
}
SpellAuraProcResult Unit::HandleDummyAuraProc(Unit* pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
{
SpellEntry const* dummySpell = triggeredByAura->GetSpellProto();
SpellEffectIndex effIndex = triggeredByAura->GetEffIndex();
int32 triggerAmount = triggeredByAura->GetModifier()->m_amount;
Item* castItem = triggeredByAura->GetCastItemGuid() && GetTypeId() == TYPEID_PLAYER
? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGuid()) : NULL;
uint32 triggered_spell_id = 0;
Unit* target = pVictim;
int32 basepoints[MAX_EFFECT_INDEX] = {0, 0, 0};
switch (dummySpell->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
{
switch (dummySpell->Id)
{
// [-ZERO] TODO: check all spell id ( most of them are different in 1.12 )
// Eye for an Eye
case 9799:
case 25988:
{
// prevent damage back from weapon special attacks
if (!procSpell || procSpell->DmgClass != SPELL_DAMAGE_CLASS_MAGIC)
{ return SPELL_AURA_PROC_FAILED; }
// return damage % to attacker but < 50% own total health
basepoints[0] = triggerAmount * int32(damage) / 100;
if (basepoints[0] > (int32)GetMaxHealth() / 2)
{ basepoints[0] = (int32)GetMaxHealth() / 2; }
triggered_spell_id = 25997;
break;
}
// Sweeping Strikes
case 12292:
case 18765:
{
// prevent chain of triggered spell from same triggered spell
if (procSpell && procSpell->Id == 26654)
{ return SPELL_AURA_PROC_FAILED; }
target = SelectRandomUnfriendlyTarget(pVictim);
if (!target)
{ return SPELL_AURA_PROC_FAILED; }
triggered_spell_id = 26654;
break;
}
// Retaliation
case 20230:
{
// check attack comes not from behind
if (!HasInArc(M_PI_F, pVictim))
{ return SPELL_AURA_PROC_FAILED; }
triggered_spell_id = 22858;
break;
}
// Twisted Reflection (boss spell)
case 21063:
triggered_spell_id = 21064;
break;
// Unstable Power
case 24658:
{
if (!procSpell || procSpell->Id == 24659)
{ return SPELL_AURA_PROC_FAILED; }
// Need remove one 24659 aura
RemoveAuraHolderFromStack(24659);
return SPELL_AURA_PROC_OK;
}
// Restless Strength
case 24661:
{
// Need remove one 24662 aura
RemoveAuraHolderFromStack(24662);
return SPELL_AURA_PROC_OK;
}
// Adaptive Warding (Frostfire Regalia set)
case 28764:
{
if (!procSpell)
{ return SPELL_AURA_PROC_FAILED; }
// find Mage Armor
bool found = false;
AuraList const& mRegenInterrupt = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
for (AuraList::const_iterator iter = mRegenInterrupt.begin(); iter != mRegenInterrupt.end(); ++iter)
{
if (SpellEntry const* iterSpellProto = (*iter)->GetSpellProto())
{
if (iterSpellProto->SpellFamilyName == SPELLFAMILY_MAGE && (iterSpellProto->SpellFamilyFlags & UI64LIT(0x10000000)))
{
found = true;
break;
}
}
}
if (!found)
{ return SPELL_AURA_PROC_FAILED; }
switch (GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
{
case SPELL_SCHOOL_NORMAL:
case SPELL_SCHOOL_HOLY:
return SPELL_AURA_PROC_FAILED; // ignored
case SPELL_SCHOOL_FIRE: triggered_spell_id = 28765; break;
case SPELL_SCHOOL_NATURE: triggered_spell_id = 28768; break;
case SPELL_SCHOOL_FROST: triggered_spell_id = 28766; break;
case SPELL_SCHOOL_SHADOW: triggered_spell_id = 28769; break;
case SPELL_SCHOOL_ARCANE: triggered_spell_id = 28770; break;
default:
return SPELL_AURA_PROC_FAILED;
}
target = this;
break;
}
// Obsidian Armor (Justice Bearer`s Pauldrons shoulder)
case 27539:
{
if (!procSpell)
{ return SPELL_AURA_PROC_FAILED; }
switch (GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
{
case SPELL_SCHOOL_NORMAL:
return SPELL_AURA_PROC_FAILED; // ignore
case SPELL_SCHOOL_HOLY: triggered_spell_id = 27536; break;
case SPELL_SCHOOL_FIRE: triggered_spell_id = 27533; break;
case SPELL_SCHOOL_NATURE: triggered_spell_id = 27538; break;
case SPELL_SCHOOL_FROST: triggered_spell_id = 27534; break;
case SPELL_SCHOOL_SHADOW: triggered_spell_id = 27535; break;
case SPELL_SCHOOL_ARCANE: triggered_spell_id = 27540; break;
default:
return SPELL_AURA_PROC_FAILED;
}
target = this;
break;
}
}
break;
}
case SPELLFAMILY_MAGE:
{
// Magic Absorption
if (dummySpell->SpellIconID == 459) // only this spell have SpellIconID == 459 and dummy aura
{
if (GetPowerType() != POWER_MANA)
{ return SPELL_AURA_PROC_FAILED; }
// mana reward
basepoints[0] = (triggerAmount * GetMaxPower(POWER_MANA) / 100);
target = this;
triggered_spell_id = 29442;
break;
}
// Master of Elements
if (dummySpell->SpellIconID == 1920)
{
if (!procSpell)
{ return SPELL_AURA_PROC_FAILED; }
// mana cost save
int32 cost = procSpell->manaCost + procSpell->ManaCostPercentage * GetCreateMana() / 100;
basepoints[0] = cost * triggerAmount / 100;
if (basepoints[0] <= 0)
{ return SPELL_AURA_PROC_FAILED; }
target = this;
triggered_spell_id = 29077;
break;
}
switch (dummySpell->Id)
{
// Ignite
case 11119:
case 11120:
case 12846:
case 12847:
case 12848:
{
switch (dummySpell->Id)
{
case 11119: basepoints[0] = int32(0.04f * damage); break;
case 11120: basepoints[0] = int32(0.08f * damage); break;
case 12846: basepoints[0] = int32(0.12f * damage); break;
case 12847: basepoints[0] = int32(0.16f * damage); break;
case 12848: basepoints[0] = int32(0.20f * damage); break;
default:
sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)", dummySpell->Id);
return SPELL_AURA_PROC_FAILED;
}
triggered_spell_id = 12654;
break;
}
// Combustion
case 11129:
{
// last charge and crit
if (triggeredByAura->GetHolder()->GetAuraCharges() <= 1 && (procEx & PROC_EX_CRITICAL_HIT))
{
RemoveAurasDueToSpell(28682); //-> remove Combustion auras
return SPELL_AURA_PROC_OK; // charge counting (will removed)
}
CastSpell(this, 28682, true, castItem, triggeredByAura);
return (procEx & PROC_EX_CRITICAL_HIT) ? SPELL_AURA_PROC_OK : SPELL_AURA_PROC_FAILED; // charge update only at crit hits, no hidden cooldowns
}
}
break;
}
case SPELLFAMILY_WARRIOR:
{
// Retaliation
if (dummySpell->IsFitToFamilyMask(UI64LIT(0x0000000800000000)))
{
// check attack comes not from behind
if (!HasInArc(M_PI_F, pVictim))
{ return SPELL_AURA_PROC_FAILED; }
triggered_spell_id = 22858;
break;
}
break;
}
case SPELLFAMILY_WARLOCK:
{
break;
}
case SPELLFAMILY_PRIEST:
{
switch (dummySpell->Id)
{
// Vampiric Embrace
case 15286:
{
if (!pVictim || !pVictim->IsAlive())
{ return SPELL_AURA_PROC_FAILED; }
// pVictim is caster of aura
if (triggeredByAura->GetCasterGuid() != pVictim->GetObjectGuid())
{ return SPELL_AURA_PROC_FAILED; }
// heal amount
basepoints[0] = triggerAmount * damage / 100;
pVictim->CastCustomSpell(pVictim, 15290, &basepoints[0], NULL, NULL, true, castItem, triggeredByAura);
return SPELL_AURA_PROC_OK; // no hidden cooldown
}
// Oracle Healing Bonus ("Garments of the Oracle" set)
case 26169:
{
// heal amount
basepoints[0] = int32(damage * 10 / 100);
target = this;
triggered_spell_id = 26170;
break;
}
// Greater Heal (Vestments of Faith (Priest Tier 3) - 4 pieces bonus)
case 28809:
{
triggered_spell_id = 28810;
break;
}
}
break;
}
case SPELLFAMILY_DRUID:
{
switch (dummySpell->Id)
{
// Healing Touch (Dreamwalker Raiment set)
case 28719:
{
// mana back
basepoints[0] = int32(procSpell->manaCost * 30 / 100);
target = this;
triggered_spell_id = 28742;
break;
}
// Healing Touch Refund (Idol of Longevity trinket)
case 28847:
{
target = this;
triggered_spell_id = 28848;
break;
}
}
break;
}
case SPELLFAMILY_ROGUE:
{
switch (dummySpell->Id)
{
// Clean Escape
case 23582:
// triggered spell have same masks and etc with main Vanish spell
if (!procSpell || procSpell->Effect[EFFECT_INDEX_0] == SPELL_EFFECT_NONE)
{ return SPELL_AURA_PROC_FAILED; }
triggered_spell_id = 23583;
break;
}
break;
}
case SPELLFAMILY_HUNTER:
break;
case SPELLFAMILY_PALADIN:
{
// Seal of Righteousness - melee proc dummy
if ((dummySpell->SpellFamilyFlags & UI64LIT(0x000000008000000)) && triggeredByAura->GetEffIndex() == EFFECT_INDEX_0)
{
if (GetTypeId() != TYPEID_PLAYER)
{ return SPELL_AURA_PROC_FAILED; }
uint32 spellId;
switch (triggeredByAura->GetId())
{
case 21084: spellId = 25742; break; // Rank 1
case 20287: spellId = 25740; break; // Rank 2
case 20288: spellId = 25739; break; // Rank 3
case 20289: spellId = 25738; break; // Rank 4
case 20290: spellId = 25737; break; // Rank 5
case 20291: spellId = 25736; break; // Rank 6
case 20292: spellId = 25735; break; // Rank 7
case 20293: spellId = 25713; break; // Rank 8
default:
sLog.outError("Unit::HandleDummyAuraProc: non handled possibly SoR (Id = %u)", triggeredByAura->GetId());
return SPELL_AURA_PROC_FAILED;
}
Item* item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
float speed = (item ? item->GetProto()->Delay : BASE_ATTACK_TIME) / 1000.0f;
int damagePoint;
// In the description, we can find the divider of the base points for min/max effects.
int min=triggerAmount/87;
int max=triggerAmount/25;
damagePoint = (speed<=1.5?min:(speed>=4.0?max:min+(((max-min)/2.5f)*(speed-1.5))));
damagePoint = SpellDamageBonusDone(pVictim, dummySpell, damagePoint, SPELL_DIRECT_DAMAGE);
damagePoint = pVictim->SpellDamageBonusTaken(this, dummySpell, damagePoint, SPELL_DIRECT_DAMAGE);
CastCustomSpell(pVictim, spellId, &damagePoint, NULL, NULL, true, NULL, triggeredByAura);
return SPELL_AURA_PROC_OK; // no hidden cooldown
}
switch (dummySpell->Id)
{
// Holy Power (Redemption Armor set)
case 28789:
{
if (!pVictim)
{ return SPELL_AURA_PROC_FAILED; }
// Set class defined buff
switch (pVictim->getClass())
{
case CLASS_PALADIN:
case CLASS_PRIEST:
case CLASS_SHAMAN:
case CLASS_DRUID:
triggered_spell_id = 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
break;
case CLASS_MAGE:
case CLASS_WARLOCK:
triggered_spell_id = 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
break;
case CLASS_HUNTER:
case CLASS_ROGUE:
triggered_spell_id = 28791; // Increases the friendly target's attack power by $s1 for $d.
break;
case CLASS_WARRIOR:
triggered_spell_id = 28790; // Increases the friendly target's armor
break;
default:
return SPELL_AURA_PROC_FAILED;
}
break;
}
}
break;
}
case SPELLFAMILY_SHAMAN:
{
switch (dummySpell->Id)
{
// Totemic Power (The Earthshatterer set)
case 28823:
{
if (!pVictim)
{ return SPELL_AURA_PROC_FAILED; }
// Set class defined buff
switch (pVictim->getClass())
{
case CLASS_PALADIN:
case CLASS_PRIEST:
case CLASS_SHAMAN:
case CLASS_DRUID:
triggered_spell_id = 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
break;
case CLASS_MAGE:
case CLASS_WARLOCK:
triggered_spell_id = 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
break;
case CLASS_HUNTER:
case CLASS_ROGUE:
triggered_spell_id = 28826; // Increases the friendly target's attack power by $s1 for $d.
break;
case CLASS_WARRIOR:
triggered_spell_id = 28827; // Increases the friendly target's armor
break;
default:
return SPELL_AURA_PROC_FAILED;
}
break;
}
// Lesser Healing Wave (Totem of Flowing Water Relic)
case 28849:
{
target = this;
triggered_spell_id = 28850;
break;
}
}
break;
}
default:
break;
}
if (!triggered_spell_id)
{
// Linked spells (Proc chain)
SpellLinkedSet linkedSet = sSpellMgr.GetSpellLinked(dummySpell->Id, SPELL_LINKED_TYPE_PROC);
if (linkedSet.size() > 0)
{
for (SpellLinkedSet::const_iterator itr = linkedSet.begin(); itr != linkedSet.end(); ++itr)
{
if (target == NULL)
{ target = !(procFlag & PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL) && IsPositiveSpell(*itr) ? this : pVictim; }
CastSpell(this, *itr, true, castItem, triggeredByAura);
if (cooldown && GetTypeId() == TYPEID_PLAYER)
{ ((Player*)this)->AddSpellCooldown(*itr, 0, time(NULL) + cooldown); }
}
}
}
// processed charge only counting case
if (!triggered_spell_id)
{ return SPELL_AURA_PROC_OK; }
SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
if (!triggerEntry)
{
sLog.outError("Unit::HandleDummyAuraProc: Spell %u have nonexistent triggered spell %u", dummySpell->Id, triggered_spell_id);
return SPELL_AURA_PROC_FAILED;
}
// default case
if (!target || (target != this && !target->IsAlive()))
{ return SPELL_AURA_PROC_FAILED; }
if (cooldown && GetTypeId() == TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
{ return SPELL_AURA_PROC_FAILED; }
if (basepoints[EFFECT_INDEX_0] || basepoints[EFFECT_INDEX_1] || basepoints[EFFECT_INDEX_2])
CastCustomSpell(target, triggered_spell_id,
basepoints[EFFECT_INDEX_0] ? &basepoints[EFFECT_INDEX_0] : NULL,
basepoints[EFFECT_INDEX_1] ? &basepoints[EFFECT_INDEX_1] : NULL,
basepoints[EFFECT_INDEX_2] ? &basepoints[EFFECT_INDEX_2] : NULL,
true, castItem, triggeredByAura);
else
{ CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura); }
if (cooldown && GetTypeId() == TYPEID_PLAYER)
{ ((Player*)this)->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown); }
return SPELL_AURA_PROC_OK;
}
SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit* pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const* procSpell, uint32 procFlags, uint32 procEx, uint32 cooldown)
{
// Get triggered aura spell info
SpellEntry const* auraSpellInfo = triggeredByAura->GetSpellProto();
// Basepoints of trigger aura
int32 triggerAmount = triggeredByAura->GetModifier()->m_amount;
// Set trigger spell id, target, custom basepoints
uint32 trigger_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()];
Unit* target = NULL;
int32 basepoints[MAX_EFFECT_INDEX] = {0, 0, 0};
Item* castItem = triggeredByAura->GetCastItemGuid() && GetTypeId() == TYPEID_PLAYER
? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGuid()) : NULL;
// Try handle unknown trigger spells
// Custom requirements (not listed in procEx) Warning! damage dealing after this
// Custom triggered spells
switch (auraSpellInfo->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
switch (auraSpellInfo->Id)
{
// case 5301: break; // Defensive State (DND)
// case 7137: break; // Shadow Charge (Rank 1)
// case 7377: break; // Take Immune Periodic Damage <Not Working>
// case 13358: break; // Defensive State (DND)
// case 16092: break; // Defensive State (DND)
// case 18943: break; // Double Attack
// case 19194: break; // Double Attack
// case 19817: break; // Double Attack
// case 19818: break; // Double Attack
// case 22835: break; // Drunken Rage
// trigger_spell_id = 14822; break;
case 23780: // Aegis of Preservation (Aegis of Preservation trinket)
trigger_spell_id = 23781;
break;
// case 24949: break; // Defensive State 2 (DND)
case 27522: // Mana Drain Trigger
{
// On successful melee or ranged attack gain 8 mana and if possible drain 8 mana from the target.
if (IsAlive())
{ CastSpell(this, 29471, true, castItem, triggeredByAura); }
if (pVictim && pVictim->IsAlive())
{ CastSpell(pVictim, 27526, true, castItem, triggeredByAura); }
return SPELL_AURA_PROC_OK;
}
case 31255: // Deadly Swiftness (Rank 1)
{
// whenever you deal damage to a target who is below 20% health.
if (pVictim->GetHealth() > pVictim->GetMaxHealth() / 5)
{ return SPELL_AURA_PROC_FAILED; }
target = this;
trigger_spell_id = 22588;
break;
}
break;
}
break;
case SPELLFAMILY_MAGE:
if (auraSpellInfo->Id == 26467) // Persistent Shield (Scarab Brooch trinket)
{
// This spell originally trigger 13567 - Dummy Trigger (vs dummy effect)
basepoints[0] = damage * 15 / 100;
target = pVictim;
trigger_spell_id = 26470;
}
break;
case SPELLFAMILY_WARRIOR:
// Deep Wounds (replace triggered spells to directly apply DoT), dot spell have familyflags
if (auraSpellInfo->SpellFamilyFlags == UI64LIT(0x0) && auraSpellInfo->SpellIconID == 243)
{
float weaponDamage;
// DW should benefit of attack power, damage percent mods etc.
// TODO: check if using offhand damage is correct and if it should be divided by 2
if (haveOffhandWeapon() && getAttackTimer(BASE_ATTACK) > getAttackTimer(OFF_ATTACK))
{ weaponDamage = (GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE)) / 2; }
else
{ weaponDamage = (GetFloatValue(UNIT_FIELD_MINDAMAGE) + GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2; }
switch (auraSpellInfo->Id)
{
case 12834: basepoints[0] = int32(weaponDamage * 0.2f); break;
case 12849: basepoints[0] = int32(weaponDamage * 0.4f); break;
case 12867: basepoints[0] = int32(weaponDamage * 0.6f); break;
// Impossible case
default:
sLog.outError("Unit::HandleProcTriggerSpellAuraProc: DW unknown spell rank %u", auraSpellInfo->Id);
return SPELL_AURA_PROC_FAILED;
}
// 1 tick/sec * 6 sec = 6 ticks
basepoints[0] /= 6;
trigger_spell_id = 12721;
break;
}
break;
case SPELLFAMILY_WARLOCK:
{
// Pyroclasm
if (auraSpellInfo->SpellIconID == 1137)
{
if (!pVictim || !pVictim->IsAlive() || pVictim == this || procSpell == NULL)
{ return SPELL_AURA_PROC_FAILED; }
// Calculate spell tick count for spells
uint32 tick = 1; // Default tick = 1
// Hellfire have 15 tick
if (procSpell->SpellFamilyFlags & UI64LIT(0x0000000000000040))
{ tick = 15; }
// Rain of Fire have 4 tick
else if (procSpell->SpellFamilyFlags & UI64LIT(0x0000000000000020))
{ tick = 4; }
else
{ return SPELL_AURA_PROC_FAILED; }
// Calculate chance = baseChance / tick
float chance = 0;
switch (auraSpellInfo->Id)
{
case 18096: chance = 13.0f / tick; break;
case 18073: chance = 26.0f / tick; break;
}
// Roll chance
if (!roll_chance_f(chance))
{ return SPELL_AURA_PROC_FAILED; }
trigger_spell_id = 18093;
}
// Cheat Death
else if (auraSpellInfo->Id == 28845)
{
// When your health drops below 20% ....
int32 health20 = int32(GetMaxHealth()) / 5;
if (int32(GetHealth()) - int32(damage) >= health20 || int32(GetHealth()) < health20)
{ return SPELL_AURA_PROC_FAILED; }
}
break;
}
case SPELLFAMILY_PRIEST:
{
// Shadowguard
if (auraSpellInfo->SpellIconID == 19)
{
switch (auraSpellInfo->Id)
{
case 18137: trigger_spell_id = 28377; break; // Rank 1
case 19308: trigger_spell_id = 28378; break; // Rank 2
case 19309: trigger_spell_id = 28379; break; // Rank 3
case 19310: trigger_spell_id = 28380; break; // Rank 4
case 19311: trigger_spell_id = 28381; break; // Rank 5
case 19312: trigger_spell_id = 28382; break; // Rank 6
default:
sLog.outError("Unit::HandleProcTriggerSpellAuraProc: Spell %u not handled in SG", auraSpellInfo->Id);
return SPELL_AURA_PROC_FAILED;
}
}
// Blessed Recovery
else if (auraSpellInfo->SpellIconID == 1875)
{
switch (auraSpellInfo->Id)
{
case 27811: trigger_spell_id = 27813; break;
case 27815: trigger_spell_id = 27817; break;
case 27816: trigger_spell_id = 27818; break;
default:
sLog.outError("Unit::HandleProcTriggerSpellAuraProc: Spell %u not handled in BR", auraSpellInfo->Id);
return SPELL_AURA_PROC_FAILED;
}
basepoints[0] = damage * triggerAmount / 100 / 3;
target = this;
}
break;
}
case SPELLFAMILY_DRUID:
break;
case SPELLFAMILY_HUNTER:
break;
case SPELLFAMILY_PALADIN:
{
// Judgement of Light and Judgement of Wisdom
if (auraSpellInfo->SpellFamilyFlags & UI64LIT(0x0000000000080000))
{
switch (auraSpellInfo->Id)
{
// Judgement of Light
case 20185: trigger_spell_id = 20267; break; // Rank 1
case 20344: trigger_spell_id = 20341; break; // Rank 2
case 20345: trigger_spell_id = 20342; break; // Rank 3
case 20346: trigger_spell_id = 20343; break; // Rank 4
// Judgement of Wisdom
case 20186: trigger_spell_id = 20268; break; // Rank 1
case 20354: trigger_spell_id = 20352; break; // Rank 2
case 20355: trigger_spell_id = 20353; break; // Rank 3
default:
sLog.outError("Unit::HandleProcTriggerSpellAuraProc: Spell %u miss posibly Judgement of Light/Wisdom", auraSpellInfo->Id);
return SPELL_AURA_PROC_FAILED;
}
pVictim->CastSpell(pVictim, trigger_spell_id, true, castItem, triggeredByAura);
return SPELL_AURA_PROC_OK; // no hidden cooldown
}
// Illumination
else if (auraSpellInfo->SpellIconID == 241)
{
if (!procSpell)
{ return SPELL_AURA_PROC_FAILED; }
// procspell is triggered spell but we need mana cost of original casted spell
uint32 originalSpellId = procSpell->Id;
// Holy Shock
if (procSpell->SpellFamilyFlags & UI64LIT(0x0000000000200000))
{
switch (procSpell->Id)
{
case 25914: originalSpellId = 20473; break;
case 25913: originalSpellId = 20929; break;
case 25903: originalSpellId = 20930; break;
default:
sLog.outError("Unit::HandleProcTriggerSpellAuraProc: Spell %u not handled in HShock", procSpell->Id);
return SPELL_AURA_PROC_FAILED;
}
}
SpellEntry const* originalSpell = sSpellStore.LookupEntry(originalSpellId);
if (!originalSpell)
{
sLog.outError("Unit::HandleProcTriggerSpellAuraProc: Spell %u unknown but selected as original in Illu", originalSpellId);
return SPELL_AURA_PROC_FAILED;
}
basepoints[0] = originalSpell->manaCost;
trigger_spell_id = 20272;
target = this;
}
break;
}
case SPELLFAMILY_SHAMAN:
{
// Lightning Shield (overwrite non existing triggered spell call in spell.dbc
if (auraSpellInfo->IsFitToFamilyMask(UI64LIT(0x0000000000000400)) && auraSpellInfo->SpellVisual == 37)
{
switch (auraSpellInfo->Id)
{
case 324: // Rank 1
trigger_spell_id = 26364; break;
case 325: // Rank 2
trigger_spell_id = 26365; break;
case 905: // Rank 3
trigger_spell_id = 26366; break;
case 945: // Rank 4
trigger_spell_id = 26367; break;
case 8134: // Rank 5
trigger_spell_id = 26369; break;
case 10431: // Rank 6
trigger_spell_id = 26370; break;
case 10432: // Rank 7
trigger_spell_id = 26363; break;
default:
sLog.outError("Unit::HandleProcTriggerSpellAuraProc: Spell %u not handled in LShield", auraSpellInfo->Id);
return SPELL_AURA_PROC_FAILED;
}
}
// Lightning Shield (The Ten Storms set)
else if (auraSpellInfo->Id == 23551)
{
trigger_spell_id = 23552;
target = pVictim;
}
// Damage from Lightning Shield (The Ten Storms set)
else if (auraSpellInfo->Id == 23552)
{ trigger_spell_id = 27635; }
// Mana Surge (The Earthfury set)
else if (auraSpellInfo->Id == 23572)
{
if (!procSpell)
{ return SPELL_AURA_PROC_FAILED; }
basepoints[0] = procSpell->manaCost * 35 / 100;
trigger_spell_id = 23571;
target = this;
}
break;
}
default:
break;
}
// All ok. Check current trigger spell
SpellEntry const* triggerEntry = sSpellStore.LookupEntry(trigger_spell_id);
if (!triggerEntry)
{
// Not cast unknown spell
// sLog.outError("Unit::HandleProcTriggerSpellAuraProc: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo->Id,triggeredByAura->GetEffIndex());
return SPELL_AURA_PROC_FAILED;
}
// not allow proc extra attack spell at extra attack, except the paladin Reckoning with hacky limitation in the spelleffect
if (m_extraAttacks && triggerEntry->HasSpellEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS) && triggerEntry->Id != 20178)
{ return SPELL_AURA_PROC_FAILED; }
// Custom basepoints/target for exist spell
// dummy basepoints or other customs
switch (trigger_spell_id)
{
// Cast positive spell on enemy target
case 7099: // Curse of Mending
case 39647: // Curse of Mending
case 29494: // Temptation
case 20233: // Improved Lay on Hands (cast on target)
{
target = pVictim;
break;
}
// Combo points add triggers (need add combopoint only for main target, and after possible combopoints reset)
case 15250: // Rogue Setup
{
if (!pVictim || pVictim != getVictim()) // applied only for main target
{ return SPELL_AURA_PROC_FAILED; }
break; // continue normal case
}
// Finishing moves that add combo points
case 14189: // Seal Fate (Netherblade set)
case 14157: // Ruthlessness
{
// Need add combopoint AFTER finishing move (or they get dropped in finish phase)
if (Spell* spell = GetCurrentSpell(CURRENT_GENERIC_SPELL))
{
spell->AddTriggeredSpell(trigger_spell_id);
return SPELL_AURA_PROC_OK;
}
return SPELL_AURA_PROC_FAILED;
}
// Shamanistic Rage triggered spell
case 30824:
{
basepoints[0] = int32(GetTotalAttackPowerValue(BASE_ATTACK) * triggerAmount / 100);
break;
}
}
if (!trigger_spell_id)
{
// Linked spells (Proc chain)
SpellLinkedSet linkedSet = sSpellMgr.GetSpellLinked(auraSpellInfo->Id, SPELL_LINKED_TYPE_PROC);
if (linkedSet.size() > 0)
{
for (SpellLinkedSet::const_iterator itr = linkedSet.begin(); itr != linkedSet.end(); ++itr)
{
if (target == NULL)
{ target = !(procFlags & PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL) && IsPositiveSpell(*itr) ? this : pVictim; }
CastSpell(target, *itr, true, castItem, triggeredByAura);
if (cooldown && GetTypeId() == TYPEID_PLAYER)
{ ((Player*)this)->AddSpellCooldown(*itr, 0, time(NULL) + cooldown); }
}
}
}
if (cooldown && GetTypeId() == TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(trigger_spell_id))
{ return SPELL_AURA_PROC_FAILED; }
// try detect target manually if not set
if (target == NULL)
{ target = !(procFlags & PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL) && IsPositiveSpell(trigger_spell_id) ? this : pVictim; }
// default case
if (!target || (target != this && !target->IsAlive()))
{ return SPELL_AURA_PROC_FAILED; }
if (basepoints[EFFECT_INDEX_0] || basepoints[EFFECT_INDEX_1] || basepoints[EFFECT_INDEX_2])
CastCustomSpell(target, trigger_spell_id,
basepoints[EFFECT_INDEX_0] ? &basepoints[EFFECT_INDEX_0] : NULL,
basepoints[EFFECT_INDEX_1] ? &basepoints[EFFECT_INDEX_1] : NULL,
basepoints[EFFECT_INDEX_2] ? &basepoints[EFFECT_INDEX_2] : NULL,
true, castItem, triggeredByAura);
else
{ CastSpell(target, trigger_spell_id, true, castItem, triggeredByAura); }
if (cooldown && GetTypeId() == TYPEID_PLAYER)
{ ((Player*)this)->AddSpellCooldown(trigger_spell_id, 0, time(NULL) + cooldown); }
return SPELL_AURA_PROC_OK;
}
SpellAuraProcResult Unit::HandleProcTriggerDamageAuraProc(Unit* pVictim, uint32 /*damage*/, Aura* triggeredByAura, SpellEntry const* /*procSpell*/, uint32 /*procFlags*/, uint32 /*procEx*/, uint32 /*cooldown*/)
{
SpellEntry const* spellInfo = triggeredByAura->GetSpellProto();
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "ProcDamageAndSpell: doing %u damage from spell id %u (triggered by auratype %u of spell %u)",
triggeredByAura->GetModifier()->m_amount, spellInfo->Id, triggeredByAura->GetModifier()->m_auraname, triggeredByAura->GetId());
SpellNonMeleeDamage damageInfo(this, pVictim, spellInfo->Id, SpellSchools(spellInfo->School));
CalculateSpellDamage(&damageInfo, triggeredByAura->GetModifier()->m_amount, spellInfo);
damageInfo.target->CalculateAbsorbResistBlock(this, &damageInfo, spellInfo);
DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
SendSpellNonMeleeDamageLog(&damageInfo);
DealSpellDamage(&damageInfo, true);
return SPELL_AURA_PROC_OK;
}
SpellAuraProcResult Unit::HandleOverrideClassScriptAuraProc(Unit* pVictim, uint32 /*damage*/, Aura* triggeredByAura, SpellEntry const* procSpell, uint32 /*procFlag*/, uint32 /*procEx*/ , uint32 cooldown)
{
int32 scriptId = triggeredByAura->GetModifier()->m_miscvalue;
if (!pVictim || !pVictim->IsAlive())
{ return SPELL_AURA_PROC_FAILED; }
Item* castItem = triggeredByAura->GetCastItemGuid() && GetTypeId() == TYPEID_PLAYER
? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGuid()) : NULL;
// Basepoints of trigger aura
int32 triggerAmount = triggeredByAura->GetModifier()->m_amount;
uint32 triggered_spell_id = 0;
switch (scriptId)
{
case 836: // Improved Blizzard (Rank 1)
{
if (!procSpell || procSpell->SpellVisual != 259)
{ return SPELL_AURA_PROC_FAILED; }
triggered_spell_id = 12484;
break;
}
case 988: // Improved Blizzard (Rank 2)
{
if (!procSpell || procSpell->SpellVisual != 259)
{ return SPELL_AURA_PROC_FAILED; }
triggered_spell_id = 12485;
break;
}
case 989: // Improved Blizzard (Rank 3)
{
if (!procSpell || procSpell->SpellVisual != 259)
{ return SPELL_AURA_PROC_FAILED; }
triggered_spell_id = 12486;
break;
}
case 3656: // Corrupted Healing / Nefarian Priest Classcall
{
triggered_spell_id = 23402;
break;
}
case 4086: // Improved Mend Pet (Rank 1)
case 4087: // Improved Mend Pet (Rank 2)
{
if (!roll_chance_i(triggerAmount))
{ return SPELL_AURA_PROC_FAILED; }
triggered_spell_id = 24406;
break;
}
case 4309:
{
triggered_spell_id = 17941; // Shadow Trance (Warlock Nightfall)
break;
}
case 4533: // Dreamwalker Raiment 2 pieces bonus
{
// Chance 50%
if (!roll_chance_i(50))
{ return SPELL_AURA_PROC_FAILED; }
switch (pVictim->GetPowerType())
{
case POWER_MANA: triggered_spell_id = 28722; break;
case POWER_RAGE: triggered_spell_id = 28723; break;
case POWER_ENERGY: triggered_spell_id = 28724; break;
default:
return SPELL_AURA_PROC_FAILED;
}
break;
}
case 4537: // Dreamwalker Raiment 6 pieces bonus
triggered_spell_id = 28750; // Blessing of the Claw
break;
}
// not processed
if (!triggered_spell_id)
{ return SPELL_AURA_PROC_OK; }
// standard non-dummy case
SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
if (!triggerEntry)
{
sLog.outError("Unit::HandleOverrideClassScriptAuraProc: Spell %u triggering for class script id %u", triggered_spell_id, scriptId);
return SPELL_AURA_PROC_FAILED;
}
if (cooldown && GetTypeId() == TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
{ return SPELL_AURA_PROC_FAILED; }
CastSpell(pVictim, triggered_spell_id, true, castItem, triggeredByAura);
if (cooldown && GetTypeId() == TYPEID_PLAYER)
{ ((Player*)this)->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown); }
return SPELL_AURA_PROC_OK;
}
SpellAuraProcResult Unit::HandleModCastingSpeedNotStackAuraProc(Unit* /*pVictim*/, uint32 /*damage*/, Aura* /*triggeredByAura*/, SpellEntry const* procSpell, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 /*cooldown*/)
{
// Skip melee hits or instant cast spells
return !(procSpell == NULL || GetSpellCastTime(procSpell) == 0) ? SPELL_AURA_PROC_OK : SPELL_AURA_PROC_FAILED;
}
SpellAuraProcResult Unit::HandleReflectSpellsSchoolAuraProc(Unit* /*pVictim*/, uint32 /*damage*/, Aura* triggeredByAura, SpellEntry const* procSpell, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 /*cooldown*/)
{
// Skip Melee hits and spells ws wrong school
return !(procSpell == NULL || (triggeredByAura->GetModifier()->m_miscvalue & GetSchoolMask(procSpell->School)) == 0) ? SPELL_AURA_PROC_OK : SPELL_AURA_PROC_FAILED;
}
SpellAuraProcResult Unit::HandleModPowerCostSchoolAuraProc(Unit* /*pVictim*/, uint32 /*damage*/, Aura* triggeredByAura, SpellEntry const* procSpell, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 /*cooldown*/)
{
// Skip melee hits and spells ws wrong school or zero cost
return !(procSpell == NULL ||
(procSpell->manaCost == 0 && procSpell->ManaCostPercentage == 0) || // Cost check
(triggeredByAura->GetModifier()->m_miscvalue & GetSchoolMask(procSpell->School)) == 0) ? SPELL_AURA_PROC_OK : SPELL_AURA_PROC_FAILED; // School check
}
SpellAuraProcResult Unit::HandleMechanicImmuneResistanceAuraProc(Unit* /*pVictim*/, uint32 /*damage*/, Aura* triggeredByAura, SpellEntry const* procSpell, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 /*cooldown*/)
{
// Compare mechanic
return !(procSpell == NULL || procSpell->Mechanic != triggeredByAura->GetModifier()->m_miscvalue)
? SPELL_AURA_PROC_OK : SPELL_AURA_PROC_FAILED;
}
SpellAuraProcResult Unit::HandleModResistanceAuraProc(Unit* /*pVictim*/, uint32 damage, Aura* triggeredByAura, SpellEntry const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 /*cooldown*/)
{
SpellEntry const* spellInfo = triggeredByAura->GetSpellProto();
// Inner Fire
if (spellInfo->IsFitToFamily(SPELLFAMILY_PRIEST, UI64LIT(0x0000000000002)))
{
// only at real damage
if (!damage)
{ return SPELL_AURA_PROC_FAILED; }
}
return SPELL_AURA_PROC_OK;
}
SpellAuraProcResult Unit::HandleRemoveByDamageChanceProc(Unit* pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
{
// The chance to dispel an aura depends on the damage taken with respect to the casters level.
uint32 max_dmg = getLevel() > 8 ? 25 * getLevel() - 150 : 50;
float chance = float(damage) / max_dmg * 100.0f;
if (roll_chance_f(chance))
{
triggeredByAura->SetInUse(true);
RemoveAurasByCasterSpell(triggeredByAura->GetId(), triggeredByAura->GetCasterGuid());
triggeredByAura->SetInUse(false);
return SPELL_AURA_PROC_OK;
}
return SPELL_AURA_PROC_FAILED;
}
SpellAuraProcResult Unit::HandleInvisibilityAuraProc(Unit* pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
{
if (triggeredByAura->GetSpellProto()->HasAttribute(SPELL_ATTR_PASSIVE) || triggeredByAura->GetSpellProto()->HasAttribute(SPELL_ATTR_EX_NEGATIVE))
return SPELL_AURA_PROC_FAILED;
RemoveAurasDueToSpell(triggeredByAura->GetId());
return SPELL_AURA_PROC_OK;
}