/** * 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 * * 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 // 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; }