[9184] Fixed unread packet tail spam for CMSG_LEAVE_BATTLEFIELD
[getmangos.git] / src / game / StatSystem.cpp
blobbc08d1909d0f203730b78c3ac8e61a2a52137696
1 /*
2 * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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 UpdateAllRatings();
132 UpdateAllCritPercentages();
133 UpdateAllSpellCritChances();
134 UpdateDefenseBonusesMod();
135 UpdateShieldBlockValue();
136 UpdateArmorPenetration();
137 UpdateSpellDamageAndHealingBonus();
138 UpdateManaRegen();
139 UpdateExpertise(BASE_ATTACK);
140 UpdateExpertise(OFF_ATTACK);
141 for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
142 UpdateResistances(i);
144 return true;
147 void Player::UpdateResistances(uint32 school)
149 if(school > SPELL_SCHOOL_NORMAL)
151 float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school));
152 SetResistance(SpellSchools(school), int32(value));
154 Pet *pet = GetPet();
155 if(pet)
156 pet->UpdateResistances(school);
158 else
159 UpdateArmor();
162 void Player::UpdateArmor()
164 float value = 0.0f;
165 UnitMods unitMod = UNIT_MOD_ARMOR;
167 value = GetModifierValue(unitMod, BASE_VALUE); // base armor (from items)
168 value *= GetModifierValue(unitMod, BASE_PCT); // armor percent from items
169 value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats
170 value += GetModifierValue(unitMod, TOTAL_VALUE);
172 //add dynamic flat mods
173 AuraList const& mResbyIntellect = GetAurasByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT);
174 for(AuraList::const_iterator i = mResbyIntellect.begin();i != mResbyIntellect.end(); ++i)
176 Modifier* mod = (*i)->GetModifier();
177 if(mod->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL)
178 value += int32(GetStat(Stats((*i)->GetMiscBValue())) * mod->m_amount / 100.0f);
181 value *= GetModifierValue(unitMod, TOTAL_PCT);
183 SetArmor(int32(value));
185 Pet *pet = GetPet();
186 if(pet)
187 pet->UpdateArmor();
189 UpdateAttackPowerAndDamage(); // armor dependent auras update for SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR
192 float Player::GetHealthBonusFromStamina()
194 float stamina = GetStat(STAT_STAMINA);
196 float baseStam = stamina < 20 ? stamina : 20;
197 float moreStam = stamina - baseStam;
199 return baseStam + (moreStam*10.0f);
202 float Player::GetManaBonusFromIntellect()
204 float intellect = GetStat(STAT_INTELLECT);
206 float baseInt = intellect < 20 ? intellect : 20;
207 float moreInt = intellect - baseInt;
209 return baseInt + (moreInt*15.0f);
212 void Player::UpdateMaxHealth()
214 UnitMods unitMod = UNIT_MOD_HEALTH;
216 float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
217 value *= GetModifierValue(unitMod, BASE_PCT);
218 value += GetModifierValue(unitMod, TOTAL_VALUE) + GetHealthBonusFromStamina();
219 value *= GetModifierValue(unitMod, TOTAL_PCT);
221 SetMaxHealth((uint32)value);
224 void Player::UpdateMaxPower(Powers power)
226 UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
228 uint32 create_power = GetCreatePowers(power);
230 // ignore classes without mana
231 float bonusPower = (power == POWER_MANA && create_power > 0) ? GetManaBonusFromIntellect() : 0;
233 float value = GetModifierValue(unitMod, BASE_VALUE) + create_power;
234 value *= GetModifierValue(unitMod, BASE_PCT);
235 value += GetModifierValue(unitMod, TOTAL_VALUE) + bonusPower;
236 value *= GetModifierValue(unitMod, TOTAL_PCT);
238 SetMaxPower(power, uint32(value));
241 void Player::ApplyFeralAPBonus(int32 amount, bool apply)
243 m_baseFeralAP+= apply ? amount:-amount;
244 UpdateAttackPowerAndDamage();
247 void Player::UpdateAttackPowerAndDamage(bool ranged )
249 float val2 = 0.0f;
250 float level = float(getLevel());
252 UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER;
254 uint16 index = UNIT_FIELD_ATTACK_POWER;
255 uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MODS;
256 uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER;
258 if(ranged)
260 index = UNIT_FIELD_RANGED_ATTACK_POWER;
261 index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS;
262 index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER;
264 switch(getClass())
266 case CLASS_HUNTER: val2 = level * 2.0f + GetStat(STAT_AGILITY) - 10.0f; break;
267 case CLASS_ROGUE: val2 = level + GetStat(STAT_AGILITY) - 10.0f; break;
268 case CLASS_WARRIOR:val2 = level + GetStat(STAT_AGILITY) - 10.0f; break;
269 case CLASS_DRUID:
270 switch(m_form)
272 case FORM_CAT:
273 case FORM_BEAR:
274 case FORM_DIREBEAR:
275 val2 = 0.0f; break;
276 default:
277 val2 = GetStat(STAT_AGILITY) - 10.0f; break;
279 break;
280 default: val2 = GetStat(STAT_AGILITY) - 10.0f; break;
283 else
285 switch(getClass())
287 case CLASS_WARRIOR: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
288 case CLASS_PALADIN: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
289 case CLASS_DEATH_KNIGHT: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
290 case CLASS_ROGUE: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break;
291 case CLASS_HUNTER: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break;
292 case CLASS_SHAMAN: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break;
293 case CLASS_DRUID:
295 //Check if Predatory Strikes is skilled
296 float mLevelMult = 0.0;
297 switch(m_form)
299 case FORM_CAT:
300 case FORM_BEAR:
301 case FORM_DIREBEAR:
302 case FORM_MOONKIN:
304 Unit::AuraList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY);
305 for(Unit::AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
307 // Predatory Strikes (effect 0)
308 if ((*itr)->GetEffIndex()==0 && (*itr)->GetSpellProto()->SpellIconID == 1563)
310 mLevelMult = (*itr)->GetModifier()->m_amount / 100.0f;
311 break;
314 break;
316 default: break;
319 switch(m_form)
321 case FORM_CAT:
322 val2 = getLevel()*(mLevelMult+2.0f) + GetStat(STAT_STRENGTH)*2.0f + GetStat(STAT_AGILITY) - 20.0f + m_baseFeralAP; break;
323 case FORM_BEAR:
324 case FORM_DIREBEAR:
325 val2 = getLevel()*(mLevelMult+3.0f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f + m_baseFeralAP; break;
326 case FORM_MOONKIN:
327 val2 = getLevel()*(mLevelMult+1.5f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f + m_baseFeralAP; break;
328 default:
329 val2 = GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
331 break;
333 case CLASS_MAGE: val2 = GetStat(STAT_STRENGTH) - 10.0f; break;
334 case CLASS_PRIEST: val2 = GetStat(STAT_STRENGTH) - 10.0f; break;
335 case CLASS_WARLOCK: val2 = GetStat(STAT_STRENGTH) - 10.0f; break;
339 SetModifierValue(unitMod, BASE_VALUE, val2);
341 float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
342 float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
344 //add dynamic flat mods
345 if( ranged )
347 if ((getClassMask() & CLASSMASK_WAND_USERS)==0)
349 AuraList const& mRAPbyStat = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT);
350 for(AuraList::const_iterator i = mRAPbyStat.begin();i != mRAPbyStat.end(); ++i)
351 attPowerMod += int32(GetStat(Stats((*i)->GetModifier()->m_miscvalue)) * (*i)->GetModifier()->m_amount / 100.0f);
354 else
356 AuraList const& mAPbyStat = GetAurasByType(SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT);
357 for(AuraList::const_iterator i = mAPbyStat.begin();i != mAPbyStat.end(); ++i)
358 attPowerMod += int32(GetStat(Stats((*i)->GetModifier()->m_miscvalue)) * (*i)->GetModifier()->m_amount / 100.0f);
360 AuraList const& mAPbyArmor = GetAurasByType(SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR);
361 for(AuraList::const_iterator iter = mAPbyArmor.begin(); iter != mAPbyArmor.end(); ++iter)
362 // always: ((*i)->GetModifier()->m_miscvalue == 1 == SPELL_SCHOOL_MASK_NORMAL)
363 attPowerMod += int32(GetArmor() / (*iter)->GetModifier()->m_amount);
366 float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
368 SetInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
369 SetInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
370 SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
372 //automatically update weapon damage after attack power modification
373 if(ranged)
375 UpdateDamagePhysical(RANGED_ATTACK);
377 Pet *pet = GetPet(); //update pet's AP
378 if(pet)
379 pet->UpdateAttackPowerAndDamage();
381 else
383 UpdateDamagePhysical(BASE_ATTACK);
384 if(CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon
385 UpdateDamagePhysical(OFF_ATTACK);
389 void Player::UpdateShieldBlockValue()
391 SetUInt32Value(PLAYER_SHIELD_BLOCK, GetShieldBlockValue());
394 void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, float& min_damage, float& max_damage)
396 UnitMods unitMod;
397 UnitMods attPower;
399 switch(attType)
401 case BASE_ATTACK:
402 default:
403 unitMod = UNIT_MOD_DAMAGE_MAINHAND;
404 attPower = UNIT_MOD_ATTACK_POWER;
405 break;
406 case OFF_ATTACK:
407 unitMod = UNIT_MOD_DAMAGE_OFFHAND;
408 attPower = UNIT_MOD_ATTACK_POWER;
409 break;
410 case RANGED_ATTACK:
411 unitMod = UNIT_MOD_DAMAGE_RANGED;
412 attPower = UNIT_MOD_ATTACK_POWER_RANGED;
413 break;
416 float att_speed = GetAPMultiplier(attType,normalized);
418 float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
419 float base_pct = GetModifierValue(unitMod, BASE_PCT);
420 float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
421 float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
423 float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE);
424 float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE);
426 if (IsInFeralForm()) //check if player is druid and in cat or bear forms
428 uint32 lvl = getLevel();
429 if ( lvl > 60 ) lvl = 60;
431 weapon_mindamage = lvl*0.85*att_speed;
432 weapon_maxdamage = lvl*1.25*att_speed;
434 else if(!IsUseEquipedWeapon(attType==BASE_ATTACK)) //check if player not in form but still can't use weapon (broken/etc)
436 weapon_mindamage = BASE_MINDAMAGE;
437 weapon_maxdamage = BASE_MAXDAMAGE;
439 else if(attType == RANGED_ATTACK) //add ammo DPS to ranged damage
441 weapon_mindamage += GetAmmoDPS() * att_speed;
442 weapon_maxdamage += GetAmmoDPS() * att_speed;
445 min_damage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct;
446 max_damage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct;
449 void Player::UpdateDamagePhysical(WeaponAttackType attType)
451 float mindamage;
452 float maxdamage;
454 CalculateMinMaxDamage(attType,false,mindamage,maxdamage);
456 switch(attType)
458 case BASE_ATTACK:
459 default:
460 SetStatFloatValue(UNIT_FIELD_MINDAMAGE,mindamage);
461 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE,maxdamage);
462 break;
463 case OFF_ATTACK:
464 SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE,mindamage);
465 SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE,maxdamage);
466 break;
467 case RANGED_ATTACK:
468 SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE,mindamage);
469 SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE,maxdamage);
470 break;
474 void Player::UpdateDefenseBonusesMod()
476 UpdateBlockPercentage();
477 UpdateParryPercentage();
478 UpdateDodgePercentage();
481 void Player::UpdateBlockPercentage()
483 // No block
484 float value = 0.0f;
485 if(CanBlock())
487 // Base value
488 value = 5.0f;
489 // Modify value from defense skill
490 value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
491 // Increase from SPELL_AURA_MOD_BLOCK_PERCENT aura
492 value += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT);
493 // Increase from rating
494 value += GetRatingBonusValue(CR_BLOCK);
495 value = value < 0.0f ? 0.0f : value;
497 SetStatFloatValue(PLAYER_BLOCK_PERCENTAGE, value);
500 void Player::UpdateCritPercentage(WeaponAttackType attType)
502 BaseModGroup modGroup;
503 uint16 index;
504 CombatRating cr;
506 switch(attType)
508 case OFF_ATTACK:
509 modGroup = OFFHAND_CRIT_PERCENTAGE;
510 index = PLAYER_OFFHAND_CRIT_PERCENTAGE;
511 cr = CR_CRIT_MELEE;
512 break;
513 case RANGED_ATTACK:
514 modGroup = RANGED_CRIT_PERCENTAGE;
515 index = PLAYER_RANGED_CRIT_PERCENTAGE;
516 cr = CR_CRIT_RANGED;
517 break;
518 case BASE_ATTACK:
519 default:
520 modGroup = CRIT_PERCENTAGE;
521 index = PLAYER_CRIT_PERCENTAGE;
522 cr = CR_CRIT_MELEE;
523 break;
526 float value = GetTotalPercentageModValue(modGroup) + GetRatingBonusValue(cr);
527 // Modify crit from weapon skill and maximized defense skill of same level victim difference
528 value += (int32(GetWeaponSkillValue(attType)) - int32(GetMaxSkillValueForLevel())) * 0.04f;
529 value = value < 0.0f ? 0.0f : value;
530 SetStatFloatValue(index, value);
533 void Player::UpdateAllCritPercentages()
535 float value = GetMeleeCritFromAgility();
537 SetBaseModValue(CRIT_PERCENTAGE, PCT_MOD, value);
538 SetBaseModValue(OFFHAND_CRIT_PERCENTAGE, PCT_MOD, value);
539 SetBaseModValue(RANGED_CRIT_PERCENTAGE, PCT_MOD, value);
541 UpdateCritPercentage(BASE_ATTACK);
542 UpdateCritPercentage(OFF_ATTACK);
543 UpdateCritPercentage(RANGED_ATTACK);
546 void Player::UpdateParryPercentage()
548 // No parry
549 float value = 0.0f;
550 if (CanParry())
552 // Base parry
553 value = 5.0f;
554 // Modify value from defense skill
555 value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
556 // Parry from SPELL_AURA_MOD_PARRY_PERCENT aura
557 value += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT);
558 // Parry from rating
559 value += GetRatingBonusValue(CR_PARRY);
560 value = value < 0.0f ? 0.0f : value;
562 SetStatFloatValue(PLAYER_PARRY_PERCENTAGE, value);
565 void Player::UpdateDodgePercentage()
567 // Dodge from agility
568 float value = GetDodgeFromAgility();
569 // Modify value from defense skill
570 value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
571 // Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura
572 value += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT);
573 // Dodge from rating
574 value += GetRatingBonusValue(CR_DODGE);
575 value = value < 0.0f ? 0.0f : value;
576 SetStatFloatValue(PLAYER_DODGE_PERCENTAGE, value);
579 void Player::UpdateSpellCritChance(uint32 school)
581 // For normal school set zero crit chance
582 if(school == SPELL_SCHOOL_NORMAL)
584 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1, 0.0f);
585 return;
587 // For others recalculate it from:
588 float crit = 0.0f;
589 // Crit from Intellect
590 crit += GetSpellCritFromIntellect();
591 // Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE
592 crit += GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE);
593 // Increase crit from SPELL_AURA_MOD_ALL_CRIT_CHANCE
594 crit += GetTotalAuraModifier(SPELL_AURA_MOD_ALL_CRIT_CHANCE);
595 // Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
596 crit += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, 1<<school);
597 // Increase crit from spell crit ratings
598 crit += GetRatingBonusValue(CR_CRIT_SPELL);
600 // Store crit value
601 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1 + school, crit);
604 void Player::UpdateMeleeHitChances()
606 m_modMeleeHitChance = GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE);
607 m_modMeleeHitChance+= GetRatingBonusValue(CR_HIT_MELEE);
610 void Player::UpdateRangedHitChances()
612 m_modRangedHitChance = GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE);
613 m_modRangedHitChance+= GetRatingBonusValue(CR_HIT_RANGED);
616 void Player::UpdateSpellHitChances()
618 m_modSpellHitChance = GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HIT_CHANCE);
619 m_modSpellHitChance+= GetRatingBonusValue(CR_HIT_SPELL);
622 void Player::UpdateAllSpellCritChances()
624 for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
625 UpdateSpellCritChance(i);
628 void Player::UpdateExpertise(WeaponAttackType attack)
630 if(attack==RANGED_ATTACK)
631 return;
633 int32 expertise = int32(GetRatingBonusValue(CR_EXPERTISE));
635 Item *weapon = GetWeaponForAttack(attack);
637 AuraList const& expAuras = GetAurasByType(SPELL_AURA_MOD_EXPERTISE);
638 for(AuraList::const_iterator itr = expAuras.begin(); itr != expAuras.end(); ++itr)
640 // item neutral spell
641 if((*itr)->GetSpellProto()->EquippedItemClass == -1)
642 expertise += (*itr)->GetModifier()->m_amount;
643 // item dependent spell
644 else if(weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellProto()))
645 expertise += (*itr)->GetModifier()->m_amount;
648 if(expertise < 0)
649 expertise = 0;
651 switch(attack)
653 case BASE_ATTACK: SetUInt32Value(PLAYER_EXPERTISE, expertise); break;
654 case OFF_ATTACK: SetUInt32Value(PLAYER_OFFHAND_EXPERTISE, expertise); break;
655 default: break;
659 void Player::UpdateArmorPenetration()
661 m_armorPenetrationPct = GetRatingBonusValue(CR_ARMOR_PENETRATION);
663 AuraList const& armorAuras = GetAurasByType(SPELL_AURA_MOD_TARGET_ARMOR_PCT);
664 for(AuraList::const_iterator itr = armorAuras.begin(); itr != armorAuras.end(); ++itr)
666 // affects all weapons
667 if((*itr)->GetSpellProto()->EquippedItemClass == -1)
669 m_armorPenetrationPct += (*itr)->GetModifier()->m_amount;
670 continue;
673 // dependent on weapon class
674 for(uint8 i = 0; i < MAX_ATTACK; ++i)
676 Item *weapon = GetWeaponForAttack(WeaponAttackType(i));
677 if(weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellProto()))
679 m_armorPenetrationPct += (*itr)->GetModifier()->m_amount;
680 break;
686 void Player::ApplyManaRegenBonus(int32 amount, bool apply)
688 m_baseManaRegen+= apply ? amount : -amount;
689 UpdateManaRegen();
692 void Player::UpdateManaRegen()
694 float Intellect = GetStat(STAT_INTELLECT);
695 // Mana regen from spirit and intellect
696 float power_regen = sqrt(Intellect) * OCTRegenMPPerSpirit();
697 // Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen
698 power_regen *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, POWER_MANA);
700 // Mana regen from SPELL_AURA_MOD_POWER_REGEN aura
701 float power_regen_mp5 = (GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) + m_baseManaRegen) / 5.0f;
703 // Get bonus from SPELL_AURA_MOD_MANA_REGEN_FROM_STAT aura
704 AuraList const& regenAura = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_FROM_STAT);
705 for(AuraList::const_iterator i = regenAura.begin();i != regenAura.end(); ++i)
707 Modifier* mod = (*i)->GetModifier();
708 power_regen_mp5 += GetStat(Stats(mod->m_miscvalue)) * mod->m_amount / 500.0f;
711 // Set regen rate in cast state apply only on spirit based regen
712 int32 modManaRegenInterrupt = GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
713 if (modManaRegenInterrupt > 100)
714 modManaRegenInterrupt = 100;
715 SetStatFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER, power_regen_mp5 + power_regen * modManaRegenInterrupt / 100.0f);
717 SetStatFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER, power_regen_mp5 + power_regen);
720 void Player::_ApplyAllStatBonuses()
722 SetCanModifyStats(false);
724 _ApplyAllAuraMods();
725 _ApplyAllItemMods();
727 SetCanModifyStats(true);
729 UpdateAllStats();
732 void Player::_RemoveAllStatBonuses()
734 SetCanModifyStats(false);
736 _RemoveAllItemMods();
737 _RemoveAllAuraMods();
739 SetCanModifyStats(true);
741 UpdateAllStats();
744 /*#######################################
745 ######## ########
746 ######## MOBS STAT SYSTEM ########
747 ######## ########
748 #######################################*/
750 bool Creature::UpdateStats(Stats /*stat*/)
752 return true;
755 bool Creature::UpdateAllStats()
757 UpdateMaxHealth();
758 UpdateAttackPowerAndDamage();
760 for(int i = POWER_MANA; i < MAX_POWERS; ++i)
761 UpdateMaxPower(Powers(i));
763 for(int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
764 UpdateResistances(i);
766 return true;
769 void Creature::UpdateResistances(uint32 school)
771 if(school > SPELL_SCHOOL_NORMAL)
773 float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school));
774 SetResistance(SpellSchools(school), int32(value));
776 else
777 UpdateArmor();
780 void Creature::UpdateArmor()
782 float value = GetTotalAuraModValue(UNIT_MOD_ARMOR);
783 SetArmor(int32(value));
786 void Creature::UpdateMaxHealth()
788 float value = GetTotalAuraModValue(UNIT_MOD_HEALTH);
789 SetMaxHealth((uint32)value);
792 void Creature::UpdateMaxPower(Powers power)
794 UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
796 float value = GetTotalAuraModValue(unitMod);
797 SetMaxPower(power, uint32(value));
800 void Creature::UpdateAttackPowerAndDamage(bool ranged)
802 UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER;
804 uint16 index = UNIT_FIELD_ATTACK_POWER;
805 uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MODS;
806 uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER;
808 if(ranged)
810 index = UNIT_FIELD_RANGED_ATTACK_POWER;
811 index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS;
812 index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER;
815 float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
816 float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
817 float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
819 SetInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
820 SetInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
821 SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
823 if(ranged)
824 return;
825 //automatically update weapon damage after attack power modification
826 UpdateDamagePhysical(BASE_ATTACK);
829 void Creature::UpdateDamagePhysical(WeaponAttackType attType)
831 if(attType > BASE_ATTACK)
832 return;
834 UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND;
836 /* difference in AP between current attack power and base value from DB */
837 float att_pwr_change = GetTotalAttackPowerValue(attType) - GetCreatureInfo()->attackpower;
838 float base_value = GetModifierValue(unitMod, BASE_VALUE) + (att_pwr_change * GetAPMultiplier(attType, false) / 14.0f);
839 float base_pct = GetModifierValue(unitMod, BASE_PCT);
840 float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
841 float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
842 float dmg_multiplier = GetCreatureInfo()->dmg_multiplier;
844 float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
845 float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
847 float mindamage = ((base_value + weapon_mindamage) * dmg_multiplier * base_pct + total_value) * total_pct;
848 float maxdamage = ((base_value + weapon_maxdamage) * dmg_multiplier * base_pct + total_value) * total_pct;
850 SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage);
851 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage);
854 /*#######################################
855 ######## ########
856 ######## PETS STAT SYSTEM ########
857 ######## ########
858 #######################################*/
860 bool Pet::UpdateStats(Stats stat)
862 if(stat > STAT_SPIRIT)
863 return false;
865 // value = ((base_value * base_pct) + total_value) * total_pct
866 float value = GetTotalStatValue(stat);
868 Unit *owner = GetOwner();
869 if ( stat == STAT_STAMINA )
871 if(owner)
872 value += float(owner->GetStat(stat)) * 0.3f;
874 //warlock's and mage's pets gain 30% of owner's intellect
875 else if ( stat == STAT_INTELLECT && getPetType() == SUMMON_PET )
877 if(owner && (owner->getClass() == CLASS_WARLOCK || owner->getClass() == CLASS_MAGE) )
878 value += float(owner->GetStat(stat)) * 0.3f;
881 SetStat(stat, int32(value));
883 switch(stat)
885 case STAT_STRENGTH: UpdateAttackPowerAndDamage(); break;
886 case STAT_AGILITY: UpdateArmor(); break;
887 case STAT_STAMINA: UpdateMaxHealth(); break;
888 case STAT_INTELLECT: UpdateMaxPower(POWER_MANA); break;
889 case STAT_SPIRIT:
890 default:
891 break;
894 return true;
897 bool Pet::UpdateAllStats()
899 for (int i = STAT_STRENGTH; i < MAX_STATS; ++i)
900 UpdateStats(Stats(i));
902 for(int i = POWER_MANA; i < MAX_POWERS; ++i)
903 UpdateMaxPower(Powers(i));
905 for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
906 UpdateResistances(i);
908 return true;
911 void Pet::UpdateResistances(uint32 school)
913 if(school > SPELL_SCHOOL_NORMAL)
915 float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school));
917 Unit *owner = GetOwner();
918 // hunter and warlock pets gain 40% of owner's resistance
919 if(owner && (getPetType() == HUNTER_PET || (getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK)))
920 value += float(owner->GetResistance(SpellSchools(school))) * 0.4f;
922 SetResistance(SpellSchools(school), int32(value));
924 else
925 UpdateArmor();
928 void Pet::UpdateArmor()
930 float value = 0.0f;
931 float bonus_armor = 0.0f;
932 UnitMods unitMod = UNIT_MOD_ARMOR;
934 Unit *owner = GetOwner();
935 // hunter and warlock pets gain 35% of owner's armor value
936 if(owner && (getPetType() == HUNTER_PET || (getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK)))
937 bonus_armor = 0.35f * float(owner->GetArmor());
939 value = GetModifierValue(unitMod, BASE_VALUE);
940 value *= GetModifierValue(unitMod, BASE_PCT);
941 value += GetStat(STAT_AGILITY) * 2.0f;
942 value += GetModifierValue(unitMod, TOTAL_VALUE) + bonus_armor;
943 value *= GetModifierValue(unitMod, TOTAL_PCT);
945 SetArmor(int32(value));
948 void Pet::UpdateMaxHealth()
950 UnitMods unitMod = UNIT_MOD_HEALTH;
951 float stamina = GetStat(STAT_STAMINA) - GetCreateStat(STAT_STAMINA);
953 float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
954 value *= GetModifierValue(unitMod, BASE_PCT);
955 value += GetModifierValue(unitMod, TOTAL_VALUE) + stamina * 10.0f;
956 value *= GetModifierValue(unitMod, TOTAL_PCT);
958 SetMaxHealth((uint32)value);
961 void Pet::UpdateMaxPower(Powers power)
963 UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
965 float addValue = (power == POWER_MANA) ? GetStat(STAT_INTELLECT) - GetCreateStat(STAT_INTELLECT) : 0.0f;
967 float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
968 value *= GetModifierValue(unitMod, BASE_PCT);
969 value += GetModifierValue(unitMod, TOTAL_VALUE) + addValue * 15.0f;
970 value *= GetModifierValue(unitMod, TOTAL_PCT);
972 SetMaxPower(power, uint32(value));
975 void Pet::UpdateAttackPowerAndDamage(bool ranged)
977 if(ranged)
978 return;
980 float val = 0.0f;
981 float bonusAP = 0.0f;
982 UnitMods unitMod = UNIT_MOD_ATTACK_POWER;
984 if(GetEntry() == 416) // imp's attack power
985 val = GetStat(STAT_STRENGTH) - 10.0f;
986 else
987 val = 2 * GetStat(STAT_STRENGTH) - 20.0f;
989 Unit* owner = GetOwner();
990 if( owner && owner->GetTypeId()==TYPEID_PLAYER)
992 if(getPetType() == HUNTER_PET) //hunter pets benefit from owner's attack power
994 bonusAP = owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.22f;
995 SetBonusDamage( int32(owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.1287f));
997 //demons benefit from warlocks shadow or fire damage
998 else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK)
1000 int32 fire = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FIRE);
1001 int32 shadow = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_SHADOW)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_SHADOW);
1002 int32 maximum = (fire > shadow) ? fire : shadow;
1003 if(maximum < 0)
1004 maximum = 0;
1005 SetBonusDamage( int32(maximum * 0.15f));
1006 bonusAP = maximum * 0.57f;
1008 //water elementals benefit from mage's frost damage
1009 else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_MAGE)
1011 int32 frost = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FROST)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FROST);
1012 if(frost < 0)
1013 frost = 0;
1014 SetBonusDamage( int32(frost * 0.4f));
1018 SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, val + bonusAP);
1020 //in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB
1021 float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
1022 float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
1023 float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
1025 //UNIT_FIELD_(RANGED)_ATTACK_POWER field
1026 SetInt32Value(UNIT_FIELD_ATTACK_POWER, (int32)base_attPower);
1027 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
1028 SetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (int32)attPowerMod);
1029 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
1030 SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, attPowerMultiplier);
1032 //automatically update weapon damage after attack power modification
1033 UpdateDamagePhysical(BASE_ATTACK);
1036 void Pet::UpdateDamagePhysical(WeaponAttackType attType)
1038 if(attType > BASE_ATTACK)
1039 return;
1041 UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND;
1043 float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f;
1045 float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
1046 float base_pct = GetModifierValue(unitMod, BASE_PCT);
1047 float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
1048 float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
1050 float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
1051 float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
1053 float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct;
1054 float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct;
1056 // Pet's base damage changes depending on happiness
1057 if (getPetType() == HUNTER_PET && attType == BASE_ATTACK)
1059 switch(GetHappinessState())
1061 case HAPPY:
1062 // 125% of normal damage
1063 mindamage = mindamage * 1.25;
1064 maxdamage = maxdamage * 1.25;
1065 break;
1066 case CONTENT:
1067 // 100% of normal damage, nothing to modify
1068 break;
1069 case UNHAPPY:
1070 // 75% of normal damage
1071 mindamage = mindamage * 0.75;
1072 maxdamage = maxdamage * 0.75;
1073 break;
1077 SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage);
1078 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage);