mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-03-04 16:27:48 +00:00
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:
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user