fix(Core/Spells): Implement TrinityCore spell_group and spell_group_stack_rules (#23346)

Co-authored-by: treeston <treeston.mmoc@gmail.com>
Co-authored-by: Trisjdc <trisjdc@gmail.com>
Co-authored-by: QAston <none@none>
Co-authored-by: ariel- <ariel-@users.noreply.github.com>
Co-authored-by: Shauren <shauren.trinity@gmail.com>
Co-authored-by: Jelle Meeus <sogladev@gmail.com>
This commit is contained in:
Tereneckla
2025-11-28 19:01:25 +00:00
committed by GitHub
parent 55989205e7
commit 2f7f9bd72f
42 changed files with 1976 additions and 1705 deletions
-9
View File
@@ -47,15 +47,6 @@ AC_COMMON_API Optional<int32> MoneyStringToMoney(std::string_view moneyString);
std::string secsToTimeString(uint64 timeInSecs, bool shortText = false);
uint32 TimeStringToSecs(const std::string& timestring);
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 <class T, class U>
inline T CalculatePct(T base, U pct)
+14 -18
View File
@@ -38,6 +38,7 @@
#include "PoolMgr.h"
#include "ScriptMgr.h"
#include "ScriptedGossip.h"
#include "SpellAuraDefines.h"
#include "SpellAuraEffects.h"
#include "SpellMgr.h"
#include "TemporarySummon.h"
@@ -601,13 +602,13 @@ bool Creature::UpdateEntry(uint32 Entry, const CreatureData* data, bool changele
SetMeleeDamageSchool(SpellSchools(cInfo->dmgschool));
CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(GetLevel(), cInfo->unit_class);
float armor = stats->GenerateArmor(cInfo);
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, armor);
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_ARMOR, BASE_VALUE, armor);
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();
@@ -1017,10 +1018,7 @@ void Creature::Regenerate(Powers power)
}
// Apply modifiers (if any).
AuraEffectList const& ModPowerRegenPCTAuras = GetAuraEffectsByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT);
for (AuraEffectList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
if (Powers((*i)->GetMiscValue()) == power)
AddPct(addvalue, (*i)->GetAmount());
addvalue *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, power);
addvalue += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, power) * (power == POWER_FOCUS ? PET_FOCUS_REGEN_INTERVAL.count() : CREATURE_REGEN_INTERVAL) / (5 * IN_MILLISECONDS);
@@ -1056,9 +1054,7 @@ void Creature::RegenerateHealth()
}
// Apply modifiers (if any).
AuraEffectList const& ModPowerRegenPCTAuras = GetAuraEffectsByType(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
for (AuraEffectList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
AddPct(addvalue, (*i)->GetAmount());
addvalue *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
addvalue += GetTotalAuraModifier(SPELL_AURA_MOD_REGEN) * CREATURE_REGEN_INTERVAL / (5 * IN_MILLISECONDS);
@@ -1558,8 +1554,8 @@ void Creature::SelectLevel(bool changelevel)
/// @todo: set UNIT_FIELD_POWER*, for some creature class case (energy, etc)
SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)health);
SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, (float)mana);
SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, (float)health);
SetStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, (float)mana);
// damage
@@ -1577,8 +1573,8 @@ void Creature::SelectLevel(bool changelevel)
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);
sScriptMgr->OnCreatureSelectLevel(cInfo, this);
}
@@ -815,13 +815,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);
-1
View File
@@ -165,7 +165,6 @@ public:
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);
+7 -25
View File
@@ -1075,7 +1075,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool));
}
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel * 50));
SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel * 50));
uint32 attackTime = BASE_ATTACK_TIME;
if (!owner->IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET) && cinfo->BaseAttackTime >= 1000)
@@ -1094,7 +1094,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
// xinef: hunter pets should not inherit template resistances
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);
@@ -1111,15 +1111,15 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
}
SetCreateHealth(pInfo->health*factorHealth);
SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)pInfo->health);
SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, (float)pInfo->health);
if (petType != HUNTER_PET) //hunter pet use focus
{
SetCreateMana(pInfo->mana);
SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, (float)pInfo->mana);
SetStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, (float)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]));
@@ -1138,9 +1138,9 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
}
SetCreateHealth(std::max<uint32>(1, stats->BaseHealth[cinfo->expansion]*factorHealth));
SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, GetCreateHealth());
SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, GetCreateHealth());
SetCreateMana(stats->BaseMana * factorMana);
SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, GetCreateMana());
SetStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, GetCreateMana());
// xinef: added some multipliers so debuffs can affect pets in any way...
SetCreateStat(STAT_STRENGTH, 22);
@@ -1174,24 +1174,6 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
switch (GetEntry())
{
case NPC_FELGUARD:
{
// xinef: Glyph of Felguard, so ugly im crying... no appropriate spell
if (AuraEffect* aurEff = owner->GetAuraEffectDummy(SPELL_GLYPH_OF_FELGUARD))
{
HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, aurEff->GetAmount(), true);
}
break;
}
case NPC_VOIDWALKER:
{
if (AuraEffect* aurEff = owner->GetAuraEffectDummy(SPELL_GLYPH_OF_VOIDWALKER))
{
HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_PCT, aurEff->GetAmount(), true);
}
break;
}
case NPC_WATER_ELEMENTAL_PERM:
{
AddAura(SPELL_PET_AVOIDANCE, this);
@@ -21,6 +21,7 @@
#include "Pet.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "SpellAuraDefines.h"
#include "SpellAuraEffects.h"
// KillRewarder incapsulates logic of rewarding player upon kill with:
@@ -162,9 +163,7 @@ void KillRewarder::_RewardXP(Player* player, float rate)
if (xp)
{
// 4.2.2. Apply auras modifying rewarded XP (SPELL_AURA_MOD_XP_PCT).
Unit::AuraEffectList const& auras = player->GetAuraEffectsByType(SPELL_AURA_MOD_XP_PCT);
for (Unit::AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
AddPct(xp, (*i)->GetAmount());
xp *= player->GetTotalAuraMultiplier(SPELL_AURA_MOD_XP_PCT);
// 4.2.3. Give XP to player.
sScriptMgr->OnPlayerGiveXP(player, xp, _victim, PlayerXPSource::XPSOURCE_KILL);
+225 -184
View File
@@ -69,8 +69,10 @@
#include "Realm.h"
#include "ReputationMgr.h"
#include "ScriptMgr.h"
#include "SharedDefines.h"
#include "SocialMgr.h"
#include "Spell.h"
#include "SpellAuraDefines.h"
#include "SpellAuraEffects.h"
#include "SpellAuras.h"
#include "SpellMgr.h"
@@ -312,8 +314,8 @@ Player::Player(WorldSession* session): Unit(), m_mover(this)
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++)
@@ -831,9 +833,7 @@ int32 Player::getMaxTimer(MirrorTimerType timer)
if (!IsAlive() || HasWaterBreathingAura() || GetSession()->GetSecurity() >= AccountTypes(sWorld->getIntConfig(CONFIG_DISABLE_BREATHING)))
return DISABLED_MIRROR_TIMER;
int32 UnderWaterTime = sWorld->getIntConfig(CONFIG_WATER_BREATH_TIMER);
AuraEffectList const& mModWaterBreathing = GetAuraEffectsByType(SPELL_AURA_MOD_WATER_BREATHING);
for (AuraEffectList::const_iterator i = mModWaterBreathing.begin(); i != mModWaterBreathing.end(); ++i)
AddPct(UnderWaterTime, (*i)->GetAmount());
UnderWaterTime *= GetTotalAuraMultiplier(SPELL_AURA_MOD_WATER_BREATHING);
return UnderWaterTime;
}
case FIRE_TIMER:
@@ -1922,10 +1922,7 @@ void Player::Regenerate(Powers power)
// Mana regen calculated in Player::UpdateManaRegen(), energy regen calculated in Player::UpdateEnergyRegen()
if (power != POWER_MANA && power != POWER_ENERGY)
{
AuraEffectList const& ModPowerRegenPCTAuras = GetAuraEffectsByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT);
for (AuraEffectList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
if (Powers((*i)->GetMiscValue()) == power)
AddPct(addvalue, (*i)->GetAmount());
addvalue *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, power);
// Butchery requires combat for this effect
if (power != POWER_RUNIC_POWER || IsInCombat())
@@ -2008,11 +2005,7 @@ void Player::RegenerateHealth()
addvalue *= 1.33f;
}
AuraEffectList const& mModHealthRegenPct = GetAuraEffectsByType(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
for (AuraEffectList::const_iterator i = mModHealthRegenPct.begin(); i != mModHealthRegenPct.end(); ++i)
{
AddPct(addvalue, (*i)->GetAmount());
}
addvalue *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
if (!IsInCombat())
{
@@ -2666,14 +2659,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 + AsUnderlyingType(SPELL_SCHOOL_NORMAL), 0.0f);
SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + AsUnderlyingType(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);
@@ -5012,24 +5005,107 @@ void Player::ClearChannelWatch()
(*itr)->RemoveWatching(this);
}
void Player::HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, float amount, bool apply)
void Player::HandleBaseModFlatValue(BaseModGroup modGroup, float amount, bool apply)
{
if (modGroup >= BASEMOD_END)
{
LOG_ERROR("entities.player", "ERROR in HandleBaseModValue(): non existed BaseModGroup!");
LOG_ERROR("entities.player", "Player::HandleBaseModFlatValue: Invalid BaseModGroup/BaseModType ({}/{}) for player '{}' ({})",
modGroup, FLAT_MOD, GetName(), GetGUID().ToString());
return;
}
switch (modType)
m_auraBaseFlatMod[modGroup] += apply ? amount : -amount;
UpdateBaseModGroup(modGroup);
}
void Player::ApplyBaseModPctValue(BaseModGroup modGroup, float pct)
{
if (modGroup >= BASEMOD_END)
{
case FLAT_MOD:
m_auraBaseMod[modGroup][modType] += apply ? amount : -amount;
LOG_ERROR("entities.player", "Player::ApplyBaseModPctValue: Invalid BaseModGroup/BaseModType ({}/{}) for player '{}' ({})",
modGroup, PCT_MOD, GetName(), GetGUID().ToString());
return;
}
m_auraBasePctMod[modGroup] += CalculatePct(1.0f, 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, int32 skipEnchantSlot /*= -1*/)
{
Unit::UpdateDamageDoneMods(attackType, skipEnchantSlot);
UnitMods unitMod;
switch (attackType)
{
case BASE_ATTACK:
unitMod = UNIT_MOD_DAMAGE_MAINHAND;
break;
case PCT_MOD:
ApplyPercentModFloatVar(m_auraBaseMod[modGroup][modType], amount, apply);
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)
{
if (skipEnchantSlot == slot)
continue;
SpellItemEnchantmentEntry const* enchantmentEntry = sSpellItemEnchantmentStore.LookupEntry(item->GetEnchantmentId(EnchantmentSlot(slot)));
if (!enchantmentEntry)
continue;
for (uint8 i = 0; i < MAX_SPELL_ITEM_ENCHANTMENT_EFFECTS; ++i)
{
switch (enchantmentEntry->type[i])
{
case ITEM_ENCHANTMENT_TYPE_DAMAGE:
amount += enchantmentEntry->amount[i];
break;
case ITEM_ENCHANTMENT_TYPE_TOTEM:
if (IsClass(CLASS_SHAMAN, CLASS_CONTEXT_ABILITY))
amount += enchantmentEntry->amount[i] * item->GetTemplate()->Delay / 1000.0f;
break;
default:
break;
}
}
}
HandleStatFlatModifier(unitMod, TOTAL_VALUE, amount, true);
}
void Player::UpdateBaseModGroup(BaseModGroup modGroup)
{
if (!CanModifyStats())
return;
@@ -5060,10 +5136,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
@@ -5074,15 +5147,15 @@ float Player::GetTotalBaseModValue(BaseModGroup modGroup) const
return 0.0f;
}
if (m_auraBaseMod[modGroup][PCT_MOD] <= 0.0f)
if (m_auraBasePctMod[modGroup] <= 0.0f)
return 0.0f;
return m_auraBaseMod[modGroup][FLAT_MOD] * m_auraBaseMod[modGroup][PCT_MOD];
return m_auraBaseFlatMod[modGroup] * m_auraBasePctMod[modGroup];
}
uint32 Player::GetShieldBlockValue() const
{
float value = (m_auraBaseMod[SHIELD_BLOCK_VALUE][FLAT_MOD] + GetStat(STAT_STRENGTH) * 0.5f - 10) * m_auraBaseMod[SHIELD_BLOCK_VALUE][PCT_MOD];
float value = (m_auraBaseFlatMod[SHIELD_BLOCK_VALUE] + GetStat(STAT_STRENGTH) * 0.5f - 10) * m_auraBasePctMod[SHIELD_BLOCK_VALUE];
value = (value < 0) ? 0 : value;
@@ -5151,7 +5224,7 @@ void Player::GetDodgeFromAgility(float& diminishing, float& nondiminishing)
return;
/// @todo: research if talents/effects that increase total agility by x% should increase non-diminishing part
float base_agility = GetCreateStat(STAT_AGILITY) * m_auraModifiersGroup[UNIT_MOD_STAT_START + static_cast<uint16>(STAT_AGILITY)][BASE_PCT];
float base_agility = GetCreateStat(STAT_AGILITY) * GetPctModifierValue(UnitMods(UNIT_MOD_STAT_START + AsUnderlyingType(STAT_AGILITY)), BASE_PCT);
float bonus_agility = GetStat(STAT_AGILITY) - base_agility;
// calculate diminishing (green in char screen) and non-diminishing (white) contribution
@@ -6574,20 +6647,22 @@ void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply)
LOG_DEBUG("entities.player", "applying mods for item {} ", item->GetGUID().ToString());
WeaponAttackType attacktype = Player::GetAttackBySlot(slot);
if (item->HasSocket()) //only (un)equipping of items with sockets can influence metagems, so no need to waste time with normal items
CorrectMetaGemEnchants(slot, apply);
if (attacktype < MAX_ATTACK)
_ApplyWeaponDependentAuraMods(item, attacktype, apply);
_ApplyItemBonuses(proto, slot, apply);
if (slot == EQUIPMENT_SLOT_RANGED)
_ApplyAmmoBonuses();
ApplyItemEquipSpell(item, apply);
ApplyItemDependentAuras(item, apply);
WeaponAttackType const attackType = Player::GetAttackBySlot(slot);
if (attackType != MAX_ATTACK)
UpdateWeaponDependentAuras(attackType);
ApplyEnchantment(item, apply);
LOG_DEBUG("entities.player.items", "_ApplyItemMods complete.");
@@ -6658,30 +6733,30 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
switch (statType)
{
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);
@@ -6770,11 +6845,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);
HandleStatFlatModifier(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_RANGED, TOTAL_VALUE, float(val), apply);
break;
// case ITEM_MOD_FERAL_ATTACK_POWER:
// ApplyFeralAPBonus(int32(val), apply);
@@ -6795,7 +6870,7 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
ApplySpellPenetrationBonus(val, apply);
break;
case ITEM_MOD_BLOCK_VALUE:
HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(val), apply);
HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, float(val), apply);
break;
/// @deprecated item mods
case ITEM_MOD_SPELL_HEALING_DONE:
@@ -6825,7 +6900,7 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
if (armor)
{
UnitModifierType modType = TOTAL_VALUE;
UnitModifierFlatType modType = TOTAL_VALUE;
if (proto->Class == ITEM_CLASS_ARMOR)
{
switch (proto->SubClass)
@@ -6839,33 +6914,33 @@ 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->ArmorDamageModifier > 0 && sScriptMgr->OnPlayerCanArmorDamageModifier(this))
HandleStatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(proto->ArmorDamageModifier), apply);
HandleStatFlatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(proto->ArmorDamageModifier), apply);
if (proto->Block)
HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(proto->Block), apply);
HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, float(proto->Block), apply);
if (proto->HolyRes)
HandleStatModifier(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(proto->HolyRes), apply);
HandleStatFlatModifier(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(proto->HolyRes), apply);
if (proto->FireRes)
HandleStatModifier(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(proto->FireRes), apply);
HandleStatFlatModifier(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(proto->FireRes), apply);
if (proto->NatureRes)
HandleStatModifier(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(proto->NatureRes), apply);
HandleStatFlatModifier(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(proto->NatureRes), apply);
if (proto->FrostRes)
HandleStatModifier(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(proto->FrostRes), apply);
HandleStatFlatModifier(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(proto->FrostRes), apply);
if (proto->ShadowRes)
HandleStatModifier(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(proto->ShadowRes), apply);
HandleStatFlatModifier(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(proto->ShadowRes), apply);
if (proto->ArcaneRes)
HandleStatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(proto->ArcaneRes), apply);
HandleStatFlatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(proto->ArcaneRes), apply);
WeaponAttackType attType = Player::GetAttackBySlot(slot);
if (attType != MAX_ATTACK)
@@ -7036,6 +7111,84 @@ void Player::UpdateItemObtainSpells(Item* item, uint8 bag, uint8 slot)
ApplyItemObtainSpells(item, true);
}
// 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)
{
PlayerSpellMap const& spells = GetSpellMap();
for (auto itr = spells.begin(); itr != spells.end(); ++itr)
{
if (itr->second->State == PLAYERSPELL_REMOVED)
continue;
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
if (!spellInfo || !spellInfo->IsPassive() || spellInfo->EquippedItemClass < 0)
continue;
if (!HasAura(itr->first) && HasItemFitToSpellRequirements(spellInfo))
AddAura(itr->first, this); // no SMSG_SPELL_GO in sniff found
}
}
else
RemoveItemDependentAurasAndCasts(item);
}
bool Player::CheckAttackFitToAuraRequirement(WeaponAttackType attackType, AuraEffect const* aurEff) const
{
SpellInfo const* spellInfo = aurEff->GetSpellInfo();
if (spellInfo->EquippedItemClass == -1)
return true;
Item* item = GetWeaponForAttack(attackType, true);
if (!item || !item->IsFitToSpellRequirements(spellInfo))
return false;
return true;
}
SpellSchoolMask Player::GetMeleeDamageSchoolMask(WeaponAttackType attackType /*= BASE_ATTACK*/, uint8 damageIndex /*= 0*/) const
{
if (Item const* weapon = GetWeaponForAttack(attackType, true))
@@ -7046,110 +7199,6 @@ SpellSchoolMask Player::GetMeleeDamageSchoolMask(WeaponAttackType attackType /*=
return SPELL_SCHOOL_MASK_NORMAL;
}
void Player::_ApplyWeaponDependentAuraMods(Item* item, WeaponAttackType attackType, bool apply)
{
AuraEffectList const& auraCritList = GetAuraEffectsByType(SPELL_AURA_MOD_WEAPON_CRIT_PERCENT);
for (AuraEffectList::const_iterator itr = auraCritList.begin(); itr != auraCritList.end(); ++itr)
_ApplyWeaponDependentAuraCritMod(item, attackType, *itr, apply);
AuraEffectList const& auraDamageFlatList = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE);
for (AuraEffectList::const_iterator itr = auraDamageFlatList.begin(); itr != auraDamageFlatList.end(); ++itr)
_ApplyWeaponDependentAuraDamageMod(item, attackType, *itr, apply);
AuraEffectList const& auraDamagePctList = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
for (AuraEffectList::const_iterator itr = auraDamagePctList.begin(); itr != auraDamagePctList.end(); ++itr)
_ApplyWeaponDependentAuraDamageMod(item, attackType, *itr, apply);
}
void Player::_ApplyWeaponDependentAuraCritMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply)
{
// don't apply mod if item is broken or cannot be used
if (item->IsBroken() || !CanUseAttackType(attackType))
return;
// generic not weapon specific case processes in aura code
if (aura->GetSpellInfo()->EquippedItemClass == -1)
return;
if (!sScriptMgr->OnPlayerCanApplyWeaponDependentAuraDamageMod(this, item, attackType, aura, apply))
return;
BaseModGroup mod = BASEMOD_END;
switch (attackType)
{
case BASE_ATTACK:
mod = CRIT_PERCENTAGE;
break;
case OFF_ATTACK:
mod = OFFHAND_CRIT_PERCENTAGE;
break;
case RANGED_ATTACK:
mod = RANGED_CRIT_PERCENTAGE;
break;
default:
return;
}
if (item->IsFitToSpellRequirements(aura->GetSpellInfo()))
HandleBaseModValue(mod, FLAT_MOD, float (aura->GetAmount()), apply);
}
void Player::_ApplyWeaponDependentAuraDamageMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply)
{
// don't apply mod if item is broken or cannot be used
if (item->IsBroken() || !CanUseAttackType(attackType))
return;
// ignore spell mods for not wands
if ((aura->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) == 0 && (getClassMask() & CLASSMASK_WAND_USERS) == 0)
return;
// generic not weapon specific case processes in aura code
if (aura->GetSpellInfo()->EquippedItemClass == -1)
return;
UnitMods unitMod = UNIT_MOD_END;
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:
return;
}
UnitModifierType unitModType = TOTAL_VALUE;
switch (aura->GetAuraType())
{
case SPELL_AURA_MOD_DAMAGE_DONE:
unitModType = TOTAL_VALUE;
break;
case SPELL_AURA_MOD_DAMAGE_PERCENT_DONE:
unitModType = TOTAL_PCT;
break;
default:
return;
}
if (item->IsFitToSpellRequirements(aura->GetSpellInfo()))
{
HandleStatModifier(unitMod, unitModType, float(aura->GetAmount()), apply);
if (unitModType == TOTAL_VALUE)
{
if (aura->GetAmount() > 0)
ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, aura->GetAmount(), apply);
else
ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG, aura->GetAmount(), apply);
}
}
}
void Player::ApplyItemEquipSpell(Item* item, bool apply, bool form_change)
{
if (!item)
@@ -7464,12 +7513,6 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8
continue;
}
if (!spellInfo->CheckElixirStacking(this))
{
Spell::SendCastResult(this, spellInfo, cast_count, SPELL_FAILED_AURA_BOUNCED);
continue;
}
Spell* spell = new Spell(this, spellInfo, (count > 0) ? TRIGGERED_FULL_MASK : TRIGGERED_NONE);
spell->m_CastItem = item;
spell->m_cast_count = cast_count; // set count of casts
@@ -7578,10 +7621,7 @@ void Player::_RemoveAllItemMods()
if (!proto)
continue;
WeaponAttackType attacktype = Player::GetAttackBySlot(i);
if (attacktype < MAX_ATTACK)
_ApplyWeaponDependentAuraMods(m_items[i], attacktype, false);
ApplyItemDependentAuras(m_items[i], false);
_ApplyItemBonuses(proto, i, false);
if (i == EQUIPMENT_SLOT_RANGED)
@@ -7607,12 +7647,13 @@ void Player::_ApplyAllItemMods()
if (!proto)
continue;
WeaponAttackType attacktype = Player::GetAttackBySlot(i);
if (attacktype < MAX_ATTACK)
_ApplyWeaponDependentAuraMods(m_items[i], attacktype, true);
ApplyItemDependentAuras(m_items[i], false);
_ApplyItemBonuses(proto, i, true);
WeaponAttackType const attackType = Player::GetAttackBySlot(i);
if (attackType != MAX_ATTACK)
UpdateWeaponDependentAuras(attackType);
if (i == EQUIPMENT_SLOT_RANGED)
_ApplyAmmoBonuses();
}
@@ -12583,9 +12624,9 @@ void Player::RemoveItemDependentAurasAndCasts(Item* pItem)
{
Aura* aura = itr->second;
// skip passive (passive item dependent spells work in another way) and not self applied auras
// skip not self applied auras
SpellInfo const* spellInfo = aura->GetSpellInfo();
if (aura->IsPassive() || aura->GetCasterGUID() != GetGUID())
if (aura->GetCasterGUID() != GetGUID())
{
++itr;
continue;
+21 -8
View File
@@ -1334,7 +1334,7 @@ public:
{
return StoreItem(dest, pItem, update);
}
void RemoveItem(uint8 bag, uint8 slot, bool update, bool swap = false);
void RemoveItem(uint8 bag, uint8 slot, bool update);
void MoveItemFromInventory(uint8 bag, uint8 slot, bool update);
// in trade, auction, guild bank, mail....
void MoveItemToInventory(ItemPosCountVec const& dest, Item* pItem, bool update, bool in_characterInventoryDB = false);
@@ -2187,11 +2187,19 @@ public:
[[nodiscard]] 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, int32 skipEnchantSlot = -1) override;
void UpdateBaseModGroup(BaseModGroup modGroup);
[[nodiscard]] float GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const;
[[nodiscard]] float GetTotalBaseModValue(BaseModGroup modGroup) const;
[[nodiscard]] float GetTotalPercentageModValue(BaseModGroup modGroup) const { return m_auraBaseMod[modGroup][FLAT_MOD] + m_auraBaseMod[modGroup][PCT_MOD]; }
void _ApplyAllStatBonuses();
void _RemoveAllStatBonuses();
@@ -2203,9 +2211,13 @@ public:
SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType = BASE_ATTACK, uint8 damageIndex = 0) const override;
void _ApplyWeaponDependentAuraMods(Item* item, WeaponAttackType attackType, bool apply);
void _ApplyWeaponDependentAuraCritMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply);
void _ApplyWeaponDependentAuraDamageMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply);
void UpdateWeaponDependentAuras(WeaponAttackType attackType);
void ApplyItemDependentAuras(Item* item, bool apply);
bool CheckAttackFitToAuraRequirement(WeaponAttackType attackType, AuraEffect const* aurEff) const override;
void UpdateWeaponDependentCritAuras(WeaponAttackType attackType);
void UpdateAllWeaponDependentCritAuras();
void _ApplyItemMods(Item* item, uint8 slot, bool apply);
void _RemoveAllItemMods();
@@ -2829,7 +2841,8 @@ protected:
ActionButtonList m_actionButtons;
float m_auraBaseMod[BASEMOD_END][MOD_END];
float m_auraBaseFlatMod[BASEMOD_END];
float m_auraBasePctMod[BASEMOD_END];
int32 m_baseRatingValue[MAX_COMBAT_RATING];
uint32 m_baseSpellPower;
uint32 m_baseSpellDamage;
@@ -1405,9 +1405,7 @@ uint32 Player::CalculateQuestRewardXP(Quest const* quest)
uint32 xp = uint32(quest->XPValue(GetLevel()) * GetQuestRate(quest->IsDFQuest()));
// handle SPELL_AURA_MOD_XP_QUEST_PCT auras
Unit::AuraEffectList const& ModXPPctAuras = GetAuraEffectsByType(SPELL_AURA_MOD_XP_QUEST_PCT);
for (Unit::AuraEffectList::const_iterator i = ModXPPctAuras.begin(); i != ModXPPctAuras.end(); ++i)
AddPct(xp, (*i)->GetAmount());
xp *= GetTotalAuraMultiplier(SPELL_AURA_MOD_XP_QUEST_PCT);
return xp;
}
@@ -60,6 +60,7 @@
#include "StringConvert.h"
#include "Tokenize.h"
#include "Transport.h"
#include "Unit.h"
#include "UpdateFieldFlags.h"
#include "Util.h"
#include "World.h"
@@ -2896,7 +2897,7 @@ void Player::VisualizeItem(uint8 slot, Item* pItem)
pItem->SetState(ITEM_CHANGED, this);
}
void Player::RemoveItem(uint8 bag, uint8 slot, bool update, bool swap)
void Player::RemoveItem(uint8 bag, uint8 slot, bool update)
{
// note: removeitem does not actually change the item
// it only takes the item out of storage temporarily
@@ -2931,12 +2932,6 @@ void Player::RemoveItem(uint8 bag, uint8 slot, bool update, bool swap)
// remove item dependent auras and casts (only weapon and armor slots)
if (slot < INVENTORY_SLOT_BAG_END && slot < EQUIPMENT_SLOT_END)
{
// Xinef: Ensure that this function is called for places with swap=true
if (!swap)
{
RemoveItemDependentAurasAndCasts(pItem);
}
// remove held enchantments, update expertise
if (slot == EQUIPMENT_SLOT_MAINHAND)
{
@@ -3071,9 +3066,6 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
if (slot < EQUIPMENT_SLOT_END)
{
// remove item dependent auras and casts (only weapon and armor slots)
RemoveItemDependentAurasAndCasts(pItem);
// update expertise and armor penetration - passive auras may need it
switch (slot)
{
@@ -3865,8 +3857,8 @@ void Player::SwapItem(uint16 src, uint16 dst)
}
// now do moves, remove...
RemoveItem(dstbag, dstslot, false, true);
RemoveItem(srcbag, srcslot, false, true);
RemoveItem(dstbag, dstslot, false);
RemoveItem(srcbag, srcslot, false);
// add to dest
if (IsInventoryPos(dst))
@@ -4355,13 +4347,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, apply ? -1 : slot);
break;
}
case ITEM_ENCHANTMENT_TYPE_EQUIP_SPELL:
if (enchant_spell_id)
{
@@ -4412,7 +4403,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:
{
@@ -4439,36 +4430,36 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
{
case ITEM_MOD_MANA:
LOG_DEBUG("entities.player.items", "+ {} 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:
LOG_DEBUG("entities.player.items", "+ {} 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:
LOG_DEBUG("entities.player.items", "+ {} 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:
LOG_DEBUG("entities.player.items", "+ {} 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:
LOG_DEBUG("entities.player.items", "+ {} 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:
LOG_DEBUG("entities.player.items", "+ {} 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:
LOG_DEBUG("entities.player.items", "+ {} 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);
@@ -4579,12 +4570,12 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
LOG_DEBUG("entities.player.items", "+ {} 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);
LOG_DEBUG("entities.player.items", "+ {} 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);
LOG_DEBUG("entities.player.items", "+ {} RANGED_ATTACK_POWER", enchant_amount);
break;
// case ITEM_MOD_FERAL_ATTACK_POWER:
@@ -4612,7 +4603,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
LOG_DEBUG("entities.player.items", "+ {} 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);
LOG_DEBUG("entities.player.items", "+ {} BLOCK_VALUE", enchant_amount);
break;
/// @deprecated item mods
@@ -4631,20 +4622,9 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
}
case ITEM_ENCHANTMENT_TYPE_TOTEM: // Shaman Rockbiter Weapon
{
if (IsClass(CLASS_SHAMAN, CLASS_CONTEXT_ABILITY))
{
float addValue = 0.0f;
if (item->GetSlot() == EQUIPMENT_SLOT_MAINHAND)
{
addValue = float(enchant_amount * item->GetTemplate()->Delay / 1000.0f);
HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, addValue, apply);
}
else if (item->GetSlot() == EQUIPMENT_SLOT_OFFHAND)
{
addValue = float(enchant_amount * item->GetTemplate()->Delay / 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:
@@ -701,7 +701,7 @@ void Player::UpdateRating(CombatRating cr)
void Player::UpdateAllRatings()
{
for (int cr = 0; cr < MAX_COMBAT_RATING; ++cr)
for (uint cr = 0; cr < MAX_COMBAT_RATING; ++cr)
UpdateRating(CombatRating(cr));
}
+63 -67
View File
@@ -204,7 +204,7 @@ void Player::UpdateSpellDamageAndHealingBonus()
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));
@@ -247,9 +247,9 @@ void Player::UpdateResistances(uint32 school)
float value = 0.0f;
UnitMods unitMod = UnitMods(UNIT_MOD_RESISTANCE_START + school);
value = GetModifierValue(unitMod, BASE_VALUE);
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE);
value = GetFlatModifierValue(unitMod, BASE_VALUE);
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
AuraEffectList const& mResbyIntellect = GetAuraEffectsByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT);
for(AuraEffectList::const_iterator i = mResbyIntellect.begin(); i != mResbyIntellect.end(); ++i)
@@ -258,7 +258,7 @@ void Player::UpdateResistances(uint32 school)
value += int32(GetStat(Stats((*i)->GetMiscValueB())) * (*i)->GetAmount() / 100.0f);
}
value *= GetModifierValue(unitMod, TOTAL_PCT);
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetResistance(SpellSchools(school), int32(value));
}
@@ -270,10 +270,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
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
value += GetModifierValue(unitMod, TOTAL_VALUE);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
//add dynamic flat mods
AuraEffectList const& mResbyIntellect = GetAuraEffectsByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT);
@@ -283,7 +283,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));
@@ -314,10 +314,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);
sScriptMgr->OnPlayerAfterUpdateMaxHealth(this, value);
SetMaxHealth((uint32)value);
@@ -329,10 +329,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);
sScriptMgr->OnPlayerAfterUpdateMaxPower(this, power, value);
SetMaxPower(power, uint32(value));
@@ -487,10 +487,10 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
}
}
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)
@@ -514,7 +514,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;
sScriptMgr->OnPlayerAfterUpdateAttackPowerAndDamage(this, level, base_attPower, attPowerMod, attPowerMultiplier, ranged);
SetInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
@@ -576,10 +576,10 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo
float attackSpeedMod = GetAPMultiplier(attType, normalized);
float baseValue = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * attackSpeedMod;
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 * attackSpeedMod;
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);
@@ -681,7 +681,8 @@ 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(GetWeaponSkillValue(attType)) - int32(GetMaxSkillValueForLevel())) * 0.04f;
@@ -698,9 +699,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);
@@ -849,7 +850,7 @@ void Player::UpdateSpellCritChance(uint32 school)
// Crit from Intellect
crit += GetSpellCritFromIntellect();
// Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE
crit += GetTotalAuraModifierAreaExclusive(SPELL_AURA_MOD_SPELL_CRIT_CHANCE);
crit += GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE);
// Increase crit from SPELL_AURA_MOD_CRIT_PCT
crit += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PCT);
// Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
@@ -900,16 +901,11 @@ void Player::UpdateExpertise(WeaponAttackType attack)
Item* weapon = GetWeaponForAttack(attack, true);
AuraEffectList const& expAuras = GetAuraEffectsByType(SPELL_AURA_MOD_EXPERTISE);
for (AuraEffectList::const_iterator itr = expAuras.begin(); itr != expAuras.end(); ++itr)
expertise += GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE, [weapon](AuraEffect const* aurEff)
{
// item neutral spell
if ((*itr)->GetSpellInfo()->EquippedItemClass == -1)
expertise += (*itr)->GetAmount();
// item dependent spell
else if (weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellInfo()))
expertise += (*itr)->GetAmount();
}
return aurEff->GetSpellInfo()->EquippedItemClass == -1 || // item neutral spell
(weapon && weapon->IsFitToSpellRequirements(aurEff->GetSpellInfo())); // item dependent spell
});
if (expertise < 0)
expertise = 0;
@@ -1100,9 +1096,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(indexMod, uint32(attackPowerMod)); // UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS
@@ -1166,10 +1162,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()->DamageModifier; // = DamageModifier * _GetDamageMod(rank);
minDamage = ((weaponMinDamage + baseValue) * dmgMultiplier * basePct + totalValue) * totalPct;
@@ -1233,11 +1229,11 @@ bool Guardian::UpdateAllStats()
void Guardian::UpdateArmor()
{
float value = GetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE);
value *= GetModifierValue(UNIT_MOD_ARMOR, BASE_PCT);
float value = GetFlatModifierValue(UNIT_MOD_ARMOR, BASE_VALUE);
value *= GetPctModifierValue(UNIT_MOD_ARMOR, BASE_PCT);
value += std::max<float>(GetStat(STAT_AGILITY) - GetCreateStat(STAT_AGILITY), 0.0f) * 2.0f;
value += GetModifierValue(UNIT_MOD_ARMOR, TOTAL_VALUE);
value *= GetModifierValue(UNIT_MOD_ARMOR, TOTAL_PCT);
value += GetFlatModifierValue(UNIT_MOD_ARMOR, TOTAL_VALUE);
value *= GetPctModifierValue(UNIT_MOD_ARMOR, TOTAL_PCT);
SetArmor(int32(value));
}
@@ -1278,10 +1274,10 @@ void Guardian::UpdateMaxHealth()
break;
}
float value = GetModifierValue(unitMod, BASE_VALUE);// xinef: Do NOT add base health TWICE + GetCreateHealth();
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE) + stamina * multiplicator;
value *= GetModifierValue(unitMod, TOTAL_PCT);
float value = GetFlatModifierValue(unitMod, BASE_VALUE);// xinef: Do NOT add base health TWICE + GetCreateHealth();
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + stamina * multiplicator;
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetMaxHealth((uint32)value);
}
@@ -1311,11 +1307,11 @@ void Guardian::UpdateMaxPower(Powers power)
break;
}
// xinef: Do NOT add base mana TWICE
float value = GetModifierValue(unitMod, BASE_VALUE) + (power != POWER_MANA ? GetCreatePowers(power) : 0);
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE) + addValue * multiplicator;
value *= GetModifierValue(unitMod, TOTAL_PCT);
// Do NOT add base mana TWICE
float value = GetFlatModifierValue(unitMod, BASE_VALUE) + (power != POWER_MANA ? GetCreatePowers(power) : 0);
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + addValue * multiplicator;
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetMaxPower(power, uint32(value));
}
@@ -1335,12 +1331,12 @@ void Guardian::UpdateAttackPowerAndDamage(bool ranged)
else
val = 2 * GetStat(STAT_STRENGTH) - 20.0f;
SetModifierValue(unitMod, BASE_VALUE, val);
SetStatFlatModifier(unitMod, 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);
@@ -1362,10 +1358,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;
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;
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);
File diff suppressed because it is too large Load Diff
+46 -22
View File
@@ -123,13 +123,18 @@ enum HitInfo
HITINFO_FAKE_DAMAGE = 0x01000000 // enables damage animation even if no damage done, set only if no damage
};
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 = 3
};
enum UnitModifierPctType
{
BASE_PCT = 0,
TOTAL_PCT = 1,
MODIFIER_TYPE_PCT_END = 2
};
enum WeaponDamageRange
@@ -1050,16 +1055,32 @@ public:
for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i) SetFloatValue(static_cast<uint16>(UNIT_FIELD_NEGSTAT0) + i, 0);
}
bool HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, float amount, bool apply);
void SetModifierValue(UnitMods unitMod, UnitModifierType modifierType, float value) { m_auraModifiersGroup[unitMod][modifierType] = value; }
[[nodiscard]] float GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) const;
bool 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);
[[nodiscard]] float GetFlatModifierValue(UnitMods unitMod, UnitModifierFlatType modifierType) const;
[[nodiscard]] float GetPctModifierValue(UnitMods unitMod, UnitModifierPctType modifierType) const;
void UpdateUnitMod(UnitMods unitMod);
// only players have item requirements
[[nodiscard]] virtual bool CheckAttackFitToAuraRequirement(WeaponAttackType /*attackType*/, AuraEffect const* /*aurEff*/) const { return true; }
virtual void UpdateDamageDoneMods(WeaponAttackType attackType, int32 skipEnchantSlot = -1);
void UpdateAllDamageDoneMods();
void UpdateDamagePctDoneMods(WeaponAttackType attackType);
void UpdateAllDamagePctDoneMods();
[[nodiscard]] float GetTotalStatValue(Stats stat, float additionalValue = 0.0f) const;
void SetCanModifyStats(bool modifyStats) { m_canModifyStats = modifyStats; }
[[nodiscard]] bool CanModifyStats() const { return m_canModifyStats; }
void ApplyStatBuffMod(Stats stat, float val, bool apply) { ApplyModSignedFloatValue((val > 0 ? static_cast<uint16>(UNIT_FIELD_POSSTAT0) + stat : static_cast<uint16>(UNIT_FIELD_NEGSTAT0) + stat), val, apply); }
void ApplyStatPercentBuffMod(Stats stat, float val, bool apply);
void UpdateStatBuffMod(Stats stat);
// Unit level methods
[[nodiscard]] uint8 GetLevel() const { return uint8(GetUInt32Value(UNIT_FIELD_LEVEL)); }
@@ -1104,7 +1125,6 @@ public:
void SetMaxPower(Powers power, uint32 val);
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate = true);
int32 ModifyPowerPct(Powers power, float pct, bool apply = true);
void RewardRage(uint32 damage, uint32 weaponSpeedHitFactor, bool attacker);
@@ -1159,13 +1179,9 @@ public:
[[nodiscard]] uint32 GetResistance(SpellSchoolMask mask) const;
[[nodiscard]] uint32 GetResistance(SpellSchools school) const { return GetUInt32Value(static_cast<uint16>(UNIT_FIELD_RESISTANCES) + school); }
static float GetEffectiveResistChance(Unit const* owner, SpellSchoolMask schoolMask, Unit const* victim);
[[nodiscard]] float GetResistanceBuffMods(SpellSchools school, bool positive) const { return GetFloatValue(positive ? static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE) + school : static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE) + + school); }
void SetResistance(SpellSchools school, int32 val) { SetStatInt32Value(static_cast<uint16>(UNIT_FIELD_RESISTANCES) + school, val); }
void SetResistanceBuffMods(SpellSchools school, bool positive, float val) { SetFloatValue(positive ? static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE) + school : static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE) + + school, val); }
void ApplyResistanceBuffModsMod(SpellSchools school, bool positive, float val, bool apply) { ApplyModSignedFloatValue(positive ? static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE) + school : static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE) + + school, val, apply); }
void ApplyResistanceBuffModsPercentMod(SpellSchools school, bool positive, float val, bool apply) { ApplyPercentModFloatValue(positive ? static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE) + school : static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE) + + school, val, apply); }
void UpdateResistanceBuffModsMod(SpellSchools school);
//////////// Need triage ////////////////
uint16 GetMaxSkillValueForLevel(Unit const* target = nullptr) const { return (target ? getLevelForTarget(target) : GetLevel()) * 5; }
@@ -1319,6 +1335,10 @@ public:
void SetAuraStack(uint32 spellId, Unit* target, uint32 stack);
int32 GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue = false, int32 miscValue = 0) const;
bool IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications = false);
bool IsHighestExclusiveAuraEffect(SpellInfo const* spellInfo, AuraType auraType, int32 effectAmount, uint8 auraEffectMask, bool removeOtherAuraApplications = false);
// aura apply/remove helpers - you should better not use these
Aura* _TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount = nullptr, Item* castItem = nullptr, ObjectGuid casterGUID = ObjectGuid::Empty, bool periodicReset = false);
void _AddAura(UnitAura* aura, Unit* caster);
@@ -1328,7 +1348,7 @@ public:
void _UnapplyAura(AuraApplicationMap::iterator& i, AuraRemoveMode removeMode);
void _UnapplyAura(AuraApplication* aurApp, AuraRemoveMode removeMode);
void _RemoveNoStackAuraApplicationsDueToAura(Aura* aura);
void _RemoveNoStackAurasDueToAura(Aura* aura);
void _RemoveNoStackAurasDueToAura(Aura* aura, bool owned);
bool _IsNoStackAuraDueToAura(Aura* appliedAura, Aura* existingAura) const;
void _RegisterAuraEffect(AuraEffect* aurEff, bool apply);
@@ -1474,15 +1494,19 @@ public:
uint32 GetDiseasesByCaster(ObjectGuid casterGUID, uint8 mode = 0);
[[nodiscard]] uint32 GetDoTsByCaster(ObjectGuid casterGUID) const;
[[nodiscard]] int32 GetTotalAuraModifierAreaExclusive(AuraType auratype) const;
[[nodiscard]] int32 GetTotalAuraModifier(AuraType auratype) const;
[[nodiscard]] float GetTotalAuraMultiplier(AuraType auratype) const;
int32 GetMaxPositiveAuraModifier(AuraType auratype);
[[nodiscard]] int32 GetMaxPositiveAuraModifier(AuraType auratype) const;
[[nodiscard]] int32 GetMaxNegativeAuraModifier(AuraType auratype) const;
[[nodiscard]] int32 GetTotalAuraModifier(AuraType auratype, std::function<bool(AuraEffect const*)> const& predicate) const;
[[nodiscard]] float GetTotalAuraMultiplier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const;
[[nodiscard]] int32 GetMaxPositiveAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const;
[[nodiscard]] int32 GetMaxNegativeAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const;
[[nodiscard]] int32 GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const;
[[nodiscard]] float GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask) const;
int32 GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask, const AuraEffect* except = nullptr) const;
[[nodiscard]] int32 GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask, const AuraEffect* except = nullptr) const;
[[nodiscard]] int32 GetMaxNegativeAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const;
[[nodiscard]] int32 GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const;
@@ -1581,7 +1605,6 @@ public:
int32 HealBySpell(HealInfo& healInfo, bool critical = false);
int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask);
int32 SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask);
float SpellPctHealingModsDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype);
uint32 SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint8 effIndex, float TotalMod = 0.0f, uint32 stack = 1);
uint32 SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1);
@@ -2132,7 +2155,8 @@ protected:
AuraStateAurasMap m_auraStateAuras; // Used for improve performance of aura state checks on aura apply/remove
uint32 m_interruptMask;
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][MAX_WEAPON_DAMAGE_RANGE][MAX_ITEM_PROTO_DAMAGES];
bool m_canModifyStats;
VisibleAuraMap m_visibleAuras;
+2 -2
View File
@@ -256,8 +256,8 @@ void WorldSession::HandleAutoEquipItemOpcode(WorldPackets::Item::AutoEquipItem&
}
// now do moves, remove...
_player->RemoveItem(dstbag, dstslot, true, true);
_player->RemoveItem(packet.SourceBag, packet.SourceSlot, true, true);
_player->RemoveItem(dstbag, dstslot, true);
_player->RemoveItem(packet.SourceBag, packet.SourceSlot, true);
// add to dest
_player->EquipItem(dest, pSrcItem, true);
@@ -24,16 +24,6 @@ void ScriptMgr::OnCalcMaxDuration(Aura const* aura, int32& maxDuration)
CALL_ENABLED_HOOKS(AllSpellScript, ALLSPELLHOOK_ON_CALC_MAX_DURATION, script->OnCalcMaxDuration(aura, maxDuration));
}
bool ScriptMgr::CanModAuraEffectDamageDone(AuraEffect const* auraEff, Unit* target, AuraApplication const* aurApp, uint8 mode, bool apply)
{
CALL_ENABLED_BOOLEAN_HOOKS(AllSpellScript, ALLSPELLHOOK_CAN_MOD_AURA_EFFECT_DAMAGE_DONE, !script->CanModAuraEffectDamageDone(auraEff, target, aurApp, mode, apply));
}
bool ScriptMgr::CanModAuraEffectModDamagePercentDone(AuraEffect const* auraEff, Unit* target, AuraApplication const* aurApp, uint8 mode, bool apply)
{
CALL_ENABLED_BOOLEAN_HOOKS(AllSpellScript, ALLSPELLHOOK_CAN_MOD_AURA_EFFECT_MOD_DAMAGE_PERCENT_DONE, !script->CanModAuraEffectModDamagePercentDone(auraEff, target, aurApp, mode, apply));
}
void ScriptMgr::OnSpellCheckCast(Spell* spell, bool strict, SpellCastResult& res)
{
CALL_ENABLED_HOOKS(AllSpellScript, ALLSPELLHOOK_ON_SPELL_CHECK_CAST, script->OnSpellCheckCast(spell, strict, res));
@@ -24,8 +24,6 @@
enum AllSpellHook
{
ALLSPELLHOOK_ON_CALC_MAX_DURATION,
ALLSPELLHOOK_CAN_MOD_AURA_EFFECT_DAMAGE_DONE,
ALLSPELLHOOK_CAN_MOD_AURA_EFFECT_MOD_DAMAGE_PERCENT_DONE,
ALLSPELLHOOK_ON_SPELL_CHECK_CAST,
ALLSPELLHOOK_CAN_PREPARE,
ALLSPELLHOOK_CAN_SCALING_EVERYTHING,
@@ -56,10 +54,6 @@ public:
// Calculate max duration in applying aura
virtual void OnCalcMaxDuration(Aura const* /*aura*/, int32& /*maxDuration*/) { }
[[nodiscard]] virtual bool CanModAuraEffectDamageDone(AuraEffect const* /*auraEff*/, Unit* /*target*/, AuraApplication const* /*aurApp*/, uint8 /*mode*/, bool /*apply*/) { return true; }
[[nodiscard]] virtual bool CanModAuraEffectModDamagePercentDone(AuraEffect const* /*auraEff*/, Unit* /*target*/, AuraApplication const* /*aurApp*/, uint8 /*mode*/, bool /*apply*/) { return true; }
virtual void OnSpellCheckCast(Spell* /*spell*/, bool /*strict*/, SpellCastResult& /*res*/) { }
[[nodiscard]] virtual bool CanPrepare(Spell* /*spell*/, SpellCastTargets const* /*targets*/, AuraEffect const* /*triggeredByAura*/) { return true; }
@@ -84,21 +84,6 @@ bool ScriptMgr::IfNormalReaction(Unit const* unit, Unit const* target, Reputatio
CALL_ENABLED_BOOLEAN_HOOKS(UnitScript, UNITHOOK_IF_NORMAL_REACTION, !script->IfNormalReaction(unit, target, repRank));
}
bool ScriptMgr::IsNeedModSpellDamagePercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto)
{
CALL_ENABLED_BOOLEAN_HOOKS(UnitScript, UNITHOOK_IS_NEEDMOD_SPELL_DAMAGE_PERCENT, !script->IsNeedModSpellDamagePercent(unit, auraEff, doneTotalMod, spellProto));
}
bool ScriptMgr::IsNeedModMeleeDamagePercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto)
{
CALL_ENABLED_BOOLEAN_HOOKS(UnitScript, UNITHOOK_IS_NEEDMOD_MELEE_DAMAGE_PERCENT, !script->IsNeedModMeleeDamagePercent(unit, auraEff, doneTotalMod, spellProto));
}
bool ScriptMgr::IsNeedModHealPercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto)
{
CALL_ENABLED_BOOLEAN_HOOKS(UnitScript, UNITHOOK_IS_NEEDMOD_HEAL_PERCENT, !script->IsNeedModHealPercent(unit, auraEff, doneTotalMod, spellProto));
}
bool ScriptMgr::CanSetPhaseMask(Unit const* unit, uint32 newPhaseMask, bool update)
{
CALL_ENABLED_BOOLEAN_HOOKS(UnitScript, UNITHOOK_CAN_SET_PHASE_MASK, !script->CanSetPhaseMask(unit, newPhaseMask, update));
@@ -33,9 +33,6 @@ enum UnitHook
UNITHOOK_ON_AURA_APPLY,
UNITHOOK_ON_AURA_REMOVE,
UNITHOOK_IF_NORMAL_REACTION,
UNITHOOK_IS_NEEDMOD_SPELL_DAMAGE_PERCENT,
UNITHOOK_IS_NEEDMOD_MELEE_DAMAGE_PERCENT,
UNITHOOK_IS_NEEDMOD_HEAL_PERCENT,
UNITHOOK_CAN_SET_PHASE_MASK,
UNITHOOK_IS_CUSTOM_BUILD_VALUES_UPDATE,
UNITHOOK_SHOULD_TRACK_VALUES_UPDATE_POS_BY_INDEX,
@@ -89,12 +86,6 @@ public:
[[nodiscard]] virtual bool IfNormalReaction(Unit const* /*unit*/, Unit const* /*target*/, ReputationRank& /*repRank*/) { return true; }
[[nodiscard]] virtual bool IsNeedModSpellDamagePercent(Unit const* /*unit*/, AuraEffect* /*auraEff*/, float& /*doneTotalMod*/, SpellInfo const* /*spellProto*/) { return true; }
[[nodiscard]] virtual bool IsNeedModMeleeDamagePercent(Unit const* /*unit*/, AuraEffect* /*auraEff*/, float& /*doneTotalMod*/, SpellInfo const* /*spellProto*/) { return true; }
[[nodiscard]] virtual bool IsNeedModHealPercent(Unit const* /*unit*/, AuraEffect* /*auraEff*/, float& /*doneTotalMod*/, SpellInfo const* /*spellProto*/) { return true; }
[[nodiscard]] virtual bool CanSetPhaseMask(Unit const* /*unit*/, uint32 /*newPhaseMask*/, bool /*update*/) { return true; }
[[nodiscard]] virtual bool IsCustomBuildValuesUpdate(Unit const* /*unit*/, uint8 /*updateType*/, ByteBuffer& /*fieldBuffer*/, Player const* /*target*/, uint16 /*index*/) { return false; }
-5
View File
@@ -546,9 +546,6 @@ public: /* UnitScript */
void OnAuraApply(Unit* /*unit*/, Aura* /*aura*/);
void OnAuraRemove(Unit* unit, AuraApplication* aurApp, AuraRemoveMode mode);
bool IfNormalReaction(Unit const* unit, Unit const* target, ReputationRank& repRank);
bool IsNeedModSpellDamagePercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto);
bool IsNeedModMeleeDamagePercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto);
bool IsNeedModHealPercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto);
bool CanSetPhaseMask(Unit const* unit, uint32 newPhaseMask, bool update);
bool IsCustomBuildValuesUpdate(Unit const* unit, uint8 updateType, ByteBuffer& fieldBuffer, Player const* target, uint16 index);
bool ShouldTrackValuesUpdatePosByIndex(Unit const* unit, uint8 updateType, uint16 index);
@@ -606,8 +603,6 @@ public: /* Arena Team Script */
public: /* SpellSC */
void OnCalcMaxDuration(Aura const* aura, int32& maxDuration);
bool CanModAuraEffectDamageDone(AuraEffect const* auraEff, Unit* target, AuraApplication const* aurApp, uint8 mode, bool apply);
bool CanModAuraEffectModDamagePercentDone(AuraEffect const* auraEff, Unit* target, AuraApplication const* aurApp, uint8 mode, bool apply);
void OnSpellCheckCast(Spell* spell, bool strict, SpellCastResult& res);
bool CanPrepare(Spell* spell, SpellCastTargets const* targets, AuraEffect const* triggeredByAura);
bool CanScalingEverything(Spell* spell);
+187 -195
View File
@@ -212,7 +212,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS] =
&AuraEffect::HandleModStateImmunityMask, //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::GetAggroRange
&AuraEffect::HandleNoImmediateEffect, //153 SPELL_AURA_SPLIT_DAMAGE_FLAT
@@ -393,7 +393,6 @@ AuraEffect::AuraEffect(Aura* base, uint8 effIndex, int32* baseAmount, Unit* cast
m_amount = CalculateAmount(caster);
m_casterLevel = caster ? caster->GetLevel() : 0;
m_applyResilience = caster && caster->CanApplyResilience();
m_auraGroup = sSpellMgr->GetSpellGroup(GetId());
CalculateSpellMod();
@@ -3000,14 +2999,17 @@ void AuraEffect::HandleAuraModDisarm(AuraApplication const* aurApp, uint8 mode,
// Handle damage modification, shapeshifted druids are not affected
if (target->IsPlayer() && (!target->IsInFeralForm() || target->GetShapeshiftForm() == FORM_GHOSTWOLF))
{
if (Item* pItem = target->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
Player* player = target->ToPlayer();
if (Item* pItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
{
WeaponAttackType attacktype = Player::GetAttackBySlot(slot);
WeaponAttackType attackType = Player::GetAttackBySlot(slot);
if (attacktype < MAX_ATTACK)
player->ApplyItemDependentAuras(pItem, !apply);
if (attackType < MAX_ATTACK)
{
target->ToPlayer()->_ApplyWeaponDamage(slot, pItem->GetTemplate(), nullptr, !apply);
target->ToPlayer()->_ApplyWeaponDependentAuraMods(pItem, attacktype, !apply);
player->_ApplyWeaponDamage(slot, pItem->GetTemplate(), nullptr, !apply);
if (!apply) // apply case already handled on item dependent aura removal (if any)
player->UpdateWeaponDependentAuras(attackType);
}
}
}
@@ -3439,9 +3441,17 @@ void AuraEffect::HandleModThreat(AuraApplication const* aurApp, uint8 mode, bool
return;
Unit* target = aurApp->GetTarget();
for (int8 i = 0; i < MAX_SPELL_SCHOOL; ++i)
for (uint8 i = 0; i < MAX_SPELL_SCHOOL; ++i)
if (GetMiscValue() & (1 << i))
ApplyPercentModFloatVar(target->m_threatModifier[i], float(GetAmount()), apply);
{
if (apply)
AddPct(target->m_threatModifier[i], GetAmount());
else
{
float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_THREAT, 1 << i);
target->m_threatModifier[i] = amount;
}
}
}
void AuraEffect::HandleAuraModTotalThreat(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -4318,7 +4328,7 @@ 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 << x))
{
@@ -4326,9 +4336,9 @@ void AuraEffect::HandleAuraModResistanceExclusive(AuraApplication const* aurApp,
if (amount < GetAmount())
{
float value = float(GetAmount() - amount);
target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_VALUE, value, apply);
if (target->IsPlayer())
target->ApplyResistanceBuffModsMod(SpellSchools(x), aurApp->IsPositive(), value, apply);
target->HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_VALUE, value, apply);
if (target->IsPlayer() || target->IsPet())
target->UpdateResistanceBuffModsMod(SpellSchools(x));
}
}
}
@@ -4345,9 +4355,9 @@ void AuraEffect::HandleAuraModResistance(AuraApplication const* aurApp, uint8 mo
{
if (GetMiscValue() & int32(1 << x))
{
target->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->IsPlayer() || target->IsPet())
target->ApplyResistanceBuffModsMod(SpellSchools(x), GetAmount() > 0, (float)GetAmount(), apply);
target->UpdateResistanceBuffModsMod(SpellSchools(x));
}
}
}
@@ -4358,32 +4368,39 @@ void AuraEffect::HandleAuraModBaseResistancePCT(AuraApplication const* aurApp, u
return;
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 << x))
{
target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, float(GetAmount()), apply);
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();
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 << i))
{
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->IsPlayer() || target->IsPet())
{
target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), true, (float)GetAmount(), apply);
target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), false, (float)GetAmount(), apply);
}
target->UpdateResistanceBuffModsMod(SpellSchools(i));
}
}
}
@@ -4398,7 +4415,7 @@ void AuraEffect::HandleModBaseResistance(AuraApplication const* aurApp, uint8 mo
{
if (GetMiscValue() & (1 << i))
{
target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_VALUE, float(GetAmount()), apply);
target->HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_VALUE, float(GetAmount()), apply);
}
}
}
@@ -4430,23 +4447,28 @@ void AuraEffect::HandleAuraModStat(AuraApplication const* aurApp, uint8 mode, bo
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
return;
Unit* target = aurApp->GetTarget();
if (GetMiscValue() < -2 || GetMiscValue() > 4)
{
LOG_ERROR("spells.aura.effect", "WARNING: Spell {} effect {} has an unsupported misc value ({}) for SPELL_AURA_MOD_STAT ", GetId(), GetEffIndex(), GetMiscValue());
return;
}
Unit* target = aurApp->GetTarget();
int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_STAT, true, GetMiscValue());
if (std::abs(spellGroupVal) >= std::abs(GetAmount()))
return;
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)
{
//target->ApplyStatMod(Stats(i), m_amount, apply);
target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetAmount()), apply);
if (spellGroupVal)
target->HandleStatFlatModifier(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->IsPlayer() || target->IsPet())
target->ApplyStatBuffMod(Stats(i), (float)GetAmount(), apply);
target->UpdateStatBuffMod(Stats(i));
}
}
}
@@ -4470,8 +4492,16 @@ void AuraEffect::HandleModPercentStat(AuraApplication const* aurApp, uint8 mode,
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(GetAmount()));
else
{
float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_PERCENT_STAT, [i](AuraEffect const* aurEff)
{
return (aurEff->GetMiscValue() == i || aurEff->GetMiscValue() == -1);
});
target->SetStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, amount);
}
}
}
@@ -4549,7 +4579,7 @@ 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;
@@ -4565,39 +4595,22 @@ void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8
// save current health state
float healthPct = target->GetHealthPct();
bool alive = target->IsAlive();
float value = GetAmount();
if (GetId() == 67480) // xinef: hack fix for blessing of sanctuary stats stack with blessing of kings...
{
if (value) // not turned off
value = 10.0f;
for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++)
{
if (i == STAT_STRENGTH || i == STAT_STAMINA)
{
if (apply && (target->IsPlayer() || target->IsPet()))
target->ApplyStatPercentBuffMod(Stats(i), value, apply);
target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, value, apply);
if (!apply && (target->IsPlayer() || target->IsPet()))
target->ApplyStatPercentBuffMod(Stats(i), value, apply);
}
}
return;
}
for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++)
{
if (GetMiscValue() == i || GetMiscValue() == -1)
{
if (apply && (target->IsPlayer() || target->IsPet()))
target->ApplyStatPercentBuffMod(Stats(i), value, apply);
float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, [i](AuraEffect const* aurEff)
{
return (aurEff->GetMiscValue() == i || aurEff->GetMiscValue() == -1);
});
target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, value, apply);
if (target->GetPctModifierValue(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT) == amount)
continue;
if (!apply && (target->IsPlayer() || target->IsPet()))
target->ApplyStatPercentBuffMod(Stats(i), value, apply);
target->SetStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, amount);
if (target->IsPlayer() || target->IsPet())
target->UpdateStatBuffMod(Stats(i));
}
}
@@ -4693,7 +4706,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
@@ -4702,7 +4715,7 @@ void AuraEffect::HandleAuraModIncreaseHealth(AuraApplication const* aurApp, uint
target->ModifyHealth(-GetAmount());
else
target->SetHealth(1);
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
target->HandleStatFlatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
}
}
@@ -4716,7 +4729,7 @@ void AuraEffect::HandleAuraModIncreaseMaxHealth(AuraApplication const* aurApp, u
uint32 oldhealth = target->GetHealth();
double healthPercentage = (double)oldhealth / (double)target->GetMaxHealth();
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
target->HandleStatFlatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
// refresh percentage
if (oldhealth > 0)
@@ -4746,7 +4759,7 @@ void AuraEffect::HandleAuraModIncreaseEnergy(AuraApplication const* aurApp, uint
UnitMods unitMod = UnitMods(static_cast<uint16>(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
@@ -4765,17 +4778,16 @@ void AuraEffect::HandleAuraModIncreaseEnergyPercent(AuraApplication const* aurAp
// return;
UnitMods unitMod = UnitMods(static_cast<uint16>(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);
}
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);
}
}
@@ -4788,7 +4800,14 @@ 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);
}
// Xinef: pct was rounded down and could "kill" creature by setting its health to 0 making npc zombie
if (target->IsAlive())
@@ -4803,7 +4822,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);
}
}
/********************************/
@@ -4857,34 +4882,17 @@ 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;
Unit* target = aurApp->GetTarget();
Player* target = aurApp->GetTarget()->ToPlayer();
if (!target->IsPlayer())
if (!target)
return;
for (int i = 0; i < MAX_ATTACK; ++i)
if (Item* pItem = target->ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), true))
target->ToPlayer()->_ApplyWeaponDependentAuraCritMod(pItem, WeaponAttackType(i), this, apply);
// mods must be applied base at equipped weapon class and subclass comparison
// with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask
// GetMiscValue() comparison with item generated damage types
if (GetSpellInfo()->EquippedItemClass == -1)
{
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);
}
else
{
// done in Player::_ApplyWeaponDependentAuraMods
}
target->UpdateAllWeaponDependentCritAuras();
}
void AuraEffect::HandleModHitChance(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -4960,9 +4968,7 @@ void AuraEffect::HandleAuraModCritPct(AuraApplication const* aurApp, uint8 mode,
return;
}
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();
@@ -4986,6 +4992,13 @@ void AuraEffect::HandleModCastingSpeed(AuraApplication const* aurApp, uint8 mode
return;
}
int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, GetAuraType());
if (std::abs(spellGroupVal) >= std::abs(GetAmount()))
return;
if (spellGroupVal)
target->ApplyCastTimePercentMod(float(spellGroupVal), !apply);
target->ApplyCastTimePercentMod((float)GetAmount(), apply);
}
@@ -5007,6 +5020,17 @@ void AuraEffect::HandleModCombatSpeedPct(AuraApplication const* aurApp, uint8 mo
return;
Unit* target = aurApp->GetTarget();
int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MELEE_SLOW);
if (std::abs(spellGroupVal) >= std::abs(GetAmount()))
return;
if (spellGroupVal)
{
target->ApplyCastTimePercentMod(float(spellGroupVal), !apply);
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(spellGroupVal), !apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(spellGroupVal), !apply);
target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(spellGroupVal), !apply);
}
target->ApplyCastTimePercentMod(float(GetAmount()), apply);
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply);
@@ -5031,7 +5055,15 @@ void AuraEffect::HandleModMeleeSpeedPct(AuraApplication const* aurApp, uint8 mod
return;
Unit* target = aurApp->GetTarget();
int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_MELEE_HASTE);
if (std::abs(spellGroupVal) >= std::abs(GetAmount()))
return;
if (spellGroupVal)
{
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(spellGroupVal), !apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(spellGroupVal), !apply);
}
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(GetAmount()), apply);
}
@@ -5105,7 +5137,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
@@ -5118,7 +5150,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
@@ -5129,7 +5161,13 @@ void AuraEffect::HandleAuraModAttackPowerPercent(AuraApplication const* aurApp,
Unit* target = aurApp->GetTarget();
//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
@@ -5143,7 +5181,13 @@ void AuraEffect::HandleAuraModRangedAttackPowerPercent(AuraApplication const* au
return;
//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::HandleAuraModRangedAttackPowerOfStatPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
@@ -5184,85 +5228,25 @@ void AuraEffect::HandleModDamageDone(AuraApplication const* aurApp, uint8 mode,
Unit* target = aurApp->GetTarget();
// apply item specific bonuses for already equipped weapon
if (target->IsPlayer())
{
for (int i = 0; i < MAX_ATTACK; ++i)
if (Item* pItem = target->ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), true))
target->ToPlayer()->_ApplyWeaponDependentAuraDamageMod(pItem, WeaponAttackType(i), this, apply);
}
if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) != 0)
target->UpdateAllDamageDoneMods();
// GetMiscValue() is bitmask of spell schools
// 1 (0-bit) - normal school damage (SPELL_SCHOOL_MASK_NORMAL)
// 126 - full bitmask all magic damages (SPELL_SCHOOL_MASK_MAGIC) including wands
// 127 - full bitmask any damages
//
// mods must be applied base at equipped weapon class and subclass comparison
// with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask
// GetMiscValue() comparison with item generated damage types
if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) != 0 && sScriptMgr->CanModAuraEffectDamageDone(this, target, aurApp, mode, apply))
{
// apply generic physical damage bonuses including wand case
if (GetSpellInfo()->EquippedItemClass == -1 || !target->IsPlayer())
{
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);
if (target->IsPlayer())
{
if (GetAmount() > 0)
target->ApplyModInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, GetAmount(), apply);
else
target->ApplyModInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG, GetAmount(), apply);
}
}
else
{
// done in Player::_ApplyWeaponDependentAuraMods
}
}
// Skip non magic case for Speedup
if ((GetMiscValue() & SPELL_SCHOOL_MASK_MAGIC) == 0)
return;
if (GetSpellInfo()->EquippedItemClass != -1 || GetSpellInfo()->EquippedItemInventoryTypeMask != 0)
{
// wand magic case (skip generic to all item spell bonuses)
// done in Player::_ApplyWeaponDependentAuraMods
// Skip item specific requirements for not wand magic damage
return;
}
// Magic damage modifiers implemented in Unit::SpellDamageBonus
// Magic damage modifiers implemented in Unit::SpellBaseDamageBonus
// This information for client side use only
if (target->IsPlayer())
{
if (GetAmount() > 0)
{
for (uint32 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
{
if ((GetMiscValue() & (1 << i)) != 0)
target->ApplyModInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + i, GetAmount(), apply);
}
}
else
{
for (uint32 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
{
if ((GetMiscValue() & (1 << i)) != 0)
target->ApplyModInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + i, GetAmount(), apply);
}
}
uint16 baseField = GetAmount() >= 0 ? PLAYER_FIELD_MOD_DAMAGE_DONE_POS : PLAYER_FIELD_MOD_DAMAGE_DONE_NEG;
for (uint16 i = 0; i < MAX_SPELL_SCHOOL; ++i)
if (GetMiscValue() & (1 << i))
target->ApplyModUInt32Value(baseField + i, GetAmount(), apply);
if (Guardian* pet = target->ToPlayer()->GetGuardianPet())
pet->UpdateAttackPowerAndDamage();
}
}
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;
@@ -5271,39 +5255,32 @@ void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8
if (!target)
return;
if (!sScriptMgr->CanModAuraEffectModDamagePercentDone(this, target, aurApp, mode, apply))
return;
if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
target->UpdateAllDamagePctDoneMods();
if (target->IsPlayer())
{
for (int i = 0; i < MAX_ATTACK; ++i)
if (Item* item = target->ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), false))
target->ToPlayer()->_ApplyWeaponDependentAuraDamageMod(item, WeaponAttackType(i), this, apply);
}
if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) && (GetSpellInfo()->EquippedItemClass == -1 || !target->IsPlayer()))
{
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);
if (target->IsPlayer())
target->ToPlayer()->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, float (GetAmount()), apply);
}
else
{
// done in Player::_ApplyWeaponDependentAuraMods for SPELL_SCHOOL_MASK_NORMAL && EquippedItemClass != -1 and also for wand case
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);
}
}
}
}
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
@@ -5311,14 +5288,29 @@ 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;
target->HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, float(GetAmount()), apply);
}
if (target->IsPlayer())
target->ToPlayer()->HandleBaseModValue(SHIELD_BLOCK_VALUE, modType, float(GetAmount()), 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);
}
}
/********************************/
@@ -112,8 +112,6 @@ public:
float GetPctMods() const { return m_pctMods; }
void SetPctMods(float pctMods) { m_pctMods = pctMods; }
// xinef: stacking
uint32 GetAuraGroup() const { return m_auraGroup; }
int32 GetOldAmount() const { return m_oldAmount; }
void SetOldAmount(int32 amount) { m_oldAmount = amount; }
void SetEnabled(bool enabled) { m_isAuraEnabled = enabled; }
@@ -131,8 +129,6 @@ private:
float m_critChance;
float m_pctMods;
// xinef: stacking
uint32 m_auraGroup;
int32 m_oldAmount;
bool m_isAuraEnabled;
// xinef: channel information for channel triggering
@@ -299,6 +295,7 @@ public:
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;
+26 -102
View File
@@ -181,67 +181,6 @@ void AuraApplication::_HandleEffect(uint8 effIndex, bool apply)
// Remove all triggered by aura spells vs unlimited duration
aurEff->CleanupTriggeredSpells(GetTarget());
}
// Stacking!
if (uint32 groupId = aurEff->GetAuraGroup())
{
SpellGroupStackFlags sFlag = sSpellMgr->GetGroupStackFlags(groupId);
if (!aurEff->IsPeriodic() && (sFlag & SPELL_GROUP_STACK_FLAG_EFFECT_EXCLUSIVE))
{
AuraApplication* strongestApp = apply ? this : nullptr;
AuraEffect* strongestEff = apply ? aurEff : nullptr;
int32 amount = apply ? std::abs(aurEff->GetAmount()) : 0;
Unit* target = GetTarget();
Unit::AuraEffectList const& auraList = target->GetAuraEffectsByType(aurEff->GetAuraType());
for (Unit::AuraEffectList::const_iterator iter = auraList.begin(); iter != auraList.end(); ++iter)
{
if ((*iter)->GetAuraGroup() != groupId || (*iter) == strongestEff || (*iter)->GetBase()->IsRemoved())
continue;
// xinef: skip different misc values
if (aurEff->GetAuraType() != SPELL_AURA_230 /*SPELL_AURA_MOD_INCREASE_HEALTH_2*/ && aurEff->GetAuraType() != SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK &&
aurEff->GetMiscValue() != (*iter)->GetMiscValue())
continue;
// xinef: should not happen
AuraApplication* aurApp = (*iter)->GetBase()->GetApplicationOfTarget(target->GetGUID());
if (!aurApp)
continue;
if (amount < std::abs((*iter)->GetForcedAmount()))
{
// xinef: if we have strongest aura and it is active, turn it off
// xinef: otherwise just save new aura;
if (strongestApp && strongestEff && strongestApp->IsActive(strongestEff->GetEffIndex()))
{
strongestEff->HandleEffect(strongestApp, AURA_EFFECT_HANDLE_CHANGE_AMOUNT, false);
if (!strongestEff->GetSpellInfo()->HasAreaAuraEffect())
strongestEff->SetEnabled(false);
strongestApp->SetDisableMask(strongestEff->GetEffIndex());
}
strongestApp = aurApp;
strongestEff = (*iter);
amount = std::abs((*iter)->GetAmount());
}
// xinef: itered aura is weaker, deactivate if active
else if (aurApp->IsActive((*iter)->GetEffIndex()))
{
(*iter)->HandleEffect(aurApp, AURA_EFFECT_HANDLE_CHANGE_AMOUNT, false);
if (!(*iter)->GetSpellInfo()->HasAreaAuraEffect())
(*iter)->SetEnabled(false);
aurApp->SetDisableMask((*iter)->GetEffIndex());
}
}
// xinef: if we have new strongest aura, and it is not active
if (strongestApp && strongestEff && !strongestApp->IsActive(strongestEff->GetEffIndex()))
{
strongestApp->RemoveDisableMask(strongestEff->GetEffIndex());
strongestEff->SetEnabled(true);
strongestEff->HandleEffect(strongestApp, AURA_EFFECT_HANDLE_CHANGE_AMOUNT, true);
}
}
}
SetNeedClientUpdate();
}
@@ -661,6 +600,9 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
if (!itr->second || itr->first->IsImmunedToSpell(GetSpellInfo()) || !CanBeAppliedOn(itr->first))
addUnit = false;
if (addUnit && !itr->first->IsHighestExclusiveAura(this, true))
addUnit = false;
if (addUnit)
{
// persistent area aura does not hit flying targets
@@ -684,7 +626,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
for (Unit::AuraApplicationMap::iterator iter = itr->first->GetAppliedAuras().begin(); iter != itr->first->GetAppliedAuras().end(); ++iter)
{
Aura const* aura = iter->second->GetBase();
if (!CanStackWith(aura, false))
if (!CanStackWith(aura))
{
addUnit = false;
break;
@@ -1069,6 +1011,16 @@ void Aura::RefreshSpellMods()
player->RestoreAllSpellMods(0, this);
}
bool Aura::HasMoreThanOneEffectForType(AuraType auraType) const
{
uint32 count = 0;
for (SpellEffectInfo const& spellEffectInfo : GetSpellInfo()->GetEffects())
if (HasEffect(spellEffectInfo.EffectIndex) && spellEffectInfo.ApplyAuraName == auraType)
++count;
return count > 1;
}
bool Aura::IsArea() const
{
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
@@ -1589,7 +1541,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
// Alchemy: Mixology
if (caster && caster->HasAura(53042) && caster->IsPlayer() && !caster->ToPlayer()->GetSession()->PlayerLoading())
{
if (sSpellMgr->GetSpellGroup(GetId()) == 1) /*Elixirs*/
if (sSpellMgr->IsSpellMemberOfSpellGroup(GetId(), SPELL_GROUP_ELIXIR_BATTLE) || sSpellMgr->IsSpellMemberOfSpellGroup(GetId(), SPELL_GROUP_ELIXIR_GUARDIAN))
{
if (caster->HasSpell(GetSpellInfo()->Effects[EFFECT_0].TriggerSpell))
{
@@ -2018,7 +1970,7 @@ bool Aura::IsAuraStronger(Aura const* newAura) const
return false;
}
bool Aura::CanStackWith(Aura const* existingAura, bool remove) const
bool Aura::CanStackWith(Aura const* existingAura) const
{
// Can stack with self
if (this == existingAura)
@@ -2056,47 +2008,19 @@ bool Aura::CanStackWith(Aura const* existingAura, bool remove) const
return false;
// check spell group stack rules
// xinef: this assures us that both spells are in same group!
SpellGroupStackFlags stackFlags = sSpellMgr->CheckSpellGroupStackRules(m_spellInfo, existingSpellInfo, remove, IsArea());
if (stackFlags)
switch (sSpellMgr->CheckSpellGroupStackRules(m_spellInfo, existingSpellInfo))
{
// xinef: same caster rule is bounded by spellfamily
if (sameCaster && m_spellInfo->SpellFamilyName == existingSpellInfo->SpellFamilyName &&
(stackFlags & SPELL_GROUP_STACK_FLAG_NOT_SAME_CASTER))
case SPELL_GROUP_STACK_RULE_EXCLUSIVE:
case SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST: // if it reaches this point, existing aura is lower/equal
return false;
// xinef: normal exclusive stacking, remove if auras are equal by effects
if (stackFlags & SPELL_GROUP_STACK_FLAG_EXCLUSIVE)
{
if (GetSpellInfo()->IsAuraEffectEqual(existingSpellInfo) || GetSpellInfo()->IsRankOf(existingSpellInfo))
{
if (remove)
return IsAuraStronger(existingAura);
else
return existingAura->IsAuraStronger(this);
}
}
// xinef: check priority before effect mask
SpellGroupSpecialFlags thisAuraFlag = sSpellMgr->GetSpellGroupSpecialFlags(GetId());
SpellGroupSpecialFlags existingAuraFlag = sSpellMgr->GetSpellGroupSpecialFlags(existingSpellInfo->Id);
if (thisAuraFlag >= SPELL_GROUP_SPECIAL_FLAG_PRIORITY1 && thisAuraFlag <= SPELL_GROUP_SPECIAL_FLAG_PRIORITY4 &&
existingAuraFlag >= SPELL_GROUP_SPECIAL_FLAG_PRIORITY1 && existingAuraFlag <= SPELL_GROUP_SPECIAL_FLAG_PRIORITY4)
{
if (thisAuraFlag < existingAuraFlag)
{
case SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER:
if (sameCaster)
return false;
}
}
// xinef: forced strongest aura in group by flag
if (stackFlags & SPELL_GROUP_STACK_FLAG_FORCED_STRONGEST)
return !remove;
if (stackFlags & SPELL_GROUP_STACK_FLAG_FORCED_WEAKEST)
return remove;
// xinef: forced return, handle all cases using available flags!
return !(stackFlags & SPELL_GROUP_STACK_FLAG_NEVER_STACK);
break;
case SPELL_GROUP_STACK_RULE_DEFAULT:
case SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT:
default:
break;
}
if (m_spellInfo->SpellFamilyName != existingSpellInfo->SpellFamilyName)
+2 -1
View File
@@ -153,6 +153,7 @@ public:
uint8 GetCasterLevel() const { return m_casterLevel; }
bool HasMoreThanOneEffectForType(AuraType auraType) const;
bool IsArea() const;
bool IsPassive() const;
bool IsDeathPersistent() const;
@@ -188,7 +189,7 @@ public:
void HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, bool apply, bool onReapply);
bool CanBeAppliedOn(Unit* target);
bool CheckAreaTarget(Unit* target);
bool CanStackWith(Aura const* checkAura, bool remove) const;
bool CanStackWith(Aura const* existingAura) const;
bool IsAuraStronger(Aura const* newAura) const;
// Proc system
+43 -29
View File
@@ -19,7 +19,6 @@
#include "ArenaSpectator.h"
#include "BattlefieldMgr.h"
#include "Battleground.h"
#include "BattlegroundIC.h"
#include "CharmInfo.h"
#include "CellImpl.h"
#include "Common.h"
@@ -33,7 +32,6 @@
#include "InstanceScript.h"
#include "Log.h"
#include "LootMgr.h"
#include "MapMgr.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Opcodes.h"
@@ -41,6 +39,7 @@
#include "Player.h"
#include "ScriptMgr.h"
#include "SharedDefines.h"
#include "SpellAuraDefines.h"
#include "SpellAuraEffects.h"
#include "SpellInfo.h"
#include "SpellMgr.h"
@@ -1240,11 +1239,7 @@ void Spell::SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTarge
// Other special target selection goes here
if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
{
Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS);
for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j)
if ((*j)->IsAffectedOnSpell(m_spellInfo))
maxTargets += (*j)->GetAmount();
maxTargets += m_caster->GetTotalAuraModifierByAffectMask(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS, m_spellInfo);
Acore::Containers::RandomResize(targets, maxTargets);
}
@@ -1327,11 +1322,7 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge
// Other special target selection goes here
if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
{
Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS);
for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j)
if ((*j)->IsAffectedOnSpell(m_spellInfo))
maxTargets += (*j)->GetAmount();
maxTargets += m_caster->GetTotalAuraModifierByAffectMask(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS, m_spellInfo);
Acore::Containers::RandomResize(targets, maxTargets);
}
@@ -6076,6 +6067,8 @@ SpellCastResult Spell::CheckCast(bool strict)
}
}
uint8 approximateAuraEffectMask = 0;
uint8 nonAuraEffectMask = 0;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
// for effects of spells that have only one target
@@ -6561,6 +6554,11 @@ SpellCastResult Spell::CheckCast(bool strict)
default:
break;
}
if (m_spellInfo->Effects[i].IsAura())
approximateAuraEffectMask |= 1 << i;
else if (m_spellInfo->Effects[i].IsEffect())
nonAuraEffectMask |= 1 << i;
}
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
@@ -6723,6 +6721,13 @@ SpellCastResult Spell::CheckCast(bool strict)
default:
break;
}
// check if target already has the same type, but more powerful aura
if (!nonAuraEffectMask && (approximateAuraEffectMask & (1 << i)) && !m_spellInfo->IsTargetingArea())
if (Unit* target = m_targets.GetUnitTarget())
if (!target->IsHighestExclusiveAuraEffect(m_spellInfo, AuraType(m_spellInfo->Effects[i].ApplyAuraName),
m_spellInfo->Effects[i].CalcValue(m_caster, &m_spellValue->EffectBasePoints[i]), approximateAuraEffectMask, false))
return SPELL_FAILED_AURA_BOUNCED;
}
// check trade slot case (last, for allow catch any another cast problems)
@@ -6973,26 +6978,35 @@ bool Spell::CanAutoCast(Unit* target)
{
ObjectGuid targetguid = target->GetGUID();
for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j)
for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
{
if (m_spellInfo->Effects[j].Effect == SPELL_EFFECT_APPLY_AURA)
if (!spellEffectInfo.IsAura())
continue;
AuraType const& auraType = spellEffectInfo.ApplyAuraName;
Unit::AuraEffectList const& auras = target->GetAuraEffectsByType(auraType);
for (Unit::AuraEffectList::const_iterator auraIt = auras.begin(); auraIt != auras.end(); ++auraIt)
{
if (m_spellInfo->StackAmount <= 1)
{
if (target->HasAuraEffect(m_spellInfo->Id, j))
return false;
}
else
{
if (AuraEffect* aureff = target->GetAuraEffect(m_spellInfo->Id, j))
if (aureff->GetBase()->GetStackAmount() >= m_spellInfo->StackAmount)
return false;
}
}
else if (m_spellInfo->Effects[j].IsAreaAuraEffect())
{
if (target->HasAuraEffect(m_spellInfo->Id, j))
if (GetSpellInfo()->Id == (*auraIt)->GetSpellInfo()->Id)
return false;
switch (sSpellMgr->CheckSpellGroupStackRules(GetSpellInfo(), (*auraIt)->GetSpellInfo()))
{
case SPELL_GROUP_STACK_RULE_EXCLUSIVE:
return false;
case SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER:
if (GetCaster() == (*auraIt)->GetCaster())
return false;
break;
case SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT: // this one has further checks, but i don't think they're necessary for autocast logic
case SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST:
if (abs(spellEffectInfo.BasePoints) <= abs((*auraIt)->GetAmount()))
return false;
break;
case SPELL_GROUP_STACK_RULE_DEFAULT:
default:
break;
}
}
}
+7 -10
View File
@@ -1952,13 +1952,10 @@ void Spell::EffectEnergize(SpellEffIndex effIndex)
Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras();
for (Unit::AuraApplicationMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
{
SpellGroupSpecialFlags sFlag = sSpellMgr->GetSpellGroupSpecialFlags(itr->second->GetBase()->GetId());
if (!guardianFound)
if (sFlag & SPELL_GROUP_SPECIAL_FLAG_ELIXIR_GUARDIAN)
guardianFound = true;
if (!battleFound)
if (sFlag & SPELL_GROUP_SPECIAL_FLAG_ELIXIR_BATTLE)
battleFound = true;
if (!guardianFound && sSpellMgr->IsSpellMemberOfSpellGroup(itr->second->GetBase()->GetId(), SPELL_GROUP_ELIXIR_GUARDIAN))
guardianFound = true;
if (!battleFound && sSpellMgr->IsSpellMemberOfSpellGroup(itr->second->GetBase()->GetId(), SPELL_GROUP_ELIXIR_BATTLE))
battleFound = true;
if (battleFound && guardianFound)
break;
}
@@ -1966,9 +1963,9 @@ void Spell::EffectEnergize(SpellEffIndex effIndex)
// get all available elixirs by mask and spell level
std::set<uint32> availableElixirs;
if (!guardianFound)
sSpellMgr->GetSetOfSpellsInSpellGroupWithFlag(1, SPELL_GROUP_SPECIAL_FLAG_ELIXIR_GUARDIAN, availableElixirs);
sSpellMgr->GetSetOfSpellsInSpellGroup(SPELL_GROUP_ELIXIR_GUARDIAN, availableElixirs);
if (!battleFound)
sSpellMgr->GetSetOfSpellsInSpellGroupWithFlag(1, SPELL_GROUP_SPECIAL_FLAG_ELIXIR_BATTLE, availableElixirs);
sSpellMgr->GetSetOfSpellsInSpellGroup(SPELL_GROUP_ELIXIR_BATTLE, availableElixirs);
for (std::set<uint32>::iterator itr = availableElixirs.begin(); itr != availableElixirs.end();)
{
SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(*itr);
@@ -3598,7 +3595,7 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex)
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);
fixed_bonus = int32(fixed_bonus * weapon_total_pct);
spell_bonus = int32(spell_bonus * weapon_total_pct);
}
+8 -171
View File
@@ -326,9 +326,9 @@ std::array<SpellImplicitTargetInfo::StaticData, TOTAL_SPELL_TARGETS> SpellImplic
SpellEffectInfo::SpellEffectInfo(SpellEntry const* spellEntry, SpellInfo const* spellInfo, uint8 effIndex)
{
_spellInfo = spellInfo;
_effIndex = effIndex;
EffectIndex = effIndex;
Effect = spellEntry->Effect[effIndex];
ApplyAuraName = spellEntry->EffectApplyAuraName[effIndex];
ApplyAuraName = AuraType(spellEntry->EffectApplyAuraName[effIndex]);
Amplitude = spellEntry->EffectAmplitude[effIndex];
DieSides = spellEntry->EffectDieSides[effIndex];
RealPointsPerLevel = spellEntry->EffectRealPointsPerLevel[effIndex];
@@ -456,7 +456,7 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const
value += PointsPerComboPoint * comboPoints;
}
value = caster->ApplyEffectModifiers(_spellInfo, _effIndex, value);
value = caster->ApplyEffectModifiers(_spellInfo, EffectIndex, value);
// amount multiplication based on caster's level
if (!caster->IsControlledByPlayer() &&
@@ -501,7 +501,7 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const
break;
}
if ((sSpellMgr->GetSpellInfo(_spellInfo->Effects[_effIndex].TriggerSpell) && sSpellMgr->GetSpellInfo(_spellInfo->Effects[_effIndex].TriggerSpell)->HasAttribute(SPELL_ATTR0_SCALES_WITH_CREATURE_LEVEL)) && _spellInfo->HasAttribute(SPELL_ATTR0_SCALES_WITH_CREATURE_LEVEL))
if ((sSpellMgr->GetSpellInfo(_spellInfo->Effects[EffectIndex].TriggerSpell) && sSpellMgr->GetSpellInfo(_spellInfo->Effects[EffectIndex].TriggerSpell)->HasAttribute(SPELL_ATTR0_SCALES_WITH_CREATURE_LEVEL)) && _spellInfo->HasAttribute(SPELL_ATTR0_SCALES_WITH_CREATURE_LEVEL))
canEffectScale = false;
if (canEffectScale)
@@ -1579,122 +1579,6 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a
return SPELL_CAST_OK;
}
bool SpellInfo::IsStrongerAuraActive(Unit const* caster, Unit const* target) const
{
if (!target)
return false;
// xinef: check spell group
uint32 groupId = sSpellMgr->GetSpellGroup(Id);
if (!groupId)
return false;
SpellGroupSpecialFlags sFlag = sSpellMgr->GetSpellGroupSpecialFlags(Id);
if (sFlag & SPELL_GROUP_SPECIAL_FLAG_SKIP_STRONGER_CHECK)
return false;
for (uint8 i = EFFECT_0; i < MAX_SPELL_EFFECTS; ++i)
{
// xinef: Skip Empty effects
if (!Effects[i].IsEffect())
continue;
// xinef: if non-aura effect is preset - return false
if (!Effects[i].IsAura())
return false;
// xinef: aura is periodic - return false
if (Effects[i].Amplitude)
return false;
// xinef: exclude dummy auras
if (Effects[i].ApplyAuraName == SPELL_AURA_DUMMY)
return false;
}
for (uint8 i = EFFECT_0; i < MAX_SPELL_EFFECTS; ++i)
{
// xinef: skip non-aura efects
if (!Effects[i].IsAura())
return false;
Unit::AuraEffectList const& auraList = target->GetAuraEffectsByType((AuraType)Effects[i].ApplyAuraName);
for (Unit::AuraEffectList::const_iterator iter = auraList.begin(); iter != auraList.end(); ++iter)
{
// xinef: aura is not groupped or in different group
uint32 auraGroup = (*iter)->GetAuraGroup();
if (!auraGroup || auraGroup != groupId)
continue;
if (IsRankOf((*iter)->GetSpellInfo()) && (sFlag & SPELL_GROUP_SPECIAL_FLAG_SKIP_STRONGER_SAME_SPELL))
{
continue;
}
// xinef: check priority before effect mask
if (sFlag >= SPELL_GROUP_SPECIAL_FLAG_PRIORITY1 && sFlag <= SPELL_GROUP_SPECIAL_FLAG_PRIORITY4)
{
SpellGroupSpecialFlags sFlagCurr = sSpellMgr->GetSpellGroupSpecialFlags((*iter)->GetId());
if (sFlagCurr >= SPELL_GROUP_SPECIAL_FLAG_PRIORITY1 && sFlagCurr <= SPELL_GROUP_SPECIAL_FLAG_PRIORITY4 && sFlagCurr < sFlag)
{
return true;
}
}
// xinef: check aura effect equal auras only, some auras have different effects on different ranks - check rank also
if (!IsAuraEffectEqual((*iter)->GetSpellInfo()) && !IsRankOf((*iter)->GetSpellInfo()))
continue;
// xinef: misc value mismatches
// xinef: commented, checked above
//if (Effects[i].MiscValue != (*iter)->GetMiscValue())
// continue;
// xinef: should not happen, or effect is not active - stronger one is present
AuraApplication* aurApp = (*iter)->GetBase()->GetApplicationOfTarget(target->GetGUID());
if (!aurApp || !aurApp->IsActive((*iter)->GetEffIndex()))
continue;
// xinef: assume that all spells are either positive or negative, otherwise they should not be in one group
// xinef: take custom values into account
int32 basePoints = Effects[i].BasePoints;
int32 duration = GetMaxDuration();
// xinef: should have the same id, can be different if spell is triggered
// xinef: have to fix spell mods for triggered spell, turn off current spellmodtakingspell for preparing and restore after
if (Player const* player = caster->GetSpellModOwner())
if (player->m_spellModTakingSpell && player->m_spellModTakingSpell->m_spellInfo->Id == Id)
basePoints = player->m_spellModTakingSpell->GetSpellValue()->EffectBasePoints[i];
int32 curValue = std::abs(Effects[i].CalcValue(caster, &basePoints));
int32 auraValue = (sFlag & SPELL_GROUP_SPECIAL_FLAG_BASE_AMOUNT_CHECK) ?
std::abs((*iter)->GetSpellInfo()->Effects[(*iter)->GetEffIndex()].CalcValue((*iter)->GetCaster())) :
std::abs((*iter)->GetAmount());
// xinef: for same spells, divide amount by stack amount
if (Id == (*iter)->GetId())
auraValue /= (*iter)->GetBase()->GetStackAmount();
if (curValue < auraValue)
return true;
// xinef: little hack, if current spell is the same as aura spell, asume it is not stronger
// xinef: if values are the same, duration mods should be taken into account but they are almost always passive
if (curValue == auraValue)
{
if (Id == (*iter)->GetId())
continue;
if (!(*iter)->GetBase()->IsPassive() && duration < (*iter)->GetBase()->GetDuration())
return true;
}
}
}
return false;
}
bool SpellInfo::IsAuraEffectEqual(SpellInfo const* otherSpellInfo) const
{
uint8 matchCount = 0;
@@ -1938,10 +1822,6 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
if (HasEffect(SPELL_EFFECT_SELF_RESURRECT) || HasEffect(SPELL_EFFECT_RESURRECT) || HasEffect(SPELL_EFFECT_RESURRECT_NEW))
return SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED;
// xinef: check if stronger aura is active
if (IsStrongerAuraActive(caster, unitTarget))
return SPELL_FAILED_AURA_BOUNCED;
return SPELL_CAST_OK;
}
@@ -2316,6 +2196,8 @@ SpellSpecificType SpellInfo::LoadSpellSpecific() const
case SPELL_AURA_TRACK_RESOURCES:
case SPELL_AURA_TRACK_STEALTHED:
return SPELL_SPECIFIC_TRACKER;
default:
break;
}
}
}
@@ -2399,6 +2281,8 @@ uint32 SpellInfo::GetMaxTicks() const
if (Effects[x].Amplitude != 0)
return DotDuration / Effects[x].Amplitude;
break;
default:
break;
}
}
@@ -2889,50 +2773,3 @@ void SpellInfo::_UnloadImplicitTargetConditionLists()
delete cur;
}
}
bool SpellInfo::CheckElixirStacking(Unit const* caster) const
{
if (!caster)
{
return true;
}
// xinef: check spell group
uint32 groupId = sSpellMgr->GetSpellGroup(Id);
if (groupId != SPELL_GROUP_GUARDIAN_AND_BATTLE_ELIXIRS)
{
return true;
}
SpellGroupSpecialFlags sFlag = sSpellMgr->GetSpellGroupSpecialFlags(Id);
for (uint8 i = EFFECT_0; i < MAX_SPELL_EFFECTS; ++i)
{
if (!Effects[i].IsAura())
{
continue;
}
Unit::AuraApplicationMap const& Auras = caster->GetAppliedAuras();
for (Unit::AuraApplicationMap::const_iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
{
// xinef: aura is not groupped or in different group
uint32 auraGroup = sSpellMgr->GetSpellGroup(itr->first);
if (auraGroup != groupId)
{
continue;
}
// Cannot apply guardian/battle elixir if flask is present
if (sFlag == SPELL_GROUP_SPECIAL_FLAG_ELIXIR_BATTLE || sFlag == SPELL_GROUP_SPECIAL_FLAG_ELIXIR_GUARDIAN)
{
SpellGroupSpecialFlags sAuraFlag = sSpellMgr->GetSpellGroupSpecialFlags(itr->first);
if ((sAuraFlag & SPELL_GROUP_SPECIAL_FLAG_FLASK) == SPELL_GROUP_SPECIAL_FLAG_FLASK)
{
return false;
}
}
}
}
return true;
}
+3 -7
View File
@@ -248,10 +248,10 @@ private:
class SpellEffectInfo
{
SpellInfo const* _spellInfo;
uint8 _effIndex;
public:
uint8 EffectIndex;
uint32 Effect;
uint32 ApplyAuraName;
AuraType ApplyAuraName;
uint32 Amplitude;
int32 DieSides;
float RealPointsPerLevel;
@@ -272,7 +272,7 @@ public:
flag96 SpellClassMask;
std::list<Condition*>* ImplicitTargetConditions;
SpellEffectInfo() : _spellInfo(nullptr), _effIndex(0), Effect(0), ApplyAuraName(0), Amplitude(0), DieSides(0),
SpellEffectInfo() : _spellInfo(nullptr), EffectIndex(0), Effect(0), ApplyAuraName(SPELL_AURA_NONE), Amplitude(0), DieSides(0),
RealPointsPerLevel(0), BasePoints(0), PointsPerComboPoint(0), ValueMultiplier(0), DamageMultiplier(0),
BonusMultiplier(0), MiscValue(0), MiscValueB(0), Mechanic(MECHANIC_NONE), RadiusEntry(nullptr), ChainTarget(0),
ItemType(0), TriggerSpell(0), ImplicitTargetConditions(nullptr) {}
@@ -482,8 +482,6 @@ public:
SpellCastResult CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget = nullptr) const;
bool CheckTargetCreatureType(Unit const* target) const;
// xinef: aura stacking
bool IsStrongerAuraActive(Unit const* caster, Unit const* target) const;
bool IsAuraEffectEqual(SpellInfo const* otherSpellInfo) const;
bool ValidateAttribute6SpellDamageMods(Unit const* caster, const AuraEffect* auraEffect, bool isDot) const;
@@ -539,8 +537,6 @@ public:
// unloading helpers
void _UnloadImplicitTargetConditionLists();
bool CheckElixirStacking(Unit const* caster) const;
private:
std::array<SpellEffectInfo, MAX_SPELL_EFFECTS>& _GetEffects() { return Effects; }
SpellEffectInfo& _GetEffect(SpellEffIndex index) { ASSERT(index < Effects.size()); return Effects[index]; }
@@ -570,14 +570,6 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_CASTER_PROCS;
});
// Blessing of sanctuary stats
ApplySpellFix({ 67480 }, [](SpellInfo* spellInfo)
{
spellInfo->Effects[EFFECT_0].MiscValue = -1;
spellInfo->SpellFamilyName = SPELLFAMILY_UNK1; // allows stacking
spellInfo->Effects[EFFECT_1].ApplyAuraName = SPELL_AURA_DUMMY; // just a marker
});
ApplySpellFix({
6940, // Hand of Sacrifice
64205 // Divine Sacrifice
+310 -123
View File
@@ -18,12 +18,9 @@
#include "SpellMgr.h"
#include "BattlefieldMgr.h"
#include "BattlegroundIC.h"
#include "BattlegroundMgr.h"
#include "Chat.h"
#include "DBCStores.h"
#include "GameGraveyard.h"
#include "InstanceScript.h"
#include "MapMgr.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "ScriptMgr.h"
@@ -648,82 +645,143 @@ SpellTargetPosition const* SpellMgr::GetSpellTargetPosition(uint32 spell_id, Spe
return nullptr;
}
SpellGroupStackFlags SpellMgr::GetGroupStackFlags(uint32 groupid) const
SpellSpellGroupMapBounds SpellMgr::GetSpellSpellGroupMapBounds(uint32 spell_id) const
{
SpellGroupStackMap::const_iterator itr = mSpellGroupStackMap.find(groupid);
if (itr != mSpellGroupStackMap.end())
spell_id = GetFirstSpellInChain(spell_id);
return mSpellSpellGroup.equal_range(spell_id);
}
bool SpellMgr::IsSpellMemberOfSpellGroup(uint32 spell_id, SpellGroup group_id) const
{
SpellSpellGroupMapBounds spellGroup = GetSpellSpellGroupMapBounds(spell_id);
for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second; ++itr)
{
if (itr->second == group_id)
return true;
}
return false;
}
SpellGroupSpellMapBounds SpellMgr::GetSpellGroupSpellMapBounds(SpellGroup group_id) const
{
return mSpellGroupSpell.equal_range(group_id);
}
void SpellMgr::GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells) const
{
std::set<SpellGroup> usedGroups;
GetSetOfSpellsInSpellGroup(group_id, foundSpells, usedGroups);
}
void SpellMgr::GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells, std::set<SpellGroup>& usedGroups) const
{
if (usedGroups.find(group_id) != usedGroups.end())
return;
usedGroups.insert(group_id);
SpellGroupSpellMapBounds groupSpell = GetSpellGroupSpellMapBounds(group_id);
for (SpellGroupSpellMap::const_iterator itr = groupSpell.first; itr != groupSpell.second; ++itr)
{
if (itr->second < 0)
{
SpellGroup currGroup = (SpellGroup)abs(itr->second);
GetSetOfSpellsInSpellGroup(currGroup, foundSpells, usedGroups);
}
else
{
foundSpells.insert(itr->second);
}
}
}
bool SpellMgr::AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, uint32 auraType, int32 amount, std::map<SpellGroup, int32>& groups) const
{
uint32 spellId = spellInfo->GetFirstRankSpell()->Id;
auto spellGroupBounds = GetSpellSpellGroupMapBounds(spellId);
// Find group with SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT if it belongs to one
for (auto itr = spellGroupBounds.first; itr != spellGroupBounds.second; ++itr)
{
SpellGroup group = itr->second;
auto found = mSpellSameEffectStack.find(group);
if (found != mSpellSameEffectStack.end())
{
// check auraTypes
if (!found->second.count(auraType))
continue;
// Put the highest amount in the map
auto groupItr = groups.find(group);
if (groupItr == groups.end())
groups.emplace(group, amount);
else
{
int32 curr_amount = groups[group];
// Take absolute value because this also counts for the highest negative aura
if (std::abs(curr_amount) < std::abs(amount))
groupItr->second = amount;
}
// return because a spell should be in only one SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group per auraType
return true;
}
}
// Not in a SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group, so return false
return false;
}
SpellGroupStackRule SpellMgr::CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2) const
{
ASSERT(spellInfo1);
ASSERT(spellInfo2);
uint32 spell_id1 = spellInfo1->GetFirstRankSpell()->Id;
uint32 spell_id2 = spellInfo2->GetFirstRankSpell()->Id;
// find SpellGroups which are common for both spells
SpellSpellGroupMapBounds spellGroup1 = GetSpellSpellGroupMapBounds(spell_id1);
std::set<SpellGroup> groups;
for (SpellSpellGroupMap::const_iterator itr = spellGroup1.first; itr != spellGroup1.second; ++itr)
{
if (IsSpellMemberOfSpellGroup(spell_id2, itr->second))
{
bool add = true;
SpellGroupSpellMapBounds groupSpell = GetSpellGroupSpellMapBounds(itr->second);
for (SpellGroupSpellMap::const_iterator itr2 = groupSpell.first; itr2 != groupSpell.second; ++itr2)
{
if (itr2->second < 0)
{
SpellGroup currGroup = (SpellGroup)abs(itr2->second);
if (IsSpellMemberOfSpellGroup(spell_id1, currGroup) && IsSpellMemberOfSpellGroup(spell_id2, currGroup))
{
add = false;
break;
}
}
}
if (add)
groups.insert(itr->second);
}
}
SpellGroupStackRule rule = SPELL_GROUP_STACK_RULE_DEFAULT;
for (std::set<SpellGroup>::iterator itr = groups.begin(); itr!= groups.end(); ++itr)
{
SpellGroupStackMap::const_iterator found = mSpellGroupStack.find(*itr);
if (found != mSpellGroupStack.end())
rule = found->second;
if (rule)
break;
}
return rule;
}
SpellGroupStackRule SpellMgr::GetSpellGroupStackRule(SpellGroup group) const
{
SpellGroupStackMap::const_iterator itr = mSpellGroupStack.find(group);
if (itr != mSpellGroupStack.end())
return itr->second;
return SPELL_GROUP_STACK_FLAG_NONE;
}
uint32 SpellMgr::GetSpellGroup(uint32 spell_id) const
{
uint32 first_rank = GetFirstSpellInChain(spell_id);
SpellGroupMap::const_iterator itr = mSpellGroupMap.find(first_rank);
if (itr != mSpellGroupMap.end())
return itr->second.groupId;
return 0;
}
SpellGroupSpecialFlags SpellMgr::GetSpellGroupSpecialFlags(uint32 spell_id) const
{
uint32 first_rank = GetFirstSpellInChain(spell_id);
SpellGroupMap::const_iterator itr = mSpellGroupMap.find(first_rank);
if (itr != mSpellGroupMap.end())
return itr->second.specialFlags;
return SPELL_GROUP_SPECIAL_FLAG_NONE;
}
SpellGroupStackFlags SpellMgr::CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2, bool remove, bool areaAura) const
{
uint32 spellid_1 = spellInfo1->GetFirstRankSpell()->Id;
uint32 spellid_2 = spellInfo2->GetFirstRankSpell()->Id;
uint32 groupId = GetSpellGroup(spellid_1);
SpellGroupSpecialFlags flag1 = GetSpellGroupSpecialFlags(spellid_1);
// xinef: dunno why i added this
if (spellid_1 == spellid_2 && remove && !areaAura)
{
if (flag1 & SPELL_GROUP_SPECIAL_FLAG_SAME_SPELL_CHECK)
{
return SPELL_GROUP_STACK_FLAG_EXCLUSIVE;
}
return SPELL_GROUP_STACK_FLAG_NONE;
}
if (groupId > 0 && groupId == GetSpellGroup(spellid_2))
{
SpellGroupSpecialFlags flag2 = GetSpellGroupSpecialFlags(spellid_2);
SpellGroupStackFlags additionFlag = SPELL_GROUP_STACK_FLAG_NONE;
// xinef: first flags are used for elixir stacking rules
if (flag1 & SPELL_GROUP_SPECIAL_FLAG_STACK_EXCLUSIVE_MAX && flag2 & SPELL_GROUP_SPECIAL_FLAG_STACK_EXCLUSIVE_MAX)
{
if (flag1 & flag2)
return SPELL_GROUP_STACK_FLAG_NEVER_STACK;
}
// xinef: check only flag1 (new spell)
else if (flag1 & SPELL_GROUP_SPECIAL_FLAG_FORCED_STRONGEST)
additionFlag = SPELL_GROUP_STACK_FLAG_FORCED_STRONGEST;
else if (flag2 & SPELL_GROUP_SPECIAL_FLAG_FORCED_STRONGEST)
additionFlag = SPELL_GROUP_STACK_FLAG_FORCED_WEAKEST;
return SpellGroupStackFlags(GetGroupStackFlags(groupId) | additionFlag);
}
return SPELL_GROUP_STACK_FLAG_NONE;
}
void SpellMgr::GetSetOfSpellsInSpellGroupWithFlag(uint32 group_id, SpellGroupSpecialFlags flag, std::set<uint32>& availableElixirs) const
{
for (SpellGroupMap::const_iterator itr = mSpellGroupMap.begin(); itr != mSpellGroupMap.end(); ++itr)
if (itr->second.groupId == group_id && itr->second.specialFlags == flag)
availableElixirs.insert(itr->first); // insert spell id
return SPELL_GROUP_STACK_RULE_DEFAULT;
}
SpellProcEventEntry const* SpellMgr::GetSpellProcEvent(uint32 spellId) const
@@ -1627,10 +1685,11 @@ void SpellMgr::LoadSpellGroups()
{
uint32 oldMSTime = getMSTime();
mSpellGroupMap.clear(); // need for reload case
mSpellSpellGroup.clear(); // need for reload case
mSpellGroupSpell.clear();
// 0 1 2
QueryResult result = WorldDatabase.Query("SELECT id, spell_id, special_flag FROM spell_group");
// 0 1
QueryResult result = WorldDatabase.Query("SELECT id, spell_id FROM spell_group");
if (!result)
{
LOG_WARN("server.loading", ">> Loaded 0 spell group definitions. DB table `spell_group` is empty.");
@@ -1638,48 +1697,68 @@ void SpellMgr::LoadSpellGroups()
return;
}
std::set<uint32> groups;
uint32 count = 0;
do
{
Field* fields = result->Fetch();
uint32 group_id = fields[0].Get<uint32>();
int32 spell_id = fields[1].Get<uint32>();
SpellGroupSpecialFlags specialFlag = (SpellGroupSpecialFlags)fields[2].Get<uint32>();
SpellInfo const* spellInfo = GetSpellInfo(spell_id);
if (!spellInfo)
if (group_id <= SPELL_GROUP_DB_RANGE_MIN && group_id >= SPELL_GROUP_CORE_RANGE_MAX)
{
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` does not exist", spell_id);
continue;
}
else if (spellInfo->GetRank() > 1)
{
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` is not first rank of spell", spell_id);
LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group` is in core range, but is not defined in core!", group_id);
continue;
}
int32 spell_id = fields[1].Get<int32>();
if (mSpellGroupMap.find(spell_id) != mSpellGroupMap.end())
{
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` has more than one group", spell_id);
continue;
}
groups.insert(group_id);
mSpellGroupSpell.emplace(SpellGroup(group_id), spell_id);
if (specialFlag >= SPELL_GROUP_SPECIAL_FLAG_MAX)
{
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` has invalid special flag!", spell_id);
continue;
}
SpellStackInfo ssi;
ssi.groupId = group_id;
ssi.specialFlags = specialFlag;
mSpellGroupMap[spell_id] = ssi;
++count;
} while (result->NextRow());
LOG_INFO("server.loading", ">> Loaded {} Spell Group Definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
for (auto itr = mSpellGroupSpell.begin(); itr!= mSpellGroupSpell.end();)
{
if (itr->second < 0)
{
if (groups.find(abs(itr->second)) == groups.end())
{
LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group` does not exist", abs(itr->second));
itr = mSpellGroupSpell.erase(itr);
}
else
++itr;
}
else
{
SpellInfo const* spellInfo = GetSpellInfo(itr->second);
if (!spellInfo)
{
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` does not exist", itr->second);
itr = mSpellGroupSpell.erase(itr);
}
else if (spellInfo->GetRank() > 1)
{
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` is not first rank of spell.", itr->second);
itr = mSpellGroupSpell.erase(itr);
}
else
++itr;
}
}
for (auto groupItr = groups.begin(); groupItr != groups.end(); ++groupItr)
{
std::set<uint32> spells;
GetSetOfSpellsInSpellGroup(SpellGroup(*groupItr), spells);
for (auto spellItr = spells.begin(); spellItr != spells.end(); ++spellItr)
{
++count;
mSpellSpellGroup.emplace(*spellItr, SpellGroup(*groupItr));
}
}
LOG_INFO("server.loading", ">> Loaded {} spell group Definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
}
@@ -1687,7 +1766,10 @@ void SpellMgr::LoadSpellGroupStackRules()
{
uint32 oldMSTime = getMSTime();
mSpellGroupStackMap.clear(); // need for reload case
mSpellGroupStack.clear(); // need for reload case
mSpellSameEffectStack.clear();
std::vector<uint32> sameEffectGroups;
// 0 1
QueryResult result = WorldDatabase.Query("SELECT group_id, stack_rule FROM spell_group_stack_rules");
@@ -1705,32 +1787,132 @@ void SpellMgr::LoadSpellGroupStackRules()
uint32 group_id = fields[0].Get<uint32>();
uint8 stack_rule = fields[1].Get<int8>();
if (stack_rule >= SPELL_GROUP_STACK_FLAG_MAX)
if (stack_rule >= SPELL_GROUP_STACK_RULE_MAX)
{
LOG_ERROR("sql.sql", "SpellGroupStackRule {} listed in `spell_group_stack_rules` does not exist", stack_rule);
LOG_ERROR("sql.sql", "SpellGroupStackRule {} listed in `spell_group_stack_rules` does not exist.", stack_rule);
continue;
}
bool present = false;
for (SpellGroupMap::const_iterator itr = mSpellGroupMap.begin(); itr != mSpellGroupMap.end(); ++itr)
if (itr->second.groupId == group_id)
{
present = true;
break;
}
if (!present)
auto bounds = GetSpellGroupSpellMapBounds((SpellGroup)group_id);
if (bounds.first == bounds.second)
{
LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group_stack_rules` does not exist", group_id);
LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group_stack_rules` does not exist.", group_id);
continue;
}
mSpellGroupStackMap[group_id] = (SpellGroupStackFlags)stack_rule;
mSpellGroupStack.emplace(SpellGroup(group_id), SpellGroupStackRule(stack_rule));
// different container for same effect stack rules, need to check effect types
if (stack_rule == SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT)
sameEffectGroups.push_back(group_id);
++count;
} while (result->NextRow());
LOG_INFO("server.loading", ">> Loaded {} Spell Group Stack Rules in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", ">> Loaded {} spell group stack rules in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
count = 0;
oldMSTime = getMSTime();
for (uint32 group_id : sameEffectGroups)
{
std::set<uint32> spellIds;
GetSetOfSpellsInSpellGroup(SpellGroup(group_id), spellIds);
std::unordered_set<uint32> auraTypes;
// we have to 'guess' what effect this group corresponds to
{
std::unordered_multiset<uint32 /*auraName*/> frequencyContainer;
// only waylay for the moment (shared group)
std::vector<std::vector<uint32 /*auraName*/>> const SubGroups =
{
{ SPELL_AURA_MOD_MELEE_HASTE, SPELL_AURA_MOD_MELEE_RANGED_HASTE, SPELL_AURA_MOD_RANGED_HASTE }
};
for (uint32 spellId : spellIds)
{
SpellInfo const* spellInfo = AssertSpellInfo(spellId);
for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
{
if (!spellEffectInfo.IsAura())
continue;
uint32 auraName = spellEffectInfo.ApplyAuraName;
for (std::vector<uint32> const& subGroup : SubGroups)
{
if (std::find(subGroup.begin(), subGroup.end(), auraName) != subGroup.end())
{
// count as first aura
auraName = subGroup.front();
break;
}
}
frequencyContainer.insert(auraName);
}
}
uint32 auraType = 0;
size_t auraTypeCount = 0;
for (uint32 auraName : frequencyContainer)
{
size_t currentCount = frequencyContainer.count(auraName);
if (currentCount > auraTypeCount)
{
auraType = auraName;
auraTypeCount = currentCount;
}
}
for (std::vector<uint32> const& subGroup : SubGroups)
{
if (auraType == subGroup.front())
{
auraTypes.insert(subGroup.begin(), subGroup.end());
break;
}
}
if (auraTypes.empty())
auraTypes.insert(auraType);
}
// re-check spells against guessed group
for (uint32 spellId : spellIds)
{
SpellInfo const* spellInfo = AssertSpellInfo(spellId);
bool found = false;
while (spellInfo)
{
for (uint32 auraType : auraTypes)
{
if (spellInfo->HasAura(AuraType(auraType)))
{
found = true;
break;
}
}
if (found)
break;
spellInfo = spellInfo->GetNextRankSpell();
}
// not found either, log error
if (!found)
LOG_ERROR("sql.sql", "SpellId {} listed in `spell_group` with stack rule 3 does not share aura assigned for group {}", spellId, group_id);
}
mSpellSameEffectStack[SpellGroup(group_id)] = auraTypes;
++count;
}
LOG_INFO("server.loading", ">> Loaded {} SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT stack rules in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
}
@@ -2920,6 +3102,8 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
case SPELL_AURA_WATER_BREATHING:
spellInfo->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT;
break;
default:
break;
}
switch (spellInfo->Effects[j].ApplyAuraName)
@@ -3494,6 +3678,9 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
if (triggerSpell->AttributesCu & SPELL_ATTR0_CU_BINARY_SPELL)
allNonBinary = false;
}
break;
default:
break;
}
}
}
+51 -51
View File
@@ -20,7 +20,6 @@
// For static or at-server-startup loaded spell data
#include "Common.h"
#include "Log.h"
#include "SharedDefines.h"
#include "Unit.h"
@@ -330,56 +329,49 @@ struct SpellBonusEntry
typedef std::unordered_map<uint32, SpellBonusEntry> SpellBonusMap;
enum SpellGroupSpecialFlags
enum SpellGroup
{
SPELL_GROUP_SPECIAL_FLAG_NONE = 0x000,
SPELL_GROUP_SPECIAL_FLAG_ELIXIR_BATTLE = 0x001,
SPELL_GROUP_SPECIAL_FLAG_ELIXIR_GUARDIAN = 0x002,
SPELL_GROUP_SPECIAL_FLAG_ELIXIR_UNSTABLE = 0x004,
SPELL_GROUP_SPECIAL_FLAG_ELIXIR_SHATTRATH = 0x008,
SPELL_GROUP_SPECIAL_FLAG_STACK_EXCLUSIVE_MAX = 0x00F,
SPELL_GROUP_SPECIAL_FLAG_FORCED_STRONGEST = 0x010, // xinef: specially helpful flag if some spells have different auras, but only one should be present
SPELL_GROUP_SPECIAL_FLAG_SKIP_STRONGER_CHECK = 0x020,
SPELL_GROUP_SPECIAL_FLAG_BASE_AMOUNT_CHECK = 0x040,
SPELL_GROUP_SPECIAL_FLAG_PRIORITY1 = 0x100,
SPELL_GROUP_SPECIAL_FLAG_PRIORITY2 = 0x200,
SPELL_GROUP_SPECIAL_FLAG_PRIORITY3 = 0x400,
SPELL_GROUP_SPECIAL_FLAG_PRIORITY4 = 0x800,
SPELL_GROUP_SPECIAL_FLAG_SAME_SPELL_CHECK = 0x1000,
SPELL_GROUP_SPECIAL_FLAG_SKIP_STRONGER_SAME_SPELL = 0x2000,
SPELL_GROUP_SPECIAL_FLAG_MAX = 0x4000,
SPELL_GROUP_SPECIAL_FLAG_FLASK = SPELL_GROUP_SPECIAL_FLAG_ELIXIR_BATTLE | SPELL_GROUP_SPECIAL_FLAG_ELIXIR_GUARDIAN
SPELL_GROUP_NONE = 0,
SPELL_GROUP_ELIXIR_BATTLE = 1,
SPELL_GROUP_ELIXIR_GUARDIAN = 2,
SPELL_GROUP_CORE_RANGE_MAX = 3
};
enum SpellGroupStackFlags
namespace std
{
SPELL_GROUP_STACK_FLAG_NONE = 0x00,
SPELL_GROUP_STACK_FLAG_EXCLUSIVE = 0x01,
SPELL_GROUP_STACK_FLAG_NOT_SAME_CASTER = 0x02,
SPELL_GROUP_STACK_FLAG_FLAGGED = 0x04, // xinef: just a marker
SPELL_GROUP_STACK_FLAG_NEVER_STACK = 0x08,
SPELL_GROUP_STACK_FLAG_EFFECT_EXCLUSIVE = 0x10,
SPELL_GROUP_STACK_FLAG_MAX = 0x20,
template<>
struct hash<SpellGroup>
{
size_t operator()(SpellGroup const& group) const
{
return hash<uint32>()(uint32(group));
}
};
}
// Internal use
SPELL_GROUP_STACK_FLAG_FORCED_STRONGEST = 0x100,
SPELL_GROUP_STACK_FLAG_FORCED_WEAKEST = 0x200,
#define SPELL_GROUP_DB_RANGE_MIN 1000
// spell_id, group_id
typedef std::unordered_multimap<uint32, SpellGroup> SpellSpellGroupMap;
typedef std::pair<SpellSpellGroupMap::const_iterator, SpellSpellGroupMap::const_iterator> SpellSpellGroupMapBounds;
// group_id, spell_id
typedef std::unordered_multimap<SpellGroup, int32> SpellGroupSpellMap;
typedef std::pair<SpellGroupSpellMap::const_iterator, SpellGroupSpellMap::const_iterator> SpellGroupSpellMapBounds;
enum SpellGroupStackRule
{
SPELL_GROUP_STACK_RULE_DEFAULT,
SPELL_GROUP_STACK_RULE_EXCLUSIVE,
SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER,
SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT,
SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST,
SPELL_GROUP_STACK_RULE_MAX
};
enum SpellGroupIDs
{
SPELL_GROUP_GUARDIAN_AND_BATTLE_ELIXIRS = 1
};
typedef std::unordered_map<SpellGroup, SpellGroupStackRule> SpellGroupStackMap;
struct SpellStackInfo
{
uint32 groupId;
SpellGroupSpecialFlags specialFlags;
};
// spell_id, group_id
typedef std::map<uint32, SpellStackInfo> SpellGroupMap;
typedef std::map<uint32, SpellGroupStackFlags> SpellGroupStackMap;
typedef std::unordered_map<SpellGroup, std::unordered_set<uint32 /*auraName*/>> SameEffectStackMap;
struct SpellThreatEntry
{
@@ -679,12 +671,18 @@ public:
// Spell target coordinates
[[nodiscard]] SpellTargetPosition const* GetSpellTargetPosition(uint32 spell_id, SpellEffIndex effIndex) const;
// Spell Groups
[[nodiscard]] uint32 GetSpellGroup(uint32 spellid) const;
[[nodiscard]] SpellGroupSpecialFlags GetSpellGroupSpecialFlags(uint32 spell_id) const;
[[nodiscard]] SpellGroupStackFlags GetGroupStackFlags(uint32 groupid) const;
SpellGroupStackFlags CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2, bool remove, bool areaAura) const;
void GetSetOfSpellsInSpellGroupWithFlag(uint32 group_id, SpellGroupSpecialFlags flag, std::set<uint32>& availableElixirs) const;
// Spell Groups table
SpellSpellGroupMapBounds GetSpellSpellGroupMapBounds(uint32 spell_id) const;
bool IsSpellMemberOfSpellGroup(uint32 spell_id, SpellGroup group_id) const;
SpellGroupSpellMapBounds GetSpellGroupSpellMapBounds(SpellGroup group_id) const;
void GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells) const;
void GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells, std::set<SpellGroup>& usedGroups) const;
// Spell Group Stack Rules table
bool AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, uint32 auraType, int32 amount, std::map<SpellGroup, int32>& groups) const;
SpellGroupStackRule CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2) const;
SpellGroupStackRule GetSpellGroupStackRule(SpellGroup group_id) const;
// Spell proc event table
[[nodiscard]] SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const;
@@ -798,8 +796,10 @@ private:
SpellRequiredMap mSpellReq;
SpellLearnSkillMap mSpellLearnSkills;
SpellTargetPositionMap mSpellTargetPositions;
SpellGroupMap mSpellGroupMap;
SpellGroupStackMap mSpellGroupStackMap;
SpellSpellGroupMap mSpellSpellGroup;
SpellGroupSpellMap mSpellGroupSpell;
SpellGroupStackMap mSpellGroupStack;
SameEffectStackMap mSpellSameEffectStack;
SpellProcEventMap mSpellProcEventMap;
SpellProcMap mSpellProcMap;
SpellBonusMap mSpellBonusMap;
@@ -78,6 +78,10 @@ Position const PosMoveOnSpawn[1] =
{ -11561.9f, -1627.868f, 41.29941f, 0.0f }
};
// hack
float const DamageIncrease = 35.0f;
float const DamageDecrease = 100.f / (1.f + DamageIncrease / 100.f) - 100.f;
class boss_arlokk : public CreatureScript
{
public:
@@ -90,7 +94,7 @@ public:
void Reset() override
{
if (events.IsInPhase(PHASE_TWO))
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageDecrease); // hack
_Reset();
_summonCountA = 0;
_summonCountB = 0;
@@ -253,7 +257,7 @@ public:
events.ScheduleEvent(EVENT_RAVAGE, 10s, 14s, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_TRANSFORM_BACK, 30s, 40s, 0, PHASE_TWO);
events.SetPhase(PHASE_TWO);
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, true); // hack
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageIncrease); // hack
break;
case EVENT_RAVAGE:
DoCastVictim(SPELL_RAVAGE, true);
@@ -265,7 +269,7 @@ public:
DoCast(me, SPELL_VANISH_VISUAL);
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_DAGGER));
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(WEAPON_DAGGER));
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageDecrease); // hack
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 4s, 7s, 0, PHASE_ONE);
events.ScheduleEvent(EVENT_GOUGE, 12s, 15s, 0, PHASE_ONE);
events.ScheduleEvent(EVENT_TRANSFORM, 30s, 0, PHASE_ONE);
@@ -73,6 +73,10 @@ enum Misc
GO_SPIDER_EGGS = 179985,
};
// hack
float const DamageIncrease = 35.0f;
float const DamageDecrease = 100.f / (1.f + DamageIncrease / 100.f) - 100.f;
// High Priestess Mar'li (14510)
struct boss_marli : public BossAI
{
@@ -84,7 +88,7 @@ public:
if (_phase == PHASE_SPIDER)
{
me->RemoveAura(SPELL_SPIDER_FORM);
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false);
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageDecrease);
_phase = PHASE_TROLL;
}
@@ -143,7 +147,7 @@ private:
me->RemoveAura(SPELL_SPIDER_FORM);
DoCastSelf(SPELL_TRANSFORM_BACK, true);
Talk(SAY_TRANSFORM_BACK);
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false);
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageDecrease);
scheduler.CancelGroup(PHASE_SPIDER);
}
@@ -186,7 +190,7 @@ private:
Talk(SAY_TRANSFORM);
DoCastSelf(SPELL_SPIDER_FORM, true);
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, true);
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageIncrease);
scheduler.Schedule(5s, PHASE_SPIDER, [this](TaskContext context)
{
@@ -2037,7 +2037,7 @@ public:
npc_toc_enh_shamanAI(Creature* pCreature) : boss_faction_championsAI(pCreature, AI_MELEE)
{
SetEquipmentSlots(false, 51803, 48013, EQUIP_NO_CHANGE);
me->SetModifierValue(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, 1.0f);
me->SetStatPctModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, 1.0f);
me->UpdateDamagePhysical(OFF_ATTACK);
events.Reset();
@@ -109,7 +109,7 @@ struct boss_twin_valkyrAI : public ScriptedAI
{
pInstance = pCreature->GetInstanceScript();
me->SetReactState(REACT_PASSIVE);
me->SetModifierValue(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, 1.0f);
me->SetStatPctModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, 1.0f);
me->UpdateDamagePhysical(OFF_ATTACK);
LastSynchroHP = (int32)me->GetMaxHealth();
SpecialMask = 0;
@@ -271,12 +271,12 @@ class spell_astromancer_solarian_transform : public AuraScript
void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetUnitOwner()->HandleStatModifier(UnitMods(UNIT_MOD_ARMOR), TOTAL_PCT, 400.0f, true);
GetUnitOwner()->ApplyStatPctModifier(UNIT_MOD_ARMOR, TOTAL_PCT, 400.0f);
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetUnitOwner()->HandleStatModifier(UnitMods(UNIT_MOD_ARMOR), TOTAL_PCT, 400.0f, false);
GetUnitOwner()->ApplyStatPctModifier(UnitMods(UNIT_MOD_ARMOR), TOTAL_PCT, -80.0f);
}
void Register() override
+1 -1
View File
@@ -99,7 +99,7 @@ struct npc_pet_hunter_snake_trap : public ScriptedAI
uint32 health = uint32(107 * (me->GetLevel() - 40) * 0.025f);
me->SetCreateHealth(health);
me->SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)health);
me->SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, (float)health);
me->SetMaxHealth(health);
//Add delta to make them not all hit the same time
+11 -11
View File
@@ -174,8 +174,8 @@ class spell_dk_raise_ally : public SpellScript
if (pInfo) // exist in DB
{
ghoul->SetCreateHealth(pInfo->health);
ghoul->SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, pInfo->health);
ghoul->SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor));
ghoul->SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, pInfo->health);
ghoul->SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor));
for (uint8 stat = 0; stat < MAX_STATS; ++stat)
ghoul->SetCreateStat(Stats(stat), float(pInfo->stats[stat]));
}
@@ -194,9 +194,9 @@ class spell_dk_raise_ally : public SpellScript
// DK Ghoul haste refresh
float val = (GetCaster()->m_modAttackSpeedPct[BASE_ATTACK] - 1.0f) * 100.0f;
val *= 2000.0f + 2000.0f * ((100.0f + val) / 100.0f);
ghoul->m_modAttackSpeedPct[BASE_ATTACK] = GetCaster()->m_modAttackSpeedPct[BASE_ATTACK];
ghoul->SetFloatValue(UNIT_FIELD_BASEATTACKTIME, 2000.0f);
ghoul->ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME, val, true); // we want to reduce attack time
ghoul->SetFloatValue(UNIT_FIELD_BASEATTACKTIME, val);
// Strength + Stamina
for (uint8 i = STAT_STRENGTH; i <= STAT_STAMINA; ++i)
@@ -223,20 +223,20 @@ class spell_dk_raise_ally : public SpellScript
value = float(GetCaster()->GetStat(stat)) * mod;
value = ghoul->GetTotalStatValue(stat, value);
ghoul->SetStat(stat, int32(value));
ghoul->ApplyStatBuffMod(stat, value, true);
ghoul->UpdateStatBuffMod(stat);
}
// Attack Power
ghoul->SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, 589 + ghoul->GetStat(STAT_STRENGTH) + ghoul->GetStat(STAT_AGILITY));
ghoul->SetInt32Value(UNIT_FIELD_ATTACK_POWER, (int32)ghoul->GetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE) * ghoul->GetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_PCT));
ghoul->SetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (int32)ghoul->GetModifierValue(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE));
ghoul->SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, ghoul->GetModifierValue(UNIT_MOD_ATTACK_POWER, TOTAL_PCT) - 1.0f);
ghoul->SetStatFlatModifier(UNIT_MOD_ATTACK_POWER, BASE_VALUE, 589 + ghoul->GetStat(STAT_STRENGTH) + ghoul->GetStat(STAT_AGILITY));
ghoul->SetInt32Value(UNIT_FIELD_ATTACK_POWER, (int32)ghoul->GetFlatModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE) * ghoul->GetPctModifierValue(UNIT_MOD_ATTACK_POWER, BASE_PCT));
ghoul->SetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (int32)ghoul->GetFlatModifierValue(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE));
ghoul->SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, ghoul->GetPctModifierValue(UNIT_MOD_ATTACK_POWER, TOTAL_PCT) - 1.0f);
// Health
ghoul->SetModifierValue(UNIT_MOD_HEALTH, TOTAL_VALUE, (ghoul->GetStat(STAT_STAMINA) - ghoul->GetCreateStat(STAT_STAMINA)) * 10.0f);
ghoul->SetStatFlatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, (ghoul->GetStat(STAT_STAMINA) - ghoul->GetCreateStat(STAT_STAMINA)) * 10.0f);
// Power Energy
ghoul->SetModifierValue(UnitMods(UNIT_MOD_POWER_START + static_cast<uint8>(POWER_ENERGY)), BASE_VALUE, ghoul->GetCreatePowers(POWER_ENERGY));
ghoul->SetStatFlatModifier(UnitMods(UNIT_MOD_POWER_START + static_cast<uint8>(POWER_ENERGY)), BASE_VALUE, ghoul->GetCreatePowers(POWER_ENERGY));
ghoul->UpdateAllStats();
ghoul->SetFullHealth();
+1 -5
View File
@@ -473,11 +473,7 @@ class spell_pal_blessing_of_sanctuary : public AuraScript
{
Unit* target = GetTarget();
if (Unit* caster = GetCaster())
{
// xinef: hack
int32 value = 9;
caster->CastCustomSpell(target, SPELL_PALADIN_BLESSING_OF_SANCTUARY_BUFF, &value, &value, 0, true);
}
caster->CastSpell(target, SPELL_PALADIN_BLESSING_OF_SANCTUARY_BUFF, true);
}
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+39 -78
View File
@@ -18,6 +18,7 @@
#include "AreaDefines.h"
#include "CreatureScript.h"
#include "Pet.h"
#include "PetDefines.h"
#include "Player.h"
#include "SpellAuraEffects.h"
#include "SpellInfo.h"
@@ -25,6 +26,8 @@
#include "SpellScript.h"
#include "SpellScriptLoader.h"
#include "TemporarySummon.h"
#include "Unit.h"
#include "Util.h"
/*
* Scripts for spells with SPELLFAMILY_WARLOCK and SPELLFAMILY_GENERIC spells used by warlock players.
* Ordered alphabetically using scriptname.
@@ -73,6 +76,7 @@ enum WarlockSpells
SPELL_WARLOCK_EYE_OF_KILROGG_FLY = 58083,
SPELL_WARLOCK_PET_VOID_STAR_TALISMAN = 37386, // Void Star Talisman
SPELL_WARLOCK_DEMONIC_PACT_PROC = 48090,
SPELL_WARLOCK_GLYPH_OF_VOIDWALKER = 56247,
};
enum WarlockSpellIcons
@@ -292,7 +296,7 @@ class spell_warl_generic_scaling : public AuraScript
void CalculateResistanceAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/)
{
// xinef: pet inherits 40% of resistance from owner and 35% of armor
// pet inherits 40% of resistance from owner and 35% of armor
if (Unit* owner = GetUnitOwner()->GetOwner())
{
SpellSchoolMask schoolMask = SpellSchoolMask(aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].MiscValue);
@@ -308,7 +312,7 @@ class spell_warl_generic_scaling : public AuraScript
void CalculateStatAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/)
{
// xinef: by default warlock pet inherits 75% of stamina and 30% of intellect
// by default warlock pet inherits 75% of stamina and 30% of intellect
if (Unit* owner = GetUnitOwner()->GetOwner())
{
Stats stat = Stats(aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].MiscValue);
@@ -317,21 +321,33 @@ class spell_warl_generic_scaling : public AuraScript
}
}
void CalculateAPAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
void CalculateAPAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/)
{
// xinef: by default warlock pet inherits 57% of max(SP FIRE, SP SHADOW) as AP
if (Unit* owner = GetUnitOwner()->GetOwner())
if (Unit* pet = GetUnitOwner())
{
int32 fire = owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE);
int32 shadow = owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_SHADOW);
int32 maximum = (fire > shadow) ? fire : shadow;
amount = CalculatePct(std::max<int32>(0, maximum), 57);
// by default warlock pet inherits 57% of max(SP FIRE, SP SHADOW) as AP
if (Unit* owner = pet->GetOwner())
{
int32 fire = owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE);
int32 shadow = owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_SHADOW);
int32 maximum = (fire > shadow) ? fire : shadow;
amount = CalculatePct(std::max<int32>(0, maximum), 57);
// Glyph of felguard, 99% sure this is a HACK
if (pet->GetEntry() == NPC_FELGUARD)
{
if (AuraEffect* glyph = owner->GetAuraEffect(SPELL_GLYPH_OF_FELGUARD, EFFECT_0))
{
amount += CalculatePct(pet->GetTotalAuraModValue(UNIT_MOD_ATTACK_POWER) - aurEff->GetAmount() + amount, glyph->GetAmount());
}
}
}
}
}
void CalculateSPAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
{
// xinef: by default warlock pet inherits 15% of max(SP FIRE, SP SHADOW) as SP
// by default warlock pet inherits 15% of max(SP FIRE, SP SHADOW) as SP
if (Unit* owner = GetUnitOwner()->GetOwner())
{
int32 fire = owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE);
@@ -339,7 +355,7 @@ class spell_warl_generic_scaling : public AuraScript
int32 maximum = (fire > shadow) ? fire : shadow;
amount = CalculatePct(std::max<int32>(0, maximum), 15);
// xinef: Update appropriate player field
// Update appropriate player field
if (owner->IsPlayer())
owner->SetUInt32Value(PLAYER_PET_SPELL_POWER, (uint32)amount);
}
@@ -1370,81 +1386,27 @@ class spell_warl_shadowburn : public AuraScript
}
};
class spell_warl_glyph_of_felguard : public AuraScript
class spell_warl_voidwalker_pet_passive : public AuraScript
{
PrepareAuraScript(spell_warl_glyph_of_felguard);
PrepareAuraScript(spell_warl_voidwalker_pet_passive);
void HandleApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (Player* player = GetCaster()->ToPlayer())
{
if (Pet* pet = player->GetPet())
{
if (pet->GetEntry() == NPC_FELGUARD)
{
pet->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, aurEff->GetAmount(), true);
}
}
}
return ValidateSpellInfo({ SPELL_WARLOCK_GLYPH_OF_VOIDWALKER });
}
void HandleRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
void CalculateAmount(AuraEffect const* /* aurEff */, int32& amount, bool& /*canBeRecalculated*/)
{
if (Player* player = GetCaster()->ToPlayer())
{
if (Pet* pet = player->GetPet())
{
if (pet->GetEntry() == NPC_FELGUARD)
{
pet->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, aurEff->GetAmount(), false);
}
}
}
if (Unit* pet = GetUnitOwner())
if (pet->IsPet())
if (Unit* owner = pet->ToPet()->GetOwner())
if (AuraEffect* aurEff = owner->GetAuraEffect(SPELL_WARLOCK_GLYPH_OF_VOIDWALKER, EFFECT_0))
amount += aurEff->GetAmount();
}
void Register() override
{
OnEffectApply += AuraEffectApplyFn(spell_warl_glyph_of_felguard::HandleApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
OnEffectRemove += AuraEffectRemoveFn(spell_warl_glyph_of_felguard::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
class spell_warl_glyph_of_voidwalker : public AuraScript
{
PrepareAuraScript(spell_warl_glyph_of_voidwalker);
void HandleApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
{
if (Player* player = GetCaster()->ToPlayer())
{
if (Pet* pet = player->GetPet())
{
if (pet->GetEntry() == NPC_VOIDWALKER)
{
pet->HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_PCT, aurEff->GetAmount(), true);
}
}
}
}
void HandleRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
{
if (Player* player = GetCaster()->ToPlayer())
{
if (Pet* pet = player->GetPet())
{
if (pet->GetEntry() == NPC_VOIDWALKER)
{
pet->HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_PCT, aurEff->GetAmount(), false);
}
}
}
}
void Register() override
{
OnEffectApply += AuraEffectApplyFn(spell_warl_glyph_of_voidwalker::HandleApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
OnEffectRemove += AuraEffectRemoveFn(spell_warl_glyph_of_voidwalker::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_warl_voidwalker_pet_passive::CalculateAmount, EFFECT_0, SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE);
}
};
@@ -1529,7 +1491,6 @@ void AddSC_warlock_spell_scripts()
RegisterSpellScript(spell_warl_unstable_affliction);
RegisterSpellScript(spell_warl_drain_soul);
RegisterSpellScript(spell_warl_shadowburn);
RegisterSpellScript(spell_warl_glyph_of_felguard);
RegisterSpellScript(spell_warl_glyph_of_voidwalker);
RegisterSpellScript(spell_warl_voidwalker_pet_passive);
RegisterSpellScript(spell_warl_demonic_pact_aura);
}
+3 -6
View File
@@ -1208,8 +1208,7 @@ struct ItemRandomPropertiesEntry
{
uint32 ID; // 0
//char const* InternalName; // 1
std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> Enchantment; // 2-4
//std::array<uint32, 2> UnusedEnchantment; // 5-6
std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> Enchantment; // 2-6
std::array<char const*, 16> Name; // 7-22
//uint32 Name_lang_mask; // 23
};
@@ -1220,10 +1219,8 @@ struct ItemRandomSuffixEntry
std::array<char const*, 16> Name; // 1-16
//uint32 Name_lang_mask; // 17
//char const* InternalName; // 18
std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> Enchantment; // 19-21
//std::array<uint32, 2> UnusedEnchantment; // 22-23
std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> AllocationPct; // 24-26
//std::array<uint32, 2> UnusedAllocationPct; // 27-28
std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> Enchantment; // 19-23
std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> AllocationPct; // 24-28
};
#define MAX_ITEM_SET_ITEMS 10