[6928] Corrected the handling of evade and threat for creature summoned pets. Should...
[getmangos.git] / src / game / Unit.cpp
blob829555c2e41a50e552a0392bde83034380bd7466
1 /*
2 * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "Log.h"
21 #include "Opcodes.h"
22 #include "WorldPacket.h"
23 #include "WorldSession.h"
24 #include "World.h"
25 #include "ObjectMgr.h"
26 #include "SpellMgr.h"
27 #include "Unit.h"
28 #include "QuestDef.h"
29 #include "Player.h"
30 #include "Creature.h"
31 #include "Spell.h"
32 #include "Group.h"
33 #include "SpellAuras.h"
34 #include "MapManager.h"
35 #include "ObjectAccessor.h"
36 #include "CreatureAI.h"
37 #include "Formulas.h"
38 #include "Pet.h"
39 #include "Util.h"
40 #include "Totem.h"
41 #include "BattleGround.h"
42 #include "InstanceSaveMgr.h"
43 #include "GridNotifiersImpl.h"
44 #include "CellImpl.h"
45 #include "Path.h"
47 #include <math.h>
49 float baseMoveSpeed[MAX_MOVE_TYPE] =
51 2.5f, // MOVE_WALK
52 7.0f, // MOVE_RUN
53 1.25f, // MOVE_RUN_BACK
54 4.722222f, // MOVE_SWIM
55 4.5f, // MOVE_SWIM_BACK
56 3.141594f, // MOVE_TURN_RATE
57 7.0f, // MOVE_FLIGHT
58 4.5f, // MOVE_FLIGHT_BACK
61 // auraTypes contains attacker auras capable of proc'ing cast auras
62 static Unit::AuraTypeSet GenerateAttakerProcCastAuraTypes()
64 static Unit::AuraTypeSet auraTypes;
65 auraTypes.insert(SPELL_AURA_DUMMY);
66 auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL);
67 auraTypes.insert(SPELL_AURA_MOD_HASTE);
68 auraTypes.insert(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
69 return auraTypes;
72 // auraTypes contains victim auras capable of proc'ing cast auras
73 static Unit::AuraTypeSet GenerateVictimProcCastAuraTypes()
75 static Unit::AuraTypeSet auraTypes;
76 auraTypes.insert(SPELL_AURA_DUMMY);
77 auraTypes.insert(SPELL_AURA_PRAYER_OF_MENDING);
78 auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL);
79 return auraTypes;
82 // auraTypes contains auras capable of proc effect/damage (but not cast) for attacker
83 static Unit::AuraTypeSet GenerateAttakerProcEffectAuraTypes()
85 static Unit::AuraTypeSet auraTypes;
86 auraTypes.insert(SPELL_AURA_MOD_DAMAGE_DONE);
87 auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE);
88 auraTypes.insert(SPELL_AURA_MOD_CASTING_SPEED);
89 auraTypes.insert(SPELL_AURA_MOD_RATING);
90 return auraTypes;
93 // auraTypes contains auras capable of proc effect/damage (but not cast) for victim
94 static Unit::AuraTypeSet GenerateVictimProcEffectAuraTypes()
96 static Unit::AuraTypeSet auraTypes;
97 auraTypes.insert(SPELL_AURA_MOD_RESISTANCE);
98 auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE);
99 auraTypes.insert(SPELL_AURA_MOD_PARRY_PERCENT);
100 auraTypes.insert(SPELL_AURA_MOD_BLOCK_PERCENT);
101 auraTypes.insert(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
102 return auraTypes;
105 static Unit::AuraTypeSet attackerProcCastAuraTypes = GenerateAttakerProcCastAuraTypes();
106 static Unit::AuraTypeSet attackerProcEffectAuraTypes = GenerateAttakerProcEffectAuraTypes();
108 static Unit::AuraTypeSet victimProcCastAuraTypes = GenerateVictimProcCastAuraTypes();
109 static Unit::AuraTypeSet victimProcEffectAuraTypes = GenerateVictimProcEffectAuraTypes();
111 // auraTypes contains auras capable of proc'ing for attacker and victim
112 static Unit::AuraTypeSet GenerateProcAuraTypes()
114 Unit::AuraTypeSet auraTypes;
115 auraTypes.insert(attackerProcCastAuraTypes.begin(),attackerProcCastAuraTypes.end());
116 auraTypes.insert(attackerProcEffectAuraTypes.begin(),attackerProcEffectAuraTypes.end());
117 auraTypes.insert(victimProcCastAuraTypes.begin(),victimProcCastAuraTypes.end());
118 auraTypes.insert(victimProcEffectAuraTypes.begin(),victimProcEffectAuraTypes.end());
119 return auraTypes;
122 static Unit::AuraTypeSet procAuraTypes = GenerateProcAuraTypes();
124 bool IsPassiveStackableSpell( uint32 spellId )
126 if(!IsPassiveSpell(spellId))
127 return false;
129 SpellEntry const* spellProto = sSpellStore.LookupEntry(spellId);
130 if(!spellProto)
131 return false;
133 for(int j = 0; j < 3; ++j)
135 if(std::find(procAuraTypes.begin(),procAuraTypes.end(),spellProto->EffectApplyAuraName[j])!=procAuraTypes.end())
136 return false;
139 return true;
142 Unit::Unit()
143 : WorldObject(), i_motionMaster(this), m_ThreatManager(this), m_HostilRefManager(this)
145 m_objectType |= TYPEMASK_UNIT;
146 m_objectTypeId = TYPEID_UNIT;
147 // 2.3.2 - 0x70
148 m_updateFlag = (UPDATEFLAG_HIGHGUID | UPDATEFLAG_LIVING | UPDATEFLAG_HASPOSITION);
150 m_attackTimer[BASE_ATTACK] = 0;
151 m_attackTimer[OFF_ATTACK] = 0;
152 m_attackTimer[RANGED_ATTACK] = 0;
153 m_modAttackSpeedPct[BASE_ATTACK] = 1.0f;
154 m_modAttackSpeedPct[OFF_ATTACK] = 1.0f;
155 m_modAttackSpeedPct[RANGED_ATTACK] = 1.0f;
157 m_extraAttacks = 0;
159 m_state = 0;
160 m_form = FORM_NONE;
161 m_deathState = ALIVE;
163 for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
164 m_currentSpells[i] = NULL;
166 m_addDmgOnce = 0;
168 for(int i = 0; i < MAX_TOTEM; ++i)
169 m_TotemSlot[i] = 0;
171 m_ObjectSlot[0] = m_ObjectSlot[1] = m_ObjectSlot[2] = m_ObjectSlot[3] = 0;
172 //m_Aura = NULL;
173 //m_AurasCheck = 2000;
174 //m_removeAuraTimer = 4;
175 //tmpAura = NULL;
176 waterbreath = false;
178 m_Visibility = VISIBILITY_ON;
180 m_detectInvisibilityMask = 0;
181 m_invisibilityMask = 0;
182 m_transform = 0;
183 m_ShapeShiftFormSpellId = 0;
184 m_canModifyStats = false;
186 for (int i = 0; i < MAX_SPELL_IMMUNITY; i++)
187 m_spellImmune[i].clear();
188 for (int i = 0; i < UNIT_MOD_END; i++)
190 m_auraModifiersGroup[i][BASE_VALUE] = 0.0f;
191 m_auraModifiersGroup[i][BASE_PCT] = 1.0f;
192 m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f;
193 m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f;
195 // implement 50% base damage from offhand
196 m_auraModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f;
198 for (int i = 0; i < 3; i++)
200 m_weaponDamage[i][MINDAMAGE] = BASE_MINDAMAGE;
201 m_weaponDamage[i][MAXDAMAGE] = BASE_MAXDAMAGE;
203 for (int i = 0; i < MAX_STATS; i++)
204 m_createStats[i] = 0.0f;
206 m_attacking = NULL;
207 m_modMeleeHitChance = 0.0f;
208 m_modRangedHitChance = 0.0f;
209 m_modSpellHitChance = 0.0f;
210 m_baseSpellCritChance = 5;
212 m_CombatTimer = 0;
213 m_lastManaUse = 0;
215 //m_victimThreat = 0.0f;
216 for (int i = 0; i < MAX_SPELL_SCHOOL; ++i)
217 m_threatModifier[i] = 1.0f;
218 m_isSorted = true;
219 for (int i = 0; i < MAX_MOVE_TYPE; ++i)
220 m_speed_rate[i] = 1.0f;
222 m_removedAuras = 0;
223 m_charmInfo = NULL;
224 m_unit_movement_flags = 0;
226 // remove aurastates allowing special moves
227 for(int i=0; i < MAX_REACTIVE; ++i)
228 m_reactiveTimer[i] = 0;
231 Unit::~Unit()
233 // set current spells as deletable
234 for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
236 if (m_currentSpells[i])
238 m_currentSpells[i]->SetReferencedFromCurrent(false);
239 m_currentSpells[i] = NULL;
243 RemoveAllGameObjects();
244 RemoveAllDynObjects();
246 if(m_charmInfo) delete m_charmInfo;
249 void Unit::Update( uint32 p_time )
251 /*if(p_time > m_AurasCheck)
253 m_AurasCheck = 2000;
254 _UpdateAura();
255 }else
256 m_AurasCheck -= p_time;*/
258 // WARNING! Order of execution here is important, do not change.
259 // Spells must be processed with event system BEFORE they go to _UpdateSpells.
260 // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad.
261 m_Events.Update( p_time );
262 _UpdateSpells( p_time );
264 // update combat timer only for players and pets
265 if (isInCombat() && (GetTypeId() == TYPEID_PLAYER || ((Creature*)this)->isPet() || ((Creature*)this)->isCharmed()))
267 // Check UNIT_STAT_MELEE_ATTACKING or UNIT_STAT_CHASE (without UNIT_STAT_FOLLOW in this case) so pets can reach far away
268 // targets without stopping half way there and running off.
269 // These flags are reset after target dies or another command is given.
270 if( m_HostilRefManager.isEmpty() )
272 // m_CombatTimer set at aura start and it will be freeze until aura removing
273 if ( m_CombatTimer <= p_time )
274 ClearInCombat();
275 else
276 m_CombatTimer -= p_time;
280 if(uint32 base_att = getAttackTimer(BASE_ATTACK))
282 setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time) );
285 // update abilities available only for fraction of time
286 UpdateReactives( p_time );
288 ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, GetHealth() < GetMaxHealth()*0.20f);
289 ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, GetHealth() < GetMaxHealth()*0.35f);
291 i_motionMaster.UpdateMotion(p_time);
294 bool Unit::haveOffhandWeapon() const
296 if(GetTypeId() == TYPEID_PLAYER)
297 return ((Player*)this)->GetWeaponForAttack(OFF_ATTACK,true);
298 else
299 return false;
302 void Unit::SendMonsterMoveWithSpeedToCurrentDestination(Player* player)
304 float x, y, z;
305 if(GetMotionMaster()->GetDestination(x, y, z))
306 SendMonsterMoveWithSpeed(x, y, z, GetUnitMovementFlags(), 0, player);
309 void Unit::SendMonsterMoveWithSpeed(float x, float y, float z, uint32 MovementFlags, uint32 transitTime, Player* player)
311 if (!transitTime)
313 float dx = x - GetPositionX();
314 float dy = y - GetPositionY();
315 float dz = z - GetPositionZ();
317 float dist = ((dx*dx) + (dy*dy) + (dz*dz));
318 if(dist<0)
319 dist = 0;
320 else
321 dist = sqrt(dist);
323 double speed = GetSpeed((MovementFlags & MOVEMENTFLAG_WALK_MODE) ? MOVE_WALK : MOVE_RUN);
324 if(speed<=0)
325 speed = 2.5f;
326 speed *= 0.001f;
327 transitTime = static_cast<uint32>(dist / speed + 0.5);
329 //float orientation = (float)atan2((double)dy, (double)dx);
330 SendMonsterMove(x, y, z, 0, MovementFlags, transitTime, player);
333 void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player)
335 WorldPacket data( SMSG_MONSTER_MOVE, (41 + GetPackGUID().size()) );
336 data.append(GetPackGUID());
338 // Point A, starting location
339 data << GetPositionX() << GetPositionY() << GetPositionZ();
340 // unknown field - unrelated to orientation
341 // seems to increment about 1000 for every 1.7 seconds
342 // for now, we'll just use mstime
343 data << getMSTime();
345 data << uint8(type); // unknown
346 switch(type)
348 case 0: // normal packet
349 break;
350 case 1: // stop packet
351 SendMessageToSet( &data, true );
352 return;
353 case 2: // not used currently
354 data << float(0);
355 data << float(0);
356 data << float(0);
357 break;
358 case 3: // not used currently
359 data << uint64(0); // probably target guid
360 break;
361 case 4: // not used currently
362 data << float(0); // probably orientation
363 break;
366 //Movement Flags (0x0 = walk, 0x100 = run, 0x200 = fly/swim)
367 data << uint32(MovementFlags);
369 data << Time; // Time in between points
370 data << uint32(1); // 1 single waypoint
371 data << NewPosX << NewPosY << NewPosZ; // the single waypoint Point B
373 if(player)
374 player->GetSession()->SendPacket(&data);
375 else
376 SendMessageToSet( &data, true );
379 void Unit::SendMonsterMoveByPath(Path const& path, uint32 start, uint32 end, uint32 MovementFlags)
381 uint32 traveltime = uint32(path.GetTotalLength(start, end) * 32);
383 uint32 pathSize = end-start;
385 WorldPacket data( SMSG_MONSTER_MOVE, (GetPackGUID().size()+4+4+4+4+1+4+4+4+pathSize*4*3) );
386 data.append(GetPackGUID());
387 data << GetPositionX();
388 data << GetPositionY();
389 data << GetPositionZ();
391 // unknown field - unrelated to orientation
392 // seems to increment about 1000 for every 1.7 seconds
393 // for now, we'll just use mstime
394 data << getMSTime();
396 data << uint8( 0 );
397 data << uint32( MovementFlags );
398 data << uint32( traveltime );
399 data << uint32( pathSize );
400 data.append( (char*)path.GetNodes(start), pathSize * 4 * 3 );
402 //WPAssert( data.size() == 37 + pathnodes.Size( ) * 4 * 3 );
403 SendMessageToSet(&data, true);
406 void Unit::resetAttackTimer(WeaponAttackType type)
408 m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]);
411 bool Unit::canReachWithAttack(Unit *pVictim) const
413 assert(pVictim);
414 float reach = GetFloatValue(UNIT_FIELD_COMBATREACH);
415 if( reach <= 0.0f )
416 reach = 1.0f;
417 return IsWithinDistInMap(pVictim, reach);
420 void Unit::RemoveSpellsCausingAura(AuraType auraType)
422 if (auraType >= TOTAL_AURAS) return;
423 AuraList::iterator iter, next;
424 for (iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end(); iter = next)
426 next = iter;
427 ++next;
429 if (*iter)
431 RemoveAurasDueToSpell((*iter)->GetId());
432 if (!m_modAuras[auraType].empty())
433 next = m_modAuras[auraType].begin();
434 else
435 return;
440 bool Unit::HasAuraType(AuraType auraType) const
442 return (!m_modAuras[auraType].empty());
445 /* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */
446 void Unit::RemoveSpellbyDamageTaken(AuraType auraType, uint32 damage)
448 if(!HasAuraType(auraType))
449 return;
451 // The chance to dispel an aura depends on the damage taken with respect to the casters level.
452 uint32 max_dmg = getLevel() > 8 ? 25 * getLevel() - 150 : 50;
453 float chance = float(damage) / max_dmg * 100.0f;
454 if (roll_chance_f(chance))
455 RemoveSpellsCausingAura(auraType);
458 uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const *spellProto, bool durabilityLoss)
460 if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
461 return 0;
463 //You don't lose health from damage taken from another player while in a sanctuary
464 //You still see it in the combat log though
465 if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
467 const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
468 if(area && area->flags & AREA_FLAG_SANCTUARY) //sanctuary
469 return 0;
472 // remove affects from victim (including from 0 damage and DoTs)
473 if(pVictim != this)
474 pVictim->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
476 // remove affects from attacker at any non-DoT damage (including 0 damage)
477 if( damagetype != DOT)
479 RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
480 RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
482 if(pVictim != this)
483 RemoveSpellsCausingAura(SPELL_AURA_MOD_INVISIBILITY);
485 if(pVictim->GetTypeId() == TYPEID_PLAYER && !pVictim->IsStandState() && !pVictim->hasUnitState(UNIT_STAT_STUNNED))
486 pVictim->SetStandState(PLAYER_STATE_NONE);
489 //Script Event damage Deal
490 if( GetTypeId()== TYPEID_UNIT && ((Creature *)this)->AI())
491 ((Creature *)this)->AI()->DamageDeal(pVictim, damage);
492 //Script Event damage taken
493 if( pVictim->GetTypeId()== TYPEID_UNIT && ((Creature *)pVictim)->AI() )
494 ((Creature *)pVictim)->AI()->DamageTaken(this, damage);
496 if(!damage)
498 // Rage from physical damage received .
499 if(cleanDamage && cleanDamage->damage && (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL) && pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->getPowerType() == POWER_RAGE))
500 ((Player*)pVictim)->RewardRage(cleanDamage->damage, 0, false);
502 return 0;
505 pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR, damage);
506 // root type spells do not dispel the root effect
507 if(!spellProto || spellProto->Mechanic != MECHANIC_ROOT)
508 pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT, damage);
510 if(pVictim->GetTypeId() != TYPEID_PLAYER)
512 // no xp,health if type 8 /critters/
513 if ( pVictim->GetCreatureType() == CREATURE_TYPE_CRITTER)
515 pVictim->setDeathState(JUST_DIED);
516 pVictim->SetHealth(0);
518 // allow loot only if has loot_id in creature_template
519 CreatureInfo const* cInfo = ((Creature*)pVictim)->GetCreatureInfo();
520 if(cInfo && cInfo->lootid)
521 pVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
523 // some critters required for quests
524 if(GetTypeId() == TYPEID_PLAYER)
525 ((Player*)this)->KilledMonster(pVictim->GetEntry(),pVictim->GetGUID());
527 return damage;
530 if(!pVictim->isInCombat() && ((Creature*)pVictim)->AI())
531 ((Creature*)pVictim)->AI()->AttackStart(this);
534 DEBUG_LOG("DealDamageStart");
536 uint32 health = pVictim->GetHealth();
537 sLog.outDetail("deal dmg:%d to health:%d ",damage,health);
539 // duel ends when player has 1 or less hp
540 bool duel_hasEnded = false;
541 if(pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->duel && damage >= (health-1))
543 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
544 if(((Player*)pVictim)->duel->opponent==this || ((Player*)pVictim)->duel->opponent->GetGUID() == GetOwnerGUID())
545 damage = health-1;
547 duel_hasEnded = true;
549 //Get in CombatState
550 if(pVictim != this && damagetype != DOT)
552 SetInCombatWith(pVictim);
553 pVictim->SetInCombatWith(this);
555 if(Player* attackedPlayer = pVictim->GetCharmerOrOwnerPlayerOrPlayerItself())
556 SetContestedPvP(attackedPlayer);
559 // Rage from Damage made (only from direct weapon damage)
560 if( cleanDamage && damagetype==DIRECT_DAMAGE && this != pVictim && GetTypeId() == TYPEID_PLAYER && (getPowerType() == POWER_RAGE))
562 uint32 weaponSpeedHitFactor;
564 switch(cleanDamage->attackType)
566 case BASE_ATTACK:
568 if(cleanDamage->hitOutCome == MELEE_HIT_CRIT)
569 weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 7);
570 else
571 weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 3.5f);
573 ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true);
575 break;
577 case OFF_ATTACK:
579 if(cleanDamage->hitOutCome == MELEE_HIT_CRIT)
580 weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 3.5f);
581 else
582 weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 1.75f);
584 ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true);
586 break;
588 case RANGED_ATTACK:
589 break;
593 if(pVictim->GetTypeId() == TYPEID_PLAYER && GetTypeId() == TYPEID_PLAYER)
595 if(((Player*)pVictim)->InBattleGround())
597 Player *killer = ((Player*)this);
598 if(killer != ((Player*)pVictim))
599 if(BattleGround *bg = killer->GetBattleGround())
600 bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damage);
604 if (pVictim->GetTypeId() == TYPEID_UNIT && !((Creature*)pVictim)->isPet() && !((Creature*)pVictim)->hasLootRecipient())
605 ((Creature*)pVictim)->SetLootRecipient(this);
606 if (health <= damage)
608 DEBUG_LOG("DealDamage: victim just died");
610 // find player: owner of controlled `this` or `this` itself maybe
611 Player *player = GetCharmerOrOwnerPlayerOrPlayerItself();
613 if(pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->GetLootRecipient())
614 player = ((Creature*)pVictim)->GetLootRecipient();
615 // Reward player, his pets, and group/raid members
616 // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop)
617 if(player && player!=pVictim)
618 if(player->RewardPlayerAndGroupAtKill(pVictim))
619 player->ProcDamageAndSpell(pVictim,PROC_FLAG_KILL_XP_GIVER,PROC_FLAG_NONE);
621 DEBUG_LOG("DealDamageAttackStop");
623 // stop combat
624 pVictim->CombatStop();
625 pVictim->getHostilRefManager().deleteReferences();
627 bool damageFromSpiritOfRedemtionTalent = spellProto && spellProto->Id == 27795;
629 // if talent known but not triggered (check priest class for speedup check)
630 Aura* spiritOfRedemtionTalentReady = NULL;
631 if( !damageFromSpiritOfRedemtionTalent && // not called from SPELL_AURA_SPIRIT_OF_REDEMPTION
632 pVictim->GetTypeId()==TYPEID_PLAYER && pVictim->getClass()==CLASS_PRIEST )
634 AuraList const& vDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
635 for(AuraList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); ++itr)
637 if((*itr)->GetSpellProto()->SpellIconID==1654)
639 spiritOfRedemtionTalentReady = *itr;
640 break;
645 DEBUG_LOG("SET JUST_DIED");
646 if(!spiritOfRedemtionTalentReady)
647 pVictim->setDeathState(JUST_DIED);
649 DEBUG_LOG("DealDamageHealth1");
651 if(spiritOfRedemtionTalentReady)
653 // save value before aura remove
654 uint32 ressSpellId = pVictim->GetUInt32Value(PLAYER_SELF_RES_SPELL);
655 if(!ressSpellId)
656 ressSpellId = ((Player*)pVictim)->GetResurrectionSpellId();
658 //Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers)
659 pVictim->RemoveAllAurasOnDeath();
661 // restore for use at real death
662 pVictim->SetUInt32Value(PLAYER_SELF_RES_SPELL,ressSpellId);
664 // FORM_SPIRITOFREDEMPTION and related auras
665 pVictim->CastSpell(pVictim,27827,true,NULL,spiritOfRedemtionTalentReady);
667 else
668 pVictim->SetHealth(0);
670 // remember victim PvP death for corpse type and corpse reclaim delay
671 // at original death (not at SpiritOfRedemtionTalent timeout)
672 if( pVictim->GetTypeId()==TYPEID_PLAYER && !damageFromSpiritOfRedemtionTalent )
673 ((Player*)pVictim)->SetPvPDeath(player!=NULL);
675 // Call KilledUnit for creatures
676 if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI())
677 ((Creature*)this)->AI()->KilledUnit(pVictim);
679 // 10% durability loss on death
680 // clean InHateListOf
681 if (pVictim->GetTypeId() == TYPEID_PLAYER)
683 // only if not player and not controlled by player pet. And not at BG
684 if (durabilityLoss && !player && !((Player*)pVictim)->InBattleGround())
686 DEBUG_LOG("We are dead, loosing 10 percents durability");
687 ((Player*)pVictim)->DurabilityLossAll(0.10f,false);
688 // durability lost message
689 WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0);
690 ((Player*)pVictim)->GetSession()->SendPacket(&data);
693 else // creature died
695 DEBUG_LOG("DealDamageNotPlayer");
696 Creature *cVictim = (Creature*)pVictim;
698 if(!cVictim->isPet())
700 cVictim->DeleteThreatList();
701 cVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
703 // Call creature just died function
704 if (cVictim->AI())
705 cVictim->AI()->JustDied(this);
707 // Dungeon specific stuff, only applies to players killing creatures
708 if(cVictim->GetInstanceId())
710 Map *m = cVictim->GetMap();
711 Player *creditedPlayer = GetCharmerOrOwnerPlayerOrPlayerItself();
712 // TODO: do instance binding anyway if the charmer/owner is offline
714 if(m->IsDungeon() && creditedPlayer)
716 if(m->IsRaid() || m->IsHeroic())
718 if(cVictim->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND)
719 ((InstanceMap *)m)->PermBindAllPlayers(creditedPlayer);
721 else
723 // the reset time is set but not added to the scheduler
724 // until the players leave the instance
725 time_t resettime = cVictim->GetRespawnTimeEx() + 2 * HOUR;
726 if(InstanceSave *save = sInstanceSaveManager.GetInstanceSave(cVictim->GetInstanceId()))
727 if(save->GetResetTime() < resettime) save->SetResetTime(resettime);
733 // last damage from non duel opponent or opponent controlled creature
734 if(duel_hasEnded)
736 assert(pVictim->GetTypeId()==TYPEID_PLAYER);
737 Player *he = (Player*)pVictim;
739 assert(he->duel);
741 he->duel->opponent->CombatStopWithPets(true);
742 he->CombatStopWithPets(true);
744 he->DuelComplete(DUEL_INTERUPTED);
747 // battleground things (do this at the end, so the death state flag will be properly set to handle in the bg->handlekill)
748 if(pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->InBattleGround())
750 Player *killed = ((Player*)pVictim);
751 if(BattleGround *bg = killed->GetBattleGround())
752 if(player)
753 bg->HandleKillPlayer(killed, player);
754 //later we can add support for creature->player kills here i'm
755 //not sure, but i guess those kills also get counted in av
756 //else if(GetTypeId() == TYPEID_UNIT)
757 // bg->HandleKillPlayer(killed,(Creature*)this);
760 else // if (health <= damage)
762 DEBUG_LOG("DealDamageAlive");
764 pVictim->ModifyHealth(- (int32)damage);
766 // Check if health is below 20% (apply damage before to prevent case when after ProcDamageAndSpell health < damage
767 if(pVictim->GetHealth()*5 < pVictim->GetMaxHealth())
769 uint32 procVictim = PROC_FLAG_NONE;
771 // if just dropped below 20% (for CheatDeath)
772 if((pVictim->GetHealth()+damage)*5 > pVictim->GetMaxHealth())
773 procVictim = PROC_FLAG_LOW_HEALTH;
775 ProcDamageAndSpell(pVictim,PROC_FLAG_TARGET_LOW_HEALTH,procVictim);
778 if(damagetype != DOT)
780 if(getVictim())
782 // if have target and damage pVictim just call AI reaction
783 if(pVictim != getVictim() && pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->AI())
784 ((Creature*)pVictim)->AI()->AttackedBy(this);
786 else
788 // if not have main target then attack state with target (including AI call)
789 //start melee attacks only after melee hit
790 Attack(pVictim,(damagetype == DIRECT_DAMAGE));
794 // polymorphed and other negative transformed cases
795 if(pVictim->getTransForm() && pVictim->hasUnitState(UNIT_STAT_CONFUSED))
796 pVictim->RemoveAurasDueToSpell(pVictim->getTransForm());
798 if(damagetype == DIRECT_DAMAGE|| damagetype == SPELL_DIRECT_DAMAGE)
799 pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE);
801 if (pVictim->GetTypeId() != TYPEID_PLAYER)
803 if(spellProto && IsDamageToThreatSpell(spellProto))
804 pVictim->AddThreat(this, damage*2, damageSchoolMask, spellProto);
805 else
806 pVictim->AddThreat(this, damage, damageSchoolMask, spellProto);
808 else // victim is a player
810 // Rage from damage received
811 if(this != pVictim && pVictim->getPowerType() == POWER_RAGE)
813 uint32 rage_damage = damage + (cleanDamage ? cleanDamage->damage : 0);
814 ((Player*)pVictim)->RewardRage(rage_damage, 0, false);
817 // random durability for items (HIT TAKEN)
818 if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_DAMAGE)))
820 EquipmentSlots slot = EquipmentSlots(urand(0,EQUIPMENT_SLOT_END-1));
821 ((Player*)pVictim)->DurabilityPointLossForEquipSlot(slot);
825 if(GetTypeId()==TYPEID_PLAYER)
827 // random durability for items (HIT DONE)
828 if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_DAMAGE)))
830 EquipmentSlots slot = EquipmentSlots(urand(0,EQUIPMENT_SLOT_END-1));
831 ((Player*)this)->DurabilityPointLossForEquipSlot(slot);
835 // TODO: Store auras by interrupt flag to speed this up.
836 AuraMap& vAuras = pVictim->GetAuras();
837 for (AuraMap::iterator i = vAuras.begin(), next; i != vAuras.end(); i = next)
839 const SpellEntry *se = i->second->GetSpellProto();
840 next = i; ++next;
841 if( se->AuraInterruptFlags & AURA_INTERRUPT_FLAG_DAMAGE )
843 bool remove = true;
844 if (se->procFlags & (1<<3))
846 if (!roll_chance_i(se->procChance))
847 remove = false;
849 if (remove)
851 pVictim->RemoveAurasDueToSpell(i->second->GetId());
852 // FIXME: this may cause the auras with proc chance to be rerolled several times
853 next = vAuras.begin();
858 if (damagetype != NODAMAGE && damage && pVictim->GetTypeId() == TYPEID_PLAYER)
860 if( damagetype != DOT )
862 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
864 // skip channeled spell (processed differently below)
865 if (i == CURRENT_CHANNELED_SPELL)
866 continue;
868 if(Spell* spell = pVictim->m_currentSpells[i])
869 if(spell->getState() == SPELL_STATE_PREPARING)
870 spell->Delayed();
874 if(Spell* spell = pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL])
876 if (spell->getState() == SPELL_STATE_CASTING)
878 uint32 channelInterruptFlags = spell->m_spellInfo->ChannelInterruptFlags;
879 if( channelInterruptFlags & CHANNEL_FLAG_DELAY )
881 if(pVictim!=this) //don't shorten the duration of channeling if you damage yourself
882 spell->DelayedChannel();
884 else if( (channelInterruptFlags & (CHANNEL_FLAG_DAMAGE | CHANNEL_FLAG_DAMAGE2)) )
886 sLog.outDetail("Spell %u canceled at damage!",spell->m_spellInfo->Id);
887 pVictim->InterruptSpell(CURRENT_CHANNELED_SPELL);
890 else if (spell->getState() == SPELL_STATE_DELAYED)
891 // break channeled spell in delayed state on damage
893 sLog.outDetail("Spell %u canceled at damage!",spell->m_spellInfo->Id);
894 pVictim->InterruptSpell(CURRENT_CHANNELED_SPELL);
899 // last damage from duel opponent
900 if(duel_hasEnded)
902 assert(pVictim->GetTypeId()==TYPEID_PLAYER);
903 Player *he = (Player*)pVictim;
905 assert(he->duel);
907 he->SetHealth(1);
909 he->duel->opponent->CombatStopWithPets(true);
910 he->CombatStopWithPets(true);
912 he->CastSpell(he, 7267, true); // beg
913 he->DuelComplete(DUEL_WON);
917 DEBUG_LOG("DealDamageEnd returned %d damage", damage);
919 return damage;
922 void Unit::CastStop(uint32 except_spellid)
924 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
925 if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id!=except_spellid)
926 InterruptSpell(i,false);
929 void Unit::CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castItem, Aura* triggeredByAura, uint64 originalCaster)
931 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
933 if(!spellInfo)
935 sLog.outError("CastSpell: unknown spell id %i by caster: %s %u)", spellId,(GetTypeId()==TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
936 return;
939 CastSpell(Victim,spellInfo,triggered,castItem,triggeredByAura, originalCaster);
942 void Unit::CastSpell(Unit* Victim,SpellEntry const *spellInfo, bool triggered, Item *castItem, Aura* triggeredByAura, uint64 originalCaster)
944 if(!spellInfo)
946 sLog.outError("CastSpell: unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
947 return;
950 if (castItem)
951 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
953 if(!originalCaster && triggeredByAura)
954 originalCaster = triggeredByAura->GetCasterGUID();
956 Spell *spell = new Spell(this, spellInfo, triggered, originalCaster );
958 SpellCastTargets targets;
959 targets.setUnitTarget( Victim );
960 spell->m_CastItem = castItem;
961 spell->prepare(&targets, triggeredByAura);
964 void Unit::CastCustomSpell(Unit* Victim,uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem, Aura* triggeredByAura, uint64 originalCaster)
966 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
968 if(!spellInfo)
970 sLog.outError("CastCustomSpell: unknown spell id %i\n", spellId);
971 return;
974 CastCustomSpell(Victim,spellInfo,bp0,bp1,bp2,triggered,castItem,triggeredByAura, originalCaster);
977 void Unit::CastCustomSpell(Unit* Victim,SpellEntry const *spellInfo, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem, Aura* triggeredByAura, uint64 originalCaster)
979 if(!spellInfo)
981 sLog.outError("CastCustomSpell: unknown spell");
982 return;
985 if (castItem)
986 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
988 if(!originalCaster && triggeredByAura)
989 originalCaster = triggeredByAura->GetCasterGUID();
991 Spell *spell = new Spell(this, spellInfo, triggered, originalCaster);
993 if(bp0)
994 spell->m_currentBasePoints[0] = *bp0-int32(spellInfo->EffectBaseDice[0]);
996 if(bp1)
997 spell->m_currentBasePoints[1] = *bp1-int32(spellInfo->EffectBaseDice[1]);
999 if(bp2)
1000 spell->m_currentBasePoints[2] = *bp2-int32(spellInfo->EffectBaseDice[2]);
1002 SpellCastTargets targets;
1003 targets.setUnitTarget( Victim );
1004 spell->m_CastItem = castItem;
1005 spell->prepare(&targets, triggeredByAura);
1008 // used for scripting
1009 void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem, Aura* triggeredByAura, uint64 originalCaster)
1011 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
1013 if(!spellInfo)
1015 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()));
1016 return;
1019 CastSpell(x, y, z,spellInfo,triggered,castItem,triggeredByAura, originalCaster);
1022 // used for scripting
1023 void Unit::CastSpell(float x, float y, float z, SpellEntry const *spellInfo, bool triggered, Item *castItem, Aura* triggeredByAura, uint64 originalCaster)
1025 if(!spellInfo)
1027 sLog.outError("CastSpell(x,y,z): unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
1028 return;
1031 if (castItem)
1032 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
1034 if(!originalCaster && triggeredByAura)
1035 originalCaster = triggeredByAura->GetCasterGUID();
1037 Spell *spell = new Spell(this, spellInfo, triggered, originalCaster );
1039 SpellCastTargets targets;
1040 targets.setDestination(x, y, z);
1041 spell->m_CastItem = castItem;
1042 spell->prepare(&targets, triggeredByAura);
1045 void Unit::DealFlatDamage(Unit *pVictim, SpellEntry const *spellInfo, uint32 *damage, CleanDamage *cleanDamage, bool *crit, bool isTriggeredSpell)
1047 // TODO this in only generic way, check for exceptions
1048 DEBUG_LOG("DealFlatDamage (BEFORE) >> DMG:%u", *damage);
1050 // Per-damage class calculation
1051 switch (spellInfo->DmgClass)
1053 // Melee and Ranged Spells
1054 case SPELL_DAMAGE_CLASS_RANGED:
1055 case SPELL_DAMAGE_CLASS_MELEE:
1057 // Calculate physical outcome
1058 MeleeHitOutcome outcome = RollPhysicalOutcomeAgainst(pVictim, BASE_ATTACK, spellInfo);
1060 //Used to store the Hit Outcome
1061 cleanDamage->hitOutCome = outcome;
1063 // Return miss/evade first (sends miss message)
1064 switch(outcome)
1066 case MELEE_HIT_EVADE:
1068 SendAttackStateUpdate(HITINFO_MISS, pVictim, 1, GetSpellSchoolMask(spellInfo), 0, 0,0,VICTIMSTATE_EVADES,0);
1069 *damage = 0;
1070 return;
1072 case MELEE_HIT_MISS:
1074 SendAttackStateUpdate(HITINFO_MISS, pVictim, 1, GetSpellSchoolMask(spellInfo), 0, 0,0,VICTIMSTATE_NORMAL,0);
1075 *damage = 0;
1077 if(GetTypeId()== TYPEID_PLAYER)
1078 ((Player*)this)->UpdateWeaponSkill(BASE_ATTACK);
1080 CastMeleeProcDamageAndSpell(pVictim,0,GetSpellSchoolMask(spellInfo),BASE_ATTACK,MELEE_HIT_MISS,spellInfo,isTriggeredSpell);
1081 return;
1085 // Hitinfo, Victimstate
1086 uint32 hitInfo = HITINFO_NORMALSWING;
1087 VictimState victimState = VICTIMSTATE_NORMAL;
1089 // Physical Damage
1090 if ( GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_NORMAL )
1092 // apply spellmod to Done damage
1093 if(Player* modOwner = GetSpellModOwner())
1094 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_DAMAGE, *damage);
1096 //Calculate armor mitigation
1097 uint32 damageAfterArmor = CalcArmorReducedDamage(pVictim, *damage);
1099 // random durability for main hand weapon (ABSORB)
1100 if(damageAfterArmor < *damage)
1101 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1102 if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_ABSORB)))
1103 ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START,EQUIPMENT_SLOT_BACK)));
1105 cleanDamage->damage += *damage - damageAfterArmor;
1106 *damage = damageAfterArmor;
1108 // Magical Damage
1109 else
1111 // Calculate damage bonus
1112 *damage = SpellDamageBonus(pVictim, spellInfo, *damage, SPELL_DIRECT_DAMAGE);
1115 // Classify outcome
1116 switch (outcome)
1118 case MELEE_HIT_BLOCK_CRIT:
1119 case MELEE_HIT_CRIT:
1121 uint32 bonusDmg = *damage;
1123 // Apply crit_damage bonus
1124 if(Player* modOwner = GetSpellModOwner())
1125 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, bonusDmg);
1127 uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
1128 AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS);
1129 for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i)
1130 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
1131 bonusDmg = uint32(bonusDmg * ((*i)->GetModifier()->m_amount+100.0f)/100.0f);
1133 *damage += bonusDmg;
1135 // Resilience - reduce crit damage
1136 if (pVictim->GetTypeId()==TYPEID_PLAYER)
1138 uint32 resilienceReduction = ((Player*)pVictim)->GetMeleeCritDamageReduction(*damage);
1139 cleanDamage->damage += resilienceReduction;
1140 *damage -= resilienceReduction;
1143 *crit = true;
1144 hitInfo |= HITINFO_CRITICALHIT;
1146 ModifyAuraState(AURA_STATE_CRIT, true);
1147 StartReactiveTimer( REACTIVE_CRIT );
1149 if(getClass()==CLASS_HUNTER)
1151 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, true);
1152 StartReactiveTimer( REACTIVE_HUNTER_CRIT );
1155 if ( outcome == MELEE_HIT_BLOCK_CRIT )
1157 uint32 blocked_amount = uint32(pVictim->GetShieldBlockValue());
1158 if (blocked_amount >= *damage)
1160 hitInfo |= HITINFO_SWINGNOHITSOUND;
1161 victimState = VICTIMSTATE_BLOCKS;
1162 cleanDamage->damage += *damage; // To Help Calculate Rage
1163 *damage = 0;
1165 else
1167 // To Help Calculate Rage
1168 cleanDamage->damage += blocked_amount;
1169 *damage = *damage - blocked_amount;
1172 pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true);
1173 pVictim->StartReactiveTimer( REACTIVE_DEFENSE );
1175 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1177 // Update defense
1178 ((Player*)pVictim)->UpdateDefense();
1180 // random durability for main hand weapon (BLOCK)
1181 if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK)))
1182 ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND);
1185 break;
1187 case MELEE_HIT_PARRY:
1189 cleanDamage->damage += *damage; // To Help Calculate Rage
1190 *damage = 0;
1191 victimState = VICTIMSTATE_PARRY;
1193 // Counter-attack ( explained in Unit::DoAttackDamage() )
1194 if(pVictim->GetTypeId()==TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN) )
1196 // Get attack timers
1197 float offtime = float(pVictim->getAttackTimer(OFF_ATTACK));
1198 float basetime = float(pVictim->getAttackTimer(BASE_ATTACK));
1200 // Reduce attack time
1201 if (pVictim->haveOffhandWeapon() && offtime < basetime)
1203 float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20;
1204 float percent60 = 3 * percent20;
1205 if(offtime > percent20 && offtime <= percent60)
1207 pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20));
1209 else if(offtime > percent60)
1211 offtime -= 2 * percent20;
1212 pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime));
1215 else
1217 float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20;
1218 float percent60 = 3 * percent20;
1219 if(basetime > percent20 && basetime <= percent60)
1221 pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20));
1223 else if(basetime > percent60)
1225 basetime -= 2 * percent20;
1226 pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime));
1231 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1233 // Update victim defense ?
1234 ((Player*)pVictim)->UpdateDefense();
1236 // random durability for main hand weapon (PARRY)
1237 if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_PARRY)))
1238 ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND);
1241 // Set parry flags
1242 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
1244 // Mongoose bite - set only Counterattack here
1245 if (pVictim->getClass() == CLASS_HUNTER)
1247 pVictim->ModifyAuraState(AURA_STATE_HUNTER_PARRY,true);
1248 pVictim->StartReactiveTimer( REACTIVE_HUNTER_PARRY );
1250 else
1252 pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true);
1253 pVictim->StartReactiveTimer( REACTIVE_DEFENSE );
1255 break;
1257 case MELEE_HIT_DODGE:
1259 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1260 ((Player*)pVictim)->UpdateDefense();
1262 cleanDamage->damage += *damage; // To Help Calculate Rage
1263 *damage = 0;
1264 hitInfo |= HITINFO_SWINGNOHITSOUND;
1265 victimState = VICTIMSTATE_DODGE;
1267 // Set dodge flags
1268 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
1270 // Overpower
1271 if (GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR)
1273 ((Player*)this)->AddComboPoints(pVictim, 1);
1274 StartReactiveTimer( REACTIVE_OVERPOWER );
1277 // Riposte
1278 if (pVictim->getClass() != CLASS_ROGUE)
1280 pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true);
1281 pVictim->StartReactiveTimer( REACTIVE_DEFENSE );
1283 break;
1285 case MELEE_HIT_BLOCK:
1287 uint32 blocked_amount = uint32(pVictim->GetShieldBlockValue());
1288 if (blocked_amount >= *damage)
1290 hitInfo |= HITINFO_SWINGNOHITSOUND;
1291 victimState = VICTIMSTATE_BLOCKS;
1292 cleanDamage->damage += *damage; // To Help Calculate Rage
1293 *damage = 0;
1295 else
1297 // To Help Calculate Rage
1298 cleanDamage->damage += blocked_amount;
1299 *damage = *damage - blocked_amount;
1302 pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true);
1303 pVictim->StartReactiveTimer( REACTIVE_DEFENSE );
1305 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1307 // Update defense
1308 ((Player*)pVictim)->UpdateDefense();
1310 // random durability for main hand weapon (BLOCK)
1311 if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK)))
1312 ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND);
1314 break;
1316 case MELEE_HIT_EVADE: // already processed early
1317 case MELEE_HIT_MISS: // already processed early
1318 case MELEE_HIT_GLANCING:
1319 case MELEE_HIT_CRUSHING:
1320 case MELEE_HIT_NORMAL:
1321 break;
1324 // do all damage=0 cases here
1325 if(*damage == 0)
1326 CastMeleeProcDamageAndSpell(pVictim,0,GetSpellSchoolMask(spellInfo),BASE_ATTACK,outcome,spellInfo,isTriggeredSpell);
1328 break;
1330 // Magical Attacks
1331 case SPELL_DAMAGE_CLASS_NONE:
1332 case SPELL_DAMAGE_CLASS_MAGIC:
1334 // Calculate damage bonus
1335 *damage = SpellDamageBonus(pVictim, spellInfo, *damage, SPELL_DIRECT_DAMAGE);
1337 *crit = isSpellCrit(pVictim, spellInfo, GetSpellSchoolMask(spellInfo), BASE_ATTACK);
1338 if (*crit)
1340 *damage = SpellCriticalBonus(spellInfo, *damage, pVictim);
1342 // Resilience - reduce crit damage
1343 if (pVictim && pVictim->GetTypeId()==TYPEID_PLAYER)
1345 uint32 damage_reduction = ((Player *)pVictim)->GetSpellCritDamageReduction(*damage);
1346 if(*damage > damage_reduction)
1347 *damage -= damage_reduction;
1348 else
1349 *damage = 0;
1352 cleanDamage->hitOutCome = MELEE_HIT_CRIT;
1354 // spell proc all magic damage==0 case in this function
1355 if(*damage == 0)
1357 // Procflags
1358 uint32 procAttacker = PROC_FLAG_HIT_SPELL;
1359 uint32 procVictim = (PROC_FLAG_STRUCK_SPELL|PROC_FLAG_TAKE_DAMAGE);
1361 ProcDamageAndSpell(pVictim, procAttacker, procVictim, 0, GetSpellSchoolMask(spellInfo), spellInfo, isTriggeredSpell);
1364 break;
1368 // TODO this in only generic way, check for exceptions
1369 DEBUG_LOG("DealFlatDamage (AFTER) >> DMG:%u", *damage);
1372 uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell, bool useSpellDamage)
1374 if(!this || !pVictim)
1375 return 0;
1376 if(!isAlive() || !pVictim->isAlive())
1377 return 0;
1379 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID);
1380 if(!spellInfo)
1381 return 0;
1383 CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL);
1384 bool crit = false;
1386 if (useSpellDamage)
1387 DealFlatDamage(pVictim, spellInfo, &damage, &cleanDamage, &crit, isTriggeredSpell);
1389 // If we actually dealt some damage (spell proc's for 0 damage (normal and magic) called in DealFlatDamage)
1390 if(damage > 0)
1392 // Calculate absorb & resists
1393 uint32 absorb = 0;
1394 uint32 resist = 0;
1396 CalcAbsorbResist(pVictim,GetSpellSchoolMask(spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
1398 //No more damage left, target absorbed and/or resisted all damage
1399 if (damage > absorb + resist)
1400 damage -= absorb + resist; //Remove Absorbed and Resisted from damage actually dealt
1401 else
1403 uint32 HitInfo = HITINFO_SWINGNOHITSOUND;
1405 if (absorb)
1406 HitInfo |= HITINFO_ABSORB;
1407 if (resist)
1409 HitInfo |= HITINFO_RESIST;
1410 ProcDamageAndSpell(pVictim, PROC_FLAG_TARGET_RESISTS, PROC_FLAG_RESIST_SPELL, 0, GetSpellSchoolMask(spellInfo), spellInfo,isTriggeredSpell);
1413 //Send resist
1414 SendAttackStateUpdate(HitInfo, pVictim, 1, GetSpellSchoolMask(spellInfo), damage, absorb,resist,VICTIMSTATE_NORMAL,0);
1415 return 0;
1418 // Deal damage done
1419 damage = DealDamage(pVictim, damage, &cleanDamage, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(spellInfo), spellInfo, true);
1421 // Send damage log
1422 sLog.outDetail("SpellNonMeleeDamageLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u,absorb is %u,resist is %u",
1423 GetGUIDLow(), GetTypeId(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, spellID, absorb,resist);
1425 // Actual log sent to client
1426 SendSpellNonMeleeDamageLog(pVictim, spellID, damage, GetSpellSchoolMask(spellInfo), absorb, resist, false, 0, crit);
1428 // Procflags
1429 uint32 procAttacker = PROC_FLAG_HIT_SPELL;
1430 uint32 procVictim = (PROC_FLAG_STRUCK_SPELL|PROC_FLAG_TAKE_DAMAGE);
1432 if (crit)
1434 procAttacker |= PROC_FLAG_CRIT_SPELL;
1435 procVictim |= PROC_FLAG_STRUCK_CRIT_SPELL;
1438 ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, GetSpellSchoolMask(spellInfo), spellInfo, isTriggeredSpell);
1440 return damage;
1442 else
1444 // all spell proc for 0 normal and magic damage called in DealFlatDamage
1446 //Check for rage
1447 if(cleanDamage.damage)
1448 // Rage from damage received.
1449 if(pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->getPowerType() == POWER_RAGE))
1450 ((Player*)pVictim)->RewardRage(cleanDamage.damage, 0, false);
1452 return 0;
1456 void Unit::HandleEmoteCommand(uint32 anim_id)
1458 WorldPacket data( SMSG_EMOTE, 12 );
1459 data << uint32(anim_id);
1460 data << uint64(GetGUID());
1461 SendMessageToSet(&data, true);
1464 uint32 Unit::CalcArmorReducedDamage(Unit* pVictim, const uint32 damage)
1466 uint32 newdamage = 0;
1467 float armor = pVictim->GetArmor();
1468 // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
1469 armor += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_NORMAL);
1471 if (armor<0.0f) armor=0.0f;
1473 float tmpvalue = 0.0f;
1474 if(getLevel() <= 59) //Level 1-59
1475 tmpvalue = armor / (armor + 400.0f + 85.0f * getLevel());
1476 else if(getLevel() < 70) //Level 60-69
1477 tmpvalue = armor / (armor - 22167.5f + 467.5f * getLevel());
1478 else //Level 70+
1479 tmpvalue = armor / (armor + 10557.5f);
1481 if(tmpvalue < 0.0f)
1482 tmpvalue = 0.0f;
1483 if(tmpvalue > 0.75f)
1484 tmpvalue = 0.75f;
1485 newdamage = uint32(damage - (damage * tmpvalue));
1487 return (newdamage > 1) ? newdamage : 1;
1490 void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist)
1492 if(!pVictim || !pVictim->isAlive() || !damage)
1493 return;
1495 // Magic damage, check for resists
1496 if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL)==0)
1498 // Get base victim resistance for school
1499 float tmpvalue2 = (float)pVictim->GetResistance(GetFirstSchoolInMask(schoolMask));
1500 // Ignore resistance by self SPELL_AURA_MOD_TARGET_RESISTANCE aura
1501 tmpvalue2 += (float)GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask);
1503 tmpvalue2 *= (float)(0.15f / getLevel());
1504 if (tmpvalue2 < 0.0f)
1505 tmpvalue2 = 0.0f;
1506 if (tmpvalue2 > 0.75f)
1507 tmpvalue2 = 0.75f;
1508 uint32 ran = urand(0, 100);
1509 uint32 faq[4] = {24,6,4,6};
1510 uint8 m = 0;
1511 float Binom = 0.0f;
1512 for (uint8 i = 0; i < 4; i++)
1514 Binom += 2400 *( powf(tmpvalue2, i) * powf( (1-tmpvalue2), (4-i)))/faq[i];
1515 if (ran > Binom )
1516 ++m;
1517 else
1518 break;
1520 if (damagetype == DOT && m == 4)
1521 *resist += uint32(damage - 1);
1522 else
1523 *resist += uint32(damage * m / 4);
1524 if(*resist > damage)
1525 *resist = damage;
1527 else
1528 *resist = 0;
1530 int32 RemainingDamage = damage - *resist;
1532 // absorb without mana cost
1533 int32 reflectDamage = 0;
1534 Aura* reflectAura = NULL;
1535 AuraList const& vSchoolAbsorb = pVictim->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB);
1536 for(AuraList::const_iterator i = vSchoolAbsorb.begin(), next; i != vSchoolAbsorb.end() && RemainingDamage > 0; i = next)
1538 next = i; ++next;
1540 if (((*i)->GetModifier()->m_miscvalue & schoolMask)==0)
1541 continue;
1543 // Cheat Death
1544 if((*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE && (*i)->GetSpellProto()->SpellIconID == 2109)
1546 if (((Player*)pVictim)->HasSpellCooldown(31231))
1547 continue;
1548 if (pVictim->GetHealth() <= RemainingDamage)
1550 int32 chance = (*i)->GetModifier()->m_amount;
1551 if (roll_chance_i(chance))
1553 pVictim->CastSpell(pVictim,31231,true);
1554 ((Player*)pVictim)->AddSpellCooldown(31231,0,time(NULL)+60);
1556 // with health > 10% lost health until health==10%, in other case no losses
1557 uint32 health10 = pVictim->GetMaxHealth()/10;
1558 RemainingDamage = pVictim->GetHealth() > health10 ? pVictim->GetHealth() - health10 : 0;
1561 continue;
1564 int32 currentAbsorb;
1566 //Reflective Shield
1567 if ((pVictim != this) && (*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_PRIEST && (*i)->GetSpellProto()->SpellFamilyFlags == 0x1)
1569 if(Unit* caster = (*i)->GetCaster())
1571 AuraList const& vOverRideCS = caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
1572 for(AuraList::const_iterator k = vOverRideCS.begin(); k != vOverRideCS.end(); ++k)
1574 switch((*k)->GetModifier()->m_miscvalue)
1576 case 5065: // Rank 1
1577 case 5064: // Rank 2
1578 case 5063: // Rank 3
1579 case 5062: // Rank 4
1580 case 5061: // Rank 5
1582 if(RemainingDamage >= (*i)->GetModifier()->m_amount)
1583 reflectDamage = (*i)->GetModifier()->m_amount * (*k)->GetModifier()->m_amount/100;
1584 else
1585 reflectDamage = (*k)->GetModifier()->m_amount * RemainingDamage/100;
1586 reflectAura = *i;
1588 } break;
1589 default: break;
1592 if(reflectDamage)
1593 break;
1598 if (RemainingDamage >= (*i)->GetModifier()->m_amount)
1600 currentAbsorb = (*i)->GetModifier()->m_amount;
1601 pVictim->RemoveAurasDueToSpell((*i)->GetId());
1602 next = vSchoolAbsorb.begin();
1604 else
1606 currentAbsorb = RemainingDamage;
1607 (*i)->GetModifier()->m_amount -= RemainingDamage;
1610 RemainingDamage -= currentAbsorb;
1612 // do not cast spells while looping auras; auras can get invalid otherwise
1613 if (reflectDamage)
1614 pVictim->CastCustomSpell(this, 33619, &reflectDamage, NULL, NULL, true, NULL, reflectAura);
1616 // absorb by mana cost
1617 AuraList const& vManaShield = pVictim->GetAurasByType(SPELL_AURA_MANA_SHIELD);
1618 for(AuraList::const_iterator i = vManaShield.begin(), next; i != vManaShield.end() && RemainingDamage > 0; i = next)
1620 next = i; ++next;
1622 // check damage school mask
1623 if(((*i)->GetModifier()->m_miscvalue & schoolMask)==0)
1624 continue;
1626 int32 currentAbsorb;
1627 if (RemainingDamage >= (*i)->GetModifier()->m_amount)
1628 currentAbsorb = (*i)->GetModifier()->m_amount;
1629 else
1630 currentAbsorb = RemainingDamage;
1632 float manaMultiplier = (*i)->GetSpellProto()->EffectMultipleValue[(*i)->GetEffIndex()];
1633 if(Player *modOwner = GetSpellModOwner())
1634 modOwner->ApplySpellMod((*i)->GetId(), SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
1636 int32 maxAbsorb = int32(pVictim->GetPower(POWER_MANA) / manaMultiplier);
1637 if (currentAbsorb > maxAbsorb)
1638 currentAbsorb = maxAbsorb;
1640 (*i)->GetModifier()->m_amount -= currentAbsorb;
1641 if((*i)->GetModifier()->m_amount <= 0)
1643 pVictim->RemoveAurasDueToSpell((*i)->GetId());
1644 next = vManaShield.begin();
1647 int32 manaReduction = int32(currentAbsorb * manaMultiplier);
1648 pVictim->ApplyPowerMod(POWER_MANA, manaReduction, false);
1650 RemainingDamage -= currentAbsorb;
1653 // only split damage if not damaging yourself
1654 if(pVictim != this)
1656 AuraList const& vSplitDamageFlat = pVictim->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_FLAT);
1657 for(AuraList::const_iterator i = vSplitDamageFlat.begin(), next; i != vSplitDamageFlat.end() && RemainingDamage >= 0; i = next)
1659 next = i; ++next;
1661 // check damage school mask
1662 if(((*i)->GetModifier()->m_miscvalue & schoolMask)==0)
1663 continue;
1665 // Damage can be splitted only if aura has an alive caster
1666 Unit *caster = (*i)->GetCaster();
1667 if(!caster || caster == pVictim || !caster->IsInWorld() || !caster->isAlive())
1668 continue;
1670 int32 currentAbsorb;
1671 if (RemainingDamage >= (*i)->GetModifier()->m_amount)
1672 currentAbsorb = (*i)->GetModifier()->m_amount;
1673 else
1674 currentAbsorb = RemainingDamage;
1676 RemainingDamage -= currentAbsorb;
1678 SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, currentAbsorb, schoolMask, 0, 0, false, 0, false);
1680 CleanDamage cleanDamage = CleanDamage(currentAbsorb, BASE_ATTACK, MELEE_HIT_NORMAL);
1681 DealDamage(caster, currentAbsorb, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false);
1684 AuraList const& vSplitDamagePct = pVictim->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_PCT);
1685 for(AuraList::const_iterator i = vSplitDamagePct.begin(), next; i != vSplitDamagePct.end() && RemainingDamage >= 0; i = next)
1687 next = i; ++next;
1689 // check damage school mask
1690 if(((*i)->GetModifier()->m_miscvalue & schoolMask)==0)
1691 continue;
1693 // Damage can be splitted only if aura has an alive caster
1694 Unit *caster = (*i)->GetCaster();
1695 if(!caster || caster == pVictim || !caster->IsInWorld() || !caster->isAlive())
1696 continue;
1698 int32 splitted = int32(RemainingDamage * (*i)->GetModifier()->m_amount / 100.0f);
1700 RemainingDamage -= splitted;
1702 SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, 0, 0, false, 0, false);
1704 CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL);
1705 DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false);
1709 *absorb = damage - RemainingDamage - *resist;
1712 void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDamage, uint32 *blocked_amount, SpellSchoolMask damageSchoolMask, uint32 *hitInfo, VictimState *victimState, uint32 *absorbDamage, uint32 *resistDamage, WeaponAttackType attType, SpellEntry const *spellCasted, bool isTriggeredSpell)
1714 MeleeHitOutcome outcome;
1716 // If is casted Melee spell, calculate like physical
1717 if(!spellCasted)
1718 outcome = RollMeleeOutcomeAgainst (pVictim, attType);
1719 else
1720 outcome = RollPhysicalOutcomeAgainst (pVictim, attType, spellCasted);
1722 if(outcome == MELEE_HIT_MISS ||outcome == MELEE_HIT_DODGE ||outcome == MELEE_HIT_BLOCK ||outcome == MELEE_HIT_PARRY)
1723 pVictim->AddThreat(this, 0.0f);
1724 switch(outcome)
1726 case MELEE_HIT_EVADE:
1728 *hitInfo |= HITINFO_MISS;
1729 *damage = 0;
1730 cleanDamage->damage = 0;
1731 return;
1733 case MELEE_HIT_MISS:
1735 *hitInfo |= HITINFO_MISS;
1736 *damage = 0;
1737 cleanDamage->damage = 0;
1738 if(GetTypeId()== TYPEID_PLAYER)
1739 ((Player*)this)->UpdateWeaponSkill(attType);
1740 return;
1744 /// If this is a creature and it attacks from behind it has a probability to daze it's victim
1745 if( (outcome==MELEE_HIT_CRIT || outcome==MELEE_HIT_CRUSHING || outcome==MELEE_HIT_NORMAL || outcome==MELEE_HIT_GLANCING) &&
1746 GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->GetCharmerOrOwnerGUID() && !pVictim->HasInArc(M_PI, this) )
1748 // -probability is between 0% and 40%
1749 // 20% base chance
1750 float Probability = 20;
1752 //there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1753 if( pVictim->getLevel() < 30 )
1754 Probability = 0.65f*pVictim->getLevel()+0.5;
1756 uint32 VictimDefense=pVictim->GetDefenseSkillValue(this);
1757 uint32 AttackerMeleeSkill=GetUnitMeleeSkill(pVictim);
1759 Probability *= AttackerMeleeSkill/(float)VictimDefense;
1761 if(Probability > 40.0f)
1762 Probability = 40.0f;
1764 if(roll_chance_f(Probability))
1765 CastSpell(pVictim, 1604, true);
1768 //Calculate the damage after armor mitigation if SPELL_SCHOOL_NORMAL
1769 if (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL)
1771 uint32 damageAfterArmor = CalcArmorReducedDamage(pVictim, *damage);
1773 // random durability for main hand weapon (ABSORB)
1774 if(damageAfterArmor < *damage)
1775 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1776 if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_ABSORB)))
1777 ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START,EQUIPMENT_SLOT_BACK)));
1779 cleanDamage->damage += *damage - damageAfterArmor;
1780 *damage = damageAfterArmor;
1783 if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER )
1784 ((Player*)this)->UpdateCombatSkills(pVictim, attType, outcome, false);
1786 if(GetTypeId() != TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
1787 ((Player*)pVictim)->UpdateCombatSkills(this, attType, outcome, true);
1789 switch (outcome)
1791 case MELEE_HIT_BLOCK_CRIT:
1792 case MELEE_HIT_CRIT:
1794 //*hitInfo = 0xEA;
1795 // 0xEA
1796 *hitInfo = HITINFO_CRITICALHIT | HITINFO_NORMALSWING2 | 0x8;
1798 // Crit bonus calc
1799 uint32 crit_bonus;
1800 crit_bonus = *damage;
1802 // Apply crit_damage bonus for melee spells
1803 if (spellCasted)
1805 if(Player* modOwner = GetSpellModOwner())
1806 modOwner->ApplySpellMod(spellCasted->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
1808 uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
1809 AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS);
1810 for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i)
1811 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
1812 crit_bonus = uint32(crit_bonus * ((*i)->GetModifier()->m_amount+100.0f)/100.0f);
1815 *damage += crit_bonus;
1817 uint32 resilienceReduction = 0;
1819 if(attType == RANGED_ATTACK)
1821 int32 mod = pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE);
1822 *damage = int32((*damage) * float((100.0f + mod)/100.0f));
1823 // Resilience - reduce crit damage
1824 if (pVictim->GetTypeId()==TYPEID_PLAYER)
1825 resilienceReduction = ((Player*)pVictim)->GetRangedCritDamageReduction(*damage);
1827 else
1829 int32 mod = pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
1830 mod += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE);
1831 *damage = int32((*damage) * float((100.0f + mod)/100.0f));
1832 // Resilience - reduce crit damage
1833 if (pVictim->GetTypeId()==TYPEID_PLAYER)
1834 resilienceReduction = ((Player*)pVictim)->GetMeleeCritDamageReduction(*damage);
1837 *damage -= resilienceReduction;
1838 cleanDamage->damage += resilienceReduction;
1840 if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER )
1841 ((Player*)this)->UpdateWeaponSkill(attType);
1843 ModifyAuraState(AURA_STATE_CRIT, true);
1844 StartReactiveTimer( REACTIVE_CRIT );
1846 if(getClass()==CLASS_HUNTER)
1848 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, true);
1849 StartReactiveTimer( REACTIVE_HUNTER_CRIT );
1852 if ( outcome == MELEE_HIT_BLOCK_CRIT )
1854 *blocked_amount = pVictim->GetShieldBlockValue();
1856 if (pVictim->GetUnitBlockChance())
1857 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD);
1858 else
1859 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
1861 //Only set VICTIMSTATE_BLOCK on a full block
1862 if (*blocked_amount >= uint32(*damage))
1864 *victimState = VICTIMSTATE_BLOCKS;
1865 *blocked_amount = uint32(*damage);
1868 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1870 // Update defense
1871 ((Player*)pVictim)->UpdateDefense();
1873 // random durability for main hand weapon (BLOCK)
1874 if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK)))
1875 ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND);
1878 pVictim->ModifyAuraState(AURA_STATE_DEFENSE,true);
1879 pVictim->StartReactiveTimer( REACTIVE_DEFENSE );
1880 break;
1883 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL);
1884 break;
1886 case MELEE_HIT_PARRY:
1888 if(attType == RANGED_ATTACK) //range attack - no parry
1890 outcome = MELEE_HIT_NORMAL;
1891 break;
1894 cleanDamage->damage += *damage;
1895 *damage = 0;
1896 *victimState = VICTIMSTATE_PARRY;
1898 // instant (maybe with small delay) counter attack
1900 float offtime = float(pVictim->getAttackTimer(OFF_ATTACK));
1901 float basetime = float(pVictim->getAttackTimer(BASE_ATTACK));
1903 // after parry nearest next attack time will reduced at %40 from full attack time.
1904 // The delay cannot be reduced to less than 20% of your weapon base swing delay.
1905 if (pVictim->haveOffhandWeapon() && offtime < basetime)
1907 float percent20 = pVictim->GetAttackTime(OFF_ATTACK)*0.20;
1908 float percent60 = 3*percent20;
1909 // set to 20% if in range 20%...20+40% of full time
1910 if(offtime > percent20 && offtime <= percent60)
1912 pVictim->setAttackTimer(OFF_ATTACK,uint32(percent20));
1914 // decrease at %40 from full time
1915 else if(offtime > percent60)
1917 offtime -= 2*percent20;
1918 pVictim->setAttackTimer(OFF_ATTACK,uint32(offtime));
1920 // ELSE not changed
1922 else
1924 float percent20 = pVictim->GetAttackTime(BASE_ATTACK)*0.20;
1925 float percent60 = 3*percent20;
1926 // set to 20% if in range 20%...20+40% of full time
1927 if(basetime > percent20 && basetime <= percent60)
1929 pVictim->setAttackTimer(BASE_ATTACK,uint32(percent20));
1931 // decrease at %40 from full time
1932 else if(basetime > percent60)
1934 basetime -= 2*percent20;
1935 pVictim->setAttackTimer(BASE_ATTACK,uint32(basetime));
1937 // ELSE not changed
1941 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1943 // Update victim defense ?
1944 ((Player*)pVictim)->UpdateDefense();
1946 // random durability for main hand weapon (PARRY)
1947 if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_PARRY)))
1948 ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND);
1951 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
1953 if (pVictim->getClass() == CLASS_HUNTER)
1955 pVictim->ModifyAuraState(AURA_STATE_HUNTER_PARRY,true);
1956 pVictim->StartReactiveTimer( REACTIVE_HUNTER_PARRY );
1958 else
1960 pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true);
1961 pVictim->StartReactiveTimer( REACTIVE_DEFENSE );
1964 CastMeleeProcDamageAndSpell(pVictim, 0, damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell);
1965 return;
1967 case MELEE_HIT_DODGE:
1969 if(attType == RANGED_ATTACK) //range attack - no dodge
1971 outcome = MELEE_HIT_NORMAL;
1972 break;
1975 cleanDamage->damage += *damage;
1976 *damage = 0;
1977 *victimState = VICTIMSTATE_DODGE;
1979 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1980 ((Player*)pVictim)->UpdateDefense();
1982 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
1984 if (pVictim->getClass() != CLASS_ROGUE) // Riposte
1986 pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true);
1987 pVictim->StartReactiveTimer( REACTIVE_DEFENSE );
1990 // Overpower
1991 if (GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR)
1993 ((Player*)this)->AddComboPoints(pVictim, 1);
1994 StartReactiveTimer( REACTIVE_OVERPOWER );
1997 CastMeleeProcDamageAndSpell(pVictim, 0, damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell);
1998 return;
2000 case MELEE_HIT_BLOCK:
2002 *blocked_amount = pVictim->GetShieldBlockValue();
2004 if (pVictim->GetUnitBlockChance())
2005 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD);
2006 else
2007 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
2009 //Only set VICTIMSTATE_BLOCK on a full block
2010 if (*blocked_amount >= uint32(*damage))
2012 *victimState = VICTIMSTATE_BLOCKS;
2013 *blocked_amount = uint32(*damage);
2016 if(pVictim->GetTypeId() == TYPEID_PLAYER)
2018 // Update defense
2019 ((Player*)pVictim)->UpdateDefense();
2021 // random durability for main hand weapon (BLOCK)
2022 if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK)))
2023 ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND);
2026 pVictim->ModifyAuraState(AURA_STATE_DEFENSE,true);
2027 pVictim->StartReactiveTimer( REACTIVE_DEFENSE );
2029 break;
2031 case MELEE_HIT_GLANCING:
2033 float reducePercent = 1.0f; //damage factor
2035 // calculate base values and mods
2036 float baseLowEnd = 1.3;
2037 float baseHighEnd = 1.2;
2038 switch(getClass()) // lowering base values for casters
2040 case CLASS_SHAMAN:
2041 case CLASS_PRIEST:
2042 case CLASS_MAGE:
2043 case CLASS_WARLOCK:
2044 case CLASS_DRUID:
2045 baseLowEnd -= 0.7;
2046 baseHighEnd -= 0.3;
2047 break;
2050 float maxLowEnd = 0.6;
2051 switch(getClass()) // upper for melee classes
2053 case CLASS_WARRIOR:
2054 case CLASS_ROGUE:
2055 maxLowEnd = 0.91; //If the attacker is a melee class then instead the lower value of 0.91
2058 // calculate values
2059 int32 diff = int32(pVictim->GetDefenseSkillValue(this)) - int32(GetWeaponSkillValue(attType,pVictim));
2060 float lowEnd = baseLowEnd - ( 0.05f * diff );
2061 float highEnd = baseHighEnd - ( 0.03f * diff );
2063 // apply max/min bounds
2064 if ( lowEnd < 0.01f ) //the low end must not go bellow 0.01f
2065 lowEnd = 0.01f;
2066 else if ( lowEnd > maxLowEnd ) //the smaller value of this and 0.6 is kept as the low end
2067 lowEnd = maxLowEnd;
2069 if ( highEnd < 0.2f ) //high end limits
2070 highEnd = 0.2f;
2071 if ( highEnd > 0.99f )
2072 highEnd = 0.99f;
2074 if(lowEnd > highEnd) // prevent negative range size
2075 lowEnd = highEnd;
2077 reducePercent = lowEnd + rand_norm() * ( highEnd - lowEnd );
2079 *damage = uint32(reducePercent * *damage);
2080 cleanDamage->damage += *damage;
2081 *hitInfo |= HITINFO_GLANCING;
2082 break;
2084 case MELEE_HIT_CRUSHING:
2086 // 150% normal damage
2087 *damage += (*damage / 2);
2088 cleanDamage->damage = *damage;
2089 *hitInfo |= HITINFO_CRUSHING;
2090 // TODO: victimState, victim animation?
2091 break;
2093 default:
2094 break;
2097 // apply melee damage bonus and absorb only if base damage not fully blocked to prevent negative damage or damage with full block
2098 if(*victimState != VICTIMSTATE_BLOCKS)
2100 MeleeDamageBonus(pVictim, damage,attType,spellCasted);
2101 CalcAbsorbResist(pVictim, damageSchoolMask, DIRECT_DAMAGE, *damage-*blocked_amount, absorbDamage, resistDamage);
2104 if (*absorbDamage) *hitInfo |= HITINFO_ABSORB;
2105 if (*resistDamage) *hitInfo |= HITINFO_RESIST;
2107 cleanDamage->damage += *blocked_amount;
2109 if (*damage <= *absorbDamage + *resistDamage + *blocked_amount)
2111 //*hitInfo = 0x00010020;
2112 //*hitInfo |= HITINFO_SWINGNOHITSOUND;
2113 //*damageType = 0;
2114 CastMeleeProcDamageAndSpell(pVictim, 0, damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell);
2115 return;
2118 // update at damage Judgement aura duration that applied by attacker at victim
2119 if(*damage)
2121 AuraMap const& vAuras = pVictim->GetAuras();
2122 for(AuraMap::const_iterator itr = vAuras.begin(); itr != vAuras.end(); ++itr)
2124 SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
2125 if( (spellInfo->AttributesEx3 & 0x40000) && spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN &&
2126 ((*itr).second->GetCasterGUID() == GetGUID() && (!spellCasted || spellCasted->Id == 35395)) )
2128 (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration());
2129 (*itr).second->UpdateAuraDuration();
2134 CastMeleeProcDamageAndSpell(pVictim, (*damage - *absorbDamage - *resistDamage - *blocked_amount), damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell);
2136 // victim's damage shield
2137 // yet another hack to fix crashes related to the aura getting removed during iteration
2138 std::set<Aura*> alreadyDone;
2139 uint32 removedAuras = pVictim->m_removedAuras;
2140 AuraList const& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD);
2141 for(AuraList::const_iterator i = vDamageShields.begin(), next = vDamageShields.begin(); i != vDamageShields.end(); i = next)
2143 ++next;
2144 if (alreadyDone.find(*i) == alreadyDone.end())
2146 alreadyDone.insert(*i);
2147 pVictim->SpellNonMeleeDamageLog(this, (*i)->GetId(), (*i)->GetModifier()->m_amount, false, false);
2148 if (pVictim->m_removedAuras > removedAuras)
2150 removedAuras = pVictim->m_removedAuras;
2151 next = vDamageShields.begin();
2157 void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool extra )
2159 if(hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED) )
2160 return;
2162 if (!pVictim->isAlive())
2163 return;
2165 if(IsNonMeleeSpellCasted(false))
2166 return;
2168 uint32 hitInfo;
2169 if (attType == BASE_ATTACK)
2170 hitInfo = HITINFO_NORMALSWING2;
2171 else if (attType == OFF_ATTACK)
2172 hitInfo = HITINFO_LEFTSWING;
2173 else
2174 return; // ignore ranged case
2176 uint32 extraAttacks = m_extraAttacks;
2178 // melee attack spell casted at main hand attack only
2179 if (attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL])
2181 m_currentSpells[CURRENT_MELEE_SPELL]->cast();
2183 // not recent extra attack only at any non extra attack (melee spell case)
2184 if(!extra && extraAttacks)
2186 while(m_extraAttacks)
2188 AttackerStateUpdate(pVictim, BASE_ATTACK, true);
2189 if(m_extraAttacks > 0)
2190 --m_extraAttacks;
2194 return;
2197 VictimState victimState = VICTIMSTATE_NORMAL;
2199 CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
2200 uint32 blocked_dmg = 0;
2201 uint32 absorbed_dmg = 0;
2202 uint32 resisted_dmg = 0;
2204 SpellSchoolMask meleeSchoolMask = GetMeleeDamageSchoolMask();
2206 if(pVictim->IsImmunedToDamage(meleeSchoolMask,true)) // use charges
2208 SendAttackStateUpdate (HITINFO_NORMALSWING, pVictim, 1, meleeSchoolMask, 0, 0, 0, VICTIMSTATE_IS_IMMUNE, 0);
2210 // not recent extra attack only at any non extra attack (miss case)
2211 if(!extra && extraAttacks)
2213 while(m_extraAttacks)
2215 AttackerStateUpdate(pVictim, BASE_ATTACK, true);
2216 if(m_extraAttacks > 0)
2217 --m_extraAttacks;
2221 return;
2224 uint32 damage = CalculateDamage (attType, false);
2226 DoAttackDamage (pVictim, &damage, &cleanDamage, &blocked_dmg, meleeSchoolMask, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, attType);
2228 if (hitInfo & HITINFO_MISS)
2229 //send miss
2230 SendAttackStateUpdate (hitInfo, pVictim, 1, meleeSchoolMask, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg);
2231 else
2233 //do animation
2234 SendAttackStateUpdate (hitInfo, pVictim, 1, meleeSchoolMask, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg);
2236 if (damage > (absorbed_dmg + resisted_dmg + blocked_dmg))
2237 damage -= (absorbed_dmg + resisted_dmg + blocked_dmg);
2238 else
2239 damage = 0;
2241 DealDamage (pVictim, damage, &cleanDamage, DIRECT_DAMAGE, meleeSchoolMask, NULL, true);
2243 if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive())
2245 for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
2246 ((Player*)this)->CastItemCombatSpell(((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i),pVictim,attType);
2250 if (GetTypeId() == TYPEID_PLAYER)
2251 DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2252 GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, absorbed_dmg, blocked_dmg, resisted_dmg);
2253 else
2254 DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2255 GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, absorbed_dmg, blocked_dmg, resisted_dmg);
2257 // extra attack only at any non extra attack (normal case)
2258 if(!extra && extraAttacks)
2260 while(m_extraAttacks)
2262 AttackerStateUpdate(pVictim, BASE_ATTACK, true);
2263 if(m_extraAttacks > 0)
2264 --m_extraAttacks;
2269 MeleeHitOutcome Unit::RollPhysicalOutcomeAgainst (Unit const *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo)
2271 // Miss chance based on melee
2272 float miss_chance = MeleeMissChanceCalc(pVictim, attType);
2274 // Critical hit chance
2275 float crit_chance = GetUnitCriticalChance(attType, pVictim);
2276 // this is to avoid compiler issue when declaring variables inside if
2277 float block_chance, parry_chance, dodge_chance;
2279 // cannot be dodged/parried/blocked
2280 if(spellInfo->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK)
2282 block_chance = 0.0f;
2283 parry_chance = 0.0f;
2284 dodge_chance = 0.0f;
2286 else
2288 // parry can be avoided only by some abilities
2289 parry_chance = pVictim->GetUnitParryChance();
2290 // block might be bypassed by it as well
2291 block_chance = pVictim->GetUnitBlockChance();
2292 // stunned target cannot dodge and this is check in GetUnitDodgeChance()
2293 dodge_chance = pVictim->GetUnitDodgeChance();
2296 // Only players can have Talent&Spell bonuses
2297 if (GetTypeId() == TYPEID_PLAYER)
2299 // Increase from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL aura
2300 crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, spellInfo->SchoolMask);
2302 if( dodge_chance != 0.0f ) // if dodge chance is already 0, ignore talents for speed
2304 AuraList const& mCanNotBeDodge = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
2305 for(AuraList::const_iterator i = mCanNotBeDodge.begin(); i != mCanNotBeDodge.end(); ++i)
2307 // can't be dodged rogue finishing move
2308 if((*i)->GetModifier()->m_miscvalue == VICTIMSTATE_DODGE)
2310 if(spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE))
2312 dodge_chance = 0.0f;
2313 break;
2320 // Spellmods
2321 if(Player* modOwner = GetSpellModOwner())
2322 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance);
2324 DEBUG_LOG("PHYSICAL OUTCOME: miss %f crit %f dodge %f parry %f block %f",miss_chance,crit_chance,dodge_chance,parry_chance, block_chance);
2326 return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance*100), int32(miss_chance*100),int32(dodge_chance*100),int32(parry_chance*100),int32(block_chance*100), true);
2329 MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit *pVictim, WeaponAttackType attType) const
2331 // This is only wrapper
2333 // Miss chance based on melee
2334 float miss_chance = MeleeMissChanceCalc(pVictim, attType);
2336 // Critical hit chance
2337 float crit_chance = GetUnitCriticalChance(attType, pVictim);
2339 // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case)
2340 float dodge_chance = pVictim->GetUnitDodgeChance();
2341 float block_chance = pVictim->GetUnitBlockChance();
2342 float parry_chance = pVictim->GetUnitParryChance();
2344 // Useful if want to specify crit & miss chances for melee, else it could be removed
2345 DEBUG_LOG("MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance,crit_chance,dodge_chance,parry_chance,block_chance);
2347 return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance*100), int32(miss_chance*100), int32(dodge_chance*100),int32(parry_chance*100),int32(block_chance*100), false);
2350 MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance, bool SpellCasted ) const
2352 if(pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
2353 return MELEE_HIT_EVADE;
2355 int32 attackerMaxSkillValueForLevel = GetMaxSkillValueForLevel(pVictim);
2356 int32 victimMaxSkillValueForLevel = pVictim->GetMaxSkillValueForLevel(this);
2358 int32 attackerWeaponSkill = GetWeaponSkillValue(attType,pVictim);
2359 int32 victimDefenseSkill = pVictim->GetDefenseSkillValue(this);
2361 // bonus from skills is 0.04%
2362 int32 skillBonus = 4 * ( attackerWeaponSkill - victimMaxSkillValueForLevel );
2363 int32 skillBonus2 = 4 * ( attackerMaxSkillValueForLevel - victimDefenseSkill );
2364 int32 sum = 0, tmp = 0;
2365 int32 roll = urand (0, 10000);
2367 DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus);
2368 DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d",
2369 roll, miss_chance, dodge_chance, parry_chance, block_chance, crit_chance);
2371 tmp = miss_chance;
2373 if (tmp > 0 && roll < (sum += tmp ))
2375 DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS");
2376 return MELEE_HIT_MISS;
2379 // always crit against a sitting target (except 0 crit chance)
2380 if( pVictim->GetTypeId() == TYPEID_PLAYER && crit_chance > 0 && !pVictim->IsStandState() )
2382 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)");
2383 return MELEE_HIT_CRIT;
2386 // Dodge chance
2388 // only players can't dodge if attacker is behind
2389 if (pVictim->GetTypeId() == TYPEID_PLAYER && !pVictim->HasInArc(M_PI,this))
2391 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind and victim was a player.");
2393 else
2395 // Reduce dodge chance by attacker expertise rating
2396 if (GetTypeId() == TYPEID_PLAYER)
2397 dodge_chance -= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType)*100);
2399 // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2400 dodge_chance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE);
2402 tmp = dodge_chance;
2403 if ( (tmp > 0) // check if unit _can_ dodge
2404 && ((tmp -= skillBonus) > 0)
2405 && roll < (sum += tmp))
2407 DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum-tmp, sum);
2408 return MELEE_HIT_DODGE;
2412 // parry & block chances
2414 // check if attack comes from behind, nobody can parry or block if attacker is behind
2415 if (!pVictim->HasInArc(M_PI,this))
2417 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind.");
2419 else
2421 // Reduce parry chance by attacker expertise rating
2422 if (GetTypeId() == TYPEID_PLAYER)
2423 parry_chance-= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType)*100);
2425 if(pVictim->GetTypeId()==TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY) )
2427 int32 tmp = int32(parry_chance);
2428 if ( (tmp > 0) // check if unit _can_ parry
2429 && ((tmp -= skillBonus) > 0)
2430 && (roll < (sum += tmp)))
2432 DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum-tmp, sum);
2433 return MELEE_HIT_PARRY;
2437 if(pVictim->GetTypeId()==TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK) )
2439 tmp = block_chance;
2440 if ( (tmp > 0) // check if unit _can_ block
2441 && ((tmp -= skillBonus) > 0)
2442 && (roll < (sum += tmp)))
2444 // Critical chance
2445 tmp = crit_chance + skillBonus2;
2446 if ( GetTypeId() == TYPEID_PLAYER && SpellCasted && tmp > 0 )
2448 if ( roll_chance_i(tmp/100))
2450 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCKED CRIT");
2451 return MELEE_HIT_BLOCK_CRIT;
2454 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum-tmp, sum);
2455 return MELEE_HIT_BLOCK;
2460 // Critical chance
2461 tmp = crit_chance + skillBonus2;
2463 if (tmp > 0 && roll < (sum += tmp))
2465 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum-tmp, sum);
2466 return MELEE_HIT_CRIT;
2469 // 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)
2470 if( attType != RANGED_ATTACK && !SpellCasted &&
2471 (GetTypeId() == TYPEID_PLAYER || ((Creature*)this)->isPet()) &&
2472 pVictim->GetTypeId() != TYPEID_PLAYER && !((Creature*)pVictim)->isPet() &&
2473 getLevel() < pVictim->getLevelForTarget(this) )
2475 // cap possible value (with bonuses > max skill)
2476 int32 skill = attackerWeaponSkill;
2477 int32 maxskill = attackerMaxSkillValueForLevel;
2478 skill = (skill > maxskill) ? maxskill : skill;
2480 tmp = (10 + (victimDefenseSkill - skill)) * 100;
2481 tmp = tmp > 4000 ? 4000 : tmp;
2482 if (roll < (sum += tmp))
2484 DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum-4000, sum);
2485 return MELEE_HIT_GLANCING;
2489 if(GetTypeId()!=TYPEID_PLAYER && !(((Creature*)this)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRUSH) && !((Creature*)this)->isPet() )
2491 // mobs can score crushing blows if they're 3 or more levels above victim
2492 // or when their weapon skill is 15 or more above victim's defense skill
2493 tmp = victimDefenseSkill;
2494 int32 tmpmax = victimMaxSkillValueForLevel;
2495 // having defense above your maximum (from items, talents etc.) has no effect
2496 tmp = tmp > tmpmax ? tmpmax : tmp;
2497 // tmp = mob's level * 5 - player's current defense skill
2498 tmp = attackerMaxSkillValueForLevel - tmp;
2499 if(tmp >= 15)
2501 // add 2% chance per lacking skill point, min. is 15%
2502 tmp = tmp * 200 - 1500;
2503 if (roll < (sum += tmp))
2505 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum-tmp, sum);
2506 return MELEE_HIT_CRUSHING;
2511 DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL");
2512 return MELEE_HIT_NORMAL;
2515 uint32 Unit::CalculateDamage (WeaponAttackType attType, bool normalized)
2517 float min_damage, max_damage;
2519 if (normalized && GetTypeId()==TYPEID_PLAYER)
2520 ((Player*)this)->CalculateMinMaxDamage(attType,normalized,min_damage, max_damage);
2521 else
2523 switch (attType)
2525 case RANGED_ATTACK:
2526 min_damage = GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE);
2527 max_damage = GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE);
2528 break;
2529 case BASE_ATTACK:
2530 min_damage = GetFloatValue(UNIT_FIELD_MINDAMAGE);
2531 max_damage = GetFloatValue(UNIT_FIELD_MAXDAMAGE);
2532 break;
2533 case OFF_ATTACK:
2534 min_damage = GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE);
2535 max_damage = GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE);
2536 break;
2537 // Just for good manner
2538 default:
2539 min_damage = 0.0f;
2540 max_damage = 0.0f;
2541 break;
2545 if (min_damage > max_damage)
2547 std::swap(min_damage,max_damage);
2550 if(max_damage == 0.0f)
2551 max_damage = 5.0f;
2553 return urand((uint32)min_damage, (uint32)max_damage);
2556 float Unit::CalculateLevelPenalty(SpellEntry const* spellProto) const
2558 if(spellProto->spellLevel <= 0)
2559 return 1.0f;
2561 float LvlPenalty = 0.0f;
2563 if(spellProto->spellLevel < 20)
2564 LvlPenalty = 20.0f - spellProto->spellLevel * 3.75f;
2565 float LvlFactor = (float(spellProto->spellLevel) + 6.0f) / float(getLevel());
2566 if(LvlFactor > 1.0f)
2567 LvlFactor = 1.0f;
2569 return (100.0f - LvlPenalty) * LvlFactor / 100.0f;
2572 void Unit::SendAttackStart(Unit* pVictim)
2574 WorldPacket data( SMSG_ATTACKSTART, 16 );
2575 data << uint64(GetGUID());
2576 data << uint64(pVictim->GetGUID());
2578 SendMessageToSet(&data, true);
2579 DEBUG_LOG( "WORLD: Sent SMSG_ATTACKSTART" );
2582 void Unit::SendAttackStop(Unit* victim)
2584 if(!victim)
2585 return;
2587 WorldPacket data( SMSG_ATTACKSTOP, (4+16) ); // we guess size
2588 data.append(GetPackGUID());
2589 data.append(victim->GetPackGUID()); // can be 0x00...
2590 data << uint32(0); // can be 0x1
2591 SendMessageToSet(&data, true);
2592 sLog.outDetail("%s %u stopped attacking %s %u", (GetTypeId()==TYPEID_PLAYER ? "player" : "creature"), GetGUIDLow(), (victim->GetTypeId()==TYPEID_PLAYER ? "player" : "creature"),victim->GetGUIDLow());
2594 /*if(victim->GetTypeId() == TYPEID_UNIT)
2595 ((Creature*)victim)->AI().EnterEvadeMode(this);*/
2599 // Melee based spells can be miss, parry or dodge on this step
2600 // Crit or block - determined on damage calculation phase! (and can be both in some time)
2601 float Unit::MeleeSpellMissChance(Unit *pVictim, WeaponAttackType attType, int32 skillDiff, SpellEntry const *spell)
2603 // Calculate hit chance (more correct for chance mod)
2604 int32 HitChance;
2606 // PvP - PvE melee chances
2607 int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7;
2608 int32 leveldif = pVictim->getLevelForTarget(this) - getLevelForTarget(pVictim);
2609 if(leveldif < 3)
2610 HitChance = 95 - leveldif;
2611 else
2612 HitChance = 93 - (leveldif - 2) * lchance;
2614 // Hit chance depends from victim auras
2615 if(attType == RANGED_ATTACK)
2616 HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE);
2617 else
2618 HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE);
2620 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
2621 if(Player *modOwner = GetSpellModOwner())
2622 modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, HitChance);
2624 // Miss = 100 - hit
2625 float miss_chance= 100.0f - HitChance;
2627 // Bonuses from attacker aura and ratings
2628 if (attType == RANGED_ATTACK)
2629 miss_chance -= m_modRangedHitChance;
2630 else
2631 miss_chance -= m_modMeleeHitChance;
2633 // bonus from skills is 0.04%
2634 miss_chance -= skillDiff * 0.04f;
2636 // Limit miss chance from 0 to 60%
2637 if (miss_chance < 0.0f)
2638 return 0.0f;
2639 if (miss_chance > 60.0f)
2640 return 60.0f;
2641 return miss_chance;
2644 // Melee based spells hit result calculations
2645 SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
2647 WeaponAttackType attType = BASE_ATTACK;
2649 if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
2650 attType = RANGED_ATTACK;
2652 // bonus from skills is 0.04% per skill Diff
2653 int32 attackerWeaponSkill = int32(GetWeaponSkillValue(attType,pVictim));
2654 int32 skillDiff = attackerWeaponSkill - int32(pVictim->GetMaxSkillValueForLevel(this));
2655 int32 fullSkillDiff = attackerWeaponSkill - int32(pVictim->GetDefenseSkillValue(this));
2657 uint32 roll = urand (0, 10000);
2658 uint32 missChance = uint32(MeleeSpellMissChance(pVictim, attType, fullSkillDiff, spell)*100.0f);
2660 // Roll miss
2661 uint32 tmp = missChance;
2662 if (roll < tmp)
2663 return SPELL_MISS_MISS;
2665 // Same spells cannot be parry/dodge
2666 if (spell->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK)
2667 return SPELL_MISS_NONE;
2669 // Ranged attack can`t miss too
2670 if (attType == RANGED_ATTACK)
2671 return SPELL_MISS_NONE;
2673 bool attackFromBehind = !pVictim->HasInArc(M_PI,this);
2675 // Roll dodge
2676 int32 dodgeChance = int32(pVictim->GetUnitDodgeChance()*100.0f) - skillDiff * 4;
2677 // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2678 dodgeChance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE);
2680 // Reduce dodge chance by attacker expertise rating
2681 if (GetTypeId() == TYPEID_PLAYER)
2682 dodgeChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2683 if (dodgeChance < 0)
2684 dodgeChance = 0;
2686 // Can`t dodge from behind in PvP (but its possible in PvE)
2687 if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER && attackFromBehind)
2688 dodgeChance = 0;
2690 // Rogue talent`s cant be dodged
2691 AuraList const& mCanNotBeDodge = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
2692 for(AuraList::const_iterator i = mCanNotBeDodge.begin(); i != mCanNotBeDodge.end(); ++i)
2694 if((*i)->GetModifier()->m_miscvalue == VICTIMSTATE_DODGE) // can't be dodged rogue finishing move
2696 if(spell->SpellFamilyName==SPELLFAMILY_ROGUE && (spell->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE))
2698 dodgeChance = 0;
2699 break;
2704 tmp += dodgeChance;
2705 if (roll < tmp)
2706 return SPELL_MISS_DODGE;
2708 // Roll parry
2709 int32 parryChance = int32(pVictim->GetUnitParryChance()*100.0f) - skillDiff * 4;
2710 // Reduce parry chance by attacker expertise rating
2711 if (GetTypeId() == TYPEID_PLAYER)
2712 parryChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2713 // Can`t parry from behind
2714 if (parryChance < 0 || attackFromBehind)
2715 parryChance = 0;
2717 tmp += parryChance;
2718 if (roll < tmp)
2719 return SPELL_MISS_PARRY;
2721 return SPELL_MISS_NONE;
2724 // TODO need use unit spell resistances in calculations
2725 SpellMissInfo Unit::MagicSpellHitResult(Unit *pVictim, SpellEntry const *spell)
2727 // Can`t miss on dead target (on skinning for example)
2728 if (!pVictim->isAlive())
2729 return SPELL_MISS_NONE;
2731 SpellSchoolMask schoolMask = GetSpellSchoolMask(spell);
2732 // PvP - PvE spell misschances per leveldif > 2
2733 int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 7 : 11;
2734 int32 leveldif = int32(pVictim->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim));
2736 // Base hit chance from attacker and victim levels
2737 int32 modHitChance;
2738 if(leveldif < 3)
2739 modHitChance = 96 - leveldif;
2740 else
2741 modHitChance = 94 - (leveldif - 2) * lchance;
2743 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
2744 if(Player *modOwner = GetSpellModOwner())
2745 modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance);
2746 // Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras
2747 modHitChance+=GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT, schoolMask);
2748 // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
2749 modHitChance+= pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask);
2750 // Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura
2751 if (IsAreaOfEffectSpell(spell))
2752 modHitChance-=pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE);
2753 // Reduce spell hit chance for dispel mechanic spells from victim SPELL_AURA_MOD_DISPEL_RESIST
2754 if (IsDispelSpell(spell))
2755 modHitChance-=pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_DISPEL_RESIST);
2756 // Chance resist mechanic (select max value from every mechanic spell effect)
2757 int32 resist_mech = 0;
2758 // Get effects mechanic and chance
2759 for(int eff = 0; eff < 3; ++eff)
2761 int32 effect_mech = GetEffectMechanic(spell, eff);
2762 if (effect_mech)
2764 int32 temp = pVictim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE, effect_mech);
2765 if (resist_mech < temp)
2766 resist_mech = temp;
2769 // Apply mod
2770 modHitChance-=resist_mech;
2772 // Chance resist debuff
2773 modHitChance-=pVictim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spell->Dispel));
2775 int32 HitChance = modHitChance * 100;
2776 // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
2777 HitChance += int32(m_modSpellHitChance*100.0f);
2779 // Decrease hit chance from victim rating bonus
2780 if (pVictim->GetTypeId()==TYPEID_PLAYER)
2781 HitChance -= int32(((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_SPELL)*100.0f);
2783 if (HitChance < 100) HitChance = 100;
2784 if (HitChance > 9900) HitChance = 9900;
2786 uint32 rand = urand(0,10000);
2787 if (rand > HitChance)
2788 return SPELL_MISS_RESIST;
2789 return SPELL_MISS_NONE;
2792 SpellMissInfo Unit::SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool CanReflect)
2794 // Return evade for units in evade mode
2795 if (pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
2796 return SPELL_MISS_EVADE;
2798 // Check for immune (use charges)
2799 if (pVictim->IsImmunedToSpell(spell,true))
2800 return SPELL_MISS_IMMUNE;
2802 // All positive spells can`t miss
2803 // TODO: client not show miss log for this spells - so need find info for this in dbc and use it!
2804 if (IsPositiveSpell(spell->Id))
2805 return SPELL_MISS_NONE;
2807 // Check for immune (use charges)
2808 if (pVictim->IsImmunedToDamage(GetSpellSchoolMask(spell),true))
2809 return SPELL_MISS_IMMUNE;
2811 // Try victim reflect spell
2812 if (CanReflect)
2814 // specialized first
2815 Unit::AuraList const& mReflectSpellsSchool = pVictim->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL);
2816 for(Unit::AuraList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i)
2818 if((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spell))
2820 int32 reflectchance = (*i)->GetModifier()->m_amount;
2821 if (reflectchance > 0 && roll_chance_i(reflectchance))
2823 if((*i)->m_procCharges > 0)
2825 --(*i)->m_procCharges;
2826 if((*i)->m_procCharges==0)
2827 pVictim->RemoveAurasDueToSpell((*i)->GetId());
2829 return SPELL_MISS_REFLECT;
2834 // generic reflection
2835 Unit::AuraList const& mReflectSpells = pVictim->GetAurasByType(SPELL_AURA_REFLECT_SPELLS);
2836 for(Unit::AuraList::const_iterator i = mReflectSpells.begin(); i != mReflectSpells.end(); ++i)
2838 int32 reflectchance = (*i)->GetModifier()->m_amount;
2839 if (reflectchance > 0 && roll_chance_i(reflectchance))
2841 if((*i)->m_procCharges > 0)
2843 --(*i)->m_procCharges;
2844 if((*i)->m_procCharges==0)
2845 pVictim->RemoveAurasDueToSpell((*i)->GetId());
2847 return SPELL_MISS_REFLECT;
2852 // Temporary solution for melee based spells and spells vs SPELL_SCHOOL_NORMAL (hit result calculated after)
2853 for (int i=0;i<3;i++)
2855 if (spell->Effect[i] == SPELL_EFFECT_WEAPON_DAMAGE ||
2856 spell->Effect[i] == SPELL_EFFECT_WEAPON_PERCENT_DAMAGE ||
2857 spell->Effect[i] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG ||
2858 spell->Effect[i] == SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL)
2859 return SPELL_MISS_NONE;
2862 // TODO need use this code for spell hit result calculation
2863 // now code commented for computability
2864 switch (spell->DmgClass)
2866 case SPELL_DAMAGE_CLASS_RANGED:
2867 case SPELL_DAMAGE_CLASS_MELEE:
2868 // return MeleeSpellHitResult(pVictim, spell);
2869 return SPELL_MISS_NONE;
2870 case SPELL_DAMAGE_CLASS_NONE:
2871 case SPELL_DAMAGE_CLASS_MAGIC:
2872 return MagicSpellHitResult(pVictim, spell);
2874 return SPELL_MISS_NONE;
2877 float Unit::MeleeMissChanceCalc(const Unit *pVictim, WeaponAttackType attType) const
2879 if(!pVictim)
2880 return 0.0f;
2882 // Base misschance 5%
2883 float misschance = 5.0f;
2885 // DualWield - Melee spells and physical dmg spells - 5% , white damage 24%
2886 if (haveOffhandWeapon() && attType != RANGED_ATTACK)
2888 bool isNormal = false;
2889 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
2891 if( m_currentSpells[i] && (GetSpellSchoolMask(m_currentSpells[i]->m_spellInfo) & SPELL_SCHOOL_MASK_NORMAL) )
2893 isNormal = true;
2894 break;
2897 if (isNormal || m_currentSpells[CURRENT_MELEE_SPELL])
2899 misschance = 5.0f;
2901 else
2903 misschance = 24.0f;
2907 // PvP : PvE melee misschances per leveldif > 2
2908 int32 chance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7;
2910 int32 leveldif = int32(pVictim->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim));
2911 if(leveldif < 0)
2912 leveldif = 0;
2914 // Hit chance from attacker based on ratings and auras
2915 float m_modHitChance;
2916 if (attType == RANGED_ATTACK)
2917 m_modHitChance = m_modRangedHitChance;
2918 else
2919 m_modHitChance = m_modMeleeHitChance;
2921 if(leveldif < 3)
2922 misschance += (leveldif - m_modHitChance);
2923 else
2924 misschance += ((leveldif - 2) * chance - m_modHitChance);
2926 // Hit chance for victim based on ratings
2927 if (pVictim->GetTypeId()==TYPEID_PLAYER)
2929 if (attType == RANGED_ATTACK)
2930 misschance += ((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_RANGED);
2931 else
2932 misschance += ((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_MELEE);
2935 // Modify miss chance by victim auras
2936 if(attType == RANGED_ATTACK)
2937 misschance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE);
2938 else
2939 misschance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE);
2941 // Modify miss chance from skill difference ( bonus from skills is 0.04% )
2942 int32 skillBonus = int32(GetWeaponSkillValue(attType,pVictim)) - int32(pVictim->GetDefenseSkillValue(this));
2943 misschance -= skillBonus * 0.04f;
2945 // Limit miss chance from 0 to 60%
2946 if ( misschance < 0.0f)
2947 return 0.0f;
2948 if ( misschance > 60.0f)
2949 return 60.0f;
2951 return misschance;
2954 uint32 Unit::GetDefenseSkillValue(Unit const* target) const
2956 if(GetTypeId() == TYPEID_PLAYER)
2958 // in PvP use full skill instead current skill value
2959 uint32 value = (target && target->GetTypeId() == TYPEID_PLAYER)
2960 ? ((Player*)this)->GetMaxSkillValue(SKILL_DEFENSE)
2961 : ((Player*)this)->GetSkillValue(SKILL_DEFENSE);
2962 value += uint32(((Player*)this)->GetRatingBonusValue(CR_DEFENSE_SKILL));
2963 return value;
2965 else
2966 return GetUnitMeleeSkill(target);
2969 float Unit::GetUnitDodgeChance() const
2971 if(hasUnitState(UNIT_STAT_STUNNED))
2972 return 0.0f;
2973 if( GetTypeId() == TYPEID_PLAYER )
2974 return GetFloatValue(PLAYER_DODGE_PERCENTAGE);
2975 else
2977 if(((Creature const*)this)->isTotem())
2978 return 0.0f;
2979 else
2981 float dodge = 5.0f;
2982 dodge += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT);
2983 return dodge > 0.0f ? dodge : 0.0f;
2988 float Unit::GetUnitParryChance() const
2990 if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED))
2991 return 0.0f;
2993 float chance = 0.0f;
2995 if(GetTypeId() == TYPEID_PLAYER)
2997 Player const* player = (Player const*)this;
2998 if(player->CanParry() )
3000 Item *tmpitem = player->GetWeaponForAttack(BASE_ATTACK,true);
3001 if(!tmpitem)
3002 tmpitem = player->GetWeaponForAttack(OFF_ATTACK,true);
3004 if(tmpitem)
3005 chance = GetFloatValue(PLAYER_PARRY_PERCENTAGE);
3008 else if(GetTypeId() == TYPEID_UNIT)
3010 if(GetCreatureType() == CREATURE_TYPE_HUMANOID)
3012 chance = 5.0f;
3013 chance += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT);
3017 return chance > 0.0f ? chance : 0.0f;
3020 float Unit::GetUnitBlockChance() const
3022 if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED))
3023 return 0.0f;
3025 if(GetTypeId() == TYPEID_PLAYER)
3027 Player const* player = (Player const*)this;
3028 if(player->CanBlock() )
3030 Item *tmpitem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
3031 if(tmpitem && !tmpitem->IsBroken() && tmpitem->GetProto()->Block)
3032 return GetFloatValue(PLAYER_BLOCK_PERCENTAGE);
3034 // is player but has no block ability or no not broken shield equipped
3035 return 0.0f;
3037 else
3039 if(((Creature const*)this)->isTotem())
3040 return 0.0f;
3041 else
3043 float block = 5.0f;
3044 block += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT);
3045 return block > 0.0f ? block : 0.0f;
3050 float Unit::GetUnitCriticalChance(WeaponAttackType attackType, const Unit *pVictim) const
3052 float crit;
3054 if(GetTypeId() == TYPEID_PLAYER)
3056 switch(attackType)
3058 case BASE_ATTACK:
3059 crit = GetFloatValue( PLAYER_CRIT_PERCENTAGE );
3060 break;
3061 case OFF_ATTACK:
3062 crit = GetFloatValue( PLAYER_OFFHAND_CRIT_PERCENTAGE );
3063 break;
3064 case RANGED_ATTACK:
3065 crit = GetFloatValue( PLAYER_RANGED_CRIT_PERCENTAGE );
3066 break;
3067 // Just for good manner
3068 default:
3069 crit = 0.0f;
3070 break;
3073 else
3075 crit = 5.0f;
3076 crit += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PERCENT);
3079 // flat aura mods
3080 if(attackType == RANGED_ATTACK)
3081 crit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE);
3082 else
3083 crit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE);
3085 crit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
3087 // reduce crit chance from Rating for players
3088 if (pVictim->GetTypeId()==TYPEID_PLAYER)
3090 if (attackType==RANGED_ATTACK)
3091 crit -= ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_RANGED);
3092 else
3093 crit -= ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE);
3096 if (crit < 0.0f)
3097 crit = 0.0f;
3098 return crit;
3101 uint32 Unit::GetWeaponSkillValue (WeaponAttackType attType, Unit const* target) const
3103 uint32 value = 0;
3104 if(GetTypeId() == TYPEID_PLAYER)
3106 Item* item = ((Player*)this)->GetWeaponForAttack(attType,true);
3108 // feral or unarmed skill only for base attack
3109 if(attType != BASE_ATTACK && !item )
3110 return 0;
3112 if(((Player*)this)->IsInFeralForm())
3113 return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact
3115 // weapon skill or (unarmed for base attack)
3116 uint32 skill = item ? item->GetSkill() : SKILL_UNARMED;
3118 // in PvP use full skill instead current skill value
3119 value = (target && target->GetTypeId() == TYPEID_PLAYER)
3120 ? ((Player*)this)->GetMaxSkillValue(skill)
3121 : ((Player*)this)->GetSkillValue(skill);
3122 // Modify value from ratings
3123 value += uint32(((Player*)this)->GetRatingBonusValue(CR_WEAPON_SKILL));
3124 switch (attType)
3126 case BASE_ATTACK: value+=uint32(((Player*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_MAINHAND));break;
3127 case OFF_ATTACK: value+=uint32(((Player*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_OFFHAND));break;
3128 case RANGED_ATTACK: value+=uint32(((Player*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_RANGED));break;
3131 else
3132 value = GetUnitMeleeSkill(target);
3133 return value;
3136 void Unit::_UpdateSpells( uint32 time )
3138 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
3139 _UpdateAutoRepeatSpell();
3141 // remove finished spells from current pointers
3142 for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
3144 if (m_currentSpells[i] && m_currentSpells[i]->getState() == SPELL_STATE_FINISHED)
3146 m_currentSpells[i]->SetReferencedFromCurrent(false);
3147 m_currentSpells[i] = NULL; // remove pointer
3151 // TODO: Find a better way to prevent crash when multiple auras are removed.
3152 m_removedAuras = 0;
3153 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
3154 if ((*i).second)
3155 (*i).second->SetUpdated(false);
3157 for (AuraMap::iterator i = m_Auras.begin(), next; i != m_Auras.end(); i = next)
3159 next = i;
3160 ++next;
3161 if ((*i).second)
3163 // prevent double update
3164 if ((*i).second->IsUpdated())
3165 continue;
3166 (*i).second->SetUpdated(true);
3167 (*i).second->Update( time );
3168 // several auras can be deleted due to update
3169 if (m_removedAuras)
3171 if (m_Auras.empty()) break;
3172 next = m_Auras.begin();
3173 m_removedAuras = 0;
3178 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end();)
3180 if ((*i).second)
3182 if ( !(*i).second->GetAuraDuration() && !((*i).second->IsPermanent() || ((*i).second->IsPassive())) )
3184 RemoveAura(i);
3186 else
3188 ++i;
3191 else
3193 ++i;
3197 if(!m_gameObj.empty())
3199 std::list<GameObject*>::iterator ite1, dnext1;
3200 for (ite1 = m_gameObj.begin(); ite1 != m_gameObj.end(); ite1 = dnext1)
3202 dnext1 = ite1;
3203 //(*i)->Update( difftime );
3204 if( !(*ite1)->isSpawned() )
3206 (*ite1)->SetOwnerGUID(0);
3207 (*ite1)->SetRespawnTime(0);
3208 (*ite1)->Delete();
3209 dnext1 = m_gameObj.erase(ite1);
3211 else
3212 ++dnext1;
3217 void Unit::_UpdateAutoRepeatSpell()
3219 //check "realtime" interrupts
3220 if ( (GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isMoving()) || IsNonMeleeSpellCasted(false,false,true) )
3222 // cancel wand shoot
3223 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
3224 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
3225 m_AutoRepeatFirstCast = true;
3226 return;
3229 //apply delay
3230 if ( m_AutoRepeatFirstCast && getAttackTimer(RANGED_ATTACK) < 500 )
3231 setAttackTimer(RANGED_ATTACK,500);
3232 m_AutoRepeatFirstCast = false;
3234 //castroutine
3235 if (isAttackReady(RANGED_ATTACK))
3237 // Check if able to cast
3238 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast(true))
3240 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
3241 return;
3244 // we want to shoot
3245 Spell* spell = new Spell(this, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo, true, 0);
3246 spell->prepare(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets));
3248 // all went good, reset attack
3249 resetAttackTimer(RANGED_ATTACK);
3253 void Unit::SetCurrentCastedSpell( Spell * pSpell )
3255 assert(pSpell); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
3257 uint32 CSpellType = pSpell->GetCurrentContainer();
3259 if (pSpell == m_currentSpells[CSpellType]) return; // avoid breaking self
3261 // break same type spell if it is not delayed
3262 InterruptSpell(CSpellType,false);
3264 // special breakage effects:
3265 switch (CSpellType)
3267 case CURRENT_GENERIC_SPELL:
3269 // generic spells always break channeled not delayed spells
3270 InterruptSpell(CURRENT_CHANNELED_SPELL,false);
3272 // autorepeat breaking
3273 if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL] )
3275 // break autorepeat if not Auto Shot
3276 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
3277 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
3278 m_AutoRepeatFirstCast = true;
3280 } break;
3282 case CURRENT_CHANNELED_SPELL:
3284 // channel spells always break generic non-delayed and any channeled spells
3285 InterruptSpell(CURRENT_GENERIC_SPELL,false);
3286 InterruptSpell(CURRENT_CHANNELED_SPELL);
3288 // it also does break autorepeat if not Auto Shot
3289 if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL] &&
3290 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351 )
3291 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
3292 } break;
3294 case CURRENT_AUTOREPEAT_SPELL:
3296 // only Auto Shoot does not break anything
3297 if (pSpell->m_spellInfo->Category == 351)
3299 // generic autorepeats break generic non-delayed and channeled non-delayed spells
3300 InterruptSpell(CURRENT_GENERIC_SPELL,false);
3301 InterruptSpell(CURRENT_CHANNELED_SPELL,false);
3303 // special action: set first cast flag
3304 m_AutoRepeatFirstCast = true;
3305 } break;
3307 default:
3309 // other spell types don't break anything now
3310 } break;
3313 // current spell (if it is still here) may be safely deleted now
3314 if (m_currentSpells[CSpellType])
3315 m_currentSpells[CSpellType]->SetReferencedFromCurrent(false);
3317 // set new current spell
3318 m_currentSpells[CSpellType] = pSpell;
3319 pSpell->SetReferencedFromCurrent(true);
3322 void Unit::InterruptSpell(uint32 spellType, bool withDelayed)
3324 assert(spellType < CURRENT_MAX_SPELL);
3326 if(m_currentSpells[spellType] && (withDelayed || m_currentSpells[spellType]->getState() != SPELL_STATE_DELAYED) )
3328 // send autorepeat cancel message for autorepeat spells
3329 if (spellType == CURRENT_AUTOREPEAT_SPELL)
3331 if(GetTypeId()==TYPEID_PLAYER)
3332 ((Player*)this)->SendAutoRepeatCancel();
3335 if (m_currentSpells[spellType]->getState() != SPELL_STATE_FINISHED)
3336 m_currentSpells[spellType]->cancel();
3337 m_currentSpells[spellType]->SetReferencedFromCurrent(false);
3338 m_currentSpells[spellType] = NULL;
3342 bool Unit::IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled, bool skipAutorepeat) const
3344 // We don't do loop here to explicitly show that melee spell is excluded.
3345 // Maybe later some special spells will be excluded too.
3347 // generic spells are casted when they are not finished and not delayed
3348 if ( m_currentSpells[CURRENT_GENERIC_SPELL] &&
3349 (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) &&
3350 (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) )
3351 return(true);
3353 // channeled spells may be delayed, but they are still considered casted
3354 else if ( !skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
3355 (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED) )
3356 return(true);
3358 // autorepeat spells may be finished or delayed, but they are still considered casted
3359 else if ( !skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL] )
3360 return(true);
3362 return(false);
3365 void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id)
3367 // generic spells are interrupted if they are not finished or delayed
3368 if (m_currentSpells[CURRENT_GENERIC_SPELL] && (!spell_id || m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id==spell_id))
3370 if ( (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) &&
3371 (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) )
3372 m_currentSpells[CURRENT_GENERIC_SPELL]->cancel();
3373 m_currentSpells[CURRENT_GENERIC_SPELL]->SetReferencedFromCurrent(false);
3374 m_currentSpells[CURRENT_GENERIC_SPELL] = NULL;
3377 // autorepeat spells are interrupted if they are not finished or delayed
3378 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && (!spell_id || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id==spell_id))
3380 // send disable autorepeat packet in any case
3381 if(GetTypeId()==TYPEID_PLAYER)
3382 ((Player*)this)->SendAutoRepeatCancel();
3384 if ( (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_FINISHED) &&
3385 (withDelayed || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_DELAYED) )
3386 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->cancel();
3387 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SetReferencedFromCurrent(false);
3388 m_currentSpells[CURRENT_AUTOREPEAT_SPELL] = NULL;
3391 // channeled spells are interrupted if they are not finished, even if they are delayed
3392 if (m_currentSpells[CURRENT_CHANNELED_SPELL] && (!spell_id || m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id==spell_id))
3394 if (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED)
3395 m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel();
3396 m_currentSpells[CURRENT_CHANNELED_SPELL]->SetReferencedFromCurrent(false);
3397 m_currentSpells[CURRENT_CHANNELED_SPELL] = NULL;
3401 Spell* Unit::FindCurrentSpellBySpellId(uint32 spell_id) const
3403 for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
3404 if(m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id==spell_id)
3405 return m_currentSpells[i];
3406 return NULL;
3409 bool Unit::isInFront(Unit const* target, float distance, float arc) const
3411 return IsWithinDistInMap(target, distance) && HasInArc( arc, target );
3414 void Unit::SetInFront(Unit const* target)
3416 SetOrientation(GetAngle(target));
3419 bool Unit::isInBack(Unit const* target, float distance, float arc) const
3421 return IsWithinDistInMap(target, distance) && !HasInArc( 2 * M_PI - arc, target );
3424 bool Unit::isInAccessablePlaceFor(Creature const* c) const
3426 if(IsInWater())
3427 return c->canSwim();
3428 else
3429 return c->canWalk() || c->canFly();
3432 bool Unit::IsInWater() const
3434 return MapManager::Instance().GetBaseMap(GetMapId())->IsInWater(GetPositionX(),GetPositionY(), GetPositionZ());
3437 bool Unit::IsUnderWater() const
3439 return MapManager::Instance().GetBaseMap(GetMapId())->IsUnderWater(GetPositionX(),GetPositionY(),GetPositionZ());
3442 void Unit::DeMorph()
3444 SetDisplayId(GetNativeDisplayId());
3447 int32 Unit::GetTotalAuraModifier(AuraType auratype) const
3449 int32 modifier = 0;
3451 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3452 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3453 modifier += (*i)->GetModifier()->m_amount;
3455 return modifier;
3458 float Unit::GetTotalAuraMultiplier(AuraType auratype) const
3460 float multiplier = 1.0f;
3462 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3463 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3464 multiplier *= (100.0f + (*i)->GetModifier()->m_amount)/100.0f;
3466 return multiplier;
3469 int32 Unit::GetMaxPositiveAuraModifier(AuraType auratype) const
3471 int32 modifier = 0;
3473 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3474 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3475 if ((*i)->GetModifier()->m_amount > modifier)
3476 modifier = (*i)->GetModifier()->m_amount;
3478 return modifier;
3481 int32 Unit::GetMaxNegativeAuraModifier(AuraType auratype) const
3483 int32 modifier = 0;
3485 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3486 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3487 if ((*i)->GetModifier()->m_amount < modifier)
3488 modifier = (*i)->GetModifier()->m_amount;
3490 return modifier;
3493 int32 Unit::GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const
3495 int32 modifier = 0;
3497 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3498 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3500 Modifier* mod = (*i)->GetModifier();
3501 if (mod->m_miscvalue & misc_mask)
3502 modifier += mod->m_amount;
3504 return modifier;
3507 float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask) const
3509 float multiplier = 1.0f;
3511 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3512 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3514 Modifier* mod = (*i)->GetModifier();
3515 if (mod->m_miscvalue & misc_mask)
3516 multiplier *= (100.0f + mod->m_amount)/100.0f;
3518 return multiplier;
3521 int32 Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const
3523 int32 modifier = 0;
3525 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3526 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3528 Modifier* mod = (*i)->GetModifier();
3529 if (mod->m_miscvalue & misc_mask && mod->m_amount > modifier)
3530 modifier = mod->m_amount;
3533 return modifier;
3536 int32 Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const
3538 int32 modifier = 0;
3540 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3541 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3543 Modifier* mod = (*i)->GetModifier();
3544 if (mod->m_miscvalue & misc_mask && mod->m_amount < modifier)
3545 modifier = mod->m_amount;
3548 return modifier;
3551 int32 Unit::GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const
3553 int32 modifier = 0;
3555 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3556 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3558 Modifier* mod = (*i)->GetModifier();
3559 if (mod->m_miscvalue == misc_value)
3560 modifier += mod->m_amount;
3562 return modifier;
3565 float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype, int32 misc_value) const
3567 float multiplier = 1.0f;
3569 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3570 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3572 Modifier* mod = (*i)->GetModifier();
3573 if (mod->m_miscvalue == misc_value)
3574 multiplier *= (100.0f + mod->m_amount)/100.0f;
3576 return multiplier;
3579 int32 Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const
3581 int32 modifier = 0;
3583 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3584 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3586 Modifier* mod = (*i)->GetModifier();
3587 if (mod->m_miscvalue == misc_value && mod->m_amount > modifier)
3588 modifier = mod->m_amount;
3591 return modifier;
3594 int32 Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const
3596 int32 modifier = 0;
3598 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3599 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3601 Modifier* mod = (*i)->GetModifier();
3602 if (mod->m_miscvalue == misc_value && mod->m_amount < modifier)
3603 modifier = mod->m_amount;
3606 return modifier;
3609 bool Unit::AddAura(Aura *Aur)
3611 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
3612 if( !isAlive() && Aur->GetId() != 20584 && Aur->GetId() != 8326 && Aur->GetId() != 2584 &&
3613 (GetTypeId()!=TYPEID_PLAYER || !((Player*)this)->GetSession()->PlayerLoading()) )
3615 delete Aur;
3616 return false;
3619 if(Aur->GetTarget() != this)
3621 sLog.outError("Aura (spell %u eff %u) add to aura list of %s (lowguid: %u) but Aura target is %s (lowguid: %u)",
3622 Aur->GetId(),Aur->GetEffIndex(),(GetTypeId()==TYPEID_PLAYER?"player":"creature"),GetGUIDLow(),
3623 (Aur->GetTarget()->GetTypeId()==TYPEID_PLAYER?"player":"creature"),Aur->GetTarget()->GetGUIDLow());
3624 delete Aur;
3625 return false;
3628 SpellEntry const* aurSpellInfo = Aur->GetSpellProto();
3630 spellEffectPair spair = spellEffectPair(Aur->GetId(), Aur->GetEffIndex());
3631 AuraMap::iterator i = m_Auras.find( spair );
3633 // take out same spell
3634 if (i != m_Auras.end())
3636 // passive and persistent auras can stack with themselves any number of times
3637 if (!Aur->IsPassive() && !Aur->IsPersistent())
3639 // replace aura if next will > spell StackAmount
3640 if(aurSpellInfo->StackAmount)
3642 if(m_Auras.count(spair) >= aurSpellInfo->StackAmount)
3643 RemoveAura(i,AURA_REMOVE_BY_STACK);
3645 // if StackAmount==0 not allow auras from same caster
3646 else
3648 for(AuraMap::iterator i2 = m_Auras.lower_bound(spair); i2 != m_Auras.upper_bound(spair); ++i2)
3650 if(i2->second->GetCasterGUID()==Aur->GetCasterGUID())
3652 // can be only single (this check done at _each_ aura add
3653 RemoveAura(i2,AURA_REMOVE_BY_STACK);
3654 break;
3657 bool stop = false;
3658 switch(aurSpellInfo->EffectApplyAuraName[Aur->GetEffIndex()])
3660 // DoT/HoT/etc
3661 case SPELL_AURA_PERIODIC_DAMAGE: // allow stack
3662 case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
3663 case SPELL_AURA_PERIODIC_LEECH:
3664 case SPELL_AURA_PERIODIC_HEAL:
3665 case SPELL_AURA_OBS_MOD_HEALTH:
3666 case SPELL_AURA_PERIODIC_MANA_LEECH:
3667 case SPELL_AURA_PERIODIC_ENERGIZE:
3668 case SPELL_AURA_OBS_MOD_MANA:
3669 case SPELL_AURA_POWER_BURN_MANA:
3670 break;
3671 default: // not allow
3672 // can be only single (this check done at _each_ aura add
3673 RemoveAura(i2,AURA_REMOVE_BY_STACK);
3674 stop = true;
3675 break;
3678 if(stop)
3679 break;
3685 // passive auras stack with all (except passive spell proc auras)
3686 if ((!Aur->IsPassive() || !IsPassiveStackableSpell(Aur->GetId())) &&
3687 !(Aur->GetId() == 20584 || Aur->GetId() == 8326))
3689 if (!RemoveNoStackAurasDueToAura(Aur))
3691 delete Aur;
3692 return false; // couldn't remove conflicting aura with higher rank
3696 // update single target auras list (before aura add to aura list, to prevent unexpected remove recently added aura)
3697 if (IsSingleTargetSpell(aurSpellInfo) && Aur->GetTarget())
3699 // caster pointer can be deleted in time aura remove, find it by guid at each iteration
3700 for(;;)
3702 Unit* caster = Aur->GetCaster();
3703 if(!caster) // caster deleted and not required adding scAura
3704 break;
3706 bool restart = false;
3707 AuraList& scAuras = caster->GetSingleCastAuras();
3708 for(AuraList::iterator itr = scAuras.begin(); itr != scAuras.end(); ++itr)
3710 if( (*itr)->GetTarget() != Aur->GetTarget() &&
3711 IsSingleTargetSpells((*itr)->GetSpellProto(),aurSpellInfo) )
3713 if ((*itr)->IsInUse())
3715 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());
3716 continue;
3718 (*itr)->GetTarget()->RemoveAura((*itr)->GetId(), (*itr)->GetEffIndex());
3719 restart = true;
3720 break;
3724 if(!restart)
3726 // done
3727 scAuras.push_back(Aur);
3728 break;
3733 // add aura, register in lists and arrays
3734 Aur->_AddAura();
3735 m_Auras.insert(AuraMap::value_type(spellEffectPair(Aur->GetId(), Aur->GetEffIndex()), Aur));
3736 if (Aur->GetModifier()->m_auraname < TOTAL_AURAS)
3738 m_modAuras[Aur->GetModifier()->m_auraname].push_back(Aur);
3741 Aur->ApplyModifier(true,true);
3742 sLog.outDebug("Aura %u now is in use", Aur->GetModifier()->m_auraname);
3743 return true;
3746 void Unit::RemoveRankAurasDueToSpell(uint32 spellId)
3748 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
3749 if(!spellInfo)
3750 return;
3751 AuraMap::iterator i,next;
3752 for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
3754 next = i;
3755 ++next;
3756 uint32 i_spellId = (*i).second->GetId();
3757 if((*i).second && i_spellId && i_spellId != spellId)
3759 if(spellmgr.IsRankSpellDueToSpell(spellInfo,i_spellId))
3761 RemoveAurasDueToSpell(i_spellId);
3763 if( m_Auras.empty() )
3764 break;
3765 else
3766 next = m_Auras.begin();
3772 bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur)
3774 if (!Aur)
3775 return false;
3777 SpellEntry const* spellProto = Aur->GetSpellProto();
3778 if (!spellProto)
3779 return false;
3781 uint32 spellId = Aur->GetId();
3782 uint32 effIndex = Aur->GetEffIndex();
3784 SpellSpecific spellId_spec = GetSpellSpecific(spellId);
3786 AuraMap::iterator i,next;
3787 for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
3789 next = i;
3790 ++next;
3791 if (!(*i).second) continue;
3793 SpellEntry const* i_spellProto = (*i).second->GetSpellProto();
3795 if (!i_spellProto)
3796 continue;
3798 uint32 i_spellId = i_spellProto->Id;
3800 if(IsPassiveSpell(i_spellId))
3802 if(IsPassiveStackableSpell(i_spellId))
3803 continue;
3805 // passive non-stackable spells not stackable only with another rank of same spell
3806 if (!spellmgr.IsRankSpellDueToSpell(spellProto, i_spellId))
3807 continue;
3810 uint32 i_effIndex = (*i).second->GetEffIndex();
3812 if(i_spellId == spellId) continue;
3814 bool is_triggered_by_spell = false;
3815 // prevent triggered aura of removing aura that triggered it
3816 for(int j = 0; j < 3; ++j)
3817 if (i_spellProto->EffectTriggerSpell[j] == spellProto->Id)
3818 is_triggered_by_spell = true;
3819 if (is_triggered_by_spell) continue;
3821 for(int j = 0; j < 3; ++j)
3823 // prevent remove dummy triggered spells at next effect aura add
3824 switch(spellProto->Effect[j]) // main spell auras added added after triggered spell
3826 case SPELL_EFFECT_DUMMY:
3827 switch(spellId)
3829 case 5420: if(i_spellId==34123) is_triggered_by_spell = true; break;
3831 break;
3834 if(is_triggered_by_spell)
3835 break;
3837 // prevent remove form main spell by triggered passive spells
3838 switch(i_spellProto->EffectApplyAuraName[j]) // main aura added before triggered spell
3840 case SPELL_AURA_MOD_SHAPESHIFT:
3841 switch(i_spellId)
3843 case 24858: if(spellId==24905) is_triggered_by_spell = true; break;
3844 case 33891: if(spellId==5420 || spellId==34123) is_triggered_by_spell = true; break;
3845 case 34551: if(spellId==22688) is_triggered_by_spell = true; break;
3847 break;
3851 if(!is_triggered_by_spell)
3853 SpellSpecific i_spellId_spec = GetSpellSpecific(i_spellId);
3855 bool is_sspc = IsSingleFromSpellSpecificPerCaster(spellId_spec,i_spellId_spec);
3857 if( is_sspc && Aur->GetCasterGUID() == (*i).second->GetCasterGUID() )
3859 // cannot remove higher rank
3860 if (spellmgr.IsRankSpellDueToSpell(spellProto, i_spellId))
3861 if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
3862 return false;
3864 // Its a parent aura (create this aura in ApplyModifier)
3865 if ((*i).second->IsInUse())
3867 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());
3868 continue;
3870 RemoveAurasDueToSpell(i_spellId);
3872 if( m_Auras.empty() )
3873 break;
3874 else
3875 next = m_Auras.begin();
3877 else if( !is_sspc && spellmgr.IsNoStackSpellDueToSpell(spellId, i_spellId) )
3879 // Its a parent aura (create this aura in ApplyModifier)
3880 if ((*i).second->IsInUse())
3882 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());
3883 continue;
3885 RemoveAurasDueToSpell(i_spellId);
3887 if( m_Auras.empty() )
3888 break;
3889 else
3890 next = m_Auras.begin();
3892 // Potions stack aura by aura (elixirs/flask already checked)
3893 else if( spellProto->SpellFamilyName == SPELLFAMILY_POTION && i_spellProto->SpellFamilyName == SPELLFAMILY_POTION )
3895 if (IsNoStackAuraDueToAura(spellId, effIndex, i_spellId, i_effIndex))
3897 if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
3898 return false; // cannot remove higher rank
3900 // Its a parent aura (create this aura in ApplyModifier)
3901 if ((*i).second->IsInUse())
3903 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());
3904 continue;
3906 RemoveAura(i);
3907 next = i;
3912 return true;
3915 void Unit::RemoveAura(uint32 spellId, uint32 effindex, Aura* except)
3917 spellEffectPair spair = spellEffectPair(spellId, effindex);
3918 for(AuraMap::iterator iter = m_Auras.lower_bound(spair); iter != m_Auras.upper_bound(spair);)
3920 if(iter->second!=except)
3922 RemoveAura(iter);
3923 iter = m_Auras.lower_bound(spair);
3925 else
3926 ++iter;
3930 void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint64 casterGUID, Unit *dispeler)
3932 for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
3934 Aura *aur = iter->second;
3935 if (aur->GetId() == spellId && aur->GetCasterGUID() == casterGUID)
3937 // Custom dispel case
3938 // Unstable Affliction
3939 if (aur->GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (aur->GetSpellProto()->SpellFamilyFlags & 0x010000000000LL))
3941 int32 damage = aur->GetModifier()->m_amount*9;
3942 uint64 caster_guid = aur->GetCasterGUID();
3944 // Remove aura
3945 RemoveAura(iter, AURA_REMOVE_BY_DISPEL);
3947 // backfire damage and silence
3948 dispeler->CastCustomSpell(dispeler, 31117, &damage, NULL, NULL, true, NULL, NULL,caster_guid);
3950 iter = m_Auras.begin(); // iterator can be invalidate at cast if self-dispel
3952 else
3953 RemoveAura(iter, AURA_REMOVE_BY_DISPEL);
3955 else
3956 ++iter;
3960 void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit *stealer)
3962 for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
3964 Aura *aur = iter->second;
3965 if (aur->GetId() == spellId && aur->GetCasterGUID() == casterGUID)
3967 int32 basePoints = aur->GetBasePoints();
3968 // construct the new aura for the attacker
3969 Aura * new_aur = CreateAura(aur->GetSpellProto(), aur->GetEffIndex(), &basePoints, stealer);
3970 if(!new_aur)
3971 continue;
3973 // set its duration and maximum duration
3974 // max duration 2 minutes (in msecs)
3975 int32 dur = aur->GetAuraDuration();
3976 const int32 max_dur = 2*MINUTE*1000;
3977 new_aur->SetAuraMaxDuration( max_dur > dur ? dur : max_dur );
3978 new_aur->SetAuraDuration( max_dur > dur ? dur : max_dur );
3980 // add the new aura to stealer
3981 stealer->AddAura(new_aur);
3983 // Remove aura as dispel
3984 RemoveAura(iter, AURA_REMOVE_BY_DISPEL);
3986 else
3987 ++iter;
3991 void Unit::RemoveAurasDueToSpellByCancel(uint32 spellId)
3993 for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
3995 if (iter->second->GetId() == spellId)
3996 RemoveAura(iter, AURA_REMOVE_BY_CANCEL);
3997 else
3998 ++iter;
4002 void Unit::RemoveAurasWithDispelType( DispelType type )
4004 // Create dispel mask by dispel type
4005 uint32 dispelMask = GetDispellMask(type);
4006 // Dispel all existing auras vs current dispel type
4007 AuraMap& auras = GetAuras();
4008 for(AuraMap::iterator itr = auras.begin(); itr != auras.end(); )
4010 SpellEntry const* spell = itr->second->GetSpellProto();
4011 if( (1<<spell->Dispel) & dispelMask )
4013 // Dispel aura
4014 RemoveAurasDueToSpell(spell->Id);
4015 itr = auras.begin();
4017 else
4018 ++itr;
4022 void Unit::RemoveSingleAuraFromStack(uint32 spellId, uint32 effindex)
4024 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
4025 if(iter != m_Auras.end())
4026 RemoveAura(iter);
4029 void Unit::RemoveAurasDueToSpell(uint32 spellId, Aura* except)
4031 for (int i = 0; i < 3; ++i)
4032 RemoveAura(spellId,i,except);
4035 void Unit::RemoveAurasDueToItemSpell(Item* castItem,uint32 spellId)
4037 for (int k=0; k < 3; ++k)
4039 spellEffectPair spair = spellEffectPair(spellId, k);
4040 for (AuraMap::iterator iter = m_Auras.lower_bound(spair); iter != m_Auras.upper_bound(spair);)
4042 if (iter->second->GetCastItemGUID() == castItem->GetGUID())
4044 RemoveAura(iter);
4045 iter = m_Auras.upper_bound(spair); // overwrite by more appropriate
4047 else
4048 ++iter;
4053 void Unit::RemoveAurasWithInterruptFlags(uint32 flags)
4055 for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
4057 if (iter->second->GetSpellProto()->AuraInterruptFlags & flags)
4058 RemoveAura(iter);
4059 else
4060 ++iter;
4064 void Unit::RemoveNotOwnSingleTargetAuras()
4066 // single target auras from other casters
4067 for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
4069 if (iter->second->GetCasterGUID()!=GetGUID() && IsSingleTargetSpell(iter->second->GetSpellProto()))
4070 RemoveAura(iter);
4071 else
4072 ++iter;
4075 // single target auras at other targets
4076 AuraList& scAuras = GetSingleCastAuras();
4077 for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end(); )
4079 Aura* aura = *iter;
4080 if (aura->GetTarget()!=this)
4082 scAuras.erase(iter); // explicitly remove, instead waiting remove in RemoveAura
4083 aura->GetTarget()->RemoveAura(aura->GetId(),aura->GetEffIndex());
4084 iter = scAuras.begin();
4086 else
4087 ++iter;
4092 void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode)
4094 Aura* Aur = i->second;
4095 SpellEntry const* AurSpellInfo = Aur->GetSpellProto();
4097 Unit* caster = NULL;
4098 if (IsSingleTargetSpell(AurSpellInfo))
4100 caster = Aur->GetCaster();
4101 if(caster)
4103 AuraList& scAuras = caster->GetSingleCastAuras();
4104 scAuras.remove(Aur);
4106 else
4108 sLog.outError("Couldn't find the caster of the single target aura, may crash later!");
4109 assert(false);
4113 // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
4114 if (Aur->GetModifier()->m_auraname < TOTAL_AURAS)
4116 m_modAuras[Aur->GetModifier()->m_auraname].remove(Aur);
4119 // Set remove mode
4120 Aur->SetRemoveMode(mode);
4121 // some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura
4122 // remove aura from list before to prevent deleting it before
4123 m_Auras.erase(i);
4124 ++m_removedAuras; // internal count used by unit update
4126 // Statue unsummoned at aura remove
4127 Totem* statue = NULL;
4128 bool caster_channeled = false;
4129 if(IsChanneledSpell(AurSpellInfo))
4131 if(!caster) // can be already located for IsSingleTargetSpell case
4132 caster = Aur->GetCaster();
4134 if(caster)
4136 if(caster->GetTypeId()==TYPEID_UNIT && ((Creature*)caster)->isTotem() && ((Totem*)caster)->GetTotemType()==TOTEM_STATUE)
4137 statue = ((Totem*)caster);
4138 else
4139 caster_channeled = caster==this;
4143 sLog.outDebug("Aura %u now is remove mode %d",Aur->GetModifier()->m_auraname, mode);
4144 Aur->ApplyModifier(false,true);
4145 Aur->_RemoveAura();
4146 delete Aur;
4148 if(caster_channeled)
4149 RemoveAurasAtChanneledTarget (AurSpellInfo);
4151 if(statue)
4152 statue->UnSummon();
4154 // only way correctly remove all auras from list
4155 if( m_Auras.empty() )
4156 i = m_Auras.end();
4157 else
4158 i = m_Auras.begin();
4161 void Unit::RemoveAllAuras()
4163 while (!m_Auras.empty())
4165 AuraMap::iterator iter = m_Auras.begin();
4166 RemoveAura(iter);
4170 void Unit::RemoveArenaAuras(bool onleave)
4172 // in join, remove positive buffs, on end, remove negative
4173 // used to remove positive visible auras in arenas
4174 for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
4176 if ( !(iter->second->GetSpellProto()->AttributesEx4 & (1<<21)) // don't remove stances, shadowform, pally/hunter auras
4177 && !iter->second->IsPassive() // don't remove passive auras
4178 && (!(iter->second->GetSpellProto()->Attributes & SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY) || !(iter->second->GetSpellProto()->Attributes & SPELL_ATTR_UNK8)) // not unaffected by invulnerability auras or not having that unknown flag (that seemed the most probable)
4179 && (iter->second->IsPositive() ^ onleave)) // remove positive buffs on enter, negative buffs on leave
4180 RemoveAura(iter);
4181 else
4182 ++iter;
4186 void Unit::RemoveAllAurasOnDeath()
4188 // used just after dieing to remove all visible auras
4189 // and disable the mods for the passive ones
4190 for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
4192 if (!iter->second->IsPassive() && !iter->second->IsDeathPersistent())
4193 RemoveAura(iter, AURA_REMOVE_BY_DEATH);
4194 else
4195 ++iter;
4199 void Unit::DelayAura(uint32 spellId, uint32 effindex, int32 delaytime)
4201 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
4202 if (iter != m_Auras.end())
4204 if (iter->second->GetAuraDuration() < delaytime)
4205 iter->second->SetAuraDuration(0);
4206 else
4207 iter->second->SetAuraDuration(iter->second->GetAuraDuration() - delaytime);
4208 iter->second->UpdateAuraDuration();
4209 sLog.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter->second->GetModifier()->m_auraname, GetGUIDLow(), iter->second->GetAuraDuration());
4213 void Unit::_RemoveAllAuraMods()
4215 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
4217 (*i).second->ApplyModifier(false);
4221 void Unit::_ApplyAllAuraMods()
4223 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
4225 (*i).second->ApplyModifier(true);
4229 Aura* Unit::GetAura(uint32 spellId, uint32 effindex)
4231 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
4232 if (iter != m_Auras.end())
4233 return iter->second;
4234 return NULL;
4237 void Unit::AddDynObject(DynamicObject* dynObj)
4239 m_dynObjGUIDs.push_back(dynObj->GetGUID());
4242 void Unit::RemoveDynObject(uint32 spellid)
4244 if(m_dynObjGUIDs.empty())
4245 return;
4246 for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
4248 DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs.begin());
4249 if(!dynObj)
4251 i = m_dynObjGUIDs.erase(i);
4253 else if(spellid == 0 || dynObj->GetSpellId() == spellid)
4255 dynObj->Delete();
4256 i = m_dynObjGUIDs.erase(i);
4258 else
4259 ++i;
4263 void Unit::RemoveAllDynObjects()
4265 while(!m_dynObjGUIDs.empty())
4267 DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs.begin());
4268 if(dynObj)
4269 dynObj->Delete();
4270 m_dynObjGUIDs.erase(m_dynObjGUIDs.begin());
4274 DynamicObject * Unit::GetDynObject(uint32 spellId, uint32 effIndex)
4276 for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
4278 DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs.begin());
4279 if(!dynObj)
4281 i = m_dynObjGUIDs.erase(i);
4282 continue;
4285 if (dynObj->GetSpellId() == spellId && dynObj->GetEffIndex() == effIndex)
4286 return dynObj;
4287 ++i;
4289 return NULL;
4292 DynamicObject * Unit::GetDynObject(uint32 spellId)
4294 for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
4296 DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs.begin());
4297 if(!dynObj)
4299 i = m_dynObjGUIDs.erase(i);
4300 continue;
4303 if (dynObj->GetSpellId() == spellId)
4304 return dynObj;
4305 ++i;
4307 return NULL;
4310 void Unit::AddGameObject(GameObject* gameObj)
4312 assert(gameObj && gameObj->GetOwnerGUID()==0);
4313 m_gameObj.push_back(gameObj);
4314 gameObj->SetOwnerGUID(GetGUID());
4317 void Unit::RemoveGameObject(GameObject* gameObj, bool del)
4319 assert(gameObj && gameObj->GetOwnerGUID()==GetGUID());
4321 // GO created by some spell
4322 if ( GetTypeId()==TYPEID_PLAYER && gameObj->GetSpellId() )
4324 SpellEntry const* createBySpell = sSpellStore.LookupEntry(gameObj->GetSpellId());
4325 // Need activate spell use for owner
4326 if (createBySpell && createBySpell->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE)
4327 ((Player*)this)->SendCooldownEvent(createBySpell);
4329 gameObj->SetOwnerGUID(0);
4330 m_gameObj.remove(gameObj);
4331 if(del)
4333 gameObj->SetRespawnTime(0);
4334 gameObj->Delete();
4338 void Unit::RemoveGameObject(uint32 spellid, bool del)
4340 if(m_gameObj.empty())
4341 return;
4342 std::list<GameObject*>::iterator i, next;
4343 for (i = m_gameObj.begin(); i != m_gameObj.end(); i = next)
4345 next = i;
4346 if(spellid == 0 || (*i)->GetSpellId() == spellid)
4348 (*i)->SetOwnerGUID(0);
4349 if(del)
4351 (*i)->SetRespawnTime(0);
4352 (*i)->Delete();
4355 next = m_gameObj.erase(i);
4357 else
4358 ++next;
4362 void Unit::RemoveAllGameObjects()
4364 // remove references to unit
4365 for(std::list<GameObject*>::iterator i = m_gameObj.begin(); i != m_gameObj.end();)
4367 (*i)->SetOwnerGUID(0);
4368 (*i)->SetRespawnTime(0);
4369 (*i)->Delete();
4370 i = m_gameObj.erase(i);
4374 void Unit::SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, SpellSchoolMask damageSchoolMask,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit)
4376 sLog.outDebug("Sending: SMSG_SPELLNONMELEEDAMAGELOG");
4377 WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16+4+4+1+4+4+1+1+4+4+1)); // we guess size
4378 data.append(target->GetPackGUID());
4379 data.append(GetPackGUID());
4380 data << uint32(SpellID);
4381 data << uint32(Damage-AbsorbedDamage-Resist-Blocked);
4382 data << uint8(damageSchoolMask); // spell school
4383 data << uint32(AbsorbedDamage); // AbsorbedDamage
4384 data << uint32(Resist); // resist
4385 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
4386 data << uint8(0); // unk isFromAura
4387 data << uint32(Blocked); // blocked
4388 data << uint32(CriticalHit ? 0x27 : 0x25); // hitType, flags: 0x2 - SPELL_HIT_TYPE_CRIT, 0x10 - replace caster?
4389 data << uint8(0); // isDebug?
4390 SendMessageToSet( &data, true );
4393 void Unit::SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
4395 WorldPacket data(SMSG_SPELLLOGMISS, (4+8+1+4+8+1));
4396 data << uint32(spellID);
4397 data << uint64(GetGUID());
4398 data << uint8(0); // can be 0 or 1
4399 data << uint32(1); // target count
4400 // for(i = 0; i < target count; ++i)
4401 data << uint64(target->GetGUID()); // target GUID
4402 data << uint8(missInfo);
4403 // end loop
4404 SendMessageToSet(&data, true);
4407 void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount)
4409 sLog.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
4411 WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16+45)); // we guess size
4412 data << (uint32)HitInfo;
4413 data.append(GetPackGUID());
4414 data.append(target->GetPackGUID());
4415 data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount);
4417 data << (uint8)SwingType; // count?
4419 // for(i = 0; i < SwingType; ++i)
4420 data << (uint32)damageSchoolMask;
4421 data << (float)(Damage-AbsorbDamage-Resist-BlockedAmount);
4422 // still need to double check damage
4423 data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount);
4424 data << (uint32)AbsorbDamage;
4425 data << (uint32)Resist;
4426 // end loop
4428 data << (uint32)TargetState;
4430 if( AbsorbDamage == 0 ) //also 0x3E8 = 0x3E8, check when that happens
4431 data << (uint32)0;
4432 else
4433 data << (uint32)-1;
4435 data << (uint32)0;
4436 data << (uint32)BlockedAmount;
4438 SendMessageToSet( &data, true );
4441 void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 damage, SpellSchoolMask damageSchoolMask, SpellEntry const *procSpell, bool isTriggeredSpell, WeaponAttackType attType)
4443 sLog.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker, procVictim);
4444 if(procSpell)
4445 sLog.outDebug("ProcDamageAndSpell: invoked due to spell id %u %s", procSpell->Id, (isTriggeredSpell?"(triggered)":""));
4447 // Assign melee/ranged proc flags for magic attacks, that are actually melee/ranged abilities
4448 // not assign for spell proc triggered spell to prevent infinity (or unexpected 2-3 times) melee damage spell proc call with melee damage effect
4449 // That is the question though if it's fully correct
4450 if(procSpell && !isTriggeredSpell)
4452 if(procSpell->DmgClass == SPELL_DAMAGE_CLASS_MELEE)
4454 if(procAttacker & PROC_FLAG_HIT_SPELL) procAttacker |= PROC_FLAG_HIT_MELEE;
4455 if(procAttacker & PROC_FLAG_CRIT_SPELL) procAttacker |= PROC_FLAG_CRIT_MELEE;
4456 if(procVictim & PROC_FLAG_STRUCK_SPELL) procVictim |= PROC_FLAG_STRUCK_MELEE;
4457 if(procVictim & PROC_FLAG_STRUCK_CRIT_SPELL) procVictim |= PROC_FLAG_STRUCK_CRIT_MELEE;
4458 attType = BASE_ATTACK; // Melee abilities are assumed to be dealt with mainhand weapon
4460 else if (procSpell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
4462 if(procAttacker & PROC_FLAG_HIT_SPELL) procAttacker |= PROC_FLAG_HIT_RANGED;
4463 if(procAttacker & PROC_FLAG_CRIT_SPELL) procAttacker |= PROC_FLAG_CRIT_RANGED;
4464 if(procVictim & PROC_FLAG_STRUCK_SPELL) procVictim |= PROC_FLAG_STRUCK_RANGED;
4465 if(procVictim & PROC_FLAG_STRUCK_CRIT_SPELL) procVictim |= PROC_FLAG_STRUCK_CRIT_RANGED;
4466 attType = RANGED_ATTACK;
4469 if(damage && (procVictim & (PROC_FLAG_STRUCK_MELEE|PROC_FLAG_STRUCK_RANGED|PROC_FLAG_STRUCK_SPELL)))
4470 procVictim |= (PROC_FLAG_TAKE_DAMAGE|PROC_FLAG_TOUCH);
4472 // Not much to do if no flags are set.
4473 if (procAttacker)
4475 // processing auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set
4476 ProcDamageAndSpellFor(false,pVictim,procAttacker,attackerProcEffectAuraTypes,attType, procSpell, damage, damageSchoolMask);
4477 ProcDamageAndSpellFor(false,pVictim,procAttacker,attackerProcCastAuraTypes,attType, procSpell, damage, damageSchoolMask);
4480 // Now go on with a victim's events'n'auras
4481 // Not much to do if no flags are set or there is no victim
4482 if(pVictim && pVictim->isAlive() && procVictim)
4484 // processing auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set
4485 pVictim->ProcDamageAndSpellFor(true,this,procVictim,victimProcEffectAuraTypes,attType,procSpell, damage, damageSchoolMask);
4486 pVictim->ProcDamageAndSpellFor(true,this,procVictim,victimProcCastAuraTypes,attType,procSpell, damage, damageSchoolMask);
4490 void Unit::CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, SpellSchoolMask damageSchoolMask, WeaponAttackType attType, MeleeHitOutcome outcome, SpellEntry const *spellCasted, bool isTriggeredSpell)
4492 if(!pVictim)
4493 return;
4495 uint32 procAttacker = PROC_FLAG_NONE;
4496 uint32 procVictim = PROC_FLAG_NONE;
4498 switch(outcome)
4500 case MELEE_HIT_EVADE:
4501 return;
4502 case MELEE_HIT_MISS:
4503 if(attType == BASE_ATTACK || attType == OFF_ATTACK)
4505 procAttacker = PROC_FLAG_MISS;
4507 break;
4508 case MELEE_HIT_BLOCK_CRIT:
4509 case MELEE_HIT_CRIT:
4510 if(spellCasted && attType == BASE_ATTACK)
4512 procAttacker |= PROC_FLAG_CRIT_SPELL;
4513 procVictim |= PROC_FLAG_STRUCK_CRIT_SPELL;
4514 if ( outcome == MELEE_HIT_BLOCK_CRIT )
4516 procVictim |= PROC_FLAG_BLOCK;
4517 procAttacker |= PROC_FLAG_TARGET_BLOCK;
4520 else if(attType == BASE_ATTACK || attType == OFF_ATTACK)
4522 procAttacker = PROC_FLAG_HIT_MELEE | PROC_FLAG_CRIT_MELEE;
4523 procVictim = PROC_FLAG_STRUCK_MELEE | PROC_FLAG_STRUCK_CRIT_MELEE;
4525 else
4527 procAttacker = PROC_FLAG_HIT_RANGED | PROC_FLAG_CRIT_RANGED;
4528 procVictim = PROC_FLAG_STRUCK_RANGED | PROC_FLAG_STRUCK_CRIT_RANGED;
4530 break;
4531 case MELEE_HIT_PARRY:
4532 procAttacker = PROC_FLAG_TARGET_DODGE_OR_PARRY;
4533 procVictim = PROC_FLAG_PARRY;
4534 break;
4535 case MELEE_HIT_BLOCK:
4536 procAttacker = PROC_FLAG_TARGET_BLOCK;
4537 procVictim = PROC_FLAG_BLOCK;
4538 break;
4539 case MELEE_HIT_DODGE:
4540 procAttacker = PROC_FLAG_TARGET_DODGE_OR_PARRY;
4541 procVictim = PROC_FLAG_DODGE;
4542 break;
4543 case MELEE_HIT_CRUSHING:
4544 if(attType == BASE_ATTACK || attType == OFF_ATTACK)
4546 procAttacker = PROC_FLAG_HIT_MELEE | PROC_FLAG_CRIT_MELEE;
4547 procVictim = PROC_FLAG_STRUCK_MELEE | PROC_FLAG_STRUCK_CRIT_MELEE;
4549 else
4551 procAttacker = PROC_FLAG_HIT_RANGED | PROC_FLAG_CRIT_RANGED;
4552 procVictim = PROC_FLAG_STRUCK_RANGED | PROC_FLAG_STRUCK_CRIT_RANGED;
4554 break;
4555 default:
4556 if(attType == BASE_ATTACK || attType == OFF_ATTACK)
4558 procAttacker = PROC_FLAG_HIT_MELEE;
4559 procVictim = PROC_FLAG_STRUCK_MELEE;
4561 else
4563 procAttacker = PROC_FLAG_HIT_RANGED;
4564 procVictim = PROC_FLAG_STRUCK_RANGED;
4566 break;
4569 if(damage > 0)
4570 procVictim |= PROC_FLAG_TAKE_DAMAGE;
4572 if(procAttacker != PROC_FLAG_NONE || procVictim != PROC_FLAG_NONE)
4573 ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, damageSchoolMask, spellCasted, isTriggeredSpell, attType);
4576 bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * /*procSpell*/, uint32 /*procFlag*/, uint32 cooldown)
4578 SpellEntry const *hasteSpell = triggeredByAura->GetSpellProto();
4580 Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4581 ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL;
4583 uint32 triggered_spell_id = 0;
4584 Unit* target = pVictim;
4585 int32 basepoints0 = 0;
4587 switch(hasteSpell->SpellFamilyName)
4589 case SPELLFAMILY_ROGUE:
4591 switch(hasteSpell->Id)
4593 // Blade Flurry
4594 case 13877:
4595 case 33735:
4597 target = SelectNearbyTarget();
4598 if(!target)
4599 return false;
4600 basepoints0 = damage;
4601 triggered_spell_id = 22482;
4602 break;
4605 break;
4609 // processed charge only counting case
4610 if(!triggered_spell_id)
4611 return true;
4613 SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
4615 if(!triggerEntry)
4617 sLog.outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u",hasteSpell->Id,triggered_spell_id);
4618 return false;
4621 // default case
4622 if(!target || target!=this && !target->isAlive())
4623 return false;
4625 if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
4626 return false;
4628 if(basepoints0)
4629 CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
4630 else
4631 CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura);
4633 if( cooldown && GetTypeId()==TYPEID_PLAYER )
4634 ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown);
4636 return true;
4639 bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 cooldown)
4641 SpellEntry const *dummySpell = triggeredByAura->GetSpellProto ();
4642 uint32 effIndex = triggeredByAura->GetEffIndex ();
4644 Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4645 ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL;
4647 uint32 triggered_spell_id = 0;
4648 Unit* target = pVictim;
4649 int32 basepoints0 = 0;
4651 switch(dummySpell->SpellFamilyName)
4653 case SPELLFAMILY_GENERIC:
4655 switch (dummySpell->Id)
4657 // Eye of Eye
4658 case 9799:
4659 case 25988:
4661 // prevent damage back from weapon special attacks
4662 if (!procSpell || procSpell->DmgClass != SPELL_DAMAGE_CLASS_MAGIC )
4663 return false;
4665 // return damage % to attacker but < 50% own total health
4666 basepoints0 = triggeredByAura->GetModifier()->m_amount*int32(damage)/100;
4667 if(basepoints0 > GetMaxHealth()/2)
4668 basepoints0 = GetMaxHealth()/2;
4670 triggered_spell_id = 25997;
4671 break;
4673 // Sweeping Strikes
4674 case 12328:
4675 case 18765:
4676 case 35429:
4678 // prevent chain of triggered spell from same triggered spell
4679 if(procSpell && procSpell->Id==26654)
4680 return false;
4682 target = SelectNearbyTarget();
4683 if(!target)
4684 return false;
4686 triggered_spell_id = 26654;
4687 break;
4689 // Unstable Power
4690 case 24658:
4692 if (!procSpell || procSpell->Id == 24659)
4693 return false;
4694 // Need remove one 24659 aura
4695 RemoveSingleAuraFromStack(24659, 0);
4696 RemoveSingleAuraFromStack(24659, 1);
4697 return true;
4699 // Restless Strength
4700 case 24661:
4702 // Need remove one 24662 aura
4703 RemoveSingleAuraFromStack(24662, 0);
4704 return true;
4706 // Adaptive Warding (Frostfire Regalia set)
4707 case 28764:
4709 if(!procSpell)
4710 return false;
4712 // find Mage Armor
4713 bool found = false;
4714 AuraList const& mRegenInterupt = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
4715 for(AuraList::const_iterator iter = mRegenInterupt.begin(); iter != mRegenInterupt.end(); ++iter)
4717 if(SpellEntry const* iterSpellProto = (*iter)->GetSpellProto())
4719 if(iterSpellProto->SpellFamilyName==SPELLFAMILY_MAGE && (iterSpellProto->SpellFamilyFlags & 0x10000000))
4721 found=true;
4722 break;
4726 if(!found)
4727 return false;
4729 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
4731 case SPELL_SCHOOL_NORMAL:
4732 case SPELL_SCHOOL_HOLY:
4733 return false; // ignored
4734 case SPELL_SCHOOL_FIRE: triggered_spell_id = 28765; break;
4735 case SPELL_SCHOOL_NATURE: triggered_spell_id = 28768; break;
4736 case SPELL_SCHOOL_FROST: triggered_spell_id = 28766; break;
4737 case SPELL_SCHOOL_SHADOW: triggered_spell_id = 28769; break;
4738 case SPELL_SCHOOL_ARCANE: triggered_spell_id = 28770; break;
4739 default:
4740 return false;
4743 target = this;
4744 break;
4746 // Obsidian Armor (Justice Bearer`s Pauldrons shoulder)
4747 case 27539:
4749 if(!procSpell)
4750 return false;
4752 // not from DoT
4753 bool found = false;
4754 for(int j = 0; j < 3; ++j)
4756 if(procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE||procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT)
4758 found = true;
4759 break;
4762 if(found)
4763 return false;
4765 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
4767 case SPELL_SCHOOL_NORMAL:
4768 return false; // ignore
4769 case SPELL_SCHOOL_HOLY: triggered_spell_id = 27536; break;
4770 case SPELL_SCHOOL_FIRE: triggered_spell_id = 27533; break;
4771 case SPELL_SCHOOL_NATURE: triggered_spell_id = 27538; break;
4772 case SPELL_SCHOOL_FROST: triggered_spell_id = 27534; break;
4773 case SPELL_SCHOOL_SHADOW: triggered_spell_id = 27535; break;
4774 case SPELL_SCHOOL_ARCANE: triggered_spell_id = 27540; break;
4775 default:
4776 return false;
4779 target = this;
4780 break;
4782 // Mana Leech (Passive) (Priest Pet Aura)
4783 case 28305:
4785 // Cast on owner
4786 target = GetOwner();
4787 if(!target)
4788 return false;
4790 basepoints0 = int32(damage * 2.5f); // manaregen
4791 triggered_spell_id = 34650;
4792 break;
4794 // Mark of Malice
4795 case 33493:
4797 // Cast finish spell at last charge
4798 if (triggeredByAura->m_procCharges > 1)
4799 return false;
4801 target = this;
4802 triggered_spell_id = 33494;
4803 break;
4805 // Twisted Reflection (boss spell)
4806 case 21063:
4807 triggered_spell_id = 21064;
4808 break;
4809 // Vampiric Aura (boss spell)
4810 case 38196:
4812 basepoints0 = 3 * damage; // 300%
4813 if (basepoints0 < 0)
4814 return false;
4816 triggered_spell_id = 31285;
4817 target = this;
4818 break;
4820 // Aura of Madness (Darkmoon Card: Madness trinket)
4821 //=====================================================
4822 // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior)
4823 // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid)
4824 // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid)
4825 // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4826 // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes)
4827 // 41005 Manic: +35 haste (spell, melee and ranged) (All classes)
4828 // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter)
4829 // 41011 Martyr Complex: +35 stamina (All classes)
4830 // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4831 // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4832 case 39446:
4834 if(GetTypeId() != TYPEID_PLAYER)
4835 return false;
4837 // Select class defined buff
4838 switch (getClass())
4840 case CLASS_PALADIN: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4841 case CLASS_DRUID: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4843 uint32 RandomSpell[]={39511,40997,40998,40999,41002,41005,41009,41011,41409};
4844 triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ];
4845 break;
4847 case CLASS_ROGUE: // 39511,40997,40998,41002,41005,41011
4848 case CLASS_WARRIOR: // 39511,40997,40998,41002,41005,41011
4850 uint32 RandomSpell[]={39511,40997,40998,41002,41005,41011};
4851 triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ];
4852 break;
4854 case CLASS_PRIEST: // 40999,41002,41005,41009,41011,41406,41409
4855 case CLASS_SHAMAN: // 40999,41002,41005,41009,41011,41406,41409
4856 case CLASS_MAGE: // 40999,41002,41005,41009,41011,41406,41409
4857 case CLASS_WARLOCK: // 40999,41002,41005,41009,41011,41406,41409
4859 uint32 RandomSpell[]={40999,41002,41005,41009,41011,41406,41409};
4860 triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ];
4861 break;
4863 case CLASS_HUNTER: // 40997,40999,41002,41005,41009,41011,41406,41409
4865 uint32 RandomSpell[]={40997,40999,41002,41005,41009,41011,41406,41409};
4866 triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ];
4867 break;
4869 default:
4870 return false;
4873 target = this;
4874 if (roll_chance_i(10))
4875 ((Player*)this)->Say("This is Madness!", LANG_UNIVERSAL);
4876 break;
4879 // TODO: need find item for aura and triggered spells
4880 // Sunwell Exalted Caster Neck (??? neck)
4881 // cast ??? Light's Wrath if Exalted by Aldor
4882 // cast ??? Arcane Bolt if Exalted by Scryers*/
4883 case 46569:
4884 return false; // disable for while
4887 if(GetTypeId() != TYPEID_PLAYER)
4888 return false;
4890 // Get Aldor reputation rank
4891 if (((Player *)this)->GetReputationRank(932) == REP_EXALTED)
4893 target = this;
4894 triggered_spell_id = ???
4895 break;
4897 // Get Scryers reputation rank
4898 if (((Player *)this)->GetReputationRank(934) == REP_EXALTED)
4900 triggered_spell_id = ???
4901 break;
4903 return false;
4904 }/**/
4905 // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck)
4906 // cast 45479 Light's Wrath if Exalted by Aldor
4907 // cast 45429 Arcane Bolt if Exalted by Scryers
4908 case 45481:
4910 if(GetTypeId() != TYPEID_PLAYER)
4911 return false;
4913 // Get Aldor reputation rank
4914 if (((Player *)this)->GetReputationRank(932) == REP_EXALTED)
4916 target = this;
4917 triggered_spell_id = 45479;
4918 break;
4920 // Get Scryers reputation rank
4921 if (((Player *)this)->GetReputationRank(934) == REP_EXALTED)
4923 triggered_spell_id = 45429;
4924 break;
4926 return false;
4928 // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck)
4929 // cast 45480 Light's Strength if Exalted by Aldor
4930 // cast 45428 Arcane Strike if Exalted by Scryers
4931 case 45482:
4933 if(GetTypeId() != TYPEID_PLAYER)
4934 return false;
4936 // Get Aldor reputation rank
4937 if (((Player *)this)->GetReputationRank(932) == REP_EXALTED)
4939 target = this;
4940 triggered_spell_id = 45480;
4941 break;
4943 // Get Scryers reputation rank
4944 if (((Player *)this)->GetReputationRank(934) == REP_EXALTED)
4946 triggered_spell_id = 45428;
4947 break;
4949 return false;
4951 // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck)
4952 // cast 45431 Arcane Insight if Exalted by Aldor
4953 // cast 45432 Light's Ward if Exalted by Scryers
4954 case 45483:
4956 if(GetTypeId() != TYPEID_PLAYER)
4957 return false;
4959 // Get Aldor reputation rank
4960 if (((Player *)this)->GetReputationRank(932) == REP_EXALTED)
4962 target = this;
4963 triggered_spell_id = 45432;
4964 break;
4966 // Get Scryers reputation rank
4967 if (((Player *)this)->GetReputationRank(934) == REP_EXALTED)
4969 target = this;
4970 triggered_spell_id = 45431;
4971 break;
4973 return false;
4975 // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck)
4976 // cast 45478 Light's Salvation if Exalted by Aldor
4977 // cast 45430 Arcane Surge if Exalted by Scryers
4978 case 45484:
4980 if(GetTypeId() != TYPEID_PLAYER)
4981 return false;
4983 // Get Aldor reputation rank
4984 if (((Player *)this)->GetReputationRank(932) == REP_EXALTED)
4986 target = this;
4987 triggered_spell_id = 45478;
4988 break;
4990 // Get Scryers reputation rank
4991 if (((Player *)this)->GetReputationRank(934) == REP_EXALTED)
4993 triggered_spell_id = 45430;
4994 break;
4996 return false;
4999 break;
5001 case SPELLFAMILY_MAGE:
5003 // Magic Absorption
5004 if (dummySpell->SpellIconID == 459) // only this spell have SpellIconID == 459 and dummy aura
5006 if (getPowerType() != POWER_MANA)
5007 return false;
5009 // mana reward
5010 basepoints0 = (triggeredByAura->GetModifier()->m_amount * GetMaxPower(POWER_MANA) / 100);
5011 target = this;
5012 triggered_spell_id = 29442;
5013 break;
5015 // Master of Elements
5016 if (dummySpell->SpellIconID == 1920)
5018 if(!procSpell)
5019 return false;
5021 // mana cost save
5022 basepoints0 = procSpell->manaCost * triggeredByAura->GetModifier()->m_amount/100;
5023 if( basepoints0 <=0 )
5024 return false;
5026 target = this;
5027 triggered_spell_id = 29077;
5028 break;
5030 switch(dummySpell->Id)
5032 // Ignite
5033 case 11119:
5034 case 11120:
5035 case 12846:
5036 case 12847:
5037 case 12848:
5039 switch (dummySpell->Id)
5041 case 11119: basepoints0 = int32(0.04f*damage); break;
5042 case 11120: basepoints0 = int32(0.08f*damage); break;
5043 case 12846: basepoints0 = int32(0.12f*damage); break;
5044 case 12847: basepoints0 = int32(0.16f*damage); break;
5045 case 12848: basepoints0 = int32(0.20f*damage); break;
5046 default:
5047 sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell->Id);
5048 return false;
5051 triggered_spell_id = 12654;
5052 break;
5054 // Combustion
5055 case 11129:
5057 //last charge and crit
5058 if( triggeredByAura->m_procCharges <= 1 && (procFlag & PROC_FLAG_CRIT_SPELL) )
5060 RemoveAurasDueToSpell(28682); //-> remove Combustion auras
5061 return true; // charge counting (will removed)
5064 CastSpell(this, 28682, true, castItem, triggeredByAura);
5065 return(procFlag & PROC_FLAG_CRIT_SPELL);// charge update only at crit hits, no hidden cooldowns
5068 break;
5070 case SPELLFAMILY_WARRIOR:
5072 // Retaliation
5073 if(dummySpell->SpellFamilyFlags==0x0000000800000000LL)
5075 // check attack comes not from behind
5076 if (!HasInArc(M_PI, pVictim))
5077 return false;
5079 triggered_spell_id = 22858;
5080 break;
5082 break;
5084 case SPELLFAMILY_WARLOCK:
5086 // Seed of Corruption
5087 if (dummySpell->SpellFamilyFlags & 0x0000001000000000LL)
5089 Modifier* mod = triggeredByAura->GetModifier();
5090 // if damage is more than need or target die from damage deal finish spell
5091 // FIX ME: not triggered currently at death
5092 if( mod->m_amount <= damage || GetHealth() <= damage )
5094 // remember guid before aura delete
5095 uint64 casterGuid = triggeredByAura->GetCasterGUID();
5097 // Remove aura (before cast for prevent infinite loop handlers)
5098 RemoveAurasDueToSpell(triggeredByAura->GetId());
5100 // Cast finish spell (triggeredByAura already not exist!)
5101 CastSpell(this, 27285, true, castItem, NULL, casterGuid);
5102 return true; // no hidden cooldown
5105 // Damage counting
5106 mod->m_amount-=damage;
5107 return true;
5109 // Seed of Corruption (Mobs cast) - no die req
5110 if (dummySpell->SpellFamilyFlags == 0x00LL && dummySpell->SpellIconID == 1932)
5112 Modifier* mod = triggeredByAura->GetModifier();
5113 // if damage is more than need deal finish spell
5114 if( mod->m_amount <= damage )
5116 // remember guid before aura delete
5117 uint64 casterGuid = triggeredByAura->GetCasterGUID();
5119 // Remove aura (before cast for prevent infinite loop handlers)
5120 RemoveAurasDueToSpell(triggeredByAura->GetId());
5122 // Cast finish spell (triggeredByAura already not exist!)
5123 CastSpell(this, 32865, true, castItem, NULL, casterGuid);
5124 return true; // no hidden cooldown
5126 // Damage counting
5127 mod->m_amount-=damage;
5128 return true;
5130 switch(dummySpell->Id)
5132 // Nightfall
5133 case 18094:
5134 case 18095:
5136 target = this;
5137 triggered_spell_id = 17941;
5138 break;
5140 //Soul Leech
5141 case 30293:
5142 case 30295:
5143 case 30296:
5145 // health
5146 basepoints0 = int32(damage*triggeredByAura->GetModifier()->m_amount/100);
5147 target = this;
5148 triggered_spell_id = 30294;
5149 break;
5151 // Shadowflame (Voidheart Raiment set bonus)
5152 case 37377:
5154 triggered_spell_id = 37379;
5155 break;
5157 // Pet Healing (Corruptor Raiment or Rift Stalker Armor)
5158 case 37381:
5160 target = GetPet();
5161 if(!target)
5162 return false;
5164 // heal amount
5165 basepoints0 = damage * triggeredByAura->GetModifier()->m_amount/100;
5166 triggered_spell_id = 37382;
5167 break;
5169 // Shadowflame Hellfire (Voidheart Raiment set bonus)
5170 case 39437:
5172 triggered_spell_id = 37378;
5173 break;
5176 break;
5178 case SPELLFAMILY_PRIEST:
5180 // Vampiric Touch
5181 if( dummySpell->SpellFamilyFlags & 0x0000040000000000LL )
5183 if(!pVictim || !pVictim->isAlive())
5184 return false;
5186 // pVictim is caster of aura
5187 if(triggeredByAura->GetCasterGUID() != pVictim->GetGUID())
5188 return false;
5190 // energize amount
5191 basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100;
5192 pVictim->CastCustomSpell(pVictim,34919,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
5193 return true; // no hidden cooldown
5195 switch(dummySpell->Id)
5197 // Vampiric Embrace
5198 case 15286:
5200 if(!pVictim || !pVictim->isAlive())
5201 return false;
5203 // pVictim is caster of aura
5204 if(triggeredByAura->GetCasterGUID() != pVictim->GetGUID())
5205 return false;
5207 // heal amount
5208 basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100;
5209 pVictim->CastCustomSpell(pVictim,15290,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
5210 return true; // no hidden cooldown
5212 // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen)
5213 case 40438:
5215 // Shadow Word: Pain
5216 if( procSpell->SpellFamilyFlags & 0x0000000000008000LL )
5217 triggered_spell_id = 40441;
5218 // Renew
5219 else if( procSpell->SpellFamilyFlags & 0x0000000000000010LL )
5220 triggered_spell_id = 40440;
5221 else
5222 return false;
5224 target = this;
5225 break;
5227 // Oracle Healing Bonus ("Garments of the Oracle" set)
5228 case 26169:
5230 // heal amount
5231 basepoints0 = int32(damage * 10/100);
5232 target = this;
5233 triggered_spell_id = 26170;
5234 break;
5236 // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set
5237 case 39372:
5239 if(!procSpell || (GetSpellSchoolMask(procSpell) & (SPELL_SCHOOL_MASK_FROST | SPELL_SCHOOL_MASK_SHADOW))==0 )
5240 return false;
5242 // heal amount
5243 basepoints0 = int32(damage * 2 / 100);
5244 target = this;
5245 triggered_spell_id = 39373;
5246 break;
5248 // Vestments of Faith (Priest Tier 3) - 4 pieces bonus
5249 case 28809:
5251 triggered_spell_id = 28810;
5252 break;
5255 break;
5257 case SPELLFAMILY_DRUID:
5259 switch(dummySpell->Id)
5261 // Healing Touch (Dreamwalker Raiment set)
5262 case 28719:
5264 // mana back
5265 basepoints0 = int32(procSpell->manaCost * 30 / 100);
5266 target = this;
5267 triggered_spell_id = 28742;
5268 break;
5270 // Healing Touch Refund (Idol of Longevity trinket)
5271 case 28847:
5273 target = this;
5274 triggered_spell_id = 28848;
5275 break;
5277 // Mana Restore (Malorne Raiment set / Malorne Regalia set)
5278 case 37288:
5279 case 37295:
5281 target = this;
5282 triggered_spell_id = 37238;
5283 break;
5285 // Druid Tier 6 Trinket
5286 case 40442:
5288 float chance;
5290 // Starfire
5291 if( procSpell->SpellFamilyFlags & 0x0000000000000004LL )
5293 triggered_spell_id = 40445;
5294 chance = 25.f;
5296 // Rejuvenation
5297 else if( procSpell->SpellFamilyFlags & 0x0000000000000010LL )
5299 triggered_spell_id = 40446;
5300 chance = 25.f;
5302 // Mangle (cat/bear)
5303 else if( procSpell->SpellFamilyFlags & 0x0000044000000000LL )
5305 triggered_spell_id = 40452;
5306 chance = 40.f;
5308 else
5309 return false;
5311 if (!roll_chance_f(chance))
5312 return false;
5314 target = this;
5315 break;
5317 // Maim Interrupt
5318 case 44835:
5320 // Deadly Interrupt Effect
5321 triggered_spell_id = 32747;
5322 break;
5325 break;
5327 case SPELLFAMILY_ROGUE:
5329 switch(dummySpell->Id)
5331 // Deadly Throw Interrupt
5332 case 32748:
5334 // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw
5335 if(this == pVictim)
5336 return false;
5338 triggered_spell_id = 32747;
5339 break;
5342 // Quick Recovery
5343 if( dummySpell->SpellIconID == 2116 )
5345 if(!procSpell)
5346 return false;
5348 // only rogue's finishing moves (maybe need additional checks)
5349 if( procSpell->SpellFamilyName!=SPELLFAMILY_ROGUE ||
5350 (procSpell->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE) == 0)
5351 return false;
5353 // energy cost save
5354 basepoints0 = procSpell->manaCost * triggeredByAura->GetModifier()->m_amount/100;
5355 if(basepoints0 <= 0)
5356 return false;
5358 target = this;
5359 triggered_spell_id = 31663;
5360 break;
5362 break;
5364 case SPELLFAMILY_HUNTER:
5366 // Thrill of the Hunt
5367 if ( dummySpell->SpellIconID == 2236 )
5369 if(!procSpell)
5370 return false;
5372 // mana cost save
5373 basepoints0 = procSpell->manaCost * 40/100;
5374 if(basepoints0 <= 0)
5375 return false;
5377 target = this;
5378 triggered_spell_id = 34720;
5379 break;
5381 break;
5383 case SPELLFAMILY_PALADIN:
5385 // Seal of Righteousness - melee proc dummy
5386 if (dummySpell->SpellFamilyFlags&0x000000008000000LL && triggeredByAura->GetEffIndex()==0)
5388 if(GetTypeId() != TYPEID_PLAYER)
5389 return false;
5391 uint32 spellId;
5392 switch (triggeredByAura->GetId())
5394 case 21084: spellId = 25742; break; // Rank 1
5395 case 20287: spellId = 25740; break; // Rank 2
5396 case 20288: spellId = 25739; break; // Rank 3
5397 case 20289: spellId = 25738; break; // Rank 4
5398 case 20290: spellId = 25737; break; // Rank 5
5399 case 20291: spellId = 25736; break; // Rank 6
5400 case 20292: spellId = 25735; break; // Rank 7
5401 case 20293: spellId = 25713; break; // Rank 8
5402 case 27155: spellId = 27156; break; // Rank 9
5403 default:
5404 sLog.outError("Unit::HandleDummyAuraProc: non handled possibly SoR (Id = %u)", triggeredByAura->GetId());
5405 return false;
5407 Item *item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
5408 float speed = (item ? item->GetProto()->Delay : BASE_ATTACK_TIME)/1000.0f;
5410 float damageBasePoints;
5411 if(item && item->GetProto()->InventoryType == INVTYPE_2HWEAPON)
5412 // two hand weapon
5413 damageBasePoints=1.20f*triggeredByAura->GetModifier()->m_amount * 1.2f * 1.03f * speed/100.0f + 1;
5414 else
5415 // one hand weapon/no weapon
5416 damageBasePoints=0.85f*ceil(triggeredByAura->GetModifier()->m_amount * 1.2f * 1.03f * speed/100.0f) - 1;
5418 int32 damagePoint = int32(damageBasePoints + 0.03f * (GetWeaponDamageRange(BASE_ATTACK,MINDAMAGE)+GetWeaponDamageRange(BASE_ATTACK,MAXDAMAGE))/2.0f) + 1;
5420 // apply damage bonuses manually
5421 if(damagePoint >= 0)
5422 damagePoint = SpellDamageBonus(pVictim, dummySpell, damagePoint, SPELL_DIRECT_DAMAGE);
5424 CastCustomSpell(pVictim,spellId,&damagePoint,NULL,NULL,true,NULL, triggeredByAura);
5425 return true; // no hidden cooldown
5427 // Seal of Blood do damage trigger
5428 if(dummySpell->SpellFamilyFlags & 0x0000040000000000LL)
5430 switch(triggeredByAura->GetEffIndex())
5432 case 0:
5433 // prevent chain triggering
5434 if(procSpell && procSpell->Id==31893 )
5435 return false;
5437 triggered_spell_id = 31893;
5438 break;
5439 case 1:
5441 // damage
5442 basepoints0 = triggeredByAura->GetModifier()->m_amount * damage / 100;
5443 target = this;
5444 triggered_spell_id = 32221;
5445 break;
5450 switch(dummySpell->Id)
5452 // Holy Power (Redemption Armor set)
5453 case 28789:
5455 if(!pVictim)
5456 return false;
5458 // Set class defined buff
5459 switch (pVictim->getClass())
5461 case CLASS_PALADIN:
5462 case CLASS_PRIEST:
5463 case CLASS_SHAMAN:
5464 case CLASS_DRUID:
5465 triggered_spell_id = 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5466 break;
5467 case CLASS_MAGE:
5468 case CLASS_WARLOCK:
5469 triggered_spell_id = 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5470 break;
5471 case CLASS_HUNTER:
5472 case CLASS_ROGUE:
5473 triggered_spell_id = 28791; // Increases the friendly target's attack power by $s1 for $d.
5474 break;
5475 case CLASS_WARRIOR:
5476 triggered_spell_id = 28790; // Increases the friendly target's armor
5477 break;
5478 default:
5479 return false;
5481 break;
5483 //Seal of Vengeance
5484 case 31801:
5486 if(effIndex != 0) // effect 1,2 used by seal unleashing code
5487 return false;
5489 triggered_spell_id = 31803;
5490 break;
5492 // Spiritual Att.
5493 case 31785:
5494 case 33776:
5496 // if healed by another unit (pVictim)
5497 if(this == pVictim)
5498 return false;
5500 // heal amount
5501 basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100;
5502 target = this;
5503 triggered_spell_id = 31786;
5504 break;
5506 // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal)
5507 case 40470:
5509 if( !procSpell )
5510 return false;
5512 float chance;
5514 // Flash of light/Holy light
5515 if( procSpell->SpellFamilyFlags & 0x00000000C0000000LL)
5517 triggered_spell_id = 40471;
5518 chance = 15.f;
5520 // Judgement
5521 else if( procSpell->SpellFamilyFlags & 0x0000000000800000LL )
5523 triggered_spell_id = 40472;
5524 chance = 50.f;
5526 else
5527 return false;
5529 if (!roll_chance_f(chance))
5530 return false;
5532 break;
5535 break;
5537 case SPELLFAMILY_SHAMAN:
5539 switch(dummySpell->Id)
5541 // Totemic Power (The Earthshatterer set)
5542 case 28823:
5544 if( !pVictim )
5545 return false;
5547 // Set class defined buff
5548 switch (pVictim->getClass())
5550 case CLASS_PALADIN:
5551 case CLASS_PRIEST:
5552 case CLASS_SHAMAN:
5553 case CLASS_DRUID:
5554 triggered_spell_id = 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5555 break;
5556 case CLASS_MAGE:
5557 case CLASS_WARLOCK:
5558 triggered_spell_id = 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5559 break;
5560 case CLASS_HUNTER:
5561 case CLASS_ROGUE:
5562 triggered_spell_id = 28826; // Increases the friendly target's attack power by $s1 for $d.
5563 break;
5564 case CLASS_WARRIOR:
5565 triggered_spell_id = 28827; // Increases the friendly target's armor
5566 break;
5567 default:
5568 return false;
5570 break;
5572 // Lesser Healing Wave (Totem of Flowing Water Relic)
5573 case 28849:
5575 target = this;
5576 triggered_spell_id = 28850;
5577 break;
5579 // Windfury Weapon (Passive) 1-5 Ranks
5580 case 33757:
5582 if(GetTypeId()!=TYPEID_PLAYER)
5583 return false;
5585 if(!castItem || !castItem->IsEquipped())
5586 return false;
5588 // custom cooldown processing case
5589 if( cooldown && ((Player*)this)->HasSpellCooldown(dummySpell->Id))
5590 return false;
5592 uint32 spellId;
5593 switch (castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)))
5595 case 283: spellId = 33757; break; //1 Rank
5596 case 284: spellId = 33756; break; //2 Rank
5597 case 525: spellId = 33755; break; //3 Rank
5598 case 1669:spellId = 33754; break; //4 Rank
5599 case 2636:spellId = 33727; break; //5 Rank
5600 default:
5602 sLog.outError("Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)",
5603 castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)),dummySpell->Id);
5604 return false;
5608 SpellEntry const* windfurySpellEntry = sSpellStore.LookupEntry(spellId);
5609 if(!windfurySpellEntry)
5611 sLog.outError("Unit::HandleDummyAuraProc: non existed spell id: %u (Windfury)",spellId);
5612 return false;
5615 int32 extra_attack_power = CalculateSpellDamage(windfurySpellEntry,0,windfurySpellEntry->EffectBasePoints[0],pVictim);
5617 // Off-Hand case
5618 if ( castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND )
5620 // Value gained from additional AP
5621 basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(OFF_ATTACK)/1000/2);
5622 triggered_spell_id = 33750;
5624 // Main-Hand case
5625 else
5627 // Value gained from additional AP
5628 basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(BASE_ATTACK)/1000);
5629 triggered_spell_id = 25504;
5632 // apply cooldown before cast to prevent processing itself
5633 if( cooldown )
5634 ((Player*)this)->AddSpellCooldown(dummySpell->Id,0,time(NULL) + cooldown);
5636 // Attack Twice
5637 for ( uint32 i = 0; i<2; ++i )
5638 CastCustomSpell(pVictim,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
5640 return true;
5642 // Shaman Tier 6 Trinket
5643 case 40463:
5645 if( !procSpell )
5646 return false;
5648 float chance;
5649 if (procSpell->SpellFamilyFlags & 0x0000000000000001LL)
5651 triggered_spell_id = 40465; // Lightning Bolt
5652 chance = 15.f;
5654 else if (procSpell->SpellFamilyFlags & 0x0000000000000080LL)
5656 triggered_spell_id = 40465; // Lesser Healing Wave
5657 chance = 10.f;
5659 else if (procSpell->SpellFamilyFlags & 0x0000001000000000LL)
5661 triggered_spell_id = 40466; // Stormstrike
5662 chance = 50.f;
5664 else
5665 return false;
5667 if (!roll_chance_f(chance))
5668 return false;
5670 target = this;
5671 break;
5675 // Earth Shield
5676 if(dummySpell->SpellFamilyFlags==0x40000000000LL)
5678 if(GetTypeId() != TYPEID_PLAYER)
5679 return false;
5681 // heal
5682 basepoints0 = triggeredByAura->GetModifier()->m_amount;
5683 target = this;
5684 triggered_spell_id = 379;
5685 break;
5687 // Lightning Overload
5688 if (dummySpell->SpellIconID == 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura
5690 if(!procSpell || GetTypeId() != TYPEID_PLAYER || !pVictim )
5691 return false;
5693 // custom cooldown processing case
5694 if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(dummySpell->Id))
5695 return false;
5697 uint32 spellId = 0;
5698 // Every Lightning Bolt and Chain Lightning spell have duplicate vs half damage and zero cost
5699 switch (procSpell->Id)
5701 // Lightning Bolt
5702 case 403: spellId = 45284; break; // Rank 1
5703 case 529: spellId = 45286; break; // Rank 2
5704 case 548: spellId = 45287; break; // Rank 3
5705 case 915: spellId = 45288; break; // Rank 4
5706 case 943: spellId = 45289; break; // Rank 5
5707 case 6041: spellId = 45290; break; // Rank 6
5708 case 10391: spellId = 45291; break; // Rank 7
5709 case 10392: spellId = 45292; break; // Rank 8
5710 case 15207: spellId = 45293; break; // Rank 9
5711 case 15208: spellId = 45294; break; // Rank 10
5712 case 25448: spellId = 45295; break; // Rank 11
5713 case 25449: spellId = 45296; break; // Rank 12
5714 // Chain Lightning
5715 case 421: spellId = 45297; break; // Rank 1
5716 case 930: spellId = 45298; break; // Rank 2
5717 case 2860: spellId = 45299; break; // Rank 3
5718 case 10605: spellId = 45300; break; // Rank 4
5719 case 25439: spellId = 45301; break; // Rank 5
5720 case 25442: spellId = 45302; break; // Rank 6
5721 default:
5722 sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell->Id);
5723 return false;
5725 // No thread generated mod
5726 SpellModifier *mod = new SpellModifier;
5727 mod->op = SPELLMOD_THREAT;
5728 mod->value = -100;
5729 mod->type = SPELLMOD_PCT;
5730 mod->spellId = dummySpell->Id;
5731 mod->effectId = 0;
5732 mod->lastAffected = NULL;
5733 mod->mask = 0x0000000000000003LL;
5734 mod->charges = 0;
5735 ((Player*)this)->AddSpellMod(mod, true);
5737 // Remove cooldown (Chain Lightning - have Category Recovery time)
5738 if (procSpell->SpellFamilyFlags & 0x0000000000000002LL)
5739 ((Player*)this)->RemoveSpellCooldown(spellId);
5741 // Hmmm.. in most case spells already set half basepoints but...
5742 // Lightning Bolt (2-10 rank) have full basepoint and half bonus from level
5743 // As on wiki:
5744 // BUG: Rank 2 to 10 (and maybe 11) of Lightning Bolt will proc another Bolt with FULL damage (not halved). This bug is known and will probably be fixed soon.
5745 // So - no add changes :)
5746 CastSpell(pVictim, spellId, true, castItem, triggeredByAura);
5748 ((Player*)this)->AddSpellMod(mod, false);
5750 if( cooldown && GetTypeId()==TYPEID_PLAYER )
5751 ((Player*)this)->AddSpellCooldown(dummySpell->Id,0,time(NULL) + cooldown);
5753 return true;
5755 break;
5757 default:
5758 break;
5761 // processed charge only counting case
5762 if(!triggered_spell_id)
5763 return true;
5765 SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
5767 if(!triggerEntry)
5769 sLog.outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u",dummySpell->Id,triggered_spell_id);
5770 return false;
5773 // default case
5774 if(!target || target!=this && !target->isAlive())
5775 return false;
5777 if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
5778 return false;
5780 if(basepoints0)
5781 CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
5782 else
5783 CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura);
5785 if( cooldown && GetTypeId()==TYPEID_PLAYER )
5786 ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown);
5788 return true;
5791 bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 procFlags,WeaponAttackType attackType, uint32 cooldown)
5793 SpellEntry const* auraSpellInfo = triggeredByAura->GetSpellProto();
5795 Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
5796 ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL;
5798 uint32 triggered_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()];
5799 Unit* target = !(procFlags & PROC_FLAG_HEAL) && IsPositiveSpell(triggered_spell_id) ? this : pVictim;
5800 int32 basepoints0 = 0;
5802 switch(auraSpellInfo->SpellFamilyName)
5804 case SPELLFAMILY_GENERIC:
5806 switch(auraSpellInfo->Id)
5808 // Aegis of Preservation
5809 case 23780:
5810 //Aegis Heal (instead non-existed triggered spell)
5811 triggered_spell_id = 23781;
5812 target = this;
5813 break;
5814 // Elune's Touch (moonkin mana restore)
5815 case 24905:
5817 // Elune's Touch (instead non-existed triggered spell)
5818 triggered_spell_id = 33926;
5819 basepoints0 = int32(0.3f * GetTotalAttackPowerValue(BASE_ATTACK));
5820 target = this;
5821 break;
5823 // Enlightenment
5824 case 29601:
5826 // only for cast with mana price
5827 if(!procSpell || procSpell->powerType!=POWER_MANA || procSpell->manaCost==0 && procSpell->ManaCostPercentage==0 && procSpell->manaCostPerlevel==0)
5828 return false;
5829 break; // fall through to normal cast
5831 // Health Restore
5832 case 33510:
5834 // at melee hit call std triggered spell
5835 if(procFlags & PROC_FLAG_HIT_MELEE)
5836 break; // fall through to normal cast
5838 // Mark of Conquest - else (at range hit) called custom case
5839 triggered_spell_id = 39557;
5840 target = this;
5841 break;
5843 // Shaleskin
5844 case 36576:
5845 return true; // nothing to do
5846 // Forgotten Knowledge (Blade of Wizardry)
5847 case 38319:
5848 // only for harmful enemy targeted spell
5849 if(!pVictim || pVictim==this || !procSpell || IsPositiveSpell(procSpell->Id))
5850 return false;
5851 break; // fall through to normal cast
5852 // Aura of Wrath (Darkmoon Card: Wrath trinket bonus)
5853 case 39442:
5855 // proc only at non-crit hits
5856 if(procFlags & (PROC_FLAG_CRIT_MELEE|PROC_FLAG_CRIT_RANGED|PROC_FLAG_CRIT_SPELL))
5857 return false;
5858 break; // fall through to normal cast
5860 // Augment Pain (Timbal's Focusing Crystal trinket bonus)
5861 case 45054:
5863 if(!procSpell)
5864 return false;
5866 //only periodic damage can trigger spell
5867 bool found = false;
5868 for(int j = 0; j < 3; ++j)
5870 if( procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE ||
5871 procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT ||
5872 procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_LEECH )
5874 found = true;
5875 break;
5878 if(!found)
5879 return false;
5881 break; // fall through to normal cast
5883 // Evasive Maneuvers (Commendation of Kael'thas)
5884 case 45057:
5886 // damage taken that reduces below 35% health
5887 // does NOT mean you must have been >= 35% before
5888 if (int32(GetHealth())-int32(damage) >= int32(GetMaxHealth()*0.35f))
5889 return false;
5890 break; // fall through to normal cast
5894 switch(triggered_spell_id)
5896 // Setup
5897 case 15250:
5899 // applied only for main target
5900 if(!pVictim || pVictim != getVictim())
5901 return false;
5903 // continue normal case
5904 break;
5906 // Shamanistic Rage triggered spell
5907 case 30824:
5908 basepoints0 = int32(GetTotalAttackPowerValue(BASE_ATTACK)*triggeredByAura->GetModifier()->m_amount/100);
5909 break;
5911 break;
5913 case SPELLFAMILY_MAGE:
5915 switch(auraSpellInfo->SpellIconID)
5917 // Blazing Speed
5918 case 2127:
5919 //Blazing Speed (instead non-existed triggered spell)
5920 triggered_spell_id = 31643;
5921 target = this;
5922 break;
5924 switch(auraSpellInfo->Id)
5926 // Persistent Shield (Scarab Brooch)
5927 case 26467:
5928 basepoints0 = int32(damage * 0.15f);
5929 break;
5931 break;
5933 case SPELLFAMILY_WARRIOR:
5935 //Rampage
5936 if((auraSpellInfo->SpellFamilyFlags & 0x100000) && auraSpellInfo->SpellIconID==2006)
5938 //all ranks have effect[0]==AURA (Proc Trigger Spell, non-existed)
5939 //and effect[1]==TriggerSpell
5940 if(auraSpellInfo->Effect[1]!=SPELL_EFFECT_TRIGGER_SPELL)
5942 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have wrong effect in RM",triggeredByAura->GetSpellProto()->Id);
5943 return false;
5945 triggered_spell_id = auraSpellInfo->EffectTriggerSpell[1];
5946 break; // fall through to normal cast
5948 break;
5950 case SPELLFAMILY_WARLOCK:
5952 // Pyroclasm
5953 if(auraSpellInfo->SpellFamilyFlags == 0x0000000000000000 && auraSpellInfo->SpellIconID==1137)
5955 // last case for Hellfire that damage caster also but don't must stun caster
5956 if( pVictim == this )
5957 return false;
5959 // custom chance
5960 float chance = 0;
5961 switch (triggeredByAura->GetId())
5963 case 18096: chance = 13.0f; break;
5964 case 18073: chance = 26.0f; break;
5966 if (!roll_chance_f(chance))
5967 return false;
5969 // Pyroclasm (instead non-existed triggered spell)
5970 triggered_spell_id = 18093;
5971 target = pVictim;
5972 break;
5974 // Drain Soul
5975 if(auraSpellInfo->SpellFamilyFlags & 0x0000000000004000)
5977 bool found = false;
5978 Unit::AuraList const& mAddFlatModifier = GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
5979 for(Unit::AuraList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i)
5981 //Improved Drain Soul
5982 if ((*i)->GetModifier()->m_miscvalue == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellProto()->SpellIconID == 113)
5984 int32 value2 = CalculateSpellDamage((*i)->GetSpellProto(),2,(*i)->GetSpellProto()->EffectBasePoints[2],this);
5985 basepoints0 = value2 * GetMaxPower(POWER_MANA) / 100;
5986 // Drain Soul
5987 CastCustomSpell(this, 18371, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
5988 break;
5991 // Not remove charge (aura removed on death in any cases)
5992 // Need for correct work Drain Soul SPELL_AURA_CHANNEL_DEATH_ITEM aura
5993 return false;
5995 break;
5997 case SPELLFAMILY_PRIEST:
5999 //Blessed Recovery
6000 if(auraSpellInfo->SpellFamilyFlags == 0x00000000LL && auraSpellInfo->SpellIconID==1875)
6002 switch (triggeredByAura->GetSpellProto()->Id)
6004 case 27811: triggered_spell_id = 27813; break;
6005 case 27815: triggered_spell_id = 27817; break;
6006 case 27816: triggered_spell_id = 27818; break;
6007 default:
6008 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura->GetSpellProto()->Id);
6009 return false;
6012 int32 heal_amount = damage * triggeredByAura->GetModifier()->m_amount / 100;
6013 basepoints0 = heal_amount/3;
6014 target = this;
6015 break;
6017 // Shadowguard
6018 if((auraSpellInfo->SpellFamilyFlags & 0x80000000LL) && auraSpellInfo->SpellVisual==7958)
6020 switch(triggeredByAura->GetSpellProto()->Id)
6022 case 18137:
6023 triggered_spell_id = 28377; break; // Rank 1
6024 case 19308:
6025 triggered_spell_id = 28378; break; // Rank 2
6026 case 19309:
6027 triggered_spell_id = 28379; break; // Rank 3
6028 case 19310:
6029 triggered_spell_id = 28380; break; // Rank 4
6030 case 19311:
6031 triggered_spell_id = 28381; break; // Rank 5
6032 case 19312:
6033 triggered_spell_id = 28382; break; // Rank 6
6034 case 25477:
6035 triggered_spell_id = 28385; break; // Rank 7
6036 default:
6037 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura->GetSpellProto()->Id);
6038 return false;
6040 target = pVictim;
6041 break;
6043 break;
6045 case SPELLFAMILY_DRUID:
6047 switch(auraSpellInfo->Id)
6049 // Leader of the Pack (triggering Improved Leader of the Pack heal)
6050 case 24932:
6052 if (triggeredByAura->GetModifier()->m_amount == 0)
6053 return false;
6054 basepoints0 = triggeredByAura->GetModifier()->m_amount * GetMaxHealth() / 100;
6055 triggered_spell_id = 34299;
6056 break;
6058 // Druid Forms Trinket (Druid Tier5 Trinket, triggers different spells per Form)
6059 case 37336:
6061 switch(m_form)
6063 case FORM_BEAR:
6064 case FORM_DIREBEAR:
6065 triggered_spell_id=37340; break;// Ursine Blessing
6066 case FORM_CAT:
6067 triggered_spell_id=37341; break;// Feline Blessing
6068 case FORM_TREE:
6069 triggered_spell_id=37342; break;// Slyvan Blessing
6070 case FORM_MOONKIN:
6071 triggered_spell_id=37343; break;// Lunar Blessing
6072 case FORM_NONE:
6073 triggered_spell_id=37344; break;// Cenarion Blessing (for caster form, except FORM_MOONKIN)
6074 default:
6075 return false;
6078 target = this;
6079 break;
6082 break;
6084 case SPELLFAMILY_ROGUE:
6086 if(auraSpellInfo->SpellFamilyFlags == 0x0000000000000000LL)
6088 switch(auraSpellInfo->SpellIconID)
6090 // Combat Potency
6091 case 2260:
6093 // skip non offhand attacks
6094 if(attackType!=OFF_ATTACK)
6095 return false;
6096 break; // fall through to normal cast
6100 break;
6102 case SPELLFAMILY_PALADIN:
6104 if(auraSpellInfo->SpellFamilyFlags == 0x00000000LL)
6106 switch(auraSpellInfo->Id)
6108 // Lightning Capacitor
6109 case 37657:
6111 // trinket ProcTriggerSpell but for safe checks for player
6112 if(!castItem || !pVictim || !pVictim->isAlive() || GetTypeId()!=TYPEID_PLAYER)
6113 return false;
6115 if(((Player*)this)->HasSpellCooldown(37657))
6116 return false;
6118 // stacking
6119 CastSpell(this, 37658, true, castItem, triggeredByAura);
6120 // 2.5s cooldown before it can stack again, current system allow 1 sec step in cooldown
6121 ((Player*)this)->AddSpellCooldown(37657,0,time(NULL)+(roll_chance_i(50) ? 2 : 3));
6123 // counting
6124 uint32 count = 0;
6125 AuraList const& dummyAura = GetAurasByType(SPELL_AURA_DUMMY);
6126 for(AuraList::const_iterator itr = dummyAura.begin(); itr != dummyAura.end(); ++itr)
6127 if((*itr)->GetId()==37658)
6128 ++count;
6130 // release at 3 aura in stack
6131 if(count <= 2)
6132 return true; // main triggered spell casted anyway
6134 RemoveAurasDueToSpell(37658);
6135 CastSpell(pVictim, 37661, true, castItem, triggeredByAura);
6136 return true;
6138 // Healing Discount
6139 case 37705:
6140 // Healing Trance (instead non-existed triggered spell)
6141 triggered_spell_id = 37706;
6142 target = this;
6143 break;
6144 // HoTs on Heals (Fel Reaver's Piston trinket)
6145 case 38299:
6147 // at direct heal effect
6148 if(!procSpell || !IsSpellHaveEffect(procSpell,SPELL_EFFECT_HEAL))
6149 return false;
6151 // single proc at time
6152 AuraList const& scAuras = GetSingleCastAuras();
6153 for(AuraList::const_iterator itr = scAuras.begin(); itr != scAuras.end(); ++itr)
6154 if((*itr)->GetId()==triggered_spell_id)
6155 return false;
6157 // positive cast at victim instead self
6158 target = pVictim;
6159 break;
6162 switch(auraSpellInfo->SpellIconID)
6164 case 241:
6166 switch(auraSpellInfo->EffectTriggerSpell[0])
6168 //Illumination
6169 case 18350:
6171 if(!procSpell)
6172 return false;
6174 // procspell is triggered spell but we need mana cost of original casted spell
6175 uint32 originalSpellId = procSpell->Id;
6177 // Holy Shock
6178 if(procSpell->SpellFamilyName == SPELLFAMILY_PALADIN)
6180 if(procSpell->SpellFamilyFlags & 0x0001000000000000LL)
6182 switch(procSpell->Id)
6184 case 25914: originalSpellId = 20473; break;
6185 case 25913: originalSpellId = 20929; break;
6186 case 25903: originalSpellId = 20930; break;
6187 case 27175: originalSpellId = 27174; break;
6188 case 33074: originalSpellId = 33072; break;
6189 default:
6190 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell->Id);
6191 return false;
6196 SpellEntry const *originalSpell = sSpellStore.LookupEntry(originalSpellId);
6197 if(!originalSpell)
6199 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu",originalSpellId);
6200 return false;
6203 // percent stored in effect 1 (class scripts) base points
6204 int32 percent = auraSpellInfo->EffectBasePoints[1]+1;
6206 basepoints0 = originalSpell->manaCost*percent/100;
6207 triggered_spell_id = 20272;
6208 target = this;
6209 break;
6212 break;
6216 if(auraSpellInfo->SpellFamilyFlags & 0x00080000)
6218 switch(auraSpellInfo->SpellIconID)
6220 //Judgement of Wisdom (overwrite non existing triggered spell call in spell.dbc
6221 case 206:
6223 if(!pVictim || !pVictim->isAlive())
6224 return false;
6226 switch(triggeredByAura->GetSpellProto()->Id)
6228 case 20186:
6229 triggered_spell_id = 20268; // Rank 1
6230 break;
6231 case 20354:
6232 triggered_spell_id = 20352; // Rank 2
6233 break;
6234 case 20355:
6235 triggered_spell_id = 20353; // Rank 3
6236 break;
6237 case 27164:
6238 triggered_spell_id = 27165; // Rank 4
6239 break;
6240 default:
6241 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoW",triggeredByAura->GetSpellProto()->Id);
6242 return false;
6245 pVictim->CastSpell(pVictim,triggered_spell_id,true,castItem,triggeredByAura,GetGUID());
6246 return true; // no hidden cooldown
6248 //Judgement of Light
6249 case 299:
6251 if(!pVictim || !pVictim->isAlive())
6252 return false;
6254 // overwrite non existing triggered spell call in spell.dbc
6255 switch(triggeredByAura->GetSpellProto()->Id)
6257 case 20185:
6258 triggered_spell_id = 20267; // Rank 1
6259 break;
6260 case 20344:
6261 triggered_spell_id = 20341; // Rank 2
6262 break;
6263 case 20345:
6264 triggered_spell_id = 20342; // Rank 3
6265 break;
6266 case 20346:
6267 triggered_spell_id = 20343; // Rank 4
6268 break;
6269 case 27162:
6270 triggered_spell_id = 27163; // Rank 5
6271 break;
6272 default:
6273 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoL",triggeredByAura->GetSpellProto()->Id);
6274 return false;
6276 pVictim->CastSpell(pVictim,triggered_spell_id,true,castItem,triggeredByAura,GetGUID());
6277 return true; // no hidden cooldown
6281 // custom check for proc spell
6282 switch(auraSpellInfo->Id)
6284 // Bonus Healing (item spell)
6285 case 40971:
6287 if(!pVictim || !pVictim->isAlive())
6288 return false;
6290 // bonus if health < 50%
6291 if(pVictim->GetHealth() >= pVictim->GetMaxHealth()*triggeredByAura->GetModifier()->m_amount/100)
6292 return false;
6294 // cast at target positive spell
6295 target = pVictim;
6296 break;
6299 switch(triggered_spell_id)
6301 // Seal of Command
6302 case 20424:
6303 // prevent chain of triggered spell from same triggered spell
6304 if(procSpell && procSpell->Id==20424)
6305 return false;
6306 break;
6308 break;
6310 case SPELLFAMILY_SHAMAN:
6312 if(auraSpellInfo->SpellFamilyFlags == 0x0000000000000000)
6314 switch(auraSpellInfo->SpellIconID)
6316 case 19:
6318 switch(auraSpellInfo->Id)
6320 case 23551: // Lightning Shield - Tier2: 8 pieces proc shield
6322 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6323 triggered_spell_id = 23552;
6324 target = pVictim;
6325 break;
6327 case 23552: // Lightning Shield - trigger shield damage
6329 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6330 triggered_spell_id = 27635;
6331 target = pVictim;
6332 break;
6335 break;
6337 // Mana Surge (Shaman T1 bonus)
6338 case 87:
6340 if(!procSpell)
6341 return false;
6343 basepoints0 = procSpell->manaCost * 35/100;
6344 triggered_spell_id = 23571;
6345 target = this;
6346 break;
6348 //Nature's Guardian
6349 case 2013:
6351 if(GetTypeId()!=TYPEID_PLAYER)
6352 return false;
6354 // damage taken that reduces below 30% health
6355 // does NOT mean you must have been >= 30% before
6356 if (10*(int32(GetHealth())-int32(damage)) >= 3*GetMaxHealth())
6357 return false;
6359 triggered_spell_id = 31616;
6361 // need check cooldown now
6362 if( cooldown && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
6363 return false;
6365 basepoints0 = triggeredByAura->GetModifier()->m_amount * GetMaxHealth() / 100;
6366 target = this;
6367 if(pVictim && pVictim->isAlive())
6368 pVictim->getThreatManager().modifyThreatPercent(this,-10);
6369 break;
6374 // Water Shield (we can't set cooldown for main spell - it's player casted spell
6375 if((auraSpellInfo->SpellFamilyFlags & 0x0000002000000000LL) && auraSpellInfo->SpellVisual==7358)
6377 target = this;
6378 break;
6381 // Lightning Shield
6382 if((auraSpellInfo->SpellFamilyFlags & 0x00000400) && auraSpellInfo->SpellVisual==37)
6384 // overwrite non existing triggered spell call in spell.dbc
6385 switch(triggeredByAura->GetSpellProto()->Id)
6387 case 324:
6388 triggered_spell_id = 26364; break; // Rank 1
6389 case 325:
6390 triggered_spell_id = 26365; break; // Rank 2
6391 case 905:
6392 triggered_spell_id = 26366; break; // Rank 3
6393 case 945:
6394 triggered_spell_id = 26367; break; // Rank 4
6395 case 8134:
6396 triggered_spell_id = 26369; break; // Rank 5
6397 case 10431:
6398 triggered_spell_id = 26370; break; // Rank 6
6399 case 10432:
6400 triggered_spell_id = 26363; break; // Rank 7
6401 case 25469:
6402 triggered_spell_id = 26371; break; // Rank 8
6403 case 25472:
6404 triggered_spell_id = 26372; break; // Rank 9
6405 default:
6406 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura->GetSpellProto()->Id);
6407 return false;
6410 target = pVictim;
6411 break;
6413 break;
6417 // standard non-dummy case
6418 if(!triggered_spell_id)
6420 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo->Id,triggeredByAura->GetEffIndex());
6421 return false;
6424 SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
6426 if(!triggerEntry)
6428 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have not existed EffectTriggered[%d]=%u, not handled custom case?",auraSpellInfo->Id,triggeredByAura->GetEffIndex(),triggered_spell_id);
6429 return false;
6432 // not allow proc extra attack spell at extra attack
6433 if( m_extraAttacks && IsSpellHaveEffect(triggerEntry,SPELL_EFFECT_ADD_EXTRA_ATTACKS) )
6434 return false;
6436 if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
6437 return false;
6439 // default case
6440 if(!target || target!=this && !target->isAlive())
6441 return false;
6443 if(basepoints0)
6444 CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
6445 else
6446 CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura);
6448 if( cooldown && GetTypeId()==TYPEID_PLAYER )
6449 ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown);
6451 return true;
6454 bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, Aura *triggeredByAura, SpellEntry const *procSpell, uint32 cooldown)
6456 int32 scriptId = triggeredByAura->GetModifier()->m_miscvalue;
6458 if(!pVictim || !pVictim->isAlive())
6459 return false;
6461 Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
6462 ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL;
6464 uint32 triggered_spell_id = 0;
6466 switch(scriptId)
6468 case 836: // Improved Blizzard (Rank 1)
6470 if (!procSpell || procSpell->SpellVisual!=9487)
6471 return false;
6472 triggered_spell_id = 12484;
6473 break;
6475 case 988: // Improved Blizzard (Rank 2)
6477 if (!procSpell || procSpell->SpellVisual!=9487)
6478 return false;
6479 triggered_spell_id = 12485;
6480 break;
6482 case 989: // Improved Blizzard (Rank 3)
6484 if (!procSpell || procSpell->SpellVisual!=9487)
6485 return false;
6486 triggered_spell_id = 12486;
6487 break;
6489 case 4086: // Improved Mend Pet (Rank 1)
6490 case 4087: // Improved Mend Pet (Rank 2)
6492 int32 chance = triggeredByAura->GetSpellProto()->EffectBasePoints[triggeredByAura->GetEffIndex()];
6493 if(!roll_chance_i(chance))
6494 return false;
6496 triggered_spell_id = 24406;
6497 break;
6499 case 4533: // Dreamwalker Raiment 2 pieces bonus
6501 // Chance 50%
6502 if (!roll_chance_i(50))
6503 return false;
6505 switch (pVictim->getPowerType())
6507 case POWER_MANA: triggered_spell_id = 28722; break;
6508 case POWER_RAGE: triggered_spell_id = 28723; break;
6509 case POWER_ENERGY: triggered_spell_id = 28724; break;
6510 default:
6511 return false;
6513 break;
6515 case 4537: // Dreamwalker Raiment 6 pieces bonus
6516 triggered_spell_id = 28750; // Blessing of the Claw
6517 break;
6518 case 5497: // Improved Mana Gems (Serpent-Coil Braid)
6519 triggered_spell_id = 37445; // Mana Surge
6520 break;
6523 // not processed
6524 if(!triggered_spell_id)
6525 return false;
6527 // standard non-dummy case
6528 SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
6530 if(!triggerEntry)
6532 sLog.outError("Unit::HandleOverrideClassScriptAuraProc: Spell %u triggering for class script id %u",triggered_spell_id,scriptId);
6533 return false;
6536 if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
6537 return false;
6539 CastSpell(pVictim, triggered_spell_id, true, castItem, triggeredByAura);
6541 if( cooldown && GetTypeId()==TYPEID_PLAYER )
6542 ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown);
6544 return true;
6547 void Unit::setPowerType(Powers new_powertype)
6549 SetByteValue(UNIT_FIELD_BYTES_0, 3, new_powertype);
6551 if(GetTypeId() == TYPEID_PLAYER)
6553 if(((Player*)this)->GetGroup())
6554 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE);
6556 else if(((Creature*)this)->isPet())
6558 Pet *pet = ((Pet*)this);
6559 if(pet->isControlled())
6561 Unit *owner = GetOwner();
6562 if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
6563 ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE);
6567 switch(new_powertype)
6569 default:
6570 case POWER_MANA:
6571 break;
6572 case POWER_RAGE:
6573 SetMaxPower(POWER_RAGE,GetCreatePowers(POWER_RAGE));
6574 SetPower( POWER_RAGE,0);
6575 break;
6576 case POWER_FOCUS:
6577 SetMaxPower(POWER_FOCUS,GetCreatePowers(POWER_FOCUS));
6578 SetPower( POWER_FOCUS,GetCreatePowers(POWER_FOCUS));
6579 break;
6580 case POWER_ENERGY:
6581 SetMaxPower(POWER_ENERGY,GetCreatePowers(POWER_ENERGY));
6582 SetPower( POWER_ENERGY,0);
6583 break;
6584 case POWER_HAPPINESS:
6585 SetMaxPower(POWER_HAPPINESS,GetCreatePowers(POWER_HAPPINESS));
6586 SetPower(POWER_HAPPINESS,GetCreatePowers(POWER_HAPPINESS));
6587 break;
6591 FactionTemplateEntry const* Unit::getFactionTemplateEntry() const
6593 FactionTemplateEntry const* entry = sFactionTemplateStore.LookupEntry(getFaction());
6594 if(!entry)
6596 static uint64 guid = 0; // prevent repeating spam same faction problem
6598 if(GetGUID() != guid)
6600 if(GetTypeId() == TYPEID_PLAYER)
6601 sLog.outError("Player %s have invalid faction (faction template id) #%u", ((Player*)this)->GetName(), getFaction());
6602 else
6603 sLog.outError("Creature (template id: %u) have invalid faction (faction template id) #%u", ((Creature*)this)->GetCreatureInfo()->Entry, getFaction());
6604 guid = GetGUID();
6607 return entry;
6610 bool Unit::IsHostileTo(Unit const* unit) const
6612 // always non-hostile to self
6613 if(unit==this)
6614 return false;
6616 // always non-hostile to GM in GM mode
6617 if(unit->GetTypeId()==TYPEID_PLAYER && ((Player const*)unit)->isGameMaster())
6618 return false;
6620 // always hostile to enemy
6621 if(getVictim()==unit || unit->getVictim()==this)
6622 return true;
6624 // test pet/charm masters instead pers/charmeds
6625 Unit const* testerOwner = GetCharmerOrOwner();
6626 Unit const* targetOwner = unit->GetCharmerOrOwner();
6628 // always hostile to owner's enemy
6629 if(testerOwner && (testerOwner->getVictim()==unit || unit->getVictim()==testerOwner))
6630 return true;
6632 // always hostile to enemy owner
6633 if(targetOwner && (getVictim()==targetOwner || targetOwner->getVictim()==this))
6634 return true;
6636 // always hostile to owner of owner's enemy
6637 if(testerOwner && targetOwner && (testerOwner->getVictim()==targetOwner || targetOwner->getVictim()==testerOwner))
6638 return true;
6640 Unit const* tester = testerOwner ? testerOwner : this;
6641 Unit const* target = targetOwner ? targetOwner : unit;
6643 // always non-hostile to target with common owner, or to owner/pet
6644 if(tester==target)
6645 return false;
6647 // special cases (Duel, etc)
6648 if(tester->GetTypeId()==TYPEID_PLAYER && target->GetTypeId()==TYPEID_PLAYER)
6650 Player const* pTester = (Player const*)tester;
6651 Player const* pTarget = (Player const*)target;
6653 // Duel
6654 if(pTester->duel && pTester->duel->opponent == pTarget && pTester->duel->startTime != 0)
6655 return true;
6657 // Group
6658 if(pTester->GetGroup() && pTester->GetGroup()==pTarget->GetGroup())
6659 return false;
6661 // Sanctuary
6662 if(pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY))
6663 return false;
6665 // PvP FFA state
6666 if(pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP) && pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP))
6667 return true;
6669 //= PvP states
6670 // Green/Blue (can't attack)
6671 if(pTester->GetTeam()==pTarget->GetTeam())
6672 return false;
6674 // Red (can attack) if true, Blue/Yellow (can't attack) in another case
6675 return pTester->IsPvP() && pTarget->IsPvP();
6678 // faction base cases
6679 FactionTemplateEntry const*tester_faction = tester->getFactionTemplateEntry();
6680 FactionTemplateEntry const*target_faction = target->getFactionTemplateEntry();
6681 if(!tester_faction || !target_faction)
6682 return false;
6684 if(target->isAttackingPlayer() && tester->IsContestedGuard())
6685 return true;
6687 // PvC forced reaction and reputation case
6688 if(tester->GetTypeId()==TYPEID_PLAYER)
6690 // forced reaction
6691 ForcedReactions::const_iterator forceItr = ((Player*)tester)->m_forcedReactions.find(target_faction->faction);
6692 if(forceItr!=((Player*)tester)->m_forcedReactions.end())
6693 return forceItr->second <= REP_HOSTILE;
6695 // if faction have reputation then hostile state for tester at 100% dependent from at_war state
6696 if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction))
6697 if(raw_target_faction->reputationListID >=0)
6698 if(FactionState const* factionState = ((Player*)tester)->GetFactionState(raw_target_faction))
6699 return (factionState->Flags & FACTION_FLAG_AT_WAR);
6701 // CvP forced reaction and reputation case
6702 else if(target->GetTypeId()==TYPEID_PLAYER)
6704 // forced reaction
6705 ForcedReactions::const_iterator forceItr = ((Player const*)target)->m_forcedReactions.find(tester_faction->faction);
6706 if(forceItr!=((Player const*)target)->m_forcedReactions.end())
6707 return forceItr->second <= REP_HOSTILE;
6709 // apply reputation state
6710 FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction);
6711 if(raw_tester_faction && raw_tester_faction->reputationListID >=0 )
6712 return ((Player const*)target)->GetReputationRank(raw_tester_faction) <= REP_HOSTILE;
6715 // common faction based case (CvC,PvC,CvP)
6716 return tester_faction->IsHostileTo(*target_faction);
6719 bool Unit::IsFriendlyTo(Unit const* unit) const
6721 // always friendly to self
6722 if(unit==this)
6723 return true;
6725 // always friendly to GM in GM mode
6726 if(unit->GetTypeId()==TYPEID_PLAYER && ((Player const*)unit)->isGameMaster())
6727 return true;
6729 // always non-friendly to enemy
6730 if(getVictim()==unit || unit->getVictim()==this)
6731 return false;
6733 // test pet/charm masters instead pers/charmeds
6734 Unit const* testerOwner = GetCharmerOrOwner();
6735 Unit const* targetOwner = unit->GetCharmerOrOwner();
6737 // always non-friendly to owner's enemy
6738 if(testerOwner && (testerOwner->getVictim()==unit || unit->getVictim()==testerOwner))
6739 return false;
6741 // always non-friendly to enemy owner
6742 if(targetOwner && (getVictim()==targetOwner || targetOwner->getVictim()==this))
6743 return false;
6745 // always non-friendly to owner of owner's enemy
6746 if(testerOwner && targetOwner && (testerOwner->getVictim()==targetOwner || targetOwner->getVictim()==testerOwner))
6747 return false;
6749 Unit const* tester = testerOwner ? testerOwner : this;
6750 Unit const* target = targetOwner ? targetOwner : unit;
6752 // always friendly to target with common owner, or to owner/pet
6753 if(tester==target)
6754 return true;
6756 // special cases (Duel)
6757 if(tester->GetTypeId()==TYPEID_PLAYER && target->GetTypeId()==TYPEID_PLAYER)
6759 Player const* pTester = (Player const*)tester;
6760 Player const* pTarget = (Player const*)target;
6762 // Duel
6763 if(pTester->duel && pTester->duel->opponent == target && pTester->duel->startTime != 0)
6764 return false;
6766 // Group
6767 if(pTester->GetGroup() && pTester->GetGroup()==pTarget->GetGroup())
6768 return true;
6770 // Sanctuary
6771 if(pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY))
6772 return true;
6774 // PvP FFA state
6775 if(pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP) && pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP))
6776 return false;
6778 //= PvP states
6779 // Green/Blue (non-attackable)
6780 if(pTester->GetTeam()==pTarget->GetTeam())
6781 return true;
6783 // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable)
6784 return !pTarget->IsPvP();
6787 // faction base cases
6788 FactionTemplateEntry const*tester_faction = tester->getFactionTemplateEntry();
6789 FactionTemplateEntry const*target_faction = target->getFactionTemplateEntry();
6790 if(!tester_faction || !target_faction)
6791 return false;
6793 if(target->isAttackingPlayer() && tester->IsContestedGuard())
6794 return false;
6796 // PvC forced reaction and reputation case
6797 if(tester->GetTypeId()==TYPEID_PLAYER)
6799 // forced reaction
6800 ForcedReactions::const_iterator forceItr = ((Player const*)tester)->m_forcedReactions.find(target_faction->faction);
6801 if(forceItr!=((Player const*)tester)->m_forcedReactions.end())
6802 return forceItr->second >= REP_FRIENDLY;
6804 // if faction have reputation then friendly state for tester at 100% dependent from at_war state
6805 if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction))
6806 if(raw_target_faction->reputationListID >=0)
6807 if(FactionState const* FactionState = ((Player*)tester)->GetFactionState(raw_target_faction))
6808 return !(FactionState->Flags & FACTION_FLAG_AT_WAR);
6810 // CvP forced reaction and reputation case
6811 else if(target->GetTypeId()==TYPEID_PLAYER)
6813 // forced reaction
6814 ForcedReactions::const_iterator forceItr = ((Player const*)target)->m_forcedReactions.find(tester_faction->faction);
6815 if(forceItr!=((Player const*)target)->m_forcedReactions.end())
6816 return forceItr->second >= REP_FRIENDLY;
6818 // apply reputation state
6819 if(FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction))
6820 if(raw_tester_faction->reputationListID >=0 )
6821 return ((Player const*)target)->GetReputationRank(raw_tester_faction) >= REP_FRIENDLY;
6824 // common faction based case (CvC,PvC,CvP)
6825 return tester_faction->IsFriendlyTo(*target_faction);
6828 bool Unit::IsHostileToPlayers() const
6830 FactionTemplateEntry const* my_faction = getFactionTemplateEntry();
6831 if(!my_faction)
6832 return false;
6834 FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction);
6835 if(raw_faction && raw_faction->reputationListID >=0 )
6836 return false;
6838 return my_faction->IsHostileToPlayers();
6841 bool Unit::IsNeutralToAll() const
6843 FactionTemplateEntry const* my_faction = getFactionTemplateEntry();
6844 if(!my_faction)
6845 return true;
6847 FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction);
6848 if(raw_faction && raw_faction->reputationListID >=0 )
6849 return false;
6851 return my_faction->IsNeutralToAll();
6854 bool Unit::Attack(Unit *victim, bool meleeAttack)
6856 if(!victim || victim == this)
6857 return false;
6859 // dead units can neither attack nor be attacked
6860 if(!isAlive() || !victim->isAlive())
6861 return false;
6863 // player cannot attack in mount state
6864 if(GetTypeId()==TYPEID_PLAYER && IsMounted())
6865 return false;
6867 // nobody can attack GM in GM-mode
6868 if(victim->GetTypeId()==TYPEID_PLAYER)
6870 if(((Player*)victim)->isGameMaster())
6871 return false;
6873 else
6875 if(((Creature*)victim)->IsInEvadeMode())
6876 return false;
6879 // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
6880 if(HasAuraType(SPELL_AURA_MOD_UNATTACKABLE))
6881 RemoveSpellsCausingAura(SPELL_AURA_MOD_UNATTACKABLE);
6883 if (m_attacking)
6885 if (m_attacking == victim)
6887 // switch to melee attack from ranged/magic
6888 if( meleeAttack && !hasUnitState(UNIT_STAT_MELEE_ATTACKING) )
6890 addUnitState(UNIT_STAT_MELEE_ATTACKING);
6891 SendAttackStart(victim);
6892 return true;
6894 return false;
6896 AttackStop();
6899 //Set our target
6900 SetUInt64Value(UNIT_FIELD_TARGET, victim->GetGUID());
6902 if(meleeAttack)
6903 addUnitState(UNIT_STAT_MELEE_ATTACKING);
6904 m_attacking = victim;
6905 m_attacking->_addAttacker(this);
6907 if(m_attacking->GetTypeId()==TYPEID_UNIT && ((Creature*)m_attacking)->AI())
6908 ((Creature*)m_attacking)->AI()->AttackedBy(this);
6910 if(GetTypeId()==TYPEID_UNIT)
6912 WorldPacket data(SMSG_AI_REACTION, 12);
6913 data << uint64(GetGUID());
6914 data << uint32(AI_REACTION_AGGRO); // Aggro sound
6915 ((WorldObject*)this)->SendMessageToSet(&data, true);
6917 ((Creature*)this)->CallAssistance();
6918 ((Creature*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
6921 // delay offhand weapon attack to next attack time
6922 if(haveOffhandWeapon())
6923 resetAttackTimer(OFF_ATTACK);
6925 if(meleeAttack)
6926 SendAttackStart(victim);
6928 return true;
6931 bool Unit::AttackStop()
6933 if (!m_attacking)
6934 return false;
6936 Unit* victim = m_attacking;
6938 m_attacking->_removeAttacker(this);
6939 m_attacking = NULL;
6941 //Clear our target
6942 SetUInt64Value(UNIT_FIELD_TARGET, 0);
6944 clearUnitState(UNIT_STAT_MELEE_ATTACKING);
6946 InterruptSpell(CURRENT_MELEE_SPELL);
6948 if( GetTypeId()==TYPEID_UNIT )
6950 // reset call assistance
6951 ((Creature*)this)->SetNoCallAssistance(false);
6954 SendAttackStop(victim);
6956 return true;
6959 void Unit::CombatStop(bool cast)
6961 if(cast& IsNonMeleeSpellCasted(false))
6962 InterruptNonMeleeSpells(false);
6964 AttackStop();
6965 RemoveAllAttackers();
6966 if( GetTypeId()==TYPEID_PLAYER )
6967 ((Player*)this)->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
6968 ClearInCombat();
6971 void Unit::CombatStopWithPets(bool cast)
6973 CombatStop(cast);
6974 if(Pet* pet = GetPet())
6975 pet->CombatStop(cast);
6976 if(Unit* charm = GetCharm())
6977 charm->CombatStop(cast);
6978 if(GetTypeId()==TYPEID_PLAYER)
6980 GuardianPetList const& guardians = ((Player*)this)->GetGuardians();
6981 for(GuardianPetList::const_iterator itr = guardians.begin(); itr != guardians.end(); ++itr)
6982 if(Unit* guardian = Unit::GetUnit(*this,*itr))
6983 guardian->CombatStop(cast);
6987 bool Unit::isAttackingPlayer() const
6989 if(hasUnitState(UNIT_STAT_ATTACK_PLAYER))
6990 return true;
6992 Pet* pet = GetPet();
6993 if(pet && pet->isAttackingPlayer())
6994 return true;
6996 Unit* charmed = GetCharm();
6997 if(charmed && charmed->isAttackingPlayer())
6998 return true;
7000 for (int8 i = 0; i < MAX_TOTEM; i++)
7002 if(m_TotemSlot[i])
7004 Creature *totem = ObjectAccessor::GetCreature(*this, m_TotemSlot[i]);
7005 if(totem && totem->isAttackingPlayer())
7006 return true;
7010 return false;
7013 void Unit::RemoveAllAttackers()
7015 while (!m_attackers.empty())
7017 AttackerSet::iterator iter = m_attackers.begin();
7018 if(!(*iter)->AttackStop())
7020 sLog.outError("WORLD: Unit has an attacker that isn't attacking it!");
7021 m_attackers.erase(iter);
7026 void Unit::ModifyAuraState(AuraState flag, bool apply)
7028 if (apply)
7030 if (!HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)))
7032 SetFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
7033 if(GetTypeId() == TYPEID_PLAYER)
7035 const PlayerSpellMap& sp_list = ((Player*)this)->GetSpellMap();
7036 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
7038 if(itr->second->state == PLAYERSPELL_REMOVED) continue;
7039 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
7040 if (!spellInfo || !IsPassiveSpell(itr->first)) continue;
7041 if (spellInfo->CasterAuraState == flag)
7042 CastSpell(this, itr->first, true, NULL);
7047 else
7049 if (HasFlag(UNIT_FIELD_AURASTATE,1<<(flag-1)))
7051 RemoveFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
7052 Unit::AuraMap& tAuras = GetAuras();
7053 for (Unit::AuraMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
7055 SpellEntry const* spellProto = (*itr).second->GetSpellProto();
7056 if (spellProto->CasterAuraState == flag)
7058 // exceptions (applied at state but not removed at state change)
7059 // Rampage
7060 if(spellProto->SpellIconID==2006 && spellProto->SpellFamilyName==SPELLFAMILY_WARRIOR && spellProto->SpellFamilyFlags==0x100000)
7062 ++itr;
7063 continue;
7066 RemoveAura(itr);
7068 else
7069 ++itr;
7075 Unit *Unit::GetOwner() const
7077 uint64 ownerid = GetOwnerGUID();
7078 if(!ownerid)
7079 return NULL;
7080 return ObjectAccessor::GetUnit(*this, ownerid);
7083 Unit *Unit::GetCharmer() const
7085 if(uint64 charmerid = GetCharmerGUID())
7086 return ObjectAccessor::GetUnit(*this, charmerid);
7087 return NULL;
7090 Player* Unit::GetCharmerOrOwnerPlayerOrPlayerItself()
7092 uint64 guid = GetCharmerOrOwnerGUID();
7093 if(IS_PLAYER_GUID(guid))
7094 return ObjectAccessor::GetPlayer(*this, guid);
7096 return GetTypeId()==TYPEID_PLAYER ? (Player*)this : NULL;
7099 Pet* Unit::GetPet() const
7101 if(uint64 pet_guid = GetPetGUID())
7103 if(Pet* pet = ObjectAccessor::GetPet(pet_guid))
7104 return pet;
7106 sLog.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid));
7107 const_cast<Unit*>(this)->SetPet(0);
7110 return NULL;
7113 Unit* Unit::GetCharm() const
7115 if(uint64 charm_guid = GetCharmGUID())
7117 if(Unit* pet = ObjectAccessor::GetUnit(*this, charm_guid))
7118 return pet;
7120 sLog.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid));
7121 const_cast<Unit*>(this)->SetCharm(0);
7124 return NULL;
7127 void Unit::SetPet(Pet* pet)
7129 SetUInt64Value(UNIT_FIELD_SUMMON, pet ? pet->GetGUID() : 0);
7131 // FIXME: hack, speed must be set only at follow
7132 if(pet)
7133 for(int i = 0; i < MAX_MOVE_TYPE; ++i)
7134 pet->SetSpeed(UnitMoveType(i), m_speed_rate[i], true);
7137 void Unit::SetCharm(Unit* pet)
7139 SetUInt64Value(UNIT_FIELD_CHARM, pet ? pet->GetGUID() : 0);
7142 void Unit::UnsummonAllTotems()
7144 for (int8 i = 0; i < MAX_TOTEM; ++i)
7146 if(!m_TotemSlot[i])
7147 continue;
7149 Creature *OldTotem = ObjectAccessor::GetCreature(*this, m_TotemSlot[i]);
7150 if (OldTotem && OldTotem->isTotem())
7151 ((Totem*)OldTotem)->UnSummon();
7155 void Unit::SendHealSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, bool critical)
7157 // we guess size
7158 WorldPacket data(SMSG_SPELLHEALLOG, (8+8+4+4+1));
7159 data.append(pVictim->GetPackGUID());
7160 data.append(GetPackGUID());
7161 data << uint32(SpellID);
7162 data << uint32(Damage);
7163 data << uint8(critical ? 1 : 0);
7164 data << uint8(0); // unused in client?
7165 SendMessageToSet(&data, true);
7168 void Unit::SendEnergizeSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, Powers powertype)
7170 WorldPacket data(SMSG_SPELLENERGIZELOG, (8+8+4+4+4+1));
7171 data.append(pVictim->GetPackGUID());
7172 data.append(GetPackGUID());
7173 data << uint32(SpellID);
7174 data << uint32(powertype);
7175 data << uint32(Damage);
7176 SendMessageToSet(&data, true);
7179 uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 pdamage, DamageEffectType damagetype)
7181 if(!spellProto || !pVictim || damagetype==DIRECT_DAMAGE )
7182 return pdamage;
7184 int32 BonusDamage = 0;
7185 if( GetTypeId()==TYPEID_UNIT )
7187 // Pets just add their bonus damage to their spell damage
7188 // note that their spell damage is just gain of their own auras
7189 if (((Creature*)this)->isPet())
7191 BonusDamage = ((Pet*)this)->GetBonusDamage();
7193 // For totems get damage bonus from owner (statue isn't totem in fact)
7194 else if (((Creature*)this)->isTotem() && ((Totem*)this)->GetTotemType()!=TOTEM_STATUE)
7196 if(Unit* owner = GetOwner())
7197 return owner->SpellDamageBonus(pVictim, spellProto, pdamage, damagetype);
7201 // Damage Done
7202 uint32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto);
7204 // Taken/Done fixed damage bonus auras
7205 int32 DoneAdvertisedBenefit = SpellBaseDamageBonus(GetSpellSchoolMask(spellProto))+BonusDamage;
7206 int32 TakenAdvertisedBenefit = SpellBaseDamageBonusForVictim(GetSpellSchoolMask(spellProto), pVictim);
7208 // Damage over Time spells bonus calculation
7209 float DotFactor = 1.0f;
7210 if(damagetype == DOT)
7212 int32 DotDuration = GetSpellDuration(spellProto);
7213 // 200% limit
7214 if(DotDuration > 0)
7216 if(DotDuration > 30000) DotDuration = 30000;
7217 if(!IsChanneledSpell(spellProto)) DotFactor = DotDuration / 15000.0f;
7218 int x = 0;
7219 for(int j = 0; j < 3; j++)
7221 if( spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && (
7222 spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE ||
7223 spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH) )
7225 x = j;
7226 break;
7229 int DotTicks = 6;
7230 if(spellProto->EffectAmplitude[x] != 0)
7231 DotTicks = DotDuration / spellProto->EffectAmplitude[x];
7232 if(DotTicks)
7234 DoneAdvertisedBenefit /= DotTicks;
7235 TakenAdvertisedBenefit /= DotTicks;
7240 // Taken/Done total percent damage auras
7241 float DoneTotalMod = 1.0f;
7242 float TakenTotalMod = 1.0f;
7244 // ..done
7245 AuraList const& mModDamagePercentDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
7246 for(AuraList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
7248 if( ((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto)) &&
7249 (*i)->GetSpellProto()->EquippedItemClass == -1 &&
7250 // -1 == any item class (not wand then)
7251 (*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 )
7252 // 0 == any inventory type (not wand then)
7254 DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
7258 uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
7259 AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS);
7260 for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i)
7261 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
7262 DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
7264 // ..taken
7265 AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
7266 for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
7267 if( (*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto) )
7268 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
7270 // .. taken pct: scripted (increases damage of * against targets *)
7271 AuraList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
7272 for(AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
7274 switch((*i)->GetModifier()->m_miscvalue)
7276 //Molten Fury
7277 case 4920: case 4919:
7278 if(pVictim->HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT))
7279 TakenTotalMod *= (100.0f+(*i)->GetModifier()->m_amount)/100.0f; break;
7283 // .. taken pct: dummy auras
7284 AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
7285 for(AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
7287 switch((*i)->GetSpellProto()->SpellIconID)
7289 //Cheat Death
7290 case 2109:
7291 if( ((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto)) )
7293 if(pVictim->GetTypeId() != TYPEID_PLAYER)
7294 continue;
7295 float mod = -((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL)*2*4;
7296 if (mod < (*i)->GetModifier()->m_amount)
7297 mod = (*i)->GetModifier()->m_amount;
7298 TakenTotalMod *= (mod+100.0f)/100.0f;
7300 break;
7301 //Mangle
7302 case 2312:
7303 for(int j=0;j<3;j++)
7305 if(GetEffectMechanic(spellProto, j)==MECHANIC_BLEED)
7307 TakenTotalMod *= (100.0f+(*i)->GetModifier()->m_amount)/100.0f;
7308 break;
7311 break;
7315 // Distribute Damage over multiple effects, reduce by AoE
7316 CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime );
7318 // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
7319 for(int j = 0; j < 3; ++j)
7321 if( spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH ||
7322 spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH )
7324 CastingTime /= 2;
7325 break;
7329 switch(spellProto->SpellFamilyName)
7331 case SPELLFAMILY_MAGE:
7332 // Ignite - do not modify, it is (8*Rank)% damage of procing Spell
7333 if(spellProto->Id==12654)
7335 return pdamage;
7337 // Ice Lance
7338 else if((spellProto->SpellFamilyFlags & 0x20000LL) && spellProto->SpellIconID == 186)
7340 CastingTime /= 3; // applied 1/3 bonuses in case generic target
7341 if(pVictim->isFrozen()) // and compensate this for frozen target.
7342 TakenTotalMod *= 3.0f;
7344 // Pyroblast - 115% of Fire Damage, DoT - 20% of Fire Damage
7345 else if((spellProto->SpellFamilyFlags & 0x400000LL) && spellProto->SpellIconID == 184 )
7347 DotFactor = damagetype == DOT ? 0.2f : 1.0f;
7348 CastingTime = damagetype == DOT ? 3500 : 4025;
7350 // Fireball - 100% of Fire Damage, DoT - 0% of Fire Damage
7351 else if((spellProto->SpellFamilyFlags & 0x1LL) && spellProto->SpellIconID == 185)
7353 CastingTime = 3500;
7354 DotFactor = damagetype == DOT ? 0.0f : 1.0f;
7356 // Molten armor
7357 else if (spellProto->SpellFamilyFlags & 0x0000000800000000LL)
7359 CastingTime = 0;
7361 // Arcane Missiles triggered spell
7362 else if ((spellProto->SpellFamilyFlags & 0x200000LL) && spellProto->SpellIconID == 225)
7364 CastingTime = 1000;
7366 // Blizzard triggered spell
7367 else if ((spellProto->SpellFamilyFlags & 0x80080LL) && spellProto->SpellIconID == 285)
7369 CastingTime = 500;
7371 break;
7372 case SPELLFAMILY_WARLOCK:
7373 // Life Tap
7374 if((spellProto->SpellFamilyFlags & 0x40000LL) && spellProto->SpellIconID == 208)
7376 CastingTime = 2800; // 80% from +shadow damage
7377 DoneTotalMod = 1.0f;
7378 TakenTotalMod = 1.0f;
7380 // Dark Pact
7381 else if((spellProto->SpellFamilyFlags & 0x80000000LL) && spellProto->SpellIconID == 154 && GetPetGUID())
7383 CastingTime = 3360; // 96% from +shadow damage
7384 DoneTotalMod = 1.0f;
7385 TakenTotalMod = 1.0f;
7387 // Soul Fire - 115% of Fire Damage
7388 else if((spellProto->SpellFamilyFlags & 0x8000000000LL) && spellProto->SpellIconID == 184)
7390 CastingTime = 4025;
7392 // Curse of Agony - 120% of Shadow Damage
7393 else if((spellProto->SpellFamilyFlags & 0x0000000400LL) && spellProto->SpellIconID == 544)
7395 DotFactor = 1.2f;
7397 // Drain Mana - 0% of Shadow Damage
7398 else if((spellProto->SpellFamilyFlags & 0x10LL) && spellProto->SpellIconID == 548)
7400 CastingTime = 0;
7402 // Drain Soul 214.3%
7403 else if ((spellProto->SpellFamilyFlags & 0x4000LL) && spellProto->SpellIconID == 113 )
7405 CastingTime = 7500;
7407 // Hellfire
7408 else if ((spellProto->SpellFamilyFlags & 0x40LL) && spellProto->SpellIconID == 937)
7410 CastingTime = damagetype == DOT ? 5000 : 500; // self damage seems to be so
7412 // Unstable Affliction - 180%
7413 else if (spellProto->Id == 31117 && spellProto->SpellIconID == 232)
7415 CastingTime = 6300;
7417 // Corruption 93%
7418 else if ((spellProto->SpellFamilyFlags & 0x2LL) && spellProto->SpellIconID == 313)
7420 DotFactor = 0.93f;
7422 break;
7423 case SPELLFAMILY_PALADIN:
7424 // Consecration - 95% of Holy Damage
7425 if((spellProto->SpellFamilyFlags & 0x20LL) && spellProto->SpellIconID == 51)
7427 DotFactor = 0.95f;
7428 CastingTime = 3500;
7430 // Seal of Righteousness - 10.2%/9.8% ( based on weapon type ) of Holy Damage, multiplied by weapon speed
7431 else if((spellProto->SpellFamilyFlags & 0x8000000LL) && spellProto->SpellIconID == 25)
7433 Item *item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
7434 float wspeed = GetAttackTime(BASE_ATTACK)/1000.0f;
7436 if( item && item->GetProto()->InventoryType == INVTYPE_2HWEAPON)
7437 CastingTime = uint32(wspeed*3500*0.102f);
7438 else
7439 CastingTime = uint32(wspeed*3500*0.098f);
7441 // Judgement of Righteousness - 73%
7442 else if ((spellProto->SpellFamilyFlags & 1024) && spellProto->SpellIconID == 25)
7444 CastingTime = 2555;
7446 // Seal of Vengeance - 17% per Fully Stacked Tick - 5 Applications
7447 else if ((spellProto->SpellFamilyFlags & 0x80000000000LL) && spellProto->SpellIconID == 2292)
7449 DotFactor = 0.17f;
7450 CastingTime = 3500;
7452 // Holy shield - 5% of Holy Damage
7453 else if ((spellProto->SpellFamilyFlags & 0x4000000000LL) && spellProto->SpellIconID == 453)
7455 CastingTime = 175;
7457 // Blessing of Sanctuary - 0%
7458 else if ((spellProto->SpellFamilyFlags & 0x10000000LL) && spellProto->SpellIconID == 29)
7460 CastingTime = 0;
7462 // Seal of Righteousness trigger - already computed for parent spell
7463 else if ( spellProto->SpellFamilyName==SPELLFAMILY_PALADIN && spellProto->SpellIconID==25 && spellProto->AttributesEx4 & 0x00800000LL )
7465 return pdamage;
7467 break;
7468 case SPELLFAMILY_SHAMAN:
7469 // totem attack
7470 if (spellProto->SpellFamilyFlags & 0x000040000000LL)
7472 if (spellProto->SpellIconID == 33) // Fire Nova totem attack must be 21.4%(untested)
7473 CastingTime = 749; // ignore CastingTime and use as modifier
7474 else if (spellProto->SpellIconID == 680) // Searing Totem attack 8%
7475 CastingTime = 280; // ignore CastingTime and use as modifier
7476 else if (spellProto->SpellIconID == 37) // Magma totem attack must be 6.67%(untested)
7477 CastingTime = 234; // ignore CastingTimePenalty and use as modifier
7479 // Lightning Shield (and proc shield from T2 8 pieces bonus ) 33% per charge
7480 else if( (spellProto->SpellFamilyFlags & 0x00000000400LL) || spellProto->Id == 23552)
7481 CastingTime = 1155; // ignore CastingTimePenalty and use as modifier
7482 break;
7483 case SPELLFAMILY_PRIEST:
7484 // Mana Burn - 0% of Shadow Damage
7485 if((spellProto->SpellFamilyFlags & 0x10LL) && spellProto->SpellIconID == 212)
7487 CastingTime = 0;
7489 // Mind Flay - 59% of Shadow Damage
7490 else if((spellProto->SpellFamilyFlags & 0x800000LL) && spellProto->SpellIconID == 548)
7492 CastingTime = 2065;
7494 // Holy Fire - 86.71%, DoT - 16.5%
7495 else if ((spellProto->SpellFamilyFlags & 0x100000LL) && spellProto->SpellIconID == 156)
7497 DotFactor = damagetype == DOT ? 0.165f : 1.0f;
7498 CastingTime = damagetype == DOT ? 3500 : 3035;
7500 // Shadowguard - 28% per charge
7501 else if ((spellProto->SpellFamilyFlags & 0x2000000LL) && spellProto->SpellIconID == 19)
7503 CastingTime = 980;
7505 // Touch of Weakeness - 10%
7506 else if ((spellProto->SpellFamilyFlags & 0x80000LL) && spellProto->SpellIconID == 1591)
7508 CastingTime = 350;
7510 // Reflective Shield (back damage) - 0% (other spells fit to check not have damage effects/auras)
7511 else if (spellProto->SpellFamilyFlags == 0 && spellProto->SpellIconID == 566)
7513 CastingTime = 0;
7515 // Holy Nova - 14%
7516 else if ((spellProto->SpellFamilyFlags & 0x400000LL) && spellProto->SpellIconID == 1874)
7518 CastingTime = 500;
7520 break;
7521 case SPELLFAMILY_DRUID:
7522 // Hurricane triggered spell
7523 if((spellProto->SpellFamilyFlags & 0x400000LL) && spellProto->SpellIconID == 220)
7525 CastingTime = 500;
7527 break;
7528 case SPELLFAMILY_WARRIOR:
7529 case SPELLFAMILY_HUNTER:
7530 case SPELLFAMILY_ROGUE:
7531 CastingTime = 0;
7532 break;
7533 default:
7534 break;
7537 float LvlPenalty = CalculateLevelPenalty(spellProto);
7539 // Spellmod SpellDamage
7540 float SpellModSpellDamage = 100.0f;
7542 if(Player* modOwner = GetSpellModOwner())
7543 modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_SPELL_BONUS_DAMAGE,SpellModSpellDamage);
7545 SpellModSpellDamage /= 100.0f;
7547 float DoneActualBenefit = DoneAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * SpellModSpellDamage * LvlPenalty;
7548 float TakenActualBenefit = TakenAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty;
7550 float tmpDamage = (float(pdamage)+DoneActualBenefit)*DoneTotalMod;
7552 // Add flat bonus from spell damage versus
7553 tmpDamage += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS, creatureTypeMask);
7555 // apply spellmod to Done damage
7556 if(Player* modOwner = GetSpellModOwner())
7557 modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage);
7559 tmpDamage = (tmpDamage+TakenActualBenefit)*TakenTotalMod;
7561 if( GetTypeId() == TYPEID_UNIT && !((Creature*)this)->isPet() )
7562 tmpDamage *= ((Creature*)this)->GetSpellDamageMod(((Creature*)this)->GetCreatureInfo()->rank);
7564 return tmpDamage > 0 ? uint32(tmpDamage) : 0;
7567 int32 Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask)
7569 int32 DoneAdvertisedBenefit = 0;
7571 // ..done
7572 AuraList const& mDamageDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE);
7573 for(AuraList::const_iterator i = mDamageDone.begin();i != mDamageDone.end(); ++i)
7574 if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0 &&
7575 (*i)->GetSpellProto()->EquippedItemClass == -1 &&
7576 // -1 == any item class (not wand then)
7577 (*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 )
7578 // 0 == any inventory type (not wand then)
7579 DoneAdvertisedBenefit += (*i)->GetModifier()->m_amount;
7581 if (GetTypeId() == TYPEID_PLAYER)
7583 // Damage bonus from stats
7584 AuraList const& mDamageDoneOfStatPercent = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT);
7585 for(AuraList::const_iterator i = mDamageDoneOfStatPercent.begin();i != mDamageDoneOfStatPercent.end(); ++i)
7587 if((*i)->GetModifier()->m_miscvalue & schoolMask)
7589 SpellEntry const* iSpellProto = (*i)->GetSpellProto();
7590 uint8 eff = (*i)->GetEffIndex();
7592 // stat used dependent from next effect aura SPELL_AURA_MOD_SPELL_HEALING presence and misc value (stat index)
7593 Stats usedStat = STAT_INTELLECT;
7594 if(eff < 2 && iSpellProto->EffectApplyAuraName[eff+1]==SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT)
7595 usedStat = Stats(iSpellProto->EffectMiscValue[eff+1]);
7597 DoneAdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifier()->m_amount / 100.0f);
7600 // ... and attack power
7601 AuraList const& mDamageDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER);
7602 for(AuraList::const_iterator i =mDamageDonebyAP.begin();i != mDamageDonebyAP.end(); ++i)
7603 if ((*i)->GetModifier()->m_miscvalue & schoolMask)
7604 DoneAdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifier()->m_amount / 100.0f);
7607 return DoneAdvertisedBenefit;
7610 int32 Unit::SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask, Unit *pVictim)
7612 uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
7614 int32 TakenAdvertisedBenefit = 0;
7615 // ..done (for creature type by mask) in taken
7616 AuraList const& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
7617 for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
7618 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
7619 TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount;
7621 // ..taken
7622 AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
7623 for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
7624 if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0)
7625 TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount;
7627 return TakenAdvertisedBenefit;
7630 bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType)
7632 // not critting spell
7633 if((spellProto->AttributesEx2 & SPELL_ATTR_EX2_CANT_CRIT))
7634 return false;
7636 float crit_chance = 0.0f;
7637 switch(spellProto->DmgClass)
7639 case SPELL_DAMAGE_CLASS_NONE:
7640 return false;
7641 case SPELL_DAMAGE_CLASS_MAGIC:
7643 if (schoolMask & SPELL_SCHOOL_MASK_NORMAL)
7644 crit_chance = 0.0f;
7645 // For other schools
7646 else if (GetTypeId() == TYPEID_PLAYER)
7647 crit_chance = GetFloatValue( PLAYER_SPELL_CRIT_PERCENTAGE1 + GetFirstSchoolInMask(schoolMask));
7648 else
7650 crit_chance = m_baseSpellCritChance;
7651 crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask);
7653 // taken
7654 if (pVictim && !IsPositiveSpell(spellProto->Id))
7656 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
7657 crit_chance += pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE, schoolMask);
7658 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
7659 crit_chance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
7660 // Modify by player victim resilience
7661 if (pVictim->GetTypeId() == TYPEID_PLAYER)
7662 crit_chance -= ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL);
7663 // scripted (increase crit chance ... against ... target by x%
7664 if(pVictim->isFrozen()) // Shatter
7666 AuraList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
7667 for(AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
7669 switch((*i)->GetModifier()->m_miscvalue)
7671 case 849: crit_chance+= 10.0f; break; //Shatter Rank 1
7672 case 910: crit_chance+= 20.0f; break; //Shatter Rank 2
7673 case 911: crit_chance+= 30.0f; break; //Shatter Rank 3
7674 case 912: crit_chance+= 40.0f; break; //Shatter Rank 4
7675 case 913: crit_chance+= 50.0f; break; //Shatter Rank 5
7680 break;
7682 case SPELL_DAMAGE_CLASS_MELEE:
7683 case SPELL_DAMAGE_CLASS_RANGED:
7685 if (pVictim)
7687 crit_chance = GetUnitCriticalChance(attackType, pVictim);
7688 crit_chance+= (int32(GetMaxSkillValueForLevel(pVictim)) - int32(pVictim->GetDefenseSkillValue(this))) * 0.04f;
7689 crit_chance+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask);
7691 break;
7693 default:
7694 return false;
7696 // percent done
7697 // only players use intelligence for critical chance computations
7698 if(Player* modOwner = GetSpellModOwner())
7699 modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance);
7701 crit_chance = crit_chance > 0.0f ? crit_chance : 0.0f;
7702 if (roll_chance_f(crit_chance))
7703 return true;
7704 return false;
7707 uint32 Unit::SpellCriticalBonus(SpellEntry const *spellProto, uint32 damage, Unit *pVictim)
7709 // Calculate critical bonus
7710 int32 crit_bonus;
7711 switch(spellProto->DmgClass)
7713 case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100%
7714 case SPELL_DAMAGE_CLASS_RANGED:
7715 // TODO: write here full calculation for melee/ranged spells
7716 crit_bonus = damage;
7717 break;
7718 default:
7719 crit_bonus = damage / 2; // for spells is 50%
7720 break;
7723 // adds additional damage to crit_bonus (from talents)
7724 if(Player* modOwner = GetSpellModOwner())
7725 modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
7727 if(pVictim)
7729 uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
7730 crit_bonus = int32(crit_bonus * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, creatureTypeMask));
7733 if(crit_bonus > 0)
7734 damage += crit_bonus;
7736 return damage;
7739 uint32 Unit::SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, Unit *pVictim)
7741 // For totems get healing bonus from owner (statue isn't totem in fact)
7742 if( GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem() && ((Totem*)this)->GetTotemType()!=TOTEM_STATUE)
7743 if(Unit* owner = GetOwner())
7744 return owner->SpellHealingBonus(spellProto, healamount, damagetype, pVictim);
7746 // Healing Done
7748 // These Spells are doing fixed amount of healing (TODO found less hack-like check)
7749 if (spellProto->Id == 15290 || spellProto->Id == 39373 ||
7750 spellProto->Id == 33778 || spellProto->Id == 379 ||
7751 spellProto->Id == 38395 || spellProto->Id == 40972)
7752 return healamount;
7754 int32 AdvertisedBenefit = SpellBaseHealingBonus(GetSpellSchoolMask(spellProto));
7755 uint32 CastingTime = GetSpellCastTime(spellProto);
7757 // Healing Taken
7758 AdvertisedBenefit += SpellBaseHealingBonusForVictim(GetSpellSchoolMask(spellProto), pVictim);
7760 // Blessing of Light dummy effects healing taken from Holy Light and Flash of Light
7761 if (spellProto->SpellFamilyName == SPELLFAMILY_PALADIN && (spellProto->SpellFamilyFlags & 0x00000000C0000000LL))
7763 AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
7764 for(AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
7766 if((*i)->GetSpellProto()->SpellVisual == 9180)
7768 // Flash of Light
7769 if ((spellProto->SpellFamilyFlags & 0x0000000040000000LL) && (*i)->GetEffIndex() == 1)
7770 AdvertisedBenefit += (*i)->GetModifier()->m_amount;
7771 // Holy Light
7772 else if ((spellProto->SpellFamilyFlags & 0x0000000080000000LL) && (*i)->GetEffIndex() == 0)
7773 AdvertisedBenefit += (*i)->GetModifier()->m_amount;
7778 float ActualBenefit = 0.0f;
7780 if (AdvertisedBenefit != 0)
7782 // Healing over Time spells
7783 float DotFactor = 1.0f;
7784 if(damagetype == DOT)
7786 int32 DotDuration = GetSpellDuration(spellProto);
7787 if(DotDuration > 0)
7789 // 200% limit
7790 if(DotDuration > 30000) DotDuration = 30000;
7791 if(!IsChanneledSpell(spellProto)) DotFactor = DotDuration / 15000.0f;
7792 int x = 0;
7793 for(int j = 0; j < 3; j++)
7795 if( spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && (
7796 spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_HEAL ||
7797 spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH) )
7799 x = j;
7800 break;
7803 int DotTicks = 6;
7804 if(spellProto->EffectAmplitude[x] != 0)
7805 DotTicks = DotDuration / spellProto->EffectAmplitude[x];
7806 if(DotTicks)
7807 AdvertisedBenefit /= DotTicks;
7811 // distribute healing to all effects, reduce AoE damage
7812 CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime );
7814 // 0% bonus for damage and healing spells for leech spells from healing bonus
7815 for(int j = 0; j < 3; ++j)
7817 if( spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH ||
7818 spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH )
7820 CastingTime = 0;
7821 break;
7825 // Exception
7826 switch (spellProto->SpellFamilyName)
7828 case SPELLFAMILY_SHAMAN:
7829 // Healing stream from totem (add 6% per tick from hill bonus owner)
7830 if (spellProto->SpellFamilyFlags & 0x000000002000LL)
7831 CastingTime = 210;
7832 // Earth Shield 30% per charge
7833 else if (spellProto->SpellFamilyFlags & 0x40000000000LL)
7834 CastingTime = 1050;
7835 break;
7836 case SPELLFAMILY_DRUID:
7837 // Lifebloom
7838 if (spellProto->SpellFamilyFlags & 0x1000000000LL)
7840 CastingTime = damagetype == DOT ? 3500 : 1200;
7841 DotFactor = damagetype == DOT ? 0.519f : 1.0f;
7843 // Tranquility triggered spell
7844 else if (spellProto->SpellFamilyFlags & 0x80LL)
7845 CastingTime = 667;
7846 // Rejuvenation
7847 else if (spellProto->SpellFamilyFlags & 0x10LL)
7848 DotFactor = 0.845f;
7849 // Regrowth
7850 else if (spellProto->SpellFamilyFlags & 0x40LL)
7852 DotFactor = damagetype == DOT ? 0.705f : 1.0f;
7853 CastingTime = damagetype == DOT ? 3500 : 1010;
7855 break;
7856 case SPELLFAMILY_PRIEST:
7857 // Holy Nova - 14%
7858 if ((spellProto->SpellFamilyFlags & 0x8000000LL) && spellProto->SpellIconID == 1874)
7859 CastingTime = 500;
7860 break;
7861 case SPELLFAMILY_PALADIN:
7862 // Seal and Judgement of Light
7863 if ( spellProto->SpellFamilyFlags & 0x100040000LL )
7864 CastingTime = 0;
7865 break;
7866 case SPELLFAMILY_WARRIOR:
7867 case SPELLFAMILY_ROGUE:
7868 case SPELLFAMILY_HUNTER:
7869 CastingTime = 0;
7870 break;
7873 float LvlPenalty = CalculateLevelPenalty(spellProto);
7875 // Spellmod SpellDamage
7876 float SpellModSpellDamage = 100.0f;
7878 if(Player* modOwner = GetSpellModOwner())
7879 modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_SPELL_BONUS_DAMAGE,SpellModSpellDamage);
7881 SpellModSpellDamage /= 100.0f;
7883 ActualBenefit = (float)AdvertisedBenefit * ((float)CastingTime / 3500.0f) * DotFactor * SpellModSpellDamage * LvlPenalty;
7886 // use float as more appropriate for negative values and percent applying
7887 float heal = healamount + ActualBenefit;
7889 // TODO: check for ALL/SPELLS type
7890 // Healing done percent
7891 AuraList const& mHealingDonePct = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT);
7892 for(AuraList::const_iterator i = mHealingDonePct.begin();i != mHealingDonePct.end(); ++i)
7893 heal *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f;
7895 // apply spellmod to Done amount
7896 if(Player* modOwner = GetSpellModOwner())
7897 modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal);
7899 // Healing Wave cast
7900 if (spellProto->SpellFamilyName == SPELLFAMILY_SHAMAN && spellProto->SpellFamilyFlags & 0x0000000000000040LL)
7902 // Search for Healing Way on Victim (stack up to 3 time)
7903 int32 pctMod = 0;
7904 Unit::AuraList const& auraDummy = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
7905 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr!=auraDummy.end(); ++itr)
7906 if((*itr)->GetId() == 29203)
7907 pctMod += (*itr)->GetModifier()->m_amount;
7908 // Apply bonus
7909 if (pctMod)
7910 heal = heal * (100 + pctMod) / 100;
7913 // Healing taken percent
7914 float minval = pVictim->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT);
7915 if(minval)
7916 heal *= (100.0f + minval) / 100.0f;
7918 float maxval = pVictim->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT);
7919 if(maxval)
7920 heal *= (100.0f + maxval) / 100.0f;
7922 if (heal < 0) heal = 0;
7924 return uint32(heal);
7927 int32 Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask)
7929 int32 AdvertisedBenefit = 0;
7931 AuraList const& mHealingDone = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE);
7932 for(AuraList::const_iterator i = mHealingDone.begin();i != mHealingDone.end(); ++i)
7933 if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0)
7934 AdvertisedBenefit += (*i)->GetModifier()->m_amount;
7936 // Healing bonus of spirit, intellect and strength
7937 if (GetTypeId() == TYPEID_PLAYER)
7939 // Healing bonus from stats
7940 AuraList const& mHealingDoneOfStatPercent = GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT);
7941 for(AuraList::const_iterator i = mHealingDoneOfStatPercent.begin();i != mHealingDoneOfStatPercent.end(); ++i)
7943 // stat used dependent from misc value (stat index)
7944 Stats usedStat = Stats((*i)->GetSpellProto()->EffectMiscValue[(*i)->GetEffIndex()]);
7945 AdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifier()->m_amount / 100.0f);
7948 // ... and attack power
7949 AuraList const& mHealingDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER);
7950 for(AuraList::const_iterator i = mHealingDonebyAP.begin();i != mHealingDonebyAP.end(); ++i)
7951 if ((*i)->GetModifier()->m_miscvalue & schoolMask)
7952 AdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifier()->m_amount / 100.0f);
7954 return AdvertisedBenefit;
7957 int32 Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask, Unit *pVictim)
7959 int32 AdvertisedBenefit = 0;
7960 AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_HEALING);
7961 for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
7962 if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0)
7963 AdvertisedBenefit += (*i)->GetModifier()->m_amount;
7964 return AdvertisedBenefit;
7967 bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask, bool useCharges)
7969 // no charges dependent checks
7970 SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
7971 for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
7972 if(itr->type & shoolMask)
7973 return true;
7975 // charges dependent checks
7976 SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
7977 for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
7979 if(itr->type & shoolMask)
7981 if(useCharges)
7983 AuraList const& auraDamageImmunity = GetAurasByType(SPELL_AURA_DAMAGE_IMMUNITY);
7984 for(AuraList::const_iterator auraItr = auraDamageImmunity.begin(); auraItr != auraDamageImmunity.end(); ++auraItr)
7986 if((*auraItr)->GetId()==itr->spellId)
7988 if((*auraItr)->m_procCharges > 0)
7990 --(*auraItr)->m_procCharges;
7991 if((*auraItr)->m_procCharges==0)
7992 RemoveAurasDueToSpell(itr->spellId);
7994 break;
7998 return true;
8002 return false;
8005 bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges)
8007 if (!spellInfo)
8008 return false;
8010 // no charges first
8012 //FIX ME this hack: don't get feared if stunned
8013 if (spellInfo->Mechanic == MECHANIC_FEAR )
8015 if ( hasUnitState(UNIT_STAT_STUNNED) )
8016 return true;
8019 // not have spells with charges currently
8020 SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL];
8021 for(SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr)
8022 if(itr->type == spellInfo->Dispel)
8023 return true;
8025 if( !(spellInfo->AttributesEx & SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE) && // unaffected by school immunity
8026 !(spellInfo->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY)) // can remove immune (by dispell or immune it)
8028 // not have spells with charges currently
8029 SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
8030 for(SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
8031 if( !(IsPositiveSpell(itr->spellId) && IsPositiveSpell(spellInfo->Id)) &&
8032 (itr->type & GetSpellSchoolMask(spellInfo)) )
8033 return true;
8036 // charges dependent checks
8038 SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
8039 for(SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
8041 if(itr->type == spellInfo->Mechanic)
8043 if(useCharges)
8045 AuraList const& auraMechImmunity = GetAurasByType(SPELL_AURA_MECHANIC_IMMUNITY);
8046 for(AuraList::const_iterator auraItr = auraMechImmunity.begin(); auraItr != auraMechImmunity.end(); ++auraItr)
8048 if((*auraItr)->GetId()==itr->spellId)
8050 if((*auraItr)->m_procCharges > 0)
8052 --(*auraItr)->m_procCharges;
8053 if((*auraItr)->m_procCharges==0)
8054 RemoveAurasDueToSpell(itr->spellId);
8056 break;
8060 return true;
8064 return false;
8067 bool Unit::IsImmunedToSpellEffect(uint32 effect, uint32 mechanic) const
8069 //If m_immuneToEffect type contain this effect type, IMMUNE effect.
8070 SpellImmuneList const& effectList = m_spellImmune[IMMUNITY_EFFECT];
8071 for (SpellImmuneList::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr)
8072 if(itr->type == effect)
8073 return true;
8075 SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
8076 for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
8077 if(itr->type == mechanic)
8078 return true;
8080 return false;
8083 bool Unit::IsDamageToThreatSpell(SpellEntry const * spellInfo) const
8085 if(!spellInfo)
8086 return false;
8088 uint32 family = spellInfo->SpellFamilyName;
8089 uint64 flags = spellInfo->SpellFamilyFlags;
8091 if((family == 5 && flags == 256) || //Searing Pain
8092 (family == 6 && flags == 8192) || //Mind Blast
8093 (family == 11 && flags == 1048576)) //Earth Shock
8094 return true;
8096 return false;
8099 void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attType, SpellEntry const *spellProto)
8101 if(!pVictim)
8102 return;
8104 if(*pdamage == 0)
8105 return;
8107 uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
8109 // Taken/Done fixed damage bonus auras
8110 int32 DoneFlatBenefit = 0;
8111 int32 TakenFlatBenefit = 0;
8113 // ..done (for creature type by mask) in taken
8114 AuraList const& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
8115 for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
8116 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
8117 DoneFlatBenefit += (*i)->GetModifier()->m_amount;
8119 // ..done
8120 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
8122 // ..done (base at attack power for marked target and base at attack power for creature type)
8123 int32 APbonus = 0;
8124 if(attType == RANGED_ATTACK)
8126 APbonus += pVictim->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS);
8128 // ..done (base at attack power and creature type)
8129 AuraList const& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS);
8130 for(AuraList::const_iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i)
8131 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
8132 APbonus += (*i)->GetModifier()->m_amount;
8134 else
8136 APbonus += pVictim->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS);
8138 // ..done (base at attack power and creature type)
8139 AuraList const& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS);
8140 for(AuraList::const_iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i)
8141 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
8142 APbonus += (*i)->GetModifier()->m_amount;
8145 if (APbonus!=0) // Can be negative
8147 bool normalized = false;
8148 if(spellProto)
8150 for (uint8 i = 0; i<3;i++)
8152 if (spellProto->Effect[i] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG)
8154 normalized = true;
8155 break;
8160 DoneFlatBenefit += int32(APbonus/14.0f * GetAPMultiplier(attType,normalized));
8163 // ..taken
8164 AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
8165 for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
8166 if((*i)->GetModifier()->m_miscvalue & GetMeleeDamageSchoolMask())
8167 TakenFlatBenefit += (*i)->GetModifier()->m_amount;
8169 if(attType!=RANGED_ATTACK)
8170 TakenFlatBenefit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN);
8171 else
8172 TakenFlatBenefit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN);
8174 // Done/Taken total percent damage auras
8175 float DoneTotalMod = 1;
8176 float TakenTotalMod = 1;
8178 // ..done
8179 // SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage
8180 // SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage
8182 AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS);
8183 for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i)
8184 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
8185 DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
8187 // ..taken
8188 AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
8189 for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
8190 if((*i)->GetModifier()->m_miscvalue & GetMeleeDamageSchoolMask())
8191 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
8193 // .. taken pct: dummy auras
8194 AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
8195 for(AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
8197 switch((*i)->GetSpellProto()->SpellIconID)
8199 //Cheat Death
8200 case 2109:
8201 if((*i)->GetModifier()->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL)
8203 if(pVictim->GetTypeId() != TYPEID_PLAYER)
8204 continue;
8205 float mod = ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE)*(-8.0f);
8206 if (mod < (*i)->GetModifier()->m_amount)
8207 mod = (*i)->GetModifier()->m_amount;
8208 TakenTotalMod *= (mod+100.0f)/100.0f;
8210 break;
8211 //Mangle
8212 case 2312:
8213 if(spellProto==NULL)
8214 break;
8215 // Should increase Shred (initial Damage of Lacerate and Rake handled in Spell::EffectSchoolDMG)
8216 if(spellProto->SpellFamilyName==SPELLFAMILY_DRUID && (spellProto->SpellFamilyFlags==0x00008000LL))
8217 TakenTotalMod *= (100.0f+(*i)->GetModifier()->m_amount)/100.0f;
8218 break;
8222 // .. taken pct: class scripts
8223 AuraList const& mclassScritAuras = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
8224 for(AuraList::const_iterator i = mclassScritAuras.begin(); i != mclassScritAuras.end(); ++i)
8226 switch((*i)->GetMiscValue())
8228 case 6427: case 6428: // Dirty Deeds
8229 if(pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT))
8231 Aura* eff0 = GetAura((*i)->GetId(),0);
8232 if(!eff0 || (*i)->GetEffIndex()!=1)
8234 sLog.outError("Spell structure of DD (%u) changed.",(*i)->GetId());
8235 continue;
8238 // effect 0 have expected value but in negative state
8239 TakenTotalMod *= (-eff0->GetModifier()->m_amount+100.0f)/100.0f;
8241 break;
8245 if(attType != RANGED_ATTACK)
8247 AuraList const& mModMeleeDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT);
8248 for(AuraList::const_iterator i = mModMeleeDamageTakenPercent.begin(); i != mModMeleeDamageTakenPercent.end(); ++i)
8249 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
8251 else
8253 AuraList const& mModRangedDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT);
8254 for(AuraList::const_iterator i = mModRangedDamageTakenPercent.begin(); i != mModRangedDamageTakenPercent.end(); ++i)
8255 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
8258 float tmpDamage = float(int32(*pdamage) + DoneFlatBenefit) * DoneTotalMod;
8260 // apply spellmod to Done damage
8261 if(spellProto)
8263 if(Player* modOwner = GetSpellModOwner())
8264 modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, tmpDamage);
8267 tmpDamage = (tmpDamage + TakenFlatBenefit)*TakenTotalMod;
8269 // bonus result can be negative
8270 *pdamage = tmpDamage > 0 ? uint32(tmpDamage) : 0;
8273 void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply)
8275 if (apply)
8277 for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(), next; itr != m_spellImmune[op].end(); itr = next)
8279 next = itr; ++next;
8280 if(itr->type == type)
8282 m_spellImmune[op].erase(itr);
8283 next = m_spellImmune[op].begin();
8286 SpellImmune Immune;
8287 Immune.spellId = spellId;
8288 Immune.type = type;
8289 m_spellImmune[op].push_back(Immune);
8291 else
8293 for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(); itr != m_spellImmune[op].end(); ++itr)
8295 if(itr->spellId == spellId)
8297 m_spellImmune[op].erase(itr);
8298 break;
8305 void Unit::ApplySpellDispelImmunity(const SpellEntry * spellProto, DispelType type, bool apply)
8307 ApplySpellImmune(spellProto->Id,IMMUNITY_DISPEL, type, apply);
8309 if (apply && spellProto->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY)
8310 RemoveAurasWithDispelType(type);
8313 float Unit::GetWeaponProcChance() const
8315 // normalized proc chance for weapon attack speed
8316 // (odd formula...)
8317 if(isAttackReady(BASE_ATTACK))
8318 return (GetAttackTime(BASE_ATTACK) * 1.8f / 1000.0f);
8319 else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK))
8320 return (GetAttackTime(OFF_ATTACK) * 1.6f / 1000.0f);
8321 return 0;
8324 float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM) const
8326 // proc per minute chance calculation
8327 if (PPM <= 0) return 0.0f;
8328 uint32 result = uint32((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
8329 return result;
8332 void Unit::Mount(uint32 mount)
8334 if(!mount)
8335 return;
8337 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNTING);
8339 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, mount);
8341 SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT );
8343 // unsummon pet
8344 if(GetTypeId() == TYPEID_PLAYER)
8346 Pet* pet = GetPet();
8347 if(pet)
8349 if(pet->isControlled())
8351 ((Player*)this)->SetTemporaryUnsummonedPetNumber(pet->GetCharmInfo()->GetPetNumber());
8352 ((Player*)this)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL));
8355 ((Player*)this)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT);
8357 else
8358 ((Player*)this)->SetTemporaryUnsummonedPetNumber(0);
8362 void Unit::Unmount()
8364 if(!IsMounted())
8365 return;
8367 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_MOUNTED);
8369 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0);
8370 RemoveFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT );
8372 // only resummon old pet if the player is already added to a map
8373 // this prevents adding a pet to a not created map which would otherwise cause a crash
8374 // (it could probably happen when logging in after a previous crash)
8375 if(GetTypeId() == TYPEID_PLAYER && IsInWorld() && ((Player*)this)->GetTemporaryUnsummonedPetNumber() && isAlive())
8377 Pet* NewPet = new Pet;
8378 if(!NewPet->LoadPetFromDB(this, 0, ((Player*)this)->GetTemporaryUnsummonedPetNumber(), true))
8379 delete NewPet;
8381 ((Player*)this)->SetTemporaryUnsummonedPetNumber(0);
8385 void Unit::SetInCombatWith(Unit* enemy)
8387 Unit* eOwner = enemy->GetCharmerOrOwnerOrSelf();
8388 if(eOwner->IsPvP())
8390 SetInCombatState(true);
8391 return;
8394 //check for duel
8395 if(eOwner->GetTypeId() == TYPEID_PLAYER && ((Player*)eOwner)->duel)
8397 Unit const* myOwner = GetCharmerOrOwnerOrSelf();
8398 if(((Player const*)eOwner)->duel->opponent == myOwner)
8400 SetInCombatState(true);
8401 return;
8404 SetInCombatState(false);
8407 void Unit::SetInCombatState(bool PvP)
8409 // only alive units can be in combat
8410 if(!isAlive())
8411 return;
8413 if(PvP)
8414 m_CombatTimer = 5000;
8415 SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
8417 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet()))
8418 SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
8421 void Unit::ClearInCombat()
8423 m_CombatTimer = 0;
8424 RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
8426 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet()))
8427 RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
8429 // Player's state will be cleared in Player::UpdateContestedPvP
8430 if(GetTypeId()!=TYPEID_PLAYER)
8431 clearUnitState(UNIT_STAT_ATTACK_PLAYER);
8434 bool Unit::isTargetableForAttack() const
8436 if (GetTypeId()==TYPEID_PLAYER && ((Player *)this)->isGameMaster())
8437 return false;
8439 if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE))
8440 return false;
8442 return isAlive() && !hasUnitState(UNIT_STAT_DIED)&& !isInFlight() /*&& !isStealth()*/;
8445 int32 Unit::ModifyHealth(int32 dVal)
8447 int32 gain = 0;
8449 if(dVal==0)
8450 return 0;
8452 int32 curHealth = (int32)GetHealth();
8454 int32 val = dVal + curHealth;
8455 if(val <= 0)
8457 SetHealth(0);
8458 return -curHealth;
8461 int32 maxHealth = (int32)GetMaxHealth();
8463 if(val < maxHealth)
8465 SetHealth(val);
8466 gain = val - curHealth;
8468 else if(curHealth != maxHealth)
8470 SetHealth(maxHealth);
8471 gain = maxHealth - curHealth;
8474 return gain;
8477 int32 Unit::ModifyPower(Powers power, int32 dVal)
8479 int32 gain = 0;
8481 if(dVal==0)
8482 return 0;
8484 int32 curPower = (int32)GetPower(power);
8486 int32 val = dVal + curPower;
8487 if(val <= 0)
8489 SetPower(power,0);
8490 return -curPower;
8493 int32 maxPower = (int32)GetMaxPower(power);
8495 if(val < maxPower)
8497 SetPower(power,val);
8498 gain = val - curPower;
8500 else if(curPower != maxPower)
8502 SetPower(power,maxPower);
8503 gain = maxPower - curPower;
8506 return gain;
8509 bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList, bool is3dDistance) const
8511 if(!u)
8512 return false;
8514 // Always can see self
8515 if (u==this)
8516 return true;
8518 // player visible for other player if not logout and at same transport
8519 // including case when player is out of world
8520 bool at_same_transport =
8521 GetTypeId() == TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER &&
8522 !((Player*)this)->GetSession()->PlayerLogout() && !((Player*)u)->GetSession()->PlayerLogout() &&
8523 !((Player*)this)->GetSession()->PlayerLoading() && !((Player*)u)->GetSession()->PlayerLoading() &&
8524 ((Player*)this)->GetTransport() && ((Player*)this)->GetTransport() == ((Player*)u)->GetTransport();
8526 // not in world
8527 if(!at_same_transport && (!IsInWorld() || !u->IsInWorld()))
8528 return false;
8530 // forbidden to seen (at GM respawn command)
8531 if(m_Visibility==VISIBILITY_RESPAWN)
8532 return false;
8534 // always seen by owner
8535 if(GetCharmerOrOwnerGUID()==u->GetGUID())
8536 return true;
8538 // Grid dead/alive checks
8539 if( u->GetTypeId()==TYPEID_PLAYER)
8541 // non visible at grid for any stealth state
8542 if(!IsVisibleInGridForPlayer((Player *)u))
8543 return false;
8545 // if player is dead then he can't detect anyone in any cases
8546 if(!u->isAlive())
8547 detect = false;
8549 else
8551 // all dead creatures/players not visible for any creatures
8552 if(!u->isAlive() || !isAlive())
8553 return false;
8556 // different visible distance checks
8557 if(u->isInFlight()) // what see player in flight
8559 // use object grey distance for all (only see objects any way)
8560 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceInFlight()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), is3dDistance))
8561 return false;
8563 else if(!isAlive()) // distance for show body
8565 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), is3dDistance))
8566 return false;
8568 else if(GetTypeId()==TYPEID_PLAYER) // distance for show player
8570 if(u->GetTypeId()==TYPEID_PLAYER)
8572 // Players far than max visible distance for player or not in our map are not visible too
8573 if (!at_same_transport && !IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance))
8574 return false;
8576 else
8578 // Units far than max visible distance for creature or not in our map are not visible too
8579 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance))
8580 return false;
8583 else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed
8585 // Pet/charmed far than max visible distance for player or not in our map are not visible too
8586 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance))
8587 return false;
8589 else // distance for show creature
8591 // Units far than max visible distance for creature or not in our map are not visible too
8592 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance))
8593 return false;
8596 // Visible units, always are visible for all units, except for units under invisibility
8597 if (m_Visibility == VISIBILITY_ON && u->m_invisibilityMask==0)
8598 return true;
8600 // GMs see any players, not higher GMs and all units
8601 if (u->GetTypeId() == TYPEID_PLAYER && ((Player *)u)->isGameMaster())
8603 if(GetTypeId() == TYPEID_PLAYER)
8604 return ((Player *)this)->GetSession()->GetSecurity() <= ((Player *)u)->GetSession()->GetSecurity();
8605 else
8606 return true;
8609 // non faction visibility non-breakable for non-GMs
8610 if (m_Visibility == VISIBILITY_OFF)
8611 return false;
8613 // raw invisibility
8614 bool invisible = (m_invisibilityMask != 0 || u->m_invisibilityMask !=0);
8616 // detectable invisibility case
8617 if( invisible && (
8618 // Invisible units, always are visible for units under same invisibility type
8619 (m_invisibilityMask & u->m_invisibilityMask)!=0 ||
8620 // Invisible units, always are visible for unit that can detect this invisibility (have appropriate level for detect)
8621 u->canDetectInvisibilityOf(this) ||
8622 // Units that can detect invisibility always are visible for units that can be detected
8623 canDetectInvisibilityOf(u) ))
8625 invisible = false;
8628 // special cases for always overwrite invisibility/stealth
8629 if(invisible || m_Visibility == VISIBILITY_GROUP_STEALTH)
8631 // non-hostile case
8632 if (!u->IsHostileTo(this))
8634 // player see other player with stealth/invisibility only if he in same group or raid or same team (raid/team case dependent from conf setting)
8635 if(GetTypeId()==TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER)
8637 if(((Player*)this)->IsGroupVisibleFor(((Player*)u)))
8638 return true;
8640 // else apply same rules as for hostile case (detecting check for stealth)
8643 // hostile case
8644 else
8646 // Hunter mark functionality
8647 AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_STALKED);
8648 for(AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
8649 if((*iter)->GetCasterGUID()==u->GetGUID())
8650 return true;
8652 // else apply detecting check for stealth
8655 // none other cases for detect invisibility, so invisible
8656 if(invisible)
8657 return false;
8659 // else apply stealth detecting check
8662 // unit got in stealth in this moment and must ignore old detected state
8663 if (m_Visibility == VISIBILITY_GROUP_NO_DETECT)
8664 return false;
8666 // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible
8667 if (m_Visibility != VISIBILITY_GROUP_STEALTH)
8668 return true;
8670 // NOW ONLY STEALTH CASE
8672 // stealth and detected and visible for some seconds
8673 if (u->GetTypeId() == TYPEID_PLAYER && ((Player*)u)->m_DetectInvTimer > 300 && ((Player*)u)->HaveAtClient(this))
8674 return true;
8676 //if in non-detect mode then invisible for unit
8677 if (!detect)
8678 return false;
8680 // Special cases
8682 // If is attacked then stealth is lost, some creature can use stealth too
8683 if( !getAttackers().empty() )
8684 return true;
8686 // If there is collision rogue is seen regardless of level difference
8687 // TODO: check sizes in DB
8688 float distance = GetDistance(u);
8689 if (distance < 0.24f)
8690 return true;
8692 //If a mob or player is stunned he will not be able to detect stealth
8693 if (u->hasUnitState(UNIT_STAT_STUNNED) && (u != this))
8694 return false;
8696 // Creature can detect target only in aggro radius
8697 if(u->GetTypeId() != TYPEID_PLAYER)
8699 //Always invisible from back and out of aggro range
8700 bool isInFront = u->isInFront(this,((Creature const*)u)->GetAttackDistance(this));
8701 if(!isInFront)
8702 return false;
8704 else
8706 //Always invisible from back
8707 bool isInFront = u->isInFront(this,(GetTypeId()==TYPEID_PLAYER || GetCharmerOrOwnerGUID()) ? World::GetMaxVisibleDistanceForPlayer() : World::GetMaxVisibleDistanceForCreature());
8708 if(!isInFront)
8709 return false;
8712 // if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los
8713 if(!u->HasAuraType(SPELL_AURA_DETECT_STEALTH))
8715 //Calculation if target is in front
8717 //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5)
8718 float visibleDistance = 10.5f - (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH)/100.0f);
8720 //Visible distance is modified by
8721 //-Level Diff (every level diff = 1.0f in visible distance)
8722 visibleDistance += int32(u->getLevelForTarget(this)) - int32(getLevelForTarget(u));
8724 //This allows to check talent tree and will add addition stealth dependent on used points)
8725 int32 stealthMod = GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL);
8726 if(stealthMod < 0)
8727 stealthMod = 0;
8729 //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia)
8730 //based on wowwiki every 5 mod we have 1 more level diff in calculation
8731 visibleDistance += (int32(u->GetTotalAuraModifier(SPELL_AURA_MOD_DETECT)) - stealthMod)/5.0f;
8733 if(distance > visibleDistance)
8734 return false;
8737 // Now check is target visible with LoS
8738 float ox,oy,oz;
8739 u->GetPosition(ox,oy,oz);
8740 return IsWithinLOS(ox,oy,oz);
8743 void Unit::SetVisibility(UnitVisibility x)
8745 m_Visibility = x;
8747 if(IsInWorld())
8749 Map *m = GetMap();
8751 if(GetTypeId()==TYPEID_PLAYER)
8752 m->PlayerRelocation((Player*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8753 else
8754 m->CreatureRelocation((Creature*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8758 bool Unit::canDetectInvisibilityOf(Unit const* u) const
8760 if(uint32 mask = (m_detectInvisibilityMask & u->m_invisibilityMask))
8762 for(uint32 i = 0; i < 10; ++i)
8764 if(((1 << i) & mask)==0)
8765 continue;
8767 // find invisibility level
8768 uint32 invLevel = 0;
8769 Unit::AuraList const& iAuras = u->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY);
8770 for(Unit::AuraList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr)
8771 if(((*itr)->GetModifier()->m_miscvalue)==i && invLevel < (*itr)->GetModifier()->m_amount)
8772 invLevel = (*itr)->GetModifier()->m_amount;
8774 // find invisibility detect level
8775 uint32 detectLevel = 0;
8776 Unit::AuraList const& dAuras = GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION);
8777 for(Unit::AuraList::const_iterator itr = dAuras.begin(); itr != dAuras.end(); ++itr)
8778 if(((*itr)->GetModifier()->m_miscvalue)==i && detectLevel < (*itr)->GetModifier()->m_amount)
8779 detectLevel = (*itr)->GetModifier()->m_amount;
8781 if(i==6 && GetTypeId()==TYPEID_PLAYER) // special drunk detection case
8783 detectLevel = ((Player*)this)->GetDrunkValue();
8786 if(invLevel <= detectLevel)
8787 return true;
8791 return false;
8794 void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
8796 int32 main_speed_mod = 0;
8797 float stack_bonus = 1.0f;
8798 float non_stack_bonus = 1.0f;
8800 switch(mtype)
8802 case MOVE_WALK:
8803 return;
8804 case MOVE_RUN:
8806 if (IsMounted()) // Use on mount auras
8808 main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED);
8809 stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS);
8810 non_stack_bonus = (100.0f + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK))/100.0f;
8812 else
8814 main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SPEED);
8815 stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_SPEED_ALWAYS);
8816 non_stack_bonus = (100.0f + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_SPEED_NOT_STACK))/100.0f;
8818 break;
8820 case MOVE_RUN_BACK:
8821 return;
8822 case MOVE_SWIM:
8824 main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SWIM_SPEED);
8825 break;
8827 case MOVE_SWIM_BACK:
8828 return;
8829 case MOVE_FLIGHT:
8831 if (IsMounted()) // Use on mount auras
8832 main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED);
8833 else // Use not mount (shapeshift for example) auras (should stack)
8834 main_speed_mod = GetTotalAuraModifier(SPELL_AURA_MOD_SPEED_FLIGHT);
8835 stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS);
8836 non_stack_bonus = (100.0 + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK))/100.0f;
8837 break;
8839 case MOVE_FLIGHT_BACK:
8840 return;
8841 default:
8842 sLog.outError("Unit::UpdateSpeed: Unsupported move type (%d)", mtype);
8843 return;
8846 float bonus = non_stack_bonus > stack_bonus ? non_stack_bonus : stack_bonus;
8847 // now we ready for speed calculation
8848 float speed = main_speed_mod ? bonus*(100.0f + main_speed_mod)/100.0f : bonus;
8850 switch(mtype)
8852 case MOVE_RUN:
8853 case MOVE_SWIM:
8854 case MOVE_FLIGHT:
8856 // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
8857 // TODO: possible affect only on MOVE_RUN
8858 if(int32 normalization = GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED))
8860 // Use speed from aura
8861 float max_speed = normalization / baseMoveSpeed[mtype];
8862 if (speed > max_speed)
8863 speed = max_speed;
8865 break;
8867 default:
8868 break;
8871 // Apply strongest slow aura mod to speed
8872 int32 slow = GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED);
8873 if (slow)
8874 speed *=(100.0f + slow)/100.0f;
8875 SetSpeed(mtype, speed, forced);
8878 float Unit::GetSpeed( UnitMoveType mtype ) const
8880 return m_speed_rate[mtype]*baseMoveSpeed[mtype];
8883 void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced)
8885 if (rate < 0)
8886 rate = 0.0f;
8888 // Update speed only on change
8889 if (m_speed_rate[mtype] == rate)
8890 return;
8892 m_speed_rate[mtype] = rate;
8894 propagateSpeedChange();
8896 // Send speed change packet only for player
8897 if (GetTypeId()!=TYPEID_PLAYER)
8898 return;
8900 WorldPacket data;
8901 if(!forced)
8903 switch(mtype)
8905 case MOVE_WALK:
8906 data.Initialize(MSG_MOVE_SET_WALK_SPEED, 8+4+1+4+4+4+4+4+4+4);
8907 break;
8908 case MOVE_RUN:
8909 data.Initialize(MSG_MOVE_SET_RUN_SPEED, 8+4+1+4+4+4+4+4+4+4);
8910 break;
8911 case MOVE_RUN_BACK:
8912 data.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED, 8+4+1+4+4+4+4+4+4+4);
8913 break;
8914 case MOVE_SWIM:
8915 data.Initialize(MSG_MOVE_SET_SWIM_SPEED, 8+4+1+4+4+4+4+4+4+4);
8916 break;
8917 case MOVE_SWIM_BACK:
8918 data.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED, 8+4+1+4+4+4+4+4+4+4);
8919 break;
8920 case MOVE_TURN_RATE:
8921 data.Initialize(MSG_MOVE_SET_TURN_RATE, 8+4+1+4+4+4+4+4+4+4);
8922 break;
8923 case MOVE_FLIGHT:
8924 data.Initialize(MSG_MOVE_SET_FLIGHT_SPEED, 8+4+1+4+4+4+4+4+4+4);
8925 break;
8926 case MOVE_FLIGHT_BACK:
8927 data.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED, 8+4+1+4+4+4+4+4+4+4);
8928 break;
8929 default:
8930 sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype);
8931 return;
8934 data.append(GetPackGUID());
8935 data << uint32(0); //movement flags
8936 data << uint8(0); //unk
8937 data << uint32(getMSTime());
8938 data << float(GetPositionX());
8939 data << float(GetPositionY());
8940 data << float(GetPositionZ());
8941 data << float(GetOrientation());
8942 data << uint32(0); //flag unk
8943 data << float(GetSpeed(mtype));
8944 SendMessageToSet( &data, true );
8946 else
8948 // register forced speed changes for WorldSession::HandleForceSpeedChangeAck
8949 // and do it only for real sent packets and use run for run/mounted as client expected
8950 ++((Player*)this)->m_forced_speed_changes[mtype];
8951 switch(mtype)
8953 case MOVE_WALK:
8954 data.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE, 16);
8955 break;
8956 case MOVE_RUN:
8957 data.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE, 17);
8958 break;
8959 case MOVE_RUN_BACK:
8960 data.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE, 16);
8961 break;
8962 case MOVE_SWIM:
8963 data.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE, 16);
8964 break;
8965 case MOVE_SWIM_BACK:
8966 data.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE, 16);
8967 break;
8968 case MOVE_TURN_RATE:
8969 data.Initialize(SMSG_FORCE_TURN_RATE_CHANGE, 16);
8970 break;
8971 case MOVE_FLIGHT:
8972 data.Initialize(SMSG_FORCE_FLIGHT_SPEED_CHANGE, 16);
8973 break;
8974 case MOVE_FLIGHT_BACK:
8975 data.Initialize(SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE, 16);
8976 break;
8977 default:
8978 sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype);
8979 return;
8981 data.append(GetPackGUID());
8982 data << (uint32)0; // moveEvent, NUM_PMOVE_EVTS = 0x39
8983 if (mtype == MOVE_RUN)
8984 data << uint8(0); // new 2.1.0
8985 data << float(GetSpeed(mtype));
8986 SendMessageToSet( &data, true );
8988 if(Pet* pet = GetPet())
8989 pet->SetSpeed(MOVE_RUN, m_speed_rate[mtype],forced);
8992 void Unit::SetHover(bool on)
8994 if(on)
8995 CastSpell(this,11010,true);
8996 else
8997 RemoveAurasDueToSpell(11010);
9000 void Unit::setDeathState(DeathState s)
9002 if (s != ALIVE && s!= JUST_ALIVED)
9004 CombatStop();
9005 DeleteThreatList();
9006 ClearComboPointHolders(); // any combo points pointed to unit lost at it death
9008 if(IsNonMeleeSpellCasted(false))
9009 InterruptNonMeleeSpells(false);
9012 if (s == JUST_DIED)
9014 RemoveAllAurasOnDeath();
9015 UnsummonAllTotems();
9017 ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false);
9018 ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false);
9019 // remove aurastates allowing special moves
9020 ClearAllReactives();
9021 ClearDiminishings();
9023 else if(s == JUST_ALIVED)
9025 RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); // clear skinnable for creature and player (at battleground)
9028 if (m_deathState != ALIVE && s == ALIVE)
9030 //_ApplyAllAuraMods();
9032 m_deathState = s;
9035 /*########################################
9036 ######## ########
9037 ######## AGGRO SYSTEM ########
9038 ######## ########
9039 ########################################*/
9040 bool Unit::CanHaveThreatList() const
9042 // only creatures can have threat list
9043 if( GetTypeId() != TYPEID_UNIT )
9044 return false;
9046 // only alive units can have threat list
9047 if( !isAlive() )
9048 return false;
9050 // totems can not have threat list
9051 if( ((Creature*)this)->isTotem() )
9052 return false;
9054 // pets can not have a threat list, unless they are controlled by a creature
9055 if( ((Creature*)this)->isPet() && IS_PLAYER_GUID(((Pet*)this)->GetOwnerGUID()) )
9056 return false;
9058 return true;
9061 //======================================================================
9063 float Unit::ApplyTotalThreatModifier(float threat, SpellSchoolMask schoolMask)
9065 if(!HasAuraType(SPELL_AURA_MOD_THREAT))
9066 return threat;
9068 SpellSchools school = GetFirstSchoolInMask(schoolMask);
9070 return threat * m_threatModifier[school];
9073 //======================================================================
9075 void Unit::AddThreat(Unit* pVictim, float threat, SpellSchoolMask schoolMask, SpellEntry const *threatSpell)
9077 // Only mobs can manage threat lists
9078 if(CanHaveThreatList())
9079 m_ThreatManager.addThreat(pVictim, threat, schoolMask, threatSpell);
9082 //======================================================================
9084 void Unit::DeleteThreatList()
9086 m_ThreatManager.clearReferences();
9089 //======================================================================
9091 void Unit::TauntApply(Unit* taunter)
9093 assert(GetTypeId()== TYPEID_UNIT);
9095 if(!taunter || (taunter->GetTypeId() == TYPEID_PLAYER && ((Player*)taunter)->isGameMaster()))
9096 return;
9098 if(!CanHaveThreatList())
9099 return;
9101 Unit *target = getVictim();
9102 if(target && target == taunter)
9103 return;
9105 SetInFront(taunter);
9106 if (((Creature*)this)->AI())
9107 ((Creature*)this)->AI()->AttackStart(taunter);
9109 m_ThreatManager.tauntApply(taunter);
9112 //======================================================================
9114 void Unit::TauntFadeOut(Unit *taunter)
9116 assert(GetTypeId()== TYPEID_UNIT);
9118 if(!taunter || (taunter->GetTypeId() == TYPEID_PLAYER && ((Player*)taunter)->isGameMaster()))
9119 return;
9121 if(!CanHaveThreatList())
9122 return;
9124 Unit *target = getVictim();
9125 if(!target || target != taunter)
9126 return;
9128 if(m_ThreatManager.isThreatListEmpty())
9130 if(((Creature*)this)->AI())
9131 ((Creature*)this)->AI()->EnterEvadeMode();
9132 return;
9135 m_ThreatManager.tauntFadeOut(taunter);
9136 target = m_ThreatManager.getHostilTarget();
9138 if (target && target != taunter)
9140 SetInFront(target);
9141 if (((Creature*)this)->AI())
9142 ((Creature*)this)->AI()->AttackStart(target);
9146 //======================================================================
9148 bool Unit::SelectHostilTarget()
9150 //function provides main threat functionality
9151 //next-victim-selection algorithm and evade mode are called
9152 //threat list sorting etc.
9154 assert(GetTypeId()== TYPEID_UNIT);
9155 Unit* target = NULL;
9157 //This function only useful once AI has been initialized
9158 if (!((Creature*)this)->AI())
9159 return false;
9161 if(!m_ThreatManager.isThreatListEmpty())
9163 if(!HasAuraType(SPELL_AURA_MOD_TAUNT))
9165 target = m_ThreatManager.getHostilTarget();
9169 if(target)
9171 if(!hasUnitState(UNIT_STAT_STUNNED))
9172 SetInFront(target);
9173 ((Creature*)this)->AI()->AttackStart(target);
9174 return true;
9177 // no target but something prevent go to evade mode
9178 if( !isInCombat() || HasAuraType(SPELL_AURA_MOD_TAUNT) )
9179 return false;
9181 // last case when creature don't must go to evade mode:
9182 // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list
9183 // for example at owner command to pet attack some far away creature
9184 // Note: creature not have targeted movement generator but have attacker in this case
9185 if( GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE )
9187 for(AttackerSet::const_iterator itr = m_attackers.begin(); itr != m_attackers.end(); ++itr)
9189 if( (*itr)->IsInMap(this) && (*itr)->isTargetableForAttack() && (*itr)->isInAccessablePlaceFor((Creature*)this) )
9190 return false;
9194 // enter in evade mode in other case
9195 ((Creature*)this)->AI()->EnterEvadeMode();
9197 return false;
9200 //======================================================================
9201 //======================================================================
9202 //======================================================================
9204 int32 Unit::CalculateSpellDamage(SpellEntry const* spellProto, uint8 effect_index, int32 effBasePoints, Unit const* target)
9206 Player* unitPlayer = (GetTypeId() == TYPEID_PLAYER) ? (Player*)this : NULL;
9208 uint8 comboPoints = unitPlayer ? unitPlayer->GetComboPoints() : 0;
9210 int32 level = int32(getLevel());
9211 if (level > (int32)spellProto->maxLevel && spellProto->maxLevel > 0)
9212 level = (int32)spellProto->maxLevel;
9213 else if (level < (int32)spellProto->baseLevel)
9214 level = (int32)spellProto->baseLevel;
9215 level-= (int32)spellProto->spellLevel;
9217 float basePointsPerLevel = spellProto->EffectRealPointsPerLevel[effect_index];
9218 float randomPointsPerLevel = spellProto->EffectDicePerLevel[effect_index];
9219 int32 basePoints = int32(effBasePoints + level * basePointsPerLevel);
9220 int32 randomPoints = int32(spellProto->EffectDieSides[effect_index] + level * randomPointsPerLevel);
9221 float comboDamage = spellProto->EffectPointsPerComboPoint[effect_index];
9223 // prevent random generator from getting confused by spells casted with Unit::CastCustomSpell
9224 int32 randvalue = spellProto->EffectBaseDice[effect_index] >= randomPoints ? spellProto->EffectBaseDice[effect_index]:irand(spellProto->EffectBaseDice[effect_index], randomPoints);
9225 int32 value = basePoints + randvalue;
9226 //random damage
9227 if(comboDamage != 0 && unitPlayer && target && (target->GetGUID() == unitPlayer->GetComboTarget()))
9228 value += (int32)(comboDamage * comboPoints);
9230 if(Player* modOwner = GetSpellModOwner())
9232 modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_ALL_EFFECTS, value);
9233 switch(effect_index)
9235 case 0:
9236 modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT1, value);
9237 break;
9238 case 1:
9239 modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT2, value);
9240 break;
9241 case 2:
9242 modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT3, value);
9243 break;
9247 if(spellProto->Attributes & SPELL_ATTR_LEVEL_DAMAGE_CALCULATION && spellProto->spellLevel &&
9248 spellProto->Effect[effect_index] != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE &&
9249 spellProto->Effect[effect_index] != SPELL_EFFECT_KNOCK_BACK)
9250 value = int32(value*0.25f*exp(getLevel()*(70-spellProto->spellLevel)/1000.0f));
9252 return value;
9255 int32 Unit::CalculateSpellDuration(SpellEntry const* spellProto, uint8 effect_index, Unit const* target)
9257 Player* unitPlayer = (GetTypeId() == TYPEID_PLAYER) ? (Player*)this : NULL;
9259 uint8 comboPoints = unitPlayer ? unitPlayer->GetComboPoints() : 0;
9261 int32 minduration = GetSpellDuration(spellProto);
9262 int32 maxduration = GetSpellMaxDuration(spellProto);
9264 int32 duration;
9266 if( minduration != -1 && minduration != maxduration )
9267 duration = minduration + int32((maxduration - minduration) * comboPoints / 5);
9268 else
9269 duration = minduration;
9271 if (duration > 0)
9273 int32 mechanic = GetEffectMechanic(spellProto, effect_index);
9274 // Find total mod value (negative bonus)
9275 int32 durationMod_always = target->GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD, mechanic);
9276 // Find max mod (negative bonus)
9277 int32 durationMod_not_stack = target->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK, mechanic);
9279 int32 durationMod = 0;
9280 // Select strongest negative mod
9281 if (durationMod_always > durationMod_not_stack)
9282 durationMod = durationMod_not_stack;
9283 else
9284 durationMod = durationMod_always;
9286 if (durationMod != 0)
9287 duration = int32(int64(duration) * (100+durationMod) /100);
9289 if (duration < 0) duration = 0;
9292 return duration;
9295 DiminishingLevels Unit::GetDiminishing(DiminishingGroup group)
9297 for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
9299 if(i->DRGroup != group)
9300 continue;
9302 if(!i->hitCount)
9303 return DIMINISHING_LEVEL_1;
9305 if(!i->hitTime)
9306 return DIMINISHING_LEVEL_1;
9308 // If last spell was casted more than 15 seconds ago - reset the count.
9309 if(i->stack==0 && getMSTimeDiff(i->hitTime,getMSTime()) > 15000)
9311 i->hitCount = DIMINISHING_LEVEL_1;
9312 return DIMINISHING_LEVEL_1;
9314 // or else increase the count.
9315 else
9317 return DiminishingLevels(i->hitCount);
9320 return DIMINISHING_LEVEL_1;
9323 void Unit::IncrDiminishing(DiminishingGroup group)
9325 // Checking for existing in the table
9326 bool IsExist = false;
9327 for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
9329 if(i->DRGroup != group)
9330 continue;
9332 IsExist = true;
9333 if(i->hitCount < DIMINISHING_LEVEL_IMMUNE)
9334 i->hitCount += 1;
9336 break;
9339 if(!IsExist)
9340 m_Diminishing.push_back(DiminishingReturn(group,getMSTime(),DIMINISHING_LEVEL_2));
9343 void Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,Unit* caster,DiminishingLevels Level)
9345 if(duration == -1 || group == DIMINISHING_NONE || caster->IsFriendlyTo(this) )
9346 return;
9348 // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
9349 if(duration > 10000 && IsDiminishingReturnsGroupDurationLimited(group))
9351 // test pet/charm masters instead pets/charmeds
9352 Unit const* targetOwner = GetCharmerOrOwner();
9353 Unit const* casterOwner = caster->GetCharmerOrOwner();
9355 Unit const* target = targetOwner ? targetOwner : this;
9356 Unit const* source = casterOwner ? casterOwner : caster;
9358 if(target->GetTypeId() == TYPEID_PLAYER && source->GetTypeId() == TYPEID_PLAYER)
9359 duration = 10000;
9362 float mod = 1.0f;
9364 // Some diminishings applies to mobs too (for example, Stun)
9365 if((GetDiminishingReturnsGroupType(group) == DRTYPE_PLAYER && GetTypeId() == TYPEID_PLAYER) || GetDiminishingReturnsGroupType(group) == DRTYPE_ALL)
9367 DiminishingLevels diminish = Level;
9368 switch(diminish)
9370 case DIMINISHING_LEVEL_1: break;
9371 case DIMINISHING_LEVEL_2: mod = 0.5f; break;
9372 case DIMINISHING_LEVEL_3: mod = 0.25f; break;
9373 case DIMINISHING_LEVEL_IMMUNE: mod = 0.0f;break;
9374 default: break;
9378 duration = int32(duration * mod);
9381 void Unit::ApplyDiminishingAura( DiminishingGroup group, bool apply )
9383 // Checking for existing in the table
9384 for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
9386 if(i->DRGroup != group)
9387 continue;
9389 i->hitTime = getMSTime();
9391 if(apply)
9392 i->stack += 1;
9393 else if(i->stack)
9394 i->stack -= 1;
9396 break;
9400 Unit* Unit::GetUnit(WorldObject& object, uint64 guid)
9402 return ObjectAccessor::GetUnit(object,guid);
9405 bool Unit::isVisibleForInState( Player const* u, bool inVisibleList ) const
9407 return isVisibleForOrDetect(u, false, inVisibleList, false);
9410 uint32 Unit::GetCreatureType() const
9412 if(GetTypeId() == TYPEID_PLAYER)
9414 SpellShapeshiftEntry const* ssEntry = sSpellShapeshiftStore.LookupEntry(((Player*)this)->m_form);
9415 if(ssEntry && ssEntry->creatureType > 0)
9416 return ssEntry->creatureType;
9417 else
9418 return CREATURE_TYPE_HUMANOID;
9420 else
9421 return ((Creature*)this)->GetCreatureInfo()->type;
9424 /*#######################################
9425 ######## ########
9426 ######## STAT SYSTEM ########
9427 ######## ########
9428 #######################################*/
9430 bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, float amount, bool apply)
9432 if(unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END)
9434 sLog.outError("ERROR in HandleStatModifier(): non existed UnitMods or wrong UnitModifierType!");
9435 return false;
9438 float val = 1.0f;
9440 switch(modifierType)
9442 case BASE_VALUE:
9443 case TOTAL_VALUE:
9444 m_auraModifiersGroup[unitMod][modifierType] += apply ? amount : -amount;
9445 break;
9446 case BASE_PCT:
9447 case TOTAL_PCT:
9448 if(amount <= -100.0f) //small hack-fix for -100% modifiers
9449 amount = -200.0f;
9451 val = (100.0f + amount) / 100.0f;
9452 m_auraModifiersGroup[unitMod][modifierType] *= apply ? val : (1.0f/val);
9453 break;
9455 default:
9456 break;
9459 if(!CanModifyStats())
9460 return false;
9462 switch(unitMod)
9464 case UNIT_MOD_STAT_STRENGTH:
9465 case UNIT_MOD_STAT_AGILITY:
9466 case UNIT_MOD_STAT_STAMINA:
9467 case UNIT_MOD_STAT_INTELLECT:
9468 case UNIT_MOD_STAT_SPIRIT: UpdateStats(GetStatByAuraGroup(unitMod)); break;
9470 case UNIT_MOD_ARMOR: UpdateArmor(); break;
9471 case UNIT_MOD_HEALTH: UpdateMaxHealth(); break;
9473 case UNIT_MOD_MANA:
9474 case UNIT_MOD_RAGE:
9475 case UNIT_MOD_FOCUS:
9476 case UNIT_MOD_ENERGY:
9477 case UNIT_MOD_HAPPINESS: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod)); break;
9479 case UNIT_MOD_RESISTANCE_HOLY:
9480 case UNIT_MOD_RESISTANCE_FIRE:
9481 case UNIT_MOD_RESISTANCE_NATURE:
9482 case UNIT_MOD_RESISTANCE_FROST:
9483 case UNIT_MOD_RESISTANCE_SHADOW:
9484 case UNIT_MOD_RESISTANCE_ARCANE: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod)); break;
9486 case UNIT_MOD_ATTACK_POWER: UpdateAttackPowerAndDamage(); break;
9487 case UNIT_MOD_ATTACK_POWER_RANGED: UpdateAttackPowerAndDamage(true); break;
9489 case UNIT_MOD_DAMAGE_MAINHAND: UpdateDamagePhysical(BASE_ATTACK); break;
9490 case UNIT_MOD_DAMAGE_OFFHAND: UpdateDamagePhysical(OFF_ATTACK); break;
9491 case UNIT_MOD_DAMAGE_RANGED: UpdateDamagePhysical(RANGED_ATTACK); break;
9493 default:
9494 break;
9497 return true;
9500 float Unit::GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) const
9502 if( unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END)
9504 sLog.outError("ERROR: trial to access non existed modifier value from UnitMods!");
9505 return 0.0f;
9508 if(modifierType == TOTAL_PCT && m_auraModifiersGroup[unitMod][modifierType] <= 0.0f)
9509 return 0.0f;
9511 return m_auraModifiersGroup[unitMod][modifierType];
9514 float Unit::GetTotalStatValue(Stats stat) const
9516 UnitMods unitMod = UnitMods(UNIT_MOD_STAT_START + stat);
9518 if(m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f)
9519 return 0.0f;
9521 // value = ((base_value * base_pct) + total_value) * total_pct
9522 float value = m_auraModifiersGroup[unitMod][BASE_VALUE] + GetCreateStat(stat);
9523 value *= m_auraModifiersGroup[unitMod][BASE_PCT];
9524 value += m_auraModifiersGroup[unitMod][TOTAL_VALUE];
9525 value *= m_auraModifiersGroup[unitMod][TOTAL_PCT];
9527 return value;
9530 float Unit::GetTotalAuraModValue(UnitMods unitMod) const
9532 if(unitMod >= UNIT_MOD_END)
9534 sLog.outError("ERROR: trial to access non existed UnitMods in GetTotalAuraModValue()!");
9535 return 0.0f;
9538 if(m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f)
9539 return 0.0f;
9541 float value = m_auraModifiersGroup[unitMod][BASE_VALUE];
9542 value *= m_auraModifiersGroup[unitMod][BASE_PCT];
9543 value += m_auraModifiersGroup[unitMod][TOTAL_VALUE];
9544 value *= m_auraModifiersGroup[unitMod][TOTAL_PCT];
9546 return value;
9549 SpellSchools Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod) const
9551 SpellSchools school = SPELL_SCHOOL_NORMAL;
9553 switch(unitMod)
9555 case UNIT_MOD_RESISTANCE_HOLY: school = SPELL_SCHOOL_HOLY; break;
9556 case UNIT_MOD_RESISTANCE_FIRE: school = SPELL_SCHOOL_FIRE; break;
9557 case UNIT_MOD_RESISTANCE_NATURE: school = SPELL_SCHOOL_NATURE; break;
9558 case UNIT_MOD_RESISTANCE_FROST: school = SPELL_SCHOOL_FROST; break;
9559 case UNIT_MOD_RESISTANCE_SHADOW: school = SPELL_SCHOOL_SHADOW; break;
9560 case UNIT_MOD_RESISTANCE_ARCANE: school = SPELL_SCHOOL_ARCANE; break;
9562 default:
9563 break;
9566 return school;
9569 Stats Unit::GetStatByAuraGroup(UnitMods unitMod) const
9571 Stats stat = STAT_STRENGTH;
9573 switch(unitMod)
9575 case UNIT_MOD_STAT_STRENGTH: stat = STAT_STRENGTH; break;
9576 case UNIT_MOD_STAT_AGILITY: stat = STAT_AGILITY; break;
9577 case UNIT_MOD_STAT_STAMINA: stat = STAT_STAMINA; break;
9578 case UNIT_MOD_STAT_INTELLECT: stat = STAT_INTELLECT; break;
9579 case UNIT_MOD_STAT_SPIRIT: stat = STAT_SPIRIT; break;
9581 default:
9582 break;
9585 return stat;
9588 Powers Unit::GetPowerTypeByAuraGroup(UnitMods unitMod) const
9590 Powers power = POWER_MANA;
9592 switch(unitMod)
9594 case UNIT_MOD_MANA: power = POWER_MANA; break;
9595 case UNIT_MOD_RAGE: power = POWER_RAGE; break;
9596 case UNIT_MOD_FOCUS: power = POWER_FOCUS; break;
9597 case UNIT_MOD_ENERGY: power = POWER_ENERGY; break;
9598 case UNIT_MOD_HAPPINESS: power = POWER_HAPPINESS; break;
9600 default:
9601 break;
9604 return power;
9607 float Unit::GetTotalAttackPowerValue(WeaponAttackType attType) const
9609 UnitMods unitMod = (attType == RANGED_ATTACK) ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER;
9611 float val = GetTotalAuraModValue(unitMod);
9612 if(val < 0.0f)
9613 val = 0.0f;
9615 return val;
9618 float Unit::GetWeaponDamageRange(WeaponAttackType attType ,WeaponDamageRange type) const
9620 if (attType == OFF_ATTACK && !haveOffhandWeapon())
9621 return 0.0f;
9623 return m_weaponDamage[attType][type];
9626 void Unit::SetLevel(uint32 lvl)
9628 SetUInt32Value(UNIT_FIELD_LEVEL, lvl);
9630 // group update
9631 if ((GetTypeId() == TYPEID_PLAYER) && ((Player*)this)->GetGroup())
9632 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL);
9635 void Unit::SetHealth(uint32 val)
9637 uint32 maxHealth = GetMaxHealth();
9638 if(maxHealth < val)
9639 val = maxHealth;
9641 SetUInt32Value(UNIT_FIELD_HEALTH, val);
9643 // group update
9644 if(GetTypeId() == TYPEID_PLAYER)
9646 if(((Player*)this)->GetGroup())
9647 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP);
9649 else if(((Creature*)this)->isPet())
9651 Pet *pet = ((Pet*)this);
9652 if(pet->isControlled())
9654 Unit *owner = GetOwner();
9655 if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
9656 ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP);
9661 void Unit::SetMaxHealth(uint32 val)
9663 uint32 health = GetHealth();
9664 SetUInt32Value(UNIT_FIELD_MAXHEALTH, val);
9666 // group update
9667 if(GetTypeId() == TYPEID_PLAYER)
9669 if(((Player*)this)->GetGroup())
9670 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP);
9672 else if(((Creature*)this)->isPet())
9674 Pet *pet = ((Pet*)this);
9675 if(pet->isControlled())
9677 Unit *owner = GetOwner();
9678 if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
9679 ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP);
9683 if(val < health)
9684 SetHealth(val);
9687 void Unit::SetPower(Powers power, uint32 val)
9689 if(GetPower(power) == val)
9690 return;
9692 uint32 maxPower = GetMaxPower(power);
9693 if(maxPower < val)
9694 val = maxPower;
9696 SetStatInt32Value(UNIT_FIELD_POWER1 + power, val);
9698 // group update
9699 if(GetTypeId() == TYPEID_PLAYER)
9701 if(((Player*)this)->GetGroup())
9702 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER);
9704 else if(((Creature*)this)->isPet())
9706 Pet *pet = ((Pet*)this);
9707 if(pet->isControlled())
9709 Unit *owner = GetOwner();
9710 if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
9711 ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER);
9714 // Update the pet's character sheet with happiness damage bonus
9715 if(pet->getPetType() == HUNTER_PET && power == POWER_HAPPINESS)
9717 pet->UpdateDamagePhysical(BASE_ATTACK);
9722 void Unit::SetMaxPower(Powers power, uint32 val)
9724 uint32 cur_power = GetPower(power);
9725 SetStatInt32Value(UNIT_FIELD_MAXPOWER1 + power, val);
9727 // group update
9728 if(GetTypeId() == TYPEID_PLAYER)
9730 if(((Player*)this)->GetGroup())
9731 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER);
9733 else if(((Creature*)this)->isPet())
9735 Pet *pet = ((Pet*)this);
9736 if(pet->isControlled())
9738 Unit *owner = GetOwner();
9739 if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
9740 ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER);
9744 if(val < cur_power)
9745 SetPower(power, val);
9748 void Unit::ApplyPowerMod(Powers power, uint32 val, bool apply)
9750 ApplyModUInt32Value(UNIT_FIELD_POWER1+power, val, apply);
9752 // group update
9753 if(GetTypeId() == TYPEID_PLAYER)
9755 if(((Player*)this)->GetGroup())
9756 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER);
9758 else if(((Creature*)this)->isPet())
9760 Pet *pet = ((Pet*)this);
9761 if(pet->isControlled())
9763 Unit *owner = GetOwner();
9764 if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
9765 ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER);
9770 void Unit::ApplyMaxPowerMod(Powers power, uint32 val, bool apply)
9772 ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1+power, val, apply);
9774 // group update
9775 if(GetTypeId() == TYPEID_PLAYER)
9777 if(((Player*)this)->GetGroup())
9778 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER);
9780 else if(((Creature*)this)->isPet())
9782 Pet *pet = ((Pet*)this);
9783 if(pet->isControlled())
9785 Unit *owner = GetOwner();
9786 if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
9787 ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER);
9792 void Unit::ApplyAuraProcTriggerDamage( Aura* aura, bool apply )
9794 AuraList& tAuraProcTriggerDamage = m_modAuras[SPELL_AURA_PROC_TRIGGER_DAMAGE];
9795 if(apply)
9796 tAuraProcTriggerDamage.push_back(aura);
9797 else
9798 tAuraProcTriggerDamage.remove(aura);
9801 uint32 Unit::GetCreatePowers( Powers power ) const
9803 // POWER_FOCUS and POWER_HAPPINESS only have hunter pet
9804 switch(power)
9806 case POWER_MANA: return GetCreateMana();
9807 case POWER_RAGE: return 1000;
9808 case POWER_FOCUS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 100);
9809 case POWER_ENERGY: return 100;
9810 case POWER_HAPPINESS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 1050000);
9813 return 0;
9816 void Unit::AddToWorld()
9818 Object::AddToWorld();
9821 void Unit::RemoveFromWorld()
9823 // cleanup
9824 if(IsInWorld())
9826 RemoveNotOwnSingleTargetAuras();
9829 Object::RemoveFromWorld();
9832 void Unit::CleanupsBeforeDelete()
9834 if(m_uint32Values) // only for fully created object
9836 InterruptNonMeleeSpells(true);
9837 m_Events.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList
9838 CombatStop();
9839 ClearComboPointHolders();
9840 DeleteThreatList();
9841 getHostilRefManager().setOnlineOfflineState(false);
9842 RemoveAllAuras();
9843 RemoveAllGameObjects();
9844 RemoveAllDynObjects();
9845 GetMotionMaster()->Clear(false); // remove different non-standard movement generators.
9847 RemoveFromWorld();
9850 CharmInfo* Unit::InitCharmInfo(Unit *charm)
9852 if(!m_charmInfo)
9853 m_charmInfo = new CharmInfo(charm);
9854 return m_charmInfo;
9857 CharmInfo::CharmInfo(Unit* unit)
9858 : m_unit(unit), m_CommandState(COMMAND_FOLLOW), m_reactState(REACT_PASSIVE), m_petnumber(0)
9860 for(int i =0; i<4; ++i)
9862 m_charmspells[i].spellId = 0;
9863 m_charmspells[i].active = ACT_DISABLED;
9867 void CharmInfo::InitPetActionBar()
9869 // the first 3 SpellOrActions are attack, follow and stay
9870 for(uint32 i = 0; i < 3; i++)
9872 PetActionBar[i].Type = ACT_COMMAND;
9873 PetActionBar[i].SpellOrAction = COMMAND_ATTACK - i;
9875 PetActionBar[i + 7].Type = ACT_REACTION;
9876 PetActionBar[i + 7].SpellOrAction = COMMAND_ATTACK - i;
9878 for(uint32 i=0; i < 4; i++)
9880 PetActionBar[i + 3].Type = ACT_DISABLED;
9881 PetActionBar[i + 3].SpellOrAction = 0;
9885 void CharmInfo::InitEmptyActionBar()
9887 for(uint32 x = 1; x < 10; ++x)
9889 PetActionBar[x].Type = ACT_CAST;
9890 PetActionBar[x].SpellOrAction = 0;
9892 PetActionBar[0].Type = ACT_COMMAND;
9893 PetActionBar[0].SpellOrAction = COMMAND_ATTACK;
9896 void CharmInfo::InitPossessCreateSpells()
9898 if(m_unit->GetTypeId() == TYPEID_PLAYER)
9899 return;
9901 InitEmptyActionBar(); //charm action bar
9903 for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x)
9905 if (IsPassiveSpell(((Creature*)m_unit)->m_spells[x]))
9906 m_unit->CastSpell(m_unit, ((Creature*)m_unit)->m_spells[x], true);
9907 else
9908 AddSpellToAB(0, ((Creature*)m_unit)->m_spells[x], ACT_CAST);
9912 void CharmInfo::InitCharmCreateSpells()
9914 if(m_unit->GetTypeId() == TYPEID_PLAYER) //charmed players don't have spells
9916 InitEmptyActionBar();
9917 return;
9920 InitPetActionBar();
9922 for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x)
9924 uint32 spellId = ((Creature*)m_unit)->m_spells[x];
9925 m_charmspells[x].spellId = spellId;
9927 if(!spellId)
9928 continue;
9930 if (IsPassiveSpell(spellId))
9932 m_unit->CastSpell(m_unit, spellId, true);
9933 m_charmspells[x].active = ACT_PASSIVE;
9935 else
9937 ActiveStates newstate;
9938 bool onlyselfcast = true;
9939 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
9941 if(!spellInfo) onlyselfcast = false;
9942 for(uint32 i = 0;i<3 && onlyselfcast;++i) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
9944 if(spellInfo->EffectImplicitTargetA[i] != TARGET_SELF && spellInfo->EffectImplicitTargetA[i] != 0)
9945 onlyselfcast = false;
9948 if(onlyselfcast || !IsPositiveSpell(spellId)) //only self cast and spells versus enemies are autocastable
9949 newstate = ACT_DISABLED;
9950 else
9951 newstate = ACT_CAST;
9953 AddSpellToAB(0, spellId, newstate);
9958 bool CharmInfo::AddSpellToAB(uint32 oldid, uint32 newid, ActiveStates newstate)
9960 for(uint8 i = 0; i < 10; i++)
9962 if((PetActionBar[i].Type == ACT_DISABLED || PetActionBar[i].Type == ACT_ENABLED || PetActionBar[i].Type == ACT_CAST) && PetActionBar[i].SpellOrAction == oldid)
9964 PetActionBar[i].SpellOrAction = newid;
9965 if(!oldid)
9967 if(newstate == ACT_DECIDE)
9968 PetActionBar[i].Type = ACT_DISABLED;
9969 else
9970 PetActionBar[i].Type = newstate;
9973 return true;
9976 return false;
9979 void CharmInfo::ToggleCreatureAutocast(uint32 spellid, bool apply)
9981 if(IsPassiveSpell(spellid))
9982 return;
9984 for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x)
9986 if(spellid == m_charmspells[x].spellId)
9988 m_charmspells[x].active = apply ? ACT_ENABLED : ACT_DISABLED;
9993 void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow)
9995 m_petnumber = petnumber;
9996 if(statwindow)
9997 m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, m_petnumber);
9998 else
9999 m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, 0);
10002 bool Unit::isFrozen() const
10004 AuraList const& mRoot = GetAurasByType(SPELL_AURA_MOD_ROOT);
10005 for(AuraList::const_iterator i = mRoot.begin(); i != mRoot.end(); ++i)
10006 if( GetSpellSchoolMask((*i)->GetSpellProto()) & SPELL_SCHOOL_MASK_FROST)
10007 return true;
10008 return false;
10011 struct ProcTriggeredData
10013 ProcTriggeredData(Aura* _triggeredByAura, uint32 _cooldown)
10014 : triggeredByAura(_triggeredByAura),
10015 triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura->GetId(),triggeredByAura->GetEffIndex())),
10016 cooldown(_cooldown)
10019 Aura* triggeredByAura; // triggred aura, can be invalidate at triggered aura proccessing
10020 Unit::spellEffectPair triggeredByAura_SpellPair; // spell pair, used for re-find aura (by pointer comparison in range)
10021 uint32 cooldown; // possible hidden cooldown
10024 typedef std::list< ProcTriggeredData > ProcTriggeredList;
10026 void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, AuraTypeSet const& procAuraTypes, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage, SpellSchoolMask damageSchoolMask )
10028 for(AuraTypeSet::const_iterator aur = procAuraTypes.begin(); aur != procAuraTypes.end(); ++aur)
10030 // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
10031 ProcTriggeredList procTriggered;
10033 AuraList const& auras = GetAurasByType(*aur);
10034 for(AuraList::const_iterator i = auras.begin(), next; i != auras.end(); i = next)
10036 next = i; ++next;
10038 Aura* i_aura = *i;
10040 uint32 cooldown; // returned at next line
10041 if(!IsTriggeredAtSpellProcEvent(i_aura->GetSpellProto(), procSpell, procFlag,attType,isVictim,cooldown))
10042 continue;
10044 procTriggered.push_back( ProcTriggeredData(i_aura, cooldown) );
10047 // Handle effects proceed this time
10048 for(ProcTriggeredList::iterator i = procTriggered.begin(); i != procTriggered.end(); ++i)
10050 // Some auras can be deleted in function called in this loop (except first, ofc)
10051 // Until storing auras in std::multimap to hard check deleting by another way
10052 if(i != procTriggered.begin())
10054 bool found = false;
10055 AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair);
10056 AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair);
10057 for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr)
10059 if(itr->second==i->triggeredByAura)
10061 found = true;
10062 break;
10066 if(!found)
10068 sLog.outError("Spell aura %u (id:%u effect:%u) has been deleted before call spell proc event handler",*aur,i->triggeredByAura_SpellPair.first,i->triggeredByAura_SpellPair.second);
10069 sLog.outError("It can be deleted one from early processed auras:");
10070 for(ProcTriggeredList::iterator i2 = procTriggered.begin(); i != i2; ++i2)
10071 sLog.outError(" Spell aura %u (id:%u effect:%u)",*aur,i2->triggeredByAura_SpellPair.first,i2->triggeredByAura_SpellPair.second);
10072 sLog.outError(" <end of list>");
10073 continue;
10077 /// this is aura triggering code call
10078 Aura* triggeredByAura = i->triggeredByAura;
10080 /// save charges existence before processing to prevent crash at access to deleted triggered aura after
10081 /// used in speedup code check before check aura existance.
10082 bool triggeredByAuraWithCharges = triggeredByAura->m_procCharges > 0;
10084 /// success in event proccesing
10085 /// used in speedup code check before check aura existance.
10086 bool casted = false;
10088 /// process triggered code
10089 switch(*aur)
10091 case SPELL_AURA_PROC_TRIGGER_SPELL:
10093 sLog.outDebug("ProcDamageAndSpell: casting spell (triggered by %s proc aura of spell %u)",
10094 (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
10095 casted = HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, attType, i->cooldown);
10096 break;
10098 case SPELL_AURA_PROC_TRIGGER_DAMAGE:
10100 uint32 triggered_damage = triggeredByAura->GetModifier()->m_amount;
10101 sLog.outDebug("ProcDamageAndSpell: doing %u damage (triggered by %s aura of spell %u)",
10102 triggered_damage, (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
10103 SpellNonMeleeDamageLog(pTarget, triggeredByAura->GetId(), triggered_damage, true, true);
10104 casted = true;
10105 break;
10107 case SPELL_AURA_DUMMY:
10109 uint32 effect = triggeredByAura->GetEffIndex();
10110 sLog.outDebug("ProcDamageAndSpell: casting spell (triggered by %s dummy aura of spell %u)",
10111 (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
10112 casted = HandleDummyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag,i->cooldown);
10113 break;
10115 case SPELL_AURA_PRAYER_OF_MENDING:
10117 sLog.outDebug("ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
10118 (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
10120 casted = HandleMeandingAuraProc(triggeredByAura);
10121 break;
10123 case SPELL_AURA_MOD_HASTE:
10125 sLog.outDebug("ProcDamageAndSpell: casting spell (triggered by %s haste aura of spell %u)",
10126 (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
10127 casted = HandleHasteAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag,i->cooldown);
10128 break;
10130 case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN:
10132 // nothing do, just charges counter
10133 // but count only in case appropriate school damage
10134 casted = triggeredByAura->GetModifier()->m_miscvalue & damageSchoolMask;
10135 break;
10137 case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS:
10139 sLog.outDebug("ProcDamageAndSpell: casting spell (triggered by %s class script aura of spell %u)",
10140 (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
10141 casted = HandleOverrideClassScriptAuraProc(pTarget, triggeredByAura, procSpell,i->cooldown);
10142 break;
10144 default:
10146 // nothing do, just charges counter
10147 casted = true;
10148 break;
10152 /// Update charge (aura can be removed by triggers)
10153 if(casted && triggeredByAuraWithCharges)
10155 /// need re-found aura (can be dropped by triggers)
10156 AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair);
10157 AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair);
10158 for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr)
10160 if(itr->second == triggeredByAura) // pointer still valid
10162 if(triggeredByAura->m_procCharges > 0)
10163 triggeredByAura->m_procCharges -= 1;
10165 triggeredByAura->UpdateAuraCharges();
10166 break;
10172 /// Safely remove auras with zero charges
10173 for(AuraList::const_iterator i = auras.begin(), next; i != auras.end(); i = next)
10175 next = i; ++next;
10176 if((*i)->m_procCharges == 0)
10178 RemoveAurasDueToSpell((*i)->GetId());
10179 next = auras.begin();
10185 SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const
10187 return SPELL_SCHOOL_MASK_NORMAL;
10190 Player* Unit::GetSpellModOwner()
10192 if(GetTypeId()==TYPEID_PLAYER)
10193 return (Player*)this;
10194 if(((Creature*)this)->isPet() || ((Creature*)this)->isTotem())
10196 Unit* owner = GetOwner();
10197 if(owner && owner->GetTypeId()==TYPEID_PLAYER)
10198 return (Player*)owner;
10200 return NULL;
10203 ///----------Pet responses methods-----------------
10204 void Unit::SendPetCastFail(uint32 spellid, uint8 msg)
10206 Unit *owner = GetCharmerOrOwner();
10207 if(!owner || owner->GetTypeId() != TYPEID_PLAYER)
10208 return;
10210 WorldPacket data(SMSG_PET_CAST_FAILED, (4+1));
10211 data << uint32(spellid);
10212 data << uint8(msg);
10213 ((Player*)owner)->GetSession()->SendPacket(&data);
10216 void Unit::SendPetActionFeedback (uint8 msg)
10218 Unit* owner = GetOwner();
10219 if(!owner || owner->GetTypeId() != TYPEID_PLAYER)
10220 return;
10222 WorldPacket data(SMSG_PET_ACTION_FEEDBACK, 1);
10223 data << uint8(msg);
10224 ((Player*)owner)->GetSession()->SendPacket(&data);
10227 void Unit::SendPetTalk (uint32 pettalk)
10229 Unit* owner = GetOwner();
10230 if(!owner || owner->GetTypeId() != TYPEID_PLAYER)
10231 return;
10233 WorldPacket data(SMSG_PET_ACTION_SOUND, 8+4);
10234 data << uint64(GetGUID());
10235 data << uint32(pettalk);
10236 ((Player*)owner)->GetSession()->SendPacket(&data);
10239 void Unit::SendPetSpellCooldown (uint32 spellid, time_t cooltime)
10241 Unit* owner = GetOwner();
10242 if(!owner || owner->GetTypeId() != TYPEID_PLAYER)
10243 return;
10245 WorldPacket data(SMSG_SPELL_COOLDOWN, 8+1+4+4);
10246 data << uint64(GetGUID());
10247 data << uint8(0x0); // flags (0x1, 0x2)
10248 data << uint32(spellid);
10249 data << uint32(cooltime);
10251 ((Player*)owner)->GetSession()->SendPacket(&data);
10254 void Unit::SendPetClearCooldown (uint32 spellid)
10256 Unit* owner = GetOwner();
10257 if(!owner || owner->GetTypeId() != TYPEID_PLAYER)
10258 return;
10260 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
10261 data << uint32(spellid);
10262 data << uint64(GetGUID());
10263 ((Player*)owner)->GetSession()->SendPacket(&data);
10266 void Unit::SendPetAIReaction(uint64 guid)
10268 Unit* owner = GetOwner();
10269 if(!owner || owner->GetTypeId() != TYPEID_PLAYER)
10270 return;
10272 WorldPacket data(SMSG_AI_REACTION, 12);
10273 data << uint64(guid) << uint32(00000002);
10274 ((Player*)owner)->GetSession()->SendPacket(&data);
10277 ///----------End of Pet responses methods----------
10279 void Unit::StopMoving()
10281 clearUnitState(UNIT_STAT_MOVING);
10283 // send explicit stop packet
10284 // rely on vmaps here because for example stormwind is in air
10285 //float z = MapManager::Instance().GetBaseMap(GetMapId())->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true);
10286 //if (fabs(GetPositionZ() - z) < 2.0f)
10287 // Relocate(GetPositionX(), GetPositionY(), z);
10288 Relocate(GetPositionX(), GetPositionY(),GetPositionZ());
10290 SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), 0, true, 0);
10292 // update position and orientation;
10293 WorldPacket data;
10294 BuildHeartBeatMsg(&data);
10295 SendMessageToSet(&data,false);
10298 void Unit::SetFeared(bool apply, uint64 casterGUID, uint32 spellID)
10300 if( apply )
10302 if(HasAuraType(SPELL_AURA_PREVENTS_FLEEING))
10303 return;
10305 SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
10307 GetMotionMaster()->MovementExpired(false);
10308 CastStop(GetGUID()==casterGUID ? spellID : 0);
10310 Unit* caster = ObjectAccessor::GetUnit(*this,casterGUID);
10312 GetMotionMaster()->MoveFleeing(caster); // caster==NULL processed in MoveFleeing
10314 else
10316 RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
10318 GetMotionMaster()->MovementExpired(false);
10320 if( GetTypeId() != TYPEID_PLAYER && isAlive() )
10322 // restore appropriate movement generator
10323 if(getVictim())
10324 GetMotionMaster()->MoveChase(getVictim());
10325 else
10326 GetMotionMaster()->Initialize();
10328 // attack caster if can
10329 Unit* caster = ObjectAccessor::GetObjectInWorld(casterGUID, (Unit*)NULL);
10330 if(caster && caster != getVictim() && ((Creature*)this)->AI())
10331 ((Creature*)this)->AI()->AttackStart(caster);
10335 if (GetTypeId() == TYPEID_PLAYER)
10336 ((Player*)this)->SetClientControl(this, !apply);
10339 void Unit::SetConfused(bool apply, uint64 casterGUID, uint32 spellID)
10341 if( apply )
10343 SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
10345 CastStop(GetGUID()==casterGUID ? spellID : 0);
10347 GetMotionMaster()->MoveConfused();
10349 else
10351 RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
10353 GetMotionMaster()->MovementExpired(false);
10355 if (GetTypeId() == TYPEID_UNIT)
10357 // if in combat restore movement generator
10358 if(getVictim())
10359 GetMotionMaster()->MoveChase(getVictim());
10363 if(GetTypeId() == TYPEID_PLAYER)
10364 ((Player*)this)->SetClientControl(this, !apply);
10367 bool Unit::IsSitState() const
10369 uint8 s = getStandState();
10370 return s == PLAYER_STATE_SIT_CHAIR || s == PLAYER_STATE_SIT_LOW_CHAIR ||
10371 s == PLAYER_STATE_SIT_MEDIUM_CHAIR || s == PLAYER_STATE_SIT_HIGH_CHAIR ||
10372 s == PLAYER_STATE_SIT;
10375 bool Unit::IsStandState() const
10377 uint8 s = getStandState();
10378 return !IsSitState() && s != PLAYER_STATE_SLEEP && s != PLAYER_STATE_KNEEL;
10381 void Unit::SetStandState(uint8 state)
10383 SetByteValue(UNIT_FIELD_BYTES_1, 0, state);
10385 if (IsStandState())
10386 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_SEATED);
10388 if(GetTypeId()==TYPEID_PLAYER)
10390 WorldPacket data(SMSG_STANDSTATE_UPDATE, 1);
10391 data << (uint8)state;
10392 ((Player*)this)->GetSession()->SendPacket(&data);
10396 bool Unit::IsPolymorphed() const
10398 return GetSpellSpecific(getTransForm())==SPELL_MAGE_POLYMORPH;
10401 void Unit::SetDisplayId(uint32 modelId)
10403 SetUInt32Value(UNIT_FIELD_DISPLAYID, modelId);
10405 if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
10407 Pet *pet = ((Pet*)this);
10408 if(!pet->isControlled())
10409 return;
10410 Unit *owner = GetOwner();
10411 if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
10412 ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID);
10416 void Unit::ClearComboPointHolders()
10418 while(!m_ComboPointHolders.empty())
10420 uint32 lowguid = *m_ComboPointHolders.begin();
10422 Player* plr = objmgr.GetPlayer(MAKE_NEW_GUID(lowguid, 0, HIGHGUID_PLAYER));
10423 if(plr && plr->GetComboTarget()==GetGUID()) // recheck for safe
10424 plr->ClearComboPoints(); // remove also guid from m_ComboPointHolders;
10425 else
10426 m_ComboPointHolders.erase(lowguid); // or remove manually
10430 void Unit::ClearAllReactives()
10433 for(int i=0; i < MAX_REACTIVE; ++i)
10434 m_reactiveTimer[i] = 0;
10436 if (HasAuraState( AURA_STATE_DEFENSE))
10437 ModifyAuraState(AURA_STATE_DEFENSE, false);
10438 if (getClass() == CLASS_HUNTER && HasAuraState( AURA_STATE_HUNTER_PARRY))
10439 ModifyAuraState(AURA_STATE_HUNTER_PARRY, false);
10440 if (HasAuraState( AURA_STATE_CRIT))
10441 ModifyAuraState(AURA_STATE_CRIT, false);
10442 if (getClass() == CLASS_HUNTER && HasAuraState( AURA_STATE_HUNTER_CRIT_STRIKE) )
10443 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, false);
10445 if(getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER)
10446 ((Player*)this)->ClearComboPoints();
10449 void Unit::UpdateReactives( uint32 p_time )
10451 for(int i = 0; i < MAX_REACTIVE; ++i)
10453 ReactiveType reactive = ReactiveType(i);
10455 if(!m_reactiveTimer[reactive])
10456 continue;
10458 if ( m_reactiveTimer[reactive] <= p_time)
10460 m_reactiveTimer[reactive] = 0;
10462 switch ( reactive )
10464 case REACTIVE_DEFENSE:
10465 if (HasAuraState(AURA_STATE_DEFENSE))
10466 ModifyAuraState(AURA_STATE_DEFENSE, false);
10467 break;
10468 case REACTIVE_HUNTER_PARRY:
10469 if ( getClass() == CLASS_HUNTER && HasAuraState(AURA_STATE_HUNTER_PARRY))
10470 ModifyAuraState(AURA_STATE_HUNTER_PARRY, false);
10471 break;
10472 case REACTIVE_CRIT:
10473 if (HasAuraState(AURA_STATE_CRIT))
10474 ModifyAuraState(AURA_STATE_CRIT, false);
10475 break;
10476 case REACTIVE_HUNTER_CRIT:
10477 if ( getClass() == CLASS_HUNTER && HasAuraState(AURA_STATE_HUNTER_CRIT_STRIKE) )
10478 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, false);
10479 break;
10480 case REACTIVE_OVERPOWER:
10481 if(getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER)
10482 ((Player*)this)->ClearComboPoints();
10483 break;
10484 default:
10485 break;
10488 else
10490 m_reactiveTimer[reactive] -= p_time;
10495 Unit* Unit::SelectNearbyTarget() const
10497 CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
10498 Cell cell(p);
10499 cell.data.Part.reserved = ALL_DISTRICT;
10500 cell.SetNoCreate();
10502 std::list<Unit *> targets;
10505 MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, this, ATTACK_DISTANCE);
10506 MaNGOS::UnitListSearcher<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck> searcher(targets, u_check);
10508 TypeContainerVisitor<MaNGOS::UnitListSearcher<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher);
10509 TypeContainerVisitor<MaNGOS::UnitListSearcher<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher);
10511 CellLock<GridReadGuard> cell_lock(cell, p);
10512 cell_lock->Visit(cell_lock, world_unit_searcher, *GetMap());
10513 cell_lock->Visit(cell_lock, grid_unit_searcher, *GetMap());
10516 // remove current target
10517 if(getVictim())
10518 targets.remove(getVictim());
10520 // remove not LoS targets
10521 for(std::list<Unit *>::iterator tIter = targets.begin(); tIter != targets.end();)
10523 if(!IsWithinLOSInMap(*tIter))
10525 std::list<Unit *>::iterator tIter2 = tIter;
10526 ++tIter;
10527 targets.erase(tIter2);
10529 else
10530 ++tIter;
10533 // no appropriate targets
10534 if(targets.empty())
10535 return NULL;
10537 // select random
10538 uint32 rIdx = urand(0,targets.size()-1);
10539 std::list<Unit *>::const_iterator tcIter = targets.begin();
10540 for(uint32 i = 0; i < rIdx; ++i)
10541 ++tcIter;
10543 return *tcIter;
10546 void Unit::ApplyAttackTimePercentMod( WeaponAttackType att,float val, bool apply )
10548 if(val > 0)
10550 ApplyPercentModFloatVar(m_modAttackSpeedPct[att], val, !apply);
10551 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME+att,val,!apply);
10553 else
10555 ApplyPercentModFloatVar(m_modAttackSpeedPct[att], -val, apply);
10556 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME+att,-val,apply);
10560 void Unit::ApplyCastTimePercentMod(float val, bool apply )
10562 if(val > 0)
10563 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED,val,!apply);
10564 else
10565 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED,-val,apply);
10568 uint32 Unit::GetCastingTimeForBonus( SpellEntry const *spellProto, DamageEffectType damagetype, uint32 CastingTime )
10570 // Not apply this to creature casted spells with casttime==0
10571 if(CastingTime==0 && GetTypeId()==TYPEID_UNIT && !((Creature*)this)->isPet())
10572 return 3500;
10574 if (CastingTime > 7000) CastingTime = 7000;
10575 if (CastingTime < 1500) CastingTime = 1500;
10577 if(damagetype == DOT && !IsChanneledSpell(spellProto))
10578 CastingTime = 3500;
10580 int32 overTime = 0;
10581 uint8 effects = 0;
10582 bool DirectDamage = false;
10583 bool AreaEffect = false;
10585 for ( uint32 i=0; i<3;i++)
10587 switch ( spellProto->Effect[i] )
10589 case SPELL_EFFECT_SCHOOL_DAMAGE:
10590 case SPELL_EFFECT_POWER_DRAIN:
10591 case SPELL_EFFECT_HEALTH_LEECH:
10592 case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE:
10593 case SPELL_EFFECT_POWER_BURN:
10594 case SPELL_EFFECT_HEAL:
10595 DirectDamage = true;
10596 break;
10597 case SPELL_EFFECT_APPLY_AURA:
10598 switch ( spellProto->EffectApplyAuraName[i] )
10600 case SPELL_AURA_PERIODIC_DAMAGE:
10601 case SPELL_AURA_PERIODIC_HEAL:
10602 case SPELL_AURA_PERIODIC_LEECH:
10603 if ( GetSpellDuration(spellProto) )
10604 overTime = GetSpellDuration(spellProto);
10605 break;
10606 default:
10607 // -5% per additional effect
10608 ++effects;
10609 break;
10611 default:
10612 break;
10615 if(IsAreaEffectTarget(Targets(spellProto->EffectImplicitTargetA[i])) || IsAreaEffectTarget(Targets(spellProto->EffectImplicitTargetB[i])))
10616 AreaEffect = true;
10619 // Combined Spells with Both Over Time and Direct Damage
10620 if ( overTime > 0 && CastingTime > 0 && DirectDamage )
10622 // mainly for DoTs which are 3500 here otherwise
10623 uint32 OriginalCastTime = GetSpellCastTime(spellProto);
10624 if (OriginalCastTime > 7000) OriginalCastTime = 7000;
10625 if (OriginalCastTime < 1500) OriginalCastTime = 1500;
10626 // Portion to Over Time
10627 float PtOT = (overTime / 15000.f) / ((overTime / 15000.f) + (OriginalCastTime / 3500.f));
10629 if ( damagetype == DOT )
10630 CastingTime = uint32(CastingTime * PtOT);
10631 else if ( PtOT < 1.0f )
10632 CastingTime = uint32(CastingTime * (1 - PtOT));
10633 else
10634 CastingTime = 0;
10637 // Area Effect Spells receive only half of bonus
10638 if ( AreaEffect )
10639 CastingTime /= 2;
10641 // -5% of total per any additional effect
10642 for ( uint8 i=0; i<effects; ++i)
10644 if ( CastingTime > 175 )
10646 CastingTime -= 175;
10648 else
10650 CastingTime = 0;
10651 break;
10655 return CastingTime;
10658 void Unit::UpdateAuraForGroup(uint8 slot)
10660 if(GetTypeId() == TYPEID_PLAYER)
10662 Player* player = (Player*)this;
10663 if(player->GetGroup())
10665 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS);
10666 player->SetAuraUpdateMask(slot);
10669 else if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
10671 Pet *pet = ((Pet*)this);
10672 if(pet->isControlled())
10674 Unit *owner = GetOwner();
10675 if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
10677 ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS);
10678 pet->SetAuraUpdateMask(slot);
10684 float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized)
10686 if (!normalized || GetTypeId() != TYPEID_PLAYER)
10687 return float(GetAttackTime(attType))/1000.0f;
10689 Item *Weapon = ((Player*)this)->GetWeaponForAttack(attType);
10690 if (!Weapon)
10691 return 2.4; // fist attack
10693 switch (Weapon->GetProto()->InventoryType)
10695 case INVTYPE_2HWEAPON:
10696 return 3.3;
10697 case INVTYPE_RANGED:
10698 case INVTYPE_RANGEDRIGHT:
10699 case INVTYPE_THROWN:
10700 return 2.8;
10701 case INVTYPE_WEAPON:
10702 case INVTYPE_WEAPONMAINHAND:
10703 case INVTYPE_WEAPONOFFHAND:
10704 default:
10705 return Weapon->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_DAGGER ? 1.7 : 2.4;
10709 Aura* Unit::GetDummyAura( uint32 spell_id ) const
10711 Unit::AuraList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY);
10712 for(Unit::AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
10713 if ((*itr)->GetId() == spell_id)
10714 return *itr;
10716 return NULL;
10719 bool Unit::IsUnderLastManaUseEffect() const
10721 return getMSTimeDiff(m_lastManaUse,getMSTime()) < 5000;
10724 void Unit::SetContestedPvP(Player *attackedPlayer)
10726 Player* player = GetCharmerOrOwnerPlayerOrPlayerItself();
10728 if(!player || attackedPlayer && (attackedPlayer == player || player->duel && player->duel->opponent == attackedPlayer))
10729 return;
10731 player->SetContestedPvPTimer(30000);
10732 if(!player->hasUnitState(UNIT_STAT_ATTACK_PLAYER))
10734 player->addUnitState(UNIT_STAT_ATTACK_PLAYER);
10735 player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP);
10736 // call MoveInLineOfSight for nearby contested guards
10737 SetVisibility(GetVisibility());
10739 if(!hasUnitState(UNIT_STAT_ATTACK_PLAYER))
10741 addUnitState(UNIT_STAT_ATTACK_PLAYER);
10742 // call MoveInLineOfSight for nearby contested guards
10743 SetVisibility(GetVisibility());
10747 void Unit::AddPetAura(PetAura const* petSpell)
10749 m_petAuras.insert(petSpell);
10750 if(Pet* pet = GetPet())
10751 pet->CastPetAura(petSpell);
10754 void Unit::RemovePetAura(PetAura const* petSpell)
10756 m_petAuras.erase(petSpell);
10757 if(Pet* pet = GetPet())
10758 pet->RemoveAurasDueToSpell(petSpell->GetAura(pet->GetEntry()));
10761 Pet* Unit::CreateTamedPetFrom(Creature* creatureTarget,uint32 spell_id)
10763 Pet* pet = new Pet(HUNTER_PET);
10765 if(!pet->CreateBaseAtCreature(creatureTarget))
10767 delete pet;
10768 return NULL;
10771 pet->SetOwnerGUID(GetGUID());
10772 pet->SetCreatorGUID(GetGUID());
10773 pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, getFaction());
10774 pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, spell_id);
10776 if(!pet->InitStatsForLevel(creatureTarget->getLevel()))
10778 sLog.outError("ERROR: Pet::InitStatsForLevel() failed for creature (Entry: %u)!",creatureTarget->GetEntry());
10779 delete pet;
10780 return NULL;
10783 pet->GetCharmInfo()->SetPetNumber(objmgr.GeneratePetNumber(), true);
10784 // this enables pet details window (Shift+P)
10785 pet->AIM_Initialize();
10786 pet->InitPetCreateSpells();
10787 pet->SetHealth(pet->GetMaxHealth());
10789 return pet;
10792 bool Unit::IsTriggeredAtSpellProcEvent(SpellEntry const* spellProto, SpellEntry const* procSpell, uint32 procFlag, WeaponAttackType attType, bool isVictim, uint32& cooldown )
10794 SpellProcEventEntry const * spellProcEvent = spellmgr.GetSpellProcEvent(spellProto->Id);
10796 if(!spellProcEvent)
10798 // used to prevent spam in log about same non-handled spells
10799 static std::set<uint32> nonHandledSpellProcSet;
10801 if(spellProto->procFlags != 0 && nonHandledSpellProcSet.find(spellProto->Id)==nonHandledSpellProcSet.end())
10803 sLog.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto->Id,(isVictim?"a victim's":"an attacker's"));
10804 nonHandledSpellProcSet.insert(spellProto->Id);
10807 // spell.dbc use totally different flags, that only can create problems if used.
10808 return false;
10811 // Check spellProcEvent data requirements
10812 if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent, procSpell,procFlag))
10813 return false;
10815 // Check if current equipment allows aura to proc
10816 if(!isVictim && GetTypeId() == TYPEID_PLAYER )
10818 if(spellProto->EquippedItemClass == ITEM_CLASS_WEAPON)
10820 Item *item = ((Player*)this)->GetWeaponForAttack(attType,true);
10822 if(!item || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
10823 return false;
10825 else if(spellProto->EquippedItemClass == ITEM_CLASS_ARMOR)
10827 // Check if player is wearing shield
10828 Item *item = ((Player*)this)->GetShield(true);
10829 if(!item || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
10830 return false;
10834 float chance = (float)spellProto->procChance;
10836 if(Player* modOwner = GetSpellModOwner())
10837 modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance);
10839 if(!isVictim && spellProcEvent && spellProcEvent->ppmRate != 0)
10841 uint32 WeaponSpeed = GetAttackTime(attType);
10842 chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate);
10845 cooldown = spellProcEvent ? spellProcEvent->cooldown : 0;
10846 return roll_chance_f(chance);
10849 bool Unit::HandleMeandingAuraProc( Aura* triggeredByAura )
10851 // aura can be deleted at casts
10852 SpellEntry const* spellProto = triggeredByAura->GetSpellProto();
10853 uint32 effIdx = triggeredByAura->GetEffIndex();
10854 int32 heal = triggeredByAura->GetModifier()->m_amount;
10855 uint64 caster_guid = triggeredByAura->GetCasterGUID();
10857 // jumps
10858 int32 jumps = triggeredByAura->m_procCharges-1;
10860 // current aura expire
10861 triggeredByAura->m_procCharges = 1; // will removed at next charges decrease
10863 // next target selection
10864 if(jumps > 0 && GetTypeId()==TYPEID_PLAYER && IS_PLAYER_GUID(caster_guid))
10866 float radius;
10867 if (spellProto->EffectRadiusIndex[effIdx])
10868 radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellProto->EffectRadiusIndex[effIdx]));
10869 else
10870 radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(spellProto->rangeIndex));
10872 if(Player* caster = ((Player*)triggeredByAura->GetCaster()))
10874 caster->ApplySpellMod(spellProto->Id, SPELLMOD_RADIUS, radius,NULL);
10876 if(Player* target = ((Player*)this)->GetNextRandomRaidMember(radius))
10878 // aura will applied from caster, but spell casted from current aura holder
10879 SpellModifier *mod = new SpellModifier;
10880 mod->op = SPELLMOD_CHARGES;
10881 mod->value = jumps-5; // negative
10882 mod->type = SPELLMOD_FLAT;
10883 mod->spellId = spellProto->Id;
10884 mod->effectId = effIdx;
10885 mod->lastAffected = NULL;
10886 mod->mask = spellProto->SpellFamilyFlags;
10887 mod->charges = 0;
10889 caster->AddSpellMod(mod, true);
10890 CastCustomSpell(target,spellProto->Id,&heal,NULL,NULL,true,NULL,triggeredByAura,caster->GetGUID());
10891 caster->AddSpellMod(mod, false);
10896 // heal
10897 CastCustomSpell(this,33110,&heal,NULL,NULL,true,NULL,NULL,caster_guid);
10898 return true;
10901 void Unit::RemoveAurasAtChanneledTarget(SpellEntry const* spellInfo)
10903 uint64 target_guid = GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT);
10905 if(!IS_UNIT_GUID(target_guid))
10906 return;
10908 Unit* target = ObjectAccessor::GetUnit(*this, target_guid);
10909 if(!target)
10910 return;
10912 for (AuraMap::iterator iter = target->GetAuras().begin(); iter != target->GetAuras().end(); )
10914 if (iter->second->GetId() == spellInfo->Id && iter->second->GetCasterGUID()==GetGUID())
10915 target->RemoveAura(iter);
10916 else
10917 ++iter;