2 * Copyright (C) 2005-2013 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
19 #include "DBCStores.h"
24 #include "SharedDefines.h"
25 #include "SpellAuras.h"
28 /*#######################################
30 ######## PLAYERS STAT SYSTEM ########
32 #######################################*/
34 bool Player::UpdateStats(Stats stat
)
36 if (stat
> STAT_SPIRIT
)
39 // value = ((base_value * base_pct) + total_value) * total_pct
40 float value
= GetTotalStatValue(stat
);
42 SetStat(stat
, int32(value
));
44 if (stat
== STAT_STAMINA
|| stat
== STAT_INTELLECT
)
48 pet
->UpdateStats(stat
);
57 UpdateAllCritPercentages();
58 UpdateDodgePercentage();
60 case STAT_STAMINA
: UpdateMaxHealth(); break;
62 UpdateMaxPower(POWER_MANA
);
63 UpdateAllSpellCritChances();
64 UpdateArmor(); // SPELL_AURA_MOD_RESISTANCE_OF_INTELLECT_PERCENT, only armor currently
73 // Need update (exist AP from stat auras)
74 UpdateAttackPowerAndDamage();
75 UpdateAttackPowerAndDamage(true);
77 UpdateSpellDamageAndHealingBonus();
80 // Update ratings in exist SPELL_AURA_MOD_RATING_FROM_STAT and only depends from stat
82 AuraList
const& modRatingFromStat
= GetAurasByType(SPELL_AURA_MOD_RATING_FROM_STAT
);
83 for (AuraList::const_iterator i
= modRatingFromStat
.begin(); i
!= modRatingFromStat
.end(); ++i
)
84 if (Stats((*i
)->GetMiscBValue()) == stat
)
85 mask
|= (*i
)->GetMiscValue();
88 for (uint32 rating
= 0; rating
< MAX_COMBAT_RATING
; ++rating
)
89 if (mask
& (1 << rating
))
90 ApplyRatingMod(CombatRating(rating
), 0, true);
95 void Player::ApplySpellPowerBonus(int32 amount
, bool apply
)
97 m_baseSpellPower
+= apply
? amount
: -amount
;
99 // For speed just update for client
100 ApplyModUInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS
, amount
, apply
);
101 for (int i
= SPELL_SCHOOL_HOLY
; i
< MAX_SPELL_SCHOOL
; ++i
)
102 ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS
+ i
, amount
, apply
);;
105 void Player::UpdateSpellDamageAndHealingBonus()
107 // Magic damage modifiers implemented in Unit::SpellDamageBonusDone
108 // This information for client side use only
109 // Get healing bonus for all schools
110 SetStatInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS
, SpellBaseHealingBonusDone(SPELL_SCHOOL_MASK_ALL
));
111 // Get damage bonus for all schools
112 for (int i
= SPELL_SCHOOL_HOLY
; i
< MAX_SPELL_SCHOOL
; ++i
)
113 SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS
+ i
, SpellBaseDamageBonusDone(SpellSchoolMask(1 << i
)));
116 bool Player::UpdateAllStats()
118 for (int i
= STAT_STRENGTH
; i
< MAX_STATS
; ++i
)
120 float value
= GetTotalStatValue(Stats(i
));
121 SetStat(Stats(i
), (int32
)value
);
125 // calls UpdateAttackPowerAndDamage() in UpdateArmor for SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR
126 UpdateAttackPowerAndDamage(true);
129 for (uint32 i
= POWER_MANA
; i
< MAX_POWERS
; ++i
)
130 UpdateMaxPower(Powers(i
));
133 UpdateAllCritPercentages();
134 UpdateAllSpellCritChances();
135 UpdateBlockPercentage();
136 UpdateParryPercentage();
137 UpdateShieldBlockDamageValue();
138 UpdateDodgePercentage();
139 UpdateArmorPenetration();
140 UpdateSpellDamageAndHealingBonus();
142 UpdateExpertise(BASE_ATTACK
);
143 UpdateExpertise(OFF_ATTACK
);
144 for (int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; ++i
)
145 UpdateResistances(i
);
150 void Player::UpdateResistances(uint32 school
)
152 if (school
> SPELL_SCHOOL_NORMAL
)
154 float value
= GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START
+ school
));
155 SetResistance(SpellSchools(school
), int32(value
));
159 pet
->UpdateResistances(school
);
165 void Player::UpdateArmor()
168 UnitMods unitMod
= UNIT_MOD_ARMOR
;
170 value
= GetModifierValue(unitMod
, BASE_VALUE
); // base armor (from items)
171 value
*= GetModifierValue(unitMod
, BASE_PCT
); // armor percent from items
172 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
);
174 // add dynamic flat mods
175 AuraList
const& mResbyIntellect
= GetAurasByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT
);
176 for (AuraList::const_iterator i
= mResbyIntellect
.begin(); i
!= mResbyIntellect
.end(); ++i
)
178 Modifier
* mod
= (*i
)->GetModifier();
179 if (mod
->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
180 value
+= int32(GetStat(Stats((*i
)->GetMiscBValue())) * mod
->m_amount
/ 100.0f
);
183 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
185 SetArmor(int32(value
));
191 UpdateAttackPowerAndDamage(); // armor dependent auras update for SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR
194 float Player::GetHealthBonusFromStamina()
196 GtOCTHpPerStaminaEntry
const* hpBase
= sGtOCTHpPerStaminaStore
.LookupEntry((getClass() - 1) * GT_MAX_LEVEL
+ getLevel() - 1);
198 float stamina
= GetStat(STAT_STAMINA
);
200 float baseStam
= stamina
< 20 ? stamina
: 20;
201 float moreStam
= stamina
- baseStam
;
205 return baseStam
+ moreStam
* hpBase
->ratio
;
208 float Player::GetManaBonusFromIntellect()
210 float intellect
= GetStat(STAT_INTELLECT
);
212 float baseInt
= intellect
< 20 ? intellect
: 20;
213 float moreInt
= intellect
- baseInt
;
215 return baseInt
+ (moreInt
* 15.0f
);
218 void Player::UpdateMaxHealth()
220 UnitMods unitMod
= UNIT_MOD_HEALTH
;
222 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreateHealth();
223 value
*= GetModifierValue(unitMod
, BASE_PCT
);
224 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + GetHealthBonusFromStamina();
225 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
227 SetMaxHealth((uint32
)value
);
230 void Player::UpdateMaxPower(Powers power
)
232 MANGOS_ASSERT(power
< MAX_POWERS
);
234 UnitMods unitMod
= UnitMods(UNIT_MOD_POWER_START
+ power
);
236 uint32 create_power
= GetCreateMaxPowers(power
);
238 // ignore classes without mana
239 float bonusPower
= (power
== POWER_MANA
&& create_power
> 0) ? GetManaBonusFromIntellect() : 0;
241 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + create_power
;
242 value
*= GetModifierValue(unitMod
, BASE_PCT
);
243 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + bonusPower
;
244 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
246 SetMaxPower(power
, uint32(value
));
249 void Player::UpdateAttackPowerAndDamage(bool ranged
)
251 ChrClassesEntry
const * chrEntry
= sChrClassesStore
.LookupEntry(getClass());
252 MANGOS_ASSERT(chrEntry
);
255 float level
= float(getLevel());
257 UnitMods unitMod
= ranged
? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
259 uint16 index
= UNIT_FIELD_ATTACK_POWER
;
260 uint16 index_mod
= UNIT_FIELD_ATTACK_POWER_MOD_POS
;
261 uint16 index_mult
= UNIT_FIELD_ATTACK_POWER_MULTIPLIER
;
265 index
= UNIT_FIELD_RANGED_ATTACK_POWER
;
266 index_mod
= UNIT_FIELD_RANGED_ATTACK_POWER_MOD_POS
;
267 index_mult
= UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER
;
269 float rapPerAgi
= std::max(GetStat(STAT_AGILITY
) - 10.0f
, 0.0f
) * chrEntry
->rapPerAgi
;
273 case CLASS_HUNTER
: val2
= level
* 2.0f
+ rapPerAgi
; break;
274 case CLASS_ROGUE
: val2
= level
+ rapPerAgi
; break;
275 case CLASS_WARRIOR
: val2
= level
+ rapPerAgi
; break;
281 float apPerAgi
= std::max(GetStat(STAT_AGILITY
) - 10.0f
, 0.0f
) * chrEntry
->apPerAgi
;
282 float apPerStr
= std::max(GetStat(STAT_STRENGTH
) - 10.0f
, 0.0f
) * chrEntry
->apPerStr
;
288 case CLASS_DEATH_KNIGHT
:
297 val2
= level
* levelmod
+ apPerAgi
+ apPerStr
;
299 // extracted from client
300 if (getClass() == CLASS_DRUID
&& GetShapeshiftForm())
302 if (SpellShapeshiftFormEntry
const * entry
= sSpellShapeshiftFormStore
.LookupEntry(uint32(GetShapeshiftForm())))
303 if (entry
->flags1
& 0x20)
304 val2
+= std::max(GetStat(STAT_AGILITY
) - 10.0f
, 0.0f
) * chrEntry
->apPerStr
;
308 SetModifierValue(unitMod
, BASE_VALUE
, val2
);
310 float base_attPower
= GetModifierValue(unitMod
, BASE_VALUE
) * GetModifierValue(unitMod
, BASE_PCT
);
311 float attPowerMod
= GetModifierValue(unitMod
, TOTAL_VALUE
);
313 // add dynamic flat mods
316 if ((getClassMask() & CLASSMASK_WAND_USERS
) == 0)
318 AuraList
const& mRAPbyStat
= GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT
);
319 for (AuraList::const_iterator i
= mRAPbyStat
.begin(); i
!= mRAPbyStat
.end(); ++i
)
320 attPowerMod
+= int32(GetStat(Stats((*i
)->GetModifier()->m_miscvalue
)) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
325 AuraList
const& mAPbyStat
= GetAurasByType(SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT
);
326 for (AuraList::const_iterator i
= mAPbyStat
.begin(); i
!= mAPbyStat
.end(); ++i
)
327 attPowerMod
+= int32(GetStat(Stats((*i
)->GetModifier()->m_miscvalue
)) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
329 AuraList
const& mAPbyArmor
= GetAurasByType(SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR
);
330 for (AuraList::const_iterator iter
= mAPbyArmor
.begin(); iter
!= mAPbyArmor
.end(); ++iter
)
331 // always: ((*i)->GetModifier()->m_miscvalue == 1 == SPELL_SCHOOL_MASK_NORMAL)
332 attPowerMod
+= int32(GetArmor() / (*iter
)->GetModifier()->m_amount
);
335 float attPowerMultiplier
= GetModifierValue(unitMod
, TOTAL_PCT
) - 1.0f
;
337 SetInt32Value(index
, (uint32
)base_attPower
); // UNIT_FIELD_(RANGED)_ATTACK_POWER field
338 SetInt32Value(index_mod
, (uint32
)attPowerMod
); // UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
339 SetFloatValue(index_mult
, attPowerMultiplier
); // UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
341 // automatically update weapon damage after attack power modification
344 UpdateDamagePhysical(RANGED_ATTACK
);
346 Pet
* pet
= GetPet(); // update pet's AP
348 pet
->UpdateAttackPowerAndDamage();
352 UpdateDamagePhysical(BASE_ATTACK
);
353 if (CanDualWield() && haveOffhandWeapon()) // allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon
354 UpdateDamagePhysical(OFF_ATTACK
);
358 void Player::UpdateShieldBlockDamageValue()
360 SetUInt32Value(PLAYER_SHIELD_BLOCK
, GetShieldBlockDamageValue());
363 void Player::CalculateMinMaxDamage(WeaponAttackType attType
, bool normalized
, float& min_damage
, float& max_damage
)
372 unitMod
= UNIT_MOD_DAMAGE_MAINHAND
;
373 attPower
= UNIT_MOD_ATTACK_POWER
;
376 unitMod
= UNIT_MOD_DAMAGE_OFFHAND
;
377 attPower
= UNIT_MOD_ATTACK_POWER
;
380 unitMod
= UNIT_MOD_DAMAGE_RANGED
;
381 attPower
= UNIT_MOD_ATTACK_POWER_RANGED
;
385 float att_speed
= GetAPMultiplier(attType
, normalized
);
387 float base_value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetTotalAttackPowerValue(attType
) / 14.0f
* att_speed
;
388 float base_pct
= GetModifierValue(unitMod
, BASE_PCT
);
389 float total_value
= GetModifierValue(unitMod
, TOTAL_VALUE
);
390 float total_pct
= GetModifierValue(unitMod
, TOTAL_PCT
);
392 float weapon_mindamage
= GetWeaponDamageRange(attType
, MINDAMAGE
);
393 float weapon_maxdamage
= GetWeaponDamageRange(attType
, MAXDAMAGE
);
395 if (IsInFeralForm()) // check if player is druid and in cat or bear forms, non main hand attacks not allowed for this mode so not check attack type
397 float weaponSpeed
= GetAttackTime(attType
) / 1000.0f
;
399 switch (GetShapeshiftForm())
402 weapon_mindamage
= weapon_mindamage
/ weaponSpeed
;
403 weapon_maxdamage
= weapon_maxdamage
/ weaponSpeed
;
406 weapon_mindamage
= weapon_mindamage
/ weaponSpeed
+ weapon_mindamage
/ 2.5f
;
407 weapon_maxdamage
= weapon_maxdamage
/ weaponSpeed
+ weapon_maxdamage
/ 2.5f
;
411 else if (!CanUseEquippedWeapon(attType
)) // check if player not in form but still can't use weapon (broken/etc)
413 weapon_mindamage
= BASE_MINDAMAGE
;
414 weapon_maxdamage
= BASE_MAXDAMAGE
;
416 else if (attType
== RANGED_ATTACK
) // add ammo DPS to ranged damage
418 weapon_mindamage
+= GetAmmoDPS() * att_speed
;
419 weapon_maxdamage
+= GetAmmoDPS() * att_speed
;
422 min_damage
= ((base_value
+ weapon_mindamage
) * base_pct
+ total_value
) * total_pct
;
423 max_damage
= ((base_value
+ weapon_maxdamage
) * base_pct
+ total_value
) * total_pct
;
426 void Player::UpdateDamagePhysical(WeaponAttackType attType
)
431 CalculateMinMaxDamage(attType
, false, mindamage
, maxdamage
);
437 SetStatFloatValue(UNIT_FIELD_MINDAMAGE
, mindamage
);
438 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE
, maxdamage
);
441 SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE
, mindamage
);
442 SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE
, maxdamage
);
445 SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE
, mindamage
);
446 SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE
, maxdamage
);
451 void Player::UpdateBlockPercentage()
459 // Increase from SPELL_AURA_MOD_BLOCK_CHANCE_PERCENT aura
460 value
+= GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_CHANCE_PERCENT
);
461 // Increase from rating (exists only on auras)
462 value
+= GetRatingBonusValue(CR_BLOCK
);
463 value
= value
< 0.0f
? 0.0f
: value
;
465 SetStatFloatValue(PLAYER_BLOCK_PERCENTAGE
, value
);
468 void Player::UpdateCritPercentage(WeaponAttackType attType
)
470 BaseModGroup modGroup
;
477 modGroup
= OFFHAND_CRIT_PERCENTAGE
;
478 index
= PLAYER_OFFHAND_CRIT_PERCENTAGE
;
482 modGroup
= RANGED_CRIT_PERCENTAGE
;
483 index
= PLAYER_RANGED_CRIT_PERCENTAGE
;
488 modGroup
= CRIT_PERCENTAGE
;
489 index
= PLAYER_CRIT_PERCENTAGE
;
494 float value
= GetTotalPercentageModValue(modGroup
) + GetRatingBonusValue(cr
);
495 // Modify crit from weapon skill and maximized defense skill of same level victim difference
496 value
+= (int32(GetMaxSkillValueForLevel()) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
497 value
= value
< 0.0f
? 0.0f
: value
;
498 SetStatFloatValue(index
, value
);
501 void Player::UpdateAllCritPercentages()
503 float value
= GetMeleeCritFromAgility();
505 SetBaseModValue(CRIT_PERCENTAGE
, PCT_MOD
, value
);
506 SetBaseModValue(OFFHAND_CRIT_PERCENTAGE
, PCT_MOD
, value
);
507 SetBaseModValue(RANGED_CRIT_PERCENTAGE
, PCT_MOD
, value
);
509 UpdateCritPercentage(BASE_ATTACK
);
510 UpdateCritPercentage(OFF_ATTACK
);
511 UpdateCritPercentage(RANGED_ATTACK
);
514 const float Player::m_diminishing_k
[MAX_CLASSES
] =
529 void Player::UpdateParryPercentage()
531 const float parry_cap
[MAX_CLASSES
] =
533 65.631440f
, // Warrior
534 65.631440f
, // Paladin
535 145.560408f
, // Hunter
536 145.560408f
, // Rogue
539 145.560408f
, // Shaman
548 uint32 pclass
= getClass() - 1;
549 if (CanParry() && parry_cap
[pclass
] > 0.0f
)
552 float nondiminishing
= 5.0f
;
553 float diminishing
= 0.0f
;
554 GetParryFromStrength(diminishing
, nondiminishing
);
556 diminishing
+= GetRatingBonusValue(CR_PARRY
);
557 // Parry from SPELL_AURA_MOD_PARRY_PERCENT aura
558 nondiminishing
+= GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT
);
559 // apply diminishing formula to diminishing parry chance
560 value
= nondiminishing
+ diminishing
* parry_cap
[pclass
] /
561 (diminishing
+ parry_cap
[pclass
] * m_diminishing_k
[pclass
]);
562 value
= value
< 0.0f
? 0.0f
: value
;
564 SetStatFloatValue(PLAYER_PARRY_PERCENTAGE
, value
);
567 void Player::UpdateDodgePercentage()
569 const float dodge_cap
[MAX_CLASSES
] =
571 65.631440f
, // Warrior
572 65.631440f
, // Paladin
573 145.560408f
, // Hunter
574 145.560408f
, // Rogue
575 150.375940f
, // Priest
577 145.560408f
, // Shaman
579 150.375940f
, // Warlock
584 float diminishing
= 0.0f
;
585 float nondiminishing
= 0.0f
;
586 // Dodge from agility
587 GetDodgeFromAgility(diminishing
, nondiminishing
);
588 // Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura
589 nondiminishing
+= GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT
);
591 diminishing
+= GetRatingBonusValue(CR_DODGE
);
592 // apply diminishing formula to diminishing dodge chance
593 uint32 pclass
= getClass() - 1;
594 float value
= nondiminishing
+ (diminishing
* dodge_cap
[pclass
] /
595 (diminishing
+ dodge_cap
[pclass
] * m_diminishing_k
[pclass
]));
596 value
= value
< 0.0f
? 0.0f
: value
;
597 SetStatFloatValue(PLAYER_DODGE_PERCENTAGE
, value
);
600 void Player::UpdateSpellCritChance(uint32 school
)
602 // For normal school set zero crit chance
603 if (school
== SPELL_SCHOOL_NORMAL
)
605 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1
, 0.0f
);
608 // For others recalculate it from:
610 // Crit from Intellect
611 crit
+= GetSpellCritFromIntellect();
612 // Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE
613 crit
+= GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE
);
614 // Increase crit from SPELL_AURA_MOD_ALL_CRIT_CHANCE
615 crit
+= GetTotalAuraModifier(SPELL_AURA_MOD_ALL_CRIT_CHANCE
);
616 // Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
617 crit
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, 1 << school
);
618 // Increase crit from spell crit ratings
619 crit
+= GetRatingBonusValue(CR_CRIT_SPELL
);
622 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1
+ school
, crit
);
625 void Player::UpdateMeleeHitChances()
627 m_modMeleeHitChance
= GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE
);
628 m_modMeleeHitChance
+= GetRatingBonusValue(CR_HIT_MELEE
);
631 void Player::UpdateRangedHitChances()
633 m_modRangedHitChance
= GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE
);
634 m_modRangedHitChance
+= GetRatingBonusValue(CR_HIT_RANGED
);
637 void Player::UpdateSpellHitChances()
639 m_modSpellHitChance
= GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HIT_CHANCE
);
640 m_modSpellHitChance
+= GetRatingBonusValue(CR_HIT_SPELL
);
643 void Player::UpdateAllSpellCritChances()
645 for (int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; ++i
)
646 UpdateSpellCritChance(i
);
649 void Player::UpdateExpertise(WeaponAttackType attack
)
651 if (attack
== RANGED_ATTACK
)
654 int32 expertise
= int32(GetRatingBonusValue(CR_EXPERTISE
));
656 Item
* weapon
= GetWeaponForAttack(attack
);
658 AuraList
const& expAuras
= GetAurasByType(SPELL_AURA_MOD_EXPERTISE
);
659 for (AuraList::const_iterator itr
= expAuras
.begin(); itr
!= expAuras
.end(); ++itr
)
661 // item neutral spell
662 if((*itr
)->GetSpellProto()->GetEquippedItemClass() == -1)
663 expertise
+= (*itr
)->GetModifier()->m_amount
;
664 // item dependent spell
665 else if (weapon
&& weapon
->IsFitToSpellRequirements((*itr
)->GetSpellProto()))
666 expertise
+= (*itr
)->GetModifier()->m_amount
;
674 case BASE_ATTACK
: SetUInt32Value(PLAYER_EXPERTISE
, expertise
); break;
675 case OFF_ATTACK
: SetUInt32Value(PLAYER_OFFHAND_EXPERTISE
, expertise
); break;
680 void Player::UpdateArmorPenetration()
682 m_armorPenetrationPct
= GetRatingBonusValue(CR_ARMOR_PENETRATION
);
684 AuraList
const& armorAuras
= GetAurasByType(SPELL_AURA_MOD_TARGET_ARMOR_PCT
);
685 for (AuraList::const_iterator itr
= armorAuras
.begin(); itr
!= armorAuras
.end(); ++itr
)
687 // affects all weapons
688 if((*itr
)->GetSpellProto()->GetEquippedItemClass() == -1)
690 m_armorPenetrationPct
+= (*itr
)->GetModifier()->m_amount
;
694 // dependent on weapon class
695 for (uint8 i
= 0; i
< MAX_ATTACK
; ++i
)
697 Item
* weapon
= GetWeaponForAttack(WeaponAttackType(i
));
698 if (weapon
&& weapon
->IsFitToSpellRequirements((*itr
)->GetSpellProto()))
700 m_armorPenetrationPct
+= (*itr
)->GetModifier()->m_amount
;
707 void Player::ApplyManaRegenBonus(int32 amount
, bool apply
)
709 m_baseManaRegen
+= apply
? amount
: -amount
;
713 void Player::ApplyHealthRegenBonus(int32 amount
, bool apply
)
715 m_baseHealthRegen
+= apply
? amount
: -amount
;
718 void Player::UpdateManaRegen()
720 float base_regen
= GetCreateMana() * 0.01f
;
722 // Mana regen from spirit and intellect
723 float spirit_regen
= sqrt(GetStat(STAT_INTELLECT
)) * OCTRegenMPPerSpirit();
724 // Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen
725 spirit_regen
*= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT
, POWER_MANA
);
727 // Mana regen from SPELL_AURA_MOD_POWER_REGEN aura
728 float power_regen_mp5
= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN
, POWER_MANA
) / 5.0f
;
730 // Get bonus from SPELL_AURA_MOD_MANA_REGEN_FROM_STAT aura
731 AuraList
const& regenAura
= GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_FROM_STAT
);
732 for (AuraList::const_iterator i
= regenAura
.begin(); i
!= regenAura
.end(); ++i
)
734 Modifier
* mod
= (*i
)->GetModifier();
735 power_regen_mp5
+= GetStat(Stats(mod
->m_miscvalue
)) * mod
->m_amount
/ 500.0f
;
738 // Set regen rate in cast state apply only on spirit based regen
739 int32 modManaRegenInterrupt
= GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
);
740 if (modManaRegenInterrupt
> 100)
741 modManaRegenInterrupt
= 100;
743 SetStatFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER
, base_regen
+ power_regen_mp5
+ spirit_regen
* modManaRegenInterrupt
/ 100.0f
);
744 SetStatFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER
, base_regen
+ 0.001f
+ power_regen_mp5
+ spirit_regen
);
747 void Player::UpdateMasteryAuras()
749 if (!HasAuraType(SPELL_AURA_MASTERY
))
751 SetFloatValue(PLAYER_MASTERY
, 0.0f
);
755 float masteryValue
= GetTotalAuraModifier(SPELL_AURA_MASTERY
) + GetRatingBonusValue(CR_MASTERY
);
756 SetFloatValue(PLAYER_MASTERY
, masteryValue
);
758 std::vector
<uint32
> const* masterySpells
= GetTalentTreeMasterySpells(m_talentsPrimaryTree
[m_activeSpec
]);
762 for (uint32 i
= 0; i
< masterySpells
->size(); ++i
)
764 SpellAuraHolder
* holder
= GetSpellAuraHolder(masterySpells
->at(i
));
768 SpellEntry
const* spellEntry
= holder
->GetSpellProto();
770 // calculate mastery scaling coef
771 int32 masteryCoef
= GetMasteryCoefficient(spellEntry
);
775 // update aura modifiers
776 for (uint32 j
= 0; j
< MAX_EFFECT_INDEX
; ++j
)
778 Aura
* aura
= holder
->GetAuraByEffectIndex(SpellEffectIndex(j
));
782 if (spellEntry
->CalculateSimpleValue(SpellEffectIndex(j
)))
785 aura
->ApplyModifier(false, false);
786 aura
->GetModifier()->m_amount
= int32(masteryValue
* masteryCoef
/ 100.0f
);
787 aura
->ApplyModifier(true, false);
792 void Player::_ApplyAllStatBonuses()
794 SetCanModifyStats(false);
799 SetCanModifyStats(true);
804 void Player::_RemoveAllStatBonuses()
806 SetCanModifyStats(false);
808 _RemoveAllItemMods();
809 _RemoveAllAuraMods();
811 SetCanModifyStats(true);
816 /*#######################################
818 ######## MOBS STAT SYSTEM ########
820 #######################################*/
822 bool Creature::UpdateStats(Stats
/*stat*/)
827 bool Creature::UpdateAllStats()
830 UpdateAttackPowerAndDamage();
832 for (uint32 i
= POWER_MANA
; i
< MAX_POWERS
; ++i
)
833 UpdateMaxPower(Powers(i
));
835 for (int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; ++i
)
836 UpdateResistances(i
);
841 void Creature::UpdateResistances(uint32 school
)
843 if (school
> SPELL_SCHOOL_NORMAL
)
845 float value
= GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START
+ school
));
846 SetResistance(SpellSchools(school
), int32(value
));
852 void Creature::UpdateArmor()
854 float value
= GetTotalAuraModValue(UNIT_MOD_ARMOR
);
855 SetArmor(int32(value
));
858 void Creature::UpdateMaxHealth()
860 float value
= GetTotalAuraModValue(UNIT_MOD_HEALTH
);
861 SetMaxHealth((uint32
)value
);
864 void Creature::UpdateMaxPower(Powers power
)
866 MANGOS_ASSERT(power
< MAX_POWERS
);
868 UnitMods unitMod
= UnitMods(UNIT_MOD_POWER_START
+ power
);
870 float value
= GetTotalAuraModValue(unitMod
);
871 SetMaxPower(power
, uint32(value
));
874 void Creature::UpdateAttackPowerAndDamage(bool ranged
)
876 UnitMods unitMod
= ranged
? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
878 uint16 index
= UNIT_FIELD_ATTACK_POWER
;
879 uint16 index_mod
= UNIT_FIELD_ATTACK_POWER_MOD_POS
;
880 uint16 index_mult
= UNIT_FIELD_ATTACK_POWER_MULTIPLIER
;
884 index
= UNIT_FIELD_RANGED_ATTACK_POWER
;
885 index_mod
= UNIT_FIELD_RANGED_ATTACK_POWER_MOD_POS
;
886 index_mult
= UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER
;
889 float base_attPower
= GetModifierValue(unitMod
, BASE_VALUE
) * GetModifierValue(unitMod
, BASE_PCT
);
890 float attPowerMod
= GetModifierValue(unitMod
, TOTAL_VALUE
);
891 float attPowerMultiplier
= GetModifierValue(unitMod
, TOTAL_PCT
) - 1.0f
;
893 SetInt32Value(index
, (uint32
)base_attPower
); // UNIT_FIELD_(RANGED)_ATTACK_POWER field
894 SetInt32Value(index_mod
, (uint32
)attPowerMod
); // UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
895 SetFloatValue(index_mult
, attPowerMultiplier
); // UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
900 // automatically update weapon damage after attack power modification
901 UpdateDamagePhysical(BASE_ATTACK
);
902 UpdateDamagePhysical(OFF_ATTACK
);
905 void Creature::UpdateDamagePhysical(WeaponAttackType attType
)
907 if (attType
> OFF_ATTACK
)
910 UnitMods unitMod
= (attType
== BASE_ATTACK
? UNIT_MOD_DAMAGE_MAINHAND
: UNIT_MOD_DAMAGE_OFFHAND
);
912 /* difference in AP between current attack power and base value from DB */
913 float att_pwr_change
= GetTotalAttackPowerValue(attType
) - GetCreatureInfo()->attackpower
;
914 float base_value
= GetModifierValue(unitMod
, BASE_VALUE
) + (att_pwr_change
* GetAPMultiplier(attType
, false) / 14.0f
);
915 float base_pct
= GetModifierValue(unitMod
, BASE_PCT
);
916 float total_value
= GetModifierValue(unitMod
, TOTAL_VALUE
);
917 float total_pct
= GetModifierValue(unitMod
, TOTAL_PCT
);
918 float dmg_multiplier
= GetCreatureInfo()->dmg_multiplier
;
920 float weapon_mindamage
= GetWeaponDamageRange(attType
, MINDAMAGE
);
921 float weapon_maxdamage
= GetWeaponDamageRange(attType
, MAXDAMAGE
);
923 float mindamage
= ((base_value
+ weapon_mindamage
) * dmg_multiplier
* base_pct
+ total_value
) * total_pct
;
924 float maxdamage
= ((base_value
+ weapon_maxdamage
) * dmg_multiplier
* base_pct
+ total_value
) * total_pct
;
926 SetStatFloatValue(attType
== BASE_ATTACK
? UNIT_FIELD_MINDAMAGE
: UNIT_FIELD_MINOFFHANDDAMAGE
, mindamage
);
927 SetStatFloatValue(attType
== BASE_ATTACK
? UNIT_FIELD_MAXDAMAGE
: UNIT_FIELD_MAXOFFHANDDAMAGE
, maxdamage
);
930 /*#######################################
932 ######## PETS STAT SYSTEM ########
934 #######################################*/
936 bool Pet::UpdateStats(Stats stat
)
938 if (stat
> STAT_SPIRIT
)
941 // value = ((base_value * base_pct) + total_value) * total_pct
942 float value
= GetTotalStatValue(stat
);
944 Unit
* owner
= GetOwner();
945 if (stat
== STAT_STAMINA
)
948 value
+= float(owner
->GetStat(stat
)) * 0.3f
;
950 // warlock's and mage's pets gain 30% of owner's intellect
951 else if (stat
== STAT_INTELLECT
&& getPetType() == SUMMON_PET
)
953 if (owner
&& (owner
->getClass() == CLASS_WARLOCK
|| owner
->getClass() == CLASS_MAGE
))
954 value
+= float(owner
->GetStat(stat
)) * 0.3f
;
957 SetStat(stat
, int32(value
));
961 case STAT_STRENGTH
: UpdateAttackPowerAndDamage(); break;
962 case STAT_AGILITY
: UpdateArmor(); break;
963 case STAT_STAMINA
: UpdateMaxHealth(); break;
964 case STAT_INTELLECT
: UpdateMaxPower(POWER_MANA
); break;
973 bool Pet::UpdateAllStats()
975 for (int i
= STAT_STRENGTH
; i
< MAX_STATS
; ++i
)
976 UpdateStats(Stats(i
));
978 for (uint32 i
= POWER_MANA
; i
< MAX_POWERS
; ++i
)
979 UpdateMaxPower(Powers(i
));
981 for (int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; ++i
)
982 UpdateResistances(i
);
987 void Pet::UpdateResistances(uint32 school
)
989 if (school
> SPELL_SCHOOL_NORMAL
)
991 float value
= GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START
+ school
));
993 Unit
* owner
= GetOwner();
994 // hunter and warlock pets gain 40% of owner's resistance
995 if (owner
&& (getPetType() == HUNTER_PET
|| (getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_WARLOCK
)))
996 value
+= float(owner
->GetResistance(SpellSchools(school
))) * 0.4f
;
998 SetResistance(SpellSchools(school
), int32(value
));
1004 void Pet::UpdateArmor()
1007 float bonus_armor
= 0.0f
;
1008 UnitMods unitMod
= UNIT_MOD_ARMOR
;
1010 Unit
* owner
= GetOwner();
1011 // hunter and warlock pets gain 35% of owner's armor value
1012 if (owner
&& (getPetType() == HUNTER_PET
|| (getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_WARLOCK
)))
1013 bonus_armor
= 0.35f
* float(owner
->GetArmor());
1015 value
= GetModifierValue(unitMod
, BASE_VALUE
);
1016 value
*= GetModifierValue(unitMod
, BASE_PCT
);
1017 value
+= GetStat(STAT_AGILITY
) * 2.0f
;
1018 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + bonus_armor
;
1019 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
1021 SetArmor(int32(value
));
1024 void Pet::UpdateMaxHealth()
1026 UnitMods unitMod
= UNIT_MOD_HEALTH
;
1027 float stamina
= GetStat(STAT_STAMINA
) - GetCreateStat(STAT_STAMINA
);
1029 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreateHealth();
1030 value
*= GetModifierValue(unitMod
, BASE_PCT
);
1031 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + stamina
* 10.0f
;
1032 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
1034 SetMaxHealth((uint32
)value
);
1037 void Pet::UpdateMaxPower(Powers power
)
1039 MANGOS_ASSERT(power
< MAX_POWERS
);
1041 UnitMods unitMod
= UnitMods(UNIT_MOD_POWER_START
+ power
);
1043 float addValue
= (power
== POWER_MANA
) ? GetStat(STAT_INTELLECT
) - GetCreateStat(STAT_INTELLECT
) : 0.0f
;
1045 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreateMaxPowers(power
);
1046 value
*= GetModifierValue(unitMod
, BASE_PCT
);
1047 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + addValue
* 15.0f
;
1048 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
1050 SetMaxPower(power
, uint32(value
));
1053 void Pet::UpdateAttackPowerAndDamage(bool ranged
)
1059 float bonusAP
= 0.0f
;
1060 UnitMods unitMod
= UNIT_MOD_ATTACK_POWER
;
1062 if (GetEntry() == 416) // imp's attack power
1063 val
= GetStat(STAT_STRENGTH
) - 10.0f
;
1065 val
= 2 * GetStat(STAT_STRENGTH
) - 20.0f
;
1067 Unit
* owner
= GetOwner();
1068 if (owner
&& owner
->GetTypeId() == TYPEID_PLAYER
)
1070 if (getPetType() == HUNTER_PET
) // hunter pets benefit from owner's attack power
1072 bonusAP
= owner
->GetTotalAttackPowerValue(RANGED_ATTACK
) * 0.22f
;
1073 SetBonusDamage(int32(owner
->GetTotalAttackPowerValue(RANGED_ATTACK
) * 0.1287f
));
1075 // demons benefit from warlocks shadow or fire damage
1076 else if (getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_WARLOCK
)
1078 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
);
1079 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
);
1080 int32 maximum
= (fire
> shadow
) ? fire
: shadow
;
1083 SetBonusDamage(int32(maximum
* 0.15f
));
1084 bonusAP
= maximum
* 0.57f
;
1086 // water elementals benefit from mage's frost damage
1087 else if (getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_MAGE
)
1089 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
);
1092 SetBonusDamage(int32(frost
* 0.4f
));
1096 SetModifierValue(UNIT_MOD_ATTACK_POWER
, BASE_VALUE
, val
+ bonusAP
);
1098 // in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB
1099 float base_attPower
= GetModifierValue(unitMod
, BASE_VALUE
) * GetModifierValue(unitMod
, BASE_PCT
);
1100 float attPowerMod
= GetModifierValue(unitMod
, TOTAL_VALUE
);
1101 float attPowerMultiplier
= GetModifierValue(unitMod
, TOTAL_PCT
) - 1.0f
;
1103 // UNIT_FIELD_(RANGED)_ATTACK_POWER field
1104 SetInt32Value(UNIT_FIELD_ATTACK_POWER
, (int32
)base_attPower
);
1105 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
1106 SetInt32Value(UNIT_FIELD_ATTACK_POWER_MOD_POS
, (int32
)attPowerMod
);
1107 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
1108 SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER
, attPowerMultiplier
);
1110 // automatically update weapon damage after attack power modification
1111 UpdateDamagePhysical(BASE_ATTACK
);
1114 void Pet::UpdateDamagePhysical(WeaponAttackType attType
)
1116 if (attType
> BASE_ATTACK
)
1119 UnitMods unitMod
= UNIT_MOD_DAMAGE_MAINHAND
;
1121 float att_speed
= float(GetAttackTime(BASE_ATTACK
)) / 1000.0f
;
1123 float base_value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetTotalAttackPowerValue(attType
) / 14.0f
* att_speed
;
1124 float base_pct
= GetModifierValue(unitMod
, BASE_PCT
);
1125 float total_value
= GetModifierValue(unitMod
, TOTAL_VALUE
);
1126 float total_pct
= GetModifierValue(unitMod
, TOTAL_PCT
);
1128 float weapon_mindamage
= GetWeaponDamageRange(BASE_ATTACK
, MINDAMAGE
);
1129 float weapon_maxdamage
= GetWeaponDamageRange(BASE_ATTACK
, MAXDAMAGE
);
1131 float mindamage
= ((base_value
+ weapon_mindamage
) * base_pct
+ total_value
) * total_pct
;
1132 float maxdamage
= ((base_value
+ weapon_maxdamage
) * base_pct
+ total_value
) * total_pct
;
1134 SetStatFloatValue(UNIT_FIELD_MINDAMAGE
, mindamage
);
1135 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE
, maxdamage
);