PageRenderTime 362ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 3ms

/src/server/game/Entities/Unit/Unit.cpp

https://bitbucket.org/vitasic/gsv23.7
C++ | 12650 lines | 9953 code | 1410 blank | 1287 comment | 3557 complexity | 7ec1cff59d0e2ad064991a504da14235 MD5 | raw file
  1. /*
  2. * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
  3. *
  4. * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation; either version 2 of the License, or (at your
  9. * option) any later version.
  10. */
  11. #include "Common.h"
  12. #include "CreatureAIImpl.h"
  13. #include "Log.h"
  14. #include "Opcodes.h"
  15. #include "WorldPacket.h"
  16. #include "WorldSession.h"
  17. #include "World.h"
  18. #include "ObjectMgr.h"
  19. #include "SpellMgr.h"
  20. #include "Unit.h"
  21. #include "QuestDef.h"
  22. #include "Player.h"
  23. #include "Creature.h"
  24. #include "Spell.h"
  25. #include "Group.h"
  26. #include "SpellAuras.h"
  27. #include "SpellAuraEffects.h"
  28. #include "MapManager.h"
  29. #include "ObjectAccessor.h"
  30. #include "CreatureAI.h"
  31. #include "Formulas.h"
  32. #include "Pet.h"
  33. #include "Util.h"
  34. #include "Totem.h"
  35. #include "Battleground.h"
  36. #include "OutdoorPvP.h"
  37. #include "InstanceSaveMgr.h"
  38. #include "GridNotifiersImpl.h"
  39. #include "CellImpl.h"
  40. #include "CreatureGroups.h"
  41. #include "PetAI.h"
  42. #include "PassiveAI.h"
  43. #include "TemporarySummon.h"
  44. #include "Vehicle.h"
  45. #include "Transport.h"
  46. #include "InstanceScript.h"
  47. #include "MoveSplineInit.h"
  48. #include "MoveSpline.h"
  49. #include "PathFinder.h"
  50. #include <math.h>
  51. float baseMoveSpeed[MAX_MOVE_TYPE] =
  52. {
  53. 2.5f, // MOVE_WALK
  54. 7.0f, // MOVE_RUN
  55. 4.5f, // MOVE_RUN_BACK
  56. 4.722222f, // MOVE_SWIM
  57. 2.5f, // MOVE_SWIM_BACK
  58. 3.141594f, // MOVE_TURN_RATE
  59. 7.0f, // MOVE_FLIGHT
  60. 4.5f, // MOVE_FLIGHT_BACK
  61. 3.14f // MOVE_PITCH_RATE
  62. };
  63. float playerBaseMoveSpeed[MAX_MOVE_TYPE] = {
  64. 2.5f, // MOVE_WALK
  65. 7.0f, // MOVE_RUN
  66. 4.5f, // MOVE_RUN_BACK
  67. 4.722222f, // MOVE_SWIM
  68. 2.5f, // MOVE_SWIM_BACK
  69. 3.141594f, // MOVE_TURN_RATE
  70. 7.0f, // MOVE_FLIGHT
  71. 4.5f, // MOVE_FLIGHT_BACK
  72. 3.14f // MOVE_PITCH_RATE
  73. };
  74. // Used for prepare can/can`t triggr aura
  75. static bool InitTriggerAuraData();
  76. // Define can trigger auras
  77. static bool isTriggerAura[TOTAL_AURAS];
  78. // Define can`t trigger auras (need for disable second trigger)
  79. static bool isNonTriggerAura[TOTAL_AURAS];
  80. // Triggered always, even from triggered spells
  81. static bool isAlwaysTriggeredAura[TOTAL_AURAS];
  82. // Prepare lists
  83. static bool procPrepared = InitTriggerAuraData();
  84. DamageInfo::DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellEntry const* _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType)
  85. : m_attacker(_attacker), m_victim(_victim), m_damage(_damage), m_spellInfo(_spellInfo), m_schoolMask(_schoolMask),
  86. m_damageType(_damageType), m_attackType(BASE_ATTACK)
  87. {
  88. m_absorb = 0;
  89. m_resist = 0;
  90. m_block = 0;
  91. }
  92. DamageInfo::DamageInfo(CalcDamageInfo& dmgInfo)
  93. : m_attacker(dmgInfo.attacker), m_victim(dmgInfo.target), m_damage(dmgInfo.damage), m_spellInfo(NULL), m_schoolMask(SpellSchoolMask(dmgInfo.damageSchoolMask)),
  94. m_damageType(DIRECT_DAMAGE), m_attackType(dmgInfo.attackType)
  95. {
  96. m_absorb = 0;
  97. m_resist = 0;
  98. m_block = 0;
  99. }
  100. void DamageInfo::ModifyDamage(int32 amount)
  101. {
  102. amount = std::min(amount, int32(GetDamage()));
  103. m_damage += amount;
  104. }
  105. void DamageInfo::AbsorbDamage(uint32 amount)
  106. {
  107. amount = std::min(amount, GetDamage());
  108. m_absorb += amount;
  109. m_damage -= amount;
  110. }
  111. void DamageInfo::ResistDamage(uint32 amount)
  112. {
  113. amount = std::min(amount, GetDamage());
  114. m_resist += amount;
  115. m_damage -= amount;
  116. }
  117. void DamageInfo::BlockDamage(uint32 amount)
  118. {
  119. amount = std::min(amount, GetDamage());
  120. m_block += amount;
  121. m_damage -= amount;
  122. }
  123. static uint32 SpellFamilyNameByClass[] = {4, 10, 9, 8, 6, 15, 11, 3, 5, 18, 7};
  124. ProcEventInfo::ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
  125. :_actor(actor), _actionTarget(actionTarget), _procTarget(procTarget), _typeMask(typeMask), _spellTypeMask(spellTypeMask), _spellPhaseMask(spellPhaseMask),
  126. _hitMask(hitMask), _spell(spell), _damageInfo(damageInfo), _healInfo(healInfo) { }
  127. // we can disable this warning for this since it only
  128. // causes undefined behavior when passed to the base class constructor
  129. #ifdef _MSC_VER
  130. #pragma warning(disable:4355)
  131. #endif
  132. Unit::Unit(bool isWorldObject): WorldObject(isWorldObject),
  133. m_movedPlayer(NULL), m_lastSanctuaryTime(0), IsAIEnabled(false), NeedChangeAI(false),
  134. m_ControlledByPlayer(false), i_AI(NULL), i_disabledAI(NULL), m_procDeep(0),
  135. m_removedAurasCount(0), i_motionMaster(this), m_ThreatManager(this), m_vehicle(NULL),
  136. m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE), m_HostileRefManager(this), movespline(new Movement::MoveSpline())
  137. {
  138. #ifdef _MSC_VER
  139. #pragma warning(default:4355)
  140. #endif
  141. m_objectType |= TYPEMASK_UNIT;
  142. m_objectTypeId = TYPEID_UNIT;
  143. m_updateFlag = (UPDATEFLAG_LIVING | UPDATEFLAG_HAS_POSITION);
  144. m_attackTimer[BASE_ATTACK] = 0;
  145. m_attackTimer[OFF_ATTACK] = 0;
  146. m_attackTimer[RANGED_ATTACK] = 0;
  147. m_modAttackSpeedPct[BASE_ATTACK] = 1.0f;
  148. m_modAttackSpeedPct[OFF_ATTACK] = 1.0f;
  149. m_modAttackSpeedPct[RANGED_ATTACK] = 1.0f;
  150. m_extraAttacks = 0;
  151. m_canDualWield = false;
  152. m_rootTimes = 0;
  153. m_state = 0;
  154. m_deathState = ALIVE;
  155. for(uint8 i = 0; i < CURRENT_MAX_SPELL; ++i)
  156. m_currentSpells[i] = NULL;
  157. m_addDmgOnce = 0;
  158. for(uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
  159. m_SummonSlot[i] = 0;
  160. m_ObjectSlot[0] = m_ObjectSlot[1] = m_ObjectSlot[2] = m_ObjectSlot[3] = 0;
  161. m_auraUpdateIterator = m_ownedAuras.end();
  162. m_interruptMask = 0;
  163. m_transform = 0;
  164. m_canModifyStats = false;
  165. for(uint8 i = 0; i < MAX_SPELL_IMMUNITY; ++i)
  166. m_spellImmune[i].clear();
  167. for(uint8 i = 0; i < UNIT_MOD_END; ++i)
  168. {
  169. m_auraModifiersGroup[i][BASE_VALUE] = 0.0f;
  170. m_auraModifiersGroup[i][BASE_PCT] = 1.0f;
  171. m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f;
  172. m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f;
  173. }
  174. // implement 50% base damage from offhand
  175. m_auraModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f;
  176. for(uint8 i = 0; i < MAX_ATTACK; ++i)
  177. {
  178. m_weaponDamage[i][MINDAMAGE] = BASE_MINDAMAGE;
  179. m_weaponDamage[i][MAXDAMAGE] = BASE_MAXDAMAGE;
  180. }
  181. for(uint8 i = 0; i < MAX_STATS; ++i)
  182. m_createStats[i] = 0.0f;
  183. m_attacking = NULL;
  184. m_modMeleeHitChance = 0.0f;
  185. m_modRangedHitChance = 0.0f;
  186. m_modSpellHitChance = 0.0f;
  187. m_baseSpellCritChance = 5;
  188. m_CombatTimer = 0;
  189. m_lastManaUse = 0;
  190. for(uint8 i = 0; i < MAX_SPELL_SCHOOL; ++i)
  191. m_threatModifier[i] = 1.0f;
  192. m_isSorted = true;
  193. for(uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
  194. m_speed_rate[i] = 1.0f;
  195. m_charmInfo = NULL;
  196. m_reducedThreatPercent = 0;
  197. m_misdirectionTargetGUID = 0;
  198. // remove aurastates allowing special moves
  199. for(uint8 i = 0; i < MAX_REACTIVE; ++i)
  200. m_reactiveTimer[i] = 0;
  201. m_cleanupDone = false;
  202. m_duringRemoveFromWorld = false;
  203. m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE);
  204. _focusSpell = NULL;
  205. _targetLocked = false;
  206. m_lastLiquid = NULL;
  207. }
  208. bool GlobalCooldownMgr::HasGlobalCooldown(SpellEntry const* spellInfo) const
  209. {
  210. GlobalCooldownList::const_iterator itr = m_GlobalCooldowns.find(spellInfo->StartRecoveryCategory);
  211. return itr != m_GlobalCooldowns.end() && itr->second.duration && getMSTimeDiff(itr->second.cast_time, getMSTime()) < itr->second.duration;
  212. }
  213. void GlobalCooldownMgr::AddGlobalCooldown(SpellEntry const* spellInfo, uint32 gcd)
  214. {
  215. m_GlobalCooldowns[spellInfo->StartRecoveryCategory] = GlobalCooldown(gcd, getMSTime());
  216. }
  217. void GlobalCooldownMgr::CancelGlobalCooldown(SpellEntry const* spellInfo)
  218. {
  219. m_GlobalCooldowns[spellInfo->StartRecoveryCategory].duration = 0;
  220. }
  221. Unit::~Unit()
  222. {
  223. // set current spells as deletable
  224. for(uint8 i = 0; i < CURRENT_MAX_SPELL; ++i)
  225. {
  226. if(m_currentSpells[i])
  227. {
  228. m_currentSpells[i]->SetReferencedFromCurrent(false);
  229. m_currentSpells[i] = NULL;
  230. }
  231. }
  232. _DeleteRemovedAuras();
  233. // remove veiw point for spectator
  234. if (!m_sharedVision.empty())
  235. {
  236. for (SharedVisionList::iterator itr = m_sharedVision.begin(); itr != m_sharedVision.end(); ++itr)
  237. if ((*itr)->isSpectator() && (*itr)->getSpectateFrom())
  238. {
  239. (*itr)->SetViewpoint((*itr)->getSpectateFrom(), false);
  240. if (m_sharedVision.empty())
  241. break;
  242. --itr;
  243. }
  244. }
  245. delete m_charmInfo;
  246. delete m_vehicleKit;
  247. delete movespline;
  248. ASSERT(!m_duringRemoveFromWorld);
  249. ASSERT(!m_attacking);
  250. ASSERT(m_attackers.empty());
  251. ASSERT(m_sharedVision.empty());
  252. ASSERT(m_Controlled.empty());
  253. ASSERT(m_appliedAuras.empty());
  254. ASSERT(m_ownedAuras.empty());
  255. ASSERT(m_removedAuras.empty());
  256. ASSERT(m_gameObj.empty());
  257. ASSERT(m_dynObj.empty());
  258. }
  259. void Unit::Update(uint32 p_time)
  260. {
  261. m_Events.Update(p_time);
  262. if(!IsInWorld())
  263. return;
  264. _UpdateSpells(p_time);
  265. // If this is set during update SetCantProc(false) call is missing somewhere in the code
  266. // Having this would prevent spells from being proced, so let's crash
  267. ASSERT(!m_procDeep);
  268. if(CanHaveThreatList() && getThreatManager().isNeedUpdateToClient(p_time))
  269. SendThreatListUpdate();
  270. // update combat timer only for players and pets (only pets with PetAI)
  271. if(isInCombat() && (GetTypeId() == TYPEID_PLAYER || (ToCreature()->isPet() && IsControlledByPlayer())))
  272. {
  273. // Check UNIT_STAT_MELEE_ATTACKING or UNIT_STAT_CHASE (without UNIT_STAT_FOLLOW in this case) so pets can reach far away
  274. // targets without stopping half way there and running off.
  275. // These flags are reset after target dies or another command is given.
  276. if(m_HostileRefManager.isEmpty())
  277. {
  278. // m_CombatTimer set at aura start and it will be freeze until aura removing
  279. if(m_CombatTimer <= p_time)
  280. ClearInCombat();
  281. else
  282. m_CombatTimer -= p_time;
  283. }
  284. }
  285. // not implemented before 3.0.2
  286. //if(!HasUnitState(UNIT_STAT_CASTING))
  287. {
  288. if(uint32 base_att = getAttackTimer(BASE_ATTACK))
  289. setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time));
  290. if(uint32 ranged_att = getAttackTimer(RANGED_ATTACK))
  291. setAttackTimer(RANGED_ATTACK, (p_time >= ranged_att ? 0 : ranged_att - p_time));
  292. if(uint32 off_att = getAttackTimer(OFF_ATTACK))
  293. setAttackTimer(OFF_ATTACK, (p_time >= off_att ? 0 : off_att - p_time));
  294. }
  295. // update abilities available only for fraction of time
  296. UpdateReactives(p_time);
  297. if(isAlive())
  298. {
  299. ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, HealthBelowPct(20));
  300. ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, HealthBelowPct(35));
  301. ModifyAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, HealthAbovePct(75));
  302. }
  303. UpdateSplineMovement(p_time);
  304. i_motionMaster.UpdateMotion(p_time);
  305. }
  306. bool Unit::haveOffhandWeapon() const
  307. {
  308. if(GetTypeId() == TYPEID_PLAYER)
  309. return ToPlayer()->GetWeaponForAttack(OFF_ATTACK, true);
  310. else
  311. return m_canDualWield;
  312. }
  313. void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath, bool forceDestination)
  314. {
  315. Movement::MoveSplineInit init(*this);
  316. init.MoveTo(x, y, z, generatePath, forceDestination);
  317. init.SetVelocity(speed);
  318. init.Launch();
  319. }
  320. void Unit::UpdateSplineMovement(uint32 t_diff)
  321. {
  322. if(movespline->Finalized())
  323. return;
  324. movespline->updateState(t_diff);
  325. bool arrived = movespline->Finalized();
  326. if(arrived)
  327. DisableSpline();
  328. m_movesplineTimer.Update(t_diff);
  329. if(m_movesplineTimer.Passed() || arrived)
  330. {
  331. m_movesplineTimer.Reset(400 /*POSITION_UPDATE_DELAY*/);
  332. Movement::Location loc = movespline->ComputePosition();
  333. if(GetTypeId() == TYPEID_PLAYER)
  334. ((Player*)this)->SetPosition(loc.x,loc.y,loc.z,loc.orientation);
  335. else
  336. GetMap()->CreatureRelocation((Creature*)this,loc.x,loc.y,loc.z,loc.orientation);
  337. }
  338. }
  339. void Unit::DisableSpline()
  340. {
  341. m_movementInfo.RemoveMovementFlag(MovementFlags(MOVEMENTFLAG_SPLINE_ENABLED|MOVEMENTFLAG_FORWARD));
  342. movespline->_Interrupt();
  343. }
  344. void Unit::SendMonsterMoveExitVehicle(Position const* newPos)
  345. {
  346. WorldPacket data(SMSG_MONSTER_MOVE, 1+12+4+1+4+4+4+12+GetPackGUID().size());
  347. data.append(GetPackGUID());
  348. data << uint8(GetTypeId() == TYPEID_PLAYER ? 1 : 0); // new in 3.1, bool
  349. data << GetPositionX() << GetPositionY() << GetPositionZ();
  350. data << getMSTime();
  351. data << uint8(SPLINETYPE_FACING_ANGLE);
  352. data << float(GetOrientation()); // guess
  353. data << uint32(SPLINEFLAG_EXIT_VEHICLE);
  354. data << uint32(0); // Time in between points
  355. data << uint32(1); // 1 single waypoint
  356. data << newPos->GetPositionX();
  357. data << newPos->GetPositionY();
  358. data << newPos->GetPositionZ();
  359. SendMessageToSet(&data, true);
  360. }
  361. void Unit::SendMonsterMoveTransport(Unit* vehicleOwner)
  362. {
  363. // TODO: Turn into BuildMonsterMoveTransport packet and allow certain variables (for npc movement aboard vehicles)
  364. WorldPacket data(SMSG_MONSTER_MOVE_TRANSPORT, GetPackGUID().size()+vehicleOwner->GetPackGUID().size() + 47);
  365. data.append(GetPackGUID());
  366. data.append(vehicleOwner->GetPackGUID());
  367. data << int8(GetTransSeat());
  368. data << uint8(GetTypeId() == TYPEID_PLAYER ? 1 : 0); // boolean
  369. data << GetPositionX() - vehicleOwner->GetPositionX();
  370. data << GetPositionY() - vehicleOwner->GetPositionY();
  371. data << GetPositionZ() - vehicleOwner->GetPositionZ();
  372. data << uint32(getMSTime()); // should be an increasing constant that indicates movement packet count
  373. data << uint8(SPLINETYPE_FACING_ANGLE);
  374. data << GetTransOffsetO(); // facing angle?
  375. data << uint32(SPLINEFLAG_TRANSPORT);
  376. data << uint32(GetTransTime()); // move time
  377. data << uint32(1); // amount of waypoints
  378. data << uint32(0); // waypoint X
  379. data << uint32(0); // waypoint Y
  380. data << uint32(0); // waypoint Z
  381. SendMessageToSet(&data, true);
  382. }
  383. void Unit::resetAttackTimer(WeaponAttackType type)
  384. {
  385. m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]);
  386. }
  387. bool Unit::IsWithinCombatRange(const Unit* obj, float dist2compare) const
  388. {
  389. if(!obj || !IsInMap(obj)) return false;
  390. float dx = GetPositionX() - obj->GetPositionX();
  391. float dy = GetPositionY() - obj->GetPositionY();
  392. float dz = GetPositionZ() - obj->GetPositionZ();
  393. float distsq = dx*dx + dy*dy + dz*dz;
  394. float sizefactor = GetCombatReach() + obj->GetCombatReach();
  395. float maxdist = dist2compare + sizefactor;
  396. return distsq < maxdist * maxdist;
  397. }
  398. bool Unit::IsWithinMeleeRange(const Unit* obj, float dist) const
  399. {
  400. if(!obj || !IsInMap(obj)) return false;
  401. float dx = GetPositionX() - obj->GetPositionX();
  402. float dy = GetPositionY() - obj->GetPositionY();
  403. float dz = GetPositionZ() - obj->GetPositionZ();
  404. float distsq = dx*dx + dy*dy + dz*dz;
  405. float sizefactor = GetMeleeReach() + obj->GetMeleeReach();
  406. float maxdist = dist + sizefactor;
  407. return distsq < maxdist * maxdist;
  408. }
  409. void Unit::GetRandomContactPoint(const Unit* obj, float &x, float &y, float &z, float distance2dMin, float distance2dMax) const
  410. {
  411. float combat_reach = GetCombatReach();
  412. if(combat_reach < 0.1f) // sometimes bugged for players
  413. combat_reach = DEFAULT_COMBAT_REACH;
  414. uint32 attacker_number = getAttackers().size();
  415. if(attacker_number > 0)
  416. --attacker_number;
  417. GetNearPoint(obj, x, y, z, obj->GetCombatReach(), distance2dMin+(distance2dMax-distance2dMin) * (float)rand_norm()
  418. , GetAngle(obj) + (attacker_number ? (static_cast<float>(M_PI/2) - static_cast<float>(M_PI) * (float)rand_norm()) * float(attacker_number) / combat_reach * 0.3f : 0));
  419. }
  420. void Unit::SetVisibleAura(uint8 slot, AuraApplication * aur)
  421. {
  422. if (Aura* aura = aur->GetBase())
  423. if (Player *player = ToPlayer())
  424. if (player->HaveSpectators() && slot < MAX_AURAS)
  425. {
  426. SpectatorAddonMsg msg;
  427. uint64 casterID = 0;
  428. if (aura->GetCaster())
  429. casterID = (aura->GetCaster()->ToPlayer()) ? aura->GetCaster()->GetGUID() : 0;
  430. msg.SetPlayer(player->GetName());
  431. msg.CreateAura(casterID, aura->GetSpellProto()->Id,
  432. aur->IsPositive(), aura->GetSpellProto()->Dispel,
  433. aura->GetDuration(), aura->GetMaxDuration(),
  434. aura->GetStackAmount(), false);
  435. player->SendSpectatorAddonMsgToBG(msg);
  436. }
  437. m_visibleAuras[slot] = aur;
  438. UpdateAuraForGroup(slot);
  439. }
  440. void Unit::RemoveVisibleAura(uint8 slot)
  441. {
  442. AuraApplication *aurApp = GetVisibleAura(slot);
  443. if (aurApp && slot < MAX_AURAS)
  444. {
  445. if (Aura* aura = aurApp->GetBase())
  446. if (Player *player = ToPlayer())
  447. if (player->HaveSpectators())
  448. {
  449. SpectatorAddonMsg msg;
  450. uint64 casterID = 0;
  451. if (aura->GetCaster())
  452. casterID = (aura->GetCaster()->ToPlayer()) ? aura->GetCaster()->GetGUID() : 0;
  453. msg.SetPlayer(player->GetName());
  454. msg.CreateAura(casterID, aura->GetSpellProto()->Id,
  455. aurApp->IsPositive(), aura->GetSpellProto()->Dispel,
  456. aura->GetDuration(), aura->GetMaxDuration(),
  457. aura->GetStackAmount(), true);
  458. player->SendSpectatorAddonMsgToBG(msg);
  459. }
  460. }
  461. m_visibleAuras.erase(slot);
  462. UpdateAuraForGroup(slot);
  463. }
  464. void Unit::UpdateInterruptMask()
  465. {
  466. m_interruptMask = 0;
  467. for(AuraApplicationList::const_iterator i = m_interruptableAuras.begin(); i != m_interruptableAuras.end(); ++i)
  468. m_interruptMask |= (*i)->GetBase()->GetSpellProto()->AuraInterruptFlags;
  469. if(Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL])
  470. if(spell->getState() == SPELL_STATE_CASTING)
  471. m_interruptMask |= spell->m_spellInfo->ChannelInterruptFlags;
  472. }
  473. bool Unit::HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, uint32 familyFlags) const
  474. {
  475. if(!HasAuraType(auraType))
  476. return false;
  477. AuraEffectList const& auras = GetAuraEffectsByType(auraType);
  478. for(AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
  479. if(SpellEntry const* iterSpellProto = (*itr)->GetSpellProto())
  480. if(iterSpellProto->SpellFamilyName == familyName && iterSpellProto->SpellFamilyFlags[0] & familyFlags)
  481. return true;
  482. return false;
  483. }
  484. void Unit::DealDamageMods(Unit* victim, uint32 &damage, uint32* absorb)
  485. {
  486. if(!victim || !victim->isAlive() || victim->HasUnitState(UNIT_STAT_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode()))
  487. {
  488. if(absorb)
  489. *absorb += damage;
  490. damage = 0;
  491. return;
  492. }
  493. uint32 originalDamage = damage;
  494. if(absorb && originalDamage > damage)
  495. *absorb += (originalDamage - damage);
  496. }
  497. uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* pCleanDMG, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const* pSpell, bool durabilityLoss)
  498. {
  499. if(!pVictim)
  500. return 0;
  501. if(pVictim->IsAIEnabled)
  502. pVictim->GetAI()->DamageTaken(this, damage);
  503. if(IsAIEnabled)
  504. GetAI()->DamageDealt(pVictim, damage, damagetype);
  505. if(damage >= pVictim->GetHealth() && this->GetTypeId() == TYPEID_PLAYER)
  506. ((Player*)this)->UpdateKillingTimedAchievementProgress(pVictim->GetEntry(),pVictim->GetTypeId());
  507. if(damagetype != NODAMAGE)
  508. {
  509. // interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras)
  510. if(pSpell)
  511. {
  512. if(!(pSpell->AttributesEx4 & SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS))
  513. pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TAKE_DAMAGE, pSpell->Id);
  514. } else pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TAKE_DAMAGE, 0);
  515. // We're going to call functions which can modify content of the list during iteration over it's elements
  516. // Let's copy the list so we can prevent iterator invalidation
  517. AuraEffectList vCopyDamageCopy(pVictim->GetAuraEffectsByType(SPELL_AURA_SHARE_DAMAGE_PCT));
  518. // copy damage to casters of this aura
  519. for(AuraEffectList::iterator i = vCopyDamageCopy.begin(); i != vCopyDamageCopy.end(); ++i)
  520. {
  521. // Check if aura was removed during iteration - we don't need to work on such auras
  522. if(!((*i)->GetBase()->IsAppliedOnTarget(pVictim->GetGUID())))
  523. continue;
  524. // check damage school mask
  525. if(((*i)->GetMiscValue() & damageSchoolMask) == 0)
  526. continue;
  527. Unit* shareDamageTarget = (*i)->GetCaster();
  528. if(!shareDamageTarget)
  529. continue;
  530. SpellEntry const* spell = (*i)->GetSpellProto();
  531. uint32 share = CalculatePctN(damage, (*i)->GetAmount());
  532. // TODO: check packets if damage is done by pVictim, or by attacker of pVictim
  533. DealDamageMods(shareDamageTarget, share, NULL);
  534. DealDamage(shareDamageTarget, share, NULL, NODAMAGE, GetSpellSchoolMask(spell), spell, false);
  535. }
  536. }
  537. // Rage from Damage made (only from direct weapon damage)
  538. if(pCleanDMG && damagetype == DIRECT_DAMAGE && this != pVictim && getPowerType() == POWER_RAGE)
  539. {
  540. uint32 weaponSpeedHitFactor;
  541. uint32 rage_damage = damage + pCleanDMG->absorbed_damage;
  542. switch(pCleanDMG->attackType)
  543. {
  544. case BASE_ATTACK:
  545. {
  546. weaponSpeedHitFactor = uint32(GetAttackTime(pCleanDMG->attackType) / 1000.0f * 3.5f);
  547. if(pCleanDMG->hitOutCome == MELEE_HIT_CRIT)
  548. weaponSpeedHitFactor *= 2;
  549. RewardRage(rage_damage, weaponSpeedHitFactor, true);
  550. break;
  551. }
  552. case OFF_ATTACK:
  553. {
  554. weaponSpeedHitFactor = uint32(GetAttackTime(pCleanDMG->attackType) / 1000.0f * 1.75f);
  555. if(pCleanDMG->hitOutCome == MELEE_HIT_CRIT)
  556. weaponSpeedHitFactor *= 2;
  557. RewardRage(rage_damage, weaponSpeedHitFactor, true);
  558. break;
  559. }
  560. default:
  561. break;
  562. }
  563. }
  564. if(!damage)
  565. {
  566. // Rage from absorbed damage
  567. if(pCleanDMG && pCleanDMG->absorbed_damage && pVictim->getPowerType() == POWER_RAGE)
  568. pVictim->RewardRage(pCleanDMG->absorbed_damage, 0, false);
  569. return 0;
  570. }
  571. uint32 health = pVictim->GetHealth();
  572. // duel ends when player has 1 or less hp
  573. bool duel_hasEnded = false;
  574. bool duel_wasMounted = false;
  575. if(pVictim->GetTypeId() == TYPEID_PLAYER && pVictim->ToPlayer()->duel && damage >= (health-1))
  576. {
  577. // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
  578. if(pVictim->ToPlayer()->duel->opponent == this || pVictim->ToPlayer()->duel->opponent->GetGUID() == GetOwnerGUID())
  579. damage = health - 1;
  580. duel_hasEnded = true;
  581. } else if(pVictim->IsVehicle() && damage >= (health-1) && pVictim->GetCharmer() && pVictim->GetCharmer()->GetTypeId() == TYPEID_PLAYER) {
  582. Player* pPlayer = pVictim->GetCharmer()->ToPlayer();
  583. if(pPlayer && pPlayer->duel && pPlayer->duel->isMounted)
  584. {
  585. // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
  586. if(pPlayer->duel->opponent == this || pPlayer->duel->opponent->GetGUID() == GetCharmerGUID())
  587. damage = health - 1;
  588. duel_wasMounted = true;
  589. duel_hasEnded = true;
  590. }
  591. }
  592. if(GetTypeId() == TYPEID_PLAYER && this != pVictim)
  593. {
  594. Player* pKiller = ToPlayer();
  595. // in bg, count dmg if pVictim is also a player
  596. if(pVictim->GetTypeId() == TYPEID_PLAYER)
  597. if(Battleground* pBG = pKiller->GetBattleground())
  598. pBG->UpdatePlayerScore(pKiller, SCORE_DAMAGE_DONE, damage);
  599. pKiller->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, damage, 0, pVictim);
  600. pKiller->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT, damage);
  601. }
  602. if(pVictim->GetTypeId() == TYPEID_PLAYER)
  603. pVictim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED, damage);
  604. else if(!pVictim->IsControlledByPlayer() || pVictim->IsVehicle()) {
  605. if(!pVictim->ToCreature()->hasLootRecipient())
  606. pVictim->ToCreature()->SetLootRecipient(this);
  607. if(IsControlledByPlayer())
  608. pVictim->ToCreature()->LowerPlayerDamageReq(health < damage ? health : damage);
  609. }
  610. if(health <= damage)
  611. {
  612. if(pVictim->GetTypeId() == TYPEID_PLAYER && pVictim != this)
  613. {
  614. pVictim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, health);
  615. // call before auras are removed
  616. if(Player* pPlayer = GetCharmerOrOwnerPlayerOrPlayerItself())
  617. pPlayer->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL, 1, 0, pVictim);
  618. }
  619. // Heirloom trinkets on "kill a target that yields experience or honor" effect
  620. if(this->ToPlayer() && this->isAlive()) {
  621. if(this->ToPlayer()->isHonorOrXPTarget(pVictim)) {
  622. AuraEffectList const& heirloom = GetAuraEffectsByType(SPELL_AURA_DUMMY);
  623. for(AuraEffectList::const_iterator j = heirloom.begin(); j != heirloom.end(); ++j)
  624. {
  625. if((*j)->GetId() == 59915 && this->getPowerType() == POWER_MANA)
  626. this->CastSpell(this, 59914, true);
  627. if((*j)->GetId() == 59906)
  628. {
  629. int32 bonushealth = this->GetMaxHealth() * this->GetAura(59906)->GetEffect(0)->GetAmount() / 100;
  630. this->CastCustomSpell(this, 59913, &bonushealth, 0, 0, true);
  631. }
  632. }
  633. }
  634. }
  635. Kill(pVictim, durabilityLoss);
  636. } else {
  637. if(pVictim->GetTypeId() == TYPEID_PLAYER)
  638. pVictim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, damage);
  639. pVictim->ModifyHealth(- (int32)damage);
  640. if(damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE)
  641. pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE, pSpell ? pSpell->Id : 0);
  642. if(pVictim->GetTypeId() != TYPEID_PLAYER)
  643. pVictim->AddThreat(this, (float)damage, damageSchoolMask, pSpell);
  644. else { // pVictim is a player
  645. // random durability for items (HIT TAKEN)
  646. if(roll_chance_f(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE))) {
  647. EquipmentSlots slot = EquipmentSlots(urand(0, EQUIPMENT_SLOT_END-1));
  648. pVictim->ToPlayer()->DurabilityPointLossForEquipSlot(slot);
  649. }
  650. }
  651. // Rage from damage received
  652. if(this != pVictim && pVictim->getPowerType() == POWER_RAGE)
  653. {
  654. uint32 rage_damage = damage + (pCleanDMG ? pCleanDMG->absorbed_damage : 0);
  655. pVictim->RewardRage(rage_damage, 0, false);
  656. }
  657. if(GetTypeId() == TYPEID_PLAYER)
  658. {
  659. // random durability for items (HIT DONE)
  660. if(roll_chance_f(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE)))
  661. {
  662. EquipmentSlots slot = EquipmentSlots(urand(0, EQUIPMENT_SLOT_END-1));
  663. ToPlayer()->DurabilityPointLossForEquipSlot(slot);
  664. }
  665. }
  666. if(damagetype != NODAMAGE && damage)
  667. {
  668. if(pVictim != this && pVictim->GetTypeId() == TYPEID_PLAYER) // does not support creature push_back
  669. {
  670. if(damagetype != DOT)
  671. {
  672. if(Spell* pSpell = pVictim->m_currentSpells[CURRENT_GENERIC_SPELL])
  673. {
  674. if(pSpell->getState() == SPELL_STATE_PREPARING)
  675. {
  676. uint32 interruptFlags = pSpell->m_spellInfo->InterruptFlags;
  677. if(interruptFlags & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG)
  678. pVictim->InterruptNonMeleeSpells(false);
  679. else if(interruptFlags & SPELL_INTERRUPT_FLAG_PUSH_BACK)
  680. pSpell->Delayed();
  681. }
  682. }
  683. }
  684. if(Spell* pSpell = pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL])
  685. {
  686. if(pSpell->getState() == SPELL_STATE_CASTING)
  687. {
  688. uint32 channelInterruptFlags = pSpell->m_spellInfo->ChannelInterruptFlags;
  689. if(((channelInterruptFlags & CHANNEL_FLAG_DELAY) != 0) && (damagetype != DOT))
  690. pSpell->DelayedChannel();
  691. }
  692. }
  693. }
  694. }
  695. // last damage from duel opponent
  696. if(duel_hasEnded)
  697. {
  698. Player* pPlayer;
  699. duel_wasMounted ? pPlayer = pVictim->GetCharmer()->ToPlayer() : pPlayer = pVictim->ToPlayer();
  700. if(!pPlayer->isAlive())
  701. pPlayer->ResurrectPlayer(1.0f);
  702. pPlayer->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
  703. pPlayer->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
  704. pPlayer->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH);
  705. pPlayer->SetHealth(1);
  706. pPlayer->duel->opponent->CombatStopWithPets(true);
  707. pPlayer->CombatStopWithPets(true);
  708. pPlayer->CastSpell(pPlayer, 7267, true);
  709. pPlayer->DuelComplete(DUEL_WON);
  710. }
  711. }
  712. return damage;
  713. }
  714. void Unit::CastStop(uint32 except_spellid)
  715. {
  716. for(uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
  717. if(m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id != except_spellid)
  718. InterruptSpell(CurrentSpellTypes(i), false);
  719. }
  720. void Unit::CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
  721. {
  722. SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId);
  723. if(!spellInfo)
  724. {
  725. sLog->outError("CastSpell: unknown spell id %i by caster: %s %u)", spellId, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
  726. return;
  727. }
  728. CastSpell(Victim, spellInfo, triggered, castItem, triggeredByAura, originalCaster);
  729. }
  730. void Unit::CastSpell(Unit* Victim, SpellEntry const* spellInfo, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
  731. {
  732. if(!spellInfo)
  733. {
  734. sLog->outError("CastSpell: unknown spell by caster: %s %u)", (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
  735. return;
  736. }
  737. if(!originalCaster && GetTypeId() == TYPEID_UNIT && ToCreature()->isTotem() && IsControlledByPlayer())
  738. if(Unit* owner = GetOwner())
  739. originalCaster=owner->GetGUID();
  740. SpellCastTargets targets;
  741. targets.SetUnitTarget(Victim);
  742. if(castItem)
  743. sLog->outDebug(DebugLogFilters(LOG_FILTER_SPELLS_AURAS | LOG_FILTER_PLAYER_ITEMS), "WORLD: cast Item spellId - %i", spellInfo->Id);
  744. if(!originalCaster && triggeredByAura)
  745. originalCaster = triggeredByAura->GetCasterGUID();
  746. Spell* pSpell = new Spell(this, spellInfo, triggered, originalCaster);
  747. pSpell->m_CastItem = castItem;
  748. pSpell->prepare(&targets, triggeredByAura);
  749. }
  750. void Unit::CastCustomSpell(Unit* target, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
  751. {
  752. CustomSpellValues values;
  753. if(bp0)
  754. values.AddSpellMod(SPELLVALUE_BASE_POINT0, *bp0);
  755. if(bp1)
  756. values.AddSpellMod(SPELLVALUE_BASE_POINT1, *bp1);
  757. if(bp2)
  758. values.AddSpellMod(SPELLVALUE_BASE_POINT2, *bp2);
  759. CastCustomSpell(spellId, values, target, triggered, castItem, triggeredByAura, originalCaster);
  760. }
  761. void Unit::CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* target, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
  762. {
  763. CustomSpellValues values;
  764. values.AddSpellMod(mod, value);
  765. CastCustomSpell(spellId, values, target, triggered, castItem, triggeredByAura, originalCaster);
  766. }
  767. void Unit::CastCustomSpell(uint32 spellId, CustomSpellValues const& value, Unit* Victim, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
  768. {
  769. SpellEntry const* pSpellInfo = sSpellStore.LookupEntry(spellId);
  770. if(!pSpellInfo)
  771. {
  772. sLog->outError("CastSpell: unknown spell id %i by caster: %s %u)", spellId, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
  773. return;
  774. }
  775. SpellCastTargets targets;
  776. targets.SetUnitTarget(Victim);
  777. if(!originalCaster && triggeredByAura)
  778. originalCaster = triggeredByAura->GetCasterGUID();
  779. Spell* pSpell = new Spell(this, pSpellInfo, triggered, originalCaster);
  780. if(castItem)
  781. {
  782. sLog->outDebug(DebugLogFilters(LOG_FILTER_SPELLS_AURAS | LOG_FILTER_PLAYER_ITEMS), "WORLD: cast Item spellId - %i", pSpellInfo->Id);
  783. pSpell->m_CastItem = castItem;
  784. }
  785. for(CustomSpellValues::const_iterator itr = value.begin(); itr != value.end(); ++itr)
  786. pSpell->SetSpellValue(itr->first, itr->second);
  787. pSpell->prepare(&targets, triggeredByAura);
  788. }
  789. // used for scripting
  790. void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster, Unit* OriginalVictim)
  791. {
  792. SpellEntry const* pSpellInfo = sSpellStore.LookupEntry(spellId);
  793. if(!pSpellInfo)
  794. {
  795. sLog->outError("CastSpell(x, y, z): unknown spell id %i by caster: %s %u)", spellId, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
  796. return;
  797. }
  798. if(castItem)
  799. sLog->outDebug(DebugLogFilters(LOG_FILTER_SPELLS_AURAS | LOG_FILTER_PLAYER_ITEMS), "WORLD: cast Item spellId - %i", pSpellInfo->Id);
  800. if(!originalCaster && triggeredByAura)
  801. originalCaster = triggeredByAura->GetCasterGUID();
  802. Spell* pSpell = new Spell(this, pSpellInfo, triggered, originalCaster);
  803. SpellCastTargets targets;
  804. targets.SetDst(x, y, z, GetOrientation());
  805. if(OriginalVictim)
  806. targets.SetUnitTarget(OriginalVictim);
  807. pSpell->m_CastItem = castItem;
  808. pSpell->prepare(&targets, triggeredByAura);
  809. }
  810. void Unit::CastSpell(GameObject* pGO, uint32 spellId, bool triggered, Item* castItem, AuraEffect* triggeredByAura, uint64 originalCaster)
  811. {
  812. if(!pGO)
  813. return;
  814. SpellEntry const* pSpellInfo = sSpellStore.LookupEntry(spellId);
  815. if(!pSpellInfo)
  816. {
  817. sLog->outError("CastSpell(x, y, z): unknown spell id %i by caster: %s %u)", spellId, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
  818. return;
  819. }
  820. if(castItem)
  821. sLog->outDebug(DebugLogFilters(LOG_FILTER_SPELLS_AURAS | LOG_FILTER_PLAYER_ITEMS), "WORLD: cast Item spellId - %i", pSpellInfo->Id);
  822. if(!originalCaster && triggeredByAura)
  823. originalCaster = triggeredByAura->GetCasterGUID();
  824. Spell* pSpell = new Spell(this, pSpellInfo, triggered, originalCaster);
  825. SpellCastTargets targets;
  826. targets.SetGOTarget(pGO);
  827. pSpell->m_CastItem = castItem;
  828. pSpell->prepare(&targets, triggeredByAura);
  829. }
  830. // Obsolete func need remove, here only for comotability vs another patches
  831. uint32 Unit::SpellNonMeleeDamageLog(Unit* victim, uint32 spellID, uint32 damage)
  832. {
  833. SpellEntry const* pSpellInfo = sSpellStore.LookupEntry(spellID);
  834. SpellNonMeleeDamage damageInfo(this, victim, pSpellInfo->Id, pSpellInfo->SchoolMask);
  835. damage = SpellDamageBonus(victim, pSpellInfo, damage, SPELL_DIRECT_DAMAGE);
  836. CalculateSpellDamageTaken(&damageInfo, damage, pSpellInfo);
  837. DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
  838. SendSpellNonMeleeDamageLog(&damageInfo);
  839. DealSpellDamage(&damageInfo, true);
  840. return damageInfo.damage;
  841. }
  842. void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 damage, SpellEntry const* spellInfo, WeaponAttackType attackType, bool crit)
  843. {
  844. if(damage < 0)
  845. return;
  846. Unit* victim = damageInfo->target;
  847. if(!victim || !victim->isAlive())
  848. return;
  849. SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask);
  850. uint32 crTypeMask = victim->GetCreatureTypeMask();
  851. if(IsDamageReducedByArmor(damageSchoolMask, spellInfo))
  852. damage = CalcArmorReducedDamage(victim, damage, spellInfo, attackType);
  853. bool blocked = false;
  854. // Per-school calc
  855. switch(spellInfo->DmgClass)
  856. {
  857. // Melee and Ranged Spells
  858. case SPELL_DAMAGE_CLASS_RANGED:
  859. case SPELL_DAMAGE_CLASS_MELEE:
  860. {
  861. // Physical Damage
  862. if(damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL)
  863. {
  864. // Get blocked status
  865. blocked = isSpellBlocked(victim, spellInfo, attackType);
  866. }
  867. if(crit)
  868. {
  869. damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
  870. // Calculate crit bonus
  871. uint32 crit_bonus = damage;
  872. // Apply crit_damage bonus for melee spells
  873. if(Player* modOwner = GetSpellModOwner())
  874. modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
  875. damage += crit_bonus;
  876. // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
  877. float critPctDamageMod = 0.0f;
  878. if(attackType == RANGED_ATTACK)
  879. critPctDamageMod += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE);
  880. else
  881. critPctDamageMod += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
  882. // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
  883. critPctDamageMod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, GetSpellSchoolMask(spellInfo)) - 1.0f) * 100;
  884. // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
  885. critPctDamageMod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask);
  886. if(critPctDamageMod != 0)
  887. AddPctF(damage, critPctDamageMod);
  888. }
  889. // Spell weapon based damage CAN BE crit & blocked at same time
  890. if(blocked)
  891. {
  892. damageInfo->blocked = victim->GetShieldBlockValue();
  893. // double blocked amount if block is critical
  894. if(victim->isBlockCritical())
  895. damageInfo->blocked += damageInfo->blocked;
  896. if(damage < int32(damageInfo->blocked))
  897. damageInfo->blocked = uint32(damage);
  898. damage -= damageInfo->blocked;
  899. }
  900. if(attackType != RANGED_ATTACK)
  901. ApplyResilience(victim, NULL, &damage, crit, CR_CRIT_TAKEN_MELEE);
  902. else
  903. ApplyResilience(victim, NULL, &damage, crit, CR_CRIT_TAKEN_RANGED);
  904. break;
  905. }
  906. // Magical Attacks
  907. case SPELL_DAMAGE_CLASS_NONE:
  908. case SPELL_DAMAGE_CLASS_MAGIC:
  909. {
  910. // If crit add critical bonus
  911. if(crit)
  912. {
  913. damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
  914. damage = SpellCriticalDamageBonus(spellInfo, damage, victim);
  915. }
  916. ApplyResilience(victim, NULL, &damage, crit, CR_CRIT_TAKEN_SPELL);
  917. break;
  918. }
  919. default:
  920. break;
  921. }
  922. // Calculate absorb resist
  923. if(damage > 0)
  924. {
  925. CalcAbsorbResist(victim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist, spellInfo);
  926. damage -= damageInfo->absorb + damageInfo->resist;
  927. }
  928. else
  929. damage = 0;
  930. damageInfo->damage = damage;
  931. }
  932. void Unit::DealSpellDamage(SpellNonMeleeDamage* pDamageInfo, bool durabilityLoss)
  933. {
  934. if(pDamageInfo == 0)
  935. return;
  936. Unit* victim = pDamageInfo->target;
  937. if(!victim)
  938. return;
  939. if(!victim->isAlive() || victim->HasUnitState(UNIT_STAT_IN_FLIGHT) || (victim->HasUnitState(UNIT_STAT_ONVEHICLE) && victim->GetVehicleBase() != this) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode()))
  940. return;
  941. SpellEntry const* pSpellEntry = sSpellStore.LookupEntry(pDamageInfo->SpellID);
  942. if(pSpellEntry == NULL)
  943. {
  944. sLog->outDebug(LOG_FILTER_UNITS, "Unit::DealSpellDamage have wrong damageInfo->SpellID: %u", pDamageInfo->SpellID);
  945. return;
  946. }
  947. // Call default DealDamage
  948. CleanDamage cleanDamage(pDamageInfo->cleanDamage, pDamageInfo->absorb, BASE_ATTACK, MELEE_HIT_NORMAL);
  949. DealDamage(victim, pDamageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(pDamageInfo->schoolMask), pSpellEntry, durabilityLoss);
  950. }
  951. // TODO for melee need create structure as in
  952. void Unit::CalculateMeleeDamage(Unit* pVictim, uint32 damage, CalcDamageInfo* pDamageInfo, WeaponAttackType attackType)
  953. {
  954. pDamageInfo->attacker = this;
  955. pDamageInfo->target = pVictim;
  956. pDamageInfo->damageSchoolMask = GetMeleeDamageSchoolMask();
  957. pDamageInfo->attackType = attackType;
  958. pDamageInfo->damage = 0;
  959. pDamageInfo->cleanDamage = 0;
  960. pDamageInfo->absorb = 0;
  961. pDamageInfo->resist = 0;
  962. pDamageInfo->blocked_amount = 0;
  963. pDamageInfo->TargetState = 0;
  964. pDamageInfo->HitInfo = 0;
  965. pDamageInfo->procAttacker = PROC_FLAG_NONE;
  966. pDamageInfo->procVictim = PROC_FLAG_NONE;
  967. pDamageInfo->procEx = PROC_EX_NONE;
  968. pDamageInfo->hitOutCome = MELEE_HIT_EVADE;
  969. if(!pVictim)
  970. return;
  971. if(!isAlive() || !pVictim->isAlive())
  972. return;
  973. // Select HitInfo/procAttacker/procVictim flag based on attack type
  974. switch(attackType)
  975. {
  976. case BASE_ATTACK:
  977. {
  978. pDamageInfo->procAttacker = PROC_FLAG_DONE_MELEE_AUTO_ATTACK | PROC_FLAG_DONE_MAINHAND_ATTACK;
  979. pDamageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK;
  980. pDamageInfo->HitInfo = HITINFO_NORMALSWING2;
  981. break;
  982. }
  983. case OFF_ATTACK:
  984. {
  985. pDamageInfo->procAttacker = PROC_FLAG_DONE_MELEE_AUTO_ATTACK | PROC_FLAG_DONE_OFFHAND_ATTACK;
  986. pDamageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK;
  987. pDamageInfo->HitInfo = HITINFO_LEFTSWING;
  988. break;
  989. }
  990. default:
  991. return;
  992. }
  993. // Physical Immune check
  994. if(pDamageInfo->target->IsImmunedToDamage(SpellSchoolMask(pDamageInfo->damageSchoolMask)))
  995. {
  996. pDamageInfo->HitInfo |= HITINFO_NORMALSWING;
  997. pDamageInfo->TargetState = VICTIMSTATE_IS_IMMUNE;
  998. pDamageInfo->procEx |= PROC_EX_IMMUNE;
  999. pDamageInfo->damage = 0;
  1000. pDamageInfo->cleanDamage = 0;
  1001. return;
  1002. }
  1003. damage += CalculateDamage(pDamageInfo->attackType, false, true);
  1004. // Add melee damage bonus
  1005. MeleeDamageBonus(pDamageInfo->target, &damage, pDamageInfo->attackType);
  1006. // Calculate armor reduction
  1007. if(IsDamageReducedByArmor((SpellSchoolMask)(pDamageInfo->damageSchoolMask)))
  1008. {
  1009. pDamageInfo->damage = CalcArmorReducedDamage(pDamageInfo->target, damage, NULL, pDamageInfo->attackType);
  1010. pDamageInfo->cleanDamage += damage - pDamageInfo->damage;
  1011. } else pDamageInfo->damage = damage;
  1012. pDamageInfo->hitOutCome = RollMeleeOutcomeAgainst(pDamageInfo->target, pDamageInfo->attackType);
  1013. switch(pDamageInfo->hitOutCome)
  1014. {
  1015. case MELEE_HIT_EVADE:
  1016. {
  1017. pDamageInfo->HitInfo |= HITINFO_MISS|HITINFO_SWINGNOHITSOUND;
  1018. pDamageInfo->TargetState = VICTIMSTATE_EVADES;
  1019. pDamageInfo->procEx|=PROC_EX_EVADE;
  1020. pDamageInfo->damage = 0;
  1021. pDamageInfo->cleanDamage = 0;
  1022. return;
  1023. }
  1024. case MELEE_HIT_MISS:
  1025. {
  1026. pDamageInfo->HitInfo |= HITINFO_MISS;
  1027. pDamageInfo->TargetState = VICTIMSTATE_INTACT;
  1028. pDamageInfo->procEx |= PROC_EX_MISS;
  1029. pDamageInfo->damage = 0;
  1030. pDamageInfo->cleanDamage = 0;
  1031. break;
  1032. }
  1033. case MELEE_HIT_NORMAL:
  1034. {
  1035. pDamageInfo->TargetState = VICTIMSTATE_HIT;
  1036. pDamageInfo->procEx|=PROC_EX_NORMAL_HIT;
  1037. break;
  1038. }
  1039. case MELEE_HIT_CRIT:
  1040. {
  1041. pDamageInfo->HitInfo |= HITINFO_CRITICALHIT;
  1042. pDamageInfo->TargetState = VICTIMSTATE_HIT;
  1043. pDamageInfo->procEx |= PROC_EX_CRITICAL_HIT;
  1044. // Crit bonus calc
  1045. pDamageInfo->damage += pDamageInfo->damage;
  1046. float mod = 0.0f;
  1047. // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
  1048. if(pDamageInfo->attackType == RANGED_ATTACK)
  1049. mod += pDamageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE);
  1050. else
  1051. mod += pDamageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
  1052. // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
  1053. mod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, pDamageInfo->damageSchoolMask) - 1.0f) * 100;
  1054. uint32 crTypeMask = pDamageInfo->target->GetCreatureTypeMask();
  1055. // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
  1056. mod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask);
  1057. if(mod != 0)
  1058. AddPctF(pDamageInfo->damage, mod);
  1059. break;
  1060. }
  1061. case MELEE_HIT_PARRY:
  1062. {
  1063. pDamageInfo->TargetState = VICTIMSTATE_PARRY;
  1064. pDamageInfo->procEx |= PROC_EX_PARRY;
  1065. pDamageInfo->cleanDamage += pDamageInfo->damage;
  1066. pDamageInfo->damage = 0;
  1067. break;
  1068. }
  1069. case MELEE_HIT_DODGE:
  1070. {
  1071. pDamageInfo->TargetState = VICTIMSTATE_DODGE;
  1072. pDamageInfo->procEx |= PROC_EX_DODGE;
  1073. pDamageInfo->cleanDamage += pDamageInfo->damage;
  1074. pDamageInfo->damage = 0;
  1075. break;
  1076. }
  1077. case MELEE_HIT_BLOCK:
  1078. {
  1079. pDamageInfo->TargetState = VICTIMSTATE_HIT;
  1080. pDamageInfo->HitInfo |= HITINFO_BLOCK;
  1081. pDamageInfo->procEx |= PROC_EX_BLOCK;
  1082. pDamageInfo->blocked_amount = pDamageInfo->target->GetShieldBlockValue();
  1083. if(pDamageInfo->target->isBlockCritical())
  1084. pDamageInfo->blocked_amount+=pDamageInfo->blocked_amount;
  1085. if(pDamageInfo->blocked_amount >= pDamageInfo->damage)
  1086. {
  1087. pDamageInfo->TargetState = VICTIMSTATE_BLOCKS;
  1088. pDamageInfo->blocked_amount = pDamageInfo->damage;
  1089. pDamageInfo->procEx |= PROC_EX_FULL_BLOCK;
  1090. } else pDamageInfo->procEx |= PROC_EX_NORMAL_HIT;
  1091. pDamageInfo->damage -= pDamageInfo->blocked_amount;
  1092. pDamageInfo->cleanDamage += pDamageInfo->blocked_amount;
  1093. break;
  1094. }
  1095. case MELEE_HIT_GLANCING:
  1096. {
  1097. pDamageInfo->HitInfo |= HITINFO_GLANCING;
  1098. pDamageInfo->TargetState = VICTIMSTATE_HIT;
  1099. pDamageInfo->procEx |= PROC_EX_NORMAL_HIT;
  1100. int32 leveldif = int32(pVictim->getLevel()) - int32(getLevel());
  1101. if(leveldif > 3)
  1102. leveldif = 3;
  1103. float reducePercent = 1 - leveldif * 0.1f;
  1104. pDamageInfo->cleanDamage += pDamageInfo->damage-uint32(reducePercent * pDamageInfo->damage);
  1105. pDamageInfo->damage = uint32(reducePercent * pDamageInfo->damage);
  1106. break;
  1107. }
  1108. case MELEE_HIT_CRUSHING:
  1109. {
  1110. pDamageInfo->HitInfo |= HITINFO_CRUSHING;
  1111. pDamageInfo->TargetState = VICTIMSTATE_HIT;
  1112. pDamageInfo->procEx |= PROC_EX_NORMAL_HIT;
  1113. // 150% normal damage
  1114. pDamageInfo->damage += (pDamageInfo->damage / 2);
  1115. break;
  1116. }
  1117. default:
  1118. break;
  1119. }
  1120. int32 resilienceReduction = pDamageInfo->damage;
  1121. if(attackType != RANGED_ATTACK)
  1122. ApplyResilience(pVictim, NULL, &resilienceReduction, (pDamageInfo->hitOutCome == MELEE_HIT_CRIT), CR_CRIT_TAKEN_MELEE);
  1123. else
  1124. ApplyResilience(pVictim, NULL, &resilienceReduction, (pDamageInfo->hitOutCome == MELEE_HIT_CRIT), CR_CRIT_TAKEN_RANGED);
  1125. resilienceReduction = pDamageInfo->damage - resilienceReduction;
  1126. pDamageInfo->damage -= resilienceReduction;
  1127. pDamageInfo->cleanDamage += resilienceReduction;
  1128. // Calculate absorb resist
  1129. if(int32(pDamageInfo->damage) > 0)
  1130. {
  1131. pDamageInfo->procVictim |= PROC_FLAG_TAKEN_DAMAGE;
  1132. // Calculate absorb & resists
  1133. CalcAbsorbResist(pDamageInfo->target, SpellSchoolMask(pDamageInfo->damageSchoolMask), DIRECT_DAMAGE, pDamageInfo->damage, &pDamageInfo->absorb, &pDamageInfo->resist);
  1134. pDamageInfo->damage -= pDamageInfo->absorb + pDamageInfo->resist;
  1135. if(pDamageInfo->absorb)
  1136. {
  1137. pDamageInfo->HitInfo |= HITINFO_ABSORB;
  1138. pDamageInfo->procEx |= PROC_EX_ABSORB;
  1139. }
  1140. if(pDamageInfo->resist)
  1141. pDamageInfo->HitInfo |= HITINFO_RESIST;
  1142. }
  1143. else // Impossible get negative result but....
  1144. pDamageInfo->damage = 0;
  1145. }
  1146. void Unit::DealMeleeDamage(CalcDamageInfo* pDamageInfo, bool durabilityLoss)
  1147. {
  1148. Unit* victim = pDamageInfo->target;
  1149. if(!victim->isAlive() || victim->HasUnitState(UNIT_STAT_IN_FLIGHT) || (victim->HasUnitState(UNIT_STAT_ONVEHICLE) && victim->GetVehicleBase() != this) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode()))
  1150. return;
  1151. // Hmmmm dont like this emotes client must by self do all animations
  1152. if(pDamageInfo->HitInfo & HITINFO_CRITICALHIT)
  1153. victim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL);
  1154. if(pDamageInfo->blocked_amount && pDamageInfo->TargetState != VICTIMSTATE_BLOCKS)
  1155. victim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD);
  1156. if(pDamageInfo->TargetState == VICTIMSTATE_PARRY)
  1157. {
  1158. // Get attack timers
  1159. float offtime = float(victim->getAttackTimer(OFF_ATTACK));
  1160. float basetime = float(victim->getAttackTimer(BASE_ATTACK));
  1161. // Reduce attack time
  1162. if(victim->haveOffhandWeapon() && offtime < basetime)
  1163. {
  1164. float percent20 = victim->GetAttackTime(OFF_ATTACK) * 0.20f;
  1165. float percent60 = 3.0f * percent20;
  1166. if(offtime > percent20 && offtime <= percent60)
  1167. victim->setAttackTimer(OFF_ATTACK, uint32(percent20));
  1168. else if(offtime > percent60)
  1169. {
  1170. offtime -= 2.0f * percent20;
  1171. victim->setAttackTimer(OFF_ATTACK, uint32(offtime));
  1172. }
  1173. } else {
  1174. float percent20 = victim->GetAttackTime(BASE_ATTACK) * 0.20f;
  1175. float percent60 = 3.0f * percent20;
  1176. if(basetime > percent20 && basetime <= percent60)
  1177. victim->setAttackTimer(BASE_ATTACK, uint32(percent20));
  1178. else if(basetime > percent60)
  1179. {
  1180. basetime -= 2.0f * percent20;
  1181. victim->setAttackTimer(BASE_ATTACK, uint32(basetime));
  1182. }
  1183. }
  1184. }
  1185. // Call default DealDamage
  1186. CleanDamage cleanDamage(pDamageInfo->cleanDamage, pDamageInfo->absorb, pDamageInfo->attackType, pDamageInfo->hitOutCome);
  1187. DealDamage(victim, pDamageInfo->damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(pDamageInfo->damageSchoolMask), NULL, durabilityLoss);
  1188. // If this is a creature and it attacks from behind it has a probability to daze it's victim
  1189. if((pDamageInfo->hitOutCome == MELEE_HIT_CRIT || pDamageInfo->hitOutCome == MELEE_HIT_CRUSHING || pDamageInfo->hitOutCome == MELEE_HIT_NORMAL || pDamageInfo->hitOutCome == MELEE_HIT_GLANCING) &&
  1190. GetTypeId() != TYPEID_PLAYER && !ToCreature()->IsControlledByPlayer() && !victim->HasInArc(M_PI, this)
  1191. && (victim->GetTypeId() == TYPEID_PLAYER || !victim->ToCreature()->isWorldBoss()))
  1192. {
  1193. // -probability is between 0% and 40%
  1194. // 20% base chance
  1195. float Probability = 20.0f;
  1196. // there is a newbie protection, at level 10 just 7% base chance; assuming linear function
  1197. if(victim->getLevel() < 30)
  1198. Probability = 0.65f * victim->getLevel() + 0.5f;
  1199. uint32 VictimDefense = victim->GetDefenseSkillValue();
  1200. uint32 AttackerMeleeSkill = GetUnitMeleeSkill();
  1201. VictimDefense = VictimDefense > 1 ? VictimDefense : 1;
  1202. Probability *= AttackerMeleeSkill/VictimDefense;
  1203. if(Probability > 40.0f)
  1204. Probability = 40.0f;
  1205. if(roll_chance_f(Probability))
  1206. CastSpell(victim, 1604, true);
  1207. }
  1208. if(GetTypeId() == TYPEID_PLAYER)
  1209. ToPlayer()->CastItemCombatSpell(victim, pDamageInfo->attackType, pDamageInfo->procVictim, pDamageInfo->procEx);
  1210. // Do effect if any damage done to target
  1211. if(pDamageInfo->damage)
  1212. {
  1213. // We're going to call functions which can modify content of the list during iteration over it's elements
  1214. // Let's copy the list so we can prevent iterator invalidation
  1215. AuraEffectList vDamageShieldsCopy(victim->GetAuraEffectsByType(SPELL_AURA_DAMAGE_SHIELD));
  1216. for(AuraEffectList::const_iterator dmgShieldItr = vDamageShieldsCopy.begin(); dmgShieldItr != vDamageShieldsCopy.end(); ++dmgShieldItr)
  1217. {
  1218. SpellEntry const* i_spellProto = (*dmgShieldItr)->GetSpellProto();
  1219. // Damage shield can be resisted...
  1220. if(SpellMissInfo missInfo = victim->SpellHitResult(this, i_spellProto, false))
  1221. {
  1222. victim->SendSpellMiss(this, i_spellProto->Id, missInfo);
  1223. continue;
  1224. }
  1225. // ...or immuned
  1226. if(IsImmunedToDamage(i_spellProto))
  1227. {
  1228. victim->SendSpellDamageImmune(this, i_spellProto->Id);
  1229. continue;
  1230. }
  1231. uint32 damage = (*dmgShieldItr)->GetAmount();
  1232. if(Unit* caster = (*dmgShieldItr)->GetCaster())
  1233. damage = caster->SpellDamageBonus(this, i_spellProto, damage, SPELL_DIRECT_DAMAGE);
  1234. // No Unit::CalcAbsorbResist here - opcode doesn't send that data - this damage is probably not affected by that
  1235. victim->DealDamageMods(this, damage, NULL);
  1236. // TODO: Move this to a packet handler
  1237. WorldPacket data(SMSG_SPELLDAMAGESHIELD, (8+8+4+4+4+4));
  1238. data << uint64(victim->GetGUID());
  1239. data << uint64(GetGUID());
  1240. data << uint32(i_spellProto->Id);
  1241. data << uint32(damage); // Damage
  1242. int32 overkill = int32(damage) - int32(GetHealth());
  1243. data << uint32(overkill > 0 ? overkill : 0); // Overkill
  1244. data << uint32(i_spellProto->SchoolMask);
  1245. victim->SendMessageToSet(&data, true);
  1246. victim->DealDamage(this, damage, 0, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(i_spellProto), i_spellProto, true);
  1247. }
  1248. }
  1249. }
  1250. void Unit::HandleEmoteCommand(uint32 anim_id)
  1251. {
  1252. WorldPacket data(SMSG_EMOTE, 4 + 8);
  1253. data << uint32(anim_id);
  1254. data << uint64(GetGUID());
  1255. SendMessageToSet(&data, true);
  1256. }
  1257. bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellEntry const* spellInfo, uint8 effIndex)
  1258. {
  1259. // only physical spells damage gets reduced by armor
  1260. if((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
  1261. return false;
  1262. if(spellInfo)
  1263. {
  1264. // there are spells with no specific attribute but they have "ignores armor" in tooltip
  1265. if(sSpellMgr->GetSpellCustomAttr(spellInfo->Id) & SPELL_ATTR0_CU_IGNORE_ARMOR)
  1266. return false;
  1267. // bleeding effects are not reduced by armor
  1268. if(effIndex != MAX_SPELL_EFFECTS && spellInfo->EffectApplyAuraName[effIndex] == SPELL_AURA_PERIODIC_DAMAGE)
  1269. if(GetSpellMechanicMask(spellInfo, effIndex) & (1<<MECHANIC_BLEED))
  1270. return false;
  1271. }
  1272. return true;
  1273. }
  1274. uint32 Unit::CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellEntry const* spellInfo, WeaponAttackType /*attackType*/)
  1275. {
  1276. uint32 newdamage = 0;
  1277. float armor = float(victim->GetArmor());
  1278. // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
  1279. armor += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_NORMAL);
  1280. if(spellInfo)
  1281. if(Player* modOwner = GetSpellModOwner())
  1282. modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_IGNORE_ARMOR, armor);
  1283. AuraEffectList const& ResIgnoreAurasAb = GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST);
  1284. for(AuraEffectList::const_iterator j = ResIgnoreAurasAb.begin(); j != ResIgnoreAurasAb.end(); ++j)
  1285. {
  1286. if((*j)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL
  1287. && (*j)->IsAffectedOnSpell(spellInfo))
  1288. armor = floor(AddPctN(armor, -(*j)->GetAmount()));
  1289. }
  1290. AuraEffectList const& ResIgnoreAuras = GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
  1291. for(AuraEffectList::const_iterator j = ResIgnoreAuras.begin(); j != ResIgnoreAuras.end(); ++j)
  1292. {
  1293. if((*j)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
  1294. armor = floor(AddPctN(armor, -(*j)->GetAmount()));
  1295. }
  1296. if(GetTypeId() == TYPEID_PLAYER)
  1297. {
  1298. float bonusPct = 0;
  1299. AuraEffectList const& ResIgnoreAuras = GetAuraEffectsByType(SPELL_AURA_MOD_ARMOR_PENETRATION_PCT);
  1300. for(AuraEffectList::const_iterator itr = ResIgnoreAuras.begin(); itr != ResIgnoreAuras.end(); ++itr)
  1301. {
  1302. // item neutral spell
  1303. if((*itr)->GetSpellProto()->EquippedItemClass == -1)
  1304. {
  1305. /*
  1306. armor = floor(AddPctN(armor, -(*itr)->GetAmount()));
  1307. continue;
  1308. */
  1309. if (!spellInfo || (*itr)->IsAffectedOnSpell(spellInfo) || (*itr)->GetMiscValue() & GetSpellSchoolMask(spellInfo)) //(*itr)->GetMiscValue() & GetSpellSchoolMask(spellInfo)
  1310. bonusPct += (*itr)->GetAmount();
  1311. else if (!(*itr)->GetMiscValue() && !(*itr)->HasSpellClassMask())
  1312. bonusPct += (*itr)->GetAmount();
  1313. }
  1314. // item dependent spell - check current weapons
  1315. // for (int i = 0; i < MAX_ATTACK; ++i)
  1316. else
  1317. {
  1318. if (ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*itr)->GetSpellProto()))
  1319. bonusPct += (*itr)->GetAmount();
  1320. /*
  1321. Item* weapon = ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), true);
  1322. if (weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellInfo()))
  1323. {
  1324. armor = floor(AddPctN(armor, -(*itr)->GetAmount()));
  1325. break;
  1326. }
  1327. */
  1328. }
  1329. }
  1330. // }
  1331. /*
  1332. // Apply Player CR_ARMOR_PENETRATION rating
  1333. if(GetTypeId() == TYPEID_PLAYER)
  1334. {
  1335. */
  1336. float maxArmorPen = 0;
  1337. if(victim->getLevel() < 60)
  1338. maxArmorPen = float(450 + 85 * victim->getLevel()); // 400 - original
  1339. else
  1340. maxArmorPen = 450 + 85 * victim->getLevel() + 4.5f * 85 * (victim->getLevel() - 59);
  1341. // Cap armor penetration to this number
  1342. maxArmorPen = std::min((armor + maxArmorPen) / 3, armor);
  1343. // Figure out how much armor do we ignore
  1344. float armorPen = CalculatePctF(maxArmorPen, bonusPct + ToPlayer()->GetRatingBonusValue(CR_ARMOR_PENETRATION));
  1345. // Got the value, apply it
  1346. armor -= armorPen;
  1347. }
  1348. if(armor < 0.0f)
  1349. armor = 0.0f;
  1350. float levelModifier = getLevel();
  1351. if(levelModifier > 59)
  1352. levelModifier = levelModifier + (4.5f * (levelModifier - 59));
  1353. float tmpvalue = 0.1f * armor / (8.5f * levelModifier + 40);
  1354. tmpvalue = tmpvalue / (1.0f + tmpvalue);
  1355. if(tmpvalue < 0.0f)
  1356. tmpvalue = 0.0f;
  1357. if(tmpvalue > 0.75f)
  1358. tmpvalue = 0.75f;
  1359. newdamage = uint32(damage - (damage * tmpvalue));
  1360. return (newdamage > 1) ? newdamage : 1;
  1361. }
  1362. void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist, SpellEntry const* spellInfo)
  1363. {
  1364. if(!victim || !victim->isAlive() || !damage)
  1365. return;
  1366. DamageInfo dmgInfo = DamageInfo(this, victim, damage, spellInfo, schoolMask, damagetype);
  1367. // Magic damage, check for resists
  1368. if((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
  1369. {
  1370. float baseVictimResistance = float(victim->GetResistance(GetFirstSchoolInMask(schoolMask)));
  1371. float ignoredResistance = float(GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
  1372. if(Player* pPlayer = ToPlayer())
  1373. ignoredResistance += float(pPlayer->GetSpellPenetrationItemMod());
  1374. float victimResistance = baseVictimResistance + ignoredResistance;
  1375. static uint32 const BOSS_LEVEL = 83;
  1376. static float const BOSS_RESISTANCE_CONSTANT = 510.0f;
  1377. uint32 level = victim->getLevel();
  1378. float resistanceConstant = 0.0f;
  1379. if(level == BOSS_LEVEL)
  1380. resistanceConstant = BOSS_RESISTANCE_CONSTANT;
  1381. else
  1382. resistanceConstant = level * 5.0f;
  1383. float averageResist = victimResistance / (victimResistance + resistanceConstant);
  1384. float discreteResistProbability[11];
  1385. for(uint32 i = 0; i < 11; ++i)
  1386. {
  1387. discreteResistProbability[i] = 0.5f - 2.5f * fabs(0.1f * i - averageResist);
  1388. if(discreteResistProbability[i] < 0.0f)
  1389. discreteResistProbability[i] = 0.0f;
  1390. }
  1391. if(averageResist <= 0.1f)
  1392. {
  1393. discreteResistProbability[0] = 1.0f - 7.5f * averageResist;
  1394. discreteResistProbability[1] = 5.0f * averageResist;
  1395. discreteResistProbability[2] = 2.5f * averageResist;
  1396. }
  1397. float r = float(rand_norm());
  1398. uint32 i = 0;
  1399. float probabilitySum = discreteResistProbability[0];
  1400. while(r >= probabilitySum && i < 10)
  1401. probabilitySum += discreteResistProbability[++i];
  1402. float damageResisted;
  1403. if(this->GetTypeId() == TYPEID_PLAYER && this->getClass() == CLASS_PALADIN)
  1404. {
  1405. //if(this->HasAura(53375))
  1406. //else
  1407. if(this->HasAura(53376))
  1408. damageResisted = float(damage * i / 20);
  1409. } else damageResisted = float(damage * i / 10);
  1410. // These spells should ignore any resistances
  1411. if(spellInfo && spellInfo->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT)
  1412. damageResisted = 0;
  1413. AuraEffectList const& ResIgnoreAurasAb = GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST);
  1414. for(AuraEffectList::const_iterator j = ResIgnoreAurasAb.begin(); j != ResIgnoreAurasAb.end(); ++j)
  1415. if(((*j)->GetMiscValue() & schoolMask) && (*j)->IsAffectedOnSpell(spellInfo))
  1416. AddPctN(damageResisted, -(*j)->GetAmount());
  1417. AuraEffectList const& ResIgnoreAuras = GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
  1418. for(AuraEffectList::const_iterator j = ResIgnoreAuras.begin(); j != ResIgnoreAuras.end(); ++j)
  1419. if((*j)->GetMiscValue() & schoolMask)
  1420. AddPctN(damageResisted, -(*j)->GetAmount());
  1421. dmgInfo.ResistDamage(uint32(damageResisted));
  1422. }
  1423. // Ignore Absorption Auras
  1424. float auraAbsorbMod = 0;
  1425. AuraEffectList const& AbsIgnoreAurasA = GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL);
  1426. for(AuraEffectList::const_iterator itr = AbsIgnoreAurasA.begin(); itr != AbsIgnoreAurasA.end(); ++itr)
  1427. {
  1428. if(!((*itr)->GetMiscValue() & schoolMask))
  1429. continue;
  1430. if((*itr)->GetAmount() > auraAbsorbMod)
  1431. auraAbsorbMod = float((*itr)->GetAmount());
  1432. }
  1433. AuraEffectList const& AbsIgnoreAurasB = GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL);
  1434. for(AuraEffectList::const_iterator itr = AbsIgnoreAurasB.begin(); itr != AbsIgnoreAurasB.end(); ++itr)
  1435. {
  1436. if(!((*itr)->GetMiscValue() & schoolMask))
  1437. continue;
  1438. if(((*itr)->GetAmount() > auraAbsorbMod) && (*itr)->IsAffectedOnSpell(spellInfo))
  1439. auraAbsorbMod = float((*itr)->GetAmount());
  1440. }
  1441. RoundToInterval(auraAbsorbMod, 0.0f, 100.0f);
  1442. // We're going to call functions which can modify content of the list during iteration over it's elements
  1443. // Let's copy the list so we can prevent iterator invalidation
  1444. AuraEffectList vSchoolAbsorbCopy(victim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_ABSORB));
  1445. vSchoolAbsorbCopy.sort(Trinity::AbsorbAuraOrderPred());
  1446. // absorb without mana cost
  1447. for(AuraEffectList::iterator itr = vSchoolAbsorbCopy.begin(); (itr != vSchoolAbsorbCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr)
  1448. {
  1449. AuraEffect* absorbAurEff = *itr;
  1450. // Check if aura was removed during iteration - we don't need to work on such auras
  1451. AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID());
  1452. if(!aurApp)
  1453. continue;
  1454. if(!(absorbAurEff->GetMiscValue() & schoolMask))
  1455. continue;
  1456. // get amount which can be still absorbed by the aura
  1457. int32 currentAbsorb = absorbAurEff->GetAmount();
  1458. // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
  1459. if(currentAbsorb < 0)
  1460. currentAbsorb = 0;
  1461. uint32 absorb = currentAbsorb;
  1462. bool defaultPrevented = false;
  1463. absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, dmgInfo, absorb, defaultPrevented);
  1464. currentAbsorb = absorb;
  1465. if(defaultPrevented)
  1466. continue;
  1467. // Apply absorb mod auras
  1468. AddPctF(currentAbsorb, -auraAbsorbMod);
  1469. // absorb must be smaller than the damage itself
  1470. currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(dmgInfo.GetDamage()));
  1471. dmgInfo.AbsorbDamage(currentAbsorb);
  1472. absorb = currentAbsorb;
  1473. absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, dmgInfo, absorb);
  1474. // Check if our aura is using amount to count damage
  1475. if(absorbAurEff->GetAmount() >= 0)
  1476. {
  1477. // Reduce shield amount
  1478. absorbAurEff->SetAmount(absorbAurEff->GetAmount() - currentAbsorb);
  1479. // Aura cannot absorb anything more - remove it
  1480. if(absorbAurEff->GetAmount() <= 0)
  1481. absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
  1482. }
  1483. }
  1484. // absorb by mana cost
  1485. AuraEffectList vManaShieldCopy(victim->GetAuraEffectsByType(SPELL_AURA_MANA_SHIELD));
  1486. for(AuraEffectList::const_iterator itr = vManaShieldCopy.begin(); (itr != vManaShieldCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr)
  1487. {
  1488. AuraEffect* absorbAurEff = *itr;
  1489. // Check if aura was removed during iteration - we don't need to work on such auras
  1490. AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID());
  1491. if(!aurApp)
  1492. continue;
  1493. // check damage school mask
  1494. if(!(absorbAurEff->GetMiscValue() & schoolMask))
  1495. continue;
  1496. // get amount which can be still absorbed by the aura
  1497. int32 currentAbsorb = absorbAurEff->GetAmount();
  1498. // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
  1499. if(currentAbsorb < 0)
  1500. currentAbsorb = 0;
  1501. uint32 absorb = currentAbsorb;
  1502. bool defaultPrevented = false;
  1503. absorbAurEff->GetBase()->CallScriptEffectManaShieldHandlers(absorbAurEff, aurApp, dmgInfo, absorb, defaultPrevented);
  1504. currentAbsorb = absorb;
  1505. if(defaultPrevented)
  1506. continue;
  1507. AddPctF(currentAbsorb, -auraAbsorbMod);
  1508. // absorb must be smaller than the damage itself
  1509. currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(dmgInfo.GetDamage()));
  1510. int32 manaReduction = currentAbsorb;
  1511. // lower absorb amount by talents
  1512. if(float manaMultiplier = SpellMgr::CalculateSpellEffectValueMultiplier(absorbAurEff->GetSpellProto(), absorbAurEff->GetEffIndex(), absorbAurEff->GetCaster()))
  1513. manaReduction = int32(float(manaReduction) * manaMultiplier);
  1514. int32 manaTaken = -victim->ModifyPower(POWER_MANA, -manaReduction);
  1515. // take case when mana has ended up into account
  1516. currentAbsorb = currentAbsorb ? int32(float(currentAbsorb) * (float(manaTaken) / float(manaReduction))) : 0;
  1517. dmgInfo.AbsorbDamage(currentAbsorb);
  1518. absorb = currentAbsorb;
  1519. absorbAurEff->GetBase()->CallScriptEffectAfterManaShieldHandlers(absorbAurEff, aurApp, dmgInfo, absorb);
  1520. // Check if our aura is using amount to count damage
  1521. if(absorbAurEff->GetAmount() >= 0)
  1522. {
  1523. absorbAurEff->SetAmount(absorbAurEff->GetAmount() - currentAbsorb);
  1524. if((absorbAurEff->GetAmount() <= 0))
  1525. absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
  1526. }
  1527. }
  1528. // split damage auras - only when not damaging self
  1529. if(victim != this)
  1530. {
  1531. // We're going to call functions which can modify content of the list during iteration over it's elements
  1532. // Let's copy the list so we can prevent iterator invalidation
  1533. AuraEffectList vSplitDamageFlatCopy(victim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_FLAT));
  1534. for(AuraEffectList::iterator itr = vSplitDamageFlatCopy.begin(); (itr != vSplitDamageFlatCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr)
  1535. {
  1536. // Check if aura was removed during iteration - we don't need to work on such auras
  1537. if(!((*itr)->GetBase()->IsAppliedOnTarget(victim->GetGUID())))
  1538. continue;
  1539. // check damage school mask
  1540. if(!((*itr)->GetMiscValue() & schoolMask))
  1541. continue;
  1542. // Damage can be splitted only if aura has an alive caster
  1543. Unit* caster = (*itr)->GetCaster();
  1544. if(!caster || (caster == victim) || !caster->IsInWorld() || !caster->isAlive())
  1545. continue;
  1546. int32 splitDamage = (*itr)->GetAmount();
  1547. // absorb must be smaller than the damage itself
  1548. splitDamage = RoundToInterval(splitDamage, 0, int32(dmgInfo.GetDamage()));
  1549. dmgInfo.AbsorbDamage(splitDamage);
  1550. uint32 splitted = splitDamage;
  1551. uint32 splitted_absorb = 0;
  1552. DealDamageMods(caster, splitted, &splitted_absorb);
  1553. SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellProto()->Id, splitted, schoolMask, splitted_absorb, 0, false, 0, false);
  1554. CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
  1555. DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*itr)->GetSpellProto(), false);
  1556. }
  1557. // We're going to call functions which can modify content of the list during iteration over it's elements
  1558. // Let's copy the list so we can prevent iterator invalidation
  1559. AuraEffectList vSplitDamagePctCopy(victim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_PCT));
  1560. for(AuraEffectList::iterator itr = vSplitDamagePctCopy.begin(), next; (itr != vSplitDamagePctCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr)
  1561. {
  1562. // Check if aura was removed during iteration - we don't need to work on such auras
  1563. if(!((*itr)->GetBase()->IsAppliedOnTarget(victim->GetGUID())))
  1564. continue;
  1565. // check damage school mask
  1566. if(!((*itr)->GetMiscValue() & schoolMask))
  1567. continue;
  1568. // Damage can be splitted only if aura has an alive caster
  1569. Unit* caster = (*itr)->GetCaster();
  1570. if(!caster || (caster == victim) || !caster->IsInWorld() || !caster->isAlive())
  1571. continue;
  1572. int32 splitDamage = CalculatePctN(dmgInfo.GetDamage(), (*itr)->GetAmount());
  1573. // absorb must be smaller than the damage itself
  1574. splitDamage = RoundToInterval(splitDamage, 0, int32(dmgInfo.GetDamage()));
  1575. dmgInfo.AbsorbDamage(splitDamage);
  1576. uint32 splitted = splitDamage;
  1577. uint32 split_absorb = 0;
  1578. DealDamageMods(caster, splitted, &split_absorb);
  1579. SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellProto()->Id, splitted, schoolMask, split_absorb, 0, false, 0, false);
  1580. CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
  1581. DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*itr)->GetSpellProto(), false);
  1582. }
  1583. }
  1584. *resist = dmgInfo.GetResist();
  1585. *absorb = dmgInfo.GetAbsorb();
  1586. }
  1587. void Unit::CalcHealAbsorb(Unit* victim, const SpellEntry *healSpell, uint32 &healAmount, uint32 &absorb)
  1588. {
  1589. if(!healAmount)
  1590. return;
  1591. int32 RemainingHeal = healAmount;
  1592. // Need remove expired auras after
  1593. bool existExpired = false;
  1594. // absorb without mana cost
  1595. AuraEffectList const& vHealAbsorb = victim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_HEAL_ABSORB);
  1596. for(AuraEffectList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end() && RemainingHeal > 0; ++i)
  1597. {
  1598. if(!((*i)->GetMiscValue() & healSpell->SchoolMask))
  1599. continue;
  1600. // Max Amount can be absorbed by this aura
  1601. int32 currentAbsorb = (*i)->GetAmount();
  1602. // Found empty aura (impossible but..)
  1603. if(currentAbsorb <= 0)
  1604. {
  1605. existExpired = true;
  1606. continue;
  1607. }
  1608. // currentAbsorb - damage can be absorbed by shield
  1609. // If need absorb less damage
  1610. if(RemainingHeal < currentAbsorb)
  1611. currentAbsorb = RemainingHeal;
  1612. RemainingHeal -= currentAbsorb;
  1613. // Reduce shield amount
  1614. (*i)->SetAmount((*i)->GetAmount() - currentAbsorb);
  1615. // Need remove it later
  1616. if((*i)->GetAmount() <= 0)
  1617. existExpired = true;
  1618. }
  1619. // Remove all expired absorb auras
  1620. if(existExpired)
  1621. {
  1622. for(AuraEffectList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end();)
  1623. {
  1624. AuraEffect* auraEff = *i;
  1625. ++i;
  1626. if(auraEff->GetAmount() <= 0)
  1627. {
  1628. uint32 removedAuras = victim->m_removedAurasCount;
  1629. auraEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
  1630. if(removedAuras+1 < victim->m_removedAurasCount)
  1631. i = vHealAbsorb.begin();
  1632. }
  1633. }
  1634. }
  1635. absorb = RemainingHeal > 0 ? (healAmount - RemainingHeal) : healAmount;
  1636. healAmount = RemainingHeal;
  1637. }
  1638. void Unit::AttackerStateUpdate (Unit* pVictim, WeaponAttackType attType, bool extra)
  1639. {
  1640. if(HasUnitState(UNIT_STAT_CANNOT_AUTOATTACK) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))
  1641. return;
  1642. if(!pVictim->isAlive())
  1643. return;
  1644. if((attType == BASE_ATTACK || attType == OFF_ATTACK) && !this->IsWithinLOSInMap(pVictim) && !isPet())
  1645. return;
  1646. CombatStart(pVictim);
  1647. RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MELEE_ATTACK);
  1648. uint32 hitInfo;
  1649. if(attType == BASE_ATTACK)
  1650. hitInfo = HITINFO_NORMALSWING2;
  1651. else if(attType == OFF_ATTACK)
  1652. hitInfo = HITINFO_LEFTSWING;
  1653. else
  1654. return; // ignore ranged case
  1655. // melee attack spell casted at main hand attack only - no normal melee dmg dealt
  1656. if(attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL])
  1657. m_currentSpells[CURRENT_MELEE_SPELL]->cast();
  1658. else
  1659. {
  1660. // attack can be redirected to another target
  1661. pVictim = SelectMagnetTarget(pVictim);
  1662. CalcDamageInfo damageInfo;
  1663. CalculateMeleeDamage(pVictim, 0, &damageInfo, attType);
  1664. // Send log damage message to client
  1665. DealDamageMods(pVictim, damageInfo.damage, &damageInfo.absorb);
  1666. SendAttackStateUpdate(&damageInfo);
  1667. //TriggerAurasProcOnEvent(damageInfo);
  1668. ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType);
  1669. DealMeleeDamage(&damageInfo, true);
  1670. }
  1671. if(!extra && m_extraAttacks)
  1672. {
  1673. while(m_extraAttacks)
  1674. {
  1675. AttackerStateUpdate(pVictim, BASE_ATTACK, true);
  1676. if(m_extraAttacks > 0)
  1677. --m_extraAttacks;
  1678. }
  1679. }
  1680. }
  1681. MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* victim, WeaponAttackType attType) const
  1682. {
  1683. // This is only wrapper
  1684. // Miss chance based on melee
  1685. //float miss_chance = MeleeMissChanceCalc(victim, attType);
  1686. float miss_chance = MeleeSpellMissChance(victim, attType, int32(GetWeaponSkillValue(attType, victim)) - int32(victim->GetDefenseSkillValue(this)), 0);
  1687. // Critical hit chance
  1688. float crit_chance = GetUnitCriticalChance(attType, victim);
  1689. // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case)
  1690. float dodge_chance = victim->GetUnitDodgeChance();
  1691. float block_chance = victim->GetUnitBlockChance();
  1692. float parry_chance = victim->GetUnitParryChance();
  1693. // Useful if want to specify crit & miss chances for melee, else it could be removed
  1694. sLog->outDebug(LOG_FILTER_UNITS, "MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance, crit_chance, dodge_chance, parry_chance, block_chance);
  1695. return RollMeleeOutcomeAgainst(victim, attType, int32(crit_chance*100), int32(miss_chance*100), int32(dodge_chance*100), int32(parry_chance*100), int32(block_chance*100));
  1696. }
  1697. MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance) const
  1698. {
  1699. if(victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode())
  1700. return MELEE_HIT_EVADE;
  1701. int32 attackerMaxSkillValueForLevel = GetMaxSkillValueForLevel(victim);
  1702. int32 victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this);
  1703. int32 attackerWeaponSkill = GetWeaponSkillValue(attType, victim);
  1704. int32 victimDefenseSkill = victim->GetDefenseSkillValue(this);
  1705. // bonus from skills is 0.04%
  1706. int32 skillBonus = 4 * (attackerWeaponSkill - victimMaxSkillValueForLevel);
  1707. int32 sum = 0, tmp = 0;
  1708. int32 roll = urand(0, 10000);
  1709. sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus);
  1710. sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d",
  1711. roll, miss_chance, dodge_chance, parry_chance, block_chance, crit_chance);
  1712. tmp = miss_chance;
  1713. if(tmp > 0 && roll < (sum += tmp))
  1714. {
  1715. sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: MISS");
  1716. return MELEE_HIT_MISS;
  1717. }
  1718. // always crit against a sitting target (except 0 crit chance)
  1719. if(victim->GetTypeId() == TYPEID_PLAYER && crit_chance > 0 && !victim->IsStandState())
  1720. {
  1721. sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: CRIT (sitting victim)");
  1722. return MELEE_HIT_CRIT;
  1723. }
  1724. // Dodge chance
  1725. // only players can't dodge if attacker is behind
  1726. if(victim->GetTypeId() == TYPEID_PLAYER && !victim->HasInArc(M_PI, this) && !victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
  1727. {
  1728. sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: attack came from behind and victim was a player.");
  1729. }
  1730. else
  1731. {
  1732. // Reduce dodge chance by attacker expertise rating
  1733. if(GetTypeId() == TYPEID_PLAYER)
  1734. dodge_chance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100);
  1735. else
  1736. dodge_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
  1737. // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
  1738. dodge_chance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE) * 100;
  1739. dodge_chance = int32 (float (dodge_chance) * GetTotalAuraMultiplier(SPELL_AURA_MOD_ENEMY_DODGE));
  1740. tmp = dodge_chance;
  1741. if((tmp > 0) // check if unit _can_ dodge
  1742. && ((tmp -= skillBonus) > 0)
  1743. && roll < (sum += tmp))
  1744. {
  1745. sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum-tmp, sum);
  1746. return MELEE_HIT_DODGE;
  1747. }
  1748. }
  1749. // parry & block chances
  1750. // check if attack comes from behind, nobody can parry or block if attacker is behind
  1751. if(!victim->HasInArc(M_PI, this) && !victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
  1752. sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: attack came from behind.");
  1753. else
  1754. {
  1755. // Reduce parry chance by attacker expertise rating
  1756. if(GetTypeId() == TYPEID_PLAYER)
  1757. parry_chance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100);
  1758. else
  1759. parry_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
  1760. if(victim->GetTypeId() == TYPEID_PLAYER || !(victim->ToCreature()->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY))
  1761. {
  1762. int32 tmp2 = int32(parry_chance);
  1763. if(tmp2 > 0 // check if unit _can_ parry
  1764. && (tmp2 -= skillBonus) > 0
  1765. && roll < (sum += tmp2))
  1766. {
  1767. sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum-tmp2, sum);
  1768. return MELEE_HIT_PARRY;
  1769. }
  1770. }
  1771. if(victim->GetTypeId() == TYPEID_PLAYER || !(victim->ToCreature()->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK))
  1772. {
  1773. tmp = block_chance;
  1774. if(tmp > 0 // check if unit _can_ block
  1775. && (tmp -= skillBonus) > 0
  1776. && roll < (sum += tmp))
  1777. {
  1778. sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum-tmp, sum);
  1779. return MELEE_HIT_BLOCK;
  1780. }
  1781. }
  1782. }
  1783. // Critical chance
  1784. tmp = crit_chance;
  1785. if(tmp > 0 && roll < (sum += tmp))
  1786. {
  1787. sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum-tmp, sum);
  1788. if(GetTypeId() == TYPEID_UNIT && (ToCreature()->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRIT))
  1789. sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: CRIT DISABLED)");
  1790. else
  1791. return MELEE_HIT_CRIT;
  1792. }
  1793. // Max 40% chance to score a glancing blow against mobs that are higher level (can do only players and pets and not with ranged weapon)
  1794. if(attType != RANGED_ATTACK &&
  1795. (GetTypeId() == TYPEID_PLAYER || ToCreature()->isPet()) &&
  1796. victim->GetTypeId() != TYPEID_PLAYER && !victim->ToCreature()->isPet() &&
  1797. getLevel() < victim->getLevelForTarget(this))
  1798. {
  1799. // cap possible value (with bonuses > max skill)
  1800. int32 skill = attackerWeaponSkill;
  1801. int32 maxskill = attackerMaxSkillValueForLevel;
  1802. skill = (skill > maxskill) ? maxskill : skill;
  1803. tmp = (10 + (victimDefenseSkill - skill)) * 100;
  1804. tmp = tmp > 4000 ? 4000 : tmp;
  1805. if(roll < (sum += tmp))
  1806. {
  1807. sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum-4000, sum);
  1808. return MELEE_HIT_GLANCING;
  1809. }
  1810. }
  1811. // mobs can score crushing blows if they're 4 or more levels above victim
  1812. if(getLevelForTarget(victim) >= victim->getLevelForTarget(this) + 4 &&
  1813. // can be from by creature (if can) or from controlled player that considered as creature
  1814. !IsControlledByPlayer() &&
  1815. !(GetTypeId() == TYPEID_UNIT && ToCreature()->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRUSH))
  1816. {
  1817. // when their weapon skill is 15 or more above victim's defense skill
  1818. tmp = victimDefenseSkill;
  1819. int32 tmpmax = victimMaxSkillValueForLevel;
  1820. // having defense above your maximum (from items, talents etc.) has no effect
  1821. tmp = tmp > tmpmax ? tmpmax : tmp;
  1822. // tmp = mob's level * 5 - player's current defense skill
  1823. tmp = attackerMaxSkillValueForLevel - tmp;
  1824. if(tmp >= 15)
  1825. {
  1826. // add 2% chance per lacking skill point, min. is 15%
  1827. tmp = tmp * 200 - 1500;
  1828. if(roll < (sum += tmp))
  1829. {
  1830. sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum-tmp, sum);
  1831. return MELEE_HIT_CRUSHING;
  1832. }
  1833. }
  1834. }
  1835. sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: NORMAL");
  1836. return MELEE_HIT_NORMAL;
  1837. }
  1838. uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct)
  1839. {
  1840. float min_damage, max_damage;
  1841. if(GetTypeId() == TYPEID_PLAYER && (normalized || !addTotalPct))
  1842. ToPlayer()->CalculateMinMaxDamage(attType, normalized, addTotalPct, min_damage, max_damage);
  1843. else
  1844. {
  1845. switch(attType)
  1846. {
  1847. case RANGED_ATTACK:
  1848. min_damage = GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE);
  1849. max_damage = GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE);
  1850. break;
  1851. case BASE_ATTACK:
  1852. min_damage = GetFloatValue(UNIT_FIELD_MINDAMAGE);
  1853. max_damage = GetFloatValue(UNIT_FIELD_MAXDAMAGE);
  1854. break;
  1855. case OFF_ATTACK:
  1856. min_damage = GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE);
  1857. max_damage = GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE);
  1858. break;
  1859. // Just for good manner
  1860. default:
  1861. min_damage = 0.0f;
  1862. max_damage = 0.0f;
  1863. break;
  1864. }
  1865. }
  1866. if(GetTypeId() == TYPEID_PLAYER)
  1867. {
  1868. min_damage /= GetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT);
  1869. max_damage /= GetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT);
  1870. }
  1871. if(min_damage > max_damage)
  1872. std::swap(min_damage, max_damage);
  1873. if(max_damage == 0.0f)
  1874. max_damage = 5.0f;
  1875. // Rounding
  1876. min_damage += 0.5f;
  1877. max_damage += 0.5f;
  1878. return urand((uint32)min_damage, (uint32)max_damage);
  1879. }
  1880. float Unit::CalculateLevelPenalty(SpellEntry const* spellProto) const
  1881. {
  1882. if(spellProto->spellLevel <= 0 || spellProto->spellLevel >= spellProto->maxLevel)
  1883. return 1.0f;
  1884. float LvlPenalty = 0.0f;
  1885. if(spellProto->spellLevel < 20)
  1886. LvlPenalty = 20.0f - spellProto->spellLevel * 3.75f;
  1887. float LvlFactor = (float(spellProto->spellLevel) + 6.0f) / float(getLevel());
  1888. if(LvlFactor > 1.0f)
  1889. LvlFactor = 1.0f;
  1890. return AddPctF(LvlFactor, -LvlPenalty);
  1891. }
  1892. void Unit::SendMeleeAttackStart(Unit* victim)
  1893. {
  1894. WorldPacket data(SMSG_ATTACKSTART, 8 + 8);
  1895. data << uint64(GetGUID());
  1896. data << uint64(victim->GetGUID());
  1897. SendMessageToSet(&data, true);
  1898. sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_ATTACKSTART");
  1899. }
  1900. void Unit::SendMeleeAttackStop(Unit* pVictim)
  1901. {
  1902. WorldPacket data(SMSG_ATTACKSTOP, (8+8+4)); // we guess size
  1903. data.append(GetPackGUID());
  1904. data.append(pVictim ? pVictim->GetPackGUID() : 0); // can be 0x00...
  1905. data << uint32(0); // can be 0x1
  1906. SendMessageToSet(&data, true);
  1907. sLog->outDebug(LOG_FILTER_UNITS, "WORLD: Sent SMSG_ATTACKSTOP");
  1908. if(pVictim)
  1909. sLog->outDebug(LOG_FILTER_UNITS, "%s %u stopped attacking %s %u", (GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), GetGUIDLow(), (pVictim->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), pVictim->GetGUIDLow());
  1910. else
  1911. sLog->outDebug(LOG_FILTER_UNITS, "%s %u stopped attacking", (GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), GetGUIDLow());
  1912. //sLog->outDetail("%s %u stopped attacking %s %u", (GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), GetGUIDLow(), (pVictim->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), pVictim->GetGUIDLow());
  1913. }
  1914. bool Unit::isSpellBlocked(Unit* pVictim, SpellEntry const* pSpellEntry, WeaponAttackType attackType)
  1915. {
  1916. // These spells can't be blocked
  1917. if(pSpellEntry && pSpellEntry->Attributes & SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK)
  1918. return false;
  1919. if(pVictim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION) || pVictim->HasInArc(M_PI, this))
  1920. {
  1921. // Check creatures flags_extra for disable block
  1922. if(pVictim->GetTypeId() == TYPEID_UNIT &&
  1923. pVictim->ToCreature()->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK)
  1924. return false;
  1925. float blockChance = pVictim->GetUnitBlockChance();
  1926. blockChance += (int32(GetWeaponSkillValue(attackType)) - int32(pVictim->GetMaxSkillValueForLevel())) * 0.04f;
  1927. if(roll_chance_f(blockChance))
  1928. return true;
  1929. }
  1930. return false;
  1931. }
  1932. bool Unit::isBlockCritical()
  1933. {
  1934. if(roll_chance_i(GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_CRIT_CHANCE)))
  1935. return true;
  1936. return false;
  1937. }
  1938. int32 Unit::GetMechanicResistChance(const SpellEntry* spell)
  1939. {
  1940. if(!spell)
  1941. return 0;
  1942. int32 resist_mech = 0;
  1943. for(uint8 eff = 0; eff < MAX_SPELL_EFFECTS; ++eff)
  1944. {
  1945. if(spell->Effect[eff] == 0)
  1946. break;
  1947. int32 effect_mech = GetEffectMechanic(spell, eff);
  1948. if(effect_mech)
  1949. {
  1950. int32 temp = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE, effect_mech);
  1951. if(resist_mech < temp)
  1952. resist_mech = temp;
  1953. }
  1954. }
  1955. return resist_mech;
  1956. }
  1957. // Melee based spells hit result calculations
  1958. SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellEntry const* spell)
  1959. {
  1960. // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore
  1961. // resist and deflect chances
  1962. if(spell->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT)
  1963. return SPELL_MISS_NONE;
  1964. WeaponAttackType attType = BASE_ATTACK;
  1965. // Check damage class instead of attack type to correctly handle judgements
  1966. // - they are meele, but can't be dodged/parried/deflected because of ranged dmg class
  1967. if(spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
  1968. attType = RANGED_ATTACK;
  1969. int32 attackerWeaponSkill;
  1970. // skill value for these spells (for example judgements) is 5* level
  1971. if(spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED && !IsRangedWeaponSpell(spell))
  1972. attackerWeaponSkill = getLevel() * 5;
  1973. // bonus from skills is 0.04% per skill Diff
  1974. else
  1975. attackerWeaponSkill = int32(GetWeaponSkillValue(attType, victim));
  1976. int32 skillDiff = attackerWeaponSkill - int32(victim->GetMaxSkillValueForLevel(this));
  1977. int32 fullSkillDiff = attackerWeaponSkill - int32(victim->GetDefenseSkillValue(this));
  1978. uint32 roll = urand(0, 10000);
  1979. uint32 missChance = uint32(MeleeSpellMissChance(victim, attType, fullSkillDiff, spell->Id) * 100.0f);
  1980. // Roll miss
  1981. uint32 tmp = missChance;
  1982. if(roll < tmp)
  1983. return SPELL_MISS_MISS;
  1984. // Chance resist mechanic (select max value from every mechanic spell effect)
  1985. int32 resist_mech = 0;
  1986. // Get effects mechanic and chance
  1987. for(uint8 eff = 0; eff < MAX_SPELL_EFFECTS; ++eff)
  1988. {
  1989. int32 effect_mech = GetEffectMechanic(spell, eff);
  1990. if(effect_mech)
  1991. {
  1992. int32 temp = victim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE, effect_mech);
  1993. if(resist_mech < temp*100)
  1994. resist_mech = temp*100;
  1995. }
  1996. }
  1997. // Roll chance
  1998. tmp += resist_mech;
  1999. if(roll < tmp)
  2000. return SPELL_MISS_RESIST;
  2001. bool canDodge = true;
  2002. bool canParry = true;
  2003. bool canBlock = spell->AttributesEx3 & SPELL_ATTR3_BLOCKABLE_SPELL;
  2004. // Same spells cannot be parry/dodge
  2005. if(spell->Attributes & SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK)
  2006. return SPELL_MISS_NONE;
  2007. // Chance resist mechanic
  2008. int32 resist_chance = victim->GetMechanicResistChance(spell) * 100;
  2009. tmp += resist_chance;
  2010. if(roll < tmp)
  2011. return SPELL_MISS_RESIST;
  2012. // Ranged attacks can only miss, resist and deflect
  2013. if(attType == RANGED_ATTACK)
  2014. {
  2015. /*
  2016. canParry = false;
  2017. canDodge = false;
  2018. */
  2019. // Judgements cannot be deflected
  2020. if(spell->Category == SPELLCATEGORY_JUDGEMENT)
  2021. return SPELL_MISS_NONE;
  2022. // only if in front
  2023. if(victim->HasInArc(M_PI, this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
  2024. {
  2025. int32 deflect_chance = victim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100;
  2026. tmp+=deflect_chance;
  2027. if(roll < tmp)
  2028. return SPELL_MISS_DEFLECT;
  2029. }
  2030. return SPELL_MISS_NONE;
  2031. }
  2032. // Check for attack from behind
  2033. if(!victim->HasInArc(M_PI, this) && !victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
  2034. {
  2035. // Can`t dodge from behind in PvP (but its possible in PvE)
  2036. if(victim->GetTypeId() == TYPEID_PLAYER)
  2037. canDodge = false;
  2038. // Can`t parry or block
  2039. canParry = false;
  2040. canBlock = false;
  2041. }
  2042. // Check creatures flags_extra for disable parry
  2043. if(victim->GetTypeId() == TYPEID_UNIT)
  2044. {
  2045. uint32 flagEx = victim->ToCreature()->GetCreatureInfo()->flags_extra;
  2046. if(flagEx & CREATURE_FLAG_EXTRA_NO_PARRY)
  2047. canParry = false;
  2048. // Check creatures flags_extra for disable block
  2049. if(flagEx & CREATURE_FLAG_EXTRA_NO_BLOCK)
  2050. canBlock = false;
  2051. }
  2052. // Ignore combat result aura
  2053. AuraEffectList const& ignore = GetAuraEffectsByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
  2054. for(AuraEffectList::const_iterator i = ignore.begin(); i != ignore.end(); ++i)
  2055. {
  2056. if(!(*i)->IsAffectedOnSpell(spell))
  2057. continue;
  2058. switch((*i)->GetMiscValue())
  2059. {
  2060. case MELEE_HIT_DODGE: canDodge = false; break;
  2061. case MELEE_HIT_BLOCK: canBlock = false; break;
  2062. case MELEE_HIT_PARRY: canParry = false; break;
  2063. default:
  2064. sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell %u SPELL_AURA_IGNORE_COMBAT_RESULT have unhandled state %d", (*i)->GetId(), (*i)->GetMiscValue());
  2065. break;
  2066. }
  2067. }
  2068. if(canDodge)
  2069. {
  2070. // Roll dodge
  2071. int32 dodgeChance = int32(victim->GetUnitDodgeChance() * 100.0f) - skillDiff * 4;
  2072. // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
  2073. dodgeChance += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE) * 100;
  2074. dodgeChance = int32(float(dodgeChance) * GetTotalAuraMultiplier(SPELL_AURA_MOD_ENEMY_DODGE));
  2075. // Reduce dodge chance by attacker expertise rating
  2076. if(GetTypeId() == TYPEID_PLAYER)
  2077. dodgeChance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
  2078. else
  2079. dodgeChance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
  2080. if(dodgeChance < 0)
  2081. dodgeChance = 0;
  2082. if(roll < (tmp += dodgeChance))
  2083. return SPELL_MISS_DODGE;
  2084. }
  2085. if(canParry)
  2086. {
  2087. // Roll parry
  2088. int32 parryChance = int32(victim->GetUnitParryChance() * 100.0f) - skillDiff * 4;
  2089. // Reduce parry chance by attacker expertise rating
  2090. if(GetTypeId() == TYPEID_PLAYER)
  2091. parryChance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
  2092. else
  2093. parryChance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
  2094. if(parryChance < 0)
  2095. parryChance = 0;
  2096. tmp += parryChance;
  2097. if(roll < tmp)
  2098. return SPELL_MISS_PARRY;
  2099. }
  2100. if(canBlock)
  2101. {
  2102. int32 blockChance = int32(victim->GetUnitBlockChance() * 100.0f) - skillDiff * 4;
  2103. if(blockChance < 0)
  2104. blockChance = 0;
  2105. tmp += blockChance;
  2106. if(roll < tmp)
  2107. return SPELL_MISS_BLOCK;
  2108. }
  2109. return SPELL_MISS_NONE;
  2110. }
  2111. // TODO need use unit spell resistances in calculations
  2112. SpellMissInfo Unit::MagicSpellHitResult(Unit* pVictim, SpellEntry const* spell)
  2113. {
  2114. // Can`t miss on dead target (on skinning for example)
  2115. if(!pVictim->isAlive() && pVictim->GetTypeId() != TYPEID_PLAYER)
  2116. return SPELL_MISS_NONE;
  2117. SpellSchoolMask schoolMask = GetSpellSchoolMask(spell);
  2118. // PvP - PvE spell misschances per leveldif > 2
  2119. int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 7 : 11;
  2120. int32 thisLevel = getLevelForTarget(pVictim);
  2121. if(GetTypeId() == TYPEID_UNIT && ToCreature()->isTrigger())
  2122. thisLevel = std::max<int32>(thisLevel, spell->spellLevel);
  2123. int32 leveldif = int32(pVictim->getLevelForTarget(this)) - thisLevel;
  2124. // Base hit chance from attacker and victim levels
  2125. int32 modHitChance;
  2126. if(leveldif < 3)
  2127. modHitChance = 96 - leveldif;
  2128. else
  2129. modHitChance = 94 - (leveldif - 2) * lchance;
  2130. // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
  2131. if(Player* modOwner = GetSpellModOwner())
  2132. modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance);
  2133. // Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras
  2134. modHitChance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT, schoolMask);
  2135. // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will ignore target's avoidance effects
  2136. if(!(spell->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT))
  2137. {
  2138. // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
  2139. if(!(spell->SpellFamilyName == SPELLFAMILY_WARLOCK && spell->SpellIconID == 3178)) // Chaos Bolt should ignore it
  2140. modHitChance += pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask);
  2141. // Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura
  2142. if(IsAreaOfEffectSpell(spell))
  2143. modHitChance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE);
  2144. // Decrease hit chance from victim rating bonus
  2145. if(pVictim->GetTypeId() == TYPEID_PLAYER)
  2146. modHitChance -= int32(pVictim->ToPlayer()->GetRatingBonusValue(CR_HIT_TAKEN_SPELL));
  2147. }
  2148. int32 HitChance = modHitChance * 100;
  2149. // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
  2150. HitChance += int32(m_modSpellHitChance * 100.0f);
  2151. if(HitChance < 100)
  2152. HitChance = 100;
  2153. else if(HitChance > 10000)
  2154. HitChance = 10000;
  2155. int32 tmp = 10000 - HitChance;
  2156. int32 rand = irand(0, 10000);
  2157. if(rand < tmp)
  2158. return SPELL_MISS_MISS;
  2159. // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore
  2160. // resist and deflect chances
  2161. if(spell->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT)
  2162. return SPELL_MISS_NONE;
  2163. // Chance resist mechanic (select max value from every mechanic spell effect)
  2164. int32 resist_chance = pVictim->GetMechanicResistChance(spell) * 100;
  2165. tmp += resist_chance;
  2166. // Chance resist debuff
  2167. if(!IsPositiveSpell(spell->Id))
  2168. {
  2169. bool bNegativeAura = false;
  2170. for(uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
  2171. {
  2172. if(spell->EffectApplyAuraName[i] != 0)
  2173. {
  2174. bNegativeAura = true;
  2175. break;
  2176. }
  2177. }
  2178. if(bNegativeAura)
  2179. {
  2180. tmp += pVictim->GetMaxPositiveAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spell->Dispel)) * 100;
  2181. tmp += pVictim->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spell->Dispel)) * 100;
  2182. }
  2183. }
  2184. // Roll chance
  2185. if(rand < tmp)
  2186. return SPELL_MISS_RESIST;
  2187. // Chaos Bolt cannot be deflected
  2188. if(spell->SpellFamilyName == SPELLFAMILY_WARLOCK && spell->SpellIconID == 3178)
  2189. return SPELL_MISS_NONE;
  2190. // cast by caster in front of victim
  2191. if(pVictim->HasInArc(M_PI, this) || pVictim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
  2192. {
  2193. int32 deflect_chance = pVictim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100;
  2194. tmp += deflect_chance;
  2195. if(rand < tmp)
  2196. return SPELL_MISS_DEFLECT;
  2197. }
  2198. return SPELL_MISS_NONE;
  2199. }
  2200. // Calculate spell hit result can be:
  2201. // Every spell can: Evade/Immune/Reflect/Sucesful hit
  2202. // For melee based spells:
  2203. // Miss
  2204. // Dodge
  2205. // Parry
  2206. // For spells
  2207. // Resist
  2208. SpellMissInfo Unit::SpellHitResult(Unit* pVictim, SpellEntry const* pSpell, bool CanReflect)
  2209. {
  2210. if(!pVictim)
  2211. return SPELL_MISS_NONE;
  2212. // Check for immune
  2213. if(pVictim->IsImmunedToSpell(pSpell))
  2214. return SPELL_MISS_IMMUNE;
  2215. // All positive spells can`t miss
  2216. // TODO: client not show miss log for this spells - so need find info for this in dbc and use it!
  2217. if(IsPositiveSpell(pSpell->Id)
  2218. &&(!IsHostileTo(pVictim))) // prevent from affecting enemy by "positive" spell
  2219. return SPELL_MISS_NONE;
  2220. // Check for immune
  2221. if(pVictim->IsImmunedToDamage(pSpell))
  2222. return SPELL_MISS_IMMUNE;
  2223. if(this == pVictim)
  2224. return SPELL_MISS_NONE;
  2225. // Return evade for units in evade mode
  2226. if(pVictim->GetTypeId() == TYPEID_UNIT && pVictim->ToCreature()->IsInEvadeMode())
  2227. return SPELL_MISS_EVADE;
  2228. // Try victim reflect spell
  2229. if(CanReflect)
  2230. {
  2231. int32 reflectchance = pVictim->GetTotalAuraModifier(SPELL_AURA_REFLECT_SPELLS);
  2232. Unit::AuraEffectList const& mReflectSpellsSchool = pVictim->GetAuraEffectsByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL);
  2233. for(Unit::AuraEffectList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i)
  2234. if((*i)->GetMiscValue() & GetSpellSchoolMask(pSpell))
  2235. reflectchance += (*i)->GetAmount();
  2236. if(reflectchance > 0 && roll_chance_i(reflectchance))
  2237. {
  2238. return SPELL_MISS_REFLECT;
  2239. }
  2240. }
  2241. switch(pSpell->DmgClass)
  2242. {
  2243. case SPELL_DAMAGE_CLASS_RANGED:
  2244. case SPELL_DAMAGE_CLASS_MELEE:
  2245. return MeleeSpellHitResult(pVictim, pSpell);
  2246. case SPELL_DAMAGE_CLASS_NONE:
  2247. return SPELL_MISS_NONE;
  2248. case SPELL_DAMAGE_CLASS_MAGIC:
  2249. return MagicSpellHitResult(pVictim, pSpell);
  2250. }
  2251. return SPELL_MISS_NONE;
  2252. }
  2253. uint32 Unit::GetDefenseSkillValue(Unit const* target) const
  2254. {
  2255. if(GetTypeId() == TYPEID_PLAYER)
  2256. {
  2257. // in PvP use full skill instead current skill value
  2258. uint32 value = (target && target->GetTypeId() == TYPEID_PLAYER)
  2259. ? ToPlayer()->GetMaxSkillValue(SKILL_DEFENSE) : ToPlayer()->GetSkillValue(SKILL_DEFENSE);
  2260. value += uint32(ToPlayer()->GetRatingBonusValue(CR_DEFENSE_SKILL));
  2261. return value;
  2262. }
  2263. else
  2264. return GetUnitMeleeSkill(target);
  2265. }
  2266. float Unit::GetUnitDodgeChance() const
  2267. {
  2268. if(IsNonMeleeSpellCasted(false) || HasUnitState(UNIT_STAT_CONTROLLED) || HasUnitState(UNIT_STAT_CASTING))
  2269. return 0.0f;
  2270. if(GetTypeId() == TYPEID_PLAYER)
  2271. return GetFloatValue(PLAYER_DODGE_PERCENTAGE);
  2272. else
  2273. {
  2274. if(ToCreature()->isTotem())
  2275. return 0.0f;
  2276. else
  2277. {
  2278. float dodge = 5.0f;
  2279. dodge += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT);
  2280. return dodge > 0.0f ? dodge : 0.0f;
  2281. }
  2282. }
  2283. }
  2284. float Unit::GetUnitParryChance() const
  2285. {
  2286. if(IsNonMeleeSpellCasted(false) || HasUnitState(UNIT_STAT_CONTROLLED))
  2287. return 0.0f;
  2288. float chance = 0.0f;
  2289. if(Player const* player = ToPlayer())
  2290. {
  2291. if(player->CanParry())
  2292. {
  2293. Item* tmpitem = player->GetWeaponForAttack(BASE_ATTACK, true);
  2294. if(!tmpitem)
  2295. tmpitem = player->GetWeaponForAttack(OFF_ATTACK, true);
  2296. if(tmpitem)
  2297. chance = GetFloatValue(PLAYER_PARRY_PERCENTAGE);
  2298. }
  2299. }
  2300. else if(GetTypeId() == TYPEID_UNIT)
  2301. {
  2302. if(GetCreatureType() == CREATURE_TYPE_HUMANOID)
  2303. {
  2304. chance = 5.0f;
  2305. chance += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT);
  2306. }
  2307. }
  2308. return chance > 0.0f ? chance : 0.0f;
  2309. }
  2310. float Unit::GetUnitBlockChance() const
  2311. {
  2312. if(IsNonMeleeSpellCasted(false) || HasUnitState(UNIT_STAT_CONTROLLED))
  2313. return 0.0f;
  2314. if(Player const* player = ToPlayer())
  2315. {
  2316. if(player->CanBlock())
  2317. {
  2318. Item* tmpitem = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
  2319. if(tmpitem && !tmpitem->IsBroken() && tmpitem->GetTemplate()->Block)
  2320. return GetFloatValue(PLAYER_BLOCK_PERCENTAGE);
  2321. }
  2322. // is player but has no block ability or no not broken shield equipped
  2323. return 0.0f;
  2324. }
  2325. else
  2326. {
  2327. if(ToCreature()->isTotem())
  2328. return 0.0f;
  2329. else
  2330. {
  2331. float block = 5.0f;
  2332. block += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT);
  2333. return block > 0.0f ? block : 0.0f;
  2334. }
  2335. }
  2336. }
  2337. float Unit::GetUnitCriticalChance(WeaponAttackType attackType, const Unit* victim) const
  2338. {
  2339. float crit;
  2340. if(GetTypeId() == TYPEID_PLAYER)
  2341. {
  2342. switch(attackType)
  2343. {
  2344. case BASE_ATTACK:
  2345. crit = GetFloatValue(PLAYER_CRIT_PERCENTAGE);
  2346. break;
  2347. case OFF_ATTACK:
  2348. crit = GetFloatValue(PLAYER_OFFHAND_CRIT_PERCENTAGE);
  2349. break;
  2350. case RANGED_ATTACK:
  2351. crit = GetFloatValue(PLAYER_RANGED_CRIT_PERCENTAGE);
  2352. break;
  2353. // Just for good manner
  2354. default:
  2355. crit = 0.0f;
  2356. break;
  2357. }
  2358. }
  2359. else
  2360. {
  2361. crit = 5.0f;
  2362. crit += GetTotalAuraModifier(SPELL_AURA_MOD_WEAPON_CRIT_PERCENT);
  2363. crit += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PCT);
  2364. }
  2365. // flat aura mods
  2366. if(attackType == RANGED_ATTACK)
  2367. crit += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE);
  2368. else
  2369. crit += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE);
  2370. crit += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
  2371. // reduce crit chance from Rating for players
  2372. if(attackType != RANGED_ATTACK)
  2373. {
  2374. ApplyResilience(victim, &crit, NULL, false, CR_CRIT_TAKEN_MELEE);
  2375. // Glyph of barkskin
  2376. if(victim->HasAura(63057) && victim->HasAura(22812))
  2377. crit -= 25.0f;
  2378. }
  2379. else
  2380. ApplyResilience(victim, &crit, NULL, false, CR_CRIT_TAKEN_RANGED);
  2381. // Apply crit chance from defence skill
  2382. crit += (int32(GetMaxSkillValueForLevel(victim)) - int32(victim->GetDefenseSkillValue(this))) * 0.04f;
  2383. if(crit < 0.0f)
  2384. crit = 0.0f;
  2385. return crit;
  2386. }
  2387. uint32 Unit::GetWeaponSkillValue (WeaponAttackType attType, Unit const* target) const
  2388. {
  2389. uint32 value = 0;
  2390. if(Player const* player = ToPlayer())
  2391. {
  2392. Item* item = player->GetWeaponForAttack(attType, true);
  2393. // feral or unarmed skill only for base attack
  2394. if(attType != BASE_ATTACK && !item)
  2395. return 0;
  2396. if(IsInFeralForm())
  2397. return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact
  2398. // weapon skill or (unarmed for base attack and fist weapons)
  2399. uint32 skill;
  2400. if(item && item->GetSkill() != SKILL_FIST_WEAPONS)
  2401. skill = item->GetSkill();
  2402. else
  2403. skill = SKILL_UNARMED;
  2404. // in PvP use full skill instead current skill value
  2405. value = (target && target->IsControlledByPlayer())
  2406. ? player->GetMaxSkillValue(skill)
  2407. : player->GetSkillValue(skill);
  2408. // Modify value from ratings
  2409. value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL));
  2410. switch(attType)
  2411. {
  2412. case BASE_ATTACK: value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_MAINHAND)); break;
  2413. case OFF_ATTACK: value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_OFFHAND)); break;
  2414. case RANGED_ATTACK: value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_RANGED)); break;
  2415. default: break;
  2416. }
  2417. }
  2418. else
  2419. value = GetUnitMeleeSkill(target);
  2420. return value;
  2421. }
  2422. void Unit::_DeleteRemovedAuras()
  2423. {
  2424. while(!m_removedAuras.empty())
  2425. {
  2426. delete m_removedAuras.front();
  2427. m_removedAuras.pop_front();
  2428. }
  2429. }
  2430. void Unit::_UpdateSpells(uint32 time)
  2431. {
  2432. if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
  2433. _UpdateAutoRepeatSpell();
  2434. // remove finished spells from current pointers
  2435. for(uint32 i = 0; i < CURRENT_MAX_SPELL; ++i)
  2436. {
  2437. if(m_currentSpells[i] && m_currentSpells[i]->getState() == SPELL_STATE_FINISHED)
  2438. {
  2439. m_currentSpells[i]->SetReferencedFromCurrent(false);
  2440. m_currentSpells[i] = NULL; // remove pointer
  2441. }
  2442. }
  2443. // m_auraUpdateIterator can be updated in indirect called code at aura remove to skip next planned to update but removed auras
  2444. for(m_auraUpdateIterator = m_ownedAuras.begin(); m_auraUpdateIterator != m_ownedAuras.end();)
  2445. {
  2446. Aura* i_aura = m_auraUpdateIterator->second;
  2447. ++m_auraUpdateIterator; // need shift to next for allow update if need into aura update
  2448. i_aura->UpdateOwner(time, this);
  2449. }
  2450. // remove expired auras - do that after updates(used in scripts?)
  2451. for(AuraMap::iterator i = m_ownedAuras.begin(); i != m_ownedAuras.end();)
  2452. {
  2453. if(i->second->IsExpired())
  2454. RemoveOwnedAura(i, AURA_REMOVE_BY_EXPIRE);
  2455. else
  2456. ++i;
  2457. }
  2458. for(VisibleAuraMap::iterator itr = m_visibleAuras.begin(); itr != m_visibleAuras.end(); ++itr)
  2459. if(itr->second->IsNeedClientUpdate())
  2460. itr->second->ClientUpdate();
  2461. _DeleteRemovedAuras();
  2462. if(!m_gameObj.empty())
  2463. {
  2464. GameObjectList::iterator itr;
  2465. for(itr = m_gameObj.begin(); itr != m_gameObj.end();)
  2466. {
  2467. if(!(*itr)->isSpawned())
  2468. {
  2469. (*itr)->SetOwnerGUID(0);
  2470. (*itr)->SetRespawnTime(0);
  2471. (*itr)->Delete();
  2472. m_gameObj.erase(itr++);
  2473. }
  2474. else
  2475. ++itr;
  2476. }
  2477. }
  2478. }
  2479. void Unit::_UpdateAutoRepeatSpell()
  2480. {
  2481. // check "realtime" interrupts
  2482. if((GetTypeId() == TYPEID_PLAYER && ToPlayer()->isMoving()) || IsNonMeleeSpellCasted(false, false, true, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id == 75))
  2483. {
  2484. // cancel wand shoot
  2485. if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != 75)
  2486. InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
  2487. m_AutoRepeatFirstCast = true;
  2488. return;
  2489. }
  2490. // apply delay (Auto Shot (spellID 75) not affected)
  2491. if(m_AutoRepeatFirstCast && getAttackTimer(RANGED_ATTACK) < 500 && m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != 75)
  2492. setAttackTimer(RANGED_ATTACK, 500);
  2493. m_AutoRepeatFirstCast = false;
  2494. // castroutine
  2495. if(isAttackReady(RANGED_ATTACK))
  2496. {
  2497. // Check if able to cast
  2498. if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckCast(true) != SPELL_CAST_OK)
  2499. {
  2500. InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
  2501. return;
  2502. }
  2503. // we want to shoot
  2504. Spell* spell = new Spell(this, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo, true);
  2505. spell->prepare(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets));
  2506. // all went good, reset attack
  2507. resetAttackTimer(RANGED_ATTACK);
  2508. }
  2509. }
  2510. void Unit::SetCurrentCastedSpell(Spell* pSpell)
  2511. {
  2512. ASSERT(pSpell); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
  2513. CurrentSpellTypes CSpellType = pSpell->GetCurrentContainer();
  2514. if(pSpell == m_currentSpells[CSpellType]) return; // avoid breaking self
  2515. // break same type spell if it is not delayed
  2516. InterruptSpell(CSpellType, false);
  2517. // special breakage effects:
  2518. switch(CSpellType)
  2519. {
  2520. case CURRENT_GENERIC_SPELL:
  2521. {
  2522. // generic spells always break channeled not delayed spells
  2523. InterruptSpell(CURRENT_CHANNELED_SPELL, false);
  2524. // autorepeat breaking
  2525. if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
  2526. {
  2527. // break autorepeat if not Auto Shot
  2528. if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != 75)
  2529. InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
  2530. m_AutoRepeatFirstCast = true;
  2531. }
  2532. AddUnitState(UNIT_STAT_CASTING);
  2533. } break;
  2534. case CURRENT_CHANNELED_SPELL:
  2535. {
  2536. // channel spells always break generic non-delayed and any channeled spells
  2537. InterruptSpell(CURRENT_GENERIC_SPELL, false);
  2538. InterruptSpell(CURRENT_CHANNELED_SPELL);
  2539. // it also does break autorepeat if not Auto Shot
  2540. if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL] &&
  2541. m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != 75)
  2542. InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
  2543. AddUnitState(UNIT_STAT_CASTING);
  2544. } break;
  2545. case CURRENT_AUTOREPEAT_SPELL:
  2546. {
  2547. // only Auto Shoot does not break anything
  2548. if(pSpell->m_spellInfo->Id != 75)
  2549. {
  2550. // generic autorepeats break generic non-delayed and channeled non-delayed spells
  2551. InterruptSpell(CURRENT_GENERIC_SPELL, false);
  2552. InterruptSpell(CURRENT_CHANNELED_SPELL, false);
  2553. }
  2554. // special action: set first cast flag
  2555. m_AutoRepeatFirstCast = true;
  2556. } break;
  2557. default:
  2558. {
  2559. // other spell types don't break anything now
  2560. } break;
  2561. }
  2562. // current spell (if it is still here) may be safely deleted now
  2563. if(m_currentSpells[CSpellType])
  2564. m_currentSpells[CSpellType]->SetReferencedFromCurrent(false);
  2565. // set new current spell
  2566. m_currentSpells[CSpellType] = pSpell;
  2567. pSpell->SetReferencedFromCurrent(true);
  2568. pSpell->m_selfContainer = &(m_currentSpells[pSpell->GetCurrentContainer()]);
  2569. }
  2570. void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool withInstant)
  2571. {
  2572. ASSERT(spellType < CURRENT_MAX_SPELL);
  2573. Spell* spell = m_currentSpells[spellType];
  2574. if(spell
  2575. && (withDelayed || spell->getState() != SPELL_STATE_DELAYED)
  2576. && (withInstant || spell->GetCastTime() > 0))
  2577. {
  2578. // for example, do not let self-stun aura interrupt itself
  2579. if(!spell->IsInterruptable())
  2580. return;
  2581. // send autorepeat cancel message for autorepeat spells
  2582. if(spellType == CURRENT_AUTOREPEAT_SPELL)
  2583. if(GetTypeId() == TYPEID_PLAYER)
  2584. ToPlayer()->SendAutoRepeatCancel(this);
  2585. if(spell->getState() != SPELL_STATE_FINISHED)
  2586. spell->cancel();
  2587. m_currentSpells[spellType] = NULL;
  2588. spell->SetReferencedFromCurrent(false);
  2589. }
  2590. }
  2591. void Unit::FinishSpell(CurrentSpellTypes spellType, bool ok /*= true*/)
  2592. {
  2593. Spell* spell = m_currentSpells[spellType];
  2594. if(!spell)
  2595. return;
  2596. if(spellType == CURRENT_CHANNELED_SPELL)
  2597. spell->SendChannelUpdate(0);
  2598. spell->finish(ok);
  2599. }
  2600. bool Unit::IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled, bool skipAutorepeat, bool isAutoshoot, bool skipInstant) const
  2601. {
  2602. // We don't do loop here to explicitly show that melee spell is excluded.
  2603. // Maybe later some special spells will be excluded too.
  2604. // if checkInstant then instant spells shouldn't count as being casted
  2605. if(!skipInstant && m_currentSpells[CURRENT_GENERIC_SPELL] && !m_currentSpells[CURRENT_GENERIC_SPELL]->GetCastTime())
  2606. return false;
  2607. // generic spells are casted when they are not finished and not delayed
  2608. if(m_currentSpells[CURRENT_GENERIC_SPELL] &&
  2609. (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) &&
  2610. (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED))
  2611. {
  2612. if(!isAutoshoot || !(m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->AttributesEx2 & SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS))
  2613. return(true);
  2614. }
  2615. // channeled spells may be delayed, but they are still considered casted
  2616. else if(!skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
  2617. (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED))
  2618. {
  2619. if(!isAutoshoot || !(m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->AttributesEx2 & SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS))
  2620. return(true);
  2621. }
  2622. // autorepeat spells may be finished or delayed, but they are still considered casted
  2623. else if(!skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
  2624. return(true);
  2625. return(false);
  2626. }
  2627. void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id, bool withInstant)
  2628. {
  2629. // generic spells are interrupted if they are not finished or delayed
  2630. if(m_currentSpells[CURRENT_GENERIC_SPELL] && (!spell_id || m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id == spell_id))
  2631. InterruptSpell(CURRENT_GENERIC_SPELL, withDelayed, withInstant);
  2632. // autorepeat spells are interrupted if they are not finished or delayed
  2633. if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && (!spell_id || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id == spell_id))
  2634. InterruptSpell(CURRENT_AUTOREPEAT_SPELL, withDelayed, withInstant);
  2635. // channeled spells are interrupted if they are not finished, even if they are delayed
  2636. if(m_currentSpells[CURRENT_CHANNELED_SPELL] && (!spell_id || m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id == spell_id))
  2637. InterruptSpell(CURRENT_CHANNELED_SPELL, true, true);
  2638. }
  2639. Spell* Unit::FindCurrentSpellBySpellId(uint32 spell_id) const
  2640. {
  2641. for(uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
  2642. if(m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id == spell_id)
  2643. return m_currentSpells[i];
  2644. return NULL;
  2645. }
  2646. int32 Unit::GetCurrentSpellCastTime(uint32 spell_id) const
  2647. {
  2648. if(Spell const* spell = FindCurrentSpellBySpellId(spell_id))
  2649. return spell->GetCastTime();
  2650. return 0;
  2651. }
  2652. bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
  2653. {
  2654. return IsWithinDistInMap(target, distance) && HasInArc(arc, target);
  2655. }
  2656. bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const
  2657. {
  2658. return IsWithinDistInMap(target, distance) && !HasInArc(2 * M_PI - arc, target);
  2659. }
  2660. bool Unit::SetWalk(bool enable)
  2661. {
  2662. if(enable == IsWalking())
  2663. return false;
  2664. if(enable)
  2665. AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
  2666. else
  2667. RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
  2668. return true;
  2669. }
  2670. bool Unit::SetDisableGravity(bool disable, bool /*packetOnly = false*/)
  2671. {
  2672. if(disable == IsLevitating())
  2673. return false;
  2674. if(disable)
  2675. AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
  2676. else
  2677. RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
  2678. return true;
  2679. }
  2680. bool Unit::isInAccessiblePlaceFor(Creature const* c) const
  2681. {
  2682. if(IsInWater())
  2683. return c->canSwim();
  2684. else
  2685. return c->canWalk() || c->canFly();
  2686. }
  2687. bool Unit::IsInWater() const
  2688. {
  2689. return GetBaseMap()->IsInWater(GetPositionX(), GetPositionY(), GetPositionZ());
  2690. }
  2691. bool Unit::IsUnderWater() const
  2692. {
  2693. return GetBaseMap()->IsUnderWater(GetPositionX(), GetPositionY(), GetPositionZ());
  2694. }
  2695. void Unit::UpdateUnderwaterState(Map* m, float x, float y, float z)
  2696. {
  2697. if(!isPet() && !IsVehicle())
  2698. return;
  2699. LiquidData liquid_status;
  2700. ZLiquidStatus res = m->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquid_status);
  2701. if(!res)
  2702. {
  2703. if(m_lastLiquid && m_lastLiquid->SpellId)
  2704. RemoveAurasDueToSpell(m_lastLiquid->SpellId);
  2705. RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_UNDERWATER);
  2706. m_lastLiquid = NULL;
  2707. return;
  2708. }
  2709. if(uint32 liqEntry = liquid_status.entry)
  2710. {
  2711. LiquidTypeEntry const* liquid = sLiquidTypeStore.LookupEntry(liqEntry);
  2712. if(m_lastLiquid && m_lastLiquid->SpellId && m_lastLiquid->Id != liqEntry)
  2713. RemoveAurasDueToSpell(m_lastLiquid->SpellId);
  2714. if(liquid && liquid->SpellId)
  2715. {
  2716. if(res & (LIQUID_MAP_UNDER_WATER | LIQUID_MAP_IN_WATER))
  2717. CastSpell(this, liquid->SpellId, true);
  2718. else
  2719. RemoveAurasDueToSpell(liquid->SpellId);
  2720. }
  2721. RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_ABOVEWATER);
  2722. m_lastLiquid = liquid;
  2723. }
  2724. else if(m_lastLiquid && m_lastLiquid->SpellId)
  2725. {
  2726. RemoveAurasDueToSpell(m_lastLiquid->SpellId);
  2727. RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_UNDERWATER);
  2728. m_lastLiquid = NULL;
  2729. }
  2730. }
  2731. void Unit::DeMorph()
  2732. {
  2733. SetDisplayId(GetNativeDisplayId());
  2734. }
  2735. Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellEntry const* newAura, uint8 effMask, Unit* caster, int32* baseAmount /*= NULL*/, Item* castItem /*= NULL*/, uint64 casterGUID /*= 0*/)
  2736. {
  2737. ASSERT(casterGUID || caster);
  2738. if(!casterGUID)
  2739. casterGUID = caster->GetGUID();
  2740. // passive and Incanter's Absorption and auras with different type can stack with themselves any number of times
  2741. if(!IsMultiSlotAura(newAura))
  2742. {
  2743. // check if cast item changed
  2744. uint64 castItemGUID = 0;
  2745. if(castItem)
  2746. castItemGUID = castItem->GetGUID();
  2747. // find current aura from spell and change it's stackamount, or refresh it's duration
  2748. if(Aura* foundAura = GetOwnedAura(newAura->Id, casterGUID, (sSpellMgr->GetSpellCustomAttr(newAura->Id) & SPELL_ATTR0_CU_ENCHANT_PROC) ? castItemGUID : 0, 0))
  2749. {
  2750. // effect masks do not match
  2751. // extremely rare case
  2752. // let's just recreate aura
  2753. if(effMask != foundAura->GetEffectMask())
  2754. return NULL;
  2755. // update basepoints with new values - effect amount will be recalculated in ModStackAmount
  2756. for(uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
  2757. {
  2758. if(!foundAura->HasEffect(i))
  2759. continue;
  2760. int bp;
  2761. if(baseAmount)
  2762. bp = *(baseAmount + i);
  2763. else
  2764. bp = foundAura->GetSpellProto()->EffectBasePoints[i];
  2765. int32* oldBP = const_cast<int32*>(&(foundAura->GetEffect(i)->m_baseAmount));
  2766. *oldBP = bp;
  2767. }
  2768. // correct cast item guid if needed
  2769. if(castItemGUID != foundAura->GetCastItemGUID())
  2770. {
  2771. uint64* oldGUID = const_cast<uint64 *>(&foundAura->m_castItemGuid);
  2772. *oldGUID = castItemGUID;
  2773. }
  2774. // try to increase stack amount
  2775. foundAura->ModStackAmount(1);
  2776. return foundAura;
  2777. }
  2778. }
  2779. return NULL;
  2780. }
  2781. void Unit::_AddAura(UnitAura* pAura, Unit* pCaster)
  2782. {
  2783. if(m_cleanupDone)
  2784. sLog->outDetail("OH FUCK! Unit::_AddAura ID: %u", pAura->GetId());
  2785. m_ownedAuras.insert(AuraMap::value_type(pAura->GetId(), pAura));
  2786. _RemoveNoStackAurasDueToAura(pAura);
  2787. if(pAura->IsRemoved())
  2788. return;
  2789. if(!pCaster)
  2790. return;
  2791. pAura->SetIsSingleTarget(pCaster && IsSingleTargetSpell(pAura->GetSpellProto()));
  2792. if(pAura->IsSingleTarget())
  2793. {
  2794. ASSERT((IsInWorld() && !IsDuringRemoveFromWorld()) || (pAura->GetCasterGUID() == GetGUID()));
  2795. // register single target aura
  2796. pCaster->GetSingleCastAuras().push_back(pAura);
  2797. // remove other single target auras
  2798. Unit::AuraList& scAuras = pCaster->GetSingleCastAuras();
  2799. for(Unit::AuraList::iterator itr = scAuras.begin(); itr != scAuras.end();)
  2800. {
  2801. if((*itr) != pAura &&
  2802. IsSingleTargetSpells((*itr)->GetSpellProto(), pAura->GetSpellProto()))
  2803. {
  2804. (*itr)->Remove();
  2805. itr = scAuras.begin();
  2806. }
  2807. else
  2808. ++itr;
  2809. }
  2810. }
  2811. }
  2812. // creates aura application instance and registers it in lists
  2813. // aura application effects are handled separately to prevent aura list corruption
  2814. AuraApplication* Unit::_CreateAuraApplication(Aura* pAura, uint8 effMask)
  2815. {
  2816. // can't apply aura on unit which is going to be deleted - to not create a memory leak
  2817. if(m_cleanupDone)
  2818. sLog->outDetail("OH FUCK! Unit::_CreateAuraApplication ID: %u", pAura->GetId());
  2819. // aura musn't be removed
  2820. ASSERT(!pAura->IsRemoved());
  2821. // aura mustn't be already applied on target
  2822. ASSERT(!pAura->IsAppliedOnTarget(GetGUID()) && "Unit::_CreateAuraApplication: aura musn't be applied on target");
  2823. SpellEntry const* aurSpellInfo = pAura->GetSpellProto();
  2824. uint32 aurId = aurSpellInfo->Id;
  2825. // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
  2826. if(!isAlive() && !IsDeathPersistentSpell(aurSpellInfo) &&
  2827. (GetTypeId() != TYPEID_PLAYER || !ToPlayer()->GetSession()->PlayerLoading()))
  2828. return NULL;
  2829. Unit* pCaster = pAura->GetCaster();
  2830. AuraApplication* aurApp = new AuraApplication(this, pCaster, pAura, effMask);
  2831. m_appliedAuras.insert(AuraApplicationMap::value_type(aurId, aurApp));
  2832. if(aurSpellInfo->AuraInterruptFlags)
  2833. {
  2834. m_interruptableAuras.push_back(aurApp);
  2835. AddInterruptMask(aurSpellInfo->AuraInterruptFlags);
  2836. }
  2837. if(AuraState aState = GetSpellAuraState(pAura->GetSpellProto()))
  2838. m_auraStateAuras.insert(AuraStateAurasMap::value_type(aState, aurApp));
  2839. pAura->_ApplyForTarget(this, pCaster, aurApp);
  2840. return aurApp;
  2841. }
  2842. void Unit::_ApplyAuraEffect(Aura* pAura, uint8 effIndex)
  2843. {
  2844. ASSERT(pAura);
  2845. ASSERT(pAura->HasEffect(effIndex));
  2846. AuraApplication* aurApp = pAura->GetApplicationOfTarget(GetGUID());
  2847. ASSERT(aurApp);
  2848. if(!aurApp->GetEffectMask())
  2849. _ApplyAura(aurApp, 1 << effIndex);
  2850. else
  2851. aurApp->_HandleEffect(effIndex, true);
  2852. }
  2853. // handles effects of aura application
  2854. // should be done after registering aura in lists
  2855. void Unit::_ApplyAura(AuraApplication* aurApp, uint8 effMask)
  2856. {
  2857. Aura* aura = aurApp->GetBase();
  2858. _RemoveNoStackAurasDueToAura(aura);
  2859. if(aurApp->GetRemoveMode())
  2860. return;
  2861. // Update target aura state flag
  2862. if(AuraState aState = GetSpellAuraState(aura->GetSpellProto()))
  2863. ModifyAuraState(aState, true);
  2864. if(aurApp->GetRemoveMode())
  2865. return;
  2866. // Sitdown on apply aura req seated
  2867. if(aura->GetSpellProto()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED && !IsSitState())
  2868. SetStandState(UNIT_STAND_STATE_SIT);
  2869. Unit* caster = aura->GetCaster();
  2870. if(aurApp->GetRemoveMode())
  2871. return;
  2872. aura->HandleAuraSpecificMods(aurApp, caster, true, false);
  2873. // apply effects of the aura
  2874. for(uint8 i = 0 ; i < MAX_SPELL_EFFECTS; ++i)
  2875. {
  2876. if(effMask & 1 << i && (!aurApp->GetRemoveMode()))
  2877. aurApp->_HandleEffect(i, true);
  2878. }
  2879. }
  2880. // removes aura application from lists and unapplies effects
  2881. void Unit::_UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMode)
  2882. {
  2883. AuraApplication* aurApp = i->second;
  2884. ASSERT(aurApp);
  2885. ASSERT(!aurApp->GetRemoveMode());
  2886. ASSERT(aurApp->GetTarget() == this);
  2887. aurApp->SetRemoveMode(removeMode);
  2888. Aura* aura = aurApp->GetBase();
  2889. sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Aura %u now is remove mode %d", aura->GetId(), removeMode);
  2890. // dead loop is killing the server probably
  2891. ASSERT(m_removedAurasCount < 0xFFFFFFFF);
  2892. ++m_removedAurasCount;
  2893. Unit* caster = aura->GetCaster();
  2894. // Remove all pointers from lists here to prevent possible pointer invalidation on spellcast/auraapply/auraremove
  2895. m_appliedAuras.erase(i);
  2896. if(aura->GetSpellProto()->AuraInterruptFlags)
  2897. {
  2898. m_interruptableAuras.remove(aurApp);
  2899. UpdateInterruptMask();
  2900. }
  2901. bool auraStateFound = false;
  2902. AuraState auraState = GetSpellAuraState(aura->GetSpellProto());
  2903. if(auraState)
  2904. {
  2905. bool canBreak = false;
  2906. // Get mask of all aurastates from remaining auras
  2907. for(AuraStateAurasMap::iterator itr = m_auraStateAuras.lower_bound(auraState); itr != m_auraStateAuras.upper_bound(auraState) && !(auraStateFound && canBreak);)
  2908. {
  2909. if(itr->second == aurApp)
  2910. {
  2911. m_auraStateAuras.erase(itr);
  2912. itr = m_auraStateAuras.lower_bound(auraState);
  2913. canBreak = true;
  2914. continue;
  2915. }
  2916. auraStateFound = true;
  2917. ++itr;
  2918. }
  2919. }
  2920. aurApp->_Remove();
  2921. aura->_UnapplyForTarget(this, caster, aurApp);
  2922. // remove effects of the spell - needs to be done after removing aura from lists
  2923. for(uint8 itr = 0 ; itr < MAX_SPELL_EFFECTS; ++itr)
  2924. {
  2925. if(aurApp->HasEffect(itr))
  2926. aurApp->_HandleEffect(itr, false);
  2927. }
  2928. // all effect mustn't be applied
  2929. ASSERT(!aurApp->GetEffectMask());
  2930. // Remove totem at next update if totem loses its aura
  2931. if(aurApp->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE && GetTypeId() == TYPEID_UNIT && ToCreature()->isTotem()&& ToTotem()->GetSummonerGUID() == aura->GetCasterGUID())
  2932. {
  2933. if(ToTotem()->GetSpell() == aura->GetId() && ToTotem()->GetTotemType() == TOTEM_PASSIVE)
  2934. ToTotem()->setDeathState(JUST_DIED);
  2935. }
  2936. // Remove aurastates only if were not found
  2937. if(!auraStateFound)
  2938. ModifyAuraState(auraState, false);
  2939. aura->HandleAuraSpecificMods(aurApp, caster, false, false);
  2940. i = m_appliedAuras.begin();
  2941. }
  2942. void Unit::_UnapplyAura(AuraApplication* aurApp, AuraRemoveMode removeMode)
  2943. {
  2944. // aura can be removed from unit only if it's applied on it, shouldn't happen
  2945. ASSERT(aurApp->GetBase()->GetApplicationOfTarget(GetGUID()) == aurApp);
  2946. uint32 spellId = aurApp->GetBase()->GetId();
  2947. for(AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
  2948. {
  2949. if(iter->second == aurApp)
  2950. {
  2951. _UnapplyAura(iter, removeMode);
  2952. return;
  2953. }
  2954. else
  2955. ++iter;
  2956. }
  2957. ASSERT(false);
  2958. }
  2959. void Unit::_RemoveNoStackAuraApplicationsDueToAura(Aura* pAura)
  2960. {
  2961. // dynobj auras can stack infinite number of times
  2962. if(pAura->GetType() == DYNOBJ_AURA_TYPE)
  2963. return;
  2964. SpellEntry const* pSpellEntry = pAura->GetSpellProto();
  2965. uint32 spellId = pSpellEntry->Id;
  2966. // passive spell special case (only non stackable with ranks)
  2967. if(IsPassiveSpell(spellId) && IsPassiveSpellStackableWithRanks(pSpellEntry))
  2968. return;
  2969. bool remove = false;
  2970. for(AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
  2971. {
  2972. if(remove)
  2973. {
  2974. remove = false;
  2975. i = m_appliedAuras.begin();
  2976. }
  2977. if(!_IsNoStackAuraDueToAura(pAura, i->second->GetBase()))
  2978. continue;
  2979. RemoveAura(i, AURA_REMOVE_BY_DEFAULT);
  2980. if(i == m_appliedAuras.end())
  2981. break;
  2982. remove = true;
  2983. }
  2984. }
  2985. void Unit::_RemoveNoStackAurasDueToAura(Aura* pAura)
  2986. {
  2987. SpellEntry const* pSpellEntry = pAura->GetSpellProto();
  2988. uint32 spellId = pSpellEntry->Id;
  2989. // passive spell special case (only non stackable with ranks)
  2990. if(IsPassiveSpell(spellId) && IsPassiveSpellStackableWithRanks(pSpellEntry))
  2991. return;
  2992. bool remove = false;
  2993. for(AuraMap::iterator i = m_ownedAuras.begin(); i != m_ownedAuras.end(); ++i)
  2994. {
  2995. if(remove)
  2996. {
  2997. remove = false;
  2998. i = m_ownedAuras.begin();
  2999. }
  3000. if(!_IsNoStackAuraDueToAura(pAura, i->second))
  3001. continue;
  3002. RemoveOwnedAura(i, AURA_REMOVE_BY_DEFAULT);
  3003. if(i == m_ownedAuras.end())
  3004. break;
  3005. remove = true;
  3006. }
  3007. }
  3008. bool Unit::_IsNoStackAuraDueToAura(Aura* pAppliedAura, Aura* pExistingAura) const
  3009. {
  3010. SpellEntry const* pSpellEntryAP = pAppliedAura->GetSpellProto();
  3011. // Do not check already applied aura
  3012. if(pExistingAura == pAppliedAura)
  3013. return false;
  3014. // Do not check dynobj auras for stacking
  3015. if(pExistingAura->GetType() != UNIT_AURA_TYPE)
  3016. return false;
  3017. SpellEntry const* pSpellEntryEP = pExistingAura->GetSpellProto();
  3018. uint32 i_spellId = pSpellEntryEP->Id;
  3019. bool sameCaster = pAppliedAura->GetCasterGUID() == pExistingAura->GetCasterGUID();
  3020. if(IsPassiveSpell(i_spellId))
  3021. {
  3022. // passive non-stackable spells not stackable only for same caster
  3023. if(!sameCaster)
  3024. return false;
  3025. // passive non-stackable spells not stackable only with another rank of same spell
  3026. if(!sSpellMgr->IsRankSpellDueToSpell(pSpellEntryAP, i_spellId))
  3027. return false;
  3028. }
  3029. bool is_triggered_by_spell = false;
  3030. // prevent triggering aura of removing aura that triggered it
  3031. // prevent triggered aura of removing aura that triggering it (triggered effect early some aura of parent spell
  3032. for(uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
  3033. {
  3034. if(pSpellEntryEP->EffectTriggerSpell[j] == pSpellEntryAP->Id
  3035. || pSpellEntryAP->EffectTriggerSpell[j] == pSpellEntryEP->Id) // I do not know what is this for
  3036. {
  3037. is_triggered_by_spell = true;
  3038. break;
  3039. }
  3040. }
  3041. if(is_triggered_by_spell)
  3042. return false;
  3043. if(sSpellMgr->CanAurasStack(pAppliedAura, pExistingAura, sameCaster))
  3044. return false;
  3045. return true;
  3046. }
  3047. void Unit::_RegisterAuraEffect(AuraEffect* aurEff, bool apply)
  3048. {
  3049. if(apply)
  3050. m_modAuras[aurEff->GetAuraType()].push_back(aurEff);
  3051. else
  3052. m_modAuras[aurEff->GetAuraType()].remove(aurEff);
  3053. }
  3054. // All aura base removes should go threw this function!
  3055. void Unit::RemoveOwnedAura(AuraMap::iterator &i, AuraRemoveMode removeMode)
  3056. {
  3057. Aura* aura = i->second;
  3058. ASSERT(!aura->IsRemoved());
  3059. // if unit currently update aura list then make safe update iterator shift to next
  3060. if(m_auraUpdateIterator == i)
  3061. ++m_auraUpdateIterator;
  3062. m_ownedAuras.erase(i);
  3063. m_removedAuras.push_back(aura);
  3064. // Unregister single target aura
  3065. if(aura->IsSingleTarget())
  3066. aura->UnregisterSingleTarget();
  3067. aura->_Remove(removeMode);
  3068. i = m_ownedAuras.begin();
  3069. }
  3070. void Unit::RemoveOwnedAura(uint32 spellId, uint64 caster, uint8 reqEffMask, AuraRemoveMode removeMode)
  3071. {
  3072. for(AuraMap::iterator itr = m_ownedAuras.lower_bound(spellId); itr != m_ownedAuras.upper_bound(spellId);)
  3073. if(((itr->second->GetEffectMask() & reqEffMask) == reqEffMask) && (!caster || itr->second->GetCasterGUID() == caster))
  3074. {
  3075. RemoveOwnedAura(itr, removeMode);
  3076. itr = m_ownedAuras.lower_bound(spellId);
  3077. }
  3078. else
  3079. ++itr;
  3080. }
  3081. void Unit::RemoveOwnedAura(Aura* aura, AuraRemoveMode removeMode)
  3082. {
  3083. if(aura->IsRemoved())
  3084. return;
  3085. ASSERT(aura->GetOwner() == this);
  3086. uint32 spellId = aura->GetId();
  3087. for(AuraMap::iterator itr = m_ownedAuras.lower_bound(spellId); itr != m_ownedAuras.upper_bound(spellId); ++itr)
  3088. {
  3089. if(itr->second == aura)
  3090. {
  3091. RemoveOwnedAura(itr, removeMode);
  3092. return;
  3093. }
  3094. }
  3095. }
  3096. Aura* Unit::GetOwnedAura(uint32 spellId, uint64 casterGUID, uint64 itemCasterGUID, uint8 reqEffMask, Aura* except) const
  3097. {
  3098. for(AuraMap::const_iterator itr = m_ownedAuras.lower_bound(spellId); itr != m_ownedAuras.upper_bound(spellId); ++itr)
  3099. if(((itr->second->GetEffectMask() & reqEffMask) == reqEffMask) && (!casterGUID || itr->second->GetCasterGUID() == casterGUID) && (!itemCasterGUID || itr->second->GetCastItemGUID() == itemCasterGUID) && (!except || except != itr->second))
  3100. return itr->second;
  3101. return NULL;
  3102. }
  3103. void Unit::RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode)
  3104. {
  3105. AuraApplication* aurApp = i->second;
  3106. // Do not remove aura which is already being removed
  3107. if(aurApp->GetRemoveMode())
  3108. return;
  3109. Aura* aura = aurApp->GetBase();
  3110. _UnapplyAura(i, mode);
  3111. // Remove aura - for Area and Target auras
  3112. if(aura->GetOwner() == this)
  3113. aura->Remove(mode);
  3114. }
  3115. void Unit::RemoveAura(uint32 spellId, uint64 caster, uint8 reqEffMask, AuraRemoveMode removeMode)
  3116. {
  3117. for(AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
  3118. {
  3119. Aura const* aura = iter->second->GetBase();
  3120. if(((aura->GetEffectMask() & reqEffMask) == reqEffMask)
  3121. && (!caster || aura->GetCasterGUID() == caster))
  3122. {
  3123. RemoveAura(iter, removeMode);
  3124. return;
  3125. }
  3126. else
  3127. ++iter;
  3128. }
  3129. }
  3130. void Unit::RemoveAura(AuraApplication* aurApp, AuraRemoveMode mode)
  3131. {
  3132. // we've special situation here, RemoveAura called while during aura removal
  3133. // this kind of call is needed only when aura effect removal handler
  3134. // or event triggered by it expects to remove
  3135. // not yet removed effects of an aura
  3136. if(aurApp->GetRemoveMode())
  3137. {
  3138. // remove remaining effects of an aura
  3139. for(uint8 itr = 0 ; itr < MAX_SPELL_EFFECTS; ++itr)
  3140. {
  3141. if(aurApp->HasEffect(itr))
  3142. aurApp->_HandleEffect(itr, false);
  3143. }
  3144. return;
  3145. }
  3146. // no need to remove
  3147. if(aurApp->GetBase()->GetApplicationOfTarget(GetGUID()) != aurApp || aurApp->GetBase()->IsRemoved())
  3148. return;
  3149. uint32 spellId = aurApp->GetBase()->GetId();
  3150. for(AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
  3151. {
  3152. if(aurApp == iter->second)
  3153. {
  3154. RemoveAura(iter, mode);
  3155. return;
  3156. }
  3157. else
  3158. ++iter;
  3159. }
  3160. }
  3161. void Unit::RemoveAura(Aura* aura, AuraRemoveMode mode)
  3162. {
  3163. if(aura->IsRemoved())
  3164. return;
  3165. if(AuraApplication* aurApp = aura->GetApplicationOfTarget(GetGUID()))
  3166. RemoveAura(aurApp, mode);
  3167. }
  3168. void Unit::RemoveAurasDueToSpell(uint32 spellId, uint64 caster, uint8 reqEffMask, AuraRemoveMode removeMode)
  3169. {
  3170. for(AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
  3171. {
  3172. Aura const* pAura = iter->second->GetBase();
  3173. if(pAura && ((pAura->GetEffectMask() & reqEffMask) == reqEffMask) && (!caster || pAura->GetCasterGUID() == caster))
  3174. {
  3175. RemoveAura(iter, removeMode);
  3176. iter = m_appliedAuras.lower_bound(spellId);
  3177. }
  3178. else
  3179. ++iter;
  3180. }
  3181. }
  3182. void Unit::RemoveAuraFromStack(uint32 spellId, uint64 caster, AuraRemoveMode removeMode)
  3183. {
  3184. for(AuraMap::iterator iter = m_ownedAuras.lower_bound(spellId); iter != m_ownedAuras.upper_bound(spellId);)
  3185. {
  3186. Aura* pAura = iter->second;
  3187. if((pAura->GetType() == UNIT_AURA_TYPE) && (!caster || pAura->GetCasterGUID() == caster))
  3188. {
  3189. pAura->ModStackAmount(-1, removeMode);
  3190. return;
  3191. }
  3192. else
  3193. ++iter;
  3194. }
  3195. }
  3196. void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint64 casterGUID, Unit* dispeller, uint8 chargesRemoved/*= 1*/)
  3197. {
  3198. for(AuraMap::iterator iter = m_ownedAuras.lower_bound(spellId); iter != m_ownedAuras.upper_bound(spellId);)
  3199. {
  3200. Aura* aura = iter->second;
  3201. if(aura->GetCasterGUID() == casterGUID)
  3202. {
  3203. if(aura->GetSpellProto()->AttributesEx7 & SPELL_ATTR7_DISPEL_CHARGES)
  3204. aura->ModCharges(-chargesRemoved, AURA_REMOVE_BY_ENEMY_SPELL);
  3205. else
  3206. aura->ModStackAmount(-chargesRemoved, AURA_REMOVE_BY_ENEMY_SPELL);
  3207. switch(aura->GetSpellProto()->SpellFamilyName)
  3208. {
  3209. case SPELLFAMILY_WARLOCK:
  3210. {
  3211. // Unstable Affliction (crash if before removeaura?)
  3212. if(aura->GetSpellProto()->SpellFamilyFlags[1] & 0x0100)
  3213. {
  3214. Unit* caster = aura->GetCaster();
  3215. if(!caster)
  3216. break;
  3217. if(AuraEffect const* aurEff = aura->GetEffect(EFFECT_0))
  3218. {
  3219. int32 damage = aurEff->GetAmount() * 9;
  3220. // backfire damage and silence
  3221. caster->CastCustomSpell(dispeller, 31117, &damage, NULL, NULL, true, NULL, aurEff);
  3222. }
  3223. }
  3224. break;
  3225. }
  3226. case SPELLFAMILY_DRUID:
  3227. {
  3228. // Lifebloom
  3229. if(aura->GetSpellProto()->SpellFamilyFlags[1] & 0x10)
  3230. {
  3231. if(AuraEffect const* aurEff = aura->GetEffect(EFFECT_1))
  3232. {
  3233. // final heal
  3234. int32 healAmount = aurEff->GetAmount();
  3235. int32 stack = chargesRemoved;
  3236. CastCustomSpell(this, 33778, &healAmount, &stack, NULL, true, NULL, NULL, aura->GetCasterGUID());
  3237. // mana
  3238. if(Unit* caster = aura->GetCaster())
  3239. {
  3240. int32 mana = CalculatePctU(caster->GetCreateMana(), aura->GetSpellProto()->ManaCostPercentage) * chargesRemoved / 2;
  3241. caster->CastCustomSpell(caster, 64372, &mana, NULL, NULL, true, NULL, NULL, aura->GetCasterGUID());
  3242. }
  3243. }
  3244. }
  3245. break;
  3246. }
  3247. case SPELLFAMILY_SHAMAN:
  3248. {
  3249. // Flame Shock
  3250. if(aura->GetSpellProto()->SpellFamilyFlags[0] & 0x10000000)
  3251. {
  3252. if(Unit* caster = aura->GetCaster())
  3253. {
  3254. uint32 triggeredSpellId = 0;
  3255. // Lava Flows
  3256. if(AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_SHAMAN, 3087, 0))
  3257. {
  3258. switch(aurEff->GetId())
  3259. {
  3260. case 51482: // Rank 3
  3261. triggeredSpellId = 65264;
  3262. break;
  3263. case 51481: // Rank 2
  3264. triggeredSpellId = 65263;
  3265. break;
  3266. case 51480: // Rank 1
  3267. triggeredSpellId = 64694;
  3268. break;
  3269. default:
  3270. sLog->outError("Unit::RemoveAurasDueToSpellByDispel: Unknown rank of Lava Flows (%d) found", aurEff->GetId());
  3271. }
  3272. }
  3273. if(triggeredSpellId)
  3274. caster->CastSpell(caster, triggeredSpellId, true);
  3275. }
  3276. }
  3277. break;
  3278. }
  3279. case SPELLFAMILY_HUNTER:
  3280. {
  3281. // Wyvern Sting
  3282. if(aura->GetSpellProto()->SpellFamilyFlags[1] & 0x1000)
  3283. {
  3284. Unit* caster = aura->GetCaster();
  3285. if(caster && !(dispeller->GetTypeId() == TYPEID_UNIT && dispeller->ToCreature()->isTotem()))
  3286. { // Noxious Stings
  3287. if(AuraEffect* auraEff = caster->GetAuraEffect(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS, SPELLFAMILY_HUNTER, 3521, 1))
  3288. if(Aura* newAura = caster->AddAura(aura->GetId(), dispeller))
  3289. newAura->SetDuration(aura->GetDuration() / 100 * auraEff->GetAmount());
  3290. }
  3291. }
  3292. }
  3293. default:
  3294. break;
  3295. }
  3296. return;
  3297. }
  3298. else
  3299. ++iter;
  3300. }
  3301. }
  3302. void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit* stealer)
  3303. {
  3304. for(AuraMap::iterator iter = m_ownedAuras.lower_bound(spellId); iter != m_ownedAuras.upper_bound(spellId);)
  3305. {
  3306. Aura* aura = iter->second;
  3307. if(aura->GetCasterGUID() == casterGUID)
  3308. {
  3309. int32 damage[MAX_SPELL_EFFECTS];
  3310. int32 baseDamage[MAX_SPELL_EFFECTS];
  3311. uint8 effMask = 0;
  3312. uint8 recalculateMask = 0;
  3313. Unit* caster = aura->GetCaster();
  3314. for(uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
  3315. {
  3316. if(aura->GetEffect(i))
  3317. {
  3318. baseDamage[i] = aura->GetEffect(i)->GetBaseAmount();
  3319. damage[i] = aura->GetEffect(i)->GetAmount();
  3320. effMask |= (1<<i);
  3321. if(aura->GetEffect(i)->CanBeRecalculated())
  3322. recalculateMask |= (1<<i);
  3323. }
  3324. else
  3325. {
  3326. baseDamage[i] = 0;
  3327. damage[i] = 0;
  3328. }
  3329. }
  3330. bool stealCharge = aura->GetSpellProto()->AttributesEx7 & SPELL_ATTR7_DISPEL_CHARGES;
  3331. int32 dur = std::min(2 * MINUTE * IN_MILLISECONDS, aura->GetDuration());
  3332. if(Aura* newAura = stealer->GetAura(aura->GetId(), aura->GetCasterGUID()))
  3333. {
  3334. if(stealCharge)
  3335. newAura->ModCharges(1);
  3336. else
  3337. newAura->ModStackAmount(1);
  3338. newAura->SetDuration(dur);
  3339. }
  3340. else
  3341. {
  3342. // single target state must be removed before aura creation to preserve existing single target aura
  3343. if(aura->IsSingleTarget())
  3344. aura->UnregisterSingleTarget();
  3345. if(Aura* newAura = Aura::TryRefreshStackOrCreate(aura->GetSpellProto(), effMask, stealer, NULL, &baseDamage[0], NULL, aura->GetCasterGUID()))
  3346. {
  3347. // created aura must not be single target aura,, so stealer won't loose it on recast
  3348. if(newAura->IsSingleTarget())
  3349. {
  3350. newAura->UnregisterSingleTarget();
  3351. // bring back single target aura status to the old aura
  3352. aura->SetIsSingleTarget(true);
  3353. caster->GetSingleCastAuras().push_back(aura);
  3354. }
  3355. // FIXME: using aura->GetMaxDuration() maybe not blizzlike but it fixes stealing of spells like Innervate
  3356. newAura->SetLoadedState(aura->GetMaxDuration(), dur, stealCharge ? 1 : aura->GetCharges(), 1, recalculateMask, &damage[0]);
  3357. newAura->ApplyForTargets();
  3358. }
  3359. }
  3360. if(stealCharge)
  3361. aura->ModCharges(-1, AURA_REMOVE_BY_ENEMY_SPELL);
  3362. else
  3363. aura->ModStackAmount(-1, AURA_REMOVE_BY_ENEMY_SPELL);
  3364. return;
  3365. }
  3366. else
  3367. ++iter;
  3368. }
  3369. }
  3370. void Unit::RemoveAurasDueToItemSpell(Item* castItem, uint32 spellId)
  3371. {
  3372. for(AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
  3373. {
  3374. if(!castItem || iter->second->GetBase()->GetCastItemGUID() == castItem->GetGUID())
  3375. {
  3376. RemoveAura(iter);
  3377. iter = m_appliedAuras.upper_bound(spellId); // overwrite by more appropriate
  3378. }
  3379. else
  3380. ++iter;
  3381. }
  3382. }
  3383. void Unit::RemoveAurasByType(AuraType auraType, uint64 casterGUID, Aura* except, bool negative, bool positive)
  3384. {
  3385. for(AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
  3386. {
  3387. Aura* aura = (*iter)->GetBase();
  3388. AuraApplication* aurApp = aura->GetApplicationOfTarget(GetGUID());
  3389. ++iter;
  3390. if(aurApp && aura != except && (!casterGUID || aura->GetCasterGUID() == casterGUID)
  3391. && ((negative && !aurApp->IsPositive()) || (positive && aurApp->IsPositive())))
  3392. {
  3393. uint32 removedAuras = m_removedAurasCount;
  3394. RemoveAura(aurApp);
  3395. if(m_removedAurasCount > removedAuras + 1)
  3396. iter = m_modAuras[auraType].begin();
  3397. }
  3398. }
  3399. }
  3400. void Unit::RemoveAurasWithAttribute(uint32 flags)
  3401. {
  3402. for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
  3403. {
  3404. SpellEntry const* spell = iter->second->GetBase()->GetSpellProto();
  3405. if(spell->Attributes & flags)
  3406. RemoveAura(iter);
  3407. else
  3408. ++iter;
  3409. }
  3410. }
  3411. void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase)
  3412. {
  3413. // single target auras from other casters
  3414. for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
  3415. {
  3416. AuraApplication const* aurApp = iter->second;
  3417. Aura const* aura = aurApp->GetBase();
  3418. if(aura->GetCasterGUID() != GetGUID() && IsSingleTargetSpell(aura->GetSpellProto()))
  3419. {
  3420. if(!newPhase)
  3421. RemoveAura(iter);
  3422. else
  3423. {
  3424. Unit* caster = aura->GetCaster();
  3425. if(!caster || !caster->InSamePhase(newPhase))
  3426. RemoveAura(iter);
  3427. else
  3428. ++iter;
  3429. }
  3430. }
  3431. else
  3432. ++iter;
  3433. }
  3434. // single target auras at other targets
  3435. AuraList& scAuras = GetSingleCastAuras();
  3436. for(AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();)
  3437. {
  3438. Aura* aura = *iter;
  3439. if(aura->GetUnitOwner() != this && !aura->GetUnitOwner()->InSamePhase(newPhase))
  3440. {
  3441. aura->Remove();
  3442. iter = scAuras.begin();
  3443. }
  3444. else
  3445. ++iter;
  3446. }
  3447. }
  3448. void Unit::RemoveAurasWithInterruptFlags(uint32 flag, uint32 except)
  3449. {
  3450. if(!(m_interruptMask & flag))
  3451. return;
  3452. // interrupt auras
  3453. for(AuraApplicationList::iterator iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end();)
  3454. {
  3455. Aura* aura = (*iter)->GetBase();
  3456. ++iter;
  3457. if((aura->GetSpellProto()->AuraInterruptFlags & flag) && (!except || aura->GetId() != except))
  3458. {
  3459. uint32 removedAuras = m_removedAurasCount;
  3460. RemoveAura(aura);
  3461. if(m_removedAurasCount > removedAuras + 1)
  3462. iter = m_interruptableAuras.begin();
  3463. }
  3464. }
  3465. // interrupt channeled spell
  3466. if(Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL])
  3467. if(spell->getState() == SPELL_STATE_CASTING
  3468. && (spell->m_spellInfo->ChannelInterruptFlags & flag)
  3469. && spell->m_spellInfo->Id != except)
  3470. InterruptNonMeleeSpells(false);
  3471. UpdateInterruptMask();
  3472. }
  3473. void Unit::RemoveAurasWithFamily(SpellFamilyNames family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, uint64 casterGUID)
  3474. {
  3475. for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
  3476. {
  3477. Aura const* aura = iter->second->GetBase();
  3478. if(!casterGUID || aura->GetCasterGUID() == casterGUID)
  3479. {
  3480. SpellEntry const* spell = aura->GetSpellProto();
  3481. if(spell->SpellFamilyName == uint32(family) && spell->SpellFamilyFlags.HasFlag(familyFlag1, familyFlag2, familyFlag3))
  3482. {
  3483. RemoveAura(iter);
  3484. continue;
  3485. }
  3486. }
  3487. ++iter;
  3488. }
  3489. }
  3490. void Unit::RemoveMovementImpairingAuras()
  3491. {
  3492. RemoveAurasWithMechanic((1<<MECHANIC_SNARE)|(1<<MECHANIC_ROOT));
  3493. }
  3494. void Unit::RemoveAurasWithMechanic(uint32 mechanic_mask, AuraRemoveMode removemode, uint32 except)
  3495. {
  3496. for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
  3497. {
  3498. Aura const* aura = iter->second->GetBase();
  3499. if(!except || aura->GetId() != except)
  3500. {
  3501. if(GetAllSpellMechanicMask(aura->GetSpellProto()) & mechanic_mask)
  3502. {
  3503. RemoveAura(iter, removemode);
  3504. continue;
  3505. }
  3506. }
  3507. ++iter;
  3508. }
  3509. }
  3510. void Unit::RemoveAreaAurasDueToLeaveWorld()
  3511. {
  3512. // make sure that all area auras not applied on self are removed - prevent access to deleted pointer later
  3513. for(AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
  3514. {
  3515. Aura* aura = iter->second;
  3516. ++iter;
  3517. Aura::ApplicationMap const& appMap = aura->GetApplicationMap();
  3518. for(Aura::ApplicationMap::const_iterator itr = appMap.begin(); itr!= appMap.end();)
  3519. {
  3520. AuraApplication* aurApp = itr->second;
  3521. ++itr;
  3522. if(Unit* pTarget = aurApp->GetTarget())
  3523. {
  3524. if(pTarget == this)
  3525. continue;
  3526. pTarget->RemoveAura(aurApp);
  3527. // things linked on aura remove may apply new area aura - so start from the beginning
  3528. iter = m_ownedAuras.begin();
  3529. }
  3530. }
  3531. }
  3532. // remove area auras owned by others
  3533. for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
  3534. {
  3535. if(iter->second->GetBase()->GetOwner() != this)
  3536. {
  3537. RemoveAura(iter);
  3538. }
  3539. else
  3540. ++iter;
  3541. }
  3542. }
  3543. void Unit::RemoveAllAuras()
  3544. {
  3545. // this may be a dead loop if some events on aura remove will continiously apply aura on remove
  3546. // we want to have all auras removed, so use your brain when linking events
  3547. while(!m_appliedAuras.empty() || !m_ownedAuras.empty())
  3548. {
  3549. AuraApplicationMap::iterator aurAppIter;
  3550. for(aurAppIter = m_appliedAuras.begin(); aurAppIter != m_appliedAuras.end();)
  3551. _UnapplyAura(aurAppIter, AURA_REMOVE_BY_DEFAULT);
  3552. AuraMap::iterator aurIter;
  3553. for(aurIter = m_ownedAuras.begin(); aurIter != m_ownedAuras.end();)
  3554. RemoveOwnedAura(aurIter);
  3555. }
  3556. }
  3557. void Unit::RemoveArenaAuras()
  3558. {
  3559. // in join, remove positive buffs, on end, remove negative
  3560. // used to remove positive visible auras in arenas
  3561. for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
  3562. {
  3563. AuraApplication const* aurApp = iter->second;
  3564. Aura const* aura = aurApp->GetBase();
  3565. if(!(aura->GetSpellProto()->AttributesEx4 & SPELL_ATTR4_UNK21) // don't remove stances, shadowform, pally/hunter auras
  3566. && !aura->IsPassive() // don't remove passive auras
  3567. && (aurApp->IsPositive() || !(aura->GetSpellProto()->AttributesEx3 & SPELL_ATTR3_DEATH_PERSISTENT))) // not negative death persistent auras
  3568. RemoveAura(iter);
  3569. else
  3570. ++iter;
  3571. }
  3572. }
  3573. void Unit::RemoveAllAurasOnDeath()
  3574. {
  3575. // used just after dieing to remove all visible auras
  3576. // and disable the mods for the passive ones
  3577. for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
  3578. {
  3579. Aura const* aura = iter->second->GetBase();
  3580. if(!aura->IsPassive() && !aura->IsDeathPersistent())
  3581. _UnapplyAura(iter, AURA_REMOVE_BY_DEATH);
  3582. else
  3583. ++iter;
  3584. }
  3585. for(AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
  3586. {
  3587. Aura* aura = iter->second;
  3588. if(!aura->IsPassive() && !aura->IsDeathPersistent())
  3589. RemoveOwnedAura(iter, AURA_REMOVE_BY_DEATH);
  3590. else
  3591. ++iter;
  3592. }
  3593. }
  3594. void Unit::RemoveAllAurasRequiringDeadTarget()
  3595. {
  3596. for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
  3597. {
  3598. Aura const* aura = iter->second->GetBase();
  3599. if(!aura->IsPassive() && IsRequiringDeadTargetSpell(aura->GetSpellProto()))
  3600. _UnapplyAura(iter, AURA_REMOVE_BY_DEFAULT);
  3601. else
  3602. ++iter;
  3603. }
  3604. for(AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
  3605. {
  3606. Aura* aura = iter->second;
  3607. if(!aura->IsPassive() && IsRequiringDeadTargetSpell(aura->GetSpellProto()))
  3608. RemoveOwnedAura(iter, AURA_REMOVE_BY_DEFAULT);
  3609. else
  3610. ++iter;
  3611. }
  3612. }
  3613. void Unit::RemoveAllAurasExceptType(AuraType type)
  3614. {
  3615. for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
  3616. {
  3617. Aura const* aura = iter->second->GetBase();
  3618. if(!IsSpellHaveAura(aura->GetSpellProto(), type))
  3619. _UnapplyAura(iter, AURA_REMOVE_BY_DEFAULT);
  3620. else
  3621. ++iter;
  3622. }
  3623. for(AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
  3624. {
  3625. Aura* aura = iter->second;
  3626. if(!IsSpellHaveAura(aura->GetSpellProto(), type))
  3627. RemoveOwnedAura(iter, AURA_REMOVE_BY_DEFAULT);
  3628. else
  3629. ++iter;
  3630. }
  3631. }
  3632. void Unit::DelayOwnedAuras(uint32 spellId, uint64 caster, int32 delaytime)
  3633. {
  3634. for(AuraMap::iterator iter = m_ownedAuras.lower_bound(spellId); iter != m_ownedAuras.upper_bound(spellId);++iter)
  3635. {
  3636. Aura* aura = iter->second;
  3637. if(!caster || aura->GetCasterGUID() == caster)
  3638. {
  3639. if(aura->GetDuration() < delaytime)
  3640. aura->SetDuration(0);
  3641. else
  3642. aura->SetDuration(aura->GetDuration() - delaytime);
  3643. // update for out of range group members (on 1 slot use)
  3644. aura->SetNeedClientUpdateForTargets();
  3645. sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Aura %u partially interrupted on unit %u, new duration: %u ms", aura->GetId(), GetGUIDLow(), aura->GetDuration());
  3646. }
  3647. }
  3648. }
  3649. void Unit::_RemoveAllAuraStatMods()
  3650. {
  3651. for(AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
  3652. (*i).second->GetBase()->HandleAllEffects(i->second, AURA_EFFECT_HANDLE_STAT, false);
  3653. }
  3654. void Unit::_ApplyAllAuraStatMods()
  3655. {
  3656. for(AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
  3657. (*i).second->GetBase()->HandleAllEffects(i->second, AURA_EFFECT_HANDLE_STAT, true);
  3658. }
  3659. AuraEffect* Unit::GetAuraEffect(uint32 spellId, uint8 effIndex, uint64 caster) const
  3660. {
  3661. for(AuraApplicationMap::const_iterator itr = m_appliedAuras.lower_bound(spellId); itr != m_appliedAuras.upper_bound(spellId); ++itr)
  3662. if(itr->second->HasEffect(effIndex) && (!caster || itr->second->GetBase()->GetCasterGUID() == caster))
  3663. return itr->second->GetBase()->GetEffect(effIndex);
  3664. return NULL;
  3665. }
  3666. AuraEffect* Unit::GetAuraEffectOfRankedSpell(uint32 spellId, uint8 effIndex, uint64 caster) const
  3667. {
  3668. uint32 rankSpell = sSpellMgr->GetFirstSpellInChain(spellId);
  3669. while(true)
  3670. {
  3671. if(AuraEffect* aurEff = GetAuraEffect(rankSpell, effIndex, caster))
  3672. return aurEff;
  3673. SpellChainNode const* chainNode = sSpellMgr->GetSpellChainNode(rankSpell);
  3674. if(!chainNode)
  3675. break;
  3676. else
  3677. rankSpell = chainNode->next;
  3678. }
  3679. return NULL;
  3680. }
  3681. AuraEffect* Unit::GetAuraEffect(AuraType type, SpellFamilyNames name, uint32 iconId, uint8 effIndex) const
  3682. {
  3683. AuraEffectList const& auras = GetAuraEffectsByType(type);
  3684. for(Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
  3685. {
  3686. if(effIndex != (*itr)->GetEffIndex())
  3687. continue;
  3688. SpellEntry const* spell = (*itr)->GetSpellProto();
  3689. if(spell->SpellIconID == iconId && spell->SpellFamilyName == uint32(name) && !spell->SpellFamilyFlags)
  3690. return *itr;
  3691. }
  3692. return NULL;
  3693. }
  3694. AuraEffect* Unit::GetAuraEffect(AuraType type, SpellFamilyNames family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, uint64 casterGUID)
  3695. {
  3696. AuraEffectList const& auras = GetAuraEffectsByType(type);
  3697. for(AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
  3698. {
  3699. SpellEntry const* spell = (*i)->GetSpellProto();
  3700. if(spell->SpellFamilyName == uint32(family) && spell->SpellFamilyFlags.HasFlag(familyFlag1, familyFlag2, familyFlag3))
  3701. {
  3702. if(casterGUID && (*i)->GetCasterGUID() != casterGUID)
  3703. continue;
  3704. return (*i);
  3705. }
  3706. }
  3707. return NULL;
  3708. }
  3709. AuraApplication* Unit::GetAuraApplication(uint32 spellId, uint64 casterGUID, uint64 itemCasterGUID, uint8 reqEffMask, AuraApplication* except) const
  3710. {
  3711. for(AuraApplicationMap::const_iterator itr = m_appliedAuras.lower_bound(spellId); itr != m_appliedAuras.upper_bound(spellId); ++itr)
  3712. {
  3713. Aura const* aura = itr->second->GetBase();
  3714. if(((aura->GetEffectMask() & reqEffMask) == reqEffMask) && (!casterGUID || aura->GetCasterGUID() == casterGUID) && (!itemCasterGUID || aura->GetCastItemGUID() == itemCasterGUID) && (!except || except != itr->second))
  3715. return itr->second;
  3716. }
  3717. return NULL;
  3718. }
  3719. Aura* Unit::GetAura(uint32 spellId, uint64 casterGUID, uint64 itemCasterGUID, uint8 reqEffMask) const
  3720. {
  3721. AuraApplication* aurApp = GetAuraApplication(spellId, casterGUID, itemCasterGUID, reqEffMask);
  3722. return aurApp ? aurApp->GetBase() : NULL;
  3723. }
  3724. AuraApplication* Unit::GetAuraApplicationOfRankedSpell(uint32 spellId, uint64 casterGUID, uint64 itemCasterGUID, uint8 reqEffMask, AuraApplication* except) const
  3725. {
  3726. uint32 rankSpell = sSpellMgr->GetFirstSpellInChain(spellId);
  3727. while(true)
  3728. {
  3729. if(AuraApplication* aurApp = GetAuraApplication(rankSpell, casterGUID, itemCasterGUID, reqEffMask, except))
  3730. return aurApp;
  3731. SpellChainNode const* chainNode = sSpellMgr->GetSpellChainNode(rankSpell);
  3732. if(!chainNode)
  3733. break;
  3734. else
  3735. rankSpell = chainNode->next;
  3736. }
  3737. return NULL;
  3738. }
  3739. Aura* Unit::GetAuraOfRankedSpell(uint32 spellId, uint64 casterGUID, uint64 itemCasterGUID, uint8 reqEffMask) const
  3740. {
  3741. AuraApplication* aurApp = GetAuraApplicationOfRankedSpell(spellId, casterGUID, itemCasterGUID, reqEffMask);
  3742. return aurApp ? aurApp->GetBase() : NULL;
  3743. }
  3744. bool Unit::HasAuraEffect(uint32 spellId, uint8 effIndex, uint64 caster) const
  3745. {
  3746. for(AuraApplicationMap::const_iterator itr = m_appliedAuras.lower_bound(spellId); itr != m_appliedAuras.upper_bound(spellId); ++itr)
  3747. if(itr->second->HasEffect(effIndex) && (!caster || itr->second->GetBase()->GetCasterGUID() == caster))
  3748. return true;
  3749. return false;
  3750. }
  3751. uint32 Unit::GetAuraCount(uint32 spellId) const
  3752. {
  3753. uint32 count = 0;
  3754. for(AuraApplicationMap::const_iterator itr = m_appliedAuras.lower_bound(spellId); itr != m_appliedAuras.upper_bound(spellId); ++itr)
  3755. {
  3756. if(!itr->second->GetBase()->GetStackAmount())
  3757. count++;
  3758. else
  3759. count += (uint32)itr->second->GetBase()->GetStackAmount();
  3760. }
  3761. return count;
  3762. }
  3763. bool Unit::HasAura(uint32 spellId, uint64 casterGUID, uint64 itemCasterGUID, uint8 reqEffMask) const
  3764. {
  3765. if(GetAuraApplication(spellId, casterGUID, itemCasterGUID, reqEffMask))
  3766. return true;
  3767. return false;
  3768. }
  3769. bool Unit::HasAuraType(AuraType auraType) const
  3770. {
  3771. return (!m_modAuras[auraType].empty());
  3772. }
  3773. bool Unit::HasAuraTypeWithCaster(AuraType auratype, uint64 caster) const
  3774. {
  3775. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  3776. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  3777. if(caster == (*i)->GetCasterGUID())
  3778. return true;
  3779. return false;
  3780. }
  3781. bool Unit::HasAuraTypeWithMiscvalue(AuraType auratype, int32 miscvalue) const
  3782. {
  3783. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  3784. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  3785. if(miscvalue == (*i)->GetMiscValue())
  3786. return true;
  3787. return false;
  3788. }
  3789. bool Unit::HasAuraTypeWithAffectMask(AuraType auratype, SpellEntry const* affectedSpell) const
  3790. {
  3791. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  3792. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  3793. if((*i)->IsAffectedOnSpell(affectedSpell))
  3794. return true;
  3795. return false;
  3796. }
  3797. bool Unit::HasAuraTypeWithValue(AuraType auratype, int32 value) const
  3798. {
  3799. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  3800. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  3801. if(value == (*i)->GetAmount())
  3802. return true;
  3803. return false;
  3804. }
  3805. bool Unit::HasNegativeAuraWithInterruptFlag(uint32 flag, uint64 guid)
  3806. {
  3807. if(!(m_interruptMask & flag))
  3808. return false;
  3809. for(AuraApplicationList::iterator iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end(); ++iter)
  3810. {
  3811. if(!(*iter)->IsPositive() && (*iter)->GetBase()->GetSpellProto()->AuraInterruptFlags & flag && (!guid || (*iter)->GetBase()->GetCasterGUID() == guid))
  3812. return true;
  3813. }
  3814. return false;
  3815. }
  3816. bool Unit::HasNegativeAuraWithAttribute(uint32 flag, uint64 guid)
  3817. {
  3818. for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end(); ++iter)
  3819. {
  3820. Aura const* aura = iter->second->GetBase();
  3821. if(!iter->second->IsPositive() && aura->GetSpellProto()->Attributes & flag && (!guid || aura->GetCasterGUID() == guid))
  3822. return true;
  3823. }
  3824. return false;
  3825. }
  3826. bool Unit::HasAuraWithMechanic(uint32 mechanicMask)
  3827. {
  3828. for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end(); ++iter)
  3829. {
  3830. SpellEntry const* spellInfo = iter->second->GetBase()->GetSpellProto();
  3831. if(spellInfo->Mechanic && (mechanicMask & (1 << spellInfo->Mechanic)))
  3832. return true;
  3833. for(uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
  3834. if(iter->second->HasEffect(i) && spellInfo->Effect[i] && spellInfo->EffectMechanic[i])
  3835. if(mechanicMask & (1 << spellInfo->EffectMechanic[i]))
  3836. return true;
  3837. }
  3838. return false;
  3839. }
  3840. AuraEffect* Unit::IsScriptOverriden(SpellEntry const* spell, int32 script) const
  3841. {
  3842. AuraEffectList const& auras = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
  3843. for(AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
  3844. {
  3845. if((*i)->GetMiscValue() == script)
  3846. if((*i)->IsAffectedOnSpell(spell))
  3847. return (*i);
  3848. }
  3849. return NULL;
  3850. }
  3851. uint32 Unit::GetDiseasesByCaster(uint64 casterGUID, bool remove)
  3852. {
  3853. static const AuraType diseaseAuraTypes[] =
  3854. {
  3855. SPELL_AURA_PERIODIC_DAMAGE, // Frost Fever and Blood Plague
  3856. SPELL_AURA_LINKED, // Crypt Fever and Ebon Plague
  3857. SPELL_AURA_NONE
  3858. };
  3859. uint32 diseases = 0;
  3860. for(AuraType const* itr = &diseaseAuraTypes[0]; itr && itr[0] != SPELL_AURA_NONE; ++itr)
  3861. {
  3862. for(AuraEffectList::iterator i = m_modAuras[*itr].begin(); i != m_modAuras[*itr].end();)
  3863. {
  3864. // Get auras with disease dispel type by caster
  3865. if((*i)->GetSpellProto()->Dispel == DISPEL_DISEASE
  3866. && (*i)->GetCasterGUID() == casterGUID)
  3867. {
  3868. ++diseases;
  3869. if(remove)
  3870. {
  3871. RemoveAura((*i)->GetId(), (*i)->GetCasterGUID());
  3872. i = m_modAuras[*itr].begin();
  3873. continue;
  3874. }
  3875. }
  3876. ++i;
  3877. }
  3878. }
  3879. return diseases;
  3880. }
  3881. uint32 Unit::GetDoTsByCaster(uint64 casterGUID) const
  3882. {
  3883. static const AuraType diseaseAuraTypes[] =
  3884. {
  3885. SPELL_AURA_PERIODIC_DAMAGE,
  3886. SPELL_AURA_PERIODIC_DAMAGE_PERCENT,
  3887. SPELL_AURA_NONE
  3888. };
  3889. uint32 dots = 0;
  3890. for(AuraType const* itr = &diseaseAuraTypes[0]; itr && itr[0] != SPELL_AURA_NONE; ++itr)
  3891. {
  3892. Unit::AuraEffectList const& auras = GetAuraEffectsByType(*itr);
  3893. for(AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
  3894. {
  3895. // Get auras by caster
  3896. if((*i)->GetCasterGUID() == casterGUID)
  3897. ++dots;
  3898. }
  3899. }
  3900. return dots;
  3901. }
  3902. int32 Unit::GetTotalAuraModifier(AuraType auratype) const
  3903. {
  3904. int32 modifier = 0;
  3905. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  3906. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  3907. modifier += (*i)->GetAmount();
  3908. return modifier;
  3909. }
  3910. float Unit::GetTotalAuraMultiplier(AuraType auratype) const
  3911. {
  3912. float multiplier = 1.0f;
  3913. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  3914. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  3915. AddPctN(multiplier, (*i)->GetAmount());
  3916. return multiplier;
  3917. }
  3918. int32 Unit::GetMaxPositiveAuraModifier(AuraType auratype)
  3919. {
  3920. int32 modifier = 0;
  3921. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  3922. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  3923. {
  3924. if((*i)->GetAmount() > modifier)
  3925. modifier = (*i)->GetAmount();
  3926. }
  3927. return modifier;
  3928. }
  3929. int32 Unit::GetMaxNegativeAuraModifier(AuraType auratype) const
  3930. {
  3931. int32 modifier = 0;
  3932. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  3933. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  3934. if((*i)->GetAmount() < modifier)
  3935. modifier = (*i)->GetAmount();
  3936. return modifier;
  3937. }
  3938. int32 Unit::GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const
  3939. {
  3940. int32 modifier = 0;
  3941. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  3942. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  3943. {
  3944. if((*i)->GetMiscValue()& misc_mask)
  3945. modifier += (*i)->GetAmount();
  3946. }
  3947. return modifier;
  3948. }
  3949. float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask) const
  3950. {
  3951. float multiplier = 1.0f;
  3952. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  3953. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  3954. {
  3955. if((*i)->GetMiscValue()& misc_mask)
  3956. AddPctN(multiplier, (*i)->GetAmount());
  3957. }
  3958. return multiplier;
  3959. }
  3960. int32 Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask, const AuraEffect* except) const
  3961. {
  3962. int32 modifier = 0;
  3963. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  3964. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  3965. {
  3966. if(except != (*i) && (*i)->GetMiscValue()& misc_mask && (*i)->GetAmount() > modifier)
  3967. modifier = (*i)->GetAmount();
  3968. }
  3969. return modifier;
  3970. }
  3971. int32 Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const
  3972. {
  3973. int32 modifier = 0;
  3974. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  3975. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  3976. {
  3977. if((*i)->GetMiscValue()& misc_mask && (*i)->GetAmount() < modifier)
  3978. modifier = (*i)->GetAmount();
  3979. }
  3980. return modifier;
  3981. }
  3982. int32 Unit::GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const
  3983. {
  3984. int32 modifier = 0;
  3985. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  3986. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  3987. {
  3988. if((*i)->GetMiscValue() == misc_value)
  3989. modifier += (*i)->GetAmount();
  3990. }
  3991. return modifier;
  3992. }
  3993. float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype, int32 misc_value) const
  3994. {
  3995. float multiplier = 1.0f;
  3996. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  3997. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  3998. {
  3999. if((*i)->GetMiscValue() == misc_value)
  4000. AddPctN(multiplier, (*i)->GetAmount());
  4001. }
  4002. return multiplier;
  4003. }
  4004. int32 Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const
  4005. {
  4006. int32 modifier = 0;
  4007. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  4008. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  4009. {
  4010. if((*i)->GetMiscValue() == misc_value && (*i)->GetAmount() > modifier)
  4011. modifier = (*i)->GetAmount();
  4012. }
  4013. return modifier;
  4014. }
  4015. int32 Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const
  4016. {
  4017. int32 modifier = 0;
  4018. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  4019. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  4020. {
  4021. if((*i)->GetMiscValue() == misc_value && (*i)->GetAmount() < modifier)
  4022. modifier = (*i)->GetAmount();
  4023. }
  4024. return modifier;
  4025. }
  4026. int32 Unit::GetTotalAuraModifierByAffectMask(AuraType auratype, SpellEntry const* affectedSpell) const
  4027. {
  4028. int32 modifier = 0;
  4029. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  4030. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  4031. {
  4032. if((*i)->IsAffectedOnSpell(affectedSpell))
  4033. modifier += (*i)->GetAmount();
  4034. }
  4035. return modifier;
  4036. }
  4037. float Unit::GetTotalAuraMultiplierByAffectMask(AuraType auratype, SpellEntry const* affectedSpell) const
  4038. {
  4039. float multiplier = 1.0f;
  4040. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  4041. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  4042. {
  4043. if((*i)->IsAffectedOnSpell(affectedSpell))
  4044. AddPctN(multiplier, (*i)->GetAmount());
  4045. }
  4046. return multiplier;
  4047. }
  4048. int32 Unit::GetMaxPositiveAuraModifierByAffectMask(AuraType auratype, SpellEntry const* affectedSpell) const
  4049. {
  4050. int32 modifier = 0;
  4051. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  4052. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  4053. {
  4054. if((*i)->IsAffectedOnSpell(affectedSpell) && (*i)->GetAmount() > modifier)
  4055. modifier = (*i)->GetAmount();
  4056. }
  4057. return modifier;
  4058. }
  4059. int32 Unit::GetMaxNegativeAuraModifierByAffectMask(AuraType auratype, SpellEntry const* affectedSpell) const
  4060. {
  4061. int32 modifier = 0;
  4062. AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
  4063. for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
  4064. {
  4065. if((*i)->IsAffectedOnSpell(affectedSpell) && (*i)->GetAmount() < modifier)
  4066. modifier = (*i)->GetAmount();
  4067. }
  4068. return modifier;
  4069. }
  4070. void Unit::_RegisterDynObject(DynamicObject* dynObj)
  4071. {
  4072. m_dynObj.push_back(dynObj);
  4073. }
  4074. void Unit::_UnregisterDynObject(DynamicObject* dynObj)
  4075. {
  4076. m_dynObj.remove(dynObj);
  4077. }
  4078. DynamicObject* Unit::GetDynObject(uint32 spellId)
  4079. {
  4080. if(m_dynObj.empty())
  4081. return NULL;
  4082. for(DynObjectList::const_iterator i = m_dynObj.begin(); i != m_dynObj.end();++i)
  4083. {
  4084. DynamicObject* dynObj = *i;
  4085. if(dynObj->GetSpellId() == spellId)
  4086. return dynObj;
  4087. }
  4088. return NULL;
  4089. }
  4090. void Unit::RemoveDynObject(uint32 spellId)
  4091. {
  4092. if(m_dynObj.empty())
  4093. return;
  4094. for(DynObjectList::iterator i = m_dynObj.begin(); i != m_dynObj.end();)
  4095. {
  4096. DynamicObject* dynObj = *i;
  4097. if(dynObj->GetSpellId() == spellId)
  4098. {
  4099. dynObj->Remove();
  4100. i = m_dynObj.begin();
  4101. }
  4102. else
  4103. ++i;
  4104. }
  4105. }
  4106. void Unit::RemoveAllDynObjects()
  4107. {
  4108. while(!m_dynObj.empty())
  4109. m_dynObj.front()->Remove();
  4110. }
  4111. GameObject* Unit::GetGameObject(uint32 spellId) const
  4112. {
  4113. for(GameObjectList::const_iterator i = m_gameObj.begin(); i != m_gameObj.end(); ++i)
  4114. if((*i)->GetSpellId() == spellId)
  4115. return *i;
  4116. return NULL;
  4117. }
  4118. void Unit::AddGameObject(GameObject* gameObj)
  4119. {
  4120. if(!gameObj || !gameObj->GetOwnerGUID() == 0) return;
  4121. m_gameObj.push_back(gameObj);
  4122. gameObj->SetOwnerGUID(GetGUID());
  4123. if(GetTypeId() == TYPEID_PLAYER && gameObj->GetSpellId())
  4124. {
  4125. SpellEntry const* createBySpell = sSpellStore.LookupEntry(gameObj->GetSpellId());
  4126. // Need disable spell use for owner
  4127. if(createBySpell && createBySpell->Attributes & SPELL_ATTR0_DISABLED_WHILE_ACTIVE)
  4128. // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
  4129. ToPlayer()->AddSpellAndCategoryCooldowns(createBySpell, 0, NULL, true);
  4130. }
  4131. }
  4132. void Unit::RemoveGameObject(GameObject* gameObj, bool del)
  4133. {
  4134. if(!gameObj || !gameObj->GetOwnerGUID() == GetGUID()) return;
  4135. gameObj->SetOwnerGUID(0);
  4136. for(uint32 i = 0; i < 4; ++i)
  4137. {
  4138. if(m_ObjectSlot[i] == gameObj->GetGUID())
  4139. {
  4140. m_ObjectSlot[i] = 0;
  4141. break;
  4142. }
  4143. }
  4144. // GO created by some spell
  4145. if(uint32 spellid = gameObj->GetSpellId())
  4146. {
  4147. RemoveAurasDueToSpell(spellid);
  4148. if(GetTypeId() == TYPEID_PLAYER)
  4149. {
  4150. SpellEntry const* createBySpell = sSpellStore.LookupEntry(spellid);
  4151. // Need activate spell use for owner
  4152. if(createBySpell && createBySpell->Attributes & SPELL_ATTR0_DISABLED_WHILE_ACTIVE)
  4153. // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
  4154. ToPlayer()->SendCooldownEvent(createBySpell);
  4155. }
  4156. }
  4157. m_gameObj.remove(gameObj);
  4158. if(del)
  4159. {
  4160. gameObj->SetRespawnTime(0);
  4161. gameObj->Delete();
  4162. }
  4163. }
  4164. void Unit::RemoveGameObject(uint32 spellid, bool del)
  4165. {
  4166. if(m_gameObj.empty())
  4167. return;
  4168. GameObjectList::iterator i, next;
  4169. for(i = m_gameObj.begin(); i != m_gameObj.end(); i = next)
  4170. {
  4171. next = i;
  4172. if(spellid == 0 || (*i)->GetSpellId() == spellid)
  4173. {
  4174. (*i)->SetOwnerGUID(0);
  4175. if(del)
  4176. {
  4177. (*i)->SetRespawnTime(0);
  4178. (*i)->Delete();
  4179. }
  4180. next = m_gameObj.erase(i);
  4181. }
  4182. else
  4183. ++next;
  4184. }
  4185. }
  4186. void Unit::RemoveAllGameObjects()
  4187. {
  4188. // remove references to unit
  4189. for(GameObjectList::iterator i = m_gameObj.begin(); i != m_gameObj.end();)
  4190. {
  4191. (*i)->SetOwnerGUID(0);
  4192. (*i)->SetRespawnTime(0);
  4193. (*i)->Delete();
  4194. i = m_gameObj.erase(i);
  4195. }
  4196. }
  4197. void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage *log)
  4198. {
  4199. WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16+4+4+4+1+4+4+1+1+4+4+1)); // we guess size
  4200. data.append(log->target->GetPackGUID());
  4201. data.append(log->attacker->GetPackGUID());
  4202. data << uint32(log->SpellID);
  4203. data << uint32(log->damage); // damage amount
  4204. int32 overkill = log->damage - log->target->GetHealth();
  4205. data << uint32(overkill > 0 ? overkill : 0); // overkill
  4206. data << uint8 (log->schoolMask); // damage school
  4207. data << uint32(log->absorb); // AbsorbedDamage
  4208. data << uint32(log->resist); // resist
  4209. data << uint8 (log->physicalLog); // if 1, then client show spell name (example: %s's ranged shot hit %s for %u school or %s suffers %u school damage from %s's spell_name
  4210. data << uint8 (log->unused); // unused
  4211. data << uint32(log->blocked); // blocked
  4212. data << uint32(log->HitInfo);
  4213. data << uint8 (0); // flag to use extend data
  4214. SendMessageToSet(&data, true);
  4215. }
  4216. void Unit::SendSpellNonMeleeDamageLog(Unit* target, uint32 SpellID, uint32 Damage, SpellSchoolMask damageSchoolMask, uint32 AbsorbedDamage, uint32 Resist, bool PhysicalDamage, uint32 Blocked, bool CriticalHit)
  4217. {
  4218. SpellNonMeleeDamage log(this, target, SpellID, damageSchoolMask);
  4219. log.damage = Damage - AbsorbedDamage - Resist - Blocked;
  4220. log.absorb = AbsorbedDamage;
  4221. log.resist = Resist;
  4222. log.physicalLog = PhysicalDamage;
  4223. log.blocked = Blocked;
  4224. log.HitInfo = SPELL_HIT_TYPE_UNK1 | SPELL_HIT_TYPE_UNK3 | SPELL_HIT_TYPE_UNK6;
  4225. if(CriticalHit)
  4226. log.HitInfo |= SPELL_HIT_TYPE_CRIT;
  4227. SendSpellNonMeleeDamageLog(&log);
  4228. }
  4229. void Unit::ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellEntry const* procSpell, SpellEntry const* procAura)
  4230. {
  4231. // Not much to do if no flags are set.
  4232. if(procAttacker)
  4233. ProcDamageAndSpellFor(false, victim, procAttacker, procExtra, attType, procSpell, amount, procAura);
  4234. // Now go on with a victim's events'n'auras
  4235. // Not much to do if no flags are set or there is no victim
  4236. if(victim && victim->isAlive() && procVictim)
  4237. victim->ProcDamageAndSpellFor(true, this, procVictim, procExtra, attType, procSpell, amount, procAura);
  4238. }
  4239. void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo *pInfo)
  4240. {
  4241. AuraEffect const* aura = pInfo->auraEff;
  4242. WorldPacket data(SMSG_PERIODICAURALOG, 30);
  4243. data.append(GetPackGUID());
  4244. data.appendPackGUID(aura->GetCasterGUID());
  4245. data << uint32(aura->GetId()); // spellId
  4246. data << uint32(1); // count
  4247. data << uint32(aura->GetAuraType()); // auraId
  4248. switch(aura->GetAuraType())
  4249. {
  4250. case SPELL_AURA_PERIODIC_DAMAGE:
  4251. case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
  4252. data << uint32(pInfo->damage); // damage
  4253. data << uint32(pInfo->overDamage); // overkill?
  4254. data << uint32(GetSpellSchoolMask(aura->GetSpellProto()));
  4255. data << uint32(pInfo->absorb); // absorb
  4256. data << uint32(pInfo->resist); // resist
  4257. data << uint8(pInfo->critical); // new 3.1.2 critical tick
  4258. break;
  4259. case SPELL_AURA_PERIODIC_HEAL:
  4260. case SPELL_AURA_OBS_MOD_HEALTH:
  4261. data << uint32(pInfo->damage); // damage
  4262. data << uint32(pInfo->overDamage); // overheal
  4263. data << uint32(pInfo->absorb); // absorb
  4264. data << uint8(pInfo->critical); // new 3.1.2 critical tick
  4265. break;
  4266. case SPELL_AURA_OBS_MOD_POWER:
  4267. case SPELL_AURA_PERIODIC_ENERGIZE:
  4268. data << uint32(aura->GetMiscValue()); // power type
  4269. data << uint32(pInfo->damage); // damage
  4270. break;
  4271. case SPELL_AURA_PERIODIC_MANA_LEECH:
  4272. data << uint32(aura->GetMiscValue()); // power type
  4273. data << uint32(pInfo->damage); // amount
  4274. data << float(pInfo->multiplier); // gain multiplier
  4275. break;
  4276. default:
  4277. sLog->outError("Unit::SendPeriodicAuraLog: unknown aura %u", uint32(aura->GetAuraType()));
  4278. return;
  4279. }
  4280. SendMessageToSet(&data, true);
  4281. }
  4282. void Unit::SendSpellMiss(Unit* target, uint32 spellID, SpellMissInfo missInfo)
  4283. {
  4284. WorldPacket data(SMSG_SPELLLOGMISS, (4+8+1+4+8+1));
  4285. data << uint32(spellID);
  4286. data << uint64(GetGUID());
  4287. data << uint8(0); // can be 0 or 1
  4288. data << uint32(1); // target count
  4289. // for(i = 0; i < target count; ++i)
  4290. data << uint64(target->GetGUID()); // target GUID
  4291. data << uint8(missInfo);
  4292. // end loop
  4293. SendMessageToSet(&data, true);
  4294. }
  4295. void Unit::SendSpellDamageResist(Unit* target, uint32 spellId)
  4296. {
  4297. WorldPacket data(SMSG_PROCRESIST, 8+8+4+1);
  4298. data << uint64(GetGUID());
  4299. data << uint64(target->GetGUID());
  4300. data << uint32(spellId);
  4301. data << uint8(0); // bool - log format: 0-default, 1-debug
  4302. SendMessageToSet(&data, true);
  4303. }
  4304. void Unit::SendSpellDamageImmune(Unit* target, uint32 spellId)
  4305. {
  4306. WorldPacket data(SMSG_SPELLORDAMAGE_IMMUNE, 8+8+4+1);
  4307. data << uint64(GetGUID());
  4308. data << uint64(target->GetGUID());
  4309. data << uint32(spellId);
  4310. data << uint8(0); // bool - log format: 0-default, 1-debug
  4311. SendMessageToSet(&data, true);
  4312. }
  4313. void Unit::SendAttackStateUpdate(CalcDamageInfo *damageInfo)
  4314. {
  4315. sLog->outDebug(LOG_FILTER_UNITS, "WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
  4316. uint32 count = 1;
  4317. size_t maxsize = 4+5+5+4+4+1+4+4+4+4+4+1+4+4+4+4+4*12;
  4318. WorldPacket data(SMSG_ATTACKERSTATEUPDATE, maxsize); // we guess size
  4319. data << uint32(damageInfo->HitInfo);
  4320. data.append(damageInfo->attacker->GetPackGUID());
  4321. data.append(damageInfo->target->GetPackGUID());
  4322. data << uint32(damageInfo->damage); // Full damage
  4323. int32 overkill = damageInfo->damage - damageInfo->target->GetHealth();
  4324. data << uint32(overkill < 0 ? 0 : overkill); // Overkill
  4325. data << uint8(count); // Sub damage count
  4326. for(uint32 i = 0; i < count; ++i)
  4327. {
  4328. data << uint32(damageInfo->damageSchoolMask); // School of sub damage
  4329. data << float(damageInfo->damage); // sub damage
  4330. data << uint32(damageInfo->damage); // Sub Damage
  4331. }
  4332. if(damageInfo->HitInfo & (HITINFO_ABSORB | HITINFO_ABSORB2))
  4333. {
  4334. for(uint32 i = 0; i < count; ++i)
  4335. data << uint32(damageInfo->absorb); // Absorb
  4336. }
  4337. if(damageInfo->HitInfo & (HITINFO_RESIST | HITINFO_RESIST2))
  4338. {
  4339. for(uint32 i = 0; i < count; ++i)
  4340. data << uint32(damageInfo->resist); // Resist
  4341. }
  4342. data << uint8(damageInfo->TargetState);
  4343. data << uint32(0);
  4344. data << uint32(0);
  4345. if(damageInfo->HitInfo & HITINFO_BLOCK)
  4346. data << uint32(damageInfo->blocked_amount);
  4347. if(damageInfo->HitInfo & HITINFO_UNK3)
  4348. data << uint32(0);
  4349. if(damageInfo->HitInfo & HITINFO_UNK1)
  4350. {
  4351. data << uint32(0);
  4352. data << float(0);
  4353. data << float(0);
  4354. data << float(0);
  4355. data << float(0);
  4356. data << float(0);
  4357. data << float(0);
  4358. data << float(0);
  4359. data << float(0);
  4360. data << float(0); // Found in a loop with 1 iteration
  4361. data << float(0); // ditto ^
  4362. data << uint32(0);
  4363. }
  4364. SendMessageToSet(&data, true);
  4365. }
  4366. void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType*/, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount)
  4367. {
  4368. CalcDamageInfo dmgInfo;
  4369. dmgInfo.HitInfo = HitInfo;
  4370. dmgInfo.attacker = this;
  4371. dmgInfo.target = target;
  4372. dmgInfo.damage = Damage - AbsorbDamage - Resist - BlockedAmount;
  4373. dmgInfo.damageSchoolMask = damageSchoolMask;
  4374. dmgInfo.absorb = AbsorbDamage;
  4375. dmgInfo.resist = Resist;
  4376. dmgInfo.TargetState = TargetState;
  4377. dmgInfo.blocked_amount = BlockedAmount;
  4378. SendAttackStateUpdate(&dmgInfo);
  4379. }
  4380. bool Unit::HandleHasteAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
  4381. {
  4382. SpellEntry const* hasteSpell = triggeredByAura->GetSpellProto();
  4383. Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
  4384. ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
  4385. uint32 triggered_spell_id = 0;
  4386. Unit* target = victim;
  4387. int32 basepoints0 = 0;
  4388. switch(hasteSpell->SpellFamilyName)
  4389. {
  4390. case SPELLFAMILY_ROGUE:
  4391. {
  4392. switch(hasteSpell->Id)
  4393. {
  4394. // Blade Flurry
  4395. case 13877:
  4396. case 33735:
  4397. {
  4398. target = SelectNearbyTarget(victim);
  4399. if(!target)
  4400. return false;
  4401. basepoints0 = damage;
  4402. triggered_spell_id = 22482;
  4403. break;
  4404. }
  4405. }
  4406. break;
  4407. }
  4408. }
  4409. // processed charge only counting case
  4410. if(!triggered_spell_id)
  4411. return true;
  4412. SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
  4413. if(!triggerEntry)
  4414. {
  4415. sLog->outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u", hasteSpell->Id, triggered_spell_id);
  4416. return false;
  4417. }
  4418. // default case
  4419. if((!target && !sSpellMgr->IsSrcTargetSpell(triggerEntry)) || (target && target != this && !target->isAlive()))
  4420. return false;
  4421. if(cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
  4422. return false;
  4423. if(basepoints0)
  4424. CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
  4425. else
  4426. CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura);
  4427. if(cooldown && GetTypeId() == TYPEID_PLAYER)
  4428. ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
  4429. return true;
  4430. }
  4431. bool Unit::HandleSpellCritChanceAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellEntry const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
  4432. {
  4433. SpellEntry const* triggeredByAuraSpell = triggeredByAura->GetSpellProto();
  4434. Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
  4435. ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
  4436. uint32 triggered_spell_id = 0;
  4437. Unit* target = victim;
  4438. int32 basepoints0 = 0;
  4439. switch(triggeredByAuraSpell->SpellFamilyName)
  4440. {
  4441. case SPELLFAMILY_MAGE:
  4442. {
  4443. switch(triggeredByAuraSpell->Id)
  4444. {
  4445. // Focus Magic
  4446. case 54646:
  4447. {
  4448. Unit* caster = triggeredByAura->GetCaster();
  4449. if(!caster)
  4450. return false;
  4451. triggered_spell_id = 54648;
  4452. target = caster;
  4453. break;
  4454. }
  4455. }
  4456. }
  4457. }
  4458. // processed charge only counting case
  4459. if(!triggered_spell_id)
  4460. return true;
  4461. SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
  4462. if(!triggerEntry)
  4463. {
  4464. sLog->outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u", triggeredByAuraSpell->Id, triggered_spell_id);
  4465. return false;
  4466. }
  4467. // default case
  4468. if(!target || (target != this && !target->isAlive()))
  4469. return false;
  4470. if(cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
  4471. return false;
  4472. if(basepoints0)
  4473. CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
  4474. else
  4475. CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura);
  4476. if(cooldown && GetTypeId() == TYPEID_PLAYER)
  4477. ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
  4478. return true;
  4479. }
  4480. bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
  4481. {
  4482. SpellEntry const* dummySpell = triggeredByAura->GetSpellProto();
  4483. uint32 effIndex = triggeredByAura->GetEffIndex();
  4484. int32 triggerAmount = triggeredByAura->GetAmount();
  4485. Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
  4486. ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
  4487. uint32 triggered_spell_id = 0;
  4488. uint32 cooldown_spell_id = 0; // for random trigger, will be one of the triggered spell to avoid repeatable triggers
  4489. // otherwise, it's the triggered_spell_id by default
  4490. Unit* target = victim;
  4491. int32 basepoints0 = 0;
  4492. uint64 originalCaster = 0;
  4493. switch(dummySpell->SpellFamilyName)
  4494. {
  4495. case SPELLFAMILY_GENERIC:
  4496. {
  4497. switch(dummySpell->Id)
  4498. {
  4499. // Bloodworms Health Leech
  4500. case 50453:
  4501. {
  4502. Unit* pOwner = GetOwner();
  4503. if(pOwner)
  4504. {
  4505. basepoints0 = int32(damage * 1.50f);
  4506. target = pOwner;
  4507. triggered_spell_id = 50454;
  4508. break;
  4509. }
  4510. return false;
  4511. }
  4512. // Eye for an Eye
  4513. case 9799:
  4514. case 25988:
  4515. {
  4516. // return damage % to attacker but < 50% own total health
  4517. basepoints0 = int32(std::min(CalculatePctN(damage, triggerAmount), CountPctFromMaxHealth(50)));
  4518. triggered_spell_id = 25997;
  4519. break;
  4520. }
  4521. // Sweeping Strikes
  4522. case 18765:
  4523. case 35429:
  4524. {
  4525. if(HasAura(46924))
  4526. return false;
  4527. target = SelectNearbyTarget(victim);
  4528. if(!target)
  4529. return false;
  4530. triggered_spell_id = 26654;
  4531. break;
  4532. }
  4533. // Wrecking Crew
  4534. case 46867:
  4535. {
  4536. if(!procSpell)
  4537. return false;
  4538. triggered_spell_id = 57518;
  4539. break;
  4540. }
  4541. // Unstable Power
  4542. case 24658:
  4543. {
  4544. if(!procSpell || procSpell->Id == 24659)
  4545. return false;
  4546. // Need remove one 24659 aura
  4547. RemoveAuraFromStack(24659);
  4548. return true;
  4549. }
  4550. // Restless Strength
  4551. case 24661:
  4552. {
  4553. // Need remove one 24662 aura
  4554. RemoveAuraFromStack(24662);
  4555. return true;
  4556. }
  4557. // Adaptive Warding (Frostfire Regalia set)
  4558. case 28764:
  4559. {
  4560. if(!procSpell)
  4561. return false;
  4562. // find Mage Armor
  4563. if(!GetAuraEffect(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT, SPELLFAMILY_MAGE, 0x10000000, 0, 0))
  4564. return false;
  4565. switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
  4566. {
  4567. case SPELL_SCHOOL_NORMAL:
  4568. case SPELL_SCHOOL_HOLY:
  4569. return false; // ignored
  4570. case SPELL_SCHOOL_FIRE: triggered_spell_id = 28765; break;
  4571. case SPELL_SCHOOL_NATURE: triggered_spell_id = 28768; break;
  4572. case SPELL_SCHOOL_FROST: triggered_spell_id = 28766; break;
  4573. case SPELL_SCHOOL_SHADOW: triggered_spell_id = 28769; break;
  4574. case SPELL_SCHOOL_ARCANE: triggered_spell_id = 28770; break;
  4575. default:
  4576. return false;
  4577. }
  4578. target = this;
  4579. break;
  4580. }
  4581. // Obsidian Armor (Justice Bearer`s Pauldrons shoulder)
  4582. case 27539:
  4583. {
  4584. if(!procSpell)
  4585. return false;
  4586. switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
  4587. {
  4588. case SPELL_SCHOOL_NORMAL:
  4589. return false; // ignore
  4590. case SPELL_SCHOOL_HOLY: triggered_spell_id = 27536; break;
  4591. case SPELL_SCHOOL_FIRE: triggered_spell_id = 27533; break;
  4592. case SPELL_SCHOOL_NATURE: triggered_spell_id = 27538; break;
  4593. case SPELL_SCHOOL_FROST: triggered_spell_id = 27534; break;
  4594. case SPELL_SCHOOL_SHADOW: triggered_spell_id = 27535; break;
  4595. case SPELL_SCHOOL_ARCANE: triggered_spell_id = 27540; break;
  4596. default:
  4597. return false;
  4598. }
  4599. target = this;
  4600. break;
  4601. }
  4602. // Mana Leech (Passive) (Priest Pet Aura)
  4603. case 28305:
  4604. {
  4605. // Cast on owner
  4606. target = GetOwner();
  4607. if(!target)
  4608. return false;
  4609. triggered_spell_id = 34650;
  4610. break;
  4611. }
  4612. // Mark of Malice
  4613. case 33493:
  4614. {
  4615. // Cast finish spell at last charge
  4616. if(triggeredByAura->GetBase()->GetCharges() > 1)
  4617. return false;
  4618. target = this;
  4619. triggered_spell_id = 33494;
  4620. break;
  4621. }
  4622. // Twisted Reflection (boss spell)
  4623. case 21063:
  4624. triggered_spell_id = 21064;
  4625. break;
  4626. // Vampiric Aura (boss spell)
  4627. case 38196:
  4628. {
  4629. basepoints0 = 3 * damage; // 300%
  4630. if(basepoints0 < 0)
  4631. return false;
  4632. triggered_spell_id = 31285;
  4633. target = this;
  4634. break;
  4635. }
  4636. // Aura of Madness (Darkmoon Card: Madness trinket)
  4637. //=====================================================
  4638. // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior)
  4639. // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid)
  4640. // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid)
  4641. // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin)
  4642. // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes)
  4643. // 41005 Manic: +35 haste (spell, melee and ranged) (All classes)
  4644. // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter)
  4645. // 41011 Martyr Complex: +35 stamina (All classes)
  4646. // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
  4647. // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
  4648. case 39446:
  4649. {
  4650. if(GetTypeId() != TYPEID_PLAYER || !isAlive())
  4651. return false;
  4652. // Select class defined buff
  4653. switch(getClass())
  4654. {
  4655. case CLASS_PALADIN: // 39511, 40997, 40998, 40999, 41002, 41005, 41009, 41011, 41409
  4656. case CLASS_DRUID: // 39511, 40997, 40998, 40999, 41002, 41005, 41009, 41011, 41409
  4657. triggered_spell_id = RAND(39511, 40997, 40998, 40999, 41002, 41005, 41009, 41011, 41409);
  4658. cooldown_spell_id = 39511;
  4659. break;
  4660. case CLASS_ROGUE: // 39511, 40997, 40998, 41002, 41005, 41011
  4661. case CLASS_WARRIOR: // 39511, 40997, 40998, 41002, 41005, 41011
  4662. case CLASS_DEATH_KNIGHT: // 39511, 40997, 40998, 41002, 41005, 41011
  4663. triggered_spell_id = RAND(39511, 40997, 40998, 41002, 41005, 41011);
  4664. cooldown_spell_id = 39511;
  4665. break;
  4666. case CLASS_PRIEST: // 40999, 41002, 41005, 41009, 41011, 41406, 41409
  4667. case CLASS_SHAMAN: // 40999, 41002, 41005, 41009, 41011, 41406, 41409
  4668. case CLASS_MAGE: // 40999, 41002, 41005, 41009, 41011, 41406, 41409
  4669. case CLASS_WARLOCK: // 40999, 41002, 41005, 41009, 41011, 41406, 41409
  4670. triggered_spell_id = RAND(40999, 41002, 41005, 41009, 41011, 41406, 41409);
  4671. cooldown_spell_id = 40999;
  4672. break;
  4673. case CLASS_HUNTER: // 40997, 40999, 41002, 41005, 41009, 41011, 41406, 41409
  4674. triggered_spell_id = RAND(40997, 40999, 41002, 41005, 41009, 41011, 41406, 41409);
  4675. cooldown_spell_id = 40997;
  4676. break;
  4677. default:
  4678. return false;
  4679. }
  4680. target = this;
  4681. if(roll_chance_i(10))
  4682. ToPlayer()->Say("This is Madness!", LANG_UNIVERSAL); // TODO: It should be moved to database, shouldn't it?
  4683. break;
  4684. }
  4685. // Sunwell Exalted Caster Neck (??? neck)
  4686. // cast ??? Light's Wrath if Exalted by Aldor
  4687. // cast ??? Arcane Bolt if Exalted by Scryers
  4688. case 46569:
  4689. return false; // old unused version
  4690. // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck)
  4691. // cast 45479 Light's Wrath if Exalted by Aldor
  4692. // cast 45429 Arcane Bolt if Exalted by Scryers
  4693. case 45481:
  4694. {
  4695. if(GetTypeId() != TYPEID_PLAYER)
  4696. return false;
  4697. // Get Aldor reputation rank
  4698. if(ToPlayer()->GetReputationRank(932) == REP_EXALTED)
  4699. {
  4700. target = this;
  4701. triggered_spell_id = 45479;
  4702. break;
  4703. }
  4704. // Get Scryers reputation rank
  4705. if(ToPlayer()->GetReputationRank(934) == REP_EXALTED)
  4706. {
  4707. // triggered at positive/self casts also, current attack target used then
  4708. if(IsFriendlyTo(target))
  4709. {
  4710. target = getVictim();
  4711. if(!target)
  4712. {
  4713. uint64 selected_guid = ToPlayer()->GetSelection();
  4714. target = ObjectAccessor::GetUnit(*this, selected_guid);
  4715. if(!target)
  4716. return false;
  4717. }
  4718. if(IsFriendlyTo(target))
  4719. return false;
  4720. }
  4721. triggered_spell_id = 45429;
  4722. break;
  4723. }
  4724. return false;
  4725. }
  4726. // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck)
  4727. // cast 45480 Light's Strength if Exalted by Aldor
  4728. // cast 45428 Arcane Strike if Exalted by Scryers
  4729. case 45482:
  4730. {
  4731. if(GetTypeId() != TYPEID_PLAYER)
  4732. return false;
  4733. // Get Aldor reputation rank
  4734. if(ToPlayer()->GetReputationRank(932) == REP_EXALTED)
  4735. {
  4736. target = this;
  4737. triggered_spell_id = 45480;
  4738. break;
  4739. }
  4740. // Get Scryers reputation rank
  4741. if(ToPlayer()->GetReputationRank(934) == REP_EXALTED)
  4742. {
  4743. triggered_spell_id = 45428;
  4744. break;
  4745. }
  4746. return false;
  4747. }
  4748. // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck)
  4749. // cast 45431 Arcane Insight if Exalted by Aldor
  4750. // cast 45432 Light's Ward if Exalted by Scryers
  4751. case 45483:
  4752. {
  4753. if(GetTypeId() != TYPEID_PLAYER)
  4754. return false;
  4755. // Get Aldor reputation rank
  4756. if(ToPlayer()->GetReputationRank(932) == REP_EXALTED)
  4757. {
  4758. target = this;
  4759. triggered_spell_id = 45432;
  4760. break;
  4761. }
  4762. // Get Scryers reputation rank
  4763. if(ToPlayer()->GetReputationRank(934) == REP_EXALTED)
  4764. {
  4765. target = this;
  4766. triggered_spell_id = 45431;
  4767. break;
  4768. }
  4769. return false;
  4770. }
  4771. // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck)
  4772. // cast 45478 Light's Salvation if Exalted by Aldor
  4773. // cast 45430 Arcane Surge if Exalted by Scryers
  4774. case 45484:
  4775. {
  4776. if(GetTypeId() != TYPEID_PLAYER)
  4777. return false;
  4778. // Get Aldor reputation rank
  4779. if(ToPlayer()->GetReputationRank(932) == REP_EXALTED)
  4780. {
  4781. target = this;
  4782. triggered_spell_id = 45478;
  4783. break;
  4784. }
  4785. // Get Scryers reputation rank
  4786. if(ToPlayer()->GetReputationRank(934) == REP_EXALTED)
  4787. {
  4788. triggered_spell_id = 45430;
  4789. break;
  4790. }
  4791. return false;
  4792. }
  4793. // Living Seed
  4794. case 48504:
  4795. {
  4796. triggered_spell_id = 48503;
  4797. basepoints0 = triggerAmount;
  4798. target = this;
  4799. break;
  4800. }
  4801. // Kill command
  4802. case 58914:
  4803. {
  4804. // Remove aura stack from pet
  4805. RemoveAuraFromStack(58914);
  4806. Unit* owner = GetOwner();
  4807. if(!owner)
  4808. return true;
  4809. // reduce the owner's aura stack
  4810. owner->RemoveAuraFromStack(34027);
  4811. return true;
  4812. }
  4813. // Vampiric Touch (generic, used by some boss)
  4814. case 52723:
  4815. case 60501:
  4816. {
  4817. triggered_spell_id = 52724;
  4818. basepoints0 = damage / 2;
  4819. target = this;
  4820. break;
  4821. }
  4822. // Shadowfiend Death (Gain mana if pet dies with Glyph of Shadowfiend)
  4823. case 57989:
  4824. {
  4825. Unit* owner = GetOwner();
  4826. if(!owner || owner->GetTypeId() != TYPEID_PLAYER)
  4827. return false;
  4828. // Glyph of Shadowfiend (need cast as self cast for owner, no hidden cooldown)
  4829. owner->CastSpell(owner, 58227, true, castItem, triggeredByAura);
  4830. return true;
  4831. }
  4832. // Divine purpose
  4833. case 31871:
  4834. case 31872:
  4835. {
  4836. // Roll chane
  4837. if(!victim || !victim->isAlive() || !roll_chance_i(triggerAmount))
  4838. return false;
  4839. // Remove any stun effect on target
  4840. victim->RemoveAurasWithMechanic(1<<MECHANIC_STUN, AURA_REMOVE_BY_ENEMY_SPELL);
  4841. return true;
  4842. }
  4843. // Glyph of Scourge Strike
  4844. case 58642:
  4845. {
  4846. triggered_spell_id = 69961; // Glyph of Scourge Strike
  4847. break;
  4848. }
  4849. // Glyph of Life Tap
  4850. case 63320:
  4851. {
  4852. triggered_spell_id = 63321; // Life Tap
  4853. break;
  4854. }
  4855. // Purified Shard of the Scale - Onyxia 10 Caster Trinket
  4856. case 69755:
  4857. {
  4858. triggered_spell_id = (procFlag & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS) ? 69733 : 69729;
  4859. break;
  4860. }
  4861. // Shiny Shard of the Scale - Onyxia 25 Caster Trinket
  4862. case 69739:
  4863. {
  4864. triggered_spell_id = (procFlag & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS) ? 69734 : 69730;
  4865. break;
  4866. }
  4867. case 71519: // Deathbringer's Will Normal
  4868. {
  4869. if(GetTypeId() != TYPEID_PLAYER)
  4870. return false;
  4871. std::vector<uint32> RandomSpells;
  4872. switch(getClass())
  4873. {
  4874. case CLASS_WARRIOR:
  4875. case CLASS_PALADIN:
  4876. case CLASS_DEATH_KNIGHT:
  4877. RandomSpells.push_back(71484);
  4878. RandomSpells.push_back(71491);
  4879. RandomSpells.push_back(71492);
  4880. break;
  4881. case CLASS_SHAMAN:
  4882. case CLASS_ROGUE:
  4883. RandomSpells.push_back(71486);
  4884. RandomSpells.push_back(71485);
  4885. RandomSpells.push_back(71492);
  4886. break;
  4887. case CLASS_DRUID:
  4888. RandomSpells.push_back(71484);
  4889. RandomSpells.push_back(71485);
  4890. RandomSpells.push_back(71486);
  4891. break;
  4892. case CLASS_HUNTER:
  4893. RandomSpells.push_back(71486);
  4894. RandomSpells.push_back(71491);
  4895. RandomSpells.push_back(71485);
  4896. break;
  4897. default:
  4898. return false;
  4899. }
  4900. if(RandomSpells.empty()) // shouldn't happen
  4901. return false;
  4902. uint8 rand_spell = irand(0, (RandomSpells.size() - 1));
  4903. CastSpell(target, RandomSpells[rand_spell], true, castItem, triggeredByAura, originalCaster);
  4904. for(std::vector<uint32>::iterator itr = RandomSpells.begin(); itr != RandomSpells.end(); ++itr)
  4905. {
  4906. if(!ToPlayer()->HasSpellCooldown(*itr))
  4907. ToPlayer()->AddSpellCooldown(*itr, 50362, time(NULL) + 105);
  4908. }
  4909. break;
  4910. }
  4911. case 71562: // Deathbringer's Will Heroic
  4912. {
  4913. if(GetTypeId() != TYPEID_PLAYER)
  4914. return false;
  4915. std::vector<uint32> RandomSpells;
  4916. switch(getClass())
  4917. {
  4918. case CLASS_WARRIOR:
  4919. case CLASS_PALADIN:
  4920. case CLASS_DEATH_KNIGHT:
  4921. RandomSpells.push_back(71561);
  4922. RandomSpells.push_back(71559);
  4923. RandomSpells.push_back(71560);
  4924. break;
  4925. case CLASS_SHAMAN:
  4926. case CLASS_ROGUE:
  4927. RandomSpells.push_back(71558);
  4928. RandomSpells.push_back(71556);
  4929. RandomSpells.push_back(71560);
  4930. break;
  4931. case CLASS_DRUID:
  4932. RandomSpells.push_back(71561);
  4933. RandomSpells.push_back(71556);
  4934. RandomSpells.push_back(71558);
  4935. break;
  4936. case CLASS_HUNTER:
  4937. RandomSpells.push_back(71558);
  4938. RandomSpells.push_back(71559);
  4939. RandomSpells.push_back(71556);
  4940. break;
  4941. default:
  4942. return false;
  4943. }
  4944. if(RandomSpells.empty()) // shouldn't happen
  4945. return false;
  4946. uint8 rand_spell = irand(0, (RandomSpells.size() - 1));
  4947. CastSpell(target, RandomSpells[rand_spell], true, castItem, triggeredByAura, originalCaster);
  4948. for(std::vector<uint32>::iterator itr = RandomSpells.begin(); itr != RandomSpells.end(); ++itr)
  4949. {
  4950. if(!ToPlayer()->HasSpellCooldown(*itr))
  4951. ToPlayer()->AddSpellCooldown(*itr, 50363, time(NULL) + 105);
  4952. }
  4953. break;
  4954. }
  4955. case 71875: // Item - Black Bruise: Necrotic Touch Proc
  4956. case 71877:
  4957. {
  4958. basepoints0 = CalculatePctN(int32(damage), triggerAmount);
  4959. triggered_spell_id = 71879;
  4960. break;
  4961. }
  4962. // Item - Shadowmourne Legendary
  4963. case 71903:
  4964. {
  4965. if(!victim || !victim->isAlive() || HasAura(73422)) // cant collect shards while under effect of Chaos Bane buff
  4966. return false;
  4967. CastSpell(this, 71905, true, NULL, triggeredByAura);
  4968. // this can't be handled in AuraScript because we need to know victim
  4969. Aura const* dummy = GetAura(71905);
  4970. if(!dummy || dummy->GetStackAmount() < 10)
  4971. return false;
  4972. RemoveAurasDueToSpell(71905);
  4973. triggered_spell_id = 71904;
  4974. target = victim;
  4975. break;
  4976. }
  4977. // Shadow's Fate (Shadowmourne questline)
  4978. case 71169:
  4979. {
  4980. target = triggeredByAura->GetCaster();
  4981. if(!target)
  4982. return false;
  4983. Player* player = target->ToPlayer();
  4984. if(!player)
  4985. return false;
  4986. // not checking Infusion auras because its in targetAuraSpell of credit spell
  4987. if(player->GetQuestStatus(24749) == QUEST_STATUS_INCOMPLETE && (player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_NORMAL || player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_HEROIC)) // Unholy Infusion
  4988. {
  4989. if(GetEntry() != 36678) // Professor Putricide
  4990. return false;
  4991. CastSpell(target, 71518, true); // Quest Credit
  4992. return true;
  4993. }
  4994. else if(player->GetQuestStatus(24756) == QUEST_STATUS_INCOMPLETE && (player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_NORMAL || player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_HEROIC)) // Blood Infusion
  4995. {
  4996. if(GetEntry() != 37955) // Blood-Queen Lana'thel
  4997. return false;
  4998. CastSpell(target, 72934, true); // Quest Credit
  4999. return true;
  5000. }
  5001. else if(player->GetQuestStatus(24757) == QUEST_STATUS_INCOMPLETE && (player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_NORMAL || player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_HEROIC)) // Frost Infusion
  5002. {
  5003. if(GetEntry() != 36853) // Sindragosa
  5004. return false;
  5005. CastSpell(target, 72289, true); // Quest Credit
  5006. return true;
  5007. }
  5008. else if(player->GetQuestStatus(24547) == QUEST_STATUS_INCOMPLETE) // A Feast of Souls
  5009. triggered_spell_id = 71203;
  5010. break;
  5011. }
  5012. // Gaseous Bloat (Professor Putricide add)
  5013. case 70215:
  5014. case 72858:
  5015. case 72859:
  5016. case 72860:
  5017. {
  5018. target = getVictim();
  5019. triggered_spell_id = 70701;
  5020. break;
  5021. }
  5022. // Essence of the Blood Queen
  5023. case 70871:
  5024. {
  5025. basepoints0 = CalculatePctN(int32(damage), triggerAmount);
  5026. CastCustomSpell(70872, SPELLVALUE_BASE_POINT0, basepoints0, this);
  5027. return true;
  5028. }
  5029. case 65032: // Boom aura (321 Boombot)
  5030. {
  5031. if(victim->GetEntry() != 33343) // Scrapbot
  5032. return false;
  5033. InstanceScript* pInstance = GetInstanceScript();
  5034. if(!pInstance)
  5035. return false;
  5036. pInstance->DoCastSpellOnPlayers(65037); // Achievement criteria marker
  5037. break;
  5038. }
  5039. // Meteor Fists
  5040. case 66725:
  5041. {
  5042. target = getVictim();
  5043. triggered_spell_id = 66765;
  5044. InstanceScript* instance = GetInstanceScript();
  5045. if(!instance)
  5046. return false;
  5047. instance->DoCastSpellOnPlayers(65037); // Achievement criteria marker
  5048. break;
  5049. }
  5050. }
  5051. break;
  5052. }
  5053. case SPELLFAMILY_MAGE:
  5054. {
  5055. // Magic Absorption
  5056. if(dummySpell->SpellIconID == 459) // only this spell have SpellIconID == 459 and dummy aura
  5057. {
  5058. if(getPowerType() != POWER_MANA)
  5059. return false;
  5060. // mana reward
  5061. basepoints0 = CalculatePctN(int32(GetMaxPower(POWER_MANA)), triggerAmount);
  5062. target = this;
  5063. triggered_spell_id = 29442;
  5064. break;
  5065. }
  5066. // Master of Elements
  5067. if(dummySpell->SpellIconID == 1920)
  5068. {
  5069. if(!procSpell)
  5070. return false;
  5071. // mana cost save
  5072. int32 cost = int32(procSpell->manaCost + CalculatePctU(GetCreateMana(), procSpell->ManaCostPercentage));
  5073. basepoints0 = CalculatePctN(cost, triggerAmount);
  5074. if(basepoints0 <= 0)
  5075. return false;
  5076. target = this;
  5077. triggered_spell_id = 29077;
  5078. break;
  5079. }
  5080. // Arcane Potency
  5081. if(dummySpell->SpellIconID == 2120)
  5082. {
  5083. if(!procSpell)
  5084. return false;
  5085. target = this;
  5086. switch(dummySpell->Id)
  5087. {
  5088. case 31571: triggered_spell_id = 57529; break;
  5089. case 31572: triggered_spell_id = 57531; break;
  5090. default:
  5091. sLog->outError("Unit::HandleDummyAuraProc: non handled spell id: %u", dummySpell->Id);
  5092. return false;
  5093. }
  5094. break;
  5095. }
  5096. // Hot Streak
  5097. if(dummySpell->SpellIconID == 2999)
  5098. {
  5099. if(effIndex != 0)
  5100. return false;
  5101. AuraEffect* counter = triggeredByAura->GetBase()->GetEffect(EFFECT_1);
  5102. if(!counter)
  5103. return true;
  5104. // Count spell criticals in a row in second aura
  5105. if(procEx & PROC_EX_CRITICAL_HIT)
  5106. {
  5107. counter->SetAmount(counter->GetAmount() * 2);
  5108. if(counter->GetAmount() < 100) // not enough
  5109. return true;
  5110. // Crititcal counted -> roll chance
  5111. if(roll_chance_i(triggerAmount))
  5112. CastSpell(this, 48108, true, castItem, triggeredByAura);
  5113. }
  5114. counter->SetAmount(25);
  5115. return true;
  5116. }
  5117. // Burnout
  5118. if(dummySpell->SpellIconID == 2998)
  5119. {
  5120. if(!procSpell)
  5121. return false;
  5122. int32 cost = int32(procSpell->manaCost + CalculatePctU(GetCreateMana(), procSpell->ManaCostPercentage));
  5123. basepoints0 = CalculatePctN(cost, triggerAmount);
  5124. if(basepoints0 <= 0)
  5125. return false;
  5126. triggered_spell_id = 44450;
  5127. target = this;
  5128. break;
  5129. }
  5130. // Incanter's Regalia set (add trigger chance to Mana Shield)
  5131. if(dummySpell->SpellFamilyFlags[0] & 0x8000)
  5132. {
  5133. if(GetTypeId() != TYPEID_PLAYER)
  5134. return false;
  5135. target = this;
  5136. triggered_spell_id = 37436;
  5137. break;
  5138. }
  5139. switch(dummySpell->Id)
  5140. {
  5141. case 70752: // Mage T10 2P Bonus
  5142. {
  5143. triggered_spell_id = 70753;
  5144. break;
  5145. }
  5146. case 56250: // Glyph of Seduction
  5147. case 56375: // Glyph of Polymorph
  5148. {
  5149. if(!target)
  5150. return false;
  5151. target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE, 0, target->GetAura(32409)); // SW:D shall not be removed.
  5152. target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
  5153. target->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH);
  5154. return true;
  5155. }
  5156. case 56374: // Glyph of Icy Veins
  5157. {
  5158. RemoveAurasByType(SPELL_AURA_HASTE_SPELLS, 0, 0, true, false);
  5159. RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
  5160. return true;
  5161. }
  5162. case 11119: // Ignite
  5163. case 11120:
  5164. case 12846:
  5165. case 12847:
  5166. case 12848:
  5167. {
  5168. switch(dummySpell->Id)
  5169. {
  5170. case 11119: basepoints0 = int32(0.08f * damage); break;
  5171. case 11120: basepoints0 = int32(0.16f * damage); break;
  5172. case 12846: basepoints0 = int32(0.24f * damage); break;
  5173. case 12847: basepoints0 = int32(0.32f * damage); break;
  5174. case 12848: basepoints0 = int32(0.40f * damage); break;
  5175. default:
  5176. sLog->outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)", dummySpell->Id);
  5177. return false;
  5178. }
  5179. // 2 damage tick
  5180. basepoints0 /= 2;
  5181. triggered_spell_id = 12654;
  5182. // Add remaining ticks to damage done
  5183. basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE);
  5184. break;
  5185. }
  5186. // Glyph of Ice Block
  5187. case 56372:
  5188. {
  5189. Player* plr = ToPlayer();
  5190. if(!plr)
  5191. return false;
  5192. SpellCooldowns const cooldowns = plr->GetSpellCooldowns();
  5193. // remove cooldowns on all ranks of Frost Nova
  5194. for(SpellCooldowns::const_iterator itr = cooldowns.begin(); itr != cooldowns.end(); ++itr)
  5195. {
  5196. SpellEntry const* cdSpell = sSpellStore.LookupEntry(itr->first);
  5197. // Frost Nova
  5198. if(cdSpell && cdSpell->SpellFamilyName == SPELLFAMILY_MAGE
  5199. && cdSpell->SpellFamilyFlags[0] & 0x00000040)
  5200. plr->RemoveSpellCooldown(cdSpell->Id, true);
  5201. }
  5202. break;
  5203. }
  5204. // Blessing of Ancient Kings (Val'anyr, Hammer of Ancient Kings)
  5205. case 64411:
  5206. {
  5207. if(!victim)
  5208. return false;
  5209. basepoints0 = int32(CalculatePctN(damage, 15));
  5210. if(AuraEffect* aurEff = victim->GetAuraEffect(64413, 0, GetGUID()))
  5211. {
  5212. // The shield can grow to a maximum size of 20, 000 damage absorbtion
  5213. aurEff->SetAmount(std::min<int32>(aurEff->GetAmount() + basepoints0, 20000));
  5214. // Refresh and return to prevent replacing the aura
  5215. aurEff->GetBase()->RefreshDuration();
  5216. return true;
  5217. }
  5218. target = victim;
  5219. triggered_spell_id = 64413;
  5220. break;
  5221. }
  5222. case 47020: // Enter vehicle XT-002 (Scrapbot)
  5223. {
  5224. if(GetTypeId() != TYPEID_UNIT)
  5225. return false;
  5226. Unit* vehicleBase = GetVehicleBase();
  5227. if(!vehicleBase)
  5228. return false;
  5229. // Todo: Check if this amount is blizzlike
  5230. vehicleBase->ModifyHealth(int32(vehicleBase->CountPctFromMaxHealth(1)));
  5231. break;
  5232. }
  5233. }
  5234. break;
  5235. }
  5236. case SPELLFAMILY_WARRIOR:
  5237. {
  5238. switch(dummySpell->Id)
  5239. {
  5240. // Sweeping Strikes
  5241. case 12328:
  5242. {
  5243. if(HasAura(46924))
  5244. return false;
  5245. target = SelectNearbyTarget(victim);
  5246. if(!target)
  5247. return false;
  5248. triggered_spell_id = 26654;
  5249. break;
  5250. }
  5251. // Victorious
  5252. case 32216:
  5253. {
  5254. RemoveAura(dummySpell->Id);
  5255. return false;
  5256. }
  5257. // Improved Spell Reflection
  5258. case 59088:
  5259. case 59089:
  5260. {
  5261. triggered_spell_id = 59725;
  5262. target = this;
  5263. break;
  5264. }
  5265. }
  5266. // Retaliation
  5267. if(dummySpell->SpellFamilyFlags[1] & 0x8)
  5268. {
  5269. // check attack comes not from behind
  5270. if(!HasInArc(M_PI, victim))
  5271. return false;
  5272. triggered_spell_id = 22858;
  5273. break;
  5274. }
  5275. // Second Wind
  5276. if(dummySpell->SpellIconID == 1697)
  5277. {
  5278. // only for spells and hit/crit (trigger start always) and not start from self casted spells (5530 Mace Stun Effect for example)
  5279. if(procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == victim)
  5280. return false;
  5281. // Need stun or root mechanic
  5282. if(!(GetAllSpellMechanicMask(procSpell) & ((1<<MECHANIC_ROOT)|(1<<MECHANIC_STUN))))
  5283. return false;
  5284. switch(dummySpell->Id)
  5285. {
  5286. case 29838: triggered_spell_id = 29842; break;
  5287. case 29834: triggered_spell_id = 29841; break;
  5288. case 42770: triggered_spell_id = 42771; break;
  5289. default:
  5290. sLog->outError("Unit::HandleDummyAuraProc: non handled spell id: %u (SW)", dummySpell->Id);
  5291. return false;
  5292. }
  5293. target = this;
  5294. break;
  5295. }
  5296. // Damage Shield
  5297. if(dummySpell->SpellIconID == 3214)
  5298. {
  5299. // to prevent proc from Sap
  5300. if(procSpell && procSpell->AttributesEx & SPELL_ATTR1_NOT_BREAK_STEALTH)
  5301. return false;
  5302. triggered_spell_id = 59653;
  5303. // % of amount blocked
  5304. basepoints0 = CalculatePctN(int32(GetShieldBlockValue()), triggerAmount);
  5305. break;
  5306. }
  5307. // Glyph of Blocking
  5308. if(dummySpell->Id == 58375)
  5309. {
  5310. triggered_spell_id = 58374;
  5311. break;
  5312. }
  5313. // Glyph of Sunder Armor
  5314. if(dummySpell->Id == 58387)
  5315. {
  5316. if(!victim || !victim->isAlive() || !procSpell)
  5317. return false;
  5318. target = SelectNearbyTarget(victim);
  5319. if(!target)
  5320. return false;
  5321. triggered_spell_id = 58567;
  5322. break;
  5323. }
  5324. break;
  5325. }
  5326. case SPELLFAMILY_WARLOCK:
  5327. {
  5328. // Seed of Corruption
  5329. if(dummySpell->SpellFamilyFlags[1] & 0x00000010)
  5330. {
  5331. if(procSpell && procSpell->SpellFamilyFlags[1] & 0x8000)
  5332. return false;
  5333. // if damage is more than need or target die from damage deal finish spell
  5334. if(triggeredByAura->GetAmount() <= int32(damage) || GetHealth() <= damage)
  5335. {
  5336. // remember guid before aura delete
  5337. uint64 casterGuid = triggeredByAura->GetCasterGUID();
  5338. // Remove aura (before cast for prevent infinite loop handlers)
  5339. RemoveAurasDueToSpell(triggeredByAura->GetId());
  5340. uint32 spell = sSpellMgr->GetSpellWithRank(27285, sSpellMgr->GetSpellRank(dummySpell->Id));
  5341. // Cast finish spell (triggeredByAura already not exist!)
  5342. if(Unit* caster = GetUnit(*this, casterGuid))
  5343. caster->CastSpell(this, spell, true, castItem);
  5344. return true; // no hidden cooldown
  5345. }
  5346. // Damage counting
  5347. triggeredByAura->SetAmount(triggeredByAura->GetAmount() - damage);
  5348. return true;
  5349. }
  5350. // Seed of Corruption (Mobs cast) - no die req
  5351. if(dummySpell->SpellFamilyFlags.IsEqual(0, 0, 0) && dummySpell->SpellIconID == 1932)
  5352. {
  5353. // if damage is more than need deal finish spell
  5354. if(triggeredByAura->GetAmount() <= int32(damage))
  5355. {
  5356. // remember guid before aura delete
  5357. uint64 casterGuid = triggeredByAura->GetCasterGUID();
  5358. // Remove aura (before cast for prevent infinite loop handlers)
  5359. RemoveAurasDueToSpell(triggeredByAura->GetId());
  5360. // Cast finish spell (triggeredByAura already not exist!)
  5361. if(Unit* caster = GetUnit(*this, casterGuid))
  5362. caster->CastSpell(this, 32865, true, castItem);
  5363. return true; // no hidden cooldown
  5364. }
  5365. // Damage counting
  5366. triggeredByAura->SetAmount(triggeredByAura->GetAmount() - damage);
  5367. return true;
  5368. }
  5369. // Fel Synergy
  5370. if(dummySpell->SpellIconID == 3222)
  5371. {
  5372. target = GetGuardianPet();
  5373. if(!target)
  5374. return false;
  5375. basepoints0 = CalculatePctN(int32(damage), triggerAmount);
  5376. triggered_spell_id = 54181;
  5377. break;
  5378. }
  5379. switch(dummySpell->Id)
  5380. {
  5381. // Siphon Life
  5382. case 63108:
  5383. {
  5384. // Glyph of Siphon Life
  5385. if(HasAura(56216))
  5386. triggerAmount += triggerAmount / 4;
  5387. triggered_spell_id = 63106;
  5388. target = this;
  5389. basepoints0 = CalculatePctN(int32(damage), triggerAmount);
  5390. break;
  5391. }
  5392. // Glyph of Shadowflame
  5393. case 63310:
  5394. {
  5395. triggered_spell_id = 63311;
  5396. break;
  5397. }
  5398. // Nightfall
  5399. case 18094:
  5400. case 18095:
  5401. // Glyph of corruption
  5402. case 56218:
  5403. {
  5404. target = this;
  5405. triggered_spell_id = 17941;
  5406. break;
  5407. }
  5408. // Soul Leech
  5409. case 30293:
  5410. case 30295:
  5411. case 30296:
  5412. {
  5413. // Improved Soul Leech
  5414. AuraEffectList const& SoulLeechAuras = GetAuraEffectsByType(SPELL_AURA_DUMMY);
  5415. for(Unit::AuraEffectList::const_iterator i = SoulLeechAuras.begin(); i != SoulLeechAuras.end(); ++i)
  5416. {
  5417. if((*i)->GetId() == 54117 || (*i)->GetId() == 54118)
  5418. {
  5419. if((*i)->GetEffIndex() != 0)
  5420. continue;
  5421. basepoints0 = int32((*i)->GetAmount());
  5422. target = GetGuardianPet();
  5423. if(target)
  5424. {
  5425. // regen mana for pet
  5426. CastCustomSpell(target, 54607, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
  5427. }
  5428. // regen mana for caster
  5429. CastCustomSpell(this, 59117, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
  5430. // Get second aura of spell for replenishment effect on party
  5431. if(AuraEffect const* aurEff = (*i)->GetBase()->GetEffect(EFFECT_1))
  5432. { // Replenishment - roll chance
  5433. if(roll_chance_i(aurEff->GetAmount()))
  5434. CastSpell(this, 57669, true, castItem, triggeredByAura);
  5435. }
  5436. break;
  5437. }
  5438. }
  5439. // health
  5440. basepoints0 = CalculatePctN(int32(damage), triggerAmount);
  5441. target = this;
  5442. triggered_spell_id = 30294;
  5443. break;
  5444. }
  5445. // Shadowflame (Voidheart Raiment set bonus)
  5446. case 37377:
  5447. {
  5448. triggered_spell_id = 37379;
  5449. break;
  5450. }
  5451. // Pet Healing (Corruptor Raiment or Rift Stalker Armor)
  5452. case 37381:
  5453. {
  5454. target = GetGuardianPet();
  5455. if(!target)
  5456. return false;
  5457. // heal amount
  5458. basepoints0 = CalculatePctN(int32(damage), triggerAmount);
  5459. triggered_spell_id = 37382;
  5460. break;
  5461. }
  5462. // Shadowflame Hellfire (Voidheart Raiment set bonus)
  5463. case 39437:
  5464. {
  5465. triggered_spell_id = 37378;
  5466. break;
  5467. }
  5468. }
  5469. break;
  5470. }
  5471. case SPELLFAMILY_PRIEST:
  5472. {
  5473. // Vampiric Touch
  5474. if(dummySpell->SpellFamilyFlags[1] & 0x00000400)
  5475. {
  5476. if(!victim || !victim->isAlive())
  5477. return false;
  5478. if(effIndex != 0)
  5479. return false;
  5480. // victim is caster of aura
  5481. if(triggeredByAura->GetCasterGUID() != victim->GetGUID())
  5482. return false;
  5483. // Energize 0.25% of max. mana
  5484. victim->CastSpell(victim, 57669, true, castItem, triggeredByAura);
  5485. return true; // no hidden cooldown
  5486. }
  5487. // Divine Aegis
  5488. if(dummySpell->SpellIconID == 2820)
  5489. {
  5490. if(!target)
  5491. return false;
  5492. // Multiple effects stack, so let's try to find this aura.
  5493. int32 bonus = 0;
  5494. if(AuraEffect const* aurEff = target->GetAuraEffect(47753, 0))
  5495. bonus = aurEff->GetAmount();
  5496. basepoints0 = CalculatePctN(int32(damage), triggerAmount) + bonus;
  5497. if(basepoints0 > target->getLevel() * 125)
  5498. basepoints0 = target->getLevel() * 125;
  5499. triggered_spell_id = 47753;
  5500. break;
  5501. }
  5502. // Body and Soul
  5503. if(dummySpell->SpellIconID == 2218)
  5504. {
  5505. // Proc only from Abolish desease on self cast
  5506. if(procSpell->Id != 552 || victim != this || !roll_chance_i(triggerAmount))
  5507. return false;
  5508. triggered_spell_id = 64136;
  5509. target = this;
  5510. break;
  5511. }
  5512. switch(dummySpell->Id)
  5513. {
  5514. // Vampiric Embrace
  5515. case 15286:
  5516. {
  5517. if(!victim || !victim->isAlive() || procSpell->SpellFamilyFlags[1] & 0x80000 || target->HasAura(33786))
  5518. return false;
  5519. // heal amount
  5520. int32 total = CalculatePctN(int32(damage), triggerAmount);
  5521. int32 team = total / 5;
  5522. int32 self = total - team;
  5523. CastCustomSpell(this, 15290, &team, &self, NULL, true, castItem, triggeredByAura);
  5524. return true; // no hidden cooldown
  5525. }
  5526. // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen)
  5527. case 40438:
  5528. {
  5529. // Shadow Word: Pain
  5530. if(procSpell->SpellFamilyFlags[0] & 0x8000)
  5531. triggered_spell_id = 40441;
  5532. // Renew
  5533. else if(procSpell->SpellFamilyFlags[0] & 0x40)
  5534. triggered_spell_id = 40440;
  5535. else
  5536. return false;
  5537. target = this;
  5538. break;
  5539. }
  5540. // Glyph of Prayer of Healing
  5541. case 55680:
  5542. {
  5543. triggered_spell_id = 56161;
  5544. SpellEntry const* GoPoH = sSpellStore.LookupEntry(triggered_spell_id);
  5545. if(!GoPoH)
  5546. return false;
  5547. int EffIndex = 0;
  5548. for(uint8 i = 0; i < MAX_SPELL_EFFECTS; i++)
  5549. {
  5550. if(GoPoH->Effect[i] == SPELL_EFFECT_APPLY_AURA)
  5551. {
  5552. EffIndex = i;
  5553. break;
  5554. }
  5555. }
  5556. int32 tickcount = GetSpellMaxDuration(GoPoH) / GoPoH->EffectAmplitude[EffIndex];
  5557. if(!tickcount)
  5558. return false;
  5559. basepoints0 = CalculatePctN(int32(damage), triggerAmount) / tickcount;
  5560. break;
  5561. }
  5562. // Improved Shadowform
  5563. case 47570:
  5564. case 47569:
  5565. {
  5566. if(!roll_chance_i(triggerAmount))
  5567. return false;
  5568. RemoveMovementImpairingAuras();
  5569. break;
  5570. }
  5571. // Glyph of Dispel Magic
  5572. case 55677:
  5573. {
  5574. // Dispel Magic shares spellfamilyflag with abolish disease
  5575. if(procSpell->SpellIconID != 74)
  5576. return false;
  5577. if(!target || !target->IsFriendlyTo(this) || target->GetTypeId() != TYPEID_PLAYER)
  5578. return false;
  5579. basepoints0 = int32(target->CountPctFromMaxHealth(triggerAmount));
  5580. triggered_spell_id = 56131;
  5581. break;
  5582. }
  5583. // Oracle Healing Bonus ("Garments of the Oracle" set)
  5584. case 26169:
  5585. {
  5586. // heal amount
  5587. basepoints0 = int32(CalculatePctN(damage, 10));
  5588. target = this;
  5589. triggered_spell_id = 26170;
  5590. break;
  5591. }
  5592. // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set
  5593. case 39372:
  5594. {
  5595. if(!procSpell || (GetSpellSchoolMask(procSpell) & (SPELL_SCHOOL_MASK_FROST | SPELL_SCHOOL_MASK_SHADOW)) == 0)
  5596. return false;
  5597. // heal amount
  5598. basepoints0 = CalculatePctN(int32(damage), triggerAmount);
  5599. target = this;
  5600. triggered_spell_id = 39373;
  5601. break;
  5602. }
  5603. // Greater Heal (Vestments of Faith (Priest Tier 3) - 4 pieces bonus)
  5604. case 28809:
  5605. {
  5606. triggered_spell_id = 28810;
  5607. break;
  5608. }
  5609. // Priest T10 Healer 2P Bonus
  5610. case 70770:
  5611. // Flash Heal
  5612. if(procSpell->SpellFamilyFlags[0] & 0x800)
  5613. {
  5614. triggered_spell_id = 70772;
  5615. SpellEntry const* blessHealing = sSpellStore.LookupEntry(triggered_spell_id);
  5616. if(!blessHealing)
  5617. return false;
  5618. basepoints0 = int32(CalculatePctN(damage, triggerAmount) / (GetSpellMaxDuration(blessHealing) / blessHealing->EffectAmplitude[0]));
  5619. }
  5620. break;
  5621. }
  5622. break;
  5623. }
  5624. case SPELLFAMILY_DRUID:
  5625. {
  5626. switch(dummySpell->Id)
  5627. {
  5628. // Glyph of Innervate
  5629. case 54832:
  5630. {
  5631. if(procSpell->SpellIconID != 62)
  5632. return false;
  5633. int32 mana_perc = SpellMgr::CalculateSpellEffectAmount(triggeredByAura->GetSpellProto(), triggeredByAura->GetEffIndex());
  5634. basepoints0 = int32(CalculatePctN(GetCreatePowers(POWER_MANA), mana_perc) / 10);
  5635. triggered_spell_id = 54833;
  5636. target = this;
  5637. break;
  5638. }
  5639. // Glyph of Starfire
  5640. case 54845:
  5641. {
  5642. triggered_spell_id = 54846;
  5643. break;
  5644. }
  5645. // Glyph of Shred
  5646. case 54815:
  5647. {
  5648. if(!target)
  5649. return false;
  5650. // try to find spell Rip on the target
  5651. if(AuraEffect const* AurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00800000, 0x0, 0x0, GetGUID()))
  5652. {
  5653. // Rip's max duration, note: spells which modifies Rip's duration also counted like Glyph of Rip
  5654. uint32 CountMin = AurEff->GetBase()->GetMaxDuration();
  5655. // just Rip's max duration without other spells
  5656. uint32 CountMax = GetSpellMaxDuration(AurEff->GetSpellProto());
  5657. // add possible auras' and Glyph of Shred's max duration
  5658. CountMax += 3 * triggerAmount * IN_MILLISECONDS; // Glyph of Shred -> +6 seconds
  5659. CountMax += HasAura(54818) ? 4 * IN_MILLISECONDS : 0; // Glyph of Rip -> +4 seconds
  5660. CountMax += HasAura(60141) ? 4 * IN_MILLISECONDS : 0; // Rip Duration/Lacerate Damage -> +4 seconds
  5661. // if min < max -> that means caster didn't cast 3 shred yet
  5662. // so set Rip's duration and max duration
  5663. if(CountMin < CountMax)
  5664. {
  5665. AurEff->GetBase()->SetDuration(AurEff->GetBase()->GetDuration() + triggerAmount * IN_MILLISECONDS);
  5666. AurEff->GetBase()->SetMaxDuration(CountMin + triggerAmount * IN_MILLISECONDS);
  5667. return true;
  5668. }
  5669. }
  5670. // if not found Rip
  5671. return false;
  5672. }
  5673. // Glyph of Rake
  5674. case 54821:
  5675. {
  5676. if(procSpell->SpellVisual[0] == 750 && procSpell->EffectApplyAuraName[1] == 3)
  5677. {
  5678. if(target && target->GetTypeId() == TYPEID_UNIT)
  5679. {
  5680. triggered_spell_id = 54820;
  5681. break;
  5682. }
  5683. }
  5684. return false;
  5685. }
  5686. // Leader of the Pack
  5687. case 24932:
  5688. {
  5689. if(triggerAmount <= 0)
  5690. return false;
  5691. basepoints0 = int32(CountPctFromMaxHealth(triggerAmount));
  5692. target = this;
  5693. triggered_spell_id = 34299;
  5694. if(triggeredByAura->GetCasterGUID() != GetGUID())
  5695. break;
  5696. int32 basepoints1 = triggerAmount * 2;
  5697. // Improved Leader of the Pack
  5698. // Check cooldown of heal spell cooldown
  5699. if(GetTypeId() == TYPEID_PLAYER && !ToPlayer()->HasSpellCooldown(34299))
  5700. CastCustomSpell(this, 60889, &basepoints1, 0, 0, true, 0, triggeredByAura);
  5701. break;
  5702. }
  5703. // Healing Touch (Dreamwalker Raiment set)
  5704. case 28719:
  5705. {
  5706. // mana back
  5707. basepoints0 = int32(CalculatePctN(procSpell->manaCost, 30));
  5708. target = this;
  5709. triggered_spell_id = 28742;
  5710. break;
  5711. }
  5712. // Glyph of Rejuvenation
  5713. case 54754:
  5714. {
  5715. if(!victim || !victim->HealthBelowPct(uint32(triggerAmount)))
  5716. return false;
  5717. basepoints0 = CalculatePctN(int32(damage), triggerAmount);
  5718. triggered_spell_id = 54755;
  5719. break;
  5720. }
  5721. // Healing Touch Refund (Idol of Longevity trinket)
  5722. case 28847:
  5723. {
  5724. target = this;
  5725. triggered_spell_id = 28848;
  5726. break;
  5727. }
  5728. // Mana Restore (Malorne Raiment set / Malorne Regalia set)
  5729. case 37288:
  5730. case 37295:
  5731. {
  5732. target = this;
  5733. triggered_spell_id = 37238;
  5734. break;
  5735. }
  5736. // Druid Tier 6 Trinket
  5737. case 40442:
  5738. {
  5739. float chance;
  5740. // Starfire
  5741. if(procSpell->SpellFamilyFlags[0] & 0x4)
  5742. {
  5743. triggered_spell_id = 40445;
  5744. chance = 25.0f;
  5745. }
  5746. // Rejuvenation
  5747. else if(procSpell->SpellFamilyFlags[0] & 0x10)
  5748. {
  5749. triggered_spell_id = 40446;
  5750. chance = 25.0f;
  5751. }
  5752. // Mangle (Bear) and Mangle (Cat)
  5753. else if(procSpell->SpellFamilyFlags[1] & 0x00000440)
  5754. {
  5755. triggered_spell_id = 40452;
  5756. chance = 40.0f;
  5757. }
  5758. else
  5759. return false;
  5760. if(!roll_chance_f(chance))
  5761. return false;
  5762. target = this;
  5763. break;
  5764. }
  5765. // Maim Interrupt
  5766. case 44835:
  5767. {
  5768. // Deadly Interrupt Effect
  5769. triggered_spell_id = 32747;
  5770. break;
  5771. }
  5772. case 57934: // Tricks of the Trade
  5773. {
  5774. if(Unit* unitTarget = GetMisdirectionTarget())
  5775. {
  5776. RemoveAura(dummySpell->Id, GetGUID(), 0, AURA_REMOVE_BY_DEFAULT);
  5777. CastSpell(this, 59628, true);
  5778. CastSpell(unitTarget, 57933, true);
  5779. return true;
  5780. }
  5781. return false;
  5782. }
  5783. // Item - Druid T10 Balance 4P Bonus
  5784. case 70723:
  5785. {
  5786. // Wrath & Starfire
  5787. if((procSpell->SpellFamilyFlags[0] & 0x5) && (procEx & PROC_EX_CRITICAL_HIT))
  5788. {
  5789. triggered_spell_id = 71023;
  5790. SpellEntry const* triggeredSpell = sSpellStore.LookupEntry(triggered_spell_id);
  5791. if(!triggeredSpell)
  5792. return false;
  5793. basepoints0 = CalculatePctN(int32(damage), triggerAmount) / (GetSpellMaxDuration(triggeredSpell) / triggeredSpell->EffectAmplitude[0]);
  5794. // Add remaining ticks to damage done
  5795. basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE);
  5796. }
  5797. break;
  5798. }
  5799. // Item - Druid T10 Restoration 4P Bonus (Rejuvenation)
  5800. case 70664:
  5801. {
  5802. // Proc only from normal Rejuvenation
  5803. if(procSpell->SpellVisual[0] != 32)
  5804. return false;
  5805. Player* caster = ToPlayer();
  5806. if(!caster)
  5807. return false;
  5808. if(!caster->GetGroup() && victim == this)
  5809. return false;
  5810. CastCustomSpell(70691, SPELLVALUE_BASE_POINT0, damage, victim, true);
  5811. return true;
  5812. }
  5813. case 770:
  5814. case 16857:
  5815. if(target->HasAura(33786))
  5816. return false;
  5817. break;
  5818. }
  5819. // Eclipse
  5820. if(dummySpell->SpellIconID == 2856 && GetTypeId() == TYPEID_PLAYER)
  5821. {
  5822. if(!procSpell || effIndex != 0)
  5823. return false;
  5824. bool isWrathSpell = (procSpell->SpellFamilyFlags[0] & 1);
  5825. if(!roll_chance_f(dummySpell->procChance * (isWrathSpell ? 0.6f : 1.0f)))
  5826. return false;
  5827. target = this;
  5828. if(target->HasAura(isWrathSpell ? 48517 : 48518))
  5829. return false;
  5830. triggered_spell_id = isWrathSpell ? 48518 : 48517;
  5831. break;
  5832. }
  5833. // Living Seed
  5834. else if(dummySpell->SpellIconID == 2860)
  5835. {
  5836. triggered_spell_id = 48504;
  5837. basepoints0 = CalculatePctN(int32(damage), triggerAmount);
  5838. break;
  5839. }
  5840. // King of the Jungle
  5841. else if(dummySpell->SpellIconID == 2850)
  5842. {
  5843. // Effect 0 - mod damage while having Enrage
  5844. if(effIndex == 0)
  5845. {
  5846. if(!(procSpell->SpellFamilyFlags[0] & 0x00080000))
  5847. return false;
  5848. triggered_spell_id = 51185;
  5849. basepoints0 = triggerAmount;
  5850. target = this;
  5851. break;
  5852. }
  5853. // Effect 1 - Tiger's Fury restore energy
  5854. else if(effIndex == 1)
  5855. {
  5856. if(!(procSpell->SpellFamilyFlags[2] & 0x00000800))
  5857. return false;
  5858. triggered_spell_id = 51178;
  5859. basepoints0 = triggerAmount;
  5860. target = this;
  5861. break;
  5862. }
  5863. }
  5864. break;
  5865. }
  5866. case SPELLFAMILY_ROGUE:
  5867. {
  5868. switch(dummySpell->Id)
  5869. {
  5870. // Glyph of Backstab
  5871. case 56800:
  5872. {
  5873. triggered_spell_id = 63975;
  5874. break;
  5875. }
  5876. // Deadly Throw Interrupt
  5877. case 32748:
  5878. {
  5879. // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw
  5880. if(this == victim)
  5881. return false;
  5882. triggered_spell_id = 32747;
  5883. break;
  5884. }
  5885. // Tricks of the trade
  5886. case 57934:
  5887. {
  5888. triggered_spell_id = 57933; // Tricks of the Trade, increased damage buff
  5889. target = GetMisdirectionTarget();
  5890. if(!target)
  5891. return false;;
  5892. CastSpell(this, 59628, true); // Tricks of the Trade (caster timer)
  5893. break;
  5894. }
  5895. }
  5896. // Cut to the Chase
  5897. if(dummySpell->SpellIconID == 2909)
  5898. {
  5899. // "refresh your Slice and Dice duration to its 5 combo point maximum"
  5900. // lookup Slice and Dice
  5901. if(AuraEffect const* aur = GetAuraEffect(SPELL_AURA_MOD_MELEE_HASTE, SPELLFAMILY_ROGUE, 0x40000, 0, 0))
  5902. {
  5903. aur->GetBase()->SetDuration(GetSpellMaxDuration(aur->GetSpellProto()), true);
  5904. return true;
  5905. }
  5906. return false;
  5907. }
  5908. // Deadly Brew
  5909. else if(dummySpell->SpellIconID == 2963)
  5910. {
  5911. triggered_spell_id = 3409;
  5912. break;
  5913. }
  5914. // Quick Recovery
  5915. else if(dummySpell->SpellIconID == 2116)
  5916. {
  5917. if(!procSpell)
  5918. return false;
  5919. // energy cost save
  5920. basepoints0 = CalculatePctN(int32(procSpell->manaCost), triggerAmount);
  5921. if(basepoints0 <= 0)
  5922. return false;
  5923. target = this;
  5924. triggered_spell_id = 31663;
  5925. break;
  5926. }
  5927. break;
  5928. }
  5929. case SPELLFAMILY_HUNTER:
  5930. {
  5931. // Thrill of the Hunt
  5932. if(dummySpell->SpellIconID == 2236)
  5933. {
  5934. if(!procSpell)
  5935. return false;
  5936. Spell* spell = ToPlayer()->m_spellModTakingSpell;
  5937. // Disable charge drop because of Lock and Load
  5938. ToPlayer()->SetSpellModTakingSpell(spell, false);
  5939. // Explosive Shot
  5940. if(procSpell->SpellFamilyFlags[2] & 0x200)
  5941. {
  5942. if(!victim)
  5943. return false;
  5944. if(AuraEffect const* pEff = victim->GetAuraEffect(SPELL_AURA_PERIODIC_DUMMY, SPELLFAMILY_HUNTER, 0x0, 0x80000000, 0x0, GetGUID()))
  5945. basepoints0 = CalculatePowerCost(pEff->GetSpellProto(), this, SpellSchoolMask(pEff->GetSpellProto()->SchoolMask)) * 4/10/3;
  5946. }
  5947. else
  5948. basepoints0 = CalculatePowerCost(procSpell, this, SpellSchoolMask(procSpell->SchoolMask)) * 4/10;
  5949. ToPlayer()->SetSpellModTakingSpell(spell, true);
  5950. if(basepoints0 <= 0)
  5951. return false;
  5952. target = this;
  5953. triggered_spell_id = 34720;
  5954. break;
  5955. }
  5956. // Hunting Party
  5957. if(dummySpell->SpellIconID == 3406)
  5958. {
  5959. triggered_spell_id = 57669;
  5960. target = this;
  5961. break;
  5962. }
  5963. // Improved Mend Pet
  5964. if(dummySpell->SpellIconID == 267)
  5965. {
  5966. int32 chance = SpellMgr::CalculateSpellEffectAmount(triggeredByAura->GetSpellProto(), triggeredByAura->GetEffIndex());
  5967. if(!roll_chance_i(chance))
  5968. return false;
  5969. triggered_spell_id = 24406;
  5970. break;
  5971. }
  5972. // Lock and Load
  5973. if(dummySpell->SpellIconID == 3579)
  5974. {
  5975. // Proc only from periodic (from trap activation proc another aura of this spell)
  5976. if(!(procFlag & PROC_FLAG_DONE_PERIODIC) || !roll_chance_i(triggerAmount))
  5977. return false;
  5978. triggered_spell_id = 56453;
  5979. target = this;
  5980. break;
  5981. }
  5982. // Rapid Recuperation
  5983. if(dummySpell->SpellIconID == 3560)
  5984. {
  5985. // This effect only from Rapid Killing (mana regen)
  5986. if(!(procSpell->SpellFamilyFlags[1] & 0x01000000))
  5987. return false;
  5988. target = this;
  5989. switch(dummySpell->Id)
  5990. {
  5991. case 53228: // Rank 1
  5992. triggered_spell_id = 56654;
  5993. break;
  5994. case 53232: // Rank 2
  5995. triggered_spell_id = 58882;
  5996. break;
  5997. }
  5998. break;
  5999. }
  6000. // Glyph of Mend Pet
  6001. if(dummySpell->Id == 57870)
  6002. {
  6003. victim->CastSpell(victim, 57894, true, NULL, NULL, GetGUID());
  6004. return true;
  6005. }
  6006. // Misdirection
  6007. if(dummySpell->Id == 34477)
  6008. {
  6009. RemoveAura(dummySpell->Id, GetGUID(), 0, AURA_REMOVE_BY_DEFAULT);
  6010. CastSpell(this, 35079, true);
  6011. return true;
  6012. }
  6013. //Roar of Sacrifice (pet talent spell); aura added in SpellMgr::LoadSpellCustomAttr
  6014. if(dummySpell->Id == 53480)
  6015. {
  6016. triggered_spell_id = 67481;
  6017. target = triggeredByAura->GetCaster();
  6018. basepoints0 = CalculatePctN(damage, triggerAmount);
  6019. break;
  6020. }
  6021. break;
  6022. }
  6023. case SPELLFAMILY_PALADIN:
  6024. {
  6025. // Seal of Righteousness - melee proc dummy (addition ${$MWS*(0.022*$AP+0.044*$SPH)} damage)
  6026. if(dummySpell->SpellFamilyFlags[0] & 0x8000000)
  6027. {
  6028. if(effIndex != 0)
  6029. return false;
  6030. triggered_spell_id = 25742;
  6031. float ap = GetTotalAttackPowerValue(BASE_ATTACK);
  6032. int32 holy = SpellBaseDamageBonus(SPELL_SCHOOL_MASK_HOLY) +
  6033. SpellBaseDamageBonusForVictim(SPELL_SCHOOL_MASK_HOLY, victim);
  6034. basepoints0 = (int32)GetAttackTime(BASE_ATTACK) * int32(ap * 0.022f + 0.044f * holy) / 1000;
  6035. break;
  6036. }
  6037. // Light's Beacon - Beacon of Light
  6038. if(dummySpell->Id == 53651)
  6039. {
  6040. if (!victim)
  6041. return false;
  6042. // Get target of beacon of light
  6043. if(Unit* beaconTarget = triggeredByAura->GetBase()->GetCaster())
  6044. {
  6045. // do not proc when target of beacon of light is healed
  6046. if(beaconTarget == this)
  6047. return false;
  6048. // check if it was heal by paladin which casted this beacon of light
  6049. if(beaconTarget->GetAura(53563, victim->GetGUID())) // if (!beaconTarget || beaconTarget == this || !(beaconTarget->GetAura(53563, victim->GetGUID()))) //
  6050. {
  6051. if(beaconTarget->IsWithinLOSInMap(victim))
  6052. {
  6053. basepoints0 = damage;
  6054. victim->CastCustomSpell(beaconTarget, 53654, &basepoints0, NULL, NULL, true);
  6055. return true;
  6056. }
  6057. }
  6058. }
  6059. return false;
  6060. }
  6061. // Judgements of the Wise
  6062. if(dummySpell->SpellIconID == 3017)
  6063. {
  6064. target = this;
  6065. triggered_spell_id = 31930;
  6066. // replenishment
  6067. CastSpell(this, 57669, true, castItem, triggeredByAura);
  6068. break;
  6069. }
  6070. // Sanctified Wrath
  6071. if(dummySpell->SpellIconID == 3029)
  6072. {
  6073. triggered_spell_id = 57318;
  6074. target = this;
  6075. basepoints0 = triggerAmount;
  6076. CastCustomSpell(target, triggered_spell_id, &basepoints0, &basepoints0, NULL, true, castItem, triggeredByAura);
  6077. return true;
  6078. }
  6079. // Sacred Shield
  6080. if(dummySpell->SpellFamilyFlags[1] & 0x80000)
  6081. {
  6082. if(procFlag & PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS)
  6083. {
  6084. if(procSpell->SpellFamilyName == SPELLFAMILY_PALADIN && (procSpell->SpellFamilyFlags[0] & 0x40000000))
  6085. {
  6086. basepoints0 = damage / 12;
  6087. if(basepoints0)
  6088. CastCustomSpell(this, 66922, &basepoints0, NULL, NULL, true, 0, triggeredByAura, victim->GetGUID());
  6089. return true;
  6090. }
  6091. else
  6092. return false;
  6093. }
  6094. else if(damage > 0)
  6095. triggered_spell_id = 58597;
  6096. // Item - Paladin T8 Holy 4P Bonus
  6097. if(Unit* caster = triggeredByAura->GetCaster())
  6098. if(AuraEffect const* aurEff = caster->GetAuraEffect(64895, 0))
  6099. cooldown = aurEff->GetAmount();
  6100. target = this;
  6101. break;
  6102. }
  6103. // Righteous Vengeance
  6104. if(dummySpell->SpellIconID == 3025)
  6105. {
  6106. // 4 damage tick
  6107. basepoints0 = triggerAmount * damage / 400;
  6108. triggered_spell_id = 61840;
  6109. // Add remaining ticks to damage done
  6110. basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE);
  6111. break;
  6112. }
  6113. // Sheath of Light
  6114. if(dummySpell->SpellIconID == 3030)
  6115. {
  6116. // 4 healing tick
  6117. basepoints0 = triggerAmount * damage / 400;
  6118. triggered_spell_id = 54203;
  6119. break;
  6120. }
  6121. switch(dummySpell->Id)
  6122. { // Heart of the Crusader
  6123. case 20335: // rank 1
  6124. triggered_spell_id = 21183;
  6125. break;
  6126. case 20336: // rank 2
  6127. triggered_spell_id = 54498;
  6128. break;
  6129. case 20337: // rank 3
  6130. triggered_spell_id = 54499;
  6131. break;
  6132. // Judgement of Light
  6133. case 20185:
  6134. {
  6135. if(!victim)
  6136. return false;
  6137. // 2% of base mana
  6138. basepoints0 = int32(victim->CountPctFromMaxHealth(2));
  6139. victim->CastCustomSpell(victim, 20267, &basepoints0, 0, 0, true, 0, triggeredByAura);
  6140. return true;
  6141. }
  6142. // Judgement of Wisdom
  6143. case 20186:
  6144. {
  6145. if(victim && victim->isAlive() && victim->getPowerType() == POWER_MANA)
  6146. {
  6147. // 2% of base mana
  6148. basepoints0 = int32(CalculatePctN(victim->GetCreateMana(), 2));
  6149. victim->CastCustomSpell(victim, 20268, &basepoints0, NULL, NULL, true, 0, triggeredByAura);
  6150. }
  6151. return true;
  6152. }
  6153. // Holy Power (Redemption Armor set)
  6154. case 28789:
  6155. {
  6156. if(!victim)
  6157. return false;
  6158. // Set class defined buff
  6159. switch(victim->getClass())
  6160. {
  6161. case CLASS_PALADIN:
  6162. case CLASS_PRIEST:
  6163. case CLASS_SHAMAN:
  6164. case CLASS_DRUID:
  6165. triggered_spell_id = 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
  6166. break;
  6167. case CLASS_MAGE:
  6168. case CLASS_WARLOCK:
  6169. triggered_spell_id = 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
  6170. break;
  6171. case CLASS_HUNTER:
  6172. case CLASS_ROGUE:
  6173. triggered_spell_id = 28791; // Increases the friendly target's attack power by $s1 for $d.
  6174. break;
  6175. case CLASS_WARRIOR:
  6176. triggered_spell_id = 28790; // Increases the friendly target's armor
  6177. break;
  6178. default:
  6179. return false;
  6180. }
  6181. break;
  6182. }
  6183. case 25899: // Greater Blessing of Sanctuary
  6184. case 20911: // Blessing of Sanctuary
  6185. {
  6186. target = this;
  6187. switch(target->getPowerType())
  6188. {
  6189. case POWER_MANA:
  6190. triggered_spell_id = 57319;
  6191. break;
  6192. default:
  6193. return false;
  6194. }
  6195. break;
  6196. }
  6197. // Seal of Vengeance (damage calc on apply aura)
  6198. case 31801:
  6199. {
  6200. if(effIndex != 0) // effect 1, 2 used by seal unleashing code
  6201. return false;
  6202. // At melee attack or Hammer of the Righteous spell damage considered as melee attack
  6203. bool stacker = !procSpell || procSpell->Id == 53595;
  6204. // spells with SPELL_DAMAGE_CLASS_MELEE excluding Judgements
  6205. bool damager = procSpell && procSpell->EquippedItemClass != -1;
  6206. if(!stacker && !damager)
  6207. return false;
  6208. triggered_spell_id = 31803;
  6209. // On target with 5 stacks of Holy Vengeance direct damage is done
  6210. if(Aura* aur = victim->GetAura(triggered_spell_id, GetGUID()))
  6211. {
  6212. if(aur->GetStackAmount() == 5)
  6213. {
  6214. if(stacker)
  6215. aur->RefreshDuration();
  6216. CastSpell(victim, 42463, true);
  6217. return true;
  6218. }
  6219. }
  6220. if(!stacker)
  6221. return false;
  6222. break;
  6223. }
  6224. // Seal of Corruption
  6225. case 53736:
  6226. {
  6227. if(effIndex != 0) // effect 1, 2 used by seal unleashing code
  6228. return false;
  6229. // At melee attack or Hammer of the Righteous spell damage considered as melee attack
  6230. bool stacker = !procSpell || procSpell->Id == 53595;
  6231. // spells with SPELL_DAMAGE_CLASS_MELEE excluding Judgements
  6232. bool damager = procSpell && procSpell->EquippedItemClass != -1;
  6233. if(!stacker && !damager)
  6234. return false;
  6235. triggered_spell_id = 53742;
  6236. // On target with 5 stacks of Blood Corruption direct damage is done
  6237. if(Aura* aur = victim->GetAura(triggered_spell_id, GetGUID()))
  6238. {
  6239. if(aur->GetStackAmount() == 5)
  6240. {
  6241. if(stacker)
  6242. aur->RefreshDuration();
  6243. CastSpell(victim, 53739, true);
  6244. return true;
  6245. }
  6246. }
  6247. if(!stacker)
  6248. return false;
  6249. break;
  6250. }
  6251. // Spiritual Attunement
  6252. case 31785:
  6253. case 31786:
  6254. {
  6255. // if healed by another unit (pVictim)
  6256. if(this == victim)
  6257. return false;
  6258. // heal amount
  6259. int32 mana=5*(std::min(damage,GetMaxHealth() - GetHealth()))/100;
  6260. EnergizeBySpell(this, 31785, mana, POWER_MANA);
  6261. return true;
  6262. break;
  6263. }
  6264. case 38421:
  6265. case 33776:
  6266. {
  6267. // if healed by another unit (pVictim)
  6268. if(this == victim)
  6269. return false;
  6270. int32 mana = (std::min(damage,GetMaxHealth() - GetHealth()))/10;
  6271. // heal amount
  6272. EnergizeBySpell(this, 33776, mana, POWER_MANA);
  6273. return true;
  6274. break;
  6275. }
  6276. // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal)
  6277. case 40470:
  6278. {
  6279. if(!procSpell)
  6280. return false;
  6281. float chance;
  6282. // Flash of light/Holy light
  6283. if(procSpell->SpellFamilyFlags[0] & 0xC0000000)
  6284. {
  6285. triggered_spell_id = 40471;
  6286. chance = 15.0f;
  6287. }
  6288. // Judgement (any)
  6289. else if(GetSpellSpecific(procSpell) == SPELL_SPECIFIC_JUDGEMENT)
  6290. {
  6291. triggered_spell_id = 40472;
  6292. chance = 50.0f;
  6293. }
  6294. else
  6295. return false;
  6296. if(!roll_chance_f(chance))
  6297. return false;
  6298. break;
  6299. }
  6300. // Glyph of Holy Light
  6301. case 54937:
  6302. {
  6303. triggered_spell_id = 54968;
  6304. basepoints0 = CalculatePctN(int32(damage), triggerAmount);
  6305. break;
  6306. }
  6307. // Item - Paladin T8 Holy 2P Bonus
  6308. case 64890:
  6309. {
  6310. triggered_spell_id = 64891;
  6311. basepoints0 = triggerAmount * damage / 300;
  6312. break;
  6313. }
  6314. case 71406: // Tiny Abomination in a Jar
  6315. case 71545: // Tiny Abomination in a Jar (Heroic)
  6316. {
  6317. if(!victim || !victim->isAlive())
  6318. return false;
  6319. CastSpell(this, 71432, true, NULL, triggeredByAura);
  6320. Aura const* dummy = GetAura(71432);
  6321. if(!dummy || dummy->GetStackAmount() < (dummySpell->Id == 71406 ? 8 : 7))
  6322. return false;
  6323. RemoveAurasDueToSpell(71432);
  6324. triggered_spell_id = 71433; // default main hand attack
  6325. // roll if offhand
  6326. if(Player const* player = ToPlayer())
  6327. if(player->GetWeaponForAttack(OFF_ATTACK, true) && urand(0, 1))
  6328. triggered_spell_id = 71434;
  6329. target = victim;
  6330. break;
  6331. }
  6332. case 99997: // Divine Storm Helper (SERVERSIDE)
  6333. {
  6334. if(victim == this)
  6335. return false;
  6336. triggeredByAura->SetAmount(triggeredByAura->GetAmount() + damage);
  6337. return true;
  6338. }
  6339. break;
  6340. // Item - Icecrown 25 Normal Dagger Proc
  6341. case 71880:
  6342. {
  6343. switch(getPowerType())
  6344. {
  6345. case POWER_MANA:
  6346. triggered_spell_id = 71881;
  6347. break;
  6348. case POWER_RAGE:
  6349. triggered_spell_id = 71883;
  6350. break;
  6351. case POWER_ENERGY:
  6352. triggered_spell_id = 71882;
  6353. break;
  6354. case POWER_RUNIC_POWER:
  6355. triggered_spell_id = 71884;
  6356. break;
  6357. default:
  6358. return false;
  6359. }
  6360. break;
  6361. }
  6362. // Item - Icecrown 25 Heroic Dagger Proc
  6363. case 71892:
  6364. {
  6365. switch(getPowerType())
  6366. {
  6367. case POWER_MANA:
  6368. triggered_spell_id = 71888;
  6369. break;
  6370. case POWER_RAGE:
  6371. triggered_spell_id = 71886;
  6372. break;
  6373. case POWER_ENERGY:
  6374. triggered_spell_id = 71887;
  6375. break;
  6376. case POWER_RUNIC_POWER:
  6377. triggered_spell_id = 71885;
  6378. break;
  6379. default:
  6380. return false;
  6381. }
  6382. break;
  6383. }
  6384. }
  6385. break;
  6386. }
  6387. case SPELLFAMILY_SHAMAN:
  6388. {
  6389. switch(dummySpell->Id)
  6390. {
  6391. /*
  6392. // Earthen Power (Rank 1, 2)
  6393. case 51523:
  6394. case 51524:
  6395. {
  6396. // Totem itself must be a caster of this spell
  6397. Unit* caster = NULL;
  6398. for(ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr) {
  6399. if((*itr)->GetEntry() != 2630)
  6400. continue;
  6401. caster = *itr;
  6402. break;
  6403. }
  6404. if(!caster)
  6405. return false;
  6406. caster->CastSpell(caster, 59566, true, castItem, triggeredByAura, originalCaster);
  6407. return true;
  6408. }
  6409. */
  6410. // Tidal Force
  6411. case 55198:
  6412. {
  6413. // Remove aura stack from caster
  6414. RemoveAuraFromStack(55166);
  6415. // drop charges
  6416. return false;
  6417. }
  6418. // Tidal Waves
  6419. if(dummySpell->SpellIconID == 3057)
  6420. {
  6421. if(!procSpell)
  6422. return false;
  6423. int32 bp0 = -(dummySpell->EffectBasePoints[0]);
  6424. int32 bp1 = dummySpell->EffectBasePoints[0];//BasePoints;
  6425. CastCustomSpell(this, 53390, &bp0, &bp1, NULL, true, 0, 0, GetGUID());
  6426. return true;
  6427. }
  6428. // Totemic Power (The Earthshatterer set)
  6429. case 28823:
  6430. {
  6431. if(!victim)
  6432. return false;
  6433. // Set class defined buff
  6434. switch(victim->getClass())
  6435. {
  6436. case CLASS_PALADIN:
  6437. case CLASS_PRIEST:
  6438. case CLASS_SHAMAN:
  6439. case CLASS_DRUID:
  6440. triggered_spell_id = 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
  6441. break;
  6442. case CLASS_MAGE:
  6443. case CLASS_WARLOCK:
  6444. triggered_spell_id = 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
  6445. break;
  6446. case CLASS_HUNTER:
  6447. case CLASS_ROGUE:
  6448. triggered_spell_id = 28826; // Increases the friendly target's attack power by $s1 for $d.
  6449. break;
  6450. case CLASS_WARRIOR:
  6451. triggered_spell_id = 28827; // Increases the friendly target's armor
  6452. break;
  6453. default:
  6454. return false;
  6455. }
  6456. break;
  6457. }
  6458. // Lesser Healing Wave (Totem of Flowing Water Relic)
  6459. case 28849:
  6460. {
  6461. target = this;
  6462. triggered_spell_id = 28850;
  6463. break;
  6464. }
  6465. // Windfury Weapon (Passive) 1-5 Ranks
  6466. case 33757:
  6467. {
  6468. Player* plr = ToPlayer();
  6469. if(!plr || !castItem || !castItem->IsEquipped() || !victim || !victim->isAlive())
  6470. return false;
  6471. // custom cooldown processing case
  6472. if(cooldown && plr->HasSpellCooldown(dummySpell->Id))
  6473. return false;
  6474. if(triggeredByAura->GetBase() && castItem->GetGUID() != triggeredByAura->GetBase()->GetCastItemGUID())
  6475. return false;
  6476. WeaponAttackType attType = WeaponAttackType(plr->GetAttackBySlot(castItem->GetSlot()));
  6477. if((attType != BASE_ATTACK && attType != OFF_ATTACK) || !isAttackReady(attType))
  6478. return false;
  6479. // Now compute real proc chance...
  6480. uint32 chance = 20;
  6481. plr->ApplySpellMod(dummySpell->Id, SPELLMOD_CHANCE_OF_SUCCESS, chance);
  6482. Item* addWeapon = plr->GetWeaponForAttack(attType == BASE_ATTACK ? OFF_ATTACK : BASE_ATTACK, true);
  6483. uint32 enchant_id_add = addWeapon ? addWeapon->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)) : 0;
  6484. SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id_add);
  6485. if(pEnchant && pEnchant->spellid[0] == dummySpell->Id)
  6486. chance += 14;
  6487. if(!roll_chance_i(chance))
  6488. return false;
  6489. // Now amount of extra power stored in 1 effect of Enchant spell
  6490. // Get it by item enchant id
  6491. uint32 spellId;
  6492. switch(castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)))
  6493. {
  6494. case 283: spellId = 8232; break; // 1 Rank
  6495. case 284: spellId = 8235; break; // 2 Rank
  6496. case 525: spellId = 10486; break; // 3 Rank
  6497. case 1669:spellId = 16362; break; // 4 Rank
  6498. case 2636:spellId = 25505; break; // 5 Rank
  6499. case 3785:spellId = 58801; break; // 6 Rank
  6500. case 3786:spellId = 58803; break; // 7 Rank
  6501. case 3787:spellId = 58804; break; // 8 Rank
  6502. default:
  6503. {
  6504. sLog->outError("Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)",
  6505. castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)), dummySpell->Id);
  6506. return false;
  6507. }
  6508. }
  6509. SpellEntry const* windfurySpellEntry = sSpellStore.LookupEntry(spellId);
  6510. if(!windfurySpellEntry)
  6511. {
  6512. sLog->outError("Unit::HandleDummyAuraProc: non existed spell id: %u (Windfury)", spellId);
  6513. return false;
  6514. }
  6515. int32 extra_attack_power = CalculateSpellDamage(victim, windfurySpellEntry, 1);
  6516. // Value gained from additional AP
  6517. basepoints0 = int32(extra_attack_power / 14.0f * GetAttackTime(BASE_ATTACK) / 1000);
  6518. triggered_spell_id = 25504;
  6519. // apply cooldown before cast to prevent processing itself
  6520. if(cooldown)
  6521. plr->AddSpellCooldown(dummySpell->Id, 0, time(NULL) + cooldown);
  6522. // Attack Twice
  6523. for(uint32 i = 0; i < 2; ++i)
  6524. CastCustomSpell(victim, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
  6525. return true;
  6526. }
  6527. // Shaman Tier 6 Trinket
  6528. case 40463:
  6529. {
  6530. if(!procSpell)
  6531. return false;
  6532. float chance;
  6533. if(procSpell->SpellFamilyFlags[0] & 0x1)
  6534. {
  6535. triggered_spell_id = 40465; // Lightning Bolt
  6536. chance = 15.0f;
  6537. }
  6538. else if(procSpell->SpellFamilyFlags[0] & 0x80)
  6539. {
  6540. triggered_spell_id = 40465; // Lesser Healing Wave
  6541. chance = 10.0f;
  6542. }
  6543. else if(procSpell->SpellFamilyFlags[1] & 0x00000010)
  6544. {
  6545. triggered_spell_id = 40466; // Stormstrike
  6546. chance = 50.0f;
  6547. }
  6548. else
  6549. return false;
  6550. if(!roll_chance_f(chance))
  6551. return false;
  6552. target = this;
  6553. break;
  6554. }
  6555. // Glyph of Healing Wave
  6556. case 55440:
  6557. {
  6558. // Not proc from self heals
  6559. if(this == victim)
  6560. return false;
  6561. basepoints0 = CalculatePctN(int32(damage), triggerAmount);
  6562. target = this;
  6563. triggered_spell_id = 55533;
  6564. break;
  6565. }
  6566. // Spirit Hunt
  6567. case 58877:
  6568. {
  6569. // Cast on owner
  6570. target = GetOwner();
  6571. if(!target)
  6572. return false;
  6573. basepoints0 = CalculatePctN(int32(damage), triggerAmount);
  6574. triggered_spell_id = 58879;
  6575. break;
  6576. }
  6577. // Shaman T8 Elemental 4P Bonus
  6578. case 64928:
  6579. {
  6580. basepoints0 = CalculatePctN(int32(damage), triggerAmount);
  6581. triggered_spell_id = 64930; // Electrified
  6582. break;
  6583. }
  6584. // Shaman T9 Elemental 4P Bonus
  6585. case 67228:
  6586. {
  6587. // Lava Burst
  6588. if(procSpell->SpellFamilyFlags[1] & 0x1000)
  6589. {
  6590. triggered_spell_id = 71824;
  6591. SpellEntry const* triggeredSpell = sSpellStore.LookupEntry(triggered_spell_id);
  6592. if(!triggeredSpell)
  6593. return false;
  6594. basepoints0 = CalculatePctN(int32(damage), triggerAmount) / (GetSpellMaxDuration(triggeredSpell) / triggeredSpell->EffectAmplitude[0]);
  6595. }
  6596. break;
  6597. }
  6598. // Item - Shaman T10 Restoration 4P Bonus
  6599. case 70808:
  6600. {
  6601. // Chain Heal
  6602. if((procSpell->SpellFamilyFlags[0] & 0x100) && (procEx & PROC_EX_CRITICAL_HIT))
  6603. {
  6604. triggered_spell_id = 70809;
  6605. SpellEntry const* triggeredSpell = sSpellStore.LookupEntry(triggered_spell_id);
  6606. if(!triggeredSpell)
  6607. return false;
  6608. basepoints0 = CalculatePctN(int32(damage), triggerAmount) / (GetSpellMaxDuration(triggeredSpell) / triggeredSpell->EffectAmplitude[0]);
  6609. }
  6610. break;
  6611. }
  6612. // Item - Shaman T10 Elemental 2P Bonus
  6613. case 70811:
  6614. {
  6615. if(!target)
  6616. return false;
  6617. // Lightning Bolt & Chain Lightning
  6618. if(procSpell->SpellFamilyFlags[0] & 0x3)
  6619. {
  6620. if(ToPlayer()->HasSpellCooldown(16166))
  6621. {
  6622. uint32 newCooldownDelay = ToPlayer()->GetSpellCooldownDelay(16166);
  6623. if(newCooldownDelay < 3)
  6624. newCooldownDelay = 0;
  6625. else
  6626. newCooldownDelay -= 2;
  6627. ToPlayer()->AddSpellCooldown(16166, 0, uint32(time(NULL) + newCooldownDelay));
  6628. WorldPacket data(SMSG_MODIFY_COOLDOWN, 4+8+4);
  6629. data << uint32(16166); // Spell ID
  6630. data << uint64(GetGUID()); // Player GUID
  6631. data << int32(-2000); // Cooldown mod in milliseconds
  6632. ToPlayer()->GetSession()->SendPacket(&data);
  6633. return true;
  6634. }
  6635. }
  6636. return false;
  6637. }
  6638. // Item - Shaman T10 Elemental 4P Bonus
  6639. case 70817:
  6640. {
  6641. if(!target)
  6642. return false;
  6643. // try to find spell Flame Shock on the target
  6644. if(AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0x0, 0x0, GetGUID()))
  6645. {
  6646. Aura* flameShock = aurEff->GetBase();
  6647. int32 maxDuration = flameShock->GetMaxDuration();
  6648. int32 newDuration = flameShock->GetDuration() + 2 * aurEff->GetAmplitude();
  6649. flameShock->SetDuration(newDuration);
  6650. // is it blizzlike to change max duration for FS?
  6651. if(newDuration > maxDuration)
  6652. flameShock->SetMaxDuration(newDuration);
  6653. return true;
  6654. }
  6655. // if not found Flame Shock
  6656. return false;
  6657. }
  6658. case 63280: // Glyph of Totem of Wrath
  6659. {
  6660. if(procSpell->SpellIconID != 2019)
  6661. return false;
  6662. AuraEffect* aurEffA = NULL;
  6663. AuraEffectList const& auras = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE);
  6664. for(AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
  6665. {
  6666. SpellEntry const* spell = (*i)->GetSpellProto();
  6667. if(spell->SpellFamilyName == uint32(SPELLFAMILY_SHAMAN) && spell->SpellFamilyFlags.HasFlag(0, 0x02000000, 0))
  6668. {
  6669. if((*i)->GetCasterGUID() != GetGUID())
  6670. continue;
  6671. if(spell->Id == 63283)
  6672. continue;
  6673. aurEffA = (*i);
  6674. break;
  6675. }
  6676. }
  6677. if(aurEffA)
  6678. {
  6679. int32 bp0 = 0, bp1 = 0;
  6680. bp0 = CalculatePctN(triggerAmount, aurEffA->GetAmount());
  6681. if(AuraEffect* aurEffB = aurEffA->GetBase()->GetEffect(EFFECT_1))
  6682. bp1 = CalculatePctN(triggerAmount, aurEffB->GetAmount());
  6683. CastCustomSpell(this, 63283, &bp0, &bp1, NULL, true, NULL, triggeredByAura);
  6684. return true;
  6685. }
  6686. return false;
  6687. }
  6688. break;
  6689. }
  6690. // Frozen Power
  6691. if(dummySpell->SpellIconID == 3780)
  6692. {
  6693. if(!target)
  6694. return false;
  6695. if(GetDistance(target) < 15.0f)
  6696. return false;
  6697. float chance = (float)triggerAmount;
  6698. if(!roll_chance_f(chance))
  6699. return false;
  6700. triggered_spell_id = 63685;
  6701. break;
  6702. }
  6703. // Storm, Earth and Fire
  6704. if(dummySpell->SpellIconID == 3063)
  6705. {
  6706. // Earthbind Totem summon only
  6707. if(procSpell->Id != 2484)
  6708. return false;
  6709. float chance = (float)triggerAmount;
  6710. if(!roll_chance_f(chance))
  6711. return false;
  6712. triggered_spell_id = 64695;
  6713. break;
  6714. }
  6715. // Ancestral Awakening
  6716. if(dummySpell->SpellIconID == 3065)
  6717. {
  6718. triggered_spell_id = 52759;
  6719. basepoints0 = CalculatePctN(int32(damage), triggerAmount);
  6720. target = this;
  6721. break;
  6722. }
  6723. // Earth Shield
  6724. if(dummySpell->SpellFamilyFlags[1] & 0x00000400)
  6725. {
  6726. // 3.0.8: Now correctly uses the Shaman's own spell critical strike chance to determine the chance of a critical heal.
  6727. originalCaster = triggeredByAura->GetCasterGUID();
  6728. target = this;
  6729. basepoints0 = triggerAmount;
  6730. // Glyph of Earth Shield
  6731. if(AuraEffect* aur = GetAuraEffect(63279, 0))
  6732. AddPctN(basepoints0, aur->GetAmount());
  6733. triggered_spell_id = 379;
  6734. break;
  6735. }
  6736. // Flametongue Weapon (Passive)
  6737. if(dummySpell->SpellFamilyFlags[0] & 0x200000)
  6738. {
  6739. if(GetTypeId() != TYPEID_PLAYER || !victim || !victim->isAlive() || !castItem || !castItem->IsEquipped())
  6740. return false;
  6741. float fire_onhit = float(CalculatePctF(SpellMgr::CalculateSpellEffectAmount(dummySpell, 0), 1.0f));
  6742. float add_spellpower = (float)(SpellBaseDamageBonus(SPELL_SCHOOL_MASK_FIRE)
  6743. + SpellBaseDamageBonusForVictim(SPELL_SCHOOL_MASK_FIRE, victim));
  6744. // 1.3speed = 5%, 2.6speed = 10%, 4.0 speed = 15%, so, 1.0speed = 3.84%
  6745. ApplyPctF(add_spellpower, 3.84f);
  6746. // Enchant on Off-Hand and ready?
  6747. if(castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND && isAttackReady(OFF_ATTACK))
  6748. {
  6749. float BaseWeaponSpeed = GetAttackTime(OFF_ATTACK) / 1000.0f;
  6750. // Value1: add the tooltip damage by swingspeed + Value2: add spelldmg by swingspeed
  6751. basepoints0 = int32((fire_onhit * BaseWeaponSpeed) + (add_spellpower * BaseWeaponSpeed));
  6752. triggered_spell_id = 10444;
  6753. }
  6754. // Enchant on Main-Hand and ready?
  6755. else if(castItem->GetSlot() == EQUIPMENT_SLOT_MAINHAND && isAttackReady(BASE_ATTACK))
  6756. {
  6757. float BaseWeaponSpeed = GetAttackTime(BASE_ATTACK) / 1000.0f;
  6758. // Value1: add the tooltip damage by swingspeed + Value2: add spelldmg by swingspeed
  6759. basepoints0 = int32((fire_onhit * BaseWeaponSpeed) + (add_spellpower * BaseWeaponSpeed));
  6760. triggered_spell_id = 10444;
  6761. }
  6762. // If not ready, we should return, shouldn't we?!
  6763. else
  6764. return false;
  6765. CastCustomSpell(victim, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
  6766. return true;
  6767. }
  6768. // Improved Water Shield
  6769. if(dummySpell->SpellIconID == 2287)
  6770. {
  6771. // Default chance for Healing Wave and Riptide
  6772. float chance = (float)triggeredByAura->GetAmount();
  6773. if(procSpell->SpellFamilyFlags[0] & 0x80)
  6774. // Lesser Healing Wave - 0.6 of default
  6775. chance *= 0.6f;
  6776. else if(procSpell->SpellFamilyFlags[0] & 0x100)
  6777. // Chain heal - 0.3 of default
  6778. chance *= 0.3f;
  6779. if(!roll_chance_f(chance))
  6780. return false;
  6781. // Water Shield
  6782. if(AuraEffect const* aurEff = GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0, 0x00000020, 0))
  6783. {
  6784. uint32 spell = aurEff->GetSpellProto()->EffectTriggerSpell[aurEff->GetEffIndex()];
  6785. CastSpell(this, spell, true, castItem, triggeredByAura);
  6786. return true;
  6787. }
  6788. return false;
  6789. }
  6790. // Lightning Overload
  6791. if(dummySpell->SpellIconID == 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura
  6792. {
  6793. if(!procSpell || GetTypeId() != TYPEID_PLAYER || !victim)
  6794. return false;
  6795. // custom cooldown processing case
  6796. if(cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(dummySpell->Id))
  6797. return false;
  6798. uint32 spellId = 0;
  6799. // Every Lightning Bolt and Chain Lightning spell have duplicate vs half damage and zero cost
  6800. switch(procSpell->Id)
  6801. {
  6802. // Lightning Bolt
  6803. case 403: spellId = 45284; break; // Rank 1
  6804. case 529: spellId = 45286; break; // Rank 2
  6805. case 548: spellId = 45287; break; // Rank 3
  6806. case 915: spellId = 45288; break; // Rank 4
  6807. case 943: spellId = 45289; break; // Rank 5
  6808. case 6041: spellId = 45290; break; // Rank 6
  6809. case 10391: spellId = 45291; break; // Rank 7
  6810. case 10392: spellId = 45292; break; // Rank 8
  6811. case 15207: spellId = 45293; break; // Rank 9
  6812. case 15208: spellId = 45294; break; // Rank 10
  6813. case 25448: spellId = 45295; break; // Rank 11
  6814. case 25449: spellId = 45296; break; // Rank 12
  6815. case 49237: spellId = 49239; break; // Rank 13
  6816. case 49238: spellId = 49240; break; // Rank 14
  6817. // Chain Lightning
  6818. case 421: spellId = 45297; break; // Rank 1
  6819. case 930: spellId = 45298; break; // Rank 2
  6820. case 2860: spellId = 45299; break; // Rank 3
  6821. case 10605: spellId = 45300; break; // Rank 4
  6822. case 25439: spellId = 45301; break; // Rank 5
  6823. case 25442: spellId = 45302; break; // Rank 6
  6824. case 49270: spellId = 49268; break; // Rank 7
  6825. case 49271: spellId = 49269; break; // Rank 8
  6826. default:
  6827. sLog->outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell->Id);
  6828. return false;
  6829. }
  6830. // Chain Lightning
  6831. if(procSpell->SpellFamilyFlags[0] & 0x2)
  6832. {
  6833. // Chain lightning has [LightOverload_Proc_Chance] / [Max_Number_of_Targets] chance to proc of each individual target hit.
  6834. // A maxed LO would have a 33% / 3 = 11% chance to proc of each target.
  6835. // LO chance was already "accounted" at the proc chance roll, now need to divide the chance by [Max_Number_of_Targets]
  6836. float chance = 100.0f / procSpell->EffectChainTarget[effIndex];
  6837. if(!roll_chance_f(chance))
  6838. return false;
  6839. // Remove cooldown (Chain Lightning - have Category Recovery time)
  6840. ToPlayer()->RemoveSpellCooldown(spellId);
  6841. }
  6842. CastSpell(victim, spellId, true, castItem, triggeredByAura);
  6843. if(cooldown && GetTypeId() == TYPEID_PLAYER)
  6844. ToPlayer()->AddSpellCooldown(dummySpell->Id, 0, time(NULL) + cooldown);
  6845. return true;
  6846. }
  6847. // Static Shock
  6848. if(dummySpell->SpellIconID == 3059)
  6849. {
  6850. // Lightning Shield
  6851. if(AuraEffect const* aurEff = GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x400, 0, 0))
  6852. {
  6853. uint32 spell = sSpellMgr->GetSpellWithRank(26364, sSpellMgr->GetSpellRank(aurEff->GetId()));
  6854. // custom cooldown processing case
  6855. if(GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(spell))
  6856. ToPlayer()->RemoveSpellCooldown(spell);
  6857. CastSpell(target, spell, true, castItem, triggeredByAura);
  6858. aurEff->GetBase()->DropCharge();
  6859. return true;
  6860. }
  6861. return false;
  6862. }
  6863. break;
  6864. }
  6865. case SPELLFAMILY_DEATHKNIGHT:
  6866. {
  6867. // Blood-Caked Strike - Blood-Caked Blade
  6868. if(dummySpell->SpellIconID == 138)
  6869. {
  6870. if(!target || !target->isAlive())
  6871. return false;
  6872. triggered_spell_id = dummySpell->EffectTriggerSpell[effIndex];
  6873. break;
  6874. }
  6875. // Improved Blood Presence
  6876. if(dummySpell->SpellIconID == 2636)
  6877. {
  6878. if(GetTypeId() != TYPEID_PLAYER)
  6879. return false;
  6880. basepoints0 = CalculatePctN(int32(damage), triggerAmount);
  6881. break;
  6882. }
  6883. // Butchery
  6884. if(dummySpell->SpellIconID == 2664)
  6885. {
  6886. basepoints0 = triggerAmount;
  6887. triggered_spell_id = 50163;
  6888. target = this;
  6889. break;
  6890. }
  6891. // Dancing Rune Weapon
  6892. if(dummySpell->Id == 49028)
  6893. {
  6894. // 1 dummy aura for dismiss rune blade
  6895. if(effIndex != 1)
  6896. return false;
  6897. Unit* pPet = NULL;
  6898. for(ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr) // Find Rune Weapon
  6899. if((*itr)->GetEntry() == 27893)
  6900. {
  6901. pPet = *itr;
  6902. break;
  6903. }
  6904. if(pPet && pPet->getVictim() && damage && procSpell)
  6905. {
  6906. uint32 procDmg = damage / 2;
  6907. pPet->SendSpellNonMeleeDamageLog(pPet->getVictim(), procSpell->Id, procDmg, GetSpellSchoolMask(procSpell), 0, 0, false, 0, false);
  6908. pPet->DealDamage(pPet->getVictim(), procDmg, NULL, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(procSpell), procSpell, true);
  6909. break;
  6910. }
  6911. else
  6912. return false;
  6913. }
  6914. // Mark of Blood
  6915. if(dummySpell->Id == 49005)
  6916. {
  6917. /* if(!target || target->GetTypeId() != TYPEID_PLAYER)
  6918. return false;
  6919. */
  6920. // TODO: need more info (cooldowns/PPM)
  6921. triggered_spell_id = 61607;
  6922. break;
  6923. }
  6924. // Unholy Blight
  6925. if(dummySpell->Id == 49194)
  6926. {
  6927. basepoints0 = CalculatePctN(int32(damage), triggerAmount);
  6928. // Glyph of Unholy Blight
  6929. if(AuraEffect* glyph=GetAuraEffect(63332, 0))
  6930. AddPctN(basepoints0, glyph->GetAmount());
  6931. triggered_spell_id = 50536;
  6932. basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE);
  6933. break;
  6934. }
  6935. // Vendetta
  6936. if(dummySpell->SpellFamilyFlags[0] & 0x10000)
  6937. {
  6938. basepoints0 = int32(CountPctFromMaxHealth(triggerAmount));
  6939. triggered_spell_id = 50181;
  6940. target = this;
  6941. break;
  6942. }
  6943. // Necrosis
  6944. if(dummySpell->SpellIconID == 2709)
  6945. {
  6946. basepoints0 = CalculatePctN(int32(damage), triggerAmount);
  6947. triggered_spell_id = 51460;
  6948. break;
  6949. }
  6950. // Threat of Thassarian
  6951. if(dummySpell->SpellIconID == 2023)
  6952. {
  6953. // Must Dual Wield
  6954. if(!procSpell || !haveOffhandWeapon())
  6955. return false;
  6956. switch(procSpell->Id)
  6957. {
  6958. // Obliterate
  6959. case 49020: triggered_spell_id = 66198; break; // Rank 1
  6960. case 51423: triggered_spell_id = 66972; break; // Rank 2
  6961. case 51424: triggered_spell_id = 66973; break; // Rank 3
  6962. case 51425: triggered_spell_id = 66974; break; // Rank 4
  6963. // Frost Strike
  6964. case 49143: triggered_spell_id = 66196; break; // Rank 1
  6965. case 51416: triggered_spell_id = 66958; break; // Rank 2
  6966. case 51417: triggered_spell_id = 66959; break; // Rank 3
  6967. case 51418: triggered_spell_id = 66960; break; // Rank 4
  6968. case 51419: triggered_spell_id = 66961; break; // Rank 5
  6969. case 55268: triggered_spell_id = 66962; break; // Rank 6
  6970. // Plague Strike
  6971. case 45462: triggered_spell_id = 66216; break; // Rank 1
  6972. case 49917: triggered_spell_id = 66988; break; // Rank 2
  6973. case 49918: triggered_spell_id = 66989; break; // Rank 3
  6974. case 49919: triggered_spell_id = 66990; break; // Rank 4
  6975. case 49920: triggered_spell_id = 66991; break; // Rank 5
  6976. case 49921: triggered_spell_id = 66992; break; // Rank 6
  6977. // Death Strike
  6978. case 49998: triggered_spell_id = 66188; break; // Rank 1
  6979. case 49999: triggered_spell_id = 66950; break; // Rank 2
  6980. case 45463: triggered_spell_id = 66951; break; // Rank 3
  6981. case 49923: triggered_spell_id = 66952; break; // Rank 4
  6982. case 49924: triggered_spell_id = 66953; break; // Rank 5
  6983. // Rune Strike
  6984. case 56815: triggered_spell_id = 66217; break; // Rank 1
  6985. // Blood Strike
  6986. case 45902: triggered_spell_id = 66215; break; // Rank 1
  6987. case 49926: triggered_spell_id = 66975; break; // Rank 2
  6988. case 49927: triggered_spell_id = 66976; break; // Rank 3
  6989. case 49928: triggered_spell_id = 66977; break; // Rank 4
  6990. case 49929: triggered_spell_id = 66978; break; // Rank 5
  6991. case 49930: triggered_spell_id = 66979; break; // Rank 6
  6992. default:
  6993. return false;
  6994. }
  6995. break;
  6996. }
  6997. // Runic Power Back on Snare/Root
  6998. if(dummySpell->Id == 61257)
  6999. {
  7000. // only for spells and hit/crit (trigger start always) and not start from self casted spells
  7001. if(procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == victim)
  7002. return false;
  7003. // Need snare or root mechanic
  7004. if(!(GetAllSpellMechanicMask(procSpell) & ((1<<MECHANIC_ROOT)|(1<<MECHANIC_SNARE))))
  7005. return false;
  7006. triggered_spell_id = 61258;
  7007. target = this;
  7008. break;
  7009. }
  7010. // Wandering Plague
  7011. if(dummySpell->SpellIconID == 1614)
  7012. {
  7013. if(!roll_chance_f(GetUnitCriticalChance(BASE_ATTACK, victim)))
  7014. return false;
  7015. basepoints0 = CalculatePctN(int32(damage), triggerAmount);
  7016. triggered_spell_id = 50526;
  7017. break;
  7018. }
  7019. // Sudden Doom
  7020. if(dummySpell->SpellIconID == 1939 && GetTypeId() == TYPEID_PLAYER)
  7021. {
  7022. SpellChainNode const* chain = NULL;
  7023. // get highest rank of the Death Coil spell
  7024. PlayerSpellMap const& sp_list = ToPlayer()->GetSpellMap();
  7025. for(PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
  7026. {
  7027. // check if shown in spell book
  7028. if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
  7029. continue;
  7030. SpellEntry const* spellProto = sSpellStore.LookupEntry(itr->first);
  7031. if(!spellProto)
  7032. continue;
  7033. if(spellProto->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT
  7034. && spellProto->SpellFamilyFlags[0] & 0x2000)
  7035. {
  7036. SpellChainNode const* newChain = sSpellMgr->GetSpellChainNode(itr->first);
  7037. // No chain entry or entry lower than found entry
  7038. if(!chain || !newChain || (chain->rank < newChain->rank))
  7039. {
  7040. triggered_spell_id = itr->first;
  7041. chain = newChain;
  7042. }
  7043. else
  7044. continue;
  7045. // Found spell is last in chain - do not need to look more
  7046. // Optimisation for most common case
  7047. if(chain && chain->last == itr->first)
  7048. break;
  7049. }
  7050. }
  7051. }
  7052. // Item - Death Knight T10 Melee 4P Bonus
  7053. if(dummySpell->Id == 70656)
  7054. {
  7055. Player* player = ToPlayer();
  7056. if(!player)
  7057. return false;
  7058. for(uint32 i = 0; i < MAX_RUNES; ++i)
  7059. if(player->GetRuneCooldown(i) == 0)
  7060. return false;
  7061. }
  7062. break;
  7063. }
  7064. case SPELLFAMILY_POTION:
  7065. {
  7066. // alchemist's stone
  7067. if(dummySpell->Id == 17619)
  7068. {
  7069. if(procSpell->SpellFamilyName == SPELLFAMILY_POTION)
  7070. {
  7071. for(uint8 i = 0; i < MAX_SPELL_EFFECTS; i++)
  7072. {
  7073. if(procSpell->Effect[i] == SPELL_EFFECT_HEAL)
  7074. {
  7075. triggered_spell_id = 21399;
  7076. }
  7077. else if(procSpell->Effect[i] == SPELL_EFFECT_ENERGIZE)
  7078. {
  7079. triggered_spell_id = 21400;
  7080. }
  7081. else
  7082. continue;
  7083. basepoints0 = int32(CalculateSpellDamage(this, procSpell, i) * 0.4f);
  7084. CastCustomSpell(this, triggered_spell_id, &basepoints0, NULL, NULL, true, NULL, triggeredByAura);
  7085. }
  7086. return true;
  7087. }
  7088. }
  7089. break;
  7090. }
  7091. case SPELLFAMILY_PET:
  7092. {
  7093. switch(dummySpell->SpellIconID)
  7094. {
  7095. // Guard Dog
  7096. case 201:
  7097. {
  7098. if(!victim)
  7099. return false;
  7100. triggered_spell_id = 54445;
  7101. target = this;
  7102. float addThreat = float(CalculatePctN(SpellMgr::CalculateSpellEffectAmount(procSpell, 0, this), triggerAmount));
  7103. victim->AddThreat(this, addThreat);
  7104. break;
  7105. }
  7106. // Silverback
  7107. case 1582:
  7108. triggered_spell_id = dummySpell->Id == 62765 ? 62801 : 62800;
  7109. target = this;
  7110. break;
  7111. }
  7112. break;
  7113. }
  7114. default:
  7115. break;
  7116. }
  7117. // if not handled by custom case, get triggered spell from dummySpell proto
  7118. if(!triggered_spell_id)
  7119. triggered_spell_id = dummySpell->EffectTriggerSpell[triggeredByAura->GetEffIndex()];
  7120. // processed charge only counting case
  7121. if(!triggered_spell_id)
  7122. return true;
  7123. SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
  7124. if(!triggerEntry)
  7125. {
  7126. sLog->outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u", dummySpell->Id, triggered_spell_id);
  7127. return false;
  7128. }
  7129. // default case
  7130. if((!target && !sSpellMgr->IsSrcTargetSpell(triggerEntry)) || (target && target != this && !target->isAlive()))
  7131. return false;
  7132. if(cooldown_spell_id == 0)
  7133. cooldown_spell_id = triggered_spell_id;
  7134. if(cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(cooldown_spell_id))
  7135. return false;
  7136. if(basepoints0)
  7137. CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura, originalCaster);
  7138. else
  7139. CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura, originalCaster);
  7140. if(cooldown && GetTypeId() == TYPEID_PLAYER)
  7141. ToPlayer()->AddSpellCooldown(cooldown_spell_id, 0, time(NULL) + cooldown);
  7142. return true;
  7143. }
  7144. bool Unit::HandleObsModEnergyAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellEntry const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
  7145. {
  7146. SpellEntry const* dummySpell = triggeredByAura->GetSpellProto();
  7147. //uint32 effIndex = triggeredByAura->GetEffIndex();
  7148. //int32 triggerAmount = triggeredByAura->GetAmount();
  7149. Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
  7150. ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
  7151. uint32 triggered_spell_id = 0;
  7152. Unit* target = victim;
  7153. int32 basepoints0 = 0;
  7154. switch(dummySpell->SpellFamilyName)
  7155. {
  7156. case SPELLFAMILY_HUNTER:
  7157. {
  7158. // Aspect of the Viper
  7159. if(dummySpell->SpellFamilyFlags[1] & 0x40000)
  7160. {
  7161. uint32 maxmana = GetMaxPower(POWER_MANA);
  7162. basepoints0 = CalculatePctF(maxmana, GetAttackTime(RANGED_ATTACK) / 1000.0f);
  7163. target = this;
  7164. triggered_spell_id = 34075;
  7165. break;
  7166. }
  7167. break;
  7168. }
  7169. }
  7170. // processed charge only counting case
  7171. if(!triggered_spell_id)
  7172. return true;
  7173. SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
  7174. // Try handle unknown trigger spells
  7175. if(!triggerEntry)
  7176. {
  7177. sLog->outError("Unit::HandleObsModEnergyAuraProc: Spell %u have not existed triggered spell %u", dummySpell->Id, triggered_spell_id);
  7178. return false;
  7179. }
  7180. // default case
  7181. if((!target && !sSpellMgr->IsSrcTargetSpell(triggerEntry)) || (target && target != this && !target->isAlive()))
  7182. return false;
  7183. if(cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
  7184. return false;
  7185. if(basepoints0)
  7186. CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
  7187. else
  7188. CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura);
  7189. if(cooldown && GetTypeId() == TYPEID_PLAYER)
  7190. ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
  7191. return true;
  7192. }
  7193. bool Unit::HandleModDamagePctTakenAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellEntry const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
  7194. {
  7195. SpellEntry const* dummySpell = triggeredByAura->GetSpellProto();
  7196. //uint32 effIndex = triggeredByAura->GetEffIndex();
  7197. //int32 triggerAmount = triggeredByAura->GetAmount();
  7198. Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
  7199. ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
  7200. uint32 triggered_spell_id = 0;
  7201. Unit* target = victim;
  7202. int32 basepoints0 = 0;
  7203. switch(dummySpell->SpellFamilyName)
  7204. {
  7205. case SPELLFAMILY_PALADIN:
  7206. {
  7207. // Blessing of Sanctuary
  7208. if(dummySpell->SpellFamilyFlags[0] & 0x10000000)
  7209. {
  7210. switch(getPowerType())
  7211. {
  7212. case POWER_MANA: triggered_spell_id = 57319; break;
  7213. default:
  7214. return false;
  7215. }
  7216. }
  7217. break;
  7218. }
  7219. case SPELLFAMILY_WARRIOR:
  7220. {
  7221. // Recklessness - prevent double proc
  7222. if(dummySpell->Id == 1719)
  7223. return false;
  7224. break;
  7225. }
  7226. }
  7227. // processed charge only counting case
  7228. if(!triggered_spell_id)
  7229. return true;
  7230. SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
  7231. if(!triggerEntry)
  7232. {
  7233. sLog->outError("Unit::HandleModDamagePctTakenAuraProc: Spell %u have not existed triggered spell %u", dummySpell->Id, triggered_spell_id);
  7234. return false;
  7235. }
  7236. // default case
  7237. if((!target && !sSpellMgr->IsSrcTargetSpell(triggerEntry)) || (target && target != this && !target->isAlive()))
  7238. return false;
  7239. if(cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
  7240. return false;
  7241. if(basepoints0)
  7242. CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
  7243. else
  7244. CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura);
  7245. if(cooldown && GetTypeId() == TYPEID_PLAYER)
  7246. ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
  7247. return true;
  7248. }
  7249. // Used in case when access to whole aura is needed
  7250. // All procs should be handled like this...
  7251. bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellEntry const* procSpell, uint32 /*procFlag*/, uint32 procEx, uint32 cooldown, bool * handled)
  7252. {
  7253. SpellEntry const* dummySpell = triggeredByAura->GetSpellProto();
  7254. switch(dummySpell->SpellFamilyName)
  7255. {
  7256. case SPELLFAMILY_GENERIC:
  7257. switch(dummySpell->Id)
  7258. {
  7259. // Nevermelting Ice Crystal
  7260. case 71564:
  7261. RemoveAuraFromStack(71564);
  7262. *handled = true;
  7263. break;
  7264. case 71756:
  7265. case 72782:
  7266. case 72783:
  7267. case 72784:
  7268. RemoveAuraFromStack(dummySpell->Id);
  7269. *handled = true;
  7270. break;
  7271. // Discerning Eye of the Beast
  7272. case 59915:
  7273. {
  7274. CastSpell(this, 59914, true); // 59914 already has correct basepoints in DBC, no need for custom bp
  7275. *handled = true;
  7276. break;
  7277. }
  7278. // Swift Hand of Justice
  7279. case 59906:
  7280. {
  7281. int32 bp0 = CalculatePctN(GetMaxHealth(), SpellMgr::CalculateSpellEffectAmount(dummySpell, 0));
  7282. CastCustomSpell(this, 59913, &bp0, NULL, NULL, true);
  7283. *handled = true;
  7284. break;
  7285. }
  7286. // Vigilance - original proc picking wrong target
  7287. case 50720:
  7288. {
  7289. *handled = true;
  7290. if(Unit* caster = triggeredByAura->GetCaster())
  7291. {
  7292. CastSpell(caster, 50725, true);
  7293. return true;
  7294. }
  7295. return false;
  7296. }
  7297. }
  7298. break;
  7299. case SPELLFAMILY_PALADIN:
  7300. {
  7301. // Infusion of Light
  7302. if(dummySpell->SpellIconID == 3021)
  7303. {
  7304. // Flash of Light HoT on Flash of Light when Sacred Shield active
  7305. if(procSpell->SpellFamilyFlags[0] & 0x40000000 && procSpell->SpellIconID == 242)
  7306. {
  7307. *handled = true;
  7308. if (victim && victim->HasAura(53601))
  7309. {
  7310. int32 bp0 = CalculatePctN(int32(damage / 12), SpellMgr::CalculateSpellEffectAmount(dummySpell, 2));
  7311. // Item - Paladin T9 Holy 4P Bonus
  7312. if(AuraEffect const* aurEff = GetAuraEffect(67191, 0))
  7313. AddPctN(bp0, aurEff->GetAmount());
  7314. CastCustomSpell(victim, 66922, &bp0, NULL, NULL, true);
  7315. return true;
  7316. }
  7317. }
  7318. // but should not proc on non-critical Holy Shocks
  7319. else if((procSpell->SpellFamilyFlags[0] & 0x200000 || procSpell->SpellFamilyFlags[1] & 0x10000) && !(procEx & PROC_EX_CRITICAL_HIT))
  7320. *handled = true;
  7321. break;
  7322. }
  7323. // Judgements of the Just
  7324. else if(dummySpell->SpellIconID == 3015)
  7325. {
  7326. *handled = true;
  7327. CastSpell(victim, 68055, true);
  7328. return true;
  7329. }
  7330. // Glyph of Divinity
  7331. else if(dummySpell->Id == 54939)
  7332. {
  7333. *handled = true;
  7334. // Check if we are the target and prevent mana gain
  7335. if(triggeredByAura->GetCasterGUID() == victim->GetGUID())
  7336. return false;
  7337. // Lookup base amount mana restore
  7338. for(uint8 i = 0; i<MAX_SPELL_EFFECTS; i++)
  7339. {
  7340. if(procSpell->Effect[i] == SPELL_EFFECT_ENERGIZE)
  7341. {
  7342. // value multiplied by 2 because you should get twice amount
  7343. int32 mana = SpellMgr::CalculateSpellEffectAmount(procSpell, i) * 2;
  7344. CastCustomSpell(this, 54986, 0, &mana, NULL, true);
  7345. }
  7346. }
  7347. return true;
  7348. }
  7349. break;
  7350. }
  7351. case SPELLFAMILY_SHAMAN:
  7352. {
  7353. switch(dummySpell->Id)
  7354. {
  7355. case 8178: // Grounding Totem
  7356. {
  7357. *handled = true;
  7358. break;
  7359. }
  7360. }
  7361. break;
  7362. }
  7363. case SPELLFAMILY_MAGE:
  7364. {
  7365. // Combustion
  7366. switch(dummySpell->Id)
  7367. {
  7368. case 11129:
  7369. {
  7370. if(Aura* aura = GetAura(28682))
  7371. {
  7372. if(aura->GetStackAmount() == 10)
  7373. {
  7374. RemoveAurasDueToSpell(11129);
  7375. return false;
  7376. }
  7377. }
  7378. *handled = true;
  7379. Unit* pCaster = triggeredByAura->GetCaster();
  7380. if(!pCaster || !damage)
  7381. return false;
  7382. // last charge and crit
  7383. if(triggeredByAura->GetCharges() <= 1 && (procEx & PROC_EX_CRITICAL_HIT))
  7384. return true; // charge counting (will removed)
  7385. CastSpell(this, 28682, true);
  7386. return (procEx & PROC_EX_CRITICAL_HIT) ? true : false;
  7387. }
  7388. // Empowered Fire
  7389. case 31656:
  7390. case 31657:
  7391. case 31658:
  7392. {
  7393. *handled = true;
  7394. SpellEntry const* spInfo = sSpellStore.LookupEntry(67545);
  7395. if(!spInfo)
  7396. return false;
  7397. int32 bp0 = int32(CalculatePctN(GetCreateMana(), SpellMgr::CalculateSpellEffectAmount(spInfo, 0)));
  7398. CastCustomSpell(this, 67545, &bp0, NULL, NULL, true, NULL, triggeredByAura->GetEffect(EFFECT_0), GetGUID());
  7399. return true;
  7400. }
  7401. }
  7402. break;
  7403. }
  7404. case SPELLFAMILY_ROGUE:
  7405. {
  7406. // prevent proc of Savage Combat
  7407. if(dummySpell->SpellIconID == 1959)
  7408. *handled = true;
  7409. break;
  7410. }
  7411. case SPELLFAMILY_DEATHKNIGHT:
  7412. {
  7413. // Blood of the North
  7414. // Reaping
  7415. // Death Rune Mastery
  7416. if(dummySpell->SpellIconID == 3041 || dummySpell->SpellIconID == 22 || dummySpell->SpellIconID == 2622)
  7417. {
  7418. *handled = true;
  7419. // Convert recently used Blood Rune to Death Rune
  7420. if(Player* plr = ToPlayer())
  7421. {
  7422. if(!plr || plr->getClass() != CLASS_DEATH_KNIGHT)
  7423. return false;
  7424. RuneType rune = ToPlayer()->GetLastUsedRune();
  7425. // can't proc from death rune use
  7426. if(rune == RUNE_DEATH)
  7427. return false;
  7428. AuraEffect* aurEff = triggeredByAura->GetEffect(EFFECT_0);
  7429. if(!aurEff)
  7430. return false;
  7431. // Reset amplitude - set death rune remove timer to 30s
  7432. aurEff->ResetPeriodic(true);
  7433. uint32 runesLeft;
  7434. if(dummySpell->SpellIconID == 2622)
  7435. runesLeft = 2;
  7436. else
  7437. runesLeft = 1;
  7438. for(uint8 i = 0; i < MAX_RUNES && runesLeft; ++i)
  7439. {
  7440. if(dummySpell->SpellIconID == 2622)
  7441. {
  7442. if(plr->GetCurrentRune(i) == RUNE_DEATH ||
  7443. plr->GetBaseRune(i) == RUNE_BLOOD)
  7444. continue;
  7445. }
  7446. else
  7447. {
  7448. if(plr->GetCurrentRune(i) == RUNE_DEATH ||
  7449. plr->GetBaseRune(i) != RUNE_BLOOD)
  7450. continue;
  7451. }
  7452. if(plr->GetRuneCooldown(i) != plr->GetRuneBaseCooldown(i))
  7453. continue;
  7454. --runesLeft;
  7455. // Mark aura as used
  7456. plr->AddRuneByAuraEffect(i, RUNE_DEATH, aurEff);
  7457. }
  7458. return true;
  7459. }
  7460. return false;
  7461. }
  7462. switch(dummySpell->Id)
  7463. {
  7464. // Bone Shield cooldown
  7465. case 49222:
  7466. {
  7467. *handled = true;
  7468. if(cooldown && GetTypeId() == TYPEID_PLAYER)
  7469. {
  7470. if(ToPlayer()->HasSpellCooldown(100000))
  7471. return false;
  7472. ToPlayer()->AddSpellCooldown(100000, 0, time(NULL) + cooldown);
  7473. }
  7474. return true;
  7475. }
  7476. // Hungering Cold aura drop
  7477. case 51209:
  7478. *handled = true;
  7479. // Drop only in not disease case
  7480. if(procSpell && procSpell->Dispel == DISPEL_DISEASE)
  7481. return false;
  7482. return true;
  7483. }
  7484. break;
  7485. }
  7486. case SPELLFAMILY_WARRIOR:
  7487. {
  7488. switch(dummySpell->Id)
  7489. {
  7490. // Item - Warrior T10 Protection 4P Bonus
  7491. case 70844:
  7492. {
  7493. int32 basepoints0 = CalculatePctN(GetMaxHealth(), SpellMgr::CalculateSpellEffectAmount(dummySpell, 1));
  7494. CastCustomSpell(this, 70845, &basepoints0, NULL, NULL, true);
  7495. break;
  7496. }
  7497. }
  7498. }
  7499. }
  7500. return false;
  7501. }
  7502. bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const* procSpell, uint32 procFlags, uint32 procEx, uint32 cooldown)
  7503. {
  7504. // Get triggered aura spell info
  7505. SpellEntry const* auraSpellInfo = triggeredByAura->GetSpellProto();
  7506. // Basepoints of trigger aura
  7507. int32 triggerAmount = triggeredByAura->GetAmount();
  7508. // Set trigger spell id, target, custom basepoints
  7509. uint32 trigger_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()];
  7510. Unit* target = NULL;
  7511. int32 basepoints0 = 0;
  7512. if(triggeredByAura->GetAuraType() == SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE)
  7513. basepoints0 = triggerAmount;
  7514. Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
  7515. ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
  7516. // Try handle unknown trigger spells
  7517. if(sSpellStore.LookupEntry(trigger_spell_id) == NULL)
  7518. {
  7519. switch(auraSpellInfo->SpellFamilyName)
  7520. {
  7521. case SPELLFAMILY_GENERIC:
  7522. switch(auraSpellInfo->Id)
  7523. {
  7524. case 23780: // Aegis of Preservation (Aegis of Preservation trinket)
  7525. trigger_spell_id = 23781;
  7526. break;
  7527. case 33896: // Desperate Defense (Stonescythe Whelp, Stonescythe Alpha, Stonescythe Ambusher)
  7528. trigger_spell_id = 33898;
  7529. break;
  7530. case 43820: // Charm of the Witch Doctor (Amani Charm of the Witch Doctor trinket)
  7531. // Pct value stored in dummy
  7532. basepoints0 = victim->GetCreateHealth() * SpellMgr::CalculateSpellEffectAmount(auraSpellInfo, 1) / 100;
  7533. target = victim;
  7534. break;
  7535. case 57345: // Darkmoon Card: Greatness
  7536. {
  7537. float stat = 0.0f;
  7538. // strength
  7539. if(GetStat(STAT_STRENGTH) > stat) { trigger_spell_id = 60229; stat = GetStat(STAT_STRENGTH); }
  7540. // agility
  7541. if(GetStat(STAT_AGILITY) > stat) { trigger_spell_id = 60233; stat = GetStat(STAT_AGILITY); }
  7542. // intellect
  7543. if(GetStat(STAT_INTELLECT)> stat) { trigger_spell_id = 60234; stat = GetStat(STAT_INTELLECT);}
  7544. // spirit
  7545. if(GetStat(STAT_SPIRIT) > stat) { trigger_spell_id = 60235; }
  7546. break;
  7547. }
  7548. case 64568: // Blood Reserve
  7549. {
  7550. if(HealthBelowPctDamaged(35, damage))
  7551. {
  7552. basepoints0 = triggerAmount;
  7553. trigger_spell_id = 64569;
  7554. RemoveAura(64568);
  7555. }
  7556. break;
  7557. }
  7558. case 67702: // Death's Choice, Item - Coliseum 25 Normal Melee Trinket
  7559. {
  7560. float stat = 0.0f;
  7561. // strength
  7562. if(GetStat(STAT_STRENGTH) > stat) { trigger_spell_id = 67708;stat = GetStat(STAT_STRENGTH); }
  7563. // agility
  7564. if(GetStat(STAT_AGILITY) > stat) { trigger_spell_id = 67703; }
  7565. break;
  7566. }
  7567. case 67771: // Death's Choice (heroic), Item - Coliseum 25 Heroic Melee Trinket
  7568. {
  7569. float stat = 0.0f;
  7570. // strength
  7571. if(GetStat(STAT_STRENGTH) > stat) { trigger_spell_id = 67773;stat = GetStat(STAT_STRENGTH); }
  7572. // agility
  7573. if(GetStat(STAT_AGILITY) > stat) { trigger_spell_id = 67772; }
  7574. break;
  7575. }
  7576. // Mana Drain Trigger
  7577. case 27522:
  7578. case 40336:
  7579. {
  7580. // On successful melee or ranged attack gain $29471s1 mana and if possible drain $27526s1 mana from the target.
  7581. if(isAlive())
  7582. CastSpell(this, 29471, true, castItem, triggeredByAura);
  7583. if(victim && victim->isAlive())
  7584. CastSpell(victim, 27526, true, castItem, triggeredByAura);
  7585. return true;
  7586. }
  7587. // Evasive Maneuvers
  7588. case 50240:
  7589. {
  7590. // Remove a Evasive Charge
  7591. Aura* charge = GetAura(50241);
  7592. if (charge->ModStackAmount(-1, AURA_REMOVE_BY_ENEMY_SPELL))
  7593. RemoveAurasDueToSpell(50240);
  7594. }
  7595. }
  7596. break;
  7597. case SPELLFAMILY_MAGE:
  7598. if(auraSpellInfo->SpellIconID == 2127) // Blazing Speed
  7599. {
  7600. switch(auraSpellInfo->Id)
  7601. {
  7602. case 31641: // Rank 1
  7603. case 31642: // Rank 2
  7604. trigger_spell_id = 31643;
  7605. break;
  7606. default:
  7607. sLog->outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Blazing Speed", auraSpellInfo->Id);
  7608. return false;
  7609. }
  7610. }
  7611. break;
  7612. case SPELLFAMILY_WARRIOR:
  7613. if(auraSpellInfo->Id == 50421) // Scent of Blood
  7614. {
  7615. CastSpell(this, 50422, true);
  7616. RemoveAuraFromStack(auraSpellInfo->Id);
  7617. return false;
  7618. }
  7619. break;
  7620. case SPELLFAMILY_WARLOCK:
  7621. {
  7622. // Drain Soul
  7623. if(auraSpellInfo->SpellFamilyFlags[0] & 0x4000)
  7624. {
  7625. // Improved Drain Soul
  7626. Unit::AuraEffectList const& mAddFlatModifier = GetAuraEffectsByType(SPELL_AURA_DUMMY);
  7627. for(Unit::AuraEffectList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i)
  7628. {
  7629. if((*i)->GetMiscValue() == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellProto()->SpellIconID == 113)
  7630. {
  7631. int32 value2 = CalculateSpellDamage(this, (*i)->GetSpellProto(), 2);
  7632. basepoints0 = int32(CalculatePctN(GetMaxPower(POWER_MANA), value2));
  7633. // Drain Soul
  7634. CastCustomSpell(this, 18371, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
  7635. break;
  7636. }
  7637. }
  7638. // Not remove charge (aura removed on death in any cases)
  7639. // Need for correct work Drain Soul SPELL_AURA_CHANNEL_DEATH_ITEM aura
  7640. return false;
  7641. }
  7642. // Nether Protection
  7643. else if(auraSpellInfo->SpellIconID == 1985)
  7644. {
  7645. if(!procSpell)
  7646. return false;
  7647. switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
  7648. {
  7649. case SPELL_SCHOOL_NORMAL:
  7650. return false; // ignore
  7651. case SPELL_SCHOOL_HOLY: trigger_spell_id = 54370; break;
  7652. case SPELL_SCHOOL_FIRE: trigger_spell_id = 54371; break;
  7653. case SPELL_SCHOOL_NATURE: trigger_spell_id = 54375; break;
  7654. case SPELL_SCHOOL_FROST: trigger_spell_id = 54372; break;
  7655. case SPELL_SCHOOL_SHADOW: trigger_spell_id = 54374; break;
  7656. case SPELL_SCHOOL_ARCANE: trigger_spell_id = 54373; break;
  7657. default:
  7658. return false;
  7659. }
  7660. }
  7661. break;
  7662. }
  7663. case SPELLFAMILY_PRIEST:
  7664. {
  7665. // Greater Heal Refund
  7666. if(auraSpellInfo->Id == 37594)
  7667. trigger_spell_id = 37595;
  7668. // Blessed Recovery
  7669. else if(auraSpellInfo->SpellIconID == 1875)
  7670. {
  7671. switch(auraSpellInfo->Id)
  7672. {
  7673. case 27811: trigger_spell_id = 27813; break;
  7674. case 27815: trigger_spell_id = 27817; break;
  7675. case 27816: trigger_spell_id = 27818; break;
  7676. default:
  7677. sLog->outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR", auraSpellInfo->Id);
  7678. return false;
  7679. }
  7680. basepoints0 = CalculatePctN(int32(damage), triggerAmount) / 3;
  7681. target = this;
  7682. // Add remaining ticks to healing done
  7683. basepoints0 += GetRemainingPeriodicAmount(GetGUID(), trigger_spell_id, SPELL_AURA_PERIODIC_HEAL);
  7684. }
  7685. break;
  7686. }
  7687. case SPELLFAMILY_DRUID:
  7688. {
  7689. switch(auraSpellInfo->Id)
  7690. {
  7691. // Druid Forms Trinket
  7692. case 37336:
  7693. {
  7694. switch(GetShapeshiftForm())
  7695. {
  7696. case FORM_NONE: trigger_spell_id = 37344; break;
  7697. case FORM_CAT: trigger_spell_id = 37341; break;
  7698. case FORM_BEAR:
  7699. case FORM_DIREBEAR: trigger_spell_id = 37340; break;
  7700. case FORM_TREE: trigger_spell_id = 37342; break;
  7701. case FORM_MOONKIN: trigger_spell_id = 37343; break;
  7702. default:
  7703. return false;
  7704. }
  7705. break;
  7706. }
  7707. // Druid T9 Feral Relic (Lacerate, Swipe, Mangle, and Shred)
  7708. case 67353:
  7709. {
  7710. switch(GetShapeshiftForm())
  7711. {
  7712. case FORM_CAT: trigger_spell_id = 67355; break;
  7713. case FORM_BEAR:
  7714. case FORM_DIREBEAR: trigger_spell_id = 67354; break;
  7715. default:
  7716. return false;
  7717. }
  7718. break;
  7719. }
  7720. default:
  7721. break;
  7722. }
  7723. break;
  7724. }
  7725. case SPELLFAMILY_HUNTER:
  7726. {
  7727. if(auraSpellInfo->SpellIconID == 3247) // Piercing Shots
  7728. {
  7729. switch(auraSpellInfo->Id)
  7730. {
  7731. case 53234: // Rank 1
  7732. case 53237: // Rank 2
  7733. case 53238: // Rank 3
  7734. trigger_spell_id = 63468;
  7735. break;
  7736. default:
  7737. sLog->outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Piercing Shots", auraSpellInfo->Id);
  7738. return false;
  7739. }
  7740. SpellEntry const* TriggerPS = sSpellStore.LookupEntry(trigger_spell_id);
  7741. if(!TriggerPS)
  7742. return false;
  7743. basepoints0 = CalculatePctN(int32(damage), triggerAmount) / (GetSpellMaxDuration(TriggerPS) / TriggerPS->EffectAmplitude[0]);
  7744. basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), trigger_spell_id, SPELL_AURA_PERIODIC_DAMAGE);
  7745. break;
  7746. }
  7747. break;
  7748. }
  7749. case SPELLFAMILY_PALADIN:
  7750. {
  7751. switch(auraSpellInfo->Id)
  7752. {
  7753. // Healing Discount
  7754. case 37705:
  7755. {
  7756. trigger_spell_id = 37706;
  7757. target = this;
  7758. break;
  7759. }
  7760. // Soul Preserver
  7761. case 60510:
  7762. {
  7763. trigger_spell_id = 60515;
  7764. target = this;
  7765. break;
  7766. }
  7767. // Lightning Capacitor
  7768. case 37657:
  7769. {
  7770. if(!victim || !victim->isAlive())
  7771. return false;
  7772. // stacking
  7773. CastSpell(this, 37658, true, NULL, triggeredByAura);
  7774. Aura* dummy = GetAura(37658);
  7775. // release at 3 aura in stack (cont contain in basepoint of trigger aura)
  7776. if(!dummy || dummy->GetStackAmount() < triggerAmount)
  7777. return false;
  7778. RemoveAurasDueToSpell(37658);
  7779. trigger_spell_id = 37661;
  7780. target = victim;
  7781. break;
  7782. }
  7783. // Thunder Capacitor
  7784. case 54841:
  7785. {
  7786. if(!victim || !victim->isAlive())
  7787. return false;
  7788. // stacking
  7789. CastSpell(this, 54842, true, NULL, triggeredByAura);
  7790. // counting
  7791. Aura* dummy = GetAura(54842);
  7792. // release at 3 aura in stack (cont contain in basepoint of trigger aura)
  7793. if(!dummy || dummy->GetStackAmount() < triggerAmount)
  7794. return false;
  7795. RemoveAurasDueToSpell(54842);
  7796. trigger_spell_id = 54843;
  7797. target = victim;
  7798. break;
  7799. }
  7800. //Item - Coliseum 25 Normal Caster Trinket
  7801. case 67712:
  7802. {
  7803. if(!victim || !victim->isAlive())
  7804. return false;
  7805. // stacking
  7806. CastSpell(this, 67713, true, NULL, triggeredByAura);
  7807. Aura* dummy = GetAura(67713);
  7808. // release at 3 aura in stack (cont contain in basepoint of trigger aura)
  7809. if(!dummy || dummy->GetStackAmount() < triggerAmount)
  7810. return false;
  7811. RemoveAurasDueToSpell(67713);
  7812. trigger_spell_id = 67714;
  7813. target = victim;
  7814. break;
  7815. }
  7816. //Item - Coliseum 25 Heroic Caster Trinket
  7817. case 67758:
  7818. {
  7819. if(!victim || !victim->isAlive())
  7820. return false;
  7821. // stacking
  7822. CastSpell(this, 67759, true, NULL, triggeredByAura);
  7823. Aura* dummy = GetAura(67759);
  7824. // release at 3 aura in stack (cont contain in basepoint of trigger aura)
  7825. if(!dummy || dummy->GetStackAmount() < triggerAmount)
  7826. return false;
  7827. RemoveAurasDueToSpell(67759);
  7828. trigger_spell_id = 67760;
  7829. target = victim;
  7830. break;
  7831. }
  7832. default:
  7833. // Illumination
  7834. if(auraSpellInfo->SpellIconID == 241)
  7835. {
  7836. if(!procSpell)
  7837. return false;
  7838. // procspell is triggered spell but we need mana cost of original casted spell
  7839. uint32 originalSpellId = procSpell->Id;
  7840. // Holy Shock heal
  7841. if(procSpell->SpellFamilyFlags[1] & 0x00010000)
  7842. {
  7843. switch(procSpell->Id)
  7844. {
  7845. case 25914: originalSpellId = 20473; break;
  7846. case 25913: originalSpellId = 20929; break;
  7847. case 25903: originalSpellId = 20930; break;
  7848. case 27175: originalSpellId = 27174; break;
  7849. case 33074: originalSpellId = 33072; break;
  7850. case 48820: originalSpellId = 48824; break;
  7851. case 48821: originalSpellId = 48825; break;
  7852. default:
  7853. sLog->outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock", procSpell->Id);
  7854. return false;
  7855. }
  7856. }
  7857. SpellEntry const* originalSpell = sSpellStore.LookupEntry(originalSpellId);
  7858. if(!originalSpell)
  7859. {
  7860. sLog->outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu", originalSpellId);
  7861. return false;
  7862. }
  7863. // percent stored in effect 1 (class scripts) base points
  7864. int32 cost = int32(originalSpell->manaCost + CalculatePctU(GetCreateMana(), originalSpell->ManaCostPercentage));
  7865. basepoints0 = CalculatePctN(cost, SpellMgr::CalculateSpellEffectAmount(auraSpellInfo, 1));
  7866. trigger_spell_id = 20272;
  7867. target = this;
  7868. }
  7869. break;
  7870. }
  7871. break;
  7872. }
  7873. case SPELLFAMILY_SHAMAN:
  7874. {
  7875. switch(auraSpellInfo->Id)
  7876. {
  7877. // Lightning Shield (The Ten Storms set)
  7878. case 23551:
  7879. {
  7880. trigger_spell_id = 23552;
  7881. target = victim;
  7882. break;
  7883. }
  7884. // Damage from Lightning Shield (The Ten Storms set)
  7885. case 23552:
  7886. {
  7887. trigger_spell_id = 27635;
  7888. break;
  7889. }
  7890. // Mana Surge (The Earthfury set)
  7891. case 23572:
  7892. {
  7893. if(!procSpell)
  7894. return false;
  7895. basepoints0 = int32(CalculatePctN(procSpell->manaCost, 35));
  7896. trigger_spell_id = 23571;
  7897. target = this;
  7898. break;
  7899. }
  7900. default:
  7901. {
  7902. // Lightning Shield (overwrite non existing triggered spell call in spell.dbc
  7903. if(auraSpellInfo->SpellFamilyFlags[0] & 0x400)
  7904. {
  7905. trigger_spell_id = sSpellMgr->GetSpellWithRank(26364, sSpellMgr->GetSpellRank(auraSpellInfo->Id));
  7906. }
  7907. // Nature's Guardian
  7908. else if(auraSpellInfo->SpellIconID == 2013)
  7909. {
  7910. // Check health condition - should drop to less 30% (damage deal after this!)
  7911. if(!HealthBelowPctDamaged(30, damage))
  7912. return false;
  7913. if(victim && victim->isAlive())
  7914. victim->getThreatManager().modifyThreatPercent(this, -10);
  7915. basepoints0 = int32(CountPctFromMaxHealth(triggerAmount));
  7916. trigger_spell_id = 31616;
  7917. target = this;
  7918. }
  7919. }
  7920. }
  7921. break;
  7922. }
  7923. case SPELLFAMILY_DEATHKNIGHT:
  7924. {
  7925. // Acclimation
  7926. if(auraSpellInfo->SpellIconID == 1930)
  7927. {
  7928. if(!procSpell)
  7929. return false;
  7930. switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
  7931. {
  7932. case SPELL_SCHOOL_NORMAL:
  7933. return false; // ignore
  7934. case SPELL_SCHOOL_HOLY: trigger_spell_id = 50490; break;
  7935. case SPELL_SCHOOL_FIRE: trigger_spell_id = 50362; break;
  7936. case SPELL_SCHOOL_NATURE: trigger_spell_id = 50488; break;
  7937. case SPELL_SCHOOL_FROST: trigger_spell_id = 50485; break;
  7938. case SPELL_SCHOOL_SHADOW: trigger_spell_id = 50489; break;
  7939. case SPELL_SCHOOL_ARCANE: trigger_spell_id = 50486; break;
  7940. default:
  7941. return false;
  7942. }
  7943. }
  7944. // Blood Presence (Improved)
  7945. else if(auraSpellInfo->Id == 63611)
  7946. {
  7947. if(GetTypeId() != TYPEID_PLAYER)
  7948. return false;
  7949. trigger_spell_id = 50475;
  7950. basepoints0 = CalculatePctN(int32(damage), triggerAmount);
  7951. }
  7952. break;
  7953. }
  7954. default:
  7955. break;
  7956. }
  7957. }
  7958. // All ok. Check current trigger spell
  7959. SpellEntry const* triggerEntry = sSpellStore.LookupEntry(trigger_spell_id);
  7960. if(triggerEntry == NULL)
  7961. {
  7962. // Not cast unknown spell
  7963. // sLog->outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?", auraSpellInfo->Id, triggeredByAura->GetEffIndex());
  7964. return false;
  7965. }
  7966. // not allow proc extra attack spell at extra attack
  7967. if(m_extraAttacks && IsSpellHaveEffect(triggerEntry, SPELL_EFFECT_ADD_EXTRA_ATTACKS))
  7968. return false;
  7969. // Custom requirements (not listed in procEx) Warning! damage dealing after this
  7970. // Custom triggered spells
  7971. switch(auraSpellInfo->Id)
  7972. {
  7973. // Deep Wounds
  7974. case 12834:
  7975. case 12849:
  7976. case 12867:
  7977. {
  7978. if(GetTypeId() != TYPEID_PLAYER)
  7979. return false;
  7980. // now compute approximate weapon damage by formula from wowwiki.com
  7981. Item* item = NULL;
  7982. if(procFlags & PROC_FLAG_DONE_OFFHAND_ATTACK)
  7983. item = ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
  7984. else
  7985. item = ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
  7986. // dunno if it's really needed but will prevent any possible crashes
  7987. if(!item)
  7988. return false;
  7989. ItemTemplate const* weapon = item->GetTemplate();
  7990. float weaponDPS = weapon->getDPS();
  7991. float attackPower = GetTotalAttackPowerValue(BASE_ATTACK) / 14.0f;
  7992. float weaponSpeed = float(weapon->Delay) / 1000.0f;
  7993. basepoints0 = int32((weaponDPS + attackPower) * weaponSpeed);
  7994. break;
  7995. }
  7996. // Persistent Shield (Scarab Brooch trinket)
  7997. // This spell originally trigger 13567 - Dummy Trigger (vs dummy efect)
  7998. case 26467:
  7999. {
  8000. basepoints0 = int32(CalculatePctN(damage, 15));
  8001. target = victim;
  8002. trigger_spell_id = 26470;
  8003. break;
  8004. }
  8005. // Unyielding Knights (item exploit 29108\29109)
  8006. case 38164:
  8007. {
  8008. if(!victim || victim->GetEntry() != 19457) // Proc only if your target is Grillok
  8009. return false;
  8010. break;
  8011. }
  8012. // Deflection
  8013. case 52420:
  8014. {
  8015. if(!HealthBelowPct(35))
  8016. return false;
  8017. break;
  8018. }
  8019. case 28845: // Cheat Death
  8020. {
  8021. // When your health drops below 20%
  8022. if(HealthBelowPctDamaged(20, damage) || HealthBelowPct(20))
  8023. return false;
  8024. break;
  8025. }
  8026. // Deadly Swiftness (Rank 1)
  8027. case 31255:
  8028. {
  8029. // whenever you deal damage to a target who is below 20% health.
  8030. if(!victim || !victim->isAlive() || victim->HealthAbovePct(20))
  8031. return false;
  8032. target = this;
  8033. trigger_spell_id = 22588;
  8034. }
  8035. // Greater Heal Refund (Avatar Raiment set)
  8036. case 37594:
  8037. {
  8038. if(!victim || !victim->isAlive())
  8039. return false;
  8040. // Not give if target already have full health
  8041. if(victim->IsFullHealth())
  8042. return false;
  8043. // If your Greater Heal brings the target to full health, you gain $37595s1 mana.
  8044. if(victim->GetHealth() + damage < victim->GetMaxHealth())
  8045. return false;
  8046. break;
  8047. }
  8048. // Bonus Healing (Crystal Spire of Karabor mace)
  8049. case 40971:
  8050. {
  8051. // If your target is below $s1% health
  8052. if(!victim || !victim->isAlive() || victim->HealthAbovePct(triggerAmount))
  8053. return false;
  8054. break;
  8055. }
  8056. // Rapid Recuperation
  8057. case 53228:
  8058. case 53232:
  8059. {
  8060. // This effect only from Rapid Fire (ability cast)
  8061. if(!(procSpell->SpellFamilyFlags[0] & 0x20))
  8062. return false;
  8063. break;
  8064. }
  8065. // Decimation
  8066. case 63156:
  8067. case 63158:
  8068. // Can proc only if target has hp below 35%
  8069. if(!victim || !victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, procSpell, this))
  8070. return false;
  8071. break;
  8072. // Deathbringer Saurfang - Rune of Blood
  8073. case 72408:
  8074. // can proc only if target is marked with rune
  8075. // this should be handled by targetAuraSpell, but because 72408 is not passive
  8076. // one failed proc will remove the entire aura
  8077. if(!victim->HasAura(72410))
  8078. return false;
  8079. break;
  8080. // Deathbringer Saurfang - Blood Beast's Blood Link
  8081. case 72176:
  8082. basepoints0 = 3;
  8083. break;
  8084. // Deathbringer Saurfang - Mark of the Fallen Champion
  8085. case 72256:
  8086. // this should be handled by targetAuraSpell, but because 72408 is not passive
  8087. // one failed proc will remove the entire aura
  8088. CastSpell(NULL, trigger_spell_id, true, NULL, triggeredByAura);
  8089. return true;
  8090. case 15337: // Improved Spirit Tap (Rank 1)
  8091. case 15338: // Improved Spirit Tap (Rank 2)
  8092. {
  8093. if(procSpell->SpellFamilyFlags[0] & 0x800000)
  8094. if((procSpell->Id != 58381) || !roll_chance_i(50))
  8095. return false;
  8096. target = victim;
  8097. break;
  8098. }
  8099. // Professor Putricide - Ooze Spell Tank Protection
  8100. case 71770:
  8101. if(victim)
  8102. victim->CastSpell(victim, trigger_spell_id, true); // EffectImplicitTarget is self
  8103. return true;
  8104. case 45057: // Evasive Maneuvers (Commendation of Kael`thas trinket)
  8105. case 71634: // Item - Icecrown 25 Normal Tank Trinket 1
  8106. case 71640: // Item - Icecrown 25 Heroic Tank Trinket 1
  8107. case 75475: // Item - Chamber of Aspects 25 Normal Tank Trinket
  8108. case 75481: // Item - Chamber of Aspects 25 Heroic Tank Trinket
  8109. {
  8110. // Procs only if damage takes health below $s1%
  8111. if(!HealthBelowPctDamaged(triggerAmount, damage))
  8112. return false;
  8113. break;
  8114. }
  8115. case 55689: // Glyph of Shadow only in shadow form
  8116. if(GetTypeId() == TYPEID_PLAYER)
  8117. if(Player* pPlayer = this->ToPlayer()) {
  8118. if(pPlayer->GetShapeshiftForm() != FORM_SHADOW)
  8119. return false;
  8120. }
  8121. break;
  8122. case 44404: case 54486: case 54488: case 54489: case 54490: //Missile Barrage rank 1-5
  8123. if(!procSpell->SpellFamilyFlags.HasFlag(0x20000000, 0, 0)) //for Arcane Blast normal proc chance
  8124. if(urand(0, 1))
  8125. return false; //for Arcane Barrage, Fireball, Frostbolt, Frostfire Bolt proc chance is halved
  8126. break;
  8127. default:
  8128. break;
  8129. }
  8130. // Sword Specialization
  8131. if(auraSpellInfo->SpellFamilyName == SPELLFAMILY_GENERIC && auraSpellInfo->SpellIconID == 1462 && procSpell)
  8132. {
  8133. if(Player* plr = ToPlayer())
  8134. {
  8135. if(cooldown && plr->HasSpellCooldown(16459))
  8136. return false;
  8137. // this required for attacks like Mortal Strike
  8138. plr->RemoveSpellCooldown(procSpell->Id);
  8139. CastSpell(victim, procSpell->Id, true);
  8140. if(cooldown)
  8141. plr->AddSpellCooldown(16459, 0, time(NULL) + cooldown);
  8142. return true;
  8143. }
  8144. }
  8145. // Blade Barrier
  8146. if(auraSpellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && auraSpellInfo->SpellIconID == 85)
  8147. {
  8148. Player* plr = ToPlayer();
  8149. if(!plr || plr->getClass() != CLASS_DEATH_KNIGHT)
  8150. return false;
  8151. if(!plr->IsBaseRuneSlotsOnCooldown(RUNE_BLOOD))
  8152. return false;
  8153. }
  8154. // Rime
  8155. else if(auraSpellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && auraSpellInfo->SpellIconID == 56)
  8156. {
  8157. if(GetTypeId() != TYPEID_PLAYER)
  8158. return false;
  8159. // Howling Blast
  8160. ToPlayer()->RemoveSpellCategoryCooldown(1248, true);
  8161. }
  8162. // Custom basepoints/target for exist spell
  8163. // dummy basepoints or other customs
  8164. switch(trigger_spell_id)
  8165. {
  8166. // Auras which should proc on area aura source (caster in this case):
  8167. // Turn the Tables
  8168. case 52914:
  8169. case 52915:
  8170. case 52910:
  8171. // Honor Among Thieves
  8172. case 52916:
  8173. {
  8174. target = triggeredByAura->GetBase()->GetCaster();
  8175. if(!target)
  8176. return false;
  8177. if(cooldown && target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->HasSpellCooldown(trigger_spell_id))
  8178. return false;
  8179. target->CastSpell(target, trigger_spell_id, true, castItem, triggeredByAura);
  8180. if(cooldown && GetTypeId() == TYPEID_PLAYER)
  8181. ToPlayer()->AddSpellCooldown(trigger_spell_id, 0, time(NULL) + cooldown);
  8182. return true;
  8183. }
  8184. // Cast positive spell on enemy target
  8185. case 7099: // Curse of Mending
  8186. case 39703: // Curse of Mending
  8187. case 29494: // Temptation
  8188. case 20233: // Improved Lay on Hands (cast on target)
  8189. {
  8190. target = victim;
  8191. break;
  8192. }
  8193. // Combo points add triggers (need add combopoint only for main target, and after possible combopoints reset)
  8194. case 15250: // Rogue Setup
  8195. {
  8196. // applied only for main target
  8197. if(!victim || (GetTypeId() == TYPEID_PLAYER && victim != ToPlayer()->GetSelectedUnit()))
  8198. return false;
  8199. break; // continue normal case
  8200. }
  8201. // Finish movies that add combo
  8202. case 14189: // Seal Fate (Netherblade set)
  8203. case 14157: // Ruthlessness
  8204. case 70802: // Rogue T10 4P Bonus
  8205. {
  8206. if(!victim || victim == this)
  8207. return false;
  8208. // Need add combopoint AFTER finish movie (or they dropped in finish phase)
  8209. break;
  8210. }
  8211. case 16870: // Item - Druid T10 Balance 2P Bonus
  8212. {
  8213. if(HasAura(70718))
  8214. CastSpell(this, 70721, true);
  8215. break;
  8216. }
  8217. // Bloodthirst (($m/100)% of max health)
  8218. case 23880:
  8219. {
  8220. basepoints0 = int32(CountPctFromMaxHealth(triggerAmount));
  8221. break;
  8222. }
  8223. // Shamanistic Rage triggered spell
  8224. case 30824:
  8225. {
  8226. basepoints0 = int32(CalculatePctN(GetTotalAttackPowerValue(BASE_ATTACK), triggerAmount));
  8227. break;
  8228. }
  8229. // Enlightenment (trigger only from mana cost spells)
  8230. case 35095:
  8231. {
  8232. if(!procSpell || procSpell->powerType != POWER_MANA || (procSpell->manaCost == 0 && procSpell->ManaCostPercentage == 0 && procSpell->manaCostPerlevel == 0))
  8233. return false;
  8234. break;
  8235. }
  8236. // Demonic Pact
  8237. case 48090:
  8238. {
  8239. // Get talent aura from owner
  8240. if(isPet())
  8241. if(Unit* owner = GetOwner())
  8242. {
  8243. if(AuraEffect* aurEff = owner->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, 3220, 0))
  8244. {
  8245. basepoints0 = int32((aurEff->GetAmount() * owner->SpellBaseDamageBonus(SpellSchoolMask(SPELL_SCHOOL_MASK_MAGIC)) + 100.0f) / 100.0f); // TODO: Is it right?
  8246. CastCustomSpell(this, trigger_spell_id, &basepoints0, &basepoints0, NULL, true, castItem, triggeredByAura);
  8247. return true;
  8248. }
  8249. }
  8250. break;
  8251. }
  8252. case 46916: // Slam!
  8253. case 52437: // Sudden Death
  8254. {
  8255. // Item - Warrior T10 Melee 4P Bonus
  8256. if(AuraEffect const* aurEff = GetAuraEffect(70847, EFFECT_0))
  8257. {
  8258. int32 amount = aurEff->GetAmount();
  8259. if(roll_chance_i(amount))
  8260. CastSpell(this, 70849, true, castItem, triggeredByAura); // Extra Charge
  8261. if(roll_chance_i(amount))
  8262. CastSpell(this, 71072, true, castItem, triggeredByAura); // Slam GCD Reduced
  8263. if(roll_chance_i(amount))
  8264. CastSpell(this, 71069, true, castItem, triggeredByAura); // Execute GCD Reduced
  8265. }
  8266. break;
  8267. }
  8268. // Sword and Board
  8269. case 50227:
  8270. {
  8271. // Remove cooldown on Shield Slam
  8272. if(GetTypeId() == TYPEID_PLAYER)
  8273. ToPlayer()->RemoveSpellCategoryCooldown(1209, true);
  8274. break;
  8275. }
  8276. // Maelstrom Weapon
  8277. case 53817:
  8278. {
  8279. // have rank dependent proc chance, ignore too often cases
  8280. // PPM = 2.5 * (rank of talent),
  8281. uint32 rank = sSpellMgr->GetSpellRank(auraSpellInfo->Id);
  8282. // 5 rank -> 100% 4 rank -> 80% and etc from full rate
  8283. if(!roll_chance_i(20*rank))
  8284. return false;
  8285. // Item - Shaman T10 Enhancement 4P Bonus
  8286. if(AuraEffect const* aurEff = GetAuraEffect(70832, 0))
  8287. if(Aura const* maelstrom = GetAura(53817))
  8288. if((maelstrom->GetStackAmount() == maelstrom->GetSpellProto()->StackAmount) && roll_chance_i(aurEff->GetAmount()))
  8289. CastSpell(this, 70831, true, castItem, triggeredByAura);
  8290. break;
  8291. }
  8292. // Astral Shift
  8293. case 52179:
  8294. {
  8295. if(procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == victim)
  8296. return false;
  8297. // Need stun, fear or silence mechanic
  8298. if(!(GetAllSpellMechanicMask(procSpell) & ((1<<MECHANIC_SILENCE)|(1<<MECHANIC_STUN)|(1<<MECHANIC_FEAR))))
  8299. return false;
  8300. break;
  8301. }
  8302. // Burning Determination
  8303. case 54748:
  8304. {
  8305. if(!procSpell)
  8306. return false;
  8307. // Need Interrupt or Silenced mechanic
  8308. if(!(GetAllSpellMechanicMask(procSpell) & ((1<<MECHANIC_INTERRUPT)|(1<<MECHANIC_SILENCE))))
  8309. return false;
  8310. break;
  8311. }
  8312. // Lock and Load
  8313. case 56453:
  8314. {
  8315. // Proc only from Frost/Freezing trap activation or from Freezing Arrow (the periodic dmg proc handled elsewhere)
  8316. if(!(procFlags & PROC_FLAG_DONE_TRAP_ACTIVATION) || !procSpell || !(procSpell->SchoolMask & SPELL_SCHOOL_MASK_FROST) || !roll_chance_i(triggerAmount))
  8317. return false;
  8318. break;
  8319. }
  8320. // Glyph of Death's Embrace
  8321. case 58679:
  8322. {
  8323. // Proc only from healing part of Death Coil. Check is essential as all Death Coil spells have 0x2000 mask in SpellFamilyFlags
  8324. if(!procSpell || !(procSpell->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && procSpell->SpellFamilyFlags[0] == 0x80002000))
  8325. return false;
  8326. break;
  8327. }
  8328. // Glyph of Death Grip
  8329. case 58628:
  8330. {
  8331. // remove cooldown of Death Grip
  8332. if(GetTypeId() == TYPEID_PLAYER)
  8333. ToPlayer()->RemoveSpellCooldown(49576, true);
  8334. return true;
  8335. }
  8336. // Savage Defense
  8337. case 62606:
  8338. {
  8339. basepoints0 = CalculatePctF(triggerAmount, GetTotalAttackPowerValue(BASE_ATTACK));
  8340. break;
  8341. }
  8342. // Body and Soul
  8343. case 64128:
  8344. case 65081:
  8345. {
  8346. // Proc only from PW:S cast
  8347. if(!(procSpell->SpellFamilyFlags[0] & 0x00000001))
  8348. return false;
  8349. break;
  8350. }
  8351. // Culling the Herd
  8352. case 70893:
  8353. {
  8354. // check if we're doing a critical hit
  8355. if(!(procSpell->SpellFamilyFlags[1] & 0x10000000) && (procEx != PROC_EX_CRITICAL_HIT) )
  8356. return false;
  8357. // check if we're procced by Claw, Bite or Smack (need to use the spell icon ID to detect it)
  8358. if(!(procSpell->SpellIconID == 262 || procSpell->SpellIconID == 1680 || procSpell->SpellIconID == 473 ))
  8359. return false;
  8360. break;
  8361. }
  8362. // Shadow's Fate (Shadowmourne questline)
  8363. case 71169:
  8364. {
  8365. if(GetTypeId() != TYPEID_PLAYER)
  8366. return false;
  8367. Player* player = ToPlayer();
  8368. if(player->GetQuestStatus(24749) == QUEST_STATUS_INCOMPLETE && (player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_NORMAL || player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_HEROIC)) // Unholy Infusion
  8369. {
  8370. if(!player->HasAura(71516) || victim->GetEntry() != 36678) // Shadow Infusion && Professor Putricide
  8371. return false;
  8372. }
  8373. else if(player->GetQuestStatus(24756) == QUEST_STATUS_INCOMPLETE && (player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_NORMAL || player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_HEROIC)) // Blood Infusion
  8374. {
  8375. if(!player->HasAura(72154) || victim->GetEntry() != 37955) // Thirst Quenched && Blood-Queen Lana'thel
  8376. return false;
  8377. }
  8378. else if(player->GetQuestStatus(24757) == QUEST_STATUS_INCOMPLETE && (player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_NORMAL || player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_HEROIC)) // Frost Infusion
  8379. {
  8380. if(!player->HasAura(72290) || victim->GetEntry() != 36853) // Frost-Imbued Blade && Sindragosa
  8381. return false;
  8382. }
  8383. else if(player->GetQuestStatus(24547) != QUEST_STATUS_INCOMPLETE) // A Feast of Souls
  8384. return false;
  8385. if(victim->GetTypeId() != TYPEID_UNIT)
  8386. return false;
  8387. // critters are not allowed
  8388. if(victim->GetCreatureType() == CREATURE_TYPE_CRITTER)
  8389. return false;
  8390. break;
  8391. }
  8392. }
  8393. if(cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(trigger_spell_id))
  8394. return false;
  8395. // try detect target manually if not set
  8396. if(target == NULL)
  8397. target = !(procFlags & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS)) && IsPositiveSpell(trigger_spell_id) ? this : victim;
  8398. // default case
  8399. if((!target && !sSpellMgr->IsSrcTargetSpell(triggerEntry)) || (target && target != this && !target->isAlive()))
  8400. return false;
  8401. if(basepoints0)
  8402. CastCustomSpell(target, trigger_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
  8403. else
  8404. CastSpell(target, trigger_spell_id, true, castItem, triggeredByAura);
  8405. if(cooldown && GetTypeId() == TYPEID_PLAYER)
  8406. ToPlayer()->AddSpellCooldown(trigger_spell_id, 0, time(NULL) + cooldown);
  8407. return true;
  8408. }
  8409. bool Unit::HandleOverrideClassScriptAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellEntry const* procSpell, uint32 cooldown)
  8410. {
  8411. int32 scriptId = triggeredByAura->GetMiscValue();
  8412. if(!victim || !victim->isAlive())
  8413. return false;
  8414. Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
  8415. ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
  8416. uint32 triggered_spell_id = 0;
  8417. switch(scriptId)
  8418. {
  8419. case 836: // Improved Blizzard (Rank 1)
  8420. {
  8421. if(!procSpell || procSpell->SpellVisual[0] != 9487)
  8422. return false;
  8423. triggered_spell_id = 12484;
  8424. break;
  8425. }
  8426. case 988: // Improved Blizzard (Rank 2)
  8427. {
  8428. if(!procSpell || procSpell->SpellVisual[0] != 9487)
  8429. return false;
  8430. triggered_spell_id = 12485;
  8431. break;
  8432. }
  8433. case 989: // Improved Blizzard (Rank 3)
  8434. {
  8435. if(!procSpell || procSpell->SpellVisual[0] != 9487)
  8436. return false;
  8437. triggered_spell_id = 12486;
  8438. break;
  8439. }
  8440. case 4533: // Dreamwalker Raiment 2 pieces bonus
  8441. {
  8442. // Chance 50%
  8443. if(!roll_chance_i(50))
  8444. return false;
  8445. switch(victim->getPowerType())
  8446. {
  8447. case POWER_MANA: triggered_spell_id = 28722; break;
  8448. case POWER_RAGE: triggered_spell_id = 28723; break;
  8449. case POWER_ENERGY: triggered_spell_id = 28724; break;
  8450. default:
  8451. return false;
  8452. }
  8453. break;
  8454. }
  8455. case 4537: // Dreamwalker Raiment 6 pieces bonus
  8456. triggered_spell_id = 28750; // Blessing of the Claw
  8457. break;
  8458. case 5497: // Improved Mana Gems
  8459. triggered_spell_id = 37445; // Mana Surge
  8460. break;
  8461. case 7010: // Revitalize - can proc on full hp target
  8462. case 7011:
  8463. case 7012:
  8464. {
  8465. if(!roll_chance_i(triggeredByAura->GetAmount()))
  8466. return false;
  8467. switch(victim->getPowerType())
  8468. {
  8469. case POWER_MANA: triggered_spell_id = 48542; break;
  8470. case POWER_RAGE: triggered_spell_id = 48541; break;
  8471. case POWER_ENERGY: triggered_spell_id = 48540; break;
  8472. case POWER_RUNIC_POWER: triggered_spell_id = 48543; break;
  8473. default:
  8474. break;
  8475. }
  8476. break;
  8477. }
  8478. default:
  8479. break;
  8480. }
  8481. // not processed
  8482. if(!triggered_spell_id)
  8483. return false;
  8484. // standard non-dummy case
  8485. SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
  8486. if(!triggerEntry)
  8487. {
  8488. sLog->outError("Unit::HandleOverrideClassScriptAuraProc: Spell %u triggering for class script id %u", triggered_spell_id, scriptId);
  8489. return false;
  8490. }
  8491. if(cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
  8492. return false;
  8493. CastSpell(victim, triggered_spell_id, true, castItem, triggeredByAura);
  8494. if(cooldown && GetTypeId() == TYPEID_PLAYER)
  8495. ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
  8496. return true;
  8497. }
  8498. void Unit::setPowerType(Powers new_powertype)
  8499. {
  8500. SetByteValue(UNIT_FIELD_BYTES_0, 3, new_powertype);
  8501. if(GetTypeId() == TYPEID_PLAYER)
  8502. {
  8503. if(ToPlayer()->GetGroup())
  8504. ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE);
  8505. }
  8506. else if(Pet* pet = ToCreature()->ToPet())
  8507. {
  8508. if(pet->isControlled())
  8509. {
  8510. Unit* owner = GetOwner();
  8511. if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup())
  8512. owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE);
  8513. }
  8514. }
  8515. switch(new_powertype)
  8516. {
  8517. default:
  8518. case POWER_MANA:
  8519. break;
  8520. case POWER_RAGE:
  8521. SetMaxPower(POWER_RAGE, GetCreatePowers(POWER_RAGE));
  8522. SetPower(POWER_RAGE, 0);
  8523. break;
  8524. case POWER_FOCUS:
  8525. SetMaxPower(POWER_FOCUS, GetCreatePowers(POWER_FOCUS));
  8526. SetPower(POWER_FOCUS, GetCreatePowers(POWER_FOCUS));
  8527. break;
  8528. case POWER_ENERGY:
  8529. SetMaxPower(POWER_ENERGY, GetCreatePowers(POWER_ENERGY));
  8530. break;
  8531. case POWER_HAPPINESS:
  8532. SetMaxPower(POWER_HAPPINESS, GetCreatePowers(POWER_HAPPINESS));
  8533. SetPower(POWER_HAPPINESS, GetCreatePowers(POWER_HAPPINESS));
  8534. break;
  8535. }
  8536. }
  8537. FactionTemplateEntry const* Unit::getFactionTemplateEntry() const
  8538. {
  8539. FactionTemplateEntry const* entry = sFactionTemplateStore.LookupEntry(getFaction());
  8540. if(!entry)
  8541. {
  8542. static uint64 guid = 0; // prevent repeating spam same faction problem
  8543. if(GetGUID() != guid)
  8544. {
  8545. if(Player const* player = ToPlayer())
  8546. sLog->outError("Player %s has invalid faction (faction template id) #%u", player->GetName(), getFaction());
  8547. else if(Creature const* creature = ToCreature())
  8548. sLog->outError("Creature (template id: %u) has invalid faction (faction template id) #%u", creature->GetCreatureInfo()->Entry, getFaction());
  8549. else
  8550. sLog->outError("Unit (name=%s, type=%u) has invalid faction (faction template id) #%u", GetName(), uint32(GetTypeId()), getFaction());
  8551. guid = GetGUID();
  8552. }
  8553. }
  8554. return entry;
  8555. }
  8556. bool Unit::IsHostileTo(Unit const* unit) const
  8557. {
  8558. if(!unit)
  8559. return false;
  8560. // always non-hostile to self
  8561. if(unit == this)
  8562. return false;
  8563. // always non-hostile to GM in GM mode
  8564. if(unit->GetTypeId() == TYPEID_PLAYER && ((Player const*)unit)->isGameMaster())
  8565. return false;
  8566. // always hostile to enemy
  8567. if(getVictim() == unit || unit->getVictim() == this)
  8568. return true;
  8569. // test pet/charm masters instead pers/charmeds
  8570. Unit const* testerOwner = GetCharmerOrOwner();
  8571. Unit const* targetOwner = unit->GetCharmerOrOwner();
  8572. // always hostile to owner's enemy
  8573. if(testerOwner && (testerOwner->getVictim() == unit || unit->getVictim() == testerOwner))
  8574. return true;
  8575. // always hostile to enemy owner
  8576. if(targetOwner && (getVictim() == targetOwner || targetOwner->getVictim() == this))
  8577. return true;
  8578. // always hostile to owner of owner's enemy
  8579. if(testerOwner && targetOwner && (testerOwner->getVictim() == targetOwner || targetOwner->getVictim() == testerOwner))
  8580. return true;
  8581. Unit const* tester = testerOwner ? testerOwner : this;
  8582. Unit const* target = targetOwner ? targetOwner : unit;
  8583. // always non-hostile to target with common owner, or to owner/pet
  8584. if(tester == target)
  8585. return false;
  8586. // special cases (Duel, etc)
  8587. if(tester->GetTypeId() == TYPEID_PLAYER && target->GetTypeId() == TYPEID_PLAYER)
  8588. {
  8589. Player const* pTester = (Player const*)tester;
  8590. Player const* pTarget = (Player const*)target;
  8591. // Duel
  8592. if(pTester->duel && pTester->duel->opponent == pTarget && pTester->duel->startTime != 0)
  8593. return true;
  8594. // Group
  8595. if(pTester->GetGroup() && pTester->GetGroup() == pTarget->GetGroup())
  8596. return false;
  8597. // Sanctuary
  8598. if(pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY))
  8599. return false;
  8600. // PvP FFA state
  8601. if(pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP) && pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP))
  8602. return true;
  8603. // = PvP states
  8604. // Green/Blue (can't attack)
  8605. if(!pTester->HasAuraType(SPELL_AURA_MOD_FACTION) && !pTarget->HasAuraType(SPELL_AURA_MOD_FACTION))
  8606. {
  8607. if(pTester->GetTeam() == pTarget->GetTeam())
  8608. return false;
  8609. // Red (can attack) if true, Blue/Yellow (can't attack) in another case
  8610. return pTester->IsPvP() && pTarget->IsPvP();
  8611. }
  8612. }
  8613. // faction base cases
  8614. FactionTemplateEntry const*tester_faction = tester->getFactionTemplateEntry();
  8615. FactionTemplateEntry const*target_faction = target->getFactionTemplateEntry();
  8616. if(!tester_faction || !target_faction)
  8617. return false;
  8618. if(target->isAttackingPlayer() && tester->IsContestedGuard())
  8619. return true;
  8620. // PvC forced reaction and reputation case
  8621. if(tester->GetTypeId() == TYPEID_PLAYER && !tester->HasAuraType(SPELL_AURA_MOD_FACTION))
  8622. {
  8623. // forced reaction
  8624. if(target_faction->faction)
  8625. {
  8626. if(ReputationRank const* force = tester->ToPlayer()->GetReputationMgr().GetForcedRankIfAny(target_faction))
  8627. return *force <= REP_HOSTILE;
  8628. // if faction have reputation then hostile state for tester at 100% dependent from at_war state
  8629. if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction))
  8630. if(FactionState const* factionState = tester->ToPlayer()->GetReputationMgr().GetState(raw_target_faction))
  8631. return (factionState->Flags & FACTION_FLAG_AT_WAR);
  8632. }
  8633. }
  8634. // CvP forced reaction and reputation case
  8635. else if(target->GetTypeId() == TYPEID_PLAYER && !target->HasAuraType(SPELL_AURA_MOD_FACTION))
  8636. {
  8637. // forced reaction
  8638. if(tester_faction->faction)
  8639. {
  8640. if(ReputationRank const* force = target->ToPlayer()->GetReputationMgr().GetForcedRankIfAny(tester_faction))
  8641. return *force <= REP_HOSTILE;
  8642. // apply reputation state
  8643. FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction);
  8644. if(raw_tester_faction && raw_tester_faction->reputationListID >= 0)
  8645. return ((Player const*)target)->GetReputationMgr().GetRank(raw_tester_faction) <= REP_HOSTILE;
  8646. }
  8647. }
  8648. // common faction based case (CvC, PvC, CvP)
  8649. return tester_faction->IsHostileTo(*target_faction);
  8650. }
  8651. bool Unit::IsFriendlyTo(Unit const* pUnit) const
  8652. {
  8653. // always friendly to self
  8654. if(!pUnit)
  8655. return false;
  8656. if(pUnit == this)
  8657. return true;
  8658. // always friendly to GM in GM mode
  8659. if(pUnit->GetTypeId() == TYPEID_PLAYER && ((Player const*)pUnit)->isGameMaster())
  8660. return true;
  8661. // always non-friendly to enemy
  8662. if(getVictim() == pUnit || pUnit->getVictim() == this)
  8663. return false;
  8664. // test pet/charm masters instead pers/charmeds
  8665. Unit const* testerOwner = GetCharmerOrOwner();
  8666. Unit const* targetOwner = pUnit->GetCharmerOrOwner();
  8667. // always non-friendly to owner's enemy
  8668. if(testerOwner && (testerOwner->getVictim() == pUnit || pUnit->getVictim() == testerOwner))
  8669. return false;
  8670. // always non-friendly to enemy owner
  8671. if(targetOwner && (getVictim() == targetOwner || targetOwner->getVictim() == this))
  8672. return false;
  8673. // always non-friendly to owner of owner's enemy
  8674. if(testerOwner && targetOwner && (testerOwner->getVictim() == targetOwner || targetOwner->getVictim() == testerOwner))
  8675. return false;
  8676. Unit const* tester = testerOwner ? testerOwner : this;
  8677. Unit const* target = targetOwner ? targetOwner : pUnit;
  8678. // always friendly to target with common owner, or to owner/pet
  8679. if(tester == target)
  8680. return true;
  8681. // special cases (Duel)
  8682. if(tester->GetTypeId() == TYPEID_PLAYER && target->GetTypeId() == TYPEID_PLAYER)
  8683. {
  8684. Player const* pTester = (Player const*)tester;
  8685. Player const* pTarget = (Player const*)target;
  8686. // Duel
  8687. if(pTester->duel && pTester->duel->opponent == target && pTester->duel->startTime != 0)
  8688. return false;
  8689. // Group
  8690. if(pTester->GetGroup() && pTester->GetGroup() == pTarget->GetGroup())
  8691. return true;
  8692. // Sanctuary
  8693. if(pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY))
  8694. return true;
  8695. // PvP FFA state
  8696. if(pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP) && pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP))
  8697. return false;
  8698. // = PvP states
  8699. // Green/Blue (non-attackable)
  8700. if(!pTester->HasAuraType(SPELL_AURA_MOD_FACTION) && !pTarget->HasAuraType(SPELL_AURA_MOD_FACTION))
  8701. {
  8702. if(pTester->GetTeam() == pTarget->GetTeam())
  8703. return true;
  8704. // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable)
  8705. return !pTarget->IsPvP();
  8706. }
  8707. }
  8708. // faction base cases
  8709. FactionTemplateEntry const* tester_faction = tester->getFactionTemplateEntry();
  8710. FactionTemplateEntry const* target_faction = target->getFactionTemplateEntry();
  8711. if(!tester_faction || !target_faction)
  8712. return false;
  8713. if(target->isAttackingPlayer() && tester->IsContestedGuard())
  8714. return false;
  8715. // PvC forced reaction and reputation case
  8716. if(tester->GetTypeId() == TYPEID_PLAYER && !tester->HasAuraType(SPELL_AURA_MOD_FACTION))
  8717. {
  8718. // forced reaction
  8719. if(target_faction->faction)
  8720. {
  8721. if(ReputationRank const* force = tester->ToPlayer()->GetReputationMgr().GetForcedRankIfAny(target_faction))
  8722. return *force >= REP_FRIENDLY;
  8723. // if faction have reputation then friendly state for tester at 100% dependent from at_war state
  8724. if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction))
  8725. if(FactionState const* factionState = tester->ToPlayer()->GetReputationMgr().GetState(raw_target_faction))
  8726. return !(factionState->Flags & FACTION_FLAG_AT_WAR);
  8727. }
  8728. }
  8729. // CvP forced reaction and reputation case
  8730. else if(target->GetTypeId() == TYPEID_PLAYER && !target->HasAuraType(SPELL_AURA_MOD_FACTION))
  8731. {
  8732. // forced reaction
  8733. if(tester_faction->faction)
  8734. {
  8735. if(ReputationRank const* force = target->ToPlayer()->GetReputationMgr().GetForcedRankIfAny(tester_faction))
  8736. return *force >= REP_FRIENDLY;
  8737. // apply reputation state
  8738. if(FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction))
  8739. if(raw_tester_faction->reputationListID >= 0)
  8740. return ((Player const*)target)->GetReputationMgr().GetRank(raw_tester_faction) >= REP_FRIENDLY;
  8741. }
  8742. }
  8743. // common faction based case (CvC, PvC, CvP)
  8744. return tester_faction->IsFriendlyTo(*target_faction);
  8745. }
  8746. bool Unit::IsHostileToPlayers() const
  8747. {
  8748. FactionTemplateEntry const* my_faction = getFactionTemplateEntry();
  8749. if(!my_faction || !my_faction->faction)
  8750. return false;
  8751. FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction);
  8752. if(raw_faction && raw_faction->reputationListID >= 0)
  8753. return false;
  8754. return my_faction->IsHostileToPlayers();
  8755. }
  8756. bool Unit::IsNeutralToAll() const
  8757. {
  8758. FactionTemplateEntry const* my_faction = getFactionTemplateEntry();
  8759. if(!my_faction || !my_faction->faction)
  8760. return true;
  8761. FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction);
  8762. if(raw_faction && raw_faction->reputationListID >= 0)
  8763. return false;
  8764. return my_faction->IsNeutralToAll();
  8765. }
  8766. bool Unit::Attack(Unit* victim, bool meleeAttack)
  8767. {
  8768. if(!victim || victim == this)
  8769. return false;
  8770. // dead units can neither attack nor be attacked
  8771. if(!isAlive() || !victim->IsInWorld() || !victim->isAlive())
  8772. return false;
  8773. // player cannot attack in mount state
  8774. if(GetTypeId() == TYPEID_PLAYER && IsMounted())
  8775. return false;
  8776. // nobody can attack GM in GM-mode
  8777. if(victim->GetTypeId() == TYPEID_PLAYER)
  8778. {
  8779. if(victim->ToPlayer()->isGameMaster())
  8780. return false;
  8781. }
  8782. else
  8783. {
  8784. if(victim->ToCreature()->IsInEvadeMode())
  8785. return false;
  8786. }
  8787. // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
  8788. if(HasAuraType(SPELL_AURA_MOD_UNATTACKABLE))
  8789. RemoveAurasByType(SPELL_AURA_MOD_UNATTACKABLE);
  8790. if(m_attacking)
  8791. {
  8792. if(m_attacking == victim)
  8793. {
  8794. // switch to melee attack from ranged/magic
  8795. if(meleeAttack)
  8796. {
  8797. if(!HasUnitState(UNIT_STAT_MELEE_ATTACKING))
  8798. {
  8799. AddUnitState(UNIT_STAT_MELEE_ATTACKING);
  8800. SendMeleeAttackStart(victim);
  8801. return true;
  8802. }
  8803. }
  8804. else if(HasUnitState(UNIT_STAT_MELEE_ATTACKING))
  8805. {
  8806. ClearUnitState(UNIT_STAT_MELEE_ATTACKING);
  8807. SendMeleeAttackStop(victim);
  8808. return true;
  8809. }
  8810. return false;
  8811. }
  8812. // switch target
  8813. InterruptSpell(CURRENT_MELEE_SPELL);
  8814. if(!meleeAttack)
  8815. ClearUnitState(UNIT_STAT_MELEE_ATTACKING);
  8816. }
  8817. if(m_attacking)
  8818. m_attacking->_removeAttacker(this);
  8819. m_attacking = victim;
  8820. m_attacking->_addAttacker(this);
  8821. // Set our target
  8822. SetTarget(victim->GetGUID());
  8823. if(meleeAttack)
  8824. AddUnitState(UNIT_STAT_MELEE_ATTACKING);
  8825. if(GetTypeId() == TYPEID_UNIT && !ToCreature()->isPet())
  8826. {
  8827. // should not let player enter combat by right clicking target - doesn't helps
  8828. SetInCombatWith(victim);
  8829. if(victim->GetTypeId() == TYPEID_PLAYER)
  8830. victim->SetInCombatWith(this);
  8831. AddThreat(victim, 0.0f);
  8832. ToCreature()->SendAIReaction(AI_REACTION_HOSTILE);
  8833. ToCreature()->CallAssistance();
  8834. }
  8835. // delay offhand weapon attack to next attack time
  8836. if(haveOffhandWeapon())
  8837. resetAttackTimer(OFF_ATTACK);
  8838. if(meleeAttack)
  8839. SendMeleeAttackStart(victim);
  8840. return true;
  8841. }
  8842. bool Unit::AttackStop()
  8843. {
  8844. if(!m_attacking)
  8845. return false;
  8846. Unit* pVictim = m_attacking;
  8847. m_attacking->_removeAttacker(this);
  8848. m_attacking = NULL;
  8849. // Clear our target
  8850. SetTarget(0);
  8851. ClearUnitState(UNIT_STAT_MELEE_ATTACKING);
  8852. InterruptSpell(CURRENT_MELEE_SPELL);
  8853. // reset only at real combat stop
  8854. if(Creature* pCreature = ToCreature())
  8855. {
  8856. pCreature->SetNoCallAssistance(false);
  8857. if(pCreature->HasSearchedAssistance())
  8858. {
  8859. pCreature->SetNoSearchAssistance(false);
  8860. UpdateSpeed(MOVE_RUN, false);
  8861. }
  8862. }
  8863. SendMeleeAttackStop(pVictim);
  8864. return true;
  8865. }
  8866. void Unit::CombatStop(bool includingCast)
  8867. {
  8868. if(includingCast && IsNonMeleeSpellCasted(false))
  8869. InterruptNonMeleeSpells(false);
  8870. AttackStop();
  8871. RemoveAllAttackers();
  8872. if(GetTypeId() == TYPEID_PLAYER)
  8873. ToPlayer()->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
  8874. ClearInCombat();
  8875. }
  8876. void Unit::CombatStopWithPets(bool includingCast)
  8877. {
  8878. CombatStop(includingCast);
  8879. for(ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
  8880. (*itr)->CombatStop(includingCast);
  8881. }
  8882. bool Unit::isAttackingPlayer() const
  8883. {
  8884. if(HasUnitState(UNIT_STAT_ATTACK_PLAYER))
  8885. return true;
  8886. for(ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
  8887. if((*itr)->isAttackingPlayer())
  8888. return true;
  8889. for(uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
  8890. if(m_SummonSlot[i])
  8891. if(Creature* summon = GetMap()->GetCreature(m_SummonSlot[i]))
  8892. if(summon->isAttackingPlayer())
  8893. return true;
  8894. return false;
  8895. }
  8896. void Unit::RemoveAllAttackers()
  8897. {
  8898. while(!m_attackers.empty())
  8899. {
  8900. AttackerSet::iterator iter = m_attackers.begin();
  8901. if(!(*iter)->AttackStop())
  8902. {
  8903. sLog->outError("WORLD: Unit has an attacker that isn't attacking it!");
  8904. m_attackers.erase(iter);
  8905. }
  8906. }
  8907. }
  8908. void Unit::ModifyAuraState(AuraState flag, bool apply)
  8909. {
  8910. if(apply)
  8911. {
  8912. if(!HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)))
  8913. {
  8914. SetFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
  8915. if(GetTypeId() == TYPEID_PLAYER)
  8916. {
  8917. PlayerSpellMap const& sp_list = ToPlayer()->GetSpellMap();
  8918. for(PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
  8919. {
  8920. if(itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled)
  8921. continue;
  8922. SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first);
  8923. if(!spellInfo || !IsPassiveSpell(itr->first))
  8924. continue;
  8925. if(spellInfo->CasterAuraState == uint32(flag))
  8926. CastSpell(this, itr->first, true, NULL);
  8927. }
  8928. }
  8929. else if(Pet* pet = ToCreature()->ToPet())
  8930. {
  8931. for(PetSpellMap::const_iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr)
  8932. {
  8933. if(itr->second.state == PETSPELL_REMOVED)
  8934. continue;
  8935. SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first);
  8936. if(!spellInfo || !IsPassiveSpell(itr->first))
  8937. continue;
  8938. if(spellInfo->CasterAuraState == uint32(flag))
  8939. CastSpell(this, itr->first, true, NULL);
  8940. }
  8941. }
  8942. }
  8943. }
  8944. else
  8945. {
  8946. if(HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)))
  8947. {
  8948. RemoveFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
  8949. if(flag != AURA_STATE_ENRAGE) // enrage aura state triggering continues auras
  8950. {
  8951. Unit::AuraApplicationMap& tAuras = GetAppliedAuras();
  8952. for(Unit::AuraApplicationMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
  8953. {
  8954. SpellEntry const* spellProto = (*itr).second->GetBase()->GetSpellProto();
  8955. if(spellProto->CasterAuraState == uint32(flag))
  8956. RemoveAura(itr);
  8957. else
  8958. ++itr;
  8959. }
  8960. }
  8961. }
  8962. }
  8963. }
  8964. uint32 Unit::BuildAuraStateUpdateForTarget(Unit* target) const
  8965. {
  8966. uint32 auraStates = GetUInt32Value(UNIT_FIELD_AURASTATE) &~(PER_CASTER_AURA_STATE_MASK);
  8967. for(AuraStateAurasMap::const_iterator itr = m_auraStateAuras.begin(); itr != m_auraStateAuras.end(); ++itr)
  8968. if((1<<(itr->first-1)) & PER_CASTER_AURA_STATE_MASK)
  8969. if(itr->second->GetBase()->GetCasterGUID() == target->GetGUID())
  8970. auraStates |= (1<<(itr->first-1));
  8971. return auraStates;
  8972. }
  8973. bool Unit::HasAuraState(AuraState flag, SpellEntry const* spellProto, Unit const* Caster) const
  8974. {
  8975. if(Caster)
  8976. {
  8977. if(spellProto)
  8978. {
  8979. AuraEffectList const& stateAuras = Caster->GetAuraEffectsByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE);
  8980. for(AuraEffectList::const_iterator j = stateAuras.begin(); j != stateAuras.end(); ++j)
  8981. if((*j)->IsAffectedOnSpell(spellProto))
  8982. return true;
  8983. }
  8984. // Check per caster aura state
  8985. // If aura with aurastate by caster not found return false
  8986. if((1<<(flag-1)) & PER_CASTER_AURA_STATE_MASK)
  8987. {
  8988. for(AuraStateAurasMap::const_iterator itr = m_auraStateAuras.lower_bound(flag); itr != m_auraStateAuras.upper_bound(flag); ++itr)
  8989. if(itr->second->GetBase()->GetCasterGUID() == Caster->GetGUID())
  8990. return true;
  8991. return false;
  8992. }
  8993. }
  8994. return HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
  8995. }
  8996. Unit* Unit::GetOwner() const
  8997. {
  8998. if(uint64 ownerid = GetOwnerGUID())
  8999. {
  9000. return ObjectAccessor::GetUnit(*this, ownerid);
  9001. }
  9002. return NULL;
  9003. }
  9004. Unit* Unit::GetCharmer() const
  9005. {
  9006. if(uint64 charmerid = GetCharmerGUID())
  9007. return ObjectAccessor::GetUnit(*this, charmerid);
  9008. return NULL;
  9009. }
  9010. Player* Unit::GetCharmerOrOwnerPlayerOrPlayerItself() const
  9011. {
  9012. uint64 guid = GetCharmerOrOwnerGUID();
  9013. if(IS_PLAYER_GUID(guid))
  9014. return ObjectAccessor::GetPlayer(*this, guid);
  9015. return GetTypeId() == TYPEID_PLAYER ? (Player*)this : NULL;
  9016. }
  9017. Minion *Unit::GetFirstMinion() const
  9018. {
  9019. if(uint64 pet_guid = GetMinionGUID())
  9020. {
  9021. if(Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, pet_guid))
  9022. if(pet->HasUnitTypeMask(UNIT_MASK_MINION))
  9023. return (Minion*)pet;
  9024. sLog->outError("Unit::GetFirstMinion: Minion %u not exist.", GUID_LOPART(pet_guid));
  9025. const_cast<Unit*>(this)->SetMinionGUID(0);
  9026. }
  9027. return NULL;
  9028. }
  9029. Guardian* Unit::GetGuardianPet() const
  9030. {
  9031. if(uint64 pet_guid = GetPetGUID())
  9032. {
  9033. if(Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, pet_guid))
  9034. if(pet->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
  9035. return (Guardian*)pet;
  9036. sLog->outCrash("Unit::GetGuardianPet: Guardian " UI64FMTD " not exist.", pet_guid);
  9037. const_cast<Unit*>(this)->SetPetGUID(0);
  9038. }
  9039. return NULL;
  9040. }
  9041. Unit* Unit::GetCharm() const
  9042. {
  9043. if(uint64 charm_guid = GetCharmGUID())
  9044. {
  9045. if(Unit* pet = ObjectAccessor::GetUnit(*this, charm_guid))
  9046. return pet;
  9047. sLog->outError("Unit::GetCharm: Charmed creature %u not exist.", GUID_LOPART(charm_guid));
  9048. const_cast<Unit*>(this)->SetUInt64Value(UNIT_FIELD_CHARM, 0);
  9049. }
  9050. return NULL;
  9051. }
  9052. void Unit::SetMinion(Minion *minion, bool apply)
  9053. {
  9054. sLog->outDebug(LOG_FILTER_UNITS, "SetMinion %u for %u, apply %u", minion->GetEntry(), GetEntry(), apply);
  9055. if(apply)
  9056. {
  9057. if(!minion->AddUInt64Value(UNIT_FIELD_SUMMONEDBY, GetGUID()))
  9058. {
  9059. sLog->outCrash("SetMinion: Minion %u is not the minion of owner %u", minion->GetEntry(), GetEntry());
  9060. return;
  9061. }
  9062. m_Controlled.insert(minion);
  9063. if(GetTypeId() == TYPEID_PLAYER)
  9064. {
  9065. minion->m_ControlledByPlayer = true;
  9066. minion->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
  9067. }
  9068. // Can only have one pet. If a new one is summoned, dismiss the old one.
  9069. if(minion->IsGuardianPet())
  9070. {
  9071. if(Guardian* pPet = GetGuardianPet())
  9072. {
  9073. if(pPet && pPet != minion && (pPet->isPet() || minion->isPet() || pPet->GetEntry() != minion->GetEntry()))
  9074. { // Remove / UnSummon Existing Minion or Pet
  9075. if(pPet->isPet())
  9076. ((Pet*)pPet)->Remove(PET_SAVE_AS_CURRENT);
  9077. else
  9078. pPet->UnSummon();
  9079. SetPetGUID(minion->GetGUID());
  9080. SetMinionGUID(0);
  9081. }
  9082. } else {
  9083. SetPetGUID(minion->GetGUID());
  9084. SetMinionGUID(0);
  9085. }
  9086. }
  9087. if(minion->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN))
  9088. AddUInt64Value(UNIT_FIELD_SUMMON, minion->GetGUID());
  9089. if(minion->m_Properties && minion->m_Properties->Type == SUMMON_TYPE_MINIPET)
  9090. SetCritterGUID(minion->GetGUID());
  9091. // PvP, FFAPvP
  9092. minion->SetByteValue(UNIT_FIELD_BYTES_2, 1, GetByteValue(UNIT_FIELD_BYTES_2, 1));
  9093. // FIXME: hack, speed must be set only at follow
  9094. if(GetTypeId() == TYPEID_PLAYER && minion->isPet())
  9095. for(uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
  9096. minion->SetSpeed(UnitMoveType(i), m_speed_rate[i], true);
  9097. // Ghoul pets have energy instead of mana (is anywhere better place for this code?)
  9098. if(minion->IsPetGhoul() || minion->GetEntry() == 30230)
  9099. minion->setPowerType(POWER_ENERGY);
  9100. if(GetTypeId() == TYPEID_PLAYER)
  9101. {
  9102. // Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again
  9103. SpellEntry const* spellInfo = sSpellStore.LookupEntry(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
  9104. if(spellInfo && (spellInfo->Attributes & SPELL_ATTR0_DISABLED_WHILE_ACTIVE))
  9105. ToPlayer()->AddSpellAndCategoryCooldowns(spellInfo, 0, NULL, true);
  9106. }
  9107. }
  9108. else
  9109. {
  9110. if(minion->GetOwnerGUID() != GetGUID())
  9111. {
  9112. sLog->outCrash("SetMinion: Minion %u is not the minion of owner %u", minion->GetEntry(), GetEntry());
  9113. return;
  9114. }
  9115. m_Controlled.erase(minion);
  9116. if(minion->m_Properties && minion->m_Properties->Type == SUMMON_TYPE_MINIPET)
  9117. {
  9118. if(GetCritterGUID() == minion->GetGUID())
  9119. SetCritterGUID(0);
  9120. }
  9121. if(minion->IsGuardianPet())
  9122. {
  9123. if(GetPetGUID() == minion->GetGUID())
  9124. SetPetGUID(0);
  9125. }
  9126. else if(minion->isTotem())
  9127. {
  9128. // All summoned by totem minions must disappear when it is removed.
  9129. if(SpellEntry const* spInfo = sSpellStore.LookupEntry(minion->ToTotem()->GetSpell()))
  9130. for(int i = 0; i < MAX_SPELL_EFFECTS; ++i)
  9131. {
  9132. if(spInfo->Effect[i] != SPELL_EFFECT_SUMMON)
  9133. continue;
  9134. RemoveAllMinionsByEntry(spInfo->EffectMiscValue[i]);
  9135. }
  9136. }
  9137. if(GetTypeId() == TYPEID_PLAYER)
  9138. {
  9139. if(getDeathState() == GHOULED)
  9140. {
  9141. RemoveAurasDueToSpell(46619);
  9142. RemoveAurasDueToSpell(62218);
  9143. }
  9144. SpellEntry const* spellInfo = sSpellStore.LookupEntry(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
  9145. // Remove infinity cooldown
  9146. if(spellInfo && (spellInfo->Attributes & SPELL_ATTR0_DISABLED_WHILE_ACTIVE))
  9147. ToPlayer()->SendCooldownEvent(spellInfo);
  9148. }
  9149. //if(minion->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
  9150. {
  9151. if(RemoveUInt64Value(UNIT_FIELD_SUMMON, minion->GetGUID()))
  9152. {
  9153. // Check if there is another minion
  9154. for(ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
  9155. {
  9156. // do not use this check, creature do not have charm guid
  9157. if(GetGUID() == (*itr)->GetCharmerGUID())
  9158. continue;
  9159. if((*itr)->GetOwnerGUID() != GetGUID())
  9160. {
  9161. OutDebugInfo();
  9162. (*itr)->OutDebugInfo();
  9163. ASSERT(false);
  9164. }
  9165. ASSERT((*itr)->GetTypeId() == TYPEID_UNIT);
  9166. if(!(*itr)->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN))
  9167. continue;
  9168. if(AddUInt64Value(UNIT_FIELD_SUMMON, (*itr)->GetGUID()))
  9169. {
  9170. // show another pet bar if there is no charm bar
  9171. if(GetTypeId() == TYPEID_PLAYER && !GetCharmGUID())
  9172. {
  9173. if((*itr)->isPet())
  9174. ToPlayer()->PetSpellInitialize();
  9175. else
  9176. ToPlayer()->CharmSpellInitialize();
  9177. }
  9178. }
  9179. break;
  9180. }
  9181. }
  9182. }
  9183. }
  9184. }
  9185. void Unit::GetAllMinionsByEntry(std::list<Creature*>& Minions, uint32 entry)
  9186. {
  9187. for(Unit::ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end();)
  9188. {
  9189. Unit* unit = *itr;
  9190. ++itr;
  9191. if(unit->GetEntry() == entry && unit->GetTypeId() == TYPEID_UNIT
  9192. && unit->ToCreature()->isSummon()) // minion, actually
  9193. Minions.push_back(unit->ToCreature());
  9194. }
  9195. }
  9196. void Unit::RemoveAllMinionsByEntry(uint32 entry)
  9197. {
  9198. for(Unit::ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end();)
  9199. {
  9200. Unit* unit = *itr;
  9201. ++itr;
  9202. if(unit->GetEntry() == entry && unit->GetTypeId() == TYPEID_UNIT
  9203. && unit->ToCreature()->isSummon()) // minion, actually
  9204. unit->ToTempSummon()->UnSummon();
  9205. // i think this is safe because i have never heard that a despawned minion will trigger a same minion
  9206. }
  9207. }
  9208. void Unit::SetCharm(Unit* charm, bool apply)
  9209. {
  9210. if(apply)
  9211. {
  9212. if(GetTypeId() == TYPEID_PLAYER)
  9213. {
  9214. if(!AddUInt64Value(UNIT_FIELD_CHARM, charm->GetGUID()))
  9215. sLog->outCrash("Player %s is trying to charm unit %u, but it already has a charmed unit " UI64FMTD "", GetName(), charm->GetEntry(), GetCharmGUID());
  9216. charm->m_ControlledByPlayer = true;
  9217. // TODO: maybe we can use this flag to check if controlled by player
  9218. charm->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
  9219. }
  9220. else
  9221. charm->m_ControlledByPlayer = false;
  9222. // PvP, FFAPvP
  9223. charm->SetByteValue(UNIT_FIELD_BYTES_2, 1, GetByteValue(UNIT_FIELD_BYTES_2, 1));
  9224. if(!charm->AddUInt64Value(UNIT_FIELD_CHARMEDBY, GetGUID()))
  9225. sLog->outCrash("Unit %u is being charmed, but it already has a charmer " UI64FMTD "", charm->GetEntry(), charm->GetCharmerGUID());
  9226. if(charm->HasUnitMovementFlag(MOVEMENTFLAG_WALKING))
  9227. {
  9228. charm->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
  9229. charm->SendMovementFlagUpdate();
  9230. }
  9231. m_Controlled.insert(charm);
  9232. }
  9233. else
  9234. {
  9235. if(GetTypeId() == TYPEID_PLAYER)
  9236. {
  9237. if(!RemoveUInt64Value(UNIT_FIELD_CHARM, charm->GetGUID()))
  9238. sLog->outCrash("Player %s is trying to uncharm unit %u, but it has another charmed unit " UI64FMTD "", GetName(), charm->GetEntry(), GetCharmGUID());
  9239. }
  9240. if(!charm->RemoveUInt64Value(UNIT_FIELD_CHARMEDBY, GetGUID()))
  9241. sLog->outCrash("Unit %u is being uncharmed, but it has another charmer " UI64FMTD "", charm->GetEntry(), charm->GetCharmerGUID());
  9242. if(charm->GetTypeId() == TYPEID_PLAYER)
  9243. {
  9244. charm->m_ControlledByPlayer = true;
  9245. charm->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
  9246. charm->ToPlayer()->UpdatePvPState();
  9247. }
  9248. else if(Player* player = charm->GetCharmerOrOwnerPlayerOrPlayerItself())
  9249. {
  9250. charm->m_ControlledByPlayer = true;
  9251. charm->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
  9252. charm->SetByteValue(UNIT_FIELD_BYTES_2, 1, player->GetByteValue(UNIT_FIELD_BYTES_2, 1));
  9253. }
  9254. else
  9255. {
  9256. charm->m_ControlledByPlayer = false;
  9257. charm->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
  9258. charm->SetByteValue(UNIT_FIELD_BYTES_2, 1, 0);
  9259. }
  9260. if(charm->GetTypeId() == TYPEID_PLAYER
  9261. || !charm->ToCreature()->HasUnitTypeMask(UNIT_MASK_MINION)
  9262. || charm->GetOwnerGUID() != GetGUID())
  9263. m_Controlled.erase(charm);
  9264. }
  9265. }
  9266. int32 Unit::DealHeal(Unit* victim, uint32 addhealth)
  9267. {
  9268. int32 gain = 0;
  9269. if(victim->IsAIEnabled)
  9270. victim->GetAI()->HealReceived(this, addhealth);
  9271. if(IsAIEnabled)
  9272. GetAI()->HealDone(victim, addhealth);
  9273. if(addhealth)
  9274. gain = victim->ModifyHealth(int32(addhealth));
  9275. Unit* unit = this;
  9276. if(GetTypeId() == TYPEID_UNIT && ToCreature()->isTotem())
  9277. unit = GetOwner();
  9278. if(Player* player = unit->ToPlayer())
  9279. {
  9280. if(Battleground* pBG = player->GetBattleground())
  9281. pBG->UpdatePlayerScore(player, SCORE_HEALING_DONE, gain);
  9282. // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria)
  9283. if(gain)
  9284. player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, victim);
  9285. player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED, addhealth);
  9286. }
  9287. if(Player* player = victim->ToPlayer())
  9288. {
  9289. player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED, gain);
  9290. player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED, addhealth);
  9291. }
  9292. return gain;
  9293. }
  9294. Unit* Unit::SelectMagnetTarget(Unit* victim, SpellEntry const* spellInfo)
  9295. {
  9296. if(!victim)
  9297. return NULL;
  9298. // Magic case
  9299. if(spellInfo && (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_NONE || spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC))
  9300. {
  9301. // Patch 1.2 notes: Spell Reflection no longer reflects abilities
  9302. if(spellInfo->Attributes & SPELL_ATTR0_ABILITY || spellInfo->AttributesEx & SPELL_ATTR1_CANT_BE_REDIRECTED || spellInfo->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
  9303. return victim;
  9304. // I am not sure if this should be redirected.
  9305. if(spellInfo->DmgClass == SPELL_DAMAGE_CLASS_NONE)
  9306. return victim;
  9307. Unit::AuraEffectList const& magnetAuras = victim->GetAuraEffectsByType(SPELL_AURA_SPELL_MAGNET);
  9308. for(Unit::AuraEffectList::const_iterator itr = magnetAuras.begin(); itr != magnetAuras.end(); ++itr)
  9309. if(Unit* magnet = (*itr)->GetBase()->GetUnitOwner())
  9310. if(magnet->isAlive() && IsWithinLOSInMap(magnet))
  9311. {
  9312. (*itr)->GetBase()->DropCharge(AURA_REMOVE_BY_EXPIRE);
  9313. return magnet;
  9314. }
  9315. }
  9316. // Melee && ranged case
  9317. else
  9318. {
  9319. AuraEffectList const& hitTriggerAuras = victim->GetAuraEffectsByType(SPELL_AURA_ADD_CASTER_HIT_TRIGGER);
  9320. for(AuraEffectList::const_iterator i = hitTriggerAuras.begin(); i != hitTriggerAuras.end(); ++i)
  9321. if(Unit* magnet = (*i)->GetBase()->GetCaster())
  9322. if(magnet->isAlive() && magnet->IsWithinLOSInMap(this))
  9323. if(roll_chance_i((*i)->GetAmount()))
  9324. {
  9325. (*i)->GetBase()->DropCharge(AURA_REMOVE_BY_EXPIRE);
  9326. return magnet;
  9327. }
  9328. }
  9329. return victim;
  9330. }
  9331. Unit* Unit::GetFirstControlled() const
  9332. {
  9333. // Sequence: charmed, pet, other guardians
  9334. Unit* unit = GetCharm();
  9335. if(!unit)
  9336. if(uint64 guid = GetUInt64Value(UNIT_FIELD_SUMMON))
  9337. unit = ObjectAccessor::GetUnit(*this, guid);
  9338. return unit;
  9339. }
  9340. void Unit::RemoveAllControlled()
  9341. {
  9342. // possessed pet and vehicle
  9343. if(GetTypeId() == TYPEID_PLAYER)
  9344. ToPlayer()->StopCastingCharm();
  9345. while(!m_Controlled.empty())
  9346. {
  9347. Unit* target = *m_Controlled.begin();
  9348. m_Controlled.erase(m_Controlled.begin());
  9349. if(target->GetCharmerGUID() == GetGUID())
  9350. target->RemoveCharmAuras();
  9351. else if(target->GetOwnerGUID() == GetGUID() && target->isSummon())
  9352. target->ToTempSummon()->UnSummon();
  9353. else
  9354. sLog->outError("Unit %u is trying to release unit %u which is neither charmed nor owned by it", GetEntry(), target->GetEntry());
  9355. }
  9356. if(GetPetGUID())
  9357. sLog->outCrash("Unit %u is not able to release its pet " UI64FMTD, GetEntry(), GetPetGUID());
  9358. if(GetMinionGUID())
  9359. sLog->outCrash("Unit %u is not able to release its minion " UI64FMTD, GetEntry(), GetMinionGUID());
  9360. if(GetCharmGUID())
  9361. sLog->outCrash("Unit %u is not able to release its charm " UI64FMTD, GetEntry(), GetCharmGUID());
  9362. }
  9363. Unit* Unit::GetNextRandomRaidMemberOrPet(float radius)
  9364. {
  9365. Player* player = NULL;
  9366. if(GetTypeId() == TYPEID_PLAYER)
  9367. player = ToPlayer();
  9368. // Should we enable this also for charmed units?
  9369. else if(GetTypeId() == TYPEID_UNIT && ToCreature()->isPet())
  9370. player = GetOwner()->ToPlayer();
  9371. if(!player)
  9372. return NULL;
  9373. Group* pGroup = player->GetGroup();
  9374. // When there is no group check pet presence
  9375. if(!pGroup)
  9376. {
  9377. // We are pet now, return owner
  9378. if(player != this)
  9379. return IsWithinDistInMap(player, radius) ? player : NULL;
  9380. Unit* pet = GetGuardianPet();
  9381. // No pet, no group, nothing to return
  9382. if(!pet)
  9383. return NULL;
  9384. // We are owner now, return pet
  9385. return IsWithinDistInMap(pet, radius) ? pet : NULL;
  9386. }
  9387. std::vector<Unit*> nearMembers;
  9388. // reserve place for players and pets because resizing vector every unit push is unefficient (vector is reallocated then)
  9389. nearMembers.reserve(pGroup->GetMembersCount() * 2);
  9390. for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
  9391. if(Player* Target = itr->getSource())
  9392. {
  9393. // IsHostileTo check duel and controlled by enemy
  9394. if(Target != this && Target->isAlive() && IsWithinDistInMap(Target, radius) && !IsHostileTo(Target))
  9395. nearMembers.push_back(Target);
  9396. // Push player's pet to vector
  9397. if(Unit* pet = Target->GetGuardianPet())
  9398. if(pet != this && pet->isAlive() && IsWithinDistInMap(pet, radius) && !IsHostileTo(pet))
  9399. nearMembers.push_back(pet);
  9400. }
  9401. if(nearMembers.empty())
  9402. return NULL;
  9403. uint32 randTarget = urand(0, nearMembers.size()-1);
  9404. return nearMembers[randTarget];
  9405. }
  9406. // only called in Player::SetSeer
  9407. // so move it to Player?
  9408. void Unit::AddPlayerToVision(Player* plr)
  9409. {
  9410. if(m_sharedVision.empty())
  9411. {
  9412. setActive(true);
  9413. SetWorldObject(true);
  9414. }
  9415. m_sharedVision.push_back(plr);
  9416. }
  9417. // only called in Player::SetSeer
  9418. void Unit::RemovePlayerFromVision(Player* plr)
  9419. {
  9420. m_sharedVision.remove(plr);
  9421. if(m_sharedVision.empty())
  9422. {
  9423. setActive(false);
  9424. SetWorldObject(false);
  9425. }
  9426. }
  9427. void Unit::RemoveBindSightAuras()
  9428. {
  9429. RemoveAurasByType(SPELL_AURA_BIND_SIGHT);
  9430. }
  9431. void Unit::RemoveCharmAuras()
  9432. {
  9433. RemoveAurasByType(SPELL_AURA_MOD_CHARM);
  9434. RemoveAurasByType(SPELL_AURA_MOD_POSSESS_PET);
  9435. RemoveAurasByType(SPELL_AURA_MOD_POSSESS);
  9436. RemoveAurasByType(SPELL_AURA_AOE_CHARM);
  9437. }
  9438. void Unit::UnsummonAllTotems()
  9439. {
  9440. for(uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
  9441. {
  9442. if(!m_SummonSlot[i])
  9443. continue;
  9444. if(Creature* OldTotem = GetMap()->GetCreature(m_SummonSlot[i]))
  9445. if(OldTotem->isSummon())
  9446. OldTotem->ToTempSummon()->UnSummon();
  9447. }
  9448. }
  9449. void Unit::SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical)
  9450. {
  9451. // we guess size
  9452. WorldPacket data(SMSG_SPELLHEALLOG, (8+8+4+4+4+4+1+1));
  9453. data.append(victim->GetPackGUID());
  9454. data.append(GetPackGUID());
  9455. data << uint32(SpellID);
  9456. data << uint32(Damage);
  9457. data << uint32(OverHeal);
  9458. data << uint32(Absorb); // Absorb amount
  9459. data << uint8(critical ? 1 : 0);
  9460. data << uint8(0); // unused
  9461. SendMessageToSet(&data, true);
  9462. }
  9463. int32 Unit::HealBySpell(Unit* victim, SpellEntry const* spellInfo, uint32 addHealth, bool critical)
  9464. {
  9465. uint32 absorb = 0;
  9466. // calculate heal absorb and reduce healing
  9467. CalcHealAbsorb(victim, spellInfo, addHealth, absorb);
  9468. int32 gain = DealHeal(victim, addHealth);
  9469. SendHealSpellLog(victim, spellInfo->Id, addHealth, uint32(addHealth - gain), absorb, critical);
  9470. return gain;
  9471. }
  9472. void Unit::SendEnergizeSpellLog(Unit* victim, uint32 spellID, uint32 damage, Powers powerType)
  9473. {
  9474. WorldPacket data(SMSG_SPELLENERGIZELOG, (8+8+4+4+4+1));
  9475. data.append(victim->GetPackGUID());
  9476. data.append(GetPackGUID());
  9477. data << uint32(spellID);
  9478. data << uint32(powerType);
  9479. data << uint32(damage);
  9480. SendMessageToSet(&data, true);
  9481. }
  9482. void Unit::EnergizeBySpell(Unit* victim, uint32 spellID, uint32 damage, Powers powerType)
  9483. {
  9484. SendEnergizeSpellLog(victim, spellID, damage, powerType);
  9485. // needs to be called after sending spell log
  9486. victim->ModifyPower(powerType, damage);
  9487. SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellID);
  9488. victim->getHostileRefManager().threatAssist(this, float(damage) * 0.5f, spellInfo);
  9489. }
  9490. uint32 Unit::SpellDamageBonus(Unit* victim, SpellEntry const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack)
  9491. {
  9492. if(!spellProto || !victim || damagetype == DIRECT_DAMAGE)
  9493. return pdamage;
  9494. // small exception for Deep Wounds, can't find any general rule
  9495. // should ignore ALL damage mods, they already calculated in trigger spell
  9496. if(spellProto->Id == 12721) // Deep Wounds
  9497. return pdamage;
  9498. // For totems get damage bonus from owner
  9499. if(GetTypeId() == TYPEID_UNIT && ToCreature()->isTotem())
  9500. if(Unit* owner = GetOwner())
  9501. return owner->SpellDamageBonus(victim, spellProto, pdamage, damagetype);
  9502. // Taken/Done total percent damage auras
  9503. float DoneTotalMod = 1.0f;
  9504. float ApCoeffMod = 1.0f;
  9505. int32 DoneTotal = 0;
  9506. int32 TakenTotal = 0;
  9507. // ..done
  9508. // Pet damage?
  9509. if(GetTypeId() == TYPEID_UNIT && !ToCreature()->isPet())
  9510. DoneTotalMod *= ToCreature()->GetSpellDamageMod(ToCreature()->GetCreatureInfo()->rank);
  9511. AuraEffectList const& mModDamagePercentDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
  9512. for(AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
  9513. if ((*i)->GetMiscValue() & GetSpellSchoolMask(spellProto) && !(GetSpellSchoolMask(spellProto) & SPELL_SCHOOL_MASK_NORMAL))
  9514. {
  9515. if((*i)->GetSpellProto()->EquippedItemClass == -1)
  9516. AddPctN(DoneTotalMod, (*i)->GetAmount());
  9517. else if(!((*i)->GetSpellProto()->AttributesEx5 & SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK))
  9518. {
  9519. if((*i)->GetSpellProto()->EquippedItemClass & spellProto->EquippedItemClass)
  9520. if(((*i)->GetSpellProto()->EquippedItemSubClassMask == 0) ||
  9521. ((*i)->GetSpellProto()->EquippedItemSubClassMask & spellProto->EquippedItemSubClassMask))
  9522. AddPctN(DoneTotalMod, (*i)->GetAmount());
  9523. }
  9524. else if(ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*i)->GetSpellProto()))
  9525. AddPctN(DoneTotalMod, (*i)->GetAmount());
  9526. }
  9527. uint32 creatureTypeMask = victim->GetCreatureTypeMask();
  9528. // Add flat bonus from spell damage versus
  9529. DoneTotal += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS, creatureTypeMask);
  9530. AuraEffectList const& mDamageDoneVersus = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS);
  9531. for(AuraEffectList::const_iterator i = mDamageDoneVersus.begin(); i != mDamageDoneVersus.end(); ++i)
  9532. if(creatureTypeMask & uint32((*i)->GetMiscValue()))
  9533. AddPctN(DoneTotalMod, (*i)->GetAmount());
  9534. // bonus against aurastate
  9535. AuraEffectList const& mDamageDoneVersusAurastate = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE);
  9536. for(AuraEffectList::const_iterator i = mDamageDoneVersusAurastate.begin(); i != mDamageDoneVersusAurastate.end(); ++i)
  9537. if(victim->HasAuraState(AuraState((*i)->GetMiscValue())))
  9538. AddPctN(DoneTotalMod, (*i)->GetAmount());
  9539. // done scripted mod (take it from owner)
  9540. Unit* owner = GetOwner() ? GetOwner() : this;
  9541. AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
  9542. for(AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
  9543. {
  9544. if(!(*i)->IsAffectedOnSpell(spellProto))
  9545. continue;
  9546. switch((*i)->GetMiscValue())
  9547. {
  9548. case 4920: // Molten Fury
  9549. case 4919:
  9550. case 6917: // Death's Embrace
  9551. case 6926:
  9552. case 6928:
  9553. {
  9554. if(victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
  9555. AddPctN(DoneTotalMod, (*i)->GetAmount());
  9556. break;
  9557. }
  9558. // Soul Siphon
  9559. case 4992:
  9560. case 4993:
  9561. {
  9562. // effect 1 m_amount
  9563. int32 maxPercent = (*i)->GetAmount();
  9564. // effect 0 m_amount
  9565. int32 stepPercent = CalculateSpellDamage(this, (*i)->GetSpellProto(), 0);
  9566. // count affliction effects and calc additional damage in percentage
  9567. int32 modPercent = 0;
  9568. AuraApplicationMap const& victimAuras = victim->GetAppliedAuras();
  9569. for(AuraApplicationMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr)
  9570. {
  9571. Aura const* aura = itr->second->GetBase();
  9572. SpellEntry const* m_spell = aura->GetSpellProto();
  9573. if(m_spell->SpellFamilyName != SPELLFAMILY_WARLOCK || !(m_spell->SpellFamilyFlags[1] & 0x0004071B || m_spell->SpellFamilyFlags[0] & 0x8044C402))
  9574. continue;
  9575. modPercent += stepPercent * aura->GetStackAmount();
  9576. if(modPercent >= maxPercent)
  9577. {
  9578. modPercent = maxPercent;
  9579. break;
  9580. }
  9581. }
  9582. AddPctN(DoneTotalMod, modPercent);
  9583. break;
  9584. }
  9585. case 6916: // Death's Embrace
  9586. case 6925:
  9587. case 6927:
  9588. if(HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, spellProto, this))
  9589. AddPctN(DoneTotalMod, (*i)->GetAmount());
  9590. break;
  9591. case 5481: // Starfire Bonus
  9592. {
  9593. if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x200002, 0, 0))
  9594. AddPctN(DoneTotalMod, (*i)->GetAmount());
  9595. break;
  9596. }
  9597. case 4418: // Increased Shock Damage
  9598. case 4554: // Increased Lightning Damage
  9599. case 4555: // Improved Moonfire
  9600. case 5142: // Increased Lightning Damage
  9601. case 5147: // Improved Consecration / Libram of Resurgence
  9602. case 5148: // Idol of the Shooting Star
  9603. case 6008: // Increased Lightning Damage
  9604. case 8627: // Totem of Hex
  9605. {
  9606. DoneTotal += (*i)->GetAmount();
  9607. break;
  9608. }
  9609. // Tundra Stalker
  9610. // Merciless Combat
  9611. case 7277:
  9612. {
  9613. // Merciless Combat
  9614. if((*i)->GetSpellProto()->SpellIconID == 2656)
  9615. {
  9616. if(!victim->HealthAbovePct(35))
  9617. AddPctN(DoneTotalMod, (*i)->GetAmount());
  9618. }
  9619. // Tundra Stalker
  9620. else
  9621. {
  9622. // Frost Fever (target debuff)
  9623. if(victim->HasAura(55095))
  9624. AddPctN(DoneTotalMod, (*i)->GetAmount());
  9625. break;
  9626. }
  9627. break;
  9628. }
  9629. // Rage of Rivendare
  9630. case 7293:
  9631. {
  9632. if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, 0, 0x02000000, 0))
  9633. {
  9634. if(SpellChainNode const* chain = sSpellMgr->GetSpellChainNode((*i)->GetId()))
  9635. AddPctF(DoneTotalMod, chain->rank * 2.0f);
  9636. }
  9637. break;
  9638. }
  9639. // Twisted Faith
  9640. case 7377:
  9641. {
  9642. if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0, 0, GetGUID()))
  9643. AddPctN(DoneTotalMod, (*i)->GetAmount());
  9644. break;
  9645. }
  9646. // Marked for Death
  9647. case 7598:
  9648. case 7599:
  9649. case 7600:
  9650. case 7601:
  9651. case 7602:
  9652. {
  9653. if(victim->GetAuraEffect(SPELL_AURA_MOD_STALKED, SPELLFAMILY_HUNTER, 0x400, 0, 0))
  9654. AddPctN(DoneTotalMod, (*i)->GetAmount());
  9655. break;
  9656. }
  9657. // Dirty Deeds
  9658. case 6427:
  9659. case 6428:
  9660. case 6579:
  9661. case 6580:
  9662. {
  9663. if(victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
  9664. {
  9665. // effect 0 have expected value but in negative state
  9666. int32 bonus = -(*i)->GetBase()->GetEffect(0)->GetAmount();
  9667. AddPctN(DoneTotalMod, bonus);
  9668. }
  9669. break;
  9670. }
  9671. }
  9672. }
  9673. // Custom scripted damage
  9674. switch(spellProto->SpellFamilyName)
  9675. {
  9676. case SPELLFAMILY_MAGE:
  9677. // Ice Lance
  9678. if(spellProto->SpellIconID == 186) {
  9679. if(victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this)) {
  9680. // Glyph of Ice Lance
  9681. if(owner->HasAura(56377) && victim->getLevel() > owner->getLevel())
  9682. DoneTotalMod *= 4.0f;
  9683. else
  9684. DoneTotalMod *= 3.0f;
  9685. }
  9686. } // Torment the weak
  9687. if(spellProto->SpellFamilyFlags[0] & 0x20600021 || spellProto->SpellFamilyFlags[1] & 0x9000) {
  9688. if(victim->HasAuraWithMechanic((1<<MECHANIC_SNARE)|(1<<MECHANIC_SLOW_ATTACK))) {
  9689. AuraEffectList const& mDumyAuras = GetAuraEffectsByType(SPELL_AURA_DUMMY);
  9690. for(AuraEffectList::const_iterator i = mDumyAuras.begin(); i != mDumyAuras.end(); ++i) {
  9691. if((*i)->GetSpellProto()->SpellIconID == 3263) {
  9692. AddPctN(DoneTotalMod, (*i)->GetAmount());
  9693. break;
  9694. }
  9695. }
  9696. }
  9697. }
  9698. break;
  9699. case SPELLFAMILY_PRIEST:
  9700. // Mind Flay
  9701. if(spellProto->SpellFamilyFlags[0] & 0x800000) {
  9702. // Glyph of Shadow Word: Pain
  9703. if(AuraEffect* aurEff = GetAuraEffect(55687, 0))
  9704. // Increase Mind Flay damage if Shadow Word: Pain present on target
  9705. if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0, 0, GetGUID()))
  9706. AddPctN(DoneTotalMod, aurEff->GetAmount());
  9707. // Twisted Faith - Mind Flay part
  9708. if(AuraEffect* aurEff = GetAuraEffect(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS, SPELLFAMILY_PRIEST, 2848, 1))
  9709. // Increase Mind Flay damage if Shadow Word: Pain present on target
  9710. if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0, 0, GetGUID()))
  9711. AddPctN(DoneTotalMod, aurEff->GetAmount());
  9712. } // Smite
  9713. else if(spellProto->SpellFamilyFlags[0] & 0x80)
  9714. {
  9715. // Glyph of Smite
  9716. if(AuraEffect* aurEff = GetAuraEffect(55692, 0))
  9717. if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x100000, 0, 0, GetGUID()))
  9718. AddPctN(DoneTotalMod, aurEff->GetAmount());
  9719. } // Shadow Word: Death
  9720. else if(spellProto->SpellFamilyFlags[1] & 0x2)
  9721. { // Glyph of Shadow Word: Death
  9722. if(AuraEffect* aurEff = GetAuraEffect(55682, 1))
  9723. if(victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT))
  9724. AddPctN(DoneTotalMod, aurEff->GetAmount());
  9725. }
  9726. break;
  9727. case SPELLFAMILY_PALADIN:
  9728. // Judgement of Vengeance/Judgement of Corruption
  9729. if((spellProto->SpellFamilyFlags[1] & 0x400000) && spellProto->SpellIconID == 2292) {
  9730. // Get stack of Holy Vengeance/Blood Corruption on the target added by caster
  9731. uint32 stacks = 0;
  9732. Unit::AuraEffectList const& auras = victim->GetAuraEffectsByType(SPELL_AURA_PERIODIC_DAMAGE);
  9733. for(Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) {
  9734. if(((*itr)->GetId() == 31803 || (*itr)->GetId() == 53742) && (*itr)->GetCasterGUID() == GetGUID())
  9735. {
  9736. stacks = (*itr)->GetBase()->GetStackAmount();
  9737. break;
  9738. }
  9739. }
  9740. // + 10% for each application of Holy Vengeance/Blood Corruption on the target
  9741. if(stacks)
  9742. AddPctU(DoneTotalMod, 10 * stacks);
  9743. }
  9744. break;
  9745. case SPELLFAMILY_DRUID:
  9746. // Thorns
  9747. if(spellProto->SpellFamilyFlags[0] & 0x100) {
  9748. // Brambles
  9749. if(AuraEffect* aurEff = GetAuraEffectOfRankedSpell(16836, 0))
  9750. AddPctN(DoneTotalMod, aurEff->GetAmount());
  9751. }
  9752. break;
  9753. case SPELLFAMILY_WARLOCK:
  9754. // Fire and Brimstone
  9755. if(spellProto->SpellFamilyFlags[1] & 0x00020040) {
  9756. if(victim->HasAuraState(AURA_STATE_CONFLAGRATE)) {
  9757. AuraEffectList const& mDumyAuras = GetAuraEffectsByType(SPELL_AURA_DUMMY);
  9758. for(AuraEffectList::const_iterator i = mDumyAuras.begin(); i != mDumyAuras.end(); ++i) {
  9759. if((*i)->GetSpellProto()->SpellIconID == 3173) {
  9760. AddPctN(DoneTotalMod, (*i)->GetAmount());
  9761. break;
  9762. }
  9763. }
  9764. }
  9765. } // Drain Soul - increased damage for targets under 25 % HP
  9766. if(spellProto->SpellFamilyFlags[0] & 0x00004000) {
  9767. if(HasAura(100001))
  9768. DoneTotalMod *= 4;
  9769. } // Shadow Bite (15% increase from each dot)
  9770. if(spellProto->SpellFamilyFlags[1] & 0x00400000 && isPet()) {
  9771. if(uint8 count = victim->GetDoTsByCaster(GetOwnerGUID()))
  9772. AddPctN(DoneTotalMod, 15 * count);
  9773. }
  9774. break;
  9775. case SPELLFAMILY_HUNTER:
  9776. // Steady Shot
  9777. if(spellProto->SpellFamilyFlags[1] & 0x1) {
  9778. if(AuraEffect* aurEff = GetAuraEffect(56826, 0)) { // Glyph of Steady Shot
  9779. if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_HUNTER, 0x00004000, 0, 0, GetGUID()))
  9780. AddPctN(DoneTotalMod, aurEff->GetAmount());
  9781. }
  9782. }
  9783. break;
  9784. case SPELLFAMILY_DEATHKNIGHT:
  9785. // Improved Icy Touch
  9786. if(spellProto->SpellFamilyFlags[0] & 0x2) {
  9787. if(AuraEffect* aurEff = GetDummyAuraEffect(SPELLFAMILY_DEATHKNIGHT, 2721, 0))
  9788. AddPctN(DoneTotalMod, aurEff->GetAmount());
  9789. } // Glacier Rot
  9790. if(spellProto->SpellFamilyFlags[0] & 0x2 || spellProto->SpellFamilyFlags[1] & 0x6) {
  9791. if(AuraEffect* aurEff = GetDummyAuraEffect(SPELLFAMILY_DEATHKNIGHT, 196, 0)) {
  9792. if(victim->GetDiseasesByCaster(owner->GetGUID()) > 0)
  9793. AddPctN(DoneTotalMod, aurEff->GetAmount());
  9794. }
  9795. } // Impurity (dummy effect)
  9796. if(GetTypeId() == TYPEID_PLAYER) {
  9797. PlayerSpellMap playerSpells = ToPlayer()->GetSpellMap();
  9798. for(PlayerSpellMap::const_iterator itr = playerSpells.begin(); itr != playerSpells.end(); ++itr)
  9799. {
  9800. if(itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled)
  9801. continue;
  9802. switch(itr->first)
  9803. {
  9804. case 49220:
  9805. case 49633:
  9806. case 49635:
  9807. case 49636:
  9808. case 49638:
  9809. {
  9810. if(SpellEntry const* proto = sSpellStore.LookupEntry(itr->first))
  9811. AddPctN(ApCoeffMod, SpellMgr::CalculateSpellEffectAmount(proto, 0));
  9812. }
  9813. break;
  9814. }
  9815. }
  9816. } // Sigil of the Vengeful Heart
  9817. if(spellProto->SpellFamilyFlags[0] & 0x2000)
  9818. {
  9819. if(AuraEffect* aurEff = GetAuraEffect(64962, EFFECT_1))
  9820. DoneTotal += aurEff->GetAmount();
  9821. }
  9822. break;
  9823. }
  9824. // ..taken
  9825. float TakenTotalMod = 1.0f;
  9826. // from positive and negative SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
  9827. // multiplicative bonus, for example Dispersion + Shadowform (0.10*0.85=0.085)
  9828. TakenTotalMod *= victim->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, GetSpellSchoolMask(spellProto));
  9829. // .. taken pct: dummy auras
  9830. AuraEffectList const& mDummyAuras = victim->GetAuraEffectsByType(SPELL_AURA_DUMMY);
  9831. for(AuraEffectList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
  9832. {
  9833. switch((*i)->GetSpellProto()->SpellIconID)
  9834. {
  9835. // Cheat Death
  9836. case 2109:
  9837. if((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
  9838. {
  9839. if(victim->GetTypeId() != TYPEID_PLAYER)
  9840. continue;
  9841. float mod = victim->ToPlayer()->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE) * (-8.0f);
  9842. AddPctF(TakenTotalMod, mod);
  9843. }
  9844. break;
  9845. // Ebon Plague
  9846. case 1933:
  9847. if((*i)->GetMiscValue() & (spellProto ? GetSpellSchoolMask(spellProto) : 0))
  9848. AddPctN(TakenTotalMod, (*i)->GetAmount());
  9849. break;
  9850. }
  9851. }
  9852. // From caster spells
  9853. AuraEffectList const& mOwnerTaken = victim->GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_FROM_CASTER);
  9854. for(AuraEffectList::const_iterator i = mOwnerTaken.begin(); i != mOwnerTaken.end(); ++i)
  9855. if((*i)->GetCasterGUID() == GetGUID() && (*i)->IsAffectedOnSpell(spellProto))
  9856. AddPctN(TakenTotalMod, (*i)->GetAmount());
  9857. // Mod damage from spell mechanic
  9858. if(uint32 mechanicMask = GetAllSpellMechanicMask(spellProto))
  9859. {
  9860. AuraEffectList const& mDamageDoneMechanic = victim->GetAuraEffectsByType(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT);
  9861. for(AuraEffectList::const_iterator i = mDamageDoneMechanic.begin(); i != mDamageDoneMechanic.end(); ++i)
  9862. if(mechanicMask & uint32(1<<((*i)->GetMiscValue())))
  9863. AddPctN(TakenTotalMod, (*i)->GetAmount());
  9864. }
  9865. // Taken/Done fixed damage bonus auras
  9866. int32 DoneAdvertisedBenefit = SpellBaseDamageBonus(GetSpellSchoolMask(spellProto));
  9867. int32 TakenAdvertisedBenefit = SpellBaseDamageBonusForVictim(GetSpellSchoolMask(spellProto), victim);
  9868. // Pets just add their bonus damage to their spell damage
  9869. // note that their spell damage is just gain of their own auras
  9870. if(HasUnitTypeMask(UNIT_MASK_GUARDIAN))
  9871. DoneAdvertisedBenefit += ((Guardian*)this)->GetBonusDamage();
  9872. // Check for table values
  9873. float coeff = 0;
  9874. SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id);
  9875. if(bonus)
  9876. {
  9877. if(damagetype == DOT)
  9878. {
  9879. coeff = bonus->dot_damage;
  9880. if(bonus->ap_dot_bonus > 0)
  9881. {
  9882. WeaponAttackType attType = (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK;
  9883. float APbonus = (float) victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS);
  9884. APbonus += GetTotalAttackPowerValue(attType);
  9885. DoneTotal += int32(bonus->ap_dot_bonus * stack * ApCoeffMod * APbonus);
  9886. }
  9887. }
  9888. else
  9889. {
  9890. coeff = bonus->direct_damage;
  9891. if(bonus->ap_bonus > 0)
  9892. {
  9893. WeaponAttackType attType = (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK;
  9894. float APbonus = (float) victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS);
  9895. APbonus += GetTotalAttackPowerValue(attType);
  9896. DoneTotal += int32(bonus->ap_bonus * stack * ApCoeffMod * APbonus);
  9897. }
  9898. }
  9899. }
  9900. // Default calculation
  9901. if(DoneAdvertisedBenefit || TakenAdvertisedBenefit)
  9902. {
  9903. if(!bonus || coeff < 0)
  9904. {
  9905. // Damage Done from spell damage bonus
  9906. int32 CastingTime = IsChanneledSpell(spellProto) ? GetSpellDuration(spellProto) : GetSpellCastTime(spellProto);
  9907. // Damage over Time spells bonus calculation
  9908. float DotFactor = 1.0f;
  9909. if(damagetype == DOT)
  9910. {
  9911. int32 DotDuration = GetSpellDuration(spellProto);
  9912. // 200% limit
  9913. if(DotDuration > 0)
  9914. {
  9915. if(DotDuration > 30000)
  9916. DotDuration = 30000;
  9917. if(!IsChanneledSpell(spellProto))
  9918. DotFactor = DotDuration / 15000.0f;
  9919. uint8 x = 0;
  9920. for(uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
  9921. {
  9922. if(spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && (
  9923. spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE ||
  9924. spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH))
  9925. {
  9926. x = j;
  9927. break;
  9928. }
  9929. }
  9930. int32 DotTicks = 6;
  9931. if(spellProto->EffectAmplitude[x] != 0)
  9932. DotTicks = DotDuration / spellProto->EffectAmplitude[x];
  9933. if(DotTicks)
  9934. {
  9935. DoneAdvertisedBenefit /= DotTicks;
  9936. TakenAdvertisedBenefit /= DotTicks;
  9937. }
  9938. }
  9939. }
  9940. // Distribute Damage over multiple effects, reduce by AoE
  9941. CastingTime = GetCastingTimeForBonus(spellProto, damagetype, CastingTime);
  9942. // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
  9943. for(uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
  9944. {
  9945. if(spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH ||
  9946. (spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH))
  9947. {
  9948. CastingTime /= 2;
  9949. break;
  9950. }
  9951. }
  9952. if(spellProto->SchoolMask != SPELL_SCHOOL_MASK_NORMAL)
  9953. coeff = (CastingTime / 3500.0f) * DotFactor;
  9954. else
  9955. coeff = DotFactor;
  9956. }
  9957. float coeff2 = CalculateLevelPenalty(spellProto) * stack;
  9958. if(spellProto->SpellFamilyName) // TODO: fix this
  9959. TakenTotal+= int32(TakenAdvertisedBenefit * coeff * coeff2);
  9960. if(Player* modOwner = GetSpellModOwner())
  9961. {
  9962. coeff *= 100.0f;
  9963. modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff);
  9964. coeff /= 100.0f;
  9965. if(isPet())
  9966. modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_ALL_EFFECTS, DoneAdvertisedBenefit);
  9967. }
  9968. DoneTotal += (int32)(DoneAdvertisedBenefit * coeff * coeff2);
  9969. }
  9970. // Some spells don't benefit from done mods
  9971. if(spellProto->AttributesEx3 & SPELL_ATTR3_NO_DONE_BONUS)
  9972. {
  9973. DoneTotal = 0;
  9974. DoneTotalMod = 1.0f;
  9975. }
  9976. // Some spells don't benefit from pct done mods
  9977. // maybe should be implemented like SPELL_ATTR3_NO_DONE_BONUS,
  9978. // but then it may break spell power coeffs work on spell 31117
  9979. if(spellProto->AttributesEx6 & SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS)
  9980. DoneTotalMod = 1.0f;
  9981. float tmpDamage = (int32(pdamage) + DoneTotal) * DoneTotalMod;
  9982. // apply spellmod to Done damage (flat and pct)
  9983. if(Player* modOwner = GetSpellModOwner())
  9984. modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage);
  9985. tmpDamage = (tmpDamage + TakenTotal) * TakenTotalMod;
  9986. return uint32(std::max(tmpDamage, 0.0f));
  9987. }
  9988. int32 Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask)
  9989. {
  9990. int32 DoneAdvertisedBenefit = 0;
  9991. // ..done
  9992. AuraEffectList const& mDamageDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE);
  9993. for(AuraEffectList::const_iterator i = mDamageDone.begin(); i != mDamageDone.end(); ++i)
  9994. if(((*i)->GetMiscValue() & schoolMask) != 0 &&
  9995. (*i)->GetSpellProto()->EquippedItemClass == -1 &&
  9996. // -1 == any item class (not wand then)
  9997. (*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0)
  9998. // 0 == any inventory type (not wand then)
  9999. DoneAdvertisedBenefit += (*i)->GetAmount();
  10000. if(GetTypeId() == TYPEID_PLAYER)
  10001. {
  10002. // Base value
  10003. DoneAdvertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
  10004. // Damage bonus from stats
  10005. AuraEffectList const& mDamageDoneOfStatPercent = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT);
  10006. for(AuraEffectList::const_iterator i = mDamageDoneOfStatPercent.begin(); i != mDamageDoneOfStatPercent.end(); ++i)
  10007. {
  10008. if((*i)->GetMiscValue() & schoolMask)
  10009. {
  10010. // stat used stored in miscValueB for this aura
  10011. Stats usedStat = Stats((*i)->GetMiscValueB());
  10012. DoneAdvertisedBenefit += int32(CalculatePctN(GetStat(usedStat), (*i)->GetAmount()));
  10013. }
  10014. }
  10015. // ... and attack power
  10016. AuraEffectList const& mDamageDonebyAP = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER);
  10017. for(AuraEffectList::const_iterator i =mDamageDonebyAP.begin(); i != mDamageDonebyAP.end(); ++i)
  10018. if((*i)->GetMiscValue() & schoolMask)
  10019. DoneAdvertisedBenefit += int32(CalculatePctN(GetTotalAttackPowerValue(BASE_ATTACK), (*i)->GetAmount()));
  10020. }
  10021. return DoneAdvertisedBenefit > 0 ? DoneAdvertisedBenefit : 0;
  10022. }
  10023. int32 Unit::SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask, Unit* victim)
  10024. {
  10025. uint32 creatureTypeMask = victim->GetCreatureTypeMask();
  10026. int32 TakenAdvertisedBenefit = 0;
  10027. // ..done (for creature type by mask) in taken
  10028. AuraEffectList const& mDamageDoneCreature = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
  10029. for(AuraEffectList::const_iterator i = mDamageDoneCreature.begin(); i != mDamageDoneCreature.end(); ++i)
  10030. if(creatureTypeMask & uint32((*i)->GetMiscValue()))
  10031. TakenAdvertisedBenefit += (*i)->GetAmount();
  10032. // ..taken
  10033. AuraEffectList const& mDamageTaken = victim->GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
  10034. for(AuraEffectList::const_iterator i = mDamageTaken.begin(); i != mDamageTaken.end(); ++i)
  10035. if(((*i)->GetMiscValue() & schoolMask) != 0)
  10036. TakenAdvertisedBenefit += (*i)->GetAmount();
  10037. return TakenAdvertisedBenefit > 0 ? TakenAdvertisedBenefit : 0;
  10038. }
  10039. bool Unit::isSpellCrit(Unit* victim, SpellEntry const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType) const
  10040. {
  10041. // Mobs can't crit with spells but creatures owned by a player CAN crit.
  10042. if(IS_CREATURE_GUID(GetGUID()) && !(GetOwner() && GetOwner()->GetTypeId() == TYPEID_PLAYER))
  10043. return false;
  10044. // not critting spell
  10045. if((spellProto->AttributesEx2 & SPELL_ATTR2_CANT_CRIT))
  10046. return false;
  10047. float crit_chance = 0.0f;
  10048. switch(spellProto->DmgClass)
  10049. {
  10050. case SPELL_DAMAGE_CLASS_NONE:
  10051. // We need more spells to find a general way (if there is any)
  10052. switch(spellProto->Id)
  10053. {
  10054. case 379: // Earth Shield
  10055. case 33778: // Lifebloom Final Bloom
  10056. case 64844: // Divine Hymn
  10057. break;
  10058. default:
  10059. return false;
  10060. }
  10061. case SPELL_DAMAGE_CLASS_MAGIC:
  10062. {
  10063. if(schoolMask & SPELL_SCHOOL_MASK_NORMAL)
  10064. crit_chance = 0.0f;
  10065. // For other schools
  10066. else if(GetTypeId() == TYPEID_PLAYER)
  10067. crit_chance = GetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1 + GetFirstSchoolInMask(schoolMask));
  10068. else
  10069. {
  10070. crit_chance = (float)m_baseSpellCritChance;
  10071. crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask);
  10072. }
  10073. // taken
  10074. if(victim)
  10075. {
  10076. if(!IsPositiveSpell(spellProto->Id))
  10077. {
  10078. // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
  10079. crit_chance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE, schoolMask);
  10080. // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
  10081. crit_chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
  10082. ApplyResilience(victim, &crit_chance, NULL, false, CR_CRIT_TAKEN_SPELL);
  10083. }
  10084. // scripted (increase crit chance ... against ... target by x%
  10085. AuraEffectList const& mOverrideClassScript = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
  10086. for(AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
  10087. {
  10088. if(!((*i)->IsAffectedOnSpell(spellProto)))
  10089. continue;
  10090. int32 modChance = 0;
  10091. switch((*i)->GetMiscValue())
  10092. {
  10093. // Shatter
  10094. case 911: modChance+= 16;
  10095. case 910: modChance+= 17;
  10096. case 849: modChance+= 17;
  10097. if(!victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this))
  10098. break;
  10099. crit_chance+=modChance;
  10100. break;
  10101. case 7917: // Glyph of Shadowburn
  10102. if(victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
  10103. crit_chance+=(*i)->GetAmount();
  10104. break;
  10105. default:
  10106. break;
  10107. }
  10108. }
  10109. // Custom crit by class
  10110. switch(spellProto->SpellFamilyName)
  10111. {
  10112. case SPELLFAMILY_DRUID:
  10113. // Improved Faerie Fire
  10114. if(victim->HasAuraState(AURA_STATE_FAERIE_FIRE)) {
  10115. if(AuraEffect const* aurEff = GetDummyAuraEffect(SPELLFAMILY_DRUID, 109, 0))
  10116. crit_chance += aurEff->GetAmount();
  10117. }
  10118. // cumulative effect - don't break
  10119. // Starfire
  10120. if(spellProto->SpellFamilyFlags[0] & 0x4 && spellProto->SpellIconID == 1485) {
  10121. // Improved Insect Swarm
  10122. if(AuraEffect const* aurEff = GetDummyAuraEffect(SPELLFAMILY_DRUID, 1771, 0)) {
  10123. if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00000002, 0, 0))
  10124. crit_chance += aurEff->GetAmount();
  10125. }
  10126. }
  10127. break;
  10128. case SPELLFAMILY_ROGUE:
  10129. // Shiv-applied poisons can't crit
  10130. if(FindCurrentSpellBySpellId(5938))
  10131. crit_chance = 0.0f;
  10132. break;
  10133. case SPELLFAMILY_PALADIN:
  10134. // Flash of light
  10135. if(spellProto->SpellFamilyFlags[0] & 0x40000000) {
  10136. // Sacred Shield
  10137. if(AuraEffect const* aura = victim->GetAuraEffect(58597, 1, GetGUID()))
  10138. crit_chance += aura->GetAmount();
  10139. break;
  10140. }
  10141. // Exorcism
  10142. else if(spellProto->Category == 19) {
  10143. if(victim->GetCreatureTypeMask() & CREATURE_TYPEMASK_DEMON_OR_UNDEAD)
  10144. return true;
  10145. break;
  10146. }
  10147. break;
  10148. case SPELLFAMILY_SHAMAN:
  10149. // Lava Burst
  10150. if(spellProto->SpellFamilyFlags[1] & 0x00001000)
  10151. {
  10152. if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0, 0, GetGUID()))
  10153. if(victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE) > -100)
  10154. return true;
  10155. break;
  10156. }
  10157. break;
  10158. }
  10159. }
  10160. break;
  10161. }
  10162. case SPELL_DAMAGE_CLASS_MELEE:
  10163. if(victim)
  10164. {
  10165. // Custom crit by class
  10166. switch(spellProto->SpellFamilyName)
  10167. {
  10168. case SPELLFAMILY_DRUID:
  10169. // Rend and Tear - bonus crit chance for Ferocious Bite on bleeding targets
  10170. if(spellProto->SpellFamilyFlags[0] & 0x00800000
  10171. && spellProto->SpellIconID == 1680
  10172. && victim->HasAuraState(AURA_STATE_BLEEDING))
  10173. {
  10174. if(AuraEffect const* rendAndTear = GetDummyAuraEffect(SPELLFAMILY_DRUID, 2859, 1))
  10175. crit_chance += rendAndTear->GetAmount();
  10176. break;
  10177. }
  10178. break;
  10179. case SPELLFAMILY_WARRIOR:
  10180. // Victory Rush
  10181. if(spellProto->SpellFamilyFlags[1] & 0x100)
  10182. {
  10183. // Glyph of Victory Rush
  10184. if(AuraEffect const* aurEff = GetAuraEffect(58382, 0))
  10185. crit_chance += aurEff->GetAmount();
  10186. break;
  10187. }
  10188. break;
  10189. }
  10190. }
  10191. case SPELL_DAMAGE_CLASS_RANGED:
  10192. {
  10193. if(victim)
  10194. {
  10195. crit_chance += GetUnitCriticalChance(attackType, victim);
  10196. crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask);
  10197. }
  10198. break;
  10199. }
  10200. default:
  10201. return false;
  10202. }
  10203. // percent done
  10204. // only players use intelligence for critical chance computations
  10205. if(Player* modOwner = GetSpellModOwner())
  10206. modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance);
  10207. crit_chance = crit_chance > 0.0f ? crit_chance : 0.0f;
  10208. if(roll_chance_f(crit_chance) && (victim && !victim->HasAura(53480)))
  10209. return true;
  10210. return false;
  10211. }
  10212. uint32 Unit::SpellCriticalDamageBonus(SpellEntry const* spellProto, uint32 damage, Unit* victim)
  10213. {
  10214. // Calculate critical bonus
  10215. int32 crit_bonus = damage;
  10216. float crit_mod = 0.0f;
  10217. switch(spellProto->DmgClass)
  10218. {
  10219. case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100%
  10220. case SPELL_DAMAGE_CLASS_RANGED:
  10221. // TODO: write here full calculation for melee/ranged spells
  10222. crit_bonus += damage;
  10223. break;
  10224. default:
  10225. crit_bonus += damage / 2; // for spells is 50%
  10226. break;
  10227. }
  10228. crit_mod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, GetSpellSchoolMask(spellProto)) - 1.0f) * 100;
  10229. if(victim)
  10230. crit_mod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, victim->GetCreatureTypeMask());
  10231. if(crit_bonus != 0)
  10232. AddPctF(crit_bonus, crit_mod);
  10233. crit_bonus -= damage;
  10234. // adds additional damage to crit_bonus (from talents)
  10235. if(Player* modOwner = GetSpellModOwner())
  10236. modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
  10237. crit_bonus += damage;
  10238. return crit_bonus;
  10239. }
  10240. uint32 Unit::SpellCriticalHealingBonus(SpellEntry const* spellProto, uint32 damage, Unit* victim)
  10241. {
  10242. // Calculate critical bonus
  10243. int32 crit_bonus;
  10244. switch(spellProto->DmgClass)
  10245. {
  10246. case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100%
  10247. case SPELL_DAMAGE_CLASS_RANGED:
  10248. // TODO: write here full calculation for melee/ranged spells
  10249. crit_bonus = damage;
  10250. break;
  10251. default:
  10252. crit_bonus = damage / 2; // for spells is 50%
  10253. break;
  10254. }
  10255. if(victim)
  10256. {
  10257. uint32 creatureTypeMask = victim->GetCreatureTypeMask();
  10258. crit_bonus = int32(crit_bonus * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, creatureTypeMask));
  10259. }
  10260. if(crit_bonus > 0)
  10261. damage += crit_bonus;
  10262. damage = int32(float(damage) * GetTotalAuraMultiplier(SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT));
  10263. return damage;
  10264. }
  10265. uint32 Unit::SpellHealingBonus(Unit* victim, SpellEntry const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack)
  10266. {
  10267. // For totems get healing bonus from owner (statue isn't totem in fact)
  10268. if(GetTypeId() == TYPEID_UNIT && ToCreature()->isTotem())
  10269. if(Unit* owner = GetOwner())
  10270. return owner->SpellHealingBonus(victim, spellProto, healamount, damagetype, stack);
  10271. // no bonus for heal potions/bandages
  10272. if(spellProto->SpellFamilyName == SPELLFAMILY_POTION)
  10273. return healamount;
  10274. // and Warlock's Healthstones
  10275. if(spellProto->SpellFamilyName == SPELLFAMILY_WARLOCK && (spellProto->SpellFamilyFlags[0] & 0x10000))
  10276. return healamount;
  10277. // Healing Done
  10278. // Taken/Done total percent damage auras
  10279. float DoneTotalMod = 1.0f;
  10280. float TakenTotalMod = 1.0f;
  10281. int32 DoneTotal = 0;
  10282. int32 TakenTotal = 0;
  10283. // Healing done percent
  10284. AuraEffectList const& mHealingDonePct = GetAuraEffectsByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT);
  10285. for(AuraEffectList::const_iterator i = mHealingDonePct.begin(); i != mHealingDonePct.end(); ++i)
  10286. AddPctN(DoneTotalMod, (*i)->GetAmount());
  10287. // done scripted mod (take it from owner)
  10288. Unit* owner = GetOwner() ? GetOwner() : this;
  10289. AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
  10290. for(AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
  10291. {
  10292. if(!(*i)->IsAffectedOnSpell(spellProto))
  10293. continue;
  10294. switch((*i)->GetMiscValue())
  10295. {
  10296. case 4415: // Increased Rejuvenation Healing
  10297. case 4953:
  10298. case 3736: // Hateful Totem of the Third Wind / Increased Lesser Healing Wave / LK Arena (4/5/6) Totem of the Third Wind / Savage Totem of the Third Wind
  10299. DoneTotal += (*i)->GetAmount();
  10300. break;
  10301. case 7997: // Renewed Hope
  10302. case 7998:
  10303. if(victim->HasAura(6788))
  10304. AddPctN(DoneTotalMod, (*i)->GetAmount());
  10305. break;
  10306. case 21: // Test of Faith
  10307. case 6935:
  10308. case 6918:
  10309. if(victim->HealthBelowPct(50))
  10310. AddPctN(DoneTotalMod, (*i)->GetAmount());
  10311. break;
  10312. case 7798: // Glyph of Regrowth
  10313. {
  10314. if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_DRUID, 0x40, 0, 0))
  10315. AddPctN(DoneTotalMod, (*i)->GetAmount());
  10316. break;
  10317. }
  10318. case 8477: // Nourish Heal Boost
  10319. {
  10320. int32 stepPercent = (*i)->GetAmount();
  10321. int32 modPercent = 0;
  10322. AuraApplicationMap const& victimAuras = victim->GetAppliedAuras();
  10323. for(AuraApplicationMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr)
  10324. {
  10325. Aura const* aura = itr->second->GetBase();
  10326. if(aura->GetCasterGUID() != GetGUID())
  10327. continue;
  10328. SpellEntry const* m_spell = aura->GetSpellProto();
  10329. if(m_spell->SpellFamilyName != SPELLFAMILY_DRUID ||
  10330. !(m_spell->SpellFamilyFlags[1] & 0x00000010 || m_spell->SpellFamilyFlags[0] & 0x50))
  10331. continue;
  10332. modPercent += stepPercent * aura->GetStackAmount();
  10333. }
  10334. AddPctN(DoneTotalMod, modPercent);
  10335. break;
  10336. }
  10337. case 7871: // Glyph of Lesser Healing Wave
  10338. {
  10339. if(victim->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0, 0x00000400, 0, GetGUID()))
  10340. AddPctN(DoneTotalMod, (*i)->GetAmount());
  10341. break;
  10342. }
  10343. default:
  10344. break;
  10345. }
  10346. }
  10347. // Taken/Done fixed damage bonus auras
  10348. int32 DoneAdvertisedBenefit = SpellBaseHealingBonus(GetSpellSchoolMask(spellProto));
  10349. int32 TakenAdvertisedBenefit = SpellBaseHealingBonusForVictim(GetSpellSchoolMask(spellProto), victim);
  10350. bool scripted = false;
  10351. for(uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
  10352. {
  10353. switch(spellProto->EffectApplyAuraName[i])
  10354. {
  10355. // These auras do not use healing coeff
  10356. case SPELL_AURA_PERIODIC_LEECH:
  10357. case SPELL_AURA_PERIODIC_HEALTH_FUNNEL:
  10358. scripted = true;
  10359. break;
  10360. }
  10361. if(spellProto->Effect[i] == SPELL_EFFECT_HEALTH_LEECH)
  10362. scripted = true;
  10363. }
  10364. // Check for table values
  10365. SpellBonusEntry const* bonus = !scripted ? sSpellMgr->GetSpellBonusData(spellProto->Id) : NULL;
  10366. float coeff = 0;
  10367. float factorMod = 1.0f;
  10368. if(bonus)
  10369. {
  10370. if(damagetype == DOT)
  10371. {
  10372. coeff = bonus->dot_damage;
  10373. if(bonus->ap_dot_bonus > 0)
  10374. DoneTotal += int32(bonus->ap_dot_bonus * stack * GetTotalAttackPowerValue(
  10375. (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE)? RANGED_ATTACK : BASE_ATTACK));
  10376. }
  10377. else
  10378. {
  10379. coeff = bonus->direct_damage;
  10380. if(bonus->ap_bonus > 0)
  10381. DoneTotal += int32(bonus->ap_bonus * stack * GetTotalAttackPowerValue(
  10382. (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE)? RANGED_ATTACK : BASE_ATTACK));
  10383. }
  10384. }
  10385. else // scripted bonus
  10386. {
  10387. // Gift of the Naaru
  10388. if(spellProto->SpellFamilyFlags[2] & 0x80000000 && spellProto->SpellIconID == 329)
  10389. {
  10390. scripted = true;
  10391. int32 apBonus = int32(std::max(GetTotalAttackPowerValue(BASE_ATTACK), GetTotalAttackPowerValue(RANGED_ATTACK)));
  10392. if(apBonus > DoneAdvertisedBenefit)
  10393. DoneTotal += int32(apBonus * 0.22f); // 22% of AP per tick
  10394. else
  10395. DoneTotal += int32(DoneAdvertisedBenefit * 0.377f); // 37.7% of BH per tick
  10396. }
  10397. // Earthliving - 0.45% of normal hot coeff
  10398. else if(spellProto->SpellFamilyName == SPELLFAMILY_SHAMAN && spellProto->SpellFamilyFlags[1] & 0x80000)
  10399. factorMod *= 0.45f;
  10400. // Already set to scripted? so not uses healing bonus coefficient
  10401. // No heal coeff for SPELL_DAMAGE_CLASS_NONE class spells by default
  10402. else if(scripted || spellProto->DmgClass == SPELL_DAMAGE_CLASS_NONE)
  10403. {
  10404. scripted = true;
  10405. coeff = 0.0f;
  10406. }
  10407. }
  10408. // Default calculation
  10409. if(DoneAdvertisedBenefit || TakenAdvertisedBenefit)
  10410. {
  10411. if((!bonus && !scripted) || coeff < 0)
  10412. {
  10413. // Damage Done from spell damage bonus
  10414. int32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto);
  10415. // Damage over Time spells bonus calculation
  10416. float DotFactor = 1.0f;
  10417. if(damagetype == DOT)
  10418. {
  10419. int32 DotDuration = GetSpellDuration(spellProto);
  10420. // 200% limit
  10421. if(DotDuration > 0)
  10422. {
  10423. if(DotDuration > 30000) DotDuration = 30000;
  10424. if(!IsChanneledSpell(spellProto)) DotFactor = DotDuration / 15000.0f;
  10425. uint32 x = 0;
  10426. for(uint8 j = 0; j < MAX_SPELL_EFFECTS; j++)
  10427. {
  10428. if(spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && (
  10429. spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE ||
  10430. spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH))
  10431. {
  10432. x = j;
  10433. break;
  10434. }
  10435. }
  10436. int32 DotTicks = 6;
  10437. if(spellProto->EffectAmplitude[x] != 0)
  10438. DotTicks = DotDuration / spellProto->EffectAmplitude[x];
  10439. if(DotTicks)
  10440. {
  10441. DoneAdvertisedBenefit = DoneAdvertisedBenefit * int32(stack) / DotTicks;
  10442. TakenAdvertisedBenefit = TakenAdvertisedBenefit * int32(stack) / DotTicks;
  10443. }
  10444. }
  10445. }
  10446. // Distribute Damage over multiple effects, reduce by AoE
  10447. CastingTime = GetCastingTimeForBonus(spellProto, damagetype, CastingTime);
  10448. // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
  10449. for(uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
  10450. {
  10451. if(spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH ||
  10452. (spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH))
  10453. {
  10454. CastingTime /= 2;
  10455. break;
  10456. }
  10457. }
  10458. // As wowwiki says: C = (Cast Time / 3.5) * 1.88 (for healing spells)
  10459. coeff = (CastingTime / 3500.0f) * DotFactor * 1.88f;
  10460. }
  10461. factorMod *= CalculateLevelPenalty(spellProto) * stack;
  10462. TakenTotal += int32(TakenAdvertisedBenefit * coeff * factorMod);
  10463. if(Player* modOwner = GetSpellModOwner())
  10464. {
  10465. coeff *= 100.0f;
  10466. modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff);
  10467. coeff /= 100.0f;
  10468. }
  10469. DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod);
  10470. }
  10471. // use float as more appropriate for negative values and percent applying
  10472. float heal = (int32(healamount) + DoneTotal) * DoneTotalMod;
  10473. // apply spellmod to Done amount
  10474. if(Player* modOwner = GetSpellModOwner())
  10475. modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal);
  10476. // Nourish cast
  10477. if(spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[1] & 0x2000000)
  10478. {
  10479. // Rejuvenation, Regrowth, Lifebloom, or Wild Growth
  10480. if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_DRUID, 0x50, 0x4000010, 0))
  10481. // increase healing by 20%
  10482. TakenTotalMod *= 1.2f;
  10483. }
  10484. // Taken mods
  10485. // Tenacity increase healing % taken
  10486. if(AuraEffect const* Tenacity = victim->GetAuraEffect(58549, 0))
  10487. AddPctN(TakenTotalMod, Tenacity->GetAmount());
  10488. // Healing taken percent
  10489. float minval = (float)victim->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT);
  10490. if(minval)
  10491. AddPctF(TakenTotalMod, minval);
  10492. float maxval = (float)victim->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT);
  10493. if(maxval)
  10494. AddPctF(TakenTotalMod, maxval);
  10495. if(damagetype == DOT)
  10496. {
  10497. // Healing over time taken percent
  10498. float minval_hot = (float)victim->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HOT_PCT);
  10499. if(minval_hot)
  10500. AddPctF(TakenTotalMod, minval_hot);
  10501. float maxval_hot = (float)victim->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HOT_PCT);
  10502. if(maxval_hot)
  10503. AddPctF(TakenTotalMod, maxval_hot);
  10504. }
  10505. AuraEffectList const& mHealingGet= victim->GetAuraEffectsByType(SPELL_AURA_MOD_HEALING_RECEIVED);
  10506. for(AuraEffectList::const_iterator i = mHealingGet.begin(); i != mHealingGet.end(); ++i)
  10507. if(GetGUID() == (*i)->GetCasterGUID() && (*i)->IsAffectedOnSpell(spellProto))
  10508. AddPctN(TakenTotalMod, (*i)->GetAmount());
  10509. heal = (int32(heal) + TakenTotal) * TakenTotalMod;
  10510. return uint32(std::max(heal, 0.0f));
  10511. }
  10512. int32 Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask)
  10513. {
  10514. int32 AdvertisedBenefit = 0;
  10515. AuraEffectList const& mHealingDone = GetAuraEffectsByType(SPELL_AURA_MOD_HEALING_DONE);
  10516. for(AuraEffectList::const_iterator i = mHealingDone.begin(); i != mHealingDone.end(); ++i)
  10517. if(!(*i)->GetMiscValue() || ((*i)->GetMiscValue() & schoolMask) != 0)
  10518. AdvertisedBenefit += (*i)->GetAmount();
  10519. // Healing bonus of spirit, intellect and strength
  10520. if(GetTypeId() == TYPEID_PLAYER)
  10521. {
  10522. // Base value
  10523. AdvertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
  10524. // Healing bonus from stats
  10525. AuraEffectList const& mHealingDoneOfStatPercent = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT);
  10526. for(AuraEffectList::const_iterator i = mHealingDoneOfStatPercent.begin(); i != mHealingDoneOfStatPercent.end(); ++i)
  10527. {
  10528. // stat used dependent from misc value (stat index)
  10529. Stats usedStat = Stats((*i)->GetSpellProto()->EffectMiscValue[(*i)->GetEffIndex()]);
  10530. AdvertisedBenefit += int32(CalculatePctN(GetStat(usedStat), (*i)->GetAmount()));
  10531. }
  10532. // ... and attack power
  10533. AuraEffectList const& mHealingDonebyAP = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER);
  10534. for(AuraEffectList::const_iterator i = mHealingDonebyAP.begin(); i != mHealingDonebyAP.end(); ++i)
  10535. if((*i)->GetMiscValue() & schoolMask)
  10536. AdvertisedBenefit += int32(CalculatePctN(GetTotalAttackPowerValue(BASE_ATTACK), (*i)->GetAmount()));
  10537. }
  10538. return AdvertisedBenefit;
  10539. }
  10540. int32 Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask, Unit* victim)
  10541. {
  10542. int32 AdvertisedBenefit = 0;
  10543. AuraEffectList const& mDamageTaken = victim->GetAuraEffectsByType(SPELL_AURA_MOD_HEALING);
  10544. for(AuraEffectList::const_iterator i = mDamageTaken.begin(); i != mDamageTaken.end(); ++i)
  10545. if(((*i)->GetMiscValue() & schoolMask) != 0)
  10546. AdvertisedBenefit += (*i)->GetAmount();
  10547. return AdvertisedBenefit;
  10548. }
  10549. bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask)
  10550. {
  10551. // If m_immuneToSchool type contain this school type, IMMUNE damage.
  10552. SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
  10553. for(SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
  10554. if(itr->type & shoolMask)
  10555. return true;
  10556. // If m_immuneToDamage type contain magic, IMMUNE damage.
  10557. SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
  10558. for(SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
  10559. if(itr->type & shoolMask)
  10560. return true;
  10561. return false;
  10562. }
  10563. bool Unit::IsImmunedToDamage(SpellEntry const* spellInfo)
  10564. {
  10565. if(spellInfo->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
  10566. return false;
  10567. uint32 shoolMask = GetSpellSchoolMask(spellInfo);
  10568. if(spellInfo->Id != 42292 && spellInfo->Id !=59752)
  10569. {
  10570. // If m_immuneToSchool type contain this school type, IMMUNE damage.
  10571. SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
  10572. for(SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
  10573. if(itr->type & shoolMask && !CanSpellPierceImmuneAura(spellInfo, sSpellStore.LookupEntry(itr->spellId)))
  10574. return true;
  10575. }
  10576. // If m_immuneToDamage type contain magic, IMMUNE damage.
  10577. SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
  10578. for(SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
  10579. if(itr->type & shoolMask)
  10580. return true;
  10581. return false;
  10582. }
  10583. bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo)
  10584. {
  10585. if(!spellInfo)
  10586. return false;
  10587. // Single spell immunity.
  10588. SpellImmuneList const& idList = m_spellImmune[IMMUNITY_ID];
  10589. for(SpellImmuneList::const_iterator itr = idList.begin(); itr != idList.end(); ++itr)
  10590. if(itr->type == spellInfo->Id)
  10591. return true;
  10592. if(spellInfo->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
  10593. return false;
  10594. if(spellInfo->Dispel)
  10595. {
  10596. SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL];
  10597. for(SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr)
  10598. if(itr->type == spellInfo->Dispel)
  10599. return true;
  10600. }
  10601. if(spellInfo->Mechanic)
  10602. {
  10603. SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
  10604. for(SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
  10605. if(itr->type == spellInfo->Mechanic)
  10606. return true;
  10607. }
  10608. for(int i = 0; i < MAX_SPELL_EFFECTS; ++i)
  10609. {
  10610. // State/effect immunities applied by aura expect full spell immunity
  10611. // Ignore effects with mechanic, they are supposed to be checked separately
  10612. if(!spellInfo->EffectMechanic[i] && spellInfo->Effect[i] != SPELL_EFFECT_KNOCK_BACK)
  10613. if(IsImmunedToSpellEffect(spellInfo, i))
  10614. return true;
  10615. }
  10616. if(spellInfo->Id != 42292 && spellInfo->Id !=59752)
  10617. {
  10618. SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
  10619. for(SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
  10620. if((itr->type & GetSpellSchoolMask(spellInfo))
  10621. && !(IsPositiveSpell(itr->spellId) && IsPositiveSpell(spellInfo->Id))
  10622. && !CanSpellPierceImmuneAura(spellInfo, sSpellStore.LookupEntry(itr->spellId)))
  10623. return true;
  10624. }
  10625. return false;
  10626. }
  10627. bool Unit::IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const
  10628. {
  10629. if(!spellInfo)
  10630. return false;
  10631. // If m_immuneToEffect type contain this effect type, IMMUNE effect.
  10632. uint32 effect = spellInfo->Effect[index];
  10633. SpellImmuneList const& effectList = m_spellImmune[IMMUNITY_EFFECT];
  10634. for(SpellImmuneList::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr)
  10635. if(itr->type == effect)
  10636. return true;
  10637. if(uint32 mechanic = spellInfo->EffectMechanic[index])
  10638. {
  10639. SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
  10640. for(SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
  10641. if(itr->type == mechanic)
  10642. return true;
  10643. }
  10644. if(uint32 aura = spellInfo->EffectApplyAuraName[index])
  10645. {
  10646. SpellImmuneList const& list = m_spellImmune[IMMUNITY_STATE];
  10647. for(SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
  10648. if(itr->type == aura)
  10649. return true;
  10650. // Check for immune to application of harmful magical effects
  10651. AuraEffectList const& immuneAuraApply = GetAuraEffectsByType(SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL);
  10652. for(AuraEffectList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter)
  10653. {
  10654. //if(spellInfo->Dispel == DISPEL_MAGIC && // Magic debuff
  10655. // ((*iter)->GetMiscValue() & GetSpellSchoolMask(spellInfo)) && // Check school
  10656. // !IsPositiveEffect(spellInfo->Id, index)) // Harmful
  10657. if((spellInfo->Dispel == DISPEL_MAGIC || spellInfo->Dispel == DISPEL_CURSE ||
  10658. spellInfo->Dispel == DISPEL_DISEASE || spellInfo->Dispel == DISPEL_POISON) // Magic or curse debuff
  10659. // && ((*iter)->GetMiscValue() & spellInfo->GetSchoolMask()) // Check school
  10660. // && !spellInfo->IsPositiveEffect(index)) // Harmful
  10661. && ((*iter)->GetMiscValue() & GetSpellSchoolMask(spellInfo)) // Check school
  10662. && !IsPositiveEffect(spellInfo->Id, index)) // Harmful
  10663. return true;
  10664. }
  10665. }
  10666. if(GetTypeId() == TYPEID_PLAYER && spellInfo->Id != 49560)
  10667. {
  10668. if(spellInfo->Effect[index] == SPELL_EFFECT_ATTACK_ME)
  10669. return true;
  10670. if(spellInfo->EffectApplyAuraName[index] == SPELL_AURA_MOD_TAUNT)
  10671. return true;
  10672. }
  10673. return false;
  10674. }
  10675. void Unit::MeleeDamageBonus(Unit* victim, uint32 *pdamage, WeaponAttackType attType, SpellEntry const* spellProto)
  10676. {
  10677. if(!victim)
  10678. return;
  10679. if(*pdamage == 0)
  10680. return;
  10681. uint32 creatureTypeMask = victim->GetCreatureTypeMask();
  10682. // Taken/Done fixed damage bonus auras
  10683. int32 DoneFlatBenefit = 0;
  10684. int32 TakenFlatBenefit = 0;
  10685. // ..done (for creature type by mask) in taken
  10686. AuraEffectList const& mDamageDoneCreature = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
  10687. for(AuraEffectList::const_iterator i = mDamageDoneCreature.begin(); i != mDamageDoneCreature.end(); ++i)
  10688. if(creatureTypeMask & uint32((*i)->GetMiscValue()))
  10689. DoneFlatBenefit += (*i)->GetAmount();
  10690. // ..done
  10691. // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
  10692. // ..done (base at attack power for marked target and base at attack power for creature type)
  10693. int32 APbonus = 0;
  10694. if(attType == RANGED_ATTACK)
  10695. {
  10696. APbonus += victim->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS);
  10697. // ..done (base at attack power and creature type)
  10698. AuraEffectList const& mCreatureAttackPower = GetAuraEffectsByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS);
  10699. for(AuraEffectList::const_iterator i = mCreatureAttackPower.begin(); i != mCreatureAttackPower.end(); ++i)
  10700. if(creatureTypeMask & uint32((*i)->GetMiscValue()))
  10701. APbonus += (*i)->GetAmount();
  10702. }
  10703. else
  10704. {
  10705. APbonus += victim->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS);
  10706. // ..done (base at attack power and creature type)
  10707. AuraEffectList const& mCreatureAttackPower = GetAuraEffectsByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS);
  10708. for(AuraEffectList::const_iterator i = mCreatureAttackPower.begin(); i != mCreatureAttackPower.end(); ++i)
  10709. if(creatureTypeMask & uint32((*i)->GetMiscValue()))
  10710. APbonus += (*i)->GetAmount();
  10711. }
  10712. if(APbonus != 0) // Can be negative
  10713. {
  10714. bool normalized = false;
  10715. if(spellProto)
  10716. for(uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
  10717. if(spellProto->Effect[i] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG)
  10718. {
  10719. normalized = true;
  10720. break;
  10721. }
  10722. DoneFlatBenefit += int32(APbonus/14.0f * GetAPMultiplier(attType, normalized));
  10723. }
  10724. // ..taken
  10725. AuraEffectList const& mDamageTaken = victim->GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
  10726. for(AuraEffectList::const_iterator i = mDamageTaken.begin(); i != mDamageTaken.end(); ++i)
  10727. if((*i)->GetMiscValue() & GetMeleeDamageSchoolMask())
  10728. TakenFlatBenefit += (*i)->GetAmount();
  10729. if(attType != RANGED_ATTACK)
  10730. TakenFlatBenefit += victim->GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN);
  10731. else
  10732. TakenFlatBenefit += victim->GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN);
  10733. Player* player = ToPlayer();
  10734. // Done/Taken total percent damage auras
  10735. float DoneTotalMod = 1.0f;
  10736. float TakenTotalMod = 1.0f;
  10737. // ..done
  10738. AuraEffectList const& mModDamagePercentDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
  10739. for(AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
  10740. if(spellProto)
  10741. {
  10742. if((*i)->GetMiscValue() & GetSpellSchoolMask(spellProto))
  10743. {
  10744. if((*i)->GetSpellProto()->EquippedItemClass == -1)
  10745. AddPctN(DoneTotalMod, (*i)->GetAmount());
  10746. else if(!((*i)->GetSpellProto()->AttributesEx5 & SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK))
  10747. {
  10748. if((*i)->GetSpellProto()->EquippedItemClass & spellProto->EquippedItemClass)
  10749. if(((*i)->GetSpellProto()->EquippedItemSubClassMask == 0) ||
  10750. ((*i)->GetSpellProto()->EquippedItemSubClassMask & spellProto->EquippedItemSubClassMask))
  10751. AddPctN(DoneTotalMod, (*i)->GetAmount());
  10752. }
  10753. else if(ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*i)->GetSpellProto()))
  10754. AddPctN(DoneTotalMod, (*i)->GetAmount());
  10755. }
  10756. }
  10757. else if(player)
  10758. {
  10759. if(!((*i)->GetSpellProto()->AttributesEx5 & SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK))
  10760. {
  10761. EquipmentSlots slot;
  10762. switch(attType)
  10763. {
  10764. case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
  10765. case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
  10766. case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
  10767. default: return;
  10768. }
  10769. Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
  10770. if(item && !item->IsBroken() && item->IsFitToSpellRequirements((*i)->GetSpellProto()))
  10771. AddPctN(DoneTotalMod, (*i)->GetAmount());
  10772. }
  10773. else if(player->HasItemFitToSpellRequirements((*i)->GetSpellProto()))
  10774. AddPctN(DoneTotalMod, (*i)->GetAmount());
  10775. }
  10776. // Creatures' melee
  10777. else if((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
  10778. if(!HasUnitTypeMask(UNIT_MASK_GUARDIAN))
  10779. AddPctN(DoneTotalMod, (*i)->GetAmount());
  10780. AuraEffectList const& mDamageDoneVersus = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS);
  10781. for(AuraEffectList::const_iterator i = mDamageDoneVersus.begin(); i != mDamageDoneVersus.end(); ++i)
  10782. if(creatureTypeMask & uint32((*i)->GetMiscValue()))
  10783. AddPctN(DoneTotalMod, (*i)->GetAmount());
  10784. // bonus against aurastate
  10785. AuraEffectList const& mDamageDoneVersusAurastate = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE);
  10786. for(AuraEffectList::const_iterator i = mDamageDoneVersusAurastate.begin(); i != mDamageDoneVersusAurastate.end(); ++i)
  10787. if(victim->HasAuraState(AuraState((*i)->GetMiscValue())))
  10788. AddPctN(DoneTotalMod, (*i)->GetAmount());
  10789. // done scripted mod (take it from owner)
  10790. Unit* owner = GetOwner() ? GetOwner() : this;
  10791. AuraEffectList const& mOverrideClassScript = owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
  10792. for(AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
  10793. {
  10794. if(!(*i)->IsAffectedOnSpell(spellProto))
  10795. continue;
  10796. switch((*i)->GetMiscValue())
  10797. {
  10798. // Tundra Stalker
  10799. // Merciless Combat
  10800. case 7277:
  10801. {
  10802. // Merciless Combat
  10803. if((*i)->GetSpellProto()->SpellIconID == 2656)
  10804. {
  10805. if(!victim->HealthAbovePct(35))
  10806. AddPctN(DoneTotalMod, (*i)->GetAmount());
  10807. }
  10808. // Tundra Stalker
  10809. else
  10810. {
  10811. // Frost Fever (target debuff)
  10812. if(victim->HasAura(55095))
  10813. AddPctN(DoneTotalMod, (*i)->GetAmount());
  10814. }
  10815. break;
  10816. }
  10817. // Rage of Rivendare
  10818. case 7293:
  10819. {
  10820. if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, 0, 0x02000000, 0))
  10821. if(SpellChainNode const* chain = sSpellMgr->GetSpellChainNode((*i)->GetId()))
  10822. AddPctF(DoneTotalMod, chain->rank * 2.0f);
  10823. break;
  10824. }
  10825. // Marked for Death
  10826. case 7598:
  10827. case 7599:
  10828. case 7600:
  10829. case 7601:
  10830. case 7602:
  10831. {
  10832. if(victim->GetAuraEffect(SPELL_AURA_MOD_STALKED, SPELLFAMILY_HUNTER, 0x400, 0, 0))
  10833. AddPctN(DoneTotalMod, (*i)->GetAmount());
  10834. break;
  10835. }
  10836. // Dirty Deeds
  10837. case 6427:
  10838. case 6428:
  10839. {
  10840. if(victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
  10841. {
  10842. // effect 0 have expected value but in negative state
  10843. int32 bonus = -(*i)->GetBase()->GetEffect(0)->GetAmount();
  10844. AddPctN(DoneTotalMod, bonus);
  10845. }
  10846. break;
  10847. }
  10848. }
  10849. }
  10850. // Custom scripted damage
  10851. if(spellProto)
  10852. switch(spellProto->SpellFamilyName)
  10853. {
  10854. case SPELLFAMILY_DEATHKNIGHT:
  10855. // Glacier Rot
  10856. if(spellProto->SpellFamilyFlags[0] & 0x2 || spellProto->SpellFamilyFlags[1] & 0x6)
  10857. if(AuraEffect* aurEff = GetDummyAuraEffect(SPELLFAMILY_DEATHKNIGHT, 196, 0))
  10858. if(victim->GetDiseasesByCaster(owner->GetGUID()) > 0)
  10859. AddPctN(DoneTotalMod, aurEff->GetAmount());
  10860. break;
  10861. }
  10862. // ..taken
  10863. TakenTotalMod *= victim->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, GetMeleeDamageSchoolMask());
  10864. // From caster spells
  10865. AuraEffectList const& mOwnerTaken = victim->GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_FROM_CASTER);
  10866. for(AuraEffectList::const_iterator i = mOwnerTaken.begin(); i != mOwnerTaken.end(); ++i)
  10867. if((*i)->GetCasterGUID() == GetGUID() && (*i)->IsAffectedOnSpell(spellProto))
  10868. AddPctN(TakenTotalMod, (*i)->GetAmount());
  10869. // .. taken pct (special attacks)
  10870. if(spellProto)
  10871. {
  10872. // Mod damage from spell mechanic
  10873. uint32 mechanicMask = GetAllSpellMechanicMask(spellProto);
  10874. // Shred, Maul - "Effects which increase Bleed damage also increase Shred damage"
  10875. if(spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[0] & 0x00008800)
  10876. mechanicMask |= (1<<MECHANIC_BLEED);
  10877. if(mechanicMask)
  10878. {
  10879. AuraEffectList const& mDamageDoneMechanic = victim->GetAuraEffectsByType(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT);
  10880. for(AuraEffectList::const_iterator i = mDamageDoneMechanic.begin(); i != mDamageDoneMechanic.end(); ++i)
  10881. if(mechanicMask & uint32(1<<((*i)->GetMiscValue())))
  10882. AddPctN(TakenTotalMod, (*i)->GetAmount());
  10883. }
  10884. }
  10885. // .. taken pct: dummy auras
  10886. AuraEffectList const& mDummyAuras = victim->GetAuraEffectsByType(SPELL_AURA_DUMMY);
  10887. for(AuraEffectList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
  10888. {
  10889. switch((*i)->GetSpellProto()->SpellIconID)
  10890. {
  10891. // Cheat Death
  10892. case 2109:
  10893. if((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
  10894. {
  10895. if(victim->GetTypeId() != TYPEID_PLAYER)
  10896. continue;
  10897. float mod = victim->ToPlayer()->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE) * (-8.0f);
  10898. AddPctF(TakenTotalMod, std::max(mod, float((*i)->GetAmount())));
  10899. }
  10900. break;
  10901. // Blessing of Sanctuary
  10902. // Greater Blessing of Sanctuary
  10903. case 19:
  10904. case 1804:
  10905. {
  10906. if((*i)->GetSpellProto()->SpellFamilyName != SPELLFAMILY_PALADIN)
  10907. continue;
  10908. if((*i)->GetMiscValue() & (spellProto ? GetSpellSchoolMask(spellProto) : 0))
  10909. AddPctN(TakenTotalMod, (*i)->GetAmount());
  10910. break;
  10911. }
  10912. // Ebon Plague
  10913. case 1933:
  10914. if((*i)->GetMiscValue() & (spellProto ? GetSpellSchoolMask(spellProto) : 0))
  10915. AddPctN(TakenTotalMod, (*i)->GetAmount());
  10916. break;
  10917. }
  10918. }
  10919. // .. taken pct: class scripts
  10920. /*AuraEffectList const& mclassScritAuras = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
  10921. for(AuraEffectList::const_iterator i = mclassScritAuras.begin(); i != mclassScritAuras.end(); ++i)
  10922. {
  10923. switch((*i)->GetMiscValue()) { }
  10924. }*/
  10925. if(attType != RANGED_ATTACK)
  10926. {
  10927. AuraEffectList const& mModMeleeDamageTakenPercent = victim->GetAuraEffectsByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT);
  10928. for(AuraEffectList::const_iterator i = mModMeleeDamageTakenPercent.begin(); i != mModMeleeDamageTakenPercent.end(); ++i)
  10929. AddPctN(TakenTotalMod, (*i)->GetAmount());
  10930. }
  10931. else
  10932. {
  10933. AuraEffectList const& mModRangedDamageTakenPercent = victim->GetAuraEffectsByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT);
  10934. for(AuraEffectList::const_iterator i = mModRangedDamageTakenPercent.begin(); i != mModRangedDamageTakenPercent.end(); ++i)
  10935. AddPctN(TakenTotalMod, (*i)->GetAmount());
  10936. }
  10937. float tmpDamage = float(int32(*pdamage) + DoneFlatBenefit) * DoneTotalMod;
  10938. // apply spellmod to Done damage
  10939. if(spellProto)
  10940. if(Player* modOwner = GetSpellModOwner())
  10941. modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, tmpDamage);
  10942. tmpDamage = (tmpDamage + TakenFlatBenefit) * TakenTotalMod;
  10943. // bonus result can be negative
  10944. *pdamage = uint32(std::max(tmpDamage, 0.0f));
  10945. }
  10946. void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply)
  10947. {
  10948. if(apply)
  10949. {
  10950. for(SpellImmuneList::iterator itr = m_spellImmune[op].begin(), next; itr != m_spellImmune[op].end(); itr = next)
  10951. {
  10952. next = itr; ++next;
  10953. if(itr->type == type)
  10954. {
  10955. m_spellImmune[op].erase(itr);
  10956. next = m_spellImmune[op].begin();
  10957. }
  10958. }
  10959. SpellImmune Immune;
  10960. Immune.spellId = spellId;
  10961. Immune.type = type;
  10962. m_spellImmune[op].push_back(Immune);
  10963. }
  10964. else
  10965. {
  10966. for(SpellImmuneList::iterator itr = m_spellImmune[op].begin(); itr != m_spellImmune[op].end(); ++itr)
  10967. {
  10968. if(itr->spellId == spellId && itr->type == type)
  10969. {
  10970. m_spellImmune[op].erase(itr);
  10971. break;
  10972. }
  10973. }
  10974. }
  10975. }
  10976. void Unit::ApplySpellDispelImmunity(const SpellEntry * spellProto, DispelType type, bool apply)
  10977. {
  10978. ApplySpellImmune(spellProto->Id, IMMUNITY_DISPEL, type, apply);
  10979. if(apply && spellProto->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
  10980. {
  10981. // Create dispel mask by dispel type
  10982. uint32 dispelMask = GetDispelMask(type);
  10983. // Dispel all existing auras vs current dispel type
  10984. AuraApplicationMap& auras = GetAppliedAuras();
  10985. for(AuraApplicationMap::iterator itr = auras.begin(); itr != auras.end();)
  10986. {
  10987. SpellEntry const* spell = itr->second->GetBase()->GetSpellProto();
  10988. if((1<<spell->Dispel) & dispelMask)
  10989. {
  10990. // Dispel aura
  10991. RemoveAura(itr);
  10992. }
  10993. else
  10994. ++itr;
  10995. }
  10996. }
  10997. }
  10998. float Unit::GetWeaponProcChance() const
  10999. {
  11000. // normalized proc chance for weapon attack speed
  11001. // (odd formula...)
  11002. if(isAttackReady(BASE_ATTACK))
  11003. return (GetAttackTime(BASE_ATTACK) * 1.8f / 1000.0f);
  11004. else if(haveOffhandWeapon() && isAttackReady(OFF_ATTACK))
  11005. return (GetAttackTime(OFF_ATTACK) * 1.6f / 1000.0f);
  11006. return 0;
  11007. }
  11008. float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM, const SpellEntry * spellProto) const
  11009. {
  11010. // proc per minute chance calculation
  11011. if(PPM <= 0) return 0.0f;
  11012. // Apply chance modifer aura
  11013. if(spellProto)
  11014. if(Player* modOwner = GetSpellModOwner())
  11015. modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_PROC_PER_MINUTE, PPM);
  11016. return floor((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
  11017. }
  11018. void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry)
  11019. {
  11020. if(mount)
  11021. SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, mount);
  11022. SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT);
  11023. if(Player* pPlayer = ToPlayer())
  11024. {
  11025. // mount as a vehicle
  11026. if(VehicleId)
  11027. {
  11028. if(CreateVehicleKit(VehicleId, creatureEntry))
  11029. {
  11030. GetVehicleKit()->Reset();
  11031. // Send others that we now have a vehicle
  11032. WorldPacket data(SMSG_PLAYER_VEHICLE_DATA, GetPackGUID().size()+4);
  11033. data.appendPackGUID(GetGUID());
  11034. data << uint32(VehicleId);
  11035. SendMessageToSet(&data, true);
  11036. data.Initialize(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0);
  11037. pPlayer->GetSession()->SendPacket(&data);
  11038. // mounts can also have accessories
  11039. GetVehicleKit()->InstallAllAccessories(false);
  11040. }
  11041. }
  11042. // unsummon pet
  11043. if(Pet* pPet = pPlayer->GetPet())
  11044. {
  11045. Battleground* pBG = ToPlayer()->GetBattleground();
  11046. // don't unsummon pet in arena but SetFlag UNIT_FLAG_STUNNED to disable pet's interface
  11047. if(pBG && pBG->isArena())
  11048. pPet->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
  11049. else
  11050. pPlayer->UnsummonPetTemporaryIfAny();
  11051. }
  11052. }
  11053. RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNT);
  11054. }
  11055. void Unit::Unmount()
  11056. {
  11057. if(!IsMounted())
  11058. return;
  11059. SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0);
  11060. RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT);
  11061. WorldPacket data(SMSG_DISMOUNT, 8);
  11062. data.appendPackGUID(GetGUID());
  11063. SendMessageToSet(&data, true);
  11064. // unmount as a vehicle
  11065. if(GetTypeId() == TYPEID_PLAYER && GetVehicleKit())
  11066. {
  11067. // Send other players that we are no longer a vehicle
  11068. WorldPacket data(SMSG_PLAYER_VEHICLE_DATA, 8+4);
  11069. data.appendPackGUID(GetGUID());
  11070. data << uint32(0);
  11071. ToPlayer()->SendMessageToSet(&data, true);
  11072. // Remove vehicle from player
  11073. RemoveVehicleKit();
  11074. }
  11075. RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_MOUNTED);
  11076. // only resummon old pet if the player is already added to a map
  11077. // this prevents adding a pet to a not created map which would otherwise cause a crash
  11078. // (it could probably happen when logging in after a previous crash)
  11079. if(Player* plr = ToPlayer())
  11080. {
  11081. if(Pet* pPet = plr->GetPet())
  11082. {
  11083. if(pPet->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED) && !pPet->HasUnitState(UNIT_STAT_STUNNED))
  11084. pPet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
  11085. }
  11086. else
  11087. plr->ResummonPetTemporaryUnSummonedIfAny();
  11088. }
  11089. }
  11090. void Unit::SetInCombatWith(Unit* enemy)
  11091. {
  11092. Unit* eOwner = enemy->GetCharmerOrOwnerOrSelf();
  11093. if(eOwner->IsPvP())
  11094. {
  11095. SetInCombatState(true, enemy);
  11096. return;
  11097. }
  11098. // check for duel
  11099. if(eOwner->GetTypeId() == TYPEID_PLAYER && eOwner->ToPlayer()->duel)
  11100. {
  11101. Unit const* myOwner = GetCharmerOrOwnerOrSelf();
  11102. if(((Player const*)eOwner)->duel->opponent == myOwner)
  11103. {
  11104. SetInCombatState(true, enemy);
  11105. return;
  11106. }
  11107. }
  11108. SetInCombatState(false, enemy);
  11109. }
  11110. void Unit::CombatStart(Unit* target, bool initialAggro)
  11111. {
  11112. if(initialAggro)
  11113. {
  11114. if(!target->IsStandState())
  11115. target->SetStandState(UNIT_STAND_STATE_STAND);
  11116. if(!target->isInCombat() && target->GetTypeId() != TYPEID_PLAYER
  11117. && !target->ToCreature()->HasReactState(REACT_PASSIVE) && target->ToCreature()->IsAIEnabled)
  11118. {
  11119. target->ToCreature()->AI()->AttackStart(this);
  11120. }
  11121. SetInCombatWith(target);
  11122. target->SetInCombatWith(this);
  11123. }
  11124. Unit* who = target->GetCharmerOrOwnerOrSelf();
  11125. if(who->GetTypeId() == TYPEID_PLAYER)
  11126. SetContestedPvP(who->ToPlayer());
  11127. Player* me = GetCharmerOrOwnerPlayerOrPlayerItself();
  11128. if(me && who->IsPvP()
  11129. && (who->GetTypeId() != TYPEID_PLAYER
  11130. || !me->duel || me->duel->opponent != who))
  11131. {
  11132. me->UpdatePvP(true);
  11133. me->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
  11134. }
  11135. }
  11136. void Unit::SetInCombatState(bool PvP, Unit* enemy)
  11137. {
  11138. // only alive units can be in combat
  11139. if(!isAlive())
  11140. return;
  11141. if(PvP)
  11142. m_CombatTimer = 5000;
  11143. if(isInCombat() || HasUnitState(UNIT_STAT_EVADE))
  11144. return;
  11145. SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
  11146. if(Creature* creature = ToCreature())
  11147. {
  11148. // Set home position at place of engaging combat for escorted creatures
  11149. if((IsAIEnabled && creature->AI()->IsEscorted()) ||
  11150. GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE ||
  11151. GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE)
  11152. creature->SetHomePosition(GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
  11153. if(enemy)
  11154. {
  11155. if(IsAIEnabled)
  11156. {
  11157. creature->AI()->EnterCombat(enemy);
  11158. RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); // always remove Out of Combat Non Attackable flag if we enter combat and AI is enabled
  11159. }
  11160. if(creature->GetFormation())
  11161. creature->GetFormation()->MemberAttackStart(creature, enemy);
  11162. }
  11163. if(isPet())
  11164. {
  11165. UpdateSpeed(MOVE_RUN, true);
  11166. UpdateSpeed(MOVE_SWIM, true);
  11167. UpdateSpeed(MOVE_FLIGHT, true);
  11168. }
  11169. if(!(creature->GetCreatureInfo()->type_flags & CREATURE_TYPEFLAGS_MOUNTED_COMBAT))
  11170. Unmount();
  11171. }
  11172. for(Unit::ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
  11173. {
  11174. (*itr)->SetInCombatState(PvP, enemy);
  11175. (*itr)->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
  11176. }
  11177. }
  11178. void Unit::ClearInCombat()
  11179. {
  11180. m_CombatTimer = 0;
  11181. RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
  11182. // Player's state will be cleared in Player::UpdateContestedPvP
  11183. if(Creature* creature = ToCreature())
  11184. {
  11185. if(creature->GetCreatureInfo() && creature->GetCreatureInfo()->unit_flags & UNIT_FLAG_OOC_NOT_ATTACKABLE)
  11186. SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); // re-apply Out of Combat Non Attackable flag if we leave combat, can be overriden in scripts in EnterEvadeMode()
  11187. ClearUnitState(UNIT_STAT_ATTACK_PLAYER);
  11188. if(HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TAPPED))
  11189. SetUInt32Value(UNIT_DYNAMIC_FLAGS, creature->GetCreatureInfo()->dynamicflags);
  11190. if(creature->isPet())
  11191. {
  11192. if(Unit* owner = GetOwner())
  11193. for(uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
  11194. if(owner->GetSpeedRate(UnitMoveType(i)) > GetSpeedRate(UnitMoveType(i)))
  11195. SetSpeed(UnitMoveType(i), owner->GetSpeedRate(UnitMoveType(i)), true);
  11196. }
  11197. else if(!isCharmed())
  11198. return;
  11199. }
  11200. else
  11201. ToPlayer()->UpdatePotionCooldown();
  11202. RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
  11203. }
  11204. // TODO: remove this function
  11205. bool Unit::isTargetableForAttack() const
  11206. {
  11207. return isAttackableByAOE() && !HasUnitState(UNIT_STAT_DIED);
  11208. }
  11209. bool Unit::canAttack(Unit const* target, bool force) const
  11210. {
  11211. ASSERT(target);
  11212. if(force)
  11213. {
  11214. if(IsFriendlyTo(target))
  11215. return false;
  11216. if(GetTypeId() != TYPEID_PLAYER)
  11217. {
  11218. if(isPet())
  11219. {
  11220. if(Unit* owner = GetOwner())
  11221. if(!(owner->canAttack(target)))
  11222. return false;
  11223. }
  11224. else if(!IsHostileTo(target))
  11225. return false;
  11226. }
  11227. }
  11228. else if(!IsHostileTo(target))
  11229. return false;
  11230. if(!target->isAttackableByAOE())
  11231. return false;
  11232. if(target->HasUnitState(UNIT_STAT_DIED) && GetTypeId() != TYPEID_PLAYER)
  11233. {
  11234. if(!ToCreature() || !ToCreature()->isGuard())
  11235. return false;
  11236. // guards can detect fake death