[4366] Applied MaNGOS coding style to src/game.
[mangos-git.git] / src / game / Unit.cpp
blob92982ea34dab24aa01098669289fb6fa838868f8
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"
42 #include <math.h>
44 float baseMoveSpeed[MAX_MOVE_TYPE] =
46 2.5f, // MOVE_WALK
47 7.0f, // MOVE_RUN
48 1.25f, // MOVE_WALKBACK
49 4.722222f, // MOVE_SWIM
50 4.5f, // MOVE_SWIMBACK
51 3.141594f, // MOVE_TURN
52 7.0f, // MOVE_FLY
53 4.5f // MOVE_FLYBACK
56 // auraTypes contains auras capable of proc'ing for attacker
57 static std::set<uint32> GenerateAttakerProcAuraTypes()
59 static std::set<uint32> auraTypes;
60 auraTypes.insert(SPELL_AURA_DUMMY);
61 auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL);
62 auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE);
63 return auraTypes;
66 // auraTypes contains auras capable of proc'ing for attacker
67 static std::set<uint32> GenerateVictimProcAuraTypes()
69 static std::set<uint32> auraTypes;
70 auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL);
71 auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE);
72 auraTypes.insert(SPELL_AURA_DUMMY);
73 auraTypes.insert(SPELL_AURA_MOD_PARRY_PERCENT);
74 return auraTypes;
77 static std::set<uint32> attackerProcAuraTypes = GenerateAttakerProcAuraTypes();
78 static std::set<uint32> victimProcAuraTypes = GenerateVictimProcAuraTypes();
80 // auraTypes contains auras capable of proc'ing for attacker and victim
81 static std::set<uint32> GenerateProcAuraTypes()
83 static std::set<uint32> auraTypes = victimProcAuraTypes;
84 auraTypes.insert(attackerProcAuraTypes.begin(),attackerProcAuraTypes.end());
85 return auraTypes;
88 static std::set<uint32> procAuraTypes = GenerateProcAuraTypes();
90 bool IsPassiveStackableSpell( uint32 spellId )
92 if(!IsPassiveSpell(spellId))
93 return false;
95 SpellEntry const* spellProto = sSpellStore.LookupEntry(spellId);
96 if(!spellProto)
97 return false;
99 for(int j = 0; j < 3; ++j)
101 if(std::find(procAuraTypes.begin(),procAuraTypes.end(),spellProto->EffectApplyAuraName[j])!=procAuraTypes.end())
102 return false;
105 return true;
108 Unit::Unit( WorldObject *instantiator )
109 : WorldObject( instantiator ), m_ThreatManager(this), m_HostilRefManager(this)
111 m_objectType |= TYPE_UNIT;
112 m_objectTypeId = TYPEID_UNIT;
113 // 2.1.2 - 0x70
114 m_updateFlag = (UPDATEFLAG_ALL | UPDATEFLAG_LIVING | UPDATEFLAG_HASPOSITION);
116 m_attackTimer[BASE_ATTACK] = 0;
117 m_attackTimer[OFF_ATTACK] = 0;
118 m_attackTimer[RANGED_ATTACK] = 0;
119 m_modAttackSpeedPct[BASE_ATTACK] = 1.0f;
120 m_modAttackSpeedPct[OFF_ATTACK] = 1.0f;
121 m_modAttackSpeedPct[RANGED_ATTACK] = 1.0f;
123 m_state = 0;
124 m_form = 0;
125 m_deathState = ALIVE;
127 for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
128 m_currentSpells[i] = NULL;
129 m_addDmgOnce = 0;
130 m_TotemSlot[0] = m_TotemSlot[1] = m_TotemSlot[2] = m_TotemSlot[3] = 0;
131 m_ObjectSlot[0] = m_ObjectSlot[1] = m_ObjectSlot[2] = m_ObjectSlot[3] = 0;
132 //m_Aura = NULL;
133 //m_AurasCheck = 2000;
134 //m_removeAuraTimer = 4;
135 //tmpAura = NULL;
136 m_silenced = false;
137 waterbreath = false;
139 m_Visibility = VISIBILITY_ON;
141 m_detectStealth = 0;
142 m_detectInvisibility = 0;
143 m_stealthvalue = 0;
144 m_invisibilityvalue = 0;
145 m_transform = 0;
146 m_ShapeShiftForm = 0;
147 m_canModifyStats = false;
149 for (int i = 0; i < TOTAL_AURAS; i++)
150 m_AuraModifiers[i] = 0;
151 for (int i = 0; i < IMMUNITY_MECHANIC; i++)
152 m_spellImmune[i].clear();
153 for (int i = 0; i < UNIT_MOD_END; i++)
155 m_auraModifiersGroup[i][BASE_VALUE] = 0.0f;
156 m_auraModifiersGroup[i][BASE_PCT] = 1.0f;
157 m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f;
158 m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f;
160 // implement 50% base damage from offhand
161 m_auraModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f;
163 for (int i = 0; i < 3; i++)
165 m_weaponDamage[i][MINDAMAGE] = BASE_MINDAMAGE;
166 m_weaponDamage[i][MAXDAMAGE] = BASE_MAXDAMAGE;
168 for (int i = 0; i < MAX_STATS; i++)
169 m_createStats[i] = 0.0f;
171 m_attacking = NULL;
172 m_modHitChance = 0;
173 m_modSpellHitChance = 0;
174 m_baseSpellCritChance = 5;
175 m_modResilience = 0.0;
176 m_CombatTimer = 0;
177 //m_victimThreat = 0.0f;
178 for (int i = 0; i < MAX_SPELL_SCHOOL; ++i)
179 m_threatModifier[i] = 1.0f;
180 m_isSorted = true;
181 for (int i = 0; i < MAX_MOVE_TYPE; ++i)
182 m_speed_rate[i] = 1.0f;
184 m_removedAuras = 0;
185 m_charmInfo = NULL;
188 Unit::~Unit()
190 // set current spells as deletable
191 for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
193 // spell may be safely deleted now
194 if (m_currentSpells[i]) m_currentSpells[i]->SetDeletable(true);
195 m_currentSpells[i] = NULL;
198 // remove references to unit
199 for(std::list<GameObject*>::iterator i = m_gameObj.begin(); i != m_gameObj.end();)
201 (*i)->SetOwnerGUID(0);
202 (*i)->SetRespawnTime(0);
203 (*i)->Delete();
204 i = m_gameObj.erase(i);
207 RemoveAllDynObjects();
209 if(m_charmInfo) delete m_charmInfo;
212 void Unit::RemoveAllDynObjects()
214 while(!m_dynObjGUIDs.empty())
216 DynamicObject* dynObj = ObjectAccessor::Instance().GetDynamicObject(*this,*m_dynObjGUIDs.begin());
217 if(dynObj)
218 dynObj->Delete();
219 m_dynObjGUIDs.erase(m_dynObjGUIDs.begin());
223 void Unit::Update( uint32 p_time )
225 /*if(p_time > m_AurasCheck)
227 m_AurasCheck = 2000;
228 _UpdateAura();
229 }else
230 m_AurasCheck -= p_time;*/
232 // WARNING! Order of execution here is important, do not change.
233 // Spells must be processed with event system BEFORE they go to _UpdateSpells.
234 // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad.
235 m_Events.Update( p_time );
236 _UpdateSpells( p_time );
238 //update combat timer only for players and pets
239 if (isInCombat() && (GetTypeId() == TYPEID_PLAYER || ((Creature*)this)->isPet() || ((Creature*)this)->isCharmed()))
241 if(m_HostilRefManager.isEmpty())
243 // m_CombatTimer set at aura start and it will be freeze until aura removing
244 if(!HasAuraType(SPELL_AURA_INTERRUPT_REGEN))
246 if ( m_CombatTimer <= p_time )
247 ClearInCombat();
248 else
249 m_CombatTimer -= p_time;
254 if(uint32 base_att = getAttackTimer(BASE_ATTACK))
256 setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time) );
258 if(GetHealth() < GetMaxHealth()*0.2)
259 ModifyAuraState(AURA_STATE_HEALTHLESS, true);
260 else ModifyAuraState(AURA_STATE_HEALTHLESS, false);
263 bool Unit::haveOffhandWeapon() const
265 if(GetTypeId() == TYPEID_PLAYER)
267 Item *tmpitem = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
269 return tmpitem && !tmpitem->IsBroken() && (tmpitem->GetProto()->InventoryType == INVTYPE_WEAPON || tmpitem->GetProto()->InventoryType == INVTYPE_WEAPONOFFHAND);
271 else
272 return false;
275 void Unit::SendMoveToPacket(float x, float y, float z, bool run, uint32 transitTime)
277 float dx = x - GetPositionX();
278 float dy = y - GetPositionY();
279 float dz = z - GetPositionZ();
280 if (!transitTime)
282 float dist = ((dx*dx) + (dy*dy) + (dz*dz));
283 if(dist<0)
284 dist = 0;
285 else
286 dist = sqrt(dist);
287 double speed = GetSpeed(run ? MOVE_RUN : MOVE_WALK);
288 if(speed<=0)
289 speed = 2.5f;
290 speed *= 0.001f;
291 transitTime = static_cast<uint32>(dist / speed + 0.5);
293 //float orientation = (float)atan2((double)dy, (double)dx);
294 SendMonsterMove(x,y,z,0,run,transitTime);
297 void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, bool Run, uint32 Time)
299 WorldPacket data( SMSG_MONSTER_MOVE, (41 + GetPackGUID().size()) );
300 data.append(GetPackGUID());
302 // Point A, starting location
303 data << GetPositionX() << GetPositionY() << GetPositionZ();
304 // unknown field - unrelated to orientation
305 // seems to increment about 1000 for every 1.7 seconds
306 // for now, we'll just use mstime
307 data << getMSTime();
309 data << uint8(type); // unknown
310 switch(type)
312 case 0: // normal packet
313 break;
314 case 1: // stop packet
315 SendMessageToSet( &data, true );
316 return;
317 case 3: // not used currently
318 data << uint64(0); // probably target guid
319 break;
320 case 4: // not used currently
321 data << float(0); // probably orientation
322 break;
325 data << uint32(Run ? 0x00000100 : 0x00000000); // flags (0x100 - running, 0x200 - taxi)
326 /* Flags:
327 512: Floating, moving without walking/running
329 data << Time; // Time in between points
330 data << uint32(1); // 1 single waypoint
331 data << NewPosX << NewPosY << NewPosZ; // the single waypoint Point B
333 SendMessageToSet( &data, true );
336 void Unit::resetAttackTimer(WeaponAttackType type)
338 if (GetTypeId() == TYPEID_PLAYER)
339 m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]);
340 else
341 m_attackTimer[type] = uint32(BASE_ATTACK_TIME * m_modAttackSpeedPct[type]);
344 bool Unit::canReachWithAttack(Unit *pVictim) const
346 assert(pVictim);
347 float reach = GetFloatValue(UNIT_FIELD_COMBATREACH);
348 if( reach <= 0.0f )
349 reach = 1.0f;
350 return IsWithinDistInMap(pVictim, reach);
353 void Unit::RemoveSpellsCausingAura(uint32 auraType)
355 if (auraType >= TOTAL_AURAS) return;
356 AuraList::iterator iter, next;
357 for (iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end(); iter = next)
359 next = iter;
360 ++next;
362 if (*iter)
364 RemoveAurasDueToSpell((*iter)->GetId());
365 if (!m_modAuras[auraType].empty())
366 next = m_modAuras[auraType].begin();
367 else
368 return;
373 bool Unit::HasAuraType(uint32 auraType) const
375 return (!m_modAuras[auraType].empty());
378 /* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */
379 void Unit::RemoveSpellbyDamageTaken(uint32 auraType, uint32 damage)
381 if(!HasAuraType(auraType))
382 return;
384 // The chance to dispell an aura depends on the damage taken with respect to the casters level.
385 uint32 max_dmg = getLevel() > 8 ? 25 * getLevel() - 150 : 50;
386 float chance = float(damage) / max_dmg * 100.0;
387 if (roll_chance_f(chance))
388 RemoveSpellsCausingAura(auraType);
391 void Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, uint8 damageSchool, SpellEntry const *spellProto, uint32 procFlag, bool durabilityLoss)
393 if (!pVictim->isAlive() || pVictim->isInFlight()) return;
395 //You don't lose health from damage taken from another player while in a sanctuary
396 //You still see it in the combat log though
397 if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
399 const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
400 if(area && area->flags & 0x800) //sanctuary
401 return;
404 // remove affects at any damage (including 0 damage)
405 if(HasStealthAura())
406 RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
407 if(HasInvisibilityAura())
408 RemoveSpellsCausingAura(SPELL_AURA_MOD_INVISIBILITY);
409 // remove death simulation at damage
410 if(hasUnitState(UNIT_STAT_DIED))
411 RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
413 //Script Event damage Deal
414 if( GetTypeId()== TYPEID_UNIT && ((Creature *)this)->AI())
415 ((Creature *)this)->AI()->DamageDeal(pVictim, damage);
416 //Script Event damage taken
417 if( pVictim->GetTypeId()== TYPEID_UNIT && ((Creature *)pVictim)->AI() )
418 ((Creature *)pVictim)->AI()->DamageTaken(this, damage);
420 if(!damage)
422 // Rage from damage received.
423 if(cleanDamage && cleanDamage->damage && pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->getPowerType() == POWER_RAGE))
424 ((Player*)pVictim)->RewardRage(cleanDamage->damage, 0, false);
426 return;
429 pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR, damage);
430 // root type spells do not dispell the root effect
431 if(!spellProto || spellProto->Mechanic != MECHANIC_ROOT)
432 pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT, damage);
434 if(pVictim->GetTypeId() != TYPEID_PLAYER)
436 //pVictim->SetInFront(this);
437 // no loot,xp,health if type 8 /critters/
438 if ( pVictim->GetCreatureType() == CREATURE_TYPE_CRITTER)
440 pVictim->setDeathState(JUST_DIED);
441 pVictim->SetHealth(0);
442 pVictim->CombatStop(true);
443 pVictim->DeleteThreatList();
444 return;
446 if(!pVictim->isInCombat() && ((Creature*)pVictim)->AI())
447 ((Creature*)pVictim)->AI()->AttackStart(this);
450 DEBUG_LOG("DealDamageStart");
452 uint32 health = pVictim->GetHealth();
453 sLog.outDetail("deal dmg:%d to health:%d ",damage,health);
455 // duel ends when player has 1 or less hp
456 bool duel_hasEnded = false;
457 if(pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->duel && damage >= (health-1))
459 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
460 if(((Player*)pVictim)->duel->opponent==this || ((Player*)pVictim)->duel->opponent->GetGUID() == GetOwnerGUID())
461 damage = health-1;
463 duel_hasEnded = true;
465 //Get in CombatState
466 if(pVictim != this && damagetype != DOT)
468 SetInCombat();
469 pVictim->SetInCombat();
472 // Rage from Damage made
473 if( cleanDamage && this != pVictim && GetTypeId() == TYPEID_PLAYER && (getPowerType() == POWER_RAGE))
475 uint32 weaponSpeedHitFactor;
477 switch(cleanDamage->attackType)
479 case BASE_ATTACK:
481 if(cleanDamage->hitOutCome == MELEE_HIT_CRIT)
482 weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 7);
483 else
484 weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 3.5f);
486 ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true);
488 break;
490 case OFF_ATTACK:
492 if(cleanDamage->hitOutCome == MELEE_HIT_CRIT)
493 weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 3.5f);
494 else
495 weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 1.75f);
497 ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true);
499 break;
501 case RANGED_ATTACK:
502 break;
506 if (health <= damage)
509 DEBUG_LOG("DealDamage: victim just died");
511 DEBUG_LOG("DealDamageAttackStop");
512 AttackStop();
513 pVictim->CombatStop(true);
515 DEBUG_LOG("SET JUST_DIED");
516 pVictim->setDeathState(JUST_DIED);
518 DEBUG_LOG("DealDamageHealth1");
519 pVictim->SetHealth(0);
521 // Call KilledUnit for creatures
522 if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI())
523 ((Creature*)this)->AI()->KilledUnit(pVictim);
525 // 10% durability loss on death
526 // clean InHateListOf
527 if (pVictim->GetTypeId() == TYPEID_PLAYER)
529 if (GetTypeId() != TYPEID_PLAYER && durabilityLoss)
531 DEBUG_LOG("We are dead, loosing 10 percents durability");
532 ((Player*)pVictim)->DurabilityLossAll(0.10);
533 // durability lost message
534 WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0);
535 ((Player*)pVictim)->GetSession()->SendPacket(&data);
537 pVictim->getHostilRefManager().deleteReferences();
539 Pet *pet = pVictim->GetPet();
540 if(pet && pVictim->GetTypeId() != TYPEID_PLAYER)
542 pet->setDeathState(JUST_DIED);
543 pet->CombatStop(true);
544 pet->SetHealth(0);
545 pet->addUnitState(UNIT_STAT_DIED);
546 pet->getHostilRefManager().deleteReferences();
549 else // creature died
551 DEBUG_LOG("DealDamageNotPlayer");
553 if(((Creature*)pVictim)->isPet())
554 pVictim->getHostilRefManager().deleteReferences();
555 else
557 pVictim->DeleteThreatList();
558 pVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
560 // Call creature just died function
561 if (((Creature*)pVictim)->AI())
562 ((Creature*)pVictim)->AI()->JustDied(this);
565 //judge if GainXP, Pet kill like player kill,kill pet not like PvP
566 bool PvP = false;
567 Player *player = NULL;
569 if(GetTypeId() == TYPEID_PLAYER)
571 player = (Player*)this;
572 if(pVictim->GetTypeId() == TYPEID_PLAYER)
573 PvP = true;
575 Unit* pet = NULL;
577 if(player->GetPetGUID() && (pet = player->GetPet()))
578 pet->ClearInCombat();
580 if(player->GetCharmGUID() && (pet = player->GetCharm()))
581 pet->ClearInCombat();
584 // FIXME: or charmed (can be player). Maybe must be check before GetTypeId() == TYPEID_PLAYER
585 else if(GetCharmerOrOwnerGUID()) // Pet or timed creature, etc
587 Unit* pet = this;
588 Unit* owner = pet->GetCharmerOrOwner();
590 if(owner && owner->GetTypeId() == TYPEID_PLAYER)
592 player = (Player*)owner;
593 player->ClearInCombat();
594 if(pVictim->GetTypeId() == TYPEID_PLAYER)
595 PvP = true;
598 if(pet->GetTypeId()==TYPEID_UNIT && ((Creature*)pet)->isPet())
600 uint32 petxp = MaNGOS::XP::BaseGain(getLevel(), pVictim->getLevel());
601 ((Pet*)pet)->GivePetXP(petxp);
605 // self or owner of pet
606 if(player)
608 if(player!=pVictim)
610 // prepare data for near group iteration (PvP and !PvP cases
611 uint32 xp = PvP || IsNoDamageXPArea(player->GetAreaId()) ? 0 : MaNGOS::XP::Gain(player, pVictim);
612 bool honored_kill = false;
614 Group *pGroup = player->GetGroup();
615 if(pGroup)
617 uint32 count = pGroup->GetMemberCountForXPAtKill(pVictim);
618 if(count)
620 // skip in check PvP case (for speed, not used)
621 bool is_raid = PvP ? false : MapManager::Instance().GetBaseMap(player->GetMapId())->IsRaid() && pGroup->isRaidGroup();
623 for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
625 Player *pGroupGuy = pGroup->GetMemberForXPAtKill(itr->getSource(),pVictim);
626 if(!pGroupGuy)
627 continue;
629 // honor can be in PvP and !PvP (racial leader) cases
630 if(pGroupGuy->RewardHonor(pVictim,count) && player==pGroupGuy)
631 honored_kill = true;
633 // xp and reputation only in !PvP case
634 if(!PvP)
636 // FIXME: xp/count for all in group at this moment, must be level dependent
637 float rate = 1.0f/count;
639 // if with raid in raid dungeon then all receive full reputation at kill
640 pGroupGuy->RewardReputation(pVictim,is_raid ? 1.0f : rate);
642 uint32 itr_xp = uint32(xp*rate);
644 pGroupGuy->GiveXP(itr_xp, pVictim);
645 if(Pet* pet = player->GetPet())
647 pet->GivePetXP(itr_xp/2);
650 // normal creature (not pet/etc) can be only in !PvP case
651 if(pVictim->GetTypeId()==TYPEID_UNIT)
652 pGroupGuy->KilledMonster(pVictim->GetEntry(), pVictim->GetGUID());
657 else // if (!pGroup)
659 // honor can be in PvP and !PvP (racial leader) cases
660 if(player->RewardHonor(pVictim,1))
661 honored_kill = true;
663 // xp and reputation only in !PvP case
664 if(!PvP)
666 player->RewardReputation(pVictim,1);
667 player->GiveXP(xp, pVictim);
668 if(Pet* pet = player->GetPet())
670 pet->GivePetXP(xp);
673 // normal creature (not pet/etc) can be only in !PvP case
674 if(pVictim->GetTypeId()==TYPEID_UNIT)
675 player->KilledMonster(pVictim->GetEntry(),pVictim->GetGUID());
679 if(xp || honored_kill)
680 player->ProcDamageAndSpell(pVictim,PROC_FLAG_KILL_XP_GIVER,PROC_FLAG_NONE);
683 else // if (player)
685 DEBUG_LOG("Monster kill Monster");
688 // last damage from duel opponent or opponent controlled creature?
689 if(duel_hasEnded)
691 assert(pVictim->GetTypeId()==TYPEID_PLAYER);
692 Player *he = (Player*)pVictim;
694 assert(he->duel);
696 CombatStop(); // for case killed by pet
697 if (IsNonMeleeSpellCasted(true))
698 InterruptNonMeleeSpells(true);
699 if(he->duel->opponent!=this)
701 he->duel->opponent->CombatStop();
702 if(he->duel->opponent->IsNonMeleeSpellCasted(true))
703 he->duel->opponent->InterruptNonMeleeSpells(true);
705 he->CombatStop();
706 if(he->IsNonMeleeSpellCasted(true))
707 he->InterruptNonMeleeSpells(true);
709 he->DuelComplete(0);
712 else // if (health <= damage)
714 DEBUG_LOG("DealDamageAlive");
716 pVictim->ModifyHealth(- (int32)damage);
718 // Check if health is below 20% (apply damage before to prevent case when after ProcDamageAndSpell health < damage
719 if(pVictim->GetHealth()*5 < pVictim->GetMaxHealth())
721 uint32 procVictim = PROC_FLAG_NONE;
723 // if just dropped below 20% (for CheatDeath)
724 if((pVictim->GetHealth()+damage)*5 > pVictim->GetMaxHealth())
725 procVictim = PROC_FLAG_LOW_HEALTH;
727 ProcDamageAndSpell(pVictim,PROC_FLAG_TARGET_LOW_HEALTH,procVictim);
730 if(damagetype != DOT)
732 //start melee attacks only after melee hit
733 Attack(pVictim,(damagetype == DIRECT_DAMAGE));
736 if(pVictim->getTransForm() && pVictim->hasUnitState(UNIT_STAT_CONFUSED))
738 pVictim->RemoveAurasDueToSpell(pVictim->getTransForm());
739 pVictim->setTransForm(0);
742 if (pVictim->GetTypeId() != TYPEID_PLAYER)
744 if(spellProto && IsDamageToThreatSpell(spellProto))
745 damage *= 2;
746 pVictim->AddThreat(this, damage, damageSchool, spellProto);
748 else // victim is a player
750 // Rage from damage received
751 if(this != pVictim && pVictim->GetTypeId() == TYPEID_PLAYER && pVictim->getPowerType() == POWER_RAGE)
753 uint32 rage_damage = damage + (cleanDamage ? cleanDamage->damage : 0);
754 ((Player*)pVictim)->RewardRage(rage_damage, 0, false);
757 // random durability for items (HIT)
758 if (urand(0,300) == 10)
760 DEBUG_LOG("HIT: We decrease durability with 5 percent");
761 ((Player*)pVictim)->DurabilityLossAll(0.05);
765 // TODO: Store auras by interrupt flag to speed this up.
766 AuraMap& vAuras = pVictim->GetAuras();
767 for (AuraMap::iterator i = vAuras.begin(), next; i != vAuras.end(); i = next)
769 const SpellEntry *se = i->second->GetSpellProto();
770 next = i; next++;
771 if( se->AuraInterruptFlags & AURA_INTERRUPT_FLAG_DAMAGE )
773 bool remove = true;
774 if (se->procFlags & (1<<3))
776 if (!roll_chance_i(se->procChance))
777 remove = false;
779 if (remove)
781 pVictim->RemoveAurasDueToSpell(i->second->GetId());
782 // FIXME: this may cause the auras with proc chance to be rerolled several times
783 next = vAuras.begin();
788 if (damagetype != NODAMAGE)
790 if(pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL] && pVictim->GetTypeId() == TYPEID_PLAYER && damage)
792 if (pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() == SPELL_STATE_CASTING)
794 uint32 channelInterruptFlags = pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->ChannelInterruptFlags;
795 if( channelInterruptFlags & CHANNEL_FLAG_DELAY )
797 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)));
798 pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->DelayedChannel((int32)(0.25f * GetDuration(pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo)));
800 else if( (channelInterruptFlags & (CHANNEL_FLAG_DAMAGE | CHANNEL_FLAG_DAMAGE2)) )
802 sLog.outDetail("Spell %u canceled at damage!",pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id);
803 pVictim->InterruptSpell(CURRENT_CHANNELED_SPELL);
806 else if (pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() == SPELL_STATE_DELAYED)
807 // break channeled spell in delayed state on damage
809 sLog.outDetail("Spell %u canceled at damage!",pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id);
810 pVictim->InterruptSpell(CURRENT_CHANNELED_SPELL);
815 // last damage from duel opponent
816 if(duel_hasEnded)
818 assert(pVictim->GetTypeId()==TYPEID_PLAYER);
819 Player *he = (Player*)pVictim;
821 assert(he->duel);
823 he->ModifyHealth(1);
824 CombatStop(); // for case killed by pet
825 if(he->duel->opponent!=this)
826 he->duel->opponent->CombatStop();
827 he->CombatStop();
829 he->CastSpell(he, 7267, true); // beg
830 he->DuelComplete(1);
834 DEBUG_LOG("DealDamageEnd");
837 void Unit::CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster)
839 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
841 if(!spellInfo)
843 sLog.outError("WORLD: unknown spell id %i\n", spellId);
844 return;
847 CastSpell(Victim,spellInfo,triggered,castItem,triggredByAura, originalCaster);
850 void Unit::CastSpell(Unit* Victim,SpellEntry const *spellInfo, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster)
852 if(!spellInfo)
854 sLog.outError("WORLD: unknown spell ");
855 return;
858 if (castItem)
859 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
861 Spell *spell = new Spell(this, spellInfo, triggered, triggredByAura,originalCaster);
863 SpellCastTargets targets;
864 targets.setUnitTarget( Victim );
865 spell->m_CastItem = castItem;
866 spell->prepare(&targets);
869 void Unit::CastCustomSpell(Unit* Victim,uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster)
871 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
873 if(!spellInfo)
875 sLog.outError("WORLD: unknown spell id %i\n", spellId);
876 return;
879 CastCustomSpell(Victim,spellInfo,bp0,bp1,bp2,triggered,castItem,triggredByAura, originalCaster);
882 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)
884 if(!spellInfo)
886 sLog.outError("WORLD: unknown spell ");
887 return;
890 if (castItem)
891 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
893 Spell *spell = new Spell(this, spellInfo, triggered, triggredByAura,originalCaster);
895 if(bp0)
896 spell->m_currentBasePoints[0] = *bp0;
898 if(bp1)
899 spell->m_currentBasePoints[1] = *bp1;
901 if(bp2)
902 spell->m_currentBasePoints[2] = *bp2;
904 SpellCastTargets targets;
905 targets.setUnitTarget( Victim );
906 spell->m_CastItem = castItem;
907 spell->prepare(&targets);
910 void Unit::DealDamageBySchool(Unit *pVictim, SpellEntry const *spellInfo, uint32 *damage, CleanDamage *cleanDamage, bool *crit, bool isTriggeredSpell)
913 // TODO this in only generic way, check for exceptions
914 DEBUG_LOG("DealDamageBySchool (BEFORE) SCHOOL %u >> DMG:%u", spellInfo->School, *damage);
916 // Per-school calc
917 switch (spellInfo->School)
919 // Physical damage school
920 case SPELL_SCHOOL_NORMAL:
922 // Calculate physical outcome
923 MeleeHitOutcome outcome;
924 outcome = RollPhysicalOutcomeAgainst(pVictim, BASE_ATTACK, spellInfo);
926 //Used to store the Hit Outcome
927 cleanDamage->hitOutCome = outcome;
929 // Return miss first (sends miss message)
930 if(outcome == MELEE_HIT_MISS)
932 SendAttackStateUpdate(HITINFO_MISS, pVictim, 1, spellInfo->School, 0, 0,0,1,0);
933 *damage = 0;
935 if(GetTypeId()== TYPEID_PLAYER)
936 ((Player*)this)->UpdateWeaponSkill(BASE_ATTACK);
938 CastMeleeProcDamageAndSpell(pVictim,0,BASE_ATTACK,MELEE_HIT_MISS,spellInfo,isTriggeredSpell);
939 return;
942 // Hitinfo, Victimstate
943 uint32 hitInfo, victimState;
944 hitInfo = HITINFO_NORMALSWING;
946 //Calculate armor mitigation
947 uint32 damageAfterArmor;
948 damageAfterArmor = CalcArmorReducedDamage(pVictim, *damage);
949 cleanDamage->damage += *damage - damageAfterArmor;
950 *damage = damageAfterArmor;
952 // Classify outcome
953 switch (outcome)
955 case MELEE_HIT_CRIT:
957 *damage *= 2;
958 // Resilience - reduce crit damage by 2x%
959 uint32 resilienceReduction = uint32(pVictim->m_modResilience * 2/100 * (*damage));
960 cleanDamage->damage += resilienceReduction;
961 *damage -= resilienceReduction;
962 *crit = true;
963 hitInfo |= HITINFO_CRITICALHIT;
964 break;
966 case MELEE_HIT_PARRY:
968 cleanDamage->damage += *damage; // To Help Calculate Rage
969 *damage = 0;
970 victimState = VICTIMSTATE_PARRY;
972 // Counter-attack ( explained in Unit::DoAttackDamage() )
974 // Get attack timers
975 float offtime = float(pVictim->getAttackTimer(OFF_ATTACK));
976 float basetime = float(pVictim->getAttackTimer(BASE_ATTACK));
978 // Reduce attack time
979 if (pVictim->haveOffhandWeapon() && offtime < basetime)
981 float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20;
982 float percent60 = 3 * percent20;
983 if(offtime > percent20 && offtime <= percent60)
985 pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20));
987 else if(offtime > percent60)
989 offtime -= 2 * percent20;
990 pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime));
993 else
995 float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20;
996 float percent60 = 3 * percent20;
997 if(basetime > percent20 && basetime <= percent60)
999 pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20));
1001 else if(basetime > percent60)
1003 basetime -= 2 * percent20;
1004 pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime));
1009 // Update victim defense ?
1010 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1011 ((Player*)pVictim)->UpdateDefense();
1013 // Set parry flags
1014 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
1015 pVictim->ModifyAuraState(AURA_STATE_PARRY, true);
1016 break;
1018 case MELEE_HIT_DODGE:
1020 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1021 ((Player*)pVictim)->UpdateDefense();
1023 cleanDamage->damage += *damage; // To Help Calculate Rage
1024 *damage = 0;
1025 hitInfo |= HITINFO_SWINGNOHITSOUND;
1026 victimState = VICTIMSTATE_DODGE;
1027 break;
1029 case MELEE_HIT_BLOCK:
1031 uint32 blocked_amount;
1032 blocked_amount = uint32(pVictim->GetShieldBlockValue());
1033 if (blocked_amount >= *damage)
1035 hitInfo |= HITINFO_SWINGNOHITSOUND;
1036 victimState = VICTIMSTATE_BLOCKS;
1037 cleanDamage->damage += *damage; // To Help Calculate Rage
1038 *damage = 0;
1040 else
1042 // To Help Calculate Rage
1043 cleanDamage->damage += blocked_amount;
1044 *damage = *damage - blocked_amount;
1046 break;
1049 case MELEE_HIT_MISS:
1050 case MELEE_HIT_GLANCING:
1051 case MELEE_HIT_CRUSHING:
1052 case MELEE_HIT_NORMAL:
1053 break;
1056 // Update attack state
1057 SendAttackStateUpdate(victimState ? hitInfo|victimState : hitInfo, pVictim, 1, spellInfo->School, 0, 0,0,1,0);
1059 // do all damage=0 cases here
1060 if(damage <= 0)
1061 CastMeleeProcDamageAndSpell(pVictim,0,BASE_ATTACK,outcome,spellInfo,isTriggeredSpell);
1063 break;
1065 // Other schools
1066 case SPELL_SCHOOL_HOLY:
1067 case SPELL_SCHOOL_FIRE:
1068 case SPELL_SCHOOL_NATURE:
1069 case SPELL_SCHOOL_FROST:
1070 case SPELL_SCHOOL_SHADOW:
1071 case SPELL_SCHOOL_ARCANE:
1073 //Spell miss (sends resist message)
1074 if(SpellMissChanceCalc(pVictim) > urand(0,10000))
1076 cleanDamage->damage = 0;
1077 *damage = 0;
1078 ProcDamageAndSpell(pVictim, PROC_FLAG_TARGET_RESISTS, PROC_FLAG_RESIST_SPELL, 0, spellInfo,isTriggeredSpell);
1079 SendAttackStateUpdate(HITINFO_RESIST|HITINFO_SWINGNOHITSOUND, pVictim, 1, spellInfo->School, 0, 0,0,1,0);
1080 return;
1083 // Calculate damage bonus
1084 *damage = SpellDamageBonus(pVictim, spellInfo, *damage, SPELL_DIRECT_DAMAGE);
1086 // Calculate critical bonus
1087 *crit = SpellCriticalBonus(spellInfo, (int32*)damage, pVictim);
1088 cleanDamage->hitOutCome = MELEE_HIT_CRIT;
1090 // spell proc all magic damage==0 case in this function
1091 if(damage <= 0)
1093 // Procflags
1094 uint32 procAttacker = PROC_FLAG_HIT_SPELL;
1095 uint32 procVictim = (PROC_FLAG_STRUCK_SPELL|PROC_FLAG_TAKE_DAMAGE);
1097 ProcDamageAndSpell(pVictim, procAttacker, procVictim, 0, spellInfo, isTriggeredSpell);
1100 break;
1103 // TODO this in only generic way, check for exceptions
1104 DEBUG_LOG("DealDamageBySchool (AFTER) SCHOOL %u >> DMG:%u", spellInfo->School, *damage);
1107 void Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell, bool useSpellDamage)
1109 if(!this || !pVictim)
1110 return;
1111 if(!this->isAlive() || !pVictim->isAlive())
1112 return;
1114 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID);
1115 if(!spellInfo)
1116 return;
1118 CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL);
1119 bool crit = false;
1121 if (useSpellDamage)
1122 DealDamageBySchool(pVictim, spellInfo, &damage, &cleanDamage, &crit, isTriggeredSpell);
1124 // If we actually dealt some damage (spell proc's for 0 damage (normal and magic) called in DealDamageBySchool)
1125 if(damage > 0)
1127 // Calculate absorb & resists
1128 uint32 absorb = 0;
1129 uint32 resist = 0;
1131 CalcAbsorbResist(pVictim,spellInfo->School, damage, &absorb, &resist);
1133 // Only send absorbed message if we actually absorbed some damage
1134 if(damage > 0)
1136 // Handle absorb & resists
1137 if(damage <= absorb + resist && absorb)
1139 SendAttackStateUpdate(HITINFO_ABSORB|HITINFO_SWINGNOHITSOUND, pVictim, 1, spellInfo->School,damage, absorb,resist,1,0);
1140 return;
1142 else if(damage <= resist) // If we didn't fully absorb check if we fully resisted
1144 ProcDamageAndSpell(pVictim, PROC_FLAG_TARGET_RESISTS, PROC_FLAG_RESIST_SPELL, 0, spellInfo,isTriggeredSpell);
1145 SendAttackStateUpdate(HITINFO_RESIST|HITINFO_SWINGNOHITSOUND, pVictim, 1, spellInfo->School, damage, absorb,resist,1,0);
1146 return;
1150 // Send damage log
1151 sLog.outDetail("SpellNonMeleeDamageLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u,absorb is %u,resist is %u",
1152 GetGUIDLow(), GetTypeId(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, spellID, absorb,resist);
1153 SendSpellNonMeleeDamageLog(pVictim, spellID, damage, spellInfo->School, absorb, resist, false, 0, crit);
1155 // Deal damage done
1156 DealDamage(pVictim, (damage-absorb-resist), &cleanDamage, SPELL_DIRECT_DAMAGE, spellInfo->School, spellInfo, 0, true);
1158 // Procflags
1159 uint32 procAttacker = PROC_FLAG_HIT_SPELL;
1160 uint32 procVictim = (PROC_FLAG_STRUCK_SPELL|PROC_FLAG_TAKE_DAMAGE);
1162 if (crit)
1164 procAttacker |= PROC_FLAG_CRIT_SPELL;
1165 procVictim |= PROC_FLAG_STRUCK_CRIT_SPELL;
1168 ProcDamageAndSpell(pVictim, procAttacker, procVictim, (damage-absorb-resist), spellInfo, isTriggeredSpell);
1170 else
1172 // all spell proc for 0 normal and magic damage called in DealDamageBySchool
1174 //Check for rage
1175 if(cleanDamage.damage)
1176 // Rage from damage received.
1177 if(pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->getPowerType() == POWER_RAGE))
1178 ((Player*)pVictim)->RewardRage(cleanDamage.damage, 0, false);
1182 void Unit::PeriodicAuraLog(Unit *pVictim, SpellEntry const *spellProto, Modifier *mod, uint8 effect_idx)
1184 uint32 procFlag = 0;
1185 if(!this || !pVictim || !isAlive() || !pVictim->isAlive())
1187 return;
1189 uint32 absorb=0;
1190 uint32 resist=0;
1191 CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
1192 uint32 pdamage = mod->m_amount;
1194 if(mod->m_auraname != SPELL_AURA_PERIODIC_HEAL && mod->m_auraname != SPELL_AURA_OBS_MOD_HEALTH)
1196 //Calculate armor mitigation if it is a physical spell
1197 if (spellProto->School == 0)
1199 uint32 pdamageReductedArmor = CalcArmorReducedDamage(pVictim, pdamage);
1200 cleanDamage.damage += pdamage - pdamageReductedArmor;
1201 pdamage = pdamageReductedArmor;
1204 CalcAbsorbResist(pVictim, spellProto->School, pdamage, &absorb, &resist);
1207 sLog.outDetail("PeriodicAuraLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u abs is %u",
1208 GetGUIDLow(), GetTypeId(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), pdamage, spellProto->Id,absorb);
1210 switch(mod->m_auraname)
1212 case SPELL_AURA_PERIODIC_DAMAGE:
1213 case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
1215 pdamage = SpellDamageBonus(pVictim,spellProto,pdamage,DOT);
1217 if(mod->m_auraname == SPELL_AURA_PERIODIC_DAMAGE_PERCENT)
1218 pdamage = GetHealth()*(100+mod->m_amount)/100;
1220 WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
1221 data.append(pVictim->GetPackGUID());
1222 data.append(GetPackGUID());
1223 data << uint32(spellProto->Id);
1224 data << uint32(1);
1225 data << uint32(mod->m_auraname);
1226 data << (uint32)pdamage;
1227 data << (uint32)spellProto->School;
1228 data << (uint32)absorb;
1229 data << (uint32)resist;
1230 SendMessageToSet(&data,true);
1232 DealDamage(pVictim, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), &cleanDamage, DOT, spellProto->School, spellProto, procFlag, true);
1233 ProcDamageAndSpell(pVictim, PROC_FLAG_HIT_SPELL, PROC_FLAG_TAKE_DAMAGE, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), spellProto);
1234 break;
1236 case SPELL_AURA_PERIODIC_HEAL:
1237 case SPELL_AURA_OBS_MOD_HEALTH:
1239 pdamage = SpellHealingBonus(spellProto, pdamage, DOT, pVictim);
1241 WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
1242 data.append(pVictim->GetPackGUID());
1243 data.append(GetPackGUID());
1244 data << uint32(spellProto->Id);
1245 data << uint32(1);
1246 data << uint32(mod->m_auraname);
1247 data << (uint32)pdamage;
1248 SendMessageToSet(&data,true);
1250 int32 gain = pVictim->ModifyHealth(pdamage);
1251 pVictim->getHostilRefManager().threatAssist(this, float(gain) * 0.5f, spellProto->School, spellProto);
1253 // heal for caster damage
1254 if(pVictim!=this && spellProto->SpellVisual==163)
1256 uint32 dmg = spellProto->manaPerSecond;
1257 if(GetHealth() <= dmg && GetTypeId()==TYPEID_PLAYER)
1259 RemoveAurasDueToSpell(spellProto->Id);
1261 // finish current generic/channeling spells, don't affect autorepeat
1262 if(m_currentSpells[CURRENT_GENERIC_SPELL])
1264 m_currentSpells[CURRENT_GENERIC_SPELL]->finish();
1266 if(m_currentSpells[CURRENT_CHANNELED_SPELL])
1268 m_currentSpells[CURRENT_CHANNELED_SPELL]->SendChannelUpdate(0);
1269 m_currentSpells[CURRENT_CHANNELED_SPELL]->finish();
1272 else
1274 SendSpellNonMeleeDamageLog(this, spellProto->Id, gain, spellProto->School, 0, 0, false, 0, false);
1275 DealDamage(this, gain, &cleanDamage, NODAMAGE, spellProto->School, spellProto, PROC_FLAG_HEAL, true);
1279 if(mod->m_auraname == SPELL_AURA_PERIODIC_HEAL && pVictim != this)
1280 ProcDamageAndSpell(pVictim, PROC_FLAG_HEAL, PROC_FLAG_HEALED, pdamage, spellProto);
1281 break;
1283 case SPELL_AURA_PERIODIC_LEECH:
1285 float multiplier = spellProto->EffectMultipleValue[effect_idx] > 0 ? spellProto->EffectMultipleValue[effect_idx] : 1;
1286 uint32 pdamage = mod->m_amount;
1288 pdamage = SpellDamageBonus(pVictim,spellProto,pdamage,DOT);
1290 if(pVictim->GetHealth() < pdamage)
1291 pdamage = uint32(pVictim->GetHealth());
1293 SendSpellNonMeleeDamageLog(pVictim, spellProto->Id, pdamage, spellProto->School, absorb, resist, false, 0);
1294 DealDamage(pVictim, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), &cleanDamage, DOT, spellProto->School, spellProto, procFlag, false);
1295 ProcDamageAndSpell(pVictim, PROC_FLAG_HIT_SPELL, PROC_FLAG_TAKE_DAMAGE, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), spellProto);
1296 if (!pVictim->isAlive() && IsNonMeleeSpellCasted(false))
1298 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
1300 if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id == spellProto->Id)
1301 m_currentSpells[i]->cancel();
1305 int32 gain = ModifyHealth(int32(pdamage * multiplier));
1306 getHostilRefManager().threatAssist(this, float(gain) * 0.5f, spellProto->School, spellProto);
1308 if(GetTypeId() == TYPEID_PLAYER)
1309 SendHealSpellOnPlayer(this, spellProto->Id, uint32(pdamage * multiplier));
1310 break;
1312 case SPELL_AURA_PERIODIC_MANA_LEECH:
1314 if(mod->m_miscvalue < 0 || mod->m_miscvalue > 4)
1315 break;
1317 Powers power = Powers(mod->m_miscvalue);
1319 int32 drain_amount = pVictim->GetPower(power) > pdamage ? pdamage : pVictim->GetPower(power);
1321 pVictim->ModifyPower(power, -drain_amount);
1323 float gain_multiplier = GetMaxPower(power) > 0 ? spellProto->EffectMultipleValue[effect_idx] : 0;
1325 WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
1326 data.append(pVictim->GetPackGUID());
1327 data.append(GetPackGUID());
1328 data << uint32(spellProto->Id);
1329 data << uint32(1);
1330 data << uint32(mod->m_auraname);
1331 data << (uint32)power; // power type
1332 data << (uint32)drain_amount;
1333 data << (float)gain_multiplier;
1334 SendMessageToSet(&data,true);
1336 int32 gain_amount = int32(drain_amount*gain_multiplier);
1338 if(gain_amount)
1340 int32 gain = ModifyPower(power,gain_amount);
1341 pVictim->AddThreat(this, float(gain) * 0.5f, spellProto->School, spellProto);
1343 break;
1345 case SPELL_AURA_PERIODIC_ENERGIZE:
1347 if(mod->m_miscvalue < 0 || mod->m_miscvalue > 4)
1348 break;
1350 Powers power = Powers(mod->m_miscvalue);
1352 if(pVictim->GetMaxPower(power) == 0)
1353 break;
1355 WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
1356 data.append(pVictim->GetPackGUID());
1357 data.append(GetPackGUID());
1358 data << uint32(spellProto->Id);
1359 data << uint32(1);
1360 data << uint32(mod->m_auraname);
1361 data << (uint32)power; // power type
1362 data << (uint32)mod->m_amount;
1363 SendMessageToSet(&data,true);
1365 int32 gain = pVictim->ModifyPower(power,mod->m_amount);
1366 pVictim->getHostilRefManager().threatAssist(this, float(gain) * 0.5f, spellProto->School, spellProto);
1367 break;
1369 case SPELL_AURA_OBS_MOD_MANA:
1371 if(GetMaxPower(POWER_MANA) == 0)
1372 break;
1374 WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
1375 data.append(pVictim->GetPackGUID());
1376 data.append(GetPackGUID());
1377 data << uint32(spellProto->Id);
1378 data << uint32(1);
1379 data << uint32(mod->m_auraname);
1380 data << (uint32)mod->m_amount;
1381 data << (uint32)0; // ?
1382 SendMessageToSet(&data,true);
1384 int32 gain = ModifyPower(POWER_MANA, mod->m_amount);
1385 getHostilRefManager().threatAssist(this, float(gain) * 0.5f, spellProto->School, spellProto);
1386 break;
1391 void Unit::HandleEmoteCommand(uint32 anim_id)
1393 WorldPacket data( SMSG_EMOTE, 12 );
1394 data << anim_id << GetGUID();
1395 WPAssert(data.size() == 12);
1397 SendMessageToSet(&data, true);
1400 uint32 Unit::CalcArmorReducedDamage(Unit* pVictim, const uint32 damage)
1402 uint32 newdamage = 0;
1403 float armor = pVictim->GetArmor();
1405 float tmpvalue = 0.0;
1406 if(getLevel() <= 59) //Level 1-59
1407 tmpvalue = armor / (armor + 400.0 + 85.0 * getLevel());
1408 else if(getLevel() < 70) //Level 60-69
1409 tmpvalue = armor / (armor - 22167.5 + 467.5 * getLevel());
1410 else //Level 70+
1411 tmpvalue = armor / (armor + 10557.5);
1413 if(tmpvalue < 0.0)
1414 tmpvalue = 0.0;
1415 if(tmpvalue > 0.75)
1416 tmpvalue = 0.75;
1417 newdamage = uint32(damage - (damage * tmpvalue));
1419 return (newdamage > 1) ? newdamage : 1;
1422 void Unit::CalcAbsorbResist(Unit *pVictim,uint32 School, const uint32 damage, uint32 *absorb, uint32 *resist)
1424 if(!pVictim || !pVictim->isAlive() || !damage)
1425 return;
1427 // Magic damage, check for resists
1428 if (School != SPELL_SCHOOL_NORMAL)
1430 int32 tmpvalue2 = pVictim->GetResistance(SpellSchools(School));
1431 AuraList const& mModTargetRes = GetAurasByType(SPELL_AURA_MOD_TARGET_RESISTANCE);
1432 for(AuraList::const_iterator i = mModTargetRes.begin(); i != mModTargetRes.end(); ++i)
1433 if ((*i)->GetModifier()->m_miscvalue & (1 << School))
1434 tmpvalue2 += (*i)->GetModifier()->m_amount;
1435 if (tmpvalue2 < 0) tmpvalue2 = 0;
1436 *resist += uint32(damage*tmpvalue2*0.0025*pVictim->getLevel()/getLevel());
1437 if(*resist > damage)
1438 *resist = damage;
1440 else
1441 *resist = 0;
1443 int32 RemainingDamage = damage - *resist;
1444 int32 currentAbsorb, manaReduction, maxAbsorb;
1445 float manaMultiplier;
1447 if (School == SPELL_SCHOOL_NORMAL)
1449 AuraList const& vManaShield = pVictim->GetAurasByType(SPELL_AURA_MANA_SHIELD);
1450 for(AuraList::const_iterator i = vManaShield.begin(), next; i != vManaShield.end() && RemainingDamage >= 0; i = next)
1452 next = i; next++;
1453 if (RemainingDamage - (*i)->m_absorbDmg >= 0)
1454 currentAbsorb = (*i)->m_absorbDmg;
1455 else
1456 currentAbsorb = RemainingDamage;
1458 manaMultiplier = (*i)->GetSpellProto()->EffectMultipleValue[(*i)->GetEffIndex()];
1459 maxAbsorb = int32(pVictim->GetPower(POWER_MANA) / manaMultiplier);
1460 if (currentAbsorb > maxAbsorb)
1461 currentAbsorb = maxAbsorb;
1463 (*i)->m_absorbDmg -= currentAbsorb;
1464 if((*i)->m_absorbDmg <= 0)
1466 pVictim->RemoveAurasDueToSpell((*i)->GetId());
1467 next = vManaShield.begin();
1470 manaReduction = int32(currentAbsorb * manaMultiplier);
1471 pVictim->ApplyPowerMod(POWER_MANA, manaReduction, false);
1473 RemainingDamage -= currentAbsorb;
1477 AuraList const& vSchoolAbsorb = pVictim->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB);
1478 for(AuraList::const_iterator i = vSchoolAbsorb.begin(), next; i != vSchoolAbsorb.end() && RemainingDamage >= 0; i = next)
1480 next = i; next++;
1481 if ((*i)->GetModifier()->m_miscvalue & int32(1<<School))
1483 if (RemainingDamage - (*i)->m_absorbDmg >= 0)
1485 currentAbsorb = (*i)->m_absorbDmg;
1486 pVictim->RemoveAurasDueToSpell((*i)->GetId());
1487 next = vSchoolAbsorb.begin();
1489 else
1491 currentAbsorb = RemainingDamage;
1492 (*i)->m_absorbDmg -= RemainingDamage;
1495 RemainingDamage -= currentAbsorb;
1499 *absorb = damage - RemainingDamage - *resist;
1502 void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDamage, uint32 *blocked_amount, uint32 *damageType, uint32 *hitInfo, uint32 *victimState, uint32 *absorbDamage, uint32 *resistDamage, WeaponAttackType attType, SpellEntry const *spellCasted, bool isTriggeredSpell)
1504 pVictim->ModifyAuraState(AURA_STATE_PARRY, false);
1505 pVictim->ModifyAuraState(AURA_STATE_DEFENSE, false);
1506 ModifyAuraState(AURA_STATE_CRIT, false);
1508 MeleeHitOutcome outcome;
1510 // If is casted Melee spell, calculate like physical
1511 if(!spellCasted)
1512 outcome = RollMeleeOutcomeAgainst (pVictim, attType);
1513 else
1514 outcome = RollPhysicalOutcomeAgainst (pVictim, attType, spellCasted);
1516 if (outcome == MELEE_HIT_MISS)
1518 *hitInfo |= HITINFO_MISS;
1519 *damage = 0;
1520 cleanDamage->damage = 0;
1521 if(GetTypeId()== TYPEID_PLAYER)
1522 ((Player*)this)->UpdateWeaponSkill(attType);
1523 return;
1526 /// If this is a creature and it attacks from behind it has a probability to daze it's victim
1527 if( (outcome==MELEE_HIT_CRIT || outcome==MELEE_HIT_CRUSHING || outcome==MELEE_HIT_NORMAL || outcome==MELEE_HIT_GLANCING) &&
1528 GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->GetCharmerOrOwnerGUID() && !pVictim->HasInArc(M_PI, this) )
1530 // -probability is between 0% and 40%
1531 // 20% base chance
1532 float Probability = 20;
1534 //there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1535 if( pVictim->getLevel() < 30 )
1536 Probability = 0.65f*pVictim->getLevel()+0.5;
1538 uint32 VictimDefense=pVictim->GetDefenseSkillValue();
1539 uint32 AttackerMeleeSkill=GetUnitMeleeSkill();
1541 Probability *= AttackerMeleeSkill/(float)VictimDefense;
1543 if(Probability > 40)
1544 Probability = 40;
1546 if(roll_chance_f(Probability))
1547 CastSpell(pVictim, 1604, true);
1550 *damage += CalculateDamage (attType);
1552 //Calculate the damage after armor mitigation if SPELL_SCHOOL_NORMAL
1553 if (*damageType == SPELL_SCHOOL_NORMAL)
1555 uint32 damageAfterArmor = CalcArmorReducedDamage(pVictim, *damage);
1556 cleanDamage->damage += *damage - damageAfterArmor;
1557 *damage = damageAfterArmor;
1559 // Instant Attacks (Spellmods)
1560 // TODO: AP bonus related to mainhand weapon
1561 if(spellCasted)
1562 if(GetTypeId()== TYPEID_PLAYER)
1563 ((Player*)this)->ApplySpellMod(spellCasted->Id, SPELLMOD_DAMAGE, *damage);
1565 if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER )
1566 ((Player*)this)->UpdateCombatSkills(pVictim, attType, outcome, false);
1568 if(GetTypeId() != TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
1569 ((Player*)pVictim)->UpdateCombatSkills(this, attType, outcome, true);
1571 switch (outcome)
1573 case MELEE_HIT_CRIT:
1574 //*hitInfo = 0xEA;
1575 // 0xEA
1576 *hitInfo = HITINFO_CRITICALHIT | HITINFO_NORMALSWING2 | 0x8;
1578 // Crit bonus calc
1579 uint32 crit_bonus;
1580 crit_bonus = *damage;
1582 // Apply crit_damage bonus for melee spells
1583 if (GetTypeId() == TYPEID_PLAYER && spellCasted)
1585 ((Player*)this)->ApplySpellMod(spellCasted->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
1588 *damage += crit_bonus;
1590 // Resilience - reduce crit damage by 2x%
1591 uint32 resilienceReduction;
1592 resilienceReduction = uint32(pVictim->m_modResilience * 2/100 * (*damage));
1593 *damage -= resilienceReduction;
1594 cleanDamage->damage += resilienceReduction;
1596 if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER )
1597 ((Player*)this)->UpdateWeaponSkill(attType);
1599 ModifyAuraState(AURA_STATE_CRIT, true);
1601 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL);
1602 break;
1604 case MELEE_HIT_PARRY:
1605 if(attType == RANGED_ATTACK) //range attack - no parry
1606 break;
1608 cleanDamage->damage += *damage;
1609 *damage = 0;
1610 *victimState = VICTIMSTATE_PARRY;
1612 // instant (maybe with small delay) counter attack
1614 float offtime = float(pVictim->getAttackTimer(OFF_ATTACK));
1615 float basetime = float(pVictim->getAttackTimer(BASE_ATTACK));
1617 // after parry nearest next attack time will reduced at %40 from full attack time.
1618 // The delay cannot be reduced to less than 20% of your weapon’s base swing delay.
1619 if (pVictim->haveOffhandWeapon() && offtime < basetime)
1621 float percent20 = pVictim->GetAttackTime(OFF_ATTACK)*0.20;
1622 float percent60 = 3*percent20;
1623 // set to 20% if in range 20%...20+40% of full time
1624 if(offtime > percent20 && offtime <= percent60)
1626 pVictim->setAttackTimer(OFF_ATTACK,uint32(percent20));
1628 // decrease at %40 from full time
1629 else if(offtime > percent60)
1631 offtime -= 2*percent20;
1632 pVictim->setAttackTimer(OFF_ATTACK,uint32(offtime));
1634 // ELSE not changed
1636 else
1638 float percent20 = pVictim->GetAttackTime(BASE_ATTACK)*0.20;
1639 float percent60 = 3*percent20;
1640 // set to 20% if in range 20%...20+40% of full time
1641 if(basetime > percent20 && basetime <= percent60)
1643 pVictim->setAttackTimer(BASE_ATTACK,uint32(percent20));
1645 // decrease at %40 from full time
1646 else if(basetime > percent60)
1648 basetime -= 2*percent20;
1649 pVictim->setAttackTimer(BASE_ATTACK,uint32(basetime));
1651 // ELSE not changed
1655 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1656 ((Player*)pVictim)->UpdateDefense();
1658 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
1659 pVictim->ModifyAuraState(AURA_STATE_PARRY,true);
1660 if (pVictim->getClass() != CLASS_HUNTER) // Mongoose Bite
1661 pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true);
1663 CastMeleeProcDamageAndSpell(pVictim, 0, attType, outcome, spellCasted, isTriggeredSpell);
1664 return;
1666 case MELEE_HIT_DODGE:
1667 if(attType == RANGED_ATTACK) //range attack - no dodge
1668 break;
1669 cleanDamage->damage += *damage;
1670 *damage = 0;
1671 *victimState = VICTIMSTATE_DODGE;
1673 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1674 ((Player*)pVictim)->UpdateDefense();
1676 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
1678 if (pVictim->getClass() != CLASS_ROGUE) // Riposte
1679 pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true);
1681 CastMeleeProcDamageAndSpell(pVictim, 0, attType, outcome, spellCasted, isTriggeredSpell);
1682 return;
1684 case MELEE_HIT_BLOCK:
1685 *blocked_amount = uint32(pVictim->GetShieldBlockValue() + (pVictim->GetStat(STAT_STRENGTH) / 20.0f) -1);
1687 if (pVictim->GetUnitBlockChance())
1688 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD);
1689 else
1690 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
1692 //Only set VICTIMSTATE_BLOCK on a full block
1693 if (*blocked_amount >= *damage)
1695 *victimState = VICTIMSTATE_BLOCKS;
1696 *blocked_amount = *damage;
1699 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1700 ((Player*)pVictim)->UpdateDefense();
1701 pVictim->ModifyAuraState(AURA_STATE_DEFENSE,true);
1702 break;
1704 case MELEE_HIT_GLANCING:
1706 float reducePercent = 1.0f; //damage factor
1708 // calculate base values and mods
1709 float baseLowEnd = 1.3;
1710 float baseHighEnd = 1.2;
1711 switch(getClass()) // lowering base values for casters
1713 case CLASS_SHAMAN:
1714 case CLASS_PRIEST:
1715 case CLASS_MAGE:
1716 case CLASS_WARLOCK:
1717 case CLASS_DRUID:
1718 baseLowEnd -= 0.7;
1719 baseHighEnd -= 0.3;
1720 break;
1723 float maxLowEnd = 0.6;
1724 switch(getClass()) // upper for melee classes
1726 case CLASS_WARRIOR:
1727 case CLASS_ROGUE:
1728 maxLowEnd = 0.91; //If the attacker is a melee class then instead the lower value of 0.91
1731 // calculate values
1732 int32 diff = pVictim->GetDefenseSkillValue() - GetWeaponSkillValue(attType);
1733 float lowEnd = baseLowEnd - ( 0.05f * diff );
1734 float highEnd = baseHighEnd - ( 0.03f * diff );
1736 // apply max/min bounds
1737 if ( lowEnd < 0.01f ) //the low end must not go bellow 0.01f
1738 lowEnd = 0.01f;
1739 else if ( lowEnd > maxLowEnd ) //the smaller value of this and 0.6 is kept as the low end
1740 lowEnd = maxLowEnd;
1742 if ( highEnd < 0.2f ) //high end limits
1743 highEnd = 0.2f;
1744 if ( highEnd > 0.99f )
1745 highEnd = 0.99f;
1747 if(lowEnd > highEnd) // prevent negative range size
1748 lowEnd = highEnd;
1750 reducePercent = lowEnd + rand_norm() * ( highEnd - lowEnd );
1752 *damage = uint32(reducePercent * *damage);
1753 cleanDamage->damage += *damage;
1754 *hitInfo |= HITINFO_GLANCING;
1755 break;
1757 case MELEE_HIT_CRUSHING:
1759 // 150% normal damage
1760 *damage += (*damage / 2);
1761 cleanDamage->damage = *damage;
1762 *hitInfo |= HITINFO_CRUSHING;
1763 // TODO: victimState, victim animation?
1764 break;
1766 default:
1767 break;
1770 // apply melee damage bonus and absorb only if base damage not fully blocked to prevent negative damage or damage with full block
1771 if(*victimState != VICTIMSTATE_BLOCKS)
1773 MeleeDamageBonus(pVictim, damage,attType);
1774 CalcAbsorbResist(pVictim, *damageType, *damage-*blocked_amount, absorbDamage, resistDamage);
1777 if (*absorbDamage) *hitInfo |= HITINFO_ABSORB;
1778 if (*resistDamage) *hitInfo |= HITINFO_RESIST;
1779 cleanDamage += *blocked_amount;
1781 if (*damage <= *absorbDamage + *resistDamage + *blocked_amount)
1783 //*hitInfo = 0x00010020;
1784 //*hitInfo |= HITINFO_SWINGNOHITSOUND;
1785 //*damageType = 0;
1786 CastMeleeProcDamageAndSpell(pVictim, 0, attType, outcome, spellCasted, isTriggeredSpell);
1787 return;
1790 CastMeleeProcDamageAndSpell(pVictim, (*damage - *absorbDamage - *resistDamage - *blocked_amount), attType, outcome, spellCasted, isTriggeredSpell);
1792 // victim's damage shield
1793 // yet another hack to fix crashes related to the aura getting removed during iteration
1794 std::set<Aura*> alreadyDone;
1795 uint32 removedAuras = pVictim->m_removedAuras;
1796 AuraList const& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD);
1797 for(AuraList::const_iterator i = vDamageShields.begin(), next = vDamageShields.begin(); i != vDamageShields.end(); i = next)
1799 next++;
1800 if (alreadyDone.find(*i) == alreadyDone.end())
1802 alreadyDone.insert(*i);
1803 pVictim->SpellNonMeleeDamageLog(this, (*i)->GetId(), (*i)->GetModifier()->m_amount, false, false);
1804 if (pVictim->m_removedAuras > removedAuras)
1806 removedAuras = pVictim->m_removedAuras;
1807 next = vDamageShields.begin();
1812 if (pVictim->GetTypeId() == TYPEID_PLAYER && *damage)
1814 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
1816 // skip channeled spell (processed differently below)
1817 if (i == CURRENT_CHANNELED_SPELL)
1818 continue;
1820 if(pVictim->m_currentSpells[i])
1822 sLog.outDetail("Spell Delayed!%d",(int32)(0.25f * pVictim->m_currentSpells[i]->casttime));
1823 pVictim->m_currentSpells[i]->Delayed((int32)(0.25f * pVictim->m_currentSpells[i]->casttime));
1827 // process channeled spell separately
1828 if (pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL])
1830 if (pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() == SPELL_STATE_CASTING)
1832 uint32 channelInterruptFlags = pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->ChannelInterruptFlags;
1833 if( channelInterruptFlags & CHANNEL_FLAG_DELAY )
1835 sLog.outDetail("Spell Delayed!%d",(int32)(0.25f * GetDuration(pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo)));
1836 pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->DelayedChannel((int32)(0.25f * GetDuration(pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo)));
1837 return;
1839 else if( !(channelInterruptFlags & (CHANNEL_FLAG_DAMAGE | CHANNEL_FLAG_DAMAGE2)) )
1840 return;
1842 sLog.outDetail("Spell Canceled!");
1843 pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel();
1845 else if (pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() == SPELL_STATE_DELAYED)
1847 // break channeled spell in delayed state on damage
1848 sLog.outDetail("Spell Canceled!");
1849 pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel();
1855 void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool isTriggered)
1857 if(hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNDED | UNIT_STAT_FLEEING) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED) )
1858 return;
1860 if (!pVictim->isAlive())
1861 return;
1863 if(!isTriggered)
1865 if(IsNonMeleeSpellCasted(false))
1866 return;
1868 // melee attack spell casted at main hand attack only
1869 if (m_currentSpells[CURRENT_MELEE_SPELL] && attType == BASE_ATTACK)
1871 m_currentSpells[CURRENT_MELEE_SPELL]->cast();
1872 return;
1876 uint32 hitInfo;
1877 if (attType == BASE_ATTACK)
1878 hitInfo = HITINFO_NORMALSWING2;
1879 else if (attType == OFF_ATTACK)
1880 hitInfo = HITINFO_LEFTSWING;
1881 else
1882 return;
1884 uint32 damageType = NORMAL_DAMAGE;
1885 uint32 victimState = VICTIMSTATE_NORMAL;
1887 uint32 damage = 0;
1888 CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
1889 uint32 blocked_dmg = 0;
1890 uint32 absorbed_dmg = 0;
1891 uint32 resisted_dmg = 0;
1893 if( pVictim->IsImmunedToPhysicalDamage() )
1895 SendAttackStateUpdate (HITINFO_MISS, pVictim, 1, NORMAL_DAMAGE, 0, 0, 0, VICTIMSTATE_IS_IMMUNE, 0);
1896 return;
1899 DoAttackDamage (pVictim, &damage, &cleanDamage, &blocked_dmg, &damageType, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, attType);
1901 cleanDamage.damage += blocked_dmg;
1903 if (hitInfo & HITINFO_MISS)
1904 //send miss
1905 SendAttackStateUpdate (hitInfo, pVictim, 1, damageType, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg);
1906 else
1908 //do animation
1909 SendAttackStateUpdate (hitInfo, pVictim, 1, damageType, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg);
1911 if (damage > (absorbed_dmg + resisted_dmg + blocked_dmg))
1912 damage -= (absorbed_dmg + resisted_dmg + blocked_dmg);
1913 else
1914 damage = 0;
1916 DealDamage (pVictim, damage, &cleanDamage, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, 0, true);
1918 if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive())
1920 for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
1921 ((Player*)this)->CastItemCombatSpell(((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i),pVictim);
1925 if (GetTypeId() == TYPEID_PLAYER)
1926 DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
1927 GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, absorbed_dmg, blocked_dmg, resisted_dmg);
1928 else
1929 DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
1930 GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, absorbed_dmg, blocked_dmg, resisted_dmg);
1933 MeleeHitOutcome Unit::RollPhysicalOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo)
1935 // Miss chance based on melee
1936 int32 miss_chance = (int32)(MeleeMissChanceCalc(pVictim));
1938 // Critical hit chance
1939 float crit_chance = GetUnitCriticalChance(attType);
1941 // Only players can have Talent&Spell bonuses
1942 if (GetTypeId() == TYPEID_PLAYER)
1944 // Talents
1945 AuraList const& mSpellCritSchool = GetAurasByType(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL);
1946 for(AuraList::const_iterator i = mSpellCritSchool.begin(); i != mSpellCritSchool.end(); ++i)
1947 if((*i)->GetModifier()->m_miscvalue == -2 || ((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellInfo->School)) != 0)
1948 crit_chance += (*i)->GetModifier()->m_amount;
1950 // flat
1951 AuraList const& mAttackerSWCrit = pVictim->GetAurasByType(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
1952 for(AuraList::const_iterator i = mAttackerSWCrit.begin(); i != mAttackerSWCrit.end(); ++i)
1953 crit_chance += (*i)->GetModifier()->m_amount;
1955 // Spellmods
1956 ((Player*)this)->ApplySpellMod(spellInfo->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance);
1959 DEBUG_LOG("PHYSICAL OUTCOME: hit %u crit %f miss %u",m_modHitChance,crit_chance,miss_chance);
1961 return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance * 100 ), miss_chance, m_modHitChance);
1964 MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType) const
1966 // This is only wrapper
1968 // Miss chance based on melee
1969 int32 miss_chance = (int32)(MeleeMissChanceCalc(pVictim));
1971 // Critical hit chance
1972 float crit_chance = GetUnitCriticalChance(attType);
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 // Useful if want to specify crit & miss chances for melee, else it could be removed
1980 DEBUG_LOG("MELEE OUTCOME: hit %u crit %u miss %u", m_modHitChance,crit_chance,miss_chance);
1981 return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance * 100 ), miss_chance, m_modHitChance);
1984 MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 hit_chance) const
1986 int32 skillDiff = GetWeaponSkillValue(attType) - pVictim->GetDefenseSkillValue();
1987 // bonus from skills is 0.04%
1988 int32 skillBonus = skillDiff * 4;
1989 int32 skillBonus2 = 4 * ( GetWeaponSkillValue(attType) - pVictim->GetPureDefenseSkillValue() );
1990 int32 sum = 0, tmp = 0;
1991 int32 roll = urand (0, 10000);
1993 DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus);
1994 DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, +hit %d, dodge %u, parry %u, block %u, crit %u",
1995 roll, hit_chance, (uint32)(pVictim->GetUnitDodgeChance()*100), (uint32)(pVictim->GetUnitParryChance()*100),
1996 (uint32)(pVictim->GetUnitBlockChance()*100), crit_chance);
1998 // dual wield has 24% base chance to miss instead of 5%, also
1999 // base miss rate is 5% and can't get higher than 60%
2001 // Inherit if passed
2002 tmp = miss_chance - skillBonus;
2004 if(tmp > 6000)
2005 tmp = 6000;
2007 if (tmp > 0 && roll < (sum += tmp ))
2009 DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS");
2010 return MELEE_HIT_MISS;
2013 // always crit against a sitting target (except 0 crit chance)
2014 if( (pVictim->GetTypeId() == TYPEID_PLAYER) && crit_chance > 0 &&
2015 (((Player*)pVictim)->getStandState() & (PLAYER_STATE_SLEEP | PLAYER_STATE_SIT
2016 | PLAYER_STATE_SIT_CHAIR
2017 | PLAYER_STATE_SIT_LOW_CHAIR
2018 | PLAYER_STATE_SIT_MEDIUM_CHAIR
2019 | PLAYER_STATE_SIT_HIGH_CHAIR)))
2021 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)");
2022 return MELEE_HIT_CRIT;
2025 // stunned target cannot dodge and this is check in GetUnitDodgeChance()
2026 tmp = (int32)(pVictim->GetUnitDodgeChance()*100) - skillBonus2;
2027 if (tmp > 0 && roll < (sum += tmp))
2029 DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum-tmp, sum);
2030 return MELEE_HIT_DODGE;
2033 int32 modCrit = 0;
2035 // check if attack comes from behind
2036 if (!pVictim->HasInArc(M_PI,this))
2038 // ASSUME +10% crit from behind
2039 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind.");
2040 modCrit += 1000;
2042 else
2044 // cannot parry or block attacks from behind, but can from forward
2045 tmp = (int32)(pVictim->GetUnitParryChance()*100);
2046 if ( (tmp > 0) // check if unit _can_ parry
2047 && ((tmp -= skillBonus2) > 0)
2048 && (roll < (sum += tmp)))
2050 DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum-tmp, sum);
2051 return MELEE_HIT_PARRY;
2054 tmp = (int32)(pVictim->GetUnitBlockChance()*100);
2055 if ( (tmp > 0) // check if unit _can_ block
2056 && ((tmp -= skillBonus2) > 0)
2057 && (roll < (sum += tmp)))
2059 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum-tmp, sum);
2060 return MELEE_HIT_BLOCK;
2064 // Resilience - reduce crit chance by x%
2065 modCrit -= int32(pVictim->m_modResilience*100);
2067 // Critical chance
2068 tmp = crit_chance + skillBonus + modCrit;
2070 if (tmp > 0 && roll < (sum += tmp))
2072 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum-tmp, sum);
2073 return MELEE_HIT_CRIT;
2076 // Max 40% chance to score a glancing blow against mobs that are higher level
2077 if( GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && getLevel() < pVictim->getLevel() )
2079 // cap possible value (with bonuses > max skill)
2080 int32 skill = GetWeaponSkillValue(attType);
2081 int32 maxskill = GetMaxSkillValueForLevel();
2082 skill = (skill > maxskill) ? maxskill : skill;
2084 tmp = (10 + (pVictim->GetDefenseSkillValue() - skill)) * 100;
2085 tmp = tmp > 4000 ? 4000 : tmp;
2086 if (roll < (sum += tmp))
2088 DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum-4000, sum);
2089 return MELEE_HIT_GLANCING;
2093 // mobs can score crushing blows if they're 3 or more levels above victim
2094 // or when their weapon skill is 15 or more above victim's defense skill
2095 tmp = pVictim->GetDefenseSkillValue();
2096 int32 tmpmax = pVictim->GetMaxSkillValueForLevel();
2097 // having defense above your maximum (from items, talents etc.) has no effect
2098 tmp = tmp > tmpmax ? tmpmax : tmp;
2099 // tmp = mob's level * 5 - player's current defense skill
2100 tmp = GetMaxSkillValueForLevel() - tmp;
2101 if (GetTypeId() != TYPEID_PLAYER && (tmp >= 15))
2103 // add 2% chance per lacking skill point, min. is 15%
2104 tmp = tmp * 200 - 1500;
2105 if (roll < (sum += tmp))
2107 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum-tmp, sum);
2108 return MELEE_HIT_CRUSHING;
2112 DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL");
2113 return MELEE_HIT_NORMAL;
2116 uint32 Unit::CalculateDamage (WeaponAttackType attType)
2118 float min_damage, max_damage;
2120 switch (attType)
2122 case RANGED_ATTACK:
2123 min_damage = GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE);
2124 max_damage = GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE);
2125 break;
2126 case BASE_ATTACK:
2127 min_damage = GetFloatValue(UNIT_FIELD_MINDAMAGE);
2128 max_damage = GetFloatValue(UNIT_FIELD_MAXDAMAGE);
2129 break;
2130 case OFF_ATTACK:
2131 min_damage = GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE);
2132 max_damage = GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE);
2133 break;
2136 if (min_damage > max_damage)
2138 std::swap(min_damage,max_damage);
2141 if(max_damage == 0.0)
2142 max_damage = 5.0;
2144 return rand32((uint32)min_damage, (uint32)max_damage);
2147 void Unit::SendAttackStart(Unit* pVictim)
2149 if(GetTypeId()!=TYPEID_PLAYER || !pVictim)
2150 return;
2152 WorldPacket data( SMSG_ATTACKSTART, 16 );
2153 data << GetGUID();
2154 data << pVictim->GetGUID();
2156 ((Player*)this)->SendMessageToSet(&data, true);
2157 DEBUG_LOG( "WORLD: Sent SMSG_ATTACKSTART" );
2160 void Unit::SendAttackStop(Unit* victim)
2162 if(!victim)
2163 return;
2165 WorldPacket data( SMSG_ATTACKSTOP, (4+16) ); // we guess size
2166 data.append(GetPackGUID());
2167 data.append(victim->GetPackGUID()); // can be 0x00...
2168 data << uint32(0); // can be 0x1
2169 SendMessageToSet(&data, true);
2170 sLog.outDetail("%s %u stopped attacking %s %u", (GetTypeId()==TYPEID_PLAYER ? "player" : "creature"), GetGUIDLow(), (victim->GetTypeId()==TYPEID_PLAYER ? "player" : "creature"),victim->GetGUIDLow());
2172 /*if(victim->GetTypeId() == TYPEID_UNIT)
2173 ((Creature*)victim)->AI().EnterEvadeMode(this);*/
2176 uint32 Unit::SpellMissChanceCalc(Unit *pVictim) const
2178 if(!pVictim)
2179 return 0;
2181 // PvP : PvE spell misschances per leveldif > 2
2182 int32 chance = pVictim->GetTypeId() == TYPEID_PLAYER ? 700 : 1100;
2184 int32 leveldif = pVictim->getLevel() - getLevel();
2185 if(leveldif < 0)
2186 leveldif = 0;
2188 int32 misschance = 400 - m_modSpellHitChance*100;
2189 if(leveldif < 3)
2190 misschance += leveldif * 100;
2191 else
2192 misschance += (leveldif - 2) * chance;
2194 return misschance < 100 ? 100 : misschance;
2197 int32 Unit::MeleeMissChanceCalc(const Unit *pVictim) const
2199 if(!pVictim)
2200 return 0;
2202 // Base misschance 5%
2203 int32 misschance = 500;
2205 // DualWield - Melee spells and physical dmg spells - 5% , white damage 24%
2206 if (haveOffhandWeapon())
2208 bool isNormal = false;
2209 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
2211 if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->School == SPELL_SCHOOL_NORMAL)
2213 isNormal = true;
2214 break;
2217 if (isNormal || m_currentSpells[CURRENT_MELEE_SPELL])
2219 misschance = 500;
2221 else
2223 misschance = 2400;
2227 // PvP : PvE melee misschances per leveldif > 2
2228 int32 chance = pVictim->GetTypeId() == TYPEID_PLAYER ? 500 : 700;
2230 int32 leveldif = pVictim->getLevel() - getLevel();
2231 if(leveldif < 0)
2232 leveldif = 0;
2234 if(leveldif < 3)
2235 misschance += leveldif * 100 - m_modHitChance*100;
2236 else
2237 misschance += (leveldif - 2) * chance - m_modHitChance*100;
2239 return misschance > 6000 ? 6000 : misschance;
2242 uint16 Unit::GetDefenseSkillValue() const
2244 if(GetTypeId() == TYPEID_PLAYER)
2245 return ((Player*)this)->GetSkillValue (SKILL_DEFENSE);
2246 else
2247 return GetUnitMeleeSkill();
2250 uint16 Unit::GetPureDefenseSkillValue() const
2252 if(GetTypeId() == TYPEID_PLAYER)
2253 return ((Player*)this)->GetPureSkillValue(SKILL_DEFENSE);
2254 else
2255 return GetUnitMeleeSkill();
2258 float Unit::GetUnitDodgeChance() const
2260 if(hasUnitState(UNIT_STAT_STUNDED))
2261 return 0;
2262 return GetTypeId() == TYPEID_PLAYER ? GetFloatValue(PLAYER_DODGE_PERCENTAGE) : 5;
2265 float Unit::GetUnitParryChance() const
2267 float chance = 0;
2268 if(GetTypeId() == TYPEID_PLAYER)
2270 Player const* player = (Player const*)this;
2271 if(player->CanParry() && player->IsUseEquipedWeapon() )
2273 Item *tmpitem = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
2274 if(!tmpitem || tmpitem->IsBroken())
2275 tmpitem = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
2277 if(tmpitem && !tmpitem->IsBroken() && (
2278 tmpitem->GetProto()->InventoryType == INVTYPE_WEAPON ||
2279 tmpitem->GetProto()->InventoryType == INVTYPE_WEAPONOFFHAND ||
2280 tmpitem->GetProto()->InventoryType == INVTYPE_WEAPONMAINHAND ||
2281 tmpitem->GetProto()->InventoryType == INVTYPE_2HWEAPON))
2282 chance = GetFloatValue(PLAYER_PARRY_PERCENTAGE);
2285 else if(GetTypeId() == TYPEID_UNIT)
2287 if(GetCreatureType() == CREATURE_TYPE_HUMANOID)
2288 chance = 5;
2291 return chance;
2294 float Unit::GetUnitBlockChance() const
2296 float chance = 0;
2297 if(GetTypeId() == TYPEID_PLAYER)
2299 Item *tmpitem = ((Player const*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
2300 if(tmpitem && !tmpitem->IsBroken() && tmpitem->GetProto()->Block)
2301 chance = GetFloatValue(PLAYER_BLOCK_PERCENTAGE);
2303 else
2304 chance = 5;
2306 return chance;
2309 uint16 Unit::GetWeaponSkillValue (WeaponAttackType attType) const
2311 if(GetTypeId() == TYPEID_PLAYER)
2313 uint16 slot;
2314 switch (attType)
2316 case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
2317 case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
2318 case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
2319 default:
2320 return 0;
2322 Item *item = ((Player*)this)->GetItemByPos (INVENTORY_SLOT_BAG_0, slot);
2324 if(slot != EQUIPMENT_SLOT_MAINHAND && (!item || item->IsBroken() ||
2325 item->GetProto()->Class != ITEM_CLASS_WEAPON || !((Player*)this)->IsUseEquipedWeapon() ))
2326 return 0;
2328 // in range
2329 uint32 skill = item && !item->IsBroken() && ((Player*)this)->IsUseEquipedWeapon()
2330 ? item->GetSkill() : SKILL_UNARMED;
2331 return ((Player*)this)->GetSkillValue (skill);
2333 else
2334 return GetUnitMeleeSkill();
2337 uint16 Unit::GetPureWeaponSkillValue (WeaponAttackType attType) const
2339 if(GetTypeId() == TYPEID_PLAYER)
2341 uint16 slot;
2342 switch (attType)
2344 case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
2345 case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
2346 case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
2347 default:
2348 return 0;
2350 Item *item = ((Player*)this)->GetItemByPos (INVENTORY_SLOT_BAG_0, slot);
2352 if(slot != EQUIPMENT_SLOT_MAINHAND && (!item || item->IsBroken() ||
2353 item->GetProto()->Class != ITEM_CLASS_WEAPON || !((Player*)this)->IsUseEquipedWeapon() ))
2354 return 0;
2356 // in range
2357 uint32 skill = item && !item->IsBroken() && ((Player*)this)->IsUseEquipedWeapon()
2358 ? item->GetSkill() : SKILL_UNARMED;
2359 return ((Player*)this)->GetPureSkillValue (skill);
2361 else
2362 return GetUnitMeleeSkill();
2365 void Unit::_UpdateSpells( uint32 time )
2367 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
2368 _UpdateAutoRepeatSpell( time );
2370 // remove finished spells from current pointers
2371 for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
2373 if (m_currentSpells[i] && m_currentSpells[i]->getState() == SPELL_STATE_FINISHED)
2375 m_currentSpells[i]->SetDeletable(true); // spell may be safely deleted now
2376 m_currentSpells[i] = NULL; // remove pointer
2380 // TODO: Find a better way to prevent crash when multiple auras are removed.
2381 m_removedAuras = 0;
2382 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
2383 if ((*i).second)
2384 (*i).second->SetUpdated(false);
2386 for (AuraMap::iterator i = m_Auras.begin(), next; i != m_Auras.end(); i = next)
2388 next = i;
2389 next++;
2390 if ((*i).second)
2392 // prevent double update
2393 if ((*i).second->IsUpdated())
2394 continue;
2395 (*i).second->SetUpdated(true);
2396 (*i).second->Update( time );
2397 // several auras can be deleted due to update
2398 if (m_removedAuras)
2400 if (m_Auras.empty()) break;
2401 next = m_Auras.begin();
2402 m_removedAuras = 0;
2407 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end();)
2409 if ((*i).second)
2411 if ( !(*i).second->GetAuraDuration() && !((*i).second->IsPermanent() || ((*i).second->IsPassive())) )
2413 RemoveAura(i);
2415 else
2417 ++i;
2420 else
2422 ++i;
2426 if(!m_gameObj.empty())
2428 std::list<GameObject*>::iterator ite1, dnext1;
2429 for (ite1 = m_gameObj.begin(); ite1 != m_gameObj.end(); ite1 = dnext1)
2431 dnext1 = ite1;
2432 //(*i)->Update( difftime );
2433 if( !(*ite1)->isSpawned() )
2435 (*ite1)->SetOwnerGUID(0);
2436 (*ite1)->SetRespawnTime(0);
2437 (*ite1)->Delete();
2438 dnext1 = m_gameObj.erase(ite1);
2440 else
2441 ++dnext1;
2446 void Unit::_UpdateAutoRepeatSpell( uint32 time )
2448 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_FINISHED)
2450 //Auto Shot & Shoot
2451 if( m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->AttributesEx2 == 0x000020 && GetTypeId() == TYPEID_PLAYER )
2453 // Auto Shot don't require ranged weapon cooldown at first cast, wand shoot does, so the 'FINISHED' state
2454 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
2456 // Shoot
2457 resetAttackTimer( RANGED_ATTACK );
2459 else
2461 // Auto Shoot
2462 if (m_AutoRepeatFirstCast)
2464 // first cast only with recovery time (not less)
2465 if (getAttackTimer( RANGED_ATTACK ) < m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->RecoveryTime)
2466 setAttackTimer( RANGED_ATTACK, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->RecoveryTime);
2467 m_AutoRepeatFirstCast = false;
2469 else
2471 // second or further casts
2472 resetAttackTimer( RANGED_ATTACK );
2476 else
2478 setAttackTimer( RANGED_ATTACK, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->RecoveryTime);
2481 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_IDLE);
2483 else if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_IDLE && isAttackReady(RANGED_ATTACK) )
2485 // check if we can cast
2486 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast() == 0)
2488 // check movement in player case
2489 if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isMoving())
2491 // cancel wand shooting
2492 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
2493 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
2494 // ELSE delay auto-repeat ranged weapon until player movement stop
2496 else
2497 // recheck range and req. items (ammo and gun, etc)
2498 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckRange() == 0 && m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckItems() == 0 )
2500 // check, if we are casting melee spell (it blocks autorepeat)
2501 if ( ! (m_currentSpells[CURRENT_MELEE_SPELL] &&
2502 (m_currentSpells[CURRENT_MELEE_SPELL]->getState() != SPELL_STATE_FINISHED) &&
2503 (m_currentSpells[CURRENT_MELEE_SPELL]->getState() != SPELL_STATE_DELAYED)) )
2505 // check, if we are casting something else, if no then run autorepeat spell
2506 if (!IsNonMeleeSpellCasted(false, false, true))
2508 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_PREPARING);
2509 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->ReSetTimer();
2513 else
2515 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
2518 else
2520 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
2523 else if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_PREPARING)
2525 // check, if some other incomplete spell exists (including melee) or ranged attack is not ready
2526 if ( m_currentSpells[CURRENT_MELEE_SPELL] ||
2527 m_currentSpells[CURRENT_GENERIC_SPELL] ||
2528 m_currentSpells[CURRENT_CHANNELED_SPELL] ||
2529 !isAttackReady(RANGED_ATTACK) )
2531 // some other spell is here or ranged attack is not ready, break us to idle state
2532 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->finish(false);
2533 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_IDLE);
2538 void Unit::SetCurrentCastedSpell( Spell * pSpell )
2540 assert(pSpell); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
2542 uint32 CSpellType = pSpell->GetCurrentContainer();
2544 pSpell->SetDeletable(false); // spell will not be deleted until gone from current pointers
2545 if (pSpell == m_currentSpells[CSpellType]) return; // avoid breaking self
2547 // break same type spell if it is not delayed
2548 if ( m_currentSpells[CSpellType] &&
2549 m_currentSpells[CSpellType]->getState() != SPELL_STATE_DELAYED )
2551 InterruptSpell(CSpellType);
2554 // special breakage effects:
2555 switch (CSpellType)
2557 case CURRENT_GENERIC_SPELL:
2559 // generic spells always break channeled not delayed spells
2560 if ( m_currentSpells[CURRENT_CHANNELED_SPELL] &&
2561 m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_DELAYED )
2563 InterruptSpell(CURRENT_CHANNELED_SPELL);
2566 // autorepeat breaking
2567 if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL] )
2569 // break autorepeat if not Auto Shot
2570 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
2571 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
2573 } break;
2575 case CURRENT_CHANNELED_SPELL:
2577 // channel spells always break generic and channeled spells
2578 InterruptSpell(CURRENT_GENERIC_SPELL);
2579 InterruptSpell(CURRENT_CHANNELED_SPELL);
2581 // it also does break autorepeat if not Auto Shot
2582 if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL] &&
2583 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351 )
2584 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
2585 } break;
2587 case CURRENT_AUTOREPEAT_SPELL:
2589 // only Auto Shoot does not break anything
2590 if (pSpell->m_spellInfo->Category == 351)
2592 // generic autorepeats break generic and channeled spells
2593 InterruptSpell(CURRENT_GENERIC_SPELL);
2594 InterruptSpell(CURRENT_CHANNELED_SPELL);
2596 else
2598 // special action: set first cast flag for Auto Shoot
2599 m_AutoRepeatFirstCast = true;
2601 } break;
2603 default:
2605 // other spell types don't break anything now
2606 } break;
2609 // current spell (if it is still here) may be safely deleted now
2610 if (m_currentSpells[CSpellType])
2611 m_currentSpells[CSpellType]->SetDeletable(true);
2613 // set new current spell
2614 m_currentSpells[CSpellType] = pSpell;
2617 void Unit::InterruptSpell(uint32 spellType)
2619 assert(spellType < CURRENT_MAX_SPELL);
2621 if(m_currentSpells[spellType])
2623 // send autorepeat cancel message for autorepeat spells
2624 if (spellType == CURRENT_AUTOREPEAT_SPELL)
2626 if(GetTypeId()==TYPEID_PLAYER)
2627 ((Player*)this)->SendAutoRepeatCancel();
2630 if (m_currentSpells[spellType]->getState() != SPELL_STATE_FINISHED)
2631 m_currentSpells[spellType]->cancel();
2632 m_currentSpells[spellType]->SetDeletable(true);
2633 m_currentSpells[spellType] = NULL;
2637 bool Unit::IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled, bool skipAutorepeat)
2639 // We don't do loop here to explicitly show that melee spell is excluded.
2640 // Maybe later some special spells will be excluded too.
2642 // generic spells are casted when they are not finished and not delayed
2643 if ( m_currentSpells[CURRENT_GENERIC_SPELL] &&
2644 (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) &&
2645 (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) )
2646 return(true);
2648 // channeled spells may be delayed, but they are still considered casted
2649 else if ( !skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
2650 (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED) )
2651 return(true);
2653 // autorepeat spells may be finished or delayed, but they are still considered casted
2654 else if ( !skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL] )
2655 return(true);
2657 return(false);
2660 void Unit::InterruptNonMeleeSpells(bool withDelayed)
2662 // generic spells are interrupted if they are not finished or delayed
2663 if (m_currentSpells[CURRENT_GENERIC_SPELL])
2665 if ( (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) &&
2666 (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) )
2667 m_currentSpells[CURRENT_GENERIC_SPELL]->cancel();
2668 m_currentSpells[CURRENT_GENERIC_SPELL]->SetDeletable(true);
2669 m_currentSpells[CURRENT_GENERIC_SPELL] = NULL;
2672 // autorepeat spells are interrupted if they are not finished or delayed
2673 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
2675 // send disable autorepeat packet in any case
2676 if(GetTypeId()==TYPEID_PLAYER)
2677 ((Player*)this)->SendAutoRepeatCancel();
2679 if ( (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_FINISHED) &&
2680 (withDelayed || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_DELAYED) )
2681 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->cancel();
2682 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SetDeletable(true);
2683 m_currentSpells[CURRENT_AUTOREPEAT_SPELL] = NULL;
2686 // channeled spells are interrupted if they are not finished, even if they are delayed
2687 if (m_currentSpells[CURRENT_CHANNELED_SPELL])
2689 if (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED)
2690 m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel();
2691 m_currentSpells[CURRENT_CHANNELED_SPELL]->SetDeletable(true);
2692 m_currentSpells[CURRENT_CHANNELED_SPELL] = NULL;
2696 bool Unit::isInFront(Unit const* target, float radius) const
2698 return IsWithinDistInMap(target, radius) && HasInArc( M_PI, target );
2701 void Unit::SetInFront(Unit const* target)
2703 SetOrientation(GetAngle(target));
2706 bool Unit::isInAccessablePlaceFor(Creature* c) const
2708 if(IsInWater())
2709 return c->isCanSwimOrFly();
2710 else
2711 return c->isCanWalkOrFly();
2714 bool Unit::IsInWater() const
2716 return MapManager::Instance().GetMap(GetMapId(), this)->IsInWater(GetPositionX(),GetPositionY(), GetPositionZ());
2719 bool Unit::IsUnderWater() const
2721 return MapManager::Instance().GetMap(GetMapId(), this)->IsUnderWater(GetPositionX(),GetPositionY(),GetPositionZ());
2724 void Unit::DeMorph()
2726 SetUInt32Value(UNIT_FIELD_DISPLAYID, GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID));
2729 long Unit::GetTotalAuraModifier(uint32 ModifierID) const
2731 uint32 modifier = 0;
2733 AuraList const& mTotalAuraList = GetAurasByType(ModifierID);
2734 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
2735 modifier += (*i)->GetModifier()->m_amount;
2737 return modifier;
2740 bool Unit::AddAura(Aura *Aur, bool uniq)
2742 // ghost spell check
2743 if (!isAlive() && !(Aur->GetSpellProto()->Id == 20584 || Aur->GetSpellProto()->Id == 8326))
2745 delete Aur;
2746 return false;
2749 if(Aur->GetTarget() != this)
2751 sLog.outError("Aura (spell %u eff %u) add to aura list of %s (lowguid: %u) but Aura target is %s (lowguid: %u)",
2752 Aur->GetId(),Aur->GetEffIndex(),(GetTypeId()==TYPEID_PLAYER?"player":"creature"),GetGUIDLow(),
2753 (Aur->GetTarget()->GetTypeId()==TYPEID_PLAYER?"player":"creature"),Aur->GetTarget()->GetGUIDLow());
2754 delete Aur;
2755 return false;
2758 AuraMap::iterator i = m_Auras.find( spellEffectPair(Aur->GetId(), Aur->GetEffIndex()) );
2760 // take out same spell
2761 if (i != m_Auras.end())
2763 /*(*i).second->SetAuraDuration(Aur->GetAuraDuration());
2764 if ((*i).second->GetTarget())
2765 if ((*i).second->GetTarget()->GetTypeId() == TYPEID_PLAYER )
2766 (*i).second->UpdateAuraDuration();
2767 delete Aur;
2768 return false;*/
2769 // passive and persistent auras can stack with themselves any number of times
2770 if (!Aur->IsPassive() && !Aur->IsPersistent() && m_Auras.count(spellEffectPair(Aur->GetId(), Aur->GetEffIndex())) >= Aur->GetSpellProto()->StackAmount)
2771 RemoveAura(i);
2774 // passive auras stack with all (except passive spell proc auras)
2775 if ((!Aur->IsPassive() || !IsPassiveStackableSpell(Aur->GetId())) &&
2776 !(Aur->GetSpellProto()->Id == 20584 || Aur->GetSpellProto()->Id == 8326))
2778 if (!RemoveNoStackAurasDueToAura(Aur))
2780 delete Aur;
2781 return false; // couldnt remove conflicting aura with higher rank
2785 // adding linked auras
2786 // add the shapeshift aura's boosts
2787 if(Aur->GetModifier()->m_auraname == SPELL_AURA_MOD_SHAPESHIFT)
2788 Aur->HandleShapeshiftBoosts(true);
2790 Aur->_AddAura();
2791 m_Auras.insert(AuraMap::value_type(spellEffectPair(Aur->GetId(), Aur->GetEffIndex()), Aur));
2792 if (Aur->GetModifier()->m_auraname < TOTAL_AURAS)
2794 m_modAuras[Aur->GetModifier()->m_auraname].push_back(Aur);
2795 m_AuraModifiers[Aur->GetModifier()->m_auraname] += (Aur->GetModifier()->m_amount);
2798 if (IsSingleTarget(Aur->GetId()) && Aur->GetTarget() && Aur->GetSpellProto())
2800 if(Unit* caster = Aur->GetCaster())
2802 AuraList& scAuras = caster->GetSingleCastAuras();
2803 AuraList::iterator itr, next;
2804 for (itr = scAuras.begin(); itr != scAuras.end(); itr = next)
2806 next = itr;
2807 next++;
2808 if ((*itr)->GetTarget() != Aur->GetTarget() &&
2809 (*itr)->GetSpellProto()->Category == Aur->GetSpellProto()->Category &&
2810 (*itr)->GetSpellProto()->SpellIconID == Aur->GetSpellProto()->SpellIconID &&
2811 (*itr)->GetSpellProto()->SpellVisual == Aur->GetSpellProto()->SpellVisual &&
2812 (*itr)->GetSpellProto()->Attributes == Aur->GetSpellProto()->Attributes &&
2813 (*itr)->GetSpellProto()->AttributesEx == Aur->GetSpellProto()->AttributesEx &&
2814 (*itr)->GetSpellProto()->AttributesExEx == Aur->GetSpellProto()->AttributesExEx)
2816 (*itr)->GetTarget()->RemoveAura((*itr)->GetId(), (*itr)->GetEffIndex());
2817 if(scAuras.empty())
2818 break;
2819 else
2820 next = scAuras.begin();
2823 scAuras.push_back(Aur);
2826 return true;
2829 void Unit::RemoveRankAurasDueToSpell(uint32 spellId)
2831 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
2832 if(!spellInfo)
2833 return;
2834 AuraMap::iterator i,next;
2835 for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
2837 next = i;
2838 next++;
2839 uint32 i_spellId = (*i).second->GetId();
2840 if((*i).second && i_spellId && i_spellId != spellId)
2842 if(objmgr.IsRankSpellDueToSpell(spellInfo,i_spellId))
2844 RemoveAurasDueToSpell(i_spellId);
2846 if( m_Auras.empty() )
2847 break;
2848 else
2849 next = m_Auras.begin();
2855 bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur)
2857 if (!Aur)
2858 return false;
2860 SpellEntry const* spellProto = Aur->GetSpellProto();
2861 if (!spellProto)
2862 return false;
2864 uint32 spellId = Aur->GetId();
2865 uint32 effIndex = Aur->GetEffIndex();
2866 bool is_sec = IsSpellSingleEffectPerCaster(spellId);
2867 AuraMap::iterator i,next;
2868 for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
2870 next = i;
2871 next++;
2872 if (!(*i).second) continue;
2874 if (!(*i).second->GetSpellProto())
2875 continue;
2877 uint32 i_spellId = (*i).second->GetId();
2879 if(IsPassiveSpell(i_spellId))
2881 if(IsPassiveStackableSpell(i_spellId))
2882 continue;
2884 // passive non-stackable spells not stackable only with another rank of same spell
2885 if (!objmgr.IsRankSpellDueToSpell(Aur->GetSpellProto(), i_spellId))
2886 continue;
2889 uint32 i_effIndex = (*i).second->GetEffIndex();
2891 if(i_spellId == spellId) continue;
2893 bool is_triggered_by_spell = false;
2894 // prevent triggered aura of removing aura that triggered it
2895 for(int j = 0; j < 3; ++j)
2896 if ((*i).second->GetSpellProto()->EffectTriggerSpell[j] == spellProto->Id)
2897 is_triggered_by_spell = true;
2898 if (is_triggered_by_spell) continue;
2900 // prevent remove dummy triggered spells at next effect aura add
2901 for(int j = 0; j < 3; ++j)
2903 switch(spellProto->Effect[j])
2905 case SPELL_EFFECT_DUMMY:
2906 switch(spellId)
2908 case 5420: if(i_spellId==34123) is_triggered_by_spell = true; break;
2910 break;
2912 if(is_triggered_by_spell)
2913 break;
2915 switch(spellProto->EffectApplyAuraName[j])
2917 case SPELL_AURA_MOD_SHAPESHIFT:
2918 switch(spellId)
2920 case 33891: if(i_spellId==5420 || i_spellId==34123) is_triggered_by_spell = true; break;
2922 break;
2926 if(!is_triggered_by_spell)
2928 bool sec_match = false;
2929 bool is_i_sec = IsSpellSingleEffectPerCaster(i_spellId);
2930 if( is_sec && is_i_sec )
2931 if (Aur->GetCasterGUID() == (*i).second->GetCasterGUID())
2932 if (GetSpellSpecific(spellId) == GetSpellSpecific(i_spellId))
2933 sec_match = true;
2934 if( sec_match || objmgr.IsNoStackSpellDueToSpell(spellId, i_spellId) && !is_sec && !is_i_sec )
2936 // if sec_match this isn't always true, needs to be rechecked
2937 if (objmgr.IsRankSpellDueToSpell(Aur->GetSpellProto(), i_spellId))
2938 if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
2939 return false; // cannot remove higher rank
2941 RemoveAurasDueToSpell(i_spellId);
2943 if( m_Auras.empty() )
2944 break;
2945 else
2946 next = m_Auras.begin();
2948 else // Potions stack aura by aura
2949 if (Aur->GetSpellProto()->SpellFamilyName == SPELLFAMILY_POTION &&
2950 (*i).second->GetSpellProto()->SpellFamilyName == SPELLFAMILY_POTION)
2952 if (IsNoStackAuraDueToAura(spellId, effIndex, i_spellId, i_effIndex))
2954 if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
2955 return false; // cannot remove higher rank
2957 RemoveAura(i);
2958 next = i;
2963 return true;
2966 void Unit::RemoveFirstAuraByDispel(uint32 dispel_type, Unit *pCaster)
2968 AuraMap::iterator i;
2969 for (i = m_Auras.begin(); i != m_Auras.end();)
2971 if ((*i).second && (*i).second->GetSpellProto()->Dispel == dispel_type)
2973 if(dispel_type == 1)
2975 bool positive = true;
2976 switch((*i).second->GetSpellProto()->EffectImplicitTargetA[(*i).second->GetEffIndex()])
2978 case TARGET_CHAIN_DAMAGE:
2979 case TARGET_ALL_ENEMY_IN_AREA:
2980 case TARGET_ALL_ENEMY_IN_AREA_INSTANT:
2981 case TARGET_ALL_ENEMIES_AROUND_CASTER:
2982 case TARGET_IN_FRONT_OF_CASTER:
2983 case TARGET_DUELVSPLAYER:
2984 case TARGET_ALL_ENEMY_IN_AREA_CHANNELED:
2985 case TARGET_CURRENT_SELECTED_ENEMY:
2986 positive = false;
2987 break;
2989 default:
2990 positive = ((*i).second->GetSpellProto()->AttributesEx & (1<<7)) ? false : true;
2992 if(positive && IsFriendlyTo(pCaster)) // PBW
2994 ++i;
2995 continue;
2998 RemoveAura(i);
2999 break;
3001 else
3002 ++i;
3006 void Unit::RemoveAreaAurasByOthers(uint64 guid)
3008 int j = 0;
3009 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end();)
3011 if (i->second && i->second->IsAreaAura())
3013 uint64 casterGuid = i->second->GetCasterGUID();
3014 uint64 targetGuid = i->second->GetTarget()->GetGUID();
3015 // if area aura cast by someone else or by the specified caster
3016 if (casterGuid == guid || (guid == 0 && casterGuid != targetGuid))
3018 for (j = 0; j < 4; j++)
3019 if (m_TotemSlot[j] == casterGuid)
3020 break;
3021 // and not by one of my totems
3022 if (j == 4)
3023 RemoveAura(i);
3024 else
3025 ++i;
3027 else
3028 ++i;
3030 else
3031 ++i;
3035 void Unit::RemoveAura(uint32 spellId, uint32 effindex)
3037 AuraMap::iterator iter;
3038 while((iter = m_Auras.find(spellEffectPair(spellId, effindex))) != m_Auras.end())
3039 RemoveAura(iter);
3042 void Unit::RemoveAurasDueToSpell(uint32 spellId)
3044 for (int i = 0; i < 3; ++i)
3045 RemoveAura(spellId,i);
3048 void Unit::RemoveAurasDueToItem(Item* castItem)
3050 for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
3052 if (iter->second->GetCastItemGUID() == castItem->GetGUID())
3053 RemoveAura(iter);
3054 else
3055 ++iter;
3059 void Unit::RemoveAura(AuraMap::iterator &i, bool onDeath)
3061 if (IsSingleTarget((*i).second->GetId()))
3063 if(Unit* caster = (*i).second->GetCaster())
3065 AuraList& scAuras = caster->GetSingleCastAuras();
3066 scAuras.remove((*i).second);
3068 else
3069 sLog.outError("Unit::RemoveAura: cannot remove the single cast aura from the caster, potential crash!");
3071 // remove aura from party members when the caster turns off the aura
3072 if((*i).second->IsAreaAura())
3074 Unit *i_target = (*i).second->GetTarget();
3075 if((*i).second->GetCasterGUID() == i_target->GetGUID())
3077 Unit* i_caster = i_target;
3079 Unit* owner = NULL;
3080 Group *pGroup = NULL;
3081 Player *pGroupOf = NULL;
3082 if (i_caster->GetTypeId() == TYPEID_PLAYER)
3084 pGroupOf = (Player*)i_caster;
3085 pGroup = pGroupOf->GetGroup();
3087 else if(((Creature*)i_caster)->isTotem() || ((Creature*)i_caster)->isPet() || i_caster->isCharmed())
3089 owner = i_caster->GetCharmerOrOwner();
3090 if (owner && owner->GetTypeId() == TYPEID_PLAYER)
3092 pGroupOf = (Player*)owner;
3093 pGroup = pGroupOf->GetGroup();
3097 //float radius = GetRadius(sSpellRadiusStore.LookupEntry((*i).second->GetSpellProto()->EffectRadiusIndex[(*i).second->GetEffIndex()]));
3098 if(pGroup && pGroupOf)
3100 for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
3102 Player* Target = itr->getSource();
3103 if(!Target || !pGroup->SameSubGroup(pGroupOf, Target))
3104 continue;
3106 if(Target->GetGUID() == i_caster->GetGUID())
3107 continue;
3108 Aura *t_aura = Target->GetAura((*i).second->GetId(), (*i).second->GetEffIndex());
3109 if (t_aura)
3110 if (t_aura->GetCasterGUID() == i_caster->GetGUID())
3111 Target->RemoveAura((*i).second->GetId(), (*i).second->GetEffIndex());
3114 else if(owner)
3116 Aura *t_aura = owner->GetAura((*i).second->GetId(), (*i).second->GetEffIndex());
3117 if (t_aura)
3118 if (t_aura->GetCasterGUID() == i_caster->GetGUID())
3119 owner->RemoveAura((*i).second->GetId(), (*i).second->GetEffIndex());
3123 if ((*i).second->GetModifier()->m_auraname < TOTAL_AURAS)
3125 m_AuraModifiers[(*i).second->GetModifier()->m_auraname] -= ((*i).second->GetModifier()->m_amount);
3126 m_modAuras[(*i).second->GetModifier()->m_auraname].remove((*i).second);
3128 (*i).second->SetRemoveOnDeath(onDeath);
3130 // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
3131 Aura* Aur = i->second;
3133 DiminishingMechanics mech = DIMINISHING_NONE;
3134 if(Aur->GetSpellProto()->Mechanic)
3136 mech = Unit::Mechanic2DiminishingMechanics(Aur->GetSpellProto()->Mechanic);
3137 if(mech == DIMINISHING_MECHANIC_STUN || GetTypeId() == TYPEID_PLAYER && mech != DIMINISHING_NONE)
3138 UpdateDiminishingTime(mech);
3141 // must remove before removing from list (its remove dependent auras and _i_ is only safe iterator value
3142 // remove the shapeshift aura's boosts
3143 if(Aur->GetModifier()->m_auraname == SPELL_AURA_MOD_SHAPESHIFT)
3144 Aur->HandleShapeshiftBoosts(false);
3146 m_Auras.erase(i);
3147 m_removedAuras++; // internal count used by unit update
3149 Aur->_RemoveAura();
3150 delete Aur;
3152 // only way correctly remove all auras from list
3153 if( m_Auras.empty() )
3154 i = m_Auras.end();
3155 else
3156 i = m_Auras.begin();
3159 bool Unit::SetAurDuration(uint32 spellId, uint32 effindex,uint32 duration)
3161 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
3162 if (iter != m_Auras.end())
3164 (*iter).second->SetAuraDuration(duration);
3165 (*iter).second->UpdateAuraDuration();
3166 return true;
3168 return false;
3171 uint32 Unit::GetAurDuration(uint32 spellId, uint32 effindex)
3173 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
3174 if (iter != m_Auras.end())
3176 return (*iter).second->GetAuraDuration();
3178 return 0;
3181 void Unit::RemoveAllAuras()
3183 while (!m_Auras.empty())
3185 AuraMap::iterator iter = m_Auras.begin();
3186 RemoveAura(iter);
3190 void Unit::RemoveAllAurasOnDeath()
3192 // used just after dieing to remove all visible auras
3193 // and disable the mods for the passive ones
3194 for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
3196 if (!iter->second->IsPassive())
3197 RemoveAura(iter, true);
3198 else
3199 ++iter;
3203 void Unit::DelayAura(uint32 spellId, uint32 effindex, int32 delaytime)
3205 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
3206 if (iter != m_Auras.end())
3208 if (iter->second->GetAuraDuration() < delaytime)
3209 iter->second->SetAuraDuration(0);
3210 else
3211 iter->second->SetAuraDuration(iter->second->GetAuraDuration() - delaytime);
3212 iter->second->UpdateAuraDuration();
3213 sLog.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter->second->GetModifier()->m_auraname, GetGUIDLow(), iter->second->GetAuraDuration());
3217 void Unit::_RemoveAllAuraMods()
3219 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
3221 (*i).second->ApplyModifier(false);
3225 void Unit::_ApplyAllAuraMods()
3227 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
3229 (*i).second->ApplyModifier(true);
3233 // TODO: FIX-ME!!!
3234 /*void Unit::_UpdateAura()
3236 if(GetTypeId() != TYPEID_PLAYER || !m_Auras)
3237 return;
3239 Player* pThis = (Player*)this;
3241 Player* pGroupGuy;
3242 Group* pGroup;
3244 pGroup = objmgr.GetGroupByLeader(pThis->GetGroupLeader());
3246 if(!SetAffDuration(m_Auras->GetId(),this,6000))
3247 AddAura(m_Auras);
3249 if(!pGroup)
3250 return;
3251 else
3253 for(uint32 i=0;i<pGroup->GetMembersCount();i++)
3255 pGroupGuy = ObjectAccessor::Instance().FindPlayer(pGroup->GetMemberGUID(i));
3257 if(!pGroupGuy)
3258 continue;
3259 if(pGroupGuy->GetGUID() == GetGUID())
3260 continue;
3261 if(sqrt(
3262 (GetPositionX()-pGroupGuy->GetPositionX())*(GetPositionX()-pGroupGuy->GetPositionX())
3263 +(GetPositionY()-pGroupGuy->GetPositionY())*(GetPositionY()-pGroupGuy->GetPositionY())
3264 +(GetPositionZ()-pGroupGuy->GetPositionZ())*(GetPositionZ()-pGroupGuy->GetPositionZ())
3265 ) <=30)
3267 if(!pGroupGuy->SetAffDuration(m_Auras->GetId(),this,6000))
3268 pGroupGuy->AddAura(m_Auras);
3270 else
3272 if(m_removeAuraTimer == 0)
3274 printf("remove aura from %u\n", pGroupGuy->GetGUID());
3275 pGroupGuy->RemoveAura(m_Auras->GetId());
3280 if(m_removeAuraTimer > 0)
3281 m_removeAuraTimer -= 1;
3282 else
3283 m_removeAuraTimer = 4;
3286 Aura* Unit::GetAura(uint32 spellId, uint32 effindex)
3288 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
3289 if (iter != m_Auras.end())
3290 return iter->second;
3291 return NULL;
3294 void Unit::AddDynObject(DynamicObject* dynObj)
3296 m_dynObjGUIDs.push_back(dynObj->GetGUID());
3299 void Unit::RemoveDynObject(uint32 spellid)
3301 if(m_dynObjGUIDs.empty())
3302 return;
3303 for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
3305 DynamicObject* dynObj = ObjectAccessor::Instance().GetDynamicObject(*this,*m_dynObjGUIDs.begin());
3306 if(!dynObj)
3308 i = m_dynObjGUIDs.erase(i);
3310 else if(spellid == 0 || dynObj->GetSpellId() == spellid)
3312 dynObj->Delete();
3313 i = m_dynObjGUIDs.erase(i);
3315 else
3316 ++i;
3320 DynamicObject * Unit::GetDynObject(uint32 spellId, uint32 effIndex)
3322 for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
3324 DynamicObject* dynObj = ObjectAccessor::Instance().GetDynamicObject(*this,*m_dynObjGUIDs.begin());
3325 if(!dynObj)
3327 i = m_dynObjGUIDs.erase(i);
3328 continue;
3331 if (dynObj->GetSpellId() == spellId && dynObj->GetEffIndex() == effIndex)
3332 return dynObj;
3333 ++i;
3335 return NULL;
3338 void Unit::AddGameObject(GameObject* gameObj)
3340 assert(gameObj && gameObj->GetOwnerGUID()==0);
3341 m_gameObj.push_back(gameObj);
3342 gameObj->SetOwnerGUID(GetGUID());
3345 void Unit::RemoveGameObject(GameObject* gameObj, bool del)
3347 assert(gameObj && gameObj->GetOwnerGUID()==GetGUID());
3348 gameObj->SetOwnerGUID(0);
3349 m_gameObj.remove(gameObj);
3350 if(del)
3352 gameObj->SetRespawnTime(0);
3353 gameObj->Delete();
3357 void Unit::RemoveGameObject(uint32 spellid, bool del)
3359 if(m_gameObj.empty())
3360 return;
3361 std::list<GameObject*>::iterator i, next;
3362 for (i = m_gameObj.begin(); i != m_gameObj.end(); i = next)
3364 next = i;
3365 if(spellid == 0 || (*i)->GetSpellId() == spellid)
3367 (*i)->SetOwnerGUID(0);
3368 if(del)
3370 (*i)->SetRespawnTime(0);
3371 (*i)->Delete();
3374 next = m_gameObj.erase(i);
3376 else
3377 ++next;
3381 void Unit::SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, uint8 DamageType,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit)
3383 WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16+31)); // we guess size
3384 data.append(target->GetPackGUID());
3385 data.append(GetPackGUID());
3386 data << uint32(SpellID);
3387 data << uint32(Damage-AbsorbedDamage-Resist-Blocked);
3388 data << uint8(DamageType); //damagetype
3389 data << uint32(AbsorbedDamage); //AbsorbedDamage
3390 data << uint32(Resist); //resist
3391 data << (uint8)PhysicalDamage;
3392 data << uint8(0);
3393 data << uint32(Blocked); //blocked
3394 data << uint8(CriticalHit ? 2 : 0); //seen 0x05 also...
3395 data << uint32(0);
3396 SendMessageToSet( &data, true );
3399 void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, uint32 DamageType, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, uint32 TargetState, uint32 BlockedAmount)
3401 sLog.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
3403 WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16+45)); // we guess size
3404 data << (uint32)HitInfo;
3405 data.append(GetPackGUID());
3406 data.append(target->GetPackGUID());
3407 data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount);
3409 data << (uint8)SwingType;
3410 data << (uint32)DamageType;
3413 data << (float)(Damage-AbsorbDamage-Resist-BlockedAmount);
3414 // still need to double check damaga
3415 data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount);
3416 data << (uint32)AbsorbDamage;
3417 data << (uint32)Resist;
3418 data << (uint32)TargetState;
3420 if( AbsorbDamage == 0 ) //also 0x3E8 = 0x3E8, check when that happens
3421 data << (uint32)0;
3422 else
3423 data << (uint32)-1;
3425 data << (uint32)0;
3426 data << (uint32)BlockedAmount;
3428 SendMessageToSet( &data, true );
3431 struct ProcTriggeredData
3433 ProcTriggeredData(SpellEntry const * _spellInfo, uint32 _spellParam, Aura* _triggeredByAura)
3434 : spellInfo(_spellInfo), spellParam(_spellParam), triggeredByAura(_triggeredByAura) {}
3436 SpellEntry const * spellInfo;
3437 uint32 spellParam;
3438 Aura* triggeredByAura;
3441 typedef std::list< ProcTriggeredData > ProcTriggeredList;
3443 // used to prevent spam in log about same non-handled spells
3444 static std::set<uint32> nonHandledSpellProcSet;
3446 void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 damage, SpellEntry const *procSpell, bool isTriggeredSpell, WeaponAttackType attType)
3448 sLog.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker, procVictim);
3449 if(procSpell)
3450 sLog.outDebug("ProcDamageAndSpell: invoked due to spell id %u %s", procSpell->Id, (isTriggeredSpell?"(triggered)":""));
3452 // Assign melee/ranged proc flags for magic attacks, that are actually melee/ranged abilities
3453 // not assign for spell proc triggered spell to prevent infinity (or unexpacted 2-3 times) melee damage spell proc call with melee damage effect
3454 // That is the question though if it's fully correct
3455 if(procSpell && !isTriggeredSpell)
3457 if(procSpell->DmgClass == SPELL_DAMAGE_CLASS_MELEE)
3459 if(procAttacker & PROC_FLAG_HIT_SPELL) procAttacker |= PROC_FLAG_HIT_MELEE;
3460 if(procAttacker & PROC_FLAG_CRIT_SPELL) procAttacker |= PROC_FLAG_CRIT_MELEE;
3461 if(procVictim & PROC_FLAG_STRUCK_SPELL) procVictim |= PROC_FLAG_STRUCK_MELEE;
3462 if(procVictim & PROC_FLAG_STRUCK_CRIT_SPELL) procVictim |= PROC_FLAG_STRUCK_CRIT_MELEE;
3463 attType = BASE_ATTACK; // Melee abilities are assumed to be dealt with mainhand weapon
3465 else if (procSpell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
3467 if(procAttacker & PROC_FLAG_HIT_SPELL) procAttacker |= PROC_FLAG_HIT_RANGED;
3468 if(procAttacker & PROC_FLAG_CRIT_SPELL) procAttacker |= PROC_FLAG_CRIT_RANGED;
3469 if(procVictim & PROC_FLAG_STRUCK_SPELL) procVictim |= PROC_FLAG_STRUCK_RANGED;
3470 if(procVictim & PROC_FLAG_STRUCK_CRIT_SPELL) procVictim |= PROC_FLAG_STRUCK_CRIT_RANGED;
3471 attType = RANGED_ATTACK;
3474 if(damage && (procVictim & (PROC_FLAG_STRUCK_MELEE|PROC_FLAG_STRUCK_RANGED|PROC_FLAG_STRUCK_SPELL)))
3475 procVictim |= (PROC_FLAG_TAKE_DAMAGE|PROC_FLAG_TOUCH);
3477 // Not much to do if no flags are set.
3478 if (procAttacker)
3480 for(std::set<uint32>::iterator aur = attackerProcAuraTypes.begin(); aur != attackerProcAuraTypes.end(); ++aur)
3482 // List of spells (effects) that proced. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
3483 ProcTriggeredList procTriggered;
3485 AuraList const& attackerAuras = GetAurasByType(*aur);
3486 for(AuraList::const_iterator i = attackerAuras.begin(), next; i != attackerAuras.end(); i = next)
3488 next = i; next++;
3489 uint32 procFlag = procAttacker;
3491 SpellEntry const *spellProto = (*i)->GetSpellProto();
3492 if(!spellProto) continue;
3493 SpellProcEventEntry const *spellProcEvent = objmgr.GetSpellProcEvent(spellProto->Id);
3495 if(!spellProcEvent && spellProto->procFlags != 0 && nonHandledSpellProcSet.find(spellProto->Id)==nonHandledSpellProcSet.end())
3497 sLog.outError("ProcDamageAndSpell: spell %u (attacker's aura source) not have record in `spell_proc_event`)",spellProto->Id);
3498 nonHandledSpellProcSet.insert(spellProto->Id);
3501 uint32 procFlags = spellProcEvent ? spellProcEvent->procFlags : spellProto->procFlags;
3502 // Check if current equipment allows aura to proc
3503 if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->IsUseEquipedWeapon())
3505 if(spellProto->EquippedItemClass == ITEM_CLASS_WEAPON)
3507 Item *item = NULL;
3508 if(attType == BASE_ATTACK)
3509 item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
3510 else if (attType == OFF_ATTACK)
3511 item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
3512 else
3513 item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
3515 if(!item || item->IsBroken() || item->GetProto()->Class != ITEM_CLASS_WEAPON || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
3516 continue;
3518 else if(spellProto->EquippedItemClass == ITEM_CLASS_ARMOR)
3520 // Check if player is wearing shield
3521 Item *item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
3522 if(!item || item->IsBroken() || item->GetProto()->Class != ITEM_CLASS_ARMOR || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
3523 continue;
3526 if((procFlag & procFlags) == 0)
3527 continue;
3529 // Additional checks in case spell cast/hit/crit is the event
3530 // Check (if set) school, category, skill line, spell talent mask
3531 if(spellProcEvent)
3533 if(spellProcEvent->schoolMask && (!procSpell || !procSpell->School || ((1<<procSpell->School) & spellProcEvent->schoolMask) == 0))
3534 continue;
3535 if(spellProcEvent->category && (!procSpell || procSpell->Category != spellProcEvent->category))
3536 continue;
3537 if(spellProcEvent->skillId)
3539 if (!procSpell) continue;
3540 SkillLineAbilityEntry const *skillLineEntry = sSkillLineAbilityStore.LookupEntry(procSpell->Id);
3541 if(!skillLineEntry || skillLineEntry->skillId != spellProcEvent->skillId)
3542 continue;
3544 if(spellProcEvent->spellFamilyName && (!procSpell || spellProcEvent->spellFamilyName != procSpell->SpellFamilyName))
3545 continue;
3546 if(spellProcEvent->spellFamilyMask && (!procSpell || (spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags) == 0))
3547 continue;
3550 // Need to use floats here, cuz calculated PPM chance often is about 1-2%
3551 float chance = (float)spellProto->procChance;
3552 if(GetTypeId() == TYPEID_PLAYER)
3553 ((Player*)this)->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance);
3554 uint32 WeaponSpeed = GetAttackTime(attType);
3555 if(spellProcEvent && spellProcEvent->ppmRate != 0)
3556 chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate);
3558 if(roll_chance_f(chance))
3560 if((*i)->m_procCharges > 0)
3561 (*i)->m_procCharges -= 1;
3563 uint32 i_spell_eff = (*i)->GetEffIndex();
3565 int32 i_spell_param;
3566 switch(*aur)
3568 case SPELL_AURA_PROC_TRIGGER_SPELL: i_spell_param = procFlag; break;
3569 case SPELL_AURA_DUMMY: i_spell_param = i_spell_eff; break;
3570 default: i_spell_param = (*i)->GetModifier()->m_amount; break;
3573 procTriggered.push_back( ProcTriggeredData(spellProto,i_spell_param,*i) );
3577 // Handle effects proceed this time
3578 for(ProcTriggeredList::iterator i = procTriggered.begin(); i != procTriggered.end(); i++)
3580 if(*aur == SPELL_AURA_PROC_TRIGGER_SPELL)
3582 sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered by an attacker's aura of spell %u)", i->spellInfo->Id,i->triggeredByAura->GetId());
3583 HandleProcTriggerSpell(pVictim, damage, i->triggeredByAura, procSpell,i->spellParam);
3585 else if(*aur == SPELL_AURA_PROC_TRIGGER_DAMAGE)
3587 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());
3588 uint32 damage = i->spellParam;
3589 // TODO: remove hack for Seal of Righteousness. That should not be there
3590 if(i->spellInfo->SpellVisual == 7986)
3591 damage = (damage * GetAttackTime(BASE_ATTACK))/60/1000;
3592 if(pVictim && pVictim->isAlive())
3593 SpellNonMeleeDamageLog(pVictim, i->spellInfo->Id, damage, true, true);
3595 else if(*aur == SPELL_AURA_DUMMY)
3597 // TODO: write a DUMMY aura handle code
3598 if (pVictim && pVictim->isAlive())
3600 sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by an attacker dummy aura of spell %u)", i->spellInfo->Id,i->triggeredByAura->GetId());
3601 HandleDummyAuraProc(pVictim, i->spellInfo, i->spellParam, damage, i->triggeredByAura, procSpell, procAttacker);
3606 // Safely remove attacker auras with zero charges
3607 for(AuraList::const_iterator i = attackerAuras.begin(), next; i != attackerAuras.end(); i = next)
3609 next = i; ++next;
3610 if((*i)->m_procCharges == 0)
3612 RemoveAurasDueToSpell((*i)->GetId());
3613 next = attackerAuras.begin();
3619 // Now go on with a victim's events'n'auras
3620 // Not much to do if no flags are set or there is no victim
3621 if(pVictim && pVictim->isAlive() && procVictim)
3623 for(std::set<uint32>::iterator aur = victimProcAuraTypes.begin(); aur != victimProcAuraTypes.end(); aur++)
3625 // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
3626 ProcTriggeredList procTriggered;
3628 AuraList const& victimAuras = pVictim->GetAurasByType(*aur);
3629 for(AuraList::const_iterator i = victimAuras.begin(), next; i != victimAuras.end(); i = next)
3631 next = i; next++;
3632 uint32 procFlag = procVictim;
3634 SpellEntry const *spellProto = (*i)->GetSpellProto();
3635 if(!spellProto) continue;
3636 SpellProcEventEntry const *spellProcEvent = objmgr.GetSpellProcEvent(spellProto->Id);
3638 if(!spellProcEvent && spellProto->procFlags != 0 && nonHandledSpellProcSet.find(spellProto->Id)==nonHandledSpellProcSet.end())
3640 sLog.outError("ProcDamageAndSpell: spell %u (victim's aura source) not have record in `spell_proc_event`)",spellProto->Id);
3641 nonHandledSpellProcSet.insert(spellProto->Id);
3644 uint32 procFlags = spellProcEvent ? spellProcEvent->procFlags : spellProto->procFlags;
3645 if((procFlag & procFlags) == 0)
3646 continue;
3648 // Additional checks in case spell cast/hit/crit is the event
3649 // Check (if set) school, category, skill line, spell talent mask
3650 if(spellProcEvent)
3652 if(spellProcEvent->schoolMask && (!procSpell || !procSpell->School || ((1<<procSpell->School) & spellProcEvent->schoolMask) == 0))
3653 continue;
3654 if(spellProcEvent->category && (!procSpell || procSpell->Category != spellProcEvent->category))
3655 continue;
3656 if(spellProcEvent->skillId)
3658 if (!procSpell) continue;
3659 SkillLineAbilityEntry const *skillLineEntry = sSkillLineAbilityStore.LookupEntry(procSpell->Id);
3660 if(!skillLineEntry || skillLineEntry->skillId != spellProcEvent->skillId)
3661 continue;
3663 if(spellProcEvent->spellFamilyName && (!procSpell || spellProcEvent->spellFamilyName != procSpell->SpellFamilyName))
3664 continue;
3665 if(spellProcEvent->spellFamilyMask && (!procSpell || (spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags) == 0))
3666 continue;
3669 // procChance is exact number in percents anyway
3670 uint32 chance = spellProto->procChance;
3671 if(pVictim->GetTypeId() == TYPEID_PLAYER)
3672 ((Player*)pVictim)->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance);
3673 if(roll_chance_i(chance))
3675 if((*i)->m_procCharges > 0)
3676 (*i)->m_procCharges -= 1;
3678 uint32 i_spell_eff = (*i)->GetEffIndex();
3679 int32 i_spell_param;
3680 switch(*aur)
3682 case SPELL_AURA_PROC_TRIGGER_SPELL: i_spell_param = procFlag; break;
3683 case SPELL_AURA_DUMMY: i_spell_param = i_spell_eff; break;
3684 default: i_spell_param = (*i)->GetModifier()->m_amount; break;
3687 procTriggered.push_back( ProcTriggeredData(spellProto,i_spell_param,*i) );
3691 // Handle effects proced this time
3692 for(ProcTriggeredList::iterator i = procTriggered.begin(); i != procTriggered.end(); i++)
3694 if(*aur == SPELL_AURA_PROC_TRIGGER_SPELL)
3696 sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered by a victim's aura of spell %u))",i->spellInfo->Id, i->triggeredByAura);
3697 pVictim->HandleProcTriggerSpell(this, damage, i->triggeredByAura, procSpell,i->spellParam);
3699 else if(*aur == SPELL_AURA_PROC_TRIGGER_DAMAGE)
3701 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);
3702 pVictim->SpellNonMeleeDamageLog(this, i->spellInfo->Id, i->spellParam, true, true);
3704 else if(*aur == SPELL_AURA_DUMMY)
3706 // TODO: write a DUMMY aura handle code
3707 sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered by a victim's dummy aura of spell %u))",i->spellInfo->Id, i->triggeredByAura);
3708 pVictim->HandleDummyAuraProc(this, i->spellInfo, i->spellParam, damage, i->triggeredByAura, procSpell, procVictim);
3712 // Safely remove auras with zero charges
3713 for(AuraList::const_iterator i = victimAuras.begin(), next; i != victimAuras.end(); i = next)
3715 next = i; ++next;
3716 if((*i)->m_procCharges == 0)
3718 pVictim->RemoveAurasDueToSpell((*i)->GetId());
3719 next = victimAuras.begin();
3726 void Unit::CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, WeaponAttackType attType, MeleeHitOutcome outcome, SpellEntry const *spellCasted, bool isTriggeredSpell)
3728 if(!pVictim)
3729 return;
3731 uint32 procAttacker = PROC_FLAG_NONE;
3732 uint32 procVictim = PROC_FLAG_NONE;
3734 switch(outcome)
3736 case MELEE_HIT_MISS:
3737 if(attType == BASE_ATTACK || attType == OFF_ATTACK)
3739 procAttacker = PROC_FLAG_MISS;
3741 break;
3742 case MELEE_HIT_CRIT:
3743 if(spellCasted && attType == BASE_ATTACK)
3745 procAttacker |= PROC_FLAG_CRIT_SPELL;
3746 procVictim |= PROC_FLAG_STRUCK_CRIT_SPELL;
3748 else if(attType == BASE_ATTACK || attType == OFF_ATTACK)
3750 procAttacker = PROC_FLAG_HIT_MELEE | PROC_FLAG_CRIT_MELEE;
3751 procVictim = PROC_FLAG_STRUCK_MELEE | PROC_FLAG_STRUCK_CRIT_MELEE;
3753 else
3755 procAttacker = PROC_FLAG_HIT_RANGED | PROC_FLAG_CRIT_RANGED;
3756 procVictim = PROC_FLAG_STRUCK_RANGED | PROC_FLAG_STRUCK_CRIT_RANGED;
3758 break;
3759 case MELEE_HIT_PARRY:
3760 procAttacker = PROC_FLAG_TARGET_DODGE_OR_PARRY;
3761 procVictim = PROC_FLAG_PARRY;
3762 break;
3763 case MELEE_HIT_BLOCK:
3764 procAttacker = PROC_FLAG_TARGET_BLOCK;
3765 procVictim = PROC_FLAG_BLOCK;
3766 break;
3767 case MELEE_HIT_DODGE:
3768 procAttacker = PROC_FLAG_TARGET_DODGE_OR_PARRY;
3769 procVictim = PROC_FLAG_DODGE;
3770 break;
3771 case MELEE_HIT_CRUSHING:
3772 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 default:
3784 if(attType == BASE_ATTACK || attType == OFF_ATTACK)
3786 procAttacker = PROC_FLAG_HIT_MELEE;
3787 procVictim = PROC_FLAG_STRUCK_MELEE;
3789 else
3791 procAttacker = PROC_FLAG_HIT_RANGED;
3792 procVictim = PROC_FLAG_STRUCK_RANGED;
3794 break;
3797 if(damage > 0)
3798 procVictim |= PROC_FLAG_TAKE_DAMAGE;
3800 if(procAttacker != PROC_FLAG_NONE || procVictim != PROC_FLAG_NONE)
3801 ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, spellCasted, isTriggeredSpell, attType);
3804 void Unit::HandleDummyAuraProc(Unit *pVictim, SpellEntry const *dummySpell, uint32 effIndex, uint32 damage, Aura* triggredByAura, SpellEntry const * procSpell, uint32 procFlag)
3806 switch(dummySpell->Id )
3808 // Ignite
3809 case 11119:
3810 case 11120:
3811 case 12846:
3812 case 12847:
3813 case 12848:
3815 if(!pVictim)
3816 return;
3818 int32 igniteDotBasePoints0;
3820 switch (dummySpell->Id)
3822 case 11119: igniteDotBasePoints0=int32(0.04f*damage)-1; break;
3823 case 11120: igniteDotBasePoints0=int32(0.08f*damage)-1; break;
3824 case 12846: igniteDotBasePoints0=int32(0.12f*damage)-1; break;
3825 case 12847: igniteDotBasePoints0=int32(0.16f*damage)-1; break;
3826 case 12848: igniteDotBasePoints0=int32(0.20f*damage)-1; break;
3827 default:
3828 sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell->Id);
3829 return;
3831 CastCustomSpell(pVictim, 12654, &igniteDotBasePoints0, NULL, NULL, true, NULL, triggredByAura);
3832 return;
3835 // Combustion
3836 case 11129:
3838 CastSpell(this, 28682, true, NULL, triggredByAura);
3839 if (!(procFlag & PROC_FLAG_CRIT_SPELL)) //no crit
3840 triggredByAura->m_procCharges += 1; //-> reincrease procCharge count since it was decreased before
3841 else if (triggredByAura->m_procCharges == 0) //no more charges left and crit
3842 RemoveAurasDueToSpell(28682); //-> remove Combustion auras
3843 return;
3845 // Nightfall
3846 case 18094:
3847 case 18095:
3849 CastSpell(this, 17941, true, NULL, triggredByAura);
3850 return;
3852 // VE
3853 case 15286:
3855 if(!pVictim)
3856 return;
3858 if(triggredByAura->GetCasterGUID() == pVictim->GetGUID())
3860 //VEHeal has a BaseDice of 0, so no decrement needed
3861 int32 VEHealBasePoints0 = triggredByAura->GetModifier()->m_amount*damage/100;
3862 pVictim->CastCustomSpell(pVictim, 15290, &VEHealBasePoints0, NULL, NULL, true, NULL, triggredByAura);
3864 return;
3866 // Eye of Eye
3867 case 9799:
3868 case 25988:
3870 if(!pVictim)
3871 return;
3873 // return damage % to attacker but < 50% own total health
3874 uint32 backDamage = triggredByAura->GetModifier()->m_amount*damage/100;
3875 if(backDamage > GetMaxHealth()/2)
3876 backDamage = GetMaxHealth()/2;
3878 int32 YYDamageBasePoints0 = backDamage-1;
3879 CastCustomSpell(pVictim, 25997, &YYDamageBasePoints0, NULL, NULL, true, NULL, triggredByAura);
3881 return;
3884 // L.Overload
3885 case 30675:
3886 case 30678:
3887 case 30679:
3888 case 30680:
3889 case 30681:
3891 if(!procSpell)
3892 return;
3894 // we assume lightning bolt and chain lightning are generic (not channeled/autorepeat) spells
3895 if(!pVictim || !m_currentSpells[CURRENT_GENERIC_SPELL])
3896 return;
3898 // remove cooldown from first cast
3899 if(GetTypeId()==TYPEID_PLAYER)
3900 ((Player*)this)->RemoveSpellCooldown(procSpell->Id);
3901 // prepare cast as triggered spell (this need for correct targets selection after not finished currently cast)
3902 m_currentSpells[CURRENT_GENERIC_SPELL]->AddTriggeredSpell(procSpell);
3905 // Spiritual Att.
3906 case 33776:
3907 case 31785:
3909 if(!pVictim)
3910 return;
3912 // if healed by another unit (pVictim)
3913 if(this != pVictim)
3915 int32 SAHealBasePoints0 = triggredByAura->GetModifier()->m_amount*damage/100-1;
3916 CastCustomSpell(this, 31786, &SAHealBasePoints0, NULL, NULL, true, NULL, triggredByAura);
3919 return;
3922 // Shadowflame (item set effect)
3923 case 37377:
3925 if(GetTypeId() != TYPEID_PLAYER)
3926 return;
3928 Item* castItem = ((Player*)this)->GetItemByGuid(triggredByAura->GetCastItemGUID());
3929 if(!castItem)
3930 return;
3932 CastSpell(pVictim,37379,true,castItem,triggredByAura);
3933 return;
3935 // Shadowflame Hellfire (item set effect)
3936 case 39437:
3938 if(GetTypeId() != TYPEID_PLAYER)
3939 return;
3941 Item* castItem = ((Player*)this)->GetItemByGuid(triggredByAura->GetCastItemGUID());
3942 if(!castItem)
3943 return;
3945 CastSpell(pVictim,37378,true,castItem,triggredByAura);
3946 return;
3949 default: break;
3952 switch(dummySpell->SpellFamilyName)
3954 case SPELLFAMILY_SHAMAN:
3955 if(dummySpell->SpellFamilyFlags==0x40000000000LL)
3957 int32 HealBasePoints0 = dummySpell->EffectBasePoints[0];
3958 CastCustomSpell(this,379,&HealBasePoints0,NULL,NULL,true,NULL,triggredByAura);
3959 return;
3961 break;
3962 default:
3963 break;
3966 // Non SpellID checks
3967 switch(dummySpell->SpellIconID)
3969 // Master of Elements
3970 case 1920:
3972 if(!procSpell)
3973 return;
3975 if(dummySpell->SpellFamilyName!=SPELLFAMILY_MAGE)
3976 return;
3978 int32 MEManaCostSave = procSpell->manaCost * triggredByAura->GetModifier()->m_amount/100;
3979 if(MEManaCostSave <= 0)
3980 return;
3981 int32 MEManaRestoreBasePoints0 = MEManaCostSave-1;
3982 CastCustomSpell(this,29077,&MEManaRestoreBasePoints0,NULL,NULL,true,NULL, triggredByAura);
3984 return;
3986 // VT
3987 case 2213:
3989 if(!pVictim)
3990 return;
3992 if(triggredByAura->GetCasterGUID() == pVictim->GetGUID())
3994 int32 VTEnergizeBasePoints0 = triggredByAura->GetModifier()->m_amount*damage/100 - 1;
3995 pVictim->CastCustomSpell(pVictim,34919,&VTEnergizeBasePoints0,NULL,NULL,true,NULL, triggredByAura);
3997 return;
3999 // Quick Recovery
4000 case 2116:
4002 if(!procSpell)
4003 return;
4005 if(dummySpell->SpellFamilyName!=SPELLFAMILY_ROGUE)
4006 return;
4008 // only rogue's finishing moves (maybe need additional checks)
4009 if( procSpell->SpellFamilyName!=SPELLFAMILY_ROGUE ||
4010 (procSpell->SpellFamilyFlags & (0x40000 | 0x80000 | 0x100000 | 0x200000 | 0x800000000LL | 0x20000)) == 0)
4011 return;
4013 int32 QREnegyCostSave = procSpell->manaCost * triggredByAura->GetModifier()->m_amount/100;
4014 if(QREnegyCostSave <= 0)
4015 return;
4016 int32 QREnergizeBasePoints0 = QREnegyCostSave-1;
4017 CastCustomSpell(this,31663,&QREnergizeBasePoints0,NULL,NULL,true,NULL, triggredByAura);
4019 return;
4021 // Thrill of the Hunt
4022 case 2236:
4024 if(!procSpell)
4025 return;
4027 if(dummySpell->SpellFamilyName!=SPELLFAMILY_HUNTER)
4028 return;
4030 int32 THManaCostSave = procSpell->manaCost * 40/100;
4031 if(THManaCostSave <= 0)
4032 return;
4033 int32 THEnergizeBasePoints0 = THManaCostSave-1;
4034 CastCustomSpell(this,34720,&THEnergizeBasePoints0,NULL,NULL,true,NULL, triggredByAura);
4036 return;
4041 void Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 procFlags)
4043 SpellEntry const* auraSpellInfo = triggeredByAura->GetSpellProto();
4045 switch(auraSpellInfo->SpellIconID)
4047 case 19:
4049 switch(auraSpellInfo->SpellFamilyName)
4051 case SPELLFAMILY_SHAMAN:
4053 //Lightning Shield (overwrite non existing triggered spell call in spell.dbc
4054 if(auraSpellInfo->SpellFamilyFlags==0x00000400)
4056 if(!pVictim)
4057 return;
4059 uint32 spell = 0;
4060 switch(triggeredByAura->GetSpellProto()->Id)
4062 // Rank 1
4063 case 324: spell = 26364; break;
4064 // Rank 2
4065 case 325: spell = 26365; break;
4066 // Rank 3
4067 case 905: spell = 26366; break;
4068 // Rank 4
4069 case 945: spell = 26367; break;
4070 // Rank 5
4071 case 8134: spell = 26369; break;
4072 // Rank 6
4073 case 10431: spell = 26370; break;
4074 // Rank 7
4075 case 10432: spell = 26363; break;
4076 // Rank 8
4077 case 25469: spell = 26371; break;
4078 // Rank 9
4079 case 25472: spell = 26372; break;
4080 default:
4081 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura->GetSpellProto()->Id);
4082 return;
4084 CastSpell(pVictim, spell, true, NULL, triggeredByAura);
4085 return;
4087 break;
4089 case SPELLFAMILY_PRIEST:
4091 // Priest's "Shadowguard"
4092 if(auraSpellInfo->SpellFamilyFlags==0x100080000000LL)
4094 if(!pVictim)
4095 return;
4097 uint32 spell = 0;
4098 switch(triggeredByAura->GetSpellProto()->Id)
4100 // Rank 1
4101 case 18137: spell = 28377; break;
4102 // Rank 2
4103 case 19308: spell = 28378; break;
4104 // Rank 3
4105 case 19309: spell = 28379; break;
4106 // Rank 4
4107 case 19310: spell = 28380; break;
4108 // Rank 5
4109 case 19311: spell = 28381; break;
4110 // Rank 6
4111 case 19312: spell = 28382; break;
4112 // Rank 7
4113 case 25477: spell = 28385; break;
4114 default:
4115 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura->GetSpellProto()->Id);
4116 return;
4118 CastSpell(pVictim, spell, true, NULL, triggeredByAura);
4119 return;
4121 break;
4124 break;
4126 case 87:
4128 //Mana Surge (Shaman T1 bonus)
4129 //Effect: 23571
4130 if(!procSpell)
4131 return;
4133 int32 manaSurgeSpellBasePoints0 = procSpell->manaCost * 35/100;
4134 CastCustomSpell(this, 23571, &manaSurgeSpellBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
4135 return;
4137 case 113:
4139 //Improved Drain Soul
4140 //Effect: 18371
4141 Unit::AuraList const& mAddFlatModifier = GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
4142 for(Unit::AuraList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i)
4144 if ((*i)->GetModifier()->m_miscvalue == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellProto()->SpellIconID == 113)
4146 int32 impDrainSoulBasePoints0 = (*i)->GetSpellProto()->EffectBasePoints[2] * GetMaxPower(POWER_MANA) / 100;
4147 CastCustomSpell(this, 18371, &impDrainSoulBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
4150 return;
4152 case 241:
4154 switch(auraSpellInfo->EffectTriggerSpell[0])
4156 //Illumination
4157 case 18350:
4159 if(!procSpell)
4160 return;
4162 SpellEntry const *originalSpell = procSpell;
4164 // in case HShock procspell is triggered spell but we need mana cost of original casted spell
4165 if(procSpell->SpellFamilyName == SPELLFAMILY_PALADIN && procSpell->SpellFamilyFlags == 0x00200000)
4167 uint32 originalSpellId = 0;
4168 switch(procSpell->Id)
4170 case 25914: originalSpellId = 20473; break;
4171 case 25913: originalSpellId = 20929; break;
4172 case 25903: originalSpellId = 20930; break;
4173 case 27175: originalSpellId = 27174; break;
4174 case 33074: originalSpellId = 33072; break;
4175 default:
4176 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell->Id);
4177 return;
4179 SpellEntry const *HSSpell= sSpellStore.LookupEntry(originalSpellId);
4180 if(!HSSpell)
4182 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but used in HShock",originalSpellId);
4183 return;
4185 originalSpell = HSSpell;
4188 // percent stored in effect 1 (class scripts) base points
4189 int32 percent = auraSpellInfo->EffectBasePoints[1]+1;
4191 // BasePoints = val -1 not required (EffectBaseDice==0)
4192 int32 ILManaSpellBasePoints0 = originalSpell->manaCost*percent/100;
4193 CastCustomSpell(this, 20272, &ILManaSpellBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
4194 return;
4197 break;
4199 case 312:
4201 //Improved Leader of the Pack
4202 //Effect 34299
4203 //Cooldown: 6 secs
4204 if (triggeredByAura->GetModifier()->m_amount == 0)
4205 break;
4206 int32 improvedLotPBasePoints0 = triggeredByAura->GetModifier()->m_amount * GetMaxHealth() / 100 - 1;
4207 CastCustomSpell(this, 34299, &improvedLotPBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
4208 if (GetTypeId() == TYPEID_PLAYER)
4209 ((Player*)this)->AddSpellCooldown(34299,0,time(NULL) + 6);
4210 return;
4212 case 1137:
4214 //Pyroclasm
4215 //Effect: 18093
4216 float chance = 0;
4217 switch (triggeredByAura->GetSpellProto()->Id)
4219 case 18096:
4220 chance = 13.0;
4221 break;
4222 case 18073:
4223 chance = 26.0;
4224 break;
4226 if (pVictim && pVictim->isAlive() && roll_chance_f(chance))
4227 CastSpell(pVictim, 18093, true, NULL, triggeredByAura);
4228 return;
4230 case 1875:
4232 //Blessed Recovery
4233 uint32 EffectId = 0;
4234 switch (triggeredByAura->GetSpellProto()->Id)
4236 case 27811: EffectId = 27813; break;
4237 case 27815: EffectId = 27817; break;
4238 case 27816: EffectId = 27818; break;
4239 default:
4240 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura->GetSpellProto()->Id);
4241 return;
4244 int32 heal_amount = damage * triggeredByAura->GetModifier()->m_amount / 100;
4245 int32 BRHealBasePoints0 = heal_amount/3-1;
4246 CastCustomSpell(this, EffectId, &BRHealBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
4247 return;
4249 case 2006:
4250 //Rampage
4251 //Effects: 30029(Rank 1), 30031(Rank 2), 30032(Rank 3)
4252 //Check EffectTriggerSpell[1] to determine correct effect id
4253 //CastSpell(this, triggredByAura->GetSpellProto()->EffectTriggerSpell[1], true, NULL, triggredByAura);
4254 return;
4255 case 2013:
4257 //Nature's Guardian
4258 //Effects: 31616, 39301
4259 //Cooldown: 5 secs
4260 /*float HealthRatio = GetHealth() / GetMaxHealth();
4261 float HealthRatioBefore = (GetHealth() + damage) / GetMaxHealth();
4262 if (HealthRatio < 0.3 && HealthRatioBefore >= 0.3)
4264 SpellEntry const *NGHealTemplate = sSpellStore.LookupEntry(31616);
4265 SpellEntry NGHeal = *NGHealTemplate;
4266 NGHeal.EffectBasePoints[0] = triggredByAura->GetModifier()->m_amount * GetMaxHealth() / 100;
4267 CastSpell(this, &NGHeal, true, NULL, triggredByAura);
4268 if (pVictim && pVictim->isAlive())
4269 CastSpell(pVictim, 39301, true, NULL, triggredByAura);
4270 if (GetTypeId() == TYPEID_PLAYER)
4272 ((Player*)this)->AddSpellCooldown(31616,0,time(NULL) + 5);
4273 ((Player*)this)->AddSpellCooldown(39301,0,time(NULL) + 5);
4276 return;
4278 case 2127:
4279 //Blazing Speed
4280 //Effect: 31643
4281 CastSpell(this, 31643, true, NULL, triggeredByAura);
4282 return;
4285 // custom check for proc spell
4286 switch(auraSpellInfo->Id)
4288 // Lightning Capacitor
4289 case 37657:
4291 if(!pVictim)
4292 return;
4294 // stacking
4295 CastSpell(this, 37658, true, NULL, triggeredByAura);
4297 // counting
4298 uint32 count = 0;
4299 AuraList const& dummyAura = GetAurasByType(SPELL_AURA_DUMMY);
4300 for(AuraList::const_iterator itr = dummyAura.begin(); itr != dummyAura.end(); ++itr)
4301 if((*itr)->GetId()==37658)
4302 ++count;
4304 // release at 3 aura in stack
4305 if(count >2)
4307 RemoveAurasDueToSpell(37658);
4308 CastSpell(pVictim, 37661, true, NULL, triggeredByAura);
4310 return;
4314 // standard non-dummy case
4315 uint32 trigger_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()];
4316 if(!trigger_spell_id)
4318 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo->Id,triggeredByAura->GetEffIndex());
4319 return;
4322 // but with dummy basepoints or other customs
4323 switch(trigger_spell_id)
4325 // Shamanistic Rage triggered spell
4326 case 30824:
4328 int32 SRBasePoints0 = int32(GetTotalAttackPowerValue(BASE_ATTACK)*triggeredByAura->GetModifier()->m_amount/100) -1;
4329 CastCustomSpell(this, 30824, &SRBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
4330 return;
4332 // Backlash triggered spell
4333 case 34936:
4335 // need set custom cooldown
4336 if(isAlive() && GetTypeId()==TYPEID_PLAYER && !((Player*)this)->HasSpellCooldown(34936))
4338 CastSpell(this,trigger_spell_id,true,NULL,triggeredByAura);
4339 ((Player*)this)->AddSpellCooldown(34936,0,time(NULL)+8);
4341 return;
4345 // default case
4346 if(IsPositiveSpell(trigger_spell_id) && !(procFlags & PROC_FLAG_HEAL))
4347 CastSpell(this,trigger_spell_id,true,NULL,triggeredByAura);
4348 else if(pVictim && pVictim->isAlive())
4349 CastSpell(pVictim,trigger_spell_id,true,NULL,triggeredByAura);
4352 void Unit::setPowerType(Powers new_powertype)
4354 uint32 tem_bytes_0 = GetUInt32Value(UNIT_FIELD_BYTES_0);
4355 SetUInt32Value(UNIT_FIELD_BYTES_0,((tem_bytes_0<<8)>>8) + (uint32(new_powertype)<<24));
4357 if (GetTypeId() == TYPEID_PLAYER)
4358 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE);
4360 switch(new_powertype)
4362 default:
4363 case POWER_MANA:
4364 break;
4365 case POWER_RAGE:
4366 SetMaxPower(POWER_RAGE,GetCreatePowers(POWER_RAGE));
4367 SetPower( POWER_RAGE,0);
4368 break;
4369 case POWER_FOCUS:
4370 SetMaxPower(POWER_FOCUS,GetCreatePowers(POWER_FOCUS));
4371 SetPower( POWER_FOCUS,GetCreatePowers(POWER_FOCUS));
4372 break;
4373 case POWER_ENERGY:
4374 SetMaxPower(POWER_ENERGY,GetCreatePowers(POWER_ENERGY));
4375 SetPower( POWER_ENERGY,0);
4376 break;
4377 case POWER_HAPPINESS:
4378 SetMaxPower(POWER_HAPPINESS,GetCreatePowers(POWER_HAPPINESS));
4379 SetPower(POWER_HAPPINESS,GetCreatePowers(POWER_HAPPINESS));
4380 break;
4384 FactionTemplateEntry const* Unit::getFactionTemplateEntry() const
4386 FactionTemplateEntry const* entry = sFactionTemplateStore.LookupEntry(getFaction());
4387 if(!entry)
4389 static uint64 guid = 0; // prevent repeating spam same faction problem
4391 if(GetGUID() != guid)
4393 if(GetTypeId() == TYPEID_PLAYER)
4394 sLog.outError("Player %s have invalid faction (faction template id) #%u", ((Player*)this)->GetName(), getFaction());
4395 else
4396 sLog.outError("Creature (template id: %u) have invalid faction (faction template id) #%u", ((Creature*)this)->GetCreatureInfo()->Entry, getFaction());
4397 guid = GetGUID();
4400 return entry;
4403 bool Unit::IsHostileTo(Unit const* unit) const
4405 // always non-hostile to self
4406 if(unit==this)
4407 return false;
4409 // always hostile to enemy
4410 if(getVictim()==unit || unit->getVictim()==this)
4411 return true;
4413 // test pet/charm masters instead pers/charmeds
4414 Unit const* testerOwner = GetCharmerOrOwner();
4415 Unit const* targetOwner = unit->GetCharmerOrOwner();
4417 // always hostile to owner's enemy
4418 if(testerOwner && (testerOwner->getVictim()==unit || unit->getVictim()==testerOwner))
4419 return true;
4421 // always hostile to enemy owner
4422 if(targetOwner && (getVictim()==targetOwner || targetOwner->getVictim()==this))
4423 return true;
4425 // always hostile to owner of owner's enemy
4426 if(testerOwner && targetOwner && (testerOwner->getVictim()==targetOwner || targetOwner->getVictim()==testerOwner))
4427 return true;
4429 Unit const* tester = testerOwner ? testerOwner : this;
4430 Unit const* target = targetOwner ? targetOwner : unit;
4432 // special cases (Duel, etc)
4433 if(tester->GetTypeId()==TYPEID_PLAYER && target->GetTypeId()==TYPEID_PLAYER)
4435 // Duel
4436 if(((Player const*)tester)->duel && ((Player const*)tester)->duel->opponent == target && ((Player const*)tester)->duel->startTime != 0)
4437 return true;
4439 //= PvP states
4440 // Green/Blue (can't attack)
4441 if(((Player*)tester)->GetTeam()==((Player*)target)->GetTeam())
4442 return false;
4444 // Red (can attack) if true, Blue/Yellow (can't attack) in another case
4445 return ((Player*)tester)->IsPvP() && ((Player*)target)->IsPvP();
4448 // faction base cases
4449 FactionTemplateEntry const*tester_faction = tester->getFactionTemplateEntry();
4450 FactionTemplateEntry const*target_faction = target->getFactionTemplateEntry();
4451 if(!tester_faction || !target_faction)
4452 return false;
4454 // PvC forced reaction and reputation case
4455 if(tester->GetTypeId()==TYPEID_PLAYER)
4457 // forced reaction
4458 ForcedReactions::const_iterator forceItr = ((Player*)tester)->m_forcedReactions.find(target_faction->faction);
4459 if(forceItr!=((Player*)tester)->m_forcedReactions.end())
4461 return forceItr->second <= REP_HOSTILE;
4464 // apply reputation state
4465 FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction);
4466 if(raw_target_faction && raw_target_faction->reputationListID >=0 )
4468 if(((Player*)tester)->IsFactionAtWar(raw_target_faction))
4469 return true;
4472 // CvP forced reaction and reputation case
4473 else if(target->GetTypeId()==TYPEID_PLAYER)
4475 // forced reaction
4476 ForcedReactions::const_iterator forceItr = ((Player*)target)->m_forcedReactions.find(tester_faction->faction);
4477 if(forceItr!=((Player*)target)->m_forcedReactions.end())
4479 return forceItr->second <= REP_HOSTILE;
4482 // apply reputation state
4483 FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction);
4484 if(raw_tester_faction && raw_tester_faction->reputationListID >=0 )
4486 return ((Player*)target)->GetReputationRank(raw_tester_faction) <= REP_HOSTILE;
4490 // common faction based case (CvC,PvC,CvP)
4491 return tester_faction->IsHostileTo(*target_faction);
4494 bool Unit::IsFriendlyTo(Unit const* unit) const
4496 // always friendly to self
4497 if(unit==this)
4498 return true;
4500 // always non-friendly to enemy
4501 if(getVictim()==unit || unit->getVictim()==this)
4502 return false;
4504 // test pet/charm masters instead pers/charmeds
4505 Unit const* testerOwner = GetCharmerOrOwner();
4506 Unit const* targetOwner = unit->GetCharmerOrOwner();
4508 // always non-friendly to owner's enemy
4509 if(testerOwner && (testerOwner->getVictim()==unit || unit->getVictim()==testerOwner))
4510 return false;
4512 // always non-friendly to enemy owner
4513 if(targetOwner && (getVictim()==targetOwner || targetOwner->getVictim()==this))
4514 return false;
4516 // always non-friendly to owner of owner's enemy
4517 if(testerOwner && targetOwner && (testerOwner->getVictim()==targetOwner || targetOwner->getVictim()==testerOwner))
4518 return false;
4520 Unit const* tester = testerOwner ? testerOwner : this;
4521 Unit const* target = targetOwner ? targetOwner : unit;
4523 // special cases (Duel)
4524 if(tester->GetTypeId()==TYPEID_PLAYER && target->GetTypeId()==TYPEID_PLAYER)
4526 // Duel
4527 if(((Player const*)tester)->duel && ((Player const*)tester)->duel->opponent == target && ((Player const*)tester)->duel->startTime != 0)
4528 return false;
4530 //= PvP states
4531 // Green/Blue (non-attackable)
4532 if(((Player*)tester)->GetTeam()==((Player*)target)->GetTeam())
4533 return true;
4535 // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable)
4536 return !((Player*)target)->IsPvP();
4539 // faction base cases
4540 FactionTemplateEntry const*tester_faction = tester->getFactionTemplateEntry();
4541 FactionTemplateEntry const*target_faction = target->getFactionTemplateEntry();
4542 if(!tester_faction || !target_faction)
4543 return false;
4545 // PvC forced reaction and reputation case
4546 if(tester->GetTypeId()==TYPEID_PLAYER)
4548 // forced reaction
4549 ForcedReactions::const_iterator forceItr = ((Player*)tester)->m_forcedReactions.find(target_faction->faction);
4550 if(forceItr!=((Player*)tester)->m_forcedReactions.end())
4552 return forceItr->second >= REP_FRIENDLY;
4555 // apply reputation state
4556 FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction);
4557 if(raw_target_faction && raw_target_faction->reputationListID >=0 )
4559 if(((Player*)tester)->IsFactionAtWar(raw_target_faction))
4560 return false;
4563 // CvP forced reaction and reputation case
4564 else if(target->GetTypeId()==TYPEID_PLAYER)
4566 // forced reaction
4567 ForcedReactions::const_iterator forceItr = ((Player*)target)->m_forcedReactions.find(tester_faction->faction);
4568 if(forceItr!=((Player*)target)->m_forcedReactions.end())
4570 return forceItr->second >= REP_FRIENDLY;
4573 // apply reputation state
4574 FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction);
4575 if(raw_tester_faction && raw_tester_faction->reputationListID >=0 )
4577 return ((Player*)target)->GetReputationRank(raw_tester_faction) >= REP_FRIENDLY;
4581 // common faction based case (CvC,PvC,CvP)
4582 return tester_faction->IsFriendlyTo(*target_faction);
4585 bool Unit::IsHostileToPlayers() const
4587 FactionTemplateEntry const* my_faction = getFactionTemplateEntry();
4588 if(!my_faction)
4589 return false;
4591 FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction);
4592 if(raw_faction && raw_faction->reputationListID >=0 )
4593 return false;
4595 return my_faction->IsHostileToPlayers();
4598 bool Unit::IsNeutralToAll() const
4600 FactionTemplateEntry const* my_faction = getFactionTemplateEntry();
4601 if(!my_faction)
4602 return true;
4604 FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction);
4605 if(raw_faction && raw_faction->reputationListID >=0 )
4606 return false;
4608 return my_faction->IsNeutralToAll();
4611 bool Unit::Attack(Unit *victim, bool playerMeleeAttack)
4613 if(!victim || victim == this)
4614 return false;
4616 // player don't must attack in mount state
4617 if(GetTypeId()==TYPEID_PLAYER && IsMounted())
4618 return false;
4620 // anyone don't must attack GM in GM-mode
4621 if(victim->GetTypeId()==TYPEID_PLAYER && ((Player*)victim)->isGameMaster())
4622 return false;
4624 if (m_attacking)
4626 if (m_attacking == victim)
4627 return false;
4628 AttackStop();
4631 //Set our target
4632 SetUInt64Value(UNIT_FIELD_TARGET, victim->GetGUID());
4634 addUnitState(UNIT_STAT_ATTACKING);
4635 SetInCombat();
4636 m_attacking = victim;
4637 m_attacking->_addAttacker(this);
4639 if(m_attacking->GetTypeId()==TYPEID_UNIT && ((Creature*)m_attacking)->AI())
4640 ((Creature*)m_attacking)->AI()->AttackedBy(this);
4642 if( GetTypeId()==TYPEID_UNIT && !(((Creature*)this)->isPet() || isCharmed()) )
4644 ((Creature*)this)->CallAssistence();
4646 //if(!isAttackReady(BASE_ATTACK))
4647 //resetAttackTimer(BASE_ATTACK);
4649 // delay offhand weapon attack to next attack time
4650 if(haveOffhandWeapon())
4651 resetAttackTimer(OFF_ATTACK);
4653 if(playerMeleeAttack)
4654 SendAttackStart(victim);
4656 return true;
4659 bool Unit::AttackStop()
4661 if (!m_attacking)
4662 return false;
4664 Unit* victim = m_attacking;
4666 m_attacking->_removeAttacker(this);
4667 m_attacking = NULL;
4669 //Clear our target
4670 SetUInt64Value(UNIT_FIELD_TARGET, 0);
4672 clearUnitState(UNIT_STAT_ATTACKING);
4674 InterruptSpell(CURRENT_MELEE_SPELL);
4676 if( GetTypeId()==TYPEID_UNIT )
4678 // reset call assistance
4679 ((Creature*)this)->SetNoCallAssistence(false);
4682 SendAttackStop(victim);
4684 return true;
4687 bool Unit::isAttackingPlayer() const
4689 if(getVictim())
4691 if(getVictim()->GetTypeId() == TYPEID_PLAYER)
4692 return true;
4694 if(getVictim()->GetOwnerGUID() && GUID_HIPART(getVictim()->GetOwnerGUID())==HIGHGUID_PLAYER)
4695 return true;
4698 Pet* pet = GetPet();
4699 if(pet && pet->isAttackingPlayer())
4700 return true;
4702 Unit* charmed = GetCharm();
4703 if(charmed && charmed->isAttackingPlayer())
4704 return true;
4706 for (int8 i = 0; i < 4; i++)
4708 if(m_TotemSlot[i])
4710 Creature *totem = ObjectAccessor::Instance().GetCreature(*this, m_TotemSlot[i]);
4711 if(totem && totem->isAttackingPlayer())
4712 return true;
4716 return false;
4719 void Unit::RemoveAllAttackers()
4721 while (m_attackers.size() != 0)
4723 AttackerSet::iterator iter = m_attackers.begin();
4724 if(!(*iter)->AttackStop())
4726 sLog.outError("WORLD: Unit has an attacker that isnt attacking it!");
4727 m_attackers.erase(iter);
4732 void Unit::ModifyAuraState(uint32 flag, bool apply)
4734 if (apply)
4736 if (!HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)))
4738 SetFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
4739 if(GetTypeId() == TYPEID_PLAYER)
4741 const PlayerSpellMap& sp_list = ((Player*)this)->GetSpellMap();
4742 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
4744 if(itr->second->state == PLAYERSPELL_REMOVED) continue;
4745 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
4746 if (!spellInfo || !IsPassiveSpell(itr->first)) continue;
4747 if (spellInfo->CasterAuraState == flag)
4748 CastSpell(this, itr->first, true, NULL);
4753 else
4755 if (HasFlag(UNIT_FIELD_AURASTATE,1<<(flag-1)))
4757 RemoveFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
4758 Unit::AuraMap& tAuras = GetAuras();
4759 for (Unit::AuraMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
4761 if ((*itr).second->GetSpellProto()->CasterAuraState == flag)
4762 RemoveAura(itr);
4763 else
4764 ++itr;
4770 Unit *Unit::GetOwner() const
4772 uint64 ownerid = GetOwnerGUID();
4773 if(!ownerid)
4774 return NULL;
4775 return ObjectAccessor::Instance().GetUnit(*this, ownerid);
4778 Unit *Unit::GetCharmer() const
4780 uint64 charmerid = GetCharmerGUID();
4781 if(!charmerid)
4782 return NULL;
4783 return ObjectAccessor::Instance().GetUnit(*this, charmerid);
4786 Pet* Unit::GetPet() const
4788 uint64 pet_guid = GetPetGUID();
4789 if(pet_guid)
4791 Pet* pet = ObjectAccessor::Instance().GetPet(pet_guid);
4792 if(!pet)
4794 sLog.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid));
4795 const_cast<Unit*>(this)->SetPet(0);
4796 return NULL;
4798 return pet;
4801 return NULL;
4804 Unit* Unit::GetCharm() const
4806 uint64 charm_guid = GetCharmGUID();
4807 if(charm_guid)
4809 Unit* pet = ObjectAccessor::Instance().GetUnit(*this, charm_guid);
4810 if(!pet)
4812 sLog.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid));
4813 const_cast<Unit*>(this)->SetCharm(0);
4815 return pet;
4817 else
4818 return NULL;
4821 void Unit::SetPet(Pet* pet)
4823 SetUInt64Value(UNIT_FIELD_SUMMON,pet ? pet->GetGUID() : 0);
4825 if(pet)
4827 for(int i = 0; i < MAX_MOVE_TYPE; ++i)
4829 pet->SetSpeed(UnitMoveType(i),m_speed_rate[i],true);
4834 void Unit::SetCharm(Unit* charmed)
4836 SetUInt64Value(UNIT_FIELD_CHARM,charmed ? charmed->GetGUID() : 0);
4839 void Unit::UnsummonAllTotems()
4841 for (int8 i = 0; i < 4; ++i)
4843 if(!m_TotemSlot[i])
4844 continue;
4846 Creature *OldTotem = ObjectAccessor::Instance().GetCreature(*this, m_TotemSlot[i]);
4847 if (OldTotem && OldTotem->isTotem())
4848 ((Totem*)OldTotem)->UnSummon();
4852 void Unit::SendHealSpellOnPlayer(Unit *pVictim, uint32 SpellID, uint32 Damage, bool critical)
4854 // we guess size
4855 WorldPacket data(SMSG_HEALSPELL_ON_PLAYER_OBSOLETE, (8+8+4+4+1));
4856 data.append(pVictim->GetPackGUID());
4857 data.append(GetPackGUID());
4858 data << SpellID;
4859 data << Damage;
4860 data << uint8(critical ? 1 : 0);
4861 SendMessageToSet(&data, true);
4864 void Unit::SendHealSpellOnPlayerPet(Unit *pVictim, uint32 SpellID, uint32 Damage,Powers powertype, bool critical)
4866 WorldPacket data(SMSG_HEALSPELL_ON_PLAYERS_PET_OBSOLETE, (8+8+4+4+4+1));
4867 data.append(pVictim->GetPackGUID());
4868 data.append(GetPackGUID());
4869 data << SpellID;
4870 data << uint32(powertype);
4871 data << Damage;
4872 data << uint8(critical ? 1 : 0);
4873 SendMessageToSet(&data, true);
4876 uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 pdamage, DamageEffectType damagetype)
4878 if(!spellProto || !pVictim || damagetype==DIRECT_DAMAGE )
4879 return pdamage;
4881 if(pVictim->IsImmunedToSpellDamage(spellProto))
4882 return 0;
4884 uint32 creatureTypeMask = GetCreatureTypeMask();
4886 // Damage Done
4887 uint32 CastingTime = GetCastTime(sCastTimesStore.LookupEntry(spellProto->CastingTimeIndex));
4888 if (CastingTime > 7000) CastingTime = 7000; // Plus Damage efficient maximum 200% ( 7.0 seconds )
4889 if (CastingTime < 1500) CastingTime = 1500;
4891 // Taken/Done fixed damage bonus auras
4892 int32 DoneAdvertisedBenefit = 0;
4893 int32 TakenAdvertisedBenefit = 0;
4895 // ..done (for creature type by mask) in taken
4896 AuraList const& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
4897 for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
4898 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
4899 TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount;
4901 // ..done
4902 AuraList const& mDamageDone = this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE);
4903 for(AuraList::const_iterator i = mDamageDone.begin();i != mDamageDone.end(); ++i)
4904 if(((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0 &&
4905 (*i)->GetSpellProto()->EquippedItemClass == -1 &&
4906 // -1 == any item class (not wand then)
4907 (*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 )
4908 // 0 == any inventory type (not wand then)
4909 DoneAdvertisedBenefit += (*i)->GetModifier()->m_amount;
4911 if (GetTypeId() == TYPEID_PLAYER)
4913 // Damage bonus of spirit
4914 AuraList const& mDamageDonebySpi = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_SPIRIT);
4915 for(AuraList::const_iterator i = mDamageDonebySpi.begin();i != mDamageDonebySpi.end(); ++i)
4916 if((*i)->GetModifier()->m_miscvalue & 1 << spellProto->School)
4917 DoneAdvertisedBenefit += int32(GetStat(STAT_SPIRIT) * (*i)->GetModifier()->m_amount / 100.0f);
4919 // ... and intellect
4920 AuraList const& mDamageDonebyInt = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_INTELLECT);
4921 for(AuraList::const_iterator i = mDamageDonebyInt.begin();i != mDamageDonebyInt.end(); ++i)
4922 if ((*i)->GetModifier()->m_miscvalue & 1 << spellProto->School)
4923 DoneAdvertisedBenefit += int32(GetStat(STAT_INTELLECT) * (*i)->GetModifier()->m_amount / 100.0f);
4926 // ..taken
4927 AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
4928 for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
4929 if(((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0)
4930 TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount;
4932 // Damage over Time spells bonus calculation
4933 float DotFactor = 1.0f;
4934 if(damagetype == DOT)
4936 CastingTime = 3500;
4937 uint32 DotDuration = GetDuration(spellProto);
4938 // 200% limit
4939 if(DotDuration > 0)
4941 if(DotDuration > 30000) DotDuration = 30000;
4942 DotFactor = DotDuration / 15000.0f;
4943 int x = 0;
4944 for(int j = 0; j < 3; j++)
4945 if(spellProto->Effect[j] == 6) x = j;
4946 int DotTicks = 6;
4947 if(spellProto->EffectAmplitude[x] != 0)
4948 DotTicks = DotDuration / spellProto->EffectAmplitude[x];
4949 if(DotTicks)
4951 DoneAdvertisedBenefit /= DotTicks;
4952 TakenAdvertisedBenefit /= DotTicks;
4957 // Taken/Done total percent damage auras
4958 float DoneTotalMod = 1.0f;
4959 float TakenTotalMod = 1.0f;
4961 // ..done
4962 AuraList const& mModDamagePercentDone = this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
4963 for(AuraList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
4964 if( spellProto->School != 0 && ((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0 &&
4965 (*i)->GetSpellProto()->EquippedItemClass == -1 &&
4966 // -1 == any item class (not wand then)
4967 (*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 )
4968 // 0 == any inventory type (not wand then)
4969 DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
4971 // ..taken
4972 AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
4973 for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
4974 if( spellProto->School != 0 && ((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0 )
4975 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
4977 // Exceptions
4978 // Lifetap
4979 if(spellProto->SpellVisual == 1225 && spellProto->SpellIconID == 208)
4981 CastingTime = 2800; // 80% from +shadow damage
4982 DoneTotalMod = 1.0f;
4983 TakenTotalMod = 1.0f;
4985 // Dark Pact
4986 if(spellProto->SpellVisual == 827 && spellProto->SpellIconID == 154 && GetPet())
4988 CastingTime = 3360; // 96% from +shadow damage
4989 DoneTotalMod = 1.0f;
4990 TakenTotalMod = 1.0f;
4992 // Ice Lance
4993 if(spellProto->Id == 30455)
4995 CastingTime /= 3.0f; // applied 1/3 bonuses in case generic target
4996 if(pVictim->isFrozen()) // and compensate this for frozen target.
4997 TakenTotalMod *= 3.0f;
5000 // Level Factor
5001 float LvlPenalty = 0.0f;
5002 if(spellProto->spellLevel < 20)
5003 LvlPenalty = (20.0f - (float)(spellProto->spellLevel)) * 3.75f;
5004 float LvlFactor = ((float)(spellProto->spellLevel) + 6.0f) / (float)(getLevel());
5005 if(LvlFactor > 1.0f)
5006 LvlFactor = 1.0f;
5008 // Spellmod SpellDamage
5009 float SpellModSpellDamage = 100.0f;
5010 if (GetTypeId() == TYPEID_PLAYER)
5011 ((Player*)this)->ApplySpellMod(spellProto->Id,SPELLMOD_SPELL_DAMAGE,SpellModSpellDamage);
5012 SpellModSpellDamage /= 100.0f;
5014 float DoneActualBenefit = DoneAdvertisedBenefit * (CastingTime / 3500.0f) * (100.0f - LvlPenalty) * LvlFactor * DotFactor * SpellModSpellDamage / 100.0f;
5015 float TakenActualBenefit = TakenAdvertisedBenefit * (CastingTime / 3500.0f) * (100.0f - LvlPenalty) * LvlFactor * DotFactor / 100.0f;
5017 float tmpDamage = (float(pdamage)+DoneActualBenefit)*DoneTotalMod;
5018 tmpDamage = (tmpDamage+TakenActualBenefit)*TakenTotalMod;
5020 return tmpDamage > 0 ? uint32(tmpDamage) : 0;
5023 bool Unit::SpellCriticalBonus(SpellEntry const *spellProto, int32 *peffect, Unit *pVictim)
5025 // Chance to crit is computed from INT and LEVEL as follows:
5026 // chance = base + INT / (rate0 + rate1 * LEVEL)
5027 // The formula keeps the crit chance at %5 on every level unless the player
5028 // increases his intelligence by other means (enchants, buffs, talents, ...)
5029 if(spellProto->Id == 15290 || spellProto->Id == 39373) return false;
5031 float crit_chance = 0.0f;
5033 // base value
5034 if (GetTypeId() != TYPEID_PLAYER)
5036 // flat done
5037 // TODO: can creatures have critical chance auras?
5038 crit_chance = m_baseSpellCritChance;
5039 AuraList const& mSpellCritSchool = GetAurasByType(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL);
5040 for(AuraList::const_iterator i = mSpellCritSchool.begin(); i != mSpellCritSchool.end(); ++i)
5041 if((*i)->GetModifier()->m_miscvalue == -2 || ((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0)
5042 crit_chance += (*i)->GetModifier()->m_amount;
5044 else
5045 crit_chance = GetFloatValue( PLAYER_SPELL_CRIT_PERCENTAGE1 + spellProto->School);
5047 // percent done
5048 // only players use intelligence for critical chance computations
5049 if (GetTypeId() == TYPEID_PLAYER)
5051 ((Player*)this)->ApplySpellMod(spellProto->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance);
5054 // taken
5055 if (pVictim)
5057 // flat
5058 AuraList const& mAttackerSpellCrit = pVictim->GetAurasByType(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE);
5059 for(AuraList::const_iterator i = mAttackerSpellCrit.begin(); i != mAttackerSpellCrit.end(); ++i)
5060 if((*i)->GetModifier()->m_miscvalue == -2 || ((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0)
5061 crit_chance += (*i)->GetModifier()->m_amount;
5063 // flat: Resilience - reduce crit chance by x%
5064 crit_chance -= pVictim->m_modResilience;
5066 // flat: scripted (increase crit chance ... against ... target by x%
5067 AuraList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
5068 for(AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
5070 switch((*i)->GetModifier()->m_miscvalue)
5072 //Shatter Rank 1
5073 case 849: if(pVictim->isFrozen()) crit_chance+= 10; break;
5074 //Shatter Rank 2
5075 case 910: if(pVictim->isFrozen()) crit_chance+= 20; break;
5076 //Shatter Rank 3
5077 case 911: if(pVictim->isFrozen()) crit_chance+= 30; break;
5078 //Shatter Rank 4
5079 case 912: if(pVictim->isFrozen()) crit_chance+= 40; break;
5080 //Shatter Rank 5
5081 case 913: if(pVictim->isFrozen()) crit_chance+= 50; break;
5085 // flat
5086 AuraList const& mAttackerSWCrit = pVictim->GetAurasByType(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
5087 for(AuraList::const_iterator i = mAttackerSWCrit.begin(); i != mAttackerSWCrit.end(); ++i)
5088 crit_chance += (*i)->GetModifier()->m_amount;
5091 crit_chance = crit_chance > 0.0 ? crit_chance : 0.0;
5092 if (roll_chance_f(crit_chance))
5094 int32 crit_bonus = *peffect / 2;
5095 if (GetTypeId() == TYPEID_PLAYER) // adds additional damage to crit_bonus (from talents)
5096 ((Player*)this)->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
5098 *peffect += crit_bonus;
5099 // Resilience - reduce crit damage by 2x%
5100 if (pVictim)
5101 *peffect -= int32(pVictim->m_modResilience * 2/100 * (*peffect));
5103 return true;
5105 return false;
5108 uint32 Unit::SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, Unit *pVictim)
5110 // Healing Done
5112 // Vampiric Embrace, Shadowmend - cannot critically heal
5113 if(spellProto->Id == 15290 || spellProto->Id == 39373) return healamount;
5115 int32 AdvertisedBenefit = 0;
5116 uint32 CastingTime = GetCastTime(sCastTimesStore.LookupEntry(spellProto->CastingTimeIndex));
5117 if (CastingTime > 7000) CastingTime = 7000;
5118 if (CastingTime < 1500) CastingTime = 1500;
5119 if (spellProto->Effect[0] == SPELL_EFFECT_APPLY_AURA) CastingTime = 3500;
5121 AuraList const& mHealingDone = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE);
5122 for(AuraList::const_iterator i = mHealingDone.begin();i != mHealingDone.end(); ++i)
5123 if(((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0)
5124 AdvertisedBenefit += (*i)->GetModifier()->m_amount;
5126 // Healing bonus of spirit, intellect and strength
5127 if (GetTypeId() == TYPEID_PLAYER)
5129 AdvertisedBenefit += int32(GetStat(STAT_SPIRIT) * GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HEALING_OF_SPIRIT) / 100.0f);
5130 AdvertisedBenefit += int32(GetStat(STAT_INTELLECT) * GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HEALING_OF_INTELLECT) / 100.0f);
5131 AdvertisedBenefit += int32(GetStat(STAT_STRENGTH) * GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HEALING_OF_STRENGTH) / 100.0f);
5134 // Healing Taken
5135 AdvertisedBenefit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_HEALING);
5137 //BoL dummy effects
5138 if (spellProto->SpellFamilyName == SPELLFAMILY_PALADIN && (spellProto->SpellFamilyFlags & 0xC0000000))
5140 AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
5141 for(AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
5142 if((*i)->GetSpellProto()->SpellVisual == 9180)
5143 //FoL
5144 if ((spellProto->SpellFamilyFlags & 0x40000000) && (*i)->GetEffIndex() == 1)
5145 AdvertisedBenefit += (*i)->GetModifier()->m_amount;
5146 //HL
5147 else if ((spellProto->SpellFamilyFlags & 0x80000000) && (*i)->GetEffIndex() == 0)
5148 AdvertisedBenefit += (*i)->GetModifier()->m_amount;
5151 // Healing over Time spells
5152 float DotFactor = 1.0f;
5153 if(damagetype == DOT)
5155 CastingTime = 3500;
5156 uint32 DotDuration = GetDuration(spellProto);
5157 // 200% limit
5158 if(DotDuration > 30000) DotDuration = 30000;
5159 DotFactor = DotDuration / 15000.0f;
5160 int x = 0;
5161 for(int j = 0; j < 3; j++)
5162 if(spellProto->Effect[j] == 6) x = j;
5163 int DotTicks = 6;
5164 if(spellProto->EffectAmplitude[x] != 0)
5165 DotTicks = DotDuration / spellProto->EffectAmplitude[x];
5166 if(DotTicks)
5167 AdvertisedBenefit /= DotTicks;
5170 // Level Factor
5171 float LvlPenalty = 0.0f;
5172 if(spellProto->spellLevel < 20)
5173 LvlPenalty = (20.0f - (float)(spellProto->spellLevel)) * 3.75f;
5174 float LvlFactor = ((float)(spellProto->spellLevel) + 6.0f) / (float)(getLevel());
5175 if(LvlFactor > 1.0f)
5176 LvlFactor = 1.0f;
5178 float ActualBenefit = (float)AdvertisedBenefit * ((float)CastingTime / 3500.0f) * (100.0f - LvlPenalty) * LvlFactor * DotFactor / 100.0f;
5180 // use float as more appropriate for negative values and percent applying
5181 float heal = healamount + ActualBenefit;
5183 // TODO: check for ALL/SPELLS type
5184 // Healing done percent
5185 AuraList const& mHealingDonePct = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT);
5186 for(AuraList::const_iterator i = mHealingDonePct.begin();i != mHealingDonePct.end(); ++i)
5187 heal *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f;
5189 // Healing taken percent
5190 AuraList const& mHealingPct = pVictim->GetAurasByType(SPELL_AURA_MOD_HEALING_PCT);
5191 for(AuraList::const_iterator i = mHealingPct.begin();i != mHealingPct.end(); ++i)
5192 heal *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f;
5194 if (heal < 0) heal = 0;
5196 return uint32(heal);
5199 bool Unit::IsImmunedToPhysicalDamage() const
5201 //If m_immuneToDamage type contain magic, IMMUNE damage.
5202 SpellImmuneList const& damageImmList = m_spellImmune[IMMUNITY_DAMAGE];
5203 for (SpellImmuneList::const_iterator itr = damageImmList.begin(); itr != damageImmList.end(); ++itr)
5204 if(itr->type & IMMUNE_DAMAGE_PHYSICAL)
5205 return true;
5207 //If m_immuneToSchool type contain this school type, IMMUNE damage.
5208 SpellImmuneList const& spellImmList = m_spellImmune[IMMUNITY_SCHOOL];
5209 for (SpellImmuneList::const_iterator itr = spellImmList.begin(); itr != spellImmList.end(); ++itr)
5210 if(itr->type & IMMUNE_SCHOOL_PHYSICAL)
5211 return true;
5213 return false;
5216 bool Unit::IsImmunedToSpellDamage(SpellEntry const* spellInfo) const
5218 //If m_immuneToDamage type contain magic, IMMUNE damage.
5219 SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
5220 for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
5221 if(itr->type & uint32(1<<spellInfo->School))
5222 return true;
5224 //If m_immuneToSchool type contain this school type, IMMUNE damage.
5225 SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
5226 for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
5227 if(itr->type & uint32(1<<spellInfo->School))
5228 return true;
5230 return false;
5233 bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo) const
5235 if (!spellInfo)
5236 return false;
5238 SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL];
5239 for(SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr)
5240 if(itr->type == spellInfo->Dispel)
5241 return true;
5243 SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
5244 for(SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
5245 if(itr->type == spellInfo->Mechanic)
5246 return true;
5248 int32 chance = 0;
5249 AuraList const& mModMechanicRes = GetAurasByType(SPELL_AURA_MOD_MECHANIC_RESISTANCE);
5250 for(AuraList::const_iterator i = mModMechanicRes.begin();i != mModMechanicRes.end(); ++i)
5251 if((*i)->GetModifier()->m_miscvalue == int32(spellInfo->Mechanic))
5252 chance+= (*i)->GetModifier()->m_amount;
5253 if(roll_chance_i(chance))
5254 return true;
5256 return false;
5259 bool Unit::IsImmunedToSpellEffect(uint32 effect) const
5261 //If m_immuneToEffect type contain this effect type, IMMUNE effect.
5262 SpellImmuneList const& effectList = m_spellImmune[IMMUNITY_EFFECT];
5263 for (SpellImmuneList::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr)
5264 if(itr->type == effect)
5265 return true;
5267 return false;
5270 bool Unit::IsDamageToThreatSpell(SpellEntry const * spellInfo) const
5272 if(!spellInfo)
5273 return false;
5275 uint32 family = spellInfo->SpellFamilyName;
5276 uint32 flags = spellInfo->SpellFamilyFlags;
5278 if((family == 5 && flags == 256) || //Searing Pain
5279 (family == 6 && flags == 8192) || //Mind Blast
5280 (family == 11 && flags == 1048576)) //Earth Shock
5281 return true;
5283 return false;
5286 void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attType)
5288 if(!pVictim) return;
5290 if(*pdamage == 0)
5291 return;
5293 uint32 creatureTypeMask = GetCreatureTypeMask();
5295 if(GetTypeId() != TYPEID_PLAYER && ((Creature*)this)->isPet())
5297 if(getPowerType() == POWER_FOCUS)
5299 uint32 happiness = GetPower(POWER_HAPPINESS);
5300 if(happiness>=666000)
5301 *pdamage = uint32(*pdamage * 1.25);
5302 else if(happiness<333000)
5303 *pdamage = uint32(*pdamage * 0.75);
5304 else *pdamage = uint32(*pdamage * 1.0);
5308 // Taken/Done fixed damage bonus auras
5309 int32 DoneFlatBenefit = 0;
5310 int32 TakenFlatBenefit = 0;
5312 // ..done (for creature type by mask) in taken
5313 AuraList const& mDamageDoneCreature = this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
5314 for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
5315 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
5316 DoneFlatBenefit += (*i)->GetModifier()->m_amount;
5318 // ..done
5319 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
5321 // ..done (base at attack power and creature type)
5322 AuraList const& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_CREATURE_ATTACK_POWER);
5323 for(AuraList::const_iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i)
5324 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
5325 DoneFlatBenefit += int32((*i)->GetModifier()->m_amount/14.0f * GetAttackTime(attType)/1000);
5327 // ..done (base at attack power for marked target)
5328 if(attType == RANGED_ATTACK)
5330 AuraList const& mRangedAttackPowerAttackerBonus = pVictim->GetAurasByType(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS);
5331 for(AuraList::const_iterator i = mRangedAttackPowerAttackerBonus.begin();i != mRangedAttackPowerAttackerBonus.end(); ++i)
5332 DoneFlatBenefit += int32((*i)->GetModifier()->m_amount/14.0f * GetAttackTime(RANGED_ATTACK)/1000);
5335 // ..taken
5336 AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
5337 for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
5338 if((*i)->GetModifier()->m_miscvalue & IMMUNE_SCHOOL_PHYSICAL)
5339 TakenFlatBenefit += (*i)->GetModifier()->m_amount;
5341 if(attType!=RANGED_ATTACK)
5343 AuraList const& mModMeleeDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN);
5344 for(AuraList::const_iterator i = mModMeleeDamageTaken.begin(); i != mModMeleeDamageTaken.end(); ++i)
5345 TakenFlatBenefit += (*i)->GetModifier()->m_amount;
5347 else
5349 AuraList const& mModRangedDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN);
5350 for(AuraList::const_iterator i = mModRangedDamageTaken.begin(); i != mModRangedDamageTaken.end(); ++i)
5351 TakenFlatBenefit += (*i)->GetModifier()->m_amount;
5354 // Done/Taken total percent damage auras
5355 float TakenTotalMod = 1;
5357 // ..done
5358 // SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage
5359 // SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage
5361 // ..taken
5362 AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
5363 for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
5364 if((*i)->GetModifier()->m_miscvalue & IMMUNE_SCHOOL_PHYSICAL)
5365 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
5367 if(attType != RANGED_ATTACK)
5369 AuraList const& mModMeleeDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT);
5370 for(AuraList::const_iterator i = mModMeleeDamageTakenPercent.begin(); i != mModMeleeDamageTakenPercent.end(); ++i)
5371 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
5373 else
5375 AuraList const& mModRangedDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT);
5376 for(AuraList::const_iterator i = mModRangedDamageTakenPercent.begin(); i != mModRangedDamageTakenPercent.end(); ++i)
5377 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
5380 float tmpDamage = ((int32(*pdamage) + DoneFlatBenefit) + TakenFlatBenefit)*TakenTotalMod;
5382 // bonus result can be negative
5383 *pdamage = tmpDamage > 0 ? uint32(tmpDamage) : 0;
5386 void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply)
5388 if (apply)
5390 for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(), next; itr != m_spellImmune[op].end(); itr = next)
5392 next = itr; next++;
5393 if(itr->type == type)
5395 m_spellImmune[op].erase(itr);
5396 next = m_spellImmune[op].begin();
5399 SpellImmune Immune;
5400 Immune.spellId = spellId;
5401 Immune.type = type;
5402 m_spellImmune[op].push_back(Immune);
5404 else
5406 for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(); itr != m_spellImmune[op].end(); ++itr)
5408 if(itr->spellId == spellId)
5410 m_spellImmune[op].erase(itr);
5411 break;
5418 float Unit::GetWeaponProcChance() const
5420 // normalized proc chance for weapon attack speed
5421 // (odd formulae...)
5422 if(isAttackReady(BASE_ATTACK))
5423 return (GetAttackTime(BASE_ATTACK) * 1.8f / 1000.0f);
5424 else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK))
5425 return (GetAttackTime(OFF_ATTACK) * 1.6f / 1000.0f);
5426 return 0;
5429 float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM) const
5431 // proc per minute chance calculation
5432 if (PPM <= 0) return 0.0f;
5433 uint32 result = uint32((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
5434 return result;
5437 void Unit::Mount(uint32 mount, bool taxi)
5439 if(!mount)
5440 return;
5442 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, mount);
5444 uint32 flag = UNIT_FLAG_MOUNT;
5445 if(taxi)
5446 flag |= UNIT_FLAG_DISABLE_MOVE;
5448 SetFlag( UNIT_FIELD_FLAGS, flag );
5450 // unsummon pet
5451 if(GetTypeId() == TYPEID_PLAYER)
5453 Pet* pet = GetPet();
5454 if(pet)
5456 if(pet->getPetType() == SUMMON_PET || pet->getPetType() == HUNTER_PET)
5458 ((Player*)this)->SetOldPetNumber(pet->GetCharmInfo()->GetPetNumber());
5459 ((Player*)this)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL));
5462 ((Player*)this)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT);
5464 else
5465 ((Player*)this)->SetOldPetNumber(0);
5469 void Unit::Unmount()
5471 if(!IsMounted())
5472 return;
5474 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0);
5475 RemoveFlag( UNIT_FIELD_FLAGS ,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_MOUNT );
5477 if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->GetOldPetNumber() && isAlive())
5479 Pet* NewPet = new Pet(this);
5480 if(!NewPet->LoadPetFromDB(this, 0, ((Player*)this)->GetOldPetNumber(), true))
5481 delete NewPet;
5483 ((Player*)this)->SetOldPetNumber(0);
5487 void Unit::SetInCombat()
5489 m_CombatTimer = 5000;
5490 SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
5492 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet()))
5493 SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
5496 void Unit::ClearInCombat(bool force)
5498 // wait aura and combat timer expire
5499 if(!force && HasAuraType(SPELL_AURA_INTERRUPT_REGEN))
5500 return;
5502 m_CombatTimer = 0;
5503 RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
5505 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet()))
5506 RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
5508 // remove combo points
5509 if(GetTypeId()==TYPEID_PLAYER)
5510 ((Player*)this)->ClearComboPoints();
5513 bool Unit::isTargetableForAttack()
5515 if (GetTypeId()==TYPEID_PLAYER && ((Player *)this)->isGameMaster())
5516 return false;
5517 return isAlive() && !hasUnitState(UNIT_STAT_DIED)&& !isInFlight() /*&& !isStealth()*/;
5520 int32 Unit::ModifyHealth(int32 dVal)
5522 int32 gain = 0;
5524 if(dVal==0)
5525 return 0;
5527 int32 curHealth = (int32)GetHealth();
5529 int32 val = dVal + curHealth;
5530 if(val <= 0)
5532 SetHealth(0);
5533 return -curHealth;
5536 int32 maxHealth = (int32)GetMaxHealth();
5538 if(val < maxHealth)
5540 SetHealth(val);
5541 gain = val - curHealth;
5543 else if(curHealth != maxHealth)
5545 SetHealth(maxHealth);
5546 gain = maxHealth - curHealth;
5549 return gain;
5552 int32 Unit::ModifyPower(Powers power, int32 dVal)
5554 int32 gain = 0;
5556 if(dVal==0)
5557 return 0;
5559 int32 curPower = (int32)GetPower(power);
5561 int32 val = dVal + curPower;
5562 if(val <= 0)
5564 SetPower(power,0);
5565 return -curPower;
5568 int32 maxPower = (int32)GetMaxPower(power);
5570 if(val < maxPower)
5572 SetPower(power,val);
5573 gain = val - curPower;
5575 else if(curPower != maxPower)
5577 SetPower(power,maxPower);
5578 gain = maxPower - curPower;
5581 return gain;
5584 bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList) const
5586 if(!u)
5587 return false;
5589 // Always can see self
5590 if (u==this)
5591 return true;
5593 // player visible for other player if not logout and at same transport
5594 // including case when player is out of world
5595 bool at_same_transport =
5596 GetTypeId() == TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER &&
5597 !((Player*)this)->GetSession()->PlayerLogout() && !((Player*)u)->GetSession()->PlayerLogout() &&
5598 !((Player*)this)->GetSession()->PlayerLoading() && !((Player*)u)->GetSession()->PlayerLoading() &&
5599 ((Player*)this)->GetTransport() && ((Player*)this)->GetTransport() == ((Player*)u)->GetTransport();
5601 // not in world
5602 if(!at_same_transport && (!IsInWorld() || !u->IsInWorld()))
5603 return false;
5605 // always seen by owner
5606 if(GetCharmerOrOwnerGUID()==u->GetGUID())
5607 return true;
5609 // Grid dead/alive checks
5610 if( u->GetTypeId()==TYPEID_PLAYER)
5612 // non visible at grid for any stealth state
5613 if(!IsVisibleInGridForPlayer((Player *)u))
5614 return false;
5616 // if player is dead then he can't detect anyone in anycases
5617 if(!u->isAlive())
5618 detect = false;
5620 else
5622 // all dead creatures/players not visible for any creatures
5623 if(!u->isAlive() || !isAlive())
5624 return false;
5627 // different visible distance checks
5628 if(u->isInFlight()) // what see player in flight
5630 // use object grey distance for all (only see objects any way)
5631 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceInFlight()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f)))
5632 return false;
5634 else if(!isAlive()) // distance for show body
5636 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f)))
5637 return false;
5639 else if(GetTypeId()==TYPEID_PLAYER) // distance for show player
5641 if(u->GetTypeId()==TYPEID_PLAYER)
5643 // Players far than max visible distance for player or not in our map are not visible too
5644 if (!at_same_transport && !IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))
5645 return false;
5647 else
5649 // Units far than max visible distance for creature or not in our map are not visible too
5650 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))
5651 return false;
5654 else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed
5656 // Pet/charmed far than max visible distance for player or not in our map are not visible too
5657 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))
5658 return false;
5660 else // distance for show creature
5662 // Units far than max visible distance for creature or not in our map are not visible too
5663 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))
5664 return false;
5667 // Visible units, always are visible for all units, except for units under invisibility
5668 if (m_Visibility == VISIBILITY_ON && u->GetVisibility()!= VISIBILITY_GROUP_INVISIBILITY)
5669 return true;
5671 // GMs are visible for higher gms (or players are visible for gms)
5672 if (u->GetTypeId() == TYPEID_PLAYER && ((Player *)u)->isGameMaster())
5673 return (GetTypeId() == TYPEID_PLAYER && ((Player *)this)->GetSession()->GetSecurity() <= ((Player *)u)->GetSession()->GetSecurity());
5675 // non faction visibility non-breakable for non-GMs
5676 if (m_Visibility == VISIBILITY_OFF)
5677 return false;
5679 // Invisible units, always are visible for units under invisibility or unit that can detect this invisibility
5680 if (m_Visibility == VISIBILITY_GROUP_INVISIBILITY)
5682 if(u->GetVisibility()== VISIBILITY_GROUP_INVISIBILITY || m_invisibilityvalue <= u->m_detectInvisibility)
5683 return true;
5686 // Units that can detect invisibility always are visible for units that can be detected
5687 if (u->GetVisibility()== VISIBILITY_GROUP_INVISIBILITY)
5689 if(m_detectInvisibility >= u->m_invisibilityvalue)
5690 return true;
5693 // Stealth/invisible not hostile units, not visible (except Player-with-Player case)
5694 if (!u->IsHostileTo(this))
5696 // 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)
5697 if(GetTypeId()==TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER)
5699 if(((Player*)this)->IsGroupVisibleFor(((Player*)u)))
5700 return true;
5702 // else apply same rules as for hostile case (detecting check)
5705 else
5707 // Hunter mark functionality
5708 AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_STALKED);
5709 for(AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
5710 if((*iter)->GetCasterGUID()==u->GetGUID())
5711 return true;
5714 // unit got in stealth in this moment and must ignore old detected state
5715 // invisibility not have chance for detection
5716 if (m_Visibility == VISIBILITY_ON || m_Visibility == VISIBILITY_GROUP_NO_DETECT || m_Visibility == VISIBILITY_GROUP_INVISIBILITY)
5717 return false;
5719 // NOW ONLY STEALTH CASE
5721 // stealth and detected
5722 if (u->GetTypeId() == TYPEID_PLAYER && ((Player*)u)->HaveAtClient(this) )
5723 return true;
5725 //if in non-detect mode then invisible for unit
5726 if (!detect)
5727 return false;
5729 // Special cases
5730 bool IsVisible = true;
5731 bool isInFront = u->isInFront(this,World::GetMaxVisibleDistanceForObject());
5732 float distance = sqrt(GetDistanceSq(u));
5734 // If is attacked then stealth is lost, some creature can use stealth too
5735 if (this->isAttacked())
5736 return IsVisible;
5738 // If there is collision rogue is seen regardless of level difference
5739 // TODO: check sizes in DB
5740 if (distance < 0.24f)
5741 return IsVisible;
5743 //If a mob or player is stunned he will not be able to detect stealth
5744 if ((u->hasUnitState(UNIT_STAT_STUNDED)) && (u != this))
5746 IsVisible=false;
5747 return IsVisible;
5750 // Cases based on level difference and position
5751 int32 levelDiff = u->getLevel() - this->getLevel();
5753 //If mob is 5 levels more than player he gets detected automaticly
5754 if (u->GetTypeId()!=TYPEID_PLAYER && levelDiff > 5)
5755 return IsVisible;
5757 // If victim has more than 5 lvls above caster
5758 if ((this->GetTypeId() == TYPEID_UNIT)&& ( levelDiff > 5 ))
5759 return IsVisible;
5761 // If caster has more than 5 levels above victim
5762 if ((this->GetTypeId() == TYPEID_UNIT)&& ( levelDiff < -5 ))
5764 IsVisible=false;
5765 return IsVisible;
5768 float modifier = 1; // 100 pct
5769 float pvpMultiplier = 0;
5770 float distanceFormula = 0;
5771 int32 rank = 0;
5772 //This allows to check talent tree and will add addition stealth dependant on used points)
5773 uint32 stealthMod = GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL);
5774 //****************************************************************************************
5775 // Stealth detection calculation
5776 int32 x = (((u->m_detectStealth+1) / 5) - (((m_stealthvalue+1) / 5) + (stealthMod/5) + 59));
5778 if (x<0) x = 1;
5779 // Check rank if mob is not a player otherwise rank = 1 and there is no modifier when in pvp
5780 if (u->GetTypeId() != TYPEID_PLAYER)
5781 rank = ((Creature const*)u)->GetCreatureInfo()->rank;
5783 // Probabilty of being seen
5784 if (levelDiff < 0)
5785 distanceFormula = ((sWorld.getRate(RATE_CREATURE_AGGRO) * 16) / (abs(levelDiff) + 1.5)) * 2;
5786 if (levelDiff >= 0)
5787 distanceFormula = (((sWorld.getRate(RATE_CREATURE_AGGRO) * 16)) / 2) * (levelDiff + 1);
5789 // Original probability values
5790 // removed level of mob in calculation as it should not affect the detection, it is mainly dependant on level difference
5791 //at this distance, the detector has to be a 15% prob of detect
5792 float averageDist = 1 - 0.11016949 * x + 0.00301637 * x * x;
5793 if (averageDist < 1) averageDist = 1;
5795 float prob = 0;
5796 if (distance > averageDist)
5797 //prob between 10% and 0%
5798 prob = (averageDist - 200 + 9 * distance) / (averageDist - 20);
5799 else
5800 prob = 75 - (60 / averageDist) * distance; //prob between 15% and 75% (75% max prob)
5802 // If is not in front, probability floor
5803 if (!isInFront)
5804 prob = prob / 100;
5805 if (prob < 0.1)
5806 prob = 0.1;
5808 // Mob rank affects modifier
5809 modifier = rank <= 4 ? 1 + rank * 0.2f : 1;
5811 if (distance < 0.24f)
5813 return IsVisible;
5816 // PVP distance assigned depending on level
5817 if (this->GetTypeId() == TYPEID_UNIT)
5819 // Level diff floor/ceiling <-5,5>
5820 pvpMultiplier = levelDiff > 5 ? 12 : levelDiff < 5 ? 2 : 7 + levelDiff;
5821 pvpMultiplier = pvpMultiplier - (x / 100);
5824 // PVP stealth handler
5825 if (this->GetTypeId() == TYPEID_PLAYER)
5827 // Do not loose stealth when coming from back
5828 if (!isInFront)
5830 IsVisible=false;
5831 return IsVisible;
5834 // If comes in front
5835 if (isInFront && (distance >= pvpMultiplier))
5837 IsVisible=false;
5838 return IsVisible;
5841 if (isInFront && (distance < pvpMultiplier))
5843 return IsVisible;
5846 else
5848 // PVE stealth handler
5849 // Distance of approch player stays stealth 100% is dependant of level. No probabiliy or detection is rolled
5850 // This establishes a buffer zone in between mob start to see you and mob start to roll probabilities or detect you
5851 if ((distance < 100) && (distance > ((distanceFormula * 2) * modifier)) && (distance > 0.24f))
5853 IsVisible=false;
5854 return IsVisible;
5857 //If victim is level lower or more probability of detection drops
5858 if ((levelDiff < 0) && (distance > 0.24f))
5860 if (abs(levelDiff ) > 4)
5861 IsVisible = false;
5862 else
5864 if (rand_chance() > ( prob * modifier / (30 + levelDiff * 5)))
5865 IsVisible = false;
5867 return IsVisible;
5869 // Level detection based on level, the higher the mob level the higher the chance of detection.
5870 if ((distance > 0.24f) && (levelDiff < 5) && (levelDiff >= 0))
5872 if (rand_chance() > ((prob * modifier) / (30 - levelDiff * 5) ))
5873 IsVisible = false;
5874 else
5875 IsVisible = true;
5877 return IsVisible;
5881 // Didn't match any criteria ?
5882 DEBUG_LOG("Unit::isVisibleForFor unhandled result, dist %f levelDiff %i target_type %u prob %u modifier %u",distance,levelDiff,u->GetTypeId(),prob, modifier);
5884 // Safety return
5885 return IsVisible;
5888 void Unit::SetVisibility(UnitVisibility x)
5890 m_Visibility = x;
5892 if(IsInWorld())
5894 Map *m = MapManager::Instance().GetMap(GetMapId(), this);
5896 if(GetTypeId()==TYPEID_PLAYER)
5897 m->PlayerRelocation((Player*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
5898 else
5899 m->CreatureRelocation((Creature*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
5903 float Unit::GetSpeed( UnitMoveType mtype ) const
5905 return m_speed_rate[mtype]*baseMoveSpeed[mtype];
5908 void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced)
5910 m_speed_rate[mtype] = 1.0f;
5911 ApplySpeedMod(mtype, rate, forced, true);
5914 void Unit::ApplySpeedMod(UnitMoveType mtype, float rate, bool forced, bool apply)
5916 WorldPacket data;
5918 if(apply)
5919 m_speed_rate[mtype] *= rate;
5920 else
5921 m_speed_rate[mtype] /= rate;
5923 switch(mtype)
5925 case MOVE_WALK:
5926 if(forced) { data.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE, 16); }
5927 else { data.Initialize(MSG_MOVE_SET_WALK_SPEED, 16); }
5928 break;
5929 case MOVE_RUN:
5930 if(forced) { data.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE, 16); }
5931 else { data.Initialize(MSG_MOVE_SET_RUN_SPEED, 16); }
5932 break;
5933 case MOVE_WALKBACK:
5934 if(forced) { data.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE, 16); }
5935 else { data.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED, 16); }
5936 break;
5937 case MOVE_SWIM:
5938 if(forced) { data.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE, 16); }
5939 else { data.Initialize(MSG_MOVE_SET_SWIM_SPEED, 16); }
5940 break;
5941 case MOVE_SWIMBACK:
5942 if(forced) { data.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE, 16); }
5943 else { data.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED, 16); }
5944 break;
5945 case MOVE_TURN:
5946 if(forced) { data.Initialize(SMSG_FORCE_TURN_RATE_CHANGE, 16); }
5947 else { data.Initialize(MSG_MOVE_SET_TURN_RATE, 16); }
5948 break;
5949 case MOVE_FLY:
5950 if(forced) { data.Initialize(SMSG_FORCE_FLY_SPEED_CHANGE, 16); }
5951 else { data.Initialize(SMSG_MOVE_SET_FLY_SPEED, 16); }
5952 break;
5953 case MOVE_FLYBACK:
5954 break;
5955 default:
5956 sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype);
5957 return;
5960 data.append(GetPackGUID());
5961 data << (uint32)0;
5962 if (mtype == MOVE_RUN) data << uint8(0); // new 2.1.0
5963 data << float(GetSpeed(mtype));
5964 SendMessageToSet( &data, true );
5966 if(Pet* pet = GetPet())
5967 pet->SetSpeed(mtype,m_speed_rate[mtype],forced);
5970 void Unit::SetHover(bool on)
5972 if(on)
5973 CastSpell(this,11010,true);
5974 else
5975 RemoveAurasDueToSpell(11010);
5978 void Unit::setDeathState(DeathState s)
5980 if (s != ALIVE)
5982 CombatStop(true);
5984 if(IsNonMeleeSpellCasted(false))
5985 InterruptNonMeleeSpells(false);
5988 if (s == JUST_DIED)
5990 RemoveAllAurasOnDeath();
5991 UnsummonAllTotems();
5993 if (m_deathState != ALIVE && s == ALIVE)
5995 //_ApplyAllAuraMods();
5997 m_deathState = s;
6000 /*########################################
6001 ######## ########
6002 ######## AGGRO SYSTEM ########
6003 ######## ########
6004 ########################################*/
6005 bool Unit::CanHaveThreatList() const
6007 if(GetTypeId() == TYPEID_UNIT && !((Creature*)this)->isPet() && !((Creature*)this)->isTotem() )
6008 return true;
6009 else
6010 return false;
6013 //======================================================================
6015 float Unit::ApplyTotalThreatModifier(float threat, uint8 school)
6017 if(!HasAuraType(SPELL_AURA_MOD_THREAT))
6018 return threat;
6020 if(school >= MAX_SPELL_SCHOOL)
6021 return threat;
6023 return threat * m_threatModifier[school];
6026 //======================================================================
6028 void Unit::AddThreat(Unit* pVictim, float threat, uint8 school, SpellEntry const *threatSpell)
6030 // Only mobs can manage threat lists
6031 if(CanHaveThreatList())
6032 m_ThreatManager.addThreat(pVictim, threat, school, threatSpell);
6035 //======================================================================
6037 void Unit::DeleteThreatList()
6039 m_ThreatManager.clearReferences();
6042 //======================================================================
6044 void Unit::TauntApply(Unit* taunter)
6046 assert(GetTypeId()== TYPEID_UNIT);
6048 if(!taunter || (taunter->GetTypeId() == TYPEID_PLAYER && ((Player*)taunter)->isGameMaster()))
6049 return;
6051 if(!CanHaveThreatList())
6052 return;
6054 Unit *target = getVictim();
6055 if(target && target == taunter)
6056 return;
6058 SetInFront(taunter);
6059 if (((Creature*)this)->AI())
6060 ((Creature*)this)->AI()->AttackStart(taunter);
6062 m_ThreatManager.tauntApply(taunter);
6065 //======================================================================
6067 void Unit::TauntFadeOut(Unit *taunter)
6069 assert(GetTypeId()== TYPEID_UNIT);
6071 if(!taunter || (taunter->GetTypeId() == TYPEID_PLAYER && ((Player*)taunter)->isGameMaster()))
6072 return;
6074 if(!CanHaveThreatList())
6075 return;
6077 Unit *target = getVictim();
6078 if(!target || target != taunter)
6079 return;
6081 if(m_ThreatManager.isThreatListEmpty())
6083 if(((Creature*)this)->AI())
6084 ((Creature*)this)->AI()->EnterEvadeMode();
6085 return;
6088 m_ThreatManager.tauntFadeOut(taunter);
6089 target = m_ThreatManager.getHostilTarget();
6091 if (target && target != taunter)
6093 SetInFront(target);
6094 if (((Creature*)this)->AI())
6095 ((Creature*)this)->AI()->AttackStart(target);
6099 //======================================================================
6101 bool Unit::SelectHostilTarget()
6103 //function provides main threat functionality
6104 //next-victim-selection algorithm and evade mode are called
6105 //threat list sorting etc.
6107 assert(GetTypeId()== TYPEID_UNIT);
6108 Unit* target = NULL;
6110 //This function only useful once AI has been initilazied
6111 if (!((Creature*)this)->AI())
6112 return false;
6114 if(!m_ThreatManager.isThreatListEmpty())
6116 if(!HasAuraType(SPELL_AURA_MOD_TAUNT))
6118 target = m_ThreatManager.getHostilTarget();
6122 if(target)
6124 SetInFront(target);
6125 ((Creature*)this)->AI()->AttackStart(target);
6126 return true;
6129 if(isInCombat() && !HasAuraType(SPELL_AURA_MOD_TAUNT) && CanFreeMove() && m_attackers.empty())
6130 ((Creature*)this)->AI()->EnterEvadeMode();
6132 return false;
6135 //======================================================================
6136 //======================================================================
6137 //======================================================================
6139 void Unit::CalculateSpellDamageAndDuration(int32* damage, int32* duration, SpellEntry const* spellProto, uint8 effect_index, int32 effBasePoints)
6141 Player* unitPlayer = (GetTypeId() == TYPEID_PLAYER) ? (Player*)this : NULL;
6143 uint8 comboPoints = unitPlayer ? unitPlayer->GetComboPoints() : 0;
6144 bool needClearCombo = false;
6146 if(damage)
6148 int32 value = 0;
6149 uint32 level = 0;
6151 level = getLevel() - spellProto->spellLevel;
6152 if (level > spellProto->maxLevel && spellProto->maxLevel > 0)
6153 level = spellProto->maxLevel;
6155 float basePointsPerLevel = spellProto->EffectRealPointsPerLevel[effect_index];
6156 float randomPointsPerLevel = spellProto->EffectDicePerLevel[effect_index];
6157 int32 basePoints = int32(effBasePoints + level * basePointsPerLevel);
6158 int32 randomPoints = int32(spellProto->EffectDieSides[effect_index] + level * randomPointsPerLevel);
6159 float comboDamage = spellProto->EffectPointsPerComboPoint[effect_index];
6161 value = basePoints + rand32(spellProto->EffectBaseDice[effect_index], randomPoints);
6162 //random damage
6163 if(int32(spellProto->EffectBaseDice[effect_index]) != randomPoints && GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
6164 value += ((Pet*)this)->GetBonusDamage(); //bonus damage only on spells without fixed basePoints?)
6166 if(comboDamage != 0 && unitPlayer && m_attacking && (m_attacking->GetGUID() == unitPlayer->GetComboTarget()))
6168 value += (int32)(comboDamage * comboPoints);
6170 // Eviscerate
6171 if( spellProto->SpellIconID == 514 && spellProto->SpellFamilyName == SPELLFAMILY_ROGUE)
6172 value += (int32)(GetTotalAttackPowerValue(BASE_ATTACK) * comboPoints * 0.03);
6174 needClearCombo = true;
6177 if (GetTypeId() == TYPEID_PLAYER)
6179 ((Player *)this)->ApplySpellMod(spellProto->Id,SPELLMOD_ALL_EFFECTS, value);
6180 switch(effect_index)
6182 case 0:
6183 ((Player*)this)->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT1, value);
6184 break;
6185 case 1:
6186 ((Player*)this)->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT2, value);
6187 break;
6188 case 2:
6189 ((Player*)this)->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT3, value);
6190 break;
6193 ((Player*)this)->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, value);
6197 *damage = value;
6200 if(duration)
6202 int32 minduration = GetDuration(spellProto);
6203 int32 maxduration = GetMaxDuration(spellProto);
6205 if( minduration != -1 && minduration != maxduration )
6207 *duration = minduration + int32((maxduration - minduration) * comboPoints / 5);
6208 needClearCombo = true;
6210 else
6211 *duration = minduration;
6214 if(unitPlayer && needClearCombo)
6215 unitPlayer->SetComboPoints(unitPlayer->GetComboTarget(), 0);
6218 void Unit::AddDiminishing(DiminishingMechanics mech, uint32 hitTime, uint32 hitCount)
6220 m_Diminishing.push_back(DiminishingReturn(mech,hitTime,hitCount));
6223 DiminishingLevels Unit::GetDiminishing(DiminishingMechanics mech)
6225 for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
6227 if(i->Mechanic != mech) continue;
6228 if(!i->hitCount) return DIMINISHING_LEVEL_1;
6229 if(!i->hitTime) return DIMINISHING_LEVEL_1;
6230 // If last spell was casted more than 15 seconds ago - reset the count.
6231 if((getMSTime() - i->hitTime) > 15000)
6233 i->hitCount = DIMINISHING_LEVEL_1;
6234 return DIMINISHING_LEVEL_1;
6236 // or else increase the count.
6237 else
6239 if(i->hitCount > DIMINISHING_LEVEL_2)
6241 i->hitCount = DIMINISHING_LEVEL_IMMUNE;
6242 return DIMINISHING_LEVEL_IMMUNE;
6244 else return DiminishingLevels(i->hitCount);
6247 return DIMINISHING_LEVEL_1;
6250 void Unit::IncrDiminishing(DiminishingMechanics mech, uint32 duration)
6252 // Checking for existing in the table
6253 bool IsExist = false;
6254 for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
6256 if(i->Mechanic != mech)
6257 continue;
6259 IsExist = true;
6260 if(i->hitCount < DIMINISHING_LEVEL_IMMUNE)
6262 i->hitCount += 1;
6263 switch(i->hitCount)
6265 case DIMINISHING_LEVEL_2: i->hitTime = uint32(getMSTime() + duration); break;
6266 case DIMINISHING_LEVEL_3: i->hitTime = uint32(getMSTime() + duration*0.5); break;
6267 case DIMINISHING_LEVEL_IMMUNE: i->hitTime = uint32(getMSTime() + duration*0.25); break;
6268 default: break;
6271 break;
6274 if(!IsExist)
6275 AddDiminishing(mech,uint32(getMSTime() + duration),DIMINISHING_LEVEL_2);
6278 void Unit::UpdateDiminishingTime(DiminishingMechanics mech)
6280 // Checking for existing in the table
6281 bool IsExist = false;
6282 for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
6284 if(i->Mechanic != mech)
6285 continue;
6287 IsExist = true;
6288 i->hitTime = getMSTime();
6289 break;
6292 if(!IsExist)
6293 AddDiminishing(mech,getMSTime(),DIMINISHING_LEVEL_1);
6296 DiminishingMechanics Unit::Mechanic2DiminishingMechanics(uint32 mech)
6298 switch(mech)
6300 case MECHANIC_CHARM: case MECHANIC_FEAR: case MECHANIC_SLEEP:
6301 return DIMINISHING_MECHANIC_CHARM;
6302 case MECHANIC_CONFUSED: case MECHANIC_KNOCKOUT: case MECHANIC_POLYMORPH:
6303 return DIMINISHING_MECHANIC_CONFUSE;
6304 case MECHANIC_ROOT: case MECHANIC_FREEZE:
6305 return DIMINISHING_MECHANIC_ROOT;
6306 case MECHANIC_STUNDED:
6307 return DIMINISHING_MECHANIC_STUN;
6308 case MECHANIC_CHASE:
6309 return DIMINISHING_MECHANIC_SPEED;
6310 default:
6311 break;
6313 return DIMINISHING_NONE;
6316 float Unit::ApplyDiminishingToDuration(DiminishingMechanics mech, int32 duration,Unit* caster)
6318 if(duration == -1 || mech == DIMINISHING_NONE)
6319 return 1.0f;
6321 // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
6322 if(duration > 10000)
6324 // test pet/charm masters instead pets/charmeds
6325 Unit const* targetOwner = GetCharmerOrOwner();
6326 Unit const* casterOwner = caster->GetCharmerOrOwner();
6328 Unit const* target = targetOwner ? targetOwner : this;
6329 Unit const* source = casterOwner ? casterOwner : caster;
6331 if(target->GetTypeId() == TYPEID_PLAYER && source->GetTypeId() == TYPEID_PLAYER)
6332 duration = 10000;
6335 float mod = 1.0f;
6337 // Stun diminishing is applies to mobs too
6338 if(mech == DIMINISHING_MECHANIC_STUN || GetTypeId() == TYPEID_PLAYER)
6340 DiminishingLevels diminish = GetDiminishing(mech);
6341 switch(diminish)
6343 case DIMINISHING_LEVEL_1: IncrDiminishing(mech, duration); break;
6344 case DIMINISHING_LEVEL_2: IncrDiminishing(mech, duration); mod = 0.5f; break;
6345 case DIMINISHING_LEVEL_3: IncrDiminishing(mech, duration); mod = 0.25f; break;
6346 case DIMINISHING_LEVEL_IMMUNE: mod = 0.0f; break;
6347 default: break;
6351 return mod;
6354 Creature* Unit::SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime)
6356 TemporarySummon* pCreature = new TemporarySummon(this,this);
6358 pCreature->SetInstanceId(GetInstanceId());
6360 if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), GetMapId(), x, y, z, ang, id))
6362 delete pCreature;
6363 return NULL;
6366 pCreature->Summon(spwtype, despwtime);
6368 //return the creature therewith the summoner has access to it
6369 return pCreature;
6372 Unit* Unit::GetUnit(WorldObject& object, uint64 guid)
6374 return ObjectAccessor::Instance().GetUnit(object,guid);
6377 bool Unit::isVisibleForInState( Player const* u, bool inVisibleList ) const
6379 return isVisibleForOrDetect(u,false,inVisibleList);
6382 uint32 Unit::GetCreatureType() const
6384 if(GetTypeId() == TYPEID_PLAYER)
6386 switch(((Player const*)this)->m_form)
6388 case FORM_CAT:
6389 case FORM_TRAVEL:
6390 case FORM_AQUA:
6391 case FORM_BEAR:
6392 case FORM_DIREBEAR:
6393 case FORM_GHOSTWOLF:
6394 case FORM_SWIFT_FLIGHT:
6395 case FORM_FLIGHT:
6396 return CREATURE_TYPE_BEAST;
6397 case FORM_TREE:
6398 case FORM_SPIRITOFREDEMPTION:
6399 return CREATURE_TYPE_ELEMENTAL;
6400 case FORM_MOONKIN:
6401 default:
6402 return CREATURE_TYPE_HUMANOID;
6405 else
6406 return ((Creature*)this)->GetCreatureInfo()->type;
6409 /*#######################################
6410 ######## ########
6411 ######## STAT SYSTEM ########
6412 ######## ########
6413 #######################################*/
6415 bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, float amount, bool apply)
6417 if(unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END)
6419 sLog.outError("ERROR in HandleStatModifier(): nonexisted UnitMods or wrong UnitModifierType!");
6420 return false;
6423 float val = 1.0f;
6425 switch(modifierType)
6427 case BASE_VALUE:
6428 case TOTAL_VALUE:
6429 m_auraModifiersGroup[unitMod][modifierType] += apply ? amount : -amount;
6430 break;
6431 case BASE_PCT:
6432 case TOTAL_PCT:
6433 if(amount <= -100.0f) //small hack-fix for -100% modifiers
6434 amount = -200.0f;
6436 val = (100.0f + amount) / 100.0f;
6437 m_auraModifiersGroup[unitMod][modifierType] *= apply ? val : (1.0f/val);
6438 break;
6440 default:
6441 break;
6444 if(!CanModifyStats())
6445 return false;
6447 switch(unitMod)
6449 case UNIT_MOD_STAT_STRENGTH:
6450 case UNIT_MOD_STAT_AGILITY:
6451 case UNIT_MOD_STAT_STAMINA:
6452 case UNIT_MOD_STAT_INTELLECT:
6453 case UNIT_MOD_STAT_SPIRIT: UpdateStats(GetStatByAuraGroup(unitMod)); break;
6455 case UNIT_MOD_ARMOR: UpdateArmor(); break;
6456 case UNIT_MOD_HEALTH: UpdateMaxHealth(); break;
6458 case UNIT_MOD_MANA:
6459 case UNIT_MOD_RAGE:
6460 case UNIT_MOD_FOCUS:
6461 case UNIT_MOD_ENERGY:
6462 case UNIT_MOD_HAPPINESS: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod)); break;
6464 case UNIT_MOD_RESISTANCE_HOLY:
6465 case UNIT_MOD_RESISTANCE_FIRE:
6466 case UNIT_MOD_RESISTANCE_NATURE:
6467 case UNIT_MOD_RESISTANCE_FROST:
6468 case UNIT_MOD_RESISTANCE_SHADOW:
6469 case UNIT_MOD_RESISTANCE_ARCANE: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod)); break;
6471 case UNIT_MOD_ATTACK_POWER: UpdateAttackPowerAndDamage(); break;
6472 case UNIT_MOD_ATTACK_POWER_RANGED: UpdateAttackPowerAndDamage(true); break;
6474 case UNIT_MOD_DAMAGE_MAINHAND: UpdateDamagePhysical(BASE_ATTACK); break;
6475 case UNIT_MOD_DAMAGE_OFFHAND: UpdateDamagePhysical(OFF_ATTACK); break;
6476 case UNIT_MOD_DAMAGE_RANGED: UpdateDamagePhysical(RANGED_ATTACK); break;
6478 default:
6479 break;
6482 return true;
6485 float Unit::GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) const
6487 if( unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END)
6489 sLog.outError("ERROR: trial to access nonexisted modifier value from UnitMods!");
6490 return 0.0f;
6493 if(modifierType == TOTAL_PCT && m_auraModifiersGroup[unitMod][modifierType] <= 0.0f)
6494 return 0.0f;
6496 return m_auraModifiersGroup[unitMod][modifierType];
6499 float Unit::GetTotalStatValue(Stats stat) const
6501 UnitMods unitMod = UnitMods(UNIT_MOD_STAT_START + stat);
6503 if(m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f)
6504 return 0.0f;
6506 // value = ((base_value * base_pct) + total_value) * total_pct
6507 float value = m_auraModifiersGroup[unitMod][BASE_VALUE] + GetCreateStat(stat);
6508 value *= m_auraModifiersGroup[unitMod][BASE_PCT];
6509 value += m_auraModifiersGroup[unitMod][TOTAL_VALUE];
6510 value *= m_auraModifiersGroup[unitMod][TOTAL_PCT];
6512 return value;
6515 float Unit::GetTotalAuraModValue(UnitMods unitMod) const
6517 if(unitMod >= UNIT_MOD_END)
6519 sLog.outError("ERROR: trial to access nonexisted UnitMods in GetTotalAuraModValue()!");
6520 return 0.0f;
6523 if(m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f)
6524 return 0.0f;
6526 float value = m_auraModifiersGroup[unitMod][BASE_VALUE];
6527 value *= m_auraModifiersGroup[unitMod][BASE_PCT];
6528 value += m_auraModifiersGroup[unitMod][TOTAL_VALUE];
6529 value *= m_auraModifiersGroup[unitMod][TOTAL_PCT];
6531 return value;
6534 SpellSchools Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod) const
6536 SpellSchools school = SPELL_SCHOOL_NORMAL;
6538 switch(unitMod)
6540 case UNIT_MOD_RESISTANCE_HOLY: school = SPELL_SCHOOL_HOLY; break;
6541 case UNIT_MOD_RESISTANCE_FIRE: school = SPELL_SCHOOL_FIRE; break;
6542 case UNIT_MOD_RESISTANCE_NATURE: school = SPELL_SCHOOL_NATURE; break;
6543 case UNIT_MOD_RESISTANCE_FROST: school = SPELL_SCHOOL_FROST; break;
6544 case UNIT_MOD_RESISTANCE_SHADOW: school = SPELL_SCHOOL_SHADOW; break;
6545 case UNIT_MOD_RESISTANCE_ARCANE: school = SPELL_SCHOOL_ARCANE; break;
6547 default:
6548 break;
6551 return school;
6554 Stats Unit::GetStatByAuraGroup(UnitMods unitMod) const
6556 Stats stat = STAT_STRENGTH;
6558 switch(unitMod)
6560 case UNIT_MOD_STAT_STRENGTH: stat = STAT_STRENGTH; break;
6561 case UNIT_MOD_STAT_AGILITY: stat = STAT_AGILITY; break;
6562 case UNIT_MOD_STAT_STAMINA: stat = STAT_STAMINA; break;
6563 case UNIT_MOD_STAT_INTELLECT: stat = STAT_INTELLECT; break;
6564 case UNIT_MOD_STAT_SPIRIT: stat = STAT_SPIRIT; break;
6566 default:
6567 break;
6570 return stat;
6573 Powers Unit::GetPowerTypeByAuraGroup(UnitMods unitMod) const
6575 Powers power = POWER_MANA;
6577 switch(unitMod)
6579 case UNIT_MOD_MANA: power = POWER_MANA; break;
6580 case UNIT_MOD_RAGE: power = POWER_RAGE; break;
6581 case UNIT_MOD_FOCUS: power = POWER_FOCUS; break;
6582 case UNIT_MOD_ENERGY: power = POWER_ENERGY; break;
6583 case UNIT_MOD_HAPPINESS: power = POWER_HAPPINESS; break;
6585 default:
6586 break;
6589 return power;
6592 float Unit::GetTotalAttackPowerValue(WeaponAttackType attType) const
6594 UnitMods unitMod = (attType == RANGED_ATTACK) ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER;
6596 float val = GetTotalAuraModValue(unitMod);
6597 if(val < 0.0f)
6598 val = 0.0f;
6600 return val;
6603 float Unit::GetWeaponDamageRange(WeaponAttackType attType ,WeaponDamageRange type) const
6605 if (attType == OFF_ATTACK && !haveOffhandWeapon())
6606 return 0.0f;
6608 return m_weaponDamage[attType][type];
6611 void Unit::SetLevel(uint32 lvl)
6613 SetUInt32Value(UNIT_FIELD_LEVEL,lvl);
6615 // group update
6616 if (GetTypeId() == TYPEID_PLAYER)
6617 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL);
6620 void Unit::SetHealth(uint32 val)
6622 uint32 maxHealth = GetMaxHealth();
6623 if(maxHealth < val)
6624 val = maxHealth;
6626 SetUInt32Value(UNIT_FIELD_HEALTH,val);
6628 // group update
6629 if (GetTypeId() == TYPEID_PLAYER)
6630 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP);
6633 void Unit::SetMaxHealth(uint32 val)
6635 uint32 health = GetHealth();
6636 SetUInt32Value(UNIT_FIELD_MAXHEALTH,val);
6638 // group update
6639 if (GetTypeId() == TYPEID_PLAYER)
6640 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP);
6642 if(val < health)
6643 SetHealth(val);
6646 void Unit::SetPower(Powers power, uint32 val)
6648 uint32 maxPower = GetMaxPower(power);
6649 if(maxPower < val)
6650 val = maxPower;
6652 SetStatInt32Value(UNIT_FIELD_POWER1 + power,val);
6654 // group update
6655 if (GetTypeId() == TYPEID_PLAYER)
6656 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER);
6659 void Unit::SetMaxPower(Powers power, uint32 val)
6661 uint32 cur_power = GetPower(power);
6662 SetStatInt32Value(UNIT_FIELD_MAXPOWER1 + power,val);
6664 // group update
6665 if (GetTypeId() == TYPEID_PLAYER)
6666 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER);
6668 if(val < cur_power)
6669 SetPower(power, val);
6672 void Unit::ApplyPowerMod(Powers power, uint32 val, bool apply)
6674 ApplyModUInt32Value(UNIT_FIELD_POWER1+power, val, apply);
6676 // group update
6677 if (GetTypeId() == TYPEID_PLAYER)
6678 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER);
6681 void Unit::ApplyMaxPowerMod(Powers power, uint32 val, bool apply)
6683 ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1+power, val, apply);
6685 // group update
6686 if (GetTypeId() == TYPEID_PLAYER)
6687 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER);
6690 void Unit::ApplyAuraProcTriggerDamage( Aura* aura, bool apply )
6692 AuraList& tAuraProcTriggerDamage = m_modAuras[SPELL_AURA_PROC_TRIGGER_DAMAGE];
6693 if(apply)
6694 tAuraProcTriggerDamage.push_back(aura);
6695 else
6696 tAuraProcTriggerDamage.remove(aura);
6699 uint32 Unit::GetCreatePowers( Powers power ) const
6701 // POWER_FOCUS and POWER_HAPPINESS only have hunter pet
6702 switch(power)
6704 case POWER_MANA: return GetCreateMana();
6705 case POWER_RAGE: return 1000;
6706 case POWER_FOCUS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 100);
6707 case POWER_ENERGY: return 100;
6708 case POWER_HAPPINESS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 1050000);
6711 return 0;
6714 void Unit::CleanupsBeforeDelete()
6716 if(m_uint32Values) // only for fully created object
6718 m_Events.KillAllEvents();
6719 CombatStop(true);
6720 DeleteThreatList();
6721 getHostilRefManager().setOnlineOfflineState(false);
6722 RemoveAllAuras();
6723 RemoveFromWorld();
6727 CharmInfo* Unit::InitCharmInfo(Unit *charm)
6729 if(!m_charmInfo)
6730 m_charmInfo = new CharmInfo(charm);
6731 return m_charmInfo;
6734 CharmInfo::CharmInfo(Unit* unit)
6735 : m_unit(unit), m_CommandState(COMMAND_STAY), m_ReactSate(REACT_PASSIVE), m_petnumber(0)
6737 for(int i =0; i<4; ++i)
6739 m_charmspells[i].spellId = 0;
6740 m_charmspells[i].active = ACT_DISABLED;
6744 void CharmInfo::InitPetActionBar()
6746 // the first 3 SpellOrActions are attack, follow and stay
6747 for(uint32 i = 0; i < 3; i++)
6749 PetActionBar[i].Type = ACT_COMMAND;
6750 PetActionBar[i].SpellOrAction = COMMAND_ATTACK - i;
6752 PetActionBar[i + 7].Type = ACT_REACTION;
6753 PetActionBar[i + 7].SpellOrAction = COMMAND_ATTACK - i;
6755 for(uint32 i=0; i < 4; i++)
6757 PetActionBar[i + 3].Type = ACT_DISABLED;
6758 PetActionBar[i + 3].SpellOrAction = 0;
6762 void CharmInfo::InitEmptyActionBar()
6764 for(uint32 x = 1; x < 10; ++x)
6766 PetActionBar[x].Type = ACT_CAST;
6767 PetActionBar[x].SpellOrAction = 0;
6769 PetActionBar[0].Type = ACT_COMMAND;
6770 PetActionBar[0].SpellOrAction = COMMAND_ATTACK;
6773 void CharmInfo::InitPossessCreateSpells()
6775 if(m_unit->GetTypeId() == TYPEID_PLAYER)
6776 return;
6778 InitEmptyActionBar(); //charm action bar
6780 for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x)
6782 if (IsPassiveSpell(((Creature*)m_unit)->m_spells[x]))
6783 m_unit->CastSpell(m_unit, ((Creature*)m_unit)->m_spells[x], true);
6784 else
6785 AddSpellToAB(0, ((Creature*)m_unit)->m_spells[x], ACT_CAST);
6789 void CharmInfo::InitCharmCreateSpells()
6791 if(m_unit->GetTypeId() == TYPEID_PLAYER) //charmed players don't have spells
6793 InitEmptyActionBar();
6794 return;
6797 InitPetActionBar();
6799 for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x)
6801 uint32 spellId = ((Creature*)m_unit)->m_spells[x];
6802 m_charmspells[x].spellId = spellId;
6804 if(!spellId)
6805 continue;
6807 if (IsPassiveSpell(spellId))
6809 m_unit->CastSpell(m_unit, spellId, true);
6810 m_charmspells[x].active = ACT_PASSIVE;
6812 else
6814 ActiveStates newstate;
6815 bool onlyselfcast = true;
6816 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
6818 if(!spellInfo) onlyselfcast = false;
6819 for(uint32 i = 0;i<3 && onlyselfcast;++i) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
6821 if(spellInfo->EffectImplicitTargetA[i] != TARGET_SELF && spellInfo->EffectImplicitTargetA[i] != 0)
6822 onlyselfcast = false;
6825 if(onlyselfcast || !IsPositiveSpell(spellId)) //only self cast and spells versus enemies are autocastable
6826 newstate = ACT_DISABLED;
6827 else
6828 newstate = ACT_CAST;
6830 AddSpellToAB(0, spellId, newstate);
6835 bool CharmInfo::AddSpellToAB(uint32 oldid, uint32 newid, ActiveStates newstate)
6837 for(uint8 i = 0; i < 10; i++)
6839 if((PetActionBar[i].Type == ACT_DISABLED || PetActionBar[i].Type == ACT_ENABLED || PetActionBar[i].Type == ACT_CAST) && PetActionBar[i].SpellOrAction == oldid)
6841 PetActionBar[i].SpellOrAction = newid;
6842 if(!oldid)
6844 if(newstate == ACT_DECIDE)
6845 PetActionBar[i].Type = ACT_DISABLED;
6846 else
6847 PetActionBar[i].Type = newstate;
6850 return true;
6853 return false;
6856 void CharmInfo::ToggleCreatureAutocast(uint32 spellid, bool apply)
6858 if(IsPassiveSpell(spellid))
6859 return;
6861 for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x)
6863 if(spellid == m_charmspells[x].spellId)
6865 m_charmspells[x].active = apply ? ACT_ENABLED : ACT_DISABLED;
6870 void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow)
6872 m_petnumber = petnumber;
6873 if(statwindow)
6874 m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, m_petnumber);
6875 else
6876 m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, 0);
6879 bool Unit::isFrozen() const
6881 AuraList const& mRoot = GetAurasByType(SPELL_AURA_MOD_ROOT);
6882 for(AuraList::const_iterator i = mRoot.begin(); i != mRoot.end(); ++i)
6883 if( (*i)->GetSpellProto()->School == SPELL_SCHOOL_FROST)
6884 return true;
6885 return false;