OregonCore  revision be9e804-git
Your Favourite TBC server
Unit.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the OregonCore Project. See AUTHORS file for Copyright information
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation; either version 2 of the License, or (at your
7  * option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Common.h"
19 #include "Log.h"
20 #include "Opcodes.h"
21 #include "WorldPacket.h"
22 #include "WorldSession.h"
23 #include "World.h"
24 #include "ObjectMgr.h"
25 #include "SpellMgr.h"
26 #include "Unit.h"
27 #include "QuestDef.h"
28 #include "Player.h"
29 #include "Creature.h"
30 #include "Spell.h"
31 #include "Group.h"
32 #include "SpellAuras.h"
33 #include "ObjectAccessor.h"
34 #include "CreatureAI.h"
35 #include "Formulas.h"
36 #include "Pet.h"
37 #include "Utilities/Util.h"
38 #include "Totem.h"
39 #include "Battleground.h"
40 #include "OutdoorPvP.h"
41 #include "InstanceSaveMgr.h"
42 #include "GridNotifiersImpl.h"
43 #include "CellImpl.h"
44 #include "CreatureGroups.h"
45 #include "PetAI.h"
46 #include "PassiveAI.h"
47 #include "TemporarySummon.h"
48 #include "PathFinder.h"
49 #include "ScriptMgr.h"
50 #include "Object.h"
51 #include "MovementGenerator.h"
52 #include "MoveSplineInit.h"
53 #include "MoveSpline.h"
54 
55 #include <math.h>
56 #include <array>
57 
59 {
60  2.5f, // MOVE_WALK
61  7.0f, // MOVE_RUN
62  4.5f, // MOVE_RUN_BACK
63  4.722222f, // MOVE_SWIM
64  2.5f, // MOVE_SWIM_BACK
65  3.141594f, // MOVE_TURN_RATE
66  7.0f, // MOVE_FLIGHT
67  4.5f, // MOVE_FLIGHT_BACK
68 };
69 
70 // Used for preapre can/can't trigger aura
71 void InitTriggerAuraData();
72 
73 // auraTypes contains attacker auras capable of proc'ing cast auras
74 static Unit::AuraTypeSet GenerateAttakerProcCastAuraTypes()
75 {
76  static Unit::AuraTypeSet auraTypes;
77  auraTypes.insert(SPELL_AURA_DUMMY);
78  auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL);
79  auraTypes.insert(SPELL_AURA_MOD_HASTE);
80  auraTypes.insert(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
81  return auraTypes;
82 }
83 
84 // auraTypes contains victim auras capable of proc'ing cast auras
85 static Unit::AuraTypeSet GenerateVictimProcCastAuraTypes()
86 {
87  static Unit::AuraTypeSet auraTypes;
88  auraTypes.insert(SPELL_AURA_DUMMY);
89  auraTypes.insert(SPELL_AURA_PRAYER_OF_MENDING);
90  auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL);
91  return auraTypes;
92 }
93 
94 // auraTypes contains auras capable of proc effect/damage (but not cast) for attacker
95 static Unit::AuraTypeSet GenerateAttakerProcEffectAuraTypes()
96 {
97  static Unit::AuraTypeSet auraTypes;
98  auraTypes.insert(SPELL_AURA_MOD_DAMAGE_DONE);
99  auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE);
100  auraTypes.insert(SPELL_AURA_MOD_CASTING_SPEED);
101  auraTypes.insert(SPELL_AURA_MOD_RATING);
102  return auraTypes;
103 }
104 
105 // auraTypes contains auras capable of proc effect/damage (but not cast) for victim
106 static Unit::AuraTypeSet GenerateVictimProcEffectAuraTypes()
107 {
108  static Unit::AuraTypeSet auraTypes;
109  auraTypes.insert(SPELL_AURA_MOD_RESISTANCE);
110  auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE);
111  auraTypes.insert(SPELL_AURA_MOD_PARRY_PERCENT);
112  auraTypes.insert(SPELL_AURA_MOD_BLOCK_PERCENT);
113  auraTypes.insert(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
114  return auraTypes;
115 }
116 
117 static Unit::AuraTypeSet attackerProcCastAuraTypes = GenerateAttakerProcCastAuraTypes();
118 static Unit::AuraTypeSet attackerProcEffectAuraTypes = GenerateAttakerProcEffectAuraTypes();
119 
120 static Unit::AuraTypeSet victimProcCastAuraTypes = GenerateVictimProcCastAuraTypes();
121 static Unit::AuraTypeSet victimProcEffectAuraTypes = GenerateVictimProcEffectAuraTypes();
122 
123 // auraTypes contains auras capable of proc'ing for attacker and victim
124 static Unit::AuraTypeSet GenerateProcAuraTypes()
125 {
127 
128  Unit::AuraTypeSet auraTypes;
129  auraTypes.insert(attackerProcCastAuraTypes.begin(), attackerProcCastAuraTypes.end());
130  auraTypes.insert(attackerProcEffectAuraTypes.begin(), attackerProcEffectAuraTypes.end());
131  auraTypes.insert(victimProcCastAuraTypes.begin(), victimProcCastAuraTypes.end());
132  auraTypes.insert(victimProcEffectAuraTypes.begin(), victimProcEffectAuraTypes.end());
133  return auraTypes;
134 }
135 
136 static Unit::AuraTypeSet procAuraTypes = GenerateProcAuraTypes();
137 
139 {
140  if (!IsPassiveSpell(spellId))
141  return false;
142 
143  SpellEntry const* spellProto = sSpellStore.LookupEntry(spellId);
144  if (!spellProto)
145  return false;
146 
147  for (int j = 0; j < MAX_SPELL_EFFECTS; ++j)
148  {
149  if (std::find(procAuraTypes.begin(), procAuraTypes.end(), spellProto->EffectApplyAuraName[j]) != procAuraTypes.end())
150  return false;
151  }
152 
153  return true;
154 }
155 
156 typedef std::array<uint32, NUM_SPELL_PARTIAL_RESISTS> SpellPartialResistChanceEntry;
157 typedef std::vector<SpellPartialResistChanceEntry> SpellPartialResistDistribution;
158 static inline SpellPartialResistDistribution InitSpellPartialResistDistribution()
159 {
160  // Precalculated chances for 0-100% mitigation
161  // We use integer random instead of floats, so each chance is premultiplied by 100 (100.00 becomes 10000)
162  const SpellPartialResistDistribution precalculated = {
163  {{10000,0,0,0,0}},
164  {{9700,200,100,0,0}},
165  {{9400,400,200,0,0}},
166  {{9000,800,200,0,0}},
167  {{8700,1000,300,0,0}},
168  {{8400,1200,400,0,0}},
169  {{8200,1300,400,100,0}},
170  {{7900,1500,500,100,0}},
171  {{7600,1700,600,100,0}},
172  {{7300,1900,700,100,0}},
173  {{6900,2300,700,100,0}},
174  {{6600,2500,800,100,0}},
175  {{6300,2700,900,100,0}},
176  {{6000,2900,1000,100,0}},
177  {{5800,3000,1000,200,0}},
178  {{5400,3300,1100,200,0}},
179  {{5100,3600,1100,200,0}},
180  {{4800,3800,1200,200,0}},
181  {{4400,4200,1200,200,0}},
182  {{4100,4400,1300,200,0}},
183  {{3700,4800,1300,200,0}},
184  {{3400,5000,1400,200,0}},
185  {{3100,5200,1500,200,0}},
186  {{3000,5200,1500,200,100}},
187  {{2800,5300,1500,300,100}},
188  {{2500,5500,1600,300,100}},
189  {{2400,5400,1700,400,100}},
190  {{2300,5300,1800,500,100}},
191  {{2200,5100,2100,500,100}},
192  {{2100,5000,2200,600,100}},
193  {{2000,4900,2400,600,100}},
194  {{1900,4700,2600,700,100}},
195  {{1800,4600,2700,800,100}},
196  {{1700,4400,3000,800,100}},
197  {{1600,4300,3100,900,100}},
198  {{1500,4200,3200,1000,100}},
199  {{1400,4100,3300,1100,100}},
200  {{1300,3900,3600,1100,100}},
201  {{1300,3600,3800,1200,100}},
202  {{1200,3500,3900,1300,100}},
203  {{1100,3400,4000,1400,100}},
204  {{1000,3300,4100,1500,100}},
205  {{900,3100,4400,1500,100}},
206  {{800,3000,4500,1600,100}},
207  {{800,2700,4700,1700,100}},
208  {{700,2600,4800,1800,100}},
209  {{600,2500,4900,1900,100}},
210  {{600,2300,5000,1900,200}},
211  {{500,2200,5100,2000,200}},
212  {{300,2200,5300,2000,200}},
213  {{200,2100,5400,2100,200}},
214  {{200,2000,5300,2200,300}},
215  {{200,2000,5100,2200,500}},
216  {{200,1900,5000,2300,600}},
217  {{100,1900,4900,2500,600}},
218  {{100,1800,4800,2600,700}},
219  {{100,1700,4700,2700,800}},
220  {{100,1600,4500,3000,800}},
221  {{100,1500,4400,3100,900}},
222  {{100,1500,4100,3300,1000}},
223  {{100,1400,4000,3400,1100}},
224  {{100,1300,3900,3500,1200}},
225  {{100,1200,3800,3600,1300}},
226  {{100,1100,3600,3900,1300}},
227  {{100,1100,3300,4100,1400}},
228  {{100,1000,3200,4200,1500}},
229  {{100,900,3100,4300,1600}},
230  {{100,800,3000,4400,1700}},
231  {{100,800,2700,4600,1800}},
232  {{100,700,2600,4700,1900}},
233  {{100,600,2400,4900,2000}},
234  {{100,600,2200,5000,2100}},
235  {{100,500,2100,5100,2200}},
236  {{100,500,1800,5300,2300}},
237  {{100,400,1700,5400,2400}},
238  {{100,300,1600,5500,2500}},
239  {{100,300,1500,5300,2800}},
240  {{100,200,1500,5200,3000}},
241  {{0,200,1500,5200,3100}},
242  {{0,200,1400,5000,3400}},
243  {{0,200,1300,4800,3700}},
244  {{0,200,1300,4400,4100}},
245  {{0,200,1200,4200,4400}},
246  {{0,200,1200,3800,4800}},
247  {{0,200,1100,3600,5100}},
248  {{0,200,1100,3300,5400}},
249  {{0,200,1000,3000,5800}},
250  {{0,100,1000,2900,6000}},
251  {{0,100,900,2700,6300}},
252  {{0,100,800,2500,6600}},
253  {{0,100,700,2300,6900}},
254  {{0,100,700,1900,7300}},
255  {{0,100,600,1700,7600}},
256  {{0,100,500,1500,7900}},
257  {{0,100,400,1300,8200}},
258  {{0,0,400,1200,8400}},
259  {{0,0,300,1000,8700}},
260  {{0,0,200,800,9000}},
261  {{0,0,200,400,9400}},
262  {{0,0,100,200,9700}},
263  {{0,0,0,0,10000}},
264  };
265  // Inflate up to two decimal places of chance %: add intermediate values
267  for (size_t index = 0; index < precalculated.size(); ++index)
268  {
269  for (uint8 intermediate = 0; intermediate < 100; ++intermediate)
270  {
271  // Check if this is the last one first
272  if ((index + 1) == precalculated.size())
273  {
274  inflated.push_back(precalculated[index]);
275  break;
276  }
278  for (uint8 column = SPELL_PARTIAL_RESIST_NONE; column < NUM_SPELL_PARTIAL_RESISTS; ++column)
279  {
280  const uint32 base = precalculated.at(index).at(column);
281  const uint32 next = precalculated.at(index + 1).at(column);
282  values[column] = base + ((next - base) * intermediate / 100);
283  }
284  inflated.push_back(values);
285  }
286  }
287  return inflated;
288 }
289 
290 static const SpellPartialResistDistribution SPELL_PARTIAL_RESIST_DISTRIBUTION = InitSpellPartialResistDistribution();
291 
293 {
294  data >> moveFlags;
295  data >> moveFlags2;
296  data >> time;
297  data >> pos.m_positionX;
298  data >> pos.m_positionY;
299  data >> pos.m_positionZ;
300  pos.SetOrientation(data.read<float>());
301 
303  {
304  data >> t_guid;
305  data >> t_pos.m_positionX;
306  data >> t_pos.m_positionY;
307  data >> t_pos.m_positionZ;
308  t_pos.SetOrientation(data.read<float>());
309  data >> t_time;
310  }
312  data >> s_pitch;
313 
314  data >> fallTime;
315 
317  {
318  data >> j_velocity;
319  data >> j_sinAngle;
320  data >> j_cosAngle;
321  data >> j_xyspeed;
322  }
323 
325  data >> u_unk1;
326 }
327 
329 {
330  data << moveFlags;
331  data << moveFlags2;
332  data << time;
333  data << pos.GetPositionX();
334  data << pos.GetPositionY();
335  data << pos.GetPositionZ();
336  data << pos.GetOrientation();
337 
339  {
340  data << t_guid;
341  data << t_pos.GetPositionX();
342  data << t_pos.GetPositionY();
343  data << t_pos.GetPositionZ();
344  data << t_pos.GetOrientation();
345  data << t_time;
346  }
348  data << s_pitch;
349 
350  data << fallTime;
351 
353  {
354  data << j_velocity;
355  data << j_sinAngle;
356  data << j_cosAngle;
357  data << j_xyspeed;
358  }
359 
361  data << u_unk1;
362 }
363 
364 Unit::Unit(bool isWorldObject):
365  WorldObject(isWorldObject), IsAIEnabled(false),
366  NeedChangeAI(false),
367  LastCharmerGUID(0),
368  m_ControlledByPlayer(false),
369  i_AI(NULL),
370  i_disabledAI(NULL),
371  m_removedAurasCount(0),
372  i_motionMaster(this),
373  m_ThreatManager(this),
374  m_HostileRefManager(this),
375  m_lastSanctuaryTime(0),
376  m_procDeep(0),
377  movespline(new Movement::MoveSpline()),
378  m_movesplineTimer(POSITION_UPDATE_DELAY),
379  _lastDamagedTime(0)
380 {
383 
385 
392 
393  m_extraAttacks = 0;
394  m_canDualWield = false;
395 
396  m_state = 0;
397  m_form = FORM_NONE;
399 
400  for (uint8 i = 0; i < CURRENT_MAX_SPELL; ++i)
401  m_currentSpells[i] = NULL;
402 
403  for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
404  m_SummonSlot[i] = 0;
405 
406  m_ObjectSlot[0] = m_ObjectSlot[1] = m_ObjectSlot[2] = m_ObjectSlot[3] = 0;
407 
409  m_AuraFlags = 0;
410 
411  m_interruptMask = 0;
412  m_transform = 0;
414  m_canModifyStats = false;
415 
416  for (uint8 i = 0; i < MAX_SPELL_IMMUNITY; ++i)
417  m_spellImmune[i].clear();
418 
419  for (uint8 i = 0; i < UNIT_MOD_END; ++i)
420  {
421  m_auraModifiersGroup[i][BASE_VALUE] = 0.0f;
422  m_auraModifiersGroup[i][BASE_PCT] = 1.0f;
424  m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f;
425  }
426  // implement 50% base damage from offhand
428 
429  for (uint8 i = 0; i < MAX_ATTACK; ++i)
430  {
433  }
434 
435  for (uint8 i = 0; i < MAX_STATS; ++i)
436  m_createStats[i] = 0.0f;
437 
438  m_attacking = NULL;
439  m_modMeleeHitChance = 0.0f;
440  m_modRangedHitChance = 0.0f;
441  m_modSpellHitChance = 0.0f;
443 
444  m_initiatingCombat = false;
445 
447  m_lastManaUse = 0;
448 
449  for (uint8 i = 0; i < MAX_SPELL_SCHOOL; ++i)
450  m_threatModifier[i] = 1.0f;
451 
452  m_isSorted = true;
453 
454  for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
455  m_speed_rate[i] = 1.0f;
456 
458 
459  m_charmInfo = NULL;
462 
463  // remove aurastates allowing special moves
464  for (uint8 i = 0; i < MAX_REACTIVE; ++i)
465  m_reactiveTimer[i] = 0;
466 
467  m_duringRemoveFromWorld = false;
468 
469  m_baseSpeedWalk = 0.f;
470  m_baseSpeedRun = 0.f;
471 
472  _oldFactionId = 0;
473 
475 }
476 
478 {
479  // set current spells as deletable
480  for (uint8 i = 0; i < CURRENT_MAX_SPELL; ++i)
481  if (m_currentSpells[i])
482  {
484  m_currentSpells[i] = NULL;
485  }
486 
489  _DeleteAuras();
490 
491  delete m_charmInfo;
492  delete movespline;
493 
496  ASSERT(m_attackers.empty());
497  ASSERT(m_sharedVision.empty());
498 }
499 
500 // Check if unit in combat with specific unit
501 bool Unit::IsInCombatWith(Unit const* who) const
502 {
503  // Check target exists
504  if (!who)
505  return false;
506 
507  // Search in threat list
508  uint64 guid = who->GetGUID();
510  for (ThreatContainer::StorageType::const_iterator i = threatList.begin(); i != threatList.end(); ++i)
511  {
512  HostileReference* ref = (*i);
513 
514  // Return true if the unit matches
515  if (ref && ref->getUnitGuid() == guid)
516  return true;
517  }
518 
519  // Nothing found, false.
520  return false;
521 }
522 
523 void Unit::Update(uint32 p_time)
524 {
525  // WARNING! Order of execution here is important, do not change.
526  // Spells must be processed with event system BEFORE they go to _UpdateSpells.
527  // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad.
528  m_Events.Update(p_time);
529 
530  if (!IsInWorld())
531  return;
532 
533  _UpdateSpells(p_time);
534 
535  if (uint32 base_att = getAttackTimer(BASE_ATTACK))
536  setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time));
537 
538  if (uint32 base_att = getAttackTimer(OFF_ATTACK))
539  setAttackTimer(OFF_ATTACK, (p_time >= base_att ? 0 : base_att - p_time));
540 
541  if (uint32 ranged_att = getAttackTimer(RANGED_ATTACK))
542  setAttackTimer(RANGED_ATTACK, (p_time >= ranged_att ? 0 : ranged_att - p_time));
543 
544  // update abilities available only for fraction of time
545  UpdateReactives(p_time);
546 
547  if (IsAlive())
548  {
551  }
552 
553  UpdateSplineMovement(p_time);
555 
556  if (IsInCombat() && (GetTypeId() == TYPEID_PLAYER || (IsPet() && IsControlledByPlayer())))
557  {
558  if (getHostileRefManager().isEmpty())
560  ClearInCombat();
561  else
563  m_CombatTimer.Update(p_time);
564  }
565 }
566 
568 {
569  Unit *victim = GetVictim();
570  if (!victim || IsNonMeleeSpellCast(false))
571  return false;
572 
574  return false;
575 
576  uint8 swingError = 0;
577  if (!IsWithinMeleeRange(victim))
578  {
581  swingError = 1;
582  }
583  //120 degrees of radiant range
584  else if (!HasInArc(2 * M_PI / 3, victim))
585  {
588  swingError = 2;
589  }
590  else
591  {
593  {
594  // prevent base and off attack in same time, delay attack at 0.2 sec
595  if (haveOffhandWeapon())
596  {
599  }
602  }
604  {
605  // prevent base and off attack in same time, delay attack at 0.2 sec
606  uint32 base_att = getAttackTimer(BASE_ATTACK);
607  if (base_att < ATTACK_DISPLAY_DELAY)
609  // do attack
612  }
613  }
614 
615  Player* player = (GetTypeId() == TYPEID_PLAYER ? (Player*)this : NULL);
616  if (player && swingError != player->LastSwingErrorMsg())
617  {
618  if (swingError == 1)
619  player->SendAttackSwingNotInRange();
620  else if (swingError == 2)
622  player->SwingErrorMsg(swingError);
623  }
624 
625  return swingError == 0;
626 }
627 
629 {
630  if (GetTypeId() == TYPEID_PLAYER)
631  return ((Player*)this)->GetWeaponForAttack(OFF_ATTACK, true);
632  else
633  {
635  if (itemClass == ITEM_CLASS_WEAPON)
636  return true;
637 
638  return false;
639  }
640 
641  return CanDualWield();
642 }
643 
645 {
646  m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]);
647 }
648 
650 {
651  AuraList const& auras = GetAurasByType(type);
652  for (AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
653  if ((!excludeAura || excludeAura != (*itr)->GetSpellProto()->Id) &&
654  ((*itr)->GetSpellProto()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_DAMAGE))
655  return true;
656  return false;
657 }
658 
659 bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) const
660 {
661  uint32 excludeAura = 0;
662  if (Spell* currentChanneledSpell = excludeCasterChannel ? excludeCasterChannel->GetCurrentSpell(CURRENT_CHANNELED_SPELL) : NULL)
663  excludeAura = currentChanneledSpell->m_spellInfo->Id;
664 
670 }
671 
672 bool Unit::IsWithinCombatRange(const Unit* obj, float dist2compare) const
673 {
674  if (!obj || !IsInMap(obj) || !InSamePhase(obj))
675  return false;
676 
677  float dx = GetPositionX() - obj->GetPositionX();
678  float dy = GetPositionY() - obj->GetPositionY();
679  float dz = GetPositionZ() - obj->GetPositionZ();
680  float distsq = dx * dx + dy * dy + dz * dz;
681 
682  float sizefactor = GetCombatReach() + obj->GetCombatReach();
683  float maxdist = dist2compare + sizefactor;
684 
685  return distsq < maxdist * maxdist;
686 }
687 
688 bool Unit::IsWithinMeleeRange(Unit* obj, float dist) const
689 {
690  if (!obj || !IsInMap(obj) || !InSamePhase(obj))
691  return false;
692 
693  float dx = GetPositionX() - obj->GetPositionX();
694  float dy = GetPositionY() - obj->GetPositionY();
695  float dz = GetPositionZ() - obj->GetPositionZ();
696  float distsq = dx * dx + dy * dy + dz * dz;
697 
698  float sizefactor = GetMeleeReach() + obj->GetMeleeReach();
699  float maxdist = dist + sizefactor;
700 
701  return distsq < maxdist * maxdist;
702 }
703 
704 void Unit::GetRandomContactPoint(const Unit* obj, float& x, float& y, float& z, float distance2dMin, float distance2dMax) const
705 {
706  float combat_reach = GetCombatReach();
707  if (combat_reach < 0.1) // sometimes bugged for players
708  {
709  //sLog.outError("Unit %u (Type: %u) has invalid combat_reach %f",GetGUIDLow(),GetTypeId(),combat_reach);
710  //if (GetTypeId() == TYPEID_UNIT)
711  // sLog.outError("Creature entry %u has invalid combat_reach", ToCreature()->GetEntry());
712  combat_reach = DEFAULT_COMBAT_REACH;
713  }
714  uint32 attacker_number = getAttackers().size();
715  if (attacker_number > 0)
716  --attacker_number;
717  GetNearPoint(obj, x, y, z, obj->GetCombatReach(), distance2dMin + (distance2dMax - distance2dMin) * (float)rand_norm()
718  , 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));
719 }
720 
722 {
723  for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
724  {
725  if (sSpellMgr.GetSpellCustomAttr(iter->second->GetId()) & SPELL_ATTR_CU_MOVEMENT_IMPAIR)
726  RemoveAura(iter);
727  else
728  ++iter;
729  }
730 }
731 
733 {
734  if (auraType >= TOTAL_AURAS)
735  return;
736 
737  AuraList::iterator iter, next;
738  for (iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end(); iter = next)
739  {
740  next = iter;
741  ++next;
742 
743  if (*iter)
744  {
745  RemoveAurasDueToSpell((*iter)->GetId());
746  if (!m_modAuras[auraType].empty())
747  next = m_modAuras[auraType].begin();
748  else
749  return;
750  }
751  }
752 }
753 
754 void Unit::RemoveAuraTypeByCaster(AuraType auraType, uint64 casterGUID)
755 {
756  if (auraType >= TOTAL_AURAS) return;
757 
758  for (AuraList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
759  {
760  Aura* aur = *iter;
761  ++iter;
762 
763  if (aur)
764  {
765  uint32 removedAuras = m_removedAurasCount;
766  RemoveAurasByCasterSpell(aur->GetId(), casterGUID);
767  if (m_removedAurasCount > removedAuras + 1)
768  iter = m_modAuras[auraType].begin();
769  }
770  }
771 }
772 
774 {
775  if (!(m_interruptMask & flag))
776  return;
777 
778  // interrupt auras
779  AuraList::iterator iter;
780  for (iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end();)
781  {
782  Aura* aur = *iter;
783  ++iter;
784 
785  //sLog.outDetail("auraflag:%u flag:%u = %u", aur->GetSpellProto()->AuraInterruptFlags,flag, aur->GetSpellProto()->AuraInterruptFlags & flag);
786 
787  if (aur && (aur->GetSpellProto()->AuraInterruptFlags & flag))
788  {
789  if (aur->IsInUse())
790  sLog.outError("Aura %u is trying to remove itself! Flag %u. May cause crash!", aur->GetId(), flag);
791 
792  else if (!except || aur->GetId() != except)
793  {
794  uint32 removedAuras = m_removedAurasCount;
795 
797  if (m_removedAurasCount > removedAuras + 1)
798  iter = m_interruptableAuras.begin();
799 
800  }
801  }
802  }
803 
804  // interrupt channeled spell
806  if (spell->getState() == SPELL_STATE_CASTING
807  && (spell->m_spellInfo->ChannelInterruptFlags & flag)
808  && spell->m_spellInfo->Id != except)
810 
812 }
813 
815 {
816  m_interruptMask = 0;
817  for (AuraList::iterator i = m_interruptableAuras.begin(); i != m_interruptableAuras.end(); ++i)
818  {
819  if (*i)
820  m_interruptMask |= (*i)->GetSpellProto()->AuraInterruptFlags;
821  }
823  if (spell->getState() == SPELL_STATE_CASTING)
824  m_interruptMask |= spell->m_spellInfo->ChannelInterruptFlags;
825 }
826 
828 {
829  uint32 count = 0;
830  for (AuraMap::const_iterator itr = m_Auras.lower_bound(spellEffectPair(spellId, 0)); itr != m_Auras.upper_bound(spellEffectPair(spellId, 0)); ++itr)
831  {
832  if (!itr->second->GetStackAmount())
833  count++;
834  else
835  count += (uint32)itr->second->GetStackAmount();
836  }
837 
838  return count;
839 }
840 
847 bool Unit::HasHigherRankOfAura(uint32 spellid, uint8 effIndex) const
848 {
849  if (SpellChainNode const* curr = sSpellMgr.GetSpellChainNode(spellid))
850  {
851  SpellChainNode const* node = sSpellMgr.GetSpellChainNode(curr->first);
852  uint32 spell = curr->first;
853 
854  while (spell)
855  {
856  AuraMap::const_iterator aura = m_Auras.find(spellEffectPair(spell, effIndex));
857  if (aura != m_Auras.end())
858  if (node->rank > curr->rank)
859  return true;
860 
861  spell = node->next;
862  node = sSpellMgr.GetSpellChainNode(node->next);
863  }
864  }
865 
866  return false;
867 }
868 
869 bool Unit::HasAuraType(AuraType auraType) const
870 {
871  return (!m_modAuras[auraType].empty());
872 }
873 
874 bool Unit::HasAuraTypeWithCaster(AuraType auratype, uint64 caster) const
875 {
876  Unit::AuraList const& mTotalAuraList = GetAurasByType(auratype);
877  for (Unit::AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
878  if (caster == (*i)->GetCasterGUID())
879  return true;
880  return false;
881 }
882 
883 bool Unit::HasAuraTypeWithMiscvalue(AuraType auratype, int32 miscvalue) const
884 {
885  Unit::AuraList const& mTotalAuraList = GetAurasByType(auratype);
886  for (Unit::AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
887  if (miscvalue == (*i)->GetMiscValue())
888  return true;
889  return false;
890 }
891 
892 bool Unit::HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, uint64 familyFlags) const
893 {
894  if (!HasAuraType(auraType))
895  return false;
896  AuraList const& auras = GetAurasByType(auraType);
897  for (AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
898  if (SpellEntry const* iterSpellProto = (*itr)->GetSpellProto())
899  if (iterSpellProto->SpellFamilyName == familyName && iterSpellProto->SpellFamilyFlags & familyFlags)
900  return true;
901  return false;
902 }
903 
905 {
906  if (!(m_interruptMask & flag))
907  return false;
908 
909  // interrupt auras
910  AuraList::iterator iter;
911  for (iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end();)
912  {
913  Aura* aur = *iter;
914  ++iter;
915  if (!aur->IsPositive() && aur->GetSpellProto()->AuraInterruptFlags & flag)
916  return true;
917  }
918 
919  return false;
920 }
921 
922 
923 /* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */
925 {
926  // The chance to dispel an aura depends on the damage taken with respect to the casters level.
927  uint32 max_dmg = getLevel() > 8 ? 30 * getLevel() - 100 : 50;
928  float chance = float(damage) / max_dmg * 100.0f;
929 
930  AuraList::iterator i, next;
931  for (i = m_ccAuras.begin(); i != m_ccAuras.end(); i = next)
932  {
933  next = i;
934  ++next;
935 
936  if (*i && (!spell || (*i)->GetId() != spell) && roll_chance_f(chance))
937  {
938  RemoveAurasDueToSpell((*i)->GetId());
939  if (!m_ccAuras.empty())
940  next = m_ccAuras.begin();
941  else
942  return;
943  }
944  }
945 }
946 
947 uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const* spellProto, bool durabilityLoss)
948 {
949  if ((!victim->IsAlive() || victim->IsInFlight()) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode()))
950  return 0;
951 
952  //You don't lose health from damage taken from another player while in a sanctuary
953  //You still see it in the combat log though
954  if (victim != this && GetTypeId() == TYPEID_PLAYER && victim->GetTypeId() == TYPEID_PLAYER)
955  {
956  const AreaTableEntry* area = GetAreaEntryByAreaID(victim->GetAreaId());
957  if (area && area->flags & AREA_FLAG_SANCTUARY) //sanctuary
958  return 0;
959  }
960 
961  //Script Event damage taken
962  if (victim->IsAIEnabled)
963  victim->ToCreature()->AI()->DamageTaken(this, damage);
964 
965  // Signal to pet that it dealt damage
966  if (IsPet() && this != victim && victim->IsAlive())
967  ToPet()->AI()->DamageDealt(victim, damage, damagetype);
968  else if (IsAIEnabled)
969  ToCreature()->AI()->DamageDealt(victim, damage, damagetype);
970 
971  if (victim->GetTypeId() == TYPEID_PLAYER)
972  {
973  // Signal to pets that their owner was attacked - except when DOT.
974  if (this != victim && damagetype != DOT)
975  {
976  Pet* pet = victim->ToPlayer()->GetPet();
977 
978  if (pet && pet->IsAlive())
979  pet->AI()->OwnerAttackedBy(this);
980  }
981 
982  if (victim->ToPlayer()->GetCommandStatus(CHEAT_GOD))
983  return 0;
984  }
985 
986  // Signal the pet it was attacked so the AI can respond if needed
987  if (victim->GetTypeId() == TYPEID_UNIT && this != victim && victim->IsPet() && victim->IsAlive())
988  victim->ToPet()->AI()->AttackedBy(this);
989 
990  if (victim->GetTypeId() == TYPEID_UNIT && (victim->ToCreature())->IsAIEnabled)
991  {
992  // Set tagging
993  if (!victim->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_OTHER_TAGGER) && !victim->IsPet())
994  {
995  //Set Loot
996  switch (GetTypeId())
997  {
998  case TYPEID_PLAYER:
999  {
1000  victim->ToCreature()->SetLootRecipient(this);
1001  //Set tagged
1003  break;
1004  }
1005  case TYPEID_UNIT:
1006  {
1007  if (IsPet())
1008  {
1009  victim->ToCreature()->SetLootRecipient(this->GetOwner());
1011  }
1012  break;
1013  }
1014  }
1015  }
1016  }
1017 
1018  if (damage || (cleanDamage && cleanDamage->damage))
1019  {
1020  if (spellProto)
1021  {
1024  }
1025  else
1027 
1028  victim->RemoveSpellbyDamageTaken(damage, spellProto ? spellProto->Id : 0);
1029  // Rage from physical damage received
1030  if (!damage)
1031  {
1032  if ((damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL) && victim->GetTypeId() == TYPEID_PLAYER && (victim->getPowerType() == POWER_RAGE))
1033  victim->ToPlayer()->RewardRage(cleanDamage->damage, 0, false);
1034  return 0;
1035  }
1036  }
1037 
1038  DEBUG_LOG("DealDamageStart");
1039 
1040  uint32 health = victim->GetHealth();
1041  sLog.outDetail("deal dmg:%d to health:%d ", damage, health);
1042 
1043  // duel ends when player has 1 or less hp
1044  bool duel_hasEnded = false;
1045  if (victim->GetTypeId() == TYPEID_PLAYER && victim->ToPlayer()->duel && damage >= (health - 1))
1046  {
1047  // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
1048  if (victim->ToPlayer()->duel->opponent == this || victim->ToPlayer()->duel->opponent->GetGUID() == GetOwnerGUID())
1049  damage = health - 1;
1050 
1051  duel_hasEnded = true;
1052  }
1053 
1054  // Rage from Damage made (only from direct weapon damage)
1055  if (cleanDamage && damagetype == DIRECT_DAMAGE && this != victim && GetTypeId() == TYPEID_PLAYER && (getPowerType() == POWER_RAGE))
1056  {
1057  uint32 weaponSpeedHitFactor;
1058 
1059  switch (cleanDamage->attackType)
1060  {
1061  case BASE_ATTACK:
1062  {
1063  if (cleanDamage->hitOutCome == MELEE_HIT_CRIT)
1064  weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType) / 1000.0f * 7);
1065  else
1066  weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType) / 1000.0f * 3.5f);
1067 
1068  // If attack is evaded/parried/dodged DON'T add rage
1069  if (cleanDamage->hitOutCome != MELEE_HIT_EVADE && cleanDamage->hitOutCome != MELEE_HIT_PARRY && cleanDamage->hitOutCome != MELEE_HIT_DODGE)
1070  ToPlayer()->RewardRage(damage, weaponSpeedHitFactor, true);
1071 
1072  break;
1073  }
1074  case OFF_ATTACK:
1075  {
1076  if (cleanDamage->hitOutCome == MELEE_HIT_CRIT)
1077  weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType) / 1000.0f * 3.5f);
1078  else
1079  weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType) / 1000.0f * 1.75f);
1080 
1081  ToPlayer()->RewardRage(damage, weaponSpeedHitFactor, true);
1082 
1083  break;
1084  }
1085  case RANGED_ATTACK:
1086  break;
1087  }
1088  }
1089 
1090  if (victim->GetTypeId() == TYPEID_PLAYER && GetTypeId() == TYPEID_PLAYER)
1091  {
1092  if (victim->ToPlayer()->InBattleground())
1093  {
1094  Player* killer = ToPlayer();
1095  if (killer != victim->ToPlayer())
1096  if (Battleground* bg = killer->GetBattleground())
1097  bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damage);
1098  }
1099  }
1100 
1101  if (victim->GetTypeId() == TYPEID_UNIT && !victim->IsPet())
1102  {
1103  if (!victim->ToCreature()->hasLootRecipient())
1104  victim->ToCreature()->SetLootRecipient(this);
1105 
1107  victim->ToCreature()->SetPlayerDamaged(true);
1108  }
1109 
1110  if (health <= damage)
1111  {
1112  DEBUG_LOG("DealDamage: victim just died");
1113  Kill(victim, durabilityLoss);
1114 
1115  //Hook for OnPVPKill Event
1116  if (this->GetTypeId() == TYPEID_PLAYER)
1117  {
1118  if (victim->GetTypeId() == TYPEID_PLAYER)
1119  {
1120  Player *killer = this->ToPlayer();
1121  Player *killed = victim->ToPlayer();
1122  sScriptMgr.OnPVPKill(killer, killed);
1123  }
1124  else if (victim->GetTypeId() == TYPEID_UNIT)
1125  {
1126  Player *killer = this->ToPlayer();
1127  Creature *killed = victim->ToCreature();
1128  sScriptMgr.OnCreatureKill(killer, killed);
1129  }
1130  }
1131  else if (this->GetTypeId() == TYPEID_UNIT)
1132  {
1133  if (victim->GetTypeId() == TYPEID_PLAYER)
1134  {
1135  Creature *killer = this->ToCreature();
1136  Player *killed = victim->ToPlayer();
1137  sScriptMgr.OnPlayerKilledByCreature(killer, killed);
1138  }
1139  }
1140  }
1141  else // if (health <= damage)
1142  {
1143  DEBUG_LOG("DealDamageAlive");
1144 
1145  victim->ModifyHealth(-(int32)damage);
1146 
1147  if (damagetype != DOT)
1148  {
1149  if (!GetVictim())
1150  /*{
1151  // if have target and damage victim just call AI reaction
1152  if (victim != GetVictim() && victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsAIEnabled)
1153  victim->ToCreature()->AI()->AttackedBy(this);
1154  }
1155  else*/
1156  {
1157  // if not have main target then attack state with target (including AI call)
1158  //start melee attacks only after melee hit
1159  Attack(victim, (damagetype == DIRECT_DAMAGE));
1160  }
1161  }
1162 
1163  if (damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE)
1164  {
1165  victim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE, spellProto ? spellProto->Id : 0);
1166  if (victim->GetTypeId() == TYPEID_UNIT && !victim->IsPet())
1167  victim->SetLastDamagedTime(time(NULL));
1168  }
1169 
1170  if (victim->GetTypeId() != TYPEID_PLAYER)
1171  victim->AddThreat(this, (float)damage, damageSchoolMask, spellProto);
1172  else // victim is a player
1173  {
1174  // Rage from damage received
1175  if (this != victim && victim->getPowerType() == POWER_RAGE)
1176  {
1177  uint32 rage_damage = damage + (cleanDamage ? cleanDamage->damage : 0);
1178  victim->ToPlayer()->RewardRage(rage_damage, 0, false);
1179  }
1180 
1181  // random durability for items (HIT TAKEN)
1183  {
1185  victim->ToPlayer()->DurabilityPointLossForEquipSlot(slot);
1186  }
1187  }
1188 
1189  if (GetTypeId() == TYPEID_PLAYER)
1190  {
1191  // random durability for items (HIT DONE)
1193  {
1196  }
1197  }
1198 
1199  if (damagetype != NODAMAGE && damage)
1200  {
1201  if (victim != this && victim->GetTypeId() == TYPEID_PLAYER) // does not support creature push_back
1202  {
1203  if (damagetype != DOT)
1204  {
1205  if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
1206  {
1207  if (spell->getState() == SPELL_STATE_PREPARING)
1208  {
1209  uint32 interruptFlags = spell->m_spellInfo->InterruptFlags;
1210  if (interruptFlags & SPELL_INTERRUPT_FLAG_DAMAGE)
1211  victim->InterruptNonMeleeSpells(false);
1212  else if (interruptFlags & SPELL_INTERRUPT_FLAG_PUSH_BACK)
1213  spell->Delayed();
1214  }
1215  }
1216  }
1217 
1218  if (Spell* spell = victim->m_currentSpells[CURRENT_CHANNELED_SPELL])
1219  {
1220  if (spell->getState() == SPELL_STATE_CASTING)
1221  {
1222  uint32 channelInterruptFlags = spell->m_spellInfo->ChannelInterruptFlags;
1223  if (((channelInterruptFlags & CHANNEL_FLAG_DELAY) != 0) && (damagetype != DOT))
1224  spell->DelayedChannel();
1225  }
1226  }
1227  }
1228  }
1229 
1230  // last damage from duel opponent
1231  if (duel_hasEnded)
1232  {
1233  ASSERT(victim->GetTypeId() == TYPEID_PLAYER);
1234  Player* he = victim->ToPlayer();
1235 
1236  ASSERT(he->duel);
1237 
1238  he->SetHealth(1);
1239 
1240  he->duel->opponent->CombatStopWithPets(true);
1241  he->CombatStopWithPets(true);
1242 
1243  he->CastSpell(he, 7267, true); // beg
1244  he->DuelComplete(DUEL_WON);
1245  }
1246  }
1247 
1248  DEBUG_LOG("DealDamageEnd returned %d damage", damage);
1249 
1250  return damage;
1251 }
1252 
1253 void Unit::CastStop(uint32 except_spellid)
1254 {
1256  if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id != except_spellid)
1257  InterruptSpell(CurrentSpellTypes(i), false, false);
1258 }
1259 
1260 void Unit::CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item* castItem, Aura* triggeredByAura, uint64 originalCaster)
1261 {
1262  SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId);
1263 
1264  if (!spellInfo)
1265  {
1266  sLog.outError("CastSpell: unknown spell id %i by caster: %s %u)", spellId, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
1267  return;
1268  }
1269 
1270  CastSpell(Victim, spellInfo, triggered, castItem, triggeredByAura, originalCaster);
1271 }
1272 
1273 void Unit::CastSpell(Unit* Victim, SpellEntry const* spellInfo, bool triggered, Item* castItem, Aura* triggeredByAura, uint64 originalCaster)
1274 {
1275  if (!spellInfo)
1276  {
1277  sLog.outError("CastSpell: unknown spell by caster: %s %u)", (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
1278  return;
1279  }
1280 
1281  SpellCastTargets targets;
1282  uint32 targetMask = spellInfo->Targets;
1283  //if (targetMask & (TARGET_FLAG_UNIT|TARGET_FLAG_UNK2))
1284  for (int i = 0; i < MAX_SPELL_EFFECTS; ++i)
1285  {
1286  if (sSpellMgr.SpellTargetType[spellInfo->EffectImplicitTargetA[i]] == TARGET_TYPE_UNIT_TARGET)
1287  {
1288  /*SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex);
1289  if (srange && GetSpellMaxRange(srange) == 0.0f)
1290  {
1291  Victim = this;
1292  break;
1293  }
1294  else */if (!Victim)
1295  {
1296  sLog.outError("CastSpell: spell id %i by caster: %s %u) does not have unit target", spellInfo->Id, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
1297  return;
1298  }
1299  else
1300  break;
1301  }
1302  }
1303  targets.setUnitTarget(Victim);
1304 
1306  {
1307  if (!Victim)
1308  {
1309  sLog.outError("CastSpell: spell id %i by caster: %s %u) does not have destination", spellInfo->Id, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
1310  return;
1311  }
1312  targets.setDst(Victim);
1313  }
1314 
1315  #ifdef OREGON_DEBUG
1316  if (castItem)
1317  DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
1318  #endif
1319 
1320  if (!originalCaster && triggeredByAura)
1321  originalCaster = triggeredByAura->GetCasterGUID();
1322 
1323  Spell* spell = new Spell(this, spellInfo, triggered, originalCaster);
1324 
1325  // When casting a combat spell the unit has to be flagged as initiating combat
1326  // Check for self-cast case here for this may have been called by a command
1327  if (Victim && spell->GetCaster() != Victim && !IsNonCombatSpell(spellInfo))
1328  spell->GetCaster()->SetInitiatingCombat(true);
1329 
1330  spell->m_CastItem = castItem;
1331  spell->prepare(&targets, triggeredByAura);
1332 }
1333 
1334 void Unit::CastCustomSpell(Unit* target, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item* castItem, Aura* triggeredByAura, uint64 originalCaster)
1335 {
1336  CustomSpellValues values;
1337  if (bp0)
1338  values.AddSpellMod(SPELLVALUE_BASE_POINT0, *bp0);
1339  if (bp1)
1340  values.AddSpellMod(SPELLVALUE_BASE_POINT1, *bp1);
1341  if (bp2)
1342  values.AddSpellMod(SPELLVALUE_BASE_POINT2, *bp2);
1343  CastCustomSpell(spellId, values, target, triggered, castItem, triggeredByAura, originalCaster);
1344 }
1345 
1346 void Unit::CastCustomSpell(uint32 spellId, SpellValueMod mod, uint32 value, Unit* target, bool triggered, Item* castItem, Aura* triggeredByAura, uint64 originalCaster)
1347 {
1348  CustomSpellValues values;
1349  values.AddSpellMod(mod, value);
1350  CastCustomSpell(spellId, values, target, triggered, castItem, triggeredByAura, originalCaster);
1351 }
1352 
1353 void Unit::CastCustomSpell(uint32 spellId, CustomSpellValues const& value, Unit* Victim, bool triggered, Item* castItem, Aura* triggeredByAura, uint64 originalCaster)
1354 {
1355  SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId);
1356  if (!spellInfo)
1357  {
1358  sLog.outError("CastSpell: unknown spell id %i by caster: %s %u)", spellId, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
1359  return;
1360  }
1361 
1362  SpellCastTargets targets;
1363  uint32 targetMask = spellInfo->Targets;
1364 
1365  //check unit target
1366  for (int i = 0; i < MAX_SPELL_EFFECTS; ++i)
1367  {
1368  if (sSpellMgr.SpellTargetType[spellInfo->EffectImplicitTargetA[i]] == TARGET_TYPE_UNIT_TARGET)
1369  {
1370  if (!Victim)
1371  {
1372  sLog.outError("CastSpell: spell id %i by caster: %s %u) does not have unit target", spellInfo->Id, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
1373  return;
1374  }
1375  else
1376  break;
1377  }
1378  }
1379  targets.setUnitTarget(Victim);
1380 
1381  //check destination
1383  {
1384  if (!Victim)
1385  {
1386  sLog.outError("CastSpell: spell id %i by caster: %s %u) does not have destination", spellInfo->Id, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
1387  return;
1388  }
1389  targets.setDst(Victim);
1390  }
1391 
1392  if (!originalCaster && triggeredByAura)
1393  originalCaster = triggeredByAura->GetCasterGUID();
1394 
1395  Spell* spell = new Spell(this, spellInfo, triggered, originalCaster);
1396 
1397  if (castItem)
1398  {
1399  DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
1400  spell->m_CastItem = castItem;
1401  }
1402 
1403  for (CustomSpellValues::const_iterator itr = value.begin(); itr != value.end(); ++itr)
1404  spell->SetSpellValue(itr->first, itr->second);
1405 
1406  spell->prepare(&targets, triggeredByAura);
1407 }
1408 
1409 // used for scripting
1410 void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item* castItem, Aura* triggeredByAura, uint64 originalCaster)
1411 {
1412  SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId);
1413  if (!spellInfo)
1414  {
1415  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()));
1416  return;
1417  }
1418 
1419  #ifdef OREGON_DEBUG
1420  if (castItem)
1421  DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
1422  #endif
1423 
1424  if (!originalCaster && triggeredByAura)
1425  originalCaster = triggeredByAura->GetCasterGUID();
1426 
1427  Spell* spell = new Spell(this, spellInfo, triggered, originalCaster);
1428 
1429  SpellCastTargets targets;
1430  targets.setDst(x, y, z, GetOrientation());
1431  spell->m_CastItem = castItem;
1432  spell->prepare(&targets, triggeredByAura);
1433 }
1434 
1435 // used for scripting
1436 void Unit::CastSpell(GameObject* go, uint32 spellId, bool triggered, Item* castItem, Aura* triggeredByAura, uint64 originalCaster)
1437 {
1438  if (!go)
1439  return;
1440 
1441  SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId);
1442 
1443  if (!spellInfo)
1444  {
1445  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()));
1446  return;
1447  }
1448 
1449  if (!(spellInfo->Targets & (TARGET_FLAG_OBJECT | TARGET_FLAG_OBJECT_UNK)))
1450  {
1451  sLog.outError("CastSpell: spell id %i by caster: %s %u) is not gameobject spell", spellId, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
1452  return;
1453  }
1454 
1455  #ifdef OREGON_DEBUG
1456  if (castItem)
1457  DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
1458  #endif
1459 
1460  if (!originalCaster && triggeredByAura)
1461  originalCaster = triggeredByAura->GetCasterGUID();
1462 
1463  Spell* spell = new Spell(this, spellInfo, triggered, originalCaster);
1464 
1465  SpellCastTargets targets;
1466  targets.setGOTarget(go);
1467  spell->m_CastItem = castItem;
1468  spell->prepare(&targets, triggeredByAura);
1469 }
1470 
1471 // Obsolete func need remove, here only for comotability vs another patches
1472 uint32 Unit::SpellNonMeleeDamageLog(Unit* victim, uint32 spellID, uint32 damage, bool /*isTriggeredSpell*/, bool /*useSpellDamage*/)
1473 {
1474  SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellID);
1475  SpellNonMeleeDamage damageInfo(this, victim, spellInfo->Id, spellInfo->SchoolMask);
1476  damage = SpellDamageBonus(victim, spellInfo, damage, SPELL_DIRECT_DAMAGE);
1477  CalculateSpellDamageTaken(&damageInfo, damage, spellInfo);
1478  SendSpellNonMeleeDamageLog(&damageInfo);
1479  DealSpellDamage(&damageInfo, true);
1480  return damageInfo.damage;
1481 }
1482 
1483 void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellEntry const* spellInfo, WeaponAttackType attackType, bool crit)
1484 {
1485  if (damage < 0)
1486  return;
1487 
1488  Unit* victim = damageInfo->target;
1489  if (!victim || !victim->IsAlive())
1490  return;
1491 
1492  SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask);
1493  uint32 crTypeMask = victim->GetCreatureTypeMask();
1494 
1495  bool blocked = false;
1496  // Per-school calc
1497  switch (spellInfo->DmgClass)
1498  {
1499  // Melee and Ranged Spells
1502  {
1503  // Physical Damage
1504  if (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL)
1505  {
1506  // Get blocked status
1507  blocked = isSpellBlocked(victim, spellInfo, attackType);
1508  }
1509 
1510  if (crit)
1511  {
1512  damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
1513 
1514  // Calculate crit bonus
1515  uint32 crit_bonus = damage;
1516  // Apply crit_damage bonus for melee spells
1517  if (Player* modOwner = GetSpellModOwner())
1518  modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
1519  damage += crit_bonus;
1520 
1521  // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
1522  int32 critPctDamageMod = 0;
1523  if (attackType == RANGED_ATTACK)
1525  else
1526  {
1529  }
1530 
1531  // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
1532  critPctDamageMod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask);
1533 
1534  if (critPctDamageMod != 0)
1535  AddPct(damage, critPctDamageMod);
1536 
1537  // Resilience - reduce crit damage
1538  if (victim->GetTypeId() == TYPEID_PLAYER)
1539  damage -= victim->ToPlayer()->GetMeleeCritDamageReduction(damage);
1540  }
1541 
1542  // Spell weapon based damage CAN BE crit & blocked at same time
1543  if (blocked)
1544  {
1545  damageInfo->blocked = uint32(victim->GetShieldBlockValue());
1546  if (damage < int32(damageInfo->blocked))
1547  damageInfo->blocked = uint32(damage);
1548  damage -= damageInfo->blocked;
1549  }
1550  }
1551  break;
1552  // Magical Attacks
1555  {
1556  // If crit add critical bonus
1557  if (crit)
1558  {
1559  damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
1560  damage = SpellCriticalBonus(spellInfo, damage, victim);
1561 
1562  // Resilience - reduce crit damage
1563  if (victim->GetTypeId() == TYPEID_PLAYER)
1564  damage -= victim->ToPlayer()->GetSpellCritDamageReduction(damage);
1565  }
1566  }
1567  break;
1568  default:
1569  break;
1570  }
1571 
1572  // damage before absorb/resist calculation
1573  damageInfo->cleanDamage = damage;
1574  if (IsDamageReducedByArmor(damageSchoolMask, spellInfo))
1575  damage = CalcArmorReducedDamage(victim, damage);
1576 
1577  // Calculate absorb resist
1578  if (damage > 0)
1579  {
1580  CalcAbsorbResist(victim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist, spellInfo, IsBinarySpell(spellInfo));
1581  damage -= damageInfo->absorb + damageInfo->resist;
1582  }
1583  else
1584  damage = 0;
1585 
1586  damageInfo->damage = damage;
1587 }
1588 
1589 void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss)
1590 {
1591  if (damageInfo == 0)
1592  return;
1593 
1594  Unit* victim = damageInfo->target;
1595 
1596  if (!victim)
1597  return;
1598 
1599  if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode()))
1600  return;
1601 
1602  SpellEntry const* spellProto = sSpellStore.LookupEntry(damageInfo->SpellID);
1603  if (spellProto == NULL)
1604  {
1605  DEBUG_LOG("Unit::DealSpellDamage has invalid damageInfo->SpellID: %u", damageInfo->SpellID);
1606  return;
1607  }
1608 
1609  //You don't lose health from damage taken from another player while in a sanctuary
1610  //You still see it in the combat log though
1611  if (victim != this && GetTypeId() == TYPEID_PLAYER && victim->GetTypeId() == TYPEID_PLAYER)
1612  {
1613  const AreaTableEntry* area = GetAreaEntryByAreaID(victim->GetAreaId());
1614  if (area && area->flags & 0x800) //sanctuary
1615  return;
1616  }
1617 
1618  // update at damage Judgement aura duration that applied by attacker at victim
1619  if (damageInfo->damage && spellProto->Id == 35395)
1620  {
1621  AuraMap& vAuras = victim->GetAuras();
1622  for (AuraMap::iterator itr = vAuras.begin(); itr != vAuras.end(); ++itr)
1623  {
1624  SpellEntry const* spellInfo = (*itr).second->GetSpellProto();
1625  if (spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && spellInfo->AttributesEx3 & 0x40000)
1626  {
1627  (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration());
1628  (*itr).second->UpdateAuraDuration();
1629  }
1630  }
1631  }
1632  // Call default DealDamage
1633  CleanDamage cleanDamage(damageInfo->cleanDamage, BASE_ATTACK, MELEE_HIT_NORMAL);
1634  DealDamage(victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss);
1635 }
1636 
1638 void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType)
1639 {
1640  damageInfo->attacker = this;
1641  damageInfo->target = victim;
1643  damageInfo->attackType = attackType;
1644  damageInfo->damage = 0;
1645  damageInfo->cleanDamage = 0;
1646  damageInfo->absorb = 0;
1647  damageInfo->resist = 0;
1648  damageInfo->blocked_amount = 0;
1649 
1650  damageInfo->TargetState = 0;
1651  damageInfo->HitInfo = 0;
1652  damageInfo->procAttacker = PROC_FLAG_NONE;
1653  damageInfo->procVictim = PROC_FLAG_NONE;
1654  damageInfo->procEx = PROC_EX_NONE;
1655  damageInfo->hitOutCome = MELEE_HIT_EVADE;
1656 
1657  if (!victim)
1658  return;
1659 
1660  if (!IsAlive() || !victim->IsAlive())
1661  return;
1662 
1663  // Select HitInfo/procAttacker/procVictim flag based on attack type
1664  switch (attackType)
1665  {
1666  case BASE_ATTACK:
1669  damageInfo->HitInfo = HITINFO_NORMALSWING2;
1670  break;
1671  case OFF_ATTACK:
1674  damageInfo->HitInfo = HITINFO_LEFTSWING;
1675  break;
1676  case RANGED_ATTACK:
1679  damageInfo->HitInfo = HITINFO_UNK3; // HitInfo flag not confirmed.
1680  break;
1681  default:
1682  break;
1683  }
1684 
1685  // Physical Immune check
1686  if (damageInfo->target->IsImmunedToDamage(SpellSchoolMask(damageInfo->damageSchoolMask), true))
1687  {
1688  damageInfo->HitInfo |= HITINFO_NORMALSWING;
1689  damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE;
1690 
1691  damageInfo->procEx |= PROC_EX_IMMUNE;
1692  damageInfo->damage = 0;
1693  damageInfo->cleanDamage = 0;
1694  return;
1695  }
1696 
1697  damage += CalculateDamage(damageInfo->attackType, false, true);
1698  // Add melee damage bonus
1699  MeleeDamageBonus(damageInfo->target, &damage, damageInfo->attackType);
1700 
1701  // Calculate armor reduction
1703  {
1704  damageInfo->damage = CalcArmorReducedDamage(damageInfo->target, damage);
1705  damageInfo->cleanDamage += damage - damageInfo->damage;
1706  }
1707  else
1708  damageInfo->damage = damage;
1709 
1710  damageInfo->hitOutCome = RollMeleeOutcomeAgainst(damageInfo->target, damageInfo->attackType);
1711 
1712  // Disable parry or dodge for ranged attack
1713  if (damageInfo->attackType == RANGED_ATTACK)
1714  {
1715  if (damageInfo->hitOutCome == MELEE_HIT_PARRY) damageInfo->hitOutCome = MELEE_HIT_NORMAL;
1716  if (damageInfo->hitOutCome == MELEE_HIT_DODGE) damageInfo->hitOutCome = MELEE_HIT_MISS;
1717  }
1718 
1719  switch (damageInfo->hitOutCome)
1720  {
1721  case MELEE_HIT_EVADE:
1722  damageInfo->HitInfo |= HITINFO_MISS | HITINFO_SWINGNOHITSOUND;
1723  damageInfo->TargetState = VICTIMSTATE_EVADES;
1724  damageInfo->procEx |= PROC_EX_EVADE;
1725  damageInfo->damage = 0;
1726  damageInfo->cleanDamage = 0;
1727  return;
1728  case MELEE_HIT_MISS:
1729  damageInfo->HitInfo |= HITINFO_MISS;
1730  damageInfo->TargetState = VICTIMSTATE_NORMAL;
1731  damageInfo->procEx |= PROC_EX_MISS;
1732  damageInfo->damage = 0;
1733  damageInfo->cleanDamage = 0;
1734  break;
1735  case MELEE_HIT_NORMAL:
1736  damageInfo->TargetState = VICTIMSTATE_NORMAL;
1737  damageInfo->procEx |= PROC_EX_NORMAL_HIT;
1738  break;
1739  case MELEE_HIT_CRIT:
1740  {
1741  damageInfo->HitInfo |= HITINFO_CRITICALHIT;
1742  damageInfo->TargetState = VICTIMSTATE_NORMAL;
1743 
1744  damageInfo->procEx |= PROC_EX_CRITICAL_HIT;
1745  // Crit bonus calc
1746  damageInfo->damage += damageInfo->damage;
1747  int32 mod = 0;
1748  // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
1749  if (damageInfo->attackType == RANGED_ATTACK)
1751  else
1752  {
1755  }
1756 
1757  uint32 crTypeMask = damageInfo->target->GetCreatureTypeMask();
1758 
1759  // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
1761  if (mod != 0)
1762  AddPct(damageInfo->damage, mod);
1763 
1764  // Resilience - reduce crit damage
1765  if (victim->GetTypeId() == TYPEID_PLAYER)
1766  {
1767  uint32 resilienceReduction = victim->ToPlayer()->GetMeleeCritDamageReduction(damageInfo->damage);
1768  damageInfo->damage -= resilienceReduction;
1769  damageInfo->cleanDamage += resilienceReduction;
1770  }
1771  break;
1772  }
1773  case MELEE_HIT_PARRY:
1774  damageInfo->TargetState = VICTIMSTATE_PARRY;
1775  damageInfo->procEx |= PROC_EX_PARRY;
1776  damageInfo->cleanDamage += damageInfo->damage;
1777  damageInfo->damage = 0;
1778  break;
1779 
1780  case MELEE_HIT_DODGE:
1781  damageInfo->TargetState = VICTIMSTATE_DODGE;
1782  damageInfo->procEx |= PROC_EX_DODGE;
1783  damageInfo->cleanDamage += damageInfo->damage;
1784  damageInfo->damage = 0;
1785  break;
1786  case MELEE_HIT_BLOCK:
1787  damageInfo->TargetState = VICTIMSTATE_NORMAL;
1788  damageInfo->procEx |= PROC_EX_BLOCK;
1789  damageInfo->blocked_amount = damageInfo->target->GetShieldBlockValue();
1790  if (damageInfo->blocked_amount >= damageInfo->damage)
1791  {
1792  damageInfo->TargetState = VICTIMSTATE_BLOCKS;
1793  damageInfo->blocked_amount = damageInfo->damage;
1794  }
1795  else
1796  damageInfo->procEx |= PROC_EX_NORMAL_HIT;
1797  damageInfo->damage -= damageInfo->blocked_amount;
1798  damageInfo->cleanDamage += damageInfo->blocked_amount;
1799  break;
1800  case MELEE_HIT_GLANCING:
1801  {
1802  damageInfo->HitInfo |= HITINFO_GLANCING;
1803  damageInfo->TargetState = VICTIMSTATE_NORMAL;
1804  damageInfo->procEx |= PROC_EX_NORMAL_HIT;
1805  int32 leveldif = int32(victim->getLevel()) - int32(getLevel());
1806  if (leveldif > 3)
1807  leveldif = 3;
1808  float reducePercent = 1 - leveldif * 0.1f;
1809  damageInfo->cleanDamage += damageInfo->damage - uint32(reducePercent * damageInfo->damage);
1810  damageInfo->damage = uint32(reducePercent * damageInfo->damage);
1811  break;
1812  }
1813  case MELEE_HIT_CRUSHING:
1814  damageInfo->HitInfo |= HITINFO_CRUSHING;
1815  damageInfo->TargetState = VICTIMSTATE_NORMAL;
1816  damageInfo->procEx |= PROC_EX_NORMAL_HIT;
1817  // 150% normal damage
1818  damageInfo->damage += (damageInfo->damage / 2);
1819  break;
1820  default:
1821  break;
1822  }
1823 
1824  // Calculate absorb resist
1825  if (int32(damageInfo->damage) > 0)
1826  {
1827  damageInfo->procVictim |= PROC_FLAG_TAKEN_DAMAGE;
1828  // Calculate absorb & resists
1829  CalcAbsorbResist(damageInfo->target, SpellSchoolMask(damageInfo->damageSchoolMask), DIRECT_DAMAGE, damageInfo->damage, &damageInfo->absorb, &damageInfo->resist);
1830 
1831 
1832  if (damageInfo->absorb)
1833  {
1834  damageInfo->HitInfo |= HITINFO_ABSORB;
1835  damageInfo->procEx |= PROC_EX_ABSORB;
1836  }
1837 
1838  if (damageInfo->resist)
1839  damageInfo->HitInfo |= HITINFO_RESIST;
1840 
1841  damageInfo->damage -= damageInfo->absorb + damageInfo->resist;
1842  }
1843  else // Impossible get negative result but....
1844  damageInfo->damage = 0;
1845 }
1846 
1847 void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
1848 {
1849  Unit* victim = damageInfo->target;
1850 
1851  if (!victim)
1852  return;
1853 
1854  if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode()))
1855  return;
1856 
1857  //You don't lose health from damage taken from another player while in a sanctuary
1858  //You still see it in the combat log though
1859  if (victim != this && GetTypeId() == TYPEID_PLAYER && victim->GetTypeId() == TYPEID_PLAYER)
1860  {
1861  const AreaTableEntry* area = GetAreaEntryByAreaID(victim->GetAreaId());
1862  if (area && area->flags & 0x800) //sanctuary
1863  return;
1864  }
1865 
1866  if (damageInfo->TargetState == VICTIMSTATE_PARRY)
1867  {
1868  // Get attack timers
1869  float offtime = float(victim->getAttackTimer(OFF_ATTACK));
1870  float basetime = float(victim->getAttackTimer(BASE_ATTACK));
1871  // Reduce attack time
1872  if (victim->haveOffhandWeapon() && offtime < basetime)
1873  {
1874  float percent20 = victim->GetAttackTime(OFF_ATTACK) * 0.20f;
1875  float percent60 = 3.0f * percent20;
1876  if (offtime > percent20 && offtime <= percent60)
1877  victim->setAttackTimer(OFF_ATTACK, uint32(percent20));
1878  else if (offtime > percent60)
1879  {
1880  offtime -= 2.0f * percent20;
1881  victim->setAttackTimer(OFF_ATTACK, uint32(offtime));
1882  }
1883  }
1884  else
1885  {
1886  float percent20 = victim->GetAttackTime(BASE_ATTACK) * 0.20;
1887  float percent60 = 3.0f * percent20;
1888  if (basetime > percent20 && basetime <= percent60)
1889  victim->setAttackTimer(BASE_ATTACK, uint32(percent20));
1890  else if (basetime > percent60)
1891  {
1892  basetime -= 2.0f * percent20;
1893  victim->setAttackTimer(BASE_ATTACK, uint32(basetime));
1894  }
1895  }
1896  }
1897 
1898  // Call default DealDamage
1899  CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->attackType, damageInfo->hitOutCome);
1900  DealDamage(victim, damageInfo->damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->damageSchoolMask), NULL, durabilityLoss);
1901 
1902  // If this is a creature and it attacks from behind it has a probability to daze it's victim
1903  if ((damageInfo->hitOutCome == MELEE_HIT_CRIT || damageInfo->hitOutCome == MELEE_HIT_CRUSHING || damageInfo->hitOutCome == MELEE_HIT_NORMAL || damageInfo->hitOutCome == MELEE_HIT_GLANCING) &&
1904  GetTypeId() != TYPEID_PLAYER && !ToCreature()->IsControlledByPlayer() && !victim->HasInArc(float(M_PI), this) && damageInfo->damage
1905  && (victim->GetTypeId() == TYPEID_PLAYER || !victim->ToCreature()->isWorldBoss()))
1906  {
1907  // -probability is between 0% and 40%
1908  // 20% base chance
1909  float Probability = 20.0f;
1910 
1911  //there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1912  if (victim->getLevel() < 30)
1913  Probability = 0.65f * victim->getLevel() + 0.5f;
1914 
1915  uint32 VictimDefense = victim->GetDefenseSkillValue();
1916  uint32 AttackerMeleeSkill = GetUnitMeleeSkill();
1917 
1918  Probability *= AttackerMeleeSkill / (float)VictimDefense*0.16f;
1919 
1920  if (Probability < 0)
1921  Probability = 0;
1922 
1923  if (Probability > 40.0f)
1924  Probability = 40.0f;
1925 
1926  if (roll_chance_f(Probability))
1927  CastSpell(victim, 1604, true);
1928  }
1929 
1930  // update at damage Judgement aura duration that applied by attacker at victim
1931  if (damageInfo->damage)
1932  {
1933  AuraMap& vAuras = victim->GetAuras();
1934  for (AuraMap::iterator itr = vAuras.begin(); itr != vAuras.end(); ++itr)
1935  {
1936  SpellEntry const* spellInfo = (*itr).second->GetSpellProto();
1937  if (spellInfo->AttributesEx3 & 0x40000 && spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && ((*itr).second->GetCasterGUID() == GetGUID()))
1938  {
1939  (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration());
1940  (*itr).second->UpdateAuraDuration();
1941  }
1942  }
1943  }
1944 
1945  if (GetTypeId() == TYPEID_PLAYER)
1946  ToPlayer()->CastItemCombatSpell(victim, damageInfo->attackType, damageInfo->procVictim, damageInfo->procEx);
1947 
1948  // Do effect if any damage done to target
1949  if (damageInfo->procVictim & PROC_FLAG_TAKEN_DAMAGE)
1950  {
1951  // victim's damage shield
1952  std::set<Aura*> alreadyDone;
1953  uint32 removedAuras = victim->m_removedAurasCount;
1954  AuraList const& vDamageShields = victim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD);
1955  for (AuraList::const_iterator i = vDamageShields.begin(), next = vDamageShields.begin(); i != vDamageShields.end(); i = next)
1956  {
1957  ++next;
1958  if (alreadyDone.find(*i) == alreadyDone.end())
1959  {
1960  SpellEntry const* spellProto = sSpellStore.LookupEntry((*i)->GetId());
1961  if (!spellProto)
1962  continue;
1963 
1964  // Damage shield can be resisted...
1965  if (SpellMissInfo missInfo = victim->SpellHitResult(this, spellProto, false))
1966  {
1967  victim->SendSpellMiss(this, spellProto->Id, missInfo);
1968  continue;
1969  }
1970 
1971  // ...or immuned
1972  if (IsImmunedToDamage(spellProto))
1973  {
1974  victim->SendSpellDamageImmune(this, spellProto->Id);
1975  continue;
1976  }
1977 
1978  alreadyDone.insert(*i);
1979  uint32 damage = (*i)->GetModifier()->m_amount;
1980 
1981  WorldPacket data(SMSG_SPELLDAMAGESHIELD, (8 + 8 + 4 + 4 + 4));
1982  data << uint64(victim->GetGUID());
1983  data << uint64(GetGUID());
1984  data << uint32(spellProto->Id);
1985  data << uint32(damage); // Damage
1986  data << uint32(spellProto->SchoolMask);
1987  victim->SendMessageToSet(&data, true);
1988 
1989  victim->DealDamage(this, damage, 0, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(spellProto), spellProto, true);
1990 
1991  if (victim->m_removedAurasCount > removedAuras)
1992  {
1993  removedAuras = victim->m_removedAurasCount;
1994  next = vDamageShields.begin();
1995  }
1996  }
1997  }
1998  }
1999 }
2000 
2002 {
2003  WorldPacket data(SMSG_EMOTE, 4 + 8);
2004  data << uint32(anim_id);
2005  data << uint64(GetGUID());
2006  SendMessageToSet(&data, true);
2007 }
2008 
2009 bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellEntry const* spellInfo, uint8 effIndex)
2010 {
2011  // only physical spells damage gets reduced by armor
2012  if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
2013  return false;
2014  if (spellInfo)
2015  {
2016  // there are spells with no specific attribute but they have "ignores armor" in tooltip
2017 
2018  if (sSpellMgr.GetSpellCustomAttr(spellInfo->Id) & SPELL_ATTR_CU_IGNORE_ARMOR)
2019  return false;
2020 
2021  // bleeding effects are not reduced by armor
2022  // @todo Get this to work with Rake.
2023  if (effIndex != MAX_SPELL_EFFECTS)
2024  {
2025  if (spellInfo->EffectApplyAuraName[effIndex] == SPELL_AURA_PERIODIC_DAMAGE ||
2026  spellInfo->Effect[effIndex] == SPELL_EFFECT_SCHOOL_DAMAGE)
2027  if (spellInfo->GetEffectMechanicMask(effIndex) & (1<<MECHANIC_BLEED))
2028  return false;
2029  }
2030  }
2031  return true;
2032 }
2033 
2035 {
2036  if (!(schoolMask & SPELL_SCHOOL_MASK_MAGIC))
2037  return 0;
2038 
2039  uint32 resistance = 0;
2040  // Select a resistance value matching spell school mask, prefer mininal for multischool spells
2041  uint32 schools = uint32(schoolMask);
2042  for (uint32 school = 0; schools; ++school)
2043  {
2044  if ((schools & 1) && school != SPELL_SCHOOL_NORMAL && school != SPELL_SCHOOL_HOLY)
2045  {
2046  // Base victim resistance
2047  uint32 amount = GetResistance(SpellSchools(school));
2048  // Add SPELL_AURA_MOD_TARGET_RESISTANCE aura value at caster
2049  // Negative value is spell penetration, but effective resistance can't be negative since betas
2050  if (const int32 casterMod = attacker->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, (1 << school)))
2051  amount = uint32(std::max((int32(amount) + casterMod), 0));
2052  if (!amount)
2053  {
2054  resistance = 0; // No resistance for this school: use it!
2055  break;
2056  }
2057  else if (!resistance || amount < resistance)
2058  resistance = amount; // First school encountered or more vulnerable: memorize and continue
2059  }
2060  schools >>= 1;
2061  }
2062 
2063  return resistance;
2064 }
2065 
2066 float Unit::CalculateMagicResistanceMitigation(Unit* attacker, uint32 resistance, bool binary) const
2067 {
2068  // Total resistance mitigation: final ratio of resistance effectiveness
2069  float ratio = float(float(resistance) / (attacker->getLevelForTarget(this) * 5)) * 0.75f;
2070  // Add bonus resistance mitigation to victim based on level difference for non-binary spells
2071  if (!binary)
2072  ratio += std::max(int32(getLevelForTarget(attacker) - attacker->getLevelForTarget(this)), 0) * 0.02f;
2073  // Magic resistance mitigation is capped at 0.75
2074  return std::min(ratio, 0.75f);
2075 }
2076 
2078 {
2079  uint32 newdamage = 0;
2080  float armor = victim->GetArmor();
2081 
2082  // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
2084 
2085  if (armor < 0.0f) armor = 0.0f;
2086 
2087  float tmpvalue = 0.0f;
2088  if (getLevel() <= 59) //Level 1-59
2089  tmpvalue = armor / (armor + 400.0f + 85.0f * getLevel());
2090  else if (getLevel() < 70) //Level 60-69
2091  tmpvalue = armor / (armor - 22167.5f + 467.5f * getLevel());
2092  else //Level 70+
2093  tmpvalue = armor / (armor + 10557.5f);
2094 
2095  if (tmpvalue < 0.0f)
2096  tmpvalue = 0.0f;
2097  if (tmpvalue > 0.75f)
2098  tmpvalue = 0.75f;
2099 
2100  newdamage = uint32(damage - (damage * tmpvalue));
2101 
2102  return (newdamage > 1) ? newdamage : 1;
2103 }
2104 
2105 void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32* absorb, uint32* resist, SpellEntry const* spellInfo /*= NULL*/, bool binary)
2106 {
2107  if (!victim || !victim->IsAlive() || !damage)
2108  return;
2109 
2110  // Magic damage, check for resists
2111  if (!spellInfo || (spellInfo->AttributesEx4 & SPELL_ATTR4_IGNORE_RESISTANCES) == 0 && (schoolMask & SPELL_SCHOOL_MASK_MAGIC) && (!binary || damagetype == DOT))
2112  {
2113  const float mitigation = victim->CalculateMagicResistanceMitigation(victim, victim->CalculateEffectiveMagicResistance(victim, schoolMask), false);
2114  const SpellPartialResistChanceEntry &chances = SPELL_PARTIAL_RESIST_DISTRIBUTION.at(uint32(mitigation * 10000));
2115  // We choose which portion of damage is resisted below, none by default
2116  uint8 portion = SPELL_PARTIAL_RESIST_NONE;
2117  // If we got to this point, we already rolled for full resist on hit
2118  // We do a roll between remaining chances
2119  const uint8 outcomes = (NUM_SPELL_PARTIAL_RESISTS - 1);
2120  const uint32 roll = urand(1, (10000 - chances.at(SPELL_PARTIAL_RESIST_PCT_100)));
2121  uint32 sum = 0;
2122  for (uint8 outcome = SPELL_PARTIAL_RESIST_NONE; outcome < outcomes; ++outcome)
2123  {
2124  if (const uint32 chance = chances.at(outcome))
2125  {
2126  sum += chance;
2127  if (roll <= sum)
2128  {
2129  portion = outcome;
2130  break;
2131  }
2132  }
2133  }
2134  const uint32 amount = uint32(damage * (portion * (1.0f / float(outcomes))));
2135  // We already rolled for full resist on hit, so we need to deal at least *some* amount of damage...
2136  *resist = (amount >= damage) ? (damage - 1) : amount;
2137  }
2138  else
2139  *resist = 0;
2140 
2141  int32 RemainingDamage = damage - *resist;
2142 
2143  // Paladin Blessed Life 4/7/10% chance to cause 50% dmg
2144  AuraList const& blessedLife = victim->GetAurasByType(SPELL_AURA_REUSED_BLESSED_LIFE);
2145  AuraList::const_iterator blessedAura = blessedLife.begin();
2146  if (blessedAura != blessedLife.end() && *blessedAura)
2147  {
2148  if (urand(0, 100) <= (*blessedAura)->GetSpellProto()->procChance)
2149  RemainingDamage /= 2;
2150  }
2151 
2152  // Need to remove expired auras after
2153  bool expiredExists = false;
2154 
2155  // absorb without mana cost
2156  int32 reflectDamage = 0;
2157  Aura* reflectAura = NULL;
2158  AuraList const& vSchoolAbsorb = victim->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB);
2159  for (AuraList::const_iterator i = vSchoolAbsorb.begin(); i != vSchoolAbsorb.end() && RemainingDamage > 0; ++i)
2160  {
2161  int32* p_absorbAmount = &(*i)->GetModifier()->m_amount;
2162 
2163  // should not happen....
2164  if (*p_absorbAmount <= 0)
2165  {
2166  expiredExists = true;
2167  continue;
2168  }
2169 
2170  if (((*i)->GetModifier()->m_miscvalue & schoolMask) == 0)
2171  continue;
2172 
2173  // Cheat Death
2174  if ((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_ROGUE && (*i)->GetSpellProto()->SpellIconID == 2109)
2175  {
2176  if (victim->ToPlayer()->HasSpellCooldown(31231))
2177  continue;
2178  if (int32(victim->GetHealth()) <= RemainingDamage)
2179  {
2180  int32 chance = *p_absorbAmount;
2181  if (roll_chance_i(chance))
2182  {
2183  victim->CastSpell(victim, 31231, true);
2184  victim->ToPlayer()->AddSpellCooldown(31231, 0, time(NULL) + 60);
2185 
2186  // with health > 10% lost health until health == 10%, in other case no losses
2187  uint32 health10 = victim->CountPctFromMaxHealth(10);
2188  RemainingDamage = victim->GetHealth() > health10 ? victim->GetHealth() - health10 : 0;
2189  }
2190  }
2191  continue;
2192  }
2193 
2194  int32 currentAbsorb;
2195 
2196  //Reflective Shield
2197  if ((victim != this) && (*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_PRIEST && (*i)->GetSpellProto()->SpellFamilyFlags == 0x1)
2198  {
2199  if (Unit* caster = (*i)->GetCaster())
2200  {
2201  AuraList const& vOverRideCS = caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
2202  for (AuraList::const_iterator k = vOverRideCS.begin(); k != vOverRideCS.end(); ++k)
2203  {
2204  switch ((*k)->GetModifier()->m_miscvalue)
2205  {
2206  case 5065: // Rank 1
2207  case 5064: // Rank 2
2208  case 5063: // Rank 3
2209  case 5062: // Rank 4
2210  case 5061: // Rank 5
2211  {
2212  if (RemainingDamage >= *p_absorbAmount)
2213  reflectDamage = *p_absorbAmount * (*k)->GetModifier()->m_amount / 100;
2214  else
2215  reflectDamage = (*k)->GetModifier()->m_amount * RemainingDamage / 100;
2216  reflectAura = *i;
2217 
2218  }
2219  break;
2220  default:
2221  break;
2222  }
2223 
2224  if (reflectDamage)
2225  break;
2226  }
2227  }
2228  }
2229 
2230  if (RemainingDamage >= *p_absorbAmount)
2231  {
2232  currentAbsorb = *p_absorbAmount;
2233  expiredExists = true;
2234  }
2235  else
2236  currentAbsorb = RemainingDamage;
2237 
2238  *p_absorbAmount -= currentAbsorb;
2239  RemainingDamage -= currentAbsorb;
2240  }
2241  // do not cast spells while looping auras; auras can get invalid otherwise
2242  if (reflectDamage)
2243  victim->CastCustomSpell(this, 33619, &reflectDamage, NULL, NULL, true, NULL, reflectAura);
2244 
2245  // Remove all expired absorb auras
2246  if (expiredExists)
2247  {
2248  for (AuraList::const_iterator i = vSchoolAbsorb.begin(); i != vSchoolAbsorb.end();)
2249  {
2250  Aura* aur = (*i);
2251  ++i;
2252  if (aur->GetModifier()->m_amount <= 0)
2253  {
2254  uint32 removedAuras = victim->m_removedAurasCount;
2255  victim->RemoveAurasDueToSpell(aur->GetId());
2256  if (removedAuras + 1 < victim->m_removedAurasCount)
2257  i = vSchoolAbsorb.begin();
2258  }
2259  }
2260  }
2261 
2262  // absorb by mana cost
2263  AuraList const& vManaShield = victim->GetAurasByType(SPELL_AURA_MANA_SHIELD);
2264  for (AuraList::const_iterator i = vManaShield.begin(), next; i != vManaShield.end() && RemainingDamage > 0; i = next)
2265  {
2266  next = i;
2267  ++next;
2268  int32* p_absorbAmount = &(*i)->GetModifier()->m_amount;
2269 
2270  // check damage school mask
2271  if (((*i)->GetModifier()->m_miscvalue & schoolMask) == 0)
2272  continue;
2273 
2274  int32 currentAbsorb;
2275  if (RemainingDamage >= *p_absorbAmount)
2276  currentAbsorb = *p_absorbAmount;
2277  else
2278  currentAbsorb = RemainingDamage;
2279 
2280  float manaMultiplier = (*i)->GetSpellProto()->EffectMultipleValue[(*i)->GetEffIndex()];
2281  if (Player* modOwner = GetSpellModOwner())
2282  modOwner->ApplySpellMod((*i)->GetId(), SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
2283 
2284  if (manaMultiplier)
2285  {
2286  int32 maxAbsorb = int32(victim->GetPower(POWER_MANA) / manaMultiplier);
2287  if (currentAbsorb > maxAbsorb)
2288  currentAbsorb = maxAbsorb;
2289  }
2290 
2291  *p_absorbAmount -= currentAbsorb;
2292  if (*p_absorbAmount <= 0)
2293  {
2294  victim->RemoveAurasDueToSpell((*i)->GetId());
2295  next = vManaShield.begin();
2296  }
2297 
2298  int32 manaReduction = int32(currentAbsorb * manaMultiplier);
2299  victim->ApplyPowerMod(POWER_MANA, manaReduction, false);
2300 
2301  RemainingDamage -= currentAbsorb;
2302  }
2303 
2304  // only split damage if not damaging yourself
2305  if (victim != this)
2306  {
2307  AuraList const& vSplitDamageFlat = victim->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_FLAT);
2308  for (AuraList::const_iterator i = vSplitDamageFlat.begin(), next; i != vSplitDamageFlat.end() && RemainingDamage >= 0; i = next)
2309  {
2310  next = i;
2311  ++next;
2312 
2313  // check damage school mask
2314  if (((*i)->GetModifier()->m_miscvalue & schoolMask) == 0)
2315  continue;
2316 
2317  // Damage can be splitted only if aura has an alive caster
2318  Unit* caster = (*i)->GetCaster();
2319  if (!caster || caster == victim || !caster->IsInWorld() || !caster->IsAlive() || caster->IsImmunedToDamage((SpellSchoolMask)(*i)->GetSpellProto()->SchoolMask))
2320  continue;
2321 
2322  int32 currentAbsorb;
2323  if (RemainingDamage >= (*i)->GetModifier()->m_amount)
2324  currentAbsorb = (*i)->GetModifier()->m_amount;
2325  else
2326  currentAbsorb = RemainingDamage;
2327 
2328  RemainingDamage -= currentAbsorb;
2329 
2330  SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, currentAbsorb, schoolMask, 0, 0, false, 0, false);
2331 
2332  CleanDamage cleanDamage = CleanDamage(currentAbsorb, BASE_ATTACK, MELEE_HIT_NORMAL);
2333  DealDamage(caster, currentAbsorb, &cleanDamage, DOT, schoolMask, (*i)->GetSpellProto(), false);
2334  }
2335 
2336  AuraList const& vSplitDamagePct = victim->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_PCT);
2337  for (AuraList::const_iterator i = vSplitDamagePct.begin(), next; i != vSplitDamagePct.end() && RemainingDamage >= 0; i = next)
2338  {
2339  next = i;
2340  ++next;
2341 
2342  // check damage school mask
2343  if (!((*i)->GetModifier()->m_miscvalue & schoolMask))
2344  continue;
2345 
2346  // Damage can only be split if the aura has an alive caster linked
2347  Unit* caster = (*i)->GetCaster();
2348  if (!caster || caster == victim || !caster->IsInWorld() || !caster->IsAlive() || caster->IsImmunedToDamage((SpellSchoolMask)(*i)->GetSpellProto()->SchoolMask))
2349  continue;
2350 
2351  uint32 splitted = CalculatePct(RemainingDamage, (*i)->GetModifier()->m_amount);
2352 
2353  RemainingDamage -= int32(splitted);
2354 
2355  SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, 0, 0, false, 0, false);
2356 
2357  CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL);
2358  DealDamage(caster, splitted, &cleanDamage, DOT, schoolMask, (*i)->GetSpellProto(), false);
2359  // break 'Fear' and similar auras
2360  caster->ProcDamageAndSpellFor(true, this, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_EX_NORMAL_HIT, BASE_ATTACK, (*i)->GetSpellProto(), splitted);
2361  }
2362  }
2363 
2364  *absorb = damage - RemainingDamage - *resist;
2365 }
2366 
2367 void Unit::AttackerStateUpdate (Unit* victim, WeaponAttackType attType, bool extra)
2368 {
2370  return;
2371 
2372  if (!victim->IsAlive())
2373  return;
2374 
2375  if ((attType == BASE_ATTACK || attType == OFF_ATTACK) && !IsWithinLOSInMap(victim))
2376  return;
2377 
2379 
2380  if (attType != BASE_ATTACK && attType != OFF_ATTACK)
2381  return; // ignore ranged case
2382 
2383  // melee attack spell casted at main hand attack only
2384  if (attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL] && !extra)
2385  {
2387  return;
2388  }
2389 
2390  CalcDamageInfo damageInfo;
2391  CalculateMeleeDamage(victim, 0, &damageInfo, attType);
2392  // Send log damage message to client
2393  SendAttackStateUpdate(&damageInfo);
2394 
2395  ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType);
2396 
2397  DealMeleeDamage(&damageInfo, true);
2398 
2399  // We call this last because DealMeleeDamage has to check for sit state to
2400  // allow critical hits, but we set STANDING in CombatStart, therefore always
2401  // nullifying the check.
2402  CombatStart(victim);
2403 
2404  #ifdef OREGON_DEBUG
2405  if (GetTypeId() == TYPEID_PLAYER)
2406  DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2407  GetGUIDLow(), victim->GetGUIDLow(), victim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist);
2408  else
2409  DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2410  GetGUIDLow(), victim->GetGUIDLow(), victim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist);
2411  #endif
2412 
2413 }
2414 
2416 {
2417  // This is only wrapper
2418 
2419  // Miss chance based on melee
2420  //float miss_chance = MeleeMissChanceCalc(victim, attType);
2421  float miss_chance = MeleeSpellMissChance(victim, attType, int32(GetWeaponSkillValue(attType, victim)) - int32(victim->GetDefenseSkillValue(this)), 0);
2422 
2423  // Critical hit chance
2424  float crit_chance = GetUnitCriticalChance(attType, victim);
2425 
2426  // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case)
2427  float dodge_chance = victim->GetUnitDodgeChance();
2428  float block_chance = victim->GetUnitBlockChance();
2429  float parry_chance = victim->GetUnitParryChance();
2430 
2431  // Useful if want to specify crit & miss chances for melee, else it could be removed
2432  DEBUG_LOG("MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance, crit_chance, dodge_chance, parry_chance, block_chance);
2433 
2434  return RollMeleeOutcomeAgainst(victim, attType, int32(crit_chance * 100), int32(miss_chance * 100), int32(dodge_chance * 100), int32(parry_chance * 100), int32(block_chance * 100), false);
2435 }
2436 
2437 MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance, bool SpellCasted) const
2438 {
2439  if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode())
2440  return MELEE_HIT_EVADE;
2441 
2442  int32 attackerMaxSkillValueForLevel = GetMaxSkillValueForLevel(victim);
2443  int32 victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this);
2444 
2445  int32 attackerWeaponSkill = GetWeaponSkillValue(attType, victim);
2446  int32 victimDefenseSkill = victim->GetDefenseSkillValue(this);
2447 
2448  // bonus from skills is 0.04%
2449  int32 skillBonus = 4 * (attackerWeaponSkill - victimMaxSkillValueForLevel);
2450  int32 skillBonus2 = 4 * (attackerMaxSkillValueForLevel - victimDefenseSkill);
2451  int32 sum = 0, tmp = 0;
2452  int32 roll = urand (0, 10000);
2453 
2454  DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus);
2455  DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d",
2456  roll, miss_chance, dodge_chance, parry_chance, block_chance, crit_chance);
2457 
2458  tmp = miss_chance;
2459 
2460  if (tmp > 0 && roll < (sum += tmp))
2461  {
2462  DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS");
2463  return MELEE_HIT_MISS;
2464  }
2465 
2466  // always crit against a sitting target (except 0 crit chance)
2467  if (victim->GetTypeId() == TYPEID_PLAYER && crit_chance > 0 && !victim->IsStandState())
2468  {
2469  DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)");
2470  return MELEE_HIT_CRIT;
2471  }
2472 
2473  // Dodge chance
2474 
2475  // only players can't dodge if attacker is behind
2476  if (victim->GetTypeId() == TYPEID_PLAYER && !victim->HasInArc(float(M_PI), this))
2477  DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind and victim was a player.");
2478  else
2479  {
2480  // Reduce dodge chance by attacker expertise rating
2481  if (GetTypeId() == TYPEID_PLAYER)
2482  dodge_chance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100);
2483  else
2484  dodge_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
2485 
2486  // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2488  dodge_chance = int32 (float (dodge_chance) * GetTotalAuraMultiplier(SPELL_AURA_MOD_ENEMY_DODGE));
2489 
2490  tmp = dodge_chance;
2491  if ((tmp > 0) // check if unit _can_ dodge
2492  && ((tmp -= skillBonus) > 0)
2493  && roll < (sum += tmp))
2494  {
2495  DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum - tmp, sum);
2496  return MELEE_HIT_DODGE;
2497  }
2498  }
2499 
2500  // parry & block chances
2501 
2502  // check if attack comes from behind, nobody can parry or block if attacker is behind
2503  if (!victim->HasInArc(float(M_PI), this))
2504  DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind.");
2505  else
2506  {
2507  // Reduce parry chance by attacker expertise rating
2508  if (GetTypeId() == TYPEID_PLAYER)
2509  parry_chance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100);
2510  else
2511  parry_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
2512 
2514  {
2515  int32 tmp2 = int32(parry_chance);
2516  if (tmp2 > 0 // check if unit _can_ parry
2517  && (tmp2 -= skillBonus) > 0
2518  && roll < (sum += tmp2))
2519  {
2520  DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum - tmp2, sum);
2521  return MELEE_HIT_PARRY;
2522  }
2523  }
2524 
2526  {
2527  tmp = block_chance;
2528  if (tmp > 0 // check if unit _can_ block
2529  && (tmp -= skillBonus) > 0
2530  && roll < (sum += tmp))
2531  {
2532  // Critical chance
2533  tmp = crit_chance + skillBonus2;
2534  if (GetTypeId() == TYPEID_PLAYER && SpellCasted && tmp > 0)
2535  {
2536  if (roll_chance_i(tmp / 100))
2537  {
2538  DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCKED CRIT");
2539  return MELEE_HIT_BLOCK_CRIT;
2540  }
2541  }
2542  DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum - tmp, sum);
2543  return MELEE_HIT_BLOCK;
2544  }
2545  }
2546  }
2547 
2548  // Critical chance
2549  tmp = crit_chance + skillBonus2;
2550 
2551  if (tmp > 0 && roll < (sum += tmp))
2552  {
2553  DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum - tmp, sum);
2555  DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT DISABLED)");
2556  else
2557  return MELEE_HIT_CRIT;
2558  }
2559 
2560  // 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)
2561  if (attType != RANGED_ATTACK && !SpellCasted &&
2562  (GetTypeId() == TYPEID_PLAYER || IsPet()) &&
2563  victim->GetTypeId() != TYPEID_PLAYER && !victim->IsPet() &&
2564  getLevel() < victim->getLevelForTarget(this))
2565  {
2566  // cap possible value (with bonuses > max skill)
2567  int32 skill = attackerWeaponSkill;
2568  int32 maxskill = attackerMaxSkillValueForLevel;
2569  skill = (skill > maxskill) ? maxskill : skill;
2570 
2571  tmp = (10 + (victimDefenseSkill - skill)) * 100;
2572  tmp = tmp > 4000 ? 4000 : tmp;
2573  if (roll < (sum += tmp))
2574  {
2575  DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum - 4000, sum);
2576  return MELEE_HIT_GLANCING;
2577  }
2578  }
2579 
2580  // mobs can only score crushing blows with autoattack
2581  if (!SpellCasted && !IsControlledByPlayer() &&
2583  {
2584  // when their weapon skill is 15 or more above victim's defense skill
2585  tmp = victimDefenseSkill;
2586  int32 tmpmax = victimMaxSkillValueForLevel;
2587  // having defense above your maximum (from items, talents etc.) has no effect
2588  tmp = tmp > tmpmax ? tmpmax : tmp;
2589  // tmp = mob's level * 5 - player's current defense skill
2590  tmp = attackerMaxSkillValueForLevel - tmp;
2591  if (tmp >= 15)
2592  {
2593  // add 2% chance per lacking skill point, min. is 15%
2594  tmp = tmp * 200 - 1500;
2595  if (roll < (sum += tmp))
2596  {
2597  DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum - tmp, sum);
2598  return MELEE_HIT_CRUSHING;
2599  }
2600  }
2601  }
2602 
2603  DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL");
2604  return MELEE_HIT_NORMAL;
2605 }
2606 
2607 uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct)
2608 {
2609  float minDamage = 0.0f;
2610  float maxDamage = 0.0f;
2611 
2612  if (normalized && GetTypeId() == TYPEID_PLAYER)
2613  ToPlayer()->CalculateMinMaxDamage(attType, normalized, addTotalPct, minDamage, maxDamage);
2614  else
2615  {
2616  switch (attType)
2617  {
2618  case RANGED_ATTACK:
2621  break;
2622  case BASE_ATTACK:
2623  minDamage = GetFloatValue(UNIT_FIELD_MINDAMAGE);
2624  maxDamage = GetFloatValue(UNIT_FIELD_MAXDAMAGE);
2625  break;
2626  case OFF_ATTACK:
2629  break;
2630  default:
2631  break;
2632  }
2633  }
2634 
2635  minDamage = std::max(0.f, minDamage);
2636  maxDamage = std::max(0.f, maxDamage);
2637 
2638  if (minDamage > maxDamage)
2639  std::swap(minDamage, maxDamage);
2640 
2641  if (maxDamage == 0.0f)
2642  maxDamage = 5.0f;
2643 
2644  return urand(uint32(minDamage), uint32(maxDamage));
2645 }
2646 
2647 float Unit::CalculateLevelPenalty(SpellEntry const* spellProto) const
2648 {
2649  if (spellProto->spellLevel <= 0 || spellProto->spellLevel >= spellProto->maxLevel)
2650  return 1.0f;
2651 
2652  float LvlPenalty = 0.0f;
2653 
2654  if (spellProto->spellLevel < 20)
2655  LvlPenalty = (20.0f - spellProto->spellLevel) * 3.75f;
2656 
2657  float LvlFactor = (float(spellProto->spellLevel) + 6.0f) / float(getLevel());
2658  if (LvlFactor > 1.0f)
2659  LvlFactor = 1.0f;
2660 
2661  return (100.0f - LvlPenalty) * LvlFactor / 100.0f;
2662 }
2663 
2665 {
2666  WorldPacket data(SMSG_ATTACKSTART, 8 + 8);
2667  data << uint64(GetGUID());
2668  data << uint64(victim->GetGUID());
2669  SendMessageToSet(&data, true);
2670  DEBUG_LOG("WORLD: Sent SMSG_ATTACKSTART");
2671 }
2672 
2674 {
2675  WorldPacket data(SMSG_ATTACKSTOP, (8+8+4));
2676  data << GetPackGUID();
2677  if (victim)
2678  data << victim->GetPackGUID();
2679  else
2680  data << uint8(0);
2681 
2682  data << uint32(0);
2683  SendMessageToSet(&data, true);
2684  sLog.outDebug("WORLD: Sent SMSG_ATTACKSTOP");
2685 
2686  if (victim)
2687  sLog.outDetail("%s %u stopped attacking %s %u", (GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), GetGUIDLow(), (victim->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), victim->GetGUIDLow());
2688  else
2689  sLog.outDetail("%s %u stopped attacking", (GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), GetGUIDLow());
2690 }
2691 
2692 bool Unit::isSpellBlocked(Unit* victim, SpellEntry const* spellProto, WeaponAttackType attackType)
2693 {
2694  // These spells can't be blocked
2695  if (spellProto && spellProto->Attributes & SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK)
2696  return false;
2697 
2698  if (victim->HasInArc(float(M_PI), this))
2699  {
2700  // Check creatures flags_extra for disable block
2701  if (victim->GetTypeId() == TYPEID_UNIT &&
2703  return false;
2704 
2705  float blockChance = victim->GetUnitBlockChance();
2706 
2707  float fAttackerSkill = GetWeaponSkillValue(attackType, victim) * 0.04f;
2708  float fDefenserSkill = victim->GetDefenseSkillValue(this) * 0.04f;
2709 
2710  blockChance += (fDefenserSkill - fAttackerSkill);
2711  if (blockChance < 0.0)
2712  blockChance = 0.0;
2713 
2714  if (roll_chance_f(blockChance))
2715  return true;
2716  }
2717  return false;
2718 }
2719 
2720 // Melee based spells can be miss, parry or dodge on this step
2721 // Crit or block - determined on damage calculation phase! (and can be both in some time)
2722 float Unit::MeleeSpellMissChance(const Unit* victim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const
2723 {
2724  // Calculate hit chance (more correct for chance mod)
2725  float HitChance = 0.0f;
2726 
2727  // PvP - PvE melee chances
2728  if (victim->GetTypeId() == TYPEID_PLAYER)
2729  HitChance = 95.0f + skillDiff * 0.04f;
2730  else if (skillDiff < -10)
2731  HitChance = 93.0f + (skillDiff + 10) * 0.4f; // 7% base chance to miss for big skill diff (%6 in 3.x)
2732  else
2733  HitChance = 95.0f + skillDiff * 0.1f;
2734 
2735  // Hit chance depends from victim auras
2736  if (attType == RANGED_ATTACK)
2738  else
2740 
2741  // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
2742  if (spellId)
2743  {
2744  if (Player* modOwner = GetSpellModOwner())
2745  modOwner->ApplySpellMod(spellId, SPELLMOD_RESIST_MISS_CHANCE, HitChance);
2746  }
2747 
2748  // Miss = 100 - hit
2749  float miss_chance = 100.0f - HitChance;
2750 
2751  // Bonuses from attacker aura and ratings
2752  if (attType == RANGED_ATTACK)
2753  miss_chance -= m_modRangedHitChance;
2754  else
2755  miss_chance -= m_modMeleeHitChance;
2756 
2757  // bonus from skills is 0.04%
2758  //miss_chance -= skillDiff * 0.04f;
2759  int32 diff = -skillDiff;
2760  if (victim->GetTypeId() == TYPEID_PLAYER)
2761  miss_chance += diff > 0 ? diff * 0.04 : diff * 0.02;
2762  else
2763  miss_chance += diff > 10 ? 2 + (diff - 10) * 0.4 : diff * 0.1;
2764 
2765  // Limit miss chance from 0 to 60%
2766  if (miss_chance < 0.0f)
2767  return 0.0f;
2768  if (miss_chance > 60.0f)
2769  return 60.0f;
2770  return miss_chance;
2771 }
2772 
2774 {
2775  if (!spellInfo)
2776  return 0;
2777 
2778  int32 resistMech = 0;
2779  for (uint8 eff = 0; eff < MAX_SPELL_EFFECTS; ++eff)
2780  {
2781  if (spellInfo->Effect[eff] == 0)
2782  break;
2783 
2784  int32 effectMech = GetEffectMechanic(spellInfo, eff);
2785  if (effectMech)
2786  {
2788  if (resistMech < temp)
2789  resistMech = temp;
2790  }
2791  }
2792  return resistMech;
2793 }
2794 
2795 bool Unit::CanUseAttackType(uint8 attacktype) const
2796 {
2797  switch (attacktype)
2798  {
2799  case BASE_ATTACK:
2801  /* @todo Implement unit flags 2 properly
2802  case OFF_ATTACK:
2803  return !HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_DISARM_OFFHAND);
2804  case RANGED_ATTACK:
2805  return !HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_DISARM_RANGED);*/
2806  default:
2807  return true;
2808  }
2809 }
2810 
2811 // Melee based spells hit result calculations
2812 SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellEntry const* spellInfo, bool cMiss)
2813 {
2814  // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore
2815  // resist and deflect chances
2816  if (spellInfo->AttributesEx3 & SPELL_ATTR3_CANT_MISS)
2817  return SPELL_MISS_NONE;
2818 
2819  WeaponAttackType attType = BASE_ATTACK;
2820 
2821  // Check damage class instead of attack type to correctly handle judgements
2822  // - they are meele, but can't be dodged/parried/deflected because of ranged dmg class
2823  if (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
2824  attType = RANGED_ATTACK;
2825 
2826  int32 attackerWeaponSkill;
2827  // skill value for these spells (for example judgements) is 5* level
2828  if (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED && !(spellInfo->Attributes & SPELL_ATTR0_RANGED))
2829  attackerWeaponSkill = getLevel() * 5;
2830  // bonus from skills is 0.04% per skill Diff
2831  else
2832  attackerWeaponSkill = int32(GetWeaponSkillValue(attType, victim));
2833 
2834  int32 skillDiff = attackerWeaponSkill - int32(victim->GetMaxSkillValueForLevel(this));
2835  int32 fullSkillDiff = attackerWeaponSkill - int32(victim->GetDefenseSkillValue(this));
2836 
2837  uint32 roll = urand (0, 10000);
2838  uint32 tmp = 0;
2839 
2840  bool canDodge = true;
2841  bool canParry = true;
2842  bool canBlock = (spellInfo->AttributesEx3 & SPELL_ATTR3_CAN_BE_BLOCKED) != 0;
2843  bool canMiss = !(spellInfo->AttributesEx3 & SPELL_ATTR3_CANT_MISS) && cMiss;
2844 
2845  if (canMiss)
2846  {
2847  uint32 missChance = uint32(MeleeSpellMissChance(victim, attType, fullSkillDiff, spellInfo->Id) * 100.0f);
2848  // Roll miss
2849  tmp += missChance;
2850  if (roll < tmp)
2851  return SPELL_MISS_MISS;
2852  }
2853 
2854  // Chance resist mechanic
2855  int32 resist_chance = victim->GetMechanicResistChance(spellInfo) * 100;
2856  tmp += resist_chance;
2857  if (roll < tmp)
2858  return SPELL_MISS_RESIST;
2859 
2860  // @XXX: Tidal Charm: Increased chance to be resisted when used against targets over level 60.
2861  if (spellInfo->Id == 835)
2862  {
2863  if (victim->getLevel() > 60)
2864  {
2865  uint32 tmp = victim->getLevel();
2866  uint32 rand = urand(60, 160);
2867 
2868  if (rand > tmp)
2869  return SPELL_MISS_RESIST;
2870  }
2871  }
2872 
2873  // Ranged attack can`t miss too
2874  if (attType == RANGED_ATTACK)
2875  return SPELL_MISS_NONE;
2876 
2877  // Some spells cannot be parry/dodge
2879  return SPELL_MISS_NONE;
2880 
2881  // Check for attack from behind
2882  // This is the only Dodge/Block check that can't be done from behind
2883  // based on unit type.
2884  if (!victim->HasInArc(float(M_PI), this))
2885  {
2886  // Can`t dodge from behind in PvP (but its possible in PvE)
2887  if (victim->GetTypeId() == TYPEID_PLAYER)
2888  canDodge = false;
2889  // Can`t parry
2890  canParry = false;
2891  // Can't block from behind in PvE (but its possible in PvP)
2892  if (victim->GetTypeId() == TYPEID_UNIT)
2893  canBlock = false;
2894  }
2895 
2896  // Check creatures flags_extra for disable parry
2897  if (victim->GetTypeId() == TYPEID_UNIT)
2898  {
2899  uint32 flagEx = victim->ToCreature()->GetCreatureTemplate()->flags_extra;
2900  if (flagEx & CREATURE_FLAG_EXTRA_NO_PARRY)
2901  canParry = false;
2902  // Check creatures flags_extra for disable block
2903  if (flagEx & CREATURE_FLAG_EXTRA_NO_BLOCK)
2904  canBlock = false;
2905  }
2906 
2907  // Ignore combat result aura
2908  AuraList const& mCanNotBeDodge = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
2909  for (AuraList::const_iterator i = mCanNotBeDodge.begin(); i != mCanNotBeDodge.end(); ++i)
2910  {
2911  switch ((*i)->GetMiscValue())
2912  {
2913  case MELEE_HIT_DODGE:
2914  canDodge = false;
2915  break;
2916  case MELEE_HIT_BLOCK:
2917  canBlock = false;
2918  break;
2919  case MELEE_HIT_PARRY:
2920  canParry = false;
2921  break;
2922  default:
2923  DEBUG_LOG("Spell %u SPELL_AURA_IGNORE_COMBAT_RESULT has unhandled state %d", (*i)->GetId(), (*i)->GetMiscValue());
2924  break;
2925  }
2926  }
2927 
2928  if (canDodge)
2929  {
2930  // Roll dodge
2931  int32 dodgeChance = int32(victim->GetUnitDodgeChance() * 100.0f) - skillDiff * 4;
2932  // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2934  dodgeChance = int32(float(dodgeChance) * GetTotalAuraMultiplier(SPELL_AURA_MOD_ENEMY_DODGE));
2935  // Reduce dodge chance by attacker expertise rating
2936  if (GetTypeId() == TYPEID_PLAYER)
2937  dodgeChance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2938  else
2939  dodgeChance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
2940  if (dodgeChance < 0)
2941  dodgeChance = 0;
2942 
2943  if (roll < (tmp += dodgeChance))
2944  return SPELL_MISS_DODGE;
2945  }
2946 
2947  if (canParry)
2948  {
2949  // Roll parry
2950  int32 parryChance = int32(victim->GetUnitParryChance() * 100.0f) - skillDiff * 4;
2951  // Reduce parry chance by attacker expertise rating
2952  if (GetTypeId() == TYPEID_PLAYER)
2953  parryChance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2954  else
2955  parryChance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
2956  if (parryChance < 0)
2957  parryChance = 0;
2958 
2959  tmp += parryChance;
2960  if (roll < tmp)
2961  return SPELL_MISS_PARRY;
2962  }
2963 
2964  if (canBlock)
2965  {
2966  int32 blockChance = int32(victim->GetUnitBlockChance() * 100.0f) - skillDiff * 4;
2967  if (blockChance < 0)
2968  blockChance = 0;
2969  tmp += blockChance;
2970 
2971  if (roll < tmp)
2972  return SPELL_MISS_BLOCK;
2973  }
2974 
2975  return SPELL_MISS_NONE;
2976 }
2977 
2980 {
2981  // Can`t miss on dead target (on skinning for example)
2982  if ((!victim->IsAlive() && victim->GetTypeId() != TYPEID_PLAYER) || spellInfo->AttributesEx3 & SPELL_ATTR3_CANT_MISS)
2983  return SPELL_MISS_NONE;
2984 
2985  SpellSchoolMask schoolMask = GetSpellSchoolMask(spellInfo);
2986  // PvP - PvE spell misschances per leveldif > 2
2987  int32 lchance = victim->GetTypeId() == TYPEID_PLAYER ? 7 : 11;
2988  int32 thisLevel = getLevelForTarget(victim);
2989  if (GetTypeId() == TYPEID_UNIT && ToCreature()->IsTrigger())
2990  thisLevel = std::max<int32>(thisLevel, spellInfo->spellLevel);
2991  int32 leveldif = int32(victim->getLevelForTarget(this)) - thisLevel;
2992 
2993  // Base hit chance from attacker and victim levels
2994  int32 modHitChance;
2995  if (leveldif < 3)
2996  modHitChance = 96 - leveldif;
2997  else
2998  modHitChance = 94 - (leveldif - 2) * lchance;
2999 
3000  // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
3001  if (Player* modOwner = GetSpellModOwner())
3002  modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance);
3003 
3004  // Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras
3006 
3007  // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
3008  modHitChance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask);
3009  // Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura
3010  if (IsAreaOfEffectSpell(spellInfo))
3011  modHitChance -= victim->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE);
3012 
3013  // Decrease hit chance from victim rating bonus
3014  if (victim->GetTypeId() == TYPEID_PLAYER)
3015  modHitChance -= int32(victim->ToPlayer()->GetRatingBonusValue(CR_HIT_TAKEN_SPELL));
3016 
3017  // Reduce spell hit chance for dispel mechanic spells from victim SPELL_AURA_MOD_DISPEL_RESIST
3018  if (IsDispelSpell(spellInfo))
3019  modHitChance -= victim->GetTotalAuraModifier(SPELL_AURA_MOD_DISPEL_RESIST);
3020 
3021  // Chance resist mechanic (select max value from every mechanic spell effect)
3022  int32 resist_chance = victim->GetMechanicResistChance(spellInfo);
3023  // Apply mod
3024  modHitChance -= resist_chance;
3025 
3026  // Chance resist debuff
3027  modHitChance -= victim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spellInfo->Dispel));
3028 
3029  int32 HitChance = modHitChance * 100;
3030  // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
3031  HitChance += int32(m_modSpellHitChance * 100.0f);
3032 
3033  if (HitChance < 100) HitChance = 100;
3034  if (HitChance > 9900) HitChance = 9900;
3035 
3036  int32 rand = irand(0, 10000);
3037  if (rand > HitChance)
3038  return SPELL_MISS_RESIST;
3039 
3041  {
3042  const bool binary = IsBinarySpell(spellInfo);
3043  const float mitigation = victim->CalculateMagicResistanceMitigation(this, victim->CalculateEffectiveMagicResistance(this, schoolMask), binary);
3044  // Calculate full resist chance
3045  const uint32 chance = binary ? uint32(mitigation * 10000) : SPELL_PARTIAL_RESIST_DISTRIBUTION.at(uint32(mitigation * 10000)).at(SPELL_PARTIAL_RESIST_PCT_100);
3046  // Do a roll for full resist chance
3047  if (urand(0,9999) < chance)
3048  return SPELL_MISS_RESIST;
3049  }
3050 
3051  return SPELL_MISS_NONE;
3052 }
3053 
3054 // Calculate spell hit result can be:
3055 // Every spell can: Evade/Immune/Reflect/Sucesful hit
3056 // For melee based spells:
3057 // Miss
3058 // Dodge
3059 // Parry
3060 // For spells
3061 // Resist
3062 SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellEntry const* spell, bool CanReflect, bool canMiss)
3063 {
3064  // Check for immune (use charges)
3065  if (victim->IsImmuneToSpell(spell, true))
3066  return SPELL_MISS_IMMUNE;
3067 
3068  // All positive spells can`t miss
3069  // @todo client not show miss log for this spells - so need find info for this in dbc and use it!
3070  if (IsPositiveSpell(spell->Id) && !IsHostileTo(victim)) //prevent from affecting enemy by "positive" spell
3071  return SPELL_MISS_NONE;
3072 
3073  // Check for immune
3074  if (victim->IsImmunedToDamage(spell))
3075  return SPELL_MISS_IMMUNE;
3076 
3077  if (this == victim)
3078  return SPELL_MISS_NONE;
3079 
3080  // Return evade for units in evade mode
3081  if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode() && this != victim)
3082  return SPELL_MISS_EVADE;
3083 
3084  // Try victim reflect spell
3085  if (CanReflect)
3086  {
3087  int32 reflectchance = victim->GetTotalAuraModifier(SPELL_AURA_REFLECT_SPELLS);
3088  Unit::AuraList const& mReflectSpellsSchool = victim->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL);
3089  for (Unit::AuraList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i)
3090  if ((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spell))
3091  reflectchance = (*i)->GetModifierValue();
3092  if (reflectchance > 0 && roll_chance_i(reflectchance))
3093  {
3094  // Start triggers for remove charges if need (trigger only for victim, and mark as active spell)
3096  return SPELL_MISS_REFLECT;
3097  }
3098  }
3099 
3100  switch (spell->DmgClass)
3101  {
3104  return MeleeSpellHitResult(victim, spell, canMiss);
3106  return SPELL_MISS_NONE;
3108  return MagicSpellHitResult(victim, spell);
3109  }
3110  return SPELL_MISS_NONE;
3111 }
3112 
3113 float Unit::MeleeMissChanceCalc(const Unit* victim, WeaponAttackType attType) const
3114 {
3115  if (!victim)
3116  return 0.0f;
3117 
3118  // Base misschance 5%
3119  float missChance = 5.0f;
3120 
3121  // DualWield - white damage has additional 19% miss penalty
3122  if (haveOffhandWeapon() && attType != RANGED_ATTACK)
3123  {
3124  bool isNormal = false;
3126  {
3128  {
3129  isNormal = true;
3130  break;
3131  }
3132  }
3133  if (!isNormal && !m_currentSpells[CURRENT_MELEE_SPELL])
3134  missChance += 19.0f;
3135  }
3136 
3137  int32 skillDiff = int32(GetWeaponSkillValue(attType, victim)) - int32(victim->GetDefenseSkillValue(this));
3138 
3139  // PvP - PvE melee chances
3140  if ( victim->GetTypeId() == TYPEID_PLAYER )
3141  missChance -= skillDiff * 0.04f;
3142  else if ( skillDiff < -10 )
3143  missChance -= (skillDiff + 10) * 0.4f - 2.0f; // 7% base chance to miss for big skill diff (%6 in 3.x)
3144  else
3145  missChance -= skillDiff * 0.1f;
3146 
3147  // Hit chance bonus from attacker based on ratings and auras
3148  if (attType == RANGED_ATTACK)
3149  missChance -= m_modRangedHitChance;
3150  else
3151  missChance -= m_modMeleeHitChance;
3152 
3153  // Hit chance for victim based on ratings
3154  if (victim->GetTypeId() == TYPEID_PLAYER)
3155  {
3156  if (attType == RANGED_ATTACK)
3157  missChance += ((Player*)victim)->GetRatingBonusValue(CR_HIT_TAKEN_RANGED);
3158  else
3159  missChance += ((Player*)victim)->GetRatingBonusValue(CR_HIT_TAKEN_MELEE);
3160  }
3161 
3162  // Modify miss chance by victim auras
3163  if (attType == RANGED_ATTACK)
3165  else
3167 
3168  // Limit miss chance from 0 to 60%
3169  if (missChance < 0.0f)
3170  return 0.0f;
3171  if (missChance > 60.0f)
3172  return 60.0f;
3173 
3174  return missChance;
3175 }
3176 
3178 {
3179  if (GetTypeId() == TYPEID_PLAYER)
3180  {
3181  // in PvP use full skill instead current skill value
3182  uint32 value = (target && target->GetTypeId() == TYPEID_PLAYER)
3185  value += uint32(ToPlayer()->GetRatingBonusValue(CR_DEFENSE_SKILL));
3186  return value;
3187  }
3188  else
3189  return GetUnitMeleeSkill(target);
3190 }
3191 
3193 {
3195  return 0.0f;
3196 
3197  if (GetTypeId() == TYPEID_PLAYER)
3199  else
3200  {
3201  if (IsTotem())
3202  return 0.0f;
3203  else
3204  {
3205  float dodge = 5.0f;
3207  return dodge > 0.0f ? dodge : 0.0f;
3208  }
3209  }
3210 }
3211 
3213 {
3215  return 0.0f;
3216 
3217  float chance = 0.0f;
3218 
3219  if (GetTypeId() == TYPEID_PLAYER)
3220  {
3221  Player const* player = (Player const*)this;
3222  if (player->CanParry())
3223  {
3224  Item* tmpitem = player->GetWeaponForAttack(BASE_ATTACK, true);
3225  if (!tmpitem)
3226  tmpitem = player->GetWeaponForAttack(OFF_ATTACK, true);
3227 
3228  if (tmpitem)
3230  }
3231  }
3232  else if (GetTypeId() == TYPEID_UNIT)
3233  {
3235  {
3236  chance = 5.0f;
3238  }
3239  }
3240 
3241  return chance > 0.0f ? chance : 0.0f;
3242 }
3243 
3245 {
3247  return 0.0f;
3248 
3249  if (GetTypeId() == TYPEID_PLAYER)
3250  {
3251  Player const* player = (Player const*)this;
3252  if (player->CanBlock())
3253  {
3255  if (tmpitem && !tmpitem->IsBroken() && tmpitem->GetProto()->Block)
3257  }
3258  // is player but has no block ability or no not broken shield equipped
3259  return 0.0f;
3260  }
3261  else
3262  {
3263  if (IsTotem())
3264  return 0.0f;
3265  else
3266  {
3267  float block = 5.0f;
3269  return block > 0.0f ? block : 0.0f;
3270  }
3271  }
3272 }
3273 
3274 float Unit::GetUnitCriticalChance(WeaponAttackType attackType, const Unit* victim) const
3275 {
3276  float crit;
3277 
3278  if (GetTypeId() == TYPEID_PLAYER)
3279  {
3280  switch (attackType)
3281  {
3282  case BASE_ATTACK:
3284  break;
3285  case OFF_ATTACK:
3287  break;
3288  case RANGED_ATTACK:
3290  break;
3291  // Just for good manner
3292  default:
3293  crit = 0.0f;
3294  break;
3295  }
3296  }
3297  else
3298  {
3299  crit = 5.0f;
3301  }
3302 
3303  // flat aura mods
3304  if (attackType == RANGED_ATTACK)
3306  else
3308 
3310 
3311  // reduce crit chance from Rating for players
3312  if (victim->GetTypeId() == TYPEID_PLAYER)
3313  {
3314  if (attackType == RANGED_ATTACK)
3316  else
3317  crit -= victim->ToPlayer()->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE);
3318  }
3319 
3320  if (crit < 0.0f)
3321  crit = 0.0f;
3322  return crit;
3323 }
3324 
3326 {
3327  uint32 value = 0;
3328  if (GetTypeId() == TYPEID_PLAYER)
3329  {
3330  Item* item = ToPlayer()->GetWeaponForAttack(attType, true);
3331 
3332  // feral or unarmed skill only for base attack
3333  if (attType != BASE_ATTACK && !item)
3334  {
3335  if (attType == RANGED_ATTACK && getClass() == CLASS_PALADIN) //hammer
3336  return GetMaxSkillValueForLevel();
3337  return 0;
3338  }
3339 
3340  if (IsInFeralForm())
3341  return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact
3342 
3343  // weapon skill or (unarmed for base attack and fist weapons)
3344  uint32 skill = item && item->GetSkill() != SKILL_FIST_WEAPONS ? item->GetSkill() : uint32(SKILL_UNARMED);
3345 
3346  // in PvP use full skill instead current skill value
3347  value = (target && target->IsCharmedOwnedByPlayerOrPlayer())
3348  ? ToPlayer()->GetMaxSkillValue(skill)
3349  : ToPlayer()->GetSkillValue(skill);
3350  // Modify value from ratings
3351  value += uint32(ToPlayer()->GetRatingBonusValue(CR_WEAPON_SKILL));
3352  switch (attType)
3353  {
3354  case BASE_ATTACK: value += uint32(ToPlayer()->GetRatingBonusValue(CR_WEAPON_SKILL_MAINHAND)); break;
3355  case OFF_ATTACK: value += uint32(ToPlayer()->GetRatingBonusValue(CR_WEAPON_SKILL_OFFHAND)); break;
3356  case RANGED_ATTACK: value += uint32(ToPlayer()->GetRatingBonusValue(CR_WEAPON_SKILL_RANGED)); break;
3357  default: break;
3358  }
3359  }
3360  else
3361  value = GetUnitMeleeSkill(target);
3362  return value;
3363 }
3364 
3366 {
3367  while (!m_removedAuras.empty())
3368  {
3369  delete m_removedAuras.front();
3370  m_removedAuras.pop_front();
3371  }
3372 }
3373 
3375 {
3378 
3379  // remove finished spells from current pointers
3380  for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i)
3381  {
3382  if (m_currentSpells[i] && m_currentSpells[i]->getState() == SPELL_STATE_FINISHED)
3383  {
3385  m_currentSpells[i] = NULL; // remove pointer
3386  }
3387  }
3388 
3389  // m_AurasUpdateIterator can be updated in inderect called code at aura remove to skip next planned to update but removed auras
3390  for (m_AurasUpdateIterator = m_Auras.begin(); m_AurasUpdateIterator != m_Auras.end();)
3391  {
3392  Aura* i_aura = m_AurasUpdateIterator->second;
3393  ++m_AurasUpdateIterator; // need shift to next for allow update if need into aura update
3394  i_aura->Update(time);
3395  }
3396 
3397  // remove expired auras
3398  for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end();)
3399  {
3400  if (i->second->IsExpired())
3402  else
3403  ++i;
3404  }
3405 
3406  _DeleteAuras();
3407 
3408  if (!m_gameObj.empty())
3409  {
3410  std::list<GameObject*>::iterator itr;
3411  for (itr = m_gameObj.begin(); itr != m_gameObj.end();)
3412  {
3413  if (!(*itr)->isSpawned())
3414  {
3415  (*itr)->SetOwnerGUID(0);
3416  (*itr)->SetRespawnTime(0);
3417  (*itr)->Delete();
3418  m_gameObj.erase(itr++);
3419  }
3420  else
3421  ++itr;
3422  }
3423  }
3424 }
3425 
3427 {
3428  //check "realtime" interrupts
3429  if ((GetTypeId() == TYPEID_PLAYER && isMoving()) || IsNonMeleeSpellCast(false, false, true))
3430  {
3431  // cancel wand shoot
3432  if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
3434  m_AutoRepeatFirstCast = true;
3435  return;
3436  }
3437 
3438  // apply delay (Auto Shot (spellID 75) not affected)
3441  m_AutoRepeatFirstCast = false;
3442 
3443  //castroutine
3445  {
3446  // Check if able to cast
3447  if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckCast(true) != SPELL_CAST_OK)
3448  {
3450  return;
3451  }
3452 
3453  // we want to shoot
3454  Spell* spell = new Spell(this, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo, true, 0);
3455  spell->prepare(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets));
3456 
3457  // all went good, reset attack
3459  }
3460 }
3461 
3463 {
3464  ASSERT(pSpell); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
3465 
3466  CurrentSpellTypes CSpellType = pSpell->GetCurrentContainer();
3467 
3468  if (pSpell == m_currentSpells[CSpellType]) // avoid breaking self
3469  return;
3470 
3471  // break same type spell if it is not delayed
3472  InterruptSpell(CSpellType, false);
3473 
3474  // special breakage effects:
3475  switch (CSpellType)
3476  {
3477  case CURRENT_GENERIC_SPELL:
3478  {
3479  // generic spells always break channeled not delayed spells
3481 
3482  // autorepeat breaking
3484  {
3485  // break autorepeat if not Auto Shot
3486  if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
3487  InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
3488  m_AutoRepeatFirstCast = true;
3489  }
3490  if (pSpell->GetCastTime() > 0)
3492 
3493  break;
3494  }
3496  {
3497  // channel spells always break generic non-delayed and any channeled spells
3500 
3501  // it also does break autorepeat if not Auto Shot
3503  m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
3506 
3507  break;
3508  }
3510  {
3511  // only Auto Shoot does not break anything
3512  if (pSpell->m_spellInfo->Category == 351)
3513  {
3514  // generic autorepeats break generic non-delayed and channeled non-delayed spells
3517  }
3518  // special action: set first cast flag
3519  m_AutoRepeatFirstCast = true;
3520 
3521  break;
3522  }
3523  default:
3524  break; // other spell types don't break anything now
3525  }
3526 
3527  // current spell (if it is still here) may be safely deleted now
3528  if (m_currentSpells[CSpellType])
3529  m_currentSpells[CSpellType]->SetReferencedFromCurrent(false);
3530 
3531  // set new current spell
3532  m_currentSpells[CSpellType] = pSpell;
3533  pSpell->SetReferencedFromCurrent(true);
3534 
3535  pSpell->m_selfContainer = &(m_currentSpells[pSpell->GetCurrentContainer()]);
3536 }
3537 
3538 void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool withInstant)
3539 {
3540  Spell* spell = m_currentSpells[spellType];
3541  if (spell
3542  && (withDelayed || spell->getState() != SPELL_STATE_DELAYED)
3543  && (withInstant || spell->GetCastTime() > 0 || spell->getState() == SPELL_STATE_CASTING))
3544  {
3545  // for example, do not let self-stun aura interrupt itself
3546  if (!spell->IsInterruptable())
3547  return;
3548 
3549  m_currentSpells[spellType] = NULL;
3550 
3551  // send autorepeat cancel message for autorepeat spells
3552  if (spellType == CURRENT_AUTOREPEAT_SPELL)
3553  if (GetTypeId() == TYPEID_PLAYER)
3555 
3556  if (spell->getState() != SPELL_STATE_FINISHED)
3557  spell->cancel(true);
3558  else
3559  {
3560  m_currentSpells[spellType] = nullptr;
3561  spell->SetReferencedFromCurrent(false);
3562  }
3563  }
3564 }
3565 
3566 void Unit::FinishSpell(CurrentSpellTypes spellType, bool ok /*= true*/)
3567 {
3568  Spell* spell = m_currentSpells[spellType];
3569  if (!spell)
3570  return;
3571 
3572  if (spellType == CURRENT_CHANNELED_SPELL)
3573  spell->SendChannelUpdate(0);
3574 
3575  spell->finish(ok);
3576 }
3577 
3578 bool Unit::IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled, bool skipAutorepeat) const
3579 {
3580  // We don't do loop here to explicitly show that melee spell is excluded.
3581  // Maybe later some special spells will be excluded too.
3582 
3583  // generic spells are casted when they are not finished and not delayed
3586  (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED))
3587  {
3588  if (!(m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->AttributesEx2 & SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS))
3589  return (true);
3590  }
3591 
3592  // channeled spells may be delayed, but they are still considered casted
3593  else if (!skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
3595  {
3596  if (!(m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->AttributesEx2 & SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS))
3597  return (true);
3598  }
3599 
3600  // autorepeat spells may be finished or delayed, but they are still considered casted
3601  else if (!skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
3602  return (true);
3603 
3604  return (false);
3605 }
3606 
3607 void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id, bool withInstant)
3608 {
3609  // generic spells are interrupted if they are not finished or delayed
3610  if (m_currentSpells[CURRENT_GENERIC_SPELL] && (!spell_id || m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id == spell_id))
3611  InterruptSpell(CURRENT_GENERIC_SPELL, withDelayed, withInstant);
3612 
3613  // autorepeat spells are interrupted if they are not finished or delayed
3614  if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && (!spell_id || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id == spell_id))
3615  InterruptSpell(CURRENT_AUTOREPEAT_SPELL, withDelayed, withInstant);
3616 
3617  // channeled spells are interrupted if they are not finished, even if they are delayed
3618  if (m_currentSpells[CURRENT_CHANNELED_SPELL] && (!spell_id || m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id == spell_id))
3620 }
3621 
3623 {
3624  for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
3625  if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id == spell_id)
3626  return m_currentSpells[i];
3627  return NULL;
3628 }
3629 
3631 {
3632  if (Spell const* spell = FindCurrentSpellBySpellId(spell_id))
3633  return spell->GetCastTime();
3634  return 0;
3635 }
3636 
3638 {
3640  if (spell->getState() != SPELL_STATE_FINISHED)
3641  return spell->m_spellInfo->AttributesEx5 & SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING && spell->IsChannelActive();
3642 
3643  return false;
3644 }
3645 
3646 bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
3647 {
3648  return IsWithinDistInMap(target, distance) && HasInArc(arc, target);
3649 }
3650 
3651 bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const
3652 {
3653  return IsWithinDistInMap(target, distance) && !HasInArc(2 * M_PI - arc, target);
3654 }
3655 
3656 void Unit::SetFacingTo(float ori)
3657 {
3658  Movement::MoveSplineInit init(*this);
3659  init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ(), false);
3660  init.SetFacing(ori);
3661  init.Launch();
3662 }
3663 
3665 {
3666  // never face when already moving
3667  if (!IsStopped())
3668  return;
3669 
3671  Movement::MoveSplineInit init(*this);
3673  init.SetFacing(GetAngle(pObject)); // when on transport, GetAngle will still return global coordinates (and angle) that needs transforming
3674  init.Launch();
3675 }
3676 
3678 {
3679  if (IsInWater())
3680  return c->CanSwim();
3681  else
3682  return c->CanWalk() || c->CanFly();
3683 }
3684 
3685 bool Unit::IsInWater() const
3686 {
3688 }
3689 
3691 {
3693 }
3694 
3696 {
3698 }
3699 
3701 {
3702  int32 modifier = 0;
3703 
3704  AuraList const& mTotalAuraList = GetAurasByType(auratype);
3705  for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
3706  modifier += (*i)->GetModifierValue();
3707 
3708  return modifier;
3709 }
3710 
3712 {
3713  float multiplier = 1.0f;
3714 
3715  AuraList const& mTotalAuraList = GetAurasByType(auratype);
3716  for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
3717  multiplier *= (100.0f + (*i)->GetModifierValue()) / 100.0f;
3718 
3719  return multiplier;
3720 }
3721 
3723 {
3724  int32 modifier = 0;
3725 
3726  AuraList const& mTotalAuraList = GetAurasByType(auratype);
3727  for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
3728  {
3729  int32 amount = (*i)->GetModifierValue();
3730  if (amount > modifier)
3731  modifier = amount;
3732  }
3733 
3734  return modifier;
3735 }
3736 
3738 {
3739  int32 modifier = 0;
3740 
3741  AuraList const& mTotalAuraList = GetAurasByType(auratype);
3742  for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
3743  {
3744  int32 amount = (*i)->GetModifierValue();
3745  if (amount < modifier)
3746  modifier = amount;
3747  }
3748 
3749  return modifier;
3750 }
3751 
3753 {
3754  int32 modifier = 0;
3755 
3756  AuraList const& mTotalAuraList = GetAurasByType(auratype);
3757  for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
3758  {
3759  Modifier* mod = (*i)->GetModifier();
3760  if ((mod->m_miscvalue & misc_mask) != 0)
3761  modifier += (*i)->GetModifierValue();
3762  }
3763  return modifier;
3764 }
3765 
3767 {
3768  float multiplier = 1.0f;
3769 
3770  AuraList const& mTotalAuraList = GetAurasByType(auratype);
3771  for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
3772  {
3773  Modifier* mod = (*i)->GetModifier();
3774  if (mod->m_miscvalue & misc_mask)
3775  multiplier *= (100.0f + (*i)->GetModifierValue()) / 100.0f;
3776  }
3777  return multiplier;
3778 }
3779 
3781 {
3782  int32 modifier = 0;
3783 
3784  AuraList const& mTotalAuraList = GetAurasByType(auratype);
3785  for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
3786  {
3787  Modifier* mod = (*i)->GetModifier();
3788  int32 amount = (*i)->GetModifierValue();
3789  if (mod->m_miscvalue & misc_mask && amount > modifier)
3790  modifier = amount;
3791  }
3792 
3793  return modifier;
3794 }
3795 
3797 {
3798  int32 modifier = 0;
3799 
3800  AuraList const& mTotalAuraList = GetAurasByType(auratype);
3801  for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
3802  {
3803  Modifier* mod = (*i)->GetModifier();
3804  int32 amount = (*i)->GetModifierValue();
3805  if (mod->m_miscvalue & misc_mask && amount < modifier)
3806  modifier = amount;
3807  }
3808 
3809  return modifier;
3810 }
3811 
3813 {
3814  int32 modifier = 0;
3815 
3816  AuraList const& mTotalAuraList = GetAurasByType(auratype);
3817  for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
3818  {
3819  Modifier* mod = (*i)->GetModifier();
3820  if (mod->m_miscvalue == misc_value)
3821  modifier += (*i)->GetModifierValue();
3822  }
3823  return modifier;
3824 }
3825 
3826 float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype, int32 misc_value) const
3827 {
3828  float multiplier = 1.0f;
3829 
3830  AuraList const& mTotalAuraList = GetAurasByType(auratype);
3831  for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
3832  {
3833  Modifier* mod = (*i)->GetModifier();
3834  if (mod->m_miscvalue == misc_value)
3835  multiplier *= (100.0f + (*i)->GetModifierValue()) / 100.0f;
3836  }
3837  return multiplier;
3838 }
3839 
3841 {
3842  int32 modifier = 0;
3843 
3844  AuraList const& mTotalAuraList = GetAurasByType(auratype);
3845  for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
3846  {
3847  Modifier* mod = (*i)->GetModifier();
3848  int32 amount = (*i)->GetModifierValue();
3849  if (mod->m_miscvalue == misc_value && amount > modifier)
3850  modifier = amount;
3851  }
3852 
3853  return modifier;
3854 }
3855 
3857 {
3858  int32 modifier = 0;
3859 
3860  AuraList const& mTotalAuraList = GetAurasByType(auratype);
3861  for (AuraList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
3862  {
3863  Modifier* mod = (*i)->GetModifier();
3864  int32 amount = (*i)->GetModifierValue();
3865  if (mod->m_miscvalue == misc_value && amount < modifier)
3866  modifier = amount;
3867  }
3868 
3869  return modifier;
3870 }
3871 
3873 {
3874  // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
3875  if (!IsAlive() && Aur->GetId() != 20584 && Aur->GetId() != 8326 && Aur->GetId() != 2584 &&
3877  {
3878  delete Aur;
3879  return false;
3880  }
3881 
3882  if (Aur->GetTarget() != this)
3883  {
3884  sLog.outError("Aura (spell %u eff %u) add to aura list of %s (lowguid: %u) but Aura target is %s (lowguid: %u)",
3885  Aur->GetId(), Aur->GetEffIndex(), (GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), GetGUIDLow(),
3886  (Aur->GetTarget()->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), Aur->GetTarget()->GetGUIDLow());
3887  delete Aur;
3888  return false;
3889  }
3890 
3891  SpellEntry const* aurSpellInfo = Aur->GetSpellProto();
3892 
3893  spellEffectPair spair = spellEffectPair(Aur->GetId(), Aur->GetEffIndex());
3894  bool stackModified = false;
3895 
3896  // Handle aura stacking down below...
3897  if (!Aur->IsPassive() && !Aur->IsPersistent())
3898  {
3899  for (AuraMap::iterator i2 = m_Auras.lower_bound(spair); i2 != m_Auras.upper_bound(spair);)
3900  {
3901  Aura* aur2 = i2->second;
3902 
3903  if (aur2 && !stackModified)
3904  {
3905  ASSERT(aur2->GetId() == Aur->GetId());
3906 
3907  // @todo: fix this hack
3908  // Allow mongoose proc from different weapons... this should be corrected to allow multiple
3909  // auras triggered by different enchanted items this is not possible currently since we only have
3910  // GUID and not even information if the Aura was "triggered" see m_IsTriggeredSpell in Spell.h
3911  if (Aur->GetCastItemGUID() && Aur->GetId() == 28093)
3912  {
3913  bool allow = true;
3914 
3915  for (AuraMap::const_iterator i3 = m_Auras.lower_bound(spair); i3 != m_Auras.upper_bound(spair); i3++)
3916  if (i3->second->GetCastItemGUID() == Aur->GetCastItemGUID())
3917  allow = false;
3918 
3919  if (allow)
3920  break;
3921  }
3922 
3923  if (sSpellMgr.IsNoStackSpellDueToSpell(Aur->GetId(), aur2->GetId(), Aur->GetCasterGUID() == aur2->GetCasterGUID()))
3924  {
3925  // Non stackable and capped auras do not allow stacking
3926  if (!(aurSpellInfo->StackAmount && uint32(aur2->GetStackAmount()) < aurSpellInfo->StackAmount))
3927  {
3928  // Do not let the stack size exceed the maximum stack limit
3929  // Instead of adding a new stack, just set the duration time
3930  // we need to use time from Aur because of diminishing effects
3931  aur2->SetAuraDuration(Aur->GetAuraMaxDuration());
3932  aur2->SetAuraProcCharges(Aur->m_procCharges);
3933  aur2->UpdateAuraDuration();
3934  aur2->UpdateAuraCharges();
3935  *aur2->GetModifier() = *Aur->GetModifier();
3936  delete Aur;
3937  return true;
3938  }
3939 
3940  // Increment aura's stack, one stack per one call
3941  Aur->SetStackAmount(aur2->GetStackAmount() + 1);
3942  stackModified = true;
3943 
3944  // Existing aura will be replaced with the newly created one
3946  i2 = m_Auras.lower_bound(spair);
3947  continue;
3948  }
3949  }
3950 
3951  ++i2;
3952  }
3953  }
3954 
3955  // passive auras stack with all (except passive spell proc auras)
3956  if ((!Aur->IsPassive() || !IsPassiveStackableSpell(Aur->GetId())) &&
3957  !(Aur->GetId() == 20584 || Aur->GetId() == 8326))
3958  {
3959  if (!RemoveNoStackAurasDueToAura(Aur))
3960  {
3961  delete Aur;
3962  return false; // couldn't remove conflicting aura with higher rank
3963  }
3964  }
3965 
3966  // update single target auras list (before aura add to aura list, to prevent unexpected remove recently added aura)
3967  if (Aur->IsSingleTarget() && Aur->GetTarget())
3968  {
3969  // caster pointer can be deleted in time aura remove, find it by guid at each iteration
3970  for (;;)
3971  {
3972  Unit* caster = Aur->GetCaster();
3973  if (!caster) // caster deleted and not required adding scAura
3974  break;
3975 
3976  bool restart = false;
3977  AuraList& scAuras = caster->GetSingleCastAuras();
3978  for (AuraList::iterator itr = scAuras.begin(); itr != scAuras.end(); ++itr)
3979  {
3980  if ((*itr)->GetTarget() != Aur->GetTarget() &&
3981  IsSingleTargetSpells((*itr)->GetSpellProto(), aurSpellInfo))
3982  {
3983  if ((*itr)->IsInUse())
3984  {
3985  sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for IsSingleTargetSpell", (*itr)->GetId(), (*itr)->GetEffIndex(), Aur->GetId(), Aur->GetEffIndex());
3986  continue;
3987  }
3988  (*itr)->GetTarget()->RemoveAura((*itr)->GetId(), (*itr)->GetEffIndex());
3989  restart = true;
3990  break;
3991  }
3992  }
3993 
3994  if (!restart)
3995  {
3996  // done
3997  scAuras.push_back(Aur);
3998  break;
3999  }
4000  }
4001  }
4002 
4003  // add aura, register in lists and arrays
4004  Aur->_AddAura();
4005  m_Auras.insert(AuraMap::value_type(spellEffectPair(Aur->GetId(), Aur->GetEffIndex()), Aur));
4006  if (Aur->GetModifier()->m_auraname < TOTAL_AURAS)
4007  {
4008  m_modAuras[Aur->GetModifier()->m_auraname].push_back(Aur);
4009  if (Aur->GetSpellProto()->AuraInterruptFlags)
4010  {
4011  m_interruptableAuras.push_back(Aur);
4013  }
4015  && (Aur->GetModifier()->m_auraname != SPELL_AURA_MOD_POSSESS)) //only dummy aura is breakable
4016  m_ccAuras.push_back(Aur);
4017  }
4018 
4019  Aur->ApplyModifier(true, true);
4020 
4021  uint32 id = Aur->GetId();
4022  if (sSpellMgr.GetSpellCustomAttr(id) & SPELL_ATTR_CU_LINK_AURA)
4023  {
4024  if (const std::vector<int32>* spell_triggered = sSpellMgr.GetSpellLinked(id + SPELL_LINK_AURA))
4025  {
4026  for (std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr)
4027  if (*itr < 0)
4028  ApplySpellImmune(id, IMMUNITY_ID, -(*itr), true);
4029  else if (Unit* caster = Aur->GetCaster())
4030  caster->AddAura(*itr, this);
4031  }
4032  }
4033 
4034  DEBUG_LOG("Aura %u now is in use", Aur->GetModifier()->m_auraname);
4035  return true;
4036 }
4037 
4039 {
4040  SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId);
4041  if (!spellInfo)
4042  return;
4043  AuraMap::iterator i, next;
4044  for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
4045  {
4046  next = i;
4047  ++next;
4048  uint32 i_spellId = (*i).second->GetId();
4049  if ((*i).second && i_spellId && i_spellId != spellId)
4050  {
4051  if (sSpellMgr.IsRankSpellDueToSpell(spellInfo, i_spellId))
4052  {
4053  RemoveAurasDueToSpell(i_spellId);
4054 
4055  if (m_Auras.empty())
4056  break;
4057  else
4058  next = m_Auras.begin();
4059  }
4060  }
4061  }
4062 }
4063 
4065 {
4066  if (!Aur) return false;
4067 
4068  SpellEntry const* spellProto = Aur->GetSpellProto();
4069  if (!spellProto) return false;
4070 
4071  uint32 spellId = Aur->GetId();
4072  uint32 effIndex = Aur->GetEffIndex();
4073 
4074  AuraMap::iterator i, next;
4075  for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
4076  {
4077  next = i;
4078  ++next;
4079  if (!(*i).second) continue;
4080 
4081  SpellEntry const* i_spellProto = (*i).second->GetSpellProto();
4082  if (!i_spellProto) continue;
4083 
4084  uint32 i_spellId = i_spellProto->Id;
4085 
4086  if (spellId == i_spellId)
4087  continue;
4088 
4089  if (IsPassiveSpell(i_spellId))
4090  {
4091  // passive non-stackable spells not stackable only with another rank of same spell
4092  if (IsPassiveStackableSpell(i_spellId) || !sSpellMgr.IsRankSpellDueToSpell(spellProto, i_spellId))
4093  continue;
4094  }
4095  uint32 i_effIndex = (*i).second->GetEffIndex();
4096 
4097  bool is_triggered_by_spell = false;
4098  // prevent triggered aura of removing aura that triggered it
4099  for (int j = 0; j < MAX_SPELL_EFFECTS; ++j)
4100  {
4101  if (i_spellProto->EffectTriggerSpell[j] == spellProto->Id)
4102  {
4103  is_triggered_by_spell = true;
4104  break;
4105  }
4106  }
4107  if (is_triggered_by_spell) continue;
4108 
4109  for (int j = 0; j < MAX_SPELL_EFFECTS; ++j)
4110  {
4111  // prevent remove dummy triggered spells at next effect aura add
4112  if (spellProto->Effect[j] == SPELL_EFFECT_DUMMY && spellId == 5420 && i_spellId == 34123)
4113  is_triggered_by_spell = true;
4114 
4115  // main aura added before triggered spell
4116  // prevent remove form main spell by triggered passive spells
4117  else if (i_spellProto->EffectApplyAuraName[j] == SPELL_AURA_MOD_SHAPESHIFT)
4118  {
4119  if ((i_spellId == 24858 && spellId == 24905) || (i_spellId == 34551 && spellId == 22688))
4120  is_triggered_by_spell = true;
4121 
4122  else if (i_spellId == 33891 && (spellId == 5420 || spellId == 34123))
4123  is_triggered_by_spell = true;
4124  }
4125  else continue;
4126  break;
4127  }
4128 
4129  if (!is_triggered_by_spell)
4130  {
4131  bool sameCaster = Aur->GetCasterGUID() == (*i).second->GetCasterGUID();
4132 
4133  if (!sSpellMgr.IsNoStackSpellDueToSpell(spellId, i_spellId, sameCaster))
4134  continue;
4135 
4136  int32 aur1Rank = Aur->GetModifierValue();
4137  int32 aur2Rank = (*i).second->GetModifierValue();
4138  // Check if effect is "better"
4139  if (!sameCaster && (abs(aur1Rank)-abs(aur2Rank)) < 0)
4140  return false;
4141  // Some spells should be not removed by lower rank of them (totem, paladin aura)
4142  if (!sameCaster && spellProto->DurationIndex == 21 && sSpellMgr.IsRankSpellDueToSpell(spellProto, i_spellId))
4143  if (spellProto->Effect[effIndex] == SPELL_EFFECT_APPLY_AREA_AURA_PARTY)
4144  if (CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
4145  return false;
4146 
4147  // Its a parent aura (create this aura in ApplyModifier)
4148  if ((*i).second->IsInUse())
4149  {
4150  sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i->second->GetId(), i->second->GetEffIndex(), Aur->GetId(), Aur->GetEffIndex());
4151  continue;
4152  }
4153  uint64 caster = (*i).second->GetCasterGUID();
4154  // Remove all auras by aura caster
4155  for (uint8 a = 0; a < MAX_SPELL_EFFECTS; ++a)
4156  {
4157  spellEffectPair spair = spellEffectPair(i_spellId, a);
4158  for (AuraMap::iterator iter = m_Auras.lower_bound(spair); iter != m_Auras.upper_bound(spair);)
4159  {
4160  if (iter->second->GetCasterGUID() == caster)
4161  {
4163  iter = m_Auras.lower_bound(spair);
4164  }
4165  else ++iter;
4166  }
4167  }
4168  if (m_Auras.empty()) break;
4169  else next = m_Auras.begin();
4170  }
4171  }
4172  return true;
4173 }
4174 
4175 void Unit::RemoveAura(uint32 spellId, uint32 effindex, Aura* except)
4176 {
4177  spellEffectPair spair = spellEffectPair(spellId, effindex);
4178  for (AuraMap::iterator iter = m_Auras.lower_bound(spair); iter != m_Auras.upper_bound(spair);)
4179  {
4180  if (iter->second != except)
4181  {
4182  RemoveAura(iter);
4183  iter = m_Auras.lower_bound(spair);
4184  }
4185  else
4186  ++iter;
4187  }
4188 }
4189 
4191 {
4192  for (int k = 0; k < MAX_SPELL_EFFECTS; ++k)
4193  {
4194  spellEffectPair spair = spellEffectPair(spellId, k);
4195  for (AuraMap::iterator iter = m_Auras.lower_bound(spair); iter != m_Auras.upper_bound(spair);)
4196  {
4197  if (iter->second->GetCasterGUID() == casterGUID)
4198  {
4199  RemoveAura(iter);
4200  iter = m_Auras.upper_bound(spair); // overwrite by more appropriate
4201  }
4202  else
4203  ++iter;
4204  }
4205  }
4206 }
4207 
4208 void Unit::SetAurasDurationByCasterSpell(uint32 spellId, uint64 casterGUID, int32 duration)
4209 {
4210  for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
4211  {
4212  spellEffectPair spair = spellEffectPair(spellId, i);
4213  for (AuraMap::const_iterator itr = GetAuras().lower_bound(spair); itr != GetAuras().upper_bound(spair); ++itr)
4214  {
4215  if (itr->second->GetCasterGUID() == casterGUID)
4216  {
4217  itr->second->SetAuraDuration(duration);
4218  break;
4219  }
4220  }
4221  }
4222 }
4223 
4225 {
4226  // Returns first found aura from spell-use only in cases where effindex of spell doesn't matter!
4227  for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
4228  {
4229  spellEffectPair spair = spellEffectPair(spellId, i);
4230  for (AuraMap::const_iterator itr = GetAuras().lower_bound(spair); itr != GetAuras().upper_bound(spair); ++itr)
4231  {
4232  if (itr->second->GetCasterGUID() == casterGUID)
4233  return itr->second;
4234  }
4235  }
4236  return NULL;
4237 }
4238 
4239 void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint64 casterGUID, Unit* dispeler)
4240 {
4241  for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
4242  {
4243  Aura* aur = iter->second;
4244  if (aur->GetId() == spellId && aur->GetCasterGUID() == casterGUID)
4245  {
4246  // Custom dispel case
4247  // Unstable Affliction
4248  if (aur->GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (aur->GetSpellProto()->SpellFamilyFlags & 0x010000000000LL))
4249  {
4250  int32 damage = aur->GetModifier()->m_amount * 9;
4251  uint64 caster_guid = aur->GetCasterGUID();
4252 
4253  // Remove aura
4255 
4256  // backfire damage and silence
4257  dispeler->CastCustomSpell(dispeler, 31117, &damage, NULL, NULL, true, NULL, NULL, caster_guid);
4258 
4259  iter = m_Auras.begin(); // iterator can be invalidate at cast if self-dispel
4260  }
4261  else
4263  }
4264  else
4265  ++iter;
4266  }
4267 }
4268 
4269 void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit* stealer)
4270 {
4271  for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
4272  {
4273  Aura* aur = iter->second;
4274  if (aur->GetId() == spellId && aur->GetCasterGUID() == casterGUID)
4275  {
4276  //int32 basePoints = aur->GetBasePoints();
4277  // construct the new aura for the attacker
4278  Aura* new_aur = CreateAura(aur->GetSpellProto(), aur->GetEffIndex(), NULL/*&basePoints*/, stealer);
4279  if (!new_aur)
4280  continue;
4281 
4282  // set its duration and maximum duration
4283  // max duration 2 minutes (in msecs)
4284  int32 dur = aur->GetAuraDuration();
4285  const int32 max_dur = 2 * MINUTE * IN_MILLISECONDS;
4286  new_aur->SetAuraMaxDuration(max_dur > dur ? dur : max_dur);
4287  new_aur->SetAuraDuration(max_dur > dur ? dur : max_dur);
4288  new_aur->SetAuraProcCharges(aur->m_procCharges);
4289 
4290  // Unregister _before_ adding to stealer
4291  aur->UnregisterSingleCastAura();
4292  // strange but intended behaviour: Stolen single target auras won't be treated as single targeted
4293  new_aur->SetIsSingleTarget(false);
4294  // add the new aura to stealer
4295  stealer->AddAura(new_aur);
4296  // Remove aura as dispel
4297  if (aur->GetStackAmount() > 1)
4298  {
4299  // reapply modifier with reduced stack amount
4300  aur->ApplyModifier(false, true);
4301  aur->SetStackAmount(aur->GetStackAmount() - 1);
4302  aur->ApplyModifier(true, true);
4303 
4305  ++iter;
4306  }
4307  else
4309  }
4310  else
4311  ++iter;
4312  }
4313 }
4314 
4316 {
4317  for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
4318  {
4319  if (iter->second->GetId() == spellId)
4321  else
4322  ++iter;
4323  }
4324 }
4325 
4327 {
4328  for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
4329  {
4330  SpellEntry const* spell = iter->second->GetSpellProto();
4331  if (spell->Attributes & flags)
4332  RemoveAura(iter);
4333  else
4334  ++iter;
4335  }
4336 }
4337 
4339 {
4340  // Create dispel mask by dispel type
4341  uint32 dispelMask = GetDispelMask(type);
4342  // Dispel all existing auras vs current dispel type
4343  AuraMap& auras = GetAuras();
4344  for (AuraMap::iterator itr = auras.begin(); itr != auras.end();)
4345  {
4346  SpellEntry const* spell = itr->second->GetSpellProto();
4347  if ((1 << spell->Dispel) & dispelMask && !itr->second->IsInUse())
4348  {
4349  // Dispel aura
4350  RemoveAurasDueToSpell(spell->Id);
4351  itr = auras.begin();
4352  }
4353  else
4354  ++itr;
4355  }
4356 }
4357 
4359 {
4360  for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
4361  {
4362  Aura* aur = iter->second;
4363  if (aur->GetId() == spellId)
4364  {
4365  if (iter->second->GetStackAmount() > 1)
4366  {
4367  // reapply modifier with reduced stack amount
4368  iter->second->ApplyModifier(false, true);
4369  iter->second->SetStackAmount(iter->second->GetStackAmount() - 1);
4370  iter->second->ApplyModifier(true, true);
4371 
4372  iter->second->UpdateSlotCounterAndDuration();
4373  return; // not remove aura if stack amount > 1
4374  }
4375  else
4377  }
4378  else
4379  ++iter;
4380  }
4381 }
4382 
4384 {
4385  AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
4386  if (iter != m_Auras.end())
4387  {
4388  if (iter->second->GetStackAmount() > 1)
4389  {
4390  // reapply modifier with reduced stack amount
4391  iter->second->ApplyModifier(false, true);
4392  iter->second->SetStackAmount(iter->second->GetStackAmount() - 1);
4393  iter->second->ApplyModifier(true, true);
4394 
4395  iter->second->UpdateSlotCounterAndDuration();
4396  return; // not remove aura if stack amount > 1
4397  }
4398  RemoveAura(iter);
4399  }
4400 }
4401 
4403 {
4404  for (int i = 0; i < MAX_SPELL_EFFECTS; ++i)
4405  RemoveAura(spellId, i, except);
4406 }
4407 
4409 {
4410  for (int k = 0; k < MAX_SPELL_EFFECTS; ++k)
4411  {
4412  spellEffectPair spair = spellEffectPair(spellId, k);
4413  for (AuraMap::iterator iter = m_Auras.lower_bound(spair); iter != m_Auras.upper_bound(spair);)
4414  {
4415  if (iter->second->GetCastItemGUID() == castItem->GetGUID())
4416  {
4417  RemoveAura(iter);
4418  iter = m_Auras.upper_bound(spair); // overwrite by more appropriate
4419  }
4420  else
4421  ++iter;
4422  }
4423  }
4424 }
4425 
4426 void Unit::RemoveAurasByType(AuraType auraType, uint64 casterGUID, Aura* except, bool negative, bool positive)
4427 {
4428  if (auraType >= TOTAL_AURAS)
4429  return;
4430 
4431  for (AuraList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
4432  {
4433  Aura* aura = *iter;
4434 
4435  ++iter;
4436  if (aura != except && (!casterGUID || aura->GetCasterGUID() == casterGUID)
4437  && ((negative && !aura->IsPositive()) || (positive && aura->IsPositive())))
4438  {
4439  uint32 removedAuras = m_removedAurasCount;
4440  RemoveAurasDueToSpell(aura->GetId());
4441  if (m_removedAurasCount > removedAuras + 1)
4442  iter = m_modAuras[auraType].begin();
4443  }
4444  }
4445 }
4446 
4448 {
4449  // single target auras from other casters
4450  for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
4451  {
4452  if (iter->second->GetCasterGUID() != GetGUID() && IsSingleTargetSpell(iter->second->GetSpellProto()))
4453  RemoveAura(iter);
4454  else
4455  ++iter;
4456  }
4457 
4458  // single target auras at other targets
4459  AuraList& scAuras = GetSingleCastAuras();
4460  for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();)
4461  {
4462  Aura* aur = *iter;
4463  ++iter;
4464  if (aur->GetTarget() != this)
4465  {
4466  uint32 removedAuras = m_removedAurasCount;
4467  aur->GetTarget()->RemoveAura(aur->GetId(), aur->GetEffIndex());
4468  if (m_removedAurasCount > removedAuras + 1)
4469  iter = scAuras.begin();
4470  }
4471  }
4472 
4473 }
4474 
4475 void Unit::RemoveAura(AuraMap::iterator& i, AuraRemoveMode mode)
4476 {
4477  Aura* Aur = i->second;
4478 
4479  // if unit currently update aura list then make safe update iterator shift to next
4480  if (m_AurasUpdateIterator == i)
4482 
4483  // some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura
4484  // remove aura from list before to prevent deleting it before
4485  m_Auras.erase(i);
4487 
4488  SpellEntry const* AurSpellInfo = Aur->GetSpellProto();
4489  Unit* caster = NULL;
4490  Aur->UnregisterSingleCastAura();
4491 
4492  // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
4493  if (Aur->GetModifier()->m_auraname < TOTAL_AURAS)
4494  {
4495  m_modAuras[Aur->GetModifier()->m_auraname].remove(Aur);
4496 
4497  if (Aur->GetSpellProto()->AuraInterruptFlags)
4498  {
4499  m_interruptableAuras.remove(Aur);
4501  }
4502 
4504  && (Aur->GetModifier()->m_auraname != SPELL_AURA_MOD_POSSESS)) //only dummy aura is breakable
4505  m_ccAuras.remove(Aur);
4506  }
4507 
4508  // Set remove mode
4509  Aur->SetRemoveMode(mode);
4510 
4511  // Statue unsummoned at aura remove
4512  //Totem* statue = NULL;
4513  if (Aur->GetAuraDuration() && !Aur->IsPersistent() && IsChanneledSpell(AurSpellInfo))
4514  {
4515  if (!caster) // can be already located for IsSingleTargetSpell case
4516  caster = Aur->GetCaster();
4517 
4518  if (caster && caster->IsAlive())
4519  {
4520  // stop caster chanelling state
4522  //prevent recurential call
4524  {
4525  if (caster == this || !IsAreaOfEffectSpell(AurSpellInfo))
4526  {
4527  // remove auras only for non-aoe spells or when chanelled aura is removed
4528  // because aoe spells don't require aura on target to continue
4529  if (AurSpellInfo->EffectApplyAuraName[Aur->GetEffIndex()] != SPELL_AURA_PERIODIC_DUMMY
4530  && AurSpellInfo->EffectApplyAuraName[Aur->GetEffIndex()] != SPELL_AURA_DUMMY)
4531  //don't stop channeling of scripted spells (this is actually a hack)
4532  {
4534  caster->m_currentSpells[CURRENT_CHANNELED_SPELL] = NULL;
4535 
4536  }
4537  }
4538 
4539  //if (caster->GetTypeId() == TYPEID_UNIT && caster->IsTotem() && ((Totem*)caster)->GetTotemType() == TOTEM_STATUE)
4540  // statue = ((Totem*)caster);
4541  }
4542 
4543  // Unsummon summon as possessed creatures on spell cancel
4544  if (caster->GetTypeId() == TYPEID_PLAYER)
4545  if (Unit* charm = caster->GetCharm())
4546  if (charm->GetTypeId() == TYPEID_UNIT
4547  && charm->ToCreature()->HasUnitTypeMask(UNIT_MASK_PUPPET)
4548  && charm->GetUInt32Value(UNIT_CREATED_BY_SPELL) == AurSpellInfo->Id)
4549  ((Puppet*)charm)->UnSummon();
4550  }
4551  }
4552 
4553  DEBUG_LOG("Aura %u (%u) now is remove mode %d", Aur->GetId(), Aur->GetModifier()->m_auraname, mode);
4554  ASSERT(!Aur->IsInUse());
4555  Aur->ApplyModifier(false, true);
4556 
4557  Aur->SetStackAmount(0);
4558 
4559  // set aura to be removed during unit::_updatespells
4560  m_removedAuras.push_back(Aur);
4561 
4562  Aur->_RemoveAura();
4563 
4564  bool stack = false;
4565  spellEffectPair spair = spellEffectPair(Aur->GetId(), Aur->GetEffIndex());
4566  for (AuraMap::const_iterator itr = GetAuras().lower_bound(spair); itr != GetAuras().upper_bound(spair); ++itr)
4567  {
4568  if (itr->second->GetCasterGUID() == GetGUID())
4569  stack = true;
4570  }
4571  if (!stack)
4572  {
4573  // Remove all triggered by aura spells vs unlimited duration
4574  Aur->CleanupTriggeredSpells();
4575 
4576  // Remove Linked Auras
4577  uint32 id = Aur->GetId();
4578  if (sSpellMgr.GetSpellCustomAttr(id) & SPELL_ATTR_CU_LINK_REMOVE)
4579  {
4580  if (const std::vector<int32>* spell_triggered = sSpellMgr.GetSpellLinked(-(int32)id))
4581  {
4582  for (std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr)
4583  if (*itr < 0)
4584  RemoveAurasDueToSpell(-(*itr));
4585  else if (Unit* caster = Aur->GetCaster())
4586  CastSpell(this, *itr, true, 0, 0, caster->GetGUID());
4587  }
4588  }
4589  if (sSpellMgr.GetSpellCustomAttr(id) & SPELL_ATTR_CU_LINK_AURA)
4590  {
4591  if (const std::vector<int32>* spell_triggered = sSpellMgr.GetSpellLinked(id + SPELL_LINK_AURA))
4592  {
4593  for (std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr)
4594  if (*itr < 0)
4595  ApplySpellImmune(id, IMMUNITY_ID, -(*itr), false);
4596  else
4597  RemoveAurasDueToSpell(*itr);
4598  }
4599  }
4600  }
4601 
4602  //if (statue)
4603  // statue->UnSummon();
4604 
4605  i = m_Auras.begin();
4606 }
4607 
4609 {
4610  while (!m_Auras.empty())
4611  {
4612  AuraMap::iterator iter = m_Auras.begin();
4613  RemoveAura(iter);
4614  }
4615 }
4616 
4618 {
4619  // in join, remove positive buffs, on end, remove negative
4620  // used to remove positive visible auras in arenas
4621  for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
4622  {
4623  Aura* aura = iter->second;
4624  if (!(aura->GetSpellProto()->AttributesEx4 & SPELL_ATTR4_STANCES) // don't remove stances, shadowform, pally/hunter auras
4625  && !aura->IsPassive() // don't remove passive auras
4626  && (aura->IsPositive() || !(aura->GetSpellProto()->AttributesEx3 & SPELL_ATTR3_DEATH_PERSISTENT))) // not negative death persistent auras
4627  RemoveAura(iter);
4628  else
4629  ++iter;
4630  }
4631 }
4632 
4634 {
4635  // used just after dieing to remove all visible auras
4636  // and disable the mods for the passive ones
4637  for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
4638  {
4639  if (!iter->second->IsPassive() && !iter->second->IsDeathPersistent())
4641  else
4642  ++iter;
4643  }
4644 }
4645 
4646 void Unit::DelayAura(uint32 spellId, uint32 effindex, int32 delaytime)
4647 {
4648  AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
4649  if (iter != m_Auras.end())
4650  {
4651  if (iter->second->GetAuraDuration() < delaytime)
4652  iter->second->SetAuraDuration(0);
4653  else
4654  iter->second->SetAuraDuration(iter->second->GetAuraDuration() - delaytime);
4655  iter->second->UpdateAuraDuration();
4656  DEBUG_LOG("Aura %u partially interrupted on unit %u, new duration: %u ms", iter->second->GetModifier()->m_auraname, GetGUIDLow(), iter->second->GetAuraDuration());
4657  }
4658 }
4659 
4661 {
4662  for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
4663  (*i).second->ApplyModifier(false);
4664 }
4665 
4667 {
4668  for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
4669  (*i).second->ApplyModifier(true);
4670 }
4671 
4672 Aura* Unit::GetAura(uint32 spellId, uint32 effindex)
4673 {
4674  AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
4675  if (iter != m_Auras.end())
4676  return iter->second;
4677  return NULL;
4678 }
4679 
4681 {
4682  m_dynObjGUIDs.push_back(dynObj->GetGUID());
4683 }
4684 
4686 {
4687  if (m_dynObjGUIDs.empty())
4688  return;
4689  for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
4690  {
4691  DynamicObject* dynObj = GetMap()->GetDynamicObject(*i);
4692  if (!dynObj) // may happen if a dynobj is removed when grid unload
4693  i = m_dynObjGUIDs.erase(i);
4694  else if (spellid == 0 || dynObj->GetSpellId() == spellid)
4695  {
4696  dynObj->Remove();
4697  i = m_dynObjGUIDs.erase(i);
4698  }
4699  else
4700  ++i;
4701  }
4702 }
4703 
4705 {
4706  while (!m_dynObjGUIDs.empty())
4707  {
4708  DynamicObject* dynObj = GetMap()->GetDynamicObject(*m_dynObjGUIDs.begin());
4709  if (dynObj)
4710  dynObj->Remove();
4711  m_dynObjGUIDs.erase(m_dynObjGUIDs.begin());
4712  }
4713 }
4714 
4716 {
4717  for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
4718  {
4719  DynamicObject* dynObj = GetMap()->GetDynamicObject(*i);
4720  if (!dynObj)
4721  {
4722  i = m_dynObjGUIDs.erase(i);
4723  continue;
4724  }
4725 
4726  if (dynObj->GetSpellId() == spellId && dynObj->GetEffIndex() == effIndex)
4727  return dynObj;
4728  ++i;
4729  }
4730  return NULL;
4731 }
4732 
4734 {
4735  for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
4736  {
4737  DynamicObject* dynObj = GetMap()->GetDynamicObject(*i);
4738  if (!dynObj)
4739  {
4740  i = m_dynObjGUIDs.erase(i);
4741  continue;
4742  }
4743 
4744  if (dynObj->GetSpellId() == spellId)
4745  return dynObj;
4746  ++i;
4747  }
4748  return NULL;
4749 }
4750 
4752 {
4753  if (!gameObj || gameObj->GetOwnerGUID() != 0)
4754  return;
4755 
4756  m_gameObj.push_back(gameObj);
4757  gameObj->SetOwnerGUID(GetGUID());
4758 }
4759 
4760 void Unit::RemoveGameObject(GameObject* gameObj, bool del)
4761 {
4762  if (!gameObj || gameObj->GetOwnerGUID() != GetGUID())
4763  return;
4764 
4765  gameObj->SetOwnerGUID(0);
4766 
4767  for (uint8 i = 0; i < 3; ++i)
4768  {
4769  if (m_ObjectSlot[i] == gameObj->GetGUID())
4770  {
4771  m_ObjectSlot[i] = 0;
4772  break;
4773  }
4774  }
4775 
4776  // GO created by some spell
4777  if (uint32 spellid = gameObj->GetSpellId())
4778  {
4779  RemoveAurasDueToSpell(spellid);
4780 
4781  if (GetTypeId() == TYPEID_PLAYER)
4782  {
4783  SpellEntry const* createBySpell = sSpellStore.LookupEntry(spellid);
4784  // Need activate spell use for owner
4785  if (createBySpell && createBySpell->Attributes & SPELL_ATTR0_DISABLED_WHILE_ACTIVE)
4786  // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
4787  ToPlayer()->SendCooldownEvent(createBySpell);
4788  }
4789  }
4790 
4791  m_gameObj.remove(gameObj);
4792 
4793  if (del)
4794  {
4795  gameObj->SetRespawnTime(0);
4796  gameObj->Delete();
4797  }
4798 }
4799 
4800 void Unit::RemoveGameObject(uint32 spellid, bool del)
4801 {
4802  if (m_gameObj.empty())
4803  return;
4804  std::list<GameObject*>::iterator i, next;
4805  for (i = m_gameObj.begin(); i != m_gameObj.end(); i = next)
4806  {
4807  next = i;
4808  if (spellid == 0 || (*i)->GetSpellId() == spellid)
4809  {
4810  (*i)->SetOwnerGUID(0);
4811  if (del)
4812  {
4813  (*i)->SetRespawnTime(0);
4814  (*i)->Delete();
4815  }
4816 
4817  next = m_gameObj.erase(i);
4818  }
4819  else
4820  ++next;
4821  }
4822 }
4823 
4825 {
4826  // remove references to unit
4827  for (std::list<GameObject*>::iterator i = m_gameObj.begin(); i != m_gameObj.end();)
4828  {
4829  (*i)->SetOwnerGUID(0);
4830  (*i)->SetRespawnTime(0);
4831  (*i)->Delete();
4832  i = m_gameObj.erase(i);
4833  }
4834 }
4835 
4837 {
4838  WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16 + 4 + 4 + 1 + 4 + 4 + 1 + 1 + 4 + 4 + 1)); // we guess size
4839  data << log->target->GetPackGUID();
4840  data << log->attacker->GetPackGUID();
4841  data << uint32(log->SpellID);
4842  data << uint32(log->damage); // damage amount
4843  data << uint8 (log->schoolMask); // damage school
4844  data << uint32(log->absorb); // AbsorbedDamage
4845  data << uint32(log->resist); // resist
4846  data << uint8 (log->physicalLog); // damsge type? flag
4847  data << uint8 (log->unused); // unused
4848  data << uint32(log->blocked); // blocked
4849  data << uint32(log->HitInfo);
4850  data << uint8 (0); // flag to use extend data
4851  SendMessageToSet(&data, true);
4852 }
4853 
4854 void Unit::SendSpellNonMeleeDamageLog(Unit* target, uint32 SpellID, uint32 Damage, SpellSchoolMask damageSchoolMask, uint32 AbsorbedDamage, uint32 Resist, bool PhysicalDamage, uint32 Blocked, bool CriticalHit)
4855 {
4856  DEBUG_LOG("Sending: SMSG_SPELLNONMELEEDAMAGELOG");
4857  WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16 + 4 + 4 + 1 + 4 + 4 + 1 + 1 + 4 + 4 + 1)); // we guess size
4858  data << target->GetPackGUID();
4859  data << GetPackGUID();
4860  data << uint32(SpellID);
4861  data << uint32(Damage - AbsorbedDamage - Resist - Blocked);
4862  data << uint8(damageSchoolMask); // spell school
4863  data << uint32(AbsorbedDamage); // AbsorbedDamage
4864  data << uint32(Resist); // resist
4865  data << uint8(PhysicalDamage); // 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
4866  data << uint8(0); // unk isFromAura
4867  data << uint32(Blocked); // blocked
4868  data << uint32(CriticalHit ? 0x27 : 0x25); // hitType, flags: 0x2 - SPELL_HIT_TYPE_CRIT, 0x10 - replace caster?
4869  data << uint8(0); // isDebug?
4870  SendMessageToSet(&data, true);
4871 }
4872 
4873 void Unit::ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellEntry const* procSpell, bool canTrigger)
4874 {
4875  // Proc all effects (auras/talents/whatever) on on victim first, then on caster
4876 
4877  // Now go on with a victim's events'n'auras
4878  // Not much to do if no flags are set or there is no victim
4879  if (victim && victim->IsAlive() && procVictim)
4880  victim->ProcDamageAndSpellFor(true, this, procVictim, procExtra, attType, procSpell, amount);
4881 
4882  // Not much to do if no flags are set.
4883  if (procAttacker && canTrigger)
4884  ProcDamageAndSpellFor(false, victim, procAttacker, procExtra, attType, procSpell, amount);
4885 }
4886 
4887 void Unit::SendSpellMiss(Unit* target, uint32 spellID, SpellMissInfo missInfo)
4888 {
4889  WorldPacket data(SMSG_SPELLLOGMISS, (4+8+1+4+8+1));
4890  data << uint32(spellID);
4891  data << uint64(GetGUID());
4892  data << uint8(0); // can be 0 or 1
4893  data << uint32(1); // target count
4894  // for (i = 0; i < target count; ++i)
4895  data << uint64(target->GetGUID()); // target GUID
4896  data << uint8(missInfo);
4897  // end loop
4898  SendMessageToSet(&data, true);
4899 }
4900 
4902 {
4903  WorldPacket data(SMSG_SPELLORDAMAGE_IMMUNE, 8 + 8 + 4 + 1);
4904  data << uint64(GetGUID());
4905  data << uint64(target->GetGUID());
4906  data << uint32(spellId);
4907  data << uint8(0); // bool - log format: 0-default, 1-debug
4908  SendMessageToSet(&data, true);
4909 }
4910 
4912 {
4913  WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16 + 84)); // we guess size
4914  data << (uint32)damageInfo->HitInfo;
4915  data << GetPackGUID();
4916  data << damageInfo->target->GetPackGUID();
4917  data << (uint32)(damageInfo->damage); // Full damage
4918 
4919  data << (uint8)1; // Sub damage count
4920  //=== Sub damage description
4921  data << (uint32)(damageInfo->damageSchoolMask); // School of sub damage
4922  data << (float)damageInfo->damage; // sub damage
4923  data << (uint32)damageInfo->damage; // Sub Damage
4924  data << (uint32)damageInfo->absorb; // Absorb
4925  data << (uint32)damageInfo->resist; // Resist
4926  //=================================================
4927  data << (uint32)damageInfo->TargetState;
4928  data << (uint32)0;
4929  data << (uint32)0;
4930  data << (uint32)damageInfo->blocked_amount;
4931  SendMessageToSet(&data, true);
4932 }
4933 
4934 void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 SwingType, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount)
4935 {
4936  DEBUG_LOG("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
4937 
4938  WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16 + 45)); // we guess size
4939  data << (uint32)HitInfo;
4940  data << GetPackGUID();
4941  data << target->GetPackGUID();
4942  data << (uint32)(Damage - AbsorbDamage - Resist - BlockedAmount);
4943 
4944  data << (uint8)SwingType; // count?
4945 
4946  // for (i = 0; i < SwingType; ++i)
4947  data << (uint32)damageSchoolMask;
4948  data << (float)(Damage - AbsorbDamage - Resist - BlockedAmount);
4949  // still need to double check damage
4950  data << (uint32)(Damage - AbsorbDamage - Resist - BlockedAmount);
4951  data << (uint32)AbsorbDamage;
4952  data << (uint32)Resist;
4953  // end loop
4954 
4955  data << (uint32)TargetState;
4956 
4957  if (AbsorbDamage == 0) //also 0x3E8 = 0x3E8, check when that happens
4958  data << (uint32)0;
4959  else
4960  data << (uint32) - 1;
4961 
4962  data << (uint32)0;
4963  data << (uint32)BlockedAmount;
4964 
4965  SendMessageToSet(&data, true);
4966 }
4967 
4968 bool Unit::HandleHasteAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellEntry const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
4969 {
4970  SpellEntry const* hasteSpell = triggeredByAura->GetSpellProto();
4971 
4972  Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
4973  ? ToPlayer()->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL;
4974 
4975  uint32 triggered_spell_id = 0;
4976  Unit* target = victim;
4977  int32 basepoints0 = 0;
4978 
4979  switch (hasteSpell->SpellFamilyName)
4980  {
4981  case SPELLFAMILY_ROGUE:
4982  {
4983  switch (hasteSpell->Id)
4984  {
4985  // Blade Flurry
4986  case 13877:
4987  case 33735:
4988  {
4989  target = SelectNearbyTarget(victim);
4990  if (!target || !target->IsHostileTo(target->GetVictim()))
4991  return false;
4992  basepoints0 = damage;
4993  triggered_spell_id = 22482;
4994  break;
4995  }
4996  }
4997  break;
4998  }
4999  }
5000 
5001  // processed charge only counting case
5002  if (!triggered_spell_id)
5003  return true;
5004 
5005  SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
5006 
5007  if (!tri