Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
UnitCombat.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "Battlefield.h"
7#include "BattlefieldMgr.h"
8#include "Battleground.h"
9#include "CellImpl.h"
10#include "Common.h"
11#include "ConditionMgr.h"
12#include "Creature.h"
13#include "CreatureAI.h"
14#include "CreatureAIImpl.h"
15#include "CreatureGroups.h"
16#include "Formulas.h"
17#include "GridNotifiersImpl.h"
18#include "Group.h"
19#include "InstanceSaveMgr.h"
20#include "InstanceScript.h"
21#include "Log.h"
22#include "MapManager.h"
23#include "MovementStructures.h"
24#include "MoveSpline.h"
25#include "ObjectAccessor.h"
26#include "ObjectMgr.h"
27#include "Opcodes.h"
28#include "OutdoorPvP.h"
29#include "PassiveAI.h"
30#include "Pet.h"
31#include "PetAI.h"
32#include "Player.h"
33#include "QuestDef.h"
34#include "ReputationMgr.h"
35#include "Spell.h"
36#include "SpellAuraEffects.h"
37#include "SpellAuras.h"
38#include "SpellInfo.h"
39#include "SpellMgr.h"
40#include "TemporarySummon.h"
41#include "Totem.h"
42#include "Transport.h"
43#include "Unit.h"
44#include "UpdateFieldFlags.h"
45#include "Util.h"
46#include "Vehicle.h"
47#include "World.h"
48#include "WorldPacket.h"
49#include "WorldSession.h"
50
51#include <math.h>
52
53void Unit::DealDamageMods(Unit* victim, uint32& damage, uint32* absorb)
54{
55 if (!victim || !victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TypeID::TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode()))
56 {
57 if (absorb)
58 *absorb += damage;
59 damage = 0;
60 }
61}
62
63uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss)
64{
65 if (victim->IsAIEnabled)
66 victim->GetAI()->DamageTaken(this, damage);
67
68 if (IsAIEnabled)
69 GetAI()->DamageDealt(victim, damage, damagetype);
70
71 // Hook for OnDamage Event
72 sScriptMgr->OnDamage(this, victim, damage);
73
74 if (victim->GetTypeId() == TypeID::TYPEID_PLAYER && this != victim)
75 {
76 // Signal to pets that their owner was attacked
77 Pet* pet = victim->ToPlayer()->GetPet();
78
79 if (pet && pet->IsAlive())
80 pet->AI()->OwnerAttackedBy(this);
81
82 if (victim->ToPlayer()->GetCommandStatus(CHEAT_GOD))
83 return 0;
84 }
85
86 // Signal the pet it was attacked so the AI can respond if needed
87 if (victim->GetTypeId() == TypeID::TYPEID_UNIT && this != victim && victim->IsPet() && victim->IsAlive())
88 victim->ToPet()->AI()->AttackedBy(this);
89
90 if (damagetype != NODAMAGE)
91 {
92 // interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras)
93 if (spellProto)
94 {
97 }
98 else
100
101 // We're going to call functions which can modify content of the list during iteration over it's elements
102 // Let's copy the list so we can prevent iterator invalidation
104 // copy damage to casters of this aura
105 for (AuraEffectList::iterator i = vCopyDamageCopy.begin(); i != vCopyDamageCopy.end(); ++i)
106 {
107 // Check if aura was removed during iteration - we don't need to work on such auras
108 if (!((*i)->GetBase()->IsAppliedOnTarget(victim->GetGUID())))
109 continue;
110 // check damage school mask
111 if (((*i)->GetMiscValue() & damageSchoolMask) == 0)
112 continue;
113
114 Unit* shareDamageTarget = (*i)->GetCaster();
115 if (!shareDamageTarget)
116 continue;
117 SpellInfo const* spell = (*i)->GetSpellInfo();
118
119 uint32 share = CalculatePct(damage, (*i)->GetAmount());
120
122 DealDamageMods(shareDamageTarget, share, NULL);
123 DealDamage(shareDamageTarget, share, NULL, NODAMAGE, spell->GetSchoolMask(), spell, false);
124 }
125 }
126
127 // Rage from Damage made (only from direct weapon damage)
128 if (cleanDamage && damagetype == DIRECT_DAMAGE && this != victim && getPowerType() == POWER_RAGE)
129 {
130 uint32 rage = uint32(GetAttackTime(cleanDamage->attackType) / 1000 * 8.125f);
131 switch (cleanDamage->attackType)
132 {
134 {
135 rage /= 2;
136 RewardRage(rage, true);
137 break;
138 }
140 {
141 RewardRage(rage, true);
142 break;
143 }
144 default:
145 break;
146 }
147 }
148
149 if (!damage)
150 {
151 // Rage from absorbed damage
152 if (cleanDamage && cleanDamage->absorbed_damage && victim->getPowerType() == POWER_RAGE)
153 victim->RewardRage(cleanDamage->absorbed_damage, false);
154
155 return 0;
156 }
157
158 SF_LOG_DEBUG("entities.unit", "DealDamageStart");
159
160 uint32 health = victim->GetHealth();
161 SF_LOG_DEBUG("entities.unit", "Unit " UI64FMTD " dealt %u damage to unit " UI64FMTD, GetGUID(), damage, victim->GetGUID());
162
163 // duel ends when player has 1 or less hp
164 bool duel_hasEnded = false;
165 bool duel_wasMounted = false;
166 if (victim->GetTypeId() == TypeID::TYPEID_PLAYER && victim->ToPlayer()->duel && damage >= (health - 1))
167 {
168 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
169 if (victim->ToPlayer()->duel->opponent == this || victim->ToPlayer()->duel->opponent->GetGUID() == GetOwnerGUID())
170 damage = health - 1;
171
172 duel_hasEnded = true;
173 }
174 else if (victim->IsVehicle() && damage >= (health - 1) && victim->GetCharmer() && victim->GetCharmer()->GetTypeId() == TypeID::TYPEID_PLAYER)
175 {
176 Player* victimRider = victim->GetCharmer()->ToPlayer();
177
178 if (victimRider && victimRider->duel && victimRider->duel->isMounted)
179 {
180 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
181 if (victimRider->duel->opponent == this || victimRider->duel->opponent->GetGUID() == GetCharmerGUID())
182 damage = health - 1;
183
184 duel_wasMounted = true;
185 duel_hasEnded = true;
186 }
187 }
188
189 if (GetTypeId() == TypeID::TYPEID_PLAYER && this != victim)
190 {
191 Player* killer = ToPlayer();
192
193 // in bg, count dmg if victim is also a player
194 if (victim->GetTypeId() == TypeID::TYPEID_PLAYER)
195 if (Battleground* bg = killer->GetBattleground())
196 bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damage);
197
200 }
201
202 if (victim->GetTypeId() == TypeID::TYPEID_PLAYER)
204 else if (!victim->IsControlledByPlayer() || victim->IsVehicle())
205 {
206 if (!victim->ToCreature()->hasLootRecipient())
207 victim->ToCreature()->SetLootRecipient(this);
208
210 victim->ToCreature()->LowerPlayerDamageReq(health < damage ? health : damage);
211 }
212
213 if (health <= damage)
214 {
215 SF_LOG_DEBUG("entities.unit", "DealDamage: victim just died");
216
217 if (victim->GetTypeId() == TypeID::TYPEID_PLAYER && victim != this)
219
220 Kill(victim, durabilityLoss);
221 }
222 else
223 {
224 SF_LOG_DEBUG("entities.unit", "DealDamageAlive");
225
226 if (victim->GetTypeId() == TypeID::TYPEID_PLAYER)
228
229 victim->ModifyHealth(-(int32)damage);
230
231 if (damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE)
232 {
233 victim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE, spellProto ? spellProto->Id : 0);
234 if (victim->GetTypeId() == TypeID::TYPEID_UNIT && !victim->IsPet())
235 victim->SetLastDamagedTime(time(NULL));
236 }
237
238 if (victim->GetTypeId() != TypeID::TYPEID_PLAYER)
239 victim->AddThreat(this, float(damage), damageSchoolMask, spellProto);
240 else // victim is a player
241 {
242 // random durability for items (HIT TAKEN)
244 {
245 EquipmentSlots slot = EquipmentSlots(std::rand() % (EQUIPMENT_SLOT_END - 1));
247 }
248 }
249
250 // Rage from damage received
251 if (this != victim && victim->getPowerType() == POWER_RAGE)
252 {
253 uint32 rage_damage = damage + (cleanDamage ? cleanDamage->absorbed_damage : 0);
254 victim->RewardRage(rage_damage, false);
255 }
256
258 {
259 // random durability for items (HIT DONE)
261 {
262 EquipmentSlots slot = EquipmentSlots(std::rand() % (EQUIPMENT_SLOT_END - 1));
264 }
265 }
266
267 if (damagetype != NODAMAGE && damage)
268 {
269 if (victim != this && victim->GetTypeId() == TypeID::TYPEID_PLAYER) // does not support creature push_back
270 {
271 if (damagetype != DOT)
272 if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
273 if (spell->getState() == SPELL_STATE_PREPARING)
274 {
275 uint32 interruptFlags = spell->m_spellInfo->InterruptFlags;
276 if (interruptFlags & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG)
277 victim->InterruptNonMeleeSpells(false);
278 else if (interruptFlags & SPELL_INTERRUPT_FLAG_PUSH_BACK)
279 spell->Delayed();
280 }
281
282 if (Spell* spell = victim->m_currentSpells[CURRENT_CHANNELED_SPELL])
283 if (spell->getState() == SPELL_STATE_CASTING)
284 {
285 uint32 channelInterruptFlags = spell->m_spellInfo->ChannelInterruptFlags;
286 if (((channelInterruptFlags & CHANNEL_FLAG_DELAY) != 0) && (damagetype != DOT))
287 spell->DelayedChannel();
288 }
289 }
290 }
291
292 // last damage from duel opponent
293 if (duel_hasEnded)
294 {
295 Player* he = duel_wasMounted ? victim->GetCharmer()->ToPlayer() : victim->ToPlayer();
296
297 ASSERT(he && he->duel);
298
299 if (duel_wasMounted) // In this case victim==mount
300 victim->SetHealth(1);
301 else
302 he->SetHealth(1);
303
304 he->duel->opponent->CombatStopWithPets(true);
305 he->CombatStopWithPets(true);
306
307 he->CastSpell(he, 7267, true); // beg
309 }
310 }
311
312 SF_LOG_DEBUG("entities.unit", "DealDamageEnd returned %d damage", damage);
313
314 return damage;
315}
316
317void Unit::CastStop(uint32 except_spellid)
318{
320 if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id != except_spellid)
322}
323
324void Unit::CastSpell(SpellCastTargets const& targets, SpellInfo const* spellInfo, CustomSpellValues const* value, TriggerCastFlags triggerFlags, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
325{
326 if (!spellInfo)
327 {
328 SF_LOG_ERROR("entities.unit", "CastSpell: unknown spell by caster: %s %u)", (GetTypeId() == TypeID::TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TypeID::TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
329 return;
330 }
331
333 if (!originalCaster && triggeredByAura)
334 originalCaster = triggeredByAura->GetCasterGUID();
335
336 Spell* spell = new Spell(this, spellInfo, triggerFlags, originalCaster);
337
338 if (value)
339 for (CustomSpellValues::const_iterator itr = value->begin(); itr != value->end(); ++itr)
340 spell->SetSpellValue(itr->first, itr->second);
341
342 spell->m_CastItem = castItem;
343 spell->prepare(&targets, triggeredByAura);
344}
345
346void Unit::CastSpell(Unit* victim, uint32 spellId, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
347{
348 CastSpell(victim, spellId, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE, castItem, triggeredByAura, originalCaster);
349}
350
351void Unit::CastSpell(Unit* victim, uint32 spellId, TriggerCastFlags triggerFlags /*= TRIGGER_NONE*/, Item* castItem /*= NULL*/, AuraEffect const* triggeredByAura /*= NULL*/, uint64 originalCaster /*= 0*/)
352{
353 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
354 if (!spellInfo)
355 {
356 SF_LOG_ERROR("entities.unit", "CastSpell: unknown spell id %u by caster: %s %u)", spellId, (GetTypeId() == TypeID::TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TypeID::TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
357 return;
358 }
359
360 CastSpell(victim, spellInfo, triggerFlags, castItem, triggeredByAura, originalCaster);
361}
362
363void Unit::CastSpell(Unit* victim, SpellInfo const* spellInfo, bool triggered, Item* castItem/*= NULL*/, AuraEffect const* triggeredByAura /*= NULL*/, uint64 originalCaster /*= 0*/)
364{
365 CastSpell(victim, spellInfo, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE, castItem, triggeredByAura, originalCaster);
366}
367
368void Unit::CastSpell(Unit* victim, SpellInfo const* spellInfo, TriggerCastFlags triggerFlags, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
369{
370 SpellCastTargets targets;
371 targets.SetUnitTarget(victim);
372 CastSpell(targets, spellInfo, NULL, triggerFlags, castItem, triggeredByAura, originalCaster);
373}
374
375void Unit::CastCustomSpell(Unit* target, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
376{
377 CustomSpellValues values;
378 if (bp0)
380 if (bp1)
382 if (bp2)
384 CastCustomSpell(spellId, values, target, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE, castItem, triggeredByAura, originalCaster);
385}
386
387void Unit::CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* target, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
388{
389 CustomSpellValues values;
390 values.AddSpellMod(mod, value);
391 CastCustomSpell(spellId, values, target, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE, castItem, triggeredByAura, originalCaster);
392}
393
394void Unit::CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* target, TriggerCastFlags triggerFlags, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
395{
396 CustomSpellValues values;
397 values.AddSpellMod(mod, value);
398 CastCustomSpell(spellId, values, target, triggerFlags, castItem, triggeredByAura, originalCaster);
399}
400
401void Unit::CastCustomSpell(uint32 spellId, CustomSpellValues const& value, Unit* victim, TriggerCastFlags triggerFlags, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
402{
403 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
404 if (!spellInfo)
405 {
406 SF_LOG_ERROR("entities.unit", "CastSpell: unknown spell id %u by caster: %s %u)", spellId, (GetTypeId() == TypeID::TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TypeID::TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
407 return;
408 }
409 SpellCastTargets targets;
410 targets.SetUnitTarget(victim);
411
412 CastSpell(targets, spellInfo, &value, triggerFlags, castItem, triggeredByAura, originalCaster);
413}
414
415void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
416{
417 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
418 if (!spellInfo)
419 {
420 SF_LOG_ERROR("entities.unit", "CastSpell: unknown spell id %u by caster: %s %u)", spellId, (GetTypeId() == TypeID::TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TypeID::TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
421 return;
422 }
423 SpellCastTargets targets;
424 targets.SetDst(x, y, z, GetOrientation());
425
426 CastSpell(targets, spellInfo, NULL, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE, castItem, triggeredByAura, originalCaster);
427}
428
429void Unit::CastSpell(GameObject* go, uint32 spellId, bool triggered, Item* castItem, AuraEffect* triggeredByAura, uint64 originalCaster)
430{
431 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
432 if (!spellInfo)
433 {
434 SF_LOG_ERROR("entities.unit", "CastSpell: unknown spell id %u by caster: %s %u)", spellId, (GetTypeId() == TypeID::TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TypeID::TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
435 return;
436 }
437 SpellCastTargets targets;
438 targets.SetGOTarget(go);
439
440 CastSpell(targets, spellInfo, NULL, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE, castItem, triggeredByAura, originalCaster);
441}
442
443// Obsolete func need remove, here only for comotability vs another patches
445{
446 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID);
447 SpellNonMeleeDamage damageInfo(this, victim, spellInfo->Id, spellInfo->SchoolMask);
448 damage = SpellDamageBonusDone(victim, spellInfo, damage, SPELL_DIRECT_DAMAGE);
449 damage = victim->SpellDamageBonusTaken(this, spellInfo, damage, SPELL_DIRECT_DAMAGE);
450
451 CalculateSpellDamageTaken(&damageInfo, damage, spellInfo);
452 DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
453 SendSpellNonMeleeDamageLog(&damageInfo);
454 DealSpellDamage(&damageInfo, true);
455 return damageInfo.damage;
456}
457
458void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType, bool crit)
459{
460 if (damage < 0)
461 return;
462
463 Unit* victim = damageInfo->target;
464 if (!victim || !victim->IsAlive())
465 return;
466
467 SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask);
468
469 if (IsDamageReducedByArmor(damageSchoolMask, spellInfo))
470 damage = CalcArmorReducedDamage(victim, damage, spellInfo, attackType);
471
472 bool blocked = false;
473 // Per-school calc
474 switch (spellInfo->DmgClass)
475 {
476 // Melee and Ranged Spells
479 {
480 // Physical Damage
481 if (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL)
482 {
483 // Get blocked status
484 blocked = isSpellBlocked(victim, spellInfo, attackType);
485 }
486
487 if (crit)
488 {
489 damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
490
491 // Calculate crit bonus
492 uint32 crit_bonus = damage;
493 // Apply crit_damage bonus for melee spells
494 if (Player* modOwner = GetSpellModOwner())
495 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
496 damage += crit_bonus;
497
498 // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
499 float critPctDamageMod = 0.0f;
500 if (attackType == WeaponAttackType::RANGED_ATTACK)
502 else
504
505 // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
506 critPctDamageMod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellInfo->GetSchoolMask()) - 1.0f) * 100;
507
508 if (critPctDamageMod != 0)
509 AddPct(damage, critPctDamageMod);
510 }
511
512 // Spell weapon based damage CAN BE crit & blocked at same time
513 if (blocked)
514 {
515 // double blocked amount if block is critical
516 uint32 value = victim->GetBlockPercent();
517 if (victim->isBlockCritical())
518 value *= 2; // double blocked percent
519 damageInfo->blocked = CalculatePct(damage, value);
520 damage -= damageInfo->blocked;
521 }
522
523 ApplyResilience(victim, &damage, crit);
524 break;
525 }
526 // Magical Attacks
529 {
530 // If crit add critical bonus
531 if (crit)
532 {
533 damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
534 damage = SpellCriticalDamageBonus(spellInfo, damage, victim);
535 }
536
537 ApplyResilience(victim, &damage, crit);
538 break;
539 }
540 default:
541 break;
542 }
543
544 // Script Hook For CalculateSpellDamageTaken -- Allow scripts to change the Damage post class mitigation calculations
545 sScriptMgr->ModifySpellDamageTaken(damageInfo->target, damageInfo->attacker, damage);
546
547 // Calculate absorb resist
548 if (damage > 0)
549 {
550 CalcAbsorbResist(victim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist, spellInfo);
551 damage -= damageInfo->absorb + damageInfo->resist;
552 }
553 else
554 damage = 0;
555
556 damageInfo->damage = damage;
557}
558
559void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss)
560{
561 if (damageInfo == 0)
562 return;
563
564 Unit* victim = damageInfo->target;
565
566 if (!victim)
567 return;
568
569 if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TypeID::TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode()))
570 return;
571
572 SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(damageInfo->SpellID);
573 if (spellProto == NULL)
574 {
575 SF_LOG_DEBUG("entities.unit", "Unit::DealSpellDamage has wrong damageInfo->SpellID: %u", damageInfo->SpellID);
576 return;
577 }
578
579 // Call default DealDamage
581 DealDamage(victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss);
582}
583
585void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType)
586{
587 damageInfo->attacker = this;
588 damageInfo->target = victim;
590 damageInfo->attackType = attackType;
591 damageInfo->damage = 0;
592 damageInfo->cleanDamage = 0;
593 damageInfo->absorb = 0;
594 damageInfo->resist = 0;
595 damageInfo->blocked_amount = 0;
596
598 damageInfo->HitInfo = 0;
599 damageInfo->procAttacker = PROC_FLAG_NONE;
600 damageInfo->procVictim = PROC_FLAG_NONE;
601 damageInfo->procEx = PROC_EX_NONE;
603
604 if (!victim)
605 return;
606
607 if (!IsAlive() || !victim->IsAlive())
608 return;
609
610 // Select HitInfo/procAttacker/procVictim flag based on attack type
611 switch (attackType)
612 {
616 break;
620 damageInfo->HitInfo = HITINFO_OFFHAND;
621 break;
622 default:
623 return;
624 }
625
626 // Physical Immune check
627 if (damageInfo->target->IsImmunedToDamage(SpellSchoolMask(damageInfo->damageSchoolMask)))
628 {
629 damageInfo->HitInfo |= HITINFO_NORMALSWING;
631
632 damageInfo->procEx |= PROC_EX_IMMUNE;
633 damageInfo->damage = 0;
634 damageInfo->cleanDamage = 0;
635 return;
636 }
637
638 damage += CalculateDamage(damageInfo->attackType, false, true);
639 // Add melee damage bonus
640 damage = MeleeDamageBonusDone(damageInfo->target, damage, damageInfo->attackType);
641 damage = damageInfo->target->MeleeDamageBonusTaken(this, damage, damageInfo->attackType);
642
643 // Script Hook For CalculateMeleeDamage -- Allow scripts to change the Damage pre class mitigation calculations
644 sScriptMgr->ModifyMeleeDamage(damageInfo->target, damageInfo->attacker, damage);
645
646 // Calculate armor reduction
648 {
649 damageInfo->damage = CalcArmorReducedDamage(damageInfo->target, damage, NULL, damageInfo->attackType);
650 damageInfo->cleanDamage += damage - damageInfo->damage;
651 }
652 else
653 damageInfo->damage = damage;
654
655 damageInfo->hitOutCome = RollMeleeOutcomeAgainst(damageInfo->target, damageInfo->attackType);
656
657 switch (damageInfo->hitOutCome)
658 {
662 damageInfo->procEx |= PROC_EX_EVADE;
663 damageInfo->damage = 0;
664 damageInfo->cleanDamage = 0;
665 return;
667 damageInfo->HitInfo |= HITINFO_MISS;
669 damageInfo->procEx |= PROC_EX_MISS;
670 damageInfo->damage = 0;
671 damageInfo->cleanDamage = 0;
672 break;
675 damageInfo->procEx |= PROC_EX_NORMAL_HIT;
676 break;
678 {
679 damageInfo->HitInfo |= HITINFO_CRITICALHIT;
681
682 damageInfo->procEx |= PROC_EX_CRITICAL_HIT;
683 // Crit bonus calc
684 damageInfo->damage += damageInfo->damage;
685 float mod = 0.0f;
686 // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
689 else
691
692 // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
694
695 if (mod != 0)
696 AddPct(damageInfo->damage, mod);
697 break;
698 }
701 damageInfo->procEx |= PROC_EX_PARRY;
702 damageInfo->cleanDamage += damageInfo->damage;
703 damageInfo->damage = 0;
704 break;
707 damageInfo->procEx |= PROC_EX_DODGE;
708 damageInfo->cleanDamage += damageInfo->damage;
709 damageInfo->damage = 0;
710 break;
713 damageInfo->HitInfo |= HITINFO_BLOCK;
714 damageInfo->procEx |= PROC_EX_BLOCK | PROC_EX_NORMAL_HIT;
715 // 30% damage blocked, double blocked amount if block is critical
716 damageInfo->blocked_amount = CalculatePct(damageInfo->damage, damageInfo->target->isBlockCritical() ? damageInfo->target->GetBlockPercent() * 2 : damageInfo->target->GetBlockPercent());
717 damageInfo->damage -= damageInfo->blocked_amount;
718 damageInfo->cleanDamage += damageInfo->blocked_amount;
719 break;
721 {
722 damageInfo->HitInfo |= HITINFO_GLANCING;
724 damageInfo->procEx |= PROC_EX_NORMAL_HIT;
725 int32 leveldif = int32(victim->getLevel()) - int32(getLevel());
726 if (leveldif > 3)
727 leveldif = 3;
728 float reducePercent = 1 - leveldif * 0.1f;
729 damageInfo->cleanDamage += damageInfo->damage - uint32(reducePercent * damageInfo->damage);
730 damageInfo->damage = uint32(reducePercent * damageInfo->damage);
731 break;
732 }
734 damageInfo->HitInfo |= HITINFO_CRUSHING;
736 damageInfo->procEx |= PROC_EX_NORMAL_HIT;
737 // 150% normal damage
738 damageInfo->damage += (damageInfo->damage / 2);
739 break;
740 default:
741 break;
742 }
743
744 int32 resilienceReduction = damageInfo->damage;
745 ApplyResilience(victim, &resilienceReduction, damageInfo->hitOutCome == MeleeHitOutcome::MELEE_HIT_CRIT);
746 resilienceReduction = damageInfo->damage - resilienceReduction;
747 damageInfo->damage -= resilienceReduction;
748 damageInfo->cleanDamage += resilienceReduction;
749
750 // Calculate absorb resist
751 if (int32(damageInfo->damage) > 0)
752 {
753 damageInfo->procVictim |= PROC_FLAG_TAKEN_DAMAGE;
754 // Calculate absorb & resists
755 CalcAbsorbResist(damageInfo->target, SpellSchoolMask(damageInfo->damageSchoolMask), DIRECT_DAMAGE, damageInfo->damage, &damageInfo->absorb, &damageInfo->resist);
756
757 if (damageInfo->absorb)
758 {
759 damageInfo->HitInfo |= ((damageInfo->damage - damageInfo->absorb) == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB);
761 damageInfo->procEx |= PROC_EX_ABSORB;
762 }
763
764 if (damageInfo->resist)
765 damageInfo->HitInfo |= ((damageInfo->damage - damageInfo->resist) == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST);
766
767 damageInfo->damage -= damageInfo->absorb + damageInfo->resist;
768 }
769 else // Impossible get negative result but....
770 damageInfo->damage = 0;
771
772 // Always apply HITINFO_AFFECTS_VICTIM in case its not a miss or full absorb
773 if (!(damageInfo->HitInfo & HITINFO_MISS) || !(damageInfo->HitInfo & HITINFO_FULL_ABSORB))
774 damageInfo->HitInfo |= HITINFO_AFFECTS_VICTIM;
775}
776
777void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
778{
779 Unit* victim = damageInfo->target;
780
781 if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TypeID::TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode()))
782 return;
783
784 // Hmmmm dont like this emotes client must by self do all animations
785 if (damageInfo->HitInfo & HITINFO_CRITICALHIT)
787 if (damageInfo->blocked_amount && damageInfo->TargetState != VictimState::VICTIMSTATE_BLOCK)
789
791 {
792 // Get attack timers
793 float offtime = float(victim->getAttackTimer(WeaponAttackType::OFF_ATTACK));
794 float basetime = float(victim->getAttackTimer(WeaponAttackType::BASE_ATTACK));
795 // Reduce attack time
796 if (victim->haveOffhandWeapon() && offtime < basetime)
797 {
798 float percent20 = victim->GetAttackTime(WeaponAttackType::OFF_ATTACK) * 0.20f;
799 float percent60 = 3.0f * percent20;
800 if (offtime > percent20 && offtime <= percent60)
802 else if (offtime > percent60)
803 {
804 offtime -= 2.0f * percent20;
806 }
807 }
808 else
809 {
810 float percent20 = victim->GetAttackTime(WeaponAttackType::BASE_ATTACK) * 0.20f;
811 float percent60 = 3.0f * percent20;
812 if (basetime > percent20 && basetime <= percent60)
814 else if (basetime > percent60)
815 {
816 basetime -= 2.0f * percent20;
818 }
819 }
820 }
821
822 // Call default DealDamage
823 CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->absorb, damageInfo->attackType, damageInfo->hitOutCome);
824 DealDamage(victim, damageInfo->damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->damageSchoolMask), NULL, durabilityLoss);
825
826 // If this is a creature and it attacks from behind it has a probability to daze it's victim
830 && (victim->GetTypeId() == TypeID::TYPEID_PLAYER || !victim->ToCreature()->isWorldBoss()) && !victim->IsVehicle())
831 {
832 // -probability is between 0% and 40%
833 // 20% base chance
834 float Probability = 20.0f;
835
836 // there is a newbie protection, at level 10 just 7% base chance; assuming linear function
837 if (victim->getLevel() < 30)
838 Probability = 0.65f * victim->getLevel() + 0.5f;
839
840 uint32 VictimDefense = victim->GetMaxSkillValueForLevel(this);
841 uint32 AttackerMeleeSkill = GetMaxSkillValueForLevel();
842
843 Probability *= AttackerMeleeSkill / (float)VictimDefense * 0.16;
844
845 if (Probability < 0)
846 Probability = 0;
847
848 if (Probability > 40.0f)
849 Probability = 40.0f;
850
851 if (roll_chance_f(Probability))
852 CastSpell(victim, 1604, true);
853 }
854
856 ToPlayer()->CastItemCombatSpell(victim, damageInfo->attackType, damageInfo->procVictim, damageInfo->procEx);
857
858 // Do effect if any damage done to target
859 if (damageInfo->damage)
860 {
861 // We're going to call functions which can modify content of the list during iteration over it's elements
862 // Let's copy the list so we can prevent iterator invalidation
864 for (AuraEffectList::const_iterator dmgShieldItr = vDamageShieldsCopy.begin(); dmgShieldItr != vDamageShieldsCopy.end(); ++dmgShieldItr)
865 {
866 SpellInfo const* i_spellProto = (*dmgShieldItr)->GetSpellInfo();
867 // Damage shield can be resisted...
868 if (SpellMissInfo missInfo = victim->SpellHitResult(this, i_spellProto, false))
869 {
870 victim->SendSpellMiss(this, i_spellProto->Id, missInfo);
871 continue;
872 }
873
874 // ...or immuned
875 if (IsImmunedToDamage(i_spellProto))
876 {
877 victim->SendSpellDamageImmune(this, i_spellProto->Id);
878 continue;
879 }
880
881 uint32 damage = (*dmgShieldItr)->GetAmount();
882
883 if (Unit* caster = (*dmgShieldItr)->GetCaster())
884 {
885 damage = caster->SpellDamageBonusDone(this, i_spellProto, damage, SPELL_DIRECT_DAMAGE);
886 damage = this->SpellDamageBonusTaken(caster, i_spellProto, damage, SPELL_DIRECT_DAMAGE);
887 }
888
889 // No Unit::CalcAbsorbResist here - opcode doesn't send that data - this damage is probably not affected by that
890 victim->DealDamageMods(this, damage, NULL);
891
892 // defender guid
893 ObjectGuid defenderGUID = victim->GetGUID();
894 // attacker guid
895 ObjectGuid attackerGUID = GetGUID();
896
898 WorldPacket data(SMSG_SPELLDAMAGESHIELD, 8 + 8 + 4 + 4 + 4 + 4 + 4);
899 data.WriteGuidMask(attackerGUID, 1);
900 data.WriteGuidMask(defenderGUID, 2);
901 data.WriteBit(0); // hasSpellCastLogData //72
902 data.WriteGuidMask(defenderGUID, 6);
903 data.WriteGuidMask(attackerGUID, 3);
904 data.WriteGuidMask(defenderGUID, 4);
905 data.WriteGuidMask(attackerGUID, 2, 5, 6);
906 data.WriteGuidMask(defenderGUID, 3);
907 data.WriteGuidMask(attackerGUID, 0);
908 data.WriteGuidMask(defenderGUID, 5, 1, 0);
909 data.WriteGuidMask(attackerGUID, 7, 4);
910 data.WriteGuidMask(defenderGUID, 7);
911
912 data.FlushBits();
913 //if72 {}
914 data.WriteGuidBytes(attackerGUID, 2);
915 data.WriteGuidBytes(defenderGUID, 6);
916 data.WriteGuidBytes(attackerGUID, 6, 4);
917 data.WriteGuidBytes(defenderGUID, 3);
918 data.WriteGuidBytes(attackerGUID, 7);
919 data << uint32(damageInfo->absorb); // LogAbsorb
920 data.WriteGuidBytes(defenderGUID, 4);
921 data.WriteGuidBytes(attackerGUID, 1);
922 data << uint32(damage); // Damage
923 data.WriteGuidBytes(defenderGUID, 7);
924 data << uint32(i_spellProto->Id);
925 int32 overkill = int32(damage) - int32(GetHealth());
926 data << uint32(overkill > 0 ? overkill : 0); // Overkill
927 data.WriteGuidBytes(attackerGUID, 5);
928 data.WriteGuidBytes(defenderGUID, 5);
929 data.WriteGuidBytes(attackerGUID, 0);
930 data.WriteGuidBytes(defenderGUID, 1, 0, 2);
931 data << uint32(i_spellProto->SchoolMask);
932 data.WriteGuidBytes(attackerGUID, 3);
933 victim->SendMessageToSet(&data, true);
934
935 victim->DealDamage(this, damage, 0, SPELL_DIRECT_DAMAGE, i_spellProto->GetSchoolMask(), i_spellProto, true);
936 }
937 }
938}
939
941{
942 if (anim_id == 10)
943 {
945 return;
946 }
948 {
950 return;
951 }
952 else if (anim_id == 483)
953 {
955 return;
956 }
957
958 WorldPacket data(SMSG_EMOTE, 4 + 8);
959 data << uint32(anim_id);
960 data << uint64(GetGUID());
961 SendMessageToSet(&data, true);
962}
963
964bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* spellInfo, uint8 effIndex)
965{
966 // only physical spells damage gets reduced by armor
967 if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
968 return false;
969 if (spellInfo)
970 {
971 // there are spells with no specific attribute but they have "ignores armor" in tooltip
973 return false;
974
975 // bleeding effects are not reduced by armor
976 if (effIndex != MAX_SPELL_EFFECTS)
977 {
978 if (spellInfo->Effects[effIndex].ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE ||
979 spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_SCHOOL_DAMAGE)
980 if (spellInfo->GetEffectMechanicMask(effIndex) & (1 << MECHANIC_BLEED))
981 return false;
982 }
983 }
984 return true;
985}
986
987uint32 Unit::CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType /*attackType*/)
988{
989 float armor = float(victim->GetArmor());
990
991 // bypass enemy armor by SPELL_AURA_BYPASS_ARMOR_FOR_CASTER
992 int32 armorBypassPct = 0;
994 for (AuraEffectList::const_iterator i = reductionAuras.begin(); i != reductionAuras.end(); ++i)
995 if ((*i)->GetCasterGUID() == GetGUID())
996 armorBypassPct += (*i)->GetAmount();
997 armor = CalculatePct(armor, 100 - std::min(armorBypassPct, 100));
998
999 // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
1001
1002 if (spellInfo)
1003 if (Player* modOwner = GetSpellModOwner())
1004 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_IGNORE_ARMOR, armor);
1005
1007 for (AuraEffectList::const_iterator j = resIgnoreAuras.begin(); j != resIgnoreAuras.end(); ++j)
1008 {
1009 if ((*j)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
1010 armor = floor(AddPct(armor, -(*j)->GetAmount()));
1011 }
1012
1014 for (AuraEffectList::const_iterator k = ArPenAuras.begin(); k != ArPenAuras.end(); ++k)
1015 {
1016 if ((*k)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
1017 armor = floor(AddPct(armor, -(*k)->GetAmount()));
1018 }
1019
1020 if (armor < 0.0f)
1021 armor = 0.0f;
1022
1023 float levelModifier = getLevel();
1024
1025 if (levelModifier > 85)
1026 levelModifier = levelModifier + (4.5 * (levelModifier - 59)) + (20 * (levelModifier - 80)) + (22 * (levelModifier - 85));
1027 else if (levelModifier > 80)
1028 levelModifier = levelModifier + (4.5 * (levelModifier - 59)) + (20 * (levelModifier - 80));
1029 else if (levelModifier > 59)
1030 levelModifier = levelModifier + (4.5 * (levelModifier - 59));
1031
1032 float tmpvalue = 0.1f * armor / (8.5f * levelModifier + 40);
1033 tmpvalue = tmpvalue / (1.0f + tmpvalue);
1034
1035 if (tmpvalue < 0.0f)
1036 tmpvalue = 0.0f;
1037 if (tmpvalue > 0.75f)
1038 tmpvalue = 0.75f;
1039
1040 return std::max<uint32>(damage * (1.0f - tmpvalue), 1);
1041}
1042
1043uint32 Unit::CalcSpellResistance(Unit* victim, SpellSchoolMask schoolMask, SpellInfo const* spellInfo) const
1044{
1045 // Magic damage, check for resists
1046 if (!(schoolMask & SPELL_SCHOOL_MASK_SPELL))
1047 return 0;
1048
1049 // Ignore spells that can't be resisted
1050 if (spellInfo && spellInfo->AttributesEx4 & SPELL_ATTR4_IGNORE_RESISTANCES)
1051 return 0;
1052
1053 uint8 const bossLevel = 83;
1054 uint32 const bossResistanceConstant = 510;
1055 uint32 resistanceConstant = 0;
1056 uint8 level = victim->getLevel();
1057
1058 if (level == bossLevel)
1059 resistanceConstant = bossResistanceConstant;
1060 else
1061 resistanceConstant = level * 5;
1062
1063 int32 baseVictimResistance = victim->GetResistance(schoolMask);
1064 baseVictimResistance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask);
1065
1066 if (Player const* player = ToPlayer())
1067 baseVictimResistance -= player->GetSpellPenetrationItemMod();
1068
1069 // Resistance can't be lower then 0
1070 int32 victimResistance = std::max<int32>(baseVictimResistance, 0);
1071
1072 if (victimResistance > 0)
1073 {
1074 int32 ignoredResistance = 0;
1075
1077 for (AuraEffectList::const_iterator itr = ResIgnoreAuras.begin(); itr != ResIgnoreAuras.end(); ++itr)
1078 if ((*itr)->GetMiscValue() & schoolMask)
1079 ignoredResistance += (*itr)->GetAmount();
1080
1081 ignoredResistance = std::min<int32>(ignoredResistance, 100);
1082 ApplyPct(victimResistance, 100 - ignoredResistance);
1083 }
1084
1085 if (victimResistance <= 0)
1086 return 0;
1087
1088 float averageResist = float(victimResistance) / float(victimResistance + resistanceConstant);
1089
1090 float discreteResistProbability[11];
1091 for (uint32 i = 0; i < 11; ++i)
1092 {
1093 discreteResistProbability[i] = 0.5f - 2.5f * fabs(0.1f * i - averageResist);
1094 if (discreteResistProbability[i] < 0.0f)
1095 discreteResistProbability[i] = 0.0f;
1096 }
1097
1098 if (averageResist <= 0.1f)
1099 {
1100 discreteResistProbability[0] = 1.0f - 7.5f * averageResist;
1101 discreteResistProbability[1] = 5.0f * averageResist;
1102 discreteResistProbability[2] = 2.5f * averageResist;
1103 }
1104
1105 uint32 resistance = 0;
1106 float r = float(rand_norm());
1107 float probabilitySum = discreteResistProbability[0];
1108
1109 while (r >= probabilitySum && resistance < 10)
1110 probabilitySum += discreteResistProbability[++resistance];
1111
1112 return resistance * 10;
1113}
1114
1115void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, uint32 const damage, uint32* absorb, uint32* resist, SpellInfo const* spellInfo /*= NULL*/)
1116{
1117 if (!victim || !victim->IsAlive() || !damage)
1118 return;
1119
1120 DamageInfo dmgInfo = DamageInfo(this, victim, damage, spellInfo, schoolMask, damagetype);
1121
1122 uint32 spellResistance = CalcSpellResistance(victim, schoolMask, spellInfo);
1123 dmgInfo.ResistDamage(CalculatePct(damage, spellResistance));
1124
1125 // Ignore Absorption Auras
1126 float auraAbsorbMod = 0;
1128 for (AuraEffectList::const_iterator itr = AbsIgnoreAurasA.begin(); itr != AbsIgnoreAurasA.end(); ++itr)
1129 {
1130 if (!((*itr)->GetMiscValue() & schoolMask))
1131 continue;
1132
1133 if ((*itr)->GetAmount() > auraAbsorbMod)
1134 auraAbsorbMod = float((*itr)->GetAmount());
1135 }
1136
1138 for (AuraEffectList::const_iterator itr = AbsIgnoreAurasB.begin(); itr != AbsIgnoreAurasB.end(); ++itr)
1139 {
1140 if (!((*itr)->GetMiscValue() & schoolMask))
1141 continue;
1142
1143 if (((*itr)->GetAmount() > auraAbsorbMod) && (*itr)->IsAffectingSpell(spellInfo))
1144 auraAbsorbMod = float((*itr)->GetAmount());
1145 }
1146
1147 RoundToInterval(auraAbsorbMod, 0.0f, 100.0f);
1148
1149 // We're going to call functions which can modify content of the list during iteration over it's elements
1150 // Let's copy the list so we can prevent iterator invalidation
1152 vSchoolAbsorbCopy.sort(Skyfire::AbsorbAuraOrderPred());
1153
1154 // absorb without mana cost
1155 for (AuraEffectList::iterator itr = vSchoolAbsorbCopy.begin(); (itr != vSchoolAbsorbCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr)
1156 {
1157 AuraEffect* absorbAurEff = *itr;
1158 // Check if aura was removed during iteration - we don't need to work on such auras
1159 AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID());
1160 if (!aurApp)
1161 continue;
1162 if (!(absorbAurEff->GetMiscValue() & schoolMask))
1163 continue;
1164
1165 // get amount which can be still absorbed by the aura
1166 int32 currentAbsorb = absorbAurEff->GetAmount();
1167 // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
1168 if (currentAbsorb < 0)
1169 currentAbsorb = 0;
1170
1171 uint32 tempAbsorb = uint32(currentAbsorb);
1172
1173 bool defaultPrevented = false;
1174
1175 absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, dmgInfo, tempAbsorb, defaultPrevented);
1176 currentAbsorb = tempAbsorb;
1177
1178 if (defaultPrevented)
1179 continue;
1180
1181 // Apply absorb mod auras
1182 AddPct(currentAbsorb, -auraAbsorbMod);
1183
1184 // absorb must be smaller than the damage itself
1185 currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(dmgInfo.GetDamage()));
1186
1187 dmgInfo.AbsorbDamage(currentAbsorb);
1188
1189 tempAbsorb = currentAbsorb;
1190 absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, dmgInfo, tempAbsorb);
1191
1192 // Check if our aura is using amount to count damage
1193 if (absorbAurEff->GetAmount() >= 0)
1194 {
1195 // Reduce shield amount
1196 absorbAurEff->SetAmount(absorbAurEff->GetAmount() - currentAbsorb);
1197 // Aura cannot absorb anything more - remove it
1198 if (absorbAurEff->GetAmount() <= 0)
1199 absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
1200 }
1201 }
1202
1203 // absorb by mana cost
1205 for (AuraEffectList::const_iterator itr = vManaShieldCopy.begin(); (itr != vManaShieldCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr)
1206 {
1207 AuraEffect* absorbAurEff = *itr;
1208 // Check if aura was removed during iteration - we don't need to work on such auras
1209 AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID());
1210 if (!aurApp)
1211 continue;
1212 // check damage school mask
1213 if (!(absorbAurEff->GetMiscValue() & schoolMask))
1214 continue;
1215
1216 // get amount which can be still absorbed by the aura
1217 int32 currentAbsorb = absorbAurEff->GetAmount();
1218 // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
1219 if (currentAbsorb < 0)
1220 currentAbsorb = 0;
1221
1222 uint32 tempAbsorb = currentAbsorb;
1223
1224 bool defaultPrevented = false;
1225
1226 absorbAurEff->GetBase()->CallScriptEffectManaShieldHandlers(absorbAurEff, aurApp, dmgInfo, tempAbsorb, defaultPrevented);
1227 currentAbsorb = tempAbsorb;
1228
1229 if (defaultPrevented)
1230 continue;
1231
1232 AddPct(currentAbsorb, -auraAbsorbMod);
1233
1234 // absorb must be smaller than the damage itself
1235 currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(dmgInfo.GetDamage()));
1236
1237 int32 manaReduction = currentAbsorb;
1238
1239 // lower absorb amount by talents
1240 if (float manaMultiplier = absorbAurEff->GetSpellInfo()->Effects[absorbAurEff->GetEffIndex()].CalcValueMultiplier(absorbAurEff->GetCaster()))
1241 manaReduction = int32(float(manaReduction) * manaMultiplier);
1242
1243 int32 manaTaken = -victim->ModifyPower(POWER_MANA, -manaReduction);
1244
1245 // take case when mana has ended up into account
1246 currentAbsorb = currentAbsorb ? int32(float(currentAbsorb) * (float(manaTaken) / float(manaReduction))) : 0;
1247
1248 dmgInfo.AbsorbDamage(currentAbsorb);
1249
1250 tempAbsorb = currentAbsorb;
1251 absorbAurEff->GetBase()->CallScriptEffectAfterManaShieldHandlers(absorbAurEff, aurApp, dmgInfo, tempAbsorb);
1252
1253 // Check if our aura is using amount to count damage
1254 if (absorbAurEff->GetAmount() >= 0)
1255 {
1256 absorbAurEff->SetAmount(absorbAurEff->GetAmount() - currentAbsorb);
1257 if ((absorbAurEff->GetAmount() <= 0))
1258 absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
1259 }
1260 }
1261
1262 // split damage auras - only when not damaging self
1263 if (victim != this)
1264 {
1265 // We're going to call functions which can modify content of the list during iteration over it's elements
1266 // Let's copy the list so we can prevent iterator invalidation
1268 for (AuraEffectList::iterator itr = vSplitDamagePctCopy.begin(); itr != vSplitDamagePctCopy.end() && dmgInfo.GetDamage() > 0; ++itr)
1269 {
1270 // Check if aura was removed during iteration - we don't need to work on such auras
1271 AuraApplication const* aurApp = (*itr)->GetBase()->GetApplicationOfTarget(victim->GetGUID());
1272 if (!aurApp)
1273 continue;
1274
1275 // check damage school mask
1276 if (!((*itr)->GetMiscValue() & schoolMask))
1277 continue;
1278
1279 // Damage can be splitted only if aura has an alive caster
1280 Unit* caster = (*itr)->GetCaster();
1281 if (!caster || (caster == victim) || !caster->IsInWorld() || !caster->IsAlive())
1282 continue;
1283
1284 uint32 splitDamage = CalculatePct(dmgInfo.GetDamage(), (*itr)->GetAmount());
1285
1286 (*itr)->GetBase()->CallScriptEffectSplitHandlers((*itr), aurApp, dmgInfo, splitDamage);
1287
1288 // absorb must be smaller than the damage itself
1289 splitDamage = RoundToInterval(splitDamage, uint32(0), uint32(dmgInfo.GetDamage()));
1290
1291 dmgInfo.AbsorbDamage(splitDamage);
1292 uint32 splitted = splitDamage;
1293 uint32 split_absorb = 0;
1294 DealDamageMods(caster, splitted, &split_absorb);
1295
1296 SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitted, schoolMask, split_absorb, 0, false, 0, false);
1297
1299 DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*itr)->GetSpellInfo(), false);
1300 }
1301 }
1302
1303 *resist = dmgInfo.GetResist();
1304 *absorb = dmgInfo.GetAbsorb();
1305}
1306
1307void Unit::CalcHealAbsorb(Unit* victim, SpellInfo const* healSpell, uint32& healAmount, uint32& absorb)
1308{
1309 if (!healAmount)
1310 return;
1311
1312 int32 RemainingHeal = healAmount;
1313
1314 // Need remove expired auras after
1315 bool existExpired = false;
1316
1317 // absorb without mana cost
1319 for (AuraEffectList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end() && RemainingHeal > 0; ++i)
1320 {
1321 if (!((*i)->GetMiscValue() & healSpell->SchoolMask))
1322 continue;
1323
1324 // Max Amount can be absorbed by this aura
1325 int32 currentAbsorb = (*i)->GetAmount();
1326
1327 // Found empty aura (impossible but..)
1328 if (currentAbsorb <= 0)
1329 {
1330 existExpired = true;
1331 continue;
1332 }
1333
1334 // currentAbsorb - damage can be absorbed by shield
1335 // If need absorb less damage
1336 if (RemainingHeal < currentAbsorb)
1337 currentAbsorb = RemainingHeal;
1338
1339 RemainingHeal -= currentAbsorb;
1340
1341 // Reduce shield amount
1342 (*i)->SetAmount((*i)->GetAmount() - currentAbsorb);
1343 // Need remove it later
1344 if ((*i)->GetAmount() <= 0)
1345 existExpired = true;
1346 }
1347
1348 // Remove all expired absorb auras
1349 if (existExpired)
1350 {
1351 for (AuraEffectList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end();)
1352 {
1353 AuraEffect* auraEff = *i;
1354 ++i;
1355 if (auraEff->GetAmount() <= 0)
1356 {
1357 uint32 removedAuras = victim->m_removedAurasCount;
1359 if (removedAuras + 1 < victim->m_removedAurasCount)
1360 i = vHealAbsorb.begin();
1361 }
1362 }
1363 }
1364
1365 absorb = RemainingHeal > 0 ? (healAmount - RemainingHeal) : healAmount;
1366 healAmount = RemainingHeal;
1367}
1368
1369void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extra)
1370{
1372 return;
1373
1374 if (!victim->IsAlive())
1375 return;
1376
1377 if ((attType == WeaponAttackType::BASE_ATTACK || attType == WeaponAttackType::OFF_ATTACK) && !IsWithinLOSInMap(victim))
1378 return;
1379
1380 CombatStart(victim);
1382
1384 return; // ignore ranged case
1385
1386
1387 // melee attack spell casted at main hand attack only - no normal melee dmg dealt
1392 else
1393 {
1394 // attack can be redirected to another target
1395 victim = GetMeleeHitRedirectTarget(victim);
1396
1397 CalcDamageInfo damageInfo;
1398 CalculateMeleeDamage(victim, 0, &damageInfo, attType);
1399 // Send log damage message to client
1400 DealDamageMods(victim, damageInfo.damage, &damageInfo.absorb);
1401 SendAttackStateUpdate(&damageInfo);
1402
1403 //TriggerAurasProcOnEvent(damageInfo);
1404 ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType);
1405
1406 DealMeleeDamage(&damageInfo, true);
1407
1409 SF_LOG_DEBUG("entities.unit", "AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
1410 GetGUIDLow(), victim->GetGUIDLow(), uint8(victim->GetTypeId()), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist);
1411 else
1412 SF_LOG_DEBUG("entities.unit", "AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
1413 GetGUIDLow(), victim->GetGUIDLow(), uint8(victim->GetTypeId()), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist);
1414 }
1415}
1416
1418{
1419 while (m_extraAttacks)
1420 {
1423 }
1424}
1425
1427{
1428 // This is only wrapper
1429
1430 // Miss chance based on melee
1431 //float miss_chance = MeleeMissChanceCalc(victim, attType);
1432 float miss_chance = MeleeSpellMissChance(victim, attType, 0);
1433
1434 // Critical hit chance
1435 float crit_chance = GetUnitCriticalChance(attType, victim);
1436
1437 // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case)
1438 float dodge_chance = victim->GetUnitDodgeChance();
1439 float block_chance = victim->GetUnitBlockChance();
1440 float parry_chance = victim->GetUnitParryChance();
1441
1442 // Useful if want to specify crit & miss chances for melee, else it could be removed
1443 SF_LOG_DEBUG("entities.unit", "MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance, crit_chance, dodge_chance, parry_chance, block_chance);
1444
1445 return RollMeleeOutcomeAgainst(victim, attType, int32(crit_chance * 100), int32(miss_chance * 100), int32(dodge_chance * 100), int32(parry_chance * 100), int32(block_chance * 100));
1446}
1447
1448MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* victim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance) const
1449{
1450 if (victim->GetTypeId() == TypeID::TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode())
1452
1453 int32 attackerMaxSkillValueForLevel = GetMaxSkillValueForLevel(victim);
1454 int32 victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this);
1455
1456 // bonus from skills is 0.04%
1457 int32 skillBonus = 4 * (attackerMaxSkillValueForLevel - victimMaxSkillValueForLevel);
1458 int32 sum = 0, tmp = 0;
1459 int32 roll = std::rand() % 10000;
1460
1461 SF_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus);
1462 SF_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d",
1463 roll, miss_chance, dodge_chance, parry_chance, block_chance, crit_chance);
1464
1465 tmp = miss_chance;
1466
1467 if (tmp > 0 && roll < (sum += tmp))
1468 {
1469 SF_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: MISS");
1471 }
1472
1473 // always crit against a sitting target (except 0 crit chance)
1474 if (victim->GetTypeId() == TypeID::TYPEID_PLAYER && crit_chance > 0 && !victim->IsStandState())
1475 {
1476 SF_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: CRIT (sitting victim)");
1478 }
1479
1480 // Dodge chance
1481
1482 // only players can't dodge if attacker is behind
1483 if (victim->GetTypeId() == TypeID::TYPEID_PLAYER && !victim->HasInArc(M_PI, this) && !victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
1484 {
1485 SF_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: attack came from behind and victim was a player.");
1486 }
1487 else
1488 {
1489 // Reduce dodge chance by attacker expertise rating
1491 dodge_chance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100);
1492 else
1493 dodge_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
1494
1495 // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
1497 dodge_chance = int32(float(dodge_chance) * GetTotalAuraMultiplier(SPELL_AURA_MOD_ENEMY_DODGE));
1498
1499 tmp = dodge_chance;
1500 if ((tmp > 0) // check if unit _can_ dodge
1501 && ((tmp -= skillBonus) > 0)
1502 && roll < (sum += tmp))
1503 {
1504 SF_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum - tmp, sum);
1506 }
1507 }
1508
1509 // parry & block chances
1510
1511 // check if attack comes from behind, nobody can parry or block if attacker is behind
1512 if (!victim->HasInArc(M_PI, this) && !victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
1513 SF_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: attack came from behind.");
1514 else
1515 {
1516 // Reduce parry chance by attacker expertise rating
1518 parry_chance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100);
1519 else
1520 parry_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
1521
1523 {
1524 int32 tmp2 = int32(parry_chance);
1525 if (tmp2 > 0 // check if unit _can_ parry
1526 && (tmp2 -= skillBonus) > 0
1527 && roll < (sum += tmp2))
1528 {
1529 SF_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum - tmp2, sum);
1531 }
1532 }
1533
1535 {
1536 tmp = block_chance;
1537 if (tmp > 0 // check if unit _can_ block
1538 && (tmp -= skillBonus) > 0
1539 && roll < (sum += tmp))
1540 {
1541 SF_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum - tmp, sum);
1543 }
1544 }
1545 }
1546
1547 // Critical chance
1548 tmp = crit_chance;
1549
1550 if (tmp > 0 && roll < (sum += tmp))
1551 {
1552 SF_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum - tmp, sum);
1553 if (GetTypeId() == TypeID::TYPEID_UNIT && (ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRIT))
1554 SF_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: CRIT DISABLED)");
1555 else
1557 }
1558
1559 // 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)
1560 if (attType != WeaponAttackType::RANGED_ATTACK &&
1562 victim->GetTypeId() != TypeID::TYPEID_PLAYER && !victim->ToCreature()->IsPet() &&
1563 getLevel() < victim->getLevelForTarget(this))
1564 {
1565 // cap possible value (with bonuses > max skill)
1566 int32 skill = attackerMaxSkillValueForLevel;
1567
1568 tmp = (10 + (victimMaxSkillValueForLevel - skill)) * 100;
1569 tmp = tmp > 4000 ? 4000 : tmp;
1570 if (roll < (sum += tmp))
1571 {
1572 SF_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum - 4000, sum);
1574 }
1575 }
1576
1577 // mobs can score crushing blows if they're 4 or more levels above victim
1578 if (getLevelForTarget(victim) >= victim->getLevelForTarget(this) + 4 &&
1579 // can be from by creature (if can) or from controlled player that considered as creature
1581 !(GetTypeId() == TypeID::TYPEID_UNIT && ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRUSH))
1582 {
1583 // when their weapon skill is 15 or more above victim's defense skill
1584 tmp = victimMaxSkillValueForLevel;
1585 // tmp = mob's level * 5 - player's current defense skill
1586 tmp = attackerMaxSkillValueForLevel - tmp;
1587 if (tmp >= 15)
1588 {
1589 // add 2% chance per lacking skill point, min. is 15%
1590 tmp = tmp * 200 - 1500;
1591 if (roll < (sum += tmp))
1592 {
1593 SF_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum - tmp, sum);
1595 }
1596 }
1597 }
1598
1599 SF_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: NORMAL");
1601}
1602
1603uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct)
1604{
1605 float min_damage, max_damage;
1606
1607 if (GetTypeId() == TypeID::TYPEID_PLAYER && (normalized || !addTotalPct))
1608 ToPlayer()->CalculateMinMaxDamage(attType, normalized, addTotalPct, min_damage, max_damage);
1609 else
1610 {
1611 switch (attType)
1612 {
1616 break;
1620 break;
1624 break;
1625 // Just for good manner
1626 default:
1627 min_damage = 0.0f;
1628 max_damage = 0.0f;
1629 break;
1630 }
1631 }
1632
1633 if (min_damage > max_damage)
1634 std::swap(min_damage, max_damage);
1635
1636 if (max_damage == 0.0f)
1637 max_damage = 5.0f;
1638
1639 return std::rand() % (uint32)max_damage + (uint32)min_damage;
1640}
1641
1642float Unit::CalculateLevelPenalty(SpellInfo const* spellProto) const
1643{
1644 if (spellProto->SpellLevel <= 0 || spellProto->SpellLevel >= spellProto->MaxLevel)
1645 return 1.0f;
1646
1647 float LvlPenalty = 0.0f;
1648
1649 if (spellProto->SpellLevel < 20)
1650 LvlPenalty = 20.0f - spellProto->SpellLevel * 3.75f;
1651 float LvlFactor = (float(spellProto->SpellLevel) + 6.0f) / float(getLevel());
1652 if (LvlFactor > 1.0f)
1653 LvlFactor = 1.0f;
1654
1655 return AddPct(LvlFactor, -LvlPenalty);
1656}
@ SCORE_DAMAGE_DONE
#define M_PI
Definition Common.h:192
@ CREATURE_FLAG_EXTRA_NO_BLOCK
Definition Creature.h:33
@ CREATURE_FLAG_EXTRA_NO_CRIT
Definition Creature.h:40
@ CREATURE_FLAG_EXTRA_NO_CRUSH
Definition Creature.h:34
@ CREATURE_FLAG_EXTRA_NO_PARRY
Definition Creature.h:31
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED
Definition DBCEnums.h:257
@ ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE
Definition DBCEnums.h:181
@ ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED
Definition DBCEnums.h:258
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT
Definition DBCEnums.h:256
#define MAX_SPELL_EFFECTS
std::int32_t int32
Definition Define.h:73
#define UI64FMTD
Definition Define.h:64
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
std::uint64_t uint64
Definition Define.h:76
#define ASSERT
Definition Errors.h:29
#define SF_LOG_DEBUG(filterType__,...)
Definition Log.h:134
#define SF_LOG_ERROR(filterType__,...)
Definition Log.h:143
@ TYPEID_PLAYER
Definition Object.h:55
@ TYPEID_UNIT
Definition Object.h:54
@ CHEAT_GOD
Definition Player.h:988
EquipmentSlots
Definition Player.h:687
@ EQUIPMENT_SLOT_END
Definition Player.h:708
#define sScriptMgr
Definition ScriptMgr.h:764
@ EMOTE_ONESHOT_WOUND_CRITICAL
@ EMOTE_ONESHOT_PARRY_SHIELD
@ POWER_RAGE
@ POWER_MANA
@ SPELL_EFFECT_SCHOOL_DAMAGE
@ SPELL_DAMAGE_CLASS_RANGED
@ SPELL_DAMAGE_CLASS_MAGIC
@ SPELL_DAMAGE_CLASS_NONE
@ SPELL_DAMAGE_CLASS_MELEE
@ SPELL_ATTR4_IGNORE_RESISTANCES
@ SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS
@ SPELL_HIT_TYPE_CRIT
SpellMissInfo
@ MECHANIC_BLEED
SpellSchoolMask
@ SPELL_SCHOOL_MASK_NORMAL
@ SPELL_SCHOOL_MASK_SPELL
@ SPELL_STATE_PREPARING
Definition Spell.h:265
@ SPELL_STATE_CASTING
Definition Spell.h:266
@ SPELL_AURA_MANA_SHIELD
@ SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL
@ SPELL_AURA_PERIODIC_DAMAGE
@ SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE
@ SPELL_AURA_MOD_IGNORE_TARGET_RESIST
@ SPELL_AURA_DAMAGE_SHIELD
@ SPELL_AURA_MOD_EXPERTISE
@ SPELL_AURA_SHARE_DAMAGE_PCT
@ SPELL_AURA_IGNORE_HIT_DIRECTION
@ SPELL_AURA_SCHOOL_HEAL_ABSORB
@ SPELL_AURA_BYPASS_ARMOR_FOR_CASTER
@ SPELL_AURA_MOD_ENEMY_DODGE
@ SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL
@ SPELL_AURA_SPLIT_DAMAGE_PCT
@ SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
@ SPELL_AURA_MOD_ARMOR_PENETRATION_PCT
@ SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
@ SPELL_AURA_MOD_TARGET_RESISTANCE
@ SPELL_AURA_SCHOOL_ABSORB
@ SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
@ SPELL_ATTR0_CU_IGNORE_ARMOR
Definition SpellInfo.h:77
#define sSpellMgr
Definition SpellMgr.h:744
@ PROC_EX_NONE
Definition SpellMgr.h:184
@ PROC_EX_DODGE
Definition SpellMgr.h:189
@ PROC_EX_BLOCK
Definition SpellMgr.h:191
@ PROC_EX_CRITICAL_HIT
Definition SpellMgr.h:186
@ PROC_EX_NORMAL_HIT
Definition SpellMgr.h:185
@ PROC_EX_IMMUNE
Definition SpellMgr.h:193
@ PROC_EX_MISS
Definition SpellMgr.h:187
@ PROC_EX_ABSORB
Definition SpellMgr.h:195
@ PROC_EX_PARRY
Definition SpellMgr.h:190
@ PROC_EX_EVADE
Definition SpellMgr.h:192
@ PROC_FLAG_DONE_MELEE_AUTO_ATTACK
Definition SpellMgr.h:101
@ PROC_FLAG_DONE_MAINHAND_ATTACK
Definition SpellMgr.h:131
@ PROC_FLAG_TAKEN_DAMAGE
Definition SpellMgr.h:128
@ PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK
Definition SpellMgr.h:102
@ PROC_FLAG_DONE_OFFHAND_ATTACK
Definition SpellMgr.h:132
@ PROC_FLAG_NONE
Definition SpellMgr.h:96
@ CHANNEL_FLAG_DELAY
Definition Unit.h:36
@ AURA_INTERRUPT_FLAG_TAKE_DAMAGE
Definition Unit.h:42
@ AURA_INTERRUPT_FLAG_DIRECT_DAMAGE
Definition Unit.h:65
@ AURA_INTERRUPT_FLAG_MELEE_ATTACK
Definition Unit.h:53
WeaponAttackType
Definition Unit.h:572
@ VICTIMSTATE_DODGE
Definition Unit.h:292
@ VICTIMSTATE_BLOCK
Definition Unit.h:295
@ VICTIMSTATE_MISS
Definition Unit.h:290
@ VICTIMSTATE_EVADE
Definition Unit.h:296
@ VICTIMSTATE_WOUND
Definition Unit.h:291
@ VICTIMSTATE_PARRY
Definition Unit.h:293
@ VICTIMSTATE_IMMUNE
Definition Unit.h:297
@ SPELLMOD_CRIT_DAMAGE_BONUS
Definition Unit.h:88
@ SPELLMOD_IGNORE_ARMOR
Definition Unit.h:86
SpellValueMod
Definition Unit.h:113
@ SPELLVALUE_BASE_POINT1
Definition Unit.h:115
@ SPELLVALUE_BASE_POINT2
Definition Unit.h:116
@ SPELLVALUE_BASE_POINT0
Definition Unit.h:114
@ HITINFO_PARTIAL_ABSORB
Definition Unit.h:310
@ HITINFO_FULL_RESIST
Definition Unit.h:311
@ HITINFO_NORMALSWING
Definition Unit.h:303
@ HITINFO_BLOCK
Definition Unit.h:317
@ HITINFO_CRUSHING
Definition Unit.h:321
@ HITINFO_SWINGNOHITSOUND
Definition Unit.h:325
@ HITINFO_MISS
Definition Unit.h:308
@ HITINFO_FULL_ABSORB
Definition Unit.h:309
@ HITINFO_OFFHAND
Definition Unit.h:306
@ HITINFO_GLANCING
Definition Unit.h:320
@ HITINFO_CRITICALHIT
Definition Unit.h:313
@ HITINFO_PARTIAL_RESIST
Definition Unit.h:312
@ HITINFO_AFFECTS_VICTIM
Definition Unit.h:305
#define CURRENT_FIRST_NON_MELEE_SPELL
Definition Unit.h:1114
@ AURA_REMOVE_BY_ENEMY_SPELL
Definition Unit.h:409
TriggerCastFlags
Definition Unit.h:415
@ TRIGGERED_FULL_MASK
Will ignore most target checks (mostly DBC target checks).
Definition Unit.h:435
@ TRIGGERED_NONE
Definition Unit.h:416
#define CURRENT_MAX_SPELL
Definition Unit.h:1115
CurrentSpellTypes
Definition Unit.h:1107
@ CURRENT_CHANNELED_SPELL
Definition Unit.h:1110
@ CURRENT_GENERIC_SPELL
Definition Unit.h:1109
@ CURRENT_MELEE_SPELL
Definition Unit.h:1108
MeleeHitOutcome
Definition Unit.h:828
@ MELEE_HIT_NORMAL
Definition Unit.h:830
@ MELEE_HIT_CRUSHING
Definition Unit.h:830
@ MELEE_HIT_PARRY
Definition Unit.h:829
@ MELEE_HIT_DODGE
Definition Unit.h:829
@ MELEE_HIT_EVADE
Definition Unit.h:829
@ MELEE_HIT_BLOCK
Definition Unit.h:829
@ MELEE_HIT_GLANCING
Definition Unit.h:830
@ SPELL_INTERRUPT_FLAG_ABORT_ON_DMG
Definition Unit.h:28
@ SPELL_INTERRUPT_FLAG_PUSH_BACK
Definition Unit.h:25
@ UNIT_STATE_CANNOT_AUTOATTACK
Definition Unit.h:546
@ UNIT_STATE_IN_FLIGHT
Definition Unit.h:520
@ UNIT_FLAG_PACIFIED
Definition Unit.h:642
DamageEffectType
Definition Unit.h:613
@ DIRECT_DAMAGE
Definition Unit.h:614
@ NODAMAGE
Definition Unit.h:618
@ DOT
Definition Unit.h:616
@ SPELL_DIRECT_DAMAGE
Definition Unit.h:615
@ UNIT_FIELD_MAX_RANGED_DAMAGE
@ UNIT_FIELD_MIN_DAMAGE
@ UNIT_FIELD_FLAGS
@ UNIT_FIELD_MAX_OFF_HAND_DAMAGE
@ UNIT_FIELD_MIN_RANGED_DAMAGE
@ UNIT_FIELD_MIN_OFF_HAND_DAMAGE
@ UNIT_FIELD_MAX_DAMAGE
@ UNIT_FIELD_NPC_EMOTESTATE
double rand_norm(void)
Definition Util.cpp:50
bool roll_chance_f(float chance)
Definition Util.h:83
T AddPct(T &base, U pct)
Definition Util.h:109
T RoundToInterval(T &num, T floor, T ceil)
Definition Util.h:121
T ApplyPct(T &base, U pct)
Definition Util.h:115
T CalculatePct(T base, U pct)
Definition Util.h:103
Aura * GetBase() const
Definition SpellAuras.h:55
SpellInfo const * GetSpellInfo() const
void SetAmount(int32 amount)
Unit * GetCaster() const
int32 GetMiscValue() const
Aura * GetBase() const
uint32 GetEffIndex() const
uint64 GetCasterGUID() const
int32 GetAmount() const
const AuraApplication * GetApplicationOfTarget(uint64 guid) const
Definition SpellAuras.h:176
void CallScriptEffectAbsorbHandlers(AuraEffect *aurEff, AuraApplication const *aurApp, DamageInfo &dmgInfo, uint32 &absorbAmount, bool &defaultPrevented)
void CallScriptEffectAfterAbsorbHandlers(AuraEffect *aurEff, AuraApplication const *aurApp, DamageInfo &dmgInfo, uint32 &absorbAmount)
void CallScriptEffectManaShieldHandlers(AuraEffect *aurEff, AuraApplication const *aurApp, DamageInfo &dmgInfo, uint32 &absorbAmount, bool &defaultPrevented)
void CallScriptEffectAfterManaShieldHandlers(AuraEffect *aurEff, AuraApplication const *aurApp, DamageInfo &dmgInfo, uint32 &absorbAmount)
virtual void Remove(AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)=0
void WriteGuidBytes(const ObjectGuid &guid, Offsets... offsets)
Definition ByteBuffer.h:264
bool WriteBit(uint32 bit)
Definition ByteBuffer.h:164
void WriteGuidMask(const ObjectGuid &guid, Offsets... offsets)
Definition ByteBuffer.h:248
void FlushBits()
Definition ByteBuffer.h:154
virtual void OwnerAttackedBy(Unit *)
Definition CreatureAI.h:131
virtual void AttackedBy(Unit *)
Definition CreatureAI.h:111
bool isWorldBoss() const
bool hasLootRecipient() const
Definition Creature.h:549
void SetLootRecipient(Unit *unit)
Definition Creature.cpp:893
CreatureTemplate const * GetCreatureTemplate() const
Definition Creature.h:524
bool IsInEvadeMode() const
Definition Creature.h:478
CreatureAI * AI() const
Definition Creature.h:483
void LowerPlayerDamageReq(uint32 unDamage)
void AddSpellMod(SpellValueMod mod, int32 value)
Definition Unit.h:131
const_iterator end() const
Definition Unit.h:141
StorageType::const_iterator const_iterator
Definition Unit.h:128
const_iterator begin() const
Definition Unit.h:136
void ResistDamage(uint32 amount)
Definition Unit.cpp:112
void AbsorbDamage(uint32 amount)
Definition Unit.cpp:105
uint32 GetResist() const
Definition Unit.h:931
uint32 GetDamage() const
Definition Unit.h:923
uint32 GetAbsorb() const
Definition Unit.h:927
Definition Item.h:202
uint64 GetGUID() const
Definition Object.h:119
uint32 GetUInt32Value(uint16 index) const
Definition Object.cpp:325
Player * ToPlayer()
Definition Object.h:204
bool IsInWorld() const
Definition Object.h:114
uint32 GetGUIDLow() const
Definition Object.h:120
TypeID GetTypeId() const
Definition Object.h:131
float GetFloatValue(uint16 index) const
Definition Object.cpp:337
uint32 GetEntry() const
Definition Object.h:125
Creature * ToCreature()
Definition Object.h:207
bool HasFlag(uint16 index, uint32 flag) const
Definition Object.cpp:1309
void SetUInt32Value(uint16 index, uint32 value)
Definition Object.cpp:1038
Definition Pet.h:28
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float &min_damage, float &max_damage)
void DuelComplete(DuelCompleteType type)
Definition Player.cpp:8277
void CastItemCombatSpell(Unit *target, WeaponAttackType attType, uint32 procVictim, uint32 procEx)
Definition Player.cpp:8913
void DurabilityPointLossForEquipSlot(EquipmentSlots slot)
Definition Player.cpp:5483
Pet * GetPet() const
Definition Player.cpp:15640
bool GetCommandStatus(uint32 command) const
Definition Player.h:1407
Battleground * GetBattleground() const
Definition Player.cpp:19212
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, Unit *unit=NULL)
Definition Player.cpp:21033
DuelInfo * duel
Definition Player.h:2253
void SetDst(float x, float y, float z, float orientation, uint32 mapId=MAPID_INVALID)
Definition Spell.cpp:388
void SetGOTarget(GameObject *target)
Definition Spell.cpp:258
void SetUnitTarget(Unit *target)
Definition Spell.cpp:228
float CalcValueMultiplier(Unit *caster, Spell *spell=NULL) const
uint32 ApplyAuraName
Definition SpellInfo.h:90
Definition Spell.h:289
void SetSpellValue(SpellValueMod mod, int32 value)
Definition Spell.cpp:7659
void prepare(SpellCastTargets const *targets, AuraEffect const *triggeredByAura=NULL)
Definition Spell.cpp:2939
Item * m_CastItem
Definition Spell.h:531
SpellEffectInfo Effects[MAX_SPELL_EFFECTS]
Definition SpellInfo.h:255
uint32 MaxLevel
Definition SpellInfo.h:204
uint32 SpellLevel
Definition SpellInfo.h:206
uint32 GetEffectMechanicMask(uint8 effIndex) const
uint32 AttributesCu
Definition SpellInfo.h:178
uint32 Id
Definition SpellInfo.h:160
uint32 SchoolMask
Definition SpellInfo.h:231
SpellSchoolMask GetSchoolMask() const
uint32 DmgClass
Definition SpellInfo.h:228
uint32 AttributesEx4
Definition SpellInfo.h:168
virtual void DamageTaken(Unit *, uint32 &)
Definition UnitAI.h:216
virtual void DamageDealt(Unit *, uint32 &, DamageEffectType)
Definition UnitAI.h:211
int32 ModifyHealth(int32 val)
Definition Unit.cpp:4023
void ApplyResilience(Unit const *victim, int32 *damage, bool isCrit) const
Definition Unit.cpp:7395
bool IsVehicle() const
Definition Unit.h:1523
void CastStop(uint32 except_spellid=0)
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition Unit.h:2243
Spell * m_currentSpells[CURRENT_MAX_SPELL]
Definition Unit.h:2895
uint32 SpellCriticalDamageBonus(SpellInfo const *spellProto, uint32 damage, Unit *victim)
Definition Unit.cpp:3316
void Kill(Unit *victim, bool durabilityLoss=true)
Definition Unit.cpp:6342
Pet * ToPet()
Definition Unit.h:2803
bool isSpellBlocked(Unit *victim, SpellInfo const *spellProto, WeaponAttackType attackType=WeaponAttackType::BASE_ATTACK)
Definition Unit.cpp:696
bool isBlockCritical()
Definition Unit.cpp:715
void CastSpell(SpellCastTargets const &targets, SpellInfo const *spellInfo, CustomSpellValues const *value, TriggerCastFlags triggerFlags=TRIGGERED_NONE, Item *castItem=NULL, AuraEffect const *triggeredByAura=NULL, uint64 originalCaster=0)
uint32 GetResistance(SpellSchools school) const
Definition Unit.h:1590
void RemoveAurasWithInterruptFlags(uint32 flag, uint32 except=0)
Player * GetSpellModOwner() const
Definition Unit.cpp:5818
void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
Definition Unit.cpp:1927
float GetUnitDodgeChance() const
Definition Unit.cpp:1063
void AddThreat(Unit *victim, float fThreat, SpellSchoolMask schoolMask=SPELL_SCHOOL_MASK_NORMAL, SpellInfo const *threatSpell=NULL)
Definition Unit.cpp:4463
void HandleProcExtraAttackFor(Unit *victim)
Unit * GetCharmer() const
Definition Unit.cpp:2348
void SendSpellDamageImmune(Unit *target, uint32 spellId)
Definition Unit.cpp:1956
void DealDamageMods(Unit *victim, uint32 &damage, uint32 *absorb)
void SendAttackStateUpdate(CalcDamageInfo *damageInfo)
Definition Unit.cpp:1985
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition Unit.cpp:1433
bool haveOffhandWeapon() const
Definition Unit.cpp:350
uint32 MeleeDamageBonusTaken(Unit *attacker, uint32 pdamage, WeaponAttackType attType, SpellInfo const *spellProto=NULL)
bool IsPet() const
Definition Unit.h:1511
MeleeHitOutcome RollMeleeOutcomeAgainst(const Unit *victim, WeaponAttackType attType) const
static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const *spellInfo=NULL, uint8 effIndex=MAX_SPELL_EFFECTS)
uint8 getLevelForTarget(WorldObject const *) const override
Definition Unit.h:1532
void SetLastDamagedTime(time_t val)
Definition Unit.h:2844
void CombatStart(Unit *target, bool initialAggro=true)
uint32 CalcArmorReducedDamage(Unit *victim, const uint32 damage, SpellInfo const *spellInfo, WeaponAttackType attackType=WeaponAttackType::MAX_ATTACK)
int32 GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const
bool IsAlive() const
Definition Unit.h:2032
uint32 m_removedAurasCount
Definition Unit.h:2903
void SetHealth(uint32 val)
Definition Unit.cpp:5162
bool IsStandState() const
Definition Unit.cpp:5896
virtual uint32 GetBlockPercent() const
Definition Unit.h:1812
void DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss)
uint16 GetMaxSkillValueForLevel(Unit const *target=NULL) const
Definition Unit.h:1757
int32 ModifyPower(Powers power, int32 val)
Definition Unit.cpp:4081
uint32 m_extraAttacks
Definition Unit.h:1453
uint64 GetCharmerGUID() const
Definition Unit.h:2071
uint32 getAttackTimer(WeaponAttackType type) const
Definition Unit.h:1428
Unit * GetMeleeHitRedirectTarget(Unit *victim, SpellInfo const *spellInfo=NULL)
Definition Unit.cpp:2751
void CalcAbsorbResist(Unit *victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, uint32 const damage, uint32 *absorb, uint32 *resist, SpellInfo const *spellInfo=NULL)
uint32 DealDamage(Unit *victim, uint32 damage, CleanDamage const *cleanDamage=NULL, DamageEffectType damagetype=DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask=SPELL_SCHOOL_MASK_NORMAL, SpellInfo const *spellProto=NULL, bool durabilityLoss=true)
uint32 CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct)
void CalcHealAbsorb(Unit *victim, SpellInfo const *spellInfo, uint32 &healAmount, uint32 &absorb)
uint32 CalcSpellResistance(Unit *victim, SpellSchoolMask schoolMask, SpellInfo const *spellInfo) const
uint32 GetHealth() const
Definition Unit.h:1600
void RewardRage(uint32 baseRage, bool attacker)
Definition Unit.cpp:8914
float GetTotalAuraMultiplier(AuraType auratype) const
bool HasAuraType(AuraType auraType) const
void setAttackTimer(WeaponAttackType type, uint32 time)
Definition Unit.h:1423
uint32 MeleeDamageBonusDone(Unit *pVictim, uint32 damage, WeaponAttackType attType, SpellInfo const *spellProto=NULL)
uint32 GetArmor() const
Definition Unit.h:1581
uint32 GetAttackTime(WeaponAttackType att) const
Definition Unit.cpp:4122
uint32 SpellDamageBonusDone(Unit *victim, SpellInfo const *spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack=1) const
void SendSpellNonMeleeDamageLog(SpellNonMeleeDamage *log)
Definition Unit.cpp:1766
float GetUnitBlockChance() const
Definition Unit.cpp:1126
bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const
Definition Unit.cpp:3415
bool IsAIEnabled
Definition Unit.h:2735
void DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
bool HasUnitState(const uint32 f) const
Definition Unit.h:1485
void CastCustomSpell(Unit *victim, uint32 spellId, int32 const *bp0, int32 const *bp1, int32 const *bp2, bool triggered, Item *castItem=NULL, AuraEffect const *triggeredByAura=NULL, uint64 originalCaster=0)
Unit(bool isWorldObject)
Definition Unit.cpp:142
int32 GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const
uint32 SpellDamageBonusTaken(Unit *caster, SpellInfo const *spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack=1) const
void CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 damage, SpellInfo const *spellInfo, WeaponAttackType attackType=WeaponAttackType::BASE_ATTACK, bool crit=false)
UnitAI * GetAI()
Definition Unit.h:1393
SpellInfo const * m_overrideAutoattackSpellInfo
Definition Unit.h:2896
void AttackerStateUpdate(Unit *victim, WeaponAttackType attType=WeaponAttackType::BASE_ATTACK, bool extra=false)
uint64 GetOwnerGUID() const
Definition Unit.h:2050
bool IsControlledByPlayer() const
Definition Unit.h:2100
float GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask) const
void HandleEmoteCommand(uint32 anim_id)
virtual SpellSchoolMask GetMeleeDamageSchoolMask() const
Definition Unit.cpp:5801
float GetUnitParryChance() const
Definition Unit.cpp:1083
Powers getPowerType() const
Definition Unit.h:1651
int32 GetTotalAuraModifier(AuraType auratype) const
uint8 getLevel() const
Definition Unit.h:1528
std::list< AuraEffect * > AuraEffectList
Definition Unit.h:1383
uint32 SpellNonMeleeDamageLog(Unit *victim, uint32 spellID, uint32 damage)
float MeleeSpellMissChance(Unit const *victim, WeaponAttackType attType, uint32 spellId) const
Definition Unit.cpp:7421
float CalculateLevelPenalty(SpellInfo const *spellProto) const
void ProcDamageAndSpell(Unit *victim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType=WeaponAttackType::BASE_ATTACK, SpellInfo const *procSpell=NULL, SpellInfo const *procAura=NULL)
Definition UnitProc.cpp:53
void InterruptSpell(CurrentSpellTypes spellType, bool withDelayed=true, bool withInstant=true)
Definition Unit.cpp:1365
void CalculateMeleeDamage(Unit *victim, uint32 damage, CalcDamageInfo *damageInfo, WeaponAttackType attackType=WeaponAttackType::BASE_ATTACK)
float GetUnitCriticalChance(WeaponAttackType attackType, const Unit *victim) const
Definition Unit.cpp:1155
void CombatStopWithPets(bool includingCast=false)
SpellMissInfo SpellHitResult(Unit *victim, SpellInfo const *spellInfo, bool canReflect=false)
Definition Unit.cpp:1007
bool IsWithinLOSInMap(WorldObject const *obj) const
Definition Object.cpp:1656
virtual void SendMessageToSet(WorldPacket *data, bool self)
Definition Object.cpp:2485
@ SMSG_EMOTE
Definition Opcodes.h:647
@ SMSG_SPELLDAMAGESHIELD
Definition Opcodes.h:970
#define sWorld
Definition World.h:910
@ RATE_DURABILITY_LOSS_DAMAGE
Definition World.h:435
uint32 damageSchoolMask
Definition Unit.h:1011
uint32 blocked_amount
Definition Unit.h:1015
MeleeHitOutcome hitOutCome
Definition Unit.h:1024
uint32 procAttacker
Definition Unit.h:1020
uint32 procVictim
Definition Unit.h:1021
uint32 cleanDamage
Definition Unit.h:1023
VictimState TargetState
Definition Unit.h:1017
uint32 absorb
Definition Unit.h:1013
uint32 resist
Definition Unit.h:1014
uint32 damage
Definition Unit.h:1012
uint32 procEx
Definition Unit.h:1022
uint32 HitInfo
Definition Unit.h:1016
Unit * attacker
Definition Unit.h:1009
Unit * target
Definition Unit.h:1010
WeaponAttackType attackType
Definition Unit.h:1019
uint32 absorbed_damage
Definition Unit.h:868
WeaponAttackType attackType
Definition Unit.h:871
uint32 flags_extra
Definition Creature.h:129
bool isMounted
Definition Player.h:463
Player * opponent
Definition Player.h:459
float GetOrientation() const
Definition Object.h:331
bool HasInArc(float arcangle, Position const *pos, float border=2.0f) const
Definition Object.cpp:1898
uint32 schoolMask
Definition Unit.h:1040
uint32 cleanDamage
Definition Unit.h:1048