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
22 #include "WorldPacket.h"
23 #include "WorldSession.h"
25 #include "ObjectMgr.h"
33 #include "SpellAuras.h"
34 #include "MapManager.h"
35 #include "ObjectAccessor.h"
36 #include "CreatureAI.h"
43 Unit::Unit() : Object()
45 m_objectType
|= TYPE_UNIT
;
46 m_objectTypeId
= TYPEID_UNIT
;
53 m_currentSpell
= NULL
;
54 m_currentMeleeSpell
= NULL
;
56 m_TotemSlot1
= m_TotemSlot2
= m_TotemSlot3
= m_TotemSlot4
= 0;
58 //m_AurasCheck = 2000;
59 //m_removeAuraTimer = 4;
64 m_immuneToMechanic
= 0;
75 for (int i
= 0; i
< TOTAL_AURAS
; i
++)
76 m_AuraModifiers
[i
] = -1;
82 m_modSpellHitChance
= 0;
83 m_baseSpellCritChance
= 5;
84 m_spellCritSchool
.clear();
85 m_reflectSpellSchool
.clear();
87 m_damageDoneCreature
.clear();
94 void Unit::Update( uint32 p_time
)
96 /*if(p_time > m_AurasCheck)
101 m_AurasCheck -= p_time;*/
103 _UpdateSpells( p_time
);
104 _UpdateHostil( p_time
);
106 if(m_attackTimer
> 0)
108 if(p_time
>= m_attackTimer
)
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
));
125 double speed
= GetSpeed(run
? MOVE_RUN
: MOVE_WALK
);
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
)
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
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
)
159 m_attackTimer
= time
;
164 if (GetTypeId() == TYPEID_PLAYER
)
166 m_attackTimer
= GetUInt32Value(UNIT_FIELD_RANGEDATTACKTIME
);
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
183 float reach
= GetFloatValue(UNIT_FIELD_COMBATREACH
);
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
)
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();
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;
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
);
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
264 if (pVictim
->GetTypeId() == TYPEID_PLAYER
)
266 DEBUG_LOG("We are dead, loosing 10 percents durability");
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
);
281 Creature
*pet
= pVictim
->GetPet();
282 if(pet
&& pet
->isPet())
284 pet
->setDeathState(JUST_DIED
);
285 pet
->SendAttackStop(attackerGuid
);
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
);
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;
311 if(GetTypeId() == TYPEID_PLAYER
)
314 player
= (Player
*)this;
315 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
318 else if(((Creature
*)this)->isPet())
320 Unit
* owner
= ((Pet
*)this)->GetOwner();
323 else if(owner
->GetTypeId() == TYPEID_PLAYER
)
325 player
= (Player
*)owner
;
332 player
->CalculateHonor(pVictim
);
333 player
->CalculateReputation(pVictim
);
337 DEBUG_LOG("DealDamageIsPvE");
338 uint32 xp
= MaNGOS::XP::Gain(player
, pVictim
);
340 entry
= pVictim
->GetUInt32Value(OBJECT_FIELD_ENTRY
);
342 Group
*pGroup
= objmgr
.GetGroupByLeader(player
->GetGroupLeader());
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
));
352 if(GetDistanceSq(pGroupGuy
) > sWorld
.getConfig(CONFIG_GETXP_DISTANCE
))
354 if(uint32(abs((int)pGroupGuy
->getLevel() - (int)pVictim
->getLevel())) > sWorld
.getConfig(CONFIG_GETXP_LEVELDIFF
))
356 pGroupGuy
->GiveXP(xp
, pVictim
);
357 pGroupGuy
->KilledMonster(entry
, victimGuid
);
362 DEBUG_LOG("Player kill enemy alone");
363 player
->GiveXP(xp
, pVictim
);
364 player
->KilledMonster(entry
,victimGuid
);
370 DEBUG_LOG("Monster kill Monster");
371 SendAttackStop(victimGuid
);
372 addUnitState(UNIT_STAT_DIED
);
378 DEBUG_LOG("DealDamageAlive");
379 pVictim
->SetHealth(health
- damage
);
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);
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
);
421 sLog
.outError("WORLD: unknown spell id %i\n", spellId
);
425 Spell
*spell
= new Spell(this, spellInfo
, triggered
, 0);
428 SpellCastTargets targets
;
429 targets
.setUnitTarget( Victim
);
430 spell
->prepare(&targets
);
434 void Unit::SpellNonMeleeDamageLog(Unit
*pVictim
, uint32 spellID
, uint32 damage
)
437 if(!this || !pVictim
)
439 if(!this->isAlive() || !pVictim
->isAlive())
443 int32 critchance
= m_baseSpellCritChance
;
445 CreatureInfo
*cinfo
= NULL
;
446 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
447 cinfo
= ((Creature
*)pVictim
)->GetCreatureInfo();
449 SpellEntry
*spellInfo
= sSpellStore
.LookupEntry(spellID
);
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);
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
;
474 absorb
= CalDamageAbsorb(pVictim
,spellInfo
->School
,damage
,&resist
);
478 if(m_modSpellHitChance
+100 < urand(0,100))
480 SendAttackStateUpdate(HITINFO_HITSTRANGESOUND1
|HITINFO_MISS
, pVictim
->GetGUID(), 1, spellInfo
->School
, 0, 0,0,1,0);
484 if( (damage
-absorb
-resist
)<= 0 )
486 SendAttackStateUpdate(HITINFO_HITSTRANGESOUND1
|HITINFO_NOACTION
, pVictim
->GetGUID(), 1, spellInfo
->School
, damage
, absorb
,resist
,1,0);
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
)
500 if(!this || !pVictim
|| !isAlive() || !pVictim
->isAlive())
506 int32 critchance
= m_baseSpellCritChance
;
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
);
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);
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
;
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
);
545 data
.Initialize(SMSG_PERIODICAURALOG
);
546 data
<< uint8(0xFF) << pVictim
->GetGUID();
547 data
<< uint8(0xFF) << this->GetGUID();
548 data
<< spellProto
->Id
;
551 data
<< mod
->m_auraname
;
552 data
<< (uint32
)(mod
->m_amount
);
553 data
<< spellProto
->School
;
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);
576 SetHealth(GetMaxHealth());
578 else if(mod
->m_auraname
== SPELL_AURA_PERIODIC_LEECH
)
583 if(mod
->m_auraname
!= spellInfo
->EffectApplyAuraName
[x
])
585 if(pVictim
->GetHealth() - mod
->m_amount
> 0)
586 tmpvalue
= uint32(mod
->m_amount
*spellInfo
->EffectMultipleValue
[x
]);
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();
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
)
607 if(mod
->m_auraname
!= spellInfo
->EffectApplyAuraName
[x
])
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
]);
616 tmpvalue
= uint32(pVictim
->GetPower(POWER_MANA
)*spellInfo
->EffectMultipleValue
[x
]);
617 pVictim
->SetPower(POWER_MANA
,0);
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)
629 SetPower(Powers(mod
->m_miscvalue
),GetPower(Powers(mod
->m_miscvalue
))+mod
->m_amount
);
633 void Unit::HandleEmoteCommand(uint32 anim_id
)
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;
649 bool removeAura
=false;
653 if(!pVictim
->isAlive())
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
;
670 AbsorbDamage
= (*i
)->m_totalAbsorb
- (*i
)->m_currAbsorb
;
671 (*i
)->m_currAbsorb
= (*i
)->m_totalAbsorb
;
675 if((*i
)->m_modType
== SPELL_AURA_MANA_SHIELD
)
679 if(spellInfo
->EffectApplyAuraName
[x
] == SPELL_AURA_MANA_SHIELD
)
681 multiple
= spellInfo
->EffectMultipleValue
[x
];
684 currentPower
= pVictim
->GetPower(POWER_MANA
);
685 if ( (float)(currentPower
) > AbsorbDamage
*multiple
)
687 pVictim
->SetPower(POWER_MANA
, (uint32
)(currentPower
-AbsorbDamage
*multiple
) );
691 pVictim
->SetPower(POWER_MANA
, 0 );
696 pVictim
->RemoveAurasDueToSpell((*i
)->m_spellId
);
702 uint32 armor
= pVictim
->GetArmor();
703 float tmpvalue
= armor
/(pVictim
->getLevel()*85.0 +400.0 +armor
);
708 AbsorbDamage
+= uint32(damage
* tmpvalue
);
709 if(AbsorbDamage
> damage
)
710 AbsorbDamage
= damage
;
714 uint32 tmpvalue2
= pVictim
->GetResistance(SpellSchools(School
));
715 *resist
+= uint32(damage
*tmpvalue2
*0.0025*pVictim
->getLevel()/getLevel());
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);
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
;
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
;
757 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() != TYPEID_PLAYER
&& ((Creature
*)pVictim
)->GetCreatureInfo()->type
!= 8 )
758 ((Player
*)this)->UpdateMeleeSkillWeapon();
764 *hitInfo
= HITINFO_HITSTRANGESOUND1
| HITINFO_HITSTRANGESOUND2
| HITINFO_CRITICALHIT
765 | HITINFO_NORMALSWING2
| 0x8; // 0xEA
768 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL
);
771 case MELEE_HIT_PARRY
:
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
);
784 case MELEE_HIT_DODGE
:
788 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
789 ((Player
*)pVictim
)->UpdateDefense();
791 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
794 case MELEE_HIT_BLOCK
:
795 *blocked_amount
= (pVictim
->GetUnitBlockValue() * (pVictim
->GetStat(STAT_STRENGTH
) / 20));
797 if (*blocked_amount
< *damage
)
798 *damage
-= *blocked_amount
;
802 if (pVictim
->GetUnitBlockValue())
803 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD
);
805 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
809 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
810 ((Player
*)pVictim
)->UpdateDefense();
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;
819 *damage
= *damage
* reducePerc
/ 100;
820 *hitInfo
|= HITINFO_GLANCING
;
823 case MELEE_HIT_CRUSHING
:
824 // 150% normal damage
825 *damage
+= (*damage
/ 2);
826 *hitInfo
|= HITINFO_CRUSHING
;
827 // TODO: victimState, victim animation?
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
;
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();
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
);
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
);
871 procdamage
->procCharges
-= 1;
875 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
877 ProcTriggerDamage
*procdamage
= (*i
).second
->GetProcDamage();
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
);
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
))
900 procspell
->procCharges
-= 1;
901 SpellEntry
*spellInfo
= sSpellStore
.LookupEntry((*i
).second
->GetProcSpell()->trigger
);
905 sLog
.outError("WORLD: unknown spell id %i\n", (*i
).second
->GetProcSpell()->trigger
);
909 Spell
*spell
= new Spell(pVictim
, spellInfo
, true, 0);
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
))
930 procspell
->procCharges
-= 1;
931 SpellEntry
*spellInfo
= sSpellStore
.LookupEntry((*i
).second
->GetProcSpell()->trigger
);
935 sLog
.outError("WORLD: unknown spell id %i\n", (*i
).second
->GetProcSpell()->trigger
);
939 Spell
*spell
= new Spell(pVictim
, spellInfo
, true, 0);
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
));
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
))
969 if (!pVictim
->isAlive())
971 SendAttackStop(pVictim
->GetGUID());
978 if (m_currentMeleeSpell
)
980 m_currentMeleeSpell
->cast();
985 uint32 hitInfo
= HITINFO_NORMALSWING2
|HITINFO_HITSTRANGESOUND1
;
986 uint32 damageType
= NORMAL_DAMAGE
;
987 uint32 victimState
= VICTIMSTATE_NORMAL
;
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
)
998 SendAttackStateUpdate (hitInfo
, pVictim
->GetGUID(), 1, damageType
, damage
, absorbed_dmg
, resisted_dmg
, victimState
, blocked_dmg
);
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
);
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
);
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
; }
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.");
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
;
1120 min_damage
= GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE
);
1121 max_damage
= GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE
);
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)
1136 float diff
= max_damage
- min_damage
+ 1;
1138 dmg
= float (rand()%(uint32
)diff
+ (uint32
)min_damage
);
1142 void Unit::SendAttackStop(uint64 victimGuid
)
1145 data
.Initialize( SMSG_ATTACKSTOP
);
1146 data
<< uint8(0xFF) << GetGUID();
1147 data
<< uint8(0xFF) << victimGuid
;
1148 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
);
1164 return GetUnitMeleeSkill();
1167 float Unit::GetUnitDodgeChance() const
1169 if(hasUnitState(UNIT_STAT_STUNDED
))
1172 return GetTypeId() == TYPEID_PLAYER
? m_floatValues
[ PLAYER_DODGE_PERCENTAGE
] : 5;
1175 float Unit::GetUnitParryChance() const
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
);
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
)
1201 float Unit::GetUnitBlockChance() const
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
);
1216 uint16
Unit::GetWeaponSkillValue() const
1218 if(GetTypeId() == TYPEID_PLAYER
)
1221 Item
*item
= ((Player
*)this)->GetItemByPos (INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
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
);
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
)
1242 if( m_currentSpell
->m_spellInfo
->Id
== 75 && GetTypeId() == TYPEID_PLAYER
)
1243 setAttackTimer( 0, true );
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();
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.
1284 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
1286 (*i
).second
->SetUpdated(false);
1288 for (AuraMap::iterator i
= m_Auras
.begin(), next
; i
!= m_Auras
.end(); i
= next
)
1294 // prevent double update
1295 if ((*i
).second
->IsUpdated())
1297 (*i
).second
->SetUpdated(true);
1298 (*i
).second
->Update( time
);
1299 // several auras can be deleted due to update
1302 if (m_Auras
.empty()) break;
1303 next
= m_Auras
.begin();
1309 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end();)
1313 if ( !(*i
).second
->GetAuraDuration() && !(*i
).second
->IsPermanent() )
1328 if(m_dynObj
.empty())
1330 std::list
<DynamicObject
*>::iterator ite
, dnext
;
1331 for (ite
= m_dynObj
.begin(); ite
!= m_dynObj
.end(); ite
= dnext
)
1335 //(*i)->Update( difftime );
1336 if( (*ite
)->isFinished() )
1339 m_dynObj
.erase(ite
);
1340 if(m_dynObj
.empty())
1343 dnext
= m_dynObj
.begin();
1346 if(m_gameObj
.empty())
1348 std::list
<GameObject
*>::iterator ite1
, dnext1
;
1349 for (ite1
= m_gameObj
.begin(); ite1
!= m_gameObj
.end(); ite1
= dnext1
)
1353 //(*i)->Update( difftime );
1354 if( (*ite1
)->isFinished() )
1357 m_gameObj
.erase(ite1
);
1358 if(m_gameObj
.empty())
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())
1380 iter
= m_hostilList
.begin();
1386 Unit
* Unit::SelectHostilTarget()
1388 if(!m_hostilList
.size())
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
);
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
;
1417 m_currentSpell
->cancel();
1418 delete m_currentSpell
;
1419 m_currentSpell
= NULL
;
1421 m_currentSpell
= pSpell
;
1425 void Unit::InterruptSpell()
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
)
1467 modifier
+= (*i
).second
->GetModifier()->m_amount
;
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();
1490 if (!Aur
->IsPassive()) // passive auras stack with all
1492 if (!RemoveNoStackAurasDueToAura(Aur
))
1495 return false; // couldnt remove conflicting aura with higher rank
1496 } // couldnt remove conflicting aura with higher rank
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
)
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())
1523 next
= scAuras
->begin();
1526 scAuras
->push_back(Aur
);
1532 void Unit::RemoveRankAurasDueToSpell(uint32 spellId
)
1534 SpellEntry
*spellInfo
= sSpellStore
.LookupEntry(spellId
);
1537 AuraMap::iterator i
,next
;
1538 for (i
= m_Auras
.begin(); i
!= m_Auras
.end(); i
= 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() )
1552 next
= m_Auras
.begin();
1558 bool Unit::RemoveNoStackAurasDueToAura(Aura
*Aur
)
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
)
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
))
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() )
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
1610 if( m_Auras
.empty() )
1613 next
= m_Auras
.begin();
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()])
1635 case TARGET_AE_E_INSTANT
:
1637 case TARGET_INFRONT
:
1638 case TARGET_DUELVSPLAYER
:
1639 case TARGET_AE_E_CHANNEL
:
1640 case TARGET_AE_SELECTED
:
1645 positive
= ((*i
).second
->GetSpellProto()->AttributesEx
& (1<<7)) ? false : true;
1654 if(i
== m_Auras
.end()) return;
1659 void Unit::RemoveAura(uint32 spellId
, uint32 effindex
)
1661 AuraMap::iterator i
= m_Auras
.find( spellEffectPair(spellId
, effindex
) );
1662 if(i
!= m_Auras
.end())
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())
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()]));
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())
1698 Aura
*t_aura
= Target
->GetAura((*i
).second
->GetId(), (*i
).second
->GetEffIndex());
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();
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
);
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();
1734 void Unit::RemoveAllAuras()
1736 while (!m_Auras
.empty())
1738 AuraMap::iterator iter
= m_Auras
.begin();
1743 void Unit::_RemoveStatsMods()
1748 void Unit::_ApplyStatsMods()
1753 void Unit::ApplyStats(bool apply
)
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();
1767 uint32 val2
,tem_att_power
;
1770 val2
= 2*GetStat(STAT_AGILITY
);
1772 ApplyArmorMod( val2
, apply
);
1775 val2
= (GetStat(STAT_STAMINA
) - pinfo
->stamina
)*10;
1777 ApplyMaxHealthMod( val2
, apply
);
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)
1794 if(getClass() == HUNTER
)
1795 val2
= getLevel() * 2 + GetStat(STAT_AGILITY
) * 2 - 20;
1797 val2
= getLevel() + GetStat(STAT_AGILITY
) * 2 - 20;
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
);
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
);
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
);
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
);
1834 tem_att_power
= GetUInt32Value(UNIT_FIELD_ATTACK_POWER
) + GetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS
);
1836 val
= GetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER
);
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
);
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
);
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);
1862 val
= float(GetStat(STAT_AGILITY
)/classrate
);
1864 ApplyModFloatValue(PLAYER_DODGE_PERCENTAGE
, val
, apply
);
1869 ApplyModFloatValue(PLAYER_PARRY_PERCENTAGE
, val
, apply
);
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
)
1883 (*i
).second
->ApplyModifier(false);
1888 void Unit::_ApplyAllAuraMods()
1890 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
1893 (*i
).second
->ApplyModifier(true);
1899 /*void Unit::_UpdateAura()
1901 if(GetTypeId() != TYPEID_PLAYER || !m_Auras)
1904 Player* pThis = (Player*)this;
1909 pGroup = objmgr.GetGroupByLeader(pThis->GetGroupLeader());
1911 if(!SetAffDuration(m_Auras->GetId(),this,6000))
1918 for(uint32 i=0;i<pGroup->GetMembersCount();i++)
1920 pGroupGuy = ObjectAccessor::Instance().FindPlayer(pGroup->GetMemberGUID(i));
1924 if(pGroupGuy->GetGUID() == GetGUID())
1927 (GetPositionX()-pGroupGuy->GetPositionX())*(GetPositionX()-pGroupGuy->GetPositionX())
1928 +(GetPositionY()-pGroupGuy->GetPositionY())*(GetPositionY()-pGroupGuy->GetPositionY())
1929 +(GetPositionZ()-pGroupGuy->GetPositionZ())*(GetPositionZ()-pGroupGuy->GetPositionZ())
1932 if(!pGroupGuy->SetAffDuration(m_Auras->GetId(),this,6000))
1933 pGroupGuy->AddAura(m_Auras);
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;
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
;
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
;
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
;
1981 m_hostilList
.push_back(Hostil(guid
,hostility
));
1984 void Unit::AddItemEnchant(uint32 enchant_id
,bool apply
)
1986 if (GetTypeId() != TYPEID_PLAYER
)
1989 SpellItemEnchantment
*pEnchant
;
1990 pEnchant
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
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
);
2014 ApplyModUInt32Value(UNIT_FIELD_MINDAMAGE
,enchant_value1
,apply
);
2015 ApplyModUInt32Value(UNIT_FIELD_MAXDAMAGE
,enchant_value1
,apply
);
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())
2040 std::list
<DynamicObject
*>::iterator i
, next
;
2041 for (i
= m_dynObj
.begin(); i
!= m_dynObj
.end(); i
= next
)
2045 if(spellid
== 0 || (*i
)->GetSpellId() == spellid
)
2049 if(m_dynObj
.empty())
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())
2066 std::list
<GameObject
*>::iterator i
, next
;
2067 for (i
= m_gameObj
.begin(); i
!= m_gameObj
.end(); i
= next
)
2071 if(spellid
== 0 || (*i
)->GetSpellId() == spellid
)
2077 if(m_gameObj
.empty())
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
)
2088 data
.Initialize(SMSG_SPELLNONMELEEDAMAGELOG
);
2089 data
<< uint8(0xFF) << targetGUID
;
2090 data
<< uint8(0xFF) << GetGUID();
2093 data
<< DamageType
; //damagetype
2094 data
<< AbsorbedDamage
; //AbsorbedDamage
2095 data
<< Resist
; //resist
2096 data
<< (uint8
)PhysicalDamage
;
2098 data
<< Blocked
; //blocked
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");
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
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
)
2145 SetMaxPower(POWER_RAGE
,1000);
2146 SetPower( POWER_RAGE
,0);
2149 SetMaxPower(POWER_FOCUS
,100);
2150 SetPower( POWER_FOCUS
,100);
2153 SetMaxPower(POWER_ENERGY
,100);
2154 SetPower( POWER_ENERGY
,100);
2156 case POWER_HAPPINESS
:
2157 SetMaxPower(POWER_HAPPINESS
,1000000);
2158 SetPower(POWER_HAPPINESS
,1000000);
2163 FactionTemplateEntry
* Unit::getFactionTemplateEntry() const
2165 FactionTemplateEntry
* entry
= sFactionTemplateStore
.LookupEntry(getFaction());
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());
2175 sLog
.outError("Creature (template id: %u) have invalide faction (fuction template id) #%u", ((Creature
*)this)->GetCreatureInfo()->Entry
, getFaction());
2182 bool Unit::Attack(Unit
*victim
)
2189 if (m_attacking
== victim
)
2193 addUnitState(UNIT_STAT_ATTACKING
);
2194 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_ATTACKING
);
2195 m_attacking
= victim
;
2196 m_attacking
->_addAttacker(this);
2200 bool Unit::AttackStop()
2205 m_attacking
->_removeAttacker(this);
2207 clearUnitState(UNIT_STAT_ATTACKING
);
2208 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_ATTACKING
);
2212 bool Unit::isInCombatWithPlayer() const
2214 if(getVictim() && getVictim()->GetTypeId() == TYPEID_PLAYER
)
2217 for(AttackerSet::const_iterator i
= m_attackers
.begin(); i
!= m_attackers
.end(); ++i
)
2219 if((*i
)->GetTypeId() == TYPEID_PLAYER
) return true;
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
)
2242 void Unit::RemoveStateFlag(uint32 index
, uint32 oldFlag
)
2247 Creature
* Unit::GetPet() const
2249 uint64 pet_guid
= GetPetGUID();
2252 Creature
* pet
= ObjectAccessor::Instance().GetCreature(*this, pet_guid
);
2255 sLog
.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid
));
2256 const_cast<Unit
*>(this)->SetPet(0);
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
};
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
]);
2281 data
.Initialize(SMSG_GAMEOBJECT_DESPAWN_ANIM
);
2283 SendMessageToSet(&data
, true);
2285 data
.Initialize(SMSG_DESTROY_OBJECT
);
2287 SendMessageToSet(&data
, true);
2288 MapManager::Instance().GetMap(OldTotem
->GetMapId())->Remove(OldTotem
, true);