[6982] Implemented gmlevel-based command security
[getmangos.git] / src / game / StatSystem.cpp
bloba4127e832d022f1deffefc03f069bf52d630bf98
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 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::UpdateSpellDamageAndHealingBonus()
96 // Magic damage modifiers implemented in Unit::SpellDamageBonus
97 // This information for client side use only
98 // Get healing bonus for all schools
99 SetStatInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, SpellBaseHealingBonus(SPELL_SCHOOL_MASK_ALL));
100 // Get damage bonus for all schools
101 for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
102 SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, SpellBaseDamageBonus(SpellSchoolMask(1 << i)));
105 bool Player::UpdateAllStats()
107 for (int i = STAT_STRENGTH; i < MAX_STATS; i++)
109 float value = GetTotalStatValue(Stats(i));
110 SetStat(Stats(i), (int32)value);
113 UpdateAttackPowerAndDamage();
114 UpdateAttackPowerAndDamage(true);
115 UpdateArmor();
116 UpdateMaxHealth();
118 for(int i = POWER_MANA; i < MAX_POWERS; i++)
119 UpdateMaxPower(Powers(i));
121 UpdateAllCritPercentages();
122 UpdateAllSpellCritChances();
123 UpdateDefenseBonusesMod();
124 UpdateShieldBlockValue();
125 UpdateSpellDamageAndHealingBonus();
126 UpdateManaRegen();
127 UpdateExpertise(BASE_ATTACK);
128 UpdateExpertise(OFF_ATTACK);
129 for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
130 UpdateResistances(i);
132 return true;
135 void Player::UpdateResistances(uint32 school)
137 if(school > SPELL_SCHOOL_NORMAL)
139 float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school));
140 SetResistance(SpellSchools(school), int32(value));
142 Pet *pet = GetPet();
143 if(pet)
144 pet->UpdateResistances(school);
146 else
147 UpdateArmor();
150 void Player::UpdateArmor()
152 float value = 0.0f;
153 UnitMods unitMod = UNIT_MOD_ARMOR;
155 value = GetModifierValue(unitMod, BASE_VALUE); // base armor (from items)
156 value *= GetModifierValue(unitMod, BASE_PCT); // armor percent from items
157 value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats
158 value += GetModifierValue(unitMod, TOTAL_VALUE);
160 //add dynamic flat mods
161 AuraList const& mResbyIntellect = GetAurasByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT);
162 for(AuraList::const_iterator i = mResbyIntellect.begin();i != mResbyIntellect.end(); ++i)
164 Modifier* mod = (*i)->GetModifier();
165 if(mod->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL)
166 value += int32(GetStat(Stats((*i)->GetMiscBValue())) * mod->m_amount / 100.0f);
169 value *= GetModifierValue(unitMod, TOTAL_PCT);
171 SetArmor(int32(value));
173 Pet *pet = GetPet();
174 if(pet)
175 pet->UpdateArmor();
178 float Player::GetHealthBonusFromStamina()
180 float stamina = GetStat(STAT_STAMINA);
182 float baseStam = stamina < 20 ? stamina : 20;
183 float moreStam = stamina - baseStam;
185 return baseStam + (moreStam*10.0f);
188 float Player::GetManaBonusFromIntellect()
190 float intellect = GetStat(STAT_INTELLECT);
192 float baseInt = intellect < 20 ? intellect : 20;
193 float moreInt = intellect - baseInt;
195 return baseInt + (moreInt*15.0f);
198 void Player::UpdateMaxHealth()
200 UnitMods unitMod = UNIT_MOD_HEALTH;
202 float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
203 value *= GetModifierValue(unitMod, BASE_PCT);
204 value += GetModifierValue(unitMod, TOTAL_VALUE) + GetHealthBonusFromStamina();
205 value *= GetModifierValue(unitMod, TOTAL_PCT);
207 SetMaxHealth((uint32)value);
210 void Player::UpdateMaxPower(Powers power)
212 UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
214 float bonusPower = (power == POWER_MANA) ? GetManaBonusFromIntellect() : 0;
216 float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
217 value *= GetModifierValue(unitMod, BASE_PCT);
218 value += GetModifierValue(unitMod, TOTAL_VALUE) + bonusPower;
219 value *= GetModifierValue(unitMod, TOTAL_PCT);
221 SetMaxPower(power, uint32(value));
224 void Player::UpdateAttackPowerAndDamage(bool ranged )
226 float val2 = 0.0f;
227 float level = float(getLevel());
229 UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER;
231 uint16 index = UNIT_FIELD_ATTACK_POWER;
232 uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MODS;
233 uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER;
235 if(ranged)
237 index = UNIT_FIELD_RANGED_ATTACK_POWER;
238 index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS;
239 index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER;
241 switch(getClass())
243 case CLASS_HUNTER: val2 = level * 2.0f + GetStat(STAT_AGILITY) - 10.0f; break;
244 case CLASS_ROGUE: val2 = level + GetStat(STAT_AGILITY) - 10.0f; break;
245 case CLASS_WARRIOR:val2 = level + GetStat(STAT_AGILITY) - 10.0f; break;
246 case CLASS_DRUID:
247 switch(m_form)
249 case FORM_CAT:
250 case FORM_BEAR:
251 case FORM_DIREBEAR:
252 val2 = 0.0f; break;
253 default:
254 val2 = GetStat(STAT_AGILITY) - 10.0f; break;
256 break;
257 default: val2 = GetStat(STAT_AGILITY) - 10.0f; break;
260 else
262 switch(getClass())
264 case CLASS_WARRIOR: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
265 case CLASS_PALADIN: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
266 case CLASS_DEATH_KNIGHT: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
267 case CLASS_ROGUE: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break;
268 case CLASS_HUNTER: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break;
269 case CLASS_SHAMAN: val2 = level*2.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
270 case CLASS_DRUID:
272 //Check if Predatory Strikes is skilled
273 float mLevelMult = 0.0;
274 switch(m_form)
276 case FORM_CAT:
277 case FORM_BEAR:
278 case FORM_DIREBEAR:
279 case FORM_MOONKIN:
281 Unit::AuraList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY);
282 for(Unit::AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
284 // Predatory Strikes
285 if ((*itr)->GetSpellProto()->SpellIconID == 1563)
287 mLevelMult = (*itr)->GetModifier()->m_amount / 100.0f;
288 break;
291 break;
295 switch(m_form)
297 case FORM_CAT:
298 val2 = getLevel()*(mLevelMult+2.0f) + GetStat(STAT_STRENGTH)*2.0f + GetStat(STAT_AGILITY) - 20.0f; break;
299 case FORM_BEAR:
300 case FORM_DIREBEAR:
301 val2 = getLevel()*(mLevelMult+3.0f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
302 case FORM_MOONKIN:
303 val2 = getLevel()*(mLevelMult+1.5f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
304 default:
305 val2 = GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
307 break;
309 case CLASS_MAGE: val2 = GetStat(STAT_STRENGTH) - 10.0f; break;
310 case CLASS_PRIEST: val2 = GetStat(STAT_STRENGTH) - 10.0f; break;
311 case CLASS_WARLOCK: val2 = GetStat(STAT_STRENGTH) - 10.0f; break;
315 SetModifierValue(unitMod, BASE_VALUE, val2);
317 float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
318 float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
320 //add dynamic flat mods
321 if ((getClassMask() & CLASSMASK_WAND_USERS)==0)
323 if( ranged )
325 AuraList const& mRAPbyIntellect = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT);
326 for(AuraList::const_iterator i = mRAPbyIntellect.begin();i != mRAPbyIntellect.end(); ++i)
327 attPowerMod += int32(GetStat(Stats((*i)->GetModifier()->m_miscvalue)) * (*i)->GetModifier()->m_amount / 100.0f);
329 else
331 AuraList const& mRAPbyIntellect = GetAurasByType(SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT);
332 for(AuraList::const_iterator i = mRAPbyIntellect.begin();i != mRAPbyIntellect.end(); ++i)
333 attPowerMod += int32(GetStat(Stats((*i)->GetModifier()->m_miscvalue)) * (*i)->GetModifier()->m_amount / 100.0f);
337 float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
339 SetUInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
340 SetUInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
341 SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
343 //automatically update weapon damage after attack power modification
344 if(ranged)
346 UpdateDamagePhysical(RANGED_ATTACK);
348 Pet *pet = GetPet(); //update pet's AP
349 if(pet)
350 pet->UpdateAttackPowerAndDamage();
352 else
354 UpdateDamagePhysical(BASE_ATTACK);
355 if(CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon
356 UpdateDamagePhysical(OFF_ATTACK);
360 void Player::UpdateShieldBlockValue()
362 SetUInt32Value(PLAYER_SHIELD_BLOCK, GetShieldBlockValue());
365 void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, float& min_damage, float& max_damage)
367 UnitMods unitMod;
368 UnitMods attPower;
370 switch(attType)
372 case BASE_ATTACK:
373 default:
374 unitMod = UNIT_MOD_DAMAGE_MAINHAND;
375 attPower = UNIT_MOD_ATTACK_POWER;
376 break;
377 case OFF_ATTACK:
378 unitMod = UNIT_MOD_DAMAGE_OFFHAND;
379 attPower = UNIT_MOD_ATTACK_POWER;
380 break;
381 case RANGED_ATTACK:
382 unitMod = UNIT_MOD_DAMAGE_RANGED;
383 attPower = UNIT_MOD_ATTACK_POWER_RANGED;
384 break;
387 float att_speed = GetAPMultiplier(attType,normalized);
389 float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
390 float base_pct = GetModifierValue(unitMod, BASE_PCT);
391 float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
392 float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
394 float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE);
395 float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE);
397 if (IsInFeralForm()) //check if player is druid and in cat or bear forms
399 uint32 lvl = getLevel();
400 if ( lvl > 60 ) lvl = 60;
402 weapon_mindamage = lvl*0.85*att_speed;
403 weapon_maxdamage = lvl*1.25*att_speed;
405 else if(!IsUseEquipedWeapon(attType==BASE_ATTACK)) //check if player not in form but still can't use weapon (broken/etc)
407 weapon_mindamage = BASE_MINDAMAGE;
408 weapon_maxdamage = BASE_MAXDAMAGE;
410 else if(attType == RANGED_ATTACK) //add ammo DPS to ranged damage
412 weapon_mindamage += GetAmmoDPS() * att_speed;
413 weapon_maxdamage += GetAmmoDPS() * att_speed;
416 min_damage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct;
417 max_damage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct;
420 void Player::UpdateDamagePhysical(WeaponAttackType attType)
422 float mindamage;
423 float maxdamage;
425 CalculateMinMaxDamage(attType,false,mindamage,maxdamage);
427 switch(attType)
429 case BASE_ATTACK:
430 default:
431 SetStatFloatValue(UNIT_FIELD_MINDAMAGE,mindamage);
432 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE,maxdamage);
433 break;
434 case OFF_ATTACK:
435 SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE,mindamage);
436 SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE,maxdamage);
437 break;
438 case RANGED_ATTACK:
439 SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE,mindamage);
440 SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE,maxdamage);
441 break;
445 void Player::UpdateDefenseBonusesMod()
447 UpdateBlockPercentage();
448 UpdateParryPercentage();
449 UpdateDodgePercentage();
452 void Player::UpdateBlockPercentage()
454 // No block
455 float value = 0.0f;
456 if(CanBlock())
458 // Base value
459 value = 5.0f;
460 // Modify value from defense skill
461 value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
462 // Increase from SPELL_AURA_MOD_BLOCK_PERCENT aura
463 value += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT);
464 // Increase from rating
465 value += GetRatingBonusValue(CR_BLOCK);
466 value = value < 0.0f ? 0.0f : value;
468 SetStatFloatValue(PLAYER_BLOCK_PERCENTAGE, value);
471 void Player::UpdateCritPercentage(WeaponAttackType attType)
473 BaseModGroup modGroup;
474 uint16 index;
475 CombatRating cr;
477 switch(attType)
479 case OFF_ATTACK:
480 modGroup = OFFHAND_CRIT_PERCENTAGE;
481 index = PLAYER_OFFHAND_CRIT_PERCENTAGE;
482 cr = CR_CRIT_MELEE;
483 break;
484 case RANGED_ATTACK:
485 modGroup = RANGED_CRIT_PERCENTAGE;
486 index = PLAYER_RANGED_CRIT_PERCENTAGE;
487 cr = CR_CRIT_RANGED;
488 break;
489 case BASE_ATTACK:
490 default:
491 modGroup = CRIT_PERCENTAGE;
492 index = PLAYER_CRIT_PERCENTAGE;
493 cr = CR_CRIT_MELEE;
494 break;
497 float value = GetTotalPercentageModValue(modGroup) + GetRatingBonusValue(cr);
498 // Modify crit from weapon skill and maximized defense skill of same level victim difference
499 value += (int32(GetWeaponSkillValue(attType)) - int32(GetMaxSkillValueForLevel())) * 0.04f;
500 value = value < 0.0f ? 0.0f : value;
501 SetStatFloatValue(index, value);
504 void Player::UpdateAllCritPercentages()
506 float value = GetMeleeCritFromAgility();
508 SetBaseModValue(CRIT_PERCENTAGE, PCT_MOD, value);
509 SetBaseModValue(OFFHAND_CRIT_PERCENTAGE, PCT_MOD, value);
510 SetBaseModValue(RANGED_CRIT_PERCENTAGE, PCT_MOD, value);
512 UpdateCritPercentage(BASE_ATTACK);
513 UpdateCritPercentage(OFF_ATTACK);
514 UpdateCritPercentage(RANGED_ATTACK);
517 void Player::UpdateParryPercentage()
519 // No parry
520 float value = 0.0f;
521 if (CanParry())
523 // Base parry
524 value = 5.0f;
525 // Modify value from defense skill
526 value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
527 // Parry from SPELL_AURA_MOD_PARRY_PERCENT aura
528 value += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT);
529 // Parry from rating
530 value += GetRatingBonusValue(CR_PARRY);
531 value = value < 0.0f ? 0.0f : value;
533 SetStatFloatValue(PLAYER_PARRY_PERCENTAGE, value);
536 void Player::UpdateDodgePercentage()
538 // Dodge from agility
539 float value = GetDodgeFromAgility();
540 // Modify value from defense skill
541 value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
542 // Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura
543 value += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT);
544 // Dodge from rating
545 value += GetRatingBonusValue(CR_DODGE);
546 value = value < 0.0f ? 0.0f : value;
547 SetStatFloatValue(PLAYER_DODGE_PERCENTAGE, value);
550 void Player::UpdateSpellCritChance(uint32 school)
552 // For normal school set zero crit chance
553 if(school == SPELL_SCHOOL_NORMAL)
555 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1, 0.0f);
556 return;
558 // For others recalculate it from:
559 float crit = 0.0f;
560 // Crit from Intellect
561 crit += GetSpellCritFromIntellect();
562 // Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE
563 crit += GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE);
564 // Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
565 crit += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, 1<<school);
566 // Increase crit from spell crit ratings
567 crit += GetRatingBonusValue(CR_CRIT_SPELL);
569 // Store crit value
570 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1 + school, crit);
573 void Player::UpdateMeleeHitChances()
575 m_modMeleeHitChance = GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE);
576 m_modMeleeHitChance+= GetRatingBonusValue(CR_HIT_MELEE);
579 void Player::UpdateRangedHitChances()
581 m_modRangedHitChance = GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE);
582 m_modRangedHitChance+= GetRatingBonusValue(CR_HIT_RANGED);
585 void Player::UpdateSpellHitChances()
587 m_modSpellHitChance = GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HIT_CHANCE);
588 m_modSpellHitChance+= GetRatingBonusValue(CR_HIT_SPELL);
591 void Player::UpdateAllSpellCritChances()
593 for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
594 UpdateSpellCritChance(i);
597 void Player::UpdateExpertise(WeaponAttackType attack)
599 if(attack==RANGED_ATTACK)
600 return;
602 int32 expertise = int32(GetRatingBonusValue(CR_EXPERTISE));
604 Item *weapon = GetWeaponForAttack(attack);
606 AuraList const& expAuras = GetAurasByType(SPELL_AURA_MOD_EXPERTISE);
607 for(AuraList::const_iterator itr = expAuras.begin(); itr != expAuras.end(); ++itr)
609 // item neutral spell
610 if((*itr)->GetSpellProto()->EquippedItemClass == -1)
611 expertise += (*itr)->GetModifier()->m_amount;
612 // item dependent spell
613 else if(weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellProto()))
614 expertise += (*itr)->GetModifier()->m_amount;
617 if(expertise < 0)
618 expertise = 0;
620 switch(attack)
622 case BASE_ATTACK: SetUInt32Value(PLAYER_EXPERTISE, expertise); break;
623 case OFF_ATTACK: SetUInt32Value(PLAYER_OFFHAND_EXPERTISE, expertise); break;
624 default: break;
628 void Player::UpdateManaRegen()
630 float Intellect = GetStat(STAT_INTELLECT);
631 // Mana regen from spirit and intellect
632 float power_regen = sqrt(Intellect) * OCTRegenMPPerSpirit();
633 // Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen
634 power_regen *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, POWER_MANA);
636 // Mana regen from SPELL_AURA_MOD_POWER_REGEN aura
637 float power_regen_mp5 = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) / 5.0f;
639 // Get bonus from SPELL_AURA_MOD_MANA_REGEN_FROM_STAT aura
640 AuraList const& regenAura = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_FROM_STAT);
641 for(AuraList::const_iterator i = regenAura.begin();i != regenAura.end(); ++i)
643 Modifier* mod = (*i)->GetModifier();
644 power_regen_mp5 += GetStat(Stats(mod->m_miscvalue)) * mod->m_amount / 500.0f;
647 // Bonus from some dummy auras
648 AuraList const& mDummyAuras = GetAurasByType(SPELL_AURA_PERIODIC_DUMMY);
649 for(AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
650 if((*i)->GetId() == 34074) // Aspect of the Viper
652 power_regen_mp5 += (*i)->GetModifier()->m_amount * Intellect / 500.0f;
653 // Add regen bonus from level in this dummy
654 power_regen_mp5 += getLevel() * 35 / 100;
657 // Set regen rate in cast state apply only on spirit based regen
658 int32 modManaRegenInterrupt = GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
659 if (modManaRegenInterrupt > 100)
660 modManaRegenInterrupt = 100;
661 SetStatFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER, power_regen_mp5 + power_regen * modManaRegenInterrupt / 100.0f);
663 SetStatFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER, power_regen_mp5 + power_regen);
666 void Player::_ApplyAllStatBonuses()
668 SetCanModifyStats(false);
670 _ApplyAllAuraMods();
671 _ApplyAllItemMods();
673 SetCanModifyStats(true);
675 UpdateAllStats();
678 void Player::_RemoveAllStatBonuses()
680 SetCanModifyStats(false);
682 _RemoveAllItemMods();
683 _RemoveAllAuraMods();
685 SetCanModifyStats(true);
687 UpdateAllStats();
690 /*#######################################
691 ######## ########
692 ######## MOBS STAT SYSTEM ########
693 ######## ########
694 #######################################*/
696 bool Creature::UpdateStats(Stats /*stat*/)
698 return true;
701 bool Creature::UpdateAllStats()
703 UpdateMaxHealth();
704 UpdateAttackPowerAndDamage();
706 for(int i = POWER_MANA; i < MAX_POWERS; ++i)
707 UpdateMaxPower(Powers(i));
709 for(int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
710 UpdateResistances(i);
712 return true;
715 void Creature::UpdateResistances(uint32 school)
717 if(school > SPELL_SCHOOL_NORMAL)
719 float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school));
720 SetResistance(SpellSchools(school), int32(value));
722 else
723 UpdateArmor();
726 void Creature::UpdateArmor()
728 float value = GetTotalAuraModValue(UNIT_MOD_ARMOR);
729 SetArmor(int32(value));
732 void Creature::UpdateMaxHealth()
734 float value = GetTotalAuraModValue(UNIT_MOD_HEALTH);
735 SetMaxHealth((uint32)value);
738 void Creature::UpdateMaxPower(Powers power)
740 UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
742 float value = GetTotalAuraModValue(unitMod);
743 SetMaxPower(power, uint32(value));
746 void Creature::UpdateAttackPowerAndDamage(bool ranged)
748 if(ranged)
749 return;
751 //automatically update weapon damage after attack power modification
752 UpdateDamagePhysical(BASE_ATTACK);
755 void Creature::UpdateDamagePhysical(WeaponAttackType attType)
757 if(attType > BASE_ATTACK)
758 return;
760 UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND;
762 float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f;
764 float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
765 float base_pct = GetModifierValue(unitMod, BASE_PCT);
766 float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
767 float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
769 float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
770 float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
772 float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct ;
773 float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct ;
775 SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage);
776 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage);
779 /*#######################################
780 ######## ########
781 ######## PETS STAT SYSTEM ########
782 ######## ########
783 #######################################*/
785 bool Pet::UpdateStats(Stats stat)
787 if(stat > STAT_SPIRIT)
788 return false;
790 // value = ((base_value * base_pct) + total_value) * total_pct
791 float value = GetTotalStatValue(stat);
793 Unit *owner = GetOwner();
794 if ( stat == STAT_STAMINA )
796 if(owner)
797 value += float(owner->GetStat(stat)) * 0.3f;
799 //warlock's and mage's pets gain 30% of owner's intellect
800 else if ( stat == STAT_INTELLECT && getPetType() == SUMMON_PET )
802 if(owner && (owner->getClass() == CLASS_WARLOCK || owner->getClass() == CLASS_MAGE) )
803 value += float(owner->GetStat(stat)) * 0.3f;
806 SetStat(stat, int32(value));
808 switch(stat)
810 case STAT_STRENGTH: UpdateAttackPowerAndDamage(); break;
811 case STAT_AGILITY: UpdateArmor(); break;
812 case STAT_STAMINA: UpdateMaxHealth(); break;
813 case STAT_INTELLECT: UpdateMaxPower(POWER_MANA); break;
814 case STAT_SPIRIT:
815 default:
816 break;
819 return true;
822 bool Pet::UpdateAllStats()
824 for (int i = STAT_STRENGTH; i < MAX_STATS; i++)
825 UpdateStats(Stats(i));
827 for(int i = POWER_MANA; i < MAX_POWERS; i++)
828 UpdateMaxPower(Powers(i));
830 for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
831 UpdateResistances(i);
833 return true;
836 void Pet::UpdateResistances(uint32 school)
838 if(school > SPELL_SCHOOL_NORMAL)
840 float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school));
842 Unit *owner = GetOwner();
843 // hunter and warlock pets gain 40% of owner's resistance
844 if(owner && (getPetType() == HUNTER_PET || getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK))
845 value += float(owner->GetResistance(SpellSchools(school))) * 0.4f;
847 SetResistance(SpellSchools(school), int32(value));
849 else
850 UpdateArmor();
853 void Pet::UpdateArmor()
855 float value = 0.0f;
856 float bonus_armor = 0.0f;
857 UnitMods unitMod = UNIT_MOD_ARMOR;
859 Unit *owner = GetOwner();
860 // hunter and warlock pets gain 35% of owner's armor value
861 if(owner && (getPetType() == HUNTER_PET || getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK))
862 bonus_armor = 0.35f * float(owner->GetArmor());
864 value = GetModifierValue(unitMod, BASE_VALUE);
865 value *= GetModifierValue(unitMod, BASE_PCT);
866 value += GetStat(STAT_AGILITY) * 2.0f;
867 value += GetModifierValue(unitMod, TOTAL_VALUE) + bonus_armor;
868 value *= GetModifierValue(unitMod, TOTAL_PCT);
870 SetArmor(int32(value));
873 void Pet::UpdateMaxHealth()
875 UnitMods unitMod = UNIT_MOD_HEALTH;
876 float stamina = GetStat(STAT_STAMINA) - GetCreateStat(STAT_STAMINA);
878 float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
879 value *= GetModifierValue(unitMod, BASE_PCT);
880 value += GetModifierValue(unitMod, TOTAL_VALUE) + stamina * 10.0f;
881 value *= GetModifierValue(unitMod, TOTAL_PCT);
883 SetMaxHealth((uint32)value);
886 void Pet::UpdateMaxPower(Powers power)
888 UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
890 float addValue = (power == POWER_MANA) ? GetStat(STAT_INTELLECT) - GetCreateStat(STAT_INTELLECT) : 0.0f;
892 float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
893 value *= GetModifierValue(unitMod, BASE_PCT);
894 value += GetModifierValue(unitMod, TOTAL_VALUE) + addValue * 15.0f;
895 value *= GetModifierValue(unitMod, TOTAL_PCT);
897 SetMaxPower(power, uint32(value));
900 void Pet::UpdateAttackPowerAndDamage(bool ranged)
902 if(ranged)
903 return;
905 float val = 0.0f;
906 float bonusAP = 0.0f;
907 UnitMods unitMod = UNIT_MOD_ATTACK_POWER;
909 if(GetEntry() == 416) // imp's attack power
910 val = GetStat(STAT_STRENGTH) - 10.0f;
911 else
912 val = 2 * GetStat(STAT_STRENGTH) - 20.0f;
914 Unit* owner = GetOwner();
915 if( owner && owner->GetTypeId()==TYPEID_PLAYER)
917 if(getPetType() == HUNTER_PET) //hunter pets benefit from owner's attack power
919 bonusAP = owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.22f;
920 SetBonusDamage( int32(owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.1287f));
922 //demons benefit from warlocks shadow or fire damage
923 else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK)
925 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);
926 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);
927 int32 maximum = (fire > shadow) ? fire : shadow;
928 if(maximum < 0)
929 maximum = 0;
930 SetBonusDamage( int32(maximum * 0.15f));
931 bonusAP = maximum * 0.57f;
933 //water elementals benefit from mage's frost damage
934 else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_MAGE)
936 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);
937 if(frost < 0)
938 frost = 0;
939 SetBonusDamage( int32(frost * 0.4f));
943 SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, val + bonusAP);
945 //in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB
946 float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
947 float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
948 float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
950 //UNIT_FIELD_(RANGED)_ATTACK_POWER field
951 SetUInt32Value(UNIT_FIELD_ATTACK_POWER, (uint32)base_attPower);
952 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
953 SetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (uint32)attPowerMod);
954 //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
955 SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, attPowerMultiplier);
957 //automatically update weapon damage after attack power modification
958 UpdateDamagePhysical(BASE_ATTACK);
961 void Pet::UpdateDamagePhysical(WeaponAttackType attType)
963 if(attType > BASE_ATTACK)
964 return;
966 UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND;
968 float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f;
970 float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
971 float base_pct = GetModifierValue(unitMod, BASE_PCT);
972 float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
973 float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
975 float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
976 float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
978 float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct;
979 float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct;
981 // Pet's base damage changes depending on happiness
982 if (getPetType() == HUNTER_PET && attType == BASE_ATTACK)
984 switch(GetHappinessState())
986 case HAPPY:
987 // 125% of normal damage
988 mindamage = mindamage * 1.25;
989 maxdamage = maxdamage * 1.25;
990 break;
991 case CONTENT:
992 // 100% of normal damage, nothing to modify
993 break;
994 case UNHAPPY:
995 // 75% of normal damage
996 mindamage = mindamage * 0.75;
997 maxdamage = maxdamage * 0.75;
998 break;
1002 SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage);
1003 SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage);