* Removed the misdesigned on_events script/hooks. * Lots of related cleanups and assertions. * The interface is now fully object-oriented. ** Scripts no longer use function pointers. ** Scripts no longer use the general-purpose Script struct for everything. ** Script types are split into separate classes which must be inherited depending on what functionality is desired. * Several script types have been added to allow extending functionality in a code-only manner (some script types require assignment in the recently added ScriptName columns in the database, though). ** SpellHandlerScript: Wrapper around spell scripts (returns new SpellScript objects (`spell_script_names`.`ScriptName`)). ** ServerScript: Allows scripting events that occur in the network layer. ** WorldScript: Allows scripting certain world-global events. ** FormulaScript: Allows hooking and interfering with core formulas. ** *MapScript: Allows hooking different map types (including world, instance, and battleground maps (`instance_template`.`ScriptName`)). ** ItemScript: Allows scripting of items (like the old interface (`item_template`.`ScriptName`)). ** CreatureScript: Allows scripting of creatures/AI (like the old interface (`creature_template`.`ScriptName`)). ** GameObjectScript: Allows scripting of gameobjects (like the old interface (`gameobject_template`.`ScriptName`)). ** AreaTriggerScript: Allows scripting triggered area triggers (like the old interface (`areatrigger_scripts`.`ScriptName`)). ** OutdoorPvPScript: Script which should return OutdoorPvP objects for use by OutdoorPvPMgr (`outdoorpvp_template`.`ScriptName`). ** CommandScript: Allows extending the in-core command table. ** WeatherScript: Allows scripting of weather changes (`game_weather`.`ScriptName`). ** AuctionHouseScript: Allows scripting of auction events. ** ConditionScript: Allows scripting of conditions (`conditions`.`ScriptName`). ** DynamicObjectScript: Allows scripting of dynamicobjects. ** TransportScript: Allows scripting of transport events (`transports`.`ScriptName`). * OutdoorPvP objects are now created through scripts. This effectively means that they'll need to be moved to scripts before the they're functional again. * The whole idea with this new interface is to allow expanding core functionality without touching core code. If further hooks are needed to expand functionality of the core, let us know; we'll add them, if we agree that it is appropriate to do so. *** NOTE: The scripts project will _not_ build before it has been adapted to the new interface. *** Thanks to everyone who helped out with related preparations and suggestions! --HG-- branch : trunk
7882 lines
313 KiB
C++
7882 lines
313 KiB
C++
/*
|
|
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
|
*
|
|
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.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 "DatabaseEnv.h"
|
|
#include "WorldPacket.h"
|
|
#include "Opcodes.h"
|
|
#include "Log.h"
|
|
#include "UpdateMask.h"
|
|
#include "World.h"
|
|
#include "ObjectMgr.h"
|
|
#include "SpellMgr.h"
|
|
#include "Player.h"
|
|
#include "SkillExtraItems.h"
|
|
#include "Unit.h"
|
|
#include "Spell.h"
|
|
#include "DynamicObject.h"
|
|
#include "SpellAuras.h"
|
|
#include "SpellAuraEffects.h"
|
|
#include "Group.h"
|
|
#include "UpdateData.h"
|
|
#include "MapManager.h"
|
|
#include "ObjectAccessor.h"
|
|
#include "SharedDefines.h"
|
|
#include "Pet.h"
|
|
#include "GameObject.h"
|
|
#include "GossipDef.h"
|
|
#include "Creature.h"
|
|
#include "Totem.h"
|
|
#include "CreatureAI.h"
|
|
#include "BattleGroundMgr.h"
|
|
#include "BattleGround.h"
|
|
#include "BattleGroundEY.h"
|
|
#include "BattleGroundWS.h"
|
|
#include "OutdoorPvPMgr.h"
|
|
#include "Language.h"
|
|
#include "SocialMgr.h"
|
|
#include "Util.h"
|
|
#include "VMapFactory.h"
|
|
#include "TemporarySummon.h"
|
|
#include "CellImpl.h"
|
|
#include "GridNotifiers.h"
|
|
#include "GridNotifiersImpl.h"
|
|
#include "SkillDiscovery.h"
|
|
#include "Formulas.h"
|
|
#include "Vehicle.h"
|
|
#include "ScriptMgr.h"
|
|
|
|
pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
|
|
{
|
|
&Spell::EffectNULL, // 0
|
|
&Spell::EffectInstaKill, // 1 SPELL_EFFECT_INSTAKILL
|
|
&Spell::EffectSchoolDMG, // 2 SPELL_EFFECT_SCHOOL_DAMAGE
|
|
&Spell::EffectDummy, // 3 SPELL_EFFECT_DUMMY
|
|
&Spell::EffectUnused, // 4 SPELL_EFFECT_PORTAL_TELEPORT unused
|
|
&Spell::EffectTeleportUnits, // 5 SPELL_EFFECT_TELEPORT_UNITS
|
|
&Spell::EffectApplyAura, // 6 SPELL_EFFECT_APPLY_AURA
|
|
&Spell::EffectEnvirinmentalDMG, // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
|
|
&Spell::EffectPowerDrain, // 8 SPELL_EFFECT_POWER_DRAIN
|
|
&Spell::EffectHealthLeech, // 9 SPELL_EFFECT_HEALTH_LEECH
|
|
&Spell::EffectHeal, // 10 SPELL_EFFECT_HEAL
|
|
&Spell::EffectBind, // 11 SPELL_EFFECT_BIND
|
|
&Spell::EffectNULL, // 12 SPELL_EFFECT_PORTAL
|
|
&Spell::EffectUnused, // 13 SPELL_EFFECT_RITUAL_BASE unused
|
|
&Spell::EffectUnused, // 14 SPELL_EFFECT_RITUAL_SPECIALIZE unused
|
|
&Spell::EffectUnused, // 15 SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL unused
|
|
&Spell::EffectQuestComplete, // 16 SPELL_EFFECT_QUEST_COMPLETE
|
|
&Spell::EffectWeaponDmg, // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
|
|
&Spell::EffectResurrect, // 18 SPELL_EFFECT_RESURRECT
|
|
&Spell::EffectAddExtraAttacks, // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS
|
|
&Spell::EffectUnused, // 20 SPELL_EFFECT_DODGE one spell: Dodge
|
|
&Spell::EffectUnused, // 21 SPELL_EFFECT_EVADE one spell: Evade (DND)
|
|
&Spell::EffectParry, // 22 SPELL_EFFECT_PARRY
|
|
&Spell::EffectBlock, // 23 SPELL_EFFECT_BLOCK one spell: Block
|
|
&Spell::EffectCreateItem, // 24 SPELL_EFFECT_CREATE_ITEM
|
|
&Spell::EffectUnused, // 25 SPELL_EFFECT_WEAPON
|
|
&Spell::EffectUnused, // 26 SPELL_EFFECT_DEFENSE one spell: Defense
|
|
&Spell::EffectPersistentAA, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA
|
|
&Spell::EffectSummonType, // 28 SPELL_EFFECT_SUMMON
|
|
&Spell::EffectLeap, // 29 SPELL_EFFECT_LEAP
|
|
&Spell::EffectEnergize, // 30 SPELL_EFFECT_ENERGIZE
|
|
&Spell::EffectWeaponDmg, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
|
|
&Spell::EffectTriggerMissileSpell, // 32 SPELL_EFFECT_TRIGGER_MISSILE
|
|
&Spell::EffectOpenLock, // 33 SPELL_EFFECT_OPEN_LOCK
|
|
&Spell::EffectSummonChangeItem, // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM
|
|
&Spell::EffectApplyAreaAura, // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY
|
|
&Spell::EffectLearnSpell, // 36 SPELL_EFFECT_LEARN_SPELL
|
|
&Spell::EffectUnused, // 37 SPELL_EFFECT_SPELL_DEFENSE one spell: SPELLDEFENSE (DND)
|
|
&Spell::EffectDispel, // 38 SPELL_EFFECT_DISPEL
|
|
&Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE
|
|
&Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD
|
|
&Spell::EffectJump, // 41 SPELL_EFFECT_JUMP
|
|
&Spell::EffectJumpDest, // 42 SPELL_EFFECT_JUMP_DEST
|
|
&Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
|
|
&Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP
|
|
&Spell::EffectAddHonor, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related
|
|
&Spell::EffectUnused, // 46 SPELL_EFFECT_SPAWN clientside, unit appears as if it was just spawned
|
|
&Spell::EffectTradeSkill, // 47 SPELL_EFFECT_TRADE_SKILL
|
|
&Spell::EffectUnused, // 48 SPELL_EFFECT_STEALTH one spell: Base Stealth
|
|
&Spell::EffectUnused, // 49 SPELL_EFFECT_DETECT one spell: Detect
|
|
&Spell::EffectTransmitted, // 50 SPELL_EFFECT_TRANS_DOOR
|
|
&Spell::EffectUnused, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT unused
|
|
&Spell::EffectUnused, // 52 SPELL_EFFECT_GUARANTEE_HIT one spell: zzOLDCritical Shot
|
|
&Spell::EffectEnchantItemPerm, // 53 SPELL_EFFECT_ENCHANT_ITEM
|
|
&Spell::EffectEnchantItemTmp, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
|
|
&Spell::EffectTameCreature, // 55 SPELL_EFFECT_TAMECREATURE
|
|
&Spell::EffectSummonPet, // 56 SPELL_EFFECT_SUMMON_PET
|
|
&Spell::EffectLearnPetSpell, // 57 SPELL_EFFECT_LEARN_PET_SPELL
|
|
&Spell::EffectWeaponDmg, // 58 SPELL_EFFECT_WEAPON_DAMAGE
|
|
&Spell::EffectCreateRandomItem, // 59 SPELL_EFFECT_CREATE_RANDOM_ITEM create item base at spell specific loot
|
|
&Spell::EffectProficiency, // 60 SPELL_EFFECT_PROFICIENCY
|
|
&Spell::EffectSendEvent, // 61 SPELL_EFFECT_SEND_EVENT
|
|
&Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN
|
|
&Spell::EffectThreat, // 63 SPELL_EFFECT_THREAT
|
|
&Spell::EffectTriggerSpell, // 64 SPELL_EFFECT_TRIGGER_SPELL
|
|
&Spell::EffectApplyAreaAura, // 65 SPELL_EFFECT_APPLY_AREA_AURA_RAID
|
|
&Spell::EffectRechargeManaGem, // 66 SPELL_EFFECT_CREATE_MANA_GEM (possibly recharge it, misc - is item ID)
|
|
&Spell::EffectHealMaxHealth, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH
|
|
&Spell::EffectInterruptCast, // 68 SPELL_EFFECT_INTERRUPT_CAST
|
|
&Spell::EffectDistract, // 69 SPELL_EFFECT_DISTRACT
|
|
&Spell::EffectPull, // 70 SPELL_EFFECT_PULL one spell: Distract Move
|
|
&Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET
|
|
&Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT
|
|
&Spell::EffectUnused, // 73 SPELL_EFFECT_UNTRAIN_TALENTS
|
|
&Spell::EffectApplyGlyph, // 74 SPELL_EFFECT_APPLY_GLYPH
|
|
&Spell::EffectHealMechanical, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit
|
|
&Spell::EffectSummonObjectWild, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD
|
|
&Spell::EffectScriptEffect, // 77 SPELL_EFFECT_SCRIPT_EFFECT
|
|
&Spell::EffectUnused, // 78 SPELL_EFFECT_ATTACK
|
|
&Spell::EffectSanctuary, // 79 SPELL_EFFECT_SANCTUARY
|
|
&Spell::EffectAddComboPoints, // 80 SPELL_EFFECT_ADD_COMBO_POINTS
|
|
&Spell::EffectUnused, // 81 SPELL_EFFECT_CREATE_HOUSE one spell: Create House (TEST)
|
|
&Spell::EffectNULL, // 82 SPELL_EFFECT_BIND_SIGHT
|
|
&Spell::EffectDuel, // 83 SPELL_EFFECT_DUEL
|
|
&Spell::EffectStuck, // 84 SPELL_EFFECT_STUCK
|
|
&Spell::EffectSummonPlayer, // 85 SPELL_EFFECT_SUMMON_PLAYER
|
|
&Spell::EffectActivateObject, // 86 SPELL_EFFECT_ACTIVATE_OBJECT
|
|
&Spell::EffectWMODamage, // 87 SPELL_EFFECT_WMO_DAMAGE
|
|
&Spell::EffectWMORepair, // 88 SPELL_EFFECT_WMO_REPAIR
|
|
&Spell::EffectUnused, // 89 SPELL_EFFECT_WMO_CHANGE // 0 intact // 1 damaged // 2 destroyed // 3 rebuilding
|
|
&Spell::EffectKillCreditPersonal, // 90 SPELL_EFFECT_KILL_CREDIT Kill credit but only for single person
|
|
&Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash
|
|
&Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM
|
|
&Spell::EffectForceDeselect, // 93 SPELL_EFFECT_FORCE_DESELECT
|
|
&Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT
|
|
&Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING
|
|
&Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE
|
|
&Spell::EffectCastButtons, // 97 SPELL_EFFECT_CAST_BUTTON (totem bar since 3.2.2a)
|
|
&Spell::EffectKnockBack, // 98 SPELL_EFFECT_KNOCK_BACK
|
|
&Spell::EffectDisEnchant, // 99 SPELL_EFFECT_DISENCHANT
|
|
&Spell::EffectInebriate, //100 SPELL_EFFECT_INEBRIATE
|
|
&Spell::EffectFeedPet, //101 SPELL_EFFECT_FEED_PET
|
|
&Spell::EffectDismissPet, //102 SPELL_EFFECT_DISMISS_PET
|
|
&Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION
|
|
&Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1
|
|
&Spell::EffectSummonObject, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2
|
|
&Spell::EffectSummonObject, //106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3
|
|
&Spell::EffectSummonObject, //107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4
|
|
&Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC
|
|
&Spell::EffectSummonDeadPet, //109 SPELL_EFFECT_SUMMON_DEAD_PET
|
|
&Spell::EffectDestroyAllTotems, //110 SPELL_EFFECT_DESTROY_ALL_TOTEMS
|
|
&Spell::EffectDurabilityDamage, //111 SPELL_EFFECT_DURABILITY_DAMAGE
|
|
&Spell::EffectUnused, //112 SPELL_EFFECT_112
|
|
&Spell::EffectResurrectNew, //113 SPELL_EFFECT_RESURRECT_NEW
|
|
&Spell::EffectTaunt, //114 SPELL_EFFECT_ATTACK_ME
|
|
&Spell::EffectDurabilityDamagePCT, //115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT
|
|
&Spell::EffectSkinPlayerCorpse, //116 SPELL_EFFECT_SKIN_PLAYER_CORPSE one spell: Remove Insignia, bg usage, required special corpse flags...
|
|
&Spell::EffectSpiritHeal, //117 SPELL_EFFECT_SPIRIT_HEAL one spell: Spirit Heal
|
|
&Spell::EffectSkill, //118 SPELL_EFFECT_SKILL professions and more
|
|
&Spell::EffectApplyAreaAura, //119 SPELL_EFFECT_APPLY_AREA_AURA_PET
|
|
&Spell::EffectUnused, //120 SPELL_EFFECT_TELEPORT_GRAVEYARD one spell: Graveyard Teleport Test
|
|
&Spell::EffectWeaponDmg, //121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG
|
|
&Spell::EffectUnused, //122 SPELL_EFFECT_122 unused
|
|
&Spell::EffectSendTaxi, //123 SPELL_EFFECT_SEND_TAXI taxi/flight related (misc value is taxi path id)
|
|
&Spell::EffectPlayerPull, //124 SPELL_EFFECT_PLAYER_PULL opposite of knockback effect (pulls player twoard caster)
|
|
&Spell::EffectModifyThreatPercent, //125 SPELL_EFFECT_MODIFY_THREAT_PERCENT
|
|
&Spell::EffectStealBeneficialBuff, //126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF spell steal effect?
|
|
&Spell::EffectProspecting, //127 SPELL_EFFECT_PROSPECTING Prospecting spell
|
|
&Spell::EffectApplyAreaAura, //128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND
|
|
&Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
|
|
&Spell::EffectRedirectThreat, //130 SPELL_EFFECT_REDIRECT_THREAT
|
|
&Spell::EffectPlayerNotification, //131 SPELL_EFFECT_PLAYER_NOTIFICATION
|
|
&Spell::EffectPlayMusic, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value (SoundEntries.dbc)
|
|
&Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization
|
|
&Spell::EffectKillCredit, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry
|
|
&Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET
|
|
&Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT
|
|
&Spell::EffectEnergizePct, //137 SPELL_EFFECT_ENERGIZE_PCT
|
|
&Spell::EffectLeapBack, //138 SPELL_EFFECT_LEAP_BACK Leap back
|
|
&Spell::EffectQuestClear, //139 SPELL_EFFECT_CLEAR_QUEST Reset quest status (miscValue - quest ID)
|
|
&Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST
|
|
&Spell::EffectForceCastWithValue, //141 SPELL_EFFECT_FORCE_CAST_WITH_VALUE
|
|
&Spell::EffectTriggerSpellWithValue, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE
|
|
&Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER
|
|
&Spell::EffectKnockBack, //144 SPELL_EFFECT_KNOCK_BACK_DEST
|
|
&Spell::EffectPlayerPull, //145 SPELL_EFFECT_145 Black Hole Effect
|
|
&Spell::EffectActivateRune, //146 SPELL_EFFECT_ACTIVATE_RUNE
|
|
&Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail
|
|
&Spell::EffectUnused, //148 SPELL_EFFECT_148 1 spell - 43509
|
|
&Spell::EffectChargeDest, //149 SPELL_EFFECT_CHARGE_DEST
|
|
&Spell::EffectQuestStart, //150 SPELL_EFFECT_QUEST_START
|
|
&Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2
|
|
&Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend
|
|
&Spell::EffectCreateTamedPet, //153 SPELL_EFFECT_CREATE_TAMED_PET misc value is creature entry
|
|
&Spell::EffectDiscoverTaxi, //154 SPELL_EFFECT_DISCOVER_TAXI
|
|
&Spell::EffectTitanGrip, //155 SPELL_EFFECT_TITAN_GRIP Allows you to equip two-handed axes, maces and swords in one hand, but you attack $49152s1% slower than normal.
|
|
&Spell::EffectEnchantItemPrismatic, //156 SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC
|
|
&Spell::EffectCreateItem2, //157 SPELL_EFFECT_CREATE_ITEM_2 create item or create item template and replace by some randon spell loot item
|
|
&Spell::EffectMilling, //158 SPELL_EFFECT_MILLING milling
|
|
&Spell::EffectRenamePet, //159 SPELL_EFFECT_ALLOW_RENAME_PET allow rename pet once again
|
|
&Spell::EffectNULL, //160 SPELL_EFFECT_160 1 spell - 45534
|
|
&Spell::EffectSpecCount, //161 SPELL_EFFECT_TALENT_SPEC_COUNT second talent spec (learn/revert)
|
|
&Spell::EffectActivateSpec, //162 SPELL_EFFECT_TALENT_SPEC_SELECT activate primary/secondary spec
|
|
&Spell::EffectNULL, //163 unused
|
|
&Spell::EffectRemoveAura, //164 SPELL_EFFECT_REMOVE_AURA
|
|
};
|
|
|
|
void Spell::EffectNULL(uint32 /*i*/)
|
|
{
|
|
sLog.outDebug("WORLD: Spell Effect DUMMY");
|
|
}
|
|
|
|
void Spell::EffectUnused(uint32 /*i*/)
|
|
{
|
|
// NOT USED BY ANY SPELL OR USELESS OR IMPLEMENTED IN DIFFERENT WAY IN TRINITY
|
|
}
|
|
|
|
void Spell::EffectResurrectNew(uint32 i)
|
|
{
|
|
if (!unitTarget || unitTarget->isAlive())
|
|
return;
|
|
|
|
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
if (!unitTarget->IsInWorld())
|
|
return;
|
|
|
|
Player* pTarget = unitTarget->ToPlayer();
|
|
|
|
if (pTarget->isRessurectRequested()) // already have one active request
|
|
return;
|
|
|
|
uint32 health = damage;
|
|
uint32 mana = m_spellInfo->EffectMiscValue[i];
|
|
pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
|
|
SendResurrectRequest(pTarget);
|
|
}
|
|
|
|
void Spell::EffectInstaKill(uint32 /*i*/)
|
|
{
|
|
if (!unitTarget || !unitTarget->isAlive())
|
|
return;
|
|
|
|
// Demonic Sacrifice
|
|
if (m_spellInfo->Id == 18788 && unitTarget->GetTypeId() == TYPEID_UNIT)
|
|
{
|
|
uint32 entry = unitTarget->GetEntry();
|
|
uint32 spellID;
|
|
switch (entry)
|
|
{
|
|
case 416: spellID = 18789; break; //imp
|
|
case 417: spellID = 18792; break; //fellhunter
|
|
case 1860: spellID = 18790; break; //void
|
|
case 1863: spellID = 18791; break; //succubus
|
|
case 17252: spellID = 35701; break; //fellguard
|
|
default:
|
|
sLog.outError("EffectInstaKill: Unhandled creature entry (%u) case.", entry);
|
|
return;
|
|
}
|
|
|
|
m_caster->CastSpell(m_caster, spellID, true);
|
|
}
|
|
|
|
if (m_caster == unitTarget) // prevent interrupt message
|
|
finish();
|
|
|
|
m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
|
|
}
|
|
|
|
void Spell::EffectEnvirinmentalDMG(uint32 i)
|
|
{
|
|
uint32 absorb = 0;
|
|
uint32 resist = 0;
|
|
|
|
// Note: this hack with damage replace required until GO casting not implemented
|
|
// environment damage spells already have around enemies targeting but this not help in case not existed GO casting support
|
|
// currently each enemy selected explicitly and self cast damage, we prevent apply self casted spell bonuses/etc
|
|
damage = SpellMgr::CalculateSpellEffectAmount(m_spellInfo, i, m_caster);
|
|
|
|
m_caster->CalcAbsorbResist(m_caster, GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist, m_spellInfo);
|
|
|
|
m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false);
|
|
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
|
m_caster->ToPlayer()->EnvironmentalDamage(DAMAGE_FIRE, damage);
|
|
}
|
|
|
|
void Spell::EffectSchoolDMG(uint32 /*effect_idx*/)
|
|
{
|
|
}
|
|
|
|
void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
|
|
{
|
|
bool apply_direct_bonus = true;
|
|
|
|
if (unitTarget && unitTarget->isAlive())
|
|
{
|
|
switch (m_spellInfo->SpellFamilyName)
|
|
{
|
|
case SPELLFAMILY_GENERIC:
|
|
{
|
|
// Meteor like spells (divided damage to targets)
|
|
if (m_customAttr & SPELL_ATTR_CU_SHARE_DAMAGE)
|
|
{
|
|
uint32 count = 0;
|
|
for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
|
|
if (ihit->effectMask & (1<<effect_idx))
|
|
++count;
|
|
|
|
damage /= count; // divide to all targets
|
|
}
|
|
|
|
switch(m_spellInfo->Id) // better way to check unknown
|
|
{
|
|
// Positive/Negative Charge
|
|
case 28062:
|
|
case 28085:
|
|
case 39090:
|
|
case 39093:
|
|
if (!m_triggeredByAuraSpell)
|
|
break;
|
|
if (unitTarget == m_caster)
|
|
{
|
|
uint8 count = 0;
|
|
for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
|
|
if (ihit->targetGUID != m_caster->GetGUID())
|
|
if (Player *target = ObjectAccessor::GetPlayer(*m_caster, ihit->targetGUID))
|
|
if (target->HasAura(m_triggeredByAuraSpell->Id))
|
|
++count;
|
|
if (count)
|
|
{
|
|
uint32 spellId = 0;
|
|
switch (m_spellInfo->Id)
|
|
{
|
|
case 28062: spellId = 29659; break;
|
|
case 28085: spellId = 29660; break;
|
|
case 39090: spellId = 39089; break;
|
|
case 39093: spellId = 39092; break;
|
|
}
|
|
m_caster->SetAuraStack(spellId, m_caster, count);
|
|
}
|
|
}
|
|
|
|
if (unitTarget->HasAura(m_triggeredByAuraSpell->Id))
|
|
damage = 0;
|
|
break;
|
|
// Consumption
|
|
case 28865:
|
|
damage = (((InstanceMap*)m_caster->GetMap())->GetDifficulty() == REGULAR_DIFFICULTY ? 2750 : 4250);
|
|
break;
|
|
// percent from health with min
|
|
case 25599: // Thundercrash
|
|
{
|
|
damage = unitTarget->GetHealth() / 2;
|
|
if (damage < 200)
|
|
damage = 200;
|
|
break;
|
|
}
|
|
// arcane charge. must only affect demons (also undead?)
|
|
case 45072:
|
|
{
|
|
if (unitTarget->GetCreatureType() != CREATURE_TYPE_DEMON
|
|
&& unitTarget->GetCreatureType() != CREATURE_TYPE_UNDEAD)
|
|
return;
|
|
break;
|
|
}
|
|
case 33671: // gruul's shatter
|
|
case 50811: // krystallus shatter ( Normal )
|
|
case 61547: // krystallus shatter ( Heroic )
|
|
{
|
|
// don't damage self and only players
|
|
if (unitTarget->GetGUID() == m_caster->GetGUID() || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
float radius = GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[0]));
|
|
if (!radius) return;
|
|
float distance = m_caster->GetDistance2d(unitTarget);
|
|
damage = (distance > radius) ? 0 : int32(m_spellInfo->EffectBasePoints[0]*((radius - distance)/radius));
|
|
break;
|
|
}
|
|
// TODO: add spell specific target requirement hook for spells
|
|
// Shadowbolts only affects targets with Shadow Mark (Gothik)
|
|
case 27831:
|
|
case 55638:
|
|
if (!unitTarget->HasAura(27825))
|
|
return;
|
|
break;
|
|
// Cataclysmic Bolt
|
|
case 38441:
|
|
{
|
|
damage = unitTarget->GetMaxHealth() / 2;
|
|
break;
|
|
}
|
|
// Tympanic Tantrum
|
|
case 62775:
|
|
{
|
|
damage = unitTarget->GetMaxHealth() / 10;
|
|
break;
|
|
}
|
|
// Gargoyle Strike
|
|
case 51963:
|
|
{
|
|
// about +4 base spell dmg per level
|
|
damage = (m_caster->getLevel() - 60) * 4 + 60;
|
|
break;
|
|
}
|
|
|
|
// Loken Pulsing Shockwave
|
|
case 59837:
|
|
case 52942:
|
|
{
|
|
// don't damage self and only players
|
|
if(unitTarget->GetGUID() == m_caster->GetGUID() || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
float radius = GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[0]));
|
|
if (!radius)
|
|
return;
|
|
float distance = m_caster->GetDistance2d(unitTarget);
|
|
damage = (distance > radius) ? 0 : int32(m_spellInfo->EffectBasePoints[0]*distance);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_WARRIOR:
|
|
{
|
|
// Bloodthirst
|
|
if (m_spellInfo->SpellFamilyFlags[1] & 0x400)
|
|
damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100);
|
|
// Shield Slam
|
|
else if (m_spellInfo->SpellFamilyFlags[1] & 0x200 && m_spellInfo->Category == 1209)
|
|
damage += m_caster->ApplyEffectModifiers(m_spellInfo,effect_idx,int32(m_caster->GetShieldBlockValue()));
|
|
// Victory Rush
|
|
else if (m_spellInfo->SpellFamilyFlags[1] & 0x100)
|
|
{
|
|
damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
|
|
m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false);
|
|
}
|
|
// Shockwave
|
|
else if (m_spellInfo->Id == 46968)
|
|
{
|
|
int32 pct = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, 2);
|
|
if (pct > 0)
|
|
damage+= int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * pct / 100);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_WARLOCK:
|
|
{
|
|
// Incinerate Rank 1 & 2
|
|
if ((m_spellInfo->SpellFamilyFlags[1] & 0x000040) && m_spellInfo->SpellIconID == 2128)
|
|
{
|
|
// Incinerate does more dmg (dmg*0.25) if the target have Immolate debuff.
|
|
// Check aura state for speed but aura state set not only for Immolate spell
|
|
if (unitTarget->HasAuraState(AURA_STATE_CONFLAGRATE))
|
|
{
|
|
if (unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x4, 0, 0))
|
|
damage += damage/4;
|
|
}
|
|
}
|
|
// Conflagrate - consumes Immolate or Shadowflame
|
|
else if (m_spellInfo->TargetAuraState == AURA_STATE_CONFLAGRATE)
|
|
{
|
|
AuraEffect const* aura = NULL; // found req. aura for damage calculation
|
|
|
|
Unit::AuraEffectList const &mPeriodic = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_DAMAGE);
|
|
for (Unit::AuraEffectList::const_iterator i = mPeriodic.begin(); i != mPeriodic.end(); ++i)
|
|
{
|
|
// for caster applied auras only
|
|
if ((*i)->GetSpellProto()->SpellFamilyName != SPELLFAMILY_WARLOCK ||
|
|
(*i)->GetCasterGUID() != m_caster->GetGUID())
|
|
continue;
|
|
|
|
// Immolate
|
|
if ((*i)->GetSpellProto()->SpellFamilyFlags[0] & 0x4)
|
|
{
|
|
aura = *i; // it selected always if exist
|
|
break;
|
|
}
|
|
|
|
// Shadowflame
|
|
if ((*i)->GetSpellProto()->SpellFamilyFlags[2] & 0x00000002)
|
|
aura = *i; // remember but wait possible Immolate as primary priority
|
|
}
|
|
|
|
// found Immolate or Shadowflame
|
|
if (aura)
|
|
{
|
|
uint32 pdamage = aura->GetAmount() > 0 ? aura->GetAmount() : 0;
|
|
pdamage = m_caster->SpellDamageBonus(unitTarget, aura->GetSpellProto(), pdamage, DOT, aura->GetBase()->GetStackAmount());
|
|
uint32 pct_dir = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, (effect_idx + 1));
|
|
damage += pdamage * aura->GetTotalTicks() * pct_dir / 100;
|
|
|
|
uint32 pct_dot = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, (effect_idx + 2)) / 3;
|
|
m_currentBasePoints[1] = SpellMgr::CalculateSpellEffectBaseAmount(pdamage * aura->GetTotalTicks() * pct_dot / 100, m_spellInfo, 1);
|
|
|
|
apply_direct_bonus = false;
|
|
// Glyph of Conflagrate
|
|
if (!m_caster->HasAura(56235))
|
|
unitTarget->RemoveAurasDueToSpell(aura->GetId(), m_caster->GetGUID());
|
|
|
|
break;
|
|
}
|
|
}
|
|
// Shadow Bite
|
|
else if (m_spellInfo->SpellFamilyFlags[1] & 0x400000)
|
|
{
|
|
if (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->isPet())
|
|
{
|
|
// Get DoTs on target by owner (5% increase by dot)
|
|
damage += 5 * unitTarget->GetDoTsByCaster(m_caster->GetOwnerGUID()) / 100;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_PRIEST:
|
|
{
|
|
// Shadow Word: Death - deals damage equal to damage done to caster
|
|
if ((m_spellInfo->SpellFamilyFlags[1] & 0x2))
|
|
{
|
|
int32 back_damage = m_caster->SpellDamageBonus(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE);
|
|
// Pain and Suffering reduces damage
|
|
if (AuraEffect * aurEff = m_caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 2874, 0))
|
|
back_damage -= aurEff->GetAmount() * back_damage / 100;
|
|
|
|
if (back_damage < unitTarget->GetHealth())
|
|
m_caster->CastCustomSpell(m_caster, 32409, &back_damage, 0, 0, true);
|
|
}
|
|
// Mind Blast - applies Mind Trauma if:
|
|
else if (m_spellInfo->SpellFamilyFlags[2] & 0x00002000)
|
|
{
|
|
// We are in Shadow Form
|
|
if (m_caster->m_form == FORM_SHADOW)
|
|
// We have Improved Mind Blast
|
|
if (AuraEffect * aurEff = m_caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST,95,0))
|
|
// Chance has been successfully rolled
|
|
if (roll_chance_i(aurEff->GetAmount()))
|
|
m_caster->CastSpell(unitTarget, 48301, true);
|
|
}
|
|
// Smite
|
|
else if (m_spellInfo->SpellFamilyFlags[0] & 0x80)
|
|
{
|
|
// Glyph of Smite
|
|
if (AuraEffect * aurEff = m_caster->GetAuraEffect(55692, 0))
|
|
if (unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x100000, 0, 0, m_caster->GetGUID()))
|
|
damage += damage * aurEff->GetAmount() / 100;
|
|
}
|
|
// Improved Mind Blast (Mind Blast in shadow form bonus)
|
|
else if (m_caster->m_form == FORM_SHADOW && (m_spellInfo->SpellFamilyFlags[0] & 0x00002000))
|
|
{
|
|
Unit::AuraEffectList const& ImprMindBlast = m_caster->GetAuraEffectsByType(SPELL_AURA_ADD_FLAT_MODIFIER);
|
|
for (Unit::AuraEffectList::const_iterator i = ImprMindBlast.begin(); i != ImprMindBlast.end(); ++i)
|
|
{
|
|
if ((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_PRIEST &&
|
|
((*i)->GetSpellProto()->SpellIconID == 95))
|
|
{
|
|
int chance = SpellMgr::CalculateSpellEffectAmount((*i)->GetSpellProto(), 1, m_caster);
|
|
if (roll_chance_i(chance))
|
|
// Mind Trauma
|
|
m_caster->CastSpell(unitTarget, 48301, true, 0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_DRUID:
|
|
{
|
|
// Ferocious Bite
|
|
if (m_caster->GetTypeId() == TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags[0] & 0x000800000) && m_spellInfo->SpellVisual[0] == 6587)
|
|
{
|
|
// converts each extra point of energy into ($f1+$AP/410) additional damage
|
|
float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
|
|
float multiple = ap / 410 + m_spellInfo->DmgMultiplier[effect_idx];
|
|
int32 energy = -(m_caster->ModifyPower(POWER_ENERGY, -30));
|
|
damage += int32(energy * multiple);
|
|
damage += int32(m_caster->ToPlayer()->GetComboPoints() * ap * 7 / 100);
|
|
}
|
|
// Wrath
|
|
else if (m_spellInfo->SpellFamilyFlags[0] & 0x00000001)
|
|
{
|
|
// Improved Insect Swarm
|
|
if (AuraEffect const * aurEff = m_caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 1771, 0))
|
|
if (unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00200000, 0, 0))
|
|
damage = int32(damage*(100.0f+aurEff->GetAmount())/100.0f);
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_ROGUE:
|
|
{
|
|
// Envenom
|
|
if (m_caster->GetTypeId() == TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags[1] & 0x8))
|
|
{
|
|
// consume from stack dozes not more that have combo-points
|
|
if (uint32 combo = m_caster->ToPlayer()->GetComboPoints())
|
|
{
|
|
// Lookup for Deadly poison (only attacker applied)
|
|
if (AuraEffect const * aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_ROGUE, 0x10000, 0, 0, m_caster->GetGUID()))
|
|
{
|
|
// count consumed deadly poison doses at target
|
|
bool needConsume = true;
|
|
uint32 spellId = aurEff->GetId();
|
|
uint32 doses = aurEff->GetBase()->GetStackAmount();
|
|
if (doses > combo)
|
|
doses = combo;
|
|
// Master Poisoner
|
|
Unit::AuraEffectList const& auraList = m_caster->ToPlayer()->GetAuraEffectsByType(SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL_NOT_STACK);
|
|
for (Unit::AuraEffectList::const_iterator iter = auraList.begin(); iter != auraList.end(); ++iter)
|
|
{
|
|
if ((*iter)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_ROGUE && (*iter)->GetSpellProto()->SpellIconID == 1960)
|
|
{
|
|
uint32 chance = SpellMgr::CalculateSpellEffectAmount((*iter)->GetSpellProto(), 2, m_caster);
|
|
|
|
if (chance && roll_chance_i(chance))
|
|
needConsume = false;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (needConsume)
|
|
for (uint32 i = 0; i < doses; ++i)
|
|
unitTarget->RemoveAuraFromStack(spellId);
|
|
damage *= doses;
|
|
damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.09f * doses);
|
|
}
|
|
// Eviscerate and Envenom Bonus Damage (item set effect)
|
|
if (m_caster->HasAura(37169))
|
|
damage += ((Player*)m_caster)->GetComboPoints()*40;
|
|
}
|
|
}
|
|
// Eviscerate
|
|
else if ((m_spellInfo->SpellFamilyFlags[0] & 0x00020000) && m_caster->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
if (uint32 combo = ((Player*)m_caster)->GetComboPoints())
|
|
{
|
|
float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
|
|
damage += irand(int32(ap * combo * 0.03f), int32(ap * combo * 0.07f));
|
|
|
|
// Eviscerate and Envenom Bonus Damage (item set effect)
|
|
if (m_caster->HasAura(37169))
|
|
damage += combo*40;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_HUNTER:
|
|
{
|
|
//Gore
|
|
if (m_spellInfo->SpellIconID == 1578)
|
|
{
|
|
if (m_caster->HasAura(57627)) // Charge 6 sec post-affect
|
|
damage *= 2;
|
|
}
|
|
// Steady Shot
|
|
else if (m_spellInfo->SpellFamilyFlags[1] & 0x1)
|
|
{
|
|
bool found = false;
|
|
// check dazed affect
|
|
Unit::AuraEffectList const& decSpeedList = unitTarget->GetAuraEffectsByType(SPELL_AURA_MOD_DECREASE_SPEED);
|
|
for (Unit::AuraEffectList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
|
|
{
|
|
if ((*iter)->GetSpellProto()->SpellIconID == 15 && (*iter)->GetSpellProto()->Dispel == 0)
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// TODO: should this be put on taken but not done?
|
|
if (found)
|
|
damage += m_spellInfo->EffectBasePoints[1];
|
|
|
|
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
// Add Ammo and Weapon damage plus RAP * 0.1
|
|
Item *item = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK);
|
|
if (item)
|
|
{
|
|
float dmg_min = item->GetProto()->Damage->DamageMin;
|
|
float dmg_max = item->GetProto()->Damage->DamageMax;
|
|
if (dmg_max == 0.0f && dmg_min > dmg_max)
|
|
damage += int32(dmg_min);
|
|
else
|
|
damage += irand(int32(dmg_min), int32(dmg_max));
|
|
damage += m_caster->ToPlayer()->GetAmmoDPS()*item->GetProto()->Delay*0.001f;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_PALADIN:
|
|
{
|
|
// Hammer of the Righteous
|
|
if (m_spellInfo->SpellFamilyFlags[1]&0x00040000)
|
|
{
|
|
// Add main hand dps * effect[2] amount
|
|
float average = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2;
|
|
int32 count = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, 2);
|
|
damage += count * int32(average * IN_MILLISECONDS) / m_caster->GetAttackTime(BASE_ATTACK);
|
|
}
|
|
// Shield of Righteousness
|
|
else if (m_spellInfo->SpellFamilyFlags[1]&0x00100000)
|
|
{
|
|
damage += int32(m_caster->GetShieldBlockValue() * 1.3f);
|
|
}
|
|
// Judgement of Righteousness
|
|
else if (m_spellInfo->Id == 20187)
|
|
{
|
|
float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
|
|
float sp = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo));
|
|
damage += int32(0.2f*ap + 0.32f*sp);
|
|
}
|
|
// Judgement of Wisdom, Light, Justice
|
|
else if (m_spellInfo->Id == 54158)
|
|
{
|
|
float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
|
|
float sp = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo));
|
|
damage += int32(0.14f*ap + 0.22f*sp);
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_DEATHKNIGHT:
|
|
{
|
|
// Blood Boil - bonus for diseased targets
|
|
if (m_spellInfo->SpellFamilyFlags[0] & 0x00040000 && unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, 0, 0, 0x00000002, m_caster->GetGUID()))
|
|
{
|
|
damage += m_damage / 2;
|
|
damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)* 0.035f);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (m_originalCaster && damage > 0 && apply_direct_bonus)
|
|
damage = m_originalCaster->SpellDamageBonus(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE);
|
|
|
|
m_damage += damage;
|
|
}
|
|
}
|
|
|
|
void Spell::EffectDummy(uint32 i)
|
|
{
|
|
if (!unitTarget && !gameObjTarget && !itemTarget)
|
|
return;
|
|
|
|
uint32 spell_id = 0;
|
|
int32 bp = 0;
|
|
bool triggered = true;
|
|
SpellCastTargets targets;
|
|
|
|
// selection by spell family
|
|
switch (m_spellInfo->SpellFamilyName)
|
|
{
|
|
case SPELLFAMILY_GENERIC:
|
|
{
|
|
switch (m_spellInfo->Id)
|
|
{
|
|
case 8063: // Deviate Fish
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
uint32 spell_id = 0;
|
|
switch(urand(1,5))
|
|
{
|
|
case 1: spell_id = 8064; break; // Sleepy
|
|
case 2: spell_id = 8065; break; // Invigorate
|
|
case 3: spell_id = 8066; break; // Shrink
|
|
case 4: spell_id = 8067; break; // Party Time!
|
|
case 5: spell_id = 8068; break; // Healthy Spirit
|
|
}
|
|
m_caster->CastSpell(m_caster, spell_id, true, NULL);
|
|
return;
|
|
}
|
|
case 8213: // Savory Deviate Delight
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
uint32 spell_id = 0;
|
|
switch(urand(1,2))
|
|
{
|
|
// Flip Out - ninja
|
|
case 1: spell_id = (m_caster->getGender() == GENDER_MALE ? 8219 : 8220); break;
|
|
// Yaaarrrr - pirate
|
|
case 2: spell_id = (m_caster->getGender() == GENDER_MALE ? 8221 : 8222); break;
|
|
}
|
|
m_caster->CastSpell(m_caster,spell_id,true,NULL);
|
|
return;
|
|
}
|
|
case 8593: // Symbol of life (restore creature to life)
|
|
case 31225: // Shimmering Vessel (restore creature to life)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
|
|
return;
|
|
unitTarget->ToCreature()->setDeathState(JUST_ALIVED);
|
|
return;
|
|
}
|
|
case 12162: // Deep wounds
|
|
case 12850: // (now good common check for this spells)
|
|
case 12868:
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
float damage;
|
|
// DW should benefit of attack power, damage percent mods etc.
|
|
// TODO: check if using offhand damage is correct and if it should be divided by 2
|
|
if (m_caster->haveOffhandWeapon() && m_caster->getAttackTimer(BASE_ATTACK) > m_caster->getAttackTimer(OFF_ATTACK))
|
|
damage = (m_caster->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE))/2;
|
|
else
|
|
damage = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE))/2;
|
|
|
|
switch (m_spellInfo->Id)
|
|
{
|
|
case 12162: damage *= 0.16f; break; // Rank 1
|
|
case 12850: damage *= 0.32f; break; // Rank 2
|
|
case 12868: damage *= 0.48f; break; // Rank 3
|
|
default:
|
|
sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id);
|
|
return;
|
|
};
|
|
|
|
// get remaining damage of old Deep Wound aura
|
|
AuraEffect* deepWound = unitTarget->GetAuraEffect(12721, 0);
|
|
if (deepWound)
|
|
{
|
|
int32 remainingTicks = deepWound->GetBase()->GetDuration() / deepWound->GetAmplitude();
|
|
damage += remainingTicks * deepWound->GetAmount();
|
|
}
|
|
|
|
// 1 tick/sec * 6 sec = 6 ticks
|
|
int32 deepWoundsDotBasePoints0 = int32(damage / 6);
|
|
m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL);
|
|
return;
|
|
}
|
|
case 13120: // net-o-matic
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
uint32 spell_id = 0;
|
|
|
|
uint32 roll = urand(0, 99);
|
|
|
|
if (roll < 2) // 2% for 30 sec self root (off-like chance unknown)
|
|
spell_id = 16566;
|
|
else if (roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown)
|
|
spell_id = 13119;
|
|
else // normal root
|
|
spell_id = 13099;
|
|
|
|
m_caster->CastSpell(unitTarget,spell_id,true,NULL);
|
|
return;
|
|
}
|
|
case 67019: // Flask of the North
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
uint32 spell_id;
|
|
switch(urand(1, 3))
|
|
{
|
|
case 1: spell_id = 67016; break;
|
|
case 2: spell_id = 67017; break;
|
|
default:spell_id = 67018; break;
|
|
}
|
|
|
|
m_caster->CastSpell(m_caster, spell_id, true, NULL);
|
|
return;
|
|
}
|
|
case 13280: // Gnomish Death Ray
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
if (urand(0, 99) < 15)
|
|
m_caster->CastSpell(m_caster, 13493, true, NULL); // failure
|
|
else
|
|
m_caster->CastSpell(unitTarget, 13279, true, NULL);
|
|
|
|
return;
|
|
}
|
|
case 13567: // Dummy Trigger
|
|
{
|
|
// can be used for different aura triggering, so select by aura
|
|
if (!m_triggeredByAuraSpell || !unitTarget)
|
|
return;
|
|
|
|
switch (m_triggeredByAuraSpell->Id)
|
|
{
|
|
case 26467: // Persistent Shield
|
|
m_caster->CastCustomSpell(unitTarget, 26470, &damage, NULL, NULL, true);
|
|
break;
|
|
default:
|
|
sLog.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u",m_triggeredByAuraSpell->Id);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
case 14537: // Six Demon Bag
|
|
{
|
|
if( !unitTarget || !unitTarget->isAlive()) return;
|
|
|
|
uint32 ClearSpellId[6] =
|
|
{
|
|
15662, // Fireball
|
|
11538, // Frostball
|
|
21179, // Chain Lightning
|
|
14621, // Polymorph
|
|
25189, // Enveloping Winds
|
|
14642 // Summon Felhund minion
|
|
};
|
|
|
|
uint32 effect = 0;
|
|
uint32 rand = urand(0, 100);
|
|
|
|
if (rand >= 0 && rand < 25) // Fireball (25% chance)
|
|
effect = ClearSpellId[0];
|
|
else if (rand >= 25 && rand < 50) // Frostball (25% chance)
|
|
effect = ClearSpellId[1];
|
|
else if (rand >=50 && rand < 70) // Chain Lighting (25% chance)
|
|
effect = ClearSpellId[2];
|
|
else if (rand >= 70 && rand < 80) // Polymorph (10% chance)
|
|
{
|
|
effect = ClearSpellId[3];
|
|
if (urand(0, 100) <= 30) // 30% chance to self-cast
|
|
unitTarget = m_caster;
|
|
}
|
|
else if (rand >=80 && rand < 95) // Enveloping Winds (15% chance)
|
|
effect = ClearSpellId[4];
|
|
else // Summon Felhund minion (5% chance)
|
|
{
|
|
effect = ClearSpellId[5];
|
|
unitTarget = m_caster;
|
|
}
|
|
|
|
m_caster->CastSpell(unitTarget, effect, true);
|
|
return;
|
|
}
|
|
case 15998: // Capture Worg Pup
|
|
case 29435: // Capture Female Kaliri Hatchling
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
|
|
return;
|
|
|
|
unitTarget->ToCreature()->ForcedDespawn();
|
|
return;
|
|
}
|
|
case 16589: // Noggenfogger Elixir
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
uint32 spell_id = 0;
|
|
switch (urand(1, 3))
|
|
{
|
|
case 1: spell_id = 16595; break;
|
|
case 2: spell_id = 16593; break;
|
|
default:spell_id = 16591; break;
|
|
}
|
|
|
|
m_caster->CastSpell(m_caster, spell_id, true, NULL);
|
|
return;
|
|
}
|
|
case 17251: // Spirit Healer Res
|
|
{
|
|
if (!unitTarget || !m_originalCaster)
|
|
return;
|
|
|
|
if (m_originalCaster->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
WorldPacket data(SMSG_SPIRIT_HEALER_CONFIRM, 8);
|
|
data << uint64(unitTarget->GetGUID());
|
|
m_originalCaster->ToPlayer()->GetSession()->SendPacket(&data);
|
|
}
|
|
return;
|
|
}
|
|
case 17271: // Test Fetid Skull
|
|
{
|
|
if (!itemTarget && m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
uint32 spell_id = roll_chance_i(50)
|
|
? 17269 // Create Resonating Skull
|
|
: 17270; // Create Bone Dust
|
|
|
|
m_caster->CastSpell(m_caster, spell_id, true, NULL);
|
|
return;
|
|
}
|
|
case 20577: // Cannibalize
|
|
if (unitTarget)
|
|
m_caster->CastSpell(m_caster, 20578, false, NULL);
|
|
return;
|
|
case 23019: // Crystal Prison Dummy DND
|
|
{
|
|
if (!unitTarget || !unitTarget->isAlive() || unitTarget->GetTypeId() != TYPEID_UNIT || unitTarget->ToCreature()->isPet())
|
|
return;
|
|
|
|
Creature* creatureTarget = unitTarget->ToCreature();
|
|
|
|
m_caster->SummonGameObject(179644, creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(), creatureTarget->GetOrientation(), 0, 0, 0, 0, creatureTarget->GetRespawnTime()-time(NULL));
|
|
sLog.outDebug("SummonGameObject at SpellEfects.cpp EffectDummy for Spell 23019");
|
|
|
|
creatureTarget->ForcedDespawn();
|
|
|
|
return;
|
|
}
|
|
case 23074: // Arcanite Dragonling
|
|
if (!m_CastItem) return;
|
|
m_caster->CastSpell(m_caster, 19804, true, m_CastItem);
|
|
return;
|
|
case 23075: // Mithril Mechanical Dragonling
|
|
if (!m_CastItem) return;
|
|
m_caster->CastSpell(m_caster, 12749, true, m_CastItem);
|
|
return;
|
|
case 23076: // Mechanical Dragonling
|
|
if (!m_CastItem) return;
|
|
m_caster->CastSpell(m_caster, 4073, true, m_CastItem);
|
|
return;
|
|
case 23133: // Gnomish Battle Chicken
|
|
if (!m_CastItem) return;
|
|
m_caster->CastSpell(m_caster, 13166, true, m_CastItem);
|
|
return;
|
|
case 23448: // Transporter Arrival - Ultrasafe Transporter: Gadgetzan - backfires
|
|
{
|
|
int32 r = irand(0, 119);
|
|
if (r < 20) // Transporter Malfunction - 1/6 polymorph
|
|
m_caster->CastSpell(m_caster, 23444, true);
|
|
else if (r < 100) // Evil Twin - 4/6 evil twin
|
|
m_caster->CastSpell(m_caster, 23445, true);
|
|
else // Transporter Malfunction - 1/6 miss the target
|
|
m_caster->CastSpell(m_caster, 36902, true);
|
|
return;
|
|
}
|
|
case 23453: // Gnomish Transporter - Ultrasafe Transporter: Gadgetzan
|
|
if (roll_chance_i(50)) // Gadgetzan Transporter - success
|
|
m_caster->CastSpell(m_caster, 23441, true);
|
|
else // Gadgetzan Transporter Failure - failure
|
|
m_caster->CastSpell(m_caster, 23446, true);
|
|
return;
|
|
case 23645: // Hourglass Sand
|
|
m_caster->RemoveAurasDueToSpell(23170); // Brood Affliction: Bronze
|
|
return;
|
|
case 23725: // Gift of Life (warrior bwl trinket)
|
|
m_caster->CastSpell(m_caster, 23782, true);
|
|
m_caster->CastSpell(m_caster, 23783, true);
|
|
return;
|
|
case 25860: // Reindeer Transformation
|
|
{
|
|
if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED))
|
|
return;
|
|
|
|
float flyspeed = m_caster->GetSpeedRate(MOVE_FLIGHT);
|
|
float speed = m_caster->GetSpeedRate(MOVE_RUN);
|
|
|
|
m_caster->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
|
|
|
//5 different spells used depending on mounted speed and if mount can fly or not
|
|
if (flyspeed >= 4.1f)
|
|
// Flying Reindeer
|
|
m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer
|
|
else if (flyspeed >= 3.8f)
|
|
// Flying Reindeer
|
|
m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer
|
|
else if (flyspeed >= 1.6f)
|
|
// Flying Reindeer
|
|
m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer
|
|
else if (speed >= 2.0f)
|
|
// Reindeer
|
|
m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer
|
|
else
|
|
// Reindeer
|
|
m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer
|
|
|
|
return;
|
|
}
|
|
case 26074: // Holiday Cheer
|
|
// implemented at client side
|
|
return;
|
|
// Polarity Shift
|
|
case 28089:
|
|
if (unitTarget)
|
|
unitTarget->CastSpell(unitTarget, roll_chance_i(50) ? 28059 : 28084, true, NULL, NULL, m_caster->GetGUID());
|
|
break;
|
|
// Polarity Shift
|
|
case 39096:
|
|
if (unitTarget)
|
|
unitTarget->CastSpell(unitTarget, roll_chance_i(50) ? 39088 : 39091, true, NULL, NULL, m_caster->GetGUID());
|
|
break;
|
|
case 29200: // Purify Helboar Meat
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
uint32 spell_id = roll_chance_i(50)
|
|
? 29277 // Summon Purified Helboar Meat
|
|
: 29278; // Summon Toxic Helboar Meat
|
|
|
|
m_caster->CastSpell(m_caster,spell_id,true,NULL);
|
|
return;
|
|
}
|
|
case 29858: // Soulshatter
|
|
if (unitTarget && unitTarget->CanHaveThreatList()
|
|
&& unitTarget->getThreatManager().getThreat(m_caster) > 0.0f)
|
|
m_caster->CastSpell(unitTarget,32835,true);
|
|
return;
|
|
case 30458: // Nigh Invulnerability
|
|
if (!m_CastItem) return;
|
|
if (roll_chance_i(86)) // Nigh-Invulnerability - success
|
|
m_caster->CastSpell(m_caster, 30456, true, m_CastItem);
|
|
else // Complete Vulnerability - backfire in 14% casts
|
|
m_caster->CastSpell(m_caster, 30457, true, m_CastItem);
|
|
return;
|
|
case 30507: // Poultryizer
|
|
if (!m_CastItem) return;
|
|
if (roll_chance_i(80)) // Poultryized! - success
|
|
m_caster->CastSpell(unitTarget, 30501, true, m_CastItem);
|
|
else // Poultryized! - backfire 20%
|
|
m_caster->CastSpell(unitTarget, 30504, true, m_CastItem);
|
|
return;
|
|
case 33060: // Make a Wish
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
uint32 spell_id = 0;
|
|
|
|
switch(urand(1,5))
|
|
{
|
|
case 1: spell_id = 33053; break; // Mr Pinchy's Blessing
|
|
case 2: spell_id = 33057; break; // Summon Mighty Mr. Pinchy
|
|
case 3: spell_id = 33059; break; // Summon Furious Mr. Pinchy
|
|
case 4: spell_id = 33062; break; // Tiny Magical Crawdad
|
|
case 5: spell_id = 33064; break; // Mr. Pinchy's Gift
|
|
}
|
|
|
|
m_caster->CastSpell(m_caster, spell_id, true, NULL);
|
|
return;
|
|
}
|
|
case 34665: //Administer Antidote
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT
|
|
|| unitTarget->GetEntry() != 16880 || unitTarget->ToCreature()->isPet())
|
|
return;
|
|
|
|
unitTarget->ToCreature()->UpdateEntry(16992);
|
|
m_caster->ToPlayer()->RewardPlayerAndGroupAtEvent(16992, unitTarget);
|
|
|
|
if (unitTarget->IsAIEnabled)
|
|
unitTarget->ToCreature()->AI()->AttackStart(m_caster);
|
|
|
|
return;
|
|
}
|
|
case 35745: // Socrethar's Stone
|
|
{
|
|
uint32 spell_id;
|
|
switch(m_caster->GetAreaId())
|
|
{
|
|
case 3900: spell_id = 35743; break; // Socrethar Portal
|
|
case 3742: spell_id = 35744; break; // Socrethar Portal
|
|
default: return;
|
|
}
|
|
|
|
m_caster->CastSpell(m_caster, spell_id, true);
|
|
return;
|
|
}
|
|
case 37674: // Chaos Blast
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
int32 basepoints0 = 100;
|
|
m_caster->CastCustomSpell(unitTarget, 37675, &basepoints0, NULL, NULL, true);
|
|
return;
|
|
}
|
|
case 40109: // Knockdown Fel Cannon: The Bolt
|
|
{
|
|
unitTarget->CastSpell(unitTarget, 40075, true);
|
|
return;
|
|
}
|
|
case 40802: // Mingo's Fortune Generator (Mingo's Fortune Giblets)
|
|
{
|
|
// selecting one from Bloodstained Fortune item
|
|
uint32 newitemid;
|
|
switch(urand(1, 20))
|
|
{
|
|
case 1: newitemid = 32688; break;
|
|
case 2: newitemid = 32689; break;
|
|
case 3: newitemid = 32690; break;
|
|
case 4: newitemid = 32691; break;
|
|
case 5: newitemid = 32692; break;
|
|
case 6: newitemid = 32693; break;
|
|
case 7: newitemid = 32700; break;
|
|
case 8: newitemid = 32701; break;
|
|
case 9: newitemid = 32702; break;
|
|
case 10: newitemid = 32703; break;
|
|
case 11: newitemid = 32704; break;
|
|
case 12: newitemid = 32705; break;
|
|
case 13: newitemid = 32706; break;
|
|
case 14: newitemid = 32707; break;
|
|
case 15: newitemid = 32708; break;
|
|
case 16: newitemid = 32709; break;
|
|
case 17: newitemid = 32710; break;
|
|
case 18: newitemid = 32711; break;
|
|
case 19: newitemid = 32712; break;
|
|
case 20: newitemid = 32713; break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
DoCreateItem(i, newitemid);
|
|
return;
|
|
}
|
|
// Wrath of the Astromancer
|
|
case 42784:
|
|
{
|
|
uint32 count = 0;
|
|
for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
|
|
if (ihit->effectMask & (1<<i))
|
|
++count;
|
|
|
|
damage = 12000; // maybe wrong value
|
|
damage /= count;
|
|
|
|
SpellEntry const *spellInfo = sSpellStore.LookupEntry(42784);
|
|
|
|
// now deal the damage
|
|
for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
|
|
if (ihit->effectMask & (1<<i))
|
|
{
|
|
if (Unit* casttarget = Unit::GetUnit((*unitTarget), ihit->targetGUID))
|
|
m_caster->DealDamage(casttarget, damage, NULL, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_ARCANE, spellInfo, false);
|
|
}
|
|
|
|
return;
|
|
}
|
|
// Demon Broiled Surprise
|
|
case 43723:
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player *player = (Player*)m_caster;
|
|
|
|
if (player && player->GetQuestStatus(11379) == QUEST_STATUS_INCOMPLETE)
|
|
{
|
|
Creature *creature = player->FindNearestCreature(19973, 10, false);
|
|
if (!creature)
|
|
{
|
|
SendCastResult(SPELL_FAILED_NOT_HERE);
|
|
return;
|
|
}
|
|
|
|
player->CastSpell(player, 43753, false);
|
|
}
|
|
return;
|
|
}
|
|
case 44875: // Complete Raptor Capture
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
|
|
return;
|
|
|
|
unitTarget->ToCreature()->ForcedDespawn();
|
|
|
|
//cast spell Raptor Capture Credit
|
|
m_caster->CastSpell(m_caster, 42337, true, NULL);
|
|
return;
|
|
}
|
|
case 47170: // Impale Leviroth
|
|
{
|
|
if (!unitTarget && unitTarget->GetEntry() != 26452 && ((unitTarget->GetHealth() / unitTarget->GetMaxHealth()) * 100.0f) > 95.0f)
|
|
return;
|
|
|
|
m_caster->DealDamage(unitTarget, unitTarget->GetMaxHealth()*0.93f);
|
|
return;
|
|
}
|
|
case 49357: // Brewfest Mount Transformation
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED))
|
|
return;
|
|
m_caster->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
|
// Ram for Alliance, Kodo for Horde
|
|
if (m_caster->ToPlayer()->GetTeam() == ALLIANCE)
|
|
{
|
|
if (m_caster->GetSpeedRate(MOVE_RUN) >= 2.0f)
|
|
// 100% Ram
|
|
m_caster->CastSpell(m_caster, 43900, true);
|
|
else
|
|
// 60% Ram
|
|
m_caster->CastSpell(m_caster, 43899, true);
|
|
}
|
|
else
|
|
{
|
|
if (m_caster->ToPlayer()->GetSpeedRate(MOVE_RUN) >= 2.0f)
|
|
// 100% Kodo
|
|
m_caster->CastSpell(m_caster, 49379, true);
|
|
else
|
|
// 60% Kodo
|
|
m_caster->CastSpell(m_caster, 49378, true);
|
|
}
|
|
return;
|
|
// Magic Pull
|
|
case 51336:
|
|
m_caster->CastSpell(unitTarget,50770,true);
|
|
break;
|
|
case 52845: // Brewfest Mount Transformation (Faction Swap)
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED))
|
|
return;
|
|
m_caster->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
|
// Ram for Horde, Kodo for Alliance
|
|
if (m_caster->ToPlayer()->GetTeam() == HORDE)
|
|
{
|
|
if (m_caster->GetSpeedRate(MOVE_RUN) >= 2.0f)
|
|
// 100% Ram
|
|
m_caster->CastSpell(m_caster, 43900, true);
|
|
else
|
|
// 60% Ram
|
|
m_caster->CastSpell(m_caster, 43899, true);
|
|
}
|
|
else
|
|
{
|
|
if (m_caster->ToPlayer()->GetSpeedRate(MOVE_RUN) >= 2.0f)
|
|
// 100% Kodo
|
|
m_caster->CastSpell(m_caster, 49379, true);
|
|
else
|
|
// 60% Kodo
|
|
m_caster->CastSpell(m_caster, 49378, true);
|
|
}
|
|
return;
|
|
case 55004: // Nitro Boosts
|
|
if (!m_CastItem)
|
|
return;
|
|
if (roll_chance_i(95)) // Nitro Boosts - success
|
|
m_caster->CastSpell(m_caster, 54861, true, m_CastItem);
|
|
else // Knocked Up - backfire 5%
|
|
m_caster->CastSpell(m_caster, 46014, true, m_CastItem);
|
|
return;
|
|
case 50243: // Teach Language
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// spell has a 1/3 chance to trigger one of the below
|
|
if (roll_chance_i(66))
|
|
return;
|
|
if (m_caster->ToPlayer()->GetTeam() == ALLIANCE)
|
|
{
|
|
// 1000001 - gnomish binary
|
|
m_caster->CastSpell(m_caster, 50242, true);
|
|
}
|
|
else
|
|
{
|
|
// 01001000 - goblin binary
|
|
m_caster->CastSpell(m_caster, 50246, true);
|
|
}
|
|
|
|
return;
|
|
}
|
|
case 51582: //Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite)
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
if (BattleGround* bg = m_caster->ToPlayer()->GetBattleGround())
|
|
bg->EventPlayerDroppedFlag(m_caster->ToPlayer());
|
|
|
|
m_caster->CastSpell(m_caster, 30452, true, NULL);
|
|
return;
|
|
}
|
|
case 51592: // Pickup Primordial Hatchling
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
|
|
return;
|
|
|
|
unitTarget->ToCreature()->ForcedDespawn();
|
|
return;
|
|
}
|
|
case 52308: // Take Sputum Sample
|
|
{
|
|
switch(i)
|
|
{
|
|
case 0:
|
|
{
|
|
uint32 spellID = SpellMgr::CalculateSpellEffectAmount(m_spellInfo, 0);
|
|
uint32 reqAuraID = SpellMgr::CalculateSpellEffectAmount(m_spellInfo, 1);
|
|
|
|
if (m_caster->HasAuraEffect(reqAuraID,0))
|
|
m_caster->CastSpell(m_caster,spellID,true,NULL);
|
|
return;
|
|
}
|
|
case 1:
|
|
return; // additional data for dummy[0]
|
|
}
|
|
return;
|
|
}
|
|
case 52759: // Ancestral Awakening
|
|
if (!unitTarget)
|
|
return;
|
|
m_caster->CastCustomSpell(unitTarget, 52752, &damage, NULL, NULL, true);
|
|
return;
|
|
case 54171: //Divine Storm
|
|
{
|
|
m_caster->CastCustomSpell(unitTarget, 54172, &damage, 0, 0, true);
|
|
return;
|
|
}
|
|
case 58418: // Portal to Orgrimmar
|
|
case 58420: // Portal to Stormwind
|
|
return; // implemented in EffectScript[0]
|
|
case 59640: // Underbelly Elixir
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
uint32 spell_id = 0;
|
|
switch(urand(1,3))
|
|
{
|
|
case 1: spell_id = 59645; break;
|
|
case 2: spell_id = 59831; break;
|
|
case 3: spell_id = 59843; break;
|
|
}
|
|
m_caster->CastSpell(m_caster,spell_id,true,NULL);
|
|
return;
|
|
}
|
|
case 62324: // Throw Passenger
|
|
{
|
|
if (m_targets.HasTraj())
|
|
{
|
|
if (Vehicle *vehicle = m_caster->GetVehicleKit())
|
|
if (Unit *passenger = vehicle->GetPassenger(damage - 1))
|
|
{
|
|
std::list<Unit*> unitList;
|
|
// use 99 because it is 3d search
|
|
SearchAreaTarget(unitList, 99, PUSH_DST_CENTER, SPELL_TARGETS_ENTRY, 33114);
|
|
float minDist = 99 * 99;
|
|
Vehicle *target = NULL;
|
|
for (std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end(); ++itr)
|
|
{
|
|
if (Vehicle *seat = (*itr)->GetVehicleKit())
|
|
if (!seat->GetPassenger(0))
|
|
if (Unit *device = seat->GetPassenger(2))
|
|
if (!device->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
|
|
{
|
|
float dist = (*itr)->GetExactDistSq(&m_targets.m_dstPos);
|
|
if (dist < minDist)
|
|
{
|
|
minDist = dist;
|
|
target = seat;
|
|
}
|
|
}
|
|
}
|
|
if (target && target->GetBase()->IsWithinDist2d(&m_targets.m_dstPos, GetSpellRadius(m_spellInfo, i, false) * 2)) // now we use *2 because the location of the seat is not correct
|
|
passenger->EnterVehicle(target, 0);
|
|
else
|
|
{
|
|
passenger->ExitVehicle();
|
|
float x, y, z;
|
|
m_targets.m_dstPos.GetPosition(x, y, z);
|
|
passenger->GetMotionMaster()->MoveJump(x, y, z, m_targets.GetSpeedXY(), m_targets.GetSpeedZ());
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
case 64385: // Unusual Compass
|
|
{
|
|
m_caster->SetOrientation(float(urand(0,62832)) / 10000.0f);
|
|
WorldPacket data;
|
|
m_caster->BuildHeartBeatMsg(&data);
|
|
m_caster->SendMessageToSet(&data,true);
|
|
return;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case SPELLFAMILY_WARRIOR:
|
|
// Charge
|
|
if (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_WARRIOR_CHARGE && m_spellInfo->SpellVisual[0] == 867)
|
|
{
|
|
int32 chargeBasePoints0 = damage;
|
|
m_caster->CastCustomSpell(m_caster, 34846, &chargeBasePoints0, NULL, NULL, true);
|
|
|
|
//Juggernaut crit bonus
|
|
if (m_caster->HasAura(64976))
|
|
m_caster->CastSpell(m_caster, 65156, true);
|
|
return;
|
|
}
|
|
//Slam
|
|
if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_WARRIOR_SLAM && m_spellInfo->SpellIconID == 559)
|
|
{
|
|
int32 bp0 = damage;
|
|
m_caster->CastCustomSpell(unitTarget, 50783, &bp0, NULL, NULL, true, 0);
|
|
return;
|
|
}
|
|
// Execute
|
|
if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_WARRIOR_EXECUTE)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
uint32 rage = m_caster->GetPower(POWER_RAGE);
|
|
|
|
// Glyph of Execution bonus
|
|
if (AuraEffect *aura = m_caster->GetAuraEffect(58367, 0))
|
|
rage += aura->GetAmount();
|
|
|
|
spell_id = 20647;
|
|
|
|
// Sudden death cost modifier
|
|
if (Aura * aur = m_caster->GetAura(52437))
|
|
{
|
|
rage += m_powerCost;
|
|
m_caster->ModifyPower(POWER_RAGE, -m_powerCost);
|
|
if (m_caster->GetPower(POWER_RAGE) < 100)
|
|
m_caster->SetPower(POWER_RAGE, 100);
|
|
m_caster->RemoveAura(aur);
|
|
}
|
|
else
|
|
{
|
|
rage += m_powerCost;
|
|
m_caster->ModifyPower(POWER_RAGE, -m_powerCost);
|
|
}
|
|
|
|
if (rage > 300)
|
|
rage = 300;
|
|
|
|
bp = damage+int32(rage * m_spellInfo->DmgMultiplier[i] +
|
|
m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
|
|
break;
|
|
}
|
|
// Concussion Blow
|
|
if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_WARRIOR_CONCUSSION_BLOW)
|
|
{
|
|
m_damage+= uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
|
|
return;
|
|
}
|
|
switch(m_spellInfo->Id)
|
|
{
|
|
// Bloodthirst
|
|
case 23881:
|
|
{
|
|
m_caster->CastCustomSpell(unitTarget, 23885, &damage, NULL, NULL, true, NULL);
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
case SPELLFAMILY_WARLOCK:
|
|
// Life Tap
|
|
if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_WARLOCK_LIFETAP)
|
|
{
|
|
float spFactor = 0;
|
|
switch (m_spellInfo->Id)
|
|
{
|
|
case 11689: spFactor = 0.2; break;
|
|
case 27222:
|
|
case 57946: spFactor = 0.5; break;
|
|
default: spFactor = 0; break;
|
|
}
|
|
int32 damage = m_spellInfo->EffectBasePoints[0] + (6.3875 * m_spellInfo->baseLevel);
|
|
int32 mana = damage + (m_caster->ToPlayer()->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+SPELL_SCHOOL_SHADOW) * spFactor);
|
|
|
|
if (unitTarget && (int32(unitTarget->GetHealth()) > damage))
|
|
{
|
|
// Shouldn't Appear in Combat Log
|
|
unitTarget->ModifyHealth(-damage);
|
|
|
|
// Improved Life Tap mod
|
|
if (AuraEffect const * aurEff = m_caster->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, 208, 0))
|
|
mana = (aurEff->GetAmount() + 100)* mana / 100;
|
|
|
|
m_caster->CastCustomSpell(unitTarget, 31818, &mana, NULL, NULL, true);
|
|
|
|
// Mana Feed
|
|
int32 manaFeedVal = 0;
|
|
if (AuraEffect const * aurEff = m_caster->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_WARLOCK, 1982, 0))
|
|
manaFeedVal = aurEff->GetAmount();
|
|
|
|
if (manaFeedVal > 0)
|
|
{
|
|
manaFeedVal = manaFeedVal * mana / 100;
|
|
m_caster->CastCustomSpell(m_caster, 32553, &manaFeedVal, NULL, NULL, true, NULL);
|
|
}
|
|
}
|
|
else
|
|
SendCastResult(SPELL_FAILED_FIZZLE);
|
|
return;
|
|
}
|
|
break;
|
|
case SPELLFAMILY_DRUID:
|
|
// Starfall
|
|
if (m_spellInfo->SpellFamilyFlags[2] & SPELLFAMILYFLAG2_DRUID_STARFALL)
|
|
{
|
|
//Shapeshifting into an animal form or mounting cancels the effect.
|
|
if (m_caster->GetCreatureType() == CREATURE_TYPE_BEAST || m_caster->IsMounted())
|
|
{
|
|
if (m_triggeredByAuraSpell)
|
|
m_caster->RemoveAurasDueToSpell(m_triggeredByAuraSpell->Id);
|
|
return;
|
|
}
|
|
|
|
//Any effect which causes you to lose control of your character will supress the starfall effect.
|
|
if (m_caster->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_ROOT | UNIT_STAT_CONFUSED))
|
|
return;
|
|
|
|
m_caster->CastSpell(unitTarget, damage, true);
|
|
return;
|
|
}
|
|
break;
|
|
case SPELLFAMILY_HUNTER:
|
|
switch(m_spellInfo->Id)
|
|
{
|
|
case 37506: // Scatter Shot
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// break Auto Shot and autohit
|
|
m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
|
|
m_caster->AttackStop();
|
|
m_caster->ToPlayer()->SendAttackSwingCancelAttack();
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
case SPELLFAMILY_PALADIN:
|
|
// Divine Storm
|
|
if (m_spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_PALADIN_DIVINESTORM && i == 1)
|
|
{
|
|
int32 dmg = m_damage * damage / 100;
|
|
if (!unitTarget)
|
|
unitTarget = m_caster;
|
|
m_caster->CastCustomSpell(unitTarget, 54171, &dmg, 0, 0, true);
|
|
return;
|
|
}
|
|
|
|
switch(m_spellInfo->Id)
|
|
{
|
|
case 31789: // Righteous Defense (step 1)
|
|
{
|
|
// 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), copy
|
|
Unit::AttackerSet attackers = unitTarget->getAttackers();
|
|
|
|
// selected from list 3
|
|
for (int i = 0; i < std::min(size_t(3),attackers.size()); ++i)
|
|
{
|
|
Unit::AttackerSet::iterator aItr = attackers.begin();
|
|
std::advance(aItr, rand() % attackers.size());
|
|
AddUnitTarget((*aItr), 1);
|
|
attackers.erase(aItr);
|
|
}
|
|
|
|
// now let next effect cast spell at each target.
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
case SPELLFAMILY_SHAMAN:
|
|
// Cleansing Totem Pulse
|
|
if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_SHAMAN_TOTEM_EFFECTS && m_spellInfo->SpellIconID == 1673)
|
|
{
|
|
int32 bp1 = 1;
|
|
// Cleansing Totem Effect
|
|
if (unitTarget)
|
|
m_caster->CastCustomSpell(unitTarget, 52025, NULL, &bp1, NULL, true, NULL, NULL, m_originalCasterGUID);
|
|
return;
|
|
}
|
|
// Healing Stream Totem
|
|
if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_SHAMAN_HEALING_STREAM)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
// Restorative Totems
|
|
if (Unit *owner = m_caster->GetOwner())
|
|
if (AuraEffect *dummy = owner->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 338, 1))
|
|
damage += damage * dummy->GetAmount() / 100;
|
|
|
|
m_caster->CastCustomSpell(unitTarget, 52042, &damage, 0, 0, true, 0, 0, m_originalCasterGUID);
|
|
return;
|
|
}
|
|
// Mana Spring Totem
|
|
if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_SHAMAN_MANA_SPRING)
|
|
{
|
|
if (!unitTarget || unitTarget->getPowerType() != POWER_MANA)
|
|
return;
|
|
m_caster->CastCustomSpell(unitTarget, 52032, &damage, 0, 0, true, 0, 0, m_originalCasterGUID);
|
|
return;
|
|
}
|
|
if (m_spellInfo->Id == 39610) // Mana Tide Totem effect
|
|
{
|
|
if (!unitTarget || unitTarget->getPowerType() != POWER_MANA)
|
|
return;
|
|
// Glyph of Mana Tide
|
|
if (Unit *owner = m_caster->GetOwner())
|
|
if (AuraEffect *dummy = owner->GetAuraEffect(55441, 0))
|
|
damage += dummy->GetAmount();
|
|
// Regenerate 6% of Total Mana Every 3 secs
|
|
int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100;
|
|
m_caster->CastCustomSpell(unitTarget, 39609, &EffectBasePoints0, NULL, NULL, true, NULL, NULL, m_originalCasterGUID);
|
|
return;
|
|
}
|
|
// Fire Nova
|
|
if (m_spellInfo->SpellIconID == 33)
|
|
{
|
|
if (!m_caster)
|
|
return;
|
|
|
|
uint32 triggered_spell_id;
|
|
switch(m_spellInfo->Id)
|
|
{
|
|
case 1535: triggered_spell_id = 8349; break;
|
|
case 8498: triggered_spell_id = 8502; break;
|
|
case 8499: triggered_spell_id = 8503; break;
|
|
case 11314: triggered_spell_id = 11306; break;
|
|
case 11315: triggered_spell_id = 11307; break;
|
|
case 25546: triggered_spell_id = 25535; break;
|
|
case 25547: triggered_spell_id = 25537; break;
|
|
case 61649: triggered_spell_id = 61650; break;
|
|
case 61657: triggered_spell_id = 61654; break;
|
|
default:
|
|
break;
|
|
}
|
|
// fire slot
|
|
if (triggered_spell_id && m_caster->m_SummonSlot[1])
|
|
{
|
|
Creature* totem = m_caster->GetMap()->GetCreature(m_caster->m_SummonSlot[1]);
|
|
if (totem && totem->isTotem())
|
|
totem->CastSpell(totem, triggered_spell_id, true);
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
// Lava Lash
|
|
if (m_spellInfo->SpellFamilyFlags[2] & SPELLFAMILYFLAG2_SHAMAN_LAVA_LASH)
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
if (Item *item = m_caster->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND))
|
|
{
|
|
// Damage is increased by 25% if your off-hand weapon is enchanted with Flametongue.
|
|
if (m_caster->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0x200000, 0, 0))
|
|
m_damage += m_damage * damage / 100;
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
case SPELLFAMILY_DEATHKNIGHT:
|
|
// Death strike
|
|
if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_DK_DEATH_STRIKE)
|
|
{
|
|
uint32 count = unitTarget->GetDiseasesByCaster(m_caster->GetGUID());
|
|
int32 bp = count * m_caster->GetMaxHealth() * m_spellInfo->DmgMultiplier[0] / 100;
|
|
// Improved Death Strike
|
|
if (AuraEffect const * aurEff = m_caster->GetAuraEffect(SPELL_AURA_ADD_PCT_MODIFIER, SPELLFAMILY_DEATHKNIGHT, 2751, 0))
|
|
bp = bp * (m_caster->CalculateSpellDamage(m_caster, aurEff->GetSpellProto(), 2) + 100.0f) / 100.0f;
|
|
m_caster->CastCustomSpell(m_caster, 45470, &bp, NULL, NULL, false);
|
|
return;
|
|
}
|
|
// Scourge Strike
|
|
if (m_spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_DK_SCOURGE_STRIKE)
|
|
{
|
|
int32 bp = (m_damage * damage * unitTarget->GetDiseasesByCaster(m_caster->GetGUID())) / 100;
|
|
m_caster->CastCustomSpell(unitTarget, 70890, &bp, NULL, NULL, true);
|
|
return;
|
|
}
|
|
// Death Coil
|
|
if (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_DK_DEATH_COIL)
|
|
{
|
|
if (m_caster->IsFriendlyTo(unitTarget))
|
|
{
|
|
int32 bp = damage * 1.5f;
|
|
m_caster->CastCustomSpell(unitTarget, 47633, &bp, NULL, NULL, true);
|
|
}
|
|
else
|
|
{
|
|
int32 bp = damage;
|
|
m_caster->CastCustomSpell(unitTarget, 47632, &bp, NULL, NULL, true);
|
|
}
|
|
return;
|
|
}
|
|
// Hungering Cold
|
|
if (m_spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_DK_HUNGERING_COLD)
|
|
{
|
|
unitTarget->CastSpell(m_caster, 51209, true);
|
|
return;
|
|
}
|
|
// Death Grip
|
|
if (m_spellInfo->Id == 49560)
|
|
{
|
|
Position pos;
|
|
GetSummonPosition(i, pos);
|
|
if (Unit *unit = unitTarget->GetVehicleBase()) // what is this for?
|
|
unit->CastSpell(pos.GetPositionX(),pos.GetPositionY(),pos.GetPositionZ(),damage,true);
|
|
else
|
|
unitTarget->CastSpell(pos.GetPositionX(),pos.GetPositionY(),pos.GetPositionZ(),damage,true);
|
|
return;
|
|
}
|
|
else if (m_spellInfo->Id == 46584) // Raise dead
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// Do we have talent Master of Ghouls?
|
|
if (m_caster->HasAura(52143))
|
|
// summon as pet
|
|
bp = 52150;
|
|
else
|
|
// or guardian
|
|
bp = 46585;
|
|
|
|
if (m_targets.HasDst())
|
|
{
|
|
targets.setDst(&m_targets.m_dstPos);
|
|
}
|
|
else
|
|
{
|
|
targets.setDst(m_caster);
|
|
// Corpse not found - take reagents (only not triggered cast can take them)
|
|
triggered = false;
|
|
}
|
|
// Remove cooldown - summon spellls have category
|
|
m_caster->ToPlayer()->RemoveSpellCooldown(m_spellInfo->Id,true);
|
|
spell_id=48289;
|
|
}
|
|
// Raise dead - take reagents and trigger summon spells
|
|
else if (m_spellInfo->Id == 48289)
|
|
{
|
|
if (m_targets.HasDst())
|
|
targets.setDst(&m_targets.m_dstPos);
|
|
|
|
spell_id = CalculateDamage(0, NULL);
|
|
}
|
|
// Corpse Explosion
|
|
else if (m_spellInfo->SpellIconID == 1737)
|
|
{
|
|
// Dummy effect 1 is used only for targeting and damage amount
|
|
if (i != 0)
|
|
return;
|
|
int32 bp = 0;
|
|
// Living ghoul as a target
|
|
if (unitTarget->isAlive())
|
|
{
|
|
bp = unitTarget->GetMaxHealth()*0.25f;
|
|
}
|
|
// Some corpse
|
|
else
|
|
{
|
|
bp = damage;
|
|
}
|
|
m_caster->CastCustomSpell(unitTarget, SpellMgr::CalculateSpellEffectAmount(m_spellInfo, 1), &bp,NULL,NULL,true);
|
|
// Corpse Explosion (Suicide)
|
|
unitTarget->CastCustomSpell(unitTarget,43999,&bp,NULL,NULL,true);
|
|
// Set corpse look
|
|
unitTarget->SetDisplayId(25537+urand(0,3));
|
|
}
|
|
// Runic Power Feed (keeping Gargoyle alive)
|
|
else if (m_spellInfo->Id == 50524)
|
|
{
|
|
// No power, dismiss Gargoyle
|
|
if (m_caster->GetPower(POWER_RUNIC_POWER)<30)
|
|
m_caster->RemoveAurasDueToSpell(50514, m_caster->GetGUID());
|
|
else
|
|
m_caster->ModifyPower(POWER_RUNIC_POWER,-30);
|
|
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
|
|
//spells triggered by dummy effect should not miss
|
|
if (spell_id)
|
|
{
|
|
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
|
|
|
|
if (!spellInfo)
|
|
{
|
|
sLog.outError("EffectDummy of spell %u: triggering unknown spell id %i\n", m_spellInfo->Id, spell_id);
|
|
return;
|
|
}
|
|
|
|
targets.setUnitTarget(unitTarget);
|
|
Spell* spell = new Spell(m_caster, spellInfo, triggered, m_originalCasterGUID, NULL, true);
|
|
if (bp) spell->m_currentBasePoints[0] = SpellMgr::CalculateSpellEffectBaseAmount(bp, spellInfo, 0);
|
|
spell->prepare(&targets);
|
|
}
|
|
|
|
// pet auras
|
|
if (PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id,i))
|
|
{
|
|
m_caster->AddPetAura(petSpell);
|
|
return;
|
|
}
|
|
|
|
// normal DB scripted effect
|
|
sLog.outDebug("Spell ScriptStart spellid %u in EffectDummy(%u)", m_spellInfo->Id, i);
|
|
m_caster->GetMap()->ScriptsStart(sSpellScripts, MAKE_PAIR32(m_spellInfo->Id,i), m_caster, unitTarget);
|
|
|
|
// Script based implementation. Must be used only for not good for implementation in core spell effects
|
|
// So called only for not proccessed cases
|
|
if (gameObjTarget)
|
|
sScriptMgr.OnDummyEffect(m_caster, m_spellInfo->Id, SpellEffIndex(i), gameObjTarget);
|
|
else if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT)
|
|
sScriptMgr.OnDummyEffect(m_caster, m_spellInfo->Id, SpellEffIndex(i), unitTarget->ToCreature());
|
|
else if (itemTarget)
|
|
sScriptMgr.OnDummyEffect(m_caster, m_spellInfo->Id, SpellEffIndex(i), itemTarget);
|
|
}
|
|
|
|
void Spell::EffectTriggerSpellWithValue(uint32 i)
|
|
{
|
|
uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
|
|
|
|
// normal case
|
|
SpellEntry const *spellInfo = sSpellStore.LookupEntry(triggered_spell_id);
|
|
|
|
if (!spellInfo)
|
|
{
|
|
sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
|
|
return;
|
|
}
|
|
|
|
int32 bp = damage;
|
|
Unit * caster = GetTriggeredSpellCaster(spellInfo, m_caster, unitTarget);
|
|
|
|
caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true);
|
|
}
|
|
|
|
void Spell::EffectTriggerRitualOfSummoning(uint32 i)
|
|
{
|
|
uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
|
|
SpellEntry const *spellInfo = sSpellStore.LookupEntry(triggered_spell_id);
|
|
|
|
if (!spellInfo)
|
|
{
|
|
sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
|
|
return;
|
|
}
|
|
|
|
finish();
|
|
|
|
m_caster->CastSpell(unitTarget,spellInfo,false);
|
|
}
|
|
|
|
void Spell::EffectForceCast(uint32 i)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
|
|
|
|
// normal case
|
|
SpellEntry const *spellInfo = sSpellStore.LookupEntry(triggered_spell_id);
|
|
|
|
if (!spellInfo)
|
|
{
|
|
sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
|
|
return;
|
|
}
|
|
|
|
if (damage)
|
|
{
|
|
switch(m_spellInfo->Id)
|
|
{
|
|
case 52588: // Skeletal Gryphon Escape
|
|
case 48598: // Ride Flamebringer Cue
|
|
unitTarget->RemoveAura(damage);
|
|
break;
|
|
case 52463: // Hide In Mine Car
|
|
case 52349: // Overtake
|
|
unitTarget->CastCustomSpell(unitTarget, spellInfo->Id, &damage, NULL, NULL, true, NULL, NULL, m_originalCasterGUID);
|
|
return;
|
|
//case 72378: // Blood Nova
|
|
//case 73058: // Blood Nova
|
|
}
|
|
}
|
|
Unit * caster = GetTriggeredSpellCaster(spellInfo, m_caster, unitTarget);
|
|
|
|
caster->CastSpell(unitTarget, spellInfo, true, NULL, NULL, m_originalCasterGUID);
|
|
}
|
|
|
|
void Spell::EffectForceCastWithValue(uint32 i)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
|
|
|
|
// normal case
|
|
SpellEntry const *spellInfo = sSpellStore.LookupEntry(triggered_spell_id);
|
|
|
|
if (!spellInfo)
|
|
{
|
|
sLog.outError("EffectForceCastWithValue of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
|
|
return;
|
|
}
|
|
int32 bp = damage;
|
|
Unit * caster = GetTriggeredSpellCaster(spellInfo, m_caster, unitTarget);
|
|
|
|
caster->CastCustomSpell(unitTarget, spellInfo->Id, &bp, &bp, &bp, true, NULL, NULL, m_originalCasterGUID);
|
|
}
|
|
|
|
|
|
void Spell::EffectTriggerSpell(uint32 effIndex)
|
|
{
|
|
// only unit case known
|
|
if (!unitTarget)
|
|
{
|
|
if (gameObjTarget || itemTarget)
|
|
sLog.outError("Spell::EffectTriggerSpell (Spell: %u): Unsupported non-unit case!",m_spellInfo->Id);
|
|
return;
|
|
}
|
|
|
|
uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effIndex];
|
|
Unit* originalCaster = NULL;
|
|
|
|
// special cases
|
|
switch(triggered_spell_id)
|
|
{
|
|
// Mirror Image
|
|
case 58832:
|
|
{
|
|
// Glyph of Mirror Image
|
|
if (m_caster->HasAura(63093))
|
|
m_caster->CastSpell(m_caster, 65047, true); // Mirror Image
|
|
|
|
break;
|
|
}
|
|
// Vanish (not exist)
|
|
case 18461:
|
|
{
|
|
unitTarget->RemoveMovementImpairingAuras();
|
|
unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STALKED);
|
|
|
|
// if this spell is given to NPC it must handle rest by it's own AI
|
|
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// get highest rank of the Stealth spell
|
|
uint32 spellId = 0;
|
|
SpellEntry const *spellInfo;
|
|
const PlayerSpellMap& sp_list = unitTarget->ToPlayer()->GetSpellMap();
|
|
for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
|
|
{
|
|
// only highest rank is shown in spell book, so simply check if shown in spell book
|
|
if (!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
|
|
continue;
|
|
|
|
spellInfo = sSpellStore.LookupEntry(itr->first);
|
|
if (!spellInfo)
|
|
continue;
|
|
|
|
if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_STEALTH)
|
|
{
|
|
spellId = spellInfo->Id;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// no Stealth spell found
|
|
if (!spellId)
|
|
return;
|
|
|
|
// reset cooldown on it if needed
|
|
if (unitTarget->ToPlayer()->HasSpellCooldown(spellId))
|
|
unitTarget->ToPlayer()->RemoveSpellCooldown(spellId);
|
|
|
|
// Push stealth to list because it must be handled after combat remove
|
|
m_TriggerSpells.push_back(spellInfo);
|
|
return;
|
|
}
|
|
// Demonic Empowerment -- succubus
|
|
case 54437:
|
|
{
|
|
unitTarget->RemoveMovementImpairingAuras();
|
|
unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STALKED);
|
|
unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STUN);
|
|
|
|
// Cast Lesser Invisibility
|
|
triggered_spell_id = 7870;
|
|
break;
|
|
}
|
|
// just skip
|
|
case 23770: // Sayge's Dark Fortune of *
|
|
// not exist, common cooldown can be implemented in scripts if need.
|
|
return;
|
|
// Brittle Armor - (need add max stack of 24575 Brittle Armor)
|
|
case 29284:
|
|
{
|
|
// Brittle Armor
|
|
SpellEntry const* spell = sSpellStore.LookupEntry(24575);
|
|
if (!spell)
|
|
return;
|
|
|
|
for (int j=0; j < spell->StackAmount; ++j)
|
|
m_caster->CastSpell(unitTarget, spell->Id, true);
|
|
return;
|
|
}
|
|
// Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
|
|
case 29286:
|
|
{
|
|
// Mercurial Shield
|
|
SpellEntry const* spell = sSpellStore.LookupEntry(26464);
|
|
if (!spell)
|
|
return;
|
|
|
|
for (int j=0; j < spell->StackAmount; ++j)
|
|
m_caster->CastSpell(unitTarget, spell->Id, true);
|
|
return;
|
|
}
|
|
// Righteous Defense
|
|
case 31980:
|
|
{
|
|
m_caster->CastSpell(unitTarget, 31790, true);
|
|
return;
|
|
}
|
|
// Cloak of Shadows
|
|
case 35729:
|
|
{
|
|
uint32 dispelMask = GetDispellMask(DISPEL_ALL);
|
|
Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras();
|
|
for (Unit::AuraApplicationMap::iterator iter = Auras.begin(); iter != Auras.end();)
|
|
{
|
|
// remove all harmful spells on you...
|
|
SpellEntry const* spell = iter->second->GetBase()->GetSpellProto();
|
|
if ((spell->DmgClass == SPELL_DAMAGE_CLASS_MAGIC // only affect magic spells
|
|
|| ((1<<spell->Dispel) & dispelMask))
|
|
// ignore positive and passive auras
|
|
&& !iter->second->IsPositive() && !iter->second->GetBase()->IsPassive())
|
|
{
|
|
m_caster->RemoveAura(iter);
|
|
}
|
|
else
|
|
iter++;
|
|
}
|
|
return;
|
|
}
|
|
// Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
|
|
case 41967:
|
|
{
|
|
if (Unit *pet = unitTarget->GetGuardianPet())
|
|
pet->CastSpell(pet, 28305, true);
|
|
return;
|
|
}
|
|
// Empower Rune Weapon
|
|
case 53258:
|
|
return; // skip, hack-added in spell effect
|
|
// Snake Trap
|
|
case 57879:
|
|
originalCaster = m_originalCaster;
|
|
break;
|
|
}
|
|
|
|
// normal case
|
|
SpellEntry const *spellInfo = sSpellStore.LookupEntry(triggered_spell_id);
|
|
if (!spellInfo)
|
|
{
|
|
sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
|
|
return;
|
|
}
|
|
|
|
// Remove spell cooldown (not category) if spell triggering spell with cooldown and same category
|
|
// Needed by freezing arrow and few other spells
|
|
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->CategoryRecoveryTime && spellInfo->CategoryRecoveryTime
|
|
&& m_spellInfo->Category == spellInfo->Category)
|
|
m_caster->ToPlayer()->RemoveSpellCooldown(spellInfo->Id);
|
|
|
|
// Note: not exist spells with weapon req. and IsSpellHaveCasterSourceTargets == true
|
|
// so this just for speedup places in else
|
|
Unit * caster = GetTriggeredSpellCaster(spellInfo, m_caster, unitTarget);
|
|
|
|
caster->CastSpell(unitTarget,spellInfo,true, 0, 0, (originalCaster ? originalCaster->GetGUID() : 0));
|
|
}
|
|
|
|
void Spell::EffectTriggerMissileSpell(uint32 effect_idx)
|
|
{
|
|
uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effect_idx];
|
|
|
|
// normal case
|
|
SpellEntry const *spellInfo = sSpellStore.LookupEntry(triggered_spell_id);
|
|
|
|
if (!spellInfo)
|
|
{
|
|
sLog.outError("EffectTriggerMissileSpell of spell %u (eff: %u): triggering unknown spell id %u",
|
|
m_spellInfo->Id,effect_idx,triggered_spell_id);
|
|
return;
|
|
}
|
|
|
|
if (m_CastItem)
|
|
DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
|
|
|
|
// Remove spell cooldown (not category) if spell triggering spell with cooldown and same category
|
|
// Needed by freezing arrow and few other spells
|
|
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->CategoryRecoveryTime && spellInfo->CategoryRecoveryTime
|
|
&& m_spellInfo->Category == spellInfo->Category)
|
|
m_caster->ToPlayer()->RemoveSpellCooldown(spellInfo->Id);
|
|
|
|
float x, y, z;
|
|
m_targets.m_dstPos.GetPosition(x, y, z);
|
|
m_caster->CastSpell(x, y, z, spellInfo->Id, true, m_CastItem, 0, m_originalCasterGUID);
|
|
}
|
|
|
|
void Spell::EffectJump(uint32 i)
|
|
{
|
|
if (m_caster->isInFlight())
|
|
return;
|
|
|
|
float x,y,z,o;
|
|
if (m_targets.getUnitTarget())
|
|
{
|
|
m_targets.getUnitTarget()->GetContactPoint(m_caster,x,y,z,CONTACT_DISTANCE);
|
|
o = m_caster->GetOrientation();
|
|
}
|
|
else if (m_targets.getGOTarget())
|
|
{
|
|
m_targets.getGOTarget()->GetContactPoint(m_caster,x,y,z,CONTACT_DISTANCE);
|
|
o = m_caster->GetOrientation();
|
|
}
|
|
else
|
|
{
|
|
sLog.outError("Spell::EffectJump - unsupported target mode for spell ID %u", m_spellInfo->Id);
|
|
return;
|
|
}
|
|
|
|
float speedXY, speedZ;
|
|
CalculateJumpSpeeds(i, m_caster->GetExactDist2d(x, y), speedXY, speedZ);
|
|
m_caster->GetMotionMaster()->MoveJump(x, y, z, speedXY, speedZ);
|
|
}
|
|
|
|
void Spell::EffectJumpDest(uint32 i)
|
|
{
|
|
if (m_caster->isInFlight())
|
|
return;
|
|
|
|
// Init dest coordinates
|
|
float x,y,z,o;
|
|
if (m_targets.HasDst())
|
|
{
|
|
m_targets.m_dstPos.GetPosition(x, y, z);
|
|
|
|
if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_DEST_TARGET_BACK)
|
|
{
|
|
// explicit cast data from client or server-side cast
|
|
// some spell at client send caster
|
|
Unit* pTarget = NULL;
|
|
if (m_targets.getUnitTarget() && m_targets.getUnitTarget() != m_caster)
|
|
pTarget = m_targets.getUnitTarget();
|
|
else if (m_caster->getVictim())
|
|
pTarget = m_caster->getVictim();
|
|
else if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
|
pTarget = ObjectAccessor::GetUnit(*m_caster, m_caster->ToPlayer()->GetSelection());
|
|
|
|
o = pTarget ? pTarget->GetOrientation() : m_caster->GetOrientation();
|
|
}
|
|
else
|
|
o = m_caster->GetOrientation();
|
|
}
|
|
else
|
|
{
|
|
sLog.outError("Spell::EffectJumpDest - unsupported target mode for spell ID %u", m_spellInfo->Id);
|
|
return;
|
|
}
|
|
|
|
float speedXY, speedZ;
|
|
CalculateJumpSpeeds(i, m_caster->GetExactDist2d(x, y), speedXY, speedZ);
|
|
m_caster->GetMotionMaster()->MoveJump(x, y, z, speedXY, speedZ);
|
|
}
|
|
|
|
void Spell::CalculateJumpSpeeds(uint8 i, float dist, float & speedXY, float & speedZ)
|
|
{
|
|
if (m_spellInfo->EffectMiscValue[i])
|
|
speedZ = float(m_spellInfo->EffectMiscValue[i])/10;
|
|
else if (m_spellInfo->EffectMiscValueB[i])
|
|
speedZ = float(m_spellInfo->EffectMiscValueB[i])/10;
|
|
else
|
|
speedZ = 10.0f;
|
|
speedXY = dist * 10.0f / speedZ;
|
|
}
|
|
|
|
void Spell::EffectTeleportUnits(uint32 /*i*/)
|
|
{
|
|
if (!unitTarget || unitTarget->isInFlight())
|
|
return;
|
|
|
|
// Pre effects
|
|
uint8 uiMaxSafeLevel = 0;
|
|
switch (m_spellInfo->Id)
|
|
{
|
|
case 48129: // Scroll of Recall
|
|
uiMaxSafeLevel = 40;
|
|
case 60320: // Scroll of Recall II
|
|
if (!uiMaxSafeLevel)
|
|
uiMaxSafeLevel = 70;
|
|
case 60321: // Scroll of Recal III
|
|
if (!uiMaxSafeLevel)
|
|
uiMaxSafeLevel = 80;
|
|
|
|
if (unitTarget->getLevel() > uiMaxSafeLevel)
|
|
{
|
|
unitTarget->AddAura(60444,unitTarget); //Apply Lost! Aura
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// If not exist data for dest location - return
|
|
if (!m_targets.HasDst())
|
|
{
|
|
sLog.outError("Spell::EffectTeleportUnits - does not have destination for spell ID %u\n", m_spellInfo->Id);
|
|
return;
|
|
}
|
|
|
|
// Init dest coordinates
|
|
uint32 mapid = m_targets.m_dstPos.GetMapId();
|
|
if (mapid == MAPID_INVALID)
|
|
mapid = unitTarget->GetMapId();
|
|
float x, y, z, orientation;
|
|
m_targets.m_dstPos.GetPosition(x, y, z, orientation);
|
|
if (!orientation && m_targets.getUnitTarget())
|
|
orientation = m_targets.getUnitTarget()->GetOrientation();
|
|
sLog.outDebug("Spell::EffectTeleportUnits - teleport unit to %u %f %f %f %f\n", mapid, x, y, z, orientation);
|
|
|
|
if (mapid == unitTarget->GetMapId())
|
|
unitTarget->NearTeleportTo(x, y, z, orientation, unitTarget == m_caster);
|
|
else if (unitTarget->GetTypeId() == TYPEID_PLAYER)
|
|
unitTarget->ToPlayer()->TeleportTo(mapid, x, y, z, orientation, unitTarget == m_caster ? TELE_TO_SPELL : 0);
|
|
|
|
// post effects for TARGET_DST_DB
|
|
switch (m_spellInfo->Id)
|
|
{
|
|
// Dimensional Ripper - Everlook
|
|
case 23442:
|
|
{
|
|
int32 r = irand(0, 119);
|
|
if (r >= 70) // 7/12 success
|
|
{
|
|
if (r < 100) // 4/12 evil twin
|
|
m_caster->CastSpell(m_caster, 23445, true);
|
|
else // 1/12 fire
|
|
m_caster->CastSpell(m_caster, 23449, true);
|
|
}
|
|
return;
|
|
}
|
|
// Ultrasafe Transporter: Toshley's Station
|
|
case 36941:
|
|
{
|
|
if (roll_chance_i(50)) // 50% success
|
|
{
|
|
int32 rand_eff = urand(1, 7);
|
|
switch (rand_eff)
|
|
{
|
|
case 1:
|
|
// soul split - evil
|
|
m_caster->CastSpell(m_caster, 36900, true);
|
|
break;
|
|
case 2:
|
|
// soul split - good
|
|
m_caster->CastSpell(m_caster, 36901, true);
|
|
break;
|
|
case 3:
|
|
// Increase the size
|
|
m_caster->CastSpell(m_caster, 36895, true);
|
|
break;
|
|
case 4:
|
|
// Decrease the size
|
|
m_caster->CastSpell(m_caster, 36893, true);
|
|
break;
|
|
case 5:
|
|
// Transform
|
|
{
|
|
if (m_caster->ToPlayer()->GetTeam() == ALLIANCE)
|
|
m_caster->CastSpell(m_caster, 36897, true);
|
|
else
|
|
m_caster->CastSpell(m_caster, 36899, true);
|
|
break;
|
|
}
|
|
case 6:
|
|
// chicken
|
|
m_caster->CastSpell(m_caster, 36940, true);
|
|
break;
|
|
case 7:
|
|
// evil twin
|
|
m_caster->CastSpell(m_caster, 23445, true);
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
// Dimensional Ripper - Area 52
|
|
case 36890:
|
|
{
|
|
if (roll_chance_i(50)) // 50% success
|
|
{
|
|
int32 rand_eff = urand(1, 4);
|
|
switch (rand_eff)
|
|
{
|
|
case 1:
|
|
// soul split - evil
|
|
m_caster->CastSpell(m_caster, 36900, true);
|
|
break;
|
|
case 2:
|
|
// soul split - good
|
|
m_caster->CastSpell(m_caster, 36901, true);
|
|
break;
|
|
case 3:
|
|
// Increase the size
|
|
m_caster->CastSpell(m_caster, 36895, true);
|
|
break;
|
|
case 4:
|
|
// Transform
|
|
{
|
|
if (m_caster->ToPlayer()->GetTeam() == ALLIANCE)
|
|
m_caster->CastSpell(m_caster, 36897, true);
|
|
else
|
|
m_caster->CastSpell(m_caster, 36899, true);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Spell::EffectApplyAura(uint32 i)
|
|
{
|
|
if (!m_spellAura || !unitTarget)
|
|
return;
|
|
ASSERT(unitTarget == m_spellAura->GetOwner());
|
|
m_spellAura->_ApplyEffectForTargets(i);
|
|
}
|
|
|
|
void Spell::EffectApplyAreaAura(uint32 i)
|
|
{
|
|
if (!m_spellAura || !unitTarget)
|
|
return;
|
|
ASSERT (unitTarget == m_spellAura->GetOwner());
|
|
m_spellAura->_ApplyEffectForTargets(i);
|
|
}
|
|
|
|
void Spell::EffectUnlearnSpecialization(uint32 i)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player *_player = (Player*)unitTarget;
|
|
uint32 spellToUnlearn = m_spellInfo->EffectTriggerSpell[i];
|
|
|
|
_player->removeSpell(spellToUnlearn);
|
|
|
|
sLog.outDebug("Spell: Player %u has unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow());
|
|
}
|
|
|
|
void Spell::EffectPowerDrain(uint32 i)
|
|
{
|
|
if (m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
|
|
return;
|
|
|
|
Powers drain_power = Powers(m_spellInfo->EffectMiscValue[i]);
|
|
|
|
if (!unitTarget)
|
|
return;
|
|
if (!unitTarget->isAlive())
|
|
return;
|
|
if (unitTarget->getPowerType() != drain_power)
|
|
return;
|
|
if (damage < 0)
|
|
return;
|
|
|
|
uint32 curPower = unitTarget->GetPower(drain_power);
|
|
|
|
//add spell damage bonus
|
|
damage=m_caster->SpellDamageBonus(unitTarget,m_spellInfo,uint32(damage),SPELL_DIRECT_DAMAGE);
|
|
|
|
// resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
|
|
uint32 power = damage;
|
|
if (drain_power == POWER_MANA)
|
|
power -= unitTarget->GetSpellCritDamageReduction(power);
|
|
|
|
int32 new_damage;
|
|
if (curPower < power)
|
|
new_damage = curPower;
|
|
else
|
|
new_damage = power;
|
|
|
|
unitTarget->ModifyPower(drain_power,-new_damage);
|
|
|
|
// Don`t restore from self drain
|
|
if (drain_power == POWER_MANA && m_caster != unitTarget)
|
|
{
|
|
float manaMultiplier = m_spellInfo->EffectMultipleValue[i];
|
|
if (manaMultiplier == 0)
|
|
manaMultiplier = 1;
|
|
|
|
if (Player *modOwner = m_caster->GetSpellModOwner())
|
|
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
|
|
|
|
int32 gain = int32(new_damage * manaMultiplier);
|
|
|
|
m_caster->EnergizeBySpell(m_caster, m_spellInfo->Id, gain, POWER_MANA);
|
|
}
|
|
}
|
|
|
|
void Spell::EffectSendEvent(uint32 EffectIndex)
|
|
{
|
|
/*
|
|
we do not handle a flag dropping or clicking on flag in battleground by sendevent system
|
|
*/
|
|
sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id);
|
|
|
|
Object *pTarget;
|
|
if (focusObject)
|
|
pTarget = focusObject;
|
|
else if (unitTarget)
|
|
pTarget = unitTarget;
|
|
else if (gameObjTarget)
|
|
pTarget = gameObjTarget;
|
|
else
|
|
pTarget = NULL;
|
|
|
|
m_caster->GetMap()->ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, pTarget);
|
|
}
|
|
|
|
void Spell::EffectPowerBurn(uint32 i)
|
|
{
|
|
if (m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
|
|
return;
|
|
|
|
Powers powertype = Powers(m_spellInfo->EffectMiscValue[i]);
|
|
|
|
if (!unitTarget)
|
|
return;
|
|
if (!unitTarget->isAlive())
|
|
return;
|
|
if (unitTarget->getPowerType() != powertype)
|
|
return;
|
|
if (damage < 0)
|
|
return;
|
|
|
|
//Unit* caster = m_originalCaster ? m_originalCaster : m_caster;
|
|
|
|
// burn x% of target's mana, up to maximum of 2x% of caster's mana (Mana Burn)
|
|
if (m_spellInfo->ManaCostPercentage)
|
|
{
|
|
uint32 maxdamage = m_caster->GetMaxPower(powertype) * damage * 2 / 100;
|
|
damage = unitTarget->GetMaxPower(powertype) * damage / 100;
|
|
if (damage > maxdamage) damage = maxdamage;
|
|
}
|
|
|
|
int32 curPower = int32(unitTarget->GetPower(powertype));
|
|
|
|
uint32 power = damage;
|
|
// resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
|
|
if (powertype == POWER_MANA)
|
|
power -= unitTarget->GetSpellCritDamageReduction(power);
|
|
|
|
int32 new_damage = (curPower < power) ? curPower : power;
|
|
|
|
unitTarget->ModifyPower(powertype, -new_damage);
|
|
float multiplier = m_spellInfo->EffectMultipleValue[i];
|
|
|
|
if (Player *modOwner = m_caster->GetSpellModOwner())
|
|
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
|
|
|
|
new_damage = int32(new_damage*multiplier);
|
|
//m_damage+=new_damage; should not apply spell bonus
|
|
//TODO: no log
|
|
//unitTarget->ModifyHealth(-new_damage);
|
|
if (m_originalCaster)
|
|
m_originalCaster->DealDamage(unitTarget, new_damage);
|
|
|
|
unitTarget->RemoveAurasByType(SPELL_AURA_MOD_FEAR);
|
|
}
|
|
|
|
void Spell::EffectHeal(uint32 /*i*/)
|
|
{
|
|
}
|
|
|
|
void Spell::SpellDamageHeal(uint32 /*i*/)
|
|
{
|
|
if (unitTarget && unitTarget->isAlive() && damage >= 0)
|
|
{
|
|
// Try to get original caster
|
|
Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
|
|
|
|
// Skip if m_originalCaster not available
|
|
if (!caster)
|
|
return;
|
|
|
|
int32 addhealth = damage;
|
|
|
|
// Vessel of the Naaru (Vial of the Sunwell trinket)
|
|
if (m_spellInfo->Id == 45064)
|
|
{
|
|
// Amount of heal - depends from stacked Holy Energy
|
|
int damageAmount = 0;
|
|
if (AuraEffect const * aurEff = m_caster->GetAuraEffect(45062, 0))
|
|
{
|
|
damageAmount+= aurEff->GetAmount();
|
|
m_caster->RemoveAurasDueToSpell(45062);
|
|
}
|
|
|
|
addhealth += damageAmount;
|
|
}
|
|
// Swiftmend - consumes Regrowth or Rejuvenation
|
|
else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND, m_spellInfo, m_caster))
|
|
{
|
|
Unit::AuraEffectList const& RejorRegr = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_HEAL);
|
|
// find most short by duration
|
|
AuraEffect *targetAura = NULL;
|
|
for (Unit::AuraEffectList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
|
|
{
|
|
if ((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
|
|
&& (*i)->GetSpellProto()->SpellFamilyFlags[0] & 0x50)
|
|
{
|
|
if (!targetAura || (*i)->GetBase()->GetDuration() < targetAura->GetBase()->GetDuration())
|
|
targetAura = *i;
|
|
}
|
|
}
|
|
|
|
if (!targetAura)
|
|
{
|
|
sLog.outError("Target(GUID:" UI64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID());
|
|
return;
|
|
}
|
|
|
|
int32 tickheal = targetAura->GetAmount();
|
|
if (Unit* auraCaster = targetAura->GetCaster())
|
|
tickheal = auraCaster->SpellHealingBonus(unitTarget, targetAura->GetSpellProto(), tickheal, DOT);
|
|
//int32 tickheal = targetAura->GetSpellProto()->EffectBasePoints[idx] + 1;
|
|
//It is said that talent bonus should not be included
|
|
|
|
int32 tickcount = 0;
|
|
// Rejuvenation
|
|
if (targetAura->GetSpellProto()->SpellFamilyFlags[0] & 0x10)
|
|
tickcount = 4;
|
|
// Regrowth
|
|
else // if (targetAura->GetSpellProto()->SpellFamilyFlags[0] & 0x40)
|
|
tickcount = 6;
|
|
|
|
addhealth += tickheal * tickcount;
|
|
|
|
// Glyph of Swiftmend
|
|
if (!caster->HasAura(54824))
|
|
unitTarget->RemoveAura(targetAura->GetId(), targetAura->GetCasterGUID());
|
|
|
|
//addhealth += tickheal * tickcount;
|
|
//addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget);
|
|
}
|
|
// Glyph of Nourish
|
|
else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags[1] & 0x2000000)
|
|
{
|
|
addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL);
|
|
|
|
if (AuraEffect const* aurEff = m_caster->GetAuraEffect(62971, 0))
|
|
{
|
|
Unit::AuraEffectList const& Periodic = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_HEAL);
|
|
for (Unit::AuraEffectList::const_iterator i = Periodic.begin(); i != Periodic.end(); ++i)
|
|
{
|
|
if (m_caster->GetGUID() == (*i)->GetCasterGUID())
|
|
addhealth += addhealth * aurEff->GetAmount() / 100;
|
|
}
|
|
}
|
|
}
|
|
// Lifebloom - final heal coef multiplied by original DoT stack
|
|
else if (m_spellInfo->Id == 33778)
|
|
addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL, m_spellValue->EffectBasePoints[1]);
|
|
// Riptide - increase healing done by Chain Heal
|
|
else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[0] & 0x100)
|
|
{
|
|
addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL);
|
|
if (AuraEffect * aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_SHAMAN, 0, 0, 0x10, m_originalCasterGUID))
|
|
{
|
|
addhealth *= 1.25f;
|
|
// consume aura
|
|
unitTarget->RemoveAura(aurEff->GetBase());
|
|
}
|
|
}
|
|
// Death Pact - return pct of max health to caster
|
|
else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000)
|
|
addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, int32(caster->GetMaxHealth() * damage / 100.0f), HEAL);
|
|
else
|
|
addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL);
|
|
|
|
// Remove Grievious bite if fully healed
|
|
if (unitTarget->HasAura(48920) && (unitTarget->GetHealth() + addhealth >= unitTarget->GetMaxHealth()))
|
|
unitTarget->RemoveAura(48920);
|
|
|
|
m_damage -= addhealth;
|
|
}
|
|
}
|
|
|
|
void Spell::EffectHealPct(uint32 /*i*/)
|
|
{
|
|
if (unitTarget && unitTarget->isAlive() && damage >= 0)
|
|
{
|
|
// Try to get original caster
|
|
Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
|
|
|
|
// Skip if m_originalCaster not available
|
|
if (!caster)
|
|
return;
|
|
|
|
// Rune Tap - Party
|
|
if (m_spellInfo->Id == 59754 && unitTarget == m_caster)
|
|
return;
|
|
|
|
uint32 addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, unitTarget->GetMaxHealth() * damage / 100.0f, HEAL);
|
|
//if (Player *modOwner = m_caster->GetSpellModOwner())
|
|
// modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DAMAGE, addhealth, this);
|
|
|
|
int32 gain = caster->DealHeal(unitTarget, addhealth, m_spellInfo);
|
|
unitTarget->getHostileRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
|
|
}
|
|
}
|
|
|
|
void Spell::EffectHealMechanical(uint32 /*i*/)
|
|
{
|
|
// Mechanic creature type should be correctly checked by targetCreatureType field
|
|
if (unitTarget && unitTarget->isAlive() && damage >= 0)
|
|
{
|
|
// Try to get original caster
|
|
Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
|
|
|
|
// Skip if m_originalCaster not available
|
|
if (!caster)
|
|
return;
|
|
|
|
uint32 addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, uint32(damage), HEAL);
|
|
caster->DealHeal(unitTarget, addhealth, m_spellInfo);
|
|
}
|
|
}
|
|
|
|
void Spell::EffectHealthLeech(uint32 i)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
if (!unitTarget->isAlive())
|
|
return;
|
|
|
|
if (damage < 0)
|
|
return;
|
|
|
|
sLog.outDebug("HealthLeech :%i", damage);
|
|
|
|
float multiplier = m_spellInfo->EffectMultipleValue[i];
|
|
|
|
if (Player *modOwner = m_caster->GetSpellModOwner())
|
|
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
|
|
|
|
// Do not apply multiplier to damage if it's Death Coil
|
|
int32 new_damage;
|
|
if (m_spellInfo->SpellFamilyFlags[0] & 0x80000)
|
|
new_damage = damage;
|
|
else
|
|
new_damage = int32(damage*multiplier);
|
|
uint32 curHealth = unitTarget->GetHealth();
|
|
new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage);
|
|
if (curHealth < new_damage)
|
|
new_damage = curHealth;
|
|
|
|
if (m_caster->isAlive())
|
|
{
|
|
// Insead add it just to healing if it's Death Coil
|
|
if (m_spellInfo->SpellFamilyFlags[0] & 0x80000)
|
|
new_damage = int32(new_damage*multiplier);
|
|
new_damage = m_caster->SpellHealingBonus(m_caster, m_spellInfo, new_damage, HEAL);
|
|
m_caster->DealHeal(m_caster, uint32(new_damage), m_spellInfo);
|
|
}
|
|
// m_healthLeech+=tmpvalue;
|
|
// m_damage+=new_damage;
|
|
}
|
|
|
|
void Spell::DoCreateItem(uint32 /*i*/, uint32 itemtype)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player* player = (Player*)unitTarget;
|
|
|
|
uint32 newitemid = itemtype;
|
|
ItemPrototype const *pProto = objmgr.GetItemPrototype(newitemid);
|
|
if (!pProto)
|
|
{
|
|
player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
|
|
return;
|
|
}
|
|
|
|
// bg reward have some special in code work
|
|
uint32 bgType = 0;
|
|
switch(m_spellInfo->Id)
|
|
{
|
|
case SPELL_AV_MARK_WINNER:
|
|
case SPELL_AV_MARK_LOSER:
|
|
bgType = BATTLEGROUND_AV;
|
|
break;
|
|
case SPELL_WS_MARK_WINNER:
|
|
case SPELL_WS_MARK_LOSER:
|
|
bgType = BATTLEGROUND_WS;
|
|
break;
|
|
case SPELL_AB_MARK_WINNER:
|
|
case SPELL_AB_MARK_LOSER:
|
|
bgType = BATTLEGROUND_AB;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
uint32 num_to_add = damage;
|
|
|
|
if (num_to_add < 1)
|
|
num_to_add = 1;
|
|
if (num_to_add > pProto->GetMaxStackSize())
|
|
num_to_add = pProto->GetMaxStackSize();
|
|
|
|
// init items_count to 1, since 1 item will be created regardless of specialization
|
|
int items_count=1;
|
|
// the chance to create additional items
|
|
float additionalCreateChance=0.0f;
|
|
// the maximum number of created additional items
|
|
uint8 additionalMaxNum=0;
|
|
// get the chance and maximum number for creating extra items
|
|
if (canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum))
|
|
{
|
|
// roll with this chance till we roll not to create or we create the max num
|
|
while (roll_chance_f(additionalCreateChance) && items_count <= additionalMaxNum)
|
|
++items_count;
|
|
}
|
|
|
|
// really will be created more items
|
|
num_to_add *= items_count;
|
|
|
|
// can the player store the new item?
|
|
ItemPosCountVec dest;
|
|
uint32 no_space = 0;
|
|
uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space);
|
|
if (msg != EQUIP_ERR_OK)
|
|
{
|
|
// convert to possible store amount
|
|
if (msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS)
|
|
num_to_add -= no_space;
|
|
else
|
|
{
|
|
// if not created by another reason from full inventory or unique items amount limitation
|
|
player->SendEquipError(msg, NULL, NULL, newitemid);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (num_to_add)
|
|
{
|
|
// create the new item and store it
|
|
Item* pItem = player->StoreNewItem(dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid));
|
|
|
|
// was it successful? return error if not
|
|
if (!pItem)
|
|
{
|
|
player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
|
|
return;
|
|
}
|
|
|
|
// set the "Crafted by ..." property of the item
|
|
if (pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST && newitemid != 6265 && newitemid != 6948)
|
|
pItem->SetUInt32Value(ITEM_FIELD_CREATOR, player->GetGUIDLow());
|
|
|
|
// send info to the client
|
|
if (pItem)
|
|
player->SendNewItem(pItem, num_to_add, true, bgType == 0);
|
|
|
|
// we succeeded in creating at least one item, so a levelup is possible
|
|
if (bgType == 0)
|
|
player->UpdateCraftSkill(m_spellInfo->Id);
|
|
}
|
|
|
|
/*
|
|
// for battleground marks send by mail if not add all expected
|
|
if (no_space > 0 && bgType)
|
|
{
|
|
if (BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(BattleGroundTypeId(bgType)))
|
|
bg->SendRewardMarkByMail(player, newitemid, no_space);
|
|
}
|
|
*/
|
|
}
|
|
|
|
void Spell::EffectCreateItem(uint32 i)
|
|
{
|
|
DoCreateItem(i,m_spellInfo->EffectItemType[i]);
|
|
}
|
|
|
|
void Spell::EffectCreateItem2(uint32 i)
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
Player* player = (Player*)m_caster;
|
|
|
|
uint32 item_id = m_spellInfo->EffectItemType[i];
|
|
|
|
if (item_id)
|
|
DoCreateItem(i, item_id);
|
|
|
|
// special case: fake item replaced by generate using spell_loot_template
|
|
if (IsLootCraftingSpell(m_spellInfo))
|
|
{
|
|
if (item_id)
|
|
{
|
|
if (!player->HasItemCount(item_id, 1))
|
|
return;
|
|
|
|
// remove reagent
|
|
uint32 count = 1;
|
|
player->DestroyItemCount(item_id, count, true);
|
|
|
|
// create some random items
|
|
player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell);
|
|
}
|
|
else
|
|
player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell); // create some random items
|
|
}
|
|
}
|
|
|
|
void Spell::EffectCreateRandomItem(uint32 /*i*/)
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
Player* player = (Player*)m_caster;
|
|
|
|
// create some random items
|
|
player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell);
|
|
}
|
|
|
|
void Spell::EffectPersistentAA(uint32 i)
|
|
{
|
|
if (!m_spellAura)
|
|
{
|
|
float radius = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
|
|
if (Player* modOwner = m_originalCaster->GetSpellModOwner())
|
|
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius);
|
|
|
|
Unit *caster = m_caster->GetEntry() == WORLD_TRIGGER ? m_originalCaster : m_caster;
|
|
// Caster not in world, might be spell triggered from aura removal
|
|
if (!caster->IsInWorld())
|
|
return;
|
|
DynamicObject* dynObj = new DynamicObject;
|
|
if (!dynObj->Create(objmgr.GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), caster, m_spellInfo->Id, m_targets.m_dstPos, radius, false))
|
|
{
|
|
delete dynObj;
|
|
return;
|
|
}
|
|
caster->AddDynObject(dynObj);
|
|
dynObj->GetMap()->Add(dynObj);
|
|
|
|
if (Aura * aura = Aura::TryCreate(m_spellInfo, dynObj, caster, &m_currentBasePoints[0]))
|
|
m_spellAura = aura;
|
|
else
|
|
{
|
|
ASSERT(false);
|
|
return;
|
|
}
|
|
m_spellAura->_RegisterForTargets();
|
|
}
|
|
ASSERT(m_spellAura->GetDynobjOwner());
|
|
m_spellAura->_ApplyEffectForTargets(i);
|
|
}
|
|
|
|
void Spell::EffectEnergize(uint32 i)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
if (!unitTarget->isAlive())
|
|
return;
|
|
|
|
if (m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
|
|
return;
|
|
|
|
Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
|
|
|
|
// Some level depends spells
|
|
int level_multiplier = 0;
|
|
int level_diff = 0;
|
|
switch (m_spellInfo->Id)
|
|
{
|
|
case 9512: // Restore Energy
|
|
level_diff = m_caster->getLevel() - 40;
|
|
level_multiplier = 2;
|
|
break;
|
|
case 24571: // Blood Fury
|
|
level_diff = m_caster->getLevel() - 60;
|
|
level_multiplier = 10;
|
|
break;
|
|
case 24532: // Burst of Energy
|
|
level_diff = m_caster->getLevel() - 60;
|
|
level_multiplier = 4;
|
|
break;
|
|
case 31930: // Judgements of the Wise
|
|
case 63375: // Improved Stormstrike
|
|
case 68082: // Glyph of Seal of Command
|
|
damage = damage * unitTarget->GetCreateMana() / 100;
|
|
break;
|
|
case 48542: // Revitalize
|
|
damage = damage * unitTarget->GetMaxPower(power) / 100;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (level_diff > 0)
|
|
damage -= level_multiplier * level_diff;
|
|
|
|
if (damage < 0)
|
|
return;
|
|
|
|
if (unitTarget->GetMaxPower(power) == 0)
|
|
return;
|
|
|
|
m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, damage, power);
|
|
|
|
// Mad Alchemist's Potion
|
|
if (m_spellInfo->Id == 45051)
|
|
{
|
|
// find elixirs on target
|
|
bool guardianFound = false;
|
|
bool battleFound = false;
|
|
Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras();
|
|
for (Unit::AuraApplicationMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
|
|
{
|
|
uint32 spell_id = itr->second->GetBase()->GetId();
|
|
if (!guardianFound)
|
|
if (spellmgr.IsSpellMemberOfSpellGroup(spell_id, SPELL_GROUP_ELIXIR_GUARDIAN))
|
|
guardianFound = true;
|
|
if (!battleFound)
|
|
if (spellmgr.IsSpellMemberOfSpellGroup(spell_id, SPELL_GROUP_ELIXIR_BATTLE))
|
|
battleFound = true;
|
|
if (battleFound && guardianFound)
|
|
break;
|
|
}
|
|
|
|
// get all available elixirs by mask and spell level
|
|
std::set<uint32> avalibleElixirs;
|
|
if (!guardianFound)
|
|
spellmgr.GetSetOfSpellsInSpellGroup(SPELL_GROUP_ELIXIR_GUARDIAN, avalibleElixirs);
|
|
if (!battleFound)
|
|
spellmgr.GetSetOfSpellsInSpellGroup(SPELL_GROUP_ELIXIR_BATTLE, avalibleElixirs);
|
|
for (std::set<uint32>::iterator itr = avalibleElixirs.begin(); itr != avalibleElixirs.end() ;)
|
|
{
|
|
SpellEntry const *spellInfo = sSpellStore.LookupEntry(*itr);
|
|
if (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel())
|
|
avalibleElixirs.erase(itr++);
|
|
else if (spellmgr.IsSpellMemberOfSpellGroup(*itr, SPELL_GROUP_ELIXIR_SHATTRATH))
|
|
avalibleElixirs.erase(itr++);
|
|
else if (spellmgr.IsSpellMemberOfSpellGroup(*itr, SPELL_GROUP_ELIXIR_UNSTABLE))
|
|
avalibleElixirs.erase(itr++);
|
|
else
|
|
++itr;
|
|
}
|
|
|
|
if (!avalibleElixirs.empty())
|
|
{
|
|
// cast random elixir on target
|
|
uint32 rand_spell = urand(0,avalibleElixirs.size()-1);
|
|
std::set<uint32>::iterator itr = avalibleElixirs.begin();
|
|
std::advance(itr, rand_spell);
|
|
m_caster->CastSpell(unitTarget,*itr,true,m_CastItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Spell::EffectEnergizePct(uint32 i)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
if (!unitTarget->isAlive())
|
|
return;
|
|
|
|
if (m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
|
|
return;
|
|
|
|
Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
|
|
|
|
uint32 maxPower = unitTarget->GetMaxPower(power);
|
|
if (maxPower == 0)
|
|
return;
|
|
|
|
uint32 gain = damage * maxPower / 100;
|
|
m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, gain, power);
|
|
}
|
|
|
|
void Spell::SendLoot(uint64 guid, LootType loottype)
|
|
{
|
|
Player* player = (Player*)m_caster;
|
|
if (!player)
|
|
return;
|
|
|
|
if (gameObjTarget)
|
|
{
|
|
if (sScriptMgr.OnGossipHello(player, gameObjTarget))
|
|
return;
|
|
|
|
switch (gameObjTarget->GetGoType())
|
|
{
|
|
case GAMEOBJECT_TYPE_DOOR:
|
|
case GAMEOBJECT_TYPE_BUTTON:
|
|
gameObjTarget->UseDoorOrButton();
|
|
player->GetMap()->ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
|
|
return;
|
|
|
|
case GAMEOBJECT_TYPE_QUESTGIVER:
|
|
// start or end quest
|
|
player->PrepareQuestMenu(guid);
|
|
player->SendPreparedQuest(guid);
|
|
return;
|
|
|
|
case GAMEOBJECT_TYPE_SPELL_FOCUS:
|
|
// triggering linked GO
|
|
if (uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId)
|
|
gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
|
|
return;
|
|
|
|
case GAMEOBJECT_TYPE_GOOBER:
|
|
gameObjTarget->Use(m_caster);
|
|
return;
|
|
|
|
case GAMEOBJECT_TYPE_CHEST:
|
|
// TODO: possible must be moved to loot release (in different from linked triggering)
|
|
if (gameObjTarget->GetGOInfo()->chest.eventId)
|
|
{
|
|
sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow());
|
|
player->GetMap()->ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
|
|
}
|
|
|
|
// triggering linked GO
|
|
if (uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId)
|
|
gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
|
|
|
|
// Don't return, let loots been taken
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Send loot
|
|
player->SendLoot(guid, loottype);
|
|
}
|
|
|
|
void Spell::EffectOpenLock(uint32 effIndex)
|
|
{
|
|
if (!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
{
|
|
sLog.outDebug("WORLD: Open Lock - No Player Caster!");
|
|
return;
|
|
}
|
|
|
|
Player* player = (Player*)m_caster;
|
|
|
|
uint32 lockId = 0;
|
|
uint64 guid = 0;
|
|
|
|
// Get lockId
|
|
if (gameObjTarget)
|
|
{
|
|
GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo();
|
|
// Arathi Basin banner opening !
|
|
if (goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune ||
|
|
goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK)
|
|
{
|
|
//CanUseBattleGroundObject() already called in CheckCast()
|
|
// in battleground check
|
|
if (BattleGround *bg = player->GetBattleGround())
|
|
{
|
|
bg->EventPlayerClickedOnFlag(player, gameObjTarget);
|
|
return;
|
|
}
|
|
}
|
|
else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
|
|
{
|
|
//CanUseBattleGroundObject() already called in CheckCast()
|
|
// in battleground check
|
|
if (BattleGround *bg = player->GetBattleGround())
|
|
{
|
|
if (bg->GetTypeID(true) == BATTLEGROUND_EY)
|
|
bg->EventPlayerClickedOnFlag(player, gameObjTarget);
|
|
return;
|
|
}
|
|
}else if (m_spellInfo->Id == 1842 && gameObjTarget->GetGOInfo()->type == GAMEOBJECT_TYPE_TRAP && gameObjTarget->GetOwner())
|
|
{
|
|
gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
|
|
return;
|
|
}
|
|
// TODO: Add script for spell 41920 - Filling, becouse server it freze when use this spell
|
|
// handle outdoor pvp object opening, return true if go was registered for handling
|
|
// these objects must have been spawned by outdoorpvp!
|
|
else if (gameObjTarget->GetGOInfo()->type == GAMEOBJECT_TYPE_GOOBER && sOutdoorPvPMgr.HandleOpenGo(player, gameObjTarget->GetGUID()))
|
|
return;
|
|
lockId = goInfo->GetLockId();
|
|
guid = gameObjTarget->GetGUID();
|
|
}
|
|
else if (itemTarget)
|
|
{
|
|
lockId = itemTarget->GetProto()->LockID;
|
|
guid = itemTarget->GetGUID();
|
|
}
|
|
else
|
|
{
|
|
sLog.outDebug("WORLD: Open Lock - No GameObject/Item Target!");
|
|
return;
|
|
}
|
|
|
|
SkillType skillId = SKILL_NONE;
|
|
int32 reqSkillValue = 0;
|
|
int32 skillValue;
|
|
|
|
SpellCastResult res = CanOpenLock(effIndex, lockId, skillId, reqSkillValue, skillValue);
|
|
if (res != SPELL_CAST_OK)
|
|
{
|
|
SendCastResult(res);
|
|
return;
|
|
}
|
|
|
|
if (gameObjTarget)
|
|
SendLoot(guid, LOOT_SKINNING);
|
|
else
|
|
itemTarget->SetFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_UNLOCKED);
|
|
|
|
// not allow use skill grow at item base open
|
|
if (!m_CastItem && skillId != SKILL_NONE)
|
|
{
|
|
// update skill if really known
|
|
if (uint32 pureSkillValue = player->GetPureSkillValue(skillId))
|
|
{
|
|
if (gameObjTarget)
|
|
{
|
|
// Allow one skill-up until respawned
|
|
if (!gameObjTarget->IsInSkillupList(player->GetGUIDLow()) &&
|
|
player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue))
|
|
gameObjTarget->AddToSkillupList(player->GetGUIDLow());
|
|
}
|
|
else if (itemTarget)
|
|
{
|
|
// Do one skill-up
|
|
player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Spell::EffectSummonChangeItem(uint32 i)
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player *player = (Player*)m_caster;
|
|
|
|
// applied only to using item
|
|
if (!m_CastItem)
|
|
return;
|
|
|
|
// ... only to item in own inventory/bank/equip_slot
|
|
if (m_CastItem->GetOwnerGUID() != player->GetGUID())
|
|
return;
|
|
|
|
uint32 newitemid = m_spellInfo->EffectItemType[i];
|
|
if (!newitemid)
|
|
return;
|
|
|
|
uint16 pos = m_CastItem->GetPos();
|
|
|
|
Item *pNewItem = Item::CreateItem(newitemid, 1, player);
|
|
if (!pNewItem)
|
|
return;
|
|
|
|
for (uint8 j = PERM_ENCHANTMENT_SLOT; j <= TEMP_ENCHANTMENT_SLOT; ++j)
|
|
if (m_CastItem->GetEnchantmentId(EnchantmentSlot(j)))
|
|
pNewItem->SetEnchantment(EnchantmentSlot(j), m_CastItem->GetEnchantmentId(EnchantmentSlot(j)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(j)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(j)));
|
|
|
|
if (m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY))
|
|
{
|
|
double loosePercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY));
|
|
player->DurabilityLoss(pNewItem, loosePercent);
|
|
}
|
|
|
|
if (player->IsInventoryPos(pos))
|
|
{
|
|
ItemPosCountVec dest;
|
|
uint8 msg = player->CanStoreItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true);
|
|
if (msg == EQUIP_ERR_OK)
|
|
{
|
|
player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), true);
|
|
|
|
// prevent crash at access and unexpected charges counting with item update queue corrupt
|
|
if (m_CastItem == m_targets.getItemTarget())
|
|
m_targets.setItemTarget(NULL);
|
|
|
|
m_CastItem = NULL;
|
|
|
|
player->StoreItem(dest, pNewItem, true);
|
|
return;
|
|
}
|
|
}
|
|
else if (player->IsBankPos(pos))
|
|
{
|
|
ItemPosCountVec dest;
|
|
uint8 msg = player->CanBankItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true);
|
|
if (msg == EQUIP_ERR_OK)
|
|
{
|
|
player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), true);
|
|
|
|
// prevent crash at access and unexpected charges counting with item update queue corrupt
|
|
if (m_CastItem == m_targets.getItemTarget())
|
|
m_targets.setItemTarget(NULL);
|
|
|
|
m_CastItem = NULL;
|
|
|
|
player->BankItem(dest, pNewItem, true);
|
|
return;
|
|
}
|
|
}
|
|
else if (player->IsEquipmentPos(pos))
|
|
{
|
|
uint16 dest;
|
|
|
|
player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), true);
|
|
|
|
uint8 msg = player->CanEquipItem(m_CastItem->GetSlot(), dest, pNewItem, true);
|
|
|
|
if (msg == EQUIP_ERR_OK || msg == EQUIP_ERR_CANT_DO_RIGHT_NOW)
|
|
{
|
|
if (msg == EQUIP_ERR_CANT_DO_RIGHT_NOW) dest = EQUIPMENT_SLOT_MAINHAND;
|
|
|
|
// prevent crash at access and unexpected charges counting with item update queue corrupt
|
|
if (m_CastItem == m_targets.getItemTarget())
|
|
m_targets.setItemTarget(NULL);
|
|
|
|
m_CastItem = NULL;
|
|
|
|
player->EquipItem(dest, pNewItem, true);
|
|
player->AutoUnequipOffhandIfNeed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
// fail
|
|
delete pNewItem;
|
|
}
|
|
|
|
void Spell::EffectProficiency(uint32 /*i*/)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
Player *p_target = (Player*)unitTarget;
|
|
|
|
uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask;
|
|
if (m_spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON && !(p_target->GetWeaponProficiency() & subClassMask))
|
|
{
|
|
p_target->AddWeaponProficiency(subClassMask);
|
|
p_target->SendProficiency(ITEM_CLASS_WEAPON, p_target->GetWeaponProficiency());
|
|
}
|
|
if (m_spellInfo->EquippedItemClass == ITEM_CLASS_ARMOR && !(p_target->GetArmorProficiency() & subClassMask))
|
|
{
|
|
p_target->AddArmorProficiency(subClassMask);
|
|
p_target->SendProficiency(ITEM_CLASS_ARMOR, p_target->GetArmorProficiency());
|
|
}
|
|
}
|
|
|
|
void Spell::EffectSummonType(uint32 i)
|
|
{
|
|
uint32 entry = m_spellInfo->EffectMiscValue[i];
|
|
if (!entry)
|
|
return;
|
|
|
|
SummonPropertiesEntry const *properties = sSummonPropertiesStore.LookupEntry(m_spellInfo->EffectMiscValueB[i]);
|
|
if (!properties)
|
|
{
|
|
sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
|
|
return;
|
|
}
|
|
|
|
if (!m_originalCaster)
|
|
return;
|
|
|
|
int32 duration = GetSpellDuration(m_spellInfo);
|
|
if (Player* modOwner = m_originalCaster->GetSpellModOwner())
|
|
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
|
|
|
|
Position pos;
|
|
GetSummonPosition(i, pos);
|
|
|
|
/*//totem must be at same Z in case swimming caster and etc.
|
|
if (fabs(z - m_caster->GetPositionZ()) > 5)
|
|
z = m_caster->GetPositionZ();
|
|
|
|
uint8 level = m_caster->getLevel();
|
|
|
|
// level of creature summoned using engineering item based at engineering skill level
|
|
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_CastItem)
|
|
{
|
|
ItemPrototype const *proto = m_CastItem->GetProto();
|
|
if (proto && proto->RequiredSkill == SKILL_ENGINERING)
|
|
{
|
|
uint16 skill202 = m_caster->ToPlayer()->GetSkillValue(SKILL_ENGINERING);
|
|
if (skill202)
|
|
level = skill202/5;
|
|
}
|
|
}*/
|
|
|
|
TempSummon *summon = NULL;
|
|
|
|
switch (properties->Category)
|
|
{
|
|
default:
|
|
if (properties->Flags & 512)
|
|
{
|
|
SummonGuardian(i, entry, properties);
|
|
break;
|
|
}
|
|
switch (properties->Type)
|
|
{
|
|
case SUMMON_TYPE_PET:
|
|
case SUMMON_TYPE_GUARDIAN:
|
|
case SUMMON_TYPE_GUARDIAN2:
|
|
case SUMMON_TYPE_MINION:
|
|
SummonGuardian(i, entry, properties);
|
|
break;
|
|
case SUMMON_TYPE_VEHICLE:
|
|
case SUMMON_TYPE_VEHICLE2:
|
|
if (m_originalCaster)
|
|
summon = m_caster->GetMap()->SummonCreature(entry, pos, properties, duration, m_originalCaster);
|
|
break;
|
|
case SUMMON_TYPE_TOTEM:
|
|
{
|
|
summon = m_caster->GetMap()->SummonCreature(entry, pos, properties, duration, m_originalCaster);
|
|
if (!summon || !summon->isTotem())
|
|
return;
|
|
|
|
if (damage) // if not spell info, DB values used
|
|
{
|
|
summon->SetMaxHealth(damage);
|
|
summon->SetHealth(damage);
|
|
}
|
|
|
|
//summon->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id);
|
|
|
|
if (m_originalCaster->GetTypeId() == TYPEID_PLAYER
|
|
&& properties->Slot >= SUMMON_SLOT_TOTEM
|
|
&& properties->Slot < MAX_TOTEM_SLOT)
|
|
{
|
|
// set display id depending on race
|
|
uint32 displayId = m_originalCaster->GetModelForTotem(PlayerTotemType(properties->Id));
|
|
summon->SetNativeDisplayId(displayId);
|
|
summon->SetDisplayId(displayId);
|
|
|
|
//summon->SendUpdateToPlayerm_originalCaster->ToPlayer();
|
|
WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
|
|
data << uint8(properties->Slot-1);
|
|
data << uint64(m_originalCaster->GetGUID());
|
|
data << uint32(duration);
|
|
data << uint32(m_spellInfo->Id);
|
|
m_originalCaster->ToPlayer()->SendDirectMessage(&data);
|
|
}
|
|
break;
|
|
}
|
|
case SUMMON_TYPE_MINIPET:
|
|
{
|
|
summon = m_caster->GetMap()->SummonCreature(entry, pos, properties, duration, m_originalCaster);
|
|
if (!summon || !summon->HasUnitTypeMask(UNIT_MASK_MINION))
|
|
return;
|
|
|
|
//summon->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as summon...
|
|
summon->SelectLevel(summon->GetCreatureInfo()); // some summoned creaters have different from 1 DB data for level/hp
|
|
summon->SetUInt32Value(UNIT_NPC_FLAGS, summon->GetCreatureInfo()->npcflag);
|
|
|
|
summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
|
|
|
|
summon->AI()->EnterEvadeMode();
|
|
|
|
std::string name = m_originalCaster->GetName();
|
|
name.append(petTypeSuffix[3]);
|
|
summon->SetName(name);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
float radius = GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
|
|
|
|
int32 amount = damage > 0 ? damage : 1;
|
|
if (m_spellInfo->Id == 18662) // Curse of Doom
|
|
amount = 1;
|
|
|
|
for (uint32 count = 0; count < amount; ++count)
|
|
{
|
|
GetSummonPosition(i, pos, radius, count);
|
|
|
|
TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
|
|
|
|
summon = m_originalCaster->SummonCreature(entry, pos, summonType, duration);
|
|
if (!summon)
|
|
continue;
|
|
if (properties->Category == SUMMON_CATEGORY_ALLY)
|
|
{
|
|
summon->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_originalCaster->GetGUID());
|
|
summon->setFaction(m_originalCaster->getFaction());
|
|
summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}//switch
|
|
break;
|
|
case SUMMON_CATEGORY_PET:
|
|
SummonGuardian(i, entry, properties);
|
|
break;
|
|
case SUMMON_CATEGORY_PUPPET:
|
|
summon = m_caster->GetMap()->SummonCreature(entry, pos, properties, duration, m_originalCaster);
|
|
break;
|
|
case SUMMON_CATEGORY_VEHICLE:
|
|
{
|
|
float x, y, z;
|
|
m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE);
|
|
summon = m_caster->GetMap()->SummonCreature(entry, pos, properties, duration, m_caster);
|
|
if (!summon || !summon->IsVehicle())
|
|
return;
|
|
|
|
if (m_spellInfo->EffectBasePoints[i])
|
|
{
|
|
SpellEntry const *spellProto = sSpellStore.LookupEntry(SpellMgr::CalculateSpellEffectAmount(m_spellInfo, i));
|
|
if (spellProto)
|
|
m_caster->CastSpell(summon, spellProto, true);
|
|
}
|
|
|
|
m_caster->EnterVehicle(summon->GetVehicleKit());
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (summon)
|
|
{
|
|
summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
|
|
summon->SetCreatorGUID(m_originalCaster->GetGUID());
|
|
}
|
|
}
|
|
|
|
void Spell::EffectLearnSpell(uint32 i)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
{
|
|
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
|
EffectLearnPetSpell(i);
|
|
|
|
return;
|
|
}
|
|
|
|
Player *player = (Player*)unitTarget;
|
|
|
|
uint32 spellToLearn = (m_spellInfo->Id == 483 || m_spellInfo->Id == 55884) ? damage : m_spellInfo->EffectTriggerSpell[i];
|
|
player->learnSpell(spellToLearn, false);
|
|
|
|
sLog.outDebug("Spell: Player %u has learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow());
|
|
}
|
|
|
|
typedef std::list< std::pair<uint32, uint64> > DispelList;
|
|
typedef std::list< std::pair<Aura *, uint8> > DispelChargesList;
|
|
void Spell::EffectDispel(uint32 i)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
DispelChargesList dispel_list;
|
|
|
|
// Create dispel mask by dispel type
|
|
uint32 dispel_type = m_spellInfo->EffectMiscValue[i];
|
|
uint32 dispelMask = GetDispellMask(DispelType(dispel_type));
|
|
Unit::AuraMap const& auras = unitTarget->GetOwnedAuras();
|
|
for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
|
|
{
|
|
Aura * aura = itr->second;
|
|
AuraApplication * aurApp = aura->GetApplicationOfTarget(unitTarget->GetGUID());
|
|
if (!aurApp)
|
|
continue;
|
|
|
|
if ((1<<aura->GetSpellProto()->Dispel) & dispelMask)
|
|
{
|
|
if (aura->GetSpellProto()->Dispel == DISPEL_MAGIC)
|
|
{
|
|
bool positive = aurApp->IsPositive() ? (!(aura->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)) : false;
|
|
|
|
// do not remove positive auras if friendly target
|
|
// negative auras if non-friendly target
|
|
if (positive == unitTarget->IsFriendlyTo(m_caster))
|
|
continue;
|
|
}
|
|
|
|
// The charges / stack amounts don't count towards the total number of auras that can be dispelled.
|
|
// Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell
|
|
// Polymorph instead of 1 / (5 + 1) -> 16%.
|
|
bool dispel_charges = aura->GetSpellProto()->AttributesEx7 & SPELL_ATTR_EX7_DISPEL_CHARGES;
|
|
uint8 charges = dispel_charges ? aura->GetCharges() : aura->GetStackAmount();
|
|
if (charges > 0)
|
|
dispel_list.push_back(std::make_pair(aura, charges));
|
|
}
|
|
}
|
|
|
|
if (dispel_list.empty())
|
|
return;
|
|
|
|
// Ok if exist some buffs for dispel try dispel it
|
|
uint32 failCount = 0;
|
|
DispelList success_list;
|
|
WorldPacket dataFail(SMSG_DISPEL_FAILED, 8+8+4+4+damage*4);
|
|
// dispel N = damage buffs (or while exist buffs for dispel)
|
|
for (int32 count = 0; count < damage && !dispel_list.empty();)
|
|
{
|
|
// Random select buff for dispel
|
|
DispelChargesList::iterator itr = dispel_list.begin();
|
|
std::advance(itr, urand(0, dispel_list.size() - 1));
|
|
|
|
bool success = false;
|
|
// 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
|
|
if (!GetDispelChance(itr->first->GetCaster(), unitTarget, itr->first->GetId(), !unitTarget->IsFriendlyTo(m_caster), &success))
|
|
{
|
|
dispel_list.erase(itr);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if (success)
|
|
{
|
|
success_list.push_back(std::make_pair(itr->first->GetId(), itr->first->GetCasterGUID()));
|
|
--itr->second;
|
|
if (itr->second <= 0)
|
|
dispel_list.erase(itr);
|
|
}
|
|
else
|
|
{
|
|
if (!failCount)
|
|
{
|
|
// Failed to dispell
|
|
dataFail << uint64(m_caster->GetGUID()); // Caster GUID
|
|
dataFail << uint64(unitTarget->GetGUID()); // Victim GUID
|
|
dataFail << uint32(m_spellInfo->Id); // dispel spell id
|
|
}
|
|
++failCount;
|
|
dataFail << uint32(itr->first->GetId()); // Spell Id
|
|
}
|
|
++count;
|
|
}
|
|
}
|
|
|
|
if (failCount)
|
|
m_caster->SendMessageToSet(&dataFail, true);
|
|
|
|
if (success_list.empty())
|
|
return;
|
|
|
|
WorldPacket dataSuccess(SMSG_SPELLDISPELLOG, 8+8+4+1+4+damage*5);
|
|
// Send packet header
|
|
dataSuccess.append(unitTarget->GetPackGUID()); // Victim GUID
|
|
dataSuccess.append(m_caster->GetPackGUID()); // Caster GUID
|
|
dataSuccess << uint32(m_spellInfo->Id); // dispel spell id
|
|
dataSuccess << uint8(0); // not used
|
|
dataSuccess << uint32(success_list.size()); // count
|
|
for (DispelList::iterator itr = success_list.begin(); itr != success_list.end(); ++itr)
|
|
{
|
|
// Send dispelled spell info
|
|
dataSuccess << uint32(itr->first); // Spell Id
|
|
dataSuccess << uint8(0); // 0 - dispelled !=0 cleansed
|
|
unitTarget->RemoveAurasDueToSpellByDispel(itr->first, itr->second, m_caster);
|
|
}
|
|
m_caster->SendMessageToSet(&dataSuccess, true);
|
|
|
|
// On success dispel
|
|
// Devour Magic
|
|
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == SPELLCATEGORY_DEVOUR_MAGIC)
|
|
{
|
|
int32 heal_amount = SpellMgr::CalculateSpellEffectAmount(m_spellInfo, 1);
|
|
m_caster->CastCustomSpell(m_caster, 19658, &heal_amount, NULL, NULL, true);
|
|
}
|
|
}
|
|
|
|
void Spell::EffectDualWield(uint32 /*i*/)
|
|
{
|
|
unitTarget->SetCanDualWield(true);
|
|
if (unitTarget->GetTypeId() == TYPEID_UNIT)
|
|
unitTarget->ToCreature()->UpdateDamagePhysical(OFF_ATTACK);
|
|
}
|
|
|
|
void Spell::EffectPull(uint32 /*i*/)
|
|
{
|
|
// TODO: create a proper pull towards distract spell center for distract
|
|
sLog.outDebug("WORLD: Spell Effect DUMMY");
|
|
}
|
|
|
|
void Spell::EffectDistract(uint32 /*i*/)
|
|
{
|
|
// Check for possible target
|
|
if (!unitTarget || unitTarget->isInCombat())
|
|
return;
|
|
|
|
// target must be OK to do this
|
|
if (unitTarget->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING))
|
|
return;
|
|
|
|
float angle = unitTarget->GetAngle(&m_targets.m_dstPos);
|
|
|
|
if (unitTarget->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
// For players just turn them
|
|
unitTarget->ToPlayer()->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false);
|
|
unitTarget->ToPlayer()->SendTeleportAckPacket();
|
|
}
|
|
else
|
|
{
|
|
// Set creature Distracted, Stop it, And turn it
|
|
unitTarget->SetOrientation(angle);
|
|
unitTarget->StopMoving();
|
|
unitTarget->GetMotionMaster()->MoveDistract(damage * IN_MILLISECONDS);
|
|
}
|
|
}
|
|
|
|
void Spell::EffectPickPocket(uint32 /*i*/)
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// victim must be creature and attackable
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget))
|
|
return;
|
|
|
|
// victim have to be alive and humanoid or undead
|
|
if (unitTarget->isAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0)
|
|
m_caster->ToPlayer()->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING);
|
|
}
|
|
|
|
void Spell::EffectAddFarsight(uint32 i)
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
float radius = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
|
|
int32 duration = GetSpellDuration(m_spellInfo);
|
|
// Caster not in world, might be spell triggered from aura removal
|
|
if (!m_caster->IsInWorld())
|
|
return;
|
|
DynamicObject* dynObj = new DynamicObject;
|
|
if (!dynObj->Create(objmgr.GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, m_targets.m_dstPos, radius, true))
|
|
{
|
|
delete dynObj;
|
|
return;
|
|
}
|
|
dynObj->SetDuration(duration);
|
|
dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
|
|
m_caster->AddDynObject(dynObj);
|
|
|
|
dynObj->setActive(true); //must before add to map to be put in world container
|
|
dynObj->GetMap()->Add(dynObj); //grid will also be loaded
|
|
|
|
// Need to update visibility of object for client to accept farsight guid
|
|
m_caster->ToPlayer()->SetViewpoint(dynObj, true);
|
|
//m_caster->ToPlayer()->UpdateVisibilityOf(dynObj);
|
|
}
|
|
|
|
void Spell::EffectTeleUnitsFaceCaster(uint32 i)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
if (unitTarget->isInFlight())
|
|
return;
|
|
|
|
float dis = m_caster->GetSpellRadiusForTarget(unitTarget, sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
|
|
|
|
float fx,fy,fz;
|
|
m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
|
|
|
|
unitTarget->NearTeleportTo(fx,fy,fz,-m_caster->GetOrientation(),unitTarget == m_caster);
|
|
}
|
|
|
|
void Spell::EffectLearnSkill(uint32 i)
|
|
{
|
|
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
if (damage < 0)
|
|
return;
|
|
|
|
uint32 skillid = m_spellInfo->EffectMiscValue[i];
|
|
uint16 skillval = unitTarget->ToPlayer()->GetPureSkillValue(skillid);
|
|
unitTarget->ToPlayer()->SetSkill(skillid, SpellMgr::CalculateSpellEffectAmount(m_spellInfo, i), skillval?skillval:1, damage*75);
|
|
}
|
|
|
|
void Spell::EffectAddHonor(uint32 /*i*/)
|
|
{
|
|
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// not scale value for item based reward (/10 value expected)
|
|
if (m_CastItem)
|
|
{
|
|
unitTarget->ToPlayer()->RewardHonor(NULL, 1, damage/10);
|
|
sLog.outDebug("SpellEffect::AddHonor (spell_id %u) rewards %d honor points (item %u) for player: %u", m_spellInfo->Id, damage/10, m_CastItem->GetEntry(),unitTarget->ToPlayer()->GetGUIDLow());
|
|
return;
|
|
}
|
|
|
|
// do not allow to add too many honor for player (50 * 21) = 1040 at level 70, or (50 * 31) = 1550 at level 80
|
|
if (damage <= 50)
|
|
{
|
|
uint32 honor_reward = Trinity::Honor::hk_honor_at_level(unitTarget->getLevel(), damage);
|
|
unitTarget->ToPlayer()->RewardHonor(NULL, 1, honor_reward);
|
|
sLog.outDebug("SpellEffect::AddHonor (spell_id %u) rewards %u honor points (scale) to player: %u", m_spellInfo->Id, honor_reward, unitTarget->ToPlayer()->GetGUIDLow());
|
|
}
|
|
else
|
|
{
|
|
//maybe we have correct honor_gain in damage already
|
|
unitTarget->ToPlayer()->RewardHonor(NULL, 1, damage);
|
|
sLog.outError("SpellEffect::AddHonor (spell_id %u) rewards %u honor points (non scale) for player: %u", m_spellInfo->Id, damage, unitTarget->ToPlayer()->GetGUIDLow());
|
|
}
|
|
}
|
|
|
|
void Spell::EffectTradeSkill(uint32 /*i*/)
|
|
{
|
|
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
// uint32 skillid = m_spellInfo->EffectMiscValue[i];
|
|
// uint16 skillmax = unitTarget->ToPlayer()->(skillid);
|
|
// unitTarget->ToPlayer()->SetSkill(skillid,skillval?skillval:1,skillmax+75);
|
|
}
|
|
|
|
void Spell::EffectEnchantItemPerm(uint32 effect_idx)
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
if (!itemTarget)
|
|
return;
|
|
|
|
Player* p_caster = (Player*)m_caster;
|
|
|
|
// Handle vellums
|
|
if (itemTarget->IsWeaponVellum() || itemTarget->IsArmorVellum())
|
|
{
|
|
// destroy one vellum from stack
|
|
uint32 count = 1;
|
|
p_caster->DestroyItemCount(itemTarget,count,true);
|
|
unitTarget=p_caster;
|
|
// and add a scroll
|
|
DoCreateItem(effect_idx,m_spellInfo->EffectItemType[effect_idx]);
|
|
itemTarget=NULL;
|
|
m_targets.setItemTarget(NULL);
|
|
}
|
|
else
|
|
{
|
|
// do not increase skill if vellum used
|
|
if (!(m_CastItem && m_CastItem->GetProto()->Flags & ITEM_PROTO_FLAG_TRIGGERED_CAST))
|
|
p_caster->UpdateCraftSkill(m_spellInfo->Id);
|
|
|
|
uint32 enchant_id = m_spellInfo->EffectMiscValue[effect_idx];
|
|
if (!enchant_id)
|
|
return;
|
|
|
|
SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
|
|
if (!pEnchant)
|
|
return;
|
|
|
|
// item can be in trade slot and have owner diff. from caster
|
|
Player* item_owner = itemTarget->GetOwner();
|
|
if (!item_owner)
|
|
return;
|
|
|
|
if (item_owner != p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
|
|
{
|
|
sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
|
|
p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
|
|
itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
|
|
item_owner->GetName(),item_owner->GetSession()->GetAccountId());
|
|
}
|
|
|
|
// remove old enchanting before applying new if equipped
|
|
item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false);
|
|
|
|
itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0);
|
|
|
|
// add new enchanting if equipped
|
|
item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,true);
|
|
}
|
|
}
|
|
|
|
void Spell::EffectEnchantItemPrismatic(uint32 effect_idx)
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
if (!itemTarget)
|
|
return;
|
|
|
|
Player* p_caster = (Player*)m_caster;
|
|
|
|
uint32 enchant_id = m_spellInfo->EffectMiscValue[effect_idx];
|
|
if (!enchant_id)
|
|
return;
|
|
|
|
SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
|
|
if (!pEnchant)
|
|
return;
|
|
|
|
// support only enchantings with add socket in this slot
|
|
{
|
|
bool add_socket = false;
|
|
for (uint8 i = 0; i < 3; ++i)
|
|
{
|
|
if (pEnchant->type[i] == ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET)
|
|
{
|
|
add_socket = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!add_socket)
|
|
{
|
|
sLog.outError("Spell::EffectEnchantItemPrismatic: attempt apply enchant spell %u with SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC (%u) but without ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET (%u), not suppoted yet.",
|
|
m_spellInfo->Id,SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC,ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// item can be in trade slot and have owner diff. from caster
|
|
Player* item_owner = itemTarget->GetOwner();
|
|
if (!item_owner)
|
|
return;
|
|
|
|
if (item_owner != p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
|
|
{
|
|
sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
|
|
p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
|
|
itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
|
|
item_owner->GetName(),item_owner->GetSession()->GetAccountId());
|
|
}
|
|
|
|
// remove old enchanting before applying new if equipped
|
|
item_owner->ApplyEnchantment(itemTarget,PRISMATIC_ENCHANTMENT_SLOT,false);
|
|
|
|
itemTarget->SetEnchantment(PRISMATIC_ENCHANTMENT_SLOT, enchant_id, 0, 0);
|
|
|
|
// add new enchanting if equipped
|
|
item_owner->ApplyEnchantment(itemTarget,PRISMATIC_ENCHANTMENT_SLOT,true);
|
|
}
|
|
|
|
void Spell::EffectEnchantItemTmp(uint32 i)
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player* p_caster = (Player*)m_caster;
|
|
|
|
// Rockbiter Weapon apply to both weapon
|
|
if (!itemTarget)
|
|
return;
|
|
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[0] & 0x400000)
|
|
{
|
|
uint32 spell_id = 0;
|
|
|
|
// enchanting spell selected by calculated damage-per-sec stored in Effect[1] base value
|
|
// Note: damage calculated (correctly) with rounding int32(float(v)) but
|
|
// RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime
|
|
switch(damage)
|
|
{
|
|
// Rank 1
|
|
case 2: spell_id = 36744; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
|
|
// Rank 2
|
|
case 4: spell_id = 36753; break; // 0% [ 7% == 4, 14% == 4]
|
|
case 5: spell_id = 36751; break; // 20%
|
|
// Rank 3
|
|
case 6: spell_id = 36754; break; // 0% [ 7% == 6, 14% == 6]
|
|
case 7: spell_id = 36755; break; // 20%
|
|
// Rank 4
|
|
case 9: spell_id = 36761; break; // 0% [ 7% == 6]
|
|
case 10: spell_id = 36758; break; // 14%
|
|
case 11: spell_id = 36760; break; // 20%
|
|
default:
|
|
sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",damage);
|
|
return;
|
|
}
|
|
|
|
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
|
|
if (!spellInfo)
|
|
{
|
|
sLog.outError("Spell::EffectEnchantItemTmp: unknown spell id %i", spell_id);
|
|
return;
|
|
|
|
}
|
|
|
|
for (int j = BASE_ATTACK; j <= OFF_ATTACK; ++j)
|
|
{
|
|
if (Item* item = p_caster->GetWeaponForAttack(WeaponAttackType(j)))
|
|
{
|
|
if (item->IsFitToSpellRequirements(m_spellInfo))
|
|
{
|
|
Spell *spell = new Spell(m_caster, spellInfo, true);
|
|
SpellCastTargets targets;
|
|
targets.setItemTarget(item);
|
|
spell->prepare(&targets);
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
if (!itemTarget)
|
|
return;
|
|
|
|
uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
|
|
|
|
if (!enchant_id)
|
|
{
|
|
sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,i);
|
|
return;
|
|
}
|
|
|
|
SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
|
|
if (!pEnchant)
|
|
{
|
|
sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo->Id,i,enchant_id);
|
|
return;
|
|
}
|
|
|
|
// select enchantment duration
|
|
uint32 duration;
|
|
|
|
// rogue family enchantments exception by duration
|
|
if (m_spellInfo->Id == 38615)
|
|
duration = 1800; // 30 mins
|
|
// other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
|
|
else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE)
|
|
duration = 3600; // 1 hour
|
|
// shaman family enchantments
|
|
else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN)
|
|
duration = 1800; // 30 mins
|
|
// other cases with this SpellVisual already selected
|
|
else if (m_spellInfo->SpellVisual[0] == 215)
|
|
duration = 1800; // 30 mins
|
|
// some fishing pole bonuses except Glow Worm which lasts full hour
|
|
else if (m_spellInfo->SpellVisual[0] == 563 && m_spellInfo->Id != 64401)
|
|
duration = 600; // 10 mins
|
|
// shaman rockbiter enchantments
|
|
else if (m_spellInfo->SpellVisual[0] == 0)
|
|
duration = 1800; // 30 mins
|
|
else if (m_spellInfo->Id == 29702)
|
|
duration = 300; // 5 mins
|
|
else if (m_spellInfo->Id == 37360)
|
|
duration = 300; // 5 mins
|
|
// default case
|
|
else
|
|
duration = 3600; // 1 hour
|
|
|
|
// item can be in trade slot and have owner diff. from caster
|
|
Player* item_owner = itemTarget->GetOwner();
|
|
if (!item_owner)
|
|
return;
|
|
|
|
if (item_owner != p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
|
|
{
|
|
sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
|
|
p_caster->GetName(), p_caster->GetSession()->GetAccountId(),
|
|
itemTarget->GetProto()->Name1, itemTarget->GetEntry(),
|
|
item_owner->GetName(), item_owner->GetSession()->GetAccountId());
|
|
}
|
|
|
|
// remove old enchanting before applying new if equipped
|
|
item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT, false);
|
|
|
|
itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration * 1000, 0);
|
|
|
|
// add new enchanting if equipped
|
|
item_owner->ApplyEnchantment(itemTarget, TEMP_ENCHANTMENT_SLOT, true);
|
|
}
|
|
|
|
void Spell::EffectTameCreature(uint32 /*i*/)
|
|
{
|
|
if (m_caster->GetPetGUID())
|
|
return;
|
|
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
if (unitTarget->GetTypeId() != TYPEID_UNIT)
|
|
return;
|
|
|
|
Creature* creatureTarget = unitTarget->ToCreature();
|
|
|
|
if (creatureTarget->isPet())
|
|
return;
|
|
|
|
if (m_caster->getClass() != CLASS_HUNTER)
|
|
return;
|
|
|
|
// cast finish successfully
|
|
//SendChannelUpdate(0);
|
|
finish();
|
|
|
|
Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget,m_spellInfo->Id);
|
|
if (!pet) // in very specific state like near world end/etc.
|
|
return;
|
|
|
|
// "kill" original creature
|
|
creatureTarget->ForcedDespawn();
|
|
|
|
uint8 level = (creatureTarget->getLevel() < (m_caster->getLevel() - 5)) ? (m_caster->getLevel() - 5) : creatureTarget->getLevel();
|
|
|
|
// prepare visual effect for levelup
|
|
pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
|
|
|
|
// add to world
|
|
pet->GetMap()->Add(pet->ToCreature());
|
|
|
|
// visual effect for levelup
|
|
pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
|
|
|
|
// caster have pet now
|
|
m_caster->SetMinion(pet, true);
|
|
|
|
pet->InitTalentForLevel();
|
|
|
|
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
|
|
m_caster->ToPlayer()->PetSpellInitialize();
|
|
}
|
|
}
|
|
|
|
void Spell::EffectSummonPet(uint32 i)
|
|
{
|
|
Player *owner = NULL;
|
|
if (m_originalCaster)
|
|
{
|
|
if (m_originalCaster->GetTypeId() == TYPEID_PLAYER)
|
|
owner = (Player*)m_originalCaster;
|
|
else if (m_originalCaster->ToCreature()->isTotem())
|
|
owner = m_originalCaster->GetCharmerOrOwnerPlayerOrPlayerItself();
|
|
}
|
|
|
|
uint32 petentry = m_spellInfo->EffectMiscValue[i];
|
|
|
|
if (!owner)
|
|
{
|
|
SummonPropertiesEntry const *properties = sSummonPropertiesStore.LookupEntry(67);
|
|
if (properties)
|
|
SummonGuardian(i, petentry, properties);
|
|
return;
|
|
}
|
|
|
|
Pet *OldSummon = owner->GetPet();
|
|
|
|
// if pet requested type already exist
|
|
if (OldSummon)
|
|
{
|
|
if (petentry == 0 || OldSummon->GetEntry() == petentry)
|
|
{
|
|
// pet in corpse state can't be summoned
|
|
if (OldSummon->isDead())
|
|
return;
|
|
|
|
ASSERT(OldSummon->GetMap() == owner->GetMap());
|
|
|
|
//OldSummon->GetMap()->Remove(OldSummon->ToCreature(),false);
|
|
|
|
float px, py, pz;
|
|
owner->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
|
|
|
|
OldSummon->NearTeleportTo(px, py, pz, OldSummon->GetOrientation());
|
|
//OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
|
|
//OldSummon->SetMap(owner->GetMap());
|
|
//owner->GetMap()->Add(OldSummon->ToCreature());
|
|
|
|
if (owner->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled())
|
|
owner->ToPlayer()->PetSpellInitialize();
|
|
|
|
return;
|
|
}
|
|
|
|
if (owner->GetTypeId() == TYPEID_PLAYER)
|
|
owner->ToPlayer()->RemovePet(OldSummon,(OldSummon->getPetType() == HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false);
|
|
else
|
|
return;
|
|
}
|
|
|
|
float x, y, z;
|
|
owner->GetClosePoint(x, y, z, owner->GetObjectSize());
|
|
Pet* pet = owner->SummonPet(petentry, x, y, z, owner->GetOrientation(), SUMMON_PET, 0);
|
|
if (!pet)
|
|
return;
|
|
|
|
if (m_caster->GetTypeId() == TYPEID_UNIT)
|
|
{
|
|
if (m_caster->ToCreature()->isTotem())
|
|
pet->SetReactState(REACT_AGGRESSIVE);
|
|
else
|
|
pet->SetReactState(REACT_DEFENSIVE);
|
|
}
|
|
|
|
pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
|
|
|
|
// generate new name for summon pet
|
|
std::string new_name=objmgr.GeneratePetName(petentry);
|
|
if (!new_name.empty())
|
|
pet->SetName(new_name);
|
|
}
|
|
|
|
void Spell::EffectLearnPetSpell(uint32 i)
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player *_player = (Player*)m_caster;
|
|
|
|
Pet *pet = _player->GetPet();
|
|
if (!pet)
|
|
return;
|
|
if (!pet->isAlive())
|
|
return;
|
|
|
|
SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]);
|
|
if (!learn_spellproto)
|
|
return;
|
|
|
|
pet->learnSpell(learn_spellproto->Id);
|
|
|
|
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
|
|
_player->PetSpellInitialize();
|
|
}
|
|
|
|
void Spell::EffectTaunt(uint32 /*i*/)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
// this effect use before aura Taunt apply for prevent taunt already attacking target
|
|
// for spell as marked "non effective at already attacking target"
|
|
if (!unitTarget || !unitTarget->CanHaveThreatList()
|
|
|| unitTarget->getVictim() == m_caster)
|
|
{
|
|
SendCastResult(SPELL_FAILED_DONT_REPORT);
|
|
return;
|
|
}
|
|
|
|
if (m_spellInfo->Id == 62124)
|
|
{
|
|
int32 damageDone = 1 + m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.5f;
|
|
m_caster->DealDamage(unitTarget, damageDone, NULL, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_HOLY, m_spellInfo, false);
|
|
m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damageDone, SPELL_SCHOOL_MASK_HOLY, 0, 0, false, false, false);
|
|
}
|
|
|
|
// Also use this effect to set the taunter's threat to the taunted creature's highest value
|
|
if (unitTarget->getThreatManager().getCurrentVictim())
|
|
{
|
|
float myThreat = unitTarget->getThreatManager().getThreat(m_caster);
|
|
float itsThreat = unitTarget->getThreatManager().getCurrentVictim()->getThreat();
|
|
if (itsThreat > myThreat)
|
|
unitTarget->getThreatManager().addThreat(m_caster, itsThreat - myThreat);
|
|
}
|
|
|
|
//Set aggro victim to caster
|
|
if (!unitTarget->getThreatManager().getOnlineContainer().empty())
|
|
if (HostileReference* forcedVictim = unitTarget->getThreatManager().getOnlineContainer().getReferenceByTarget(m_caster))
|
|
unitTarget->getThreatManager().setCurrentVictim(forcedVictim);
|
|
|
|
if (unitTarget->ToCreature()->IsAIEnabled && !unitTarget->ToCreature()->HasReactState(REACT_PASSIVE))
|
|
unitTarget->ToCreature()->AI()->AttackStart(m_caster);
|
|
}
|
|
|
|
void Spell::EffectWeaponDmg(uint32 /*i*/)
|
|
{
|
|
}
|
|
|
|
void Spell::SpellDamageWeaponDmg(uint32 i)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
if (!unitTarget->isAlive())
|
|
return;
|
|
|
|
// multiple weapon dmg effect workaround
|
|
// execute only the last weapon damage
|
|
// and handle all effects at once
|
|
for (uint32 j = i + 1; j < 3; ++j)
|
|
{
|
|
switch (m_spellInfo->Effect[j])
|
|
{
|
|
case SPELL_EFFECT_WEAPON_DAMAGE:
|
|
case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
|
|
case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
|
|
case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
|
|
return; // we must calculate only at last weapon effect
|
|
break;
|
|
}
|
|
}
|
|
|
|
// some spell specific modifiers
|
|
float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
|
|
int32 fixed_bonus = 0;
|
|
int32 spell_bonus = 0; // bonus specific for spell
|
|
|
|
switch (m_spellInfo->SpellFamilyName)
|
|
{
|
|
case SPELLFAMILY_WARRIOR:
|
|
{
|
|
// Devastate (player ones)
|
|
if (m_spellInfo->SpellFamilyFlags[1] & 0x40)
|
|
{
|
|
// Player can apply only 58567 Sunder Armor effect.
|
|
bool needCast = !unitTarget->HasAura(58567, m_caster->GetGUID());
|
|
if (needCast)
|
|
m_caster->CastSpell(unitTarget, 58567, true);
|
|
|
|
if (Aura * aur = unitTarget->GetAura(58567, m_caster->GetGUID()))
|
|
{
|
|
// 58388 - Glyph of Devastate dummy aura.
|
|
if (int32 num = (needCast ? 0 : 1) + (m_caster->HasAura(58388) ? 1 : 0))
|
|
aur->ModStackAmount(num);
|
|
fixed_bonus += (aur->GetStackAmount() - 1) * CalculateDamage(2, unitTarget);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_ROGUE:
|
|
{
|
|
// Fan of Knives, Hemorrhage, Ghostly Strike
|
|
if ((m_spellInfo->SpellFamilyFlags[1] & 0x40000)
|
|
|| (m_spellInfo->SpellFamilyFlags[0] & 0x6000000))
|
|
{
|
|
// Hemorrhage
|
|
if (m_spellInfo->SpellFamilyFlags[0] & 0x2000000)
|
|
{
|
|
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
|
m_caster->ToPlayer()->AddComboPoints(unitTarget, 1, this);
|
|
}
|
|
// 50% more damage with daggers
|
|
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
|
if (Item* item = m_caster->ToPlayer()->GetWeaponForAttack(m_attackType, true))
|
|
if (item->GetProto()->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER)
|
|
totalDamagePercentMod *= 1.5f;
|
|
}
|
|
// Mutilate (for each hand)
|
|
else if (m_spellInfo->SpellFamilyFlags[1] & 0x6)
|
|
{
|
|
bool found = false;
|
|
// fast check
|
|
if (unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON, m_spellInfo, m_caster))
|
|
found = true;
|
|
// full aura scan
|
|
else
|
|
{
|
|
Unit::AuraApplicationMap const& auras = unitTarget->GetAppliedAuras();
|
|
for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
|
|
{
|
|
if (itr->second->GetBase()->GetSpellProto()->Dispel == DISPEL_POISON)
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (found)
|
|
totalDamagePercentMod *= 1.2f; // 120% if poisoned
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_PALADIN:
|
|
{
|
|
// Seal of Command - Increase damage by 36% on every swing
|
|
if (m_spellInfo->SpellFamilyFlags[0] & 0x2000000)
|
|
{
|
|
totalDamagePercentMod *= 1.36f; //136% damage
|
|
}
|
|
|
|
// Seal of Command Unleashed
|
|
else if (m_spellInfo->Id == 20467)
|
|
{
|
|
spell_bonus += int32(0.08f*m_caster->GetTotalAttackPowerValue(BASE_ATTACK));
|
|
spell_bonus += int32(0.13f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)));
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_SHAMAN:
|
|
{
|
|
// Skyshatter Harness item set bonus
|
|
// Stormstrike
|
|
if (AuraEffect * aurEff = m_caster->IsScriptOverriden(m_spellInfo, 5634))
|
|
m_caster->CastSpell(m_caster, 38430, true, NULL, aurEff);
|
|
break;
|
|
}
|
|
case SPELLFAMILY_DRUID:
|
|
{
|
|
// Mangle (Cat): CP
|
|
if (m_spellInfo->SpellFamilyFlags[1] & 0x400)
|
|
{
|
|
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
|
m_caster->ToPlayer()->AddComboPoints(unitTarget,1, this);
|
|
}
|
|
// Shred, Maul - Rend and Tear
|
|
else if (m_spellInfo->SpellFamilyFlags[0] & 0x00008800 && unitTarget->HasAuraState(AURA_STATE_BLEEDING))
|
|
{
|
|
if (AuraEffect const* rendAndTear = m_caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 2859, 0))
|
|
{
|
|
totalDamagePercentMod *= float((rendAndTear->GetAmount() + 100.0f) / 100.0f);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_HUNTER:
|
|
{
|
|
// Kill Shot - bonus damage from Ranged Attack Power
|
|
if (m_spellInfo->SpellFamilyFlags[1] & 0x800000)
|
|
spell_bonus += int32(0.4f*m_caster->GetTotalAttackPowerValue(RANGED_ATTACK));
|
|
break;
|
|
}
|
|
case SPELLFAMILY_DEATHKNIGHT:
|
|
{
|
|
// Plague Strike
|
|
if (m_spellInfo->SpellFamilyFlags[0] & 0x00000001)
|
|
{
|
|
// Glyph of Plague Strike
|
|
if (AuraEffect * aurEff = m_caster->GetAuraEffect(58657,0))
|
|
totalDamagePercentMod *= float((aurEff->GetAmount() + 100.0f) / 100.0f);
|
|
}
|
|
// Blood Strike
|
|
else if (m_spellInfo->SpellFamilyFlags[0] & 0x400000)
|
|
{
|
|
totalDamagePercentMod *= (float(unitTarget->GetDiseasesByCaster(m_caster->GetGUID())) * 12.5f + 100.0f) / 100.0f;
|
|
|
|
// Glyph of Blood Strike
|
|
if (AuraEffect * aurEff = m_caster->GetAuraEffect(59332,0))
|
|
{
|
|
if (unitTarget->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED))
|
|
totalDamagePercentMod *= float((20 + 100.0f) / 100.0f);
|
|
}
|
|
}
|
|
// Death Strike
|
|
else if (m_spellInfo->SpellFamilyFlags[0] & 0x00000010)
|
|
{
|
|
// Glyph of Death Strike
|
|
if (AuraEffect * aurEff = m_caster->GetAuraEffect(59336,0))
|
|
{
|
|
if (uint32 runic = m_caster->GetPower(POWER_RUNIC_POWER))
|
|
{
|
|
if (runic > 25)
|
|
runic = 25;
|
|
|
|
totalDamagePercentMod *= float((runic + 100.0f) / 100.0f);
|
|
}
|
|
}
|
|
}
|
|
// Obliterate (12.5% more damage per disease)
|
|
else if (m_spellInfo->SpellFamilyFlags[1] & 0x20000)
|
|
{
|
|
bool consumeDiseases = true;
|
|
// Annihilation
|
|
if (AuraEffect * aurEff = m_caster->GetDummyAuraEffect(SPELLFAMILY_DEATHKNIGHT, 2710, 0))
|
|
{
|
|
// Do not consume diseases if roll sucesses
|
|
if (roll_chance_i(aurEff->GetAmount()))
|
|
consumeDiseases = false;
|
|
}
|
|
totalDamagePercentMod *= (float(CalculateDamage(2, unitTarget) * unitTarget->GetDiseasesByCaster(m_caster->GetGUID(), consumeDiseases) / 2) + 100.0f) / 100.0f;
|
|
}
|
|
// Blood-Caked Strike - Blood-Caked Blade
|
|
else if (m_spellInfo->SpellIconID == 1736)
|
|
totalDamagePercentMod *= (float(unitTarget->GetDiseasesByCaster(m_caster->GetGUID())) * 12.5f + 100.0f) / 100.0f;
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool normalized = false;
|
|
float weaponDamagePercentMod = 1.0;
|
|
for (int j = 0; j < 3; ++j)
|
|
{
|
|
switch(m_spellInfo->Effect[j])
|
|
{
|
|
case SPELL_EFFECT_WEAPON_DAMAGE:
|
|
case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
|
|
fixed_bonus += CalculateDamage(j, unitTarget);
|
|
break;
|
|
case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
|
|
fixed_bonus += CalculateDamage(j, unitTarget);
|
|
normalized = true;
|
|
break;
|
|
case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
|
|
weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f;
|
|
break;
|
|
default:
|
|
break; // not weapon damage effect, just skip
|
|
}
|
|
}
|
|
|
|
// apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
|
|
if (fixed_bonus || spell_bonus)
|
|
{
|
|
UnitMods unitMod;
|
|
switch(m_attackType)
|
|
{
|
|
default:
|
|
case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
|
|
case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
|
|
case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
|
|
}
|
|
|
|
float weapon_total_pct = 1.0f;
|
|
if (m_spellInfo->SchoolMask & SPELL_SCHOOL_MASK_NORMAL)
|
|
weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
|
|
|
|
if (fixed_bonus)
|
|
fixed_bonus = int32(fixed_bonus * weapon_total_pct);
|
|
if (spell_bonus)
|
|
spell_bonus = int32(spell_bonus * weapon_total_pct);
|
|
}
|
|
|
|
int32 weaponDamage = m_caster->CalculateDamage(m_attackType, normalized, true);
|
|
|
|
// Sequence is important
|
|
for (int j = 0; j < 3; ++j)
|
|
{
|
|
// We assume that a spell have at most one fixed_bonus
|
|
// and at most one weaponDamagePercentMod
|
|
switch(m_spellInfo->Effect[j])
|
|
{
|
|
case SPELL_EFFECT_WEAPON_DAMAGE:
|
|
case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
|
|
case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
|
|
weaponDamage += fixed_bonus;
|
|
break;
|
|
case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
|
|
weaponDamage = int32(weaponDamage * weaponDamagePercentMod);
|
|
default:
|
|
break; // not weapon damage effect, just skip
|
|
}
|
|
}
|
|
|
|
if (spell_bonus)
|
|
weaponDamage += spell_bonus;
|
|
|
|
if (totalDamagePercentMod != 1.0f)
|
|
weaponDamage = int32(weaponDamage * totalDamagePercentMod);
|
|
|
|
// prevent negative damage
|
|
uint32 eff_damage = uint32(weaponDamage > 0 ? weaponDamage : 0);
|
|
|
|
// Add melee damage bonuses (also check for negative)
|
|
m_caster->MeleeDamageBonus(unitTarget, &eff_damage, m_attackType, m_spellInfo);
|
|
m_damage+= eff_damage;
|
|
}
|
|
|
|
void Spell::EffectThreat(uint32 /*i*/)
|
|
{
|
|
if (!unitTarget || !unitTarget->isAlive() || !m_caster->isAlive())
|
|
return;
|
|
|
|
if (!unitTarget->CanHaveThreatList())
|
|
return;
|
|
|
|
unitTarget->AddThreat(m_caster, float(damage));
|
|
}
|
|
|
|
void Spell::EffectHealMaxHealth(uint32 /*i*/)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
if (!unitTarget->isAlive())
|
|
return;
|
|
|
|
int32 addhealth;
|
|
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN) // Lay on Hands
|
|
{
|
|
if (m_caster && m_caster->GetGUID() == unitTarget->GetGUID())
|
|
{
|
|
m_caster->CastSpell(m_caster, 25771, true); // Forbearance
|
|
m_caster->CastSpell(m_caster, 61988, true); // Immune shield marker (serverside)
|
|
m_caster->CastSpell(m_caster, 61987, true); // Avenging Wrath marker
|
|
}
|
|
|
|
addhealth = m_caster->GetMaxHealth();
|
|
}
|
|
else
|
|
addhealth = unitTarget->GetMaxHealth() - unitTarget->GetHealth();
|
|
if (m_originalCaster)
|
|
{
|
|
addhealth=m_originalCaster->SpellHealingBonus(unitTarget,m_spellInfo, addhealth, HEAL);
|
|
m_originalCaster->DealHeal(unitTarget, addhealth, m_spellInfo);
|
|
}
|
|
}
|
|
|
|
void Spell::EffectInterruptCast(uint32 /*i*/)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
if (!unitTarget->isAlive())
|
|
return;
|
|
|
|
// TODO: not all spells that used this effect apply cooldown at school spells
|
|
// also exist case: apply cooldown to interrupted cast only and to all spells
|
|
for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i)
|
|
{
|
|
if (Spell* spell = unitTarget->GetCurrentSpell(CurrentSpellTypes(i)))
|
|
{
|
|
SpellEntry const* curSpellInfo = spell->m_spellInfo;
|
|
// check if we can interrupt spell
|
|
if ((spell->getState() == SPELL_STATE_CASTING
|
|
|| spell->getState() == SPELL_STATE_PREPARING && spell->GetCastTime() > 0.0f)
|
|
&& curSpellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && curSpellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE)
|
|
{
|
|
if (m_originalCaster)
|
|
{
|
|
int32 duration = m_originalCaster->ModSpellDuration(m_spellInfo, unitTarget, m_originalCaster->CalcSpellDuration(m_spellInfo), false);
|
|
unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(curSpellInfo), duration/*GetSpellDuration(m_spellInfo)*/);
|
|
}
|
|
unitTarget->InterruptSpell(CurrentSpellTypes(i), false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Spell::EffectSummonObjectWild(uint32 i)
|
|
{
|
|
uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
|
|
|
|
GameObject* pGameObj = new GameObject;
|
|
|
|
WorldObject* target = focusObject;
|
|
if (!target)
|
|
target = m_caster;
|
|
|
|
float x, y, z;
|
|
if (m_targets.HasDst())
|
|
m_targets.m_dstPos.GetPosition(x, y, z);
|
|
else
|
|
m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE);
|
|
|
|
Map *map = target->GetMap();
|
|
|
|
if (!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
|
|
m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
|
|
{
|
|
delete pGameObj;
|
|
return;
|
|
}
|
|
|
|
int32 duration = GetSpellDuration(m_spellInfo);
|
|
|
|
pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0);
|
|
pGameObj->SetSpellId(m_spellInfo->Id);
|
|
|
|
// Wild object not have owner and check clickable by players
|
|
map->Add(pGameObj);
|
|
|
|
if (pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP && m_caster->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
Player *pl = m_caster->ToPlayer();
|
|
BattleGround* bg = pl->GetBattleGround();
|
|
|
|
switch(pGameObj->GetMapId())
|
|
{
|
|
case 489: //WS
|
|
{
|
|
if (bg && bg->GetTypeID(true) == BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS)
|
|
{
|
|
uint32 team = ALLIANCE;
|
|
|
|
if (pl->GetTeam() == team)
|
|
team = HORDE;
|
|
|
|
((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team);
|
|
}
|
|
break;
|
|
}
|
|
case 566: //EY
|
|
{
|
|
if (bg && bg->GetTypeID(true) == BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS)
|
|
{
|
|
((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID());
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (uint32 linkedEntry = pGameObj->GetGOInfo()->GetLinkedGameObjectEntry())
|
|
{
|
|
GameObject* linkedGO = new GameObject;
|
|
if (linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
|
|
m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
|
|
{
|
|
linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0);
|
|
linkedGO->SetSpellId(m_spellInfo->Id);
|
|
|
|
// Wild object not have owner and check clickable by players
|
|
map->Add(linkedGO);
|
|
}
|
|
else
|
|
{
|
|
delete linkedGO;
|
|
linkedGO = NULL;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Spell::EffectScriptEffect(uint32 effIndex)
|
|
{
|
|
// TODO: we must implement hunter pet summon at login there (spell 6962)
|
|
|
|
switch(m_spellInfo->SpellFamilyName)
|
|
{
|
|
case SPELLFAMILY_GENERIC:
|
|
{
|
|
switch(m_spellInfo->Id)
|
|
{
|
|
case 6962:
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player* plr = m_caster->ToPlayer();
|
|
if (plr && plr->GetLastPetNumber())
|
|
{
|
|
PetType NewPetType = (plr->getClass() == CLASS_HUNTER) ? HUNTER_PET : SUMMON_PET;
|
|
if (Pet* NewPet = new Pet(plr,NewPetType))
|
|
{
|
|
if (NewPet->LoadPetFromDB(plr, 0, plr->GetLastPetNumber(), true))
|
|
{
|
|
NewPet->SetHealth(NewPet->GetMaxHealth());
|
|
NewPet->SetPower(NewPet->getPowerType(),NewPet->GetMaxPower(NewPet->getPowerType()));
|
|
|
|
switch (NewPet->GetEntry())
|
|
{
|
|
case 11859:
|
|
case 89:
|
|
NewPet->SetEntry(416);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
delete NewPet;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
// Glyph of Starfire
|
|
case 54846:
|
|
{
|
|
if (AuraEffect const * aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE,SPELLFAMILY_DRUID,0x00000002,0,0,m_caster->GetGUID()))
|
|
{
|
|
uint32 countMin = aurEff->GetBase()->GetMaxDuration();
|
|
uint32 countMax = 18000;
|
|
countMax += m_caster->HasAura(38414) ? 3000 : 0;
|
|
countMax += m_caster->HasAura(57865) ? 3000 : 0;
|
|
|
|
if (countMin < countMax)
|
|
{
|
|
aurEff->GetBase()->SetDuration(uint32(aurEff->GetBase()->GetDuration()+3000));
|
|
aurEff->GetBase()->SetMaxDuration(countMin+3000);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
// Glyph of Backstab
|
|
case 63975:
|
|
{
|
|
if (AuraEffect const * aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE,SPELLFAMILY_ROGUE,0x00100000,0,0,m_caster->GetGUID()))
|
|
{
|
|
uint32 countMin = aurEff->GetBase()->GetMaxDuration();
|
|
uint32 countMax = 12000;
|
|
countMax += m_caster->HasAura(56801) ? 4000 : 0;
|
|
|
|
if (countMin < countMax)
|
|
{
|
|
aurEff->GetBase()->SetDuration(uint32(aurEff->GetBase()->GetDuration()+3000));
|
|
aurEff->GetBase()->SetMaxDuration(countMin+2000);
|
|
}
|
|
|
|
}
|
|
return;
|
|
}
|
|
// Dispelling Analysis
|
|
case 37028:
|
|
{
|
|
unitTarget->RemoveAurasDueToSpell(36904);
|
|
return;
|
|
}
|
|
case 45204: // Clone Me!
|
|
case 41055: // Copy Weapon
|
|
case 45206: // Copy Off-hand Weapon
|
|
unitTarget->CastSpell(m_caster, damage, false);
|
|
break;
|
|
case 45205: // Copy Offhand Weapon
|
|
case 41054: // Copy Weapon
|
|
m_caster->CastSpell(unitTarget, damage, false);
|
|
break;
|
|
// Despawn Horse
|
|
case 52267:
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
|
|
return;
|
|
unitTarget->ToCreature()->ForcedDespawn();
|
|
return;
|
|
}
|
|
case 55693: // Remove Collapsing Cave Aura
|
|
if (!unitTarget)
|
|
return;
|
|
unitTarget->RemoveAurasDueToSpell(SpellMgr::CalculateSpellEffectAmount(m_spellInfo, effIndex));
|
|
break;
|
|
// PX-238 Winter Wondervolt TRAP
|
|
case 26275:
|
|
{
|
|
uint32 spells[4] = { 26272, 26157, 26273, 26274 };
|
|
|
|
// check presence
|
|
for (uint8 j = 0; j < 4; ++j)
|
|
if (unitTarget->HasAuraEffect(spells[j],0))
|
|
return;
|
|
|
|
// select spell
|
|
uint32 iTmpSpellId = spells[urand(0,3)];
|
|
|
|
// cast
|
|
unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
|
|
return;
|
|
}
|
|
// Bending Shinbone
|
|
case 8856:
|
|
{
|
|
if (!itemTarget && m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
uint32 spell_id = 0;
|
|
switch(urand(1, 5))
|
|
{
|
|
case 1: spell_id = 8854; break;
|
|
default: spell_id = 8855; break;
|
|
}
|
|
|
|
m_caster->CastSpell(m_caster,spell_id,true,NULL);
|
|
return;
|
|
}
|
|
// Brittle Armor - need remove one 24575 Brittle Armor aura
|
|
case 24590:
|
|
unitTarget->RemoveAuraFromStack(24575);
|
|
return;
|
|
// Mercurial Shield - need remove one 26464 Mercurial Shield aura
|
|
case 26465:
|
|
unitTarget->RemoveAuraFromStack(26464);
|
|
return;
|
|
// Orb teleport spells
|
|
case 25140:
|
|
case 25143:
|
|
case 25650:
|
|
case 25652:
|
|
case 29128:
|
|
case 29129:
|
|
case 35376:
|
|
case 35727:
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
uint32 spellid;
|
|
switch(m_spellInfo->Id)
|
|
{
|
|
case 25140: spellid = 32571; break;
|
|
case 25143: spellid = 32572; break;
|
|
case 25650: spellid = 30140; break;
|
|
case 25652: spellid = 30141; break;
|
|
case 29128: spellid = 32568; break;
|
|
case 29129: spellid = 32569; break;
|
|
case 35376: spellid = 25649; break;
|
|
case 35727: spellid = 35730; break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
unitTarget->CastSpell(unitTarget,spellid,false);
|
|
return;
|
|
}
|
|
// Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
|
|
case 22539:
|
|
case 22972:
|
|
case 22975:
|
|
case 22976:
|
|
case 22977:
|
|
case 22978:
|
|
case 22979:
|
|
case 22980:
|
|
case 22981:
|
|
case 22982:
|
|
case 22983:
|
|
case 22984:
|
|
case 22985:
|
|
{
|
|
if (!unitTarget || !unitTarget->isAlive())
|
|
return;
|
|
|
|
// Onyxia Scale Cloak
|
|
if (unitTarget->HasAura(22683))
|
|
return;
|
|
|
|
// Shadow Flame
|
|
m_caster->CastSpell(unitTarget, 22682, true);
|
|
return;
|
|
}
|
|
// Piccolo of the Flaming Fire
|
|
case 17512:
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
|
|
return;
|
|
}
|
|
// Escape artist
|
|
case 20589:
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
unitTarget->RemoveMovementImpairingAuras();
|
|
return;
|
|
}
|
|
// Decimate
|
|
case 28374:
|
|
case 54426:
|
|
if (unitTarget)
|
|
{
|
|
int32 damage = (int32)unitTarget->GetHealth() - (int32)unitTarget->GetMaxHealth() * 0.05f;
|
|
if (damage > 0)
|
|
m_caster->CastCustomSpell(28375, SPELLVALUE_BASE_POINT0, damage, unitTarget);
|
|
}
|
|
return;
|
|
// Mirren's Drinking Hat
|
|
case 29830:
|
|
{
|
|
uint32 item = 0;
|
|
switch (urand(1, 6))
|
|
{
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
item = 23584; break; // Loch Modan Lager
|
|
case 4:
|
|
case 5:
|
|
item = 23585; break; // Stouthammer Lite
|
|
case 6:
|
|
item = 23586; break; // Aerie Peak Pale Ale
|
|
}
|
|
if (item)
|
|
DoCreateItem(effIndex,item);
|
|
break;
|
|
}
|
|
// Improved Sprint
|
|
case 30918:
|
|
{
|
|
// Removes snares and roots.
|
|
unitTarget->RemoveMovementImpairingAuras();
|
|
break;
|
|
}
|
|
// Spirit Walk
|
|
case 58876:
|
|
{
|
|
// Removes snares and roots.
|
|
unitTarget->RemoveMovementImpairingAuras();
|
|
break;
|
|
}
|
|
// Plant Warmaul Ogre Banner
|
|
case 32307:
|
|
{
|
|
Player *p_caster = dynamic_cast<Player*>(m_caster);
|
|
if (!p_caster)
|
|
break;
|
|
p_caster->RewardPlayerAndGroupAtEvent(18388, unitTarget);
|
|
Creature *cTarget = dynamic_cast<Creature*>(unitTarget);
|
|
if (!cTarget)
|
|
break;
|
|
cTarget->setDeathState(CORPSE);
|
|
cTarget->RemoveCorpse();
|
|
break;
|
|
}
|
|
// Tidal Surge
|
|
case 38358:
|
|
if (unitTarget)
|
|
m_caster->CastSpell(unitTarget, 38353, true);
|
|
return;
|
|
/*// Flame Crash
|
|
case 41126:
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
unitTarget->CastSpell(unitTarget, 41131, true);
|
|
break;
|
|
}*/
|
|
// Draw Soul
|
|
case 40904:
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
unitTarget->CastSpell(m_caster, 40903, true);
|
|
break;
|
|
}
|
|
case 48025: // Headless Horseman's Mount
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// Prevent stacking of mounts and client crashes upon dismounting
|
|
unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
|
|
|
// Triggered spell id dependent on riding skill and zone
|
|
bool canFly = true;
|
|
uint32 v_map = GetVirtualMapForMapAndZone(unitTarget->GetMapId(), unitTarget->GetZoneId());
|
|
if (v_map != 530 && v_map != 571)
|
|
canFly = false;
|
|
|
|
if (canFly && v_map == 571 && !unitTarget->ToPlayer()->HasSpell(54197))
|
|
canFly = false;
|
|
|
|
float x, y, z;
|
|
unitTarget->GetPosition(x, y, z);
|
|
uint32 areaFlag = unitTarget->GetBaseMap()->GetAreaFlag(x, y, z);
|
|
AreaTableEntry const *pArea = sAreaStore.LookupEntry(areaFlag);
|
|
if (canFly && pArea->flags & AREA_FLAG_NO_FLY_ZONE)
|
|
canFly = false;
|
|
|
|
switch(unitTarget->ToPlayer()->GetBaseSkillValue(SKILL_RIDING))
|
|
{
|
|
case 75: unitTarget->CastSpell(unitTarget, 51621, true); break;
|
|
case 150: unitTarget->CastSpell(unitTarget, 48024, true); break;
|
|
case 225:
|
|
{
|
|
if (canFly)
|
|
unitTarget->CastSpell(unitTarget, 51617, true);
|
|
else
|
|
unitTarget->CastSpell(unitTarget, 48024, true);
|
|
}break;
|
|
case 300:
|
|
{
|
|
if (canFly)
|
|
unitTarget->CastSpell(unitTarget, 48023, true);
|
|
else
|
|
unitTarget->CastSpell(unitTarget, 48024, true);
|
|
}break;
|
|
}
|
|
return;
|
|
}
|
|
case 47977: // Magic Broom
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// Prevent stacking of mounts and client crashes upon dismounting
|
|
unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
|
|
|
// Triggered spell id dependent on riding skill and zone
|
|
bool canFly = true;
|
|
uint32 v_map = GetVirtualMapForMapAndZone(unitTarget->GetMapId(), unitTarget->GetZoneId());
|
|
if (v_map != 530 && v_map != 571)
|
|
canFly = false;
|
|
|
|
if (canFly && v_map == 571 && !unitTarget->ToPlayer()->HasSpell(54197))
|
|
canFly = false;
|
|
|
|
float x, y, z;
|
|
unitTarget->GetPosition(x, y, z);
|
|
uint32 areaFlag = unitTarget->GetBaseMap()->GetAreaFlag(x, y, z);
|
|
AreaTableEntry const *pArea = sAreaStore.LookupEntry(areaFlag);
|
|
if (canFly && pArea->flags & AREA_FLAG_NO_FLY_ZONE)
|
|
canFly = false;
|
|
|
|
switch(unitTarget->ToPlayer()->GetBaseSkillValue(SKILL_RIDING))
|
|
{
|
|
case 75: unitTarget->CastSpell(unitTarget, 42680, true); break;
|
|
case 150: unitTarget->CastSpell(unitTarget, 42683, true); break;
|
|
case 225:
|
|
{
|
|
if (canFly)
|
|
unitTarget->CastSpell(unitTarget, 42667, true);
|
|
else
|
|
unitTarget->CastSpell(unitTarget, 42683, true);
|
|
}break;
|
|
case 300:
|
|
{
|
|
if (canFly)
|
|
unitTarget->CastSpell(unitTarget, 42668, true);
|
|
else
|
|
unitTarget->CastSpell(unitTarget, 42683, true);
|
|
}break;
|
|
}
|
|
return;
|
|
}
|
|
// Mug Transformation
|
|
case 41931:
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
uint8 bag = 19;
|
|
uint8 slot = 0;
|
|
Item *item = NULL;
|
|
|
|
while (bag < 256)
|
|
{
|
|
item = m_caster->ToPlayer()->GetItemByPos(bag, slot);
|
|
if (item && item->GetEntry() == 38587) break;
|
|
++slot;
|
|
if (slot == 39)
|
|
{
|
|
slot = 0;
|
|
++bag;
|
|
}
|
|
}
|
|
if (bag < 256)
|
|
{
|
|
if (m_caster->ToPlayer()->GetItemByPos(bag,slot)->GetCount() == 1) m_caster->ToPlayer()->RemoveItem(bag,slot,true);
|
|
else m_caster->ToPlayer()->GetItemByPos(bag,slot)->SetCount(m_caster->ToPlayer()->GetItemByPos(bag,slot)->GetCount()-1);
|
|
// Spell 42518 (Braufest - Gratisprobe des Braufest herstellen)
|
|
m_caster->CastSpell(m_caster, 42518, true);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
// Force Cast - Portal Effect: Sunwell Isle
|
|
case 44876:
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
unitTarget->CastSpell(unitTarget, 44870, true);
|
|
break;
|
|
}
|
|
// Brutallus - Burn
|
|
case 45141:
|
|
case 45151:
|
|
{
|
|
//Workaround for Range ... should be global for every ScriptEffect
|
|
float radius = GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex]));
|
|
if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->GetDistance(m_caster) >= radius && !unitTarget->HasAura(46394) && unitTarget != m_caster)
|
|
unitTarget->CastSpell(unitTarget, 46394, true);
|
|
|
|
break;
|
|
}
|
|
// spell of Brutallus - Stomp
|
|
case 45185:
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
unitTarget->RemoveAurasDueToSpell(46394);
|
|
|
|
break;
|
|
}
|
|
// Negative Energy
|
|
case 46289:
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
m_caster->CastSpell(unitTarget, 46285, true);
|
|
break;
|
|
}
|
|
// Goblin Weather Machine
|
|
case 46203:
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
uint32 spellId = 0;
|
|
switch(rand() % 4)
|
|
{
|
|
case 0: spellId = 46740; break;
|
|
case 1: spellId = 46739; break;
|
|
case 2: spellId = 46738; break;
|
|
case 3: spellId = 46736; break;
|
|
}
|
|
unitTarget->CastSpell(unitTarget, spellId, true);
|
|
break;
|
|
}
|
|
// 5,000 Gold
|
|
case 46642:
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
unitTarget->ToPlayer()->ModifyMoney(5000 * GOLD);
|
|
|
|
break;
|
|
}
|
|
// Roll Dice - Decahedral Dwarven Dice
|
|
case 47770:
|
|
{
|
|
char buf[128];
|
|
char *gender = "his";
|
|
if (m_caster->getGender() > 0)
|
|
gender = "her";
|
|
sprintf(buf, "%s rubs %s [Decahedral Dwarven Dice] between %s hands and rolls. One %u and one %u.", m_caster->GetName(), gender, gender, urand(1,10), urand(1,10));
|
|
m_caster->MonsterTextEmote(buf, 0);
|
|
break;
|
|
}
|
|
// Roll 'dem Bones - Worn Troll Dice
|
|
case 47776:
|
|
{
|
|
char buf[128];
|
|
char *gender = "his";
|
|
if (m_caster->getGender() > 0)
|
|
gender = "her";
|
|
sprintf(buf, "%s causually tosses %s [Worn Troll Dice]. One %u and one %u.", m_caster->GetName(), gender, urand(1,6), urand(1,6));
|
|
m_caster->MonsterTextEmote(buf, 0);
|
|
break;
|
|
}
|
|
// Vigilance
|
|
case 50725:
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// Remove Taunt cooldown
|
|
unitTarget->ToPlayer()->RemoveSpellCooldown(355, true);
|
|
|
|
return;
|
|
}
|
|
// Death Knight Initiate Visual
|
|
case 51519:
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
|
|
return;
|
|
|
|
uint32 iTmpSpellId = 0;
|
|
switch (unitTarget->GetDisplayId())
|
|
{
|
|
case 25369: iTmpSpellId = 51552; break; // bloodelf female
|
|
case 25373: iTmpSpellId = 51551; break; // bloodelf male
|
|
case 25363: iTmpSpellId = 51542; break; // draenei female
|
|
case 25357: iTmpSpellId = 51541; break; // draenei male
|
|
case 25361: iTmpSpellId = 51537; break; // dwarf female
|
|
case 25356: iTmpSpellId = 51538; break; // dwarf male
|
|
case 25372: iTmpSpellId = 51550; break; // forsaken female
|
|
case 25367: iTmpSpellId = 51549; break; // forsaken male
|
|
case 25362: iTmpSpellId = 51540; break; // gnome female
|
|
case 25359: iTmpSpellId = 51539; break; // gnome male
|
|
case 25355: iTmpSpellId = 51534; break; // human female
|
|
case 25354: iTmpSpellId = 51520; break; // human male
|
|
case 25360: iTmpSpellId = 51536; break; // nightelf female
|
|
case 25358: iTmpSpellId = 51535; break; // nightelf male
|
|
case 25368: iTmpSpellId = 51544; break; // orc female
|
|
case 25364: iTmpSpellId = 51543; break; // orc male
|
|
case 25371: iTmpSpellId = 51548; break; // tauren female
|
|
case 25366: iTmpSpellId = 51547; break; // tauren male
|
|
case 25370: iTmpSpellId = 51545; break; // troll female
|
|
case 25365: iTmpSpellId = 51546; break; // troll male
|
|
default: return;
|
|
}
|
|
|
|
unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
|
|
Creature* npc = unitTarget->ToCreature();
|
|
npc->LoadEquipment(npc->GetEquipmentId());
|
|
return;
|
|
}
|
|
// Emblazon Runeblade
|
|
case 51770:
|
|
{
|
|
if (!m_originalCaster)
|
|
return;
|
|
|
|
m_originalCaster->CastSpell(m_originalCaster, damage, false);
|
|
break;
|
|
}
|
|
// Deathbolt from Thalgran Blightbringer
|
|
// reflected by Freya's Ward
|
|
// Retribution by Sevenfold Retribution
|
|
case 51854:
|
|
{
|
|
if (!m_caster || !unitTarget)
|
|
return;
|
|
if (unitTarget->HasAura(51845))
|
|
unitTarget->CastSpell(m_caster, 51856, true);
|
|
else
|
|
m_caster->CastSpell(unitTarget, 51855, true);
|
|
break;
|
|
}
|
|
// Summon Ghouls On Scarlet Crusade
|
|
case 51904:
|
|
{
|
|
if (!m_targets.HasDst())
|
|
return;
|
|
|
|
float x, y, z;
|
|
float radius = GetSpellRadius(m_spellInfo, effIndex, true);
|
|
for (uint8 i = 0; i < 15; ++i)
|
|
{
|
|
m_caster->GetRandomPoint(m_targets.m_dstPos, radius, x, y, z);
|
|
m_caster->CastSpell(x, y, z, 54522, true);
|
|
}
|
|
break;
|
|
}
|
|
case 52173: // Coyote Spirit Despawn
|
|
case 60243: // Blood Parrot Despawn
|
|
if (unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->ToCreature()->isSummon())
|
|
unitTarget->ToTempSummon()->UnSummon();
|
|
return;
|
|
// Sky Darkener Assault
|
|
case 52124:
|
|
if (unitTarget)
|
|
m_caster->CastSpell(unitTarget, 52125, false);
|
|
return;
|
|
case 52479: // Gift of the Harvester
|
|
if (unitTarget && m_originalCaster)
|
|
m_originalCaster->CastSpell(unitTarget, urand(0, 1) ? damage : 52505, true);
|
|
return;
|
|
// Death Gate
|
|
case 52751:
|
|
{
|
|
if (!unitTarget || unitTarget->getClass() != CLASS_DEATH_KNIGHT)
|
|
return;
|
|
// triggered spell is stored in m_spellInfo->EffectBasePoints[0]
|
|
unitTarget->CastSpell(unitTarget, damage, false);
|
|
break;
|
|
}
|
|
case 53110: // Devour Humanoid
|
|
if (unitTarget)
|
|
unitTarget->CastSpell(m_caster, damage, true);
|
|
return;
|
|
// Winged Steed of the Ebon Blade
|
|
case 54729:
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// Prevent stacking of mounts and client crashes upon dismounting
|
|
unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
|
|
|
// Triggered spell id dependent on riding skill
|
|
if (uint16 skillval = unitTarget->ToPlayer()->GetSkillValue(SKILL_RIDING))
|
|
{
|
|
if (skillval >= 300)
|
|
unitTarget->CastSpell(unitTarget, 54727, true);
|
|
else
|
|
unitTarget->CastSpell(unitTarget, 54726, true);
|
|
}
|
|
return;
|
|
}
|
|
case 58418: // Portal to Orgrimmar
|
|
case 58420: // Portal to Stormwind
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || effIndex != 0)
|
|
return;
|
|
|
|
uint32 spellID = SpellMgr::CalculateSpellEffectAmount(m_spellInfo, 0);
|
|
uint32 questID = SpellMgr::CalculateSpellEffectAmount(m_spellInfo, 1);
|
|
|
|
if (unitTarget->ToPlayer()->GetQuestStatus(questID) == QUEST_STATUS_COMPLETE && !unitTarget->ToPlayer()->GetQuestRewardStatus (questID))
|
|
unitTarget->CastSpell(unitTarget, spellID, true);
|
|
|
|
return;
|
|
}
|
|
// Gigantic Feast
|
|
case 58466:
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
unitTarget->CastSpell(unitTarget, 58648, true);
|
|
unitTarget->CastSpell(unitTarget, 58467, true);
|
|
break;
|
|
}
|
|
// Small Feast
|
|
case 58475:
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
unitTarget->CastSpell(unitTarget, 58648, true);
|
|
unitTarget->CastSpell(unitTarget, 58477, true);
|
|
break;
|
|
}
|
|
// Great Feast
|
|
case 57337:
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
unitTarget->CastSpell(unitTarget, 58067, true);
|
|
break;
|
|
}
|
|
//Fish Feast
|
|
case 57397:
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
unitTarget->CastSpell(unitTarget, 58648, true);
|
|
unitTarget->CastSpell(unitTarget, 57398, true);
|
|
break;
|
|
}
|
|
case 58941: // Rock Shards
|
|
if (unitTarget && m_originalCaster)
|
|
{
|
|
for (uint32 i = 0; i < 3; ++i)
|
|
{
|
|
m_originalCaster->CastSpell(unitTarget, 58689, true);
|
|
m_originalCaster->CastSpell(unitTarget, 58692, true);
|
|
}
|
|
if (((InstanceMap*)m_originalCaster->GetMap())->GetDifficulty() == REGULAR_DIFFICULTY)
|
|
{
|
|
m_originalCaster->CastSpell(unitTarget, 58695, true);
|
|
m_originalCaster->CastSpell(unitTarget, 58696, true);
|
|
}
|
|
else
|
|
{
|
|
m_originalCaster->CastSpell(unitTarget, 60883, true);
|
|
m_originalCaster->CastSpell(unitTarget, 60884, true);
|
|
}
|
|
}
|
|
return;
|
|
case 58983: // Big Blizzard Bear
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// Prevent stacking of mounts and client crashes upon dismounting
|
|
unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
|
|
|
// Triggered spell id dependent on riding skill
|
|
if (uint16 skillval = unitTarget->ToPlayer()->GetSkillValue(SKILL_RIDING))
|
|
{
|
|
if (skillval >= 150)
|
|
unitTarget->CastSpell(unitTarget, 58999, true);
|
|
else
|
|
unitTarget->CastSpell(unitTarget, 58997, true);
|
|
}
|
|
return;
|
|
}
|
|
case 71342: // Big Love Rocket
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// Prevent stacking of mounts and client crashes upon dismounting
|
|
unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
|
|
|
// Triggered spell id dependent on riding skill and zone
|
|
bool canFly = true;
|
|
uint32 v_map = GetVirtualMapForMapAndZone(unitTarget->GetMapId(), unitTarget->GetZoneId());
|
|
if (v_map != 530 && v_map != 571)
|
|
canFly = false;
|
|
|
|
if (canFly && v_map == 571 && !unitTarget->ToPlayer()->HasSpell(54197))
|
|
canFly = false;
|
|
|
|
float x, y, z;
|
|
unitTarget->GetPosition(x, y, z);
|
|
uint32 areaFlag = unitTarget->GetBaseMap()->GetAreaFlag(x, y, z);
|
|
AreaTableEntry const *pArea = sAreaStore.LookupEntry(areaFlag);
|
|
if (canFly && pArea->flags & AREA_FLAG_NO_FLY_ZONE)
|
|
canFly = false;
|
|
|
|
switch(unitTarget->ToPlayer()->GetBaseSkillValue(SKILL_RIDING))
|
|
{
|
|
case 0: unitTarget->CastSpell(unitTarget, 71343, true); break;
|
|
case 75: unitTarget->CastSpell(unitTarget, 71344, true); break;
|
|
case 150: unitTarget->CastSpell(unitTarget, 71345, true); break;
|
|
case 225:
|
|
{
|
|
if (canFly)
|
|
unitTarget->CastSpell(unitTarget, 71346, true);
|
|
else
|
|
unitTarget->CastSpell(unitTarget, 71345, true);
|
|
}break;
|
|
case 300:
|
|
{
|
|
if (canFly)
|
|
unitTarget->CastSpell(unitTarget, 71347, true);
|
|
else
|
|
unitTarget->CastSpell(unitTarget, 71345, true);
|
|
}break;
|
|
}
|
|
return;
|
|
}
|
|
case 72286: // Invincible
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// Prevent stacking of mounts and client crashes upon dismounting
|
|
unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
|
|
|
// Triggered spell id dependent on riding skill and zone
|
|
bool canFly = true;
|
|
uint32 v_map = GetVirtualMapForMapAndZone(unitTarget->GetMapId(), unitTarget->GetZoneId());
|
|
if (v_map != 530 && v_map != 571)
|
|
canFly = false;
|
|
|
|
if (canFly && v_map == 571 && !unitTarget->ToPlayer()->HasSpell(54197))
|
|
canFly = false;
|
|
|
|
float x, y, z;
|
|
unitTarget->GetPosition(x, y, z);
|
|
uint32 areaFlag = unitTarget->GetBaseMap()->GetAreaFlag(x, y, z);
|
|
AreaTableEntry const *pArea = sAreaStore.LookupEntry(areaFlag);
|
|
if (canFly && pArea->flags & AREA_FLAG_NO_FLY_ZONE)
|
|
canFly = false;
|
|
|
|
switch(unitTarget->ToPlayer()->GetBaseSkillValue(SKILL_RIDING))
|
|
{
|
|
case 75: unitTarget->CastSpell(unitTarget, 72281, true); break;
|
|
case 150: unitTarget->CastSpell(unitTarget, 72282, true); break;
|
|
case 225:
|
|
{
|
|
if (canFly)
|
|
unitTarget->CastSpell(unitTarget, 72283, true);
|
|
else
|
|
unitTarget->CastSpell(unitTarget, 72282, true);
|
|
}break;
|
|
case 300:
|
|
{
|
|
if (canFly)
|
|
unitTarget->CastSpell(unitTarget, 72284, true);
|
|
else
|
|
unitTarget->CastSpell(unitTarget, 72282, true);
|
|
}break;
|
|
}
|
|
return;
|
|
}
|
|
case 74856: // Blazing Hippogryph
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// Prevent stacking of mounts and client crashes upon dismounting
|
|
unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
|
|
|
// Triggered spell id dependent on riding skill
|
|
if (uint16 skillval = unitTarget->ToPlayer()->GetSkillValue(SKILL_RIDING))
|
|
{
|
|
if (skillval >= 300)
|
|
unitTarget->CastSpell(unitTarget, 74855, true);
|
|
else
|
|
unitTarget->CastSpell(unitTarget, 74854, true);
|
|
}
|
|
return;
|
|
}
|
|
case 75614: // Celestial Steed
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// Prevent stacking of mounts and client crashes upon dismounting
|
|
unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
|
|
|
// Triggered spell id dependent on riding skill and zone
|
|
bool canFly = true;
|
|
uint32 v_map = GetVirtualMapForMapAndZone(unitTarget->GetMapId(), unitTarget->GetZoneId());
|
|
if (v_map != 530 && v_map != 571)
|
|
canFly = false;
|
|
|
|
if (canFly && v_map == 571 && !unitTarget->ToPlayer()->HasSpell(54197))
|
|
canFly = false;
|
|
|
|
float x, y, z;
|
|
unitTarget->GetPosition(x, y, z);
|
|
uint32 areaFlag = unitTarget->GetBaseMap()->GetAreaFlag(x, y, z);
|
|
AreaTableEntry const *pArea = sAreaStore.LookupEntry(areaFlag);
|
|
if (canFly && pArea->flags & AREA_FLAG_NO_FLY_ZONE)
|
|
canFly = false;
|
|
|
|
switch(unitTarget->ToPlayer()->GetBaseSkillValue(SKILL_RIDING))
|
|
{
|
|
case 75: unitTarget->CastSpell(unitTarget, 75619, true); break;
|
|
case 150: unitTarget->CastSpell(unitTarget, 75620, true); break;
|
|
case 225:
|
|
{
|
|
if (canFly)
|
|
unitTarget->CastSpell(unitTarget, 75617, true);
|
|
else
|
|
unitTarget->CastSpell(unitTarget, 75620, true);
|
|
}break;
|
|
case 300:
|
|
{
|
|
if (canFly)
|
|
{
|
|
if (unitTarget->ToPlayer()->Has310Flyer(false))
|
|
unitTarget->CastSpell(unitTarget, 76153, true);
|
|
else
|
|
unitTarget->CastSpell(unitTarget, 75618, true);
|
|
}
|
|
else
|
|
unitTarget->CastSpell(unitTarget, 75620, true);
|
|
}break;
|
|
}
|
|
return;
|
|
}
|
|
case 75973: // X-53 Touring Rocket
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// Prevent stacking of mounts
|
|
unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
|
|
|
// Triggered spell id dependent on riding skill
|
|
if (uint16 skillval = unitTarget->ToPlayer()->GetSkillValue(SKILL_RIDING))
|
|
{
|
|
if (skillval >= 300)
|
|
{
|
|
if (unitTarget->ToPlayer()->Has310Flyer(false))
|
|
unitTarget->CastSpell(unitTarget, 76154, true);
|
|
else
|
|
unitTarget->CastSpell(unitTarget, 75972, true);
|
|
}
|
|
else
|
|
unitTarget->CastSpell(unitTarget, 75957, true);
|
|
}
|
|
return;
|
|
}
|
|
case 59317: // Teleporting
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// return from top
|
|
if (unitTarget->ToPlayer()->GetAreaId() == 4637)
|
|
unitTarget->CastSpell(unitTarget, 59316, true);
|
|
// teleport atop
|
|
else
|
|
unitTarget->CastSpell(unitTarget, 59314, true);
|
|
|
|
return;
|
|
// random spell learn instead placeholder
|
|
case 60893: // Northrend Alchemy Research
|
|
case 61177: // Northrend Inscription Research
|
|
case 61288: // Minor Inscription Research
|
|
case 61756: // Northrend Inscription Research (FAST QA VERSION)
|
|
case 64323: // Book of Glyph Mastery
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// learn random explicit discovery recipe (if any)
|
|
if (uint32 discoveredSpell = GetExplicitDiscoverySpell(m_spellInfo->Id, (Player*)m_caster))
|
|
m_caster->ToPlayer()->learnSpell(discoveredSpell, false);
|
|
return;
|
|
}
|
|
case 62428: // Load into Catapult
|
|
{
|
|
if (Vehicle *seat = m_caster->GetVehicleKit())
|
|
if (Unit *passenger = seat->GetPassenger(0))
|
|
if (Unit *demolisher = m_caster->GetVehicleBase())
|
|
passenger->CastSpell(demolisher, damage, true);
|
|
return;
|
|
}
|
|
case 62482: // Grab Crate
|
|
{
|
|
if (unitTarget)
|
|
{
|
|
if (Vehicle *seat = m_caster->GetVehicleKit())
|
|
{
|
|
if (Creature *oldContainer = dynamic_cast<Creature*>(seat->GetPassenger(1)))
|
|
oldContainer->DisappearAndDie();
|
|
// TODO: a hack, range = 11, should after some time cast, otherwise too far
|
|
unitTarget->CastSpell(seat->GetBase(), 62496, true);
|
|
unitTarget->EnterVehicle(seat, 1);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
case 60123: // Lightwell
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_UNIT || !m_caster->ToCreature()->isSummon())
|
|
return;
|
|
|
|
uint32 spell_heal;
|
|
|
|
switch(m_caster->GetEntry())
|
|
{
|
|
case 31897: spell_heal = 7001; break;
|
|
case 31896: spell_heal = 27873; break;
|
|
case 31895: spell_heal = 27874; break;
|
|
case 31894: spell_heal = 28276; break;
|
|
case 31893: spell_heal = 48084; break;
|
|
case 31883: spell_heal = 48085; break;
|
|
default:
|
|
sLog.outError("Unknown Lightwell spell caster %u", m_caster->GetEntry());
|
|
return;
|
|
}
|
|
Aura * chargesaura = m_caster->GetAura(59907);
|
|
|
|
if (chargesaura && chargesaura->GetCharges() > 1)
|
|
{
|
|
chargesaura->SetCharges(chargesaura->GetCharges() - 1);
|
|
m_caster->CastSpell(unitTarget, spell_heal, true, NULL, NULL, m_caster->ToTempSummon()->GetSummonerGUID());
|
|
}
|
|
else
|
|
m_caster->ToTempSummon()->UnSummon();
|
|
return;
|
|
}
|
|
// Stoneclaw Totem
|
|
case 55328: // Rank 1
|
|
case 55329: // Rank 2
|
|
case 55330: // Rank 3
|
|
case 55332: // Rank 4
|
|
case 55333: // Rank 5
|
|
case 55335: // Rank 6
|
|
case 55278: // Rank 7
|
|
case 58589: // Rank 8
|
|
case 58590: // Rank 9
|
|
case 58591: // Rank 10
|
|
{
|
|
int32 basepoints0 = damage;
|
|
// Cast Absorb on totems
|
|
for (uint8 slot = SUMMON_SLOT_TOTEM; slot < MAX_TOTEM_SLOT; ++slot)
|
|
{
|
|
if (!unitTarget->m_SummonSlot[slot])
|
|
continue;
|
|
|
|
Creature* totem = unitTarget->GetMap()->GetCreature(unitTarget->m_SummonSlot[slot]);
|
|
if (totem && totem->isTotem())
|
|
{
|
|
m_caster->CastCustomSpell(totem, 55277, &basepoints0, NULL, NULL, true);
|
|
}
|
|
}
|
|
// Glyph of Stoneclaw Totem
|
|
if (AuraEffect *aur=unitTarget->GetAuraEffect(63298, 0))
|
|
{
|
|
basepoints0 *= aur->GetAmount();
|
|
m_caster->CastCustomSpell(unitTarget, 55277, &basepoints0, NULL, NULL, true);
|
|
}
|
|
break;
|
|
}
|
|
case 67751:// Ghoul Explode
|
|
{
|
|
unitTarget->CastSpell(unitTarget,67729,false); //Explode
|
|
break;
|
|
}
|
|
case 66545: //Summon Memory
|
|
{
|
|
uint8 uiRandom = urand(0,25);
|
|
uint32 uiSpells[26] = {66704,66705,66706,66707,66709,66710,66711,66712,66713,66714,66715,66708,66708,66691,66692,66694,66695,66696,66697,66698,66699,66700,66701,66702,66703,66543};
|
|
|
|
m_caster->CastSpell(m_caster,uiSpells[uiRandom],true);
|
|
break;
|
|
}
|
|
case 45668: // Ultra-Advanced Proto-Typical Shortening Blaster
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
|
|
return;
|
|
|
|
if (roll_chance_i(50)) // chance unknown, using 50
|
|
return;
|
|
|
|
static uint32 const spellPlayer[5] =
|
|
{
|
|
45674, // Bigger!
|
|
45675, // Shrunk
|
|
45678, // Yellow
|
|
45682, // Ghost
|
|
45684 // Polymorph
|
|
};
|
|
|
|
static uint32 const spellTarget[5] = {
|
|
45673, // Bigger!
|
|
45672, // Shrunk
|
|
45677, // Yellow
|
|
45681, // Ghost
|
|
45683 // Polymorph
|
|
};
|
|
|
|
m_caster->CastSpell(m_caster, spellPlayer[urand(0,4)], true);
|
|
unitTarget->CastSpell(unitTarget, spellTarget[urand(0,4)], true);
|
|
break;
|
|
}
|
|
case 64142: // Upper Deck - Create Foam Sword
|
|
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
Player *plr = unitTarget->ToPlayer();
|
|
static uint32 const itemId[] = {45061, 45176, 45177, 45178, 45179, 0};
|
|
// player can only have one of these items
|
|
for (uint32 const *itr = &itemId[0]; *itr; ++itr)
|
|
if (plr->HasItemCount(*itr, 1, true))
|
|
return;
|
|
DoCreateItem(effIndex, itemId[urand(0,4)]);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_WARLOCK:
|
|
{
|
|
switch(m_spellInfo->Id)
|
|
{
|
|
// Healthstone creating spells
|
|
case 6201:
|
|
case 6202:
|
|
case 5699:
|
|
case 11729:
|
|
case 11730:
|
|
case 27230:
|
|
case 47871:
|
|
case 47878:
|
|
{
|
|
uint32 itemtype;
|
|
uint32 rank = 0;
|
|
|
|
// Improved Healthstone
|
|
if (AuraEffect const * aurEff = unitTarget->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, 284, 0))
|
|
{
|
|
if (aurEff->GetId() == 18692)
|
|
rank = 1;
|
|
else if (aurEff->GetId() == 18693)
|
|
rank = 2;
|
|
else
|
|
sLog.outError("Unknown rank of Improved Healthstone id: %d", aurEff->GetId());
|
|
}
|
|
|
|
static uint32 const itypes[8][3] = {
|
|
{ 5512, 19004, 19005}, // Minor Healthstone
|
|
{ 5511, 19006, 19007}, // Lesser Healthstone
|
|
{ 5509, 19008, 19009}, // Healthstone
|
|
{ 5510, 19010, 19011}, // Greater Healthstone
|
|
{ 9421, 19012, 19013}, // Major Healthstone
|
|
{22103, 22104, 22105}, // Master Healthstone
|
|
{36889, 36890, 36891}, // Demonic Healthstone
|
|
{36892, 36893, 36894} // Fel Healthstone
|
|
};
|
|
|
|
switch(m_spellInfo->Id)
|
|
{
|
|
case 6201:
|
|
itemtype=itypes[0][rank];break; // Minor Healthstone
|
|
case 6202:
|
|
itemtype=itypes[1][rank];break; // Lesser Healthstone
|
|
case 5699:
|
|
itemtype=itypes[2][rank];break; // Healthstone
|
|
case 11729:
|
|
itemtype=itypes[3][rank];break; // Greater Healthstone
|
|
case 11730:
|
|
itemtype=itypes[4][rank];break; // Major Healthstone
|
|
case 27230:
|
|
itemtype=itypes[5][rank];break; // Master Healthstone
|
|
case 47871:
|
|
itemtype=itypes[6][rank];break; // Demonic Healthstone
|
|
case 47878:
|
|
itemtype=itypes[7][rank];break; // Fel Healthstone
|
|
default:
|
|
return;
|
|
}
|
|
DoCreateItem(effIndex, itemtype);
|
|
return;
|
|
}
|
|
// Everlasting Affliction
|
|
case 47422:
|
|
// Refresh corruption on target
|
|
if (AuraEffect * aur = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x2, 0, 0, m_caster->GetGUID()))
|
|
aur->GetBase()->RefreshDuration();
|
|
return;
|
|
// Demonic Empowerment
|
|
case 47193:
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || !unitTarget->ToCreature()->isPet())
|
|
return;
|
|
CreatureInfo const * ci = objmgr.GetCreatureTemplate(unitTarget->GetEntry());
|
|
switch (ci->family)
|
|
{
|
|
case CREATURE_FAMILY_SUCCUBUS:
|
|
unitTarget->CastSpell(unitTarget, 54435, true);
|
|
break;
|
|
case CREATURE_FAMILY_VOIDWALKER:
|
|
{
|
|
SpellEntry const* spellInfo = sSpellStore.LookupEntry(54443);
|
|
int32 hp = unitTarget->GetMaxHealth() * m_caster->CalculateSpellDamage(unitTarget, spellInfo, 0) /100;
|
|
unitTarget->CastCustomSpell(unitTarget, 54443,&hp, NULL, NULL,true);
|
|
//unitTarget->CastSpell(unitTarget, 54441, true);
|
|
break;
|
|
}
|
|
case CREATURE_FAMILY_FELGUARD:
|
|
unitTarget->CastSpell(unitTarget, 54508, true);
|
|
break;
|
|
case CREATURE_FAMILY_FELHUNTER:
|
|
unitTarget->CastSpell(unitTarget, 54509, true);
|
|
break;
|
|
case CREATURE_FAMILY_IMP:
|
|
unitTarget->CastSpell(unitTarget, 54444, true);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
// Guarded by The Light
|
|
case 63521:
|
|
{
|
|
// Divine Plea
|
|
if (Aura * aura = m_caster->GetAura(54428))
|
|
aura->RefreshDuration();
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_HUNTER:
|
|
{
|
|
switch(m_spellInfo->Id)
|
|
{
|
|
// Invigoration
|
|
case 53412:
|
|
{
|
|
if (AuraEffect * aurEff = unitTarget->GetDummyAuraEffect(SPELLFAMILY_HUNTER, 3487, 0))
|
|
{
|
|
if (roll_chance_i(aurEff->GetAmount()))
|
|
unitTarget->CastSpell(unitTarget, 53398, true);
|
|
}
|
|
break;
|
|
}
|
|
// Heart of the Pheonix
|
|
case 55709:
|
|
{
|
|
int pct = 100;
|
|
if (unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->ToCreature()->isPet())
|
|
if (Unit* owner = unitTarget->ToCreature()->GetOwner())
|
|
owner->CastCustomSpell(unitTarget, 54114, &pct, NULL, NULL, true);
|
|
break;
|
|
}
|
|
// Chimera Shot
|
|
case 53209:
|
|
{
|
|
uint32 spellId = 0;
|
|
int32 basePoint = 0;
|
|
Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras();
|
|
for (Unit::AuraApplicationMap::iterator i = Auras.begin(); i != Auras.end(); ++i)
|
|
{
|
|
Aura * aura = (*i).second->GetBase();
|
|
if (aura->GetCasterGUID() != m_caster->GetGUID())
|
|
continue;
|
|
// Search only Serpent Sting, Viper Sting, Scorpid Sting auras
|
|
flag96 familyFlag = aura->GetSpellProto()->SpellFamilyFlags;
|
|
if (!(familyFlag[1] & 0x00000080 || familyFlag[0] & 0x0000C000))
|
|
continue;
|
|
if (AuraEffect const * aurEff = aura->GetEffect(0))
|
|
{
|
|
// Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting.
|
|
if (familyFlag[0] & 0x4000)
|
|
{
|
|
int32 TickCount = aurEff->GetTotalTicks();
|
|
spellId = 53353; // 53353 Chimera Shot - Serpent
|
|
basePoint = aurEff->GetAmount() * TickCount * 40 / 100;
|
|
}
|
|
// Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting.
|
|
else if (familyFlag[1] & 0x00000080)
|
|
{
|
|
int32 TickCount = aura->GetEffect(0)->GetTotalTicks();
|
|
spellId = 53358; // 53358 Chimera Shot - Viper
|
|
|
|
// Amount of one aura tick
|
|
basePoint = aurEff->GetAmount() * unitTarget->GetMaxPower(POWER_MANA) / 100 ;
|
|
int32 casterBasePoint = aurEff->GetAmount() * unitTarget->GetMaxPower(POWER_MANA) / 50 ;
|
|
if (basePoint > casterBasePoint)
|
|
basePoint = casterBasePoint;
|
|
basePoint = basePoint * TickCount * 60 / 100;
|
|
}
|
|
// Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute.
|
|
else if (familyFlag[0] & 0x00008000)
|
|
spellId = 53359; // 53359 Chimera Shot - Scorpid
|
|
// ?? nothing say in spell desc (possibly need addition check)
|
|
//if (familyFlag & 0x0000010000000000LL || // dot
|
|
// familyFlag & 0x0000100000000000LL) // stun
|
|
//{
|
|
// spellId = 53366; // 53366 Chimera Shot - Wyvern
|
|
//}
|
|
|
|
// Refresh aura duration
|
|
aura->RefreshDuration();
|
|
}
|
|
break;
|
|
}
|
|
if (spellId)
|
|
m_caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, false);
|
|
return;
|
|
}
|
|
// Master's Call
|
|
case 53271:
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
if (Pet *PlrPet = m_caster->ToPlayer()->GetPet())
|
|
m_caster->CastSpell(PlrPet, 62305, true);
|
|
return;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_PALADIN:
|
|
{
|
|
// Judgement (seal trigger)
|
|
if (m_spellInfo->Category == SPELLCATEGORY_JUDGEMENT)
|
|
{
|
|
if (!unitTarget || !unitTarget->isAlive())
|
|
return;
|
|
uint32 spellId1 = 0;
|
|
uint32 spellId2 = 0;
|
|
uint32 spellId3 = 0;
|
|
|
|
// Judgement self add switch
|
|
switch (m_spellInfo->Id)
|
|
{
|
|
case 53407: spellId1 = 20184; break; // Judgement of Justice
|
|
case 20271: // Judgement of Light
|
|
case 57774: spellId1 = 20185; break; // Judgement of Light
|
|
case 53408: spellId1 = 20186; break; // Judgement of Wisdom
|
|
default:
|
|
sLog.outError("Unsupported Judgement (seal trigger) spell (Id: %u) in Spell::EffectScriptEffect",m_spellInfo->Id);
|
|
return;
|
|
}
|
|
// all seals have aura dummy in 2 effect
|
|
Unit::AuraApplicationMap & sealAuras = m_caster->GetAppliedAuras();
|
|
for (Unit::AuraApplicationMap::iterator iter = sealAuras.begin(); iter != sealAuras.end();)
|
|
{
|
|
switch (iter->first)
|
|
{
|
|
// Heart of the Crusader
|
|
case 20335: // Rank 1
|
|
spellId3 = 21183;
|
|
break;
|
|
case 20336: // Rank 2
|
|
spellId3 = 54498;
|
|
break;
|
|
case 20337: // Rank 3
|
|
spellId3 = 54499;
|
|
break;
|
|
}
|
|
Aura * aura = iter->second->GetBase();
|
|
if (IsSealSpell(aura->GetSpellProto()))
|
|
{
|
|
if (AuraEffect * aureff = aura->GetEffect(2))
|
|
if (aureff->GetAuraType() == SPELL_AURA_DUMMY)
|
|
{
|
|
if (sSpellStore.LookupEntry(aureff->GetAmount()))
|
|
spellId2 = aureff->GetAmount();
|
|
break;
|
|
}
|
|
if (!spellId2)
|
|
{
|
|
switch (iter->first)
|
|
{
|
|
// Seal of light, Seal of wisdom, Seal of justice
|
|
case 20165:
|
|
case 20166:
|
|
case 20164:
|
|
spellId2 = 54158;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
++iter;
|
|
}
|
|
if (spellId1)
|
|
m_caster->CastSpell(unitTarget, spellId1, true);
|
|
if (spellId2)
|
|
m_caster->CastSpell(unitTarget, spellId2, true);
|
|
if (spellId3)
|
|
m_caster->CastSpell(unitTarget, spellId3, true);
|
|
return;
|
|
}
|
|
}
|
|
case SPELLFAMILY_POTION:
|
|
{
|
|
switch(m_spellInfo->Id)
|
|
{
|
|
// Dreaming Glory
|
|
case 28698:
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
unitTarget->CastSpell(unitTarget, 28694, true);
|
|
break;
|
|
}
|
|
// Netherbloom
|
|
case 28702:
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
// 25% chance of casting a random buff
|
|
if (roll_chance_i(75))
|
|
return;
|
|
|
|
// triggered spells are 28703 to 28707
|
|
// Note: some sources say, that there was the possibility of
|
|
// receiving a debuff. However, this seems to be removed by a patch.
|
|
const uint32 spellid = 28703;
|
|
|
|
// don't overwrite an existing aura
|
|
for (uint8 i = 0; i < 5; ++i)
|
|
if (unitTarget->HasAura(spellid + i))
|
|
return;
|
|
unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true);
|
|
break;
|
|
}
|
|
|
|
// Nightmare Vine
|
|
case 28720:
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
// 25% chance of casting Nightmare Pollen
|
|
if (roll_chance_i(75))
|
|
return;
|
|
unitTarget->CastSpell(unitTarget, 28721, true);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_DEATHKNIGHT:
|
|
{
|
|
// Pestilence
|
|
if (m_spellInfo->SpellFamilyFlags[1]&0x10000)
|
|
{
|
|
// Get diseases on target of spell
|
|
if (m_targets.getUnitTarget() && // Glyph of Disease - cast on unit target too to refresh aura
|
|
(m_targets.getUnitTarget() != unitTarget || m_caster->GetAura(63334)))
|
|
{
|
|
// And spread them on target
|
|
// Blood Plague
|
|
if (m_targets.getUnitTarget()->GetAura(55078))
|
|
m_caster->CastSpell(unitTarget, 55078, true);
|
|
// Frost Fever
|
|
if (m_targets.getUnitTarget()->GetAura(55095))
|
|
m_caster->CastSpell(unitTarget, 55095, true);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_WARRIOR:
|
|
{
|
|
// Shattering Throw
|
|
if (m_spellInfo->SpellFamilyFlags[1] & 0x00400000)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
// remove shields, will still display immune to damage part
|
|
unitTarget->RemoveAurasWithMechanic(1<<MECHANIC_IMMUNE_SHIELD, AURA_REMOVE_BY_ENEMY_SPELL);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// normal DB scripted effect
|
|
sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect(%u)", m_spellInfo->Id, effIndex);
|
|
m_caster->GetMap()->ScriptsStart(sSpellScripts, MAKE_PAIR32(m_spellInfo->Id,effIndex), m_caster, unitTarget);
|
|
}
|
|
|
|
void Spell::EffectSanctuary(uint32 /*i*/)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
std::list<Unit*> targets;
|
|
Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(unitTarget, unitTarget, m_caster->GetMap()->GetVisibilityDistance());
|
|
Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(unitTarget, targets, u_check);
|
|
unitTarget->VisitNearbyObject(m_caster->GetMap()->GetVisibilityDistance(), searcher);
|
|
for (std::list<Unit*>::iterator iter = targets.begin(); iter != targets.end(); ++iter)
|
|
{
|
|
if (!(*iter)->hasUnitState(UNIT_STAT_CASTING))
|
|
continue;
|
|
|
|
for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
|
|
{
|
|
if ((*iter)->GetCurrentSpell(i)
|
|
&& (*iter)->GetCurrentSpell(i)->m_targets.getUnitTargetGUID() == unitTarget->GetGUID())
|
|
{
|
|
(*iter)->InterruptSpell(CurrentSpellTypes(i), false);
|
|
}
|
|
}
|
|
}
|
|
|
|
unitTarget->CombatStop();
|
|
unitTarget->getHostileRefManager().deleteReferences(); // stop all fighting
|
|
// Vanish allows to remove all threat and cast regular stealth so other spells can be used
|
|
if (m_caster->GetTypeId() == TYPEID_PLAYER
|
|
&& m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE
|
|
&& (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_VANISH))
|
|
{
|
|
m_caster->ToPlayer()->RemoveAurasByType(SPELL_AURA_MOD_ROOT);
|
|
// Overkill
|
|
if (m_caster->ToPlayer()->HasSpell(58426))
|
|
m_caster->CastSpell(m_caster, 58427, true);
|
|
}
|
|
}
|
|
|
|
void Spell::EffectAddComboPoints(uint32 /*i*/)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
if (!m_caster->m_movedPlayer)
|
|
return;
|
|
|
|
if (damage <= 0)
|
|
return;
|
|
|
|
m_caster->m_movedPlayer->AddComboPoints(unitTarget, damage, this);
|
|
}
|
|
|
|
void Spell::EffectDuel(uint32 i)
|
|
{
|
|
if (!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player *caster = (Player*)m_caster;
|
|
Player *target = (Player*)unitTarget;
|
|
|
|
// caster or target already have requested duel
|
|
if (caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetGUIDLow()))
|
|
return;
|
|
|
|
// Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities)
|
|
// Don't have to check the target's map since you cannot challenge someone across maps
|
|
if (caster->GetMap()->Instanceable())
|
|
//if (mapid != 0 && mapid != 1 && mapid != 530 && mapid != 571 && mapid != 609)
|
|
{
|
|
SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
|
|
return;
|
|
}
|
|
|
|
AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId());
|
|
if (casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL))
|
|
{
|
|
SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
|
|
return;
|
|
}
|
|
|
|
AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId());
|
|
if (targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL))
|
|
{
|
|
SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
|
|
return;
|
|
}
|
|
|
|
//CREATE DUEL FLAG OBJECT
|
|
GameObject* pGameObj = new GameObject;
|
|
|
|
uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
|
|
|
|
Map *map = m_caster->GetMap();
|
|
if (!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id,
|
|
map, m_caster->GetPhaseMask(),
|
|
m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 ,
|
|
m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 ,
|
|
m_caster->GetPositionZ(),
|
|
m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY))
|
|
{
|
|
delete pGameObj;
|
|
return;
|
|
}
|
|
|
|
pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction());
|
|
pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1);
|
|
int32 duration = GetSpellDuration(m_spellInfo);
|
|
pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0);
|
|
pGameObj->SetSpellId(m_spellInfo->Id);
|
|
|
|
m_caster->AddGameObject(pGameObj);
|
|
map->Add(pGameObj);
|
|
//END
|
|
|
|
// Send request
|
|
WorldPacket data(SMSG_DUEL_REQUESTED, 8 + 8);
|
|
data << uint64(pGameObj->GetGUID());
|
|
data << uint64(caster->GetGUID());
|
|
caster->GetSession()->SendPacket(&data);
|
|
target->GetSession()->SendPacket(&data);
|
|
|
|
// create duel-info
|
|
DuelInfo *duel = new DuelInfo;
|
|
duel->initiator = caster;
|
|
duel->opponent = target;
|
|
duel->startTime = 0;
|
|
duel->startTimer = 0;
|
|
caster->duel = duel;
|
|
|
|
DuelInfo *duel2 = new DuelInfo;
|
|
duel2->initiator = caster;
|
|
duel2->opponent = caster;
|
|
duel2->startTime = 0;
|
|
duel2->startTimer = 0;
|
|
target->duel = duel2;
|
|
|
|
caster->SetUInt64Value(PLAYER_DUEL_ARBITER, pGameObj->GetGUID());
|
|
target->SetUInt64Value(PLAYER_DUEL_ARBITER, pGameObj->GetGUID());
|
|
}
|
|
|
|
void Spell::EffectStuck(uint32 /*i*/)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
if (!sWorld.getConfig(CONFIG_CAST_UNSTUCK))
|
|
return;
|
|
|
|
Player* pTarget = (Player*)unitTarget;
|
|
|
|
sLog.outDebug("Spell Effect: Stuck");
|
|
sLog.outDetail("Player %s (guid %u) used auto-unstuck future at map %u (%f, %f, %f)", pTarget->GetName(), pTarget->GetGUIDLow(), m_caster->GetMapId(), m_caster->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ());
|
|
|
|
if (pTarget->isInFlight())
|
|
return;
|
|
|
|
pTarget->TeleportTo(pTarget->GetStartPosition(), unitTarget == m_caster ? TELE_TO_SPELL : 0);
|
|
// homebind location is loaded always
|
|
// pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget == m_caster ? TELE_TO_SPELL : 0));
|
|
|
|
// Stuck spell trigger Hearthstone cooldown
|
|
SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690);
|
|
if (!spellInfo)
|
|
return;
|
|
Spell spell(pTarget, spellInfo, true, 0);
|
|
spell.SendSpellCooldown();
|
|
}
|
|
|
|
void Spell::EffectSummonPlayer(uint32 /*i*/)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// Evil Twin (ignore player summon, but hide this for summoner)
|
|
if (unitTarget->HasAura(23445))
|
|
return;
|
|
|
|
float x, y, z;
|
|
m_caster->GetClosePoint(x, y, z, unitTarget->GetObjectSize());
|
|
|
|
unitTarget->ToPlayer()->SetSummonPoint(m_caster->GetMapId(),x,y,z);
|
|
|
|
WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4);
|
|
data << uint64(m_caster->GetGUID()); // summoner guid
|
|
data << uint32(m_caster->GetZoneId()); // summoner zone
|
|
data << uint32(MAX_PLAYER_SUMMON_DELAY*IN_MILLISECONDS); // auto decline after msecs
|
|
unitTarget->ToPlayer()->GetSession()->SendPacket(&data);
|
|
}
|
|
|
|
static ScriptInfo generateActivateCommand()
|
|
{
|
|
ScriptInfo si;
|
|
si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
|
|
return si;
|
|
}
|
|
|
|
void Spell::EffectActivateObject(uint32 effect_idx)
|
|
{
|
|
if (!gameObjTarget)
|
|
return;
|
|
|
|
static ScriptInfo activateCommand = generateActivateCommand();
|
|
|
|
int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx];
|
|
|
|
gameObjTarget->GetMap()->ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
|
|
}
|
|
|
|
void Spell::EffectApplyGlyph(uint32 i)
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER || m_glyphIndex >= MAX_GLYPH_SLOT_INDEX)
|
|
return;
|
|
|
|
Player *player = (Player*)m_caster;
|
|
|
|
// apply new one
|
|
if (uint32 glyph = m_spellInfo->EffectMiscValue[i])
|
|
{
|
|
if (GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph))
|
|
{
|
|
if (GlyphSlotEntry const *gs = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex)))
|
|
{
|
|
if (gp->TypeFlags != gs->TypeFlags)
|
|
{
|
|
SendCastResult(SPELL_FAILED_INVALID_GLYPH);
|
|
return; // glyph slot mismatch
|
|
}
|
|
}
|
|
|
|
// remove old glyph
|
|
if (uint32 oldglyph = player->GetGlyph(m_glyphIndex))
|
|
{
|
|
if (GlyphPropertiesEntry const *old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
|
|
{
|
|
player->RemoveAurasDueToSpell(old_gp->SpellId);
|
|
player->SetGlyph(m_glyphIndex, 0);
|
|
}
|
|
}
|
|
|
|
player->CastSpell(m_caster, gp->SpellId, true);
|
|
player->SetGlyph(m_glyphIndex, glyph);
|
|
player->SendTalentsInfoData(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Spell::EffectEnchantHeldItem(uint32 i)
|
|
{
|
|
// this is only item spell effect applied to main-hand weapon of target player (players in area)
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player* item_owner = (Player*)unitTarget;
|
|
Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
|
|
|
|
if (!item)
|
|
return;
|
|
|
|
// must be equipped
|
|
if (!item ->IsEquipped())
|
|
return;
|
|
|
|
if (m_spellInfo->EffectMiscValue[i])
|
|
{
|
|
uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
|
|
int32 duration = GetSpellDuration(m_spellInfo); //Try duration index first ..
|
|
if (!duration)
|
|
duration = damage;//+1; //Base points after ..
|
|
if (!duration)
|
|
duration = 10; //10 seconds for enchants which don't have listed duration
|
|
|
|
SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
|
|
if (!pEnchant)
|
|
return;
|
|
|
|
// Always go to temp enchantment slot
|
|
EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT;
|
|
|
|
// Enchantment will not be applied if a different one already exists
|
|
if (item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id)
|
|
return;
|
|
|
|
// Apply the temporary enchantment
|
|
item->SetEnchantment(slot, enchant_id, duration*IN_MILLISECONDS, 0);
|
|
item_owner->ApplyEnchantment(item, slot, true);
|
|
}
|
|
}
|
|
|
|
void Spell::EffectDisEnchant(uint32 /*i*/)
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player* p_caster = (Player*)m_caster;
|
|
if (!itemTarget || !itemTarget->GetProto()->DisenchantID)
|
|
return;
|
|
|
|
p_caster->UpdateCraftSkill(m_spellInfo->Id);
|
|
|
|
m_caster->ToPlayer()->SendLoot(itemTarget->GetGUID(),LOOT_DISENCHANTING);
|
|
|
|
// item will be removed at disenchanting end
|
|
}
|
|
|
|
void Spell::EffectInebriate(uint32 /*i*/)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player *player = (Player*)unitTarget;
|
|
uint16 currentDrunk = player->GetDrunkValue();
|
|
uint16 drunkMod = damage * 256;
|
|
if (currentDrunk + drunkMod > 0xFFFF)
|
|
currentDrunk = 0xFFFF;
|
|
else
|
|
currentDrunk += drunkMod;
|
|
player->SetDrunkValue(currentDrunk, m_CastItem ? m_CastItem->GetEntry() : 0);
|
|
}
|
|
|
|
void Spell::EffectFeedPet(uint32 i)
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player *_player = (Player*)m_caster;
|
|
|
|
Item* foodItem = m_targets.getItemTarget();
|
|
if (!foodItem)
|
|
return;
|
|
|
|
Pet *pet = _player->GetPet();
|
|
if (!pet)
|
|
return;
|
|
|
|
if (!pet->isAlive())
|
|
return;
|
|
|
|
int32 benefit = pet->GetCurrentFoodBenefitLevel(foodItem->GetProto()->ItemLevel);
|
|
if (benefit <= 0)
|
|
return;
|
|
|
|
uint32 count = 1;
|
|
_player->DestroyItemCount(foodItem,count,true);
|
|
// TODO: fix crash when a spell has two effects, both pointed at the same item target
|
|
|
|
m_caster->CastCustomSpell(pet, m_spellInfo->EffectTriggerSpell[i], &benefit, NULL, NULL, true);
|
|
}
|
|
|
|
void Spell::EffectDismissPet(uint32 /*i*/)
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Pet* pet = m_caster->ToPlayer()->GetPet();
|
|
|
|
// not let dismiss dead pet
|
|
if (!pet||!pet->isAlive())
|
|
return;
|
|
|
|
m_caster->ToPlayer()->RemovePet(pet, PET_SAVE_NOT_IN_SLOT);
|
|
}
|
|
|
|
void Spell::EffectSummonObject(uint32 i)
|
|
{
|
|
uint32 go_id = m_spellInfo->EffectMiscValue[i];
|
|
|
|
uint8 slot = 0;
|
|
switch(m_spellInfo->Effect[i])
|
|
{
|
|
case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: slot = 0; break;
|
|
case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: slot = 1; break;
|
|
case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: slot = 2; break;
|
|
case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: slot = 3; break;
|
|
default: return;
|
|
}
|
|
|
|
uint64 guid = m_caster->m_ObjectSlot[slot];
|
|
if (guid != 0)
|
|
{
|
|
GameObject* obj = NULL;
|
|
if (m_caster)
|
|
obj = m_caster->GetMap()->GetGameObject(guid);
|
|
|
|
if (obj)
|
|
{
|
|
// Recast case - null spell id to make auras not be removed on object remove from world
|
|
if (m_spellInfo->Id == obj->GetSpellId())
|
|
obj->SetSpellId(0);
|
|
m_caster->RemoveGameObject(obj, true);
|
|
}
|
|
m_caster->m_ObjectSlot[slot] = 0;
|
|
}
|
|
|
|
GameObject* pGameObj = new GameObject;
|
|
|
|
float x, y, z;
|
|
// If dest location if present
|
|
if (m_targets.HasDst())
|
|
m_targets.m_dstPos.GetPosition(x, y, z);
|
|
// Summon in random point all other units if location present
|
|
else
|
|
m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE);
|
|
|
|
Map *map = m_caster->GetMap();
|
|
if (!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map,
|
|
m_caster->GetPhaseMask(), x, y, z, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY))
|
|
{
|
|
delete pGameObj;
|
|
return;
|
|
}
|
|
|
|
//pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel());
|
|
int32 duration = GetSpellDuration(m_spellInfo);
|
|
pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0);
|
|
pGameObj->SetSpellId(m_spellInfo->Id);
|
|
m_caster->AddGameObject(pGameObj);
|
|
|
|
map->Add(pGameObj);
|
|
|
|
m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID();
|
|
}
|
|
|
|
void Spell::EffectResurrect(uint32 /*effIndex*/)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
if (unitTarget->isAlive())
|
|
return;
|
|
if (!unitTarget->IsInWorld())
|
|
return;
|
|
|
|
switch (m_spellInfo->Id)
|
|
{
|
|
// Defibrillate (Goblin Jumper Cables) have 33% chance on success
|
|
case 8342:
|
|
if (roll_chance_i(67))
|
|
{
|
|
m_caster->CastSpell(m_caster, 8338, true, m_CastItem);
|
|
return;
|
|
}
|
|
break;
|
|
// Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
|
|
case 22999:
|
|
if (roll_chance_i(50))
|
|
{
|
|
m_caster->CastSpell(m_caster, 23055, true, m_CastItem);
|
|
return;
|
|
}
|
|
break;
|
|
// Defibrillate ( Gnomish Army Knife) have 67% chance on success_list
|
|
case 54732:
|
|
if (roll_chance_i(33))
|
|
{
|
|
return;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
Player* pTarget = unitTarget->ToPlayer();
|
|
|
|
if (pTarget->isRessurectRequested()) // already have one active request
|
|
return;
|
|
|
|
uint32 health = pTarget->GetMaxHealth() * damage / 100;
|
|
uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100;
|
|
|
|
pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
|
|
SendResurrectRequest(pTarget);
|
|
}
|
|
|
|
void Spell::EffectAddExtraAttacks(uint32 /*i*/)
|
|
{
|
|
if (!unitTarget || !unitTarget->isAlive())
|
|
return;
|
|
|
|
if (unitTarget->m_extraAttacks)
|
|
return;
|
|
|
|
Unit *victim = unitTarget->getVictim();
|
|
|
|
// attack prevented
|
|
// fixme, some attacks may not target current victim, this is right now not handled
|
|
if (!victim || !unitTarget->IsWithinMeleeRange(victim) || !unitTarget->HasInArc(2*M_PI/3, victim))
|
|
return;
|
|
|
|
// Only for proc/log informations
|
|
unitTarget->m_extraAttacks = damage;
|
|
// Need to send log before attack is made
|
|
SendLogExecute();
|
|
m_needSpellLog = false;
|
|
|
|
unitTarget->AttackerStateUpdate(victim, BASE_ATTACK, true);
|
|
}
|
|
|
|
void Spell::EffectParry(uint32 /*i*/)
|
|
{
|
|
if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
|
|
unitTarget->ToPlayer()->SetCanParry(true);
|
|
}
|
|
|
|
void Spell::EffectBlock(uint32 /*i*/)
|
|
{
|
|
if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
|
|
unitTarget->ToPlayer()->SetCanBlock(true);
|
|
}
|
|
|
|
void Spell::EffectLeap(uint32 i)
|
|
{
|
|
if (unitTarget->isInFlight())
|
|
return;
|
|
|
|
if (!m_targets.HasDst())
|
|
return;
|
|
|
|
unitTarget->NearTeleportTo(m_targets.m_dstPos.GetPositionX(), m_targets.m_dstPos.GetPositionY(), m_targets.m_dstPos.GetPositionZ(), m_targets.m_dstPos.GetOrientation(), unitTarget == m_caster);
|
|
}
|
|
|
|
void Spell::EffectReputation(uint32 i)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player *_player = (Player*)unitTarget;
|
|
|
|
int32 rep_change = damage;//+1; // field store reputation change -1
|
|
|
|
uint32 faction_id = m_spellInfo->EffectMiscValue[i];
|
|
|
|
FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
|
|
|
|
if (!factionEntry)
|
|
return;
|
|
|
|
if (RepRewardRate const * repData = objmgr.GetRepRewardRate(faction_id))
|
|
{
|
|
rep_change = (float)rep_change * repData->spell_rate;
|
|
}
|
|
|
|
_player->GetReputationMgr().ModifyReputation(factionEntry, rep_change);
|
|
}
|
|
|
|
void Spell::EffectQuestComplete(uint32 i)
|
|
{
|
|
Player *pPlayer;
|
|
|
|
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
|
pPlayer = (Player*)m_caster;
|
|
else if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
|
|
pPlayer = (Player*)unitTarget;
|
|
else
|
|
return;
|
|
|
|
uint32 quest_id = m_spellInfo->EffectMiscValue[i];
|
|
if (quest_id)
|
|
{
|
|
uint16 log_slot = pPlayer->FindQuestSlot(quest_id);
|
|
if (log_slot < MAX_QUEST_LOG_SIZE)
|
|
pPlayer->AreaExploredOrEventHappens(quest_id);
|
|
else if (!pPlayer->GetQuestRewardStatus(quest_id)) // never rewarded before
|
|
pPlayer->CompleteQuest(quest_id); // quest not in log - for internal use
|
|
}
|
|
}
|
|
|
|
void Spell::EffectForceDeselect(uint32 /*i*/)
|
|
{
|
|
WorldPacket data(SMSG_CLEAR_TARGET, 8);
|
|
data << uint64(m_caster->GetGUID());
|
|
m_caster->SendMessageToSet(&data, true);
|
|
}
|
|
|
|
void Spell::EffectSelfResurrect(uint32 i)
|
|
{
|
|
if (!unitTarget || unitTarget->isAlive())
|
|
return;
|
|
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
if (!unitTarget->IsInWorld())
|
|
return;
|
|
|
|
uint32 health = 0;
|
|
uint32 mana = 0;
|
|
|
|
// flat case
|
|
if (damage < 0)
|
|
{
|
|
health = uint32(-damage);
|
|
mana = m_spellInfo->EffectMiscValue[i];
|
|
}
|
|
// percent case
|
|
else
|
|
{
|
|
health = uint32(damage/100.0f*unitTarget->GetMaxHealth());
|
|
if (unitTarget->GetMaxPower(POWER_MANA) > 0)
|
|
mana = uint32(damage/100.0f*unitTarget->GetMaxPower(POWER_MANA));
|
|
}
|
|
|
|
Player *plr = unitTarget->ToPlayer();
|
|
plr->ResurrectPlayer(0.0f);
|
|
|
|
plr->SetHealth(health);
|
|
plr->SetPower(POWER_MANA, mana);
|
|
plr->SetPower(POWER_RAGE, 0);
|
|
plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY));
|
|
|
|
plr->SpawnCorpseBones();
|
|
}
|
|
|
|
void Spell::EffectSkinning(uint32 /*i*/)
|
|
{
|
|
if (unitTarget->GetTypeId() != TYPEID_UNIT)
|
|
return;
|
|
if (!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Creature* creature = unitTarget->ToCreature();
|
|
int32 targetLevel = creature->getLevel();
|
|
|
|
uint32 skill = creature->GetCreatureInfo()->GetRequiredLootSkill();
|
|
|
|
m_caster->ToPlayer()->SendLoot(creature->GetGUID(),LOOT_SKINNING);
|
|
creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
|
|
|
|
int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5;
|
|
|
|
int32 skillValue = m_caster->ToPlayer()->GetPureSkillValue(skill);
|
|
|
|
// Double chances for elites
|
|
m_caster->ToPlayer()->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1);
|
|
}
|
|
|
|
void Spell::EffectCharge(uint32 /*i*/)
|
|
{
|
|
Unit *target = m_targets.getUnitTarget();
|
|
if (!target)
|
|
return;
|
|
|
|
float x, y, z;
|
|
target->GetContactPoint(m_caster, x, y, z);
|
|
m_caster->GetMotionMaster()->MoveCharge(x, y, z);
|
|
|
|
// not all charge effects used in negative spells
|
|
if (!IsPositiveSpell(m_spellInfo->Id) && m_caster->GetTypeId() == TYPEID_PLAYER)
|
|
m_caster->Attack(target, true);
|
|
}
|
|
|
|
void Spell::EffectChargeDest(uint32 /*i*/)
|
|
{
|
|
if (m_targets.HasDst())
|
|
{
|
|
float x, y, z;
|
|
m_targets.m_dstPos.GetPosition(x, y, z);
|
|
m_caster->GetMotionMaster()->MoveCharge(x, y, z);
|
|
}
|
|
}
|
|
|
|
void Spell::EffectKnockBack(uint32 i)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
// Typhoon
|
|
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags[1] & 0x01000000)
|
|
{
|
|
// Glyph of Typhoon
|
|
if (m_caster->HasAura(62135))
|
|
return;
|
|
}
|
|
|
|
// Thunderstorm
|
|
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[1] & 0x00002000)
|
|
{
|
|
// Glyph of Thunderstorm
|
|
if (m_caster->HasAura(62132))
|
|
return;
|
|
}
|
|
|
|
float ratio = m_caster->GetCombatReach() / std::max(unitTarget->GetCombatReach(), 1.0f);
|
|
if (ratio < 1.0f)
|
|
ratio = ratio * ratio * ratio * 0.1f; // volume = length^3
|
|
else
|
|
ratio = 0.1f; // dbc value ratio
|
|
float speedxy = float(m_spellInfo->EffectMiscValue[i]) * ratio;
|
|
float speedz = float(damage) * ratio;
|
|
if (speedxy < 0.1f && speedz < 0.1f)
|
|
return;
|
|
|
|
float x, y;
|
|
if (m_spellInfo->Effect[i] == SPELL_EFFECT_KNOCK_BACK_DEST)
|
|
{
|
|
if (m_targets.HasDst())
|
|
m_targets.m_dstPos.GetPosition(x, y);
|
|
else
|
|
return;
|
|
}
|
|
else //if (m_spellInfo->Effect[i] == SPELL_EFFECT_KNOCK_BACK)
|
|
{
|
|
m_caster->GetPosition(x, y);
|
|
}
|
|
|
|
unitTarget->KnockbackFrom(x, y, speedxy, speedz);
|
|
}
|
|
|
|
void Spell::EffectLeapBack(uint32 i)
|
|
{
|
|
float speedxy = float(m_spellInfo->EffectMiscValue[i])/10;
|
|
float speedz = float(damage/10);
|
|
if (!speedxy)
|
|
{
|
|
if (m_targets.getUnitTarget())
|
|
m_caster->JumpTo(m_targets.getUnitTarget(), speedz);
|
|
}
|
|
else
|
|
{
|
|
//1891: Disengage
|
|
m_caster->JumpTo(speedxy, speedz, m_spellInfo->SpellIconID != 1891);
|
|
}
|
|
}
|
|
|
|
void Spell::EffectQuestClear(uint32 i)
|
|
{
|
|
Player *pPlayer = NULL;
|
|
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
|
pPlayer = m_caster->ToPlayer();
|
|
else if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
|
|
pPlayer = unitTarget->ToPlayer();
|
|
|
|
if (!pPlayer)
|
|
return;
|
|
|
|
uint32 quest_id = m_spellInfo->EffectMiscValue[i];
|
|
|
|
Quest const* pQuest = objmgr.GetQuestTemplate(quest_id);
|
|
|
|
if (!pQuest)
|
|
return;
|
|
|
|
QuestStatusMap::iterator qs_itr = pPlayer->getQuestStatusMap().find(quest_id);
|
|
// Player has never done this quest
|
|
if (qs_itr == pPlayer->getQuestStatusMap().end())
|
|
return;
|
|
|
|
// remove all quest entries for 'entry' from quest log
|
|
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
|
|
{
|
|
uint32 quest = pPlayer->GetQuestSlotQuestId(slot);
|
|
if (quest == quest_id)
|
|
{
|
|
pPlayer->SetQuestSlot(slot, 0);
|
|
|
|
// we ignore unequippable quest items in this case, its' still be equipped
|
|
pPlayer->TakeQuestSourceItem(quest, false);
|
|
}
|
|
}
|
|
|
|
// set quest status to not started (will be updated in DB at next save)
|
|
pPlayer->SetQuestStatus(quest_id, QUEST_STATUS_NONE);
|
|
|
|
// reset rewarded for restart repeatable quest
|
|
QuestStatusData &data = qs_itr->second;
|
|
data.m_rewarded = false;
|
|
}
|
|
|
|
void Spell::EffectSendTaxi(uint32 i)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
unitTarget->ToPlayer()->ActivateTaxiPathTo(m_spellInfo->EffectMiscValue[i],m_spellInfo->Id);
|
|
}
|
|
|
|
void Spell::EffectPlayerPull(uint32 i)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
float speedZ = m_spellInfo->EffectBasePoints[i]/10;
|
|
float speedXY = m_spellInfo->EffectMiscValue[i]/10;
|
|
unitTarget->GetMotionMaster()->MoveJump(m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), speedXY, speedZ);
|
|
}
|
|
|
|
void Spell::EffectDispelMechanic(uint32 i)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
uint32 mechanic = m_spellInfo->EffectMiscValue[i];
|
|
|
|
std::queue < std::pair < uint32, uint64 > > dispel_list;
|
|
|
|
Unit::AuraMap const& auras = unitTarget->GetOwnedAuras();
|
|
for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
|
|
{
|
|
Aura * aura = itr->second;
|
|
if (!aura->GetApplicationOfTarget(unitTarget->GetGUID()))
|
|
continue;
|
|
bool success = false;
|
|
GetDispelChance(aura->GetCaster(), unitTarget, aura->GetId(), !unitTarget->IsFriendlyTo(m_caster), &success);
|
|
if ((GetAllSpellMechanicMask(aura->GetSpellProto()) & (1 << mechanic)) && success)
|
|
dispel_list.push(std::make_pair(aura->GetId(), aura->GetCasterGUID()));
|
|
}
|
|
|
|
for (; dispel_list.size(); dispel_list.pop())
|
|
{
|
|
unitTarget->RemoveAura(dispel_list.front().first, dispel_list.front().second, 0, AURA_REMOVE_BY_ENEMY_SPELL);
|
|
}
|
|
}
|
|
|
|
void Spell::EffectSummonDeadPet(uint32 /*i*/)
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
Player *_player = (Player*)m_caster;
|
|
Pet *pet = _player->GetPet();
|
|
if (!pet)
|
|
return;
|
|
if (pet->isAlive())
|
|
return;
|
|
if (damage < 0)
|
|
return;
|
|
|
|
float x,y,z;
|
|
_player->GetPosition(x, y, z);
|
|
_player->GetMap()->CreatureRelocation(pet, x, y, z, _player->GetOrientation());
|
|
|
|
pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0);
|
|
pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
|
|
pet->setDeathState(ALIVE);
|
|
pet->clearUnitState(UNIT_STAT_ALL_STATE);
|
|
pet->SetHealth(uint32(pet->GetMaxHealth()*(float(damage)/100)));
|
|
|
|
//pet->AIM_Initialize();
|
|
//_player->PetSpellInitialize();
|
|
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
|
|
}
|
|
|
|
void Spell::EffectDestroyAllTotems(uint32 /*i*/)
|
|
{
|
|
int32 mana = 0;
|
|
for (uint8 slot = SUMMON_SLOT_TOTEM; slot < MAX_TOTEM_SLOT; ++slot)
|
|
{
|
|
if (!m_caster->m_SummonSlot[slot])
|
|
continue;
|
|
|
|
Creature* totem = m_caster->GetMap()->GetCreature(m_caster->m_SummonSlot[slot]);
|
|
if (totem && totem->isTotem())
|
|
{
|
|
uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL);
|
|
SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id);
|
|
if (spellInfo)
|
|
{
|
|
mana += spellInfo->manaCost;
|
|
mana += spellInfo->ManaCostPercentage * m_caster->GetCreateMana() / 100;
|
|
}
|
|
totem->ToTotem()->UnSummon();
|
|
}
|
|
}
|
|
mana = mana * damage / 100;
|
|
|
|
if (mana)
|
|
m_caster->CastCustomSpell(m_caster, 39104, &mana, NULL, NULL, true);
|
|
}
|
|
|
|
void Spell::EffectDurabilityDamage(uint32 i)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
int32 slot = m_spellInfo->EffectMiscValue[i];
|
|
|
|
// FIXME: some spells effects have value -1/-2
|
|
// Possibly its mean -1 all player equipped items and -2 all items
|
|
if (slot < 0)
|
|
{
|
|
unitTarget->ToPlayer()->DurabilityPointsLossAll(damage, (slot < -1));
|
|
return;
|
|
}
|
|
|
|
// invalid slot value
|
|
if (slot >= INVENTORY_SLOT_BAG_END)
|
|
return;
|
|
|
|
if (Item* item = unitTarget->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
|
unitTarget->ToPlayer()->DurabilityPointsLoss(item, damage);
|
|
}
|
|
|
|
void Spell::EffectDurabilityDamagePCT(uint32 i)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
int32 slot = m_spellInfo->EffectMiscValue[i];
|
|
|
|
// FIXME: some spells effects have value -1/-2
|
|
// Possibly its mean -1 all player equipped items and -2 all items
|
|
if (slot < 0)
|
|
{
|
|
unitTarget->ToPlayer()->DurabilityLossAll(double(damage)/100.0f, (slot < -1));
|
|
return;
|
|
}
|
|
|
|
// invalid slot value
|
|
if (slot >= INVENTORY_SLOT_BAG_END)
|
|
return;
|
|
|
|
if (damage <= 0)
|
|
return;
|
|
|
|
if (Item* item = unitTarget->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
|
unitTarget->ToPlayer()->DurabilityLoss(item, double(damage)/100.0f);
|
|
}
|
|
|
|
void Spell::EffectModifyThreatPercent(uint32 /*effIndex*/)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
|
|
unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage);
|
|
}
|
|
|
|
void Spell::EffectTransmitted(uint32 effIndex)
|
|
{
|
|
uint32 name_id = m_spellInfo->EffectMiscValue[effIndex];
|
|
|
|
GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id);
|
|
|
|
if (!goinfo)
|
|
{
|
|
sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id, m_spellInfo->Id);
|
|
return;
|
|
}
|
|
|
|
float fx, fy, fz;
|
|
|
|
if (m_targets.HasDst())
|
|
m_targets.m_dstPos.GetPosition(fx, fy, fz);
|
|
//FIXME: this can be better check for most objects but still hack
|
|
else if (m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed == 0)
|
|
{
|
|
float dis = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex]));
|
|
m_caster->GetClosePoint(fx, fy, fz, DEFAULT_WORLD_OBJECT_SIZE, dis);
|
|
}
|
|
else
|
|
{
|
|
//GO is always friendly to it's creator, get range for friends
|
|
float min_dis = GetSpellMinRangeForFriend(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
|
|
float max_dis = GetSpellMaxRangeForFriend(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
|
|
float dis = rand_norm() * (max_dis - min_dis) + min_dis;
|
|
|
|
m_caster->GetClosePoint(fx, fy, fz, DEFAULT_WORLD_OBJECT_SIZE, dis);
|
|
}
|
|
|
|
Map *cMap = m_caster->GetMap();
|
|
if (goinfo->type == GAMEOBJECT_TYPE_FISHINGNODE)
|
|
{
|
|
LiquidData liqData;
|
|
if ( !cMap->IsInWater(fx, fy, fz + 1.f/* -0.5f */, &liqData)) // Hack to prevent fishing bobber from failing to land on fishing hole
|
|
{ // but this is not proper, we really need to ignore not materialized objects
|
|
SendCastResult(SPELL_FAILED_NOT_HERE);
|
|
SendChannelUpdate(0);
|
|
return;
|
|
}
|
|
|
|
// replace by water level in this case
|
|
//fz = cMap->GetWaterLevel(fx, fy);
|
|
fz = liqData.level;
|
|
}
|
|
// if gameobject is summoning object, it should be spawned right on caster's position
|
|
else if (goinfo->type == GAMEOBJECT_TYPE_SUMMONING_RITUAL)
|
|
{
|
|
m_caster->GetPosition(fx, fy, fz);
|
|
}
|
|
|
|
GameObject* pGameObj = new GameObject;
|
|
|
|
if (!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap,
|
|
m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
|
|
{
|
|
delete pGameObj;
|
|
return;
|
|
}
|
|
|
|
int32 duration = GetSpellDuration(m_spellInfo);
|
|
|
|
switch(goinfo->type)
|
|
{
|
|
case GAMEOBJECT_TYPE_FISHINGNODE:
|
|
{
|
|
m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID());
|
|
m_caster->AddGameObject(pGameObj); // will removed at spell cancel
|
|
|
|
// end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
|
|
// start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
|
|
int32 lastSec = 0;
|
|
switch(urand(0, 3))
|
|
{
|
|
case 0: lastSec = 3; break;
|
|
case 1: lastSec = 7; break;
|
|
case 2: lastSec = 13; break;
|
|
case 3: lastSec = 17; break;
|
|
}
|
|
|
|
duration = duration - lastSec*IN_MILLISECONDS + FISHING_BOBBER_READY_TIME*IN_MILLISECONDS;
|
|
break;
|
|
}
|
|
case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
|
|
{
|
|
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
pGameObj->AddUniqueUse(m_caster->ToPlayer());
|
|
m_caster->AddGameObject(pGameObj); // will removed at spell cancel
|
|
}
|
|
break;
|
|
}
|
|
case GAMEOBJECT_TYPE_DUEL_ARBITER: // 52991
|
|
m_caster->AddGameObject(pGameObj);
|
|
break;
|
|
case GAMEOBJECT_TYPE_FISHINGHOLE:
|
|
case GAMEOBJECT_TYPE_CHEST:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0);
|
|
|
|
pGameObj->SetOwnerGUID(m_caster->GetGUID());
|
|
|
|
//pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel());
|
|
pGameObj->SetSpellId(m_spellInfo->Id);
|
|
|
|
DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted");
|
|
//m_caster->AddGameObject(pGameObj);
|
|
//m_ObjToDel.push_back(pGameObj);
|
|
|
|
cMap->Add(pGameObj);
|
|
|
|
if (uint32 linkedEntry = pGameObj->GetGOInfo()->GetLinkedGameObjectEntry())
|
|
{
|
|
GameObject* linkedGO = new GameObject;
|
|
if (linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
|
|
m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
|
|
{
|
|
linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0);
|
|
//linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel());
|
|
linkedGO->SetSpellId(m_spellInfo->Id);
|
|
linkedGO->SetOwnerGUID(m_caster->GetGUID());
|
|
|
|
linkedGO->GetMap()->Add(linkedGO);
|
|
}
|
|
else
|
|
{
|
|
delete linkedGO;
|
|
linkedGO = NULL;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Spell::EffectProspecting(uint32 /*i*/)
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player* p_caster = (Player*)m_caster;
|
|
if (!itemTarget || !(itemTarget->GetProto()->Flags & ITEM_PROTO_FLAG_PROSPECTABLE))
|
|
return;
|
|
|
|
if (itemTarget->GetCount() < 5)
|
|
return;
|
|
|
|
if (sWorld.getConfig(CONFIG_SKILL_PROSPECTING))
|
|
{
|
|
uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING);
|
|
uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
|
|
p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue);
|
|
}
|
|
|
|
m_caster->ToPlayer()->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING);
|
|
}
|
|
|
|
void Spell::EffectMilling(uint32 /*i*/)
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player* p_caster = (Player*)m_caster;
|
|
if (!itemTarget || !(itemTarget->GetProto()->Flags & ITEM_PROTO_FLAG_MILLABLE))
|
|
return;
|
|
|
|
if (itemTarget->GetCount() < 5)
|
|
return;
|
|
|
|
if (sWorld.getConfig(CONFIG_SKILL_MILLING))
|
|
{
|
|
uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_INSCRIPTION);
|
|
uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
|
|
p_caster->UpdateGatherSkill(SKILL_INSCRIPTION, SkillValue, reqSkillValue);
|
|
}
|
|
|
|
m_caster->ToPlayer()->SendLoot(itemTarget->GetGUID(), LOOT_MILLING);
|
|
}
|
|
|
|
void Spell::EffectSkill(uint32 /*i*/)
|
|
{
|
|
sLog.outDebug("WORLD: SkillEFFECT");
|
|
}
|
|
|
|
/* There is currently no need for this effect. We handle it in BattleGround.cpp
|
|
If we would handle the resurrection here, the spiritguide would instantly disappear as the
|
|
player revives, and so we wouldn't see the spirit heal visual effect on the npc.
|
|
This is why we use a half sec delay between the visual effect and the resurrection itself */
|
|
void Spell::EffectSpiritHeal(uint32 /*i*/)
|
|
{
|
|
/*
|
|
if (!unitTarget || unitTarget->isAlive())
|
|
return;
|
|
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
if (!unitTarget->IsInWorld())
|
|
return;
|
|
|
|
//m_spellInfo->EffectBasePoints[i]; == 99 (percent?)
|
|
//unitTarget->ToPlayer()->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
|
|
unitTarget->ToPlayer()->ResurrectPlayer(1.0f);
|
|
unitTarget->ToPlayer()->SpawnCorpseBones();
|
|
*/
|
|
}
|
|
|
|
// remove insignia spell effect
|
|
void Spell::EffectSkinPlayerCorpse(uint32 /*i*/)
|
|
{
|
|
sLog.outDebug("Effect: SkinPlayerCorpse");
|
|
if ((m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->isAlive()))
|
|
return;
|
|
|
|
unitTarget->ToPlayer()->RemovedInsignia((Player*)m_caster);
|
|
}
|
|
|
|
void Spell::EffectStealBeneficialBuff(uint32 i)
|
|
{
|
|
sLog.outDebug("Effect: StealBeneficialBuff");
|
|
|
|
if (!unitTarget || unitTarget == m_caster) // can't steal from self
|
|
return;
|
|
|
|
DispelChargesList steal_list;
|
|
|
|
// Create dispel mask by dispel type
|
|
uint32 dispelMask = GetDispellMask(DispelType(m_spellInfo->EffectMiscValue[i]));
|
|
Unit::AuraMap const& auras = unitTarget->GetOwnedAuras();
|
|
for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
|
|
{
|
|
Aura * aura = itr->second;
|
|
AuraApplication * aurApp = aura->GetApplicationOfTarget(unitTarget->GetGUID());
|
|
if (!aurApp)
|
|
continue;
|
|
|
|
if ((1<<aura->GetSpellProto()->Dispel) & dispelMask)
|
|
{
|
|
// Need check for passive? this
|
|
if (!aurApp->IsPositive() || aura->IsPassive() || aura->GetSpellProto()->AttributesEx4 & SPELL_ATTR_EX4_NOT_STEALABLE)
|
|
continue;
|
|
|
|
// The charges / stack amounts don't count towards the total number of auras that can be dispelled.
|
|
// Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell
|
|
// Polymorph instead of 1 / (5 + 1) -> 16%.
|
|
bool dispel_charges = aura->GetSpellProto()->AttributesEx7 & SPELL_ATTR_EX7_DISPEL_CHARGES;
|
|
uint8 charges = dispel_charges ? aura->GetCharges() : aura->GetStackAmount();
|
|
if (charges > 0)
|
|
steal_list.push_back(std::make_pair(aura, charges));
|
|
}
|
|
}
|
|
|
|
if (steal_list.empty())
|
|
return;
|
|
|
|
// Ok if exist some buffs for dispel try dispel it
|
|
uint32 failCount = 0;
|
|
DispelList success_list;
|
|
WorldPacket dataFail(SMSG_DISPEL_FAILED, 8+8+4+4+damage*4);
|
|
// dispel N = damage buffs (or while exist buffs for dispel)
|
|
for (int32 count = 0; count < damage && !steal_list.empty();)
|
|
{
|
|
// Random select buff for dispel
|
|
DispelChargesList::iterator itr = steal_list.begin();
|
|
std::advance(itr, urand(0, steal_list.size() - 1));
|
|
|
|
bool success = false;
|
|
// 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
|
|
if (!GetDispelChance(itr->first->GetCaster(), unitTarget, itr->first->GetId(), !unitTarget->IsFriendlyTo(m_caster), &success))
|
|
{
|
|
steal_list.erase(itr);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if (success)
|
|
{
|
|
success_list.push_back(std::make_pair(itr->first->GetId(), itr->first->GetCasterGUID()));
|
|
--itr->second;
|
|
if (itr->second <= 0)
|
|
steal_list.erase(itr);
|
|
}
|
|
else
|
|
{
|
|
if (!failCount)
|
|
{
|
|
// Failed to dispell
|
|
dataFail << uint64(m_caster->GetGUID()); // Caster GUID
|
|
dataFail << uint64(unitTarget->GetGUID()); // Victim GUID
|
|
dataFail << uint32(m_spellInfo->Id); // dispel spell id
|
|
}
|
|
++failCount;
|
|
dataFail << uint32(itr->first->GetId()); // Spell Id
|
|
}
|
|
++count;
|
|
}
|
|
}
|
|
|
|
if (failCount)
|
|
m_caster->SendMessageToSet(&dataFail, true);
|
|
|
|
if (success_list.empty())
|
|
return;
|
|
|
|
WorldPacket dataSuccess(SMSG_SPELLSTEALLOG, 8+8+4+1+4+damage*5);
|
|
dataSuccess.append(unitTarget->GetPackGUID()); // Victim GUID
|
|
dataSuccess.append(m_caster->GetPackGUID()); // Caster GUID
|
|
dataSuccess << uint32(m_spellInfo->Id); // dispel spell id
|
|
dataSuccess << uint8(0); // not used
|
|
dataSuccess << uint32(success_list.size()); // count
|
|
for (DispelList::iterator itr = success_list.begin(); itr!=success_list.end(); ++itr)
|
|
{
|
|
dataSuccess << uint32(itr->first); // Spell Id
|
|
dataSuccess << uint8(0); // 0 - steals !=0 transfers
|
|
unitTarget->RemoveAurasDueToSpellBySteal(itr->first, itr->second, m_caster);
|
|
}
|
|
m_caster->SendMessageToSet(&dataSuccess, true);
|
|
}
|
|
|
|
void Spell::EffectKillCreditPersonal(uint32 i)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
unitTarget->ToPlayer()->KilledMonsterCredit(m_spellInfo->EffectMiscValue[i], 0);
|
|
}
|
|
|
|
void Spell::EffectKillCredit(uint32 i)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
int32 creatureEntry = m_spellInfo->EffectMiscValue[i];
|
|
if (!creatureEntry)
|
|
{
|
|
if (m_spellInfo->Id == 42793) // Burn Body
|
|
creatureEntry = 24008; // Fallen Combatant
|
|
}
|
|
|
|
if (creatureEntry)
|
|
unitTarget->ToPlayer()->RewardPlayerAndGroupAtEvent(creatureEntry, unitTarget);
|
|
}
|
|
|
|
void Spell::EffectQuestFail(uint32 i)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
unitTarget->ToPlayer()->FailQuest(m_spellInfo->EffectMiscValue[i]);
|
|
}
|
|
|
|
void Spell::EffectQuestStart(uint32 i)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player * player = unitTarget->ToPlayer();
|
|
if (Quest const* qInfo = objmgr.GetQuestTemplate(m_spellInfo->EffectMiscValue[i]))
|
|
{
|
|
if (player->CanTakeQuest(qInfo, false) && player->CanAddQuest(qInfo, false))
|
|
{
|
|
player->AddQuest(qInfo, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Spell::EffectActivateRune(uint32 eff_idx)
|
|
{
|
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player *plr = (Player*)m_caster;
|
|
|
|
if (plr->getClass() != CLASS_DEATH_KNIGHT)
|
|
return;
|
|
|
|
// needed later
|
|
m_runesState = m_caster->ToPlayer()->GetRunesState();
|
|
|
|
uint32 count = damage;
|
|
if (count == 0) count = 1;
|
|
for (uint32 j = 0; j < MAX_RUNES && count > 0; ++j)
|
|
{
|
|
if (plr->GetRuneCooldown(j) && plr->GetCurrentRune(j) == RuneType(m_spellInfo->EffectMiscValue[eff_idx]))
|
|
{
|
|
plr->SetRuneCooldown(j, 0);
|
|
--count;
|
|
}
|
|
}
|
|
// Empower rune weapon
|
|
if (m_spellInfo->Id == 47568)
|
|
{
|
|
// Need to do this just once
|
|
if (eff_idx != 0)
|
|
return;
|
|
|
|
for (uint32 i = 0; i < MAX_RUNES; ++i)
|
|
{
|
|
if (plr->GetRuneCooldown(i) && (plr->GetCurrentRune(i) == RUNE_FROST || plr->GetCurrentRune(i) == RUNE_DEATH))
|
|
plr->SetRuneCooldown(i, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Spell::EffectCreateTamedPet(uint32 i)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || unitTarget->GetPetGUID() || unitTarget->getClass() != CLASS_HUNTER)
|
|
return;
|
|
|
|
uint32 creatureEntry = m_spellInfo->EffectMiscValue[i];
|
|
Pet * pet = unitTarget->CreateTamedPetFrom(creatureEntry, m_spellInfo->Id);
|
|
if (!pet)
|
|
return;
|
|
|
|
// add to world
|
|
pet->GetMap()->Add(pet->ToCreature());
|
|
|
|
// unitTarget has pet now
|
|
unitTarget->SetMinion(pet, true);
|
|
|
|
pet->InitTalentForLevel();
|
|
|
|
if (unitTarget->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
|
|
unitTarget->ToPlayer()->PetSpellInitialize();
|
|
}
|
|
}
|
|
|
|
void Spell::EffectDiscoverTaxi(uint32 i)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
uint32 nodeid = m_spellInfo->EffectMiscValue[i];
|
|
if (sTaxiNodesStore.LookupEntry(nodeid))
|
|
unitTarget->ToPlayer()->GetSession()->SendDiscoverNewTaxiNode(nodeid);
|
|
}
|
|
|
|
void Spell::EffectTitanGrip(uint32 /*eff_idx*/)
|
|
{
|
|
if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
|
|
unitTarget->ToPlayer()->SetCanTitanGrip(true);
|
|
}
|
|
|
|
void Spell::EffectRedirectThreat(uint32 /*i*/)
|
|
{
|
|
if (unitTarget)
|
|
m_caster->SetReducedThreatPercent((uint32)damage, unitTarget->GetGUID());
|
|
}
|
|
|
|
void Spell::EffectWMODamage(uint32 /*i*/)
|
|
{
|
|
if (gameObjTarget && gameObjTarget->GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING)
|
|
{
|
|
Unit *caster = m_originalCaster;
|
|
if (!caster)
|
|
return;
|
|
|
|
FactionTemplateEntry const *casterft, *goft;
|
|
casterft = caster->getFactionTemplateEntry();
|
|
goft = sFactionTemplateStore.LookupEntry(gameObjTarget->GetUInt32Value(GAMEOBJECT_FACTION));
|
|
// Do not allow to damage GO's of friendly factions (ie: Wintergrasp Walls)
|
|
if (casterft && goft && !casterft->IsFriendlyTo(*goft))
|
|
{
|
|
gameObjTarget->TakenDamage(uint32(damage), caster);
|
|
WorldPacket data(SMSG_DESTRUCTIBLE_BUILDING_DAMAGE, 8+8+8+4+4);
|
|
data.append(gameObjTarget->GetPackGUID());
|
|
data.append(caster->GetPackGUID());
|
|
if (Unit *who = caster->GetCharmerOrOwner())
|
|
data.append(who->GetPackGUID());
|
|
else
|
|
data << uint8(0);
|
|
data << uint32(damage);
|
|
data << uint32(m_spellInfo->Id);
|
|
gameObjTarget->SendMessageToSet(&data, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Spell::EffectWMORepair(uint32 /*i*/)
|
|
{
|
|
if (gameObjTarget && gameObjTarget->GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING)
|
|
gameObjTarget->Rebuild();
|
|
}
|
|
|
|
void Spell::SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const *properties)
|
|
{
|
|
Unit *caster = m_originalCaster;
|
|
if (!caster)
|
|
return;
|
|
|
|
if (caster->isTotem())
|
|
caster = caster->ToTotem()->GetOwner();
|
|
|
|
// in another case summon new
|
|
uint8 level = caster->getLevel();
|
|
|
|
// level of pet summoned using engineering item based at engineering skill level
|
|
if (m_CastItem && caster->GetTypeId() == TYPEID_PLAYER)
|
|
if (ItemPrototype const *proto = m_CastItem->GetProto())
|
|
if (proto->RequiredSkill == SKILL_ENGINERING)
|
|
if (uint16 skill202 = caster->ToPlayer()->GetSkillValue(SKILL_ENGINERING))
|
|
level = skill202/5;
|
|
|
|
//float radius = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
|
|
float radius = 5.0f;
|
|
int32 amount = damage > 0 ? damage : 1;
|
|
int32 duration = GetSpellDuration(m_spellInfo);
|
|
switch (m_spellInfo->Id)
|
|
{
|
|
case 1122: // Inferno
|
|
amount = 1;
|
|
break;
|
|
case 49028: // Dancing Rune Weapon
|
|
if (AuraEffect *aurEff = m_originalCaster->GetAuraEffect(63330, 0)) // glyph of Dancing Rune Weapon
|
|
duration += aurEff->GetAmount();
|
|
break;
|
|
}
|
|
if (Player* modOwner = m_originalCaster->GetSpellModOwner())
|
|
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
|
|
|
|
//TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
|
|
Map *map = caster->GetMap();
|
|
|
|
for (uint32 count = 0; count < amount; ++count)
|
|
{
|
|
Position pos;
|
|
GetSummonPosition(i, pos, radius, count);
|
|
|
|
TempSummon *summon = map->SummonCreature(entry, pos, properties, duration, caster);
|
|
if (!summon)
|
|
return;
|
|
if (summon->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
|
|
((Guardian*)summon)->InitStatsForLevel(level);
|
|
|
|
summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
|
|
if (summon->HasUnitTypeMask(UNIT_MASK_MINION) && m_targets.HasDst())
|
|
((Minion*)summon)->SetFollowAngle(m_caster->GetAngle(summon));
|
|
|
|
if (summon->GetEntry() == 27893)
|
|
if (uint32 weapon = m_caster->GetUInt32Value(PLAYER_VISIBLE_ITEM_16_ENTRYID))
|
|
{
|
|
summon->SetDisplayId(11686);
|
|
summon->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, weapon);
|
|
}
|
|
else
|
|
summon->SetDisplayId(1126);
|
|
|
|
summon->AI()->EnterEvadeMode();
|
|
}
|
|
}
|
|
|
|
void Spell::GetSummonPosition(uint32 i, Position &pos, float radius, uint32 count)
|
|
{
|
|
pos.SetOrientation(m_caster->GetOrientation());
|
|
|
|
if (m_targets.HasDst())
|
|
{
|
|
// Summon 1 unit in dest location
|
|
if (count == 0)
|
|
pos.Relocate(m_targets.m_dstPos);
|
|
// Summon in random point all other units if location present
|
|
else
|
|
{
|
|
//This is a workaround. Do not have time to write much about it
|
|
switch (m_spellInfo->EffectImplicitTargetA[i])
|
|
{
|
|
case TARGET_MINION:
|
|
case TARGET_DEST_CASTER_RANDOM:
|
|
m_caster->GetNearPosition(pos, radius * rand_norm(), rand_norm()*2*M_PI);
|
|
break;
|
|
case TARGET_DEST_DEST_RANDOM:
|
|
case TARGET_DEST_TARGET_RANDOM:
|
|
m_caster->GetRandomPoint(m_targets.m_dstPos, radius, pos);
|
|
break;
|
|
default:
|
|
pos.Relocate(m_targets.m_dstPos);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// Summon if dest location not present near caster
|
|
else
|
|
{
|
|
float x, y, z;
|
|
m_caster->GetClosePoint(x,y,z,3.0f);
|
|
pos.Relocate(x, y, z);
|
|
}
|
|
}
|
|
|
|
void Spell::EffectRenamePet(uint32 /*eff_idx*/)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT ||
|
|
!unitTarget->ToCreature()->isPet() || ((Pet*)unitTarget)->getPetType() != HUNTER_PET)
|
|
return;
|
|
|
|
unitTarget->RemoveByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED);
|
|
}
|
|
|
|
void Spell::EffectPlayMusic(uint32 i)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
uint32 soundid = m_spellInfo->EffectMiscValue[i];
|
|
|
|
if (!sSoundEntriesStore.LookupEntry(soundid))
|
|
{
|
|
sLog.outError("EffectPlayMusic: Sound (Id: %u) not exist in spell %u.",soundid,m_spellInfo->Id);
|
|
return;
|
|
}
|
|
|
|
WorldPacket data(SMSG_PLAY_MUSIC, 4);
|
|
data << uint32(soundid);
|
|
unitTarget->ToPlayer()->GetSession()->SendPacket(&data);
|
|
}
|
|
|
|
void Spell::EffectSpecCount(uint32 /*eff_idx*/)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
unitTarget->ToPlayer()->UpdateSpecCount(damage);
|
|
}
|
|
|
|
void Spell::EffectActivateSpec(uint32 /*eff_idx*/)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
unitTarget->ToPlayer()->ActivateSpec(damage-1); // damage is 1 or 2, spec is 0 or 1
|
|
}
|
|
|
|
void Spell::EffectPlayerNotification(uint32 /*eff_idx*/)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
switch(m_spellInfo->Id)
|
|
{
|
|
case 58730: // Restricted Flight Area
|
|
case 58600: // Restricted Flight Area
|
|
unitTarget->ToPlayer()->GetSession()->SendNotification(LANG_ZONE_NOFLYZONE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Spell::EffectRemoveAura(uint32 i)
|
|
{
|
|
if (!unitTarget)
|
|
return;
|
|
// there may be need of specifying casterguid of removed auras
|
|
unitTarget->RemoveAurasDueToSpell(m_spellInfo->EffectTriggerSpell[i]);
|
|
}
|
|
|
|
void Spell::EffectCastButtons(uint32 i)
|
|
{
|
|
if (!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player *p_caster = (Player*)m_caster;
|
|
uint32 button_id = m_spellInfo->EffectMiscValue[i] + 132;
|
|
uint32 n_buttons = m_spellInfo->EffectMiscValueB[i];
|
|
|
|
for (; n_buttons; n_buttons--, button_id++)
|
|
{
|
|
ActionButton const* ab = p_caster->GetActionButton(button_id);
|
|
if (!ab || ab->GetType() != ACTION_BUTTON_SPELL)
|
|
continue;
|
|
|
|
uint32 spell_id = ab->GetAction();
|
|
if (!spell_id)
|
|
continue;
|
|
|
|
if (p_caster->HasSpellCooldown(spell_id))
|
|
continue;
|
|
|
|
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
|
|
uint32 cost = CalculatePowerCost(spellInfo, m_caster, GetSpellSchoolMask(spellInfo));
|
|
|
|
if (m_caster->GetPower(POWER_MANA) < cost)
|
|
break;
|
|
|
|
m_caster->CastSpell(unitTarget, spell_id, true);
|
|
m_caster->ModifyPower(POWER_MANA, -(int32)cost);
|
|
p_caster->AddSpellAndCategoryCooldowns(spellInfo, 0);
|
|
}
|
|
}
|
|
|
|
void Spell::EffectRechargeManaGem(uint32 /*i*/)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player *player = (Player*)m_caster;
|
|
|
|
if (!player)
|
|
return;
|
|
|
|
uint32 item_id = m_spellInfo->EffectItemType[0];
|
|
|
|
ItemPrototype const *pProto = objmgr.GetItemPrototype(item_id);
|
|
if (!pProto)
|
|
{
|
|
player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
|
|
return;
|
|
}
|
|
|
|
if (Item* pItem = player->GetItemByEntry(item_id))
|
|
{
|
|
for (int x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x)
|
|
pItem->SetSpellCharges(x,pProto->Spells[x].SpellCharges);
|
|
pItem->SetState(ITEM_CHANGED,player);
|
|
}
|
|
}
|
|
|
|
void Spell::EffectBind(uint32 i)
|
|
{
|
|
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player* player = (Player*)unitTarget;
|
|
|
|
uint32 area_id;
|
|
WorldLocation loc;
|
|
if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_DST_DB || m_spellInfo->EffectImplicitTargetB[i] == TARGET_DST_DB)
|
|
{
|
|
SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id);
|
|
if (!st)
|
|
{
|
|
sLog.outError( "Spell::EffectBind - unknown teleport coordinates for spell ID %u", m_spellInfo->Id );
|
|
return;
|
|
}
|
|
|
|
loc.m_mapId = st->target_mapId;
|
|
loc.m_positionX = st->target_X;
|
|
loc.m_positionY = st->target_Y;
|
|
loc.m_positionZ = st->target_Y;
|
|
loc.m_orientation = st->target_Orientation;
|
|
area_id = player->GetAreaId();
|
|
}
|
|
else
|
|
{
|
|
player->GetPosition(&loc);
|
|
area_id = player->GetAreaId();
|
|
}
|
|
|
|
player->SetHomebind(loc, area_id);
|
|
|
|
// binding
|
|
WorldPacket data( SMSG_BINDPOINTUPDATE, (4+4+4+4+4) );
|
|
data << float(loc.m_positionX);
|
|
data << float(loc.m_positionY);
|
|
data << float(loc.m_positionZ);
|
|
data << uint32(loc.m_mapId);
|
|
data << uint32(area_id);
|
|
player->SendDirectMessage( &data );
|
|
|
|
DEBUG_LOG("New homebind X : %f", loc.m_positionX);
|
|
DEBUG_LOG("New homebind Y : %f", loc.m_positionY);
|
|
DEBUG_LOG("New homebind Z : %f", loc.m_positionZ);
|
|
DEBUG_LOG("New homebind MapId : %u", loc.m_mapId);
|
|
DEBUG_LOG("New homebind AreaId : %u", area_id);
|
|
|
|
// zone update
|
|
data.Initialize(SMSG_PLAYERBOUND, 8+4);
|
|
data << uint64(player->GetGUID());
|
|
data << uint32(area_id);
|
|
player->SendDirectMessage( &data );
|
|
}
|