summaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server')
-rw-r--r--src/server/apps/worldserver/Main.cpp4
-rw-r--r--src/server/apps/worldserver/worldserver.conf.dist14
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.cpp20
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.h1
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp32
-rw-r--r--src/server/game/Entities/Object/Object.cpp7
-rw-r--r--src/server/game/Entities/Object/Object.h1
-rw-r--r--src/server/game/Entities/Pet/Pet.cpp32
-rw-r--r--src/server/game/Entities/Player/KillRewarder.cpp5
-rw-r--r--src/server/game/Entities/Player/Player.cpp379
-rw-r--r--src/server/game/Entities/Player/Player.h29
-rw-r--r--src/server/game/Entities/Player/PlayerQuest.cpp4
-rw-r--r--src/server/game/Entities/Player/PlayerStorage.cpp86
-rw-r--r--src/server/game/Entities/Player/PlayerUpdates.cpp2
-rw-r--r--src/server/game/Entities/Unit/StatSystem.cpp134
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp1030
-rw-r--r--src/server/game/Entities/Unit/Unit.h70
-rw-r--r--src/server/game/Handlers/ItemHandler.cpp4
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp2
-rw-r--r--src/server/game/Scripting/ScriptDefines/AllSpellScript.cpp10
-rw-r--r--src/server/game/Scripting/ScriptDefines/AllSpellScript.h6
-rw-r--r--src/server/game/Scripting/ScriptDefines/UnitScript.cpp15
-rw-r--r--src/server/game/Scripting/ScriptDefines/UnitScript.h9
-rw-r--r--src/server/game/Scripting/ScriptMgr.h5
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp405
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.h5
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp128
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.h3
-rw-r--r--src/server/game/Spells/Spell.cpp75
-rw-r--r--src/server/game/Spells/SpellEffects.cpp17
-rw-r--r--src/server/game/Spells/SpellInfo.cpp179
-rw-r--r--src/server/game/Spells/SpellInfo.h10
-rw-r--r--src/server/game/Spells/SpellInfoCorrections.cpp24
-rw-r--r--src/server/game/Spells/SpellMgr.cpp379
-rw-r--r--src/server/game/Spells/SpellMgr.h102
-rw-r--r--src/server/scripts/EasternKingdoms/ZulGurub/boss_arlokk.cpp10
-rw-r--r--src/server/scripts/EasternKingdoms/ZulGurub/boss_marli.cpp10
-rw-r--r--src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_jedoga_shadowseeker.cpp24
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp2
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp2
-rw-r--r--src/server/scripts/Northrend/Gundrak/boss_eck.cpp17
-rw-r--r--src/server/scripts/Northrend/Ulduar/HallsOfStone/brann_bronzebeard.cpp2
-rw-r--r--src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp64
-rw-r--r--src/server/scripts/Northrend/zone_crystalsong_forest.cpp135
-rw-r--r--src/server/scripts/Northrend/zone_dalaran.cpp6
-rw-r--r--src/server/scripts/Northrend/zone_howling_fjord.cpp237
-rw-r--r--src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp4
-rw-r--r--src/server/scripts/Pet/pet_hunter.cpp2
-rw-r--r--src/server/scripts/Spells/spell_dk.cpp22
-rw-r--r--src/server/scripts/Spells/spell_druid.cpp11
-rw-r--r--src/server/scripts/Spells/spell_generic.cpp28
-rw-r--r--src/server/scripts/Spells/spell_paladin.cpp25
-rw-r--r--src/server/scripts/Spells/spell_quest.cpp23
-rw-r--r--src/server/scripts/Spells/spell_warlock.cpp117
-rw-r--r--src/server/scripts/World/npcs_special.cpp4
-rw-r--r--src/server/shared/DataStores/DBCStructure.h9
-rw-r--r--src/server/shared/Network/AsyncAcceptor.h52
-rw-r--r--src/server/shared/Network/SocketMgr.h4
58 files changed, 2142 insertions, 1896 deletions
diff --git a/src/server/apps/worldserver/Main.cpp b/src/server/apps/worldserver/Main.cpp
index d1c10131b1..511c17e367 100644
--- a/src/server/apps/worldserver/Main.cpp
+++ b/src/server/apps/worldserver/Main.cpp
@@ -48,6 +48,7 @@
#include "SecretMgr.h"
#include "SharedDefines.h"
#include "SteadyTimer.h"
+#include "Systemd.h"
#include "World.h"
#include "WorldSessionMgr.h"
#include "WorldSocket.h"
@@ -406,7 +407,8 @@ int main(int argc, char** argv)
sScriptMgr->OnShutdown();
// set server offline
- LoginDatabase.DirectExecute("UPDATE realmlist SET flag = flag | {} WHERE id = '{}'", REALM_FLAG_OFFLINE, realm.Id.Realm);
+ if (!sConfigMgr->GetOption<bool>("Network.UseSocketActivation", false))
+ LoginDatabase.DirectExecute("UPDATE realmlist SET flag = flag | {} WHERE id = '{}'", REALM_FLAG_OFFLINE, realm.Id.Realm);
LOG_INFO("server.worldserver", "Halting process...");
diff --git a/src/server/apps/worldserver/worldserver.conf.dist b/src/server/apps/worldserver/worldserver.conf.dist
index 07945f07f3..089c1911a5 100644
--- a/src/server/apps/worldserver/worldserver.conf.dist
+++ b/src/server/apps/worldserver/worldserver.conf.dist
@@ -398,6 +398,20 @@ Network.TcpNodelay = 1
Network.EnableProxyProtocol = 0
#
+# Network.UseSocketActivation
+# Description: Enable systemd socket activation support for the worldserver.
+# When enabled and the process is started by systemd socket activation,
+# the server will use the socket passed by systemd instead of
+# creating and binding its own listening socket. Disabled by default.
+#
+# When enabled the realm is not automatically set as offline on shutdown.
+#
+# Example: 1 - (Enabled)
+# Default: 0 - (Disabled)
+
+Network.UseSocketActivation = 0
+
+#
###################################################################################################
###################################################################################################
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
index 762dc6e12e..522b17e41e 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
@@ -15,12 +15,13 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "ScriptedCreature.h"
#include "Cell.h"
#include "CellImpl.h"
+#include "Containers.h"
#include "GameTime.h"
#include "GridNotifiers.h"
#include "ObjectMgr.h"
+#include "ScriptedCreature.h"
#include "Spell.h"
#include "TemporarySummon.h"
@@ -141,6 +142,23 @@ Creature* SummonList::GetCreatureWithEntry(uint32 entry) const
return nullptr;
}
+Creature* SummonList::GetRandomCreatureWithEntry(uint32 entry) const
+{
+ std::vector<ObjectGuid> candidates;
+ candidates.reserve(storage_.size());
+
+ for (auto const guid : storage_)
+ if (Creature* summon = ObjectAccessor::GetCreature(*me, guid))
+ if (summon->GetEntry() == entry)
+ candidates.push_back(guid);
+
+ if (candidates.empty())
+ return nullptr;
+
+ ObjectGuid randomGuid = Acore::Containers::SelectRandomContainerElement(candidates);
+ return ObjectAccessor::GetCreature(*me, randomGuid);
+}
+
bool SummonList::IsAnyCreatureAlive() const
{
for (auto const& guid : storage_)
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h
index 4aceb3fae5..47f8cf30c4 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h
@@ -157,6 +157,7 @@ public:
uint32 GetEntryCount(uint32 entry) const;
void Respawn();
Creature* GetCreatureWithEntry(uint32 entry) const;
+ Creature* GetRandomCreatureWithEntry(uint32 entry) const;
private:
Creature* me;
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 370e4c07df..c0b78bd2ae 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -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);
}
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index 3d86fd0599..73ced58747 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -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);
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index 9e84a3732a..02d38a2f5a 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -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);
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index 4cb7d3d1b1..55ebf72afd 100644
--- a/src/server/game/Entities/Pet/Pet.cpp
+++ b/src/server/game/Entities/Pet/Pet.cpp
@@ -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);
diff --git a/src/server/game/Entities/Player/KillRewarder.cpp b/src/server/game/Entities/Player/KillRewarder.cpp
index dce44da0f5..78d24b4dbc 100644
--- a/src/server/game/Entities/Player/KillRewarder.cpp
+++ b/src/server/game/Entities/Player/KillRewarder.cpp
@@ -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);
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 33d73b6e26..5bcd49fcf3 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -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 OFF_ATTACK:
+ unitMod = UNIT_MOD_DAMAGE_OFFHAND;
break;
- case PCT_MOD:
- ApplyPercentModFloatVar(m_auraBaseMod[modGroup][modType], amount, apply);
+ 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,118 +7111,92 @@ void Player::UpdateItemObtainSpells(Item* item, uint8 bag, uint8 slot)
ApplyItemObtainSpells(item, true);
}
-SpellSchoolMask Player::GetMeleeDamageSchoolMask(WeaponAttackType attackType /*= BASE_ATTACK*/, uint8 damageIndex /*= 0*/) const
-{
- if (Item const* weapon = GetWeaponForAttack(attackType, true))
- {
- return SpellSchoolMask(1 << weapon->GetTemplate()->Damage[damageIndex].DamageType);
- }
-
- 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)
+// 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)
{
- // 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;
+ BaseModGroup modGroup;
switch (attackType)
{
case BASE_ATTACK:
- mod = CRIT_PERCENTAGE;
+ modGroup = CRIT_PERCENTAGE;
break;
case OFF_ATTACK:
- mod = OFFHAND_CRIT_PERCENTAGE;
+ modGroup = OFFHAND_CRIT_PERCENTAGE;
break;
case RANGED_ATTACK:
- mod = RANGED_CRIT_PERCENTAGE;
+ modGroup = RANGED_CRIT_PERCENTAGE;
break;
default:
- return;
+ ABORT();
+ break;
}
- if (item->IsFitToSpellRequirements(aura->GetSpellInfo()))
- HandleBaseModValue(mod, FLAT_MOD, float (aura->GetAmount()), apply);
+ 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::_ApplyWeaponDependentAuraDamageMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply)
+void Player::UpdateAllWeaponDependentCritAuras()
{
- // 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;
+ for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i)
+ UpdateWeaponDependentCritAuras(WeaponAttackType(i));
+}
- // generic not weapon specific case processes in aura code
- if (aura->GetSpellInfo()->EquippedItemClass == -1)
- return;
+void Player::UpdateWeaponDependentAuras(WeaponAttackType attackType)
+{
+ UpdateWeaponDependentCritAuras(attackType);
+ UpdateDamageDoneMods(attackType);
+ UpdateDamagePctDoneMods(attackType);
+}
- UnitMods unitMod = UNIT_MOD_END;
- switch (attackType)
+void Player::ApplyItemDependentAuras(Item* item, bool apply)
+{
+ if (apply)
{
- 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;
- }
+ PlayerSpellMap const& spells = GetSpellMap();
+ for (auto itr = spells.begin(); itr != spells.end(); ++itr)
+ {
+ if (itr->second->State == PLAYERSPELL_REMOVED)
+ continue;
- 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;
+ 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);
+}
- if (item->IsFitToSpellRequirements(aura->GetSpellInfo()))
+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))
{
- 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);
- }
+ return SpellSchoolMask(1 << weapon->GetTemplate()->Damage[damageIndex].DamageType);
}
+
+ return SPELL_SCHOOL_MASK_NORMAL;
}
void Player::ApplyItemEquipSpell(Item* item, bool apply, bool form_change)
@@ -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], true);
_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;
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 1603a4f687..4e29cd5f5e 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -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;
diff --git a/src/server/game/Entities/Player/PlayerQuest.cpp b/src/server/game/Entities/Player/PlayerQuest.cpp
index 554622bba6..a2a99a4bd9 100644
--- a/src/server/game/Entities/Player/PlayerQuest.cpp
+++ b/src/server/game/Entities/Player/PlayerQuest.cpp
@@ -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;
}
diff --git a/src/server/game/Entities/Player/PlayerStorage.cpp b/src/server/game/Entities/Player/PlayerStorage.cpp
index bad5c36824..46d964e819 100644
--- a/src/server/game/Entities/Player/PlayerStorage.cpp
+++ b/src/server/game/Entities/Player/PlayerStorage.cpp
@@ -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:
@@ -6308,7 +6288,7 @@ void Player::_LoadQuestStatus(PreparedQueryResult result)
++slot;
}
- LOG_DEBUG("entities.player.loading", "Quest status is {{}} for quest {{}} for player ({})", questStatusData.Status, quest_id, GetGUID().ToString());
+ LOG_DEBUG("entities.player.loading", "Quest status is ({}) for quest ({}) for player ({})", questStatusData.Status, quest_id, GetGUID().ToString());
}
} while (result->NextRow());
}
@@ -6419,7 +6399,7 @@ void Player::_LoadWeeklyQuestStatus(PreparedQueryResult result)
continue;
m_weeklyquests.insert(quest_id);
- LOG_DEBUG("entities.player.loading", "Weekly quest {{}} cooldown for player ({})", quest_id, GetGUID().ToString());
+ LOG_DEBUG("entities.player.loading", "Weekly quest ({}) cooldown for player ({})", quest_id, GetGUID().ToString());
} while (result->NextRow());
}
@@ -6442,7 +6422,7 @@ void Player::_LoadSeasonalQuestStatus(PreparedQueryResult result)
continue;
m_seasonalquests[event_id].insert(quest_id);
- LOG_DEBUG("entities.player.loading", "Seasonal quest {{}} cooldown for player ({})", quest_id, GetGUID().ToString());
+ LOG_DEBUG("entities.player.loading", "Seasonal quest ({}) cooldown for player ({})", quest_id, GetGUID().ToString());
} while (result->NextRow());
}
@@ -6464,7 +6444,7 @@ void Player::_LoadMonthlyQuestStatus(PreparedQueryResult result)
continue;
m_monthlyquests.insert(quest_id);
- LOG_DEBUG("entities.player.loading", "Monthly quest {{}} cooldown for player ({})", quest_id, GetGUID().ToString());
+ LOG_DEBUG("entities.player.loading", "Monthly quest ({}) cooldown for player ({})", quest_id, GetGUID().ToString());
} while (result->NextRow());
}
diff --git a/src/server/game/Entities/Player/PlayerUpdates.cpp b/src/server/game/Entities/Player/PlayerUpdates.cpp
index 2913f66238..9a4427ce49 100644
--- a/src/server/game/Entities/Player/PlayerUpdates.cpp
+++ b/src/server/game/Entities/Player/PlayerUpdates.cpp
@@ -701,7 +701,7 @@ void Player::UpdateRating(CombatRating cr)
void Player::UpdateAllRatings()
{
- for (int cr = 0; cr < MAX_COMBAT_RATING; ++cr)
+ for (uint8 cr = 0; cr < MAX_COMBAT_RATING; ++cr)
UpdateRating(CombatRating(cr));
}
diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp
index 9009bc7d73..24c025ac6d 100644
--- a/src/server/game/Entities/Unit/StatSystem.cpp
+++ b/src/server/game/Entities/Unit/StatSystem.cpp
@@ -157,7 +157,7 @@ bool Player::UpdateStats(Stats stat)
mask |= (*i)->GetMiscValue();
if (mask)
{
- for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
+ for (uint8 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
if (mask & (1 << rating))
ApplyRatingMod(CombatRating(rating), 0, true);
}
@@ -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
- value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats
- value += GetModifierValue(unitMod, TOTAL_VALUE);
+ float value = GetFlatModifierValue(unitMod, BASE_VALUE); // base armor (from items)
+ value *= GetPctModifierValue(unitMod, BASE_PCT); // armor percent from items
+ value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats
+ 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);
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 31da399db5..623886eb78 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -16,7 +16,6 @@
*/
#include "Unit.h"
-#include "AccountMgr.h"
#include "AreaDefines.h"
#include "ArenaSpectator.h"
#include "Battlefield.h"
@@ -35,6 +34,7 @@
#include "CreatureGroups.h"
#include "DisableMgr.h"
#include "DynamicVisibility.h"
+#include "Errors.h"
#include "GameObjectAI.h"
#include "GameTime.h"
#include "GridNotifiersImpl.h"
@@ -54,19 +54,19 @@
#include "Player.h"
#include "ReputationMgr.h"
#include "ScriptMgr.h"
-#include "SmartAI.h"
+#include "SharedDefines.h"
#include "Spell.h"
+#include "SpellAuraDefines.h"
#include "SpellAuraEffects.h"
#include "SpellAuras.h"
#include "SpellInfo.h"
#include "SpellMgr.h"
-#include "TargetedMovementGenerator.h"
#include "TemporarySummon.h"
-#include "Tokenize.h"
#include "Totem.h"
#include "TotemAI.h"
#include "Transport.h"
#include "UpdateFieldFlags.h"
+#include "UpdateFields.h"
#include "Util.h"
#include "Vehicle.h"
#include "World.h"
@@ -268,13 +268,13 @@ Unit::Unit() : WorldObject(),
for (uint8 i = 0; i < UNIT_MOD_END; ++i)
{
- m_auraModifiersGroup[i][BASE_VALUE] = 0.0f;
- m_auraModifiersGroup[i][BASE_PCT] = 1.0f;
- m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f;
- m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f;
+ m_auraFlatModifiersGroup[i][BASE_VALUE] = 0.0f;
+ m_auraFlatModifiersGroup[i][TOTAL_VALUE] = 0.0f;
+ m_auraPctModifiersGroup[i][BASE_PCT] = 1.0f;
+ m_auraPctModifiersGroup[i][TOTAL_PCT] = 1.0f;
}
// implement 50% base damage from offhand
- m_auraModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f;
+ m_auraPctModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f;
for (uint8 i = 0; i < MAX_ATTACK; ++i)
{
@@ -628,7 +628,7 @@ void Unit::UpdateSplinePosition()
//if (HasUnitState(UNIT_STATE_CANNOT_TURN))
// loc.orientation = GetOrientation();
- if (IsPlayer())
+ if (IsPlayer() || IsPet())
UpdatePosition(loc.x, loc.y, loc.z, loc.orientation);
else
ToCreature()->SetPosition(loc.x, loc.y, loc.z, loc.orientation);
@@ -2096,22 +2096,22 @@ uint32 Unit::CalcArmorReducedDamage(Unit const* attacker, Unit const* victim, co
if (attacker->IsPlayer())
{
float bonusPct = 0;
- AuraEffectList const& armorPenAuras = attacker->GetAuraEffectsByType(SPELL_AURA_MOD_ARMOR_PENETRATION_PCT);
- for (AuraEffectList::const_iterator itr = armorPenAuras.begin(); itr != armorPenAuras.end(); ++itr)
+ bonusPct += attacker->GetTotalAuraModifier(SPELL_AURA_MOD_ARMOR_PENETRATION_PCT, [spellInfo,attacker](AuraEffect const* aurEff)
{
- if ((*itr)->GetSpellInfo()->EquippedItemClass == -1)
+ if (aurEff->GetSpellInfo()->EquippedItemClass == -1)
{
- if (!spellInfo || (*itr)->IsAffectedOnSpell(spellInfo) || (*itr)->GetMiscValue() & spellInfo->GetSchoolMask())
- bonusPct += (*itr)->GetAmount();
- else if (!(*itr)->GetMiscValue() && !(*itr)->HasSpellClassMask())
- bonusPct += (*itr)->GetAmount();
+ if (!spellInfo || aurEff->IsAffectedOnSpell(spellInfo) || aurEff->GetMiscValue() & spellInfo->GetSchoolMask())
+ return true;
+ else if (!aurEff->GetMiscValue() && !aurEff->HasSpellClassMask())
+ return true;
}
else
{
- if (attacker->ToPlayer()->HasItemFitToSpellRequirements((*itr)->GetSpellInfo()))
- bonusPct += (*itr)->GetAmount();
+ if (attacker->ToPlayer()->HasItemFitToSpellRequirements(aurEff->GetSpellInfo()))
+ return true;
}
- }
+ return false;
+ });
float maxArmorPen = 0;
if (victim->GetLevel() < 60)
@@ -3534,10 +3534,8 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spell, bool Ca
if (CanReflect)
{
int32 reflectchance = victim->GetTotalAuraModifier(SPELL_AURA_REFLECT_SPELLS);
- Unit::AuraEffectList const& mReflectSpellsSchool = victim->GetAuraEffectsByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL);
- for (Unit::AuraEffectList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i)
- if ((*i)->GetMiscValue() & spell->GetSchoolMask())
- reflectchance += (*i)->GetAmount();
+ reflectchance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_REFLECT_SPELLS_SCHOOL, spell->GetSchoolMask());
+
if (reflectchance > 0 && roll_chance_i(reflectchance))
{
// Start triggers for remove charges if need (trigger only for victim, and mark as active spell)
@@ -3611,14 +3609,7 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, Spell const* spell, bool CanRef
if (CanReflect)
{
int32 reflectchance = victim->GetTotalAuraModifier(SPELL_AURA_REFLECT_SPELLS);
- Unit::AuraEffectList const& mReflectSpellsSchool = victim->GetAuraEffectsByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL);
- for (Unit::AuraEffectList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i)
- {
- if ((*i)->GetMiscValue() & spell->GetSpellSchoolMask())
- {
- reflectchance += (*i)->GetAmount();
- }
- }
+ reflectchance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_REFLECT_SPELLS_SCHOOL, spellInfo->GetSchoolMask());
if (reflectchance > 0 && roll_chance_i(reflectchance))
{
@@ -3799,14 +3790,10 @@ float Unit::GetUnitCriticalChance(WeaponAttackType attackType, Unit const* victi
else
crit += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE);
- AuraEffectList const& mTotalAuraList = victim->GetAuraEffectsByType(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER);
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
+ crit += victim->GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [this](AuraEffect const* aurEff)
{
- if (GetGUID() != (*i)->GetCasterGUID())
- continue;
-
- crit += (*i)->GetAmount();
- }
+ return GetGUID() == aurEff->GetCasterGUID();
+ });
// reduce crit chance from Rating for players
if (attackType != RANGED_ATTACK)
@@ -4420,16 +4407,85 @@ void Unit::DeMorph()
SetDisplayId(GetNativeDisplayId());
}
+int32 Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue /*= false*/, int32 miscValue /*= 0*/) const
+{
+ int32 val = 0;
+ SpellSpellGroupMapBounds spellGroup = sSpellMgr->GetSpellSpellGroupMapBounds(aurEff->GetSpellInfo()->GetFirstRankSpell()->Id);
+ for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second ; ++itr)
+ {
+ if (sSpellMgr->GetSpellGroupStackRule(itr->second) == SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT)
+ {
+ AuraEffectList const& auraEffList = GetAuraEffectsByType(auraType);
+ for (AuraEffectList::const_iterator auraItr = auraEffList.begin(); auraItr != auraEffList.end(); ++auraItr)
+ {
+ if (aurEff != (*auraItr) && (!checkMiscValue || (*auraItr)->GetMiscValue() == miscValue) &&
+ sSpellMgr->IsSpellMemberOfSpellGroup((*auraItr)->GetSpellInfo()->Id, itr->second))
+ {
+ // absolute value only
+ if (abs(val) < abs((*auraItr)->GetAmount()))
+ val = (*auraItr)->GetAmount();
+ }
+ }
+ }
+ }
+ return val;
+}
+
+bool Unit::IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications /*= false*/)
+{
+ for (uint32 i = 0 ; i < MAX_SPELL_EFFECTS; ++i)
+ if (AuraEffect const* aurEff = aura->GetEffect(i))
+ if (!IsHighestExclusiveAuraEffect(aura->GetSpellInfo(), aurEff->GetAuraType(), aurEff->GetAmount(), aura->GetEffectMask(), removeOtherAuraApplications))
+ return false;
+
+ return true;
+}
+
+bool Unit::IsHighestExclusiveAuraEffect(SpellInfo const* spellInfo, AuraType auraType, int32 effectAmount, uint8 auraEffectMask, bool removeOtherAuraApplications /*= false*/)
+{
+ AuraEffectList const& auras = GetAuraEffectsByType(auraType);
+ for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end();)
+ {
+ AuraEffect const* existingAurEff = (*itr);
+ ++itr;
+
+ if (sSpellMgr->CheckSpellGroupStackRules(spellInfo, existingAurEff->GetSpellInfo()) == SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST)
+ {
+ int32 diff = abs(effectAmount) - abs(existingAurEff->GetAmount());
+ if (!diff)
+ for (int32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ diff += int32((auraEffectMask & (1 << i)) >> i) - int32((existingAurEff->GetBase()->GetEffectMask() & (1 << i)) >> i);
+
+ if (diff > 0)
+ {
+ Aura const* base = existingAurEff->GetBase();
+ // no removing of area auras from the original owner, as that completely cancels them
+ if (removeOtherAuraApplications && (!base->IsArea() || base->GetOwner() != this))
+ {
+ if (AuraApplication* aurApp = existingAurEff->GetBase()->GetApplicationOfTarget(GetGUID()))
+ {
+ bool hasMoreThanOneEffect = base->HasMoreThanOneEffectForType(auraType);
+ uint32 removedAuras = m_removedAurasCount;
+ RemoveAura(aurApp);
+ if (hasMoreThanOneEffect || m_removedAurasCount > removedAuras)
+ itr = auras.begin();
+ }
+ }
+ }
+ else if (diff < 0)
+ return false;
+ }
+ }
+
+ return true;
+}
+
Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount /*= nullptr*/, Item* castItem /*= nullptr*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/, bool periodicReset /*= false*/)
{
ASSERT(casterGUID || caster);
if (!casterGUID)
casterGUID = caster->GetGUID();
- // Xinef: Hax for mixology, best solution qq
- if (sSpellMgr->GetSpellGroup(newAura->Id) == 1)
- return nullptr;
-
// passive and Incanter's Absorption and auras with different type can stack with themselves any number of times
if (!newAura->IsMultiSlotAura())
{
@@ -4485,7 +4541,7 @@ void Unit::_AddAura(UnitAura* aura, Unit* caster)
ASSERT(!m_cleanupDone);
m_ownedAuras.insert(AuraMap::value_type(aura->GetId(), aura));
- _RemoveNoStackAurasDueToAura(aura);
+ _RemoveNoStackAurasDueToAura(aura, true);
if (aura->IsRemoved())
return;
@@ -4575,7 +4631,7 @@ void Unit::_ApplyAura(AuraApplication* aurApp, uint8 effMask)
{
Aura* aura = aurApp->GetBase();
- _RemoveNoStackAurasDueToAura(aura);
+ _RemoveNoStackAurasDueToAura(aura, false);
if (aurApp->GetRemoveMode())
return;
@@ -4733,7 +4789,7 @@ void Unit::_UnapplyAura(AuraApplication* aurApp, AuraRemoveMode removeMode)
ABORT();
}
-void Unit::_RemoveNoStackAurasDueToAura(Aura* aura)
+void Unit::_RemoveNoStackAurasDueToAura(Aura* aura, bool owned)
{
//SpellInfo const* spellProto = aura->GetSpellInfo();
@@ -4743,23 +4799,17 @@ void Unit::_RemoveNoStackAurasDueToAura(Aura* aura)
// if (spellProto->IsPassiveStackableWithRanks())
// return;
- bool remove = false;
- for (AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
+ ASSERT(aura);
+ if (!IsHighestExclusiveAura(aura))
{
- if (remove)
- {
- remove = false;
- i = m_appliedAuras.begin();
- }
-
- if (aura->CanStackWith(i->second->GetBase(), true))
- continue;
-
- RemoveAura(i, AURA_REMOVE_BY_DEFAULT);
- if (i == m_appliedAuras.end())
- break;
- remove = true;
+ aura->Remove();
+ return;
}
+
+ if (owned)
+ RemoveOwnedAuras([aura](Aura const* ownedAura) { return !aura->CanStackWith(ownedAura); });
+ else
+ RemoveAppliedAuras([aura](AuraApplication const* appliedAura) { return !aura->CanStackWith(appliedAura->GetBase()); });
}
void Unit::_RegisterAuraEffect(AuraEffect* aurEff, bool apply)
@@ -5987,232 +6037,309 @@ uint32 Unit::GetDoTsByCaster(ObjectGuid casterGUID) const
return dots;
}
-int32 Unit::GetTotalAuraModifierAreaExclusive(AuraType auratype) const
+int32 Unit::GetTotalAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
{
+ AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
+ if (mTotalAuraList.empty())
+ return 0;
+
+ std::map<SpellGroup, int32> sameEffectSpellGroup;
int32 modifier = 0;
- int32 areaModifier = 0;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
+ for (AuraEffect const* aurEff : mTotalAuraList)
{
- if ((*i)->GetSpellInfo()->HasAreaAuraEffect())
+ if (predicate(aurEff))
{
- if (areaModifier < (*i)->GetAmount())
- areaModifier = (*i)->GetAmount();
+ // Check if the Aura Effect has a the Same Effect Stack Rule and if so, use the highest amount of that SpellGroup
+ // If the Aura Effect does not have this Stack Rule, it returns false so we can add to the multiplier as usual
+ if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), static_cast<uint32>(auraType), aurEff->GetAmount(), sameEffectSpellGroup))
+ modifier += aurEff->GetAmount();
}
- else
- modifier += (*i)->GetAmount();
}
- return modifier + areaModifier;
-}
-
-int32 Unit::GetTotalAuraModifier(AuraType auratype) const
-{
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- if (mTotalAuraList.empty())
- return 0;
-
- int32 modifier = 0;
-
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- modifier += (*i)->GetAmount();
+ // Add the highest of the Same Effect Stack Rule SpellGroups to the accumulator
+ for (auto const& [_, amount] : sameEffectSpellGroup)
+ modifier += amount;
return modifier;
}
-float Unit::GetTotalAuraMultiplier(AuraType auratype) const
+float Unit::GetTotalAuraMultiplier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
{
+ AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
+ if (mTotalAuraList.empty())
+ return 1.0f;
+
+ std::map<SpellGroup, int32> sameEffectSpellGroup;
float multiplier = 1.0f;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- AddPct(multiplier, (*i)->GetAmount());
+ for (AuraEffect const* aurEff : mTotalAuraList)
+ {
+ if (predicate(aurEff))
+ {
+ // Check if the Aura Effect has a the Same Effect Stack Rule and if so, use the highest amount of that SpellGroup
+ // If the Aura Effect does not have this Stack Rule, it returns false so we can add to the multiplier as usual
+ if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), static_cast<uint32>(auraType), aurEff->GetAmount(), sameEffectSpellGroup))
+ AddPct(multiplier, aurEff->GetAmount());
+ }
+ }
+
+ // Add the highest of the Same Effect Stack Rule SpellGroups to the multiplier
+ for (auto itr = sameEffectSpellGroup.begin(); itr != sameEffectSpellGroup.end(); ++itr)
+ AddPct(multiplier, itr->second);
return multiplier;
}
-int32 Unit::GetMaxPositiveAuraModifier(AuraType auratype)
+int32 Unit::GetMaxPositiveAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
{
- int32 modifier = 0;
+ AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
+ if (mTotalAuraList.empty())
+ return 0;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
+ int32 modifier = 0;
+ for (AuraEffect const* aurEff : mTotalAuraList)
{
- if ((*i)->GetAmount() > modifier)
- modifier = (*i)->GetAmount();
+ if (predicate(aurEff))
+ modifier = std::max(modifier, aurEff->GetAmount());
}
return modifier;
}
-int32 Unit::GetMaxNegativeAuraModifier(AuraType auratype) const
+int32 Unit::GetMaxNegativeAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
{
- int32 modifier = 0;
-
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- if ((*i)->GetAmount() < modifier)
- modifier = (*i)->GetAmount();
-
- return modifier;
-}
+ AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
+ if (mTotalAuraList.empty())
+ return 0;
-int32 Unit::GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const
-{
int32 modifier = 0;
-
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
+ for (AuraEffect const* aurEff : mTotalAuraList)
{
- if ((*i)->GetMiscValue()& misc_mask)
- modifier += (*i)->GetAmount();
+ if (predicate(aurEff))
+ modifier = std::min(modifier, aurEff->GetAmount());
}
+
return modifier;
}
-float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask) const
+int32 Unit::GetTotalAuraModifier(AuraType auraType) const
{
- float multiplier = 1.0f;
+ return GetTotalAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
+}
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- if (((*i)->GetMiscValue() & misc_mask))
- AddPct(multiplier, (*i)->GetAmount());
+float Unit::GetTotalAuraMultiplier(AuraType auraType) const
+{
+ return GetTotalAuraMultiplier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
+}
- return multiplier;
+int32 Unit::GetMaxPositiveAuraModifier(AuraType auraType) const
+{
+ return GetMaxPositiveAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
}
-int32 Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask, const AuraEffect* except) const
+int32 Unit::GetMaxNegativeAuraModifier(AuraType auraType) const
{
- int32 modifier = 0;
+ return GetMaxNegativeAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
+}
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
+int32 Unit::GetTotalAuraModifierByMiscMask(AuraType auraType, uint32 miscMask) const
+{
+ return GetTotalAuraModifier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
{
- if (except != (*i) && (*i)->GetMiscValue()& misc_mask && (*i)->GetAmount() > modifier)
- modifier = (*i)->GetAmount();
- }
-
- return modifier;
+ if ((aurEff->GetMiscValue() & miscMask) != 0)
+ return true;
+ return false;
+ });
}
-int32 Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const
+float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auraType, uint32 miscMask) const
{
- int32 modifier = 0;
-
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
+ return GetTotalAuraMultiplier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
{
- if ((*i)->GetMiscValue()& misc_mask && (*i)->GetAmount() < modifier)
- modifier = (*i)->GetAmount();
- }
-
- return modifier;
+ if ((aurEff->GetMiscValue() & miscMask) != 0)
+ return true;
+ return false;
+ });
}
-int32 Unit::GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const
+int32 Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auraType, uint32 miscMask, AuraEffect const* except /*= nullptr*/) const
{
- int32 modifier = 0;
-
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- if ((*i)->GetMiscValue() == misc_value)
- modifier += (*i)->GetAmount();
-
- return modifier;
+ return GetMaxPositiveAuraModifier(auraType, [miscMask, except](AuraEffect const* aurEff) -> bool
+ {
+ if (except != aurEff && (aurEff->GetMiscValue() & miscMask) != 0)
+ return true;
+ return false;
+ });
}
-float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype, int32 misc_value) const
+int32 Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auraType, uint32 miscMask) const
{
- float multiplier = 1.0f;
-
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- if ((*i)->GetMiscValue() == misc_value)
- AddPct(multiplier, (*i)->GetAmount());
-
- return multiplier;
+ return GetMaxNegativeAuraModifier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
+ {
+ if ((aurEff->GetMiscValue() & miscMask) != 0)
+ return true;
+ return false;
+ });
}
-int32 Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const
+int32 Unit::GetTotalAuraModifierByMiscValue(AuraType auraType, int32 miscValue) const
{
- int32 modifier = 0;
-
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
+ return GetTotalAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
{
- if ((*i)->GetMiscValue() == misc_value && (*i)->GetAmount() > modifier)
- modifier = (*i)->GetAmount();
- }
+ if (aurEff->GetMiscValue() == miscValue)
+ return true;
+ return false;
+ });
+}
- return modifier;
+float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auraType, int32 miscValue) const
+{
+ return GetTotalAuraMultiplier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
+ {
+ if (aurEff->GetMiscValue() == miscValue)
+ return true;
+ return false;
+ });
}
-int32 Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const
+int32 Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auraType, int32 miscValue) const
{
- int32 modifier = 0;
+ return GetMaxPositiveAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
+ {
+ if (aurEff->GetMiscValue() == miscValue)
+ return true;
+ return false;
+ });
+}
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
+int32 Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auraType, int32 miscValue) const
+{
+ return GetMaxNegativeAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
{
- if ((*i)->GetMiscValue() == misc_value && (*i)->GetAmount() < modifier)
- modifier = (*i)->GetAmount();
- }
+ if (aurEff->GetMiscValue() == miscValue)
+ return true;
+ return false;
+ });
+}
- return modifier;
+int32 Unit::GetTotalAuraModifierByAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
+{
+ return GetTotalAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
+ {
+ if (aurEff->IsAffectedOnSpell(affectedSpell))
+ return true;
+ return false;
+ });
}
-int32 Unit::GetTotalAuraModifierByAffectMask(AuraType auratype, SpellInfo const* affectedSpell) const
+float Unit::GetTotalAuraMultiplierByAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
{
- int32 modifier = 0;
+ return GetTotalAuraMultiplier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
+ {
+ if (aurEff->IsAffectedOnSpell(affectedSpell))
+ return true;
+ return false;
+ });
+}
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- if ((*i)->IsAffectedOnSpell(affectedSpell))
- modifier += (*i)->GetAmount();
+int32 Unit::GetMaxPositiveAuraModifierByAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
+{
+ return GetMaxPositiveAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
+ {
+ if (aurEff->IsAffectedOnSpell(affectedSpell))
+ return true;
+ return false;
+ });
+}
- return modifier;
+int32 Unit::GetMaxNegativeAuraModifierByAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
+{
+ return GetMaxNegativeAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
+ {
+ if (aurEff->IsAffectedOnSpell(affectedSpell))
+ return true;
+ return false;
+ });
}
-float Unit::GetTotalAuraMultiplierByAffectMask(AuraType auratype, SpellInfo const* affectedSpell) const
+void Unit::UpdateResistanceBuffModsMod(SpellSchools school)
{
- float multiplier = 1.0f;
+ float modPos = 0.0f;
+ float modNeg = 0.0f;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- if ((*i)->IsAffectedOnSpell(affectedSpell))
- AddPct(multiplier, (*i)->GetAmount());
+ // these auras are always positive
+ modPos = GetMaxPositiveAuraModifierByMiscMask(SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE, 1 << school);
+ modPos += GetTotalAuraModifier(SPELL_AURA_MOD_RESISTANCE, [school](AuraEffect const* aurEff) -> bool
+ {
+ if ((aurEff->GetMiscValue() & (1 << school)) && aurEff->GetAmount() > 0)
+ return true;
+ return false;
+ });
- return multiplier;
+ modNeg = GetTotalAuraModifier(SPELL_AURA_MOD_RESISTANCE, [school](AuraEffect const* aurEff) -> bool
+ {
+ if ((aurEff->GetMiscValue() & (1 << school)) && aurEff->GetAmount() < 0)
+ return true;
+ return false;
+ });
+
+ float factor = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_RESISTANCE_PCT, 1 << school);
+ modPos *= factor;
+ modNeg *= factor;
+
+ SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + AsUnderlyingType(school), modPos);
+ SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + AsUnderlyingType(school), modNeg);
}
-int32 Unit::GetMaxPositiveAuraModifierByAffectMask(AuraType auratype, SpellInfo const* affectedSpell) const
+void Unit::UpdateStatBuffMod(Stats stat)
{
- int32 modifier = 0;
+ float modPos = 0.0f;
+ float modNeg = 0.0f;
+ float factor = 0.0f;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
+ UnitMods const unitMod = static_cast<UnitMods>(UNIT_MOD_STAT_START + AsUnderlyingType(stat));
+
+ // includes value from items and enchantments
+ float modValue = GetFlatModifierValue(unitMod, BASE_VALUE);
+ if (modValue > 0.f)
+ modPos += modValue;
+ else
+ modNeg += modValue;
+
+ modPos += GetTotalAuraModifier(SPELL_AURA_MOD_STAT, [stat](AuraEffect const* aurEff) -> bool
{
- if ((*i)->IsAffectedOnSpell(affectedSpell) && (*i)->GetAmount() > modifier)
- modifier = (*i)->GetAmount();
- }
+ if ((aurEff->GetMiscValue() < 0 || aurEff->GetMiscValue() == stat) && aurEff->GetAmount() > 0)
+ return true;
+ return false;
+ });
- return modifier;
-}
+ modNeg += GetTotalAuraModifier(SPELL_AURA_MOD_STAT, [stat](AuraEffect const* aurEff) -> bool
+ {
+ if ((aurEff->GetMiscValue() < 0 || aurEff->GetMiscValue() == stat) && aurEff->GetAmount() < 0)
+ return true;
+ return false;
+ });
-int32 Unit::GetMaxNegativeAuraModifierByAffectMask(AuraType auratype, SpellInfo const* affectedSpell) const
-{
- int32 modifier = 0;
+ factor = GetTotalAuraMultiplier(SPELL_AURA_MOD_PERCENT_STAT, [stat](AuraEffect const* aurEff) -> bool
+ {
+ if (aurEff->GetMiscValue() == -1 || aurEff->GetMiscValue() == stat)
+ return true;
+ return false;
+ });
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
+ factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, [stat](AuraEffect const* aurEff) -> bool
{
- if ((*i)->IsAffectedOnSpell(affectedSpell) && (*i)->GetAmount() < modifier)
- modifier = (*i)->GetAmount();
- }
+ if (aurEff->GetMiscValue() == -1 || aurEff->GetMiscValue() == stat)
+ return true;
+ return false;
+ });
- return modifier;
+ modPos *= factor;
+ modNeg *= factor;
+
+ SetFloatValue(UNIT_FIELD_POSSTAT0 + AsUnderlyingType(stat), modPos);
+ SetFloatValue(UNIT_FIELD_NEGSTAT0 + AsUnderlyingType(stat), modNeg);
}
void Unit::_RegisterDynObject(DynamicObject* dynObj)
@@ -11387,44 +11514,41 @@ float Unit::SpellPctDamageModsDone(Unit* victim, SpellInfo const* spellProto, Da
// Done total percent damage auras
float DoneTotalMod = 1.0f;
- AuraEffectList const& mModDamagePercentDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
- for (AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
+ DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, [spellProto, this, damagetype](AuraEffect const* aurEff)
{
// prevent apply mods from weapon specific case to non weapon specific spells (Example: thunder clap and two-handed weapon specialization)
- if (spellProto->EquippedItemClass == -1 && (*i)->GetSpellInfo()->EquippedItemClass != -1 &&
- !(*i)->GetSpellInfo()->HasAttribute(SPELL_ATTR5_AURA_AFFECTS_NOT_JUST_REQ_EQUIPPED_ITEM) && (*i)->GetMiscValue() == SPELL_SCHOOL_MASK_NORMAL)
+ if (spellProto->EquippedItemClass == -1 && aurEff->GetSpellInfo()->EquippedItemClass != -1 &&
+ !aurEff->GetSpellInfo()->HasAttribute(SPELL_ATTR5_AURA_AFFECTS_NOT_JUST_REQ_EQUIPPED_ITEM) && aurEff->GetMiscValue() == SPELL_SCHOOL_MASK_NORMAL)
{
- continue;
- }
-
- if (!spellProto->ValidateAttribute6SpellDamageMods(this, *i, damagetype == DOT))
- continue;
+ return false;
+ }
- if (!sScriptMgr->IsNeedModSpellDamagePercent(this, *i, DoneTotalMod, spellProto))
- continue;
+ if (!spellProto->ValidateAttribute6SpellDamageMods(this, aurEff, damagetype == DOT))
+ return false;
- if ((*i)->GetMiscValue() & spellProto->GetSchoolMask())
+ if (aurEff->GetMiscValue() & spellProto->GetSchoolMask())
{
- if ((*i)->GetSpellInfo()->EquippedItemClass == -1)
- AddPct(DoneTotalMod, (*i)->GetAmount());
- else if (!(*i)->GetSpellInfo()->HasAttribute(SPELL_ATTR5_AURA_AFFECTS_NOT_JUST_REQ_EQUIPPED_ITEM) && ((*i)->GetSpellInfo()->EquippedItemSubClassMask == 0))
- AddPct(DoneTotalMod, (*i)->GetAmount());
- else if (ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*i)->GetSpellInfo()))
- AddPct(DoneTotalMod, (*i)->GetAmount());
+ if (aurEff->GetSpellInfo()->EquippedItemClass == -1)
+ return true;
+ else if (!aurEff->GetSpellInfo()->HasAttribute(SPELL_ATTR5_AURA_AFFECTS_NOT_JUST_REQ_EQUIPPED_ITEM) && (aurEff->GetSpellInfo()->EquippedItemSubClassMask == 0))
+ return true;
+ else if (ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements(aurEff->GetSpellInfo()))
+ return true;
}
- }
+ return false;
+ });
uint32 creatureTypeMask = victim->GetCreatureTypeMask();
- AuraEffectList const& mDamageDoneVersus = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS);
- for (AuraEffectList::const_iterator i = mDamageDoneVersus.begin(); i != mDamageDoneVersus.end(); ++i)
- if ((creatureTypeMask & uint32((*i)->GetMiscValue())) && spellProto->ValidateAttribute6SpellDamageMods(this, *i, damagetype == DOT))
- AddPct(DoneTotalMod, (*i)->GetAmount());
+ DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS, [creatureTypeMask, spellProto, damagetype, this](AuraEffect const* aurEff)
+ {
+ return creatureTypeMask & aurEff->GetMiscValue() && spellProto->ValidateAttribute6SpellDamageMods(this, aurEff, damagetype == DOT);
+ });
// bonus against aurastate
- AuraEffectList const& mDamageDoneVersusAurastate = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE);
- for (AuraEffectList::const_iterator i = mDamageDoneVersusAurastate.begin(); i != mDamageDoneVersusAurastate.end(); ++i)
- if (victim->HasAuraState(AuraStateType((*i)->GetMiscValue())) && spellProto->ValidateAttribute6SpellDamageMods(this, *i, damagetype == DOT))
- AddPct(DoneTotalMod, (*i)->GetAmount());
+ DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE, [victim, spellProto, damagetype, this](AuraEffect const* aurEff)
+ {
+ return victim->HasAuraState(AuraStateType(aurEff->GetMiscValue())) && spellProto->ValidateAttribute6SpellDamageMods(this, aurEff, damagetype == DOT);
+ });
// done scripted mod (take it from owner)
Unit* owner = GetOwner() ? GetOwner() : this;
@@ -11876,22 +12000,19 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui
// from positive and negative SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
// multiplicative bonus, for example Dispersion + Shadowform (0.10*0.85=0.085)
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- if (((*i)->GetMiscValue() & spellProto->GetSchoolMask()))
- if (spellProto->ValidateAttribute6SpellDamageMods(caster, *i, damagetype == DOT))
- AddPct(TakenTotalMod, (*i)->GetAmount());
+ TakenTotalMod *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, spellProto->GetSchoolMask());
TakenTotalMod = processDummyAuras(TakenTotalMod);
// From caster spells
if (caster)
{
- AuraEffectList const& mOwnerTaken = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_FROM_CASTER);
- for (AuraEffectList::const_iterator i = mOwnerTaken.begin(); i != mOwnerTaken.end(); ++i)
- if ((*i)->GetCasterGUID() == caster->GetGUID() && (*i)->IsAffectedOnSpell(spellProto))
- if (spellProto->ValidateAttribute6SpellDamageMods(caster, *i, damagetype == DOT))
- AddPct(TakenTotalMod, (*i)->GetAmount());
+ TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_FROM_CASTER, [caster, spellProto](AuraEffect const* aurEff) -> bool
+ {
+ if (aurEff->GetCasterGUID() == caster->GetGUID() && aurEff->IsAffectedOnSpell(spellProto))
+ return true;
+ return false;
+ });
}
if (uint32 mechanicMask = spellProto->GetAllEffectsMechanicMask())
@@ -12014,16 +12135,14 @@ float Unit::processDummyAuras(float TakenTotalMod) const
int32 Unit::SpellBaseDamageBonusDone(SpellSchoolMask schoolMask)
{
- int32 DoneAdvertisedBenefit = 0;
-
- AuraEffectList const& mDamageDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE);
- for (AuraEffectList::const_iterator i = mDamageDone.begin(); i != mDamageDone.end(); ++i)
- if (((*i)->GetMiscValue() & schoolMask) != 0 &&
- (*i)->GetSpellInfo()->EquippedItemClass == -1 &&
+ int32 DoneAdvertisedBenefit = GetTotalAuraModifier(SPELL_AURA_MOD_DAMAGE_DONE, [schoolMask](AuraEffect const* aurEff)
+ {
+ return aurEff->GetMiscValue() & schoolMask &&
// -1 == any item class (not wand then)
- (*i)->GetSpellInfo()->EquippedItemInventoryTypeMask == 0)
- // 0 == any inventory type (not wand then)
- DoneAdvertisedBenefit += (*i)->GetAmount();
+ aurEff->GetSpellInfo()->EquippedItemClass == -1 &&
+ // 0 == any inventory type (not wand then)
+ aurEff->GetSpellInfo()->EquippedItemInventoryTypeMask == 0;
+ });
if (IsPlayer())
{
@@ -12043,31 +12162,20 @@ int32 Unit::SpellBaseDamageBonusDone(SpellSchoolMask schoolMask)
}
}
// ... and attack power
- AuraEffectList const& mDamageDonebyAP = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER);
- for (AuraEffectList::const_iterator i = mDamageDonebyAP.begin(); i != mDamageDonebyAP.end(); ++i)
- if ((*i)->GetMiscValue() & schoolMask)
- DoneAdvertisedBenefit += int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), (*i)->GetAmount()));
+ DoneAdvertisedBenefit += int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER, schoolMask)));
}
return DoneAdvertisedBenefit;
}
int32 Unit::SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask, bool isDoT)
{
- int32 TakenAdvertisedBenefit = 0;
-
- AuraEffectList const& mDamageTaken = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
- for (AuraEffectList::const_iterator i = mDamageTaken.begin(); i != mDamageTaken.end(); ++i)
- if (((*i)->GetMiscValue() & schoolMask) != 0)
- {
+ return GetTotalAuraModifier(SPELL_AURA_MOD_DAMAGE_TAKEN, [schoolMask, isDoT](AuraEffect const* aurEff)
+ {
+ return (aurEff->GetMiscValue() & schoolMask) != 0
// Xinef: if we have DoT damage type and aura has charges, check if it affects DoTs
// Xinef: required for hemorrhage & rupture / garrote
- if (isDoT && (*i)->GetBase()->IsUsingCharges() && !((*i)->GetSpellInfo()->ProcFlags & PROC_FLAG_TAKEN_PERIODIC))
- continue;
-
- TakenAdvertisedBenefit += (*i)->GetAmount();
- }
-
- return TakenAdvertisedBenefit;
+ && !(isDoT && aurEff->GetBase()->IsUsingCharges() && aurEff->GetSpellInfo()->ProcFlags & PROC_FLAG_TAKEN_PERIODIC);
+ });
}
float Unit::SpellDoneCritChance(Unit const* /*victim*/, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType, bool skipEffectCheck) const
@@ -12338,14 +12446,10 @@ float Unit::SpellTakenCritChance(Unit const* caster, SpellInfo const* spellProto
if (caster)
{
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER);
- for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
+ crit_chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [caster](AuraEffect const* aurEff)
{
- if (caster->GetGUID() != (*i)->GetCasterGUID())
- continue;
-
- crit_chance += (*i)->GetAmount();
- }
+ return caster->GetGUID() == aurEff->GetCasterGUID();
+ });
}
// Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
@@ -12458,14 +12562,7 @@ float Unit::SpellPctHealingModsDone(Unit* victim, SpellInfo const* spellProto, D
float DoneTotalMod = 1.0f;
// Healing done percent
- AuraEffectList const& mHealingDonePct = GetAuraEffectsByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT);
- for (auto const& auraEff : mHealingDonePct)
- {
- if (!sScriptMgr->IsNeedModHealPercent(this, auraEff, DoneTotalMod, spellProto))
- continue;
-
- AddPct(DoneTotalMod, auraEff->GetAmount());
- }
+ DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_DONE_PERCENT);
// done scripted mod (take it from owner)
Unit* owner = GetOwner() ? GetOwner() : this;
@@ -12631,6 +12728,8 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui
case SPELL_AURA_PERIODIC_HEALTH_FUNNEL:
DoneTotal = 0;
break;
+ default:
+ break;
}
if (spellProto->Effects[i].Effect == SPELL_EFFECT_HEALTH_LEECH)
DoneTotal = 0;
@@ -12672,7 +12771,7 @@ uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, u
int32 TakenTotal = 0;
// Taken fixed damage bonus auras
- int32 TakenAdvertisedBenefit = SpellBaseHealingBonusTaken(spellProto->GetSchoolMask());
+ int32 TakenAdvertisedBenefit = GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_HEALING, spellProto->GetSchoolMask());
// Nourish cast, glyph of nourish
if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[1] & 0x2000000 && caster)
@@ -12746,10 +12845,10 @@ uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, u
if (caster)
{
- AuraEffectList const& mHealingGet = GetAuraEffectsByType(SPELL_AURA_MOD_HEALING_RECEIVED);
- for (AuraEffectList::const_iterator i = mHealingGet.begin(); i != mHealingGet.end(); ++i)
- if (caster->GetGUID() == (*i)->GetCasterGUID() && (*i)->IsAffectedOnSpell(spellProto))
- AddPct(TakenTotalMod, (*i)->GetAmount());
+ TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_RECEIVED, [caster, spellProto](AuraEffect const* aurEff)
+ {
+ return caster->GetGUID() == aurEff->GetCasterGUID() && aurEff->IsAffectedOnSpell(spellProto);
+ });
}
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
@@ -12761,6 +12860,8 @@ uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, u
case SPELL_AURA_PERIODIC_HEALTH_FUNNEL:
TakenTotal = 0;
break;
+ default:
+ break;
}
if (spellProto->Effects[i].Effect == SPELL_EFFECT_HEALTH_LEECH)
TakenTotal = 0;
@@ -12782,10 +12883,10 @@ int32 Unit::SpellBaseHealingBonusDone(SpellSchoolMask schoolMask)
{
int32 AdvertisedBenefit = 0;
- AuraEffectList const& mHealingDone = GetAuraEffectsByType(SPELL_AURA_MOD_HEALING_DONE);
- for (AuraEffectList::const_iterator i = mHealingDone.begin(); i != mHealingDone.end(); ++i)
- if (!(*i)->GetMiscValue() || ((*i)->GetMiscValue() & schoolMask) != 0)
- AdvertisedBenefit += (*i)->GetAmount();
+ AdvertisedBenefit += GetTotalAuraModifier(SPELL_AURA_MOD_HEALING_DONE, [schoolMask](AuraEffect const* aurEff)
+ {
+ return !aurEff->GetMiscValue() || (aurEff->GetMiscValue() & schoolMask) != 0;
+ });
// Healing bonus of spirit, intellect and strength
if (IsPlayer())
@@ -12804,26 +12905,11 @@ int32 Unit::SpellBaseHealingBonusDone(SpellSchoolMask schoolMask)
}
// ... and attack power
- AuraEffectList const& mHealingDonebyAP = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER);
- for (AuraEffectList::const_iterator i = mHealingDonebyAP.begin(); i != mHealingDonebyAP.end(); ++i)
- if ((*i)->GetMiscValue() & schoolMask)
- AdvertisedBenefit += int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), (*i)->GetAmount()));
+ AdvertisedBenefit += int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER, schoolMask)));
}
return AdvertisedBenefit;
}
-int32 Unit::SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask)
-{
- int32 AdvertisedBenefit = 0;
-
- AuraEffectList const& mDamageTaken = GetAuraEffectsByType(SPELL_AURA_MOD_HEALING);
- for (AuraEffectList::const_iterator i = mDamageTaken.begin(); i != mDamageTaken.end(); ++i)
- if (((*i)->GetMiscValue() & schoolMask) != 0)
- AdvertisedBenefit += (*i)->GetAmount();
-
- return AdvertisedBenefit;
-}
-
bool Unit::IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const
{
if (meleeSchoolMask == SPELL_SCHOOL_MASK_NONE)
@@ -13172,10 +13258,7 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType
int32 DoneFlatBenefit = 0;
// ..done
- AuraEffectList const& mDamageDoneCreature = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
- for (AuraEffectList::const_iterator i = mDamageDoneCreature.begin(); i != mDamageDoneCreature.end(); ++i)
- if (creatureTypeMask & uint32((*i)->GetMiscValue()))
- DoneFlatBenefit += (*i)->GetAmount();
+ DoneFlatBenefit += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE, creatureTypeMask);
// ..done
// SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
@@ -13188,20 +13271,14 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType
APbonus += victim->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS);
// ..done (base at attack power and creature type)
- AuraEffectList const& mCreatureAttackPower = GetAuraEffectsByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS);
- for (AuraEffectList::const_iterator i = mCreatureAttackPower.begin(); i != mCreatureAttackPower.end(); ++i)
- if (creatureTypeMask & uint32((*i)->GetMiscValue()))
- APbonus += (*i)->GetAmount();
+ APbonus += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS, creatureTypeMask);
}
else
{
APbonus += victim->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS);
// ..done (base at attack power and creature type)
- AuraEffectList const& mCreatureAttackPower = GetAuraEffectsByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS);
- for (AuraEffectList::const_iterator i = mCreatureAttackPower.begin(); i != mCreatureAttackPower.end(); ++i)
- if (creatureTypeMask & uint32((*i)->GetMiscValue()))
- APbonus += (*i)->GetAmount();
+ APbonus += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS, creatureTypeMask);
}
if (APbonus != 0) // Can be negative
@@ -13224,37 +13301,34 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType
if (!(damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL))
{
// Some spells don't benefit from pct done mods
- AuraEffectList const& mModDamagePercentDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
- for (AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
- {
- if (!spellProto || (spellProto->ValidateAttribute6SpellDamageMods(this, *i, false) &&
- sScriptMgr->IsNeedModMeleeDamagePercent(this, *i, DoneTotalMod, spellProto)))
+ DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, [spellProto, this, damageSchoolMask](AuraEffect const* aurEff)
+ {
+ if (!spellProto || (spellProto->ValidateAttribute6SpellDamageMods(this, aurEff, false)))
{
- if (((*i)->GetMiscValue() & damageSchoolMask))
+ if ((aurEff->GetMiscValue() & damageSchoolMask))
{
- if ((*i)->GetSpellInfo()->EquippedItemClass == -1)
- AddPct(DoneTotalMod, (*i)->GetAmount());
- else if (!(*i)->GetSpellInfo()->HasAttribute(SPELL_ATTR5_AURA_AFFECTS_NOT_JUST_REQ_EQUIPPED_ITEM) && ((*i)->GetSpellInfo()->EquippedItemSubClassMask == 0))
- AddPct(DoneTotalMod, (*i)->GetAmount());
- else if (ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*i)->GetSpellInfo()))
- AddPct(DoneTotalMod, (*i)->GetAmount());
+ if (aurEff->GetSpellInfo()->EquippedItemClass == -1)
+ return true;
+ else if (!aurEff->GetSpellInfo()->HasAttribute(SPELL_ATTR5_AURA_AFFECTS_NOT_JUST_REQ_EQUIPPED_ITEM) && (aurEff->GetSpellInfo()->EquippedItemSubClassMask == 0))
+ return true;
+ else if (ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements(aurEff->GetSpellInfo()))
+ return true;
}
}
- }
+ return false;
+ });
}
- AuraEffectList const& mDamageDoneVersus = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS);
- for (AuraEffectList::const_iterator i = mDamageDoneVersus.begin(); i != mDamageDoneVersus.end(); ++i)
- if (creatureTypeMask & uint32((*i)->GetMiscValue()))
- if (!spellProto || spellProto->ValidateAttribute6SpellDamageMods(this, *i, false))
- AddPct(DoneTotalMod, (*i)->GetAmount());
+ DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS, [creatureTypeMask, spellProto, this](AuraEffect const* aurEff)
+ {
+ return (creatureTypeMask & aurEff->GetMiscValue() && (!spellProto || spellProto->ValidateAttribute6SpellDamageMods(this, aurEff, false)));
+ });
// bonus against aurastate
- AuraEffectList const& mDamageDoneVersusAurastate = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE);
- for (AuraEffectList::const_iterator i = mDamageDoneVersusAurastate.begin(); i != mDamageDoneVersusAurastate.end(); ++i)
- if (victim->HasAuraState(AuraStateType((*i)->GetMiscValue())))
- if (!spellProto || spellProto->ValidateAttribute6SpellDamageMods(this, *i, false))
- AddPct(DoneTotalMod, (*i)->GetAmount());
+ DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE, [victim, spellProto, this](AuraEffect const* aurEff)
+ {
+ return (victim->HasAuraState(AuraStateType(aurEff->GetMiscValue())) && (!spellProto || spellProto->ValidateAttribute6SpellDamageMods(this, aurEff, false)));
+ });
// done scripted mod (take it from owner)
Unit* owner = GetOwner() ? GetOwner() : this;
@@ -13361,10 +13435,7 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT
int32 TakenFlatBenefit = 0;
// ..taken
- AuraEffectList const& mDamageTaken = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
- for (AuraEffectList::const_iterator i = mDamageTaken.begin(); i != mDamageTaken.end(); ++i)
- if ((*i)->GetMiscValue() & damageSchoolMask)
- TakenFlatBenefit += (*i)->GetAmount();
+ TakenFlatBenefit += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_TAKEN, damageSchoolMask);
if (attType != RANGED_ATTACK)
TakenFlatBenefit += GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN);
@@ -13380,10 +13451,10 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT
if (spellProto)
{
// From caster spells
- AuraEffectList const& mOwnerTaken = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_FROM_CASTER);
- for (AuraEffectList::const_iterator i = mOwnerTaken.begin(); i != mOwnerTaken.end(); ++i)
- if ((*i)->GetCasterGUID() == attacker->GetGUID() && (*i)->IsAffectedOnSpell(spellProto))
- AddPct(TakenTotalMod, (*i)->GetAmount());
+ TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_FROM_CASTER, [attacker, spellProto](AuraEffect const* aurEff)
+ {
+ return attacker->GetGUID() == aurEff->GetCasterGUID() && aurEff->IsAffectedOnSpell(spellProto);
+ });
// Mod damage from spell mechanic
uint32 mechanicMask = spellProto->GetAllEffectsMechanicMask();
@@ -13394,10 +13465,12 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT
if (mechanicMask)
{
- AuraEffectList const& mDamageDoneMechanic = GetAuraEffectsByType(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT);
- for (AuraEffectList::const_iterator i = mDamageDoneMechanic.begin(); i != mDamageDoneMechanic.end(); ++i)
- if (mechanicMask & uint32(1 << ((*i)->GetMiscValue())))
- AddPct(TakenTotalMod, (*i)->GetAmount());
+ TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, [mechanicMask](AuraEffect const* aurEff) -> bool
+ {
+ if (mechanicMask & uint32(1 << (aurEff->GetMiscValue())))
+ return true;
+ return false;
+ });
}
}
@@ -13414,15 +13487,11 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT
if (attType != RANGED_ATTACK)
{
- AuraEffectList const& mModMeleeDamageTakenPercent = GetAuraEffectsByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT);
- for (AuraEffectList::const_iterator i = mModMeleeDamageTakenPercent.begin(); i != mModMeleeDamageTakenPercent.end(); ++i)
- AddPct(TakenTotalMod, (*i)->GetAmount());
+ TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT);
}
else
{
- AuraEffectList const& mModRangedDamageTakenPercent = GetAuraEffectsByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT);
- for (AuraEffectList::const_iterator i = mModRangedDamageTakenPercent.begin(); i != mModRangedDamageTakenPercent.end(); ++i)
- AddPct(TakenTotalMod, (*i)->GetAmount());
+ TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT);
}
// No positive taken bonus, custom attr
@@ -14021,7 +14090,22 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
if (repThisToTarget > REP_NEUTRAL
|| (repTargetToThis = target->GetReactionTo(this)) > REP_NEUTRAL)
- return false;
+ {
+ // contested guards can attack contested PvP players even though players may be friendly
+ if (!target->IsControlledByPlayer())
+ return false;
+
+ bool isContestedGuard = false;
+ if (FactionTemplateEntry const* entry = GetFactionTemplateEntry())
+ isContestedGuard = entry->factionFlags & FACTION_TEMPLATE_FLAG_ATTACK_PVP_ACTIVE_PLAYERS;
+
+ bool isContestedPvp = false;
+ if (Player const* player = target->GetCharmerOrOwnerPlayerOrPlayerItself())
+ isContestedPvp = player->HasPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP);
+
+ if (!isContestedGuard && !isContestedPvp)
+ return false;
+ }
// Not all neutral creatures can be attacked (even some unfriendly faction does not react aggresive to you, like Sporaggar)
if (repThisToTarget == REP_NEUTRAL &&
@@ -14272,15 +14356,6 @@ int32 Unit::ModifyPower(Powers power, int32 dVal, bool withPowerUpdate /*= true*
return gain;
}
-// returns negative amount on power reduction
-int32 Unit::ModifyPowerPct(Powers power, float pct, bool apply)
-{
- float amount = (float)GetMaxPower(power);
- ApplyPercentModFloatVar(amount, pct, apply);
-
- return ModifyPower(power, (int32)amount - (int32)GetMaxPower(power));
-}
-
bool Unit::IsAlwaysVisibleFor(WorldObject const* seer) const
{
if (WorldObject::IsAlwaysVisibleFor(seer))
@@ -15230,30 +15305,100 @@ uint32 Unit::GetCreatureType() const
######## ########
#######################################*/
-bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, float amount, bool apply)
+bool Unit::HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply)
{
- if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END)
+ if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_FLAT_END)
{
LOG_ERROR("entities.unit", "ERROR in HandleStatModifier(): non-existing UnitMods or wrong UnitModifierType!");
return false;
}
+ if (!amount)
+ return false;
+
switch (modifierType)
{
case BASE_VALUE:
case TOTAL_VALUE:
- m_auraModifiersGroup[unitMod][modifierType] += apply ? amount : -amount;
+ m_auraFlatModifiersGroup[unitMod][modifierType] += apply ? amount : -amount;
break;
+ default:
+ break;
+ }
+
+ UpdateUnitMod(unitMod);
+ return true;
+}
+
+// Usage outside of AuraEffect Handlers is discouraged as the value will be lost when auras change. Use an Aura instead.
+void Unit::ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float pct)
+{
+ if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_PCT_END)
+ {
+ LOG_ERROR("entities.unit", "ERROR in ApplyStatPctModifier(): non-existing UnitMods or wrong UnitModifierType!");
+ return;
+ }
+
+ if (!pct)
+ return;
+
+ switch (modifierType)
+ {
case BASE_PCT:
case TOTAL_PCT:
- ApplyPercentModFloatVar(m_auraModifiersGroup[unitMod][modifierType], amount, apply);
+ AddPct(m_auraPctModifiersGroup[unitMod][modifierType], pct);
break;
default:
break;
}
- if (!CanModifyStats())
- return false;
+ UpdateUnitMod(unitMod);
+}
+
+void Unit::SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val)
+{
+ if (m_auraFlatModifiersGroup[unitMod][modifierType] == val)
+ return;
+
+ m_auraFlatModifiersGroup[unitMod][modifierType] = val;
+ UpdateUnitMod(unitMod);
+}
+
+void Unit::SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val)
+{
+ if (m_auraPctModifiersGroup[unitMod][modifierType] == val)
+ return;
+
+ m_auraPctModifiersGroup[unitMod][modifierType] = val;
+ UpdateUnitMod(unitMod);
+}
+
+float Unit::GetFlatModifierValue(UnitMods unitMod, UnitModifierFlatType modifierType) const
+{
+ if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_FLAT_END)
+ {
+ LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!");
+ return 0.0f;
+ }
+
+ return m_auraFlatModifiersGroup[unitMod][modifierType];
+}
+
+float Unit::GetPctModifierValue(UnitMods unitMod, UnitModifierPctType modifierType) const
+{
+ if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_PCT_END)
+ {
+ LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!");
+ return 0.0f;
+ }
+
+ return m_auraPctModifiersGroup[unitMod][modifierType];
+}
+
+void Unit::UpdateUnitMod(UnitMods unitMod)
+{
+ if (!CanModifyStats())
+ return;
switch (unitMod)
{
@@ -15311,36 +15456,100 @@ bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, f
default:
break;
}
+}
- return true;
+void Unit::UpdateDamageDoneMods(WeaponAttackType attackType, int32 /*skipEnchantSlot = -1*/)
+{
+ UnitMods unitMod;
+ switch (attackType)
+ {
+ case BASE_ATTACK:
+ unitMod = UNIT_MOD_DAMAGE_MAINHAND;
+ break;
+ case OFF_ATTACK:
+ unitMod = UNIT_MOD_DAMAGE_OFFHAND;
+ break;
+ case RANGED_ATTACK:
+ unitMod = UNIT_MOD_DAMAGE_RANGED;
+ break;
+ default:
+ ABORT();
+ break;
+ }
+
+ float amount = GetTotalAuraModifier(SPELL_AURA_MOD_DAMAGE_DONE, [&](AuraEffect const* aurEff) -> bool
+ {
+ if (!(aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
+ return false;
+
+ return CheckAttackFitToAuraRequirement(attackType, aurEff);
+ });
+
+ SetStatFlatModifier(unitMod, TOTAL_VALUE, amount);
+}
+
+void Unit::UpdateAllDamageDoneMods()
+{
+ for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i)
+ UpdateDamageDoneMods(WeaponAttackType(i));
}
-float Unit::GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) const
+void Unit::UpdateDamagePctDoneMods(WeaponAttackType attackType)
{
- if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END)
+ float factor;
+ UnitMods unitMod;
+ switch (attackType)
{
- LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!");
- return 0.0f;
+ case BASE_ATTACK:
+ factor = 1.0f;
+ unitMod = UNIT_MOD_DAMAGE_MAINHAND;
+ break;
+ case OFF_ATTACK:
+ // off hand has 50% penalty
+ factor = 0.5f;
+ unitMod = UNIT_MOD_DAMAGE_OFFHAND;
+ break;
+ case RANGED_ATTACK:
+ factor = 1.0f;
+ unitMod = UNIT_MOD_DAMAGE_RANGED;
+ break;
+ default:
+ ABORT();
+ break;
}
- if (modifierType == TOTAL_PCT && m_auraModifiersGroup[unitMod][modifierType] <= 0.0f)
- return 0.0f;
+ factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, [attackType, this](AuraEffect const* aurEff) -> bool
+ {
+ if (!(aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
+ return false;
+
+ return CheckAttackFitToAuraRequirement(attackType, aurEff);
+ });
+
+ if (attackType == OFF_ATTACK)
+ factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT, std::bind(&Unit::CheckAttackFitToAuraRequirement, this, attackType, std::placeholders::_1));
- return m_auraModifiersGroup[unitMod][modifierType];
+ SetStatPctModifier(unitMod, TOTAL_PCT, factor);
+}
+
+void Unit::UpdateAllDamagePctDoneMods()
+{
+ for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i)
+ UpdateDamagePctDoneMods(WeaponAttackType(i));
}
float Unit::GetTotalStatValue(Stats stat, float additionalValue) const
{
UnitMods unitMod = UnitMods(static_cast<uint16>(UNIT_MOD_STAT_START) + stat);
- if (m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f)
+ if (GetPctModifierValue(unitMod, TOTAL_PCT) <= 0.0f)
return 0.0f;
// value = ((base_value * base_pct) + total_value) * total_pct
- float value = m_auraModifiersGroup[unitMod][BASE_VALUE] + GetCreateStat(stat);
- value *= m_auraModifiersGroup[unitMod][BASE_PCT];
- value += m_auraModifiersGroup[unitMod][TOTAL_VALUE] + additionalValue;
- value *= m_auraModifiersGroup[unitMod][TOTAL_PCT];
+ float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreateStat(stat);
+ value *= GetPctModifierValue(unitMod, BASE_PCT);
+ value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + additionalValue;
+ value *= GetPctModifierValue(unitMod, TOTAL_PCT);
return value;
}
@@ -15353,25 +15562,16 @@ float Unit::GetTotalAuraModValue(UnitMods unitMod) const
return 0.0f;
}
- if (m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f)
+ if (GetPctModifierValue(unitMod, TOTAL_PCT) <= 0.0f)
return 0.0f;
- float value = m_auraModifiersGroup[unitMod][BASE_VALUE];
- value *= m_auraModifiersGroup[unitMod][BASE_PCT];
- value += m_auraModifiersGroup[unitMod][TOTAL_VALUE];
- value *= m_auraModifiersGroup[unitMod][TOTAL_PCT];
-
+ float value = GetFlatModifierValue(unitMod, BASE_VALUE);
+ value *= GetPctModifierValue(unitMod, BASE_PCT);
+ value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
+ value *= GetPctModifierValue(unitMod, TOTAL_PCT);
return value;
}
-void Unit::ApplyStatPercentBuffMod(Stats stat, float val, bool apply)
-{
- if (val == -100.0f) // prevent set var to zero
- val = -99.99f;
- float var = GetStat(stat) * val / 100.0f;
- ApplyModSignedFloatValue((var > 0 ? static_cast<uint16>(UNIT_FIELD_POSSTAT0) + stat : static_cast<uint16>(UNIT_FIELD_NEGSTAT0) + stat), var, apply);
-}
-
SpellSchools Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod) const
{
SpellSchools school = SPELL_SCHOOL_NORMAL;
@@ -17078,28 +17278,40 @@ Unit* Unit::SelectNearbyNoTotemTarget(Unit* exclude, float dist) const
return Acore::Containers::SelectRandomContainerElement(targets);
}
+void ApplyPercentModFloatVar(float& var, float val, bool apply)
+{
+ var *= (apply ? (100.0f + val) / 100.0f : 100.0f / (100.0f + val));
+}
+
void Unit::ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply)
{
+ float amount = GetFloatValue(UNIT_FIELD_BASEATTACKTIME + AsUnderlyingType(att));
+
float remainingTimePct = std::max((float)m_attackTimer[att], 0.0f) / (GetAttackTime(att) * m_modAttackSpeedPct[att]);
- if (val > 0)
+ if (val > 0.f)
{
ApplyPercentModFloatVar(m_modAttackSpeedPct[att], val, !apply);
- ApplyPercentModFloatValue(static_cast<uint16>(UNIT_FIELD_BASEATTACKTIME) + att, val, !apply);
+ ApplyPercentModFloatVar(amount, val, !apply);
}
else
{
ApplyPercentModFloatVar(m_modAttackSpeedPct[att], -val, apply);
- ApplyPercentModFloatValue(static_cast<uint16>(UNIT_FIELD_BASEATTACKTIME) + att, -val, apply);
+ ApplyPercentModFloatVar(amount, -val, apply);
}
+ SetFloatValue(UNIT_FIELD_BASEATTACKTIME + AsUnderlyingType(att), amount);
m_attackTimer[att] = uint32(GetAttackTime(att) * m_modAttackSpeedPct[att] * remainingTimePct);
}
void Unit::ApplyCastTimePercentMod(float val, bool apply)
{
- if (val > 0)
- ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED, val, !apply);
+ float amount = GetFloatValue(UNIT_MOD_CAST_SPEED);
+
+ if (val > 0.f)
+ ApplyPercentModFloatVar(amount, val, !apply);
else
- ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED, -val, apply);
+ ApplyPercentModFloatVar(amount, -val, apply);
+
+ SetFloatValue(UNIT_MOD_CAST_SPEED, amount);
}
uint32 Unit::GetCastingTimeForBonus(SpellInfo const* spellProto, DamageEffectType damagetype, uint32 CastingTime) const
@@ -18388,7 +18600,7 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
}
// dismount players when charmed
- if (IsPlayer())
+ if (IsPlayer() && type != CHARM_TYPE_POSSESS)
RemoveAurasByType(SPELL_AURA_MOUNTED);
if (charmer->IsPlayer())
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index c335f7e0ed..934bb1c70c 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -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
@@ -214,7 +219,7 @@ enum WeaponAttackType : uint8
MAX_ATTACK
};
-enum CombatRating
+enum CombatRating : uint8
{
CR_WEAPON_SKILL = 0,
CR_DEFENSE_SKILL = 1,
@@ -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;
diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp
index aef8767541..9fc5643d0a 100644
--- a/src/server/game/Handlers/ItemHandler.cpp
+++ b/src/server/game/Handlers/ItemHandler.cpp
@@ -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);
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index a878194589..fb40ce36ac 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -299,6 +299,8 @@ void WorldSession::HandleMoveTeleportAck(WorldPacket& recvData)
plMover->UpdatePosition(dest, true);
+ plMover->SetFallInformation(GameTime::GetGameTime().count(), dest.GetPositionZ());
+
// xinef: teleport pets if they are not unsummoned
if (Pet* pet = plMover->GetPet())
{
diff --git a/src/server/game/Scripting/ScriptDefines/AllSpellScript.cpp b/src/server/game/Scripting/ScriptDefines/AllSpellScript.cpp
index 3f15648935..d47939fe0b 100644
--- a/src/server/game/Scripting/ScriptDefines/AllSpellScript.cpp
+++ b/src/server/game/Scripting/ScriptDefines/AllSpellScript.cpp
@@ -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));
diff --git a/src/server/game/Scripting/ScriptDefines/AllSpellScript.h b/src/server/game/Scripting/ScriptDefines/AllSpellScript.h
index 7536f8cf5b..df069bcb11 100644
--- a/src/server/game/Scripting/ScriptDefines/AllSpellScript.h
+++ b/src/server/game/Scripting/ScriptDefines/AllSpellScript.h
@@ -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; }
diff --git a/src/server/game/Scripting/ScriptDefines/UnitScript.cpp b/src/server/game/Scripting/ScriptDefines/UnitScript.cpp
index 2975ec4f1a..c36cfcd25a 100644
--- a/src/server/game/Scripting/ScriptDefines/UnitScript.cpp
+++ b/src/server/game/Scripting/ScriptDefines/UnitScript.cpp
@@ -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));
diff --git a/src/server/game/Scripting/ScriptDefines/UnitScript.h b/src/server/game/Scripting/ScriptDefines/UnitScript.h
index 26c4e2b13d..046f9cc117 100644
--- a/src/server/game/Scripting/ScriptDefines/UnitScript.h
+++ b/src/server/game/Scripting/ScriptDefines/UnitScript.h
@@ -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; }
diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h
index 6a9a0914d3..5aa131f042 100644
--- a/src/server/game/Scripting/ScriptMgr.h
+++ b/src/server/game/Scripting/ScriptMgr.h
@@ -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);
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 06d3166e0a..7ffb4065f8 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -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();
@@ -727,9 +726,12 @@ void AuraEffect::ChangeAmount(int32 newAmount, bool mark, bool onStackOrReapply)
std::list<AuraApplication*> effectApplications;
GetApplicationList(effectApplications);
- for (std::list<AuraApplication*>::const_iterator apptItr = effectApplications.begin(); apptItr != effectApplications.end(); ++apptItr)
- if ((*apptItr)->HasEffect(GetEffIndex()))
- HandleEffect(*apptItr, handleMask, false);
+ for (AuraApplication* aurApp : effectApplications)
+ if (aurApp->HasEffect(GetEffIndex()))
+ {
+ aurApp->GetTarget()->_RegisterAuraEffect(this, false);
+ HandleEffect(aurApp, handleMask, false);
+ }
if (handleMask & AURA_EFFECT_HANDLE_CHANGE_AMOUNT)
{
@@ -740,9 +742,15 @@ void AuraEffect::ChangeAmount(int32 newAmount, bool mark, bool onStackOrReapply)
CalculateSpellMod();
}
- for (std::list<AuraApplication*>::const_iterator apptItr = effectApplications.begin(); apptItr != effectApplications.end(); ++apptItr)
- if ((*apptItr)->HasEffect(GetEffIndex()))
- HandleEffect(*apptItr, handleMask, true);
+ for (AuraApplication* aurApp : effectApplications)
+ if (aurApp->HasEffect(GetEffIndex()))
+ {
+ if (aurApp->GetRemoveMode() != AURA_REMOVE_NONE)
+ continue;
+
+ aurApp->GetTarget()->_RegisterAuraEffect(this, true);
+ HandleEffect(aurApp, handleMask, true);
+ }
}
void AuraEffect::HandleEffect(AuraApplication* aurApp, uint8 mode, bool apply)
@@ -3000,14 +3008,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 +3450,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 +4337,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 +4345,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 +4364,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 +4377,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 +4424,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 +4456,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 +4501,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 +4588,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 +4604,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 +4715,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 +4724,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 +4738,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 +4768,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 +4787,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 +4809,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 +4831,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 +4891,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 +4977,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 +5001,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 +5029,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 +5064,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);
}
@@ -5073,7 +5114,7 @@ void AuraEffect::HandleModRating(AuraApplication const* aurApp, uint8 mode, bool
if (!target->IsPlayer())
return;
- for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
+ for (uint8 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
if (GetMiscValue() & (1 << rating))
target->ToPlayer()->ApplyRatingMod(CombatRating(rating), GetAmount(), apply);
}
@@ -5089,7 +5130,7 @@ void AuraEffect::HandleModRatingFromStat(AuraApplication const* aurApp, uint8 mo
return;
// Just recalculate ratings
- for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
+ for (uint8 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
if (GetMiscValue() & (1 << rating))
target->ToPlayer()->ApplyRatingMod(CombatRating(rating), 0, apply);
}
@@ -5105,7 +5146,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 +5159,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 +5170,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 +5190,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,141 +5237,89 @@ void AuraEffect::HandleModDamageDone(AuraApplication const* aurApp, uint8 mode,
Unit* target = aurApp->GetTarget();
- // apply item specific bonuses for already equipped weapon
+ if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) != 0)
+ target->UpdateAllDamageDoneMods();
+
+ // Magic damage modifiers implemented in Unit::SpellBaseDamageBonus
+ // This information for client side use only
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);
- }
- // 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
+ 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 ((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
- }
+ if (Guardian* pet = target->ToPlayer()->GetGuardianPet())
+ pet->UpdateAttackPowerAndDamage();
}
+}
- // Skip non magic case for Speedup
- if ((GetMiscValue() & SPELL_SCHOOL_MASK_MAGIC) == 0)
+void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
+{
+ if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
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
+ Unit* target = aurApp->GetTarget();
+ if (!target)
return;
- }
- // Magic damage modifiers implemented in Unit::SpellDamageBonus
- // This information for client side use only
+ if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
+ target->UpdateAllDamagePctDoneMods();
+
if (target->IsPlayer())
{
- if (GetAmount() > 0)
+ for (uint8 i = 0; i < MAX_SPELL_SCHOOL; ++i)
{
- for (uint32 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
+ if (GetMiscValue() & (1 << i))
{
- if ((GetMiscValue() & (1 << i)) != 0)
- target->ApplyModInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + i, GetAmount(), apply);
+ // 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);
}
}
- 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);
- }
- }
- if (Guardian* pet = target->ToPlayer()->GetGuardianPet())
- pet->UpdateAttackPowerAndDamage();
}
}
-void AuraEffect::HandleModDamagePercentDone(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();
- if (!target)
- return;
-
- if (!sScriptMgr->CanModAuraEffectModDamagePercentDone(this, target, aurApp, mode, apply))
- return;
- 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
- }
+ // also handles spell group stacks
+ target->UpdateDamagePctDoneMods(OFF_ATTACK);
}
-void AuraEffect::HandleModOffhandDamagePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const
+void AuraEffect::HandleShieldBlockValue(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)
+ return;
- target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetAmount()), apply);
+ target->HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, float(GetAmount()), apply);
}
-void AuraEffect::HandleShieldBlockValue(AuraApplication const* aurApp, uint8 mode, bool apply) const
+void AuraEffect::HandleShieldBlockValuePercent(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();
-
- BaseModType modType = FLAT_MOD;
- if (GetAuraType() == SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT)
- modType = PCT_MOD;
+ Player* target = aurApp->GetTarget()->ToPlayer();
+ if (!target)
+ return;
- if (target->IsPlayer())
- target->ToPlayer()->HandleBaseModValue(SHIELD_BLOCK_VALUE, modType, float(GetAmount()), apply);
+ 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);
+ }
}
/********************************/
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h
index 73640626bc..8349c83fc2 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.h
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.h
@@ -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;
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 7d6260e24e..0b3b35d59e 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -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)
diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h
index 7b7ab603ec..8731299f8b 100644
--- a/src/server/game/Spells/Auras/SpellAuras.h
+++ b/src/server/game/Spells/Auras/SpellAuras.h
@@ -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
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 24f1c1ad68..608b9614b8 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -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)
@@ -6609,8 +6607,13 @@ SpellCastResult Spell::CheckCast(bool strict)
if (target->IsCreature() && target->ToCreature()->IsVehicle())
return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
+ // Allow SPELL_AURA_MOD_POSSESS to work on mounted players,
+ // but keep the old restriction for everything else.
if (target->IsMounted())
- return SPELL_FAILED_CANT_BE_CHARMED;
+ {
+ if (!(target->IsPlayer() && m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_POSSESS))
+ return SPELL_FAILED_CANT_BE_CHARMED;
+ }
if (target->GetCharmerGUID())
return SPELL_FAILED_CHARMED;
@@ -6718,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)
@@ -6968,27 +6978,36 @@ 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 (GetSpellInfo()->Id == (*auraIt)->GetSpellInfo()->Id)
+ return false;
+
+ switch (sSpellMgr->CheckSpellGroupStackRules(GetSpellInfo(), (*auraIt)->GetSpellInfo()))
{
- if (target->HasAuraEffect(m_spellInfo->Id, j))
+ case SPELL_GROUP_STACK_RULE_EXCLUSIVE:
return false;
- }
- else
- {
- if (AuraEffect* aureff = target->GetAuraEffect(m_spellInfo->Id, j))
- if (aureff->GetBase()->GetStackAmount() >= m_spellInfo->StackAmount)
+ 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;
}
}
- else if (m_spellInfo->Effects[j].IsAreaAuraEffect())
- {
- if (target->HasAuraEffect(m_spellInfo->Id, j))
- return false;
- }
}
SpellCastResult result = CheckPetCast(target);
@@ -7905,7 +7924,7 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff) const
case SPELL_AURA_AOE_CHARM:
if (target->IsCreature() && target->IsVehicle())
return false;
- if (target->IsMounted())
+ if (target->IsMounted() && m_spellInfo->Effects[eff].ApplyAuraName != SPELL_AURA_MOD_POSSESS)
return false;
if (target->GetCharmerGUID())
return false;
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 3343c70595..d725b682ec 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -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);
}
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 2a54900431..74b89e99bd 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -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;
-}
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index eba1ad9013..50b6d88d40 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -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]; }
diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp
index d3322349b4..0615f39c00 100644
--- a/src/server/game/Spells/SpellInfoCorrections.cpp
+++ b/src/server/game/Spells/SpellInfoCorrections.cpp
@@ -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
@@ -5170,6 +5162,14 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->ProcCharges = 1;
});
+ ApplySpellFix({
+ 56917, // To Icecrown Airship - Teleport to Airship (A)
+ 57417, // To Icecrown Airship - Teleport to Airship (H)
+ }, [](SpellInfo* spellInfo)
+ {
+ spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(6); // 100 yards
+ });
+
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
{
SpellInfo* spellInfo = mSpellInfoMap[i];
@@ -5291,14 +5291,6 @@ void SpellMgr::LoadSpellInfoCorrections()
factionTemplateEntry = const_cast<FactionTemplateEntry*>(sFactionTemplateStore.LookupEntry(1921)); // The Taunka
factionTemplateEntry->hostileMask |= 8;
- // Remove 1 from guards friendly mask, making able to attack players
- factionTemplateEntry = const_cast<FactionTemplateEntry*>(sFactionTemplateStore.LookupEntry(1857)); // Area 52 Bruiser
- factionTemplateEntry->friendlyMask &= ~1;
- factionTemplateEntry = const_cast<FactionTemplateEntry*>(sFactionTemplateStore.LookupEntry(1806)); // Netherstorm Agent
- factionTemplateEntry->friendlyMask &= ~1;
- factionTemplateEntry = const_cast<FactionTemplateEntry*>(sFactionTemplateStore.LookupEntry(1812)); // K3 Bruiser
- factionTemplateEntry->friendlyMask &= ~1;
-
// Remove vehicles attr, making accessories selectable
VehicleSeatEntry* vse = const_cast<VehicleSeatEntry*>(sVehicleSeatStore.LookupEntry(4689)); // Siege Engine, Accessory
vse->m_flags &= ~VEHICLE_SEAT_FLAG_PASSENGER_NOT_SELECTABLE;
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index f424be399a..ba297d4588 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -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())
- return itr->second;
-
- return SPELL_GROUP_STACK_FLAG_NONE;
+ spell_id = GetFirstSpellInChain(spell_id);
+ return mSpellSpellGroup.equal_range(spell_id);
}
-uint32 SpellMgr::GetSpellGroup(uint32 spell_id) const
+bool SpellMgr::IsSpellMemberOfSpellGroup(uint32 spell_id, SpellGroup group_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;
+ 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;
}
-SpellGroupSpecialFlags SpellMgr::GetSpellGroupSpecialFlags(uint32 spell_id) const
+SpellGroupSpellMapBounds SpellMgr::GetSpellGroupSpellMapBounds(SpellGroup group_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;
+ return mSpellGroupSpell.equal_range(group_id);
}
-SpellGroupStackFlags SpellMgr::CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2, bool remove, bool areaAura) const
+void SpellMgr::GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells) const
{
- uint32 spellid_1 = spellInfo1->GetFirstRankSpell()->Id;
- uint32 spellid_2 = spellInfo2->GetFirstRankSpell()->Id;
-
- uint32 groupId = GetSpellGroup(spellid_1);
+ std::set<SpellGroup> usedGroups;
+ GetSetOfSpellsInSpellGroup(group_id, foundSpells, usedGroups);
+}
- SpellGroupSpecialFlags flag1 = GetSpellGroupSpecialFlags(spellid_1);
+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);
- // xinef: dunno why i added this
- if (spellid_1 == spellid_2 && remove && !areaAura)
+ SpellGroupSpellMapBounds groupSpell = GetSpellGroupSpellMapBounds(group_id);
+ for (SpellGroupSpellMap::const_iterator itr = groupSpell.first; itr != groupSpell.second; ++itr)
{
- if (flag1 & SPELL_GROUP_SPECIAL_FLAG_SAME_SPELL_CHECK)
+ if (itr->second < 0)
{
- return SPELL_GROUP_STACK_FLAG_EXCLUSIVE;
+ SpellGroup currGroup = (SpellGroup)abs(itr->second);
+ GetSetOfSpellsInSpellGroup(currGroup, foundSpells, usedGroups);
+ }
+ else
+ {
+ foundSpells.insert(itr->second);
}
-
- return SPELL_GROUP_STACK_FLAG_NONE;
}
+}
- if (groupId > 0 && groupId == GetSpellGroup(spellid_2))
+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)
{
- 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)
+ SpellGroup group = itr->second;
+ auto found = mSpellSameEffectStack.find(group);
+ if (found != mSpellSameEffectStack.end())
{
- if (flag1 & flag2)
- return SPELL_GROUP_STACK_FLAG_NEVER_STACK;
+ // 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;
}
- // 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;
+ }
+ // 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);
- return SpellGroupStackFlags(GetGroupStackFlags(groupId) | additionFlag);
+ 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);
+ }
}
- return SPELL_GROUP_STACK_FLAG_NONE;
+ 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;
}
-void SpellMgr::GetSetOfSpellsInSpellGroupWithFlag(uint32 group_id, SpellGroupSpecialFlags flag, std::set<uint32>& availableElixirs) const
+SpellGroupStackRule SpellMgr::GetSpellGroupStackRule(SpellGroup group) 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
+ SpellGroupStackMap::const_iterator itr = mSpellGroupStack.find(group);
+ if (itr != mSpellGroupStack.end())
+ return itr->second;
+
+ 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>();
+
+ groups.insert(group_id);
+ mSpellGroupSpell.emplace(SpellGroup(group_id), spell_id);
+
+ } while (result->NextRow());
- if (mSpellGroupMap.find(spell_id) != mSpellGroupMap.end())
+ for (auto itr = mSpellGroupSpell.begin(); itr!= mSpellGroupSpell.end();)
+ {
+ if (itr->second < 0)
{
- LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` has more than one group", spell_id);
- continue;
+ 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;
}
-
- if (specialFlag >= SPELL_GROUP_SPECIAL_FLAG_MAX)
+ else
{
- LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` has invalid special flag!", spell_id);
- continue;
+ 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;
}
+ }
- SpellStackInfo ssi;
- ssi.groupId = group_id;
- ssi.specialFlags = specialFlag;
- mSpellGroupMap[spell_id] = ssi;
+ for (auto groupItr = groups.begin(); groupItr != groups.end(); ++groupItr)
+ {
+ std::set<uint32> spells;
+ GetSetOfSpellsInSpellGroup(SpellGroup(*groupItr), spells);
- ++count;
- } while (result->NextRow());
+ 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", ">> 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;
}
}
}
diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h
index feb1e4f7ec..30220e1516 100644
--- a/src/server/game/Spells/SpellMgr.h
+++ b/src/server/game/Spells/SpellMgr.h
@@ -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,
-
- // Internal use
- SPELL_GROUP_STACK_FLAG_FORCED_STRONGEST = 0x100,
- SPELL_GROUP_STACK_FLAG_FORCED_WEAKEST = 0x200,
-};
+ template<>
+ struct hash<SpellGroup>
+ {
+ size_t operator()(SpellGroup const& group) const
+ {
+ return hash<uint32>()(uint32(group));
+ }
+ };
+}
-enum SpellGroupIDs
-{
- SPELL_GROUP_GUARDIAN_AND_BATTLE_ELIXIRS = 1
-};
+#define SPELL_GROUP_DB_RANGE_MIN 1000
-struct SpellStackInfo
+// 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
{
- uint32 groupId;
- SpellGroupSpecialFlags specialFlags;
+ 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
};
-// spell_id, group_id
-typedef std::map<uint32, SpellStackInfo> SpellGroupMap;
-typedef std::map<uint32, SpellGroupStackFlags> SpellGroupStackMap;
+
+typedef std::unordered_map<SpellGroup, SpellGroupStackRule> 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;
diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_arlokk.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_arlokk.cpp
index 584e05f6f2..83275a1793 100644
--- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_arlokk.cpp
+++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_arlokk.cpp
@@ -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);
diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_marli.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_marli.cpp
index d453d5e2f7..b350b680e5 100644
--- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_marli.cpp
+++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_marli.cpp
@@ -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)
{
diff --git a/src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_jedoga_shadowseeker.cpp b/src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_jedoga_shadowseeker.cpp
index 6392a738ed..d780776064 100644
--- a/src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_jedoga_shadowseeker.cpp
+++ b/src/server/scripts/Northrend/AzjolNerub/ahnkahet/boss_jedoga_shadowseeker.cpp
@@ -16,7 +16,6 @@
*/
#include "AchievementCriteriaScript.h"
-#include "Containers.h"
#include "CreatureScript.h"
#include "ObjectAccessor.h"
#include "ScriptedCreature.h"
@@ -209,7 +208,7 @@ struct boss_jedoga_shadowseeker : public BossAI
}
}
- sacraficeTarget_GUID.Clear();
+ sacrificeTargetGUID.Clear();
sayPreachTimer = 120000;
ritualTriggered = false;
volunteerWork = true;
@@ -268,12 +267,12 @@ struct boss_jedoga_shadowseeker : public BossAI
}
case NPC_TWILIGHT_VOLUNTEER:
{
- if (sacraficeTarget_GUID && summon->GetGUID() != sacraficeTarget_GUID)
+ if (sacrificeTargetGUID && summon->GetGUID() != sacrificeTargetGUID)
{
break;
}
- if (killer != me && killer->GetGUID() != sacraficeTarget_GUID)
+ if (killer != me && killer->GetGUID() != sacrificeTargetGUID)
{
volunteerWork = false;
}
@@ -315,7 +314,7 @@ struct boss_jedoga_shadowseeker : public BossAI
{
if (action == ACTION_SACRAFICE)
{
- if (Creature* target = ObjectAccessor::GetCreature(*me, sacraficeTarget_GUID))
+ if (Creature* target = ObjectAccessor::GetCreature(*me, sacrificeTargetGUID))
{
Unit::Kill(me, target);
}
@@ -395,9 +394,9 @@ struct boss_jedoga_shadowseeker : public BossAI
me->SetFacingTo(5.66f);
if (!summons.empty())
{
- sacraficeTarget_GUID = Acore::Containers::SelectRandomContainerElement(summons);
- if (ObjectAccessor::GetCreature(*me, sacraficeTarget_GUID))
+ if (Creature* creature = summons.GetRandomCreatureWithEntry(NPC_TWILIGHT_VOLUNTEER))
{
+ sacrificeTargetGUID = creature->GetGUID();
events.ScheduleEvent(EVENT_JEDGA_START_RITUAL, 3s, 0, PHASE_RITUAL);
}
// Something failed, let players continue but do not grant achievement
@@ -518,15 +517,16 @@ struct boss_jedoga_shadowseeker : public BossAI
}
case EVENT_JEDGA_START_RITUAL:
{
- sacraficeTarget_GUID = Acore::Containers::SelectRandomContainerElement(summons);
- if (Creature* volunteer = ObjectAccessor::GetCreature(*me, sacraficeTarget_GUID))
+ if (Creature* creature = summons.GetRandomCreatureWithEntry(NPC_TWILIGHT_VOLUNTEER))
{
+ sacrificeTargetGUID = creature->GetGUID();
Talk(SAY_SACRIFICE_1);
- sacraficeTarget_GUID = volunteer->GetGUID();
- volunteer->AI()->DoAction(ACTION_RITUAL_BEGIN);
+ creature->AI()->DoAction(ACTION_RITUAL_BEGIN);
}
break;
}
+ default:
+ break;
}
}
@@ -546,7 +546,7 @@ struct boss_jedoga_shadowseeker : public BossAI
private:
GuidList oocSummons;
GuidList oocTriggers;
- ObjectGuid sacraficeTarget_GUID;
+ ObjectGuid sacrificeTargetGUID;
uint32 sayPreachTimer;
bool combatSummonsSummoned;
bool ritualTriggered;
diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp
index 319fc1f83e..d27d43b388 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp
@@ -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();
diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp
index eb26cad02b..2ffe2f7dd5 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp
@@ -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;
diff --git a/src/server/scripts/Northrend/Gundrak/boss_eck.cpp b/src/server/scripts/Northrend/Gundrak/boss_eck.cpp
index 9e7a6bbc97..12f84b71f1 100644
--- a/src/server/scripts/Northrend/Gundrak/boss_eck.cpp
+++ b/src/server/scripts/Northrend/Gundrak/boss_eck.cpp
@@ -36,7 +36,8 @@ enum Misc
EVENT_ECK_BITE = 2,
EVENT_ECK_SPIT = 3,
EVENT_ECK_SPRING = 4,
- EVENT_ECK_HEALTH = 5
+ EVENT_ECK_CRAZED_EMOTE = 5,
+ EMOTE_CRAZED = 1
};
class boss_eck : public CreatureScript
@@ -89,7 +90,8 @@ public:
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
- events.ScheduleEvent(EVENT_ECK_BERSERK, 60s, 90s);
+ events.ScheduleEvent(EVENT_ECK_CRAZED_EMOTE, 76s, 78s);
+ events.ScheduleEvent(EVENT_ECK_BERSERK, 90s);
events.ScheduleEvent(EVENT_ECK_BITE, 5s);
events.ScheduleEvent(EVENT_ECK_SPIT, 10s, 37s);
events.ScheduleEvent(EVENT_ECK_SPRING, 10s, 24s);
@@ -111,18 +113,11 @@ public:
switch (events.ExecuteEvent())
{
- case EVENT_ECK_HEALTH:
- if (me->HealthBelowPct(21))
- {
- events.CancelEvent(EVENT_ECK_BERSERK);
- me->CastSpell(me, SPELL_ECK_BERSERK, false);
- break;
- }
- events.ScheduleEvent(EVENT_ECK_HEALTH, 1s);
+ case EVENT_ECK_CRAZED_EMOTE:
+ Talk(EMOTE_CRAZED);
break;
case EVENT_ECK_BERSERK:
me->CastSpell(me, SPELL_ECK_BERSERK, false);
- events.CancelEvent(EVENT_ECK_HEALTH);
break;
case EVENT_ECK_BITE:
me->CastSpell(me->GetVictim(), SPELL_ECK_BITE, false);
diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/brann_bronzebeard.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/brann_bronzebeard.cpp
index 54406752f9..933c006ce9 100644
--- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/brann_bronzebeard.cpp
+++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/brann_bronzebeard.cpp
@@ -664,7 +664,6 @@ public:
me->CastSpell(me, 59046, true); // credit
}
- me->ReplaceAllNpcFlags(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STAND);
me->SendMovementFlagUpdate();
@@ -871,6 +870,7 @@ void brann_bronzebeard::brann_bronzebeardAI::WaypointReached(uint32 id)
//Tribunal end, stand in the middle of the sky room
case 17:
SetEscortPaused(true);
+ me->ReplaceAllNpcFlags(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);
me->SetOrientation(3.91672f);
me->SendMovementFlagUpdate();
break;
diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp
index 09ee369913..1a7cb30300 100644
--- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp
+++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp
@@ -82,30 +82,33 @@ struct npc_dragonflayer_forge_master : public ScriptedAI
enum EnslavedProtoDrake
{
- TYPE_PROTODRAKE_AT = 28,
- DATA_PROTODRAKE_MOVE = 6,
-
- PATH_PROTODRAKE = 125946,
+ SPELL_REND = 43931,
+ SPELL_FLAME_BREATH = 50653,
+ SPELL_KNOCK_AWAY = 49722,
EVENT_REND = 1,
EVENT_FLAME_BREATH = 2,
EVENT_KNOCKAWAY = 3,
+ // Special
+ EVENT_PRE_LAND = 4,
+ EVENT_LAND = 5,
- SPELL_REND = 43931,
- SPELL_FLAME_BREATH = 50653,
- SPELL_KNOCK_AWAY = 49722,
-
- POINT_LAST = 6,
+ // Special
+ TYPE_PROTODRAKE_AT = 28,
+ DATA_PROTODRAKE_MOVE = 6,
+ POINT_TAKE_OFF = 1,
+ POINT_PRE_LAND = 2,
+ POINT_LAND = 3,
};
-const Position protodrakeCheckPos = {206.24f, -190.28f, 200.11f, 0.f};
+const Position protodrakeCheckPos{206.24f, -190.28f, 200.11f, 0.f};
+const Position protodrakeTakeOffPos{209.1206f, -187.86578f, 215.00346f};
+const Position protodrakePreLandPos{230.80234f, -164.99632f, 196.74878f};
+const Position protodrakeLandPos{241.2079f, -163.06265f, 193.47125f};
struct npc_enslaved_proto_drake : public ScriptedAI
{
- npc_enslaved_proto_drake(Creature* creature) : ScriptedAI(creature)
- {
- _setData = false;
- }
+ explicit npc_enslaved_proto_drake(Creature* creature) : ScriptedAI(creature) { }
void Reset() override
{
@@ -113,22 +116,35 @@ struct npc_enslaved_proto_drake : public ScriptedAI
_events.ScheduleEvent(EVENT_REND, 2s, 3s);
_events.ScheduleEvent(EVENT_FLAME_BREATH, 5500ms, 7s);
_events.ScheduleEvent(EVENT_KNOCKAWAY, 3500ms, 6s);
+ scheduler.CancelAll();
}
void MovementInform(uint32 type, uint32 id) override
{
- if (type == WAYPOINT_MOTION_TYPE && id == POINT_LAST)
+ if (type == EFFECT_MOTION_TYPE && id == POINT_TAKE_OFF)
{
+ ScheduleUniqueTimedEvent(500ms, [&]
+ {
+ me->GetMotionMaster()->MovePoint(POINT_PRE_LAND, protodrakePreLandPos);
+ }, EVENT_PRE_LAND);
+ }
+
+ if (type == POINT_MOTION_TYPE && id == POINT_PRE_LAND)
+ {
+ ScheduleUniqueTimedEvent(0s, [&]
+ {
+ me->GetMotionMaster()->MovePoint(POINT_LAND, protodrakeLandPos);
+ }, EVENT_LAND);
+ }
+
+ if (type == POINT_MOTION_TYPE && id == POINT_LAND)
+ {
+ me->SetFacingTo(0.25f);
me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0.25f);
if (Vehicle* v = me->GetVehicleKit())
if (Unit* p = v->GetPassenger(0))
if (Creature* rider = p->ToCreature())
rider->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0.25f);
-
- me->SetCanFly(false);
- me->SetDisableGravity(false);
- me->SetFacingTo(0.25f);
- me->SetImmuneToAll(false);
}
}
@@ -137,14 +153,14 @@ struct npc_enslaved_proto_drake : public ScriptedAI
if (type == TYPE_PROTODRAKE_AT && data == DATA_PROTODRAKE_MOVE && !_setData && me->IsAlive() && me->GetDistance(protodrakeCheckPos) < 10.0f)
{
_setData = true;
- me->SetCanFly(true);
- me->SetDisableGravity(true);
- me->GetMotionMaster()->MoveWaypoint(PATH_PROTODRAKE, false);
+ me->GetMotionMaster()->MoveTakeoff(POINT_TAKE_OFF, protodrakeTakeOffPos, 8.0f);
}
}
void UpdateAI(uint32 diff) override
{
+ scheduler.Update(diff);
+
if (!UpdateVictim())
return;
@@ -178,7 +194,7 @@ struct npc_enslaved_proto_drake : public ScriptedAI
}
private:
- bool _setData;
+ bool _setData{false};
EventMap _events;
};
diff --git a/src/server/scripts/Northrend/zone_crystalsong_forest.cpp b/src/server/scripts/Northrend/zone_crystalsong_forest.cpp
index bdf394cad9..645d3c0224 100644
--- a/src/server/scripts/Northrend/zone_crystalsong_forest.cpp
+++ b/src/server/scripts/Northrend/zone_crystalsong_forest.cpp
@@ -15,52 +15,100 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "CombatAI.h"
#include "CreatureScript.h"
-#include "PassiveAI.h"
#include "Player.h"
#include "ScriptedCreature.h"
-#include "SmartScriptMgr.h"
+#include "SpellAuras.h"
+#include "SpellScript.h"
#include "Transport.h"
#include "Vehicle.h"
enum ePreparationsForWar
{
- NPC_HAMMERHEAD = 30585,
- NPC_CLOUDBUSTER = 30470,
- TRANSPORT_ORGRIMS_HAMMER = 192241,
- TRANSPORT_THE_SKYBREAKER = 192242
+ NPC_CLOUDBUSTER = 30470,
+ NPC_HAMMERHEAD = 30585,
+ TRANSPORT_ORGRIMS_HAMMER = 192241,
+ TRANSPORT_THE_SKYBREAKER = 192242,
+ SEAT_PLAYER = 0,
+ SPELL_FLIGHT = 48602,
+ SPELL_TO_ICECROWN_PLAYER_AURA_DISMOUNT_A = 56904,
+ SPELL_TO_ICECROWN_PLAYER_AURA_DISMOUNT_H = 57419,
+ SPELL_TO_ICECROWN_AIRSHIP_PLAYER_AURA_TELEPORT_TO_DALARAN = 57460,
+ SPELL_TO_ICECROWN_AIRSHIP_FROST_WYRM_WAITING_TO_SUMMON_AURA = 57498,
+ POINT_END = 16,
+ SPELL_TO_ICECROWN_AIRSHIP_AURA_DISMOUNT_RESPONSE = 56921, // unhandled - vehicle casts 50630 on self
+ SPELL_EJECT_ALL_PASSENGERS = 50630,
+ SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_A_FORCE_PLAYER_TO_CAST = 57554,
+ SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_H_FORCE_PLAYER_TO_CAST = 57556,
+ SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_A = 56917,
+ SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_H = 57417,
};
-struct npc_preparations_for_war_vehicle : public NullCreatureAI
+struct npc_preparations_for_war_vehicle : public VehicleAI
{
- npc_preparations_for_war_vehicle(Creature* creature) : NullCreatureAI(creature) { }
-
- uint8 pointId;
- uint32 searchForShipTimer;
- uint32 transportEntry;
+ explicit npc_preparations_for_war_vehicle(Creature* creature) : VehicleAI(creature), searchForShipTimer(0), transportEntry(me->GetEntry() == NPC_CLOUDBUSTER ? TRANSPORT_THE_SKYBREAKER : TRANSPORT_ORGRIMS_HAMMER)
+ {
+ if (transportEntry == TRANSPORT_THE_SKYBREAKER)
+ {
+ // 30476 - [DND] Icecrown Flight To Airship Bunny (A)
+ passenger_x = 31.41805;
+ passenger_y = 0.126893;
+ passenger_z = 41.69821;
+ }
+ else // TRANSPORT_ORGRIMS_HAMMER
+ {
+ // 30588 - [DND] Icecrown Flight To Airship Bunny (H)
+ passenger_x = -18.10283;
+ passenger_y = -0.042108;
+ passenger_z = 45.31725;
+ }
+ }
- void InitializeAI() override
+ void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override
{
- me->GetMotionMaster()->MovePath(me->GetEntry(), FORCED_MOVEMENT_NONE, PathSource::SMART_WAYPOINT_MGR);
+ if (apply)
+ {
+ DoCastSelf(SPELL_TO_ICECROWN_AIRSHIP_PLAYER_AURA_TELEPORT_TO_DALARAN, true);
+ DoCastSelf(SPELL_FLIGHT, true);
+ DoCastSelf(me->GetEntry() == NPC_CLOUDBUSTER ? SPELL_TO_ICECROWN_PLAYER_AURA_DISMOUNT_A : SPELL_TO_ICECROWN_PLAYER_AURA_DISMOUNT_H , true);
+ DoCastSelf(SPELL_TO_ICECROWN_AIRSHIP_FROST_WYRM_WAITING_TO_SUMMON_AURA, true);
+ me->GetMotionMaster()->MovePath(me->GetEntry(), FORCED_MOVEMENT_NONE, PathSource::SMART_WAYPOINT_MGR);
+ }
+ else
+ who->RemoveAurasDueToSpell(VEHICLE_SPELL_PARACHUTE); // maybe vehicle / seat flag should be responsible for parachute gain?
+ }
- NullCreatureAI::InitializeAI();
- pointId = 0;
- searchForShipTimer = 0;
- transportEntry = (me->GetEntry() == NPC_HAMMERHEAD ? TRANSPORT_ORGRIMS_HAMMER : TRANSPORT_THE_SKYBREAKER);
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type == ESCORT_MOTION_TYPE && id == POINT_END)
+ searchForShipTimer = 3000;
}
- void MovementInform(uint32 type, uint32 /*id*/) override
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
{
- if (type == ESCORT_MOTION_TYPE)
- if (++pointId == 17) // path size
- searchForShipTimer = 3000;
+ switch (spell->Id)
+ {
+ case SPELL_TO_ICECROWN_AIRSHIP_AURA_DISMOUNT_RESPONSE:
+ break;
+ case SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_A_FORCE_PLAYER_TO_CAST:
+ case SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_H_FORCE_PLAYER_TO_CAST:
+ {
+ uint32 teleportSpell = (spell->Id == SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_A_FORCE_PLAYER_TO_CAST)
+ ? SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_A
+ : SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_H;
+ DoCastSelf(teleportSpell, true); // hack: cast on self to avoid visual glitch on player when ejecting and teleporting on transport
+ DoCastSelf(SPELL_EJECT_ALL_PASSENGERS, true);
+ me->DespawnOrUnsummon(0s);
+ break;
+ }
+ default:
+ break;
+ }
}
void UpdateAI(uint32 diff) override
{
- // horde 7.55f, -0.09, 34.44, 3.13, +20
- // ally 45.18f, 0.03, 40.09, 3.14 +5
-
if (searchForShipTimer)
{
searchForShipTimer += diff;
@@ -68,37 +116,14 @@ struct npc_preparations_for_war_vehicle : public NullCreatureAI
{
searchForShipTimer = 1;
TransportsContainer const& transports = me->GetMap()->GetAllTransports();
- for (TransportsContainer::const_iterator itr = transports.begin(); itr != transports.end(); ++itr)
+ for (auto const transport : transports)
{
- if ((*itr)->GetEntry() == transportEntry)
+ if (transport->GetEntry() == transportEntry)
{
- float x, y, z;
- if (transportEntry == TRANSPORT_ORGRIMS_HAMMER)
- {
- x = 7.55f;
- y = -0.09f;
- z = 54.44f;
- }
- else
- {
- x = 45.18f;
- y = 0.03f;
- z = 45.09f;
- }
+ float x = passenger_x, y = passenger_y, z = passenger_z;
+ transport->CalculatePassengerPosition(x, y, z);
- (*itr)->CalculatePassengerPosition(x, y, z);
-
- if (me->GetDistance2d(x, y) < 10.0f)
- {
- me->DespawnOrUnsummon(1s);
- if (Vehicle* vehicle = me->GetVehicleKit())
- if (Unit* passenger = vehicle->GetPassenger(0))
- {
- passenger->NearTeleportTo(x, y, z - (transportEntry == TRANSPORT_ORGRIMS_HAMMER ? 19.0f : 4.0f), M_PI);
- passenger->RemoveAurasDueToSpell(VEHICLE_SPELL_PARACHUTE); // maybe vehicle / seat flag should be responsible for parachute gain?
- }
- }
- else
+ if (me->GetDistance2d(x, y) > 20.0f) // dismount trigger (56905, 57420) range is 30
me->GetMotionMaster()->MovePoint(0, x, y, z, FORCED_MOVEMENT_NONE, 0.f, 0.f, false, false);
break;
}
@@ -106,6 +131,10 @@ struct npc_preparations_for_war_vehicle : public NullCreatureAI
}
}
}
+private:
+ float passenger_x, passenger_y, passenger_z;
+ uint32 searchForShipTimer;
+ uint32 transportEntry;
};
/*******************************************************
diff --git a/src/server/scripts/Northrend/zone_dalaran.cpp b/src/server/scripts/Northrend/zone_dalaran.cpp
index ca887acbe8..7c5b9fba41 100644
--- a/src/server/scripts/Northrend/zone_dalaran.cpp
+++ b/src/server/scripts/Northrend/zone_dalaran.cpp
@@ -428,7 +428,7 @@ public:
struct npc_mageguard_dalaranAI : public ScriptedAI
{
- npc_mageguard_dalaranAI(Creature* creature) : ScriptedAI(creature)
+ explicit npc_mageguard_dalaranAI(Creature* creature) : ScriptedAI(creature)
{
creature->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_NORMAL, true);
@@ -449,6 +449,9 @@ public:
if (!me->IsWithinDist(who, 5.0f, false))
return;
+ if (who->IsCreature() && who->GetCreatureType() == CREATURE_TYPE_NON_COMBAT_PET)
+ return;
+
Player* player = who->GetCharmerOrOwnerPlayerOrPlayerItself();
if (!player || player->IsGameMaster() || player->IsBeingTeleported() || (player->GetPositionZ() > 670 && player->GetVehicle()) ||
@@ -484,7 +487,6 @@ public:
break;
}
me->SetOrientation(me->GetHomePosition().GetOrientation());
- return;
}
void UpdateAI(uint32 /*diff*/) override {}
diff --git a/src/server/scripts/Northrend/zone_howling_fjord.cpp b/src/server/scripts/Northrend/zone_howling_fjord.cpp
index fc28598ec2..928a0a71e8 100644
--- a/src/server/scripts/Northrend/zone_howling_fjord.cpp
+++ b/src/server/scripts/Northrend/zone_howling_fjord.cpp
@@ -66,109 +66,6 @@ public:
}
};
-// The cleansing
-enum TurmoilTexts
-{
- SAY_TURMOIL_0 = 0,
- SAY_TURMOIL_1 = 1,
- SAY_TURMOIL_HALF_HP = 2,
- SAY_TURMOIL_DEATH = 3,
-};
-
-class npc_your_inner_turmoil : public CreatureScript
-{
-public:
- npc_your_inner_turmoil() : CreatureScript("npc_your_inner_turmoil") { }
-
- struct npc_your_inner_turmoilAI : public ScriptedAI
- {
- npc_your_inner_turmoilAI(Creature* creature) : ScriptedAI(creature) {}
-
- uint32 timer;
- short phase;
- bool health50;
-
- void Reset() override
- {
- timer = 0;
- phase = 0;
- health50 = false;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (timer >= 6000 && phase < 2)
- {
- phase++;
- setphase(phase);
- timer = 0;
- }
-
- timer += diff;
-
- DoMeleeAttackIfReady();
- }
-
- void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
- {
- if (HealthBelowPct(50) && !health50)
- {
- if (TempSummon const* tempSummon = me->ToTempSummon())
- {
- if (WorldObject* summoner = tempSummon->GetSummonerUnit())
- {
- Talk(SAY_TURMOIL_HALF_HP, summoner);
- }
- }
-
- health50 = true;
- }
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- if (TempSummon const* tempSummon = me->ToTempSummon())
- {
- if (WorldObject* summoner = tempSummon->GetSummonerUnit())
- {
- Talk(SAY_TURMOIL_DEATH, summoner);
- }
- }
- }
-
- void setphase(short newPhase)
- {
- Unit* summoner = me->ToTempSummon() ? me->ToTempSummon()->GetSummonerUnit() : nullptr;
- if (!summoner || !summoner->IsPlayer())
- return;
-
- switch (newPhase)
- {
- case 1:
- Talk(SAY_TURMOIL_0, summoner->ToPlayer());
- return;
- case 2:
- {
- Talk(SAY_TURMOIL_1, summoner->ToPlayer());
- me->SetLevel(summoner->GetLevel());
- me->SetFaction(FACTION_MONSTER);
- if (me->GetExactDist(summoner) < 50.0f)
- {
- me->UpdatePosition(summoner->GetPositionX(), summoner->GetPositionY(), summoner->GetPositionZ(), 0.0f, true);
- summoner->CastSpell(me, 50218, true); // clone caster
- AttackStart(summoner);
- }
- }
- }
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_your_inner_turmoilAI(creature);
- }
-};
-
/*######
## npc_apothecary_hanes
######*/
@@ -457,13 +354,145 @@ class spell_hawk_hunting : public SpellScript
}
};
+/*######
+## Quest 11317, 11322: The Cleansing
+######*/
+
+enum TheCleansing
+{
+ SPELL_CLEANSING_SOUL = 43351,
+ SPELL_SUMMON_INNER_TURMOIL = 50167,
+ SPELL_RECENT_MEDITATION = 61720,
+ SPELL_MIRROR_IMAGE_AURA = 50218,
+
+ QUEST_THE_CLEANSING_H = 11317,
+ QUEST_THE_CLEANSING_A = 11322
+};
+
+// 43365 - The Cleansing: Shrine Cast
+class spell_the_cleansing_shrine_cast : public SpellScript
+{
+ PrepareSpellScript(spell_the_cleansing_shrine_cast);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_RECENT_MEDITATION, SPELL_CLEANSING_SOUL }) &&
+ sObjectMgr->GetQuestTemplate(QUEST_THE_CLEANSING_H) &&
+ sObjectMgr->GetQuestTemplate(QUEST_THE_CLEANSING_A);
+ }
+
+ SpellCastResult CheckCast()
+ {
+ // Error is correct for quest check but may be not correct for aura and this may be a wrong place to send error
+ if (Player* target = GetExplTargetUnit()->ToPlayer())
+ {
+ if (target->HasAura(SPELL_RECENT_MEDITATION) || (!(target->GetQuestStatus(QUEST_THE_CLEANSING_H) == QUEST_STATUS_INCOMPLETE ||
+ target->GetQuestStatus(QUEST_THE_CLEANSING_A) == QUEST_STATUS_INCOMPLETE)))
+ {
+ Spell::SendCastResult(target, GetSpellInfo(), 0, SPELL_FAILED_FIZZLE);
+ return SPELL_FAILED_FIZZLE;
+ }
+ }
+ return SPELL_CAST_OK;
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ GetHitUnit()->CastSpell(GetHitUnit(), SPELL_CLEANSING_SOUL, true);
+ }
+
+ void Register() override
+ {
+ OnCheckCast += SpellCheckCastFn(spell_the_cleansing_shrine_cast::CheckCast);
+ OnEffectHitTarget += SpellEffectFn(spell_the_cleansing_shrine_cast::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+// 43351 - Cleansing Soul
+class spell_the_cleansing_cleansing_soul : public AuraScript
+{
+ PrepareAuraScript(spell_the_cleansing_cleansing_soul);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_SUMMON_INNER_TURMOIL, SPELL_RECENT_MEDITATION });
+ }
+
+ void AfterApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ GetTarget()->SetStandState(UNIT_STAND_STATE_SIT);
+ }
+
+ void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Unit* target = GetTarget();
+ target->SetStandState(UNIT_STAND_STATE_STAND);
+ target->CastSpell(target, SPELL_SUMMON_INNER_TURMOIL, true);
+ target->CastSpell(target, SPELL_RECENT_MEDITATION, true);
+ }
+
+ void Register() override
+ {
+ AfterEffectApply += AuraEffectApplyFn(spell_the_cleansing_cleansing_soul::AfterApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_the_cleansing_cleansing_soul::AfterRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+};
+
+// 50217 - The Cleansing: Script Effect Player Cast Mirror Image
+class spell_the_cleansing_mirror_image_script_effect : public SpellScript
+{
+ PrepareSpellScript(spell_the_cleansing_mirror_image_script_effect);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_MIRROR_IMAGE_AURA });
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ GetHitUnit()->CastSpell(GetHitUnit(), SPELL_MIRROR_IMAGE_AURA, true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_the_cleansing_mirror_image_script_effect::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+// 50238 - The Cleansing: Your Inner Turmoil's On Death Cast on Master
+class spell_the_cleansing_on_death_cast_on_master : public SpellScript
+{
+ PrepareSpellScript(spell_the_cleansing_on_death_cast_on_master);
+
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ return ValidateSpellInfo({ uint32(spellInfo->GetEffect(EFFECT_0).CalcValue()) });
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* caster = GetCaster())
+ if (TempSummon* casterSummon = caster->ToTempSummon())
+ if (Unit* summoner = casterSummon->GetSummonerUnit())
+ summoner->CastSpell(summoner, GetSpellInfo()->Effects[EFFECT_0].CalcValue(), true);
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_the_cleansing_on_death_cast_on_master::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
void AddSC_howling_fjord()
{
new npc_attracted_reef_bull();
- new npc_your_inner_turmoil();
new npc_apothecary_hanes();
new npc_plaguehound_tracker();
new npc_razael_and_lyana();
RegisterCreatureAI(npc_rodin_lightning_enabler);
RegisterSpellScript(spell_hawk_hunting);
+ RegisterSpellScript(spell_the_cleansing_shrine_cast);
+ RegisterSpellScript(spell_the_cleansing_cleansing_soul);
+ RegisterSpellScript(spell_the_cleansing_mirror_image_script_effect);
+ RegisterSpellScript(spell_the_cleansing_on_death_cast_on_master);
}
diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp
index 6cc9c8ae3a..94e300720c 100644
--- a/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp
+++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp
@@ -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
diff --git a/src/server/scripts/Pet/pet_hunter.cpp b/src/server/scripts/Pet/pet_hunter.cpp
index 3a6d979506..b82180e666 100644
--- a/src/server/scripts/Pet/pet_hunter.cpp
+++ b/src/server/scripts/Pet/pet_hunter.cpp
@@ -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
diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp
index 49687928fb..4cb86db3da 100644
--- a/src/server/scripts/Spells/spell_dk.cpp
+++ b/src/server/scripts/Spells/spell_dk.cpp
@@ -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();
diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp
index c6f90e153e..85a12610da 100644
--- a/src/server/scripts/Spells/spell_druid.cpp
+++ b/src/server/scripts/Spells/spell_druid.cpp
@@ -443,15 +443,16 @@ class spell_dru_enrage : public AuraScript
void RecalculateBaseArmor()
{
+ // Recalculate modifies the list while we're iterating through it, so let's copy it instead
Unit::AuraEffectList const& auras = GetTarget()->GetAuraEffectsByType(SPELL_AURA_MOD_BASE_RESISTANCE_PCT);
- for (Unit::AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
+ std::vector<AuraEffect*> aurEffs(auras.begin(), auras.end());
+
+ for (AuraEffect* aurEff : aurEffs)
{
- SpellInfo const* spellInfo = (*i)->GetSpellInfo();
+ SpellInfo const* spellInfo = aurEff->GetSpellInfo();
// Dire- / Bear Form (Passive)
if (spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && spellInfo->SpellFamilyFlags.HasFlag(0x0, 0x0, 0x2))
- {
- (*i)->RecalculateAmount();
- }
+ aurEff->RecalculateAmount();
}
}
diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
index 68ef5e5540..38f669693f 100644
--- a/src/server/scripts/Spells/spell_generic.cpp
+++ b/src/server/scripts/Spells/spell_generic.cpp
@@ -4423,7 +4423,9 @@ class spell_gen_eject_all_passengers : public SpellScript
}
};
-/* 62539 - Eject Passenger 2
+/* 49259 - Despawn Driver
+ 49261 - Dismount Passenger
+ 62539 - Eject Passenger 2
64614 - Eject Passenger 4
64629 - Eject Passenger 1
64630 - Eject Passenger 2
@@ -5671,6 +5673,29 @@ class spell_gen_bm_on : public SpellScript
}
};
+class spell_gen_whisper_to_controller : public SpellScript
+{
+ PrepareSpellScript(spell_gen_whisper_to_controller);
+
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ return sObjectMgr->GetBroadcastText(uint32(spellInfo->GetEffect(EFFECT_0).CalcValue()));
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* caster = GetCaster())
+ if (TempSummon* casterSummon = caster->ToTempSummon())
+ if (Player* target = casterSummon->GetSummonerUnit()->ToPlayer())
+ casterSummon->Unit::Whisper(uint32(GetEffectValue()), target, false);
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_gen_whisper_to_controller::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
void AddSC_generic_spell_scripts()
{
RegisterSpellScript(spell_silithyst);
@@ -5844,4 +5869,5 @@ void AddSC_generic_spell_scripts()
RegisterSpellScript(spell_gen_invis_on);
RegisterSpellScript(spell_gen_bm_on);
RegisterSpellScript(spell_gen_bm_off);
+ RegisterSpellScript(spell_gen_whisper_to_controller);
}
diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp
index f9cdd76231..0acf87cb21 100644
--- a/src/server/scripts/Spells/spell_paladin.cpp
+++ b/src/server/scripts/Spells/spell_paladin.cpp
@@ -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*/)
@@ -965,6 +961,24 @@ class spell_pal_lay_on_hands : public SpellScript
return true;
}
+ void HandleMaxHealthHeal(SpellEffIndex /*effIndex*/)
+ {
+ Unit* caster = GetCaster();
+ Unit* target = GetExplTargetUnit();
+
+ if (!target || !caster)
+ return;
+
+ uint32 baseHeal = caster->GetMaxHealth();
+ uint32 modifiedHeal = target->SpellHealingBonusTaken(caster, GetSpellInfo(), baseHeal, HEAL);
+
+ // EffectHealMaxHealth() ignores healing modifiers, so we pre-apply the
+ // difference here; this delta will be added on top of the raw heal.
+ int64 healAdjustment = int64(modifiedHeal) - int64(baseHeal);
+
+ SetHitHeal(healAdjustment);
+ }
+
SpellCastResult CheckCast()
{
Unit* caster = GetCaster();
@@ -1004,6 +1018,7 @@ class spell_pal_lay_on_hands : public SpellScript
{
OnCheckCast += SpellCheckCastFn(spell_pal_lay_on_hands::CheckCast);
AfterHit += SpellHitFn(spell_pal_lay_on_hands::HandleScript);
+ OnEffectHitTarget += SpellEffectFn(spell_pal_lay_on_hands::HandleMaxHealthHeal, EFFECT_0, SPELL_EFFECT_HEAL_MAX_HEALTH);
}
int32 _manaAmount;
diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp
index 870cc73850..4e1b563333 100644
--- a/src/server/scripts/Spells/spell_quest.cpp
+++ b/src/server/scripts/Spells/spell_quest.cpp
@@ -247,28 +247,6 @@ class spell_q10525_vision_guide : public AuraScript
}
};
-class spell_q11322_q11317_the_cleansing : public AuraScript
-{
- PrepareAuraScript(spell_q11322_q11317_the_cleansing)
-
- void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- Unit* ar = GetCaster();
- if (ar && ar->ToPlayer())
- {
- if (ar->ToPlayer()->GetQuestStatus(11317) == QUEST_STATUS_INCOMPLETE || ar->ToPlayer()->GetQuestStatus(11322) == QUEST_STATUS_INCOMPLETE)
- ar->SummonCreature(27959, 3032.0f, -5095.0f, 723.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000);
-
- ar->SetStandState(UNIT_STAND_STATE_SIT);
- }
- }
-
- void Register() override
- {
- OnEffectApply += AuraEffectApplyFn(spell_q11322_q11317_the_cleansing::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
- }
-};
-
class spell_q10714_on_spirits_wings : public SpellScript
{
PrepareSpellScript(spell_q10714_on_spirits_wings);
@@ -2499,7 +2477,6 @@ void AddSC_quest_spell_scripts()
RegisterSpellScript(spell_q12014_steady_as_a_rock);
RegisterSpellAndAuraScriptPair(spell_q11026_a11051_banish_the_demons, spell_q11026_a11051_banish_the_demons_aura);
RegisterSpellScript(spell_q10525_vision_guide);
- RegisterSpellScript(spell_q11322_q11317_the_cleansing);
RegisterSpellScript(spell_q10714_on_spirits_wings);
RegisterSpellScript(spell_q10720_the_smallest_creature);
RegisterSpellScript(spell_q13086_last_line_of_defence);
diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp
index d6a6a3d8cf..e484b2b333 100644
--- a/src/server/scripts/Spells/spell_warlock.cpp
+++ b/src/server/scripts/Spells/spell_warlock.cpp
@@ -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*/)
- {
- 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);
- }
- }
- }
- }
-
- void HandleRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
- {
- 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);
- }
- }
- }
- }
-
- 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*/)
+ bool Validate(SpellInfo const* /*spellInfo*/) override
{
- 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);
- }
- }
- }
+ 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_VOIDWALKER)
- {
- pet->HandleStatModifier(UNIT_MOD_STAT_STAMINA, 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_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);
}
diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp
index 23b46b039d..cb669c3f0e 100644
--- a/src/server/scripts/World/npcs_special.cpp
+++ b/src/server/scripts/World/npcs_special.cpp
@@ -563,10 +563,6 @@ public:
if (!SpawnAssoc)
return;
- // check if they're hostile
- if (!(me->IsHostileTo(who) || who->IsHostileTo(me)))
- return;
-
if (me->IsValidAttackTarget(who))
{
Player* playerTarget = who->ToPlayer();
diff --git a/src/server/shared/DataStores/DBCStructure.h b/src/server/shared/DataStores/DBCStructure.h
index 59ebe9b57f..4e7e8ca2cd 100644
--- a/src/server/shared/DataStores/DBCStructure.h
+++ b/src/server/shared/DataStores/DBCStructure.h
@@ -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
diff --git a/src/server/shared/Network/AsyncAcceptor.h b/src/server/shared/Network/AsyncAcceptor.h
index f91c2ca37e..71c58ed937 100644
--- a/src/server/shared/Network/AsyncAcceptor.h
+++ b/src/server/shared/Network/AsyncAcceptor.h
@@ -20,6 +20,7 @@
#include "IpAddress.h"
#include "Log.h"
+#include "Systemd.h"
#include <atomic>
#include <boost/asio/ip/tcp.hpp>
#include <functional>
@@ -33,10 +34,20 @@ class AsyncAcceptor
public:
typedef void(*AcceptCallback)(tcp::socket&& newSocket, uint32 threadIndex);
- AsyncAcceptor(Acore::Asio::IoContext& ioContext, std::string const& bindIp, uint16 port) :
+ AsyncAcceptor(Acore::Asio::IoContext& ioContext, std::string const& bindIp, uint16 port, bool supportSocketActivation = false) :
_acceptor(ioContext), _endpoint(Acore::Net::make_address(bindIp), port),
- _socket(ioContext), _closed(false), _socketFactory([this](){ return DefaultSocketFactory(); })
+ _socket(ioContext), _closed(false), _socketFactory([this](){ return DefaultSocketFactory(); }),
+ _supportSocketActivation(supportSocketActivation)
{
+ int const listen_fd = get_listen_fd();
+ if (_supportSocketActivation && listen_fd > 0)
+ {
+ LOG_DEBUG("network", "Using socket from systemd socket activation");
+ boost::system::error_code errorCode;
+ _acceptor.assign(boost::asio::ip::tcp::v4(), listen_fd, errorCode);
+ if (errorCode)
+ LOG_WARN("network", "Failed to assign socket {}", errorCode.message());
+ }
}
template<class T>
@@ -72,27 +83,31 @@ public:
bool Bind()
{
boost::system::error_code errorCode;
- _acceptor.open(_endpoint.protocol(), errorCode);
- if (errorCode)
+ // with socket activation the acceptor is already open and bound
+ if (!_acceptor.is_open())
{
- LOG_INFO("network", "Failed to open acceptor {}", errorCode.message());
- return false;
- }
+ _acceptor.open(_endpoint.protocol(), errorCode);
+ if (errorCode)
+ {
+ LOG_INFO("network", "Failed to open acceptor {}", errorCode.message());
+ return false;
+ }
#if AC_PLATFORM != AC_PLATFORM_WINDOWS
- _acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true), errorCode);
- if (errorCode)
- {
- LOG_INFO("network", "Failed to set reuse_address option on acceptor {}", errorCode.message());
- return false;
- }
+ _acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true), errorCode);
+ if (errorCode)
+ {
+ LOG_INFO("network", "Failed to set reuse_address option on acceptor {}", errorCode.message());
+ return false;
+ }
#endif
- _acceptor.bind(_endpoint, errorCode);
- if (errorCode)
- {
- LOG_INFO("network", "Could not bind to {}:{} {}", _endpoint.address().to_string(), _endpoint.port(), errorCode.message());
- return false;
+ _acceptor.bind(_endpoint, errorCode);
+ if (errorCode)
+ {
+ LOG_INFO("network", "Could not bind to {}:{} {}", _endpoint.address().to_string(), _endpoint.port(), errorCode.message());
+ return false;
+ }
}
_acceptor.listen(ACORE_MAX_LISTEN_CONNECTIONS, errorCode);
@@ -124,6 +139,7 @@ private:
tcp::socket _socket;
std::atomic<bool> _closed;
std::function<std::pair<tcp::socket*, uint32>()> _socketFactory;
+ bool _supportSocketActivation;
};
template<class T>
diff --git a/src/server/shared/Network/SocketMgr.h b/src/server/shared/Network/SocketMgr.h
index dc0c5e6f5f..085e4e2380 100644
--- a/src/server/shared/Network/SocketMgr.h
+++ b/src/server/shared/Network/SocketMgr.h
@@ -19,6 +19,7 @@
#define SocketMgr_h__
#include "AsyncAcceptor.h"
+#include "Config.h"
#include "Errors.h"
#include "NetworkThread.h"
#include <boost/asio/ip/tcp.hpp>
@@ -42,7 +43,8 @@ public:
std::unique_ptr<AsyncAcceptor> acceptor;
try
{
- acceptor = std::make_unique<AsyncAcceptor>(ioContext, bindIp, port);
+ bool supportSocketActivation = sConfigMgr->GetOption<bool>("Network.UseSocketActivation", false);
+ acceptor = std::make_unique<AsyncAcceptor>(ioContext, bindIp, port, supportSocketActivation);
}
catch (boost::system::system_error const& err)
{