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::ApplySpellDamageBonus(int32 amount
, bool apply
)
96 m_baseSpellDamage
+=apply
?amount
:-amount
;
97 // For speed just update for client
98 ApplyModUInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS
, amount
, apply
);
101 void Player::ApplySpellHealingBonus(int32 amount
, bool apply
)
103 m_baseSpellHealing
+=apply
?amount
:-amount
;
104 // For speed just update for client
105 for(int i
= SPELL_SCHOOL_HOLY
; i
< MAX_SPELL_SCHOOL
; i
++)
106 ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS
+i
, amount
, apply
);;
109 void Player::UpdateSpellDamageAndHealingBonus()
111 // Magic damage modifiers implemented in Unit::SpellDamageBonus
112 // This information for client side use only
113 // Get healing bonus for all schools
114 SetStatInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS
, SpellBaseHealingBonus(SPELL_SCHOOL_MASK_ALL
));
115 // Get damage bonus for all schools
116 for(int i
= SPELL_SCHOOL_HOLY
; i
< MAX_SPELL_SCHOOL
; i
++)
117 SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS
+i
, SpellBaseDamageBonus(SpellSchoolMask(1 << i
)));
120 bool Player::UpdateAllStats()
122 for (int i
= STAT_STRENGTH
; i
< MAX_STATS
; i
++)
124 float value
= GetTotalStatValue(Stats(i
));
125 SetStat(Stats(i
), (int32
)value
);
128 UpdateAttackPowerAndDamage();
129 UpdateAttackPowerAndDamage(true);
133 for(int i
= POWER_MANA
; i
< MAX_POWERS
; i
++)
134 UpdateMaxPower(Powers(i
));
136 UpdateAllCritPercentages();
137 UpdateAllSpellCritChances();
138 UpdateDefenseBonusesMod();
139 UpdateShieldBlockValue();
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
+= GetStat(STAT_AGILITY
) * 2.0f
; // armor bonus from stats
173 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
);
175 //add dynamic flat mods
176 AuraList
const& mResbyIntellect
= GetAurasByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT
);
177 for(AuraList::const_iterator i
= mResbyIntellect
.begin();i
!= mResbyIntellect
.end(); ++i
)
179 Modifier
* mod
= (*i
)->GetModifier();
180 if(mod
->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
181 value
+= int32(GetStat(Stats((*i
)->GetMiscBValue())) * mod
->m_amount
/ 100.0f
);
184 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
186 SetArmor(int32(value
));
193 float Player::GetHealthBonusFromStamina()
195 float stamina
= GetStat(STAT_STAMINA
);
197 float baseStam
= stamina
< 20 ? stamina
: 20;
198 float moreStam
= stamina
- baseStam
;
200 return baseStam
+ (moreStam
*10.0f
);
203 float Player::GetManaBonusFromIntellect()
205 float intellect
= GetStat(STAT_INTELLECT
);
207 float baseInt
= intellect
< 20 ? intellect
: 20;
208 float moreInt
= intellect
- baseInt
;
210 return baseInt
+ (moreInt
*15.0f
);
213 void Player::UpdateMaxHealth()
215 UnitMods unitMod
= UNIT_MOD_HEALTH
;
217 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreateHealth();
218 value
*= GetModifierValue(unitMod
, BASE_PCT
);
219 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + GetHealthBonusFromStamina();
220 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
222 SetMaxHealth((uint32
)value
);
225 void Player::UpdateMaxPower(Powers power
)
227 UnitMods unitMod
= UnitMods(UNIT_MOD_POWER_START
+ power
);
229 float bonusPower
= (power
== POWER_MANA
) ? GetManaBonusFromIntellect() : 0;
231 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreatePowers(power
);
232 value
*= GetModifierValue(unitMod
, BASE_PCT
);
233 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + bonusPower
;
234 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
236 SetMaxPower(power
, uint32(value
));
239 void Player::ApplyFeralAPBonus(int32 amount
, bool apply
)
241 m_baseFeralAP
+= apply
? amount
:-amount
;
242 UpdateAttackPowerAndDamage();
245 void Player::UpdateAttackPowerAndDamage(bool ranged
)
248 float level
= float(getLevel());
250 UnitMods unitMod
= ranged
? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
252 uint16 index
= UNIT_FIELD_ATTACK_POWER
;
253 uint16 index_mod
= UNIT_FIELD_ATTACK_POWER_MODS
;
254 uint16 index_mult
= UNIT_FIELD_ATTACK_POWER_MULTIPLIER
;
258 index
= UNIT_FIELD_RANGED_ATTACK_POWER
;
259 index_mod
= UNIT_FIELD_RANGED_ATTACK_POWER_MODS
;
260 index_mult
= UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER
;
264 case CLASS_HUNTER
: val2
= level
* 2.0f
+ GetStat(STAT_AGILITY
) - 10.0f
; break;
265 case CLASS_ROGUE
: val2
= level
+ GetStat(STAT_AGILITY
) - 10.0f
; break;
266 case CLASS_WARRIOR
:val2
= level
+ GetStat(STAT_AGILITY
) - 10.0f
; break;
275 val2
= GetStat(STAT_AGILITY
) - 10.0f
; break;
278 default: val2
= GetStat(STAT_AGILITY
) - 10.0f
; break;
285 case CLASS_WARRIOR
: val2
= level
*3.0f
+ GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
286 case CLASS_PALADIN
: val2
= level
*3.0f
+ GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
287 case CLASS_DEATH_KNIGHT
: val2
= level
*3.0f
+ GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
288 case CLASS_ROGUE
: val2
= level
*2.0f
+ GetStat(STAT_STRENGTH
) + GetStat(STAT_AGILITY
) - 20.0f
; break;
289 case CLASS_HUNTER
: val2
= level
*2.0f
+ GetStat(STAT_STRENGTH
) + GetStat(STAT_AGILITY
) - 20.0f
; break;
290 case CLASS_SHAMAN
: val2
= level
*2.0f
+ GetStat(STAT_STRENGTH
) + GetStat(STAT_AGILITY
) - 20.0f
; break;
293 //Check if Predatory Strikes is skilled
294 float mLevelMult
= 0.0;
302 Unit::AuraList
const& mDummy
= GetAurasByType(SPELL_AURA_DUMMY
);
303 for(Unit::AuraList::const_iterator itr
= mDummy
.begin(); itr
!= mDummy
.end(); ++itr
)
306 if ((*itr
)->GetSpellProto()->SpellIconID
== 1563)
308 mLevelMult
= (*itr
)->GetModifier()->m_amount
/ 100.0f
;
319 val2
= getLevel()*(mLevelMult
+2.0f
) + GetStat(STAT_STRENGTH
)*2.0f
+ GetStat(STAT_AGILITY
) - 20.0f
+ m_baseFeralAP
; break;
322 val2
= getLevel()*(mLevelMult
+3.0f
) + GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
+ m_baseFeralAP
; break;
324 val2
= getLevel()*(mLevelMult
+1.5f
) + GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
+ m_baseFeralAP
; break;
326 val2
= GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
330 case CLASS_MAGE
: val2
= GetStat(STAT_STRENGTH
) - 10.0f
; break;
331 case CLASS_PRIEST
: val2
= GetStat(STAT_STRENGTH
) - 10.0f
; break;
332 case CLASS_WARLOCK
: val2
= GetStat(STAT_STRENGTH
) - 10.0f
; break;
336 SetModifierValue(unitMod
, BASE_VALUE
, val2
);
338 float base_attPower
= GetModifierValue(unitMod
, BASE_VALUE
) * GetModifierValue(unitMod
, BASE_PCT
);
339 float attPowerMod
= GetModifierValue(unitMod
, TOTAL_VALUE
);
341 //add dynamic flat mods
344 if ((getClassMask() & CLASSMASK_WAND_USERS
)==0)
346 AuraList
const& mRAPbyStat
= GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT
);
347 for(AuraList::const_iterator i
= mRAPbyStat
.begin();i
!= mRAPbyStat
.end(); ++i
)
348 attPowerMod
+= int32(GetStat(Stats((*i
)->GetModifier()->m_miscvalue
)) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
353 AuraList
const& mAPbyStat
= GetAurasByType(SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT
);
354 for(AuraList::const_iterator i
= mAPbyStat
.begin();i
!= mAPbyStat
.end(); ++i
)
355 attPowerMod
+= int32(GetStat(Stats((*i
)->GetModifier()->m_miscvalue
)) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
358 float attPowerMultiplier
= GetModifierValue(unitMod
, TOTAL_PCT
) - 1.0f
;
360 SetUInt32Value(index
, (uint32
)base_attPower
); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
361 SetUInt32Value(index_mod
, (uint32
)attPowerMod
); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
362 SetFloatValue(index_mult
, attPowerMultiplier
); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
364 //automatically update weapon damage after attack power modification
367 UpdateDamagePhysical(RANGED_ATTACK
);
369 Pet
*pet
= GetPet(); //update pet's AP
371 pet
->UpdateAttackPowerAndDamage();
375 UpdateDamagePhysical(BASE_ATTACK
);
376 if(CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon
377 UpdateDamagePhysical(OFF_ATTACK
);
381 void Player::UpdateShieldBlockValue()
383 SetUInt32Value(PLAYER_SHIELD_BLOCK
, GetShieldBlockValue());
386 void Player::CalculateMinMaxDamage(WeaponAttackType attType
, bool normalized
, float& min_damage
, float& max_damage
)
395 unitMod
= UNIT_MOD_DAMAGE_MAINHAND
;
396 attPower
= UNIT_MOD_ATTACK_POWER
;
399 unitMod
= UNIT_MOD_DAMAGE_OFFHAND
;
400 attPower
= UNIT_MOD_ATTACK_POWER
;
403 unitMod
= UNIT_MOD_DAMAGE_RANGED
;
404 attPower
= UNIT_MOD_ATTACK_POWER_RANGED
;
408 float att_speed
= GetAPMultiplier(attType
,normalized
);
410 float base_value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetTotalAttackPowerValue(attType
)/ 14.0f
* att_speed
;
411 float base_pct
= GetModifierValue(unitMod
, BASE_PCT
);
412 float total_value
= GetModifierValue(unitMod
, TOTAL_VALUE
);
413 float total_pct
= GetModifierValue(unitMod
, TOTAL_PCT
);
415 float weapon_mindamage
= GetWeaponDamageRange(attType
, MINDAMAGE
);
416 float weapon_maxdamage
= GetWeaponDamageRange(attType
, MAXDAMAGE
);
418 if (IsInFeralForm()) //check if player is druid and in cat or bear forms
420 uint32 lvl
= getLevel();
421 if ( lvl
> 60 ) lvl
= 60;
423 weapon_mindamage
= lvl
*0.85*att_speed
;
424 weapon_maxdamage
= lvl
*1.25*att_speed
;
426 else if(!IsUseEquipedWeapon(attType
==BASE_ATTACK
)) //check if player not in form but still can't use weapon (broken/etc)
428 weapon_mindamage
= BASE_MINDAMAGE
;
429 weapon_maxdamage
= BASE_MAXDAMAGE
;
431 else if(attType
== RANGED_ATTACK
) //add ammo DPS to ranged damage
433 weapon_mindamage
+= GetAmmoDPS() * att_speed
;
434 weapon_maxdamage
+= GetAmmoDPS() * att_speed
;
437 min_damage
= ((base_value
+ weapon_mindamage
) * base_pct
+ total_value
) * total_pct
;
438 max_damage
= ((base_value
+ weapon_maxdamage
) * base_pct
+ total_value
) * total_pct
;
441 void Player::UpdateDamagePhysical(WeaponAttackType attType
)
446 CalculateMinMaxDamage(attType
,false,mindamage
,maxdamage
);
452 SetStatFloatValue(UNIT_FIELD_MINDAMAGE
,mindamage
);
453 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE
,maxdamage
);
456 SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE
,mindamage
);
457 SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE
,maxdamage
);
460 SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE
,mindamage
);
461 SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE
,maxdamage
);
466 void Player::UpdateDefenseBonusesMod()
468 UpdateBlockPercentage();
469 UpdateParryPercentage();
470 UpdateDodgePercentage();
473 void Player::UpdateBlockPercentage()
481 // Modify value from defense skill
482 value
+= (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
483 // Increase from SPELL_AURA_MOD_BLOCK_PERCENT aura
484 value
+= GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT
);
485 // Increase from rating
486 value
+= GetRatingBonusValue(CR_BLOCK
);
487 value
= value
< 0.0f
? 0.0f
: value
;
489 SetStatFloatValue(PLAYER_BLOCK_PERCENTAGE
, value
);
492 void Player::UpdateCritPercentage(WeaponAttackType attType
)
494 BaseModGroup modGroup
;
501 modGroup
= OFFHAND_CRIT_PERCENTAGE
;
502 index
= PLAYER_OFFHAND_CRIT_PERCENTAGE
;
506 modGroup
= RANGED_CRIT_PERCENTAGE
;
507 index
= PLAYER_RANGED_CRIT_PERCENTAGE
;
512 modGroup
= CRIT_PERCENTAGE
;
513 index
= PLAYER_CRIT_PERCENTAGE
;
518 float value
= GetTotalPercentageModValue(modGroup
) + GetRatingBonusValue(cr
);
519 // Modify crit from weapon skill and maximized defense skill of same level victim difference
520 value
+= (int32(GetWeaponSkillValue(attType
)) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
521 value
= value
< 0.0f
? 0.0f
: value
;
522 SetStatFloatValue(index
, value
);
525 void Player::UpdateAllCritPercentages()
527 float value
= GetMeleeCritFromAgility();
529 SetBaseModValue(CRIT_PERCENTAGE
, PCT_MOD
, value
);
530 SetBaseModValue(OFFHAND_CRIT_PERCENTAGE
, PCT_MOD
, value
);
531 SetBaseModValue(RANGED_CRIT_PERCENTAGE
, PCT_MOD
, value
);
533 UpdateCritPercentage(BASE_ATTACK
);
534 UpdateCritPercentage(OFF_ATTACK
);
535 UpdateCritPercentage(RANGED_ATTACK
);
538 void Player::UpdateParryPercentage()
546 // Modify value from defense skill
547 value
+= (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
548 // Parry from SPELL_AURA_MOD_PARRY_PERCENT aura
549 value
+= GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT
);
551 value
+= GetRatingBonusValue(CR_PARRY
);
552 value
= value
< 0.0f
? 0.0f
: value
;
554 SetStatFloatValue(PLAYER_PARRY_PERCENTAGE
, value
);
557 void Player::UpdateDodgePercentage()
559 // Dodge from agility
560 float value
= GetDodgeFromAgility();
561 // Modify value from defense skill
562 value
+= (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
563 // Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura
564 value
+= GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT
);
566 value
+= GetRatingBonusValue(CR_DODGE
);
567 value
= value
< 0.0f
? 0.0f
: value
;
568 SetStatFloatValue(PLAYER_DODGE_PERCENTAGE
, value
);
571 void Player::UpdateSpellCritChance(uint32 school
)
573 // For normal school set zero crit chance
574 if(school
== SPELL_SCHOOL_NORMAL
)
576 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1
, 0.0f
);
579 // For others recalculate it from:
581 // Crit from Intellect
582 crit
+= GetSpellCritFromIntellect();
583 // Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE
584 crit
+= GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE
);
585 // Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
586 crit
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, 1<<school
);
587 // Increase crit from spell crit ratings
588 crit
+= GetRatingBonusValue(CR_CRIT_SPELL
);
591 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1
+ school
, crit
);
594 void Player::UpdateMeleeHitChances()
596 m_modMeleeHitChance
= GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE
);
597 m_modMeleeHitChance
+= GetRatingBonusValue(CR_HIT_MELEE
);
600 void Player::UpdateRangedHitChances()
602 m_modRangedHitChance
= GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE
);
603 m_modRangedHitChance
+= GetRatingBonusValue(CR_HIT_RANGED
);
606 void Player::UpdateSpellHitChances()
608 m_modSpellHitChance
= GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HIT_CHANCE
);
609 m_modSpellHitChance
+= GetRatingBonusValue(CR_HIT_SPELL
);
612 void Player::UpdateAllSpellCritChances()
614 for (int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; i
++)
615 UpdateSpellCritChance(i
);
618 void Player::UpdateExpertise(WeaponAttackType attack
)
620 if(attack
==RANGED_ATTACK
)
623 int32 expertise
= int32(GetRatingBonusValue(CR_EXPERTISE
));
625 Item
*weapon
= GetWeaponForAttack(attack
);
627 AuraList
const& expAuras
= GetAurasByType(SPELL_AURA_MOD_EXPERTISE
);
628 for(AuraList::const_iterator itr
= expAuras
.begin(); itr
!= expAuras
.end(); ++itr
)
630 // item neutral spell
631 if((*itr
)->GetSpellProto()->EquippedItemClass
== -1)
632 expertise
+= (*itr
)->GetModifier()->m_amount
;
633 // item dependent spell
634 else if(weapon
&& weapon
->IsFitToSpellRequirements((*itr
)->GetSpellProto()))
635 expertise
+= (*itr
)->GetModifier()->m_amount
;
643 case BASE_ATTACK
: SetUInt32Value(PLAYER_EXPERTISE
, expertise
); break;
644 case OFF_ATTACK
: SetUInt32Value(PLAYER_OFFHAND_EXPERTISE
, expertise
); break;
649 void Player::ApplyManaRegenBonus(int32 amount
, bool apply
)
651 m_baseManaRegen
+= apply
? amount
: -amount
;
655 void Player::UpdateManaRegen()
657 float Intellect
= GetStat(STAT_INTELLECT
);
658 // Mana regen from spirit and intellect
659 float power_regen
= sqrt(Intellect
) * OCTRegenMPPerSpirit();
660 // Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen
661 power_regen
*= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT
, POWER_MANA
);
663 // Mana regen from SPELL_AURA_MOD_POWER_REGEN aura
664 float power_regen_mp5
= (GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN
, POWER_MANA
) + m_baseManaRegen
) / 5.0f
;
666 // Get bonus from SPELL_AURA_MOD_MANA_REGEN_FROM_STAT aura
667 AuraList
const& regenAura
= GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_FROM_STAT
);
668 for(AuraList::const_iterator i
= regenAura
.begin();i
!= regenAura
.end(); ++i
)
670 Modifier
* mod
= (*i
)->GetModifier();
671 power_regen_mp5
+= GetStat(Stats(mod
->m_miscvalue
)) * mod
->m_amount
/ 500.0f
;
674 // Bonus from some dummy auras
675 AuraList
const& mDummyAuras
= GetAurasByType(SPELL_AURA_PERIODIC_DUMMY
);
676 for(AuraList::const_iterator i
= mDummyAuras
.begin();i
!= mDummyAuras
.end(); ++i
)
677 if((*i
)->GetId() == 34074) // Aspect of the Viper
679 power_regen_mp5
+= (*i
)->GetModifier()->m_amount
* Intellect
/ 500.0f
;
680 // Add regen bonus from level in this dummy
681 power_regen_mp5
+= getLevel() * 35 / 100;
684 // Set regen rate in cast state apply only on spirit based regen
685 int32 modManaRegenInterrupt
= GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
);
686 if (modManaRegenInterrupt
> 100)
687 modManaRegenInterrupt
= 100;
688 SetStatFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER
, power_regen_mp5
+ power_regen
* modManaRegenInterrupt
/ 100.0f
);
690 SetStatFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER
, power_regen_mp5
+ power_regen
);
693 void Player::_ApplyAllStatBonuses()
695 SetCanModifyStats(false);
700 SetCanModifyStats(true);
705 void Player::_RemoveAllStatBonuses()
707 SetCanModifyStats(false);
709 _RemoveAllItemMods();
710 _RemoveAllAuraMods();
712 SetCanModifyStats(true);
717 /*#######################################
719 ######## MOBS STAT SYSTEM ########
721 #######################################*/
723 bool Creature::UpdateStats(Stats
/*stat*/)
728 bool Creature::UpdateAllStats()
731 UpdateAttackPowerAndDamage();
733 for(int i
= POWER_MANA
; i
< MAX_POWERS
; ++i
)
734 UpdateMaxPower(Powers(i
));
736 for(int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; ++i
)
737 UpdateResistances(i
);
742 void Creature::UpdateResistances(uint32 school
)
744 if(school
> SPELL_SCHOOL_NORMAL
)
746 float value
= GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START
+ school
));
747 SetResistance(SpellSchools(school
), int32(value
));
753 void Creature::UpdateArmor()
755 float value
= GetTotalAuraModValue(UNIT_MOD_ARMOR
);
756 SetArmor(int32(value
));
759 void Creature::UpdateMaxHealth()
761 float value
= GetTotalAuraModValue(UNIT_MOD_HEALTH
);
762 SetMaxHealth((uint32
)value
);
765 void Creature::UpdateMaxPower(Powers power
)
767 UnitMods unitMod
= UnitMods(UNIT_MOD_POWER_START
+ power
);
769 float value
= GetTotalAuraModValue(unitMod
);
770 SetMaxPower(power
, uint32(value
));
773 void Creature::UpdateAttackPowerAndDamage(bool ranged
)
778 //automatically update weapon damage after attack power modification
779 UpdateDamagePhysical(BASE_ATTACK
);
782 void Creature::UpdateDamagePhysical(WeaponAttackType attType
)
784 if(attType
> BASE_ATTACK
)
787 UnitMods unitMod
= UNIT_MOD_DAMAGE_MAINHAND
;
789 float att_speed
= float(GetAttackTime(BASE_ATTACK
))/1000.0f
;
791 float base_value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetTotalAttackPowerValue(attType
)/ 14.0f
* att_speed
;
792 float base_pct
= GetModifierValue(unitMod
, BASE_PCT
);
793 float total_value
= GetModifierValue(unitMod
, TOTAL_VALUE
);
794 float total_pct
= GetModifierValue(unitMod
, TOTAL_PCT
);
796 float weapon_mindamage
= GetWeaponDamageRange(BASE_ATTACK
, MINDAMAGE
);
797 float weapon_maxdamage
= GetWeaponDamageRange(BASE_ATTACK
, MAXDAMAGE
);
799 float mindamage
= ((base_value
+ weapon_mindamage
) * base_pct
+ total_value
) * total_pct
;
800 float maxdamage
= ((base_value
+ weapon_maxdamage
) * base_pct
+ total_value
) * total_pct
;
802 SetStatFloatValue(UNIT_FIELD_MINDAMAGE
, mindamage
);
803 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE
, maxdamage
);
806 /*#######################################
808 ######## PETS STAT SYSTEM ########
810 #######################################*/
812 bool Pet::UpdateStats(Stats stat
)
814 if(stat
> STAT_SPIRIT
)
817 // value = ((base_value * base_pct) + total_value) * total_pct
818 float value
= GetTotalStatValue(stat
);
820 Unit
*owner
= GetOwner();
821 if ( stat
== STAT_STAMINA
)
824 value
+= float(owner
->GetStat(stat
)) * 0.3f
;
826 //warlock's and mage's pets gain 30% of owner's intellect
827 else if ( stat
== STAT_INTELLECT
&& getPetType() == SUMMON_PET
)
829 if(owner
&& (owner
->getClass() == CLASS_WARLOCK
|| owner
->getClass() == CLASS_MAGE
) )
830 value
+= float(owner
->GetStat(stat
)) * 0.3f
;
833 SetStat(stat
, int32(value
));
837 case STAT_STRENGTH
: UpdateAttackPowerAndDamage(); break;
838 case STAT_AGILITY
: UpdateArmor(); break;
839 case STAT_STAMINA
: UpdateMaxHealth(); break;
840 case STAT_INTELLECT
: UpdateMaxPower(POWER_MANA
); break;
849 bool Pet::UpdateAllStats()
851 for (int i
= STAT_STRENGTH
; i
< MAX_STATS
; i
++)
852 UpdateStats(Stats(i
));
854 for(int i
= POWER_MANA
; i
< MAX_POWERS
; i
++)
855 UpdateMaxPower(Powers(i
));
857 for (int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; i
++)
858 UpdateResistances(i
);
863 void Pet::UpdateResistances(uint32 school
)
865 if(school
> SPELL_SCHOOL_NORMAL
)
867 float value
= GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START
+ school
));
869 Unit
*owner
= GetOwner();
870 // hunter and warlock pets gain 40% of owner's resistance
871 if(owner
&& (getPetType() == HUNTER_PET
|| getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_WARLOCK
))
872 value
+= float(owner
->GetResistance(SpellSchools(school
))) * 0.4f
;
874 SetResistance(SpellSchools(school
), int32(value
));
880 void Pet::UpdateArmor()
883 float bonus_armor
= 0.0f
;
884 UnitMods unitMod
= UNIT_MOD_ARMOR
;
886 Unit
*owner
= GetOwner();
887 // hunter and warlock pets gain 35% of owner's armor value
888 if(owner
&& (getPetType() == HUNTER_PET
|| getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_WARLOCK
))
889 bonus_armor
= 0.35f
* float(owner
->GetArmor());
891 value
= GetModifierValue(unitMod
, BASE_VALUE
);
892 value
*= GetModifierValue(unitMod
, BASE_PCT
);
893 value
+= GetStat(STAT_AGILITY
) * 2.0f
;
894 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + bonus_armor
;
895 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
897 SetArmor(int32(value
));
900 void Pet::UpdateMaxHealth()
902 UnitMods unitMod
= UNIT_MOD_HEALTH
;
903 float stamina
= GetStat(STAT_STAMINA
) - GetCreateStat(STAT_STAMINA
);
905 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreateHealth();
906 value
*= GetModifierValue(unitMod
, BASE_PCT
);
907 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + stamina
* 10.0f
;
908 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
910 SetMaxHealth((uint32
)value
);
913 void Pet::UpdateMaxPower(Powers power
)
915 UnitMods unitMod
= UnitMods(UNIT_MOD_POWER_START
+ power
);
917 float addValue
= (power
== POWER_MANA
) ? GetStat(STAT_INTELLECT
) - GetCreateStat(STAT_INTELLECT
) : 0.0f
;
919 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreatePowers(power
);
920 value
*= GetModifierValue(unitMod
, BASE_PCT
);
921 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + addValue
* 15.0f
;
922 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
924 SetMaxPower(power
, uint32(value
));
927 void Pet::UpdateAttackPowerAndDamage(bool ranged
)
933 float bonusAP
= 0.0f
;
934 UnitMods unitMod
= UNIT_MOD_ATTACK_POWER
;
936 if(GetEntry() == 416) // imp's attack power
937 val
= GetStat(STAT_STRENGTH
) - 10.0f
;
939 val
= 2 * GetStat(STAT_STRENGTH
) - 20.0f
;
941 Unit
* owner
= GetOwner();
942 if( owner
&& owner
->GetTypeId()==TYPEID_PLAYER
)
944 if(getPetType() == HUNTER_PET
) //hunter pets benefit from owner's attack power
946 bonusAP
= owner
->GetTotalAttackPowerValue(RANGED_ATTACK
) * 0.22f
;
947 SetBonusDamage( int32(owner
->GetTotalAttackPowerValue(RANGED_ATTACK
) * 0.1287f
));
949 //demons benefit from warlocks shadow or fire damage
950 else if(getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_WARLOCK
)
952 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
);
953 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
);
954 int32 maximum
= (fire
> shadow
) ? fire
: shadow
;
957 SetBonusDamage( int32(maximum
* 0.15f
));
958 bonusAP
= maximum
* 0.57f
;
960 //water elementals benefit from mage's frost damage
961 else if(getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_MAGE
)
963 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
);
966 SetBonusDamage( int32(frost
* 0.4f
));
970 SetModifierValue(UNIT_MOD_ATTACK_POWER
, BASE_VALUE
, val
+ bonusAP
);
972 //in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB
973 float base_attPower
= GetModifierValue(unitMod
, BASE_VALUE
) * GetModifierValue(unitMod
, BASE_PCT
);
974 float attPowerMod
= GetModifierValue(unitMod
, TOTAL_VALUE
);
975 float attPowerMultiplier
= GetModifierValue(unitMod
, TOTAL_PCT
) - 1.0f
;
977 //UNIT_FIELD_(RANGED)_ATTACK_POWER field
978 SetUInt32Value(UNIT_FIELD_ATTACK_POWER
, (uint32
)base_attPower
);
979 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
980 SetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS
, (uint32
)attPowerMod
);
981 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
982 SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER
, attPowerMultiplier
);
984 //automatically update weapon damage after attack power modification
985 UpdateDamagePhysical(BASE_ATTACK
);
988 void Pet::UpdateDamagePhysical(WeaponAttackType attType
)
990 if(attType
> BASE_ATTACK
)
993 UnitMods unitMod
= UNIT_MOD_DAMAGE_MAINHAND
;
995 float att_speed
= float(GetAttackTime(BASE_ATTACK
))/1000.0f
;
997 float base_value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetTotalAttackPowerValue(attType
)/ 14.0f
* att_speed
;
998 float base_pct
= GetModifierValue(unitMod
, BASE_PCT
);
999 float total_value
= GetModifierValue(unitMod
, TOTAL_VALUE
);
1000 float total_pct
= GetModifierValue(unitMod
, TOTAL_PCT
);
1002 float weapon_mindamage
= GetWeaponDamageRange(BASE_ATTACK
, MINDAMAGE
);
1003 float weapon_maxdamage
= GetWeaponDamageRange(BASE_ATTACK
, MAXDAMAGE
);
1005 float mindamage
= ((base_value
+ weapon_mindamage
) * base_pct
+ total_value
) * total_pct
;
1006 float maxdamage
= ((base_value
+ weapon_maxdamage
) * base_pct
+ total_value
) * total_pct
;
1008 // Pet's base damage changes depending on happiness
1009 if (getPetType() == HUNTER_PET
&& attType
== BASE_ATTACK
)
1011 switch(GetHappinessState())
1014 // 125% of normal damage
1015 mindamage
= mindamage
* 1.25;
1016 maxdamage
= maxdamage
* 1.25;
1019 // 100% of normal damage, nothing to modify
1022 // 75% of normal damage
1023 mindamage
= mindamage
* 0.75;
1024 maxdamage
= maxdamage
* 0.75;
1029 SetStatFloatValue(UNIT_FIELD_MINDAMAGE
, mindamage
);
1030 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE
, maxdamage
);