[2921] Applied MaNGOS coding style (see trunk/bcpp.cfg).
[mangos-git.git] / src / game / Unit.cpp
blob8df2c9e489fec656d4347a1c73a0fec30ecaa062
1 /*
2 * Copyright (C) 2005,2006 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 "FactionTemplateResolver.h"
42 #include <math.h>
44 float baseMoveSpeed[MAX_MOVE_TYPE] =
46 2.5f, // MOVE_WALK
47 7.0f, // MOVE_RUN
48 1.25f, // MOVE_WALKBACK
49 4.722222f, // MOVE_SWIM
50 4.5f, // MOVE_SWIMBACK
51 3.141594f // MOVE_TURN
54 Unit::Unit() : Object()
56 m_objectType |= TYPE_UNIT;
57 m_objectTypeId = TYPEID_UNIT;
59 m_attackTimer[BASE_ATTACK] = 0;
60 m_attackTimer[OFF_ATTACK] = 0;
61 m_attackTimer[RANGED_ATTACK] = 0;
63 m_state = 0;
64 m_form = 0;
65 m_deathState = ALIVE;
66 m_currentSpell = NULL;
67 m_oldSpell = NULL;
68 m_currentMeleeSpell = NULL;
69 m_addDmgOnce = 0;
70 m_TotemSlot[0] = m_TotemSlot[1] = m_TotemSlot[2] = m_TotemSlot[3] = 0;
71 //m_Aura = NULL;
72 //m_AurasCheck = 2000;
73 //m_removeAuraTimer = 4;
74 //tmpAura = NULL;
75 m_silenced = false;
76 waterbreath = false;
78 m_Visibility = VISIBILITY_ON;
79 m_UpdateVisibility = VISIBLE_NOCHANGES;
81 m_detectStealth = 0;
82 m_stealthvalue = 0;
83 m_transform = 0;
84 m_ShapeShiftForm = 0;
86 for (int i = 0; i < TOTAL_AURAS; i++)
87 m_AuraModifiers[i] = -1;
88 for (int i = 0; i < IMMUNITY_MECHANIC; i++)
89 m_spellImmune[i].clear();
91 m_attacking = NULL;
92 m_modDamagePCT = 0;
93 m_modHitChance = 0;
94 m_modSpellHitChance = 0;
95 m_baseSpellCritChance = 5;
96 m_modCastSpeedPct = 0;
97 m_CombatTimer = 0;
99 for (int i = 0; i < MAX_MOVE_TYPE; ++i)
100 m_speed_rate[i] = 1.0f;
103 Unit::~Unit()
105 // remove references to unit
106 std::list<GameObject*>::iterator i;
107 for (i = m_gameObj.begin(); i != m_gameObj.end();)
109 (*i)->SetOwnerGUID(0);
110 (*i)->Delete();
111 i = m_gameObj.erase(i);
115 void Unit::Update( uint32 p_time )
117 /*if(p_time > m_AurasCheck)
119 m_AurasCheck = 2000;
120 _UpdateAura();
121 }else
122 m_AurasCheck -= p_time;*/
124 _UpdateSpells( p_time );
125 _UpdateHostil( p_time );
127 if (isInCombat() && GetTypeId() == TYPEID_PLAYER ) //update combat timer only for players
129 if ( m_CombatTimer <= p_time )
131 ClearInCombat();
133 else
134 m_CombatTimer -= p_time;
137 if(uint32 base_att = getAttackTimer(BASE_ATTACK))
139 setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time) );
141 if(GetHealth() < GetMaxHealth()*0.2)
142 SetFlag(UNIT_FIELD_AURASTATE, uint32(1<<1));
143 else RemoveFlag(UNIT_FIELD_AURASTATE, uint32(1<<1));
146 bool Unit::haveOffhandWeapon() const
148 if(GetTypeId() == TYPEID_PLAYER)
150 Item *tmpitem = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
152 return tmpitem && !tmpitem->IsBroken() && (tmpitem->GetProto()->InventoryType == INVTYPE_WEAPON || tmpitem->GetProto()->InventoryType == INVTYPE_WEAPONOFFHAND);
154 else
155 return false;
158 void Unit::SendMoveToPacket(float x, float y, float z, bool run, uint32 transitTime)
160 float dx = x - GetPositionX();
161 float dy = y - GetPositionY();
162 float dz = z - GetPositionZ();
163 if (!transitTime)
165 float dist = ((dx*dx) + (dy*dy) + (dz*dz));
166 if(dist<0)
167 dist = 0;
168 else
169 dist = ::sqrt(dist);
170 double speed = GetSpeed(run ? MOVE_RUN : MOVE_WALK);
171 if(speed<=0)
172 speed = 2.5f;
173 speed *= 0.001f;
174 transitTime = static_cast<uint32>(dist / speed + 0.5);
176 //float orientation = (float)atan2((double)dy, (double)dx);
177 SendMonsterMove(x,y,z,false,run,transitTime);
180 void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, bool Walkback, bool Run, uint32 Time)
182 WorldPacket data( SMSG_MONSTER_MOVE, (41+GetPackGUID().size()) );
183 data.append(GetPackGUID());
184 // Point A, starting location
185 data << GetPositionX() << GetPositionY() << GetPositionZ();
186 // unknown field - unrelated to orientation
187 // seems to increment about 1000 for every 1.7 seconds
188 // for now, we'll just use mstime
189 data << getMSTime();
191 data << uint8(Walkback); // walkback when walking from A to B
192 data << uint32(Run ? 0x00000100 : 0x00000000); // flags
193 /* Flags:
194 512: Floating, moving without walking/running
196 data << Time; // Time in between points
197 data << uint32(1); // 1 single waypoint
198 data << NewPosX << NewPosY << NewPosZ; // the single waypoint Point B
199 SendMessageToSet( &data, true );
202 void Unit::resetAttackTimer(WeaponAttackType type)
204 if (GetTypeId() == TYPEID_PLAYER)
205 m_attackTimer[type] = GetAttackTime(type);
206 else
207 m_attackTimer[type] = 2000;
210 bool Unit::canReachWithAttack(Unit *pVictim) const
212 assert(pVictim);
213 float reach = GetFloatValue(UNIT_FIELD_COMBATREACH);
214 if( reach <= 0.0f )
215 reach = 1.0f;
216 return IsWithinDist(pVictim, reach);
219 void Unit::RemoveSpellsCausingAura(uint32 auraType)
221 if (auraType >= TOTAL_AURAS) return;
222 AuraList::iterator iter, next;
223 for (iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end(); iter = next)
225 next = iter;
226 ++next;
228 if (*iter)
230 RemoveAurasDueToSpell((*iter)->GetId());
231 if (!m_modAuras[auraType].empty())
232 next = m_modAuras[auraType].begin();
233 else
234 return;
239 bool Unit::HasAuraType(uint32 auraType) const
241 return (!m_modAuras[auraType].empty());
244 void Unit::DealDamage(Unit *pVictim, uint32 damage, DamageEffectType damagetype, uint32 procFlag, bool durabilityLoss)
246 if (!pVictim->isAlive() || pVictim->isInFlight()) return;
248 if(!damage) return;
250 if(HasStealthAura())
251 RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
252 if(HasInvisibilityAura())
253 RemoveSpellsCausingAura(SPELL_AURA_MOD_INVISIBILITY);
255 if(pVictim->GetTypeId() != TYPEID_PLAYER)
257 //pVictim->SetInFront(this);
258 // no loot,xp,health if type 8 /critters/
259 if ( ((Creature*)pVictim)->GetCreatureInfo()->type == 8)
261 pVictim->setDeathState(JUST_DIED);
262 pVictim->SetHealth(0);
263 pVictim->CombatStop();
264 return;
266 ((Creature*)pVictim)->AI().AttackStart(this);
269 DEBUG_LOG("DealDamageStart");
271 uint32 health = pVictim->GetHealth();
272 sLog.outDetail("deal dmg:%d to heals:%d ",damage,health);
274 // duel ends when player has 1 or less hp
275 bool duel_hasEnded = false;
276 if(pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->duel && damage >= (health-1))
278 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
279 if(((Player*)pVictim)->duel->opponent==this || ((Player*)pVictim)->duel->opponent->GetGUID() == GetOwnerGUID())
280 damage = health-1;
282 duel_hasEnded = true;
285 if (health <= damage)
287 if(pVictim->GetTypeId() == TYPEID_UNIT) //leave combat mode when killing mobs
288 ClearInCombat();
289 else
290 SetInCombat();
292 pVictim->ClearInCombat();
294 DEBUG_LOG("DealDamage: victim just died");
296 DEBUG_LOG("DealDamageAttackStop");
297 AttackStop();
298 pVictim->CombatStop();
300 DEBUG_LOG("SET JUST_DIED");
301 pVictim->setDeathState(JUST_DIED);
303 DEBUG_LOG("DealDamageHealth1");
304 pVictim->SetHealth(0);
306 // 10% durability loss on death
307 // clean hostilList
308 if (pVictim->GetTypeId() == TYPEID_PLAYER)
310 if (GetTypeId() != TYPEID_PLAYER && durabilityLoss)
312 DEBUG_LOG("We are dead, loosing 10 percents durability");
313 ((Player*)pVictim)->DurabilityLossAll(0.10);
314 // durability lost message
315 WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0);
316 ((Player*)pVictim)->GetSession()->SendPacket(&data);
318 HostilList::iterator i;
319 for(i = m_hostilList.begin(); i != m_hostilList.end(); i++)
321 if(i->UnitGuid==pVictim->GetGUID())
323 m_hostilList.erase(i);
324 break;
328 Pet *pet = pVictim->GetPet();
329 if(pet)
331 pet->setDeathState(JUST_DIED);
332 pet->CombatStop();
333 pet->SetHealth(0);
334 pet->addUnitState(UNIT_STAT_DIED);
335 for(i = m_hostilList.begin(); i != m_hostilList.end(); ++i)
337 if(i->UnitGuid==pet->GetGUID())
339 m_hostilList.erase(i);
340 break;
345 else
347 pVictim->m_hostilList.clear();
348 DEBUG_LOG("DealDamageNotPlayer");
349 if(!((Creature*)pVictim)->isPet())
350 pVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
353 //judge if GainXP, Pet kill like player kill,kill pet not like PvP
354 bool PvP = false;
355 Player *player = 0;
357 if(GetTypeId() == TYPEID_PLAYER)
359 player = (Player*)this;
360 if(pVictim->GetTypeId() == TYPEID_PLAYER)
361 PvP = true;
363 else if(GetOwnerGUID()) // Pet or timed creature, etc
365 Creature* pet = (Creature*)this;
366 Unit* owner = ((Creature*)this)->GetOwner();
368 if(owner && owner->GetTypeId() == TYPEID_PLAYER)
370 player = (Player*)owner;
371 player->ClearInCombat();
374 if(pet->isPet())
376 uint32 petxp = MaNGOS::XP::BaseGain(getLevel(), pVictim->getLevel());
377 ((Pet*)pet)->GivePetXP(petxp);
381 // self or owner of pet
382 if(player)
384 player->CalculateHonor(pVictim);
385 player->CalculateReputation(pVictim);
387 if(!PvP)
389 DEBUG_LOG("DealDamageIsPvE");
390 uint32 xp = MaNGOS::XP::Gain(player, pVictim);
392 Group *pGroup = player->groupInfo.group;
393 if(pGroup)
395 DEBUG_LOG("Kill Enemy In Group");
396 xp /= pGroup->GetMembersCount();
397 for (uint32 i = 0; i < pGroup->GetMembersCount(); i++)
399 Player *pGroupGuy = objmgr.GetPlayer(pGroup->GetMemberGUID(i));
400 if(!pGroupGuy)
401 continue;
402 if(pVictim->GetDistanceSq(pGroupGuy) > sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
403 continue;
404 if(uint32(abs((int)pGroupGuy->getLevel() - (int)pVictim->getLevel())) > sWorld.getConfig(CONFIG_GROUP_XP_LEVELDIFF))
405 continue;
406 pGroupGuy->GiveXP(xp, pVictim);
407 if(Pet* pet = player->GetPet())
409 pet->GivePetXP(xp/2);
411 pGroupGuy->KilledMonster(pVictim->GetEntry(), pVictim->GetGUID());
414 else
416 DEBUG_LOG("Player kill enemy alone");
417 player->GiveXP(xp, pVictim);
418 if(Pet* pet = player->GetPet())
420 pet->GivePetXP(xp);
422 player->KilledMonster(pVictim->GetEntry(),pVictim->GetGUID());
426 else
428 DEBUG_LOG("Monster kill Monster");
431 // last damage NOT from duel opponent or opponent controlled creature
432 if(duel_hasEnded)
434 assert(pVictim->GetTypeId()==TYPEID_PLAYER);
435 Player *he = (Player*)pVictim;
437 assert(he->duel);
439 CombatStop(); // for case killed by pet
440 if(he->duel->opponent!=this)
441 he->duel->opponent->CombatStop();
442 he->CombatStop();
444 he->DuelComplete(0);
447 else
449 DEBUG_LOG("DealDamageAlive");
450 pVictim->ModifyHealth(- (int32)damage);
451 if(damagetype != DOT)
453 Attack(pVictim);
454 if(damagetype == DIRECT_DAMAGE) //start melee attacks only after melee hit
455 SendAttackStart(pVictim);
458 //Get in CombatState
459 if(pVictim != this && damagetype != DOT)
461 SetInCombat();
462 pVictim->SetInCombat();
465 if(pVictim->getTransForm())
467 pVictim->RemoveAurasDueToSpell(pVictim->getTransForm());
468 pVictim->setTransForm(0);
471 if (pVictim->GetTypeId() != TYPEID_PLAYER)
473 ((Creature *)pVictim)->AI().DamageInflict(this, damage);
474 pVictim->AddHostil(GetGUID(), damage);
476 else
478 // rage from recieved damage (from creatures and players)
479 if( pVictim != this // not generate rage for self damage (falls, ...)
480 // warrior and some druid forms
481 && (((Player*)pVictim)->getPowerType() == POWER_RAGE))
482 ((Player*)pVictim)->CalcRage(damage,false);
484 // random durability for items (HIT)
485 int randdurability = urand(0, 300);
486 if (randdurability == 10)
488 DEBUG_LOG("HIT: We decrease durability with 5 percent");
489 ((Player*)pVictim)->DurabilityLossAll(0.05);
493 // TODO: Store auras by interrupt flag to speed this up.
494 // TODO: Fix roots that should not break from its own damage.
495 AuraMap& vAuras = pVictim->GetAuras();
496 for (AuraMap::iterator i = vAuras.begin(), next; i != vAuras.end(); i = next)
498 next = i; next++;
499 if (i->second->GetSpellProto()->AuraInterruptFlags & (1<<1))
501 bool remove = true;
502 if (i->second->GetSpellProto()->procFlags & (1<<3))
503 if (i->second->GetSpellProto()->procChance < rand_chance())
504 remove = false;
505 if (remove)
507 pVictim->RemoveAurasDueToSpell(i->second->GetId());
508 next = vAuras.begin();
513 if(pVictim->m_currentSpell && pVictim->GetTypeId() == TYPEID_PLAYER && damage
514 && pVictim->m_currentSpell->getState() == SPELL_STATE_CASTING)
516 uint32 channelInterruptFlags = pVictim->m_currentSpell->m_spellInfo->ChannelInterruptFlags;
517 if( channelInterruptFlags & CHANNEL_FLAG_DELAY )
519 sLog.outDetail("Spell %u delayed (%d) at damage!",pVictim->m_currentSpell->m_spellInfo->Id,(int32)(0.25f * GetDuration(pVictim->m_currentSpell->m_spellInfo)));
520 pVictim->m_currentSpell->DelayedChannel((int32)(0.25f * GetDuration(pVictim->m_currentSpell->m_spellInfo)));
522 else if( (channelInterruptFlags & (CHANNEL_FLAG_DAMAGE | CHANNEL_FLAG_DAMAGE2)) )
524 sLog.outDetail("Spell %u canceled at damage!",pVictim->m_currentSpell->m_spellInfo->Id);
525 pVictim->m_currentSpell->cancel();
529 // last damage from duel opponent
530 if(duel_hasEnded)
532 assert(pVictim->GetTypeId()==TYPEID_PLAYER);
533 Player *he = (Player*)pVictim;
535 assert(he->duel);
537 he->ModifyHealth(1);
538 CombatStop(); // for case killed by pet
539 if(he->duel->opponent!=this)
540 he->duel->opponent->CombatStop();
541 he->CombatStop();
543 he->CastSpell(he, 7267, false); // beg
544 he->DuelComplete(1);
548 DEBUG_LOG("DealDamageEnd");
551 void Unit::CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castItem)
553 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
555 if(!spellInfo)
557 sLog.outError("WORLD: unknown spell id %i\n", spellId);
558 return;
561 CastSpell(Victim,spellInfo,triggered,castItem);
563 /* if (castItem)
564 DEBUG_LOG("WORLD: cast Item spellId - %i", spellId);
566 Spell *spell = new Spell(this, spellInfo, triggered, 0);
567 WPAssert(spell);
569 SpellCastTargets targets;
570 targets.setUnitTarget( Victim );
571 spell->m_CastItem = castItem;
572 spell->prepare(&targets);
573 m_canMove = false;
574 if (triggered) delete spell;
578 void Unit::CastSpell(Unit* Victim,SpellEntry const *spellInfo, bool triggered, Item *castItem)
580 if(!spellInfo)
582 sLog.outError("WORLD: unknown spell ");
583 return;
586 if (castItem)
587 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
589 Spell *spell = new Spell(this, spellInfo, triggered, 0);
590 WPAssert(spell);
592 SpellCastTargets targets;
593 targets.setUnitTarget( Victim );
594 spell->m_CastItem = castItem;
595 spell->prepare(&targets);
596 m_canMove = false;
597 if (triggered) delete spell; // triggered spell not self deleted
600 void Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage)
602 if(!this || !pVictim)
603 return;
604 if(!this->isAlive() || !pVictim->isAlive())
605 return;
606 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID);
607 if(!spellInfo)
608 return;
610 uint32 absorb=0;
611 uint32 resist=0;
613 //Spell miss (sends resist message)
614 if(SpellMissChanceCalc(pVictim) > urand(0,10000))
616 SendAttackStateUpdate(HITINFO_RESIST|HITINFO_SWINGNOHITSOUND, pVictim, 1, spellInfo->School, 0, 0,0,1,0);
617 return;
620 uint32 pdamage = SpellDamageBonus(pVictim,spellInfo,damage);
621 bool crit = SpellCriticalBonus(spellInfo, (int32*)&pdamage);
623 //Calculate armor mitigation if it is a physical spell
624 if (spellInfo->School == 0)
625 pdamage = CalcArmorReducedDamage(pVictim, damage);
626 CalcAbsorbResist(pVictim,spellInfo->School,pdamage, &absorb, &resist);
628 // Only send absorbed message if we actually absorbed some damage
629 if( pdamage <= absorb+resist && absorb)
631 SendAttackStateUpdate(HITINFO_ABSORB|HITINFO_SWINGNOHITSOUND, pVictim, 1, spellInfo->School, pdamage, absorb,resist,1,0);
632 return;
633 }else // If we didn't fully absorb check if we fully resisted
634 if( pdamage <= resist)
636 SendAttackStateUpdate(HITINFO_RESIST|HITINFO_SWINGNOHITSOUND, pVictim, 1, spellInfo->School, pdamage, absorb,resist,1,0);
637 return;
640 sLog.outDetail("SpellNonMeleeDamageLog: %u %X attacked %u %X for %u dmg inflicted by %u,abs is %u,resist is %u",
641 GetGUIDLow(), GetGUIDHigh(), pVictim->GetGUIDLow(), pVictim->GetGUIDHigh(), pdamage, spellID, absorb, resist);
643 SendSpellNonMeleeDamageLog(pVictim, spellID, pdamage, spellInfo->School, absorb, resist, false, 0, crit);
644 DealDamage(pVictim, pdamage<(absorb+resist)?0:(pdamage-absorb-resist), SPELL_DIRECT_DAMAGE, 0, true);
647 void Unit::PeriodicAuraLog(Unit *pVictim, SpellEntry const *spellProto, Modifier *mod)
649 uint32 procFlag = 0;
650 if(!this || !pVictim || !isAlive() || !pVictim->isAlive())
652 return;
654 uint32 absorb=0;
655 uint32 resist=0;
657 uint32 pdamage = mod->m_amount;
659 //Calculate armor mitigation if it is a physical spell
660 if (spellProto->School == 0)
661 pdamage = CalcArmorReducedDamage(pVictim, pdamage);
663 CalcAbsorbResist(pVictim, spellProto->School, pdamage, &absorb, &resist);
665 sLog.outDetail("PeriodicAuraLog: %u %X attacked %u %X for %u dmg inflicted by %u abs is %u",
666 GetGUIDLow(), GetGUIDHigh(), pVictim->GetGUIDLow(), pVictim->GetGUIDHigh(), pdamage, spellProto->Id,absorb);
668 WorldPacket data(SMSG_PERIODICAURALOG, (21+16)); // we guess size
669 data.append(pVictim->GetPackGUID());
670 data.append(this->GetPackGUID());
671 data << spellProto->Id;
672 data << uint32(1);
674 data << mod->m_auraname;
675 data << (uint32)(mod->m_amount);
676 data << spellProto->School;
677 data << uint32(0);
678 SendMessageToSet(&data,true);
680 if(mod->m_auraname == SPELL_AURA_PERIODIC_DAMAGE)
682 pdamage = SpellDamageBonus(pVictim, spellProto, pdamage);
683 SendSpellNonMeleeDamageLog(pVictim, spellProto->Id, mod->m_amount, spellProto->School, absorb, resist, false, 0);
684 SendMessageToSet(&data,true);
685 DealDamage(pVictim, mod->m_amount <= int32(absorb+resist) ? 0 : (mod->m_amount-absorb-resist), DOT, procFlag, true);
687 else if(mod->m_auraname == SPELL_AURA_PERIODIC_DAMAGE_PERCENT)
689 pdamage = SpellDamageBonus(pVictim, spellProto, pdamage);
690 int32 pdamage = GetHealth()*(100+mod->m_amount)/100;
691 SendSpellNonMeleeDamageLog(pVictim, spellProto->Id, pdamage, spellProto->School, absorb, resist, false, 0);
692 SendMessageToSet(&data,true);
693 DealDamage(pVictim, pdamage <= int32(absorb+resist) ? 0 : (pdamage-absorb-resist), DOT, procFlag, true);
695 else if(mod->m_auraname == SPELL_AURA_PERIODIC_HEAL || mod->m_auraname == SPELL_AURA_OBS_MOD_HEALTH)
697 pdamage = SpellHealingBonus(spellProto, pdamage);
698 pVictim->ModifyHealth(pdamage);
700 if(pVictim->GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_PLAYER)
701 SendHealSpellOnPlayer(pVictim, spellProto->Id, pdamage);
703 else if(mod->m_auraname == SPELL_AURA_PERIODIC_LEECH)
705 uint32 tmpvalue = 0;
706 float tmpvalue2 = 0;
707 for(int x=0;x<3;x++)
709 if(mod->m_auraname != spellProto->EffectApplyAuraName[x])
710 continue;
711 tmpvalue2 = spellProto->EffectMultipleValue[x];
712 tmpvalue2 = tmpvalue2 > 0 ? tmpvalue2 : 1;
714 if(pVictim->GetHealth() - mod->m_amount > 0)
715 tmpvalue = uint32(mod->m_amount*tmpvalue2);
716 else
717 tmpvalue = uint32(pVictim->GetHealth()*tmpvalue2);
719 SendSpellNonMeleeDamageLog(pVictim, spellProto->Id, tmpvalue, spellProto->School, absorb, resist, false, 0);
720 DealDamage(pVictim, mod->m_amount <= int32(absorb+resist) ? 0 : (mod->m_amount-absorb-resist), DOT, procFlag, false);
721 if (!pVictim->isAlive() && m_currentSpell)
722 if (m_currentSpell->m_spellInfo)
723 if (m_currentSpell->m_spellInfo->Id == spellProto->Id)
724 m_currentSpell->cancel();
726 break;
729 ModifyHealth(tmpvalue);
731 if(pVictim->GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_PLAYER)
732 pVictim->SendHealSpellOnPlayer(this, spellProto->Id, tmpvalue);
734 else if(mod->m_auraname == SPELL_AURA_PERIODIC_MANA_LEECH)
736 if(pVictim->getPowerType() != POWER_MANA)
737 return;
738 if(getPowerType() != POWER_MANA)
739 return;
741 uint32 tmpvalue = 0;
742 for(int x=0;x<3;x++)
744 if(mod->m_auraname != spellProto->EffectApplyAuraName[x])
745 continue;
747 int32 amount;
748 if(int32(pVictim->GetPower(POWER_MANA)) > mod->m_amount)
749 amount = mod->m_amount;
750 else
751 amount = pVictim->GetPower(POWER_MANA);
753 pVictim->ModifyPower(POWER_MANA, - amount);
755 tmpvalue = uint32(amount*spellProto->EffectMultipleValue[x]);
756 break;
759 ModifyPower(POWER_MANA,tmpvalue);
761 if(pVictim->GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_PLAYER)
762 SendHealSpellOnPlayerPet(this, spellProto->Id, tmpvalue, POWER_MANA);
764 else if(mod->m_auraname == SPELL_AURA_PERIODIC_ENERGIZE)
766 if(mod->m_miscvalue < 0 || mod->m_miscvalue > 4)
767 return;
769 Powers power = Powers(mod->m_miscvalue);
771 if(getPowerType() != power)
772 return;
774 ModifyPower(power,mod->m_amount);
776 if(pVictim->GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_PLAYER)
777 SendHealSpellOnPlayerPet(pVictim, spellProto->Id, mod->m_amount, power);
779 else if(mod->m_auraname == SPELL_AURA_OBS_MOD_MANA)
781 if(getPowerType() != POWER_MANA)
782 return;
784 ModifyPower(POWER_MANA, mod->m_amount);
788 void Unit::HandleEmoteCommand(uint32 anim_id)
790 WorldPacket data( SMSG_EMOTE, 12 );
791 data << anim_id << GetGUID();
792 WPAssert(data.size() == 12);
794 SendMessageToSet(&data, true);
797 uint32 Unit::CalcArmorReducedDamage(Unit* pVictim, const uint32 damage)
799 uint32 newdamage = 0;
800 float armor = pVictim->GetArmor();
801 float tmpvalue = armor / (getLevel() * 85.0 + 400.0 +armor);
803 if(tmpvalue < 0)
804 tmpvalue = 0.0;
805 if(tmpvalue > 0.75)
806 tmpvalue = 0.75;
807 newdamage = uint32(damage - (damage * tmpvalue));
809 return (newdamage > 1) ? newdamage : 1;
812 void Unit::CalcAbsorbResist(Unit *pVictim,uint32 School, const uint32 damage, uint32 *absorb, uint32 *resist)
814 if(!pVictim || !pVictim->isAlive() || !damage)
815 return;
817 // Magic damage, check for resists
818 if (School != SPELL_SCHOOL_NORMAL)
820 float tmpvalue2 = pVictim->GetResistance(SpellSchools(School));
821 if (tmpvalue2 < 0) tmpvalue2 = 0;
822 *resist += uint32(damage*tmpvalue2*0.0025*pVictim->getLevel()/getLevel());
823 if(*resist > damage)
824 *resist = damage;
825 }else *resist = 0;
827 int32 RemainingDamage = damage - *resist;
828 int32 currentAbsorb, manaReduction, maxAbsorb;
829 float manaMultiplier;
831 if (School == SPELL_SCHOOL_NORMAL)
833 AuraList& vManaShield = pVictim->GetAurasByType(SPELL_AURA_MANA_SHIELD);
834 for(AuraList::iterator i = vManaShield.begin(), next; i != vManaShield.end() && RemainingDamage >= 0; i = next)
836 next = i; next++;
837 if (RemainingDamage - (*i)->m_absorbDmg >= 0)
838 currentAbsorb = (*i)->m_absorbDmg;
839 else
840 currentAbsorb = RemainingDamage;
842 manaMultiplier = (*i)->GetSpellProto()->EffectMultipleValue[(*i)->GetEffIndex()];
843 maxAbsorb = int32(pVictim->GetPower(POWER_MANA) / manaMultiplier);
844 if (currentAbsorb > maxAbsorb)
845 currentAbsorb = maxAbsorb;
847 (*i)->m_absorbDmg -= currentAbsorb;
848 if((*i)->m_absorbDmg <= 0)
850 pVictim->RemoveAurasDueToSpell((*i)->GetId());
851 next = vManaShield.begin();
854 manaReduction = int32(currentAbsorb * manaMultiplier);
855 pVictim->ApplyPowerMod(POWER_MANA, manaReduction, false);
857 RemainingDamage -= currentAbsorb;
861 AuraList& vSchoolAbsorb = pVictim->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB);
862 for(AuraList::iterator i = vSchoolAbsorb.begin(), next; i != vSchoolAbsorb.end() && RemainingDamage >= 0; i = next)
864 next = i; next++;
865 if ((*i)->GetModifier()->m_miscvalue & int32(1<<School))
867 if (RemainingDamage - (*i)->m_absorbDmg >= 0)
869 currentAbsorb = (*i)->m_absorbDmg;
870 pVictim->RemoveAurasDueToSpell((*i)->GetId());
871 next = vSchoolAbsorb.begin();
873 else
875 currentAbsorb = RemainingDamage;
876 (*i)->m_absorbDmg -= RemainingDamage;
879 RemainingDamage -= currentAbsorb;
883 *absorb = damage - RemainingDamage - *resist;
886 void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, uint32 *blocked_amount, uint32 *damageType, uint32 *hitInfo, uint32 *victimState, uint32 *absorbDamage, uint32 *resistDamage, WeaponAttackType attType)
888 pVictim->RemoveFlag(UNIT_FIELD_AURASTATE, uint32((1<<(AURA_STATE_PARRY-1)) | 1<<(AURA_STATE_DODGE-1)));
889 MeleeHitOutcome outcome = RollMeleeOutcomeAgainst (pVictim, attType);
890 if (outcome == MELEE_HIT_MISS)
892 *hitInfo |= HITINFO_MISS;
893 if(GetTypeId()== TYPEID_PLAYER)
894 ((Player*)this)->UpdateWeaponSkill(attType);
895 return;
898 *damage += CalculateDamage (attType);
900 //Calculate the damage after armor mitigation if SPELL_SCHOOL_NORMAL
901 if (*damageType == SPELL_SCHOOL_NORMAL)
902 *damage = CalcArmorReducedDamage(pVictim, *damage);
904 if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && ((Creature*)pVictim)->GetCreatureInfo()->type != 8 )
905 ((Player*)this)->UpdateCombatSkills(pVictim, attType, outcome, false);
906 if(GetTypeId() != TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
907 ((Player*)pVictim)->UpdateCombatSkills(this, attType, outcome, true);
909 switch (outcome)
911 case MELEE_HIT_CRIT:
912 //*hitInfo = 0xEA;
913 // 0xEA
914 *hitInfo = HITINFO_CRITICALHIT | HITINFO_NORMALSWING2 | 0x8;
915 *damage *= 2;
917 if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && ((Creature*)pVictim)->GetCreatureInfo()->type != 8 )
918 ((Player*)this)->UpdateWeaponSkill(attType);
920 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL);
921 break;
923 case MELEE_HIT_PARRY:
924 *damage = 0;
925 *victimState = VICTIMSTATE_PARRY;
927 // instant (maybe with small delay) counter attack
929 uint32 offtime = pVictim->getAttackTimer(OFF_ATTACK);
930 uint32 basetime = pVictim->getAttackTimer(BASE_ATTACK);
932 if (pVictim->haveOffhandWeapon() && offtime < basetime)
934 if( offtime > ATTACK_DISPLAY_DELAY )
935 pVictim->setAttackTimer(OFF_ATTACK,ATTACK_DISPLAY_DELAY);
937 else
939 if ( basetime > ATTACK_DISPLAY_DELAY )
940 pVictim->setAttackTimer(BASE_ATTACK,ATTACK_DISPLAY_DELAY);
944 if(pVictim->GetTypeId() == TYPEID_PLAYER)
945 ((Player*)pVictim)->UpdateDefense();
947 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
948 pVictim->SetFlag(UNIT_FIELD_AURASTATE, uint32(1<<(AURA_STATE_DODGE-1)));
949 return;
951 case MELEE_HIT_DODGE:
952 *damage = 0;
953 *victimState = VICTIMSTATE_DODGE;
955 if(pVictim->GetTypeId() == TYPEID_PLAYER)
956 ((Player*)pVictim)->UpdateDefense();
958 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
959 pVictim->SetFlag(UNIT_FIELD_AURASTATE, uint32(1<<(AURA_STATE_DODGE-1)));
960 return;
962 case MELEE_HIT_BLOCK:
963 *blocked_amount = uint32(pVictim->GetBlockValue() + (pVictim->GetStat(STAT_STRENGTH) / 20) -1);
965 if (pVictim->GetUnitBlockChance())
966 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD);
967 else
968 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
970 //Only set VICTIMSTATE_BLOCK on a full block
971 if (*blocked_amount >= *damage)
973 *victimState = VICTIMSTATE_BLOCKS;
974 *blocked_amount = *damage;
977 if(pVictim->GetTypeId() == TYPEID_PLAYER)
978 ((Player*)pVictim)->UpdateDefense();
979 pVictim->SetFlag(UNIT_FIELD_AURASTATE, uint32(1<<(AURA_STATE_DODGE-1)));
980 break;
982 case MELEE_HIT_GLANCING:
984 // 30% reduction at 15 skill diff, no reduction at 5 skill diff
985 int32 reducePerc = 100 - (pVictim->GetDefenceSkillValue() - GetWeaponSkillValue(attType) - 5) * 3;
986 if (reducePerc < 70)
987 reducePerc = 70;
988 *damage = *damage * reducePerc / 100;
989 *hitInfo |= HITINFO_GLANCING;
990 break;
992 case MELEE_HIT_CRUSHING:
993 // 150% normal damage
994 *damage += (*damage / 2);
995 *hitInfo |= HITINFO_CRUSHING;
996 // TODO: victimState, victim animation?
997 break;
999 default:
1000 break;
1003 MeleeDamageBonus(pVictim, damage);
1004 CalcAbsorbResist(pVictim, *damageType, *damage-*blocked_amount, absorbDamage, resistDamage);
1006 if (*absorbDamage) *hitInfo |= HITINFO_ABSORB;
1007 if (*resistDamage) *hitInfo |= HITINFO_RESIST;
1009 if (*damage <= *absorbDamage + *resistDamage + *blocked_amount)
1011 //*hitInfo = 0x00010020;
1012 //*hitInfo |= HITINFO_SWINGNOHITSOUND;
1013 //*damageType = 0;
1014 return;
1017 // victim's damage shield
1018 AuraList& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD);
1019 for(AuraList::iterator i = vDamageShields.begin(); i != vDamageShields.end(); ++i)
1020 pVictim->SpellNonMeleeDamageLog(this, (*i)->GetId(), (*i)->GetModifier()->m_amount);
1022 if(pVictim->m_currentSpell && pVictim->GetTypeId() == TYPEID_PLAYER && *damage)
1024 if (pVictim->m_currentSpell->getState() != SPELL_STATE_CASTING)
1026 sLog.outDetail("Spell Delayed!%d",(int32)(0.25f * pVictim->m_currentSpell->casttime));
1027 pVictim->m_currentSpell->Delayed((int32)(0.25f * pVictim->m_currentSpell->casttime));
1029 else
1031 uint32 channelInterruptFlags = pVictim->m_currentSpell->m_spellInfo->ChannelInterruptFlags;
1032 if( channelInterruptFlags & CHANNEL_FLAG_DELAY )
1034 sLog.outDetail("Spell Delayed!%d",(int32)(0.25f * GetDuration(pVictim->m_currentSpell->m_spellInfo)));
1035 pVictim->m_currentSpell->DelayedChannel((int32)(0.25f * GetDuration(pVictim->m_currentSpell->m_spellInfo)));
1036 return;
1038 else if( !(channelInterruptFlags & (CHANNEL_FLAG_DAMAGE | CHANNEL_FLAG_DAMAGE2)) )
1039 return;
1041 sLog.outDetail("Spell Canceled!");
1042 pVictim->m_currentSpell->cancel();
1047 void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType)
1049 if(hasUnitState(UNIT_STAT_CONFUSED) || hasUnitState(UNIT_STAT_STUNDED))
1050 return;
1052 if (!pVictim->isAlive())
1053 return;
1055 if(m_currentSpell)
1056 return;
1058 // melee attack spell casted at main hand attack only
1059 if (m_currentMeleeSpell && attType == BASE_ATTACK)
1061 m_currentMeleeSpell->cast();
1062 return;
1065 uint32 hitInfo;
1066 if (attType == BASE_ATTACK)
1067 hitInfo = HITINFO_NORMALSWING2;
1068 else if (attType == OFF_ATTACK)
1069 hitInfo = HITINFO_LEFTSWING;
1070 else
1071 return;
1073 uint32 damageType = NORMAL_DAMAGE;
1074 uint32 victimState = VICTIMSTATE_NORMAL;
1075 uint32 procflag = PROC_FLAG_NONE;
1077 uint32 damage = 0;
1078 uint32 blocked_dmg = 0;
1079 uint32 absorbed_dmg = 0;
1080 uint32 resisted_dmg = 0;
1082 DoAttackDamage (pVictim, &damage, &blocked_dmg, &damageType, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, attType);
1084 if(attType == RANGED_ATTACK)
1086 procflag |= PROC_FLAG_LONG_ATTACK;
1087 if(damage > 0)
1088 procflag |= PROC_FLAG_LONG_HIT;
1090 else
1092 procflag |= PROC_FLAG_SHORT_ATTACK;
1093 if(damage > 0)
1094 procflag |= PROC_FLAG_SHORT_HIT;
1097 if (hitInfo & HITINFO_MISS)
1098 //send miss
1099 SendAttackStateUpdate (hitInfo, pVictim, 1, damageType, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg);
1100 else
1102 //do animation
1103 SendAttackStateUpdate (hitInfo, pVictim, 1, damageType, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg);
1105 if (damage > (absorbed_dmg + resisted_dmg + blocked_dmg))
1106 damage -= (absorbed_dmg + resisted_dmg + blocked_dmg);
1107 else
1108 damage = 0;
1110 DealDamage (pVictim, damage, DIRECT_DAMAGE, 0, true);
1112 // rage from maked damage TO creatures and players (target dead case)
1113 if(GetTypeId() == TYPEID_PLAYER && (getPowerType() == POWER_RAGE))
1114 ((Player*)this)->CalcRage(damage,true);
1116 if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive())
1118 for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
1119 ((Player*)this)->CastItemCombatSpell(((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i),pVictim);
1123 if(!pVictim->isAlive())
1124 procflag = PROC_FLAG_DIE;
1126 ProcDamageAndSpell(pVictim, procflag, (procflag<<1));
1128 if (GetTypeId() == TYPEID_PLAYER)
1129 DEBUG_LOG("AttackerStateUpdate: (Player) %u %X attacked %u %X for %u dmg, absorbed %u, blocked %u, resisted %u.",
1130 GetGUIDLow(), GetGUIDHigh(), pVictim->GetGUIDLow(), pVictim->GetGUIDHigh(), damage, absorbed_dmg, blocked_dmg, resisted_dmg);
1131 else
1132 DEBUG_LOG("AttackerStateUpdate: (NPC) %u %X attacked %u %X for %u dmg, absorbed %u, blocked %u, resisted %u.",
1133 GetGUIDLow(), GetGUIDHigh(), pVictim->GetGUIDLow(), pVictim->GetGUIDHigh(), damage, absorbed_dmg, blocked_dmg, resisted_dmg);
1136 MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType) const
1138 int32 skillDiff = GetWeaponSkillValue(attType) - pVictim->GetDefenceSkillValue();
1139 // bonus from skills is 0.04%
1140 int32 skillBonus = skillDiff * 4;
1141 int32 skillBonus2 = 4 * ( GetWeaponSkillValue(attType) - pVictim->GetPureDefenceSkillValue() );
1142 int32 sum = 0, tmp = 0;
1143 int32 roll = urand (0, 10000);
1145 DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus);
1146 DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, +hit %d, dodge %u, parry %u, block %u, crit %u",
1147 roll, m_modHitChance, (uint32)(pVictim->GetUnitDodgeChance()*100), (uint32)(pVictim->GetUnitParryChance()*100),
1148 (uint32)(pVictim->GetUnitBlockChance()*100), (uint32)(GetUnitCriticalChance()*100));
1150 // dual wield has 24% base chance to miss instead of 5%, also
1151 // base miss rate is 5% and can't get higher than 60%
1152 tmp = MeleeMissChanceCalc(pVictim) - skillBonus;
1154 if(tmp > 6000)
1155 tmp = 6000;
1157 if (tmp > 0 && roll < (sum += tmp ))
1159 DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS");
1160 return MELEE_HIT_MISS;
1163 // always crit against a sitting target
1164 if ( (pVictim->GetTypeId() == TYPEID_PLAYER)
1165 && (((Player*)pVictim)->getStandState() & (PLAYER_STATE_SLEEP | PLAYER_STATE_SIT
1166 | PLAYER_STATE_SIT_CHAIR
1167 | PLAYER_STATE_SIT_LOW_CHAIR
1168 | PLAYER_STATE_SIT_MEDIUM_CHAIR
1169 | PLAYER_STATE_SIT_HIGH_CHAIR)))
1171 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)");
1172 return MELEE_HIT_CRIT;
1175 // stunned target cannot dodge and this is check in GetUnitDodgeChance()
1176 tmp = (int32)(pVictim->GetUnitDodgeChance()*100) - skillBonus2;
1177 if (tmp > 0 && roll < (sum += tmp))
1179 DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum-tmp, sum);
1180 return MELEE_HIT_DODGE;
1183 int32 modCrit = 0;
1185 // check if attack comes from behind
1186 if (!pVictim->HasInArc(M_PI,this))
1188 // ASSUME +10% crit from behind
1189 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind.");
1190 modCrit += 1000;
1192 else
1194 // cannot parry or block attacks from behind, but can from forward
1195 tmp = (int32)(pVictim->GetUnitParryChance()*100);
1196 if ( (tmp > 0) // check if unit _can_ parry
1197 && ((tmp -= skillBonus2) > 0)
1198 && (roll < (sum += tmp)))
1200 DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum-tmp, sum);
1201 return MELEE_HIT_PARRY;
1204 tmp = (int32)(pVictim->GetUnitBlockChance()*100);
1205 if ( (tmp > 0) // check if unit _can_ block
1206 && ((tmp -= skillBonus2) > 0)
1207 && (roll < (sum += tmp)))
1209 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum-tmp, sum);
1210 return MELEE_HIT_BLOCK;
1214 // Max 40% chance to score a glancing blow against mobs that are higher level
1215 if ( (GetTypeId() == TYPEID_PLAYER)
1216 && (pVictim->GetTypeId() != TYPEID_PLAYER)
1217 && ((getLevel() < pVictim->getLevel())))
1219 tmp = GetWeaponSkillValue(attType);
1220 int32 maxskill = getLevel() * 5;
1221 tmp = (tmp > maxskill) ? maxskill : tmp;
1222 tmp = ((pVictim->getLevel()* 5 - tmp - 5) * 300 + 1000 );
1223 tmp = tmp > 4000 ? 4000 : tmp;
1224 if (roll < (sum += tmp))
1226 DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum-4000, sum);
1227 return MELEE_HIT_GLANCING;
1231 // FIXME: +skill and +defense has no effect on crit chance in PvP combat
1232 tmp = (int32)(GetUnitCriticalChance()*100) + skillBonus + modCrit;
1233 if (tmp > 0 && roll < (sum += tmp))
1235 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum-tmp, sum);
1236 return MELEE_HIT_CRIT;
1239 // mobs can score crushing blows if they're 3 or more levels above victim
1240 // or when their weapon skill is 15 or more above victim's defense skill
1241 tmp = pVictim->GetDefenceSkillValue();
1242 uint32 tmpmax = pVictim->getLevel() * 5;
1243 // having defense above your maximum (from items, talents etc.) has no effect
1244 tmp = tmp > tmpmax ? tmpmax : tmp;
1245 // tmp = mob's level * 5 - player's current defense skill
1246 tmp = getLevel() * 5 - tmp;
1247 if (GetTypeId() != TYPEID_PLAYER && (tmp >= 15))
1249 // add 2% chance per lacking skill point, min. is 15%
1250 tmp = tmp * 200 - 1500;
1251 if (roll < (sum += tmp))
1253 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum-tmp, sum);
1254 return MELEE_HIT_CRUSHING;
1258 DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL");
1259 return MELEE_HIT_NORMAL;
1262 uint32 Unit::CalculateDamage (WeaponAttackType attType)
1264 float min_damage, max_damage;
1266 switch (attType)
1268 case RANGED_ATTACK:
1269 min_damage = GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE);
1270 max_damage = GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE);
1271 break;
1272 case BASE_ATTACK:
1273 min_damage = GetFloatValue(UNIT_FIELD_MINDAMAGE);
1274 max_damage = GetFloatValue(UNIT_FIELD_MAXDAMAGE);
1275 break;
1276 case OFF_ATTACK:
1277 // TODO: add offhand dmg from talents
1278 min_damage = GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) * 0.5;
1279 max_damage = GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE) * 0.5;
1280 break;
1283 if (min_damage > max_damage)
1285 std::swap(min_damage,max_damage);
1288 if(max_damage == 0.0)
1289 max_damage = 5.0;
1291 return urand ((uint32)min_damage, (uint32)max_damage);
1294 void Unit::SendAttackStart(Unit* pVictim)
1296 if(GetTypeId()!=TYPEID_PLAYER)
1297 return;
1299 WorldPacket data( SMSG_ATTACKSTART, 16 );
1300 data << GetGUID();
1301 data << pVictim->GetGUID();
1303 ((Player*)this)->SendMessageToSet(&data, true);
1304 DEBUG_LOG( "WORLD: Sent SMSG_ATTACKSTART" );
1307 void Unit::SendAttackStop(Unit* victim)
1309 WorldPacket data( SMSG_ATTACKSTOP, (4+16) ); // we guess size
1310 data.append(GetPackGUID());
1311 data.append(victim->GetPackGUID());
1312 data << uint32( 0 );
1313 data << (uint32)0;
1315 SendMessageToSet(&data, true);
1316 sLog.outDetail("%s %u stopped attacking %s %u", (GetTypeId()==TYPEID_PLAYER ? "player" : "creature"), GetGUIDLow(), (victim->GetTypeId()==TYPEID_PLAYER ? "player" : "creature"),victim->GetGUIDLow());
1318 if(victim->GetTypeId() == TYPEID_UNIT)
1319 ((Creature*)victim)->AI().AttackStop(this);
1322 uint32 Unit::SpellMissChanceCalc(Unit *pVictim) const
1324 if(!pVictim)
1325 return 0;
1327 // PvP : PvE spell misschances per leveldif > 2
1328 int32 chance = pVictim->GetTypeId() == TYPEID_PLAYER ? 700 : 1100;
1330 int32 leveldif = pVictim->getLevel() - getLevel();
1331 if(leveldif < 0)
1332 leveldif = 0;
1334 int32 misschance = 400 - m_modSpellHitChance*100;
1335 if(leveldif < 3)
1336 misschance += leveldif * 100;
1337 else
1338 misschance += (leveldif - 2) * chance;
1340 return misschance < 100 ? 100 : misschance;
1343 int32 Unit::MeleeMissChanceCalc(const Unit *pVictim) const
1345 if(!pVictim)
1346 return 0;
1348 int32 misschance = haveOffhandWeapon() ? 2400 : 500; //base misschance for DW : melee attacks
1350 // PvP : PvE melee misschances per leveldif > 2
1351 int32 chance = pVictim->GetTypeId() == TYPEID_PLAYER ? 500 : 700;
1353 int32 leveldif = pVictim->getLevel() - getLevel();
1354 if(leveldif < 0)
1355 leveldif = 0;
1357 if(leveldif < 3)
1358 misschance += leveldif * 100 - m_modHitChance*100;
1359 else
1360 misschance += (leveldif - 2) * chance - m_modHitChance*100;
1362 return misschance > 6000 ? 6000 : misschance;
1365 uint16 Unit::GetDefenceSkillValue() const
1367 if(GetTypeId() == TYPEID_PLAYER)
1368 return ((Player*)this)->GetSkillValue (SKILL_DEFENSE);
1369 else
1370 return GetUnitMeleeSkill();
1373 uint16 Unit::GetPureDefenceSkillValue() const
1375 if(GetTypeId() == TYPEID_PLAYER)
1376 return ((Player*)this)->GetPureSkillValue(SKILL_DEFENSE);
1377 else
1378 return GetUnitMeleeSkill();
1381 float Unit::GetUnitDodgeChance() const
1383 if(hasUnitState(UNIT_STAT_STUNDED))
1384 return 0;
1386 return GetTypeId() == TYPEID_PLAYER ? m_floatValues[ PLAYER_DODGE_PERCENTAGE ] : 5;
1389 float Unit::GetUnitParryChance() const
1391 float chance = 0;
1392 if(GetTypeId() == TYPEID_PLAYER)
1394 Player const* player = (Player const*)this;
1395 if(player->CanParry())
1397 Item *tmpitem = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
1398 if(!tmpitem || tmpitem->IsBroken())
1399 tmpitem = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
1401 if(tmpitem && !tmpitem->IsBroken() &&
1402 (tmpitem->GetProto()->InventoryType == INVTYPE_WEAPON || tmpitem->GetProto()->InventoryType == INVTYPE_2HWEAPON))
1403 chance = GetFloatValue(PLAYER_PARRY_PERCENTAGE);
1406 else if(GetTypeId() == TYPEID_UNIT)
1408 if(((Creature const*)this)->GetCreatureInfo()->type == CREATURE_TYPE_HUMANOID)
1409 chance = 5;
1412 return chance;
1415 float Unit::GetUnitBlockChance() const
1417 float chance = 0;
1418 if(GetTypeId() == TYPEID_PLAYER)
1420 Item *tmpitem = ((Player const*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
1421 if(tmpitem && !tmpitem->IsBroken() && tmpitem->GetProto()->Block)
1422 chance = GetFloatValue(PLAYER_BLOCK_PERCENTAGE);
1424 else
1425 chance = 5;
1427 return chance;
1430 uint16 Unit::GetWeaponSkillValue (WeaponAttackType attType) const
1432 if(GetTypeId() == TYPEID_PLAYER)
1434 uint16 slot;
1435 switch (attType)
1437 case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
1438 case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
1439 case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
1441 Item *item = ((Player*)this)->GetItemByPos (INVENTORY_SLOT_BAG_0, slot);
1443 if(attType != EQUIPMENT_SLOT_MAINHAND && (!item || item->IsBroken()))
1444 return 0;
1446 // in range
1447 uint32 skill = item && !item->IsBroken() ? item->GetSkill() : SKILL_UNARMED;
1448 return ((Player*)this)->GetSkillValue (skill);
1450 else
1451 return GetUnitMeleeSkill();
1454 uint16 Unit::GetPureWeaponSkillValue (WeaponAttackType attType) const
1456 if(GetTypeId() == TYPEID_PLAYER)
1458 uint16 slot;
1459 switch (attType)
1461 case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
1462 case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
1463 case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
1465 Item *item = ((Player*)this)->GetItemByPos (INVENTORY_SLOT_BAG_0, slot);
1467 if(attType != EQUIPMENT_SLOT_MAINHAND && (!item || item->IsBroken()))
1468 return 0;
1470 // in range
1471 uint32 skill = item && !item->IsBroken() ? item->GetSkill() : SKILL_UNARMED;
1472 return ((Player*)this)->GetPureSkillValue (skill);
1474 else
1475 return GetUnitMeleeSkill();
1478 void Unit::_UpdateSpells( uint32 time )
1480 if(m_oldSpell != NULL)
1482 delete m_oldSpell;
1483 m_oldSpell = NULL;
1486 if(m_currentSpell != NULL)
1488 m_currentSpell->update(time);
1489 if(m_currentSpell->IsAutoRepeat())
1491 if(m_currentSpell->getState() == SPELL_STATE_FINISHED)
1493 //Auto Shot & Shoot
1494 if( m_currentSpell->m_spellInfo->AttributesEx2 == 0x000020 && GetTypeId() == TYPEID_PLAYER )
1495 resetAttackTimer( RANGED_ATTACK );
1496 else
1497 setAttackTimer( RANGED_ATTACK, m_currentSpell->m_spellInfo->RecoveryTime);
1499 m_currentSpell->setState(SPELL_STATE_IDLE);
1501 else if(m_currentSpell->getState() == SPELL_STATE_IDLE && isAttackReady(RANGED_ATTACK) )
1503 // check movement in player case
1504 if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->GetMovementFlags())
1506 // cancel wand shooting
1507 if(m_currentSpell->m_spellInfo->Category == 351)
1509 WorldPacket data(SMSG_CANCEL_AUTO_REPEAT, 0);
1510 ((Player*)this)->GetSession()->SendPacket(&data);
1511 castSpell(NULL);
1513 // ELSE delay auto-repeat ranged weapon until player movement stop
1515 else
1516 // recheck range and req. items (ammo and gun, etc)
1517 if(m_currentSpell->CheckRange() == 0 && m_currentSpell->CheckItems() == 0 )
1519 m_currentSpell->setState(SPELL_STATE_PREPARING);
1520 m_currentSpell->ReSetTimer();
1522 else
1524 if(GetTypeId()==TYPEID_PLAYER)
1526 WorldPacket data(SMSG_CANCEL_AUTO_REPEAT, 0);
1527 ((Player*)this)->GetSession()->SendPacket(&data);
1529 castSpell(NULL);
1533 else if(m_currentSpell->getState() == SPELL_STATE_FINISHED)
1535 delete m_currentSpell;
1536 m_currentSpell = NULL;
1540 if(m_currentMeleeSpell != NULL)
1542 m_currentMeleeSpell ->update(time);
1543 if(m_currentMeleeSpell ->getState() == SPELL_STATE_FINISHED)
1545 delete m_currentMeleeSpell ;
1546 m_currentMeleeSpell = NULL;
1550 // TODO: Find a better way to prevent crash when multiple auras are removed.
1551 m_removedAuras = 0;
1552 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
1553 if ((*i).second)
1554 (*i).second->SetUpdated(false);
1556 for (AuraMap::iterator i = m_Auras.begin(), next; i != m_Auras.end(); i = next)
1558 next = i;
1559 next++;
1560 if ((*i).second)
1562 // prevent double update
1563 if ((*i).second->IsUpdated())
1564 continue;
1565 (*i).second->SetUpdated(true);
1566 (*i).second->Update( time );
1567 // several auras can be deleted due to update
1568 if (m_removedAuras)
1570 if (m_Auras.empty()) break;
1571 next = m_Auras.begin();
1572 m_removedAuras = 0;
1577 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end();)
1579 if ((*i).second)
1581 if ( !(*i).second->GetAuraDuration() && !((*i).second->IsPermanent() || ((*i).second->IsPassive())) )
1583 RemoveAura(i);
1585 else
1587 ++i;
1590 else
1592 ++i;
1596 if(!m_dynObj.empty())
1598 std::list<DynamicObject*>::iterator ite, dnext;
1599 for (ite = m_dynObj.begin(); ite != m_dynObj.end(); ite = dnext)
1601 dnext = ite;
1602 //(*i)->Update( difftime );
1603 if( (*ite)->isFinished() )
1605 (*ite)->Delete();
1606 dnext = m_dynObj.erase(ite);
1608 else
1609 ++dnext;
1612 if(!m_gameObj.empty())
1614 std::list<GameObject*>::iterator ite1, dnext1;
1615 for (ite1 = m_gameObj.begin(); ite1 != m_gameObj.end(); ite1 = dnext1)
1617 dnext1 = ite1;
1618 //(*i)->Update( difftime );
1619 if( (*ite1)->isFinished() )
1621 (*ite1)->SetOwnerGUID(0);
1622 (*ite1)->Delete();
1623 dnext1 = m_gameObj.erase(ite1);
1625 else
1626 ++dnext1;
1631 void Unit::_UpdateHostil( uint32 time )
1633 if(!isInCombat() && m_hostilList.size() )
1635 HostilList::iterator iter, next;
1636 for(iter=m_hostilList.begin(); iter!=m_hostilList.end(); iter = next)
1638 next = iter;
1639 iter->Hostility-=time/1000.0f;
1640 if(iter->Hostility<=0.0f)
1642 next = m_hostilList.erase(iter);
1644 else
1645 ++next;
1650 Unit* Unit::SelectHostilTarget()
1652 if(!m_hostilList.size())
1653 return NULL;
1655 m_hostilList.sort();
1656 m_hostilList.reverse();
1657 uint64 guid = m_hostilList.front().UnitGuid;
1658 if(!getVictim() || guid != getVictim()->GetGUID())
1659 return ObjectAccessor::Instance().GetUnit(*this, guid);
1660 else
1661 return NULL;
1664 void Unit::castSpell( Spell * pSpell )
1667 if(pSpell && pSpell->IsMeleeSpell())
1669 if(m_currentMeleeSpell)
1671 m_currentMeleeSpell->cancel();
1672 delete m_currentMeleeSpell;
1673 m_currentMeleeSpell = NULL;
1675 m_currentMeleeSpell = pSpell;
1677 else
1679 if(m_currentSpell)
1681 m_currentSpell->cancel();
1682 // let call spell from spell (single level recursion) and not crash at returning to procesiing old spell
1683 if(m_oldSpell)
1684 delete m_oldSpell;
1685 m_oldSpell = m_currentSpell;
1687 m_currentSpell = pSpell;
1691 void Unit::InterruptSpell()
1693 if(m_currentSpell)
1695 //m_currentSpell->SendInterrupted(0x20);
1696 m_currentSpell->cancel();
1700 bool Unit::isInFront(Unit const* target, float radius)
1702 return IsWithinDist(target, radius) && HasInArc( M_PI, target );
1705 void Unit::SetInFront(Unit const* target)
1707 m_orientation = GetAngle(target);
1710 bool Unit::isInAccessablePlaceFor(Creature* c) const
1712 if(IsInWater())
1713 return c->isCanSwimOrFly();
1714 else
1715 return c->isCanWalkOrFly();
1718 bool Unit::IsInWater() const
1720 return MapManager::Instance().GetMap(GetMapId())->IsInWater(GetPositionX(),GetPositionY());
1723 bool Unit::IsUnderWater() const
1725 return MapManager::Instance().GetMap(GetMapId())->IsUnderWater(GetPositionX(),GetPositionY(),GetPositionZ());
1728 void Unit::DeMorph()
1731 uint32 displayid = GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID);
1732 SetUInt32Value(UNIT_FIELD_DISPLAYID, displayid);
1735 long Unit::GetTotalAuraModifier(uint32 ModifierID)
1737 uint32 modifier = 0;
1738 bool auraFound = false;
1740 AuraMap::const_iterator i;
1741 for (i = m_Auras.begin(); i != m_Auras.end(); i++)
1743 if ((*i).second && (*i).second->GetModifier()->m_auraname == ModifierID)
1745 auraFound = true;
1746 modifier += (*i).second->GetModifier()->m_amount;
1749 if (auraFound)
1750 modifier++;
1752 return modifier;
1755 bool Unit::AddAura(Aura *Aur, bool uniq)
1757 if (!isAlive())
1759 delete Aur;
1760 return false;
1763 AuraMap::iterator i = m_Auras.find( spellEffectPair(Aur->GetId(), Aur->GetEffIndex()) );
1765 // take out same spell
1766 if (i != m_Auras.end())
1768 /*(*i).second->SetAuraDuration(Aur->GetAuraDuration());
1769 if ((*i).second->GetTarget())
1770 if ((*i).second->GetTarget()->GetTypeId() == TYPEID_PLAYER )
1771 (*i).second->UpdateAuraDuration();
1772 delete Aur;
1773 return false;*/
1774 // passive and persistent auras can stack with themselves any number of times
1775 if (!Aur->IsPassive() && !Aur->IsPersistent() && m_Auras.count(spellEffectPair(Aur->GetId(), Aur->GetEffIndex())) >= Aur->GetSpellProto()->StackAmount)
1776 RemoveAura(i);
1779 if (!Aur->IsPassive()) // passive auras stack with all
1781 if (!RemoveNoStackAurasDueToAura(Aur))
1783 delete Aur;
1784 return false; // couldnt remove conflicting aura with higher rank
1788 Aur->_AddAura();
1789 m_Auras.insert(AuraMap::value_type(spellEffectPair(Aur->GetId(), Aur->GetEffIndex()), Aur));
1790 if (Aur->GetModifier()->m_auraname < TOTAL_AURAS)
1792 m_modAuras[Aur->GetModifier()->m_auraname].push_back(Aur);
1793 m_AuraModifiers[Aur->GetModifier()->m_auraname] += (Aur->GetModifier()->m_amount);
1796 if (IsSingleTarget(Aur->GetId()) && Aur->GetTarget() && Aur->GetSpellProto())
1798 if(Unit* caster = Aur->GetCaster())
1800 std::list<Aura *> *scAuras = caster->GetSingleCastAuras();
1801 std::list<Aura *>::iterator itr, next;
1802 for (itr = scAuras->begin(); itr != scAuras->end(); itr = next)
1804 next = itr;
1805 next++;
1806 if ((*itr)->GetTarget() != Aur->GetTarget() &&
1807 (*itr)->GetSpellProto()->Category == Aur->GetSpellProto()->Category &&
1808 (*itr)->GetSpellProto()->SpellIconID == Aur->GetSpellProto()->SpellIconID &&
1809 (*itr)->GetSpellProto()->SpellVisual == Aur->GetSpellProto()->SpellVisual &&
1810 (*itr)->GetSpellProto()->Attributes == Aur->GetSpellProto()->Attributes &&
1811 (*itr)->GetSpellProto()->AttributesEx == Aur->GetSpellProto()->AttributesEx &&
1812 (*itr)->GetSpellProto()->AttributesExEx == Aur->GetSpellProto()->AttributesExEx)
1814 (*itr)->GetTarget()->RemoveAura((*itr)->GetId(), (*itr)->GetEffIndex());
1815 if(scAuras->empty())
1816 break;
1817 else
1818 next = scAuras->begin();
1821 scAuras->push_back(Aur);
1824 return true;
1827 void Unit::RemoveRankAurasDueToSpell(uint32 spellId)
1829 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
1830 if(!spellInfo)
1831 return;
1832 AuraMap::iterator i,next;
1833 for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
1835 next = i;
1836 next++;
1837 uint32 i_spellId = (*i).second->GetId();
1838 if((*i).second && i_spellId && i_spellId != spellId)
1840 if(IsRankSpellDueToSpell(spellInfo,i_spellId))
1842 RemoveAurasDueToSpell(i_spellId);
1844 if( m_Auras.empty() )
1845 break;
1846 else
1847 next = m_Auras.begin();
1853 bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur)
1855 if (!Aur)
1856 return false;
1857 if (!Aur->GetSpellProto()) return false;
1858 uint32 spellId = Aur->GetId();
1859 uint32 effIndex = Aur->GetEffIndex();
1860 bool is_sec = IsSpellSingleEffectPerCaster(spellId);
1861 AuraMap::iterator i,next;
1862 for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
1864 next = i;
1865 next++;
1866 if (!(*i).second) continue;
1867 if (!(*i).second->GetSpellProto()) continue;
1868 if (IsPassiveSpell((*i).second->GetId())) continue;
1870 uint32 i_spellId = (*i).second->GetId();
1871 uint32 i_effIndex = (*i).second->GetEffIndex();
1872 if(i_spellId != spellId)
1874 bool sec_match = false;
1875 if (is_sec && IsSpellSingleEffectPerCaster(i_spellId))
1876 if (Aur->GetCasterGUID() == (*i).second->GetCasterGUID())
1877 if (GetSpellSpecific(spellId) == GetSpellSpecific(i_spellId))
1878 sec_match = true;
1880 if(IsNoStackSpellDueToSpell(spellId, i_spellId) || sec_match)
1882 // if sec_match this isnt always true, needs to be rechecked
1883 if (IsRankSpellDueToSpell(Aur->GetSpellProto(), i_spellId))
1884 if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
1885 return false; // cannot remove higher rank
1887 RemoveAurasDueToSpell(i_spellId);
1889 if( m_Auras.empty() )
1890 break;
1891 else
1892 next = m_Auras.begin();
1894 else // Potions stack aura by aura
1895 if (Aur->GetSpellProto()->SpellFamilyName == SPELLFAMILY_POTION &&
1896 (*i).second->GetSpellProto()->SpellFamilyName == SPELLFAMILY_POTION)
1898 if (IsNoStackAuraDueToAura(spellId, effIndex, i_spellId, i_effIndex))
1900 if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
1901 return false; // cannot remove higher rank
1903 RemoveAura(i);
1905 if( m_Auras.empty() )
1906 break;
1907 else
1908 next = m_Auras.begin();
1913 return true;
1916 void Unit::RemoveFirstAuraByDispel(uint32 dispel_type)
1918 AuraMap::iterator i,next;
1919 for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
1921 next = i;
1922 next++;
1923 if ((*i).second && (*i).second->GetSpellProto()->Dispel == dispel_type)
1925 if(dispel_type == 1)
1927 bool positive = true;
1928 switch((*i).second->GetSpellProto()->EffectImplicitTargetA[(*i).second->GetEffIndex()])
1930 case TARGET_SINGLE_ENEMY:
1931 case TARGET_ALL_ENEMY_IN_AREA:
1932 case TARGET_ALL_ENEMY_IN_AREA_INSTANT:
1933 case TARGET_ALL_ENEMIES_AROUND_CASTER:
1934 case TARGET_IN_FRONT_OF_CASTER:
1935 case TARGET_DUELVSPLAYER:
1936 case TARGET_ALL_ENEMY_IN_AREA_CHANNELED:
1937 case TARGET_CURRENT_SELECTED_ENEMY:
1938 positive = false;
1939 break;
1941 default:
1942 positive = ((*i).second->GetSpellProto()->AttributesEx & (1<<7)) ? false : true;
1944 if(positive)
1945 continue;
1947 RemoveAura(i);
1948 if( m_Auras.empty() )
1949 break;
1950 else
1951 next = m_Auras.begin();
1956 void Unit::RemoveAreaAurasByOthers(uint64 guid)
1958 int j = 0;
1959 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end();)
1961 if (i->second && i->second->IsAreaAura())
1963 uint64 casterGuid = i->second->GetCasterGUID();
1964 uint64 targetGuid = i->second->GetTarget()->GetGUID();
1965 // if area aura cast by someone else or by the specified caster
1966 if (casterGuid == guid || (guid == 0 && casterGuid != targetGuid))
1968 for (j = 0; j < 4; j++)
1969 if (m_TotemSlot[j] == casterGuid)
1970 break;
1971 // and not by one of my totems
1972 if (j == 4)
1973 RemoveAura(i);
1974 else
1975 ++i;
1977 else
1978 ++i;
1980 else
1981 ++i;
1985 void Unit::RemoveAura(uint32 spellId, uint32 effindex)
1987 AuraMap::iterator i = m_Auras.find( spellEffectPair(spellId, effindex) );
1988 if(i != m_Auras.end())
1989 RemoveAura(i);
1992 void Unit::RemoveAurasDueToSpell(uint32 spellId)
1994 for (int i = 0; i < 3; i++)
1996 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, i));
1997 if (iter != m_Auras.end())
1998 RemoveAura(iter);
2002 void Unit::RemoveAura(AuraMap::iterator &i, bool onDeath)
2004 if (IsSingleTarget((*i).second->GetId()))
2006 if(Unit* caster = (*i).second->GetCaster())
2008 std::list<Aura *> *scAuras = caster->GetSingleCastAuras();
2009 scAuras->remove((*i).second);
2012 // remove aura from party members when the caster turns off the aura
2013 if((*i).second->IsAreaAura())
2015 Unit *i_target = (*i).second->GetTarget();
2016 if((*i).second->GetCasterGUID() == i_target->GetGUID())
2018 Unit* i_caster = i_target;
2020 Group *pGroup = NULL;
2021 if (i_caster->GetTypeId() == TYPEID_PLAYER)
2022 pGroup = ((Player*)i_caster)->groupInfo.group;
2023 else if(((Creature*)i_caster)->isTotem())
2025 Unit *owner = ((Totem*)i_caster)->GetOwner();
2026 if (owner && owner->GetTypeId() == TYPEID_PLAYER)
2027 pGroup = ((Player*)owner)->groupInfo.group;
2030 //float radius = GetRadius(sSpellRadiusStore.LookupEntry((*i).second->GetSpellProto()->EffectRadiusIndex[(*i).second->GetEffIndex()]));
2031 if(pGroup)
2033 for(uint32 p=0;p<pGroup->GetMembersCount();p++)
2035 if(!pGroup->SameSubGroup(i_caster->GetGUID(), pGroup->GetMemberGUID(p)))
2036 continue;
2038 Unit* Target = objmgr.GetPlayer(pGroup->GetMemberGUID(p));
2039 if(!Target || Target->GetGUID() == i_caster->GetGUID())
2040 continue;
2041 Aura *t_aura = Target->GetAura((*i).second->GetId(), (*i).second->GetEffIndex());
2042 if (t_aura)
2043 if (t_aura->GetCasterGUID() == i_caster->GetGUID())
2044 Target->RemoveAura((*i).second->GetId(), (*i).second->GetEffIndex());
2049 if ((*i).second->GetModifier()->m_auraname < TOTAL_AURAS)
2051 m_AuraModifiers[(*i).second->GetModifier()->m_auraname] -= ((*i).second->GetModifier()->m_amount);
2052 m_modAuras[(*i).second->GetModifier()->m_auraname].remove((*i).second);
2054 (*i).second->SetRemoveOnDeath(onDeath);
2055 (*i).second->_RemoveAura();
2057 delete (*i).second;
2058 m_Auras.erase(i++);
2059 m_removedAuras++; // internal count used by unit update
2062 bool Unit::SetAurDuration(uint32 spellId, uint32 effindex,uint32 duration)
2064 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
2065 if (iter != m_Auras.end())
2067 (*iter).second->SetAuraDuration(duration);
2068 return true;
2070 return false;
2073 uint32 Unit::GetAurDuration(uint32 spellId, uint32 effindex)
2075 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
2076 if (iter != m_Auras.end())
2078 return (*iter).second->GetAuraDuration();
2080 return 0;
2083 void Unit::RemoveAllAuras()
2085 while (!m_Auras.empty())
2087 AuraMap::iterator iter = m_Auras.begin();
2088 RemoveAura(iter);
2092 void Unit::RemoveAllAurasOnDeath()
2094 // used just after dieing to remove all visible auras
2095 // and disable the mods for the passive ones
2096 for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
2097 if (!iter->second->IsPassive())
2098 RemoveAura(iter, true);
2099 else
2100 ++iter;
2101 _RemoveAllAuraMods();
2104 void Unit::DelayAura(uint32 spellId, uint32 effindex, int32 delaytime)
2106 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
2107 if (iter != m_Auras.end())
2109 iter->second->SetAuraDuration(iter->second->GetAuraDuration() + delaytime);
2110 if(iter->second->IsPeriodic())
2111 iter->second->DelayPeriodicTimer(delaytime);
2112 iter->second->UpdateAuraDuration();
2113 sLog.outDebug("Aura %u delayed on unit %u, new duration: %u ms",iter->second->GetModifier()->m_auraname, GetGUIDLow(), iter->second->GetAuraDuration());
2117 void Unit::_RemoveStatsMods()
2119 ApplyStats(false);
2122 void Unit::_ApplyStatsMods()
2124 ApplyStats(true);
2127 void Unit::ApplyStats(bool apply)
2129 // TODO:
2130 // -- add --
2131 // spell crit formula: 5 + INT/100
2132 // skill formula: skill*0,04 for all, use defense skill for parry/dodge
2133 // froze spells gives + 50% change to crit
2135 if(GetTypeId() != TYPEID_PLAYER) return;
2137 float val;
2138 int32 val2,tem_att_power;
2139 float totalstatmods[5] = {1,1,1,1,1};
2140 float totalresmods[7] = {1,1,1,1,1,1,1};
2142 AuraList& mModTotalStatPct = GetAurasByType(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE);
2143 for(AuraList::iterator i = mModTotalStatPct.begin(); i != mModTotalStatPct.end(); ++i)
2145 if((*i)->GetModifier()->m_miscvalue != -1)
2146 totalstatmods[(*i)->GetModifier()->m_miscvalue] *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f;
2147 else
2148 for (uint8 j = 0; j < MAX_STATS; j++)
2149 totalstatmods[j] *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f;
2151 AuraList& mModResistancePct = GetAurasByType(SPELL_AURA_MOD_RESISTANCE_PCT);
2152 for(AuraList::iterator i = mModResistancePct.begin(); i != mModResistancePct.end(); ++i)
2153 for(uint8 j = 0; j < MAX_SPELL_SCHOOOL; j++)
2154 if((*i)->GetModifier()->m_miscvalue & (1<<j))
2155 totalresmods[j] *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f;
2157 for (uint8 i = 0; i < MAX_STATS; i++)
2158 totalstatmods[i] = totalstatmods[i] * 100.0f - 100.0f;
2159 for (uint8 i = 0; i < MAX_SPELL_SCHOOOL; i++)
2160 totalresmods[i] = totalresmods[i] * 100.0f - 100.0f;
2162 // restore percent mods
2163 if (apply)
2165 for (uint8 i = 0; i < MAX_STATS; i++)
2167 if (totalstatmods[i] != 0)
2169 ApplyStatPercentMod(Stats(i),totalstatmods[i], apply );
2170 ((Player*)this)->ApplyPosStatPercentMod(Stats(i),totalstatmods[i], apply );
2171 ((Player*)this)->ApplyNegStatPercentMod(Stats(i),totalstatmods[i], apply );
2174 for (uint8 i = 0; i < MAX_SPELL_SCHOOOL; i++)
2176 if (totalresmods[i] != 0)
2178 ApplyResistancePercentMod(SpellSchools(i), totalresmods[i], apply );
2179 ((Player*)this)->ApplyResistanceBuffModsPercentMod(SpellSchools(i),true, totalresmods[i], apply);
2180 ((Player*)this)->ApplyResistanceBuffModsPercentMod(SpellSchools(i),false, totalresmods[i], apply);
2185 // Armor
2186 val = 2*(GetStat(STAT_AGILITY) - ((Player*)this)->GetCreateStat(STAT_AGILITY));
2188 ApplyArmorMod( val, apply);
2190 // HP
2191 val2 = uint32((GetStat(STAT_STAMINA) - ((Player*)this)->GetCreateStat(STAT_STAMINA))*10);
2193 ApplyMaxHealthMod( val2, apply);
2195 // MP
2196 if(getClass() != CLASS_WARRIOR && getClass() != CLASS_ROGUE)
2198 val2 = uint32((GetStat(STAT_INTELLECT) - ((Player*)this)->GetCreateStat(STAT_INTELLECT))*15);
2200 ApplyMaxPowerMod(POWER_MANA, val2, apply);
2204 float classrate = 0;
2206 // Melee Attack Power
2207 // && Melee DPS - (Damage Per Second)
2209 //Ranged
2210 if(getClass() == CLASS_HUNTER)
2211 val2 = uint32(getLevel() * 2 + GetStat(STAT_AGILITY) * 2 - 20);
2212 else
2213 val2 = uint32(getLevel() + GetStat(STAT_AGILITY) * 2 - 20);
2215 if(!apply)
2216 tem_att_power = GetUInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER) + GetUInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER_MODS);
2218 ApplyModUInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER, val2, apply);
2220 if(apply)
2221 tem_att_power = GetUInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER) + GetUInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER_MODS);
2223 val = GetFloatValue(UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER);
2224 if(val>0)
2225 tem_att_power = uint32(val*tem_att_power);
2227 val = tem_att_power/14.0f * GetAttackTime(RANGED_ATTACK)/1000;
2228 ApplyModFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, val, apply);
2229 ApplyModFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, val, apply);
2231 //Not-ranged
2233 switch(getClass())
2235 case CLASS_WARRIOR: val2 = uint32(getLevel()*3 + GetStat(STAT_STRENGTH)*2 - 20); break;
2236 case CLASS_PALADIN: val2 = uint32(getLevel()*3 + GetStat(STAT_STRENGTH)*2 - 20); break;
2237 case CLASS_ROGUE: val2 = uint32(getLevel()*2 + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20); break;
2238 case CLASS_HUNTER: val2 = uint32(getLevel()*2 + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20); break;
2239 case CLASS_SHAMAN: val2 = uint32(getLevel()*2 + GetStat(STAT_STRENGTH)*2 - 20); break;
2240 case CLASS_DRUID: val2 = uint32(GetStat(STAT_STRENGTH)*2 - 20); break;
2241 case CLASS_MAGE: val2 = uint32(GetStat(STAT_STRENGTH) - 10); break;
2242 case CLASS_PRIEST: val2 = uint32(GetStat(STAT_STRENGTH) - 10); break;
2243 case CLASS_WARLOCK: val2 = uint32(GetStat(STAT_STRENGTH) - 10); break;
2245 tem_att_power = GetUInt32Value(UNIT_FIELD_ATTACK_POWER) + GetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS);
2247 ApplyModUInt32Value(UNIT_FIELD_ATTACK_POWER, val2, apply);
2249 if(apply)
2250 tem_att_power = GetUInt32Value(UNIT_FIELD_ATTACK_POWER) + GetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS);
2252 val = GetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER);
2253 if(val>0)
2254 tem_att_power = uint32(val*tem_att_power);
2256 val = tem_att_power/14.0f * GetAttackTime(BASE_ATTACK)/1000;
2258 ApplyModFloatValue(UNIT_FIELD_MINDAMAGE, val, apply);
2259 ApplyModFloatValue(UNIT_FIELD_MAXDAMAGE, val, apply);
2261 val = tem_att_power/14.0f * GetAttackTime(OFF_ATTACK)/1000;
2263 ApplyModFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE, val, apply);
2264 ApplyModFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE, val, apply);
2266 // critical
2267 if(getClass() == CLASS_HUNTER) classrate = 53;
2268 else if(getClass() == CLASS_ROGUE) classrate = 29;
2269 else classrate = 20;
2271 val = GetStat(STAT_AGILITY)/classrate;
2273 ApplyModFloatValue(PLAYER_CRIT_PERCENTAGE, val, apply);
2275 //dodge
2276 if(getClass() == CLASS_HUNTER) classrate = 26.5;
2277 else if(getClass() == CLASS_ROGUE) classrate = 14.5;
2278 else classrate = 20;
2279 ///*+(Defense*0,04);
2280 if (getRace() == RACE_NIGHTELF)
2281 val = GetStat(STAT_AGILITY)/classrate + 1;
2282 else
2283 val = GetStat(STAT_AGILITY)/classrate;
2285 ApplyModFloatValue(PLAYER_DODGE_PERCENTAGE, val, apply);
2287 // remove percent mods to see original stats when adding buffs/items
2288 if (!apply)
2290 for (uint8 i = 0; i < MAX_STATS; i++)
2292 if (totalstatmods[i])
2294 ApplyStatPercentMod(Stats(i),totalstatmods[i], apply );
2295 ((Player*)this)->ApplyPosStatPercentMod(Stats(i),totalstatmods[i], apply );
2296 ((Player*)this)->ApplyNegStatPercentMod(Stats(i),totalstatmods[i], apply );
2299 for (uint8 i = 0; i < MAX_SPELL_SCHOOOL; i++)
2301 if (totalresmods[i])
2303 ApplyResistancePercentMod(SpellSchools(i), totalresmods[i], apply );
2304 ((Player*)this)->ApplyResistanceBuffModsPercentMod(SpellSchools(i),true, totalresmods[i], apply);
2305 ((Player*)this)->ApplyResistanceBuffModsPercentMod(SpellSchools(i),false, totalresmods[i], apply);
2311 void Unit::_RemoveAllAuraMods()
2313 ApplyStats(false);
2314 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
2316 switch ((*i).second->GetModifier()->m_auraname)
2318 case SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE:
2319 case SPELL_AURA_MOD_RESISTANCE_PCT:
2320 // these are already removed by applystats
2321 break;
2322 default:
2323 (*i).second->ApplyModifier(false);
2326 ApplyStats(true);
2328 // these must be removed after applystats
2329 AuraList& mModTotalStatPct = GetAurasByType(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE);
2330 for(AuraList::iterator i = mModTotalStatPct.begin(); i != mModTotalStatPct.end(); ++i)
2331 (*i)->ApplyModifier(false);
2332 AuraList& mModResistancePct = GetAurasByType(SPELL_AURA_MOD_RESISTANCE_PCT);
2333 for(AuraList::iterator i = mModResistancePct.begin(); i != mModResistancePct.end(); ++i)
2334 (*i)->ApplyModifier(false);
2337 void Unit::_ApplyAllAuraMods()
2339 // these must be applied before applystats
2340 AuraList& mModTotalStatPct = GetAurasByType(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE);
2341 for(AuraList::iterator i = mModTotalStatPct.begin(); i != mModTotalStatPct.end(); ++i)
2342 (*i)->ApplyModifier(true);
2343 AuraList& mModResistancePct = GetAurasByType(SPELL_AURA_MOD_RESISTANCE_PCT);
2344 for(AuraList::iterator i = mModResistancePct.begin(); i != mModResistancePct.end(); ++i)
2345 (*i)->ApplyModifier(true);
2346 ApplyStats(false);
2348 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
2350 switch ((*i).second->GetModifier()->m_auraname)
2352 case SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE:
2353 case SPELL_AURA_MOD_RESISTANCE_PCT:
2354 // these are already applied by applystats
2355 break;
2356 default:
2357 (*i).second->ApplyModifier(true);
2360 ApplyStats(true);
2363 // TODO: FIX-ME!!!
2364 /*void Unit::_UpdateAura()
2366 if(GetTypeId() != TYPEID_PLAYER || !m_Auras)
2367 return;
2369 Player* pThis = (Player*)this;
2371 Player* pGroupGuy;
2372 Group* pGroup;
2374 pGroup = objmgr.GetGroupByLeader(pThis->GetGroupLeader());
2376 if(!SetAffDuration(m_Auras->GetId(),this,6000))
2377 AddAura(m_Auras);
2379 if(!pGroup)
2380 return;
2381 else
2383 for(uint32 i=0;i<pGroup->GetMembersCount();i++)
2385 pGroupGuy = ObjectAccessor::Instance().FindPlayer(pGroup->GetMemberGUID(i));
2387 if(!pGroupGuy)
2388 continue;
2389 if(pGroupGuy->GetGUID() == GetGUID())
2390 continue;
2391 if(sqrt(
2392 (GetPositionX()-pGroupGuy->GetPositionX())*(GetPositionX()-pGroupGuy->GetPositionX())
2393 +(GetPositionY()-pGroupGuy->GetPositionY())*(GetPositionY()-pGroupGuy->GetPositionY())
2394 +(GetPositionZ()-pGroupGuy->GetPositionZ())*(GetPositionZ()-pGroupGuy->GetPositionZ())
2395 ) <=30)
2397 if(!pGroupGuy->SetAffDuration(m_Auras->GetId(),this,6000))
2398 pGroupGuy->AddAura(m_Auras);
2400 else
2402 if(m_removeAuraTimer == 0)
2404 printf("remove aura from %u\n", pGroupGuy->GetGUID());
2405 pGroupGuy->RemoveAura(m_Auras->GetId());
2410 if(m_removeAuraTimer > 0)
2411 m_removeAuraTimer -= 1;
2412 else
2413 m_removeAuraTimer = 4;
2416 Aura* Unit::GetAura(uint32 spellId, uint32 effindex)
2418 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
2419 if (iter != m_Auras.end())
2420 return iter->second;
2421 return NULL;
2424 float Unit::GetHostility(uint64 guid) const
2426 HostilList::const_iterator i;
2427 for ( i = m_hostilList.begin(); i!= m_hostilList.end(); i++)
2429 if(i->UnitGuid==guid)
2430 return i->Hostility;
2432 return 0.0f;
2435 void Unit::AddHostil(uint64 guid, float hostility)
2437 HostilList::iterator i;
2438 for(i = m_hostilList.begin(); i != m_hostilList.end(); i++)
2440 if(i->UnitGuid==guid)
2442 i->Hostility+=hostility;
2443 return;
2446 m_hostilList.push_back(Hostil(guid,hostility));
2449 void Unit::AddItemEnchant(Item *item,uint32 enchant_id,bool apply)
2451 if (GetTypeId() != TYPEID_PLAYER)
2452 return;
2454 if(!item)
2455 return;
2457 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
2458 if(!pEnchant)
2459 return;
2460 uint32 enchant_display = pEnchant->display_type;
2461 uint32 enchant_value1 = pEnchant->value1;
2462 uint32 enchant_spell_id = pEnchant->spellid;
2464 SpellEntry const *enchantSpell_info = sSpellStore.LookupEntry(enchant_spell_id);
2466 if(enchant_display ==4)
2468 ApplyArmorMod(enchant_value1,apply);
2470 else if(enchant_display ==2)
2472 if(getClass() == CLASS_HUNTER)
2474 ApplyModFloatValue(UNIT_FIELD_MINRANGEDDAMAGE,enchant_value1,apply);
2475 ApplyModFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE,enchant_value1,apply);
2477 else
2479 ApplyModFloatValue(UNIT_FIELD_MINDAMAGE,enchant_value1,apply);
2480 ApplyModFloatValue(UNIT_FIELD_MAXDAMAGE,enchant_value1,apply);
2483 else
2485 if(apply && enchant_display == 3)
2487 Spell spell(this, enchantSpell_info, true, 0);
2488 SpellCastTargets targets;
2489 targets.setUnitTarget(this);
2490 spell.prepare(&targets);
2492 else RemoveAurasDueToSpell(enchant_spell_id);
2496 void Unit::AddDynObject(DynamicObject* dynObj)
2498 m_dynObj.push_back(dynObj);
2501 void Unit::RemoveDynObject(uint32 spellid)
2503 if(m_dynObj.empty())
2504 return;
2505 std::list<DynamicObject*>::iterator i, next;
2506 for (i = m_dynObj.begin(); i != m_dynObj.end(); i = next)
2508 next = i;
2509 if(spellid == 0 || (*i)->GetSpellId() == spellid)
2511 (*i)->Delete();
2512 next = m_dynObj.erase(i);
2514 else
2515 ++next;
2519 DynamicObject * Unit::GetDynObject(uint32 spellId, uint32 effIndex)
2521 std::list<DynamicObject*>::iterator i;
2522 for (i = m_dynObj.begin(); i != m_dynObj.end(); ++i)
2523 if ((*i)->GetSpellId() == spellId && (*i)->GetEffIndex() == effIndex)
2524 return *i;
2525 return NULL;
2528 void Unit::AddGameObject(GameObject* gameObj)
2530 assert(gameObj && gameObj->GetOwnerGUID()==0);
2531 m_gameObj.push_back(gameObj);
2532 gameObj->SetOwnerGUID(GetGUID());
2535 void Unit::RemoveGameObject(GameObject* gameObj, bool del)
2537 assert(gameObj && gameObj->GetOwnerGUID()==GetGUID());
2538 gameObj->SetOwnerGUID(0);
2539 m_gameObj.remove(gameObj);
2540 if(del)
2541 gameObj->Delete();
2544 void Unit::RemoveGameObject(uint32 spellid, bool del)
2546 if(m_gameObj.empty())
2547 return;
2548 std::list<GameObject*>::iterator i, next;
2549 for (i = m_gameObj.begin(); i != m_gameObj.end(); i = next)
2551 next = i;
2552 if(spellid == 0 || (*i)->GetSpellId() == spellid)
2554 (*i)->SetOwnerGUID(0);
2555 if(del)
2556 (*i)->Delete();
2558 next = m_gameObj.erase(i);
2560 else
2561 ++next;
2565 void Unit::SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, uint8 DamageType,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit)
2567 WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16+31)); // we guess size
2568 data.append(target->GetPackGUID());
2569 data.append(GetPackGUID());
2570 data << SpellID;
2571 data << (Damage-AbsorbedDamage-Resist-Blocked);
2572 data << DamageType; //damagetype
2573 data << AbsorbedDamage; //AbsorbedDamage
2574 data << Resist; //resist
2575 data << (uint8)PhysicalDamage;
2576 data << uint8(0);
2577 data << Blocked; //blocked
2578 data << uint8(CriticalHit ? 2 : 0);
2579 data << uint32(0);
2580 SendMessageToSet( &data, true );
2583 void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, uint32 DamageType, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, uint32 TargetState, uint32 BlockedAmount)
2585 sLog.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
2587 WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16+45)); // we guess size
2588 data << (uint32)HitInfo;
2589 data.append(GetPackGUID());
2590 data.append(target->GetPackGUID());
2591 data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount);
2593 data << (uint8)SwingType;
2594 data << (uint32)DamageType;
2597 data << (float)(Damage-AbsorbDamage-Resist-BlockedAmount);
2598 // still need to double check damaga
2599 data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount);
2600 data << (uint32)AbsorbDamage;
2601 data << (uint32)Resist;
2602 data << (uint32)TargetState;
2604 if( AbsorbDamage == 0 ) //also 0x3E8 = 0x3E8, check when that happens
2605 data << (uint32)0;
2606 else
2607 data << (uint32)-1;
2609 data << (uint32)0;
2610 data << (uint32)BlockedAmount;
2612 SendMessageToSet( &data, true );
2615 void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procflag1, uint32 procflag2)
2617 // this unit's proc trigger damage
2618 AuraList& mProcTriggerDamage = GetAurasByType(SPELL_AURA_PROC_TRIGGER_DAMAGE);
2619 for(AuraList::iterator i = mProcTriggerDamage.begin(), next; i != mProcTriggerDamage.end(); i = next)
2621 next = i; ++next;
2622 uint32 procflag = procflag1;
2624 SpellEntry const *spellProto= (*i)->GetSpellProto();
2626 if(spellProto->procFlags & PROC_FLAG_SHORT_HIT)
2627 procflag &= ~ PROC_FLAG_SHORT_ATTACK;
2628 if(spellProto->procFlags & PROC_FLAG_LONG_HIT)
2629 procflag &= ~ PROC_FLAG_LONG_ATTACK;
2631 if(spellProto->procFlags != 0 && (spellProto->procFlags & procflag) == 0) continue;
2632 uint32 chance = spellProto->procChance;
2633 if (chance > 100) chance = GetWeaponProcChance();
2634 if (chance > rand_chance())
2636 uint32 damage;
2637 if(spellProto->SpellIconID == 25 && spellProto->SpellVisual == 5622)
2638 damage = (*i)->GetModifier()->m_amount*GetAttackTime(BASE_ATTACK)/60/1000;
2639 else damage = (*i)->GetModifier()->m_amount;
2641 if ((*i)->m_procCharges != -1)
2643 (*i)->m_procCharges -= 1;
2644 if((*i)->m_procCharges == 0)
2646 RemoveAurasDueToSpell((*i)->GetId());
2647 next = mProcTriggerDamage.begin();
2650 // iterator `i` can be invalidate later
2652 // do it after m_procCharges, call can remove aura
2653 this->SpellNonMeleeDamageLog(pVictim,spellProto->Id, uint32(damage));
2657 // this unit's proc trigger spell
2658 AuraList& mProcTriggerSpell = GetAurasByType(SPELL_AURA_PROC_TRIGGER_SPELL);
2659 for(AuraList::iterator i = mProcTriggerSpell.begin(), next; i != mProcTriggerSpell.end(); i = next)
2661 next = i; next++;
2662 uint32 procflag = procflag1;
2664 SpellEntry const *spellProto = (*i)->GetSpellProto();
2666 if(spellProto->procFlags & PROC_FLAG_SHORT_HIT)
2667 procflag &= ~ PROC_FLAG_SHORT_ATTACK;
2668 if(spellProto->procFlags & PROC_FLAG_LONG_HIT)
2669 procflag &= ~ PROC_FLAG_LONG_ATTACK;
2671 if(spellProto->procFlags != 0 && (spellProto->procFlags & procflag) == 0) continue;
2672 uint32 chance = spellProto->procChance;
2673 if (chance > 100) chance = GetWeaponProcChance();
2674 if (chance > rand_chance())
2677 uint32 i_spell_eff = (*i)->GetEffIndex();
2679 if ((*i)->m_procCharges != -1)
2681 (*i)->m_procCharges -= 1;
2682 if((*i)->m_procCharges == 0)
2684 RemoveAurasDueToSpell(spellProto->Id);
2685 next = mProcTriggerSpell.begin();
2688 // iterator `i` can be invalidate later
2690 // do it after m_procCharges, call can remove aura
2691 this->CastSpell(pVictim, spellProto->EffectTriggerSpell[i_spell_eff], true);
2695 // this victim's proc trigger damage
2696 AuraList& vProcTriggerDamage = pVictim->GetAurasByType(SPELL_AURA_PROC_TRIGGER_DAMAGE);
2697 for(AuraList::iterator i = vProcTriggerDamage.begin(), next; i != vProcTriggerDamage.end(); i = next)
2699 next = i; next++;
2700 uint32 procflag = procflag2;
2702 SpellEntry const *spellProto = (*i)->GetSpellProto();
2704 if(spellProto->procFlags & PROC_FLAG_BE_SHORT_HIT)
2705 procflag &= ~ PROC_FLAG_BE_SHORT_ATTACK;
2706 if(spellProto->procFlags & PROC_FLAG_BE_LONG_HIT)
2707 procflag &= ~ PROC_FLAG_BE_LONG_ATTACK;
2709 if(spellProto->procFlags != 0 && (spellProto->procFlags & procflag) == 0) continue;
2710 uint32 chance = spellProto->procChance;
2711 if (chance > 100) chance = GetWeaponProcChance();
2712 if (chance > rand_chance())
2714 uint32 damage = uint32((*i)->GetModifier()->m_amount);
2715 // Special for judgement of seal
2716 if(spellProto->SpellVisual == 7395 && spellProto->SpellIconID == 278)
2718 damage = pVictim->CalculateDamage(BASE_ATTACK);
2721 if ((*i)->m_procCharges != -1)
2723 (*i)->m_procCharges -= 1;
2724 if((*i)->m_procCharges == 0)
2726 pVictim->RemoveAurasDueToSpell(spellProto->Id);
2727 next = vProcTriggerDamage.begin();
2730 // iterator `i` can be invalidate later
2732 // do it after m_procCharges, call can remove aura
2733 pVictim->SpellNonMeleeDamageLog(this,spellProto->Id, damage);
2737 // this victims's proc trigger spell
2738 AuraList& vProcTriggerSpell = pVictim->GetAurasByType(SPELL_AURA_PROC_TRIGGER_SPELL);
2739 for(AuraList::iterator i = vProcTriggerSpell.begin(), next; i != vProcTriggerSpell.end(); i = next)
2741 next = i; next++;
2742 uint32 procflag = procflag2;
2743 SpellEntry const *spellProto = (*i)->GetSpellProto();
2745 if(spellProto->procFlags & PROC_FLAG_BE_SHORT_HIT)
2746 procflag &= ~ PROC_FLAG_BE_SHORT_ATTACK;
2747 if(spellProto->procFlags & PROC_FLAG_BE_LONG_HIT)
2748 procflag &= ~ PROC_FLAG_BE_LONG_ATTACK;
2750 if(spellProto->procFlags != 0 && (spellProto->procFlags & procflag) == 0) continue;
2751 uint32 chance = spellProto->procChance;
2752 if (chance > 100) chance = GetWeaponProcChance();
2753 if (chance > rand_chance())
2755 uint32 i_spell_eff = (*i)->GetEffIndex();
2756 int32 i_spell_mod_amount = (*i)->GetModifier()->m_amount;
2758 if ((*i)->m_procCharges != -1)
2760 (*i)->m_procCharges -= 1;
2761 if((*i)->m_procCharges == 0)
2763 pVictim->RemoveAurasDueToSpell((*i)->GetId());
2764 next = vProcTriggerSpell.begin();
2767 // iterator `i` can be invalidate later
2769 // do it after m_procCharges, call can remove aura
2770 pVictim->CastSpell(this, spellProto->EffectTriggerSpell[i_spell_eff], true);
2772 // Special for judgement of seal
2773 if( spellProto->SpellFamilyFlags & (1<<19) )
2775 if(spellProto->SpellIconID == 206)
2777 if(getPowerType() == POWER_MANA)
2779 uint32 mana = 0;
2780 switch(objmgr.GetSpellRank(spellProto->Id))
2782 case 1:mana = 33;break;
2783 case 2:mana = 46;break;
2784 case 3:mana = 59;break;
2785 default:break;
2787 ModifyPower(POWER_MANA,mana);
2788 SendHealSpellOnPlayerPet(this,spellProto->Id,mana,POWER_MANA);
2791 if(spellProto->SpellIconID == 299)
2793 uint32 health = 0;
2794 switch(objmgr.GetSpellRank(spellProto->Id))
2796 case 1:health = 25;break;
2797 case 2:health = 34;break;
2798 case 3:health = 49;break;
2799 case 4:health = 61;break;
2800 default:break;
2802 ModifyHealth(health);
2803 SendHealSpellOnPlayer(this,spellProto->Id,health);
2806 // Special for Static Electricity
2807 if(spellProto->SpellFamilyName == 11 && (spellProto->SpellFamilyFlags & (1<<10)))
2809 pVictim->SpellNonMeleeDamageLog(this,spellProto->Id,i_spell_mod_amount);
2815 void Unit::setPowerType(Powers new_powertype)
2817 uint32 tem_bytes_0 = GetUInt32Value(UNIT_FIELD_BYTES_0);
2818 SetUInt32Value(UNIT_FIELD_BYTES_0,((tem_bytes_0<<8)>>8) + (uint32(new_powertype)<<24));
2819 switch(new_powertype)
2821 default:
2822 case POWER_MANA:
2823 break;
2824 case POWER_RAGE:
2825 SetMaxPower(POWER_RAGE,1000);
2826 SetPower( POWER_RAGE,0);
2827 break;
2828 case POWER_FOCUS:
2829 SetMaxPower(POWER_FOCUS,100);
2830 SetPower( POWER_FOCUS,100);
2831 break;
2832 case POWER_ENERGY:
2833 SetMaxPower(POWER_ENERGY,100);
2834 SetPower( POWER_ENERGY,100);
2835 break;
2836 case POWER_HAPPINESS:
2837 SetMaxPower(POWER_HAPPINESS,1000000);
2838 SetPower(POWER_HAPPINESS,1000000);
2839 break;
2843 FactionTemplateEntry const* Unit::getFactionTemplateEntry() const
2845 FactionTemplateEntry const* entry = sFactionTemplateStore.LookupEntry(getFaction());
2846 if(!entry)
2848 static uint64 guid = 0; // prevent repeating spam same faction problem
2850 if(GetGUID() != guid)
2852 if(GetTypeId() == TYPEID_PLAYER)
2853 sLog.outError("Player %s have invalide faction (faction template id) #%u", ((Player*)this)->GetName(), getFaction());
2854 else
2855 sLog.outError("Creature (template id: %u) have invalide faction (faction template id) #%u", ((Creature*)this)->GetCreatureInfo()->Entry, getFaction());
2856 guid = GetGUID();
2859 return entry;
2862 bool Unit::IsHostileToAll() const
2864 FactionTemplateResolver my_faction = getFactionTemplateEntry();
2866 return my_faction.IsHostileToAll();
2869 bool Unit::IsHostileTo(Unit const* unit) const
2871 // test pet/charm masters instead pers/charmeds
2872 Unit const* testerOwner = GetOwner();
2873 Unit const* targetOwner = unit->GetOwner();
2875 Unit const* tester = testerOwner ? testerOwner : this;
2876 Unit const* target = targetOwner ? targetOwner : unit;
2878 // special cases (Duel)
2879 if(tester->GetTypeId()==TYPEID_PLAYER && target->GetTypeId()==TYPEID_PLAYER)
2881 // Duel
2882 if(((Player const*)tester)->duel && ((Player const*)tester)->duel->opponent == target)
2883 return true;
2885 //= PvP states
2886 // Green/Blue (can't attack)
2887 if(((Player*)tester)->GetTeam()==((Player*)target)->GetTeam())
2888 return false;
2890 // Red (can attack) if true, Blue/Yellow (can't attack) in another case
2891 return ((Player*)tester)->IsPvP() && ((Player*)target)->IsPvP();
2894 // common case (CvC,PvC, CvP)
2895 FactionTemplateResolver tester_faction = tester->getFactionTemplateEntry();
2896 FactionTemplateResolver target_faction = target->getFactionTemplateEntry();
2898 return tester_faction.IsHostileTo(target_faction);
2901 bool Unit::IsFriendlyTo(Unit const* unit) const
2903 // test pet/charm masters instead pers/charmeds
2904 Unit const* testerOwner = GetOwner();
2905 Unit const* targetOwner = unit->GetOwner();
2907 Unit const* tester = testerOwner ? testerOwner : this;
2908 Unit const* target = targetOwner ? targetOwner : unit;
2910 // special cases (Duel)
2911 if(tester->GetTypeId()==TYPEID_PLAYER && target->GetTypeId()==TYPEID_PLAYER)
2913 // Duel
2914 if(((Player const*)tester)->duel && ((Player const*)tester)->duel->opponent == target)
2915 return false;
2917 //= PvP states
2918 // Green/Blue (non-attackable)
2919 if(((Player*)tester)->GetTeam()==((Player*)target)->GetTeam())
2920 return true;
2922 // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable)
2923 return !((Player*)target)->IsPvP();
2926 // common case (CvC, PvC, CvP)
2927 FactionTemplateResolver tester_faction = tester->getFactionTemplateEntry();
2928 FactionTemplateResolver target_faction = target->getFactionTemplateEntry();
2930 return tester_faction.IsFriendlyTo(target_faction);
2933 bool Unit::IsNeutralToAll() const
2935 FactionTemplateResolver my_faction = getFactionTemplateEntry();
2937 return my_faction.IsNeutralToAll();
2940 bool Unit::Attack(Unit *victim)
2942 if(victim == this)
2943 return false;
2945 // player don't must attack in mount state
2946 if(GetTypeId()==TYPEID_PLAYER && IsMounted())
2947 return false;
2949 if (m_attacking)
2951 if (m_attacking == victim)
2952 return false;
2953 AttackStop();
2955 addUnitState(UNIT_STAT_ATTACKING);
2956 if(GetTypeId()==TYPEID_UNIT)
2957 SetInCombat();
2958 m_attacking = victim;
2959 m_attacking->_addAttacker(this);
2961 if( GetTypeId()==TYPEID_UNIT && !((Creature*)this)->isPet() )
2963 ((Creature*)this)->CallAssistence();
2965 //if(!isAttackReady(BASE_ATTACK))
2966 //resetAttackTimer(BASE_ATTACK);
2968 // delay offhand weapon attack to next attack time
2969 if(haveOffhandWeapon())
2970 resetAttackTimer(OFF_ATTACK);
2972 return true;
2975 bool Unit::AttackStop()
2977 if (!m_attacking)
2978 return false;
2980 Unit* victim = m_attacking;
2982 m_attacking->_removeAttacker(this);
2983 m_attacking = NULL;
2984 clearUnitState(UNIT_STAT_ATTACKING);
2985 if(GetTypeId()!=TYPEID_PLAYER && m_attackers.empty())
2986 ClearInCombat();
2988 if(m_currentMeleeSpell)
2989 m_currentMeleeSpell->cancel();
2991 if( GetTypeId()==TYPEID_UNIT )
2993 ((Creature*)this)->SetNoCallAssistence(false);
2996 SendAttackStop(victim);
2998 return true;
3001 bool Unit::isInCombatWithPlayer() const
3003 if(getVictim() && getVictim()->GetTypeId() == TYPEID_PLAYER)
3004 return true;
3006 for(AttackerSet::const_iterator i = m_attackers.begin(); i != m_attackers.end(); ++i)
3008 if((*i)->GetTypeId() == TYPEID_PLAYER) return true;
3010 return false;
3013 void Unit::RemoveAllAttackers()
3015 while (m_attackers.size() != 0)
3017 AttackerSet::iterator iter = m_attackers.begin();
3018 if(!(*iter)->AttackStop())
3020 sLog.outError("WORLD: Unit has an attacker that isnt attacking it!");
3021 m_attackers.erase(iter);
3026 void Unit::SetStateFlag(uint32 index, uint32 newFlag )
3028 index |= newFlag;
3031 void Unit::RemoveStateFlag(uint32 index, uint32 oldFlag )
3033 index &= ~ oldFlag;
3036 Unit *Unit::GetOwner() const
3038 uint64 ownerid = GetOwnerGUID();
3039 if(!ownerid)
3040 return NULL;
3041 return ObjectAccessor::Instance().GetUnit(*this, ownerid);
3044 Pet* Unit::GetPet() const
3046 uint64 pet_guid = GetPetGUID();
3047 if(pet_guid)
3049 Creature* pet = ObjectAccessor::Instance().GetCreature(*this, pet_guid);
3050 if(!pet||!pet->isPet())
3052 sLog.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid));
3053 const_cast<Unit*>(this)->SetPet(0);
3054 return NULL;
3056 return (Pet*)pet;
3059 return NULL;
3062 Creature* Unit::GetCharm() const
3064 uint64 charm_guid = GetCharmGUID();
3065 if(charm_guid)
3067 Creature* pet = ObjectAccessor::Instance().GetCreature(*this, charm_guid);
3068 if(!pet)
3070 sLog.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid));
3071 const_cast<Unit*>(this)->SetCharm(0);
3073 return pet;
3075 else
3076 return NULL;
3079 void Unit::SetPet(Pet* pet)
3081 SetUInt64Value(UNIT_FIELD_SUMMON,pet ? pet->GetGUID() : 0);
3083 if(pet)
3085 for(int i = 0; i < MAX_MOVE_TYPE; ++i)
3087 pet->SetSpeed(UnitMoveType(i),m_speed_rate[i],true);
3092 void Unit::SetCharm(Creature* charmed)
3094 SetUInt64Value(UNIT_FIELD_CHARM,charmed ? charmed->GetGUID() : 0);
3097 void Unit::UnsummonTotem(int8 slot)
3099 for (int8 i = 0; i < 4; i++)
3101 if (i != slot && slot != -1) continue;
3102 Creature *OldTotem = ObjectAccessor::Instance().GetCreature(*this, m_TotemSlot[i]);
3103 if (!OldTotem || !OldTotem->isTotem()) continue;
3104 ((Totem*)OldTotem)->UnSummon();
3108 void Unit::SendHealSpellOnPlayer(Unit *pVictim, uint32 SpellID, uint32 Damage, bool critical)
3110 // we guess size
3111 WorldPacket data(SMSG_HEALSPELL_ON_PLAYER_OBSOLETE, (9+16));
3112 data.append(pVictim->GetPackGUID());
3113 data.append(GetPackGUID());
3114 data << SpellID;
3115 data << Damage;
3116 data << uint8(critical ? 1 : 0);
3117 SendMessageToSet(&data, true);
3120 void Unit::SendHealSpellOnPlayerPet(Unit *pVictim, uint32 SpellID, uint32 Damage,Powers powertype, bool critical)
3122 WorldPacket data(SMSG_HEALSPELL_ON_PLAYERS_PET_OBSOLETE, (13+8));
3123 data.append(pVictim->GetPackGUID());
3124 data.append(GetPackGUID());
3125 data << SpellID;
3126 data << uint32(powertype);
3127 data << Damage;
3128 data << uint8(critical ? 1 : 0);
3129 SendMessageToSet(&data, true);
3132 uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 pdamage)
3134 if(!spellProto || !pVictim) return pdamage;
3135 //If m_immuneToDamage type contain this damage type, IMMUNE damage.
3136 for (SpellImmuneList::iterator itr = pVictim->m_spellImmune[IMMUNITY_DAMAGE].begin(), next; itr != pVictim->m_spellImmune[IMMUNITY_DAMAGE].end(); itr = next)
3138 next = itr;
3139 next++;
3140 if((*itr)->type & uint32(1<<spellProto->School))
3142 pdamage = 0;
3143 break;
3146 //If m_immuneToSchool type contain this school type, IMMUNE damage.
3147 for (SpellImmuneList::iterator itr = pVictim->m_spellImmune[IMMUNITY_SCHOOL].begin(), next; itr != pVictim->m_spellImmune[IMMUNITY_SCHOOL].end(); itr = next)
3149 next = itr;
3150 next++;
3151 if((*itr)->type & uint32(1<<spellProto->School))
3153 pdamage = 0;
3154 break;
3157 if(pdamage == 0)
3158 return pdamage;
3159 CreatureInfo const *cinfo = NULL;
3160 if(pVictim->GetTypeId() != TYPEID_PLAYER)
3161 cinfo = ((Creature*)pVictim)->GetCreatureInfo();
3163 // Damage Done
3164 int32 AdvertisedBenefit = 0;
3165 uint32 PenaltyFactor = 0;
3166 uint32 CastingTime = GetCastTime(sCastTimesStore.LookupEntry(spellProto->CastingTimeIndex));
3167 if (CastingTime > 3500) CastingTime = 3500;
3168 if (CastingTime < 1500) CastingTime = 1500;
3170 AuraList& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
3171 for(AuraList::iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
3172 if(cinfo && (cinfo->type & (*i)->GetModifier()->m_miscvalue) != 0)
3173 AdvertisedBenefit += (*i)->GetModifier()->m_amount;
3175 AuraList& mDamageDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE);
3176 for(AuraList::iterator i = mDamageDone.begin();i != mDamageDone.end(); ++i)
3177 if(((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0)
3178 AdvertisedBenefit += (*i)->GetModifier()->m_amount;
3180 AuraList& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
3181 for(AuraList::iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
3182 if(((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0)
3183 AdvertisedBenefit += (*i)->GetModifier()->m_amount;
3185 int32 TotalMod = 0;
3186 AuraList& mModDamagePercentDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
3187 for(AuraList::iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
3188 if((((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0) && (spellProto->School != 0))
3189 TotalMod *= ((int32)((*i)->GetModifier()->m_amount) + 100)/100;
3191 // TODO - fix PenaltyFactor and complete the formula from the wiki
3192 float ActualBenefit = (float)AdvertisedBenefit * ((float)CastingTime / 3500) * (float)(100 - PenaltyFactor) / 100;
3193 pdamage = (int32)(pdamage*TotalMod)/100 + pdamage;
3194 pdamage = uint32(pdamage+ActualBenefit);
3196 return pdamage;
3199 bool Unit::SpellCriticalBonus(SpellEntry const *spellProto, int32 *peffect)
3201 int32 critchance = m_baseSpellCritChance + int32(GetStat(STAT_INTELLECT)/100-1);
3202 critchance = critchance > 0 ? critchance :0;
3204 if (GetTypeId() == TYPEID_PLAYER)
3205 ((Player*)this)->ApplySpellMod(spellProto->Id, SPELLMOD_CRITICAL_CHANCE, critchance);
3207 AuraList& mSpellCritSchool = GetAurasByType(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL);
3208 for(AuraList::iterator i = mSpellCritSchool.begin(); i != mSpellCritSchool.end(); ++i)
3209 if((*i)->GetModifier()->m_miscvalue == -2 || ((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0)
3210 critchance += (*i)->GetModifier()->m_amount;
3212 critchance = critchance > 0 ? critchance :0;
3213 if(uint32(critchance) >= urand(0,100))
3215 int32 critbonus = *peffect / 2;
3216 if (GetTypeId() == TYPEID_PLAYER)
3217 ((Player*)this)->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, critbonus);
3218 *peffect += critbonus;
3219 return true;
3221 return false;
3224 uint32 Unit::SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount)
3226 // Healing Done
3227 int32 AdvertisedBenefit = 0;
3228 uint32 PenaltyFactor = 0;
3229 uint32 CastingTime = GetCastTime(sCastTimesStore.LookupEntry(spellProto->CastingTimeIndex));
3230 if (CastingTime > 3500) CastingTime = 3500;
3231 if (CastingTime < 1500) CastingTime = 1500;
3233 AuraList& mHealingDone = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE);
3234 for(AuraList::iterator i = mHealingDone.begin();i != mHealingDone.end(); ++i)
3235 if(((*i)->GetModifier()->m_miscvalue & (int32)(1<<spellProto->School)) != 0)
3236 AdvertisedBenefit += (*i)->GetModifier()->m_amount;
3238 // TODO - fix PenaltyFactor and complete the formula from the wiki
3239 float ActualBenefit = (float)AdvertisedBenefit * ((float)CastingTime / 3500) * (float)(100 - PenaltyFactor) / 100;
3240 healamount += uint32(ActualBenefit);
3242 // TODO: check for ALL/SPELLS type
3243 AuraList& mHealingPct = GetAurasByType(SPELL_AURA_MOD_HEALING_PCT);
3244 for(AuraList::iterator i = mHealingPct.begin();i != mHealingPct.end(); ++i)
3245 healamount *= uint32((100.0f + (*i)->GetModifier()->m_amount) / 100.0f);
3246 AuraList& mHealingDonePct = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT);
3247 for(AuraList::iterator i = mHealingDonePct.begin();i != mHealingDonePct.end(); ++i)
3248 healamount *= uint32((100.0f + (*i)->GetModifier()->m_amount) / 100.0f);
3250 healamount += m_AuraModifiers[SPELL_AURA_MOD_HEALING];
3251 if (int32(healamount) < 0) healamount = 0;
3253 return healamount;
3256 void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage)
3258 if(!pVictim) return;
3260 //If m_immuneToDamage type contain magic, IMMUNE damage.
3261 for (SpellImmuneList::iterator itr = pVictim->m_spellImmune[IMMUNITY_DAMAGE].begin(), next; itr != pVictim->m_spellImmune[IMMUNITY_DAMAGE].end(); itr = next)
3263 if((*itr)->type & IMMUNE_DAMAGE_PHYSICAL)
3265 *pdamage = 0;
3266 break;
3269 //If m_immuneToSchool type contain this school type, IMMUNE damage.
3270 for (SpellImmuneList::iterator itr = pVictim->m_spellImmune[IMMUNITY_SCHOOL].begin(); itr != pVictim->m_spellImmune[IMMUNITY_SCHOOL].end(); ++itr)
3272 if((*itr)->type & IMMUNE_SCHOOL_PHYSICAL)
3274 *pdamage = 0;
3275 break;
3279 if(*pdamage == 0)
3280 return;
3282 CreatureInfo const *cinfo = NULL;
3283 if(pVictim->GetTypeId() != TYPEID_PLAYER)
3284 cinfo = ((Creature*)pVictim)->GetCreatureInfo();
3286 if(GetTypeId() != TYPEID_PLAYER && ((Creature*)this)->isPet())
3288 if(getPowerType() == POWER_FOCUS)
3290 uint32 happiness = GetPower(POWER_HAPPINESS);
3291 if(happiness>=750000)
3292 *pdamage = uint32(*pdamage * 1.25);
3293 else if(happiness>=500000)
3294 *pdamage = uint32(*pdamage * 1.0);
3295 else *pdamage = uint32(*pdamage * 0.75);
3299 // bonus result can be negative
3300 int32 damage = *pdamage;
3302 AuraList& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
3303 for(AuraList::iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
3304 if(cinfo && cinfo->type == uint32((*i)->GetModifier()->m_miscvalue))
3305 damage += (*i)->GetModifier()->m_amount;
3307 AuraList& mDamageDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE);
3308 for(AuraList::iterator i = mDamageDone.begin();i != mDamageDone.end(); ++i)
3309 if((*i)->GetModifier()->m_miscvalue & IMMUNE_SCHOOL_PHYSICAL)
3311 // old one
3312 //damage += (*i)->GetModifier()->m_amount;
3313 int32 _damage = (*pdamage + (*i)->GetModifier()->m_amount);
3314 if (_damage < 0)
3315 *pdamage = 0;
3316 else
3317 *pdamage = _damage;
3320 AuraList& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
3321 for(AuraList::iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
3322 if((*i)->GetModifier()->m_miscvalue & IMMUNE_SCHOOL_PHYSICAL)
3323 damage += (*i)->GetModifier()->m_amount;
3325 AuraList& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_CREATURE_ATTACK_POWER);
3326 for(AuraList::iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i)
3327 if(cinfo && (cinfo->type & uint32((*i)->GetModifier()->m_miscvalue)) != 0)
3328 damage += uint32((*i)->GetModifier()->m_amount/14.0f * GetAttackTime(BASE_ATTACK)/1000);
3330 // bonus result can be negative
3331 *pdamage = damage < 0 ? 0 : damage;
3333 *pdamage = uint32(*pdamage * (m_modDamagePCT+100)/100);
3336 void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply)
3338 if (apply)
3340 for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(), next; itr != m_spellImmune[op].end(); itr = next)
3342 next = itr; next++;
3343 if((*itr)->type == type)
3345 m_spellImmune[op].erase(itr);
3346 next = m_spellImmune[op].begin();
3349 SpellImmune *Immune = new SpellImmune();
3350 Immune->spellId = spellId;
3351 Immune->type = type;
3352 m_spellImmune[op].push_back(Immune);
3354 else
3356 for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(); itr != m_spellImmune[op].end(); ++itr)
3358 if((*itr)->spellId == spellId)
3360 m_spellImmune[op].erase(itr);
3361 break;
3368 uint32 Unit::GetWeaponProcChance() const
3370 // normalized proc chance for weapon attack speed
3371 if(isAttackReady(BASE_ATTACK))
3372 return uint32(GetAttackTime(BASE_ATTACK) * 1.82 / 1000);
3373 else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK))
3374 return uint32(GetAttackTime(OFF_ATTACK) * 1.82 / 1000);
3375 return 0;
3378 void Unit::Mount(uint32 mount, bool taxi)
3380 if(!mount)
3381 return;
3383 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, mount);
3385 uint32 flag = UNIT_FLAG_MOUNT;
3386 if(taxi)
3387 flag |= UNIT_FLAG_DISABLE_MOVE;
3389 SetFlag( UNIT_FIELD_FLAGS, flag );
3392 void Unit::Unmount()
3394 if(!IsMounted())
3395 return;
3397 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0);
3398 RemoveFlag( UNIT_FIELD_FLAGS ,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_MOUNT );
3401 void Unit::SetInCombat()
3403 m_CombatTimer = 5000;
3404 SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
3407 void Unit::ClearInCombat()
3409 m_CombatTimer = 0;
3410 RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
3413 bool Unit::isTargetableForAttack()
3415 if (GetTypeId()==TYPEID_PLAYER && ((Player *)this)->isGameMaster())
3416 return false;
3417 return isAlive() && !isInFlight() /*&& !isStealth()*/;
3420 void Unit::ModifyHealth(int32 dVal)
3422 if(dVal==0)
3423 return;
3425 uint32 curHealth = GetHealth();
3427 int32 val = dVal + curHealth;
3428 if(val <= 0)
3430 SetHealth(0);
3431 return;
3434 uint32 maxHealth = GetMaxHealth();
3436 if(uint32(val) < maxHealth)
3437 SetHealth(val);
3438 else
3439 if(curHealth!=maxHealth)
3440 SetHealth(maxHealth);
3443 void Unit::ModifyPower(Powers power, int32 dVal)
3445 if(dVal==0)
3446 return;
3448 uint32 curPower = GetPower(power);
3450 int32 val = dVal + curPower;
3451 if(val <= 0)
3453 SetPower(power,0);
3454 return;
3457 uint32 maxPower = GetMaxPower(power);
3459 if(uint32(val) < maxPower)
3460 SetPower(power,val);
3461 else
3462 if(curPower != maxPower)
3463 SetPower(power,maxPower);
3466 bool Unit::isVisibleFor(Unit* u, bool detect)
3468 // Visible units, always are visible for all pjs
3469 if (m_Visibility == VISIBILITY_ON)
3470 return true;
3472 // GMs are visible for higher gms (or players are visible for gms)
3473 if (u->GetTypeId() == TYPEID_PLAYER && ((Player *)u)->isGameMaster())
3474 return (GetTypeId() == TYPEID_PLAYER && ((Player *)this)->GetSession()->GetSecurity() <= ((Player *)u)->GetSession()->GetSecurity());
3476 // non faction visibility non-breakable for non-GMs
3477 if (m_Visibility == VISIBILITY_OFF)
3478 return false;
3480 // Units far than MAX_DIST_INVISIBLE, that are not gms and are stealth, are not visibles too
3481 if (!this->IsWithinDist(u,MAX_DIST_INVISIBLE_UNIT))
3482 return false;
3484 // Stealth not hostile units, not visibles (except Player-with-Player case)
3485 if (!u->IsHostileTo(this))
3487 // player autodetect other player with stealth only if he in same group or raid or same team (raid/team case dependent from conf setting)
3488 if(GetTypeId()==TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER)
3490 if(((Player*)this)->IsGroupVisibleFor(((Player*)u)))
3491 return true;
3493 // else apply same rules as for hostile case (detecting check)
3495 else
3496 return true;
3499 // if in non-detect mode then invisible for unit
3500 if(!detect)
3501 return false;
3503 bool IsVisible = true;
3504 bool notInFront = u->isInFront(this, MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT) ? 0 : 1;
3505 float Distance = sqrt(GetDistanceSq(u));
3506 float prob = 0;
3508 // Function for detection (can be improved)
3509 // Take into account that this function is executed every x secs, so prob must be low for right working
3511 int8 x = u->getLevel() + (m_detectStealth / 5) - (m_stealthvalue / 5) + 59;
3512 if (x<0) x = 0;
3513 float AverageDist = 1 - 0.11016949*x + 0.00301637*x*x; //at this distance, the detector has to be a 15% prob of detect
3514 if (AverageDist < 1) AverageDist = 1;
3515 if (Distance > AverageDist)
3516 //prob between 10% and 0%
3517 prob = (AverageDist-200+9*Distance)/(AverageDist-20);
3518 else
3519 prob = 75 - (60/AverageDist)*Distance; //prob between 15% and 75% (75% max prob)
3520 if (notInFront)
3521 prob = prob/100;
3522 if (prob < 0.1)
3523 prob = 0.1; //min prob of detect is 0.1
3525 if (rand_chance() > prob)
3526 IsVisible = false;
3527 else
3528 IsVisible = true;
3530 return IsVisible && ( Distance <= MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT) ;
3533 void Unit::SetVisibility(UnitVisibility x)
3535 m_Visibility = x;
3537 switch (x)
3539 case VISIBILITY_ON:
3540 m_UpdateVisibility = VISIBLE_SET_VISIBLE;
3541 break;
3542 case VISIBILITY_OFF:
3543 m_UpdateVisibility = VISIBLE_SET_INVISIBLE;
3544 break;
3545 case VISIBILITY_GROUP:
3546 m_UpdateVisibility = VISIBLE_SET_INVISIBLE_FOR_GROUP;
3547 break;
3549 if(GetTypeId() == TYPEID_PLAYER)
3551 Map *m = MapManager::Instance().GetMap(GetMapId());
3552 m->PlayerRelocation((Player *)this,GetPositionX(),GetPositionY(),
3553 GetPositionZ(),GetOrientation(), true);
3556 m_UpdateVisibility = VISIBLE_NOCHANGES;
3559 float Unit::GetSpeed( UnitMoveType mtype ) const
3561 return m_speed_rate[mtype]*baseMoveSpeed[mtype];
3564 void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced)
3566 m_speed_rate[mtype] = 1.0f;
3567 ApplySpeedMod(mtype, rate, forced, true);
3570 void Unit::ApplySpeedMod(UnitMoveType mtype, float rate, bool forced, bool apply)
3572 WorldPacket data;
3574 if(apply)
3575 m_speed_rate[mtype] *= rate;
3576 else
3577 m_speed_rate[mtype] /= rate;
3579 switch(mtype)
3581 case MOVE_WALK:
3582 if(forced) { data.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE, 16); }
3583 else { data.Initialize(MSG_MOVE_SET_WALK_SPEED, 16); }
3584 break;
3585 case MOVE_RUN:
3586 if(forced) { data.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE, 16); }
3587 else { data.Initialize(MSG_MOVE_SET_RUN_SPEED, 16); }
3588 break;
3589 case MOVE_WALKBACK:
3590 if(forced) { data.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE, 16); }
3591 else { data.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED, 16); }
3592 break;
3593 case MOVE_SWIM:
3594 if(forced) { data.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE, 16); }
3595 else { data.Initialize(MSG_MOVE_SET_SWIM_SPEED, 16); }
3596 break;
3597 case MOVE_SWIMBACK:
3598 data.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED, 16);
3599 break;
3600 case MOVE_TURN:
3601 return; // ignore
3602 default:
3603 sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype);
3604 return;
3607 data.append(GetPackGUID());
3608 data << (uint32)0;
3609 data << float(GetSpeed(mtype));
3610 SendMessageToSet( &data, true );
3612 if(Pet* pet = GetPet())
3613 pet->SetSpeed(mtype,m_speed_rate[mtype],forced);
3616 void Unit::SetHover(bool on)
3618 if(on)
3620 SpellEntry const *sInfo = sSpellStore.LookupEntry(11010);
3621 if(!sInfo)
3622 return;
3624 Spell spell(this, sInfo, true,0);
3625 SpellCastTargets targets;
3626 targets.setUnitTarget(this);
3627 targets.m_targetMask = TARGET_FLAG_SELF;
3628 spell.prepare(&targets);
3630 else
3632 RemoveAurasDueToSpell(11010);
3636 void Unit::setDeathState(DeathState s)
3638 if (s != ALIVE)
3640 CombatStop();
3642 if(m_currentSpell)
3643 m_currentSpell->cancel();
3646 if (s == JUST_DIED)
3648 RemoveAllAurasOnDeath();
3649 UnsummonTotem();
3651 if (m_deathState != ALIVE && s == ALIVE)
3653 _ApplyAllAuraMods();
3655 m_deathState = s;