diff options
Diffstat (limited to 'src/game/StatSystem.cpp')
-rw-r--r-- | src/game/StatSystem.cpp | 453 |
1 files changed, 294 insertions, 159 deletions
diff --git a/src/game/StatSystem.cpp b/src/game/StatSystem.cpp index ae96953e337..bd283c81fc5 100644 --- a/src/game/StatSystem.cpp +++ b/src/game/StatSystem.cpp @@ -1,7 +1,7 @@ /* - * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * - * Copyright (C) 2008 Trinity <http://www.trinitycore.org/> + * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -51,24 +51,17 @@ bool Player::UpdateStats(Stats 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 intellect currently UpdateArmor(); //SPELL_AURA_MOD_RESISTANCE_OF_INTELLECT_PERCENT, only armor currently break; @@ -78,11 +71,60 @@ bool Player::UpdateStats(Stats stat) default: break; } + + if (stat == STAT_STRENGTH) + { + UpdateAttackPowerAndDamage(false); + if (HasAuraTypeWithMiscvalue(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT, stat)) + UpdateAttackPowerAndDamage(true); + } + else if (stat == STAT_AGILITY) + { + UpdateAttackPowerAndDamage(false); + UpdateAttackPowerAndDamage(true); + } + else + { + // Need update (exist AP from stat auras) + if (HasAuraTypeWithMiscvalue(SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT, stat)) + UpdateAttackPowerAndDamage(false); + if (HasAuraTypeWithMiscvalue(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT, stat)) + UpdateAttackPowerAndDamage(true); + } + UpdateSpellDamageAndHealingBonus(); UpdateManaRegen(); + + // Update ratings in exist SPELL_AURA_MOD_RATING_FROM_STAT and only depends from stat + uint32 mask = 0; + AuraEffectList const& modRatingFromStat = GetAurasByType(SPELL_AURA_MOD_RATING_FROM_STAT); + for(AuraEffectList::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 + for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++) + ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, amount, apply); +} + +void Player::ApplySpellHealingBonus(int32 amount, bool apply) +{ + m_baseSpellHealing+=apply?amount:-amount; + // For speed just update for client + ApplyModUInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, amount, apply); +} + void Player::UpdateSpellDamageAndHealingBonus() { // Magic damage modifiers implemented in Unit::SpellDamageBonus @@ -90,24 +132,24 @@ void Player::UpdateSpellDamageAndHealingBonus() // 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++) + 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++) + for (int i = STAT_STRENGTH; i < MAX_STATS; ++i) { float value = GetTotalStatValue(Stats(i)); SetStat(Stats(i), (int32)value); } - UpdateAttackPowerAndDamage(); - UpdateAttackPowerAndDamage(true); UpdateArmor(); + // calls UpdateAttackPowerAndDamage() in UpdateArmor for SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR + UpdateAttackPowerAndDamage(true); UpdateMaxHealth(); - for(int i = POWER_MANA; i < MAX_POWERS; i++) + for(int i = POWER_MANA; i < MAX_POWERS; ++i) UpdateMaxPower(Powers(i)); UpdateAllCritPercentages(); @@ -118,7 +160,8 @@ bool Player::UpdateAllStats() UpdateManaRegen(); UpdateExpertise(BASE_ATTACK); UpdateExpertise(OFF_ATTACK); - for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) + RecalculateRating(CR_ARMOR_PENETRATION); + for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i) UpdateResistances(i); return true; @@ -150,12 +193,11 @@ void Player::UpdateArmor() 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) + AuraEffectList const& mResbyIntellect = GetAurasByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT); + for(AuraEffectList::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())) * (*i)->GetModifierValue() / 100.0f); + if((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) + value += int32(GetStat(Stats((*i)->GetMiscBValue())) * (*i)->GetAmount() / 100.0f); } value *= GetModifierValue(unitMod, TOTAL_PCT); @@ -165,6 +207,8 @@ void Player::UpdateArmor() Pet *pet = GetPet(); if(pet) pet->UpdateArmor(); + + UpdateAttackPowerAndDamage(); // armor dependent auras update for SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR } float Player::GetHealthBonusFromStamina() @@ -213,6 +257,12 @@ void Player::UpdateMaxPower(Powers power) 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; @@ -253,11 +303,12 @@ void Player::UpdateAttackPowerAndDamage(bool ranged ) { 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_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 @@ -269,13 +320,13 @@ void Player::UpdateAttackPowerAndDamage(bool ranged ) 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) + Unit::AuraEffectList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY); + for(Unit::AuraEffectList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr) { - // Predatory Strikes - if ((*itr)->GetSpellProto()->SpellIconID == 1563) + // Predatory Strikes (effect 0) + if ((*itr)->GetEffIndex()==0 && (*itr)->GetSpellProto()->SpellIconID == 1563) { - mLevelMult = (*itr)->GetModifier()->m_amount / 100.0f; + mLevelMult = (*itr)->GetAmount() / 100.0f; break; } } @@ -286,12 +337,12 @@ void Player::UpdateAttackPowerAndDamage(bool ranged ) switch(m_form) { case FORM_CAT: - val2 = getLevel()*(mLevelMult+2.0f) + GetStat(STAT_STRENGTH)*2.0f + GetStat(STAT_AGILITY) - 20.0f; break; + 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; break; + 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; break; + 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; } @@ -309,26 +360,39 @@ void Player::UpdateAttackPowerAndDamage(bool ranged ) float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE); //add dynamic flat mods - if( ranged && (getClassMask() & CLASSMASK_WAND_USERS)==0) + if( ranged ) + { + if ((getClassMask() & CLASSMASK_WAND_USERS)==0) + { + AuraEffectList const& mRAPbyStat = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT); + for(AuraEffectList::const_iterator i = mRAPbyStat.begin();i != mRAPbyStat.end(); ++i) + attPowerMod += int32(GetStat(Stats((*i)->GetMiscValue())) * (*i)->GetAmount() / 100.0f); + } + } + else { - 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)->GetModifierValue() / 100.0f); + AuraEffectList const& mAPbyStat = GetAurasByType(SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT); + for(AuraEffectList::const_iterator i = mAPbyStat.begin();i != mAPbyStat.end(); ++i) + attPowerMod += int32(GetStat(Stats((*i)->GetMiscValue())) * (*i)->GetAmount() / 100.0f); + + AuraEffectList const& mAPbyArmor = GetAurasByType(SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR); + for(AuraEffectList::const_iterator iter = mAPbyArmor.begin(); iter != mAPbyArmor.end(); ++iter) + // always: ((*i)->GetModifier()->m_miscvalue == 1 == SPELL_SCHOOL_MASK_NORMAL) + attPowerMod += int32(GetArmor() / (*iter)->GetAmount()); } 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 + 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 + Pet *pet = GetPet(); //update pet's AP //automatically update weapon damage after attack power modification if(ranged) { UpdateDamagePhysical(RANGED_ATTACK); - - Pet *pet = GetPet(); //update pet's AP - if(pet) + if(pet && pet->isHunterPet()) // At ranged attack change for hunter pet pet->UpdateAttackPowerAndDamage(); } else @@ -338,6 +402,9 @@ void Player::UpdateAttackPowerAndDamage(bool ranged ) UpdateDamagePhysical(OFF_ATTACK); if(getClass() == CLASS_SHAMAN) // mental quickness UpdateSpellDamageAndHealingBonus(); + + if(pet && pet->IsPetGhoul()) // At ranged attack change for hunter pet + pet->UpdateAttackPowerAndDamage(); } } @@ -386,8 +453,15 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, fl 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) + else if(!CanUseAttackType(attType)) //check if player not in form but still can't use (disarm case) { + //cannot use ranged/off attack, set values to 0 + if (attType != BASE_ATTACK) + { + min_damage=0; + max_damage=0; + return; + } weapon_mindamage = BASE_MINDAMAGE; weapon_maxdamage = BASE_MAXDAMAGE; } @@ -554,9 +628,56 @@ void Player::UpdateSpellCritChance(uint32 school) SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1 + school, crit); } +void Player::UpdateArmorPenetration(int32 amount) +{ + AuraEffectList const& expAuras = GetAurasByType(SPELL_AURA_MOD_ARMOR_PENETRATION_PCT); + for(AuraEffectList::const_iterator itr = expAuras.begin(); itr != expAuras.end(); ++itr) + { + // item neutral spell + if((*itr)->GetSpellProto()->EquippedItemClass == -1) + { + amount *= ((*itr)->GetAmount() + 100.0f) / 100.0f; + continue; + } + + // item dependent spell - check curent weapons + for(int i = 0; i < MAX_ATTACK; ++i) + { + Item *weapon = GetWeaponForAttack(WeaponAttackType(i)); + + if(weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellProto())) + { + amount *= ((*itr)->GetAmount() + 100.0f) / 100.0f; + break; + } + } + } + + // Store Rating Value + SetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_ARMOR_PENETRATION, amount); +} + +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++) + for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i) UpdateSpellCritChance(i); } @@ -569,15 +690,15 @@ void Player::UpdateExpertise(WeaponAttackType attack) Item *weapon = GetWeaponForAttack(attack); - AuraList const& expAuras = GetAurasByType(SPELL_AURA_MOD_EXPERTISE); - for(AuraList::const_iterator itr = expAuras.begin(); itr != expAuras.end(); ++itr) + AuraEffectList const& expAuras = GetAurasByType(SPELL_AURA_MOD_EXPERTISE); + for(AuraEffectList::const_iterator itr = expAuras.begin(); itr != expAuras.end(); ++itr) { // item neutral spell if((*itr)->GetSpellProto()->EquippedItemClass == -1) - expertise += (*itr)->GetModifierValue(); + expertise += (*itr)->GetAmount(); // item dependent spell else if(weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellProto())) - expertise += (*itr)->GetModifierValue(); + expertise += (*itr)->GetAmount(); } if(expertise < 0) @@ -591,6 +712,12 @@ void Player::UpdateExpertise(WeaponAttackType attack) } } +void Player::ApplyManaRegenBonus(int32 amount, bool apply) +{ + m_baseManaRegen+= apply ? amount : -amount; + UpdateManaRegen(); +} + void Player::UpdateManaRegen() { float Intellect = GetStat(STAT_INTELLECT); @@ -600,33 +727,22 @@ void Player::UpdateManaRegen() 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; + 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) + AuraEffectList const& regenAura = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_FROM_STAT); + for(AuraEffectList::const_iterator i = regenAura.begin();i != regenAura.end(); ++i) { - Modifier* mod = (*i)->GetModifier(); - power_regen_mp5 += GetStat(Stats(mod->m_miscvalue)) * (*i)->GetModifierValue() / 500.0f; + power_regen_mp5 += GetStat(Stats((*i)->GetMiscValue())) * (*i)->GetAmount() / 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(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER, power_regen_mp5 + power_regen * modManaRegenInterrupt / 100.0f); - SetStatFloatValue(PLAYER_FIELD_MOD_MANA_REGEN, power_regen_mp5 + power_regen); + SetStatFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER, power_regen_mp5 + power_regen); } void Player::_ApplyAllStatBonuses() @@ -712,74 +828,55 @@ void Creature::UpdateMaxPower(Powers power) void Creature::UpdateAttackPowerAndDamage(bool ranged) { - //automatically update weapon damage after attack power modification + 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) - UpdateDamagePhysical(RANGED_ATTACK); - else { - UpdateDamagePhysical(BASE_ATTACK); - UpdateDamagePhysical(OFF_ATTACK); + 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 + + //automatically update weapon damage after attack power modification + if(ranged) + return; + //automatically update weapon damage after attack power modification + UpdateDamagePhysical(BASE_ATTACK); } void Creature::UpdateDamagePhysical(WeaponAttackType attType) { - UnitMods unitMod; - switch(attType) - { - case BASE_ATTACK: - default: - unitMod = UNIT_MOD_DAMAGE_MAINHAND; - break; - case OFF_ATTACK: - unitMod = UNIT_MOD_DAMAGE_OFFHAND; - break; - case RANGED_ATTACK: - unitMod = UNIT_MOD_DAMAGE_RANGED; - break; - } - - //float att_speed = float(GetAttackTime(attType))/1000.0f; + if(attType > BASE_ATTACK) + return; - float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE); - float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE); + UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND; - //This formula is not correct - //The correct one is (Damage_from_AttackPower + Base_Weapon_Damage) * Multiplier - //We do not know the multiplier, so we assume attack power is about 25% damage - //float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed; - float base_value = GetModifierValue(unitMod, BASE_VALUE) - + (weapon_mindamage + weapon_maxdamage) / 6 - * GetTotalAttackPowerValue(attType) / (getLevel() * 5); + float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType); float base_pct = GetModifierValue(unitMod, BASE_PCT); float total_value = GetModifierValue(unitMod, TOTAL_VALUE); float total_pct = GetModifierValue(unitMod, TOTAL_PCT); + float dmg_multiplier = GetCreatureInfo()->dmg_multiplier; - if(attType == BASE_ATTACK && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED)) - { - weapon_mindamage = 0; - weapon_maxdamage = 0; - } + 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 ; + float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct * dmg_multiplier; + float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct * dmg_multiplier; - 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; - } + SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage); + SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage); } /*####################################### @@ -788,7 +885,16 @@ void Creature::UpdateDamagePhysical(WeaponAttackType attType) ######## ######## #######################################*/ -bool Pet::UpdateStats(Stats stat) +#define ENTRY_IMP 416 +#define ENTRY_VOIDWALKER 1860 +#define ENTRY_SUCCUBUS 1863 +#define ENTRY_FELHUNTER 417 +#define ENTRY_FELGUARD 17252 +#define ENTRY_WATER_ELEMENTAL 510 +#define ENTRY_TREANT 1964 +#define ENTRY_FIRE_ELEMENTAL 15438 + +bool Guardian::UpdateStats(Stats stat) { if(stat > STAT_SPIRIT) return false; @@ -799,13 +905,20 @@ bool Pet::UpdateStats(Stats stat) Unit *owner = GetOwner(); if ( stat == STAT_STAMINA ) { - if(owner) + if(owner->getClass() == CLASS_WARLOCK && isPet()) + value += float(owner->GetStat(STAT_STAMINA)) * 0.75f; + else 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 ) + else if ( stat == STAT_INTELLECT) + { + if(owner->getClass() == CLASS_WARLOCK || owner->getClass() == CLASS_MAGE) + value += float(owner->GetStat(stat)) * 0.3f; + } + else if ( stat == STAT_STRENGTH ) { - if(owner && (owner->getClass() == CLASS_WARLOCK || owner->getClass() == CLASS_MAGE) ) + if (IsPetGhoul()) value += float(owner->GetStat(stat)) * 0.3f; } @@ -825,30 +938,29 @@ bool Pet::UpdateStats(Stats stat) return true; } -bool Pet::UpdateAllStats() +bool Guardian::UpdateAllStats() { - for (int i = STAT_STRENGTH; i < MAX_STATS; i++) + for (int i = STAT_STRENGTH; i < MAX_STATS; ++i) UpdateStats(Stats(i)); - for(int i = POWER_MANA; i < MAX_POWERS; i++) + for(int i = POWER_MANA; i < MAX_POWERS; ++i) UpdateMaxPower(Powers(i)); - for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) + for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i) UpdateResistances(i); return true; } -void Pet::UpdateResistances(uint32 school) +void Guardian::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; + if(isPet()) + value += float(m_owner->GetResistance(SpellSchools(school))) * 0.4f; SetResistance(SpellSchools(school), int32(value)); } @@ -856,16 +968,15 @@ void Pet::UpdateResistances(uint32 school) UpdateArmor(); } -void Pet::UpdateArmor() +void Guardian::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()); + if(isPet()) + bonus_armor = 0.35f * float(m_owner->GetArmor()); value = GetModifierValue(unitMod, BASE_VALUE); value *= GetModifierValue(unitMod, BASE_PCT); @@ -876,34 +987,56 @@ void Pet::UpdateArmor() SetArmor(int32(value)); } -void Pet::UpdateMaxHealth() +void Guardian::UpdateMaxHealth() { UnitMods unitMod = UNIT_MOD_HEALTH; float stamina = GetStat(STAT_STAMINA) - GetCreateStat(STAT_STAMINA); + float multiplicator; + switch(GetEntry()) + { + case ENTRY_IMP: multiplicator = 8.4f; break; + case ENTRY_VOIDWALKER: multiplicator = 11.0f; break; + case ENTRY_SUCCUBUS: multiplicator = 9.1f; break; + case ENTRY_FELHUNTER: multiplicator = 9.5f; break; + case ENTRY_FELGUARD: multiplicator = 11.0f; break; + default: multiplicator = 10.0f; break; + } + float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth(); value *= GetModifierValue(unitMod, BASE_PCT); - value += GetModifierValue(unitMod, TOTAL_VALUE) + stamina * 10.0f; + value += GetModifierValue(unitMod, TOTAL_VALUE) + stamina * multiplicator; value *= GetModifierValue(unitMod, TOTAL_PCT); SetMaxHealth((uint32)value); } -void Pet::UpdateMaxPower(Powers power) +void Guardian::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 multiplicator = 15.0f; + + switch(GetEntry()) + { + case ENTRY_IMP: multiplicator = 4.95f; break; + case ENTRY_VOIDWALKER: + case ENTRY_SUCCUBUS: + case ENTRY_FELHUNTER: + case ENTRY_FELGUARD: multiplicator = 11.5f; break; + default: multiplicator = 15.0f; break; + } 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_VALUE) + addValue * multiplicator; value *= GetModifierValue(unitMod, TOTAL_PCT); SetMaxPower(power, uint32(value)); } -void Pet::UpdateAttackPowerAndDamage(bool ranged) +void Guardian::UpdateAttackPowerAndDamage(bool ranged) { if(ranged) return; @@ -912,7 +1045,7 @@ void Pet::UpdateAttackPowerAndDamage(bool ranged) float bonusAP = 0.0f; UnitMods unitMod = UNIT_MOD_ATTACK_POWER; - if(GetEntry() == 416) // imp's attack power + if(GetEntry() == ENTRY_IMP) // imp's attack power val = GetStat(STAT_STRENGTH) - 10.0f; else val = 2 * GetStat(STAT_STRENGTH) - 20.0f; @@ -920,13 +1053,18 @@ void Pet::UpdateAttackPowerAndDamage(bool ranged) Unit* owner = GetOwner(); if( owner && owner->GetTypeId()==TYPEID_PLAYER) { - if(getPetType() == HUNTER_PET) //hunter pets benefit from owner's attack power + if(isHunterPet()) //hunter pets benefit from owner's attack power { bonusAP = owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.22f; - SetBonusDamage( int32(owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.125f)); + SetBonusDamage( int32(owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.1287f)); + } + else if (IsPetGhoul()) //ghouls benefit from deathknight's attack power (may be summon pet or not) + { + bonusAP = owner->GetTotalAttackPowerValue(BASE_ATTACK) * 0.22f; + SetBonusDamage( int32(owner->GetTotalAttackPowerValue(BASE_ATTACK) * 0.1287f)); } //demons benefit from warlocks shadow or fire damage - else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK) + else if(isPet()) { 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); @@ -937,7 +1075,7 @@ void Pet::UpdateAttackPowerAndDamage(bool ranged) bonusAP = maximum * 0.57f; } //water elementals benefit from mage's frost damage - else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_MAGE) + else if(GetEntry() == ENTRY_WATER_ELEMENTAL) { 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) @@ -954,9 +1092,9 @@ void Pet::UpdateAttackPowerAndDamage(bool ranged) float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f; //UNIT_FIELD_(RANGED)_ATTACK_POWER field - SetUInt32Value(UNIT_FIELD_ATTACK_POWER, (uint32)base_attPower); + SetInt32Value(UNIT_FIELD_ATTACK_POWER, (int32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field - SetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (uint32)attPowerMod); + SetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (int32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, attPowerMultiplier); @@ -964,30 +1102,27 @@ void Pet::UpdateAttackPowerAndDamage(bool ranged) UpdateDamagePhysical(BASE_ATTACK); } -void Pet::UpdateDamagePhysical(WeaponAttackType attType) +void Guardian::UpdateDamagePhysical(WeaponAttackType attType) { if(attType > BASE_ATTACK) return; float bonusDamage = 0.0f; - if(Unit* owner = GetOwner()) + if(m_owner->GetTypeId() == TYPEID_PLAYER) { //force of nature - if(GetEntry() == 1964) + if(GetEntry() == ENTRY_TREANT) { - int32 spellDmg = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_NATURE)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_NATURE); + int32 spellDmg = int32(m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_NATURE)) - m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_NATURE); if(spellDmg > 0) bonusDamage = spellDmg * 0.09f; } //greater fire elemental - else if(GetEntry() == 15438) + else if(GetEntry() == ENTRY_FIRE_ELEMENTAL) { - if(Unit* shaman = owner->GetOwner()) - { - int32 spellDmg = int32(shaman->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE)) - shaman->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FIRE); - if(spellDmg > 0) - bonusDamage = spellDmg * 0.4f; - } + int32 spellDmg = int32(m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE)) - m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FIRE); + if(spellDmg > 0) + bonusDamage = spellDmg * 0.4f; } } @@ -1007,9 +1142,9 @@ void Pet::UpdateDamagePhysical(WeaponAttackType attType) 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) + if (isHunterPet() && attType == BASE_ATTACK) { - switch(GetHappinessState()) + switch(((Pet*)this)->GetHappinessState()) { case HAPPY: // 125% of normal damage |