aboutsummaryrefslogtreecommitdiff
path: root/src/game/StatSystem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/StatSystem.cpp')
-rw-r--r--src/game/StatSystem.cpp1920
1 files changed, 965 insertions, 955 deletions
diff --git a/src/game/StatSystem.cpp b/src/game/StatSystem.cpp
index b89346d937a..951a92cb5ad 100644
--- a/src/game/StatSystem.cpp
+++ b/src/game/StatSystem.cpp
@@ -1,955 +1,965 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "Unit.h"
-#include "Player.h"
-#include "Pet.h"
-#include "Creature.h"
-#include "SharedDefines.h"
-#include "SpellAuras.h"
-
-/*#######################################
-######## ########
-######## PLAYERS STAT SYSTEM ########
-######## ########
-#######################################*/
-
-bool Player::UpdateStats(Stats stat)
-{
- if(stat > STAT_SPIRIT)
- return false;
-
- // value = ((base_value * base_pct) + total_value) * total_pct
- float value = GetTotalStatValue(stat);
-
- SetStat(stat, int32(value));
-
- if(stat == STAT_STAMINA || stat == STAT_INTELLECT)
- {
- Pet *pet = GetPet();
- if(pet)
- pet->UpdateStats(stat);
- }
-
- switch(stat)
- {
- case STAT_STRENGTH:
- UpdateAttackPowerAndDamage();
- UpdateShieldBlockValue();
- break;
- case STAT_AGILITY:
- UpdateArmor();
- UpdateAttackPowerAndDamage(true);
- if(getClass() == CLASS_ROGUE || getClass() == CLASS_HUNTER || getClass() == CLASS_DRUID && m_form==FORM_CAT)
- UpdateAttackPowerAndDamage();
-
- UpdateAllCritPercentages();
- UpdateDodgePercentage();
- break;
-
- case STAT_STAMINA: UpdateMaxHealth(); break;
- case STAT_INTELLECT:
- UpdateMaxPower(POWER_MANA);
- UpdateAllSpellCritChances();
- UpdateAttackPowerAndDamage(true); //SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT, only intelect currently
- UpdateArmor(); //SPELL_AURA_MOD_RESISTANCE_OF_INTELLECT_PERCENT, only armor currently
- break;
-
- case STAT_SPIRIT:
- break;
-
- default:
- break;
- }
- UpdateSpellDamageAndHealingBonus();
- UpdateManaRegen();
- return true;
-}
-
-void Player::UpdateSpellDamageAndHealingBonus()
-{
- // Magic damage modifiers implemented in Unit::SpellDamageBonus
- // This information for client side use only
- // Get healing bonus for all schools
- SetStatInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, SpellBaseHealingBonus(SPELL_SCHOOL_MASK_ALL));
- // Get damage bonus for all schools
- for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
- SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, SpellBaseDamageBonus(SpellSchoolMask(1 << i)));
-}
-
-bool Player::UpdateAllStats()
-{
- for (int i = STAT_STRENGTH; i < MAX_STATS; i++)
- {
- float value = GetTotalStatValue(Stats(i));
- SetStat(Stats(i), (int32)value);
- }
-
- UpdateAttackPowerAndDamage();
- UpdateAttackPowerAndDamage(true);
- UpdateArmor();
- UpdateMaxHealth();
-
- for(int i = POWER_MANA; i < MAX_POWERS; i++)
- UpdateMaxPower(Powers(i));
-
- UpdateAllCritPercentages();
- UpdateAllSpellCritChances();
- UpdateDefenseBonusesMod();
- UpdateShieldBlockValue();
- UpdateSpellDamageAndHealingBonus();
- UpdateManaRegen();
- UpdateExpertise(BASE_ATTACK);
- UpdateExpertise(OFF_ATTACK);
- for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
- UpdateResistances(i);
-
- return true;
-}
-
-void Player::UpdateResistances(uint32 school)
-{
- if(school > SPELL_SCHOOL_NORMAL)
- {
- float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school));
- SetResistance(SpellSchools(school), int32(value));
-
- Pet *pet = GetPet();
- if(pet)
- pet->UpdateResistances(school);
- }
- else
- UpdateArmor();
-}
-
-void Player::UpdateArmor()
-{
- float value = 0.0f;
- UnitMods unitMod = UNIT_MOD_ARMOR;
-
- value = GetModifierValue(unitMod, BASE_VALUE); // base armor (from items)
- value *= GetModifierValue(unitMod, BASE_PCT); // armor percent from items
- value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats
- value += GetModifierValue(unitMod, TOTAL_VALUE);
-
- //add dynamic flat mods
- AuraList const& mResbyIntellect = GetAurasByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT);
- for(AuraList::const_iterator i = mResbyIntellect.begin();i != mResbyIntellect.end(); ++i)
- {
- Modifier* mod = (*i)->GetModifier();
- if(mod->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL)
- value += int32(GetStat(Stats((*i)->GetMiscBValue())) * mod->m_amount / 100.0f);
- }
-
- value *= GetModifierValue(unitMod, TOTAL_PCT);
-
- SetArmor(int32(value));
-
- Pet *pet = GetPet();
- if(pet)
- pet->UpdateArmor();
-}
-
-float Player::GetHealthBonusFromStamina()
-{
- float stamina = GetStat(STAT_STAMINA);
-
- float baseStam = stamina < 20 ? stamina : 20;
- float moreStam = stamina - baseStam;
-
- return baseStam + (moreStam*10.0f);
-}
-
-float Player::GetManaBonusFromIntellect()
-{
- float intellect = GetStat(STAT_INTELLECT);
-
- float baseInt = intellect < 20 ? intellect : 20;
- float moreInt = intellect - baseInt;
-
- return baseInt + (moreInt*15.0f);
-}
-
-void Player::UpdateMaxHealth()
-{
- UnitMods unitMod = UNIT_MOD_HEALTH;
-
- float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
- value *= GetModifierValue(unitMod, BASE_PCT);
- value += GetModifierValue(unitMod, TOTAL_VALUE) + GetHealthBonusFromStamina();
- value *= GetModifierValue(unitMod, TOTAL_PCT);
-
- SetMaxHealth((uint32)value);
-}
-
-void Player::UpdateMaxPower(Powers power)
-{
- UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
-
- float bonusPower = (power == POWER_MANA) ? GetManaBonusFromIntellect() : 0;
-
- float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
- value *= GetModifierValue(unitMod, BASE_PCT);
- value += GetModifierValue(unitMod, TOTAL_VALUE) + bonusPower;
- value *= GetModifierValue(unitMod, TOTAL_PCT);
-
- SetMaxPower(power, uint32(value));
-}
-
-void Player::UpdateAttackPowerAndDamage(bool ranged )
-{
- float val2 = 0.0f;
- float level = float(getLevel());
-
- UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER;
-
- uint16 index = UNIT_FIELD_ATTACK_POWER;
- uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MODS;
- uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER;
-
- if(ranged)
- {
- index = UNIT_FIELD_RANGED_ATTACK_POWER;
- index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS;
- index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER;
-
- switch(getClass())
- {
- case CLASS_HUNTER: val2 = level * 2.0f + GetStat(STAT_AGILITY) - 10.0f; break;
- case CLASS_ROGUE: val2 = level + GetStat(STAT_AGILITY) - 10.0f; break;
- case CLASS_WARRIOR:val2 = level + GetStat(STAT_AGILITY) - 10.0f; break;
- case CLASS_DRUID:
- switch(m_form)
- {
- case FORM_CAT:
- case FORM_BEAR:
- case FORM_DIREBEAR:
- val2 = 0.0f; break;
- default:
- val2 = GetStat(STAT_AGILITY) - 10.0f; break;
- }
- break;
- default: val2 = GetStat(STAT_AGILITY) - 10.0f; break;
- }
- }
- else
- {
- switch(getClass())
- {
- case CLASS_WARRIOR: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
- case CLASS_PALADIN: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
- case CLASS_ROGUE: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break;
- case CLASS_HUNTER: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break;
- case CLASS_SHAMAN: val2 = level*2.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
- case CLASS_DRUID:
- {
- //Check if Predatory Strikes is skilled
- float mLevelMult = 0.0;
- switch(m_form)
- {
- case FORM_CAT:
- case FORM_BEAR:
- case FORM_DIREBEAR:
- case FORM_MOONKIN:
- {
- Unit::AuraList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
- {
- // Predatory Strikes
- if ((*itr)->GetSpellProto()->SpellIconID == 1563)
- {
- mLevelMult = (*itr)->GetModifier()->m_amount / 100.0f;
- break;
- }
- }
- break;
- }
- }
-
- switch(m_form)
- {
- case FORM_CAT:
- val2 = getLevel()*(mLevelMult+2.0f) + GetStat(STAT_STRENGTH)*2.0f + GetStat(STAT_AGILITY) - 20.0f; break;
- case FORM_BEAR:
- case FORM_DIREBEAR:
- val2 = getLevel()*(mLevelMult+3.0f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
- case FORM_MOONKIN:
- val2 = getLevel()*(mLevelMult+1.5f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
- default:
- val2 = GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
- }
- break;
- }
- case CLASS_MAGE: val2 = GetStat(STAT_STRENGTH) - 10.0f; break;
- case CLASS_PRIEST: val2 = GetStat(STAT_STRENGTH) - 10.0f; break;
- case CLASS_WARLOCK: val2 = GetStat(STAT_STRENGTH) - 10.0f; break;
- }
- }
-
- SetModifierValue(unitMod, BASE_VALUE, val2);
-
- float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
- float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
-
- //add dynamic flat mods
- if( ranged && (getClassMask() & CLASSMASK_WAND_USERS)==0)
- {
- AuraList const& mRAPbyIntellect = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT);
- for(AuraList::const_iterator i = mRAPbyIntellect.begin();i != mRAPbyIntellect.end(); ++i)
- attPowerMod += int32(GetStat(Stats((*i)->GetModifier()->m_miscvalue)) * (*i)->GetModifier()->m_amount / 100.0f);
- }
-
- float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
-
- SetUInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
- SetUInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
- SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
-
- //automatically update weapon damage after attack power modification
- if(ranged)
- {
- UpdateDamagePhysical(RANGED_ATTACK);
-
- Pet *pet = GetPet(); //update pet's AP
- if(pet)
- pet->UpdateAttackPowerAndDamage();
- }
- else
- {
- UpdateDamagePhysical(BASE_ATTACK);
- if(CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon
- UpdateDamagePhysical(OFF_ATTACK);
- }
-}
-
-void Player::UpdateShieldBlockValue()
-{
- SetUInt32Value(PLAYER_SHIELD_BLOCK, GetShieldBlockValue());
-}
-
-void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, float& min_damage, float& max_damage)
-{
- UnitMods unitMod;
- UnitMods attPower;
-
- switch(attType)
- {
- case BASE_ATTACK:
- default:
- unitMod = UNIT_MOD_DAMAGE_MAINHAND;
- attPower = UNIT_MOD_ATTACK_POWER;
- break;
- case OFF_ATTACK:
- unitMod = UNIT_MOD_DAMAGE_OFFHAND;
- attPower = UNIT_MOD_ATTACK_POWER;
- break;
- case RANGED_ATTACK:
- unitMod = UNIT_MOD_DAMAGE_RANGED;
- attPower = UNIT_MOD_ATTACK_POWER_RANGED;
- break;
- }
-
- float att_speed = GetAPMultiplier(attType,normalized);
-
- float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
- float base_pct = GetModifierValue(unitMod, BASE_PCT);
- float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
- float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
-
- float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE);
- float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE);
-
- if (IsInFeralForm()) //check if player is druid and in cat or bear forms
- {
- uint32 lvl = getLevel();
- if ( lvl > 60 ) lvl = 60;
-
- weapon_mindamage = lvl*0.85*att_speed;
- weapon_maxdamage = lvl*1.25*att_speed;
- }
- else if(!IsUseEquipedWeapon(attType==BASE_ATTACK)) //check if player not in form but still can't use weapon (broken/etc)
- {
- weapon_mindamage = BASE_MINDAMAGE;
- weapon_maxdamage = BASE_MAXDAMAGE;
- }
- else if(attType == RANGED_ATTACK) //add ammo DPS to ranged damage
- {
- weapon_mindamage += GetAmmoDPS() * att_speed;
- weapon_maxdamage += GetAmmoDPS() * att_speed;
- }
-
- min_damage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct;
- max_damage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct;
-}
-
-void Player::UpdateDamagePhysical(WeaponAttackType attType)
-{
- float mindamage;
- float maxdamage;
-
- CalculateMinMaxDamage(attType,false,mindamage,maxdamage);
-
- switch(attType)
- {
- case BASE_ATTACK:
- default:
- SetStatFloatValue(UNIT_FIELD_MINDAMAGE,mindamage);
- SetStatFloatValue(UNIT_FIELD_MAXDAMAGE,maxdamage);
- break;
- case OFF_ATTACK:
- SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE,mindamage);
- SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE,maxdamage);
- break;
- case RANGED_ATTACK:
- SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE,mindamage);
- SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE,maxdamage);
- break;
- }
-}
-
-void Player::UpdateDefenseBonusesMod()
-{
- UpdateBlockPercentage();
- UpdateParryPercentage();
- UpdateDodgePercentage();
-}
-
-void Player::UpdateBlockPercentage()
-{
- // Base value
- float value = 5.0f;
- // Modify value from defense skill
- value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
- // Increase from SPELL_AURA_MOD_BLOCK_PERCENT aura
- value += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT);
- // Increase from rating
- value += GetRatingBonusValue(CR_BLOCK);
- value = value < 0.0f ? 0.0f : value;
- SetStatFloatValue(PLAYER_BLOCK_PERCENTAGE, value);
-}
-
-void Player::UpdateCritPercentage(WeaponAttackType attType)
-{
- BaseModGroup modGroup;
- uint16 index;
- CombatRating cr;
-
- switch(attType)
- {
- case OFF_ATTACK:
- modGroup = OFFHAND_CRIT_PERCENTAGE;
- index = PLAYER_OFFHAND_CRIT_PERCENTAGE;
- cr = CR_CRIT_MELEE;
- break;
- case RANGED_ATTACK:
- modGroup = RANGED_CRIT_PERCENTAGE;
- index = PLAYER_RANGED_CRIT_PERCENTAGE;
- cr = CR_CRIT_RANGED;
- break;
- case BASE_ATTACK:
- default:
- modGroup = CRIT_PERCENTAGE;
- index = PLAYER_CRIT_PERCENTAGE;
- cr = CR_CRIT_MELEE;
- break;
- }
-
- float value = GetTotalPercentageModValue(modGroup) + GetRatingBonusValue(cr);
- // Modify crit from weapon skill and maximized defense skill of same level victim difference
- value += (int32(GetWeaponSkillValue(attType)) - int32(GetMaxSkillValueForLevel())) * 0.04f;
- value = value < 0.0f ? 0.0f : value;
- SetStatFloatValue(index, value);
-}
-
-void Player::UpdateAllCritPercentages()
-{
- float value = GetMeleeCritFromAgility();
-
- SetBaseModValue(CRIT_PERCENTAGE, PCT_MOD, value);
- SetBaseModValue(OFFHAND_CRIT_PERCENTAGE, PCT_MOD, value);
- SetBaseModValue(RANGED_CRIT_PERCENTAGE, PCT_MOD, value);
-
- UpdateCritPercentage(BASE_ATTACK);
- UpdateCritPercentage(OFF_ATTACK);
- UpdateCritPercentage(RANGED_ATTACK);
-}
-
-void Player::UpdateParryPercentage()
-{
- // Base parry
- float value = 5.0f;
- // Modify value from defense skill
- value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
- // Parry from SPELL_AURA_MOD_PARRY_PERCENT aura
- value += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT);
- // Parry from rating
- value += GetRatingBonusValue(CR_PARRY);
- value = value < 0.0f ? 0.0f : value;
- SetStatFloatValue(PLAYER_PARRY_PERCENTAGE, value);
-}
-
-void Player::UpdateDodgePercentage()
-{
- // Dodge from agility
- float value = GetDodgeFromAgility();
- // Modify value from defense skill
- value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
- // Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura
- value += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT);
- // Dodge from rating
- value += GetRatingBonusValue(CR_DODGE);
- value = value < 0.0f ? 0.0f : value;
- SetStatFloatValue(PLAYER_DODGE_PERCENTAGE, value);
-}
-
-void Player::UpdateSpellCritChance(uint32 school)
-{
- // For normal school set zero crit chance
- if(school == SPELL_SCHOOL_NORMAL)
- {
- SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1, 0.0f);
- return;
- }
- // For others recalculate it from:
- float crit = 0.0f;
- // Crit from Intellect
- crit += GetSpellCritFromIntellect();
- // Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE
- crit += GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE);
- // Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
- crit += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, 1<<school);
- // Increase crit from spell crit ratings
- crit += GetRatingBonusValue(CR_CRIT_SPELL);
-
- // Store crit value
- SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1 + school, crit);
-}
-
-void Player::UpdateAllSpellCritChances()
-{
- for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
- UpdateSpellCritChance(i);
-}
-
-void Player::UpdateExpertise(WeaponAttackType attack)
-{
- if(attack==RANGED_ATTACK)
- return;
-
- int32 expertise = int32(GetRatingBonusValue(CR_EXPERTISE));
-
- Item *weapon = GetWeaponForAttack(attack);
-
- AuraList const& expAuras = GetAurasByType(SPELL_AURA_MOD_EXPERTISE);
- for(AuraList::const_iterator itr = expAuras.begin(); itr != expAuras.end(); ++itr)
- {
- // item neutral spell
- if((*itr)->GetSpellProto()->EquippedItemClass == -1)
- expertise += (*itr)->GetModifier()->m_amount;
- // item dependent spell
- else if(weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellProto()))
- expertise += (*itr)->GetModifier()->m_amount;
- }
-
- if(expertise < 0)
- expertise = 0;
-
- switch(attack)
- {
- case BASE_ATTACK: SetUInt32Value(PLAYER_EXPERTISE, expertise); break;
- case OFF_ATTACK: SetUInt32Value(PLAYER_OFFHAND_EXPERTISE, expertise); break;
- default: break;
- }
-}
-
-void Player::UpdateManaRegen()
-{
- float Intellect = GetStat(STAT_INTELLECT);
- // Mana regen from spirit and intellect
- float power_regen = sqrt(Intellect) * OCTRegenMPPerSpirit();
- // Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen
- power_regen *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, POWER_MANA);
-
- // Mana regen from SPELL_AURA_MOD_POWER_REGEN aura
- float power_regen_mp5 = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) / 5.0f;
-
- // Get bonus from SPELL_AURA_MOD_MANA_REGEN_FROM_STAT aura
- AuraList const& regenAura = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_FROM_STAT);
- for(AuraList::const_iterator i = regenAura.begin();i != regenAura.end(); ++i)
- {
- Modifier* mod = (*i)->GetModifier();
- power_regen_mp5 += GetStat(Stats(mod->m_miscvalue)) * mod->m_amount / 500.0f;
- }
-
- // Bonus from some dummy auras
- AuraList const& mDummyAuras = GetAurasByType(SPELL_AURA_PERIODIC_DUMMY);
- for(AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
- if((*i)->GetId() == 34074) // Aspect of the Viper
- {
- power_regen_mp5 += (*i)->GetModifier()->m_amount * Intellect / 500.0f;
- // Add regen bonus from level in this dummy
- power_regen_mp5 += getLevel() * 35 / 100;
- }
-
- // Set regen rate in cast state apply only on spirit based regen
- int32 modManaRegenInterrupt = GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
- if (modManaRegenInterrupt > 100)
- modManaRegenInterrupt = 100;
- SetStatFloatValue(PLAYER_FIELD_MOD_MANA_REGEN_INTERRUPT, power_regen_mp5 + power_regen * modManaRegenInterrupt / 100.0f);
-
- SetStatFloatValue(PLAYER_FIELD_MOD_MANA_REGEN, power_regen_mp5 + power_regen);
-}
-
-void Player::_ApplyAllStatBonuses()
-{
- SetCanModifyStats(false);
-
- _ApplyAllAuraMods();
- _ApplyAllItemMods();
-
- SetCanModifyStats(true);
-
- UpdateAllStats();
-}
-
-void Player::_RemoveAllStatBonuses()
-{
- SetCanModifyStats(false);
-
- _RemoveAllItemMods();
- _RemoveAllAuraMods();
-
- SetCanModifyStats(true);
-
- UpdateAllStats();
-}
-
-/*#######################################
-######## ########
-######## MOBS STAT SYSTEM ########
-######## ########
-#######################################*/
-
-bool Creature::UpdateStats(Stats /*stat*/)
-{
- return true;
-}
-
-bool Creature::UpdateAllStats()
-{
- UpdateMaxHealth();
- UpdateAttackPowerAndDamage();
-
- for(int i = POWER_MANA; i < MAX_POWERS; ++i)
- UpdateMaxPower(Powers(i));
-
- for(int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
- UpdateResistances(i);
-
- return true;
-}
-
-void Creature::UpdateResistances(uint32 school)
-{
- if(school > SPELL_SCHOOL_NORMAL)
- {
- float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school));
- SetResistance(SpellSchools(school), int32(value));
- }
- else
- UpdateArmor();
-}
-
-void Creature::UpdateArmor()
-{
- float value = GetTotalAuraModValue(UNIT_MOD_ARMOR);
- SetArmor(int32(value));
-}
-
-void Creature::UpdateMaxHealth()
-{
- float value = GetTotalAuraModValue(UNIT_MOD_HEALTH);
- SetMaxHealth((uint32)value);
-}
-
-void Creature::UpdateMaxPower(Powers power)
-{
- UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
-
- float value = GetTotalAuraModValue(unitMod);
- SetMaxPower(power, uint32(value));
-}
-
-void Creature::UpdateAttackPowerAndDamage(bool ranged)
-{
- if(ranged)
- return;
-
- //automatically update weapon damage after attack power modification
- UpdateDamagePhysical(BASE_ATTACK);
-}
-
-void Creature::UpdateDamagePhysical(WeaponAttackType attType)
-{
- if(attType > BASE_ATTACK)
- return;
-
- UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND;
-
- float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f;
-
- float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
- float base_pct = GetModifierValue(unitMod, BASE_PCT);
- float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
- float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
-
- float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
- float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
-
- float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct ;
- float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct ;
-
- SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage);
- SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage);
-}
-
-/*#######################################
-######## ########
-######## PETS STAT SYSTEM ########
-######## ########
-#######################################*/
-
-bool Pet::UpdateStats(Stats stat)
-{
- if(stat > STAT_SPIRIT)
- return false;
-
- // value = ((base_value * base_pct) + total_value) * total_pct
- float value = GetTotalStatValue(stat);
-
- Unit *owner = GetOwner();
- if ( stat == STAT_STAMINA )
- {
- if(owner)
- value += float(owner->GetStat(stat)) * 0.3f;
- }
- //warlock's and mage's pets gain 30% of owner's intellect
- else if ( stat == STAT_INTELLECT && getPetType() == SUMMON_PET )
- {
- if(owner && (owner->getClass() == CLASS_WARLOCK || owner->getClass() == CLASS_MAGE) )
- value += float(owner->GetStat(stat)) * 0.3f;
- }
-
- SetStat(stat, int32(value));
-
- switch(stat)
- {
- case STAT_STRENGTH: UpdateAttackPowerAndDamage(); break;
- case STAT_AGILITY: UpdateArmor(); break;
- case STAT_STAMINA: UpdateMaxHealth(); break;
- case STAT_INTELLECT: UpdateMaxPower(POWER_MANA); break;
- case STAT_SPIRIT:
- default:
- break;
- }
-
- return true;
-}
-
-bool Pet::UpdateAllStats()
-{
- for (int i = STAT_STRENGTH; i < MAX_STATS; i++)
- UpdateStats(Stats(i));
-
- for(int i = POWER_MANA; i < MAX_POWERS; i++)
- UpdateMaxPower(Powers(i));
-
- for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
- UpdateResistances(i);
-
- return true;
-}
-
-void Pet::UpdateResistances(uint32 school)
-{
- if(school > SPELL_SCHOOL_NORMAL)
- {
- float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school));
-
- Unit *owner = GetOwner();
- // hunter and warlock pets gain 40% of owner's resistance
- if(owner && (getPetType() == HUNTER_PET || getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK))
- value += float(owner->GetResistance(SpellSchools(school))) * 0.4f;
-
- SetResistance(SpellSchools(school), int32(value));
- }
- else
- UpdateArmor();
-}
-
-void Pet::UpdateArmor()
-{
- float value = 0.0f;
- float bonus_armor = 0.0f;
- UnitMods unitMod = UNIT_MOD_ARMOR;
-
- Unit *owner = GetOwner();
- // hunter and warlock pets gain 35% of owner's armor value
- if(owner && (getPetType() == HUNTER_PET || getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK))
- bonus_armor = 0.35f * float(owner->GetArmor());
-
- value = GetModifierValue(unitMod, BASE_VALUE);
- value *= GetModifierValue(unitMod, BASE_PCT);
- value += GetStat(STAT_AGILITY) * 2.0f;
- value += GetModifierValue(unitMod, TOTAL_VALUE) + bonus_armor;
- value *= GetModifierValue(unitMod, TOTAL_PCT);
-
- SetArmor(int32(value));
-}
-
-void Pet::UpdateMaxHealth()
-{
- UnitMods unitMod = UNIT_MOD_HEALTH;
- float stamina = GetStat(STAT_STAMINA) - GetCreateStat(STAT_STAMINA);
-
- float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
- value *= GetModifierValue(unitMod, BASE_PCT);
- value += GetModifierValue(unitMod, TOTAL_VALUE) + stamina * 10.0f;
- value *= GetModifierValue(unitMod, TOTAL_PCT);
-
- SetMaxHealth((uint32)value);
-}
-
-void Pet::UpdateMaxPower(Powers power)
-{
- UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
- float addValue = (power == POWER_MANA) ? GetStat(STAT_INTELLECT) - GetCreateStat(STAT_INTELLECT) : 0.0f;
-
- float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
- value *= GetModifierValue(unitMod, BASE_PCT);
- value += GetModifierValue(unitMod, TOTAL_VALUE) + addValue * 15.0f;
- value *= GetModifierValue(unitMod, TOTAL_PCT);
-
- SetMaxPower(power, uint32(value));
-}
-
-void Pet::UpdateAttackPowerAndDamage(bool ranged)
-{
- if(ranged)
- return;
-
- float val = 0.0f;
- float bonusAP = 0.0f;
- UnitMods unitMod = UNIT_MOD_ATTACK_POWER;
-
- if(GetEntry() == 416) // imp's attack power
- val = GetStat(STAT_STRENGTH) - 10.0f;
- else
- val = 2 * GetStat(STAT_STRENGTH) - 20.0f;
-
- Unit* owner = GetOwner();
- if( owner && owner->GetTypeId()==TYPEID_PLAYER)
- {
- if(getPetType() == HUNTER_PET) //hunter pets benefit from owner's attack power
- {
- bonusAP = owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.22f;
- SetBonusDamage( int32(owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.125f));
- }
- //demons benefit from warlocks shadow or fire damage
- else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK)
- {
- 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);
- 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);
- int32 maximum = (fire > shadow) ? fire : shadow;
- if(maximum < 0)
- maximum = 0;
- SetBonusDamage( int32(maximum * 0.15f));
- bonusAP = maximum * 0.57f;
- }
- //water elementals benefit from mage's frost damage
- else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_MAGE)
- {
- 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);
- if(frost < 0)
- frost = 0;
- SetBonusDamage( int32(frost * 0.4f));
- }
- }
-
- SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, val + bonusAP);
-
- //in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB
- float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
- float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
- float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
-
- //UNIT_FIELD_(RANGED)_ATTACK_POWER field
- SetUInt32Value(UNIT_FIELD_ATTACK_POWER, (uint32)base_attPower);
- //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
- SetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (uint32)attPowerMod);
- //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
- SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, attPowerMultiplier);
-
- //automatically update weapon damage after attack power modification
- UpdateDamagePhysical(BASE_ATTACK);
-}
-
-void Pet::UpdateDamagePhysical(WeaponAttackType attType)
-{
- if(attType > BASE_ATTACK)
- return;
-
- UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND;
-
- float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f;
-
- float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
- float base_pct = GetModifierValue(unitMod, BASE_PCT);
- float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
- float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
-
- float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
- float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
-
- float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct;
- float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct;
-
- // Pet's base damage changes depending on happiness
- if (getPetType() == HUNTER_PET && attType == BASE_ATTACK)
- {
- switch(GetHappinessState())
- {
- case HAPPY:
- // 125% of normal damage
- mindamage = mindamage * 1.25;
- maxdamage = maxdamage * 1.25;
- break;
- case CONTENT:
- // 100% of normal damage, nothing to modify
- break;
- case UNHAPPY:
- // 75% of normal damage
- mindamage = mindamage * 0.75;
- maxdamage = maxdamage * 0.75;
- break;
- }
- }
-
- SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage);
- SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage);
-}
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "Unit.h"
+#include "Player.h"
+#include "Pet.h"
+#include "Creature.h"
+#include "SharedDefines.h"
+#include "SpellAuras.h"
+
+/*#######################################
+######## ########
+######## PLAYERS STAT SYSTEM ########
+######## ########
+#######################################*/
+
+bool Player::UpdateStats(Stats stat)
+{
+ if(stat > STAT_SPIRIT)
+ return false;
+
+ // value = ((base_value * base_pct) + total_value) * total_pct
+ float value = GetTotalStatValue(stat);
+
+ SetStat(stat, int32(value));
+
+ if(stat == STAT_STAMINA || stat == STAT_INTELLECT)
+ {
+ Pet *pet = GetPet();
+ if(pet)
+ pet->UpdateStats(stat);
+ }
+
+ switch(stat)
+ {
+ case STAT_STRENGTH:
+ UpdateAttackPowerAndDamage();
+ UpdateShieldBlockValue();
+ break;
+ case STAT_AGILITY:
+ UpdateArmor();
+ UpdateAttackPowerAndDamage(true);
+ if(getClass() == CLASS_ROGUE || getClass() == CLASS_HUNTER || getClass() == CLASS_DRUID && m_form==FORM_CAT)
+ UpdateAttackPowerAndDamage();
+
+ UpdateAllCritPercentages();
+ UpdateDodgePercentage();
+ break;
+
+ case STAT_STAMINA: UpdateMaxHealth(); break;
+ case STAT_INTELLECT:
+ UpdateMaxPower(POWER_MANA);
+ UpdateAllSpellCritChances();
+ UpdateAttackPowerAndDamage(true); //SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT, only intelect currently
+ UpdateArmor(); //SPELL_AURA_MOD_RESISTANCE_OF_INTELLECT_PERCENT, only armor currently
+ break;
+
+ case STAT_SPIRIT:
+ break;
+
+ default:
+ break;
+ }
+ UpdateSpellDamageAndHealingBonus();
+ UpdateManaRegen();
+ return true;
+}
+
+void Player::UpdateSpellDamageAndHealingBonus()
+{
+ // Magic damage modifiers implemented in Unit::SpellDamageBonus
+ // This information for client side use only
+ // Get healing bonus for all schools
+ SetStatInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, SpellBaseHealingBonus(SPELL_SCHOOL_MASK_ALL));
+ // Get damage bonus for all schools
+ for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
+ SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, SpellBaseDamageBonus(SpellSchoolMask(1 << i)));
+}
+
+bool Player::UpdateAllStats()
+{
+ for (int i = STAT_STRENGTH; i < MAX_STATS; i++)
+ {
+ float value = GetTotalStatValue(Stats(i));
+ SetStat(Stats(i), (int32)value);
+ }
+
+ UpdateAttackPowerAndDamage();
+ UpdateAttackPowerAndDamage(true);
+ UpdateArmor();
+ UpdateMaxHealth();
+
+ for(int i = POWER_MANA; i < MAX_POWERS; i++)
+ UpdateMaxPower(Powers(i));
+
+ UpdateAllCritPercentages();
+ UpdateAllSpellCritChances();
+ UpdateDefenseBonusesMod();
+ UpdateShieldBlockValue();
+ UpdateSpellDamageAndHealingBonus();
+ UpdateManaRegen();
+ UpdateExpertise(BASE_ATTACK);
+ UpdateExpertise(OFF_ATTACK);
+ for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
+ UpdateResistances(i);
+
+ return true;
+}
+
+void Player::UpdateResistances(uint32 school)
+{
+ if(school > SPELL_SCHOOL_NORMAL)
+ {
+ float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school));
+ SetResistance(SpellSchools(school), int32(value));
+
+ Pet *pet = GetPet();
+ if(pet)
+ pet->UpdateResistances(school);
+ }
+ else
+ UpdateArmor();
+}
+
+void Player::UpdateArmor()
+{
+ float value = 0.0f;
+ UnitMods unitMod = UNIT_MOD_ARMOR;
+
+ value = GetModifierValue(unitMod, BASE_VALUE); // base armor (from items)
+ value *= GetModifierValue(unitMod, BASE_PCT); // armor percent from items
+ value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats
+ value += GetModifierValue(unitMod, TOTAL_VALUE);
+
+ //add dynamic flat mods
+ AuraList const& mResbyIntellect = GetAurasByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT);
+ for(AuraList::const_iterator i = mResbyIntellect.begin();i != mResbyIntellect.end(); ++i)
+ {
+ Modifier* mod = (*i)->GetModifier();
+ if(mod->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL)
+ value += int32(GetStat(Stats((*i)->GetMiscBValue())) * mod->m_amount / 100.0f);
+ }
+
+ value *= GetModifierValue(unitMod, TOTAL_PCT);
+
+ SetArmor(int32(value));
+
+ Pet *pet = GetPet();
+ if(pet)
+ pet->UpdateArmor();
+}
+
+float Player::GetHealthBonusFromStamina()
+{
+ float stamina = GetStat(STAT_STAMINA);
+
+ float baseStam = stamina < 20 ? stamina : 20;
+ float moreStam = stamina - baseStam;
+
+ return baseStam + (moreStam*10.0f);
+}
+
+float Player::GetManaBonusFromIntellect()
+{
+ float intellect = GetStat(STAT_INTELLECT);
+
+ float baseInt = intellect < 20 ? intellect : 20;
+ float moreInt = intellect - baseInt;
+
+ return baseInt + (moreInt*15.0f);
+}
+
+void Player::UpdateMaxHealth()
+{
+ UnitMods unitMod = UNIT_MOD_HEALTH;
+
+ float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
+ value *= GetModifierValue(unitMod, BASE_PCT);
+ value += GetModifierValue(unitMod, TOTAL_VALUE) + GetHealthBonusFromStamina();
+ value *= GetModifierValue(unitMod, TOTAL_PCT);
+
+ SetMaxHealth((uint32)value);
+}
+
+void Player::UpdateMaxPower(Powers power)
+{
+ UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
+
+ float bonusPower = (power == POWER_MANA) ? GetManaBonusFromIntellect() : 0;
+
+ float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
+ value *= GetModifierValue(unitMod, BASE_PCT);
+ value += GetModifierValue(unitMod, TOTAL_VALUE) + bonusPower;
+ value *= GetModifierValue(unitMod, TOTAL_PCT);
+
+ SetMaxPower(power, uint32(value));
+}
+
+void Player::UpdateAttackPowerAndDamage(bool ranged )
+{
+ float val2 = 0.0f;
+ float level = float(getLevel());
+
+ UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER;
+
+ uint16 index = UNIT_FIELD_ATTACK_POWER;
+ uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MODS;
+ uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER;
+
+ if(ranged)
+ {
+ index = UNIT_FIELD_RANGED_ATTACK_POWER;
+ index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS;
+ index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER;
+
+ switch(getClass())
+ {
+ case CLASS_HUNTER: val2 = level * 2.0f + GetStat(STAT_AGILITY) - 10.0f; break;
+ case CLASS_ROGUE: val2 = level + GetStat(STAT_AGILITY) - 10.0f; break;
+ case CLASS_WARRIOR:val2 = level + GetStat(STAT_AGILITY) - 10.0f; break;
+ case CLASS_DRUID:
+ switch(m_form)
+ {
+ case FORM_CAT:
+ case FORM_BEAR:
+ case FORM_DIREBEAR:
+ val2 = 0.0f; break;
+ default:
+ val2 = GetStat(STAT_AGILITY) - 10.0f; break;
+ }
+ break;
+ default: val2 = GetStat(STAT_AGILITY) - 10.0f; break;
+ }
+ }
+ else
+ {
+ switch(getClass())
+ {
+ case CLASS_WARRIOR: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
+ case CLASS_PALADIN: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
+ case CLASS_ROGUE: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break;
+ case CLASS_HUNTER: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break;
+ case CLASS_SHAMAN: val2 = level*2.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
+ case CLASS_DRUID:
+ {
+ //Check if Predatory Strikes is skilled
+ float mLevelMult = 0.0;
+ switch(m_form)
+ {
+ case FORM_CAT:
+ case FORM_BEAR:
+ case FORM_DIREBEAR:
+ case FORM_MOONKIN:
+ {
+ Unit::AuraList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
+ {
+ // Predatory Strikes
+ if ((*itr)->GetSpellProto()->SpellIconID == 1563)
+ {
+ mLevelMult = (*itr)->GetModifier()->m_amount / 100.0f;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ switch(m_form)
+ {
+ case FORM_CAT:
+ val2 = getLevel()*(mLevelMult+2.0f) + GetStat(STAT_STRENGTH)*2.0f + GetStat(STAT_AGILITY) - 20.0f; break;
+ case FORM_BEAR:
+ case FORM_DIREBEAR:
+ val2 = getLevel()*(mLevelMult+3.0f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
+ case FORM_MOONKIN:
+ val2 = getLevel()*(mLevelMult+1.5f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
+ default:
+ val2 = GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
+ }
+ break;
+ }
+ case CLASS_MAGE: val2 = GetStat(STAT_STRENGTH) - 10.0f; break;
+ case CLASS_PRIEST: val2 = GetStat(STAT_STRENGTH) - 10.0f; break;
+ case CLASS_WARLOCK: val2 = GetStat(STAT_STRENGTH) - 10.0f; break;
+ }
+ }
+
+ SetModifierValue(unitMod, BASE_VALUE, val2);
+
+ float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
+ float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
+
+ //add dynamic flat mods
+ if( ranged && (getClassMask() & CLASSMASK_WAND_USERS)==0)
+ {
+ AuraList const& mRAPbyIntellect = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT);
+ for(AuraList::const_iterator i = mRAPbyIntellect.begin();i != mRAPbyIntellect.end(); ++i)
+ attPowerMod += int32(GetStat(Stats((*i)->GetModifier()->m_miscvalue)) * (*i)->GetModifier()->m_amount / 100.0f);
+ }
+
+ float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
+
+ SetUInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
+ SetUInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
+ SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
+
+ //automatically update weapon damage after attack power modification
+ if(ranged)
+ {
+ UpdateDamagePhysical(RANGED_ATTACK);
+
+ Pet *pet = GetPet(); //update pet's AP
+ if(pet)
+ pet->UpdateAttackPowerAndDamage();
+ }
+ else
+ {
+ UpdateDamagePhysical(BASE_ATTACK);
+ if(CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon
+ UpdateDamagePhysical(OFF_ATTACK);
+ }
+}
+
+void Player::UpdateShieldBlockValue()
+{
+ SetUInt32Value(PLAYER_SHIELD_BLOCK, GetShieldBlockValue());
+}
+
+void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, float& min_damage, float& max_damage)
+{
+ UnitMods unitMod;
+ UnitMods attPower;
+
+ switch(attType)
+ {
+ case BASE_ATTACK:
+ default:
+ unitMod = UNIT_MOD_DAMAGE_MAINHAND;
+ attPower = UNIT_MOD_ATTACK_POWER;
+ break;
+ case OFF_ATTACK:
+ unitMod = UNIT_MOD_DAMAGE_OFFHAND;
+ attPower = UNIT_MOD_ATTACK_POWER;
+ break;
+ case RANGED_ATTACK:
+ unitMod = UNIT_MOD_DAMAGE_RANGED;
+ attPower = UNIT_MOD_ATTACK_POWER_RANGED;
+ break;
+ }
+
+ float att_speed = GetAPMultiplier(attType,normalized);
+
+ float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
+ float base_pct = GetModifierValue(unitMod, BASE_PCT);
+ float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
+ float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
+
+ float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE);
+ float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE);
+
+ if (IsInFeralForm()) //check if player is druid and in cat or bear forms
+ {
+ uint32 lvl = getLevel();
+ if ( lvl > 60 ) lvl = 60;
+
+ weapon_mindamage = lvl*0.85*att_speed;
+ weapon_maxdamage = lvl*1.25*att_speed;
+ }
+ else if(!IsUseEquipedWeapon(attType==BASE_ATTACK)) //check if player not in form but still can't use weapon (broken/etc)
+ {
+ weapon_mindamage = BASE_MINDAMAGE;
+ weapon_maxdamage = BASE_MAXDAMAGE;
+ }
+ else if(attType == RANGED_ATTACK) //add ammo DPS to ranged damage
+ {
+ weapon_mindamage += GetAmmoDPS() * att_speed;
+ weapon_maxdamage += GetAmmoDPS() * att_speed;
+ }
+
+ min_damage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct;
+ max_damage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct;
+}
+
+void Player::UpdateDamagePhysical(WeaponAttackType attType)
+{
+ float mindamage;
+ float maxdamage;
+
+ CalculateMinMaxDamage(attType,false,mindamage,maxdamage);
+
+ switch(attType)
+ {
+ case BASE_ATTACK:
+ default:
+ SetStatFloatValue(UNIT_FIELD_MINDAMAGE,mindamage);
+ SetStatFloatValue(UNIT_FIELD_MAXDAMAGE,maxdamage);
+ break;
+ case OFF_ATTACK:
+ SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE,mindamage);
+ SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE,maxdamage);
+ break;
+ case RANGED_ATTACK:
+ SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE,mindamage);
+ SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE,maxdamage);
+ break;
+ }
+}
+
+void Player::UpdateDefenseBonusesMod()
+{
+ UpdateBlockPercentage();
+ UpdateParryPercentage();
+ UpdateDodgePercentage();
+}
+
+void Player::UpdateBlockPercentage()
+{
+ // No block
+ float value = 0.0f;
+ if(CanBlock())
+ {
+ // Base value
+ value = 5.0f;
+ // Modify value from defense skill
+ value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
+ // Increase from SPELL_AURA_MOD_BLOCK_PERCENT aura
+ value += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT);
+ // Increase from rating
+ value += GetRatingBonusValue(CR_BLOCK);
+ value = value < 0.0f ? 0.0f : value;
+ }
+ SetStatFloatValue(PLAYER_BLOCK_PERCENTAGE, value);
+}
+
+void Player::UpdateCritPercentage(WeaponAttackType attType)
+{
+ BaseModGroup modGroup;
+ uint16 index;
+ CombatRating cr;
+
+ switch(attType)
+ {
+ case OFF_ATTACK:
+ modGroup = OFFHAND_CRIT_PERCENTAGE;
+ index = PLAYER_OFFHAND_CRIT_PERCENTAGE;
+ cr = CR_CRIT_MELEE;
+ break;
+ case RANGED_ATTACK:
+ modGroup = RANGED_CRIT_PERCENTAGE;
+ index = PLAYER_RANGED_CRIT_PERCENTAGE;
+ cr = CR_CRIT_RANGED;
+ break;
+ case BASE_ATTACK:
+ default:
+ modGroup = CRIT_PERCENTAGE;
+ index = PLAYER_CRIT_PERCENTAGE;
+ cr = CR_CRIT_MELEE;
+ break;
+ }
+
+ float value = GetTotalPercentageModValue(modGroup) + GetRatingBonusValue(cr);
+ // Modify crit from weapon skill and maximized defense skill of same level victim difference
+ value += (int32(GetWeaponSkillValue(attType)) - int32(GetMaxSkillValueForLevel())) * 0.04f;
+ value = value < 0.0f ? 0.0f : value;
+ SetStatFloatValue(index, value);
+}
+
+void Player::UpdateAllCritPercentages()
+{
+ float value = GetMeleeCritFromAgility();
+
+ SetBaseModValue(CRIT_PERCENTAGE, PCT_MOD, value);
+ SetBaseModValue(OFFHAND_CRIT_PERCENTAGE, PCT_MOD, value);
+ SetBaseModValue(RANGED_CRIT_PERCENTAGE, PCT_MOD, value);
+
+ UpdateCritPercentage(BASE_ATTACK);
+ UpdateCritPercentage(OFF_ATTACK);
+ UpdateCritPercentage(RANGED_ATTACK);
+}
+
+void Player::UpdateParryPercentage()
+{
+ // No parry
+ float value = 0.0f;
+ if (CanParry())
+ {
+ // Base parry
+ value = 5.0f;
+ // Modify value from defense skill
+ value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
+ // Parry from SPELL_AURA_MOD_PARRY_PERCENT aura
+ value += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT);
+ // Parry from rating
+ value += GetRatingBonusValue(CR_PARRY);
+ value = value < 0.0f ? 0.0f : value;
+ }
+ SetStatFloatValue(PLAYER_PARRY_PERCENTAGE, value);
+}
+
+void Player::UpdateDodgePercentage()
+{
+ // Dodge from agility
+ float value = GetDodgeFromAgility();
+ // Modify value from defense skill
+ value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
+ // Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura
+ value += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT);
+ // Dodge from rating
+ value += GetRatingBonusValue(CR_DODGE);
+ value = value < 0.0f ? 0.0f : value;
+ SetStatFloatValue(PLAYER_DODGE_PERCENTAGE, value);
+}
+
+void Player::UpdateSpellCritChance(uint32 school)
+{
+ // For normal school set zero crit chance
+ if(school == SPELL_SCHOOL_NORMAL)
+ {
+ SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1, 0.0f);
+ return;
+ }
+ // For others recalculate it from:
+ float crit = 0.0f;
+ // Crit from Intellect
+ crit += GetSpellCritFromIntellect();
+ // Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE
+ crit += GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE);
+ // Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
+ crit += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, 1<<school);
+ // Increase crit from spell crit ratings
+ crit += GetRatingBonusValue(CR_CRIT_SPELL);
+
+ // Store crit value
+ SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1 + school, crit);
+}
+
+void Player::UpdateAllSpellCritChances()
+{
+ for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
+ UpdateSpellCritChance(i);
+}
+
+void Player::UpdateExpertise(WeaponAttackType attack)
+{
+ if(attack==RANGED_ATTACK)
+ return;
+
+ int32 expertise = int32(GetRatingBonusValue(CR_EXPERTISE));
+
+ Item *weapon = GetWeaponForAttack(attack);
+
+ AuraList const& expAuras = GetAurasByType(SPELL_AURA_MOD_EXPERTISE);
+ for(AuraList::const_iterator itr = expAuras.begin(); itr != expAuras.end(); ++itr)
+ {
+ // item neutral spell
+ if((*itr)->GetSpellProto()->EquippedItemClass == -1)
+ expertise += (*itr)->GetModifier()->m_amount;
+ // item dependent spell
+ else if(weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellProto()))
+ expertise += (*itr)->GetModifier()->m_amount;
+ }
+
+ if(expertise < 0)
+ expertise = 0;
+
+ switch(attack)
+ {
+ case BASE_ATTACK: SetUInt32Value(PLAYER_EXPERTISE, expertise); break;
+ case OFF_ATTACK: SetUInt32Value(PLAYER_OFFHAND_EXPERTISE, expertise); break;
+ default: break;
+ }
+}
+
+void Player::UpdateManaRegen()
+{
+ float Intellect = GetStat(STAT_INTELLECT);
+ // Mana regen from spirit and intellect
+ float power_regen = sqrt(Intellect) * OCTRegenMPPerSpirit();
+ // Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen
+ power_regen *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, POWER_MANA);
+
+ // Mana regen from SPELL_AURA_MOD_POWER_REGEN aura
+ float power_regen_mp5 = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) / 5.0f;
+
+ // Get bonus from SPELL_AURA_MOD_MANA_REGEN_FROM_STAT aura
+ AuraList const& regenAura = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_FROM_STAT);
+ for(AuraList::const_iterator i = regenAura.begin();i != regenAura.end(); ++i)
+ {
+ Modifier* mod = (*i)->GetModifier();
+ power_regen_mp5 += GetStat(Stats(mod->m_miscvalue)) * mod->m_amount / 500.0f;
+ }
+
+ // Bonus from some dummy auras
+ AuraList const& mDummyAuras = GetAurasByType(SPELL_AURA_PERIODIC_DUMMY);
+ for(AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
+ if((*i)->GetId() == 34074) // Aspect of the Viper
+ {
+ power_regen_mp5 += (*i)->GetModifier()->m_amount * Intellect / 500.0f;
+ // Add regen bonus from level in this dummy
+ power_regen_mp5 += getLevel() * 35 / 100;
+ }
+
+ // Set regen rate in cast state apply only on spirit based regen
+ int32 modManaRegenInterrupt = GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
+ if (modManaRegenInterrupt > 100)
+ modManaRegenInterrupt = 100;
+ SetStatFloatValue(PLAYER_FIELD_MOD_MANA_REGEN_INTERRUPT, power_regen_mp5 + power_regen * modManaRegenInterrupt / 100.0f);
+
+ SetStatFloatValue(PLAYER_FIELD_MOD_MANA_REGEN, power_regen_mp5 + power_regen);
+}
+
+void Player::_ApplyAllStatBonuses()
+{
+ SetCanModifyStats(false);
+
+ _ApplyAllAuraMods();
+ _ApplyAllItemMods();
+
+ SetCanModifyStats(true);
+
+ UpdateAllStats();
+}
+
+void Player::_RemoveAllStatBonuses()
+{
+ SetCanModifyStats(false);
+
+ _RemoveAllItemMods();
+ _RemoveAllAuraMods();
+
+ SetCanModifyStats(true);
+
+ UpdateAllStats();
+}
+
+/*#######################################
+######## ########
+######## MOBS STAT SYSTEM ########
+######## ########
+#######################################*/
+
+bool Creature::UpdateStats(Stats /*stat*/)
+{
+ return true;
+}
+
+bool Creature::UpdateAllStats()
+{
+ UpdateMaxHealth();
+ UpdateAttackPowerAndDamage();
+
+ for(int i = POWER_MANA; i < MAX_POWERS; ++i)
+ UpdateMaxPower(Powers(i));
+
+ for(int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
+ UpdateResistances(i);
+
+ return true;
+}
+
+void Creature::UpdateResistances(uint32 school)
+{
+ if(school > SPELL_SCHOOL_NORMAL)
+ {
+ float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school));
+ SetResistance(SpellSchools(school), int32(value));
+ }
+ else
+ UpdateArmor();
+}
+
+void Creature::UpdateArmor()
+{
+ float value = GetTotalAuraModValue(UNIT_MOD_ARMOR);
+ SetArmor(int32(value));
+}
+
+void Creature::UpdateMaxHealth()
+{
+ float value = GetTotalAuraModValue(UNIT_MOD_HEALTH);
+ SetMaxHealth((uint32)value);
+}
+
+void Creature::UpdateMaxPower(Powers power)
+{
+ UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
+
+ float value = GetTotalAuraModValue(unitMod);
+ SetMaxPower(power, uint32(value));
+}
+
+void Creature::UpdateAttackPowerAndDamage(bool ranged)
+{
+ if(ranged)
+ return;
+
+ //automatically update weapon damage after attack power modification
+ UpdateDamagePhysical(BASE_ATTACK);
+}
+
+void Creature::UpdateDamagePhysical(WeaponAttackType attType)
+{
+ if(attType > BASE_ATTACK)
+ return;
+
+ UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND;
+
+ float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f;
+
+ float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
+ float base_pct = GetModifierValue(unitMod, BASE_PCT);
+ float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
+ float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
+
+ float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
+ float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
+
+ float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct ;
+ float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct ;
+
+ SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage);
+ SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage);
+}
+
+/*#######################################
+######## ########
+######## PETS STAT SYSTEM ########
+######## ########
+#######################################*/
+
+bool Pet::UpdateStats(Stats stat)
+{
+ if(stat > STAT_SPIRIT)
+ return false;
+
+ // value = ((base_value * base_pct) + total_value) * total_pct
+ float value = GetTotalStatValue(stat);
+
+ Unit *owner = GetOwner();
+ if ( stat == STAT_STAMINA )
+ {
+ if(owner)
+ value += float(owner->GetStat(stat)) * 0.3f;
+ }
+ //warlock's and mage's pets gain 30% of owner's intellect
+ else if ( stat == STAT_INTELLECT && getPetType() == SUMMON_PET )
+ {
+ if(owner && (owner->getClass() == CLASS_WARLOCK || owner->getClass() == CLASS_MAGE) )
+ value += float(owner->GetStat(stat)) * 0.3f;
+ }
+
+ SetStat(stat, int32(value));
+
+ switch(stat)
+ {
+ case STAT_STRENGTH: UpdateAttackPowerAndDamage(); break;
+ case STAT_AGILITY: UpdateArmor(); break;
+ case STAT_STAMINA: UpdateMaxHealth(); break;
+ case STAT_INTELLECT: UpdateMaxPower(POWER_MANA); break;
+ case STAT_SPIRIT:
+ default:
+ break;
+ }
+
+ return true;
+}
+
+bool Pet::UpdateAllStats()
+{
+ for (int i = STAT_STRENGTH; i < MAX_STATS; i++)
+ UpdateStats(Stats(i));
+
+ for(int i = POWER_MANA; i < MAX_POWERS; i++)
+ UpdateMaxPower(Powers(i));
+
+ for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
+ UpdateResistances(i);
+
+ return true;
+}
+
+void Pet::UpdateResistances(uint32 school)
+{
+ if(school > SPELL_SCHOOL_NORMAL)
+ {
+ float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school));
+
+ Unit *owner = GetOwner();
+ // hunter and warlock pets gain 40% of owner's resistance
+ if(owner && (getPetType() == HUNTER_PET || getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK))
+ value += float(owner->GetResistance(SpellSchools(school))) * 0.4f;
+
+ SetResistance(SpellSchools(school), int32(value));
+ }
+ else
+ UpdateArmor();
+}
+
+void Pet::UpdateArmor()
+{
+ float value = 0.0f;
+ float bonus_armor = 0.0f;
+ UnitMods unitMod = UNIT_MOD_ARMOR;
+
+ Unit *owner = GetOwner();
+ // hunter and warlock pets gain 35% of owner's armor value
+ if(owner && (getPetType() == HUNTER_PET || getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK))
+ bonus_armor = 0.35f * float(owner->GetArmor());
+
+ value = GetModifierValue(unitMod, BASE_VALUE);
+ value *= GetModifierValue(unitMod, BASE_PCT);
+ value += GetStat(STAT_AGILITY) * 2.0f;
+ value += GetModifierValue(unitMod, TOTAL_VALUE) + bonus_armor;
+ value *= GetModifierValue(unitMod, TOTAL_PCT);
+
+ SetArmor(int32(value));
+}
+
+void Pet::UpdateMaxHealth()
+{
+ UnitMods unitMod = UNIT_MOD_HEALTH;
+ float stamina = GetStat(STAT_STAMINA) - GetCreateStat(STAT_STAMINA);
+
+ float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
+ value *= GetModifierValue(unitMod, BASE_PCT);
+ value += GetModifierValue(unitMod, TOTAL_VALUE) + stamina * 10.0f;
+ value *= GetModifierValue(unitMod, TOTAL_PCT);
+
+ SetMaxHealth((uint32)value);
+}
+
+void Pet::UpdateMaxPower(Powers power)
+{
+ UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
+ float addValue = (power == POWER_MANA) ? GetStat(STAT_INTELLECT) - GetCreateStat(STAT_INTELLECT) : 0.0f;
+
+ float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
+ value *= GetModifierValue(unitMod, BASE_PCT);
+ value += GetModifierValue(unitMod, TOTAL_VALUE) + addValue * 15.0f;
+ value *= GetModifierValue(unitMod, TOTAL_PCT);
+
+ SetMaxPower(power, uint32(value));
+}
+
+void Pet::UpdateAttackPowerAndDamage(bool ranged)
+{
+ if(ranged)
+ return;
+
+ float val = 0.0f;
+ float bonusAP = 0.0f;
+ UnitMods unitMod = UNIT_MOD_ATTACK_POWER;
+
+ if(GetEntry() == 416) // imp's attack power
+ val = GetStat(STAT_STRENGTH) - 10.0f;
+ else
+ val = 2 * GetStat(STAT_STRENGTH) - 20.0f;
+
+ Unit* owner = GetOwner();
+ if( owner && owner->GetTypeId()==TYPEID_PLAYER)
+ {
+ if(getPetType() == HUNTER_PET) //hunter pets benefit from owner's attack power
+ {
+ bonusAP = owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.22f;
+ SetBonusDamage( int32(owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.125f));
+ }
+ //demons benefit from warlocks shadow or fire damage
+ else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK)
+ {
+ 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);
+ 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);
+ int32 maximum = (fire > shadow) ? fire : shadow;
+ if(maximum < 0)
+ maximum = 0;
+ SetBonusDamage( int32(maximum * 0.15f));
+ bonusAP = maximum * 0.57f;
+ }
+ //water elementals benefit from mage's frost damage
+ else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_MAGE)
+ {
+ 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);
+ if(frost < 0)
+ frost = 0;
+ SetBonusDamage( int32(frost * 0.4f));
+ }
+ }
+
+ SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, val + bonusAP);
+
+ //in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB
+ float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
+ float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
+ float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
+
+ //UNIT_FIELD_(RANGED)_ATTACK_POWER field
+ SetUInt32Value(UNIT_FIELD_ATTACK_POWER, (uint32)base_attPower);
+ //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
+ SetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (uint32)attPowerMod);
+ //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
+ SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, attPowerMultiplier);
+
+ //automatically update weapon damage after attack power modification
+ UpdateDamagePhysical(BASE_ATTACK);
+}
+
+void Pet::UpdateDamagePhysical(WeaponAttackType attType)
+{
+ if(attType > BASE_ATTACK)
+ return;
+
+ UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND;
+
+ float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f;
+
+ float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
+ float base_pct = GetModifierValue(unitMod, BASE_PCT);
+ float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
+ float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
+
+ float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
+ float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
+
+ float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct;
+ float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct;
+
+ // Pet's base damage changes depending on happiness
+ if (getPetType() == HUNTER_PET && attType == BASE_ATTACK)
+ {
+ switch(GetHappinessState())
+ {
+ case HAPPY:
+ // 125% of normal damage
+ mindamage = mindamage * 1.25;
+ maxdamage = maxdamage * 1.25;
+ break;
+ case CONTENT:
+ // 100% of normal damage, nothing to modify
+ break;
+ case UNHAPPY:
+ // 75% of normal damage
+ mindamage = mindamage * 0.75;
+ maxdamage = maxdamage * 0.75;
+ break;
+ }
+ }
+
+ SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage);
+ SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage);
+}