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