2 * Copyright (C) 2005-2010 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
));
132 UpdateAllCritPercentages();
133 UpdateAllSpellCritChances();
134 UpdateDefenseBonusesMod();
135 UpdateShieldBlockValue();
136 UpdateArmorPenetration();
137 UpdateSpellDamageAndHealingBonus();
139 UpdateExpertise(BASE_ATTACK
);
140 UpdateExpertise(OFF_ATTACK
);
141 for (int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; ++i
)
142 UpdateResistances(i
);
147 void Player::UpdateResistances(uint32 school
)
149 if(school
> SPELL_SCHOOL_NORMAL
)
151 float value
= GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START
+ school
));
152 SetResistance(SpellSchools(school
), int32(value
));
156 pet
->UpdateResistances(school
);
162 void Player::UpdateArmor()
165 UnitMods unitMod
= UNIT_MOD_ARMOR
;
167 value
= GetModifierValue(unitMod
, BASE_VALUE
); // base armor (from items)
168 value
*= GetModifierValue(unitMod
, BASE_PCT
); // armor percent from items
169 value
+= GetStat(STAT_AGILITY
) * 2.0f
; // armor bonus from stats
170 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
);
172 //add dynamic flat mods
173 AuraList
const& mResbyIntellect
= GetAurasByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT
);
174 for(AuraList::const_iterator i
= mResbyIntellect
.begin();i
!= mResbyIntellect
.end(); ++i
)
176 Modifier
* mod
= (*i
)->GetModifier();
177 if(mod
->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
178 value
+= int32(GetStat(Stats((*i
)->GetMiscBValue())) * mod
->m_amount
/ 100.0f
);
181 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
183 SetArmor(int32(value
));
189 UpdateAttackPowerAndDamage(); // armor dependent auras update for SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR
192 float Player::GetHealthBonusFromStamina()
194 float stamina
= GetStat(STAT_STAMINA
);
196 float baseStam
= stamina
< 20 ? stamina
: 20;
197 float moreStam
= stamina
- baseStam
;
199 return baseStam
+ (moreStam
*10.0f
);
202 float Player::GetManaBonusFromIntellect()
204 float intellect
= GetStat(STAT_INTELLECT
);
206 float baseInt
= intellect
< 20 ? intellect
: 20;
207 float moreInt
= intellect
- baseInt
;
209 return baseInt
+ (moreInt
*15.0f
);
212 void Player::UpdateMaxHealth()
214 UnitMods unitMod
= UNIT_MOD_HEALTH
;
216 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreateHealth();
217 value
*= GetModifierValue(unitMod
, BASE_PCT
);
218 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + GetHealthBonusFromStamina();
219 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
221 SetMaxHealth((uint32
)value
);
224 void Player::UpdateMaxPower(Powers power
)
226 UnitMods unitMod
= UnitMods(UNIT_MOD_POWER_START
+ power
);
228 uint32 create_power
= GetCreatePowers(power
);
230 // ignore classes without mana
231 float bonusPower
= (power
== POWER_MANA
&& create_power
> 0) ? GetManaBonusFromIntellect() : 0;
233 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + create_power
;
234 value
*= GetModifierValue(unitMod
, BASE_PCT
);
235 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + bonusPower
;
236 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
238 SetMaxPower(power
, uint32(value
));
241 void Player::ApplyFeralAPBonus(int32 amount
, bool apply
)
243 m_baseFeralAP
+= apply
? amount
:-amount
;
244 UpdateAttackPowerAndDamage();
247 void Player::UpdateAttackPowerAndDamage(bool ranged
)
250 float level
= float(getLevel());
252 UnitMods unitMod
= ranged
? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
254 uint16 index
= UNIT_FIELD_ATTACK_POWER
;
255 uint16 index_mod
= UNIT_FIELD_ATTACK_POWER_MODS
;
256 uint16 index_mult
= UNIT_FIELD_ATTACK_POWER_MULTIPLIER
;
260 index
= UNIT_FIELD_RANGED_ATTACK_POWER
;
261 index_mod
= UNIT_FIELD_RANGED_ATTACK_POWER_MODS
;
262 index_mult
= UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER
;
266 case CLASS_HUNTER
: val2
= level
* 2.0f
+ GetStat(STAT_AGILITY
) - 10.0f
; break;
267 case CLASS_ROGUE
: val2
= level
+ GetStat(STAT_AGILITY
) - 10.0f
; break;
268 case CLASS_WARRIOR
:val2
= level
+ GetStat(STAT_AGILITY
) - 10.0f
; break;
277 val2
= GetStat(STAT_AGILITY
) - 10.0f
; break;
280 default: val2
= GetStat(STAT_AGILITY
) - 10.0f
; break;
287 case CLASS_WARRIOR
: val2
= level
*3.0f
+ GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
288 case CLASS_PALADIN
: val2
= level
*3.0f
+ GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
289 case CLASS_DEATH_KNIGHT
: val2
= level
*3.0f
+ GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
290 case CLASS_ROGUE
: val2
= level
*2.0f
+ GetStat(STAT_STRENGTH
) + GetStat(STAT_AGILITY
) - 20.0f
; break;
291 case CLASS_HUNTER
: val2
= level
*2.0f
+ GetStat(STAT_STRENGTH
) + GetStat(STAT_AGILITY
) - 20.0f
; break;
292 case CLASS_SHAMAN
: val2
= level
*2.0f
+ GetStat(STAT_STRENGTH
) + GetStat(STAT_AGILITY
) - 20.0f
; break;
295 //Check if Predatory Strikes is skilled
296 float mLevelMult
= 0.0;
304 Unit::AuraList
const& mDummy
= GetAurasByType(SPELL_AURA_DUMMY
);
305 for(Unit::AuraList::const_iterator itr
= mDummy
.begin(); itr
!= mDummy
.end(); ++itr
)
307 // Predatory Strikes (effect 0)
308 if ((*itr
)->GetEffIndex()==0 && (*itr
)->GetSpellProto()->SpellIconID
== 1563)
310 mLevelMult
= (*itr
)->GetModifier()->m_amount
/ 100.0f
;
322 val2
= getLevel()*(mLevelMult
+2.0f
) + GetStat(STAT_STRENGTH
)*2.0f
+ GetStat(STAT_AGILITY
) - 20.0f
+ m_baseFeralAP
; break;
325 val2
= getLevel()*(mLevelMult
+3.0f
) + GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
+ m_baseFeralAP
; break;
327 val2
= getLevel()*(mLevelMult
+1.5f
) + GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
+ m_baseFeralAP
; break;
329 val2
= GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
333 case CLASS_MAGE
: val2
= GetStat(STAT_STRENGTH
) - 10.0f
; break;
334 case CLASS_PRIEST
: val2
= GetStat(STAT_STRENGTH
) - 10.0f
; break;
335 case CLASS_WARLOCK
: val2
= GetStat(STAT_STRENGTH
) - 10.0f
; break;
339 SetModifierValue(unitMod
, BASE_VALUE
, val2
);
341 float base_attPower
= GetModifierValue(unitMod
, BASE_VALUE
) * GetModifierValue(unitMod
, BASE_PCT
);
342 float attPowerMod
= GetModifierValue(unitMod
, TOTAL_VALUE
);
344 //add dynamic flat mods
347 if ((getClassMask() & CLASSMASK_WAND_USERS
)==0)
349 AuraList
const& mRAPbyStat
= GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT
);
350 for(AuraList::const_iterator i
= mRAPbyStat
.begin();i
!= mRAPbyStat
.end(); ++i
)
351 attPowerMod
+= int32(GetStat(Stats((*i
)->GetModifier()->m_miscvalue
)) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
356 AuraList
const& mAPbyStat
= GetAurasByType(SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT
);
357 for(AuraList::const_iterator i
= mAPbyStat
.begin();i
!= mAPbyStat
.end(); ++i
)
358 attPowerMod
+= int32(GetStat(Stats((*i
)->GetModifier()->m_miscvalue
)) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
360 AuraList
const& mAPbyArmor
= GetAurasByType(SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR
);
361 for(AuraList::const_iterator iter
= mAPbyArmor
.begin(); iter
!= mAPbyArmor
.end(); ++iter
)
362 // always: ((*i)->GetModifier()->m_miscvalue == 1 == SPELL_SCHOOL_MASK_NORMAL)
363 attPowerMod
+= int32(GetArmor() / (*iter
)->GetModifier()->m_amount
);
366 float attPowerMultiplier
= GetModifierValue(unitMod
, TOTAL_PCT
) - 1.0f
;
368 SetInt32Value(index
, (uint32
)base_attPower
); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
369 SetInt32Value(index_mod
, (uint32
)attPowerMod
); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
370 SetFloatValue(index_mult
, attPowerMultiplier
); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
372 //automatically update weapon damage after attack power modification
375 UpdateDamagePhysical(RANGED_ATTACK
);
377 Pet
*pet
= GetPet(); //update pet's AP
379 pet
->UpdateAttackPowerAndDamage();
383 UpdateDamagePhysical(BASE_ATTACK
);
384 if(CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon
385 UpdateDamagePhysical(OFF_ATTACK
);
389 void Player::UpdateShieldBlockValue()
391 SetUInt32Value(PLAYER_SHIELD_BLOCK
, GetShieldBlockValue());
394 void Player::CalculateMinMaxDamage(WeaponAttackType attType
, bool normalized
, float& min_damage
, float& max_damage
)
403 unitMod
= UNIT_MOD_DAMAGE_MAINHAND
;
404 attPower
= UNIT_MOD_ATTACK_POWER
;
407 unitMod
= UNIT_MOD_DAMAGE_OFFHAND
;
408 attPower
= UNIT_MOD_ATTACK_POWER
;
411 unitMod
= UNIT_MOD_DAMAGE_RANGED
;
412 attPower
= UNIT_MOD_ATTACK_POWER_RANGED
;
416 float att_speed
= GetAPMultiplier(attType
,normalized
);
418 float base_value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetTotalAttackPowerValue(attType
)/ 14.0f
* att_speed
;
419 float base_pct
= GetModifierValue(unitMod
, BASE_PCT
);
420 float total_value
= GetModifierValue(unitMod
, TOTAL_VALUE
);
421 float total_pct
= GetModifierValue(unitMod
, TOTAL_PCT
);
423 float weapon_mindamage
= GetWeaponDamageRange(attType
, MINDAMAGE
);
424 float weapon_maxdamage
= GetWeaponDamageRange(attType
, MAXDAMAGE
);
426 if (IsInFeralForm()) //check if player is druid and in cat or bear forms
428 uint32 lvl
= getLevel();
429 if ( lvl
> 60 ) lvl
= 60;
431 weapon_mindamage
= lvl
*0.85*att_speed
;
432 weapon_maxdamage
= lvl
*1.25*att_speed
;
434 else if(!IsUseEquipedWeapon(attType
==BASE_ATTACK
)) //check if player not in form but still can't use weapon (broken/etc)
436 weapon_mindamage
= BASE_MINDAMAGE
;
437 weapon_maxdamage
= BASE_MAXDAMAGE
;
439 else if(attType
== RANGED_ATTACK
) //add ammo DPS to ranged damage
441 weapon_mindamage
+= GetAmmoDPS() * att_speed
;
442 weapon_maxdamage
+= GetAmmoDPS() * att_speed
;
445 min_damage
= ((base_value
+ weapon_mindamage
) * base_pct
+ total_value
) * total_pct
;
446 max_damage
= ((base_value
+ weapon_maxdamage
) * base_pct
+ total_value
) * total_pct
;
449 void Player::UpdateDamagePhysical(WeaponAttackType attType
)
454 CalculateMinMaxDamage(attType
,false,mindamage
,maxdamage
);
460 SetStatFloatValue(UNIT_FIELD_MINDAMAGE
,mindamage
);
461 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE
,maxdamage
);
464 SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE
,mindamage
);
465 SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE
,maxdamage
);
468 SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE
,mindamage
);
469 SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE
,maxdamage
);
474 void Player::UpdateDefenseBonusesMod()
476 UpdateBlockPercentage();
477 UpdateParryPercentage();
478 UpdateDodgePercentage();
481 void Player::UpdateBlockPercentage()
489 // Modify value from defense skill
490 value
+= (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
491 // Increase from SPELL_AURA_MOD_BLOCK_PERCENT aura
492 value
+= GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT
);
493 // Increase from rating
494 value
+= GetRatingBonusValue(CR_BLOCK
);
495 value
= value
< 0.0f
? 0.0f
: value
;
497 SetStatFloatValue(PLAYER_BLOCK_PERCENTAGE
, value
);
500 void Player::UpdateCritPercentage(WeaponAttackType attType
)
502 BaseModGroup modGroup
;
509 modGroup
= OFFHAND_CRIT_PERCENTAGE
;
510 index
= PLAYER_OFFHAND_CRIT_PERCENTAGE
;
514 modGroup
= RANGED_CRIT_PERCENTAGE
;
515 index
= PLAYER_RANGED_CRIT_PERCENTAGE
;
520 modGroup
= CRIT_PERCENTAGE
;
521 index
= PLAYER_CRIT_PERCENTAGE
;
526 float value
= GetTotalPercentageModValue(modGroup
) + GetRatingBonusValue(cr
);
527 // Modify crit from weapon skill and maximized defense skill of same level victim difference
528 value
+= (int32(GetWeaponSkillValue(attType
)) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
529 value
= value
< 0.0f
? 0.0f
: value
;
530 SetStatFloatValue(index
, value
);
533 void Player::UpdateAllCritPercentages()
535 float value
= GetMeleeCritFromAgility();
537 SetBaseModValue(CRIT_PERCENTAGE
, PCT_MOD
, value
);
538 SetBaseModValue(OFFHAND_CRIT_PERCENTAGE
, PCT_MOD
, value
);
539 SetBaseModValue(RANGED_CRIT_PERCENTAGE
, PCT_MOD
, value
);
541 UpdateCritPercentage(BASE_ATTACK
);
542 UpdateCritPercentage(OFF_ATTACK
);
543 UpdateCritPercentage(RANGED_ATTACK
);
546 void Player::UpdateParryPercentage()
554 // Modify value from defense skill
555 value
+= (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
556 // Parry from SPELL_AURA_MOD_PARRY_PERCENT aura
557 value
+= GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT
);
559 value
+= GetRatingBonusValue(CR_PARRY
);
560 value
= value
< 0.0f
? 0.0f
: value
;
562 SetStatFloatValue(PLAYER_PARRY_PERCENTAGE
, value
);
565 void Player::UpdateDodgePercentage()
567 // Dodge from agility
568 float value
= GetDodgeFromAgility();
569 // Modify value from defense skill
570 value
+= (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
571 // Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura
572 value
+= GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT
);
574 value
+= GetRatingBonusValue(CR_DODGE
);
575 value
= value
< 0.0f
? 0.0f
: value
;
576 SetStatFloatValue(PLAYER_DODGE_PERCENTAGE
, value
);
579 void Player::UpdateSpellCritChance(uint32 school
)
581 // For normal school set zero crit chance
582 if(school
== SPELL_SCHOOL_NORMAL
)
584 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1
, 0.0f
);
587 // For others recalculate it from:
589 // Crit from Intellect
590 crit
+= GetSpellCritFromIntellect();
591 // Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE
592 crit
+= GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE
);
593 // Increase crit from SPELL_AURA_MOD_ALL_CRIT_CHANCE
594 crit
+= GetTotalAuraModifier(SPELL_AURA_MOD_ALL_CRIT_CHANCE
);
595 // Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
596 crit
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, 1<<school
);
597 // Increase crit from spell crit ratings
598 crit
+= GetRatingBonusValue(CR_CRIT_SPELL
);
601 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1
+ school
, crit
);
604 void Player::UpdateMeleeHitChances()
606 m_modMeleeHitChance
= GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE
);
607 m_modMeleeHitChance
+= GetRatingBonusValue(CR_HIT_MELEE
);
610 void Player::UpdateRangedHitChances()
612 m_modRangedHitChance
= GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE
);
613 m_modRangedHitChance
+= GetRatingBonusValue(CR_HIT_RANGED
);
616 void Player::UpdateSpellHitChances()
618 m_modSpellHitChance
= GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HIT_CHANCE
);
619 m_modSpellHitChance
+= GetRatingBonusValue(CR_HIT_SPELL
);
622 void Player::UpdateAllSpellCritChances()
624 for (int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; ++i
)
625 UpdateSpellCritChance(i
);
628 void Player::UpdateExpertise(WeaponAttackType attack
)
630 if(attack
==RANGED_ATTACK
)
633 int32 expertise
= int32(GetRatingBonusValue(CR_EXPERTISE
));
635 Item
*weapon
= GetWeaponForAttack(attack
);
637 AuraList
const& expAuras
= GetAurasByType(SPELL_AURA_MOD_EXPERTISE
);
638 for(AuraList::const_iterator itr
= expAuras
.begin(); itr
!= expAuras
.end(); ++itr
)
640 // item neutral spell
641 if((*itr
)->GetSpellProto()->EquippedItemClass
== -1)
642 expertise
+= (*itr
)->GetModifier()->m_amount
;
643 // item dependent spell
644 else if(weapon
&& weapon
->IsFitToSpellRequirements((*itr
)->GetSpellProto()))
645 expertise
+= (*itr
)->GetModifier()->m_amount
;
653 case BASE_ATTACK
: SetUInt32Value(PLAYER_EXPERTISE
, expertise
); break;
654 case OFF_ATTACK
: SetUInt32Value(PLAYER_OFFHAND_EXPERTISE
, expertise
); break;
659 void Player::UpdateArmorPenetration()
661 m_armorPenetrationPct
= GetRatingBonusValue(CR_ARMOR_PENETRATION
);
663 AuraList
const& armorAuras
= GetAurasByType(SPELL_AURA_MOD_TARGET_ARMOR_PCT
);
664 for(AuraList::const_iterator itr
= armorAuras
.begin(); itr
!= armorAuras
.end(); ++itr
)
666 // affects all weapons
667 if((*itr
)->GetSpellProto()->EquippedItemClass
== -1)
669 m_armorPenetrationPct
+= (*itr
)->GetModifier()->m_amount
;
673 // dependent on weapon class
674 for(uint8 i
= 0; i
< MAX_ATTACK
; ++i
)
676 Item
*weapon
= GetWeaponForAttack(WeaponAttackType(i
));
677 if(weapon
&& weapon
->IsFitToSpellRequirements((*itr
)->GetSpellProto()))
679 m_armorPenetrationPct
+= (*itr
)->GetModifier()->m_amount
;
686 void Player::ApplyManaRegenBonus(int32 amount
, bool apply
)
688 m_baseManaRegen
+= apply
? amount
: -amount
;
692 void Player::UpdateManaRegen()
694 float Intellect
= GetStat(STAT_INTELLECT
);
695 // Mana regen from spirit and intellect
696 float power_regen
= sqrt(Intellect
) * OCTRegenMPPerSpirit();
697 // Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen
698 power_regen
*= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT
, POWER_MANA
);
700 // Mana regen from SPELL_AURA_MOD_POWER_REGEN aura
701 float power_regen_mp5
= (GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN
, POWER_MANA
) + m_baseManaRegen
) / 5.0f
;
703 // Get bonus from SPELL_AURA_MOD_MANA_REGEN_FROM_STAT aura
704 AuraList
const& regenAura
= GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_FROM_STAT
);
705 for(AuraList::const_iterator i
= regenAura
.begin();i
!= regenAura
.end(); ++i
)
707 Modifier
* mod
= (*i
)->GetModifier();
708 power_regen_mp5
+= GetStat(Stats(mod
->m_miscvalue
)) * mod
->m_amount
/ 500.0f
;
711 // Set regen rate in cast state apply only on spirit based regen
712 int32 modManaRegenInterrupt
= GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
);
713 if (modManaRegenInterrupt
> 100)
714 modManaRegenInterrupt
= 100;
715 SetStatFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER
, power_regen_mp5
+ power_regen
* modManaRegenInterrupt
/ 100.0f
);
717 SetStatFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER
, power_regen_mp5
+ power_regen
);
720 void Player::_ApplyAllStatBonuses()
722 SetCanModifyStats(false);
727 SetCanModifyStats(true);
732 void Player::_RemoveAllStatBonuses()
734 SetCanModifyStats(false);
736 _RemoveAllItemMods();
737 _RemoveAllAuraMods();
739 SetCanModifyStats(true);
744 /*#######################################
746 ######## MOBS STAT SYSTEM ########
748 #######################################*/
750 bool Creature::UpdateStats(Stats
/*stat*/)
755 bool Creature::UpdateAllStats()
758 UpdateAttackPowerAndDamage();
760 for(int i
= POWER_MANA
; i
< MAX_POWERS
; ++i
)
761 UpdateMaxPower(Powers(i
));
763 for(int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; ++i
)
764 UpdateResistances(i
);
769 void Creature::UpdateResistances(uint32 school
)
771 if(school
> SPELL_SCHOOL_NORMAL
)
773 float value
= GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START
+ school
));
774 SetResistance(SpellSchools(school
), int32(value
));
780 void Creature::UpdateArmor()
782 float value
= GetTotalAuraModValue(UNIT_MOD_ARMOR
);
783 SetArmor(int32(value
));
786 void Creature::UpdateMaxHealth()
788 float value
= GetTotalAuraModValue(UNIT_MOD_HEALTH
);
789 SetMaxHealth((uint32
)value
);
792 void Creature::UpdateMaxPower(Powers power
)
794 UnitMods unitMod
= UnitMods(UNIT_MOD_POWER_START
+ power
);
796 float value
= GetTotalAuraModValue(unitMod
);
797 SetMaxPower(power
, uint32(value
));
800 void Creature::UpdateAttackPowerAndDamage(bool ranged
)
802 UnitMods unitMod
= ranged
? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
804 uint16 index
= UNIT_FIELD_ATTACK_POWER
;
805 uint16 index_mod
= UNIT_FIELD_ATTACK_POWER_MODS
;
806 uint16 index_mult
= UNIT_FIELD_ATTACK_POWER_MULTIPLIER
;
810 index
= UNIT_FIELD_RANGED_ATTACK_POWER
;
811 index_mod
= UNIT_FIELD_RANGED_ATTACK_POWER_MODS
;
812 index_mult
= UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER
;
815 float base_attPower
= GetModifierValue(unitMod
, BASE_VALUE
) * GetModifierValue(unitMod
, BASE_PCT
);
816 float attPowerMod
= GetModifierValue(unitMod
, TOTAL_VALUE
);
817 float attPowerMultiplier
= GetModifierValue(unitMod
, TOTAL_PCT
) - 1.0f
;
819 SetInt32Value(index
, (uint32
)base_attPower
); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
820 SetInt32Value(index_mod
, (uint32
)attPowerMod
); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
821 SetFloatValue(index_mult
, attPowerMultiplier
); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
825 //automatically update weapon damage after attack power modification
826 UpdateDamagePhysical(BASE_ATTACK
);
829 void Creature::UpdateDamagePhysical(WeaponAttackType attType
)
831 if(attType
> BASE_ATTACK
)
834 UnitMods unitMod
= UNIT_MOD_DAMAGE_MAINHAND
;
836 /* difference in AP between current attack power and base value from DB */
837 float att_pwr_change
= GetTotalAttackPowerValue(attType
) - GetCreatureInfo()->attackpower
;
838 float base_value
= GetModifierValue(unitMod
, BASE_VALUE
) + (att_pwr_change
* GetAPMultiplier(attType
, false) / 14.0f
);
839 float base_pct
= GetModifierValue(unitMod
, BASE_PCT
);
840 float total_value
= GetModifierValue(unitMod
, TOTAL_VALUE
);
841 float total_pct
= GetModifierValue(unitMod
, TOTAL_PCT
);
842 float dmg_multiplier
= GetCreatureInfo()->dmg_multiplier
;
844 float weapon_mindamage
= GetWeaponDamageRange(BASE_ATTACK
, MINDAMAGE
);
845 float weapon_maxdamage
= GetWeaponDamageRange(BASE_ATTACK
, MAXDAMAGE
);
847 float mindamage
= ((base_value
+ weapon_mindamage
) * dmg_multiplier
* base_pct
+ total_value
) * total_pct
;
848 float maxdamage
= ((base_value
+ weapon_maxdamage
) * dmg_multiplier
* base_pct
+ total_value
) * total_pct
;
850 SetStatFloatValue(UNIT_FIELD_MINDAMAGE
, mindamage
);
851 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE
, maxdamage
);
854 /*#######################################
856 ######## PETS STAT SYSTEM ########
858 #######################################*/
860 bool Pet::UpdateStats(Stats stat
)
862 if(stat
> STAT_SPIRIT
)
865 // value = ((base_value * base_pct) + total_value) * total_pct
866 float value
= GetTotalStatValue(stat
);
868 Unit
*owner
= GetOwner();
869 if ( stat
== STAT_STAMINA
)
872 value
+= float(owner
->GetStat(stat
)) * 0.3f
;
874 //warlock's and mage's pets gain 30% of owner's intellect
875 else if ( stat
== STAT_INTELLECT
&& getPetType() == SUMMON_PET
)
877 if(owner
&& (owner
->getClass() == CLASS_WARLOCK
|| owner
->getClass() == CLASS_MAGE
) )
878 value
+= float(owner
->GetStat(stat
)) * 0.3f
;
881 SetStat(stat
, int32(value
));
885 case STAT_STRENGTH
: UpdateAttackPowerAndDamage(); break;
886 case STAT_AGILITY
: UpdateArmor(); break;
887 case STAT_STAMINA
: UpdateMaxHealth(); break;
888 case STAT_INTELLECT
: UpdateMaxPower(POWER_MANA
); break;
897 bool Pet::UpdateAllStats()
899 for (int i
= STAT_STRENGTH
; i
< MAX_STATS
; ++i
)
900 UpdateStats(Stats(i
));
902 for(int i
= POWER_MANA
; i
< MAX_POWERS
; ++i
)
903 UpdateMaxPower(Powers(i
));
905 for (int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; ++i
)
906 UpdateResistances(i
);
911 void Pet::UpdateResistances(uint32 school
)
913 if(school
> SPELL_SCHOOL_NORMAL
)
915 float value
= GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START
+ school
));
917 Unit
*owner
= GetOwner();
918 // hunter and warlock pets gain 40% of owner's resistance
919 if(owner
&& (getPetType() == HUNTER_PET
|| (getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_WARLOCK
)))
920 value
+= float(owner
->GetResistance(SpellSchools(school
))) * 0.4f
;
922 SetResistance(SpellSchools(school
), int32(value
));
928 void Pet::UpdateArmor()
931 float bonus_armor
= 0.0f
;
932 UnitMods unitMod
= UNIT_MOD_ARMOR
;
934 Unit
*owner
= GetOwner();
935 // hunter and warlock pets gain 35% of owner's armor value
936 if(owner
&& (getPetType() == HUNTER_PET
|| (getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_WARLOCK
)))
937 bonus_armor
= 0.35f
* float(owner
->GetArmor());
939 value
= GetModifierValue(unitMod
, BASE_VALUE
);
940 value
*= GetModifierValue(unitMod
, BASE_PCT
);
941 value
+= GetStat(STAT_AGILITY
) * 2.0f
;
942 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + bonus_armor
;
943 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
945 SetArmor(int32(value
));
948 void Pet::UpdateMaxHealth()
950 UnitMods unitMod
= UNIT_MOD_HEALTH
;
951 float stamina
= GetStat(STAT_STAMINA
) - GetCreateStat(STAT_STAMINA
);
953 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreateHealth();
954 value
*= GetModifierValue(unitMod
, BASE_PCT
);
955 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + stamina
* 10.0f
;
956 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
958 SetMaxHealth((uint32
)value
);
961 void Pet::UpdateMaxPower(Powers power
)
963 UnitMods unitMod
= UnitMods(UNIT_MOD_POWER_START
+ power
);
965 float addValue
= (power
== POWER_MANA
) ? GetStat(STAT_INTELLECT
) - GetCreateStat(STAT_INTELLECT
) : 0.0f
;
967 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreatePowers(power
);
968 value
*= GetModifierValue(unitMod
, BASE_PCT
);
969 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + addValue
* 15.0f
;
970 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
972 SetMaxPower(power
, uint32(value
));
975 void Pet::UpdateAttackPowerAndDamage(bool ranged
)
981 float bonusAP
= 0.0f
;
982 UnitMods unitMod
= UNIT_MOD_ATTACK_POWER
;
984 if(GetEntry() == 416) // imp's attack power
985 val
= GetStat(STAT_STRENGTH
) - 10.0f
;
987 val
= 2 * GetStat(STAT_STRENGTH
) - 20.0f
;
989 Unit
* owner
= GetOwner();
990 if( owner
&& owner
->GetTypeId()==TYPEID_PLAYER
)
992 if(getPetType() == HUNTER_PET
) //hunter pets benefit from owner's attack power
994 bonusAP
= owner
->GetTotalAttackPowerValue(RANGED_ATTACK
) * 0.22f
;
995 SetBonusDamage( int32(owner
->GetTotalAttackPowerValue(RANGED_ATTACK
) * 0.1287f
));
997 //demons benefit from warlocks shadow or fire damage
998 else if(getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_WARLOCK
)
1000 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
);
1001 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
);
1002 int32 maximum
= (fire
> shadow
) ? fire
: shadow
;
1005 SetBonusDamage( int32(maximum
* 0.15f
));
1006 bonusAP
= maximum
* 0.57f
;
1008 //water elementals benefit from mage's frost damage
1009 else if(getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_MAGE
)
1011 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
);
1014 SetBonusDamage( int32(frost
* 0.4f
));
1018 SetModifierValue(UNIT_MOD_ATTACK_POWER
, BASE_VALUE
, val
+ bonusAP
);
1020 //in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB
1021 float base_attPower
= GetModifierValue(unitMod
, BASE_VALUE
) * GetModifierValue(unitMod
, BASE_PCT
);
1022 float attPowerMod
= GetModifierValue(unitMod
, TOTAL_VALUE
);
1023 float attPowerMultiplier
= GetModifierValue(unitMod
, TOTAL_PCT
) - 1.0f
;
1025 //UNIT_FIELD_(RANGED)_ATTACK_POWER field
1026 SetInt32Value(UNIT_FIELD_ATTACK_POWER
, (int32
)base_attPower
);
1027 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
1028 SetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS
, (int32
)attPowerMod
);
1029 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
1030 SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER
, attPowerMultiplier
);
1032 //automatically update weapon damage after attack power modification
1033 UpdateDamagePhysical(BASE_ATTACK
);
1036 void Pet::UpdateDamagePhysical(WeaponAttackType attType
)
1038 if(attType
> BASE_ATTACK
)
1041 UnitMods unitMod
= UNIT_MOD_DAMAGE_MAINHAND
;
1043 float att_speed
= float(GetAttackTime(BASE_ATTACK
))/1000.0f
;
1045 float base_value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetTotalAttackPowerValue(attType
)/ 14.0f
* att_speed
;
1046 float base_pct
= GetModifierValue(unitMod
, BASE_PCT
);
1047 float total_value
= GetModifierValue(unitMod
, TOTAL_VALUE
);
1048 float total_pct
= GetModifierValue(unitMod
, TOTAL_PCT
);
1050 float weapon_mindamage
= GetWeaponDamageRange(BASE_ATTACK
, MINDAMAGE
);
1051 float weapon_maxdamage
= GetWeaponDamageRange(BASE_ATTACK
, MAXDAMAGE
);
1053 float mindamage
= ((base_value
+ weapon_mindamage
) * base_pct
+ total_value
) * total_pct
;
1054 float maxdamage
= ((base_value
+ weapon_maxdamage
) * base_pct
+ total_value
) * total_pct
;
1056 // Pet's base damage changes depending on happiness
1057 if (getPetType() == HUNTER_PET
&& attType
== BASE_ATTACK
)
1059 switch(GetHappinessState())
1062 // 125% of normal damage
1063 mindamage
= mindamage
* 1.25;
1064 maxdamage
= maxdamage
* 1.25;
1067 // 100% of normal damage, nothing to modify
1070 // 75% of normal damage
1071 mindamage
= mindamage
* 0.75;
1072 maxdamage
= maxdamage
* 0.75;
1077 SetStatFloatValue(UNIT_FIELD_MINDAMAGE
, mindamage
);
1078 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE
, maxdamage
);