[6922] Whitespace and newline fixes
[getmangos.git] / src / game / StatSystem.cpp
blobd94e68fef164c5fc49be0e2f2d5fdee8cdb67780
1 /*
2 * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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 UpdateAttackPowerAndDamage();
53 UpdateShieldBlockValue();
54 break;
55 case STAT_AGILITY:
56 UpdateArmor();
57 UpdateAttackPowerAndDamage(true);
58 if(getClass() == CLASS_ROGUE || getClass() == CLASS_HUNTER || getClass() == CLASS_DRUID && m_form==FORM_CAT)
59 UpdateAttackPowerAndDamage();
61 UpdateAllCritPercentages();
62 UpdateDodgePercentage();
63 break;
65 case STAT_STAMINA: UpdateMaxHealth(); break;
66 case STAT_INTELLECT:
67 UpdateMaxPower(POWER_MANA);
68 UpdateAllSpellCritChances();
69 UpdateAttackPowerAndDamage(true); //SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT, only intelect currently
70 UpdateArmor(); //SPELL_AURA_MOD_RESISTANCE_OF_INTELLECT_PERCENT, only armor currently
71 break;
73 case STAT_SPIRIT:
74 break;
76 default:
77 break;
79 UpdateSpellDamageAndHealingBonus();
80 UpdateManaRegen();
81 return true;
84 void Player::UpdateSpellDamageAndHealingBonus()
86 // Magic damage modifiers implemented in Unit::SpellDamageBonus
87 // This information for client side use only
88 // Get healing bonus for all schools
89 SetStatInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, SpellBaseHealingBonus(SPELL_SCHOOL_MASK_ALL));
90 // Get damage bonus for all schools
91 for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
92 SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, SpellBaseDamageBonus(SpellSchoolMask(1 << i)));
95 bool Player::UpdateAllStats()
97 for (int i = STAT_STRENGTH; i < MAX_STATS; i++)
99 float value = GetTotalStatValue(Stats(i));
100 SetStat(Stats(i), (int32)value);
103 UpdateAttackPowerAndDamage();
104 UpdateAttackPowerAndDamage(true);
105 UpdateArmor();
106 UpdateMaxHealth();
108 for(int i = POWER_MANA; i < MAX_POWERS; i++)
109 UpdateMaxPower(Powers(i));
111 UpdateAllCritPercentages();
112 UpdateAllSpellCritChances();
113 UpdateDefenseBonusesMod();
114 UpdateShieldBlockValue();
115 UpdateSpellDamageAndHealingBonus();
116 UpdateManaRegen();
117 UpdateExpertise(BASE_ATTACK);
118 UpdateExpertise(OFF_ATTACK);
119 for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
120 UpdateResistances(i);
122 return true;
125 void Player::UpdateResistances(uint32 school)
127 if(school > SPELL_SCHOOL_NORMAL)
129 float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school));
130 SetResistance(SpellSchools(school), int32(value));
132 Pet *pet = GetPet();
133 if(pet)
134 pet->UpdateResistances(school);
136 else
137 UpdateArmor();
140 void Player::UpdateArmor()
142 float value = 0.0f;
143 UnitMods unitMod = UNIT_MOD_ARMOR;
145 value = GetModifierValue(unitMod, BASE_VALUE); // base armor (from items)
146 value *= GetModifierValue(unitMod, BASE_PCT); // armor percent from items
147 value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats
148 value += GetModifierValue(unitMod, TOTAL_VALUE);
150 //add dynamic flat mods
151 AuraList const& mResbyIntellect = GetAurasByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT);
152 for(AuraList::const_iterator i = mResbyIntellect.begin();i != mResbyIntellect.end(); ++i)
154 Modifier* mod = (*i)->GetModifier();
155 if(mod->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL)
156 value += int32(GetStat(Stats((*i)->GetMiscBValue())) * mod->m_amount / 100.0f);
159 value *= GetModifierValue(unitMod, TOTAL_PCT);
161 SetArmor(int32(value));
163 Pet *pet = GetPet();
164 if(pet)
165 pet->UpdateArmor();
168 float Player::GetHealthBonusFromStamina()
170 float stamina = GetStat(STAT_STAMINA);
172 float baseStam = stamina < 20 ? stamina : 20;
173 float moreStam = stamina - baseStam;
175 return baseStam + (moreStam*10.0f);
178 float Player::GetManaBonusFromIntellect()
180 float intellect = GetStat(STAT_INTELLECT);
182 float baseInt = intellect < 20 ? intellect : 20;
183 float moreInt = intellect - baseInt;
185 return baseInt + (moreInt*15.0f);
188 void Player::UpdateMaxHealth()
190 UnitMods unitMod = UNIT_MOD_HEALTH;
192 float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
193 value *= GetModifierValue(unitMod, BASE_PCT);
194 value += GetModifierValue(unitMod, TOTAL_VALUE) + GetHealthBonusFromStamina();
195 value *= GetModifierValue(unitMod, TOTAL_PCT);
197 SetMaxHealth((uint32)value);
200 void Player::UpdateMaxPower(Powers power)
202 UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
204 float bonusPower = (power == POWER_MANA) ? GetManaBonusFromIntellect() : 0;
206 float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
207 value *= GetModifierValue(unitMod, BASE_PCT);
208 value += GetModifierValue(unitMod, TOTAL_VALUE) + bonusPower;
209 value *= GetModifierValue(unitMod, TOTAL_PCT);
211 SetMaxPower(power, uint32(value));
214 void Player::UpdateAttackPowerAndDamage(bool ranged )
216 float val2 = 0.0f;
217 float level = float(getLevel());
219 UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER;
221 uint16 index = UNIT_FIELD_ATTACK_POWER;
222 uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MODS;
223 uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER;
225 if(ranged)
227 index = UNIT_FIELD_RANGED_ATTACK_POWER;
228 index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS;
229 index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER;
231 switch(getClass())
233 case CLASS_HUNTER: val2 = level * 2.0f + GetStat(STAT_AGILITY) - 10.0f; break;
234 case CLASS_ROGUE: val2 = level + GetStat(STAT_AGILITY) - 10.0f; break;
235 case CLASS_WARRIOR:val2 = level + GetStat(STAT_AGILITY) - 10.0f; break;
236 case CLASS_DRUID:
237 switch(m_form)
239 case FORM_CAT:
240 case FORM_BEAR:
241 case FORM_DIREBEAR:
242 val2 = 0.0f; break;
243 default:
244 val2 = GetStat(STAT_AGILITY) - 10.0f; break;
246 break;
247 default: val2 = GetStat(STAT_AGILITY) - 10.0f; break;
250 else
252 switch(getClass())
254 case CLASS_WARRIOR: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
255 case CLASS_PALADIN: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
256 case CLASS_ROGUE: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break;
257 case CLASS_HUNTER: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break;
258 case CLASS_SHAMAN: val2 = level*2.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
259 case CLASS_DRUID:
261 //Check if Predatory Strikes is skilled
262 float mLevelMult = 0.0;
263 switch(m_form)
265 case FORM_CAT:
266 case FORM_BEAR:
267 case FORM_DIREBEAR:
268 case FORM_MOONKIN:
270 Unit::AuraList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY);
271 for(Unit::AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
273 // Predatory Strikes
274 if ((*itr)->GetSpellProto()->SpellIconID == 1563)
276 mLevelMult = (*itr)->GetModifier()->m_amount / 100.0f;
277 break;
280 break;
284 switch(m_form)
286 case FORM_CAT:
287 val2 = getLevel()*(mLevelMult+2.0f) + GetStat(STAT_STRENGTH)*2.0f + GetStat(STAT_AGILITY) - 20.0f; break;
288 case FORM_BEAR:
289 case FORM_DIREBEAR:
290 val2 = getLevel()*(mLevelMult+3.0f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
291 case FORM_MOONKIN:
292 val2 = getLevel()*(mLevelMult+1.5f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
293 default:
294 val2 = GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
296 break;
298 case CLASS_MAGE: val2 = GetStat(STAT_STRENGTH) - 10.0f; break;
299 case CLASS_PRIEST: val2 = GetStat(STAT_STRENGTH) - 10.0f; break;
300 case CLASS_WARLOCK: val2 = GetStat(STAT_STRENGTH) - 10.0f; break;
304 SetModifierValue(unitMod, BASE_VALUE, val2);
306 float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
307 float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
309 //add dynamic flat mods
310 if( ranged && (getClassMask() & CLASSMASK_WAND_USERS)==0)
312 AuraList const& mRAPbyIntellect = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT);
313 for(AuraList::const_iterator i = mRAPbyIntellect.begin();i != mRAPbyIntellect.end(); ++i)
314 attPowerMod += int32(GetStat(Stats((*i)->GetModifier()->m_miscvalue)) * (*i)->GetModifier()->m_amount / 100.0f);
317 float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
319 SetUInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
320 SetUInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
321 SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
323 //automatically update weapon damage after attack power modification
324 if(ranged)
326 UpdateDamagePhysical(RANGED_ATTACK);
328 Pet *pet = GetPet(); //update pet's AP
329 if(pet)
330 pet->UpdateAttackPowerAndDamage();
332 else
334 UpdateDamagePhysical(BASE_ATTACK);
335 if(CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon
336 UpdateDamagePhysical(OFF_ATTACK);
340 void Player::UpdateShieldBlockValue()
342 SetUInt32Value(PLAYER_SHIELD_BLOCK, GetShieldBlockValue());
345 void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, float& min_damage, float& max_damage)
347 UnitMods unitMod;
348 UnitMods attPower;
350 switch(attType)
352 case BASE_ATTACK:
353 default:
354 unitMod = UNIT_MOD_DAMAGE_MAINHAND;
355 attPower = UNIT_MOD_ATTACK_POWER;
356 break;
357 case OFF_ATTACK:
358 unitMod = UNIT_MOD_DAMAGE_OFFHAND;
359 attPower = UNIT_MOD_ATTACK_POWER;
360 break;
361 case RANGED_ATTACK:
362 unitMod = UNIT_MOD_DAMAGE_RANGED;
363 attPower = UNIT_MOD_ATTACK_POWER_RANGED;
364 break;
367 float att_speed = GetAPMultiplier(attType,normalized);
369 float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
370 float base_pct = GetModifierValue(unitMod, BASE_PCT);
371 float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
372 float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
374 float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE);
375 float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE);
377 if (IsInFeralForm()) //check if player is druid and in cat or bear forms
379 uint32 lvl = getLevel();
380 if ( lvl > 60 ) lvl = 60;
382 weapon_mindamage = lvl*0.85*att_speed;
383 weapon_maxdamage = lvl*1.25*att_speed;
385 else if(!IsUseEquipedWeapon(attType==BASE_ATTACK)) //check if player not in form but still can't use weapon (broken/etc)
387 weapon_mindamage = BASE_MINDAMAGE;
388 weapon_maxdamage = BASE_MAXDAMAGE;
390 else if(attType == RANGED_ATTACK) //add ammo DPS to ranged damage
392 weapon_mindamage += GetAmmoDPS() * att_speed;
393 weapon_maxdamage += GetAmmoDPS() * att_speed;
396 min_damage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct;
397 max_damage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct;
400 void Player::UpdateDamagePhysical(WeaponAttackType attType)
402 float mindamage;
403 float maxdamage;
405 CalculateMinMaxDamage(attType,false,mindamage,maxdamage);
407 switch(attType)
409 case BASE_ATTACK:
410 default:
411 SetStatFloatValue(UNIT_FIELD_MINDAMAGE,mindamage);
412 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE,maxdamage);
413 break;
414 case OFF_ATTACK:
415 SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE,mindamage);
416 SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE,maxdamage);
417 break;
418 case RANGED_ATTACK:
419 SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE,mindamage);
420 SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE,maxdamage);
421 break;
425 void Player::UpdateDefenseBonusesMod()
427 UpdateBlockPercentage();
428 UpdateParryPercentage();
429 UpdateDodgePercentage();
432 void Player::UpdateBlockPercentage()
434 // No block
435 float value = 0.0f;
436 if(CanBlock())
438 // Base value
439 value = 5.0f;
440 // Modify value from defense skill
441 value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
442 // Increase from SPELL_AURA_MOD_BLOCK_PERCENT aura
443 value += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT);
444 // Increase from rating
445 value += GetRatingBonusValue(CR_BLOCK);
446 value = value < 0.0f ? 0.0f : value;
448 SetStatFloatValue(PLAYER_BLOCK_PERCENTAGE, value);
451 void Player::UpdateCritPercentage(WeaponAttackType attType)
453 BaseModGroup modGroup;
454 uint16 index;
455 CombatRating cr;
457 switch(attType)
459 case OFF_ATTACK:
460 modGroup = OFFHAND_CRIT_PERCENTAGE;
461 index = PLAYER_OFFHAND_CRIT_PERCENTAGE;
462 cr = CR_CRIT_MELEE;
463 break;
464 case RANGED_ATTACK:
465 modGroup = RANGED_CRIT_PERCENTAGE;
466 index = PLAYER_RANGED_CRIT_PERCENTAGE;
467 cr = CR_CRIT_RANGED;
468 break;
469 case BASE_ATTACK:
470 default:
471 modGroup = CRIT_PERCENTAGE;
472 index = PLAYER_CRIT_PERCENTAGE;
473 cr = CR_CRIT_MELEE;
474 break;
477 float value = GetTotalPercentageModValue(modGroup) + GetRatingBonusValue(cr);
478 // Modify crit from weapon skill and maximized defense skill of same level victim difference
479 value += (int32(GetWeaponSkillValue(attType)) - int32(GetMaxSkillValueForLevel())) * 0.04f;
480 value = value < 0.0f ? 0.0f : value;
481 SetStatFloatValue(index, value);
484 void Player::UpdateAllCritPercentages()
486 float value = GetMeleeCritFromAgility();
488 SetBaseModValue(CRIT_PERCENTAGE, PCT_MOD, value);
489 SetBaseModValue(OFFHAND_CRIT_PERCENTAGE, PCT_MOD, value);
490 SetBaseModValue(RANGED_CRIT_PERCENTAGE, PCT_MOD, value);
492 UpdateCritPercentage(BASE_ATTACK);
493 UpdateCritPercentage(OFF_ATTACK);
494 UpdateCritPercentage(RANGED_ATTACK);
497 void Player::UpdateParryPercentage()
499 // No parry
500 float value = 0.0f;
501 if (CanParry())
503 // Base parry
504 value = 5.0f;
505 // Modify value from defense skill
506 value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
507 // Parry from SPELL_AURA_MOD_PARRY_PERCENT aura
508 value += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT);
509 // Parry from rating
510 value += GetRatingBonusValue(CR_PARRY);
511 value = value < 0.0f ? 0.0f : value;
513 SetStatFloatValue(PLAYER_PARRY_PERCENTAGE, value);
516 void Player::UpdateDodgePercentage()
518 // Dodge from agility
519 float value = GetDodgeFromAgility();
520 // Modify value from defense skill
521 value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
522 // Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura
523 value += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT);
524 // Dodge from rating
525 value += GetRatingBonusValue(CR_DODGE);
526 value = value < 0.0f ? 0.0f : value;
527 SetStatFloatValue(PLAYER_DODGE_PERCENTAGE, value);
530 void Player::UpdateSpellCritChance(uint32 school)
532 // For normal school set zero crit chance
533 if(school == SPELL_SCHOOL_NORMAL)
535 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1, 0.0f);
536 return;
538 // For others recalculate it from:
539 float crit = 0.0f;
540 // Crit from Intellect
541 crit += GetSpellCritFromIntellect();
542 // Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE
543 crit += GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE);
544 // Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
545 crit += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, 1<<school);
546 // Increase crit from spell crit ratings
547 crit += GetRatingBonusValue(CR_CRIT_SPELL);
549 // Store crit value
550 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1 + school, crit);
553 void Player::UpdateAllSpellCritChances()
555 for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
556 UpdateSpellCritChance(i);
559 void Player::UpdateExpertise(WeaponAttackType attack)
561 if(attack==RANGED_ATTACK)
562 return;
564 int32 expertise = int32(GetRatingBonusValue(CR_EXPERTISE));
566 Item *weapon = GetWeaponForAttack(attack);
568 AuraList const& expAuras = GetAurasByType(SPELL_AURA_MOD_EXPERTISE);
569 for(AuraList::const_iterator itr = expAuras.begin(); itr != expAuras.end(); ++itr)
571 // item neutral spell
572 if((*itr)->GetSpellProto()->EquippedItemClass == -1)
573 expertise += (*itr)->GetModifier()->m_amount;
574 // item dependent spell
575 else if(weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellProto()))
576 expertise += (*itr)->GetModifier()->m_amount;
579 if(expertise < 0)
580 expertise = 0;
582 switch(attack)
584 case BASE_ATTACK: SetUInt32Value(PLAYER_EXPERTISE, expertise); break;
585 case OFF_ATTACK: SetUInt32Value(PLAYER_OFFHAND_EXPERTISE, expertise); break;
586 default: break;
590 void Player::UpdateManaRegen()
592 float Intellect = GetStat(STAT_INTELLECT);
593 // Mana regen from spirit and intellect
594 float power_regen = sqrt(Intellect) * OCTRegenMPPerSpirit();
595 // Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen
596 power_regen *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, POWER_MANA);
598 // Mana regen from SPELL_AURA_MOD_POWER_REGEN aura
599 float power_regen_mp5 = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) / 5.0f;
601 // Get bonus from SPELL_AURA_MOD_MANA_REGEN_FROM_STAT aura
602 AuraList const& regenAura = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_FROM_STAT);
603 for(AuraList::const_iterator i = regenAura.begin();i != regenAura.end(); ++i)
605 Modifier* mod = (*i)->GetModifier();
606 power_regen_mp5 += GetStat(Stats(mod->m_miscvalue)) * mod->m_amount / 500.0f;
609 // Bonus from some dummy auras
610 AuraList const& mDummyAuras = GetAurasByType(SPELL_AURA_PERIODIC_DUMMY);
611 for(AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
612 if((*i)->GetId() == 34074) // Aspect of the Viper
614 power_regen_mp5 += (*i)->GetModifier()->m_amount * Intellect / 500.0f;
615 // Add regen bonus from level in this dummy
616 power_regen_mp5 += getLevel() * 35 / 100;
619 // Set regen rate in cast state apply only on spirit based regen
620 int32 modManaRegenInterrupt = GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
621 if (modManaRegenInterrupt > 100)
622 modManaRegenInterrupt = 100;
623 SetStatFloatValue(PLAYER_FIELD_MOD_MANA_REGEN_INTERRUPT, power_regen_mp5 + power_regen * modManaRegenInterrupt / 100.0f);
625 SetStatFloatValue(PLAYER_FIELD_MOD_MANA_REGEN, power_regen_mp5 + power_regen);
628 void Player::_ApplyAllStatBonuses()
630 SetCanModifyStats(false);
632 _ApplyAllAuraMods();
633 _ApplyAllItemMods();
635 SetCanModifyStats(true);
637 UpdateAllStats();
640 void Player::_RemoveAllStatBonuses()
642 SetCanModifyStats(false);
644 _RemoveAllItemMods();
645 _RemoveAllAuraMods();
647 SetCanModifyStats(true);
649 UpdateAllStats();
652 /*#######################################
653 ######## ########
654 ######## MOBS STAT SYSTEM ########
655 ######## ########
656 #######################################*/
658 bool Creature::UpdateStats(Stats /*stat*/)
660 return true;
663 bool Creature::UpdateAllStats()
665 UpdateMaxHealth();
666 UpdateAttackPowerAndDamage();
668 for(int i = POWER_MANA; i < MAX_POWERS; ++i)
669 UpdateMaxPower(Powers(i));
671 for(int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
672 UpdateResistances(i);
674 return true;
677 void Creature::UpdateResistances(uint32 school)
679 if(school > SPELL_SCHOOL_NORMAL)
681 float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school));
682 SetResistance(SpellSchools(school), int32(value));
684 else
685 UpdateArmor();
688 void Creature::UpdateArmor()
690 float value = GetTotalAuraModValue(UNIT_MOD_ARMOR);
691 SetArmor(int32(value));
694 void Creature::UpdateMaxHealth()
696 float value = GetTotalAuraModValue(UNIT_MOD_HEALTH);
697 SetMaxHealth((uint32)value);
700 void Creature::UpdateMaxPower(Powers power)
702 UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
704 float value = GetTotalAuraModValue(unitMod);
705 SetMaxPower(power, uint32(value));
708 void Creature::UpdateAttackPowerAndDamage(bool ranged)
710 if(ranged)
711 return;
713 //automatically update weapon damage after attack power modification
714 UpdateDamagePhysical(BASE_ATTACK);
717 void Creature::UpdateDamagePhysical(WeaponAttackType attType)
719 if(attType > BASE_ATTACK)
720 return;
722 UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND;
724 float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f;
726 float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
727 float base_pct = GetModifierValue(unitMod, BASE_PCT);
728 float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
729 float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
731 float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
732 float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
734 float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct ;
735 float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct ;
737 SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage);
738 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage);
741 /*#######################################
742 ######## ########
743 ######## PETS STAT SYSTEM ########
744 ######## ########
745 #######################################*/
747 bool Pet::UpdateStats(Stats stat)
749 if(stat > STAT_SPIRIT)
750 return false;
752 // value = ((base_value * base_pct) + total_value) * total_pct
753 float value = GetTotalStatValue(stat);
755 Unit *owner = GetOwner();
756 if ( stat == STAT_STAMINA )
758 if(owner)
759 value += float(owner->GetStat(stat)) * 0.3f;
761 //warlock's and mage's pets gain 30% of owner's intellect
762 else if ( stat == STAT_INTELLECT && getPetType() == SUMMON_PET )
764 if(owner && (owner->getClass() == CLASS_WARLOCK || owner->getClass() == CLASS_MAGE) )
765 value += float(owner->GetStat(stat)) * 0.3f;
768 SetStat(stat, int32(value));
770 switch(stat)
772 case STAT_STRENGTH: UpdateAttackPowerAndDamage(); break;
773 case STAT_AGILITY: UpdateArmor(); break;
774 case STAT_STAMINA: UpdateMaxHealth(); break;
775 case STAT_INTELLECT: UpdateMaxPower(POWER_MANA); break;
776 case STAT_SPIRIT:
777 default:
778 break;
781 return true;
784 bool Pet::UpdateAllStats()
786 for (int i = STAT_STRENGTH; i < MAX_STATS; i++)
787 UpdateStats(Stats(i));
789 for(int i = POWER_MANA; i < MAX_POWERS; i++)
790 UpdateMaxPower(Powers(i));
792 for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
793 UpdateResistances(i);
795 return true;
798 void Pet::UpdateResistances(uint32 school)
800 if(school > SPELL_SCHOOL_NORMAL)
802 float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school));
804 Unit *owner = GetOwner();
805 // hunter and warlock pets gain 40% of owner's resistance
806 if(owner && (getPetType() == HUNTER_PET || getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK))
807 value += float(owner->GetResistance(SpellSchools(school))) * 0.4f;
809 SetResistance(SpellSchools(school), int32(value));
811 else
812 UpdateArmor();
815 void Pet::UpdateArmor()
817 float value = 0.0f;
818 float bonus_armor = 0.0f;
819 UnitMods unitMod = UNIT_MOD_ARMOR;
821 Unit *owner = GetOwner();
822 // hunter and warlock pets gain 35% of owner's armor value
823 if(owner && (getPetType() == HUNTER_PET || getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK))
824 bonus_armor = 0.35f * float(owner->GetArmor());
826 value = GetModifierValue(unitMod, BASE_VALUE);
827 value *= GetModifierValue(unitMod, BASE_PCT);
828 value += GetStat(STAT_AGILITY) * 2.0f;
829 value += GetModifierValue(unitMod, TOTAL_VALUE) + bonus_armor;
830 value *= GetModifierValue(unitMod, TOTAL_PCT);
832 SetArmor(int32(value));
835 void Pet::UpdateMaxHealth()
837 UnitMods unitMod = UNIT_MOD_HEALTH;
838 float stamina = GetStat(STAT_STAMINA) - GetCreateStat(STAT_STAMINA);
840 float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
841 value *= GetModifierValue(unitMod, BASE_PCT);
842 value += GetModifierValue(unitMod, TOTAL_VALUE) + stamina * 10.0f;
843 value *= GetModifierValue(unitMod, TOTAL_PCT);
845 SetMaxHealth((uint32)value);
848 void Pet::UpdateMaxPower(Powers power)
850 UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
852 float addValue = (power == POWER_MANA) ? GetStat(STAT_INTELLECT) - GetCreateStat(STAT_INTELLECT) : 0.0f;
854 float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
855 value *= GetModifierValue(unitMod, BASE_PCT);
856 value += GetModifierValue(unitMod, TOTAL_VALUE) + addValue * 15.0f;
857 value *= GetModifierValue(unitMod, TOTAL_PCT);
859 SetMaxPower(power, uint32(value));
862 void Pet::UpdateAttackPowerAndDamage(bool ranged)
864 if(ranged)
865 return;
867 float val = 0.0f;
868 float bonusAP = 0.0f;
869 UnitMods unitMod = UNIT_MOD_ATTACK_POWER;
871 if(GetEntry() == 416) // imp's attack power
872 val = GetStat(STAT_STRENGTH) - 10.0f;
873 else
874 val = 2 * GetStat(STAT_STRENGTH) - 20.0f;
876 Unit* owner = GetOwner();
877 if( owner && owner->GetTypeId()==TYPEID_PLAYER)
879 if(getPetType() == HUNTER_PET) //hunter pets benefit from owner's attack power
881 bonusAP = owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.22f;
882 SetBonusDamage( int32(owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.125f));
884 //demons benefit from warlocks shadow or fire damage
885 else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK)
887 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);
888 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);
889 int32 maximum = (fire > shadow) ? fire : shadow;
890 if(maximum < 0)
891 maximum = 0;
892 SetBonusDamage( int32(maximum * 0.15f));
893 bonusAP = maximum * 0.57f;
895 //water elementals benefit from mage's frost damage
896 else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_MAGE)
898 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);
899 if(frost < 0)
900 frost = 0;
901 SetBonusDamage( int32(frost * 0.4f));
905 SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, val + bonusAP);
907 //in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB
908 float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
909 float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
910 float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
912 //UNIT_FIELD_(RANGED)_ATTACK_POWER field
913 SetUInt32Value(UNIT_FIELD_ATTACK_POWER, (uint32)base_attPower);
914 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
915 SetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (uint32)attPowerMod);
916 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
917 SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, attPowerMultiplier);
919 //automatically update weapon damage after attack power modification
920 UpdateDamagePhysical(BASE_ATTACK);
923 void Pet::UpdateDamagePhysical(WeaponAttackType attType)
925 if(attType > BASE_ATTACK)
926 return;
928 UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND;
930 float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f;
932 float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
933 float base_pct = GetModifierValue(unitMod, BASE_PCT);
934 float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
935 float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
937 float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
938 float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
940 float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct;
941 float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct;
943 // Pet's base damage changes depending on happiness
944 if (getPetType() == HUNTER_PET && attType == BASE_ATTACK)
946 switch(GetHappinessState())
948 case HAPPY:
949 // 125% of normal damage
950 mindamage = mindamage * 1.25;
951 maxdamage = maxdamage * 1.25;
952 break;
953 case CONTENT:
954 // 100% of normal damage, nothing to modify
955 break;
956 case UNHAPPY:
957 // 75% of normal damage
958 mindamage = mindamage * 0.75;
959 maxdamage = maxdamage * 0.75;
960 break;
964 SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage);
965 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage);