From 95b91afbab455d917a2800d8936e1f29e4d9604d Mon Sep 17 00:00:00 2001 From: Neo2003 Date: Sat, 11 Oct 2008 14:16:25 -0500 Subject: [svn] * svn:eol-style native set on all files that need it --HG-- branch : trunk --- src/game/StatSystem.cpp | 1930 +++++++++++++++++++++++------------------------ 1 file changed, 965 insertions(+), 965 deletions(-) (limited to 'src/game/StatSystem.cpp') diff --git a/src/game/StatSystem.cpp b/src/game/StatSystem.cpp index 951a92cb5ad..eda78f95033 100644 --- a/src/game/StatSystem.cpp +++ b/src/game/StatSystem.cpp @@ -1,965 +1,965 @@ -/* - * Copyright (C) 2005-2008 MaNGOS - * - * 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<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 + * + * 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<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); +} -- cgit v1.2.3