From 37c79360b4d7353d94bb4b67e4d0e23ef0e419fa Mon Sep 17 00:00:00 2001 From: Xanadu Date: Tue, 20 Jul 2010 05:21:15 +0200 Subject: Moved SpellEffects.cpp where it belongs. --HG-- branch : trunk rename : src/server/game/Spells/Auras/SpellEffects.cpp => src/server/game/Spells/SpellEffects.cpp --- src/server/game/CMakeLists.txt | 2 +- src/server/game/Spells/Auras/SpellEffects.cpp | 8167 ------------------------- src/server/game/Spells/SpellEffects.cpp | 8167 +++++++++++++++++++++++++ 3 files changed, 8168 insertions(+), 8168 deletions(-) delete mode 100644 src/server/game/Spells/Auras/SpellEffects.cpp create mode 100644 src/server/game/Spells/SpellEffects.cpp (limited to 'src') diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index d1a9fac4f16..3cb646facbe 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -168,7 +168,7 @@ set(game_STAT_SRCS Skills/SkillExtraItems.cpp Spells/Auras/SpellAuras.cpp Spells/Auras/SpellAuraEffects.cpp - Spells/Auras/SpellEffects.cpp + Spells/SpellEffects.cpp Spells/Spell.cpp Spells/SpellMgr.cpp Tools/PlayerDump.cpp diff --git a/src/server/game/Spells/Auras/SpellEffects.cpp b/src/server/game/Spells/Auras/SpellEffects.cpp deleted file mode 100644 index 6a9f8ed7e10..00000000000 --- a/src/server/game/Spells/Auras/SpellEffects.cpp +++ /dev/null @@ -1,8167 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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 - */ - -#include "Common.h" -#include "DatabaseEnv.h" -#include "WorldPacket.h" -#include "Opcodes.h" -#include "Log.h" -#include "UpdateMask.h" -#include "World.h" -#include "ObjectMgr.h" -#include "SpellMgr.h" -#include "Player.h" -#include "SkillExtraItems.h" -#include "Unit.h" -#include "Spell.h" -#include "DynamicObject.h" -#include "SpellAuras.h" -#include "SpellAuraEffects.h" -#include "Group.h" -#include "UpdateData.h" -#include "MapManager.h" -#include "ObjectAccessor.h" -#include "SharedDefines.h" -#include "Pet.h" -#include "GameObject.h" -#include "GossipDef.h" -#include "Creature.h" -#include "Totem.h" -#include "CreatureAI.h" -#include "BattleGroundMgr.h" -#include "BattleGround.h" -#include "BattleGroundEY.h" -#include "BattleGroundWS.h" -#include "OutdoorPvPMgr.h" -#include "Language.h" -#include "SocialMgr.h" -#include "Util.h" -#include "VMapFactory.h" -#include "TemporarySummon.h" -#include "CellImpl.h" -#include "GridNotifiers.h" -#include "GridNotifiersImpl.h" -#include "SkillDiscovery.h" -#include "Formulas.h" -#include "Vehicle.h" -#include "ScriptMgr.h" - -pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= -{ - &Spell::EffectNULL, // 0 - &Spell::EffectInstaKill, // 1 SPELL_EFFECT_INSTAKILL - &Spell::EffectSchoolDMG, // 2 SPELL_EFFECT_SCHOOL_DAMAGE - &Spell::EffectDummy, // 3 SPELL_EFFECT_DUMMY - &Spell::EffectUnused, // 4 SPELL_EFFECT_PORTAL_TELEPORT unused - &Spell::EffectTeleportUnits, // 5 SPELL_EFFECT_TELEPORT_UNITS - &Spell::EffectApplyAura, // 6 SPELL_EFFECT_APPLY_AURA - &Spell::EffectEnvirinmentalDMG, // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE - &Spell::EffectPowerDrain, // 8 SPELL_EFFECT_POWER_DRAIN - &Spell::EffectHealthLeech, // 9 SPELL_EFFECT_HEALTH_LEECH - &Spell::EffectHeal, // 10 SPELL_EFFECT_HEAL - &Spell::EffectBind, // 11 SPELL_EFFECT_BIND - &Spell::EffectNULL, // 12 SPELL_EFFECT_PORTAL - &Spell::EffectUnused, // 13 SPELL_EFFECT_RITUAL_BASE unused - &Spell::EffectUnused, // 14 SPELL_EFFECT_RITUAL_SPECIALIZE unused - &Spell::EffectUnused, // 15 SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL unused - &Spell::EffectQuestComplete, // 16 SPELL_EFFECT_QUEST_COMPLETE - &Spell::EffectWeaponDmg, // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL - &Spell::EffectResurrect, // 18 SPELL_EFFECT_RESURRECT - &Spell::EffectAddExtraAttacks, // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS - &Spell::EffectUnused, // 20 SPELL_EFFECT_DODGE one spell: Dodge - &Spell::EffectUnused, // 21 SPELL_EFFECT_EVADE one spell: Evade (DND) - &Spell::EffectParry, // 22 SPELL_EFFECT_PARRY - &Spell::EffectBlock, // 23 SPELL_EFFECT_BLOCK one spell: Block - &Spell::EffectCreateItem, // 24 SPELL_EFFECT_CREATE_ITEM - &Spell::EffectUnused, // 25 SPELL_EFFECT_WEAPON - &Spell::EffectUnused, // 26 SPELL_EFFECT_DEFENSE one spell: Defense - &Spell::EffectPersistentAA, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA - &Spell::EffectSummonType, // 28 SPELL_EFFECT_SUMMON - &Spell::EffectLeapForward, // 29 SPELL_EFFECT_LEAP - &Spell::EffectEnergize, // 30 SPELL_EFFECT_ENERGIZE - &Spell::EffectWeaponDmg, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE - &Spell::EffectTriggerMissileSpell, // 32 SPELL_EFFECT_TRIGGER_MISSILE - &Spell::EffectOpenLock, // 33 SPELL_EFFECT_OPEN_LOCK - &Spell::EffectSummonChangeItem, // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM - &Spell::EffectApplyAreaAura, // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY - &Spell::EffectLearnSpell, // 36 SPELL_EFFECT_LEARN_SPELL - &Spell::EffectUnused, // 37 SPELL_EFFECT_SPELL_DEFENSE one spell: SPELLDEFENSE (DND) - &Spell::EffectDispel, // 38 SPELL_EFFECT_DISPEL - &Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE - &Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD - &Spell::EffectJump, // 41 SPELL_EFFECT_JUMP - &Spell::EffectJumpDest, // 42 SPELL_EFFECT_JUMP_DEST - &Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER - &Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP - &Spell::EffectAddHonor, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related - &Spell::EffectUnused, // 46 SPELL_EFFECT_SPAWN clientside, unit appears as if it was just spawned - &Spell::EffectTradeSkill, // 47 SPELL_EFFECT_TRADE_SKILL - &Spell::EffectUnused, // 48 SPELL_EFFECT_STEALTH one spell: Base Stealth - &Spell::EffectUnused, // 49 SPELL_EFFECT_DETECT one spell: Detect - &Spell::EffectTransmitted, // 50 SPELL_EFFECT_TRANS_DOOR - &Spell::EffectUnused, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT unused - &Spell::EffectUnused, // 52 SPELL_EFFECT_GUARANTEE_HIT one spell: zzOLDCritical Shot - &Spell::EffectEnchantItemPerm, // 53 SPELL_EFFECT_ENCHANT_ITEM - &Spell::EffectEnchantItemTmp, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY - &Spell::EffectTameCreature, // 55 SPELL_EFFECT_TAMECREATURE - &Spell::EffectSummonPet, // 56 SPELL_EFFECT_SUMMON_PET - &Spell::EffectLearnPetSpell, // 57 SPELL_EFFECT_LEARN_PET_SPELL - &Spell::EffectWeaponDmg, // 58 SPELL_EFFECT_WEAPON_DAMAGE - &Spell::EffectCreateRandomItem, // 59 SPELL_EFFECT_CREATE_RANDOM_ITEM create item base at spell specific loot - &Spell::EffectProficiency, // 60 SPELL_EFFECT_PROFICIENCY - &Spell::EffectSendEvent, // 61 SPELL_EFFECT_SEND_EVENT - &Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN - &Spell::EffectThreat, // 63 SPELL_EFFECT_THREAT - &Spell::EffectTriggerSpell, // 64 SPELL_EFFECT_TRIGGER_SPELL - &Spell::EffectApplyAreaAura, // 65 SPELL_EFFECT_APPLY_AREA_AURA_RAID - &Spell::EffectRechargeManaGem, // 66 SPELL_EFFECT_CREATE_MANA_GEM (possibly recharge it, misc - is item ID) - &Spell::EffectHealMaxHealth, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH - &Spell::EffectInterruptCast, // 68 SPELL_EFFECT_INTERRUPT_CAST - &Spell::EffectDistract, // 69 SPELL_EFFECT_DISTRACT - &Spell::EffectPull, // 70 SPELL_EFFECT_PULL one spell: Distract Move - &Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET - &Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT - &Spell::EffectUnused, // 73 SPELL_EFFECT_UNTRAIN_TALENTS - &Spell::EffectApplyGlyph, // 74 SPELL_EFFECT_APPLY_GLYPH - &Spell::EffectHealMechanical, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit - &Spell::EffectSummonObjectWild, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD - &Spell::EffectScriptEffect, // 77 SPELL_EFFECT_SCRIPT_EFFECT - &Spell::EffectUnused, // 78 SPELL_EFFECT_ATTACK - &Spell::EffectSanctuary, // 79 SPELL_EFFECT_SANCTUARY - &Spell::EffectAddComboPoints, // 80 SPELL_EFFECT_ADD_COMBO_POINTS - &Spell::EffectUnused, // 81 SPELL_EFFECT_CREATE_HOUSE one spell: Create House (TEST) - &Spell::EffectNULL, // 82 SPELL_EFFECT_BIND_SIGHT - &Spell::EffectDuel, // 83 SPELL_EFFECT_DUEL - &Spell::EffectStuck, // 84 SPELL_EFFECT_STUCK - &Spell::EffectSummonPlayer, // 85 SPELL_EFFECT_SUMMON_PLAYER - &Spell::EffectActivateObject, // 86 SPELL_EFFECT_ACTIVATE_OBJECT - &Spell::EffectWMODamage, // 87 SPELL_EFFECT_WMO_DAMAGE - &Spell::EffectWMORepair, // 88 SPELL_EFFECT_WMO_REPAIR - &Spell::EffectUnused, // 89 SPELL_EFFECT_WMO_CHANGE // 0 intact // 1 damaged // 2 destroyed // 3 rebuilding - &Spell::EffectKillCreditPersonal, // 90 SPELL_EFFECT_KILL_CREDIT Kill credit but only for single person - &Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash - &Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM - &Spell::EffectForceDeselect, // 93 SPELL_EFFECT_FORCE_DESELECT - &Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT - &Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING - &Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE - &Spell::EffectCastButtons, // 97 SPELL_EFFECT_CAST_BUTTON (totem bar since 3.2.2a) - &Spell::EffectKnockBack, // 98 SPELL_EFFECT_KNOCK_BACK - &Spell::EffectDisEnchant, // 99 SPELL_EFFECT_DISENCHANT - &Spell::EffectInebriate, //100 SPELL_EFFECT_INEBRIATE - &Spell::EffectFeedPet, //101 SPELL_EFFECT_FEED_PET - &Spell::EffectDismissPet, //102 SPELL_EFFECT_DISMISS_PET - &Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION - &Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1 - &Spell::EffectSummonObject, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2 - &Spell::EffectSummonObject, //106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3 - &Spell::EffectSummonObject, //107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4 - &Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC - &Spell::EffectSummonDeadPet, //109 SPELL_EFFECT_SUMMON_DEAD_PET - &Spell::EffectDestroyAllTotems, //110 SPELL_EFFECT_DESTROY_ALL_TOTEMS - &Spell::EffectDurabilityDamage, //111 SPELL_EFFECT_DURABILITY_DAMAGE - &Spell::EffectUnused, //112 SPELL_EFFECT_112 - &Spell::EffectResurrectNew, //113 SPELL_EFFECT_RESURRECT_NEW - &Spell::EffectTaunt, //114 SPELL_EFFECT_ATTACK_ME - &Spell::EffectDurabilityDamagePCT, //115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT - &Spell::EffectSkinPlayerCorpse, //116 SPELL_EFFECT_SKIN_PLAYER_CORPSE one spell: Remove Insignia, bg usage, required special corpse flags... - &Spell::EffectSpiritHeal, //117 SPELL_EFFECT_SPIRIT_HEAL one spell: Spirit Heal - &Spell::EffectSkill, //118 SPELL_EFFECT_SKILL professions and more - &Spell::EffectApplyAreaAura, //119 SPELL_EFFECT_APPLY_AREA_AURA_PET - &Spell::EffectUnused, //120 SPELL_EFFECT_TELEPORT_GRAVEYARD one spell: Graveyard Teleport Test - &Spell::EffectWeaponDmg, //121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG - &Spell::EffectUnused, //122 SPELL_EFFECT_122 unused - &Spell::EffectSendTaxi, //123 SPELL_EFFECT_SEND_TAXI taxi/flight related (misc value is taxi path id) - &Spell::EffectPlayerPull, //124 SPELL_EFFECT_PLAYER_PULL opposite of knockback effect (pulls player twoard caster) - &Spell::EffectModifyThreatPercent, //125 SPELL_EFFECT_MODIFY_THREAT_PERCENT - &Spell::EffectStealBeneficialBuff, //126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF spell steal effect? - &Spell::EffectProspecting, //127 SPELL_EFFECT_PROSPECTING Prospecting spell - &Spell::EffectApplyAreaAura, //128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND - &Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY - &Spell::EffectRedirectThreat, //130 SPELL_EFFECT_REDIRECT_THREAT - &Spell::EffectPlayerNotification, //131 SPELL_EFFECT_PLAYER_NOTIFICATION - &Spell::EffectPlayMusic, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value (SoundEntries.dbc) - &Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization - &Spell::EffectKillCredit, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry - &Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET - &Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT - &Spell::EffectEnergizePct, //137 SPELL_EFFECT_ENERGIZE_PCT - &Spell::EffectLeapBack, //138 SPELL_EFFECT_LEAP_BACK Leap back - &Spell::EffectQuestClear, //139 SPELL_EFFECT_CLEAR_QUEST Reset quest status (miscValue - quest ID) - &Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST - &Spell::EffectForceCastWithValue, //141 SPELL_EFFECT_FORCE_CAST_WITH_VALUE - &Spell::EffectTriggerSpellWithValue, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE - &Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER - &Spell::EffectKnockBack, //144 SPELL_EFFECT_KNOCK_BACK_DEST - &Spell::EffectPlayerPull, //145 SPELL_EFFECT_145 Black Hole Effect - &Spell::EffectActivateRune, //146 SPELL_EFFECT_ACTIVATE_RUNE - &Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail - &Spell::EffectUnused, //148 SPELL_EFFECT_148 unused - &Spell::EffectChargeDest, //149 SPELL_EFFECT_CHARGE_DEST - &Spell::EffectUnused, //150 SPELL_EFFECT_150 unused - &Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2 - &Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend - &Spell::EffectNULL, //153 SPELL_EFFECT_CREATE_PET misc value is creature entry - &Spell::EffectNULL, //154 unused - &Spell::EffectTitanGrip, //155 SPELL_EFFECT_TITAN_GRIP Allows you to equip two-handed axes, maces and swords in one hand, but you attack $49152s1% slower than normal. - &Spell::EffectEnchantItemPrismatic, //156 SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC - &Spell::EffectCreateItem2, //157 SPELL_EFFECT_CREATE_ITEM_2 create item or create item template and replace by some randon spell loot item - &Spell::EffectMilling, //158 SPELL_EFFECT_MILLING milling - &Spell::EffectRenamePet, //159 SPELL_EFFECT_ALLOW_RENAME_PET allow rename pet once again - &Spell::EffectNULL, //160 SPELL_EFFECT_160 unused - &Spell::EffectSpecCount, //161 SPELL_EFFECT_TALENT_SPEC_COUNT second talent spec (learn/revert) - &Spell::EffectActivateSpec, //162 SPELL_EFFECT_TALENT_SPEC_SELECT activate primary/secondary spec - &Spell::EffectNULL, //163 - &Spell::EffectRemoveAura, //164 SPELL_EFFECT_REMOVE_AURA -}; - -void Spell::EffectNULL(uint32 /*i*/) -{ - sLog.outDebug("WORLD: Spell Effect DUMMY"); -} - -void Spell::EffectUnused(uint32 /*i*/) -{ - // NOT USED BY ANY SPELL OR USELESS OR IMPLEMENTED IN DIFFERENT WAY IN TRINITY -} - -void Spell::EffectResurrectNew(uint32 i) -{ - if (!unitTarget || unitTarget->isAlive()) - return; - - if (unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - if (!unitTarget->IsInWorld()) - return; - - Player* pTarget = unitTarget->ToPlayer(); - - if (pTarget->isRessurectRequested()) // already have one active request - return; - - uint32 health = damage; - uint32 mana = m_spellInfo->EffectMiscValue[i]; - pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana); - SendResurrectRequest(pTarget); -} - -void Spell::EffectInstaKill(uint32 /*i*/) -{ - if (!unitTarget || !unitTarget->isAlive()) - return; - - // Demonic Sacrifice - if (m_spellInfo->Id == 18788 && unitTarget->GetTypeId() == TYPEID_UNIT) - { - uint32 entry = unitTarget->GetEntry(); - uint32 spellID; - switch (entry) - { - case 416: spellID = 18789; break; //imp - case 417: spellID = 18792; break; //fellhunter - case 1860: spellID = 18790; break; //void - case 1863: spellID = 18791; break; //succubus - case 17252: spellID = 35701; break; //fellguard - default: - sLog.outError("EffectInstaKill: Unhandled creature entry (%u) case.", entry); - return; - } - - m_caster->CastSpell(m_caster, spellID, true); - } - - if (m_caster == unitTarget) // prevent interrupt message - finish(); - - m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); -} - -void Spell::EffectEnvirinmentalDMG(uint32 i) -{ - uint32 absorb = 0; - uint32 resist = 0; - - // Note: this hack with damage replace required until GO casting not implemented - // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support - // currently each enemy selected explicitly and self cast damage, we prevent apply self casted spell bonuses/etc - damage = SpellMgr::CalculateSpellEffectAmount(m_spellInfo, i, m_caster); - - m_caster->CalcAbsorbResist(m_caster, GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist, m_spellInfo); - - m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false); - if (m_caster->GetTypeId() == TYPEID_PLAYER) - m_caster->ToPlayer()->EnvironmentalDamage(DAMAGE_FIRE, damage); -} - -void Spell::EffectSchoolDMG(uint32 /*effect_idx*/) -{ -} - -void Spell::SpellDamageSchoolDmg(uint32 effect_idx) -{ - bool apply_direct_bonus = true; - - if (unitTarget && unitTarget->isAlive()) - { - switch (m_spellInfo->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - { - // Meteor like spells (divided damage to targets) - if (m_customAttr & SPELL_ATTR_CU_SHARE_DAMAGE) - { - uint32 count = 0; - for (std::list::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) - if (ihit->effectMask & (1<Id) // better way to check unknown - { - // Positive/Negative Charge - case 28062: - case 28085: - case 39090: - case 39093: - if (!m_triggeredByAuraSpell) - break; - if (unitTarget == m_caster) - { - uint8 count = 0; - for (std::list::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) - if (ihit->targetGUID != m_caster->GetGUID()) - if (Player *target = ObjectAccessor::FindPlayer(ihit->targetGUID)) - if (target->HasAura(m_triggeredByAuraSpell->Id)) - ++count; - if (count) - { - uint32 spellId = 0; - switch (m_spellInfo->Id) - { - case 28062: spellId = 29659; break; - case 28085: spellId = 29660; break; - case 39090: spellId = 39089; break; - case 39093: spellId = 39092; break; - } - m_caster->SetAuraStack(spellId, m_caster, count); - } - } - - if (unitTarget->HasAura(m_triggeredByAuraSpell->Id)) - damage = 0; - break; - // Consumption - case 28865: - damage = (((InstanceMap*)m_caster->GetMap())->GetDifficulty() == REGULAR_DIFFICULTY ? 2750 : 4250); - break; - // percent from health with min - case 25599: // Thundercrash - { - damage = unitTarget->GetHealth() / 2; - if (damage < 200) - damage = 200; - break; - } - // arcane charge. must only affect demons (also undead?) - case 45072: - { - if (unitTarget->GetCreatureType() != CREATURE_TYPE_DEMON - && unitTarget->GetCreatureType() != CREATURE_TYPE_UNDEAD) - return; - break; - } - case 33671: // gruul's shatter - case 50811: // krystallus shatter ( Normal ) - case 61547: // krystallus shatter ( Heroic ) - { - // don't damage self and only players - if (unitTarget->GetGUID() == m_caster->GetGUID() || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - float radius = GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[0])); - if (!radius) return; - float distance = m_caster->GetDistance2d(unitTarget); - damage = (distance > radius) ? 0 : int32(m_spellInfo->EffectBasePoints[0]*((radius - distance)/radius)); - break; - } - // TODO: add spell specific target requirement hook for spells - // Shadowbolts only affects targets with Shadow Mark (Gothik) - case 27831: - case 55638: - if (!unitTarget->HasAura(27825)) - return; - break; - // Cataclysmic Bolt - case 38441: - { - damage = unitTarget->GetMaxHealth() / 2; - break; - } - // Tympanic Tantrum - case 62775: - { - damage = unitTarget->GetMaxHealth() / 10; - break; - } - // Gargoyle Strike - case 51963: - { - // about +4 base spell dmg per level - damage = (m_caster->getLevel() - 60) * 4 + 60; - break; - } - - // Loken Pulsing Shockwave - case 59837: - case 52942: - { - // don't damage self and only players - if(unitTarget->GetGUID() == m_caster->GetGUID() || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - float radius = GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[0])); - if (!radius) - return; - float distance = m_caster->GetDistance2d(unitTarget); - damage = (distance > radius) ? 0 : int32(m_spellInfo->EffectBasePoints[0]*distance); - break; - } - } - break; - } - case SPELLFAMILY_WARRIOR: - { - // Bloodthirst - if (m_spellInfo->SpellFamilyFlags[1] & 0x400) - damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100); - // Shield Slam - else if (m_spellInfo->SpellFamilyFlags[1] & 0x200 && m_spellInfo->Category == 1209) - damage += m_caster->ApplyEffectModifiers(m_spellInfo,effect_idx,int32(m_caster->GetShieldBlockValue())); - // Victory Rush - else if (m_spellInfo->SpellFamilyFlags[1] & 0x100) - { - damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100); - m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false); - } - // Shockwave - else if (m_spellInfo->Id == 46968) - { - int32 pct = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, 2); - if (pct > 0) - damage+= int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * pct / 100); - break; - } - break; - } - case SPELLFAMILY_WARLOCK: - { - // Incinerate Rank 1 & 2 - if ((m_spellInfo->SpellFamilyFlags[1] & 0x000040) && m_spellInfo->SpellIconID == 2128) - { - // Incinerate does more dmg (dmg*0.25) if the target have Immolate debuff. - // Check aura state for speed but aura state set not only for Immolate spell - if (unitTarget->HasAuraState(AURA_STATE_CONFLAGRATE)) - { - if (unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x4, 0, 0)) - damage += damage/4; - } - } - // Conflagrate - consumes Immolate or Shadowflame - else if (m_spellInfo->TargetAuraState == AURA_STATE_CONFLAGRATE) - { - AuraEffect const* aura = NULL; // found req. aura for damage calculation - - Unit::AuraEffectList const &mPeriodic = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_DAMAGE); - for (Unit::AuraEffectList::const_iterator i = mPeriodic.begin(); i != mPeriodic.end(); ++i) - { - // for caster applied auras only - if ((*i)->GetSpellProto()->SpellFamilyName != SPELLFAMILY_WARLOCK || - (*i)->GetCasterGUID() != m_caster->GetGUID()) - continue; - - // Immolate - if ((*i)->GetSpellProto()->SpellFamilyFlags[0] & 0x4) - { - aura = *i; // it selected always if exist - break; - } - - // Shadowflame - if ((*i)->GetSpellProto()->SpellFamilyFlags[2] & 0x00000002) - aura = *i; // remember but wait possible Immolate as primary priority - } - - // found Immolate or Shadowflame - if (aura) - { - uint32 pdamage = aura->GetAmount() > 0 ? aura->GetAmount() : 0; - pdamage = m_caster->SpellDamageBonus(unitTarget, aura->GetSpellProto(), pdamage, DOT, aura->GetBase()->GetStackAmount()); - uint32 pct_dir = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, (effect_idx + 1)); - damage += pdamage * aura->GetTotalTicks() * pct_dir / 100; - - uint32 pct_dot = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, (effect_idx + 2)) / 3; - m_currentBasePoints[1] = SpellMgr::CalculateSpellEffectBaseAmount(pdamage * aura->GetTotalTicks() * pct_dot / 100); - - apply_direct_bonus = false; - // Glyph of Conflagrate - if (!m_caster->HasAura(56235)) - unitTarget->RemoveAurasDueToSpell(aura->GetId(), m_caster->GetGUID()); - - break; - } - } - // Shadow Bite - else if (m_spellInfo->SpellFamilyFlags[1] & 0x400000) - { - if (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->isPet()) - { - // Get DoTs on target by owner (5% increase by dot) - damage += 5 * unitTarget->GetDoTsByCaster(m_caster->GetOwnerGUID()) / 100; - } - } - break; - } - case SPELLFAMILY_PRIEST: - { - // Shadow Word: Death - deals damage equal to damage done to caster - if ((m_spellInfo->SpellFamilyFlags[1] & 0x2)) - { - int32 back_damage = m_caster->SpellDamageBonus(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE); - // Pain and Suffering reduces damage - if (AuraEffect * aurEff = m_caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 2874, 0)) - back_damage -= aurEff->GetAmount() * back_damage / 100; - - if (back_damage < unitTarget->GetHealth()) - m_caster->CastCustomSpell(m_caster, 32409, &back_damage, 0, 0, true); - } - // Mind Blast - applies Mind Trauma if: - else if (m_spellInfo->SpellFamilyFlags[2] & 0x00002000) - { - // We are in Shadow Form - if (m_caster->m_form == FORM_SHADOW) - // We have Improved Mind Blast - if (AuraEffect * aurEff = m_caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST,95,0)) - // Chance has been successfully rolled - if (roll_chance_i(aurEff->GetAmount())) - m_caster->CastSpell(unitTarget, 48301, true); - } - // Smite - else if (m_spellInfo->SpellFamilyFlags[0] & 0x80) - { - // Glyph of Smite - if (AuraEffect * aurEff = m_caster->GetAuraEffect(55692, 0)) - if (unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x100000, 0, 0, m_caster->GetGUID())) - damage += damage * aurEff->GetAmount() / 100; - } - // Improved Mind Blast (Mind Blast in shadow form bonus) - else if (m_caster->m_form == FORM_SHADOW && (m_spellInfo->SpellFamilyFlags[0] & 0x00002000)) - { - Unit::AuraEffectList const& ImprMindBlast = m_caster->GetAuraEffectsByType(SPELL_AURA_ADD_FLAT_MODIFIER); - for (Unit::AuraEffectList::const_iterator i = ImprMindBlast.begin(); i != ImprMindBlast.end(); ++i) - { - if ((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_PRIEST && - ((*i)->GetSpellProto()->SpellIconID == 95)) - { - int chance = SpellMgr::CalculateSpellEffectAmount((*i)->GetSpellProto(), 1, m_caster); - if (roll_chance_i(chance)) - // Mind Trauma - m_caster->CastSpell(unitTarget, 48301, true, 0); - break; - } - } - } - break; - } - case SPELLFAMILY_DRUID: - { - // Ferocious Bite - if (m_caster->GetTypeId() == TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags[0] & 0x000800000) && m_spellInfo->SpellVisual[0] == 6587) - { - // converts each extra point of energy into ($f1+$AP/410) additional damage - float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK); - float multiple = ap / 410 + m_spellInfo->DmgMultiplier[effect_idx]; - int32 energy = -(m_caster->ModifyPower(POWER_ENERGY, -30)); - damage += int32(energy * multiple); - damage += int32(m_caster->ToPlayer()->GetComboPoints() * ap * 7 / 100); - } - // Wrath - else if (m_spellInfo->SpellFamilyFlags[0] & 0x00000001) - { - // Improved Insect Swarm - if (AuraEffect const * aurEff = m_caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 1771, 0)) - if (unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00200000, 0, 0)) - damage = int32(damage*(100.0f+aurEff->GetAmount())/100.0f); - } - break; - } - case SPELLFAMILY_ROGUE: - { - // Envenom - if (m_caster->GetTypeId() == TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags[1] & 0x8)) - { - // consume from stack dozes not more that have combo-points - if (uint32 combo = m_caster->ToPlayer()->GetComboPoints()) - { - // Lookup for Deadly poison (only attacker applied) - if (AuraEffect const * aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_ROGUE, 0x10000, 0, 0, m_caster->GetGUID())) - { - // count consumed deadly poison doses at target - bool needConsume = true; - uint32 spellId = aurEff->GetId(); - uint32 doses = aurEff->GetBase()->GetStackAmount(); - if (doses > combo) - doses = combo; - // Master Poisoner - Unit::AuraEffectList const& auraList = m_caster->ToPlayer()->GetAuraEffectsByType(SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL_NOT_STACK); - for (Unit::AuraEffectList::const_iterator iter = auraList.begin(); iter != auraList.end(); ++iter) - { - if ((*iter)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_ROGUE && (*iter)->GetSpellProto()->SpellIconID == 1960) - { - uint32 chance = SpellMgr::CalculateSpellEffectAmount((*iter)->GetSpellProto(), 2, m_caster); - - if (chance && roll_chance_i(chance)) - needConsume = false; - - break; - } - } - - if (needConsume) - for (uint32 i = 0; i < doses; ++i) - unitTarget->RemoveAuraFromStack(spellId); - damage *= doses; - damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.09f * doses); - } - // Eviscerate and Envenom Bonus Damage (item set effect) - if (m_caster->HasAura(37169)) - damage += ((Player*)m_caster)->GetComboPoints()*40; - } - } - // Eviscerate - else if ((m_spellInfo->SpellFamilyFlags[0] & 0x00020000) && m_caster->GetTypeId() == TYPEID_PLAYER) - { - if (uint32 combo = ((Player*)m_caster)->GetComboPoints()) - { - float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK); - damage += irand(int32(ap * combo * 0.03f), int32(ap * combo * 0.07f)); - - // Eviscerate and Envenom Bonus Damage (item set effect) - if (m_caster->HasAura(37169)) - damage += combo*40; - } - } - break; - } - case SPELLFAMILY_HUNTER: - { - //Gore - if (m_spellInfo->SpellIconID == 1578) - { - if (m_caster->HasAura(57627)) // Charge 6 sec post-affect - damage *= 2; - } - // Steady Shot - else if (m_spellInfo->SpellFamilyFlags[1] & 0x1) - { - bool found = false; - // check dazed affect - Unit::AuraEffectList const& decSpeedList = unitTarget->GetAuraEffectsByType(SPELL_AURA_MOD_DECREASE_SPEED); - for (Unit::AuraEffectList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter) - { - if ((*iter)->GetSpellProto()->SpellIconID == 15 && (*iter)->GetSpellProto()->Dispel == 0) - { - found = true; - break; - } - } - - // TODO: should this be put on taken but not done? - if (found) - damage += m_spellInfo->EffectBasePoints[1]; - - if (m_caster->GetTypeId() == TYPEID_PLAYER) - { - // Add Ammo and Weapon damage plus RAP * 0.1 - Item *item = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK); - if (item) - { - float dmg_min = item->GetProto()->Damage->DamageMin; - float dmg_max = item->GetProto()->Damage->DamageMax; - if (dmg_max == 0.0f && dmg_min > dmg_max) - damage += int32(dmg_min); - else - damage += irand(int32(dmg_min), int32(dmg_max)); - damage += m_caster->ToPlayer()->GetAmmoDPS()*item->GetProto()->Delay*0.001f; - } - } - - } - break; - } - case SPELLFAMILY_PALADIN: - { - // Hammer of the Righteous - if (m_spellInfo->SpellFamilyFlags[1]&0x00040000) - { - // Add main hand dps * effect[2] amount - float average = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2; - int32 count = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, 2); - damage += count * int32(average * IN_MILLISECONDS) / m_caster->GetAttackTime(BASE_ATTACK); - } - // Shield of Righteousness - else if (m_spellInfo->SpellFamilyFlags[1]&0x00100000) - { - damage += int32(m_caster->GetShieldBlockValue() * 1.3f); - } - // Judgement of Righteousness - else if (m_spellInfo->Id == 20187) - { - float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK); - float sp = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)); - damage += int32(0.2f*ap + 0.32f*sp); - } - // Judgement of Wisdom, Light, Justice - else if (m_spellInfo->Id == 54158) - { - float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK); - float sp = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)); - damage += int32(0.14f*ap + 0.22f*sp); - } - break; - } - case SPELLFAMILY_DEATHKNIGHT: - { - // Blood Boil - bonus for diseased targets - if (m_spellInfo->SpellFamilyFlags[0] & 0x00040000 && unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, 0, 0, 0x00000002, m_caster->GetGUID())) - { - damage += m_damage / 2; - damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)* 0.035f); - } - break; - } - } - - if (m_originalCaster && damage > 0 && apply_direct_bonus) - damage = m_originalCaster->SpellDamageBonus(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE); - - m_damage += damage; - } -} - -void Spell::EffectDummy(uint32 i) -{ - if (!unitTarget && !gameObjTarget && !itemTarget) - return; - - uint32 spell_id = 0; - int32 bp = 0; - bool triggered = true; - SpellCastTargets targets; - - // selection by spell family - switch (m_spellInfo->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - { - switch (m_spellInfo->Id) - { - case 8063: // Deviate Fish - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - uint32 spell_id = 0; - switch(urand(1,5)) - { - case 1: spell_id = 8064; break; // Sleepy - case 2: spell_id = 8065; break; // Invigorate - case 3: spell_id = 8066; break; // Shrink - case 4: spell_id = 8067; break; // Party Time! - case 5: spell_id = 8068; break; // Healthy Spirit - } - m_caster->CastSpell(m_caster, spell_id, true, NULL); - return; - } - case 8213: // Savory Deviate Delight - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - uint32 spell_id = 0; - switch(urand(1,2)) - { - // Flip Out - ninja - case 1: spell_id = (m_caster->getGender() == GENDER_MALE ? 8219 : 8220); break; - // Yaaarrrr - pirate - case 2: spell_id = (m_caster->getGender() == GENDER_MALE ? 8221 : 8222); break; - } - m_caster->CastSpell(m_caster,spell_id,true,NULL); - return; - } - case 8593: // Symbol of life (restore creature to life) - case 31225: // Shimmering Vessel (restore creature to life) - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) - return; - unitTarget->ToCreature()->setDeathState(JUST_ALIVED); - return; - } - case 12162: // Deep wounds - case 12850: // (now good common check for this spells) - case 12868: - { - if (!unitTarget) - return; - - float damage; - // 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 (m_caster->haveOffhandWeapon() && m_caster->getAttackTimer(BASE_ATTACK) > m_caster->getAttackTimer(OFF_ATTACK)) - damage = (m_caster->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE))/2; - else - damage = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE))/2; - - switch (m_spellInfo->Id) - { - case 12162: damage *= 0.16f; break; // Rank 1 - case 12850: damage *= 0.32f; break; // Rank 2 - case 12868: damage *= 0.48f; break; // Rank 3 - default: - sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id); - return; - }; - - // get remaining damage of old Deep Wound aura - AuraEffect* deepWound = unitTarget->GetAuraEffect(12721, 0); - if (deepWound) - { - int32 remainingTicks = deepWound->GetBase()->GetDuration() / deepWound->GetAmplitude(); - damage += remainingTicks * deepWound->GetAmount(); - } - - // 1 tick/sec * 6 sec = 6 ticks - int32 deepWoundsDotBasePoints0 = int32(damage / 6); - m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL); - return; - } - case 13120: // net-o-matic - { - if (!unitTarget) - return; - - uint32 spell_id = 0; - - uint32 roll = urand(0, 99); - - if (roll < 2) // 2% for 30 sec self root (off-like chance unknown) - spell_id = 16566; - else if (roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown) - spell_id = 13119; - else // normal root - spell_id = 13099; - - m_caster->CastSpell(unitTarget,spell_id,true,NULL); - return; - } - case 67019: // Flask of the North - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - uint32 spell_id; - switch(urand(1, 3)) - { - case 1: spell_id = 67016; break; - case 2: spell_id = 67017; break; - default:spell_id = 67018; break; - } - - m_caster->CastSpell(m_caster, spell_id, true, NULL); - return; - } - case 13280: // Gnomish Death Ray - { - if (!unitTarget) - return; - - if (urand(0, 99) < 15) - m_caster->CastSpell(m_caster, 13493, true, NULL); // failure - else - m_caster->CastSpell(unitTarget, 13279, true, NULL); - - return; - } - case 13567: // Dummy Trigger - { - // can be used for different aura triggering, so select by aura - if (!m_triggeredByAuraSpell || !unitTarget) - return; - - switch (m_triggeredByAuraSpell->Id) - { - case 26467: // Persistent Shield - m_caster->CastCustomSpell(unitTarget, 26470, &damage, NULL, NULL, true); - break; - default: - sLog.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u",m_triggeredByAuraSpell->Id); - break; - } - return; - } - case 14537: // Six Demon Bag - { - if( !unitTarget || !unitTarget->isAlive()) return; - - uint32 ClearSpellId[6] = - { - 15662, // Fireball - 11538, // Frostball - 21179, // Chain Lightning - 14621, // Polymorph - 25189, // Enveloping Winds - 14642 // Summon Felhund minion - }; - - uint32 effect = 0; - uint32 rand = urand(0, 100); - - if (rand >= 0 && rand < 25) // Fireball (25% chance) - effect = ClearSpellId[0]; - else if (rand >= 25 && rand < 50) // Frostball (25% chance) - effect = ClearSpellId[1]; - else if (rand >=50 && rand < 70) // Chain Lighting (25% chance) - effect = ClearSpellId[2]; - else if (rand >= 70 && rand < 80) // Polymorph (10% chance) - { - effect = ClearSpellId[3]; - if (urand(0, 100) <= 30) // 30% chance to self-cast - unitTarget = m_caster; - } - else if (rand >=80 && rand < 95) // Enveloping Winds (15% chance) - effect = ClearSpellId[4]; - else // Summon Felhund minion (5% chance) - { - effect = ClearSpellId[5]; - unitTarget = m_caster; - } - - m_caster->CastSpell(unitTarget, effect, true); - return; - } - case 15998: // Capture Worg Pup - case 29435: // Capture Female Kaliri Hatchling - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) - return; - - unitTarget->ToCreature()->ForcedDespawn(); - return; - } - case 16589: // Noggenfogger Elixir - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - uint32 spell_id = 0; - switch (urand(1, 3)) - { - case 1: spell_id = 16595; break; - case 2: spell_id = 16593; break; - default:spell_id = 16591; break; - } - - m_caster->CastSpell(m_caster, spell_id, true, NULL); - return; - } - case 17251: // Spirit Healer Res - { - if (!unitTarget || !m_originalCaster) - return; - - if (m_originalCaster->GetTypeId() == TYPEID_PLAYER) - { - WorldPacket data(SMSG_SPIRIT_HEALER_CONFIRM, 8); - data << uint64(unitTarget->GetGUID()); - m_originalCaster->ToPlayer()->GetSession()->SendPacket(&data); - } - return; - } - case 17271: // Test Fetid Skull - { - if (!itemTarget && m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - uint32 spell_id = roll_chance_i(50) - ? 17269 // Create Resonating Skull - : 17270; // Create Bone Dust - - m_caster->CastSpell(m_caster, spell_id, true, NULL); - return; - } - case 20577: // Cannibalize - if (unitTarget) - m_caster->CastSpell(m_caster, 20578, false, NULL); - return; - case 23019: // Crystal Prison Dummy DND - { - if (!unitTarget || !unitTarget->isAlive() || unitTarget->GetTypeId() != TYPEID_UNIT || unitTarget->ToCreature()->isPet()) - return; - - Creature* creatureTarget = unitTarget->ToCreature(); - - m_caster->SummonGameObject(179644, creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(), creatureTarget->GetOrientation(), 0, 0, 0, 0, creatureTarget->GetRespawnTime()-time(NULL)); - sLog.outDebug("SummonGameObject at SpellEfects.cpp EffectDummy for Spell 23019"); - - creatureTarget->ForcedDespawn(); - - return; - } - case 23074: // Arcanite Dragonling - if (!m_CastItem) return; - m_caster->CastSpell(m_caster, 19804, true, m_CastItem); - return; - case 23075: // Mithril Mechanical Dragonling - if (!m_CastItem) return; - m_caster->CastSpell(m_caster, 12749, true, m_CastItem); - return; - case 23076: // Mechanical Dragonling - if (!m_CastItem) return; - m_caster->CastSpell(m_caster, 4073, true, m_CastItem); - return; - case 23133: // Gnomish Battle Chicken - if (!m_CastItem) return; - m_caster->CastSpell(m_caster, 13166, true, m_CastItem); - return; - case 23448: // Transporter Arrival - Ultrasafe Transporter: Gadgetzan - backfires - { - int32 r = irand(0, 119); - if (r < 20) // Transporter Malfunction - 1/6 polymorph - m_caster->CastSpell(m_caster, 23444, true); - else if (r < 100) // Evil Twin - 4/6 evil twin - m_caster->CastSpell(m_caster, 23445, true); - else // Transporter Malfunction - 1/6 miss the target - m_caster->CastSpell(m_caster, 36902, true); - return; - } - case 23453: // Gnomish Transporter - Ultrasafe Transporter: Gadgetzan - if (roll_chance_i(50)) // Gadgetzan Transporter - success - m_caster->CastSpell(m_caster, 23441, true); - else // Gadgetzan Transporter Failure - failure - m_caster->CastSpell(m_caster, 23446, true); - return; - case 23645: // Hourglass Sand - m_caster->RemoveAurasDueToSpell(23170); // Brood Affliction: Bronze - return; - case 23725: // Gift of Life (warrior bwl trinket) - m_caster->CastSpell(m_caster, 23782, true); - m_caster->CastSpell(m_caster, 23783, true); - return; - case 25860: // Reindeer Transformation - { - if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED)) - return; - - float flyspeed = m_caster->GetSpeedRate(MOVE_FLIGHT); - float speed = m_caster->GetSpeedRate(MOVE_RUN); - - m_caster->RemoveAurasByType(SPELL_AURA_MOUNTED); - - //5 different spells used depending on mounted speed and if mount can fly or not - if (flyspeed >= 4.1f) - // Flying Reindeer - m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer - else if (flyspeed >= 3.8f) - // Flying Reindeer - m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer - else if (flyspeed >= 1.6f) - // Flying Reindeer - m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer - else if (speed >= 2.0f) - // Reindeer - m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer - else - // Reindeer - m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer - - return; - } - case 26074: // Holiday Cheer - // implemented at client side - return; - case 28006: // Arcane Cloaking - { - if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER) - // Naxxramas Entry Flag Effect DND - m_caster->CastSpell(unitTarget, 29294, true); - return; - } - // Polarity Shift - case 28089: - if (unitTarget) - unitTarget->CastSpell(unitTarget, roll_chance_i(50) ? 28059 : 28084, true, NULL, NULL, m_caster->GetGUID()); - break; - // Polarity Shift - case 39096: - if (unitTarget) - unitTarget->CastSpell(unitTarget, roll_chance_i(50) ? 39088 : 39091, true, NULL, NULL, m_caster->GetGUID()); - break; - case 29200: // Purify Helboar Meat - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - uint32 spell_id = roll_chance_i(50) - ? 29277 // Summon Purified Helboar Meat - : 29278; // Summon Toxic Helboar Meat - - m_caster->CastSpell(m_caster,spell_id,true,NULL); - return; - } - case 29858: // Soulshatter - if (unitTarget && unitTarget->CanHaveThreatList() - && unitTarget->getThreatManager().getThreat(m_caster) > 0.0f) - m_caster->CastSpell(unitTarget,32835,true); - return; - case 30458: // Nigh Invulnerability - if (!m_CastItem) return; - if (roll_chance_i(86)) // Nigh-Invulnerability - success - m_caster->CastSpell(m_caster, 30456, true, m_CastItem); - else // Complete Vulnerability - backfire in 14% casts - m_caster->CastSpell(m_caster, 30457, true, m_CastItem); - return; - case 30507: // Poultryizer - if (!m_CastItem) return; - if (roll_chance_i(80)) // Poultryized! - success - m_caster->CastSpell(unitTarget, 30501, true, m_CastItem); - else // Poultryized! - backfire 20% - m_caster->CastSpell(unitTarget, 30504, true, m_CastItem); - return; - case 33060: // Make a Wish - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - uint32 spell_id = 0; - - switch(urand(1,5)) - { - case 1: spell_id = 33053; break; // Mr Pinchy's Blessing - case 2: spell_id = 33057; break; // Summon Mighty Mr. Pinchy - case 3: spell_id = 33059; break; // Summon Furious Mr. Pinchy - case 4: spell_id = 33062; break; // Tiny Magical Crawdad - case 5: spell_id = 33064; break; // Mr. Pinchy's Gift - } - - m_caster->CastSpell(m_caster, spell_id, true, NULL); - return; - } - case 34665: //Administer Antidote - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT - || unitTarget->GetEntry() != 16880 || unitTarget->ToCreature()->isPet()) - return; - - unitTarget->ToCreature()->UpdateEntry(16992); - m_caster->ToPlayer()->RewardPlayerAndGroupAtEvent(16992, unitTarget); - - if (unitTarget->IsAIEnabled) - unitTarget->ToCreature()->AI()->AttackStart(m_caster); - - return; - } - case 35745: // Socrethar's Stone - { - uint32 spell_id; - switch(m_caster->GetAreaId()) - { - case 3900: spell_id = 35743; break; // Socrethar Portal - case 3742: spell_id = 35744; break; // Socrethar Portal - default: return; - } - - m_caster->CastSpell(m_caster, spell_id, true); - return; - } - case 37674: // Chaos Blast - { - if (!unitTarget) - return; - - int32 basepoints0 = 100; - m_caster->CastCustomSpell(unitTarget, 37675, &basepoints0, NULL, NULL, true); - return; - } - case 40109: // Knockdown Fel Cannon: The Bolt - { - unitTarget->CastSpell(unitTarget, 40075, true); - return; - } - case 40802: // Mingo's Fortune Generator (Mingo's Fortune Giblets) - { - // selecting one from Bloodstained Fortune item - uint32 newitemid; - switch(urand(1, 20)) - { - case 1: newitemid = 32688; break; - case 2: newitemid = 32689; break; - case 3: newitemid = 32690; break; - case 4: newitemid = 32691; break; - case 5: newitemid = 32692; break; - case 6: newitemid = 32693; break; - case 7: newitemid = 32700; break; - case 8: newitemid = 32701; break; - case 9: newitemid = 32702; break; - case 10: newitemid = 32703; break; - case 11: newitemid = 32704; break; - case 12: newitemid = 32705; break; - case 13: newitemid = 32706; break; - case 14: newitemid = 32707; break; - case 15: newitemid = 32708; break; - case 16: newitemid = 32709; break; - case 17: newitemid = 32710; break; - case 18: newitemid = 32711; break; - case 19: newitemid = 32712; break; - case 20: newitemid = 32713; break; - default: - return; - } - - DoCreateItem(i, newitemid); - return; - } - // Wrath of the Astromancer - case 42784: - { - uint32 count = 0; - for (std::list::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) - if (ihit->effectMask & (1<::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) - if (ihit->effectMask & (1<targetGUID)) - m_caster->DealDamage(casttarget, damage, NULL, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_ARCANE, spellInfo, false); - } - - return; - } - // Demon Broiled Surprise - case 43723: - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player *player = (Player*)m_caster; - - if (player && player->GetQuestStatus(11379) == QUEST_STATUS_INCOMPLETE) - { - Creature *creature = player->FindNearestCreature(19973, 10, false); - if (!creature) - { - SendCastResult(SPELL_FAILED_NOT_HERE); - return; - } - - player->CastSpell(player, 43753, false); - } - return; - } - case 44875: // Complete Raptor Capture - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) - return; - - unitTarget->ToCreature()->ForcedDespawn(); - - //cast spell Raptor Capture Credit - m_caster->CastSpell(m_caster, 42337, true, NULL); - return; - } - case 44997: // Converting Sentry - { - //Converted Sentry Credit - m_caster->CastSpell(m_caster, 45009, true); - return; - } - case 45030: // Impale Emissary - { - // Emissary of Hate Credit - m_caster->CastSpell(m_caster, 45088, true); - return; - } - case 47170: // Impale Leviroth - { - if (!unitTarget && unitTarget->GetEntry() != 26452 && ((unitTarget->GetHealth() / unitTarget->GetMaxHealth()) * 100.0f) > 95.0f) - return; - - m_caster->DealDamage(unitTarget, unitTarget->GetMaxHealth()*0.93f); - return; - } - case 49625: // Brave's Flare - { - //Trigger Brave's Flare Effect (with EffectTarget) - m_caster->CastSpell(m_caster, 43106, true); - return; - } - case 49634: // Sergeant's Flare - { - //Trigger Sergeant's Flare Effect (with EffectTarget) - m_caster->CastSpell(m_caster, 43068, true); - return; - } - case 49357: // Brewfest Mount Transformation - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED)) - return; - m_caster->RemoveAurasByType(SPELL_AURA_MOUNTED); - // Ram for Alliance, Kodo for Horde - if (m_caster->ToPlayer()->GetTeam() == ALLIANCE) - { - if (m_caster->GetSpeedRate(MOVE_RUN) >= 2.0f) - // 100% Ram - m_caster->CastSpell(m_caster, 43900, true); - else - // 60% Ram - m_caster->CastSpell(m_caster, 43899, true); - } - else - { - if (m_caster->ToPlayer()->GetSpeedRate(MOVE_RUN) >= 2.0f) - // 100% Kodo - m_caster->CastSpell(m_caster, 49379, true); - else - // 60% Kodo - m_caster->CastSpell(m_caster, 49378, true); - } - return; - // Magic Pull - case 51336: - m_caster->CastSpell(unitTarget,50770,true); - break; - case 52845: // Brewfest Mount Transformation (Faction Swap) - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED)) - return; - m_caster->RemoveAurasByType(SPELL_AURA_MOUNTED); - // Ram for Horde, Kodo for Alliance - if (m_caster->ToPlayer()->GetTeam() == HORDE) - { - if (m_caster->GetSpeedRate(MOVE_RUN) >= 2.0f) - // 100% Ram - m_caster->CastSpell(m_caster, 43900, true); - else - // 60% Ram - m_caster->CastSpell(m_caster, 43899, true); - } - else - { - if (m_caster->ToPlayer()->GetSpeedRate(MOVE_RUN) >= 2.0f) - // 100% Kodo - m_caster->CastSpell(m_caster, 49379, true); - else - // 60% Kodo - m_caster->CastSpell(m_caster, 49378, true); - } - return; - case 55004: // Nitro Boosts - if (!m_CastItem) - return; - if (roll_chance_i(95)) // Nitro Boosts - success - m_caster->CastSpell(m_caster, 54861, true, m_CastItem); - else // Knocked Up - backfire 5% - m_caster->CastSpell(m_caster, 46014, true, m_CastItem); - return; - case 50243: // Teach Language - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - // spell has a 1/3 chance to trigger one of the below - if (roll_chance_i(66)) - return; - if (m_caster->ToPlayer()->GetTeam() == ALLIANCE) - { - // 1000001 - gnomish binary - m_caster->CastSpell(m_caster, 50242, true); - } - else - { - // 01001000 - goblin binary - m_caster->CastSpell(m_caster, 50246, true); - } - - return; - } - case 51582: //Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite) - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - if (BattleGround* bg = m_caster->ToPlayer()->GetBattleGround()) - bg->EventPlayerDroppedFlag(m_caster->ToPlayer()); - - m_caster->CastSpell(m_caster, 30452, true, NULL); - return; - } - case 51592: // Pickup Primordial Hatchling - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) - return; - - unitTarget->ToCreature()->ForcedDespawn(); - return; - - } - case 52308: // Take Sputum Sample - { - switch(i) - { - case 0: - { - uint32 spellID = SpellMgr::CalculateSpellEffectAmount(m_spellInfo, 0); - uint32 reqAuraID = SpellMgr::CalculateSpellEffectAmount(m_spellInfo, 1); - - if (m_caster->HasAuraEffect(reqAuraID,0)) - m_caster->CastSpell(m_caster,spellID,true,NULL); - return; - } - case 1: - return; // additional data for dummy[0] - } - return; - } - case 52759: // Ancestral Awakening - if (!unitTarget) - return; - m_caster->CastCustomSpell(unitTarget, 52752, &damage, NULL, NULL, true); - return; - case 53341: // Rune of Cinderglacier - case 53343: // Rune of Razorice - { - // Runeforging Credit - m_caster->CastSpell(m_caster, 54586, true); - return; - } - case 54171: //Divine Storm - { - m_caster->CastCustomSpell(unitTarget, 54172, &damage, 0, 0, true); - return; - } - case 58418: // Portal to Orgrimmar - case 58420: // Portal to Stormwind - return; // implemented in EffectScript[0] - case 59640: // Underbelly Elixir - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - uint32 spell_id = 0; - switch(urand(1,3)) - { - case 1: spell_id = 59645; break; - case 2: spell_id = 59831; break; - case 3: spell_id = 59843; break; - } - m_caster->CastSpell(m_caster,spell_id,true,NULL); - return; - } - case 62324: // Throw Passenger - { - if (m_targets.HasTraj()) - { - if (Vehicle *vehicle = m_caster->GetVehicleKit()) - if (Unit *passenger = vehicle->GetPassenger(damage - 1)) - { - std::list unitList; - // use 99 because it is 3d search - SearchAreaTarget(unitList, 99, PUSH_DST_CENTER, SPELL_TARGETS_ENTRY, 33114); - float minDist = 99 * 99; - Vehicle *target = NULL; - for (std::list::iterator itr = unitList.begin(); itr != unitList.end(); ++itr) - { - if (Vehicle *seat = (*itr)->GetVehicleKit()) - if (!seat->GetPassenger(0)) - if (Unit *device = seat->GetPassenger(2)) - if (!device->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) - { - float dist = (*itr)->GetExactDistSq(&m_targets.m_dstPos); - if (dist < minDist) - { - minDist = dist; - target = seat; - } - } - } - if (target && target->GetBase()->IsWithinDist2d(&m_targets.m_dstPos, GetSpellRadius(m_spellInfo, i, false) * 2)) // now we use *2 because the location of the seat is not correct - passenger->EnterVehicle(target, 0); - else - { - passenger->ExitVehicle(); - float x, y, z; - m_targets.m_dstPos.GetPosition(x, y, z); - passenger->GetMotionMaster()->MoveJump(x, y, z, m_targets.GetSpeedXY(), m_targets.GetSpeedZ()); - } - } - } - return; - } - case 64385: // Unusual Compass - { - m_caster->SetOrientation(float(urand(0,62832)) / 10000.0f); - WorldPacket data; - m_caster->BuildHeartBeatMsg(&data); - m_caster->SendMessageToSet(&data,true); - return; - } - } - - break; - } - case SPELLFAMILY_MAGE: - switch(m_spellInfo->Id) - { - case 11958: // Cold Snap - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - // immediately finishes the cooldown on Frost spells - const SpellCooldowns& cm = m_caster->ToPlayer()->GetSpellCooldownMap(); - for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();) - { - SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); - - if (spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && - (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) && - spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0) - { - m_caster->ToPlayer()->RemoveSpellCooldown((itr++)->first, true); - } - else - ++itr; - } - return; - } - case 32826: // Polymorph Cast Visual - { - if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT) - { - //Polymorph Cast Visual Rank 1 - const uint32 spell_list[6] = { - 32813, // Squirrel Form - 32816, // Giraffe Form - 32817, // Serpent Form - 32818, // Dragonhawk Form - 32819, // Worgen Form - 32820 // Sheep Form - }; - unitTarget->CastSpell(unitTarget, spell_list[urand(0, 5)], true); - } - return; - } - case 31687: // Summon Water Elemental - { - if (!unitTarget) - return; - - // Glyph of Eternal Water - if (unitTarget->HasAura(70937)) - unitTarget->CastSpell(unitTarget, 70908, true); - else - unitTarget->CastSpell(unitTarget, 70907, true); - } - } - break; - case SPELLFAMILY_WARRIOR: - // Charge - if (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_WARRIOR_CHARGE && m_spellInfo->SpellVisual[0] == 867) - { - int32 chargeBasePoints0 = damage; - m_caster->CastCustomSpell(m_caster, 34846, &chargeBasePoints0, NULL, NULL, true); - - //Juggernaut crit bonus - if (m_caster->HasAura(64976)) - m_caster->CastSpell(m_caster, 65156, true); - return; - } - //Slam - if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_WARRIOR_SLAM && m_spellInfo->SpellIconID == 559) - { - int32 bp0 = damage; - m_caster->CastCustomSpell(unitTarget, 50783, &bp0, NULL, NULL, true, 0); - return; - } - // Execute - if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_WARRIOR_EXECUTE) - { - if (!unitTarget) - return; - - uint32 rage = m_caster->GetPower(POWER_RAGE); - - // Glyph of Execution bonus - if (AuraEffect *aura = m_caster->GetAuraEffect(58367, 0)) - rage += aura->GetAmount(); - - spell_id = 20647; - - // Sudden death cost modifier - if (Aura * aur = m_caster->GetAura(52437)) - { - rage += m_powerCost; - m_caster->ModifyPower(POWER_RAGE, -m_powerCost); - if (m_caster->GetPower(POWER_RAGE) < 100) - m_caster->SetPower(POWER_RAGE, 100); - m_caster->RemoveAura(aur); - } - else - { - rage += m_powerCost; - m_caster->ModifyPower(POWER_RAGE, -m_powerCost); - } - - if (rage > 300) - rage = 300; - - bp = damage+int32(rage * m_spellInfo->DmgMultiplier[i] + - m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f); - break; - } - // Concussion Blow - if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_WARRIOR_CONCUSSION_BLOW) - { - m_damage+= uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100); - return; - } - switch(m_spellInfo->Id) - { - // Warrior's Wrath - case 21977: - { - if (!unitTarget) - return; - m_caster->CastSpell(unitTarget, 21887, true);// spell mod - return; - } - // Last Stand - case 12975: - { - int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3); - m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, NULL, NULL, true, NULL); - return; - } - // Bloodthirst - case 23881: - { - m_caster->CastCustomSpell(unitTarget, 23885, &damage, NULL, NULL, true, NULL); - return; - } - } - break; - case SPELLFAMILY_WARLOCK: - // Life Tap - if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_WARLOCK_LIFETAP) - { - float spFactor = 0; - switch (m_spellInfo->Id) - { - case 11689: spFactor = 0.2; break; - case 27222: - case 57946: spFactor = 0.5; break; - default: spFactor = 0; break; - } - int32 damage = m_spellInfo->EffectBasePoints[0] + (6.3875 * m_spellInfo->baseLevel); - int32 mana = damage + (m_caster->ToPlayer()->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+SPELL_SCHOOL_SHADOW) * spFactor); - - if (unitTarget && (int32(unitTarget->GetHealth()) > damage)) - { - // Shouldn't Appear in Combat Log - unitTarget->ModifyHealth(-damage); - - // Improved Life Tap mod - if (AuraEffect const * aurEff = m_caster->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, 208, 0)) - mana = (aurEff->GetAmount() + 100)* mana / 100; - - m_caster->CastCustomSpell(unitTarget, 31818, &mana, NULL, NULL, true); - - // Mana Feed - int32 manaFeedVal = 0; - if (AuraEffect const * aurEff = m_caster->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_WARLOCK, 1982, 0)) - manaFeedVal = aurEff->GetAmount(); - - if (manaFeedVal > 0) - { - manaFeedVal = manaFeedVal * mana / 100; - m_caster->CastCustomSpell(m_caster, 32553, &manaFeedVal, NULL, NULL, true, NULL); - } - } - else - SendCastResult(SPELL_FAILED_FIZZLE); - return; - } - break; - case SPELLFAMILY_PRIEST: - // Penance - if (m_spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_PRIEST_PENANCE) - { - if (!unitTarget || !unitTarget->isAlive()) - return; - - int hurt = 0; - int heal = 0; - switch(m_spellInfo->Id) - { - case 47540: hurt = 47758; heal = 47757; break; - case 53005: hurt = 53001; heal = 52986; break; - case 53006: hurt = 53002; heal = 52987; break; - case 53007: hurt = 53003; heal = 52988; break; - default: - sLog.outError("Spell::EffectDummy: Spell %u Penance need set correct heal/damage spell", m_spellInfo->Id); - return; - } - if (m_caster->IsFriendlyTo(unitTarget)) - m_caster->CastSpell(unitTarget, heal, false, 0); - else - m_caster->CastSpell(unitTarget, hurt, false, 0); - return; - } - break; - case SPELLFAMILY_DRUID: - // Starfall - if (m_spellInfo->SpellFamilyFlags[2] & SPELLFAMILYFLAG2_DRUID_STARFALL) - { - //Shapeshifting into an animal form or mounting cancels the effect. - if (m_caster->GetCreatureType() == CREATURE_TYPE_BEAST || m_caster->IsMounted()) - { - if (m_triggeredByAuraSpell) - m_caster->RemoveAurasDueToSpell(m_triggeredByAuraSpell->Id); - return; - } - - //Any effect which causes you to lose control of your character will supress the starfall effect. - if (m_caster->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_ROOT | UNIT_STAT_CONFUSED)) - return; - - m_caster->CastSpell(unitTarget, damage, true); - return; - } - break; - case SPELLFAMILY_ROGUE: - // Hunger for Blood - if (m_spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_HUNGERFORBLOOD) - { - m_caster->CastSpell(m_caster, 63848, true); - break; - } - switch (m_spellInfo->Id) - { - case 5938: // Shiv - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - m_caster->CastSpell(unitTarget, 5940, true); - return; - } - case 14185: // Preparation - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - //immediately finishes the cooldown on certain Rogue abilities - const SpellCooldowns& cm = m_caster->ToPlayer()->GetSpellCooldownMap(); - for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();) - { - SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); - - if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE) - { - if (spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_COLDB_SHADOWSTEP || // Cold Blood, Shadowstep - spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_VAN_EVAS_SPRINT // Vanish, Evasion, Sprint - ) - m_caster->ToPlayer()->RemoveSpellCooldown((itr++)->first, true); - else if (m_caster->HasAura(56819)) // Glyph of Preparation - { - if (spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_DISMANTLE || // Dismantle - spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_KICK || // Kick - ( - spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_BLADE_FLURRY && // Blade Flurry - spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_BLADE_FLURRY - ) - ) - m_caster->ToPlayer()->RemoveSpellCooldown((itr++)->first, true); - else - ++itr; - } - else - ++itr; - } - else - ++itr; - } - return; - } - case 31231: // Cheat Death - { - m_caster->CastSpell(m_caster, 45182, true); - return; - } - } - break; - case SPELLFAMILY_HUNTER: - switch(m_spellInfo->Id) - { - case 23989: // Readiness talent - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - // immediately finishes the cooldown on your other Hunter abilities except Bestial Wrath - const SpellCooldowns& cm = m_caster->ToPlayer()->GetSpellCooldownMap(); - for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();) - { - SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); - - if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && spellInfo->Id != 19574 && GetSpellRecoveryTime(spellInfo) > 0) - m_caster->ToPlayer()->RemoveSpellCooldown((itr++)->first,true); - else - ++itr; - } - return; - } - case 37506: // Scatter Shot - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - // break Auto Shot and autohit - m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL); - m_caster->AttackStop(); - m_caster->ToPlayer()->SendAttackSwingCancelAttack(); - return; - } - // Last Stand (pet) - case 53478: - { - int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3); - m_caster->CastCustomSpell(m_caster, 53479, &healthModSpellBasePoints0, NULL, NULL, true, NULL); - return; - } - // Master's Call - case 53271: - { - if (m_caster->GetTypeId() != TYPEID_PLAYER || !unitTarget) - return; - - if (Pet *pPet = m_caster->ToPlayer()->GetPet()) - if (pPet->isAlive()) - pPet->CastSpell(unitTarget, SpellMgr::CalculateSpellEffectAmount(m_spellInfo, i), true); - return; - } - } - break; - case SPELLFAMILY_PALADIN: - // Divine Storm - if (m_spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_PALADIN_DIVINESTORM && i == 1) - { - int32 dmg = m_damage * damage / 100; - if (!unitTarget) - unitTarget = m_caster; - m_caster->CastCustomSpell(unitTarget, 54171, &dmg, 0, 0, true); - return; - } - switch(m_spellInfo->SpellIconID) - { - case 156: // Holy Shock - { - if (!unitTarget) - return; - - int hurt = 0; - int heal = 0; - - switch(m_spellInfo->Id) - { - case 20473: hurt = 25912; heal = 25914; break; - case 20929: hurt = 25911; heal = 25913; break; - case 20930: hurt = 25902; heal = 25903; break; - case 27174: hurt = 27176; heal = 27175; break; - case 33072: hurt = 33073; heal = 33074; break; - case 48824: hurt = 48822; heal = 48820; break; - case 48825: hurt = 48823; heal = 48821; break; - default: - sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id); - return; - } - - if (m_caster->IsFriendlyTo(unitTarget)) - m_caster->CastSpell(unitTarget, heal, true, 0); - else - m_caster->CastSpell(unitTarget, hurt, true, 0); - - return; - } - } - - switch(m_spellInfo->Id) - { - case 20425: // Judgement of command - { - if (!unitTarget) - return; - - SpellEntry const* spell_proto = sSpellStore.LookupEntry(damage); - if (!spell_proto) - return; - - m_caster->CastSpell(unitTarget, spell_proto, true, NULL); - return; - } - case 31789: // Righteous Defense (step 1) - { - // Clear targets for eff 1 - for (std::list::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) - ihit->effectMask &= ~(1<<1); - - // not empty (checked), copy - Unit::AttackerSet attackers = unitTarget->getAttackers(); - - // selected from list 3 - for (int i = 0; i < std::min(size_t(3),attackers.size()); ++i) - { - Unit::AttackerSet::iterator aItr = attackers.begin(); - std::advance(aItr, rand() % attackers.size()); - AddUnitTarget((*aItr), 1); - attackers.erase(aItr); - } - - // now let next effect cast spell at each target. - return; - } - case 37877: // Blessing of Faith - { - if (!unitTarget) - return; - - uint32 spell_id = 0; - switch(unitTarget->getClass()) - { - case CLASS_DRUID: spell_id = 37878; break; - case CLASS_PALADIN: spell_id = 37879; break; - case CLASS_PRIEST: spell_id = 37880; break; - case CLASS_SHAMAN: spell_id = 37881; break; - default: return; // ignore for not healing classes - } - - m_caster->CastSpell(m_caster, spell_id, true); - return; - } - } - break; - case SPELLFAMILY_SHAMAN: - // Cleansing Totem Pulse - if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_SHAMAN_TOTEM_EFFECTS && m_spellInfo->SpellIconID == 1673) - { - int32 bp1 = 1; - // Cleansing Totem Effect - if (unitTarget) - m_caster->CastCustomSpell(unitTarget, 52025, NULL, &bp1, NULL, true, NULL, NULL, m_originalCasterGUID); - return; - } - // Healing Stream Totem - if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_SHAMAN_HEALING_STREAM) - { - if (!unitTarget) - return; - // Restorative Totems - if (Unit *owner = m_caster->GetOwner()) - if (AuraEffect *dummy = owner->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 338, 1)) - damage += damage * dummy->GetAmount() / 100; - - m_caster->CastCustomSpell(unitTarget, 52042, &damage, 0, 0, true, 0, 0, m_originalCasterGUID); - return; - } - // Mana Spring Totem - if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_SHAMAN_MANA_SPRING) - { - if (!unitTarget || unitTarget->getPowerType() != POWER_MANA) - return; - m_caster->CastCustomSpell(unitTarget, 52032, &damage, 0, 0, true, 0, 0, m_originalCasterGUID); - return; - } - if (m_spellInfo->Id == 39610) // Mana Tide Totem effect - { - if (!unitTarget || unitTarget->getPowerType() != POWER_MANA) - return; - // Glyph of Mana Tide - if (Unit *owner = m_caster->GetOwner()) - if (AuraEffect *dummy = owner->GetAuraEffect(55441, 0)) - damage += dummy->GetAmount(); - // Regenerate 6% of Total Mana Every 3 secs - int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100; - m_caster->CastCustomSpell(unitTarget, 39609, &EffectBasePoints0, NULL, NULL, true, NULL, NULL, m_originalCasterGUID); - return; - } - // Fire Nova - if (m_spellInfo->SpellIconID == 33) - { - if (!m_caster) - return; - - uint32 triggered_spell_id; - switch(m_spellInfo->Id) - { - case 1535: triggered_spell_id = 8349; break; - case 8498: triggered_spell_id = 8502; break; - case 8499: triggered_spell_id = 8503; break; - case 11314: triggered_spell_id = 11306; break; - case 11315: triggered_spell_id = 11307; break; - case 25546: triggered_spell_id = 25535; break; - case 25547: triggered_spell_id = 25537; break; - case 61649: triggered_spell_id = 61650; break; - case 61657: triggered_spell_id = 61654; break; - default: - break; - } - // fire slot - if (triggered_spell_id && m_caster->m_SummonSlot[1]) - { - Creature* totem = m_caster->GetMap()->GetCreature(m_caster->m_SummonSlot[1]); - if (totem && totem->isTotem()) - totem->CastSpell(totem, triggered_spell_id, true); - return; - } - return; - } - // Lava Lash - if (m_spellInfo->SpellFamilyFlags[2] & SPELLFAMILYFLAG2_SHAMAN_LAVA_LASH) - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - if (Item *item = m_caster->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND)) - { - // Damage is increased by 25% if your off-hand weapon is enchanted with Flametongue. - if (m_caster->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0x200000, 0, 0)) - m_damage += m_damage * damage / 100; - } - return; - } - break; - case SPELLFAMILY_DEATHKNIGHT: - // Death strike - if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_DK_DEATH_STRIKE) - { - uint32 count = unitTarget->GetDiseasesByCaster(m_caster->GetGUID()); - int32 bp = count * m_caster->GetMaxHealth() * m_spellInfo->DmgMultiplier[0] / 100; - // Improved Death Strike - if (AuraEffect const * aurEff = m_caster->GetAuraEffect(SPELL_AURA_ADD_PCT_MODIFIER, SPELLFAMILY_DEATHKNIGHT, 2751, 0)) - bp = bp * (m_caster->CalculateSpellDamage(m_caster, aurEff->GetSpellProto(), 2) + 100.0f) / 100.0f; - m_caster->CastCustomSpell(m_caster, 45470, &bp, NULL, NULL, false); - return; - } - // Scourge Strike - if (m_spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_DK_SCOURGE_STRIKE) - { - int32 bp = (m_damage * damage * unitTarget->GetDiseasesByCaster(m_caster->GetGUID())) / 100; - m_caster->CastCustomSpell(unitTarget, 70890, &bp, NULL, NULL, true); - return; - } - // Death Coil - if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_DK_DEATH_COIL) - { - if (m_caster->IsFriendlyTo(unitTarget)) - { - int32 bp = damage * 1.5f; - m_caster->CastCustomSpell(unitTarget, 47633, &bp, NULL, NULL, true); - } - else - { - int32 bp = damage; - m_caster->CastCustomSpell(unitTarget, 47632, &bp, NULL, NULL, true); - } - return; - } - // Hungering Cold - if (m_spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_DK_HUNGERING_COLD) - { - unitTarget->CastSpell(m_caster, 51209, true); - return; - } - // Death Grip - if (m_spellInfo->Id == 49560) - { - Position pos; - GetSummonPosition(i, pos); - if (Unit *unit = unitTarget->GetVehicleBase()) // what is this for? - unit->CastSpell(pos.GetPositionX(),pos.GetPositionY(),pos.GetPositionZ(),damage,true); - else - unitTarget->CastSpell(pos.GetPositionX(),pos.GetPositionY(),pos.GetPositionZ(),damage,true); - return; - } - else if (m_spellInfo->Id == 46584) // Raise dead - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - // Do we have talent Master of Ghouls? - if (m_caster->HasAura(52143)) - // summon as pet - bp = 52150; - else - // or guardian - bp = 46585; - - if (m_targets.HasDst()) - { - targets.setDst(&m_targets.m_dstPos); - } - else - { - targets.setDst(m_caster); - // Corpse not found - take reagents (only not triggered cast can take them) - triggered = false; - } - // Remove cooldown - summon spellls have category - m_caster->ToPlayer()->RemoveSpellCooldown(m_spellInfo->Id,true); - spell_id=48289; - } - // Raise dead - take reagents and trigger summon spells - else if (m_spellInfo->Id == 48289) - { - if (m_targets.HasDst()) - targets.setDst(&m_targets.m_dstPos); - - spell_id = CalculateDamage(0, NULL); - } - // Corpse Explosion - else if (m_spellInfo->SpellIconID == 1737) - { - // Dummy effect 1 is used only for targeting and damage amount - if (i != 0) - return; - int32 bp = 0; - // Living ghoul as a target - if (unitTarget->isAlive()) - { - bp = unitTarget->GetMaxHealth()*0.25f; - } - // Some corpse - else - { - bp = damage; - } - m_caster->CastCustomSpell(unitTarget, SpellMgr::CalculateSpellEffectAmount(m_spellInfo, 1), &bp,NULL,NULL,true); - // Corpse Explosion (Suicide) - unitTarget->CastCustomSpell(unitTarget,43999,&bp,NULL,NULL,true); - // Set corpse look - unitTarget->SetDisplayId(25537+urand(0,3)); - } - // Runic Power Feed (keeping Gargoyle alive) - else if (m_spellInfo->Id == 50524) - { - // No power, dismiss Gargoyle - if (m_caster->GetPower(POWER_RUNIC_POWER)<30) - m_caster->RemoveAurasDueToSpell(50514, m_caster->GetGUID()); - else - m_caster->ModifyPower(POWER_RUNIC_POWER,-30); - - return; - } - break; - } - - //spells triggered by dummy effect should not miss - if (spell_id) - { - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); - - if (!spellInfo) - { - sLog.outError("EffectDummy of spell %u: triggering unknown spell id %i\n", m_spellInfo->Id, spell_id); - return; - } - - targets.setUnitTarget(unitTarget); - Spell* spell = new Spell(m_caster, spellInfo, triggered, m_originalCasterGUID, NULL, true); - if (bp) spell->m_currentBasePoints[0] = SpellMgr::CalculateSpellEffectBaseAmount(bp); - spell->prepare(&targets); - } - - // pet auras - if (PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id,i)) - { - m_caster->AddPetAura(petSpell); - return; - } - - // Script based implementation. Must be used only for not good for implementation in core spell effects - // So called only for not proccessed cases - if (gameObjTarget) - sScriptMgr.EffectDummyGameObj(m_caster, m_spellInfo->Id, i, gameObjTarget); - else if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT) - sScriptMgr.EffectDummyCreature(m_caster, m_spellInfo->Id, i, unitTarget->ToCreature()); - else if (itemTarget) - sScriptMgr.EffectDummyItem(m_caster, m_spellInfo->Id, i, itemTarget); -} - -void Spell::EffectTriggerSpellWithValue(uint32 i) -{ - uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i]; - - // normal case - SpellEntry const *spellInfo = sSpellStore.LookupEntry(triggered_spell_id); - - if (!spellInfo) - { - sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id); - return; - } - - int32 bp = damage; - Unit * caster = GetTriggeredSpellCaster(spellInfo, m_caster, unitTarget); - - caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true); -} - -void Spell::EffectTriggerRitualOfSummoning(uint32 i) -{ - uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i]; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(triggered_spell_id); - - if (!spellInfo) - { - sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id); - return; - } - - finish(); - - m_caster->CastSpell(unitTarget,spellInfo,false); -} - -void Spell::EffectForceCast(uint32 i) -{ - if (!unitTarget) - return; - - uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i]; - - // normal case - SpellEntry const *spellInfo = sSpellStore.LookupEntry(triggered_spell_id); - - if (!spellInfo) - { - sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id); - return; - } - - if (damage) - { - switch(m_spellInfo->Id) - { - case 52588: // Skeletal Gryphon Escape - case 48598: // Ride Flamebringer Cue - unitTarget->RemoveAura(damage); - break; - case 52463: // Hide In Mine Car - case 52349: // Overtake - unitTarget->CastCustomSpell(unitTarget, spellInfo->Id, &damage, NULL, NULL, true, NULL, NULL, m_originalCasterGUID); - return; - //case 72378: // Blood Nova - //case 73058: // Blood Nova - } - } - Unit * caster = GetTriggeredSpellCaster(spellInfo, m_caster, unitTarget); - - caster->CastSpell(unitTarget, spellInfo, true, NULL, NULL, m_originalCasterGUID); -} - -void Spell::EffectForceCastWithValue(uint32 i) -{ - if (!unitTarget) - return; - - uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i]; - - // normal case - SpellEntry const *spellInfo = sSpellStore.LookupEntry(triggered_spell_id); - - if (!spellInfo) - { - sLog.outError("EffectForceCastWithValue of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id); - return; - } - int32 bp = damage; - Unit * caster = GetTriggeredSpellCaster(spellInfo, m_caster, unitTarget); - - caster->CastCustomSpell(unitTarget, spellInfo->Id, &bp, &bp, &bp, true, NULL, NULL, m_originalCasterGUID); -} - - -void Spell::EffectTriggerSpell(uint32 effIndex) -{ - // only unit case known - if (!unitTarget) - { - if (gameObjTarget || itemTarget) - sLog.outError("Spell::EffectTriggerSpell (Spell: %u): Unsupported non-unit case!",m_spellInfo->Id); - return; - } - - uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effIndex]; - Unit* originalCaster = NULL; - - // special cases - switch(triggered_spell_id) - { - // Mirror Image - case 58832: - { - // Glyph of Mirror Image - if (m_caster->HasAura(63093)) - m_caster->CastSpell(m_caster, 65047, true); // Mirror Image - - break; - } - // Vanish (not exist) - case 18461: - { - unitTarget->RemoveMovementImpairingAuras(); - unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STALKED); - - // if this spell is given to NPC it must handle rest by it's own AI - if (unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - // get highest rank of the Stealth spell - uint32 spellId = 0; - SpellEntry const *spellInfo; - const PlayerSpellMap& sp_list = unitTarget->ToPlayer()->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) - { - // only highest rank is shown in spell book, so simply check if shown in spell book - if (!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED) - continue; - - spellInfo = sSpellStore.LookupEntry(itr->first); - if (!spellInfo) - continue; - - if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_STEALTH) - { - spellId = spellInfo->Id; - break; - } - } - - // no Stealth spell found - if (!spellId) - return; - - // reset cooldown on it if needed - if (unitTarget->ToPlayer()->HasSpellCooldown(spellId)) - unitTarget->ToPlayer()->RemoveSpellCooldown(spellId); - - // Push stealth to list because it must be handled after combat remove - m_TriggerSpells.push_back(spellInfo); - return; - } - // Demonic Empowerment -- succubus - case 54437: - { - unitTarget->RemoveMovementImpairingAuras(); - unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STALKED); - unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STUN); - - // Cast Lesser Invisibility - triggered_spell_id = 7870; - break; - } - // just skip - case 23770: // Sayge's Dark Fortune of * - // not exist, common cooldown can be implemented in scripts if need. - return; - // Brittle Armor - (need add max stack of 24575 Brittle Armor) - case 29284: - { - // Brittle Armor - SpellEntry const* spell = sSpellStore.LookupEntry(24575); - if (!spell) - return; - - for (int j=0; j < spell->StackAmount; ++j) - m_caster->CastSpell(unitTarget, spell->Id, true); - return; - } - // Mercurial Shield - (need add max stack of 26464 Mercurial Shield) - case 29286: - { - // Mercurial Shield - SpellEntry const* spell = sSpellStore.LookupEntry(26464); - if (!spell) - return; - - for (int j=0; j < spell->StackAmount; ++j) - m_caster->CastSpell(unitTarget, spell->Id, true); - return; - } - // Righteous Defense - case 31980: - { - m_caster->CastSpell(unitTarget, 31790, true); - return; - } - // Cloak of Shadows - case 35729: - { - uint32 dispelMask = GetDispellMask(DISPEL_ALL); - Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras(); - for (Unit::AuraApplicationMap::iterator iter = Auras.begin(); iter != Auras.end();) - { - // remove all harmful spells on you... - SpellEntry const* spell = iter->second->GetBase()->GetSpellProto(); - if ((spell->DmgClass == SPELL_DAMAGE_CLASS_MAGIC // only affect magic spells - || ((1<Dispel) & dispelMask)) - // ignore positive and passive auras - && !iter->second->IsPositive() && !iter->second->GetBase()->IsPassive()) - { - m_caster->RemoveAura(iter); - } - else - iter++; - } - return; - } - // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet - case 41967: - { - if (Unit *pet = unitTarget->GetGuardianPet()) - pet->CastSpell(pet, 28305, true); - return; - } - // Empower Rune Weapon - case 53258: - return; // skip, hack-added in spell effect - // Snake Trap - case 57879: - originalCaster = m_originalCaster; - break; - } - - // normal case - SpellEntry const *spellInfo = sSpellStore.LookupEntry(triggered_spell_id); - if (!spellInfo) - { - sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id); - return; - } - - // Remove spell cooldown (not category) if spell triggering spell with cooldown and same category - // Needed by freezing arrow and few other spells - if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->CategoryRecoveryTime && spellInfo->CategoryRecoveryTime - && m_spellInfo->Category == spellInfo->Category) - m_caster->ToPlayer()->RemoveSpellCooldown(spellInfo->Id); - - // Note: not exist spells with weapon req. and IsSpellHaveCasterSourceTargets == true - // so this just for speedup places in else - Unit * caster = GetTriggeredSpellCaster(spellInfo, m_caster, unitTarget); - - caster->CastSpell(unitTarget,spellInfo,true, 0, 0, (originalCaster ? originalCaster->GetGUID() : 0)); -} - -void Spell::EffectTriggerMissileSpell(uint32 effect_idx) -{ - uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effect_idx]; - - // normal case - SpellEntry const *spellInfo = sSpellStore.LookupEntry(triggered_spell_id); - - if (!spellInfo) - { - sLog.outError("EffectTriggerMissileSpell of spell %u (eff: %u): triggering unknown spell id %u", - m_spellInfo->Id,effect_idx,triggered_spell_id); - return; - } - - if (m_CastItem) - DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id); - - // Remove spell cooldown (not category) if spell triggering spell with cooldown and same category - // Needed by freezing arrow and few other spells - if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->CategoryRecoveryTime && spellInfo->CategoryRecoveryTime - && m_spellInfo->Category == spellInfo->Category) - m_caster->ToPlayer()->RemoveSpellCooldown(spellInfo->Id); - - float x, y, z; - m_targets.m_dstPos.GetPosition(x, y, z); - m_caster->CastSpell(x, y, z, spellInfo->Id, true, m_CastItem, 0, m_originalCasterGUID); -} - -void Spell::EffectJump(uint32 i) -{ - if (m_caster->isInFlight()) - return; - - float x,y,z,o; - if (m_targets.getUnitTarget()) - { - m_targets.getUnitTarget()->GetContactPoint(m_caster,x,y,z,CONTACT_DISTANCE); - o = m_caster->GetOrientation(); - } - else if (m_targets.getGOTarget()) - { - m_targets.getGOTarget()->GetContactPoint(m_caster,x,y,z,CONTACT_DISTANCE); - o = m_caster->GetOrientation(); - } - else - { - sLog.outError("Spell::EffectJump - unsupported target mode for spell ID %u", m_spellInfo->Id); - return; - } - - float speedXY, speedZ; - CalculateJumpSpeeds(i, m_caster->GetExactDist2d(x, y), speedXY, speedZ); - m_caster->GetMotionMaster()->MoveJump(x, y, z, speedXY, speedZ); -} - -void Spell::EffectJumpDest(uint32 i) -{ - if (m_caster->isInFlight()) - return; - - // Init dest coordinates - float x,y,z,o; - if (m_targets.HasDst()) - { - m_targets.m_dstPos.GetPosition(x, y, z); - - if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_DEST_TARGET_BACK) - { - // explicit cast data from client or server-side cast - // some spell at client send caster - Unit* pTarget = NULL; - if (m_targets.getUnitTarget() && m_targets.getUnitTarget() != m_caster) - pTarget = m_targets.getUnitTarget(); - else if (m_caster->getVictim()) - pTarget = m_caster->getVictim(); - else if (m_caster->GetTypeId() == TYPEID_PLAYER) - pTarget = ObjectAccessor::GetUnit(*m_caster, m_caster->ToPlayer()->GetSelection()); - - o = pTarget ? pTarget->GetOrientation() : m_caster->GetOrientation(); - } - else - o = m_caster->GetOrientation(); - } - else - { - sLog.outError("Spell::EffectJumpDest - unsupported target mode for spell ID %u", m_spellInfo->Id); - return; - } - - float speedXY, speedZ; - CalculateJumpSpeeds(i, m_caster->GetExactDist2d(x, y), speedXY, speedZ); - m_caster->GetMotionMaster()->MoveJump(x, y, z, speedXY, speedZ); -} - -void Spell::CalculateJumpSpeeds(uint8 i, float dist, float & speedXY, float & speedZ) -{ - if (m_spellInfo->EffectMiscValue[i]) - speedZ = float(m_spellInfo->EffectMiscValue[i])/10; - else if (m_spellInfo->EffectMiscValueB[i]) - speedZ = float(m_spellInfo->EffectMiscValueB[i])/10; - else - speedZ = 10.0f; - speedXY = dist * 10.0f / speedZ; -} - -void Spell::EffectTeleportUnits(uint32 /*i*/) -{ - if (!unitTarget || unitTarget->isInFlight()) - return; - - // Pre effects - uint8 uiMaxSafeLevel = 0; - switch (m_spellInfo->Id) - { - case 48129: // Scroll of Recall - uiMaxSafeLevel = 40; - case 60320: // Scroll of Recall II - if (!uiMaxSafeLevel) - uiMaxSafeLevel = 70; - case 60321: // Scroll of Recal III - if (!uiMaxSafeLevel) - uiMaxSafeLevel = 80; - - if (unitTarget->getLevel() > uiMaxSafeLevel) - { - unitTarget->AddAura(60444,unitTarget); //Apply Lost! Aura - return; - } - break; - } - - // If not exist data for dest location - return - if (!m_targets.HasDst()) - { - sLog.outError("Spell::EffectTeleportUnits - does not have destination for spell ID %u\n", m_spellInfo->Id); - return; - } - - // Init dest coordinates - uint32 mapid = m_targets.m_dstPos.GetMapId(); - if (mapid == MAPID_INVALID) - mapid = unitTarget->GetMapId(); - float x, y, z, orientation; - m_targets.m_dstPos.GetPosition(x, y, z, orientation); - if (!orientation && m_targets.getUnitTarget()) - orientation = m_targets.getUnitTarget()->GetOrientation(); - sLog.outDebug("Spell::EffectTeleportUnits - teleport unit to %u %f %f %f %f\n", mapid, x, y, z, orientation); - - if (mapid == unitTarget->GetMapId()) - unitTarget->NearTeleportTo(x, y, z, orientation, unitTarget == m_caster); - else if (unitTarget->GetTypeId() == TYPEID_PLAYER) - unitTarget->ToPlayer()->TeleportTo(mapid, x, y, z, orientation, unitTarget == m_caster ? TELE_TO_SPELL : 0); - - // post effects for TARGET_DST_DB - switch (m_spellInfo->Id) - { - // Dimensional Ripper - Everlook - case 23442: - { - int32 r = irand(0, 119); - if (r >= 70) // 7/12 success - { - if (r < 100) // 4/12 evil twin - m_caster->CastSpell(m_caster, 23445, true); - else // 1/12 fire - m_caster->CastSpell(m_caster, 23449, true); - } - return; - } - // Ultrasafe Transporter: Toshley's Station - case 36941: - { - if (roll_chance_i(50)) // 50% success - { - int32 rand_eff = urand(1, 7); - switch (rand_eff) - { - case 1: - // soul split - evil - m_caster->CastSpell(m_caster, 36900, true); - break; - case 2: - // soul split - good - m_caster->CastSpell(m_caster, 36901, true); - break; - case 3: - // Increase the size - m_caster->CastSpell(m_caster, 36895, true); - break; - case 4: - // Decrease the size - m_caster->CastSpell(m_caster, 36893, true); - break; - case 5: - // Transform - { - if (m_caster->ToPlayer()->GetTeam() == ALLIANCE) - m_caster->CastSpell(m_caster, 36897, true); - else - m_caster->CastSpell(m_caster, 36899, true); - break; - } - case 6: - // chicken - m_caster->CastSpell(m_caster, 36940, true); - break; - case 7: - // evil twin - m_caster->CastSpell(m_caster, 23445, true); - break; - } - } - return; - } - // Dimensional Ripper - Area 52 - case 36890: - { - if (roll_chance_i(50)) // 50% success - { - int32 rand_eff = urand(1, 4); - switch (rand_eff) - { - case 1: - // soul split - evil - m_caster->CastSpell(m_caster, 36900, true); - break; - case 2: - // soul split - good - m_caster->CastSpell(m_caster, 36901, true); - break; - case 3: - // Increase the size - m_caster->CastSpell(m_caster, 36895, true); - break; - case 4: - // Transform - { - if (m_caster->ToPlayer()->GetTeam() == ALLIANCE) - m_caster->CastSpell(m_caster, 36897, true); - else - m_caster->CastSpell(m_caster, 36899, true); - break; - } - } - } - return; - } - } -} - -void Spell::EffectApplyAura(uint32 i) -{ - if (!m_spellAura || !unitTarget) - return; - assert(unitTarget == m_spellAura->GetOwner()); - m_spellAura->_ApplyEffectForTargets(i); -} - -void Spell::EffectApplyAreaAura(uint32 i) -{ - if (!m_spellAura || !unitTarget) - return; - assert (unitTarget == m_spellAura->GetOwner()); - m_spellAura->_ApplyEffectForTargets(i); -} - -void Spell::EffectUnlearnSpecialization(uint32 i) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - Player *_player = (Player*)unitTarget; - uint32 spellToUnlearn = m_spellInfo->EffectTriggerSpell[i]; - - _player->removeSpell(spellToUnlearn); - - sLog.outDebug("Spell: Player %u has unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow()); -} - -void Spell::EffectPowerDrain(uint32 i) -{ - if (m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) - return; - - Powers drain_power = Powers(m_spellInfo->EffectMiscValue[i]); - - if (!unitTarget) - return; - if (!unitTarget->isAlive()) - return; - if (unitTarget->getPowerType() != drain_power) - return; - if (damage < 0) - return; - - uint32 curPower = unitTarget->GetPower(drain_power); - - //add spell damage bonus - damage=m_caster->SpellDamageBonus(unitTarget,m_spellInfo,uint32(damage),SPELL_DIRECT_DAMAGE); - - // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) - uint32 power = damage; - if (drain_power == POWER_MANA) - power -= unitTarget->GetSpellCritDamageReduction(power); - - int32 new_damage; - if (curPower < power) - new_damage = curPower; - else - new_damage = power; - - unitTarget->ModifyPower(drain_power,-new_damage); - - // Don`t restore from self drain - if (drain_power == POWER_MANA && m_caster != unitTarget) - { - float manaMultiplier = m_spellInfo->EffectMultipleValue[i]; - if (manaMultiplier == 0) - manaMultiplier = 1; - - if (Player *modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier); - - int32 gain = int32(new_damage * manaMultiplier); - - m_caster->EnergizeBySpell(m_caster, m_spellInfo->Id, gain, POWER_MANA); - } -} - -void Spell::EffectSendEvent(uint32 EffectIndex) -{ - /* - we do not handle a flag dropping or clicking on flag in battleground by sendevent system - */ - sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id); - - Object *pTarget; - if (focusObject) - pTarget = focusObject; - else if (unitTarget) - pTarget = unitTarget; - else if (gameObjTarget) - pTarget = gameObjTarget; - else - pTarget = NULL; - - m_caster->GetMap()->ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, pTarget); -} - -void Spell::EffectPowerBurn(uint32 i) -{ - if (m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) - return; - - Powers powertype = Powers(m_spellInfo->EffectMiscValue[i]); - - if (!unitTarget) - return; - if (!unitTarget->isAlive()) - return; - if (unitTarget->getPowerType() != powertype) - return; - if (damage < 0) - return; - - //Unit* caster = m_originalCaster ? m_originalCaster : m_caster; - - // burn x% of target's mana, up to maximum of 2x% of caster's mana (Mana Burn) - if (m_spellInfo->ManaCostPercentage) - { - uint32 maxdamage = m_caster->GetMaxPower(powertype) * damage * 2 / 100; - damage = unitTarget->GetMaxPower(powertype) * damage / 100; - if (damage > maxdamage) damage = maxdamage; - } - - int32 curPower = int32(unitTarget->GetPower(powertype)); - - uint32 power = damage; - // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) - if (powertype == POWER_MANA) - power -= unitTarget->GetSpellCritDamageReduction(power); - - int32 new_damage = (curPower < power) ? curPower : power; - - unitTarget->ModifyPower(powertype, -new_damage); - float multiplier = m_spellInfo->EffectMultipleValue[i]; - - if (Player *modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier); - - new_damage = int32(new_damage*multiplier); - //m_damage+=new_damage; should not apply spell bonus - //TODO: no log - //unitTarget->ModifyHealth(-new_damage); - if (m_originalCaster) - m_originalCaster->DealDamage(unitTarget, new_damage); - - unitTarget->RemoveAurasByType(SPELL_AURA_MOD_FEAR); -} - -void Spell::EffectHeal(uint32 /*i*/) -{ -} - -void Spell::SpellDamageHeal(uint32 /*i*/) -{ - if (unitTarget && unitTarget->isAlive() && damage >= 0) - { - // Try to get original caster - Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster; - - // Skip if m_originalCaster not available - if (!caster) - return; - - int32 addhealth = damage; - - // Vessel of the Naaru (Vial of the Sunwell trinket) - if (m_spellInfo->Id == 45064) - { - // Amount of heal - depends from stacked Holy Energy - int damageAmount = 0; - if (AuraEffect const * aurEff = m_caster->GetAuraEffect(45062, 0)) - { - damageAmount+= aurEff->GetAmount(); - m_caster->RemoveAurasDueToSpell(45062); - } - - addhealth += damageAmount; - } - // Swiftmend - consumes Regrowth or Rejuvenation - else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND, m_spellInfo, m_caster)) - { - Unit::AuraEffectList const& RejorRegr = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_HEAL); - // find most short by duration - AuraEffect *targetAura = NULL; - for (Unit::AuraEffectList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i) - { - if ((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID - && (*i)->GetSpellProto()->SpellFamilyFlags[0] & 0x50) - { - if (!targetAura || (*i)->GetBase()->GetDuration() < targetAura->GetBase()->GetDuration()) - targetAura = *i; - } - } - - if (!targetAura) - { - sLog.outError("Target(GUID:" UI64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID()); - return; - } - - int32 tickheal = targetAura->GetAmount(); - if (Unit* auraCaster = targetAura->GetCaster()) - tickheal = auraCaster->SpellHealingBonus(unitTarget, targetAura->GetSpellProto(), tickheal, DOT); - //int32 tickheal = targetAura->GetSpellProto()->EffectBasePoints[idx] + 1; - //It is said that talent bonus should not be included - - int32 tickcount = 0; - // Rejuvenation - if (targetAura->GetSpellProto()->SpellFamilyFlags[0] & 0x10) - tickcount = 4; - // Regrowth - else // if (targetAura->GetSpellProto()->SpellFamilyFlags[0] & 0x40) - tickcount = 6; - - addhealth += tickheal * tickcount; - - // Glyph of Swiftmend - if (!caster->HasAura(54824)) - unitTarget->RemoveAura(targetAura->GetId(), targetAura->GetCasterGUID()); - - //addhealth += tickheal * tickcount; - //addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget); - } - // Glyph of Nourish - else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags[1] & 0x2000000) - { - addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL); - - if (AuraEffect const* aurEff = m_caster->GetAuraEffect(62971, 0)) - { - Unit::AuraEffectList const& Periodic = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_HEAL); - for (Unit::AuraEffectList::const_iterator i = Periodic.begin(); i != Periodic.end(); ++i) - { - if (m_caster->GetGUID() == (*i)->GetCasterGUID()) - addhealth += addhealth * aurEff->GetAmount() / 100; - } - } - } - // Riptide - increase healing done by Chain Heal - else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[0] & 0x100) - { - addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL); - if (AuraEffect * aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_SHAMAN, 0, 0, 0x10, m_originalCasterGUID)) - { - addhealth *= 1.25f; - // consume aura - unitTarget->RemoveAura(aurEff->GetBase()); - } - } - // Death Pact - return pct of max health to caster - else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000) - addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, int32(caster->GetMaxHealth() * damage / 100.0f), HEAL); - else - addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL); - - // Remove Grievious bite if fully healed - if (unitTarget->HasAura(48920) && (unitTarget->GetHealth() + addhealth >= unitTarget->GetMaxHealth())) - unitTarget->RemoveAura(48920); - - m_damage -= addhealth; - } -} - -void Spell::EffectHealPct(uint32 /*i*/) -{ - if (unitTarget && unitTarget->isAlive() && damage >= 0) - { - // Try to get original caster - Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster; - - // Skip if m_originalCaster not available - if (!caster) - return; - - // Rune Tap - Party - if (m_spellInfo->Id == 59754 && unitTarget == m_caster) - return; - - uint32 addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, unitTarget->GetMaxHealth() * damage / 100.0f, HEAL); - //if (Player *modOwner = m_caster->GetSpellModOwner()) - // modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DAMAGE, addhealth, this); - - int32 gain = caster->DealHeal(unitTarget, addhealth, m_spellInfo); - unitTarget->getHostileRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo); - } -} - -void Spell::EffectHealMechanical(uint32 /*i*/) -{ - // Mechanic creature type should be correctly checked by targetCreatureType field - if (unitTarget && unitTarget->isAlive() && damage >= 0) - { - // Try to get original caster - Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster; - - // Skip if m_originalCaster not available - if (!caster) - return; - - uint32 addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, uint32(damage), HEAL); - caster->DealHeal(unitTarget, addhealth, m_spellInfo); - } -} - -void Spell::EffectHealthLeech(uint32 i) -{ - if (!unitTarget) - return; - if (!unitTarget->isAlive()) - return; - - if (damage < 0) - return; - - sLog.outDebug("HealthLeech :%i", damage); - - float multiplier = m_spellInfo->EffectMultipleValue[i]; - - if (Player *modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier); - - // Do not apply multiplier to damage if it's Death Coil - int32 new_damage; - if (m_spellInfo->SpellFamilyFlags[0] & 0x80000) - new_damage = damage; - else - new_damage = int32(damage*multiplier); - uint32 curHealth = unitTarget->GetHealth(); - new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage); - if (curHealth < new_damage) - new_damage = curHealth; - - if (m_caster->isAlive()) - { - // Insead add it just to healing if it's Death Coil - if (m_spellInfo->SpellFamilyFlags[0] & 0x80000) - new_damage = int32(new_damage*multiplier); - new_damage = m_caster->SpellHealingBonus(m_caster, m_spellInfo, new_damage, HEAL); - m_caster->DealHeal(m_caster, uint32(new_damage), m_spellInfo); - } -// m_healthLeech+=tmpvalue; -// m_damage+=new_damage; -} - -void Spell::DoCreateItem(uint32 /*i*/, uint32 itemtype) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - Player* player = (Player*)unitTarget; - - uint32 newitemid = itemtype; - ItemPrototype const *pProto = objmgr.GetItemPrototype(newitemid); - if (!pProto) - { - player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - // bg reward have some special in code work - uint32 bgType = 0; - switch(m_spellInfo->Id) - { - case SPELL_AV_MARK_WINNER: - case SPELL_AV_MARK_LOSER: - bgType = BATTLEGROUND_AV; - break; - case SPELL_WS_MARK_WINNER: - case SPELL_WS_MARK_LOSER: - bgType = BATTLEGROUND_WS; - break; - case SPELL_AB_MARK_WINNER: - case SPELL_AB_MARK_LOSER: - bgType = BATTLEGROUND_AB; - break; - default: - break; - } - - uint32 num_to_add = damage; - - if (num_to_add < 1) - num_to_add = 1; - if (num_to_add > pProto->GetMaxStackSize()) - num_to_add = pProto->GetMaxStackSize(); - - // init items_count to 1, since 1 item will be created regardless of specialization - int items_count=1; - // the chance to create additional items - float additionalCreateChance=0.0f; - // the maximum number of created additional items - uint8 additionalMaxNum=0; - // get the chance and maximum number for creating extra items - if (canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum)) - { - // roll with this chance till we roll not to create or we create the max num - while (roll_chance_f(additionalCreateChance) && items_count <= additionalMaxNum) - ++items_count; - } - - // really will be created more items - num_to_add *= items_count; - - // can the player store the new item? - ItemPosCountVec dest; - uint32 no_space = 0; - uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space); - if (msg != EQUIP_ERR_OK) - { - // convert to possible store amount - if (msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS) - num_to_add -= no_space; - else - { - // if not created by another reason from full inventory or unique items amount limitation - player->SendEquipError(msg, NULL, NULL); - return; - } - } - - if (num_to_add) - { - // create the new item and store it - Item* pItem = player->StoreNewItem(dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid)); - - // was it successful? return error if not - if (!pItem) - { - player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - // set the "Crafted by ..." property of the item - if (pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST && newitemid != 6265 && newitemid != 6948) - pItem->SetUInt32Value(ITEM_FIELD_CREATOR, player->GetGUIDLow()); - - // send info to the client - if (pItem) - player->SendNewItem(pItem, num_to_add, true, bgType == 0); - - // we succeeded in creating at least one item, so a levelup is possible - if (bgType == 0) - player->UpdateCraftSkill(m_spellInfo->Id); - } - -/* - // for battleground marks send by mail if not add all expected - if (no_space > 0 && bgType) - { - if (BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(BattleGroundTypeId(bgType))) - bg->SendRewardMarkByMail(player, newitemid, no_space); - } -*/ -} - -void Spell::EffectCreateItem(uint32 i) -{ - DoCreateItem(i,m_spellInfo->EffectItemType[i]); -} - -void Spell::EffectCreateItem2(uint32 i) -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - Player* player = (Player*)m_caster; - - uint32 item_id = m_spellInfo->EffectItemType[i]; - - if (item_id) - DoCreateItem(i, item_id); - - // special case: fake item replaced by generate using spell_loot_template - if (IsLootCraftingSpell(m_spellInfo)) - { - if (item_id) - { - if (!player->HasItemCount(item_id, 1)) - return; - - // remove reagent - uint32 count = 1; - player->DestroyItemCount(item_id, count, true); - - // create some random items - player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell); - } - else - player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell); // create some random items - } -} - -void Spell::EffectCreateRandomItem(uint32 /*i*/) -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - Player* player = (Player*)m_caster; - - // create some random items - player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell); -} - -void Spell::EffectPersistentAA(uint32 i) -{ - if (!m_spellAura) - { - float radius = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - if (Player* modOwner = m_originalCaster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius); - - Unit *caster = m_caster->GetEntry() == WORLD_TRIGGER ? m_originalCaster : m_caster; - // Caster not in world, might be spell triggered from aura removal - if (!caster->IsInWorld()) - return; - DynamicObject* dynObj = new DynamicObject; - if (!dynObj->Create(objmgr.GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), caster, m_spellInfo->Id, m_targets.m_dstPos, radius, false)) - { - delete dynObj; - return; - } - caster->AddDynObject(dynObj); - dynObj->GetMap()->Add(dynObj); - - if (Aura * aura = Aura::TryCreate(m_spellInfo, dynObj, caster, &m_currentBasePoints[0])) - m_spellAura = aura; - else - { - assert(false); - return; - } - m_spellAura->_RegisterForTargets(); - } - assert(m_spellAura->GetDynobjOwner()); - m_spellAura->_ApplyEffectForTargets(i); -} - -void Spell::EffectEnergize(uint32 i) -{ - if (!unitTarget) - return; - if (!unitTarget->isAlive()) - return; - - if (m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) - return; - - Powers power = Powers(m_spellInfo->EffectMiscValue[i]); - - // Some level depends spells - int level_multiplier = 0; - int level_diff = 0; - switch (m_spellInfo->Id) - { - case 9512: // Restore Energy - level_diff = m_caster->getLevel() - 40; - level_multiplier = 2; - break; - case 24571: // Blood Fury - level_diff = m_caster->getLevel() - 60; - level_multiplier = 10; - break; - case 24532: // Burst of Energy - level_diff = m_caster->getLevel() - 60; - level_multiplier = 4; - break; - case 31930: // Judgements of the Wise - case 63375: // Improved Stormstrike - case 68082: // Glyph of Seal of Command - damage = damage * unitTarget->GetCreateMana() / 100; - break; - case 48542: // Revitalize - damage = damage * unitTarget->GetMaxPower(power) / 100; - break; - default: - break; - } - - if (level_diff > 0) - damage -= level_multiplier * level_diff; - - if (damage < 0) - return; - - if (unitTarget->GetMaxPower(power) == 0) - return; - - m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, damage, power); - - // Mad Alchemist's Potion - if (m_spellInfo->Id == 45051) - { - // find elixirs on target - bool guardianFound = false; - bool battleFound = false; - Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras(); - for (Unit::AuraApplicationMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr) - { - uint32 spell_id = itr->second->GetBase()->GetId(); - if (!guardianFound) - if (spellmgr.IsSpellMemberOfSpellGroup(spell_id, SPELL_GROUP_ELIXIR_GUARDIAN)) - guardianFound = true; - if (!battleFound) - if (spellmgr.IsSpellMemberOfSpellGroup(spell_id, SPELL_GROUP_ELIXIR_BATTLE)) - battleFound = true; - if (battleFound && guardianFound) - break; - } - - // get all available elixirs by mask and spell level - std::set avalibleElixirs; - if (!guardianFound) - spellmgr.GetSetOfSpellsInSpellGroup(SPELL_GROUP_ELIXIR_GUARDIAN, avalibleElixirs); - if (!battleFound) - spellmgr.GetSetOfSpellsInSpellGroup(SPELL_GROUP_ELIXIR_BATTLE, avalibleElixirs); - for (std::set::iterator itr = avalibleElixirs.begin(); itr != avalibleElixirs.end() ;) - { - SpellEntry const *spellInfo = sSpellStore.LookupEntry(*itr); - if (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel()) - avalibleElixirs.erase(itr++); - else if (spellmgr.IsSpellMemberOfSpellGroup(*itr, SPELL_GROUP_ELIXIR_SHATTRATH)) - avalibleElixirs.erase(itr++); - else if (spellmgr.IsSpellMemberOfSpellGroup(*itr, SPELL_GROUP_ELIXIR_UNSTABLE)) - avalibleElixirs.erase(itr++); - else - ++itr; - } - - if (!avalibleElixirs.empty()) - { - // cast random elixir on target - uint32 rand_spell = urand(0,avalibleElixirs.size()-1); - std::set::iterator itr = avalibleElixirs.begin(); - std::advance(itr, rand_spell); - m_caster->CastSpell(unitTarget,*itr,true,m_CastItem); - } - } -} - -void Spell::EffectEnergizePct(uint32 i) -{ - if (!unitTarget) - return; - if (!unitTarget->isAlive()) - return; - - if (m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) - return; - - Powers power = Powers(m_spellInfo->EffectMiscValue[i]); - - uint32 maxPower = unitTarget->GetMaxPower(power); - if (maxPower == 0) - return; - - uint32 gain = damage * maxPower / 100; - m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, gain, power); -} - -void Spell::SendLoot(uint64 guid, LootType loottype) -{ - Player* player = (Player*)m_caster; - if (!player) - return; - - if (gameObjTarget) - { - if (sScriptMgr.GOHello(player, gameObjTarget)) - return; - - switch (gameObjTarget->GetGoType()) - { - case GAMEOBJECT_TYPE_DOOR: - case GAMEOBJECT_TYPE_BUTTON: - gameObjTarget->UseDoorOrButton(); - player->GetMap()->ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget); - return; - - case GAMEOBJECT_TYPE_QUESTGIVER: - // start or end quest - player->PrepareQuestMenu(guid); - player->SendPreparedQuest(guid); - return; - - case GAMEOBJECT_TYPE_SPELL_FOCUS: - // triggering linked GO - if (uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId) - gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster); - return; - - case GAMEOBJECT_TYPE_GOOBER: - gameObjTarget->Use(m_caster); - return; - - case GAMEOBJECT_TYPE_CHEST: - // TODO: possible must be moved to loot release (in different from linked triggering) - if (gameObjTarget->GetGOInfo()->chest.eventId) - { - sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow()); - player->GetMap()->ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget); - } - - // triggering linked GO - if (uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId) - gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster); - - // Don't return, let loots been taken - default: - break; - } - } - - // Send loot - player->SendLoot(guid, loottype); -} - -void Spell::EffectOpenLock(uint32 effIndex) -{ - if (!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER) - { - sLog.outDebug("WORLD: Open Lock - No Player Caster!"); - return; - } - - Player* player = (Player*)m_caster; - - uint32 lockId = 0; - uint64 guid = 0; - - // Get lockId - if (gameObjTarget) - { - GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo(); - // Arathi Basin banner opening ! - if (goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune || - goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK) - { - //CanUseBattleGroundObject() already called in CheckCast() - // in battleground check - if (BattleGround *bg = player->GetBattleGround()) - { - bg->EventPlayerClickedOnFlag(player, gameObjTarget); - return; - } - } - else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND) - { - //CanUseBattleGroundObject() already called in CheckCast() - // in battleground check - if (BattleGround *bg = player->GetBattleGround()) - { - if (bg->GetTypeID(true) == BATTLEGROUND_EY) - bg->EventPlayerClickedOnFlag(player, gameObjTarget); - return; - } - }else if (m_spellInfo->Id == 1842 && gameObjTarget->GetGOInfo()->type == GAMEOBJECT_TYPE_TRAP && gameObjTarget->GetOwner()) - { - gameObjTarget->SetLootState(GO_JUST_DEACTIVATED); - return; - } - // TODO: Add script for spell 41920 - Filling, becouse server it freze when use this spell - // handle outdoor pvp object opening, return true if go was registered for handling - // these objects must have been spawned by outdoorpvp! - else if (gameObjTarget->GetGOInfo()->type == GAMEOBJECT_TYPE_GOOBER && sOutdoorPvPMgr.HandleOpenGo(player, gameObjTarget->GetGUID())) - return; - lockId = goInfo->GetLockId(); - guid = gameObjTarget->GetGUID(); - } - else if (itemTarget) - { - lockId = itemTarget->GetProto()->LockID; - guid = itemTarget->GetGUID(); - } - else - { - sLog.outDebug("WORLD: Open Lock - No GameObject/Item Target!"); - return; - } - - SkillType skillId = SKILL_NONE; - int32 reqSkillValue = 0; - int32 skillValue; - - SpellCastResult res = CanOpenLock(effIndex, lockId, skillId, reqSkillValue, skillValue); - if (res != SPELL_CAST_OK) - { - SendCastResult(res); - return; - } - - SendLoot(guid, LOOT_SKINNING); - - // not allow use skill grow at item base open - if (!m_CastItem && skillId != SKILL_NONE) - { - // update skill if really known - if (uint32 pureSkillValue = player->GetPureSkillValue(skillId)) - { - if (gameObjTarget) - { - // Allow one skill-up until respawned - if (!gameObjTarget->IsInSkillupList(player->GetGUIDLow()) && - player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue)) - gameObjTarget->AddToSkillupList(player->GetGUIDLow()); - } - else if (itemTarget) - { - // Do one skill-up - player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue); - } - } - } -} - -void Spell::EffectSummonChangeItem(uint32 i) -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player *player = (Player*)m_caster; - - // applied only to using item - if (!m_CastItem) - return; - - // ... only to item in own inventory/bank/equip_slot - if (m_CastItem->GetOwnerGUID() != player->GetGUID()) - return; - - uint32 newitemid = m_spellInfo->EffectItemType[i]; - if (!newitemid) - return; - - uint16 pos = m_CastItem->GetPos(); - - Item *pNewItem = Item::CreateItem(newitemid, 1, player); - if (!pNewItem) - return; - - for (uint8 j = PERM_ENCHANTMENT_SLOT; j <= TEMP_ENCHANTMENT_SLOT; ++j) - if (m_CastItem->GetEnchantmentId(EnchantmentSlot(j))) - pNewItem->SetEnchantment(EnchantmentSlot(j), m_CastItem->GetEnchantmentId(EnchantmentSlot(j)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(j)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(j))); - - if (m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)) - { - double loosePercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); - player->DurabilityLoss(pNewItem, loosePercent); - } - - if (player->IsInventoryPos(pos)) - { - ItemPosCountVec dest; - uint8 msg = player->CanStoreItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true); - if (msg == EQUIP_ERR_OK) - { - player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), true); - - // prevent crash at access and unexpected charges counting with item update queue corrupt - if (m_CastItem == m_targets.getItemTarget()) - m_targets.setItemTarget(NULL); - - m_CastItem = NULL; - - player->StoreItem(dest, pNewItem, true); - return; - } - } - else if (player->IsBankPos(pos)) - { - ItemPosCountVec dest; - uint8 msg = player->CanBankItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true); - if (msg == EQUIP_ERR_OK) - { - player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), true); - - // prevent crash at access and unexpected charges counting with item update queue corrupt - if (m_CastItem == m_targets.getItemTarget()) - m_targets.setItemTarget(NULL); - - m_CastItem = NULL; - - player->BankItem(dest, pNewItem, true); - return; - } - } - else if (player->IsEquipmentPos(pos)) - { - uint16 dest; - - player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), true); - - uint8 msg = player->CanEquipItem(m_CastItem->GetSlot(), dest, pNewItem, true); - - if (msg == EQUIP_ERR_OK || msg == EQUIP_ERR_CANT_DO_RIGHT_NOW) - { - if (msg == EQUIP_ERR_CANT_DO_RIGHT_NOW) dest = EQUIPMENT_SLOT_MAINHAND; - - // prevent crash at access and unexpected charges counting with item update queue corrupt - if (m_CastItem == m_targets.getItemTarget()) - m_targets.setItemTarget(NULL); - - m_CastItem = NULL; - - player->EquipItem(dest, pNewItem, true); - player->AutoUnequipOffhandIfNeed(); - return; - } - } - - // fail - delete pNewItem; -} - -void Spell::EffectProficiency(uint32 /*i*/) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - Player *p_target = (Player*)unitTarget; - - uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask; - if (m_spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON && !(p_target->GetWeaponProficiency() & subClassMask)) - { - p_target->AddWeaponProficiency(subClassMask); - p_target->SendProficiency(ITEM_CLASS_WEAPON, p_target->GetWeaponProficiency()); - } - if (m_spellInfo->EquippedItemClass == ITEM_CLASS_ARMOR && !(p_target->GetArmorProficiency() & subClassMask)) - { - p_target->AddArmorProficiency(subClassMask); - p_target->SendProficiency(ITEM_CLASS_ARMOR, p_target->GetArmorProficiency()); - } -} - -void Spell::EffectSummonType(uint32 i) -{ - uint32 entry = m_spellInfo->EffectMiscValue[i]; - if (!entry) - return; - - SummonPropertiesEntry const *properties = sSummonPropertiesStore.LookupEntry(m_spellInfo->EffectMiscValueB[i]); - if (!properties) - { - sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]); - return; - } - - if (!m_originalCaster) - return; - - int32 duration = GetSpellDuration(m_spellInfo); - if (Player* modOwner = m_originalCaster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration); - - Position pos; - GetSummonPosition(i, pos); - - /*//totem must be at same Z in case swimming caster and etc. - if (fabs(z - m_caster->GetPositionZ()) > 5) - z = m_caster->GetPositionZ(); - - uint8 level = m_caster->getLevel(); - - // level of creature summoned using engineering item based at engineering skill level - if (m_caster->GetTypeId() == TYPEID_PLAYER && m_CastItem) - { - ItemPrototype const *proto = m_CastItem->GetProto(); - if (proto && proto->RequiredSkill == SKILL_ENGINERING) - { - uint16 skill202 = m_caster->ToPlayer()->GetSkillValue(SKILL_ENGINERING); - if (skill202) - level = skill202/5; - } - }*/ - - TempSummon *summon = NULL; - - switch (properties->Category) - { - default: - if (properties->Flags & 512) - { - SummonGuardian(i, entry, properties); - break; - } - switch (properties->Type) - { - case SUMMON_TYPE_PET: - case SUMMON_TYPE_GUARDIAN: - case SUMMON_TYPE_GUARDIAN2: - case SUMMON_TYPE_MINION: - SummonGuardian(i, entry, properties); - break; - case SUMMON_TYPE_VEHICLE: - case SUMMON_TYPE_VEHICLE2: - if (m_originalCaster) - summon = m_caster->GetMap()->SummonCreature(entry, pos, properties, duration, m_originalCaster); - break; - case SUMMON_TYPE_TOTEM: - { - summon = m_caster->GetMap()->SummonCreature(entry, pos, properties, duration, m_originalCaster); - if (!summon || !summon->isTotem()) - return; - - if (damage) // if not spell info, DB values used - { - summon->SetMaxHealth(damage); - summon->SetHealth(damage); - } - - //summon->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id); - - if (m_originalCaster->GetTypeId() == TYPEID_PLAYER - && properties->Slot >= SUMMON_SLOT_TOTEM - && properties->Slot < MAX_TOTEM_SLOT) - { - //summon->SendUpdateToPlayerm_originalCaster->ToPlayer(); - WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4); - data << uint8(properties->Slot-1); - data << uint64(m_originalCaster->GetGUID()); - data << uint32(duration); - data << uint32(m_spellInfo->Id); - m_originalCaster->ToPlayer()->SendDirectMessage(&data); - } - break; - } - case SUMMON_TYPE_MINIPET: - { - summon = m_caster->GetMap()->SummonCreature(entry, pos, properties, duration, m_originalCaster); - if (!summon || !summon->HasUnitTypeMask(UNIT_MASK_MINION)) - return; - - //summon->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as summon... - summon->SelectLevel(summon->GetCreatureInfo()); // some summoned creaters have different from 1 DB data for level/hp - summon->SetUInt32Value(UNIT_NPC_FLAGS, summon->GetCreatureInfo()->npcflag); - - summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - summon->AI()->EnterEvadeMode(); - - std::string name = m_originalCaster->GetName(); - name.append(petTypeSuffix[3]); - summon->SetName(name); - break; - } - default: - { - float radius = GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - - int32 amount = damage > 0 ? damage : 1; - if (m_spellInfo->Id == 18662) // Curse of Doom - amount = 1; - - for (uint32 count = 0; count < amount; ++count) - { - GetSummonPosition(i, pos, radius, count); - - TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN; - - summon = m_originalCaster->SummonCreature(entry, pos, summonType, duration); - if (!summon) - continue; - if (properties->Category == SUMMON_CATEGORY_ALLY) - { - summon->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_originalCaster->GetGUID()); - summon->setFaction(m_originalCaster->getFaction()); - summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); - } - } - break; - } - }//switch - break; - case SUMMON_CATEGORY_PET: - SummonGuardian(i, entry, properties); - break; - case SUMMON_CATEGORY_PUPPET: - summon = m_caster->GetMap()->SummonCreature(entry, pos, properties, duration, m_originalCaster); - break; - case SUMMON_CATEGORY_VEHICLE: - { - float x, y, z; - m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE); - summon = m_caster->GetMap()->SummonCreature(entry, pos, properties, duration, m_caster); - if (!summon || !summon->IsVehicle()) - return; - - if (m_spellInfo->EffectBasePoints[i]) - { - SpellEntry const *spellProto = sSpellStore.LookupEntry(SpellMgr::CalculateSpellEffectAmount(m_spellInfo, i)); - if (spellProto) - m_caster->CastSpell(summon, spellProto, true); - } - - m_caster->EnterVehicle(summon->GetVehicleKit()); - break; - } - } - - if (summon) - { - summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); - summon->SetCreatorGUID(m_originalCaster->GetGUID()); - } -} - -void Spell::EffectLearnSpell(uint32 i) -{ - if (!unitTarget) - return; - - if (unitTarget->GetTypeId() != TYPEID_PLAYER) - { - if (m_caster->GetTypeId() == TYPEID_PLAYER) - EffectLearnPetSpell(i); - - return; - } - - Player *player = (Player*)unitTarget; - - uint32 spellToLearn = (m_spellInfo->Id == 483 || m_spellInfo->Id == 55884) ? damage : m_spellInfo->EffectTriggerSpell[i]; - player->learnSpell(spellToLearn, false); - - sLog.outDebug("Spell: Player %u has learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow()); -} - -typedef std::list< std::pair > DispelList; -typedef std::list< std::pair > DispelChargesList; -void Spell::EffectDispel(uint32 i) -{ - if (!unitTarget) - return; - - DispelChargesList dispel_list; - - // Create dispel mask by dispel type - uint32 dispel_type = m_spellInfo->EffectMiscValue[i]; - uint32 dispelMask = GetDispellMask(DispelType(dispel_type)); - Unit::AuraMap const& auras = unitTarget->GetOwnedAuras(); - for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - { - Aura * aura = itr->second; - AuraApplication * aurApp = aura->GetApplicationOfTarget(unitTarget->GetGUID()); - if (!aurApp) - continue; - - if ((1<GetSpellProto()->Dispel) & dispelMask) - { - if (aura->GetSpellProto()->Dispel == DISPEL_MAGIC) - { - bool positive = aurApp->IsPositive() ? (!(aura->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)) : false; - - // do not remove positive auras if friendly target - // negative auras if non-friendly target - if (positive == unitTarget->IsFriendlyTo(m_caster)) - continue; - } - - // The charges / stack amounts don't count towards the total number of auras that can be dispelled. - // Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell - // Polymorph instead of 1 / (5 + 1) -> 16%. - bool dispel_charges = aura->GetSpellProto()->AttributesEx7 & SPELL_ATTR_EX7_DISPEL_CHARGES; - uint8 charges = dispel_charges ? aura->GetCharges() : aura->GetStackAmount(); - if (charges > 0) - dispel_list.push_back(std::make_pair(aura, charges)); - } - } - - if (dispel_list.empty()) - return; - - // Ok if exist some buffs for dispel try dispel it - uint32 failCount = 0; - DispelList success_list; - WorldPacket dataFail(SMSG_DISPEL_FAILED, 8+8+4+4+damage*4); - // dispel N = damage buffs (or while exist buffs for dispel) - for (int32 count = 0; count < damage && !dispel_list.empty();) - { - // Random select buff for dispel - DispelChargesList::iterator itr = dispel_list.begin(); - std::advance(itr, urand(0, dispel_list.size() - 1)); - - bool success = false; - // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance." - if (!GetDispelChance(itr->first->GetCaster(), unitTarget, itr->first->GetId(), !unitTarget->IsFriendlyTo(m_caster), &success)) - { - dispel_list.erase(itr); - continue; - } - else - { - if (success) - { - success_list.push_back(std::make_pair(itr->first->GetId(), itr->first->GetCasterGUID())); - --itr->second; - if (itr->second <= 0) - dispel_list.erase(itr); - } - else - { - if (!failCount) - { - // Failed to dispell - dataFail << uint64(m_caster->GetGUID()); // Caster GUID - dataFail << uint64(unitTarget->GetGUID()); // Victim GUID - dataFail << uint32(m_spellInfo->Id); // dispel spell id - } - ++failCount; - dataFail << uint32(itr->first->GetId()); // Spell Id - } - ++count; - } - } - - if (failCount) - m_caster->SendMessageToSet(&dataFail, true); - - if (success_list.empty()) - return; - - WorldPacket dataSuccess(SMSG_SPELLDISPELLOG, 8+8+4+1+4+damage*5); - // Send packet header - dataSuccess.append(unitTarget->GetPackGUID()); // Victim GUID - dataSuccess.append(m_caster->GetPackGUID()); // Caster GUID - dataSuccess << uint32(m_spellInfo->Id); // dispel spell id - dataSuccess << uint8(0); // not used - dataSuccess << uint32(success_list.size()); // count - for (DispelList::iterator itr = success_list.begin(); itr != success_list.end(); ++itr) - { - // Send dispelled spell info - dataSuccess << uint32(itr->first); // Spell Id - dataSuccess << uint8(0); // 0 - dispelled !=0 cleansed - unitTarget->RemoveAurasDueToSpellByDispel(itr->first, itr->second, m_caster); - } - m_caster->SendMessageToSet(&dataSuccess, true); - - // On success dispel - // Devour Magic - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == SPELLCATEGORY_DEVOUR_MAGIC) - { - int32 heal_amount = SpellMgr::CalculateSpellEffectAmount(m_spellInfo, 1); - m_caster->CastCustomSpell(m_caster, 19658, &heal_amount, NULL, NULL, true); - } -} - -void Spell::EffectDualWield(uint32 /*i*/) -{ - unitTarget->SetCanDualWield(true); - if (unitTarget->GetTypeId() == TYPEID_UNIT) - unitTarget->ToCreature()->UpdateDamagePhysical(OFF_ATTACK); -} - -void Spell::EffectPull(uint32 /*i*/) -{ - // TODO: create a proper pull towards distract spell center for distract - sLog.outDebug("WORLD: Spell Effect DUMMY"); -} - -void Spell::EffectDistract(uint32 /*i*/) -{ - // Check for possible target - if (!unitTarget || unitTarget->isInCombat()) - return; - - // target must be OK to do this - if (unitTarget->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING)) - return; - - float angle = unitTarget->GetAngle(&m_targets.m_dstPos); - - if (unitTarget->GetTypeId() == TYPEID_PLAYER) - { - // For players just turn them - unitTarget->ToPlayer()->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false); - unitTarget->ToPlayer()->SendTeleportAckPacket(); - } - else - { - // Set creature Distracted, Stop it, And turn it - unitTarget->SetOrientation(angle); - unitTarget->StopMoving(); - unitTarget->GetMotionMaster()->MoveDistract(damage * IN_MILLISECONDS); - } -} - -void Spell::EffectPickPocket(uint32 /*i*/) -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - // victim must be creature and attackable - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget)) - return; - - // victim have to be alive and humanoid or undead - if (unitTarget->isAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0) - m_caster->ToPlayer()->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING); -} - -void Spell::EffectAddFarsight(uint32 i) -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - float radius = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - int32 duration = GetSpellDuration(m_spellInfo); - // Caster not in world, might be spell triggered from aura removal - if (!m_caster->IsInWorld()) - return; - DynamicObject* dynObj = new DynamicObject; - if (!dynObj->Create(objmgr.GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, m_targets.m_dstPos, radius, true)) - { - delete dynObj; - return; - } - dynObj->SetDuration(duration); - dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002); - m_caster->AddDynObject(dynObj); - - dynObj->setActive(true); //must before add to map to be put in world container - dynObj->GetMap()->Add(dynObj); //grid will also be loaded - - // Need to update visibility of object for client to accept farsight guid - m_caster->ToPlayer()->SetViewpoint(dynObj, true); - //m_caster->ToPlayer()->UpdateVisibilityOf(dynObj); -} - -void Spell::EffectTeleUnitsFaceCaster(uint32 i) -{ - if (!unitTarget) - return; - - if (unitTarget->isInFlight()) - return; - - float dis = m_caster->GetSpellRadiusForTarget(unitTarget, sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - - float fx,fy,fz; - m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis); - - unitTarget->NearTeleportTo(fx,fy,fz,-m_caster->GetOrientation(),unitTarget == m_caster); -} - -void Spell::EffectLearnSkill(uint32 i) -{ - if (unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - if (damage < 0) - return; - - uint32 skillid = m_spellInfo->EffectMiscValue[i]; - uint16 skillval = unitTarget->ToPlayer()->GetPureSkillValue(skillid); - unitTarget->ToPlayer()->SetSkill(skillid, SpellMgr::CalculateSpellEffectAmount(m_spellInfo, i), skillval?skillval:1, damage*75); -} - -void Spell::EffectAddHonor(uint32 /*i*/) -{ - if (unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - // not scale value for item based reward (/10 value expected) - if (m_CastItem) - { - unitTarget->ToPlayer()->RewardHonor(NULL, 1, damage/10); - sLog.outError("SpellEffect::AddHonor (spell_id %u) rewards %d honor points (item %u) for player: %u", m_spellInfo->Id, damage/10, m_CastItem->GetEntry(),unitTarget->ToPlayer()->GetGUIDLow()); - return; - } - - // do not allow to add too many honor for player (50 * 21) = 1040 at level 70, or (50 * 31) = 1550 at level 80 - if (damage <= 50) - { - uint32 honor_reward = Trinity::Honor::hk_honor_at_level(unitTarget->getLevel(), damage); - unitTarget->ToPlayer()->RewardHonor(NULL, 1, honor_reward); - sLog.outDebug("SpellEffect::AddHonor (spell_id %u) rewards %u honor points (scale) to player: %u", m_spellInfo->Id, honor_reward, unitTarget->ToPlayer()->GetGUIDLow()); - } - else - { - //maybe we have correct honor_gain in damage already - unitTarget->ToPlayer()->RewardHonor(NULL, 1, damage); - sLog.outError("SpellEffect::AddHonor (spell_id %u) rewards %u honor points (non scale) for player: %u", m_spellInfo->Id, damage, unitTarget->ToPlayer()->GetGUIDLow()); - } -} - -void Spell::EffectTradeSkill(uint32 /*i*/) -{ - if (unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - // uint32 skillid = m_spellInfo->EffectMiscValue[i]; - // uint16 skillmax = unitTarget->ToPlayer()->(skillid); - // unitTarget->ToPlayer()->SetSkill(skillid,skillval?skillval:1,skillmax+75); -} - -void Spell::EffectEnchantItemPerm(uint32 effect_idx) -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - if (!itemTarget) - return; - - Player* p_caster = (Player*)m_caster; - - // Handle vellums - if (itemTarget->IsWeaponVellum() || itemTarget->IsArmorVellum()) - { - // destroy one vellum from stack - uint32 count = 1; - p_caster->DestroyItemCount(itemTarget,count,true); - unitTarget=p_caster; - // and add a scroll - DoCreateItem(effect_idx,m_spellInfo->EffectItemType[effect_idx]); - itemTarget=NULL; - m_targets.setItemTarget(NULL); - } - else - { - // do not increase skill if vellum used - if (!(m_CastItem && m_CastItem->GetProto()->Flags & ITEM_FLAGS_TRIGGERED_CAST)) - p_caster->UpdateCraftSkill(m_spellInfo->Id); - - uint32 enchant_id = m_spellInfo->EffectMiscValue[effect_idx]; - if (!enchant_id) - return; - - SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if (!pEnchant) - return; - - // item can be in trade slot and have owner diff. from caster - Player* item_owner = itemTarget->GetOwner(); - if (!item_owner) - return; - - if (item_owner != p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) - { - sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)", - p_caster->GetName(),p_caster->GetSession()->GetAccountId(), - itemTarget->GetProto()->Name1,itemTarget->GetEntry(), - item_owner->GetName(),item_owner->GetSession()->GetAccountId()); - } - - // remove old enchanting before applying new if equipped - item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false); - - itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0); - - // add new enchanting if equipped - item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,true); - } -} - -void Spell::EffectEnchantItemPrismatic(uint32 effect_idx) -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - if (!itemTarget) - return; - - Player* p_caster = (Player*)m_caster; - - uint32 enchant_id = m_spellInfo->EffectMiscValue[effect_idx]; - if (!enchant_id) - return; - - SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if (!pEnchant) - return; - - // support only enchantings with add socket in this slot - { - bool add_socket = false; - for (uint8 i = 0; i < 3; ++i) - { - if (pEnchant->type[i] == ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET) - { - add_socket = true; - break; - } - } - if (!add_socket) - { - sLog.outError("Spell::EffectEnchantItemPrismatic: attempt apply enchant spell %u with SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC (%u) but without ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET (%u), not suppoted yet.", - m_spellInfo->Id,SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC,ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET); - return; - } - } - - // item can be in trade slot and have owner diff. from caster - Player* item_owner = itemTarget->GetOwner(); - if (!item_owner) - return; - - if (item_owner != p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) - { - sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)", - p_caster->GetName(),p_caster->GetSession()->GetAccountId(), - itemTarget->GetProto()->Name1,itemTarget->GetEntry(), - item_owner->GetName(),item_owner->GetSession()->GetAccountId()); - } - - // remove old enchanting before applying new if equipped - item_owner->ApplyEnchantment(itemTarget,PRISMATIC_ENCHANTMENT_SLOT,false); - - itemTarget->SetEnchantment(PRISMATIC_ENCHANTMENT_SLOT, enchant_id, 0, 0); - - // add new enchanting if equipped - item_owner->ApplyEnchantment(itemTarget,PRISMATIC_ENCHANTMENT_SLOT,true); -} - -void Spell::EffectEnchantItemTmp(uint32 i) -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player* p_caster = (Player*)m_caster; - - // Rockbiter Weapon apply to both weapon - if (!itemTarget) - return; - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[0] & 0x400000) - { - uint32 spell_id = 0; - - // enchanting spell selected by calculated damage-per-sec stored in Effect[1] base value - // Note: damage calculated (correctly) with rounding int32(float(v)) but - // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime - switch(damage) - { - // Rank 1 - case 2: spell_id = 36744; break; // 0% [ 7% == 2, 14% == 2, 20% == 2] - // Rank 2 - case 4: spell_id = 36753; break; // 0% [ 7% == 4, 14% == 4] - case 5: spell_id = 36751; break; // 20% - // Rank 3 - case 6: spell_id = 36754; break; // 0% [ 7% == 6, 14% == 6] - case 7: spell_id = 36755; break; // 20% - // Rank 4 - case 9: spell_id = 36761; break; // 0% [ 7% == 6] - case 10: spell_id = 36758; break; // 14% - case 11: spell_id = 36760; break; // 20% - default: - sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",damage); - return; - } - - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); - if (!spellInfo) - { - sLog.outError("Spell::EffectEnchantItemTmp: unknown spell id %i", spell_id); - return; - - } - - for (int j = BASE_ATTACK; j <= OFF_ATTACK; ++j) - { - if (Item* item = p_caster->GetWeaponForAttack(WeaponAttackType(j))) - { - if (item->IsFitToSpellRequirements(m_spellInfo)) - { - Spell *spell = new Spell(m_caster, spellInfo, true); - SpellCastTargets targets; - targets.setItemTarget(item); - spell->prepare(&targets); - } - } - } - return; - } - if (!itemTarget) - return; - - uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; - - if (!enchant_id) - { - sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,i); - return; - } - - SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if (!pEnchant) - { - sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo->Id,i,enchant_id); - return; - } - - // select enchantment duration - uint32 duration; - - // rogue family enchantments exception by duration - if (m_spellInfo->Id == 38615) - duration = 1800; // 30 mins - // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints) - else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE) - duration = 3600; // 1 hour - // shaman family enchantments - else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN) - duration = 1800; // 30 mins - // other cases with this SpellVisual already selected - else if (m_spellInfo->SpellVisual[0] == 215) - duration = 1800; // 30 mins - // some fishing pole bonuses except Glow Worm which lasts full hour - else if (m_spellInfo->SpellVisual[0] == 563 && m_spellInfo->Id != 64401) - duration = 600; // 10 mins - // shaman rockbiter enchantments - else if (m_spellInfo->SpellVisual[0] == 0) - duration = 1800; // 30 mins - else if (m_spellInfo->Id == 29702) - duration = 300; // 5 mins - else if (m_spellInfo->Id == 37360) - duration = 300; // 5 mins - // default case - else - duration = 3600; // 1 hour - - // item can be in trade slot and have owner diff. from caster - Player* item_owner = itemTarget->GetOwner(); - if (!item_owner) - return; - - if (item_owner != p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) - { - sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)", - p_caster->GetName(), p_caster->GetSession()->GetAccountId(), - itemTarget->GetProto()->Name1, itemTarget->GetEntry(), - item_owner->GetName(), item_owner->GetSession()->GetAccountId()); - } - - // remove old enchanting before applying new if equipped - item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT, false); - - itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration * 1000, 0); - - // add new enchanting if equipped - item_owner->ApplyEnchantment(itemTarget, TEMP_ENCHANTMENT_SLOT, true); -} - -void Spell::EffectTameCreature(uint32 /*i*/) -{ - if (m_caster->GetPetGUID()) - return; - - if (!unitTarget) - return; - - if (unitTarget->GetTypeId() != TYPEID_UNIT) - return; - - Creature* creatureTarget = unitTarget->ToCreature(); - - if (creatureTarget->isPet()) - return; - - if (m_caster->getClass() != CLASS_HUNTER) - return; - - // cast finish successfully - //SendChannelUpdate(0); - finish(); - - Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget,m_spellInfo->Id); - if (!pet) // in very specific state like near world end/etc. - return; - - // "kill" original creature - creatureTarget->ForcedDespawn(); - - uint8 level = (creatureTarget->getLevel() < (m_caster->getLevel() - 5)) ? (m_caster->getLevel() - 5) : creatureTarget->getLevel(); - - // prepare visual effect for levelup - pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1); - - // add to world - pet->GetMap()->Add(pet->ToCreature()); - - // visual effect for levelup - pet->SetUInt32Value(UNIT_FIELD_LEVEL, level); - - // caster have pet now - m_caster->SetMinion(pet, true); - - pet->InitTalentForLevel(); - - if (m_caster->GetTypeId() == TYPEID_PLAYER) - { - pet->SavePetToDB(PET_SAVE_AS_CURRENT); - m_caster->ToPlayer()->PetSpellInitialize(); - } -} - -void Spell::EffectSummonPet(uint32 i) -{ - Player *owner = NULL; - if (m_originalCaster) - { - if (m_originalCaster->GetTypeId() == TYPEID_PLAYER) - owner = (Player*)m_originalCaster; - else if (m_originalCaster->ToCreature()->isTotem()) - owner = m_originalCaster->GetCharmerOrOwnerPlayerOrPlayerItself(); - } - - uint32 petentry = m_spellInfo->EffectMiscValue[i]; - - if (!owner) - { - SummonPropertiesEntry const *properties = sSummonPropertiesStore.LookupEntry(67); - if (properties) - SummonGuardian(i, petentry, properties); - return; - } - - Pet *OldSummon = owner->GetPet(); - - // if pet requested type already exist - if (OldSummon) - { - if (petentry == 0 || OldSummon->GetEntry() == petentry) - { - // pet in corpse state can't be summoned - if (OldSummon->isDead()) - return; - - assert(OldSummon->GetMap() == owner->GetMap()); - - //OldSummon->GetMap()->Remove(OldSummon->ToCreature(),false); - - float px, py, pz; - owner->GetClosePoint(px, py, pz, OldSummon->GetObjectSize()); - - OldSummon->NearTeleportTo(px, py, pz, OldSummon->GetOrientation()); - //OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation()); - //OldSummon->SetMap(owner->GetMap()); - //owner->GetMap()->Add(OldSummon->ToCreature()); - - if (owner->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled()) - owner->ToPlayer()->PetSpellInitialize(); - - return; - } - - if (owner->GetTypeId() == TYPEID_PLAYER) - owner->ToPlayer()->RemovePet(OldSummon,(OldSummon->getPetType() == HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false); - else - return; - } - - float x, y, z; - owner->GetClosePoint(x, y, z, owner->GetObjectSize()); - Pet* pet = owner->SummonPet(petentry, x, y, z, owner->GetOrientation(), SUMMON_PET, 0); - if (!pet) - return; - - if (m_caster->GetTypeId() == TYPEID_UNIT) - { - if (m_caster->ToCreature()->isTotem()) - pet->SetReactState(REACT_AGGRESSIVE); - else - pet->SetReactState(REACT_DEFENSIVE); - } - - pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); - - // generate new name for summon pet - std::string new_name=objmgr.GeneratePetName(petentry); - if (!new_name.empty()) - pet->SetName(new_name); -} - -void Spell::EffectLearnPetSpell(uint32 i) -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player *_player = (Player*)m_caster; - - Pet *pet = _player->GetPet(); - if (!pet) - return; - if (!pet->isAlive()) - return; - - SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]); - if (!learn_spellproto) - return; - - pet->learnSpell(learn_spellproto->Id); - - pet->SavePetToDB(PET_SAVE_AS_CURRENT); - _player->PetSpellInitialize(); -} - -void Spell::EffectTaunt(uint32 /*i*/) -{ - if (!unitTarget) - return; - - // this effect use before aura Taunt apply for prevent taunt already attacking target - // for spell as marked "non effective at already attacking target" - if (!unitTarget || !unitTarget->CanHaveThreatList() - || unitTarget->getVictim() == m_caster) - { - SendCastResult(SPELL_FAILED_DONT_REPORT); - return; - } - - if (m_spellInfo->Id == 62124) - { - int32 damageDone = 1 + m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.5f; - m_caster->DealDamage(unitTarget, damageDone, NULL, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_HOLY, m_spellInfo, false); - m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damageDone, SPELL_SCHOOL_MASK_HOLY, 0, 0, false, false, false); - } - - // Also use this effect to set the taunter's threat to the taunted creature's highest value - if (unitTarget->getThreatManager().getCurrentVictim()) - { - float myThreat = unitTarget->getThreatManager().getThreat(m_caster); - float itsThreat = unitTarget->getThreatManager().getCurrentVictim()->getThreat(); - if (itsThreat > myThreat) - unitTarget->getThreatManager().addThreat(m_caster, itsThreat - myThreat); - } - - //Set aggro victim to caster - if (!unitTarget->getThreatManager().getOnlineContainer().empty()) - if (HostileReference* forcedVictim = unitTarget->getThreatManager().getOnlineContainer().getReferenceByTarget(m_caster)) - unitTarget->getThreatManager().setCurrentVictim(forcedVictim); - - if (unitTarget->ToCreature()->IsAIEnabled && !unitTarget->ToCreature()->HasReactState(REACT_PASSIVE)) - unitTarget->ToCreature()->AI()->AttackStart(m_caster); -} - -void Spell::EffectWeaponDmg(uint32 /*i*/) -{ -} - -void Spell::SpellDamageWeaponDmg(uint32 i) -{ - if (!unitTarget) - return; - if (!unitTarget->isAlive()) - return; - - // multiple weapon dmg effect workaround - // execute only the last weapon damage - // and handle all effects at once - for (uint32 j = i + 1; j < 3; ++j) - { - switch (m_spellInfo->Effect[j]) - { - case SPELL_EFFECT_WEAPON_DAMAGE: - case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: - case SPELL_EFFECT_NORMALIZED_WEAPON_DMG: - case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: - return; // we must calculate only at last weapon effect - break; - } - } - - // some spell specific modifiers - float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage - int32 fixed_bonus = 0; - int32 spell_bonus = 0; // bonus specific for spell - - switch (m_spellInfo->SpellFamilyName) - { - case SPELLFAMILY_WARRIOR: - { - // Devastate (player ones) - if (m_spellInfo->SpellFamilyFlags[1] & 0x40) - { - // Player can apply only 58567 Sunder Armor effect. - bool needCast = !unitTarget->HasAura(58567, m_caster->GetGUID()); - if (needCast) - m_caster->CastSpell(unitTarget, 58567, true); - - if (Aura * aur = unitTarget->GetAura(58567, m_caster->GetGUID())) - { - // 58388 - Glyph of Devastate dummy aura. - if (int32 num = (needCast ? 0 : 1) + (m_caster->HasAura(58388) ? 1 : 0)) - aur->ModStackAmount(num); - fixed_bonus += (aur->GetStackAmount() - 1) * CalculateDamage(2, unitTarget); - } - } - break; - } - case SPELLFAMILY_ROGUE: - { - // Fan of Knives, Hemorrhage, Ghostly Strike - if ((m_spellInfo->SpellFamilyFlags[1] & 0x40000) - || (m_spellInfo->SpellFamilyFlags[0] & 0x6000000)) - { - // Hemorrhage - if (m_spellInfo->SpellFamilyFlags[0] & 0x2000000) - { - if (m_caster->GetTypeId() == TYPEID_PLAYER) - m_caster->ToPlayer()->AddComboPoints(unitTarget, 1, this); - } - // 50% more damage with daggers - if (m_caster->GetTypeId() == TYPEID_PLAYER) - if (Item* item = m_caster->ToPlayer()->GetWeaponForAttack(m_attackType, true)) - if (item->GetProto()->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER) - totalDamagePercentMod *= 1.5f; - } - // Mutilate (for each hand) - else if (m_spellInfo->SpellFamilyFlags[1] & 0x6) - { - bool found = false; - // fast check - if (unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON, m_spellInfo, m_caster)) - found = true; - // full aura scan - else - { - Unit::AuraApplicationMap const& auras = unitTarget->GetAppliedAuras(); - for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - { - if (itr->second->GetBase()->GetSpellProto()->Dispel == DISPEL_POISON) - { - found = true; - break; - } - } - } - - if (found) - totalDamagePercentMod *= 1.2f; // 120% if poisoned - } - break; - } - case SPELLFAMILY_PALADIN: - { - // Seal of Command - Increase damage by 36% on every swing - if (m_spellInfo->SpellFamilyFlags[0] & 0x2000000) - { - totalDamagePercentMod *= 1.36f; //136% damage - } - - // Seal of Command Unleashed - else if (m_spellInfo->Id == 20467) - { - spell_bonus += int32(0.08f*m_caster->GetTotalAttackPowerValue(BASE_ATTACK)); - spell_bonus += int32(0.13f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo))); - } - break; - } - case SPELLFAMILY_SHAMAN: - { - // Skyshatter Harness item set bonus - // Stormstrike - if (AuraEffect * aurEff = m_caster->IsScriptOverriden(m_spellInfo, 5634)) - m_caster->CastSpell(m_caster, 38430, true, NULL, aurEff); - break; - } - case SPELLFAMILY_DRUID: - { - // Mangle (Cat): CP - if (m_spellInfo->SpellFamilyFlags[1] & 0x400) - { - if (m_caster->GetTypeId() == TYPEID_PLAYER) - m_caster->ToPlayer()->AddComboPoints(unitTarget,1, this); - } - // Shred, Maul - Rend and Tear - else if (m_spellInfo->SpellFamilyFlags[0] & 0x00008800 && unitTarget->HasAuraState(AURA_STATE_BLEEDING)) - { - if (AuraEffect const* rendAndTear = m_caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 2859, 0)) - { - totalDamagePercentMod *= float((rendAndTear->GetAmount() + 100.0f) / 100.0f); - } - } - break; - } - case SPELLFAMILY_HUNTER: - { - // Kill Shot - bonus damage from Ranged Attack Power - if (m_spellInfo->SpellFamilyFlags[1] & 0x800000) - spell_bonus += int32(0.4f*m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)); - break; - } - case SPELLFAMILY_DEATHKNIGHT: - { - // Plague Strike - if (m_spellInfo->SpellFamilyFlags[0] & 0x00000001) - { - // Glyph of Plague Strike - if (AuraEffect * aurEff = m_caster->GetAuraEffect(58657,0)) - totalDamagePercentMod *= float((aurEff->GetAmount() + 100.0f) / 100.0f); - } - // Blood Strike - else if (m_spellInfo->SpellFamilyFlags[0] & 0x400000) - { - totalDamagePercentMod *= (float(unitTarget->GetDiseasesByCaster(m_caster->GetGUID())) * 12.5f + 100.0f) / 100.0f; - - // Glyph of Blood Strike - if (AuraEffect * aurEff = m_caster->GetAuraEffect(59332,0)) - { - if (unitTarget->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED)) - totalDamagePercentMod *= float((20 + 100.0f) / 100.0f); - } - } - // Death Strike - else if (m_spellInfo->SpellFamilyFlags[0] & 0x00000010) - { - // Glyph of Death Strike - if (AuraEffect * aurEff = m_caster->GetAuraEffect(59336,0)) - { - if (uint32 runic = m_caster->GetPower(POWER_RUNIC_POWER)) - { - if (runic > 25) - runic = 25; - - totalDamagePercentMod *= float((runic + 100.0f) / 100.0f); - } - } - } - // Obliterate (12.5% more damage per disease) - else if (m_spellInfo->SpellFamilyFlags[1] & 0x20000) - { - bool consumeDiseases = true; - // Annihilation - if (AuraEffect * aurEff = m_caster->GetDummyAuraEffect(SPELLFAMILY_DEATHKNIGHT, 2710, 0)) - { - // Do not consume diseases if roll sucesses - if (roll_chance_i(aurEff->GetAmount())) - consumeDiseases = false; - } - totalDamagePercentMod *= (float(CalculateDamage(2, unitTarget) * unitTarget->GetDiseasesByCaster(m_caster->GetGUID(), consumeDiseases) / 2) + 100.0f) / 100.0f; - } - // Blood-Caked Strike - Blood-Caked Blade - else if (m_spellInfo->SpellIconID == 1736) - totalDamagePercentMod *= (float(unitTarget->GetDiseasesByCaster(m_caster->GetGUID())) * 12.5f + 100.0f) / 100.0f; - break; - } - } - - bool normalized = false; - float weaponDamagePercentMod = 1.0; - for (int j = 0; j < 3; ++j) - { - switch(m_spellInfo->Effect[j]) - { - case SPELL_EFFECT_WEAPON_DAMAGE: - case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: - fixed_bonus += CalculateDamage(j, unitTarget); - break; - case SPELL_EFFECT_NORMALIZED_WEAPON_DMG: - fixed_bonus += CalculateDamage(j, unitTarget); - normalized = true; - break; - case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: - weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f; - break; - default: - break; // not weapon damage effect, just skip - } - } - - // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage - if (fixed_bonus || spell_bonus) - { - UnitMods unitMod; - switch(m_attackType) - { - default: - case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break; - case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break; - case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break; - } - - float weapon_total_pct = 1.0f; - if (m_spellInfo->SchoolMask & SPELL_SCHOOL_MASK_NORMAL) - weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT); - - if (fixed_bonus) - fixed_bonus = int32(fixed_bonus * weapon_total_pct); - if (spell_bonus) - spell_bonus = int32(spell_bonus * weapon_total_pct); - } - - int32 weaponDamage = m_caster->CalculateDamage(m_attackType, normalized, true); - - // Sequence is important - for (int j = 0; j < 3; ++j) - { - // We assume that a spell have at most one fixed_bonus - // and at most one weaponDamagePercentMod - switch(m_spellInfo->Effect[j]) - { - case SPELL_EFFECT_WEAPON_DAMAGE: - case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: - case SPELL_EFFECT_NORMALIZED_WEAPON_DMG: - weaponDamage += fixed_bonus; - break; - case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: - weaponDamage = int32(weaponDamage * weaponDamagePercentMod); - default: - break; // not weapon damage effect, just skip - } - } - - if (spell_bonus) - weaponDamage += spell_bonus; - - if (totalDamagePercentMod != 1.0f) - weaponDamage = int32(weaponDamage * totalDamagePercentMod); - - // prevent negative damage - uint32 eff_damage = uint32(weaponDamage > 0 ? weaponDamage : 0); - - // Add melee damage bonuses (also check for negative) - m_caster->MeleeDamageBonus(unitTarget, &eff_damage, m_attackType, m_spellInfo); - m_damage+= eff_damage; -} - -void Spell::EffectThreat(uint32 /*i*/) -{ - if (!unitTarget || !unitTarget->isAlive() || !m_caster->isAlive()) - return; - - if (!unitTarget->CanHaveThreatList()) - return; - - unitTarget->AddThreat(m_caster, float(damage)); -} - -void Spell::EffectHealMaxHealth(uint32 /*i*/) -{ - if (!unitTarget) - return; - if (!unitTarget->isAlive()) - return; - - int32 addhealth; - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN) // Lay on Hands - { - if (m_caster && m_caster->GetGUID() == unitTarget->GetGUID()) - { - m_caster->CastSpell(m_caster, 25771, true); // Forbearance - m_caster->CastSpell(m_caster, 61988, true); // Immune shield marker (serverside) - m_caster->CastSpell(m_caster, 61987, true); // Avenging Wrath marker - } - - addhealth = m_caster->GetMaxHealth(); - } - else - addhealth = unitTarget->GetMaxHealth() - unitTarget->GetHealth(); - if (m_originalCaster) - { - addhealth=m_originalCaster->SpellHealingBonus(unitTarget,m_spellInfo, addhealth, HEAL); - m_originalCaster->DealHeal(unitTarget, addhealth, m_spellInfo); - } -} - -void Spell::EffectInterruptCast(uint32 /*i*/) -{ - if (!unitTarget) - return; - if (!unitTarget->isAlive()) - return; - - // TODO: not all spells that used this effect apply cooldown at school spells - // also exist case: apply cooldown to interrupted cast only and to all spells - for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i) - { - if (Spell* spell = unitTarget->GetCurrentSpell(CurrentSpellTypes(i))) - { - SpellEntry const* curSpellInfo = spell->m_spellInfo; - // check if we can interrupt spell - if ((spell->getState() == SPELL_STATE_CASTING - || spell->getState() == SPELL_STATE_PREPARING && spell->GetCastTime() > 0.0f) - && curSpellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && curSpellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE) - { - if (m_originalCaster) - { - int32 duration = m_originalCaster->ModSpellDuration(m_spellInfo, unitTarget, m_originalCaster->CalcSpellDuration(m_spellInfo), false); - unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(curSpellInfo), duration/*GetSpellDuration(m_spellInfo)*/); - } - unitTarget->InterruptSpell(CurrentSpellTypes(i), false); - } - } - } -} - -void Spell::EffectSummonObjectWild(uint32 i) -{ - uint32 gameobject_id = m_spellInfo->EffectMiscValue[i]; - - GameObject* pGameObj = new GameObject; - - WorldObject* target = focusObject; - if (!target) - target = m_caster; - - float x, y, z; - if (m_targets.HasDst()) - m_targets.m_dstPos.GetPosition(x, y, z); - else - m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE); - - Map *map = target->GetMap(); - - if (!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map, - m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) - { - delete pGameObj; - return; - } - - int32 duration = GetSpellDuration(m_spellInfo); - - pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); - pGameObj->SetSpellId(m_spellInfo->Id); - - // Wild object not have owner and check clickable by players - map->Add(pGameObj); - - if (pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP && m_caster->GetTypeId() == TYPEID_PLAYER) - { - Player *pl = m_caster->ToPlayer(); - BattleGround* bg = pl->GetBattleGround(); - - switch(pGameObj->GetMapId()) - { - case 489: //WS - { - if (bg && bg->GetTypeID(true) == BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS) - { - uint32 team = ALLIANCE; - - if (pl->GetTeam() == team) - team = HORDE; - - ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team); - } - break; - } - case 566: //EY - { - if (bg && bg->GetTypeID(true) == BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS) - { - ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID()); - } - break; - } - } - } - - if (uint32 linkedEntry = pGameObj->GetGOInfo()->GetLinkedGameObjectEntry()) - { - GameObject* linkedGO = new GameObject; - if (linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map, - m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) - { - linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); - linkedGO->SetSpellId(m_spellInfo->Id); - - // Wild object not have owner and check clickable by players - map->Add(linkedGO); - } - else - { - delete linkedGO; - linkedGO = NULL; - return; - } - } -} - -void Spell::EffectScriptEffect(uint32 effIndex) -{ - // TODO: we must implement hunter pet summon at login there (spell 6962) - - switch(m_spellInfo->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - { - switch(m_spellInfo->Id) - { - case 6962: - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player* plr = m_caster->ToPlayer(); - if (plr && plr->GetLastPetNumber()) - { - PetType NewPetType = (plr->getClass() == CLASS_HUNTER) ? HUNTER_PET : SUMMON_PET; - if (Pet* NewPet = new Pet(plr,NewPetType)) - { - if (NewPet->LoadPetFromDB(plr, 0, plr->GetLastPetNumber(), true)) - { - NewPet->SetHealth(NewPet->GetMaxHealth()); - NewPet->SetPower(NewPet->getPowerType(),NewPet->GetMaxPower(NewPet->getPowerType())); - - switch (NewPet->GetEntry()) - { - case 11859: - case 89: - NewPet->SetEntry(416); - break; - default: - break; - } - } - else - delete NewPet; - } - } - return; - } - // Glyph of Starfire - case 54846: - { - if (AuraEffect const * aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE,SPELLFAMILY_DRUID,0x00000002,0,0,m_caster->GetGUID())) - { - uint32 countMin = aurEff->GetBase()->GetMaxDuration(); - uint32 countMax = 18000; - countMax += m_caster->HasAura(38414) ? 3000 : 0; - countMax += m_caster->HasAura(57865) ? 3000 : 0; - - if (countMin < countMax) - { - aurEff->GetBase()->SetDuration(uint32(aurEff->GetBase()->GetDuration()+3000)); - aurEff->GetBase()->SetMaxDuration(countMin+3000); - } - } - return; - } - // Glyph of Backstab - case 63975: - { - if (AuraEffect const * aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE,SPELLFAMILY_ROGUE,0x00100000,0,0,m_caster->GetGUID())) - { - uint32 countMin = aurEff->GetBase()->GetMaxDuration(); - uint32 countMax = 12000; - countMax += m_caster->HasAura(56801) ? 4000 : 0; - - if (countMin < countMax) - { - aurEff->GetBase()->SetDuration(uint32(aurEff->GetBase()->GetDuration()+3000)); - aurEff->GetBase()->SetMaxDuration(countMin+2000); - } - - } - return; - } - // Dispelling Analysis - case 37028: - { - unitTarget->RemoveAurasDueToSpell(36904); - return; - } - case 45204: // Clone Me! - case 41055: // Copy Weapon - case 45206: // Copy Off-hand Weapon - unitTarget->CastSpell(m_caster, damage, false); - break; - case 45205: // Copy Offhand Weapon - case 41054: // Copy Weapon - m_caster->CastSpell(unitTarget, damage, false); - break; - // Despawn Horse - case 52267: - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) - return; - unitTarget->ToCreature()->ForcedDespawn(); - return; - } - case 55693: // Remove Collapsing Cave Aura - if (!unitTarget) - return; - unitTarget->RemoveAurasDueToSpell(SpellMgr::CalculateSpellEffectAmount(m_spellInfo, effIndex)); - break; - // PX-238 Winter Wondervolt TRAP - case 26275: - { - uint32 spells[4] = { 26272, 26157, 26273, 26274 }; - - // check presence - for (uint8 j = 0; j < 4; ++j) - if (unitTarget->HasAuraEffect(spells[j],0)) - return; - - // select spell - uint32 iTmpSpellId = spells[urand(0,3)]; - - // cast - unitTarget->CastSpell(unitTarget, iTmpSpellId, true); - return; - } - // Bending Shinbone - case 8856: - { - if (!itemTarget && m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - uint32 spell_id = 0; - switch(urand(1, 5)) - { - case 1: spell_id = 8854; break; - default: spell_id = 8855; break; - } - - m_caster->CastSpell(m_caster,spell_id,true,NULL); - return; - } - // Brittle Armor - need remove one 24575 Brittle Armor aura - case 24590: - unitTarget->RemoveAuraFromStack(24575); - return; - // Mercurial Shield - need remove one 26464 Mercurial Shield aura - case 26465: - unitTarget->RemoveAuraFromStack(26464); - return; - // Orb teleport spells - case 25140: - case 25143: - case 25650: - case 25652: - case 29128: - case 29129: - case 35376: - case 35727: - { - if (!unitTarget) - return; - - uint32 spellid; - switch(m_spellInfo->Id) - { - case 25140: spellid = 32571; break; - case 25143: spellid = 32572; break; - case 25650: spellid = 30140; break; - case 25652: spellid = 30141; break; - case 29128: spellid = 32568; break; - case 29129: spellid = 32569; break; - case 35376: spellid = 25649; break; - case 35727: spellid = 35730; break; - default: - return; - } - - unitTarget->CastSpell(unitTarget,spellid,false); - return; - } - // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell) - case 22539: - case 22972: - case 22975: - case 22976: - case 22977: - case 22978: - case 22979: - case 22980: - case 22981: - case 22982: - case 22983: - case 22984: - case 22985: - { - if (!unitTarget || !unitTarget->isAlive()) - return; - - // Onyxia Scale Cloak - if (unitTarget->HasAura(22683)) - return; - - // Shadow Flame - m_caster->CastSpell(unitTarget, 22682, true); - return; - } - // Piccolo of the Flaming Fire - case 17512: - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE); - return; - } - // Escape artist - case 20589: - { - if (!unitTarget) - return; - unitTarget->RemoveMovementImpairingAuras(); - return; - } - // Decimate - case 28374: - case 54426: - if (unitTarget) - { - int32 damage = (int32)unitTarget->GetHealth() - (int32)unitTarget->GetMaxHealth() * 0.05f; - if (damage > 0) - m_caster->CastCustomSpell(28375, SPELLVALUE_BASE_POINT0, damage, unitTarget); - } - return; - // Mirren's Drinking Hat - case 29830: - { - uint32 item = 0; - switch (urand(1, 6)) - { - case 1: - case 2: - case 3: - item = 23584; break; // Loch Modan Lager - case 4: - case 5: - item = 23585; break; // Stouthammer Lite - case 6: - item = 23586; break; // Aerie Peak Pale Ale - } - if (item) - DoCreateItem(effIndex,item); - break; - } - // Improved Sprint - case 30918: - { - // Removes snares and roots. - unitTarget->RemoveMovementImpairingAuras(); - break; - } - // Spirit Walk - case 58876: - { - // Removes snares and roots. - unitTarget->RemoveMovementImpairingAuras(); - break; - } - // Plant Warmaul Ogre Banner - case 32307: - { - Player *p_caster = dynamic_cast(m_caster); - if (!p_caster) - break; - p_caster->RewardPlayerAndGroupAtEvent(18388, unitTarget); - Creature *cTarget = dynamic_cast(unitTarget); - if (!cTarget) - break; - cTarget->setDeathState(CORPSE); - cTarget->RemoveCorpse(); - break; - } - // Tidal Surge - case 38358: - if (unitTarget) - m_caster->CastSpell(unitTarget, 38353, true); - return; - /*// Flame Crash - case 41126: - { - if (!unitTarget) - return; - - unitTarget->CastSpell(unitTarget, 41131, true); - break; - }*/ - // Draw Soul - case 40904: - { - if (!unitTarget) - return; - - unitTarget->CastSpell(m_caster, 40903, true); - break; - } - case 48025: // Headless Horseman's Mount - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - // Prevent stacking of mounts and client crashes upon dismounting - unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED); - - // Triggered spell id dependent on riding skill and zone - bool canFly = true; - uint32 v_map = GetVirtualMapForMapAndZone(unitTarget->GetMapId(), unitTarget->GetZoneId()); - if (v_map != 530 && v_map != 571) - canFly = false; - - if (canFly && v_map == 571 && !unitTarget->ToPlayer()->HasSpell(54197)) - canFly = false; - - float x, y, z; - unitTarget->GetPosition(x, y, z); - uint32 areaFlag = unitTarget->GetBaseMap()->GetAreaFlag(x, y, z); - AreaTableEntry const *pArea = sAreaStore.LookupEntry(areaFlag); - if (canFly && pArea->flags & AREA_FLAG_NO_FLY_ZONE) - canFly = false; - - switch(unitTarget->ToPlayer()->GetBaseSkillValue(SKILL_RIDING)) - { - case 75: unitTarget->CastSpell(unitTarget, 51621, true); break; - case 150: unitTarget->CastSpell(unitTarget, 48024, true); break; - case 225: - { - if (canFly) - unitTarget->CastSpell(unitTarget, 51617, true); - else - unitTarget->CastSpell(unitTarget, 48024, true); - }break; - case 300: - { - if (canFly) - unitTarget->CastSpell(unitTarget, 48023, true); - else - unitTarget->CastSpell(unitTarget, 48024, true); - }break; - } - return; - } - case 47977: // Magic Broom - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - // Prevent stacking of mounts and client crashes upon dismounting - unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED); - - // Triggered spell id dependent on riding skill and zone - bool canFly = true; - uint32 v_map = GetVirtualMapForMapAndZone(unitTarget->GetMapId(), unitTarget->GetZoneId()); - if (v_map != 530 && v_map != 571) - canFly = false; - - if (canFly && v_map == 571 && !unitTarget->ToPlayer()->HasSpell(54197)) - canFly = false; - - float x, y, z; - unitTarget->GetPosition(x, y, z); - uint32 areaFlag = unitTarget->GetBaseMap()->GetAreaFlag(x, y, z); - AreaTableEntry const *pArea = sAreaStore.LookupEntry(areaFlag); - if (canFly && pArea->flags & AREA_FLAG_NO_FLY_ZONE) - canFly = false; - - switch(unitTarget->ToPlayer()->GetBaseSkillValue(SKILL_RIDING)) - { - case 75: unitTarget->CastSpell(unitTarget, 42680, true); break; - case 150: unitTarget->CastSpell(unitTarget, 42683, true); break; - case 225: - { - if (canFly) - unitTarget->CastSpell(unitTarget, 42667, true); - else - unitTarget->CastSpell(unitTarget, 42683, true); - }break; - case 300: - { - if (canFly) - unitTarget->CastSpell(unitTarget, 42668, true); - else - unitTarget->CastSpell(unitTarget, 42683, true); - }break; - } - return; - } - // Mug Transformation - case 41931: - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - uint8 bag = 19; - uint8 slot = 0; - Item *item = NULL; - - while (bag < 256) - { - item = m_caster->ToPlayer()->GetItemByPos(bag, slot); - if (item && item->GetEntry() == 38587) break; - ++slot; - if (slot == 39) - { - slot = 0; - ++bag; - } - } - if (bag < 256) - { - if (m_caster->ToPlayer()->GetItemByPos(bag,slot)->GetCount() == 1) m_caster->ToPlayer()->RemoveItem(bag,slot,true); - else m_caster->ToPlayer()->GetItemByPos(bag,slot)->SetCount(m_caster->ToPlayer()->GetItemByPos(bag,slot)->GetCount()-1); - // Spell 42518 (Braufest - Gratisprobe des Braufest herstellen) - m_caster->CastSpell(m_caster, 42518, true); - return; - } - break; - } - // Force Cast - Portal Effect: Sunwell Isle - case 44876: - { - if (!unitTarget) - return; - - unitTarget->CastSpell(unitTarget, 44870, true); - break; - } - // Brutallus - Burn - case 45141: - case 45151: - { - //Workaround for Range ... should be global for every ScriptEffect - float radius = GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex])); - if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->GetDistance(m_caster) >= radius && !unitTarget->HasAura(46394) && unitTarget != m_caster) - unitTarget->CastSpell(unitTarget, 46394, true); - - break; - } - // spell of Brutallus - Stomp - case 45185: - { - if (!unitTarget) - return; - - unitTarget->RemoveAurasDueToSpell(46394); - - break; - } - // Negative Energy - case 46289: - { - if (!unitTarget) - return; - - m_caster->CastSpell(unitTarget, 46285, true); - break; - } - // Goblin Weather Machine - case 46203: - { - if (!unitTarget) - return; - - uint32 spellId = 0; - switch(rand() % 4) - { - case 0: spellId = 46740; break; - case 1: spellId = 46739; break; - case 2: spellId = 46738; break; - case 3: spellId = 46736; break; - } - unitTarget->CastSpell(unitTarget, spellId, true); - break; - } - // 5,000 Gold - case 46642: - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - unitTarget->ToPlayer()->ModifyMoney(5000 * GOLD); - - break; - } - // Roll Dice - Decahedral Dwarven Dice - case 47770: - { - char buf[128]; - char *gender = "his"; - if (m_caster->getGender() > 0) - gender = "her"; - sprintf(buf, "%s rubs %s [Decahedral Dwarven Dice] between %s hands and rolls. One %u and one %u.", m_caster->GetName(), gender, gender, urand(1,10), urand(1,10)); - m_caster->MonsterTextEmote(buf, 0); - break; - } - // Roll 'dem Bones - Worn Troll Dice - case 47776: - { - char buf[128]; - char *gender = "his"; - if (m_caster->getGender() > 0) - gender = "her"; - sprintf(buf, "%s causually tosses %s [Worn Troll Dice]. One %u and one %u.", m_caster->GetName(), gender, urand(1,6), urand(1,6)); - m_caster->MonsterTextEmote(buf, 0); - break; - } - // Vigilance - case 50725: - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - // Remove Taunt cooldown - unitTarget->ToPlayer()->RemoveSpellCooldown(355, true); - - return; - } - // Death Knight Initiate Visual - case 51519: - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) - return; - - uint32 iTmpSpellId = 0; - switch (unitTarget->GetDisplayId()) - { - case 25369: iTmpSpellId = 51552; break; // bloodelf female - case 25373: iTmpSpellId = 51551; break; // bloodelf male - case 25363: iTmpSpellId = 51542; break; // draenei female - case 25357: iTmpSpellId = 51541; break; // draenei male - case 25361: iTmpSpellId = 51537; break; // dwarf female - case 25356: iTmpSpellId = 51538; break; // dwarf male - case 25372: iTmpSpellId = 51550; break; // forsaken female - case 25367: iTmpSpellId = 51549; break; // forsaken male - case 25362: iTmpSpellId = 51540; break; // gnome female - case 25359: iTmpSpellId = 51539; break; // gnome male - case 25355: iTmpSpellId = 51534; break; // human female - case 25354: iTmpSpellId = 51520; break; // human male - case 25360: iTmpSpellId = 51536; break; // nightelf female - case 25358: iTmpSpellId = 51535; break; // nightelf male - case 25368: iTmpSpellId = 51544; break; // orc female - case 25364: iTmpSpellId = 51543; break; // orc male - case 25371: iTmpSpellId = 51548; break; // tauren female - case 25366: iTmpSpellId = 51547; break; // tauren male - case 25370: iTmpSpellId = 51545; break; // troll female - case 25365: iTmpSpellId = 51546; break; // troll male - default: return; - } - - unitTarget->CastSpell(unitTarget, iTmpSpellId, true); - Creature* npc = unitTarget->ToCreature(); - npc->LoadEquipment(npc->GetEquipmentId()); - return; - } - // Emblazon Runeblade - case 51770: - { - if (!m_originalCaster) - return; - - m_originalCaster->CastSpell(m_originalCaster, damage, false); - break; - } - // Deathbolt from Thalgran Blightbringer - // reflected by Freya's Ward - // Retribution by Sevenfold Retribution - case 51854: - { - if (!m_caster || !unitTarget) - return; - if (unitTarget->HasAura(51845)) - unitTarget->CastSpell(m_caster, 51856, true); - else - m_caster->CastSpell(unitTarget, 51855, true); - break; - } - // Summon Ghouls On Scarlet Crusade - case 51904: - { - if (!m_targets.HasDst()) - return; - - float x, y, z; - float radius = GetSpellRadius(m_spellInfo, effIndex, true); - for (uint8 i = 0; i < 15; ++i) - { - m_caster->GetRandomPoint(m_targets.m_dstPos, radius, x, y, z); - m_caster->CastSpell(x, y, z, 54522, true); - } - break; - } - case 52173: // Coyote Spirit Despawn - case 60243: // Blood Parrot Despawn - if (unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->ToCreature()->isSummon()) - unitTarget->ToTempSummon()->UnSummon(); - return; - // Sky Darkener Assault - case 52124: - if (unitTarget) - m_caster->CastSpell(unitTarget, 52125, false); - return; - case 52479: // Gift of the Harvester - if (unitTarget && m_originalCaster) - m_originalCaster->CastSpell(unitTarget, urand(0, 1) ? damage : 52505, true); - return; - // Death Gate - case 52751: - { - if (!unitTarget || unitTarget->getClass() != CLASS_DEATH_KNIGHT) - return; - // triggered spell is stored in m_spellInfo->EffectBasePoints[0] - unitTarget->CastSpell(unitTarget, damage, false); - break; - } - case 53110: // Devour Humanoid - if (unitTarget) - unitTarget->CastSpell(m_caster, damage, true); - return; - // Winged Steed of the Ebon Blade - case 54729: - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - // Prevent stacking of mounts and client crashes upon dismounting - unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED); - - // Triggered spell id dependent on riding skill - if (uint16 skillval = unitTarget->ToPlayer()->GetSkillValue(SKILL_RIDING)) - { - if (skillval >= 300) - unitTarget->CastSpell(unitTarget, 54727, true); - else - unitTarget->CastSpell(unitTarget, 54726, true); - } - return; - } - case 58418: // Portal to Orgrimmar - case 58420: // Portal to Stormwind - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || effIndex != 0) - return; - - uint32 spellID = SpellMgr::CalculateSpellEffectAmount(m_spellInfo, 0); - uint32 questID = SpellMgr::CalculateSpellEffectAmount(m_spellInfo, 1); - - if (unitTarget->ToPlayer()->GetQuestStatus(questID) == QUEST_STATUS_COMPLETE && !unitTarget->ToPlayer()->GetQuestRewardStatus (questID)) - unitTarget->CastSpell(unitTarget, spellID, true); - - return; - } - // Gigantic Feast - case 58466: - { - if (!unitTarget) - return; - - unitTarget->CastSpell(unitTarget, 58648, true); - unitTarget->CastSpell(unitTarget, 58467, true); - break; - } - // Small Feast - case 58475: - { - if (!unitTarget) - return; - - unitTarget->CastSpell(unitTarget, 58648, true); - unitTarget->CastSpell(unitTarget, 58477, true); - break; - } - // Great Feast - case 57337: - { - if (!unitTarget) - return; - - unitTarget->CastSpell(unitTarget, 58067, true); - break; - } - //Fish Feast - case 57397: - { - if (!unitTarget) - return; - - unitTarget->CastSpell(unitTarget, 58648, true); - unitTarget->CastSpell(unitTarget, 57398, true); - break; - } - case 58941: // Rock Shards - if (unitTarget && m_originalCaster) - { - for (uint32 i = 0; i < 3; ++i) - { - m_originalCaster->CastSpell(unitTarget, 58689, true); - m_originalCaster->CastSpell(unitTarget, 58692, true); - } - if (((InstanceMap*)m_originalCaster->GetMap())->GetDifficulty() == REGULAR_DIFFICULTY) - { - m_originalCaster->CastSpell(unitTarget, 58695, true); - m_originalCaster->CastSpell(unitTarget, 58696, true); - } - else - { - m_originalCaster->CastSpell(unitTarget, 60883, true); - m_originalCaster->CastSpell(unitTarget, 60884, true); - } - } - return; - case 58983: // Big Blizzard Bear - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - // Prevent stacking of mounts and client crashes upon dismounting - unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED); - - // Triggered spell id dependent on riding skill - if (uint16 skillval = unitTarget->ToPlayer()->GetSkillValue(SKILL_RIDING)) - { - if (skillval >= 150) - unitTarget->CastSpell(unitTarget, 58999, true); - else - unitTarget->CastSpell(unitTarget, 58997, true); - } - return; - } - case 71342: // Big Love Rocket - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - // Prevent stacking of mounts and client crashes upon dismounting - unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED); - - // Triggered spell id dependent on riding skill and zone - bool canFly = true; - uint32 v_map = GetVirtualMapForMapAndZone(unitTarget->GetMapId(), unitTarget->GetZoneId()); - if (v_map != 530 && v_map != 571) - canFly = false; - - if (canFly && v_map == 571 && !unitTarget->ToPlayer()->HasSpell(54197)) - canFly = false; - - float x, y, z; - unitTarget->GetPosition(x, y, z); - uint32 areaFlag = unitTarget->GetBaseMap()->GetAreaFlag(x, y, z); - AreaTableEntry const *pArea = sAreaStore.LookupEntry(areaFlag); - if (canFly && pArea->flags & AREA_FLAG_NO_FLY_ZONE) - canFly = false; - - switch(unitTarget->ToPlayer()->GetBaseSkillValue(SKILL_RIDING)) - { - case 0: unitTarget->CastSpell(unitTarget, 71343, true); break; - case 75: unitTarget->CastSpell(unitTarget, 71344, true); break; - case 150: unitTarget->CastSpell(unitTarget, 71345, true); break; - case 225: - { - if (canFly) - unitTarget->CastSpell(unitTarget, 71346, true); - else - unitTarget->CastSpell(unitTarget, 71345, true); - }break; - case 300: - { - if (canFly) - unitTarget->CastSpell(unitTarget, 71347, true); - else - unitTarget->CastSpell(unitTarget, 71345, true); - }break; - } - return; - } - case 72286: // Invincible - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - // Prevent stacking of mounts and client crashes upon dismounting - unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED); - - // Triggered spell id dependent on riding skill and zone - bool canFly = true; - uint32 v_map = GetVirtualMapForMapAndZone(unitTarget->GetMapId(), unitTarget->GetZoneId()); - if (v_map != 530 && v_map != 571) - canFly = false; - - if (canFly && v_map == 571 && !unitTarget->ToPlayer()->HasSpell(54197)) - canFly = false; - - float x, y, z; - unitTarget->GetPosition(x, y, z); - uint32 areaFlag = unitTarget->GetBaseMap()->GetAreaFlag(x, y, z); - AreaTableEntry const *pArea = sAreaStore.LookupEntry(areaFlag); - if (canFly && pArea->flags & AREA_FLAG_NO_FLY_ZONE) - canFly = false; - - switch(unitTarget->ToPlayer()->GetBaseSkillValue(SKILL_RIDING)) - { - case 75: unitTarget->CastSpell(unitTarget, 72281, true); break; - case 150: unitTarget->CastSpell(unitTarget, 72282, true); break; - case 225: - { - if (canFly) - unitTarget->CastSpell(unitTarget, 72283, true); - else - unitTarget->CastSpell(unitTarget, 72282, true); - }break; - case 300: - { - if (canFly) - unitTarget->CastSpell(unitTarget, 72284, true); - else - unitTarget->CastSpell(unitTarget, 72282, true); - }break; - } - return; - } - case 74856: // Blazing Hippogryph - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - // Prevent stacking of mounts and client crashes upon dismounting - unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED); - - // Triggered spell id dependent on riding skill - if (uint16 skillval = unitTarget->ToPlayer()->GetSkillValue(SKILL_RIDING)) - { - if (skillval >= 300) - unitTarget->CastSpell(unitTarget, 74855, true); - else - unitTarget->CastSpell(unitTarget, 74854, true); - } - return; - } - case 75614: // Celestial Steed - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - // Prevent stacking of mounts and client crashes upon dismounting - unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED); - - // Triggered spell id dependent on riding skill and zone - bool canFly = true; - uint32 v_map = GetVirtualMapForMapAndZone(unitTarget->GetMapId(), unitTarget->GetZoneId()); - if (v_map != 530 && v_map != 571) - canFly = false; - - if (canFly && v_map == 571 && !unitTarget->ToPlayer()->HasSpell(54197)) - canFly = false; - - float x, y, z; - unitTarget->GetPosition(x, y, z); - uint32 areaFlag = unitTarget->GetBaseMap()->GetAreaFlag(x, y, z); - AreaTableEntry const *pArea = sAreaStore.LookupEntry(areaFlag); - if (canFly && pArea->flags & AREA_FLAG_NO_FLY_ZONE) - canFly = false; - - switch(unitTarget->ToPlayer()->GetBaseSkillValue(SKILL_RIDING)) - { - case 75: unitTarget->CastSpell(unitTarget, 75619, true); break; - case 150: unitTarget->CastSpell(unitTarget, 75620, true); break; - case 225: - { - if (canFly) - unitTarget->CastSpell(unitTarget, 75617, true); - else - unitTarget->CastSpell(unitTarget, 75620, true); - }break; - case 300: - { - if (canFly) - { - if (unitTarget->ToPlayer()->Has310Flyer(false)) - unitTarget->CastSpell(unitTarget, 76153, true); - else - unitTarget->CastSpell(unitTarget, 75618, true); - } - else - unitTarget->CastSpell(unitTarget, 75620, true); - }break; - } - return; - } - case 75973: // X-53 Touring Rocket - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - // Prevent stacking of mounts - unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED); - - // Triggered spell id dependent on riding skill - if (uint16 skillval = unitTarget->ToPlayer()->GetSkillValue(SKILL_RIDING)) - { - if (skillval >= 300) - { - if (unitTarget->ToPlayer()->Has310Flyer(false)) - unitTarget->CastSpell(unitTarget, 76154, true); - else - unitTarget->CastSpell(unitTarget, 75972, true); - } - else - unitTarget->CastSpell(unitTarget, 75957, true); - } - return; - } - case 59317: // Teleporting - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - // return from top - if (unitTarget->ToPlayer()->GetAreaId() == 4637) - unitTarget->CastSpell(unitTarget, 59316, true); - // teleport atop - else - unitTarget->CastSpell(unitTarget, 59314, true); - - return; - // random spell learn instead placeholder - case 60893: // Northrend Alchemy Research - case 61177: // Northrend Inscription Research - case 61288: // Minor Inscription Research - case 61756: // Northrend Inscription Research (FAST QA VERSION) - case 64323: // Book of Glyph Mastery - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - // learn random explicit discovery recipe (if any) - if (uint32 discoveredSpell = GetExplicitDiscoverySpell(m_spellInfo->Id, (Player*)m_caster)) - m_caster->ToPlayer()->learnSpell(discoveredSpell, false); - return; - } - case 62428: // Load into Catapult - { - if (Vehicle *seat = m_caster->GetVehicleKit()) - if (Unit *passenger = seat->GetPassenger(0)) - if (Unit *demolisher = m_caster->GetVehicleBase()) - passenger->CastSpell(demolisher, damage, true); - return; - } - case 62482: // Grab Crate - { - if (unitTarget) - { - if (Vehicle *seat = m_caster->GetVehicleKit()) - { - if (Creature *oldContainer = dynamic_cast(seat->GetPassenger(1))) - oldContainer->DisappearAndDie(); - // TODO: a hack, range = 11, should after some time cast, otherwise too far - unitTarget->CastSpell(seat->GetBase(), 62496, true); - unitTarget->EnterVehicle(seat, 1); - } - } - return; - } - case 60123: // Lightwell - { - if (m_caster->GetTypeId() != TYPEID_UNIT || !m_caster->ToCreature()->isSummon()) - return; - - uint32 spell_heal; - - switch(m_caster->GetEntry()) - { - case 31897: spell_heal = 7001; break; - case 31896: spell_heal = 27873; break; - case 31895: spell_heal = 27874; break; - case 31894: spell_heal = 28276; break; - case 31893: spell_heal = 48084; break; - case 31883: spell_heal = 48085; break; - default: - sLog.outError("Unknown Lightwell spell caster %u", m_caster->GetEntry()); - return; - } - Aura * chargesaura = m_caster->GetAura(59907); - - if (chargesaura && chargesaura->GetCharges() > 1) - { - chargesaura->SetCharges(chargesaura->GetCharges() - 1); - m_caster->CastSpell(unitTarget, spell_heal, true, NULL, NULL, m_caster->ToTempSummon()->GetSummonerGUID()); - } - else - m_caster->ToTempSummon()->UnSummon(); - return; - } - // Stoneclaw Totem - case 55328: // Rank 1 - case 55329: // Rank 2 - case 55330: // Rank 3 - case 55332: // Rank 4 - case 55333: // Rank 5 - case 55335: // Rank 6 - case 55278: // Rank 7 - case 58589: // Rank 8 - case 58590: // Rank 9 - case 58591: // Rank 10 - { - int32 basepoints0 = damage; - // Cast Absorb on totems - for (uint8 slot = SUMMON_SLOT_TOTEM; slot < MAX_TOTEM_SLOT; ++slot) - { - if (!unitTarget->m_SummonSlot[slot]) - continue; - - Creature* totem = unitTarget->GetMap()->GetCreature(unitTarget->m_SummonSlot[slot]); - if (totem && totem->isTotem()) - { - m_caster->CastCustomSpell(totem, 55277, &basepoints0, NULL, NULL, true); - } - } - // Glyph of Stoneclaw Totem - if (AuraEffect *aur=unitTarget->GetAuraEffect(63298, 0)) - { - basepoints0 *= aur->GetAmount(); - m_caster->CastCustomSpell(unitTarget, 55277, &basepoints0, NULL, NULL, true); - } - break; - } - case 67751:// Ghoul Explode - { - unitTarget->CastSpell(unitTarget,67729,false); //Explode - break; - } - case 66545: //Summon Memory - { - uint8 uiRandom = urand(0,25); - uint32 uiSpells[26] = {66704,66705,66706,66707,66709,66710,66711,66712,66713,66714,66715,66708,66708,66691,66692,66694,66695,66696,66697,66698,66699,66700,66701,66702,66703,66543}; - - m_caster->CastSpell(m_caster,uiSpells[uiRandom],true); - break; - } - case 45668: // Ultra-Advanced Proto-Typical Shortening Blaster - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) - return; - - if (roll_chance_i(50)) // chance unknown, using 50 - return; - - static uint32 const spellPlayer[5] = - { - 45674, // Bigger! - 45675, // Shrunk - 45678, // Yellow - 45682, // Ghost - 45684 // Polymorph - }; - - static uint32 const spellTarget[5] = { - 45673, // Bigger! - 45672, // Shrunk - 45677, // Yellow - 45681, // Ghost - 45683 // Polymorph - }; - - m_caster->CastSpell(m_caster, spellPlayer[urand(0,4)], true); - unitTarget->CastSpell(unitTarget, spellTarget[urand(0,4)], true); - break; - } - case 64142: // Upper Deck - Create Foam Sword - if (unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - Player *plr = unitTarget->ToPlayer(); - static uint32 const itemId[] = {45061, 45176, 45177, 45178, 45179, 0}; - // player can only have one of these items - for (uint32 const *itr = &itemId[0]; *itr; ++itr) - if (plr->HasItemCount(*itr, 1, true)) - return; - DoCreateItem(effIndex, itemId[urand(0,4)]); - return; - } - break; - } - case SPELLFAMILY_WARLOCK: - { - switch(m_spellInfo->Id) - { - // Healthstone creating spells - case 6201: - case 6202: - case 5699: - case 11729: - case 11730: - case 27230: - case 47871: - case 47878: - { - uint32 itemtype; - uint32 rank = 0; - - // Improved Healthstone - if (AuraEffect const * aurEff = unitTarget->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, 284, 0)) - { - if (aurEff->GetId() == 18692) - rank = 1; - else if (aurEff->GetId() == 18693) - rank = 2; - else - sLog.outError("Unknown rank of Improved Healthstone id: %d", aurEff->GetId()); - } - - static uint32 const itypes[8][3] = { - { 5512, 19004, 19005}, // Minor Healthstone - { 5511, 19006, 19007}, // Lesser Healthstone - { 5509, 19008, 19009}, // Healthstone - { 5510, 19010, 19011}, // Greater Healthstone - { 9421, 19012, 19013}, // Major Healthstone - {22103, 22104, 22105}, // Master Healthstone - {36889, 36890, 36891}, // Demonic Healthstone - {36892, 36893, 36894} // Fel Healthstone - }; - - switch(m_spellInfo->Id) - { - case 6201: - itemtype=itypes[0][rank];break; // Minor Healthstone - case 6202: - itemtype=itypes[1][rank];break; // Lesser Healthstone - case 5699: - itemtype=itypes[2][rank];break; // Healthstone - case 11729: - itemtype=itypes[3][rank];break; // Greater Healthstone - case 11730: - itemtype=itypes[4][rank];break; // Major Healthstone - case 27230: - itemtype=itypes[5][rank];break; // Master Healthstone - case 47871: - itemtype=itypes[6][rank];break; // Demonic Healthstone - case 47878: - itemtype=itypes[7][rank];break; // Fel Healthstone - default: - return; - } - DoCreateItem(effIndex, itemtype); - return; - } - // Everlasting Affliction - case 47422: - // Refresh corruption on target - if (AuraEffect * aur = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x2, 0, 0, m_caster->GetGUID())) - aur->GetBase()->RefreshDuration(); - return; - // Demonic Empowerment - case 47193: - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || !unitTarget->ToCreature()->isPet()) - return; - CreatureInfo const * ci = objmgr.GetCreatureTemplate(unitTarget->GetEntry()); - switch (ci->family) - { - case CREATURE_FAMILY_SUCCUBUS: - unitTarget->CastSpell(unitTarget, 54435, true); - break; - case CREATURE_FAMILY_VOIDWALKER: - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(54443); - int32 hp = unitTarget->GetMaxHealth() * m_caster->CalculateSpellDamage(unitTarget, spellInfo, 0) /100; - unitTarget->CastCustomSpell(unitTarget, 54443,&hp, NULL, NULL,true); - //unitTarget->CastSpell(unitTarget, 54441, true); - break; - } - case CREATURE_FAMILY_FELGUARD: - unitTarget->CastSpell(unitTarget, 54508, true); - break; - case CREATURE_FAMILY_FELHUNTER: - unitTarget->CastSpell(unitTarget, 54509, true); - break; - case CREATURE_FAMILY_IMP: - unitTarget->CastSpell(unitTarget, 54444, true); - break; - } - return; - } - // Guarded by The Light - case 63521: - { - // Divine Plea - if (Aura * aura = m_caster->GetAura(54428)) - aura->RefreshDuration(); - return; - } - } - break; - } - case SPELLFAMILY_PRIEST: - { - switch(m_spellInfo->Id) - { - // Pain and Suffering - case 47948: - { - if (!unitTarget) - return; - // Refresh Shadow Word: Pain on target - if (AuraEffect * aur = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0, 0, m_caster->GetGUID())) - aur->GetBase()->RefreshDuration(); - return; - } - default: - break; - } - break; - } - case SPELLFAMILY_HUNTER: - { - switch(m_spellInfo->Id) - { - // Invigoration - case 53412: - { - if (AuraEffect * aurEff = unitTarget->GetDummyAuraEffect(SPELLFAMILY_HUNTER, 3487, 0)) - { - if (roll_chance_i(aurEff->GetAmount())) - unitTarget->CastSpell(unitTarget, 53398, true); - } - break; - } - // Heart of the Pheonix - case 55709: - { - int pct = 100; - if (unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->ToCreature()->isPet()) - if (Unit* owner = unitTarget->ToCreature()->GetOwner()) - owner->CastCustomSpell(unitTarget, 54114, &pct, NULL, NULL, true); - break; - } - // Chimera Shot - case 53209: - { - uint32 spellId = 0; - int32 basePoint = 0; - Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras(); - for (Unit::AuraApplicationMap::iterator i = Auras.begin(); i != Auras.end(); ++i) - { - Aura * aura = (*i).second->GetBase(); - if (aura->GetCasterGUID() != m_caster->GetGUID()) - continue; - // Search only Serpent Sting, Viper Sting, Scorpid Sting auras - flag96 familyFlag = aura->GetSpellProto()->SpellFamilyFlags; - if (!(familyFlag[1] & 0x00000080 || familyFlag[0] & 0x0000C000)) - continue; - if (AuraEffect const * aurEff = aura->GetEffect(0)) - { - // Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting. - if (familyFlag[0] & 0x4000) - { - int32 TickCount = aurEff->GetTotalTicks(); - spellId = 53353; // 53353 Chimera Shot - Serpent - basePoint = aurEff->GetAmount() * TickCount * 40 / 100; - } - // Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting. - else if (familyFlag[1] & 0x00000080) - { - int32 TickCount = aura->GetEffect(0)->GetTotalTicks(); - spellId = 53358; // 53358 Chimera Shot - Viper - - // Amount of one aura tick - basePoint = aurEff->GetAmount() * unitTarget->GetMaxPower(POWER_MANA) / 100 ; - int32 casterBasePoint = aurEff->GetAmount() * unitTarget->GetMaxPower(POWER_MANA) / 50 ; - if (basePoint > casterBasePoint) - basePoint = casterBasePoint; - basePoint = basePoint * TickCount * 60 / 100; - } - // Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute. - else if (familyFlag[0] & 0x00008000) - spellId = 53359; // 53359 Chimera Shot - Scorpid - // ?? nothing say in spell desc (possibly need addition check) - //if (familyFlag & 0x0000010000000000LL || // dot - // familyFlag & 0x0000100000000000LL) // stun - //{ - // spellId = 53366; // 53366 Chimera Shot - Wyvern - //} - - // Refresh aura duration - aura->RefreshDuration(); - } - break; - } - if (spellId) - m_caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, true); - return; - } - // Master's Call - case 53271: - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - if (Pet *PlrPet = m_caster->ToPlayer()->GetPet()) - m_caster->CastSpell(PlrPet, 62305, true); - return; - } - default: - break; - } - break; - } - case SPELLFAMILY_PALADIN: - { - // Judgement (seal trigger) - if (m_spellInfo->Category == SPELLCATEGORY_JUDGEMENT) - { - if (!unitTarget || !unitTarget->isAlive()) - return; - uint32 spellId1 = 0; - uint32 spellId2 = 0; - uint32 spellId3 = 0; - - // Judgement self add switch - switch (m_spellInfo->Id) - { - case 53407: spellId1 = 20184; break; // Judgement of Justice - case 20271: // Judgement of Light - case 57774: spellId1 = 20185; break; // Judgement of Light - case 53408: spellId1 = 20186; break; // Judgement of Wisdom - default: - sLog.outError("Unsupported Judgement (seal trigger) spell (Id: %u) in Spell::EffectScriptEffect",m_spellInfo->Id); - return; - } - // all seals have aura dummy in 2 effect - Unit::AuraApplicationMap & sealAuras = m_caster->GetAppliedAuras(); - for (Unit::AuraApplicationMap::iterator iter = sealAuras.begin(); iter != sealAuras.end();) - { - switch (iter->first) - { - // Heart of the Crusader - case 20335: // Rank 1 - spellId3 = 21183; - break; - case 20336: // Rank 2 - spellId3 = 54498; - break; - case 20337: // Rank 3 - spellId3 = 54499; - break; - } - Aura * aura = iter->second->GetBase(); - if (IsSealSpell(aura->GetSpellProto())) - { - if (AuraEffect * aureff = aura->GetEffect(2)) - if (aureff->GetAuraType() == SPELL_AURA_DUMMY) - { - if (sSpellStore.LookupEntry(aureff->GetAmount())) - spellId2 = aureff->GetAmount(); - break; - } - if (!spellId2) - { - switch (iter->first) - { - // Seal of light, Seal of wisdom, Seal of justice - case 20165: - case 20166: - case 20164: - spellId2 = 54158; - } - } - break; - } - else - ++iter; - } - if (spellId1) - m_caster->CastSpell(unitTarget, spellId1, true); - if (spellId2) - m_caster->CastSpell(unitTarget, spellId2, true); - if (spellId3) - m_caster->CastSpell(unitTarget, spellId3, true); - return; - } - } - case SPELLFAMILY_POTION: - { - switch(m_spellInfo->Id) - { - // Dreaming Glory - case 28698: - { - if (!unitTarget) - return; - unitTarget->CastSpell(unitTarget, 28694, true); - break; - } - // Netherbloom - case 28702: - { - if (!unitTarget) - return; - // 25% chance of casting a random buff - if (roll_chance_i(75)) - return; - - // triggered spells are 28703 to 28707 - // Note: some sources say, that there was the possibility of - // receiving a debuff. However, this seems to be removed by a patch. - const uint32 spellid = 28703; - - // don't overwrite an existing aura - for (uint8 i = 0; i < 5; ++i) - if (unitTarget->HasAura(spellid + i)) - return; - unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true); - break; - } - - // Nightmare Vine - case 28720: - { - if (!unitTarget) - return; - // 25% chance of casting Nightmare Pollen - if (roll_chance_i(75)) - return; - unitTarget->CastSpell(unitTarget, 28721, true); - break; - } - } - break; - } - case SPELLFAMILY_DEATHKNIGHT: - { - // Pestilence - if (m_spellInfo->SpellFamilyFlags[1]&0x10000) - { - // Get diseases on target of spell - if (m_targets.getUnitTarget() && // Glyph of Disease - cast on unit target too to refresh aura - (m_targets.getUnitTarget() != unitTarget || m_caster->GetAura(63334))) - { - // And spread them on target - // Blood Plague - if (m_targets.getUnitTarget()->GetAura(55078)) - m_caster->CastSpell(unitTarget, 55078, true); - // Frost Fever - if (m_targets.getUnitTarget()->GetAura(55095)) - m_caster->CastSpell(unitTarget, 55095, true); - } - } - break; - } - case SPELLFAMILY_WARRIOR: - { - // Shattering Throw - if (m_spellInfo->SpellFamilyFlags[1] & 0x00400000) - { - if (!unitTarget) - return; - // remove shields, will still display immune to damage part - unitTarget->RemoveAurasWithMechanic(1<Id); - m_caster->GetMap()->ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget); -} - -void Spell::EffectSanctuary(uint32 /*i*/) -{ - if (!unitTarget) - return; - - std::list targets; - Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(unitTarget, unitTarget, m_caster->GetMap()->GetVisibilityDistance()); - Trinity::UnitListSearcher searcher(unitTarget, targets, u_check); - unitTarget->VisitNearbyObject(m_caster->GetMap()->GetVisibilityDistance(), searcher); - for (std::list::iterator iter = targets.begin(); iter != targets.end(); ++iter) - { - if (!(*iter)->hasUnitState(UNIT_STAT_CASTING)) - continue; - - for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++) - { - if ((*iter)->GetCurrentSpell(i) - && (*iter)->GetCurrentSpell(i)->m_targets.getUnitTargetGUID() == unitTarget->GetGUID()) - { - (*iter)->InterruptSpell(CurrentSpellTypes(i), false); - } - } - } - - unitTarget->CombatStop(); - unitTarget->getHostileRefManager().deleteReferences(); // stop all fighting - // Vanish allows to remove all threat and cast regular stealth so other spells can be used - if (m_caster->GetTypeId() == TYPEID_PLAYER - && m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE - && (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_VANISH)) - { - m_caster->ToPlayer()->RemoveAurasByType(SPELL_AURA_MOD_ROOT); - // Overkill - if (m_caster->ToPlayer()->HasSpell(58426)) - m_caster->CastSpell(m_caster, 58427, true); - } -} - -void Spell::EffectAddComboPoints(uint32 /*i*/) -{ - if (!unitTarget) - return; - - if (!m_caster->m_movedPlayer) - return; - - if (damage <= 0) - return; - - m_caster->m_movedPlayer->AddComboPoints(unitTarget, damage, this); -} - -void Spell::EffectDuel(uint32 i) -{ - if (!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - Player *caster = (Player*)m_caster; - Player *target = (Player*)unitTarget; - - // caster or target already have requested duel - if (caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetGUIDLow())) - return; - - // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities) - // Don't have to check the target's map since you cannot challenge someone across maps - if (caster->GetMap()->Instanceable()) - //if (mapid != 0 && mapid != 1 && mapid != 530 && mapid != 571 && mapid != 609) - { - SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here - return; - } - - AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId()); - if (casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL)) - { - SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here - return; - } - - AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId()); - if (targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL)) - { - SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here - return; - } - - //CREATE DUEL FLAG OBJECT - GameObject* pGameObj = new GameObject; - - uint32 gameobject_id = m_spellInfo->EffectMiscValue[i]; - - Map *map = m_caster->GetMap(); - if (!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, - map, m_caster->GetPhaseMask(), - m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 , - m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 , - m_caster->GetPositionZ(), - m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY)) - { - delete pGameObj; - return; - } - - pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction()); - pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1); - int32 duration = GetSpellDuration(m_spellInfo); - pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); - pGameObj->SetSpellId(m_spellInfo->Id); - - m_caster->AddGameObject(pGameObj); - map->Add(pGameObj); - //END - - // Send request - WorldPacket data(SMSG_DUEL_REQUESTED, 8 + 8); - data << uint64(pGameObj->GetGUID()); - data << uint64(caster->GetGUID()); - caster->GetSession()->SendPacket(&data); - target->GetSession()->SendPacket(&data); - - // create duel-info - DuelInfo *duel = new DuelInfo; - duel->initiator = caster; - duel->opponent = target; - duel->startTime = 0; - duel->startTimer = 0; - caster->duel = duel; - - DuelInfo *duel2 = new DuelInfo; - duel2->initiator = caster; - duel2->opponent = caster; - duel2->startTime = 0; - duel2->startTimer = 0; - target->duel = duel2; - - caster->SetUInt64Value(PLAYER_DUEL_ARBITER, pGameObj->GetGUID()); - target->SetUInt64Value(PLAYER_DUEL_ARBITER, pGameObj->GetGUID()); -} - -void Spell::EffectStuck(uint32 /*i*/) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - if (!sWorld.getConfig(CONFIG_CAST_UNSTUCK)) - return; - - Player* pTarget = (Player*)unitTarget; - - sLog.outDebug("Spell Effect: Stuck"); - sLog.outDetail("Player %s (guid %u) used auto-unstuck future at map %u (%f, %f, %f)", pTarget->GetName(), pTarget->GetGUIDLow(), m_caster->GetMapId(), m_caster->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ()); - - if (pTarget->isInFlight()) - return; - - pTarget->TeleportTo(pTarget->GetStartPosition(), unitTarget == m_caster ? TELE_TO_SPELL : 0); - // homebind location is loaded always - // pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget == m_caster ? TELE_TO_SPELL : 0)); - - // Stuck spell trigger Hearthstone cooldown - SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690); - if (!spellInfo) - return; - Spell spell(pTarget, spellInfo, true, 0); - spell.SendSpellCooldown(); -} - -void Spell::EffectSummonPlayer(uint32 /*i*/) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - // Evil Twin (ignore player summon, but hide this for summoner) - if (unitTarget->HasAura(23445)) - return; - - float x, y, z; - m_caster->GetClosePoint(x, y, z, unitTarget->GetObjectSize()); - - unitTarget->ToPlayer()->SetSummonPoint(m_caster->GetMapId(),x,y,z); - - WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4); - data << uint64(m_caster->GetGUID()); // summoner guid - data << uint32(m_caster->GetZoneId()); // summoner zone - data << uint32(MAX_PLAYER_SUMMON_DELAY*IN_MILLISECONDS); // auto decline after msecs - unitTarget->ToPlayer()->GetSession()->SendPacket(&data); -} - -static ScriptInfo generateActivateCommand() -{ - ScriptInfo si; - si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT; - return si; -} - -void Spell::EffectActivateObject(uint32 effect_idx) -{ - if (!gameObjTarget) - return; - - static ScriptInfo activateCommand = generateActivateCommand(); - - int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx]; - - gameObjTarget->GetMap()->ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget); -} - -void Spell::EffectApplyGlyph(uint32 i) -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER || m_glyphIndex >= MAX_GLYPH_SLOT_INDEX) - return; - - Player *player = (Player*)m_caster; - - // apply new one - if (uint32 glyph = m_spellInfo->EffectMiscValue[i]) - { - if (GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph)) - { - if (GlyphSlotEntry const *gs = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex))) - { - if (gp->TypeFlags != gs->TypeFlags) - { - SendCastResult(SPELL_FAILED_INVALID_GLYPH); - return; // glyph slot mismatch - } - } - - // remove old glyph - if (uint32 oldglyph = player->GetGlyph(m_glyphIndex)) - { - if (GlyphPropertiesEntry const *old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph)) - { - player->RemoveAurasDueToSpell(old_gp->SpellId); - player->SetGlyph(m_glyphIndex, 0); - } - } - - player->CastSpell(m_caster, gp->SpellId, true); - player->SetGlyph(m_glyphIndex, glyph); - player->SendTalentsInfoData(false); - } - } -} - -void Spell::EffectEnchantHeldItem(uint32 i) -{ - // this is only item spell effect applied to main-hand weapon of target player (players in area) - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - Player* item_owner = (Player*)unitTarget; - Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); - - if (!item) - return; - - // must be equipped - if (!item ->IsEquipped()) - return; - - if (m_spellInfo->EffectMiscValue[i]) - { - uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; - int32 duration = GetSpellDuration(m_spellInfo); //Try duration index first .. - if (!duration) - duration = damage;//+1; //Base points after .. - if (!duration) - duration = 10; //10 seconds for enchants which don't have listed duration - - SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if (!pEnchant) - return; - - // Always go to temp enchantment slot - EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT; - - // Enchantment will not be applied if a different one already exists - if (item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id) - return; - - // Apply the temporary enchantment - item->SetEnchantment(slot, enchant_id, duration*IN_MILLISECONDS, 0); - item_owner->ApplyEnchantment(item, slot, true); - } -} - -void Spell::EffectDisEnchant(uint32 /*i*/) -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player* p_caster = (Player*)m_caster; - if (!itemTarget || !itemTarget->GetProto()->DisenchantID) - return; - - p_caster->UpdateCraftSkill(m_spellInfo->Id); - - m_caster->ToPlayer()->SendLoot(itemTarget->GetGUID(),LOOT_DISENCHANTING); - - // item will be removed at disenchanting end -} - -void Spell::EffectInebriate(uint32 /*i*/) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - Player *player = (Player*)unitTarget; - uint16 currentDrunk = player->GetDrunkValue(); - uint16 drunkMod = damage * 256; - if (currentDrunk + drunkMod > 0xFFFF) - currentDrunk = 0xFFFF; - else - currentDrunk += drunkMod; - player->SetDrunkValue(currentDrunk, m_CastItem ? m_CastItem->GetEntry() : 0); -} - -void Spell::EffectFeedPet(uint32 i) -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player *_player = (Player*)m_caster; - - Item* foodItem = m_targets.getItemTarget(); - if (!foodItem) - return; - - Pet *pet = _player->GetPet(); - if (!pet) - return; - - if (!pet->isAlive()) - return; - - int32 benefit = pet->GetCurrentFoodBenefitLevel(foodItem->GetProto()->ItemLevel); - if (benefit <= 0) - return; - - uint32 count = 1; - _player->DestroyItemCount(foodItem,count,true); - // TODO: fix crash when a spell has two effects, both pointed at the same item target - - m_caster->CastCustomSpell(pet, m_spellInfo->EffectTriggerSpell[i], &benefit, NULL, NULL, true); -} - -void Spell::EffectDismissPet(uint32 /*i*/) -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Pet* pet = m_caster->ToPlayer()->GetPet(); - - // not let dismiss dead pet - if (!pet||!pet->isAlive()) - return; - - m_caster->ToPlayer()->RemovePet(pet, PET_SAVE_NOT_IN_SLOT); -} - -void Spell::EffectSummonObject(uint32 i) -{ - uint32 go_id = m_spellInfo->EffectMiscValue[i]; - - uint8 slot = 0; - switch(m_spellInfo->Effect[i]) - { - case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: slot = 0; break; - case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: slot = 1; break; - case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: slot = 2; break; - case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: slot = 3; break; - default: return; - } - - uint64 guid = m_caster->m_ObjectSlot[slot]; - if (guid != 0) - { - GameObject* obj = NULL; - if (m_caster) - obj = m_caster->GetMap()->GetGameObject(guid); - - if (obj) - { - // Recast case - null spell id to make auras not be removed on object remove from world - if (m_spellInfo->Id == obj->GetSpellId()) - obj->SetSpellId(0); - m_caster->RemoveGameObject(obj, true); - } - m_caster->m_ObjectSlot[slot] = 0; - } - - GameObject* pGameObj = new GameObject; - - float x, y, z; - // If dest location if present - if (m_targets.HasDst()) - m_targets.m_dstPos.GetPosition(x, y, z); - // Summon in random point all other units if location present - else - m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE); - - Map *map = m_caster->GetMap(); - if (!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map, - m_caster->GetPhaseMask(), x, y, z, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY)) - { - delete pGameObj; - return; - } - - //pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel()); - int32 duration = GetSpellDuration(m_spellInfo); - pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); - pGameObj->SetSpellId(m_spellInfo->Id); - m_caster->AddGameObject(pGameObj); - - map->Add(pGameObj); - - m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID(); -} - -void Spell::EffectResurrect(uint32 /*effIndex*/) -{ - if (!unitTarget) - return; - if (unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - if (unitTarget->isAlive()) - return; - if (!unitTarget->IsInWorld()) - return; - - switch (m_spellInfo->Id) - { - // Defibrillate (Goblin Jumper Cables) have 33% chance on success - case 8342: - if (roll_chance_i(67)) - { - m_caster->CastSpell(m_caster, 8338, true, m_CastItem); - return; - } - break; - // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success - case 22999: - if (roll_chance_i(50)) - { - m_caster->CastSpell(m_caster, 23055, true, m_CastItem); - return; - } - break; - // Defibrillate ( Gnomish Army Knife) have 67% chance on success_list - case 54732: - if (roll_chance_i(33)) - { - return; - } - break; - default: - break; - } - - Player* pTarget = unitTarget->ToPlayer(); - - if (pTarget->isRessurectRequested()) // already have one active request - return; - - uint32 health = pTarget->GetMaxHealth() * damage / 100; - uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100; - - pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana); - SendResurrectRequest(pTarget); -} - -void Spell::EffectAddExtraAttacks(uint32 /*i*/) -{ - if (!unitTarget || !unitTarget->isAlive()) - return; - - if (unitTarget->m_extraAttacks) - return; - - Unit *victim = unitTarget->getVictim(); - - // attack prevented - // fixme, some attacks may not target current victim, this is right now not handled - if (!victim || !unitTarget->IsWithinMeleeRange(victim) || !unitTarget->HasInArc(2*M_PI/3, victim)) - return; - - // Only for proc/log informations - unitTarget->m_extraAttacks = damage; - // Need to send log before attack is made - SendLogExecute(); - m_needSpellLog = false; - - unitTarget->AttackerStateUpdate(victim, BASE_ATTACK, true); -} - -void Spell::EffectParry(uint32 /*i*/) -{ - if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER) - unitTarget->ToPlayer()->SetCanParry(true); -} - -void Spell::EffectBlock(uint32 /*i*/) -{ - if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER) - unitTarget->ToPlayer()->SetCanBlock(true); -} - -void Spell::EffectLeapForward(uint32 i) -{ - if (unitTarget->isInFlight()) - return; - - if (!m_targets.HasDst()) - return; - - uint32 mapid = m_caster->GetMapId(); - float dist = m_caster->GetSpellRadiusForTarget(unitTarget, sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - if (Player* modOwner = m_originalCaster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, dist); - - float x,y,z; - float destx,desty,destz,ground,floor; - float orientation = unitTarget->GetOrientation(), step = dist/10.0f; - - unitTarget->GetPosition(x,y,z); - destx = x + dist * cos(orientation); - desty = y + dist * sin(orientation); - ground = unitTarget->GetMap()->GetHeight(destx,desty,MAX_HEIGHT,true); - floor = unitTarget->GetMap()->GetHeight(destx,desty,z, true); - destz = fabs(ground - z) <= fabs(floor - z) ? ground : floor; - - bool col = VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid,x,y,z+0.5f,destx,desty,destz+0.5f,destx,desty,destz,-0.5f); - - if (col) // We had a collision! - { - destx -= 0.6 * cos(orientation); - desty -= 0.6 * sin(orientation); - dist = sqrt((x-destx)*(x-destx) + (y-desty)*(y-desty)); - step = dist/10.0f; - } - - int j = 0; - for (j; j < 10; j++) - { - if (fabs(z - destz) > 6) - { - destx -= step * cos(orientation); - desty -= step * sin(orientation); - ground = unitTarget->GetMap()->GetHeight(destx,desty,MAX_HEIGHT,true); - floor = unitTarget->GetMap()->GetHeight(destx,desty,z, true); - destz = fabs(ground - z) <= fabs(floor - z) ? ground:floor; - } else break; - } - - if (j < 10) - unitTarget->NearTeleportTo(destx, desty, destz + 0.07531, orientation, unitTarget == m_caster); -} - -void Spell::EffectReputation(uint32 i) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - Player *_player = (Player*)unitTarget; - - int32 rep_change = damage;//+1; // field store reputation change -1 - - uint32 faction_id = m_spellInfo->EffectMiscValue[i]; - - FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id); - - if (!factionEntry) - return; - - _player->GetReputationMgr().ModifyReputation(factionEntry, rep_change); -} - -void Spell::EffectQuestComplete(uint32 i) -{ - Player *pPlayer; - - if (m_caster->GetTypeId() == TYPEID_PLAYER) - pPlayer = (Player*)m_caster; - else if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER) - pPlayer = (Player*)unitTarget; - else - return; - - uint32 quest_id = m_spellInfo->EffectMiscValue[i]; - if (quest_id) - { - uint16 log_slot = pPlayer->FindQuestSlot(quest_id); - if (log_slot < MAX_QUEST_LOG_SIZE) - pPlayer->AreaExploredOrEventHappens(quest_id); - else - pPlayer->CompleteQuest(quest_id); // quest not in log - for internal use - } -} - -void Spell::EffectForceDeselect(uint32 /*i*/) -{ - WorldPacket data(SMSG_CLEAR_TARGET, 8); - data << uint64(m_caster->GetGUID()); - m_caster->SendMessageToSet(&data, true); -} - -void Spell::EffectSelfResurrect(uint32 i) -{ - if (!unitTarget || unitTarget->isAlive()) - return; - if (unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - if (!unitTarget->IsInWorld()) - return; - - uint32 health = 0; - uint32 mana = 0; - - // flat case - if (damage < 0) - { - health = uint32(-damage); - mana = m_spellInfo->EffectMiscValue[i]; - } - // percent case - else - { - health = uint32(damage/100.0f*unitTarget->GetMaxHealth()); - if (unitTarget->GetMaxPower(POWER_MANA) > 0) - mana = uint32(damage/100.0f*unitTarget->GetMaxPower(POWER_MANA)); - } - - Player *plr = unitTarget->ToPlayer(); - plr->ResurrectPlayer(0.0f); - - plr->SetHealth(health); - plr->SetPower(POWER_MANA, mana); - plr->SetPower(POWER_RAGE, 0); - plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY)); - - plr->SpawnCorpseBones(); -} - -void Spell::EffectSkinning(uint32 /*i*/) -{ - if (unitTarget->GetTypeId() != TYPEID_UNIT) - return; - if (!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Creature* creature = unitTarget->ToCreature(); - int32 targetLevel = creature->getLevel(); - - uint32 skill = creature->GetCreatureInfo()->GetRequiredLootSkill(); - - m_caster->ToPlayer()->SendLoot(creature->GetGUID(),LOOT_SKINNING); - creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); - - int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5; - - int32 skillValue = m_caster->ToPlayer()->GetPureSkillValue(skill); - - // Double chances for elites - m_caster->ToPlayer()->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1); -} - -void Spell::EffectCharge(uint32 /*i*/) -{ - Unit *target = m_targets.getUnitTarget(); - if (!target) - return; - - float x, y, z; - target->GetContactPoint(m_caster, x, y, z); - m_caster->GetMotionMaster()->MoveCharge(x, y, z); - - // not all charge effects used in negative spells - if (!IsPositiveSpell(m_spellInfo->Id) && m_caster->GetTypeId() == TYPEID_PLAYER) - m_caster->Attack(target, true); -} - -void Spell::EffectChargeDest(uint32 /*i*/) -{ - if (m_targets.HasDst()) - { - float x, y, z; - m_targets.m_dstPos.GetPosition(x, y, z); - m_caster->GetMotionMaster()->MoveCharge(x, y, z); - } -} - -void Spell::EffectKnockBack(uint32 i) -{ - if (!unitTarget) - return; - - // Typhoon - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags[1] & 0x01000000) - { - // Glyph of Typhoon - if (m_caster->HasAura(62135)) - return; - } - - // Thunderstorm - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[1] & 0x00002000) - { - // Glyph of Thunderstorm - if (m_caster->HasAura(62132)) - return; - } - - float ratio = m_caster->GetCombatReach() / std::max(unitTarget->GetCombatReach(), 1.0f); - if (ratio < 1.0f) - ratio = ratio * ratio * ratio * 0.1f; // volume = length^3 - else - ratio = 0.1f; // dbc value ratio - float speedxy = float(m_spellInfo->EffectMiscValue[i]) * ratio; - float speedz = float(damage) * ratio; - if (speedxy < 0.1f && speedz < 0.1f) - return; - - float x, y; - if (m_spellInfo->Effect[i] == SPELL_EFFECT_KNOCK_BACK_DEST) - { - if (m_targets.HasDst()) - m_targets.m_dstPos.GetPosition(x, y); - else - return; - } - else //if (m_spellInfo->Effect[i] == SPELL_EFFECT_KNOCK_BACK) - { - m_caster->GetPosition(x, y); - } - - unitTarget->KnockbackFrom(x, y, speedxy, speedz); -} - -void Spell::EffectLeapBack(uint32 i) -{ - float speedxy = float(m_spellInfo->EffectMiscValue[i])/10; - float speedz = float(damage/10); - if (!speedxy) - { - if (m_targets.getUnitTarget()) - m_caster->JumpTo(m_targets.getUnitTarget(), speedz); - } - else - { - //1891: Disengage - m_caster->JumpTo(speedxy, speedz, m_spellInfo->SpellIconID != 1891); - } -} - -void Spell::EffectQuestClear(uint32 i) -{ - Player *pPlayer = NULL; - if (m_caster->GetTypeId() == TYPEID_PLAYER) - pPlayer = m_caster->ToPlayer(); - else if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER) - pPlayer = unitTarget->ToPlayer(); - - if (!pPlayer) - return; - - uint32 quest_id = m_spellInfo->EffectMiscValue[i]; - - Quest const* pQuest = objmgr.GetQuestTemplate(quest_id); - - if (!pQuest) - return; - - QuestStatusMap::iterator qs_itr = pPlayer->getQuestStatusMap().find(quest_id); - // Player has never done this quest - if (qs_itr == pPlayer->getQuestStatusMap().end()) - return; - - // remove all quest entries for 'entry' from quest log - for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) - { - uint32 quest = pPlayer->GetQuestSlotQuestId(slot); - if (quest == quest_id) - { - pPlayer->SetQuestSlot(slot, 0); - - // we ignore unequippable quest items in this case, its' still be equipped - pPlayer->TakeQuestSourceItem(quest, false); - } - } - - // set quest status to not started (will be updated in DB at next save) - pPlayer->SetQuestStatus(quest_id, QUEST_STATUS_NONE); - - // reset rewarded for restart repeatable quest - QuestStatusData &data = qs_itr->second; - data.m_rewarded = false; -} - -void Spell::EffectSendTaxi(uint32 i) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - unitTarget->ToPlayer()->ActivateTaxiPathTo(m_spellInfo->EffectMiscValue[i],m_spellInfo->Id); -} - -void Spell::EffectPlayerPull(uint32 i) -{ - if (!unitTarget) - return; - - float speedZ = m_spellInfo->EffectBasePoints[i]/10; - float speedXY = m_spellInfo->EffectMiscValue[i]/10; - unitTarget->GetMotionMaster()->MoveJump(m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), speedXY, speedZ); -} - -void Spell::EffectDispelMechanic(uint32 i) -{ - if (!unitTarget) - return; - - uint32 mechanic = m_spellInfo->EffectMiscValue[i]; - - std::queue < std::pair < uint32, uint64 > > dispel_list; - - Unit::AuraMap const& auras = unitTarget->GetOwnedAuras(); - for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - { - Aura * aura = itr->second; - if (!aura->GetApplicationOfTarget(unitTarget->GetGUID())) - continue; - bool success = false; - GetDispelChance(aura->GetCaster(), unitTarget, aura->GetId(), !unitTarget->IsFriendlyTo(m_caster), &success); - if ((GetAllSpellMechanicMask(aura->GetSpellProto()) & (1 << mechanic)) && success) - dispel_list.push(std::make_pair(aura->GetId(), aura->GetCasterGUID())); - } - - for (; dispel_list.size(); dispel_list.pop()) - { - unitTarget->RemoveAura(dispel_list.front().first, dispel_list.front().second, 0, AURA_REMOVE_BY_ENEMY_SPELL); - } -} - -void Spell::EffectSummonDeadPet(uint32 /*i*/) -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - Player *_player = (Player*)m_caster; - Pet *pet = _player->GetPet(); - if (!pet) - return; - if (pet->isAlive()) - return; - if (damage < 0) - return; - - float x,y,z; - _player->GetPosition(x, y, z); - _player->GetMap()->CreatureRelocation(pet, x, y, z, _player->GetOrientation()); - - pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); - pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); - pet->setDeathState(ALIVE); - pet->clearUnitState(UNIT_STAT_ALL_STATE); - pet->SetHealth(uint32(pet->GetMaxHealth()*(float(damage)/100))); - - //pet->AIM_Initialize(); - //_player->PetSpellInitialize(); - pet->SavePetToDB(PET_SAVE_AS_CURRENT); -} - -void Spell::EffectDestroyAllTotems(uint32 /*i*/) -{ - int32 mana = 0; - for (uint8 slot = SUMMON_SLOT_TOTEM; slot < MAX_TOTEM_SLOT; ++slot) - { - if (!m_caster->m_SummonSlot[slot]) - continue; - - Creature* totem = m_caster->GetMap()->GetCreature(m_caster->m_SummonSlot[slot]); - if (totem && totem->isTotem()) - { - uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL); - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id); - if (spellInfo) - { - mana += spellInfo->manaCost; - mana += spellInfo->ManaCostPercentage * m_caster->GetCreateMana() / 100; - } - totem->ToTotem()->UnSummon(); - } - } - mana = mana * damage / 100; - - if (mana) - m_caster->CastCustomSpell(m_caster, 39104, &mana, NULL, NULL, true); -} - -void Spell::EffectDurabilityDamage(uint32 i) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - int32 slot = m_spellInfo->EffectMiscValue[i]; - - // FIXME: some spells effects have value -1/-2 - // Possibly its mean -1 all player equipped items and -2 all items - if (slot < 0) - { - unitTarget->ToPlayer()->DurabilityPointsLossAll(damage, (slot < -1)); - return; - } - - // invalid slot value - if (slot >= INVENTORY_SLOT_BAG_END) - return; - - if (Item* item = unitTarget->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, slot)) - unitTarget->ToPlayer()->DurabilityPointsLoss(item, damage); -} - -void Spell::EffectDurabilityDamagePCT(uint32 i) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - int32 slot = m_spellInfo->EffectMiscValue[i]; - - // FIXME: some spells effects have value -1/-2 - // Possibly its mean -1 all player equipped items and -2 all items - if (slot < 0) - { - unitTarget->ToPlayer()->DurabilityLossAll(double(damage)/100.0f, (slot < -1)); - return; - } - - // invalid slot value - if (slot >= INVENTORY_SLOT_BAG_END) - return; - - if (damage <= 0) - return; - - if (Item* item = unitTarget->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, slot)) - unitTarget->ToPlayer()->DurabilityLoss(item, double(damage)/100.0f); -} - -void Spell::EffectModifyThreatPercent(uint32 /*effIndex*/) -{ - if (!unitTarget) - return; - - unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage); -} - -void Spell::EffectTransmitted(uint32 effIndex) -{ - uint32 name_id = m_spellInfo->EffectMiscValue[effIndex]; - - GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id); - - if (!goinfo) - { - sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id, m_spellInfo->Id); - return; - } - - float fx, fy, fz; - - if (m_targets.HasDst()) - m_targets.m_dstPos.GetPosition(fx, fy, fz); - //FIXME: this can be better check for most objects but still hack - else if (m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed == 0) - { - float dis = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex])); - m_caster->GetClosePoint(fx, fy, fz, DEFAULT_WORLD_OBJECT_SIZE, dis); - } - else - { - //GO is always friendly to it's creator, get range for friends - float min_dis = GetSpellMinRangeForFriend(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); - float max_dis = GetSpellMaxRangeForFriend(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); - float dis = rand_norm() * (max_dis - min_dis) + min_dis; - - m_caster->GetClosePoint(fx, fy, fz, DEFAULT_WORLD_OBJECT_SIZE, dis); - } - - Map *cMap = m_caster->GetMap(); - if (goinfo->type == GAMEOBJECT_TYPE_FISHINGNODE) - { - LiquidData liqData; - if ( !cMap->IsInWater(fx, fy, fz + 1.f/* -0.5f */, &liqData)) // Hack to prevent fishing bobber from failing to land on fishing hole - { // but this is not proper, we really need to ignore not materialized objects - SendCastResult(SPELL_FAILED_NOT_HERE); - SendChannelUpdate(0); - return; - } - - // replace by water level in this case - //fz = cMap->GetWaterLevel(fx, fy); - fz = liqData.level; - } - // if gameobject is summoning object, it should be spawned right on caster's position - else if (goinfo->type == GAMEOBJECT_TYPE_SUMMONING_RITUAL) - { - m_caster->GetPosition(fx, fy, fz); - } - - GameObject* pGameObj = new GameObject; - - if (!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap, - m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) - { - delete pGameObj; - return; - } - - int32 duration = GetSpellDuration(m_spellInfo); - - switch(goinfo->type) - { - case GAMEOBJECT_TYPE_FISHINGNODE: - { - m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID()); - m_caster->AddGameObject(pGameObj); // will removed at spell cancel - - // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo)) - // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME) - int32 lastSec = 0; - switch(urand(0, 3)) - { - case 0: lastSec = 3; break; - case 1: lastSec = 7; break; - case 2: lastSec = 13; break; - case 3: lastSec = 17; break; - } - - duration = duration - lastSec*IN_MILLISECONDS + FISHING_BOBBER_READY_TIME*IN_MILLISECONDS; - break; - } - case GAMEOBJECT_TYPE_SUMMONING_RITUAL: - { - if (m_caster->GetTypeId() == TYPEID_PLAYER) - { - pGameObj->AddUniqueUse(m_caster->ToPlayer()); - m_caster->AddGameObject(pGameObj); // will removed at spell cancel - } - break; - } - case GAMEOBJECT_TYPE_DUEL_ARBITER: // 52991 - m_caster->AddGameObject(pGameObj); - break; - case GAMEOBJECT_TYPE_FISHINGHOLE: - case GAMEOBJECT_TYPE_CHEST: - default: - break; - } - - pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); - - pGameObj->SetOwnerGUID(m_caster->GetGUID()); - - //pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); - pGameObj->SetSpellId(m_spellInfo->Id); - - DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted"); - //m_caster->AddGameObject(pGameObj); - //m_ObjToDel.push_back(pGameObj); - - cMap->Add(pGameObj); - - if (uint32 linkedEntry = pGameObj->GetGOInfo()->GetLinkedGameObjectEntry()) - { - GameObject* linkedGO = new GameObject; - if (linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap, - m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) - { - linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); - //linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); - linkedGO->SetSpellId(m_spellInfo->Id); - linkedGO->SetOwnerGUID(m_caster->GetGUID()); - - linkedGO->GetMap()->Add(linkedGO); - } - else - { - delete linkedGO; - linkedGO = NULL; - return; - } - } -} - -void Spell::EffectProspecting(uint32 /*i*/) -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player* p_caster = (Player*)m_caster; - if (!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP)) - return; - - if (itemTarget->GetCount() < 5) - return; - - if (sWorld.getConfig(CONFIG_SKILL_PROSPECTING)) - { - uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING); - uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank; - p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue); - } - - m_caster->ToPlayer()->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING); -} - -void Spell::EffectMilling(uint32 /*i*/) -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player* p_caster = (Player*)m_caster; - if (!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_HERBS)) - return; - - if (itemTarget->GetCount() < 5) - return; - - if (sWorld.getConfig(CONFIG_SKILL_MILLING)) - { - uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_INSCRIPTION); - uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank; - p_caster->UpdateGatherSkill(SKILL_INSCRIPTION, SkillValue, reqSkillValue); - } - - m_caster->ToPlayer()->SendLoot(itemTarget->GetGUID(), LOOT_MILLING); -} - -void Spell::EffectSkill(uint32 /*i*/) -{ - sLog.outDebug("WORLD: SkillEFFECT"); -} - -/* There is currently no need for this effect. We handle it in BattleGround.cpp - If we would handle the resurrection here, the spiritguide would instantly disappear as the - player revives, and so we wouldn't see the spirit heal visual effect on the npc. - This is why we use a half sec delay between the visual effect and the resurrection itself */ -void Spell::EffectSpiritHeal(uint32 /*i*/) -{ - /* - if (!unitTarget || unitTarget->isAlive()) - return; - if (unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - if (!unitTarget->IsInWorld()) - return; - - //m_spellInfo->EffectBasePoints[i]; == 99 (percent?) - //unitTarget->ToPlayer()->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA)); - unitTarget->ToPlayer()->ResurrectPlayer(1.0f); - unitTarget->ToPlayer()->SpawnCorpseBones(); - */ -} - -// remove insignia spell effect -void Spell::EffectSkinPlayerCorpse(uint32 /*i*/) -{ - sLog.outDebug("Effect: SkinPlayerCorpse"); - if ((m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->isAlive())) - return; - - unitTarget->ToPlayer()->RemovedInsignia((Player*)m_caster); -} - -void Spell::EffectStealBeneficialBuff(uint32 i) -{ - sLog.outDebug("Effect: StealBeneficialBuff"); - - if (!unitTarget || unitTarget == m_caster) // can't steal from self - return; - - DispelChargesList steal_list; - - // Create dispel mask by dispel type - uint32 dispelMask = GetDispellMask(DispelType(m_spellInfo->EffectMiscValue[i])); - Unit::AuraMap const& auras = unitTarget->GetOwnedAuras(); - for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - { - Aura * aura = itr->second; - AuraApplication * aurApp = aura->GetApplicationOfTarget(unitTarget->GetGUID()); - if (!aurApp) - continue; - - if ((1<GetSpellProto()->Dispel) & dispelMask) - { - // Need check for passive? this - if (!aurApp->IsPositive() || aura->IsPassive() || aura->GetSpellProto()->AttributesEx4 & SPELL_ATTR_EX4_NOT_STEALABLE) - continue; - - // The charges / stack amounts don't count towards the total number of auras that can be dispelled. - // Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell - // Polymorph instead of 1 / (5 + 1) -> 16%. - bool dispel_charges = aura->GetSpellProto()->AttributesEx7 & SPELL_ATTR_EX7_DISPEL_CHARGES; - uint8 charges = dispel_charges ? aura->GetCharges() : aura->GetStackAmount(); - if (charges > 0) - steal_list.push_back(std::make_pair(aura, charges)); - } - } - - if (steal_list.empty()) - return; - - // Ok if exist some buffs for dispel try dispel it - uint32 failCount = 0; - DispelList success_list; - WorldPacket dataFail(SMSG_DISPEL_FAILED, 8+8+4+4+damage*4); - // dispel N = damage buffs (or while exist buffs for dispel) - for (int32 count = 0; count < damage && !steal_list.empty();) - { - // Random select buff for dispel - DispelChargesList::iterator itr = steal_list.begin(); - std::advance(itr, urand(0, steal_list.size() - 1)); - - bool success = false; - // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance." - if (!GetDispelChance(itr->first->GetCaster(), unitTarget, itr->first->GetId(), !unitTarget->IsFriendlyTo(m_caster), &success)) - { - steal_list.erase(itr); - continue; - } - else - { - if (success) - { - success_list.push_back(std::make_pair(itr->first->GetId(), itr->first->GetCasterGUID())); - --itr->second; - if (itr->second <= 0) - steal_list.erase(itr); - } - else - { - if (!failCount) - { - // Failed to dispell - dataFail << uint64(m_caster->GetGUID()); // Caster GUID - dataFail << uint64(unitTarget->GetGUID()); // Victim GUID - dataFail << uint32(m_spellInfo->Id); // dispel spell id - } - ++failCount; - dataFail << uint32(itr->first->GetId()); // Spell Id - } - ++count; - } - } - - if (failCount) - m_caster->SendMessageToSet(&dataFail, true); - - if (success_list.empty()) - return; - - WorldPacket dataSuccess(SMSG_SPELLSTEALLOG, 8+8+4+1+4+damage*5); - dataSuccess.append(unitTarget->GetPackGUID()); // Victim GUID - dataSuccess.append(m_caster->GetPackGUID()); // Caster GUID - dataSuccess << uint32(m_spellInfo->Id); // dispel spell id - dataSuccess << uint8(0); // not used - dataSuccess << uint32(success_list.size()); // count - for (DispelList::iterator itr = success_list.begin(); itr!=success_list.end(); ++itr) - { - dataSuccess << uint32(itr->first); // Spell Id - dataSuccess << uint8(0); // 0 - steals !=0 transfers - unitTarget->RemoveAurasDueToSpellBySteal(itr->first, itr->second, m_caster); - } - m_caster->SendMessageToSet(&dataSuccess, true); -} - -void Spell::EffectKillCreditPersonal(uint32 i) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - unitTarget->ToPlayer()->KilledMonsterCredit(m_spellInfo->EffectMiscValue[i], 0); -} - -void Spell::EffectKillCredit(uint32 i) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - int32 creatureEntry = m_spellInfo->EffectMiscValue[i]; - if (!creatureEntry) - { - if (m_spellInfo->Id == 42793) // Burn Body - creatureEntry = 24008; // Fallen Combatant - } - - if (creatureEntry) - unitTarget->ToPlayer()->RewardPlayerAndGroupAtEvent(creatureEntry, unitTarget); -} - -void Spell::EffectQuestFail(uint32 i) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - unitTarget->ToPlayer()->FailQuest(m_spellInfo->EffectMiscValue[i]); -} - -void Spell::EffectActivateRune(uint32 eff_idx) -{ - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player *plr = (Player*)m_caster; - - if (plr->getClass() != CLASS_DEATH_KNIGHT) - return; - - // needed later - m_runesState = m_caster->ToPlayer()->GetRunesState(); - - uint32 count = damage; - if (count == 0) count = 1; - for (uint32 j = 0; j < MAX_RUNES && count > 0; ++j) - { - if (plr->GetRuneCooldown(j) && plr->GetCurrentRune(j) == RuneType(m_spellInfo->EffectMiscValue[eff_idx])) - { - plr->SetRuneCooldown(j, 0); - --count; - } - } - // Empower rune weapon - if (m_spellInfo->Id == 47568) - { - // Need to do this just once - if (eff_idx != 0) - return; - - for (uint32 i = 0; i < MAX_RUNES; ++i) - { - if (plr->GetRuneCooldown(i) && (plr->GetCurrentRune(i) == RUNE_FROST || plr->GetCurrentRune(i) == RUNE_DEATH)) - plr->SetRuneCooldown(i, 0); - } - } -} - -void Spell::EffectTitanGrip(uint32 /*eff_idx*/) -{ - if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER) - unitTarget->ToPlayer()->SetCanTitanGrip(true); -} - -void Spell::EffectRedirectThreat(uint32 /*i*/) -{ - if (unitTarget) - m_caster->SetReducedThreatPercent((uint32)damage, unitTarget->GetGUID()); -} - -void Spell::EffectWMODamage(uint32 /*i*/) -{ - if (gameObjTarget && gameObjTarget->GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING) - { - Unit *caster = m_originalCaster; - if (!caster) - return; - - FactionTemplateEntry const *casterft, *goft; - casterft = caster->getFactionTemplateEntry(); - goft = sFactionTemplateStore.LookupEntry(gameObjTarget->GetUInt32Value(GAMEOBJECT_FACTION)); - // Do not allow to damage GO's of friendly factions (ie: Wintergrasp Walls) - if (casterft && goft && !casterft->IsFriendlyTo(*goft)) - { - gameObjTarget->TakenDamage(uint32(damage), caster); - WorldPacket data(SMSG_DESTRUCTIBLE_BUILDING_DAMAGE, 8+8+8+4+4); - data.append(gameObjTarget->GetPackGUID()); - data.append(caster->GetPackGUID()); - if (Unit *who = caster->GetCharmerOrOwner()) - data.append(who->GetPackGUID()); - else - data << uint8(0); - data << uint32(damage); - data << uint32(m_spellInfo->Id); - gameObjTarget->SendMessageToSet(&data, false); - } - } -} - -void Spell::EffectWMORepair(uint32 /*i*/) -{ - if (gameObjTarget && gameObjTarget->GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING) - gameObjTarget->Rebuild(); -} - -void Spell::SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const *properties) -{ - Unit *caster = m_originalCaster; - if (!caster) - return; - - if (caster->isTotem()) - caster = caster->ToTotem()->GetOwner(); - - // in another case summon new - uint8 level = caster->getLevel(); - - // level of pet summoned using engineering item based at engineering skill level - if (m_CastItem && caster->GetTypeId() == TYPEID_PLAYER) - if (ItemPrototype const *proto = m_CastItem->GetProto()) - if (proto->RequiredSkill == SKILL_ENGINERING) - if (uint16 skill202 = caster->ToPlayer()->GetSkillValue(SKILL_ENGINERING)) - level = skill202/5; - - //float radius = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - float radius = 5.0f; - int32 amount = damage > 0 ? damage : 1; - int32 duration = GetSpellDuration(m_spellInfo); - switch (m_spellInfo->Id) - { - case 1122: // Inferno - amount = 1; - break; - case 49028: // Dancing Rune Weapon - if (AuraEffect *aurEff = m_originalCaster->GetAuraEffect(63330, 0)) // glyph of Dancing Rune Weapon - duration += aurEff->GetAmount(); - break; - } - if (Player* modOwner = m_originalCaster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration); - - //TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN; - Map *map = caster->GetMap(); - - for (uint32 count = 0; count < amount; ++count) - { - Position pos; - GetSummonPosition(i, pos, radius, count); - - TempSummon *summon = map->SummonCreature(entry, pos, properties, duration, caster); - if (!summon) - return; - if (summon->HasUnitTypeMask(UNIT_MASK_GUARDIAN)) - ((Guardian*)summon)->InitStatsForLevel(level); - - summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); - if (summon->HasUnitTypeMask(UNIT_MASK_MINION) && m_targets.HasDst()) - ((Minion*)summon)->SetFollowAngle(m_caster->GetAngle(summon)); - - if (summon->GetEntry() == 27893) - if (uint32 weapon = m_caster->GetUInt32Value(PLAYER_VISIBLE_ITEM_16_ENTRYID)) - { - summon->SetDisplayId(11686); - summon->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, weapon); - } - else - summon->SetDisplayId(1126); - - summon->AI()->EnterEvadeMode(); - } -} - -void Spell::GetSummonPosition(uint32 i, Position &pos, float radius, uint32 count) -{ - pos.SetOrientation(m_caster->GetOrientation()); - - if (m_targets.HasDst()) - { - // Summon 1 unit in dest location - if (count == 0) - pos.Relocate(m_targets.m_dstPos); - // Summon in random point all other units if location present - else - { - //This is a workaround. Do not have time to write much about it - switch (m_spellInfo->EffectImplicitTargetA[i]) - { - case TARGET_MINION: - case TARGET_DEST_CASTER_RANDOM: - m_caster->GetNearPosition(pos, radius * rand_norm(), rand_norm()*2*M_PI); - break; - case TARGET_DEST_DEST_RANDOM: - case TARGET_DEST_TARGET_RANDOM: - m_caster->GetRandomPoint(m_targets.m_dstPos, radius, pos); - break; - default: - pos.Relocate(m_targets.m_dstPos); - break; - } - } - } - // Summon if dest location not present near caster - else - { - float x, y, z; - m_caster->GetClosePoint(x,y,z,3.0f); - pos.Relocate(x, y, z); - } -} - -void Spell::EffectRenamePet(uint32 /*eff_idx*/) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || - !unitTarget->ToCreature()->isPet() || ((Pet*)unitTarget)->getPetType() != HUNTER_PET) - return; - - unitTarget->RemoveByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED); -} - -void Spell::EffectPlayMusic(uint32 i) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - uint32 soundid = m_spellInfo->EffectMiscValue[i]; - - if (!sSoundEntriesStore.LookupEntry(soundid)) - { - sLog.outError("EffectPlayMusic: Sound (Id: %u) not exist in spell %u.",soundid,m_spellInfo->Id); - return; - } - - WorldPacket data(SMSG_PLAY_MUSIC, 4); - data << uint32(soundid); - unitTarget->ToPlayer()->GetSession()->SendPacket(&data); -} - -void Spell::EffectSpecCount(uint32 /*eff_idx*/) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - unitTarget->ToPlayer()->UpdateSpecCount(damage); -} - -void Spell::EffectActivateSpec(uint32 /*eff_idx*/) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - unitTarget->ToPlayer()->ActivateSpec(damage-1); // damage is 1 or 2, spec is 0 or 1 -} - -void Spell::EffectPlayerNotification(uint32 /*eff_idx*/) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - switch(m_spellInfo->Id) - { - case 58730: // Restricted Flight Area - case 58600: // Restricted Flight Area - unitTarget->ToPlayer()->GetSession()->SendNotification(LANG_ZONE_NOFLYZONE); - break; - } -} - -void Spell::EffectRemoveAura(uint32 i) -{ - if (!unitTarget) - return; - // there may be need of specifying casterguid of removed auras - unitTarget->RemoveAurasDueToSpell(m_spellInfo->EffectTriggerSpell[i]); -} - -void Spell::EffectCastButtons(uint32 i) -{ - if (!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player *p_caster = (Player*)m_caster; - uint32 button_id = m_spellInfo->EffectMiscValue[i] + 132; - uint32 n_buttons = m_spellInfo->EffectMiscValueB[i]; - - for (; n_buttons; n_buttons--, button_id++) - { - ActionButton const* ab = p_caster->GetActionButton(button_id); - if (!ab || ab->GetType() != ACTION_BUTTON_SPELL) - continue; - - uint32 spell_id = ab->GetAction(); - if (!spell_id) - continue; - - if (p_caster->HasSpellCooldown(spell_id)) - continue; - - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); - uint32 cost = CalculatePowerCost(spellInfo, m_caster, GetSpellSchoolMask(spellInfo)); - - if (m_caster->GetPower(POWER_MANA) < cost) - break; - - m_caster->CastSpell(unitTarget, spell_id, true); - m_caster->ModifyPower(POWER_MANA, -(int32)cost); - p_caster->AddSpellAndCategoryCooldowns(spellInfo, 0); - } -} - -void Spell::EffectRechargeManaGem(uint32 /*i*/) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - Player *player = (Player*)m_caster; - - if (!player) - return; - - uint32 item_id = m_spellInfo->EffectItemType[0]; - - ItemPrototype const *pProto = objmgr.GetItemPrototype(item_id); - if (!pProto) - { - player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - if (Item* pItem = player->GetItemByEntry(item_id)) - { - for (int x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x) - pItem->SetSpellCharges(x,pProto->Spells[x].SpellCharges); - pItem->SetState(ITEM_CHANGED,player); - } -} - -void Spell::EffectBind(uint32 i) -{ - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - Player* player = (Player*)unitTarget; - - uint32 area_id; - WorldLocation loc; - if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_DST_DB || m_spellInfo->EffectImplicitTargetB[i] == TARGET_DST_DB) - { - SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id); - if (!st) - { - sLog.outError( "Spell::EffectBind - unknown teleport coordinates for spell ID %u", m_spellInfo->Id ); - return; - } - - loc.m_mapId = st->target_mapId; - loc.m_positionX = st->target_X; - loc.m_positionY = st->target_Y; - loc.m_positionZ = st->target_Y; - loc.m_orientation = st->target_Orientation; - area_id = player->GetAreaId(); - } - else - { - player->GetPosition(&loc); - area_id = player->GetAreaId(); - } - - player->SetHomebind(loc, area_id); - - // binding - WorldPacket data( SMSG_BINDPOINTUPDATE, (4+4+4+4+4) ); - data << float(loc.m_positionX); - data << float(loc.m_positionY); - data << float(loc.m_positionZ); - data << uint32(loc.m_mapId); - data << uint32(area_id); - player->SendDirectMessage( &data ); - - DEBUG_LOG("New homebind X : %f", loc.m_positionX); - DEBUG_LOG("New homebind Y : %f", loc.m_positionY); - DEBUG_LOG("New homebind Z : %f", loc.m_positionZ); - DEBUG_LOG("New homebind MapId : %u", loc.m_mapId); - DEBUG_LOG("New homebind AreaId : %u", area_id); - - // zone update - data.Initialize(SMSG_PLAYERBOUND, 8+4); - data << uint64(player->GetGUID()); - data << uint32(area_id); - player->SendDirectMessage( &data ); -} diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp new file mode 100644 index 00000000000..6a9f8ed7e10 --- /dev/null +++ b/src/server/game/Spells/SpellEffects.cpp @@ -0,0 +1,8167 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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 + */ + +#include "Common.h" +#include "DatabaseEnv.h" +#include "WorldPacket.h" +#include "Opcodes.h" +#include "Log.h" +#include "UpdateMask.h" +#include "World.h" +#include "ObjectMgr.h" +#include "SpellMgr.h" +#include "Player.h" +#include "SkillExtraItems.h" +#include "Unit.h" +#include "Spell.h" +#include "DynamicObject.h" +#include "SpellAuras.h" +#include "SpellAuraEffects.h" +#include "Group.h" +#include "UpdateData.h" +#include "MapManager.h" +#include "ObjectAccessor.h" +#include "SharedDefines.h" +#include "Pet.h" +#include "GameObject.h" +#include "GossipDef.h" +#include "Creature.h" +#include "Totem.h" +#include "CreatureAI.h" +#include "BattleGroundMgr.h" +#include "BattleGround.h" +#include "BattleGroundEY.h" +#include "BattleGroundWS.h" +#include "OutdoorPvPMgr.h" +#include "Language.h" +#include "SocialMgr.h" +#include "Util.h" +#include "VMapFactory.h" +#include "TemporarySummon.h" +#include "CellImpl.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "SkillDiscovery.h" +#include "Formulas.h" +#include "Vehicle.h" +#include "ScriptMgr.h" + +pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= +{ + &Spell::EffectNULL, // 0 + &Spell::EffectInstaKill, // 1 SPELL_EFFECT_INSTAKILL + &Spell::EffectSchoolDMG, // 2 SPELL_EFFECT_SCHOOL_DAMAGE + &Spell::EffectDummy, // 3 SPELL_EFFECT_DUMMY + &Spell::EffectUnused, // 4 SPELL_EFFECT_PORTAL_TELEPORT unused + &Spell::EffectTeleportUnits, // 5 SPELL_EFFECT_TELEPORT_UNITS + &Spell::EffectApplyAura, // 6 SPELL_EFFECT_APPLY_AURA + &Spell::EffectEnvirinmentalDMG, // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE + &Spell::EffectPowerDrain, // 8 SPELL_EFFECT_POWER_DRAIN + &Spell::EffectHealthLeech, // 9 SPELL_EFFECT_HEALTH_LEECH + &Spell::EffectHeal, // 10 SPELL_EFFECT_HEAL + &Spell::EffectBind, // 11 SPELL_EFFECT_BIND + &Spell::EffectNULL, // 12 SPELL_EFFECT_PORTAL + &Spell::EffectUnused, // 13 SPELL_EFFECT_RITUAL_BASE unused + &Spell::EffectUnused, // 14 SPELL_EFFECT_RITUAL_SPECIALIZE unused + &Spell::EffectUnused, // 15 SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL unused + &Spell::EffectQuestComplete, // 16 SPELL_EFFECT_QUEST_COMPLETE + &Spell::EffectWeaponDmg, // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL + &Spell::EffectResurrect, // 18 SPELL_EFFECT_RESURRECT + &Spell::EffectAddExtraAttacks, // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS + &Spell::EffectUnused, // 20 SPELL_EFFECT_DODGE one spell: Dodge + &Spell::EffectUnused, // 21 SPELL_EFFECT_EVADE one spell: Evade (DND) + &Spell::EffectParry, // 22 SPELL_EFFECT_PARRY + &Spell::EffectBlock, // 23 SPELL_EFFECT_BLOCK one spell: Block + &Spell::EffectCreateItem, // 24 SPELL_EFFECT_CREATE_ITEM + &Spell::EffectUnused, // 25 SPELL_EFFECT_WEAPON + &Spell::EffectUnused, // 26 SPELL_EFFECT_DEFENSE one spell: Defense + &Spell::EffectPersistentAA, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA + &Spell::EffectSummonType, // 28 SPELL_EFFECT_SUMMON + &Spell::EffectLeapForward, // 29 SPELL_EFFECT_LEAP + &Spell::EffectEnergize, // 30 SPELL_EFFECT_ENERGIZE + &Spell::EffectWeaponDmg, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE + &Spell::EffectTriggerMissileSpell, // 32 SPELL_EFFECT_TRIGGER_MISSILE + &Spell::EffectOpenLock, // 33 SPELL_EFFECT_OPEN_LOCK + &Spell::EffectSummonChangeItem, // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM + &Spell::EffectApplyAreaAura, // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY + &Spell::EffectLearnSpell, // 36 SPELL_EFFECT_LEARN_SPELL + &Spell::EffectUnused, // 37 SPELL_EFFECT_SPELL_DEFENSE one spell: SPELLDEFENSE (DND) + &Spell::EffectDispel, // 38 SPELL_EFFECT_DISPEL + &Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE + &Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD + &Spell::EffectJump, // 41 SPELL_EFFECT_JUMP + &Spell::EffectJumpDest, // 42 SPELL_EFFECT_JUMP_DEST + &Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER + &Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP + &Spell::EffectAddHonor, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related + &Spell::EffectUnused, // 46 SPELL_EFFECT_SPAWN clientside, unit appears as if it was just spawned + &Spell::EffectTradeSkill, // 47 SPELL_EFFECT_TRADE_SKILL + &Spell::EffectUnused, // 48 SPELL_EFFECT_STEALTH one spell: Base Stealth + &Spell::EffectUnused, // 49 SPELL_EFFECT_DETECT one spell: Detect + &Spell::EffectTransmitted, // 50 SPELL_EFFECT_TRANS_DOOR + &Spell::EffectUnused, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT unused + &Spell::EffectUnused, // 52 SPELL_EFFECT_GUARANTEE_HIT one spell: zzOLDCritical Shot + &Spell::EffectEnchantItemPerm, // 53 SPELL_EFFECT_ENCHANT_ITEM + &Spell::EffectEnchantItemTmp, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY + &Spell::EffectTameCreature, // 55 SPELL_EFFECT_TAMECREATURE + &Spell::EffectSummonPet, // 56 SPELL_EFFECT_SUMMON_PET + &Spell::EffectLearnPetSpell, // 57 SPELL_EFFECT_LEARN_PET_SPELL + &Spell::EffectWeaponDmg, // 58 SPELL_EFFECT_WEAPON_DAMAGE + &Spell::EffectCreateRandomItem, // 59 SPELL_EFFECT_CREATE_RANDOM_ITEM create item base at spell specific loot + &Spell::EffectProficiency, // 60 SPELL_EFFECT_PROFICIENCY + &Spell::EffectSendEvent, // 61 SPELL_EFFECT_SEND_EVENT + &Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN + &Spell::EffectThreat, // 63 SPELL_EFFECT_THREAT + &Spell::EffectTriggerSpell, // 64 SPELL_EFFECT_TRIGGER_SPELL + &Spell::EffectApplyAreaAura, // 65 SPELL_EFFECT_APPLY_AREA_AURA_RAID + &Spell::EffectRechargeManaGem, // 66 SPELL_EFFECT_CREATE_MANA_GEM (possibly recharge it, misc - is item ID) + &Spell::EffectHealMaxHealth, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH + &Spell::EffectInterruptCast, // 68 SPELL_EFFECT_INTERRUPT_CAST + &Spell::EffectDistract, // 69 SPELL_EFFECT_DISTRACT + &Spell::EffectPull, // 70 SPELL_EFFECT_PULL one spell: Distract Move + &Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET + &Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT + &Spell::EffectUnused, // 73 SPELL_EFFECT_UNTRAIN_TALENTS + &Spell::EffectApplyGlyph, // 74 SPELL_EFFECT_APPLY_GLYPH + &Spell::EffectHealMechanical, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit + &Spell::EffectSummonObjectWild, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD + &Spell::EffectScriptEffect, // 77 SPELL_EFFECT_SCRIPT_EFFECT + &Spell::EffectUnused, // 78 SPELL_EFFECT_ATTACK + &Spell::EffectSanctuary, // 79 SPELL_EFFECT_SANCTUARY + &Spell::EffectAddComboPoints, // 80 SPELL_EFFECT_ADD_COMBO_POINTS + &Spell::EffectUnused, // 81 SPELL_EFFECT_CREATE_HOUSE one spell: Create House (TEST) + &Spell::EffectNULL, // 82 SPELL_EFFECT_BIND_SIGHT + &Spell::EffectDuel, // 83 SPELL_EFFECT_DUEL + &Spell::EffectStuck, // 84 SPELL_EFFECT_STUCK + &Spell::EffectSummonPlayer, // 85 SPELL_EFFECT_SUMMON_PLAYER + &Spell::EffectActivateObject, // 86 SPELL_EFFECT_ACTIVATE_OBJECT + &Spell::EffectWMODamage, // 87 SPELL_EFFECT_WMO_DAMAGE + &Spell::EffectWMORepair, // 88 SPELL_EFFECT_WMO_REPAIR + &Spell::EffectUnused, // 89 SPELL_EFFECT_WMO_CHANGE // 0 intact // 1 damaged // 2 destroyed // 3 rebuilding + &Spell::EffectKillCreditPersonal, // 90 SPELL_EFFECT_KILL_CREDIT Kill credit but only for single person + &Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash + &Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM + &Spell::EffectForceDeselect, // 93 SPELL_EFFECT_FORCE_DESELECT + &Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT + &Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING + &Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE + &Spell::EffectCastButtons, // 97 SPELL_EFFECT_CAST_BUTTON (totem bar since 3.2.2a) + &Spell::EffectKnockBack, // 98 SPELL_EFFECT_KNOCK_BACK + &Spell::EffectDisEnchant, // 99 SPELL_EFFECT_DISENCHANT + &Spell::EffectInebriate, //100 SPELL_EFFECT_INEBRIATE + &Spell::EffectFeedPet, //101 SPELL_EFFECT_FEED_PET + &Spell::EffectDismissPet, //102 SPELL_EFFECT_DISMISS_PET + &Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION + &Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1 + &Spell::EffectSummonObject, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2 + &Spell::EffectSummonObject, //106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3 + &Spell::EffectSummonObject, //107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4 + &Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC + &Spell::EffectSummonDeadPet, //109 SPELL_EFFECT_SUMMON_DEAD_PET + &Spell::EffectDestroyAllTotems, //110 SPELL_EFFECT_DESTROY_ALL_TOTEMS + &Spell::EffectDurabilityDamage, //111 SPELL_EFFECT_DURABILITY_DAMAGE + &Spell::EffectUnused, //112 SPELL_EFFECT_112 + &Spell::EffectResurrectNew, //113 SPELL_EFFECT_RESURRECT_NEW + &Spell::EffectTaunt, //114 SPELL_EFFECT_ATTACK_ME + &Spell::EffectDurabilityDamagePCT, //115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT + &Spell::EffectSkinPlayerCorpse, //116 SPELL_EFFECT_SKIN_PLAYER_CORPSE one spell: Remove Insignia, bg usage, required special corpse flags... + &Spell::EffectSpiritHeal, //117 SPELL_EFFECT_SPIRIT_HEAL one spell: Spirit Heal + &Spell::EffectSkill, //118 SPELL_EFFECT_SKILL professions and more + &Spell::EffectApplyAreaAura, //119 SPELL_EFFECT_APPLY_AREA_AURA_PET + &Spell::EffectUnused, //120 SPELL_EFFECT_TELEPORT_GRAVEYARD one spell: Graveyard Teleport Test + &Spell::EffectWeaponDmg, //121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG + &Spell::EffectUnused, //122 SPELL_EFFECT_122 unused + &Spell::EffectSendTaxi, //123 SPELL_EFFECT_SEND_TAXI taxi/flight related (misc value is taxi path id) + &Spell::EffectPlayerPull, //124 SPELL_EFFECT_PLAYER_PULL opposite of knockback effect (pulls player twoard caster) + &Spell::EffectModifyThreatPercent, //125 SPELL_EFFECT_MODIFY_THREAT_PERCENT + &Spell::EffectStealBeneficialBuff, //126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF spell steal effect? + &Spell::EffectProspecting, //127 SPELL_EFFECT_PROSPECTING Prospecting spell + &Spell::EffectApplyAreaAura, //128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND + &Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY + &Spell::EffectRedirectThreat, //130 SPELL_EFFECT_REDIRECT_THREAT + &Spell::EffectPlayerNotification, //131 SPELL_EFFECT_PLAYER_NOTIFICATION + &Spell::EffectPlayMusic, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value (SoundEntries.dbc) + &Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization + &Spell::EffectKillCredit, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry + &Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET + &Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT + &Spell::EffectEnergizePct, //137 SPELL_EFFECT_ENERGIZE_PCT + &Spell::EffectLeapBack, //138 SPELL_EFFECT_LEAP_BACK Leap back + &Spell::EffectQuestClear, //139 SPELL_EFFECT_CLEAR_QUEST Reset quest status (miscValue - quest ID) + &Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST + &Spell::EffectForceCastWithValue, //141 SPELL_EFFECT_FORCE_CAST_WITH_VALUE + &Spell::EffectTriggerSpellWithValue, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE + &Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER + &Spell::EffectKnockBack, //144 SPELL_EFFECT_KNOCK_BACK_DEST + &Spell::EffectPlayerPull, //145 SPELL_EFFECT_145 Black Hole Effect + &Spell::EffectActivateRune, //146 SPELL_EFFECT_ACTIVATE_RUNE + &Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail + &Spell::EffectUnused, //148 SPELL_EFFECT_148 unused + &Spell::EffectChargeDest, //149 SPELL_EFFECT_CHARGE_DEST + &Spell::EffectUnused, //150 SPELL_EFFECT_150 unused + &Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2 + &Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend + &Spell::EffectNULL, //153 SPELL_EFFECT_CREATE_PET misc value is creature entry + &Spell::EffectNULL, //154 unused + &Spell::EffectTitanGrip, //155 SPELL_EFFECT_TITAN_GRIP Allows you to equip two-handed axes, maces and swords in one hand, but you attack $49152s1% slower than normal. + &Spell::EffectEnchantItemPrismatic, //156 SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC + &Spell::EffectCreateItem2, //157 SPELL_EFFECT_CREATE_ITEM_2 create item or create item template and replace by some randon spell loot item + &Spell::EffectMilling, //158 SPELL_EFFECT_MILLING milling + &Spell::EffectRenamePet, //159 SPELL_EFFECT_ALLOW_RENAME_PET allow rename pet once again + &Spell::EffectNULL, //160 SPELL_EFFECT_160 unused + &Spell::EffectSpecCount, //161 SPELL_EFFECT_TALENT_SPEC_COUNT second talent spec (learn/revert) + &Spell::EffectActivateSpec, //162 SPELL_EFFECT_TALENT_SPEC_SELECT activate primary/secondary spec + &Spell::EffectNULL, //163 + &Spell::EffectRemoveAura, //164 SPELL_EFFECT_REMOVE_AURA +}; + +void Spell::EffectNULL(uint32 /*i*/) +{ + sLog.outDebug("WORLD: Spell Effect DUMMY"); +} + +void Spell::EffectUnused(uint32 /*i*/) +{ + // NOT USED BY ANY SPELL OR USELESS OR IMPLEMENTED IN DIFFERENT WAY IN TRINITY +} + +void Spell::EffectResurrectNew(uint32 i) +{ + if (!unitTarget || unitTarget->isAlive()) + return; + + if (unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + if (!unitTarget->IsInWorld()) + return; + + Player* pTarget = unitTarget->ToPlayer(); + + if (pTarget->isRessurectRequested()) // already have one active request + return; + + uint32 health = damage; + uint32 mana = m_spellInfo->EffectMiscValue[i]; + pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana); + SendResurrectRequest(pTarget); +} + +void Spell::EffectInstaKill(uint32 /*i*/) +{ + if (!unitTarget || !unitTarget->isAlive()) + return; + + // Demonic Sacrifice + if (m_spellInfo->Id == 18788 && unitTarget->GetTypeId() == TYPEID_UNIT) + { + uint32 entry = unitTarget->GetEntry(); + uint32 spellID; + switch (entry) + { + case 416: spellID = 18789; break; //imp + case 417: spellID = 18792; break; //fellhunter + case 1860: spellID = 18790; break; //void + case 1863: spellID = 18791; break; //succubus + case 17252: spellID = 35701; break; //fellguard + default: + sLog.outError("EffectInstaKill: Unhandled creature entry (%u) case.", entry); + return; + } + + m_caster->CastSpell(m_caster, spellID, true); + } + + if (m_caster == unitTarget) // prevent interrupt message + finish(); + + m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); +} + +void Spell::EffectEnvirinmentalDMG(uint32 i) +{ + uint32 absorb = 0; + uint32 resist = 0; + + // Note: this hack with damage replace required until GO casting not implemented + // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support + // currently each enemy selected explicitly and self cast damage, we prevent apply self casted spell bonuses/etc + damage = SpellMgr::CalculateSpellEffectAmount(m_spellInfo, i, m_caster); + + m_caster->CalcAbsorbResist(m_caster, GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist, m_spellInfo); + + m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false); + if (m_caster->GetTypeId() == TYPEID_PLAYER) + m_caster->ToPlayer()->EnvironmentalDamage(DAMAGE_FIRE, damage); +} + +void Spell::EffectSchoolDMG(uint32 /*effect_idx*/) +{ +} + +void Spell::SpellDamageSchoolDmg(uint32 effect_idx) +{ + bool apply_direct_bonus = true; + + if (unitTarget && unitTarget->isAlive()) + { + switch (m_spellInfo->SpellFamilyName) + { + case SPELLFAMILY_GENERIC: + { + // Meteor like spells (divided damage to targets) + if (m_customAttr & SPELL_ATTR_CU_SHARE_DAMAGE) + { + uint32 count = 0; + for (std::list::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + if (ihit->effectMask & (1<Id) // better way to check unknown + { + // Positive/Negative Charge + case 28062: + case 28085: + case 39090: + case 39093: + if (!m_triggeredByAuraSpell) + break; + if (unitTarget == m_caster) + { + uint8 count = 0; + for (std::list::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + if (ihit->targetGUID != m_caster->GetGUID()) + if (Player *target = ObjectAccessor::FindPlayer(ihit->targetGUID)) + if (target->HasAura(m_triggeredByAuraSpell->Id)) + ++count; + if (count) + { + uint32 spellId = 0; + switch (m_spellInfo->Id) + { + case 28062: spellId = 29659; break; + case 28085: spellId = 29660; break; + case 39090: spellId = 39089; break; + case 39093: spellId = 39092; break; + } + m_caster->SetAuraStack(spellId, m_caster, count); + } + } + + if (unitTarget->HasAura(m_triggeredByAuraSpell->Id)) + damage = 0; + break; + // Consumption + case 28865: + damage = (((InstanceMap*)m_caster->GetMap())->GetDifficulty() == REGULAR_DIFFICULTY ? 2750 : 4250); + break; + // percent from health with min + case 25599: // Thundercrash + { + damage = unitTarget->GetHealth() / 2; + if (damage < 200) + damage = 200; + break; + } + // arcane charge. must only affect demons (also undead?) + case 45072: + { + if (unitTarget->GetCreatureType() != CREATURE_TYPE_DEMON + && unitTarget->GetCreatureType() != CREATURE_TYPE_UNDEAD) + return; + break; + } + case 33671: // gruul's shatter + case 50811: // krystallus shatter ( Normal ) + case 61547: // krystallus shatter ( Heroic ) + { + // don't damage self and only players + if (unitTarget->GetGUID() == m_caster->GetGUID() || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + float radius = GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[0])); + if (!radius) return; + float distance = m_caster->GetDistance2d(unitTarget); + damage = (distance > radius) ? 0 : int32(m_spellInfo->EffectBasePoints[0]*((radius - distance)/radius)); + break; + } + // TODO: add spell specific target requirement hook for spells + // Shadowbolts only affects targets with Shadow Mark (Gothik) + case 27831: + case 55638: + if (!unitTarget->HasAura(27825)) + return; + break; + // Cataclysmic Bolt + case 38441: + { + damage = unitTarget->GetMaxHealth() / 2; + break; + } + // Tympanic Tantrum + case 62775: + { + damage = unitTarget->GetMaxHealth() / 10; + break; + } + // Gargoyle Strike + case 51963: + { + // about +4 base spell dmg per level + damage = (m_caster->getLevel() - 60) * 4 + 60; + break; + } + + // Loken Pulsing Shockwave + case 59837: + case 52942: + { + // don't damage self and only players + if(unitTarget->GetGUID() == m_caster->GetGUID() || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + float radius = GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[0])); + if (!radius) + return; + float distance = m_caster->GetDistance2d(unitTarget); + damage = (distance > radius) ? 0 : int32(m_spellInfo->EffectBasePoints[0]*distance); + break; + } + } + break; + } + case SPELLFAMILY_WARRIOR: + { + // Bloodthirst + if (m_spellInfo->SpellFamilyFlags[1] & 0x400) + damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100); + // Shield Slam + else if (m_spellInfo->SpellFamilyFlags[1] & 0x200 && m_spellInfo->Category == 1209) + damage += m_caster->ApplyEffectModifiers(m_spellInfo,effect_idx,int32(m_caster->GetShieldBlockValue())); + // Victory Rush + else if (m_spellInfo->SpellFamilyFlags[1] & 0x100) + { + damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100); + m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false); + } + // Shockwave + else if (m_spellInfo->Id == 46968) + { + int32 pct = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, 2); + if (pct > 0) + damage+= int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * pct / 100); + break; + } + break; + } + case SPELLFAMILY_WARLOCK: + { + // Incinerate Rank 1 & 2 + if ((m_spellInfo->SpellFamilyFlags[1] & 0x000040) && m_spellInfo->SpellIconID == 2128) + { + // Incinerate does more dmg (dmg*0.25) if the target have Immolate debuff. + // Check aura state for speed but aura state set not only for Immolate spell + if (unitTarget->HasAuraState(AURA_STATE_CONFLAGRATE)) + { + if (unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x4, 0, 0)) + damage += damage/4; + } + } + // Conflagrate - consumes Immolate or Shadowflame + else if (m_spellInfo->TargetAuraState == AURA_STATE_CONFLAGRATE) + { + AuraEffect const* aura = NULL; // found req. aura for damage calculation + + Unit::AuraEffectList const &mPeriodic = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_DAMAGE); + for (Unit::AuraEffectList::const_iterator i = mPeriodic.begin(); i != mPeriodic.end(); ++i) + { + // for caster applied auras only + if ((*i)->GetSpellProto()->SpellFamilyName != SPELLFAMILY_WARLOCK || + (*i)->GetCasterGUID() != m_caster->GetGUID()) + continue; + + // Immolate + if ((*i)->GetSpellProto()->SpellFamilyFlags[0] & 0x4) + { + aura = *i; // it selected always if exist + break; + } + + // Shadowflame + if ((*i)->GetSpellProto()->SpellFamilyFlags[2] & 0x00000002) + aura = *i; // remember but wait possible Immolate as primary priority + } + + // found Immolate or Shadowflame + if (aura) + { + uint32 pdamage = aura->GetAmount() > 0 ? aura->GetAmount() : 0; + pdamage = m_caster->SpellDamageBonus(unitTarget, aura->GetSpellProto(), pdamage, DOT, aura->GetBase()->GetStackAmount()); + uint32 pct_dir = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, (effect_idx + 1)); + damage += pdamage * aura->GetTotalTicks() * pct_dir / 100; + + uint32 pct_dot = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, (effect_idx + 2)) / 3; + m_currentBasePoints[1] = SpellMgr::CalculateSpellEffectBaseAmount(pdamage * aura->GetTotalTicks() * pct_dot / 100); + + apply_direct_bonus = false; + // Glyph of Conflagrate + if (!m_caster->HasAura(56235)) + unitTarget->RemoveAurasDueToSpell(aura->GetId(), m_caster->GetGUID()); + + break; + } + } + // Shadow Bite + else if (m_spellInfo->SpellFamilyFlags[1] & 0x400000) + { + if (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->isPet()) + { + // Get DoTs on target by owner (5% increase by dot) + damage += 5 * unitTarget->GetDoTsByCaster(m_caster->GetOwnerGUID()) / 100; + } + } + break; + } + case SPELLFAMILY_PRIEST: + { + // Shadow Word: Death - deals damage equal to damage done to caster + if ((m_spellInfo->SpellFamilyFlags[1] & 0x2)) + { + int32 back_damage = m_caster->SpellDamageBonus(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE); + // Pain and Suffering reduces damage + if (AuraEffect * aurEff = m_caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 2874, 0)) + back_damage -= aurEff->GetAmount() * back_damage / 100; + + if (back_damage < unitTarget->GetHealth()) + m_caster->CastCustomSpell(m_caster, 32409, &back_damage, 0, 0, true); + } + // Mind Blast - applies Mind Trauma if: + else if (m_spellInfo->SpellFamilyFlags[2] & 0x00002000) + { + // We are in Shadow Form + if (m_caster->m_form == FORM_SHADOW) + // We have Improved Mind Blast + if (AuraEffect * aurEff = m_caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST,95,0)) + // Chance has been successfully rolled + if (roll_chance_i(aurEff->GetAmount())) + m_caster->CastSpell(unitTarget, 48301, true); + } + // Smite + else if (m_spellInfo->SpellFamilyFlags[0] & 0x80) + { + // Glyph of Smite + if (AuraEffect * aurEff = m_caster->GetAuraEffect(55692, 0)) + if (unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x100000, 0, 0, m_caster->GetGUID())) + damage += damage * aurEff->GetAmount() / 100; + } + // Improved Mind Blast (Mind Blast in shadow form bonus) + else if (m_caster->m_form == FORM_SHADOW && (m_spellInfo->SpellFamilyFlags[0] & 0x00002000)) + { + Unit::AuraEffectList const& ImprMindBlast = m_caster->GetAuraEffectsByType(SPELL_AURA_ADD_FLAT_MODIFIER); + for (Unit::AuraEffectList::const_iterator i = ImprMindBlast.begin(); i != ImprMindBlast.end(); ++i) + { + if ((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_PRIEST && + ((*i)->GetSpellProto()->SpellIconID == 95)) + { + int chance = SpellMgr::CalculateSpellEffectAmount((*i)->GetSpellProto(), 1, m_caster); + if (roll_chance_i(chance)) + // Mind Trauma + m_caster->CastSpell(unitTarget, 48301, true, 0); + break; + } + } + } + break; + } + case SPELLFAMILY_DRUID: + { + // Ferocious Bite + if (m_caster->GetTypeId() == TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags[0] & 0x000800000) && m_spellInfo->SpellVisual[0] == 6587) + { + // converts each extra point of energy into ($f1+$AP/410) additional damage + float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK); + float multiple = ap / 410 + m_spellInfo->DmgMultiplier[effect_idx]; + int32 energy = -(m_caster->ModifyPower(POWER_ENERGY, -30)); + damage += int32(energy * multiple); + damage += int32(m_caster->ToPlayer()->GetComboPoints() * ap * 7 / 100); + } + // Wrath + else if (m_spellInfo->SpellFamilyFlags[0] & 0x00000001) + { + // Improved Insect Swarm + if (AuraEffect const * aurEff = m_caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 1771, 0)) + if (unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00200000, 0, 0)) + damage = int32(damage*(100.0f+aurEff->GetAmount())/100.0f); + } + break; + } + case SPELLFAMILY_ROGUE: + { + // Envenom + if (m_caster->GetTypeId() == TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags[1] & 0x8)) + { + // consume from stack dozes not more that have combo-points + if (uint32 combo = m_caster->ToPlayer()->GetComboPoints()) + { + // Lookup for Deadly poison (only attacker applied) + if (AuraEffect const * aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_ROGUE, 0x10000, 0, 0, m_caster->GetGUID())) + { + // count consumed deadly poison doses at target + bool needConsume = true; + uint32 spellId = aurEff->GetId(); + uint32 doses = aurEff->GetBase()->GetStackAmount(); + if (doses > combo) + doses = combo; + // Master Poisoner + Unit::AuraEffectList const& auraList = m_caster->ToPlayer()->GetAuraEffectsByType(SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL_NOT_STACK); + for (Unit::AuraEffectList::const_iterator iter = auraList.begin(); iter != auraList.end(); ++iter) + { + if ((*iter)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_ROGUE && (*iter)->GetSpellProto()->SpellIconID == 1960) + { + uint32 chance = SpellMgr::CalculateSpellEffectAmount((*iter)->GetSpellProto(), 2, m_caster); + + if (chance && roll_chance_i(chance)) + needConsume = false; + + break; + } + } + + if (needConsume) + for (uint32 i = 0; i < doses; ++i) + unitTarget->RemoveAuraFromStack(spellId); + damage *= doses; + damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.09f * doses); + } + // Eviscerate and Envenom Bonus Damage (item set effect) + if (m_caster->HasAura(37169)) + damage += ((Player*)m_caster)->GetComboPoints()*40; + } + } + // Eviscerate + else if ((m_spellInfo->SpellFamilyFlags[0] & 0x00020000) && m_caster->GetTypeId() == TYPEID_PLAYER) + { + if (uint32 combo = ((Player*)m_caster)->GetComboPoints()) + { + float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK); + damage += irand(int32(ap * combo * 0.03f), int32(ap * combo * 0.07f)); + + // Eviscerate and Envenom Bonus Damage (item set effect) + if (m_caster->HasAura(37169)) + damage += combo*40; + } + } + break; + } + case SPELLFAMILY_HUNTER: + { + //Gore + if (m_spellInfo->SpellIconID == 1578) + { + if (m_caster->HasAura(57627)) // Charge 6 sec post-affect + damage *= 2; + } + // Steady Shot + else if (m_spellInfo->SpellFamilyFlags[1] & 0x1) + { + bool found = false; + // check dazed affect + Unit::AuraEffectList const& decSpeedList = unitTarget->GetAuraEffectsByType(SPELL_AURA_MOD_DECREASE_SPEED); + for (Unit::AuraEffectList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter) + { + if ((*iter)->GetSpellProto()->SpellIconID == 15 && (*iter)->GetSpellProto()->Dispel == 0) + { + found = true; + break; + } + } + + // TODO: should this be put on taken but not done? + if (found) + damage += m_spellInfo->EffectBasePoints[1]; + + if (m_caster->GetTypeId() == TYPEID_PLAYER) + { + // Add Ammo and Weapon damage plus RAP * 0.1 + Item *item = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK); + if (item) + { + float dmg_min = item->GetProto()->Damage->DamageMin; + float dmg_max = item->GetProto()->Damage->DamageMax; + if (dmg_max == 0.0f && dmg_min > dmg_max) + damage += int32(dmg_min); + else + damage += irand(int32(dmg_min), int32(dmg_max)); + damage += m_caster->ToPlayer()->GetAmmoDPS()*item->GetProto()->Delay*0.001f; + } + } + + } + break; + } + case SPELLFAMILY_PALADIN: + { + // Hammer of the Righteous + if (m_spellInfo->SpellFamilyFlags[1]&0x00040000) + { + // Add main hand dps * effect[2] amount + float average = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2; + int32 count = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, 2); + damage += count * int32(average * IN_MILLISECONDS) / m_caster->GetAttackTime(BASE_ATTACK); + } + // Shield of Righteousness + else if (m_spellInfo->SpellFamilyFlags[1]&0x00100000) + { + damage += int32(m_caster->GetShieldBlockValue() * 1.3f); + } + // Judgement of Righteousness + else if (m_spellInfo->Id == 20187) + { + float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK); + float sp = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)); + damage += int32(0.2f*ap + 0.32f*sp); + } + // Judgement of Wisdom, Light, Justice + else if (m_spellInfo->Id == 54158) + { + float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK); + float sp = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)); + damage += int32(0.14f*ap + 0.22f*sp); + } + break; + } + case SPELLFAMILY_DEATHKNIGHT: + { + // Blood Boil - bonus for diseased targets + if (m_spellInfo->SpellFamilyFlags[0] & 0x00040000 && unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, 0, 0, 0x00000002, m_caster->GetGUID())) + { + damage += m_damage / 2; + damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)* 0.035f); + } + break; + } + } + + if (m_originalCaster && damage > 0 && apply_direct_bonus) + damage = m_originalCaster->SpellDamageBonus(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE); + + m_damage += damage; + } +} + +void Spell::EffectDummy(uint32 i) +{ + if (!unitTarget && !gameObjTarget && !itemTarget) + return; + + uint32 spell_id = 0; + int32 bp = 0; + bool triggered = true; + SpellCastTargets targets; + + // selection by spell family + switch (m_spellInfo->SpellFamilyName) + { + case SPELLFAMILY_GENERIC: + { + switch (m_spellInfo->Id) + { + case 8063: // Deviate Fish + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + uint32 spell_id = 0; + switch(urand(1,5)) + { + case 1: spell_id = 8064; break; // Sleepy + case 2: spell_id = 8065; break; // Invigorate + case 3: spell_id = 8066; break; // Shrink + case 4: spell_id = 8067; break; // Party Time! + case 5: spell_id = 8068; break; // Healthy Spirit + } + m_caster->CastSpell(m_caster, spell_id, true, NULL); + return; + } + case 8213: // Savory Deviate Delight + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + uint32 spell_id = 0; + switch(urand(1,2)) + { + // Flip Out - ninja + case 1: spell_id = (m_caster->getGender() == GENDER_MALE ? 8219 : 8220); break; + // Yaaarrrr - pirate + case 2: spell_id = (m_caster->getGender() == GENDER_MALE ? 8221 : 8222); break; + } + m_caster->CastSpell(m_caster,spell_id,true,NULL); + return; + } + case 8593: // Symbol of life (restore creature to life) + case 31225: // Shimmering Vessel (restore creature to life) + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) + return; + unitTarget->ToCreature()->setDeathState(JUST_ALIVED); + return; + } + case 12162: // Deep wounds + case 12850: // (now good common check for this spells) + case 12868: + { + if (!unitTarget) + return; + + float damage; + // 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 (m_caster->haveOffhandWeapon() && m_caster->getAttackTimer(BASE_ATTACK) > m_caster->getAttackTimer(OFF_ATTACK)) + damage = (m_caster->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE))/2; + else + damage = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE))/2; + + switch (m_spellInfo->Id) + { + case 12162: damage *= 0.16f; break; // Rank 1 + case 12850: damage *= 0.32f; break; // Rank 2 + case 12868: damage *= 0.48f; break; // Rank 3 + default: + sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id); + return; + }; + + // get remaining damage of old Deep Wound aura + AuraEffect* deepWound = unitTarget->GetAuraEffect(12721, 0); + if (deepWound) + { + int32 remainingTicks = deepWound->GetBase()->GetDuration() / deepWound->GetAmplitude(); + damage += remainingTicks * deepWound->GetAmount(); + } + + // 1 tick/sec * 6 sec = 6 ticks + int32 deepWoundsDotBasePoints0 = int32(damage / 6); + m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL); + return; + } + case 13120: // net-o-matic + { + if (!unitTarget) + return; + + uint32 spell_id = 0; + + uint32 roll = urand(0, 99); + + if (roll < 2) // 2% for 30 sec self root (off-like chance unknown) + spell_id = 16566; + else if (roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown) + spell_id = 13119; + else // normal root + spell_id = 13099; + + m_caster->CastSpell(unitTarget,spell_id,true,NULL); + return; + } + case 67019: // Flask of the North + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + uint32 spell_id; + switch(urand(1, 3)) + { + case 1: spell_id = 67016; break; + case 2: spell_id = 67017; break; + default:spell_id = 67018; break; + } + + m_caster->CastSpell(m_caster, spell_id, true, NULL); + return; + } + case 13280: // Gnomish Death Ray + { + if (!unitTarget) + return; + + if (urand(0, 99) < 15) + m_caster->CastSpell(m_caster, 13493, true, NULL); // failure + else + m_caster->CastSpell(unitTarget, 13279, true, NULL); + + return; + } + case 13567: // Dummy Trigger + { + // can be used for different aura triggering, so select by aura + if (!m_triggeredByAuraSpell || !unitTarget) + return; + + switch (m_triggeredByAuraSpell->Id) + { + case 26467: // Persistent Shield + m_caster->CastCustomSpell(unitTarget, 26470, &damage, NULL, NULL, true); + break; + default: + sLog.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u",m_triggeredByAuraSpell->Id); + break; + } + return; + } + case 14537: // Six Demon Bag + { + if( !unitTarget || !unitTarget->isAlive()) return; + + uint32 ClearSpellId[6] = + { + 15662, // Fireball + 11538, // Frostball + 21179, // Chain Lightning + 14621, // Polymorph + 25189, // Enveloping Winds + 14642 // Summon Felhund minion + }; + + uint32 effect = 0; + uint32 rand = urand(0, 100); + + if (rand >= 0 && rand < 25) // Fireball (25% chance) + effect = ClearSpellId[0]; + else if (rand >= 25 && rand < 50) // Frostball (25% chance) + effect = ClearSpellId[1]; + else if (rand >=50 && rand < 70) // Chain Lighting (25% chance) + effect = ClearSpellId[2]; + else if (rand >= 70 && rand < 80) // Polymorph (10% chance) + { + effect = ClearSpellId[3]; + if (urand(0, 100) <= 30) // 30% chance to self-cast + unitTarget = m_caster; + } + else if (rand >=80 && rand < 95) // Enveloping Winds (15% chance) + effect = ClearSpellId[4]; + else // Summon Felhund minion (5% chance) + { + effect = ClearSpellId[5]; + unitTarget = m_caster; + } + + m_caster->CastSpell(unitTarget, effect, true); + return; + } + case 15998: // Capture Worg Pup + case 29435: // Capture Female Kaliri Hatchling + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) + return; + + unitTarget->ToCreature()->ForcedDespawn(); + return; + } + case 16589: // Noggenfogger Elixir + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + uint32 spell_id = 0; + switch (urand(1, 3)) + { + case 1: spell_id = 16595; break; + case 2: spell_id = 16593; break; + default:spell_id = 16591; break; + } + + m_caster->CastSpell(m_caster, spell_id, true, NULL); + return; + } + case 17251: // Spirit Healer Res + { + if (!unitTarget || !m_originalCaster) + return; + + if (m_originalCaster->GetTypeId() == TYPEID_PLAYER) + { + WorldPacket data(SMSG_SPIRIT_HEALER_CONFIRM, 8); + data << uint64(unitTarget->GetGUID()); + m_originalCaster->ToPlayer()->GetSession()->SendPacket(&data); + } + return; + } + case 17271: // Test Fetid Skull + { + if (!itemTarget && m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + uint32 spell_id = roll_chance_i(50) + ? 17269 // Create Resonating Skull + : 17270; // Create Bone Dust + + m_caster->CastSpell(m_caster, spell_id, true, NULL); + return; + } + case 20577: // Cannibalize + if (unitTarget) + m_caster->CastSpell(m_caster, 20578, false, NULL); + return; + case 23019: // Crystal Prison Dummy DND + { + if (!unitTarget || !unitTarget->isAlive() || unitTarget->GetTypeId() != TYPEID_UNIT || unitTarget->ToCreature()->isPet()) + return; + + Creature* creatureTarget = unitTarget->ToCreature(); + + m_caster->SummonGameObject(179644, creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(), creatureTarget->GetOrientation(), 0, 0, 0, 0, creatureTarget->GetRespawnTime()-time(NULL)); + sLog.outDebug("SummonGameObject at SpellEfects.cpp EffectDummy for Spell 23019"); + + creatureTarget->ForcedDespawn(); + + return; + } + case 23074: // Arcanite Dragonling + if (!m_CastItem) return; + m_caster->CastSpell(m_caster, 19804, true, m_CastItem); + return; + case 23075: // Mithril Mechanical Dragonling + if (!m_CastItem) return; + m_caster->CastSpell(m_caster, 12749, true, m_CastItem); + return; + case 23076: // Mechanical Dragonling + if (!m_CastItem) return; + m_caster->CastSpell(m_caster, 4073, true, m_CastItem); + return; + case 23133: // Gnomish Battle Chicken + if (!m_CastItem) return; + m_caster->CastSpell(m_caster, 13166, true, m_CastItem); + return; + case 23448: // Transporter Arrival - Ultrasafe Transporter: Gadgetzan - backfires + { + int32 r = irand(0, 119); + if (r < 20) // Transporter Malfunction - 1/6 polymorph + m_caster->CastSpell(m_caster, 23444, true); + else if (r < 100) // Evil Twin - 4/6 evil twin + m_caster->CastSpell(m_caster, 23445, true); + else // Transporter Malfunction - 1/6 miss the target + m_caster->CastSpell(m_caster, 36902, true); + return; + } + case 23453: // Gnomish Transporter - Ultrasafe Transporter: Gadgetzan + if (roll_chance_i(50)) // Gadgetzan Transporter - success + m_caster->CastSpell(m_caster, 23441, true); + else // Gadgetzan Transporter Failure - failure + m_caster->CastSpell(m_caster, 23446, true); + return; + case 23645: // Hourglass Sand + m_caster->RemoveAurasDueToSpell(23170); // Brood Affliction: Bronze + return; + case 23725: // Gift of Life (warrior bwl trinket) + m_caster->CastSpell(m_caster, 23782, true); + m_caster->CastSpell(m_caster, 23783, true); + return; + case 25860: // Reindeer Transformation + { + if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED)) + return; + + float flyspeed = m_caster->GetSpeedRate(MOVE_FLIGHT); + float speed = m_caster->GetSpeedRate(MOVE_RUN); + + m_caster->RemoveAurasByType(SPELL_AURA_MOUNTED); + + //5 different spells used depending on mounted speed and if mount can fly or not + if (flyspeed >= 4.1f) + // Flying Reindeer + m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer + else if (flyspeed >= 3.8f) + // Flying Reindeer + m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer + else if (flyspeed >= 1.6f) + // Flying Reindeer + m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer + else if (speed >= 2.0f) + // Reindeer + m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer + else + // Reindeer + m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer + + return; + } + case 26074: // Holiday Cheer + // implemented at client side + return; + case 28006: // Arcane Cloaking + { + if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER) + // Naxxramas Entry Flag Effect DND + m_caster->CastSpell(unitTarget, 29294, true); + return; + } + // Polarity Shift + case 28089: + if (unitTarget) + unitTarget->CastSpell(unitTarget, roll_chance_i(50) ? 28059 : 28084, true, NULL, NULL, m_caster->GetGUID()); + break; + // Polarity Shift + case 39096: + if (unitTarget) + unitTarget->CastSpell(unitTarget, roll_chance_i(50) ? 39088 : 39091, true, NULL, NULL, m_caster->GetGUID()); + break; + case 29200: // Purify Helboar Meat + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + uint32 spell_id = roll_chance_i(50) + ? 29277 // Summon Purified Helboar Meat + : 29278; // Summon Toxic Helboar Meat + + m_caster->CastSpell(m_caster,spell_id,true,NULL); + return; + } + case 29858: // Soulshatter + if (unitTarget && unitTarget->CanHaveThreatList() + && unitTarget->getThreatManager().getThreat(m_caster) > 0.0f) + m_caster->CastSpell(unitTarget,32835,true); + return; + case 30458: // Nigh Invulnerability + if (!m_CastItem) return; + if (roll_chance_i(86)) // Nigh-Invulnerability - success + m_caster->CastSpell(m_caster, 30456, true, m_CastItem); + else // Complete Vulnerability - backfire in 14% casts + m_caster->CastSpell(m_caster, 30457, true, m_CastItem); + return; + case 30507: // Poultryizer + if (!m_CastItem) return; + if (roll_chance_i(80)) // Poultryized! - success + m_caster->CastSpell(unitTarget, 30501, true, m_CastItem); + else // Poultryized! - backfire 20% + m_caster->CastSpell(unitTarget, 30504, true, m_CastItem); + return; + case 33060: // Make a Wish + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + uint32 spell_id = 0; + + switch(urand(1,5)) + { + case 1: spell_id = 33053; break; // Mr Pinchy's Blessing + case 2: spell_id = 33057; break; // Summon Mighty Mr. Pinchy + case 3: spell_id = 33059; break; // Summon Furious Mr. Pinchy + case 4: spell_id = 33062; break; // Tiny Magical Crawdad + case 5: spell_id = 33064; break; // Mr. Pinchy's Gift + } + + m_caster->CastSpell(m_caster, spell_id, true, NULL); + return; + } + case 34665: //Administer Antidote + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT + || unitTarget->GetEntry() != 16880 || unitTarget->ToCreature()->isPet()) + return; + + unitTarget->ToCreature()->UpdateEntry(16992); + m_caster->ToPlayer()->RewardPlayerAndGroupAtEvent(16992, unitTarget); + + if (unitTarget->IsAIEnabled) + unitTarget->ToCreature()->AI()->AttackStart(m_caster); + + return; + } + case 35745: // Socrethar's Stone + { + uint32 spell_id; + switch(m_caster->GetAreaId()) + { + case 3900: spell_id = 35743; break; // Socrethar Portal + case 3742: spell_id = 35744; break; // Socrethar Portal + default: return; + } + + m_caster->CastSpell(m_caster, spell_id, true); + return; + } + case 37674: // Chaos Blast + { + if (!unitTarget) + return; + + int32 basepoints0 = 100; + m_caster->CastCustomSpell(unitTarget, 37675, &basepoints0, NULL, NULL, true); + return; + } + case 40109: // Knockdown Fel Cannon: The Bolt + { + unitTarget->CastSpell(unitTarget, 40075, true); + return; + } + case 40802: // Mingo's Fortune Generator (Mingo's Fortune Giblets) + { + // selecting one from Bloodstained Fortune item + uint32 newitemid; + switch(urand(1, 20)) + { + case 1: newitemid = 32688; break; + case 2: newitemid = 32689; break; + case 3: newitemid = 32690; break; + case 4: newitemid = 32691; break; + case 5: newitemid = 32692; break; + case 6: newitemid = 32693; break; + case 7: newitemid = 32700; break; + case 8: newitemid = 32701; break; + case 9: newitemid = 32702; break; + case 10: newitemid = 32703; break; + case 11: newitemid = 32704; break; + case 12: newitemid = 32705; break; + case 13: newitemid = 32706; break; + case 14: newitemid = 32707; break; + case 15: newitemid = 32708; break; + case 16: newitemid = 32709; break; + case 17: newitemid = 32710; break; + case 18: newitemid = 32711; break; + case 19: newitemid = 32712; break; + case 20: newitemid = 32713; break; + default: + return; + } + + DoCreateItem(i, newitemid); + return; + } + // Wrath of the Astromancer + case 42784: + { + uint32 count = 0; + for (std::list::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + if (ihit->effectMask & (1<::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + if (ihit->effectMask & (1<targetGUID)) + m_caster->DealDamage(casttarget, damage, NULL, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_ARCANE, spellInfo, false); + } + + return; + } + // Demon Broiled Surprise + case 43723: + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player *player = (Player*)m_caster; + + if (player && player->GetQuestStatus(11379) == QUEST_STATUS_INCOMPLETE) + { + Creature *creature = player->FindNearestCreature(19973, 10, false); + if (!creature) + { + SendCastResult(SPELL_FAILED_NOT_HERE); + return; + } + + player->CastSpell(player, 43753, false); + } + return; + } + case 44875: // Complete Raptor Capture + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) + return; + + unitTarget->ToCreature()->ForcedDespawn(); + + //cast spell Raptor Capture Credit + m_caster->CastSpell(m_caster, 42337, true, NULL); + return; + } + case 44997: // Converting Sentry + { + //Converted Sentry Credit + m_caster->CastSpell(m_caster, 45009, true); + return; + } + case 45030: // Impale Emissary + { + // Emissary of Hate Credit + m_caster->CastSpell(m_caster, 45088, true); + return; + } + case 47170: // Impale Leviroth + { + if (!unitTarget && unitTarget->GetEntry() != 26452 && ((unitTarget->GetHealth() / unitTarget->GetMaxHealth()) * 100.0f) > 95.0f) + return; + + m_caster->DealDamage(unitTarget, unitTarget->GetMaxHealth()*0.93f); + return; + } + case 49625: // Brave's Flare + { + //Trigger Brave's Flare Effect (with EffectTarget) + m_caster->CastSpell(m_caster, 43106, true); + return; + } + case 49634: // Sergeant's Flare + { + //Trigger Sergeant's Flare Effect (with EffectTarget) + m_caster->CastSpell(m_caster, 43068, true); + return; + } + case 49357: // Brewfest Mount Transformation + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED)) + return; + m_caster->RemoveAurasByType(SPELL_AURA_MOUNTED); + // Ram for Alliance, Kodo for Horde + if (m_caster->ToPlayer()->GetTeam() == ALLIANCE) + { + if (m_caster->GetSpeedRate(MOVE_RUN) >= 2.0f) + // 100% Ram + m_caster->CastSpell(m_caster, 43900, true); + else + // 60% Ram + m_caster->CastSpell(m_caster, 43899, true); + } + else + { + if (m_caster->ToPlayer()->GetSpeedRate(MOVE_RUN) >= 2.0f) + // 100% Kodo + m_caster->CastSpell(m_caster, 49379, true); + else + // 60% Kodo + m_caster->CastSpell(m_caster, 49378, true); + } + return; + // Magic Pull + case 51336: + m_caster->CastSpell(unitTarget,50770,true); + break; + case 52845: // Brewfest Mount Transformation (Faction Swap) + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED)) + return; + m_caster->RemoveAurasByType(SPELL_AURA_MOUNTED); + // Ram for Horde, Kodo for Alliance + if (m_caster->ToPlayer()->GetTeam() == HORDE) + { + if (m_caster->GetSpeedRate(MOVE_RUN) >= 2.0f) + // 100% Ram + m_caster->CastSpell(m_caster, 43900, true); + else + // 60% Ram + m_caster->CastSpell(m_caster, 43899, true); + } + else + { + if (m_caster->ToPlayer()->GetSpeedRate(MOVE_RUN) >= 2.0f) + // 100% Kodo + m_caster->CastSpell(m_caster, 49379, true); + else + // 60% Kodo + m_caster->CastSpell(m_caster, 49378, true); + } + return; + case 55004: // Nitro Boosts + if (!m_CastItem) + return; + if (roll_chance_i(95)) // Nitro Boosts - success + m_caster->CastSpell(m_caster, 54861, true, m_CastItem); + else // Knocked Up - backfire 5% + m_caster->CastSpell(m_caster, 46014, true, m_CastItem); + return; + case 50243: // Teach Language + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + // spell has a 1/3 chance to trigger one of the below + if (roll_chance_i(66)) + return; + if (m_caster->ToPlayer()->GetTeam() == ALLIANCE) + { + // 1000001 - gnomish binary + m_caster->CastSpell(m_caster, 50242, true); + } + else + { + // 01001000 - goblin binary + m_caster->CastSpell(m_caster, 50246, true); + } + + return; + } + case 51582: //Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite) + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + if (BattleGround* bg = m_caster->ToPlayer()->GetBattleGround()) + bg->EventPlayerDroppedFlag(m_caster->ToPlayer()); + + m_caster->CastSpell(m_caster, 30452, true, NULL); + return; + } + case 51592: // Pickup Primordial Hatchling + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) + return; + + unitTarget->ToCreature()->ForcedDespawn(); + return; + + } + case 52308: // Take Sputum Sample + { + switch(i) + { + case 0: + { + uint32 spellID = SpellMgr::CalculateSpellEffectAmount(m_spellInfo, 0); + uint32 reqAuraID = SpellMgr::CalculateSpellEffectAmount(m_spellInfo, 1); + + if (m_caster->HasAuraEffect(reqAuraID,0)) + m_caster->CastSpell(m_caster,spellID,true,NULL); + return; + } + case 1: + return; // additional data for dummy[0] + } + return; + } + case 52759: // Ancestral Awakening + if (!unitTarget) + return; + m_caster->CastCustomSpell(unitTarget, 52752, &damage, NULL, NULL, true); + return; + case 53341: // Rune of Cinderglacier + case 53343: // Rune of Razorice + { + // Runeforging Credit + m_caster->CastSpell(m_caster, 54586, true); + return; + } + case 54171: //Divine Storm + { + m_caster->CastCustomSpell(unitTarget, 54172, &damage, 0, 0, true); + return; + } + case 58418: // Portal to Orgrimmar + case 58420: // Portal to Stormwind + return; // implemented in EffectScript[0] + case 59640: // Underbelly Elixir + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + uint32 spell_id = 0; + switch(urand(1,3)) + { + case 1: spell_id = 59645; break; + case 2: spell_id = 59831; break; + case 3: spell_id = 59843; break; + } + m_caster->CastSpell(m_caster,spell_id,true,NULL); + return; + } + case 62324: // Throw Passenger + { + if (m_targets.HasTraj()) + { + if (Vehicle *vehicle = m_caster->GetVehicleKit()) + if (Unit *passenger = vehicle->GetPassenger(damage - 1)) + { + std::list unitList; + // use 99 because it is 3d search + SearchAreaTarget(unitList, 99, PUSH_DST_CENTER, SPELL_TARGETS_ENTRY, 33114); + float minDist = 99 * 99; + Vehicle *target = NULL; + for (std::list::iterator itr = unitList.begin(); itr != unitList.end(); ++itr) + { + if (Vehicle *seat = (*itr)->GetVehicleKit()) + if (!seat->GetPassenger(0)) + if (Unit *device = seat->GetPassenger(2)) + if (!device->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) + { + float dist = (*itr)->GetExactDistSq(&m_targets.m_dstPos); + if (dist < minDist) + { + minDist = dist; + target = seat; + } + } + } + if (target && target->GetBase()->IsWithinDist2d(&m_targets.m_dstPos, GetSpellRadius(m_spellInfo, i, false) * 2)) // now we use *2 because the location of the seat is not correct + passenger->EnterVehicle(target, 0); + else + { + passenger->ExitVehicle(); + float x, y, z; + m_targets.m_dstPos.GetPosition(x, y, z); + passenger->GetMotionMaster()->MoveJump(x, y, z, m_targets.GetSpeedXY(), m_targets.GetSpeedZ()); + } + } + } + return; + } + case 64385: // Unusual Compass + { + m_caster->SetOrientation(float(urand(0,62832)) / 10000.0f); + WorldPacket data; + m_caster->BuildHeartBeatMsg(&data); + m_caster->SendMessageToSet(&data,true); + return; + } + } + + break; + } + case SPELLFAMILY_MAGE: + switch(m_spellInfo->Id) + { + case 11958: // Cold Snap + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + // immediately finishes the cooldown on Frost spells + const SpellCooldowns& cm = m_caster->ToPlayer()->GetSpellCooldownMap(); + for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();) + { + SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); + + if (spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && + (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) && + spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0) + { + m_caster->ToPlayer()->RemoveSpellCooldown((itr++)->first, true); + } + else + ++itr; + } + return; + } + case 32826: // Polymorph Cast Visual + { + if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT) + { + //Polymorph Cast Visual Rank 1 + const uint32 spell_list[6] = { + 32813, // Squirrel Form + 32816, // Giraffe Form + 32817, // Serpent Form + 32818, // Dragonhawk Form + 32819, // Worgen Form + 32820 // Sheep Form + }; + unitTarget->CastSpell(unitTarget, spell_list[urand(0, 5)], true); + } + return; + } + case 31687: // Summon Water Elemental + { + if (!unitTarget) + return; + + // Glyph of Eternal Water + if (unitTarget->HasAura(70937)) + unitTarget->CastSpell(unitTarget, 70908, true); + else + unitTarget->CastSpell(unitTarget, 70907, true); + } + } + break; + case SPELLFAMILY_WARRIOR: + // Charge + if (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_WARRIOR_CHARGE && m_spellInfo->SpellVisual[0] == 867) + { + int32 chargeBasePoints0 = damage; + m_caster->CastCustomSpell(m_caster, 34846, &chargeBasePoints0, NULL, NULL, true); + + //Juggernaut crit bonus + if (m_caster->HasAura(64976)) + m_caster->CastSpell(m_caster, 65156, true); + return; + } + //Slam + if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_WARRIOR_SLAM && m_spellInfo->SpellIconID == 559) + { + int32 bp0 = damage; + m_caster->CastCustomSpell(unitTarget, 50783, &bp0, NULL, NULL, true, 0); + return; + } + // Execute + if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_WARRIOR_EXECUTE) + { + if (!unitTarget) + return; + + uint32 rage = m_caster->GetPower(POWER_RAGE); + + // Glyph of Execution bonus + if (AuraEffect *aura = m_caster->GetAuraEffect(58367, 0)) + rage += aura->GetAmount(); + + spell_id = 20647; + + // Sudden death cost modifier + if (Aura * aur = m_caster->GetAura(52437)) + { + rage += m_powerCost; + m_caster->ModifyPower(POWER_RAGE, -m_powerCost); + if (m_caster->GetPower(POWER_RAGE) < 100) + m_caster->SetPower(POWER_RAGE, 100); + m_caster->RemoveAura(aur); + } + else + { + rage += m_powerCost; + m_caster->ModifyPower(POWER_RAGE, -m_powerCost); + } + + if (rage > 300) + rage = 300; + + bp = damage+int32(rage * m_spellInfo->DmgMultiplier[i] + + m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f); + break; + } + // Concussion Blow + if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_WARRIOR_CONCUSSION_BLOW) + { + m_damage+= uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100); + return; + } + switch(m_spellInfo->Id) + { + // Warrior's Wrath + case 21977: + { + if (!unitTarget) + return; + m_caster->CastSpell(unitTarget, 21887, true);// spell mod + return; + } + // Last Stand + case 12975: + { + int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3); + m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, NULL, NULL, true, NULL); + return; + } + // Bloodthirst + case 23881: + { + m_caster->CastCustomSpell(unitTarget, 23885, &damage, NULL, NULL, true, NULL); + return; + } + } + break; + case SPELLFAMILY_WARLOCK: + // Life Tap + if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_WARLOCK_LIFETAP) + { + float spFactor = 0; + switch (m_spellInfo->Id) + { + case 11689: spFactor = 0.2; break; + case 27222: + case 57946: spFactor = 0.5; break; + default: spFactor = 0; break; + } + int32 damage = m_spellInfo->EffectBasePoints[0] + (6.3875 * m_spellInfo->baseLevel); + int32 mana = damage + (m_caster->ToPlayer()->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+SPELL_SCHOOL_SHADOW) * spFactor); + + if (unitTarget && (int32(unitTarget->GetHealth()) > damage)) + { + // Shouldn't Appear in Combat Log + unitTarget->ModifyHealth(-damage); + + // Improved Life Tap mod + if (AuraEffect const * aurEff = m_caster->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, 208, 0)) + mana = (aurEff->GetAmount() + 100)* mana / 100; + + m_caster->CastCustomSpell(unitTarget, 31818, &mana, NULL, NULL, true); + + // Mana Feed + int32 manaFeedVal = 0; + if (AuraEffect const * aurEff = m_caster->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_WARLOCK, 1982, 0)) + manaFeedVal = aurEff->GetAmount(); + + if (manaFeedVal > 0) + { + manaFeedVal = manaFeedVal * mana / 100; + m_caster->CastCustomSpell(m_caster, 32553, &manaFeedVal, NULL, NULL, true, NULL); + } + } + else + SendCastResult(SPELL_FAILED_FIZZLE); + return; + } + break; + case SPELLFAMILY_PRIEST: + // Penance + if (m_spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_PRIEST_PENANCE) + { + if (!unitTarget || !unitTarget->isAlive()) + return; + + int hurt = 0; + int heal = 0; + switch(m_spellInfo->Id) + { + case 47540: hurt = 47758; heal = 47757; break; + case 53005: hurt = 53001; heal = 52986; break; + case 53006: hurt = 53002; heal = 52987; break; + case 53007: hurt = 53003; heal = 52988; break; + default: + sLog.outError("Spell::EffectDummy: Spell %u Penance need set correct heal/damage spell", m_spellInfo->Id); + return; + } + if (m_caster->IsFriendlyTo(unitTarget)) + m_caster->CastSpell(unitTarget, heal, false, 0); + else + m_caster->CastSpell(unitTarget, hurt, false, 0); + return; + } + break; + case SPELLFAMILY_DRUID: + // Starfall + if (m_spellInfo->SpellFamilyFlags[2] & SPELLFAMILYFLAG2_DRUID_STARFALL) + { + //Shapeshifting into an animal form or mounting cancels the effect. + if (m_caster->GetCreatureType() == CREATURE_TYPE_BEAST || m_caster->IsMounted()) + { + if (m_triggeredByAuraSpell) + m_caster->RemoveAurasDueToSpell(m_triggeredByAuraSpell->Id); + return; + } + + //Any effect which causes you to lose control of your character will supress the starfall effect. + if (m_caster->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_ROOT | UNIT_STAT_CONFUSED)) + return; + + m_caster->CastSpell(unitTarget, damage, true); + return; + } + break; + case SPELLFAMILY_ROGUE: + // Hunger for Blood + if (m_spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_HUNGERFORBLOOD) + { + m_caster->CastSpell(m_caster, 63848, true); + break; + } + switch (m_spellInfo->Id) + { + case 5938: // Shiv + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + m_caster->CastSpell(unitTarget, 5940, true); + return; + } + case 14185: // Preparation + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + //immediately finishes the cooldown on certain Rogue abilities + const SpellCooldowns& cm = m_caster->ToPlayer()->GetSpellCooldownMap(); + for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();) + { + SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); + + if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE) + { + if (spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_COLDB_SHADOWSTEP || // Cold Blood, Shadowstep + spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_VAN_EVAS_SPRINT // Vanish, Evasion, Sprint + ) + m_caster->ToPlayer()->RemoveSpellCooldown((itr++)->first, true); + else if (m_caster->HasAura(56819)) // Glyph of Preparation + { + if (spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_DISMANTLE || // Dismantle + spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_KICK || // Kick + ( + spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_BLADE_FLURRY && // Blade Flurry + spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_BLADE_FLURRY + ) + ) + m_caster->ToPlayer()->RemoveSpellCooldown((itr++)->first, true); + else + ++itr; + } + else + ++itr; + } + else + ++itr; + } + return; + } + case 31231: // Cheat Death + { + m_caster->CastSpell(m_caster, 45182, true); + return; + } + } + break; + case SPELLFAMILY_HUNTER: + switch(m_spellInfo->Id) + { + case 23989: // Readiness talent + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + // immediately finishes the cooldown on your other Hunter abilities except Bestial Wrath + const SpellCooldowns& cm = m_caster->ToPlayer()->GetSpellCooldownMap(); + for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();) + { + SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); + + if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && spellInfo->Id != 19574 && GetSpellRecoveryTime(spellInfo) > 0) + m_caster->ToPlayer()->RemoveSpellCooldown((itr++)->first,true); + else + ++itr; + } + return; + } + case 37506: // Scatter Shot + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + // break Auto Shot and autohit + m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL); + m_caster->AttackStop(); + m_caster->ToPlayer()->SendAttackSwingCancelAttack(); + return; + } + // Last Stand (pet) + case 53478: + { + int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3); + m_caster->CastCustomSpell(m_caster, 53479, &healthModSpellBasePoints0, NULL, NULL, true, NULL); + return; + } + // Master's Call + case 53271: + { + if (m_caster->GetTypeId() != TYPEID_PLAYER || !unitTarget) + return; + + if (Pet *pPet = m_caster->ToPlayer()->GetPet()) + if (pPet->isAlive()) + pPet->CastSpell(unitTarget, SpellMgr::CalculateSpellEffectAmount(m_spellInfo, i), true); + return; + } + } + break; + case SPELLFAMILY_PALADIN: + // Divine Storm + if (m_spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_PALADIN_DIVINESTORM && i == 1) + { + int32 dmg = m_damage * damage / 100; + if (!unitTarget) + unitTarget = m_caster; + m_caster->CastCustomSpell(unitTarget, 54171, &dmg, 0, 0, true); + return; + } + switch(m_spellInfo->SpellIconID) + { + case 156: // Holy Shock + { + if (!unitTarget) + return; + + int hurt = 0; + int heal = 0; + + switch(m_spellInfo->Id) + { + case 20473: hurt = 25912; heal = 25914; break; + case 20929: hurt = 25911; heal = 25913; break; + case 20930: hurt = 25902; heal = 25903; break; + case 27174: hurt = 27176; heal = 27175; break; + case 33072: hurt = 33073; heal = 33074; break; + case 48824: hurt = 48822; heal = 48820; break; + case 48825: hurt = 48823; heal = 48821; break; + default: + sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id); + return; + } + + if (m_caster->IsFriendlyTo(unitTarget)) + m_caster->CastSpell(unitTarget, heal, true, 0); + else + m_caster->CastSpell(unitTarget, hurt, true, 0); + + return; + } + } + + switch(m_spellInfo->Id) + { + case 20425: // Judgement of command + { + if (!unitTarget) + return; + + SpellEntry const* spell_proto = sSpellStore.LookupEntry(damage); + if (!spell_proto) + return; + + m_caster->CastSpell(unitTarget, spell_proto, true, NULL); + return; + } + case 31789: // Righteous Defense (step 1) + { + // Clear targets for eff 1 + for (std::list::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + ihit->effectMask &= ~(1<<1); + + // not empty (checked), copy + Unit::AttackerSet attackers = unitTarget->getAttackers(); + + // selected from list 3 + for (int i = 0; i < std::min(size_t(3),attackers.size()); ++i) + { + Unit::AttackerSet::iterator aItr = attackers.begin(); + std::advance(aItr, rand() % attackers.size()); + AddUnitTarget((*aItr), 1); + attackers.erase(aItr); + } + + // now let next effect cast spell at each target. + return; + } + case 37877: // Blessing of Faith + { + if (!unitTarget) + return; + + uint32 spell_id = 0; + switch(unitTarget->getClass()) + { + case CLASS_DRUID: spell_id = 37878; break; + case CLASS_PALADIN: spell_id = 37879; break; + case CLASS_PRIEST: spell_id = 37880; break; + case CLASS_SHAMAN: spell_id = 37881; break; + default: return; // ignore for not healing classes + } + + m_caster->CastSpell(m_caster, spell_id, true); + return; + } + } + break; + case SPELLFAMILY_SHAMAN: + // Cleansing Totem Pulse + if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_SHAMAN_TOTEM_EFFECTS && m_spellInfo->SpellIconID == 1673) + { + int32 bp1 = 1; + // Cleansing Totem Effect + if (unitTarget) + m_caster->CastCustomSpell(unitTarget, 52025, NULL, &bp1, NULL, true, NULL, NULL, m_originalCasterGUID); + return; + } + // Healing Stream Totem + if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_SHAMAN_HEALING_STREAM) + { + if (!unitTarget) + return; + // Restorative Totems + if (Unit *owner = m_caster->GetOwner()) + if (AuraEffect *dummy = owner->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 338, 1)) + damage += damage * dummy->GetAmount() / 100; + + m_caster->CastCustomSpell(unitTarget, 52042, &damage, 0, 0, true, 0, 0, m_originalCasterGUID); + return; + } + // Mana Spring Totem + if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_SHAMAN_MANA_SPRING) + { + if (!unitTarget || unitTarget->getPowerType() != POWER_MANA) + return; + m_caster->CastCustomSpell(unitTarget, 52032, &damage, 0, 0, true, 0, 0, m_originalCasterGUID); + return; + } + if (m_spellInfo->Id == 39610) // Mana Tide Totem effect + { + if (!unitTarget || unitTarget->getPowerType() != POWER_MANA) + return; + // Glyph of Mana Tide + if (Unit *owner = m_caster->GetOwner()) + if (AuraEffect *dummy = owner->GetAuraEffect(55441, 0)) + damage += dummy->GetAmount(); + // Regenerate 6% of Total Mana Every 3 secs + int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100; + m_caster->CastCustomSpell(unitTarget, 39609, &EffectBasePoints0, NULL, NULL, true, NULL, NULL, m_originalCasterGUID); + return; + } + // Fire Nova + if (m_spellInfo->SpellIconID == 33) + { + if (!m_caster) + return; + + uint32 triggered_spell_id; + switch(m_spellInfo->Id) + { + case 1535: triggered_spell_id = 8349; break; + case 8498: triggered_spell_id = 8502; break; + case 8499: triggered_spell_id = 8503; break; + case 11314: triggered_spell_id = 11306; break; + case 11315: triggered_spell_id = 11307; break; + case 25546: triggered_spell_id = 25535; break; + case 25547: triggered_spell_id = 25537; break; + case 61649: triggered_spell_id = 61650; break; + case 61657: triggered_spell_id = 61654; break; + default: + break; + } + // fire slot + if (triggered_spell_id && m_caster->m_SummonSlot[1]) + { + Creature* totem = m_caster->GetMap()->GetCreature(m_caster->m_SummonSlot[1]); + if (totem && totem->isTotem()) + totem->CastSpell(totem, triggered_spell_id, true); + return; + } + return; + } + // Lava Lash + if (m_spellInfo->SpellFamilyFlags[2] & SPELLFAMILYFLAG2_SHAMAN_LAVA_LASH) + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + if (Item *item = m_caster->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND)) + { + // Damage is increased by 25% if your off-hand weapon is enchanted with Flametongue. + if (m_caster->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0x200000, 0, 0)) + m_damage += m_damage * damage / 100; + } + return; + } + break; + case SPELLFAMILY_DEATHKNIGHT: + // Death strike + if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_DK_DEATH_STRIKE) + { + uint32 count = unitTarget->GetDiseasesByCaster(m_caster->GetGUID()); + int32 bp = count * m_caster->GetMaxHealth() * m_spellInfo->DmgMultiplier[0] / 100; + // Improved Death Strike + if (AuraEffect const * aurEff = m_caster->GetAuraEffect(SPELL_AURA_ADD_PCT_MODIFIER, SPELLFAMILY_DEATHKNIGHT, 2751, 0)) + bp = bp * (m_caster->CalculateSpellDamage(m_caster, aurEff->GetSpellProto(), 2) + 100.0f) / 100.0f; + m_caster->CastCustomSpell(m_caster, 45470, &bp, NULL, NULL, false); + return; + } + // Scourge Strike + if (m_spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_DK_SCOURGE_STRIKE) + { + int32 bp = (m_damage * damage * unitTarget->GetDiseasesByCaster(m_caster->GetGUID())) / 100; + m_caster->CastCustomSpell(unitTarget, 70890, &bp, NULL, NULL, true); + return; + } + // Death Coil + if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_DK_DEATH_COIL) + { + if (m_caster->IsFriendlyTo(unitTarget)) + { + int32 bp = damage * 1.5f; + m_caster->CastCustomSpell(unitTarget, 47633, &bp, NULL, NULL, true); + } + else + { + int32 bp = damage; + m_caster->CastCustomSpell(unitTarget, 47632, &bp, NULL, NULL, true); + } + return; + } + // Hungering Cold + if (m_spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_DK_HUNGERING_COLD) + { + unitTarget->CastSpell(m_caster, 51209, true); + return; + } + // Death Grip + if (m_spellInfo->Id == 49560) + { + Position pos; + GetSummonPosition(i, pos); + if (Unit *unit = unitTarget->GetVehicleBase()) // what is this for? + unit->CastSpell(pos.GetPositionX(),pos.GetPositionY(),pos.GetPositionZ(),damage,true); + else + unitTarget->CastSpell(pos.GetPositionX(),pos.GetPositionY(),pos.GetPositionZ(),damage,true); + return; + } + else if (m_spellInfo->Id == 46584) // Raise dead + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + // Do we have talent Master of Ghouls? + if (m_caster->HasAura(52143)) + // summon as pet + bp = 52150; + else + // or guardian + bp = 46585; + + if (m_targets.HasDst()) + { + targets.setDst(&m_targets.m_dstPos); + } + else + { + targets.setDst(m_caster); + // Corpse not found - take reagents (only not triggered cast can take them) + triggered = false; + } + // Remove cooldown - summon spellls have category + m_caster->ToPlayer()->RemoveSpellCooldown(m_spellInfo->Id,true); + spell_id=48289; + } + // Raise dead - take reagents and trigger summon spells + else if (m_spellInfo->Id == 48289) + { + if (m_targets.HasDst()) + targets.setDst(&m_targets.m_dstPos); + + spell_id = CalculateDamage(0, NULL); + } + // Corpse Explosion + else if (m_spellInfo->SpellIconID == 1737) + { + // Dummy effect 1 is used only for targeting and damage amount + if (i != 0) + return; + int32 bp = 0; + // Living ghoul as a target + if (unitTarget->isAlive()) + { + bp = unitTarget->GetMaxHealth()*0.25f; + } + // Some corpse + else + { + bp = damage; + } + m_caster->CastCustomSpell(unitTarget, SpellMgr::CalculateSpellEffectAmount(m_spellInfo, 1), &bp,NULL,NULL,true); + // Corpse Explosion (Suicide) + unitTarget->CastCustomSpell(unitTarget,43999,&bp,NULL,NULL,true); + // Set corpse look + unitTarget->SetDisplayId(25537+urand(0,3)); + } + // Runic Power Feed (keeping Gargoyle alive) + else if (m_spellInfo->Id == 50524) + { + // No power, dismiss Gargoyle + if (m_caster->GetPower(POWER_RUNIC_POWER)<30) + m_caster->RemoveAurasDueToSpell(50514, m_caster->GetGUID()); + else + m_caster->ModifyPower(POWER_RUNIC_POWER,-30); + + return; + } + break; + } + + //spells triggered by dummy effect should not miss + if (spell_id) + { + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); + + if (!spellInfo) + { + sLog.outError("EffectDummy of spell %u: triggering unknown spell id %i\n", m_spellInfo->Id, spell_id); + return; + } + + targets.setUnitTarget(unitTarget); + Spell* spell = new Spell(m_caster, spellInfo, triggered, m_originalCasterGUID, NULL, true); + if (bp) spell->m_currentBasePoints[0] = SpellMgr::CalculateSpellEffectBaseAmount(bp); + spell->prepare(&targets); + } + + // pet auras + if (PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id,i)) + { + m_caster->AddPetAura(petSpell); + return; + } + + // Script based implementation. Must be used only for not good for implementation in core spell effects + // So called only for not proccessed cases + if (gameObjTarget) + sScriptMgr.EffectDummyGameObj(m_caster, m_spellInfo->Id, i, gameObjTarget); + else if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT) + sScriptMgr.EffectDummyCreature(m_caster, m_spellInfo->Id, i, unitTarget->ToCreature()); + else if (itemTarget) + sScriptMgr.EffectDummyItem(m_caster, m_spellInfo->Id, i, itemTarget); +} + +void Spell::EffectTriggerSpellWithValue(uint32 i) +{ + uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i]; + + // normal case + SpellEntry const *spellInfo = sSpellStore.LookupEntry(triggered_spell_id); + + if (!spellInfo) + { + sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id); + return; + } + + int32 bp = damage; + Unit * caster = GetTriggeredSpellCaster(spellInfo, m_caster, unitTarget); + + caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true); +} + +void Spell::EffectTriggerRitualOfSummoning(uint32 i) +{ + uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i]; + SpellEntry const *spellInfo = sSpellStore.LookupEntry(triggered_spell_id); + + if (!spellInfo) + { + sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id); + return; + } + + finish(); + + m_caster->CastSpell(unitTarget,spellInfo,false); +} + +void Spell::EffectForceCast(uint32 i) +{ + if (!unitTarget) + return; + + uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i]; + + // normal case + SpellEntry const *spellInfo = sSpellStore.LookupEntry(triggered_spell_id); + + if (!spellInfo) + { + sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id); + return; + } + + if (damage) + { + switch(m_spellInfo->Id) + { + case 52588: // Skeletal Gryphon Escape + case 48598: // Ride Flamebringer Cue + unitTarget->RemoveAura(damage); + break; + case 52463: // Hide In Mine Car + case 52349: // Overtake + unitTarget->CastCustomSpell(unitTarget, spellInfo->Id, &damage, NULL, NULL, true, NULL, NULL, m_originalCasterGUID); + return; + //case 72378: // Blood Nova + //case 73058: // Blood Nova + } + } + Unit * caster = GetTriggeredSpellCaster(spellInfo, m_caster, unitTarget); + + caster->CastSpell(unitTarget, spellInfo, true, NULL, NULL, m_originalCasterGUID); +} + +void Spell::EffectForceCastWithValue(uint32 i) +{ + if (!unitTarget) + return; + + uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i]; + + // normal case + SpellEntry const *spellInfo = sSpellStore.LookupEntry(triggered_spell_id); + + if (!spellInfo) + { + sLog.outError("EffectForceCastWithValue of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id); + return; + } + int32 bp = damage; + Unit * caster = GetTriggeredSpellCaster(spellInfo, m_caster, unitTarget); + + caster->CastCustomSpell(unitTarget, spellInfo->Id, &bp, &bp, &bp, true, NULL, NULL, m_originalCasterGUID); +} + + +void Spell::EffectTriggerSpell(uint32 effIndex) +{ + // only unit case known + if (!unitTarget) + { + if (gameObjTarget || itemTarget) + sLog.outError("Spell::EffectTriggerSpell (Spell: %u): Unsupported non-unit case!",m_spellInfo->Id); + return; + } + + uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effIndex]; + Unit* originalCaster = NULL; + + // special cases + switch(triggered_spell_id) + { + // Mirror Image + case 58832: + { + // Glyph of Mirror Image + if (m_caster->HasAura(63093)) + m_caster->CastSpell(m_caster, 65047, true); // Mirror Image + + break; + } + // Vanish (not exist) + case 18461: + { + unitTarget->RemoveMovementImpairingAuras(); + unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STALKED); + + // if this spell is given to NPC it must handle rest by it's own AI + if (unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + // get highest rank of the Stealth spell + uint32 spellId = 0; + SpellEntry const *spellInfo; + const PlayerSpellMap& sp_list = unitTarget->ToPlayer()->GetSpellMap(); + for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) + { + // only highest rank is shown in spell book, so simply check if shown in spell book + if (!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED) + continue; + + spellInfo = sSpellStore.LookupEntry(itr->first); + if (!spellInfo) + continue; + + if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_STEALTH) + { + spellId = spellInfo->Id; + break; + } + } + + // no Stealth spell found + if (!spellId) + return; + + // reset cooldown on it if needed + if (unitTarget->ToPlayer()->HasSpellCooldown(spellId)) + unitTarget->ToPlayer()->RemoveSpellCooldown(spellId); + + // Push stealth to list because it must be handled after combat remove + m_TriggerSpells.push_back(spellInfo); + return; + } + // Demonic Empowerment -- succubus + case 54437: + { + unitTarget->RemoveMovementImpairingAuras(); + unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STALKED); + unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STUN); + + // Cast Lesser Invisibility + triggered_spell_id = 7870; + break; + } + // just skip + case 23770: // Sayge's Dark Fortune of * + // not exist, common cooldown can be implemented in scripts if need. + return; + // Brittle Armor - (need add max stack of 24575 Brittle Armor) + case 29284: + { + // Brittle Armor + SpellEntry const* spell = sSpellStore.LookupEntry(24575); + if (!spell) + return; + + for (int j=0; j < spell->StackAmount; ++j) + m_caster->CastSpell(unitTarget, spell->Id, true); + return; + } + // Mercurial Shield - (need add max stack of 26464 Mercurial Shield) + case 29286: + { + // Mercurial Shield + SpellEntry const* spell = sSpellStore.LookupEntry(26464); + if (!spell) + return; + + for (int j=0; j < spell->StackAmount; ++j) + m_caster->CastSpell(unitTarget, spell->Id, true); + return; + } + // Righteous Defense + case 31980: + { + m_caster->CastSpell(unitTarget, 31790, true); + return; + } + // Cloak of Shadows + case 35729: + { + uint32 dispelMask = GetDispellMask(DISPEL_ALL); + Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras(); + for (Unit::AuraApplicationMap::iterator iter = Auras.begin(); iter != Auras.end();) + { + // remove all harmful spells on you... + SpellEntry const* spell = iter->second->GetBase()->GetSpellProto(); + if ((spell->DmgClass == SPELL_DAMAGE_CLASS_MAGIC // only affect magic spells + || ((1<Dispel) & dispelMask)) + // ignore positive and passive auras + && !iter->second->IsPositive() && !iter->second->GetBase()->IsPassive()) + { + m_caster->RemoveAura(iter); + } + else + iter++; + } + return; + } + // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet + case 41967: + { + if (Unit *pet = unitTarget->GetGuardianPet()) + pet->CastSpell(pet, 28305, true); + return; + } + // Empower Rune Weapon + case 53258: + return; // skip, hack-added in spell effect + // Snake Trap + case 57879: + originalCaster = m_originalCaster; + break; + } + + // normal case + SpellEntry const *spellInfo = sSpellStore.LookupEntry(triggered_spell_id); + if (!spellInfo) + { + sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id); + return; + } + + // Remove spell cooldown (not category) if spell triggering spell with cooldown and same category + // Needed by freezing arrow and few other spells + if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->CategoryRecoveryTime && spellInfo->CategoryRecoveryTime + && m_spellInfo->Category == spellInfo->Category) + m_caster->ToPlayer()->RemoveSpellCooldown(spellInfo->Id); + + // Note: not exist spells with weapon req. and IsSpellHaveCasterSourceTargets == true + // so this just for speedup places in else + Unit * caster = GetTriggeredSpellCaster(spellInfo, m_caster, unitTarget); + + caster->CastSpell(unitTarget,spellInfo,true, 0, 0, (originalCaster ? originalCaster->GetGUID() : 0)); +} + +void Spell::EffectTriggerMissileSpell(uint32 effect_idx) +{ + uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effect_idx]; + + // normal case + SpellEntry const *spellInfo = sSpellStore.LookupEntry(triggered_spell_id); + + if (!spellInfo) + { + sLog.outError("EffectTriggerMissileSpell of spell %u (eff: %u): triggering unknown spell id %u", + m_spellInfo->Id,effect_idx,triggered_spell_id); + return; + } + + if (m_CastItem) + DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id); + + // Remove spell cooldown (not category) if spell triggering spell with cooldown and same category + // Needed by freezing arrow and few other spells + if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->CategoryRecoveryTime && spellInfo->CategoryRecoveryTime + && m_spellInfo->Category == spellInfo->Category) + m_caster->ToPlayer()->RemoveSpellCooldown(spellInfo->Id); + + float x, y, z; + m_targets.m_dstPos.GetPosition(x, y, z); + m_caster->CastSpell(x, y, z, spellInfo->Id, true, m_CastItem, 0, m_originalCasterGUID); +} + +void Spell::EffectJump(uint32 i) +{ + if (m_caster->isInFlight()) + return; + + float x,y,z,o; + if (m_targets.getUnitTarget()) + { + m_targets.getUnitTarget()->GetContactPoint(m_caster,x,y,z,CONTACT_DISTANCE); + o = m_caster->GetOrientation(); + } + else if (m_targets.getGOTarget()) + { + m_targets.getGOTarget()->GetContactPoint(m_caster,x,y,z,CONTACT_DISTANCE); + o = m_caster->GetOrientation(); + } + else + { + sLog.outError("Spell::EffectJump - unsupported target mode for spell ID %u", m_spellInfo->Id); + return; + } + + float speedXY, speedZ; + CalculateJumpSpeeds(i, m_caster->GetExactDist2d(x, y), speedXY, speedZ); + m_caster->GetMotionMaster()->MoveJump(x, y, z, speedXY, speedZ); +} + +void Spell::EffectJumpDest(uint32 i) +{ + if (m_caster->isInFlight()) + return; + + // Init dest coordinates + float x,y,z,o; + if (m_targets.HasDst()) + { + m_targets.m_dstPos.GetPosition(x, y, z); + + if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_DEST_TARGET_BACK) + { + // explicit cast data from client or server-side cast + // some spell at client send caster + Unit* pTarget = NULL; + if (m_targets.getUnitTarget() && m_targets.getUnitTarget() != m_caster) + pTarget = m_targets.getUnitTarget(); + else if (m_caster->getVictim()) + pTarget = m_caster->getVictim(); + else if (m_caster->GetTypeId() == TYPEID_PLAYER) + pTarget = ObjectAccessor::GetUnit(*m_caster, m_caster->ToPlayer()->GetSelection()); + + o = pTarget ? pTarget->GetOrientation() : m_caster->GetOrientation(); + } + else + o = m_caster->GetOrientation(); + } + else + { + sLog.outError("Spell::EffectJumpDest - unsupported target mode for spell ID %u", m_spellInfo->Id); + return; + } + + float speedXY, speedZ; + CalculateJumpSpeeds(i, m_caster->GetExactDist2d(x, y), speedXY, speedZ); + m_caster->GetMotionMaster()->MoveJump(x, y, z, speedXY, speedZ); +} + +void Spell::CalculateJumpSpeeds(uint8 i, float dist, float & speedXY, float & speedZ) +{ + if (m_spellInfo->EffectMiscValue[i]) + speedZ = float(m_spellInfo->EffectMiscValue[i])/10; + else if (m_spellInfo->EffectMiscValueB[i]) + speedZ = float(m_spellInfo->EffectMiscValueB[i])/10; + else + speedZ = 10.0f; + speedXY = dist * 10.0f / speedZ; +} + +void Spell::EffectTeleportUnits(uint32 /*i*/) +{ + if (!unitTarget || unitTarget->isInFlight()) + return; + + // Pre effects + uint8 uiMaxSafeLevel = 0; + switch (m_spellInfo->Id) + { + case 48129: // Scroll of Recall + uiMaxSafeLevel = 40; + case 60320: // Scroll of Recall II + if (!uiMaxSafeLevel) + uiMaxSafeLevel = 70; + case 60321: // Scroll of Recal III + if (!uiMaxSafeLevel) + uiMaxSafeLevel = 80; + + if (unitTarget->getLevel() > uiMaxSafeLevel) + { + unitTarget->AddAura(60444,unitTarget); //Apply Lost! Aura + return; + } + break; + } + + // If not exist data for dest location - return + if (!m_targets.HasDst()) + { + sLog.outError("Spell::EffectTeleportUnits - does not have destination for spell ID %u\n", m_spellInfo->Id); + return; + } + + // Init dest coordinates + uint32 mapid = m_targets.m_dstPos.GetMapId(); + if (mapid == MAPID_INVALID) + mapid = unitTarget->GetMapId(); + float x, y, z, orientation; + m_targets.m_dstPos.GetPosition(x, y, z, orientation); + if (!orientation && m_targets.getUnitTarget()) + orientation = m_targets.getUnitTarget()->GetOrientation(); + sLog.outDebug("Spell::EffectTeleportUnits - teleport unit to %u %f %f %f %f\n", mapid, x, y, z, orientation); + + if (mapid == unitTarget->GetMapId()) + unitTarget->NearTeleportTo(x, y, z, orientation, unitTarget == m_caster); + else if (unitTarget->GetTypeId() == TYPEID_PLAYER) + unitTarget->ToPlayer()->TeleportTo(mapid, x, y, z, orientation, unitTarget == m_caster ? TELE_TO_SPELL : 0); + + // post effects for TARGET_DST_DB + switch (m_spellInfo->Id) + { + // Dimensional Ripper - Everlook + case 23442: + { + int32 r = irand(0, 119); + if (r >= 70) // 7/12 success + { + if (r < 100) // 4/12 evil twin + m_caster->CastSpell(m_caster, 23445, true); + else // 1/12 fire + m_caster->CastSpell(m_caster, 23449, true); + } + return; + } + // Ultrasafe Transporter: Toshley's Station + case 36941: + { + if (roll_chance_i(50)) // 50% success + { + int32 rand_eff = urand(1, 7); + switch (rand_eff) + { + case 1: + // soul split - evil + m_caster->CastSpell(m_caster, 36900, true); + break; + case 2: + // soul split - good + m_caster->CastSpell(m_caster, 36901, true); + break; + case 3: + // Increase the size + m_caster->CastSpell(m_caster, 36895, true); + break; + case 4: + // Decrease the size + m_caster->CastSpell(m_caster, 36893, true); + break; + case 5: + // Transform + { + if (m_caster->ToPlayer()->GetTeam() == ALLIANCE) + m_caster->CastSpell(m_caster, 36897, true); + else + m_caster->CastSpell(m_caster, 36899, true); + break; + } + case 6: + // chicken + m_caster->CastSpell(m_caster, 36940, true); + break; + case 7: + // evil twin + m_caster->CastSpell(m_caster, 23445, true); + break; + } + } + return; + } + // Dimensional Ripper - Area 52 + case 36890: + { + if (roll_chance_i(50)) // 50% success + { + int32 rand_eff = urand(1, 4); + switch (rand_eff) + { + case 1: + // soul split - evil + m_caster->CastSpell(m_caster, 36900, true); + break; + case 2: + // soul split - good + m_caster->CastSpell(m_caster, 36901, true); + break; + case 3: + // Increase the size + m_caster->CastSpell(m_caster, 36895, true); + break; + case 4: + // Transform + { + if (m_caster->ToPlayer()->GetTeam() == ALLIANCE) + m_caster->CastSpell(m_caster, 36897, true); + else + m_caster->CastSpell(m_caster, 36899, true); + break; + } + } + } + return; + } + } +} + +void Spell::EffectApplyAura(uint32 i) +{ + if (!m_spellAura || !unitTarget) + return; + assert(unitTarget == m_spellAura->GetOwner()); + m_spellAura->_ApplyEffectForTargets(i); +} + +void Spell::EffectApplyAreaAura(uint32 i) +{ + if (!m_spellAura || !unitTarget) + return; + assert (unitTarget == m_spellAura->GetOwner()); + m_spellAura->_ApplyEffectForTargets(i); +} + +void Spell::EffectUnlearnSpecialization(uint32 i) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + Player *_player = (Player*)unitTarget; + uint32 spellToUnlearn = m_spellInfo->EffectTriggerSpell[i]; + + _player->removeSpell(spellToUnlearn); + + sLog.outDebug("Spell: Player %u has unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow()); +} + +void Spell::EffectPowerDrain(uint32 i) +{ + if (m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) + return; + + Powers drain_power = Powers(m_spellInfo->EffectMiscValue[i]); + + if (!unitTarget) + return; + if (!unitTarget->isAlive()) + return; + if (unitTarget->getPowerType() != drain_power) + return; + if (damage < 0) + return; + + uint32 curPower = unitTarget->GetPower(drain_power); + + //add spell damage bonus + damage=m_caster->SpellDamageBonus(unitTarget,m_spellInfo,uint32(damage),SPELL_DIRECT_DAMAGE); + + // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) + uint32 power = damage; + if (drain_power == POWER_MANA) + power -= unitTarget->GetSpellCritDamageReduction(power); + + int32 new_damage; + if (curPower < power) + new_damage = curPower; + else + new_damage = power; + + unitTarget->ModifyPower(drain_power,-new_damage); + + // Don`t restore from self drain + if (drain_power == POWER_MANA && m_caster != unitTarget) + { + float manaMultiplier = m_spellInfo->EffectMultipleValue[i]; + if (manaMultiplier == 0) + manaMultiplier = 1; + + if (Player *modOwner = m_caster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier); + + int32 gain = int32(new_damage * manaMultiplier); + + m_caster->EnergizeBySpell(m_caster, m_spellInfo->Id, gain, POWER_MANA); + } +} + +void Spell::EffectSendEvent(uint32 EffectIndex) +{ + /* + we do not handle a flag dropping or clicking on flag in battleground by sendevent system + */ + sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id); + + Object *pTarget; + if (focusObject) + pTarget = focusObject; + else if (unitTarget) + pTarget = unitTarget; + else if (gameObjTarget) + pTarget = gameObjTarget; + else + pTarget = NULL; + + m_caster->GetMap()->ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, pTarget); +} + +void Spell::EffectPowerBurn(uint32 i) +{ + if (m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) + return; + + Powers powertype = Powers(m_spellInfo->EffectMiscValue[i]); + + if (!unitTarget) + return; + if (!unitTarget->isAlive()) + return; + if (unitTarget->getPowerType() != powertype) + return; + if (damage < 0) + return; + + //Unit* caster = m_originalCaster ? m_originalCaster : m_caster; + + // burn x% of target's mana, up to maximum of 2x% of caster's mana (Mana Burn) + if (m_spellInfo->ManaCostPercentage) + { + uint32 maxdamage = m_caster->GetMaxPower(powertype) * damage * 2 / 100; + damage = unitTarget->GetMaxPower(powertype) * damage / 100; + if (damage > maxdamage) damage = maxdamage; + } + + int32 curPower = int32(unitTarget->GetPower(powertype)); + + uint32 power = damage; + // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) + if (powertype == POWER_MANA) + power -= unitTarget->GetSpellCritDamageReduction(power); + + int32 new_damage = (curPower < power) ? curPower : power; + + unitTarget->ModifyPower(powertype, -new_damage); + float multiplier = m_spellInfo->EffectMultipleValue[i]; + + if (Player *modOwner = m_caster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier); + + new_damage = int32(new_damage*multiplier); + //m_damage+=new_damage; should not apply spell bonus + //TODO: no log + //unitTarget->ModifyHealth(-new_damage); + if (m_originalCaster) + m_originalCaster->DealDamage(unitTarget, new_damage); + + unitTarget->RemoveAurasByType(SPELL_AURA_MOD_FEAR); +} + +void Spell::EffectHeal(uint32 /*i*/) +{ +} + +void Spell::SpellDamageHeal(uint32 /*i*/) +{ + if (unitTarget && unitTarget->isAlive() && damage >= 0) + { + // Try to get original caster + Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster; + + // Skip if m_originalCaster not available + if (!caster) + return; + + int32 addhealth = damage; + + // Vessel of the Naaru (Vial of the Sunwell trinket) + if (m_spellInfo->Id == 45064) + { + // Amount of heal - depends from stacked Holy Energy + int damageAmount = 0; + if (AuraEffect const * aurEff = m_caster->GetAuraEffect(45062, 0)) + { + damageAmount+= aurEff->GetAmount(); + m_caster->RemoveAurasDueToSpell(45062); + } + + addhealth += damageAmount; + } + // Swiftmend - consumes Regrowth or Rejuvenation + else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND, m_spellInfo, m_caster)) + { + Unit::AuraEffectList const& RejorRegr = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_HEAL); + // find most short by duration + AuraEffect *targetAura = NULL; + for (Unit::AuraEffectList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i) + { + if ((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID + && (*i)->GetSpellProto()->SpellFamilyFlags[0] & 0x50) + { + if (!targetAura || (*i)->GetBase()->GetDuration() < targetAura->GetBase()->GetDuration()) + targetAura = *i; + } + } + + if (!targetAura) + { + sLog.outError("Target(GUID:" UI64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID()); + return; + } + + int32 tickheal = targetAura->GetAmount(); + if (Unit* auraCaster = targetAura->GetCaster()) + tickheal = auraCaster->SpellHealingBonus(unitTarget, targetAura->GetSpellProto(), tickheal, DOT); + //int32 tickheal = targetAura->GetSpellProto()->EffectBasePoints[idx] + 1; + //It is said that talent bonus should not be included + + int32 tickcount = 0; + // Rejuvenation + if (targetAura->GetSpellProto()->SpellFamilyFlags[0] & 0x10) + tickcount = 4; + // Regrowth + else // if (targetAura->GetSpellProto()->SpellFamilyFlags[0] & 0x40) + tickcount = 6; + + addhealth += tickheal * tickcount; + + // Glyph of Swiftmend + if (!caster->HasAura(54824)) + unitTarget->RemoveAura(targetAura->GetId(), targetAura->GetCasterGUID()); + + //addhealth += tickheal * tickcount; + //addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget); + } + // Glyph of Nourish + else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags[1] & 0x2000000) + { + addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL); + + if (AuraEffect const* aurEff = m_caster->GetAuraEffect(62971, 0)) + { + Unit::AuraEffectList const& Periodic = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_HEAL); + for (Unit::AuraEffectList::const_iterator i = Periodic.begin(); i != Periodic.end(); ++i) + { + if (m_caster->GetGUID() == (*i)->GetCasterGUID()) + addhealth += addhealth * aurEff->GetAmount() / 100; + } + } + } + // Riptide - increase healing done by Chain Heal + else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[0] & 0x100) + { + addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL); + if (AuraEffect * aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_SHAMAN, 0, 0, 0x10, m_originalCasterGUID)) + { + addhealth *= 1.25f; + // consume aura + unitTarget->RemoveAura(aurEff->GetBase()); + } + } + // Death Pact - return pct of max health to caster + else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000) + addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, int32(caster->GetMaxHealth() * damage / 100.0f), HEAL); + else + addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL); + + // Remove Grievious bite if fully healed + if (unitTarget->HasAura(48920) && (unitTarget->GetHealth() + addhealth >= unitTarget->GetMaxHealth())) + unitTarget->RemoveAura(48920); + + m_damage -= addhealth; + } +} + +void Spell::EffectHealPct(uint32 /*i*/) +{ + if (unitTarget && unitTarget->isAlive() && damage >= 0) + { + // Try to get original caster + Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster; + + // Skip if m_originalCaster not available + if (!caster) + return; + + // Rune Tap - Party + if (m_spellInfo->Id == 59754 && unitTarget == m_caster) + return; + + uint32 addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, unitTarget->GetMaxHealth() * damage / 100.0f, HEAL); + //if (Player *modOwner = m_caster->GetSpellModOwner()) + // modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DAMAGE, addhealth, this); + + int32 gain = caster->DealHeal(unitTarget, addhealth, m_spellInfo); + unitTarget->getHostileRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo); + } +} + +void Spell::EffectHealMechanical(uint32 /*i*/) +{ + // Mechanic creature type should be correctly checked by targetCreatureType field + if (unitTarget && unitTarget->isAlive() && damage >= 0) + { + // Try to get original caster + Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster; + + // Skip if m_originalCaster not available + if (!caster) + return; + + uint32 addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, uint32(damage), HEAL); + caster->DealHeal(unitTarget, addhealth, m_spellInfo); + } +} + +void Spell::EffectHealthLeech(uint32 i) +{ + if (!unitTarget) + return; + if (!unitTarget->isAlive()) + return; + + if (damage < 0) + return; + + sLog.outDebug("HealthLeech :%i", damage); + + float multiplier = m_spellInfo->EffectMultipleValue[i]; + + if (Player *modOwner = m_caster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier); + + // Do not apply multiplier to damage if it's Death Coil + int32 new_damage; + if (m_spellInfo->SpellFamilyFlags[0] & 0x80000) + new_damage = damage; + else + new_damage = int32(damage*multiplier); + uint32 curHealth = unitTarget->GetHealth(); + new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage); + if (curHealth < new_damage) + new_damage = curHealth; + + if (m_caster->isAlive()) + { + // Insead add it just to healing if it's Death Coil + if (m_spellInfo->SpellFamilyFlags[0] & 0x80000) + new_damage = int32(new_damage*multiplier); + new_damage = m_caster->SpellHealingBonus(m_caster, m_spellInfo, new_damage, HEAL); + m_caster->DealHeal(m_caster, uint32(new_damage), m_spellInfo); + } +// m_healthLeech+=tmpvalue; +// m_damage+=new_damage; +} + +void Spell::DoCreateItem(uint32 /*i*/, uint32 itemtype) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + Player* player = (Player*)unitTarget; + + uint32 newitemid = itemtype; + ItemPrototype const *pProto = objmgr.GetItemPrototype(newitemid); + if (!pProto) + { + player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + // bg reward have some special in code work + uint32 bgType = 0; + switch(m_spellInfo->Id) + { + case SPELL_AV_MARK_WINNER: + case SPELL_AV_MARK_LOSER: + bgType = BATTLEGROUND_AV; + break; + case SPELL_WS_MARK_WINNER: + case SPELL_WS_MARK_LOSER: + bgType = BATTLEGROUND_WS; + break; + case SPELL_AB_MARK_WINNER: + case SPELL_AB_MARK_LOSER: + bgType = BATTLEGROUND_AB; + break; + default: + break; + } + + uint32 num_to_add = damage; + + if (num_to_add < 1) + num_to_add = 1; + if (num_to_add > pProto->GetMaxStackSize()) + num_to_add = pProto->GetMaxStackSize(); + + // init items_count to 1, since 1 item will be created regardless of specialization + int items_count=1; + // the chance to create additional items + float additionalCreateChance=0.0f; + // the maximum number of created additional items + uint8 additionalMaxNum=0; + // get the chance and maximum number for creating extra items + if (canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum)) + { + // roll with this chance till we roll not to create or we create the max num + while (roll_chance_f(additionalCreateChance) && items_count <= additionalMaxNum) + ++items_count; + } + + // really will be created more items + num_to_add *= items_count; + + // can the player store the new item? + ItemPosCountVec dest; + uint32 no_space = 0; + uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space); + if (msg != EQUIP_ERR_OK) + { + // convert to possible store amount + if (msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS) + num_to_add -= no_space; + else + { + // if not created by another reason from full inventory or unique items amount limitation + player->SendEquipError(msg, NULL, NULL); + return; + } + } + + if (num_to_add) + { + // create the new item and store it + Item* pItem = player->StoreNewItem(dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid)); + + // was it successful? return error if not + if (!pItem) + { + player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + // set the "Crafted by ..." property of the item + if (pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST && newitemid != 6265 && newitemid != 6948) + pItem->SetUInt32Value(ITEM_FIELD_CREATOR, player->GetGUIDLow()); + + // send info to the client + if (pItem) + player->SendNewItem(pItem, num_to_add, true, bgType == 0); + + // we succeeded in creating at least one item, so a levelup is possible + if (bgType == 0) + player->UpdateCraftSkill(m_spellInfo->Id); + } + +/* + // for battleground marks send by mail if not add all expected + if (no_space > 0 && bgType) + { + if (BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(BattleGroundTypeId(bgType))) + bg->SendRewardMarkByMail(player, newitemid, no_space); + } +*/ +} + +void Spell::EffectCreateItem(uint32 i) +{ + DoCreateItem(i,m_spellInfo->EffectItemType[i]); +} + +void Spell::EffectCreateItem2(uint32 i) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + Player* player = (Player*)m_caster; + + uint32 item_id = m_spellInfo->EffectItemType[i]; + + if (item_id) + DoCreateItem(i, item_id); + + // special case: fake item replaced by generate using spell_loot_template + if (IsLootCraftingSpell(m_spellInfo)) + { + if (item_id) + { + if (!player->HasItemCount(item_id, 1)) + return; + + // remove reagent + uint32 count = 1; + player->DestroyItemCount(item_id, count, true); + + // create some random items + player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell); + } + else + player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell); // create some random items + } +} + +void Spell::EffectCreateRandomItem(uint32 /*i*/) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + Player* player = (Player*)m_caster; + + // create some random items + player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell); +} + +void Spell::EffectPersistentAA(uint32 i) +{ + if (!m_spellAura) + { + float radius = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); + if (Player* modOwner = m_originalCaster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius); + + Unit *caster = m_caster->GetEntry() == WORLD_TRIGGER ? m_originalCaster : m_caster; + // Caster not in world, might be spell triggered from aura removal + if (!caster->IsInWorld()) + return; + DynamicObject* dynObj = new DynamicObject; + if (!dynObj->Create(objmgr.GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), caster, m_spellInfo->Id, m_targets.m_dstPos, radius, false)) + { + delete dynObj; + return; + } + caster->AddDynObject(dynObj); + dynObj->GetMap()->Add(dynObj); + + if (Aura * aura = Aura::TryCreate(m_spellInfo, dynObj, caster, &m_currentBasePoints[0])) + m_spellAura = aura; + else + { + assert(false); + return; + } + m_spellAura->_RegisterForTargets(); + } + assert(m_spellAura->GetDynobjOwner()); + m_spellAura->_ApplyEffectForTargets(i); +} + +void Spell::EffectEnergize(uint32 i) +{ + if (!unitTarget) + return; + if (!unitTarget->isAlive()) + return; + + if (m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) + return; + + Powers power = Powers(m_spellInfo->EffectMiscValue[i]); + + // Some level depends spells + int level_multiplier = 0; + int level_diff = 0; + switch (m_spellInfo->Id) + { + case 9512: // Restore Energy + level_diff = m_caster->getLevel() - 40; + level_multiplier = 2; + break; + case 24571: // Blood Fury + level_diff = m_caster->getLevel() - 60; + level_multiplier = 10; + break; + case 24532: // Burst of Energy + level_diff = m_caster->getLevel() - 60; + level_multiplier = 4; + break; + case 31930: // Judgements of the Wise + case 63375: // Improved Stormstrike + case 68082: // Glyph of Seal of Command + damage = damage * unitTarget->GetCreateMana() / 100; + break; + case 48542: // Revitalize + damage = damage * unitTarget->GetMaxPower(power) / 100; + break; + default: + break; + } + + if (level_diff > 0) + damage -= level_multiplier * level_diff; + + if (damage < 0) + return; + + if (unitTarget->GetMaxPower(power) == 0) + return; + + m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, damage, power); + + // Mad Alchemist's Potion + if (m_spellInfo->Id == 45051) + { + // find elixirs on target + bool guardianFound = false; + bool battleFound = false; + Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras(); + for (Unit::AuraApplicationMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr) + { + uint32 spell_id = itr->second->GetBase()->GetId(); + if (!guardianFound) + if (spellmgr.IsSpellMemberOfSpellGroup(spell_id, SPELL_GROUP_ELIXIR_GUARDIAN)) + guardianFound = true; + if (!battleFound) + if (spellmgr.IsSpellMemberOfSpellGroup(spell_id, SPELL_GROUP_ELIXIR_BATTLE)) + battleFound = true; + if (battleFound && guardianFound) + break; + } + + // get all available elixirs by mask and spell level + std::set avalibleElixirs; + if (!guardianFound) + spellmgr.GetSetOfSpellsInSpellGroup(SPELL_GROUP_ELIXIR_GUARDIAN, avalibleElixirs); + if (!battleFound) + spellmgr.GetSetOfSpellsInSpellGroup(SPELL_GROUP_ELIXIR_BATTLE, avalibleElixirs); + for (std::set::iterator itr = avalibleElixirs.begin(); itr != avalibleElixirs.end() ;) + { + SpellEntry const *spellInfo = sSpellStore.LookupEntry(*itr); + if (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel()) + avalibleElixirs.erase(itr++); + else if (spellmgr.IsSpellMemberOfSpellGroup(*itr, SPELL_GROUP_ELIXIR_SHATTRATH)) + avalibleElixirs.erase(itr++); + else if (spellmgr.IsSpellMemberOfSpellGroup(*itr, SPELL_GROUP_ELIXIR_UNSTABLE)) + avalibleElixirs.erase(itr++); + else + ++itr; + } + + if (!avalibleElixirs.empty()) + { + // cast random elixir on target + uint32 rand_spell = urand(0,avalibleElixirs.size()-1); + std::set::iterator itr = avalibleElixirs.begin(); + std::advance(itr, rand_spell); + m_caster->CastSpell(unitTarget,*itr,true,m_CastItem); + } + } +} + +void Spell::EffectEnergizePct(uint32 i) +{ + if (!unitTarget) + return; + if (!unitTarget->isAlive()) + return; + + if (m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) + return; + + Powers power = Powers(m_spellInfo->EffectMiscValue[i]); + + uint32 maxPower = unitTarget->GetMaxPower(power); + if (maxPower == 0) + return; + + uint32 gain = damage * maxPower / 100; + m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, gain, power); +} + +void Spell::SendLoot(uint64 guid, LootType loottype) +{ + Player* player = (Player*)m_caster; + if (!player) + return; + + if (gameObjTarget) + { + if (sScriptMgr.GOHello(player, gameObjTarget)) + return; + + switch (gameObjTarget->GetGoType()) + { + case GAMEOBJECT_TYPE_DOOR: + case GAMEOBJECT_TYPE_BUTTON: + gameObjTarget->UseDoorOrButton(); + player->GetMap()->ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget); + return; + + case GAMEOBJECT_TYPE_QUESTGIVER: + // start or end quest + player->PrepareQuestMenu(guid); + player->SendPreparedQuest(guid); + return; + + case GAMEOBJECT_TYPE_SPELL_FOCUS: + // triggering linked GO + if (uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId) + gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster); + return; + + case GAMEOBJECT_TYPE_GOOBER: + gameObjTarget->Use(m_caster); + return; + + case GAMEOBJECT_TYPE_CHEST: + // TODO: possible must be moved to loot release (in different from linked triggering) + if (gameObjTarget->GetGOInfo()->chest.eventId) + { + sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow()); + player->GetMap()->ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget); + } + + // triggering linked GO + if (uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId) + gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster); + + // Don't return, let loots been taken + default: + break; + } + } + + // Send loot + player->SendLoot(guid, loottype); +} + +void Spell::EffectOpenLock(uint32 effIndex) +{ + if (!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER) + { + sLog.outDebug("WORLD: Open Lock - No Player Caster!"); + return; + } + + Player* player = (Player*)m_caster; + + uint32 lockId = 0; + uint64 guid = 0; + + // Get lockId + if (gameObjTarget) + { + GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo(); + // Arathi Basin banner opening ! + if (goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune || + goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK) + { + //CanUseBattleGroundObject() already called in CheckCast() + // in battleground check + if (BattleGround *bg = player->GetBattleGround()) + { + bg->EventPlayerClickedOnFlag(player, gameObjTarget); + return; + } + } + else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND) + { + //CanUseBattleGroundObject() already called in CheckCast() + // in battleground check + if (BattleGround *bg = player->GetBattleGround()) + { + if (bg->GetTypeID(true) == BATTLEGROUND_EY) + bg->EventPlayerClickedOnFlag(player, gameObjTarget); + return; + } + }else if (m_spellInfo->Id == 1842 && gameObjTarget->GetGOInfo()->type == GAMEOBJECT_TYPE_TRAP && gameObjTarget->GetOwner()) + { + gameObjTarget->SetLootState(GO_JUST_DEACTIVATED); + return; + } + // TODO: Add script for spell 41920 - Filling, becouse server it freze when use this spell + // handle outdoor pvp object opening, return true if go was registered for handling + // these objects must have been spawned by outdoorpvp! + else if (gameObjTarget->GetGOInfo()->type == GAMEOBJECT_TYPE_GOOBER && sOutdoorPvPMgr.HandleOpenGo(player, gameObjTarget->GetGUID())) + return; + lockId = goInfo->GetLockId(); + guid = gameObjTarget->GetGUID(); + } + else if (itemTarget) + { + lockId = itemTarget->GetProto()->LockID; + guid = itemTarget->GetGUID(); + } + else + { + sLog.outDebug("WORLD: Open Lock - No GameObject/Item Target!"); + return; + } + + SkillType skillId = SKILL_NONE; + int32 reqSkillValue = 0; + int32 skillValue; + + SpellCastResult res = CanOpenLock(effIndex, lockId, skillId, reqSkillValue, skillValue); + if (res != SPELL_CAST_OK) + { + SendCastResult(res); + return; + } + + SendLoot(guid, LOOT_SKINNING); + + // not allow use skill grow at item base open + if (!m_CastItem && skillId != SKILL_NONE) + { + // update skill if really known + if (uint32 pureSkillValue = player->GetPureSkillValue(skillId)) + { + if (gameObjTarget) + { + // Allow one skill-up until respawned + if (!gameObjTarget->IsInSkillupList(player->GetGUIDLow()) && + player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue)) + gameObjTarget->AddToSkillupList(player->GetGUIDLow()); + } + else if (itemTarget) + { + // Do one skill-up + player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue); + } + } + } +} + +void Spell::EffectSummonChangeItem(uint32 i) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player *player = (Player*)m_caster; + + // applied only to using item + if (!m_CastItem) + return; + + // ... only to item in own inventory/bank/equip_slot + if (m_CastItem->GetOwnerGUID() != player->GetGUID()) + return; + + uint32 newitemid = m_spellInfo->EffectItemType[i]; + if (!newitemid) + return; + + uint16 pos = m_CastItem->GetPos(); + + Item *pNewItem = Item::CreateItem(newitemid, 1, player); + if (!pNewItem) + return; + + for (uint8 j = PERM_ENCHANTMENT_SLOT; j <= TEMP_ENCHANTMENT_SLOT; ++j) + if (m_CastItem->GetEnchantmentId(EnchantmentSlot(j))) + pNewItem->SetEnchantment(EnchantmentSlot(j), m_CastItem->GetEnchantmentId(EnchantmentSlot(j)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(j)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(j))); + + if (m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)) + { + double loosePercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); + player->DurabilityLoss(pNewItem, loosePercent); + } + + if (player->IsInventoryPos(pos)) + { + ItemPosCountVec dest; + uint8 msg = player->CanStoreItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true); + if (msg == EQUIP_ERR_OK) + { + player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), true); + + // prevent crash at access and unexpected charges counting with item update queue corrupt + if (m_CastItem == m_targets.getItemTarget()) + m_targets.setItemTarget(NULL); + + m_CastItem = NULL; + + player->StoreItem(dest, pNewItem, true); + return; + } + } + else if (player->IsBankPos(pos)) + { + ItemPosCountVec dest; + uint8 msg = player->CanBankItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true); + if (msg == EQUIP_ERR_OK) + { + player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), true); + + // prevent crash at access and unexpected charges counting with item update queue corrupt + if (m_CastItem == m_targets.getItemTarget()) + m_targets.setItemTarget(NULL); + + m_CastItem = NULL; + + player->BankItem(dest, pNewItem, true); + return; + } + } + else if (player->IsEquipmentPos(pos)) + { + uint16 dest; + + player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), true); + + uint8 msg = player->CanEquipItem(m_CastItem->GetSlot(), dest, pNewItem, true); + + if (msg == EQUIP_ERR_OK || msg == EQUIP_ERR_CANT_DO_RIGHT_NOW) + { + if (msg == EQUIP_ERR_CANT_DO_RIGHT_NOW) dest = EQUIPMENT_SLOT_MAINHAND; + + // prevent crash at access and unexpected charges counting with item update queue corrupt + if (m_CastItem == m_targets.getItemTarget()) + m_targets.setItemTarget(NULL); + + m_CastItem = NULL; + + player->EquipItem(dest, pNewItem, true); + player->AutoUnequipOffhandIfNeed(); + return; + } + } + + // fail + delete pNewItem; +} + +void Spell::EffectProficiency(uint32 /*i*/) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + Player *p_target = (Player*)unitTarget; + + uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask; + if (m_spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON && !(p_target->GetWeaponProficiency() & subClassMask)) + { + p_target->AddWeaponProficiency(subClassMask); + p_target->SendProficiency(ITEM_CLASS_WEAPON, p_target->GetWeaponProficiency()); + } + if (m_spellInfo->EquippedItemClass == ITEM_CLASS_ARMOR && !(p_target->GetArmorProficiency() & subClassMask)) + { + p_target->AddArmorProficiency(subClassMask); + p_target->SendProficiency(ITEM_CLASS_ARMOR, p_target->GetArmorProficiency()); + } +} + +void Spell::EffectSummonType(uint32 i) +{ + uint32 entry = m_spellInfo->EffectMiscValue[i]; + if (!entry) + return; + + SummonPropertiesEntry const *properties = sSummonPropertiesStore.LookupEntry(m_spellInfo->EffectMiscValueB[i]); + if (!properties) + { + sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]); + return; + } + + if (!m_originalCaster) + return; + + int32 duration = GetSpellDuration(m_spellInfo); + if (Player* modOwner = m_originalCaster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration); + + Position pos; + GetSummonPosition(i, pos); + + /*//totem must be at same Z in case swimming caster and etc. + if (fabs(z - m_caster->GetPositionZ()) > 5) + z = m_caster->GetPositionZ(); + + uint8 level = m_caster->getLevel(); + + // level of creature summoned using engineering item based at engineering skill level + if (m_caster->GetTypeId() == TYPEID_PLAYER && m_CastItem) + { + ItemPrototype const *proto = m_CastItem->GetProto(); + if (proto && proto->RequiredSkill == SKILL_ENGINERING) + { + uint16 skill202 = m_caster->ToPlayer()->GetSkillValue(SKILL_ENGINERING); + if (skill202) + level = skill202/5; + } + }*/ + + TempSummon *summon = NULL; + + switch (properties->Category) + { + default: + if (properties->Flags & 512) + { + SummonGuardian(i, entry, properties); + break; + } + switch (properties->Type) + { + case SUMMON_TYPE_PET: + case SUMMON_TYPE_GUARDIAN: + case SUMMON_TYPE_GUARDIAN2: + case SUMMON_TYPE_MINION: + SummonGuardian(i, entry, properties); + break; + case SUMMON_TYPE_VEHICLE: + case SUMMON_TYPE_VEHICLE2: + if (m_originalCaster) + summon = m_caster->GetMap()->SummonCreature(entry, pos, properties, duration, m_originalCaster); + break; + case SUMMON_TYPE_TOTEM: + { + summon = m_caster->GetMap()->SummonCreature(entry, pos, properties, duration, m_originalCaster); + if (!summon || !summon->isTotem()) + return; + + if (damage) // if not spell info, DB values used + { + summon->SetMaxHealth(damage); + summon->SetHealth(damage); + } + + //summon->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id); + + if (m_originalCaster->GetTypeId() == TYPEID_PLAYER + && properties->Slot >= SUMMON_SLOT_TOTEM + && properties->Slot < MAX_TOTEM_SLOT) + { + //summon->SendUpdateToPlayerm_originalCaster->ToPlayer(); + WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4); + data << uint8(properties->Slot-1); + data << uint64(m_originalCaster->GetGUID()); + data << uint32(duration); + data << uint32(m_spellInfo->Id); + m_originalCaster->ToPlayer()->SendDirectMessage(&data); + } + break; + } + case SUMMON_TYPE_MINIPET: + { + summon = m_caster->GetMap()->SummonCreature(entry, pos, properties, duration, m_originalCaster); + if (!summon || !summon->HasUnitTypeMask(UNIT_MASK_MINION)) + return; + + //summon->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as summon... + summon->SelectLevel(summon->GetCreatureInfo()); // some summoned creaters have different from 1 DB data for level/hp + summon->SetUInt32Value(UNIT_NPC_FLAGS, summon->GetCreatureInfo()->npcflag); + + summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + summon->AI()->EnterEvadeMode(); + + std::string name = m_originalCaster->GetName(); + name.append(petTypeSuffix[3]); + summon->SetName(name); + break; + } + default: + { + float radius = GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); + + int32 amount = damage > 0 ? damage : 1; + if (m_spellInfo->Id == 18662) // Curse of Doom + amount = 1; + + for (uint32 count = 0; count < amount; ++count) + { + GetSummonPosition(i, pos, radius, count); + + TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN; + + summon = m_originalCaster->SummonCreature(entry, pos, summonType, duration); + if (!summon) + continue; + if (properties->Category == SUMMON_CATEGORY_ALLY) + { + summon->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_originalCaster->GetGUID()); + summon->setFaction(m_originalCaster->getFaction()); + summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); + } + } + break; + } + }//switch + break; + case SUMMON_CATEGORY_PET: + SummonGuardian(i, entry, properties); + break; + case SUMMON_CATEGORY_PUPPET: + summon = m_caster->GetMap()->SummonCreature(entry, pos, properties, duration, m_originalCaster); + break; + case SUMMON_CATEGORY_VEHICLE: + { + float x, y, z; + m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE); + summon = m_caster->GetMap()->SummonCreature(entry, pos, properties, duration, m_caster); + if (!summon || !summon->IsVehicle()) + return; + + if (m_spellInfo->EffectBasePoints[i]) + { + SpellEntry const *spellProto = sSpellStore.LookupEntry(SpellMgr::CalculateSpellEffectAmount(m_spellInfo, i)); + if (spellProto) + m_caster->CastSpell(summon, spellProto, true); + } + + m_caster->EnterVehicle(summon->GetVehicleKit()); + break; + } + } + + if (summon) + { + summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); + summon->SetCreatorGUID(m_originalCaster->GetGUID()); + } +} + +void Spell::EffectLearnSpell(uint32 i) +{ + if (!unitTarget) + return; + + if (unitTarget->GetTypeId() != TYPEID_PLAYER) + { + if (m_caster->GetTypeId() == TYPEID_PLAYER) + EffectLearnPetSpell(i); + + return; + } + + Player *player = (Player*)unitTarget; + + uint32 spellToLearn = (m_spellInfo->Id == 483 || m_spellInfo->Id == 55884) ? damage : m_spellInfo->EffectTriggerSpell[i]; + player->learnSpell(spellToLearn, false); + + sLog.outDebug("Spell: Player %u has learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow()); +} + +typedef std::list< std::pair > DispelList; +typedef std::list< std::pair > DispelChargesList; +void Spell::EffectDispel(uint32 i) +{ + if (!unitTarget) + return; + + DispelChargesList dispel_list; + + // Create dispel mask by dispel type + uint32 dispel_type = m_spellInfo->EffectMiscValue[i]; + uint32 dispelMask = GetDispellMask(DispelType(dispel_type)); + Unit::AuraMap const& auras = unitTarget->GetOwnedAuras(); + for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + { + Aura * aura = itr->second; + AuraApplication * aurApp = aura->GetApplicationOfTarget(unitTarget->GetGUID()); + if (!aurApp) + continue; + + if ((1<GetSpellProto()->Dispel) & dispelMask) + { + if (aura->GetSpellProto()->Dispel == DISPEL_MAGIC) + { + bool positive = aurApp->IsPositive() ? (!(aura->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)) : false; + + // do not remove positive auras if friendly target + // negative auras if non-friendly target + if (positive == unitTarget->IsFriendlyTo(m_caster)) + continue; + } + + // The charges / stack amounts don't count towards the total number of auras that can be dispelled. + // Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell + // Polymorph instead of 1 / (5 + 1) -> 16%. + bool dispel_charges = aura->GetSpellProto()->AttributesEx7 & SPELL_ATTR_EX7_DISPEL_CHARGES; + uint8 charges = dispel_charges ? aura->GetCharges() : aura->GetStackAmount(); + if (charges > 0) + dispel_list.push_back(std::make_pair(aura, charges)); + } + } + + if (dispel_list.empty()) + return; + + // Ok if exist some buffs for dispel try dispel it + uint32 failCount = 0; + DispelList success_list; + WorldPacket dataFail(SMSG_DISPEL_FAILED, 8+8+4+4+damage*4); + // dispel N = damage buffs (or while exist buffs for dispel) + for (int32 count = 0; count < damage && !dispel_list.empty();) + { + // Random select buff for dispel + DispelChargesList::iterator itr = dispel_list.begin(); + std::advance(itr, urand(0, dispel_list.size() - 1)); + + bool success = false; + // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance." + if (!GetDispelChance(itr->first->GetCaster(), unitTarget, itr->first->GetId(), !unitTarget->IsFriendlyTo(m_caster), &success)) + { + dispel_list.erase(itr); + continue; + } + else + { + if (success) + { + success_list.push_back(std::make_pair(itr->first->GetId(), itr->first->GetCasterGUID())); + --itr->second; + if (itr->second <= 0) + dispel_list.erase(itr); + } + else + { + if (!failCount) + { + // Failed to dispell + dataFail << uint64(m_caster->GetGUID()); // Caster GUID + dataFail << uint64(unitTarget->GetGUID()); // Victim GUID + dataFail << uint32(m_spellInfo->Id); // dispel spell id + } + ++failCount; + dataFail << uint32(itr->first->GetId()); // Spell Id + } + ++count; + } + } + + if (failCount) + m_caster->SendMessageToSet(&dataFail, true); + + if (success_list.empty()) + return; + + WorldPacket dataSuccess(SMSG_SPELLDISPELLOG, 8+8+4+1+4+damage*5); + // Send packet header + dataSuccess.append(unitTarget->GetPackGUID()); // Victim GUID + dataSuccess.append(m_caster->GetPackGUID()); // Caster GUID + dataSuccess << uint32(m_spellInfo->Id); // dispel spell id + dataSuccess << uint8(0); // not used + dataSuccess << uint32(success_list.size()); // count + for (DispelList::iterator itr = success_list.begin(); itr != success_list.end(); ++itr) + { + // Send dispelled spell info + dataSuccess << uint32(itr->first); // Spell Id + dataSuccess << uint8(0); // 0 - dispelled !=0 cleansed + unitTarget->RemoveAurasDueToSpellByDispel(itr->first, itr->second, m_caster); + } + m_caster->SendMessageToSet(&dataSuccess, true); + + // On success dispel + // Devour Magic + if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == SPELLCATEGORY_DEVOUR_MAGIC) + { + int32 heal_amount = SpellMgr::CalculateSpellEffectAmount(m_spellInfo, 1); + m_caster->CastCustomSpell(m_caster, 19658, &heal_amount, NULL, NULL, true); + } +} + +void Spell::EffectDualWield(uint32 /*i*/) +{ + unitTarget->SetCanDualWield(true); + if (unitTarget->GetTypeId() == TYPEID_UNIT) + unitTarget->ToCreature()->UpdateDamagePhysical(OFF_ATTACK); +} + +void Spell::EffectPull(uint32 /*i*/) +{ + // TODO: create a proper pull towards distract spell center for distract + sLog.outDebug("WORLD: Spell Effect DUMMY"); +} + +void Spell::EffectDistract(uint32 /*i*/) +{ + // Check for possible target + if (!unitTarget || unitTarget->isInCombat()) + return; + + // target must be OK to do this + if (unitTarget->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING)) + return; + + float angle = unitTarget->GetAngle(&m_targets.m_dstPos); + + if (unitTarget->GetTypeId() == TYPEID_PLAYER) + { + // For players just turn them + unitTarget->ToPlayer()->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false); + unitTarget->ToPlayer()->SendTeleportAckPacket(); + } + else + { + // Set creature Distracted, Stop it, And turn it + unitTarget->SetOrientation(angle); + unitTarget->StopMoving(); + unitTarget->GetMotionMaster()->MoveDistract(damage * IN_MILLISECONDS); + } +} + +void Spell::EffectPickPocket(uint32 /*i*/) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + // victim must be creature and attackable + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget)) + return; + + // victim have to be alive and humanoid or undead + if (unitTarget->isAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0) + m_caster->ToPlayer()->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING); +} + +void Spell::EffectAddFarsight(uint32 i) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + float radius = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); + int32 duration = GetSpellDuration(m_spellInfo); + // Caster not in world, might be spell triggered from aura removal + if (!m_caster->IsInWorld()) + return; + DynamicObject* dynObj = new DynamicObject; + if (!dynObj->Create(objmgr.GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, m_targets.m_dstPos, radius, true)) + { + delete dynObj; + return; + } + dynObj->SetDuration(duration); + dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002); + m_caster->AddDynObject(dynObj); + + dynObj->setActive(true); //must before add to map to be put in world container + dynObj->GetMap()->Add(dynObj); //grid will also be loaded + + // Need to update visibility of object for client to accept farsight guid + m_caster->ToPlayer()->SetViewpoint(dynObj, true); + //m_caster->ToPlayer()->UpdateVisibilityOf(dynObj); +} + +void Spell::EffectTeleUnitsFaceCaster(uint32 i) +{ + if (!unitTarget) + return; + + if (unitTarget->isInFlight()) + return; + + float dis = m_caster->GetSpellRadiusForTarget(unitTarget, sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); + + float fx,fy,fz; + m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis); + + unitTarget->NearTeleportTo(fx,fy,fz,-m_caster->GetOrientation(),unitTarget == m_caster); +} + +void Spell::EffectLearnSkill(uint32 i) +{ + if (unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + if (damage < 0) + return; + + uint32 skillid = m_spellInfo->EffectMiscValue[i]; + uint16 skillval = unitTarget->ToPlayer()->GetPureSkillValue(skillid); + unitTarget->ToPlayer()->SetSkill(skillid, SpellMgr::CalculateSpellEffectAmount(m_spellInfo, i), skillval?skillval:1, damage*75); +} + +void Spell::EffectAddHonor(uint32 /*i*/) +{ + if (unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + // not scale value for item based reward (/10 value expected) + if (m_CastItem) + { + unitTarget->ToPlayer()->RewardHonor(NULL, 1, damage/10); + sLog.outError("SpellEffect::AddHonor (spell_id %u) rewards %d honor points (item %u) for player: %u", m_spellInfo->Id, damage/10, m_CastItem->GetEntry(),unitTarget->ToPlayer()->GetGUIDLow()); + return; + } + + // do not allow to add too many honor for player (50 * 21) = 1040 at level 70, or (50 * 31) = 1550 at level 80 + if (damage <= 50) + { + uint32 honor_reward = Trinity::Honor::hk_honor_at_level(unitTarget->getLevel(), damage); + unitTarget->ToPlayer()->RewardHonor(NULL, 1, honor_reward); + sLog.outDebug("SpellEffect::AddHonor (spell_id %u) rewards %u honor points (scale) to player: %u", m_spellInfo->Id, honor_reward, unitTarget->ToPlayer()->GetGUIDLow()); + } + else + { + //maybe we have correct honor_gain in damage already + unitTarget->ToPlayer()->RewardHonor(NULL, 1, damage); + sLog.outError("SpellEffect::AddHonor (spell_id %u) rewards %u honor points (non scale) for player: %u", m_spellInfo->Id, damage, unitTarget->ToPlayer()->GetGUIDLow()); + } +} + +void Spell::EffectTradeSkill(uint32 /*i*/) +{ + if (unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + // uint32 skillid = m_spellInfo->EffectMiscValue[i]; + // uint16 skillmax = unitTarget->ToPlayer()->(skillid); + // unitTarget->ToPlayer()->SetSkill(skillid,skillval?skillval:1,skillmax+75); +} + +void Spell::EffectEnchantItemPerm(uint32 effect_idx) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + if (!itemTarget) + return; + + Player* p_caster = (Player*)m_caster; + + // Handle vellums + if (itemTarget->IsWeaponVellum() || itemTarget->IsArmorVellum()) + { + // destroy one vellum from stack + uint32 count = 1; + p_caster->DestroyItemCount(itemTarget,count,true); + unitTarget=p_caster; + // and add a scroll + DoCreateItem(effect_idx,m_spellInfo->EffectItemType[effect_idx]); + itemTarget=NULL; + m_targets.setItemTarget(NULL); + } + else + { + // do not increase skill if vellum used + if (!(m_CastItem && m_CastItem->GetProto()->Flags & ITEM_FLAGS_TRIGGERED_CAST)) + p_caster->UpdateCraftSkill(m_spellInfo->Id); + + uint32 enchant_id = m_spellInfo->EffectMiscValue[effect_idx]; + if (!enchant_id) + return; + + SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if (!pEnchant) + return; + + // item can be in trade slot and have owner diff. from caster + Player* item_owner = itemTarget->GetOwner(); + if (!item_owner) + return; + + if (item_owner != p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) + { + sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)", + p_caster->GetName(),p_caster->GetSession()->GetAccountId(), + itemTarget->GetProto()->Name1,itemTarget->GetEntry(), + item_owner->GetName(),item_owner->GetSession()->GetAccountId()); + } + + // remove old enchanting before applying new if equipped + item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false); + + itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0); + + // add new enchanting if equipped + item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,true); + } +} + +void Spell::EffectEnchantItemPrismatic(uint32 effect_idx) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + if (!itemTarget) + return; + + Player* p_caster = (Player*)m_caster; + + uint32 enchant_id = m_spellInfo->EffectMiscValue[effect_idx]; + if (!enchant_id) + return; + + SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if (!pEnchant) + return; + + // support only enchantings with add socket in this slot + { + bool add_socket = false; + for (uint8 i = 0; i < 3; ++i) + { + if (pEnchant->type[i] == ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET) + { + add_socket = true; + break; + } + } + if (!add_socket) + { + sLog.outError("Spell::EffectEnchantItemPrismatic: attempt apply enchant spell %u with SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC (%u) but without ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET (%u), not suppoted yet.", + m_spellInfo->Id,SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC,ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET); + return; + } + } + + // item can be in trade slot and have owner diff. from caster + Player* item_owner = itemTarget->GetOwner(); + if (!item_owner) + return; + + if (item_owner != p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) + { + sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)", + p_caster->GetName(),p_caster->GetSession()->GetAccountId(), + itemTarget->GetProto()->Name1,itemTarget->GetEntry(), + item_owner->GetName(),item_owner->GetSession()->GetAccountId()); + } + + // remove old enchanting before applying new if equipped + item_owner->ApplyEnchantment(itemTarget,PRISMATIC_ENCHANTMENT_SLOT,false); + + itemTarget->SetEnchantment(PRISMATIC_ENCHANTMENT_SLOT, enchant_id, 0, 0); + + // add new enchanting if equipped + item_owner->ApplyEnchantment(itemTarget,PRISMATIC_ENCHANTMENT_SLOT,true); +} + +void Spell::EffectEnchantItemTmp(uint32 i) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player* p_caster = (Player*)m_caster; + + // Rockbiter Weapon apply to both weapon + if (!itemTarget) + return; + if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[0] & 0x400000) + { + uint32 spell_id = 0; + + // enchanting spell selected by calculated damage-per-sec stored in Effect[1] base value + // Note: damage calculated (correctly) with rounding int32(float(v)) but + // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime + switch(damage) + { + // Rank 1 + case 2: spell_id = 36744; break; // 0% [ 7% == 2, 14% == 2, 20% == 2] + // Rank 2 + case 4: spell_id = 36753; break; // 0% [ 7% == 4, 14% == 4] + case 5: spell_id = 36751; break; // 20% + // Rank 3 + case 6: spell_id = 36754; break; // 0% [ 7% == 6, 14% == 6] + case 7: spell_id = 36755; break; // 20% + // Rank 4 + case 9: spell_id = 36761; break; // 0% [ 7% == 6] + case 10: spell_id = 36758; break; // 14% + case 11: spell_id = 36760; break; // 20% + default: + sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",damage); + return; + } + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); + if (!spellInfo) + { + sLog.outError("Spell::EffectEnchantItemTmp: unknown spell id %i", spell_id); + return; + + } + + for (int j = BASE_ATTACK; j <= OFF_ATTACK; ++j) + { + if (Item* item = p_caster->GetWeaponForAttack(WeaponAttackType(j))) + { + if (item->IsFitToSpellRequirements(m_spellInfo)) + { + Spell *spell = new Spell(m_caster, spellInfo, true); + SpellCastTargets targets; + targets.setItemTarget(item); + spell->prepare(&targets); + } + } + } + return; + } + if (!itemTarget) + return; + + uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; + + if (!enchant_id) + { + sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,i); + return; + } + + SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if (!pEnchant) + { + sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo->Id,i,enchant_id); + return; + } + + // select enchantment duration + uint32 duration; + + // rogue family enchantments exception by duration + if (m_spellInfo->Id == 38615) + duration = 1800; // 30 mins + // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints) + else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE) + duration = 3600; // 1 hour + // shaman family enchantments + else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN) + duration = 1800; // 30 mins + // other cases with this SpellVisual already selected + else if (m_spellInfo->SpellVisual[0] == 215) + duration = 1800; // 30 mins + // some fishing pole bonuses except Glow Worm which lasts full hour + else if (m_spellInfo->SpellVisual[0] == 563 && m_spellInfo->Id != 64401) + duration = 600; // 10 mins + // shaman rockbiter enchantments + else if (m_spellInfo->SpellVisual[0] == 0) + duration = 1800; // 30 mins + else if (m_spellInfo->Id == 29702) + duration = 300; // 5 mins + else if (m_spellInfo->Id == 37360) + duration = 300; // 5 mins + // default case + else + duration = 3600; // 1 hour + + // item can be in trade slot and have owner diff. from caster + Player* item_owner = itemTarget->GetOwner(); + if (!item_owner) + return; + + if (item_owner != p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) + { + sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)", + p_caster->GetName(), p_caster->GetSession()->GetAccountId(), + itemTarget->GetProto()->Name1, itemTarget->GetEntry(), + item_owner->GetName(), item_owner->GetSession()->GetAccountId()); + } + + // remove old enchanting before applying new if equipped + item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT, false); + + itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration * 1000, 0); + + // add new enchanting if equipped + item_owner->ApplyEnchantment(itemTarget, TEMP_ENCHANTMENT_SLOT, true); +} + +void Spell::EffectTameCreature(uint32 /*i*/) +{ + if (m_caster->GetPetGUID()) + return; + + if (!unitTarget) + return; + + if (unitTarget->GetTypeId() != TYPEID_UNIT) + return; + + Creature* creatureTarget = unitTarget->ToCreature(); + + if (creatureTarget->isPet()) + return; + + if (m_caster->getClass() != CLASS_HUNTER) + return; + + // cast finish successfully + //SendChannelUpdate(0); + finish(); + + Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget,m_spellInfo->Id); + if (!pet) // in very specific state like near world end/etc. + return; + + // "kill" original creature + creatureTarget->ForcedDespawn(); + + uint8 level = (creatureTarget->getLevel() < (m_caster->getLevel() - 5)) ? (m_caster->getLevel() - 5) : creatureTarget->getLevel(); + + // prepare visual effect for levelup + pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1); + + // add to world + pet->GetMap()->Add(pet->ToCreature()); + + // visual effect for levelup + pet->SetUInt32Value(UNIT_FIELD_LEVEL, level); + + // caster have pet now + m_caster->SetMinion(pet, true); + + pet->InitTalentForLevel(); + + if (m_caster->GetTypeId() == TYPEID_PLAYER) + { + pet->SavePetToDB(PET_SAVE_AS_CURRENT); + m_caster->ToPlayer()->PetSpellInitialize(); + } +} + +void Spell::EffectSummonPet(uint32 i) +{ + Player *owner = NULL; + if (m_originalCaster) + { + if (m_originalCaster->GetTypeId() == TYPEID_PLAYER) + owner = (Player*)m_originalCaster; + else if (m_originalCaster->ToCreature()->isTotem()) + owner = m_originalCaster->GetCharmerOrOwnerPlayerOrPlayerItself(); + } + + uint32 petentry = m_spellInfo->EffectMiscValue[i]; + + if (!owner) + { + SummonPropertiesEntry const *properties = sSummonPropertiesStore.LookupEntry(67); + if (properties) + SummonGuardian(i, petentry, properties); + return; + } + + Pet *OldSummon = owner->GetPet(); + + // if pet requested type already exist + if (OldSummon) + { + if (petentry == 0 || OldSummon->GetEntry() == petentry) + { + // pet in corpse state can't be summoned + if (OldSummon->isDead()) + return; + + assert(OldSummon->GetMap() == owner->GetMap()); + + //OldSummon->GetMap()->Remove(OldSummon->ToCreature(),false); + + float px, py, pz; + owner->GetClosePoint(px, py, pz, OldSummon->GetObjectSize()); + + OldSummon->NearTeleportTo(px, py, pz, OldSummon->GetOrientation()); + //OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation()); + //OldSummon->SetMap(owner->GetMap()); + //owner->GetMap()->Add(OldSummon->ToCreature()); + + if (owner->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled()) + owner->ToPlayer()->PetSpellInitialize(); + + return; + } + + if (owner->GetTypeId() == TYPEID_PLAYER) + owner->ToPlayer()->RemovePet(OldSummon,(OldSummon->getPetType() == HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false); + else + return; + } + + float x, y, z; + owner->GetClosePoint(x, y, z, owner->GetObjectSize()); + Pet* pet = owner->SummonPet(petentry, x, y, z, owner->GetOrientation(), SUMMON_PET, 0); + if (!pet) + return; + + if (m_caster->GetTypeId() == TYPEID_UNIT) + { + if (m_caster->ToCreature()->isTotem()) + pet->SetReactState(REACT_AGGRESSIVE); + else + pet->SetReactState(REACT_DEFENSIVE); + } + + pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); + + // generate new name for summon pet + std::string new_name=objmgr.GeneratePetName(petentry); + if (!new_name.empty()) + pet->SetName(new_name); +} + +void Spell::EffectLearnPetSpell(uint32 i) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player *_player = (Player*)m_caster; + + Pet *pet = _player->GetPet(); + if (!pet) + return; + if (!pet->isAlive()) + return; + + SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]); + if (!learn_spellproto) + return; + + pet->learnSpell(learn_spellproto->Id); + + pet->SavePetToDB(PET_SAVE_AS_CURRENT); + _player->PetSpellInitialize(); +} + +void Spell::EffectTaunt(uint32 /*i*/) +{ + if (!unitTarget) + return; + + // this effect use before aura Taunt apply for prevent taunt already attacking target + // for spell as marked "non effective at already attacking target" + if (!unitTarget || !unitTarget->CanHaveThreatList() + || unitTarget->getVictim() == m_caster) + { + SendCastResult(SPELL_FAILED_DONT_REPORT); + return; + } + + if (m_spellInfo->Id == 62124) + { + int32 damageDone = 1 + m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.5f; + m_caster->DealDamage(unitTarget, damageDone, NULL, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_HOLY, m_spellInfo, false); + m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damageDone, SPELL_SCHOOL_MASK_HOLY, 0, 0, false, false, false); + } + + // Also use this effect to set the taunter's threat to the taunted creature's highest value + if (unitTarget->getThreatManager().getCurrentVictim()) + { + float myThreat = unitTarget->getThreatManager().getThreat(m_caster); + float itsThreat = unitTarget->getThreatManager().getCurrentVictim()->getThreat(); + if (itsThreat > myThreat) + unitTarget->getThreatManager().addThreat(m_caster, itsThreat - myThreat); + } + + //Set aggro victim to caster + if (!unitTarget->getThreatManager().getOnlineContainer().empty()) + if (HostileReference* forcedVictim = unitTarget->getThreatManager().getOnlineContainer().getReferenceByTarget(m_caster)) + unitTarget->getThreatManager().setCurrentVictim(forcedVictim); + + if (unitTarget->ToCreature()->IsAIEnabled && !unitTarget->ToCreature()->HasReactState(REACT_PASSIVE)) + unitTarget->ToCreature()->AI()->AttackStart(m_caster); +} + +void Spell::EffectWeaponDmg(uint32 /*i*/) +{ +} + +void Spell::SpellDamageWeaponDmg(uint32 i) +{ + if (!unitTarget) + return; + if (!unitTarget->isAlive()) + return; + + // multiple weapon dmg effect workaround + // execute only the last weapon damage + // and handle all effects at once + for (uint32 j = i + 1; j < 3; ++j) + { + switch (m_spellInfo->Effect[j]) + { + case SPELL_EFFECT_WEAPON_DAMAGE: + case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: + case SPELL_EFFECT_NORMALIZED_WEAPON_DMG: + case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: + return; // we must calculate only at last weapon effect + break; + } + } + + // some spell specific modifiers + float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage + int32 fixed_bonus = 0; + int32 spell_bonus = 0; // bonus specific for spell + + switch (m_spellInfo->SpellFamilyName) + { + case SPELLFAMILY_WARRIOR: + { + // Devastate (player ones) + if (m_spellInfo->SpellFamilyFlags[1] & 0x40) + { + // Player can apply only 58567 Sunder Armor effect. + bool needCast = !unitTarget->HasAura(58567, m_caster->GetGUID()); + if (needCast) + m_caster->CastSpell(unitTarget, 58567, true); + + if (Aura * aur = unitTarget->GetAura(58567, m_caster->GetGUID())) + { + // 58388 - Glyph of Devastate dummy aura. + if (int32 num = (needCast ? 0 : 1) + (m_caster->HasAura(58388) ? 1 : 0)) + aur->ModStackAmount(num); + fixed_bonus += (aur->GetStackAmount() - 1) * CalculateDamage(2, unitTarget); + } + } + break; + } + case SPELLFAMILY_ROGUE: + { + // Fan of Knives, Hemorrhage, Ghostly Strike + if ((m_spellInfo->SpellFamilyFlags[1] & 0x40000) + || (m_spellInfo->SpellFamilyFlags[0] & 0x6000000)) + { + // Hemorrhage + if (m_spellInfo->SpellFamilyFlags[0] & 0x2000000) + { + if (m_caster->GetTypeId() == TYPEID_PLAYER) + m_caster->ToPlayer()->AddComboPoints(unitTarget, 1, this); + } + // 50% more damage with daggers + if (m_caster->GetTypeId() == TYPEID_PLAYER) + if (Item* item = m_caster->ToPlayer()->GetWeaponForAttack(m_attackType, true)) + if (item->GetProto()->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER) + totalDamagePercentMod *= 1.5f; + } + // Mutilate (for each hand) + else if (m_spellInfo->SpellFamilyFlags[1] & 0x6) + { + bool found = false; + // fast check + if (unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON, m_spellInfo, m_caster)) + found = true; + // full aura scan + else + { + Unit::AuraApplicationMap const& auras = unitTarget->GetAppliedAuras(); + for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + { + if (itr->second->GetBase()->GetSpellProto()->Dispel == DISPEL_POISON) + { + found = true; + break; + } + } + } + + if (found) + totalDamagePercentMod *= 1.2f; // 120% if poisoned + } + break; + } + case SPELLFAMILY_PALADIN: + { + // Seal of Command - Increase damage by 36% on every swing + if (m_spellInfo->SpellFamilyFlags[0] & 0x2000000) + { + totalDamagePercentMod *= 1.36f; //136% damage + } + + // Seal of Command Unleashed + else if (m_spellInfo->Id == 20467) + { + spell_bonus += int32(0.08f*m_caster->GetTotalAttackPowerValue(BASE_ATTACK)); + spell_bonus += int32(0.13f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo))); + } + break; + } + case SPELLFAMILY_SHAMAN: + { + // Skyshatter Harness item set bonus + // Stormstrike + if (AuraEffect * aurEff = m_caster->IsScriptOverriden(m_spellInfo, 5634)) + m_caster->CastSpell(m_caster, 38430, true, NULL, aurEff); + break; + } + case SPELLFAMILY_DRUID: + { + // Mangle (Cat): CP + if (m_spellInfo->SpellFamilyFlags[1] & 0x400) + { + if (m_caster->GetTypeId() == TYPEID_PLAYER) + m_caster->ToPlayer()->AddComboPoints(unitTarget,1, this); + } + // Shred, Maul - Rend and Tear + else if (m_spellInfo->SpellFamilyFlags[0] & 0x00008800 && unitTarget->HasAuraState(AURA_STATE_BLEEDING)) + { + if (AuraEffect const* rendAndTear = m_caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 2859, 0)) + { + totalDamagePercentMod *= float((rendAndTear->GetAmount() + 100.0f) / 100.0f); + } + } + break; + } + case SPELLFAMILY_HUNTER: + { + // Kill Shot - bonus damage from Ranged Attack Power + if (m_spellInfo->SpellFamilyFlags[1] & 0x800000) + spell_bonus += int32(0.4f*m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)); + break; + } + case SPELLFAMILY_DEATHKNIGHT: + { + // Plague Strike + if (m_spellInfo->SpellFamilyFlags[0] & 0x00000001) + { + // Glyph of Plague Strike + if (AuraEffect * aurEff = m_caster->GetAuraEffect(58657,0)) + totalDamagePercentMod *= float((aurEff->GetAmount() + 100.0f) / 100.0f); + } + // Blood Strike + else if (m_spellInfo->SpellFamilyFlags[0] & 0x400000) + { + totalDamagePercentMod *= (float(unitTarget->GetDiseasesByCaster(m_caster->GetGUID())) * 12.5f + 100.0f) / 100.0f; + + // Glyph of Blood Strike + if (AuraEffect * aurEff = m_caster->GetAuraEffect(59332,0)) + { + if (unitTarget->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED)) + totalDamagePercentMod *= float((20 + 100.0f) / 100.0f); + } + } + // Death Strike + else if (m_spellInfo->SpellFamilyFlags[0] & 0x00000010) + { + // Glyph of Death Strike + if (AuraEffect * aurEff = m_caster->GetAuraEffect(59336,0)) + { + if (uint32 runic = m_caster->GetPower(POWER_RUNIC_POWER)) + { + if (runic > 25) + runic = 25; + + totalDamagePercentMod *= float((runic + 100.0f) / 100.0f); + } + } + } + // Obliterate (12.5% more damage per disease) + else if (m_spellInfo->SpellFamilyFlags[1] & 0x20000) + { + bool consumeDiseases = true; + // Annihilation + if (AuraEffect * aurEff = m_caster->GetDummyAuraEffect(SPELLFAMILY_DEATHKNIGHT, 2710, 0)) + { + // Do not consume diseases if roll sucesses + if (roll_chance_i(aurEff->GetAmount())) + consumeDiseases = false; + } + totalDamagePercentMod *= (float(CalculateDamage(2, unitTarget) * unitTarget->GetDiseasesByCaster(m_caster->GetGUID(), consumeDiseases) / 2) + 100.0f) / 100.0f; + } + // Blood-Caked Strike - Blood-Caked Blade + else if (m_spellInfo->SpellIconID == 1736) + totalDamagePercentMod *= (float(unitTarget->GetDiseasesByCaster(m_caster->GetGUID())) * 12.5f + 100.0f) / 100.0f; + break; + } + } + + bool normalized = false; + float weaponDamagePercentMod = 1.0; + for (int j = 0; j < 3; ++j) + { + switch(m_spellInfo->Effect[j]) + { + case SPELL_EFFECT_WEAPON_DAMAGE: + case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: + fixed_bonus += CalculateDamage(j, unitTarget); + break; + case SPELL_EFFECT_NORMALIZED_WEAPON_DMG: + fixed_bonus += CalculateDamage(j, unitTarget); + normalized = true; + break; + case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: + weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f; + break; + default: + break; // not weapon damage effect, just skip + } + } + + // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage + if (fixed_bonus || spell_bonus) + { + UnitMods unitMod; + switch(m_attackType) + { + default: + case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break; + case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break; + case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break; + } + + float weapon_total_pct = 1.0f; + if (m_spellInfo->SchoolMask & SPELL_SCHOOL_MASK_NORMAL) + weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT); + + if (fixed_bonus) + fixed_bonus = int32(fixed_bonus * weapon_total_pct); + if (spell_bonus) + spell_bonus = int32(spell_bonus * weapon_total_pct); + } + + int32 weaponDamage = m_caster->CalculateDamage(m_attackType, normalized, true); + + // Sequence is important + for (int j = 0; j < 3; ++j) + { + // We assume that a spell have at most one fixed_bonus + // and at most one weaponDamagePercentMod + switch(m_spellInfo->Effect[j]) + { + case SPELL_EFFECT_WEAPON_DAMAGE: + case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: + case SPELL_EFFECT_NORMALIZED_WEAPON_DMG: + weaponDamage += fixed_bonus; + break; + case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: + weaponDamage = int32(weaponDamage * weaponDamagePercentMod); + default: + break; // not weapon damage effect, just skip + } + } + + if (spell_bonus) + weaponDamage += spell_bonus; + + if (totalDamagePercentMod != 1.0f) + weaponDamage = int32(weaponDamage * totalDamagePercentMod); + + // prevent negative damage + uint32 eff_damage = uint32(weaponDamage > 0 ? weaponDamage : 0); + + // Add melee damage bonuses (also check for negative) + m_caster->MeleeDamageBonus(unitTarget, &eff_damage, m_attackType, m_spellInfo); + m_damage+= eff_damage; +} + +void Spell::EffectThreat(uint32 /*i*/) +{ + if (!unitTarget || !unitTarget->isAlive() || !m_caster->isAlive()) + return; + + if (!unitTarget->CanHaveThreatList()) + return; + + unitTarget->AddThreat(m_caster, float(damage)); +} + +void Spell::EffectHealMaxHealth(uint32 /*i*/) +{ + if (!unitTarget) + return; + if (!unitTarget->isAlive()) + return; + + int32 addhealth; + if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN) // Lay on Hands + { + if (m_caster && m_caster->GetGUID() == unitTarget->GetGUID()) + { + m_caster->CastSpell(m_caster, 25771, true); // Forbearance + m_caster->CastSpell(m_caster, 61988, true); // Immune shield marker (serverside) + m_caster->CastSpell(m_caster, 61987, true); // Avenging Wrath marker + } + + addhealth = m_caster->GetMaxHealth(); + } + else + addhealth = unitTarget->GetMaxHealth() - unitTarget->GetHealth(); + if (m_originalCaster) + { + addhealth=m_originalCaster->SpellHealingBonus(unitTarget,m_spellInfo, addhealth, HEAL); + m_originalCaster->DealHeal(unitTarget, addhealth, m_spellInfo); + } +} + +void Spell::EffectInterruptCast(uint32 /*i*/) +{ + if (!unitTarget) + return; + if (!unitTarget->isAlive()) + return; + + // TODO: not all spells that used this effect apply cooldown at school spells + // also exist case: apply cooldown to interrupted cast only and to all spells + for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i) + { + if (Spell* spell = unitTarget->GetCurrentSpell(CurrentSpellTypes(i))) + { + SpellEntry const* curSpellInfo = spell->m_spellInfo; + // check if we can interrupt spell + if ((spell->getState() == SPELL_STATE_CASTING + || spell->getState() == SPELL_STATE_PREPARING && spell->GetCastTime() > 0.0f) + && curSpellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && curSpellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE) + { + if (m_originalCaster) + { + int32 duration = m_originalCaster->ModSpellDuration(m_spellInfo, unitTarget, m_originalCaster->CalcSpellDuration(m_spellInfo), false); + unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(curSpellInfo), duration/*GetSpellDuration(m_spellInfo)*/); + } + unitTarget->InterruptSpell(CurrentSpellTypes(i), false); + } + } + } +} + +void Spell::EffectSummonObjectWild(uint32 i) +{ + uint32 gameobject_id = m_spellInfo->EffectMiscValue[i]; + + GameObject* pGameObj = new GameObject; + + WorldObject* target = focusObject; + if (!target) + target = m_caster; + + float x, y, z; + if (m_targets.HasDst()) + m_targets.m_dstPos.GetPosition(x, y, z); + else + m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE); + + Map *map = target->GetMap(); + + if (!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map, + m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) + { + delete pGameObj; + return; + } + + int32 duration = GetSpellDuration(m_spellInfo); + + pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); + pGameObj->SetSpellId(m_spellInfo->Id); + + // Wild object not have owner and check clickable by players + map->Add(pGameObj); + + if (pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP && m_caster->GetTypeId() == TYPEID_PLAYER) + { + Player *pl = m_caster->ToPlayer(); + BattleGround* bg = pl->GetBattleGround(); + + switch(pGameObj->GetMapId()) + { + case 489: //WS + { + if (bg && bg->GetTypeID(true) == BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS) + { + uint32 team = ALLIANCE; + + if (pl->GetTeam() == team) + team = HORDE; + + ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team); + } + break; + } + case 566: //EY + { + if (bg && bg->GetTypeID(true) == BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS) + { + ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID()); + } + break; + } + } + } + + if (uint32 linkedEntry = pGameObj->GetGOInfo()->GetLinkedGameObjectEntry()) + { + GameObject* linkedGO = new GameObject; + if (linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map, + m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) + { + linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); + linkedGO->SetSpellId(m_spellInfo->Id); + + // Wild object not have owner and check clickable by players + map->Add(linkedGO); + } + else + { + delete linkedGO; + linkedGO = NULL; + return; + } + } +} + +void Spell::EffectScriptEffect(uint32 effIndex) +{ + // TODO: we must implement hunter pet summon at login there (spell 6962) + + switch(m_spellInfo->SpellFamilyName) + { + case SPELLFAMILY_GENERIC: + { + switch(m_spellInfo->Id) + { + case 6962: + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player* plr = m_caster->ToPlayer(); + if (plr && plr->GetLastPetNumber()) + { + PetType NewPetType = (plr->getClass() == CLASS_HUNTER) ? HUNTER_PET : SUMMON_PET; + if (Pet* NewPet = new Pet(plr,NewPetType)) + { + if (NewPet->LoadPetFromDB(plr, 0, plr->GetLastPetNumber(), true)) + { + NewPet->SetHealth(NewPet->GetMaxHealth()); + NewPet->SetPower(NewPet->getPowerType(),NewPet->GetMaxPower(NewPet->getPowerType())); + + switch (NewPet->GetEntry()) + { + case 11859: + case 89: + NewPet->SetEntry(416); + break; + default: + break; + } + } + else + delete NewPet; + } + } + return; + } + // Glyph of Starfire + case 54846: + { + if (AuraEffect const * aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE,SPELLFAMILY_DRUID,0x00000002,0,0,m_caster->GetGUID())) + { + uint32 countMin = aurEff->GetBase()->GetMaxDuration(); + uint32 countMax = 18000; + countMax += m_caster->HasAura(38414) ? 3000 : 0; + countMax += m_caster->HasAura(57865) ? 3000 : 0; + + if (countMin < countMax) + { + aurEff->GetBase()->SetDuration(uint32(aurEff->GetBase()->GetDuration()+3000)); + aurEff->GetBase()->SetMaxDuration(countMin+3000); + } + } + return; + } + // Glyph of Backstab + case 63975: + { + if (AuraEffect const * aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE,SPELLFAMILY_ROGUE,0x00100000,0,0,m_caster->GetGUID())) + { + uint32 countMin = aurEff->GetBase()->GetMaxDuration(); + uint32 countMax = 12000; + countMax += m_caster->HasAura(56801) ? 4000 : 0; + + if (countMin < countMax) + { + aurEff->GetBase()->SetDuration(uint32(aurEff->GetBase()->GetDuration()+3000)); + aurEff->GetBase()->SetMaxDuration(countMin+2000); + } + + } + return; + } + // Dispelling Analysis + case 37028: + { + unitTarget->RemoveAurasDueToSpell(36904); + return; + } + case 45204: // Clone Me! + case 41055: // Copy Weapon + case 45206: // Copy Off-hand Weapon + unitTarget->CastSpell(m_caster, damage, false); + break; + case 45205: // Copy Offhand Weapon + case 41054: // Copy Weapon + m_caster->CastSpell(unitTarget, damage, false); + break; + // Despawn Horse + case 52267: + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) + return; + unitTarget->ToCreature()->ForcedDespawn(); + return; + } + case 55693: // Remove Collapsing Cave Aura + if (!unitTarget) + return; + unitTarget->RemoveAurasDueToSpell(SpellMgr::CalculateSpellEffectAmount(m_spellInfo, effIndex)); + break; + // PX-238 Winter Wondervolt TRAP + case 26275: + { + uint32 spells[4] = { 26272, 26157, 26273, 26274 }; + + // check presence + for (uint8 j = 0; j < 4; ++j) + if (unitTarget->HasAuraEffect(spells[j],0)) + return; + + // select spell + uint32 iTmpSpellId = spells[urand(0,3)]; + + // cast + unitTarget->CastSpell(unitTarget, iTmpSpellId, true); + return; + } + // Bending Shinbone + case 8856: + { + if (!itemTarget && m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + uint32 spell_id = 0; + switch(urand(1, 5)) + { + case 1: spell_id = 8854; break; + default: spell_id = 8855; break; + } + + m_caster->CastSpell(m_caster,spell_id,true,NULL); + return; + } + // Brittle Armor - need remove one 24575 Brittle Armor aura + case 24590: + unitTarget->RemoveAuraFromStack(24575); + return; + // Mercurial Shield - need remove one 26464 Mercurial Shield aura + case 26465: + unitTarget->RemoveAuraFromStack(26464); + return; + // Orb teleport spells + case 25140: + case 25143: + case 25650: + case 25652: + case 29128: + case 29129: + case 35376: + case 35727: + { + if (!unitTarget) + return; + + uint32 spellid; + switch(m_spellInfo->Id) + { + case 25140: spellid = 32571; break; + case 25143: spellid = 32572; break; + case 25650: spellid = 30140; break; + case 25652: spellid = 30141; break; + case 29128: spellid = 32568; break; + case 29129: spellid = 32569; break; + case 35376: spellid = 25649; break; + case 35727: spellid = 35730; break; + default: + return; + } + + unitTarget->CastSpell(unitTarget,spellid,false); + return; + } + // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell) + case 22539: + case 22972: + case 22975: + case 22976: + case 22977: + case 22978: + case 22979: + case 22980: + case 22981: + case 22982: + case 22983: + case 22984: + case 22985: + { + if (!unitTarget || !unitTarget->isAlive()) + return; + + // Onyxia Scale Cloak + if (unitTarget->HasAura(22683)) + return; + + // Shadow Flame + m_caster->CastSpell(unitTarget, 22682, true); + return; + } + // Piccolo of the Flaming Fire + case 17512: + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE); + return; + } + // Escape artist + case 20589: + { + if (!unitTarget) + return; + unitTarget->RemoveMovementImpairingAuras(); + return; + } + // Decimate + case 28374: + case 54426: + if (unitTarget) + { + int32 damage = (int32)unitTarget->GetHealth() - (int32)unitTarget->GetMaxHealth() * 0.05f; + if (damage > 0) + m_caster->CastCustomSpell(28375, SPELLVALUE_BASE_POINT0, damage, unitTarget); + } + return; + // Mirren's Drinking Hat + case 29830: + { + uint32 item = 0; + switch (urand(1, 6)) + { + case 1: + case 2: + case 3: + item = 23584; break; // Loch Modan Lager + case 4: + case 5: + item = 23585; break; // Stouthammer Lite + case 6: + item = 23586; break; // Aerie Peak Pale Ale + } + if (item) + DoCreateItem(effIndex,item); + break; + } + // Improved Sprint + case 30918: + { + // Removes snares and roots. + unitTarget->RemoveMovementImpairingAuras(); + break; + } + // Spirit Walk + case 58876: + { + // Removes snares and roots. + unitTarget->RemoveMovementImpairingAuras(); + break; + } + // Plant Warmaul Ogre Banner + case 32307: + { + Player *p_caster = dynamic_cast(m_caster); + if (!p_caster) + break; + p_caster->RewardPlayerAndGroupAtEvent(18388, unitTarget); + Creature *cTarget = dynamic_cast(unitTarget); + if (!cTarget) + break; + cTarget->setDeathState(CORPSE); + cTarget->RemoveCorpse(); + break; + } + // Tidal Surge + case 38358: + if (unitTarget) + m_caster->CastSpell(unitTarget, 38353, true); + return; + /*// Flame Crash + case 41126: + { + if (!unitTarget) + return; + + unitTarget->CastSpell(unitTarget, 41131, true); + break; + }*/ + // Draw Soul + case 40904: + { + if (!unitTarget) + return; + + unitTarget->CastSpell(m_caster, 40903, true); + break; + } + case 48025: // Headless Horseman's Mount + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + // Prevent stacking of mounts and client crashes upon dismounting + unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED); + + // Triggered spell id dependent on riding skill and zone + bool canFly = true; + uint32 v_map = GetVirtualMapForMapAndZone(unitTarget->GetMapId(), unitTarget->GetZoneId()); + if (v_map != 530 && v_map != 571) + canFly = false; + + if (canFly && v_map == 571 && !unitTarget->ToPlayer()->HasSpell(54197)) + canFly = false; + + float x, y, z; + unitTarget->GetPosition(x, y, z); + uint32 areaFlag = unitTarget->GetBaseMap()->GetAreaFlag(x, y, z); + AreaTableEntry const *pArea = sAreaStore.LookupEntry(areaFlag); + if (canFly && pArea->flags & AREA_FLAG_NO_FLY_ZONE) + canFly = false; + + switch(unitTarget->ToPlayer()->GetBaseSkillValue(SKILL_RIDING)) + { + case 75: unitTarget->CastSpell(unitTarget, 51621, true); break; + case 150: unitTarget->CastSpell(unitTarget, 48024, true); break; + case 225: + { + if (canFly) + unitTarget->CastSpell(unitTarget, 51617, true); + else + unitTarget->CastSpell(unitTarget, 48024, true); + }break; + case 300: + { + if (canFly) + unitTarget->CastSpell(unitTarget, 48023, true); + else + unitTarget->CastSpell(unitTarget, 48024, true); + }break; + } + return; + } + case 47977: // Magic Broom + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + // Prevent stacking of mounts and client crashes upon dismounting + unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED); + + // Triggered spell id dependent on riding skill and zone + bool canFly = true; + uint32 v_map = GetVirtualMapForMapAndZone(unitTarget->GetMapId(), unitTarget->GetZoneId()); + if (v_map != 530 && v_map != 571) + canFly = false; + + if (canFly && v_map == 571 && !unitTarget->ToPlayer()->HasSpell(54197)) + canFly = false; + + float x, y, z; + unitTarget->GetPosition(x, y, z); + uint32 areaFlag = unitTarget->GetBaseMap()->GetAreaFlag(x, y, z); + AreaTableEntry const *pArea = sAreaStore.LookupEntry(areaFlag); + if (canFly && pArea->flags & AREA_FLAG_NO_FLY_ZONE) + canFly = false; + + switch(unitTarget->ToPlayer()->GetBaseSkillValue(SKILL_RIDING)) + { + case 75: unitTarget->CastSpell(unitTarget, 42680, true); break; + case 150: unitTarget->CastSpell(unitTarget, 42683, true); break; + case 225: + { + if (canFly) + unitTarget->CastSpell(unitTarget, 42667, true); + else + unitTarget->CastSpell(unitTarget, 42683, true); + }break; + case 300: + { + if (canFly) + unitTarget->CastSpell(unitTarget, 42668, true); + else + unitTarget->CastSpell(unitTarget, 42683, true); + }break; + } + return; + } + // Mug Transformation + case 41931: + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + uint8 bag = 19; + uint8 slot = 0; + Item *item = NULL; + + while (bag < 256) + { + item = m_caster->ToPlayer()->GetItemByPos(bag, slot); + if (item && item->GetEntry() == 38587) break; + ++slot; + if (slot == 39) + { + slot = 0; + ++bag; + } + } + if (bag < 256) + { + if (m_caster->ToPlayer()->GetItemByPos(bag,slot)->GetCount() == 1) m_caster->ToPlayer()->RemoveItem(bag,slot,true); + else m_caster->ToPlayer()->GetItemByPos(bag,slot)->SetCount(m_caster->ToPlayer()->GetItemByPos(bag,slot)->GetCount()-1); + // Spell 42518 (Braufest - Gratisprobe des Braufest herstellen) + m_caster->CastSpell(m_caster, 42518, true); + return; + } + break; + } + // Force Cast - Portal Effect: Sunwell Isle + case 44876: + { + if (!unitTarget) + return; + + unitTarget->CastSpell(unitTarget, 44870, true); + break; + } + // Brutallus - Burn + case 45141: + case 45151: + { + //Workaround for Range ... should be global for every ScriptEffect + float radius = GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex])); + if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->GetDistance(m_caster) >= radius && !unitTarget->HasAura(46394) && unitTarget != m_caster) + unitTarget->CastSpell(unitTarget, 46394, true); + + break; + } + // spell of Brutallus - Stomp + case 45185: + { + if (!unitTarget) + return; + + unitTarget->RemoveAurasDueToSpell(46394); + + break; + } + // Negative Energy + case 46289: + { + if (!unitTarget) + return; + + m_caster->CastSpell(unitTarget, 46285, true); + break; + } + // Goblin Weather Machine + case 46203: + { + if (!unitTarget) + return; + + uint32 spellId = 0; + switch(rand() % 4) + { + case 0: spellId = 46740; break; + case 1: spellId = 46739; break; + case 2: spellId = 46738; break; + case 3: spellId = 46736; break; + } + unitTarget->CastSpell(unitTarget, spellId, true); + break; + } + // 5,000 Gold + case 46642: + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + unitTarget->ToPlayer()->ModifyMoney(5000 * GOLD); + + break; + } + // Roll Dice - Decahedral Dwarven Dice + case 47770: + { + char buf[128]; + char *gender = "his"; + if (m_caster->getGender() > 0) + gender = "her"; + sprintf(buf, "%s rubs %s [Decahedral Dwarven Dice] between %s hands and rolls. One %u and one %u.", m_caster->GetName(), gender, gender, urand(1,10), urand(1,10)); + m_caster->MonsterTextEmote(buf, 0); + break; + } + // Roll 'dem Bones - Worn Troll Dice + case 47776: + { + char buf[128]; + char *gender = "his"; + if (m_caster->getGender() > 0) + gender = "her"; + sprintf(buf, "%s causually tosses %s [Worn Troll Dice]. One %u and one %u.", m_caster->GetName(), gender, urand(1,6), urand(1,6)); + m_caster->MonsterTextEmote(buf, 0); + break; + } + // Vigilance + case 50725: + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + // Remove Taunt cooldown + unitTarget->ToPlayer()->RemoveSpellCooldown(355, true); + + return; + } + // Death Knight Initiate Visual + case 51519: + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) + return; + + uint32 iTmpSpellId = 0; + switch (unitTarget->GetDisplayId()) + { + case 25369: iTmpSpellId = 51552; break; // bloodelf female + case 25373: iTmpSpellId = 51551; break; // bloodelf male + case 25363: iTmpSpellId = 51542; break; // draenei female + case 25357: iTmpSpellId = 51541; break; // draenei male + case 25361: iTmpSpellId = 51537; break; // dwarf female + case 25356: iTmpSpellId = 51538; break; // dwarf male + case 25372: iTmpSpellId = 51550; break; // forsaken female + case 25367: iTmpSpellId = 51549; break; // forsaken male + case 25362: iTmpSpellId = 51540; break; // gnome female + case 25359: iTmpSpellId = 51539; break; // gnome male + case 25355: iTmpSpellId = 51534; break; // human female + case 25354: iTmpSpellId = 51520; break; // human male + case 25360: iTmpSpellId = 51536; break; // nightelf female + case 25358: iTmpSpellId = 51535; break; // nightelf male + case 25368: iTmpSpellId = 51544; break; // orc female + case 25364: iTmpSpellId = 51543; break; // orc male + case 25371: iTmpSpellId = 51548; break; // tauren female + case 25366: iTmpSpellId = 51547; break; // tauren male + case 25370: iTmpSpellId = 51545; break; // troll female + case 25365: iTmpSpellId = 51546; break; // troll male + default: return; + } + + unitTarget->CastSpell(unitTarget, iTmpSpellId, true); + Creature* npc = unitTarget->ToCreature(); + npc->LoadEquipment(npc->GetEquipmentId()); + return; + } + // Emblazon Runeblade + case 51770: + { + if (!m_originalCaster) + return; + + m_originalCaster->CastSpell(m_originalCaster, damage, false); + break; + } + // Deathbolt from Thalgran Blightbringer + // reflected by Freya's Ward + // Retribution by Sevenfold Retribution + case 51854: + { + if (!m_caster || !unitTarget) + return; + if (unitTarget->HasAura(51845)) + unitTarget->CastSpell(m_caster, 51856, true); + else + m_caster->CastSpell(unitTarget, 51855, true); + break; + } + // Summon Ghouls On Scarlet Crusade + case 51904: + { + if (!m_targets.HasDst()) + return; + + float x, y, z; + float radius = GetSpellRadius(m_spellInfo, effIndex, true); + for (uint8 i = 0; i < 15; ++i) + { + m_caster->GetRandomPoint(m_targets.m_dstPos, radius, x, y, z); + m_caster->CastSpell(x, y, z, 54522, true); + } + break; + } + case 52173: // Coyote Spirit Despawn + case 60243: // Blood Parrot Despawn + if (unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->ToCreature()->isSummon()) + unitTarget->ToTempSummon()->UnSummon(); + return; + // Sky Darkener Assault + case 52124: + if (unitTarget) + m_caster->CastSpell(unitTarget, 52125, false); + return; + case 52479: // Gift of the Harvester + if (unitTarget && m_originalCaster) + m_originalCaster->CastSpell(unitTarget, urand(0, 1) ? damage : 52505, true); + return; + // Death Gate + case 52751: + { + if (!unitTarget || unitTarget->getClass() != CLASS_DEATH_KNIGHT) + return; + // triggered spell is stored in m_spellInfo->EffectBasePoints[0] + unitTarget->CastSpell(unitTarget, damage, false); + break; + } + case 53110: // Devour Humanoid + if (unitTarget) + unitTarget->CastSpell(m_caster, damage, true); + return; + // Winged Steed of the Ebon Blade + case 54729: + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + // Prevent stacking of mounts and client crashes upon dismounting + unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED); + + // Triggered spell id dependent on riding skill + if (uint16 skillval = unitTarget->ToPlayer()->GetSkillValue(SKILL_RIDING)) + { + if (skillval >= 300) + unitTarget->CastSpell(unitTarget, 54727, true); + else + unitTarget->CastSpell(unitTarget, 54726, true); + } + return; + } + case 58418: // Portal to Orgrimmar + case 58420: // Portal to Stormwind + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || effIndex != 0) + return; + + uint32 spellID = SpellMgr::CalculateSpellEffectAmount(m_spellInfo, 0); + uint32 questID = SpellMgr::CalculateSpellEffectAmount(m_spellInfo, 1); + + if (unitTarget->ToPlayer()->GetQuestStatus(questID) == QUEST_STATUS_COMPLETE && !unitTarget->ToPlayer()->GetQuestRewardStatus (questID)) + unitTarget->CastSpell(unitTarget, spellID, true); + + return; + } + // Gigantic Feast + case 58466: + { + if (!unitTarget) + return; + + unitTarget->CastSpell(unitTarget, 58648, true); + unitTarget->CastSpell(unitTarget, 58467, true); + break; + } + // Small Feast + case 58475: + { + if (!unitTarget) + return; + + unitTarget->CastSpell(unitTarget, 58648, true); + unitTarget->CastSpell(unitTarget, 58477, true); + break; + } + // Great Feast + case 57337: + { + if (!unitTarget) + return; + + unitTarget->CastSpell(unitTarget, 58067, true); + break; + } + //Fish Feast + case 57397: + { + if (!unitTarget) + return; + + unitTarget->CastSpell(unitTarget, 58648, true); + unitTarget->CastSpell(unitTarget, 57398, true); + break; + } + case 58941: // Rock Shards + if (unitTarget && m_originalCaster) + { + for (uint32 i = 0; i < 3; ++i) + { + m_originalCaster->CastSpell(unitTarget, 58689, true); + m_originalCaster->CastSpell(unitTarget, 58692, true); + } + if (((InstanceMap*)m_originalCaster->GetMap())->GetDifficulty() == REGULAR_DIFFICULTY) + { + m_originalCaster->CastSpell(unitTarget, 58695, true); + m_originalCaster->CastSpell(unitTarget, 58696, true); + } + else + { + m_originalCaster->CastSpell(unitTarget, 60883, true); + m_originalCaster->CastSpell(unitTarget, 60884, true); + } + } + return; + case 58983: // Big Blizzard Bear + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + // Prevent stacking of mounts and client crashes upon dismounting + unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED); + + // Triggered spell id dependent on riding skill + if (uint16 skillval = unitTarget->ToPlayer()->GetSkillValue(SKILL_RIDING)) + { + if (skillval >= 150) + unitTarget->CastSpell(unitTarget, 58999, true); + else + unitTarget->CastSpell(unitTarget, 58997, true); + } + return; + } + case 71342: // Big Love Rocket + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + // Prevent stacking of mounts and client crashes upon dismounting + unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED); + + // Triggered spell id dependent on riding skill and zone + bool canFly = true; + uint32 v_map = GetVirtualMapForMapAndZone(unitTarget->GetMapId(), unitTarget->GetZoneId()); + if (v_map != 530 && v_map != 571) + canFly = false; + + if (canFly && v_map == 571 && !unitTarget->ToPlayer()->HasSpell(54197)) + canFly = false; + + float x, y, z; + unitTarget->GetPosition(x, y, z); + uint32 areaFlag = unitTarget->GetBaseMap()->GetAreaFlag(x, y, z); + AreaTableEntry const *pArea = sAreaStore.LookupEntry(areaFlag); + if (canFly && pArea->flags & AREA_FLAG_NO_FLY_ZONE) + canFly = false; + + switch(unitTarget->ToPlayer()->GetBaseSkillValue(SKILL_RIDING)) + { + case 0: unitTarget->CastSpell(unitTarget, 71343, true); break; + case 75: unitTarget->CastSpell(unitTarget, 71344, true); break; + case 150: unitTarget->CastSpell(unitTarget, 71345, true); break; + case 225: + { + if (canFly) + unitTarget->CastSpell(unitTarget, 71346, true); + else + unitTarget->CastSpell(unitTarget, 71345, true); + }break; + case 300: + { + if (canFly) + unitTarget->CastSpell(unitTarget, 71347, true); + else + unitTarget->CastSpell(unitTarget, 71345, true); + }break; + } + return; + } + case 72286: // Invincible + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + // Prevent stacking of mounts and client crashes upon dismounting + unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED); + + // Triggered spell id dependent on riding skill and zone + bool canFly = true; + uint32 v_map = GetVirtualMapForMapAndZone(unitTarget->GetMapId(), unitTarget->GetZoneId()); + if (v_map != 530 && v_map != 571) + canFly = false; + + if (canFly && v_map == 571 && !unitTarget->ToPlayer()->HasSpell(54197)) + canFly = false; + + float x, y, z; + unitTarget->GetPosition(x, y, z); + uint32 areaFlag = unitTarget->GetBaseMap()->GetAreaFlag(x, y, z); + AreaTableEntry const *pArea = sAreaStore.LookupEntry(areaFlag); + if (canFly && pArea->flags & AREA_FLAG_NO_FLY_ZONE) + canFly = false; + + switch(unitTarget->ToPlayer()->GetBaseSkillValue(SKILL_RIDING)) + { + case 75: unitTarget->CastSpell(unitTarget, 72281, true); break; + case 150: unitTarget->CastSpell(unitTarget, 72282, true); break; + case 225: + { + if (canFly) + unitTarget->CastSpell(unitTarget, 72283, true); + else + unitTarget->CastSpell(unitTarget, 72282, true); + }break; + case 300: + { + if (canFly) + unitTarget->CastSpell(unitTarget, 72284, true); + else + unitTarget->CastSpell(unitTarget, 72282, true); + }break; + } + return; + } + case 74856: // Blazing Hippogryph + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + // Prevent stacking of mounts and client crashes upon dismounting + unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED); + + // Triggered spell id dependent on riding skill + if (uint16 skillval = unitTarget->ToPlayer()->GetSkillValue(SKILL_RIDING)) + { + if (skillval >= 300) + unitTarget->CastSpell(unitTarget, 74855, true); + else + unitTarget->CastSpell(unitTarget, 74854, true); + } + return; + } + case 75614: // Celestial Steed + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + // Prevent stacking of mounts and client crashes upon dismounting + unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED); + + // Triggered spell id dependent on riding skill and zone + bool canFly = true; + uint32 v_map = GetVirtualMapForMapAndZone(unitTarget->GetMapId(), unitTarget->GetZoneId()); + if (v_map != 530 && v_map != 571) + canFly = false; + + if (canFly && v_map == 571 && !unitTarget->ToPlayer()->HasSpell(54197)) + canFly = false; + + float x, y, z; + unitTarget->GetPosition(x, y, z); + uint32 areaFlag = unitTarget->GetBaseMap()->GetAreaFlag(x, y, z); + AreaTableEntry const *pArea = sAreaStore.LookupEntry(areaFlag); + if (canFly && pArea->flags & AREA_FLAG_NO_FLY_ZONE) + canFly = false; + + switch(unitTarget->ToPlayer()->GetBaseSkillValue(SKILL_RIDING)) + { + case 75: unitTarget->CastSpell(unitTarget, 75619, true); break; + case 150: unitTarget->CastSpell(unitTarget, 75620, true); break; + case 225: + { + if (canFly) + unitTarget->CastSpell(unitTarget, 75617, true); + else + unitTarget->CastSpell(unitTarget, 75620, true); + }break; + case 300: + { + if (canFly) + { + if (unitTarget->ToPlayer()->Has310Flyer(false)) + unitTarget->CastSpell(unitTarget, 76153, true); + else + unitTarget->CastSpell(unitTarget, 75618, true); + } + else + unitTarget->CastSpell(unitTarget, 75620, true); + }break; + } + return; + } + case 75973: // X-53 Touring Rocket + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + // Prevent stacking of mounts + unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED); + + // Triggered spell id dependent on riding skill + if (uint16 skillval = unitTarget->ToPlayer()->GetSkillValue(SKILL_RIDING)) + { + if (skillval >= 300) + { + if (unitTarget->ToPlayer()->Has310Flyer(false)) + unitTarget->CastSpell(unitTarget, 76154, true); + else + unitTarget->CastSpell(unitTarget, 75972, true); + } + else + unitTarget->CastSpell(unitTarget, 75957, true); + } + return; + } + case 59317: // Teleporting + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + // return from top + if (unitTarget->ToPlayer()->GetAreaId() == 4637) + unitTarget->CastSpell(unitTarget, 59316, true); + // teleport atop + else + unitTarget->CastSpell(unitTarget, 59314, true); + + return; + // random spell learn instead placeholder + case 60893: // Northrend Alchemy Research + case 61177: // Northrend Inscription Research + case 61288: // Minor Inscription Research + case 61756: // Northrend Inscription Research (FAST QA VERSION) + case 64323: // Book of Glyph Mastery + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + // learn random explicit discovery recipe (if any) + if (uint32 discoveredSpell = GetExplicitDiscoverySpell(m_spellInfo->Id, (Player*)m_caster)) + m_caster->ToPlayer()->learnSpell(discoveredSpell, false); + return; + } + case 62428: // Load into Catapult + { + if (Vehicle *seat = m_caster->GetVehicleKit()) + if (Unit *passenger = seat->GetPassenger(0)) + if (Unit *demolisher = m_caster->GetVehicleBase()) + passenger->CastSpell(demolisher, damage, true); + return; + } + case 62482: // Grab Crate + { + if (unitTarget) + { + if (Vehicle *seat = m_caster->GetVehicleKit()) + { + if (Creature *oldContainer = dynamic_cast(seat->GetPassenger(1))) + oldContainer->DisappearAndDie(); + // TODO: a hack, range = 11, should after some time cast, otherwise too far + unitTarget->CastSpell(seat->GetBase(), 62496, true); + unitTarget->EnterVehicle(seat, 1); + } + } + return; + } + case 60123: // Lightwell + { + if (m_caster->GetTypeId() != TYPEID_UNIT || !m_caster->ToCreature()->isSummon()) + return; + + uint32 spell_heal; + + switch(m_caster->GetEntry()) + { + case 31897: spell_heal = 7001; break; + case 31896: spell_heal = 27873; break; + case 31895: spell_heal = 27874; break; + case 31894: spell_heal = 28276; break; + case 31893: spell_heal = 48084; break; + case 31883: spell_heal = 48085; break; + default: + sLog.outError("Unknown Lightwell spell caster %u", m_caster->GetEntry()); + return; + } + Aura * chargesaura = m_caster->GetAura(59907); + + if (chargesaura && chargesaura->GetCharges() > 1) + { + chargesaura->SetCharges(chargesaura->GetCharges() - 1); + m_caster->CastSpell(unitTarget, spell_heal, true, NULL, NULL, m_caster->ToTempSummon()->GetSummonerGUID()); + } + else + m_caster->ToTempSummon()->UnSummon(); + return; + } + // Stoneclaw Totem + case 55328: // Rank 1 + case 55329: // Rank 2 + case 55330: // Rank 3 + case 55332: // Rank 4 + case 55333: // Rank 5 + case 55335: // Rank 6 + case 55278: // Rank 7 + case 58589: // Rank 8 + case 58590: // Rank 9 + case 58591: // Rank 10 + { + int32 basepoints0 = damage; + // Cast Absorb on totems + for (uint8 slot = SUMMON_SLOT_TOTEM; slot < MAX_TOTEM_SLOT; ++slot) + { + if (!unitTarget->m_SummonSlot[slot]) + continue; + + Creature* totem = unitTarget->GetMap()->GetCreature(unitTarget->m_SummonSlot[slot]); + if (totem && totem->isTotem()) + { + m_caster->CastCustomSpell(totem, 55277, &basepoints0, NULL, NULL, true); + } + } + // Glyph of Stoneclaw Totem + if (AuraEffect *aur=unitTarget->GetAuraEffect(63298, 0)) + { + basepoints0 *= aur->GetAmount(); + m_caster->CastCustomSpell(unitTarget, 55277, &basepoints0, NULL, NULL, true); + } + break; + } + case 67751:// Ghoul Explode + { + unitTarget->CastSpell(unitTarget,67729,false); //Explode + break; + } + case 66545: //Summon Memory + { + uint8 uiRandom = urand(0,25); + uint32 uiSpells[26] = {66704,66705,66706,66707,66709,66710,66711,66712,66713,66714,66715,66708,66708,66691,66692,66694,66695,66696,66697,66698,66699,66700,66701,66702,66703,66543}; + + m_caster->CastSpell(m_caster,uiSpells[uiRandom],true); + break; + } + case 45668: // Ultra-Advanced Proto-Typical Shortening Blaster + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) + return; + + if (roll_chance_i(50)) // chance unknown, using 50 + return; + + static uint32 const spellPlayer[5] = + { + 45674, // Bigger! + 45675, // Shrunk + 45678, // Yellow + 45682, // Ghost + 45684 // Polymorph + }; + + static uint32 const spellTarget[5] = { + 45673, // Bigger! + 45672, // Shrunk + 45677, // Yellow + 45681, // Ghost + 45683 // Polymorph + }; + + m_caster->CastSpell(m_caster, spellPlayer[urand(0,4)], true); + unitTarget->CastSpell(unitTarget, spellTarget[urand(0,4)], true); + break; + } + case 64142: // Upper Deck - Create Foam Sword + if (unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + Player *plr = unitTarget->ToPlayer(); + static uint32 const itemId[] = {45061, 45176, 45177, 45178, 45179, 0}; + // player can only have one of these items + for (uint32 const *itr = &itemId[0]; *itr; ++itr) + if (plr->HasItemCount(*itr, 1, true)) + return; + DoCreateItem(effIndex, itemId[urand(0,4)]); + return; + } + break; + } + case SPELLFAMILY_WARLOCK: + { + switch(m_spellInfo->Id) + { + // Healthstone creating spells + case 6201: + case 6202: + case 5699: + case 11729: + case 11730: + case 27230: + case 47871: + case 47878: + { + uint32 itemtype; + uint32 rank = 0; + + // Improved Healthstone + if (AuraEffect const * aurEff = unitTarget->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, 284, 0)) + { + if (aurEff->GetId() == 18692) + rank = 1; + else if (aurEff->GetId() == 18693) + rank = 2; + else + sLog.outError("Unknown rank of Improved Healthstone id: %d", aurEff->GetId()); + } + + static uint32 const itypes[8][3] = { + { 5512, 19004, 19005}, // Minor Healthstone + { 5511, 19006, 19007}, // Lesser Healthstone + { 5509, 19008, 19009}, // Healthstone + { 5510, 19010, 19011}, // Greater Healthstone + { 9421, 19012, 19013}, // Major Healthstone + {22103, 22104, 22105}, // Master Healthstone + {36889, 36890, 36891}, // Demonic Healthstone + {36892, 36893, 36894} // Fel Healthstone + }; + + switch(m_spellInfo->Id) + { + case 6201: + itemtype=itypes[0][rank];break; // Minor Healthstone + case 6202: + itemtype=itypes[1][rank];break; // Lesser Healthstone + case 5699: + itemtype=itypes[2][rank];break; // Healthstone + case 11729: + itemtype=itypes[3][rank];break; // Greater Healthstone + case 11730: + itemtype=itypes[4][rank];break; // Major Healthstone + case 27230: + itemtype=itypes[5][rank];break; // Master Healthstone + case 47871: + itemtype=itypes[6][rank];break; // Demonic Healthstone + case 47878: + itemtype=itypes[7][rank];break; // Fel Healthstone + default: + return; + } + DoCreateItem(effIndex, itemtype); + return; + } + // Everlasting Affliction + case 47422: + // Refresh corruption on target + if (AuraEffect * aur = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x2, 0, 0, m_caster->GetGUID())) + aur->GetBase()->RefreshDuration(); + return; + // Demonic Empowerment + case 47193: + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || !unitTarget->ToCreature()->isPet()) + return; + CreatureInfo const * ci = objmgr.GetCreatureTemplate(unitTarget->GetEntry()); + switch (ci->family) + { + case CREATURE_FAMILY_SUCCUBUS: + unitTarget->CastSpell(unitTarget, 54435, true); + break; + case CREATURE_FAMILY_VOIDWALKER: + { + SpellEntry const* spellInfo = sSpellStore.LookupEntry(54443); + int32 hp = unitTarget->GetMaxHealth() * m_caster->CalculateSpellDamage(unitTarget, spellInfo, 0) /100; + unitTarget->CastCustomSpell(unitTarget, 54443,&hp, NULL, NULL,true); + //unitTarget->CastSpell(unitTarget, 54441, true); + break; + } + case CREATURE_FAMILY_FELGUARD: + unitTarget->CastSpell(unitTarget, 54508, true); + break; + case CREATURE_FAMILY_FELHUNTER: + unitTarget->CastSpell(unitTarget, 54509, true); + break; + case CREATURE_FAMILY_IMP: + unitTarget->CastSpell(unitTarget, 54444, true); + break; + } + return; + } + // Guarded by The Light + case 63521: + { + // Divine Plea + if (Aura * aura = m_caster->GetAura(54428)) + aura->RefreshDuration(); + return; + } + } + break; + } + case SPELLFAMILY_PRIEST: + { + switch(m_spellInfo->Id) + { + // Pain and Suffering + case 47948: + { + if (!unitTarget) + return; + // Refresh Shadow Word: Pain on target + if (AuraEffect * aur = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0, 0, m_caster->GetGUID())) + aur->GetBase()->RefreshDuration(); + return; + } + default: + break; + } + break; + } + case SPELLFAMILY_HUNTER: + { + switch(m_spellInfo->Id) + { + // Invigoration + case 53412: + { + if (AuraEffect * aurEff = unitTarget->GetDummyAuraEffect(SPELLFAMILY_HUNTER, 3487, 0)) + { + if (roll_chance_i(aurEff->GetAmount())) + unitTarget->CastSpell(unitTarget, 53398, true); + } + break; + } + // Heart of the Pheonix + case 55709: + { + int pct = 100; + if (unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->ToCreature()->isPet()) + if (Unit* owner = unitTarget->ToCreature()->GetOwner()) + owner->CastCustomSpell(unitTarget, 54114, &pct, NULL, NULL, true); + break; + } + // Chimera Shot + case 53209: + { + uint32 spellId = 0; + int32 basePoint = 0; + Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras(); + for (Unit::AuraApplicationMap::iterator i = Auras.begin(); i != Auras.end(); ++i) + { + Aura * aura = (*i).second->GetBase(); + if (aura->GetCasterGUID() != m_caster->GetGUID()) + continue; + // Search only Serpent Sting, Viper Sting, Scorpid Sting auras + flag96 familyFlag = aura->GetSpellProto()->SpellFamilyFlags; + if (!(familyFlag[1] & 0x00000080 || familyFlag[0] & 0x0000C000)) + continue; + if (AuraEffect const * aurEff = aura->GetEffect(0)) + { + // Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting. + if (familyFlag[0] & 0x4000) + { + int32 TickCount = aurEff->GetTotalTicks(); + spellId = 53353; // 53353 Chimera Shot - Serpent + basePoint = aurEff->GetAmount() * TickCount * 40 / 100; + } + // Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting. + else if (familyFlag[1] & 0x00000080) + { + int32 TickCount = aura->GetEffect(0)->GetTotalTicks(); + spellId = 53358; // 53358 Chimera Shot - Viper + + // Amount of one aura tick + basePoint = aurEff->GetAmount() * unitTarget->GetMaxPower(POWER_MANA) / 100 ; + int32 casterBasePoint = aurEff->GetAmount() * unitTarget->GetMaxPower(POWER_MANA) / 50 ; + if (basePoint > casterBasePoint) + basePoint = casterBasePoint; + basePoint = basePoint * TickCount * 60 / 100; + } + // Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute. + else if (familyFlag[0] & 0x00008000) + spellId = 53359; // 53359 Chimera Shot - Scorpid + // ?? nothing say in spell desc (possibly need addition check) + //if (familyFlag & 0x0000010000000000LL || // dot + // familyFlag & 0x0000100000000000LL) // stun + //{ + // spellId = 53366; // 53366 Chimera Shot - Wyvern + //} + + // Refresh aura duration + aura->RefreshDuration(); + } + break; + } + if (spellId) + m_caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, true); + return; + } + // Master's Call + case 53271: + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + if (Pet *PlrPet = m_caster->ToPlayer()->GetPet()) + m_caster->CastSpell(PlrPet, 62305, true); + return; + } + default: + break; + } + break; + } + case SPELLFAMILY_PALADIN: + { + // Judgement (seal trigger) + if (m_spellInfo->Category == SPELLCATEGORY_JUDGEMENT) + { + if (!unitTarget || !unitTarget->isAlive()) + return; + uint32 spellId1 = 0; + uint32 spellId2 = 0; + uint32 spellId3 = 0; + + // Judgement self add switch + switch (m_spellInfo->Id) + { + case 53407: spellId1 = 20184; break; // Judgement of Justice + case 20271: // Judgement of Light + case 57774: spellId1 = 20185; break; // Judgement of Light + case 53408: spellId1 = 20186; break; // Judgement of Wisdom + default: + sLog.outError("Unsupported Judgement (seal trigger) spell (Id: %u) in Spell::EffectScriptEffect",m_spellInfo->Id); + return; + } + // all seals have aura dummy in 2 effect + Unit::AuraApplicationMap & sealAuras = m_caster->GetAppliedAuras(); + for (Unit::AuraApplicationMap::iterator iter = sealAuras.begin(); iter != sealAuras.end();) + { + switch (iter->first) + { + // Heart of the Crusader + case 20335: // Rank 1 + spellId3 = 21183; + break; + case 20336: // Rank 2 + spellId3 = 54498; + break; + case 20337: // Rank 3 + spellId3 = 54499; + break; + } + Aura * aura = iter->second->GetBase(); + if (IsSealSpell(aura->GetSpellProto())) + { + if (AuraEffect * aureff = aura->GetEffect(2)) + if (aureff->GetAuraType() == SPELL_AURA_DUMMY) + { + if (sSpellStore.LookupEntry(aureff->GetAmount())) + spellId2 = aureff->GetAmount(); + break; + } + if (!spellId2) + { + switch (iter->first) + { + // Seal of light, Seal of wisdom, Seal of justice + case 20165: + case 20166: + case 20164: + spellId2 = 54158; + } + } + break; + } + else + ++iter; + } + if (spellId1) + m_caster->CastSpell(unitTarget, spellId1, true); + if (spellId2) + m_caster->CastSpell(unitTarget, spellId2, true); + if (spellId3) + m_caster->CastSpell(unitTarget, spellId3, true); + return; + } + } + case SPELLFAMILY_POTION: + { + switch(m_spellInfo->Id) + { + // Dreaming Glory + case 28698: + { + if (!unitTarget) + return; + unitTarget->CastSpell(unitTarget, 28694, true); + break; + } + // Netherbloom + case 28702: + { + if (!unitTarget) + return; + // 25% chance of casting a random buff + if (roll_chance_i(75)) + return; + + // triggered spells are 28703 to 28707 + // Note: some sources say, that there was the possibility of + // receiving a debuff. However, this seems to be removed by a patch. + const uint32 spellid = 28703; + + // don't overwrite an existing aura + for (uint8 i = 0; i < 5; ++i) + if (unitTarget->HasAura(spellid + i)) + return; + unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true); + break; + } + + // Nightmare Vine + case 28720: + { + if (!unitTarget) + return; + // 25% chance of casting Nightmare Pollen + if (roll_chance_i(75)) + return; + unitTarget->CastSpell(unitTarget, 28721, true); + break; + } + } + break; + } + case SPELLFAMILY_DEATHKNIGHT: + { + // Pestilence + if (m_spellInfo->SpellFamilyFlags[1]&0x10000) + { + // Get diseases on target of spell + if (m_targets.getUnitTarget() && // Glyph of Disease - cast on unit target too to refresh aura + (m_targets.getUnitTarget() != unitTarget || m_caster->GetAura(63334))) + { + // And spread them on target + // Blood Plague + if (m_targets.getUnitTarget()->GetAura(55078)) + m_caster->CastSpell(unitTarget, 55078, true); + // Frost Fever + if (m_targets.getUnitTarget()->GetAura(55095)) + m_caster->CastSpell(unitTarget, 55095, true); + } + } + break; + } + case SPELLFAMILY_WARRIOR: + { + // Shattering Throw + if (m_spellInfo->SpellFamilyFlags[1] & 0x00400000) + { + if (!unitTarget) + return; + // remove shields, will still display immune to damage part + unitTarget->RemoveAurasWithMechanic(1<Id); + m_caster->GetMap()->ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget); +} + +void Spell::EffectSanctuary(uint32 /*i*/) +{ + if (!unitTarget) + return; + + std::list targets; + Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(unitTarget, unitTarget, m_caster->GetMap()->GetVisibilityDistance()); + Trinity::UnitListSearcher searcher(unitTarget, targets, u_check); + unitTarget->VisitNearbyObject(m_caster->GetMap()->GetVisibilityDistance(), searcher); + for (std::list::iterator iter = targets.begin(); iter != targets.end(); ++iter) + { + if (!(*iter)->hasUnitState(UNIT_STAT_CASTING)) + continue; + + for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++) + { + if ((*iter)->GetCurrentSpell(i) + && (*iter)->GetCurrentSpell(i)->m_targets.getUnitTargetGUID() == unitTarget->GetGUID()) + { + (*iter)->InterruptSpell(CurrentSpellTypes(i), false); + } + } + } + + unitTarget->CombatStop(); + unitTarget->getHostileRefManager().deleteReferences(); // stop all fighting + // Vanish allows to remove all threat and cast regular stealth so other spells can be used + if (m_caster->GetTypeId() == TYPEID_PLAYER + && m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE + && (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_VANISH)) + { + m_caster->ToPlayer()->RemoveAurasByType(SPELL_AURA_MOD_ROOT); + // Overkill + if (m_caster->ToPlayer()->HasSpell(58426)) + m_caster->CastSpell(m_caster, 58427, true); + } +} + +void Spell::EffectAddComboPoints(uint32 /*i*/) +{ + if (!unitTarget) + return; + + if (!m_caster->m_movedPlayer) + return; + + if (damage <= 0) + return; + + m_caster->m_movedPlayer->AddComboPoints(unitTarget, damage, this); +} + +void Spell::EffectDuel(uint32 i) +{ + if (!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + Player *caster = (Player*)m_caster; + Player *target = (Player*)unitTarget; + + // caster or target already have requested duel + if (caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetGUIDLow())) + return; + + // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities) + // Don't have to check the target's map since you cannot challenge someone across maps + if (caster->GetMap()->Instanceable()) + //if (mapid != 0 && mapid != 1 && mapid != 530 && mapid != 571 && mapid != 609) + { + SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here + return; + } + + AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId()); + if (casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL)) + { + SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here + return; + } + + AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId()); + if (targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL)) + { + SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here + return; + } + + //CREATE DUEL FLAG OBJECT + GameObject* pGameObj = new GameObject; + + uint32 gameobject_id = m_spellInfo->EffectMiscValue[i]; + + Map *map = m_caster->GetMap(); + if (!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, + map, m_caster->GetPhaseMask(), + m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 , + m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 , + m_caster->GetPositionZ(), + m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY)) + { + delete pGameObj; + return; + } + + pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction()); + pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1); + int32 duration = GetSpellDuration(m_spellInfo); + pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); + pGameObj->SetSpellId(m_spellInfo->Id); + + m_caster->AddGameObject(pGameObj); + map->Add(pGameObj); + //END + + // Send request + WorldPacket data(SMSG_DUEL_REQUESTED, 8 + 8); + data << uint64(pGameObj->GetGUID()); + data << uint64(caster->GetGUID()); + caster->GetSession()->SendPacket(&data); + target->GetSession()->SendPacket(&data); + + // create duel-info + DuelInfo *duel = new DuelInfo; + duel->initiator = caster; + duel->opponent = target; + duel->startTime = 0; + duel->startTimer = 0; + caster->duel = duel; + + DuelInfo *duel2 = new DuelInfo; + duel2->initiator = caster; + duel2->opponent = caster; + duel2->startTime = 0; + duel2->startTimer = 0; + target->duel = duel2; + + caster->SetUInt64Value(PLAYER_DUEL_ARBITER, pGameObj->GetGUID()); + target->SetUInt64Value(PLAYER_DUEL_ARBITER, pGameObj->GetGUID()); +} + +void Spell::EffectStuck(uint32 /*i*/) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + if (!sWorld.getConfig(CONFIG_CAST_UNSTUCK)) + return; + + Player* pTarget = (Player*)unitTarget; + + sLog.outDebug("Spell Effect: Stuck"); + sLog.outDetail("Player %s (guid %u) used auto-unstuck future at map %u (%f, %f, %f)", pTarget->GetName(), pTarget->GetGUIDLow(), m_caster->GetMapId(), m_caster->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ()); + + if (pTarget->isInFlight()) + return; + + pTarget->TeleportTo(pTarget->GetStartPosition(), unitTarget == m_caster ? TELE_TO_SPELL : 0); + // homebind location is loaded always + // pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget == m_caster ? TELE_TO_SPELL : 0)); + + // Stuck spell trigger Hearthstone cooldown + SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690); + if (!spellInfo) + return; + Spell spell(pTarget, spellInfo, true, 0); + spell.SendSpellCooldown(); +} + +void Spell::EffectSummonPlayer(uint32 /*i*/) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + // Evil Twin (ignore player summon, but hide this for summoner) + if (unitTarget->HasAura(23445)) + return; + + float x, y, z; + m_caster->GetClosePoint(x, y, z, unitTarget->GetObjectSize()); + + unitTarget->ToPlayer()->SetSummonPoint(m_caster->GetMapId(),x,y,z); + + WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4); + data << uint64(m_caster->GetGUID()); // summoner guid + data << uint32(m_caster->GetZoneId()); // summoner zone + data << uint32(MAX_PLAYER_SUMMON_DELAY*IN_MILLISECONDS); // auto decline after msecs + unitTarget->ToPlayer()->GetSession()->SendPacket(&data); +} + +static ScriptInfo generateActivateCommand() +{ + ScriptInfo si; + si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT; + return si; +} + +void Spell::EffectActivateObject(uint32 effect_idx) +{ + if (!gameObjTarget) + return; + + static ScriptInfo activateCommand = generateActivateCommand(); + + int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx]; + + gameObjTarget->GetMap()->ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget); +} + +void Spell::EffectApplyGlyph(uint32 i) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER || m_glyphIndex >= MAX_GLYPH_SLOT_INDEX) + return; + + Player *player = (Player*)m_caster; + + // apply new one + if (uint32 glyph = m_spellInfo->EffectMiscValue[i]) + { + if (GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph)) + { + if (GlyphSlotEntry const *gs = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex))) + { + if (gp->TypeFlags != gs->TypeFlags) + { + SendCastResult(SPELL_FAILED_INVALID_GLYPH); + return; // glyph slot mismatch + } + } + + // remove old glyph + if (uint32 oldglyph = player->GetGlyph(m_glyphIndex)) + { + if (GlyphPropertiesEntry const *old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph)) + { + player->RemoveAurasDueToSpell(old_gp->SpellId); + player->SetGlyph(m_glyphIndex, 0); + } + } + + player->CastSpell(m_caster, gp->SpellId, true); + player->SetGlyph(m_glyphIndex, glyph); + player->SendTalentsInfoData(false); + } + } +} + +void Spell::EffectEnchantHeldItem(uint32 i) +{ + // this is only item spell effect applied to main-hand weapon of target player (players in area) + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + Player* item_owner = (Player*)unitTarget; + Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); + + if (!item) + return; + + // must be equipped + if (!item ->IsEquipped()) + return; + + if (m_spellInfo->EffectMiscValue[i]) + { + uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; + int32 duration = GetSpellDuration(m_spellInfo); //Try duration index first .. + if (!duration) + duration = damage;//+1; //Base points after .. + if (!duration) + duration = 10; //10 seconds for enchants which don't have listed duration + + SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if (!pEnchant) + return; + + // Always go to temp enchantment slot + EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT; + + // Enchantment will not be applied if a different one already exists + if (item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id) + return; + + // Apply the temporary enchantment + item->SetEnchantment(slot, enchant_id, duration*IN_MILLISECONDS, 0); + item_owner->ApplyEnchantment(item, slot, true); + } +} + +void Spell::EffectDisEnchant(uint32 /*i*/) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player* p_caster = (Player*)m_caster; + if (!itemTarget || !itemTarget->GetProto()->DisenchantID) + return; + + p_caster->UpdateCraftSkill(m_spellInfo->Id); + + m_caster->ToPlayer()->SendLoot(itemTarget->GetGUID(),LOOT_DISENCHANTING); + + // item will be removed at disenchanting end +} + +void Spell::EffectInebriate(uint32 /*i*/) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + Player *player = (Player*)unitTarget; + uint16 currentDrunk = player->GetDrunkValue(); + uint16 drunkMod = damage * 256; + if (currentDrunk + drunkMod > 0xFFFF) + currentDrunk = 0xFFFF; + else + currentDrunk += drunkMod; + player->SetDrunkValue(currentDrunk, m_CastItem ? m_CastItem->GetEntry() : 0); +} + +void Spell::EffectFeedPet(uint32 i) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player *_player = (Player*)m_caster; + + Item* foodItem = m_targets.getItemTarget(); + if (!foodItem) + return; + + Pet *pet = _player->GetPet(); + if (!pet) + return; + + if (!pet->isAlive()) + return; + + int32 benefit = pet->GetCurrentFoodBenefitLevel(foodItem->GetProto()->ItemLevel); + if (benefit <= 0) + return; + + uint32 count = 1; + _player->DestroyItemCount(foodItem,count,true); + // TODO: fix crash when a spell has two effects, both pointed at the same item target + + m_caster->CastCustomSpell(pet, m_spellInfo->EffectTriggerSpell[i], &benefit, NULL, NULL, true); +} + +void Spell::EffectDismissPet(uint32 /*i*/) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Pet* pet = m_caster->ToPlayer()->GetPet(); + + // not let dismiss dead pet + if (!pet||!pet->isAlive()) + return; + + m_caster->ToPlayer()->RemovePet(pet, PET_SAVE_NOT_IN_SLOT); +} + +void Spell::EffectSummonObject(uint32 i) +{ + uint32 go_id = m_spellInfo->EffectMiscValue[i]; + + uint8 slot = 0; + switch(m_spellInfo->Effect[i]) + { + case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: slot = 0; break; + case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: slot = 1; break; + case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: slot = 2; break; + case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: slot = 3; break; + default: return; + } + + uint64 guid = m_caster->m_ObjectSlot[slot]; + if (guid != 0) + { + GameObject* obj = NULL; + if (m_caster) + obj = m_caster->GetMap()->GetGameObject(guid); + + if (obj) + { + // Recast case - null spell id to make auras not be removed on object remove from world + if (m_spellInfo->Id == obj->GetSpellId()) + obj->SetSpellId(0); + m_caster->RemoveGameObject(obj, true); + } + m_caster->m_ObjectSlot[slot] = 0; + } + + GameObject* pGameObj = new GameObject; + + float x, y, z; + // If dest location if present + if (m_targets.HasDst()) + m_targets.m_dstPos.GetPosition(x, y, z); + // Summon in random point all other units if location present + else + m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE); + + Map *map = m_caster->GetMap(); + if (!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map, + m_caster->GetPhaseMask(), x, y, z, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY)) + { + delete pGameObj; + return; + } + + //pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel()); + int32 duration = GetSpellDuration(m_spellInfo); + pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); + pGameObj->SetSpellId(m_spellInfo->Id); + m_caster->AddGameObject(pGameObj); + + map->Add(pGameObj); + + m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID(); +} + +void Spell::EffectResurrect(uint32 /*effIndex*/) +{ + if (!unitTarget) + return; + if (unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + if (unitTarget->isAlive()) + return; + if (!unitTarget->IsInWorld()) + return; + + switch (m_spellInfo->Id) + { + // Defibrillate (Goblin Jumper Cables) have 33% chance on success + case 8342: + if (roll_chance_i(67)) + { + m_caster->CastSpell(m_caster, 8338, true, m_CastItem); + return; + } + break; + // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success + case 22999: + if (roll_chance_i(50)) + { + m_caster->CastSpell(m_caster, 23055, true, m_CastItem); + return; + } + break; + // Defibrillate ( Gnomish Army Knife) have 67% chance on success_list + case 54732: + if (roll_chance_i(33)) + { + return; + } + break; + default: + break; + } + + Player* pTarget = unitTarget->ToPlayer(); + + if (pTarget->isRessurectRequested()) // already have one active request + return; + + uint32 health = pTarget->GetMaxHealth() * damage / 100; + uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100; + + pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana); + SendResurrectRequest(pTarget); +} + +void Spell::EffectAddExtraAttacks(uint32 /*i*/) +{ + if (!unitTarget || !unitTarget->isAlive()) + return; + + if (unitTarget->m_extraAttacks) + return; + + Unit *victim = unitTarget->getVictim(); + + // attack prevented + // fixme, some attacks may not target current victim, this is right now not handled + if (!victim || !unitTarget->IsWithinMeleeRange(victim) || !unitTarget->HasInArc(2*M_PI/3, victim)) + return; + + // Only for proc/log informations + unitTarget->m_extraAttacks = damage; + // Need to send log before attack is made + SendLogExecute(); + m_needSpellLog = false; + + unitTarget->AttackerStateUpdate(victim, BASE_ATTACK, true); +} + +void Spell::EffectParry(uint32 /*i*/) +{ + if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER) + unitTarget->ToPlayer()->SetCanParry(true); +} + +void Spell::EffectBlock(uint32 /*i*/) +{ + if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER) + unitTarget->ToPlayer()->SetCanBlock(true); +} + +void Spell::EffectLeapForward(uint32 i) +{ + if (unitTarget->isInFlight()) + return; + + if (!m_targets.HasDst()) + return; + + uint32 mapid = m_caster->GetMapId(); + float dist = m_caster->GetSpellRadiusForTarget(unitTarget, sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); + if (Player* modOwner = m_originalCaster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, dist); + + float x,y,z; + float destx,desty,destz,ground,floor; + float orientation = unitTarget->GetOrientation(), step = dist/10.0f; + + unitTarget->GetPosition(x,y,z); + destx = x + dist * cos(orientation); + desty = y + dist * sin(orientation); + ground = unitTarget->GetMap()->GetHeight(destx,desty,MAX_HEIGHT,true); + floor = unitTarget->GetMap()->GetHeight(destx,desty,z, true); + destz = fabs(ground - z) <= fabs(floor - z) ? ground : floor; + + bool col = VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid,x,y,z+0.5f,destx,desty,destz+0.5f,destx,desty,destz,-0.5f); + + if (col) // We had a collision! + { + destx -= 0.6 * cos(orientation); + desty -= 0.6 * sin(orientation); + dist = sqrt((x-destx)*(x-destx) + (y-desty)*(y-desty)); + step = dist/10.0f; + } + + int j = 0; + for (j; j < 10; j++) + { + if (fabs(z - destz) > 6) + { + destx -= step * cos(orientation); + desty -= step * sin(orientation); + ground = unitTarget->GetMap()->GetHeight(destx,desty,MAX_HEIGHT,true); + floor = unitTarget->GetMap()->GetHeight(destx,desty,z, true); + destz = fabs(ground - z) <= fabs(floor - z) ? ground:floor; + } else break; + } + + if (j < 10) + unitTarget->NearTeleportTo(destx, desty, destz + 0.07531, orientation, unitTarget == m_caster); +} + +void Spell::EffectReputation(uint32 i) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + Player *_player = (Player*)unitTarget; + + int32 rep_change = damage;//+1; // field store reputation change -1 + + uint32 faction_id = m_spellInfo->EffectMiscValue[i]; + + FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id); + + if (!factionEntry) + return; + + _player->GetReputationMgr().ModifyReputation(factionEntry, rep_change); +} + +void Spell::EffectQuestComplete(uint32 i) +{ + Player *pPlayer; + + if (m_caster->GetTypeId() == TYPEID_PLAYER) + pPlayer = (Player*)m_caster; + else if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER) + pPlayer = (Player*)unitTarget; + else + return; + + uint32 quest_id = m_spellInfo->EffectMiscValue[i]; + if (quest_id) + { + uint16 log_slot = pPlayer->FindQuestSlot(quest_id); + if (log_slot < MAX_QUEST_LOG_SIZE) + pPlayer->AreaExploredOrEventHappens(quest_id); + else + pPlayer->CompleteQuest(quest_id); // quest not in log - for internal use + } +} + +void Spell::EffectForceDeselect(uint32 /*i*/) +{ + WorldPacket data(SMSG_CLEAR_TARGET, 8); + data << uint64(m_caster->GetGUID()); + m_caster->SendMessageToSet(&data, true); +} + +void Spell::EffectSelfResurrect(uint32 i) +{ + if (!unitTarget || unitTarget->isAlive()) + return; + if (unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + if (!unitTarget->IsInWorld()) + return; + + uint32 health = 0; + uint32 mana = 0; + + // flat case + if (damage < 0) + { + health = uint32(-damage); + mana = m_spellInfo->EffectMiscValue[i]; + } + // percent case + else + { + health = uint32(damage/100.0f*unitTarget->GetMaxHealth()); + if (unitTarget->GetMaxPower(POWER_MANA) > 0) + mana = uint32(damage/100.0f*unitTarget->GetMaxPower(POWER_MANA)); + } + + Player *plr = unitTarget->ToPlayer(); + plr->ResurrectPlayer(0.0f); + + plr->SetHealth(health); + plr->SetPower(POWER_MANA, mana); + plr->SetPower(POWER_RAGE, 0); + plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY)); + + plr->SpawnCorpseBones(); +} + +void Spell::EffectSkinning(uint32 /*i*/) +{ + if (unitTarget->GetTypeId() != TYPEID_UNIT) + return; + if (!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Creature* creature = unitTarget->ToCreature(); + int32 targetLevel = creature->getLevel(); + + uint32 skill = creature->GetCreatureInfo()->GetRequiredLootSkill(); + + m_caster->ToPlayer()->SendLoot(creature->GetGUID(),LOOT_SKINNING); + creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); + + int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5; + + int32 skillValue = m_caster->ToPlayer()->GetPureSkillValue(skill); + + // Double chances for elites + m_caster->ToPlayer()->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1); +} + +void Spell::EffectCharge(uint32 /*i*/) +{ + Unit *target = m_targets.getUnitTarget(); + if (!target) + return; + + float x, y, z; + target->GetContactPoint(m_caster, x, y, z); + m_caster->GetMotionMaster()->MoveCharge(x, y, z); + + // not all charge effects used in negative spells + if (!IsPositiveSpell(m_spellInfo->Id) && m_caster->GetTypeId() == TYPEID_PLAYER) + m_caster->Attack(target, true); +} + +void Spell::EffectChargeDest(uint32 /*i*/) +{ + if (m_targets.HasDst()) + { + float x, y, z; + m_targets.m_dstPos.GetPosition(x, y, z); + m_caster->GetMotionMaster()->MoveCharge(x, y, z); + } +} + +void Spell::EffectKnockBack(uint32 i) +{ + if (!unitTarget) + return; + + // Typhoon + if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags[1] & 0x01000000) + { + // Glyph of Typhoon + if (m_caster->HasAura(62135)) + return; + } + + // Thunderstorm + if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[1] & 0x00002000) + { + // Glyph of Thunderstorm + if (m_caster->HasAura(62132)) + return; + } + + float ratio = m_caster->GetCombatReach() / std::max(unitTarget->GetCombatReach(), 1.0f); + if (ratio < 1.0f) + ratio = ratio * ratio * ratio * 0.1f; // volume = length^3 + else + ratio = 0.1f; // dbc value ratio + float speedxy = float(m_spellInfo->EffectMiscValue[i]) * ratio; + float speedz = float(damage) * ratio; + if (speedxy < 0.1f && speedz < 0.1f) + return; + + float x, y; + if (m_spellInfo->Effect[i] == SPELL_EFFECT_KNOCK_BACK_DEST) + { + if (m_targets.HasDst()) + m_targets.m_dstPos.GetPosition(x, y); + else + return; + } + else //if (m_spellInfo->Effect[i] == SPELL_EFFECT_KNOCK_BACK) + { + m_caster->GetPosition(x, y); + } + + unitTarget->KnockbackFrom(x, y, speedxy, speedz); +} + +void Spell::EffectLeapBack(uint32 i) +{ + float speedxy = float(m_spellInfo->EffectMiscValue[i])/10; + float speedz = float(damage/10); + if (!speedxy) + { + if (m_targets.getUnitTarget()) + m_caster->JumpTo(m_targets.getUnitTarget(), speedz); + } + else + { + //1891: Disengage + m_caster->JumpTo(speedxy, speedz, m_spellInfo->SpellIconID != 1891); + } +} + +void Spell::EffectQuestClear(uint32 i) +{ + Player *pPlayer = NULL; + if (m_caster->GetTypeId() == TYPEID_PLAYER) + pPlayer = m_caster->ToPlayer(); + else if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER) + pPlayer = unitTarget->ToPlayer(); + + if (!pPlayer) + return; + + uint32 quest_id = m_spellInfo->EffectMiscValue[i]; + + Quest const* pQuest = objmgr.GetQuestTemplate(quest_id); + + if (!pQuest) + return; + + QuestStatusMap::iterator qs_itr = pPlayer->getQuestStatusMap().find(quest_id); + // Player has never done this quest + if (qs_itr == pPlayer->getQuestStatusMap().end()) + return; + + // remove all quest entries for 'entry' from quest log + for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) + { + uint32 quest = pPlayer->GetQuestSlotQuestId(slot); + if (quest == quest_id) + { + pPlayer->SetQuestSlot(slot, 0); + + // we ignore unequippable quest items in this case, its' still be equipped + pPlayer->TakeQuestSourceItem(quest, false); + } + } + + // set quest status to not started (will be updated in DB at next save) + pPlayer->SetQuestStatus(quest_id, QUEST_STATUS_NONE); + + // reset rewarded for restart repeatable quest + QuestStatusData &data = qs_itr->second; + data.m_rewarded = false; +} + +void Spell::EffectSendTaxi(uint32 i) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + unitTarget->ToPlayer()->ActivateTaxiPathTo(m_spellInfo->EffectMiscValue[i],m_spellInfo->Id); +} + +void Spell::EffectPlayerPull(uint32 i) +{ + if (!unitTarget) + return; + + float speedZ = m_spellInfo->EffectBasePoints[i]/10; + float speedXY = m_spellInfo->EffectMiscValue[i]/10; + unitTarget->GetMotionMaster()->MoveJump(m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), speedXY, speedZ); +} + +void Spell::EffectDispelMechanic(uint32 i) +{ + if (!unitTarget) + return; + + uint32 mechanic = m_spellInfo->EffectMiscValue[i]; + + std::queue < std::pair < uint32, uint64 > > dispel_list; + + Unit::AuraMap const& auras = unitTarget->GetOwnedAuras(); + for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + { + Aura * aura = itr->second; + if (!aura->GetApplicationOfTarget(unitTarget->GetGUID())) + continue; + bool success = false; + GetDispelChance(aura->GetCaster(), unitTarget, aura->GetId(), !unitTarget->IsFriendlyTo(m_caster), &success); + if ((GetAllSpellMechanicMask(aura->GetSpellProto()) & (1 << mechanic)) && success) + dispel_list.push(std::make_pair(aura->GetId(), aura->GetCasterGUID())); + } + + for (; dispel_list.size(); dispel_list.pop()) + { + unitTarget->RemoveAura(dispel_list.front().first, dispel_list.front().second, 0, AURA_REMOVE_BY_ENEMY_SPELL); + } +} + +void Spell::EffectSummonDeadPet(uint32 /*i*/) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + Player *_player = (Player*)m_caster; + Pet *pet = _player->GetPet(); + if (!pet) + return; + if (pet->isAlive()) + return; + if (damage < 0) + return; + + float x,y,z; + _player->GetPosition(x, y, z); + _player->GetMap()->CreatureRelocation(pet, x, y, z, _player->GetOrientation()); + + pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); + pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); + pet->setDeathState(ALIVE); + pet->clearUnitState(UNIT_STAT_ALL_STATE); + pet->SetHealth(uint32(pet->GetMaxHealth()*(float(damage)/100))); + + //pet->AIM_Initialize(); + //_player->PetSpellInitialize(); + pet->SavePetToDB(PET_SAVE_AS_CURRENT); +} + +void Spell::EffectDestroyAllTotems(uint32 /*i*/) +{ + int32 mana = 0; + for (uint8 slot = SUMMON_SLOT_TOTEM; slot < MAX_TOTEM_SLOT; ++slot) + { + if (!m_caster->m_SummonSlot[slot]) + continue; + + Creature* totem = m_caster->GetMap()->GetCreature(m_caster->m_SummonSlot[slot]); + if (totem && totem->isTotem()) + { + uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL); + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id); + if (spellInfo) + { + mana += spellInfo->manaCost; + mana += spellInfo->ManaCostPercentage * m_caster->GetCreateMana() / 100; + } + totem->ToTotem()->UnSummon(); + } + } + mana = mana * damage / 100; + + if (mana) + m_caster->CastCustomSpell(m_caster, 39104, &mana, NULL, NULL, true); +} + +void Spell::EffectDurabilityDamage(uint32 i) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + int32 slot = m_spellInfo->EffectMiscValue[i]; + + // FIXME: some spells effects have value -1/-2 + // Possibly its mean -1 all player equipped items and -2 all items + if (slot < 0) + { + unitTarget->ToPlayer()->DurabilityPointsLossAll(damage, (slot < -1)); + return; + } + + // invalid slot value + if (slot >= INVENTORY_SLOT_BAG_END) + return; + + if (Item* item = unitTarget->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, slot)) + unitTarget->ToPlayer()->DurabilityPointsLoss(item, damage); +} + +void Spell::EffectDurabilityDamagePCT(uint32 i) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + int32 slot = m_spellInfo->EffectMiscValue[i]; + + // FIXME: some spells effects have value -1/-2 + // Possibly its mean -1 all player equipped items and -2 all items + if (slot < 0) + { + unitTarget->ToPlayer()->DurabilityLossAll(double(damage)/100.0f, (slot < -1)); + return; + } + + // invalid slot value + if (slot >= INVENTORY_SLOT_BAG_END) + return; + + if (damage <= 0) + return; + + if (Item* item = unitTarget->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, slot)) + unitTarget->ToPlayer()->DurabilityLoss(item, double(damage)/100.0f); +} + +void Spell::EffectModifyThreatPercent(uint32 /*effIndex*/) +{ + if (!unitTarget) + return; + + unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage); +} + +void Spell::EffectTransmitted(uint32 effIndex) +{ + uint32 name_id = m_spellInfo->EffectMiscValue[effIndex]; + + GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id); + + if (!goinfo) + { + sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id, m_spellInfo->Id); + return; + } + + float fx, fy, fz; + + if (m_targets.HasDst()) + m_targets.m_dstPos.GetPosition(fx, fy, fz); + //FIXME: this can be better check for most objects but still hack + else if (m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed == 0) + { + float dis = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex])); + m_caster->GetClosePoint(fx, fy, fz, DEFAULT_WORLD_OBJECT_SIZE, dis); + } + else + { + //GO is always friendly to it's creator, get range for friends + float min_dis = GetSpellMinRangeForFriend(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); + float max_dis = GetSpellMaxRangeForFriend(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); + float dis = rand_norm() * (max_dis - min_dis) + min_dis; + + m_caster->GetClosePoint(fx, fy, fz, DEFAULT_WORLD_OBJECT_SIZE, dis); + } + + Map *cMap = m_caster->GetMap(); + if (goinfo->type == GAMEOBJECT_TYPE_FISHINGNODE) + { + LiquidData liqData; + if ( !cMap->IsInWater(fx, fy, fz + 1.f/* -0.5f */, &liqData)) // Hack to prevent fishing bobber from failing to land on fishing hole + { // but this is not proper, we really need to ignore not materialized objects + SendCastResult(SPELL_FAILED_NOT_HERE); + SendChannelUpdate(0); + return; + } + + // replace by water level in this case + //fz = cMap->GetWaterLevel(fx, fy); + fz = liqData.level; + } + // if gameobject is summoning object, it should be spawned right on caster's position + else if (goinfo->type == GAMEOBJECT_TYPE_SUMMONING_RITUAL) + { + m_caster->GetPosition(fx, fy, fz); + } + + GameObject* pGameObj = new GameObject; + + if (!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap, + m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) + { + delete pGameObj; + return; + } + + int32 duration = GetSpellDuration(m_spellInfo); + + switch(goinfo->type) + { + case GAMEOBJECT_TYPE_FISHINGNODE: + { + m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID()); + m_caster->AddGameObject(pGameObj); // will removed at spell cancel + + // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo)) + // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME) + int32 lastSec = 0; + switch(urand(0, 3)) + { + case 0: lastSec = 3; break; + case 1: lastSec = 7; break; + case 2: lastSec = 13; break; + case 3: lastSec = 17; break; + } + + duration = duration - lastSec*IN_MILLISECONDS + FISHING_BOBBER_READY_TIME*IN_MILLISECONDS; + break; + } + case GAMEOBJECT_TYPE_SUMMONING_RITUAL: + { + if (m_caster->GetTypeId() == TYPEID_PLAYER) + { + pGameObj->AddUniqueUse(m_caster->ToPlayer()); + m_caster->AddGameObject(pGameObj); // will removed at spell cancel + } + break; + } + case GAMEOBJECT_TYPE_DUEL_ARBITER: // 52991 + m_caster->AddGameObject(pGameObj); + break; + case GAMEOBJECT_TYPE_FISHINGHOLE: + case GAMEOBJECT_TYPE_CHEST: + default: + break; + } + + pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); + + pGameObj->SetOwnerGUID(m_caster->GetGUID()); + + //pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); + pGameObj->SetSpellId(m_spellInfo->Id); + + DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted"); + //m_caster->AddGameObject(pGameObj); + //m_ObjToDel.push_back(pGameObj); + + cMap->Add(pGameObj); + + if (uint32 linkedEntry = pGameObj->GetGOInfo()->GetLinkedGameObjectEntry()) + { + GameObject* linkedGO = new GameObject; + if (linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap, + m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) + { + linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); + //linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); + linkedGO->SetSpellId(m_spellInfo->Id); + linkedGO->SetOwnerGUID(m_caster->GetGUID()); + + linkedGO->GetMap()->Add(linkedGO); + } + else + { + delete linkedGO; + linkedGO = NULL; + return; + } + } +} + +void Spell::EffectProspecting(uint32 /*i*/) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player* p_caster = (Player*)m_caster; + if (!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP)) + return; + + if (itemTarget->GetCount() < 5) + return; + + if (sWorld.getConfig(CONFIG_SKILL_PROSPECTING)) + { + uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING); + uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank; + p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue); + } + + m_caster->ToPlayer()->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING); +} + +void Spell::EffectMilling(uint32 /*i*/) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player* p_caster = (Player*)m_caster; + if (!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_HERBS)) + return; + + if (itemTarget->GetCount() < 5) + return; + + if (sWorld.getConfig(CONFIG_SKILL_MILLING)) + { + uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_INSCRIPTION); + uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank; + p_caster->UpdateGatherSkill(SKILL_INSCRIPTION, SkillValue, reqSkillValue); + } + + m_caster->ToPlayer()->SendLoot(itemTarget->GetGUID(), LOOT_MILLING); +} + +void Spell::EffectSkill(uint32 /*i*/) +{ + sLog.outDebug("WORLD: SkillEFFECT"); +} + +/* There is currently no need for this effect. We handle it in BattleGround.cpp + If we would handle the resurrection here, the spiritguide would instantly disappear as the + player revives, and so we wouldn't see the spirit heal visual effect on the npc. + This is why we use a half sec delay between the visual effect and the resurrection itself */ +void Spell::EffectSpiritHeal(uint32 /*i*/) +{ + /* + if (!unitTarget || unitTarget->isAlive()) + return; + if (unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + if (!unitTarget->IsInWorld()) + return; + + //m_spellInfo->EffectBasePoints[i]; == 99 (percent?) + //unitTarget->ToPlayer()->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA)); + unitTarget->ToPlayer()->ResurrectPlayer(1.0f); + unitTarget->ToPlayer()->SpawnCorpseBones(); + */ +} + +// remove insignia spell effect +void Spell::EffectSkinPlayerCorpse(uint32 /*i*/) +{ + sLog.outDebug("Effect: SkinPlayerCorpse"); + if ((m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->isAlive())) + return; + + unitTarget->ToPlayer()->RemovedInsignia((Player*)m_caster); +} + +void Spell::EffectStealBeneficialBuff(uint32 i) +{ + sLog.outDebug("Effect: StealBeneficialBuff"); + + if (!unitTarget || unitTarget == m_caster) // can't steal from self + return; + + DispelChargesList steal_list; + + // Create dispel mask by dispel type + uint32 dispelMask = GetDispellMask(DispelType(m_spellInfo->EffectMiscValue[i])); + Unit::AuraMap const& auras = unitTarget->GetOwnedAuras(); + for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + { + Aura * aura = itr->second; + AuraApplication * aurApp = aura->GetApplicationOfTarget(unitTarget->GetGUID()); + if (!aurApp) + continue; + + if ((1<GetSpellProto()->Dispel) & dispelMask) + { + // Need check for passive? this + if (!aurApp->IsPositive() || aura->IsPassive() || aura->GetSpellProto()->AttributesEx4 & SPELL_ATTR_EX4_NOT_STEALABLE) + continue; + + // The charges / stack amounts don't count towards the total number of auras that can be dispelled. + // Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell + // Polymorph instead of 1 / (5 + 1) -> 16%. + bool dispel_charges = aura->GetSpellProto()->AttributesEx7 & SPELL_ATTR_EX7_DISPEL_CHARGES; + uint8 charges = dispel_charges ? aura->GetCharges() : aura->GetStackAmount(); + if (charges > 0) + steal_list.push_back(std::make_pair(aura, charges)); + } + } + + if (steal_list.empty()) + return; + + // Ok if exist some buffs for dispel try dispel it + uint32 failCount = 0; + DispelList success_list; + WorldPacket dataFail(SMSG_DISPEL_FAILED, 8+8+4+4+damage*4); + // dispel N = damage buffs (or while exist buffs for dispel) + for (int32 count = 0; count < damage && !steal_list.empty();) + { + // Random select buff for dispel + DispelChargesList::iterator itr = steal_list.begin(); + std::advance(itr, urand(0, steal_list.size() - 1)); + + bool success = false; + // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance." + if (!GetDispelChance(itr->first->GetCaster(), unitTarget, itr->first->GetId(), !unitTarget->IsFriendlyTo(m_caster), &success)) + { + steal_list.erase(itr); + continue; + } + else + { + if (success) + { + success_list.push_back(std::make_pair(itr->first->GetId(), itr->first->GetCasterGUID())); + --itr->second; + if (itr->second <= 0) + steal_list.erase(itr); + } + else + { + if (!failCount) + { + // Failed to dispell + dataFail << uint64(m_caster->GetGUID()); // Caster GUID + dataFail << uint64(unitTarget->GetGUID()); // Victim GUID + dataFail << uint32(m_spellInfo->Id); // dispel spell id + } + ++failCount; + dataFail << uint32(itr->first->GetId()); // Spell Id + } + ++count; + } + } + + if (failCount) + m_caster->SendMessageToSet(&dataFail, true); + + if (success_list.empty()) + return; + + WorldPacket dataSuccess(SMSG_SPELLSTEALLOG, 8+8+4+1+4+damage*5); + dataSuccess.append(unitTarget->GetPackGUID()); // Victim GUID + dataSuccess.append(m_caster->GetPackGUID()); // Caster GUID + dataSuccess << uint32(m_spellInfo->Id); // dispel spell id + dataSuccess << uint8(0); // not used + dataSuccess << uint32(success_list.size()); // count + for (DispelList::iterator itr = success_list.begin(); itr!=success_list.end(); ++itr) + { + dataSuccess << uint32(itr->first); // Spell Id + dataSuccess << uint8(0); // 0 - steals !=0 transfers + unitTarget->RemoveAurasDueToSpellBySteal(itr->first, itr->second, m_caster); + } + m_caster->SendMessageToSet(&dataSuccess, true); +} + +void Spell::EffectKillCreditPersonal(uint32 i) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + unitTarget->ToPlayer()->KilledMonsterCredit(m_spellInfo->EffectMiscValue[i], 0); +} + +void Spell::EffectKillCredit(uint32 i) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + int32 creatureEntry = m_spellInfo->EffectMiscValue[i]; + if (!creatureEntry) + { + if (m_spellInfo->Id == 42793) // Burn Body + creatureEntry = 24008; // Fallen Combatant + } + + if (creatureEntry) + unitTarget->ToPlayer()->RewardPlayerAndGroupAtEvent(creatureEntry, unitTarget); +} + +void Spell::EffectQuestFail(uint32 i) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + unitTarget->ToPlayer()->FailQuest(m_spellInfo->EffectMiscValue[i]); +} + +void Spell::EffectActivateRune(uint32 eff_idx) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player *plr = (Player*)m_caster; + + if (plr->getClass() != CLASS_DEATH_KNIGHT) + return; + + // needed later + m_runesState = m_caster->ToPlayer()->GetRunesState(); + + uint32 count = damage; + if (count == 0) count = 1; + for (uint32 j = 0; j < MAX_RUNES && count > 0; ++j) + { + if (plr->GetRuneCooldown(j) && plr->GetCurrentRune(j) == RuneType(m_spellInfo->EffectMiscValue[eff_idx])) + { + plr->SetRuneCooldown(j, 0); + --count; + } + } + // Empower rune weapon + if (m_spellInfo->Id == 47568) + { + // Need to do this just once + if (eff_idx != 0) + return; + + for (uint32 i = 0; i < MAX_RUNES; ++i) + { + if (plr->GetRuneCooldown(i) && (plr->GetCurrentRune(i) == RUNE_FROST || plr->GetCurrentRune(i) == RUNE_DEATH)) + plr->SetRuneCooldown(i, 0); + } + } +} + +void Spell::EffectTitanGrip(uint32 /*eff_idx*/) +{ + if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER) + unitTarget->ToPlayer()->SetCanTitanGrip(true); +} + +void Spell::EffectRedirectThreat(uint32 /*i*/) +{ + if (unitTarget) + m_caster->SetReducedThreatPercent((uint32)damage, unitTarget->GetGUID()); +} + +void Spell::EffectWMODamage(uint32 /*i*/) +{ + if (gameObjTarget && gameObjTarget->GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING) + { + Unit *caster = m_originalCaster; + if (!caster) + return; + + FactionTemplateEntry const *casterft, *goft; + casterft = caster->getFactionTemplateEntry(); + goft = sFactionTemplateStore.LookupEntry(gameObjTarget->GetUInt32Value(GAMEOBJECT_FACTION)); + // Do not allow to damage GO's of friendly factions (ie: Wintergrasp Walls) + if (casterft && goft && !casterft->IsFriendlyTo(*goft)) + { + gameObjTarget->TakenDamage(uint32(damage), caster); + WorldPacket data(SMSG_DESTRUCTIBLE_BUILDING_DAMAGE, 8+8+8+4+4); + data.append(gameObjTarget->GetPackGUID()); + data.append(caster->GetPackGUID()); + if (Unit *who = caster->GetCharmerOrOwner()) + data.append(who->GetPackGUID()); + else + data << uint8(0); + data << uint32(damage); + data << uint32(m_spellInfo->Id); + gameObjTarget->SendMessageToSet(&data, false); + } + } +} + +void Spell::EffectWMORepair(uint32 /*i*/) +{ + if (gameObjTarget && gameObjTarget->GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING) + gameObjTarget->Rebuild(); +} + +void Spell::SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const *properties) +{ + Unit *caster = m_originalCaster; + if (!caster) + return; + + if (caster->isTotem()) + caster = caster->ToTotem()->GetOwner(); + + // in another case summon new + uint8 level = caster->getLevel(); + + // level of pet summoned using engineering item based at engineering skill level + if (m_CastItem && caster->GetTypeId() == TYPEID_PLAYER) + if (ItemPrototype const *proto = m_CastItem->GetProto()) + if (proto->RequiredSkill == SKILL_ENGINERING) + if (uint16 skill202 = caster->ToPlayer()->GetSkillValue(SKILL_ENGINERING)) + level = skill202/5; + + //float radius = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); + float radius = 5.0f; + int32 amount = damage > 0 ? damage : 1; + int32 duration = GetSpellDuration(m_spellInfo); + switch (m_spellInfo->Id) + { + case 1122: // Inferno + amount = 1; + break; + case 49028: // Dancing Rune Weapon + if (AuraEffect *aurEff = m_originalCaster->GetAuraEffect(63330, 0)) // glyph of Dancing Rune Weapon + duration += aurEff->GetAmount(); + break; + } + if (Player* modOwner = m_originalCaster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration); + + //TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN; + Map *map = caster->GetMap(); + + for (uint32 count = 0; count < amount; ++count) + { + Position pos; + GetSummonPosition(i, pos, radius, count); + + TempSummon *summon = map->SummonCreature(entry, pos, properties, duration, caster); + if (!summon) + return; + if (summon->HasUnitTypeMask(UNIT_MASK_GUARDIAN)) + ((Guardian*)summon)->InitStatsForLevel(level); + + summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); + if (summon->HasUnitTypeMask(UNIT_MASK_MINION) && m_targets.HasDst()) + ((Minion*)summon)->SetFollowAngle(m_caster->GetAngle(summon)); + + if (summon->GetEntry() == 27893) + if (uint32 weapon = m_caster->GetUInt32Value(PLAYER_VISIBLE_ITEM_16_ENTRYID)) + { + summon->SetDisplayId(11686); + summon->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, weapon); + } + else + summon->SetDisplayId(1126); + + summon->AI()->EnterEvadeMode(); + } +} + +void Spell::GetSummonPosition(uint32 i, Position &pos, float radius, uint32 count) +{ + pos.SetOrientation(m_caster->GetOrientation()); + + if (m_targets.HasDst()) + { + // Summon 1 unit in dest location + if (count == 0) + pos.Relocate(m_targets.m_dstPos); + // Summon in random point all other units if location present + else + { + //This is a workaround. Do not have time to write much about it + switch (m_spellInfo->EffectImplicitTargetA[i]) + { + case TARGET_MINION: + case TARGET_DEST_CASTER_RANDOM: + m_caster->GetNearPosition(pos, radius * rand_norm(), rand_norm()*2*M_PI); + break; + case TARGET_DEST_DEST_RANDOM: + case TARGET_DEST_TARGET_RANDOM: + m_caster->GetRandomPoint(m_targets.m_dstPos, radius, pos); + break; + default: + pos.Relocate(m_targets.m_dstPos); + break; + } + } + } + // Summon if dest location not present near caster + else + { + float x, y, z; + m_caster->GetClosePoint(x,y,z,3.0f); + pos.Relocate(x, y, z); + } +} + +void Spell::EffectRenamePet(uint32 /*eff_idx*/) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || + !unitTarget->ToCreature()->isPet() || ((Pet*)unitTarget)->getPetType() != HUNTER_PET) + return; + + unitTarget->RemoveByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED); +} + +void Spell::EffectPlayMusic(uint32 i) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + uint32 soundid = m_spellInfo->EffectMiscValue[i]; + + if (!sSoundEntriesStore.LookupEntry(soundid)) + { + sLog.outError("EffectPlayMusic: Sound (Id: %u) not exist in spell %u.",soundid,m_spellInfo->Id); + return; + } + + WorldPacket data(SMSG_PLAY_MUSIC, 4); + data << uint32(soundid); + unitTarget->ToPlayer()->GetSession()->SendPacket(&data); +} + +void Spell::EffectSpecCount(uint32 /*eff_idx*/) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + unitTarget->ToPlayer()->UpdateSpecCount(damage); +} + +void Spell::EffectActivateSpec(uint32 /*eff_idx*/) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + unitTarget->ToPlayer()->ActivateSpec(damage-1); // damage is 1 or 2, spec is 0 or 1 +} + +void Spell::EffectPlayerNotification(uint32 /*eff_idx*/) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + switch(m_spellInfo->Id) + { + case 58730: // Restricted Flight Area + case 58600: // Restricted Flight Area + unitTarget->ToPlayer()->GetSession()->SendNotification(LANG_ZONE_NOFLYZONE); + break; + } +} + +void Spell::EffectRemoveAura(uint32 i) +{ + if (!unitTarget) + return; + // there may be need of specifying casterguid of removed auras + unitTarget->RemoveAurasDueToSpell(m_spellInfo->EffectTriggerSpell[i]); +} + +void Spell::EffectCastButtons(uint32 i) +{ + if (!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player *p_caster = (Player*)m_caster; + uint32 button_id = m_spellInfo->EffectMiscValue[i] + 132; + uint32 n_buttons = m_spellInfo->EffectMiscValueB[i]; + + for (; n_buttons; n_buttons--, button_id++) + { + ActionButton const* ab = p_caster->GetActionButton(button_id); + if (!ab || ab->GetType() != ACTION_BUTTON_SPELL) + continue; + + uint32 spell_id = ab->GetAction(); + if (!spell_id) + continue; + + if (p_caster->HasSpellCooldown(spell_id)) + continue; + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); + uint32 cost = CalculatePowerCost(spellInfo, m_caster, GetSpellSchoolMask(spellInfo)); + + if (m_caster->GetPower(POWER_MANA) < cost) + break; + + m_caster->CastSpell(unitTarget, spell_id, true); + m_caster->ModifyPower(POWER_MANA, -(int32)cost); + p_caster->AddSpellAndCategoryCooldowns(spellInfo, 0); + } +} + +void Spell::EffectRechargeManaGem(uint32 /*i*/) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + Player *player = (Player*)m_caster; + + if (!player) + return; + + uint32 item_id = m_spellInfo->EffectItemType[0]; + + ItemPrototype const *pProto = objmgr.GetItemPrototype(item_id); + if (!pProto) + { + player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + if (Item* pItem = player->GetItemByEntry(item_id)) + { + for (int x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x) + pItem->SetSpellCharges(x,pProto->Spells[x].SpellCharges); + pItem->SetState(ITEM_CHANGED,player); + } +} + +void Spell::EffectBind(uint32 i) +{ + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + Player* player = (Player*)unitTarget; + + uint32 area_id; + WorldLocation loc; + if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_DST_DB || m_spellInfo->EffectImplicitTargetB[i] == TARGET_DST_DB) + { + SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id); + if (!st) + { + sLog.outError( "Spell::EffectBind - unknown teleport coordinates for spell ID %u", m_spellInfo->Id ); + return; + } + + loc.m_mapId = st->target_mapId; + loc.m_positionX = st->target_X; + loc.m_positionY = st->target_Y; + loc.m_positionZ = st->target_Y; + loc.m_orientation = st->target_Orientation; + area_id = player->GetAreaId(); + } + else + { + player->GetPosition(&loc); + area_id = player->GetAreaId(); + } + + player->SetHomebind(loc, area_id); + + // binding + WorldPacket data( SMSG_BINDPOINTUPDATE, (4+4+4+4+4) ); + data << float(loc.m_positionX); + data << float(loc.m_positionY); + data << float(loc.m_positionZ); + data << uint32(loc.m_mapId); + data << uint32(area_id); + player->SendDirectMessage( &data ); + + DEBUG_LOG("New homebind X : %f", loc.m_positionX); + DEBUG_LOG("New homebind Y : %f", loc.m_positionY); + DEBUG_LOG("New homebind Z : %f", loc.m_positionZ); + DEBUG_LOG("New homebind MapId : %u", loc.m_mapId); + DEBUG_LOG("New homebind AreaId : %u", area_id); + + // zone update + data.Initialize(SMSG_PLAYERBOUND, 8+4); + data << uint64(player->GetGUID()); + data << uint32(area_id); + player->SendDirectMessage( &data ); +} -- cgit v1.2.3