[4400] * sql/updates/Makefile.am: Added missing SQL updates.
[mangos-git.git] / src / game / Unit.cpp
blobb7df9adb531af3d5cfae2a02b3b998fe80cab315
1 /*
2 * Copyright (C) 2005,2006,2007 MaNGOS <http://www.mangosproject.org/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "Log.h"
21 #include "Opcodes.h"
22 #include "WorldPacket.h"
23 #include "WorldSession.h"
24 #include "World.h"
25 #include "ObjectMgr.h"
26 #include "Unit.h"
27 #include "QuestDef.h"
28 #include "Player.h"
29 #include "Creature.h"
30 #include "Spell.h"
31 #include "Group.h"
32 #include "SpellAuras.h"
33 #include "MapManager.h"
34 #include "ObjectAccessor.h"
35 #include "CreatureAI.h"
36 #include "Formulas.h"
37 #include "Pet.h"
38 #include "Util.h"
39 #include "Totem.h"
40 #include "TemporarySummon.h"
41 #include "BattleGroundMgr.h"
43 #include <math.h>
45 float baseMoveSpeed[MAX_MOVE_TYPE] =
47 2.5f, // MOVE_WALK
48 7.0f, // MOVE_RUN
49 1.25f, // MOVE_WALKBACK
50 4.722222f, // MOVE_SWIM
51 4.5f, // MOVE_SWIMBACK
52 3.141594f, // MOVE_TURN
53 7.0f, // MOVE_FLY
54 4.5f // MOVE_FLYBACK
57 // auraTypes contains auras capable of proc'ing for attacker
58 static Unit::AuraTypeSet GenerateAttakerProcAuraTypes()
60 static Unit::AuraTypeSet auraTypes;
61 auraTypes.insert(SPELL_AURA_DUMMY);
62 auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL);
63 auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE);
64 return auraTypes;
67 // auraTypes contains auras capable of proc'ing for attacker
68 static Unit::AuraTypeSet GenerateVictimProcAuraTypes()
70 static Unit::AuraTypeSet auraTypes;
71 auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL);
72 auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE);
73 auraTypes.insert(SPELL_AURA_DUMMY);
74 auraTypes.insert(SPELL_AURA_MOD_PARRY_PERCENT);
75 return auraTypes;
78 static Unit::AuraTypeSet attackerProcAuraTypes = GenerateAttakerProcAuraTypes();
79 static Unit::AuraTypeSet victimProcAuraTypes = GenerateVictimProcAuraTypes();
81 // auraTypes contains auras capable of proc'ing for attacker and victim
82 static Unit::AuraTypeSet GenerateProcAuraTypes()
84 static Unit::AuraTypeSet auraTypes = victimProcAuraTypes;
85 auraTypes.insert(attackerProcAuraTypes.begin(),attackerProcAuraTypes.end());
86 return auraTypes;
89 static Unit::AuraTypeSet procAuraTypes = GenerateProcAuraTypes();
91 bool IsPassiveStackableSpell( uint32 spellId )
93 if(!IsPassiveSpell(spellId))
94 return false;
96 SpellEntry const* spellProto = sSpellStore.LookupEntry(spellId);
97 if(!spellProto)
98 return false;
100 for(int j = 0; j < 3; ++j)
102 if(std::find(procAuraTypes.begin(),procAuraTypes.end(),spellProto->EffectApplyAuraName[j])!=procAuraTypes.end())
103 return false;
106 return true;
109 Unit::Unit( WorldObject *instantiator )
110 : WorldObject( instantiator ), m_ThreatManager(this), m_HostilRefManager(this)
112 m_objectType |= TYPE_UNIT;
113 m_objectTypeId = TYPEID_UNIT;
114 // 2.1.2 - 0x70
115 m_updateFlag = (UPDATEFLAG_ALL | UPDATEFLAG_LIVING | UPDATEFLAG_HASPOSITION);
117 m_attackTimer[BASE_ATTACK] = 0;
118 m_attackTimer[OFF_ATTACK] = 0;
119 m_attackTimer[RANGED_ATTACK] = 0;
120 m_modAttackSpeedPct[BASE_ATTACK] = 1.0f;
121 m_modAttackSpeedPct[OFF_ATTACK] = 1.0f;
122 m_modAttackSpeedPct[RANGED_ATTACK] = 1.0f;
124 m_state = 0;
125 m_form = 0;
126 m_deathState = ALIVE;
128 for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
129 m_currentSpells[i] = NULL;
130 m_addDmgOnce = 0;
131 m_TotemSlot[0] = m_TotemSlot[1] = m_TotemSlot[2] = m_TotemSlot[3] = 0;
132 m_ObjectSlot[0] = m_ObjectSlot[1] = m_ObjectSlot[2] = m_ObjectSlot[3] = 0;
133 //m_Aura = NULL;
134 //m_AurasCheck = 2000;
135 //m_removeAuraTimer = 4;
136 //tmpAura = NULL;
137 m_silenced = false;
138 waterbreath = false;
140 m_Visibility = VISIBILITY_ON;
142 m_detectStealth = 0;
143 m_detectInvisibility = 0;
144 m_stealthvalue = 0;
145 m_invisibilityvalue = 0;
146 m_transform = 0;
147 m_ShapeShiftForm = 0;
148 m_canModifyStats = false;
150 for (int i = 0; i < TOTAL_AURAS; i++)
151 m_AuraModifiers[i] = 0;
152 for (int i = 0; i < IMMUNITY_MECHANIC; i++)
153 m_spellImmune[i].clear();
154 for (int i = 0; i < UNIT_MOD_END; i++)
156 m_auraModifiersGroup[i][BASE_VALUE] = 0.0f;
157 m_auraModifiersGroup[i][BASE_PCT] = 1.0f;
158 m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f;
159 m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f;
161 // implement 50% base damage from offhand
162 m_auraModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f;
164 for (int i = 0; i < 3; i++)
166 m_weaponDamage[i][MINDAMAGE] = BASE_MINDAMAGE;
167 m_weaponDamage[i][MAXDAMAGE] = BASE_MAXDAMAGE;
169 for (int i = 0; i < MAX_STATS; i++)
170 m_createStats[i] = 0.0f;
172 m_attacking = NULL;
173 m_modHitChance = 0;
174 m_modSpellHitChance = 0;
175 m_baseSpellCritChance = 5;
176 m_modResilience = 0.0;
177 m_CombatTimer = 0;
178 //m_victimThreat = 0.0f;
179 for (int i = 0; i < MAX_SPELL_SCHOOL; ++i)
180 m_threatModifier[i] = 1.0f;
181 m_isSorted = true;
182 for (int i = 0; i < MAX_MOVE_TYPE; ++i)
183 m_speed_rate[i] = 1.0f;
185 m_removedAuras = 0;
186 m_charmInfo = NULL;
189 Unit::~Unit()
191 // set current spells as deletable
192 for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
194 // spell may be safely deleted now
195 if (m_currentSpells[i]) m_currentSpells[i]->SetDeletable(true);
196 m_currentSpells[i] = NULL;
199 // remove references to unit
200 for(std::list<GameObject*>::iterator i = m_gameObj.begin(); i != m_gameObj.end();)
202 (*i)->SetOwnerGUID(0);
203 (*i)->SetRespawnTime(0);
204 (*i)->Delete();
205 i = m_gameObj.erase(i);
208 RemoveAllDynObjects();
210 if(m_charmInfo) delete m_charmInfo;
213 void Unit::RemoveAllDynObjects()
215 while(!m_dynObjGUIDs.empty())
217 DynamicObject* dynObj = ObjectAccessor::Instance().GetDynamicObject(*this,*m_dynObjGUIDs.begin());
218 if(dynObj)
219 dynObj->Delete();
220 m_dynObjGUIDs.erase(m_dynObjGUIDs.begin());
224 void Unit::Update( uint32 p_time )
226 /*if(p_time > m_AurasCheck)
228 m_AurasCheck = 2000;
229 _UpdateAura();
230 }else
231 m_AurasCheck -= p_time;*/
233 // WARNING! Order of execution here is important, do not change.
234 // Spells must be processed with event system BEFORE they go to _UpdateSpells.
235 // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad.
236 m_Events.Update( p_time );
237 _UpdateSpells( p_time );
239 //update combat timer only for players and pets
240 if (isInCombat() && (GetTypeId() == TYPEID_PLAYER || ((Creature*)this)->isPet() || ((Creature*)this)->isCharmed()))
242 if(m_HostilRefManager.isEmpty())
244 // m_CombatTimer set at aura start and it will be freeze until aura removing
245 if(!HasAuraType(SPELL_AURA_INTERRUPT_REGEN))
247 if ( m_CombatTimer <= p_time )
248 ClearInCombat();
249 else
250 m_CombatTimer -= p_time;
255 if(uint32 base_att = getAttackTimer(BASE_ATTACK))
257 setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time) );
259 if(GetHealth() < GetMaxHealth()*0.2)
260 ModifyAuraState(AURA_STATE_HEALTHLESS, true);
261 else ModifyAuraState(AURA_STATE_HEALTHLESS, false);
264 bool Unit::haveOffhandWeapon() const
266 if(GetTypeId() == TYPEID_PLAYER)
268 Item *tmpitem = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
270 return tmpitem && !tmpitem->IsBroken() && (tmpitem->GetProto()->InventoryType == INVTYPE_WEAPON || tmpitem->GetProto()->InventoryType == INVTYPE_WEAPONOFFHAND);
272 else
273 return false;
276 void Unit::SendMoveToPacket(float x, float y, float z, bool run, uint32 transitTime)
278 float dx = x - GetPositionX();
279 float dy = y - GetPositionY();
280 float dz = z - GetPositionZ();
281 if (!transitTime)
283 float dist = ((dx*dx) + (dy*dy) + (dz*dz));
284 if(dist<0)
285 dist = 0;
286 else
287 dist = sqrt(dist);
288 double speed = GetSpeed(run ? MOVE_RUN : MOVE_WALK);
289 if(speed<=0)
290 speed = 2.5f;
291 speed *= 0.001f;
292 transitTime = static_cast<uint32>(dist / speed + 0.5);
294 //float orientation = (float)atan2((double)dy, (double)dx);
295 SendMonsterMove(x,y,z,0,run,transitTime);
298 void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, bool Run, uint32 Time)
300 WorldPacket data( SMSG_MONSTER_MOVE, (41 + GetPackGUID().size()) );
301 data.append(GetPackGUID());
303 // Point A, starting location
304 data << GetPositionX() << GetPositionY() << GetPositionZ();
305 // unknown field - unrelated to orientation
306 // seems to increment about 1000 for every 1.7 seconds
307 // for now, we'll just use mstime
308 data << getMSTime();
310 data << uint8(type); // unknown
311 switch(type)
313 case 0: // normal packet
314 break;
315 case 1: // stop packet
316 SendMessageToSet( &data, true );
317 return;
318 case 3: // not used currently
319 data << uint64(0); // probably target guid
320 break;
321 case 4: // not used currently
322 data << float(0); // probably orientation
323 break;
326 data << uint32(Run ? 0x00000100 : 0x00000000); // flags (0x100 - running, 0x200 - taxi)
327 /* Flags:
328 512: Floating, moving without walking/running
330 data << Time; // Time in between points
331 data << uint32(1); // 1 single waypoint
332 data << NewPosX << NewPosY << NewPosZ; // the single waypoint Point B
334 SendMessageToSet( &data, true );
337 void Unit::resetAttackTimer(WeaponAttackType type)
339 if (GetTypeId() == TYPEID_PLAYER)
340 m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]);
341 else
342 m_attackTimer[type] = uint32(BASE_ATTACK_TIME * m_modAttackSpeedPct[type]);
345 bool Unit::canReachWithAttack(Unit *pVictim) const
347 assert(pVictim);
348 float reach = GetFloatValue(UNIT_FIELD_COMBATREACH);
349 if( reach <= 0.0f )
350 reach = 1.0f;
351 return IsWithinDistInMap(pVictim, reach);
354 void Unit::RemoveSpellsCausingAura(uint32 auraType)
356 if (auraType >= TOTAL_AURAS) return;
357 AuraList::iterator iter, next;
358 for (iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end(); iter = next)
360 next = iter;
361 ++next;
363 if (*iter)
365 RemoveAurasDueToSpell((*iter)->GetId());
366 if (!m_modAuras[auraType].empty())
367 next = m_modAuras[auraType].begin();
368 else
369 return;
374 bool Unit::HasAuraType(uint32 auraType) const
376 return (!m_modAuras[auraType].empty());
379 /* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */
380 void Unit::RemoveSpellbyDamageTaken(uint32 auraType, uint32 damage)
382 if(!HasAuraType(auraType))
383 return;
385 // The chance to dispell an aura depends on the damage taken with respect to the casters level.
386 uint32 max_dmg = getLevel() > 8 ? 25 * getLevel() - 150 : 50;
387 float chance = float(damage) / max_dmg * 100.0;
388 if (roll_chance_f(chance))
389 RemoveSpellsCausingAura(auraType);
392 void Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchools damageSchool, SpellEntry const *spellProto, uint32 procFlag, bool durabilityLoss)
394 if (!pVictim->isAlive() || pVictim->isInFlight()) return;
396 //You don't lose health from damage taken from another player while in a sanctuary
397 //You still see it in the combat log though
398 if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
400 const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
401 if(area && area->flags & 0x800) //sanctuary
402 return;
405 // remove affects at any damage (including 0 damage)
406 RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
407 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 physical damage received .
423 if(cleanDamage && cleanDamage->damage && damageSchool==SPELL_SCHOOL_NORMAL && 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 (only from direct weapon damage)
473 if( cleanDamage && damagetype==DIRECT_DAMAGE && 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)
508 // battleground things
509 if(pVictim->GetTypeId() == TYPEID_PLAYER && (((Player*)pVictim)->InBattleGround()))
511 Player *killed = ((Player*)pVictim);
512 Player *killer = NULL;
513 if(GetTypeId() == TYPEID_PLAYER)
514 killer = ((Player*)this);
515 else if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
517 Unit *owner = GetOwner();
518 if(owner->GetTypeId() == TYPEID_PLAYER)
519 killer = ((Player*)owner);
522 BattleGround *bg = sBattleGroundMgr.GetBattleGround(killed->GetBattleGroundId());
523 if(bg)
525 bg->HandleKillPlayer(killed, killer); // drop flags and etc
526 // add +1 deaths
527 bg->UpdatePlayerScore(killed, SCORE_DEATHS, 1);
528 if(killer)
529 // add +1 kills
530 bg->UpdatePlayerScore(killer, SCORE_KILLS, 1);
534 DEBUG_LOG("DealDamage: victim just died");
536 DEBUG_LOG("DealDamageAttackStop");
537 AttackStop();
538 pVictim->CombatStop(true);
540 DEBUG_LOG("SET JUST_DIED");
541 pVictim->setDeathState(JUST_DIED);
543 DEBUG_LOG("DealDamageHealth1");
544 pVictim->SetHealth(0);
546 // Call KilledUnit for creatures
547 if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI())
548 ((Creature*)this)->AI()->KilledUnit(pVictim);
550 // 10% durability loss on death
551 // clean InHateListOf
552 if (pVictim->GetTypeId() == TYPEID_PLAYER)
554 if (GetTypeId() != TYPEID_PLAYER && durabilityLoss)
556 DEBUG_LOG("We are dead, loosing 10 percents durability");
557 ((Player*)pVictim)->DurabilityLossAll(0.10);
558 // durability lost message
559 WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0);
560 ((Player*)pVictim)->GetSession()->SendPacket(&data);
562 pVictim->getHostilRefManager().deleteReferences();
564 Pet *pet = pVictim->GetPet();
565 if(pet && pVictim->GetTypeId() != TYPEID_PLAYER)
567 pet->setDeathState(JUST_DIED);
568 pet->CombatStop(true);
569 pet->SetHealth(0);
570 pet->addUnitState(UNIT_STAT_DIED);
571 pet->getHostilRefManager().deleteReferences();
574 else // creature died
576 DEBUG_LOG("DealDamageNotPlayer");
578 if(((Creature*)pVictim)->isPet())
579 pVictim->getHostilRefManager().deleteReferences();
580 else
582 pVictim->DeleteThreatList();
583 pVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
585 // Call creature just died function
586 if (((Creature*)pVictim)->AI())
587 ((Creature*)pVictim)->AI()->JustDied(this);
590 //judge if GainXP, Pet kill like player kill,kill pet not like PvP
591 bool PvP = false;
592 Player *player = NULL;
594 if(GetTypeId() == TYPEID_PLAYER)
596 player = (Player*)this;
597 if(pVictim->GetTypeId() == TYPEID_PLAYER)
598 PvP = true;
600 Unit* pet = NULL;
602 if(player->GetPetGUID() && (pet = player->GetPet()))
603 pet->ClearInCombat();
605 if(player->GetCharmGUID() && (pet = player->GetCharm()))
606 pet->ClearInCombat();
608 // FIXME: or charmed (can be player). Maybe must be check before GetTypeId() == TYPEID_PLAYER
609 else if(GetCharmerOrOwnerGUID()) // Pet or timed creature, etc
611 Unit* pet = this;
612 Unit* owner = pet->GetCharmerOrOwner();
614 if(owner && owner->GetTypeId() == TYPEID_PLAYER)
616 player = (Player*)owner;
617 player->ClearInCombat();
618 if(pVictim->GetTypeId() == TYPEID_PLAYER)
619 PvP = true;
622 if(pet->GetTypeId()==TYPEID_UNIT && ((Creature*)pet)->isPet())
624 uint32 petxp = MaNGOS::XP::BaseGain(getLevel(), pVictim->getLevel());
625 ((Pet*)pet)->GivePetXP(petxp);
629 // self or owner of pet
630 if(player)
632 if(player!=pVictim)
634 // prepare data for near group iteration (PvP and !PvP cases
635 uint32 xp = PvP || IsNoDamageXPArea(player->GetAreaId()) ? 0 : MaNGOS::XP::Gain(player, pVictim);
636 bool honored_kill = false;
638 Group *pGroup = player->GetGroup();
639 if(pGroup)
641 uint32 count = pGroup->GetMemberCountForXPAtKill(pVictim);
642 if(count)
644 // skip in check PvP case (for speed, not used)
645 bool is_raid = PvP ? false : MapManager::Instance().GetBaseMap(player->GetMapId())->IsRaid() && pGroup->isRaidGroup();
647 for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
649 Player *pGroupGuy = pGroup->GetMemberForXPAtKill(itr->getSource(),pVictim);
650 if(!pGroupGuy)
651 continue;
653 // honor can be in PvP and !PvP (racial leader) cases
654 if(pGroupGuy->RewardHonor(pVictim,count) && player==pGroupGuy)
655 honored_kill = true;
657 // xp and reputation only in !PvP case
658 if(!PvP)
660 // FIXME: xp/count for all in group at this moment, must be level dependent
661 float rate = 1.0f/count;
663 // if with raid in raid dungeon then all receive full reputation at kill
664 pGroupGuy->RewardReputation(pVictim,is_raid ? 1.0f : rate);
666 uint32 itr_xp = uint32(xp*rate);
668 pGroupGuy->GiveXP(itr_xp, pVictim);
669 if(Pet* pet = player->GetPet())
671 pet->GivePetXP(itr_xp/2);
674 // normal creature (not pet/etc) can be only in !PvP case
675 if(pVictim->GetTypeId()==TYPEID_UNIT)
676 pGroupGuy->KilledMonster(pVictim->GetEntry(), pVictim->GetGUID());
681 else // if (!pGroup)
683 // honor can be in PvP and !PvP (racial leader) cases
684 if(player->RewardHonor(pVictim,1))
685 honored_kill = true;
687 // xp and reputation only in !PvP case
688 if(!PvP)
690 player->RewardReputation(pVictim,1);
691 player->GiveXP(xp, pVictim);
692 if(Pet* pet = player->GetPet())
694 pet->GivePetXP(xp);
697 // normal creature (not pet/etc) can be only in !PvP case
698 if(pVictim->GetTypeId()==TYPEID_UNIT)
699 player->KilledMonster(pVictim->GetEntry(),pVictim->GetGUID());
703 if(xp || honored_kill)
704 player->ProcDamageAndSpell(pVictim,PROC_FLAG_KILL_XP_GIVER,PROC_FLAG_NONE);
707 else // if (player)
709 DEBUG_LOG("Monster kill Monster");
712 // last damage from duel opponent or opponent controlled creature?
713 if(duel_hasEnded)
715 assert(pVictim->GetTypeId()==TYPEID_PLAYER);
716 Player *he = (Player*)pVictim;
718 assert(he->duel);
720 CombatStop(); // for case killed by pet
721 if (IsNonMeleeSpellCasted(true))
722 InterruptNonMeleeSpells(true);
723 if(he->duel->opponent!=this)
725 he->duel->opponent->CombatStop();
726 if(he->duel->opponent->IsNonMeleeSpellCasted(true))
727 he->duel->opponent->InterruptNonMeleeSpells(true);
729 he->CombatStop();
730 if(he->IsNonMeleeSpellCasted(true))
731 he->InterruptNonMeleeSpells(true);
733 he->DuelComplete(0);
736 else // if (health <= damage)
738 DEBUG_LOG("DealDamageAlive");
740 pVictim->ModifyHealth(- (int32)damage);
742 // Check if health is below 20% (apply damage before to prevent case when after ProcDamageAndSpell health < damage
743 if(pVictim->GetHealth()*5 < pVictim->GetMaxHealth())
745 uint32 procVictim = PROC_FLAG_NONE;
747 // if just dropped below 20% (for CheatDeath)
748 if((pVictim->GetHealth()+damage)*5 > pVictim->GetMaxHealth())
749 procVictim = PROC_FLAG_LOW_HEALTH;
751 ProcDamageAndSpell(pVictim,PROC_FLAG_TARGET_LOW_HEALTH,procVictim);
754 if(damagetype != DOT)
756 //start melee attacks only after melee hit
757 Attack(pVictim,(damagetype == DIRECT_DAMAGE));
760 if(pVictim->getTransForm() && pVictim->hasUnitState(UNIT_STAT_CONFUSED))
762 pVictim->RemoveAurasDueToSpell(pVictim->getTransForm());
763 pVictim->setTransForm(0);
766 if (pVictim->GetTypeId() != TYPEID_PLAYER)
768 if(spellProto && IsDamageToThreatSpell(spellProto))
769 damage *= 2;
770 pVictim->AddThreat(this, damage, damageSchool, spellProto);
772 else // victim is a player
774 // Rage from damage received
775 if(this != pVictim && pVictim->GetTypeId() == TYPEID_PLAYER && pVictim->getPowerType() == POWER_RAGE)
777 uint32 rage_damage = damage + (cleanDamage ? cleanDamage->damage : 0);
778 ((Player*)pVictim)->RewardRage(rage_damage, 0, false);
781 // random durability for items (HIT)
782 if (urand(0,300) == 10)
784 DEBUG_LOG("HIT: We decrease durability with 5 percent");
785 ((Player*)pVictim)->DurabilityLossAll(0.05);
789 // TODO: Store auras by interrupt flag to speed this up.
790 AuraMap& vAuras = pVictim->GetAuras();
791 for (AuraMap::iterator i = vAuras.begin(), next; i != vAuras.end(); i = next)
793 const SpellEntry *se = i->second->GetSpellProto();
794 next = i; next++;
795 if( se->AuraInterruptFlags & AURA_INTERRUPT_FLAG_DAMAGE )
797 bool remove = true;
798 if (se->procFlags & (1<<3))
800 if (!roll_chance_i(se->procChance))
801 remove = false;
803 if (remove)
805 pVictim->RemoveAurasDueToSpell(i->second->GetId());
806 // FIXME: this may cause the auras with proc chance to be rerolled several times
807 next = vAuras.begin();
812 if (damagetype != NODAMAGE)
814 if(pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL] && pVictim->GetTypeId() == TYPEID_PLAYER && damage)
816 if (pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() == SPELL_STATE_CASTING)
818 uint32 channelInterruptFlags = pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->ChannelInterruptFlags;
819 if( channelInterruptFlags & CHANNEL_FLAG_DELAY )
821 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)));
822 pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->DelayedChannel((int32)(0.25f * GetDuration(pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo)));
824 else if( (channelInterruptFlags & (CHANNEL_FLAG_DAMAGE | CHANNEL_FLAG_DAMAGE2)) )
826 sLog.outDetail("Spell %u canceled at damage!",pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id);
827 pVictim->InterruptSpell(CURRENT_CHANNELED_SPELL);
830 else if (pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() == SPELL_STATE_DELAYED)
831 // break channeled spell in delayed state on damage
833 sLog.outDetail("Spell %u canceled at damage!",pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id);
834 pVictim->InterruptSpell(CURRENT_CHANNELED_SPELL);
839 // last damage from duel opponent
840 if(duel_hasEnded)
842 assert(pVictim->GetTypeId()==TYPEID_PLAYER);
843 Player *he = (Player*)pVictim;
845 assert(he->duel);
847 he->ModifyHealth(1);
848 CombatStop(); // for case killed by pet
849 if(he->duel->opponent!=this)
850 he->duel->opponent->CombatStop();
851 he->CombatStop();
853 he->CastSpell(he, 7267, true); // beg
854 he->DuelComplete(1);
858 DEBUG_LOG("DealDamageEnd");
861 void Unit::CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster)
863 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
865 if(!spellInfo)
867 sLog.outError("WORLD: unknown spell id %i\n", spellId);
868 return;
871 CastSpell(Victim,spellInfo,triggered,castItem,triggredByAura, originalCaster);
874 void Unit::CastSpell(Unit* Victim,SpellEntry const *spellInfo, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster)
876 if(!spellInfo)
878 sLog.outError("WORLD: unknown spell ");
879 return;
882 if (castItem)
883 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
885 Spell *spell = new Spell(this, spellInfo, triggered, triggredByAura,originalCaster);
887 SpellCastTargets targets;
888 targets.setUnitTarget( Victim );
889 spell->m_CastItem = castItem;
890 spell->prepare(&targets);
893 void Unit::CastCustomSpell(Unit* Victim,uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem, Aura* triggredByAura, uint64 originalCaster)
895 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
897 if(!spellInfo)
899 sLog.outError("WORLD: unknown spell id %i\n", spellId);
900 return;
903 CastCustomSpell(Victim,spellInfo,bp0,bp1,bp2,triggered,castItem,triggredByAura, originalCaster);
906 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)
908 if(!spellInfo)
910 sLog.outError("WORLD: unknown spell ");
911 return;
914 if (castItem)
915 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
917 Spell *spell = new Spell(this, spellInfo, triggered, triggredByAura,originalCaster);
919 if(bp0)
920 spell->m_currentBasePoints[0] = *bp0;
922 if(bp1)
923 spell->m_currentBasePoints[1] = *bp1;
925 if(bp2)
926 spell->m_currentBasePoints[2] = *bp2;
928 SpellCastTargets targets;
929 targets.setUnitTarget( Victim );
930 spell->m_CastItem = castItem;
931 spell->prepare(&targets);
934 void Unit::DealDamageBySchool(Unit *pVictim, SpellEntry const *spellInfo, uint32 *damage, CleanDamage *cleanDamage, bool *crit, bool isTriggeredSpell)
937 // TODO this in only generic way, check for exceptions
938 DEBUG_LOG("DealDamageBySchool (BEFORE) SCHOOL %u >> DMG:%u", spellInfo->School, *damage);
940 // Per-school calc
941 switch (spellInfo->School)
943 // Physical damage school
944 case SPELL_SCHOOL_NORMAL:
946 // Calculate physical outcome
947 MeleeHitOutcome outcome;
948 outcome = RollPhysicalOutcomeAgainst(pVictim, BASE_ATTACK, spellInfo);
950 //Used to store the Hit Outcome
951 cleanDamage->hitOutCome = outcome;
953 // Return miss first (sends miss message)
954 if(outcome == MELEE_HIT_MISS)
956 SendAttackStateUpdate(HITINFO_MISS, pVictim, 1, SpellSchools(spellInfo->School), 0, 0,0,1,0);
957 *damage = 0;
959 if(GetTypeId()== TYPEID_PLAYER)
960 ((Player*)this)->UpdateWeaponSkill(BASE_ATTACK);
962 CastMeleeProcDamageAndSpell(pVictim,0,BASE_ATTACK,MELEE_HIT_MISS,spellInfo,isTriggeredSpell);
963 return;
966 // Hitinfo, Victimstate
967 uint32 hitInfo, victimState;
968 hitInfo = HITINFO_NORMALSWING;
970 //Calculate armor mitigation
971 uint32 damageAfterArmor;
972 damageAfterArmor = CalcArmorReducedDamage(pVictim, *damage);
973 cleanDamage->damage += *damage - damageAfterArmor;
974 *damage = damageAfterArmor;
976 // Classify outcome
977 switch (outcome)
979 case MELEE_HIT_CRIT:
981 *damage *= 2;
982 // Resilience - reduce crit damage by 2x%
983 uint32 resilienceReduction = uint32(pVictim->m_modResilience * 2/100 * (*damage));
984 cleanDamage->damage += resilienceReduction;
985 *damage -= resilienceReduction;
986 *crit = true;
987 hitInfo |= HITINFO_CRITICALHIT;
988 break;
990 case MELEE_HIT_PARRY:
992 cleanDamage->damage += *damage; // To Help Calculate Rage
993 *damage = 0;
994 victimState = VICTIMSTATE_PARRY;
996 // Counter-attack ( explained in Unit::DoAttackDamage() )
998 // Get attack timers
999 float offtime = float(pVictim->getAttackTimer(OFF_ATTACK));
1000 float basetime = float(pVictim->getAttackTimer(BASE_ATTACK));
1002 // Reduce attack time
1003 if (pVictim->haveOffhandWeapon() && offtime < basetime)
1005 float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20;
1006 float percent60 = 3 * percent20;
1007 if(offtime > percent20 && offtime <= percent60)
1009 pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20));
1011 else if(offtime > percent60)
1013 offtime -= 2 * percent20;
1014 pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime));
1017 else
1019 float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20;
1020 float percent60 = 3 * percent20;
1021 if(basetime > percent20 && basetime <= percent60)
1023 pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20));
1025 else if(basetime > percent60)
1027 basetime -= 2 * percent20;
1028 pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime));
1033 // Update victim defense ?
1034 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1035 ((Player*)pVictim)->UpdateDefense();
1037 // Set parry flags
1038 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
1039 pVictim->ModifyAuraState(AURA_STATE_PARRY, true);
1040 break;
1042 case MELEE_HIT_DODGE:
1044 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1045 ((Player*)pVictim)->UpdateDefense();
1047 cleanDamage->damage += *damage; // To Help Calculate Rage
1048 *damage = 0;
1049 hitInfo |= HITINFO_SWINGNOHITSOUND;
1050 victimState = VICTIMSTATE_DODGE;
1051 break;
1053 case MELEE_HIT_BLOCK:
1055 uint32 blocked_amount;
1056 blocked_amount = uint32(pVictim->GetShieldBlockValue());
1057 if (blocked_amount >= *damage)
1059 hitInfo |= HITINFO_SWINGNOHITSOUND;
1060 victimState = VICTIMSTATE_BLOCKS;
1061 cleanDamage->damage += *damage; // To Help Calculate Rage
1062 *damage = 0;
1064 else
1066 // To Help Calculate Rage
1067 cleanDamage->damage += blocked_amount;
1068 *damage = *damage - blocked_amount;
1070 break;
1073 case MELEE_HIT_MISS:
1074 case MELEE_HIT_GLANCING:
1075 case MELEE_HIT_CRUSHING:
1076 case MELEE_HIT_NORMAL:
1077 break;
1080 // Update attack state
1081 SendAttackStateUpdate(victimState ? hitInfo|victimState : hitInfo, pVictim, 1, SpellSchools(spellInfo->School), 0, 0,0,1,0);
1083 // do all damage=0 cases here
1084 if(damage <= 0)
1085 CastMeleeProcDamageAndSpell(pVictim,0,BASE_ATTACK,outcome,spellInfo,isTriggeredSpell);
1087 break;
1089 // Other schools
1090 case SPELL_SCHOOL_HOLY:
1091 case SPELL_SCHOOL_FIRE:
1092 case SPELL_SCHOOL_NATURE:
1093 case SPELL_SCHOOL_FROST:
1094 case SPELL_SCHOOL_SHADOW:
1095 case SPELL_SCHOOL_ARCANE:
1097 //Spell miss (sends resist message)
1098 if(SpellMissChanceCalc(pVictim) > urand(0,10000))
1100 cleanDamage->damage = 0;
1101 *damage = 0;
1102 ProcDamageAndSpell(pVictim, PROC_FLAG_TARGET_RESISTS, PROC_FLAG_RESIST_SPELL, 0, spellInfo,isTriggeredSpell);
1103 SendAttackStateUpdate(HITINFO_RESIST|HITINFO_SWINGNOHITSOUND, pVictim, 1, SpellSchools(spellInfo->School), 0, 0,0,1,0);
1104 return;
1107 // Calculate damage bonus
1108 *damage = SpellDamageBonus(pVictim, spellInfo, *damage, SPELL_DIRECT_DAMAGE);
1110 // Calculate critical bonus
1111 *crit = SpellCriticalBonus(spellInfo, (int32*)damage, pVictim);
1112 cleanDamage->hitOutCome = MELEE_HIT_CRIT;
1114 // spell proc all magic damage==0 case in this function
1115 if(damage <= 0)
1117 // Procflags
1118 uint32 procAttacker = PROC_FLAG_HIT_SPELL;
1119 uint32 procVictim = (PROC_FLAG_STRUCK_SPELL|PROC_FLAG_TAKE_DAMAGE);
1121 ProcDamageAndSpell(pVictim, procAttacker, procVictim, 0, spellInfo, isTriggeredSpell);
1124 break;
1127 // TODO this in only generic way, check for exceptions
1128 DEBUG_LOG("DealDamageBySchool (AFTER) SCHOOL %u >> DMG:%u", spellInfo->School, *damage);
1131 void Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell, bool useSpellDamage)
1133 if(!this || !pVictim)
1134 return;
1135 if(!this->isAlive() || !pVictim->isAlive())
1136 return;
1138 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID);
1139 if(!spellInfo)
1140 return;
1142 CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL);
1143 bool crit = false;
1145 if (useSpellDamage)
1146 DealDamageBySchool(pVictim, spellInfo, &damage, &cleanDamage, &crit, isTriggeredSpell);
1148 // If we actually dealt some damage (spell proc's for 0 damage (normal and magic) called in DealDamageBySchool)
1149 if(damage > 0)
1151 // Calculate absorb & resists
1152 uint32 absorb = 0;
1153 uint32 resist = 0;
1155 CalcAbsorbResist(pVictim,SpellSchools(spellInfo->School), damage, &absorb, &resist);
1157 // Only send absorbed message if we actually absorbed some damage
1158 if(damage > 0)
1160 // Handle absorb & resists
1161 if(damage <= absorb + resist && absorb)
1163 SendAttackStateUpdate(HITINFO_ABSORB|HITINFO_SWINGNOHITSOUND, pVictim, 1, SpellSchools(spellInfo->School),damage, absorb,resist,1,0);
1164 return;
1166 else if(damage <= resist) // If we didn't fully absorb check if we fully resisted
1168 ProcDamageAndSpell(pVictim, PROC_FLAG_TARGET_RESISTS, PROC_FLAG_RESIST_SPELL, 0, spellInfo,isTriggeredSpell);
1169 SendAttackStateUpdate(HITINFO_RESIST|HITINFO_SWINGNOHITSOUND, pVictim, 1, SpellSchools(spellInfo->School), damage, absorb,resist,1,0);
1170 return;
1174 // Send damage log
1175 sLog.outDetail("SpellNonMeleeDamageLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u,absorb is %u,resist is %u",
1176 GetGUIDLow(), GetTypeId(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, spellID, absorb,resist);
1177 SendSpellNonMeleeDamageLog(pVictim, spellID, damage, SpellSchools(spellInfo->School), absorb, resist, false, 0, crit);
1179 // Deal damage done
1180 DealDamage(pVictim, (damage-absorb-resist), &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchools(spellInfo->School), spellInfo, 0, true);
1182 // Procflags
1183 uint32 procAttacker = PROC_FLAG_HIT_SPELL;
1184 uint32 procVictim = (PROC_FLAG_STRUCK_SPELL|PROC_FLAG_TAKE_DAMAGE);
1186 if (crit)
1188 procAttacker |= PROC_FLAG_CRIT_SPELL;
1189 procVictim |= PROC_FLAG_STRUCK_CRIT_SPELL;
1192 ProcDamageAndSpell(pVictim, procAttacker, procVictim, (damage-absorb-resist), spellInfo, isTriggeredSpell);
1194 else
1196 // all spell proc for 0 normal and magic damage called in DealDamageBySchool
1198 //Check for rage
1199 if(cleanDamage.damage)
1200 // Rage from damage received.
1201 if(pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->getPowerType() == POWER_RAGE))
1202 ((Player*)pVictim)->RewardRage(cleanDamage.damage, 0, false);
1206 void Unit::PeriodicAuraLog(Unit *pVictim, SpellEntry const *spellProto, Modifier *mod, uint8 effect_idx)
1208 uint32 procFlag = 0;
1209 if(!this || !pVictim || !isAlive() || !pVictim->isAlive())
1211 return;
1213 uint32 absorb=0;
1214 uint32 resist=0;
1215 CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
1216 uint32 pdamage = mod->m_amount;
1218 if(mod->m_auraname != SPELL_AURA_PERIODIC_HEAL && mod->m_auraname != SPELL_AURA_OBS_MOD_HEALTH)
1220 //Calculate armor mitigation if it is a physical spell
1221 if (spellProto->School == SPELL_SCHOOL_NORMAL)
1223 uint32 pdamageReductedArmor = CalcArmorReducedDamage(pVictim, pdamage);
1224 cleanDamage.damage += pdamage - pdamageReductedArmor;
1225 pdamage = pdamageReductedArmor;
1228 CalcAbsorbResist(pVictim, SpellSchools(spellProto->School), pdamage, &absorb, &resist);
1231 sLog.outDetail("PeriodicAuraLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u abs is %u",
1232 GetGUIDLow(), GetTypeId(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), pdamage, spellProto->Id,absorb);
1234 switch(mod->m_auraname)
1236 case SPELL_AURA_PERIODIC_DAMAGE:
1237 case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
1239 pdamage = SpellDamageBonus(pVictim,spellProto,pdamage,DOT);
1241 if(mod->m_auraname == SPELL_AURA_PERIODIC_DAMAGE_PERCENT)
1242 pdamage = GetHealth()*(100+mod->m_amount)/100;
1244 WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
1245 data.append(pVictim->GetPackGUID());
1246 data.append(GetPackGUID());
1247 data << uint32(spellProto->Id);
1248 data << uint32(1);
1249 data << uint32(mod->m_auraname);
1250 data << (uint32)pdamage;
1251 data << (uint32)spellProto->School;
1252 data << (uint32)absorb;
1253 data << (uint32)resist;
1254 SendMessageToSet(&data,true);
1256 DealDamage(pVictim, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), &cleanDamage, DOT, SpellSchools(spellProto->School), spellProto, procFlag, true);
1257 ProcDamageAndSpell(pVictim, PROC_FLAG_HIT_SPELL, PROC_FLAG_TAKE_DAMAGE, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), spellProto);
1258 break;
1260 case SPELL_AURA_PERIODIC_HEAL:
1261 case SPELL_AURA_OBS_MOD_HEALTH:
1263 pdamage = SpellHealingBonus(spellProto, pdamage, DOT, pVictim);
1265 WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
1266 data.append(pVictim->GetPackGUID());
1267 data.append(GetPackGUID());
1268 data << uint32(spellProto->Id);
1269 data << uint32(1);
1270 data << uint32(mod->m_auraname);
1271 data << (uint32)pdamage;
1272 SendMessageToSet(&data,true);
1274 int32 gain = pVictim->ModifyHealth(pdamage);
1275 pVictim->getHostilRefManager().threatAssist(this, float(gain) * 0.5f, spellProto);
1277 // heal for caster damage
1278 if(pVictim!=this && spellProto->SpellVisual==163)
1280 uint32 dmg = spellProto->manaPerSecond;
1281 if(GetHealth() <= dmg && GetTypeId()==TYPEID_PLAYER)
1283 RemoveAurasDueToSpell(spellProto->Id);
1285 // finish current generic/channeling spells, don't affect autorepeat
1286 if(m_currentSpells[CURRENT_GENERIC_SPELL])
1288 m_currentSpells[CURRENT_GENERIC_SPELL]->finish();
1290 if(m_currentSpells[CURRENT_CHANNELED_SPELL])
1292 m_currentSpells[CURRENT_CHANNELED_SPELL]->SendChannelUpdate(0);
1293 m_currentSpells[CURRENT_CHANNELED_SPELL]->finish();
1296 else
1298 SendSpellNonMeleeDamageLog(this, spellProto->Id, gain, SpellSchools(spellProto->School), 0, 0, false, 0, false);
1299 DealDamage(this, gain, &cleanDamage, NODAMAGE, SpellSchools(spellProto->School), spellProto, PROC_FLAG_HEAL, true);
1303 if(mod->m_auraname == SPELL_AURA_PERIODIC_HEAL && pVictim != this)
1304 ProcDamageAndSpell(pVictim, PROC_FLAG_HEAL, PROC_FLAG_HEALED, pdamage, spellProto);
1305 break;
1307 case SPELL_AURA_PERIODIC_LEECH:
1309 float multiplier = spellProto->EffectMultipleValue[effect_idx] > 0 ? spellProto->EffectMultipleValue[effect_idx] : 1;
1310 uint32 pdamage = mod->m_amount;
1312 pdamage = SpellDamageBonus(pVictim,spellProto,pdamage,DOT);
1314 if(pVictim->GetHealth() < pdamage)
1315 pdamage = uint32(pVictim->GetHealth());
1317 SendSpellNonMeleeDamageLog(pVictim, spellProto->Id, pdamage, SpellSchools(spellProto->School), absorb, resist, false, 0);
1318 DealDamage(pVictim, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), &cleanDamage, DOT, SpellSchools(spellProto->School), spellProto, procFlag, false);
1319 ProcDamageAndSpell(pVictim, PROC_FLAG_HIT_SPELL, PROC_FLAG_TAKE_DAMAGE, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), spellProto);
1320 if (!pVictim->isAlive() && IsNonMeleeSpellCasted(false))
1322 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
1324 if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id == spellProto->Id)
1325 m_currentSpells[i]->cancel();
1329 int32 gain = ModifyHealth(int32(pdamage * multiplier));
1330 getHostilRefManager().threatAssist(this, float(gain) * 0.5f, spellProto);
1332 if(GetTypeId() == TYPEID_PLAYER)
1333 SendHealSpellOnPlayer(this, spellProto->Id, uint32(pdamage * multiplier));
1334 break;
1336 case SPELL_AURA_PERIODIC_MANA_LEECH:
1338 if(mod->m_miscvalue < 0 || mod->m_miscvalue > 4)
1339 break;
1341 Powers power = Powers(mod->m_miscvalue);
1343 int32 drain_amount = pVictim->GetPower(power) > pdamage ? pdamage : pVictim->GetPower(power);
1345 pVictim->ModifyPower(power, -drain_amount);
1347 float gain_multiplier = GetMaxPower(power) > 0 ? spellProto->EffectMultipleValue[effect_idx] : 0;
1349 WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
1350 data.append(pVictim->GetPackGUID());
1351 data.append(GetPackGUID());
1352 data << uint32(spellProto->Id);
1353 data << uint32(1);
1354 data << uint32(mod->m_auraname);
1355 data << (uint32)power; // power type
1356 data << (uint32)drain_amount;
1357 data << (float)gain_multiplier;
1358 SendMessageToSet(&data,true);
1360 int32 gain_amount = int32(drain_amount*gain_multiplier);
1362 if(gain_amount)
1364 int32 gain = ModifyPower(power,gain_amount);
1365 pVictim->AddThreat(this, float(gain) * 0.5f, SpellSchools(spellProto->School), spellProto);
1367 break;
1369 case SPELL_AURA_PERIODIC_ENERGIZE:
1371 if(mod->m_miscvalue < 0 || mod->m_miscvalue > 4)
1372 break;
1374 Powers power = Powers(mod->m_miscvalue);
1376 if(pVictim->GetMaxPower(power) == 0)
1377 break;
1379 WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
1380 data.append(pVictim->GetPackGUID());
1381 data.append(GetPackGUID());
1382 data << uint32(spellProto->Id);
1383 data << uint32(1);
1384 data << uint32(mod->m_auraname);
1385 data << (uint32)power; // power type
1386 data << (uint32)mod->m_amount;
1387 SendMessageToSet(&data,true);
1389 int32 gain = pVictim->ModifyPower(power,mod->m_amount);
1390 pVictim->getHostilRefManager().threatAssist(this, float(gain) * 0.5f, spellProto);
1391 break;
1393 case SPELL_AURA_OBS_MOD_MANA:
1395 if(GetMaxPower(POWER_MANA) == 0)
1396 break;
1398 WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
1399 data.append(pVictim->GetPackGUID());
1400 data.append(GetPackGUID());
1401 data << uint32(spellProto->Id);
1402 data << uint32(1);
1403 data << uint32(mod->m_auraname);
1404 data << (uint32)mod->m_amount;
1405 data << (uint32)0; // ?
1406 SendMessageToSet(&data,true);
1408 int32 gain = ModifyPower(POWER_MANA, mod->m_amount);
1409 getHostilRefManager().threatAssist(this, float(gain) * 0.5f, spellProto);
1410 break;
1415 void Unit::HandleEmoteCommand(uint32 anim_id)
1417 WorldPacket data( SMSG_EMOTE, 12 );
1418 data << anim_id << GetGUID();
1419 WPAssert(data.size() == 12);
1421 SendMessageToSet(&data, true);
1424 uint32 Unit::CalcArmorReducedDamage(Unit* pVictim, const uint32 damage)
1426 uint32 newdamage = 0;
1427 float armor = pVictim->GetArmor();
1429 float tmpvalue = 0.0;
1430 if(getLevel() <= 59) //Level 1-59
1431 tmpvalue = armor / (armor + 400.0 + 85.0 * getLevel());
1432 else if(getLevel() < 70) //Level 60-69
1433 tmpvalue = armor / (armor - 22167.5 + 467.5 * getLevel());
1434 else //Level 70+
1435 tmpvalue = armor / (armor + 10557.5);
1437 if(tmpvalue < 0.0)
1438 tmpvalue = 0.0;
1439 if(tmpvalue > 0.75)
1440 tmpvalue = 0.75;
1441 newdamage = uint32(damage - (damage * tmpvalue));
1443 return (newdamage > 1) ? newdamage : 1;
1446 void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchools school, const uint32 damage, uint32 *absorb, uint32 *resist)
1448 if(!pVictim || !pVictim->isAlive() || !damage)
1449 return;
1451 // Magic damage, check for resists
1452 if (school != SPELL_SCHOOL_NORMAL)
1454 int32 tmpvalue2 = pVictim->GetResistance(school);
1455 AuraList const& mModTargetRes = GetAurasByType(SPELL_AURA_MOD_TARGET_RESISTANCE);
1456 for(AuraList::const_iterator i = mModTargetRes.begin(); i != mModTargetRes.end(); ++i)
1457 if ((*i)->GetModifier()->m_miscvalue & int32(1 << school))
1458 tmpvalue2 += (*i)->GetModifier()->m_amount;
1459 if (tmpvalue2 < 0) tmpvalue2 = 0;
1460 *resist += uint32(damage*tmpvalue2*0.0025*pVictim->getLevel()/getLevel());
1461 if(*resist > damage)
1462 *resist = damage;
1464 else
1465 *resist = 0;
1467 int32 RemainingDamage = damage - *resist;
1468 int32 currentAbsorb, manaReduction, maxAbsorb;
1469 float manaMultiplier;
1471 if (school == SPELL_SCHOOL_NORMAL)
1473 AuraList const& vManaShield = pVictim->GetAurasByType(SPELL_AURA_MANA_SHIELD);
1474 for(AuraList::const_iterator i = vManaShield.begin(), next; i != vManaShield.end() && RemainingDamage >= 0; i = next)
1476 next = i; next++;
1477 if (RemainingDamage - (*i)->m_absorbDmg >= 0)
1478 currentAbsorb = (*i)->m_absorbDmg;
1479 else
1480 currentAbsorb = RemainingDamage;
1482 manaMultiplier = (*i)->GetSpellProto()->EffectMultipleValue[(*i)->GetEffIndex()];
1483 maxAbsorb = int32(pVictim->GetPower(POWER_MANA) / manaMultiplier);
1484 if (currentAbsorb > maxAbsorb)
1485 currentAbsorb = maxAbsorb;
1487 (*i)->m_absorbDmg -= currentAbsorb;
1488 if((*i)->m_absorbDmg <= 0)
1490 pVictim->RemoveAurasDueToSpell((*i)->GetId());
1491 next = vManaShield.begin();
1494 manaReduction = int32(currentAbsorb * manaMultiplier);
1495 pVictim->ApplyPowerMod(POWER_MANA, manaReduction, false);
1497 RemainingDamage -= currentAbsorb;
1501 AuraList const& vSchoolAbsorb = pVictim->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB);
1502 for(AuraList::const_iterator i = vSchoolAbsorb.begin(), next; i != vSchoolAbsorb.end() && RemainingDamage >= 0; i = next)
1504 next = i; next++;
1505 if ((*i)->GetModifier()->m_miscvalue & int32(1<<school))
1507 if (RemainingDamage - (*i)->m_absorbDmg >= 0)
1509 currentAbsorb = (*i)->m_absorbDmg;
1510 pVictim->RemoveAurasDueToSpell((*i)->GetId());
1511 next = vSchoolAbsorb.begin();
1513 else
1515 currentAbsorb = RemainingDamage;
1516 (*i)->m_absorbDmg -= RemainingDamage;
1519 RemainingDamage -= currentAbsorb;
1523 *absorb = damage - RemainingDamage - *resist;
1526 void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDamage, uint32 *blocked_amount, SpellSchools damageType, uint32 *hitInfo, uint32 *victimState, uint32 *absorbDamage, uint32 *resistDamage, WeaponAttackType attType, SpellEntry const *spellCasted, bool isTriggeredSpell)
1528 pVictim->ModifyAuraState(AURA_STATE_PARRY, false);
1529 pVictim->ModifyAuraState(AURA_STATE_DEFENSE, false);
1530 ModifyAuraState(AURA_STATE_CRIT, false);
1532 MeleeHitOutcome outcome;
1534 // If is casted Melee spell, calculate like physical
1535 if(!spellCasted)
1536 outcome = RollMeleeOutcomeAgainst (pVictim, attType);
1537 else
1538 outcome = RollPhysicalOutcomeAgainst (pVictim, attType, spellCasted);
1540 if (outcome == MELEE_HIT_MISS)
1542 *hitInfo |= HITINFO_MISS;
1543 *damage = 0;
1544 cleanDamage->damage = 0;
1545 if(GetTypeId()== TYPEID_PLAYER)
1546 ((Player*)this)->UpdateWeaponSkill(attType);
1547 return;
1550 /// If this is a creature and it attacks from behind it has a probability to daze it's victim
1551 if( (outcome==MELEE_HIT_CRIT || outcome==MELEE_HIT_CRUSHING || outcome==MELEE_HIT_NORMAL || outcome==MELEE_HIT_GLANCING) &&
1552 GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->GetCharmerOrOwnerGUID() && !pVictim->HasInArc(M_PI, this) )
1554 // -probability is between 0% and 40%
1555 // 20% base chance
1556 float Probability = 20;
1558 //there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1559 if( pVictim->getLevel() < 30 )
1560 Probability = 0.65f*pVictim->getLevel()+0.5;
1562 uint32 VictimDefense=pVictim->GetDefenseSkillValue();
1563 uint32 AttackerMeleeSkill=GetUnitMeleeSkill();
1565 Probability *= AttackerMeleeSkill/(float)VictimDefense;
1567 if(Probability > 40)
1568 Probability = 40;
1570 if(roll_chance_f(Probability))
1571 CastSpell(pVictim, 1604, true);
1574 *damage += CalculateDamage (attType);
1576 //Calculate the damage after armor mitigation if SPELL_SCHOOL_NORMAL
1577 if (damageType == SPELL_SCHOOL_NORMAL)
1579 uint32 damageAfterArmor = CalcArmorReducedDamage(pVictim, *damage);
1580 cleanDamage->damage += *damage - damageAfterArmor;
1581 *damage = damageAfterArmor;
1583 // Instant Attacks (Spellmods)
1584 // TODO: AP bonus related to mainhand weapon
1585 if(spellCasted)
1586 if(GetTypeId()== TYPEID_PLAYER)
1587 ((Player*)this)->ApplySpellMod(spellCasted->Id, SPELLMOD_DAMAGE, *damage);
1589 if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER )
1590 ((Player*)this)->UpdateCombatSkills(pVictim, attType, outcome, false);
1592 if(GetTypeId() != TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
1593 ((Player*)pVictim)->UpdateCombatSkills(this, attType, outcome, true);
1595 switch (outcome)
1597 case MELEE_HIT_CRIT:
1598 //*hitInfo = 0xEA;
1599 // 0xEA
1600 *hitInfo = HITINFO_CRITICALHIT | HITINFO_NORMALSWING2 | 0x8;
1602 // Crit bonus calc
1603 uint32 crit_bonus;
1604 crit_bonus = *damage;
1606 // Apply crit_damage bonus for melee spells
1607 if (GetTypeId() == TYPEID_PLAYER && spellCasted)
1609 ((Player*)this)->ApplySpellMod(spellCasted->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
1612 *damage += crit_bonus;
1614 // Resilience - reduce crit damage by 2x%
1615 uint32 resilienceReduction;
1616 resilienceReduction = uint32(pVictim->m_modResilience * 2/100 * (*damage));
1617 *damage -= resilienceReduction;
1618 cleanDamage->damage += resilienceReduction;
1620 if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER )
1621 ((Player*)this)->UpdateWeaponSkill(attType);
1623 ModifyAuraState(AURA_STATE_CRIT, true);
1625 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL);
1626 break;
1628 case MELEE_HIT_PARRY:
1629 if(attType == RANGED_ATTACK) //range attack - no parry
1630 break;
1632 cleanDamage->damage += *damage;
1633 *damage = 0;
1634 *victimState = VICTIMSTATE_PARRY;
1636 // instant (maybe with small delay) counter attack
1638 float offtime = float(pVictim->getAttackTimer(OFF_ATTACK));
1639 float basetime = float(pVictim->getAttackTimer(BASE_ATTACK));
1641 // after parry nearest next attack time will reduced at %40 from full attack time.
1642 // The delay cannot be reduced to less than 20% of your weapon’s base swing delay.
1643 if (pVictim->haveOffhandWeapon() && offtime < basetime)
1645 float percent20 = pVictim->GetAttackTime(OFF_ATTACK)*0.20;
1646 float percent60 = 3*percent20;
1647 // set to 20% if in range 20%...20+40% of full time
1648 if(offtime > percent20 && offtime <= percent60)
1650 pVictim->setAttackTimer(OFF_ATTACK,uint32(percent20));
1652 // decrease at %40 from full time
1653 else if(offtime > percent60)
1655 offtime -= 2*percent20;
1656 pVictim->setAttackTimer(OFF_ATTACK,uint32(offtime));
1658 // ELSE not changed
1660 else
1662 float percent20 = pVictim->GetAttackTime(BASE_ATTACK)*0.20;
1663 float percent60 = 3*percent20;
1664 // set to 20% if in range 20%...20+40% of full time
1665 if(basetime > percent20 && basetime <= percent60)
1667 pVictim->setAttackTimer(BASE_ATTACK,uint32(percent20));
1669 // decrease at %40 from full time
1670 else if(basetime > percent60)
1672 basetime -= 2*percent20;
1673 pVictim->setAttackTimer(BASE_ATTACK,uint32(basetime));
1675 // ELSE not changed
1679 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1680 ((Player*)pVictim)->UpdateDefense();
1682 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
1683 pVictim->ModifyAuraState(AURA_STATE_PARRY,true);
1684 if (pVictim->getClass() != CLASS_HUNTER) // Mongoose Bite
1685 pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true);
1687 CastMeleeProcDamageAndSpell(pVictim, 0, attType, outcome, spellCasted, isTriggeredSpell);
1688 return;
1690 case MELEE_HIT_DODGE:
1691 if(attType == RANGED_ATTACK) //range attack - no dodge
1692 break;
1693 cleanDamage->damage += *damage;
1694 *damage = 0;
1695 *victimState = VICTIMSTATE_DODGE;
1697 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1698 ((Player*)pVictim)->UpdateDefense();
1700 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
1702 if (pVictim->getClass() != CLASS_ROGUE) // Riposte
1703 pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true);
1705 CastMeleeProcDamageAndSpell(pVictim, 0, attType, outcome, spellCasted, isTriggeredSpell);
1706 return;
1708 case MELEE_HIT_BLOCK:
1709 *blocked_amount = uint32(pVictim->GetShieldBlockValue() + (pVictim->GetStat(STAT_STRENGTH) / 20.0f) -1);
1711 if (pVictim->GetUnitBlockChance())
1712 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD);
1713 else
1714 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
1716 //Only set VICTIMSTATE_BLOCK on a full block
1717 if (*blocked_amount >= *damage)
1719 *victimState = VICTIMSTATE_BLOCKS;
1720 *blocked_amount = *damage;
1723 if(pVictim->GetTypeId() == TYPEID_PLAYER)
1724 ((Player*)pVictim)->UpdateDefense();
1725 pVictim->ModifyAuraState(AURA_STATE_DEFENSE,true);
1726 break;
1728 case MELEE_HIT_GLANCING:
1730 float reducePercent = 1.0f; //damage factor
1732 // calculate base values and mods
1733 float baseLowEnd = 1.3;
1734 float baseHighEnd = 1.2;
1735 switch(getClass()) // lowering base values for casters
1737 case CLASS_SHAMAN:
1738 case CLASS_PRIEST:
1739 case CLASS_MAGE:
1740 case CLASS_WARLOCK:
1741 case CLASS_DRUID:
1742 baseLowEnd -= 0.7;
1743 baseHighEnd -= 0.3;
1744 break;
1747 float maxLowEnd = 0.6;
1748 switch(getClass()) // upper for melee classes
1750 case CLASS_WARRIOR:
1751 case CLASS_ROGUE:
1752 maxLowEnd = 0.91; //If the attacker is a melee class then instead the lower value of 0.91
1755 // calculate values
1756 int32 diff = pVictim->GetDefenseSkillValue() - GetWeaponSkillValue(attType);
1757 float lowEnd = baseLowEnd - ( 0.05f * diff );
1758 float highEnd = baseHighEnd - ( 0.03f * diff );
1760 // apply max/min bounds
1761 if ( lowEnd < 0.01f ) //the low end must not go bellow 0.01f
1762 lowEnd = 0.01f;
1763 else if ( lowEnd > maxLowEnd ) //the smaller value of this and 0.6 is kept as the low end
1764 lowEnd = maxLowEnd;
1766 if ( highEnd < 0.2f ) //high end limits
1767 highEnd = 0.2f;
1768 if ( highEnd > 0.99f )
1769 highEnd = 0.99f;
1771 if(lowEnd > highEnd) // prevent negative range size
1772 lowEnd = highEnd;
1774 reducePercent = lowEnd + rand_norm() * ( highEnd - lowEnd );
1776 *damage = uint32(reducePercent * *damage);
1777 cleanDamage->damage += *damage;
1778 *hitInfo |= HITINFO_GLANCING;
1779 break;
1781 case MELEE_HIT_CRUSHING:
1783 // 150% normal damage
1784 *damage += (*damage / 2);
1785 cleanDamage->damage = *damage;
1786 *hitInfo |= HITINFO_CRUSHING;
1787 // TODO: victimState, victim animation?
1788 break;
1790 default:
1791 break;
1794 // apply melee damage bonus and absorb only if base damage not fully blocked to prevent negative damage or damage with full block
1795 if(*victimState != VICTIMSTATE_BLOCKS)
1797 MeleeDamageBonus(pVictim, damage,attType);
1798 CalcAbsorbResist(pVictim, damageType, *damage-*blocked_amount, absorbDamage, resistDamage);
1801 if (*absorbDamage) *hitInfo |= HITINFO_ABSORB;
1802 if (*resistDamage) *hitInfo |= HITINFO_RESIST;
1803 cleanDamage += *blocked_amount;
1805 if (*damage <= *absorbDamage + *resistDamage + *blocked_amount)
1807 //*hitInfo = 0x00010020;
1808 //*hitInfo |= HITINFO_SWINGNOHITSOUND;
1809 //*damageType = 0;
1810 CastMeleeProcDamageAndSpell(pVictim, 0, attType, outcome, spellCasted, isTriggeredSpell);
1811 return;
1814 CastMeleeProcDamageAndSpell(pVictim, (*damage - *absorbDamage - *resistDamage - *blocked_amount), attType, outcome, spellCasted, isTriggeredSpell);
1816 // victim's damage shield
1817 // yet another hack to fix crashes related to the aura getting removed during iteration
1818 std::set<Aura*> alreadyDone;
1819 uint32 removedAuras = pVictim->m_removedAuras;
1820 AuraList const& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD);
1821 for(AuraList::const_iterator i = vDamageShields.begin(), next = vDamageShields.begin(); i != vDamageShields.end(); i = next)
1823 next++;
1824 if (alreadyDone.find(*i) == alreadyDone.end())
1826 alreadyDone.insert(*i);
1827 pVictim->SpellNonMeleeDamageLog(this, (*i)->GetId(), (*i)->GetModifier()->m_amount, false, false);
1828 if (pVictim->m_removedAuras > removedAuras)
1830 removedAuras = pVictim->m_removedAuras;
1831 next = vDamageShields.begin();
1836 if (pVictim->GetTypeId() == TYPEID_PLAYER && *damage)
1838 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
1840 // skip channeled spell (processed differently below)
1841 if (i == CURRENT_CHANNELED_SPELL)
1842 continue;
1844 if(pVictim->m_currentSpells[i])
1846 sLog.outDetail("Spell Delayed!%d",(int32)(0.25f * pVictim->m_currentSpells[i]->casttime));
1847 pVictim->m_currentSpells[i]->Delayed((int32)(0.25f * pVictim->m_currentSpells[i]->casttime));
1851 // process channeled spell separately
1852 if (pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL])
1854 if (pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() == SPELL_STATE_CASTING)
1856 uint32 channelInterruptFlags = pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->ChannelInterruptFlags;
1857 if( channelInterruptFlags & CHANNEL_FLAG_DELAY )
1859 sLog.outDetail("Spell Delayed!%d",(int32)(0.25f * GetDuration(pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo)));
1860 pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->DelayedChannel((int32)(0.25f * GetDuration(pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo)));
1861 return;
1863 else if( !(channelInterruptFlags & (CHANNEL_FLAG_DAMAGE | CHANNEL_FLAG_DAMAGE2)) )
1864 return;
1866 sLog.outDetail("Spell Canceled!");
1867 pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel();
1869 else if (pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() == SPELL_STATE_DELAYED)
1871 // break channeled spell in delayed state on damage
1872 sLog.outDetail("Spell Canceled!");
1873 pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel();
1879 void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool isTriggered)
1881 if(hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNDED | UNIT_STAT_FLEEING) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED) )
1882 return;
1884 if (!pVictim->isAlive())
1885 return;
1887 if(!isTriggered)
1889 if(IsNonMeleeSpellCasted(false))
1890 return;
1892 // melee attack spell casted at main hand attack only
1893 if (m_currentSpells[CURRENT_MELEE_SPELL] && attType == BASE_ATTACK)
1895 m_currentSpells[CURRENT_MELEE_SPELL]->cast();
1896 return;
1900 uint32 hitInfo;
1901 if (attType == BASE_ATTACK)
1902 hitInfo = HITINFO_NORMALSWING2;
1903 else if (attType == OFF_ATTACK)
1904 hitInfo = HITINFO_LEFTSWING;
1905 else
1906 return;
1908 uint32 victimState = VICTIMSTATE_NORMAL;
1910 uint32 damage = 0;
1911 CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
1912 uint32 blocked_dmg = 0;
1913 uint32 absorbed_dmg = 0;
1914 uint32 resisted_dmg = 0;
1916 if( pVictim->IsImmunedToPhysicalDamage() )
1918 SendAttackStateUpdate (HITINFO_MISS, pVictim, 1, SPELL_SCHOOL_NORMAL, 0, 0, 0, VICTIMSTATE_IS_IMMUNE, 0);
1919 return;
1922 DoAttackDamage (pVictim, &damage, &cleanDamage, &blocked_dmg, SPELL_SCHOOL_NORMAL, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, attType);
1924 cleanDamage.damage += blocked_dmg;
1926 if (hitInfo & HITINFO_MISS)
1927 //send miss
1928 SendAttackStateUpdate (hitInfo, pVictim, 1, SPELL_SCHOOL_NORMAL, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg);
1929 else
1931 //do animation
1932 SendAttackStateUpdate (hitInfo, pVictim, 1, SPELL_SCHOOL_NORMAL, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg);
1934 if (damage > (absorbed_dmg + resisted_dmg + blocked_dmg))
1935 damage -= (absorbed_dmg + resisted_dmg + blocked_dmg);
1936 else
1937 damage = 0;
1939 DealDamage (pVictim, damage, &cleanDamage, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, 0, true);
1941 if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive())
1943 for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
1944 ((Player*)this)->CastItemCombatSpell(((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i),pVictim);
1948 if (GetTypeId() == TYPEID_PLAYER)
1949 DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
1950 GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, absorbed_dmg, blocked_dmg, resisted_dmg);
1951 else
1952 DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
1953 GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, absorbed_dmg, blocked_dmg, resisted_dmg);
1956 MeleeHitOutcome Unit::RollPhysicalOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo)
1958 // Miss chance based on melee
1959 int32 miss_chance = (int32)(MeleeMissChanceCalc(pVictim));
1961 // Critical hit chance
1962 float crit_chance = GetUnitCriticalChance(attType);
1964 // Only players can have Talent&Spell bonuses
1965 if (GetTypeId() == TYPEID_PLAYER)
1967 // Talents
1968 AuraList const& mSpellCritSchool = GetAurasByType(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL);
1969 for(AuraList::const_iterator i = mSpellCritSchool.begin(); i != mSpellCritSchool.end(); ++i)
1970 if((*i)->GetModifier()->m_miscvalue == -2 || ((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellInfo->School)) != 0)
1971 crit_chance += (*i)->GetModifier()->m_amount;
1973 // flat
1974 AuraList const& mAttackerSWCrit = pVictim->GetAurasByType(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
1975 for(AuraList::const_iterator i = mAttackerSWCrit.begin(); i != mAttackerSWCrit.end(); ++i)
1976 crit_chance += (*i)->GetModifier()->m_amount;
1978 // Spellmods
1979 ((Player*)this)->ApplySpellMod(spellInfo->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance);
1982 DEBUG_LOG("PHYSICAL OUTCOME: hit %u crit %f miss %u",m_modHitChance,crit_chance,miss_chance);
1984 return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance * 100 ), miss_chance, m_modHitChance);
1987 MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType) const
1989 // This is only wrapper
1991 // Miss chance based on melee
1992 int32 miss_chance = (int32)(MeleeMissChanceCalc(pVictim));
1994 // Critical hit chance
1995 float crit_chance = GetUnitCriticalChance(attType);
1997 // flat
1998 AuraList const& mAttackerSWCrit = pVictim->GetAurasByType(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
1999 for(AuraList::const_iterator i = mAttackerSWCrit.begin(); i != mAttackerSWCrit.end(); ++i)
2000 crit_chance += (*i)->GetModifier()->m_amount;
2002 // Useful if want to specify crit & miss chances for melee, else it could be removed
2003 DEBUG_LOG("MELEE OUTCOME: hit %u crit %u miss %u", m_modHitChance,crit_chance,miss_chance);
2004 return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance * 100 ), miss_chance, m_modHitChance);
2007 MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 hit_chance) const
2009 int32 skillDiff = GetWeaponSkillValue(attType) - pVictim->GetDefenseSkillValue();
2010 // bonus from skills is 0.04%
2011 int32 skillBonus = skillDiff * 4;
2012 int32 skillBonus2 = 4 * ( GetWeaponSkillValue(attType) - pVictim->GetPureDefenseSkillValue() );
2013 int32 sum = 0, tmp = 0;
2014 int32 roll = urand (0, 10000);
2016 DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus);
2017 DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, +hit %d, dodge %u, parry %u, block %u, crit %u",
2018 roll, hit_chance, (uint32)(pVictim->GetUnitDodgeChance()*100), (uint32)(pVictim->GetUnitParryChance()*100),
2019 (uint32)(pVictim->GetUnitBlockChance()*100), crit_chance);
2021 // dual wield has 24% base chance to miss instead of 5%, also
2022 // base miss rate is 5% and can't get higher than 60%
2024 // Inherit if passed
2025 tmp = miss_chance - skillBonus;
2027 if(tmp > 6000)
2028 tmp = 6000;
2030 if (tmp > 0 && roll < (sum += tmp ))
2032 DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS");
2033 return MELEE_HIT_MISS;
2036 // always crit against a sitting target (except 0 crit chance)
2037 if( (pVictim->GetTypeId() == TYPEID_PLAYER) && crit_chance > 0 &&
2038 (((Player*)pVictim)->getStandState() & (PLAYER_STATE_SLEEP | PLAYER_STATE_SIT
2039 | PLAYER_STATE_SIT_CHAIR
2040 | PLAYER_STATE_SIT_LOW_CHAIR
2041 | PLAYER_STATE_SIT_MEDIUM_CHAIR
2042 | PLAYER_STATE_SIT_HIGH_CHAIR)))
2044 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)");
2045 return MELEE_HIT_CRIT;
2048 // stunned target cannot dodge and this is check in GetUnitDodgeChance()
2049 tmp = (int32)(pVictim->GetUnitDodgeChance()*100) - skillBonus2;
2050 if (tmp > 0 && roll < (sum += tmp))
2052 DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum-tmp, sum);
2053 return MELEE_HIT_DODGE;
2056 int32 modCrit = 0;
2058 // check if attack comes from behind
2059 if (!pVictim->HasInArc(M_PI,this))
2061 // ASSUME +10% crit from behind
2062 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind.");
2063 modCrit += 1000;
2065 else
2067 // cannot parry or block attacks from behind, but can from forward
2068 tmp = (int32)(pVictim->GetUnitParryChance()*100);
2069 if ( (tmp > 0) // check if unit _can_ parry
2070 && ((tmp -= skillBonus2) > 0)
2071 && (roll < (sum += tmp)))
2073 DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum-tmp, sum);
2074 return MELEE_HIT_PARRY;
2077 tmp = (int32)(pVictim->GetUnitBlockChance()*100);
2078 if ( (tmp > 0) // check if unit _can_ block
2079 && ((tmp -= skillBonus2) > 0)
2080 && (roll < (sum += tmp)))
2082 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum-tmp, sum);
2083 return MELEE_HIT_BLOCK;
2087 // Resilience - reduce crit chance by x%
2088 modCrit -= int32(pVictim->m_modResilience*100);
2090 // Critical chance
2091 tmp = crit_chance + skillBonus + modCrit;
2093 if (tmp > 0 && roll < (sum += tmp))
2095 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum-tmp, sum);
2096 return MELEE_HIT_CRIT;
2099 // Max 40% chance to score a glancing blow against mobs that are higher level
2100 if( GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && getLevel() < pVictim->getLevel() )
2102 // cap possible value (with bonuses > max skill)
2103 int32 skill = GetWeaponSkillValue(attType);
2104 int32 maxskill = GetMaxSkillValueForLevel();
2105 skill = (skill > maxskill) ? maxskill : skill;
2107 tmp = (10 + (pVictim->GetDefenseSkillValue() - skill)) * 100;
2108 tmp = tmp > 4000 ? 4000 : tmp;
2109 if (roll < (sum += tmp))
2111 DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum-4000, sum);
2112 return MELEE_HIT_GLANCING;
2116 // mobs can score crushing blows if they're 3 or more levels above victim
2117 // or when their weapon skill is 15 or more above victim's defense skill
2118 tmp = pVictim->GetDefenseSkillValue();
2119 int32 tmpmax = pVictim->GetMaxSkillValueForLevel();
2120 // having defense above your maximum (from items, talents etc.) has no effect
2121 tmp = tmp > tmpmax ? tmpmax : tmp;
2122 // tmp = mob's level * 5 - player's current defense skill
2123 tmp = GetMaxSkillValueForLevel() - tmp;
2124 if (GetTypeId() != TYPEID_PLAYER && (tmp >= 15))
2126 // add 2% chance per lacking skill point, min. is 15%
2127 tmp = tmp * 200 - 1500;
2128 if (roll < (sum += tmp))
2130 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum-tmp, sum);
2131 return MELEE_HIT_CRUSHING;
2135 DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL");
2136 return MELEE_HIT_NORMAL;
2139 uint32 Unit::CalculateDamage (WeaponAttackType attType)
2141 float min_damage, max_damage;
2143 switch (attType)
2145 case RANGED_ATTACK:
2146 min_damage = GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE);
2147 max_damage = GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE);
2148 break;
2149 case BASE_ATTACK:
2150 min_damage = GetFloatValue(UNIT_FIELD_MINDAMAGE);
2151 max_damage = GetFloatValue(UNIT_FIELD_MAXDAMAGE);
2152 break;
2153 case OFF_ATTACK:
2154 min_damage = GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE);
2155 max_damage = GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE);
2156 break;
2159 if (min_damage > max_damage)
2161 std::swap(min_damage,max_damage);
2164 if(max_damage == 0.0)
2165 max_damage = 5.0;
2167 return rand32((uint32)min_damage, (uint32)max_damage);
2170 void Unit::SendAttackStart(Unit* pVictim)
2172 if(GetTypeId()!=TYPEID_PLAYER || !pVictim)
2173 return;
2175 WorldPacket data( SMSG_ATTACKSTART, 16 );
2176 data << GetGUID();
2177 data << pVictim->GetGUID();
2179 ((Player*)this)->SendMessageToSet(&data, true);
2180 DEBUG_LOG( "WORLD: Sent SMSG_ATTACKSTART" );
2183 void Unit::SendAttackStop(Unit* victim)
2185 if(!victim)
2186 return;
2188 WorldPacket data( SMSG_ATTACKSTOP, (4+16) ); // we guess size
2189 data.append(GetPackGUID());
2190 data.append(victim->GetPackGUID()); // can be 0x00...
2191 data << uint32(0); // can be 0x1
2192 SendMessageToSet(&data, true);
2193 sLog.outDetail("%s %u stopped attacking %s %u", (GetTypeId()==TYPEID_PLAYER ? "player" : "creature"), GetGUIDLow(), (victim->GetTypeId()==TYPEID_PLAYER ? "player" : "creature"),victim->GetGUIDLow());
2195 /*if(victim->GetTypeId() == TYPEID_UNIT)
2196 ((Creature*)victim)->AI().EnterEvadeMode(this);*/
2199 uint32 Unit::SpellMissChanceCalc(Unit *pVictim) const
2201 if(!pVictim)
2202 return 0;
2204 // PvP : PvE spell misschances per leveldif > 2
2205 int32 chance = pVictim->GetTypeId() == TYPEID_PLAYER ? 700 : 1100;
2207 int32 leveldif = pVictim->getLevel() - getLevel();
2208 if(leveldif < 0)
2209 leveldif = 0;
2211 int32 misschance = 400 - m_modSpellHitChance*100;
2212 if(leveldif < 3)
2213 misschance += leveldif * 100;
2214 else
2215 misschance += (leveldif - 2) * chance;
2217 return misschance < 100 ? 100 : misschance;
2220 int32 Unit::MeleeMissChanceCalc(const Unit *pVictim) const
2222 if(!pVictim)
2223 return 0;
2225 // Base misschance 5%
2226 int32 misschance = 500;
2228 // DualWield - Melee spells and physical dmg spells - 5% , white damage 24%
2229 if (haveOffhandWeapon())
2231 bool isNormal = false;
2232 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
2234 if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->School == SPELL_SCHOOL_NORMAL)
2236 isNormal = true;
2237 break;
2240 if (isNormal || m_currentSpells[CURRENT_MELEE_SPELL])
2242 misschance = 500;
2244 else
2246 misschance = 2400;
2250 // PvP : PvE melee misschances per leveldif > 2
2251 int32 chance = pVictim->GetTypeId() == TYPEID_PLAYER ? 500 : 700;
2253 int32 leveldif = pVictim->getLevel() - getLevel();
2254 if(leveldif < 0)
2255 leveldif = 0;
2257 if(leveldif < 3)
2258 misschance += leveldif * 100 - m_modHitChance*100;
2259 else
2260 misschance += (leveldif - 2) * chance - m_modHitChance*100;
2262 return misschance > 6000 ? 6000 : misschance;
2265 uint16 Unit::GetDefenseSkillValue() const
2267 if(GetTypeId() == TYPEID_PLAYER)
2268 return ((Player*)this)->GetSkillValue (SKILL_DEFENSE);
2269 else
2270 return GetUnitMeleeSkill();
2273 uint16 Unit::GetPureDefenseSkillValue() const
2275 if(GetTypeId() == TYPEID_PLAYER)
2276 return ((Player*)this)->GetPureSkillValue(SKILL_DEFENSE);
2277 else
2278 return GetUnitMeleeSkill();
2281 float Unit::GetUnitDodgeChance() const
2283 if(hasUnitState(UNIT_STAT_STUNDED))
2284 return 0;
2285 return GetTypeId() == TYPEID_PLAYER ? GetFloatValue(PLAYER_DODGE_PERCENTAGE) : 5;
2288 float Unit::GetUnitParryChance() const
2290 float chance = 0;
2291 if(GetTypeId() == TYPEID_PLAYER)
2293 Player const* player = (Player const*)this;
2294 if(player->CanParry() && player->IsUseEquipedWeapon() )
2296 Item *tmpitem = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
2297 if(!tmpitem || tmpitem->IsBroken())
2298 tmpitem = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
2300 if(tmpitem && !tmpitem->IsBroken() && (
2301 tmpitem->GetProto()->InventoryType == INVTYPE_WEAPON ||
2302 tmpitem->GetProto()->InventoryType == INVTYPE_WEAPONOFFHAND ||
2303 tmpitem->GetProto()->InventoryType == INVTYPE_WEAPONMAINHAND ||
2304 tmpitem->GetProto()->InventoryType == INVTYPE_2HWEAPON))
2305 chance = GetFloatValue(PLAYER_PARRY_PERCENTAGE);
2308 else if(GetTypeId() == TYPEID_UNIT)
2310 if(GetCreatureType() == CREATURE_TYPE_HUMANOID)
2311 chance = 5;
2314 return chance;
2317 float Unit::GetUnitBlockChance() const
2319 float chance = 0;
2320 if(GetTypeId() == TYPEID_PLAYER)
2322 Item *tmpitem = ((Player const*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
2323 if(tmpitem && !tmpitem->IsBroken() && tmpitem->GetProto()->Block)
2324 chance = GetFloatValue(PLAYER_BLOCK_PERCENTAGE);
2326 else
2327 chance = 5;
2329 return chance;
2332 uint16 Unit::GetWeaponSkillValue (WeaponAttackType attType) const
2334 if(GetTypeId() == TYPEID_PLAYER)
2336 uint16 slot;
2337 switch (attType)
2339 case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
2340 case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
2341 case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
2342 default:
2343 return 0;
2345 Item *item = ((Player*)this)->GetItemByPos (INVENTORY_SLOT_BAG_0, slot);
2347 if(slot != EQUIPMENT_SLOT_MAINHAND && (!item || item->IsBroken() ||
2348 item->GetProto()->Class != ITEM_CLASS_WEAPON || !((Player*)this)->IsUseEquipedWeapon() ))
2349 return 0;
2351 // in range
2352 uint32 skill = item && !item->IsBroken() && ((Player*)this)->IsUseEquipedWeapon()
2353 ? item->GetSkill() : SKILL_UNARMED;
2354 return ((Player*)this)->GetSkillValue (skill);
2356 else
2357 return GetUnitMeleeSkill();
2360 uint16 Unit::GetPureWeaponSkillValue (WeaponAttackType attType) const
2362 if(GetTypeId() == TYPEID_PLAYER)
2364 uint16 slot;
2365 switch (attType)
2367 case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
2368 case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
2369 case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
2370 default:
2371 return 0;
2373 Item *item = ((Player*)this)->GetItemByPos (INVENTORY_SLOT_BAG_0, slot);
2375 if(slot != EQUIPMENT_SLOT_MAINHAND && (!item || item->IsBroken() ||
2376 item->GetProto()->Class != ITEM_CLASS_WEAPON || !((Player*)this)->IsUseEquipedWeapon() ))
2377 return 0;
2379 // in range
2380 uint32 skill = item && !item->IsBroken() && ((Player*)this)->IsUseEquipedWeapon()
2381 ? item->GetSkill() : SKILL_UNARMED;
2382 return ((Player*)this)->GetPureSkillValue (skill);
2384 else
2385 return GetUnitMeleeSkill();
2388 void Unit::_UpdateSpells( uint32 time )
2390 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
2391 _UpdateAutoRepeatSpell( time );
2393 // remove finished spells from current pointers
2394 for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
2396 if (m_currentSpells[i] && m_currentSpells[i]->getState() == SPELL_STATE_FINISHED)
2398 m_currentSpells[i]->SetDeletable(true); // spell may be safely deleted now
2399 m_currentSpells[i] = NULL; // remove pointer
2403 // TODO: Find a better way to prevent crash when multiple auras are removed.
2404 m_removedAuras = 0;
2405 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
2406 if ((*i).second)
2407 (*i).second->SetUpdated(false);
2409 for (AuraMap::iterator i = m_Auras.begin(), next; i != m_Auras.end(); i = next)
2411 next = i;
2412 next++;
2413 if ((*i).second)
2415 // prevent double update
2416 if ((*i).second->IsUpdated())
2417 continue;
2418 (*i).second->SetUpdated(true);
2419 (*i).second->Update( time );
2420 // several auras can be deleted due to update
2421 if (m_removedAuras)
2423 if (m_Auras.empty()) break;
2424 next = m_Auras.begin();
2425 m_removedAuras = 0;
2430 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end();)
2432 if ((*i).second)
2434 if ( !(*i).second->GetAuraDuration() && !((*i).second->IsPermanent() || ((*i).second->IsPassive())) )
2436 RemoveAura(i);
2438 else
2440 ++i;
2443 else
2445 ++i;
2449 if(!m_gameObj.empty())
2451 std::list<GameObject*>::iterator ite1, dnext1;
2452 for (ite1 = m_gameObj.begin(); ite1 != m_gameObj.end(); ite1 = dnext1)
2454 dnext1 = ite1;
2455 //(*i)->Update( difftime );
2456 if( !(*ite1)->isSpawned() )
2458 (*ite1)->SetOwnerGUID(0);
2459 (*ite1)->SetRespawnTime(0);
2460 (*ite1)->Delete();
2461 dnext1 = m_gameObj.erase(ite1);
2463 else
2464 ++dnext1;
2469 void Unit::_UpdateAutoRepeatSpell( uint32 time )
2471 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_FINISHED)
2473 //Auto Shot & Shoot
2474 if( m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->AttributesEx2 == 0x000020 && GetTypeId() == TYPEID_PLAYER )
2476 // Auto Shot don't require ranged weapon cooldown at first cast, wand shoot does, so the 'FINISHED' state
2477 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
2479 // Shoot
2480 resetAttackTimer( RANGED_ATTACK );
2482 else
2484 // Auto Shoot
2485 if (m_AutoRepeatFirstCast)
2487 // first cast only with recovery time (not less)
2488 if (getAttackTimer( RANGED_ATTACK ) < m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->RecoveryTime)
2489 setAttackTimer( RANGED_ATTACK, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->RecoveryTime);
2490 m_AutoRepeatFirstCast = false;
2492 else
2494 // second or further casts
2495 resetAttackTimer( RANGED_ATTACK );
2499 else
2501 setAttackTimer( RANGED_ATTACK, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->RecoveryTime);
2504 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_IDLE);
2506 else if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_IDLE && isAttackReady(RANGED_ATTACK) )
2508 // check if we can cast
2509 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast() == 0)
2511 // check movement in player case
2512 if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isMoving())
2514 // cancel wand shooting
2515 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
2516 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
2517 // ELSE delay auto-repeat ranged weapon until player movement stop
2519 else
2520 // recheck range and req. items (ammo and gun, etc)
2521 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckRange() == 0 && m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckItems() == 0 )
2523 // check, if we are casting melee spell (it blocks autorepeat)
2524 if ( ! (m_currentSpells[CURRENT_MELEE_SPELL] &&
2525 (m_currentSpells[CURRENT_MELEE_SPELL]->getState() != SPELL_STATE_FINISHED) &&
2526 (m_currentSpells[CURRENT_MELEE_SPELL]->getState() != SPELL_STATE_DELAYED)) )
2528 // check, if we are casting something else, if no then run autorepeat spell
2529 if (!IsNonMeleeSpellCasted(false, false, true))
2531 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_PREPARING);
2532 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->ReSetTimer();
2536 else
2538 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
2541 else
2543 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
2546 else if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() == SPELL_STATE_PREPARING)
2548 // check, if some other incomplete spell exists (including melee) or ranged attack is not ready
2549 if ( m_currentSpells[CURRENT_MELEE_SPELL] ||
2550 m_currentSpells[CURRENT_GENERIC_SPELL] ||
2551 m_currentSpells[CURRENT_CHANNELED_SPELL] ||
2552 !isAttackReady(RANGED_ATTACK) )
2554 // some other spell is here or ranged attack is not ready, break us to idle state
2555 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->finish(false);
2556 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->setState(SPELL_STATE_IDLE);
2561 void Unit::SetCurrentCastedSpell( Spell * pSpell )
2563 assert(pSpell); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
2565 uint32 CSpellType = pSpell->GetCurrentContainer();
2567 pSpell->SetDeletable(false); // spell will not be deleted until gone from current pointers
2568 if (pSpell == m_currentSpells[CSpellType]) return; // avoid breaking self
2570 // break same type spell if it is not delayed
2571 if ( m_currentSpells[CSpellType] &&
2572 m_currentSpells[CSpellType]->getState() != SPELL_STATE_DELAYED )
2574 InterruptSpell(CSpellType);
2577 // special breakage effects:
2578 switch (CSpellType)
2580 case CURRENT_GENERIC_SPELL:
2582 // generic spells always break channeled not delayed spells
2583 if ( m_currentSpells[CURRENT_CHANNELED_SPELL] &&
2584 m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_DELAYED )
2586 InterruptSpell(CURRENT_CHANNELED_SPELL);
2589 // autorepeat breaking
2590 if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL] )
2592 // break autorepeat if not Auto Shot
2593 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
2594 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
2596 } break;
2598 case CURRENT_CHANNELED_SPELL:
2600 // channel spells always break generic and channeled spells
2601 InterruptSpell(CURRENT_GENERIC_SPELL);
2602 InterruptSpell(CURRENT_CHANNELED_SPELL);
2604 // it also does break autorepeat if not Auto Shot
2605 if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL] &&
2606 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351 )
2607 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
2608 } break;
2610 case CURRENT_AUTOREPEAT_SPELL:
2612 // only Auto Shoot does not break anything
2613 if (pSpell->m_spellInfo->Category == 351)
2615 // generic autorepeats break generic and channeled spells
2616 InterruptSpell(CURRENT_GENERIC_SPELL);
2617 InterruptSpell(CURRENT_CHANNELED_SPELL);
2619 else
2621 // special action: set first cast flag for Auto Shoot
2622 m_AutoRepeatFirstCast = true;
2624 } break;
2626 default:
2628 // other spell types don't break anything now
2629 } break;
2632 // current spell (if it is still here) may be safely deleted now
2633 if (m_currentSpells[CSpellType])
2634 m_currentSpells[CSpellType]->SetDeletable(true);
2636 // set new current spell
2637 m_currentSpells[CSpellType] = pSpell;
2640 void Unit::InterruptSpell(uint32 spellType)
2642 assert(spellType < CURRENT_MAX_SPELL);
2644 if(m_currentSpells[spellType])
2646 // send autorepeat cancel message for autorepeat spells
2647 if (spellType == CURRENT_AUTOREPEAT_SPELL)
2649 if(GetTypeId()==TYPEID_PLAYER)
2650 ((Player*)this)->SendAutoRepeatCancel();
2653 if (m_currentSpells[spellType]->getState() != SPELL_STATE_FINISHED)
2654 m_currentSpells[spellType]->cancel();
2655 m_currentSpells[spellType]->SetDeletable(true);
2656 m_currentSpells[spellType] = NULL;
2660 bool Unit::IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled, bool skipAutorepeat)
2662 // We don't do loop here to explicitly show that melee spell is excluded.
2663 // Maybe later some special spells will be excluded too.
2665 // generic spells are casted when they are not finished and not delayed
2666 if ( m_currentSpells[CURRENT_GENERIC_SPELL] &&
2667 (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) &&
2668 (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) )
2669 return(true);
2671 // channeled spells may be delayed, but they are still considered casted
2672 else if ( !skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
2673 (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED) )
2674 return(true);
2676 // autorepeat spells may be finished or delayed, but they are still considered casted
2677 else if ( !skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL] )
2678 return(true);
2680 return(false);
2683 void Unit::InterruptNonMeleeSpells(bool withDelayed)
2685 // generic spells are interrupted if they are not finished or delayed
2686 if (m_currentSpells[CURRENT_GENERIC_SPELL])
2688 if ( (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) &&
2689 (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) )
2690 m_currentSpells[CURRENT_GENERIC_SPELL]->cancel();
2691 m_currentSpells[CURRENT_GENERIC_SPELL]->SetDeletable(true);
2692 m_currentSpells[CURRENT_GENERIC_SPELL] = NULL;
2695 // autorepeat spells are interrupted if they are not finished or delayed
2696 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
2698 // send disable autorepeat packet in any case
2699 if(GetTypeId()==TYPEID_PLAYER)
2700 ((Player*)this)->SendAutoRepeatCancel();
2702 if ( (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_FINISHED) &&
2703 (withDelayed || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_DELAYED) )
2704 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->cancel();
2705 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SetDeletable(true);
2706 m_currentSpells[CURRENT_AUTOREPEAT_SPELL] = NULL;
2709 // channeled spells are interrupted if they are not finished, even if they are delayed
2710 if (m_currentSpells[CURRENT_CHANNELED_SPELL])
2712 if (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED)
2713 m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel();
2714 m_currentSpells[CURRENT_CHANNELED_SPELL]->SetDeletable(true);
2715 m_currentSpells[CURRENT_CHANNELED_SPELL] = NULL;
2719 bool Unit::isInFront(Unit const* target, float radius) const
2721 return IsWithinDistInMap(target, radius) && HasInArc( M_PI, target );
2724 void Unit::SetInFront(Unit const* target)
2726 SetOrientation(GetAngle(target));
2729 bool Unit::isInAccessablePlaceFor(Creature* c) const
2731 if(IsInWater())
2732 return c->isCanSwimOrFly();
2733 else
2734 return c->isCanWalkOrFly();
2737 bool Unit::IsInWater() const
2739 return MapManager::Instance().GetMap(GetMapId(), this)->IsInWater(GetPositionX(),GetPositionY(), GetPositionZ());
2742 bool Unit::IsUnderWater() const
2744 return MapManager::Instance().GetMap(GetMapId(), this)->IsUnderWater(GetPositionX(),GetPositionY(),GetPositionZ());
2747 void Unit::DeMorph()
2749 SetUInt32Value(UNIT_FIELD_DISPLAYID, GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID));
2752 long Unit::GetTotalAuraModifier(uint32 ModifierID) const
2754 uint32 modifier = 0;
2756 AuraList const& mTotalAuraList = GetAurasByType(ModifierID);
2757 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
2758 modifier += (*i)->GetModifier()->m_amount;
2760 return modifier;
2763 bool Unit::AddAura(Aura *Aur, bool uniq)
2765 // ghost spell check
2766 if (!isAlive() && !(Aur->GetSpellProto()->Id == 20584 || Aur->GetSpellProto()->Id == 8326))
2768 delete Aur;
2769 return false;
2772 if(Aur->GetTarget() != this)
2774 sLog.outError("Aura (spell %u eff %u) add to aura list of %s (lowguid: %u) but Aura target is %s (lowguid: %u)",
2775 Aur->GetId(),Aur->GetEffIndex(),(GetTypeId()==TYPEID_PLAYER?"player":"creature"),GetGUIDLow(),
2776 (Aur->GetTarget()->GetTypeId()==TYPEID_PLAYER?"player":"creature"),Aur->GetTarget()->GetGUIDLow());
2777 delete Aur;
2778 return false;
2781 AuraMap::iterator i = m_Auras.find( spellEffectPair(Aur->GetId(), Aur->GetEffIndex()) );
2783 // take out same spell
2784 if (i != m_Auras.end())
2786 /*(*i).second->SetAuraDuration(Aur->GetAuraDuration());
2787 if ((*i).second->GetTarget())
2788 if ((*i).second->GetTarget()->GetTypeId() == TYPEID_PLAYER )
2789 (*i).second->UpdateAuraDuration();
2790 delete Aur;
2791 return false;*/
2792 // passive and persistent auras can stack with themselves any number of times
2793 if (!Aur->IsPassive() && !Aur->IsPersistent() && m_Auras.count(spellEffectPair(Aur->GetId(), Aur->GetEffIndex())) >= Aur->GetSpellProto()->StackAmount)
2794 RemoveAura(i);
2797 // passive auras stack with all (except passive spell proc auras)
2798 if ((!Aur->IsPassive() || !IsPassiveStackableSpell(Aur->GetId())) &&
2799 !(Aur->GetSpellProto()->Id == 20584 || Aur->GetSpellProto()->Id == 8326))
2801 if (!RemoveNoStackAurasDueToAura(Aur))
2803 delete Aur;
2804 return false; // couldnt remove conflicting aura with higher rank
2808 // adding linked auras
2809 // add the shapeshift aura's boosts
2810 if(Aur->GetModifier()->m_auraname == SPELL_AURA_MOD_SHAPESHIFT)
2811 Aur->HandleShapeshiftBoosts(true);
2813 Aur->_AddAura();
2814 m_Auras.insert(AuraMap::value_type(spellEffectPair(Aur->GetId(), Aur->GetEffIndex()), Aur));
2815 if (Aur->GetModifier()->m_auraname < TOTAL_AURAS)
2817 m_modAuras[Aur->GetModifier()->m_auraname].push_back(Aur);
2818 m_AuraModifiers[Aur->GetModifier()->m_auraname] += (Aur->GetModifier()->m_amount);
2821 if (IsSingleTarget(Aur->GetId()) && Aur->GetTarget() && Aur->GetSpellProto())
2823 if(Unit* caster = Aur->GetCaster())
2825 AuraList& scAuras = caster->GetSingleCastAuras();
2826 AuraList::iterator itr, next;
2827 for (itr = scAuras.begin(); itr != scAuras.end(); itr = next)
2829 next = itr;
2830 next++;
2831 if ((*itr)->GetTarget() != Aur->GetTarget() &&
2832 (*itr)->GetSpellProto()->Category == Aur->GetSpellProto()->Category &&
2833 (*itr)->GetSpellProto()->SpellIconID == Aur->GetSpellProto()->SpellIconID &&
2834 (*itr)->GetSpellProto()->SpellVisual == Aur->GetSpellProto()->SpellVisual &&
2835 (*itr)->GetSpellProto()->Attributes == Aur->GetSpellProto()->Attributes &&
2836 (*itr)->GetSpellProto()->AttributesEx == Aur->GetSpellProto()->AttributesEx &&
2837 (*itr)->GetSpellProto()->AttributesExEx == Aur->GetSpellProto()->AttributesExEx)
2839 (*itr)->GetTarget()->RemoveAura((*itr)->GetId(), (*itr)->GetEffIndex());
2840 if(scAuras.empty())
2841 break;
2842 else
2843 next = scAuras.begin();
2846 scAuras.push_back(Aur);
2849 return true;
2852 void Unit::RemoveRankAurasDueToSpell(uint32 spellId)
2854 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
2855 if(!spellInfo)
2856 return;
2857 AuraMap::iterator i,next;
2858 for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
2860 next = i;
2861 next++;
2862 uint32 i_spellId = (*i).second->GetId();
2863 if((*i).second && i_spellId && i_spellId != spellId)
2865 if(objmgr.IsRankSpellDueToSpell(spellInfo,i_spellId))
2867 RemoveAurasDueToSpell(i_spellId);
2869 if( m_Auras.empty() )
2870 break;
2871 else
2872 next = m_Auras.begin();
2878 bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur)
2880 if (!Aur)
2881 return false;
2883 SpellEntry const* spellProto = Aur->GetSpellProto();
2884 if (!spellProto)
2885 return false;
2887 uint32 spellId = Aur->GetId();
2888 uint32 effIndex = Aur->GetEffIndex();
2889 bool is_sec = IsSpellSingleEffectPerCaster(spellId);
2890 AuraMap::iterator i,next;
2891 for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
2893 next = i;
2894 next++;
2895 if (!(*i).second) continue;
2897 if (!(*i).second->GetSpellProto())
2898 continue;
2900 uint32 i_spellId = (*i).second->GetId();
2902 if(IsPassiveSpell(i_spellId))
2904 if(IsPassiveStackableSpell(i_spellId))
2905 continue;
2907 // passive non-stackable spells not stackable only with another rank of same spell
2908 if (!objmgr.IsRankSpellDueToSpell(Aur->GetSpellProto(), i_spellId))
2909 continue;
2912 uint32 i_effIndex = (*i).second->GetEffIndex();
2914 if(i_spellId == spellId) continue;
2916 bool is_triggered_by_spell = false;
2917 // prevent triggered aura of removing aura that triggered it
2918 for(int j = 0; j < 3; ++j)
2919 if ((*i).second->GetSpellProto()->EffectTriggerSpell[j] == spellProto->Id)
2920 is_triggered_by_spell = true;
2921 if (is_triggered_by_spell) continue;
2923 // prevent remove dummy triggered spells at next effect aura add
2924 for(int j = 0; j < 3; ++j)
2926 switch(spellProto->Effect[j])
2928 case SPELL_EFFECT_DUMMY:
2929 switch(spellId)
2931 case 5420: if(i_spellId==34123) is_triggered_by_spell = true; break;
2933 break;
2935 if(is_triggered_by_spell)
2936 break;
2938 switch(spellProto->EffectApplyAuraName[j])
2940 case SPELL_AURA_MOD_SHAPESHIFT:
2941 switch(spellId)
2943 case 33891: if(i_spellId==5420 || i_spellId==34123) is_triggered_by_spell = true; break;
2945 break;
2949 if(!is_triggered_by_spell)
2951 bool sec_match = false;
2952 bool is_i_sec = IsSpellSingleEffectPerCaster(i_spellId);
2953 if( is_sec && is_i_sec )
2954 if (Aur->GetCasterGUID() == (*i).second->GetCasterGUID())
2955 if (GetSpellSpecific(spellId) == GetSpellSpecific(i_spellId))
2956 sec_match = true;
2957 if( sec_match || objmgr.IsNoStackSpellDueToSpell(spellId, i_spellId) && !is_sec && !is_i_sec )
2959 // if sec_match this isn't always true, needs to be rechecked
2960 if (objmgr.IsRankSpellDueToSpell(Aur->GetSpellProto(), i_spellId))
2961 if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
2962 return false; // cannot remove higher rank
2964 RemoveAurasDueToSpell(i_spellId);
2966 if( m_Auras.empty() )
2967 break;
2968 else
2969 next = m_Auras.begin();
2971 else // Potions stack aura by aura
2972 if (Aur->GetSpellProto()->SpellFamilyName == SPELLFAMILY_POTION &&
2973 (*i).second->GetSpellProto()->SpellFamilyName == SPELLFAMILY_POTION)
2975 if (IsNoStackAuraDueToAura(spellId, effIndex, i_spellId, i_effIndex))
2977 if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
2978 return false; // cannot remove higher rank
2980 RemoveAura(i);
2981 next = i;
2986 return true;
2989 void Unit::RemoveFirstAuraByDispel(uint32 dispel_type, Unit *pCaster)
2991 AuraMap::iterator i;
2992 for (i = m_Auras.begin(); i != m_Auras.end();)
2994 if ((*i).second && (*i).second->GetSpellProto()->Dispel == dispel_type)
2996 SpellEntry const* spellInfo = (*i).second->GetSpellProto();
2997 uint32 eff = (*i).second->GetEffIndex();
2999 if(dispel_type == 1)
3001 bool positive = true;
3003 if(!IsPositiveTarget(spellInfo->EffectImplicitTargetA[eff],spellInfo->EffectImplicitTargetB[eff]))
3004 positive = false;
3005 else
3006 positive = (spellInfo->AttributesEx & (1<<7))==0;
3008 if(positive && IsFriendlyTo(pCaster)) // PBW
3010 ++i;
3011 continue;
3014 RemoveAura(i);
3015 break;
3017 else
3018 ++i;
3022 void Unit::RemoveAreaAurasByOthers(uint64 guid)
3024 int j = 0;
3025 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end();)
3027 if (i->second && i->second->IsAreaAura())
3029 uint64 casterGuid = i->second->GetCasterGUID();
3030 uint64 targetGuid = i->second->GetTarget()->GetGUID();
3031 // if area aura cast by someone else or by the specified caster
3032 if (casterGuid == guid || (guid == 0 && casterGuid != targetGuid))
3034 for (j = 0; j < 4; j++)
3035 if (m_TotemSlot[j] == casterGuid)
3036 break;
3037 // and not by one of my totems
3038 if (j == 4)
3039 RemoveAura(i);
3040 else
3041 ++i;
3043 else
3044 ++i;
3046 else
3047 ++i;
3051 void Unit::RemoveAura(uint32 spellId, uint32 effindex)
3053 AuraMap::iterator iter;
3054 while((iter = m_Auras.find(spellEffectPair(spellId, effindex))) != m_Auras.end())
3055 RemoveAura(iter);
3058 void Unit::RemoveAurasDueToSpell(uint32 spellId)
3060 for (int i = 0; i < 3; ++i)
3061 RemoveAura(spellId,i);
3064 void Unit::RemoveAurasDueToItem(Item* castItem)
3066 for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
3068 if (iter->second->GetCastItemGUID() == castItem->GetGUID())
3069 RemoveAura(iter);
3070 else
3071 ++iter;
3075 void Unit::RemoveAura(AuraMap::iterator &i, bool onDeath)
3077 if (IsSingleTarget((*i).second->GetId()))
3079 if(Unit* caster = (*i).second->GetCaster())
3081 AuraList& scAuras = caster->GetSingleCastAuras();
3082 scAuras.remove((*i).second);
3084 else
3085 sLog.outError("Unit::RemoveAura: cannot remove the single cast aura (SpellId: %u Effect: %u) from the caster, potential crash!",(*i).second->GetId(),(*i).second->GetEffIndex());
3087 // remove aura from party members when the caster turns off the aura
3088 if((*i).second->IsAreaAura())
3090 Unit *i_target = (*i).second->GetTarget();
3091 if((*i).second->GetCasterGUID() == i_target->GetGUID())
3093 Unit* i_caster = i_target;
3095 Unit* owner = NULL;
3096 Group *pGroup = NULL;
3097 Player *pGroupOf = NULL;
3098 if (i_caster->GetTypeId() == TYPEID_PLAYER)
3100 pGroupOf = (Player*)i_caster;
3101 pGroup = pGroupOf->GetGroup();
3103 else if(((Creature*)i_caster)->isTotem() || ((Creature*)i_caster)->isPet() || i_caster->isCharmed())
3105 owner = i_caster->GetCharmerOrOwner();
3106 if (owner && owner->GetTypeId() == TYPEID_PLAYER)
3108 pGroupOf = (Player*)owner;
3109 pGroup = pGroupOf->GetGroup();
3113 //float radius = GetRadius(sSpellRadiusStore.LookupEntry((*i).second->GetSpellProto()->EffectRadiusIndex[(*i).second->GetEffIndex()]));
3114 if(pGroup && pGroupOf)
3116 for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
3118 Player* Target = itr->getSource();
3119 if(!Target || !pGroup->SameSubGroup(pGroupOf, Target))
3120 continue;
3122 if(Target->GetGUID() == i_caster->GetGUID())
3123 continue;
3124 Aura *t_aura = Target->GetAura((*i).second->GetId(), (*i).second->GetEffIndex());
3125 if (t_aura)
3126 if (t_aura->GetCasterGUID() == i_caster->GetGUID())
3127 Target->RemoveAura((*i).second->GetId(), (*i).second->GetEffIndex());
3130 else if(owner)
3132 Aura *t_aura = owner->GetAura((*i).second->GetId(), (*i).second->GetEffIndex());
3133 if (t_aura)
3134 if (t_aura->GetCasterGUID() == i_caster->GetGUID())
3135 owner->RemoveAura((*i).second->GetId(), (*i).second->GetEffIndex());
3139 if ((*i).second->GetModifier()->m_auraname < TOTAL_AURAS)
3141 m_AuraModifiers[(*i).second->GetModifier()->m_auraname] -= ((*i).second->GetModifier()->m_amount);
3142 m_modAuras[(*i).second->GetModifier()->m_auraname].remove((*i).second);
3144 (*i).second->SetRemoveOnDeath(onDeath);
3146 // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
3147 Aura* Aur = i->second;
3149 DiminishingMechanics mech = DIMINISHING_NONE;
3150 if(Aur->GetSpellProto()->Mechanic)
3152 mech = Unit::Mechanic2DiminishingMechanics(Aur->GetSpellProto()->Mechanic);
3153 if(mech == DIMINISHING_MECHANIC_STUN || GetTypeId() == TYPEID_PLAYER && mech != DIMINISHING_NONE)
3154 UpdateDiminishingTime(mech);
3157 // must remove before removing from list (its remove dependent auras and _i_ is only safe iterator value
3158 // remove the shapeshift aura's boosts
3159 if(Aur->GetModifier()->m_auraname == SPELL_AURA_MOD_SHAPESHIFT)
3160 Aur->HandleShapeshiftBoosts(false);
3162 m_Auras.erase(i);
3163 m_removedAuras++; // internal count used by unit update
3165 Aur->_RemoveAura();
3166 delete Aur;
3168 // only way correctly remove all auras from list
3169 if( m_Auras.empty() )
3170 i = m_Auras.end();
3171 else
3172 i = m_Auras.begin();
3175 bool Unit::SetAurDuration(uint32 spellId, uint32 effindex,uint32 duration)
3177 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
3178 if (iter != m_Auras.end())
3180 (*iter).second->SetAuraDuration(duration);
3181 (*iter).second->UpdateAuraDuration();
3182 return true;
3184 return false;
3187 uint32 Unit::GetAurDuration(uint32 spellId, uint32 effindex)
3189 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
3190 if (iter != m_Auras.end())
3192 return (*iter).second->GetAuraDuration();
3194 return 0;
3197 void Unit::RemoveAllAuras()
3199 while (!m_Auras.empty())
3201 AuraMap::iterator iter = m_Auras.begin();
3202 RemoveAura(iter);
3206 void Unit::RemoveAllAurasOnDeath()
3208 // used just after dieing to remove all visible auras
3209 // and disable the mods for the passive ones
3210 for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
3212 if (!iter->second->IsPassive())
3213 RemoveAura(iter, true);
3214 else
3215 ++iter;
3219 void Unit::DelayAura(uint32 spellId, uint32 effindex, int32 delaytime)
3221 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
3222 if (iter != m_Auras.end())
3224 if (iter->second->GetAuraDuration() < delaytime)
3225 iter->second->SetAuraDuration(0);
3226 else
3227 iter->second->SetAuraDuration(iter->second->GetAuraDuration() - delaytime);
3228 iter->second->UpdateAuraDuration();
3229 sLog.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter->second->GetModifier()->m_auraname, GetGUIDLow(), iter->second->GetAuraDuration());
3233 void Unit::_RemoveAllAuraMods()
3235 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
3237 (*i).second->ApplyModifier(false);
3241 void Unit::_ApplyAllAuraMods()
3243 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
3245 (*i).second->ApplyModifier(true);
3249 // TODO: FIX-ME!!!
3250 /*void Unit::_UpdateAura()
3252 if(GetTypeId() != TYPEID_PLAYER || !m_Auras)
3253 return;
3255 Player* pThis = (Player*)this;
3257 Player* pGroupGuy;
3258 Group* pGroup;
3260 pGroup = objmgr.GetGroupByLeader(pThis->GetGroupLeader());
3262 if(!SetAffDuration(m_Auras->GetId(),this,6000))
3263 AddAura(m_Auras);
3265 if(!pGroup)
3266 return;
3267 else
3269 for(uint32 i=0;i<pGroup->GetMembersCount();i++)
3271 pGroupGuy = ObjectAccessor::Instance().FindPlayer(pGroup->GetMemberGUID(i));
3273 if(!pGroupGuy)
3274 continue;
3275 if(pGroupGuy->GetGUID() == GetGUID())
3276 continue;
3277 if(sqrt(
3278 (GetPositionX()-pGroupGuy->GetPositionX())*(GetPositionX()-pGroupGuy->GetPositionX())
3279 +(GetPositionY()-pGroupGuy->GetPositionY())*(GetPositionY()-pGroupGuy->GetPositionY())
3280 +(GetPositionZ()-pGroupGuy->GetPositionZ())*(GetPositionZ()-pGroupGuy->GetPositionZ())
3281 ) <=30)
3283 if(!pGroupGuy->SetAffDuration(m_Auras->GetId(),this,6000))
3284 pGroupGuy->AddAura(m_Auras);
3286 else
3288 if(m_removeAuraTimer == 0)
3290 printf("remove aura from %u\n", pGroupGuy->GetGUID());
3291 pGroupGuy->RemoveAura(m_Auras->GetId());
3296 if(m_removeAuraTimer > 0)
3297 m_removeAuraTimer -= 1;
3298 else
3299 m_removeAuraTimer = 4;
3302 Aura* Unit::GetAura(uint32 spellId, uint32 effindex)
3304 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
3305 if (iter != m_Auras.end())
3306 return iter->second;
3307 return NULL;
3310 void Unit::AddDynObject(DynamicObject* dynObj)
3312 m_dynObjGUIDs.push_back(dynObj->GetGUID());
3315 void Unit::RemoveDynObject(uint32 spellid)
3317 if(m_dynObjGUIDs.empty())
3318 return;
3319 for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
3321 DynamicObject* dynObj = ObjectAccessor::Instance().GetDynamicObject(*this,*m_dynObjGUIDs.begin());
3322 if(!dynObj)
3324 i = m_dynObjGUIDs.erase(i);
3326 else if(spellid == 0 || dynObj->GetSpellId() == spellid)
3328 dynObj->Delete();
3329 i = m_dynObjGUIDs.erase(i);
3331 else
3332 ++i;
3336 DynamicObject * Unit::GetDynObject(uint32 spellId, uint32 effIndex)
3338 for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
3340 DynamicObject* dynObj = ObjectAccessor::Instance().GetDynamicObject(*this,*m_dynObjGUIDs.begin());
3341 if(!dynObj)
3343 i = m_dynObjGUIDs.erase(i);
3344 continue;
3347 if (dynObj->GetSpellId() == spellId && dynObj->GetEffIndex() == effIndex)
3348 return dynObj;
3349 ++i;
3351 return NULL;
3354 void Unit::AddGameObject(GameObject* gameObj)
3356 assert(gameObj && gameObj->GetOwnerGUID()==0);
3357 m_gameObj.push_back(gameObj);
3358 gameObj->SetOwnerGUID(GetGUID());
3361 void Unit::RemoveGameObject(GameObject* gameObj, bool del)
3363 assert(gameObj && gameObj->GetOwnerGUID()==GetGUID());
3364 gameObj->SetOwnerGUID(0);
3365 m_gameObj.remove(gameObj);
3366 if(del)
3368 gameObj->SetRespawnTime(0);
3369 gameObj->Delete();
3373 void Unit::RemoveGameObject(uint32 spellid, bool del)
3375 if(m_gameObj.empty())
3376 return;
3377 std::list<GameObject*>::iterator i, next;
3378 for (i = m_gameObj.begin(); i != m_gameObj.end(); i = next)
3380 next = i;
3381 if(spellid == 0 || (*i)->GetSpellId() == spellid)
3383 (*i)->SetOwnerGUID(0);
3384 if(del)
3386 (*i)->SetRespawnTime(0);
3387 (*i)->Delete();
3390 next = m_gameObj.erase(i);
3392 else
3393 ++next;
3397 void Unit::SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, SpellSchools DamageType,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit)
3399 WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16+31)); // we guess size
3400 data.append(target->GetPackGUID());
3401 data.append(GetPackGUID());
3402 data << uint32(SpellID);
3403 data << uint32(Damage-AbsorbedDamage-Resist-Blocked);
3404 data << uint8(DamageType); //damagetype
3405 data << uint32(AbsorbedDamage); //AbsorbedDamage
3406 data << uint32(Resist); //resist
3407 data << (uint8)PhysicalDamage;
3408 data << uint8(0);
3409 data << uint32(Blocked); //blocked
3410 data << uint8(CriticalHit ? 2 : 0); //seen 0x05 also...
3411 data << uint32(0);
3412 SendMessageToSet( &data, true );
3415 void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SpellSchools DamageType, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, uint32 TargetState, uint32 BlockedAmount)
3417 sLog.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
3419 WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16+45)); // we guess size
3420 data << (uint32)HitInfo;
3421 data.append(GetPackGUID());
3422 data.append(target->GetPackGUID());
3423 data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount);
3425 data << (uint8)SwingType;
3426 data << (uint32)DamageType;
3429 data << (float)(Damage-AbsorbDamage-Resist-BlockedAmount);
3430 // still need to double check damaga
3431 data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount);
3432 data << (uint32)AbsorbDamage;
3433 data << (uint32)Resist;
3434 data << (uint32)TargetState;
3436 if( AbsorbDamage == 0 ) //also 0x3E8 = 0x3E8, check when that happens
3437 data << (uint32)0;
3438 else
3439 data << (uint32)-1;
3441 data << (uint32)0;
3442 data << (uint32)BlockedAmount;
3444 SendMessageToSet( &data, true );
3447 void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 damage, SpellEntry const *procSpell, bool isTriggeredSpell, WeaponAttackType attType)
3449 sLog.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker, procVictim);
3450 if(procSpell)
3451 sLog.outDebug("ProcDamageAndSpell: invoked due to spell id %u %s", procSpell->Id, (isTriggeredSpell?"(triggered)":""));
3453 // Assign melee/ranged proc flags for magic attacks, that are actually melee/ranged abilities
3454 // not assign for spell proc triggered spell to prevent infinity (or unexpacted 2-3 times) melee damage spell proc call with melee damage effect
3455 // That is the question though if it's fully correct
3456 if(procSpell && !isTriggeredSpell)
3458 if(procSpell->DmgClass == SPELL_DAMAGE_CLASS_MELEE)
3460 if(procAttacker & PROC_FLAG_HIT_SPELL) procAttacker |= PROC_FLAG_HIT_MELEE;
3461 if(procAttacker & PROC_FLAG_CRIT_SPELL) procAttacker |= PROC_FLAG_CRIT_MELEE;
3462 if(procVictim & PROC_FLAG_STRUCK_SPELL) procVictim |= PROC_FLAG_STRUCK_MELEE;
3463 if(procVictim & PROC_FLAG_STRUCK_CRIT_SPELL) procVictim |= PROC_FLAG_STRUCK_CRIT_MELEE;
3464 attType = BASE_ATTACK; // Melee abilities are assumed to be dealt with mainhand weapon
3466 else if (procSpell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
3468 if(procAttacker & PROC_FLAG_HIT_SPELL) procAttacker |= PROC_FLAG_HIT_RANGED;
3469 if(procAttacker & PROC_FLAG_CRIT_SPELL) procAttacker |= PROC_FLAG_CRIT_RANGED;
3470 if(procVictim & PROC_FLAG_STRUCK_SPELL) procVictim |= PROC_FLAG_STRUCK_RANGED;
3471 if(procVictim & PROC_FLAG_STRUCK_CRIT_SPELL) procVictim |= PROC_FLAG_STRUCK_CRIT_RANGED;
3472 attType = RANGED_ATTACK;
3475 if(damage && (procVictim & (PROC_FLAG_STRUCK_MELEE|PROC_FLAG_STRUCK_RANGED|PROC_FLAG_STRUCK_SPELL)))
3476 procVictim |= (PROC_FLAG_TAKE_DAMAGE|PROC_FLAG_TOUCH);
3478 // Not much to do if no flags are set.
3479 if (procAttacker)
3481 ProcDamageAndSpellFor(false,pVictim,procAttacker,attackerProcAuraTypes,attType, procSpell, damage);
3484 // Now go on with a victim's events'n'auras
3485 // Not much to do if no flags are set or there is no victim
3486 if(pVictim && pVictim->isAlive() && procVictim)
3488 pVictim->ProcDamageAndSpellFor(true,this,procVictim,victimProcAuraTypes,attType,procSpell, damage);
3492 void Unit::CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, WeaponAttackType attType, MeleeHitOutcome outcome, SpellEntry const *spellCasted, bool isTriggeredSpell)
3494 if(!pVictim)
3495 return;
3497 uint32 procAttacker = PROC_FLAG_NONE;
3498 uint32 procVictim = PROC_FLAG_NONE;
3500 switch(outcome)
3502 case MELEE_HIT_MISS:
3503 if(attType == BASE_ATTACK || attType == OFF_ATTACK)
3505 procAttacker = PROC_FLAG_MISS;
3507 break;
3508 case MELEE_HIT_CRIT:
3509 if(spellCasted && attType == BASE_ATTACK)
3511 procAttacker |= PROC_FLAG_CRIT_SPELL;
3512 procVictim |= PROC_FLAG_STRUCK_CRIT_SPELL;
3514 else if(attType == BASE_ATTACK || attType == OFF_ATTACK)
3516 procAttacker = PROC_FLAG_HIT_MELEE | PROC_FLAG_CRIT_MELEE;
3517 procVictim = PROC_FLAG_STRUCK_MELEE | PROC_FLAG_STRUCK_CRIT_MELEE;
3519 else
3521 procAttacker = PROC_FLAG_HIT_RANGED | PROC_FLAG_CRIT_RANGED;
3522 procVictim = PROC_FLAG_STRUCK_RANGED | PROC_FLAG_STRUCK_CRIT_RANGED;
3524 break;
3525 case MELEE_HIT_PARRY:
3526 procAttacker = PROC_FLAG_TARGET_DODGE_OR_PARRY;
3527 procVictim = PROC_FLAG_PARRY;
3528 break;
3529 case MELEE_HIT_BLOCK:
3530 procAttacker = PROC_FLAG_TARGET_BLOCK;
3531 procVictim = PROC_FLAG_BLOCK;
3532 break;
3533 case MELEE_HIT_DODGE:
3534 procAttacker = PROC_FLAG_TARGET_DODGE_OR_PARRY;
3535 procVictim = PROC_FLAG_DODGE;
3536 break;
3537 case MELEE_HIT_CRUSHING:
3538 if(attType == BASE_ATTACK || attType == OFF_ATTACK)
3540 procAttacker = PROC_FLAG_HIT_MELEE | PROC_FLAG_CRIT_MELEE;
3541 procVictim = PROC_FLAG_STRUCK_MELEE | PROC_FLAG_STRUCK_CRIT_MELEE;
3543 else
3545 procAttacker = PROC_FLAG_HIT_RANGED | PROC_FLAG_CRIT_RANGED;
3546 procVictim = PROC_FLAG_STRUCK_RANGED | PROC_FLAG_STRUCK_CRIT_RANGED;
3548 break;
3549 default:
3550 if(attType == BASE_ATTACK || attType == OFF_ATTACK)
3552 procAttacker = PROC_FLAG_HIT_MELEE;
3553 procVictim = PROC_FLAG_STRUCK_MELEE;
3555 else
3557 procAttacker = PROC_FLAG_HIT_RANGED;
3558 procVictim = PROC_FLAG_STRUCK_RANGED;
3560 break;
3563 if(damage > 0)
3564 procVictim |= PROC_FLAG_TAKE_DAMAGE;
3566 if(procAttacker != PROC_FLAG_NONE || procVictim != PROC_FLAG_NONE)
3567 ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, spellCasted, isTriggeredSpell, attType);
3570 void Unit::HandleDummyAuraProc(Unit *pVictim, SpellEntry const *dummySpell, uint32 effIndex, uint32 damage, Aura* triggredByAura, SpellEntry const * procSpell, uint32 procFlag)
3572 switch(dummySpell->Id )
3574 // Ignite
3575 case 11119:
3576 case 11120:
3577 case 12846:
3578 case 12847:
3579 case 12848:
3581 if(!pVictim || !pVictim->isAlive())
3582 return;
3584 int32 igniteDotBasePoints0;
3586 switch (dummySpell->Id)
3588 case 11119: igniteDotBasePoints0=int32(0.04f*damage)-1; break;
3589 case 11120: igniteDotBasePoints0=int32(0.08f*damage)-1; break;
3590 case 12846: igniteDotBasePoints0=int32(0.12f*damage)-1; break;
3591 case 12847: igniteDotBasePoints0=int32(0.16f*damage)-1; break;
3592 case 12848: igniteDotBasePoints0=int32(0.20f*damage)-1; break;
3593 default:
3594 sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell->Id);
3595 return;
3597 CastCustomSpell(pVictim, 12654, &igniteDotBasePoints0, NULL, NULL, true, NULL, triggredByAura);
3598 return;
3601 // Combustion
3602 case 11129:
3604 CastSpell(this, 28682, true, NULL, triggredByAura);
3605 if (!(procFlag & PROC_FLAG_CRIT_SPELL)) //no crit
3606 triggredByAura->m_procCharges += 1; //-> reincrease procCharge count since it was decreased before
3607 else if (triggredByAura->m_procCharges == 0) //no more charges left and crit
3608 RemoveAurasDueToSpell(28682); //-> remove Combustion auras
3609 return;
3611 // Nightfall
3612 case 18094:
3613 case 18095:
3615 CastSpell(this, 17941, true, NULL, triggredByAura);
3616 return;
3618 // VE
3619 case 15286:
3621 if(!pVictim || !pVictim->isAlive())
3622 return;
3624 if(triggredByAura->GetCasterGUID() == pVictim->GetGUID())
3626 //VEHeal has a BaseDice of 0, so no decrement needed
3627 int32 VEHealBasePoints0 = triggredByAura->GetModifier()->m_amount*damage/100;
3628 pVictim->CastCustomSpell(pVictim, 15290, &VEHealBasePoints0, NULL, NULL, true, NULL, triggredByAura);
3630 return;
3632 // Eye of Eye
3633 case 9799:
3634 case 25988:
3636 if(!pVictim || !pVictim->isAlive())
3637 return;
3639 // return damage % to attacker but < 50% own total health
3640 uint32 backDamage = triggredByAura->GetModifier()->m_amount*damage/100;
3641 if(backDamage > GetMaxHealth()/2)
3642 backDamage = GetMaxHealth()/2;
3644 int32 YYDamageBasePoints0 = backDamage-1;
3645 CastCustomSpell(pVictim, 25997, &YYDamageBasePoints0, NULL, NULL, true, NULL, triggredByAura);
3647 return;
3650 // L.Overload
3651 case 30675:
3652 case 30678:
3653 case 30679:
3654 case 30680:
3655 case 30681:
3657 if(!procSpell)
3658 return;
3660 // we assume lightning bolt and chain lightning are generic (not channeled/autorepeat) spells
3661 if(!pVictim || !m_currentSpells[CURRENT_GENERIC_SPELL])
3662 return;
3664 // remove cooldown from first cast
3665 if(GetTypeId()==TYPEID_PLAYER)
3666 ((Player*)this)->RemoveSpellCooldown(procSpell->Id);
3667 // prepare cast as triggered spell (this need for correct targets selection after not finished currently cast)
3668 m_currentSpells[CURRENT_GENERIC_SPELL]->AddTriggeredSpell(procSpell);
3671 // Spiritual Att.
3672 case 33776:
3673 case 31785:
3675 if(!pVictim)
3676 return;
3678 // if healed by another unit (pVictim)
3679 if(this != pVictim)
3681 int32 SAHealBasePoints0 = triggredByAura->GetModifier()->m_amount*damage/100-1;
3682 CastCustomSpell(this, 31786, &SAHealBasePoints0, NULL, NULL, true, NULL, triggredByAura);
3685 return;
3688 // Shadowflame (item set effect)
3689 case 37377:
3691 if(GetTypeId() != TYPEID_PLAYER || !pVictim || !pVictim->isAlive())
3692 return;
3694 Item* castItem = ((Player*)this)->GetItemByGuid(triggredByAura->GetCastItemGUID());
3695 if(!castItem)
3696 return;
3698 CastSpell(pVictim,37379,true,castItem,triggredByAura);
3699 return;
3701 // Shadowflame Hellfire (item set effect)
3702 case 39437:
3704 if(GetTypeId() != TYPEID_PLAYER || !pVictim || !pVictim->isAlive())
3705 return;
3707 Item* castItem = ((Player*)this)->GetItemByGuid(triggredByAura->GetCastItemGUID());
3708 if(!castItem)
3709 return;
3711 CastSpell(pVictim,37378,true,castItem,triggredByAura);
3712 return;
3715 default: break;
3718 switch(dummySpell->SpellFamilyName)
3720 case SPELLFAMILY_SHAMAN:
3721 if(dummySpell->SpellFamilyFlags==0x40000000000LL)
3723 int32 HealBasePoints0 = dummySpell->EffectBasePoints[0];
3724 CastCustomSpell(this,379,&HealBasePoints0,NULL,NULL,true,NULL,triggredByAura);
3725 return;
3727 break;
3728 default:
3729 break;
3732 // Non SpellID checks
3733 switch(dummySpell->SpellIconID)
3735 // Master of Elements
3736 case 1920:
3738 if(!procSpell)
3739 return;
3741 if(dummySpell->SpellFamilyName!=SPELLFAMILY_MAGE)
3742 return;
3744 int32 MEManaCostSave = procSpell->manaCost * triggredByAura->GetModifier()->m_amount/100;
3745 if(MEManaCostSave <= 0)
3746 return;
3747 int32 MEManaRestoreBasePoints0 = MEManaCostSave-1;
3748 CastCustomSpell(this,29077,&MEManaRestoreBasePoints0,NULL,NULL,true,NULL, triggredByAura);
3750 return;
3752 // VT
3753 case 2213:
3755 if(!pVictim || !pVictim->isAlive())
3756 return;
3758 if(triggredByAura->GetCasterGUID() == pVictim->GetGUID())
3760 int32 VTEnergizeBasePoints0 = triggredByAura->GetModifier()->m_amount*damage/100 - 1;
3761 pVictim->CastCustomSpell(pVictim,34919,&VTEnergizeBasePoints0,NULL,NULL,true,NULL, triggredByAura);
3763 return;
3765 // Quick Recovery
3766 case 2116:
3768 if(!procSpell)
3769 return;
3771 if(dummySpell->SpellFamilyName!=SPELLFAMILY_ROGUE)
3772 return;
3774 // only rogue's finishing moves (maybe need additional checks)
3775 if( procSpell->SpellFamilyName!=SPELLFAMILY_ROGUE ||
3776 (procSpell->SpellFamilyFlags & (0x40000 | 0x80000 | 0x100000 | 0x200000 | 0x800000000LL | 0x20000)) == 0)
3777 return;
3779 int32 QREnegyCostSave = procSpell->manaCost * triggredByAura->GetModifier()->m_amount/100;
3780 if(QREnegyCostSave <= 0)
3781 return;
3782 int32 QREnergizeBasePoints0 = QREnegyCostSave-1;
3783 CastCustomSpell(this,31663,&QREnergizeBasePoints0,NULL,NULL,true,NULL, triggredByAura);
3785 return;
3787 // Thrill of the Hunt
3788 case 2236:
3790 if(!procSpell)
3791 return;
3793 if(dummySpell->SpellFamilyName!=SPELLFAMILY_HUNTER)
3794 return;
3796 int32 THManaCostSave = procSpell->manaCost * 40/100;
3797 if(THManaCostSave <= 0)
3798 return;
3799 int32 THEnergizeBasePoints0 = THManaCostSave-1;
3800 CastCustomSpell(this,34720,&THEnergizeBasePoints0,NULL,NULL,true,NULL, triggredByAura);
3802 return;
3807 void Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 procFlags)
3809 SpellEntry const* auraSpellInfo = triggeredByAura->GetSpellProto();
3811 switch(auraSpellInfo->SpellIconID)
3813 case 19:
3815 switch(auraSpellInfo->SpellFamilyName)
3817 case SPELLFAMILY_SHAMAN:
3819 //Lightning Shield (overwrite non existing triggered spell call in spell.dbc
3820 if(auraSpellInfo->SpellFamilyFlags==0x00000400)
3822 if(!pVictim || !pVictim->isAlive())
3823 return;
3825 uint32 spell = 0;
3826 switch(triggeredByAura->GetSpellProto()->Id)
3828 // Rank 1
3829 case 324: spell = 26364; break;
3830 // Rank 2
3831 case 325: spell = 26365; break;
3832 // Rank 3
3833 case 905: spell = 26366; break;
3834 // Rank 4
3835 case 945: spell = 26367; break;
3836 // Rank 5
3837 case 8134: spell = 26369; break;
3838 // Rank 6
3839 case 10431: spell = 26370; break;
3840 // Rank 7
3841 case 10432: spell = 26363; break;
3842 // Rank 8
3843 case 25469: spell = 26371; break;
3844 // Rank 9
3845 case 25472: spell = 26372; break;
3846 default:
3847 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura->GetSpellProto()->Id);
3848 return;
3850 CastSpell(pVictim, spell, true, NULL, triggeredByAura);
3851 return;
3853 break;
3855 case SPELLFAMILY_PRIEST:
3857 // Priest's "Shadowguard"
3858 if(auraSpellInfo->SpellFamilyFlags==0x100080000000LL)
3860 if(!pVictim || !pVictim->isAlive())
3861 return;
3863 uint32 spell = 0;
3864 switch(triggeredByAura->GetSpellProto()->Id)
3866 // Rank 1
3867 case 18137: spell = 28377; break;
3868 // Rank 2
3869 case 19308: spell = 28378; break;
3870 // Rank 3
3871 case 19309: spell = 28379; break;
3872 // Rank 4
3873 case 19310: spell = 28380; break;
3874 // Rank 5
3875 case 19311: spell = 28381; break;
3876 // Rank 6
3877 case 19312: spell = 28382; break;
3878 // Rank 7
3879 case 25477: spell = 28385; break;
3880 default:
3881 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura->GetSpellProto()->Id);
3882 return;
3884 CastSpell(pVictim, spell, true, NULL, triggeredByAura);
3885 return;
3887 break;
3890 break;
3892 case 87:
3894 //Mana Surge (Shaman T1 bonus)
3895 //Effect: 23571
3896 if(!procSpell)
3897 return;
3899 int32 manaSurgeSpellBasePoints0 = procSpell->manaCost * 35/100;
3900 CastCustomSpell(this, 23571, &manaSurgeSpellBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
3901 return;
3903 case 113:
3905 //Improved Drain Soul
3906 //Effect: 18371
3907 Unit::AuraList const& mAddFlatModifier = GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
3908 for(Unit::AuraList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i)
3910 if ((*i)->GetModifier()->m_miscvalue == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellProto()->SpellIconID == 113)
3912 int32 impDrainSoulBasePoints0 = (*i)->GetSpellProto()->EffectBasePoints[2] * GetMaxPower(POWER_MANA) / 100;
3913 CastCustomSpell(this, 18371, &impDrainSoulBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
3916 return;
3918 case 241:
3920 switch(auraSpellInfo->EffectTriggerSpell[0])
3922 //Illumination
3923 case 18350:
3925 if(!procSpell)
3926 return;
3928 SpellEntry const *originalSpell = procSpell;
3930 // in case HShock procspell is triggered spell but we need mana cost of original casted spell
3931 if(procSpell->SpellFamilyName == SPELLFAMILY_PALADIN && procSpell->SpellFamilyFlags == 0x00200000)
3933 uint32 originalSpellId = 0;
3934 switch(procSpell->Id)
3936 case 25914: originalSpellId = 20473; break;
3937 case 25913: originalSpellId = 20929; break;
3938 case 25903: originalSpellId = 20930; break;
3939 case 27175: originalSpellId = 27174; break;
3940 case 33074: originalSpellId = 33072; break;
3941 default:
3942 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell->Id);
3943 return;
3945 SpellEntry const *HSSpell= sSpellStore.LookupEntry(originalSpellId);
3946 if(!HSSpell)
3948 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but used in HShock",originalSpellId);
3949 return;
3951 originalSpell = HSSpell;
3954 // percent stored in effect 1 (class scripts) base points
3955 int32 percent = auraSpellInfo->EffectBasePoints[1]+1;
3957 // BasePoints = val -1 not required (EffectBaseDice==0)
3958 int32 ILManaSpellBasePoints0 = originalSpell->manaCost*percent/100;
3959 CastCustomSpell(this, 20272, &ILManaSpellBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
3960 return;
3963 break;
3965 case 312:
3967 //Improved Leader of the Pack
3968 //Cooldown: 6 secs
3969 if (triggeredByAura->GetModifier()->m_amount == 0)
3970 break;
3971 int32 improvedLotPBasePoints0 = triggeredByAura->GetModifier()->m_amount * GetMaxHealth() / 100 - 1;
3972 CastCustomSpell(this, 34299, &improvedLotPBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
3973 if (GetTypeId() == TYPEID_PLAYER)
3974 ((Player*)this)->AddSpellCooldown(34299,0,time(NULL) + 6);
3975 return;
3977 case 1137:
3979 if(!pVictim || !pVictim->isAlive())
3980 return;
3982 //Pyroclasm
3983 float chance = 0;
3984 switch (triggeredByAura->GetSpellProto()->Id)
3986 case 18096:
3987 chance = 13.0;
3988 break;
3989 case 18073:
3990 chance = 26.0;
3991 break;
3993 if (roll_chance_f(chance))
3994 CastSpell(pVictim, 18093, true, NULL, triggeredByAura);
3995 return;
3997 case 1875:
3999 //Blessed Recovery
4000 uint32 EffectId = 0;
4001 switch (triggeredByAura->GetSpellProto()->Id)
4003 case 27811: EffectId = 27813; break;
4004 case 27815: EffectId = 27817; break;
4005 case 27816: EffectId = 27818; break;
4006 default:
4007 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura->GetSpellProto()->Id);
4008 return;
4011 int32 heal_amount = damage * triggeredByAura->GetModifier()->m_amount / 100;
4012 int32 BRHealBasePoints0 = heal_amount/3-1;
4013 CastCustomSpell(this, EffectId, &BRHealBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
4014 return;
4016 case 2006:
4017 //Rampage
4018 //Effects: 30029(Rank 1), 30031(Rank 2), 30032(Rank 3)
4019 //Check EffectTriggerSpell[1] to determine correct effect id
4020 //CastSpell(this, triggredByAura->GetSpellProto()->EffectTriggerSpell[1], true, NULL, triggredByAura);
4021 return;
4022 case 2013:
4024 //Nature's Guardian
4025 //Effects: 31616, 39301
4026 //Cooldown: 5 secs
4027 /*float HealthRatio = GetHealth() / GetMaxHealth();
4028 float HealthRatioBefore = (GetHealth() + damage) / GetMaxHealth();
4029 if (HealthRatio < 0.3 && HealthRatioBefore >= 0.3)
4031 SpellEntry const *NGHealTemplate = sSpellStore.LookupEntry(31616);
4032 SpellEntry NGHeal = *NGHealTemplate;
4033 NGHeal.EffectBasePoints[0] = triggredByAura->GetModifier()->m_amount * GetMaxHealth() / 100;
4034 CastSpell(this, &NGHeal, true, NULL, triggredByAura);
4035 if (pVictim && pVictim->isAlive())
4036 CastSpell(pVictim, 39301, true, NULL, triggredByAura);
4037 if (GetTypeId() == TYPEID_PLAYER)
4039 ((Player*)this)->AddSpellCooldown(31616,0,time(NULL) + 5);
4040 ((Player*)this)->AddSpellCooldown(39301,0,time(NULL) + 5);
4043 return;
4045 case 2127:
4046 //Blazing Speed
4047 CastSpell(this, 31643, true, NULL, triggeredByAura);
4048 return;
4051 // custom check for proc spell
4052 switch(auraSpellInfo->Id)
4054 // Lightning Capacitor
4055 case 37657:
4057 if(!pVictim || !pVictim->isAlive())
4058 return;
4060 // stacking
4061 CastSpell(this, 37658, true, NULL, triggeredByAura);
4063 // counting
4064 uint32 count = 0;
4065 AuraList const& dummyAura = GetAurasByType(SPELL_AURA_DUMMY);
4066 for(AuraList::const_iterator itr = dummyAura.begin(); itr != dummyAura.end(); ++itr)
4067 if((*itr)->GetId()==37658)
4068 ++count;
4070 // release at 3 aura in stack
4071 if(count >2)
4073 RemoveAurasDueToSpell(37658);
4074 CastSpell(pVictim, 37661, true, NULL, triggeredByAura);
4076 return;
4080 // standard non-dummy case
4081 uint32 trigger_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()];
4082 if(!trigger_spell_id)
4084 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo->Id,triggeredByAura->GetEffIndex());
4085 return;
4088 // but with dummy basepoints or other customs
4089 switch(trigger_spell_id)
4091 // Shamanistic Rage triggered spell
4092 case 30824:
4094 int32 SRBasePoints0 = int32(GetTotalAttackPowerValue(BASE_ATTACK)*triggeredByAura->GetModifier()->m_amount/100) -1;
4095 CastCustomSpell(this, 30824, &SRBasePoints0, NULL, NULL, true, NULL, triggeredByAura);
4096 return;
4098 // Backlash triggered spell
4099 case 34936:
4101 // need set custom cooldown
4102 if(isAlive() && GetTypeId()==TYPEID_PLAYER && !((Player*)this)->HasSpellCooldown(34936))
4104 CastSpell(this,trigger_spell_id,true,NULL,triggeredByAura);
4105 ((Player*)this)->AddSpellCooldown(34936,0,time(NULL)+8);
4107 return;
4111 // default case
4112 if(IsPositiveSpell(trigger_spell_id) && !(procFlags & PROC_FLAG_HEAL))
4113 CastSpell(this,trigger_spell_id,true,NULL,triggeredByAura);
4114 else if(pVictim && pVictim->isAlive())
4115 CastSpell(pVictim,trigger_spell_id,true,NULL,triggeredByAura);
4118 void Unit::setPowerType(Powers new_powertype)
4120 uint32 tem_bytes_0 = GetUInt32Value(UNIT_FIELD_BYTES_0);
4121 SetUInt32Value(UNIT_FIELD_BYTES_0,((tem_bytes_0<<8)>>8) + (uint32(new_powertype)<<24));
4123 if (GetTypeId() == TYPEID_PLAYER)
4124 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE);
4126 switch(new_powertype)
4128 default:
4129 case POWER_MANA:
4130 break;
4131 case POWER_RAGE:
4132 SetMaxPower(POWER_RAGE,GetCreatePowers(POWER_RAGE));
4133 SetPower( POWER_RAGE,0);
4134 break;
4135 case POWER_FOCUS:
4136 SetMaxPower(POWER_FOCUS,GetCreatePowers(POWER_FOCUS));
4137 SetPower( POWER_FOCUS,GetCreatePowers(POWER_FOCUS));
4138 break;
4139 case POWER_ENERGY:
4140 SetMaxPower(POWER_ENERGY,GetCreatePowers(POWER_ENERGY));
4141 SetPower( POWER_ENERGY,0);
4142 break;
4143 case POWER_HAPPINESS:
4144 SetMaxPower(POWER_HAPPINESS,GetCreatePowers(POWER_HAPPINESS));
4145 SetPower(POWER_HAPPINESS,GetCreatePowers(POWER_HAPPINESS));
4146 break;
4150 FactionTemplateEntry const* Unit::getFactionTemplateEntry() const
4152 FactionTemplateEntry const* entry = sFactionTemplateStore.LookupEntry(getFaction());
4153 if(!entry)
4155 static uint64 guid = 0; // prevent repeating spam same faction problem
4157 if(GetGUID() != guid)
4159 if(GetTypeId() == TYPEID_PLAYER)
4160 sLog.outError("Player %s have invalid faction (faction template id) #%u", ((Player*)this)->GetName(), getFaction());
4161 else
4162 sLog.outError("Creature (template id: %u) have invalid faction (faction template id) #%u", ((Creature*)this)->GetCreatureInfo()->Entry, getFaction());
4163 guid = GetGUID();
4166 return entry;
4169 bool Unit::IsHostileTo(Unit const* unit) const
4171 // always non-hostile to self
4172 if(unit==this)
4173 return false;
4175 // always hostile to enemy
4176 if(getVictim()==unit || unit->getVictim()==this)
4177 return true;
4179 // test pet/charm masters instead pers/charmeds
4180 Unit const* testerOwner = GetCharmerOrOwner();
4181 Unit const* targetOwner = unit->GetCharmerOrOwner();
4183 // always hostile to owner's enemy
4184 if(testerOwner && (testerOwner->getVictim()==unit || unit->getVictim()==testerOwner))
4185 return true;
4187 // always hostile to enemy owner
4188 if(targetOwner && (getVictim()==targetOwner || targetOwner->getVictim()==this))
4189 return true;
4191 // always hostile to owner of owner's enemy
4192 if(testerOwner && targetOwner && (testerOwner->getVictim()==targetOwner || targetOwner->getVictim()==testerOwner))
4193 return true;
4195 Unit const* tester = testerOwner ? testerOwner : this;
4196 Unit const* target = targetOwner ? targetOwner : unit;
4198 // special cases (Duel, etc)
4199 if(tester->GetTypeId()==TYPEID_PLAYER && target->GetTypeId()==TYPEID_PLAYER)
4201 // Duel
4202 if(((Player const*)tester)->duel && ((Player const*)tester)->duel->opponent == target && ((Player const*)tester)->duel->startTime != 0)
4203 return true;
4205 //= PvP states
4206 // Green/Blue (can't attack)
4207 if(((Player*)tester)->GetTeam()==((Player*)target)->GetTeam())
4208 return false;
4210 // Red (can attack) if true, Blue/Yellow (can't attack) in another case
4211 return ((Player*)tester)->IsPvP() && ((Player*)target)->IsPvP();
4214 // faction base cases
4215 FactionTemplateEntry const*tester_faction = tester->getFactionTemplateEntry();
4216 FactionTemplateEntry const*target_faction = target->getFactionTemplateEntry();
4217 if(!tester_faction || !target_faction)
4218 return false;
4220 // PvC forced reaction and reputation case
4221 if(tester->GetTypeId()==TYPEID_PLAYER)
4223 // forced reaction
4224 ForcedReactions::const_iterator forceItr = ((Player*)tester)->m_forcedReactions.find(target_faction->faction);
4225 if(forceItr!=((Player*)tester)->m_forcedReactions.end())
4227 return forceItr->second <= REP_HOSTILE;
4230 // apply reputation state
4231 FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction);
4232 if(raw_target_faction && raw_target_faction->reputationListID >=0 )
4234 if(((Player*)tester)->IsFactionAtWar(raw_target_faction))
4235 return true;
4238 // CvP forced reaction and reputation case
4239 else if(target->GetTypeId()==TYPEID_PLAYER)
4241 // forced reaction
4242 ForcedReactions::const_iterator forceItr = ((Player*)target)->m_forcedReactions.find(tester_faction->faction);
4243 if(forceItr!=((Player*)target)->m_forcedReactions.end())
4245 return forceItr->second <= REP_HOSTILE;
4248 // apply reputation state
4249 FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction);
4250 if(raw_tester_faction && raw_tester_faction->reputationListID >=0 )
4252 return ((Player*)target)->GetReputationRank(raw_tester_faction) <= REP_HOSTILE;
4256 // common faction based case (CvC,PvC,CvP)
4257 return tester_faction->IsHostileTo(*target_faction);
4260 bool Unit::IsFriendlyTo(Unit const* unit) const
4262 // always friendly to self
4263 if(unit==this)
4264 return true;
4266 // always non-friendly to enemy
4267 if(getVictim()==unit || unit->getVictim()==this)
4268 return false;
4270 // test pet/charm masters instead pers/charmeds
4271 Unit const* testerOwner = GetCharmerOrOwner();
4272 Unit const* targetOwner = unit->GetCharmerOrOwner();
4274 // always non-friendly to owner's enemy
4275 if(testerOwner && (testerOwner->getVictim()==unit || unit->getVictim()==testerOwner))
4276 return false;
4278 // always non-friendly to enemy owner
4279 if(targetOwner && (getVictim()==targetOwner || targetOwner->getVictim()==this))
4280 return false;
4282 // always non-friendly to owner of owner's enemy
4283 if(testerOwner && targetOwner && (testerOwner->getVictim()==targetOwner || targetOwner->getVictim()==testerOwner))
4284 return false;
4286 Unit const* tester = testerOwner ? testerOwner : this;
4287 Unit const* target = targetOwner ? targetOwner : unit;
4289 // special cases (Duel)
4290 if(tester->GetTypeId()==TYPEID_PLAYER && target->GetTypeId()==TYPEID_PLAYER)
4292 // Duel
4293 if(((Player const*)tester)->duel && ((Player const*)tester)->duel->opponent == target && ((Player const*)tester)->duel->startTime != 0)
4294 return false;
4296 //= PvP states
4297 // Green/Blue (non-attackable)
4298 if(((Player*)tester)->GetTeam()==((Player*)target)->GetTeam())
4299 return true;
4301 // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable)
4302 return !((Player*)target)->IsPvP();
4305 // faction base cases
4306 FactionTemplateEntry const*tester_faction = tester->getFactionTemplateEntry();
4307 FactionTemplateEntry const*target_faction = target->getFactionTemplateEntry();
4308 if(!tester_faction || !target_faction)
4309 return false;
4311 // PvC forced reaction and reputation case
4312 if(tester->GetTypeId()==TYPEID_PLAYER)
4314 // forced reaction
4315 ForcedReactions::const_iterator forceItr = ((Player*)tester)->m_forcedReactions.find(target_faction->faction);
4316 if(forceItr!=((Player*)tester)->m_forcedReactions.end())
4318 return forceItr->second >= REP_FRIENDLY;
4321 // apply reputation state
4322 FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction);
4323 if(raw_target_faction && raw_target_faction->reputationListID >=0 )
4325 if(((Player*)tester)->IsFactionAtWar(raw_target_faction))
4326 return false;
4329 // CvP forced reaction and reputation case
4330 else if(target->GetTypeId()==TYPEID_PLAYER)
4332 // forced reaction
4333 ForcedReactions::const_iterator forceItr = ((Player*)target)->m_forcedReactions.find(tester_faction->faction);
4334 if(forceItr!=((Player*)target)->m_forcedReactions.end())
4336 return forceItr->second >= REP_FRIENDLY;
4339 // apply reputation state
4340 FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction);
4341 if(raw_tester_faction && raw_tester_faction->reputationListID >=0 )
4343 return ((Player*)target)->GetReputationRank(raw_tester_faction) >= REP_FRIENDLY;
4347 // common faction based case (CvC,PvC,CvP)
4348 return tester_faction->IsFriendlyTo(*target_faction);
4351 bool Unit::IsHostileToPlayers() const
4353 FactionTemplateEntry const* my_faction = getFactionTemplateEntry();
4354 if(!my_faction)
4355 return false;
4357 FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction);
4358 if(raw_faction && raw_faction->reputationListID >=0 )
4359 return false;
4361 return my_faction->IsHostileToPlayers();
4364 bool Unit::IsNeutralToAll() const
4366 FactionTemplateEntry const* my_faction = getFactionTemplateEntry();
4367 if(!my_faction)
4368 return true;
4370 FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction);
4371 if(raw_faction && raw_faction->reputationListID >=0 )
4372 return false;
4374 return my_faction->IsNeutralToAll();
4377 bool Unit::Attack(Unit *victim, bool playerMeleeAttack)
4379 if(!victim || victim == this)
4380 return false;
4382 // player don't must attack in mount state
4383 if(GetTypeId()==TYPEID_PLAYER && IsMounted())
4384 return false;
4386 // anyone don't must attack GM in GM-mode
4387 if(victim->GetTypeId()==TYPEID_PLAYER && ((Player*)victim)->isGameMaster())
4388 return false;
4390 if (m_attacking)
4392 if (m_attacking == victim)
4393 return false;
4394 AttackStop();
4397 //Set our target
4398 SetUInt64Value(UNIT_FIELD_TARGET, victim->GetGUID());
4400 addUnitState(UNIT_STAT_ATTACKING);
4401 SetInCombat();
4402 m_attacking = victim;
4403 m_attacking->_addAttacker(this);
4405 if(m_attacking->GetTypeId()==TYPEID_UNIT && ((Creature*)m_attacking)->AI())
4406 ((Creature*)m_attacking)->AI()->AttackedBy(this);
4408 if( GetTypeId()==TYPEID_UNIT && !(((Creature*)this)->isPet() || isCharmed()) )
4410 ((Creature*)this)->CallAssistence();
4412 //if(!isAttackReady(BASE_ATTACK))
4413 //resetAttackTimer(BASE_ATTACK);
4415 // delay offhand weapon attack to next attack time
4416 if(haveOffhandWeapon())
4417 resetAttackTimer(OFF_ATTACK);
4419 if(playerMeleeAttack)
4420 SendAttackStart(victim);
4422 return true;
4425 bool Unit::AttackStop()
4427 if (!m_attacking)
4428 return false;
4430 Unit* victim = m_attacking;
4432 m_attacking->_removeAttacker(this);
4433 m_attacking = NULL;
4435 //Clear our target
4436 SetUInt64Value(UNIT_FIELD_TARGET, 0);
4438 clearUnitState(UNIT_STAT_ATTACKING);
4440 InterruptSpell(CURRENT_MELEE_SPELL);
4442 if( GetTypeId()==TYPEID_UNIT )
4444 // reset call assistance
4445 ((Creature*)this)->SetNoCallAssistence(false);
4448 SendAttackStop(victim);
4450 return true;
4453 bool Unit::isAttackingPlayer() const
4455 if(getVictim())
4457 if(getVictim()->GetTypeId() == TYPEID_PLAYER)
4458 return true;
4460 if(getVictim()->GetOwnerGUID() && GUID_HIPART(getVictim()->GetOwnerGUID())==HIGHGUID_PLAYER)
4461 return true;
4464 Pet* pet = GetPet();
4465 if(pet && pet->isAttackingPlayer())
4466 return true;
4468 Unit* charmed = GetCharm();
4469 if(charmed && charmed->isAttackingPlayer())
4470 return true;
4472 for (int8 i = 0; i < 4; i++)
4474 if(m_TotemSlot[i])
4476 Creature *totem = ObjectAccessor::Instance().GetCreature(*this, m_TotemSlot[i]);
4477 if(totem && totem->isAttackingPlayer())
4478 return true;
4482 return false;
4485 void Unit::RemoveAllAttackers()
4487 while (m_attackers.size() != 0)
4489 AttackerSet::iterator iter = m_attackers.begin();
4490 if(!(*iter)->AttackStop())
4492 sLog.outError("WORLD: Unit has an attacker that isnt attacking it!");
4493 m_attackers.erase(iter);
4498 void Unit::ModifyAuraState(uint32 flag, bool apply)
4500 if (apply)
4502 if (!HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)))
4504 SetFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
4505 if(GetTypeId() == TYPEID_PLAYER)
4507 const PlayerSpellMap& sp_list = ((Player*)this)->GetSpellMap();
4508 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
4510 if(itr->second->state == PLAYERSPELL_REMOVED) continue;
4511 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
4512 if (!spellInfo || !IsPassiveSpell(itr->first)) continue;
4513 if (spellInfo->CasterAuraState == flag)
4514 CastSpell(this, itr->first, true, NULL);
4519 else
4521 if (HasFlag(UNIT_FIELD_AURASTATE,1<<(flag-1)))
4523 RemoveFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
4524 Unit::AuraMap& tAuras = GetAuras();
4525 for (Unit::AuraMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
4527 if ((*itr).second->GetSpellProto()->CasterAuraState == flag)
4528 RemoveAura(itr);
4529 else
4530 ++itr;
4536 Unit *Unit::GetOwner() const
4538 uint64 ownerid = GetOwnerGUID();
4539 if(!ownerid)
4540 return NULL;
4541 return ObjectAccessor::Instance().GetUnit(*this, ownerid);
4544 Unit *Unit::GetCharmer() const
4546 uint64 charmerid = GetCharmerGUID();
4547 if(!charmerid)
4548 return NULL;
4549 return ObjectAccessor::Instance().GetUnit(*this, charmerid);
4552 Pet* Unit::GetPet() const
4554 uint64 pet_guid = GetPetGUID();
4555 if(pet_guid)
4557 Pet* pet = ObjectAccessor::Instance().GetPet(pet_guid);
4558 if(!pet)
4560 sLog.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid));
4561 const_cast<Unit*>(this)->SetPet(0);
4562 return NULL;
4564 return pet;
4567 return NULL;
4570 Unit* Unit::GetCharm() const
4572 uint64 charm_guid = GetCharmGUID();
4573 if(charm_guid)
4575 Unit* pet = ObjectAccessor::Instance().GetUnit(*this, charm_guid);
4576 if(!pet)
4578 sLog.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid));
4579 const_cast<Unit*>(this)->SetCharm(0);
4581 return pet;
4583 else
4584 return NULL;
4587 void Unit::SetPet(Pet* pet)
4589 SetUInt64Value(UNIT_FIELD_SUMMON,pet ? pet->GetGUID() : 0);
4591 if(pet)
4593 for(int i = 0; i < MAX_MOVE_TYPE; ++i)
4595 pet->SetSpeed(UnitMoveType(i),m_speed_rate[i],true);
4600 void Unit::SetCharm(Unit* charmed)
4602 SetUInt64Value(UNIT_FIELD_CHARM,charmed ? charmed->GetGUID() : 0);
4605 void Unit::UnsummonAllTotems()
4607 for (int8 i = 0; i < 4; ++i)
4609 if(!m_TotemSlot[i])
4610 continue;
4612 Creature *OldTotem = ObjectAccessor::Instance().GetCreature(*this, m_TotemSlot[i]);
4613 if (OldTotem && OldTotem->isTotem())
4614 ((Totem*)OldTotem)->UnSummon();
4618 void Unit::SendHealSpellOnPlayer(Unit *pVictim, uint32 SpellID, uint32 Damage, bool critical)
4620 // we guess size
4621 WorldPacket data(SMSG_HEALSPELL_ON_PLAYER_OBSOLETE, (8+8+4+4+1));
4622 data.append(pVictim->GetPackGUID());
4623 data.append(GetPackGUID());
4624 data << SpellID;
4625 data << Damage;
4626 data << uint8(critical ? 1 : 0);
4627 SendMessageToSet(&data, true);
4630 void Unit::SendHealSpellOnPlayerPet(Unit *pVictim, uint32 SpellID, uint32 Damage,Powers powertype, bool critical)
4632 WorldPacket data(SMSG_HEALSPELL_ON_PLAYERS_PET_OBSOLETE, (8+8+4+4+4+1));
4633 data.append(pVictim->GetPackGUID());
4634 data.append(GetPackGUID());
4635 data << SpellID;
4636 data << uint32(powertype);
4637 data << Damage;
4638 data << uint8(critical ? 1 : 0);
4639 SendMessageToSet(&data, true);
4642 uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 pdamage, DamageEffectType damagetype)
4644 if(!spellProto || !pVictim || damagetype==DIRECT_DAMAGE )
4645 return pdamage;
4647 if(pVictim->IsImmunedToSpellDamage(spellProto))
4648 return 0;
4650 uint32 creatureTypeMask = GetCreatureTypeMask();
4652 // Damage Done
4653 uint32 CastingTime = GetCastTime(sCastTimesStore.LookupEntry(spellProto->CastingTimeIndex));
4654 if (CastingTime > 7000) CastingTime = 7000; // Plus Damage efficient maximum 200% ( 7.0 seconds )
4655 if (CastingTime < 1500) CastingTime = 1500;
4657 // Taken/Done fixed damage bonus auras
4658 int32 DoneAdvertisedBenefit = 0;
4659 int32 TakenAdvertisedBenefit = 0;
4661 // ..done (for creature type by mask) in taken
4662 AuraList const& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
4663 for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
4664 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
4665 TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount;
4667 // ..done
4668 AuraList const& mDamageDone = this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE);
4669 for(AuraList::const_iterator i = mDamageDone.begin();i != mDamageDone.end(); ++i)
4670 if(((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0 &&
4671 (*i)->GetSpellProto()->EquippedItemClass == -1 &&
4672 // -1 == any item class (not wand then)
4673 (*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 )
4674 // 0 == any inventory type (not wand then)
4675 DoneAdvertisedBenefit += (*i)->GetModifier()->m_amount;
4677 if (GetTypeId() == TYPEID_PLAYER)
4679 // Damage bonus of spirit
4680 AuraList const& mDamageDonebySpi = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_SPIRIT);
4681 for(AuraList::const_iterator i = mDamageDonebySpi.begin();i != mDamageDonebySpi.end(); ++i)
4682 if((*i)->GetModifier()->m_miscvalue & 1 << spellProto->School)
4683 DoneAdvertisedBenefit += int32(GetStat(STAT_SPIRIT) * (*i)->GetModifier()->m_amount / 100.0f);
4685 // ... and intellect
4686 AuraList const& mDamageDonebyInt = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_INTELLECT);
4687 for(AuraList::const_iterator i = mDamageDonebyInt.begin();i != mDamageDonebyInt.end(); ++i)
4688 if ((*i)->GetModifier()->m_miscvalue & 1 << spellProto->School)
4689 DoneAdvertisedBenefit += int32(GetStat(STAT_INTELLECT) * (*i)->GetModifier()->m_amount / 100.0f);
4692 // ..taken
4693 AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
4694 for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
4695 if(((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0)
4696 TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount;
4698 // Damage over Time spells bonus calculation
4699 float DotFactor = 1.0f;
4700 if(damagetype == DOT)
4702 CastingTime = 3500;
4703 uint32 DotDuration = GetDuration(spellProto);
4704 // 200% limit
4705 if(DotDuration > 0)
4707 if(DotDuration > 30000) DotDuration = 30000;
4708 DotFactor = DotDuration / 15000.0f;
4709 int x = 0;
4710 for(int j = 0; j < 3; j++)
4711 if(spellProto->Effect[j] == 6) x = j;
4712 int DotTicks = 6;
4713 if(spellProto->EffectAmplitude[x] != 0)
4714 DotTicks = DotDuration / spellProto->EffectAmplitude[x];
4715 if(DotTicks)
4717 DoneAdvertisedBenefit /= DotTicks;
4718 TakenAdvertisedBenefit /= DotTicks;
4723 // Taken/Done total percent damage auras
4724 float DoneTotalMod = 1.0f;
4725 float TakenTotalMod = 1.0f;
4727 // ..done
4728 AuraList const& mModDamagePercentDone = this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
4729 for(AuraList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
4731 if( ((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0 &&
4732 (*i)->GetSpellProto()->EquippedItemClass == -1 &&
4733 // -1 == any item class (not wand then)
4734 (*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 )
4735 // 0 == any inventory type (not wand then)
4737 DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
4741 // ..taken
4742 AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
4743 for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
4744 if( ((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0 )
4745 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
4747 // Exceptions
4748 // Lifetap
4749 if(spellProto->SpellVisual == 1225 && spellProto->SpellIconID == 208)
4751 CastingTime = 2800; // 80% from +shadow damage
4752 DoneTotalMod = 1.0f;
4753 TakenTotalMod = 1.0f;
4755 // Dark Pact
4756 if(spellProto->SpellVisual == 827 && spellProto->SpellIconID == 154 && GetPet())
4758 CastingTime = 3360; // 96% from +shadow damage
4759 DoneTotalMod = 1.0f;
4760 TakenTotalMod = 1.0f;
4762 // Ice Lance
4763 if(spellProto->Id == 30455)
4765 CastingTime /= 3.0f; // applied 1/3 bonuses in case generic target
4766 if(pVictim->isFrozen()) // and compensate this for frozen target.
4767 TakenTotalMod *= 3.0f;
4770 // Level Factor
4771 float LvlPenalty = 0.0f;
4772 if(spellProto->spellLevel < 20)
4773 LvlPenalty = (20.0f - (float)(spellProto->spellLevel)) * 3.75f;
4774 float LvlFactor = ((float)(spellProto->spellLevel) + 6.0f) / (float)(getLevel());
4775 if(LvlFactor > 1.0f)
4776 LvlFactor = 1.0f;
4778 // Spellmod SpellDamage
4779 float SpellModSpellDamage = 100.0f;
4780 if (GetTypeId() == TYPEID_PLAYER)
4781 ((Player*)this)->ApplySpellMod(spellProto->Id,SPELLMOD_SPELL_DAMAGE,SpellModSpellDamage);
4782 SpellModSpellDamage /= 100.0f;
4784 float DoneActualBenefit = DoneAdvertisedBenefit * (CastingTime / 3500.0f) * (100.0f - LvlPenalty) * LvlFactor * DotFactor * SpellModSpellDamage / 100.0f;
4785 float TakenActualBenefit = TakenAdvertisedBenefit * (CastingTime / 3500.0f) * (100.0f - LvlPenalty) * LvlFactor * DotFactor / 100.0f;
4787 float tmpDamage = (float(pdamage)+DoneActualBenefit)*DoneTotalMod;
4788 tmpDamage = (tmpDamage+TakenActualBenefit)*TakenTotalMod;
4790 return tmpDamage > 0 ? uint32(tmpDamage) : 0;
4793 bool Unit::SpellCriticalBonus(SpellEntry const *spellProto, int32 *peffect, Unit *pVictim)
4795 // Chance to crit is computed from INT and LEVEL as follows:
4796 // chance = base + INT / (rate0 + rate1 * LEVEL)
4797 // The formula keeps the crit chance at %5 on every level unless the player
4798 // increases his intelligence by other means (enchants, buffs, talents, ...)
4799 if(spellProto->Id == 15290 || spellProto->Id == 39373) return false;
4801 float crit_chance = 0.0f;
4803 // base value
4804 if (GetTypeId() != TYPEID_PLAYER)
4806 // flat done
4807 // TODO: can creatures have critical chance auras?
4808 crit_chance = m_baseSpellCritChance;
4809 AuraList const& mSpellCritSchool = GetAurasByType(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL);
4810 for(AuraList::const_iterator i = mSpellCritSchool.begin(); i != mSpellCritSchool.end(); ++i)
4811 if((*i)->GetModifier()->m_miscvalue == -2 || ((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0)
4812 crit_chance += (*i)->GetModifier()->m_amount;
4814 else
4815 crit_chance = GetFloatValue( PLAYER_SPELL_CRIT_PERCENTAGE1 + spellProto->School);
4817 // percent done
4818 // only players use intelligence for critical chance computations
4819 if (GetTypeId() == TYPEID_PLAYER)
4821 ((Player*)this)->ApplySpellMod(spellProto->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance);
4824 // taken
4825 if (pVictim)
4827 // flat
4828 AuraList const& mAttackerSpellCrit = pVictim->GetAurasByType(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE);
4829 for(AuraList::const_iterator i = mAttackerSpellCrit.begin(); i != mAttackerSpellCrit.end(); ++i)
4830 if((*i)->GetModifier()->m_miscvalue == -2 || ((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0)
4831 crit_chance += (*i)->GetModifier()->m_amount;
4833 // flat: Resilience - reduce crit chance by x%
4834 crit_chance -= pVictim->m_modResilience;
4836 // flat: scripted (increase crit chance ... against ... target by x%
4837 AuraList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4838 for(AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
4840 switch((*i)->GetModifier()->m_miscvalue)
4842 //Shatter Rank 1
4843 case 849: if(pVictim->isFrozen()) crit_chance+= 10; break;
4844 //Shatter Rank 2
4845 case 910: if(pVictim->isFrozen()) crit_chance+= 20; break;
4846 //Shatter Rank 3
4847 case 911: if(pVictim->isFrozen()) crit_chance+= 30; break;
4848 //Shatter Rank 4
4849 case 912: if(pVictim->isFrozen()) crit_chance+= 40; break;
4850 //Shatter Rank 5
4851 case 913: if(pVictim->isFrozen()) crit_chance+= 50; break;
4855 // flat
4856 AuraList const& mAttackerSWCrit = pVictim->GetAurasByType(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
4857 for(AuraList::const_iterator i = mAttackerSWCrit.begin(); i != mAttackerSWCrit.end(); ++i)
4858 crit_chance += (*i)->GetModifier()->m_amount;
4861 crit_chance = crit_chance > 0.0 ? crit_chance : 0.0;
4862 if (roll_chance_f(crit_chance))
4864 int32 crit_bonus = *peffect / 2;
4865 if (GetTypeId() == TYPEID_PLAYER) // adds additional damage to crit_bonus (from talents)
4866 ((Player*)this)->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
4868 *peffect += crit_bonus;
4869 // Resilience - reduce crit damage by 2x%
4870 if (pVictim)
4871 *peffect -= int32(pVictim->m_modResilience * 2/100 * (*peffect));
4873 return true;
4875 return false;
4878 uint32 Unit::SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, Unit *pVictim)
4880 // Healing Done
4882 // Vampiric Embrace, Shadowmend - cannot critically heal
4883 if(spellProto->Id == 15290 || spellProto->Id == 39373) return healamount;
4885 int32 AdvertisedBenefit = 0;
4886 uint32 CastingTime = GetCastTime(sCastTimesStore.LookupEntry(spellProto->CastingTimeIndex));
4887 if (CastingTime > 7000) CastingTime = 7000;
4888 if (CastingTime < 1500) CastingTime = 1500;
4889 if (spellProto->Effect[0] == SPELL_EFFECT_APPLY_AURA) CastingTime = 3500;
4891 AuraList const& mHealingDone = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE);
4892 for(AuraList::const_iterator i = mHealingDone.begin();i != mHealingDone.end(); ++i)
4893 if(((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0)
4894 AdvertisedBenefit += (*i)->GetModifier()->m_amount;
4896 // Healing bonus of spirit, intellect and strength
4897 if (GetTypeId() == TYPEID_PLAYER)
4899 AdvertisedBenefit += int32(GetStat(STAT_SPIRIT) * GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HEALING_OF_SPIRIT) / 100.0f);
4900 AdvertisedBenefit += int32(GetStat(STAT_INTELLECT) * GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HEALING_OF_INTELLECT) / 100.0f);
4901 AdvertisedBenefit += int32(GetStat(STAT_STRENGTH) * GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HEALING_OF_STRENGTH) / 100.0f);
4904 // Healing Taken
4905 AdvertisedBenefit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_HEALING);
4907 //BoL dummy effects
4908 if (spellProto->SpellFamilyName == SPELLFAMILY_PALADIN && (spellProto->SpellFamilyFlags & 0xC0000000))
4910 AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
4911 for(AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
4912 if((*i)->GetSpellProto()->SpellVisual == 9180)
4913 //FoL
4914 if ((spellProto->SpellFamilyFlags & 0x40000000) && (*i)->GetEffIndex() == 1)
4915 AdvertisedBenefit += (*i)->GetModifier()->m_amount;
4916 //HL
4917 else if ((spellProto->SpellFamilyFlags & 0x80000000) && (*i)->GetEffIndex() == 0)
4918 AdvertisedBenefit += (*i)->GetModifier()->m_amount;
4921 // Healing over Time spells
4922 float DotFactor = 1.0f;
4923 if(damagetype == DOT)
4925 CastingTime = 3500;
4926 uint32 DotDuration = GetDuration(spellProto);
4927 // 200% limit
4928 if(DotDuration > 30000) DotDuration = 30000;
4929 DotFactor = DotDuration / 15000.0f;
4930 int x = 0;
4931 for(int j = 0; j < 3; j++)
4932 if(spellProto->Effect[j] == 6) x = j;
4933 int DotTicks = 6;
4934 if(spellProto->EffectAmplitude[x] != 0)
4935 DotTicks = DotDuration / spellProto->EffectAmplitude[x];
4936 if(DotTicks)
4937 AdvertisedBenefit /= DotTicks;
4940 // Level Factor
4941 float LvlPenalty = 0.0f;
4942 if(spellProto->spellLevel < 20)
4943 LvlPenalty = (20.0f - (float)(spellProto->spellLevel)) * 3.75f;
4944 float LvlFactor = ((float)(spellProto->spellLevel) + 6.0f) / (float)(getLevel());
4945 if(LvlFactor > 1.0f)
4946 LvlFactor = 1.0f;
4948 float ActualBenefit = (float)AdvertisedBenefit * ((float)CastingTime / 3500.0f) * (100.0f - LvlPenalty) * LvlFactor * DotFactor / 100.0f;
4950 // use float as more appropriate for negative values and percent applying
4951 float heal = healamount + ActualBenefit;
4953 // TODO: check for ALL/SPELLS type
4954 // Healing done percent
4955 AuraList const& mHealingDonePct = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT);
4956 for(AuraList::const_iterator i = mHealingDonePct.begin();i != mHealingDonePct.end(); ++i)
4957 heal *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f;
4959 // Healing taken percent
4960 AuraList const& mHealingPct = pVictim->GetAurasByType(SPELL_AURA_MOD_HEALING_PCT);
4961 for(AuraList::const_iterator i = mHealingPct.begin();i != mHealingPct.end(); ++i)
4962 heal *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f;
4964 if (heal < 0) heal = 0;
4966 return uint32(heal);
4969 bool Unit::IsImmunedToPhysicalDamage() const
4971 //If m_immuneToDamage type contain magic, IMMUNE damage.
4972 SpellImmuneList const& damageImmList = m_spellImmune[IMMUNITY_DAMAGE];
4973 for (SpellImmuneList::const_iterator itr = damageImmList.begin(); itr != damageImmList.end(); ++itr)
4974 if(itr->type & IMMUNE_DAMAGE_PHYSICAL)
4975 return true;
4977 //If m_immuneToSchool type contain this school type, IMMUNE damage.
4978 SpellImmuneList const& spellImmList = m_spellImmune[IMMUNITY_SCHOOL];
4979 for (SpellImmuneList::const_iterator itr = spellImmList.begin(); itr != spellImmList.end(); ++itr)
4980 if(itr->type & IMMUNE_SCHOOL_PHYSICAL)
4981 return true;
4983 return false;
4986 bool Unit::IsImmunedToSpellDamage(SpellEntry const* spellInfo) const
4988 //If m_immuneToDamage type contain magic, IMMUNE damage.
4989 SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
4990 for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
4991 if(itr->type & uint32(1<<spellInfo->School))
4992 return true;
4994 //If m_immuneToSchool type contain this school type, IMMUNE damage.
4995 SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
4996 for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
4997 if(itr->type & uint32(1<<spellInfo->School))
4998 return true;
5000 return false;
5003 bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo) const
5005 if (!spellInfo)
5006 return false;
5008 SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL];
5009 for(SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr)
5010 if(itr->type == spellInfo->Dispel)
5011 return true;
5013 SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
5014 for(SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
5015 if(itr->type == spellInfo->Mechanic)
5016 return true;
5018 int32 chance = 0;
5019 AuraList const& mModMechanicRes = GetAurasByType(SPELL_AURA_MOD_MECHANIC_RESISTANCE);
5020 for(AuraList::const_iterator i = mModMechanicRes.begin();i != mModMechanicRes.end(); ++i)
5021 if((*i)->GetModifier()->m_miscvalue == int32(spellInfo->Mechanic))
5022 chance+= (*i)->GetModifier()->m_amount;
5023 if(roll_chance_i(chance))
5024 return true;
5026 return false;
5029 bool Unit::IsImmunedToSpellEffect(uint32 effect) const
5031 //If m_immuneToEffect type contain this effect type, IMMUNE effect.
5032 SpellImmuneList const& effectList = m_spellImmune[IMMUNITY_EFFECT];
5033 for (SpellImmuneList::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr)
5034 if(itr->type == effect)
5035 return true;
5037 return false;
5040 bool Unit::IsDamageToThreatSpell(SpellEntry const * spellInfo) const
5042 if(!spellInfo)
5043 return false;
5045 uint32 family = spellInfo->SpellFamilyName;
5046 uint32 flags = spellInfo->SpellFamilyFlags;
5048 if((family == 5 && flags == 256) || //Searing Pain
5049 (family == 6 && flags == 8192) || //Mind Blast
5050 (family == 11 && flags == 1048576)) //Earth Shock
5051 return true;
5053 return false;
5056 void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attType)
5058 if(!pVictim) return;
5060 if(*pdamage == 0)
5061 return;
5063 uint32 creatureTypeMask = GetCreatureTypeMask();
5065 if(GetTypeId() != TYPEID_PLAYER && ((Creature*)this)->isPet())
5067 if(getPowerType() == POWER_FOCUS)
5069 uint32 happiness = GetPower(POWER_HAPPINESS);
5070 if(happiness>=666000)
5071 *pdamage = uint32(*pdamage * 1.25);
5072 else if(happiness<333000)
5073 *pdamage = uint32(*pdamage * 0.75);
5074 else *pdamage = uint32(*pdamage * 1.0);
5078 // Taken/Done fixed damage bonus auras
5079 int32 DoneFlatBenefit = 0;
5080 int32 TakenFlatBenefit = 0;
5082 // ..done (for creature type by mask) in taken
5083 AuraList const& mDamageDoneCreature = this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
5084 for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
5085 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
5086 DoneFlatBenefit += (*i)->GetModifier()->m_amount;
5088 // ..done
5089 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
5091 // ..done (base at attack power and creature type)
5092 AuraList const& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_CREATURE_ATTACK_POWER);
5093 for(AuraList::const_iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i)
5094 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
5095 DoneFlatBenefit += int32((*i)->GetModifier()->m_amount/14.0f * GetAttackTime(attType)/1000);
5097 // ..done (base at attack power for marked target)
5098 if(attType == RANGED_ATTACK)
5100 AuraList const& mRangedAttackPowerAttackerBonus = pVictim->GetAurasByType(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS);
5101 for(AuraList::const_iterator i = mRangedAttackPowerAttackerBonus.begin();i != mRangedAttackPowerAttackerBonus.end(); ++i)
5102 DoneFlatBenefit += int32((*i)->GetModifier()->m_amount/14.0f * GetAttackTime(RANGED_ATTACK)/1000);
5105 // ..taken
5106 AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
5107 for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
5108 if((*i)->GetModifier()->m_miscvalue & IMMUNE_SCHOOL_PHYSICAL)
5109 TakenFlatBenefit += (*i)->GetModifier()->m_amount;
5111 if(attType!=RANGED_ATTACK)
5113 AuraList const& mModMeleeDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN);
5114 for(AuraList::const_iterator i = mModMeleeDamageTaken.begin(); i != mModMeleeDamageTaken.end(); ++i)
5115 TakenFlatBenefit += (*i)->GetModifier()->m_amount;
5117 else
5119 AuraList const& mModRangedDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN);
5120 for(AuraList::const_iterator i = mModRangedDamageTaken.begin(); i != mModRangedDamageTaken.end(); ++i)
5121 TakenFlatBenefit += (*i)->GetModifier()->m_amount;
5124 // Done/Taken total percent damage auras
5125 float TakenTotalMod = 1;
5127 // ..done
5128 // SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage
5129 // SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage
5131 // ..taken
5132 AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
5133 for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
5134 if((*i)->GetModifier()->m_miscvalue & IMMUNE_SCHOOL_PHYSICAL)
5135 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
5137 if(attType != RANGED_ATTACK)
5139 AuraList const& mModMeleeDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT);
5140 for(AuraList::const_iterator i = mModMeleeDamageTakenPercent.begin(); i != mModMeleeDamageTakenPercent.end(); ++i)
5141 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
5143 else
5145 AuraList const& mModRangedDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT);
5146 for(AuraList::const_iterator i = mModRangedDamageTakenPercent.begin(); i != mModRangedDamageTakenPercent.end(); ++i)
5147 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
5150 float tmpDamage = ((int32(*pdamage) + DoneFlatBenefit) + TakenFlatBenefit)*TakenTotalMod;
5152 // bonus result can be negative
5153 *pdamage = tmpDamage > 0 ? uint32(tmpDamage) : 0;
5156 void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply)
5158 if (apply)
5160 for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(), next; itr != m_spellImmune[op].end(); itr = next)
5162 next = itr; next++;
5163 if(itr->type == type)
5165 m_spellImmune[op].erase(itr);
5166 next = m_spellImmune[op].begin();
5169 SpellImmune Immune;
5170 Immune.spellId = spellId;
5171 Immune.type = type;
5172 m_spellImmune[op].push_back(Immune);
5174 else
5176 for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(); itr != m_spellImmune[op].end(); ++itr)
5178 if(itr->spellId == spellId)
5180 m_spellImmune[op].erase(itr);
5181 break;
5188 float Unit::GetWeaponProcChance() const
5190 // normalized proc chance for weapon attack speed
5191 // (odd formulae...)
5192 if(isAttackReady(BASE_ATTACK))
5193 return (GetAttackTime(BASE_ATTACK) * 1.8f / 1000.0f);
5194 else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK))
5195 return (GetAttackTime(OFF_ATTACK) * 1.6f / 1000.0f);
5196 return 0;
5199 float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM) const
5201 // proc per minute chance calculation
5202 if (PPM <= 0) return 0.0f;
5203 uint32 result = uint32((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
5204 return result;
5207 void Unit::Mount(uint32 mount, bool taxi)
5209 if(!mount)
5210 return;
5212 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, mount);
5214 uint32 flag = UNIT_FLAG_MOUNT;
5215 if(taxi)
5216 flag |= UNIT_FLAG_DISABLE_MOVE;
5218 SetFlag( UNIT_FIELD_FLAGS, flag );
5220 // unsummon pet
5221 if(GetTypeId() == TYPEID_PLAYER)
5223 Pet* pet = GetPet();
5224 if(pet)
5226 if(pet->getPetType() == SUMMON_PET || pet->getPetType() == HUNTER_PET)
5228 ((Player*)this)->SetOldPetNumber(pet->GetCharmInfo()->GetPetNumber());
5229 ((Player*)this)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL));
5232 ((Player*)this)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT);
5234 else
5235 ((Player*)this)->SetOldPetNumber(0);
5239 void Unit::Unmount()
5241 if(!IsMounted())
5242 return;
5244 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0);
5245 RemoveFlag( UNIT_FIELD_FLAGS ,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_MOUNT );
5247 if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->GetOldPetNumber() && isAlive())
5249 Pet* NewPet = new Pet(this);
5250 if(!NewPet->LoadPetFromDB(this, 0, ((Player*)this)->GetOldPetNumber(), true))
5251 delete NewPet;
5253 ((Player*)this)->SetOldPetNumber(0);
5257 void Unit::SetInCombat()
5259 m_CombatTimer = 5000;
5260 SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
5262 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet()))
5263 SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
5266 void Unit::ClearInCombat(bool force)
5268 // wait aura and combat timer expire
5269 if(!force && HasAuraType(SPELL_AURA_INTERRUPT_REGEN))
5270 return;
5272 m_CombatTimer = 0;
5273 RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
5275 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet()))
5276 RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
5278 // remove combo points
5279 if(GetTypeId()==TYPEID_PLAYER)
5280 ((Player*)this)->ClearComboPoints();
5283 bool Unit::isTargetableForAttack()
5285 if (GetTypeId()==TYPEID_PLAYER && ((Player *)this)->isGameMaster())
5286 return false;
5287 return isAlive() && !hasUnitState(UNIT_STAT_DIED)&& !isInFlight() /*&& !isStealth()*/;
5290 int32 Unit::ModifyHealth(int32 dVal)
5292 int32 gain = 0;
5294 if(dVal==0)
5295 return 0;
5297 int32 curHealth = (int32)GetHealth();
5299 int32 val = dVal + curHealth;
5300 if(val <= 0)
5302 SetHealth(0);
5303 return -curHealth;
5306 int32 maxHealth = (int32)GetMaxHealth();
5308 if(val < maxHealth)
5310 SetHealth(val);
5311 gain = val - curHealth;
5313 else if(curHealth != maxHealth)
5315 SetHealth(maxHealth);
5316 gain = maxHealth - curHealth;
5319 return gain;
5322 int32 Unit::ModifyPower(Powers power, int32 dVal)
5324 int32 gain = 0;
5326 if(dVal==0)
5327 return 0;
5329 int32 curPower = (int32)GetPower(power);
5331 int32 val = dVal + curPower;
5332 if(val <= 0)
5334 SetPower(power,0);
5335 return -curPower;
5338 int32 maxPower = (int32)GetMaxPower(power);
5340 if(val < maxPower)
5342 SetPower(power,val);
5343 gain = val - curPower;
5345 else if(curPower != maxPower)
5347 SetPower(power,maxPower);
5348 gain = maxPower - curPower;
5351 return gain;
5354 bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList) const
5356 if(!u)
5357 return false;
5359 // Always can see self
5360 if (u==this)
5361 return true;
5363 // player visible for other player if not logout and at same transport
5364 // including case when player is out of world
5365 bool at_same_transport =
5366 GetTypeId() == TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER &&
5367 !((Player*)this)->GetSession()->PlayerLogout() && !((Player*)u)->GetSession()->PlayerLogout() &&
5368 !((Player*)this)->GetSession()->PlayerLoading() && !((Player*)u)->GetSession()->PlayerLoading() &&
5369 ((Player*)this)->GetTransport() && ((Player*)this)->GetTransport() == ((Player*)u)->GetTransport();
5371 // not in world
5372 if(!at_same_transport && (!IsInWorld() || !u->IsInWorld()))
5373 return false;
5375 // always seen by owner
5376 if(GetCharmerOrOwnerGUID()==u->GetGUID())
5377 return true;
5379 // Grid dead/alive checks
5380 if( u->GetTypeId()==TYPEID_PLAYER)
5382 // non visible at grid for any stealth state
5383 if(!IsVisibleInGridForPlayer((Player *)u))
5384 return false;
5386 // if player is dead then he can't detect anyone in anycases
5387 if(!u->isAlive())
5388 detect = false;
5390 else
5392 // all dead creatures/players not visible for any creatures
5393 if(!u->isAlive() || !isAlive())
5394 return false;
5397 // different visible distance checks
5398 if(u->isInFlight()) // what see player in flight
5400 // use object grey distance for all (only see objects any way)
5401 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceInFlight()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f)))
5402 return false;
5404 else if(!isAlive()) // distance for show body
5406 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f)))
5407 return false;
5409 else if(GetTypeId()==TYPEID_PLAYER) // distance for show player
5411 if(u->GetTypeId()==TYPEID_PLAYER)
5413 // Players far than max visible distance for player or not in our map are not visible too
5414 if (!at_same_transport && !IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))
5415 return false;
5417 else
5419 // Units far than max visible distance for creature or not in our map are not visible too
5420 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))
5421 return false;
5424 else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed
5426 // Pet/charmed far than max visible distance for player or not in our map are not visible too
5427 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))
5428 return false;
5430 else // distance for show creature
5432 // Units far than max visible distance for creature or not in our map are not visible too
5433 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))
5434 return false;
5437 // Visible units, always are visible for all units, except for units under invisibility
5438 if (m_Visibility == VISIBILITY_ON && u->GetVisibility()!= VISIBILITY_GROUP_INVISIBILITY)
5439 return true;
5441 // GMs are visible for higher gms (or players are visible for gms)
5442 if (u->GetTypeId() == TYPEID_PLAYER && ((Player *)u)->isGameMaster())
5443 return (GetTypeId() == TYPEID_PLAYER && ((Player *)this)->GetSession()->GetSecurity() <= ((Player *)u)->GetSession()->GetSecurity());
5445 // non faction visibility non-breakable for non-GMs
5446 if (m_Visibility == VISIBILITY_OFF)
5447 return false;
5449 // Invisible units, always are visible for units under invisibility or unit that can detect this invisibility
5450 if (m_Visibility == VISIBILITY_GROUP_INVISIBILITY)
5452 if(u->GetVisibility()== VISIBILITY_GROUP_INVISIBILITY || m_invisibilityvalue <= u->m_detectInvisibility)
5453 return true;
5456 // Units that can detect invisibility always are visible for units that can be detected
5457 if (u->GetVisibility()== VISIBILITY_GROUP_INVISIBILITY)
5459 if(m_detectInvisibility >= u->m_invisibilityvalue)
5460 return true;
5463 // Stealth/invisible not hostile units, not visible (except Player-with-Player case)
5464 if (!u->IsHostileTo(this))
5466 // 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)
5467 if(GetTypeId()==TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER)
5469 if(((Player*)this)->IsGroupVisibleFor(((Player*)u)))
5470 return true;
5472 // else apply same rules as for hostile case (detecting check)
5475 else
5477 // Hunter mark functionality
5478 AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_STALKED);
5479 for(AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
5480 if((*iter)->GetCasterGUID()==u->GetGUID())
5481 return true;
5484 // unit got in stealth in this moment and must ignore old detected state
5485 // invisibility not have chance for detection
5486 if (m_Visibility == VISIBILITY_ON || m_Visibility == VISIBILITY_GROUP_NO_DETECT || m_Visibility == VISIBILITY_GROUP_INVISIBILITY)
5487 return false;
5489 // NOW ONLY STEALTH CASE
5491 // stealth and detected
5492 if (u->GetTypeId() == TYPEID_PLAYER && ((Player*)u)->HaveAtClient(this) )
5493 return true;
5495 //if in non-detect mode then invisible for unit
5496 if (!detect)
5497 return false;
5499 // Special cases
5500 bool IsVisible = true;
5501 bool isInFront = u->isInFront(this,World::GetMaxVisibleDistanceForObject());
5502 float distance = sqrt(GetDistanceSq(u));
5504 // If is attacked then stealth is lost, some creature can use stealth too
5505 if (this->isAttacked())
5506 return IsVisible;
5508 // If there is collision rogue is seen regardless of level difference
5509 // TODO: check sizes in DB
5510 if (distance < 0.24f)
5511 return IsVisible;
5513 //If a mob or player is stunned he will not be able to detect stealth
5514 if ((u->hasUnitState(UNIT_STAT_STUNDED)) && (u != this))
5516 IsVisible=false;
5517 return IsVisible;
5520 // Cases based on level difference and position
5521 int32 levelDiff = u->getLevel() - this->getLevel();
5523 //If mob is 5 levels more than player he gets detected automaticly
5524 if (u->GetTypeId()!=TYPEID_PLAYER && levelDiff > 5)
5525 return IsVisible;
5527 // If victim has more than 5 lvls above caster
5528 if ((this->GetTypeId() == TYPEID_UNIT)&& ( levelDiff > 5 ))
5529 return IsVisible;
5531 // If caster has more than 5 levels above victim
5532 if ((this->GetTypeId() == TYPEID_UNIT)&& ( levelDiff < -5 ))
5534 IsVisible=false;
5535 return IsVisible;
5538 float modifier = 1; // 100 pct
5539 float pvpMultiplier = 0;
5540 float distanceFormula = 0;
5541 int32 rank = 0;
5542 //This allows to check talent tree and will add addition stealth dependant on used points)
5543 uint32 stealthMod = GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL);
5544 //****************************************************************************************
5545 // Stealth detection calculation
5546 int32 x = (((u->m_detectStealth+1) / 5) - (((m_stealthvalue+1) / 5) + (stealthMod/5) + 59));
5548 if (x<0) x = 1;
5549 // Check rank if mob is not a player otherwise rank = 1 and there is no modifier when in pvp
5550 if (u->GetTypeId() != TYPEID_PLAYER)
5551 rank = ((Creature const*)u)->GetCreatureInfo()->rank;
5553 // Probabilty of being seen
5554 if (levelDiff < 0)
5555 distanceFormula = ((sWorld.getRate(RATE_CREATURE_AGGRO) * 16) / (abs(levelDiff) + 1.5)) * 2;
5556 if (levelDiff >= 0)
5557 distanceFormula = (((sWorld.getRate(RATE_CREATURE_AGGRO) * 16)) / 2) * (levelDiff + 1);
5559 // Original probability values
5560 // removed level of mob in calculation as it should not affect the detection, it is mainly dependant on level difference
5561 //at this distance, the detector has to be a 15% prob of detect
5562 float averageDist = 1 - 0.11016949 * x + 0.00301637 * x * x;
5563 if (averageDist < 1) averageDist = 1;
5565 float prob = 0;
5566 if (distance > averageDist)
5567 //prob between 10% and 0%
5568 prob = (averageDist - 200 + 9 * distance) / (averageDist - 20);
5569 else
5570 prob = 75 - (60 / averageDist) * distance; //prob between 15% and 75% (75% max prob)
5572 // If is not in front, probability floor
5573 if (!isInFront)
5574 prob = prob / 100;
5575 if (prob < 0.1)
5576 prob = 0.1;
5578 // Mob rank affects modifier
5579 modifier = rank <= 4 ? 1 + rank * 0.2f : 1;
5581 if (distance < 0.24f)
5583 return IsVisible;
5586 // PVP distance assigned depending on level
5587 if (this->GetTypeId() == TYPEID_UNIT)
5589 // Level diff floor/ceiling <-5,5>
5590 pvpMultiplier = levelDiff > 5 ? 12 : levelDiff < 5 ? 2 : 7 + levelDiff;
5591 pvpMultiplier = pvpMultiplier - (x / 100);
5594 // PVP stealth handler
5595 if (this->GetTypeId() == TYPEID_PLAYER)
5597 // Do not loose stealth when coming from back
5598 if (!isInFront)
5600 IsVisible=false;
5601 return IsVisible;
5604 // If comes in front
5605 if (isInFront && (distance >= pvpMultiplier))
5607 IsVisible=false;
5608 return IsVisible;
5611 if (isInFront && (distance < pvpMultiplier))
5613 return IsVisible;
5616 else
5618 // PVE stealth handler
5619 // Distance of approch player stays stealth 100% is dependant of level. No probabiliy or detection is rolled
5620 // This establishes a buffer zone in between mob start to see you and mob start to roll probabilities or detect you
5621 if ((distance < 100) && (distance > ((distanceFormula * 2) * modifier)) && (distance > 0.24f))
5623 IsVisible=false;
5624 return IsVisible;
5627 //If victim is level lower or more probability of detection drops
5628 if ((levelDiff < 0) && (distance > 0.24f))
5630 if (abs(levelDiff ) > 4)
5631 IsVisible = false;
5632 else
5634 if (rand_chance() > ( prob * modifier / (30 + levelDiff * 5)))
5635 IsVisible = false;
5637 return IsVisible;
5639 // Level detection based on level, the higher the mob level the higher the chance of detection.
5640 if ((distance > 0.24f) && (levelDiff < 5) && (levelDiff >= 0))
5642 if (rand_chance() > ((prob * modifier) / (30 - levelDiff * 5) ))
5643 IsVisible = false;
5644 else
5645 IsVisible = true;
5647 return IsVisible;
5651 // Didn't match any criteria ?
5652 DEBUG_LOG("Unit::isVisibleForFor unhandled result, dist %f levelDiff %i target_type %u prob %u modifier %u",distance,levelDiff,u->GetTypeId(),prob, modifier);
5654 // Safety return
5655 return IsVisible;
5658 void Unit::SetVisibility(UnitVisibility x)
5660 m_Visibility = x;
5662 if(IsInWorld())
5664 Map *m = MapManager::Instance().GetMap(GetMapId(), this);
5666 if(GetTypeId()==TYPEID_PLAYER)
5667 m->PlayerRelocation((Player*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
5668 else
5669 m->CreatureRelocation((Creature*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
5673 float Unit::GetSpeed( UnitMoveType mtype ) const
5675 return m_speed_rate[mtype]*baseMoveSpeed[mtype];
5678 void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced)
5680 m_speed_rate[mtype] = 1.0f;
5681 ApplySpeedMod(mtype, rate, forced, true);
5684 void Unit::ApplySpeedMod(UnitMoveType mtype, float rate, bool forced, bool apply)
5686 WorldPacket data;
5688 if(apply)
5689 m_speed_rate[mtype] *= rate;
5690 else
5691 m_speed_rate[mtype] /= rate;
5693 switch(mtype)
5695 case MOVE_WALK:
5696 if(forced) { data.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE, 16); }
5697 else { data.Initialize(MSG_MOVE_SET_WALK_SPEED, 16); }
5698 break;
5699 case MOVE_RUN:
5700 if(forced) { data.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE, 16); }
5701 else { data.Initialize(MSG_MOVE_SET_RUN_SPEED, 16); }
5702 break;
5703 case MOVE_WALKBACK:
5704 if(forced) { data.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE, 16); }
5705 else { data.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED, 16); }
5706 break;
5707 case MOVE_SWIM:
5708 if(forced) { data.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE, 16); }
5709 else { data.Initialize(MSG_MOVE_SET_SWIM_SPEED, 16); }
5710 break;
5711 case MOVE_SWIMBACK:
5712 if(forced) { data.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE, 16); }
5713 else { data.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED, 16); }
5714 break;
5715 case MOVE_TURN:
5716 if(forced) { data.Initialize(SMSG_FORCE_TURN_RATE_CHANGE, 16); }
5717 else { data.Initialize(MSG_MOVE_SET_TURN_RATE, 16); }
5718 break;
5719 case MOVE_FLY:
5720 if(forced) { data.Initialize(SMSG_FORCE_FLY_SPEED_CHANGE, 16); }
5721 else { data.Initialize(SMSG_MOVE_SET_FLY_SPEED, 16); }
5722 break;
5723 case MOVE_FLYBACK:
5724 break;
5725 default:
5726 sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype);
5727 return;
5730 data.append(GetPackGUID());
5731 data << (uint32)0;
5732 if (mtype == MOVE_RUN) data << uint8(0); // new 2.1.0
5733 data << float(GetSpeed(mtype));
5734 SendMessageToSet( &data, true );
5736 if(Pet* pet = GetPet())
5737 pet->SetSpeed(mtype,m_speed_rate[mtype],forced);
5740 void Unit::SetHover(bool on)
5742 if(on)
5743 CastSpell(this,11010,true);
5744 else
5745 RemoveAurasDueToSpell(11010);
5748 void Unit::setDeathState(DeathState s)
5750 if (s != ALIVE)
5752 CombatStop(true);
5754 if(IsNonMeleeSpellCasted(false))
5755 InterruptNonMeleeSpells(false);
5758 if (s == JUST_DIED)
5760 RemoveAllAurasOnDeath();
5761 UnsummonAllTotems();
5763 if (m_deathState != ALIVE && s == ALIVE)
5765 //_ApplyAllAuraMods();
5767 m_deathState = s;
5770 /*########################################
5771 ######## ########
5772 ######## AGGRO SYSTEM ########
5773 ######## ########
5774 ########################################*/
5775 bool Unit::CanHaveThreatList() const
5777 if(GetTypeId() == TYPEID_UNIT && !((Creature*)this)->isPet() && !((Creature*)this)->isTotem() )
5778 return true;
5779 else
5780 return false;
5783 //======================================================================
5785 float Unit::ApplyTotalThreatModifier(float threat, SpellSchools school)
5787 if(!HasAuraType(SPELL_AURA_MOD_THREAT))
5788 return threat;
5790 if(school >= MAX_SPELL_SCHOOL)
5792 sLog.outError("Unit::ApplyTotalThreatModifier: Spell school with out-of-range value: %u",uint32(school));
5793 return threat;
5796 return threat * m_threatModifier[school];
5799 //======================================================================
5801 void Unit::AddThreat(Unit* pVictim, float threat, SpellSchools school, SpellEntry const *threatSpell)
5803 // Only mobs can manage threat lists
5804 if(CanHaveThreatList())
5805 m_ThreatManager.addThreat(pVictim, threat, school, threatSpell);
5808 //======================================================================
5810 void Unit::DeleteThreatList()
5812 m_ThreatManager.clearReferences();
5815 //======================================================================
5817 void Unit::TauntApply(Unit* taunter)
5819 assert(GetTypeId()== TYPEID_UNIT);
5821 if(!taunter || (taunter->GetTypeId() == TYPEID_PLAYER && ((Player*)taunter)->isGameMaster()))
5822 return;
5824 if(!CanHaveThreatList())
5825 return;
5827 Unit *target = getVictim();
5828 if(target && target == taunter)
5829 return;
5831 SetInFront(taunter);
5832 if (((Creature*)this)->AI())
5833 ((Creature*)this)->AI()->AttackStart(taunter);
5835 m_ThreatManager.tauntApply(taunter);
5838 //======================================================================
5840 void Unit::TauntFadeOut(Unit *taunter)
5842 assert(GetTypeId()== TYPEID_UNIT);
5844 if(!taunter || (taunter->GetTypeId() == TYPEID_PLAYER && ((Player*)taunter)->isGameMaster()))
5845 return;
5847 if(!CanHaveThreatList())
5848 return;
5850 Unit *target = getVictim();
5851 if(!target || target != taunter)
5852 return;
5854 if(m_ThreatManager.isThreatListEmpty())
5856 if(((Creature*)this)->AI())
5857 ((Creature*)this)->AI()->EnterEvadeMode();
5858 return;
5861 m_ThreatManager.tauntFadeOut(taunter);
5862 target = m_ThreatManager.getHostilTarget();
5864 if (target && target != taunter)
5866 SetInFront(target);
5867 if (((Creature*)this)->AI())
5868 ((Creature*)this)->AI()->AttackStart(target);
5872 //======================================================================
5874 bool Unit::SelectHostilTarget()
5876 //function provides main threat functionality
5877 //next-victim-selection algorithm and evade mode are called
5878 //threat list sorting etc.
5880 assert(GetTypeId()== TYPEID_UNIT);
5881 Unit* target = NULL;
5883 //This function only useful once AI has been initilazied
5884 if (!((Creature*)this)->AI())
5885 return false;
5887 if(!m_ThreatManager.isThreatListEmpty())
5889 if(!HasAuraType(SPELL_AURA_MOD_TAUNT))
5891 target = m_ThreatManager.getHostilTarget();
5895 if(target)
5897 SetInFront(target);
5898 ((Creature*)this)->AI()->AttackStart(target);
5899 return true;
5902 if(isInCombat() && !HasAuraType(SPELL_AURA_MOD_TAUNT) && CanFreeMove() && m_attackers.empty())
5903 ((Creature*)this)->AI()->EnterEvadeMode();
5905 return false;
5908 //======================================================================
5909 //======================================================================
5910 //======================================================================
5912 void Unit::CalculateSpellDamageAndDuration(int32* damage, int32* duration, SpellEntry const* spellProto, uint8 effect_index, int32 effBasePoints)
5914 Player* unitPlayer = (GetTypeId() == TYPEID_PLAYER) ? (Player*)this : NULL;
5916 uint8 comboPoints = unitPlayer ? unitPlayer->GetComboPoints() : 0;
5917 bool needClearCombo = false;
5919 if(damage)
5921 int32 value = 0;
5922 uint32 level = 0;
5924 level = getLevel() - spellProto->spellLevel;
5925 if (level > spellProto->maxLevel && spellProto->maxLevel > 0)
5926 level = spellProto->maxLevel;
5928 float basePointsPerLevel = spellProto->EffectRealPointsPerLevel[effect_index];
5929 float randomPointsPerLevel = spellProto->EffectDicePerLevel[effect_index];
5930 int32 basePoints = int32(effBasePoints + level * basePointsPerLevel);
5931 int32 randomPoints = int32(spellProto->EffectDieSides[effect_index] + level * randomPointsPerLevel);
5932 float comboDamage = spellProto->EffectPointsPerComboPoint[effect_index];
5934 value = basePoints + rand32(spellProto->EffectBaseDice[effect_index], randomPoints);
5935 //random damage
5936 if(int32(spellProto->EffectBaseDice[effect_index]) != randomPoints && GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
5937 value += ((Pet*)this)->GetBonusDamage(); //bonus damage only on spells without fixed basePoints?)
5939 if(comboDamage != 0 && unitPlayer && m_attacking && (m_attacking->GetGUID() == unitPlayer->GetComboTarget()))
5941 value += (int32)(comboDamage * comboPoints);
5943 // Eviscerate
5944 if( spellProto->SpellIconID == 514 && spellProto->SpellFamilyName == SPELLFAMILY_ROGUE)
5945 value += (int32)(GetTotalAttackPowerValue(BASE_ATTACK) * comboPoints * 0.03);
5947 needClearCombo = true;
5950 if (GetTypeId() == TYPEID_PLAYER)
5952 ((Player *)this)->ApplySpellMod(spellProto->Id,SPELLMOD_ALL_EFFECTS, value);
5953 switch(effect_index)
5955 case 0:
5956 ((Player*)this)->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT1, value);
5957 break;
5958 case 1:
5959 ((Player*)this)->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT2, value);
5960 break;
5961 case 2:
5962 ((Player*)this)->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT3, value);
5963 break;
5966 ((Player*)this)->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, value);
5970 *damage = value;
5973 if(duration)
5975 int32 minduration = GetDuration(spellProto);
5976 int32 maxduration = GetMaxDuration(spellProto);
5978 if( minduration != -1 && minduration != maxduration )
5980 *duration = minduration + int32((maxduration - minduration) * comboPoints / 5);
5981 needClearCombo = true;
5983 else
5984 *duration = minduration;
5987 if(unitPlayer && needClearCombo)
5988 unitPlayer->SetComboPoints(unitPlayer->GetComboTarget(), 0);
5991 void Unit::AddDiminishing(DiminishingMechanics mech, uint32 hitTime, uint32 hitCount)
5993 m_Diminishing.push_back(DiminishingReturn(mech,hitTime,hitCount));
5996 DiminishingLevels Unit::GetDiminishing(DiminishingMechanics mech)
5998 for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
6000 if(i->Mechanic != mech) continue;
6001 if(!i->hitCount) return DIMINISHING_LEVEL_1;
6002 if(!i->hitTime) return DIMINISHING_LEVEL_1;
6003 // If last spell was casted more than 15 seconds ago - reset the count.
6004 if((getMSTime() - i->hitTime) > 15000)
6006 i->hitCount = DIMINISHING_LEVEL_1;
6007 return DIMINISHING_LEVEL_1;
6009 // or else increase the count.
6010 else
6012 if(i->hitCount > DIMINISHING_LEVEL_2)
6014 i->hitCount = DIMINISHING_LEVEL_IMMUNE;
6015 return DIMINISHING_LEVEL_IMMUNE;
6017 else return DiminishingLevels(i->hitCount);
6020 return DIMINISHING_LEVEL_1;
6023 void Unit::IncrDiminishing(DiminishingMechanics mech, uint32 duration)
6025 // Checking for existing in the table
6026 bool IsExist = false;
6027 for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
6029 if(i->Mechanic != mech)
6030 continue;
6032 IsExist = true;
6033 if(i->hitCount < DIMINISHING_LEVEL_IMMUNE)
6035 i->hitCount += 1;
6036 switch(i->hitCount)
6038 case DIMINISHING_LEVEL_2: i->hitTime = uint32(getMSTime() + duration); break;
6039 case DIMINISHING_LEVEL_3: i->hitTime = uint32(getMSTime() + duration*0.5); break;
6040 case DIMINISHING_LEVEL_IMMUNE: i->hitTime = uint32(getMSTime() + duration*0.25); break;
6041 default: break;
6044 break;
6047 if(!IsExist)
6048 AddDiminishing(mech,uint32(getMSTime() + duration),DIMINISHING_LEVEL_2);
6051 void Unit::UpdateDiminishingTime(DiminishingMechanics mech)
6053 // Checking for existing in the table
6054 bool IsExist = false;
6055 for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
6057 if(i->Mechanic != mech)
6058 continue;
6060 IsExist = true;
6061 i->hitTime = getMSTime();
6062 break;
6065 if(!IsExist)
6066 AddDiminishing(mech,getMSTime(),DIMINISHING_LEVEL_1);
6069 DiminishingMechanics Unit::Mechanic2DiminishingMechanics(uint32 mech)
6071 switch(mech)
6073 case MECHANIC_CHARM: case MECHANIC_FEAR: case MECHANIC_SLEEP:
6074 return DIMINISHING_MECHANIC_CHARM;
6075 case MECHANIC_CONFUSED: case MECHANIC_KNOCKOUT: case MECHANIC_POLYMORPH:
6076 return DIMINISHING_MECHANIC_CONFUSE;
6077 case MECHANIC_ROOT: case MECHANIC_FREEZE:
6078 return DIMINISHING_MECHANIC_ROOT;
6079 case MECHANIC_STUNDED:
6080 return DIMINISHING_MECHANIC_STUN;
6081 case MECHANIC_CHASE:
6082 return DIMINISHING_MECHANIC_SPEED;
6083 default:
6084 break;
6086 return DIMINISHING_NONE;
6089 float Unit::ApplyDiminishingToDuration(DiminishingMechanics mech, int32 duration,Unit* caster)
6091 if(duration == -1 || mech == DIMINISHING_NONE)
6092 return 1.0f;
6094 // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
6095 if(duration > 10000)
6097 // test pet/charm masters instead pets/charmeds
6098 Unit const* targetOwner = GetCharmerOrOwner();
6099 Unit const* casterOwner = caster->GetCharmerOrOwner();
6101 Unit const* target = targetOwner ? targetOwner : this;
6102 Unit const* source = casterOwner ? casterOwner : caster;
6104 if(target->GetTypeId() == TYPEID_PLAYER && source->GetTypeId() == TYPEID_PLAYER)
6105 duration = 10000;
6108 float mod = 1.0f;
6110 // Stun diminishing is applies to mobs too
6111 if(mech == DIMINISHING_MECHANIC_STUN || GetTypeId() == TYPEID_PLAYER)
6113 DiminishingLevels diminish = GetDiminishing(mech);
6114 switch(diminish)
6116 case DIMINISHING_LEVEL_1: IncrDiminishing(mech, duration); break;
6117 case DIMINISHING_LEVEL_2: IncrDiminishing(mech, duration); mod = 0.5f; break;
6118 case DIMINISHING_LEVEL_3: IncrDiminishing(mech, duration); mod = 0.25f; break;
6119 case DIMINISHING_LEVEL_IMMUNE: mod = 0.0f; break;
6120 default: break;
6124 return mod;
6127 Creature* Unit::SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime)
6129 TemporarySummon* pCreature = new TemporarySummon(this,this);
6131 pCreature->SetInstanceId(GetInstanceId());
6133 if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), GetMapId(), x, y, z, ang, id))
6135 delete pCreature;
6136 return NULL;
6139 pCreature->Summon(spwtype, despwtime);
6141 //return the creature therewith the summoner has access to it
6142 return pCreature;
6145 Unit* Unit::GetUnit(WorldObject& object, uint64 guid)
6147 return ObjectAccessor::Instance().GetUnit(object,guid);
6150 bool Unit::isVisibleForInState( Player const* u, bool inVisibleList ) const
6152 return isVisibleForOrDetect(u,false,inVisibleList);
6155 uint32 Unit::GetCreatureType() const
6157 if(GetTypeId() == TYPEID_PLAYER)
6159 switch(((Player const*)this)->m_form)
6161 case FORM_CAT:
6162 case FORM_TRAVEL:
6163 case FORM_AQUA:
6164 case FORM_BEAR:
6165 case FORM_DIREBEAR:
6166 case FORM_GHOSTWOLF:
6167 case FORM_SWIFT_FLIGHT:
6168 case FORM_FLIGHT:
6169 return CREATURE_TYPE_BEAST;
6170 case FORM_TREE:
6171 case FORM_SPIRITOFREDEMPTION:
6172 return CREATURE_TYPE_ELEMENTAL;
6173 case FORM_MOONKIN:
6174 default:
6175 return CREATURE_TYPE_HUMANOID;
6178 else
6179 return ((Creature*)this)->GetCreatureInfo()->type;
6182 /*#######################################
6183 ######## ########
6184 ######## STAT SYSTEM ########
6185 ######## ########
6186 #######################################*/
6188 bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, float amount, bool apply)
6190 if(unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END)
6192 sLog.outError("ERROR in HandleStatModifier(): nonexisted UnitMods or wrong UnitModifierType!");
6193 return false;
6196 float val = 1.0f;
6198 switch(modifierType)
6200 case BASE_VALUE:
6201 case TOTAL_VALUE:
6202 m_auraModifiersGroup[unitMod][modifierType] += apply ? amount : -amount;
6203 break;
6204 case BASE_PCT:
6205 case TOTAL_PCT:
6206 if(amount <= -100.0f) //small hack-fix for -100% modifiers
6207 amount = -200.0f;
6209 val = (100.0f + amount) / 100.0f;
6210 m_auraModifiersGroup[unitMod][modifierType] *= apply ? val : (1.0f/val);
6211 break;
6213 default:
6214 break;
6217 if(!CanModifyStats())
6218 return false;
6220 switch(unitMod)
6222 case UNIT_MOD_STAT_STRENGTH:
6223 case UNIT_MOD_STAT_AGILITY:
6224 case UNIT_MOD_STAT_STAMINA:
6225 case UNIT_MOD_STAT_INTELLECT:
6226 case UNIT_MOD_STAT_SPIRIT: UpdateStats(GetStatByAuraGroup(unitMod)); break;
6228 case UNIT_MOD_ARMOR: UpdateArmor(); break;
6229 case UNIT_MOD_HEALTH: UpdateMaxHealth(); break;
6231 case UNIT_MOD_MANA:
6232 case UNIT_MOD_RAGE:
6233 case UNIT_MOD_FOCUS:
6234 case UNIT_MOD_ENERGY:
6235 case UNIT_MOD_HAPPINESS: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod)); break;
6237 case UNIT_MOD_RESISTANCE_HOLY:
6238 case UNIT_MOD_RESISTANCE_FIRE:
6239 case UNIT_MOD_RESISTANCE_NATURE:
6240 case UNIT_MOD_RESISTANCE_FROST:
6241 case UNIT_MOD_RESISTANCE_SHADOW:
6242 case UNIT_MOD_RESISTANCE_ARCANE: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod)); break;
6244 case UNIT_MOD_ATTACK_POWER: UpdateAttackPowerAndDamage(); break;
6245 case UNIT_MOD_ATTACK_POWER_RANGED: UpdateAttackPowerAndDamage(true); break;
6247 case UNIT_MOD_DAMAGE_MAINHAND: UpdateDamagePhysical(BASE_ATTACK); break;
6248 case UNIT_MOD_DAMAGE_OFFHAND: UpdateDamagePhysical(OFF_ATTACK); break;
6249 case UNIT_MOD_DAMAGE_RANGED: UpdateDamagePhysical(RANGED_ATTACK); break;
6251 default:
6252 break;
6255 return true;
6258 float Unit::GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) const
6260 if( unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END)
6262 sLog.outError("ERROR: trial to access nonexisted modifier value from UnitMods!");
6263 return 0.0f;
6266 if(modifierType == TOTAL_PCT && m_auraModifiersGroup[unitMod][modifierType] <= 0.0f)
6267 return 0.0f;
6269 return m_auraModifiersGroup[unitMod][modifierType];
6272 float Unit::GetTotalStatValue(Stats stat) const
6274 UnitMods unitMod = UnitMods(UNIT_MOD_STAT_START + stat);
6276 if(m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f)
6277 return 0.0f;
6279 // value = ((base_value * base_pct) + total_value) * total_pct
6280 float value = m_auraModifiersGroup[unitMod][BASE_VALUE] + GetCreateStat(stat);
6281 value *= m_auraModifiersGroup[unitMod][BASE_PCT];
6282 value += m_auraModifiersGroup[unitMod][TOTAL_VALUE];
6283 value *= m_auraModifiersGroup[unitMod][TOTAL_PCT];
6285 return value;
6288 float Unit::GetTotalAuraModValue(UnitMods unitMod) const
6290 if(unitMod >= UNIT_MOD_END)
6292 sLog.outError("ERROR: trial to access nonexisted UnitMods in GetTotalAuraModValue()!");
6293 return 0.0f;
6296 if(m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f)
6297 return 0.0f;
6299 float value = m_auraModifiersGroup[unitMod][BASE_VALUE];
6300 value *= m_auraModifiersGroup[unitMod][BASE_PCT];
6301 value += m_auraModifiersGroup[unitMod][TOTAL_VALUE];
6302 value *= m_auraModifiersGroup[unitMod][TOTAL_PCT];
6304 return value;
6307 SpellSchools Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod) const
6309 SpellSchools school = SPELL_SCHOOL_NORMAL;
6311 switch(unitMod)
6313 case UNIT_MOD_RESISTANCE_HOLY: school = SPELL_SCHOOL_HOLY; break;
6314 case UNIT_MOD_RESISTANCE_FIRE: school = SPELL_SCHOOL_FIRE; break;
6315 case UNIT_MOD_RESISTANCE_NATURE: school = SPELL_SCHOOL_NATURE; break;
6316 case UNIT_MOD_RESISTANCE_FROST: school = SPELL_SCHOOL_FROST; break;
6317 case UNIT_MOD_RESISTANCE_SHADOW: school = SPELL_SCHOOL_SHADOW; break;
6318 case UNIT_MOD_RESISTANCE_ARCANE: school = SPELL_SCHOOL_ARCANE; break;
6320 default:
6321 break;
6324 return school;
6327 Stats Unit::GetStatByAuraGroup(UnitMods unitMod) const
6329 Stats stat = STAT_STRENGTH;
6331 switch(unitMod)
6333 case UNIT_MOD_STAT_STRENGTH: stat = STAT_STRENGTH; break;
6334 case UNIT_MOD_STAT_AGILITY: stat = STAT_AGILITY; break;
6335 case UNIT_MOD_STAT_STAMINA: stat = STAT_STAMINA; break;
6336 case UNIT_MOD_STAT_INTELLECT: stat = STAT_INTELLECT; break;
6337 case UNIT_MOD_STAT_SPIRIT: stat = STAT_SPIRIT; break;
6339 default:
6340 break;
6343 return stat;
6346 Powers Unit::GetPowerTypeByAuraGroup(UnitMods unitMod) const
6348 Powers power = POWER_MANA;
6350 switch(unitMod)
6352 case UNIT_MOD_MANA: power = POWER_MANA; break;
6353 case UNIT_MOD_RAGE: power = POWER_RAGE; break;
6354 case UNIT_MOD_FOCUS: power = POWER_FOCUS; break;
6355 case UNIT_MOD_ENERGY: power = POWER_ENERGY; break;
6356 case UNIT_MOD_HAPPINESS: power = POWER_HAPPINESS; break;
6358 default:
6359 break;
6362 return power;
6365 float Unit::GetTotalAttackPowerValue(WeaponAttackType attType) const
6367 UnitMods unitMod = (attType == RANGED_ATTACK) ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER;
6369 float val = GetTotalAuraModValue(unitMod);
6370 if(val < 0.0f)
6371 val = 0.0f;
6373 return val;
6376 float Unit::GetWeaponDamageRange(WeaponAttackType attType ,WeaponDamageRange type) const
6378 if (attType == OFF_ATTACK && !haveOffhandWeapon())
6379 return 0.0f;
6381 return m_weaponDamage[attType][type];
6384 void Unit::SetLevel(uint32 lvl)
6386 SetUInt32Value(UNIT_FIELD_LEVEL,lvl);
6388 // group update
6389 if (GetTypeId() == TYPEID_PLAYER)
6390 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL);
6393 void Unit::SetHealth(uint32 val)
6395 uint32 maxHealth = GetMaxHealth();
6396 if(maxHealth < val)
6397 val = maxHealth;
6399 SetUInt32Value(UNIT_FIELD_HEALTH,val);
6401 // group update
6402 if (GetTypeId() == TYPEID_PLAYER)
6403 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP);
6406 void Unit::SetMaxHealth(uint32 val)
6408 uint32 health = GetHealth();
6409 SetUInt32Value(UNIT_FIELD_MAXHEALTH,val);
6411 // group update
6412 if (GetTypeId() == TYPEID_PLAYER)
6413 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP);
6415 if(val < health)
6416 SetHealth(val);
6419 void Unit::SetPower(Powers power, uint32 val)
6421 uint32 maxPower = GetMaxPower(power);
6422 if(maxPower < val)
6423 val = maxPower;
6425 SetStatInt32Value(UNIT_FIELD_POWER1 + power,val);
6427 // group update
6428 if (GetTypeId() == TYPEID_PLAYER)
6429 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER);
6432 void Unit::SetMaxPower(Powers power, uint32 val)
6434 uint32 cur_power = GetPower(power);
6435 SetStatInt32Value(UNIT_FIELD_MAXPOWER1 + power,val);
6437 // group update
6438 if (GetTypeId() == TYPEID_PLAYER)
6439 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER);
6441 if(val < cur_power)
6442 SetPower(power, val);
6445 void Unit::ApplyPowerMod(Powers power, uint32 val, bool apply)
6447 ApplyModUInt32Value(UNIT_FIELD_POWER1+power, val, apply);
6449 // group update
6450 if (GetTypeId() == TYPEID_PLAYER)
6451 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER);
6454 void Unit::ApplyMaxPowerMod(Powers power, uint32 val, bool apply)
6456 ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1+power, val, apply);
6458 // group update
6459 if (GetTypeId() == TYPEID_PLAYER)
6460 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER);
6463 void Unit::ApplyAuraProcTriggerDamage( Aura* aura, bool apply )
6465 AuraList& tAuraProcTriggerDamage = m_modAuras[SPELL_AURA_PROC_TRIGGER_DAMAGE];
6466 if(apply)
6467 tAuraProcTriggerDamage.push_back(aura);
6468 else
6469 tAuraProcTriggerDamage.remove(aura);
6472 uint32 Unit::GetCreatePowers( Powers power ) const
6474 // POWER_FOCUS and POWER_HAPPINESS only have hunter pet
6475 switch(power)
6477 case POWER_MANA: return GetCreateMana();
6478 case POWER_RAGE: return 1000;
6479 case POWER_FOCUS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 100);
6480 case POWER_ENERGY: return 100;
6481 case POWER_HAPPINESS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 1050000);
6484 return 0;
6487 void Unit::CleanupsBeforeDelete()
6489 if(m_uint32Values) // only for fully created object
6491 m_Events.KillAllEvents();
6492 CombatStop(true);
6493 DeleteThreatList();
6494 getHostilRefManager().setOnlineOfflineState(false);
6495 RemoveAllAuras();
6496 RemoveFromWorld();
6500 CharmInfo* Unit::InitCharmInfo(Unit *charm)
6502 if(!m_charmInfo)
6503 m_charmInfo = new CharmInfo(charm);
6504 return m_charmInfo;
6507 CharmInfo::CharmInfo(Unit* unit)
6508 : m_unit(unit), m_CommandState(COMMAND_STAY), m_ReactSate(REACT_PASSIVE), m_petnumber(0)
6510 for(int i =0; i<4; ++i)
6512 m_charmspells[i].spellId = 0;
6513 m_charmspells[i].active = ACT_DISABLED;
6517 void CharmInfo::InitPetActionBar()
6519 // the first 3 SpellOrActions are attack, follow and stay
6520 for(uint32 i = 0; i < 3; i++)
6522 PetActionBar[i].Type = ACT_COMMAND;
6523 PetActionBar[i].SpellOrAction = COMMAND_ATTACK - i;
6525 PetActionBar[i + 7].Type = ACT_REACTION;
6526 PetActionBar[i + 7].SpellOrAction = COMMAND_ATTACK - i;
6528 for(uint32 i=0; i < 4; i++)
6530 PetActionBar[i + 3].Type = ACT_DISABLED;
6531 PetActionBar[i + 3].SpellOrAction = 0;
6535 void CharmInfo::InitEmptyActionBar()
6537 for(uint32 x = 1; x < 10; ++x)
6539 PetActionBar[x].Type = ACT_CAST;
6540 PetActionBar[x].SpellOrAction = 0;
6542 PetActionBar[0].Type = ACT_COMMAND;
6543 PetActionBar[0].SpellOrAction = COMMAND_ATTACK;
6546 void CharmInfo::InitPossessCreateSpells()
6548 if(m_unit->GetTypeId() == TYPEID_PLAYER)
6549 return;
6551 InitEmptyActionBar(); //charm action bar
6553 for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x)
6555 if (IsPassiveSpell(((Creature*)m_unit)->m_spells[x]))
6556 m_unit->CastSpell(m_unit, ((Creature*)m_unit)->m_spells[x], true);
6557 else
6558 AddSpellToAB(0, ((Creature*)m_unit)->m_spells[x], ACT_CAST);
6562 void CharmInfo::InitCharmCreateSpells()
6564 if(m_unit->GetTypeId() == TYPEID_PLAYER) //charmed players don't have spells
6566 InitEmptyActionBar();
6567 return;
6570 InitPetActionBar();
6572 for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x)
6574 uint32 spellId = ((Creature*)m_unit)->m_spells[x];
6575 m_charmspells[x].spellId = spellId;
6577 if(!spellId)
6578 continue;
6580 if (IsPassiveSpell(spellId))
6582 m_unit->CastSpell(m_unit, spellId, true);
6583 m_charmspells[x].active = ACT_PASSIVE;
6585 else
6587 ActiveStates newstate;
6588 bool onlyselfcast = true;
6589 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
6591 if(!spellInfo) onlyselfcast = false;
6592 for(uint32 i = 0;i<3 && onlyselfcast;++i) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
6594 if(spellInfo->EffectImplicitTargetA[i] != TARGET_SELF && spellInfo->EffectImplicitTargetA[i] != 0)
6595 onlyselfcast = false;
6598 if(onlyselfcast || !IsPositiveSpell(spellId)) //only self cast and spells versus enemies are autocastable
6599 newstate = ACT_DISABLED;
6600 else
6601 newstate = ACT_CAST;
6603 AddSpellToAB(0, spellId, newstate);
6608 bool CharmInfo::AddSpellToAB(uint32 oldid, uint32 newid, ActiveStates newstate)
6610 for(uint8 i = 0; i < 10; i++)
6612 if((PetActionBar[i].Type == ACT_DISABLED || PetActionBar[i].Type == ACT_ENABLED || PetActionBar[i].Type == ACT_CAST) && PetActionBar[i].SpellOrAction == oldid)
6614 PetActionBar[i].SpellOrAction = newid;
6615 if(!oldid)
6617 if(newstate == ACT_DECIDE)
6618 PetActionBar[i].Type = ACT_DISABLED;
6619 else
6620 PetActionBar[i].Type = newstate;
6623 return true;
6626 return false;
6629 void CharmInfo::ToggleCreatureAutocast(uint32 spellid, bool apply)
6631 if(IsPassiveSpell(spellid))
6632 return;
6634 for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x)
6636 if(spellid == m_charmspells[x].spellId)
6638 m_charmspells[x].active = apply ? ACT_ENABLED : ACT_DISABLED;
6643 void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow)
6645 m_petnumber = petnumber;
6646 if(statwindow)
6647 m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, m_petnumber);
6648 else
6649 m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, 0);
6652 bool Unit::isFrozen() const
6654 AuraList const& mRoot = GetAurasByType(SPELL_AURA_MOD_ROOT);
6655 for(AuraList::const_iterator i = mRoot.begin(); i != mRoot.end(); ++i)
6656 if( (*i)->GetSpellProto()->School == SPELL_SCHOOL_FROST)
6657 return true;
6658 return false;
6661 struct ProcTriggeredData
6663 ProcTriggeredData(SpellEntry const * _spellInfo, uint32 _spellParam, Aura* _triggeredByAura)
6664 : spellInfo(_spellInfo), spellParam(_spellParam), triggeredByAura(_triggeredByAura),
6665 triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura->GetId(),triggeredByAura->GetEffIndex()))
6668 SpellEntry const * spellInfo;
6669 uint32 spellParam;
6670 Aura* triggeredByAura;
6671 Unit::spellEffectPair triggeredByAura_SpellPair;
6674 typedef std::list< ProcTriggeredData > ProcTriggeredList;
6676 void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, AuraTypeSet const& procAuraTypes, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage )
6678 for(AuraTypeSet::const_iterator aur = procAuraTypes.begin(); aur != procAuraTypes.end(); ++aur)
6680 // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
6681 ProcTriggeredList procTriggered;
6683 AuraList const& auras = GetAurasByType(*aur);
6684 for(AuraList::const_iterator i = auras.begin(), next; i != auras.end(); i = next)
6686 next = i; next++;
6688 SpellEntry const *spellProto = (*i)->GetSpellProto();
6689 if(!spellProto)
6690 continue;
6692 SpellProcEventEntry const *spellProcEvent = objmgr.GetSpellProcEvent(spellProto->Id);
6693 if(!spellProcEvent)
6695 // used to prevent spam in log about same non-handled spells
6696 static Unit::AuraTypeSet nonHandledSpellProcSet;
6698 if(spellProto->procFlags != 0 && nonHandledSpellProcSet.find(spellProto->Id)==nonHandledSpellProcSet.end())
6700 sLog.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto->Id,(isVictim?"a victim's":"an attacker's"));
6701 nonHandledSpellProcSet.insert(spellProto->Id);
6704 // spell.dbc use totally different flags, that only can create problems if used.
6705 continue;
6708 // Check spellProcEvent data requirements
6709 if(!ObjectMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent, procSpell,procFlag))
6710 continue;
6712 // Check if current equipment allows aura to proc
6713 if(!isVictim && GetTypeId() == TYPEID_PLAYER && ((Player*)this)->IsUseEquipedWeapon())
6715 if(spellProto->EquippedItemClass == ITEM_CLASS_WEAPON)
6717 Item *item = NULL;
6718 if(attType == BASE_ATTACK)
6719 item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
6720 else if (attType == OFF_ATTACK)
6721 item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
6722 else
6723 item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
6725 if(!item || item->IsBroken() || item->GetProto()->Class != ITEM_CLASS_WEAPON || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
6726 continue;
6728 else if(spellProto->EquippedItemClass == ITEM_CLASS_ARMOR)
6730 // Check if player is wearing shield
6731 Item *item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
6732 if(!item || item->IsBroken() || item->GetProto()->Class != ITEM_CLASS_ARMOR || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
6733 continue;
6737 // Need to use floats here, cuz calculated PPM chance often is about 1-2%
6738 float chance = (float)spellProto->procChance;
6739 if(GetTypeId() == TYPEID_PLAYER)
6740 ((Player*)this)->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance);
6742 if(!isVictim && spellProcEvent->ppmRate != 0)
6744 uint32 WeaponSpeed = GetAttackTime(attType);
6745 chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate);
6748 if(roll_chance_f(chance))
6750 if((*i)->m_procCharges > 0)
6751 (*i)->m_procCharges -= 1;
6753 uint32 i_spell_eff = (*i)->GetEffIndex();
6755 int32 i_spell_param;
6756 switch(*aur)
6758 case SPELL_AURA_PROC_TRIGGER_SPELL: i_spell_param = procFlag; break;
6759 case SPELL_AURA_DUMMY: i_spell_param = i_spell_eff; break;
6760 default: i_spell_param = (*i)->GetModifier()->m_amount; break;
6763 procTriggered.push_back( ProcTriggeredData(spellProto,i_spell_param,*i) );
6767 // Handle effects proceed this time
6768 for(ProcTriggeredList::iterator i = procTriggered.begin(); i != procTriggered.end(); ++i)
6770 // Some auras can be deleted in function called in this loop (except first, ofc)
6771 // Until storing auars in std::multimap to hard check deleting by another way
6772 if(i != procTriggered.begin())
6774 bool found = false;
6775 AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair);
6776 AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair);
6777 for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr)
6779 if(itr->second==i->triggeredByAura)
6781 found = true;
6782 break;
6786 if(!found)
6788 sLog.outError("Spell aura %u (id:%u effect:%u) has been deleted before call spell proc event handler",*aur,i->triggeredByAura_SpellPair.first,i->triggeredByAura_SpellPair.second);
6789 sLog.outError("It can be deleted one from early proccesed auras:");
6790 for(ProcTriggeredList::iterator i2 = procTriggered.begin(); i != i2; ++i2)
6791 sLog.outError(" Spell aura %u (id:%u effect:%u)",*aur,i2->triggeredByAura_SpellPair.first,i2->triggeredByAura_SpellPair.second);
6792 sLog.outError(" <end of list>");
6793 continue;
6797 if(*aur == SPELL_AURA_PROC_TRIGGER_SPELL)
6799 sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId());
6800 HandleProcTriggerSpell(pTarget, damage, i->triggeredByAura, procSpell,i->spellParam);
6802 else if(*aur == SPELL_AURA_PROC_TRIGGER_DAMAGE)
6804 sLog.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", i->spellParam, i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId());
6805 uint32 damage = i->spellParam;
6806 // TODO: remove hack for Seal of Righteousness. That should not be there
6807 if(!isVictim && i->spellInfo->SpellVisual == 7986)
6808 damage = (damage * GetAttackTime(BASE_ATTACK))/60/1000;
6809 SpellNonMeleeDamageLog(pTarget, i->spellInfo->Id, damage, true, true);
6811 else if(*aur == SPELL_AURA_DUMMY)
6813 sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId());
6814 HandleDummyAuraProc(pTarget, i->spellInfo, i->spellParam, damage, i->triggeredByAura, procSpell, procFlag);
6818 // Safely remove auras with zero charges
6819 for(AuraList::const_iterator i = auras.begin(), next; i != auras.end(); i = next)
6821 next = i; ++next;
6822 if((*i)->m_procCharges == 0)
6824 RemoveAurasDueToSpell((*i)->GetId());
6825 next = auras.begin();