2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
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
23 #include "SharedDefines.h"
24 #include "SpellAuras.h"
26 /*#######################################
28 ######## PLAYERS STAT SYSTEM ########
30 #######################################*/
32 bool Player::UpdateStats(Stats stat
)
34 if(stat
> STAT_SPIRIT
)
37 // value = ((base_value * base_pct) + total_value) * total_pct
38 float value
= GetTotalStatValue(stat
);
40 SetStat(stat
, int32(value
));
42 if(stat
== STAT_STAMINA
|| stat
== STAT_INTELLECT
)
46 pet
->UpdateStats(stat
);
52 UpdateShieldBlockValue();
56 UpdateAllCritPercentages();
57 UpdateDodgePercentage();
59 case STAT_STAMINA
: UpdateMaxHealth(); break;
61 UpdateMaxPower(POWER_MANA
);
62 UpdateAllSpellCritChances();
63 UpdateArmor(); //SPELL_AURA_MOD_RESISTANCE_OF_INTELLECT_PERCENT, only armor currently
72 // Need update (exist AP from stat auras)
73 UpdateAttackPowerAndDamage();
74 UpdateAttackPowerAndDamage(true);
76 UpdateSpellDamageAndHealingBonus();
79 // Update ratings in exist SPELL_AURA_MOD_RATING_FROM_STAT and only depends from stat
81 AuraList
const& modRatingFromStat
= GetAurasByType(SPELL_AURA_MOD_RATING_FROM_STAT
);
82 for(AuraList::const_iterator i
= modRatingFromStat
.begin();i
!= modRatingFromStat
.end(); ++i
)
83 if (Stats((*i
)->GetMiscBValue()) == stat
)
84 mask
|= (*i
)->GetMiscValue();
87 for (uint32 rating
= 0; rating
< MAX_COMBAT_RATING
; ++rating
)
88 if (mask
& (1 << rating
))
89 ApplyRatingMod(CombatRating(rating
), 0, true);
94 void Player::ApplySpellPowerBonus(int32 amount
, bool apply
)
96 m_baseSpellPower
+=apply
?amount
:-amount
;
98 // For speed just update for client
99 ApplyModUInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS
, amount
, apply
);
100 for(int i
= SPELL_SCHOOL_HOLY
; i
< MAX_SPELL_SCHOOL
; ++i
)
101 ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS
+i
, amount
, apply
);;
104 void Player::UpdateSpellDamageAndHealingBonus()
106 // Magic damage modifiers implemented in Unit::SpellDamageBonus
107 // This information for client side use only
108 // Get healing bonus for all schools
109 SetStatInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS
, SpellBaseHealingBonus(SPELL_SCHOOL_MASK_ALL
));
110 // Get damage bonus for all schools
111 for(int i
= SPELL_SCHOOL_HOLY
; i
< MAX_SPELL_SCHOOL
; ++i
)
112 SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS
+i
, SpellBaseDamageBonus(SpellSchoolMask(1 << i
)));
115 bool Player::UpdateAllStats()
117 for (int i
= STAT_STRENGTH
; i
< MAX_STATS
; ++i
)
119 float value
= GetTotalStatValue(Stats(i
));
120 SetStat(Stats(i
), (int32
)value
);
124 // calls UpdateAttackPowerAndDamage() in UpdateArmor for SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR
125 UpdateAttackPowerAndDamage(true);
128 for(int i
= POWER_MANA
; i
< MAX_POWERS
; ++i
)
129 UpdateMaxPower(Powers(i
));
131 UpdateAllCritPercentages();
132 UpdateAllSpellCritChances();
133 UpdateDefenseBonusesMod();
134 UpdateShieldBlockValue();
135 UpdateArmorPenetration();
136 UpdateSpellDamageAndHealingBonus();
138 UpdateExpertise(BASE_ATTACK
);
139 UpdateExpertise(OFF_ATTACK
);
140 for (int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; ++i
)
141 UpdateResistances(i
);
146 void Player::UpdateResistances(uint32 school
)
148 if(school
> SPELL_SCHOOL_NORMAL
)
150 float value
= GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START
+ school
));
151 SetResistance(SpellSchools(school
), int32(value
));
155 pet
->UpdateResistances(school
);
161 void Player::UpdateArmor()
164 UnitMods unitMod
= UNIT_MOD_ARMOR
;
166 value
= GetModifierValue(unitMod
, BASE_VALUE
); // base armor (from items)
167 value
*= GetModifierValue(unitMod
, BASE_PCT
); // armor percent from items
168 value
+= GetStat(STAT_AGILITY
) * 2.0f
; // armor bonus from stats
169 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
);
171 //add dynamic flat mods
172 AuraList
const& mResbyIntellect
= GetAurasByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT
);
173 for(AuraList::const_iterator i
= mResbyIntellect
.begin();i
!= mResbyIntellect
.end(); ++i
)
175 Modifier
* mod
= (*i
)->GetModifier();
176 if(mod
->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
177 value
+= int32(GetStat(Stats((*i
)->GetMiscBValue())) * mod
->m_amount
/ 100.0f
);
180 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
182 SetArmor(int32(value
));
188 UpdateAttackPowerAndDamage(); // armor dependent auras update for SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR
191 float Player::GetHealthBonusFromStamina()
193 float stamina
= GetStat(STAT_STAMINA
);
195 float baseStam
= stamina
< 20 ? stamina
: 20;
196 float moreStam
= stamina
- baseStam
;
198 return baseStam
+ (moreStam
*10.0f
);
201 float Player::GetManaBonusFromIntellect()
203 float intellect
= GetStat(STAT_INTELLECT
);
205 float baseInt
= intellect
< 20 ? intellect
: 20;
206 float moreInt
= intellect
- baseInt
;
208 return baseInt
+ (moreInt
*15.0f
);
211 void Player::UpdateMaxHealth()
213 UnitMods unitMod
= UNIT_MOD_HEALTH
;
215 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreateHealth();
216 value
*= GetModifierValue(unitMod
, BASE_PCT
);
217 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + GetHealthBonusFromStamina();
218 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
220 SetMaxHealth((uint32
)value
);
223 void Player::UpdateMaxPower(Powers power
)
225 UnitMods unitMod
= UnitMods(UNIT_MOD_POWER_START
+ power
);
227 uint32 create_power
= GetCreatePowers(power
);
229 // ignore classes without mana
230 float bonusPower
= (power
== POWER_MANA
&& create_power
> 0) ? GetManaBonusFromIntellect() : 0;
232 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + create_power
;
233 value
*= GetModifierValue(unitMod
, BASE_PCT
);
234 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + bonusPower
;
235 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
237 SetMaxPower(power
, uint32(value
));
240 void Player::ApplyFeralAPBonus(int32 amount
, bool apply
)
242 m_baseFeralAP
+= apply
? amount
:-amount
;
243 UpdateAttackPowerAndDamage();
246 void Player::UpdateAttackPowerAndDamage(bool ranged
)
249 float level
= float(getLevel());
251 UnitMods unitMod
= ranged
? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
253 uint16 index
= UNIT_FIELD_ATTACK_POWER
;
254 uint16 index_mod
= UNIT_FIELD_ATTACK_POWER_MODS
;
255 uint16 index_mult
= UNIT_FIELD_ATTACK_POWER_MULTIPLIER
;
259 index
= UNIT_FIELD_RANGED_ATTACK_POWER
;
260 index_mod
= UNIT_FIELD_RANGED_ATTACK_POWER_MODS
;
261 index_mult
= UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER
;
265 case CLASS_HUNTER
: val2
= level
* 2.0f
+ GetStat(STAT_AGILITY
) - 10.0f
; break;
266 case CLASS_ROGUE
: val2
= level
+ GetStat(STAT_AGILITY
) - 10.0f
; break;
267 case CLASS_WARRIOR
:val2
= level
+ GetStat(STAT_AGILITY
) - 10.0f
; break;
276 val2
= GetStat(STAT_AGILITY
) - 10.0f
; break;
279 default: val2
= GetStat(STAT_AGILITY
) - 10.0f
; break;
286 case CLASS_WARRIOR
: val2
= level
*3.0f
+ GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
287 case CLASS_PALADIN
: val2
= level
*3.0f
+ GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
288 case CLASS_DEATH_KNIGHT
: val2
= level
*3.0f
+ GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
289 case CLASS_ROGUE
: val2
= level
*2.0f
+ GetStat(STAT_STRENGTH
) + GetStat(STAT_AGILITY
) - 20.0f
; break;
290 case CLASS_HUNTER
: val2
= level
*2.0f
+ GetStat(STAT_STRENGTH
) + GetStat(STAT_AGILITY
) - 20.0f
; break;
291 case CLASS_SHAMAN
: val2
= level
*2.0f
+ GetStat(STAT_STRENGTH
) + GetStat(STAT_AGILITY
) - 20.0f
; break;
294 //Check if Predatory Strikes is skilled
295 float mLevelMult
= 0.0;
303 Unit::AuraList
const& mDummy
= GetAurasByType(SPELL_AURA_DUMMY
);
304 for(Unit::AuraList::const_iterator itr
= mDummy
.begin(); itr
!= mDummy
.end(); ++itr
)
306 // Predatory Strikes (effect 0)
307 if ((*itr
)->GetEffIndex()==0 && (*itr
)->GetSpellProto()->SpellIconID
== 1563)
309 mLevelMult
= (*itr
)->GetModifier()->m_amount
/ 100.0f
;
321 val2
= getLevel()*(mLevelMult
+2.0f
) + GetStat(STAT_STRENGTH
)*2.0f
+ GetStat(STAT_AGILITY
) - 20.0f
+ m_baseFeralAP
; break;
324 val2
= getLevel()*(mLevelMult
+3.0f
) + GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
+ m_baseFeralAP
; break;
326 val2
= getLevel()*(mLevelMult
+1.5f
) + GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
+ m_baseFeralAP
; break;
328 val2
= GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
332 case CLASS_MAGE
: val2
= GetStat(STAT_STRENGTH
) - 10.0f
; break;
333 case CLASS_PRIEST
: val2
= GetStat(STAT_STRENGTH
) - 10.0f
; break;
334 case CLASS_WARLOCK
: val2
= GetStat(STAT_STRENGTH
) - 10.0f
; break;
338 SetModifierValue(unitMod
, BASE_VALUE
, val2
);
340 float base_attPower
= GetModifierValue(unitMod
, BASE_VALUE
) * GetModifierValue(unitMod
, BASE_PCT
);
341 float attPowerMod
= GetModifierValue(unitMod
, TOTAL_VALUE
);
343 //add dynamic flat mods
346 if ((getClassMask() & CLASSMASK_WAND_USERS
)==0)
348 AuraList
const& mRAPbyStat
= GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT
);
349 for(AuraList::const_iterator i
= mRAPbyStat
.begin();i
!= mRAPbyStat
.end(); ++i
)
350 attPowerMod
+= int32(GetStat(Stats((*i
)->GetModifier()->m_miscvalue
)) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
355 AuraList
const& mAPbyStat
= GetAurasByType(SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT
);
356 for(AuraList::const_iterator i
= mAPbyStat
.begin();i
!= mAPbyStat
.end(); ++i
)
357 attPowerMod
+= int32(GetStat(Stats((*i
)->GetModifier()->m_miscvalue
)) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
359 AuraList
const& mAPbyArmor
= GetAurasByType(SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR
);
360 for(AuraList::const_iterator iter
= mAPbyArmor
.begin(); iter
!= mAPbyArmor
.end(); ++iter
)
361 // always: ((*i)->GetModifier()->m_miscvalue == 1 == SPELL_SCHOOL_MASK_NORMAL)
362 attPowerMod
+= int32(GetArmor() / (*iter
)->GetModifier()->m_amount
);
365 float attPowerMultiplier
= GetModifierValue(unitMod
, TOTAL_PCT
) - 1.0f
;
367 SetInt32Value(index
, (uint32
)base_attPower
); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
368 SetInt32Value(index_mod
, (uint32
)attPowerMod
); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
369 SetFloatValue(index_mult
, attPowerMultiplier
); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
371 //automatically update weapon damage after attack power modification
374 UpdateDamagePhysical(RANGED_ATTACK
);
376 Pet
*pet
= GetPet(); //update pet's AP
378 pet
->UpdateAttackPowerAndDamage();
382 UpdateDamagePhysical(BASE_ATTACK
);
383 if(CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon
384 UpdateDamagePhysical(OFF_ATTACK
);
388 void Player::UpdateShieldBlockValue()
390 SetUInt32Value(PLAYER_SHIELD_BLOCK
, GetShieldBlockValue());
393 void Player::CalculateMinMaxDamage(WeaponAttackType attType
, bool normalized
, float& min_damage
, float& max_damage
)
402 unitMod
= UNIT_MOD_DAMAGE_MAINHAND
;
403 attPower
= UNIT_MOD_ATTACK_POWER
;
406 unitMod
= UNIT_MOD_DAMAGE_OFFHAND
;
407 attPower
= UNIT_MOD_ATTACK_POWER
;
410 unitMod
= UNIT_MOD_DAMAGE_RANGED
;
411 attPower
= UNIT_MOD_ATTACK_POWER_RANGED
;
415 float att_speed
= GetAPMultiplier(attType
,normalized
);
417 float base_value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetTotalAttackPowerValue(attType
)/ 14.0f
* att_speed
;
418 float base_pct
= GetModifierValue(unitMod
, BASE_PCT
);
419 float total_value
= GetModifierValue(unitMod
, TOTAL_VALUE
);
420 float total_pct
= GetModifierValue(unitMod
, TOTAL_PCT
);
422 float weapon_mindamage
= GetWeaponDamageRange(attType
, MINDAMAGE
);
423 float weapon_maxdamage
= GetWeaponDamageRange(attType
, MAXDAMAGE
);
425 if (IsInFeralForm()) //check if player is druid and in cat or bear forms
427 uint32 lvl
= getLevel();
428 if ( lvl
> 60 ) lvl
= 60;
430 weapon_mindamage
= lvl
*0.85*att_speed
;
431 weapon_maxdamage
= lvl
*1.25*att_speed
;
433 else if(!IsUseEquipedWeapon(attType
==BASE_ATTACK
)) //check if player not in form but still can't use weapon (broken/etc)
435 weapon_mindamage
= BASE_MINDAMAGE
;
436 weapon_maxdamage
= BASE_MAXDAMAGE
;
438 else if(attType
== RANGED_ATTACK
) //add ammo DPS to ranged damage
440 weapon_mindamage
+= GetAmmoDPS() * att_speed
;
441 weapon_maxdamage
+= GetAmmoDPS() * att_speed
;
444 min_damage
= ((base_value
+ weapon_mindamage
) * base_pct
+ total_value
) * total_pct
;
445 max_damage
= ((base_value
+ weapon_maxdamage
) * base_pct
+ total_value
) * total_pct
;
448 void Player::UpdateDamagePhysical(WeaponAttackType attType
)
453 CalculateMinMaxDamage(attType
,false,mindamage
,maxdamage
);
459 SetStatFloatValue(UNIT_FIELD_MINDAMAGE
,mindamage
);
460 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE
,maxdamage
);
463 SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE
,mindamage
);
464 SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE
,maxdamage
);
467 SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE
,mindamage
);
468 SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE
,maxdamage
);
473 void Player::UpdateDefenseBonusesMod()
475 UpdateBlockPercentage();
476 UpdateParryPercentage();
477 UpdateDodgePercentage();
480 void Player::UpdateBlockPercentage()
488 // Modify value from defense skill
489 value
+= (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
490 // Increase from SPELL_AURA_MOD_BLOCK_PERCENT aura
491 value
+= GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT
);
492 // Increase from rating
493 value
+= GetRatingBonusValue(CR_BLOCK
);
494 value
= value
< 0.0f
? 0.0f
: value
;
496 SetStatFloatValue(PLAYER_BLOCK_PERCENTAGE
, value
);
499 void Player::UpdateCritPercentage(WeaponAttackType attType
)
501 BaseModGroup modGroup
;
508 modGroup
= OFFHAND_CRIT_PERCENTAGE
;
509 index
= PLAYER_OFFHAND_CRIT_PERCENTAGE
;
513 modGroup
= RANGED_CRIT_PERCENTAGE
;
514 index
= PLAYER_RANGED_CRIT_PERCENTAGE
;
519 modGroup
= CRIT_PERCENTAGE
;
520 index
= PLAYER_CRIT_PERCENTAGE
;
525 float value
= GetTotalPercentageModValue(modGroup
) + GetRatingBonusValue(cr
);
526 // Modify crit from weapon skill and maximized defense skill of same level victim difference
527 value
+= (int32(GetWeaponSkillValue(attType
)) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
528 value
= value
< 0.0f
? 0.0f
: value
;
529 SetStatFloatValue(index
, value
);
532 void Player::UpdateAllCritPercentages()
534 float value
= GetMeleeCritFromAgility();
536 SetBaseModValue(CRIT_PERCENTAGE
, PCT_MOD
, value
);
537 SetBaseModValue(OFFHAND_CRIT_PERCENTAGE
, PCT_MOD
, value
);
538 SetBaseModValue(RANGED_CRIT_PERCENTAGE
, PCT_MOD
, value
);
540 UpdateCritPercentage(BASE_ATTACK
);
541 UpdateCritPercentage(OFF_ATTACK
);
542 UpdateCritPercentage(RANGED_ATTACK
);
545 void Player::UpdateParryPercentage()
553 // Modify value from defense skill
554 value
+= (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
555 // Parry from SPELL_AURA_MOD_PARRY_PERCENT aura
556 value
+= GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT
);
558 value
+= GetRatingBonusValue(CR_PARRY
);
559 value
= value
< 0.0f
? 0.0f
: value
;
561 SetStatFloatValue(PLAYER_PARRY_PERCENTAGE
, value
);
564 void Player::UpdateDodgePercentage()
566 // Dodge from agility
567 float value
= GetDodgeFromAgility();
568 // Modify value from defense skill
569 value
+= (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
570 // Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura
571 value
+= GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT
);
573 value
+= GetRatingBonusValue(CR_DODGE
);
574 value
= value
< 0.0f
? 0.0f
: value
;
575 SetStatFloatValue(PLAYER_DODGE_PERCENTAGE
, value
);
578 void Player::UpdateSpellCritChance(uint32 school
)
580 // For normal school set zero crit chance
581 if(school
== SPELL_SCHOOL_NORMAL
)
583 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1
, 0.0f
);
586 // For others recalculate it from:
588 // Crit from Intellect
589 crit
+= GetSpellCritFromIntellect();
590 // Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE
591 crit
+= GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE
);
592 // Increase crit from SPELL_AURA_MOD_ALL_CRIT_CHANCE
593 crit
+= GetTotalAuraModifier(SPELL_AURA_MOD_ALL_CRIT_CHANCE
);
594 // Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
595 crit
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, 1<<school
);
596 // Increase crit from spell crit ratings
597 crit
+= GetRatingBonusValue(CR_CRIT_SPELL
);
600 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1
+ school
, crit
);
603 void Player::UpdateMeleeHitChances()
605 m_modMeleeHitChance
= GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE
);
606 m_modMeleeHitChance
+= GetRatingBonusValue(CR_HIT_MELEE
);
609 void Player::UpdateRangedHitChances()
611 m_modRangedHitChance
= GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE
);
612 m_modRangedHitChance
+= GetRatingBonusValue(CR_HIT_RANGED
);
615 void Player::UpdateSpellHitChances()
617 m_modSpellHitChance
= GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HIT_CHANCE
);
618 m_modSpellHitChance
+= GetRatingBonusValue(CR_HIT_SPELL
);
621 void Player::UpdateAllSpellCritChances()
623 for (int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; ++i
)
624 UpdateSpellCritChance(i
);
627 void Player::UpdateExpertise(WeaponAttackType attack
)
629 if(attack
==RANGED_ATTACK
)
632 int32 expertise
= int32(GetRatingBonusValue(CR_EXPERTISE
));
634 Item
*weapon
= GetWeaponForAttack(attack
);
636 AuraList
const& expAuras
= GetAurasByType(SPELL_AURA_MOD_EXPERTISE
);
637 for(AuraList::const_iterator itr
= expAuras
.begin(); itr
!= expAuras
.end(); ++itr
)
639 // item neutral spell
640 if((*itr
)->GetSpellProto()->EquippedItemClass
== -1)
641 expertise
+= (*itr
)->GetModifier()->m_amount
;
642 // item dependent spell
643 else if(weapon
&& weapon
->IsFitToSpellRequirements((*itr
)->GetSpellProto()))
644 expertise
+= (*itr
)->GetModifier()->m_amount
;
652 case BASE_ATTACK
: SetUInt32Value(PLAYER_EXPERTISE
, expertise
); break;
653 case OFF_ATTACK
: SetUInt32Value(PLAYER_OFFHAND_EXPERTISE
, expertise
); break;
658 void Player::UpdateArmorPenetration()
660 m_armorPenetrationPct
= GetRatingBonusValue(CR_ARMOR_PENETRATION
);
662 AuraList
const& armorAuras
= GetAurasByType(SPELL_AURA_MOD_TARGET_ARMOR_PCT
);
663 for(AuraList::const_iterator itr
= armorAuras
.begin(); itr
!= armorAuras
.end(); ++itr
)
665 // affects all weapons
666 if((*itr
)->GetSpellProto()->EquippedItemClass
== -1)
668 m_armorPenetrationPct
+= (*itr
)->GetModifier()->m_amount
;
672 // dependent on weapon class
673 for(uint8 i
= 0; i
< MAX_ATTACK
; ++i
)
675 Item
*weapon
= GetWeaponForAttack(WeaponAttackType(i
));
676 if(weapon
&& weapon
->IsFitToSpellRequirements((*itr
)->GetSpellProto()))
678 m_armorPenetrationPct
+= (*itr
)->GetModifier()->m_amount
;
685 void Player::ApplyManaRegenBonus(int32 amount
, bool apply
)
687 m_baseManaRegen
+= apply
? amount
: -amount
;
691 void Player::UpdateManaRegen()
693 float Intellect
= GetStat(STAT_INTELLECT
);
694 // Mana regen from spirit and intellect
695 float power_regen
= sqrt(Intellect
) * OCTRegenMPPerSpirit();
696 // Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen
697 power_regen
*= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT
, POWER_MANA
);
699 // Mana regen from SPELL_AURA_MOD_POWER_REGEN aura
700 float power_regen_mp5
= (GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN
, POWER_MANA
) + m_baseManaRegen
) / 5.0f
;
702 // Get bonus from SPELL_AURA_MOD_MANA_REGEN_FROM_STAT aura
703 AuraList
const& regenAura
= GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_FROM_STAT
);
704 for(AuraList::const_iterator i
= regenAura
.begin();i
!= regenAura
.end(); ++i
)
706 Modifier
* mod
= (*i
)->GetModifier();
707 power_regen_mp5
+= GetStat(Stats(mod
->m_miscvalue
)) * mod
->m_amount
/ 500.0f
;
710 // Set regen rate in cast state apply only on spirit based regen
711 int32 modManaRegenInterrupt
= GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
);
712 if (modManaRegenInterrupt
> 100)
713 modManaRegenInterrupt
= 100;
714 SetStatFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER
, power_regen_mp5
+ power_regen
* modManaRegenInterrupt
/ 100.0f
);
716 SetStatFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER
, power_regen_mp5
+ power_regen
);
719 void Player::_ApplyAllStatBonuses()
721 SetCanModifyStats(false);
726 SetCanModifyStats(true);
731 void Player::_RemoveAllStatBonuses()
733 SetCanModifyStats(false);
735 _RemoveAllItemMods();
736 _RemoveAllAuraMods();
738 SetCanModifyStats(true);
743 /*#######################################
745 ######## MOBS STAT SYSTEM ########
747 #######################################*/
749 bool Creature::UpdateStats(Stats
/*stat*/)
754 bool Creature::UpdateAllStats()
757 UpdateAttackPowerAndDamage();
759 for(int i
= POWER_MANA
; i
< MAX_POWERS
; ++i
)
760 UpdateMaxPower(Powers(i
));
762 for(int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; ++i
)
763 UpdateResistances(i
);
768 void Creature::UpdateResistances(uint32 school
)
770 if(school
> SPELL_SCHOOL_NORMAL
)
772 float value
= GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START
+ school
));
773 SetResistance(SpellSchools(school
), int32(value
));
779 void Creature::UpdateArmor()
781 float value
= GetTotalAuraModValue(UNIT_MOD_ARMOR
);
782 SetArmor(int32(value
));
785 void Creature::UpdateMaxHealth()
787 float value
= GetTotalAuraModValue(UNIT_MOD_HEALTH
);
788 SetMaxHealth((uint32
)value
);
791 void Creature::UpdateMaxPower(Powers power
)
793 UnitMods unitMod
= UnitMods(UNIT_MOD_POWER_START
+ power
);
795 float value
= GetTotalAuraModValue(unitMod
);
796 SetMaxPower(power
, uint32(value
));
799 void Creature::UpdateAttackPowerAndDamage(bool ranged
)
801 UnitMods unitMod
= ranged
? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
803 uint16 index
= UNIT_FIELD_ATTACK_POWER
;
804 uint16 index_mod
= UNIT_FIELD_ATTACK_POWER_MODS
;
805 uint16 index_mult
= UNIT_FIELD_ATTACK_POWER_MULTIPLIER
;
809 index
= UNIT_FIELD_RANGED_ATTACK_POWER
;
810 index_mod
= UNIT_FIELD_RANGED_ATTACK_POWER_MODS
;
811 index_mult
= UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER
;
814 float base_attPower
= GetModifierValue(unitMod
, BASE_VALUE
) * GetModifierValue(unitMod
, BASE_PCT
);
815 float attPowerMod
= GetModifierValue(unitMod
, TOTAL_VALUE
);
816 float attPowerMultiplier
= GetModifierValue(unitMod
, TOTAL_PCT
) - 1.0f
;
818 SetInt32Value(index
, (uint32
)base_attPower
); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
819 SetInt32Value(index_mod
, (uint32
)attPowerMod
); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
820 SetFloatValue(index_mult
, attPowerMultiplier
); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
824 //automatically update weapon damage after attack power modification
825 UpdateDamagePhysical(BASE_ATTACK
);
828 void Creature::UpdateDamagePhysical(WeaponAttackType attType
)
830 if(attType
> BASE_ATTACK
)
833 UnitMods unitMod
= UNIT_MOD_DAMAGE_MAINHAND
;
835 /* difference in AP between current attack power and base value from DB */
836 float att_pwr_change
= GetTotalAttackPowerValue(attType
) - GetCreatureInfo()->attackpower
;
837 float base_value
= GetModifierValue(unitMod
, BASE_VALUE
) + (att_pwr_change
* GetAPMultiplier(attType
, false) / 14.0f
);
838 float base_pct
= GetModifierValue(unitMod
, BASE_PCT
);
839 float total_value
= GetModifierValue(unitMod
, TOTAL_VALUE
);
840 float total_pct
= GetModifierValue(unitMod
, TOTAL_PCT
);
841 float dmg_multiplier
= GetCreatureInfo()->dmg_multiplier
;
843 float weapon_mindamage
= GetWeaponDamageRange(BASE_ATTACK
, MINDAMAGE
);
844 float weapon_maxdamage
= GetWeaponDamageRange(BASE_ATTACK
, MAXDAMAGE
);
846 float mindamage
= ((base_value
+ weapon_mindamage
) * dmg_multiplier
* base_pct
+ total_value
) * total_pct
;
847 float maxdamage
= ((base_value
+ weapon_maxdamage
) * dmg_multiplier
* base_pct
+ total_value
) * total_pct
;
849 SetStatFloatValue(UNIT_FIELD_MINDAMAGE
, mindamage
);
850 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE
, maxdamage
);
853 /*#######################################
855 ######## PETS STAT SYSTEM ########
857 #######################################*/
859 bool Pet::UpdateStats(Stats stat
)
861 if(stat
> STAT_SPIRIT
)
864 // value = ((base_value * base_pct) + total_value) * total_pct
865 float value
= GetTotalStatValue(stat
);
867 Unit
*owner
= GetOwner();
868 if ( stat
== STAT_STAMINA
)
871 value
+= float(owner
->GetStat(stat
)) * 0.3f
;
873 //warlock's and mage's pets gain 30% of owner's intellect
874 else if ( stat
== STAT_INTELLECT
&& getPetType() == SUMMON_PET
)
876 if(owner
&& (owner
->getClass() == CLASS_WARLOCK
|| owner
->getClass() == CLASS_MAGE
) )
877 value
+= float(owner
->GetStat(stat
)) * 0.3f
;
880 SetStat(stat
, int32(value
));
884 case STAT_STRENGTH
: UpdateAttackPowerAndDamage(); break;
885 case STAT_AGILITY
: UpdateArmor(); break;
886 case STAT_STAMINA
: UpdateMaxHealth(); break;
887 case STAT_INTELLECT
: UpdateMaxPower(POWER_MANA
); break;
896 bool Pet::UpdateAllStats()
898 for (int i
= STAT_STRENGTH
; i
< MAX_STATS
; ++i
)
899 UpdateStats(Stats(i
));
901 for(int i
= POWER_MANA
; i
< MAX_POWERS
; ++i
)
902 UpdateMaxPower(Powers(i
));
904 for (int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; ++i
)
905 UpdateResistances(i
);
910 void Pet::UpdateResistances(uint32 school
)
912 if(school
> SPELL_SCHOOL_NORMAL
)
914 float value
= GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START
+ school
));
916 Unit
*owner
= GetOwner();
917 // hunter and warlock pets gain 40% of owner's resistance
918 if(owner
&& (getPetType() == HUNTER_PET
|| (getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_WARLOCK
)))
919 value
+= float(owner
->GetResistance(SpellSchools(school
))) * 0.4f
;
921 SetResistance(SpellSchools(school
), int32(value
));
927 void Pet::UpdateArmor()
930 float bonus_armor
= 0.0f
;
931 UnitMods unitMod
= UNIT_MOD_ARMOR
;
933 Unit
*owner
= GetOwner();
934 // hunter and warlock pets gain 35% of owner's armor value
935 if(owner
&& (getPetType() == HUNTER_PET
|| (getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_WARLOCK
)))
936 bonus_armor
= 0.35f
* float(owner
->GetArmor());
938 value
= GetModifierValue(unitMod
, BASE_VALUE
);
939 value
*= GetModifierValue(unitMod
, BASE_PCT
);
940 value
+= GetStat(STAT_AGILITY
) * 2.0f
;
941 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + bonus_armor
;
942 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
944 SetArmor(int32(value
));
947 void Pet::UpdateMaxHealth()
949 UnitMods unitMod
= UNIT_MOD_HEALTH
;
950 float stamina
= GetStat(STAT_STAMINA
) - GetCreateStat(STAT_STAMINA
);
952 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreateHealth();
953 value
*= GetModifierValue(unitMod
, BASE_PCT
);
954 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + stamina
* 10.0f
;
955 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
957 SetMaxHealth((uint32
)value
);
960 void Pet::UpdateMaxPower(Powers power
)
962 UnitMods unitMod
= UnitMods(UNIT_MOD_POWER_START
+ power
);
964 float addValue
= (power
== POWER_MANA
) ? GetStat(STAT_INTELLECT
) - GetCreateStat(STAT_INTELLECT
) : 0.0f
;
966 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreatePowers(power
);
967 value
*= GetModifierValue(unitMod
, BASE_PCT
);
968 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + addValue
* 15.0f
;
969 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
971 SetMaxPower(power
, uint32(value
));
974 void Pet::UpdateAttackPowerAndDamage(bool ranged
)
980 float bonusAP
= 0.0f
;
981 UnitMods unitMod
= UNIT_MOD_ATTACK_POWER
;
983 if(GetEntry() == 416) // imp's attack power
984 val
= GetStat(STAT_STRENGTH
) - 10.0f
;
986 val
= 2 * GetStat(STAT_STRENGTH
) - 20.0f
;
988 Unit
* owner
= GetOwner();
989 if( owner
&& owner
->GetTypeId()==TYPEID_PLAYER
)
991 if(getPetType() == HUNTER_PET
) //hunter pets benefit from owner's attack power
993 bonusAP
= owner
->GetTotalAttackPowerValue(RANGED_ATTACK
) * 0.22f
;
994 SetBonusDamage( int32(owner
->GetTotalAttackPowerValue(RANGED_ATTACK
) * 0.1287f
));
996 //demons benefit from warlocks shadow or fire damage
997 else if(getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_WARLOCK
)
999 int32 fire
= int32(owner
->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS
+ SPELL_SCHOOL_FIRE
)) - owner
->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG
+ SPELL_SCHOOL_FIRE
);
1000 int32 shadow
= int32(owner
->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS
+ SPELL_SCHOOL_SHADOW
)) - owner
->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG
+ SPELL_SCHOOL_SHADOW
);
1001 int32 maximum
= (fire
> shadow
) ? fire
: shadow
;
1004 SetBonusDamage( int32(maximum
* 0.15f
));
1005 bonusAP
= maximum
* 0.57f
;
1007 //water elementals benefit from mage's frost damage
1008 else if(getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_MAGE
)
1010 int32 frost
= int32(owner
->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS
+ SPELL_SCHOOL_FROST
)) - owner
->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG
+ SPELL_SCHOOL_FROST
);
1013 SetBonusDamage( int32(frost
* 0.4f
));
1017 SetModifierValue(UNIT_MOD_ATTACK_POWER
, BASE_VALUE
, val
+ bonusAP
);
1019 //in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB
1020 float base_attPower
= GetModifierValue(unitMod
, BASE_VALUE
) * GetModifierValue(unitMod
, BASE_PCT
);
1021 float attPowerMod
= GetModifierValue(unitMod
, TOTAL_VALUE
);
1022 float attPowerMultiplier
= GetModifierValue(unitMod
, TOTAL_PCT
) - 1.0f
;
1024 //UNIT_FIELD_(RANGED)_ATTACK_POWER field
1025 SetInt32Value(UNIT_FIELD_ATTACK_POWER
, (int32
)base_attPower
);
1026 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
1027 SetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS
, (int32
)attPowerMod
);
1028 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
1029 SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER
, attPowerMultiplier
);
1031 //automatically update weapon damage after attack power modification
1032 UpdateDamagePhysical(BASE_ATTACK
);
1035 void Pet::UpdateDamagePhysical(WeaponAttackType attType
)
1037 if(attType
> BASE_ATTACK
)
1040 UnitMods unitMod
= UNIT_MOD_DAMAGE_MAINHAND
;
1042 float att_speed
= float(GetAttackTime(BASE_ATTACK
))/1000.0f
;
1044 float base_value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetTotalAttackPowerValue(attType
)/ 14.0f
* att_speed
;
1045 float base_pct
= GetModifierValue(unitMod
, BASE_PCT
);
1046 float total_value
= GetModifierValue(unitMod
, TOTAL_VALUE
);
1047 float total_pct
= GetModifierValue(unitMod
, TOTAL_PCT
);
1049 float weapon_mindamage
= GetWeaponDamageRange(BASE_ATTACK
, MINDAMAGE
);
1050 float weapon_maxdamage
= GetWeaponDamageRange(BASE_ATTACK
, MAXDAMAGE
);
1052 float mindamage
= ((base_value
+ weapon_mindamage
) * base_pct
+ total_value
) * total_pct
;
1053 float maxdamage
= ((base_value
+ weapon_maxdamage
) * base_pct
+ total_value
) * total_pct
;
1055 // Pet's base damage changes depending on happiness
1056 if (getPetType() == HUNTER_PET
&& attType
== BASE_ATTACK
)
1058 switch(GetHappinessState())
1061 // 125% of normal damage
1062 mindamage
= mindamage
* 1.25;
1063 maxdamage
= maxdamage
* 1.25;
1066 // 100% of normal damage, nothing to modify
1069 // 75% of normal damage
1070 mindamage
= mindamage
* 0.75;
1071 maxdamage
= maxdamage
* 0.75;
1076 SetStatFloatValue(UNIT_FIELD_MINDAMAGE
, mindamage
);
1077 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE
, maxdamage
);