Core/Spells: rework part 4: iterate over effects first

Implement far spell queue processing

# Conflicts:
#	src/server/game/Spells/Spell.cpp
This commit is contained in:
ariel- authored and Ovahlord committed 2022-09-12 09:15:13 +02:00
1 parent 3fbbea61bd
commit 4bb8c93df8
12 files changed
+765 -834

No files matched your search

@@ -18,7 +18,6 @@
#include "KillRewarder.h"
#include "SpellAuraEffects.h"
#include "Creature.h"
#include "EventProcessor.h"
#include "Formulas.h"
#include "Group.h"
#include "Guild.h"
+2 -2
View File
@@ -7963,7 +7963,7 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT
if (!(damageInfo.GetHitMask() & (PROC_HIT_NORMAL | PROC_HIT_CRITICAL | PROC_HIT_ABSORB)))
return false;
if (damageInfo.GetSpellInfo() && damageInfo.GetSpellInfo()->HasAttribute(SPELL_ATTR3_CANT_TRIGGER_CASTER_PROCS))
if (damageInfo.GetSpellInfo() && damageInfo.GetSpellInfo()->HasAttribute(SPELL_ATTR3_SUPPRESS_CASTER_PROCS))
return false;
return true;
@@ -23281,7 +23281,7 @@ Unit* Player::GetSelectedUnit() const
Player* Player::GetSelectedPlayer() const
{
if (ObjectGuid selectionGUID = GetTarget())
return ObjectAccessor::GetPlayer(*this, selectionGUID);
return ObjectAccessor::FindConnectedPlayer(selectionGUID);
return nullptr;
}
+14
View File
@@ -3448,8 +3448,22 @@ bool Map::IsSpawnGroupActive(uint32 groupId) const
return (_toggledSpawnGroupIds.find(groupId) != _toggledSpawnGroupIds.end()) != !(data->flags & SPAWNGROUP_FLAG_MANUAL_SPAWN);
}
void Map::AddFarSpellCallback(FarSpellCallback&& callback)
{
_farSpellCallbacks.Enqueue(new FarSpellCallback(std::move(callback)));
}
void Map::DelayedUpdate(uint32 t_diff)
{
{
FarSpellCallback* callback;
while (_farSpellCallbacks.Dequeue(callback))
{
(*callback)(this);
delete callback;
}
}
RemoveAllObjectsInRemoveList();
// Don't unload grids if it's battleground, since we may have manually added GOs, creatures, those doesn't load from DB at grid re-load !
+6
View File
@@ -25,6 +25,7 @@
#include "GridDefines.h"
#include "GridRefManager.h"
#include "MapRefManager.h"
#include "MPSCQueue.h"
#include "ObjectGuid.h"
#include "Optional.h"
#include "SharedDefines.h"
@@ -876,6 +877,9 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
// This will not affect any already-present creatures in the group
void SetSpawnGroupInactive(uint32 groupId) { SetSpawnGroupActive(groupId, false); }
typedef std::function<void(Map*)> FarSpellCallback;
void AddFarSpellCallback(FarSpellCallback&& callback);
// Sets and stores world state values that will be used by the AchievementMgr to check additional criterias that require world state values
void SetWorldState(uint32 worldStateId, int32 value, bool withUpdatePacket = true);
int32 GetWorldStateValue(uint32 worldStateId) const;
@@ -968,6 +972,8 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
std::unordered_set<Object*> _updateObjects;
std::unordered_map<uint32 /*worldStateId*/, int32 /*value*/> _worldStates;
MPSCQueue<FarSpellCallback> _farSpellCallbacks;
};
enum InstanceResetMethod
@@ -477,8 +477,8 @@ enum SpellAttr3
SPELL_ATTR3_DONT_DISPLAY_CHANNEL_BAR = 0x00002000, // 13 Clientside attribute - will not display channeling bar
SPELL_ATTR3_IS_HONORLESS_TARGET = 0x00004000, // 14 "Honorless Target" only this spells have this flag
SPELL_ATTR3_UNK15 = 0x00008000, // 15 Auto Shoot, Shoot, Throw, - this is autoshot flag
SPELL_ATTR3_CANT_TRIGGER_CASTER_PROCS = 0x00010000, // 16 Suppress Caster Procs
SPELL_ATTR3_CANT_TRIGGER_TARGET_PROCS = 0x00020000, // 17 Suppress Target Procs
SPELL_ATTR3_SUPPRESS_CASTER_PROCS = 0x00010000, // 16 Suppress Caster Procs
SPELL_ATTR3_SUPPRESS_TARGET_PROCS = 0x00020000, // 17 Suppress Target Procs
SPELL_ATTR3_IGNORE_HIT_RESULT = 0x00040000, // 18 Spell should always hit its target
SPELL_ATTR3_DISABLE_PROC = 0x00080000, // 19 during aura proc no spells can trigger (20178, 20375)
SPELL_ATTR3_DEATH_PERSISTENT = 0x00100000, // 20 Death persistent spells
File diff suppressed because it is too large. Load diff
+67 -40
View File
@@ -481,7 +481,6 @@ class TC_GAME_API Spell
int32 CalculateDamage(uint8 i, Unit const* target) const;
bool HaveTargetsForEffect(uint8 effect) const;
void Delayed();
void DelayedChannel();
uint32 getState() const { return m_spellState; }
@@ -625,7 +624,7 @@ class TC_GAME_API Spell
bool m_executedCurrently; // mark as executed to prevent deleted and access by dead pointers
bool m_needComboPoints;
uint8 m_applyMultiplierMask;
float m_damageMultipliers[3];
float m_damageMultipliers[MAX_SPELL_EFFECTS];
// Current targets, to be used in SpellEffects (MUST BE USED ONLY IN SPELL EFFECTS)
Unit* unitTarget;
@@ -659,48 +658,79 @@ class TC_GAME_API Spell
// Spell target subsystem
// *****************************************
// Targets store structures and data
struct TargetInfo
struct TargetInfoBase
{
ObjectGuid targetGUID;
uint64 timeDelay;
int32 damage;
virtual void PreprocessTarget(Spell* /*spell*/) { }
virtual void DoTargetSpellHit(Spell* spell, uint8 effIndex) = 0;
virtual void DoDamageAndTriggers(Spell* /*spell*/) { }
SpellMissInfo missCondition;
SpellMissInfo reflectResult;
uint8 EffectMask = 0;
uint8 effectMask;
bool processed;
bool alive;
bool crit;
bool scaleAura;
protected:
TargetInfoBase() { }
virtual ~TargetInfoBase() { }
};
std::list<TargetInfo> m_UniqueTargetInfo;
struct TargetInfo : public TargetInfoBase
{
void PreprocessTarget(Spell* spell) override;
void DoTargetSpellHit(Spell* spell, uint8 effIndex) override;
void DoDamageAndTriggers(Spell* spell) override;
ObjectGuid TargetGUID;
uint64 TimeDelay = 0ULL;
int32 Damage = 0;
int32 Healing = 0;
SpellMissInfo MissCondition = SPELL_MISS_NONE;
SpellMissInfo ReflectResult = SPELL_MISS_NONE;
bool IsAlive = false;
bool IsCrit = false;
bool ScaleAura = false;
// info set at PreprocessTarget, used by DoTargetSpellHit
DiminishingGroup DRGroup = DIMINISHING_NONE;
int32 AuraDuration = 0;
SpellInfo const* AuraSpellInfo = nullptr;
int32 AuraBasePoints[MAX_SPELL_EFFECTS] = { };
bool Positive = true;
private:
Unit* _spellHitTarget = nullptr; // changed for example by reflect
bool _enablePVP = false; // need to enable PVP at DoDamageAndTriggers?
};
std::vector<TargetInfo> m_UniqueTargetInfo;
uint8 m_channelTargetEffectMask; // Mask req. alive targets
struct GOTargetInfo
struct GOTargetInfo : public TargetInfoBase
{
ObjectGuid targetGUID;
uint64 timeDelay;
uint8 effectMask;
bool processed;
};
std::list<GOTargetInfo> m_UniqueGOTargetInfo;
void DoTargetSpellHit(Spell* spell, uint8 effIndex) override;
struct ItemTargetInfo
{
Item *item;
uint8 effectMask;
ObjectGuid TargetGUID;
uint64 TimeDelay = 0ULL;
};
std::list<ItemTargetInfo> m_UniqueItemInfo;
std::vector<GOTargetInfo> m_UniqueGOTargetInfo;
struct CorpseTargetInfo
struct ItemTargetInfo : public TargetInfoBase
{
ObjectGuid targetGUID;
uint64 timeDelay;
uint8 effectMask;
bool processed;
void DoTargetSpellHit(Spell* spell, uint8 effIndex) override;
Item* TargetItem = nullptr;
};
std::list<CorpseTargetInfo> m_UniqueCorpseTargetInfo;
std::vector<ItemTargetInfo> m_UniqueItemInfo;
struct CorpseTargetInfo : public TargetInfoBase
{
void DoTargetSpellHit(Spell* spell, uint8 effIndex) override;
ObjectGuid TargetGUID;
uint64 TimeDelay = 0ULL;
};
std::vector<CorpseTargetInfo> m_UniqueCorpseTargetInfo;
template <class Container>
void DoProcessTargetContainer(Container& targetContainer);
SpellDestination m_destTargets[MAX_SPELL_EFFECTS];
@@ -710,16 +740,14 @@ class TC_GAME_API Spell
void AddCorpseTarget(Corpse* target, uint32 effectMask);
void AddDestTarget(SpellDestination const& dest, uint32 effIndex);
void DoAllEffectOnTarget(TargetInfo* target);
SpellMissInfo DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleAura);
SpellMissInfo PreprocessSpellHit(Unit* unit, bool scaleAura, TargetInfo& targetInfo);
void DoSpellEffectHit(Unit* unit, uint8 effIndex, TargetInfo& targetInfo);
void DoTriggersOnSpellHit(Unit* unit, uint8 effMask);
void DoAllEffectOnTarget(GOTargetInfo* target);
void DoAllEffectOnTarget(ItemTargetInfo* target);
void DoAllEffectOnTarget(CorpseTargetInfo* target);
bool UpdateChanneledTargetList();
bool IsValidDeadOrAliveTarget(Unit const* target) const;
void HandleLaunchPhase();
void DoAllEffectOnLaunchTarget(TargetInfo& targetInfo, float* multiplier);
void DoEffectOnLaunchTarget(TargetInfo& targetInfo, float multiplier, uint8 effIndex);
void PrepareTargetProcessing();
void FinishTargetProcessing();
@@ -735,7 +763,6 @@ class TC_GAME_API Spell
void CallScriptAfterCastHandlers();
void CallScriptOnSpellStartHandlers();
SpellCastResult CallScriptCheckCastHandlers();
void PrepareScriptHitHandlers();
bool CallScriptEffectHandlers(SpellEffIndex effIndex, SpellEffectHandleMode mode);
void CallScriptSuccessfulDispel(SpellEffIndex effIndex);
void CallScriptBeforeHitHandlers();
@@ -787,7 +814,7 @@ class TC_GAME_API Spell
uint8 m_auraScaleMask;
std::unique_ptr<PathGenerator> m_preGeneratedPath;
ByteBuffer * m_effectExecuteData[MAX_SPELL_EFFECTS];
ByteBuffer* m_effectExecuteData[MAX_SPELL_EFFECTS];
Spell(Spell const& right) = delete;
Spell& operator=(Spell const& right) = delete;
+5 -5
View File
@@ -363,8 +363,8 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex)
if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_SHARE_DAMAGE))
{
uint32 count = 0;
for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
if (ihit->effectMask & (1<<effIndex))
for (auto ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
if (ihit->EffectMask & (1 << effIndex))
++count;
damage /= count; // divide to all targets
@@ -1072,10 +1072,10 @@ void Spell::EffectHeal(SpellEffIndex effIndex)
if (m_spellInfo->Id == 45064)
{
// Amount of heal - depends from stacked Holy Energy
int damageAmount = 0;
int32 damageAmount = 0;
if (AuraEffect const* aurEff = m_caster->GetAuraEffect(45062, 0))
{
damageAmount+= aurEff->GetAmount();
damageAmount += aurEff->GetAmount();
m_caster->RemoveAurasDueToSpell(45062);
}
@@ -1128,7 +1128,7 @@ void Spell::EffectHeal(SpellEffIndex effIndex)
if (unitTarget->HasAura(48920) && (unitTarget->GetHealth() + addhealth >= unitTarget->GetMaxHealth()))
unitTarget->RemoveAura(48920);
m_damage -= addhealth;
m_healing += addhealth;
}
}
+2 -15
View File
@@ -418,19 +418,6 @@ bool SpellEffectInfo::IsAreaAuraEffect() const
return false;
}
bool SpellEffectInfo::IsFarUnitTargetEffect() const
{
return (Effect == SPELL_EFFECT_SUMMON_PLAYER)
|| (Effect == SPELL_EFFECT_SUMMON_RAF_FRIEND)
|| (Effect == SPELL_EFFECT_RESURRECT)
|| (Effect == SPELL_EFFECT_RESURRECT_NEW);
}
bool SpellEffectInfo::IsFarDestTargetEffect() const
{
return Effect == SPELL_EFFECT_TELEPORT_UNITS;
}
bool SpellEffectInfo::IsUnitOwnedAuraEffect() const
{
return IsAreaAuraEffect() || Effect == SPELL_EFFECT_APPLY_AURA || Effect == SPELL_EFFECT_APPLY_AURA_2;
@@ -3366,14 +3353,14 @@ float SpellInfo::GetMaxRange(bool positive, Unit* caster, Spell* spell) const
int32 SpellInfo::GetDuration() const
{
if (!DurationEntry)
return 0;
return IsPassive() ? -1 : 0;
return (DurationEntry->Duration == -1) ? -1 : abs(DurationEntry->Duration);
}
int32 SpellInfo::GetMaxDuration() const
{
if (!DurationEntry)
return 0;
return IsPassive() ? -1 : 0;
return (DurationEntry->MaxDuration == -1) ? -1 : abs(DurationEntry->MaxDuration);
}
-2
View File
@@ -289,8 +289,6 @@ public:
bool IsAura(AuraType aura) const;
bool IsTargetingArea() const;
bool IsAreaAuraEffect() const;
bool IsFarUnitTargetEffect() const;
bool IsFarDestTargetEffect() const;
bool IsUnitOwnedAuraEffect() const;
int32 CalcValue(Unit const* caster = nullptr, int32 const* basePoints = nullptr, Unit const* target = nullptr) const;
+1 -12
View File
@@ -3684,17 +3684,6 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->MaxAffectedTargets = 1;
});
// Boom (XT-002)
ApplySpellFix({ 62834 }, [](SpellInfo* spellInfo)
{
// This hack is here because we suspect our implementation of spell effect execution on targets
// is done in the wrong order. We suspect that EFFECT_0 needs to be applied on all targets,
// then EFFECT_1, etc - instead of applying each effect on target1, then target2, etc.
// The above situation causes the visual for this spell to be bugged, so we remove the instakill
// effect and implement a script hack for that.
spellInfo->Effects[EFFECT_1].Effect = 0;
});
ApplySpellFix({
64386, // Terrifying Screech (Auriaya)
64389, // Sentinel Blast (Auriaya)
@@ -4859,7 +4848,7 @@ void SpellMgr::LoadSpellInfoCorrections()
// Feral Charge (Cat Form)
ApplySpellFix({ 49376 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 &= ~SPELL_ATTR3_CANT_TRIGGER_CASTER_PROCS;
spellInfo->AttributesEx3 &= ~SPELL_ATTR3_SUPPRESS_CASTER_PROCS;
});
//
@@ -629,29 +629,6 @@ class npc_pummeller : public CreatureScript
* XE-321 BOOMBOT
*
*///----------------------------------------------------
class BoomEvent : public BasicEvent
{
public:
BoomEvent(Creature* me) : _me(me)
{
}
bool Execute(uint64 /*time*/, uint32 /*diff*/) override
{
// This hack is here because we suspect our implementation of spell effect execution on targets
// is done in the wrong order. We suspect that EFFECT_0 needs to be applied on all targets,
// then EFFECT_1, etc - instead of applying each effect on target1, then target2, etc.
// The above situation causes the visual for this spell to be bugged, so we remove the instakill
// effect and implement a script hack for that.
_me->CastSpell(_me, SPELL_BOOM, false);
return true;
}
private:
Creature* _me;
};
class npc_boombot : public CreatureScript
{
public:
@@ -703,12 +680,7 @@ class npc_boombot : public CreatureScript
damage = 0;
// Visual only seems to work if the instant kill event is delayed or the spell itself is delayed
// Casting done from player and caster source has the same targetinfo flags,
// so that can't be the issue
// See BoomEvent class
// Schedule 1s delayed
me->m_Events.AddEvent(new BoomEvent(me), me->m_Events.CalculateTime(1*IN_MILLISECONDS));
DoCastAOE(SPELL_BOOM);
}
}