[4374] * Removed some wrong SubVersion properties.
[mangos-git.git] / src / game / Unit.cpp
blob6b82bfd478b7239bc4563af1a91867be0ebb875c
1 /*
2 * Copyright (C) 2005,2006,2007 MaNGOS <http://www.mangosproject.org/>
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 "Unit.h"
27 #include "QuestDef.h"
28 #include "Player.h"
29 #include "Creature.h"
30 #include "Spell.h"
31 #include "Group.h"
32 #include "SpellAuras.h"
33 #include "MapManager.h"
34 #include "ObjectAccessor.h"
35 #include "CreatureAI.h"
36 #include "Formulas.h"
37 #include "Pet.h"
38 #include "Util.h"
39 #include "Totem.h"
40 #include "TemporarySummon.h"
41 #include "BattleGroundMgr.h"
43 #include <math.h>
45 float baseMoveSpeed[MAX_MOVE_TYPE] =
47 2.5f, // MOVE_WALK
48 7.0f, // MOVE_RUN
49 1.25f, // MOVE_WALKBACK
50 4.722222f, // MOVE_SWIM
51 4.5f, // MOVE_SWIMBACK
52 3.141594f, // MOVE_TURN
53 7.0f, // MOVE_FLY
54 4.5f // MOVE_FLYBACK
57 // auraTypes contains auras capable of proc'ing for attacker
58 static std::set<uint32> GenerateAttakerProcAuraTypes()
60 static std::set<uint32> auraTypes;
61 auraTypes.insert(SPELL_AURA_DUMMY);
62 auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL);
63 auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE);
64 return auraTypes;
67 // auraTypes contains auras capable of proc'ing for attacker
68 static std::set<uint32> GenerateVictimProcAuraTypes()
70 static std::set<uint32> auraTypes;
71 auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL);
72 auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE);
73 auraTypes.insert(SPELL_AURA_DUMMY);
74 auraTypes.insert(SPELL_AURA_MOD_PARRY_PERCENT);
75 return auraTypes;
78 static std::set<uint32> attackerProcAuraTypes = GenerateAttakerProcAuraTypes();
79 static std::set<uint32> victimProcAuraTypes = GenerateVictimProcAuraTypes();
81 // auraTypes contains auras capable of proc'ing for attacker and victim
82 static std::set<uint32> GenerateProcAuraTypes()
84 static std::set<uint32> auraTypes = victimProcAuraTypes;
85 auraTypes.insert(attackerProcAuraTypes.begin(),attackerProcAuraTypes.end());
86 return auraTypes;
89 static std::set<uint32> procAuraTypes = GenerateProcAuraTypes();
91 bool IsPassiveStackableSpell( uint32 spellId )
93 if(!IsPassiveSpell(spellId))
94 return false;
96 SpellEntry const* spellProto = sSpellStore.LookupEntry(spellId);
97 if(!spellProto)
98 return false;
100 for(int j = 0; j < 3; ++j)
102 if(std::find(procAuraTypes.begin(),procAuraTypes.end(),spellProto->EffectApplyAuraName[j])!=procAuraTypes.end())
103 return false;
106 return true;
109 Unit::Unit( WorldObject *instantiator )
110 : WorldObject( instantiator ), m_ThreatManager(this), m_HostilRefManager(this)
112 m_objectType |= TYPE_UNIT;
113 m_objectTypeId = TYPEID_UNIT;
114 // 2.1.2 - 0x70
115 m_updateFlag = (UPDATEFLAG_ALL | UPDATEFLAG_LIVING | UPDATEFLAG_HASPOSITION);
117 m_attackTimer[BASE_ATTACK] = 0;
118 m_attackTimer[OFF_ATTACK] = 0;
119 m_attackTimer[RANGED_ATTACK] = 0;
120 m_modAttackSpeedPct[BASE_ATTACK] = 1.0f;
121 m_modAttackSpeedPct[OFF_ATTACK] = 1.0f;
122 m_modAttackSpeedPct[RANGED_ATTACK] = 1.0f;
124 m_state = 0;
125 m_form = 0;
126 m_deathState = ALIVE;
128 for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
129 m_currentSpells[i] = NULL;
130 m_addDmgOnce = 0;
131 m_TotemSlot[0] = m_TotemSlot[1] = m_TotemSlot[2] = m_TotemSlot[3] = 0;
132 m_ObjectSlot[0] = m_ObjectSlot[1] = m_ObjectSlot[2] = m_ObjectSlot[3] = 0;
133 //m_Aura = NULL;
134 //m_AurasCheck = 2000;
135 //m_removeAuraTimer = 4;
136 //tmpAura = NULL;
137 m_silenced = false;
138 waterbreath = false;
140 m_Visibility = VISIBILITY_ON;
142 m_detectStealth = 0;
143 m_detectInvisibility = 0;
144 m_stealthvalue = 0;
145 m_invisibilityvalue = 0;
146 m_transform = 0;
147 m_ShapeShiftForm = 0;
148 m_canModifyStats = false;
150 for (int i = 0; i < TOTAL_AURAS; i++)
151 m_AuraModifiers[i] = 0;
152 for (int i = 0; i < IMMUNITY_MECHANIC; i++)
153 m_spellImmune[i].clear();
154 for (int i = 0; i < UNIT_MOD_END; i++)
156 m_auraModifiersGroup[i][BASE_VALUE] = 0.0f;
157 m_auraModifiersGroup[i][BASE_PCT] = 1.0f;
158 m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f;
159 m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f;
161 // implement 50% base damage from offhand
162 m_auraModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f;
164 for (int i = 0; i < 3; i++)
166 m_weaponDamage[i][MINDAMAGE] = BASE_MINDAMAGE;
167 m_weaponDamage[i][MAXDAMAGE] = BASE_MAXDAMAGE;
169 for (int i = 0; i < MAX_STATS; i++)
170 m_createStats[i] = 0.0f;
172 m_attacking = NULL;
173 m_modHitChance = 0;
174 m_modSpellHitChance = 0;
175 m_baseSpellCritChance = 5;
176 m_modResilience = 0.0;
177 m_CombatTimer = 0;
178 //m_victimThreat = 0.0f;
179 for (int i = 0; i < MAX_SPELL_SCHOOL; ++i)
180 m_threatModifier[i] = 1.0f;
181 m_isSorted = true;
182 for (int i = 0; i < MAX_MOVE_TYPE; ++i)
183 m_speed_rate[i] = 1.0f;
185 m_removedAuras = 0;
186 m_charmInfo = NULL;
189 Unit::~Unit()
191 // set current spells as deletable
192 for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
194 // spell may be safely deleted now
195 if (m_currentSpells[i]) m_currentSpells[i]->SetDeletable(true);
196 m_currentSpells[i] = NULL;
199 // remove references to unit
200 for(std::list<GameObject*>::iterator i = m_gameObj.begin(); i != m_gameObj.end();)
202 (*i)->SetOwnerGUID(0);
203 (*i)->SetRespawnTime(0);
204 (*i)->Delete();
205 i = m_gameObj.erase(i);
208 RemoveAllDynObjects();
210 if(m_charmInfo) delete m_charmInfo;
213 void Unit::RemoveAllDynObjects()
215 while(!m_dynObjGUIDs.empty())
217 DynamicObject* dynObj = ObjectAccessor::Instance().GetDynamicObject(*this,*m_dynObjGUIDs.begin());
218 if(dynObj)
219 dynObj->Delete();
220 m_dynObjGUIDs.erase(m_dynObjGUIDs.begin());
224 void Unit::Update( uint32 p_time )
226 /*if(p_time > m_AurasCheck)
228 m_AurasCheck = 2000;
229 _UpdateAura();
230 }else
231 m_AurasCheck -= p_time;*/
233 // WARNING! Order of execution here is important, do not change.
234 // Spells must be processed with event system BEFORE they go to _UpdateSpells.
235 // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad.
236 m_Events.Update( p_time );
237 _UpdateSpells( p_time );
239 //update combat timer only for players and pets
240 if (isInCombat() && (GetTypeId() == TYPEID_PLAYER || ((Creature*)this)->isPet() || ((Creature*)this)->isCharmed()))
242 if(m_HostilRefManager.isEmpty())
244 // m_CombatTimer set at aura start and it will be freeze until aura removing
245 if(!HasAuraType(SPELL_AURA_INTERRUPT_REGEN))
247 if ( m_CombatTimer <= p_time )
248 ClearInCombat();
249 else
250 m_CombatTimer -= p_time;
255 if(uint32 base_att = getAttackTimer(BASE_ATTACK))
257 setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time) );
259 if(GetHealth() < GetMaxHealth()*0.2)
260 ModifyAuraState(AURA_STATE_HEALTHLESS, true);
261 else ModifyAuraState(AURA_STATE_HEALTHLESS, false);
264 bool Unit::haveOffhandWeapon() const
266 if(GetTypeId() == TYPEID_PLAYER)
268 Item *tmpitem = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
270 return tmpitem && !tmpitem->IsBroken() && (tmpitem->GetProto()->InventoryType == INVTYPE_WEAPON || tmpitem->GetProto()->InventoryType == INVTYPE_WEAPONOFFHAND);
272 else
273 return false;
276 void Unit::SendMoveToPacket(float x, float y, float z, bool run, uint32 transitTime)
278 float dx = x - GetPositionX();
279 float dy = y - GetPositionY();
280 float dz = z - GetPositionZ();
281 if (!transitTime)
283 float dist = ((dx*dx) + (dy*dy) + (dz*dz));
284 if(dist<0)
285 dist = 0;
286 else
287 dist = sqrt(dist);
288 double speed = GetSpeed(run ? MOVE_RUN : MOVE_WALK);
289 if(speed<=0)
290 speed = 2.5f;
291 speed *= 0.001f;
292 transitTime = static_cast<uint32>(dist / speed + 0.5);
294 //float orientation = (float)atan2((double)dy, (double)dx);
295 SendMonsterMove(x,y,z,0,run,transitTime);
298 void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, bool Run, uint32 Time)
300 WorldPacket data( SMSG_MONSTER_MOVE, (41 + GetPackGUID().size()) );
301 data.append(GetPackGUID());
303 // Point A, starting location
304 data << GetPositionX() << GetPositionY() << GetPositionZ();
305 // unknown field - unrelated to orientation
306 // seems to increment about 1000 for every 1.7 seconds
307 // for now, we'll just use mstime
308 data << getMSTime();
310 data << uint8(type); // unknown
311 switch(type)
313 case 0: // normal packet
314 break;
315 case 1: // stop packet
316 SendMessageToSet( &data, true );
317 return;
318 case 3: // not used currently
319 data << uint64(0); // probably target guid
320 break;
321 case 4: // not used currently
322 data << float(0); // probably orientation
323 break;
326 data << uint32(Run ? 0x00000100 : 0x00000000); // flags (0x100 - running, 0x200 - taxi)
327 /* Flags:
328 512: Floating, moving without walking/running
330 data << Time; // Time in between points
331 data << uint32(1); // 1 single waypoint
332 data << NewPosX << NewPosY << NewPosZ; // the single waypoint Point B
334 SendMessageToSet( &data, true );
337 void Unit::resetAttackTimer(WeaponAttackType type)
339 if (GetTypeId() == TYPEID_PLAYER)
340 m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]);
341 else
342 m_attackTimer[type] = uint32(BASE_ATTACK_TIME * m_modAttackSpeedPct[type]);
345 bool Unit::canReachWithAttack(Unit *pVictim) const
347 assert(pVictim);
348 float reach = GetFloatValue(UNIT_FIELD_COMBATREACH);
349 if( reach <= 0.0f )
350 reach = 1.0f;
351 return IsWithinDistInMap(pVictim, reach);
354 void Unit::RemoveSpellsCausingAura(uint32 auraType)
356 if (auraType >= TOTAL_AURAS) return;
357 AuraList::iterator iter, next;
358 for (iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end(); iter = next)
360 next = iter;
361 ++next;
363 if (*iter)
365 RemoveAurasDueToSpell((*iter)->GetId());
366 if (!m_modAuras[auraType].empty())
367 next = m_modAuras[auraType].begin();
368 else
369 return;
374 bool Unit::HasAuraType(uint32 auraType) const
376 return (!m_modAuras[auraType].empty());
379 /* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */
380 void Unit::RemoveSpellbyDamageTaken(uint32 auraType, uint32 damage)
382 if(!HasAuraType(auraType))
383 return;
385 // The chance to dispell an aura depends on the damage taken with respect to the casters level.
386 uint32 max_dmg = getLevel() > 8 ? 25 * getLevel() - 150 : 50;
387 float chance = float(damage) / max_dmg * 100.0;
388 if (roll_chance_f(chance))
389 RemoveSpellsCausingAura(auraType);
392 void Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchools damageSchool, SpellEntry const *spellProto, uint32 procFlag, bool durabilityLoss)
394 if (!pVictim->isAlive() || pVictim->isInFlight()) return;
396 //You don't lose health from damage taken from another player while in a sanctuary
397 //You still see it in the combat log though
398 if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
400 const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
401 if(area && area->flags & 0x800) //sanctuary
402 return;
405 // remove affects at any damage (including 0 damage)
406 if(HasStealthAura())
407 RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
408 if(HasInvisibilityAura())
409 RemoveSpellsCausingAura(SPELL_AURA_MOD_INVISIBILITY);
410 // remove death simulation at damage
411 if(hasUnitState(UNIT_STAT_DIED))
412 RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
414 //Script Event damage Deal
415 if( GetTypeId()== TYPEID_UNIT && ((Creature *)this)->AI())
416 ((Creature *)this)->AI()->DamageDeal(pVictim, damage);
417 //Script Event damage taken
418 if( pVictim->GetTypeId()== TYPEID_UNIT && ((Creature *)pVictim)->AI() )
419 ((Creature *)pVictim)->AI()->DamageTaken(this, damage);
421 if(!damage)
423 // Rage from physical damage received .
424 if(cleanDamage && cleanDamage->damage && damageSchool==SPELL_SCHOOL_NORMAL && pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->getPowerType() == POWER_RAGE))
425 ((Player*)pVictim)->RewardRage(cleanDamage->damage, 0, false);
427 return;
430 pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR, damage);
431 // root type spells do not dispell the root effect
432 if(!spellProto || spellProto->Mechanic != MECHANIC_ROOT)
433 pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT, damage);
435 if(pVictim->GetTypeId() != TYPEID_PLAYER)
437 //pVictim->SetInFront(this);
438 // no loot,xp,health if type 8 /critters/
439 if ( pVictim->GetCreatureType() == CREATURE_TYPE_CRITTER)
441 pVictim->setDeathState(JUST_DIED);
442 pVictim->SetHealth(0);
443 pVictim->CombatStop(true);
444 pVictim->DeleteThreatList();
445 return;
447 if(!pVictim->isInCombat() && ((Creature*)pVictim)->AI())
448 ((Creature*)pVictim)->AI()->AttackStart(this);
451 DEBUG_LOG("DealDamageStart");
453 uint32 health = pVictim->GetHealth();
454 sLog.outDetail("deal dmg:%d to health:%d ",damage,health);
456 // duel ends when player has 1 or less hp
457 bool duel_hasEnded = false;
458 if(pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->duel && damage >= (health-1))
460 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
461 if(((Player*)pVictim)->duel->opponent==this || ((Player*)pVictim)->duel->opponent->GetGUID() == GetOwnerGUID())
462 damage = health-1;
464 duel_hasEnded = true;
466 //Get in CombatState
467 if(pVictim != this && damagetype != DOT)
469 SetInCombat();
470 pVictim->SetInCombat();
473 // Rage from Damage made (only from direct weapon damage)
474 if( cleanDamage && damagetype==DIRECT_DAMAGE && this != pVictim && GetTypeId() == TYPEID_PLAYER && (getPowerType() == POWER_RAGE))
476 uint32 weaponSpeedHitFactor;
478 switch(cleanDamage->attackType)
480 case BASE_ATTACK:
482 if(cleanDamage->hitOutCome == MELEE_HIT_CRIT)
483 weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 7);
484 else
485 weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 3.5f);
487 ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true);
489 break;
491 case OFF_ATTACK:
493 if(cleanDamage->hitOutCome == MELEE_HIT_CRIT)
494 weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 3.5f);
495 else
496 weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 1.75f);
498 ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true);
500 break;
502 case RANGED_ATTACK:
503 break;
507 if (health <= damage)
509 // battleground things
510 if(pVictim->GetTypeId() == TYPEID_PLAYER && (((Player*)pVictim)->InBattleGround()))
512 Player *killed = ((Player*)pVictim);
513 Player *killer = NULL;
514 if(GetTypeId() == TYPEID_PLAYER)
515 killer = ((Player*)this);
516 else if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
518 Unit *owner = GetOwner();
519 if(owner->GetTypeId() == TYPEID_PLAYER)
520 killer = ((Player*)owner);
523 BattleGround *bg = sBattleGroundMgr.GetBattleGround(killed->GetBattleGroundId());
524 if(bg)
526 bg->HandleKillPlayer(killed, killer); // drop flags and etc
527 // add +1 deaths
528 bg->UpdatePlayerScore(killed, SCORE_DEATHS, 1);
529 if(killer)
530 // add +1 kills
531 bg->UpdatePlayerScore(killer, SCORE_KILLS, 1);
535 DEBUG_LOG("DealDamage: victim just died");
537 DEBUG_LOG("DealDamageAttackStop");
538 AttackStop();
539 pVictim->CombatStop(true);
541 DEBUG_LOG("SET JUST_DIED");
542 pVictim->setDeathState(JUST_DIED);
544 DEBUG_LOG("DealDamageHealth1");
545 pVictim->SetHealth(0);
547 // Call KilledUnit for creatures
548 if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI())
549 ((Creature*)this)->AI()->KilledUnit(pVictim);
551 // 10% durability loss on death
552 // clean InHateListOf
553 if (pVictim->GetTypeId() == TYPEID_PLAYER)
555 if (GetTypeId() != TYPEID_PLAYER && durabilityLoss)
557 DEBUG_LOG("We are dead, loosing 10 percents durability");
558 ((Player*)pVictim)->DurabilityLossAll(0.10);
559 // durability lost message
560 WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0);
561 ((Player*)pVictim)->GetSession()->SendPacket(&data);
563 pVictim->getHostilRefManager().deleteReferences();
565 Pet *pet = pVictim->GetPet();
566 if(pet && pVictim->GetTypeId() != TYPEID_PLAYER)
568 pet->setDeathState(JUST_DIED);
569 pet->CombatStop(true);
570 pet->SetHealth(0);
571 pet->addUnitState(UNIT_STAT_DIED);
572 pet->getHostilRefManager().deleteReferences();
575 else // creature died
577 DEBUG_LOG("DealDamageNotPlayer");
579 if(((Creature*)pVictim)->isPet())
580 pVictim->getHostilRefManager().deleteReferences();
581 else
583 pVictim->DeleteThreatList();
584 pVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
586 // Call creature just died function
587 if (((Creature*)pVictim)->AI())
588 ((Creature*)pVictim)->AI()->JustDied(this);
591 //judge if GainXP, Pet kill like player kill,kill pet not like PvP
592 bool PvP = false;
593 Player *player = NULL;
595 if(GetTypeId() == TYPEID_PLAYER)
597 player = (Player*)this;
598 if(pVictim->GetTypeId() == TYPEID_PLAYER)
599 PvP = true;
601 Unit* pet = NULL;
603 if(player->GetPetGUID() && (pet = player->GetPet()))
604 pet->ClearInCombat();
606 if(player->GetCharmGUID() && (pet = player->GetCharm()))
607 pet->ClearInCombat();
609 // FIXME: or charmed (can be player). Maybe must be check before GetTypeId() == TYPEID_PLAYER
610 else if(GetCharmerOrOwnerGUID()) // Pet or timed creature, etc
612 Unit* pet = this;
613 Unit* owner = pet->GetCharmerOrOwner();
615 if(owner && owner->GetTypeId() == TYPEID_PLAYER)
617 player = (Player*)owner;
618 player->ClearInCombat();
619 if(pVictim->GetTypeId() == TYPEID_PLAYER)
620 PvP = true;
623 if(pet->GetTypeId()==TYPEID_UNIT && ((Creature*)pet)->isPet())
625 uint32 petxp = MaNGOS::XP::BaseGain(getLevel(), pVictim->getLevel());
626 ((Pet*)pet)->GivePetXP(petxp);
630 // self or owner of pet
631 if(player)
633 if(player!=pVictim)
635 // prepare data for near group iteration (PvP and !PvP cases
636 uint32 xp = PvP || IsNoDamageXPArea(player->GetAreaId()) ? 0 : MaNGOS::XP::Gain(player, pVictim);
637 bool honored_kill = false;
639 Group *pGroup = player->GetGroup();
640 if(pGroup)
642 uint32 count = pGroup->GetMemberCountForXPAtKill(pVictim);
643 if(count)
645 // skip in check PvP case (for speed, not used)
646 bool is_raid = PvP ? false : MapManager::Instance().GetBaseMap(player->GetMapId())->IsRaid() && pGroup->isRaidGroup();
648 for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
650 Player *pGroupGuy = pGroup->GetMemberForXPAtKill(itr->getSource(),pVictim);
651 if(!pGroupGuy)
652 continue;
654 // honor can be in PvP and !PvP (racial leader) cases
655 if(pGroupGuy->RewardHonor(pVictim,count) && player==pGroupGuy)
656 honored_kill = true;
658 // xp and reputation only in !PvP case
659 if(!PvP)
661 // FIXME: xp/count for all in group at this moment, must be level dependent
662 float rate = 1.0f/count;
664 // if with raid in raid dungeon then all receive full reputation at kill
665 pGroupGuy->RewardReputation(pVictim,is_raid ? 1.0f : rate);
667 uint32 itr_xp = uint32(xp*rate);
669 pGroupGuy->GiveXP(itr_xp, pVictim);
670 if(Pet* pet = player->GetPet())
672 pet->GivePetXP(itr_xp/2);
675 // normal creature (not pet/etc) can be only in !PvP case
676 if(pVictim->GetTypeId()==TYPEID_UNIT)
677 pGroupGuy->KilledMonster(pVictim->GetEntry(), pVictim->GetGUID());
682 else // if (!pGroup)
684 // honor can be in PvP and !PvP (racial leader) cases
685 if(player->RewardHonor(pVictim,1))
686 honored_kill = true;
688 // xp and reputation only in !PvP case
689 if(!PvP)
691 player->RewardReputation(pVictim,1);
692 player->GiveXP(xp, pVictim);
693 if(Pet* pet = player->GetPet())
695 pet->GivePetXP(xp);
698 // normal creature (not pet/etc) can be only in !PvP case
699 if(pVictim->GetTypeId()==TYPEID_UNIT)
700 player->KilledMonster(pVictim->GetEntry(),pVictim->GetGUID());
704 if(xp || honored_kill)
705 player->ProcDamageAndSpell(pVictim,PROC_FLAG_KILL_XP_GIVER,PROC_FLAG_NONE);
708 else // if (player)
710 DEBUG_LOG("Monster kill Monster");
713 // last damage from duel opponent or opponent controlled creature?
714 if(duel_hasEnded)
716 assert(pVictim->GetTypeId()==TYPEID_PLAYER);
717 Player *he = (Player*)pVictim;
719 assert(he->duel);
721 CombatStop(); // for case killed by pet
722 if (IsNonMeleeSpellCasted(true))
723 InterruptNonMeleeSpells(true);
724 if(he->duel->opponent!=this)
726 he->duel->opponent->CombatStop();
727 if(he->duel->opponent->IsNonMeleeSpellCasted(true))
728 he->duel->opponent->InterruptNonMeleeSpells(true);
730 he->CombatStop();
731 if(he->IsNonMeleeSpellCasted(true))
732 he->InterruptNonMeleeSpells(true);
734 he->DuelComplete(0);
737 else // if (health <= damage)
739 DEBUG_LOG("DealDamageAlive");
741 pVictim->ModifyHealth(- (int32)damage);
743 // Check if health is below 20% (apply damage before to prevent case when after ProcDamageAndSpell health < damage
744 if(pVictim->GetHealth()*5 < pVictim->GetMaxHealth())
746 uint32 procVictim = PROC_FLAG_NONE;
748 // if just dropped below 20% (for CheatDeath)
749 if((pVictim->GetHealth()+damage)*5 > pVictim->GetMaxHealth())
750 procVictim = PROC_FLAG_LOW_HEALTH;
752 ProcDamageAndSpell(pVictim,PROC_FLAG_TARGET_LOW_HEALTH,procVictim);
755 if(damagetype != DOT)
757 //start melee attacks only after melee hit
758 Attack(pVictim,(damagetype == DIRECT_DAMAGE));
761 if(pVictim->getTransForm() && pVictim->hasUnitState(UNIT_STAT_CONFUSED))
763 pVictim->RemoveAurasDueToSpell(pVictim->getTransForm());
764 pVictim->setTransForm(0);
767 if (pVictim->GetTypeId() != TYPEID_PLAYER)
769 if(spellProto && IsDamageToThreatSpell(spellProto))
770 damage *= 2;
771 pVictim->AddThreat(this, damage, damageSchool, spellProto);
773 else // victim is a player
775 // Rage from damage received (only from physical damage)
776 if(damageSchool==SPELL_SCHOOL_NORMAL && this != pVictim && pVictim->GetTypeId() == TYPEID_PLAYER && pVictim->getPowerType() == POWER_RAGE)
778 uint32 rage_damage = damage + (cleanDamage ? cleanDamage->damage : 0);
779 ((Player*)pVictim)->RewardRage(rage_damage, 0, false);
782 // random durability for items (HIT)
783 if (urand(0,300) == 10)
785 DEBUG_LOG("HIT: We decrease durability with 5 percent");
786 ((Player*)pVictim)->DurabilityLossAll(0.05);
790 // TODO: Store auras by interrupt flag to speed this up.
791 AuraMap& vAuras = pVictim->GetAuras();
792 for (AuraMap::iterator i = vAuras.begin(), next; i != vAuras.end(); i = next)
794 const SpellEntry *se = i->second->GetSpellProto();
795 next = i; next++;
796 if( se->AuraInterruptFlags & AURA_INTERRUPT_FLAG_DAMAGE )
798 bool remove = true;
799 if (se->procFlags & (1<<3))
801 if (!roll_chance_i(se->procChance))
802 remove = false;
804 if (remove)
806 pVictim->RemoveAurasDueToSpell(i->second->GetId());
807 // FIXME: this may cause the auras with proc chance to be rerolled several times
808 next = vAuras.begin();
813 if (damagetype != NODAMAGE)
815 if(pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL] && pVictim->GetTypeId() == TYPEID_PLAYER && damage)
817 if (pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() == SPELL_STATE_CASTING)
819 uint32 channelInterruptFlags = pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->ChannelInterruptFlags;
820 if( channelInterruptFlags & CHANNEL_FLAG_DELAY )
822 sLog.outDetail("Spell %u delayed (%d) at damage!",pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id,(int32)(0.25f * GetDuration(pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo)));
823 pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->DelayedChannel((int32)(0.25f * GetDuration(pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo)));
825 else if( (channelInterruptFlags & (CHANNEL_FLAG_DAMAGE | CHANNEL_FLAG_DAMAGE2)) )
827 sLog.outDetail("Spell %u canceled at damage!",pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id);
828 pVictim->InterruptSpell(CURRENT_CHANNELED_SPELL);
831 else if (pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() == SPELL_STATE_DELAYED)
832 // break channeled spell in delayed state on damage
834 sLog.outDetail("Spell %u canceled at damage!",pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id);
835 pVictim->InterruptSpell(CURRENT_CHANNELED_SPELL);
840 // last damage from duel opponent
841 if(duel_hasEnded)
843 assert(pVictim->GetTypeId()==TYPEID_PLAYER);
844 Player *he = (Player*)pVictim;
846 assert(he->duel);
848 he->ModifyHealth(1);
849 CombatStop(); // for case killed by pet
850 if(he->duel->opponent!=this)
851 he->duel->opponent->CombatStop();
852 he->CombatStop();
854 he->CastSpell(he, 7267, true); // beg
855 he->DuelComplete(1);
859 DEBUG_LOG("DealDamageEnd");
862 void Unit::CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster)
864 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
866 if(!spellInfo)
868 sLog.outError("WORLD: unknown spell id %i\n", spellId);
869 return;
872 CastSpell(Victim,spellInfo,triggered,castItem,triggredByAura, originalCaster);
875 void Unit::CastSpell(Unit* Victim,SpellEntry const *spellInfo, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster)
877 if(!spellInfo)
879 sLog.outError("WORLD: unknown spell ");
880 return;
883 if (castItem)
884 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
886 Spell *spell = new Spell(this, spellInfo, triggered, triggredByAura,originalCaster);
888 SpellCastTargets targets;
889 targets.setUnitTarget( Victim );
890 spell->m_CastItem = castItem;
891 spell->prepare(&targets);
894 void Unit::CastCustomSpell(Unit* Victim,uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster)
896 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
898 if(!spellInfo)
900 sLog.outError("WORLD: unknown spell id %i\n", spellId);
901 return;
904 CastCustomSpell(Victim,spellInfo,bp0,bp1,bp2,triggered,castItem,triggredByAura, originalCaster);
907 void Unit::CastCustomSpell(Unit* Victim,SpellEntry const *spellInfo, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster)
909 if(!spellInfo)
911 sLog.outError("WORLD: unknown spell ");
912 return;
915 if (castItem)
916 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
918 Spell *spell = new Spell(this, spellInfo, triggered, triggredByAura,originalCaster);
920 if(bp0)
921 spell->m_currentBasePoints[0] = *bp0;
923 if(bp1)
924 spell->m_currentBasePoints[1] = *bp1;
926 if(bp2)
927 spell->m_currentBasePoints[2] = *bp2;
929 SpellCastTargets targets;
930 targets.setUnitTarget( Victim );
931 spell->m_CastItem = castItem;
932 spell->prepare(&targets);
935 void Unit::DealDamageBySchool(Unit *pVictim, SpellEntry const *spellInfo, uint32 *damage, CleanDamage *cleanDamage, bool *crit, bool isTriggeredSpell)
938 // TODO this in only generic way, check for exceptions
939 DEBUG_LOG("DealDamageBySchool (BEFORE) SCHOOL %u >> DMG:%u", spellInfo->School, *damage);
941 // Per-school calc
942 switch (spellInfo->School)
944 // Physical damage school
945 case SPELL_SCHOOL_NORMAL:
947 // Calculate physical outcome
948 MeleeHitOutcome outcome;
949 outcome = RollPhysicalOutcomeAgainst(pVictim, BASE_ATTACK, spellInfo);
951 //Used to store the Hit Outcome
952 cleanDamage->hitOutCome = outcome;
954 // Return miss first (sends miss message)
955 if(outcome == MELEE_HIT_MISS)
957 SendAttackStateUpdate(HITINFO_MISS, pVictim, 1, SpellSchools(spellInfo->School), 0, 0,0,1,0);
958 *damage = 0;
960 if(GetTypeId()== TYPEID_PLAYER)
961 ((Player*)this)->UpdateWeaponSkill(BASE_ATTACK);
963 CastMeleeProcDamageAndSpell(pVictim,0,BASE_ATTACK,MELEE_HIT_MISS,spellInfo,isTriggeredSpell);
964 return;
967 // Hitinfo, Victimstate
968 uint32 hitInfo, victimState;
969 hitInfo = HITINFO_NORMALSWING;
971 //Calculate armor mitigation
972 uint32 damageAfterArmor;
973 damageAfterArmor = CalcArmorReducedDamage(pVictim, *damage);
974 cleanDamage->damage += *damage - damageAfterArmor;
975 *damage = damageAfterArmor;
977 // Classify outcome
978 switch (outcome)
980 case MELEE_HIT_CRIT:
982 *damage *= 2;
983 // Resilience - reduce crit damage by 2x%
984 uint32 resilienceReduction = uint32(pVictim->m_modResilience * 2/100 * (*damage));
985 cleanDamage->damage += resilienceReduction;
986 *damage -= resilienceReduction;
987 *crit = true;
988 hitInfo |= HITINFO_CRITICALHIT;
989 break;
991 case MELEE_HIT_PARRY:
993 cleanDamage->damage += *damage; // To Help Calculate Rage
994 *damage = 0;
995 victimState = VICTIMSTATE_PARRY;
997 // Counter-attack ( explained in Unit::DoAttackDamage() )
999 // Get attack timers
1000 float offtime = float(pVictim->getAttackTimer(OFF_ATTACK));
1001 float basetime = float(pVictim->getAttackTimer(BASE_ATTACK));
1003 // Reduce attack time
1004 if (pVictim->haveOffhandWeapon() && offtime < basetime)
1006 float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20;
1007 float percent60 = 3 * percent20;
1008 if(offtime > percent20 && offtime <= percent60)
1010 pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20));
1012 else if(offtime > percent60)
1014 offtime -= 2 * percent20;
1015 pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime));
1018 else
1020 float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20;
1021 float percent60 = 3 * percent20;
1022 if(basetime > percent20 && basetime <= percent60)
1024 pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20));
1026 else if(basetime > percent60)
1028 basetime -= 2 * percent20;
1029 pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime));
1034 // Update victim defense ?
1035 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1036 ((Player*)pVictim)->UpdateDefense();
1038 // Set parry flags
1039 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
1040 pVictim->ModifyAuraState(AURA_STATE_PARRY, true);
1041 break;
1043 case MELEE_HIT_DODGE:
1045 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1046 ((Player*)pVictim)->UpdateDefense();
1048 cleanDamage->damage += *damage; // To Help Calculate Rage
1049 *damage = 0;
1050 hitInfo |= HITINFO_SWINGNOHITSOUND;
1051 victimState = VICTIMSTATE_DODGE;
1052 break;
1054 case MELEE_HIT_BLOCK:
1056 uint32 blocked_amount;
1057 blocked_amount = uint32(pVictim->GetShieldBlockValue());
1058 if (blocked_amount >= *damage)
1060 hitInfo |= HITINFO_SWINGNOHITSOUND;
1061 victimState = VICTIMSTATE_BLOCKS;
1062 cleanDamage->damage += *damage; // To Help Calculate Rage
1063 *damage = 0;
1065 else
1067 // To Help Calculate Rage
1068 cleanDamage->damage += blocked_amount;
1069 *damage = *damage - blocked_amount;
1071 break;
1074 case MELEE_HIT_MISS:
1075 case MELEE_HIT_GLANCING:
1076 case MELEE_HIT_CRUSHING:
1077 case MELEE_HIT_NORMAL:
1078 break;
1081 // Update attack state
1082 SendAttackStateUpdate(victimState ? hitInfo|victimState : hitInfo, pVictim, 1, SpellSchools(spellInfo->School), 0, 0,0,1,0);
1084 // do all damage=0 cases here
1085 if(damage <= 0)
1086 CastMeleeProcDamageAndSpell(pVictim,0,BASE_ATTACK,outcome,spellInfo,isTriggeredSpell);
1088 break;
1090 // Other schools
1091 case SPELL_SCHOOL_HOLY:
1092 case SPELL_SCHOOL_FIRE:
1093 case SPELL_SCHOOL_NATURE:
1094 case SPELL_SCHOOL_FROST:
1095 case SPELL_SCHOOL_SHADOW:
1096 case SPELL_SCHOOL_ARCANE:
1098 //Spell miss (sends resist message)
1099 if(SpellMissChanceCalc(pVictim) > urand(0,10000))
1101 cleanDamage->damage = 0;
1102 *damage = 0;
1103 ProcDamageAndSpell(pVictim, PROC_FLAG_TARGET_RESISTS, PROC_FLAG_RESIST_SPELL, 0, spellInfo,isTriggeredSpell);
1104 SendAttackStateUpdate(HITINFO_RESIST|HITINFO_SWINGNOHITSOUND, pVictim, 1, SpellSchools(spellInfo->School), 0, 0,0,1,0);
1105 return;
1108 // Calculate damage bonus
1109 *damage = SpellDamageBonus(pVictim, spellInfo, *damage, SPELL_DIRECT_DAMAGE);
1111 // Calculate critical bonus
1112 *crit = SpellCriticalBonus(spellInfo, (int32*)damage, pVictim);
1113 cleanDamage->hitOutCome = MELEE_HIT_CRIT;
1115 // spell proc all magic damage==0 case in this function
1116 if(damage <= 0)
1118 // Procflags
1119 uint32 procAttacker = PROC_FLAG_HIT_SPELL;
1120 uint32 procVictim = (PROC_FLAG_STRUCK_SPELL|PROC_FLAG_TAKE_DAMAGE);
1122 ProcDamageAndSpell(pVictim, procAttacker, procVictim, 0, spellInfo, isTriggeredSpell);
1125 break;
1128 // TODO this in only generic way, check for exceptions
1129 DEBUG_LOG("DealDamageBySchool (AFTER) SCHOOL %u >> DMG:%u", spellInfo->School, *damage);
1132 void Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell, bool useSpellDamage)
1134 if(!this || !pVictim)
1135 return;
1136 if(!this->isAlive() || !pVictim->isAlive())
1137 return;
1139 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID);
1140 if(!spellInfo)
1141 return;
1143 CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL);
1144 bool crit = false;
1146 if (useSpellDamage)
1147 DealDamageBySchool(pVictim, spellInfo, &damage, &cleanDamage, &crit, isTriggeredSpell);
1149 // If we actually dealt some damage (spell proc's for 0 damage (normal and magic) called in DealDamageBySchool)
1150 if(damage > 0)
1152 // Calculate absorb & resists
1153 uint32 absorb = 0;
1154 uint32 resist = 0;
1156 CalcAbsorbResist(pVictim,SpellSchools(spellInfo->School), damage, &absorb, &resist);
1158 // Only send absorbed message if we actually absorbed some damage
1159 if(damage > 0)
1161 // Handle absorb & resists
1162 if(damage <= absorb + resist && absorb)
1164 SendAttackStateUpdate(HITINFO_ABSORB|HITINFO_SWINGNOHITSOUND, pVictim, 1, SpellSchools(spellInfo->School),damage, absorb,resist,1,0);
1165 return;
1167 else if(damage <= resist) // If we didn't fully absorb check if we fully resisted
1169 ProcDamageAndSpell(pVictim, PROC_FLAG_TARGET_RESISTS, PROC_FLAG_RESIST_SPELL, 0, spellInfo,isTriggeredSpell);
1170 SendAttackStateUpdate(HITINFO_RESIST|HITINFO_SWINGNOHITSOUND, pVictim, 1, SpellSchools(spellInfo->School), damage, absorb,resist,1,0);
1171 return;
1175 // Send damage log
1176 sLog.outDetail("SpellNonMeleeDamageLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u,absorb is %u,resist is %u",
1177 GetGUIDLow(), GetTypeId(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, spellID, absorb,resist);
1178 SendSpellNonMeleeDamageLog(pVictim, spellID, damage, SpellSchools(spellInfo->School), absorb, resist, false, 0, crit);
1180 // Deal damage done
1181 DealDamage(pVictim, (damage-absorb-resist), &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchools(spellInfo->School), spellInfo, 0, true);
1183 // Procflags
1184 uint32 procAttacker = PROC_FLAG_HIT_SPELL;
1185 uint32 procVictim = (PROC_FLAG_STRUCK_SPELL|PROC_FLAG_TAKE_DAMAGE);
1187 if (crit)
1189 procAttacker |= PROC_FLAG_CRIT_SPELL;
1190 procVictim |= PROC_FLAG_STRUCK_CRIT_SPELL;
1193 ProcDamageAndSpell(pVictim, procAttacker, procVictim, (damage-absorb-resist), spellInfo, isTriggeredSpell);
1195 else
1197 // all spell proc for 0 normal and magic damage called in DealDamageBySchool
1199 //Check for rage
1200 if(cleanDamage.damage)
1201 // Rage from physical damage received.
1202 if(spellInfo->School==SPELL_SCHOOL_NORMAL && pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->getPowerType() == POWER_RAGE))
1203 ((Player*)pVictim)->RewardRage(cleanDamage.damage, 0, false);
1207 void Unit::PeriodicAuraLog(Unit *pVictim, SpellEntry const *spellProto, Modifier *mod, uint8 effect_idx)
1209 uint32 procFlag = 0;
1210 if(!this || !pVictim || !isAlive() || !pVictim->isAlive())
1212 return;
1214 uint32 absorb=0;
1215 uint32 resist=0;
1216 CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
1217 uint32 pdamage = mod->m_amount;
1219 if(mod->m_auraname != SPELL_AURA_PERIODIC_HEAL && mod->m_auraname != SPELL_AURA_OBS_MOD_HEALTH)
1221 //Calculate armor mitigation if it is a physical spell
1222 if (spellProto->School == 0)
1224 uint32 pdamageReductedArmor = CalcArmorReducedDamage(pVictim, pdamage);
1225 cleanDamage.damage += pdamage - pdamageReductedArmor;
1226 pdamage = pdamageReductedArmor;
1229 CalcAbsorbResist(pVictim, SpellSchools(spellProto->School), pdamage, &absorb, &resist);
1232 sLog.outDetail("PeriodicAuraLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u abs is %u",
1233 GetGUIDLow(), GetTypeId(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), pdamage, spellProto->Id,absorb);
1235 switch(mod->m_auraname)
1237 case SPELL_AURA_PERIODIC_DAMAGE:
1238 case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
1240 pdamage = SpellDamageBonus(pVictim,spellProto,pdamage,DOT);
1242 if(mod->m_auraname == SPELL_AURA_PERIODIC_DAMAGE_PERCENT)
1243 pdamage = GetHealth()*(100+mod->m_amount)/100;
1245 WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
1246 data.append(pVictim->GetPackGUID());
1247 data.append(GetPackGUID());
1248 data << uint32(spellProto->Id);
1249 data << uint32(1);
1250 data << uint32(mod->m_auraname);
1251 data << (uint32)pdamage;
1252 data << (uint32)spellProto->School;
1253 data << (uint32)absorb;
1254 data << (uint32)resist;
1255 SendMessageToSet(&data,true);
1257 DealDamage(pVictim, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), &cleanDamage, DOT, SpellSchools(spellProto->School), spellProto, procFlag, true);
1258 ProcDamageAndSpell(pVictim, PROC_FLAG_HIT_SPELL, PROC_FLAG_TAKE_DAMAGE, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), spellProto);
1259 break;
1261 case SPELL_AURA_PERIODIC_HEAL:
1262 case SPELL_AURA_OBS_MOD_HEALTH:
1264 pdamage = SpellHealingBonus(spellProto, pdamage, DOT, pVictim);
1266 WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
1267 data.append(pVictim->GetPackGUID());
1268 data.append(GetPackGUID());
1269 data << uint32(spellProto->Id);
1270 data << uint32(1);
1271 data << uint32(mod->m_auraname);
1272 data << (uint32)pdamage;
1273 SendMessageToSet(&data,true);
1275 int32 gain = pVictim->ModifyHealth(pdamage);
1276 pVictim->getHostilRefManager().threatAssist(this, float(gain) * 0.5f, spellProto);
1278 // heal for caster damage
1279 if(pVictim!=this && spellProto->SpellVisual==163)
1281 uint32 dmg = spellProto->manaPerSecond;
1282 if(GetHealth() <= dmg && GetTypeId()==TYPEID_PLAYER)
1284 RemoveAurasDueToSpell(spellProto->Id);
1286 // finish current generic/channeling spells, don't affect autorepeat
1287 if(m_currentSpells[CURRENT_GENERIC_SPELL])
1289 m_currentSpells[CURRENT_GENERIC_SPELL]->finish();
1291 if(m_currentSpells[CURRENT_CHANNELED_SPELL])
1293 m_currentSpells[CURRENT_CHANNELED_SPELL]->SendChannelUpdate(0);
1294 m_currentSpells[CURRENT_CHANNELED_SPELL]->finish();
1297 else
1299 SendSpellNonMeleeDamageLog(this, spellProto->Id, gain, SpellSchools(spellProto->School), 0, 0, false, 0, false);
1300 DealDamage(this, gain, &cleanDamage, NODAMAGE, SpellSchools(spellProto->School), spellProto, PROC_FLAG_HEAL, true);
1304 if(mod->m_auraname == SPELL_AURA_PERIODIC_HEAL && pVictim != this)
1305 ProcDamageAndSpell(pVictim, PROC_FLAG_HEAL, PROC_FLAG_HEALED, pdamage, spellProto);
1306 break;
1308 case SPELL_AURA_PERIODIC_LEECH:
1310 float multiplier = spellProto->EffectMultipleValue[effect_idx] > 0 ? spellProto->EffectMultipleValue[effect_idx] : 1;
1311 uint32 pdamage = mod->m_amount;
1313 pdamage = SpellDamageBonus(pVictim,spellProto,pdamage,DOT);
1315 if(pVictim->GetHealth() < pdamage)
1316 pdamage = uint32(pVictim->GetHealth());
1318 SendSpellNonMeleeDamageLog(pVictim, spellProto->Id, pdamage, SpellSchools(spellProto->School), absorb, resist, false, 0);
1319 DealDamage(pVictim, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), &cleanDamage, DOT, SpellSchools(spellProto->School), spellProto, procFlag, false);
1320 ProcDamageAndSpell(pVictim, PROC_FLAG_HIT_SPELL, PROC_FLAG_TAKE_DAMAGE, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), spellProto);
1321 if (!pVictim->isAlive() && IsNonMeleeSpellCasted(false))
1323 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
1325 if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id == spellProto->Id)
1326 m_currentSpells[i]->cancel();
1330 int32 gain = ModifyHealth(int32(pdamage * multiplier));
1331 getHostilRefManager().threatAssist(this, float(gain) * 0.5f, spellProto);
1333 if(GetTypeId() == TYPEID_PLAYER)
1334 SendHealSpellOnPlayer(this, spellProto->Id, uint32(pdamage * multiplier));
1335 break;
1337 case SPELL_AURA_PERIODIC_MANA_LEECH:
1339 if(mod->m_miscvalue < 0 || mod->m_miscvalue > 4)
1340 break;
1342 Powers power = Powers(mod->m_miscvalue);
1344 int32 drain_amount = pVictim->GetPower(power) > pdamage ? pdamage : pVictim->GetPower(power);
1346 pVictim->ModifyPower(power, -drain_amount);
1348 float gain_multiplier = GetMaxPower(power) > 0 ? spellProto->EffectMultipleValue[effect_idx] : 0;
1350 WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
1351 data.append(pVictim->GetPackGUID());
1352 data.append(GetPackGUID());
1353 data << uint32(spellProto->Id);
1354 data << uint32(1);
1355 data << uint32(mod->m_auraname);
1356 data << (uint32)power; // power type
1357 data << (uint32)drain_amount;
1358 data << (float)gain_multiplier;
1359 SendMessageToSet(&data,true);
1361 int32 gain_amount = int32(drain_amount*gain_multiplier);
1363 if(gain_amount)
1365 int32 gain = ModifyPower(power,gain_amount);
1366 pVictim->AddThreat(this, float(gain) * 0.5f, SpellSchools(spellProto->School), spellProto);
1368 break;
1370 case SPELL_AURA_PERIODIC_ENERGIZE:
1372 if(mod->m_miscvalue < 0 || mod->m_miscvalue > 4)
1373 break;
1375 Powers power = Powers(mod->m_miscvalue);
1377 if(pVictim->GetMaxPower(power) == 0)
1378 break;
1380 WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
1381 data.append(pVictim->GetPackGUID());
1382 data.append(GetPackGUID());
1383 data << uint32(spellProto->Id);
1384 data << uint32(1);
1385 data << uint32(mod->m_auraname);
1386 data << (uint32)power; // power type
1387 data << (uint32)mod->m_amount;
1388 SendMessageToSet(&data,true);
1390 int32 gain = pVictim->ModifyPower(power,mod->m_amount);
1391 pVictim->getHostilRefManager().threatAssist(this, float(gain) * 0.5f, spellProto);
1392 break;
1394 case SPELL_AURA_OBS_MOD_MANA:
1396 if(GetMaxPower(POWER_MANA) == 0)
1397 break;
1399 WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
1400 data.append(pVictim->GetPackGUID());
1401 data.append(GetPackGUID());
1402 data << uint32(spellProto->Id);
1403 data << uint32(1);
1404 data << uint32(mod->m_auraname);
1405 data << (uint32)mod->m_amount;
1406 data << (uint32)0; // ?
1407 SendMessageToSet(&data,true);
1409 int32 gain = ModifyPower(POWER_MANA, mod->m_amount);
1410 getHostilRefManager().threatAssist(this, float(gain) * 0.5f, spellProto);
1411 break;
1416 void Unit::HandleEmoteCommand(uint32 anim_id)
1418 WorldPacket data( SMSG_EMOTE, 12 );
1419 data << anim_id << GetGUID();
1420 WPAssert(data.size() == 12);
1422 SendMessageToSet(&data, true);
1425 uint32 Unit::CalcArmorReducedDamage(Unit* pVictim, const uint32 damage)
1427 uint32 newdamage = 0;
1428 float armor = pVictim->GetArmor();
1430 float tmpvalue = 0.0;
1431 if(getLevel() <= 59) //Level 1-59
1432 tmpvalue = armor / (armor + 400.0 + 85.0 * getLevel());
1433 else if(getLevel() < 70) //Level 60-69
1434 tmpvalue = armor / (armor - 22167.5 + 467.5 * getLevel());
1435 else //Level 70+
1436 tmpvalue = armor / (armor + 10557.5);
1438 if(tmpvalue < 0.0)
1439 tmpvalue = 0.0;
1440 if(tmpvalue > 0.75)
1441 tmpvalue = 0.75;
1442 newdamage = uint32(damage - (damage * tmpvalue));
1444 return (newdamage > 1) ? newdamage : 1;
1447 void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchools school, const uint32 damage, uint32 *absorb, uint32 *resist)
1449 if(!pVictim || !pVictim->isAlive() || !damage)
1450 return;
1452 // Magic damage, check for resists
1453 if (school != SPELL_SCHOOL_NORMAL)
1455 int32 tmpvalue2 = pVictim->GetResistance(school);
1456 AuraList const& mModTargetRes = GetAurasByType(SPELL_AURA_MOD_TARGET_RESISTANCE);
1457 for(AuraList::const_iterator i = mModTargetRes.begin(); i != mModTargetRes.end(); ++i)
1458 if ((*i)->GetModifier()->m_miscvalue & int32(1 << school))
1459 tmpvalue2 += (*i)->GetModifier()->m_amount;
1460 if (tmpvalue2 < 0) tmpvalue2 = 0;
1461 *resist += uint32(damage*tmpvalue2*0.0025*pVictim->getLevel()/getLevel());
1462 if(*resist > damage)
1463 *resist = damage;
1465 else
1466 *resist = 0;
1468 int32 RemainingDamage = damage - *resist;
1469 int32 currentAbsorb, manaReduction, maxAbsorb;
1470 float manaMultiplier;
1472 if (school == SPELL_SCHOOL_NORMAL)
1474 AuraList const& vManaShield = pVictim->GetAurasByType(SPELL_AURA_MANA_SHIELD);
1475 for(AuraList::const_iterator i = vManaShield.begin(), next; i != vManaShield.end() && RemainingDamage >= 0; i = next)
1477 next = i; next++;
1478 if (RemainingDamage - (*i)->m_absorbDmg >= 0)
1479 currentAbsorb = (*i)->m_absorbDmg;
1480 else
1481 currentAbsorb = RemainingDamage;
1483 manaMultiplier = (*i)->GetSpellProto()->EffectMultipleValue[(*i)->GetEffIndex()];
1484 maxAbsorb = int32(pVictim->GetPower(POWER_MANA) / manaMultiplier);
1485 if (currentAbsorb > maxAbsorb)
1486 currentAbsorb = maxAbsorb;
1488 (*i)->m_absorbDmg -= currentAbsorb;
1489 if((*i)->m_absorbDmg <= 0)
1491 pVictim->RemoveAurasDueToSpell((*i)->GetId());
1492 next = vManaShield.begin();
1495 manaReduction = int32(currentAbsorb * manaMultiplier);
1496 pVictim->ApplyPowerMod(POWER_MANA, manaReduction, false);
1498 RemainingDamage -= currentAbsorb;
1502 AuraList const& vSchoolAbsorb = pVictim->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB);
1503 for(AuraList::const_iterator i = vSchoolAbsorb.begin(), next; i != vSchoolAbsorb.end() && RemainingDamage >= 0; i = next)
1505 next = i; next++;
1506 if ((*i)->GetModifier()->m_miscvalue & int32(1<<school))
1508 if (RemainingDamage - (*i)->m_absorbDmg >= 0)
1510 currentAbsorb = (*i)->m_absorbDmg;
1511 pVictim->RemoveAurasDueToSpell((*i)->GetId());
1512 next = vSchoolAbsorb.begin();
1514 else
1516 currentAbsorb = RemainingDamage;
1517 (*i)->m_absorbDmg -= RemainingDamage;
1520 RemainingDamage -= currentAbsorb;
1524 *absorb = damage - RemainingDamage - *resist;
1527 void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDamage, uint32 *blocked_amount, SpellSchools damageType, uint32 *hitInfo, uint32 *victimState, uint32 *absorbDamage, uint32 *resistDamage, WeaponAttackType attType, SpellEntry const *spellCasted, bool isTriggeredSpell)
1529 pVictim->ModifyAuraState(AURA_STATE_PARRY, false);
1530 pVictim->ModifyAuraState(AURA_STATE_DEFENSE, false);
1531 ModifyAuraState(AURA_STATE_CRIT, false);
1533 MeleeHitOutcome outcome;
1535 // If is casted Melee spell, calculate like physical
1536 if(!spellCasted)
1537 outcome = RollMeleeOutcomeAgainst (pVictim, attType);
1538 else
1539 outcome = RollPhysicalOutcomeAgainst (pVictim, attType, spellCasted);
1541 if (outcome == MELEE_HIT_MISS)
1543 *hitInfo |= HITINFO_MISS;
1544 *damage = 0;
1545 cleanDamage->damage = 0;
1546 if(GetTypeId()== TYPEID_PLAYER)
1547 ((Player*)this)->UpdateWeaponSkill(attType);
1548 return;
1551 /// If this is a creature and it attacks from behind it has a probability to daze it's victim
1552 if( (outcome==MELEE_HIT_CRIT || outcome==MELEE_HIT_CRUSHING || outcome==MELEE_HIT_NORMAL || outcome==MELEE_HIT_GLANCING) &&
1553 GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->GetCharmerOrOwnerGUID() && !pVictim->HasInArc(M_PI, this) )
1555 // -probability is between 0% and 40%
1556 // 20% base chance
1557 float Probability = 20;
1559 //there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1560 if( pVictim->getLevel() < 30 )
1561 Probability = 0.65f*pVictim->getLevel()+0.5;
1563 uint32 VictimDefense=pVictim->GetDefenseSkillValue();
1564 uint32 AttackerMeleeSkill=GetUnitMeleeSkill();
1566 Probability *= AttackerMeleeSkill/(float)VictimDefense;
1568 if(Probability > 40)
1569 Probability = 40;
1571 if(roll_chance_f(Probability))
1572 CastSpell(pVictim, 1604, true);
1575 *damage += CalculateDamage (attType);
1577 //Calculate the damage after armor mitigation if SPELL_SCHOOL_NORMAL
1578 if (damageType == SPELL_SCHOOL_NORMAL)
1580 uint32 damageAfterArmor = CalcArmorReducedDamage(pVictim, *damage);
1581 cleanDamage->damage += *damage - damageAfterArmor;
1582 *damage = damageAfterArmor;
1584 // Instant Attacks (Spellmods)
1585 // TODO: AP bonus related to mainhand weapon
1586 if(spellCasted)
1587 if(GetTypeId()== TYPEID_PLAYER)
1588 ((Player*)this)->ApplySpellMod(spellCasted->Id, SPELLMOD_DAMAGE, *damage);
1590 if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER )
1591 ((Player*)this)->UpdateCombatSkills(pVictim, attType, outcome, false);
1593 if(GetTypeId() != TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
1594 ((Player*)pVictim)->UpdateCombatSkills(this, attType, outcome, true);
1596 switch (outcome)
1598 case MELEE_HIT_CRIT:
1599 //*hitInfo = 0xEA;
1600 // 0xEA
1601 *hitInfo = HITINFO_CRITICALHIT | HITINFO_NORMALSWING2 | 0x8;
1603 // Crit bonus calc
1604 uint32 crit_bonus;
1605 crit_bonus = *damage;
1607 // Apply crit_damage bonus for melee spells
1608 if (GetTypeId() == TYPEID_PLAYER && spellCasted)
1610 ((Player*)this)->ApplySpellMod(spellCasted->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
1613 *damage += crit_bonus;
1615 // Resilience - reduce crit damage by 2x%
1616 uint32 resilienceReduction;
1617 resilienceReduction = uint32(pVictim->m_modResilience * 2/100 * (*damage));
1618 *damage -= resilienceReduction;
1619 cleanDamage->damage += resilienceReduction;
1621 if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER )
1622 ((Player*)this)->UpdateWeaponSkill(attType);
1624 ModifyAuraState(AURA_STATE_CRIT, true);
1626 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL);
1627 break;
1629 case MELEE_HIT_PARRY:
1630 if(attType == RANGED_ATTACK) //range attack - no parry
1631 break;
1633 cleanDamage->damage += *damage;
1634 *damage = 0;
1635 *victimState = VICTIMSTATE_PARRY;
1637 // instant (maybe with small delay) counter attack
1639 float offtime = float(pVictim->getAttackTimer(OFF_ATTACK));
1640 float basetime = float(pVictim->getAttackTimer(BASE_ATTACK));
1642 // after parry nearest next attack time will reduced at %40 from full attack time.
1643 // The delay cannot be reduced to less than 20% of your weapon’s base swing delay.
1644 if (pVictim->haveOffhandWeapon() && offtime < basetime)
1646 float percent20 = pVictim->GetAttackTime(OFF_ATTACK)*0.20;
1647 float percent60 = 3*percent20;
1648 // set to 20% if in range 20%...20+40% of full time
1649 if(offtime > percent20 && offtime <= percent60)
1651 pVictim->setAttackTimer(OFF_ATTACK,uint32(percent20));
1653 // decrease at %40 from full time
1654 else if(offtime > percent60)
1656 offtime -= 2*percent20;
1657 pVictim->setAttackTimer(OFF_ATTACK,uint32(offtime));
1659 // ELSE not changed
1661 else
1663 float percent20 = pVictim->GetAttackTime(BASE_ATTACK)*0.20;
1664 float percent60 = 3*percent20;
1665 // set to 20% if in range 20%...20+40% of full time
1666 if(basetime > percent20 && basetime <= percent60)
1668 pVictim->setAttackTimer(BASE_ATTACK,uint32(percent20));
1670 // decrease at %40 from full time
1671 else if(basetime > percent60)
1673 basetime -= 2*percent20;
1674 pVictim->setAttackTimer(BASE_ATTACK,uint32(basetime));
1676 // ELSE not changed
1680 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1681 ((Player*)pVictim)->UpdateDefense();
1683 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
1684 pVictim->ModifyAuraState(AURA_STATE_PARRY,true);
1685 if (pVictim->getClass() != CLASS_HUNTER) // Mongoose Bite
1686 pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true);
1688 CastMeleeProcDamageAndSpell(pVictim, 0, attType, outcome, spellCasted, isTriggeredSpell);
1689 return;
1691 case MELEE_HIT_DODGE:
1692 if(attType == RANGED_ATTACK) //range attack - no dodge
1693 break;
1694 cleanDamage->damage += *damage;
1695 *damage = 0;
1696 *victimState = VICTIMSTATE_DODGE;
1698 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1699 ((Player*)pVictim)->UpdateDefense();
1701 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
1703 if (pVictim->getClass() != CLASS_ROGUE) // Riposte
1704 pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true);
1706 CastMeleeProcDamageAndSpell(pVictim, 0, attType, outcome, spellCasted, isTriggeredSpell);
1707 return;
1709 case MELEE_HIT_BLOCK:
1710 *blocked_amount = uint32(pVictim->GetShieldBlockValue() + (pVictim->GetStat(STAT_STRENGTH) / 20.0f) -1);
1712 if (pVictim->GetUnitBlockChance())
1713 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD);
1714 else
1715 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
1717 //Only set VICTIMSTATE_BLOCK on a full block
1718 if (*blocked_amount >= *damage)
1720 *victimState = VICTIMSTATE_BLOCKS;
1721 *blocked_amount = *damage;
1724 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1725 ((Player*)pVictim)->UpdateDefense();
1726 pVictim->ModifyAuraState(AURA_STATE_DEFENSE,true);
1727 break;
1729 case MELEE_HIT_GLANCING:
1731 float reducePercent = 1.0f; //damage factor
1733 // calculate base values and mods
1734 float baseLowEnd = 1.3;
1735 float baseHighEnd = 1.2;
1736 switch(getClass()) // lowering base values for casters
1738 case CLASS_SHAMAN:
1739 case CLASS_PRIEST:
1740 case CLASS_MAGE:
1741 case CLASS_WARLOCK:
1742 case CLASS_DRUID:
1743 baseLowEnd -= 0.7;
1744 baseHighEnd -= 0.3;
1745 break;
1748 float maxLowEnd = 0.6;
1749 switch(getClass()) // upper for melee classes
1751 case CLASS_WARRIOR:
1752 case CLASS_ROGUE:
1753 maxLowEnd = 0.91; //If the attacker is a melee class then instead the lower value of 0.91
1756 // calculate values
1757 int32 diff = pVictim->GetDefenseSkillValue() - GetWeaponSkillValue(attType);
1758 float lowEnd = baseLowEnd - ( 0.05f * diff );
1759 float highEnd = baseHighEnd - ( 0.03f * diff );
1761 // apply max/min bounds
1762 if ( lowEnd < 0.01f ) //the low end must not go bellow 0.01f
1763 lowEnd = 0.01f;
1764 else if ( lowEnd > maxLowEnd ) //the smaller value of this and 0.6 is kept as the low end
1765 lowEnd = maxLowEnd;
1767 if ( highEnd < 0.2f ) //high end limits
1768 highEnd = 0.2f;
1769 if ( highEnd > 0.99f )
1770 highEnd = 0.99f;
1772 if(lowEnd > highEnd) // prevent negative range size
1773 lowEnd = highEnd;
1775 reducePercent = lowEnd + rand_norm() * ( highEnd - lowEnd );
1777 *damage = uint32(reducePercent * *damage);
1778 cleanDamage->damage += *damage;
1779 *hitInfo |= HITINFO_GLANCING;
1780 break;
1782 case MELEE_HIT_CRUSHING:
1784 // 150% normal damage
1785 *damage += (*damage / 2);
1786 cleanDamage->damage = *damage;
1787 *hitInfo |= HITINFO_CRUSHING;
1788 // TODO: victimState, victim animation?
1789 break;
1791 default:
1792 break;
1795 // apply melee damage bonus and absorb only if base damage not fully blocked to prevent negative damage or damage with full block
1796 if(*victimState != VICTIMSTATE_BLOCKS)
1798 MeleeDamageBonus(pVictim, damage,attType);
1799 CalcAbsorbResist(pVictim, damageType, *damage-*blocked_amount, absorbDamage, resistDamage);
1802 if (*absorbDamage) *hitInfo |= HITINFO_ABSORB;
1803 if (*resistDamage) *hitInfo |= HITINFO_RESIST;
1804 cleanDamage += *blocked_amount;
1806 if (*damage <= *absorbDamage + *resistDamage + *blocked_amount)
1808 //*hitInfo = 0x00010020;
1809 //*hitInfo |= HITINFO_SWINGNOHITSOUND;
1810 //*damageType = 0;
1811 CastMeleeProcDamageAndSpell(pVictim, 0, attType, outcome, spellCasted, isTriggeredSpell);
1812 return;
1815 CastMeleeProcDamageAndSpell(pVictim, (*damage - *absorbDamage - *resistDamage - *blocked_amount), attType, outcome, spellCasted, isTriggeredSpell);
1817 // victim's damage shield
1818 // yet another hack to fix crashes related to the aura getting removed during iteration
1819 std::set<Aura*> alreadyDone;
1820 uint32 removedAuras = pVictim->m_removedAuras;
1821 AuraList const& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD);
1822 for(AuraList::const_iterator i = vDamageShields.begin(), next = vDamageShields.begin(); i != vDamageShields.end(); i = next)
1824 next++;
1825 if (alreadyDone.find(*i) == alreadyDone.end())
1827 alreadyDone.insert(*i);
1828 pVictim->SpellNonMeleeDamageLog(this, (*i)->GetId(), (*i)->GetModifier()->m_amount, false, false);
1829 if (pVictim->m_removedAuras > removedAuras)
1831 removedAuras = pVictim->m_removedAuras;
1832 next = vDamageShields.begin();
1837 if (pVictim->GetTypeId() == TYPEID_PLAYER && *damage)
1839 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
1841 // skip channeled spell (processed differently below)
1842 if (i == CURRENT_CHANNELED_SPELL)
1843 continue;
1845 if(pVictim->m_currentSpells[i])
1847 sLog.outDetail("Spell Delayed!%d",(int32)(0.25f * pVictim->m_currentSpells[i]->casttime));
1848 pVictim->m_currentSpells[i]->Delayed((int32)(0.25f * pVictim->m_currentSpells[i]->casttime));
1852 // process channeled spell separately
1853 if (pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL])
1855 if (pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() == SPELL_STATE_CASTING)
1857 uint32 channelInterruptFlags = pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->ChannelInterruptFlags;
1858 if( channelInterruptFlags & CHANNEL_FLAG_DELAY )
1860 sLog.outDetail("Spell Delayed!%d",(int32)(0.25f * GetDuration(pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo)));
1861 pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->DelayedChannel((int32)(0.25f * GetDuration(pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo)));
1862 return;
1864 else if( !(channelInterruptFlags & (CHANNEL_FLAG_DAMAGE | CHANNEL_FLAG_DAMAGE2)) )
1865 return;
1867 sLog.outDetail("Spell Canceled!");
1868 pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel();
1870 else if (pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() == SPELL_STATE_DELAYED)
1872 // break channeled spell in delayed state on damage
1873 sLog.outDetail("Spell Canceled!");
1874 pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel();
1880 void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool isTriggered)
1882 if(hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNDED | UNIT_STAT_FLEEING) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED) )
1883 return;
1885 if (!pVictim->isAlive())
1886 return;
1888 if(!isTriggered)
1890 if(IsNonMeleeSpellCasted(false))
1891 return;
1893 // melee attack spell casted at main hand attack only
1894 if (m_currentSpells[CURRENT_MELEE_SPELL] && attType == BASE_ATTACK)
1896 m_currentSpells[CURRENT_MELEE_SPELL]->cast();
1897 return;
1901 uint32 hitInfo;
1902 if (attType == BASE_ATTACK)
1903 hitInfo = HITINFO_NORMALSWING2;
1904 else if (attType == OFF_ATTACK)
1905 hitInfo = HITINFO_LEFTSWING;
1906 else
1907 return;
1909 uint32 victimState = VICTIMSTATE_NORMAL;
1911 uint32 damage = 0;
1912 CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
1913 uint32 blocked_dmg = 0;
1914 uint32 absorbed_dmg = 0;
1915 uint32 resisted_dmg = 0;
1917 if( pVictim->IsImmunedToPhysicalDamage() )
1919 SendAttackStateUpdate (HITINFO_MISS, pVictim, 1, SPELL_SCHOOL_NORMAL, 0, 0, 0, VICTIMSTATE_IS_IMMUNE, 0);
1920 return;
1923 DoAttackDamage (pVictim, &damage, &cleanDamage, &blocked_dmg, SPELL_SCHOOL_NORMAL, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, attType);
1925 cleanDamage.damage += blocked_dmg;
1927 if (hitInfo & HITINFO_MISS)
1928 //send miss
1929 SendAttackStateUpdate (hitInfo, pVictim, 1, SPELL_SCHOOL_NORMAL, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg);
1930 else
1932 //do animation
1933 SendAttackStateUpdate (hitInfo, pVictim, 1, SPELL_SCHOOL_NORMAL, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg);
1935 if (damage > (absorbed_dmg + resisted_dmg + blocked_dmg))
1936 damage -= (absorbed_dmg + resisted_dmg + blocked_dmg);
1937 else
1938 damage = 0;
1940 DealDamage (pVictim, damage, &cleanDamage, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, 0, true);
1942 if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive())
1944 for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
1945 ((Player*)this)->CastItemCombatSpell(((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i),pVictim);
1949 if (GetTypeId() == TYPEID_PLAYER)
1950 DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
1951 GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, absorbed_dmg, blocked_dmg, resisted_dmg);
1952 else
1953 DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
1954 GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, absorbed_dmg, blocked_dmg, resisted_dmg);
1957 MeleeHitOutcome Unit::RollPhysicalOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo)
1959 // Miss chance based on melee
1960 int32 miss_chance = (int32)(MeleeMissChanceCalc(pVictim));
1962 // Critical hit chance
1963 float crit_chance = GetUnitCriticalChance(attType);
1965 // Only players can have Talent&Spell bonuses
1966 if (GetTypeId() == TYPEID_PLAYER)
1968 // Talents
1969 AuraList const& mSpellCritSchool = GetAurasByType(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL);
1970 for(AuraList::const_iterator i = mSpellCritSchool.begin(); i != mSpellCritSchool.end(); ++i)
1971 if((*i)->GetModifier()->m_miscvalue == -2 || ((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellInfo->School)) != 0)
1972 crit_chance += (*i)->GetModifier()->m_amount;
1974 // flat
1975 AuraList const& mAttackerSWCrit = pVictim->GetAurasByType(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
1976 for(AuraList::const_iterator i = mAttackerSWCrit.begin(); i != mAttackerSWCrit.end(); ++i)
1977 crit_chance += (*i)->GetModifier()->m_amount;
1979 // Spellmods
1980 ((Player*)this)->ApplySpellMod(spellInfo->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance);
1983 DEBUG_LOG("PHYSICAL OUTCOME: hit %u crit %f miss %u",m_modHitChance,crit_chance,miss_chance);
1985 return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance * 100 ), miss_chance, m_modHitChance);
1988 MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType) const
1990 // This is only wrapper
1992 // Miss chance based on melee
1993 int32 miss_chance = (int32)(MeleeMissChanceCalc(pVictim));
1995 // Critical hit chance
1996 float crit_chance = GetUnitCriticalChance(attType);
1998 // flat
1999 AuraList const& mAttackerSWCrit = pVictim->GetAurasByType(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
2000 for(AuraList::const_iterator i = mAttackerSWCrit.begin(); i != mAttackerSWCrit.end(); ++i)
2001 crit_chance += (*i)->GetModifier()->m_amount;
2003 // Useful if want to specify crit & miss chances for melee, else it could be removed
2004 DEBUG_LOG("MELEE OUTCOME: hit %u crit %u miss %u", m_modHitChance,crit_chance,miss_chance);
2005 return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance * 100 ), miss_chance, m_modHitChance);
2008 MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 hit_chance) const
2010 int32 skillDiff = GetWeaponSkillValue(attType) - pVictim->GetDefenseSkillValue();
2011 // bonus from skills is 0.04%
2012 int32 skillBonus = skillDiff * 4;
2013 int32 skillBonus2 = 4 * ( GetWeaponSkillValue(attType) - pVictim->GetPureDefenseSkillValue() );
2014 int32 sum = 0, tmp = 0;
2015 int32 roll = urand (0, 10000);
2017 DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus);
2018 DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, +hit %d, dodge %u, parry %u, block %u, crit %u",
2019 roll, hit_chance, (uint32)(pVictim->GetUnitDodgeChance()*100), (uint32)(pVictim->GetUnitParryChance()*100),
2020 (uint32)(pVictim->GetUnitBlockChance()*100), crit_chance);
2022 // dual wield has 24% base chance to miss instead of 5%, also
2023 // base miss rate is 5% and can't get higher than 60%
2025 // Inherit if passed
2026 tmp = miss_chance - skillBonus;
2028 if(tmp > 6000)
2029 tmp = 6000;
2031 if (tmp > 0 && roll < (sum += tmp ))
2033 DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS");
2034 return MELEE_HIT_MISS;
2037 // always crit against a sitting target (except 0 crit chance)
2038 if( (pVictim->GetTypeId() == TYPEID_PLAYER) && crit_chance > 0 &&
2039 (((Player*)pVictim)->getStandState() & (PLAYER_STATE_SLEEP | PLAYER_STATE_SIT
2040 | PLAYER_STATE_SIT_CHAIR
2041 | PLAYER_STATE_SIT_LOW_CHAIR
2042 | PLAYER_STATE_SIT_MEDIUM_CHAIR
2043 | PLAYER_STATE_SIT_HIGH_CHAIR)))
2045 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)");
2046 return MELEE_HIT_CRIT;
2049 // stunned target cannot dodge and this is check in GetUnitDodgeChance()
2050 tmp = (int32)(pVictim->GetUnitDodgeChance()*100) - skillBonus2;
2051 if (tmp > 0 && roll < (sum += tmp))
2053 DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum-tmp, sum);
2054 return MELEE_HIT_DODGE;
2057 int32 modCrit = 0;
2059 // check if attack comes from behind
2060 if (!pVictim->HasInArc(M_PI,this))
2062 // ASSUME +10% crit from behind
2063 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind.");
2064 modCrit += 1000;
2066 else
2068 // cannot parry or block attacks from behind, but can from forward
2069 tmp = (int32)(pVictim->GetUnitParryChance()*100);
2070 if ( (tmp > 0) // check if unit _can_ parry
2071 && ((tmp -= skillBonus2) > 0)
2072 && (roll < (sum += tmp)))
2074 DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum-tmp, sum);
2075 return MELEE_HIT_PARRY;
2078 tmp = (int32)(pVictim->GetUnitBlockChance()*100);
2079 if ( (tmp > 0) // check if unit _can_ block
2080 && ((tmp -= skillBonus2) > 0)
2081 && (roll < (sum += tmp)))
2083 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum-tmp, sum);
2084 return MELEE_HIT_BLOCK;
2088 // Resilience - reduce crit chance by x%
2089 modCrit -= int32(pVictim->m_modResilience*100);
2091 // Critical chance
2092 tmp = crit_chance + skillBonus + modCrit;
2094 if (tmp > 0 && roll < (sum += tmp))
2096 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum-tmp, sum);
2097 return MELEE_HIT_CRIT;
2100 // Max 40% chance to score a glancing blow against mobs that are higher level
2101 if( GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && getLevel() < pVictim->getLevel() )
2103 // cap possible value (with bonuses > max skill)
2104 int32 skill = GetWeaponSkillValue(attType);
2105 int32 maxskill = GetMaxSkillValueForLevel();
2106 skill = (skill > maxskill) ? maxskill : skill;
2108 tmp = (10 + (pVictim->GetDefenseSkillValue() - skill)) * 100;
2109 tmp = tmp > 4000 ? 4000 : tmp;
2110 if (roll < (sum += tmp))
2112 DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum-4000, sum);
2113 return MELEE_HIT_GLANCING;
2117 // mobs can score crushing blows if they're 3 or more levels above victim
2118 // or when their weapon skill is 15 or more above victim's defense skill
2119 tmp = pVictim->GetDefenseSkillValue();
2120 int32 tmpmax = pVictim->GetMaxSkillValueForLevel();
2121 // having defense above your maximum (from items, talents etc.) has no effect
2122 tmp = tmp > tmpmax ? tmpmax : tmp;
2123 // tmp = mob's level * 5 - player's current defense skill
2124 tmp = GetMaxSkillValueForLevel() - tmp;
2125 if (GetTypeId() != TYPEID_PLAYER && (tmp >= 15))
2127 // add 2% chance per lacking skill point, min. is 15%
2128 tmp = tmp * 200 - 1500;
2129 if (roll < (sum += tmp))
2131 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum-tmp, sum);
2132 return MELEE_HIT_CRUSHING;
2136 DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL");
2137 return MELEE_HIT_NORMAL;
2140 uint32 Unit::CalculateDamage (WeaponAttackType attType)
2142 float min_damage, max_damage;
2144 switch (attType)
2146 case RANGED_ATTACK:
2147 min_damage = GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE);
2148 max_damage = GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE);
2149 break;
2150 case BASE_ATTACK:
2151 min_damage = GetFloatValue(UNIT_FIELD_MINDAMAGE);
2152 max_damage = GetFloatValue(UNIT_FIELD_MAXDAMAGE);
2153 break;
2154 case OFF_ATTACK:
2155 min_damage = GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE);
2156 max_damage = GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE);
2157 break;
2160 if (min_damage > max_damage)
2162 std::swap(min_damage,max_damage);
2165 if(max_damage == 0.0)
2166 max_damage = 5.0;
2168 return rand32((uint32)min_damage, (uint32)max_damage);
2171 void Unit::SendAttackStart(Unit* pVictim)
2173 if(GetTypeId()!=TYPEID_PLAYER || !pVictim)
2174 return;
2176 WorldPacket data( SMSG_ATTACKSTART, 16 );
2177 data << GetGUID();
2178 data << pVictim->GetGUID();
2180 ((Player*)this)->SendMessageToSet(&data, true);
2181 DEBUG_LOG( "WORLD: Sent SMSG_ATTACKSTART" );
2184 void Unit::SendAttackStop(Unit* victim)
2186 if(!victim)
2187 return;
2189 WorldPacket data( SMSG_ATTACKSTOP, (4+16) ); // we guess size
2190 data.append(GetPackGUID());
2191 data.append(victim->GetPackGUID()); // can be 0x00...
2192 data << uint32(0); // can be 0x1
2193 SendMessageToSet(&data, true);
2194 sLog.outDetail("%s %u stopped attacking %s %u", (GetTypeId()==TYPEID_PLAYER ? "player" : "creature"), GetGUIDLow(), (victim->GetTypeId()==TYPEID_PLAYER ? "player" : "creature"),victim->GetGUIDLow());
2196 /*if(victim->GetTypeId() == TYPEID_UNIT)
2197 ((Creature*)victim)->AI().EnterEvadeMode(this);*/
2200 uint32 Unit::SpellMissChanceCalc(Unit *pVictim) const
2202 if(!pVictim)
2203 return 0;
2205 // PvP : PvE spell misschances per leveldif > 2
2206 int32 chance = pVictim->GetTypeId() == TYPEID_PLAYER ? 700 : 1100;
2208 int32 leveldif = pVictim->getLevel() - getLevel();
2209 if(leveldif < 0)
2210 leveldif = 0;
2212 int32 misschance = 400 - m_modSpellHitChance*100;
2213 if(leveldif < 3)
2214 misschance += leveldif * 100;
2215 else
2216 misschance += (leveldif - 2) * chance;
2218 return misschance < 100 ? 100 : misschance;
2221 int32 Unit::MeleeMissChanceCalc(const Unit *pVictim) const
2223 if(!pVictim)
2224 return 0;
2226 // Base misschance 5%
2227 int32 misschance = 500;
2229 // DualWield - Melee spells and physical dmg spells - 5% , white damage 24%
2230 if (haveOffhandWeapon())
2232 bool isNormal = false;
2233 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
2235 if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->School == SPELL_SCHOOL_NORMAL)
2237 isNormal = true;
2238 break;
2241 if (isNormal || m_currentSpells[CURRENT_MELEE_SPELL])
2243 misschance = 500;
2245 else
2247 misschance = 2400;
2251 // PvP : PvE melee misschances per leveldif > 2
2252 int32 chance = pVictim->GetTypeId() == TYPEID_PLAYER ? 500 : 700;
2254 int32 leveldif = pVictim->getLevel() - getLevel();
2255 if(leveldif < 0)
2256 leveldif = 0;
2258 if(leveldif < 3)
2259 misschance += leveldif * 100 - m_modHitChance*100;
2260 else
2261 misschance += (leveldif - 2) * chance - m_modHitChance*100;
2263 return misschance > 6000 ? 6000 : misschance;
2266 uint16 Unit::GetDefenseSkillValue() const
2268 if(GetTypeId() == TYPEID_PLAYER)
2269 return ((Player*)this)->GetSkillValue (SKILL_DEFENSE);
2270 else
2271 return GetUnitMeleeSkill();
2274 uint16 Unit::GetPureDefenseSkillValue() const
2276 if(GetTypeId() == TYPEID_PLAYER)
2277 return ((Player*)this)->GetPureSkillValue(SKILL_DEFENSE);
2278 else
2279 return GetUnitMeleeSkill();
2282 float Unit::GetUnitDodgeChance() const
2284 if(hasUnitState(UNIT_STAT_STUNDED))
2285 return 0;
2286 return GetTypeId() == TYPEID_PLAYER ? GetFloatValue(PLAYER_DODGE_PERCENTAGE) : 5;
2289 float Unit::GetUnitParryChance() const
2291 float chance = 0;
2292 if(GetTypeId() == TYPEID_PLAYER)
2294 Player const* player = (Player const*)this;
2295 if(player->CanParry() && player->IsUseEquipedWeapon() )
2297 Item *tmpitem = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
2298 if(!tmpitem || tmpitem->IsBroken())
2299 tmpitem = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
2301 if(tmpitem && !tmpitem->IsBroken() && (
2302 tmpitem->GetProto()->InventoryType == INVTYPE_WEAPON ||
2303 tmpitem->GetProto()->InventoryType == INVTYPE_WEAPONOFFHAND ||
2304 tmpitem->GetProto()->InventoryType == INVTYPE_WEAPONMAINHAND ||
2305 tmpitem->GetProto()->InventoryType == INVTYPE_2HWEAPON))
2306 chance = GetFloatValue(PLAYER_PARRY_PERCENTAGE);
2309 else if(GetTypeId() == TYPEID_UNIT)
2311 if(GetCreatureType() == CREATURE_TYPE_HUMANOID)
2312 chance = 5;
2315 return chance;
2318 float Unit::GetUnitBlockChance() const
2320 float chance = 0;
2321 if(GetTypeId() == TYPEID_PLAYER)
2323 Item *tmpitem = ((Player const*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
2324 if(tmpitem && !tmpitem->IsBroken() && tmpitem->GetProto()->Block)
2325 chance = GetFloatValue(PLAYER_BLOCK_PERCENTAGE);
2327 else
2328 chance = 5;
2330 return chance;
2333 uint16 Unit::GetWeaponSkillValue (WeaponAttackType attType) const
2335 if(GetTypeId() == TYPEID_PLAYER)
2337 uint16 slot;
2338 switch (attType)
2340 case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
2341 case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
2342 case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
2343 default:
2344 return 0;
2346 Item *item = ((Player*)this)->GetItemByPos (INVENTORY_SLOT_BAG_0, slot);
2348 if(slot != EQUIPMENT_SLOT_MAINHAND && (!item || item->IsBroken() ||
2349 item->GetProto()->Class != ITEM_CLASS_WEAPON || !((Player*)this)->IsUseEquipedWeapon() ))
2350 return 0;
2352 // in range
2353 uint32 skill = item && !item->IsBroken() && ((Player*)this)->IsUseEquipedWeapon()
2354 ? item->GetSkill() : SKILL_UNARMED;
2355 return ((Player*)this)->GetSkillValue (skill);
2357 else
2358 return GetUnitMeleeSkill();
2361 uint16 Unit::GetPureWeaponSkillValue (WeaponAttackType attType) const
2363 if(GetTypeId() == TYPEID_PLAYER)
2365 uint16 slot;
2366 switch (attType)
2368 case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
2369 case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
2370 case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
2371 default:
2372 return 0;
2374 Item *item = ((Player*)this)->GetItemByPos (INVENTORY_SLOT_BAG_0, slot);
2376 if(slot != EQUIPMENT_SLOT_MAINHAND && (!item || item->IsBroken() ||
2377 item->GetProto()->Class != ITEM_CLASS_WEAPON || !((Player*)this)->IsUseEquipedWeapon() ))
2378 return 0;
2380 // in range
2381 uint32 skill = item && !item->IsBroken() && ((Player*)this)->IsUseEquipedWeapon()
2382 ? item->GetSkill() : SKILL_UNARMED;
2383 return ((Player*)this)->GetPureSkillValue (skill);
2385 else
2386 return GetUnitMeleeSkill();
2389 void Unit::_UpdateSpells( uint32 time )
2391 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
2392 _UpdateAutoRepeatSpell( time );
2394 // remove finished spells from current pointers
2395 for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
2397 if (m_currentSpells[i] && m_currentSpells[i]->getState() == SPELL_STATE_FINISHED)
2399 m_currentSpells[i]->SetDeletable(true); // spell may be safely deleted now
2400 m_currentSpells[i] = NULL; // remove pointer
2404 // TODO: Find a better way to prevent crash when multiple auras are removed.
2405 m_removedAuras = 0;
2406 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
2407 if ((*i).second)
2408 (*i).second->SetUpdated(false);
2410 for (AuraMap::iterator i = m_Auras.begin(), next; i != m_Auras.end(); i = next)
2412 next = i;
2413 next++;
2414 if ((*i).second)
2416 // prevent double update
2417 if ((*i).second->IsUpdated())
2418 continue;
2419 (*i).second->SetUpdated(true);
2420 (*i).second->Update( time );
2421 // several auras can be deleted due to update
2422 if (m_removedAuras)
2424 if (m_Auras.empty()) break;
2425 next = m_Auras.begin();
2426 m_removedAuras = 0;
2431 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end();)
2433 if ((*i).second)
2435 if ( !(*i).second->GetAuraDuration() && !((*i).second->IsPermanent() || ((*i).second->IsPassive())) )
2437 RemoveAura(i);
2439 else
2441 ++i;
2444 else
2446 ++i;
2450 if(!m_gameObj.empty())
2452 std::list<GameObject*>::iterator ite1, dnext1;
2453 for (ite1 = m_gameObj.begin(); ite1 != m_gameObj.end(); ite1 = dnext1)
2455 dnext1 = ite1;
2456 //(*i)->Update( difftime );
2457 if( !(*ite1)->isSpawned() )
2459 (*ite1)->SetOwnerGUID(0);
2460 (*ite1)->SetRespawnTime(0);
2461 (*ite1)->Delete();
2462 dnext1 = m_gameObj.erase(ite1);
2464 else
2465 ++dnext1;
2470 void Unit::_UpdateAutoRepeatSpell( uint32 time )
2472 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_FINISHED)
2474 //Auto Shot & Shoot
2475 if( m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->AttributesEx2 == 0x000020 && GetTypeId() == TYPEID_PLAYER )
2477 // Auto Shot don't require ranged weapon cooldown at first cast, wand shoot does, so the 'FINISHED' state
2478 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
2480 // Shoot
2481 resetAttackTimer( RANGED_ATTACK );
2483 else
2485 // Auto Shoot
2486 if (m_AutoRepeatFirstCast)
2488 // first cast only with recovery time (not less)
2489 if (getAttackTimer( RANGED_ATTACK ) < m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->RecoveryTime)
2490 setAttackTimer( RANGED_ATTACK, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->RecoveryTime);
2491 m_AutoRepeatFirstCast = false;
2493 else
2495 // second or further casts
2496 resetAttackTimer( RANGED_ATTACK );
2500 else
2502 setAttackTimer( RANGED_ATTACK, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->RecoveryTime);
2505 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_IDLE);
2507 else if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_IDLE && isAttackReady(RANGED_ATTACK) )
2509 // check if we can cast
2510 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast() == 0)
2512 // check movement in player case
2513 if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isMoving())
2515 // cancel wand shooting
2516 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
2517 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
2518 // ELSE delay auto-repeat ranged weapon until player movement stop
2520 else
2521 // recheck range and req. items (ammo and gun, etc)
2522 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckRange() == 0 && m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckItems() == 0 )
2524 // check, if we are casting melee spell (it blocks autorepeat)
2525 if ( ! (m_currentSpells[CURRENT_MELEE_SPELL] &&
2526 (m_currentSpells[CURRENT_MELEE_SPELL]->getState() != SPELL_STATE_FINISHED) &&
2527 (m_currentSpells[CURRENT_MELEE_SPELL]->getState() != SPELL_STATE_DELAYED)) )
2529 // check, if we are casting something else, if no then run autorepeat spell
2530 if (!IsNonMeleeSpellCasted(false, false, true))
2532 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_PREPARING);
2533 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->ReSetTimer();
2537 else
2539 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
2542 else
2544 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
2547 else if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_PREPARING)
2549 // check, if some other incomplete spell exists (including melee) or ranged attack is not ready
2550 if ( m_currentSpells[CURRENT_MELEE_SPELL] ||
2551 m_currentSpells[CURRENT_GENERIC_SPELL] ||
2552 m_currentSpells[CURRENT_CHANNELED_SPELL] ||
2553 !isAttackReady(RANGED_ATTACK) )
2555 // some other spell is here or ranged attack is not ready, break us to idle state
2556 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->finish(false);
2557 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_IDLE);
2562 void Unit::SetCurrentCastedSpell( Spell * pSpell )
2564 assert(pSpell); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
2566 uint32 CSpellType = pSpell->GetCurrentContainer();
2568 pSpell->SetDeletable(false); // spell will not be deleted until gone from current pointers
2569 if (pSpell == m_currentSpells[CSpellType]) return; // avoid breaking self
2571 // break same type spell if it is not delayed
2572 if ( m_currentSpells[CSpellType] &&
2573 m_currentSpells[CSpellType]->getState() != SPELL_STATE_DELAYED )
2575 InterruptSpell(CSpellType);
2578 // special breakage effects:
2579 switch (CSpellType)
2581 case CURRENT_GENERIC_SPELL:
2583 // generic spells always break channeled not delayed spells
2584 if ( m_currentSpells[CURRENT_CHANNELED_SPELL] &&
2585 m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_DELAYED )
2587 InterruptSpell(CURRENT_CHANNELED_SPELL);
2590 // autorepeat breaking
2591 if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL] )
2593 // break autorepeat if not Auto Shot
2594 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
2595 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
2597 } break;
2599 case CURRENT_CHANNELED_SPELL:
2601 // channel spells always break generic and channeled spells
2602 InterruptSpell(CURRENT_GENERIC_SPELL);
2603 InterruptSpell(CURRENT_CHANNELED_SPELL);
2605 // it also does break autorepeat if not Auto Shot
2606 if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL] &&
2607 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351 )
2608 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
2609 } break;
2611 case CURRENT_AUTOREPEAT_SPELL:
2613 // only Auto Shoot does not break anything
2614 if (pSpell->m_spellInfo->Category == 351)
2616 // generic autorepeats break generic and channeled spells
2617 InterruptSpell(CURRENT_GENERIC_SPELL);
2618 InterruptSpell(CURRENT_CHANNELED_SPELL);
2620 else
2622 // special action: set first cast flag for Auto Shoot
2623 m_AutoRepeatFirstCast = true;
2625 } break;
2627 default:
2629 // other spell types don't break anything now
2630 } break;
2633 // current spell (if it is still here) may be safely deleted now
2634 if (m_currentSpells[CSpellType])
2635 m_currentSpells[CSpellType]->SetDeletable(true);
2637 // set new current spell
2638 m_currentSpells[CSpellType] = pSpell;
2641 void Unit::InterruptSpell(uint32 spellType)
2643 assert(spellType < CURRENT_MAX_SPELL);
2645 if(m_currentSpells[spellType])
2647 // send autorepeat cancel message for autorepeat spells
2648 if (spellType == CURRENT_AUTOREPEAT_SPELL)
2650 if(GetTypeId()==TYPEID_PLAYER)
2651 ((Player*)this)->SendAutoRepeatCancel();
2654 if (m_currentSpells[spellType]->getState() != SPELL_STATE_FINISHED)
2655 m_currentSpells[spellType]->cancel();
2656 m_currentSpells[spellType]->SetDeletable(true);
2657 m_currentSpells[spellType] = NULL;
2661 bool Unit::IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled, bool skipAutorepeat)
2663 // We don't do loop here to explicitly show that melee spell is excluded.
2664 // Maybe later some special spells will be excluded too.
2666 // generic spells are casted when they are not finished and not delayed
2667 if ( m_currentSpells[CURRENT_GENERIC_SPELL] &&
2668 (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) &&
2669 (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) )
2670 return(true);
2672 // channeled spells may be delayed, but they are still considered casted
2673 else if ( !skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
2674 (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED) )
2675 return(true);
2677 // autorepeat spells may be finished or delayed, but they are still considered casted
2678 else if ( !skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL] )
2679 return(true);
2681 return(false);
2684 void Unit::InterruptNonMeleeSpells(bool withDelayed)
2686 // generic spells are interrupted if they are not finished or delayed
2687 if (m_currentSpells[CURRENT_GENERIC_SPELL])
2689 if ( (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) &&
2690 (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) )
2691 m_currentSpells[CURRENT_GENERIC_SPELL]->cancel();
2692 m_currentSpells[CURRENT_GENERIC_SPELL]->SetDeletable(true);
2693 m_currentSpells[CURRENT_GENERIC_SPELL] = NULL;
2696 // autorepeat spells are interrupted if they are not finished or delayed
2697 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
2699 // send disable autorepeat packet in any case
2700 if(GetTypeId()==TYPEID_PLAYER)
2701 ((Player*)this)->SendAutoRepeatCancel();
2703 if ( (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_FINISHED) &&
2704 (withDelayed || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_DELAYED) )
2705 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->cancel();
2706 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SetDeletable(true);
2707 m_currentSpells[CURRENT_AUTOREPEAT_SPELL] = NULL;
2710 // channeled spells are interrupted if they are not finished, even if they are delayed
2711 if (m_currentSpells[CURRENT_CHANNELED_SPELL])
2713 if (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED)
2714 m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel();
2715 m_currentSpells[CURRENT_CHANNELED_SPELL]->SetDeletable(true);
2716 m_currentSpells[CURRENT_CHANNELED_SPELL] = NULL;
2720 bool Unit::isInFront(Unit const* target, float radius) const
2722 return IsWithinDistInMap(target, radius) && HasInArc( M_PI, target );
2725 void Unit::SetInFront(Unit const* target)
2727 SetOrientation(GetAngle(target));
2730 bool Unit::isInAccessablePlaceFor(Creature* c) const
2732 if(IsInWater())
2733 return c->isCanSwimOrFly();
2734 else
2735 return c->isCanWalkOrFly();
2738 bool Unit::IsInWater() const
2740 return MapManager::Instance().GetMap(GetMapId(), this)->IsInWater(GetPositionX(),GetPositionY(), GetPositionZ());
2743 bool Unit::IsUnderWater() const
2745 return MapManager::Instance().GetMap(GetMapId(), this)->IsUnderWater(GetPositionX(),GetPositionY(),GetPositionZ());
2748 void Unit::DeMorph()
2750 SetUInt32Value(UNIT_FIELD_DISPLAYID, GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID));
2753 long Unit::GetTotalAuraModifier(uint32 ModifierID) const
2755 uint32 modifier = 0;
2757 AuraList const& mTotalAuraList = GetAurasByType(ModifierID);
2758 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
2759 modifier += (*i)->GetModifier()->m_amount;
2761 return modifier;
2764 bool Unit::AddAura(Aura *Aur, bool uniq)
2766 // ghost spell check
2767 if (!isAlive() && !(Aur->GetSpellProto()->Id == 20584 || Aur->GetSpellProto()->Id == 8326))
2769 delete Aur;
2770 return false;
2773 if(Aur->GetTarget() != this)
2775 sLog.outError("Aura (spell %u eff %u) add to aura list of %s (lowguid: %u) but Aura target is %s (lowguid: %u)",
2776 Aur->GetId(),Aur->GetEffIndex(),(GetTypeId()==TYPEID_PLAYER?"player":"creature"),GetGUIDLow(),
2777 (Aur->GetTarget()->GetTypeId()==TYPEID_PLAYER?"player":"creature"),Aur->GetTarget()->GetGUIDLow());
2778 delete Aur;
2779 return false;
2782 AuraMap::iterator i = m_Auras.find( spellEffectPair(Aur->GetId(), Aur->GetEffIndex()) );
2784 // take out same spell
2785 if (i != m_Auras.end())
2787 /*(*i).second->SetAuraDuration(Aur->GetAuraDuration());
2788 if ((*i).second->GetTarget())
2789 if ((*i).second->GetTarget()->GetTypeId() == TYPEID_PLAYER )
2790 (*i).second->UpdateAuraDuration();
2791 delete Aur;
2792 return false;*/
2793 // passive and persistent auras can stack with themselves any number of times
2794 if (!Aur->IsPassive() && !Aur->IsPersistent() && m_Auras.count(spellEffectPair(Aur->GetId(), Aur->GetEffIndex())) >= Aur->GetSpellProto()->StackAmount)
2795 RemoveAura(i);
2798 // passive auras stack with all (except passive spell proc auras)
2799 if ((!Aur->IsPassive() || !IsPassiveStackableSpell(Aur->GetId())) &&
2800 !(Aur->GetSpellProto()->Id == 20584 || Aur->GetSpellProto()->Id == 8326))
2802 if (!RemoveNoStackAurasDueToAura(Aur))
2804 delete Aur;
2805 return false; // couldnt remove conflicting aura with higher rank
2809 // adding linked auras
2810 // add the shapeshift aura's boosts
2811 if(Aur->GetModifier()->m_auraname == SPELL_AURA_MOD_SHAPESHIFT)
2812 Aur->HandleShapeshiftBoosts(true);
2814 Aur->_AddAura();
2815 m_Auras.insert(AuraMap::value_type(spellEffectPair(Aur->GetId(), Aur->GetEffIndex()), Aur));
2816 if (Aur->GetModifier()->m_auraname < TOTAL_AURAS)
2818 m_modAuras[Aur->GetModifier()->m_auraname].push_back(Aur);
2819 m_AuraModifiers[Aur->GetModifier()->m_auraname] += (Aur->GetModifier()->m_amount);
2822 if (IsSingleTarget(Aur->GetId()) && Aur->GetTarget() && Aur->GetSpellProto())
2824 if(Unit* caster = Aur->GetCaster())
2826 AuraList& scAuras = caster->GetSingleCastAuras();
2827 AuraList::iterator itr, next;
2828 for (itr = scAuras.begin(); itr != scAuras.end(); itr = next)
2830 next = itr;
2831 next++;
2832 if ((*itr)->GetTarget() != Aur->GetTarget() &&
2833 (*itr)->GetSpellProto()->Category == Aur->GetSpellProto()->Category &&
2834 (*itr)->GetSpellProto()->SpellIconID == Aur->GetSpellProto()->SpellIconID &&
2835 (*itr)->GetSpellProto()->SpellVisual == Aur->GetSpellProto()->SpellVisual &&
2836 (*itr)->GetSpellProto()->Attributes == Aur->GetSpellProto()->Attributes &&
2837 (*itr)->GetSpellProto()->AttributesEx == Aur->GetSpellProto()->AttributesEx &&
2838 (*itr)->GetSpellProto()->AttributesExEx == Aur->GetSpellProto()->AttributesExEx)
2840 (*itr)->GetTarget()->RemoveAura((*itr)->GetId(), (*itr)->GetEffIndex());
2841 if(scAuras.empty())
2842 break;
2843 else
2844 next = scAuras.begin();
2847 scAuras.push_back(Aur);
2850 return true;
2853 void Unit::RemoveRankAurasDueToSpell(uint32 spellId)
2855 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
2856 if(!spellInfo)
2857 return;
2858 AuraMap::iterator i,next;
2859 for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
2861 next = i;
2862 next++;
2863 uint32 i_spellId = (*i).second->GetId();
2864 if((*i).second && i_spellId && i_spellId != spellId)
2866 if(objmgr.IsRankSpellDueToSpell(spellInfo,i_spellId))
2868 RemoveAurasDueToSpell(i_spellId);
2870 if( m_Auras.empty() )
2871 break;
2872 else
2873 next = m_Auras.begin();
2879 bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur)
2881 if (!Aur)
2882 return false;
2884 SpellEntry const* spellProto = Aur->GetSpellProto();
2885 if (!spellProto)
2886 return false;
2888 uint32 spellId = Aur->GetId();
2889 uint32 effIndex = Aur->GetEffIndex();
2890 bool is_sec = IsSpellSingleEffectPerCaster(spellId);
2891 AuraMap::iterator i,next;
2892 for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
2894 next = i;
2895 next++;
2896 if (!(*i).second) continue;
2898 if (!(*i).second->GetSpellProto())
2899 continue;
2901 uint32 i_spellId = (*i).second->GetId();
2903 if(IsPassiveSpell(i_spellId))
2905 if(IsPassiveStackableSpell(i_spellId))
2906 continue;
2908 // passive non-stackable spells not stackable only with another rank of same spell
2909 if (!objmgr.IsRankSpellDueToSpell(Aur->GetSpellProto(), i_spellId))
2910 continue;
2913 uint32 i_effIndex = (*i).second->GetEffIndex();
2915 if(i_spellId == spellId) continue;
2917 bool is_triggered_by_spell = false;
2918 // prevent triggered aura of removing aura that triggered it
2919 for(int j = 0; j < 3; ++j)
2920 if ((*i).second->GetSpellProto()->EffectTriggerSpell[j] == spellProto->Id)
2921 is_triggered_by_spell = true;
2922 if (is_triggered_by_spell) continue;
2924 // prevent remove dummy triggered spells at next effect aura add
2925 for(int j = 0; j < 3; ++j)
2927 switch(spellProto->Effect[j])
2929 case SPELL_EFFECT_DUMMY:
2930 switch(spellId)
2932 case 5420: if(i_spellId==34123) is_triggered_by_spell = true; break;
2934 break;
2936 if(is_triggered_by_spell)
2937 break;
2939 switch(spellProto->EffectApplyAuraName[j])
2941 case SPELL_AURA_MOD_SHAPESHIFT:
2942 switch(spellId)
2944 case 33891: if(i_spellId==5420 || i_spellId==34123) is_triggered_by_spell = true; break;
2946 break;
2950 if(!is_triggered_by_spell)
2952 bool sec_match = false;
2953 bool is_i_sec = IsSpellSingleEffectPerCaster(i_spellId);
2954 if( is_sec && is_i_sec )
2955 if (Aur->GetCasterGUID() == (*i).second->GetCasterGUID())
2956 if (GetSpellSpecific(spellId) == GetSpellSpecific(i_spellId))
2957 sec_match = true;
2958 if( sec_match || objmgr.IsNoStackSpellDueToSpell(spellId, i_spellId) && !is_sec && !is_i_sec )
2960 // if sec_match this isn't always true, needs to be rechecked
2961 if (objmgr.IsRankSpellDueToSpell(Aur->GetSpellProto(), i_spellId))
2962 if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
2963 return false; // cannot remove higher rank
2965 RemoveAurasDueToSpell(i_spellId);
2967 if( m_Auras.empty() )
2968 break;
2969 else
2970 next = m_Auras.begin();
2972 else // Potions stack aura by aura
2973 if (Aur->GetSpellProto()->SpellFamilyName == SPELLFAMILY_POTION &&
2974 (*i).second->GetSpellProto()->SpellFamilyName == SPELLFAMILY_POTION)
2976 if (IsNoStackAuraDueToAura(spellId, effIndex, i_spellId, i_effIndex))
2978 if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
2979 return false; // cannot remove higher rank
2981 RemoveAura(i);
2982 next = i;
2987 return true;
2990 void Unit::RemoveFirstAuraByDispel(uint32 dispel_type, Unit *pCaster)
2992 AuraMap::iterator i;
2993 for (i = m_Auras.begin(); i != m_Auras.end();)
2995 if ((*i).second && (*i).second->GetSpellProto()->Dispel == dispel_type)
2997 if(dispel_type == 1)
2999 bool positive = true;
3000 switch((*i).second->GetSpellProto()->EffectImplicitTargetA[(*i).second->GetEffIndex()])
3002 case TARGET_CHAIN_DAMAGE:
3003 case TARGET_ALL_ENEMY_IN_AREA:
3004 case TARGET_ALL_ENEMY_IN_AREA_INSTANT:
3005 case TARGET_ALL_ENEMIES_AROUND_CASTER:
3006 case TARGET_IN_FRONT_OF_CASTER:
3007 case TARGET_DUELVSPLAYER:
3008 case TARGET_ALL_ENEMY_IN_AREA_CHANNELED:
3009 case TARGET_CURRENT_SELECTED_ENEMY:
3010 positive = false;
3011 break;
3013 default:
3014 positive = ((*i).second->GetSpellProto()->AttributesEx & (1<<7)) ? false : true;
3016 if(positive && IsFriendlyTo(pCaster)) // PBW
3018 ++i;
3019 continue;
3022 RemoveAura(i);
3023 break;
3025 else
3026 ++i;
3030 void Unit::RemoveAreaAurasByOthers(uint64 guid)
3032 int j = 0;
3033 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end();)
3035 if (i->second && i->second->IsAreaAura())
3037 uint64 casterGuid = i->second->GetCasterGUID();
3038 uint64 targetGuid = i->second->GetTarget()->GetGUID();
3039 // if area aura cast by someone else or by the specified caster
3040 if (casterGuid == guid || (guid == 0 && casterGuid != targetGuid))
3042 for (j = 0; j < 4; j++)
3043 if (m_TotemSlot[j] == casterGuid)
3044 break;
3045 // and not by one of my totems
3046 if (j == 4)
3047 RemoveAura(i);
3048 else
3049 ++i;
3051 else
3052 ++i;
3054 else
3055 ++i;
3059 void Unit::RemoveAura(uint32 spellId, uint32 effindex)
3061 AuraMap::iterator iter;
3062 while((iter = m_Auras.find(spellEffectPair(spellId, effindex))) != m_Auras.end())
3063 RemoveAura(iter);
3066 void Unit::RemoveAurasDueToSpell(uint32 spellId)
3068 for (int i = 0; i < 3; ++i)
3069 RemoveAura(spellId,i);
3072 void Unit::RemoveAurasDueToItem(Item* castItem)
3074 for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
3076 if (iter->second->GetCastItemGUID() == castItem->GetGUID())
3077 RemoveAura(iter);
3078 else
3079 ++iter;
3083 void Unit::RemoveAura(AuraMap::iterator &i, bool onDeath)
3085 if (IsSingleTarget((*i).second->GetId()))
3087 if(Unit* caster = (*i).second->GetCaster())
3089 AuraList& scAuras = caster->GetSingleCastAuras();
3090 scAuras.remove((*i).second);
3092 else
3093 sLog.outError("Unit::RemoveAura: cannot remove the single cast aura from the caster, potential crash!");
3095 // remove aura from party members when the caster turns off the aura
3096 if((*i).second->IsAreaAura())
3098 Unit *i_target = (*i).second->GetTarget();
3099 if((*i).second->GetCasterGUID() == i_target->GetGUID())
3101 Unit* i_caster = i_target;
3103 Unit* owner = NULL;
3104 Group *pGroup = NULL;
3105 Player *pGroupOf = NULL;
3106 if (i_caster->GetTypeId() == TYPEID_PLAYER)
3108 pGroupOf = (Player*)i_caster;
3109 pGroup = pGroupOf->GetGroup();
3111 else if(((Creature*)i_caster)->isTotem() || ((Creature*)i_caster)->isPet() || i_caster->isCharmed())
3113 owner = i_caster->GetCharmerOrOwner();
3114 if (owner && owner->GetTypeId() == TYPEID_PLAYER)
3116 pGroupOf = (Player*)owner;
3117 pGroup = pGroupOf->GetGroup();
3121 //float radius = GetRadius(sSpellRadiusStore.LookupEntry((*i).second->GetSpellProto()->EffectRadiusIndex[(*i).second->GetEffIndex()]));
3122 if(pGroup && pGroupOf)
3124 for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
3126 Player* Target = itr->getSource();
3127 if(!Target || !pGroup->SameSubGroup(pGroupOf, Target))
3128 continue;
3130 if(Target->GetGUID() == i_caster->GetGUID())
3131 continue;
3132 Aura *t_aura = Target->GetAura((*i).second->GetId(), (*i).second->GetEffIndex());
3133 if (t_aura)
3134 if (t_aura->GetCasterGUID() == i_caster->GetGUID())
3135 Target->RemoveAura((*i).second->GetId(), (*i).second->GetEffIndex());
3138 else if(owner)
3140 Aura *t_aura = owner->GetAura((*i).second->GetId(), (*i).second->GetEffIndex());
3141 if (t_aura)
3142 if (t_aura->GetCasterGUID() == i_caster->GetGUID())
3143 owner->RemoveAura((*i).second->GetId(), (*i).second->GetEffIndex());
3147 if ((*i).second->GetModifier()->m_auraname < TOTAL_AURAS)
3149 m_AuraModifiers[(*i).second->GetModifier()->m_auraname] -= ((*i).second->GetModifier()->m_amount);
3150 m_modAuras[(*i).second->GetModifier()->m_auraname].remove((*i).second);
3152 (*i).second->SetRemoveOnDeath(onDeath);
3154 // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
3155 Aura* Aur = i->second;
3157 DiminishingMechanics mech = DIMINISHING_NONE;
3158 if(Aur->GetSpellProto()->Mechanic)
3160 mech = Unit::Mechanic2DiminishingMechanics(Aur->GetSpellProto()->Mechanic);
3161 if(mech == DIMINISHING_MECHANIC_STUN || GetTypeId() == TYPEID_PLAYER && mech != DIMINISHING_NONE)
3162 UpdateDiminishingTime(mech);
3165 // must remove before removing from list (its remove dependent auras and _i_ is only safe iterator value
3166 // remove the shapeshift aura's boosts
3167 if(Aur->GetModifier()->m_auraname == SPELL_AURA_MOD_SHAPESHIFT)
3168 Aur->HandleShapeshiftBoosts(false);
3170 m_Auras.erase(i);
3171 m_removedAuras++; // internal count used by unit update
3173 Aur->_RemoveAura();
3174 delete Aur;
3176 // only way correctly remove all auras from list
3177 if( m_Auras.empty() )
3178 i = m_Auras.end();
3179 else
3180 i = m_Auras.begin();
3183 bool Unit::SetAurDuration(uint32 spellId, uint32 effindex,uint32 duration)
3185 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
3186 if (iter != m_Auras.end())
3188 (*iter).second->SetAuraDuration(duration);
3189 (*iter).second->UpdateAuraDuration();
3190 return true;
3192 return false;
3195 uint32 Unit::GetAurDuration(uint32 spellId, uint32 effindex)
3197 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
3198 if (iter != m_Auras.end())
3200 return (*iter).second->GetAuraDuration();
3202 return 0;
3205 void Unit::RemoveAllAuras()
3207 while (!m_Auras.empty())
3209 AuraMap::iterator iter = m_Auras.begin();
3210 RemoveAura(iter);
3214 void Unit::RemoveAllAurasOnDeath()
3216 // used just after dieing to remove all visible auras
3217 // and disable the mods for the passive ones
3218 for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
3220 if (!iter->second->IsPassive())
3221 RemoveAura(iter, true);
3222 else
3223 ++iter;
3227 void Unit::DelayAura(uint32 spellId, uint32 effindex, int32 delaytime)
3229 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
3230 if (iter != m_Auras.end())
3232 if (iter->second->GetAuraDuration() < delaytime)
3233 iter->second->SetAuraDuration(0);
3234 else
3235 iter->second->SetAuraDuration(iter->second->GetAuraDuration() - delaytime);
3236 iter->second->UpdateAuraDuration();
3237 sLog.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter->second->GetModifier()->m_auraname, GetGUIDLow(), iter->second->GetAuraDuration());
3241 void Unit::_RemoveAllAuraMods()
3243 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
3245 (*i).second->ApplyModifier(false);
3249 void Unit::_ApplyAllAuraMods()
3251 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
3253 (*i).second->ApplyModifier(true);
3257 // TODO: FIX-ME!!!
3258 /*void Unit::_UpdateAura()
3260 if(GetTypeId() != TYPEID_PLAYER || !m_Auras)
3261 return;
3263 Player* pThis = (Player*)this;
3265 Player* pGroupGuy;
3266 Group* pGroup;
3268 pGroup = objmgr.GetGroupByLeader(pThis->GetGroupLeader());
3270 if(!SetAffDuration(m_Auras->GetId(),this,6000))
3271 AddAura(m_Auras);
3273 if(!pGroup)
3274 return;
3275 else
3277 for(uint32 i=0;i<pGroup->GetMembersCount();i++)
3279 pGroupGuy = ObjectAccessor::Instance().FindPlayer(pGroup->GetMemberGUID(i));
3281 if(!pGroupGuy)
3282 continue;
3283 if(pGroupGuy->GetGUID() == GetGUID())
3284 continue;
3285 if(sqrt(
3286 (GetPositionX()-pGroupGuy->GetPositionX())*(GetPositionX()-pGroupGuy->GetPositionX())
3287 +(GetPositionY()-pGroupGuy->GetPositionY())*(GetPositionY()-pGroupGuy->GetPositionY())
3288 +(GetPositionZ()-pGroupGuy->GetPositionZ())*(GetPositionZ()-pGroupGuy->GetPositionZ())
3289 ) <=30)
3291 if(!pGroupGuy->SetAffDuration(m_Auras->GetId(),this,6000))
3292 pGroupGuy->AddAura(m_Auras);
3294 else
3296 if(m_removeAuraTimer == 0)
3298 printf("remove aura from %u\n", pGroupGuy->GetGUID());
3299 pGroupGuy->RemoveAura(m_Auras->GetId());
3304 if(m_removeAuraTimer > 0)
3305 m_removeAuraTimer -= 1;
3306 else
3307 m_removeAuraTimer = 4;
3310 Aura* Unit::GetAura(uint32 spellId, uint32 effindex)
3312 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
3313 if (iter != m_Auras.end())
3314 return iter->second;
3315 return NULL;
3318 void Unit::AddDynObject(DynamicObject* dynObj)
3320 m_dynObjGUIDs.push_back(dynObj->GetGUID());
3323 void Unit::RemoveDynObject(uint32 spellid)
3325 if(m_dynObjGUIDs.empty())
3326 return;
3327 for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
3329 DynamicObject* dynObj = ObjectAccessor::Instance().GetDynamicObject(*this,*m_dynObjGUIDs.begin());
3330 if(!dynObj)
3332 i = m_dynObjGUIDs.erase(i);
3334 else if(spellid == 0 || dynObj->GetSpellId() == spellid)
3336 dynObj->Delete();
3337 i = m_dynObjGUIDs.erase(i);
3339 else
3340 ++i;
3344 DynamicObject * Unit::GetDynObject(uint32 spellId, uint32 effIndex)
3346 for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
3348 DynamicObject* dynObj = ObjectAccessor::Instance().GetDynamicObject(*this,*m_dynObjGUIDs.begin());
3349 if(!dynObj)
3351 i = m_dynObjGUIDs.erase(i);
3352 continue;
3355 if (dynObj->GetSpellId() == spellId && dynObj->GetEffIndex() == effIndex)
3356 return dynObj;
3357 ++i;
3359 return NULL;
3362 void Unit::AddGameObject(GameObject* gameObj)
3364 assert(gameObj && gameObj->GetOwnerGUID()==0);
3365 m_gameObj.push_back(gameObj);
3366 gameObj->SetOwnerGUID(GetGUID());
3369 void Unit::RemoveGameObject(GameObject* gameObj, bool del)
3371 assert(gameObj && gameObj->GetOwnerGUID()==GetGUID());
3372 gameObj->SetOwnerGUID(0);
3373 m_gameObj.remove(gameObj);
3374 if(del)
3376 gameObj->SetRespawnTime(0);
3377 gameObj->Delete();
3381 void Unit::RemoveGameObject(uint32 spellid, bool del)
3383 if(m_gameObj.empty())
3384 return;
3385 std::list<GameObject*>::iterator i, next;
3386 for (i = m_gameObj.begin(); i != m_gameObj.end(); i = next)
3388 next = i;
3389 if(spellid == 0 || (*i)->GetSpellId() == spellid)
3391 (*i)->SetOwnerGUID(0);
3392 if(del)
3394 (*i)->SetRespawnTime(0);
3395 (*i)->Delete();
3398 next = m_gameObj.erase(i);
3400 else
3401 ++next;
3405 void Unit::SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, SpellSchools DamageType,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit)
3407 WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16+31)); // we guess size
3408 data.append(target->GetPackGUID());
3409 data.append(GetPackGUID());
3410 data << uint32(SpellID);
3411 data << uint32(Damage-AbsorbedDamage-Resist-Blocked);
3412 data << uint8(DamageType); //damagetype
3413 data << uint32(AbsorbedDamage); //AbsorbedDamage
3414 data << uint32(Resist); //resist
3415 data << (uint8)PhysicalDamage;
3416 data << uint8(0);
3417 data << uint32(Blocked); //blocked
3418 data << uint8(CriticalHit ? 2 : 0); //seen 0x05 also...
3419 data << uint32(0);
3420 SendMessageToSet( &data, true );
3423 void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SpellSchools DamageType, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, uint32 TargetState, uint32 BlockedAmount)
3425 sLog.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
3427 WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16+45)); // we guess size
3428 data << (uint32)HitInfo;
3429 data.append(GetPackGUID());
3430 data.append(target->GetPackGUID());
3431 data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount);
3433 data << (uint8)SwingType;
3434 data << (uint32)DamageType;
3437 data << (float)(Damage-AbsorbDamage-Resist-BlockedAmount);
3438 // still need to double check damaga
3439 data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount);
3440 data << (uint32)AbsorbDamage;
3441 data << (uint32)Resist;
3442 data << (uint32)TargetState;
3444 if( AbsorbDamage == 0 ) //also 0x3E8 = 0x3E8, check when that happens
3445 data << (uint32)0;
3446 else
3447 data << (uint32)-1;
3449 data << (uint32)0;
3450 data << (uint32)BlockedAmount;
3452 SendMessageToSet( &data, true );
3455 struct ProcTriggeredData
3457 ProcTriggeredData(SpellEntry const * _spellInfo, uint32 _spellParam, Aura* _triggeredByAura)
3458 : spellInfo(_spellInfo), spellParam(_spellParam), triggeredByAura(_triggeredByAura) {}
3460 SpellEntry const * spellInfo;
3461 uint32 spellParam;
3462 Aura* triggeredByAura;
3465 typedef std::list< ProcTriggeredData > ProcTriggeredList;
3467 // used to prevent spam in log about same non-handled spells
3468 static std::set<uint32> nonHandledSpellProcSet;
3470 void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 damage, SpellEntry const *procSpell, bool isTriggeredSpell, WeaponAttackType attType)
3472 sLog.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker, procVictim);
3473 if(procSpell)
3474 sLog.outDebug("ProcDamageAndSpell: invoked due to spell id %u %s", procSpell->Id, (isTriggeredSpell?"(triggered)":""));
3476 // Assign melee/ranged proc flags for magic attacks, that are actually melee/ranged abilities
3477 // not assign for spell proc triggered spell to prevent infinity (or unexpacted 2-3 times) melee damage spell proc call with melee damage effect
3478 // That is the question though if it's fully correct
3479 if(procSpell && !isTriggeredSpell)
3481 if(procSpell->DmgClass == SPELL_DAMAGE_CLASS_MELEE)
3483 if(procAttacker & PROC_FLAG_HIT_SPELL) procAttacker |= PROC_FLAG_HIT_MELEE;
3484 if(procAttacker & PROC_FLAG_CRIT_SPELL) procAttacker |= PROC_FLAG_CRIT_MELEE;
3485 if(procVictim & PROC_FLAG_STRUCK_SPELL) procVictim |= PROC_FLAG_STRUCK_MELEE;
3486 if(procVictim & PROC_FLAG_STRUCK_CRIT_SPELL) procVictim |= PROC_FLAG_STRUCK_CRIT_MELEE;
3487 attType = BASE_ATTACK; // Melee abilities are assumed to be dealt with mainhand weapon
3489 else if (procSpell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
3491 if(procAttacker & PROC_FLAG_HIT_SPELL) procAttacker |= PROC_FLAG_HIT_RANGED;
3492 if(procAttacker & PROC_FLAG_CRIT_SPELL) procAttacker |= PROC_FLAG_CRIT_RANGED;
3493 if(procVictim & PROC_FLAG_STRUCK_SPELL) procVictim |= PROC_FLAG_STRUCK_RANGED;
3494 if(procVictim & PROC_FLAG_STRUCK_CRIT_SPELL) procVictim |= PROC_FLAG_STRUCK_CRIT_RANGED;
3495 attType = RANGED_ATTACK;
3498 if(damage && (procVictim & (PROC_FLAG_STRUCK_MELEE|PROC_FLAG_STRUCK_RANGED|PROC_FLAG_STRUCK_SPELL)))
3499 procVictim |= (PROC_FLAG_TAKE_DAMAGE|PROC_FLAG_TOUCH);
3501 // Not much to do if no flags are set.
3502 if (procAttacker)
3504 for(std::set<uint32>::iterator aur = attackerProcAuraTypes.begin(); aur != attackerProcAuraTypes.end(); ++aur)
3506 // List of spells (effects) that proced. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
3507 ProcTriggeredList procTriggered;
3509 AuraList const& attackerAuras = GetAurasByType(*aur);
3510 for(AuraList::const_iterator i = attackerAuras.begin(), next; i != attackerAuras.end(); i = next)
3512 next = i; next++;
3513 uint32 procFlag = procAttacker;
3515 SpellEntry const *spellProto = (*i)->GetSpellProto();
3516 if(!spellProto) continue;
3517 SpellProcEventEntry const *spellProcEvent = objmgr.GetSpellProcEvent(spellProto->Id);
3519 if(!spellProcEvent && spellProto->procFlags != 0 && nonHandledSpellProcSet.find(spellProto->Id)==nonHandledSpellProcSet.end())
3521 sLog.outError("ProcDamageAndSpell: spell %u (attacker's aura source) not have record in `spell_proc_event`)",spellProto->Id);
3522 nonHandledSpellProcSet.insert(spellProto->Id);
3525 uint32 procFlags = spellProcEvent ? spellProcEvent->procFlags : spellProto->procFlags;
3526 // Check if current equipment allows aura to proc
3527 if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->IsUseEquipedWeapon())
3529 if(spellProto->EquippedItemClass == ITEM_CLASS_WEAPON)
3531 Item *item = NULL;
3532 if(attType == BASE_ATTACK)
3533 item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
3534 else if (attType == OFF_ATTACK)
3535 item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
3536 else
3537 item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
3539 if(!item || item->IsBroken() || item->GetProto()->Class != ITEM_CLASS_WEAPON || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
3540 continue;
3542 else if(spellProto->EquippedItemClass == ITEM_CLASS_ARMOR)
3544 // Check if player is wearing shield
3545 Item *item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
3546 if(!item || item->IsBroken() || item->GetProto()->Class != ITEM_CLASS_ARMOR || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
3547 continue;
3550 if((procFlag & procFlags) == 0)
3551 continue;
3553 // Additional checks in case spell cast/hit/crit is the event
3554 // Check (if set) school, category, skill line, spell talent mask
3555 if(spellProcEvent)
3557 if(spellProcEvent->schoolMask && (!procSpell || !procSpell->School || ((1<<procSpell->School) & spellProcEvent->schoolMask) == 0))
3558 continue;
3559 if(spellProcEvent->category && (!procSpell || procSpell->Category != spellProcEvent->category))
3560 continue;
3561 if(spellProcEvent->skillId)
3563 if (!procSpell) continue;
3564 SkillLineAbilityEntry const *skillLineEntry = sSkillLineAbilityStore.LookupEntry(procSpell->Id);
3565 if(!skillLineEntry || skillLineEntry->skillId != spellProcEvent->skillId)
3566 continue;
3568 if(spellProcEvent->spellFamilyName && (!procSpell || spellProcEvent->spellFamilyName != procSpell->SpellFamilyName))
3569 continue;
3570 if(spellProcEvent->spellFamilyMask && (!procSpell || (spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags) == 0))
3571 continue;
3574 // Need to use floats here, cuz calculated PPM chance often is about 1-2%
3575 float chance = (float)spellProto->procChance;
3576 if(GetTypeId() == TYPEID_PLAYER)
3577 ((Player*)this)->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance);
3578 uint32 WeaponSpeed = GetAttackTime(attType);
3579 if(spellProcEvent && spellProcEvent->ppmRate != 0)
3580 chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate);
3582 if(roll_chance_f(chance))
3584 if((*i)->m_procCharges > 0)
3585 (*i)->m_procCharges -= 1;
3587 uint32 i_spell_eff = (*i)->GetEffIndex();
3589 int32 i_spell_param;
3590 switch(*aur)
3592 case SPELL_AURA_PROC_TRIGGER_SPELL: i_spell_param = procFlag; break;
3593 case SPELL_AURA_DUMMY: i_spell_param = i_spell_eff; break;
3594 default: i_spell_param = (*i)->GetModifier()->m_amount; break;
3597 procTriggered.push_back( ProcTriggeredData(spellProto,i_spell_param,*i) );
3601 // Handle effects proceed this time
3602 for(ProcTriggeredList::iterator i = procTriggered.begin(); i != procTriggered.end(); i++)
3604 if(*aur == SPELL_AURA_PROC_TRIGGER_SPELL)
3606 sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered by an attacker's aura of spell %u)", i->spellInfo->Id,i->triggeredByAura->GetId());
3607 HandleProcTriggerSpell(pVictim, damage, i->triggeredByAura, procSpell,i->spellParam);
3609 else if(*aur == SPELL_AURA_PROC_TRIGGER_DAMAGE)
3611 sLog.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by an attacker's aura of spell %u)", i->spellParam, i->spellInfo->Id,i->triggeredByAura->GetId());
3612 uint32 damage = i->spellParam;
3613 // TODO: remove hack for Seal of Righteousness. That should not be there
3614 if(i->spellInfo->SpellVisual == 7986)
3615 damage = (damage * GetAttackTime(BASE_ATTACK))/60/1000;
3616 if(pVictim && pVictim->isAlive())
3617 SpellNonMeleeDamageLog(pVictim, i->spellInfo->Id, damage, true, true);
3619 else if(*aur == SPELL_AURA_DUMMY)
3621 // TODO: write a DUMMY aura handle code
3622 if (pVictim && pVictim->isAlive())
3624 sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by an attacker dummy aura of spell %u)", i->spellInfo->Id,i->triggeredByAura->GetId());
3625 HandleDummyAuraProc(pVictim, i->spellInfo, i->spellParam, damage, i->triggeredByAura, procSpell, procAttacker);
3630 // Safely remove attacker auras with zero charges
3631 for(AuraList::const_iterator i = attackerAuras.begin(), next; i != attackerAuras.end(); i = next)
3633 next = i; ++next;
3634 if((*i)->m_procCharges == 0)
3636 RemoveAurasDueToSpell((*i)->GetId());
3637 next = attackerAuras.begin();
3643 // Now go on with a victim's events'n'auras
3644 // Not much to do if no flags are set or there is no victim
3645 if(pVictim && pVictim->isAlive() && procVictim)
3647 for(std::set<uint32>::iterator aur = victimProcAuraTypes.begin(); aur != victimProcAuraTypes.end(); aur++)
3649 // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
3650 ProcTriggeredList procTriggered;
3652 AuraList const& victimAuras = pVictim->GetAurasByType(*aur);
3653 for(AuraList::const_iterator i = victimAuras.begin(), next; i != victimAuras.end(); i = next)
3655 next = i; next++;
3656 uint32 procFlag = procVictim;
3658 SpellEntry const *spellProto = (*i)->GetSpellProto();
3659 if(!spellProto) continue;
3660 SpellProcEventEntry const *spellProcEvent = objmgr.GetSpellProcEvent(spellProto->Id);
3662 if(!spellProcEvent && spellProto->procFlags != 0 && nonHandledSpellProcSet.find(spellProto->Id)==nonHandledSpellProcSet.end())
3664 sLog.outError("ProcDamageAndSpell: spell %u (victim's aura source) not have record in `spell_proc_event`)",spellProto->Id);
3665 nonHandledSpellProcSet.insert(spellProto->Id);
3668 uint32 procFlags = spellProcEvent ? spellProcEvent->procFlags : spellProto->procFlags;
3669 if((procFlag & procFlags) == 0)
3670 continue;
3672 // Additional checks in case spell cast/hit/crit is the event
3673 // Check (if set) school, category, skill line, spell talent mask
3674 if(spellProcEvent)
3676 if(spellProcEvent->schoolMask && (!procSpell || !procSpell->School || ((1<<procSpell->School) & spellProcEvent->schoolMask) == 0))
3677 continue;
3678 if(spellProcEvent->category && (!procSpell || procSpell->Category != spellProcEvent->category))
3679 continue;
3680 if(spellProcEvent->skillId)
3682 if (!procSpell) continue;
3683 SkillLineAbilityEntry const *skillLineEntry = sSkillLineAbilityStore.LookupEntry(procSpell->Id);
3684 if(!skillLineEntry || skillLineEntry->skillId != spellProcEvent->skillId)
3685 continue;
3687 if(spellProcEvent->spellFamilyName && (!procSpell || spellProcEvent->spellFamilyName != procSpell->SpellFamilyName))
3688 continue;
3689 if(spellProcEvent->spellFamilyMask && (!procSpell || (spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags) == 0))
3690 continue;
3693 // procChance is exact number in percents anyway
3694 uint32 chance = spellProto->procChance;
3695 if(pVictim->GetTypeId() == TYPEID_PLAYER)
3696 ((Player*)pVictim)->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance);
3697 if(roll_chance_i(chance))
3699 if((*i)->m_procCharges > 0)
3700 (*i)->m_procCharges -= 1;
3702 uint32 i_spell_eff = (*i)->GetEffIndex();
3703 int32 i_spell_param;
3704 switch(*aur)
3706 case SPELL_AURA_PROC_TRIGGER_SPELL: i_spell_param = procFlag; break;
3707 case SPELL_AURA_DUMMY: i_spell_param = i_spell_eff; break;
3708 default: i_spell_param = (*i)->GetModifier()->m_amount; break;
3711 procTriggered.push_back( ProcTriggeredData(spellProto,i_spell_param,*i) );
3715 // Handle effects proced this time
3716 for(ProcTriggeredList::iterator i = procTriggered.begin(); i != procTriggered.end(); i++)
3718 if(*aur == SPELL_AURA_PROC_TRIGGER_SPELL)
3720 sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered by a victim's aura of spell %u))",i->spellInfo->Id, i->triggeredByAura);
3721 pVictim->HandleProcTriggerSpell(this, damage, i->triggeredByAura, procSpell,i->spellParam);
3723 else if(*aur == SPELL_AURA_PROC_TRIGGER_DAMAGE)
3725 sLog.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by a victim's aura of spell %u))", i->spellParam, i->spellInfo->Id, i->triggeredByAura);
3726 pVictim->SpellNonMeleeDamageLog(this, i->spellInfo->Id, i->spellParam, true, true);
3728 else if(*aur == SPELL_AURA_DUMMY)
3730 // TODO: write a DUMMY aura handle code
3731 sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered by a victim's dummy aura of spell %u))",i->spellInfo->Id, i->triggeredByAura);
3732 pVictim->HandleDummyAuraProc(this, i->spellInfo, i->spellParam, damage, i->triggeredByAura, procSpell, procVictim);
3736 // Safely remove auras with zero charges
3737 for(AuraList::const_iterator i = victimAuras.begin(), next; i != victimAuras.end(); i = next)
3739 next = i; ++next;
3740 if((*i)->m_procCharges == 0)
3742 pVictim->RemoveAurasDueToSpell((*i)->GetId());
3743 next = victimAuras.begin();
3750 void Unit::CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, WeaponAttackType attType, MeleeHitOutcome outcome, SpellEntry const *spellCasted, bool isTriggeredSpell)
3752 if(!pVictim)
3753 return;
3755 uint32 procAttacker = PROC_FLAG_NONE;
3756 uint32 procVictim = PROC_FLAG_NONE;
3758 switch(outcome)
3760 case MELEE_HIT_MISS:
3761 if(attType == BASE_ATTACK || attType == OFF_ATTACK)
3763 procAttacker = PROC_FLAG_MISS;
3765 break;
3766 case MELEE_HIT_CRIT:
3767 if(spellCasted && attType == BASE_ATTACK)
3769 procAttacker |= PROC_FLAG_CRIT_SPELL;
3770 procVictim |= PROC_FLAG_STRUCK_CRIT_SPELL;
3772 else if(attType == BASE_ATTACK || attType == OFF_ATTACK)
3774 procAttacker = PROC_FLAG_HIT_MELEE | PROC_FLAG_CRIT_MELEE;
3775 procVictim = PROC_FLAG_STRUCK_MELEE | PROC_FLAG_STRUCK_CRIT_MELEE;
3777 else
3779 procAttacker = PROC_FLAG_HIT_RANGED | PROC_FLAG_CRIT_RANGED;
3780 procVictim = PROC_FLAG_STRUCK_RANGED | PROC_FLAG_STRUCK_CRIT_RANGED;
3782 break;
3783 case MELEE_HIT_PARRY:
3784 procAttacker = PROC_FLAG_TARGET_DODGE_OR_PARRY;
3785 procVictim = PROC_FLAG_PARRY;
3786 break;
3787 case MELEE_HIT_BLOCK:
3788 procAttacker = PROC_FLAG_TARGET_BLOCK;
3789 procVictim = PROC_FLAG_BLOCK;
3790 break;
3791 case MELEE_HIT_DODGE:
3792 procAttacker = PROC_FLAG_TARGET_DODGE_OR_PARRY;
3793 procVictim = PROC_FLAG_DODGE;
3794 break;
3795 case MELEE_HIT_CRUSHING:
3796 if(attType == BASE_ATTACK || attType == OFF_ATTACK)
3798 procAttacker = PROC_FLAG_HIT_MELEE | PROC_FLAG_CRIT_MELEE;
3799 procVictim = PROC_FLAG_STRUCK_MELEE | PROC_FLAG_STRUCK_CRIT_MELEE;
3801 else
3803 procAttacker = PROC_FLAG_HIT_RANGED | PROC_FLAG_CRIT_RANGED;
3804 procVictim = PROC_FLAG_STRUCK_RANGED | PROC_FLAG_STRUCK_CRIT_RANGED;
3806 break;
3807 default:
3808 if(attType == BASE_ATTACK || attType == OFF_ATTACK)
3810 procAttacker = PROC_FLAG_HIT_MELEE;
3811 procVictim = PROC_FLAG_STRUCK_MELEE;
3813 else
3815 procAttacker = PROC_FLAG_HIT_RANGED;
3816 procVictim = PROC_FLAG_STRUCK_RANGED;
3818 break;
3821 if(damage > 0)
3822 procVictim |= PROC_FLAG_TAKE_DAMAGE;
3824 if(procAttacker != PROC_FLAG_NONE || procVictim != PROC_FLAG_NONE)
3825 ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, spellCasted, isTriggeredSpell, attType);
3828 void Unit::HandleDummyAuraProc(Unit *pVictim, SpellEntry const *dummySpell, uint32 effIndex, uint32 damage, Aura* triggredByAura, SpellEntry const * procSpell, uint32 procFlag)
3830 switch(dummySpell->Id )
3832 // Ignite
3833 case 11119:
3834 case 11120:
3835 case 12846:
3836 case 12847:
3837 case 12848:
3839 if(!pVictim)
3840 return;
3842 int32 igniteDotBasePoints0;
3844 switch (dummySpell->Id)
3846 case 11119: igniteDotBasePoints0=int32(0.04f*damage)-1; break;
3847 case 11120: igniteDotBasePoints0=int32(0.08f*damage)-1; break;
3848 case 12846: igniteDotBasePoints0=int32(0.12f*damage)-1; break;
3849 case 12847: igniteDotBasePoints0=int32(0.16f*damage)-1; break;
3850 case 12848: igniteDotBasePoints0=int32(0.20f*damage)-1; break;
3851 default:
3852 sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell->Id);
3853 return;
3855 CastCustomSpell(pVictim, 12654, &igniteDotBasePoints0, NULL, NULL, true, NULL, triggredByAura);
3856 return;
3859 // Combustion
3860 case 11129:
3862 CastSpell(this, 28682, true, NULL, triggredByAura);
3863 if (!(procFlag & PROC_FLAG_CRIT_SPELL)) //no crit
3864 triggredByAura->m_procCharges += 1; //-> reincrease procCharge count since it was decreased before
3865 else if (triggredByAura->m_procCharges == 0) //no more charges left and crit
3866 RemoveAurasDueToSpell(28682); //-> remove Combustion auras
3867 return;
3869 // Nightfall
3870 case 18094:
3871 case 18095:
3873 CastSpell(this, 17941, true, NULL, triggredByAura);
3874 return;
3876 // VE
3877 case 15286:
3879 if(!pVictim)
3880 return;
3882 if(triggredByAura->GetCasterGUID() == pVictim->GetGUID())
3884 //VEHeal has a BaseDice of 0, so no decrement needed
3885 int32 VEHealBasePoints0 = triggredByAura->GetModifier()->m_amount*damage/100;
3886 pVictim->CastCustomSpell(pVictim, 15290, &VEHealBasePoints0, NULL, NULL, true, NULL, triggredByAura);
3888 return;
3890 // Eye of Eye
3891 case 9799:
3892 case 25988:
3894 if(!pVictim)
3895 return;
3897 // return damage % to attacker but < 50% own total health
3898 uint32 backDamage = triggredByAura->GetModifier()->m_amount*damage/100;
3899 if(backDamage > GetMaxHealth()/2)
3900 backDamage = GetMaxHealth()/2;
3902 int32 YYDamageBasePoints0 = backDamage-1;
3903 CastCustomSpell(pVictim, 25997, &YYDamageBasePoints0, NULL, NULL, true, NULL, triggredByAura);
3905 return;
3908 // L.Overload
3909 case 30675:
3910 case 30678:
3911 case 30679:
3912 case 30680:
3913 case 30681:
3915 if(!procSpell)
3916 return;
3918 // we assume lightning bolt and chain lightning are generic (not channeled/autorepeat) spells
3919 if(!pVictim || !m_currentSpells[CURRENT_GENERIC_SPELL])
3920 return;
3922 // remove cooldown from first cast
3923 if(GetTypeId()==TYPEID_PLAYER)
3924 ((Player*)this)->RemoveSpellCooldown(procSpell->Id);
3925 // prepare cast as triggered spell (this need for correct targets selection after not finished currently cast)
3926 m_currentSpells[CURRENT_GENERIC_SPELL]->AddTriggeredSpell(procSpell);
3929 // Spiritual Att.
3930 case 33776:
3931 case 31785:
3933 if(!pVictim)
3934 return;
3936 // if healed by another unit (pVictim)
3937 if(this != pVictim)
3939 int32 SAHealBasePoints0 = triggredByAura->GetModifier()->m_amount*damage/100-1;
3940 CastCustomSpell(this, 31786, &SAHealBasePoints0, NULL, NULL, true, NULL, triggredByAura);
3943 return;
3946 // Shadowflame (item set effect)
3947 case 37377:
3949 if(GetTypeId() != TYPEID_PLAYER)
3950 return;
3952 Item* castItem = ((Player*)this)->GetItemByGuid(triggredByAura->GetCastItemGUID());
3953 if(!castItem)
3954 return;
3956 CastSpell(pVictim,37379,true,castItem,triggredByAura);
3957 return;
3959 // Shadowflame Hellfire (item set effect)
3960 case 39437:
3962 if(GetTypeId() != TYPEID_PLAYER)
3963 return;
3965 Item* castItem = ((Player*)this)->GetItemByGuid(triggredByAura->GetCastItemGUID());
3966 if(!castItem)
3967 return;
3969 CastSpell(pVictim,37378,true,castItem,triggredByAura);
3970 return;
3973 default: break;
3976 switch(dummySpell->SpellFamilyName)
3978 case SPELLFAMILY_SHAMAN:
3979 if(dummySpell->SpellFamilyFlags==0x40000000000LL)
3981 int32 HealBasePoints0 = dummySpell->EffectBasePoints[0];
3982 CastCustomSpell(this,379,&HealBasePoints0,NULL,NULL,true,NULL,triggredByAura);
3983 return;
3985 break;
3986 default:
3987 break;
3990 // Non SpellID checks
3991 switch(dummySpell->SpellIconID)
3993 // Master of Elements
3994 case 1920:
3996 if(!procSpell)
3997 return;
3999 if(dummySpell->SpellFamilyName!=SPELLFAMILY_MAGE)
4000 return;
4002 int32 MEManaCostSave = procSpell->manaCost * triggredByAura->GetModifier()->m_amount/100;
4003 if(MEManaCostSave <= 0)
4004 return;
4005 int32 MEManaRestoreBasePoints0 = MEManaCostSave-1;
4006 CastCustomSpell(this,29077,&MEManaRestoreBasePoints0,NULL,NULL,true,NULL, triggredByAura);
4008 return;
4010 // VT
4011 case 2213:
4013 if(!pVictim)
4014 return;
4016 if(triggredByAura->GetCasterGUID() == pVictim->GetGUID())
4018 int32 VTEnergizeBasePoints0 = triggredByAura->GetModifier()->m_amount*damage/100 - 1;
4019 pVictim->CastCustomSpell(pVictim,34919,&VTEnergizeBasePoints0,NULL,NULL,true,NULL, triggredByAura);
4021 return;
4023 // Quick Recovery
4024 case 2116:
4026 if(!procSpell)
4027 return;
4029 if(dummySpell->SpellFamilyName!=SPELLFAMILY_ROGUE)
4030 return;
4032 // only rogue's finishing moves (maybe need additional checks)
4033 if( procSpell->SpellFamilyName!=SPELLFAMILY_ROGUE ||
4034 (procSpell->SpellFamilyFlags & (0x40000 | 0x80000 | 0x100000 | 0x200000 | 0x800000000LL | 0x20000)) == 0)
4035 return;
4037 int32 QREnegyCostSave = procSpell->manaCost * triggredByAura->GetModifier()->m_amount/100;
4038 if(QREnegyCostSave <= 0)
4039 return;
4040 int32 QREnergizeBasePoints0 = QREnegyCostSave-1;
4041 CastCustomSpell(this,31663,&QREnergizeBasePoints0,NULL,NULL,true,NULL, triggredByAura);
4043 return;
4045 // Thrill of the Hunt
4046 case 2236:
4048 if(!procSpell)
4049 return;
4051 if(dummySpell->SpellFamilyName!=SPELLFAMILY_HUNTER)
4052 return;
4054 int32 THManaCostSave = procSpell->manaCost * 40/100;
4055 if(THManaCostSave <= 0)
4056 return;
4057 int32 THEnergizeBasePoints0 = THManaCostSave-1;
4058 CastCustomSpell(this,34720,&THEnergizeBasePoints0,NULL,NULL,true,NULL, triggredByAura);
4060 return;
4065 void Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 procFlags)
4067 SpellEntry const* auraSpellInfo = triggeredByAura->GetSpellProto();
4069 switch(auraSpellInfo->SpellIconID)
4071 case 19:
4073 switch(auraSpellInfo->SpellFamilyName)
4075 case SPELLFAMILY_SHAMAN:
4077 //Lightning Shield (overwrite non existing triggered spell call in spell.dbc
4078 if(auraSpellInfo->SpellFamilyFlags==0x00000400)
4080 if(!pVictim)
4081 return;
4083 uint32 spell = 0;
4084 switch(triggeredByAura->GetSpellProto()->Id)
4086 // Rank 1
4087 case 324: spell = 26364; break;
4088 // Rank 2
4089 case 325: spell = 26365; break;
4090 // Rank 3
4091 case 905: spell = 26366; break;
4092 // Rank 4
4093 case 945: spell = 26367; break;
4094 // Rank 5
4095 case 8134: spell = 26369; break;
4096 // Rank 6
4097 case 10431: spell = 26370; break;
4098 // Rank 7
4099 case 10432: spell = 26363; break;
4100 // Rank 8
4101 case 25469: spell = 26371; break;
4102 // Rank 9
4103 case 25472: spell = 26372; break;
4104 default:
4105 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura->GetSpellProto()->Id);
4106 return;
4108 CastSpell(pVictim, spell, true, NULL, triggeredByAura);
4109 return;
4111 break;
4113 case SPELLFAMILY_PRIEST:
4115 // Priest's "Shadowguard"
4116 if(auraSpellInfo->SpellFamilyFlags==0x100080000000LL)
4118 if(!pVictim)
4119 return;
4121 uint32 spell = 0;
4122 switch(triggeredByAura->GetSpellProto()->Id)
4124 // Rank 1
4125 case 18137: spell = 28377; break;
4126 // Rank 2
4127 case 19308: spell = 28378; break;
4128 // Rank 3
4129 case 19309: spell = 28379; break;
4130 // Rank 4
4131 case 19310: spell = 28380; break;
4132 // Rank 5
4133 case 19311: spell = 28381; break;
4134 // Rank 6
4135 case 19312: spell = 28382; break;
4136 // Rank 7
4137 case 25477: spell = 28385; break;
4138 default:
4139 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura->GetSpellProto()->Id);
4140 return;
4142 CastSpell(pVictim, spell, true, NULL, triggeredByAura);
4143 return;
4145 break;
4148 break;
4150 case 87:
4152 //Mana Surge (Shaman T1 bonus)
4153 //Effect: 23571
4154 if(!procSpell)
4155 return;
4157 int32 manaSurgeSpellBasePoints0 = procSpell->manaCost * 35/100;
4158 CastCustomSpell(this, 23571, &manaSurgeSpellBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
4159 return;
4161 case 113:
4163 //Improved Drain Soul
4164 //Effect: 18371
4165 Unit::AuraList const& mAddFlatModifier = GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
4166 for(Unit::AuraList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i)
4168 if ((*i)->GetModifier()->m_miscvalue == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellProto()->SpellIconID == 113)
4170 int32 impDrainSoulBasePoints0 = (*i)->GetSpellProto()->EffectBasePoints[2] * GetMaxPower(POWER_MANA) / 100;
4171 CastCustomSpell(this, 18371, &impDrainSoulBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
4174 return;
4176 case 241:
4178 switch(auraSpellInfo->EffectTriggerSpell[0])
4180 //Illumination
4181 case 18350:
4183 if(!procSpell)
4184 return;
4186 SpellEntry const *originalSpell = procSpell;
4188 // in case HShock procspell is triggered spell but we need mana cost of original casted spell
4189 if(procSpell->SpellFamilyName == SPELLFAMILY_PALADIN && procSpell->SpellFamilyFlags == 0x00200000)
4191 uint32 originalSpellId = 0;
4192 switch(procSpell->Id)
4194 case 25914: originalSpellId = 20473; break;
4195 case 25913: originalSpellId = 20929; break;
4196 case 25903: originalSpellId = 20930; break;
4197 case 27175: originalSpellId = 27174; break;
4198 case 33074: originalSpellId = 33072; break;
4199 default:
4200 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell->Id);
4201 return;
4203 SpellEntry const *HSSpell= sSpellStore.LookupEntry(originalSpellId);
4204 if(!HSSpell)
4206 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but used in HShock",originalSpellId);
4207 return;
4209 originalSpell = HSSpell;
4212 // percent stored in effect 1 (class scripts) base points
4213 int32 percent = auraSpellInfo->EffectBasePoints[1]+1;
4215 // BasePoints = val -1 not required (EffectBaseDice==0)
4216 int32 ILManaSpellBasePoints0 = originalSpell->manaCost*percent/100;
4217 CastCustomSpell(this, 20272, &ILManaSpellBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
4218 return;
4221 break;
4223 case 312:
4225 //Improved Leader of the Pack
4226 //Effect 34299
4227 //Cooldown: 6 secs
4228 if (triggeredByAura->GetModifier()->m_amount == 0)
4229 break;
4230 int32 improvedLotPBasePoints0 = triggeredByAura->GetModifier()->m_amount * GetMaxHealth() / 100 - 1;
4231 CastCustomSpell(this, 34299, &improvedLotPBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
4232 if (GetTypeId() == TYPEID_PLAYER)
4233 ((Player*)this)->AddSpellCooldown(34299,0,time(NULL) + 6);
4234 return;
4236 case 1137:
4238 //Pyroclasm
4239 //Effect: 18093
4240 float chance = 0;
4241 switch (triggeredByAura->GetSpellProto()->Id)
4243 case 18096:
4244 chance = 13.0;
4245 break;
4246 case 18073:
4247 chance = 26.0;
4248 break;
4250 if (pVictim && pVictim->isAlive() && roll_chance_f(chance))
4251 CastSpell(pVictim, 18093, true, NULL, triggeredByAura);
4252 return;
4254 case 1875:
4256 //Blessed Recovery
4257 uint32 EffectId = 0;
4258 switch (triggeredByAura->GetSpellProto()->Id)
4260 case 27811: EffectId = 27813; break;
4261 case 27815: EffectId = 27817; break;
4262 case 27816: EffectId = 27818; break;
4263 default:
4264 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura->GetSpellProto()->Id);
4265 return;
4268 int32 heal_amount = damage * triggeredByAura->GetModifier()->m_amount / 100;
4269 int32 BRHealBasePoints0 = heal_amount/3-1;
4270 CastCustomSpell(this, EffectId, &BRHealBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
4271 return;
4273 case 2006:
4274 //Rampage
4275 //Effects: 30029(Rank 1), 30031(Rank 2), 30032(Rank 3)
4276 //Check EffectTriggerSpell[1] to determine correct effect id
4277 //CastSpell(this, triggredByAura->GetSpellProto()->EffectTriggerSpell[1], true, NULL, triggredByAura);
4278 return;
4279 case 2013:
4281 //Nature's Guardian
4282 //Effects: 31616, 39301
4283 //Cooldown: 5 secs
4284 /*float HealthRatio = GetHealth() / GetMaxHealth();
4285 float HealthRatioBefore = (GetHealth() + damage) / GetMaxHealth();
4286 if (HealthRatio < 0.3 && HealthRatioBefore >= 0.3)
4288 SpellEntry const *NGHealTemplate = sSpellStore.LookupEntry(31616);
4289 SpellEntry NGHeal = *NGHealTemplate;
4290 NGHeal.EffectBasePoints[0] = triggredByAura->GetModifier()->m_amount * GetMaxHealth() / 100;
4291 CastSpell(this, &NGHeal, true, NULL, triggredByAura);
4292 if (pVictim && pVictim->isAlive())
4293 CastSpell(pVictim, 39301, true, NULL, triggredByAura);
4294 if (GetTypeId() == TYPEID_PLAYER)
4296 ((Player*)this)->AddSpellCooldown(31616,0,time(NULL) + 5);
4297 ((Player*)this)->AddSpellCooldown(39301,0,time(NULL) + 5);
4300 return;
4302 case 2127:
4303 //Blazing Speed
4304 //Effect: 31643
4305 CastSpell(this, 31643, true, NULL, triggeredByAura);
4306 return;
4309 // custom check for proc spell
4310 switch(auraSpellInfo->Id)
4312 // Lightning Capacitor
4313 case 37657:
4315 if(!pVictim)
4316 return;
4318 // stacking
4319 CastSpell(this, 37658, true, NULL, triggeredByAura);
4321 // counting
4322 uint32 count = 0;
4323 AuraList const& dummyAura = GetAurasByType(SPELL_AURA_DUMMY);
4324 for(AuraList::const_iterator itr = dummyAura.begin(); itr != dummyAura.end(); ++itr)
4325 if((*itr)->GetId()==37658)
4326 ++count;
4328 // release at 3 aura in stack
4329 if(count >2)
4331 RemoveAurasDueToSpell(37658);
4332 CastSpell(pVictim, 37661, true, NULL, triggeredByAura);
4334 return;
4338 // standard non-dummy case
4339 uint32 trigger_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()];
4340 if(!trigger_spell_id)
4342 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo->Id,triggeredByAura->GetEffIndex());
4343 return;
4346 // but with dummy basepoints or other customs
4347 switch(trigger_spell_id)
4349 // Shamanistic Rage triggered spell
4350 case 30824:
4352 int32 SRBasePoints0 = int32(GetTotalAttackPowerValue(BASE_ATTACK)*triggeredByAura->GetModifier()->m_amount/100) -1;
4353 CastCustomSpell(this, 30824, &SRBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
4354 return;
4356 // Backlash triggered spell
4357 case 34936:
4359 // need set custom cooldown
4360 if(isAlive() && GetTypeId()==TYPEID_PLAYER && !((Player*)this)->HasSpellCooldown(34936))
4362 CastSpell(this,trigger_spell_id,true,NULL,triggeredByAura);
4363 ((Player*)this)->AddSpellCooldown(34936,0,time(NULL)+8);
4365 return;
4369 // default case
4370 if(IsPositiveSpell(trigger_spell_id) && !(procFlags & PROC_FLAG_HEAL))
4371 CastSpell(this,trigger_spell_id,true,NULL,triggeredByAura);
4372 else if(pVictim && pVictim->isAlive())
4373 CastSpell(pVictim,trigger_spell_id,true,NULL,triggeredByAura);
4376 void Unit::setPowerType(Powers new_powertype)
4378 uint32 tem_bytes_0 = GetUInt32Value(UNIT_FIELD_BYTES_0);
4379 SetUInt32Value(UNIT_FIELD_BYTES_0,((tem_bytes_0<<8)>>8) + (uint32(new_powertype)<<24));
4381 if (GetTypeId() == TYPEID_PLAYER)
4382 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE);
4384 switch(new_powertype)
4386 default:
4387 case POWER_MANA:
4388 break;
4389 case POWER_RAGE:
4390 SetMaxPower(POWER_RAGE,GetCreatePowers(POWER_RAGE));
4391 SetPower( POWER_RAGE,0);
4392 break;
4393 case POWER_FOCUS:
4394 SetMaxPower(POWER_FOCUS,GetCreatePowers(POWER_FOCUS));
4395 SetPower( POWER_FOCUS,GetCreatePowers(POWER_FOCUS));
4396 break;
4397 case POWER_ENERGY:
4398 SetMaxPower(POWER_ENERGY,GetCreatePowers(POWER_ENERGY));
4399 SetPower( POWER_ENERGY,0);
4400 break;
4401 case POWER_HAPPINESS:
4402 SetMaxPower(POWER_HAPPINESS,GetCreatePowers(POWER_HAPPINESS));
4403 SetPower(POWER_HAPPINESS,GetCreatePowers(POWER_HAPPINESS));
4404 break;
4408 FactionTemplateEntry const* Unit::getFactionTemplateEntry() const
4410 FactionTemplateEntry const* entry = sFactionTemplateStore.LookupEntry(getFaction());
4411 if(!entry)
4413 static uint64 guid = 0; // prevent repeating spam same faction problem
4415 if(GetGUID() != guid)
4417 if(GetTypeId() == TYPEID_PLAYER)
4418 sLog.outError("Player %s have invalid faction (faction template id) #%u", ((Player*)this)->GetName(), getFaction());
4419 else
4420 sLog.outError("Creature (template id: %u) have invalid faction (faction template id) #%u", ((Creature*)this)->GetCreatureInfo()->Entry, getFaction());
4421 guid = GetGUID();
4424 return entry;
4427 bool Unit::IsHostileTo(Unit const* unit) const
4429 // always non-hostile to self
4430 if(unit==this)
4431 return false;
4433 // always hostile to enemy
4434 if(getVictim()==unit || unit->getVictim()==this)
4435 return true;
4437 // test pet/charm masters instead pers/charmeds
4438 Unit const* testerOwner = GetCharmerOrOwner();
4439 Unit const* targetOwner = unit->GetCharmerOrOwner();
4441 // always hostile to owner's enemy
4442 if(testerOwner && (testerOwner->getVictim()==unit || unit->getVictim()==testerOwner))
4443 return true;
4445 // always hostile to enemy owner
4446 if(targetOwner && (getVictim()==targetOwner || targetOwner->getVictim()==this))
4447 return true;
4449 // always hostile to owner of owner's enemy
4450 if(testerOwner && targetOwner && (testerOwner->getVictim()==targetOwner || targetOwner->getVictim()==testerOwner))
4451 return true;
4453 Unit const* tester = testerOwner ? testerOwner : this;
4454 Unit const* target = targetOwner ? targetOwner : unit;
4456 // special cases (Duel, etc)
4457 if(tester->GetTypeId()==TYPEID_PLAYER && target->GetTypeId()==TYPEID_PLAYER)
4459 // Duel
4460 if(((Player const*)tester)->duel && ((Player const*)tester)->duel->opponent == target && ((Player const*)tester)->duel->startTime != 0)
4461 return true;
4463 //= PvP states
4464 // Green/Blue (can't attack)
4465 if(((Player*)tester)->GetTeam()==((Player*)target)->GetTeam())
4466 return false;
4468 // Red (can attack) if true, Blue/Yellow (can't attack) in another case
4469 return ((Player*)tester)->IsPvP() && ((Player*)target)->IsPvP();
4472 // faction base cases
4473 FactionTemplateEntry const*tester_faction = tester->getFactionTemplateEntry();
4474 FactionTemplateEntry const*target_faction = target->getFactionTemplateEntry();
4475 if(!tester_faction || !target_faction)
4476 return false;
4478 // PvC forced reaction and reputation case
4479 if(tester->GetTypeId()==TYPEID_PLAYER)
4481 // forced reaction
4482 ForcedReactions::const_iterator forceItr = ((Player*)tester)->m_forcedReactions.find(target_faction->faction);
4483 if(forceItr!=((Player*)tester)->m_forcedReactions.end())
4485 return forceItr->second <= REP_HOSTILE;
4488 // apply reputation state
4489 FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction);
4490 if(raw_target_faction && raw_target_faction->reputationListID >=0 )
4492 if(((Player*)tester)->IsFactionAtWar(raw_target_faction))
4493 return true;
4496 // CvP forced reaction and reputation case
4497 else if(target->GetTypeId()==TYPEID_PLAYER)
4499 // forced reaction
4500 ForcedReactions::const_iterator forceItr = ((Player*)target)->m_forcedReactions.find(tester_faction->faction);
4501 if(forceItr!=((Player*)target)->m_forcedReactions.end())
4503 return forceItr->second <= REP_HOSTILE;
4506 // apply reputation state
4507 FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction);
4508 if(raw_tester_faction && raw_tester_faction->reputationListID >=0 )
4510 return ((Player*)target)->GetReputationRank(raw_tester_faction) <= REP_HOSTILE;
4514 // common faction based case (CvC,PvC,CvP)
4515 return tester_faction->IsHostileTo(*target_faction);
4518 bool Unit::IsFriendlyTo(Unit const* unit) const
4520 // always friendly to self
4521 if(unit==this)
4522 return true;
4524 // always non-friendly to enemy
4525 if(getVictim()==unit || unit->getVictim()==this)
4526 return false;
4528 // test pet/charm masters instead pers/charmeds
4529 Unit const* testerOwner = GetCharmerOrOwner();
4530 Unit const* targetOwner = unit->GetCharmerOrOwner();
4532 // always non-friendly to owner's enemy
4533 if(testerOwner && (testerOwner->getVictim()==unit || unit->getVictim()==testerOwner))
4534 return false;
4536 // always non-friendly to enemy owner
4537 if(targetOwner && (getVictim()==targetOwner || targetOwner->getVictim()==this))
4538 return false;
4540 // always non-friendly to owner of owner's enemy
4541 if(testerOwner && targetOwner && (testerOwner->getVictim()==targetOwner || targetOwner->getVictim()==testerOwner))
4542 return false;
4544 Unit const* tester = testerOwner ? testerOwner : this;
4545 Unit const* target = targetOwner ? targetOwner : unit;
4547 // special cases (Duel)
4548 if(tester->GetTypeId()==TYPEID_PLAYER && target->GetTypeId()==TYPEID_PLAYER)
4550 // Duel
4551 if(((Player const*)tester)->duel && ((Player const*)tester)->duel->opponent == target && ((Player const*)tester)->duel->startTime != 0)
4552 return false;
4554 //= PvP states
4555 // Green/Blue (non-attackable)
4556 if(((Player*)tester)->GetTeam()==((Player*)target)->GetTeam())
4557 return true;
4559 // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable)
4560 return !((Player*)target)->IsPvP();
4563 // faction base cases
4564 FactionTemplateEntry const*tester_faction = tester->getFactionTemplateEntry();
4565 FactionTemplateEntry const*target_faction = target->getFactionTemplateEntry();
4566 if(!tester_faction || !target_faction)
4567 return false;
4569 // PvC forced reaction and reputation case
4570 if(tester->GetTypeId()==TYPEID_PLAYER)
4572 // forced reaction
4573 ForcedReactions::const_iterator forceItr = ((Player*)tester)->m_forcedReactions.find(target_faction->faction);
4574 if(forceItr!=((Player*)tester)->m_forcedReactions.end())
4576 return forceItr->second >= REP_FRIENDLY;
4579 // apply reputation state
4580 FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction);
4581 if(raw_target_faction && raw_target_faction->reputationListID >=0 )
4583 if(((Player*)tester)->IsFactionAtWar(raw_target_faction))
4584 return false;
4587 // CvP forced reaction and reputation case
4588 else if(target->GetTypeId()==TYPEID_PLAYER)
4590 // forced reaction
4591 ForcedReactions::const_iterator forceItr = ((Player*)target)->m_forcedReactions.find(tester_faction->faction);
4592 if(forceItr!=((Player*)target)->m_forcedReactions.end())
4594 return forceItr->second >= REP_FRIENDLY;
4597 // apply reputation state
4598 FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction);
4599 if(raw_tester_faction && raw_tester_faction->reputationListID >=0 )
4601 return ((Player*)target)->GetReputationRank(raw_tester_faction) >= REP_FRIENDLY;
4605 // common faction based case (CvC,PvC,CvP)
4606 return tester_faction->IsFriendlyTo(*target_faction);
4609 bool Unit::IsHostileToPlayers() const
4611 FactionTemplateEntry const* my_faction = getFactionTemplateEntry();
4612 if(!my_faction)
4613 return false;
4615 FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction);
4616 if(raw_faction && raw_faction->reputationListID >=0 )
4617 return false;
4619 return my_faction->IsHostileToPlayers();
4622 bool Unit::IsNeutralToAll() const
4624 FactionTemplateEntry const* my_faction = getFactionTemplateEntry();
4625 if(!my_faction)
4626 return true;
4628 FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction);
4629 if(raw_faction && raw_faction->reputationListID >=0 )
4630 return false;
4632 return my_faction->IsNeutralToAll();
4635 bool Unit::Attack(Unit *victim, bool playerMeleeAttack)
4637 if(!victim || victim == this)
4638 return false;
4640 // player don't must attack in mount state
4641 if(GetTypeId()==TYPEID_PLAYER && IsMounted())
4642 return false;
4644 // anyone don't must attack GM in GM-mode
4645 if(victim->GetTypeId()==TYPEID_PLAYER && ((Player*)victim)->isGameMaster())
4646 return false;
4648 if (m_attacking)
4650 if (m_attacking == victim)
4651 return false;
4652 AttackStop();
4655 //Set our target
4656 SetUInt64Value(UNIT_FIELD_TARGET, victim->GetGUID());
4658 addUnitState(UNIT_STAT_ATTACKING);
4659 SetInCombat();
4660 m_attacking = victim;
4661 m_attacking->_addAttacker(this);
4663 if(m_attacking->GetTypeId()==TYPEID_UNIT && ((Creature*)m_attacking)->AI())
4664 ((Creature*)m_attacking)->AI()->AttackedBy(this);
4666 if( GetTypeId()==TYPEID_UNIT && !(((Creature*)this)->isPet() || isCharmed()) )
4668 ((Creature*)this)->CallAssistence();
4670 //if(!isAttackReady(BASE_ATTACK))
4671 //resetAttackTimer(BASE_ATTACK);
4673 // delay offhand weapon attack to next attack time
4674 if(haveOffhandWeapon())
4675 resetAttackTimer(OFF_ATTACK);
4677 if(playerMeleeAttack)
4678 SendAttackStart(victim);
4680 return true;
4683 bool Unit::AttackStop()
4685 if (!m_attacking)
4686 return false;
4688 Unit* victim = m_attacking;
4690 m_attacking->_removeAttacker(this);
4691 m_attacking = NULL;
4693 //Clear our target
4694 SetUInt64Value(UNIT_FIELD_TARGET, 0);
4696 clearUnitState(UNIT_STAT_ATTACKING);
4698 InterruptSpell(CURRENT_MELEE_SPELL);
4700 if( GetTypeId()==TYPEID_UNIT )
4702 // reset call assistance
4703 ((Creature*)this)->SetNoCallAssistence(false);
4706 SendAttackStop(victim);
4708 return true;
4711 bool Unit::isAttackingPlayer() const
4713 if(getVictim())
4715 if(getVictim()->GetTypeId() == TYPEID_PLAYER)
4716 return true;
4718 if(getVictim()->GetOwnerGUID() && GUID_HIPART(getVictim()->GetOwnerGUID())==HIGHGUID_PLAYER)
4719 return true;
4722 Pet* pet = GetPet();
4723 if(pet && pet->isAttackingPlayer())
4724 return true;
4726 Unit* charmed = GetCharm();
4727 if(charmed && charmed->isAttackingPlayer())
4728 return true;
4730 for (int8 i = 0; i < 4; i++)
4732 if(m_TotemSlot[i])
4734 Creature *totem = ObjectAccessor::Instance().GetCreature(*this, m_TotemSlot[i]);
4735 if(totem && totem->isAttackingPlayer())
4736 return true;
4740 return false;
4743 void Unit::RemoveAllAttackers()
4745 while (m_attackers.size() != 0)
4747 AttackerSet::iterator iter = m_attackers.begin();
4748 if(!(*iter)->AttackStop())
4750 sLog.outError("WORLD: Unit has an attacker that isnt attacking it!");
4751 m_attackers.erase(iter);
4756 void Unit::ModifyAuraState(uint32 flag, bool apply)
4758 if (apply)
4760 if (!HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)))
4762 SetFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
4763 if(GetTypeId() == TYPEID_PLAYER)
4765 const PlayerSpellMap& sp_list = ((Player*)this)->GetSpellMap();
4766 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
4768 if(itr->second->state == PLAYERSPELL_REMOVED) continue;
4769 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
4770 if (!spellInfo || !IsPassiveSpell(itr->first)) continue;
4771 if (spellInfo->CasterAuraState == flag)
4772 CastSpell(this, itr->first, true, NULL);
4777 else
4779 if (HasFlag(UNIT_FIELD_AURASTATE,1<<(flag-1)))
4781 RemoveFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
4782 Unit::AuraMap& tAuras = GetAuras();
4783 for (Unit::AuraMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
4785 if ((*itr).second->GetSpellProto()->CasterAuraState == flag)
4786 RemoveAura(itr);
4787 else
4788 ++itr;
4794 Unit *Unit::GetOwner() const
4796 uint64 ownerid = GetOwnerGUID();
4797 if(!ownerid)
4798 return NULL;
4799 return ObjectAccessor::Instance().GetUnit(*this, ownerid);
4802 Unit *Unit::GetCharmer() const
4804 uint64 charmerid = GetCharmerGUID();
4805 if(!charmerid)
4806 return NULL;
4807 return ObjectAccessor::Instance().GetUnit(*this, charmerid);
4810 Pet* Unit::GetPet() const
4812 uint64 pet_guid = GetPetGUID();
4813 if(pet_guid)
4815 Pet* pet = ObjectAccessor::Instance().GetPet(pet_guid);
4816 if(!pet)
4818 sLog.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid));
4819 const_cast<Unit*>(this)->SetPet(0);
4820 return NULL;
4822 return pet;
4825 return NULL;
4828 Unit* Unit::GetCharm() const
4830 uint64 charm_guid = GetCharmGUID();
4831 if(charm_guid)
4833 Unit* pet = ObjectAccessor::Instance().GetUnit(*this, charm_guid);
4834 if(!pet)
4836 sLog.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid));
4837 const_cast<Unit*>(this)->SetCharm(0);
4839 return pet;
4841 else
4842 return NULL;
4845 void Unit::SetPet(Pet* pet)
4847 SetUInt64Value(UNIT_FIELD_SUMMON,pet ? pet->GetGUID() : 0);
4849 if(pet)
4851 for(int i = 0; i < MAX_MOVE_TYPE; ++i)
4853 pet->SetSpeed(UnitMoveType(i),m_speed_rate[i],true);
4858 void Unit::SetCharm(Unit* charmed)
4860 SetUInt64Value(UNIT_FIELD_CHARM,charmed ? charmed->GetGUID() : 0);
4863 void Unit::UnsummonAllTotems()
4865 for (int8 i = 0; i < 4; ++i)
4867 if(!m_TotemSlot[i])
4868 continue;
4870 Creature *OldTotem = ObjectAccessor::Instance().GetCreature(*this, m_TotemSlot[i]);
4871 if (OldTotem && OldTotem->isTotem())
4872 ((Totem*)OldTotem)->UnSummon();
4876 void Unit::SendHealSpellOnPlayer(Unit *pVictim, uint32 SpellID, uint32 Damage, bool critical)
4878 // we guess size
4879 WorldPacket data(SMSG_HEALSPELL_ON_PLAYER_OBSOLETE, (8+8+4+4+1));
4880 data.append(pVictim->GetPackGUID());
4881 data.append(GetPackGUID());
4882 data << SpellID;
4883 data << Damage;
4884 data << uint8(critical ? 1 : 0);
4885 SendMessageToSet(&data, true);
4888 void Unit::SendHealSpellOnPlayerPet(Unit *pVictim, uint32 SpellID, uint32 Damage,Powers powertype, bool critical)
4890 WorldPacket data(SMSG_HEALSPELL_ON_PLAYERS_PET_OBSOLETE, (8+8+4+4+4+1));
4891 data.append(pVictim->GetPackGUID());
4892 data.append(GetPackGUID());
4893 data << SpellID;
4894 data << uint32(powertype);
4895 data << Damage;
4896 data << uint8(critical ? 1 : 0);
4897 SendMessageToSet(&data, true);
4900 uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 pdamage, DamageEffectType damagetype)
4902 if(!spellProto || !pVictim || damagetype==DIRECT_DAMAGE )
4903 return pdamage;
4905 if(pVictim->IsImmunedToSpellDamage(spellProto))
4906 return 0;
4908 uint32 creatureTypeMask = GetCreatureTypeMask();
4910 // Damage Done
4911 uint32 CastingTime = GetCastTime(sCastTimesStore.LookupEntry(spellProto->CastingTimeIndex));
4912 if (CastingTime > 7000) CastingTime = 7000; // Plus Damage efficient maximum 200% ( 7.0 seconds )
4913 if (CastingTime < 1500) CastingTime = 1500;
4915 // Taken/Done fixed damage bonus auras
4916 int32 DoneAdvertisedBenefit = 0;
4917 int32 TakenAdvertisedBenefit = 0;
4919 // ..done (for creature type by mask) in taken
4920 AuraList const& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
4921 for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
4922 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
4923 TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount;
4925 // ..done
4926 AuraList const& mDamageDone = this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE);
4927 for(AuraList::const_iterator i = mDamageDone.begin();i != mDamageDone.end(); ++i)
4928 if(((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0 &&
4929 (*i)->GetSpellProto()->EquippedItemClass == -1 &&
4930 // -1 == any item class (not wand then)
4931 (*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 )
4932 // 0 == any inventory type (not wand then)
4933 DoneAdvertisedBenefit += (*i)->GetModifier()->m_amount;
4935 if (GetTypeId() == TYPEID_PLAYER)
4937 // Damage bonus of spirit
4938 AuraList const& mDamageDonebySpi = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_SPIRIT);
4939 for(AuraList::const_iterator i = mDamageDonebySpi.begin();i != mDamageDonebySpi.end(); ++i)
4940 if((*i)->GetModifier()->m_miscvalue & 1 << spellProto->School)
4941 DoneAdvertisedBenefit += int32(GetStat(STAT_SPIRIT) * (*i)->GetModifier()->m_amount / 100.0f);
4943 // ... and intellect
4944 AuraList const& mDamageDonebyInt = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_INTELLECT);
4945 for(AuraList::const_iterator i = mDamageDonebyInt.begin();i != mDamageDonebyInt.end(); ++i)
4946 if ((*i)->GetModifier()->m_miscvalue & 1 << spellProto->School)
4947 DoneAdvertisedBenefit += int32(GetStat(STAT_INTELLECT) * (*i)->GetModifier()->m_amount / 100.0f);
4950 // ..taken
4951 AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
4952 for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
4953 if(((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0)
4954 TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount;
4956 // Damage over Time spells bonus calculation
4957 float DotFactor = 1.0f;
4958 if(damagetype == DOT)
4960 CastingTime = 3500;
4961 uint32 DotDuration = GetDuration(spellProto);
4962 // 200% limit
4963 if(DotDuration > 0)
4965 if(DotDuration > 30000) DotDuration = 30000;
4966 DotFactor = DotDuration / 15000.0f;
4967 int x = 0;
4968 for(int j = 0; j < 3; j++)
4969 if(spellProto->Effect[j] == 6) x = j;
4970 int DotTicks = 6;
4971 if(spellProto->EffectAmplitude[x] != 0)
4972 DotTicks = DotDuration / spellProto->EffectAmplitude[x];
4973 if(DotTicks)
4975 DoneAdvertisedBenefit /= DotTicks;
4976 TakenAdvertisedBenefit /= DotTicks;
4981 // Taken/Done total percent damage auras
4982 float DoneTotalMod = 1.0f;
4983 float TakenTotalMod = 1.0f;
4985 // ..done
4986 AuraList const& mModDamagePercentDone = this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
4987 for(AuraList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
4988 if( spellProto->School != 0 && ((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0 &&
4989 (*i)->GetSpellProto()->EquippedItemClass == -1 &&
4990 // -1 == any item class (not wand then)
4991 (*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 )
4992 // 0 == any inventory type (not wand then)
4993 DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
4995 // ..taken
4996 AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
4997 for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
4998 if( spellProto->School != 0 && ((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0 )
4999 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
5001 // Exceptions
5002 // Lifetap
5003 if(spellProto->SpellVisual == 1225 && spellProto->SpellIconID == 208)
5005 CastingTime = 2800; // 80% from +shadow damage
5006 DoneTotalMod = 1.0f;
5007 TakenTotalMod = 1.0f;
5009 // Dark Pact
5010 if(spellProto->SpellVisual == 827 && spellProto->SpellIconID == 154 && GetPet())
5012 CastingTime = 3360; // 96% from +shadow damage
5013 DoneTotalMod = 1.0f;
5014 TakenTotalMod = 1.0f;
5016 // Ice Lance
5017 if(spellProto->Id == 30455)
5019 CastingTime /= 3.0f; // applied 1/3 bonuses in case generic target
5020 if(pVictim->isFrozen()) // and compensate this for frozen target.
5021 TakenTotalMod *= 3.0f;
5024 // Level Factor
5025 float LvlPenalty = 0.0f;
5026 if(spellProto->spellLevel < 20)
5027 LvlPenalty = (20.0f - (float)(spellProto->spellLevel)) * 3.75f;
5028 float LvlFactor = ((float)(spellProto->spellLevel) + 6.0f) / (float)(getLevel());
5029 if(LvlFactor > 1.0f)
5030 LvlFactor = 1.0f;
5032 // Spellmod SpellDamage
5033 float SpellModSpellDamage = 100.0f;
5034 if (GetTypeId() == TYPEID_PLAYER)
5035 ((Player*)this)->ApplySpellMod(spellProto->Id,SPELLMOD_SPELL_DAMAGE,SpellModSpellDamage);
5036 SpellModSpellDamage /= 100.0f;
5038 float DoneActualBenefit = DoneAdvertisedBenefit * (CastingTime / 3500.0f) * (100.0f - LvlPenalty) * LvlFactor * DotFactor * SpellModSpellDamage / 100.0f;
5039 float TakenActualBenefit = TakenAdvertisedBenefit * (CastingTime / 3500.0f) * (100.0f - LvlPenalty) * LvlFactor * DotFactor / 100.0f;
5041 float tmpDamage = (float(pdamage)+DoneActualBenefit)*DoneTotalMod;
5042 tmpDamage = (tmpDamage+TakenActualBenefit)*TakenTotalMod;
5044 return tmpDamage > 0 ? uint32(tmpDamage) : 0;
5047 bool Unit::SpellCriticalBonus(SpellEntry const *spellProto, int32 *peffect, Unit *pVictim)
5049 // Chance to crit is computed from INT and LEVEL as follows:
5050 // chance = base + INT / (rate0 + rate1 * LEVEL)
5051 // The formula keeps the crit chance at %5 on every level unless the player
5052 // increases his intelligence by other means (enchants, buffs, talents, ...)
5053 if(spellProto->Id == 15290 || spellProto->Id == 39373) return false;
5055 float crit_chance = 0.0f;
5057 // base value
5058 if (GetTypeId() != TYPEID_PLAYER)
5060 // flat done
5061 // TODO: can creatures have critical chance auras?
5062 crit_chance = m_baseSpellCritChance;
5063 AuraList const& mSpellCritSchool = GetAurasByType(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL);
5064 for(AuraList::const_iterator i = mSpellCritSchool.begin(); i != mSpellCritSchool.end(); ++i)
5065 if((*i)->GetModifier()->m_miscvalue == -2 || ((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0)
5066 crit_chance += (*i)->GetModifier()->m_amount;
5068 else
5069 crit_chance = GetFloatValue( PLAYER_SPELL_CRIT_PERCENTAGE1 + spellProto->School);
5071 // percent done
5072 // only players use intelligence for critical chance computations
5073 if (GetTypeId() == TYPEID_PLAYER)
5075 ((Player*)this)->ApplySpellMod(spellProto->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance);
5078 // taken
5079 if (pVictim)
5081 // flat
5082 AuraList const& mAttackerSpellCrit = pVictim->GetAurasByType(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE);
5083 for(AuraList::const_iterator i = mAttackerSpellCrit.begin(); i != mAttackerSpellCrit.end(); ++i)
5084 if((*i)->GetModifier()->m_miscvalue == -2 || ((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0)
5085 crit_chance += (*i)->GetModifier()->m_amount;
5087 // flat: Resilience - reduce crit chance by x%
5088 crit_chance -= pVictim->m_modResilience;
5090 // flat: scripted (increase crit chance ... against ... target by x%
5091 AuraList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
5092 for(AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
5094 switch((*i)->GetModifier()->m_miscvalue)
5096 //Shatter Rank 1
5097 case 849: if(pVictim->isFrozen()) crit_chance+= 10; break;
5098 //Shatter Rank 2
5099 case 910: if(pVictim->isFrozen()) crit_chance+= 20; break;
5100 //Shatter Rank 3
5101 case 911: if(pVictim->isFrozen()) crit_chance+= 30; break;
5102 //Shatter Rank 4
5103 case 912: if(pVictim->isFrozen()) crit_chance+= 40; break;
5104 //Shatter Rank 5
5105 case 913: if(pVictim->isFrozen()) crit_chance+= 50; break;
5109 // flat
5110 AuraList const& mAttackerSWCrit = pVictim->GetAurasByType(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
5111 for(AuraList::const_iterator i = mAttackerSWCrit.begin(); i != mAttackerSWCrit.end(); ++i)
5112 crit_chance += (*i)->GetModifier()->m_amount;
5115 crit_chance = crit_chance > 0.0 ? crit_chance : 0.0;
5116 if (roll_chance_f(crit_chance))
5118 int32 crit_bonus = *peffect / 2;
5119 if (GetTypeId() == TYPEID_PLAYER) // adds additional damage to crit_bonus (from talents)
5120 ((Player*)this)->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
5122 *peffect += crit_bonus;
5123 // Resilience - reduce crit damage by 2x%
5124 if (pVictim)
5125 *peffect -= int32(pVictim->m_modResilience * 2/100 * (*peffect));
5127 return true;
5129 return false;
5132 uint32 Unit::SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, Unit *pVictim)
5134 // Healing Done
5136 // Vampiric Embrace, Shadowmend - cannot critically heal
5137 if(spellProto->Id == 15290 || spellProto->Id == 39373) return healamount;
5139 int32 AdvertisedBenefit = 0;
5140 uint32 CastingTime = GetCastTime(sCastTimesStore.LookupEntry(spellProto->CastingTimeIndex));
5141 if (CastingTime > 7000) CastingTime = 7000;
5142 if (CastingTime < 1500) CastingTime = 1500;
5143 if (spellProto->Effect[0] == SPELL_EFFECT_APPLY_AURA) CastingTime = 3500;
5145 AuraList const& mHealingDone = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE);
5146 for(AuraList::const_iterator i = mHealingDone.begin();i != mHealingDone.end(); ++i)
5147 if(((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0)
5148 AdvertisedBenefit += (*i)->GetModifier()->m_amount;
5150 // Healing bonus of spirit, intellect and strength
5151 if (GetTypeId() == TYPEID_PLAYER)
5153 AdvertisedBenefit += int32(GetStat(STAT_SPIRIT) * GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HEALING_OF_SPIRIT) / 100.0f);
5154 AdvertisedBenefit += int32(GetStat(STAT_INTELLECT) * GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HEALING_OF_INTELLECT) / 100.0f);
5155 AdvertisedBenefit += int32(GetStat(STAT_STRENGTH) * GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HEALING_OF_STRENGTH) / 100.0f);
5158 // Healing Taken
5159 AdvertisedBenefit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_HEALING);
5161 //BoL dummy effects
5162 if (spellProto->SpellFamilyName == SPELLFAMILY_PALADIN && (spellProto->SpellFamilyFlags & 0xC0000000))
5164 AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
5165 for(AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
5166 if((*i)->GetSpellProto()->SpellVisual == 9180)
5167 //FoL
5168 if ((spellProto->SpellFamilyFlags & 0x40000000) && (*i)->GetEffIndex() == 1)
5169 AdvertisedBenefit += (*i)->GetModifier()->m_amount;
5170 //HL
5171 else if ((spellProto->SpellFamilyFlags & 0x80000000) && (*i)->GetEffIndex() == 0)
5172 AdvertisedBenefit += (*i)->GetModifier()->m_amount;
5175 // Healing over Time spells
5176 float DotFactor = 1.0f;
5177 if(damagetype == DOT)
5179 CastingTime = 3500;
5180 uint32 DotDuration = GetDuration(spellProto);
5181 // 200% limit
5182 if(DotDuration > 30000) DotDuration = 30000;
5183 DotFactor = DotDuration / 15000.0f;
5184 int x = 0;
5185 for(int j = 0; j < 3; j++)
5186 if(spellProto->Effect[j] == 6) x = j;
5187 int DotTicks = 6;
5188 if(spellProto->EffectAmplitude[x] != 0)
5189 DotTicks = DotDuration / spellProto->EffectAmplitude[x];
5190 if(DotTicks)
5191 AdvertisedBenefit /= DotTicks;
5194 // Level Factor
5195 float LvlPenalty = 0.0f;
5196 if(spellProto->spellLevel < 20)
5197 LvlPenalty = (20.0f - (float)(spellProto->spellLevel)) * 3.75f;
5198 float LvlFactor = ((float)(spellProto->spellLevel) + 6.0f) / (float)(getLevel());
5199 if(LvlFactor > 1.0f)
5200 LvlFactor = 1.0f;
5202 float ActualBenefit = (float)AdvertisedBenefit * ((float)CastingTime / 3500.0f) * (100.0f - LvlPenalty) * LvlFactor * DotFactor / 100.0f;
5204 // use float as more appropriate for negative values and percent applying
5205 float heal = healamount + ActualBenefit;
5207 // TODO: check for ALL/SPELLS type
5208 // Healing done percent
5209 AuraList const& mHealingDonePct = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT);
5210 for(AuraList::const_iterator i = mHealingDonePct.begin();i != mHealingDonePct.end(); ++i)
5211 heal *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f;
5213 // Healing taken percent
5214 AuraList const& mHealingPct = pVictim->GetAurasByType(SPELL_AURA_MOD_HEALING_PCT);
5215 for(AuraList::const_iterator i = mHealingPct.begin();i != mHealingPct.end(); ++i)
5216 heal *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f;
5218 if (heal < 0) heal = 0;
5220 return uint32(heal);
5223 bool Unit::IsImmunedToPhysicalDamage() const
5225 //If m_immuneToDamage type contain magic, IMMUNE damage.
5226 SpellImmuneList const& damageImmList = m_spellImmune[IMMUNITY_DAMAGE];
5227 for (SpellImmuneList::const_iterator itr = damageImmList.begin(); itr != damageImmList.end(); ++itr)
5228 if(itr->type & IMMUNE_DAMAGE_PHYSICAL)
5229 return true;
5231 //If m_immuneToSchool type contain this school type, IMMUNE damage.
5232 SpellImmuneList const& spellImmList = m_spellImmune[IMMUNITY_SCHOOL];
5233 for (SpellImmuneList::const_iterator itr = spellImmList.begin(); itr != spellImmList.end(); ++itr)
5234 if(itr->type & IMMUNE_SCHOOL_PHYSICAL)
5235 return true;
5237 return false;
5240 bool Unit::IsImmunedToSpellDamage(SpellEntry const* spellInfo) const
5242 //If m_immuneToDamage type contain magic, IMMUNE damage.
5243 SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
5244 for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
5245 if(itr->type & uint32(1<<spellInfo->School))
5246 return true;
5248 //If m_immuneToSchool type contain this school type, IMMUNE damage.
5249 SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
5250 for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
5251 if(itr->type & uint32(1<<spellInfo->School))
5252 return true;
5254 return false;
5257 bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo) const
5259 if (!spellInfo)
5260 return false;
5262 SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL];
5263 for(SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr)
5264 if(itr->type == spellInfo->Dispel)
5265 return true;
5267 SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
5268 for(SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
5269 if(itr->type == spellInfo->Mechanic)
5270 return true;
5272 int32 chance = 0;
5273 AuraList const& mModMechanicRes = GetAurasByType(SPELL_AURA_MOD_MECHANIC_RESISTANCE);
5274 for(AuraList::const_iterator i = mModMechanicRes.begin();i != mModMechanicRes.end(); ++i)
5275 if((*i)->GetModifier()->m_miscvalue == int32(spellInfo->Mechanic))
5276 chance+= (*i)->GetModifier()->m_amount;
5277 if(roll_chance_i(chance))
5278 return true;
5280 return false;
5283 bool Unit::IsImmunedToSpellEffect(uint32 effect) const
5285 //If m_immuneToEffect type contain this effect type, IMMUNE effect.
5286 SpellImmuneList const& effectList = m_spellImmune[IMMUNITY_EFFECT];
5287 for (SpellImmuneList::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr)
5288 if(itr->type == effect)
5289 return true;
5291 return false;
5294 bool Unit::IsDamageToThreatSpell(SpellEntry const * spellInfo) const
5296 if(!spellInfo)
5297 return false;
5299 uint32 family = spellInfo->SpellFamilyName;
5300 uint32 flags = spellInfo->SpellFamilyFlags;
5302 if((family == 5 && flags == 256) || //Searing Pain
5303 (family == 6 && flags == 8192) || //Mind Blast
5304 (family == 11 && flags == 1048576)) //Earth Shock
5305 return true;
5307 return false;
5310 void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attType)
5312 if(!pVictim) return;
5314 if(*pdamage == 0)
5315 return;
5317 uint32 creatureTypeMask = GetCreatureTypeMask();
5319 if(GetTypeId() != TYPEID_PLAYER && ((Creature*)this)->isPet())
5321 if(getPowerType() == POWER_FOCUS)
5323 uint32 happiness = GetPower(POWER_HAPPINESS);
5324 if(happiness>=666000)
5325 *pdamage = uint32(*pdamage * 1.25);
5326 else if(happiness<333000)
5327 *pdamage = uint32(*pdamage * 0.75);
5328 else *pdamage = uint32(*pdamage * 1.0);
5332 // Taken/Done fixed damage bonus auras
5333 int32 DoneFlatBenefit = 0;
5334 int32 TakenFlatBenefit = 0;
5336 // ..done (for creature type by mask) in taken
5337 AuraList const& mDamageDoneCreature = this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
5338 for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
5339 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
5340 DoneFlatBenefit += (*i)->GetModifier()->m_amount;
5342 // ..done
5343 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
5345 // ..done (base at attack power and creature type)
5346 AuraList const& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_CREATURE_ATTACK_POWER);
5347 for(AuraList::const_iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i)
5348 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
5349 DoneFlatBenefit += int32((*i)->GetModifier()->m_amount/14.0f * GetAttackTime(attType)/1000);
5351 // ..done (base at attack power for marked target)
5352 if(attType == RANGED_ATTACK)
5354 AuraList const& mRangedAttackPowerAttackerBonus = pVictim->GetAurasByType(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS);
5355 for(AuraList::const_iterator i = mRangedAttackPowerAttackerBonus.begin();i != mRangedAttackPowerAttackerBonus.end(); ++i)
5356 DoneFlatBenefit += int32((*i)->GetModifier()->m_amount/14.0f * GetAttackTime(RANGED_ATTACK)/1000);
5359 // ..taken
5360 AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
5361 for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
5362 if((*i)->GetModifier()->m_miscvalue & IMMUNE_SCHOOL_PHYSICAL)
5363 TakenFlatBenefit += (*i)->GetModifier()->m_amount;
5365 if(attType!=RANGED_ATTACK)
5367 AuraList const& mModMeleeDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN);
5368 for(AuraList::const_iterator i = mModMeleeDamageTaken.begin(); i != mModMeleeDamageTaken.end(); ++i)
5369 TakenFlatBenefit += (*i)->GetModifier()->m_amount;
5371 else
5373 AuraList const& mModRangedDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN);
5374 for(AuraList::const_iterator i = mModRangedDamageTaken.begin(); i != mModRangedDamageTaken.end(); ++i)
5375 TakenFlatBenefit += (*i)->GetModifier()->m_amount;
5378 // Done/Taken total percent damage auras
5379 float TakenTotalMod = 1;
5381 // ..done
5382 // SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage
5383 // SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage
5385 // ..taken
5386 AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
5387 for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
5388 if((*i)->GetModifier()->m_miscvalue & IMMUNE_SCHOOL_PHYSICAL)
5389 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
5391 if(attType != RANGED_ATTACK)
5393 AuraList const& mModMeleeDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT);
5394 for(AuraList::const_iterator i = mModMeleeDamageTakenPercent.begin(); i != mModMeleeDamageTakenPercent.end(); ++i)
5395 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
5397 else
5399 AuraList const& mModRangedDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT);
5400 for(AuraList::const_iterator i = mModRangedDamageTakenPercent.begin(); i != mModRangedDamageTakenPercent.end(); ++i)
5401 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
5404 float tmpDamage = ((int32(*pdamage) + DoneFlatBenefit) + TakenFlatBenefit)*TakenTotalMod;
5406 // bonus result can be negative
5407 *pdamage = tmpDamage > 0 ? uint32(tmpDamage) : 0;
5410 void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply)
5412 if (apply)
5414 for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(), next; itr != m_spellImmune[op].end(); itr = next)
5416 next = itr; next++;
5417 if(itr->type == type)
5419 m_spellImmune[op].erase(itr);
5420 next = m_spellImmune[op].begin();
5423 SpellImmune Immune;
5424 Immune.spellId = spellId;
5425 Immune.type = type;
5426 m_spellImmune[op].push_back(Immune);
5428 else
5430 for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(); itr != m_spellImmune[op].end(); ++itr)
5432 if(itr->spellId == spellId)
5434 m_spellImmune[op].erase(itr);
5435 break;
5442 float Unit::GetWeaponProcChance() const
5444 // normalized proc chance for weapon attack speed
5445 // (odd formulae...)
5446 if(isAttackReady(BASE_ATTACK))
5447 return (GetAttackTime(BASE_ATTACK) * 1.8f / 1000.0f);
5448 else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK))
5449 return (GetAttackTime(OFF_ATTACK) * 1.6f / 1000.0f);
5450 return 0;
5453 float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM) const
5455 // proc per minute chance calculation
5456 if (PPM <= 0) return 0.0f;
5457 uint32 result = uint32((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
5458 return result;
5461 void Unit::Mount(uint32 mount, bool taxi)
5463 if(!mount)
5464 return;
5466 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, mount);
5468 uint32 flag = UNIT_FLAG_MOUNT;
5469 if(taxi)
5470 flag |= UNIT_FLAG_DISABLE_MOVE;
5472 SetFlag( UNIT_FIELD_FLAGS, flag );
5474 // unsummon pet
5475 if(GetTypeId() == TYPEID_PLAYER)
5477 Pet* pet = GetPet();
5478 if(pet)
5480 if(pet->getPetType() == SUMMON_PET || pet->getPetType() == HUNTER_PET)
5482 ((Player*)this)->SetOldPetNumber(pet->GetCharmInfo()->GetPetNumber());
5483 ((Player*)this)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL));
5486 ((Player*)this)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT);
5488 else
5489 ((Player*)this)->SetOldPetNumber(0);
5493 void Unit::Unmount()
5495 if(!IsMounted())
5496 return;
5498 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0);
5499 RemoveFlag( UNIT_FIELD_FLAGS ,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_MOUNT );
5501 if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->GetOldPetNumber() && isAlive())
5503 Pet* NewPet = new Pet(this);
5504 if(!NewPet->LoadPetFromDB(this, 0, ((Player*)this)->GetOldPetNumber(), true))
5505 delete NewPet;
5507 ((Player*)this)->SetOldPetNumber(0);
5511 void Unit::SetInCombat()
5513 m_CombatTimer = 5000;
5514 SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
5516 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet()))
5517 SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
5520 void Unit::ClearInCombat(bool force)
5522 // wait aura and combat timer expire
5523 if(!force && HasAuraType(SPELL_AURA_INTERRUPT_REGEN))
5524 return;
5526 m_CombatTimer = 0;
5527 RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
5529 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet()))
5530 RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
5532 // remove combo points
5533 if(GetTypeId()==TYPEID_PLAYER)
5534 ((Player*)this)->ClearComboPoints();
5537 bool Unit::isTargetableForAttack()
5539 if (GetTypeId()==TYPEID_PLAYER && ((Player *)this)->isGameMaster())
5540 return false;
5541 return isAlive() && !hasUnitState(UNIT_STAT_DIED)&& !isInFlight() /*&& !isStealth()*/;
5544 int32 Unit::ModifyHealth(int32 dVal)
5546 int32 gain = 0;
5548 if(dVal==0)
5549 return 0;
5551 int32 curHealth = (int32)GetHealth();
5553 int32 val = dVal + curHealth;
5554 if(val <= 0)
5556 SetHealth(0);
5557 return -curHealth;
5560 int32 maxHealth = (int32)GetMaxHealth();
5562 if(val < maxHealth)
5564 SetHealth(val);
5565 gain = val - curHealth;
5567 else if(curHealth != maxHealth)
5569 SetHealth(maxHealth);
5570 gain = maxHealth - curHealth;
5573 return gain;
5576 int32 Unit::ModifyPower(Powers power, int32 dVal)
5578 int32 gain = 0;
5580 if(dVal==0)
5581 return 0;
5583 int32 curPower = (int32)GetPower(power);
5585 int32 val = dVal + curPower;
5586 if(val <= 0)
5588 SetPower(power,0);
5589 return -curPower;
5592 int32 maxPower = (int32)GetMaxPower(power);
5594 if(val < maxPower)
5596 SetPower(power,val);
5597 gain = val - curPower;
5599 else if(curPower != maxPower)
5601 SetPower(power,maxPower);
5602 gain = maxPower - curPower;
5605 return gain;
5608 bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList) const
5610 if(!u)
5611 return false;
5613 // Always can see self
5614 if (u==this)
5615 return true;
5617 // player visible for other player if not logout and at same transport
5618 // including case when player is out of world
5619 bool at_same_transport =
5620 GetTypeId() == TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER &&
5621 !((Player*)this)->GetSession()->PlayerLogout() && !((Player*)u)->GetSession()->PlayerLogout() &&
5622 !((Player*)this)->GetSession()->PlayerLoading() && !((Player*)u)->GetSession()->PlayerLoading() &&
5623 ((Player*)this)->GetTransport() && ((Player*)this)->GetTransport() == ((Player*)u)->GetTransport();
5625 // not in world
5626 if(!at_same_transport && (!IsInWorld() || !u->IsInWorld()))
5627 return false;
5629 // always seen by owner
5630 if(GetCharmerOrOwnerGUID()==u->GetGUID())
5631 return true;
5633 // Grid dead/alive checks
5634 if( u->GetTypeId()==TYPEID_PLAYER)
5636 // non visible at grid for any stealth state
5637 if(!IsVisibleInGridForPlayer((Player *)u))
5638 return false;
5640 // if player is dead then he can't detect anyone in anycases
5641 if(!u->isAlive())
5642 detect = false;
5644 else
5646 // all dead creatures/players not visible for any creatures
5647 if(!u->isAlive() || !isAlive())
5648 return false;
5651 // different visible distance checks
5652 if(u->isInFlight()) // what see player in flight
5654 // use object grey distance for all (only see objects any way)
5655 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceInFlight()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f)))
5656 return false;
5658 else if(!isAlive()) // distance for show body
5660 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f)))
5661 return false;
5663 else if(GetTypeId()==TYPEID_PLAYER) // distance for show player
5665 if(u->GetTypeId()==TYPEID_PLAYER)
5667 // Players far than max visible distance for player or not in our map are not visible too
5668 if (!at_same_transport && !IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))
5669 return false;
5671 else
5673 // Units far than max visible distance for creature or not in our map are not visible too
5674 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))
5675 return false;
5678 else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed
5680 // Pet/charmed far than max visible distance for player or not in our map are not visible too
5681 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))
5682 return false;
5684 else // distance for show creature
5686 // Units far than max visible distance for creature or not in our map are not visible too
5687 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))
5688 return false;
5691 // Visible units, always are visible for all units, except for units under invisibility
5692 if (m_Visibility == VISIBILITY_ON && u->GetVisibility()!= VISIBILITY_GROUP_INVISIBILITY)
5693 return true;
5695 // GMs are visible for higher gms (or players are visible for gms)
5696 if (u->GetTypeId() == TYPEID_PLAYER && ((Player *)u)->isGameMaster())
5697 return (GetTypeId() == TYPEID_PLAYER && ((Player *)this)->GetSession()->GetSecurity() <= ((Player *)u)->GetSession()->GetSecurity());
5699 // non faction visibility non-breakable for non-GMs
5700 if (m_Visibility == VISIBILITY_OFF)
5701 return false;
5703 // Invisible units, always are visible for units under invisibility or unit that can detect this invisibility
5704 if (m_Visibility == VISIBILITY_GROUP_INVISIBILITY)
5706 if(u->GetVisibility()== VISIBILITY_GROUP_INVISIBILITY || m_invisibilityvalue <= u->m_detectInvisibility)
5707 return true;
5710 // Units that can detect invisibility always are visible for units that can be detected
5711 if (u->GetVisibility()== VISIBILITY_GROUP_INVISIBILITY)
5713 if(m_detectInvisibility >= u->m_invisibilityvalue)
5714 return true;
5717 // Stealth/invisible not hostile units, not visible (except Player-with-Player case)
5718 if (!u->IsHostileTo(this))
5720 // 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)
5721 if(GetTypeId()==TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER)
5723 if(((Player*)this)->IsGroupVisibleFor(((Player*)u)))
5724 return true;
5726 // else apply same rules as for hostile case (detecting check)
5729 else
5731 // Hunter mark functionality
5732 AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_STALKED);
5733 for(AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
5734 if((*iter)->GetCasterGUID()==u->GetGUID())
5735 return true;
5738 // unit got in stealth in this moment and must ignore old detected state
5739 // invisibility not have chance for detection
5740 if (m_Visibility == VISIBILITY_ON || m_Visibility == VISIBILITY_GROUP_NO_DETECT || m_Visibility == VISIBILITY_GROUP_INVISIBILITY)
5741 return false;
5743 // NOW ONLY STEALTH CASE
5745 // stealth and detected
5746 if (u->GetTypeId() == TYPEID_PLAYER && ((Player*)u)->HaveAtClient(this) )
5747 return true;
5749 //if in non-detect mode then invisible for unit
5750 if (!detect)
5751 return false;
5753 // Special cases
5754 bool IsVisible = true;
5755 bool isInFront = u->isInFront(this,World::GetMaxVisibleDistanceForObject());
5756 float distance = sqrt(GetDistanceSq(u));
5758 // If is attacked then stealth is lost, some creature can use stealth too
5759 if (this->isAttacked())
5760 return IsVisible;
5762 // If there is collision rogue is seen regardless of level difference
5763 // TODO: check sizes in DB
5764 if (distance < 0.24f)
5765 return IsVisible;
5767 //If a mob or player is stunned he will not be able to detect stealth
5768 if ((u->hasUnitState(UNIT_STAT_STUNDED)) && (u != this))
5770 IsVisible=false;
5771 return IsVisible;
5774 // Cases based on level difference and position
5775 int32 levelDiff = u->getLevel() - this->getLevel();
5777 //If mob is 5 levels more than player he gets detected automaticly
5778 if (u->GetTypeId()!=TYPEID_PLAYER && levelDiff > 5)
5779 return IsVisible;
5781 // If victim has more than 5 lvls above caster
5782 if ((this->GetTypeId() == TYPEID_UNIT)&& ( levelDiff > 5 ))
5783 return IsVisible;
5785 // If caster has more than 5 levels above victim
5786 if ((this->GetTypeId() == TYPEID_UNIT)&& ( levelDiff < -5 ))
5788 IsVisible=false;
5789 return IsVisible;
5792 float modifier = 1; // 100 pct
5793 float pvpMultiplier = 0;
5794 float distanceFormula = 0;
5795 int32 rank = 0;
5796 //This allows to check talent tree and will add addition stealth dependant on used points)
5797 uint32 stealthMod = GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL);
5798 //****************************************************************************************
5799 // Stealth detection calculation
5800 int32 x = (((u->m_detectStealth+1) / 5) - (((m_stealthvalue+1) / 5) + (stealthMod/5) + 59));
5802 if (x<0) x = 1;
5803 // Check rank if mob is not a player otherwise rank = 1 and there is no modifier when in pvp
5804 if (u->GetTypeId() != TYPEID_PLAYER)
5805 rank = ((Creature const*)u)->GetCreatureInfo()->rank;
5807 // Probabilty of being seen
5808 if (levelDiff < 0)
5809 distanceFormula = ((sWorld.getRate(RATE_CREATURE_AGGRO) * 16) / (abs(levelDiff) + 1.5)) * 2;
5810 if (levelDiff >= 0)
5811 distanceFormula = (((sWorld.getRate(RATE_CREATURE_AGGRO) * 16)) / 2) * (levelDiff + 1);
5813 // Original probability values
5814 // removed level of mob in calculation as it should not affect the detection, it is mainly dependant on level difference
5815 //at this distance, the detector has to be a 15% prob of detect
5816 float averageDist = 1 - 0.11016949 * x + 0.00301637 * x * x;
5817 if (averageDist < 1) averageDist = 1;
5819 float prob = 0;
5820 if (distance > averageDist)
5821 //prob between 10% and 0%
5822 prob = (averageDist - 200 + 9 * distance) / (averageDist - 20);
5823 else
5824 prob = 75 - (60 / averageDist) * distance; //prob between 15% and 75% (75% max prob)
5826 // If is not in front, probability floor
5827 if (!isInFront)
5828 prob = prob / 100;
5829 if (prob < 0.1)
5830 prob = 0.1;
5832 // Mob rank affects modifier
5833 modifier = rank <= 4 ? 1 + rank * 0.2f : 1;
5835 if (distance < 0.24f)
5837 return IsVisible;
5840 // PVP distance assigned depending on level
5841 if (this->GetTypeId() == TYPEID_UNIT)
5843 // Level diff floor/ceiling <-5,5>
5844 pvpMultiplier = levelDiff > 5 ? 12 : levelDiff < 5 ? 2 : 7 + levelDiff;
5845 pvpMultiplier = pvpMultiplier - (x / 100);
5848 // PVP stealth handler
5849 if (this->GetTypeId() == TYPEID_PLAYER)
5851 // Do not loose stealth when coming from back
5852 if (!isInFront)
5854 IsVisible=false;
5855 return IsVisible;
5858 // If comes in front
5859 if (isInFront && (distance >= pvpMultiplier))
5861 IsVisible=false;
5862 return IsVisible;
5865 if (isInFront && (distance < pvpMultiplier))
5867 return IsVisible;
5870 else
5872 // PVE stealth handler
5873 // Distance of approch player stays stealth 100% is dependant of level. No probabiliy or detection is rolled
5874 // This establishes a buffer zone in between mob start to see you and mob start to roll probabilities or detect you
5875 if ((distance < 100) && (distance > ((distanceFormula * 2) * modifier)) && (distance > 0.24f))
5877 IsVisible=false;
5878 return IsVisible;
5881 //If victim is level lower or more probability of detection drops
5882 if ((levelDiff < 0) && (distance > 0.24f))
5884 if (abs(levelDiff ) > 4)
5885 IsVisible = false;
5886 else
5888 if (rand_chance() > ( prob * modifier / (30 + levelDiff * 5)))
5889 IsVisible = false;
5891 return IsVisible;
5893 // Level detection based on level, the higher the mob level the higher the chance of detection.
5894 if ((distance > 0.24f) && (levelDiff < 5) && (levelDiff >= 0))
5896 if (rand_chance() > ((prob * modifier) / (30 - levelDiff * 5) ))
5897 IsVisible = false;
5898 else
5899 IsVisible = true;
5901 return IsVisible;
5905 // Didn't match any criteria ?
5906 DEBUG_LOG("Unit::isVisibleForFor unhandled result, dist %f levelDiff %i target_type %u prob %u modifier %u",distance,levelDiff,u->GetTypeId(),prob, modifier);
5908 // Safety return
5909 return IsVisible;
5912 void Unit::SetVisibility(UnitVisibility x)
5914 m_Visibility = x;
5916 if(IsInWorld())
5918 Map *m = MapManager::Instance().GetMap(GetMapId(), this);
5920 if(GetTypeId()==TYPEID_PLAYER)
5921 m->PlayerRelocation((Player*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
5922 else
5923 m->CreatureRelocation((Creature*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
5927 float Unit::GetSpeed( UnitMoveType mtype ) const
5929 return m_speed_rate[mtype]*baseMoveSpeed[mtype];
5932 void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced)
5934 m_speed_rate[mtype] = 1.0f;
5935 ApplySpeedMod(mtype, rate, forced, true);
5938 void Unit::ApplySpeedMod(UnitMoveType mtype, float rate, bool forced, bool apply)
5940 WorldPacket data;
5942 if(apply)
5943 m_speed_rate[mtype] *= rate;
5944 else
5945 m_speed_rate[mtype] /= rate;
5947 switch(mtype)
5949 case MOVE_WALK:
5950 if(forced) { data.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE, 16); }
5951 else { data.Initialize(MSG_MOVE_SET_WALK_SPEED, 16); }
5952 break;
5953 case MOVE_RUN:
5954 if(forced) { data.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE, 16); }
5955 else { data.Initialize(MSG_MOVE_SET_RUN_SPEED, 16); }
5956 break;
5957 case MOVE_WALKBACK:
5958 if(forced) { data.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE, 16); }
5959 else { data.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED, 16); }
5960 break;
5961 case MOVE_SWIM:
5962 if(forced) { data.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE, 16); }
5963 else { data.Initialize(MSG_MOVE_SET_SWIM_SPEED, 16); }
5964 break;
5965 case MOVE_SWIMBACK:
5966 if(forced) { data.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE, 16); }
5967 else { data.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED, 16); }
5968 break;
5969 case MOVE_TURN:
5970 if(forced) { data.Initialize(SMSG_FORCE_TURN_RATE_CHANGE, 16); }
5971 else { data.Initialize(MSG_MOVE_SET_TURN_RATE, 16); }
5972 break;
5973 case MOVE_FLY:
5974 if(forced) { data.Initialize(SMSG_FORCE_FLY_SPEED_CHANGE, 16); }
5975 else { data.Initialize(SMSG_MOVE_SET_FLY_SPEED, 16); }
5976 break;
5977 case MOVE_FLYBACK:
5978 break;
5979 default:
5980 sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype);
5981 return;
5984 data.append(GetPackGUID());
5985 data << (uint32)0;
5986 if (mtype == MOVE_RUN) data << uint8(0); // new 2.1.0
5987 data << float(GetSpeed(mtype));
5988 SendMessageToSet( &data, true );
5990 if(Pet* pet = GetPet())
5991 pet->SetSpeed(mtype,m_speed_rate[mtype],forced);
5994 void Unit::SetHover(bool on)
5996 if(on)
5997 CastSpell(this,11010,true);
5998 else
5999 RemoveAurasDueToSpell(11010);
6002 void Unit::setDeathState(DeathState s)
6004 if (s != ALIVE)
6006 CombatStop(true);
6008 if(IsNonMeleeSpellCasted(false))
6009 InterruptNonMeleeSpells(false);
6012 if (s == JUST_DIED)
6014 RemoveAllAurasOnDeath();
6015 UnsummonAllTotems();
6017 if (m_deathState != ALIVE && s == ALIVE)
6019 //_ApplyAllAuraMods();
6021 m_deathState = s;
6024 /*########################################
6025 ######## ########
6026 ######## AGGRO SYSTEM ########
6027 ######## ########
6028 ########################################*/
6029 bool Unit::CanHaveThreatList() const
6031 if(GetTypeId() == TYPEID_UNIT && !((Creature*)this)->isPet() && !((Creature*)this)->isTotem() )
6032 return true;
6033 else
6034 return false;
6037 //======================================================================
6039 float Unit::ApplyTotalThreatModifier(float threat, SpellSchools school)
6041 if(!HasAuraType(SPELL_AURA_MOD_THREAT))
6042 return threat;
6044 if(school >= MAX_SPELL_SCHOOL)
6046 sLog.outError("Unit::ApplyTotalThreatModifier: Spell school with out-of-range value: %u",uint32(school));
6047 return threat;
6050 return threat * m_threatModifier[school];
6053 //======================================================================
6055 void Unit::AddThreat(Unit* pVictim, float threat, SpellSchools school, SpellEntry const *threatSpell)
6057 // Only mobs can manage threat lists
6058 if(CanHaveThreatList())
6059 m_ThreatManager.addThreat(pVictim, threat, school, threatSpell);
6062 //======================================================================
6064 void Unit::DeleteThreatList()
6066 m_ThreatManager.clearReferences();
6069 //======================================================================
6071 void Unit::TauntApply(Unit* taunter)
6073 assert(GetTypeId()== TYPEID_UNIT);
6075 if(!taunter || (taunter->GetTypeId() == TYPEID_PLAYER && ((Player*)taunter)->isGameMaster()))
6076 return;
6078 if(!CanHaveThreatList())
6079 return;
6081 Unit *target = getVictim();
6082 if(target && target == taunter)
6083 return;
6085 SetInFront(taunter);
6086 if (((Creature*)this)->AI())
6087 ((Creature*)this)->AI()->AttackStart(taunter);
6089 m_ThreatManager.tauntApply(taunter);
6092 //======================================================================
6094 void Unit::TauntFadeOut(Unit *taunter)
6096 assert(GetTypeId()== TYPEID_UNIT);
6098 if(!taunter || (taunter->GetTypeId() == TYPEID_PLAYER && ((Player*)taunter)->isGameMaster()))
6099 return;
6101 if(!CanHaveThreatList())
6102 return;
6104 Unit *target = getVictim();
6105 if(!target || target != taunter)
6106 return;
6108 if(m_ThreatManager.isThreatListEmpty())
6110 if(((Creature*)this)->AI())
6111 ((Creature*)this)->AI()->EnterEvadeMode();
6112 return;
6115 m_ThreatManager.tauntFadeOut(taunter);
6116 target = m_ThreatManager.getHostilTarget();
6118 if (target && target != taunter)
6120 SetInFront(target);
6121 if (((Creature*)this)->AI())
6122 ((Creature*)this)->AI()->AttackStart(target);
6126 //======================================================================
6128 bool Unit::SelectHostilTarget()
6130 //function provides main threat functionality
6131 //next-victim-selection algorithm and evade mode are called
6132 //threat list sorting etc.
6134 assert(GetTypeId()== TYPEID_UNIT);
6135 Unit* target = NULL;
6137 //This function only useful once AI has been initilazied
6138 if (!((Creature*)this)->AI())
6139 return false;
6141 if(!m_ThreatManager.isThreatListEmpty())
6143 if(!HasAuraType(SPELL_AURA_MOD_TAUNT))
6145 target = m_ThreatManager.getHostilTarget();
6149 if(target)
6151 SetInFront(target);
6152 ((Creature*)this)->AI()->AttackStart(target);
6153 return true;
6156 if(isInCombat() && !HasAuraType(SPELL_AURA_MOD_TAUNT) && CanFreeMove() && m_attackers.empty())
6157 ((Creature*)this)->AI()->EnterEvadeMode();
6159 return false;
6162 //======================================================================
6163 //======================================================================
6164 //======================================================================
6166 void Unit::CalculateSpellDamageAndDuration(int32* damage, int32* duration, SpellEntry const* spellProto, uint8 effect_index, int32 effBasePoints)
6168 Player* unitPlayer = (GetTypeId() == TYPEID_PLAYER) ? (Player*)this : NULL;
6170 uint8 comboPoints = unitPlayer ? unitPlayer->GetComboPoints() : 0;
6171 bool needClearCombo = false;
6173 if(damage)
6175 int32 value = 0;
6176 uint32 level = 0;
6178 level = getLevel() - spellProto->spellLevel;
6179 if (level > spellProto->maxLevel && spellProto->maxLevel > 0)
6180 level = spellProto->maxLevel;
6182 float basePointsPerLevel = spellProto->EffectRealPointsPerLevel[effect_index];
6183 float randomPointsPerLevel = spellProto->EffectDicePerLevel[effect_index];
6184 int32 basePoints = int32(effBasePoints + level * basePointsPerLevel);
6185 int32 randomPoints = int32(spellProto->EffectDieSides[effect_index] + level * randomPointsPerLevel);
6186 float comboDamage = spellProto->EffectPointsPerComboPoint[effect_index];
6188 value = basePoints + rand32(spellProto->EffectBaseDice[effect_index], randomPoints);
6189 //random damage
6190 if(int32(spellProto->EffectBaseDice[effect_index]) != randomPoints && GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
6191 value += ((Pet*)this)->GetBonusDamage(); //bonus damage only on spells without fixed basePoints?)
6193 if(comboDamage != 0 && unitPlayer && m_attacking && (m_attacking->GetGUID() == unitPlayer->GetComboTarget()))
6195 value += (int32)(comboDamage * comboPoints);
6197 // Eviscerate
6198 if( spellProto->SpellIconID == 514 && spellProto->SpellFamilyName == SPELLFAMILY_ROGUE)
6199 value += (int32)(GetTotalAttackPowerValue(BASE_ATTACK) * comboPoints * 0.03);
6201 needClearCombo = true;
6204 if (GetTypeId() == TYPEID_PLAYER)
6206 ((Player *)this)->ApplySpellMod(spellProto->Id,SPELLMOD_ALL_EFFECTS, value);
6207 switch(effect_index)
6209 case 0:
6210 ((Player*)this)->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT1, value);
6211 break;
6212 case 1:
6213 ((Player*)this)->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT2, value);
6214 break;
6215 case 2:
6216 ((Player*)this)->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT3, value);
6217 break;
6220 ((Player*)this)->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, value);
6224 *damage = value;
6227 if(duration)
6229 int32 minduration = GetDuration(spellProto);
6230 int32 maxduration = GetMaxDuration(spellProto);
6232 if( minduration != -1 && minduration != maxduration )
6234 *duration = minduration + int32((maxduration - minduration) * comboPoints / 5);
6235 needClearCombo = true;
6237 else
6238 *duration = minduration;
6241 if(unitPlayer && needClearCombo)
6242 unitPlayer->SetComboPoints(unitPlayer->GetComboTarget(), 0);
6245 void Unit::AddDiminishing(DiminishingMechanics mech, uint32 hitTime, uint32 hitCount)
6247 m_Diminishing.push_back(DiminishingReturn(mech,hitTime,hitCount));
6250 DiminishingLevels Unit::GetDiminishing(DiminishingMechanics mech)
6252 for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
6254 if(i->Mechanic != mech) continue;
6255 if(!i->hitCount) return DIMINISHING_LEVEL_1;
6256 if(!i->hitTime) return DIMINISHING_LEVEL_1;
6257 // If last spell was casted more than 15 seconds ago - reset the count.
6258 if((getMSTime() - i->hitTime) > 15000)
6260 i->hitCount = DIMINISHING_LEVEL_1;
6261 return DIMINISHING_LEVEL_1;
6263 // or else increase the count.
6264 else
6266 if(i->hitCount > DIMINISHING_LEVEL_2)
6268 i->hitCount = DIMINISHING_LEVEL_IMMUNE;
6269 return DIMINISHING_LEVEL_IMMUNE;
6271 else return DiminishingLevels(i->hitCount);
6274 return DIMINISHING_LEVEL_1;
6277 void Unit::IncrDiminishing(DiminishingMechanics mech, uint32 duration)
6279 // Checking for existing in the table
6280 bool IsExist = false;
6281 for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
6283 if(i->Mechanic != mech)
6284 continue;
6286 IsExist = true;
6287 if(i->hitCount < DIMINISHING_LEVEL_IMMUNE)
6289 i->hitCount += 1;
6290 switch(i->hitCount)
6292 case DIMINISHING_LEVEL_2: i->hitTime = uint32(getMSTime() + duration); break;
6293 case DIMINISHING_LEVEL_3: i->hitTime = uint32(getMSTime() + duration*0.5); break;
6294 case DIMINISHING_LEVEL_IMMUNE: i->hitTime = uint32(getMSTime() + duration*0.25); break;
6295 default: break;
6298 break;
6301 if(!IsExist)
6302 AddDiminishing(mech,uint32(getMSTime() + duration),DIMINISHING_LEVEL_2);
6305 void Unit::UpdateDiminishingTime(DiminishingMechanics mech)
6307 // Checking for existing in the table
6308 bool IsExist = false;
6309 for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
6311 if(i->Mechanic != mech)
6312 continue;
6314 IsExist = true;
6315 i->hitTime = getMSTime();
6316 break;
6319 if(!IsExist)
6320 AddDiminishing(mech,getMSTime(),DIMINISHING_LEVEL_1);
6323 DiminishingMechanics Unit::Mechanic2DiminishingMechanics(uint32 mech)
6325 switch(mech)
6327 case MECHANIC_CHARM: case MECHANIC_FEAR: case MECHANIC_SLEEP:
6328 return DIMINISHING_MECHANIC_CHARM;
6329 case MECHANIC_CONFUSED: case MECHANIC_KNOCKOUT: case MECHANIC_POLYMORPH:
6330 return DIMINISHING_MECHANIC_CONFUSE;
6331 case MECHANIC_ROOT: case MECHANIC_FREEZE:
6332 return DIMINISHING_MECHANIC_ROOT;
6333 case MECHANIC_STUNDED:
6334 return DIMINISHING_MECHANIC_STUN;
6335 case MECHANIC_CHASE:
6336 return DIMINISHING_MECHANIC_SPEED;
6337 default:
6338 break;
6340 return DIMINISHING_NONE;
6343 float Unit::ApplyDiminishingToDuration(DiminishingMechanics mech, int32 duration,Unit* caster)
6345 if(duration == -1 || mech == DIMINISHING_NONE)
6346 return 1.0f;
6348 // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
6349 if(duration > 10000)
6351 // test pet/charm masters instead pets/charmeds
6352 Unit const* targetOwner = GetCharmerOrOwner();
6353 Unit const* casterOwner = caster->GetCharmerOrOwner();
6355 Unit const* target = targetOwner ? targetOwner : this;
6356 Unit const* source = casterOwner ? casterOwner : caster;
6358 if(target->GetTypeId() == TYPEID_PLAYER && source->GetTypeId() == TYPEID_PLAYER)
6359 duration = 10000;
6362 float mod = 1.0f;
6364 // Stun diminishing is applies to mobs too
6365 if(mech == DIMINISHING_MECHANIC_STUN || GetTypeId() == TYPEID_PLAYER)
6367 DiminishingLevels diminish = GetDiminishing(mech);
6368 switch(diminish)
6370 case DIMINISHING_LEVEL_1: IncrDiminishing(mech, duration); break;
6371 case DIMINISHING_LEVEL_2: IncrDiminishing(mech, duration); mod = 0.5f; break;
6372 case DIMINISHING_LEVEL_3: IncrDiminishing(mech, duration); mod = 0.25f; break;
6373 case DIMINISHING_LEVEL_IMMUNE: mod = 0.0f; break;
6374 default: break;
6378 return mod;
6381 Creature* Unit::SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime)
6383 TemporarySummon* pCreature = new TemporarySummon(this,this);
6385 pCreature->SetInstanceId(GetInstanceId());
6387 if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), GetMapId(), x, y, z, ang, id))
6389 delete pCreature;
6390 return NULL;
6393 pCreature->Summon(spwtype, despwtime);
6395 //return the creature therewith the summoner has access to it
6396 return pCreature;
6399 Unit* Unit::GetUnit(WorldObject& object, uint64 guid)
6401 return ObjectAccessor::Instance().GetUnit(object,guid);
6404 bool Unit::isVisibleForInState( Player const* u, bool inVisibleList ) const
6406 return isVisibleForOrDetect(u,false,inVisibleList);
6409 uint32 Unit::GetCreatureType() const
6411 if(GetTypeId() == TYPEID_PLAYER)
6413 switch(((Player const*)this)->m_form)
6415 case FORM_CAT:
6416 case FORM_TRAVEL:
6417 case FORM_AQUA:
6418 case FORM_BEAR:
6419 case FORM_DIREBEAR:
6420 case FORM_GHOSTWOLF:
6421 case FORM_SWIFT_FLIGHT:
6422 case FORM_FLIGHT:
6423 return CREATURE_TYPE_BEAST;
6424 case FORM_TREE:
6425 case FORM_SPIRITOFREDEMPTION:
6426 return CREATURE_TYPE_ELEMENTAL;
6427 case FORM_MOONKIN:
6428 default:
6429 return CREATURE_TYPE_HUMANOID;
6432 else
6433 return ((Creature*)this)->GetCreatureInfo()->type;
6436 /*#######################################
6437 ######## ########
6438 ######## STAT SYSTEM ########
6439 ######## ########
6440 #######################################*/
6442 bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, float amount, bool apply)
6444 if(unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END)
6446 sLog.outError("ERROR in HandleStatModifier(): nonexisted UnitMods or wrong UnitModifierType!");
6447 return false;
6450 float val = 1.0f;
6452 switch(modifierType)
6454 case BASE_VALUE:
6455 case TOTAL_VALUE:
6456 m_auraModifiersGroup[unitMod][modifierType] += apply ? amount : -amount;
6457 break;
6458 case BASE_PCT:
6459 case TOTAL_PCT:
6460 if(amount <= -100.0f) //small hack-fix for -100% modifiers
6461 amount = -200.0f;
6463 val = (100.0f + amount) / 100.0f;
6464 m_auraModifiersGroup[unitMod][modifierType] *= apply ? val : (1.0f/val);
6465 break;
6467 default:
6468 break;
6471 if(!CanModifyStats())
6472 return false;
6474 switch(unitMod)
6476 case UNIT_MOD_STAT_STRENGTH:
6477 case UNIT_MOD_STAT_AGILITY:
6478 case UNIT_MOD_STAT_STAMINA:
6479 case UNIT_MOD_STAT_INTELLECT:
6480 case UNIT_MOD_STAT_SPIRIT: UpdateStats(GetStatByAuraGroup(unitMod)); break;
6482 case UNIT_MOD_ARMOR: UpdateArmor(); break;
6483 case UNIT_MOD_HEALTH: UpdateMaxHealth(); break;
6485 case UNIT_MOD_MANA:
6486 case UNIT_MOD_RAGE:
6487 case UNIT_MOD_FOCUS:
6488 case UNIT_MOD_ENERGY:
6489 case UNIT_MOD_HAPPINESS: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod)); break;
6491 case UNIT_MOD_RESISTANCE_HOLY:
6492 case UNIT_MOD_RESISTANCE_FIRE:
6493 case UNIT_MOD_RESISTANCE_NATURE:
6494 case UNIT_MOD_RESISTANCE_FROST:
6495 case UNIT_MOD_RESISTANCE_SHADOW:
6496 case UNIT_MOD_RESISTANCE_ARCANE: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod)); break;
6498 case UNIT_MOD_ATTACK_POWER: UpdateAttackPowerAndDamage(); break;
6499 case UNIT_MOD_ATTACK_POWER_RANGED: UpdateAttackPowerAndDamage(true); break;
6501 case UNIT_MOD_DAMAGE_MAINHAND: UpdateDamagePhysical(BASE_ATTACK); break;
6502 case UNIT_MOD_DAMAGE_OFFHAND: UpdateDamagePhysical(OFF_ATTACK); break;
6503 case UNIT_MOD_DAMAGE_RANGED: UpdateDamagePhysical(RANGED_ATTACK); break;
6505 default:
6506 break;
6509 return true;
6512 float Unit::GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) const
6514 if( unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END)
6516 sLog.outError("ERROR: trial to access nonexisted modifier value from UnitMods!");
6517 return 0.0f;
6520 if(modifierType == TOTAL_PCT && m_auraModifiersGroup[unitMod][modifierType] <= 0.0f)
6521 return 0.0f;
6523 return m_auraModifiersGroup[unitMod][modifierType];
6526 float Unit::GetTotalStatValue(Stats stat) const
6528 UnitMods unitMod = UnitMods(UNIT_MOD_STAT_START + stat);
6530 if(m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f)
6531 return 0.0f;
6533 // value = ((base_value * base_pct) + total_value) * total_pct
6534 float value = m_auraModifiersGroup[unitMod][BASE_VALUE] + GetCreateStat(stat);
6535 value *= m_auraModifiersGroup[unitMod][BASE_PCT];
6536 value += m_auraModifiersGroup[unitMod][TOTAL_VALUE];
6537 value *= m_auraModifiersGroup[unitMod][TOTAL_PCT];
6539 return value;
6542 float Unit::GetTotalAuraModValue(UnitMods unitMod) const
6544 if(unitMod >= UNIT_MOD_END)
6546 sLog.outError("ERROR: trial to access nonexisted UnitMods in GetTotalAuraModValue()!");
6547 return 0.0f;
6550 if(m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f)
6551 return 0.0f;
6553 float value = m_auraModifiersGroup[unitMod][BASE_VALUE];
6554 value *= m_auraModifiersGroup[unitMod][BASE_PCT];
6555 value += m_auraModifiersGroup[unitMod][TOTAL_VALUE];
6556 value *= m_auraModifiersGroup[unitMod][TOTAL_PCT];
6558 return value;
6561 SpellSchools Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod) const
6563 SpellSchools school = SPELL_SCHOOL_NORMAL;
6565 switch(unitMod)
6567 case UNIT_MOD_RESISTANCE_HOLY: school = SPELL_SCHOOL_HOLY; break;
6568 case UNIT_MOD_RESISTANCE_FIRE: school = SPELL_SCHOOL_FIRE; break;
6569 case UNIT_MOD_RESISTANCE_NATURE: school = SPELL_SCHOOL_NATURE; break;
6570 case UNIT_MOD_RESISTANCE_FROST: school = SPELL_SCHOOL_FROST; break;
6571 case UNIT_MOD_RESISTANCE_SHADOW: school = SPELL_SCHOOL_SHADOW; break;
6572 case UNIT_MOD_RESISTANCE_ARCANE: school = SPELL_SCHOOL_ARCANE; break;
6574 default:
6575 break;
6578 return school;
6581 Stats Unit::GetStatByAuraGroup(UnitMods unitMod) const
6583 Stats stat = STAT_STRENGTH;
6585 switch(unitMod)
6587 case UNIT_MOD_STAT_STRENGTH: stat = STAT_STRENGTH; break;
6588 case UNIT_MOD_STAT_AGILITY: stat = STAT_AGILITY; break;
6589 case UNIT_MOD_STAT_STAMINA: stat = STAT_STAMINA; break;
6590 case UNIT_MOD_STAT_INTELLECT: stat = STAT_INTELLECT; break;
6591 case UNIT_MOD_STAT_SPIRIT: stat = STAT_SPIRIT; break;
6593 default:
6594 break;
6597 return stat;
6600 Powers Unit::GetPowerTypeByAuraGroup(UnitMods unitMod) const
6602 Powers power = POWER_MANA;
6604 switch(unitMod)
6606 case UNIT_MOD_MANA: power = POWER_MANA; break;
6607 case UNIT_MOD_RAGE: power = POWER_RAGE; break;
6608 case UNIT_MOD_FOCUS: power = POWER_FOCUS; break;
6609 case UNIT_MOD_ENERGY: power = POWER_ENERGY; break;
6610 case UNIT_MOD_HAPPINESS: power = POWER_HAPPINESS; break;
6612 default:
6613 break;
6616 return power;
6619 float Unit::GetTotalAttackPowerValue(WeaponAttackType attType) const
6621 UnitMods unitMod = (attType == RANGED_ATTACK) ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER;
6623 float val = GetTotalAuraModValue(unitMod);
6624 if(val < 0.0f)
6625 val = 0.0f;
6627 return val;
6630 float Unit::GetWeaponDamageRange(WeaponAttackType attType ,WeaponDamageRange type) const
6632 if (attType == OFF_ATTACK && !haveOffhandWeapon())
6633 return 0.0f;
6635 return m_weaponDamage[attType][type];
6638 void Unit::SetLevel(uint32 lvl)
6640 SetUInt32Value(UNIT_FIELD_LEVEL,lvl);
6642 // group update
6643 if (GetTypeId() == TYPEID_PLAYER)
6644 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL);
6647 void Unit::SetHealth(uint32 val)
6649 uint32 maxHealth = GetMaxHealth();
6650 if(maxHealth < val)
6651 val = maxHealth;
6653 SetUInt32Value(UNIT_FIELD_HEALTH,val);
6655 // group update
6656 if (GetTypeId() == TYPEID_PLAYER)
6657 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP);
6660 void Unit::SetMaxHealth(uint32 val)
6662 uint32 health = GetHealth();
6663 SetUInt32Value(UNIT_FIELD_MAXHEALTH,val);
6665 // group update
6666 if (GetTypeId() == TYPEID_PLAYER)
6667 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP);
6669 if(val < health)
6670 SetHealth(val);
6673 void Unit::SetPower(Powers power, uint32 val)
6675 uint32 maxPower = GetMaxPower(power);
6676 if(maxPower < val)
6677 val = maxPower;
6679 SetStatInt32Value(UNIT_FIELD_POWER1 + power,val);
6681 // group update
6682 if (GetTypeId() == TYPEID_PLAYER)
6683 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER);
6686 void Unit::SetMaxPower(Powers power, uint32 val)
6688 uint32 cur_power = GetPower(power);
6689 SetStatInt32Value(UNIT_FIELD_MAXPOWER1 + power,val);
6691 // group update
6692 if (GetTypeId() == TYPEID_PLAYER)
6693 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER);
6695 if(val < cur_power)
6696 SetPower(power, val);
6699 void Unit::ApplyPowerMod(Powers power, uint32 val, bool apply)
6701 ApplyModUInt32Value(UNIT_FIELD_POWER1+power, val, apply);
6703 // group update
6704 if (GetTypeId() == TYPEID_PLAYER)
6705 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER);
6708 void Unit::ApplyMaxPowerMod(Powers power, uint32 val, bool apply)
6710 ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1+power, val, apply);
6712 // group update
6713 if (GetTypeId() == TYPEID_PLAYER)
6714 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER);
6717 void Unit::ApplyAuraProcTriggerDamage( Aura* aura, bool apply )
6719 AuraList& tAuraProcTriggerDamage = m_modAuras[SPELL_AURA_PROC_TRIGGER_DAMAGE];
6720 if(apply)
6721 tAuraProcTriggerDamage.push_back(aura);
6722 else
6723 tAuraProcTriggerDamage.remove(aura);
6726 uint32 Unit::GetCreatePowers( Powers power ) const
6728 // POWER_FOCUS and POWER_HAPPINESS only have hunter pet
6729 switch(power)
6731 case POWER_MANA: return GetCreateMana();
6732 case POWER_RAGE: return 1000;
6733 case POWER_FOCUS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 100);
6734 case POWER_ENERGY: return 100;
6735 case POWER_HAPPINESS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 1050000);
6738 return 0;
6741 void Unit::CleanupsBeforeDelete()
6743 if(m_uint32Values) // only for fully created object
6745 m_Events.KillAllEvents();
6746 CombatStop(true);
6747 DeleteThreatList();
6748 getHostilRefManager().setOnlineOfflineState(false);
6749 RemoveAllAuras();
6750 RemoveFromWorld();
6754 CharmInfo* Unit::InitCharmInfo(Unit *charm)
6756 if(!m_charmInfo)
6757 m_charmInfo = new CharmInfo(charm);
6758 return m_charmInfo;
6761 CharmInfo::CharmInfo(Unit* unit)
6762 : m_unit(unit), m_CommandState(COMMAND_STAY), m_ReactSate(REACT_PASSIVE), m_petnumber(0)
6764 for(int i =0; i<4; ++i)
6766 m_charmspells[i].spellId = 0;
6767 m_charmspells[i].active = ACT_DISABLED;
6771 void CharmInfo::InitPetActionBar()
6773 // the first 3 SpellOrActions are attack, follow and stay
6774 for(uint32 i = 0; i < 3; i++)
6776 PetActionBar[i].Type = ACT_COMMAND;
6777 PetActionBar[i].SpellOrAction = COMMAND_ATTACK - i;
6779 PetActionBar[i + 7].Type = ACT_REACTION;
6780 PetActionBar[i + 7].SpellOrAction = COMMAND_ATTACK - i;
6782 for(uint32 i=0; i < 4; i++)
6784 PetActionBar[i + 3].Type = ACT_DISABLED;
6785 PetActionBar[i + 3].SpellOrAction = 0;
6789 void CharmInfo::InitEmptyActionBar()
6791 for(uint32 x = 1; x < 10; ++x)
6793 PetActionBar[x].Type = ACT_CAST;
6794 PetActionBar[x].SpellOrAction = 0;
6796 PetActionBar[0].Type = ACT_COMMAND;
6797 PetActionBar[0].SpellOrAction = COMMAND_ATTACK;
6800 void CharmInfo::InitPossessCreateSpells()
6802 if(m_unit->GetTypeId() == TYPEID_PLAYER)
6803 return;
6805 InitEmptyActionBar(); //charm action bar
6807 for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x)
6809 if (IsPassiveSpell(((Creature*)m_unit)->m_spells[x]))
6810 m_unit->CastSpell(m_unit, ((Creature*)m_unit)->m_spells[x], true);
6811 else
6812 AddSpellToAB(0, ((Creature*)m_unit)->m_spells[x], ACT_CAST);
6816 void CharmInfo::InitCharmCreateSpells()
6818 if(m_unit->GetTypeId() == TYPEID_PLAYER) //charmed players don't have spells
6820 InitEmptyActionBar();
6821 return;
6824 InitPetActionBar();
6826 for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x)
6828 uint32 spellId = ((Creature*)m_unit)->m_spells[x];
6829 m_charmspells[x].spellId = spellId;
6831 if(!spellId)
6832 continue;
6834 if (IsPassiveSpell(spellId))
6836 m_unit->CastSpell(m_unit, spellId, true);
6837 m_charmspells[x].active = ACT_PASSIVE;
6839 else
6841 ActiveStates newstate;
6842 bool onlyselfcast = true;
6843 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
6845 if(!spellInfo) onlyselfcast = false;
6846 for(uint32 i = 0;i<3 && onlyselfcast;++i) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
6848 if(spellInfo->EffectImplicitTargetA[i] != TARGET_SELF && spellInfo->EffectImplicitTargetA[i] != 0)
6849 onlyselfcast = false;
6852 if(onlyselfcast || !IsPositiveSpell(spellId)) //only self cast and spells versus enemies are autocastable
6853 newstate = ACT_DISABLED;
6854 else
6855 newstate = ACT_CAST;
6857 AddSpellToAB(0, spellId, newstate);
6862 bool CharmInfo::AddSpellToAB(uint32 oldid, uint32 newid, ActiveStates newstate)
6864 for(uint8 i = 0; i < 10; i++)
6866 if((PetActionBar[i].Type == ACT_DISABLED || PetActionBar[i].Type == ACT_ENABLED || PetActionBar[i].Type == ACT_CAST) && PetActionBar[i].SpellOrAction == oldid)
6868 PetActionBar[i].SpellOrAction = newid;
6869 if(!oldid)
6871 if(newstate == ACT_DECIDE)
6872 PetActionBar[i].Type = ACT_DISABLED;
6873 else
6874 PetActionBar[i].Type = newstate;
6877 return true;
6880 return false;
6883 void CharmInfo::ToggleCreatureAutocast(uint32 spellid, bool apply)
6885 if(IsPassiveSpell(spellid))
6886 return;
6888 for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x)
6890 if(spellid == m_charmspells[x].spellId)
6892 m_charmspells[x].active = apply ? ACT_ENABLED : ACT_DISABLED;
6897 void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow)
6899 m_petnumber = petnumber;
6900 if(statwindow)
6901 m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, m_petnumber);
6902 else
6903 m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, 0);
6906 bool Unit::isFrozen() const
6908 AuraList const& mRoot = GetAurasByType(SPELL_AURA_MOD_ROOT);
6909 for(AuraList::const_iterator i = mRoot.begin(); i != mRoot.end(); ++i)
6910 if( (*i)->GetSpellProto()->School == SPELL_SCHOOL_FROST)
6911 return true;
6912 return false;