diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h index 241042647c..3bce36ed20 100644 --- a/src/common/Utilities/Util.h +++ b/src/common/Utilities/Util.h @@ -67,13 +67,6 @@ TC_COMMON_API uint32 TimeStringToSecs(std::string const& timestring); TC_COMMON_API std::string TimeToTimestampStr(time_t t); TC_COMMON_API std::string TimeToHumanReadable(time_t t); -inline void ApplyPercentModFloatVar(float& var, float val, bool apply) -{ - if (val == -100.0f) // prevent set var to zero - val = -99.99f; - var *= (apply ? (100.0f + val) / 100.0f : 100.0f / (100.0f + val)); -} - // Percentage calculation template inline T CalculatePct(T base, U pct) diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 0f1f4559c9..e6e1737c61 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -610,12 +610,12 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/, SetHealth(previousHealth); SetMeleeDamageSchool(SpellSchools(cInfo->dmgschool)); - SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_HOLY])); - SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_FIRE])); - SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_NATURE])); - SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_FROST])); - SetModifierValue(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_SHADOW])); - SetModifierValue(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_ARCANE])); + SetStatFlatModifier(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_HOLY])); + SetStatFlatModifier(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_FIRE])); + SetStatFlatModifier(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_NATURE])); + SetStatFlatModifier(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_FROST])); + SetStatFlatModifier(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_SHADOW])); + SetStatFlatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_ARCANE])); SetCanModifyStats(true); UpdateAllStats(); @@ -1420,7 +1420,7 @@ void Creature::UpdateLevelDependantStats() break; } - SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)health); + SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, (float)health); // damage float basedamage = stats->GenerateBaseDamage(cInfo); @@ -1437,11 +1437,11 @@ void Creature::UpdateLevelDependantStats() SetBaseWeaponDamage(RANGED_ATTACK, MINDAMAGE, weaponBaseMinDamage); SetBaseWeaponDamage(RANGED_ATTACK, MAXDAMAGE, weaponBaseMaxDamage); - SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, stats->AttackPower); - SetModifierValue(UNIT_MOD_ATTACK_POWER_RANGED, BASE_VALUE, stats->RangedAttackPower); + SetStatFlatModifier(UNIT_MOD_ATTACK_POWER, BASE_VALUE, stats->AttackPower); + SetStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, BASE_VALUE, stats->RangedAttackPower); float armor = (float)stats->GenerateArmor(cInfo); /// @todo Why is this treated as uint32 when it's a float? - SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, armor); + SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, armor); } float Creature::_GetHealthMod(int32 Rank) diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 982156579e..2d17adc377 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -163,7 +163,7 @@ class TC_GAME_API Creature : public Unit, public GridObject, public Ma void UpdateMaxPower(Powers power) override; uint32 GetPowerIndex(Powers power) const override; void UpdateAttackPowerAndDamage(bool ranged = false) override; - void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) override; + void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) const override; void UpdatePowerRegeneration(Powers powerType) override; void SetCanDualWield(bool value) override; diff --git a/src/server/game/Entities/Creature/TemporarySummon.h b/src/server/game/Entities/Creature/TemporarySummon.h index 1a9069ab42..39de736d89 100644 --- a/src/server/game/Entities/Creature/TemporarySummon.h +++ b/src/server/game/Entities/Creature/TemporarySummon.h @@ -129,6 +129,7 @@ class TC_GAME_API Guardian : public Minion void UpdateDamagePhysical(WeaponAttackType attType) override; int32 GetBonusDamage() const { return m_bonusSpellDamage; } + float GetBonusStatFromOwner(Stats stat) const { return m_statFromOwner[stat]; } void SetBonusDamage(int32 damage); protected: int32 m_bonusSpellDamage; diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 8c691821b8..42da86c8f3 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -982,13 +982,6 @@ void Object::ApplyModSignedFloatValue(uint16 index, float val, bool apply) SetFloatValue(index, cur); } -void Object::ApplyPercentModFloatValue(uint16 index, float val, bool apply) -{ - float value = GetFloatValue(index); - ApplyPercentModFloatVar(value, val, apply); - SetFloatValue(index, value); -} - void Object::ApplyModPositiveFloatValue(uint16 index, float val, bool apply) { float cur = GetFloatValue(index); diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 8d2c05a97b..d37e78b32d 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -119,7 +119,6 @@ class TC_GAME_API Object void ApplyModUInt64Value(uint16 index, int32 val, bool apply); void ApplyModPositiveFloatValue(uint16 index, float val, bool apply); void ApplyModSignedFloatValue(uint16 index, float val, bool apply); - void ApplyPercentModFloatValue(uint16 index, float val, bool apply); void SetFlag(uint16 index, uint32 newFlag); void RemoveFlag(uint16 index, uint32 oldFlag); diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 7e5493a776..0ab1389d6a 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -801,7 +801,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel) // Hunters pets should not inherit resistances from creature_template, they have separate auras for that if (!IsHunterPet()) for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) - SetModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_VALUE, float(cinfo->resistance[i])); + SetStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_VALUE, float(cinfo->resistance[i])); // Health, mana, armor and resistance PetLevelInfo const* pInfo = sObjectMgr->GetPetLevelInfo(creature_ID, petlevel); @@ -811,7 +811,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel) SetCreateMana(pInfo->mana); if (pInfo->armor > 0) - SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor)); + SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor)); for (uint8 stat = 0; stat < MAX_STATS; ++stat) SetCreateStat(Stats(stat), float(pInfo->stats[stat])); @@ -945,8 +945,8 @@ bool Guardian::InitStatsForLevel(uint8 petlevel) SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, m_owner->GetTotalAttackPowerValue(BASE_ATTACK) * dmg_multiplier / 14); SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, m_owner->GetTotalAttackPowerValue(BASE_ATTACK) * dmg_multiplier / 14); - SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(GetOwner()->GetArmor()) * 0.35f); // Bonus Armor (35% of player armor) - SetModifierValue(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(GetOwner()->GetStat(STAT_STAMINA)) * 0.3f); // Bonus Stamina (30% of player stamina) + SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(GetOwner()->GetArmor()) * 0.35f); // Bonus Armor (35% of player armor) + SetStatFlatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(GetOwner()->GetStat(STAT_STAMINA)) * 0.3f); // Bonus Stamina (30% of player stamina) if (!HasAura(58877)) // Spirit Hunt AddAura(58877, this); if (!HasAura(61783)) // Feral Pet Scaling @@ -1003,7 +1003,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel) float attackPower = ((minDamage + maxDamage) /4) * 7; SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, minDamage); SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, maxDamage); - SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, attackPower); + SetStatFlatModifier(UNIT_MOD_ATTACK_POWER, BASE_VALUE, attackPower); SetCreateHealth(m_owner->CountPctFromMaxHealth(40)); break; } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index b08a789dd4..a7190788d1 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -295,8 +295,8 @@ Player::Player(WorldSession* session): Unit(true) for (uint8 i = 0; i < BASEMOD_END; ++i) { - m_auraBaseMod[i][FLAT_MOD] = 0.0f; - m_auraBaseMod[i][PCT_MOD] = 1.0f; + m_auraBaseFlatMod[i] = 0.0f; + m_auraBasePctMod[i] = 1.0f; } for (uint8 i = 0; i < MAX_COMBAT_RATING; i++) @@ -2536,14 +2536,14 @@ void Player::InitStatsForLevel(bool reapplyMods) // set armor (resistance 0) to original value (create_agility*2) SetArmor(int32(m_createStats[STAT_AGILITY]*2)); - SetResistanceBuffMods(SpellSchools(0), true, 0.0f); - SetResistanceBuffMods(SpellSchools(0), false, 0.0f); + SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + SPELL_SCHOOL_NORMAL, 0.0f); + SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + SPELL_SCHOOL_NORMAL, 0.0f); // set other resistance to original value (0) for (uint8 i = 1; i < MAX_SPELL_SCHOOL; ++i) { SetResistance(SpellSchools(i), 0); - SetResistanceBuffMods(SpellSchools(i), true, 0.0f); - SetResistanceBuffMods(SpellSchools(i), false, 0.0f); + SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + i, 0.0f); + SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + i, 0.0f); } SetUInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE, 0); @@ -4711,20 +4711,104 @@ void Player::LeaveLFGChannel() } } -void Player::HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, float amount, bool apply) +void Player::HandleBaseModFlatValue(BaseModGroup modGroup, float amount, bool apply) { - if (modGroup >= BASEMOD_END || modType >= MOD_END) + if (modGroup >= BASEMOD_END) { TC_LOG_ERROR("spells", "Player::HandleBaseModValue: Invalid BaseModGroup/BaseModType (%u/%u) for player '%s' (%s)", - modGroup, modType, GetName().c_str(), GetGUID().ToString().c_str()); + modGroup, FLAT_MOD, GetName().c_str(), GetGUID().ToString().c_str()); return; } - if (modType == FLAT_MOD) - m_auraBaseMod[modGroup][modType] += apply ? amount : -amount; - else // PCT_MOD - ApplyPercentModFloatVar(m_auraBaseMod[modGroup][modType], amount, apply); + m_auraBaseFlatMod[modGroup] += apply ? amount : -amount; + UpdateBaseModGroup(modGroup); +} +void Player::ApplyBaseModPctValue(BaseModGroup modGroup, float pct) +{ + if (modGroup >= BASEMOD_END) + { + TC_LOG_ERROR("spells", "Player::HandleBaseModValue: Invalid BaseModGroup/BaseModType (%u/%u) for player '%s' (%s)", + modGroup, FLAT_MOD, GetName().c_str(), GetGUID().ToString().c_str()); + return; + } + + AddPct(m_auraBasePctMod[modGroup], pct); + UpdateBaseModGroup(modGroup); +} + +void Player::SetBaseModFlatValue(BaseModGroup modGroup, float val) +{ + if (m_auraBaseFlatMod[modGroup] == val) + return; + + m_auraBaseFlatMod[modGroup] = val; + UpdateBaseModGroup(modGroup); +} + +void Player::SetBaseModPctValue(BaseModGroup modGroup, float val) +{ + if (m_auraBasePctMod[modGroup] == val) + return; + + m_auraBasePctMod[modGroup] = val; + UpdateBaseModGroup(modGroup); +} + +void Player::UpdateDamageDoneMods(WeaponAttackType attackType) +{ + Unit::UpdateDamageDoneMods(attackType); + + UnitMods unitMod; + switch (attackType) + { + case BASE_ATTACK: + unitMod = UNIT_MOD_DAMAGE_MAINHAND; + break; + case OFF_ATTACK: + unitMod = UNIT_MOD_DAMAGE_OFFHAND; + break; + case RANGED_ATTACK: + unitMod = UNIT_MOD_DAMAGE_RANGED; + break; + default: + ABORT(); + break; + } + + float amount = 0.0f; + Item* item = GetWeaponForAttack(attackType, true); + if (!item) + return; + + for (uint8 slot = 0; slot < MAX_ENCHANTMENT_SLOT; ++slot) + { + SpellItemEnchantmentEntry const* enchantmentEntry = sSpellItemEnchantmentStore.LookupEntry(item->GetEnchantmentId(EnchantmentSlot(slot))); + if (!enchantmentEntry) + continue; + + for (uint8 i = 0; i < MAX_ITEM_ENCHANTMENT_EFFECTS; ++i) + { + switch (enchantmentEntry->Effect[i]) + { + case ITEM_ENCHANTMENT_TYPE_DAMAGE: + amount += enchantmentEntry->EffectPointsMin[i]; + break; + case ITEM_ENCHANTMENT_TYPE_TOTEM: + if (getClass() == CLASS_SHAMAN) + amount += enchantmentEntry->EffectPointsMin[i] * item->GetTemplate()->GetDelay() / 1000.0f; + break; + default: + break; + } + } + } + + HandleStatFlatModifier(unitMod, TOTAL_VALUE, amount, true); +} + +void Player::UpdateBaseModGroup(BaseModGroup modGroup) +{ if (!CanModifyStats()) return; @@ -4746,10 +4830,7 @@ float Player::GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const return 0.0f; } - if (modType == PCT_MOD && m_auraBaseMod[modGroup][PCT_MOD] <= 0.0f) - return 0.0f; - - return m_auraBaseMod[modGroup][modType]; + return (modType == FLAT_MOD ? m_auraBaseFlatMod[modGroup] : m_auraBasePctMod[modGroup]); } float Player::GetTotalBaseModValue(BaseModGroup modGroup) const @@ -4761,10 +4842,7 @@ float Player::GetTotalBaseModValue(BaseModGroup modGroup) const return 0.0f; } - if (m_auraBaseMod[modGroup][PCT_MOD] <= 0.0f) - return 0.0f; - - return m_auraBaseMod[modGroup][FLAT_MOD] * m_auraBaseMod[modGroup][PCT_MOD]; + return m_auraBaseFlatMod[modGroup] * m_auraBasePctMod[modGroup]; } float Player::GetMeleeCritFromAgility() const @@ -4839,7 +4917,7 @@ void Player::GetDodgeFromAgility(float &diminishing, float &nondiminishing) cons if (!dodgeRatio || playerClass > MAX_CLASSES) return; - float baseAgility = GetCreateStat(STAT_AGILITY) * m_auraModifiersGroup[UNIT_MOD_STAT_START + STAT_AGILITY][BASE_PCT]; + float baseAgility = GetCreateStat(STAT_AGILITY) * GetPctModifierValue(UnitMods(UNIT_MOD_STAT_START + STAT_AGILITY), BASE_PCT); float bonusAgility = GetStat(STAT_AGILITY) - baseAgility; // calculate diminishing (green in char screen) and non-diminishing (white) contribution @@ -5043,7 +5121,7 @@ void Player::UpdateRating(CombatRating cr) void Player::UpdateAllRatings() { - for (int cr = 0; cr < MAX_COMBAT_RATING; ++cr) + for (uint8 cr = 0; cr < MAX_COMBAT_RATING; ++cr) UpdateRating(CombatRating(cr)); } @@ -7297,8 +7375,14 @@ void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply, bool updateItemA _ApplyItemBonuses(proto, slot, apply); ApplyItemEquipSpell(item, apply); if (updateItemAuras) + { ApplyItemDependentAuras(item, apply); + WeaponAttackType const attackType = Player::GetAttackBySlot(slot); + if (attackType != MAX_ATTACK) + UpdateWeaponDependentAuras(attackType); + } + ApplyEnchantment(item, apply); TC_LOG_DEBUG("entities.player.items", "Player::_ApplyItemMods: completed"); @@ -7338,30 +7422,30 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply switch (statID) { case ITEM_MOD_MANA: - HandleStatModifier(UNIT_MOD_MANA, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, float(val), apply); break; case ITEM_MOD_HEALTH: // modify HP - HandleStatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(val), apply); break; case ITEM_MOD_AGILITY: // modify agility - HandleStatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_AGILITY, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); + UpdateStatBuffMod(STAT_AGILITY); break; case ITEM_MOD_STRENGTH: //modify strength - HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_STRENGTH, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); + UpdateStatBuffMod(STAT_STRENGTH); break; case ITEM_MOD_INTELLECT: //modify intellect - HandleStatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_INTELLECT, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); + UpdateStatBuffMod(STAT_INTELLECT); break; case ITEM_MOD_SPIRIT: //modify spirit - HandleStatModifier(UNIT_MOD_STAT_SPIRIT, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_SPIRIT, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_STAT_SPIRIT, BASE_VALUE, float(val), apply); + UpdateStatBuffMod(STAT_SPIRIT); break; case ITEM_MOD_STAMINA: //modify stamina - HandleStatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_STAMINA, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(val), apply); + UpdateStatBuffMod(STAT_STAMINA); break; case ITEM_MOD_DEFENSE_SKILL_RATING: ApplyRatingMod(CR_DEFENSE_SKILL, int32(val), apply); @@ -7452,11 +7536,11 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply ApplyRatingMod(CR_EXPERTISE, int32(val), apply); break; case ITEM_MOD_ATTACK_POWER: - HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(val), apply); - HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(val), apply);(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(val), apply);(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply); break; case ITEM_MOD_RANGED_ATTACK_POWER: - HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(val), apply);(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply); break; case ITEM_MOD_MANA_REGENERATION: ApplyManaRegenBonus(int32(val), apply); @@ -7477,22 +7561,22 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply ApplyRatingMod(CR_MASTERY, int32(val), apply); break; case ITEM_MOD_FIRE_RESISTANCE: - HandleStatModifier(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(val), apply); break; case ITEM_MOD_FROST_RESISTANCE: - HandleStatModifier(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(val), apply); break; case ITEM_MOD_HOLY_RESISTANCE: - HandleStatModifier(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(val), apply); break; case ITEM_MOD_SHADOW_RESISTANCE: - HandleStatModifier(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(val), apply); break; case ITEM_MOD_NATURE_RESISTANCE: - HandleStatModifier(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(val), apply); break; case ITEM_MOD_ARCANE_RESISTANCE: - HandleStatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(val), apply); + HandleStatFlatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(val), apply); break; } } @@ -7509,7 +7593,7 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply if (armor) { - UnitModifierType modType = TOTAL_VALUE; + UnitModifierFlatType modType = TOTAL_VALUE; if (proto->GetClass() == ITEM_CLASS_ARMOR) { switch (proto->GetSubClass()) @@ -7523,12 +7607,12 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply break; } } - HandleStatModifier(UNIT_MOD_ARMOR, modType, float(armor), apply); + HandleStatFlatModifier(UNIT_MOD_ARMOR, modType, float(armor), apply); } // Add armor bonus from ArmorDamageModifier if > 0 if (proto->GetArmorDamageModifier() > 0) - HandleStatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(proto->GetArmorDamageModifier()), apply); + HandleStatFlatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(proto->GetArmorDamageModifier()), apply); WeaponAttackType attType = BASE_ATTACK; @@ -7647,6 +7731,49 @@ void Player::ApplyItemObtainSpells(Item* item, bool apply) } } +// this one rechecks weapon auras and stores them in BaseModGroup container +// needed for things like axe specialization applying only to axe weapons in case of dual-wield +void Player::UpdateWeaponDependentCritAuras(WeaponAttackType attackType) +{ + BaseModGroup modGroup; + switch (attackType) + { + case BASE_ATTACK: + modGroup = CRIT_PERCENTAGE; + break; + case OFF_ATTACK: + modGroup = OFFHAND_CRIT_PERCENTAGE; + break; + case RANGED_ATTACK: + modGroup = RANGED_CRIT_PERCENTAGE; + break; + default: + ABORT(); + break; + } + + float amount = 0.0f; + amount += GetTotalAuraModifier(SPELL_AURA_MOD_WEAPON_CRIT_PERCENT, std::bind(&Unit::CheckAttackFitToAuraRequirement, this, attackType, std::placeholders::_1)); + + // these auras don't have item requirement (only Combat Expertise in 3.3.5a) + amount += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PCT); + + SetBaseModFlatValue(modGroup, amount); +} + +void Player::UpdateAllWeaponDependentCritAuras() +{ + for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i) + UpdateWeaponDependentCritAuras(WeaponAttackType(i)); +} + +void Player::UpdateWeaponDependentAuras(WeaponAttackType attackType) +{ + UpdateWeaponDependentCritAuras(attackType); + UpdateDamageDoneMods(attackType); + UpdateDamagePctDoneMods(attackType); +} + void Player::ApplyItemDependentAuras(Item* item, bool apply) { if (apply) @@ -8075,6 +8202,11 @@ void Player::_ApplyAllItemMods() ApplyItemDependentAuras(m_items[i], true); _ApplyItemBonuses(proto, i, true); + + WeaponAttackType const attackType = Player::GetAttackBySlot(i); + if (attackType != MAX_ATTACK) + UpdateWeaponDependentAuras(attackType); + } } @@ -9729,7 +9861,7 @@ Item* Player::GetShield(bool useable) const return item; } -uint8 Player::GetAttackBySlot(uint8 slot) +WeaponAttackType Player::GetAttackBySlot(uint8 slot) { switch (slot) { @@ -13052,30 +13184,30 @@ void Player::ApplyReforgeEnchantment(Item* item, bool apply) switch (reforge->Source_stat) { case ITEM_MOD_MANA: - HandleStatModifier(UNIT_MOD_MANA, BASE_VALUE, -removeValue, apply); + HandleStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, -removeValue, apply); break; case ITEM_MOD_HEALTH: - HandleStatModifier(UNIT_MOD_HEALTH, BASE_VALUE, -removeValue, apply); + HandleStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, -removeValue, apply); break; case ITEM_MOD_AGILITY: - HandleStatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, -removeValue, apply); - ApplyStatBuffMod(STAT_AGILITY, -removeValue, apply); + HandleStatFlatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, -removeValue, apply); + UpdateStatBuffMod(STAT_AGILITY); break; case ITEM_MOD_STRENGTH: - HandleStatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, -removeValue, apply); - ApplyStatBuffMod(STAT_STRENGTH, -removeValue, apply); + HandleStatFlatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, -removeValue, apply); + UpdateStatBuffMod(STAT_STRENGTH); break; case ITEM_MOD_INTELLECT: - HandleStatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, -removeValue, apply); - ApplyStatBuffMod(STAT_INTELLECT, -removeValue, apply); + HandleStatFlatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, -removeValue, apply); + UpdateStatBuffMod(STAT_INTELLECT); break; case ITEM_MOD_SPIRIT: - HandleStatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, -removeValue, apply); - ApplyStatBuffMod(STAT_SPIRIT, -removeValue, apply); + HandleStatFlatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, -removeValue, apply); + UpdateStatBuffMod(STAT_SPIRIT); break; case ITEM_MOD_STAMINA: - HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, -removeValue, apply); - ApplyStatBuffMod(STAT_STAMINA, -removeValue, apply); + HandleStatFlatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, -removeValue, apply); + UpdateStatBuffMod(STAT_STAMINA); break; case ITEM_MOD_DEFENSE_SKILL_RATING: ApplyRatingMod(CR_DEFENSE_SKILL, -int32(removeValue), apply); @@ -13132,11 +13264,11 @@ void Player::ApplyReforgeEnchantment(Item* item, bool apply) ApplyRatingMod(CR_EXPERTISE, -int32(removeValue), apply); break; case ITEM_MOD_ATTACK_POWER: - HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, -removeValue, apply); - HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, -removeValue, apply); + HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, -removeValue, apply); + HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, -removeValue, apply); break; case ITEM_MOD_RANGED_ATTACK_POWER: - HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, -removeValue, apply); + HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, -removeValue, apply); break; case ITEM_MOD_MANA_REGENERATION: ApplyManaRegenBonus(-int32(removeValue), apply); @@ -13155,7 +13287,7 @@ void Player::ApplyReforgeEnchantment(Item* item, bool apply) m_spellPenetrationItemMod += apply ? -int32(removeValue) : int32(removeValue); break; case ITEM_MOD_BLOCK_VALUE: - HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, -removeValue, apply); + HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, -removeValue, apply); break; case ITEM_MOD_MASTERY_RATING: ApplyRatingMod(CR_MASTERY, -int32(removeValue), apply); @@ -13165,30 +13297,30 @@ void Player::ApplyReforgeEnchantment(Item* item, bool apply) switch (reforge->Target_stat) { case ITEM_MOD_MANA: - HandleStatModifier(UNIT_MOD_MANA, BASE_VALUE, addValue, apply); + HandleStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, addValue, apply); break; case ITEM_MOD_HEALTH: - HandleStatModifier(UNIT_MOD_HEALTH, BASE_VALUE, addValue, apply); + HandleStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, addValue, apply); break; case ITEM_MOD_AGILITY: - HandleStatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, addValue, apply); - ApplyStatBuffMod(STAT_AGILITY, addValue, apply); + HandleStatFlatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, addValue, apply); + UpdateStatBuffMod(STAT_AGILITY); break; case ITEM_MOD_STRENGTH: - HandleStatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, addValue, apply); - ApplyStatBuffMod(STAT_STRENGTH, addValue, apply); + HandleStatFlatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, addValue, apply); + UpdateStatBuffMod(STAT_STRENGTH); break; case ITEM_MOD_INTELLECT: - HandleStatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, addValue, apply); - ApplyStatBuffMod(STAT_INTELLECT, addValue, apply); + HandleStatFlatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, addValue, apply); + UpdateStatBuffMod(STAT_INTELLECT); break; case ITEM_MOD_SPIRIT: - HandleStatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, addValue, apply); - ApplyStatBuffMod(STAT_SPIRIT, addValue, apply); + HandleStatFlatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, addValue, apply); + UpdateStatBuffMod(STAT_SPIRIT); break; case ITEM_MOD_STAMINA: - HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, addValue, apply); - ApplyStatBuffMod(STAT_STAMINA, addValue, apply); + HandleStatFlatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, addValue, apply); + UpdateStatBuffMod(STAT_STAMINA); break; case ITEM_MOD_DEFENSE_SKILL_RATING: ApplyRatingMod(CR_DEFENSE_SKILL, int32(addValue), apply); @@ -13245,11 +13377,11 @@ void Player::ApplyReforgeEnchantment(Item* item, bool apply) ApplyRatingMod(CR_EXPERTISE, int32(addValue), apply); break; case ITEM_MOD_ATTACK_POWER: - HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, addValue, apply); - HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, addValue, apply); + HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, addValue, apply); + HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, addValue, apply); break; case ITEM_MOD_RANGED_ATTACK_POWER: - HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, addValue, apply); + HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, addValue, apply); break; case ITEM_MOD_MANA_REGENERATION: ApplyManaRegenBonus(int32(addValue), apply); @@ -13268,7 +13400,7 @@ void Player::ApplyReforgeEnchantment(Item* item, bool apply) m_spellPenetrationItemMod += apply ? int32(addValue) : -int32(addValue); break; case ITEM_MOD_BLOCK_VALUE: - HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, addValue, apply); + HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, addValue, apply); break; case ITEM_MOD_MASTERY_RATING: ApplyRatingMod(CR_MASTERY, int32(addValue), apply); @@ -13342,7 +13474,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool if (!item->IsBroken()) { - for (int s = 0; s < MAX_ITEM_ENCHANTMENT_EFFECTS; ++s) + for (uint8 s = 0; s < MAX_ITEM_ENCHANTMENT_EFFECTS; ++s) { uint32 enchant_display_type = pEnchant->Effect[s]; uint32 enchant_amount = pEnchant->EffectPointsMin[s]; @@ -13356,13 +13488,12 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool // processed in Player::CastItemCombatSpell break; case ITEM_ENCHANTMENT_TYPE_DAMAGE: - if (item->GetSlot() == EQUIPMENT_SLOT_MAINHAND) - HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(enchant_amount), apply); - else if (item->GetSlot() == EQUIPMENT_SLOT_OFFHAND) - HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(enchant_amount), apply); - else if (item->GetSlot() == EQUIPMENT_SLOT_RANGED) - HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(enchant_amount), apply); + { + WeaponAttackType const attackType = Player::GetAttackBySlot(item->GetSlot()); + if (attackType != MAX_ATTACK) + UpdateDamageDoneMods(attackType); break; + } case ITEM_ENCHANTMENT_TYPE_EQUIP_SPELL: if (enchant_spell_id) { @@ -13416,7 +13547,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool } } - HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + enchant_spell_id), TOTAL_VALUE, float(enchant_amount), apply); + HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + enchant_spell_id), TOTAL_VALUE, float(enchant_amount), apply); break; case ITEM_ENCHANTMENT_TYPE_STAT: { @@ -13441,36 +13572,36 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool { case ITEM_MOD_MANA: TC_LOG_DEBUG("entities.player.items", "+ %u MANA", enchant_amount); - HandleStatModifier(UNIT_MOD_MANA, BASE_VALUE, float(enchant_amount), apply); + HandleStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, float(enchant_amount), apply); break; case ITEM_MOD_HEALTH: TC_LOG_DEBUG("entities.player.items", "+ %u HEALTH", enchant_amount); - HandleStatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(enchant_amount), apply); + HandleStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(enchant_amount), apply); break; case ITEM_MOD_AGILITY: TC_LOG_DEBUG("entities.player.items", "+ %u AGILITY", enchant_amount); - HandleStatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, float(enchant_amount), apply); - ApplyStatBuffMod(STAT_AGILITY, (float)enchant_amount, apply); + HandleStatFlatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, float(enchant_amount), apply); + UpdateStatBuffMod(STAT_AGILITY); break; case ITEM_MOD_STRENGTH: TC_LOG_DEBUG("entities.player.items", "+ %u STRENGTH", enchant_amount); - HandleStatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, float(enchant_amount), apply); - ApplyStatBuffMod(STAT_STRENGTH, (float)enchant_amount, apply); + HandleStatFlatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, float(enchant_amount), apply); + UpdateStatBuffMod(STAT_STRENGTH); break; case ITEM_MOD_INTELLECT: TC_LOG_DEBUG("entities.player.items", "+ %u INTELLECT", enchant_amount); - HandleStatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, float(enchant_amount), apply); - ApplyStatBuffMod(STAT_INTELLECT, (float)enchant_amount, apply); + HandleStatFlatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, float(enchant_amount), apply); + UpdateStatBuffMod(STAT_INTELLECT); break; case ITEM_MOD_SPIRIT: TC_LOG_DEBUG("entities.player.items", "+ %u SPIRIT", enchant_amount); - HandleStatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, float(enchant_amount), apply); - ApplyStatBuffMod(STAT_SPIRIT, (float)enchant_amount, apply); + HandleStatFlatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, float(enchant_amount), apply); + UpdateStatBuffMod(STAT_SPIRIT); break; case ITEM_MOD_STAMINA: TC_LOG_DEBUG("entities.player.items", "+ %u STAMINA", enchant_amount); - HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, float(enchant_amount), apply); - ApplyStatBuffMod(STAT_STAMINA, (float)enchant_amount, apply); + HandleStatFlatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, float(enchant_amount), apply); + UpdateStatBuffMod(STAT_STAMINA); break; case ITEM_MOD_DEFENSE_SKILL_RATING: ApplyRatingMod(CR_DEFENSE_SKILL, enchant_amount, apply); @@ -13578,12 +13709,12 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool TC_LOG_DEBUG("entities.player.items", "+ %u EXPERTISE", enchant_amount); break; case ITEM_MOD_ATTACK_POWER: - HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(enchant_amount), apply); - HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply); + HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(enchant_amount), apply); + HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply); TC_LOG_DEBUG("entities.player.items", "+ %u ATTACK_POWER", enchant_amount); break; case ITEM_MOD_RANGED_ATTACK_POWER: - HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply); + HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply); TC_LOG_DEBUG("entities.player.items", "+ %u RANGED_ATTACK_POWER", enchant_amount); break; case ITEM_MOD_MANA_REGENERATION: @@ -13607,7 +13738,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool TC_LOG_DEBUG("entities.player.items", "+ %u SPELL_PENETRATION", enchant_amount); break; case ITEM_MOD_BLOCK_VALUE: - HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(enchant_amount), apply); + HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, float(enchant_amount), apply); TC_LOG_DEBUG("entities.player.items", "+ %u BLOCK_VALUE", enchant_amount); break; case ITEM_MOD_MASTERY_RATING: @@ -13621,20 +13752,9 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool } case ITEM_ENCHANTMENT_TYPE_TOTEM: // Shaman Rockbiter Weapon { - if (getClass() == CLASS_SHAMAN) - { - float addValue; - if (item->GetSlot() == EQUIPMENT_SLOT_MAINHAND) - { - addValue = float(enchant_amount * item->GetTemplate()->GetDelay() / 1000.0f); - HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, addValue, apply); - } - else if (item->GetSlot() == EQUIPMENT_SLOT_OFFHAND) - { - addValue = float(enchant_amount * item->GetTemplate()->GetDelay() / 1000.0f); - HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, addValue, apply); - } - } + WeaponAttackType const attackType = Player::GetAttackBySlot(item->GetSlot()); + if (attackType != MAX_ATTACK) + UpdateDamageDoneMods(attackType); break; } case ITEM_ENCHANTMENT_TYPE_USE_SPELL: diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index ba78e770b7..66333cc6b3 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1153,8 +1153,8 @@ class TC_GAME_API Player : public Unit, public GridObject Bag* GetBagByPos(uint8 slot) const; Item* GetWeaponForAttack(WeaponAttackType attackType, bool useable = false) const; Item* GetShield(bool useable = false) const; - static uint8 GetAttackBySlot(uint8 slot); // MAX_ATTACK if not weapon slot - std::vector &GetItemUpdateQueue() { return m_itemUpdateQueue; } + static WeaponAttackType GetAttackBySlot(uint8 slot); // MAX_ATTACK if not weapon slot + std::vector& GetItemUpdateQueue() { return m_itemUpdateQueue; } static bool IsInventoryPos(uint16 pos) { return IsInventoryPos(pos >> 8, pos & 255); } static bool IsInventoryPos(uint8 bag, uint8 slot); static bool IsEquipmentPos(uint16 pos) { return IsEquipmentPos(pos >> 8, pos & 255); } @@ -1796,7 +1796,7 @@ class TC_GAME_API Player : public Unit, public GridObject void UpdateMastery(); bool CanUseMastery() const; - void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) override; + void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) const override; void RecalculateRating(CombatRating cr) { ApplyRatingMod(cr, 0, true);} float GetMeleeCritFromAgility() const; @@ -2005,11 +2005,19 @@ class TC_GAME_API Player : public Unit, public GridObject bool CanTameExoticPets() const { return IsGameMaster() || HasAuraType(SPELL_AURA_ALLOW_TAME_PET_TYPE); } void SetRegularAttackTime(); - void SetBaseModValue(BaseModGroup modGroup, BaseModType modType, float value) { m_auraBaseMod[modGroup][modType] = value; } - void HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, float amount, bool apply); + + void HandleBaseModFlatValue(BaseModGroup modGroup, float amount, bool apply); + void ApplyBaseModPctValue(BaseModGroup modGroup, float pct); + + void SetBaseModFlatValue(BaseModGroup modGroup, float val); + void SetBaseModPctValue(BaseModGroup modGroup, float val); + + void UpdateDamageDoneMods(WeaponAttackType attackType) override; + void UpdateBaseModGroup(BaseModGroup modGroup); + float GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const; float GetTotalBaseModValue(BaseModGroup modGroup) const; - float GetTotalPercentageModValue(BaseModGroup modGroup) const { return m_auraBaseMod[modGroup][FLAT_MOD] + m_auraBaseMod[modGroup][PCT_MOD]; } + void _ApplyAllStatBonuses(); void _RemoveAllStatBonuses(); @@ -2017,6 +2025,11 @@ class TC_GAME_API Player : public Unit, public GridObject void CastAllObtainSpells(); void ApplyItemObtainSpells(Item* item, bool apply); + + void UpdateWeaponDependentCritAuras(WeaponAttackType attackType); + void UpdateAllWeaponDependentCritAuras(); + + void UpdateWeaponDependentAuras(WeaponAttackType attackType); void ApplyItemDependentAuras(Item* item, bool apply); void _ApplyItemMods(Item* item, uint8 slot, bool apply, bool updateItemAuras = true); @@ -2581,7 +2594,8 @@ class TC_GAME_API Player : public Unit, public GridObject ActionButtonList m_actionButtons; - float m_auraBaseMod[BASEMOD_END][MOD_END]; + float m_auraBaseFlatMod[BASEMOD_END]; + float m_auraBasePctMod[BASEMOD_END]; int16 m_baseRatingValue[MAX_COMBAT_RATING]; uint32 m_baseSpellPower; uint32 m_baseManaRegen; diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index 7ea5058934..6fe03739ae 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -204,7 +204,7 @@ void Player::UpdateSpellHealingPercentTaken() bool Player::UpdateAllStats() { - for (int8 i = STAT_STRENGTH; i < MAX_STATS; ++i) + for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i) { float value = GetTotalStatValue(Stats(i)); SetStat(Stats(i), int32(value)); @@ -254,9 +254,10 @@ void Player::UpdateArmor() { UnitMods unitMod = UNIT_MOD_ARMOR; - float value = GetModifierValue(unitMod, BASE_VALUE); // base armor (from items) - value *= GetModifierValue(unitMod, BASE_PCT); // armor percent from items - value += GetModifierValue(unitMod, TOTAL_VALUE); + float value = GetFlatModifierValue(unitMod, BASE_VALUE); // base armor (from items) + value *= GetPctModifierValue(unitMod, BASE_PCT); // armor percent from items + // value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats (deprecated since 4.x) + value += GetFlatModifierValue(unitMod, TOTAL_VALUE); //add dynamic flat mods AuraEffectList const& mResbyIntellect = GetAuraEffectsByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT); @@ -266,7 +267,7 @@ void Player::UpdateArmor() value += CalculatePct(GetStat(Stats((*i)->GetMiscValueB())), (*i)->GetAmount()); } - value *= GetModifierValue(unitMod, TOTAL_PCT); + value *= GetPctModifierValue(unitMod, TOTAL_PCT); SetArmor(int32(value)); UpdateAttackPowerAndDamage(); // armor dependent auras update for SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR @@ -301,10 +302,10 @@ 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); + float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreateHealth(); + value *= GetPctModifierValue(unitMod, BASE_PCT); + value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + GetHealthBonusFromStamina(); + value *= GetPctModifierValue(unitMod, TOTAL_PCT); SetMaxHealth((uint32)value); } @@ -324,10 +325,10 @@ void Player::UpdateMaxPower(Powers power) float bonusPower = (power == POWER_MANA && GetCreatePowers(power) > 0) ? 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); + float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); + value *= GetPctModifierValue(unitMod, BASE_PCT); + value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + bonusPower; + value *= GetPctModifierValue(unitMod, TOTAL_PCT); SetMaxPower(power, (int32)std::lroundf(value)); } @@ -359,10 +360,10 @@ void Player::UpdateAttackPowerAndDamage(bool ranged) val2 = strengthValue + agilityValue; } - SetModifierValue(unitMod, BASE_VALUE, val2); + SetStatFlatModifier(unitMod, BASE_VALUE, val2); - float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT); - float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE); + float base_attPower = GetFlatModifierValue(unitMod, BASE_VALUE) * GetPctModifierValue(unitMod, BASE_PCT); + float attPowerMod = GetFlatModifierValue(unitMod, TOTAL_VALUE); //add dynamic flat mods if (!ranged) @@ -373,7 +374,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged) attPowerMod += int32(GetArmor() / (*iter)->GetAmount()); } - float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f; + float attPowerMultiplier = GetPctModifierValue(unitMod, TOTAL_PCT) - 1.0f; SetInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field SetInt32Value(index_mod_pos, uint32(attPowerMod > 0.f ? attPowerMod : 0.f)); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MOD_POS field @@ -394,7 +395,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged) } } -void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) +void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) const { UnitMods unitMod; @@ -414,10 +415,10 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo float const attackPowerMod = std::max(GetAPMultiplier(attType, normalized), 0.25f); - float baseValue = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * attackPowerMod; - float basePct = GetModifierValue(unitMod, BASE_PCT); - float totalValue = GetModifierValue(unitMod, TOTAL_VALUE); - float totalPct = addTotalPct ? GetModifierValue(unitMod, TOTAL_PCT) : 1.0f; + float baseValue = GetFlatModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * attackPowerMod; + float basePct = GetPctModifierValue(unitMod, BASE_PCT); + float totalValue = GetFlatModifierValue(unitMod, TOTAL_VALUE); + float totalPct = addTotalPct ? GetPctModifierValue(unitMod, TOTAL_PCT) : 1.0f; float weaponMinDamage = GetWeaponDamageRange(attType, MINDAMAGE); float weaponMaxDamage = GetWeaponDamageRange(attType, MAXDAMAGE); @@ -510,14 +511,16 @@ void Player::UpdateCritPercentage(WeaponAttackType attType) break; } - float value = GetTotalPercentageModValue(modGroup) + GetRatingBonusValue(cr); + // flat = bonus from crit auras, pct = bonus from agility, combat rating = mods from items + float value = GetBaseModValue(modGroup, FLAT_MOD) + GetBaseModValue(modGroup, PCT_MOD) + GetRatingBonusValue(cr); + // Modify crit from weapon skill and maximized defense skill of same level victim difference value += (int32(GetMaxSkillValueForLevel()) - int32(GetMaxSkillValueForLevel())) * 0.04f; if (sWorld->getBoolConfig(CONFIG_STATS_LIMITS_ENABLE)) value = value > sWorld->getFloatConfig(CONFIG_STATS_LIMITS_CRIT) ? sWorld->getFloatConfig(CONFIG_STATS_LIMITS_CRIT) : value; - value = value < 0.0f ? 0.0f : value; + value = std::max(0.0f, value); SetStatFloatValue(index, value); } @@ -525,9 +528,9 @@ 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); + SetBaseModPctValue(CRIT_PERCENTAGE, value); + SetBaseModPctValue(OFFHAND_CRIT_PERCENTAGE, value); + SetBaseModPctValue(RANGED_CRIT_PERCENTAGE, value); UpdateCritPercentage(BASE_ATTACK); UpdateCritPercentage(OFF_ATTACK); @@ -909,10 +912,10 @@ void Creature::UpdateMaxPower(Powers power) UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power); - float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); - value *= GetModifierValue(unitMod, BASE_PCT); - value += GetModifierValue(unitMod, TOTAL_VALUE); - value *= GetModifierValue(unitMod, TOTAL_PCT); + float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); + value *= GetPctModifierValue(unitMod, BASE_PCT); + value += GetFlatModifierValue(unitMod, TOTAL_VALUE); + value *= GetPctModifierValue(unitMod, TOTAL_PCT); SetMaxPower(power, uint32(std::lroundf(value))); } @@ -965,9 +968,9 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged) indexMulti = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER; } - float baseAttackPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT); - float attackPowerMod = GetModifierValue(unitMod, TOTAL_VALUE); - float attackPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f; + float baseAttackPower = GetFlatModifierValue(unitMod, BASE_VALUE) * GetPctModifierValue(unitMod, BASE_PCT); + float attackPowerMod = GetFlatModifierValue(unitMod, TOTAL_VALUE); + float attackPowerMultiplier = GetPctModifierValue(unitMod, TOTAL_PCT) - 1.0f; SetInt32Value(index, uint32(baseAttackPower)); // UNIT_FIELD_(RANGED)_ATTACK_POWER SetInt32Value(indexModPos, uint32(attackPowerMod > 0.f ? attackPowerMod : 0.f)); // UNIT_FIELD_(RANGED)_ATTACK_POWER_MOD_POS @@ -984,7 +987,7 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged) } } -void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) +void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) const { float variance = 1.0f; UnitMods unitMod; @@ -1023,10 +1026,10 @@ void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, float attackPower = GetTotalAttackPowerValue(attType); float attackSpeedMulti = GetAPMultiplier(attType, normalized); - float baseValue = GetModifierValue(unitMod, BASE_VALUE) + (attackPower / 14.0f) * variance; - float basePct = GetModifierValue(unitMod, BASE_PCT) * attackSpeedMulti; - float totalValue = GetModifierValue(unitMod, TOTAL_VALUE); - float totalPct = addTotalPct ? GetModifierValue(unitMod, TOTAL_PCT) : 1.0f; + float baseValue = GetFlatModifierValue(unitMod, BASE_VALUE) + (attackPower / 14.0f) * variance; + float basePct = GetPctModifierValue(unitMod, BASE_PCT) * attackSpeedMulti; + float totalValue = GetFlatModifierValue(unitMod, TOTAL_VALUE); + float totalPct = addTotalPct ? GetPctModifierValue(unitMod, TOTAL_PCT) : 1.0f; float dmgMultiplier = GetCreatureTemplate()->ModDamage; // = ModDamage * _GetDamageMod(rank); minDamage = ((weaponMinDamage + baseValue) * dmgMultiplier * basePct + totalValue) * totalPct; @@ -1046,12 +1049,12 @@ bool Guardian::UpdateStats(Stats stat) // value = ((base_value * base_pct) + total_value) * total_pct float value = GetTotalStatValue(stat); - ApplyStatBuffMod(stat, m_statFromOwner[stat], false); + //ApplyStatBuffMod(stat, m_statFromOwner[stat], false); float ownersBonus = 0.0f; SetStat(stat, int32(value)); m_statFromOwner[stat] = ownersBonus; - ApplyStatBuffMod(stat, m_statFromOwner[stat], true); + UpdateStatBuffMod(stat); switch (stat) { @@ -1107,10 +1110,12 @@ void Guardian::UpdateArmor() float value = 0.0f; UnitMods unitMod = UNIT_MOD_ARMOR; - value = GetModifierValue(unitMod, BASE_VALUE); - value *= GetModifierValue(unitMod, BASE_PCT); - value += GetModifierValue(unitMod, TOTAL_VALUE); - value *= GetModifierValue(unitMod, TOTAL_PCT); + value = GetFlatModifierValue(unitMod, BASE_VALUE); + value *= GetPctModifierValue(unitMod, BASE_PCT); + //value += GetStat(STAT_AGILITY) * 2.0f; (deprecated since 4.x) + value += GetFlatModifierValue(unitMod, TOTAL_VALUE); + value *= GetPctModifierValue(unitMod, TOTAL_PCT); + SetArmor(int32(value)); } @@ -1121,10 +1126,10 @@ void Guardian::UpdateMaxHealth() float stamina = GetStat(STAT_STAMINA) - GetCreateStat(STAT_STAMINA); float multiplicator = 10.0f; - float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth(); - value *= GetModifierValue(unitMod, BASE_PCT); - value += GetModifierValue(unitMod, TOTAL_VALUE) + stamina * multiplicator; - value *= GetModifierValue(unitMod, TOTAL_PCT); + float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreateHealth(); + value *= GetPctModifierValue(unitMod, BASE_PCT); + value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + stamina * multiplicator; + value *= GetPctModifierValue(unitMod, TOTAL_PCT); SetMaxHealth((uint32)value); } @@ -1139,10 +1144,10 @@ void Guardian::UpdateMaxPower(Powers power) float addValue = (power == POWER_MANA) ? GetStat(STAT_INTELLECT) - GetCreateStat(STAT_INTELLECT) : 0.0f; float multiplicator = 15.0f; - float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); - value *= GetModifierValue(unitMod, BASE_PCT); - value += GetModifierValue(unitMod, TOTAL_VALUE) + addValue * multiplicator; - value *= GetModifierValue(unitMod, TOTAL_PCT); + float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); + value *= GetPctModifierValue(unitMod, BASE_PCT); + value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + addValue * multiplicator; + value *= GetPctModifierValue(unitMod, TOTAL_PCT); SetMaxPower(power, int32(value)); } @@ -1159,12 +1164,12 @@ void Guardian::UpdateAttackPowerAndDamage(bool ranged) UnitMods unitMod = UNIT_MOD_ATTACK_POWER; - SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, val); + SetStatFlatModifier(UNIT_MOD_ATTACK_POWER, BASE_VALUE, val); // 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; + float base_attPower = GetFlatModifierValue(unitMod, BASE_VALUE) * GetPctModifierValue(unitMod, BASE_PCT); + float attPowerMod = GetFlatModifierValue(unitMod, TOTAL_VALUE); + float attPowerMultiplier = GetPctModifierValue(unitMod, TOTAL_PCT) - 1.0f; // UNIT_FIELD_(RANGED)_ATTACK_POWER field SetInt32Value(UNIT_FIELD_ATTACK_POWER, int32(base_attPower)); @@ -1214,10 +1219,10 @@ void Guardian::UpdateDamagePhysical(WeaponAttackType attType) float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f; - float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed + bonusDamage; - float base_pct = GetModifierValue(unitMod, BASE_PCT); - float total_value = GetModifierValue(unitMod, TOTAL_VALUE); - float total_pct = GetModifierValue(unitMod, TOTAL_PCT); + float base_value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * att_speed + bonusDamage; + float base_pct = GetPctModifierValue(unitMod, BASE_PCT); + float total_value = GetFlatModifierValue(unitMod, TOTAL_VALUE); + float total_pct = GetPctModifierValue(unitMod, TOTAL_PCT); float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE); float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index e0bbb1ba42..0faf979be3 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -374,13 +374,13 @@ Unit::Unit(bool isWorldObject) : for (uint8 i = 0; i < UNIT_MOD_END; ++i) { - m_auraModifiersGroup[i][BASE_VALUE] = 0.0f; - m_auraModifiersGroup[i][BASE_PCT] = 1.0f; - m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f; - m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f; + m_auraFlatModifiersGroup[i][BASE_VALUE] = 0.0f; + m_auraFlatModifiersGroup[i][TOTAL_VALUE] = 0.0f; + m_auraPctModifiersGroup[i][BASE_PCT] = 1.0f; + m_auraPctModifiersGroup[i][TOTAL_PCT] = 1.0f; } // implement 50% base damage from offhand - m_auraModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f; + m_auraPctModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f; for (uint8 i = 0; i < MAX_ATTACK; ++i) { @@ -2253,7 +2253,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* victim, WeaponAttackTy return MELEE_HIT_NORMAL; } -uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct) +uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct) const { float minDamage = 0.0f; float maxDamage = 0.0f; @@ -4912,24 +4912,33 @@ int32 Unit::GetMaxNegativeAuraModifierByAffectMask(AuraType auraType, SpellInfo }); } -float Unit::GetResistanceBuffMods(SpellSchools school, bool positive) const +void Unit::UpdateResistanceBuffModsMod(SpellSchools school) { - return GetFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school); -} + float modPos = 0.0f; + float modNeg = 0.0f; -void Unit::SetResistanceBuffMods(SpellSchools school, bool positive, float val) -{ - SetFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school, val); -} + // these auras are always positive + modPos = GetMaxPositiveAuraModifierByMiscMask(SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE, 1 << school); + modPos += GetTotalAuraModifier(SPELL_AURA_MOD_RESISTANCE, [school](AuraEffect const* aurEff) -> bool + { + if ((aurEff->GetMiscValue() & (1 << school)) && aurEff->GetAmount() > 0) + return true; + return false; + }); -void Unit::ApplyResistanceBuffModsMod(SpellSchools school, bool positive, float val, bool apply) -{ - ApplyModSignedFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school, val, apply); -} + modNeg = GetTotalAuraModifier(SPELL_AURA_MOD_RESISTANCE, [school](AuraEffect const* aurEff) -> bool + { + if ((aurEff->GetMiscValue() & (1 << school)) && aurEff->GetAmount() < 0) + return true; + return false; + }); -void Unit::ApplyResistanceBuffModsPercentMod(SpellSchools school, bool positive, float val, bool apply) -{ - ApplyPercentModFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school, val, apply); + float factor = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_RESISTANCE_PCT, 1 << school); + modPos *= factor; + modNeg *= factor; + + SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + school, modPos); + SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + school, modNeg); } void Unit::InitStatBuffMods() @@ -4940,15 +4949,63 @@ void Unit::InitStatBuffMods() SetFloatValue(UNIT_FIELD_NEGSTAT0+i, 0); } -void Unit::ApplyStatBuffMod(Stats stat, float val, bool apply) +void Unit::UpdateStatBuffMod(Stats stat) { - ApplyModSignedFloatValue((val > 0 ? UNIT_FIELD_POSSTAT0+stat : UNIT_FIELD_NEGSTAT0+stat), val, apply); -} + float modPos = 0.0f; + float modNeg = 0.0f; + float factor = 0.0f; -void Unit::ApplyStatPercentBuffMod(Stats stat, float val, bool apply) -{ - ApplyPercentModFloatValue(UNIT_FIELD_POSSTAT0+stat, val, apply); - ApplyPercentModFloatValue(UNIT_FIELD_NEGSTAT0+stat, val, apply); + UnitMods const unitMod = static_cast(UNIT_MOD_STAT_START + stat); + + // includes value from items and enchantments + float modValue = GetFlatModifierValue(unitMod, BASE_VALUE); + if (modValue > 0.f) + modPos += modValue; + else + modNeg += modValue; + + if (IsGuardian()) + { + modValue = static_cast(this)->GetBonusStatFromOwner(stat); + if (modValue > 0.f) + modPos += modValue; + else + modNeg += modValue; + } + + modPos += GetTotalAuraModifier(SPELL_AURA_MOD_STAT, [stat](AuraEffect const* aurEff) -> bool + { + if ((aurEff->GetMiscValue() < 0 || aurEff->GetMiscValue() == stat) && aurEff->GetAmount() > 0) + return true; + return false; + }); + + modNeg += GetTotalAuraModifier(SPELL_AURA_MOD_STAT, [stat](AuraEffect const* aurEff) -> bool + { + if ((aurEff->GetMiscValue() < 0 || aurEff->GetMiscValue() == stat) && aurEff->GetAmount() < 0) + return true; + return false; + }); + + factor = GetTotalAuraMultiplier(SPELL_AURA_MOD_PERCENT_STAT, [stat](AuraEffect const* aurEff) -> bool + { + if (aurEff->GetMiscValue() == -1 || aurEff->GetMiscValue() == stat) + return true; + return false; + }); + + factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, [stat](AuraEffect const* aurEff) -> bool + { + if (aurEff->GetMiscValue() == -1 || aurEff->GetMiscValue() == stat) + return true; + return false; + }); + + modPos *= factor; + modNeg *= factor; + + SetFloatValue(UNIT_FIELD_POSSTAT0 + stat, modPos); + SetFloatValue(UNIT_FIELD_NEGSTAT0 + stat, modNeg); } void Unit::_RegisterDynObject(DynamicObject* dynObj) @@ -8755,15 +8812,6 @@ int32 Unit::ModifyPower(Powers power, int32 dVal, bool withPowerUpdate /*= true* return gain; } -// returns negative amount on power reduction -int32 Unit::ModifyPowerPct(Powers power, float pct, bool apply) -{ - float amount = (float)GetMaxPower(power); - ApplyPercentModFloatVar(amount, pct, apply); - - return ModifyPower(power, (int32)amount - GetMaxPower(power)); -} - inline float GetBasePowerRegen(uint32 powerBarId, Powers powerType, bool isInCombat) { if (powerType != POWER_ALTERNATE_POWER) @@ -9613,33 +9661,98 @@ bool Unit::IsInDisallowedMountForm() const ######## ######## #######################################*/ -bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, float amount, bool apply) +void Unit::HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply) { - if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END) + if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_FLAT_END) { - TC_LOG_ERROR("entities.unit", "ERROR in HandleStatModifier(): non-existing UnitMods or wrong UnitModifierType!"); - return false; + TC_LOG_ERROR("entities.unit", "ERROR in HandleStatFlatModifier(): non-existing UnitMods or wrong UnitModifierType!"); + return; } + if (!amount) + return; + switch (modifierType) { case BASE_VALUE: case TOTAL_VALUE: - m_auraModifiersGroup[unitMod][modifierType] += apply ? amount : -amount; - break; - case BASE_PCT: - case TOTAL_PCT: - ApplyPercentModFloatVar(m_auraModifiersGroup[unitMod][modifierType], amount, apply); + m_auraFlatModifiersGroup[unitMod][modifierType] += apply ? amount : -amount; break; default: break; } - if (IsPet()) - return false; + UpdateUnitMod(unitMod); +} +void Unit::ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float pct) +{ + if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_PCT_END) + { + TC_LOG_ERROR("entities.unit", "ERROR in ApplyStatPctModifier(): non-existing UnitMods or wrong UnitModifierType!"); + return; + } + + if (!pct) + return; + + switch (modifierType) + { + case BASE_PCT: + case TOTAL_PCT: + AddPct(m_auraPctModifiersGroup[unitMod][modifierType], pct); + break; + default: + break; + } + + UpdateUnitMod(unitMod); +} + +void Unit::SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val) +{ + if (m_auraFlatModifiersGroup[unitMod][modifierType] == val) + return; + + m_auraFlatModifiersGroup[unitMod][modifierType] = val; + UpdateUnitMod(unitMod); +} + +void Unit::SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val) +{ + if (m_auraPctModifiersGroup[unitMod][modifierType] == val) + return; + + m_auraPctModifiersGroup[unitMod][modifierType] = val; + UpdateUnitMod(unitMod); +} + +float Unit::GetFlatModifierValue(UnitMods unitMod, UnitModifierFlatType modifierType) const +{ + if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_FLAT_END) + { + TC_LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!"); + return 0.0f; + } + + return m_auraFlatModifiersGroup[unitMod][modifierType]; +} + +float Unit::GetPctModifierValue(UnitMods unitMod, UnitModifierPctType modifierType) const +{ + if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_PCT_END) + { + TC_LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!"); + return 0.0f; + } + + return m_auraPctModifiersGroup[unitMod][modifierType]; +} + +void Unit::UpdateUnitMod(UnitMods unitMod) +{ if (!CanModifyStats()) - return false; + return; switch (unitMod) { @@ -9690,36 +9803,108 @@ bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, f default: break; } +} + +bool Unit::CheckAttackFitToAuraRequirement(WeaponAttackType attackType, AuraEffect const* aurEff) const +{ + // only players have item requirements + if (GetTypeId() != TYPEID_PLAYER) + return true; + + SpellInfo const* spellInfo = aurEff->GetSpellInfo(); + if (spellInfo->EquippedItemClass == -1) + return true; + + Item* item = ToPlayer()->GetWeaponForAttack(attackType, true); + if (!item || !item->IsFitToSpellRequirements(spellInfo)) + return false; return true; } -float Unit::GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) const +void Unit::UpdateDamageDoneMods(WeaponAttackType attackType) { - if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END) + UnitMods unitMod; + switch (attackType) { - TC_LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!"); - return 0.0f; + case BASE_ATTACK: + unitMod = UNIT_MOD_DAMAGE_MAINHAND; + break; + case OFF_ATTACK: + unitMod = UNIT_MOD_DAMAGE_OFFHAND; + break; + case RANGED_ATTACK: + unitMod = UNIT_MOD_DAMAGE_RANGED; + break; + default: + ABORT(); + break; } - if (modifierType == TOTAL_PCT && m_auraModifiersGroup[unitMod][modifierType] <= 0.0f) - return 0.0f; + float amount = GetTotalAuraModifier(SPELL_AURA_MOD_DAMAGE_DONE, std::bind(&Unit::CheckAttackFitToAuraRequirement, this, attackType, std::placeholders::_1)); - return m_auraModifiersGroup[unitMod][modifierType]; + SetStatFlatModifier(unitMod, TOTAL_VALUE, amount); +} + +void Unit::UpdateAllDamageDoneMods() +{ + for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i) + UpdateDamageDoneMods(WeaponAttackType(i)); +} + +void Unit::UpdateDamagePctDoneMods(WeaponAttackType attackType) +{ + float factor; + UnitMods unitMod; + switch (attackType) + { + case BASE_ATTACK: + factor = 1.0f; + unitMod = UNIT_MOD_DAMAGE_MAINHAND; + break; + case OFF_ATTACK: + // off hand has 50% penalty + factor = 0.5f; + unitMod = UNIT_MOD_DAMAGE_OFFHAND; + break; + case RANGED_ATTACK: + factor = 1.0f; + unitMod = UNIT_MOD_DAMAGE_RANGED; + break; + default: + ABORT(); + break; + } + + factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, [attackType, this](AuraEffect const* aurEff) -> bool + { + if (!(aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)) + return false; + + return CheckAttackFitToAuraRequirement(attackType, aurEff); + }); + + if (attackType == OFF_ATTACK) + factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT, std::bind(&Unit::CheckAttackFitToAuraRequirement, this, attackType, std::placeholders::_1)); + + SetStatPctModifier(unitMod, TOTAL_PCT, factor); +} + +void Unit::UpdateAllDamagePctDoneMods() +{ + for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i) + UpdateDamagePctDoneMods(WeaponAttackType(i)); } float Unit::GetTotalStatValue(Stats stat) const { UnitMods unitMod = UnitMods(UNIT_MOD_STAT_START + stat); - if (m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f) - return 0.0f; - // value = ((base_value * base_pct) + total_value) * total_pct - float value = m_auraModifiersGroup[unitMod][BASE_VALUE] + GetCreateStat(stat); - value *= m_auraModifiersGroup[unitMod][BASE_PCT]; - value += m_auraModifiersGroup[unitMod][TOTAL_VALUE]; - value *= m_auraModifiersGroup[unitMod][TOTAL_PCT]; + float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreateStat(stat); + value *= GetPctModifierValue(unitMod, BASE_PCT); + value += GetFlatModifierValue(unitMod, TOTAL_VALUE); + value *= GetPctModifierValue(unitMod, TOTAL_PCT); return value; } @@ -9732,13 +9917,10 @@ float Unit::GetTotalAuraModValue(UnitMods unitMod) const return 0.0f; } - if (m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f) - return 0.0f; - - float value = m_auraModifiersGroup[unitMod][BASE_VALUE]; - value *= m_auraModifiersGroup[unitMod][BASE_PCT]; - value += m_auraModifiersGroup[unitMod][TOTAL_VALUE]; - value *= m_auraModifiersGroup[unitMod][TOTAL_PCT]; + float value = GetFlatModifierValue(unitMod, BASE_VALUE); + value *= GetPctModifierValue(unitMod, BASE_PCT); + value += GetFlatModifierValue(unitMod, TOTAL_VALUE); + value *= GetPctModifierValue(unitMod, TOTAL_PCT); return value; } @@ -11148,36 +11330,53 @@ Unit* Unit::SelectNearbyTarget(Unit* exclude, float dist) const return Trinity::Containers::SelectRandomContainerElement(targets); } +void ApplyPercentModFloatVar(float& var, float val, bool apply) +{ + var *= (apply ? (100.0f + val) / 100.0f : 100.0f / (100.0f + val)); +} + void Unit::ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply) { + float amount = GetFloatValue(UNIT_FIELD_BASEATTACKTIME + att); + float hasteAmount = GetFloatValue(PLAYER_FIELD_MOD_HASTE); + float rangedHasteAmount = GetFloatValue(PLAYER_FIELD_MOD_RANGED_HASTE); + float remainingTimePct = (float)m_attackTimer[att] / (GetAttackTime(att) * m_modAttackSpeedPct[att]); - if (val > 0) + if (val > 0.f) { ApplyPercentModFloatVar(m_modAttackSpeedPct[att], val, !apply); - ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME + att, val, !apply); + ApplyPercentModFloatVar(amount, val, !apply); if (GetTypeId() == TYPEID_PLAYER) { if (att == BASE_ATTACK) - ApplyPercentModFloatValue(PLAYER_FIELD_MOD_HASTE, val, !apply); + ApplyPercentModFloatVar(hasteAmount, val, !apply); else if (att == RANGED_ATTACK) - ApplyPercentModFloatValue(PLAYER_FIELD_MOD_RANGED_HASTE, val, !apply); + ApplyPercentModFloatVar(rangedHasteAmount, val, !apply); } } else { ApplyPercentModFloatVar(m_modAttackSpeedPct[att], -val, apply); - ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME + att, -val, apply); + ApplyPercentModFloatVar(amount, -val, apply); if (GetTypeId() == TYPEID_PLAYER) { if (att == BASE_ATTACK) - ApplyPercentModFloatValue(PLAYER_FIELD_MOD_HASTE, -val, apply); + ApplyPercentModFloatVar(hasteAmount, -val, apply); else if (att == RANGED_ATTACK) - ApplyPercentModFloatValue(PLAYER_FIELD_MOD_RANGED_HASTE, -val, apply); + ApplyPercentModFloatVar(rangedHasteAmount, -val, apply); } } + SetFloatValue(UNIT_FIELD_BASEATTACKTIME + att, amount); + + if (GetTypeId() == TYPEID_PLAYER) + { + SetFloatValue(PLAYER_FIELD_MOD_HASTE, hasteAmount); + SetFloatValue(PLAYER_FIELD_MOD_RANGED_HASTE, rangedHasteAmount); + } + m_attackTimer[att] = uint32(GetAttackTime(att) * m_modAttackSpeedPct[att] * remainingTimePct); } @@ -11186,41 +11385,51 @@ void Unit::ApplyHasteRegenMod(WeaponAttackType att, float val, bool apply) if (GetTypeId() != TYPEID_PLAYER) return; - if (val > 0) + float amount = GetFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN); + + if (val > 0.f) { if (att == BASE_ATTACK && getClass() != CLASS_HUNTER) - ApplyPercentModFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN, val, !apply); + ApplyPercentModFloatVar(amount, val, !apply); else if (att == RANGED_ATTACK && getClass() == CLASS_HUNTER) - ApplyPercentModFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN, val, !apply); + ApplyPercentModFloatVar(amount, val, !apply); } else { if (att == BASE_ATTACK && getClass() != CLASS_HUNTER) - ApplyPercentModFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN, -val, apply); + ApplyPercentModFloatVar(amount, -val, apply); else if (att == RANGED_ATTACK && getClass() == CLASS_HUNTER) - ApplyPercentModFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN, -val, apply); + ApplyPercentModFloatVar(amount, -val, apply); } + SetFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN, amount); + if (getClass() == CLASS_DEATH_KNIGHT) ToPlayer()->UpdatePowerRegeneration(POWER_RUNE); } void Unit::ApplyCastTimePercentMod(float val, bool apply, bool withCastHaste /*= true*/, bool withCastSpeed /*= true*/) { - if (val > 0) + float speedAmount = GetFloatValue(UNIT_MOD_CAST_SPEED); + float hasteAmount = GetFloatValue(UNIT_MOD_CAST_HASTE); + + if (val > 0.f) { if (withCastSpeed) - ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED, val, !apply); + ApplyPercentModFloatVar(speedAmount, val, !apply); if (withCastHaste) - ApplyPercentModFloatValue(UNIT_MOD_CAST_HASTE, val, !apply); + ApplyPercentModFloatVar(hasteAmount, val, !apply); } else { if (withCastSpeed) - ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED, -val, apply); + ApplyPercentModFloatVar(speedAmount, -val, apply); if (withCastHaste) - ApplyPercentModFloatValue(UNIT_MOD_CAST_HASTE, -val, apply); + ApplyPercentModFloatVar(hasteAmount, -val, apply); } + + SetFloatValue(UNIT_MOD_CAST_SPEED, speedAmount); + SetFloatValue(UNIT_MOD_CAST_HASTE, hasteAmount); } uint32 Unit::GetCastingTimeForBonus(SpellInfo const* spellProto, DamageEffectType damagetype, uint32 CastingTime) const @@ -11376,7 +11585,7 @@ float Unit::CalculateDefaultCoefficient(SpellInfo const* spellInfo, DamageEffect return (CastingTime / 3500.0f) * DotFactor; } -float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized) +float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized) const { if (GetTypeId() != TYPEID_PLAYER || (IsInFeralForm() && !normalized)) return GetAttackTime(attType) / 1000.0f; diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index eb45a21fc8..20aade5d1f 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -134,13 +134,18 @@ typedef std::vector DispelChargesList; typedef std::unordered_multimap SpellImmuneContainer; -enum UnitModifierType +enum UnitModifierFlatType { BASE_VALUE = 0, - BASE_PCT = 1, - TOTAL_VALUE = 2, - TOTAL_PCT = 3, - MODIFIER_TYPE_END = 4 + TOTAL_VALUE = 1, + MODIFIER_TYPE_FLAT_END = 2 +}; + +enum UnitModifierPctType +{ + BASE_PCT = 0, + TOTAL_PCT = 1, + MODIFIER_TYPE_PCT_END = 2 }; enum WeaponDamageRange @@ -970,7 +975,6 @@ class TC_GAME_API Unit : public WorldObject // returns the change in power int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate = true); - int32 ModifyPowerPct(Powers power, float pct, bool apply = true); float GetPowerRegen(Powers powerType, bool isInCombat) const; virtual void RegenerateHealth() { } @@ -1455,13 +1459,9 @@ class TC_GAME_API Unit : public WorldObject int32 GetMaxPositiveAuraModifierByAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const; int32 GetMaxNegativeAuraModifierByAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const; - float GetResistanceBuffMods(SpellSchools school, bool positive) const; - void SetResistanceBuffMods(SpellSchools school, bool positive, float val); - void ApplyResistanceBuffModsMod(SpellSchools school, bool positive, float val, bool apply); - void ApplyResistanceBuffModsPercentMod(SpellSchools school, bool positive, float val, bool apply); + void UpdateResistanceBuffModsMod(SpellSchools school); void InitStatBuffMods(); - void ApplyStatBuffMod(Stats stat, float val, bool apply); - void ApplyStatPercentBuffMod(Stats stat, float val, bool apply); + void UpdateStatBuffMod(Stats stat); void SetCreateStat(Stats stat, float val) { m_createStats[stat] = val; } void SetCreateHealth(uint32 val) { SetUInt32Value(UNIT_FIELD_BASE_HEALTH, val); } uint32 GetCreateHealth() const { return GetUInt32Value(UNIT_FIELD_BASE_HEALTH); } @@ -1521,9 +1521,26 @@ class TC_GAME_API Unit : public WorldObject EventProcessor m_Events; // stat system - bool HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, float amount, bool apply); - void SetModifierValue(UnitMods unitMod, UnitModifierType modifierType, float value) { m_auraModifiersGroup[unitMod][modifierType] = value; } - float GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) const; + // stat system + void HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply); + void ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float amount); + + void SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val); + void SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val); + + float GetFlatModifierValue(UnitMods unitMod, UnitModifierFlatType modifierType) const; + float GetPctModifierValue(UnitMods unitMod, UnitModifierPctType modifierType) const; + + void UpdateUnitMod(UnitMods unitMod); + + bool CheckAttackFitToAuraRequirement(WeaponAttackType attackType, AuraEffect const* aurEff) const; + + virtual void UpdateDamageDoneMods(WeaponAttackType attackType); + void UpdateAllDamageDoneMods(); + + void UpdateDamagePctDoneMods(WeaponAttackType attackType); + void UpdateAllDamagePctDoneMods(); + float GetTotalStatValue(Stats stat) const; float GetTotalAuraModValue(UnitMods unitMod) const; SpellSchools GetSpellSchoolByAuraGroup(UnitMods unitMod) const; @@ -1544,9 +1561,9 @@ class TC_GAME_API Unit : public WorldObject float GetTotalAttackPowerValue(WeaponAttackType attType) const; float GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type) const; void SetBaseWeaponDamage(WeaponAttackType attType, WeaponDamageRange damageRange, float value) { m_weaponDamage[attType][damageRange] = value; } - virtual void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) = 0; - uint32 CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct); - float GetAPMultiplier(WeaponAttackType attType, bool normalized); + virtual void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) const = 0; + uint32 CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct) const; + float GetAPMultiplier(WeaponAttackType attType, bool normalized) const; bool isInFrontInMap(Unit const* target, float distance, float arc = float(M_PI)) const; bool isInBackInMap(Unit const* target, float distance, float arc = float(M_PI)) const; @@ -1879,7 +1896,8 @@ class TC_GAME_API Unit : public WorldObject EnumFlag m_interruptMask; EnumFlag m_interruptMask2; - float m_auraModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_END]; + float m_auraFlatModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_FLAT_END]; + float m_auraPctModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_PCT_END]; float m_weaponDamage[MAX_ATTACK][2]; bool m_canModifyStats; VisibleAuraMap m_visibleAuras; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 32d22c5d80..ed1aa5526c 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -215,7 +215,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleModMechanicImmunityMask, //147 SPELL_AURA_MECHANIC_IMMUNITY_MASK &AuraEffect::HandleAuraRetainComboPoints, //148 SPELL_AURA_RETAIN_COMBO_POINTS &AuraEffect::HandleNoImmediateEffect, //149 SPELL_AURA_REDUCE_PUSHBACK - &AuraEffect::HandleShieldBlockValue, //150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT + &AuraEffect::HandleShieldBlockValuePercent, //150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT &AuraEffect::HandleAuraTrackStealthed, //151 SPELL_AURA_TRACK_STEALTHED &AuraEffect::HandleNoImmediateEffect, //152 SPELL_AURA_MOD_DETECTED_RANGE implemented in Creature::GetAttackDistance &AuraEffect::HandleUnused, //153 Unused (4.3.4) old SPELL_AURA_SPLIT_DAMAGE_FLAT @@ -347,7 +347,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNoImmediateEffect, //279 SPELL_AURA_INITIALIZE_IMAGES &AuraEffect::HandleUnused, //280 unused (4.3.4) old SPELL_AURA_MOD_ARMOR_PENETRATION_PCT &AuraEffect::HandleNoImmediateEffect, //281 SPELL_AURA_MOD_HONOR_GAIN_PCT implemented in Player::RewardHonor - &AuraEffect::HandleAuraIncreaseBaseHealthPercent, //282 SPELL_AURA_INCREASE_BASE_HEALTH_PERCENT + &AuraEffect::HandleAuraIncreaseBaseHealthPercent, //282 SPELL_AURA_MOD_BASE_HEALTH_PCT &AuraEffect::HandleNoImmediateEffect, //283 SPELL_AURA_MOD_HEALING_RECEIVED implemented in Unit::SpellHealingBonus &AuraEffect::HandleAuraLinked, //284 SPELL_AURA_LINKED &AuraEffect::HandleAuraModAttackPowerOfArmor, //285 SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR implemented in Player::UpdateAttackPowerAndDamage @@ -2405,11 +2405,15 @@ void AuraEffect::HandleAuraModDisarm(AuraApplication const* aurApp, uint8 mode, Player* player = target->ToPlayer(); if (Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot)) { - uint8 attacktype = Player::GetAttackBySlot(slot); + WeaponAttackType const attackType = Player::GetAttackBySlot(slot); player->ApplyItemDependentAuras(item, !apply); - if (attacktype < MAX_ATTACK) + if (attackType != MAX_ATTACK) + { player->_ApplyWeaponDamage(slot, item->GetTemplate(), nullptr, !apply); + if (!apply) // apply case already handled on item dependent aura removal (if any) + player->UpdateWeaponDependentAuras(attackType); + } } } @@ -3353,17 +3357,17 @@ void AuraEffect::HandleAuraModResistanceExclusive(AuraApplication const* aurApp, Unit* target = aurApp->GetTarget(); - for (int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; x++) + for (uint8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; ++x) { - if (GetMiscValue() & int32(1<GetMaxPositiveAuraModifierByMiscMask(SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE, 1<GetMaxPositiveAuraModifierByMiscMask(SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE, 1 << x, this); if (amount < GetAmount()) { float value = float(GetAmount() - amount); - target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_VALUE, value, apply); - if (target->GetTypeId() == TYPEID_PLAYER) - target->ApplyResistanceBuffModsMod(SpellSchools(x), aurApp->IsPositive(), value, apply); + target->HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_VALUE, value, apply); + if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) + target->UpdateResistanceBuffModsMod(SpellSchools(x)); } } } @@ -3376,13 +3380,13 @@ void AuraEffect::HandleAuraModResistance(AuraApplication const* aurApp, uint8 mo Unit* target = aurApp->GetTarget(); - for (int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; x++) + for (uint8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; ++x) { - if (GetMiscValue() & int32(1<HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), TOTAL_VALUE, float(GetAmount()), apply); if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) - target->ApplyResistanceBuffModsMod(SpellSchools(x), GetAmount() > 0, (float)GetAmount(), apply); + target->UpdateResistanceBuffModsMod(SpellSchools(x)); } } } @@ -3393,55 +3397,58 @@ void AuraEffect::HandleAuraModBaseResistancePCT(AuraApplication const* aurApp, u return; Unit* target = aurApp->GetTarget(); - int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_RESISTANCE); - if (abs(spellGroupVal) >= abs(GetAmount())) - return; - // only players and pets have base stats - if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) + // only players have base stats + if (target->GetTypeId() != TYPEID_PLAYER) { - for (int8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) + //pets only have base armor + if (target->IsPet() && (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)) { - if (GetMiscValue() & int32(1 << i)) + if (apply) + target->ApplyStatPctModifier(UNIT_MOD_ARMOR, BASE_PCT, float(GetAmount())); + else { - if (spellGroupVal) - target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_PCT, (float)spellGroupVal, !apply); - - target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_PCT, float(GetAmount()), apply); + float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_BASE_RESISTANCE_PCT, SPELL_SCHOOL_MASK_NORMAL); + target->SetStatPctModifier(UNIT_MOD_ARMOR, BASE_PCT, amount); + } + } + } + else + { + for (uint8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; ++x) + { + if (GetMiscValue() & (1 << x)) + { + if (apply) + target->ApplyStatPctModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, float(GetAmount())); + else + { + float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_BASE_RESISTANCE_PCT, 1 << x); + target->SetStatPctModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, amount); + } } } } } -void AuraEffect::HandleModResistancePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModResistancePercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_RESISTANCE_PCT); - if (abs(spellGroupVal) >= abs(GetAmount())) - return; - for (int8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) + for (uint8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i) { - if (GetMiscValue() & int32(1<HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, (float)spellGroupVal, !apply); - if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) - { - target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), true, (float)spellGroupVal, !apply); - target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), false, (float)spellGroupVal, !apply); - } - } - target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, float(GetAmount()), apply); + float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_RESISTANCE_PCT, 1 << i); + if (target->GetPctModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT) == amount) + continue; + + target->SetStatPctModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, amount); if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) - { - target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), true, (float)GetAmount(), apply); - target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), false, (float)GetAmount(), apply); - } + target->UpdateResistanceBuffModsMod(SpellSchools(i)); } } } @@ -3453,12 +3460,18 @@ void AuraEffect::HandleModBaseResistance(AuraApplication const* aurApp, uint8 mo Unit* target = aurApp->GetTarget(); - // only players and pets have base stats - if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) + // only players have base stats + if (target->GetTypeId() != TYPEID_PLAYER) { - for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) - if (GetMiscValue() & (1<HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_VALUE, float(GetAmount()), apply); + //pets only have base armor + if (target->IsPet() && (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)) + target->HandleStatFlatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(GetAmount()), apply); + } + else + { + for (uint8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i) + if (GetMiscValue() & (1 << i)) + target->HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_VALUE, float(GetAmount()), apply); } } @@ -3500,22 +3513,21 @@ void AuraEffect::HandleAuraModStat(AuraApplication const* aurApp, uint8 mode, bo if (abs(spellGroupVal) >= abs(GetAmount())) return; - for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++) + for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i) { // -1 or -2 is all stats (misc < -2 checked in function beginning) if (GetMiscValue() < 0 || GetMiscValue() == i) { if (spellGroupVal) { - target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(spellGroupVal), !apply); + target->HandleStatFlatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(spellGroupVal), !apply); if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) - target->ApplyStatBuffMod(Stats(i), float(spellGroupVal), !apply); + target->UpdateStatBuffMod(Stats(i)); } - //target->ApplyStatMod(Stats(i), m_amount, apply); - target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatFlatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetAmount()), apply); if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) - target->ApplyStatBuffMod(Stats(i), (float)GetAmount(), apply); + target->UpdateStatBuffMod(Stats(i)); } } } @@ -3533,14 +3545,27 @@ void AuraEffect::HandleModPercentStat(AuraApplication const* aurApp, uint8 mode, return; } - // only players and pets have base stats - if (target->GetTypeId() != TYPEID_PLAYER && !target->IsPet()) + // only players have base stats + if (target->GetTypeId() != TYPEID_PLAYER) return; for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i) { if (GetMiscValue() == i || GetMiscValue() == -1) - target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(m_amount), apply); + { + if (apply) + target->ApplyStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(m_amount)); + else + { + float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_PERCENT_STAT, [i](AuraEffect const* aurEff) -> bool + { + if (aurEff->GetMiscValue() == i || aurEff->GetMiscValue() == -1) + return true; + return false; + }); + target->SetStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, amount); + } + } } } @@ -3618,64 +3643,47 @@ void AuraEffect::HandleModHealingDone(AuraApplication const* aurApp, uint8 mode, target->ToPlayer()->UpdateSpellDamageAndHealingBonus(); } -void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; - Unit* target = aurApp->GetTarget(); - int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE); - if (abs(spellGroupVal) >= abs(GetAmount())) - return; - - if (spellGroupVal) + if (GetMiscValue() < -1 || GetMiscValue() > 4) { - for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++) - { - if (GetMiscValue() == i || GetMiscValue() == -1) // affect the same stats - { - target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(spellGroupVal), !apply); - if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) - target->ApplyStatPercentBuffMod(Stats(i), float(spellGroupVal), !apply); - } - } + TC_LOG_ERROR("spells", "WARNING: Misc Value for SPELL_AURA_MOD_PERCENT_STAT not valid"); + return; } + Unit* target = aurApp->GetTarget(); + // save current health state float healthPct = target->GetHealthPct(); - bool zeroHealth = !target->IsAlive(); + bool alive = target->IsAlive(); - // players in corpse state may mean two different states: - /// 1. player just died but did not release (in this case health == 0) - /// 2. player is corpse running (ie ghost) (in this case health == 1) - if (target->getDeathState() == CORPSE) - zeroHealth = (target->GetHealth() == 0); - - for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++) + for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i) { - if (GetMiscValueB() & 1 << i || !GetMiscValueB()) // 0 is also used for all stats + if ((GetMiscValueB() & 1 << i) || !GetMiscValueB()) // affect the same stats { - int32 spellGroupVal2 = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, true, i); - if (abs(spellGroupVal2) >= abs(GetAmount())) + float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, [i](AuraEffect const* aurEff) -> bool + { + if ((aurEff->GetMiscValueB() & 1 << i) || aurEff->GetMiscValueB() == -1) + return true; + return false; + }); + + if (target->GetPctModifierValue(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT) == amount) continue; - if (spellGroupVal2) - { - target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(spellGroupVal2), !apply); - if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) - target->ApplyStatPercentBuffMod(Stats(i), float(spellGroupVal2), !apply); - } - - target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(GetAmount()), apply); + target->SetStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, amount); if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) - target->ApplyStatPercentBuffMod(Stats(i), float(GetAmount()), apply); + target->UpdateStatBuffMod(Stats(i)); } } - // recalculate current HP/MP after applying aura modifications (only for spells with SPELL_ATTR0_UNK4 0x00000010 flag) + // recalculate current HP/MP after applying aura modifications (only for spells with SPELL_ATTR0_ABILITY 0x00000010 flag) // this check is total bullshit i think - if (GetMiscValueB() & 1 << STAT_STAMINA && (m_spellInfo->Attributes & SPELL_ATTR0_ABILITY)) - target->SetHealth(std::max(CalculatePct(target->GetMaxHealth(), healthPct), (zeroHealth ? 1 : 0))); + if (((GetMiscValueB() & 1 << STAT_STAMINA) || GetMiscValueB() == - 1) && m_spellInfo->HasAttribute(SPELL_ATTR0_ABILITY)) + target->SetHealth(std::max(uint32(healthPct * target->GetMaxHealth() * 0.01f), (alive ? 1 : 0))); } void AuraEffect::HandleAuraModResistenceOfStatPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const @@ -3731,7 +3739,7 @@ void AuraEffect::HandleModPowerRegenPCT(AuraApplication const* aurApp, uint8 mod Unit* target = aurApp->GetTarget(); if (target->GetTypeId() == TYPEID_PLAYER) - target->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_HASTE_REGEN, GetAmount(), !apply); + target->ApplyHasteRegenMod(target->getClass() == CLASS_HUNTER ? RANGED_ATTACK : BASE_ATTACK, GetAmount(), apply); HandleModPowerRegen(aurApp, mode, apply); } @@ -3783,7 +3791,7 @@ void AuraEffect::HandleAuraModIncreaseHealth(AuraApplication const* aurApp, uint if (apply) { - target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatFlatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); target->ModifyHealth(GetAmount()); } else @@ -3793,7 +3801,7 @@ void AuraEffect::HandleAuraModIncreaseHealth(AuraApplication const* aurApp, uint int32 value = std::min(target->GetHealth() - 1, GetAmount()); target->ModifyHealth(-value); } - target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatFlatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); } } @@ -3806,7 +3814,7 @@ void AuraEffect::HandleAuraModIncreaseMaxHealth(AuraApplication const* aurApp, u float percent = target->GetHealthPct(); - target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatFlatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); // refresh percentage if (target->GetHealth() > 0) @@ -3833,7 +3841,7 @@ void AuraEffect::HandleAuraModIncreaseEnergy(AuraApplication const* aurApp, uint UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + powerType); - target->HandleStatModifier(unitMod, TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatFlatModifier(unitMod, TOTAL_VALUE, float(GetAmount()), apply); } void AuraEffect::HandleAuraModIncreaseEnergyPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -3844,25 +3852,22 @@ void AuraEffect::HandleAuraModIncreaseEnergyPercent(AuraApplication const* aurAp Unit* target = aurApp->GetTarget(); Powers powerType = Powers(GetMiscValue()); - // do not check power type, we can always modify the maximum - // as the client will not see any difference - // also, placing conditions that may change during the aura duration - // inside effect handlers is not a good idea - //if (int32(powerType) != GetMiscValue()) - // return; - UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + powerType); float amount = float(GetAmount()); if (apply) { - target->HandleStatModifier(unitMod, TOTAL_PCT, amount, apply); - target->ModifyPowerPct(powerType, amount, apply); + float amount = float(GetAmount()); + target->ApplyStatPctModifier(unitMod, TOTAL_PCT, amount); + + float power = target->GetMaxPower(powerType); + AddPct(power, amount); + target->ModifyPower(powerType, (int32)power - (int32)target->GetMaxPower(powerType)); } else { - target->ModifyPowerPct(powerType, amount, apply); - target->HandleStatModifier(unitMod, TOTAL_PCT, amount, apply); + float amount = target->GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT, GetMiscValue()); + target->SetStatPctModifier(unitMod, TOTAL_PCT, amount); } } @@ -3875,11 +3880,17 @@ void AuraEffect::HandleAuraModIncreaseHealthPercent(AuraApplication const* aurAp // Unit will keep hp% after MaxHealth being modified if unit is alive. float percent = target->GetHealthPct(); - target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(GetAmount()), apply); + if (apply) + target->ApplyStatPctModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(GetAmount())); + else + { + float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT); + target->SetStatPctModifier(UNIT_MOD_HEALTH, TOTAL_PCT, amount); + } if (target->GetHealth() > 0) { - uint32 newHealth = std::max(target->CountPctFromMaxHealth(int32(percent)), 1); + uint32 newHealth = std::max(CalculatePct(target->GetMaxHealth(), percent), 1); target->SetHealth(newHealth); } } @@ -3891,7 +3902,13 @@ void AuraEffect::HandleAuraIncreaseBaseHealthPercent(AuraApplication const* aurA Unit* target = aurApp->GetTarget(); - target->HandleStatModifier(UNIT_MOD_HEALTH, BASE_PCT, float(GetAmount()), apply); + if (apply) + target->ApplyStatPctModifier(UNIT_MOD_HEALTH, BASE_PCT, float(GetAmount())); + else + { + float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_BASE_HEALTH_PCT); + target->SetStatPctModifier(UNIT_MOD_HEALTH, BASE_PCT, amount); + } } /********************************/ @@ -3942,7 +3959,7 @@ void AuraEffect::HandleAuraModRegenInterrupt(AuraApplication const* aurApp, uint HandleModManaRegen(aurApp, mode, apply); } -void AuraEffect::HandleAuraModWeaponCritPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModWeaponCritPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; @@ -3952,9 +3969,7 @@ void AuraEffect::HandleAuraModWeaponCritPercent(AuraApplication const* aurApp, u if (!target) return; - target->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float(GetAmount()), apply); - target->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float(GetAmount()), apply); - target->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float(GetAmount()), apply); + target->UpdateAllWeaponDependentCritAuras(); } void AuraEffect::HandleModHitChance(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const @@ -4015,26 +4030,14 @@ void AuraEffect::HandleAuraModCritPct(AuraApplication const* aurApp, uint8 mode, return; Unit* target = aurApp->GetTarget(); - int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_CRIT_PCT); - if (abs(spellGroupVal) >= abs(GetAmount())) - return; if (target->GetTypeId() != TYPEID_PLAYER) { - target->m_baseSpellCritChance += (apply) ? GetAmount():-GetAmount(); + target->m_baseSpellCritChance += (apply) ? GetAmount() : -GetAmount(); return; } - if (spellGroupVal) - { - target->ToPlayer()->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), !apply); - target->ToPlayer()->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), !apply); - target->ToPlayer()->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), !apply); - } - - target->ToPlayer()->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); - target->ToPlayer()->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); - target->ToPlayer()->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); + target->ToPlayer()->UpdateAllWeaponDependentCritAuras(); // included in Player::UpdateSpellCritChance calculation target->ToPlayer()->UpdateAllSpellCritChances(); @@ -4230,7 +4233,7 @@ void AuraEffect::HandleAuraModAttackPower(AuraApplication const* aurApp, uint8 m Unit* target = aurApp->GetTarget(); - target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(GetAmount()), apply); } void AuraEffect::HandleAuraModRangedAttackPower(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -4243,7 +4246,7 @@ void AuraEffect::HandleAuraModRangedAttackPower(AuraApplication const* aurApp, u if ((target->getClassMask() & CLASSMASK_WAND_USERS) != 0) return; - target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(GetAmount()), apply); } void AuraEffect::HandleAuraModAttackPowerPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -4252,15 +4255,15 @@ void AuraEffect::HandleAuraModAttackPowerPercent(AuraApplication const* aurApp, return; Unit* target = aurApp->GetTarget(); - int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_ATTACK_POWER_PCT); - if (abs(spellGroupVal) >= abs(GetAmount())) - return; - - if (spellGroupVal) - target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, float(spellGroupVal), !apply); //UNIT_FIELD_ATTACK_POWER_MULTIPLIER = multiplier - 1 - target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, float(GetAmount()), apply); + if (apply) + target->ApplyStatPctModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, float(GetAmount())); + else + { + float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_ATTACK_POWER_PCT); + target->SetStatPctModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, amount); + } } void AuraEffect::HandleAuraModRangedAttackPowerPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -4273,15 +4276,14 @@ void AuraEffect::HandleAuraModRangedAttackPowerPercent(AuraApplication const* au if ((target->getClassMask() & CLASSMASK_WAND_USERS) != 0) return; - int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_RANGED_ATTACK_POWER_PCT); - if (abs(spellGroupVal) >= abs(GetAmount())) - return; - - if (spellGroupVal) - target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, float(spellGroupVal), !apply); - //UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = multiplier - 1 - target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, float(GetAmount()), apply); + if (apply) + target->ApplyStatPctModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, float(GetAmount())); + else + { + float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_RANGED_ATTACK_POWER_PCT); + target->SetStatPctModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, amount); + } } void AuraEffect::HandleAuraModAttackPowerOfArmor(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const @@ -4320,11 +4322,7 @@ void AuraEffect::HandleModDamageDone(AuraApplication const* aurApp, uint8 mode, Unit* target = aurApp->GetTarget(); if (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) - { - target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(GetAmount()), apply); - target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(GetAmount()), apply); - target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(GetAmount()), apply); - } + target->UpdateAllDamageDoneMods(); // Magic damage modifiers implemented in Unit::SpellBaseDamageBonusDone // This information for client side use only @@ -4340,36 +4338,24 @@ void AuraEffect::HandleModDamageDone(AuraApplication const* aurApp, uint8 mode, } } -void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); - if (abs(spellGroupVal) >= abs(GetAmount())) - return; + // also handles spell group stacks if (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) - { - if (spellGroupVal) - { - target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(spellGroupVal), !apply); - target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(spellGroupVal), !apply); - target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(spellGroupVal), !apply); - } - - target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(GetAmount()), apply); - target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetAmount()), apply); - target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(GetAmount()), apply); - } + target->UpdateAllDamagePctDoneMods(); if (target->GetTypeId() == TYPEID_PLAYER) { - for (uint16 i = 0; i < MAX_SPELL_SCHOOL; ++i) + for (uint8 i = 0; i < MAX_SPELL_SCHOOL; ++i) { if (GetMiscValue() & (1 << i)) { + // only aura type modifying PLAYER_FIELD_MOD_DAMAGE_DONE_PCT float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, 1 << i); target->SetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT + i, amount); } @@ -4377,14 +4363,15 @@ void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 } } -void AuraEffect::HandleModOffhandDamagePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModOffhandDamagePercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetAmount()), apply); + // also handles spell group stacks + target->UpdateDamagePctDoneMods(OFF_ATTACK); } void AuraEffect::HandleShieldBlockValue(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -4392,14 +4379,11 @@ void AuraEffect::HandleShieldBlockValue(AuraApplication const* aurApp, uint8 mod if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; - Unit* target = aurApp->GetTarget(); + Player* target = aurApp->GetTarget()->ToPlayer(); + if (!target) + return; - BaseModType modType = FLAT_MOD; - if (GetAuraType() == SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT) - modType = PCT_MOD; - - if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->HandleBaseModValue(SHIELD_BLOCK_VALUE, modType, float(GetAmount()), apply); + target->HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, float(GetAmount()), apply); } /********************************/ @@ -4419,6 +4403,24 @@ void AuraEffect::HandleModPowerCostPCT(AuraApplication const* aurApp, uint8 mode target->ApplyModSignedFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER + i, amount, apply); } +void AuraEffect::HandleShieldBlockValuePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + return; + + Player* target = aurApp->GetTarget()->ToPlayer(); + if (!target) + return; + + if (apply) + target->ApplyBaseModPctValue(SHIELD_BLOCK_VALUE, float(GetAmount())); + else + { + float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT); + target->SetBaseModPctValue(SHIELD_BLOCK_VALUE, amount); + } +} + void AuraEffect::HandleModPowerCost(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index bb69993484..3caffcbe3c 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -275,6 +275,7 @@ class TC_GAME_API AuraEffect void HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleModOffhandDamagePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleShieldBlockValue(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandleShieldBlockValuePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; // power cost void HandleModPowerCostPCT(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleModPowerCost(AuraApplication const* aurApp, uint8 mode, bool apply) const; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index ace1df863e..c2a493e1c4 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -2814,7 +2814,7 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break; } - float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT); + float weapon_total_pct = m_caster->GetPctModifierValue(unitMod, TOTAL_PCT); if (fixed_bonus) fixed_bonus = int32(fixed_bonus * weapon_total_pct); } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp index 0046bc6d2e..e8d207d719 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp @@ -885,26 +885,20 @@ public: class spell_kelthuzad_chains_AuraScript : public AuraScript { - void HandleApply(AuraEffect const* /*eff*/, AuraEffectHandleModes /*mode*/) + void HandleApply(AuraEffect const* aurEff, AuraEffectHandleModes mode) { - Unit* target = GetTarget(); - float scale = target->GetObjectScale(); - ApplyPercentModFloatVar(scale, 200.0f, true); - target->SetObjectScale(scale); + aurEff->HandleAuraModScale(GetTargetApplication(), mode, true); } - void HandleRemove(AuraEffect const* /*eff*/, AuraEffectHandleModes /*mode*/) + void HandleRemove(AuraEffect const* aurEff, AuraEffectHandleModes mode) { - Unit* target = GetTarget(); - float scale = target->GetObjectScale(); - ApplyPercentModFloatVar(scale, 200.0f, false); - target->SetObjectScale(scale); + aurEff->HandleAuraModScale(GetTargetApplication(), mode, false); } void Register() override { - AfterEffectApply.Register(&spell_kelthuzad_chains_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_AOE_CHARM, AURA_EFFECT_HANDLE_REAL); - AfterEffectRemove.Register(&spell_kelthuzad_chains_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_AOE_CHARM, AURA_EFFECT_HANDLE_REAL); + AfterEffectApply.Register(&spell_kelthuzad_chains_AuraScript::HandleApply, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove.Register(&spell_kelthuzad_chains_AuraScript::HandleRemove, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, AURA_EFFECT_HANDLE_REAL); } };