[9033] Fixed percent mana regneration from spell 53228 and ranks buff.
[getmangos.git] / src / game / StatSystem.cpp
blob8275d0c2f0fc66c09386225a96f0cbf123f6536e
1 /*
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
19 #include "Unit.h"
20 #include "Player.h"
21 #include "Pet.h"
22 #include "Creature.h"
23 #include "SharedDefines.h"
24 #include "SpellAuras.h"
26 /*#######################################
27 ######## ########
28 ######## PLAYERS STAT SYSTEM ########
29 ######## ########
30 #######################################*/
32 bool Player::UpdateStats(Stats stat)
34 if(stat > STAT_SPIRIT)
35 return false;
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)
44 Pet *pet = GetPet();
45 if(pet)
46 pet->UpdateStats(stat);
49 switch(stat)
51 case STAT_STRENGTH:
52 UpdateShieldBlockValue();
53 break;
54 case STAT_AGILITY:
55 UpdateArmor();
56 UpdateAllCritPercentages();
57 UpdateDodgePercentage();
58 break;
59 case STAT_STAMINA: UpdateMaxHealth(); break;
60 case STAT_INTELLECT:
61 UpdateMaxPower(POWER_MANA);
62 UpdateAllSpellCritChances();
63 UpdateArmor(); //SPELL_AURA_MOD_RESISTANCE_OF_INTELLECT_PERCENT, only armor currently
64 break;
66 case STAT_SPIRIT:
67 break;
69 default:
70 break;
72 // Need update (exist AP from stat auras)
73 UpdateAttackPowerAndDamage();
74 UpdateAttackPowerAndDamage(true);
76 UpdateSpellDamageAndHealingBonus();
77 UpdateManaRegen();
79 // Update ratings in exist SPELL_AURA_MOD_RATING_FROM_STAT and only depends from stat
80 uint32 mask = 0;
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();
85 if (mask)
87 for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
88 if (mask & (1 << rating))
89 ApplyRatingMod(CombatRating(rating), 0, true);
91 return 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);
123 UpdateArmor();
124 // calls UpdateAttackPowerAndDamage() in UpdateArmor for SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR
125 UpdateAttackPowerAndDamage(true);
126 UpdateMaxHealth();
128 for(int i = POWER_MANA; i < MAX_POWERS; ++i)
129 UpdateMaxPower(Powers(i));
131 UpdateAllCritPercentages();
132 UpdateAllSpellCritChances();
133 UpdateDefenseBonusesMod();
134 UpdateShieldBlockValue();
135 UpdateArmorPenetration();
136 UpdateSpellDamageAndHealingBonus();
137 UpdateManaRegen();
138 UpdateExpertise(BASE_ATTACK);
139 UpdateExpertise(OFF_ATTACK);
140 for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
141 UpdateResistances(i);
143 return true;
146 void Player::UpdateResistances(uint32 school)
148 if(school > SPELL_SCHOOL_NORMAL)
150 float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school));
151 SetResistance(SpellSchools(school), int32(value));
153 Pet *pet = GetPet();
154 if(pet)
155 pet->UpdateResistances(school);
157 else
158 UpdateArmor();
161 void Player::UpdateArmor()
163 float value = 0.0f;
164 UnitMods unitMod = UNIT_MOD_ARMOR;
166 value = GetModifierValue(unitMod, BASE_VALUE); // base armor (from items)
167 value *= GetModifierValue(unitMod, BASE_PCT); // armor percent from items
168 value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats
169 value += GetModifierValue(unitMod, TOTAL_VALUE);
171 //add dynamic flat mods
172 AuraList const& mResbyIntellect = GetAurasByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT);
173 for(AuraList::const_iterator i = mResbyIntellect.begin();i != mResbyIntellect.end(); ++i)
175 Modifier* mod = (*i)->GetModifier();
176 if(mod->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL)
177 value += int32(GetStat(Stats((*i)->GetMiscBValue())) * mod->m_amount / 100.0f);
180 value *= GetModifierValue(unitMod, TOTAL_PCT);
182 SetArmor(int32(value));
184 Pet *pet = GetPet();
185 if(pet)
186 pet->UpdateArmor();
188 UpdateAttackPowerAndDamage(); // armor dependent auras update for SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR
191 float Player::GetHealthBonusFromStamina()
193 float stamina = GetStat(STAT_STAMINA);
195 float baseStam = stamina < 20 ? stamina : 20;
196 float moreStam = stamina - baseStam;
198 return baseStam + (moreStam*10.0f);
201 float Player::GetManaBonusFromIntellect()
203 float intellect = GetStat(STAT_INTELLECT);
205 float baseInt = intellect < 20 ? intellect : 20;
206 float moreInt = intellect - baseInt;
208 return baseInt + (moreInt*15.0f);
211 void Player::UpdateMaxHealth()
213 UnitMods unitMod = UNIT_MOD_HEALTH;
215 float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
216 value *= GetModifierValue(unitMod, BASE_PCT);
217 value += GetModifierValue(unitMod, TOTAL_VALUE) + GetHealthBonusFromStamina();
218 value *= GetModifierValue(unitMod, TOTAL_PCT);
220 SetMaxHealth((uint32)value);
223 void Player::UpdateMaxPower(Powers power)
225 UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
227 uint32 create_power = GetCreatePowers(power);
229 // ignore classes without mana
230 float bonusPower = (power == POWER_MANA && create_power > 0) ? GetManaBonusFromIntellect() : 0;
232 float value = GetModifierValue(unitMod, BASE_VALUE) + create_power;
233 value *= GetModifierValue(unitMod, BASE_PCT);
234 value += GetModifierValue(unitMod, TOTAL_VALUE) + bonusPower;
235 value *= GetModifierValue(unitMod, TOTAL_PCT);
237 SetMaxPower(power, uint32(value));
240 void Player::ApplyFeralAPBonus(int32 amount, bool apply)
242 m_baseFeralAP+= apply ? amount:-amount;
243 UpdateAttackPowerAndDamage();
246 void Player::UpdateAttackPowerAndDamage(bool ranged )
248 float val2 = 0.0f;
249 float level = float(getLevel());
251 UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER;
253 uint16 index = UNIT_FIELD_ATTACK_POWER;
254 uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MODS;
255 uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER;
257 if(ranged)
259 index = UNIT_FIELD_RANGED_ATTACK_POWER;
260 index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS;
261 index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER;
263 switch(getClass())
265 case CLASS_HUNTER: val2 = level * 2.0f + GetStat(STAT_AGILITY) - 10.0f; break;
266 case CLASS_ROGUE: val2 = level + GetStat(STAT_AGILITY) - 10.0f; break;
267 case CLASS_WARRIOR:val2 = level + GetStat(STAT_AGILITY) - 10.0f; break;
268 case CLASS_DRUID:
269 switch(m_form)
271 case FORM_CAT:
272 case FORM_BEAR:
273 case FORM_DIREBEAR:
274 val2 = 0.0f; break;
275 default:
276 val2 = GetStat(STAT_AGILITY) - 10.0f; break;
278 break;
279 default: val2 = GetStat(STAT_AGILITY) - 10.0f; break;
282 else
284 switch(getClass())
286 case CLASS_WARRIOR: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
287 case CLASS_PALADIN: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
288 case CLASS_DEATH_KNIGHT: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
289 case CLASS_ROGUE: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break;
290 case CLASS_HUNTER: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break;
291 case CLASS_SHAMAN: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break;
292 case CLASS_DRUID:
294 //Check if Predatory Strikes is skilled
295 float mLevelMult = 0.0;
296 switch(m_form)
298 case FORM_CAT:
299 case FORM_BEAR:
300 case FORM_DIREBEAR:
301 case FORM_MOONKIN:
303 Unit::AuraList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY);
304 for(Unit::AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
306 // Predatory Strikes (effect 0)
307 if ((*itr)->GetEffIndex()==0 && (*itr)->GetSpellProto()->SpellIconID == 1563)
309 mLevelMult = (*itr)->GetModifier()->m_amount / 100.0f;
310 break;
313 break;
315 default: break;
318 switch(m_form)
320 case FORM_CAT:
321 val2 = getLevel()*(mLevelMult+2.0f) + GetStat(STAT_STRENGTH)*2.0f + GetStat(STAT_AGILITY) - 20.0f + m_baseFeralAP; break;
322 case FORM_BEAR:
323 case FORM_DIREBEAR:
324 val2 = getLevel()*(mLevelMult+3.0f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f + m_baseFeralAP; break;
325 case FORM_MOONKIN:
326 val2 = getLevel()*(mLevelMult+1.5f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f + m_baseFeralAP; break;
327 default:
328 val2 = GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
330 break;
332 case CLASS_MAGE: val2 = GetStat(STAT_STRENGTH) - 10.0f; break;
333 case CLASS_PRIEST: val2 = GetStat(STAT_STRENGTH) - 10.0f; break;
334 case CLASS_WARLOCK: val2 = GetStat(STAT_STRENGTH) - 10.0f; break;
338 SetModifierValue(unitMod, BASE_VALUE, val2);
340 float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
341 float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
343 //add dynamic flat mods
344 if( ranged )
346 if ((getClassMask() & CLASSMASK_WAND_USERS)==0)
348 AuraList const& mRAPbyStat = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT);
349 for(AuraList::const_iterator i = mRAPbyStat.begin();i != mRAPbyStat.end(); ++i)
350 attPowerMod += int32(GetStat(Stats((*i)->GetModifier()->m_miscvalue)) * (*i)->GetModifier()->m_amount / 100.0f);
353 else
355 AuraList const& mAPbyStat = GetAurasByType(SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT);
356 for(AuraList::const_iterator i = mAPbyStat.begin();i != mAPbyStat.end(); ++i)
357 attPowerMod += int32(GetStat(Stats((*i)->GetModifier()->m_miscvalue)) * (*i)->GetModifier()->m_amount / 100.0f);
359 AuraList const& mAPbyArmor = GetAurasByType(SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR);
360 for(AuraList::const_iterator iter = mAPbyArmor.begin(); iter != mAPbyArmor.end(); ++iter)
361 // always: ((*i)->GetModifier()->m_miscvalue == 1 == SPELL_SCHOOL_MASK_NORMAL)
362 attPowerMod += int32(GetArmor() / (*iter)->GetModifier()->m_amount);
365 float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
367 SetInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
368 SetInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
369 SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
371 //automatically update weapon damage after attack power modification
372 if(ranged)
374 UpdateDamagePhysical(RANGED_ATTACK);
376 Pet *pet = GetPet(); //update pet's AP
377 if(pet)
378 pet->UpdateAttackPowerAndDamage();
380 else
382 UpdateDamagePhysical(BASE_ATTACK);
383 if(CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon
384 UpdateDamagePhysical(OFF_ATTACK);
388 void Player::UpdateShieldBlockValue()
390 SetUInt32Value(PLAYER_SHIELD_BLOCK, GetShieldBlockValue());
393 void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, float& min_damage, float& max_damage)
395 UnitMods unitMod;
396 UnitMods attPower;
398 switch(attType)
400 case BASE_ATTACK:
401 default:
402 unitMod = UNIT_MOD_DAMAGE_MAINHAND;
403 attPower = UNIT_MOD_ATTACK_POWER;
404 break;
405 case OFF_ATTACK:
406 unitMod = UNIT_MOD_DAMAGE_OFFHAND;
407 attPower = UNIT_MOD_ATTACK_POWER;
408 break;
409 case RANGED_ATTACK:
410 unitMod = UNIT_MOD_DAMAGE_RANGED;
411 attPower = UNIT_MOD_ATTACK_POWER_RANGED;
412 break;
415 float att_speed = GetAPMultiplier(attType,normalized);
417 float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
418 float base_pct = GetModifierValue(unitMod, BASE_PCT);
419 float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
420 float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
422 float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE);
423 float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE);
425 if (IsInFeralForm()) //check if player is druid and in cat or bear forms
427 uint32 lvl = getLevel();
428 if ( lvl > 60 ) lvl = 60;
430 weapon_mindamage = lvl*0.85*att_speed;
431 weapon_maxdamage = lvl*1.25*att_speed;
433 else if(!IsUseEquipedWeapon(attType==BASE_ATTACK)) //check if player not in form but still can't use weapon (broken/etc)
435 weapon_mindamage = BASE_MINDAMAGE;
436 weapon_maxdamage = BASE_MAXDAMAGE;
438 else if(attType == RANGED_ATTACK) //add ammo DPS to ranged damage
440 weapon_mindamage += GetAmmoDPS() * att_speed;
441 weapon_maxdamage += GetAmmoDPS() * att_speed;
444 min_damage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct;
445 max_damage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct;
448 void Player::UpdateDamagePhysical(WeaponAttackType attType)
450 float mindamage;
451 float maxdamage;
453 CalculateMinMaxDamage(attType,false,mindamage,maxdamage);
455 switch(attType)
457 case BASE_ATTACK:
458 default:
459 SetStatFloatValue(UNIT_FIELD_MINDAMAGE,mindamage);
460 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE,maxdamage);
461 break;
462 case OFF_ATTACK:
463 SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE,mindamage);
464 SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE,maxdamage);
465 break;
466 case RANGED_ATTACK:
467 SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE,mindamage);
468 SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE,maxdamage);
469 break;
473 void Player::UpdateDefenseBonusesMod()
475 UpdateBlockPercentage();
476 UpdateParryPercentage();
477 UpdateDodgePercentage();
480 void Player::UpdateBlockPercentage()
482 // No block
483 float value = 0.0f;
484 if(CanBlock())
486 // Base value
487 value = 5.0f;
488 // Modify value from defense skill
489 value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
490 // Increase from SPELL_AURA_MOD_BLOCK_PERCENT aura
491 value += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT);
492 // Increase from rating
493 value += GetRatingBonusValue(CR_BLOCK);
494 value = value < 0.0f ? 0.0f : value;
496 SetStatFloatValue(PLAYER_BLOCK_PERCENTAGE, value);
499 void Player::UpdateCritPercentage(WeaponAttackType attType)
501 BaseModGroup modGroup;
502 uint16 index;
503 CombatRating cr;
505 switch(attType)
507 case OFF_ATTACK:
508 modGroup = OFFHAND_CRIT_PERCENTAGE;
509 index = PLAYER_OFFHAND_CRIT_PERCENTAGE;
510 cr = CR_CRIT_MELEE;
511 break;
512 case RANGED_ATTACK:
513 modGroup = RANGED_CRIT_PERCENTAGE;
514 index = PLAYER_RANGED_CRIT_PERCENTAGE;
515 cr = CR_CRIT_RANGED;
516 break;
517 case BASE_ATTACK:
518 default:
519 modGroup = CRIT_PERCENTAGE;
520 index = PLAYER_CRIT_PERCENTAGE;
521 cr = CR_CRIT_MELEE;
522 break;
525 float value = GetTotalPercentageModValue(modGroup) + GetRatingBonusValue(cr);
526 // Modify crit from weapon skill and maximized defense skill of same level victim difference
527 value += (int32(GetWeaponSkillValue(attType)) - int32(GetMaxSkillValueForLevel())) * 0.04f;
528 value = value < 0.0f ? 0.0f : value;
529 SetStatFloatValue(index, value);
532 void Player::UpdateAllCritPercentages()
534 float value = GetMeleeCritFromAgility();
536 SetBaseModValue(CRIT_PERCENTAGE, PCT_MOD, value);
537 SetBaseModValue(OFFHAND_CRIT_PERCENTAGE, PCT_MOD, value);
538 SetBaseModValue(RANGED_CRIT_PERCENTAGE, PCT_MOD, value);
540 UpdateCritPercentage(BASE_ATTACK);
541 UpdateCritPercentage(OFF_ATTACK);
542 UpdateCritPercentage(RANGED_ATTACK);
545 void Player::UpdateParryPercentage()
547 // No parry
548 float value = 0.0f;
549 if (CanParry())
551 // Base parry
552 value = 5.0f;
553 // Modify value from defense skill
554 value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
555 // Parry from SPELL_AURA_MOD_PARRY_PERCENT aura
556 value += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT);
557 // Parry from rating
558 value += GetRatingBonusValue(CR_PARRY);
559 value = value < 0.0f ? 0.0f : value;
561 SetStatFloatValue(PLAYER_PARRY_PERCENTAGE, value);
564 void Player::UpdateDodgePercentage()
566 // Dodge from agility
567 float value = GetDodgeFromAgility();
568 // Modify value from defense skill
569 value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
570 // Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura
571 value += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT);
572 // Dodge from rating
573 value += GetRatingBonusValue(CR_DODGE);
574 value = value < 0.0f ? 0.0f : value;
575 SetStatFloatValue(PLAYER_DODGE_PERCENTAGE, value);
578 void Player::UpdateSpellCritChance(uint32 school)
580 // For normal school set zero crit chance
581 if(school == SPELL_SCHOOL_NORMAL)
583 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1, 0.0f);
584 return;
586 // For others recalculate it from:
587 float crit = 0.0f;
588 // Crit from Intellect
589 crit += GetSpellCritFromIntellect();
590 // Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE
591 crit += GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE);
592 // Increase crit from SPELL_AURA_MOD_ALL_CRIT_CHANCE
593 crit += GetTotalAuraModifier(SPELL_AURA_MOD_ALL_CRIT_CHANCE);
594 // Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
595 crit += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, 1<<school);
596 // Increase crit from spell crit ratings
597 crit += GetRatingBonusValue(CR_CRIT_SPELL);
599 // Store crit value
600 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1 + school, crit);
603 void Player::UpdateMeleeHitChances()
605 m_modMeleeHitChance = GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE);
606 m_modMeleeHitChance+= GetRatingBonusValue(CR_HIT_MELEE);
609 void Player::UpdateRangedHitChances()
611 m_modRangedHitChance = GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE);
612 m_modRangedHitChance+= GetRatingBonusValue(CR_HIT_RANGED);
615 void Player::UpdateSpellHitChances()
617 m_modSpellHitChance = GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HIT_CHANCE);
618 m_modSpellHitChance+= GetRatingBonusValue(CR_HIT_SPELL);
621 void Player::UpdateAllSpellCritChances()
623 for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
624 UpdateSpellCritChance(i);
627 void Player::UpdateExpertise(WeaponAttackType attack)
629 if(attack==RANGED_ATTACK)
630 return;
632 int32 expertise = int32(GetRatingBonusValue(CR_EXPERTISE));
634 Item *weapon = GetWeaponForAttack(attack);
636 AuraList const& expAuras = GetAurasByType(SPELL_AURA_MOD_EXPERTISE);
637 for(AuraList::const_iterator itr = expAuras.begin(); itr != expAuras.end(); ++itr)
639 // item neutral spell
640 if((*itr)->GetSpellProto()->EquippedItemClass == -1)
641 expertise += (*itr)->GetModifier()->m_amount;
642 // item dependent spell
643 else if(weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellProto()))
644 expertise += (*itr)->GetModifier()->m_amount;
647 if(expertise < 0)
648 expertise = 0;
650 switch(attack)
652 case BASE_ATTACK: SetUInt32Value(PLAYER_EXPERTISE, expertise); break;
653 case OFF_ATTACK: SetUInt32Value(PLAYER_OFFHAND_EXPERTISE, expertise); break;
654 default: break;
658 void Player::UpdateArmorPenetration()
660 m_armorPenetrationPct = GetRatingBonusValue(CR_ARMOR_PENETRATION);
662 AuraList const& armorAuras = GetAurasByType(SPELL_AURA_MOD_TARGET_ARMOR_PCT);
663 for(AuraList::const_iterator itr = armorAuras.begin(); itr != armorAuras.end(); ++itr)
665 // affects all weapons
666 if((*itr)->GetSpellProto()->EquippedItemClass == -1)
668 m_armorPenetrationPct += (*itr)->GetModifier()->m_amount;
669 continue;
672 // dependent on weapon class
673 for(uint8 i = 0; i < MAX_ATTACK; ++i)
675 Item *weapon = GetWeaponForAttack(WeaponAttackType(i));
676 if(weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellProto()))
678 m_armorPenetrationPct += (*itr)->GetModifier()->m_amount;
679 break;
685 void Player::ApplyManaRegenBonus(int32 amount, bool apply)
687 m_baseManaRegen+= apply ? amount : -amount;
688 UpdateManaRegen();
691 void Player::UpdateManaRegen()
693 float Intellect = GetStat(STAT_INTELLECT);
694 // Mana regen from spirit and intellect
695 float power_regen = sqrt(Intellect) * OCTRegenMPPerSpirit();
696 // Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen
697 power_regen *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, POWER_MANA);
699 // Mana regen from SPELL_AURA_MOD_POWER_REGEN aura
700 float power_regen_mp5 = (GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) + m_baseManaRegen) / 5.0f;
702 // Get bonus from SPELL_AURA_MOD_MANA_REGEN_FROM_STAT aura
703 AuraList const& regenAura = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_FROM_STAT);
704 for(AuraList::const_iterator i = regenAura.begin();i != regenAura.end(); ++i)
706 Modifier* mod = (*i)->GetModifier();
707 power_regen_mp5 += GetStat(Stats(mod->m_miscvalue)) * mod->m_amount / 500.0f;
710 // Set regen rate in cast state apply only on spirit based regen
711 int32 modManaRegenInterrupt = GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
712 if (modManaRegenInterrupt > 100)
713 modManaRegenInterrupt = 100;
714 SetStatFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER, power_regen_mp5 + power_regen * modManaRegenInterrupt / 100.0f);
716 SetStatFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER, power_regen_mp5 + power_regen);
719 void Player::_ApplyAllStatBonuses()
721 SetCanModifyStats(false);
723 _ApplyAllAuraMods();
724 _ApplyAllItemMods();
726 SetCanModifyStats(true);
728 UpdateAllStats();
731 void Player::_RemoveAllStatBonuses()
733 SetCanModifyStats(false);
735 _RemoveAllItemMods();
736 _RemoveAllAuraMods();
738 SetCanModifyStats(true);
740 UpdateAllStats();
743 /*#######################################
744 ######## ########
745 ######## MOBS STAT SYSTEM ########
746 ######## ########
747 #######################################*/
749 bool Creature::UpdateStats(Stats /*stat*/)
751 return true;
754 bool Creature::UpdateAllStats()
756 UpdateMaxHealth();
757 UpdateAttackPowerAndDamage();
759 for(int i = POWER_MANA; i < MAX_POWERS; ++i)
760 UpdateMaxPower(Powers(i));
762 for(int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
763 UpdateResistances(i);
765 return true;
768 void Creature::UpdateResistances(uint32 school)
770 if(school > SPELL_SCHOOL_NORMAL)
772 float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school));
773 SetResistance(SpellSchools(school), int32(value));
775 else
776 UpdateArmor();
779 void Creature::UpdateArmor()
781 float value = GetTotalAuraModValue(UNIT_MOD_ARMOR);
782 SetArmor(int32(value));
785 void Creature::UpdateMaxHealth()
787 float value = GetTotalAuraModValue(UNIT_MOD_HEALTH);
788 SetMaxHealth((uint32)value);
791 void Creature::UpdateMaxPower(Powers power)
793 UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
795 float value = GetTotalAuraModValue(unitMod);
796 SetMaxPower(power, uint32(value));
799 void Creature::UpdateAttackPowerAndDamage(bool ranged)
801 UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER;
803 uint16 index = UNIT_FIELD_ATTACK_POWER;
804 uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MODS;
805 uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER;
807 if(ranged)
809 index = UNIT_FIELD_RANGED_ATTACK_POWER;
810 index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS;
811 index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER;
814 float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
815 float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
816 float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
818 SetInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
819 SetInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
820 SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
822 if(ranged)
823 return;
824 //automatically update weapon damage after attack power modification
825 UpdateDamagePhysical(BASE_ATTACK);
828 void Creature::UpdateDamagePhysical(WeaponAttackType attType)
830 if(attType > BASE_ATTACK)
831 return;
833 UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND;
835 /* difference in AP between current attack power and base value from DB */
836 float att_pwr_change = GetTotalAttackPowerValue(attType) - GetCreatureInfo()->attackpower;
837 float base_value = GetModifierValue(unitMod, BASE_VALUE) + (att_pwr_change * GetAPMultiplier(attType, false) / 14.0f);
838 float base_pct = GetModifierValue(unitMod, BASE_PCT);
839 float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
840 float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
841 float dmg_multiplier = GetCreatureInfo()->dmg_multiplier;
843 float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
844 float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
846 float mindamage = ((base_value + weapon_mindamage) * dmg_multiplier * base_pct + total_value) * total_pct;
847 float maxdamage = ((base_value + weapon_maxdamage) * dmg_multiplier * base_pct + total_value) * total_pct;
849 SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage);
850 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage);
853 /*#######################################
854 ######## ########
855 ######## PETS STAT SYSTEM ########
856 ######## ########
857 #######################################*/
859 bool Pet::UpdateStats(Stats stat)
861 if(stat > STAT_SPIRIT)
862 return false;
864 // value = ((base_value * base_pct) + total_value) * total_pct
865 float value = GetTotalStatValue(stat);
867 Unit *owner = GetOwner();
868 if ( stat == STAT_STAMINA )
870 if(owner)
871 value += float(owner->GetStat(stat)) * 0.3f;
873 //warlock's and mage's pets gain 30% of owner's intellect
874 else if ( stat == STAT_INTELLECT && getPetType() == SUMMON_PET )
876 if(owner && (owner->getClass() == CLASS_WARLOCK || owner->getClass() == CLASS_MAGE) )
877 value += float(owner->GetStat(stat)) * 0.3f;
880 SetStat(stat, int32(value));
882 switch(stat)
884 case STAT_STRENGTH: UpdateAttackPowerAndDamage(); break;
885 case STAT_AGILITY: UpdateArmor(); break;
886 case STAT_STAMINA: UpdateMaxHealth(); break;
887 case STAT_INTELLECT: UpdateMaxPower(POWER_MANA); break;
888 case STAT_SPIRIT:
889 default:
890 break;
893 return true;
896 bool Pet::UpdateAllStats()
898 for (int i = STAT_STRENGTH; i < MAX_STATS; ++i)
899 UpdateStats(Stats(i));
901 for(int i = POWER_MANA; i < MAX_POWERS; ++i)
902 UpdateMaxPower(Powers(i));
904 for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
905 UpdateResistances(i);
907 return true;
910 void Pet::UpdateResistances(uint32 school)
912 if(school > SPELL_SCHOOL_NORMAL)
914 float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school));
916 Unit *owner = GetOwner();
917 // hunter and warlock pets gain 40% of owner's resistance
918 if(owner && (getPetType() == HUNTER_PET || (getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK)))
919 value += float(owner->GetResistance(SpellSchools(school))) * 0.4f;
921 SetResistance(SpellSchools(school), int32(value));
923 else
924 UpdateArmor();
927 void Pet::UpdateArmor()
929 float value = 0.0f;
930 float bonus_armor = 0.0f;
931 UnitMods unitMod = UNIT_MOD_ARMOR;
933 Unit *owner = GetOwner();
934 // hunter and warlock pets gain 35% of owner's armor value
935 if(owner && (getPetType() == HUNTER_PET || (getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK)))
936 bonus_armor = 0.35f * float(owner->GetArmor());
938 value = GetModifierValue(unitMod, BASE_VALUE);
939 value *= GetModifierValue(unitMod, BASE_PCT);
940 value += GetStat(STAT_AGILITY) * 2.0f;
941 value += GetModifierValue(unitMod, TOTAL_VALUE) + bonus_armor;
942 value *= GetModifierValue(unitMod, TOTAL_PCT);
944 SetArmor(int32(value));
947 void Pet::UpdateMaxHealth()
949 UnitMods unitMod = UNIT_MOD_HEALTH;
950 float stamina = GetStat(STAT_STAMINA) - GetCreateStat(STAT_STAMINA);
952 float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
953 value *= GetModifierValue(unitMod, BASE_PCT);
954 value += GetModifierValue(unitMod, TOTAL_VALUE) + stamina * 10.0f;
955 value *= GetModifierValue(unitMod, TOTAL_PCT);
957 SetMaxHealth((uint32)value);
960 void Pet::UpdateMaxPower(Powers power)
962 UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
964 float addValue = (power == POWER_MANA) ? GetStat(STAT_INTELLECT) - GetCreateStat(STAT_INTELLECT) : 0.0f;
966 float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
967 value *= GetModifierValue(unitMod, BASE_PCT);
968 value += GetModifierValue(unitMod, TOTAL_VALUE) + addValue * 15.0f;
969 value *= GetModifierValue(unitMod, TOTAL_PCT);
971 SetMaxPower(power, uint32(value));
974 void Pet::UpdateAttackPowerAndDamage(bool ranged)
976 if(ranged)
977 return;
979 float val = 0.0f;
980 float bonusAP = 0.0f;
981 UnitMods unitMod = UNIT_MOD_ATTACK_POWER;
983 if(GetEntry() == 416) // imp's attack power
984 val = GetStat(STAT_STRENGTH) - 10.0f;
985 else
986 val = 2 * GetStat(STAT_STRENGTH) - 20.0f;
988 Unit* owner = GetOwner();
989 if( owner && owner->GetTypeId()==TYPEID_PLAYER)
991 if(getPetType() == HUNTER_PET) //hunter pets benefit from owner's attack power
993 bonusAP = owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.22f;
994 SetBonusDamage( int32(owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.1287f));
996 //demons benefit from warlocks shadow or fire damage
997 else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK)
999 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);
1000 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);
1001 int32 maximum = (fire > shadow) ? fire : shadow;
1002 if(maximum < 0)
1003 maximum = 0;
1004 SetBonusDamage( int32(maximum * 0.15f));
1005 bonusAP = maximum * 0.57f;
1007 //water elementals benefit from mage's frost damage
1008 else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_MAGE)
1010 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);
1011 if(frost < 0)
1012 frost = 0;
1013 SetBonusDamage( int32(frost * 0.4f));
1017 SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, val + bonusAP);
1019 //in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB
1020 float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
1021 float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
1022 float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
1024 //UNIT_FIELD_(RANGED)_ATTACK_POWER field
1025 SetInt32Value(UNIT_FIELD_ATTACK_POWER, (int32)base_attPower);
1026 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
1027 SetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (int32)attPowerMod);
1028 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
1029 SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, attPowerMultiplier);
1031 //automatically update weapon damage after attack power modification
1032 UpdateDamagePhysical(BASE_ATTACK);
1035 void Pet::UpdateDamagePhysical(WeaponAttackType attType)
1037 if(attType > BASE_ATTACK)
1038 return;
1040 UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND;
1042 float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f;
1044 float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
1045 float base_pct = GetModifierValue(unitMod, BASE_PCT);
1046 float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
1047 float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
1049 float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
1050 float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
1052 float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct;
1053 float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct;
1055 // Pet's base damage changes depending on happiness
1056 if (getPetType() == HUNTER_PET && attType == BASE_ATTACK)
1058 switch(GetHappinessState())
1060 case HAPPY:
1061 // 125% of normal damage
1062 mindamage = mindamage * 1.25;
1063 maxdamage = maxdamage * 1.25;
1064 break;
1065 case CONTENT:
1066 // 100% of normal damage, nothing to modify
1067 break;
1068 case UNHAPPY:
1069 // 75% of normal damage
1070 mindamage = mindamage * 0.75;
1071 maxdamage = maxdamage * 0.75;
1072 break;
1076 SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage);
1077 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage);