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