2 * Copyright (C) 2005-2008 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::UpdateSpellDamageAndHealingBonus()
96 // Magic damage modifiers implemented in Unit::SpellDamageBonus
97 // This information for client side use only
98 // Get healing bonus for all schools
99 SetStatInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS
, SpellBaseHealingBonus(SPELL_SCHOOL_MASK_ALL
));
100 // Get damage bonus for all schools
101 for(int i
= SPELL_SCHOOL_HOLY
; i
< MAX_SPELL_SCHOOL
; i
++)
102 SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS
+i
, SpellBaseDamageBonus(SpellSchoolMask(1 << i
)));
105 bool Player::UpdateAllStats()
107 for (int i
= STAT_STRENGTH
; i
< MAX_STATS
; i
++)
109 float value
= GetTotalStatValue(Stats(i
));
110 SetStat(Stats(i
), (int32
)value
);
113 UpdateAttackPowerAndDamage();
114 UpdateAttackPowerAndDamage(true);
118 for(int i
= POWER_MANA
; i
< MAX_POWERS
; i
++)
119 UpdateMaxPower(Powers(i
));
121 UpdateAllCritPercentages();
122 UpdateAllSpellCritChances();
123 UpdateDefenseBonusesMod();
124 UpdateShieldBlockValue();
125 UpdateSpellDamageAndHealingBonus();
127 UpdateExpertise(BASE_ATTACK
);
128 UpdateExpertise(OFF_ATTACK
);
129 for (int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; i
++)
130 UpdateResistances(i
);
135 void Player::UpdateResistances(uint32 school
)
137 if(school
> SPELL_SCHOOL_NORMAL
)
139 float value
= GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START
+ school
));
140 SetResistance(SpellSchools(school
), int32(value
));
144 pet
->UpdateResistances(school
);
150 void Player::UpdateArmor()
153 UnitMods unitMod
= UNIT_MOD_ARMOR
;
155 value
= GetModifierValue(unitMod
, BASE_VALUE
); // base armor (from items)
156 value
*= GetModifierValue(unitMod
, BASE_PCT
); // armor percent from items
157 value
+= GetStat(STAT_AGILITY
) * 2.0f
; // armor bonus from stats
158 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
);
160 //add dynamic flat mods
161 AuraList
const& mResbyIntellect
= GetAurasByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT
);
162 for(AuraList::const_iterator i
= mResbyIntellect
.begin();i
!= mResbyIntellect
.end(); ++i
)
164 Modifier
* mod
= (*i
)->GetModifier();
165 if(mod
->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
166 value
+= int32(GetStat(Stats((*i
)->GetMiscBValue())) * mod
->m_amount
/ 100.0f
);
169 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
171 SetArmor(int32(value
));
178 float Player::GetHealthBonusFromStamina()
180 float stamina
= GetStat(STAT_STAMINA
);
182 float baseStam
= stamina
< 20 ? stamina
: 20;
183 float moreStam
= stamina
- baseStam
;
185 return baseStam
+ (moreStam
*10.0f
);
188 float Player::GetManaBonusFromIntellect()
190 float intellect
= GetStat(STAT_INTELLECT
);
192 float baseInt
= intellect
< 20 ? intellect
: 20;
193 float moreInt
= intellect
- baseInt
;
195 return baseInt
+ (moreInt
*15.0f
);
198 void Player::UpdateMaxHealth()
200 UnitMods unitMod
= UNIT_MOD_HEALTH
;
202 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreateHealth();
203 value
*= GetModifierValue(unitMod
, BASE_PCT
);
204 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + GetHealthBonusFromStamina();
205 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
207 SetMaxHealth((uint32
)value
);
210 void Player::UpdateMaxPower(Powers power
)
212 UnitMods unitMod
= UnitMods(UNIT_MOD_POWER_START
+ power
);
214 float bonusPower
= (power
== POWER_MANA
) ? GetManaBonusFromIntellect() : 0;
216 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreatePowers(power
);
217 value
*= GetModifierValue(unitMod
, BASE_PCT
);
218 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + bonusPower
;
219 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
221 SetMaxPower(power
, uint32(value
));
224 void Player::UpdateAttackPowerAndDamage(bool ranged
)
227 float level
= float(getLevel());
229 UnitMods unitMod
= ranged
? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
231 uint16 index
= UNIT_FIELD_ATTACK_POWER
;
232 uint16 index_mod
= UNIT_FIELD_ATTACK_POWER_MODS
;
233 uint16 index_mult
= UNIT_FIELD_ATTACK_POWER_MULTIPLIER
;
237 index
= UNIT_FIELD_RANGED_ATTACK_POWER
;
238 index_mod
= UNIT_FIELD_RANGED_ATTACK_POWER_MODS
;
239 index_mult
= UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER
;
243 case CLASS_HUNTER
: val2
= level
* 2.0f
+ GetStat(STAT_AGILITY
) - 10.0f
; break;
244 case CLASS_ROGUE
: val2
= level
+ GetStat(STAT_AGILITY
) - 10.0f
; break;
245 case CLASS_WARRIOR
:val2
= level
+ GetStat(STAT_AGILITY
) - 10.0f
; break;
254 val2
= GetStat(STAT_AGILITY
) - 10.0f
; break;
257 default: val2
= GetStat(STAT_AGILITY
) - 10.0f
; break;
264 case CLASS_WARRIOR
: val2
= level
*3.0f
+ GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
265 case CLASS_PALADIN
: val2
= level
*3.0f
+ GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
266 case CLASS_DEATH_KNIGHT
: val2
= level
*3.0f
+ GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
267 case CLASS_ROGUE
: val2
= level
*2.0f
+ GetStat(STAT_STRENGTH
) + GetStat(STAT_AGILITY
) - 20.0f
; break;
268 case CLASS_HUNTER
: val2
= level
*2.0f
+ GetStat(STAT_STRENGTH
) + GetStat(STAT_AGILITY
) - 20.0f
; break;
269 case CLASS_SHAMAN
: val2
= level
*2.0f
+ GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
272 //Check if Predatory Strikes is skilled
273 float mLevelMult
= 0.0;
281 Unit::AuraList
const& mDummy
= GetAurasByType(SPELL_AURA_DUMMY
);
282 for(Unit::AuraList::const_iterator itr
= mDummy
.begin(); itr
!= mDummy
.end(); ++itr
)
285 if ((*itr
)->GetSpellProto()->SpellIconID
== 1563)
287 mLevelMult
= (*itr
)->GetModifier()->m_amount
/ 100.0f
;
298 val2
= getLevel()*(mLevelMult
+2.0f
) + GetStat(STAT_STRENGTH
)*2.0f
+ GetStat(STAT_AGILITY
) - 20.0f
; break;
301 val2
= getLevel()*(mLevelMult
+3.0f
) + GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
303 val2
= getLevel()*(mLevelMult
+1.5f
) + GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
305 val2
= GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
309 case CLASS_MAGE
: val2
= GetStat(STAT_STRENGTH
) - 10.0f
; break;
310 case CLASS_PRIEST
: val2
= GetStat(STAT_STRENGTH
) - 10.0f
; break;
311 case CLASS_WARLOCK
: val2
= GetStat(STAT_STRENGTH
) - 10.0f
; break;
315 SetModifierValue(unitMod
, BASE_VALUE
, val2
);
317 float base_attPower
= GetModifierValue(unitMod
, BASE_VALUE
) * GetModifierValue(unitMod
, BASE_PCT
);
318 float attPowerMod
= GetModifierValue(unitMod
, TOTAL_VALUE
);
320 //add dynamic flat mods
321 if ((getClassMask() & CLASSMASK_WAND_USERS
)==0)
325 AuraList
const& mRAPbyIntellect
= GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT
);
326 for(AuraList::const_iterator i
= mRAPbyIntellect
.begin();i
!= mRAPbyIntellect
.end(); ++i
)
327 attPowerMod
+= int32(GetStat(Stats((*i
)->GetModifier()->m_miscvalue
)) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
331 AuraList
const& mRAPbyIntellect
= GetAurasByType(SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT
);
332 for(AuraList::const_iterator i
= mRAPbyIntellect
.begin();i
!= mRAPbyIntellect
.end(); ++i
)
333 attPowerMod
+= int32(GetStat(Stats((*i
)->GetModifier()->m_miscvalue
)) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
337 float attPowerMultiplier
= GetModifierValue(unitMod
, TOTAL_PCT
) - 1.0f
;
339 SetUInt32Value(index
, (uint32
)base_attPower
); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
340 SetUInt32Value(index_mod
, (uint32
)attPowerMod
); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
341 SetFloatValue(index_mult
, attPowerMultiplier
); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
343 //automatically update weapon damage after attack power modification
346 UpdateDamagePhysical(RANGED_ATTACK
);
348 Pet
*pet
= GetPet(); //update pet's AP
350 pet
->UpdateAttackPowerAndDamage();
354 UpdateDamagePhysical(BASE_ATTACK
);
355 if(CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon
356 UpdateDamagePhysical(OFF_ATTACK
);
360 void Player::UpdateShieldBlockValue()
362 SetUInt32Value(PLAYER_SHIELD_BLOCK
, GetShieldBlockValue());
365 void Player::CalculateMinMaxDamage(WeaponAttackType attType
, bool normalized
, float& min_damage
, float& max_damage
)
374 unitMod
= UNIT_MOD_DAMAGE_MAINHAND
;
375 attPower
= UNIT_MOD_ATTACK_POWER
;
378 unitMod
= UNIT_MOD_DAMAGE_OFFHAND
;
379 attPower
= UNIT_MOD_ATTACK_POWER
;
382 unitMod
= UNIT_MOD_DAMAGE_RANGED
;
383 attPower
= UNIT_MOD_ATTACK_POWER_RANGED
;
387 float att_speed
= GetAPMultiplier(attType
,normalized
);
389 float base_value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetTotalAttackPowerValue(attType
)/ 14.0f
* att_speed
;
390 float base_pct
= GetModifierValue(unitMod
, BASE_PCT
);
391 float total_value
= GetModifierValue(unitMod
, TOTAL_VALUE
);
392 float total_pct
= GetModifierValue(unitMod
, TOTAL_PCT
);
394 float weapon_mindamage
= GetWeaponDamageRange(attType
, MINDAMAGE
);
395 float weapon_maxdamage
= GetWeaponDamageRange(attType
, MAXDAMAGE
);
397 if (IsInFeralForm()) //check if player is druid and in cat or bear forms
399 uint32 lvl
= getLevel();
400 if ( lvl
> 60 ) lvl
= 60;
402 weapon_mindamage
= lvl
*0.85*att_speed
;
403 weapon_maxdamage
= lvl
*1.25*att_speed
;
405 else if(!IsUseEquipedWeapon(attType
==BASE_ATTACK
)) //check if player not in form but still can't use weapon (broken/etc)
407 weapon_mindamage
= BASE_MINDAMAGE
;
408 weapon_maxdamage
= BASE_MAXDAMAGE
;
410 else if(attType
== RANGED_ATTACK
) //add ammo DPS to ranged damage
412 weapon_mindamage
+= GetAmmoDPS() * att_speed
;
413 weapon_maxdamage
+= GetAmmoDPS() * att_speed
;
416 min_damage
= ((base_value
+ weapon_mindamage
) * base_pct
+ total_value
) * total_pct
;
417 max_damage
= ((base_value
+ weapon_maxdamage
) * base_pct
+ total_value
) * total_pct
;
420 void Player::UpdateDamagePhysical(WeaponAttackType attType
)
425 CalculateMinMaxDamage(attType
,false,mindamage
,maxdamage
);
431 SetStatFloatValue(UNIT_FIELD_MINDAMAGE
,mindamage
);
432 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE
,maxdamage
);
435 SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE
,mindamage
);
436 SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE
,maxdamage
);
439 SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE
,mindamage
);
440 SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE
,maxdamage
);
445 void Player::UpdateDefenseBonusesMod()
447 UpdateBlockPercentage();
448 UpdateParryPercentage();
449 UpdateDodgePercentage();
452 void Player::UpdateBlockPercentage()
460 // Modify value from defense skill
461 value
+= (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
462 // Increase from SPELL_AURA_MOD_BLOCK_PERCENT aura
463 value
+= GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT
);
464 // Increase from rating
465 value
+= GetRatingBonusValue(CR_BLOCK
);
466 value
= value
< 0.0f
? 0.0f
: value
;
468 SetStatFloatValue(PLAYER_BLOCK_PERCENTAGE
, value
);
471 void Player::UpdateCritPercentage(WeaponAttackType attType
)
473 BaseModGroup modGroup
;
480 modGroup
= OFFHAND_CRIT_PERCENTAGE
;
481 index
= PLAYER_OFFHAND_CRIT_PERCENTAGE
;
485 modGroup
= RANGED_CRIT_PERCENTAGE
;
486 index
= PLAYER_RANGED_CRIT_PERCENTAGE
;
491 modGroup
= CRIT_PERCENTAGE
;
492 index
= PLAYER_CRIT_PERCENTAGE
;
497 float value
= GetTotalPercentageModValue(modGroup
) + GetRatingBonusValue(cr
);
498 // Modify crit from weapon skill and maximized defense skill of same level victim difference
499 value
+= (int32(GetWeaponSkillValue(attType
)) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
500 value
= value
< 0.0f
? 0.0f
: value
;
501 SetStatFloatValue(index
, value
);
504 void Player::UpdateAllCritPercentages()
506 float value
= GetMeleeCritFromAgility();
508 SetBaseModValue(CRIT_PERCENTAGE
, PCT_MOD
, value
);
509 SetBaseModValue(OFFHAND_CRIT_PERCENTAGE
, PCT_MOD
, value
);
510 SetBaseModValue(RANGED_CRIT_PERCENTAGE
, PCT_MOD
, value
);
512 UpdateCritPercentage(BASE_ATTACK
);
513 UpdateCritPercentage(OFF_ATTACK
);
514 UpdateCritPercentage(RANGED_ATTACK
);
517 void Player::UpdateParryPercentage()
525 // Modify value from defense skill
526 value
+= (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
527 // Parry from SPELL_AURA_MOD_PARRY_PERCENT aura
528 value
+= GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT
);
530 value
+= GetRatingBonusValue(CR_PARRY
);
531 value
= value
< 0.0f
? 0.0f
: value
;
533 SetStatFloatValue(PLAYER_PARRY_PERCENTAGE
, value
);
536 void Player::UpdateDodgePercentage()
538 // Dodge from agility
539 float value
= GetDodgeFromAgility();
540 // Modify value from defense skill
541 value
+= (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
542 // Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura
543 value
+= GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT
);
545 value
+= GetRatingBonusValue(CR_DODGE
);
546 value
= value
< 0.0f
? 0.0f
: value
;
547 SetStatFloatValue(PLAYER_DODGE_PERCENTAGE
, value
);
550 void Player::UpdateSpellCritChance(uint32 school
)
552 // For normal school set zero crit chance
553 if(school
== SPELL_SCHOOL_NORMAL
)
555 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1
, 0.0f
);
558 // For others recalculate it from:
560 // Crit from Intellect
561 crit
+= GetSpellCritFromIntellect();
562 // Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE
563 crit
+= GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE
);
564 // Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
565 crit
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, 1<<school
);
566 // Increase crit from spell crit ratings
567 crit
+= GetRatingBonusValue(CR_CRIT_SPELL
);
570 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1
+ school
, crit
);
573 void Player::UpdateMeleeHitChances()
575 m_modMeleeHitChance
= GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE
);
576 m_modMeleeHitChance
+= GetRatingBonusValue(CR_HIT_MELEE
);
579 void Player::UpdateRangedHitChances()
581 m_modRangedHitChance
= GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE
);
582 m_modRangedHitChance
+= GetRatingBonusValue(CR_HIT_RANGED
);
585 void Player::UpdateSpellHitChances()
587 m_modSpellHitChance
= GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HIT_CHANCE
);
588 m_modSpellHitChance
+= GetRatingBonusValue(CR_HIT_SPELL
);
591 void Player::UpdateAllSpellCritChances()
593 for (int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; i
++)
594 UpdateSpellCritChance(i
);
597 void Player::UpdateExpertise(WeaponAttackType attack
)
599 if(attack
==RANGED_ATTACK
)
602 int32 expertise
= int32(GetRatingBonusValue(CR_EXPERTISE
));
604 Item
*weapon
= GetWeaponForAttack(attack
);
606 AuraList
const& expAuras
= GetAurasByType(SPELL_AURA_MOD_EXPERTISE
);
607 for(AuraList::const_iterator itr
= expAuras
.begin(); itr
!= expAuras
.end(); ++itr
)
609 // item neutral spell
610 if((*itr
)->GetSpellProto()->EquippedItemClass
== -1)
611 expertise
+= (*itr
)->GetModifier()->m_amount
;
612 // item dependent spell
613 else if(weapon
&& weapon
->IsFitToSpellRequirements((*itr
)->GetSpellProto()))
614 expertise
+= (*itr
)->GetModifier()->m_amount
;
622 case BASE_ATTACK
: SetUInt32Value(PLAYER_EXPERTISE
, expertise
); break;
623 case OFF_ATTACK
: SetUInt32Value(PLAYER_OFFHAND_EXPERTISE
, expertise
); break;
628 void Player::UpdateManaRegen()
630 float Intellect
= GetStat(STAT_INTELLECT
);
631 // Mana regen from spirit and intellect
632 float power_regen
= sqrt(Intellect
) * OCTRegenMPPerSpirit();
633 // Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen
634 power_regen
*= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT
, POWER_MANA
);
636 // Mana regen from SPELL_AURA_MOD_POWER_REGEN aura
637 float power_regen_mp5
= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN
, POWER_MANA
) / 5.0f
;
639 // Get bonus from SPELL_AURA_MOD_MANA_REGEN_FROM_STAT aura
640 AuraList
const& regenAura
= GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_FROM_STAT
);
641 for(AuraList::const_iterator i
= regenAura
.begin();i
!= regenAura
.end(); ++i
)
643 Modifier
* mod
= (*i
)->GetModifier();
644 power_regen_mp5
+= GetStat(Stats(mod
->m_miscvalue
)) * mod
->m_amount
/ 500.0f
;
647 // Bonus from some dummy auras
648 AuraList
const& mDummyAuras
= GetAurasByType(SPELL_AURA_PERIODIC_DUMMY
);
649 for(AuraList::const_iterator i
= mDummyAuras
.begin();i
!= mDummyAuras
.end(); ++i
)
650 if((*i
)->GetId() == 34074) // Aspect of the Viper
652 power_regen_mp5
+= (*i
)->GetModifier()->m_amount
* Intellect
/ 500.0f
;
653 // Add regen bonus from level in this dummy
654 power_regen_mp5
+= getLevel() * 35 / 100;
657 // Set regen rate in cast state apply only on spirit based regen
658 int32 modManaRegenInterrupt
= GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
);
659 if (modManaRegenInterrupt
> 100)
660 modManaRegenInterrupt
= 100;
661 SetStatFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER
, power_regen_mp5
+ power_regen
* modManaRegenInterrupt
/ 100.0f
);
663 SetStatFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER
, power_regen_mp5
+ power_regen
);
666 void Player::_ApplyAllStatBonuses()
668 SetCanModifyStats(false);
673 SetCanModifyStats(true);
678 void Player::_RemoveAllStatBonuses()
680 SetCanModifyStats(false);
682 _RemoveAllItemMods();
683 _RemoveAllAuraMods();
685 SetCanModifyStats(true);
690 /*#######################################
692 ######## MOBS STAT SYSTEM ########
694 #######################################*/
696 bool Creature::UpdateStats(Stats
/*stat*/)
701 bool Creature::UpdateAllStats()
704 UpdateAttackPowerAndDamage();
706 for(int i
= POWER_MANA
; i
< MAX_POWERS
; ++i
)
707 UpdateMaxPower(Powers(i
));
709 for(int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; ++i
)
710 UpdateResistances(i
);
715 void Creature::UpdateResistances(uint32 school
)
717 if(school
> SPELL_SCHOOL_NORMAL
)
719 float value
= GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START
+ school
));
720 SetResistance(SpellSchools(school
), int32(value
));
726 void Creature::UpdateArmor()
728 float value
= GetTotalAuraModValue(UNIT_MOD_ARMOR
);
729 SetArmor(int32(value
));
732 void Creature::UpdateMaxHealth()
734 float value
= GetTotalAuraModValue(UNIT_MOD_HEALTH
);
735 SetMaxHealth((uint32
)value
);
738 void Creature::UpdateMaxPower(Powers power
)
740 UnitMods unitMod
= UnitMods(UNIT_MOD_POWER_START
+ power
);
742 float value
= GetTotalAuraModValue(unitMod
);
743 SetMaxPower(power
, uint32(value
));
746 void Creature::UpdateAttackPowerAndDamage(bool ranged
)
751 //automatically update weapon damage after attack power modification
752 UpdateDamagePhysical(BASE_ATTACK
);
755 void Creature::UpdateDamagePhysical(WeaponAttackType attType
)
757 if(attType
> BASE_ATTACK
)
760 UnitMods unitMod
= UNIT_MOD_DAMAGE_MAINHAND
;
762 float att_speed
= float(GetAttackTime(BASE_ATTACK
))/1000.0f
;
764 float base_value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetTotalAttackPowerValue(attType
)/ 14.0f
* att_speed
;
765 float base_pct
= GetModifierValue(unitMod
, BASE_PCT
);
766 float total_value
= GetModifierValue(unitMod
, TOTAL_VALUE
);
767 float total_pct
= GetModifierValue(unitMod
, TOTAL_PCT
);
769 float weapon_mindamage
= GetWeaponDamageRange(BASE_ATTACK
, MINDAMAGE
);
770 float weapon_maxdamage
= GetWeaponDamageRange(BASE_ATTACK
, MAXDAMAGE
);
772 float mindamage
= ((base_value
+ weapon_mindamage
) * base_pct
+ total_value
) * total_pct
;
773 float maxdamage
= ((base_value
+ weapon_maxdamage
) * base_pct
+ total_value
) * total_pct
;
775 SetStatFloatValue(UNIT_FIELD_MINDAMAGE
, mindamage
);
776 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE
, maxdamage
);
779 /*#######################################
781 ######## PETS STAT SYSTEM ########
783 #######################################*/
785 bool Pet::UpdateStats(Stats stat
)
787 if(stat
> STAT_SPIRIT
)
790 // value = ((base_value * base_pct) + total_value) * total_pct
791 float value
= GetTotalStatValue(stat
);
793 Unit
*owner
= GetOwner();
794 if ( stat
== STAT_STAMINA
)
797 value
+= float(owner
->GetStat(stat
)) * 0.3f
;
799 //warlock's and mage's pets gain 30% of owner's intellect
800 else if ( stat
== STAT_INTELLECT
&& getPetType() == SUMMON_PET
)
802 if(owner
&& (owner
->getClass() == CLASS_WARLOCK
|| owner
->getClass() == CLASS_MAGE
) )
803 value
+= float(owner
->GetStat(stat
)) * 0.3f
;
806 SetStat(stat
, int32(value
));
810 case STAT_STRENGTH
: UpdateAttackPowerAndDamage(); break;
811 case STAT_AGILITY
: UpdateArmor(); break;
812 case STAT_STAMINA
: UpdateMaxHealth(); break;
813 case STAT_INTELLECT
: UpdateMaxPower(POWER_MANA
); break;
822 bool Pet::UpdateAllStats()
824 for (int i
= STAT_STRENGTH
; i
< MAX_STATS
; i
++)
825 UpdateStats(Stats(i
));
827 for(int i
= POWER_MANA
; i
< MAX_POWERS
; i
++)
828 UpdateMaxPower(Powers(i
));
830 for (int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; i
++)
831 UpdateResistances(i
);
836 void Pet::UpdateResistances(uint32 school
)
838 if(school
> SPELL_SCHOOL_NORMAL
)
840 float value
= GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START
+ school
));
842 Unit
*owner
= GetOwner();
843 // hunter and warlock pets gain 40% of owner's resistance
844 if(owner
&& (getPetType() == HUNTER_PET
|| getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_WARLOCK
))
845 value
+= float(owner
->GetResistance(SpellSchools(school
))) * 0.4f
;
847 SetResistance(SpellSchools(school
), int32(value
));
853 void Pet::UpdateArmor()
856 float bonus_armor
= 0.0f
;
857 UnitMods unitMod
= UNIT_MOD_ARMOR
;
859 Unit
*owner
= GetOwner();
860 // hunter and warlock pets gain 35% of owner's armor value
861 if(owner
&& (getPetType() == HUNTER_PET
|| getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_WARLOCK
))
862 bonus_armor
= 0.35f
* float(owner
->GetArmor());
864 value
= GetModifierValue(unitMod
, BASE_VALUE
);
865 value
*= GetModifierValue(unitMod
, BASE_PCT
);
866 value
+= GetStat(STAT_AGILITY
) * 2.0f
;
867 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + bonus_armor
;
868 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
870 SetArmor(int32(value
));
873 void Pet::UpdateMaxHealth()
875 UnitMods unitMod
= UNIT_MOD_HEALTH
;
876 float stamina
= GetStat(STAT_STAMINA
) - GetCreateStat(STAT_STAMINA
);
878 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreateHealth();
879 value
*= GetModifierValue(unitMod
, BASE_PCT
);
880 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + stamina
* 10.0f
;
881 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
883 SetMaxHealth((uint32
)value
);
886 void Pet::UpdateMaxPower(Powers power
)
888 UnitMods unitMod
= UnitMods(UNIT_MOD_POWER_START
+ power
);
890 float addValue
= (power
== POWER_MANA
) ? GetStat(STAT_INTELLECT
) - GetCreateStat(STAT_INTELLECT
) : 0.0f
;
892 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreatePowers(power
);
893 value
*= GetModifierValue(unitMod
, BASE_PCT
);
894 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + addValue
* 15.0f
;
895 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
897 SetMaxPower(power
, uint32(value
));
900 void Pet::UpdateAttackPowerAndDamage(bool ranged
)
906 float bonusAP
= 0.0f
;
907 UnitMods unitMod
= UNIT_MOD_ATTACK_POWER
;
909 if(GetEntry() == 416) // imp's attack power
910 val
= GetStat(STAT_STRENGTH
) - 10.0f
;
912 val
= 2 * GetStat(STAT_STRENGTH
) - 20.0f
;
914 Unit
* owner
= GetOwner();
915 if( owner
&& owner
->GetTypeId()==TYPEID_PLAYER
)
917 if(getPetType() == HUNTER_PET
) //hunter pets benefit from owner's attack power
919 bonusAP
= owner
->GetTotalAttackPowerValue(RANGED_ATTACK
) * 0.22f
;
920 SetBonusDamage( int32(owner
->GetTotalAttackPowerValue(RANGED_ATTACK
) * 0.1287f
));
922 //demons benefit from warlocks shadow or fire damage
923 else if(getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_WARLOCK
)
925 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
);
926 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
);
927 int32 maximum
= (fire
> shadow
) ? fire
: shadow
;
930 SetBonusDamage( int32(maximum
* 0.15f
));
931 bonusAP
= maximum
* 0.57f
;
933 //water elementals benefit from mage's frost damage
934 else if(getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_MAGE
)
936 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
);
939 SetBonusDamage( int32(frost
* 0.4f
));
943 SetModifierValue(UNIT_MOD_ATTACK_POWER
, BASE_VALUE
, val
+ bonusAP
);
945 //in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB
946 float base_attPower
= GetModifierValue(unitMod
, BASE_VALUE
) * GetModifierValue(unitMod
, BASE_PCT
);
947 float attPowerMod
= GetModifierValue(unitMod
, TOTAL_VALUE
);
948 float attPowerMultiplier
= GetModifierValue(unitMod
, TOTAL_PCT
) - 1.0f
;
950 //UNIT_FIELD_(RANGED)_ATTACK_POWER field
951 SetUInt32Value(UNIT_FIELD_ATTACK_POWER
, (uint32
)base_attPower
);
952 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
953 SetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS
, (uint32
)attPowerMod
);
954 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
955 SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER
, attPowerMultiplier
);
957 //automatically update weapon damage after attack power modification
958 UpdateDamagePhysical(BASE_ATTACK
);
961 void Pet::UpdateDamagePhysical(WeaponAttackType attType
)
963 if(attType
> BASE_ATTACK
)
966 UnitMods unitMod
= UNIT_MOD_DAMAGE_MAINHAND
;
968 float att_speed
= float(GetAttackTime(BASE_ATTACK
))/1000.0f
;
970 float base_value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetTotalAttackPowerValue(attType
)/ 14.0f
* att_speed
;
971 float base_pct
= GetModifierValue(unitMod
, BASE_PCT
);
972 float total_value
= GetModifierValue(unitMod
, TOTAL_VALUE
);
973 float total_pct
= GetModifierValue(unitMod
, TOTAL_PCT
);
975 float weapon_mindamage
= GetWeaponDamageRange(BASE_ATTACK
, MINDAMAGE
);
976 float weapon_maxdamage
= GetWeaponDamageRange(BASE_ATTACK
, MAXDAMAGE
);
978 float mindamage
= ((base_value
+ weapon_mindamage
) * base_pct
+ total_value
) * total_pct
;
979 float maxdamage
= ((base_value
+ weapon_maxdamage
) * base_pct
+ total_value
) * total_pct
;
981 // Pet's base damage changes depending on happiness
982 if (getPetType() == HUNTER_PET
&& attType
== BASE_ATTACK
)
984 switch(GetHappinessState())
987 // 125% of normal damage
988 mindamage
= mindamage
* 1.25;
989 maxdamage
= maxdamage
* 1.25;
992 // 100% of normal damage, nothing to modify
995 // 75% of normal damage
996 mindamage
= mindamage
* 0.75;
997 maxdamage
= maxdamage
* 0.75;
1002 SetStatFloatValue(UNIT_FIELD_MINDAMAGE
, mindamage
);
1003 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE
, maxdamage
);