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 UpdateAttackPowerAndDamage();
53 UpdateShieldBlockValue();
57 UpdateAttackPowerAndDamage(true);
58 if(getClass() == CLASS_ROGUE
|| getClass() == CLASS_HUNTER
|| getClass() == CLASS_DRUID
&& m_form
==FORM_CAT
)
59 UpdateAttackPowerAndDamage();
61 UpdateAllCritPercentages();
62 UpdateDodgePercentage();
65 case STAT_STAMINA
: UpdateMaxHealth(); break;
67 UpdateMaxPower(POWER_MANA
);
68 UpdateAllSpellCritChances();
69 UpdateAttackPowerAndDamage(true); //SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT, only intelect currently
70 UpdateArmor(); //SPELL_AURA_MOD_RESISTANCE_OF_INTELLECT_PERCENT, only armor currently
79 UpdateSpellDamageAndHealingBonus();
84 void Player::UpdateSpellDamageAndHealingBonus()
86 // Magic damage modifiers implemented in Unit::SpellDamageBonus
87 // This information for client side use only
88 // Get healing bonus for all schools
89 SetStatInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS
, SpellBaseHealingBonus(SPELL_SCHOOL_MASK_ALL
));
90 // Get damage bonus for all schools
91 for(int i
= SPELL_SCHOOL_HOLY
; i
< MAX_SPELL_SCHOOL
; i
++)
92 SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS
+i
, SpellBaseDamageBonus(SpellSchoolMask(1 << i
)));
95 bool Player::UpdateAllStats()
97 for (int i
= STAT_STRENGTH
; i
< MAX_STATS
; i
++)
99 float value
= GetTotalStatValue(Stats(i
));
100 SetStat(Stats(i
), (int32
)value
);
103 UpdateAttackPowerAndDamage();
104 UpdateAttackPowerAndDamage(true);
108 for(int i
= POWER_MANA
; i
< MAX_POWERS
; i
++)
109 UpdateMaxPower(Powers(i
));
111 UpdateAllCritPercentages();
112 UpdateAllSpellCritChances();
113 UpdateDefenseBonusesMod();
114 UpdateShieldBlockValue();
115 UpdateSpellDamageAndHealingBonus();
117 UpdateExpertise(BASE_ATTACK
);
118 UpdateExpertise(OFF_ATTACK
);
119 for (int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; i
++)
120 UpdateResistances(i
);
125 void Player::UpdateResistances(uint32 school
)
127 if(school
> SPELL_SCHOOL_NORMAL
)
129 float value
= GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START
+ school
));
130 SetResistance(SpellSchools(school
), int32(value
));
134 pet
->UpdateResistances(school
);
140 void Player::UpdateArmor()
143 UnitMods unitMod
= UNIT_MOD_ARMOR
;
145 value
= GetModifierValue(unitMod
, BASE_VALUE
); // base armor (from items)
146 value
*= GetModifierValue(unitMod
, BASE_PCT
); // armor percent from items
147 value
+= GetStat(STAT_AGILITY
) * 2.0f
; // armor bonus from stats
148 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
);
150 //add dynamic flat mods
151 AuraList
const& mResbyIntellect
= GetAurasByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT
);
152 for(AuraList::const_iterator i
= mResbyIntellect
.begin();i
!= mResbyIntellect
.end(); ++i
)
154 Modifier
* mod
= (*i
)->GetModifier();
155 if(mod
->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
156 value
+= int32(GetStat(Stats((*i
)->GetMiscBValue())) * mod
->m_amount
/ 100.0f
);
159 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
161 SetArmor(int32(value
));
168 float Player::GetHealthBonusFromStamina()
170 float stamina
= GetStat(STAT_STAMINA
);
172 float baseStam
= stamina
< 20 ? stamina
: 20;
173 float moreStam
= stamina
- baseStam
;
175 return baseStam
+ (moreStam
*10.0f
);
178 float Player::GetManaBonusFromIntellect()
180 float intellect
= GetStat(STAT_INTELLECT
);
182 float baseInt
= intellect
< 20 ? intellect
: 20;
183 float moreInt
= intellect
- baseInt
;
185 return baseInt
+ (moreInt
*15.0f
);
188 void Player::UpdateMaxHealth()
190 UnitMods unitMod
= UNIT_MOD_HEALTH
;
192 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreateHealth();
193 value
*= GetModifierValue(unitMod
, BASE_PCT
);
194 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + GetHealthBonusFromStamina();
195 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
197 SetMaxHealth((uint32
)value
);
200 void Player::UpdateMaxPower(Powers power
)
202 UnitMods unitMod
= UnitMods(UNIT_MOD_POWER_START
+ power
);
204 float bonusPower
= (power
== POWER_MANA
) ? GetManaBonusFromIntellect() : 0;
206 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreatePowers(power
);
207 value
*= GetModifierValue(unitMod
, BASE_PCT
);
208 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + bonusPower
;
209 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
211 SetMaxPower(power
, uint32(value
));
214 void Player::UpdateAttackPowerAndDamage(bool ranged
)
217 float level
= float(getLevel());
219 UnitMods unitMod
= ranged
? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
221 uint16 index
= UNIT_FIELD_ATTACK_POWER
;
222 uint16 index_mod
= UNIT_FIELD_ATTACK_POWER_MODS
;
223 uint16 index_mult
= UNIT_FIELD_ATTACK_POWER_MULTIPLIER
;
227 index
= UNIT_FIELD_RANGED_ATTACK_POWER
;
228 index_mod
= UNIT_FIELD_RANGED_ATTACK_POWER_MODS
;
229 index_mult
= UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER
;
233 case CLASS_HUNTER
: val2
= level
* 2.0f
+ GetStat(STAT_AGILITY
) - 10.0f
; break;
234 case CLASS_ROGUE
: val2
= level
+ GetStat(STAT_AGILITY
) - 10.0f
; break;
235 case CLASS_WARRIOR
:val2
= level
+ GetStat(STAT_AGILITY
) - 10.0f
; break;
244 val2
= GetStat(STAT_AGILITY
) - 10.0f
; break;
247 default: val2
= GetStat(STAT_AGILITY
) - 10.0f
; break;
254 case CLASS_WARRIOR
: val2
= level
*3.0f
+ GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
255 case CLASS_PALADIN
: val2
= level
*3.0f
+ GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
256 case CLASS_ROGUE
: val2
= level
*2.0f
+ GetStat(STAT_STRENGTH
) + GetStat(STAT_AGILITY
) - 20.0f
; break;
257 case CLASS_HUNTER
: val2
= level
*2.0f
+ GetStat(STAT_STRENGTH
) + GetStat(STAT_AGILITY
) - 20.0f
; break;
258 case CLASS_SHAMAN
: val2
= level
*2.0f
+ GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
261 //Check if Predatory Strikes is skilled
262 float mLevelMult
= 0.0;
270 Unit::AuraList
const& mDummy
= GetAurasByType(SPELL_AURA_DUMMY
);
271 for(Unit::AuraList::const_iterator itr
= mDummy
.begin(); itr
!= mDummy
.end(); ++itr
)
274 if ((*itr
)->GetSpellProto()->SpellIconID
== 1563)
276 mLevelMult
= (*itr
)->GetModifier()->m_amount
/ 100.0f
;
287 val2
= getLevel()*(mLevelMult
+2.0f
) + GetStat(STAT_STRENGTH
)*2.0f
+ GetStat(STAT_AGILITY
) - 20.0f
; break;
290 val2
= getLevel()*(mLevelMult
+3.0f
) + GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
292 val2
= getLevel()*(mLevelMult
+1.5f
) + GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
294 val2
= GetStat(STAT_STRENGTH
)*2.0f
- 20.0f
; break;
298 case CLASS_MAGE
: val2
= GetStat(STAT_STRENGTH
) - 10.0f
; break;
299 case CLASS_PRIEST
: val2
= GetStat(STAT_STRENGTH
) - 10.0f
; break;
300 case CLASS_WARLOCK
: val2
= GetStat(STAT_STRENGTH
) - 10.0f
; break;
304 SetModifierValue(unitMod
, BASE_VALUE
, val2
);
306 float base_attPower
= GetModifierValue(unitMod
, BASE_VALUE
) * GetModifierValue(unitMod
, BASE_PCT
);
307 float attPowerMod
= GetModifierValue(unitMod
, TOTAL_VALUE
);
309 //add dynamic flat mods
310 if( ranged
&& (getClassMask() & CLASSMASK_WAND_USERS
)==0)
312 AuraList
const& mRAPbyIntellect
= GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT
);
313 for(AuraList::const_iterator i
= mRAPbyIntellect
.begin();i
!= mRAPbyIntellect
.end(); ++i
)
314 attPowerMod
+= int32(GetStat(Stats((*i
)->GetModifier()->m_miscvalue
)) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
317 float attPowerMultiplier
= GetModifierValue(unitMod
, TOTAL_PCT
) - 1.0f
;
319 SetUInt32Value(index
, (uint32
)base_attPower
); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
320 SetUInt32Value(index_mod
, (uint32
)attPowerMod
); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
321 SetFloatValue(index_mult
, attPowerMultiplier
); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
323 //automatically update weapon damage after attack power modification
326 UpdateDamagePhysical(RANGED_ATTACK
);
328 Pet
*pet
= GetPet(); //update pet's AP
330 pet
->UpdateAttackPowerAndDamage();
334 UpdateDamagePhysical(BASE_ATTACK
);
335 if(CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon
336 UpdateDamagePhysical(OFF_ATTACK
);
340 void Player::UpdateShieldBlockValue()
342 SetUInt32Value(PLAYER_SHIELD_BLOCK
, GetShieldBlockValue());
345 void Player::CalculateMinMaxDamage(WeaponAttackType attType
, bool normalized
, float& min_damage
, float& max_damage
)
354 unitMod
= UNIT_MOD_DAMAGE_MAINHAND
;
355 attPower
= UNIT_MOD_ATTACK_POWER
;
358 unitMod
= UNIT_MOD_DAMAGE_OFFHAND
;
359 attPower
= UNIT_MOD_ATTACK_POWER
;
362 unitMod
= UNIT_MOD_DAMAGE_RANGED
;
363 attPower
= UNIT_MOD_ATTACK_POWER_RANGED
;
367 float att_speed
= GetAPMultiplier(attType
,normalized
);
369 float base_value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetTotalAttackPowerValue(attType
)/ 14.0f
* att_speed
;
370 float base_pct
= GetModifierValue(unitMod
, BASE_PCT
);
371 float total_value
= GetModifierValue(unitMod
, TOTAL_VALUE
);
372 float total_pct
= GetModifierValue(unitMod
, TOTAL_PCT
);
374 float weapon_mindamage
= GetWeaponDamageRange(attType
, MINDAMAGE
);
375 float weapon_maxdamage
= GetWeaponDamageRange(attType
, MAXDAMAGE
);
377 if (IsInFeralForm()) //check if player is druid and in cat or bear forms
379 uint32 lvl
= getLevel();
380 if ( lvl
> 60 ) lvl
= 60;
382 weapon_mindamage
= lvl
*0.85*att_speed
;
383 weapon_maxdamage
= lvl
*1.25*att_speed
;
385 else if(!IsUseEquipedWeapon(attType
==BASE_ATTACK
)) //check if player not in form but still can't use weapon (broken/etc)
387 weapon_mindamage
= BASE_MINDAMAGE
;
388 weapon_maxdamage
= BASE_MAXDAMAGE
;
390 else if(attType
== RANGED_ATTACK
) //add ammo DPS to ranged damage
392 weapon_mindamage
+= GetAmmoDPS() * att_speed
;
393 weapon_maxdamage
+= GetAmmoDPS() * att_speed
;
396 min_damage
= ((base_value
+ weapon_mindamage
) * base_pct
+ total_value
) * total_pct
;
397 max_damage
= ((base_value
+ weapon_maxdamage
) * base_pct
+ total_value
) * total_pct
;
400 void Player::UpdateDamagePhysical(WeaponAttackType attType
)
405 CalculateMinMaxDamage(attType
,false,mindamage
,maxdamage
);
411 SetStatFloatValue(UNIT_FIELD_MINDAMAGE
,mindamage
);
412 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE
,maxdamage
);
415 SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE
,mindamage
);
416 SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE
,maxdamage
);
419 SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE
,mindamage
);
420 SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE
,maxdamage
);
425 void Player::UpdateDefenseBonusesMod()
427 UpdateBlockPercentage();
428 UpdateParryPercentage();
429 UpdateDodgePercentage();
432 void Player::UpdateBlockPercentage()
440 // Modify value from defense skill
441 value
+= (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
442 // Increase from SPELL_AURA_MOD_BLOCK_PERCENT aura
443 value
+= GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT
);
444 // Increase from rating
445 value
+= GetRatingBonusValue(CR_BLOCK
);
446 value
= value
< 0.0f
? 0.0f
: value
;
448 SetStatFloatValue(PLAYER_BLOCK_PERCENTAGE
, value
);
451 void Player::UpdateCritPercentage(WeaponAttackType attType
)
453 BaseModGroup modGroup
;
460 modGroup
= OFFHAND_CRIT_PERCENTAGE
;
461 index
= PLAYER_OFFHAND_CRIT_PERCENTAGE
;
465 modGroup
= RANGED_CRIT_PERCENTAGE
;
466 index
= PLAYER_RANGED_CRIT_PERCENTAGE
;
471 modGroup
= CRIT_PERCENTAGE
;
472 index
= PLAYER_CRIT_PERCENTAGE
;
477 float value
= GetTotalPercentageModValue(modGroup
) + GetRatingBonusValue(cr
);
478 // Modify crit from weapon skill and maximized defense skill of same level victim difference
479 value
+= (int32(GetWeaponSkillValue(attType
)) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
480 value
= value
< 0.0f
? 0.0f
: value
;
481 SetStatFloatValue(index
, value
);
484 void Player::UpdateAllCritPercentages()
486 float value
= GetMeleeCritFromAgility();
488 SetBaseModValue(CRIT_PERCENTAGE
, PCT_MOD
, value
);
489 SetBaseModValue(OFFHAND_CRIT_PERCENTAGE
, PCT_MOD
, value
);
490 SetBaseModValue(RANGED_CRIT_PERCENTAGE
, PCT_MOD
, value
);
492 UpdateCritPercentage(BASE_ATTACK
);
493 UpdateCritPercentage(OFF_ATTACK
);
494 UpdateCritPercentage(RANGED_ATTACK
);
497 void Player::UpdateParryPercentage()
505 // Modify value from defense skill
506 value
+= (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
507 // Parry from SPELL_AURA_MOD_PARRY_PERCENT aura
508 value
+= GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT
);
510 value
+= GetRatingBonusValue(CR_PARRY
);
511 value
= value
< 0.0f
? 0.0f
: value
;
513 SetStatFloatValue(PLAYER_PARRY_PERCENTAGE
, value
);
516 void Player::UpdateDodgePercentage()
518 // Dodge from agility
519 float value
= GetDodgeFromAgility();
520 // Modify value from defense skill
521 value
+= (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f
;
522 // Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura
523 value
+= GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT
);
525 value
+= GetRatingBonusValue(CR_DODGE
);
526 value
= value
< 0.0f
? 0.0f
: value
;
527 SetStatFloatValue(PLAYER_DODGE_PERCENTAGE
, value
);
530 void Player::UpdateSpellCritChance(uint32 school
)
532 // For normal school set zero crit chance
533 if(school
== SPELL_SCHOOL_NORMAL
)
535 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1
, 0.0f
);
538 // For others recalculate it from:
540 // Crit from Intellect
541 crit
+= GetSpellCritFromIntellect();
542 // Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE
543 crit
+= GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE
);
544 // Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
545 crit
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, 1<<school
);
546 // Increase crit from spell crit ratings
547 crit
+= GetRatingBonusValue(CR_CRIT_SPELL
);
550 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1
+ school
, crit
);
553 void Player::UpdateAllSpellCritChances()
555 for (int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; i
++)
556 UpdateSpellCritChance(i
);
559 void Player::UpdateExpertise(WeaponAttackType attack
)
561 if(attack
==RANGED_ATTACK
)
564 int32 expertise
= int32(GetRatingBonusValue(CR_EXPERTISE
));
566 Item
*weapon
= GetWeaponForAttack(attack
);
568 AuraList
const& expAuras
= GetAurasByType(SPELL_AURA_MOD_EXPERTISE
);
569 for(AuraList::const_iterator itr
= expAuras
.begin(); itr
!= expAuras
.end(); ++itr
)
571 // item neutral spell
572 if((*itr
)->GetSpellProto()->EquippedItemClass
== -1)
573 expertise
+= (*itr
)->GetModifier()->m_amount
;
574 // item dependent spell
575 else if(weapon
&& weapon
->IsFitToSpellRequirements((*itr
)->GetSpellProto()))
576 expertise
+= (*itr
)->GetModifier()->m_amount
;
584 case BASE_ATTACK
: SetUInt32Value(PLAYER_EXPERTISE
, expertise
); break;
585 case OFF_ATTACK
: SetUInt32Value(PLAYER_OFFHAND_EXPERTISE
, expertise
); break;
590 void Player::UpdateManaRegen()
592 float Intellect
= GetStat(STAT_INTELLECT
);
593 // Mana regen from spirit and intellect
594 float power_regen
= sqrt(Intellect
) * OCTRegenMPPerSpirit();
595 // Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen
596 power_regen
*= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT
, POWER_MANA
);
598 // Mana regen from SPELL_AURA_MOD_POWER_REGEN aura
599 float power_regen_mp5
= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN
, POWER_MANA
) / 5.0f
;
601 // Get bonus from SPELL_AURA_MOD_MANA_REGEN_FROM_STAT aura
602 AuraList
const& regenAura
= GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_FROM_STAT
);
603 for(AuraList::const_iterator i
= regenAura
.begin();i
!= regenAura
.end(); ++i
)
605 Modifier
* mod
= (*i
)->GetModifier();
606 power_regen_mp5
+= GetStat(Stats(mod
->m_miscvalue
)) * mod
->m_amount
/ 500.0f
;
609 // Bonus from some dummy auras
610 AuraList
const& mDummyAuras
= GetAurasByType(SPELL_AURA_PERIODIC_DUMMY
);
611 for(AuraList::const_iterator i
= mDummyAuras
.begin();i
!= mDummyAuras
.end(); ++i
)
612 if((*i
)->GetId() == 34074) // Aspect of the Viper
614 power_regen_mp5
+= (*i
)->GetModifier()->m_amount
* Intellect
/ 500.0f
;
615 // Add regen bonus from level in this dummy
616 power_regen_mp5
+= getLevel() * 35 / 100;
619 // Set regen rate in cast state apply only on spirit based regen
620 int32 modManaRegenInterrupt
= GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
);
621 if (modManaRegenInterrupt
> 100)
622 modManaRegenInterrupt
= 100;
623 SetStatFloatValue(PLAYER_FIELD_MOD_MANA_REGEN_INTERRUPT
, power_regen_mp5
+ power_regen
* modManaRegenInterrupt
/ 100.0f
);
625 SetStatFloatValue(PLAYER_FIELD_MOD_MANA_REGEN
, power_regen_mp5
+ power_regen
);
628 void Player::_ApplyAllStatBonuses()
630 SetCanModifyStats(false);
635 SetCanModifyStats(true);
640 void Player::_RemoveAllStatBonuses()
642 SetCanModifyStats(false);
644 _RemoveAllItemMods();
645 _RemoveAllAuraMods();
647 SetCanModifyStats(true);
652 /*#######################################
654 ######## MOBS STAT SYSTEM ########
656 #######################################*/
658 bool Creature::UpdateStats(Stats
/*stat*/)
663 bool Creature::UpdateAllStats()
666 UpdateAttackPowerAndDamage();
668 for(int i
= POWER_MANA
; i
< MAX_POWERS
; ++i
)
669 UpdateMaxPower(Powers(i
));
671 for(int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; ++i
)
672 UpdateResistances(i
);
677 void Creature::UpdateResistances(uint32 school
)
679 if(school
> SPELL_SCHOOL_NORMAL
)
681 float value
= GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START
+ school
));
682 SetResistance(SpellSchools(school
), int32(value
));
688 void Creature::UpdateArmor()
690 float value
= GetTotalAuraModValue(UNIT_MOD_ARMOR
);
691 SetArmor(int32(value
));
694 void Creature::UpdateMaxHealth()
696 float value
= GetTotalAuraModValue(UNIT_MOD_HEALTH
);
697 SetMaxHealth((uint32
)value
);
700 void Creature::UpdateMaxPower(Powers power
)
702 UnitMods unitMod
= UnitMods(UNIT_MOD_POWER_START
+ power
);
704 float value
= GetTotalAuraModValue(unitMod
);
705 SetMaxPower(power
, uint32(value
));
708 void Creature::UpdateAttackPowerAndDamage(bool ranged
)
713 //automatically update weapon damage after attack power modification
714 UpdateDamagePhysical(BASE_ATTACK
);
717 void Creature::UpdateDamagePhysical(WeaponAttackType attType
)
719 if(attType
> BASE_ATTACK
)
722 UnitMods unitMod
= UNIT_MOD_DAMAGE_MAINHAND
;
724 float att_speed
= float(GetAttackTime(BASE_ATTACK
))/1000.0f
;
726 float base_value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetTotalAttackPowerValue(attType
)/ 14.0f
* att_speed
;
727 float base_pct
= GetModifierValue(unitMod
, BASE_PCT
);
728 float total_value
= GetModifierValue(unitMod
, TOTAL_VALUE
);
729 float total_pct
= GetModifierValue(unitMod
, TOTAL_PCT
);
731 float weapon_mindamage
= GetWeaponDamageRange(BASE_ATTACK
, MINDAMAGE
);
732 float weapon_maxdamage
= GetWeaponDamageRange(BASE_ATTACK
, MAXDAMAGE
);
734 float mindamage
= ((base_value
+ weapon_mindamage
) * base_pct
+ total_value
) * total_pct
;
735 float maxdamage
= ((base_value
+ weapon_maxdamage
) * base_pct
+ total_value
) * total_pct
;
737 SetStatFloatValue(UNIT_FIELD_MINDAMAGE
, mindamage
);
738 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE
, maxdamage
);
741 /*#######################################
743 ######## PETS STAT SYSTEM ########
745 #######################################*/
747 bool Pet::UpdateStats(Stats stat
)
749 if(stat
> STAT_SPIRIT
)
752 // value = ((base_value * base_pct) + total_value) * total_pct
753 float value
= GetTotalStatValue(stat
);
755 Unit
*owner
= GetOwner();
756 if ( stat
== STAT_STAMINA
)
759 value
+= float(owner
->GetStat(stat
)) * 0.3f
;
761 //warlock's and mage's pets gain 30% of owner's intellect
762 else if ( stat
== STAT_INTELLECT
&& getPetType() == SUMMON_PET
)
764 if(owner
&& (owner
->getClass() == CLASS_WARLOCK
|| owner
->getClass() == CLASS_MAGE
) )
765 value
+= float(owner
->GetStat(stat
)) * 0.3f
;
768 SetStat(stat
, int32(value
));
772 case STAT_STRENGTH
: UpdateAttackPowerAndDamage(); break;
773 case STAT_AGILITY
: UpdateArmor(); break;
774 case STAT_STAMINA
: UpdateMaxHealth(); break;
775 case STAT_INTELLECT
: UpdateMaxPower(POWER_MANA
); break;
784 bool Pet::UpdateAllStats()
786 for (int i
= STAT_STRENGTH
; i
< MAX_STATS
; i
++)
787 UpdateStats(Stats(i
));
789 for(int i
= POWER_MANA
; i
< MAX_POWERS
; i
++)
790 UpdateMaxPower(Powers(i
));
792 for (int i
= SPELL_SCHOOL_NORMAL
; i
< MAX_SPELL_SCHOOL
; i
++)
793 UpdateResistances(i
);
798 void Pet::UpdateResistances(uint32 school
)
800 if(school
> SPELL_SCHOOL_NORMAL
)
802 float value
= GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START
+ school
));
804 Unit
*owner
= GetOwner();
805 // hunter and warlock pets gain 40% of owner's resistance
806 if(owner
&& (getPetType() == HUNTER_PET
|| getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_WARLOCK
))
807 value
+= float(owner
->GetResistance(SpellSchools(school
))) * 0.4f
;
809 SetResistance(SpellSchools(school
), int32(value
));
815 void Pet::UpdateArmor()
818 float bonus_armor
= 0.0f
;
819 UnitMods unitMod
= UNIT_MOD_ARMOR
;
821 Unit
*owner
= GetOwner();
822 // hunter and warlock pets gain 35% of owner's armor value
823 if(owner
&& (getPetType() == HUNTER_PET
|| getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_WARLOCK
))
824 bonus_armor
= 0.35f
* float(owner
->GetArmor());
826 value
= GetModifierValue(unitMod
, BASE_VALUE
);
827 value
*= GetModifierValue(unitMod
, BASE_PCT
);
828 value
+= GetStat(STAT_AGILITY
) * 2.0f
;
829 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + bonus_armor
;
830 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
832 SetArmor(int32(value
));
835 void Pet::UpdateMaxHealth()
837 UnitMods unitMod
= UNIT_MOD_HEALTH
;
838 float stamina
= GetStat(STAT_STAMINA
) - GetCreateStat(STAT_STAMINA
);
840 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreateHealth();
841 value
*= GetModifierValue(unitMod
, BASE_PCT
);
842 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + stamina
* 10.0f
;
843 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
845 SetMaxHealth((uint32
)value
);
848 void Pet::UpdateMaxPower(Powers power
)
850 UnitMods unitMod
= UnitMods(UNIT_MOD_POWER_START
+ power
);
851 float addValue
= (power
== POWER_MANA
) ? GetStat(STAT_INTELLECT
) - GetCreateStat(STAT_INTELLECT
) : 0.0f
;
853 float value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetCreatePowers(power
);
854 value
*= GetModifierValue(unitMod
, BASE_PCT
);
855 value
+= GetModifierValue(unitMod
, TOTAL_VALUE
) + addValue
* 15.0f
;
856 value
*= GetModifierValue(unitMod
, TOTAL_PCT
);
858 SetMaxPower(power
, uint32(value
));
861 void Pet::UpdateAttackPowerAndDamage(bool ranged
)
867 float bonusAP
= 0.0f
;
868 UnitMods unitMod
= UNIT_MOD_ATTACK_POWER
;
870 if(GetEntry() == 416) // imp's attack power
871 val
= GetStat(STAT_STRENGTH
) - 10.0f
;
873 val
= 2 * GetStat(STAT_STRENGTH
) - 20.0f
;
875 Unit
* owner
= GetOwner();
876 if( owner
&& owner
->GetTypeId()==TYPEID_PLAYER
)
878 if(getPetType() == HUNTER_PET
) //hunter pets benefit from owner's attack power
880 bonusAP
= owner
->GetTotalAttackPowerValue(RANGED_ATTACK
) * 0.22f
;
881 SetBonusDamage( int32(owner
->GetTotalAttackPowerValue(RANGED_ATTACK
) * 0.125f
));
883 //demons benefit from warlocks shadow or fire damage
884 else if(getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_WARLOCK
)
886 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
);
887 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
);
888 int32 maximum
= (fire
> shadow
) ? fire
: shadow
;
891 SetBonusDamage( int32(maximum
* 0.15f
));
892 bonusAP
= maximum
* 0.57f
;
894 //water elementals benefit from mage's frost damage
895 else if(getPetType() == SUMMON_PET
&& owner
->getClass() == CLASS_MAGE
)
897 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
);
900 SetBonusDamage( int32(frost
* 0.4f
));
904 SetModifierValue(UNIT_MOD_ATTACK_POWER
, BASE_VALUE
, val
+ bonusAP
);
906 //in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB
907 float base_attPower
= GetModifierValue(unitMod
, BASE_VALUE
) * GetModifierValue(unitMod
, BASE_PCT
);
908 float attPowerMod
= GetModifierValue(unitMod
, TOTAL_VALUE
);
909 float attPowerMultiplier
= GetModifierValue(unitMod
, TOTAL_PCT
) - 1.0f
;
911 //UNIT_FIELD_(RANGED)_ATTACK_POWER field
912 SetUInt32Value(UNIT_FIELD_ATTACK_POWER
, (uint32
)base_attPower
);
913 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
914 SetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS
, (uint32
)attPowerMod
);
915 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
916 SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER
, attPowerMultiplier
);
918 //automatically update weapon damage after attack power modification
919 UpdateDamagePhysical(BASE_ATTACK
);
922 void Pet::UpdateDamagePhysical(WeaponAttackType attType
)
924 if(attType
> BASE_ATTACK
)
927 UnitMods unitMod
= UNIT_MOD_DAMAGE_MAINHAND
;
929 float att_speed
= float(GetAttackTime(BASE_ATTACK
))/1000.0f
;
931 float base_value
= GetModifierValue(unitMod
, BASE_VALUE
) + GetTotalAttackPowerValue(attType
)/ 14.0f
* att_speed
;
932 float base_pct
= GetModifierValue(unitMod
, BASE_PCT
);
933 float total_value
= GetModifierValue(unitMod
, TOTAL_VALUE
);
934 float total_pct
= GetModifierValue(unitMod
, TOTAL_PCT
);
936 float weapon_mindamage
= GetWeaponDamageRange(BASE_ATTACK
, MINDAMAGE
);
937 float weapon_maxdamage
= GetWeaponDamageRange(BASE_ATTACK
, MAXDAMAGE
);
939 float mindamage
= ((base_value
+ weapon_mindamage
) * base_pct
+ total_value
) * total_pct
;
940 float maxdamage
= ((base_value
+ weapon_maxdamage
) * base_pct
+ total_value
) * total_pct
;
942 // Pet's base damage changes depending on happiness
943 if (getPetType() == HUNTER_PET
&& attType
== BASE_ATTACK
)
945 switch(GetHappinessState())
948 // 125% of normal damage
949 mindamage
= mindamage
* 1.25;
950 maxdamage
= maxdamage
* 1.25;
953 // 100% of normal damage, nothing to modify
956 // 75% of normal damage
957 mindamage
= mindamage
* 0.75;
958 maxdamage
= maxdamage
* 0.75;
963 SetStatFloatValue(UNIT_FIELD_MINDAMAGE
, mindamage
);
964 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE
, maxdamage
);