diff options
Diffstat (limited to 'src/game/SpellEffects.cpp')
-rw-r--r-- | src/game/SpellEffects.cpp | 12188 |
1 files changed, 6098 insertions, 6090 deletions
diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index fa037fcdb24..32be3d65065 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -1,6090 +1,6098 @@ -/* - * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> - * - * 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 "SharedDefines.h" -#include "Database/DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.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 "CreatureAI.h" -#include "Spell.h" -#include "DynamicObject.h" -#include "SpellAuras.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 "BattleGround.h" -#include "BattleGroundEY.h" -#include "BattleGroundWS.h" -#include "VMapFactory.h" -#include "Language.h" -#include "SocialMgr.h" -#include "Util.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::EffectUnused, // 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::EffectUnused, // 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::EffectMomentMove, // 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::EffectSummonWild, // 41 SPELL_EFFECT_SUMMON_WILD - &Spell::EffectSummonGuardian, // 42 SPELL_EFFECT_SUMMON_GUARDIAN - &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::EffectNULL, // 46 SPELL_EFFECT_SPAWN we must spawn pet there - &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::EffectOpenSecretSafe, // 59 SPELL_EFFECT_OPEN_LOCK_ITEM - &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::EffectUnused, // 65 SPELL_EFFECT_HEALTH_FUNNEL unused - &Spell::EffectUnused, // 66 SPELL_EFFECT_POWER_FUNNEL unused - &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::EffectSummonGuardian, // 73 SPELL_EFFECT_SUMMON_POSSESSED - &Spell::EffectSummonTotem, // 74 SPELL_EFFECT_SUMMON_TOTEM - &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::EffectSummonTotem, // 87 SPELL_EFFECT_SUMMON_TOTEM_SLOT1 - &Spell::EffectSummonTotem, // 88 SPELL_EFFECT_SUMMON_TOTEM_SLOT2 - &Spell::EffectSummonTotem, // 89 SPELL_EFFECT_SUMMON_TOTEM_SLOT3 - &Spell::EffectSummonTotem, // 90 SPELL_EFFECT_SUMMON_TOTEM_SLOT4 - &Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash - &Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM - &Spell::EffectUnused, // 93 SPELL_EFFECT_SUMMON_PHANTASM - &Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT - &Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING - &Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE - &Spell::EffectSummonCritter, // 97 SPELL_EFFECT_SUMMON_CRITTER - &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::EffectSummonDemon, //112 SPELL_EFFECT_SUMMON_DEMON - &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::EffectNULL, //130 SPELL_EFFECT_REDIRECT_THREAT - &Spell::EffectUnused, //131 SPELL_EFFECT_131 used in some test spells - &Spell::EffectNULL, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value - &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::EffectEnergisePct, //137 SPELL_EFFECT_ENERGIZE_PCT - &Spell::EffectNULL, //138 SPELL_EFFECT_138 Leap - &Spell::EffectUnused, //139 SPELL_EFFECT_139 unused - &Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST - &Spell::EffectNULL, //141 SPELL_EFFECT_141 damage and reduce speed? - &Spell::EffectTriggerSpellWithValue, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE - &Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER - &Spell::EffectNULL, //144 SPELL_EFFECT_144 Spectral Blast - &Spell::EffectNULL, //145 SPELL_EFFECT_145 Black Hole Effect - &Spell::EffectUnused, //146 SPELL_EFFECT_146 unused - &Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail - &Spell::EffectUnused, //148 SPELL_EFFECT_148 unused - &Spell::EffectNULL, //149 SPELL_EFFECT_149 swoop - &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 -}; - -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 MANGOS -} - -void Spell::EffectResurrectNew(uint32 i) -{ - if(!unitTarget || unitTarget->isAlive()) - return; - - if(unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - if(!unitTarget->IsInWorld()) - return; - - Player* pTarget = ((Player*)unitTarget); - - 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(); - - uint32 health = unitTarget->GetHealth(); - m_caster->DealDamage(unitTarget, health, 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 = m_spellInfo->EffectBasePoints[i]+m_spellInfo->EffectBaseDice[i]; - - m_caster->CalcAbsorbResist(m_caster,GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); - - m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false); - if(m_caster->GetTypeId() == TYPEID_PLAYER) - ((Player*)m_caster)->EnvironmentalDamage(m_caster->GetGUID(),DAMAGE_FIRE,damage); -} - -void Spell::EffectSchoolDMG(uint32 effect_idx) -{ - if( unitTarget && unitTarget->isAlive()) - { - switch(m_spellInfo->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - { - //Gore - if(m_spellInfo->SpellIconID == 2269 ) - { - damage+= rand()%2 ? damage : 0; - } - - switch(m_spellInfo->Id) // better way to check unknown - { - // Meteor like spells (divided damage to targets) - case 24340: case 26558: case 28884: // Meteor - case 36837: case 38903: case 41276: // Meteor - case 26789: // Shard of the Fallen Star - case 31436: // Malevolent Cleave - case 35181: // Dive Bomb - case 40810: case 43267: case 43268: // Saber Lash - case 42384: // Brutal Swipe - case 45150: // Meteor Slash - { - uint32 count = 0; - for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) - if(ihit->effectMask & (1<<effect_idx)) - ++count; - - damage /= count; // divide to all targets - break; - } - // percent from health with min - case 25599: // Thundercrash - { - damage = unitTarget->GetHealth() / 2; - if(damage < 200) - damage = 200; - break; - } - } - break; - } - - case SPELLFAMILY_MAGE: - { - // Arcane Blast - if(m_spellInfo->SpellFamilyFlags & 0x20000000LL) - { - m_caster->CastSpell(m_caster,36032,true); - } - break; - } - case SPELLFAMILY_WARRIOR: - { - // Bloodthirst - if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL) - { - damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100); - } - // Shield Slam - else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL) - damage += int32(m_caster->GetShieldBlockValue()); - // Victory Rush - else if(m_spellInfo->SpellFamilyFlags & 0x10000000000LL) - { - damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100); - m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false); - } - break; - } - case SPELLFAMILY_WARLOCK: - { - // Incinerate Rank 1 & 2 - if((m_spellInfo->SpellFamilyFlags & 0x00004000000000LL) && m_spellInfo->SpellIconID==2128) - { - // Incinerate does more dmg (dmg*0.25) if the target is Immolated. - if(unitTarget->HasAuraState(AURA_STATE_IMMOLATE)) - damage += int32(damage*0.25); - } - break; - } - case SPELLFAMILY_DRUID: - { - // Ferocious Bite - if((m_spellInfo->SpellFamilyFlags & 0x000800000) && m_spellInfo->SpellVisual==6587) - { - // converts each extra point of energy into ($f1+$AP/630) additional damage - float multiple = m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 630 + m_spellInfo->DmgMultiplier[effect_idx]; - damage += int32(m_caster->GetPower(POWER_ENERGY) * multiple); - m_caster->SetPower(POWER_ENERGY,0); - } - // Rake - else if(m_spellInfo->SpellFamilyFlags & 0x0000000000001000LL) - { - damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100); - } - // Swipe - else if(m_spellInfo->SpellFamilyFlags & 0x0010000000000000LL) - { - damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.08f); - } - // Starfire - else if ( m_spellInfo->SpellFamilyFlags & 0x0004LL ) - { - Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i) - { - // Starfire Bonus (caster) - switch((*i)->GetModifier()->m_miscvalue) - { - case 5481: // Nordrassil Regalia - bonus - { - Unit::AuraList const& m_periodicDamageAuras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE); - for(Unit::AuraList::const_iterator itr = m_periodicDamageAuras.begin(); itr != m_periodicDamageAuras.end(); ++itr) - { - // Moonfire or Insect Swarm (target debuff from any casters) - if ( (*itr)->GetSpellProto()->SpellFamilyFlags & 0x00200002LL ) - { - int32 mod = (*i)->GetModifier()->m_amount; - damage += damage*mod/100; - break; - } - } - break; - } - case 5148: //Improved Starfire - Ivory Idol of the Moongoddes Aura - { - damage += (*i)->GetModifier()->m_amount; - break; - } - } - } - } - //Mangle Bonus for the initial damage of Lacerate and Rake - if((m_spellInfo->SpellFamilyFlags==0x0000000000001000LL && m_spellInfo->SpellIconID==494) || - (m_spellInfo->SpellFamilyFlags==0x0000010000000000LL && m_spellInfo->SpellIconID==2246)) - { - Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i) - if((*i)->GetSpellProto()->SpellFamilyFlags & 0x0000044000000000LL && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID) - { - damage = int32(damage*(100.0f+(*i)->GetModifier()->m_amount)/100.0f); - break; - } - } - break; - } - case SPELLFAMILY_ROGUE: - { - // Envenom - if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x800000000LL)) - { - // consume from stack dozes not more that have combo-points - if(uint32 combo = ((Player*)m_caster)->GetComboPoints()) - { - // count consumed deadly poison doses at target - uint32 doses = 0; - - // remove consumed poison doses - Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE); - for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end() && combo;) - { - // Deadly poison (only attacker applied) - if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE && ((*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000) && - (*itr)->GetSpellProto()->SpellVisual==5100 && (*itr)->GetCasterGUID()==m_caster->GetGUID() ) - { - --combo; - ++doses; - - unitTarget->RemoveSingleAuraFromStack((*itr)->GetId(), (*itr)->GetEffIndex()); - - itr = auras.begin(); - } - else - ++itr; - } - - damage *= doses; - damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses); - - // Eviscerate and Envenom Bonus Damage (item set effect) - if(m_caster->GetDummyAura(37169)) - damage += ((Player*)m_caster)->GetComboPoints()*40; - } - } - // Eviscerate - else if((m_spellInfo->SpellFamilyFlags & 0x00020000LL) && m_caster->GetTypeId()==TYPEID_PLAYER) - { - if(uint32 combo = ((Player*)m_caster)->GetComboPoints()) - { - damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * combo * 0.03f); - - // Eviscerate and Envenom Bonus Damage (item set effect) - if(m_caster->GetDummyAura(37169)) - damage += combo*40; - } - } - break; - } - case SPELLFAMILY_HUNTER: - { - // Mongoose Bite - if((m_spellInfo->SpellFamilyFlags & 0x000000002) && m_spellInfo->SpellVisual==342) - { - damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2); - } - // Arcane Shot - else if((m_spellInfo->SpellFamilyFlags & 0x00000800) && m_spellInfo->maxLevel > 0) - { - damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15); - } - // Steady Shot - else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL) - { - int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),(int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE)); - damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.2f); - } - //Explosive Trap Effect - else if(m_spellInfo->SpellFamilyFlags & 0x00000004) - { - damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1); - } - break; - } - case SPELLFAMILY_PALADIN: - { - //Judgement of Vengeance - if((m_spellInfo->SpellFamilyFlags & 0x800000000LL) && m_spellInfo->SpellIconID==2292) - { - uint32 stacks = 0; - Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE); - for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr) - if((*itr)->GetId() == 31803 && (*itr)->GetCasterGUID()==m_caster->GetGUID()) - ++stacks; - if(!stacks) - //No damage if the target isn't affected by this - damage = -1; - else - damage *= stacks; - } - break; - } - } - - if(damage >= 0) - { - uint32 finalDamage; - if(m_originalCaster) // m_caster only passive source of cast - finalDamage = m_originalCaster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true); - else - finalDamage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true); - - // post effects - switch(m_spellInfo->SpellFamilyName) - { - case SPELLFAMILY_WARRIOR: - { - // Bloodthirst - if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL) - { - uint32 BTAura = 0; - switch(m_spellInfo->Id) - { - case 23881: BTAura = 23885; break; - case 23892: BTAura = 23886; break; - case 23893: BTAura = 23887; break; - case 23894: BTAura = 23888; break; - case 25251: BTAura = 25252; break; - case 30335: BTAura = 30339; break; - default: - sLog.outError("Spell::EffectSchoolDMG: Spell %u not handled in BTAura",m_spellInfo->Id); - break; - } - - if (BTAura) - m_caster->CastSpell(m_caster,BTAura,true); - } - break; - } - case SPELLFAMILY_PRIEST: - { - // Shadow Word: Death - if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000200000000LL) && unitTarget->isAlive()) - // deals damage equal to damage done to caster if victim is not killed - m_caster->SpellNonMeleeDamageLog( m_caster, m_spellInfo->Id, finalDamage, m_IsTriggeredSpell, false); - - break; - } - case SPELLFAMILY_PALADIN: - { - // Judgement of Blood - if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000800000000LL) && m_spellInfo->SpellIconID==153) - { - int32 damagePoint = finalDamage * 33 / 100; - m_caster->CastCustomSpell(m_caster, 32220, &damagePoint, NULL, NULL, true); - } - break; - } - } - } - } -} - -void Spell::EffectDummy(uint32 i) -{ - if(!unitTarget && !gameObjTarget && !itemTarget) - return; - - // selection by spell family - switch(m_spellInfo->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - // Gnomish Poultryizer trinket - 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; - ((Creature*)unitTarget)->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 12850: damage *= 0.2f; break; - case 12162: damage *= 0.4f; break; - case 12868: damage *= 0.6f; break; - default: - sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id); - return; - }; - - int32 deepWoundsDotBasePoints0 = int32(damage / 4); - m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL); - return; - } - case 12975: //Last Stand - { - int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3); - m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, 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 13567: // Dummy Trigger - { - // can be used for different aura triggreing, 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 14185: // Preparation Rogue - { - if(m_caster->GetTypeId()!=TYPEID_PLAYER) - return; - - //immediately finishes the cooldown on certain Rogue abilities - const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) - { - uint32 classspell = itr->first; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell); - - if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & 0x26000000860LL)) - { - ((Player*)m_caster)->RemoveSpellCooldown(classspell); - - WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); - data << uint32(classspell); - data << uint64(m_caster->GetGUID()); - ((Player*)m_caster)->GetSession()->SendPacket(&data); - } - } - return; - } - case 15998: // Capture Worg Pup - case 29435: // Capture Female Kaliri Hatchling - { - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) - return; - - Creature* creatureTarget = (Creature*)unitTarget; - creatureTarget->setDeathState(JUST_DIED); - creatureTarget->RemoveCorpse(); - creatureTarget->SetHealth(0); // just for nice GM-mode view - 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 << unitTarget->GetGUID(); - ((Player*)m_originalCaster)->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 : 17270; - - 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 || ((Creature*)unitTarget)->isPet()) - return; - - Creature* creatureTarget = (Creature*)unitTarget; - if(creatureTarget->isPet()) - return; - - creatureTarget->setDeathState(JUST_DIED); - creatureTarget->RemoveCorpse(); - creatureTarget->SetHealth(0); // just for nice GM-mode view - - GameObject* pGameObj = new GameObject; - - Map *map = creatureTarget->GetMap(); - - if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 179644, map, - creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(), - creatureTarget->GetOrientation(), 0, 0, 0, 0, 100, 1) ) - { - delete pGameObj; - return; - } - - pGameObj->SetRespawnTime(creatureTarget->GetRespawnTime()-time(NULL)); - pGameObj->SetOwnerGUID(m_caster->GetGUID() ); - pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() ); - pGameObj->SetSpellId(m_spellInfo->Id); - - DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy\n"); - map->Add(pGameObj); - - WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8); - data << uint64(pGameObj->GetGUID()); - m_caster->SendMessageToSet(&data,true); - - return; - } - case 23074: // Arc. 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: // Ultrasafe Transporter: Gadgetzan - backfires - { - int32 r = irand(0, 119); - if ( r < 20 ) // 1/6 polymorph - m_caster->CastSpell(m_caster,23444,true); - else if ( r < 100 ) // 4/6 evil twin - m_caster->CastSpell(m_caster,23445,true); - else // 1/6 miss the target - m_caster->CastSpell(m_caster,36902,true); - return; - } - case 23453: // Ultrasafe Transporter: Gadgetzan - if ( roll_chance_i(50) ) // success - m_caster->CastSpell(m_caster,23441,true); - else // failure - m_caster->CastSpell(m_caster,23446,true); - return; - case 23645: // Hourglass Sand - m_caster->RemoveAurasDueToSpell(23170); - 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_FLY); - float speed = m_caster->GetSpeedRate(MOVE_RUN); - - m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED); - - //5 different spells used depending on mounted speed and if mount can fly or not - if (flyspeed >= 4.1f) - m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer - else if (flyspeed >= 3.8f) - m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer - else if (flyspeed >= 1.6f) - m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer - else if (speed >= 2.0f) - m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer - else - m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer - - return; - } - //case 26074: // Holiday Cheer - // return; -- implemented at client side - case 28006: // Arcane Cloaking - { - if( unitTarget->GetTypeId() == TYPEID_PLAYER ) - m_caster->CastSpell(unitTarget,29294,true); - return; - } - case 28730: // Arcane Torrent (Mana) - { - int32 count = 0; - Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraList::const_iterator i = m_dummyAuras.begin(); i != m_dummyAuras.end(); ++i) - if ((*i)->GetId() == 28734) - ++count; - if (count) - { - m_caster->RemoveAurasDueToSpell(28734); - int32 bp = damage * count; - m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true); - } - return; - } - case 29200: // Purify Helboar Meat - { - if( m_caster->GetTypeId() != TYPEID_PLAYER ) - return; - - uint32 spell_id = roll_chance_i(50) ? 29277 : 29278; - - m_caster->CastSpell(m_caster,spell_id,true,NULL); - return; - } - case 29858: // Soulshatter - if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsHostileTo(m_caster)) - m_caster->CastSpell(unitTarget,32835,true); - return; - case 30458: // Nigh Invulnerability - if (!m_CastItem) return; - if(roll_chance_i(86)) // success - m_caster->CastSpell(m_caster, 30456, true, m_CastItem); - else // 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)) // success - m_caster->CastSpell(unitTarget, 30501, true, m_CastItem); - else // 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; - case 2: spell_id = 33057; break; - case 3: spell_id = 33059; break; - case 4: spell_id = 33062; break; - case 5: spell_id = 33064; break; - } - - m_caster->CastSpell(m_caster,spell_id,true,NULL); - return; - } - case 35745: - { - uint32 spell_id; - switch(m_caster->GetAreaId()) - { - case 3900: spell_id = 35743; break; - case 3742: spell_id = 35744; break; - default: return; - } - - m_caster->CastSpell(m_caster,spell_id,true); - return; - } - case 37674: // Chaos Blast - if(unitTarget) - m_caster->CastSpell(unitTarget,37675,true); - return; - case 44875: // Complete Raptor Capture - { - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) - return; - - Creature* creatureTarget = (Creature*)unitTarget; - - creatureTarget->setDeathState(JUST_DIED); - creatureTarget->RemoveCorpse(); - creatureTarget->SetHealth(0); // just for nice GM-mode view - - //cast spell Raptor Capture Credit - m_caster->CastSpell(m_caster,42337,true,NULL); - return; - } - case 45030: // Impale Emissary - { - // Emissary of Hate Credit - m_caster->CastSpell(m_caster,45088,true); - 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(((Player*)m_caster)->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 = ((Player*)m_caster)->GetBattleGround()) - bg->EventPlayerDroppedFlag((Player*)m_caster); - - m_caster->CastSpell(m_caster, 30452, true, NULL); - return; - } - } - - //All IconID Check in there - switch(m_spellInfo->SpellIconID) - { - // Berserking (troll racial traits) - case 1661: - { - uint32 healthPerc = uint32((float(m_caster->GetHealth())/m_caster->GetMaxHealth())*100); - int32 melee_mod = 10; - if (healthPerc <= 40) - melee_mod = 30; - if (healthPerc < 100 && healthPerc > 40) - melee_mod = 10+(100-healthPerc)/3; - - int32 hasteModBasePoints0 = melee_mod; // (EffectBasePoints[0]+1)-1+(5-melee_mod) = (melee_mod-1+1)-1+5-melee_mod = 5-1 - int32 hasteModBasePoints1 = (5-melee_mod); - int32 hasteModBasePoints2 = 5; - - // FIXME: custom spell required this aura state by some unknown reason, we not need remove it anyway - m_caster->ModifyAuraState(AURA_STATE_BERSERKING,true); - m_caster->CastCustomSpell(m_caster,26635,&hasteModBasePoints0,&hasteModBasePoints1,&hasteModBasePoints2,true,NULL); - 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 PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) - { - if (itr->second->state == PLAYERSPELL_REMOVED) - continue; - - uint32 classspell = itr->first; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell); - - if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && - (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) && - spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 ) - { - ((Player*)m_caster)->RemoveSpellCooldown(classspell); - - WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); - data << uint32(classspell); - data << uint64(m_caster->GetGUID()); - ((Player*)m_caster)->GetSession()->SendPacket(&data); - } - } - return; - } - } - break; - case SPELLFAMILY_WARRIOR: - // Charge - if(m_spellInfo->SpellFamilyFlags & 0x1 && m_spellInfo->SpellVisual == 867) - { - int32 chargeBasePoints0 = damage; - m_caster->CastCustomSpell(m_caster,34846,&chargeBasePoints0,NULL,NULL,true); - return; - } - // Execute - if(m_spellInfo->SpellFamilyFlags & 0x20000000) - { - if(!unitTarget) - return; - - int32 basePoints0 = damage+int32(m_caster->GetPower(POWER_RAGE) * m_spellInfo->DmgMultiplier[i]); - m_caster->CastCustomSpell(unitTarget, 20647, &basePoints0, NULL, NULL, true, 0); - m_caster->SetPower(POWER_RAGE,0); - return; - } - if(m_spellInfo->Id==21977) //Warrior's Wrath - { - if(!unitTarget) - return; - - m_caster->CastSpell(unitTarget,21887,true); // spell mod - return; - } - break; - case SPELLFAMILY_WARLOCK: - //Life Tap (only it have this with dummy effect) - if (m_spellInfo->SpellFamilyFlags == 0x40000) - { - float cost = m_currentBasePoints[0]+1; - - if(Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, cost,this); - - int32 dmg = m_caster->SpellDamageBonus(m_caster, m_spellInfo,uint32(cost > 0 ? cost : 0), SPELL_DIRECT_DAMAGE); - - if(int32(m_caster->GetHealth()) > dmg) - { - // Shouldn't Appear in Combat Log - m_caster->ModifyHealth(-dmg); - - int32 mana = dmg; - - Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr) - { - // only Imp. Life Tap have this in combination with dummy aura - if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 208) - mana = ((*itr)->GetModifier()->m_amount + 100)* mana / 100; - } - - m_caster->CastCustomSpell(m_caster,31818,&mana,NULL,NULL,true,NULL); - - // Mana Feed - int32 manaFeedVal = m_caster->CalculateSpellDamage(m_spellInfo,1, m_spellInfo->EffectBasePoints[1],m_caster); - manaFeedVal = manaFeedVal * mana / 100; - if(manaFeedVal > 0) - m_caster->CastCustomSpell(m_caster,32553,&manaFeedVal,NULL,NULL,true,NULL); - } - else - SendCastResult(SPELL_FAILED_FIZZLE); - return; - } - break; - case SPELLFAMILY_PRIEST: - switch(m_spellInfo->Id ) - { - case 28598: // Touch of Weakness triggered spell - { - if(!unitTarget || !m_triggeredByAuraSpell) - return; - - uint32 spellid = 0; - switch(m_triggeredByAuraSpell->Id) - { - case 2652: spellid = 2943; break; // Rank 1 - case 19261: spellid = 19249; break; // Rank 2 - case 19262: spellid = 19251; break; // Rank 3 - case 19264: spellid = 19252; break; // Rank 4 - case 19265: spellid = 19253; break; // Rank 5 - case 19266: spellid = 19254; break; // Rank 6 - case 25461: spellid = 25460; break; // Rank 7 - default: - sLog.outError("Spell::EffectDummy: Spell 28598 triggered by unhandeled spell %u",m_triggeredByAuraSpell->Id); - return; - } - m_caster->CastSpell(unitTarget, spellid, true, NULL); - return; - } - } - break; - case SPELLFAMILY_DRUID: - switch(m_spellInfo->Id ) - { - case 5420: // Tree of Life passive - { - // Tree of Life area effect - int32 health_mod = int32(m_caster->GetStat(STAT_SPIRIT)/4); - m_caster->CastCustomSpell(m_caster,34123,&health_mod,NULL,NULL,true,NULL); - return; - } - } - break; - case SPELLFAMILY_ROGUE: - switch(m_spellInfo->Id ) - { - case 31231: // Cheat Death - { - m_caster->CastSpell(m_caster,45182,true); - return; - } - case 5938: // Shiv - { - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player *pCaster = ((Player*)m_caster); - - Item *item = pCaster->GetWeaponForAttack(OFF_ATTACK); - if(!item) - return; - - // all poison enchantments is temporary - uint32 enchant_id = item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT); - if(!enchant_id) - return; - - SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if(!pEnchant) - return; - - for (int s=0;s<3;s++) - { - if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL) - continue; - - SpellEntry const* combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]); - if(!combatEntry || combatEntry->Dispel != DISPEL_POISON) - continue; - - m_caster->CastSpell(unitTarget, combatEntry, true, item); - } - - m_caster->CastSpell(unitTarget, 5940, true); - return; - } - } - break; - case SPELLFAMILY_HUNTER: - // Steady Shot - if(m_spellInfo->SpellFamilyFlags & 0x100000000LL) - { - if( !unitTarget || !unitTarget->isAlive()) - return; - - bool found = false; - - // check dazed affect - Unit::AuraList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED); - for(Unit::AuraList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter) - { - if((*iter)->GetSpellProto()->SpellIconID==15 && (*iter)->GetSpellProto()->Dispel==0) - { - found = true; - break; - } - } - - if(found) - m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true); - return; - } - // Kill command - if(m_spellInfo->SpellFamilyFlags & 0x00080000000000LL) - { - if(m_caster->getClass()!=CLASS_HUNTER) - return; - - // clear hunter crit aura state - m_caster->ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE,false); - - // additional damage from pet to pet target - Pet* pet = m_caster->GetPet(); - if(!pet || !pet->getVictim()) - return; - - uint32 spell_id = 0; - switch (m_spellInfo->Id) - { - case 34026: spell_id = 34027; break; // rank 1 - default: - sLog.outError("Spell::EffectDummy: Spell %u not handled in KC",m_spellInfo->Id); - return; - } - - pet->CastSpell(pet->getVictim(), spell_id, true); - return; - } - - switch(m_spellInfo->Id) - { - case 23989: //Readiness talent - { - if(m_caster->GetTypeId()!=TYPEID_PLAYER) - return; - - //immediately finishes the cooldown for hunter abilities - const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) - { - uint32 classspell = itr->first; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell); - - if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 ) - { - ((Player*)m_caster)->RemoveSpellCooldown(classspell); - - WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); - data << uint32(classspell); - data << uint64(m_caster->GetGUID()); - ((Player*)m_caster)->GetSession()->SendPacket(&data); - } - } - 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(); - ((Player*)m_caster)->SendAttackSwingCancelAttack(); - return; - } - } - break; - case SPELLFAMILY_PALADIN: - 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; - 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; - } - case 561: // Judgement of command - { - if(!unitTarget) - return; - - uint32 spell_id = m_currentBasePoints[i]+1; - SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id); - if(!spell_proto) - return; - - if( !unitTarget->hasUnitState(UNIT_STAT_STUNDED) && m_caster->GetTypeId()==TYPEID_PLAYER) - { - // decreased damage (/2) for non-stunned target. - SpellModifier *mod = new SpellModifier; - mod->op = SPELLMOD_DAMAGE; - mod->value = -50; - mod->type = SPELLMOD_PCT; - mod->spellId = m_spellInfo->Id; - mod->effectId = i; - mod->lastAffected = NULL; - mod->mask = 0x0000020000000000LL; - mod->charges = 0; - - ((Player*)m_caster)->AddSpellMod(mod, true); - m_caster->CastSpell(unitTarget,spell_proto,true,NULL); - // mod deleted - ((Player*)m_caster)->AddSpellMod(mod, false); - } - else - m_caster->CastSpell(unitTarget,spell_proto,true,NULL); - - return; - } - } - - switch(m_spellInfo->Id) - { - case 31789: // Righteous Defense (step 1) - { - // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target) - - // non-standard cast requirement check - if (!unitTarget || unitTarget->getAttackers().empty()) - { - // clear cooldown at fail - if(m_caster->GetTypeId()==TYPEID_PLAYER) - { - ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id); - - WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); - data << uint32(m_spellInfo->Id); - data << uint64(m_caster->GetGUID()); - ((Player*)m_caster)->GetSession()->SendPacket(&data); - } - - SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT); - return; - } - - // Righteous Defense (step 2) (in old version 31980 dummy effect) - // Clear targets for eff 1 - for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) - ihit->effectMask &= ~(1<<1); - - // not empty (checked) - Unit::AttackerSet const& attackers = unitTarget->getAttackers(); - - // chance to be selected from list - float chance = 100.0f/attackers.size(); - uint32 count=0; - for(Unit::AttackerSet::const_iterator aItr = attackers.begin(); aItr != attackers.end() && count < 3; ++aItr) - { - if(!roll_chance_f(chance)) - continue; - ++count; - AddUnitTarget((*aItr), 1); - } - - // 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: - //Shaman Rockbiter Weapon - if (m_spellInfo->SpellFamilyFlags == 0x400000) - { - uint32 spell_id = 0; - switch(m_spellInfo->Id) - { - case 8017: spell_id = 36494; break; // Rank 1 - case 8018: spell_id = 36750; break; // Rank 2 - case 8019: spell_id = 36755; break; // Rank 3 - case 10399: spell_id = 36759; break; // Rank 4 - case 16314: spell_id = 36763; break; // Rank 5 - case 16315: spell_id = 36766; break; // Rank 6 - case 16316: spell_id = 36771; break; // Rank 7 - case 25479: spell_id = 36775; break; // Rank 8 - case 25485: spell_id = 36499; break; // Rank 9 - default: - sLog.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo->Id); - return; - } - - SpellEntry const *spellInfo = sSpellStore.LookupEntry( spell_id ); - - if(!spellInfo) - { - sLog.outError("WORLD: unknown spell id %i\n", spell_id); - return; - } - - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - for(int i = BASE_ATTACK; i <= OFF_ATTACK; ++i) - { - if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(i))) - { - if(item->IsFitToSpellRequirements(m_spellInfo)) - { - Spell *spell = new Spell(m_caster, spellInfo, true); - - // enchanting spell selected by calculated damage-per-sec in enchanting effect - // at calculation applied affect from Elemental Weapons talent - // real enchantment damage-1 - spell->m_currentBasePoints[1] = damage-1; - - SpellCastTargets targets; - targets.setItemTarget( item ); - spell->prepare(&targets); - } - } - } - return; - } - - if(m_spellInfo->Id == 39610) // Mana-Tide Totem effect - { - if(!unitTarget || unitTarget->getPowerType() != POWER_MANA) - return; - - // 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; - } - - break; - } - - // pet auras - if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id)) - { - m_caster->AddPetAura(petSpell); - return; - } -} - -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\n", m_spellInfo->Id,triggered_spell_id); - return; - } - - int32 bp = damage; - m_caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true,NULL,NULL,m_originalCasterGUID); -} - -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(); - Spell *spell = new Spell(m_caster, spellInfo, true); - - SpellCastTargets targets; - targets.setUnitTarget( unitTarget); - spell->prepare(&targets); - - m_caster->SetCurrentCastedSpell(spell); - spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]); - -} - -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; - } - - unitTarget->CastSpell(unitTarget,spellInfo,true,NULL,NULL,m_originalCasterGUID); -} - -void Spell::EffectTriggerSpell(uint32 i) -{ - uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i]; - - // special cases - switch(triggered_spell_id) - { - // Vanish - case 18461: - { - m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT); - m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED); - m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED); - - // if this spell is given to NPC it must handle rest by it's own AI - if ( m_caster->GetTypeId() != TYPEID_PLAYER ) - return; - - // get highest rank of the Stealth spell - uint32 spellId = 0; - const PlayerSpellMap& sp_list = ((Player*)m_caster)->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; - - SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); - if (!spellInfo) - continue; - - if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_STEALTH) - { - spellId = spellInfo->Id; - break; - } - } - - // no Stealth spell found - if (!spellId) - return; - - // reset cooldown on it if needed - if(((Player*)m_caster)->HasSpellCooldown(spellId)) - ((Player*)m_caster)->RemoveSpellCooldown(spellId); - - m_caster->CastSpell(m_caster, spellId, true); - return; - } - // 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: - { - const SpellEntry *spell = sSpellStore.LookupEntry(24575); - if (!spell) - return; - - for (int i=0; i < spell->StackAmount; ++i) - m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID); - return; - } - // Mercurial Shield - (need add max stack of 26464 Mercurial Shield) - case 29286: - { - const SpellEntry *spell = sSpellStore.LookupEntry(26464); - if (!spell) - return; - - for (int i=0; i < spell->StackAmount; ++i) - m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID); - return; - } - // Righteous Defense - case 31980: - { - m_caster->CastSpell(unitTarget, 31790, true,m_CastItem,NULL,m_originalCasterGUID); - return; - } - // Cloak of Shadows - case 35729 : - { - Unit::AuraMap& Auras = m_caster->GetAuras(); - for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter) - { - // remove all harmful spells on you... - if( // ignore positive and passive auras - !iter->second->IsPositive() && !iter->second->IsPassive() && - // ignore physical auras - (GetSpellSchoolMask(iter->second->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)==0 && - // ignore immunity persistent spells - !( iter->second->GetSpellProto()->AttributesEx & 0x10000 ) ) - { - m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id); - iter = Auras.begin(); - } - } - return; - } - // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet - case 41967: - { - if (Unit *pet = m_caster->GetPet()) - pet->CastSpell(pet, 28305, true); - return; - } - } - - // 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; - } - - // some triggered spells require specific equipment - if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER) - { - // main hand weapon required - if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND) - { - Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK); - - // skip spell if no weapon in slot or broken - if(!item || item->IsBroken() ) - return; - - // skip spell if weapon not fit to triggered spell - if(!item->IsFitToSpellRequirements(spellInfo)) - return; - } - - // offhand hand weapon required - if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND) - { - Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK); - - // skip spell if no weapon in slot or broken - if(!item || item->IsBroken() ) - return; - - // skip spell if weapon not fit to triggered spell - if(!item->IsFitToSpellRequirements(spellInfo)) - return; - } - } - - // some triggered spells must be casted instantly (for example, if next effect case instant kill caster) - bool instant = false; - for(uint32 j = i+1; j < 3; ++j) - { - if(m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL && m_spellInfo->EffectImplicitTargetA[j]==TARGET_SELF) - { - instant = true; - break; - } - } - - if(instant) - { - if (unitTarget) - m_caster->CastSpell(unitTarget,spellInfo,true,m_CastItem,NULL,m_originalCasterGUID); - } - else - m_TriggerSpells.push_back(spellInfo); -} - -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: triggering unknown spell id %effect_idx", m_spellInfo->Id,triggered_spell_id); - return; - } - - if (m_CastItem) - DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id); - - Spell *spell = new Spell(m_caster, spellInfo, true, m_originalCasterGUID ); - - SpellCastTargets targets; - targets.setDestination(m_targets.m_destX,m_targets.m_destY,m_targets.m_destZ); - spell->m_CastItem = m_CastItem; - spell->prepare(&targets, NULL); -} - -void Spell::EffectTeleportUnits(uint32 i) -{ - if(!unitTarget || unitTarget->isInFlight()) - return; - - switch (m_spellInfo->EffectImplicitTargetB[i]) - { - case TARGET_INNKEEPER_COORDINATES: - { - // Only players can teleport to innkeeper - if (unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - ((Player*)unitTarget)->TeleportTo(((Player*)unitTarget)->m_homebindMapId,((Player*)unitTarget)->m_homebindX,((Player*)unitTarget)->m_homebindY,((Player*)unitTarget)->m_homebindZ,unitTarget->GetOrientation(),unitTarget==m_caster ? TELE_TO_SPELL : 0); - return; - } - case TARGET_TABLE_X_Y_Z_COORDINATES: - { - // TODO: Only players can teleport? - if (unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id); - if(!st) - { - sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u\n", m_spellInfo->Id ); - return; - } - ((Player*)unitTarget)->TeleportTo(st->target_mapId,st->target_X,st->target_Y,st->target_Z,st->target_Orientation,unitTarget==m_caster ? TELE_TO_SPELL : 0); - break; - } - case TARGET_BEHIND_VICTIM: - { - // Get selected target for player (or victim for units) - Unit *pTarget = NULL; - if(m_caster->GetTypeId() == TYPEID_PLAYER) - pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection()); - else - pTarget = m_caster->getVictim(); - // No target present - return - if (!pTarget) - return; - // Init dest coordinates - uint32 mapid = m_caster->GetMapId(); - float x = m_targets.m_destX; - float y = m_targets.m_destY; - float z = m_targets.m_destZ; - float orientation = pTarget->GetOrientation(); - // Teleport - if(unitTarget->GetTypeId() == TYPEID_PLAYER) - ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0)); - else - { - MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation); - WorldPacket data; - unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation); - unitTarget->SendMessageToSet(&data, false); - } - return; - } - default: - { - // If not exist data for dest location - return - if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)) - { - sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u\n", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id ); - return; - } - // Init dest coordinates - uint32 mapid = m_caster->GetMapId(); - float x = m_targets.m_destX; - float y = m_targets.m_destY; - float z = m_targets.m_destZ; - float orientation = unitTarget->GetOrientation(); - // Teleport - if(unitTarget->GetTypeId() == TYPEID_PLAYER) - ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0)); - else - { - MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation); - WorldPacket data; - unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation); - unitTarget->SendMessageToSet(&data, false); - } - return; - } - } - - // post effects for TARGET_TABLE_X_Y_Z_COORDINATES - 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 (((Player*)m_caster)->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 (((Player*)m_caster)->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(!unitTarget) - return; - - SpellImmuneList const& list = unitTarget->m_spellImmune[IMMUNITY_STATE]; - for(SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr) - if(itr->type == m_spellInfo->EffectApplyAuraName[i]) - return; - - // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load) - if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 && - (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) ) - return; - - Unit* caster = m_originalCasterGUID ? m_originalCaster : m_caster; - if(!caster) - return; - - sLog.outDebug("Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[i]); - - Aura* Aur = CreateAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, caster, m_CastItem); - - // Now Reduce spell duration using data received at spell hit - int32 duration = Aur->GetAuraMaxDuration(); - unitTarget->ApplyDiminishingToDuration(m_diminishGroup,duration,m_caster,m_diminishLevel); - Aur->setDiminishGroup(m_diminishGroup); - - // if Aura removed and deleted, do not continue. - if(duration== 0 && !(Aur->IsPermanent())) - { - delete Aur; - return; - } - - if(duration != Aur->GetAuraMaxDuration()) - { - Aur->SetAuraMaxDuration(duration); - Aur->SetAuraDuration(duration); - } - - bool added = unitTarget->AddAura(Aur); - - // Aura not added and deleted in AddAura call; - if (!added) - return; - - // found crash at character loading, broken pointer to Aur... - // Aur was deleted in AddAura()... - if(!Aur) - return; - - // TODO Make a way so it works for every related spell! - if(unitTarget->GetTypeId()==TYPEID_PLAYER) // Negative buff should only be applied on players - { - uint32 spellId = 0; - if(m_spellInfo->CasterAuraStateNot==AURA_STATE_WEAKENED_SOUL || m_spellInfo->TargetAuraStateNot==AURA_STATE_WEAKENED_SOUL) - spellId = 6788; // Weakened Soul - else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_FORBEARANCE || m_spellInfo->TargetAuraStateNot==AURA_STATE_FORBEARANCE) - spellId = 25771; // Forbearance - else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_HYPOTHERMIA) - spellId = 41425; // Hypothermia - else if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages - spellId = 11196; // Recently Bandaged - else if( (m_spellInfo->AttributesEx & 0x20) && (m_spellInfo->AttributesEx2 & 0x20000) ) - spellId = 23230; // Blood Fury - Healing Reduction - - SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(spellId); - if (AdditionalSpellInfo) - { - // applied at target by target - Aura* AdditionalAura = CreateAura(AdditionalSpellInfo, 0, &m_currentBasePoints[0], unitTarget,unitTarget, 0); - unitTarget->AddAura(AdditionalAura); - sLog.outDebug("Spell: Additional Aura is: %u", AdditionalSpellInfo->EffectApplyAuraName[0]); - } - } - - // Prayer of Mending (jump animation), we need formal caster instead original for correct animation - if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL)) - m_caster->CastSpell(unitTarget,41637,true,NULL,Aur); -} - -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 have 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 && unitTarget->GetTypeId() == TYPEID_PLAYER ) - power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power); - - int32 new_damage; - if(curPower < power) - new_damage = curPower; - else - new_damage = power; - - unitTarget->ModifyPower(drain_power,-new_damage); - - if(drain_power == POWER_MANA) - { - 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->ModifyPower(POWER_MANA,gain); - //send log - m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id,gain,POWER_MANA,false); - } -} - -void Spell::EffectSendEvent(uint32 EffectIndex) -{ - if (m_caster->GetTypeId() == TYPEID_PLAYER && ((Player*)m_caster)->InBattleGround()) - { - BattleGround* bg = ((Player *)m_caster)->GetBattleGround(); - if(bg && bg->GetStatus() == STATUS_IN_PROGRESS) - { - switch(m_spellInfo->Id) - { - case 23333: // Pickup Horde Flag - /*do not uncomment . - if(bg->GetTypeID()==BATTLEGROUND_WS) - bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget); - sLog.outDebug("Send Event Horde Flag Picked Up"); - break; - /* not used : - case 23334: // Drop Horde Flag - if(bg->GetTypeID()==BATTLEGROUND_WS) - bg->EventPlayerDroppedFlag((Player*)m_caster); - sLog.outDebug("Drop Horde Flag"); - break; - */ - case 23335: // Pickup Alliance Flag - /*do not uncomment ... (it will cause crash, because of null targetobject!) anyway this is a bad way to call that event, because it would cause recursion - if(bg->GetTypeID()==BATTLEGROUND_WS) - bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget); - sLog.outDebug("Send Event Alliance Flag Picked Up"); - break; - /* not used : - case 23336: // Drop Alliance Flag - if(bg->GetTypeID()==BATTLEGROUND_WS) - bg->EventPlayerDroppedFlag((Player*)m_caster); - sLog.outDebug("Drop Alliance Flag"); - break; - case 23385: // Alliance Flag Returns - if(bg->GetTypeID()==BATTLEGROUND_WS) - bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget); - sLog.outDebug("Alliance Flag Returned"); - break; - case 23386: // Horde Flag Returns - if(bg->GetTypeID()==BATTLEGROUND_WS) - bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget); - sLog.outDebug("Horde Flag Returned"); - break;*/ - case 34976: - /* - if(bg->GetTypeID()==BATTLEGROUND_EY) - bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget); - */ - break; - default: - sLog.outDebug("Unknown spellid %u in BG event", m_spellInfo->Id); - break; - } - } - } - sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id); - sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject); -} - -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; - - int32 curPower = int32(unitTarget->GetPower(powertype)); - - // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) - uint32 power = damage; - if ( powertype == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER ) - power -= ((Player*)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_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true); -} - -void Spell::EffectHeal( 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; - Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i) - if((*i)->GetId() == 45062) - damageAmount+=(*i)->GetModifier()->m_amount; - if (damageAmount) - m_caster->RemoveAurasDueToSpell(45062); - - addhealth += damageAmount; - } - // Swiftmend - consumes Regrowth or Rejuvenation - else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND)) - { - Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL); - // find most short by duration - Aura *targetAura = NULL; - for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i) - { - if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID - && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) ) - { - if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration()) - targetAura = *i; - } - } - - if(!targetAura) - { - sLog.outError("Target(GUID:" I64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID()); - return; - } - int idx = 0; - while(idx < 3) - { - if(targetAura->GetSpellProto()->EffectApplyAuraName[idx] == SPELL_AURA_PERIODIC_HEAL) - break; - idx++; - } - - int32 tickheal = caster->SpellHealingBonus(targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT, unitTarget); - int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx]; - unitTarget->RemoveAurasDueToSpell(targetAura->GetId()); - - addhealth += tickheal * tickcount; - } - else - addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget); - - bool crit = caster->isSpellCrit(unitTarget, m_spellInfo, m_spellSchoolMask, m_attackType); - if (crit) - addhealth = caster->SpellCriticalBonus(m_spellInfo, addhealth, unitTarget); - caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, crit); - - int32 gain = unitTarget->ModifyHealth( int32(addhealth) ); - unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo); - - if(caster->GetTypeId()==TYPEID_PLAYER) - if(BattleGround *bg = ((Player*)caster)->GetBattleGround()) - bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain); - - // ignore item heals - if(m_CastItem) - return; - - uint32 procHealer = PROC_FLAG_HEAL; - if (crit) - procHealer |= PROC_FLAG_CRIT_HEAL; - - m_caster->ProcDamageAndSpell(unitTarget,procHealer,PROC_FLAG_HEALED,addhealth,SPELL_SCHOOL_MASK_NONE,m_spellInfo,m_IsTriggeredSpell); - } -} - -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; - - uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100; - caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false); - - int32 gain = unitTarget->ModifyHealth( int32(addhealth) ); - unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo); - - if(caster->GetTypeId()==TYPEID_PLAYER) - if(BattleGround *bg = ((Player*)caster)->GetBattleGround()) - bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain); - } -} - -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(m_spellInfo, uint32(damage), HEAL, unitTarget); - caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false); - unitTarget->ModifyHealth( int32(damage) ); - } -} - -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); - - int32 new_damage = int32(damage*multiplier); - uint32 curHealth = unitTarget->GetHealth(); - new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true); - if(curHealth < new_damage) - new_damage = curHealth; - - if(m_caster->isAlive()) - { - new_damage = m_caster->SpellHealingBonus(m_spellInfo, new_damage, HEAL, m_caster); - - m_caster->ModifyHealth(new_damage); - - if(m_caster->GetTypeId() == TYPEID_PLAYER) - m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(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; - } - - uint32 num_to_add; - - // TODO: maybe all this can be replaced by using correct calculated `damage` value - if(pProto->Class != ITEM_CLASS_CONSUMABLE || m_spellInfo->SpellFamilyName != SPELLFAMILY_MAGE) - { - int32 basePoints = m_currentBasePoints[i]; - int32 randomPoints = m_spellInfo->EffectDieSides[i]; - if (randomPoints) - num_to_add = basePoints + irand(1, randomPoints); - else - num_to_add = basePoints + 1; - } - else if (pProto->MaxCount == 1) - num_to_add = 1; - else if(player->getLevel() >= m_spellInfo->spellLevel) - { - int32 basePoints = m_currentBasePoints[i]; - float pointPerLevel = m_spellInfo->EffectRealPointsPerLevel[i]; - num_to_add = basePoints + 1 + uint32((player->getLevel() - m_spellInfo->spellLevel)*pointPerLevel); - } - else - num_to_add = 2; - - if (num_to_add < 1) - num_to_add = 1; - if (num_to_add > pProto->Stackable) - num_to_add = pProto->Stackable; - - // 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) - pItem->SetUInt32Value(ITEM_FIELD_CREATOR,player->GetGUIDLow()); - - // send info to the client - if(pItem) - player->SendNewItem(pItem, num_to_add, true, true); - - // we succeeded in creating at least one item, so a levelup is possible - player->UpdateCraftSkill(m_spellInfo->Id); - } - - // for battleground marks send by mail if not add all expected - if(no_space > 0 ) - { - BattleGroundTypeId bgType; - 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: - return; - } - - if(BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgType)) - bg->SendRewardMarkByMail(player,newitemid,no_space); - } -} - -void Spell::EffectCreateItem(uint32 i) -{ - DoCreateItem(i,m_spellInfo->EffectItemType[i]); -} - -void Spell::EffectPersistentAA(uint32 i) -{ - float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - - if(Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius); - - int32 duration = GetSpellDuration(m_spellInfo); - DynamicObject* dynObj = new DynamicObject; - if(!dynObj->Create(objmgr.GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, i, m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, duration, radius)) - { - delete dynObj; - return; - } - dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65); - dynObj->SetUInt32Value(GAMEOBJECT_DISPLAYID, 368003); - dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x01eeeeee); - m_caster->AddDynObject(dynObj); - MapManager::Instance().GetMap(dynObj->GetMapId(), dynObj)->Add(dynObj); -} - -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; - - // Some level depends spells - int multipler = 0; - int level_diff = 0; - switch (m_spellInfo->Id) - { - // Restore Energy - case 9512: - level_diff = m_caster->getLevel() - 40; - multipler = 2; - break; - // Blood Fury - case 24571: - level_diff = m_caster->getLevel() - 60; - multipler = 10; - break; - // Burst of Energy - case 24532: - level_diff = m_caster->getLevel() - 60; - multipler = 4; - break; - default: - break; - } - - if (level_diff > 0) - damage -= multipler * level_diff; - - if(damage < 0) - return; - - Powers power = Powers(m_spellInfo->EffectMiscValue[i]); - - if(unitTarget->GetMaxPower(power) == 0) - return; - - unitTarget->ModifyPower(power,damage); - m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power); - - // Mad Alchemist's Potion - if (m_spellInfo->Id == 45051) - { - // find elixirs on target - uint32 elixir_mask = 0; - Unit::AuraMap& Auras = unitTarget->GetAuras(); - for(Unit::AuraMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr) - { - uint32 spell_id = itr->second->GetId(); - if(uint32 mask = spellmgr.GetSpellElixirMask(spell_id)) - elixir_mask |= mask; - } - - // get available elixir mask any not active type from battle/guardian (and flask if no any) - elixir_mask = (elixir_mask & ELIXIR_FLASK_MASK) ^ ELIXIR_FLASK_MASK; - - // get all available elixirs by mask and spell level - std::vector<uint32> elixirs; - SpellElixirMap const& m_spellElixirs = spellmgr.GetSpellElixirMap(); - for(SpellElixirMap::const_iterator itr = m_spellElixirs.begin(); itr != m_spellElixirs.end(); ++itr) - { - if (itr->second & elixir_mask) - { - if (itr->second & (ELIXIR_UNSTABLE_MASK | ELIXIR_SHATTRATH_MASK)) - continue; - - SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); - if (spellInfo && (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel())) - continue; - - elixirs.push_back(itr->first); - } - } - - if (!elixirs.empty()) - { - // cast random elixir on target - uint32 rand_spell = urand(0,elixirs.size()-1); - m_caster->CastSpell(unitTarget,elixirs[rand_spell],true,m_CastItem); - } - } -} - -void Spell::EffectEnergisePct(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; - unitTarget->ModifyPower(power, gain); - m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power); -} - -void Spell::SendLoot(uint64 guid, LootType loottype) -{ - Player* player = (Player*)m_caster; - if (!player) - return; - - if (gameObjTarget) - { - switch (gameObjTarget->GetGoType()) - { - case GAMEOBJECT_TYPE_DOOR: - case GAMEOBJECT_TYPE_BUTTON: - gameObjTarget->UseDoorOrButton(); - sWorld.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: - // goober_scripts can be triggered if the player don't have the quest - if (gameObjTarget->GetGOInfo()->goober.eventId) - { - sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow()); - sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget); - } - - // cast goober spell - if (gameObjTarget->GetGOInfo()->goober.questId) - ///Quest require to be active for GO using - if(player->GetQuestStatus(gameObjTarget->GetGOInfo()->goober.questId) != QUEST_STATUS_INCOMPLETE) - return; - - gameObjTarget->AddUniqueUse(player); - gameObjTarget->SetLootState(GO_JUST_DEACTIVATED); - - //TODO? Objective counting called without spell check but with quest objective check - // if send spell id then this line will duplicate to spell casting call (double counting) - // So we or have this line and not required in quest_template have reqSpellIdN - // or must remove this line and required in DB have data in quest_template have reqSpellIdN for all quest using cases. - player->CastedCreatureOrGO(gameObjTarget->GetEntry(), gameObjTarget->GetGUID(), 0); - - // triggering linked GO - if(uint32 trapEntry = gameObjTarget->GetGOInfo()->goober.linkedTrapId) - gameObjTarget->TriggeringLinkedGameObject(trapEntry,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()); - sWorld.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 - } - } - - // Send loot - player->SendLoot(guid, loottype); -} - -void Spell::EffectOpenLock(uint32 /*i*/) -{ - if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER) - { - sLog.outDebug( "WORLD: Open Lock - No Player Caster!"); - return; - } - - Player* player = (Player*)m_caster; - - LootType loottype = LOOT_CORPSE; - 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 ) - { - if(BattleGround *bg = player->GetBattleGround())// in battleground - { - if( !player->IsMounted() && // not mounted - !player->HasStealthAura() && // not stealthed - !player->HasInvisibilityAura() && // not invisible - player->isAlive() ) // live player - { - // check if it's correct bg - if(bg && bg->GetTypeID() == BATTLEGROUND_AB) - bg->EventPlayerClickedOnFlag(player, gameObjTarget); - - return; - } - } - } - else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND) - { - if(BattleGround *bg = player->GetBattleGround()) - if(bg->GetTypeID() == BATTLEGROUND_EY) - bg->EventPlayerClickedOnFlag(player, gameObjTarget); - return; - } - lockId = gameObjTarget->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; - } - - if(!lockId) // possible case for GO and maybe for items. - { - SendLoot(guid, loottype); - return; - } - - // Get LockInfo - LockEntry const *lockInfo = sLockStore.LookupEntry(lockId); - - if (!lockInfo) - { - sLog.outError( "Spell::EffectOpenLock: %s [guid = %u] has an unknown lockId: %u!", - (gameObjTarget ? "gameobject" : "item"), GUID_LOPART(guid), lockId); - SendCastResult(SPELL_FAILED_BAD_TARGETS); - return; - } - - // check key - for(int i = 0; i < 5; ++i) - { - // type==1 This means lockInfo->key[i] is an item - if(lockInfo->keytype[i]==LOCK_KEY_ITEM && lockInfo->key[i] && m_CastItem && m_CastItem->GetEntry()==lockInfo->key[i]) - { - SendLoot(guid, loottype); - return; - } - } - - uint32 SkillId = 0; - // Check and skill-up skill - if( m_spellInfo->Effect[1] == SPELL_EFFECT_SKILL ) - SkillId = m_spellInfo->EffectMiscValue[1]; - // pickpocketing spells - else if( m_spellInfo->EffectMiscValue[0] == LOCKTYPE_PICKLOCK ) - SkillId = SKILL_LOCKPICKING; - - // skill bonus provided by casting spell (mostly item spells) - uint32 spellSkillBonus = uint32(m_currentBasePoints[0]+1); - - uint32 reqSkillValue = lockInfo->requiredminingskill; - - if(lockInfo->requiredlockskill) // required pick lock skill applying - { - if(SkillId != SKILL_LOCKPICKING) // wrong skill (cheating?) - { - SendCastResult(SPELL_FAILED_FIZZLE); - return; - } - - reqSkillValue = lockInfo->requiredlockskill; - } - else if(SkillId == SKILL_LOCKPICKING) // apply picklock skill to wrong target - { - SendCastResult(SPELL_FAILED_BAD_TARGETS); - return; - } - - if ( SkillId ) - { - loottype = LOOT_SKINNING; - if ( player->GetSkillValue(SkillId) + spellSkillBonus < reqSkillValue ) - { - SendCastResult(SPELL_FAILED_LOW_CASTLEVEL); - return; - } - - // update skill if really known - uint32 SkillValue = player->GetPureSkillValue(SkillId); - if(SkillValue) // non only item base skill - { - if(gameObjTarget) - { - // Allow one skill-up until respawned - if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) && - player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue) ) - gameObjTarget->AddToSkillupList( player->GetGUIDLow() ); - } - else if(itemTarget) - { - // Do one skill-up - uint32 SkillValue = player->GetPureSkillValue(SkillId); - player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue); - } - } - } - - SendLoot(guid, loottype); -} - -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 i= PERM_ENCHANTMENT_SLOT; i<=TEMP_ENCHANTMENT_SLOT; ++i) - { - if(m_CastItem->GetEnchantmentId(EnchantmentSlot(i))) - pNewItem->SetEnchantment(EnchantmentSlot(i), m_CastItem->GetEnchantmentId(EnchantmentSlot(i)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(i)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(i))); - } - - 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; - uint8 msg = player->CanEquipItem( 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->EquipItem( dest, pNewItem, true); - player->AutoUnequipOffhandIfNeed(); - return; - } - } - - // fail - delete pNewItem; -} - -void Spell::EffectOpenSecretSafe(uint32 i) -{ - EffectOpenLock(i); //no difference for now -} - -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 == 2 && !(p_target->GetWeaponProficiency() & subClassMask)) - { - p_target->AddWeaponProficiency(subClassMask); - p_target->SendProficiency(uint8(0x02),p_target->GetWeaponProficiency()); - } - if(m_spellInfo->EquippedItemClass == 4 && !(p_target->GetArmorProficiency() & subClassMask)) - { - p_target->AddArmorProficiency(subClassMask); - p_target->SendProficiency(uint8(0x04),p_target->GetArmorProficiency()); - } -} - -void Spell::EffectApplyAreaAura(uint32 i) -{ - if(!unitTarget) - return; - if(!unitTarget->isAlive()) - return; - - AreaAura* Aur = new AreaAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, m_caster, m_CastItem); - unitTarget->AddAura(Aur); -} - -void Spell::EffectSummonType(uint32 i) -{ - switch(m_spellInfo->EffectMiscValueB[i]) - { - case SUMMON_TYPE_GUARDIAN: - case SUMMON_TYPE_POSESSED: - case SUMMON_TYPE_POSESSED2: - EffectSummonGuardian(i); - break; - case SUMMON_TYPE_WILD: - EffectSummonWild(i); - break; - case SUMMON_TYPE_DEMON: - EffectSummonDemon(i); - break; - case SUMMON_TYPE_SUMMON: - EffectSummon(i); - break; - case SUMMON_TYPE_CRITTER: - case SUMMON_TYPE_CRITTER2: - EffectSummonCritter(i); - break; - case SUMMON_TYPE_TOTEM_SLOT1: - case SUMMON_TYPE_TOTEM_SLOT2: - case SUMMON_TYPE_TOTEM_SLOT3: - case SUMMON_TYPE_TOTEM_SLOT4: - case SUMMON_TYPE_TOTEM: - EffectSummonTotem(i); - break; - case SUMMON_TYPE_UNKNOWN1: - case SUMMON_TYPE_UNKNOWN2: - case SUMMON_TYPE_UNKNOWN3: - case SUMMON_TYPE_UNKNOWN4: - case SUMMON_TYPE_UNKNOWN5: - case SUMMON_TYPE_UNKNOWN6: - break; - default: - sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]); - break; - } -} - -void Spell::EffectSummon(uint32 i) -{ - if(m_caster->GetPetGUID()) - return; - - if(!unitTarget) - return; - uint32 pet_entry = m_spellInfo->EffectMiscValue[i]; - if(!pet_entry) - return; - uint32 level = m_caster->getLevel(); - Pet* spawnCreature = new Pet(SUMMON_PET); - - if(spawnCreature->LoadPetFromDB(m_caster,pet_entry)) - { - // set timer for unsummon - int32 duration = GetSpellDuration(m_spellInfo); - if(duration > 0) - spawnCreature->SetDuration(duration); - - return; - } - - Map *map = m_caster->GetMap(); - uint32 pet_number = objmgr.GeneratePetNumber(); - if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),map,m_spellInfo->EffectMiscValue[i], pet_number)) - { - sLog.outErrorDb("Spell::EffectSummon: no such creature entry %u",m_spellInfo->EffectMiscValue[i]); - delete spawnCreature; - return; - } - - // Summon in dest location - float x,y,z; - if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) - { - x = m_targets.m_destX; - y = m_targets.m_destY; - z = m_targets.m_destZ; - } - else - m_caster->GetClosePoint(x,y,z,spawnCreature->GetObjectSize()); - - spawnCreature->Relocate(x,y,z,-m_caster->GetOrientation()); - - if(!spawnCreature->IsPositionValid()) - { - sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY()); - delete spawnCreature; - return; - } - - // set timer for unsummon - int32 duration = GetSpellDuration(m_spellInfo); - if(duration > 0) - spawnCreature->SetDuration(duration); - - spawnCreature->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID()); - spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0); - spawnCreature->setPowerType(POWER_MANA); - spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction()); - spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0); - spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_0,2048); - spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0); - spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0); - spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE,0); - spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP,1000); - spawnCreature->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID()); - spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); - - spawnCreature->InitStatsForLevel(level); - - spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false); - - spawnCreature->AIM_Initialize(); - spawnCreature->InitPetCreateSpells(); - spawnCreature->SetHealth(spawnCreature->GetMaxHealth()); - spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA)); - - std::string name = m_caster->GetName(); - name.append(petTypeSuffix[spawnCreature->getPetType()]); - spawnCreature->SetName( name ); - - map->Add((Creature*)spawnCreature); - - if(m_caster->GetTypeId() == TYPEID_PLAYER) - { - m_caster->SetPet(spawnCreature); - spawnCreature->GetCharmInfo()->SetReactState( REACT_DEFENSIVE ); - spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT); - ((Player*)m_caster)->PetSpellInitialize(); - } -} - -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==SPELL_ID_GENERIC_LEARN) ? damage : m_spellInfo->EffectTriggerSpell[i]; - player->learnSpell(spellToLearn); - - sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() ); -} - -void Spell::EffectDispel(uint32 i) -{ - if(!unitTarget) - return; - - // Fill possible dispell list - std::vector <Aura *> 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->GetAuras(); - for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - { - Aura *aur = (*itr).second; - if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask) - { - if(aur->GetSpellProto()->Dispel == DISPEL_MAGIC) - { - bool positive = true; - if (!aur->IsPositive()) - positive = false; - else - positive = (aur->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)==0; - - // do not remove positive auras if friendly target - // negative auras if non-friendly target - if(positive == unitTarget->IsFriendlyTo(m_caster)) - continue; - } - // Add aura to dispel list - dispel_list.push_back(aur); - } - } - // Ok if exist some buffs for dispel try dispel it - if (!dispel_list.empty()) - { - std::list < std::pair<uint32,uint64> > success_list;// (spell_id,casterGuid) - std::list < uint32 > fail_list; // spell_id - int32 list_size = dispel_list.size(); - // Dispell N = damage buffs (or while exist buffs for dispel) - for (int32 count=0; count < damage && list_size > 0; ++count) - { - // Random select buff for dispel - Aura *aur = dispel_list[urand(0, list_size-1)]; - - SpellEntry const* spellInfo = aur->GetSpellProto(); - // Base dispel chance - // TODO: possible chance depend from spell level?? - int32 miss_chance = 0; - // Apply dispel mod from aura caster - if (Unit *caster = aur->GetCaster()) - { - if ( Player* modOwner = caster->GetSpellModOwner() ) - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this); - } - // Try dispel - if (roll_chance_i(miss_chance)) - fail_list.push_back(aur->GetId()); - else - success_list.push_back(std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID())); - // Remove buff from list for prevent doubles - for (std::vector<Aura *>::iterator j = dispel_list.begin(); j != dispel_list.end(); ) - { - Aura *dispeled = *j; - if (dispeled->GetId() == aur->GetId() && dispeled->GetCasterGUID() == aur->GetCasterGUID()) - { - j = dispel_list.erase(j); - --list_size; - } - else - ++j; - } - } - // Send success log and really remove auras - if (!success_list.empty()) - { - int32 count = success_list.size(); - WorldPacket data(SMSG_SPELLDISPELLOG, 8+8+4+1+4+count*5); - data.append(unitTarget->GetPackGUID()); // Victim GUID - data.append(m_caster->GetPackGUID()); // Caster GUID - data << uint32(m_spellInfo->Id); // Dispell spell id - data << uint8(0); // not used - data << uint32(count); // count - for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j) - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first); - data << uint32(spellInfo->Id); // Spell Id - data << uint8(0); // 0 - dispeled !=0 cleansed - unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster); - } - m_caster->SendMessageToSet(&data, true); - - // On succes dispel - // Devour Magic - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == 12) - { - uint32 heal_spell = 0; - switch (m_spellInfo->Id) - { - case 19505: heal_spell = 19658; break; - case 19731: heal_spell = 19732; break; - case 19734: heal_spell = 19733; break; - case 19736: heal_spell = 19735; break; - case 27276: heal_spell = 27278; break; - case 27277: heal_spell = 27279; break; - default: - sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id); - break; - } - if (heal_spell) - m_caster->CastSpell(m_caster, heal_spell, true); - } - } - // Send fail log to client - if (!fail_list.empty()) - { - // Failed to dispell - WorldPacket data(SMSG_DISPEL_FAILED, 8+8+4+4*fail_list.size()); - data << uint64(m_caster->GetGUID()); // Caster GUID - data << uint64(unitTarget->GetGUID()); // Victim GUID - data << uint32(m_spellInfo->Id); // Dispell spell id - for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j) - data << uint32(*j); // Spell Id - m_caster->SendMessageToSet(&data, true); - } - } -} - -void Spell::EffectDualWield(uint32 /*i*/) -{ - if (unitTarget->GetTypeId() == TYPEID_PLAYER) - ((Player*)unitTarget)->SetCanDualWield(true); -} - -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_STUNDED | UNIT_STAT_FLEEING ) ) - return; - - float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY); - - if ( unitTarget->GetTypeId() == TYPEID_PLAYER ) - { - // For players just turn them - WorldPacket data; - ((Player*)unitTarget)->BuildTeleportAckMsg(&data, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle); - ((Player*)unitTarget)->GetSession()->SendPacket( &data ); - ((Player*)unitTarget)->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false); - } - else - { - // Set creature Distracted, Stop it, And turn it - unitTarget->SetOrientation(angle); - unitTarget->StopMoving(); - unitTarget->GetMotionMaster()->MoveDistract(damage*1000); - } -} - -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) - { - int32 chance = 10 + int32(m_caster->getLevel()) - int32(unitTarget->getLevel()); - - if (chance > irand(0, 19)) - { - // Stealing successful - //sLog.outDebug("Sending loot from pickpocket"); - ((Player*)m_caster)->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING); - } - else - { - // Reveal action + get attack - m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - if (((Creature*)unitTarget)->AI()) - ((Creature*)unitTarget)->AI()->AttackStart(m_caster); - } - } -} - -void Spell::EffectAddFarsight(uint32 i) -{ - float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - int32 duration = GetSpellDuration(m_spellInfo); - DynamicObject* dynObj = new DynamicObject; - if(!dynObj->Create(objmgr.GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, i, m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, duration, radius)) - { - delete dynObj; - return; - } - dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65); - dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002); - m_caster->AddDynObject(dynObj); - MapManager::Instance().GetMap(dynObj->GetMapId(), dynObj)->Add(dynObj); - m_caster->SetUInt64Value(PLAYER_FARSIGHT, dynObj->GetGUID()); -} - -void Spell::EffectSummonWild(uint32 i) -{ - uint32 creature_entry = m_spellInfo->EffectMiscValue[i]; - if(!creature_entry) - return; - - uint32 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 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING); - if(skill202) - { - level = skill202/5; - } - } - } - - // select center of summon position - float center_x = m_targets.m_destX; - float center_y = m_targets.m_destY; - float center_z = m_targets.m_destZ; - - float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - - int32 amount = damage > 0 ? damage : 1; - - for(int32 count = 0; count < amount; ++count) - { - float px, py, pz; - // If dest location if present - if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) - { - // Summon 1 unit in dest location - if (count == 0) - { - px = m_targets.m_destX; - py = m_targets.m_destY; - pz = m_targets.m_destZ; - } - // Summon in random point all other units if location present - else - m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz); - } - // Summon if dest location not present near caster - else - m_caster->GetClosePoint(px,py,pz,3.0f); - - int32 duration = GetSpellDuration(m_spellInfo); - - TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN; - - m_caster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration); - } -} - -void Spell::EffectSummonGuardian(uint32 i) -{ - uint32 pet_entry = m_spellInfo->EffectMiscValue[i]; - if(!pet_entry) - return; - - // Jewelery statue case (totem like) - if(m_spellInfo->SpellIconID==2056) - { - EffectSummonTotem(i); - return; - } - - // set timer for unsummon - int32 duration = GetSpellDuration(m_spellInfo); - - // Search old Guardian only for players (if casted spell not have duration or cooldown) - // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time - // so this code hack in fact - if( m_caster->GetTypeId() == TYPEID_PLAYER && (duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0) ) - if(((Player*)m_caster)->HasGuardianWithEntry(pet_entry)) - return; // find old guardian, ignore summon - - // in another case summon new - uint32 level = m_caster->getLevel(); - - // level of pet 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 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING); - if(skill202) - { - level = skill202/5; - } - } - } - - // select center of summon position - float center_x = m_targets.m_destX; - float center_y = m_targets.m_destY; - float center_z = m_targets.m_destZ; - - float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - - int32 amount = damage > 0 ? damage : 1; - - for(int32 count = 0; count < amount; ++count) - { - Pet* spawnCreature = new Pet(GUARDIAN_PET); - - Map *map = m_caster->GetMap(); - uint32 pet_number = objmgr.GeneratePetNumber(); - if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map,m_spellInfo->EffectMiscValue[i], pet_number)) - { - sLog.outError("no such creature entry %u",m_spellInfo->EffectMiscValue[i]); - delete spawnCreature; - return; - } - - float px, py, pz; - // If dest location if present - if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) - { - // Summon 1 unit in dest location - if (count == 0) - { - px = m_targets.m_destX; - py = m_targets.m_destY; - pz = m_targets.m_destZ; - } - // Summon in random point all other units if location present - else - m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz); - } - // Summon if dest location not present near caster - else - m_caster->GetClosePoint(px,py,pz,spawnCreature->GetObjectSize()); - - spawnCreature->Relocate(px,py,pz,m_caster->GetOrientation()); - - if(!spawnCreature->IsPositionValid()) - { - sLog.outError("ERROR: Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %d Y: ^%d)", spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY()); - delete spawnCreature; - return; - } - - if(duration > 0) - spawnCreature->SetDuration(duration); - - spawnCreature->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID()); - spawnCreature->setPowerType(POWER_MANA); - spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0); - spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction()); - spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0); - spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0); - spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0); - spawnCreature->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID()); - spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); - - spawnCreature->InitStatsForLevel(level); - spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false); - - spawnCreature->AIM_Initialize(); - - if(m_caster->GetTypeId()==TYPEID_PLAYER) - ((Player*)m_caster)->AddGuardian(spawnCreature); - - map->Add((Creature*)spawnCreature); - } -} - -void Spell::EffectTeleUnitsFaceCaster(uint32 i) -{ - if(!unitTarget) - return; - - if(unitTarget->isInFlight()) - return; - - uint32 mapid = m_caster->GetMapId(); - float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - - float fx,fy,fz; - m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis); - - if(unitTarget->GetTypeId() == TYPEID_PLAYER) - ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, -m_caster->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0)); - else - MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)m_caster, fx, fy, fz, -m_caster->GetOrientation()); -} - -void Spell::EffectLearnSkill(uint32 i) -{ - if(unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - if(damage < 0) - return; - - uint32 skillid = m_spellInfo->EffectMiscValue[i]; - uint16 skillval = ((Player*)unitTarget)->GetPureSkillValue(skillid); - ((Player*)unitTarget)->SetSkill(skillid, skillval?skillval:1, damage*75); -} - -void Spell::EffectAddHonor(uint32 /*i*/) -{ - if(unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - sLog.outDebug("SpellEffect::AddHonor called for spell_id %u , that rewards %d honor points to player: %u", m_spellInfo->Id, this->damage, ((Player*)unitTarget)->GetGUIDLow()); - - // TODO: find formula for honor reward based on player's level! - - // now fixed only for level 70 players: - if (((Player*)unitTarget)->getLevel() == 70) - ((Player*)unitTarget)->RewardHonor(NULL, 1, this->damage); -} - -void Spell::EffectTradeSkill(uint32 /*i*/) -{ - if(unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - // uint32 skillid = m_spellInfo->EffectMiscValue[i]; - // uint16 skillmax = ((Player*)unitTarget)->(skillid); - // ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75); -} - -void Spell::EffectEnchantItemPerm(uint32 i) -{ - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - if (!itemTarget) - return; - - Player* p_caster = (Player*)m_caster; - - p_caster->UpdateCraftSkill(m_spellInfo->Id); - - if (m_spellInfo->EffectMiscValue[i]) - { - uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; - - 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("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::EffectEnchantItemTmp(uint32 i) -{ - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player* p_caster = (Player*)m_caster; - - if(!itemTarget) - return; - - uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; - - // Shaman Rockbiter Weapon - if(i==0 && m_spellInfo->Effect[1]==SPELL_EFFECT_DUMMY) - { - int32 enchnting_damage = m_currentBasePoints[1]+1; - - // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value - // with already applied percent bonus from Elemental Weapons talent - // 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(enchnting_damage) - { - // Rank 1 - case 2: enchant_id = 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2] - // Rank 2 - case 4: enchant_id = 6; break; // 0% [ 7% == 4, 14% == 4] - case 5: enchant_id = 3025; break; // 20% - // Rank 3 - case 6: enchant_id = 1; break; // 0% [ 7% == 6, 14% == 6] - case 7: enchant_id = 3027; break; // 20% - // Rank 4 - case 9: enchant_id = 3032; break; // 0% [ 7% == 6] - case 10: enchant_id = 503; break; // 14% - case 11: enchant_id = 3031; break; // 20% - // Rank 5 - case 15: enchant_id = 3035; break; // 0% - case 16: enchant_id = 1663; break; // 7% - case 17: enchant_id = 3033; break; // 14% - case 18: enchant_id = 3034; break; // 20% - // Rank 6 - case 28: enchant_id = 3038; break; // 0% - case 29: enchant_id = 683; break; // 7% - case 31: enchant_id = 3036; break; // 14% - case 33: enchant_id = 3037; break; // 20% - // Rank 7 - case 40: enchant_id = 3041; break; // 0% - case 42: enchant_id = 1664; break; // 7% - case 45: enchant_id = 3039; break; // 14% - case 48: enchant_id = 3040; break; // 20% - // Rank 8 - case 49: enchant_id = 3044; break; // 0% - case 52: enchant_id = 2632; break; // 7% - case 55: enchant_id = 3042; break; // 14% - case 58: enchant_id = 3043; break; // 20% - // Rank 9 - case 62: enchant_id = 2633; break; // 0% - case 66: enchant_id = 3018; break; // 7% - case 70: enchant_id = 3019; break; // 14% - case 74: enchant_id = 3020; break; // 20% - default: - sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage); - return; - } - } - - 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==215) - duration = 1800; // 30 mins - // some fishing pole bonuses - else if(m_spellInfo->SpellVisual==563) - duration = 600; // 10 mins - // shaman rockbiter enchantments - else if(m_spellInfo->SpellVisual==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("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_PLAYER) - return; - - Creature* creatureTarget = (Creature*)unitTarget; - - if(creatureTarget->isPet()) - return; - - if(m_caster->getClass() == CLASS_HUNTER) - { - // cast finish successfully - //SendChannelUpdate(0); - finish(); - - Pet* pet = new Pet(HUNTER_PET); - - if(!pet->CreateBaseAtCreature(creatureTarget)) - { - delete pet; - return; - } - - creatureTarget->setDeathState(JUST_DIED); - creatureTarget->RemoveCorpse(); - creatureTarget->SetHealth(0); // just for nice GM-mode view - - pet->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_caster->GetGUID()); - pet->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID()); - pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction()); - pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); - - if(!pet->InitStatsForLevel(creatureTarget->getLevel())) - { - sLog.outError("ERROR: InitStatsForLevel() in EffectTameCreature failed! Pet deleted."); - delete pet; - return; - } - - // prepare visual effect for levelup - pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel()-1); - - pet->GetCharmInfo()->SetPetNumber(objmgr.GeneratePetNumber(), true); - // this enables pet details window (Shift+P) - pet->AIM_Initialize(); - pet->InitPetCreateSpells(); - pet->SetHealth(pet->GetMaxHealth()); - - MapManager::Instance().GetMap(pet->GetMapId(), pet)->Add((Creature*)pet); - - // visual effect for levelup - pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel()); - - if(m_caster->GetTypeId() == TYPEID_PLAYER) - { - m_caster->SetPet(pet); - pet->SavePetToDB(PET_SAVE_AS_CURRENT); - ((Player*)m_caster)->PetSpellInitialize(); - } - } -} - -void Spell::EffectSummonPet(uint32 i) -{ - uint32 petentry = m_spellInfo->EffectMiscValue[i]; - - Pet *OldSummon = m_caster->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; - - MapManager::Instance().GetMap(OldSummon->GetMapId(), OldSummon)->Remove((Creature*)OldSummon,false); - OldSummon->SetMapId(m_caster->GetMapId()); - - float px, py, pz; - m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectSize()); - - OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation()); - MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)->Add((Creature*)OldSummon); - - if(m_caster->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled() ) - { - ((Player*)m_caster)->PetSpellInitialize(); - } - return; - } - - if(m_caster->GetTypeId() == TYPEID_PLAYER) - ((Player*)m_caster)->RemovePet(OldSummon,(OldSummon->getPetType()==HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false); - else - return; - } - - Pet* NewSummon = new Pet; - - // petentry==0 for hunter "call pet" (current pet summoned if any) - if(NewSummon->LoadPetFromDB(m_caster,petentry)) - { - if(NewSummon->getPetType()==SUMMON_PET) - { - // Remove Demonic Sacrifice auras (known pet) - Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();) - { - if((*itr)->GetModifier()->m_miscvalue==2228) - { - m_caster->RemoveAurasDueToSpell((*itr)->GetId()); - itr = auraClassScripts.begin(); - } - else - ++itr; - } - } - - return; - } - - // not error in case fail hunter call pet - if(!petentry) - { - delete NewSummon; - return; - } - - CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(petentry); - - if(!cInfo) - { - sLog.outError("EffectSummonPet: creature entry %u not found.",petentry); - delete NewSummon; - return; - } - - Map *map = m_caster->GetMap(); - uint32 pet_number = objmgr.GeneratePetNumber(); - if(!NewSummon->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, petentry, pet_number)) - { - delete NewSummon; - return; - } - - float px, py, pz; - m_caster->GetClosePoint(px, py, pz, NewSummon->GetObjectSize()); - - NewSummon->Relocate(px, py, pz, m_caster->GetOrientation()); - - if(!NewSummon->IsPositionValid()) - { - sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", NewSummon->GetGUIDLow(), NewSummon->GetEntry(), NewSummon->GetPositionX(), NewSummon->GetPositionY()); - delete NewSummon; - return; - } - - uint32 petlevel = m_caster->getLevel(); - NewSummon->setPetType(SUMMON_PET); - - uint32 faction = m_caster->getFaction(); - if(m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->isTotem()) - { - Unit* owner = ((Totem*)m_caster)->GetOwner(); - if(owner) - faction = owner->getFaction(); - NewSummon->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE); - } - - NewSummon->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_caster->GetGUID()); - NewSummon->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID()); - NewSummon->SetUInt32Value(UNIT_NPC_FLAGS , 0); - NewSummon->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction); - NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_0,2048); - NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_1,0); - NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,time(NULL)); - NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE,0); - NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP,1000); - NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); - - NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true); - // this enables pet details window (Shift+P) - - // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later - NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE); - - NewSummon->InitStatsForLevel( petlevel); - NewSummon->InitPetCreateSpells(); - - if(NewSummon->getPetType()==SUMMON_PET) - { - // Remove Demonic Sacrifice auras (new pet) - Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();) - { - if((*itr)->GetModifier()->m_miscvalue==2228) - { - m_caster->RemoveAurasDueToSpell((*itr)->GetId()); - itr = auraClassScripts.begin(); - } - else - ++itr; - } - - // generate new name for summon pet - std::string new_name=objmgr.GeneratePetName(petentry); - if(!new_name.empty()) - NewSummon->SetName(new_name); - } - else if(NewSummon->getPetType()==HUNTER_PET) - NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED); - - NewSummon->AIM_Initialize(); - NewSummon->SetHealth(NewSummon->GetMaxHealth()); - NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA)); - - map->Add((Creature*)NewSummon); - - m_caster->SetPet(NewSummon); - sLog.outDebug("New Pet has guid %u", NewSummon->GetGUIDLow()); - - if(m_caster->GetTypeId() == TYPEID_PLAYER) - { - NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT); - ((Player*)m_caster)->PetSpellInitialize(); - } -} - -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->SetTP(pet->m_TrainingPoints - pet->GetTPForSpell(learn_spellproto->Id)); - pet->learnSpell(learn_spellproto->Id); - - pet->SavePetToDB(PET_SAVE_AS_CURRENT); - _player->PetSpellInitialize(); -} - -void Spell::EffectTaunt(uint32 /*i*/) -{ - // 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->GetTypeId() != TYPEID_PLAYER) - { - if(unitTarget->getVictim()==m_caster) - { - SendCastResult(SPELL_FAILED_DONT_REPORT); - return; - } - } - - // Also use this effect to set the taunter's threat to the taunted creature's highest value - if(unitTarget->CanHaveThreatList() && unitTarget->getThreatManager().getCurrentVictim()) - unitTarget->getThreatManager().addThreat(m_caster,unitTarget->getThreatManager().getCurrentVictim()->getThreat()); -} - -void Spell::EffectWeaponDmg(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 (int j = 0; 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: - if (j < i) // we must calculate only at last weapon effect - return; - break; - } - } - - // some spell specific modifiers - bool customBonusDamagePercentMod = false; - float bonusDamagePercentMod = 1.0f; // applied to fixed effect damage bonus if set customBonusDamagePercentMod - float weaponDamagePercentMod = 1.0f; // applied to weapon damage (and to fixed effect damage bonus if customBonusDamagePercentMod not set - float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage - bool normalized = false; - - int32 spell_bonus = 0; // bonus specific for spell - switch(m_spellInfo->SpellFamilyName) - { - case SPELLFAMILY_WARRIOR: - { - // Whirlwind, single only spell with 2 weapon white damage apply if have - if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x00000400000000LL)) - { - if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK,true)) - spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized); - } - // Devastate bonus and sunder armor refresh - else if(m_spellInfo->SpellVisual == 671 && m_spellInfo->SpellIconID == 1508) - { - customBonusDamagePercentMod = true; - bonusDamagePercentMod = 0.0f; // only applied if auras found - - Unit::AuraList const& list = unitTarget->GetAurasByType(SPELL_AURA_MOD_RESISTANCE); - for(Unit::AuraList::const_iterator itr=list.begin();itr!=list.end();++itr) - { - SpellEntry const *proto = (*itr)->GetSpellProto(); - if(proto->SpellVisual == 406 && proto->SpellIconID == 565) - { - int32 duration = GetSpellDuration(proto); - (*itr)->SetAuraDuration(duration); - (*itr)->UpdateAuraDuration(); - bonusDamagePercentMod += 1.0f; // +100% - } - } - } - break; - } - case SPELLFAMILY_ROGUE: - { - // Ambush - if(m_spellInfo->SpellFamilyFlags & 0x00000200LL) - { - customBonusDamagePercentMod = true; - bonusDamagePercentMod = 2.5f; // 250% - } - // Mutilate (for each hand) - else if(m_spellInfo->SpellFamilyFlags & 0x600000000LL) - { - bool found = false; - // fast check - if(unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON)) - found = true; - // full aura scan - else - { - Unit::AuraMap const& auras = unitTarget->GetAuras(); - for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr) - { - if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON) - { - found = true; - break; - } - } - } - - if(found) - totalDamagePercentMod *= 1.5f; // 150% if poisoned - } - break; - } - case SPELLFAMILY_PALADIN: - { - // Seal of Command - receive benefit from Spell Damage and Healing - if(m_spellInfo->SpellFamilyFlags & 0x00000002000000LL) - { - spell_bonus += int32(0.20f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo))); - spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget)); - } - break; - } - case SPELLFAMILY_SHAMAN: - { - // Skyshatter Harness item set bonus - // Stormstrike - if(m_spellInfo->SpellFamilyFlags & 0x001000000000LL) - { - Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i) - { - // Stormstrike AP Buff - if ( (*i)->GetModifier()->m_miscvalue == 5634 ) - { - m_caster->CastSpell(m_caster,38430,true,NULL,*i); - break; - } - } - } - } - } - - int32 fixed_bonus = 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; - - // applied only to prev.effects fixed damage - if(customBonusDamagePercentMod) - fixed_bonus = int32(fixed_bonus*bonusDamagePercentMod); - else - fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod); - break; - default: - break; // not weapon damage effect, just skip - } - } - - // non-weapon damage - int32 bonus = spell_bonus + fixed_bonus; - - // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage - if(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 = m_caster->GetModifierValue(unitMod, TOTAL_PCT); - bonus = int32(bonus*weapon_total_pct); - } - - // + weapon damage with applied weapon% dmg to base weapon damage in call - bonus += int32(m_caster->CalculateDamage(m_attackType, normalized)*weaponDamagePercentMod); - - // total damage - bonus = int32(bonus*totalDamagePercentMod); - - // prevent negative damage - uint32 eff_damage = uint32(bonus > 0 ? bonus : 0); - - const uint32 nohitMask = HITINFO_ABSORB | HITINFO_RESIST | HITINFO_MISS; - - uint32 hitInfo = 0; - VictimState victimState = VICTIMSTATE_NORMAL; - uint32 blocked_dmg = 0; - uint32 absorbed_dmg = 0; - uint32 resisted_dmg = 0; - CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL ); - - m_caster->DoAttackDamage(unitTarget, &eff_damage, &cleanDamage, &blocked_dmg, m_spellSchoolMask, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, m_attackType, m_spellInfo, m_IsTriggeredSpell); - - if ((hitInfo & nohitMask) && m_attackType != RANGED_ATTACK) // not send ranged miss/etc - m_caster->SendAttackStateUpdate(hitInfo & nohitMask, unitTarget, 1, m_spellSchoolMask, eff_damage, absorbed_dmg, resisted_dmg, VICTIMSTATE_NORMAL, blocked_dmg); - - bool criticalhit = (hitInfo & HITINFO_CRITICALHIT); - m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, eff_damage, m_spellSchoolMask, absorbed_dmg, resisted_dmg, false, blocked_dmg, criticalhit); - - if (eff_damage > (absorbed_dmg + resisted_dmg + blocked_dmg)) - { - eff_damage -= (absorbed_dmg + resisted_dmg + blocked_dmg); - } - else - { - cleanDamage.damage += eff_damage; - eff_damage = 0; - } - - // SPELL_SCHOOL_NORMAL use for weapon-like threat and rage calculation - m_caster->DealDamage(unitTarget, eff_damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, true); - - // Hemorrhage - if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000)) - { - if(m_caster->GetTypeId()==TYPEID_PLAYER) - ((Player*)m_caster)->AddComboPoints(unitTarget, 1); - } - // Mangle (Cat): CP - if(m_spellInfo->SpellFamilyName==SPELLFAMILY_DRUID && (m_spellInfo->SpellFamilyFlags==0x0000040000000000LL)) - { - if(m_caster->GetTypeId()==TYPEID_PLAYER) - ((Player*)m_caster)->AddComboPoints(unitTarget,1); - } - - - // take ammo - if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER) - { - Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK ); - - // wands don't have ammo - if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND) - return; - - if( pItem->GetProto()->InventoryType == INVTYPE_THROWN ) - { - if(pItem->GetMaxStackCount()==1) - { - // decrease durability for non-stackable throw weapon - ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED); - } - else - { - // decrease items amount for stackable throw weapon - uint32 count = 1; - ((Player*)m_caster)->DestroyItemCount( pItem, count, true); - } - } - else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID)) - ((Player*)m_caster)->DestroyItemCount(ammo, 1, true); - } -} - -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; - - uint32 heal = m_caster->GetMaxHealth(); - - int32 gain = unitTarget->ModifyHealth(heal); - unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo); - - m_caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, heal); -} - -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 (unitTarget->m_currentSpells[i]) - { - // check if we can interrupt spell - if ( unitTarget->m_currentSpells[i]->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && unitTarget->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE ) - { - unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget->m_currentSpells[i]->m_spellInfo), GetSpellDuration(m_spellInfo)); - unitTarget->InterruptSpell(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.m_targetMask & TARGET_FLAG_DEST_LOCATION) - { - x = m_targets.m_destX; - y = m_targets.m_destY; - z = m_targets.m_destZ; - } - 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, - x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1)) - { - delete pGameObj; - return; - } - - int32 duration = GetSpellDuration(m_spellInfo); - pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0); - pGameObj->SetSpellId(m_spellInfo->Id); - - if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)... - m_caster->AddGameObject(pGameObj); - map->Add(pGameObj); - - if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS - { - if(m_caster->GetTypeId() == TYPEID_PLAYER) - { - Player *pl = (Player*)m_caster; - BattleGround* bg = ((Player *)m_caster)->GetBattleGround(); - if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS) - { - uint32 team = ALLIANCE; - - if(pl->GetTeam() == team) - team = HORDE; - - ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team); - } - } - } - - if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY - { - if(m_caster->GetTypeId() == TYPEID_PLAYER) - { - BattleGround* bg = ((Player *)m_caster)->GetBattleGround(); - if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS) - { - ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID()); - } - } - } - - if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry()) - { - GameObject* linkedGO = new GameObject; - if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map, - x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1)) - { - linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0); - linkedGO->SetSpellId(m_spellInfo->Id); - - m_caster->AddGameObject(linkedGO); - 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) - - // by spell id - switch(m_spellInfo->Id) - { - // 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; - } - - // Healthstone creating spells - case 6201: - case 6202: - case 5699: - case 11729: - case 11730: - case 27230: - { - uint32 itemtype; - uint32 rank = 0; - Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i) - { - if((*i)->GetId() == 18692) - { - rank = 1; - break; - } - else if((*i)->GetId() == 18693) - { - rank = 2; - break; - } - } - - static uint32 const itypes[6][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 - }; - - 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 - default: - return; - } - DoCreateItem( effIndex, itemtype ); - return; - } - // Brittle Armor - need remove one 24575 Brittle Armor aura - case 24590: - unitTarget->RemoveSingleAuraFromStack(24575, 0); - unitTarget->RemoveSingleAuraFromStack(24575, 1); - return; - // Mercurial Shield - need remove one 26464 Mercurial Shield aura - case 26465: - unitTarget->RemoveSingleAuraFromStack(26464, 0); - 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->GetDummyAura(22683)) - return; - - // Shadow Flame - m_caster->CastSpell(unitTarget, 22682, true); - return; - } - break; - - // Summon Black Qiraji Battle Tank - case 26656: - { - if(!unitTarget) - return; - - // Prevent stacking of mounts - unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED); - - // Two separate mounts depending on area id (allows use both in and out of specific instance) - if (unitTarget->GetAreaId() == 3428) - unitTarget->CastSpell(unitTarget, 25863, false); - else - unitTarget->CastSpell(unitTarget, 26655, false); - break; - } - // Piccolo of the Flaming Fire - case 17512: - { - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE); - break; - } - - // 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, 0)) - 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; - } - - // 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. - uint32 mechanic_mask = (1<<MECHANIC_ROOT) | (1<<MECHANIC_SNARE); - Unit::AuraMap& Auras = unitTarget->GetAuras(); - for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next) - { - next = iter; - ++next; - Aura *aur = iter->second; - if (!aur->IsPositive()) //only remove negative spells - { - // check for mechanic mask - if(GetSpellMechanicMask(aur->GetSpellProto(), aur->GetEffIndex()) & mechanic_mask) - { - unitTarget->RemoveAurasDueToSpell(aur->GetId()); - if(Auras.empty()) - break; - else - next = Auras.begin(); - } - } - } - break; - } - case 41126: // Flame Crash - { - if(!unitTarget) - return; - - unitTarget->CastSpell(unitTarget, 41131, true); - break; - } - case 44876: // Force Cast - Portal Effect: Sunwell Isle - { - if(!unitTarget) - return; - - unitTarget->CastSpell(unitTarget, 44870, true); - break; - } - - // Goblin Weather Machine - case 46203: - { - if(!unitTarget) - return; - - uint32 spellId; - 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; - } - } - - if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN ) - { - switch(m_spellInfo->SpellFamilyFlags) - { - // Judgement - case 0x800000: - { - if(!unitTarget || !unitTarget->isAlive()) - return; - uint32 spellId2 = 0; - - // all seals have aura dummy - Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr) - { - SpellEntry const *spellInfo = (*itr)->GetSpellProto(); - - // search seal (all seals have judgement's aura dummy spell id in 2 effect - if ( !spellInfo || !IsSealSpell((*itr)->GetSpellProto()) || (*itr)->GetEffIndex() != 2 ) - continue; - - // must be calculated base at raw base points in spell proto, GetModifier()->m_value for S.Righteousness modified by SPELLMOD_DAMAGE - spellId2 = (*itr)->GetSpellProto()->EffectBasePoints[2]+1; - - if(spellId2 <= 1) - continue; - - // found, remove seal - m_caster->RemoveAurasDueToSpell((*itr)->GetId()); - - // Sanctified Judgement - Unit::AuraList const& m_auras = m_caster->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraList::const_iterator i = m_auras.begin(); i != m_auras.end(); ++i) - { - if ((*i)->GetSpellProto()->SpellIconID == 205 && (*i)->GetSpellProto()->Attributes == 0x01D0LL) - { - int32 chance = (*i)->GetModifier()->m_amount; - if ( roll_chance_i(chance) ) - { - int32 mana = spellInfo->manaCost; - if ( Player* modOwner = m_caster->GetSpellModOwner() ) - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COST, mana); - mana = int32(mana* 0.8f); - m_caster->CastCustomSpell(m_caster,31930,&mana,NULL,NULL,true,NULL,*i); - } - break; - } - } - - break; - } - - m_caster->CastSpell(unitTarget,spellId2,true); - return; - } - } - } - - // normal DB scripted effect - if(!unitTarget) - return; - - sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id); - sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget); -} - -void Spell::EffectSanctuary(uint32 /*i*/) -{ - if(!unitTarget) - return; - //unitTarget->CombatStop(); - - unitTarget->CombatStop(); - unitTarget->getHostilRefManager().deleteReferences(); // stop all fighting - // Vanish allows to remove all threat and cast regular stealth so other spells can be used - if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH)) - { - ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT); - } -} - -void Spell::EffectAddComboPoints(uint32 /*i*/) -{ - if(!unitTarget) - return; - - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - if(damage <= 0) - return; - - ((Player*)m_caster)->AddComboPoints(unitTarget, damage); -} - -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()->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->GetMapId() != 0 && caster->GetMapId() != 1 && caster->GetMapId() != 530) - { - 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->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 , - m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 , - m_caster->GetPositionZ(), - m_caster->GetOrientation(), 0, 0, 0, 0, 0, 1)) - { - 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/1000 : 0); - pGameObj->SetSpellId(m_spellInfo->Id); - - m_caster->AddGameObject(pGameObj); - map->Add(pGameObj); - //END - - // Send request - WorldPacket data(SMSG_DUEL_REQUESTED, 16); - data << pGameObj->GetGUID(); - data << 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; - - // 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->GetDummyAura(23445)) - return; - - float x,y,z; - m_caster->GetClosePoint(x,y,z,unitTarget->GetObjectSize()); - - ((Player*)unitTarget)->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*1000); // auto decline after msecs - ((Player*)unitTarget)->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]; - - sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget); -} - -void Spell::EffectSummonTotem(uint32 i) -{ - uint8 slot = 0; - switch(m_spellInfo->EffectMiscValueB[i]) - { - case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break; - case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break; - case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break; - case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break; - // Battle standard case - case SUMMON_TYPE_TOTEM: slot = 254; break; - // jewelery statue case, like totem without slot - case SUMMON_TYPE_GUARDIAN: slot = 255; break; - default: return; - } - - if(slot < MAX_TOTEM) - { - uint64 guid = m_caster->m_TotemSlot[slot]; - if(guid != 0) - { - Creature *OldTotem = ObjectAccessor::GetCreature(*m_caster, guid); - if(OldTotem && OldTotem->isTotem()) - ((Totem*)OldTotem)->UnSummon(); - } - } - - uint32 team = 0; - if (m_caster->GetTypeId()==TYPEID_PLAYER) - team = ((Player*)m_caster)->GetTeam(); - - Totem* pTotem = new Totem; - - if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_spellInfo->EffectMiscValue[i], team )) - { - delete pTotem; - return; - } - - float angle = slot < MAX_TOTEM ? M_PI/MAX_TOTEM - (slot*2*M_PI/MAX_TOTEM) : 0; - - float x,y,z; - m_caster->GetClosePoint(x,y,z,pTotem->GetObjectSize(),2.0f,angle); - - // totem must be at same Z in case swimming caster and etc. - if( fabs( z - m_caster->GetPositionZ() ) > 5 ) - z = m_caster->GetPositionZ(); - - pTotem->Relocate(x, y, z, m_caster->GetOrientation()); - - if(slot < MAX_TOTEM) - m_caster->m_TotemSlot[slot] = pTotem->GetGUID(); - - pTotem->SetOwner(m_caster->GetGUID()); - pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized - - int32 duration=GetSpellDuration(m_spellInfo); - if(Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration); - pTotem->SetDuration(duration); - - if (damage) // if not spell info, DB values used - { - pTotem->SetMaxHealth(damage); - pTotem->SetHealth(damage); - } - - pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id); - pTotem->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE); - - pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_MOD_FEAR,true); - pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_TRANSFORM,true); - - pTotem->Summon(m_caster); - - if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER) - { - WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4); - data << uint8(slot); - data << uint64(pTotem->GetGUID()); - data << uint32(duration); - data << uint32(m_spellInfo->Id); - ((Player*)m_caster)->SendDirectMessage(&data); - } -} - -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 = m_currentBasePoints[i]+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*1000, 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); - - ((Player*)m_caster)->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; - - if(!itemTarget) - return; - - Pet *pet = _player->GetPet(); - if(!pet) - return; - - if(!pet->isAlive()) - return; - - int32 benefit = pet->GetCurrentFoodBenefitLevel(itemTarget->GetProto()->ItemLevel); - if(benefit <= 0) - return; - - uint32 count = 1; - _player->DestroyItemCount(itemTarget,count,true); - // TODO: fix crash when a spell has two effects, both pointed at the same item target - - m_caster->CastCustomSpell(m_caster,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true); -} - -void Spell::EffectDismissPet(uint32 /*i*/) -{ - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Pet* pet = m_caster->GetPet(); - - // not let dismiss dead pet - if(!pet||!pet->isAlive()) - return; - - ((Player*)m_caster)->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 = ObjectAccessor::GetGameObject(*m_caster, guid); - - if(obj) obj->Delete(); - m_caster->m_ObjectSlot[slot] = 0; - } - - GameObject* pGameObj = new GameObject; - - float rot2 = sin(m_caster->GetOrientation()/2); - float rot3 = cos(m_caster->GetOrientation()/2); - - float x,y,z; - // If dest location if present - if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) - { - x = m_targets.m_destX; - y = m_targets.m_destY; - z = m_targets.m_destZ; - } - // 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, x, y, z, m_caster->GetOrientation(), 0, 0, rot2, rot3, 0, 1)) - { - delete pGameObj; - return; - } - - pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel()); - int32 duration = GetSpellDuration(m_spellInfo); - pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0); - pGameObj->SetSpellId(m_spellInfo->Id); - m_caster->AddGameObject(pGameObj); - - map->Add(pGameObj); - WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8); - data << pGameObj->GetGUID(); - m_caster->SendMessageToSet(&data,true); - - m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID(); -} - -void Spell::EffectResurrect(uint32 i) -{ - 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; - default: - break; - } - - Player* pTarget = ((Player*)unitTarget); - - 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; - - unitTarget->m_extraAttacks = damage; -} - -void Spell::EffectParry(uint32 /*i*/) -{ - if (unitTarget->GetTypeId() == TYPEID_PLAYER) - { - ((Player*)unitTarget)->SetCanParry(true); - } -} - -void Spell::EffectMomentMove(uint32 i) -{ - if(unitTarget->isInFlight()) - return; - - if( m_spellInfo->rangeIndex== 1) //self range - { - uint32 mapid = m_caster->GetMapId(); - float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - - // before caster - float fx,fy,fz; - unitTarget->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis); - float ox,oy,oz; - unitTarget->GetPosition(ox,oy,oz); - - float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case - if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid, ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5)) - { - fx = fx2; - fy = fy2; - fz = fz2; - unitTarget->UpdateGroundPositionZ(fx,fy,fz); - } - - if(unitTarget->GetTypeId() == TYPEID_PLAYER) - ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, unitTarget->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0)); - else - MapManager::Instance().GetMap(mapid, unitTarget)->CreatureRelocation((Creature*)unitTarget, fx, fy, fz, unitTarget->GetOrientation()); - } -} - -void Spell::EffectReputation(uint32 i) -{ - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - Player *_player = (Player*)unitTarget; - - int32 rep_change = m_currentBasePoints[i]+1; // field store reputation change -1 - - uint32 faction_id = m_spellInfo->EffectMiscValue[i]; - - FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id); - - if(!factionEntry) - return; - - _player->ModifyFactionReputation(factionEntry,rep_change); -} - -void Spell::EffectQuestComplete(uint32 i) -{ - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player *_player = (Player*)m_caster; - - uint32 quest_id = m_spellInfo->EffectMiscValue[i]; - _player->AreaExploredOrEventHappens(quest_id); -} - -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 = ((Player*)unitTarget); - 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(); - - plr->SaveToDB(); -} - -void Spell::EffectSkinning(uint32 /*i*/) -{ - if(unitTarget->GetTypeId() != TYPEID_UNIT ) - return; - if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - Creature* creature = (Creature*) unitTarget; - int32 targetLevel = creature->getLevel(); - - uint32 skill; - if(creature->GetCreatureInfo()->flag1 & 256) - skill = SKILL_HERBALISM; // special case - else if(creature->GetCreatureInfo()->flag1 & 512) - skill = SKILL_MINING; // special case - else - skill = SKILL_SKINNING; // normal case - - ((Player*)m_caster)->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 = ((Player*)m_caster)->GetPureSkillValue(skill); - - // Double chances for elites - ((Player*)m_caster)->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1 ); -} - -void Spell::EffectCharge(uint32 /*i*/) -{ - if(!unitTarget || !m_caster) - return; - - float x, y, z; - unitTarget->GetContactPoint(m_caster, x, y, z); - if(unitTarget->GetTypeId() != TYPEID_PLAYER) - ((Creature *)unitTarget)->StopMoving(); - - // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags - m_caster->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1); - - if(m_caster->GetTypeId() != TYPEID_PLAYER) - MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)->CreatureRelocation((Creature*)m_caster,x,y,z,m_caster->GetOrientation()); - - // not all charge effects used in negative spells - if ( !IsPositiveSpell(m_spellInfo->Id)) - m_caster->Attack(unitTarget,true); -} - -void Spell::EffectSummonCritter(uint32 i) -{ - if(m_caster->GetTypeId() != TYPEID_PLAYER) - return; - Player* player = (Player*)m_caster; - - uint32 pet_entry = m_spellInfo->EffectMiscValue[i]; - if(!pet_entry) - return; - - Pet* old_critter = player->GetMiniPet(); - - // for same pet just despawn - if(old_critter && old_critter->GetEntry() == pet_entry) - { - player->RemoveMiniPet(); - return; - } - - // despawn old pet before summon new - if(old_critter) - player->RemoveMiniPet(); - - // summon new pet - Pet* critter = new Pet(MINI_PET); - - Map *map = m_caster->GetMap(); - uint32 pet_number = objmgr.GeneratePetNumber(); - if(!critter->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), - map, pet_entry, pet_number)) - { - sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry); - delete critter; - return; - } - - float x,y,z; - // If dest location if present - if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) - { - x = m_targets.m_destX; - y = m_targets.m_destY; - z = m_targets.m_destZ; - } - // Summon if dest location not present near caster - else - m_caster->GetClosePoint(x,y,z,critter->GetObjectSize()); - - critter->Relocate(x,y,z,m_caster->GetOrientation()); - - if(!critter->IsPositionValid()) - { - sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", critter->GetGUIDLow(), critter->GetEntry(), critter->GetPositionX(), critter->GetPositionY()); - delete critter; - return; - } - - critter->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID()); - critter->SetUInt64Value(UNIT_FIELD_CREATEDBY,m_caster->GetGUID()); - critter->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction()); - critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); - - critter->AIM_Initialize(); - critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter... - critter->SetMaxHealth(1); - critter->SetHealth(1); - critter->SetLevel(1); - - // set timer for unsummon - int32 duration = GetSpellDuration(m_spellInfo); - if(duration > 0) - critter->SetDuration(duration); - - std::string name = player->GetName(); - name.append(petTypeSuffix[critter->getPetType()]); - critter->SetName( name ); - player->SetMiniPet(critter); - - map->Add((Creature*)critter); -} - -void Spell::EffectKnockBack(uint32 i) -{ - if(!unitTarget || !m_caster) - return; - - // Effect only works on players - if(unitTarget->GetTypeId()!=TYPEID_PLAYER) - return; - - float vsin = sin(m_caster->GetAngle(unitTarget)); - float vcos = cos(m_caster->GetAngle(unitTarget)); - - WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4)); - data.append(unitTarget->GetPackGUID()); - data << uint32(0); // Sequence - data << float(vcos); // x direction - data << float(vsin); // y direction - data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed - data << float(damage/-10); // Z Movement speed (vertical) - - ((Player*)unitTarget)->GetSession()->SendPacket(&data); -} - -void Spell::EffectSendTaxi(uint32 i) -{ - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(m_spellInfo->EffectMiscValue[i]); - if(!entry) - return; - - std::vector<uint32> nodes; - - nodes.resize(2); - nodes[0] = entry->from; - nodes[1] = entry->to; - - uint32 mountid = 0; - switch(m_spellInfo->Id) - { - case 31606: //Stormcrow Amulet - mountid = 17447; - break; - case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run - case 45113: //Quest - Sunwell Daily - Ship Bombing Run - case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return - mountid = 22840; - break; - case 34905: //Stealth Flight - mountid = 6851; - break; - } - - ((Player*)unitTarget)->ActivateTaxiPathTo(nodes,mountid); - -} - -void Spell::EffectPlayerPull(uint32 i) -{ - if(!unitTarget || !m_caster) - return; - - // Effect only works on players - if(unitTarget->GetTypeId()!=TYPEID_PLAYER) - return; - - float vsin = sin(unitTarget->GetAngle(m_caster)); - float vcos = cos(unitTarget->GetAngle(m_caster)); - - WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4)); - data.append(unitTarget->GetPackGUID()); - data << uint32(0); // Sequence - data << float(vcos); // x direction - data << float(vsin); // y direction - // Horizontal speed - data << float(damage ? damage : unitTarget->GetDistance2d(m_caster)); - data << float(m_spellInfo->EffectMiscValue[i])/-10; // Z Movement speed - - ((Player*)unitTarget)->GetSession()->SendPacket(&data); -} - -void Spell::EffectDispelMechanic(uint32 i) -{ - if(!unitTarget) - return; - - uint32 mechanic = m_spellInfo->EffectMiscValue[i]; - - Unit::AuraMap& Auras = unitTarget->GetAuras(); - for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next) - { - next = iter; - ++next; - SpellEntry const *spell = sSpellStore.LookupEntry(iter->second->GetSpellProto()->Id); - if(spell->Mechanic == mechanic || spell->EffectMechanic[iter->second->GetEffIndex()] == mechanic) - { - unitTarget->RemoveAurasDueToSpell(spell->Id); - if(Auras.empty()) - break; - else - next = Auras.begin(); - } - } - return; -} - -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; - 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*/) -{ - float mana = 0; - for(int slot = 0; slot < MAX_TOTEM; ++slot) - { - if(!m_caster->m_TotemSlot[slot]) - continue; - - Creature* totem = ObjectAccessor::GetCreature(*m_caster,m_caster->m_TotemSlot[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 * damage / 100; - ((Totem*)totem)->UnSummon(); - } - } - - int32 gain = m_caster->ModifyPower(POWER_MANA,int32(mana)); - m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id, gain, POWER_MANA); -} - -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) - { - ((Player*)unitTarget)->DurabilityPointsLossAll(damage,(slot < -1)); - return; - } - - // invalid slot value - if(slot >= INVENTORY_SLOT_BAG_END) - return; - - if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot)) - ((Player*)unitTarget)->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) - { - ((Player*)unitTarget)->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 = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot)) - ((Player*)unitTarget)->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.m_targetMask & TARGET_FLAG_DEST_LOCATION) - { - fx = m_targets.m_destX; - fy = m_targets.m_destY; - fz = m_targets.m_destZ; - } - //FIXME: this can be better check for most objects but still hack - else if(m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed==0) - { - float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex])); - m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis); - } - else - { - float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); - float max_dis = GetSpellMaxRange(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) - { - if ( !cMap->IsInWater(fx,fy,fz-0.5f)) // 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); - } - // 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, - fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1)) - { - delete pGameObj; - return; - } - - int32 duration = GetSpellDuration(m_spellInfo); - - switch(goinfo->type) - { - case GAMEOBJECT_TYPE_FISHINGNODE: - { - m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID()); - // Orientation3 - pGameObj->SetFloatValue(GAMEOBJECT_ROTATION + 2, 0.88431775569915771 ); - // Orientation4 - pGameObj->SetFloatValue(GAMEOBJECT_ROTATION + 3, -0.4668855369091033 ); - 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; - 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*1000 + FISHING_BOBBER_READY_TIME*1000; - break; - } - case GAMEOBJECT_TYPE_SUMMONING_RITUAL: - { - if(m_caster->GetTypeId()==TYPEID_PLAYER) - { - pGameObj->AddUniqueUse((Player*)m_caster); - m_caster->AddGameObject(pGameObj); // will removed at spell cancel - } - break; - } - case GAMEOBJECT_TYPE_FISHINGHOLE: - case GAMEOBJECT_TYPE_CHEST: - default: - { - break; - } - } - - pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 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\n"); - //m_caster->AddGameObject(pGameObj); - //m_ObjToDel.push_back(pGameObj); - - cMap->Add(pGameObj); - - WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8); - data << uint64(pGameObj->GetGUID()); - m_caster->SendMessageToSet(&data,true); - - if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry()) - { - GameObject* linkedGO = new GameObject; - if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap, - fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1)) - { - linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0); - linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() ); - linkedGO->SetSpellId(m_spellInfo->Id); - linkedGO->SetOwnerGUID(m_caster->GetGUID() ); - - MapManager::Instance().GetMap(linkedGO->GetMapId(), linkedGO)->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); - } - - ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING); -} - -void Spell::EffectSkill(uint32 /*i*/) -{ - sLog.outDebug("WORLD: SkillEFFECT"); -} - -void Spell::EffectSummonDemon(uint32 i) -{ - float px = m_targets.m_destX; - float py = m_targets.m_destY; - float pz = m_targets.m_destZ; - - Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,3600000); - if (!Charmed) - return; - - // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster? - Charmed->SetLevel(m_caster->getLevel()); - - // TODO: Add damage/mana/hp according to level - - if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon - { - // Enslave demon effect, without mana cost and cooldown - m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved - - // Inferno effect - Charmed->CastSpell(Charmed, 22703, true, 0); - } -} - -/* 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?) - //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA)); - ((Player*)unitTarget)->ResurrectPlayer(1.0f); - ((Player*)unitTarget)->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; - - ((Player*)unitTarget)->RemovedInsignia( (Player*)m_caster ); -} - -void Spell::EffectStealBeneficialBuff(uint32 i) -{ - sLog.outDebug("Effect: StealBeneficialBuff"); - - if(!unitTarget || unitTarget==m_caster) // can't steal from self - return; - - std::vector <Aura *> steal_list; - // Create dispel mask by dispel type - uint32 dispelMask = GetDispellMask( DispelType(m_spellInfo->EffectMiscValue[i]) ); - Unit::AuraMap const& auras = unitTarget->GetAuras(); - for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - { - Aura *aur = (*itr).second; - if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask) - { - // Need check for passive? this - if (aur->IsPositive() && !aur->IsPassive()) - steal_list.push_back(aur); - } - } - // Ok if exist some buffs for dispel try dispel it - if (!steal_list.empty()) - { - std::list < std::pair<uint32,uint64> > success_list; - int32 list_size = steal_list.size(); - // Dispell N = damage buffs (or while exist buffs for dispel) - for (int32 count=0; count < damage && list_size > 0; ++count) - { - // Random select buff for dispel - Aura *aur = steal_list[urand(0, list_size-1)]; - // Not use chance for steal - // TODO possible need do it - success_list.push_back( std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID())); - - // Remove buff from list for prevent doubles - for (std::vector<Aura *>::iterator j = steal_list.begin(); j != steal_list.end(); ) - { - Aura *stealed = *j; - if (stealed->GetId() == aur->GetId() && stealed->GetCasterGUID() == aur->GetCasterGUID()) - { - j = steal_list.erase(j); - --list_size; - } - else - ++j; - } - } - // Really try steal and send log - if (!success_list.empty()) - { - int32 count = success_list.size(); - WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+count*5); - data.append(unitTarget->GetPackGUID()); // Victim GUID - data.append(m_caster->GetPackGUID()); // Caster GUID - data << uint32(m_spellInfo->Id); // Dispell spell id - data << uint8(0); // not used - data << uint32(count); // count - for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j) - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first); - data << uint32(spellInfo->Id); // Spell Id - data << uint8(0); // 0 - steals !=0 transfers - unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster); - } - m_caster->SendMessageToSet(&data, true); - } - } -} - -void Spell::EffectKillCredit(uint32 i) -{ - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - ((Player*)unitTarget)->KilledMonster(m_spellInfo->EffectMiscValue[i], 0); -} - -void Spell::EffectQuestFail(uint32 i) -{ - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - ((Player*)unitTarget)->FailQuest(m_spellInfo->EffectMiscValue[i]); -} +/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * 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 "SharedDefines.h"
+#include "Database/DatabaseEnv.h"
+#include "WorldPacket.h"
+#include "WorldSession.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 "CreatureAI.h"
+#include "Spell.h"
+#include "DynamicObject.h"
+#include "SpellAuras.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 "BattleGround.h"
+#include "BattleGroundEY.h"
+#include "BattleGroundWS.h"
+#include "VMapFactory.h"
+#include "Language.h"
+#include "SocialMgr.h"
+#include "Util.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::EffectUnused, // 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::EffectMomentMove, // 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::EffectSummonWild, // 41 SPELL_EFFECT_SUMMON_WILD
+ &Spell::EffectSummonGuardian, // 42 SPELL_EFFECT_SUMMON_GUARDIAN
+ &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::EffectNULL, // 46 SPELL_EFFECT_SPAWN we must spawn pet there
+ &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::EffectOpenSecretSafe, // 59 SPELL_EFFECT_OPEN_LOCK_ITEM
+ &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::EffectUnused, // 65 SPELL_EFFECT_HEALTH_FUNNEL unused
+ &Spell::EffectUnused, // 66 SPELL_EFFECT_POWER_FUNNEL unused
+ &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::EffectSummonGuardian, // 73 SPELL_EFFECT_SUMMON_POSSESSED
+ &Spell::EffectSummonTotem, // 74 SPELL_EFFECT_SUMMON_TOTEM
+ &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::EffectSummonTotem, // 87 SPELL_EFFECT_SUMMON_TOTEM_SLOT1
+ &Spell::EffectSummonTotem, // 88 SPELL_EFFECT_SUMMON_TOTEM_SLOT2
+ &Spell::EffectSummonTotem, // 89 SPELL_EFFECT_SUMMON_TOTEM_SLOT3
+ &Spell::EffectSummonTotem, // 90 SPELL_EFFECT_SUMMON_TOTEM_SLOT4
+ &Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash
+ &Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM
+ &Spell::EffectUnused, // 93 SPELL_EFFECT_SUMMON_PHANTASM
+ &Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT
+ &Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING
+ &Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE
+ &Spell::EffectSummonCritter, // 97 SPELL_EFFECT_SUMMON_CRITTER
+ &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::EffectSummonDemon, //112 SPELL_EFFECT_SUMMON_DEMON
+ &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::EffectNULL, //130 SPELL_EFFECT_REDIRECT_THREAT
+ &Spell::EffectUnused, //131 SPELL_EFFECT_131 used in some test spells
+ &Spell::EffectNULL, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value
+ &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::EffectEnergisePct, //137 SPELL_EFFECT_ENERGIZE_PCT
+ &Spell::EffectNULL, //138 SPELL_EFFECT_138 Leap
+ &Spell::EffectUnused, //139 SPELL_EFFECT_139 unused
+ &Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST
+ &Spell::EffectNULL, //141 SPELL_EFFECT_141 damage and reduce speed?
+ &Spell::EffectTriggerSpellWithValue, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE
+ &Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER
+ &Spell::EffectNULL, //144 SPELL_EFFECT_144 Spectral Blast
+ &Spell::EffectNULL, //145 SPELL_EFFECT_145 Black Hole Effect
+ &Spell::EffectUnused, //146 SPELL_EFFECT_146 unused
+ &Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail
+ &Spell::EffectUnused, //148 SPELL_EFFECT_148 unused
+ &Spell::EffectNULL, //149 SPELL_EFFECT_149 swoop
+ &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
+};
+
+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 MANGOS
+}
+
+void Spell::EffectResurrectNew(uint32 i)
+{
+ if(!unitTarget || unitTarget->isAlive())
+ return;
+
+ if(unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ if(!unitTarget->IsInWorld())
+ return;
+
+ Player* pTarget = ((Player*)unitTarget);
+
+ 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();
+
+ uint32 health = unitTarget->GetHealth();
+ m_caster->DealDamage(unitTarget, health, 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 = m_spellInfo->EffectBasePoints[i]+m_spellInfo->EffectBaseDice[i];
+
+ m_caster->CalcAbsorbResist(m_caster,GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
+
+ m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false);
+ if(m_caster->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)m_caster)->EnvironmentalDamage(m_caster->GetGUID(),DAMAGE_FIRE,damage);
+}
+
+void Spell::EffectSchoolDMG(uint32 effect_idx)
+{
+ if( unitTarget && unitTarget->isAlive())
+ {
+ switch(m_spellInfo->SpellFamilyName)
+ {
+ case SPELLFAMILY_GENERIC:
+ {
+ //Gore
+ if(m_spellInfo->SpellIconID == 2269 )
+ {
+ damage+= rand()%2 ? damage : 0;
+ }
+
+ switch(m_spellInfo->Id) // better way to check unknown
+ {
+ // Meteor like spells (divided damage to targets)
+ case 24340: case 26558: case 28884: // Meteor
+ case 36837: case 38903: case 41276: // Meteor
+ case 26789: // Shard of the Fallen Star
+ case 31436: // Malevolent Cleave
+ case 35181: // Dive Bomb
+ case 40810: case 43267: case 43268: // Saber Lash
+ case 42384: // Brutal Swipe
+ case 45150: // Meteor Slash
+ {
+ uint32 count = 0;
+ for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
+ if(ihit->effectMask & (1<<effect_idx))
+ ++count;
+
+ damage /= count; // divide to all targets
+ break;
+ }
+ // percent from health with min
+ case 25599: // Thundercrash
+ {
+ damage = unitTarget->GetHealth() / 2;
+ if(damage < 200)
+ damage = 200;
+ break;
+ }
+ }
+ break;
+ }
+
+ case SPELLFAMILY_MAGE:
+ {
+ // Arcane Blast
+ if(m_spellInfo->SpellFamilyFlags & 0x20000000LL)
+ {
+ m_caster->CastSpell(m_caster,36032,true);
+ }
+ break;
+ }
+ case SPELLFAMILY_WARRIOR:
+ {
+ // Bloodthirst
+ if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
+ {
+ damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100);
+ }
+ // Shield Slam
+ else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
+ damage += int32(m_caster->GetShieldBlockValue());
+ // Victory Rush
+ else if(m_spellInfo->SpellFamilyFlags & 0x10000000000LL)
+ {
+ damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
+ m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false);
+ }
+ break;
+ }
+ case SPELLFAMILY_WARLOCK:
+ {
+ // Incinerate Rank 1 & 2
+ if((m_spellInfo->SpellFamilyFlags & 0x00004000000000LL) && m_spellInfo->SpellIconID==2128)
+ {
+ // Incinerate does more dmg (dmg*0.25) if the target is Immolated.
+ if(unitTarget->HasAuraState(AURA_STATE_IMMOLATE))
+ damage += int32(damage*0.25);
+ }
+ break;
+ }
+ case SPELLFAMILY_DRUID:
+ {
+ // Ferocious Bite
+ if((m_spellInfo->SpellFamilyFlags & 0x000800000) && m_spellInfo->SpellVisual==6587)
+ {
+ // converts each extra point of energy into ($f1+$AP/630) additional damage
+ float multiple = m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 630 + m_spellInfo->DmgMultiplier[effect_idx];
+ damage += int32(m_caster->GetPower(POWER_ENERGY) * multiple);
+ m_caster->SetPower(POWER_ENERGY,0);
+ }
+ // Rake
+ else if(m_spellInfo->SpellFamilyFlags & 0x0000000000001000LL)
+ {
+ damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
+ }
+ // Swipe
+ else if(m_spellInfo->SpellFamilyFlags & 0x0010000000000000LL)
+ {
+ damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.08f);
+ }
+ // Starfire
+ else if ( m_spellInfo->SpellFamilyFlags & 0x0004LL )
+ {
+ Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
+ {
+ // Starfire Bonus (caster)
+ switch((*i)->GetModifier()->m_miscvalue)
+ {
+ case 5481: // Nordrassil Regalia - bonus
+ {
+ Unit::AuraList const& m_periodicDamageAuras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
+ for(Unit::AuraList::const_iterator itr = m_periodicDamageAuras.begin(); itr != m_periodicDamageAuras.end(); ++itr)
+ {
+ // Moonfire or Insect Swarm (target debuff from any casters)
+ if ( (*itr)->GetSpellProto()->SpellFamilyFlags & 0x00200002LL )
+ {
+ int32 mod = (*i)->GetModifier()->m_amount;
+ damage += damage*mod/100;
+ break;
+ }
+ }
+ break;
+ }
+ case 5148: //Improved Starfire - Ivory Idol of the Moongoddes Aura
+ {
+ damage += (*i)->GetModifier()->m_amount;
+ break;
+ }
+ }
+ }
+ }
+ //Mangle Bonus for the initial damage of Lacerate and Rake
+ if((m_spellInfo->SpellFamilyFlags==0x0000000000001000LL && m_spellInfo->SpellIconID==494) ||
+ (m_spellInfo->SpellFamilyFlags==0x0000010000000000LL && m_spellInfo->SpellIconID==2246))
+ {
+ Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
+ if((*i)->GetSpellProto()->SpellFamilyFlags & 0x0000044000000000LL && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID)
+ {
+ damage = int32(damage*(100.0f+(*i)->GetModifier()->m_amount)/100.0f);
+ break;
+ }
+ }
+ break;
+ }
+ case SPELLFAMILY_ROGUE:
+ {
+ // Envenom
+ if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x800000000LL))
+ {
+ // consume from stack dozes not more that have combo-points
+ if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
+ {
+ // count consumed deadly poison doses at target
+ uint32 doses = 0;
+
+ // remove consumed poison doses
+ Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
+ for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end() && combo;)
+ {
+ // Deadly poison (only attacker applied)
+ if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE && ((*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000) &&
+ (*itr)->GetSpellProto()->SpellVisual==5100 && (*itr)->GetCasterGUID()==m_caster->GetGUID() )
+ {
+ --combo;
+ ++doses;
+
+ unitTarget->RemoveSingleAuraFromStack((*itr)->GetId(), (*itr)->GetEffIndex());
+
+ itr = auras.begin();
+ }
+ else
+ ++itr;
+ }
+
+ damage *= doses;
+ damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses);
+
+ // Eviscerate and Envenom Bonus Damage (item set effect)
+ if(m_caster->GetDummyAura(37169))
+ damage += ((Player*)m_caster)->GetComboPoints()*40;
+ }
+ }
+ // Eviscerate
+ else if((m_spellInfo->SpellFamilyFlags & 0x00020000LL) && m_caster->GetTypeId()==TYPEID_PLAYER)
+ {
+ if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
+ {
+ damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * combo * 0.03f);
+
+ // Eviscerate and Envenom Bonus Damage (item set effect)
+ if(m_caster->GetDummyAura(37169))
+ damage += combo*40;
+ }
+ }
+ break;
+ }
+ case SPELLFAMILY_HUNTER:
+ {
+ // Mongoose Bite
+ if((m_spellInfo->SpellFamilyFlags & 0x000000002) && m_spellInfo->SpellVisual==342)
+ {
+ damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2);
+ }
+ // Arcane Shot
+ else if((m_spellInfo->SpellFamilyFlags & 0x00000800) && m_spellInfo->maxLevel > 0)
+ {
+ damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15);
+ }
+ // Steady Shot
+ else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
+ {
+ int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),(int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE));
+ damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.2f);
+ }
+ //Explosive Trap Effect
+ else if(m_spellInfo->SpellFamilyFlags & 0x00000004)
+ {
+ damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1);
+ }
+ break;
+ }
+ case SPELLFAMILY_PALADIN:
+ {
+ //Judgement of Vengeance
+ if((m_spellInfo->SpellFamilyFlags & 0x800000000LL) && m_spellInfo->SpellIconID==2292)
+ {
+ uint32 stacks = 0;
+ Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
+ for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
+ if((*itr)->GetId() == 31803 && (*itr)->GetCasterGUID()==m_caster->GetGUID())
+ ++stacks;
+ if(!stacks)
+ //No damage if the target isn't affected by this
+ damage = -1;
+ else
+ damage *= stacks;
+ }
+ break;
+ }
+ }
+
+ if(damage >= 0)
+ {
+ uint32 finalDamage;
+ if(m_originalCaster) // m_caster only passive source of cast
+ finalDamage = m_originalCaster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
+ else
+ finalDamage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
+
+ // post effects
+ switch(m_spellInfo->SpellFamilyName)
+ {
+ case SPELLFAMILY_WARRIOR:
+ {
+ // Bloodthirst
+ if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
+ {
+ uint32 BTAura = 0;
+ switch(m_spellInfo->Id)
+ {
+ case 23881: BTAura = 23885; break;
+ case 23892: BTAura = 23886; break;
+ case 23893: BTAura = 23887; break;
+ case 23894: BTAura = 23888; break;
+ case 25251: BTAura = 25252; break;
+ case 30335: BTAura = 30339; break;
+ default:
+ sLog.outError("Spell::EffectSchoolDMG: Spell %u not handled in BTAura",m_spellInfo->Id);
+ break;
+ }
+
+ if (BTAura)
+ m_caster->CastSpell(m_caster,BTAura,true);
+ }
+ break;
+ }
+ case SPELLFAMILY_PRIEST:
+ {
+ // Shadow Word: Death
+ if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000200000000LL) && unitTarget->isAlive())
+ // deals damage equal to damage done to caster if victim is not killed
+ m_caster->SpellNonMeleeDamageLog( m_caster, m_spellInfo->Id, finalDamage, m_IsTriggeredSpell, false);
+
+ break;
+ }
+ case SPELLFAMILY_PALADIN:
+ {
+ // Judgement of Blood
+ if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000800000000LL) && m_spellInfo->SpellIconID==153)
+ {
+ int32 damagePoint = finalDamage * 33 / 100;
+ m_caster->CastCustomSpell(m_caster, 32220, &damagePoint, NULL, NULL, true);
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+void Spell::EffectDummy(uint32 i)
+{
+ if(!unitTarget && !gameObjTarget && !itemTarget)
+ return;
+
+ // selection by spell family
+ switch(m_spellInfo->SpellFamilyName)
+ {
+ case SPELLFAMILY_GENERIC:
+ // Gnomish Poultryizer trinket
+ 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;
+ ((Creature*)unitTarget)->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 12850: damage *= 0.2f; break;
+ case 12162: damage *= 0.4f; break;
+ case 12868: damage *= 0.6f; break;
+ default:
+ sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id);
+ return;
+ };
+
+ int32 deepWoundsDotBasePoints0 = int32(damage / 4);
+ m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL);
+ return;
+ }
+ case 12975: //Last Stand
+ {
+ int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3);
+ m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, 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 13567: // Dummy Trigger
+ {
+ // can be used for different aura triggreing, 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 14185: // Preparation Rogue
+ {
+ if(m_caster->GetTypeId()!=TYPEID_PLAYER)
+ return;
+
+ //immediately finishes the cooldown on certain Rogue abilities
+ const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
+ for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
+ {
+ uint32 classspell = itr->first;
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
+
+ if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & 0x26000000860LL))
+ {
+ ((Player*)m_caster)->RemoveSpellCooldown(classspell);
+
+ WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
+ data << uint32(classspell);
+ data << uint64(m_caster->GetGUID());
+ ((Player*)m_caster)->GetSession()->SendPacket(&data);
+ }
+ }
+ return;
+ }
+ case 15998: // Capture Worg Pup
+ case 29435: // Capture Female Kaliri Hatchling
+ {
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
+ return;
+
+ Creature* creatureTarget = (Creature*)unitTarget;
+ creatureTarget->setDeathState(JUST_DIED);
+ creatureTarget->RemoveCorpse();
+ creatureTarget->SetHealth(0); // just for nice GM-mode view
+ 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 << unitTarget->GetGUID();
+ ((Player*)m_originalCaster)->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 : 17270;
+
+ 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 || ((Creature*)unitTarget)->isPet())
+ return;
+
+ Creature* creatureTarget = (Creature*)unitTarget;
+ if(creatureTarget->isPet())
+ return;
+
+ creatureTarget->setDeathState(JUST_DIED);
+ creatureTarget->RemoveCorpse();
+ creatureTarget->SetHealth(0); // just for nice GM-mode view
+
+ GameObject* pGameObj = new GameObject;
+
+ Map *map = creatureTarget->GetMap();
+
+ if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 179644, map,
+ creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(),
+ creatureTarget->GetOrientation(), 0, 0, 0, 0, 100, 1) )
+ {
+ delete pGameObj;
+ return;
+ }
+
+ pGameObj->SetRespawnTime(creatureTarget->GetRespawnTime()-time(NULL));
+ pGameObj->SetOwnerGUID(m_caster->GetGUID() );
+ pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
+ pGameObj->SetSpellId(m_spellInfo->Id);
+
+ DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy\n");
+ map->Add(pGameObj);
+
+ WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
+ data << uint64(pGameObj->GetGUID());
+ m_caster->SendMessageToSet(&data,true);
+
+ return;
+ }
+ case 23074: // Arc. 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: // Ultrasafe Transporter: Gadgetzan - backfires
+ {
+ int32 r = irand(0, 119);
+ if ( r < 20 ) // 1/6 polymorph
+ m_caster->CastSpell(m_caster,23444,true);
+ else if ( r < 100 ) // 4/6 evil twin
+ m_caster->CastSpell(m_caster,23445,true);
+ else // 1/6 miss the target
+ m_caster->CastSpell(m_caster,36902,true);
+ return;
+ }
+ case 23453: // Ultrasafe Transporter: Gadgetzan
+ if ( roll_chance_i(50) ) // success
+ m_caster->CastSpell(m_caster,23441,true);
+ else // failure
+ m_caster->CastSpell(m_caster,23446,true);
+ return;
+ case 23645: // Hourglass Sand
+ m_caster->RemoveAurasDueToSpell(23170);
+ 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_FLY);
+ float speed = m_caster->GetSpeedRate(MOVE_RUN);
+
+ m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
+
+ //5 different spells used depending on mounted speed and if mount can fly or not
+ if (flyspeed >= 4.1f)
+ m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer
+ else if (flyspeed >= 3.8f)
+ m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer
+ else if (flyspeed >= 1.6f)
+ m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer
+ else if (speed >= 2.0f)
+ m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer
+ else
+ m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer
+
+ return;
+ }
+ //case 26074: // Holiday Cheer
+ // return; -- implemented at client side
+ case 28006: // Arcane Cloaking
+ {
+ if( unitTarget->GetTypeId() == TYPEID_PLAYER )
+ m_caster->CastSpell(unitTarget,29294,true);
+ return;
+ }
+ case 28730: // Arcane Torrent (Mana)
+ {
+ int32 count = 0;
+ Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraList::const_iterator i = m_dummyAuras.begin(); i != m_dummyAuras.end(); ++i)
+ if ((*i)->GetId() == 28734)
+ ++count;
+ if (count)
+ {
+ m_caster->RemoveAurasDueToSpell(28734);
+ int32 bp = damage * count;
+ m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true);
+ }
+ return;
+ }
+ case 29200: // Purify Helboar Meat
+ {
+ if( m_caster->GetTypeId() != TYPEID_PLAYER )
+ return;
+
+ uint32 spell_id = roll_chance_i(50) ? 29277 : 29278;
+
+ m_caster->CastSpell(m_caster,spell_id,true,NULL);
+ return;
+ }
+ case 29858: // Soulshatter
+ if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsHostileTo(m_caster))
+ m_caster->CastSpell(unitTarget,32835,true);
+ return;
+ case 30458: // Nigh Invulnerability
+ if (!m_CastItem) return;
+ if(roll_chance_i(86)) // success
+ m_caster->CastSpell(m_caster, 30456, true, m_CastItem);
+ else // 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)) // success
+ m_caster->CastSpell(unitTarget, 30501, true, m_CastItem);
+ else // 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;
+ case 2: spell_id = 33057; break;
+ case 3: spell_id = 33059; break;
+ case 4: spell_id = 33062; break;
+ case 5: spell_id = 33064; break;
+ }
+
+ m_caster->CastSpell(m_caster,spell_id,true,NULL);
+ return;
+ }
+ case 35745:
+ {
+ uint32 spell_id;
+ switch(m_caster->GetAreaId())
+ {
+ case 3900: spell_id = 35743; break;
+ case 3742: spell_id = 35744; break;
+ default: return;
+ }
+
+ m_caster->CastSpell(m_caster,spell_id,true);
+ return;
+ }
+ case 37674: // Chaos Blast
+ if(unitTarget)
+ m_caster->CastSpell(unitTarget,37675,true);
+ return;
+ case 44875: // Complete Raptor Capture
+ {
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
+ return;
+
+ Creature* creatureTarget = (Creature*)unitTarget;
+
+ creatureTarget->setDeathState(JUST_DIED);
+ creatureTarget->RemoveCorpse();
+ creatureTarget->SetHealth(0); // just for nice GM-mode view
+
+ //cast spell Raptor Capture Credit
+ m_caster->CastSpell(m_caster,42337,true,NULL);
+ return;
+ }
+ case 45030: // Impale Emissary
+ {
+ // Emissary of Hate Credit
+ m_caster->CastSpell(m_caster,45088,true);
+ 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(((Player*)m_caster)->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 = ((Player*)m_caster)->GetBattleGround())
+ bg->EventPlayerDroppedFlag((Player*)m_caster);
+
+ m_caster->CastSpell(m_caster, 30452, true, NULL);
+ return;
+ }
+ }
+
+ //All IconID Check in there
+ switch(m_spellInfo->SpellIconID)
+ {
+ // Berserking (troll racial traits)
+ case 1661:
+ {
+ uint32 healthPerc = uint32((float(m_caster->GetHealth())/m_caster->GetMaxHealth())*100);
+ int32 melee_mod = 10;
+ if (healthPerc <= 40)
+ melee_mod = 30;
+ if (healthPerc < 100 && healthPerc > 40)
+ melee_mod = 10+(100-healthPerc)/3;
+
+ int32 hasteModBasePoints0 = melee_mod; // (EffectBasePoints[0]+1)-1+(5-melee_mod) = (melee_mod-1+1)-1+5-melee_mod = 5-1
+ int32 hasteModBasePoints1 = (5-melee_mod);
+ int32 hasteModBasePoints2 = 5;
+
+ // FIXME: custom spell required this aura state by some unknown reason, we not need remove it anyway
+ m_caster->ModifyAuraState(AURA_STATE_BERSERKING,true);
+ m_caster->CastCustomSpell(m_caster,26635,&hasteModBasePoints0,&hasteModBasePoints1,&hasteModBasePoints2,true,NULL);
+ 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 PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
+ for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
+ {
+ if (itr->second->state == PLAYERSPELL_REMOVED)
+ continue;
+
+ uint32 classspell = itr->first;
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
+
+ if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE &&
+ (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) &&
+ spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 )
+ {
+ ((Player*)m_caster)->RemoveSpellCooldown(classspell);
+
+ WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
+ data << uint32(classspell);
+ data << uint64(m_caster->GetGUID());
+ ((Player*)m_caster)->GetSession()->SendPacket(&data);
+ }
+ }
+ return;
+ }
+ }
+ break;
+ case SPELLFAMILY_WARRIOR:
+ // Charge
+ if(m_spellInfo->SpellFamilyFlags & 0x1 && m_spellInfo->SpellVisual == 867)
+ {
+ int32 chargeBasePoints0 = damage;
+ m_caster->CastCustomSpell(m_caster,34846,&chargeBasePoints0,NULL,NULL,true);
+ return;
+ }
+ // Execute
+ if(m_spellInfo->SpellFamilyFlags & 0x20000000)
+ {
+ if(!unitTarget)
+ return;
+
+ int32 basePoints0 = damage+int32(m_caster->GetPower(POWER_RAGE) * m_spellInfo->DmgMultiplier[i]);
+ m_caster->CastCustomSpell(unitTarget, 20647, &basePoints0, NULL, NULL, true, 0);
+ m_caster->SetPower(POWER_RAGE,0);
+ return;
+ }
+ if(m_spellInfo->Id==21977) //Warrior's Wrath
+ {
+ if(!unitTarget)
+ return;
+
+ m_caster->CastSpell(unitTarget,21887,true); // spell mod
+ return;
+ }
+ break;
+ case SPELLFAMILY_WARLOCK:
+ //Life Tap (only it have this with dummy effect)
+ if (m_spellInfo->SpellFamilyFlags == 0x40000)
+ {
+ float cost = m_currentBasePoints[0]+1;
+
+ if(Player* modOwner = m_caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, cost,this);
+
+ int32 dmg = m_caster->SpellDamageBonus(m_caster, m_spellInfo,uint32(cost > 0 ? cost : 0), SPELL_DIRECT_DAMAGE);
+
+ if(int32(m_caster->GetHealth()) > dmg)
+ {
+ // Shouldn't Appear in Combat Log
+ m_caster->ModifyHealth(-dmg);
+
+ int32 mana = dmg;
+
+ Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
+ {
+ // only Imp. Life Tap have this in combination with dummy aura
+ if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 208)
+ mana = ((*itr)->GetModifier()->m_amount + 100)* mana / 100;
+ }
+
+ m_caster->CastCustomSpell(m_caster,31818,&mana,NULL,NULL,true,NULL);
+
+ // Mana Feed
+ int32 manaFeedVal = m_caster->CalculateSpellDamage(m_spellInfo,1, m_spellInfo->EffectBasePoints[1],m_caster);
+ manaFeedVal = manaFeedVal * mana / 100;
+ if(manaFeedVal > 0)
+ m_caster->CastCustomSpell(m_caster,32553,&manaFeedVal,NULL,NULL,true,NULL);
+ }
+ else
+ SendCastResult(SPELL_FAILED_FIZZLE);
+ return;
+ }
+ break;
+ case SPELLFAMILY_PRIEST:
+ switch(m_spellInfo->Id )
+ {
+ case 28598: // Touch of Weakness triggered spell
+ {
+ if(!unitTarget || !m_triggeredByAuraSpell)
+ return;
+
+ uint32 spellid = 0;
+ switch(m_triggeredByAuraSpell->Id)
+ {
+ case 2652: spellid = 2943; break; // Rank 1
+ case 19261: spellid = 19249; break; // Rank 2
+ case 19262: spellid = 19251; break; // Rank 3
+ case 19264: spellid = 19252; break; // Rank 4
+ case 19265: spellid = 19253; break; // Rank 5
+ case 19266: spellid = 19254; break; // Rank 6
+ case 25461: spellid = 25460; break; // Rank 7
+ default:
+ sLog.outError("Spell::EffectDummy: Spell 28598 triggered by unhandeled spell %u",m_triggeredByAuraSpell->Id);
+ return;
+ }
+ m_caster->CastSpell(unitTarget, spellid, true, NULL);
+ return;
+ }
+ }
+ break;
+ case SPELLFAMILY_DRUID:
+ switch(m_spellInfo->Id )
+ {
+ case 5420: // Tree of Life passive
+ {
+ // Tree of Life area effect
+ int32 health_mod = int32(m_caster->GetStat(STAT_SPIRIT)/4);
+ m_caster->CastCustomSpell(m_caster,34123,&health_mod,NULL,NULL,true,NULL);
+ return;
+ }
+ }
+ break;
+ case SPELLFAMILY_ROGUE:
+ switch(m_spellInfo->Id )
+ {
+ case 31231: // Cheat Death
+ {
+ m_caster->CastSpell(m_caster,45182,true);
+ return;
+ }
+ case 5938: // Shiv
+ {
+ if(m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ Player *pCaster = ((Player*)m_caster);
+
+ Item *item = pCaster->GetWeaponForAttack(OFF_ATTACK);
+ if(!item)
+ return;
+
+ // all poison enchantments is temporary
+ uint32 enchant_id = item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT);
+ if(!enchant_id)
+ return;
+
+ SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
+ if(!pEnchant)
+ return;
+
+ for (int s=0;s<3;s++)
+ {
+ if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
+ continue;
+
+ SpellEntry const* combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]);
+ if(!combatEntry || combatEntry->Dispel != DISPEL_POISON)
+ continue;
+
+ m_caster->CastSpell(unitTarget, combatEntry, true, item);
+ }
+
+ m_caster->CastSpell(unitTarget, 5940, true);
+ return;
+ }
+ }
+ break;
+ case SPELLFAMILY_HUNTER:
+ // Steady Shot
+ if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
+ {
+ if( !unitTarget || !unitTarget->isAlive())
+ return;
+
+ bool found = false;
+
+ // check dazed affect
+ Unit::AuraList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
+ for(Unit::AuraList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
+ {
+ if((*iter)->GetSpellProto()->SpellIconID==15 && (*iter)->GetSpellProto()->Dispel==0)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if(found)
+ m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
+ return;
+ }
+ // Kill command
+ if(m_spellInfo->SpellFamilyFlags & 0x00080000000000LL)
+ {
+ if(m_caster->getClass()!=CLASS_HUNTER)
+ return;
+
+ // clear hunter crit aura state
+ m_caster->ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE,false);
+
+ // additional damage from pet to pet target
+ Pet* pet = m_caster->GetPet();
+ if(!pet || !pet->getVictim())
+ return;
+
+ uint32 spell_id = 0;
+ switch (m_spellInfo->Id)
+ {
+ case 34026: spell_id = 34027; break; // rank 1
+ default:
+ sLog.outError("Spell::EffectDummy: Spell %u not handled in KC",m_spellInfo->Id);
+ return;
+ }
+
+ pet->CastSpell(pet->getVictim(), spell_id, true);
+ return;
+ }
+
+ switch(m_spellInfo->Id)
+ {
+ case 23989: //Readiness talent
+ {
+ if(m_caster->GetTypeId()!=TYPEID_PLAYER)
+ return;
+
+ //immediately finishes the cooldown for hunter abilities
+ const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
+ for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
+ {
+ uint32 classspell = itr->first;
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
+
+ if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
+ {
+ ((Player*)m_caster)->RemoveSpellCooldown(classspell);
+
+ WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
+ data << uint32(classspell);
+ data << uint64(m_caster->GetGUID());
+ ((Player*)m_caster)->GetSession()->SendPacket(&data);
+ }
+ }
+ 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();
+ ((Player*)m_caster)->SendAttackSwingCancelAttack();
+ return;
+ }
+ }
+ break;
+ case SPELLFAMILY_PALADIN:
+ 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;
+ 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;
+ }
+ case 561: // Judgement of command
+ {
+ if(!unitTarget)
+ return;
+
+ uint32 spell_id = m_currentBasePoints[i]+1;
+ SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id);
+ if(!spell_proto)
+ return;
+
+ if( !unitTarget->hasUnitState(UNIT_STAT_STUNDED) && m_caster->GetTypeId()==TYPEID_PLAYER)
+ {
+ // decreased damage (/2) for non-stunned target.
+ SpellModifier *mod = new SpellModifier;
+ mod->op = SPELLMOD_DAMAGE;
+ mod->value = -50;
+ mod->type = SPELLMOD_PCT;
+ mod->spellId = m_spellInfo->Id;
+ mod->effectId = i;
+ mod->lastAffected = NULL;
+ mod->mask = 0x0000020000000000LL;
+ mod->charges = 0;
+
+ ((Player*)m_caster)->AddSpellMod(mod, true);
+ m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
+ // mod deleted
+ ((Player*)m_caster)->AddSpellMod(mod, false);
+ }
+ else
+ m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
+
+ return;
+ }
+ }
+
+ switch(m_spellInfo->Id)
+ {
+ case 31789: // Righteous Defense (step 1)
+ {
+ // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target)
+
+ // non-standard cast requirement check
+ if (!unitTarget || unitTarget->getAttackers().empty())
+ {
+ // clear cooldown at fail
+ if(m_caster->GetTypeId()==TYPEID_PLAYER)
+ {
+ ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
+
+ WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
+ data << uint32(m_spellInfo->Id);
+ data << uint64(m_caster->GetGUID());
+ ((Player*)m_caster)->GetSession()->SendPacket(&data);
+ }
+
+ SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT);
+ return;
+ }
+
+ // Righteous Defense (step 2) (in old version 31980 dummy effect)
+ // Clear targets for eff 1
+ for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
+ ihit->effectMask &= ~(1<<1);
+
+ // not empty (checked)
+ Unit::AttackerSet const& attackers = unitTarget->getAttackers();
+
+ // chance to be selected from list
+ float chance = 100.0f/attackers.size();
+ uint32 count=0;
+ for(Unit::AttackerSet::const_iterator aItr = attackers.begin(); aItr != attackers.end() && count < 3; ++aItr)
+ {
+ if(!roll_chance_f(chance))
+ continue;
+ ++count;
+ AddUnitTarget((*aItr), 1);
+ }
+
+ // 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:
+ //Shaman Rockbiter Weapon
+ if (m_spellInfo->SpellFamilyFlags == 0x400000)
+ {
+ uint32 spell_id = 0;
+ switch(m_spellInfo->Id)
+ {
+ case 8017: spell_id = 36494; break; // Rank 1
+ case 8018: spell_id = 36750; break; // Rank 2
+ case 8019: spell_id = 36755; break; // Rank 3
+ case 10399: spell_id = 36759; break; // Rank 4
+ case 16314: spell_id = 36763; break; // Rank 5
+ case 16315: spell_id = 36766; break; // Rank 6
+ case 16316: spell_id = 36771; break; // Rank 7
+ case 25479: spell_id = 36775; break; // Rank 8
+ case 25485: spell_id = 36499; break; // Rank 9
+ default:
+ sLog.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo->Id);
+ return;
+ }
+
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry( spell_id );
+
+ if(!spellInfo)
+ {
+ sLog.outError("WORLD: unknown spell id %i\n", spell_id);
+ return;
+ }
+
+ if(m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ for(int i = BASE_ATTACK; i <= OFF_ATTACK; ++i)
+ {
+ if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(i)))
+ {
+ if(item->IsFitToSpellRequirements(m_spellInfo))
+ {
+ Spell *spell = new Spell(m_caster, spellInfo, true);
+
+ // enchanting spell selected by calculated damage-per-sec in enchanting effect
+ // at calculation applied affect from Elemental Weapons talent
+ // real enchantment damage-1
+ spell->m_currentBasePoints[1] = damage-1;
+
+ SpellCastTargets targets;
+ targets.setItemTarget( item );
+ spell->prepare(&targets);
+ }
+ }
+ }
+ return;
+ }
+
+ if(m_spellInfo->Id == 39610) // Mana-Tide Totem effect
+ {
+ if(!unitTarget || unitTarget->getPowerType() != POWER_MANA)
+ return;
+
+ // 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;
+ }
+
+ break;
+ }
+
+ // pet auras
+ if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id))
+ {
+ m_caster->AddPetAura(petSpell);
+ return;
+ }
+}
+
+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\n", m_spellInfo->Id,triggered_spell_id);
+ return;
+ }
+
+ int32 bp = damage;
+ m_caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true,NULL,NULL,m_originalCasterGUID);
+}
+
+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();
+ Spell *spell = new Spell(m_caster, spellInfo, true);
+
+ SpellCastTargets targets;
+ targets.setUnitTarget( unitTarget);
+ spell->prepare(&targets);
+
+ m_caster->SetCurrentCastedSpell(spell);
+ spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]);
+
+}
+
+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;
+ }
+
+ unitTarget->CastSpell(unitTarget,spellInfo,true,NULL,NULL,m_originalCasterGUID);
+}
+
+void Spell::EffectTriggerSpell(uint32 i)
+{
+ uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
+
+ // special cases
+ switch(triggered_spell_id)
+ {
+ // Vanish
+ case 18461:
+ {
+ m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
+ m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
+ m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED);
+
+ // if this spell is given to NPC it must handle rest by it's own AI
+ if ( m_caster->GetTypeId() != TYPEID_PLAYER )
+ return;
+
+ // get highest rank of the Stealth spell
+ uint32 spellId = 0;
+ const PlayerSpellMap& sp_list = ((Player*)m_caster)->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;
+
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
+ if (!spellInfo)
+ continue;
+
+ if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_STEALTH)
+ {
+ spellId = spellInfo->Id;
+ break;
+ }
+ }
+
+ // no Stealth spell found
+ if (!spellId)
+ return;
+
+ // reset cooldown on it if needed
+ if(((Player*)m_caster)->HasSpellCooldown(spellId))
+ ((Player*)m_caster)->RemoveSpellCooldown(spellId);
+
+ m_caster->CastSpell(m_caster, spellId, true);
+ return;
+ }
+ // 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:
+ {
+ const SpellEntry *spell = sSpellStore.LookupEntry(24575);
+ if (!spell)
+ return;
+
+ for (int i=0; i < spell->StackAmount; ++i)
+ m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
+ return;
+ }
+ // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
+ case 29286:
+ {
+ const SpellEntry *spell = sSpellStore.LookupEntry(26464);
+ if (!spell)
+ return;
+
+ for (int i=0; i < spell->StackAmount; ++i)
+ m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
+ return;
+ }
+ // Righteous Defense
+ case 31980:
+ {
+ m_caster->CastSpell(unitTarget, 31790, true,m_CastItem,NULL,m_originalCasterGUID);
+ return;
+ }
+ // Cloak of Shadows
+ case 35729 :
+ {
+ Unit::AuraMap& Auras = m_caster->GetAuras();
+ for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter)
+ {
+ // remove all harmful spells on you...
+ if( // ignore positive and passive auras
+ !iter->second->IsPositive() && !iter->second->IsPassive() &&
+ // ignore physical auras
+ (GetSpellSchoolMask(iter->second->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)==0 &&
+ // ignore immunity persistent spells
+ !( iter->second->GetSpellProto()->AttributesEx & 0x10000 ) )
+ {
+ m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id);
+ iter = Auras.begin();
+ }
+ }
+ return;
+ }
+ // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
+ case 41967:
+ {
+ if (Unit *pet = m_caster->GetPet())
+ pet->CastSpell(pet, 28305, true);
+ return;
+ }
+ }
+
+ // 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;
+ }
+
+ // some triggered spells require specific equipment
+ if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER)
+ {
+ // main hand weapon required
+ if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND)
+ {
+ Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK);
+
+ // skip spell if no weapon in slot or broken
+ if(!item || item->IsBroken() )
+ return;
+
+ // skip spell if weapon not fit to triggered spell
+ if(!item->IsFitToSpellRequirements(spellInfo))
+ return;
+ }
+
+ // offhand hand weapon required
+ if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
+ {
+ Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK);
+
+ // skip spell if no weapon in slot or broken
+ if(!item || item->IsBroken() )
+ return;
+
+ // skip spell if weapon not fit to triggered spell
+ if(!item->IsFitToSpellRequirements(spellInfo))
+ return;
+ }
+ }
+
+ // some triggered spells must be casted instantly (for example, if next effect case instant kill caster)
+ bool instant = false;
+ for(uint32 j = i+1; j < 3; ++j)
+ {
+ if(m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL && m_spellInfo->EffectImplicitTargetA[j]==TARGET_SELF)
+ {
+ instant = true;
+ break;
+ }
+ }
+
+ if(instant)
+ {
+ if (unitTarget)
+ m_caster->CastSpell(unitTarget,spellInfo,true,m_CastItem,NULL,m_originalCasterGUID);
+ }
+ else
+ m_TriggerSpells.push_back(spellInfo);
+}
+
+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: triggering unknown spell id %effect_idx", m_spellInfo->Id,triggered_spell_id);
+ return;
+ }
+
+ if (m_CastItem)
+ DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
+
+ Spell *spell = new Spell(m_caster, spellInfo, true, m_originalCasterGUID );
+
+ SpellCastTargets targets;
+ targets.setDestination(m_targets.m_destX,m_targets.m_destY,m_targets.m_destZ);
+ spell->m_CastItem = m_CastItem;
+ spell->prepare(&targets, NULL);
+}
+
+void Spell::EffectTeleportUnits(uint32 i)
+{
+ if(!unitTarget || unitTarget->isInFlight())
+ return;
+
+ switch (m_spellInfo->EffectImplicitTargetB[i])
+ {
+ case TARGET_INNKEEPER_COORDINATES:
+ {
+ // Only players can teleport to innkeeper
+ if (unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ ((Player*)unitTarget)->TeleportTo(((Player*)unitTarget)->m_homebindMapId,((Player*)unitTarget)->m_homebindX,((Player*)unitTarget)->m_homebindY,((Player*)unitTarget)->m_homebindZ,unitTarget->GetOrientation(),unitTarget==m_caster ? TELE_TO_SPELL : 0);
+ return;
+ }
+ case TARGET_TABLE_X_Y_Z_COORDINATES:
+ {
+ // TODO: Only players can teleport?
+ if (unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
+ SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id);
+ if(!st)
+ {
+ sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u\n", m_spellInfo->Id );
+ return;
+ }
+ ((Player*)unitTarget)->TeleportTo(st->target_mapId,st->target_X,st->target_Y,st->target_Z,st->target_Orientation,unitTarget==m_caster ? TELE_TO_SPELL : 0);
+ break;
+ }
+ case TARGET_BEHIND_VICTIM:
+ {
+ // Get selected target for player (or victim for units)
+ Unit *pTarget = NULL;
+ if(m_caster->GetTypeId() == TYPEID_PLAYER)
+ pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
+ else
+ pTarget = m_caster->getVictim();
+ // No target present - return
+ if (!pTarget)
+ return;
+ // Init dest coordinates
+ uint32 mapid = m_caster->GetMapId();
+ float x = m_targets.m_destX;
+ float y = m_targets.m_destY;
+ float z = m_targets.m_destZ;
+ float orientation = pTarget->GetOrientation();
+ // Teleport
+ if(unitTarget->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
+ else
+ {
+ MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
+ WorldPacket data;
+ unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
+ unitTarget->SendMessageToSet(&data, false);
+ }
+ return;
+ }
+ default:
+ {
+ // If not exist data for dest location - return
+ if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
+ {
+ sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u\n", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id );
+ return;
+ }
+ // Init dest coordinates
+ uint32 mapid = m_caster->GetMapId();
+ float x = m_targets.m_destX;
+ float y = m_targets.m_destY;
+ float z = m_targets.m_destZ;
+ float orientation = unitTarget->GetOrientation();
+ // Teleport
+ if(unitTarget->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
+ else
+ {
+ MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
+ WorldPacket data;
+ unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
+ unitTarget->SendMessageToSet(&data, false);
+ }
+ return;
+ }
+ }
+
+ // post effects for TARGET_TABLE_X_Y_Z_COORDINATES
+ 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 (((Player*)m_caster)->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 (((Player*)m_caster)->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(!unitTarget)
+ return;
+
+ SpellImmuneList const& list = unitTarget->m_spellImmune[IMMUNITY_STATE];
+ for(SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
+ if(itr->type == m_spellInfo->EffectApplyAuraName[i])
+ return;
+
+ // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
+ if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 &&
+ (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) )
+ return;
+
+ Unit* caster = m_originalCasterGUID ? m_originalCaster : m_caster;
+ if(!caster)
+ return;
+
+ sLog.outDebug("Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[i]);
+
+ Aura* Aur = CreateAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, caster, m_CastItem);
+
+ // Now Reduce spell duration using data received at spell hit
+ int32 duration = Aur->GetAuraMaxDuration();
+ unitTarget->ApplyDiminishingToDuration(m_diminishGroup,duration,m_caster,m_diminishLevel);
+ Aur->setDiminishGroup(m_diminishGroup);
+
+ // if Aura removed and deleted, do not continue.
+ if(duration== 0 && !(Aur->IsPermanent()))
+ {
+ delete Aur;
+ return;
+ }
+
+ if(duration != Aur->GetAuraMaxDuration())
+ {
+ Aur->SetAuraMaxDuration(duration);
+ Aur->SetAuraDuration(duration);
+ }
+
+ bool added = unitTarget->AddAura(Aur);
+
+ // Aura not added and deleted in AddAura call;
+ if (!added)
+ return;
+
+ // found crash at character loading, broken pointer to Aur...
+ // Aur was deleted in AddAura()...
+ if(!Aur)
+ return;
+
+ // TODO Make a way so it works for every related spell!
+ if(unitTarget->GetTypeId()==TYPEID_PLAYER) // Negative buff should only be applied on players
+ {
+ uint32 spellId = 0;
+ if(m_spellInfo->CasterAuraStateNot==AURA_STATE_WEAKENED_SOUL || m_spellInfo->TargetAuraStateNot==AURA_STATE_WEAKENED_SOUL)
+ spellId = 6788; // Weakened Soul
+ else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_FORBEARANCE || m_spellInfo->TargetAuraStateNot==AURA_STATE_FORBEARANCE)
+ spellId = 25771; // Forbearance
+ else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_HYPOTHERMIA)
+ spellId = 41425; // Hypothermia
+ else if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages
+ spellId = 11196; // Recently Bandaged
+ else if( (m_spellInfo->AttributesEx & 0x20) && (m_spellInfo->AttributesEx2 & 0x20000) )
+ spellId = 23230; // Blood Fury - Healing Reduction
+
+ SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(spellId);
+ if (AdditionalSpellInfo)
+ {
+ // applied at target by target
+ Aura* AdditionalAura = CreateAura(AdditionalSpellInfo, 0, &m_currentBasePoints[0], unitTarget,unitTarget, 0);
+ unitTarget->AddAura(AdditionalAura);
+ sLog.outDebug("Spell: Additional Aura is: %u", AdditionalSpellInfo->EffectApplyAuraName[0]);
+ }
+ }
+
+ // Prayer of Mending (jump animation), we need formal caster instead original for correct animation
+ if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL))
+ m_caster->CastSpell(unitTarget,41637,true,NULL,Aur);
+}
+
+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 have 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 && unitTarget->GetTypeId() == TYPEID_PLAYER )
+ power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
+
+ int32 new_damage;
+ if(curPower < power)
+ new_damage = curPower;
+ else
+ new_damage = power;
+
+ unitTarget->ModifyPower(drain_power,-new_damage);
+
+ if(drain_power == POWER_MANA)
+ {
+ 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->ModifyPower(POWER_MANA,gain);
+ //send log
+ m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id,gain,POWER_MANA,false);
+ }
+}
+
+void Spell::EffectSendEvent(uint32 EffectIndex)
+{
+ if (m_caster->GetTypeId() == TYPEID_PLAYER && ((Player*)m_caster)->InBattleGround())
+ {
+ BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
+ if(bg && bg->GetStatus() == STATUS_IN_PROGRESS)
+ {
+ switch(m_spellInfo->Id)
+ {
+ case 23333: // Pickup Horde Flag
+ /*do not uncomment .
+ if(bg->GetTypeID()==BATTLEGROUND_WS)
+ bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
+ sLog.outDebug("Send Event Horde Flag Picked Up");
+ break;
+ /* not used :
+ case 23334: // Drop Horde Flag
+ if(bg->GetTypeID()==BATTLEGROUND_WS)
+ bg->EventPlayerDroppedFlag((Player*)m_caster);
+ sLog.outDebug("Drop Horde Flag");
+ break;
+ */
+ case 23335: // Pickup Alliance Flag
+ /*do not uncomment ... (it will cause crash, because of null targetobject!) anyway this is a bad way to call that event, because it would cause recursion
+ if(bg->GetTypeID()==BATTLEGROUND_WS)
+ bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
+ sLog.outDebug("Send Event Alliance Flag Picked Up");
+ break;
+ /* not used :
+ case 23336: // Drop Alliance Flag
+ if(bg->GetTypeID()==BATTLEGROUND_WS)
+ bg->EventPlayerDroppedFlag((Player*)m_caster);
+ sLog.outDebug("Drop Alliance Flag");
+ break;
+ case 23385: // Alliance Flag Returns
+ if(bg->GetTypeID()==BATTLEGROUND_WS)
+ bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
+ sLog.outDebug("Alliance Flag Returned");
+ break;
+ case 23386: // Horde Flag Returns
+ if(bg->GetTypeID()==BATTLEGROUND_WS)
+ bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
+ sLog.outDebug("Horde Flag Returned");
+ break;*/
+ case 34976:
+ /*
+ if(bg->GetTypeID()==BATTLEGROUND_EY)
+ bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
+ */
+ break;
+ default:
+ sLog.outDebug("Unknown spellid %u in BG event", m_spellInfo->Id);
+ break;
+ }
+ }
+ }
+ sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id);
+ sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
+}
+
+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;
+
+ int32 curPower = int32(unitTarget->GetPower(powertype));
+
+ // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
+ uint32 power = damage;
+ if ( powertype == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
+ power -= ((Player*)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_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
+}
+
+void Spell::EffectHeal( 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;
+ Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
+ if((*i)->GetId() == 45062)
+ damageAmount+=(*i)->GetModifier()->m_amount;
+ if (damageAmount)
+ m_caster->RemoveAurasDueToSpell(45062);
+
+ addhealth += damageAmount;
+ }
+ // Swiftmend - consumes Regrowth or Rejuvenation
+ else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND))
+ {
+ Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
+ // find most short by duration
+ Aura *targetAura = NULL;
+ for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
+ {
+ if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
+ && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) )
+ {
+ if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration())
+ targetAura = *i;
+ }
+ }
+
+ if(!targetAura)
+ {
+ sLog.outError("Target(GUID:" I64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID());
+ return;
+ }
+ int idx = 0;
+ while(idx < 3)
+ {
+ if(targetAura->GetSpellProto()->EffectApplyAuraName[idx] == SPELL_AURA_PERIODIC_HEAL)
+ break;
+ idx++;
+ }
+
+ int32 tickheal = caster->SpellHealingBonus(targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT, unitTarget);
+ int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx];
+ unitTarget->RemoveAurasDueToSpell(targetAura->GetId());
+
+ addhealth += tickheal * tickcount;
+ }
+ else
+ addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget);
+
+ bool crit = caster->isSpellCrit(unitTarget, m_spellInfo, m_spellSchoolMask, m_attackType);
+ if (crit)
+ addhealth = caster->SpellCriticalBonus(m_spellInfo, addhealth, unitTarget);
+ caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, crit);
+
+ int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
+ unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
+
+ if(caster->GetTypeId()==TYPEID_PLAYER)
+ if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
+ bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
+
+ // ignore item heals
+ if(m_CastItem)
+ return;
+
+ uint32 procHealer = PROC_FLAG_HEAL;
+ if (crit)
+ procHealer |= PROC_FLAG_CRIT_HEAL;
+
+ m_caster->ProcDamageAndSpell(unitTarget,procHealer,PROC_FLAG_HEALED,addhealth,SPELL_SCHOOL_MASK_NONE,m_spellInfo,m_IsTriggeredSpell);
+ }
+}
+
+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;
+
+ uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100;
+ caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
+
+ int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
+ unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
+
+ if(caster->GetTypeId()==TYPEID_PLAYER)
+ if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
+ bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
+ }
+}
+
+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(m_spellInfo, uint32(damage), HEAL, unitTarget);
+ caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
+ unitTarget->ModifyHealth( int32(damage) );
+ }
+}
+
+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);
+
+ int32 new_damage = int32(damage*multiplier);
+ uint32 curHealth = unitTarget->GetHealth();
+ new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
+ if(curHealth < new_damage)
+ new_damage = curHealth;
+
+ if(m_caster->isAlive())
+ {
+ new_damage = m_caster->SpellHealingBonus(m_spellInfo, new_damage, HEAL, m_caster);
+
+ m_caster->ModifyHealth(new_damage);
+
+ if(m_caster->GetTypeId() == TYPEID_PLAYER)
+ m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(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;
+ }
+
+ uint32 num_to_add;
+
+ // TODO: maybe all this can be replaced by using correct calculated `damage` value
+ if(pProto->Class != ITEM_CLASS_CONSUMABLE || m_spellInfo->SpellFamilyName != SPELLFAMILY_MAGE)
+ {
+ int32 basePoints = m_currentBasePoints[i];
+ int32 randomPoints = m_spellInfo->EffectDieSides[i];
+ if (randomPoints)
+ num_to_add = basePoints + irand(1, randomPoints);
+ else
+ num_to_add = basePoints + 1;
+ }
+ else if (pProto->MaxCount == 1)
+ num_to_add = 1;
+ else if(player->getLevel() >= m_spellInfo->spellLevel)
+ {
+ int32 basePoints = m_currentBasePoints[i];
+ float pointPerLevel = m_spellInfo->EffectRealPointsPerLevel[i];
+ num_to_add = basePoints + 1 + uint32((player->getLevel() - m_spellInfo->spellLevel)*pointPerLevel);
+ }
+ else
+ num_to_add = 2;
+
+ if (num_to_add < 1)
+ num_to_add = 1;
+ if (num_to_add > pProto->Stackable)
+ num_to_add = pProto->Stackable;
+
+ // 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)
+ pItem->SetUInt32Value(ITEM_FIELD_CREATOR,player->GetGUIDLow());
+
+ // send info to the client
+ if(pItem)
+ player->SendNewItem(pItem, num_to_add, true, true);
+
+ // we succeeded in creating at least one item, so a levelup is possible
+ player->UpdateCraftSkill(m_spellInfo->Id);
+ }
+
+ // for battleground marks send by mail if not add all expected
+ if(no_space > 0 )
+ {
+ BattleGroundTypeId bgType;
+ 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:
+ return;
+ }
+
+ if(BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgType))
+ bg->SendRewardMarkByMail(player,newitemid,no_space);
+ }
+}
+
+void Spell::EffectCreateItem(uint32 i)
+{
+ DoCreateItem(i,m_spellInfo->EffectItemType[i]);
+}
+
+void Spell::EffectPersistentAA(uint32 i)
+{
+ float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
+
+ if(Player* modOwner = m_caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius);
+
+ int32 duration = GetSpellDuration(m_spellInfo);
+ DynamicObject* dynObj = new DynamicObject;
+ if(!dynObj->Create(objmgr.GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, i, m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, duration, radius))
+ {
+ delete dynObj;
+ return;
+ }
+ dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
+ dynObj->SetUInt32Value(GAMEOBJECT_DISPLAYID, 368003);
+ dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x01eeeeee);
+ m_caster->AddDynObject(dynObj);
+ MapManager::Instance().GetMap(dynObj->GetMapId(), dynObj)->Add(dynObj);
+}
+
+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;
+
+ // Some level depends spells
+ int multipler = 0;
+ int level_diff = 0;
+ switch (m_spellInfo->Id)
+ {
+ // Restore Energy
+ case 9512:
+ level_diff = m_caster->getLevel() - 40;
+ multipler = 2;
+ break;
+ // Blood Fury
+ case 24571:
+ level_diff = m_caster->getLevel() - 60;
+ multipler = 10;
+ break;
+ // Burst of Energy
+ case 24532:
+ level_diff = m_caster->getLevel() - 60;
+ multipler = 4;
+ break;
+ default:
+ break;
+ }
+
+ if (level_diff > 0)
+ damage -= multipler * level_diff;
+
+ if(damage < 0)
+ return;
+
+ Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
+
+ if(unitTarget->GetMaxPower(power) == 0)
+ return;
+
+ unitTarget->ModifyPower(power,damage);
+ m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
+
+ // Mad Alchemist's Potion
+ if (m_spellInfo->Id == 45051)
+ {
+ // find elixirs on target
+ uint32 elixir_mask = 0;
+ Unit::AuraMap& Auras = unitTarget->GetAuras();
+ for(Unit::AuraMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
+ {
+ uint32 spell_id = itr->second->GetId();
+ if(uint32 mask = spellmgr.GetSpellElixirMask(spell_id))
+ elixir_mask |= mask;
+ }
+
+ // get available elixir mask any not active type from battle/guardian (and flask if no any)
+ elixir_mask = (elixir_mask & ELIXIR_FLASK_MASK) ^ ELIXIR_FLASK_MASK;
+
+ // get all available elixirs by mask and spell level
+ std::vector<uint32> elixirs;
+ SpellElixirMap const& m_spellElixirs = spellmgr.GetSpellElixirMap();
+ for(SpellElixirMap::const_iterator itr = m_spellElixirs.begin(); itr != m_spellElixirs.end(); ++itr)
+ {
+ if (itr->second & elixir_mask)
+ {
+ if (itr->second & (ELIXIR_UNSTABLE_MASK | ELIXIR_SHATTRATH_MASK))
+ continue;
+
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
+ if (spellInfo && (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel()))
+ continue;
+
+ elixirs.push_back(itr->first);
+ }
+ }
+
+ if (!elixirs.empty())
+ {
+ // cast random elixir on target
+ uint32 rand_spell = urand(0,elixirs.size()-1);
+ m_caster->CastSpell(unitTarget,elixirs[rand_spell],true,m_CastItem);
+ }
+ }
+}
+
+void Spell::EffectEnergisePct(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;
+ unitTarget->ModifyPower(power, gain);
+ m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
+}
+
+void Spell::SendLoot(uint64 guid, LootType loottype)
+{
+ Player* player = (Player*)m_caster;
+ if (!player)
+ return;
+
+ if (gameObjTarget)
+ {
+ switch (gameObjTarget->GetGoType())
+ {
+ case GAMEOBJECT_TYPE_DOOR:
+ case GAMEOBJECT_TYPE_BUTTON:
+ gameObjTarget->UseDoorOrButton();
+ sWorld.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:
+ // goober_scripts can be triggered if the player don't have the quest
+ if (gameObjTarget->GetGOInfo()->goober.eventId)
+ {
+ sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow());
+ sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget);
+ }
+
+ // cast goober spell
+ if (gameObjTarget->GetGOInfo()->goober.questId)
+ ///Quest require to be active for GO using
+ if(player->GetQuestStatus(gameObjTarget->GetGOInfo()->goober.questId) != QUEST_STATUS_INCOMPLETE)
+ return;
+
+ gameObjTarget->AddUniqueUse(player);
+ gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
+
+ //TODO? Objective counting called without spell check but with quest objective check
+ // if send spell id then this line will duplicate to spell casting call (double counting)
+ // So we or have this line and not required in quest_template have reqSpellIdN
+ // or must remove this line and required in DB have data in quest_template have reqSpellIdN for all quest using cases.
+ player->CastedCreatureOrGO(gameObjTarget->GetEntry(), gameObjTarget->GetGUID(), 0);
+
+ // triggering linked GO
+ if(uint32 trapEntry = gameObjTarget->GetGOInfo()->goober.linkedTrapId)
+ gameObjTarget->TriggeringLinkedGameObject(trapEntry,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());
+ sWorld.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
+ }
+ }
+
+ // Send loot
+ player->SendLoot(guid, loottype);
+}
+
+void Spell::EffectOpenLock(uint32 /*i*/)
+{
+ if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
+ {
+ sLog.outDebug( "WORLD: Open Lock - No Player Caster!");
+ return;
+ }
+
+ Player* player = (Player*)m_caster;
+
+ LootType loottype = LOOT_CORPSE;
+ 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 )
+ {
+ if(BattleGround *bg = player->GetBattleGround())// in battleground
+ {
+ if( !player->IsMounted() && // not mounted
+ !player->HasStealthAura() && // not stealthed
+ !player->HasInvisibilityAura() && // not invisible
+ player->isAlive() ) // live player
+ {
+ // check if it's correct bg
+ if(bg && bg->GetTypeID() == BATTLEGROUND_AB)
+ bg->EventPlayerClickedOnFlag(player, gameObjTarget);
+
+ return;
+ }
+ }
+ }
+ else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
+ {
+ if(BattleGround *bg = player->GetBattleGround())
+ if(bg->GetTypeID() == BATTLEGROUND_EY)
+ bg->EventPlayerClickedOnFlag(player, gameObjTarget);
+ return;
+ }
+ lockId = gameObjTarget->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;
+ }
+
+ if(!lockId) // possible case for GO and maybe for items.
+ {
+ SendLoot(guid, loottype);
+ return;
+ }
+
+ // Get LockInfo
+ LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
+
+ if (!lockInfo)
+ {
+ sLog.outError( "Spell::EffectOpenLock: %s [guid = %u] has an unknown lockId: %u!",
+ (gameObjTarget ? "gameobject" : "item"), GUID_LOPART(guid), lockId);
+ SendCastResult(SPELL_FAILED_BAD_TARGETS);
+ return;
+ }
+
+ // check key
+ for(int i = 0; i < 5; ++i)
+ {
+ // type==1 This means lockInfo->key[i] is an item
+ if(lockInfo->keytype[i]==LOCK_KEY_ITEM && lockInfo->key[i] && m_CastItem && m_CastItem->GetEntry()==lockInfo->key[i])
+ {
+ SendLoot(guid, loottype);
+ return;
+ }
+ }
+
+ uint32 SkillId = 0;
+ // Check and skill-up skill
+ if( m_spellInfo->Effect[1] == SPELL_EFFECT_SKILL )
+ SkillId = m_spellInfo->EffectMiscValue[1];
+ // pickpocketing spells
+ else if( m_spellInfo->EffectMiscValue[0] == LOCKTYPE_PICKLOCK )
+ SkillId = SKILL_LOCKPICKING;
+
+ // skill bonus provided by casting spell (mostly item spells)
+ uint32 spellSkillBonus = uint32(m_currentBasePoints[0]+1);
+
+ uint32 reqSkillValue = lockInfo->requiredminingskill;
+
+ if(lockInfo->requiredlockskill) // required pick lock skill applying
+ {
+ if(SkillId != SKILL_LOCKPICKING) // wrong skill (cheating?)
+ {
+ SendCastResult(SPELL_FAILED_FIZZLE);
+ return;
+ }
+
+ reqSkillValue = lockInfo->requiredlockskill;
+ }
+ else if(SkillId == SKILL_LOCKPICKING) // apply picklock skill to wrong target
+ {
+ SendCastResult(SPELL_FAILED_BAD_TARGETS);
+ return;
+ }
+
+ if ( SkillId )
+ {
+ loottype = LOOT_SKINNING;
+ if ( player->GetSkillValue(SkillId) + spellSkillBonus < reqSkillValue )
+ {
+ SendCastResult(SPELL_FAILED_LOW_CASTLEVEL);
+ return;
+ }
+
+ // update skill if really known
+ uint32 SkillValue = player->GetPureSkillValue(SkillId);
+ if(SkillValue) // non only item base skill
+ {
+ if(gameObjTarget)
+ {
+ // Allow one skill-up until respawned
+ if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) &&
+ player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue) )
+ gameObjTarget->AddToSkillupList( player->GetGUIDLow() );
+ }
+ else if(itemTarget)
+ {
+ // Do one skill-up
+ uint32 SkillValue = player->GetPureSkillValue(SkillId);
+ player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue);
+ }
+ }
+ }
+
+ SendLoot(guid, loottype);
+}
+
+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 i= PERM_ENCHANTMENT_SLOT; i<=TEMP_ENCHANTMENT_SLOT; ++i)
+ {
+ if(m_CastItem->GetEnchantmentId(EnchantmentSlot(i)))
+ pNewItem->SetEnchantment(EnchantmentSlot(i), m_CastItem->GetEnchantmentId(EnchantmentSlot(i)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(i)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(i)));
+ }
+
+ 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;
+ uint8 msg = player->CanEquipItem( 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->EquipItem( dest, pNewItem, true);
+ player->AutoUnequipOffhandIfNeed();
+ return;
+ }
+ }
+
+ // fail
+ delete pNewItem;
+}
+
+void Spell::EffectOpenSecretSafe(uint32 i)
+{
+ EffectOpenLock(i); //no difference for now
+}
+
+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 == 2 && !(p_target->GetWeaponProficiency() & subClassMask))
+ {
+ p_target->AddWeaponProficiency(subClassMask);
+ p_target->SendProficiency(uint8(0x02),p_target->GetWeaponProficiency());
+ }
+ if(m_spellInfo->EquippedItemClass == 4 && !(p_target->GetArmorProficiency() & subClassMask))
+ {
+ p_target->AddArmorProficiency(subClassMask);
+ p_target->SendProficiency(uint8(0x04),p_target->GetArmorProficiency());
+ }
+}
+
+void Spell::EffectApplyAreaAura(uint32 i)
+{
+ if(!unitTarget)
+ return;
+ if(!unitTarget->isAlive())
+ return;
+
+ AreaAura* Aur = new AreaAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, m_caster, m_CastItem);
+ unitTarget->AddAura(Aur);
+}
+
+void Spell::EffectSummonType(uint32 i)
+{
+ switch(m_spellInfo->EffectMiscValueB[i])
+ {
+ case SUMMON_TYPE_GUARDIAN:
+ case SUMMON_TYPE_POSESSED:
+ case SUMMON_TYPE_POSESSED2:
+ EffectSummonGuardian(i);
+ break;
+ case SUMMON_TYPE_WILD:
+ EffectSummonWild(i);
+ break;
+ case SUMMON_TYPE_DEMON:
+ EffectSummonDemon(i);
+ break;
+ case SUMMON_TYPE_SUMMON:
+ EffectSummon(i);
+ break;
+ case SUMMON_TYPE_CRITTER:
+ case SUMMON_TYPE_CRITTER2:
+ EffectSummonCritter(i);
+ break;
+ case SUMMON_TYPE_TOTEM_SLOT1:
+ case SUMMON_TYPE_TOTEM_SLOT2:
+ case SUMMON_TYPE_TOTEM_SLOT3:
+ case SUMMON_TYPE_TOTEM_SLOT4:
+ case SUMMON_TYPE_TOTEM:
+ EffectSummonTotem(i);
+ break;
+ case SUMMON_TYPE_UNKNOWN1:
+ case SUMMON_TYPE_UNKNOWN2:
+ case SUMMON_TYPE_UNKNOWN3:
+ case SUMMON_TYPE_UNKNOWN4:
+ case SUMMON_TYPE_UNKNOWN5:
+ case SUMMON_TYPE_UNKNOWN6:
+ break;
+ default:
+ sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
+ break;
+ }
+}
+
+void Spell::EffectSummon(uint32 i)
+{
+ if(m_caster->GetPetGUID())
+ return;
+
+ if(!unitTarget)
+ return;
+ uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
+ if(!pet_entry)
+ return;
+ uint32 level = m_caster->getLevel();
+ Pet* spawnCreature = new Pet(SUMMON_PET);
+
+ if(spawnCreature->LoadPetFromDB(m_caster,pet_entry))
+ {
+ // set timer for unsummon
+ int32 duration = GetSpellDuration(m_spellInfo);
+ if(duration > 0)
+ spawnCreature->SetDuration(duration);
+
+ return;
+ }
+
+ Map *map = m_caster->GetMap();
+ uint32 pet_number = objmgr.GeneratePetNumber();
+ if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),map,m_spellInfo->EffectMiscValue[i], pet_number))
+ {
+ sLog.outErrorDb("Spell::EffectSummon: no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
+ delete spawnCreature;
+ return;
+ }
+
+ // Summon in dest location
+ float x,y,z;
+ if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
+ {
+ x = m_targets.m_destX;
+ y = m_targets.m_destY;
+ z = m_targets.m_destZ;
+ }
+ else
+ m_caster->GetClosePoint(x,y,z,spawnCreature->GetObjectSize());
+
+ spawnCreature->Relocate(x,y,z,-m_caster->GetOrientation());
+
+ if(!spawnCreature->IsPositionValid())
+ {
+ sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
+ delete spawnCreature;
+ return;
+ }
+
+ // set timer for unsummon
+ int32 duration = GetSpellDuration(m_spellInfo);
+ if(duration > 0)
+ spawnCreature->SetDuration(duration);
+
+ spawnCreature->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID());
+ spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0);
+ spawnCreature->setPowerType(POWER_MANA);
+ spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
+ spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0);
+ spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_0,2048);
+ spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
+ spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0);
+ spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE,0);
+ spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP,1000);
+ spawnCreature->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID());
+ spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
+
+ spawnCreature->InitStatsForLevel(level);
+
+ spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
+
+ spawnCreature->AIM_Initialize();
+ spawnCreature->InitPetCreateSpells();
+ spawnCreature->SetHealth(spawnCreature->GetMaxHealth());
+ spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA));
+
+ std::string name = m_caster->GetName();
+ name.append(petTypeSuffix[spawnCreature->getPetType()]);
+ spawnCreature->SetName( name );
+
+ map->Add((Creature*)spawnCreature);
+
+ if(m_caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ m_caster->SetPet(spawnCreature);
+ spawnCreature->GetCharmInfo()->SetReactState( REACT_DEFENSIVE );
+ spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT);
+ ((Player*)m_caster)->PetSpellInitialize();
+ }
+}
+
+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==SPELL_ID_GENERIC_LEARN) ? damage : m_spellInfo->EffectTriggerSpell[i];
+ player->learnSpell(spellToLearn);
+
+ sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
+}
+
+void Spell::EffectDispel(uint32 i)
+{
+ if(!unitTarget)
+ return;
+
+ // Fill possible dispell list
+ std::vector <Aura *> 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->GetAuras();
+ for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
+ {
+ Aura *aur = (*itr).second;
+ if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
+ {
+ if(aur->GetSpellProto()->Dispel == DISPEL_MAGIC)
+ {
+ bool positive = true;
+ if (!aur->IsPositive())
+ positive = false;
+ else
+ positive = (aur->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)==0;
+
+ // do not remove positive auras if friendly target
+ // negative auras if non-friendly target
+ if(positive == unitTarget->IsFriendlyTo(m_caster))
+ continue;
+ }
+ // Add aura to dispel list
+ dispel_list.push_back(aur);
+ }
+ }
+ // Ok if exist some buffs for dispel try dispel it
+ if (!dispel_list.empty())
+ {
+ std::list < std::pair<uint32,uint64> > success_list;// (spell_id,casterGuid)
+ std::list < uint32 > fail_list; // spell_id
+ int32 list_size = dispel_list.size();
+ // Dispell N = damage buffs (or while exist buffs for dispel)
+ for (int32 count=0; count < damage && list_size > 0; ++count)
+ {
+ // Random select buff for dispel
+ Aura *aur = dispel_list[urand(0, list_size-1)];
+
+ SpellEntry const* spellInfo = aur->GetSpellProto();
+ // Base dispel chance
+ // TODO: possible chance depend from spell level??
+ int32 miss_chance = 0;
+ // Apply dispel mod from aura caster
+ if (Unit *caster = aur->GetCaster())
+ {
+ if ( Player* modOwner = caster->GetSpellModOwner() )
+ modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this);
+ }
+ // Try dispel
+ if (roll_chance_i(miss_chance))
+ fail_list.push_back(aur->GetId());
+ else
+ success_list.push_back(std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
+ // Remove buff from list for prevent doubles
+ for (std::vector<Aura *>::iterator j = dispel_list.begin(); j != dispel_list.end(); )
+ {
+ Aura *dispeled = *j;
+ if (dispeled->GetId() == aur->GetId() && dispeled->GetCasterGUID() == aur->GetCasterGUID())
+ {
+ j = dispel_list.erase(j);
+ --list_size;
+ }
+ else
+ ++j;
+ }
+ }
+ // Send success log and really remove auras
+ if (!success_list.empty())
+ {
+ int32 count = success_list.size();
+ WorldPacket data(SMSG_SPELLDISPELLOG, 8+8+4+1+4+count*5);
+ data.append(unitTarget->GetPackGUID()); // Victim GUID
+ data.append(m_caster->GetPackGUID()); // Caster GUID
+ data << uint32(m_spellInfo->Id); // Dispell spell id
+ data << uint8(0); // not used
+ data << uint32(count); // count
+ for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
+ {
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
+ data << uint32(spellInfo->Id); // Spell Id
+ data << uint8(0); // 0 - dispeled !=0 cleansed
+ unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster);
+ }
+ m_caster->SendMessageToSet(&data, true);
+
+ // On succes dispel
+ // Devour Magic
+ if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == 12)
+ {
+ uint32 heal_spell = 0;
+ switch (m_spellInfo->Id)
+ {
+ case 19505: heal_spell = 19658; break;
+ case 19731: heal_spell = 19732; break;
+ case 19734: heal_spell = 19733; break;
+ case 19736: heal_spell = 19735; break;
+ case 27276: heal_spell = 27278; break;
+ case 27277: heal_spell = 27279; break;
+ default:
+ sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id);
+ break;
+ }
+ if (heal_spell)
+ m_caster->CastSpell(m_caster, heal_spell, true);
+ }
+ }
+ // Send fail log to client
+ if (!fail_list.empty())
+ {
+ // Failed to dispell
+ WorldPacket data(SMSG_DISPEL_FAILED, 8+8+4+4*fail_list.size());
+ data << uint64(m_caster->GetGUID()); // Caster GUID
+ data << uint64(unitTarget->GetGUID()); // Victim GUID
+ data << uint32(m_spellInfo->Id); // Dispell spell id
+ for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j)
+ data << uint32(*j); // Spell Id
+ m_caster->SendMessageToSet(&data, true);
+ }
+ }
+}
+
+void Spell::EffectDualWield(uint32 /*i*/)
+{
+ if (unitTarget->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)unitTarget)->SetCanDualWield(true);
+}
+
+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_STUNDED | UNIT_STAT_FLEEING ) )
+ return;
+
+ float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY);
+
+ if ( unitTarget->GetTypeId() == TYPEID_PLAYER )
+ {
+ // For players just turn them
+ WorldPacket data;
+ ((Player*)unitTarget)->BuildTeleportAckMsg(&data, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle);
+ ((Player*)unitTarget)->GetSession()->SendPacket( &data );
+ ((Player*)unitTarget)->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false);
+ }
+ else
+ {
+ // Set creature Distracted, Stop it, And turn it
+ unitTarget->SetOrientation(angle);
+ unitTarget->StopMoving();
+ unitTarget->GetMotionMaster()->MoveDistract(damage*1000);
+ }
+}
+
+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)
+ {
+ int32 chance = 10 + int32(m_caster->getLevel()) - int32(unitTarget->getLevel());
+
+ if (chance > irand(0, 19))
+ {
+ // Stealing successful
+ //sLog.outDebug("Sending loot from pickpocket");
+ ((Player*)m_caster)->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING);
+ }
+ else
+ {
+ // Reveal action + get attack
+ m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ if (((Creature*)unitTarget)->AI())
+ ((Creature*)unitTarget)->AI()->AttackStart(m_caster);
+ }
+ }
+}
+
+void Spell::EffectAddFarsight(uint32 i)
+{
+ float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
+ int32 duration = GetSpellDuration(m_spellInfo);
+ DynamicObject* dynObj = new DynamicObject;
+ if(!dynObj->Create(objmgr.GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, i, m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, duration, radius))
+ {
+ delete dynObj;
+ return;
+ }
+ dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
+ dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
+ m_caster->AddDynObject(dynObj);
+ MapManager::Instance().GetMap(dynObj->GetMapId(), dynObj)->Add(dynObj);
+ m_caster->SetUInt64Value(PLAYER_FARSIGHT, dynObj->GetGUID());
+}
+
+void Spell::EffectSummonWild(uint32 i)
+{
+ uint32 creature_entry = m_spellInfo->EffectMiscValue[i];
+ if(!creature_entry)
+ return;
+
+ uint32 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 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
+ if(skill202)
+ {
+ level = skill202/5;
+ }
+ }
+ }
+
+ // select center of summon position
+ float center_x = m_targets.m_destX;
+ float center_y = m_targets.m_destY;
+ float center_z = m_targets.m_destZ;
+
+ float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
+
+ int32 amount = damage > 0 ? damage : 1;
+
+ for(int32 count = 0; count < amount; ++count)
+ {
+ float px, py, pz;
+ // If dest location if present
+ if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
+ {
+ // Summon 1 unit in dest location
+ if (count == 0)
+ {
+ px = m_targets.m_destX;
+ py = m_targets.m_destY;
+ pz = m_targets.m_destZ;
+ }
+ // Summon in random point all other units if location present
+ else
+ m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
+ }
+ // Summon if dest location not present near caster
+ else
+ m_caster->GetClosePoint(px,py,pz,3.0f);
+
+ int32 duration = GetSpellDuration(m_spellInfo);
+
+ TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
+
+ m_caster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
+ }
+}
+
+void Spell::EffectSummonGuardian(uint32 i)
+{
+ uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
+ if(!pet_entry)
+ return;
+
+ // Jewelery statue case (totem like)
+ if(m_spellInfo->SpellIconID==2056)
+ {
+ EffectSummonTotem(i);
+ return;
+ }
+
+ // set timer for unsummon
+ int32 duration = GetSpellDuration(m_spellInfo);
+
+ // Search old Guardian only for players (if casted spell not have duration or cooldown)
+ // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time
+ // so this code hack in fact
+ if( m_caster->GetTypeId() == TYPEID_PLAYER && (duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0) )
+ if(((Player*)m_caster)->HasGuardianWithEntry(pet_entry))
+ return; // find old guardian, ignore summon
+
+ // in another case summon new
+ uint32 level = m_caster->getLevel();
+
+ // level of pet 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 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
+ if(skill202)
+ {
+ level = skill202/5;
+ }
+ }
+ }
+
+ // select center of summon position
+ float center_x = m_targets.m_destX;
+ float center_y = m_targets.m_destY;
+ float center_z = m_targets.m_destZ;
+
+ float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
+
+ int32 amount = damage > 0 ? damage : 1;
+
+ for(int32 count = 0; count < amount; ++count)
+ {
+ Pet* spawnCreature = new Pet(GUARDIAN_PET);
+
+ Map *map = m_caster->GetMap();
+ uint32 pet_number = objmgr.GeneratePetNumber();
+ if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map,m_spellInfo->EffectMiscValue[i], pet_number))
+ {
+ sLog.outError("no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
+ delete spawnCreature;
+ return;
+ }
+
+ float px, py, pz;
+ // If dest location if present
+ if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
+ {
+ // Summon 1 unit in dest location
+ if (count == 0)
+ {
+ px = m_targets.m_destX;
+ py = m_targets.m_destY;
+ pz = m_targets.m_destZ;
+ }
+ // Summon in random point all other units if location present
+ else
+ m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
+ }
+ // Summon if dest location not present near caster
+ else
+ m_caster->GetClosePoint(px,py,pz,spawnCreature->GetObjectSize());
+
+ spawnCreature->Relocate(px,py,pz,m_caster->GetOrientation());
+
+ if(!spawnCreature->IsPositionValid())
+ {
+ sLog.outError("ERROR: Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %d Y: ^%d)", spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
+ delete spawnCreature;
+ return;
+ }
+
+ if(duration > 0)
+ spawnCreature->SetDuration(duration);
+
+ spawnCreature->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID());
+ spawnCreature->setPowerType(POWER_MANA);
+ spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0);
+ spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
+ spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0);
+ spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
+ spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0);
+ spawnCreature->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID());
+ spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
+
+ spawnCreature->InitStatsForLevel(level);
+ spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
+
+ spawnCreature->AIM_Initialize();
+
+ if(m_caster->GetTypeId()==TYPEID_PLAYER)
+ ((Player*)m_caster)->AddGuardian(spawnCreature);
+
+ map->Add((Creature*)spawnCreature);
+ }
+}
+
+void Spell::EffectTeleUnitsFaceCaster(uint32 i)
+{
+ if(!unitTarget)
+ return;
+
+ if(unitTarget->isInFlight())
+ return;
+
+ uint32 mapid = m_caster->GetMapId();
+ float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
+
+ float fx,fy,fz;
+ m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
+
+ if(unitTarget->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, -m_caster->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
+ else
+ MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)m_caster, fx, fy, fz, -m_caster->GetOrientation());
+}
+
+void Spell::EffectLearnSkill(uint32 i)
+{
+ if(unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ if(damage < 0)
+ return;
+
+ uint32 skillid = m_spellInfo->EffectMiscValue[i];
+ uint16 skillval = ((Player*)unitTarget)->GetPureSkillValue(skillid);
+ ((Player*)unitTarget)->SetSkill(skillid, skillval?skillval:1, damage*75);
+}
+
+void Spell::EffectAddHonor(uint32 /*i*/)
+{
+ if(unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ sLog.outDebug("SpellEffect::AddHonor called for spell_id %u , that rewards %d honor points to player: %u", m_spellInfo->Id, this->damage, ((Player*)unitTarget)->GetGUIDLow());
+
+ // TODO: find formula for honor reward based on player's level!
+
+ // now fixed only for level 70 players:
+ if (((Player*)unitTarget)->getLevel() == 70)
+ ((Player*)unitTarget)->RewardHonor(NULL, 1, this->damage);
+}
+
+void Spell::EffectTradeSkill(uint32 /*i*/)
+{
+ if(unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
+ // uint32 skillid = m_spellInfo->EffectMiscValue[i];
+ // uint16 skillmax = ((Player*)unitTarget)->(skillid);
+ // ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75);
+}
+
+void Spell::EffectEnchantItemPerm(uint32 i)
+{
+ if(m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+ if (!itemTarget)
+ return;
+
+ Player* p_caster = (Player*)m_caster;
+
+ p_caster->UpdateCraftSkill(m_spellInfo->Id);
+
+ if (m_spellInfo->EffectMiscValue[i])
+ {
+ uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
+
+ 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("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::EffectEnchantItemTmp(uint32 i)
+{
+ if(m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ Player* p_caster = (Player*)m_caster;
+
+ if(!itemTarget)
+ return;
+
+ uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
+
+ // Shaman Rockbiter Weapon
+ if(i==0 && m_spellInfo->Effect[1]==SPELL_EFFECT_DUMMY)
+ {
+ int32 enchnting_damage = m_currentBasePoints[1]+1;
+
+ // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value
+ // with already applied percent bonus from Elemental Weapons talent
+ // 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(enchnting_damage)
+ {
+ // Rank 1
+ case 2: enchant_id = 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
+ // Rank 2
+ case 4: enchant_id = 6; break; // 0% [ 7% == 4, 14% == 4]
+ case 5: enchant_id = 3025; break; // 20%
+ // Rank 3
+ case 6: enchant_id = 1; break; // 0% [ 7% == 6, 14% == 6]
+ case 7: enchant_id = 3027; break; // 20%
+ // Rank 4
+ case 9: enchant_id = 3032; break; // 0% [ 7% == 6]
+ case 10: enchant_id = 503; break; // 14%
+ case 11: enchant_id = 3031; break; // 20%
+ // Rank 5
+ case 15: enchant_id = 3035; break; // 0%
+ case 16: enchant_id = 1663; break; // 7%
+ case 17: enchant_id = 3033; break; // 14%
+ case 18: enchant_id = 3034; break; // 20%
+ // Rank 6
+ case 28: enchant_id = 3038; break; // 0%
+ case 29: enchant_id = 683; break; // 7%
+ case 31: enchant_id = 3036; break; // 14%
+ case 33: enchant_id = 3037; break; // 20%
+ // Rank 7
+ case 40: enchant_id = 3041; break; // 0%
+ case 42: enchant_id = 1664; break; // 7%
+ case 45: enchant_id = 3039; break; // 14%
+ case 48: enchant_id = 3040; break; // 20%
+ // Rank 8
+ case 49: enchant_id = 3044; break; // 0%
+ case 52: enchant_id = 2632; break; // 7%
+ case 55: enchant_id = 3042; break; // 14%
+ case 58: enchant_id = 3043; break; // 20%
+ // Rank 9
+ case 62: enchant_id = 2633; break; // 0%
+ case 66: enchant_id = 3018; break; // 7%
+ case 70: enchant_id = 3019; break; // 14%
+ case 74: enchant_id = 3020; break; // 20%
+ default:
+ sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage);
+ return;
+ }
+ }
+
+ 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==215)
+ duration = 1800; // 30 mins
+ // some fishing pole bonuses
+ else if(m_spellInfo->SpellVisual==563)
+ duration = 600; // 10 mins
+ // shaman rockbiter enchantments
+ else if(m_spellInfo->SpellVisual==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("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_PLAYER)
+ return;
+
+ Creature* creatureTarget = (Creature*)unitTarget;
+
+ if(creatureTarget->isPet())
+ return;
+
+ if(m_caster->getClass() == CLASS_HUNTER)
+ {
+ // cast finish successfully
+ //SendChannelUpdate(0);
+ finish();
+
+ Pet* pet = new Pet(HUNTER_PET);
+
+ if(!pet->CreateBaseAtCreature(creatureTarget))
+ {
+ delete pet;
+ return;
+ }
+
+ creatureTarget->setDeathState(JUST_DIED);
+ creatureTarget->RemoveCorpse();
+ creatureTarget->SetHealth(0); // just for nice GM-mode view
+
+ pet->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_caster->GetGUID());
+ pet->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID());
+ pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
+ pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
+
+ if(!pet->InitStatsForLevel(creatureTarget->getLevel()))
+ {
+ sLog.outError("ERROR: InitStatsForLevel() in EffectTameCreature failed! Pet deleted.");
+ delete pet;
+ return;
+ }
+
+ // prepare visual effect for levelup
+ pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel()-1);
+
+ pet->GetCharmInfo()->SetPetNumber(objmgr.GeneratePetNumber(), true);
+ // this enables pet details window (Shift+P)
+ pet->AIM_Initialize();
+ pet->InitPetCreateSpells();
+ pet->SetHealth(pet->GetMaxHealth());
+
+ MapManager::Instance().GetMap(pet->GetMapId(), pet)->Add((Creature*)pet);
+
+ // visual effect for levelup
+ pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel());
+
+ if(m_caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ m_caster->SetPet(pet);
+ pet->SavePetToDB(PET_SAVE_AS_CURRENT);
+ ((Player*)m_caster)->PetSpellInitialize();
+ }
+ }
+}
+
+void Spell::EffectSummonPet(uint32 i)
+{
+ uint32 petentry = m_spellInfo->EffectMiscValue[i];
+
+ Pet *OldSummon = m_caster->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;
+
+ MapManager::Instance().GetMap(OldSummon->GetMapId(), OldSummon)->Remove((Creature*)OldSummon,false);
+ OldSummon->SetMapId(m_caster->GetMapId());
+
+ float px, py, pz;
+ m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
+
+ OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
+ MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)->Add((Creature*)OldSummon);
+
+ if(m_caster->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled() )
+ {
+ ((Player*)m_caster)->PetSpellInitialize();
+ }
+ return;
+ }
+
+ if(m_caster->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)m_caster)->RemovePet(OldSummon,(OldSummon->getPetType()==HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false);
+ else
+ return;
+ }
+
+ Pet* NewSummon = new Pet;
+
+ // petentry==0 for hunter "call pet" (current pet summoned if any)
+ if(NewSummon->LoadPetFromDB(m_caster,petentry))
+ {
+ if(NewSummon->getPetType()==SUMMON_PET)
+ {
+ // Remove Demonic Sacrifice auras (known pet)
+ Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
+ {
+ if((*itr)->GetModifier()->m_miscvalue==2228)
+ {
+ m_caster->RemoveAurasDueToSpell((*itr)->GetId());
+ itr = auraClassScripts.begin();
+ }
+ else
+ ++itr;
+ }
+ }
+
+ return;
+ }
+
+ // not error in case fail hunter call pet
+ if(!petentry)
+ {
+ delete NewSummon;
+ return;
+ }
+
+ CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(petentry);
+
+ if(!cInfo)
+ {
+ sLog.outError("EffectSummonPet: creature entry %u not found.",petentry);
+ delete NewSummon;
+ return;
+ }
+
+ Map *map = m_caster->GetMap();
+ uint32 pet_number = objmgr.GeneratePetNumber();
+ if(!NewSummon->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, petentry, pet_number))
+ {
+ delete NewSummon;
+ return;
+ }
+
+ float px, py, pz;
+ m_caster->GetClosePoint(px, py, pz, NewSummon->GetObjectSize());
+
+ NewSummon->Relocate(px, py, pz, m_caster->GetOrientation());
+
+ if(!NewSummon->IsPositionValid())
+ {
+ sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", NewSummon->GetGUIDLow(), NewSummon->GetEntry(), NewSummon->GetPositionX(), NewSummon->GetPositionY());
+ delete NewSummon;
+ return;
+ }
+
+ uint32 petlevel = m_caster->getLevel();
+ NewSummon->setPetType(SUMMON_PET);
+
+ uint32 faction = m_caster->getFaction();
+ if(m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->isTotem())
+ {
+ Unit* owner = ((Totem*)m_caster)->GetOwner();
+ if(owner)
+ faction = owner->getFaction();
+ NewSummon->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE);
+ }
+
+ NewSummon->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_caster->GetGUID());
+ NewSummon->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID());
+ NewSummon->SetUInt32Value(UNIT_NPC_FLAGS , 0);
+ NewSummon->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction);
+ NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_0,2048);
+ NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
+ NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,time(NULL));
+ NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE,0);
+ NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP,1000);
+ NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
+
+ NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true);
+ // this enables pet details window (Shift+P)
+
+ // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later
+ NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
+
+ NewSummon->InitStatsForLevel( petlevel);
+ NewSummon->InitPetCreateSpells();
+
+ if(NewSummon->getPetType()==SUMMON_PET)
+ {
+ // Remove Demonic Sacrifice auras (new pet)
+ Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
+ {
+ if((*itr)->GetModifier()->m_miscvalue==2228)
+ {
+ m_caster->RemoveAurasDueToSpell((*itr)->GetId());
+ itr = auraClassScripts.begin();
+ }
+ else
+ ++itr;
+ }
+
+ // generate new name for summon pet
+ std::string new_name=objmgr.GeneratePetName(petentry);
+ if(!new_name.empty())
+ NewSummon->SetName(new_name);
+ }
+ else if(NewSummon->getPetType()==HUNTER_PET)
+ NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED);
+
+ NewSummon->AIM_Initialize();
+ NewSummon->SetHealth(NewSummon->GetMaxHealth());
+ NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA));
+
+ map->Add((Creature*)NewSummon);
+
+ m_caster->SetPet(NewSummon);
+ sLog.outDebug("New Pet has guid %u", NewSummon->GetGUIDLow());
+
+ if(m_caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
+ ((Player*)m_caster)->PetSpellInitialize();
+ }
+}
+
+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->SetTP(pet->m_TrainingPoints - pet->GetTPForSpell(learn_spellproto->Id));
+ pet->learnSpell(learn_spellproto->Id);
+
+ pet->SavePetToDB(PET_SAVE_AS_CURRENT);
+ _player->PetSpellInitialize();
+}
+
+void Spell::EffectTaunt(uint32 /*i*/)
+{
+ // 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->GetTypeId() != TYPEID_PLAYER)
+ {
+ if(unitTarget->getVictim()==m_caster)
+ {
+ SendCastResult(SPELL_FAILED_DONT_REPORT);
+ return;
+ }
+ }
+
+ // Also use this effect to set the taunter's threat to the taunted creature's highest value
+ if(unitTarget->CanHaveThreatList() && unitTarget->getThreatManager().getCurrentVictim())
+ unitTarget->getThreatManager().addThreat(m_caster,unitTarget->getThreatManager().getCurrentVictim()->getThreat());
+}
+
+void Spell::EffectWeaponDmg(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 (int j = 0; 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:
+ if (j < i) // we must calculate only at last weapon effect
+ return;
+ break;
+ }
+ }
+
+ // some spell specific modifiers
+ bool customBonusDamagePercentMod = false;
+ float bonusDamagePercentMod = 1.0f; // applied to fixed effect damage bonus if set customBonusDamagePercentMod
+ float weaponDamagePercentMod = 1.0f; // applied to weapon damage (and to fixed effect damage bonus if customBonusDamagePercentMod not set
+ float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
+ bool normalized = false;
+
+ int32 spell_bonus = 0; // bonus specific for spell
+ switch(m_spellInfo->SpellFamilyName)
+ {
+ case SPELLFAMILY_WARRIOR:
+ {
+ // Whirlwind, single only spell with 2 weapon white damage apply if have
+ if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x00000400000000LL))
+ {
+ if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK,true))
+ spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized);
+ }
+ // Devastate bonus and sunder armor refresh
+ else if(m_spellInfo->SpellVisual == 671 && m_spellInfo->SpellIconID == 1508)
+ {
+ customBonusDamagePercentMod = true;
+ bonusDamagePercentMod = 0.0f; // only applied if auras found
+
+ Unit::AuraList const& list = unitTarget->GetAurasByType(SPELL_AURA_MOD_RESISTANCE);
+ for(Unit::AuraList::const_iterator itr=list.begin();itr!=list.end();++itr)
+ {
+ SpellEntry const *proto = (*itr)->GetSpellProto();
+ if(proto->SpellVisual == 406 && proto->SpellIconID == 565)
+ {
+ int32 duration = GetSpellDuration(proto);
+ (*itr)->SetAuraDuration(duration);
+ (*itr)->UpdateAuraDuration();
+ bonusDamagePercentMod += 1.0f; // +100%
+ }
+ }
+ }
+ break;
+ }
+ case SPELLFAMILY_ROGUE:
+ {
+ // Ambush
+ if(m_spellInfo->SpellFamilyFlags & 0x00000200LL)
+ {
+ customBonusDamagePercentMod = true;
+ bonusDamagePercentMod = 2.5f; // 250%
+ }
+ // Mutilate (for each hand)
+ else if(m_spellInfo->SpellFamilyFlags & 0x600000000LL)
+ {
+ bool found = false;
+ // fast check
+ if(unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON))
+ found = true;
+ // full aura scan
+ else
+ {
+ Unit::AuraMap const& auras = unitTarget->GetAuras();
+ for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
+ {
+ if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON)
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if(found)
+ totalDamagePercentMod *= 1.5f; // 150% if poisoned
+ }
+ break;
+ }
+ case SPELLFAMILY_PALADIN:
+ {
+ // Seal of Command - receive benefit from Spell Damage and Healing
+ if(m_spellInfo->SpellFamilyFlags & 0x00000002000000LL)
+ {
+ spell_bonus += int32(0.20f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)));
+ spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget));
+ }
+ break;
+ }
+ case SPELLFAMILY_SHAMAN:
+ {
+ // Skyshatter Harness item set bonus
+ // Stormstrike
+ if(m_spellInfo->SpellFamilyFlags & 0x001000000000LL)
+ {
+ Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
+ {
+ // Stormstrike AP Buff
+ if ( (*i)->GetModifier()->m_miscvalue == 5634 )
+ {
+ m_caster->CastSpell(m_caster,38430,true,NULL,*i);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ int32 fixed_bonus = 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;
+
+ // applied only to prev.effects fixed damage
+ if(customBonusDamagePercentMod)
+ fixed_bonus = int32(fixed_bonus*bonusDamagePercentMod);
+ else
+ fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod);
+ break;
+ default:
+ break; // not weapon damage effect, just skip
+ }
+ }
+
+ // non-weapon damage
+ int32 bonus = spell_bonus + fixed_bonus;
+
+ // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
+ if(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 = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
+ bonus = int32(bonus*weapon_total_pct);
+ }
+
+ // + weapon damage with applied weapon% dmg to base weapon damage in call
+ bonus += int32(m_caster->CalculateDamage(m_attackType, normalized)*weaponDamagePercentMod);
+
+ // total damage
+ bonus = int32(bonus*totalDamagePercentMod);
+
+ // prevent negative damage
+ uint32 eff_damage = uint32(bonus > 0 ? bonus : 0);
+
+ const uint32 nohitMask = HITINFO_ABSORB | HITINFO_RESIST | HITINFO_MISS;
+
+ uint32 hitInfo = 0;
+ VictimState victimState = VICTIMSTATE_NORMAL;
+ uint32 blocked_dmg = 0;
+ uint32 absorbed_dmg = 0;
+ uint32 resisted_dmg = 0;
+ CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
+
+ m_caster->DoAttackDamage(unitTarget, &eff_damage, &cleanDamage, &blocked_dmg, m_spellSchoolMask, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, m_attackType, m_spellInfo, m_IsTriggeredSpell);
+
+ if ((hitInfo & nohitMask) && m_attackType != RANGED_ATTACK) // not send ranged miss/etc
+ m_caster->SendAttackStateUpdate(hitInfo & nohitMask, unitTarget, 1, m_spellSchoolMask, eff_damage, absorbed_dmg, resisted_dmg, VICTIMSTATE_NORMAL, blocked_dmg);
+
+ bool criticalhit = (hitInfo & HITINFO_CRITICALHIT);
+ m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, eff_damage, m_spellSchoolMask, absorbed_dmg, resisted_dmg, false, blocked_dmg, criticalhit);
+
+ if (eff_damage > (absorbed_dmg + resisted_dmg + blocked_dmg))
+ {
+ eff_damage -= (absorbed_dmg + resisted_dmg + blocked_dmg);
+ }
+ else
+ {
+ cleanDamage.damage += eff_damage;
+ eff_damage = 0;
+ }
+
+ // SPELL_SCHOOL_NORMAL use for weapon-like threat and rage calculation
+ m_caster->DealDamage(unitTarget, eff_damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, true);
+
+ // Hemorrhage
+ if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000))
+ {
+ if(m_caster->GetTypeId()==TYPEID_PLAYER)
+ ((Player*)m_caster)->AddComboPoints(unitTarget, 1);
+ }
+ // Mangle (Cat): CP
+ if(m_spellInfo->SpellFamilyName==SPELLFAMILY_DRUID && (m_spellInfo->SpellFamilyFlags==0x0000040000000000LL))
+ {
+ if(m_caster->GetTypeId()==TYPEID_PLAYER)
+ ((Player*)m_caster)->AddComboPoints(unitTarget,1);
+ }
+
+
+ // take ammo
+ if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK );
+
+ // wands don't have ammo
+ if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND)
+ return;
+
+ if( pItem->GetProto()->InventoryType == INVTYPE_THROWN )
+ {
+ if(pItem->GetMaxStackCount()==1)
+ {
+ // decrease durability for non-stackable throw weapon
+ ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
+ }
+ else
+ {
+ // decrease items amount for stackable throw weapon
+ uint32 count = 1;
+ ((Player*)m_caster)->DestroyItemCount( pItem, count, true);
+ }
+ }
+ else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID))
+ ((Player*)m_caster)->DestroyItemCount(ammo, 1, true);
+ }
+}
+
+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;
+
+ uint32 heal = m_caster->GetMaxHealth();
+
+ int32 gain = unitTarget->ModifyHealth(heal);
+ unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
+
+ m_caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, heal);
+}
+
+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 (unitTarget->m_currentSpells[i])
+ {
+ // check if we can interrupt spell
+ if ( unitTarget->m_currentSpells[i]->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && unitTarget->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE )
+ {
+ unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget->m_currentSpells[i]->m_spellInfo), GetSpellDuration(m_spellInfo));
+ unitTarget->InterruptSpell(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.m_targetMask & TARGET_FLAG_DEST_LOCATION)
+ {
+ x = m_targets.m_destX;
+ y = m_targets.m_destY;
+ z = m_targets.m_destZ;
+ }
+ 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,
+ x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
+ {
+ delete pGameObj;
+ return;
+ }
+
+ int32 duration = GetSpellDuration(m_spellInfo);
+ pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
+ pGameObj->SetSpellId(m_spellInfo->Id);
+
+ if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
+ m_caster->AddGameObject(pGameObj);
+ map->Add(pGameObj);
+
+ if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS
+ {
+ if(m_caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ Player *pl = (Player*)m_caster;
+ BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
+ if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS)
+ {
+ uint32 team = ALLIANCE;
+
+ if(pl->GetTeam() == team)
+ team = HORDE;
+
+ ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team);
+ }
+ }
+ }
+
+ if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY
+ {
+ if(m_caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
+ if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS)
+ {
+ ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID());
+ }
+ }
+ }
+
+ if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
+ {
+ GameObject* linkedGO = new GameObject;
+ if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
+ x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
+ {
+ linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
+ linkedGO->SetSpellId(m_spellInfo->Id);
+
+ m_caster->AddGameObject(linkedGO);
+ 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)
+
+ // by spell id
+ switch(m_spellInfo->Id)
+ {
+ // 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;
+ }
+
+ // Healthstone creating spells
+ case 6201:
+ case 6202:
+ case 5699:
+ case 11729:
+ case 11730:
+ case 27230:
+ {
+ uint32 itemtype;
+ uint32 rank = 0;
+ Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
+ {
+ if((*i)->GetId() == 18692)
+ {
+ rank = 1;
+ break;
+ }
+ else if((*i)->GetId() == 18693)
+ {
+ rank = 2;
+ break;
+ }
+ }
+
+ static uint32 const itypes[6][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
+ };
+
+ 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
+ default:
+ return;
+ }
+ DoCreateItem( effIndex, itemtype );
+ return;
+ }
+ // Brittle Armor - need remove one 24575 Brittle Armor aura
+ case 24590:
+ unitTarget->RemoveSingleAuraFromStack(24575, 0);
+ unitTarget->RemoveSingleAuraFromStack(24575, 1);
+ return;
+ // Mercurial Shield - need remove one 26464 Mercurial Shield aura
+ case 26465:
+ unitTarget->RemoveSingleAuraFromStack(26464, 0);
+ 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->GetDummyAura(22683))
+ return;
+
+ // Shadow Flame
+ m_caster->CastSpell(unitTarget, 22682, true);
+ return;
+ }
+ break;
+
+ // Summon Black Qiraji Battle Tank
+ case 26656:
+ {
+ if(!unitTarget)
+ return;
+
+ // Prevent stacking of mounts
+ unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
+
+ // Two separate mounts depending on area id (allows use both in and out of specific instance)
+ if (unitTarget->GetAreaId() == 3428)
+ unitTarget->CastSpell(unitTarget, 25863, false);
+ else
+ unitTarget->CastSpell(unitTarget, 26655, false);
+ break;
+ }
+ // Piccolo of the Flaming Fire
+ case 17512:
+ {
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
+ unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
+ break;
+ }
+
+ // 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, 0))
+ 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;
+ }
+
+ // 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.
+ uint32 mechanic_mask = (1<<MECHANIC_ROOT) | (1<<MECHANIC_SNARE);
+ Unit::AuraMap& Auras = unitTarget->GetAuras();
+ for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
+ {
+ next = iter;
+ ++next;
+ Aura *aur = iter->second;
+ if (!aur->IsPositive()) //only remove negative spells
+ {
+ // check for mechanic mask
+ if(GetSpellMechanicMask(aur->GetSpellProto(), aur->GetEffIndex()) & mechanic_mask)
+ {
+ unitTarget->RemoveAurasDueToSpell(aur->GetId());
+ if(Auras.empty())
+ break;
+ else
+ next = Auras.begin();
+ }
+ }
+ }
+ break;
+ }
+ case 41126: // Flame Crash
+ {
+ if(!unitTarget)
+ return;
+
+ unitTarget->CastSpell(unitTarget, 41131, true);
+ break;
+ }
+ case 44876: // Force Cast - Portal Effect: Sunwell Isle
+ {
+ if(!unitTarget)
+ return;
+
+ unitTarget->CastSpell(unitTarget, 44870, true);
+ break;
+ }
+
+ // Goblin Weather Machine
+ case 46203:
+ {
+ if(!unitTarget)
+ return;
+
+ uint32 spellId;
+ 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;
+ }
+ }
+
+ if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN )
+ {
+ switch(m_spellInfo->SpellFamilyFlags)
+ {
+ // Judgement
+ case 0x800000:
+ {
+ if(!unitTarget || !unitTarget->isAlive())
+ return;
+ uint32 spellId2 = 0;
+
+ // all seals have aura dummy
+ Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr)
+ {
+ SpellEntry const *spellInfo = (*itr)->GetSpellProto();
+
+ // search seal (all seals have judgement's aura dummy spell id in 2 effect
+ if ( !spellInfo || !IsSealSpell((*itr)->GetSpellProto()) || (*itr)->GetEffIndex() != 2 )
+ continue;
+
+ // must be calculated base at raw base points in spell proto, GetModifier()->m_value for S.Righteousness modified by SPELLMOD_DAMAGE
+ spellId2 = (*itr)->GetSpellProto()->EffectBasePoints[2]+1;
+
+ if(spellId2 <= 1)
+ continue;
+
+ // found, remove seal
+ m_caster->RemoveAurasDueToSpell((*itr)->GetId());
+
+ // Sanctified Judgement
+ Unit::AuraList const& m_auras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraList::const_iterator i = m_auras.begin(); i != m_auras.end(); ++i)
+ {
+ if ((*i)->GetSpellProto()->SpellIconID == 205 && (*i)->GetSpellProto()->Attributes == 0x01D0LL)
+ {
+ int32 chance = (*i)->GetModifier()->m_amount;
+ if ( roll_chance_i(chance) )
+ {
+ int32 mana = spellInfo->manaCost;
+ if ( Player* modOwner = m_caster->GetSpellModOwner() )
+ modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COST, mana);
+ mana = int32(mana* 0.8f);
+ m_caster->CastCustomSpell(m_caster,31930,&mana,NULL,NULL,true,NULL,*i);
+ }
+ break;
+ }
+ }
+
+ break;
+ }
+
+ m_caster->CastSpell(unitTarget,spellId2,true);
+ return;
+ }
+ }
+ }
+
+ // normal DB scripted effect
+ if(!unitTarget)
+ return;
+
+ sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id);
+ sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
+}
+
+void Spell::EffectSanctuary(uint32 /*i*/)
+{
+ if(!unitTarget)
+ return;
+ //unitTarget->CombatStop();
+
+ unitTarget->CombatStop();
+ unitTarget->getHostilRefManager().deleteReferences(); // stop all fighting
+ // Vanish allows to remove all threat and cast regular stealth so other spells can be used
+ if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH))
+ {
+ ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
+ }
+}
+
+void Spell::EffectAddComboPoints(uint32 /*i*/)
+{
+ if(!unitTarget)
+ return;
+
+ if(m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ if(damage <= 0)
+ return;
+
+ ((Player*)m_caster)->AddComboPoints(unitTarget, damage);
+}
+
+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()->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->GetMapId() != 0 && caster->GetMapId() != 1 && caster->GetMapId() != 530)
+ {
+ 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->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 ,
+ m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 ,
+ m_caster->GetPositionZ(),
+ m_caster->GetOrientation(), 0, 0, 0, 0, 0, 1))
+ {
+ 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/1000 : 0);
+ pGameObj->SetSpellId(m_spellInfo->Id);
+
+ m_caster->AddGameObject(pGameObj);
+ map->Add(pGameObj);
+ //END
+
+ // Send request
+ WorldPacket data(SMSG_DUEL_REQUESTED, 16);
+ data << pGameObj->GetGUID();
+ data << 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;
+
+ // 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->GetDummyAura(23445))
+ return;
+
+ float x,y,z;
+ m_caster->GetClosePoint(x,y,z,unitTarget->GetObjectSize());
+
+ ((Player*)unitTarget)->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*1000); // auto decline after msecs
+ ((Player*)unitTarget)->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];
+
+ sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
+}
+
+void Spell::EffectSummonTotem(uint32 i)
+{
+ uint8 slot = 0;
+ switch(m_spellInfo->EffectMiscValueB[i])
+ {
+ case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break;
+ case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break;
+ case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break;
+ case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break;
+ // Battle standard case
+ case SUMMON_TYPE_TOTEM: slot = 254; break;
+ // jewelery statue case, like totem without slot
+ case SUMMON_TYPE_GUARDIAN: slot = 255; break;
+ default: return;
+ }
+
+ if(slot < MAX_TOTEM)
+ {
+ uint64 guid = m_caster->m_TotemSlot[slot];
+ if(guid != 0)
+ {
+ Creature *OldTotem = ObjectAccessor::GetCreature(*m_caster, guid);
+ if(OldTotem && OldTotem->isTotem())
+ ((Totem*)OldTotem)->UnSummon();
+ }
+ }
+
+ uint32 team = 0;
+ if (m_caster->GetTypeId()==TYPEID_PLAYER)
+ team = ((Player*)m_caster)->GetTeam();
+
+ Totem* pTotem = new Totem;
+
+ if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_spellInfo->EffectMiscValue[i], team ))
+ {
+ delete pTotem;
+ return;
+ }
+
+ float angle = slot < MAX_TOTEM ? M_PI/MAX_TOTEM - (slot*2*M_PI/MAX_TOTEM) : 0;
+
+ float x,y,z;
+ m_caster->GetClosePoint(x,y,z,pTotem->GetObjectSize(),2.0f,angle);
+
+ // totem must be at same Z in case swimming caster and etc.
+ if( fabs( z - m_caster->GetPositionZ() ) > 5 )
+ z = m_caster->GetPositionZ();
+
+ pTotem->Relocate(x, y, z, m_caster->GetOrientation());
+
+ if(slot < MAX_TOTEM)
+ m_caster->m_TotemSlot[slot] = pTotem->GetGUID();
+
+ pTotem->SetOwner(m_caster->GetGUID());
+ pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized
+
+ int32 duration=GetSpellDuration(m_spellInfo);
+ if(Player* modOwner = m_caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration);
+ pTotem->SetDuration(duration);
+
+ if (damage) // if not spell info, DB values used
+ {
+ pTotem->SetMaxHealth(damage);
+ pTotem->SetHealth(damage);
+ }
+
+ pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id);
+ pTotem->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
+
+ pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_MOD_FEAR,true);
+ pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_TRANSFORM,true);
+
+ pTotem->Summon(m_caster);
+
+ if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
+ data << uint8(slot);
+ data << uint64(pTotem->GetGUID());
+ data << uint32(duration);
+ data << uint32(m_spellInfo->Id);
+ ((Player*)m_caster)->SendDirectMessage(&data);
+ }
+}
+
+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 = m_currentBasePoints[i]+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*1000, 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);
+
+ ((Player*)m_caster)->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;
+
+ if(!itemTarget)
+ return;
+
+ Pet *pet = _player->GetPet();
+ if(!pet)
+ return;
+
+ if(!pet->isAlive())
+ return;
+
+ int32 benefit = pet->GetCurrentFoodBenefitLevel(itemTarget->GetProto()->ItemLevel);
+ if(benefit <= 0)
+ return;
+
+ uint32 count = 1;
+ _player->DestroyItemCount(itemTarget,count,true);
+ // TODO: fix crash when a spell has two effects, both pointed at the same item target
+
+ m_caster->CastCustomSpell(m_caster,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true);
+}
+
+void Spell::EffectDismissPet(uint32 /*i*/)
+{
+ if(m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ Pet* pet = m_caster->GetPet();
+
+ // not let dismiss dead pet
+ if(!pet||!pet->isAlive())
+ return;
+
+ ((Player*)m_caster)->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 = ObjectAccessor::GetGameObject(*m_caster, guid);
+
+ if(obj) obj->Delete();
+ m_caster->m_ObjectSlot[slot] = 0;
+ }
+
+ GameObject* pGameObj = new GameObject;
+
+ float rot2 = sin(m_caster->GetOrientation()/2);
+ float rot3 = cos(m_caster->GetOrientation()/2);
+
+ float x,y,z;
+ // If dest location if present
+ if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
+ {
+ x = m_targets.m_destX;
+ y = m_targets.m_destY;
+ z = m_targets.m_destZ;
+ }
+ // 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, x, y, z, m_caster->GetOrientation(), 0, 0, rot2, rot3, 0, 1))
+ {
+ delete pGameObj;
+ return;
+ }
+
+ pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel());
+ int32 duration = GetSpellDuration(m_spellInfo);
+ pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
+ pGameObj->SetSpellId(m_spellInfo->Id);
+ m_caster->AddGameObject(pGameObj);
+
+ map->Add(pGameObj);
+ WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
+ data << pGameObj->GetGUID();
+ m_caster->SendMessageToSet(&data,true);
+
+ m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID();
+}
+
+void Spell::EffectResurrect(uint32 i)
+{
+ 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;
+ default:
+ break;
+ }
+
+ Player* pTarget = ((Player*)unitTarget);
+
+ 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;
+
+ unitTarget->m_extraAttacks = damage;
+}
+
+void Spell::EffectParry(uint32 /*i*/)
+{
+ if (unitTarget->GetTypeId() == TYPEID_PLAYER)
+ {
+ ((Player*)unitTarget)->SetCanParry(true);
+ }
+}
+
+void Spell::EffectBlock(uint32 /*i*/)
+{
+ if (unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ ((Player*)unitTarget)->SetCanBlock(true);
+}
+
+void Spell::EffectMomentMove(uint32 i)
+{
+ if(unitTarget->isInFlight())
+ return;
+
+ if( m_spellInfo->rangeIndex== 1) //self range
+ {
+ uint32 mapid = m_caster->GetMapId();
+ float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
+
+ // before caster
+ float fx,fy,fz;
+ unitTarget->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
+ float ox,oy,oz;
+ unitTarget->GetPosition(ox,oy,oz);
+
+ float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case
+ if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid, ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5))
+ {
+ fx = fx2;
+ fy = fy2;
+ fz = fz2;
+ unitTarget->UpdateGroundPositionZ(fx,fy,fz);
+ }
+
+ if(unitTarget->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, unitTarget->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
+ else
+ MapManager::Instance().GetMap(mapid, unitTarget)->CreatureRelocation((Creature*)unitTarget, fx, fy, fz, unitTarget->GetOrientation());
+ }
+}
+
+void Spell::EffectReputation(uint32 i)
+{
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ Player *_player = (Player*)unitTarget;
+
+ int32 rep_change = m_currentBasePoints[i]+1; // field store reputation change -1
+
+ uint32 faction_id = m_spellInfo->EffectMiscValue[i];
+
+ FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
+
+ if(!factionEntry)
+ return;
+
+ _player->ModifyFactionReputation(factionEntry,rep_change);
+}
+
+void Spell::EffectQuestComplete(uint32 i)
+{
+ if(m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ Player *_player = (Player*)m_caster;
+
+ uint32 quest_id = m_spellInfo->EffectMiscValue[i];
+ _player->AreaExploredOrEventHappens(quest_id);
+}
+
+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 = ((Player*)unitTarget);
+ 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();
+
+ plr->SaveToDB();
+}
+
+void Spell::EffectSkinning(uint32 /*i*/)
+{
+ if(unitTarget->GetTypeId() != TYPEID_UNIT )
+ return;
+ if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ Creature* creature = (Creature*) unitTarget;
+ int32 targetLevel = creature->getLevel();
+
+ uint32 skill;
+ if(creature->GetCreatureInfo()->flag1 & 256)
+ skill = SKILL_HERBALISM; // special case
+ else if(creature->GetCreatureInfo()->flag1 & 512)
+ skill = SKILL_MINING; // special case
+ else
+ skill = SKILL_SKINNING; // normal case
+
+ ((Player*)m_caster)->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 = ((Player*)m_caster)->GetPureSkillValue(skill);
+
+ // Double chances for elites
+ ((Player*)m_caster)->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1 );
+}
+
+void Spell::EffectCharge(uint32 /*i*/)
+{
+ if(!unitTarget || !m_caster)
+ return;
+
+ float x, y, z;
+ unitTarget->GetContactPoint(m_caster, x, y, z);
+ if(unitTarget->GetTypeId() != TYPEID_PLAYER)
+ ((Creature *)unitTarget)->StopMoving();
+
+ // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
+ m_caster->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1);
+
+ if(m_caster->GetTypeId() != TYPEID_PLAYER)
+ MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)->CreatureRelocation((Creature*)m_caster,x,y,z,m_caster->GetOrientation());
+
+ // not all charge effects used in negative spells
+ if ( !IsPositiveSpell(m_spellInfo->Id))
+ m_caster->Attack(unitTarget,true);
+}
+
+void Spell::EffectSummonCritter(uint32 i)
+{
+ if(m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+ Player* player = (Player*)m_caster;
+
+ uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
+ if(!pet_entry)
+ return;
+
+ Pet* old_critter = player->GetMiniPet();
+
+ // for same pet just despawn
+ if(old_critter && old_critter->GetEntry() == pet_entry)
+ {
+ player->RemoveMiniPet();
+ return;
+ }
+
+ // despawn old pet before summon new
+ if(old_critter)
+ player->RemoveMiniPet();
+
+ // summon new pet
+ Pet* critter = new Pet(MINI_PET);
+
+ Map *map = m_caster->GetMap();
+ uint32 pet_number = objmgr.GeneratePetNumber();
+ if(!critter->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),
+ map, pet_entry, pet_number))
+ {
+ sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry);
+ delete critter;
+ return;
+ }
+
+ float x,y,z;
+ // If dest location if present
+ if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
+ {
+ x = m_targets.m_destX;
+ y = m_targets.m_destY;
+ z = m_targets.m_destZ;
+ }
+ // Summon if dest location not present near caster
+ else
+ m_caster->GetClosePoint(x,y,z,critter->GetObjectSize());
+
+ critter->Relocate(x,y,z,m_caster->GetOrientation());
+
+ if(!critter->IsPositionValid())
+ {
+ sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", critter->GetGUIDLow(), critter->GetEntry(), critter->GetPositionX(), critter->GetPositionY());
+ delete critter;
+ return;
+ }
+
+ critter->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID());
+ critter->SetUInt64Value(UNIT_FIELD_CREATEDBY,m_caster->GetGUID());
+ critter->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
+ critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
+
+ critter->AIM_Initialize();
+ critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
+ critter->SetMaxHealth(1);
+ critter->SetHealth(1);
+ critter->SetLevel(1);
+
+ // set timer for unsummon
+ int32 duration = GetSpellDuration(m_spellInfo);
+ if(duration > 0)
+ critter->SetDuration(duration);
+
+ std::string name = player->GetName();
+ name.append(petTypeSuffix[critter->getPetType()]);
+ critter->SetName( name );
+ player->SetMiniPet(critter);
+
+ map->Add((Creature*)critter);
+}
+
+void Spell::EffectKnockBack(uint32 i)
+{
+ if(!unitTarget || !m_caster)
+ return;
+
+ // Effect only works on players
+ if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
+ return;
+
+ float vsin = sin(m_caster->GetAngle(unitTarget));
+ float vcos = cos(m_caster->GetAngle(unitTarget));
+
+ WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
+ data.append(unitTarget->GetPackGUID());
+ data << uint32(0); // Sequence
+ data << float(vcos); // x direction
+ data << float(vsin); // y direction
+ data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed
+ data << float(damage/-10); // Z Movement speed (vertical)
+
+ ((Player*)unitTarget)->GetSession()->SendPacket(&data);
+}
+
+void Spell::EffectSendTaxi(uint32 i)
+{
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(m_spellInfo->EffectMiscValue[i]);
+ if(!entry)
+ return;
+
+ std::vector<uint32> nodes;
+
+ nodes.resize(2);
+ nodes[0] = entry->from;
+ nodes[1] = entry->to;
+
+ uint32 mountid = 0;
+ switch(m_spellInfo->Id)
+ {
+ case 31606: //Stormcrow Amulet
+ mountid = 17447;
+ break;
+ case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run
+ case 45113: //Quest - Sunwell Daily - Ship Bombing Run
+ case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return
+ mountid = 22840;
+ break;
+ case 34905: //Stealth Flight
+ mountid = 6851;
+ break;
+ }
+
+ ((Player*)unitTarget)->ActivateTaxiPathTo(nodes,mountid);
+
+}
+
+void Spell::EffectPlayerPull(uint32 i)
+{
+ if(!unitTarget || !m_caster)
+ return;
+
+ // Effect only works on players
+ if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
+ return;
+
+ float vsin = sin(unitTarget->GetAngle(m_caster));
+ float vcos = cos(unitTarget->GetAngle(m_caster));
+
+ WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
+ data.append(unitTarget->GetPackGUID());
+ data << uint32(0); // Sequence
+ data << float(vcos); // x direction
+ data << float(vsin); // y direction
+ // Horizontal speed
+ data << float(damage ? damage : unitTarget->GetDistance2d(m_caster));
+ data << float(m_spellInfo->EffectMiscValue[i])/-10; // Z Movement speed
+
+ ((Player*)unitTarget)->GetSession()->SendPacket(&data);
+}
+
+void Spell::EffectDispelMechanic(uint32 i)
+{
+ if(!unitTarget)
+ return;
+
+ uint32 mechanic = m_spellInfo->EffectMiscValue[i];
+
+ Unit::AuraMap& Auras = unitTarget->GetAuras();
+ for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
+ {
+ next = iter;
+ ++next;
+ SpellEntry const *spell = sSpellStore.LookupEntry(iter->second->GetSpellProto()->Id);
+ if(spell->Mechanic == mechanic || spell->EffectMechanic[iter->second->GetEffIndex()] == mechanic)
+ {
+ unitTarget->RemoveAurasDueToSpell(spell->Id);
+ if(Auras.empty())
+ break;
+ else
+ next = Auras.begin();
+ }
+ }
+ return;
+}
+
+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;
+ 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*/)
+{
+ float mana = 0;
+ for(int slot = 0; slot < MAX_TOTEM; ++slot)
+ {
+ if(!m_caster->m_TotemSlot[slot])
+ continue;
+
+ Creature* totem = ObjectAccessor::GetCreature(*m_caster,m_caster->m_TotemSlot[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 * damage / 100;
+ ((Totem*)totem)->UnSummon();
+ }
+ }
+
+ int32 gain = m_caster->ModifyPower(POWER_MANA,int32(mana));
+ m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id, gain, POWER_MANA);
+}
+
+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)
+ {
+ ((Player*)unitTarget)->DurabilityPointsLossAll(damage,(slot < -1));
+ return;
+ }
+
+ // invalid slot value
+ if(slot >= INVENTORY_SLOT_BAG_END)
+ return;
+
+ if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
+ ((Player*)unitTarget)->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)
+ {
+ ((Player*)unitTarget)->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 = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
+ ((Player*)unitTarget)->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.m_targetMask & TARGET_FLAG_DEST_LOCATION)
+ {
+ fx = m_targets.m_destX;
+ fy = m_targets.m_destY;
+ fz = m_targets.m_destZ;
+ }
+ //FIXME: this can be better check for most objects but still hack
+ else if(m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed==0)
+ {
+ float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex]));
+ m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
+ }
+ else
+ {
+ float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
+ float max_dis = GetSpellMaxRange(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)
+ {
+ if ( !cMap->IsInWater(fx,fy,fz-0.5f)) // 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);
+ }
+ // 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,
+ fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
+ {
+ delete pGameObj;
+ return;
+ }
+
+ int32 duration = GetSpellDuration(m_spellInfo);
+
+ switch(goinfo->type)
+ {
+ case GAMEOBJECT_TYPE_FISHINGNODE:
+ {
+ m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID());
+ // Orientation3
+ pGameObj->SetFloatValue(GAMEOBJECT_ROTATION + 2, 0.88431775569915771 );
+ // Orientation4
+ pGameObj->SetFloatValue(GAMEOBJECT_ROTATION + 3, -0.4668855369091033 );
+ 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;
+ 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*1000 + FISHING_BOBBER_READY_TIME*1000;
+ break;
+ }
+ case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
+ {
+ if(m_caster->GetTypeId()==TYPEID_PLAYER)
+ {
+ pGameObj->AddUniqueUse((Player*)m_caster);
+ m_caster->AddGameObject(pGameObj); // will removed at spell cancel
+ }
+ break;
+ }
+ case GAMEOBJECT_TYPE_FISHINGHOLE:
+ case GAMEOBJECT_TYPE_CHEST:
+ default:
+ {
+ break;
+ }
+ }
+
+ pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 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\n");
+ //m_caster->AddGameObject(pGameObj);
+ //m_ObjToDel.push_back(pGameObj);
+
+ cMap->Add(pGameObj);
+
+ WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
+ data << uint64(pGameObj->GetGUID());
+ m_caster->SendMessageToSet(&data,true);
+
+ if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
+ {
+ GameObject* linkedGO = new GameObject;
+ if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
+ fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
+ {
+ linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
+ linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
+ linkedGO->SetSpellId(m_spellInfo->Id);
+ linkedGO->SetOwnerGUID(m_caster->GetGUID() );
+
+ MapManager::Instance().GetMap(linkedGO->GetMapId(), linkedGO)->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);
+ }
+
+ ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING);
+}
+
+void Spell::EffectSkill(uint32 /*i*/)
+{
+ sLog.outDebug("WORLD: SkillEFFECT");
+}
+
+void Spell::EffectSummonDemon(uint32 i)
+{
+ float px = m_targets.m_destX;
+ float py = m_targets.m_destY;
+ float pz = m_targets.m_destZ;
+
+ Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,3600000);
+ if (!Charmed)
+ return;
+
+ // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
+ Charmed->SetLevel(m_caster->getLevel());
+
+ // TODO: Add damage/mana/hp according to level
+
+ if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon
+ {
+ // Enslave demon effect, without mana cost and cooldown
+ m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
+
+ // Inferno effect
+ Charmed->CastSpell(Charmed, 22703, true, 0);
+ }
+}
+
+/* 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?)
+ //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
+ ((Player*)unitTarget)->ResurrectPlayer(1.0f);
+ ((Player*)unitTarget)->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;
+
+ ((Player*)unitTarget)->RemovedInsignia( (Player*)m_caster );
+}
+
+void Spell::EffectStealBeneficialBuff(uint32 i)
+{
+ sLog.outDebug("Effect: StealBeneficialBuff");
+
+ if(!unitTarget || unitTarget==m_caster) // can't steal from self
+ return;
+
+ std::vector <Aura *> steal_list;
+ // Create dispel mask by dispel type
+ uint32 dispelMask = GetDispellMask( DispelType(m_spellInfo->EffectMiscValue[i]) );
+ Unit::AuraMap const& auras = unitTarget->GetAuras();
+ for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
+ {
+ Aura *aur = (*itr).second;
+ if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
+ {
+ // Need check for passive? this
+ if (aur->IsPositive() && !aur->IsPassive())
+ steal_list.push_back(aur);
+ }
+ }
+ // Ok if exist some buffs for dispel try dispel it
+ if (!steal_list.empty())
+ {
+ std::list < std::pair<uint32,uint64> > success_list;
+ int32 list_size = steal_list.size();
+ // Dispell N = damage buffs (or while exist buffs for dispel)
+ for (int32 count=0; count < damage && list_size > 0; ++count)
+ {
+ // Random select buff for dispel
+ Aura *aur = steal_list[urand(0, list_size-1)];
+ // Not use chance for steal
+ // TODO possible need do it
+ success_list.push_back( std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
+
+ // Remove buff from list for prevent doubles
+ for (std::vector<Aura *>::iterator j = steal_list.begin(); j != steal_list.end(); )
+ {
+ Aura *stealed = *j;
+ if (stealed->GetId() == aur->GetId() && stealed->GetCasterGUID() == aur->GetCasterGUID())
+ {
+ j = steal_list.erase(j);
+ --list_size;
+ }
+ else
+ ++j;
+ }
+ }
+ // Really try steal and send log
+ if (!success_list.empty())
+ {
+ int32 count = success_list.size();
+ WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+count*5);
+ data.append(unitTarget->GetPackGUID()); // Victim GUID
+ data.append(m_caster->GetPackGUID()); // Caster GUID
+ data << uint32(m_spellInfo->Id); // Dispell spell id
+ data << uint8(0); // not used
+ data << uint32(count); // count
+ for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
+ {
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
+ data << uint32(spellInfo->Id); // Spell Id
+ data << uint8(0); // 0 - steals !=0 transfers
+ unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster);
+ }
+ m_caster->SendMessageToSet(&data, true);
+ }
+ }
+}
+
+void Spell::EffectKillCredit(uint32 i)
+{
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ ((Player*)unitTarget)->KilledMonster(m_spellInfo->EffectMiscValue[i], 0);
+}
+
+void Spell::EffectQuestFail(uint32 i)
+{
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ ((Player*)unitTarget)->FailQuest(m_spellInfo->EffectMiscValue[i]);
+}
|