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