mirror of
https://github.com/mangosfour/server.git
synced 2025-12-12 19:37:03 +00:00
1051 lines
36 KiB
C++
1051 lines
36 KiB
C++
/*
|
|
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
|
*
|
|
* 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:
|
|
UpdateShieldBlockValue();
|
|
break;
|
|
case STAT_AGILITY:
|
|
UpdateArmor();
|
|
UpdateAllCritPercentages();
|
|
UpdateDodgePercentage();
|
|
break;
|
|
case STAT_STAMINA: UpdateMaxHealth(); break;
|
|
case STAT_INTELLECT:
|
|
UpdateMaxPower(POWER_MANA);
|
|
UpdateAllSpellCritChances();
|
|
UpdateArmor(); //SPELL_AURA_MOD_RESISTANCE_OF_INTELLECT_PERCENT, only armor currently
|
|
break;
|
|
|
|
case STAT_SPIRIT:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
// Need update (exist AP from stat auras)
|
|
UpdateAttackPowerAndDamage();
|
|
UpdateAttackPowerAndDamage(true);
|
|
|
|
UpdateSpellDamageAndHealingBonus();
|
|
UpdateManaRegen();
|
|
|
|
// Update ratings in exist SPELL_AURA_MOD_RATING_FROM_STAT and only depends from stat
|
|
uint32 mask = 0;
|
|
AuraList const& modRatingFromStat = GetAurasByType(SPELL_AURA_MOD_RATING_FROM_STAT);
|
|
for(AuraList::const_iterator i = modRatingFromStat.begin();i != modRatingFromStat.end(); ++i)
|
|
if (Stats((*i)->GetMiscBValue()) == stat)
|
|
mask |= (*i)->GetMiscValue();
|
|
if (mask)
|
|
{
|
|
for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
|
|
if (mask & (1 << rating))
|
|
ApplyRatingMod(CombatRating(rating), 0, true);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void Player::ApplySpellDamageBonus(int32 amount, bool apply)
|
|
{
|
|
m_baseSpellDamage+=apply?amount:-amount;
|
|
// For speed just update for client
|
|
ApplyModUInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, amount, apply);
|
|
}
|
|
|
|
void Player::ApplySpellHealingBonus(int32 amount, bool apply)
|
|
{
|
|
m_baseSpellHealing+=apply?amount:-amount;
|
|
// For speed just update for client
|
|
for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
|
|
ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, amount, apply);;
|
|
}
|
|
|
|
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::ApplyFeralAPBonus(int32 amount, bool apply)
|
|
{
|
|
m_baseFeralAP+= apply ? amount:-amount;
|
|
UpdateAttackPowerAndDamage();
|
|
}
|
|
|
|
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_DEATH_KNIGHT: 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) + GetStat(STAT_AGILITY) - 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 + m_baseFeralAP; break;
|
|
case FORM_BEAR:
|
|
case FORM_DIREBEAR:
|
|
val2 = getLevel()*(mLevelMult+3.0f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f + m_baseFeralAP; break;
|
|
case FORM_MOONKIN:
|
|
val2 = getLevel()*(mLevelMult+1.5f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f + m_baseFeralAP; 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 )
|
|
{
|
|
if ((getClassMask() & CLASSMASK_WAND_USERS)==0)
|
|
{
|
|
AuraList const& mRAPbyStat = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT);
|
|
for(AuraList::const_iterator i = mRAPbyStat.begin();i != mRAPbyStat.end(); ++i)
|
|
attPowerMod += int32(GetStat(Stats((*i)->GetModifier()->m_miscvalue)) * (*i)->GetModifier()->m_amount / 100.0f);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AuraList const& mAPbyStat = GetAurasByType(SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT);
|
|
for(AuraList::const_iterator i = mAPbyStat.begin();i != mAPbyStat.end(); ++i)
|
|
attPowerMod += int32(GetStat(Stats((*i)->GetModifier()->m_miscvalue)) * (*i)->GetModifier()->m_amount / 100.0f);
|
|
}
|
|
|
|
float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
|
|
|
|
SetInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
|
|
SetInt32Value(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::UpdateMeleeHitChances()
|
|
{
|
|
m_modMeleeHitChance = GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE);
|
|
m_modMeleeHitChance+= GetRatingBonusValue(CR_HIT_MELEE);
|
|
}
|
|
|
|
void Player::UpdateRangedHitChances()
|
|
{
|
|
m_modRangedHitChance = GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE);
|
|
m_modRangedHitChance+= GetRatingBonusValue(CR_HIT_RANGED);
|
|
}
|
|
|
|
void Player::UpdateSpellHitChances()
|
|
{
|
|
m_modSpellHitChance = GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HIT_CHANCE);
|
|
m_modSpellHitChance+= GetRatingBonusValue(CR_HIT_SPELL);
|
|
}
|
|
|
|
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::ApplyManaRegenBonus(int32 amount, bool apply)
|
|
{
|
|
m_baseManaRegen+= apply ? amount : -amount;
|
|
UpdateManaRegen();
|
|
}
|
|
|
|
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) + m_baseManaRegen) / 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(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER, power_regen_mp5 + power_regen * modManaRegenInterrupt / 100.0f);
|
|
|
|
SetStatFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER, 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)
|
|
{
|
|
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;
|
|
}
|
|
|
|
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;
|
|
|
|
SetInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
|
|
SetInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
|
|
SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
|
|
|
|
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.1287f));
|
|
}
|
|
//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
|
|
SetInt32Value(UNIT_FIELD_ATTACK_POWER, (int32)base_attPower);
|
|
//UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
|
|
SetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (int32)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);
|
|
}
|