[1852] Applied MaNGOS coding style (see [source:trunk/bcpp.cfg bcpp.cfg]).
[mangos-git.git] / src / game / Unit.cpp
blobec260b3d8b96f245a5a968da2c8bfaf4eb2ceea0
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 "Stats.h"
32 #include "Group.h"
33 #include "SpellAuras.h"
34 #include "MapManager.h"
35 #include "ObjectAccessor.h"
36 #include "CreatureAI.h"
37 #include "Formulas.h"
38 #include "Pet.h"
39 #include "Util.h"
41 #include <math.h>
43 Unit::Unit() : Object()
45 m_objectType |= TYPE_UNIT;
46 m_objectTypeId = TYPEID_UNIT;
48 m_attackTimer = 0;
50 m_state = 0;
51 m_form = 0;
52 m_deathState = ALIVE;
53 m_currentSpell = NULL;
54 m_currentMeleeSpell = NULL;
55 m_addDmgOnce = 0;
56 m_TotemSlot1 = m_TotemSlot2 = m_TotemSlot3 = m_TotemSlot4 = 0;
57 //m_Aura = NULL;
58 //m_AurasCheck = 2000;
59 //m_removeAuraTimer = 4;
60 //tmpAura = NULL;
61 m_silenced = false;
62 waterbreath = false;
64 m_immuneToMechanic = 0;
65 m_immuneToEffect = 0;
66 m_immuneToState = 0;
67 m_immuneToSchool = 0;
68 m_immuneToDmg = 0;
69 m_immuneToDispel = 0;
70 m_detectStealth = 0;
71 m_stealthvalue = 0;
72 m_transform = 0;
73 m_ShapeShiftForm = 0;
75 for (int i = 0; i < TOTAL_AURAS; i++)
76 m_AuraModifiers[i] = -1;
78 m_attacking = NULL;
79 m_modDamagePCT = 0;
80 m_RegenPCT = 0;
81 m_modHitChance = 0;
82 m_modSpellHitChance = 0;
83 m_baseSpellCritChance = 5;
84 m_spellCritSchool.clear();
85 m_reflectSpellSchool.clear();
86 m_scAuras.clear();
87 m_damageDoneCreature.clear();
90 Unit::~Unit()
94 void Unit::Update( uint32 p_time )
96 /*if(p_time > m_AurasCheck)
98 m_AurasCheck = 2000;
99 _UpdateAura();
100 }else
101 m_AurasCheck -= p_time;*/
103 _UpdateSpells( p_time );
104 _UpdateHostil( p_time );
106 if(m_attackTimer > 0)
108 if(p_time >= m_attackTimer)
109 m_attackTimer = 0;
110 else
111 m_attackTimer -= p_time;
115 void Unit::SendMoveToPacket(float x, float y, float z, bool run)
117 float dx = x - GetPositionX();
118 float dy = y - GetPositionY();
119 float dz = z - GetPositionZ();
120 float dist = ((dx*dx) + (dy*dy) + (dz*dz));
121 if(dist<0)
122 dist = 0;
123 else
124 dist = ::sqrt(dist);
125 double speed = GetSpeed(run ? MOVE_RUN : MOVE_WALK);
126 if(speed<=0)
127 speed = 2.5f;
128 speed *= 0.001f;
129 uint32 time = static_cast<uint32>(dist / speed + 0.5);
130 //float orientation = (float)atan2((double)dy, (double)dx);
131 SendMonsterMove(x,y,z,false,run,time);
135 void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, bool Walkback, bool Run, uint32 Time)
137 WorldPacket data;
138 data.Initialize( SMSG_MONSTER_MOVE );
139 data << uint8(0xFF) << GetGUID();
140 // Point A, starting location
141 data << GetPositionX() << GetPositionY() << GetPositionZ();
142 // little trick related to orientation
143 data << (uint32)((*((uint32*)&GetOrientation())) & 0x30000000);
144 data << uint8(Walkback); // walkback when walking from A to B
145 data << uint32(Run ? 0x00000100 : 0x00000000); // flags
146 /* Flags:
147 512: Floating, moving without walking/running
149 data << Time; // Time in between points
150 data << uint32(1); // 1 single waypoint
151 data << NewPosX << NewPosY << NewPosZ; // the single waypoint Point B
152 WPAssert( data.size() == 50 );
153 SendMessageToSet( &data, true );
156 void Unit::setAttackTimer(uint32 time, bool rangeattack)
158 if(time)
159 m_attackTimer = time;
160 else
162 if(rangeattack)
164 if (GetTypeId() == TYPEID_PLAYER)
166 m_attackTimer = GetUInt32Value(UNIT_FIELD_RANGEDATTACKTIME);
169 else
171 if (GetTypeId() == TYPEID_PLAYER)
173 m_attackTimer = GetUInt32Value(UNIT_FIELD_BASEATTACKTIME);
176 m_attackTimer = (m_attackTimer >= 200) ? m_attackTimer : 2000;
180 bool Unit::canReachWithAttack(Unit *pVictim) const
182 assert(pVictim);
183 float reach = GetFloatValue(UNIT_FIELD_COMBATREACH);
184 if( reach <= 0.0f )
185 reach = 1.0f;
186 float distance = GetDistanceSq(pVictim);
188 return ( distance <= reach * reach );
191 void Unit::RemoveSpellsCausingAura(uint32 auraType)
193 AuraMap::iterator iter, next;
194 for (iter = m_Auras.begin(); iter != m_Auras.end(); iter = next)
196 next = iter;
197 ++next;
199 if ((*iter).second)
201 if (((*iter).second)->GetModifier()->m_auraname == auraType)
203 uint32 spellId = ((*iter).second)->GetId();
204 RemoveAurasDueToSpell(spellId);
205 if (!m_Auras.empty())
206 next = m_Auras.begin();
207 else
208 return;
214 bool Unit::HasAuraType(uint32 auraType) const
216 return (m_AuraModifiers[auraType] != -1);
219 void Unit::DealDamage(Unit *pVictim, uint32 damage, uint32 procFlag, bool durabilityLoss)
221 if (!pVictim->isAlive()) return;
223 if(isStealth())
224 RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
226 if(pVictim->GetTypeId() != TYPEID_PLAYER)
228 //pVictim->SetInFront(this);
229 // no loot,xp,health if type 8 /critters/
230 if ( ((Creature*)pVictim)->GetCreatureInfo()->type == 8)
232 pVictim->setDeathState(JUST_DIED);
233 pVictim->SetHealth(0);
234 pVictim->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_ATTACKING);
235 return;
237 ((Creature*)pVictim)->AI().AttackStart(this);
240 DEBUG_LOG("DealDamageStart");
242 uint32 health = pVictim->GetHealth();
243 sLog.outDetail("deal dmg:%d to heals:%d ",damage,health);
244 if (health <= damage)
246 DEBUG_LOG("DealDamage: victim just died");
248 DEBUG_LOG("SET JUST_DIED");
249 pVictim->setDeathState(JUST_DIED);
251 uint64 attackerGuid, victimGuid;
252 attackerGuid = GetGUID();
253 victimGuid = pVictim->GetGUID();
255 DEBUG_LOG("DealDamageAttackStop");
256 pVictim->SendAttackStop(attackerGuid);
258 DEBUG_LOG("DealDamageHealth1");
259 pVictim->SetHealth(0);
260 pVictim->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_ATTACKING);
262 // 10% durability loss on death
263 // clean hostilList
264 if (pVictim->GetTypeId() == TYPEID_PLAYER)
266 DEBUG_LOG("We are dead, loosing 10 percents durability");
267 if (durabilityLoss)
269 ((Player*)pVictim)->DeathDurabilityLoss(0.10);
271 HostilList::iterator i;
272 for(i = m_hostilList.begin(); i != m_hostilList.end(); i++)
274 if(i->UnitGuid==victimGuid)
276 m_hostilList.erase(i);
277 break;
281 Creature *pet = pVictim->GetPet();
282 if(pet && pet->isPet())
284 pet->setDeathState(JUST_DIED);
285 pet->SendAttackStop(attackerGuid);
286 pet->SetHealth(0);
287 pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_ATTACKING);
288 pet->addUnitState(UNIT_STAT_DIED);
289 for(i = m_hostilList.begin(); i != m_hostilList.end(); ++i)
291 if(i->UnitGuid==pet->GetGUID())
293 m_hostilList.erase(i);
294 break;
299 else
301 pVictim->m_hostilList.clear();
302 DEBUG_LOG("DealDamageNotPlayer");
303 pVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 1);
306 //judge if GainXP, Pet kill like player kill,kill pet not like PvP
307 bool playerkill = false;
308 bool PvP = false;
309 Player *player;
311 if(GetTypeId() == TYPEID_PLAYER)
313 playerkill = true;
314 player = (Player*)this;
315 if(pVictim->GetTypeId() == TYPEID_PLAYER)
316 PvP = true;
318 else if(((Creature*)this)->isPet())
320 Unit* owner = ((Pet*)this)->GetOwner();
321 if(!owner)
322 playerkill = false;
323 else if(owner->GetTypeId() == TYPEID_PLAYER)
325 player = (Player*)owner;
326 playerkill = true;
330 if(playerkill)
332 player->CalculateHonor(pVictim);
333 player->CalculateReputation(pVictim);
335 if(!PvP)
337 DEBUG_LOG("DealDamageIsPvE");
338 uint32 xp = MaNGOS::XP::Gain(player, pVictim);
339 uint32 entry = 0;
340 entry = pVictim->GetUInt32Value(OBJECT_FIELD_ENTRY );
342 Group *pGroup = objmgr.GetGroupByLeader(player->GetGroupLeader());
343 if(pGroup)
345 DEBUG_LOG("Kill Enemy In Group");
346 xp /= pGroup->GetMembersCount();
347 for (uint32 i = 0; i < pGroup->GetMembersCount(); i++)
349 Player *pGroupGuy = ObjectAccessor::Instance().FindPlayer(pGroup->GetMemberGUID(i));
350 if(!pGroupGuy)
351 continue;
352 if(GetDistanceSq(pGroupGuy) > sWorld.getConfig(CONFIG_GETXP_DISTANCE))
353 continue;
354 if(uint32(abs((int)pGroupGuy->getLevel() - (int)pVictim->getLevel())) > sWorld.getConfig(CONFIG_GETXP_LEVELDIFF))
355 continue;
356 pGroupGuy->GiveXP(xp, pVictim);
357 pGroupGuy->KilledMonster(entry, victimGuid);
360 else
362 DEBUG_LOG("Player kill enemy alone");
363 player->GiveXP(xp, pVictim);
364 player->KilledMonster(entry,victimGuid);
368 else
370 DEBUG_LOG("Monster kill Monster");
371 SendAttackStop(victimGuid);
372 addUnitState(UNIT_STAT_DIED);
374 AttackStop();
376 else
378 DEBUG_LOG("DealDamageAlive");
379 pVictim->SetHealth(health - damage);
380 Attack(pVictim);
382 if(pVictim->getTransForm())
384 pVictim->RemoveAurasDueToSpell(pVictim->getTransForm());
385 pVictim->setTransForm(0);
388 if (pVictim->GetTypeId() != TYPEID_PLAYER)
390 ((Creature *)pVictim)->AI().DamageInflict(this, damage);
391 pVictim->AddHostil(GetGUID(), damage);
392 if( GetTypeId() == TYPEID_PLAYER
393 && (getClass() == WARRIOR || m_form == 5 || m_form == 8) )
394 ((Player*)this)->CalcRage(damage,true);
396 else
398 if( pVictim->getClass() == WARRIOR )
399 ((Player*)pVictim)->CalcRage(damage,false);
401 // random durability for items (HIT)
402 int randdurability = urand(0, 300);
403 if (randdurability == 10)
405 DEBUG_LOG("HIT: We decrease durability with 5 percent");
406 ((Player*)pVictim)->DeathDurabilityLoss(0.05);
411 DEBUG_LOG("DealDamageEnd");
414 void Unit::CastSpell(Unit* Victim, uint32 spellId, bool triggered)
417 SpellEntry *spellInfo = sSpellStore.LookupEntry(spellId );
419 if(!spellInfo)
421 sLog.outError("WORLD: unknown spell id %i\n", spellId);
422 return;
425 Spell *spell = new Spell(this, spellInfo, triggered, 0);
426 WPAssert(spell);
428 SpellCastTargets targets;
429 targets.setUnitTarget( Victim );
430 spell->prepare(&targets);
431 m_canMove = false;
434 void Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage)
437 if(!this || !pVictim)
438 return;
439 if(!this->isAlive() || !pVictim->isAlive())
440 return;
441 uint32 absorb=0;
442 uint32 resist=0;
443 int32 critchance = m_baseSpellCritChance;
444 int crit = 0;
445 CreatureInfo *cinfo = NULL;
446 if(pVictim->GetTypeId() != TYPEID_PLAYER)
447 cinfo = ((Creature*)pVictim)->GetCreatureInfo();
449 SpellEntry *spellInfo = sSpellStore.LookupEntry(spellID);
450 if(spellInfo)
452 for(std::list<struct SpellCritSchool*>::iterator i = m_spellCritSchool.begin();i != m_spellCritSchool.end();i++)
454 if((*i)->school == -1 || (*i)->school == spellInfo->School)
456 critchance += (*i)->chance;
459 critchance += int32(GetStat(STAT_INTELLECT)/100-1);
460 critchance = critchance > 0 ? critchance :0;
461 if(critchance >= urand(0,100))
463 damage = uint32(damage*1.5);
464 crit = 1;
466 for(std::list<struct DamageDoneCreature*>::iterator i = m_damageDoneCreature.begin();i != m_damageDoneCreature.end();i++)
468 if(cinfo && cinfo->type == (*i)->creaturetype)
470 damage += (*i)->damage;
471 break;
474 absorb = CalDamageAbsorb(pVictim,spellInfo->School,damage,&resist);
477 //WorldPacket data;
478 if(m_modSpellHitChance+100 < urand(0,100))
480 SendAttackStateUpdate(HITINFO_HITSTRANGESOUND1|HITINFO_MISS, pVictim->GetGUID(), 1, spellInfo->School, 0, 0,0,1,0);
481 return;
484 if( (damage-absorb-resist)<= 0 )
486 SendAttackStateUpdate(HITINFO_HITSTRANGESOUND1|HITINFO_NOACTION, pVictim->GetGUID(), 1, spellInfo->School, damage, absorb,resist,1,0);
487 return;
490 sLog.outDetail("SpellNonMeleeDamageLog: %u %X attacked %u %X for %u dmg inflicted by %u,abs is %u,resist is %u crit is %i.",
491 GetGUIDLow(), GetGUIDHigh(), pVictim->GetGUIDLow(), pVictim->GetGUIDHigh(), damage, spellID, absorb, resist,crit);
493 SendSpellNonMeleeDamageLog(pVictim->GetGUID(), spellID, damage, spellInfo->School, absorb, resist, false, 0);
494 DealDamage(pVictim, damage<(absorb+resist)?0:(damage-absorb-resist), 0, true);
497 void Unit::PeriodicAuraLog(Unit *pVictim, SpellEntry *spellProto, Modifier *mod)
499 uint32 procFlag = 0;
500 if(!this || !pVictim || !isAlive() || !pVictim->isAlive())
502 return;
504 uint32 absorb=0;
505 uint32 resist=0;
506 int32 critchance = m_baseSpellCritChance;
507 int crit = 0;
508 uint32 pdamage = mod->m_amount;
509 CreatureInfo *cinfo = NULL;
510 if(pVictim->GetTypeId() != TYPEID_PLAYER)
511 cinfo = ((Creature*)pVictim)->GetCreatureInfo();
513 SpellEntry *spellInfo = sSpellStore.LookupEntry(spellProto->Id);
514 if(spellInfo)
516 for(std::list<struct SpellCritSchool*>::iterator i = m_spellCritSchool.begin();i != m_spellCritSchool.end();i++)
518 if((*i)->school == -2 || (*i)->school == spellInfo->School)
520 critchance += (*i)->chance;
523 critchance += int32(GetStat(STAT_INTELLECT)/100-1);
524 critchance = critchance > 0 ? critchance :0;
525 if(critchance >= urand(0,100))
527 pdamage = uint32(pdamage*1.5);
528 crit = 1;
530 for(std::list<struct DamageDoneCreature*>::iterator i = m_damageDoneCreature.begin();i != m_damageDoneCreature.end();i++)
532 if(cinfo && cinfo->type == (*i)->creaturetype)
534 pdamage += (*i)->damage;
535 break;
538 absorb = CalDamageAbsorb(pVictim,spellInfo->School,pdamage,&resist);
541 sLog.outDetail("PeriodicAuraLog: %u %X attacked %u %X for %u dmg inflicted by %u abs is %u crit is %u",
542 GetGUIDLow(), GetGUIDHigh(), pVictim->GetGUIDLow(), pVictim->GetGUIDHigh(), pdamage, spellProto->Id,absorb,crit);
544 WorldPacket data;
545 data.Initialize(SMSG_PERIODICAURALOG);
546 data << uint8(0xFF) << pVictim->GetGUID();
547 data << uint8(0xFF) << this->GetGUID();
548 data << spellProto->Id;
549 data << uint32(1);
551 data << mod->m_auraname;
552 data << (uint32)(mod->m_amount);
553 data << spellProto->School;
554 data << uint32(0);
555 SendMessageToSet(&data,true);
557 if(mod->m_auraname == SPELL_AURA_PERIODIC_DAMAGE)
559 SendSpellNonMeleeDamageLog(pVictim->GetGUID(), spellProto->Id, mod->m_amount, spellProto->School, absorb, resist, false, 0);
560 SendMessageToSet(&data,true);
562 DealDamage(pVictim, mod->m_amount <= int32(absorb+resist) ? 0 : (mod->m_amount-absorb-resist), procFlag, true);
564 else if(mod->m_auraname == SPELL_AURA_PERIODIC_DAMAGE_PERCENT)
566 int32 pdamage = GetHealth()*(100+mod->m_amount)/100;
567 SendSpellNonMeleeDamageLog(pVictim->GetGUID(), spellProto->Id, pdamage, spellProto->School, absorb, resist, false, 0);
568 SendMessageToSet(&data,true);
569 DealDamage(pVictim, pdamage <= int32(absorb+resist) ? 0 : (pdamage-absorb-resist), procFlag, true);
571 else if(mod->m_auraname == SPELL_AURA_PERIODIC_HEAL)
573 if(GetHealth() + mod->m_amount*(100+m_RegenPCT)/100 < GetMaxHealth() )
574 SetHealth(GetHealth() + mod->m_amount*(100+m_RegenPCT)/100);
575 else
576 SetHealth(GetMaxHealth());
578 else if(mod->m_auraname == SPELL_AURA_PERIODIC_LEECH)
580 uint32 tmpvalue = 0;
581 for(int x=0;x<3;x++)
583 if(mod->m_auraname != spellInfo->EffectApplyAuraName[x])
584 continue;
585 if(pVictim->GetHealth() - mod->m_amount > 0)
586 tmpvalue = uint32(mod->m_amount*spellInfo->EffectMultipleValue[x]);
587 else
588 tmpvalue = uint32(pVictim->GetHealth()*spellInfo->EffectMultipleValue[x]);
590 DealDamage(pVictim, mod->m_amount <= int32(absorb+resist) ? 0 : (mod->m_amount-absorb-resist), procFlag, false);
591 if (!pVictim->isAlive() && m_currentSpell)
592 if (m_currentSpell->m_spellInfo)
593 if (m_currentSpell->m_spellInfo->Id == spellProto->Id)
594 m_currentSpell->cancel();
596 break;
598 if(GetHealth() + tmpvalue*(100+m_RegenPCT)/100 < GetMaxHealth() )
599 SetHealth(GetHealth() + tmpvalue*(100+m_RegenPCT)/100);
600 else SetHealth(GetMaxHealth());
602 else if(mod->m_auraname == SPELL_AURA_PERIODIC_MANA_LEECH)
604 uint32 tmpvalue = 0;
605 for(int x=0;x<3;x++)
607 if(mod->m_auraname != spellInfo->EffectApplyAuraName[x])
608 continue;
609 if(pVictim->GetPower(POWER_MANA) - mod->m_amount > 0)
611 pVictim->SetPower(POWER_MANA,pVictim->GetPower(POWER_MANA) - mod->m_amount);
612 tmpvalue = uint32(mod->m_amount*spellInfo->EffectMultipleValue[x]);
614 else
616 tmpvalue = uint32(pVictim->GetPower(POWER_MANA)*spellInfo->EffectMultipleValue[x]);
617 pVictim->SetPower(POWER_MANA,0);
619 break;
621 if(GetPower(POWER_MANA) + tmpvalue < GetMaxPower(POWER_MANA) )
622 SetPower(POWER_MANA,GetPower(POWER_MANA) + tmpvalue);
623 else SetPower(POWER_MANA,GetMaxPower(POWER_MANA));
625 else if(mod->m_auraname == SPELL_AURA_PERIODIC_ENERGIZE)
627 if(mod->m_miscvalue < 0 || mod->m_miscvalue > 4)
628 return;
629 SetPower(Powers(mod->m_miscvalue),GetPower(Powers(mod->m_miscvalue))+mod->m_amount);
633 void Unit::HandleEmoteCommand(uint32 anim_id)
635 WorldPacket data;
637 data.Initialize( SMSG_EMOTE );
638 data << anim_id << GetGUID();
639 WPAssert(data.size() == 12);
641 SendMessageToSet(&data, true);
644 uint32 Unit::CalDamageAbsorb(Unit *pVictim,uint32 School,const uint32 damage,uint32 *resist)
646 uint32 AbsorbDamage=0;
647 uint32 currAbsorbDamage=0;
648 uint32 currentPower;
649 bool removeAura=false;
651 if(!pVictim)
652 return 0;
653 if(!pVictim->isAlive())
654 return 0;
656 for(std::list<struct DamageManaShield*>::iterator i = pVictim->m_damageManaShield.begin();i != pVictim->m_damageManaShield.end();i++)
658 SpellEntry *spellInfo = sSpellStore.LookupEntry( (*i)->m_spellId);
660 if(((*i)->m_schoolType & School) || (*i)->m_schoolType == School || (*i)->m_schoolType ==127)
662 currAbsorbDamage = damage+ (*i)->m_currAbsorb;
663 if(currAbsorbDamage < (*i)->m_totalAbsorb)
665 AbsorbDamage = damage;
666 (*i)->m_currAbsorb = currAbsorbDamage;
668 else
670 AbsorbDamage = (*i)->m_totalAbsorb - (*i)->m_currAbsorb;
671 (*i)->m_currAbsorb = (*i)->m_totalAbsorb;
672 removeAura = true;
675 if((*i)->m_modType == SPELL_AURA_MANA_SHIELD)
677 float multiple;
678 for(int x=0;x<3;x++)
679 if(spellInfo->EffectApplyAuraName[x] == SPELL_AURA_MANA_SHIELD)
681 multiple = spellInfo->EffectMultipleValue[x];
682 break;
684 currentPower = pVictim->GetPower(POWER_MANA);
685 if ( (float)(currentPower) > AbsorbDamage*multiple )
687 pVictim->SetPower(POWER_MANA, (uint32)(currentPower-AbsorbDamage*multiple) );
689 else
691 pVictim->SetPower(POWER_MANA, 0 );
695 if(removeAura)
696 pVictim->RemoveAurasDueToSpell((*i)->m_spellId);
698 break;
700 if(School == 0)
702 uint32 armor = pVictim->GetArmor();
703 float tmpvalue = armor/(pVictim->getLevel()*85.0 +400.0 +armor);
704 if(tmpvalue < 0)
705 tmpvalue = 0.0;
706 if(tmpvalue > 1.0)
707 tmpvalue = 1.0;
708 AbsorbDamage += uint32(damage * tmpvalue);
709 if(AbsorbDamage > damage)
710 AbsorbDamage = damage;
712 if( School > 0)
714 uint32 tmpvalue2 = pVictim->GetResistance(SpellSchools(School));
715 *resist += uint32(damage*tmpvalue2*0.0025*pVictim->getLevel()/getLevel());
716 if(*resist > damage)
717 *resist = damage;
720 // random durability loss for items on absorb (ABSORB)
721 if (pVictim->GetTypeId() == TYPEID_PLAYER)
723 int randdurability = urand(0, 300);
724 if (randdurability == 10)
726 DEBUG_LOG("BLOCK: We decrease durability with 5 percent");
727 ((Player*)pVictim)->DeathDurabilityLoss(0.05);
731 return AbsorbDamage;
734 void Unit::DoAttackDamage(Unit *pVictim, uint32 *damage, uint32 *blocked_amount, uint32 *damageType, uint32 *hitInfo, uint32 *victimState,uint32 *absorbDamage,uint32 *resist)
736 MeleeHitOutcome outcome = RollMeleeOutcomeAgainst (pVictim);
737 if (outcome == MELEE_HIT_MISS)
739 *hitInfo |= HITINFO_MISS;
740 return;
743 CreatureInfo *cinfo = NULL;
744 if(pVictim->GetTypeId() != TYPEID_PLAYER)
745 cinfo = ((Creature*)pVictim)->GetCreatureInfo();
747 *damage = (CalculateDamage (false) * (m_modDamagePCT+100))/100;
748 for(std::list<struct DamageDoneCreature*>::iterator i = m_damageDoneCreature.begin();i != m_damageDoneCreature.end();i++)
750 if(cinfo && cinfo->type == (*i)->creaturetype)
752 *damage += (*i)->damage;
753 break;
757 if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && ((Creature*)pVictim)->GetCreatureInfo()->type != 8 )
758 ((Player*)this)->UpdateMeleeSkillWeapon();
760 switch (outcome)
762 case MELEE_HIT_CRIT:
763 //*hitInfo = 0xEA;
764 *hitInfo = HITINFO_HITSTRANGESOUND1 | HITINFO_HITSTRANGESOUND2 | HITINFO_CRITICALHIT
765 | HITINFO_NORMALSWING2 | 0x8; // 0xEA
766 *damage *= 2;
768 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL);
769 break;
771 case MELEE_HIT_PARRY:
772 *damage = 0;
773 *victimState = 2;
775 if(pVictim->GetTypeId() == TYPEID_PLAYER)
777 ((Player*)pVictim)->UpdateDefense();
778 pVictim->m_attackTimer = 0; // parry sets attack timer to 0
781 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
782 break;
784 case MELEE_HIT_DODGE:
785 *damage = 0;
786 *victimState = 3;
788 if(pVictim->GetTypeId() == TYPEID_PLAYER)
789 ((Player*)pVictim)->UpdateDefense();
791 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
792 break;
794 case MELEE_HIT_BLOCK:
795 *blocked_amount = (pVictim->GetUnitBlockValue() * (pVictim->GetStat(STAT_STRENGTH) / 20));
797 if (*blocked_amount < *damage)
798 *damage -= *blocked_amount;
799 else
800 *damage = 0;
802 if (pVictim->GetUnitBlockValue())
803 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD);
804 else
805 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
807 *victimState = 4;
809 if(pVictim->GetTypeId() == TYPEID_PLAYER)
810 ((Player*)pVictim)->UpdateDefense();
811 break;
813 case MELEE_HIT_GLANCING:
815 // 30% reduction at 15 skill diff, no reduction at 5 skill diff
816 int32 reducePerc = 100 - (pVictim->GetDefenceSkillValue() - GetWeaponSkillValue() - 5) * 3;
817 if (reducePerc < 70)
818 reducePerc = 70;
819 *damage = *damage * reducePerc / 100;
820 *hitInfo |= HITINFO_GLANCING;
821 break;
823 case MELEE_HIT_CRUSHING:
824 // 150% normal damage
825 *damage += (*damage / 2);
826 *hitInfo |= HITINFO_CRUSHING;
827 // TODO: victimState, victim animation?
828 break;
830 default:
831 break;
834 for(std::list<struct DamageShield>::iterator i = pVictim->m_damageShields.begin();i != pVictim->m_damageShields.end();i++)
836 pVictim->SpellNonMeleeDamageLog(this,i->m_spellId,i->m_damage);
838 uint32 absorb= CalDamageAbsorb(pVictim,NORMAL_DAMAGE,*damage,resist);
840 if (*damage <= absorb + *resist)
842 //*hitInfo = 0x00010020;
843 *hitInfo = HITINFO_NOACTION | HITINFO_HITSTRANGESOUND1;
844 *absorbDamage = absorb;
845 *damageType = 0;
846 return;
848 else
850 *absorbDamage = absorb;
852 // proc trigger damage
853 for (AuraMap::iterator i = pVictim->m_Auras.begin(); i != pVictim->m_Auras.end(); ++i)
855 ProcTriggerDamage *procdamage = (*i).second->GetProcDamage();
856 if(procdamage)
858 bool nocharges = procdamage->procCharges == 0 ? true : false;
859 if((procdamage->procFlags & 40) && procdamage->procChance > rand_chance()
860 && (procdamage->procCharges > 0 || nocharges))
862 pVictim->SpellNonMeleeDamageLog(this,(*i).second->GetSpellProto()->Id,procdamage->procDamage);
863 if(!nocharges)
864 procdamage->procCharges -= 1;
866 else if(procdamage->procFlags == 64 && procdamage->procChance > rand_chance()
867 && (procdamage->procCharges > 0 || nocharges) && *victimState == 4)
869 pVictim->SpellNonMeleeDamageLog(this,(*i).second->GetSpellProto()->Id,procdamage->procDamage);
870 if(!nocharges)
871 procdamage->procCharges -= 1;
875 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
877 ProcTriggerDamage *procdamage = (*i).second->GetProcDamage();
878 if(procdamage)
880 bool nocharges = procdamage->procCharges == 0 ? true : false;
881 if(procdamage->procFlags == 1 && procdamage->procChance > rand_chance()
882 && (procdamage->procCharges > 0 || nocharges))
884 SpellNonMeleeDamageLog(pVictim,(*i).second->GetSpellProto()->Id,procdamage->procDamage);
885 if(!nocharges)
886 procdamage->procCharges -= 1;
890 // proc trigger aura, Fix Me about procflag & what case.
891 for (AuraMap::iterator i = pVictim->m_Auras.begin(); i != pVictim->m_Auras.end(); ++i)
893 if(ProcTriggerSpell* procspell = (*i).second->GetProcSpell())
895 bool nocharges = procspell->procCharges == 0 ? true : false;
896 if((procspell->procFlags & 40) && procspell->procChance > rand_chance()
897 && (procspell->procCharges > 0 || nocharges))
899 if(!nocharges)
900 procspell->procCharges -= 1;
901 SpellEntry *spellInfo = sSpellStore.LookupEntry((*i).second->GetProcSpell()->trigger);
903 if(!spellInfo)
905 sLog.outError("WORLD: unknown spell id %i\n", (*i).second->GetProcSpell()->trigger);
906 return;
909 Spell *spell = new Spell(pVictim, spellInfo, true, 0);
910 WPAssert(spell);
912 SpellCastTargets targets;
913 targets.setUnitTarget( this );
914 spell->prepare(&targets);
916 if((*i).second->GetProcSpell()->trigger == 26545)
917 pVictim->SpellNonMeleeDamageLog(this,(*i).second->GetSpellProto()->Id,(*i).second->CalculateDamage());
921 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
923 if(ProcTriggerSpell* procspell = (*i).second->GetProcSpell())
925 bool nocharges = procspell->procCharges == 0 ? true : false;
926 if((procspell->procFlags & 20) && procspell->procChance > rand_chance()
927 && (procspell->procCharges > 0 || nocharges))
929 if(!nocharges)
930 procspell->procCharges -= 1;
931 SpellEntry *spellInfo = sSpellStore.LookupEntry((*i).second->GetProcSpell()->trigger );
933 if(!spellInfo)
935 sLog.outError("WORLD: unknown spell id %i\n", (*i).second->GetProcSpell()->trigger);
936 return;
939 Spell *spell = new Spell(pVictim, spellInfo, true, 0);
940 WPAssert(spell);
942 SpellCastTargets targets;
943 targets.setUnitTarget( this );
944 spell->prepare(&targets);
949 if(pVictim->m_currentSpell && pVictim->GetTypeId() == TYPEID_PLAYER && *damage)
951 if (pVictim->m_currentSpell->getState() != SPELL_STATE_CASTING)
953 sLog.outString("Spell Delayed!%d",(int32)(0.25f * pVictim->m_currentSpell->casttime));
954 pVictim->m_currentSpell->Delayed((int32)(0.25f * pVictim->m_currentSpell->casttime));
956 else
958 sLog.outString("Spell Canceled!");
959 pVictim->m_currentSpell->cancel();
964 void Unit::AttackerStateUpdate (Unit *pVictim)
966 if(hasUnitState(UNIT_STAT_CONFUSED) || hasUnitState(UNIT_STAT_STUNDED))
967 return;
969 if (!pVictim->isAlive())
971 SendAttackStop(pVictim->GetGUID());
972 return;
975 if(m_currentSpell)
976 return;
978 if (m_currentMeleeSpell)
980 m_currentMeleeSpell->cast();
981 return;
984 WorldPacket data;
985 uint32 hitInfo = HITINFO_NORMALSWING2|HITINFO_HITSTRANGESOUND1;
986 uint32 damageType = NORMAL_DAMAGE;
987 uint32 victimState = VICTIMSTATE_NORMAL;
989 uint32 damage = 0;
990 uint32 blocked_dmg = 0;
991 uint32 absorbed_dmg = 0;
992 uint32 resisted_dmg = 0;
994 DoAttackDamage (pVictim, &damage, &blocked_dmg, &damageType, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg);
996 if (hitInfo & HITINFO_MISS)
997 //send miss
998 SendAttackStateUpdate (hitInfo, pVictim->GetGUID(), 1, damageType, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg);
999 else
1001 //do animation
1002 SendAttackStateUpdate (hitInfo, pVictim->GetGUID(), 1, damageType, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg);
1003 if (damage >= (absorbed_dmg + resisted_dmg))
1004 damage -= (absorbed_dmg + resisted_dmg);
1005 else
1006 damage = 0;
1007 DealDamage (pVictim, damage, 0, true);
1009 if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive())
1011 for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
1012 ((Player*)this)->CastItemCombatSpell(((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i),pVictim);
1016 if (GetTypeId() == TYPEID_PLAYER)
1017 DEBUG_LOG("AttackerStateUpdate: (Player) %u %X attacked %u %X for %u dmg, absorbed %u, resisted %u.",
1018 GetGUIDLow(), GetGUIDHigh(), pVictim->GetGUIDLow(), pVictim->GetGUIDHigh(), damage, absorbed_dmg, resisted_dmg);
1019 else
1020 DEBUG_LOG("AttackerStateUpdate: (NPC) %u %X attacked %u %X for %u dmg, absorbed %u, resisted %u.",
1021 GetGUIDLow(), GetGUIDHigh(), pVictim->GetGUIDLow(), pVictim->GetGUIDHigh(), damage, absorbed_dmg, resisted_dmg);
1024 MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim) const
1026 int32 skillDiff = GetWeaponSkillValue() - pVictim->GetDefenceSkillValue();
1027 // bonus from skills is 0.04%
1028 int32 skillBonus = skillDiff * 4;
1029 int32 sum = 0, tmp = 0;
1030 int32 roll = urand (0, 10000);
1032 DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus);
1033 DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, +hit %d, dodge %u, parry %u, block %u, crit %u",
1034 roll, m_modHitChance, (uint32)(pVictim->GetUnitDodgeChance()*100), (uint32)(pVictim->GetUnitParryChance()*100),
1035 (uint32)(pVictim->GetUnitBlockChance()*100), (uint32)(GetUnitCriticalChance()*100));
1037 // FIXME: dual wield has 24% base chance to miss instead of 5%, also
1038 // dual wield is hard-limited to min. 19% miss rate
1039 // base miss rate is 5% and can't get higher than 60%
1040 tmp = 500 - skillBonus - m_modHitChance*100;
1041 if (tmp > 0 && roll < (sum += (tmp >= 6000 ? 6000 : tmp)))
1042 { DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS"); return MELEE_HIT_MISS; }
1044 // always crit against a sitting target
1045 if ( (pVictim->GetTypeId() == TYPEID_PLAYER)
1046 && (((Player*)pVictim)->getStandState() & (PLAYER_STATE_SLEEP | PLAYER_STATE_SIT
1047 | PLAYER_STATE_SIT_CHAIR
1048 | PLAYER_STATE_SIT_LOW_CHAIR
1049 | PLAYER_STATE_SIT_MEDIUM_CHAIR
1050 | PLAYER_STATE_SIT_HIGH_CHAIR)))
1051 { DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)"); return MELEE_HIT_CRIT; }
1053 // stunned target cannot dodge and this is check in GetUnitDodgeChance()
1054 tmp = (int32)(pVictim->GetUnitDodgeChance()*100) - skillBonus;
1055 if (tmp > 0 && roll < (sum += tmp))
1056 { DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum-tmp, sum); return MELEE_HIT_DODGE; }
1058 int32 modCrit = 0;
1060 // check if attack comes from behind
1061 if (!pVictim->HasInArc(M_PI,this))
1063 // ASSUME +10% crit from behind
1064 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind.");
1065 modCrit += 1000;
1067 else
1069 // cannot parry or block attacks from behind, but can from forward
1070 tmp = (int32)(pVictim->GetUnitParryChance()*100);
1071 if ( (tmp > 0) // check if unit _can_ parry
1072 && ((tmp -= skillBonus) > 0)
1073 && (roll < (sum += tmp)))
1074 { DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum-tmp, sum); return MELEE_HIT_PARRY; }
1076 tmp = (int32)(pVictim->GetUnitBlockChance()*100);
1077 if ( (tmp > 0) // check if unit _can_ block
1078 && ((tmp -= skillBonus) > 0)
1079 && (roll < (sum += tmp)))
1080 { DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum-tmp, sum); return MELEE_HIT_BLOCK; }
1083 // flat 40% chance to score a glancing blow if you're 3 or more levels
1084 // below mob level or your weapon skill is too low
1085 if ( (GetTypeId() == TYPEID_PLAYER)
1086 && (pVictim->GetTypeId() != TYPEID_PLAYER)
1087 && ((getLevel() + 3 <= pVictim->getLevel()) || (skillDiff <= -15))
1088 && (roll < (sum += 4000)))
1089 { DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum-4000, sum); return MELEE_HIT_GLANCING; }
1091 // FIXME: +skill and +defense has no effect on crit chance in PvP combat
1092 tmp = (int32)(GetUnitCriticalChance()*100) + skillBonus + modCrit;
1093 if (tmp > 0 && roll < (sum += tmp))
1094 { DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum-tmp, sum); return MELEE_HIT_CRIT; }
1096 // mobs can score crushing blows if they're 3 or more levels above victim
1097 // or when their weapon skill is 15 or more above victim's defense skill
1098 if ( (GetTypeId() != TYPEID_PLAYER)
1099 && ((getLevel() >= pVictim->getLevel() + 3) || (skillDiff >= 15)))
1101 // tmp = player's max defense skill - player's current defense skill
1102 tmp = 5*pVictim->getLevel() - pVictim->GetDefenceSkillValue();
1103 // having defense above your maximum (from items, talents etc.) has no effect
1104 // add 2% chance per lacking skill point, min. is 15%
1105 // FIXME: chance should go up with mob lvl
1106 tmp = 1500 + (tmp > 0 ? tmp*200 : 0);
1107 if (roll < (sum += tmp))
1108 { DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum-tmp, sum); return MELEE_HIT_CRUSHING; }
1111 DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL");
1112 return MELEE_HIT_NORMAL;
1115 uint32 Unit::CalculateDamage(bool ranged)
1117 float min_damage, max_damage, dmg;
1118 if(ranged)
1120 min_damage = GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE);
1121 max_damage = GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE);
1123 else
1125 min_damage = GetFloatValue(UNIT_FIELD_MINDAMAGE)+GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE)/2;
1126 max_damage = GetFloatValue(UNIT_FIELD_MAXDAMAGE)+GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE)/2;
1128 if (min_damage > max_damage)
1130 std::swap(min_damage,max_damage);
1133 if(max_damage == 0.0)
1134 max_damage = 5.0;
1136 float diff = max_damage - min_damage + 1;
1138 dmg = float (rand()%(uint32)diff + (uint32)min_damage);
1139 return (uint32)dmg;
1142 void Unit::SendAttackStop(uint64 victimGuid)
1144 WorldPacket data;
1145 data.Initialize( SMSG_ATTACKSTOP );
1146 data << uint8(0xFF) << GetGUID();
1147 data << uint8(0xFF) << victimGuid;
1148 data << uint32( 0 );
1149 data << (uint32)0;
1151 SendMessageToSet(&data, true);
1152 sLog.outDetail("%u %X stopped attacking "I64FMT, GetGUIDLow(), GetGUIDHigh(), victimGuid);
1154 Creature *pVictim = ObjectAccessor::Instance().GetCreature(*this, victimGuid);
1155 if( pVictim != NULL )
1156 pVictim->AI().AttackStop(this);
1159 uint16 Unit::GetDefenceSkillValue() const
1161 if(GetTypeId() == TYPEID_PLAYER)
1162 return ((Player*)this)->GetSkillValue (SKILL_DEFENSE);
1163 else
1164 return GetUnitMeleeSkill();
1167 float Unit::GetUnitDodgeChance() const
1169 if(hasUnitState(UNIT_STAT_STUNDED))
1170 return 0;
1172 return GetTypeId() == TYPEID_PLAYER ? m_floatValues[ PLAYER_DODGE_PERCENTAGE ] : 5;
1175 float Unit::GetUnitParryChance() const
1177 float chance = 0;
1178 if(GetTypeId() == TYPEID_PLAYER)
1180 Player const* player = (Player const*)this;
1181 // Parry passive skill
1182 if(player->HasSpell(3127) || player->HasSpell(18848))
1184 Item *tmpitem = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
1185 if(!tmpitem)
1186 tmpitem = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
1188 if(tmpitem && tmpitem->GetProto()->InventoryType == INVTYPE_WEAPON)
1189 chance = GetFloatValue(PLAYER_PARRY_PERCENTAGE);
1192 else if(GetTypeId() == TYPEID_UNIT)
1194 if(((Creature const*)this)->GetCreatureInfo()->type == CREATURE_TYPE_HUMANOID)
1195 chance = 5;
1198 return chance;
1201 float Unit::GetUnitBlockChance() const
1203 float chance = 0;
1204 if(GetTypeId() == TYPEID_PLAYER)
1206 Item *tmpitem = ((Player const*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
1207 if(tmpitem && tmpitem->GetProto()->Block)
1208 chance = GetFloatValue(PLAYER_BLOCK_PERCENTAGE);
1210 else
1211 chance = 5;
1213 return chance;
1216 uint16 Unit::GetWeaponSkillValue() const
1218 if(GetTypeId() == TYPEID_PLAYER)
1220 uint32 skill = 0;
1221 Item *item = ((Player*)this)->GetItemByPos (INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
1222 if(!item)
1223 Item *item = ((Player*)this)->GetItemByPos (INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
1225 skill = item ? item->GetSkill() : SKILL_UNARMED;
1226 return ((Player*)this)->GetSkillValue (skill);
1228 else
1229 return GetUnitMeleeSkill();
1232 void Unit::_UpdateSpells( uint32 time )
1234 if(m_currentSpell != NULL)
1236 m_currentSpell->update(time);
1237 if(m_currentSpell->IsAutoRepeat())
1239 if(m_currentSpell->getState() == SPELL_STATE_FINISHED)
1241 //Auto shot
1242 if( m_currentSpell->m_spellInfo->Id == 75 && GetTypeId() == TYPEID_PLAYER )
1243 setAttackTimer( 0, true );
1244 else
1245 setAttackTimer(m_currentSpell->m_spellInfo->RecoveryTime);
1247 m_currentSpell->setState(SPELL_STATE_IDLE);
1249 else if(m_currentSpell->getState() == SPELL_STATE_IDLE && m_attackTimer == 0)
1251 // recheck range and req. items (ammo and gun, etc)
1252 if(m_currentSpell->CheckRange() == 0 && m_currentSpell->CheckItems() == 0 )
1254 m_currentSpell->setState(SPELL_STATE_PREPARING);
1255 m_currentSpell->ReSetTimer();
1257 else
1259 m_currentSpell->cancel();
1260 delete m_currentSpell;
1261 m_currentSpell = NULL;
1265 else if(m_currentSpell->getState() == SPELL_STATE_FINISHED)
1267 delete m_currentSpell;
1268 m_currentSpell = NULL;
1272 if(m_currentMeleeSpell != NULL)
1274 m_currentMeleeSpell ->update(time);
1275 if(m_currentMeleeSpell ->getState() == SPELL_STATE_FINISHED)
1277 delete m_currentMeleeSpell ;
1278 m_currentMeleeSpell = NULL;
1282 // TODO: Find a better way to prevent crash when multiple auras are removed.
1283 m_removedAuras = 0;
1284 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
1285 if ((*i).second)
1286 (*i).second->SetUpdated(false);
1288 for (AuraMap::iterator i = m_Auras.begin(), next; i != m_Auras.end(); i = next)
1290 next = i;
1291 next++;
1292 if ((*i).second)
1294 // prevent double update
1295 if ((*i).second->IsUpdated())
1296 continue;
1297 (*i).second->SetUpdated(true);
1298 (*i).second->Update( time );
1299 // several auras can be deleted due to update
1300 if (m_removedAuras)
1302 if (m_Auras.empty()) break;
1303 next = m_Auras.begin();
1304 m_removedAuras = 0;
1309 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end();)
1311 if ((*i).second)
1313 if ( !(*i).second->GetAuraDuration() && !(*i).second->IsPermanent() )
1315 RemoveAura(i);
1317 else
1319 ++i;
1322 else
1324 ++i;
1328 if(m_dynObj.empty())
1329 return;
1330 std::list<DynamicObject*>::iterator ite, dnext;
1331 for (ite = m_dynObj.begin(); ite != m_dynObj.end(); ite = dnext)
1333 dnext = ite;
1334 dnext++;
1335 //(*i)->Update( difftime );
1336 if( (*ite)->isFinished() )
1338 (*ite)->Delete();
1339 m_dynObj.erase(ite);
1340 if(m_dynObj.empty())
1341 break;
1342 else
1343 dnext = m_dynObj.begin();
1346 if(m_gameObj.empty())
1347 return;
1348 std::list<GameObject*>::iterator ite1, dnext1;
1349 for (ite1 = m_gameObj.begin(); ite1 != m_gameObj.end(); ite1 = dnext1)
1351 dnext1 = ite1;
1352 dnext1++;
1353 //(*i)->Update( difftime );
1354 if( (*ite1)->isFinished() )
1356 (*ite1)->Delete();
1357 m_gameObj.erase(ite1);
1358 if(m_gameObj.empty())
1359 break;
1360 else
1361 dnext1 = m_gameObj.begin();
1366 void Unit::_UpdateHostil( uint32 time )
1368 if(!isInCombat() && m_hostilList.size() )
1370 HostilList::iterator iter;
1371 for(iter=m_hostilList.begin(); iter!=m_hostilList.end(); ++iter)
1373 iter->Hostility-=time/1000.0f;
1374 if(iter->Hostility<=0.0f)
1376 m_hostilList.erase(iter);
1377 if(!m_hostilList.size())
1378 break;
1379 else
1380 iter = m_hostilList.begin();
1386 Unit* Unit::SelectHostilTarget()
1388 if(!m_hostilList.size())
1389 return NULL;
1391 m_hostilList.sort();
1392 m_hostilList.reverse();
1393 uint64 guid = m_hostilList.front().UnitGuid;
1394 if(guid != getVictim()->GetGUID())
1395 return ObjectAccessor::Instance().GetUnit(*this, guid);
1396 else
1397 return NULL;
1400 void Unit::castSpell( Spell * pSpell )
1403 if(pSpell->IsMeleeSpell())
1405 if(m_currentMeleeSpell)
1407 m_currentMeleeSpell->cancel();
1408 delete m_currentMeleeSpell;
1409 m_currentMeleeSpell = NULL;
1411 m_currentMeleeSpell = pSpell;
1413 else
1415 if(m_currentSpell)
1417 m_currentSpell->cancel();
1418 delete m_currentSpell;
1419 m_currentSpell = NULL;
1421 m_currentSpell = pSpell;
1425 void Unit::InterruptSpell()
1427 if(m_currentSpell)
1429 //m_currentSpell->SendInterrupted(0x20);
1430 m_currentSpell->cancel();
1434 bool Unit::isInFront(Unit const* target, float radius)
1436 return GetDistanceSq(target)<=radius * radius && HasInArc( M_PI, target );
1439 void Unit::SetInFront(Unit const* target)
1441 m_orientation = GetAngle(target);
1444 void Unit::DeMorph()
1447 uint32 displayid = GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID);
1448 SetUInt32Value(UNIT_FIELD_DISPLAYID, displayid);
1451 void Unit::DealWithSpellDamage(DynamicObject &obj)
1453 obj.DealWithSpellDamage(*this);
1456 long Unit::GetTotalAuraModifier(uint32 ModifierID)
1458 uint32 modifier = 0;
1459 bool auraFound = false;
1461 AuraMap::const_iterator i;
1462 for (i = m_Auras.begin(); i != m_Auras.end(); i++)
1464 if ((*i).second && (*i).second->GetModifier()->m_auraname == ModifierID)
1466 auraFound = true;
1467 modifier += (*i).second->GetModifier()->m_amount;
1470 if (auraFound)
1471 modifier++;
1473 return modifier;
1476 bool Unit::AddAura(Aura *Aur, bool uniq)
1478 AuraMap::iterator i = m_Auras.find( spellEffectPair(Aur->GetId(), Aur->GetEffIndex()) );
1479 // take out same spell
1480 if (i != m_Auras.end())
1482 (*i).second->SetAuraDuration(Aur->GetAuraDuration());
1483 if ((*i).second->GetTarget())
1484 if ((*i).second->GetTarget()->GetTypeId() == TYPEID_PLAYER )
1485 (*i).second->UpdateAuraDuration();
1486 delete Aur;
1488 else
1490 if (!Aur->IsPassive()) // passive auras stack with all
1492 if (!RemoveNoStackAurasDueToAura(Aur))
1494 delete Aur;
1495 return false; // couldnt remove conflicting aura with higher rank
1496 } // couldnt remove conflicting aura with higher rank
1499 Aur->_AddAura();
1500 m_Auras[spellEffectPair(Aur->GetId(), Aur->GetEffIndex())] = Aur;
1501 m_AuraModifiers[Aur->GetModifier()->m_auraname] += (Aur->GetModifier()->m_amount + 1);
1503 if (Aur->IsSingleTarget() && Aur->GetTarget() && Aur->GetSpellProto())
1505 std::list<Aura *> *scAuras = Aur->GetCaster()->GetSingleCastAuras();
1506 std::list<Aura *>::iterator itr, next;
1507 for (itr = scAuras->begin(); itr != scAuras->end(); itr = next)
1509 next = itr;
1510 next++;
1511 if ((*itr)->GetTarget() != Aur->GetTarget() &&
1512 (*itr)->GetSpellProto()->Category == Aur->GetSpellProto()->Category &&
1513 (*itr)->GetSpellProto()->SpellIconID == Aur->GetSpellProto()->SpellIconID &&
1514 (*itr)->GetSpellProto()->SpellVisual == Aur->GetSpellProto()->SpellVisual &&
1515 (*itr)->GetSpellProto()->Attributes == Aur->GetSpellProto()->Attributes &&
1516 (*itr)->GetSpellProto()->AttributesEx == Aur->GetSpellProto()->AttributesEx &&
1517 (*itr)->GetSpellProto()->AttributesExEx == Aur->GetSpellProto()->AttributesExEx)
1519 (*itr)->GetTarget()->RemoveAura((*itr)->GetId(), (*itr)->GetEffIndex());
1520 if(scAuras->empty())
1521 break;
1522 else
1523 next = scAuras->begin();
1526 scAuras->push_back(Aur);
1529 return true;
1532 void Unit::RemoveRankAurasDueToSpell(uint32 spellId)
1534 SpellEntry *spellInfo = sSpellStore.LookupEntry(spellId);
1535 if(!spellInfo)
1536 return;
1537 AuraMap::iterator i,next;
1538 for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
1540 next = i;
1541 next++;
1542 uint32 i_spellId = (*i).second->GetId();
1543 if((*i).second && i_spellId && i_spellId != spellId)
1545 if(IsRankSpellDueToSpell(spellInfo,i_spellId))
1547 RemoveAurasDueToSpell(i_spellId);
1549 if( m_Auras.empty() )
1550 break;
1551 else
1552 next = m_Auras.begin();
1558 bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur)
1560 if (!Aur)
1561 return false;
1562 if (!Aur->GetSpellProto()) return false;
1563 uint32 spellId = Aur->GetId();
1564 uint32 effIndex = Aur->GetEffIndex();
1565 bool is_sec = IsSpellSingleEffectPerCaster(spellId);
1566 AuraMap::iterator i,next;
1567 for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
1569 next = i;
1570 next++;
1571 if (!(*i).second) continue;
1572 if (!(*i).second->GetSpellProto()) continue;
1573 if (IsPassiveSpell((*i).second->GetId())) continue;
1575 uint32 i_spellId = (*i).second->GetId();
1576 uint32 i_effIndex = (*i).second->GetEffIndex();
1577 if(i_spellId != spellId)
1579 bool sec_match = false;
1580 if (is_sec && IsSpellSingleEffectPerCaster(i_spellId))
1581 if (Aur->GetCaster() == (*i).second->GetCaster())
1582 if (GetSpellSpecific(spellId) == GetSpellSpecific(i_spellId))
1583 sec_match = true;
1585 if(IsNoStackSpellDueToSpell(spellId, i_spellId) || sec_match)
1587 // if sec_match this isnt always true, needs to be rechecked
1588 if (IsRankSpellDueToSpell(Aur->GetSpellProto(), i_spellId))
1589 if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
1590 return false; // cannot remove higher rank
1592 RemoveAurasDueToSpell(i_spellId);
1594 if( m_Auras.empty() )
1595 break;
1596 else
1597 next = m_Auras.begin();
1599 else // Potions stack aura by aura
1600 if (Aur->GetSpellProto()->SpellFamilyName == SPELLFAMILY_POTION &&
1601 (*i).second->GetSpellProto()->SpellFamilyName == SPELLFAMILY_POTION)
1603 if (IsNoStackAuraDueToAura(spellId, effIndex, i_spellId, i_effIndex))
1605 if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
1606 return false; // cannot remove higher rank
1608 RemoveAura(i);
1610 if( m_Auras.empty() )
1611 break;
1612 else
1613 next = m_Auras.begin();
1618 return true;
1621 void Unit::RemoveFirstAuraByDispel(uint32 dispel_type)
1623 AuraMap::iterator i;
1624 for (i = m_Auras.begin(); i != m_Auras.end(); ++i)
1626 if ((*i).second && (*i).second->GetSpellProto()->Dispel == dispel_type)
1628 if(dispel_type == 1)
1630 bool positive = true;
1631 switch((*i).second->GetSpellProto()->EffectImplicitTargetA[(*i).second->GetEffIndex()])
1633 case TARGET_S_E:
1634 case TARGET_AE_E:
1635 case TARGET_AE_E_INSTANT:
1636 case TARGET_AC_E:
1637 case TARGET_INFRONT:
1638 case TARGET_DUELVSPLAYER:
1639 case TARGET_AE_E_CHANNEL:
1640 case TARGET_AE_SELECTED:
1641 positive = false;
1642 break;
1644 default:
1645 positive = ((*i).second->GetSpellProto()->AttributesEx & (1<<7)) ? false : true;
1647 if(positive)
1648 continue;
1650 break;
1654 if(i == m_Auras.end()) return;
1656 RemoveAura(i);
1659 void Unit::RemoveAura(uint32 spellId, uint32 effindex)
1661 AuraMap::iterator i = m_Auras.find( spellEffectPair(spellId, effindex) );
1662 if(i != m_Auras.end())
1663 RemoveAura(i);
1666 void Unit::RemoveAurasDueToSpell(uint32 spellId)
1668 for (int i = 0; i < 3; i++)
1670 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, i));
1671 if (iter != m_Auras.end())
1672 RemoveAura(iter);
1676 void Unit::RemoveAura(AuraMap::iterator &i)
1678 if ((*i).second->IsSingleTarget())
1680 std::list<Aura *> *scAuras = (*i).second->GetCaster()->GetSingleCastAuras();
1681 scAuras->remove((*i).second);
1683 // remove aura from party members when the caster turns off the aura
1684 if((*i).second->IsAreaAura())
1686 Unit *i_caster = (*i).second->GetCaster(), *i_target = (*i).second->GetTarget();
1687 if(i_caster->GetTypeId() == TYPEID_PLAYER && i_caster->GetGUID() == i_target->GetGUID())
1689 Group* pGroup = objmgr.GetGroupByLeader(((Player*)i_caster)->GetGroupLeader());
1690 float radius = GetRadius(sSpellRadius.LookupEntry((*i).second->GetSpellProto()->EffectRadiusIndex[(*i).second->GetEffIndex()]));
1691 if(pGroup)
1693 for(uint32 p=0;p<pGroup->GetMembersCount();p++)
1695 Unit* Target = ObjectAccessor::Instance().FindPlayer(pGroup->GetMemberGUID(p));
1696 if(!Target || Target->GetGUID() == i_caster->GetGUID())
1697 continue;
1698 Aura *t_aura = Target->GetAura((*i).second->GetId(), (*i).second->GetEffIndex());
1699 if (t_aura)
1700 if (t_aura->GetCaster()->GetGUID() == i_caster->GetGUID())
1701 Target->RemoveAura((*i).second->GetId(), (*i).second->GetEffIndex());
1706 m_AuraModifiers[(*i).second->GetModifier()->m_auraname] -= ((*i).second->GetModifier()->m_amount + 1);
1707 (*i).second->_RemoveAura();
1708 delete (*i).second;
1709 m_Auras.erase(i++);
1710 m_removedAuras++; // internal count used by unit update
1713 bool Unit::SetAurDuration(uint32 spellId, uint32 effindex,uint32 duration)
1715 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
1716 if (iter != m_Auras.end())
1718 (*iter).second->SetAuraDuration(duration);
1719 return true;
1721 return false;
1724 uint32 Unit::GetAurDuration(uint32 spellId, uint32 effindex)
1726 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
1727 if (iter != m_Auras.end())
1729 return (*iter).second->GetAuraDuration();
1731 return 0;
1734 void Unit::RemoveAllAuras()
1736 while (!m_Auras.empty())
1738 AuraMap::iterator iter = m_Auras.begin();
1739 RemoveAura(iter);
1743 void Unit::_RemoveStatsMods()
1745 ApplyStats(false);
1748 void Unit::_ApplyStatsMods()
1750 ApplyStats(true);
1753 void Unit::ApplyStats(bool apply)
1755 // TODO:
1756 // -- add --
1757 // spell crit formula: 5 + INT/100
1758 // skill formula: skill*0,04 for all, use defense skill for parry/dodge
1759 // froze spells gives + 50% change to crit
1761 if(GetTypeId() != TYPEID_PLAYER) return;
1763 PlayerCreateInfo* pinfo = ((Player*)this)->GetPlayerInfo();
1764 if(!pinfo) return;
1766 float val;
1767 uint32 val2,tem_att_power;
1769 // Armor
1770 val2 = 2*GetStat(STAT_AGILITY);
1772 ApplyArmorMod( val2, apply);
1774 // HP
1775 val2 = (GetStat(STAT_STAMINA) - pinfo->stamina)*10;
1777 ApplyMaxHealthMod( val2, apply);
1779 // MP
1780 if(getClass() != WARRIOR && getClass() != ROGUE)
1782 val2 = (GetStat(STAT_INTELLECT) - pinfo->intellect)*15;
1784 ApplyMaxPowerMod(POWER_MANA, val2, apply);
1788 float classrate = 0;
1790 // Melee Attack Power
1791 // && Melee DPS - (Damage Per Second)
1793 //Ranged
1794 if(getClass() == HUNTER)
1795 val2 = getLevel() * 2 + GetStat(STAT_AGILITY) * 2 - 20;
1796 else
1797 val2 = getLevel() + GetStat(STAT_AGILITY) * 2 - 20;
1799 if(!apply)
1800 tem_att_power = GetUInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER) + GetUInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER_MODS);
1802 ApplyModUInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER, val2, apply);
1804 if(apply)
1805 tem_att_power = GetUInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER) + GetUInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER_MODS);
1807 val = GetFloatValue(UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER);
1808 if(val>0)
1809 tem_att_power = uint32(val*tem_att_power);
1811 val = tem_att_power/14.0f * GetUInt32Value(UNIT_FIELD_RANGEDATTACKTIME)/1000;
1812 ApplyModFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, val, apply);
1813 ApplyModFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, val, apply);
1815 //Not-ranged
1817 switch(getClass())
1819 case WARRIOR: val2 = getLevel()*3 + GetStat(STAT_STRENGTH)*2 - 20; break;
1820 case PALADIN: val2 = getLevel()*3 + GetStat(STAT_STRENGTH)*2 - 20; break;
1821 case ROGUE: val2 = getLevel()*2 + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20; break;
1822 case HUNTER: val2 = getLevel()*2 + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20; break;
1823 case SHAMAN: val2 = getLevel()*2 + GetStat(STAT_STRENGTH)*2 - 20; break;
1824 case DRUID: val2 = GetStat(STAT_STRENGTH)*2 - 20; break;
1825 case MAGE: val2 = GetStat(STAT_STRENGTH) - 10; break;
1826 case PRIEST: val2 = GetStat(STAT_STRENGTH) - 10; break;
1827 case WARLOCK: val2 = GetStat(STAT_STRENGTH) - 10; break;
1829 tem_att_power = GetUInt32Value(UNIT_FIELD_ATTACK_POWER) + GetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS);
1831 ApplyModUInt32Value(UNIT_FIELD_ATTACK_POWER, val2, apply);
1833 if(apply)
1834 tem_att_power = GetUInt32Value(UNIT_FIELD_ATTACK_POWER) + GetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS);
1836 val = GetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER);
1837 if(val>0)
1838 tem_att_power = uint32(val*tem_att_power);
1840 val = tem_att_power/14.0f * GetUInt32Value(UNIT_FIELD_BASEATTACKTIME)/1000;
1842 ApplyModFloatValue(UNIT_FIELD_MINDAMAGE, val, apply);
1843 ApplyModFloatValue(UNIT_FIELD_MAXDAMAGE, val, apply);
1845 // critical
1846 if(getClass() == HUNTER) classrate = 53;
1847 else if(getClass() == ROGUE) classrate = 29;
1848 else classrate = 20;
1850 val = float(5 + GetStat(STAT_AGILITY)/classrate);
1852 ApplyModFloatValue(PLAYER_CRIT_PERCENTAGE, val, apply);
1854 //dodge
1855 if(getClass() == HUNTER) classrate = 26.5;
1856 else if(getClass() == ROGUE) classrate = 14.5;
1857 else classrate = 20;
1858 ///*+(Defense*0,04);
1859 if (getRace() == NIGHTELF)
1860 val = float(GetStat(STAT_AGILITY)/classrate + 1);
1861 else
1862 val = float(GetStat(STAT_AGILITY)/classrate);
1864 ApplyModFloatValue(PLAYER_DODGE_PERCENTAGE, val, apply);
1866 //parry
1867 val = float(5);
1869 ApplyModFloatValue(PLAYER_PARRY_PERCENTAGE, val, apply);
1871 //block
1872 val = float(GetStat(STAT_STRENGTH)/22);
1874 ApplyModFloatValue(PLAYER_BLOCK_PERCENTAGE, val, apply);
1878 void Unit::_RemoveAllAuraMods()
1880 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
1882 ApplyStats(false);
1883 (*i).second->ApplyModifier(false);
1884 ApplyStats(true);
1888 void Unit::_ApplyAllAuraMods()
1890 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
1892 ApplyStats(false);
1893 (*i).second->ApplyModifier(true);
1894 ApplyStats(true);
1898 // TODO: FIX-ME!!!
1899 /*void Unit::_UpdateAura()
1901 if(GetTypeId() != TYPEID_PLAYER || !m_Auras)
1902 return;
1904 Player* pThis = (Player*)this;
1906 Player* pGroupGuy;
1907 Group* pGroup;
1909 pGroup = objmgr.GetGroupByLeader(pThis->GetGroupLeader());
1911 if(!SetAffDuration(m_Auras->GetId(),this,6000))
1912 AddAura(m_Auras);
1914 if(!pGroup)
1915 return;
1916 else
1918 for(uint32 i=0;i<pGroup->GetMembersCount();i++)
1920 pGroupGuy = ObjectAccessor::Instance().FindPlayer(pGroup->GetMemberGUID(i));
1922 if(!pGroupGuy)
1923 continue;
1924 if(pGroupGuy->GetGUID() == GetGUID())
1925 continue;
1926 if(sqrt(
1927 (GetPositionX()-pGroupGuy->GetPositionX())*(GetPositionX()-pGroupGuy->GetPositionX())
1928 +(GetPositionY()-pGroupGuy->GetPositionY())*(GetPositionY()-pGroupGuy->GetPositionY())
1929 +(GetPositionZ()-pGroupGuy->GetPositionZ())*(GetPositionZ()-pGroupGuy->GetPositionZ())
1930 ) <=30)
1932 if(!pGroupGuy->SetAffDuration(m_Auras->GetId(),this,6000))
1933 pGroupGuy->AddAura(m_Auras);
1935 else
1937 if(m_removeAuraTimer == 0)
1939 printf("remove aura from %u\n", pGroupGuy->GetGUID());
1940 pGroupGuy->RemoveAura(m_Auras->GetId());
1945 if(m_removeAuraTimer > 0)
1946 m_removeAuraTimer -= 1;
1947 else
1948 m_removeAuraTimer = 4;
1951 Aura* Unit::GetAura(uint32 spellId, uint32 effindex)
1953 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
1954 if (iter != m_Auras.end())
1955 return iter->second;
1956 return NULL;
1959 float Unit::GetHostility(uint64 guid) const
1961 HostilList::const_iterator i;
1962 for ( i = m_hostilList.begin(); i!= m_hostilList.end(); i++)
1964 if(i->UnitGuid==guid)
1965 return i->Hostility;
1967 return 0.0f;
1970 void Unit::AddHostil(uint64 guid, float hostility)
1972 HostilList::iterator i;
1973 for(i = m_hostilList.begin(); i != m_hostilList.end(); i++)
1975 if(i->UnitGuid==guid)
1977 i->Hostility+=hostility;
1978 return;
1981 m_hostilList.push_back(Hostil(guid,hostility));
1984 void Unit::AddItemEnchant(uint32 enchant_id,bool apply)
1986 if (GetTypeId() != TYPEID_PLAYER)
1987 return;
1989 SpellItemEnchantment *pEnchant;
1990 pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
1991 if(!pEnchant)
1992 return;
1993 uint32 enchant_display = pEnchant->display_type;
1994 uint32 enchant_value1 = pEnchant->value1;
1995 //uint32 enchant_value2 = pEnchant->value2;
1996 uint32 enchant_spell_id = pEnchant->spellid;
1997 //uint32 enchant_aura_id = pEnchant->aura_id;
1998 //uint32 enchant_description = pEnchant->description;
1999 SpellEntry *enchantSpell_info = sSpellStore.LookupEntry(enchant_spell_id);
2001 if(enchant_display ==4)
2003 ApplyArmorMod(enchant_value1,apply);
2005 else if(enchant_display ==2)
2007 if(getClass() == CLASS_HUNTER)
2009 ApplyModUInt32Value(UNIT_FIELD_MINRANGEDDAMAGE,enchant_value1,apply);
2010 ApplyModUInt32Value(UNIT_FIELD_MAXRANGEDDAMAGE,enchant_value1,apply);
2012 else
2014 ApplyModUInt32Value(UNIT_FIELD_MINDAMAGE,enchant_value1,apply);
2015 ApplyModUInt32Value(UNIT_FIELD_MAXDAMAGE,enchant_value1,apply);
2018 else
2020 if(apply && ((Player*)this)->IsItemSpellToEquip(enchantSpell_info))
2022 Spell *spell = new Spell(this, enchantSpell_info, true, 0);
2023 SpellCastTargets targets;
2024 targets.setUnitTarget(this);
2025 spell->prepare(&targets);
2027 else RemoveAurasDueToSpell(enchant_spell_id);
2031 void Unit::AddDynObject(DynamicObject* dynObj)
2033 m_dynObj.push_back(dynObj);
2036 void Unit::RemoveDynObject(uint32 spellid)
2038 if(m_dynObj.empty())
2039 return;
2040 std::list<DynamicObject*>::iterator i, next;
2041 for (i = m_dynObj.begin(); i != m_dynObj.end(); i = next)
2043 next = i;
2044 next++;
2045 if(spellid == 0 || (*i)->GetSpellId() == spellid)
2047 (*i)->Delete();
2048 m_dynObj.erase(i);
2049 if(m_dynObj.empty())
2050 break;
2051 else
2052 next = m_dynObj.begin();
2057 void Unit::AddGameObject(GameObject* gameObj)
2059 m_gameObj.push_back(gameObj);
2062 void Unit::RemoveGameObject(uint32 spellid, bool del)
2064 if(m_gameObj.empty())
2065 return;
2066 std::list<GameObject*>::iterator i, next;
2067 for (i = m_gameObj.begin(); i != m_gameObj.end(); i = next)
2069 next = i;
2070 next++;
2071 if(spellid == 0 || (*i)->GetSpellId() == spellid)
2073 if(del)
2074 (*i)->Delete();
2076 m_gameObj.erase(i);
2077 if(m_gameObj.empty())
2078 break;
2079 else
2080 next = m_gameObj.begin();
2085 void Unit::SendSpellNonMeleeDamageLog(uint64 targetGUID,uint32 SpellID,uint32 Damage, uint8 DamageType,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked)
2087 WorldPacket data;
2088 data.Initialize(SMSG_SPELLNONMELEEDAMAGELOG);
2089 data << uint8(0xFF) << targetGUID;
2090 data << uint8(0xFF) << GetGUID();
2091 data << SpellID;
2092 data << Damage;
2093 data << DamageType; //damagetype
2094 data << AbsorbedDamage; //AbsorbedDamage
2095 data << Resist; //resist
2096 data << (uint8)PhysicalDamage;
2097 data << uint8(0);
2098 data << Blocked; //blocked
2099 data << uint8(0);
2100 SendMessageToSet( &data, true );
2103 void Unit::SendAttackStateUpdate(uint32 HitInfo, uint64 targetGUID, uint8 SwingType, uint32 DamageType, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, uint32 TargetState, uint32 BlockedAmount)
2105 sLog.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
2107 WorldPacket data;
2108 data.Initialize(SMSG_ATTACKERSTATEUPDATE);
2109 data << (uint32)HitInfo;
2110 data << uint8(0xFF) << GetGUID(); //source GUID
2111 data << uint8(0xFF) << targetGUID; //Target GUID
2112 data << (uint32)(Damage-AbsorbDamage);
2114 data << (uint8)SwingType;
2115 data << (uint32)DamageType;
2117 data << (float)Damage; //
2118 data << (uint32)Damage; // still need to double check damaga
2119 data << (uint32)AbsorbDamage;
2120 data << (uint32)Resist;
2121 data << (uint32)TargetState;
2123 if( AbsorbDamage == 0 ) //also 0x3E8 = 0x3E8, check when that happens
2124 data << (uint32)0;
2125 else
2126 data << (uint32)-1;
2128 data << (uint32)0;
2129 data << (uint32)BlockedAmount;
2131 SendMessageToSet( &data, true );
2134 void Unit::setPowerType(Powers PowerType)
2136 uint32 tem_bytes_0 = GetUInt32Value(UNIT_FIELD_BYTES_0);
2137 SetUInt32Value(UNIT_FIELD_BYTES_0,((tem_bytes_0<<8)>>8) + (uint32(PowerType)<<24));
2138 Powers new_powertype = getPowerType();
2139 switch(new_powertype)
2141 default:
2142 case POWER_MANA:
2143 break;
2144 case POWER_RAGE:
2145 SetMaxPower(POWER_RAGE,1000);
2146 SetPower( POWER_RAGE,0);
2147 break;
2148 case POWER_FOCUS:
2149 SetMaxPower(POWER_FOCUS,100);
2150 SetPower( POWER_FOCUS,100);
2151 break;
2152 case POWER_ENERGY:
2153 SetMaxPower(POWER_ENERGY,100);
2154 SetPower( POWER_ENERGY,100);
2155 break;
2156 case POWER_HAPPINESS:
2157 SetMaxPower(POWER_HAPPINESS,1000000);
2158 SetPower(POWER_HAPPINESS,1000000);
2159 break;
2163 FactionTemplateEntry* Unit::getFactionTemplateEntry() const
2165 FactionTemplateEntry* entry = sFactionTemplateStore.LookupEntry(getFaction());
2166 if(!entry)
2168 static uint64 guid = 0; // prevent repeating spam same faction problem
2170 if(GetGUID() != guid)
2172 if(GetTypeId() == TYPEID_PLAYER)
2173 sLog.outError("Player %s have invalide faction (fuction template id) #%u", ((Player*)this)->GetName(), getFaction());
2174 else
2175 sLog.outError("Creature (template id: %u) have invalide faction (fuction template id) #%u", ((Creature*)this)->GetCreatureInfo()->Entry, getFaction());
2176 guid = GetGUID();
2179 return entry;
2182 bool Unit::Attack(Unit *victim)
2184 if(victim == this)
2185 return false;
2187 if (m_attacking)
2189 if (m_attacking == victim)
2190 return false;
2191 AttackStop();
2193 addUnitState(UNIT_STAT_ATTACKING);
2194 SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_ATTACKING);
2195 m_attacking = victim;
2196 m_attacking->_addAttacker(this);
2197 return true;
2200 bool Unit::AttackStop()
2202 if (!m_attacking)
2203 return false;
2205 m_attacking->_removeAttacker(this);
2206 m_attacking = NULL;
2207 clearUnitState(UNIT_STAT_ATTACKING);
2208 RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_ATTACKING);
2209 return true;
2212 bool Unit::isInCombatWithPlayer() const
2214 if(getVictim() && getVictim()->GetTypeId() == TYPEID_PLAYER)
2215 return true;
2217 for(AttackerSet::const_iterator i = m_attackers.begin(); i != m_attackers.end(); ++i)
2219 if((*i)->GetTypeId() == TYPEID_PLAYER) return true;
2221 return false;
2224 void Unit::RemoveAllAttackers()
2226 while (m_attackers.size() != 0)
2228 AttackerSet::iterator iter = m_attackers.begin();
2229 if(!(*iter)->AttackStop())
2231 sLog.outError("WORLD: Unit has an attacker that isnt attacking it!");
2232 m_attackers.erase(iter);
2237 void Unit::SetStateFlag(uint32 index, uint32 newFlag )
2239 index |= newFlag;
2242 void Unit::RemoveStateFlag(uint32 index, uint32 oldFlag )
2244 index &= ~ oldFlag;
2247 Creature* Unit::GetPet() const
2249 uint64 pet_guid = GetPetGUID();
2250 if(pet_guid)
2252 Creature* pet = ObjectAccessor::Instance().GetCreature(*this, pet_guid);
2253 if(!pet)
2255 sLog.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid));
2256 const_cast<Unit*>(this)->SetPet(0);
2258 return pet;
2260 else
2261 return NULL;
2264 void Unit::SetPet(Creature* pet)
2266 SetUInt64Value(UNIT_FIELD_SUMMON,pet ? pet->GetGUID() : 0);
2269 void Unit::UnsummonTotem(int8 slot)
2271 uint64 t_guids[4] = { m_TotemSlot1, m_TotemSlot2, m_TotemSlot3, m_TotemSlot4 };
2272 WorldPacket data;
2274 for (int8 i = 0; i < 4; i++)
2276 if (i != slot && slot != -1) continue;
2277 Creature *OldTotem = ObjectAccessor::Instance().GetCreature(*this, t_guids[i]);
2279 if(OldTotem)
2281 data.Initialize(SMSG_GAMEOBJECT_DESPAWN_ANIM);
2282 data << t_guids[i];
2283 SendMessageToSet(&data, true);
2285 data.Initialize(SMSG_DESTROY_OBJECT);
2286 data << t_guids[i];
2287 SendMessageToSet(&data, true);
2288 MapManager::Instance().GetMap(OldTotem->GetMapId())->Remove(OldTotem, true);
2289 OldTotem = NULL;