fix(Core/Misc): bunch of crashfixes (#7307)
This commit is contained in:
@@ -453,12 +453,12 @@ int32 AuraEffect::CalculateAmount(Unit* caster)
|
||||
ItemRandomSuffixEntry const* item_rand_suffix = sItemRandomSuffixStore.LookupEntry(abs(castItem->GetItemRandomPropertyId()));
|
||||
if (item_rand_suffix)
|
||||
{
|
||||
for (int k = 0; k < MAX_ITEM_ENCHANTMENT_EFFECTS; k++)
|
||||
for (uint8 k = 0; k < MAX_ITEM_ENCHANTMENT_EFFECTS; k++)
|
||||
{
|
||||
SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(item_rand_suffix->enchant_id[k]);
|
||||
if (pEnchant)
|
||||
{
|
||||
for (int t = 0; t < MAX_SPELL_ITEM_ENCHANTMENT_EFFECTS; t++)
|
||||
for (uint8 t = 0; t < MAX_SPELL_ITEM_ENCHANTMENT_EFFECTS; t++)
|
||||
if (pEnchant->spellid[t] == m_spellInfo->Id)
|
||||
{
|
||||
amount = uint32((item_rand_suffix->prefix[k] * castItem->GetItemSuffixFactor()) / 10000);
|
||||
|
||||
@@ -68,6 +68,7 @@ public:
|
||||
uint32 GetTickNumber() const { return m_tickNumber; }
|
||||
int32 GetTotalTicks() const { return m_amplitude ? (GetBase()->GetMaxDuration() / m_amplitude) : 1;}
|
||||
void ResetPeriodic(bool resetPeriodicTimer = false) { if (resetPeriodicTimer) m_periodicTimer = m_amplitude; m_tickNumber = 0;}
|
||||
void ResetTicks() { m_tickNumber = 0; }
|
||||
|
||||
bool IsPeriodic() const { return m_isPeriodic; }
|
||||
void SetPeriodic(bool isPeriodic) { m_isPeriodic = isPeriodic; }
|
||||
|
||||
@@ -847,12 +847,33 @@ void Aura::SetDuration(int32 duration, bool withMods)
|
||||
SetNeedClientUpdateForTargets();
|
||||
}
|
||||
|
||||
void Aura::RefreshDuration()
|
||||
void Aura::RefreshDuration(bool withMods)
|
||||
{
|
||||
SetDuration(GetMaxDuration());
|
||||
Unit* caster = GetCaster();
|
||||
|
||||
if (!caster)
|
||||
return;
|
||||
|
||||
if (withMods && caster)
|
||||
{
|
||||
int32 duration = m_spellInfo->GetMaxDuration();
|
||||
// Calculate duration of periodics affected by haste.
|
||||
if (caster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, m_spellInfo) || m_spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC))
|
||||
duration = int32(duration * caster->GetFloatValue(UNIT_MOD_CAST_SPEED));
|
||||
SetMaxDuration(duration);
|
||||
|
||||
SetDuration(duration);
|
||||
}
|
||||
else
|
||||
SetDuration(GetMaxDuration());
|
||||
|
||||
if ((m_spellInfo->ManaPerSecond || m_spellInfo->ManaPerSecondPerLevel) && !m_spellInfo->HasAttribute(SPELL_ATTR2_NO_TARGET_PER_SECOND_COST))
|
||||
m_timeCla = 1 * IN_MILLISECONDS;
|
||||
|
||||
// also reset periodic counters
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
if (AuraEffect* aurEff = m_effects[i])
|
||||
aurEff->ResetTicks();
|
||||
}
|
||||
|
||||
void Aura::RefreshTimers(bool periodicReset /*= false*/)
|
||||
@@ -860,27 +881,13 @@ void Aura::RefreshTimers(bool periodicReset /*= false*/)
|
||||
m_maxDuration = CalcMaxDuration();
|
||||
RefreshDuration();
|
||||
Unit* caster = GetCaster();
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
if (HasEffect(i))
|
||||
{
|
||||
GetEffect(i)->CalculatePeriodic(caster, periodicReset, false);
|
||||
GetEffect(i)->CalculatePeriodicData();
|
||||
}
|
||||
}
|
||||
|
||||
// xinef: dot's rolling function
|
||||
void Aura::RefreshTimersWithMods()
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
m_maxDuration = CalcMaxDuration();
|
||||
if ((caster && caster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, m_spellInfo)) || m_spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC))
|
||||
m_maxDuration = int32(m_maxDuration * caster->GetFloatValue(UNIT_MOD_CAST_SPEED));
|
||||
if (!caster)
|
||||
return;
|
||||
|
||||
// xinef: we should take ModSpellDuration into account, but none of the spells using this function is affected by contents of ModSpellDuration
|
||||
RefreshDuration();
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
if (HasEffect(i))
|
||||
GetEffect(i)->CalculatePeriodic(caster, false, false);
|
||||
if (AuraEffect* aurEff = m_effects[i])
|
||||
aurEff->CalculatePeriodic(caster, periodicReset, false);
|
||||
}
|
||||
|
||||
void Aura::SetCharges(uint8 charges)
|
||||
@@ -931,6 +938,9 @@ void Aura::SetStackAmount(uint8 stackAmount)
|
||||
m_stackAmount = stackAmount;
|
||||
Unit* caster = GetCaster();
|
||||
|
||||
if (!caster)
|
||||
return;
|
||||
|
||||
std::list<AuraApplication*> applications;
|
||||
GetApplicationList(applications);
|
||||
|
||||
|
||||
@@ -121,9 +121,8 @@ public:
|
||||
int32 CalcMaxDuration(Unit* caster) const;
|
||||
int32 GetDuration() const { return m_duration; }
|
||||
void SetDuration(int32 duration, bool withMods = false);
|
||||
void RefreshDuration();
|
||||
void RefreshDuration(bool withMods = false);
|
||||
void RefreshTimers(bool periodicReset = false);
|
||||
void RefreshTimersWithMods();
|
||||
bool IsExpired() const { return !GetDuration();}
|
||||
bool IsPermanent() const { return GetMaxDuration() == -1; }
|
||||
|
||||
|
||||
@@ -506,6 +506,20 @@ void SpellCastTargets::Update(Unit* caster)
|
||||
}
|
||||
}
|
||||
|
||||
class SpellEvent : public BasicEvent
|
||||
{
|
||||
public:
|
||||
SpellEvent(Spell* spell);
|
||||
~SpellEvent();
|
||||
|
||||
bool Execute(uint64 e_time, uint32 p_time);
|
||||
void Abort(uint64 e_time);
|
||||
bool IsDeletable() const;
|
||||
|
||||
protected:
|
||||
Spell* m_Spell;
|
||||
};
|
||||
|
||||
void SpellCastTargets::OutDebug() const
|
||||
{
|
||||
if (!m_targetMask)
|
||||
@@ -543,7 +557,7 @@ SpellValue::SpellValue(SpellInfo const* proto)
|
||||
Spell::Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID, bool skipCheck) :
|
||||
m_spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(info, caster)),
|
||||
m_caster((info->HasAttribute(SPELL_ATTR6_ORIGINATE_FROM_CONTROLLER) && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster)
|
||||
, m_spellValue(new SpellValue(m_spellInfo))
|
||||
, m_spellValue(new SpellValue(m_spellInfo)), _spellEvent(nullptr)
|
||||
{
|
||||
m_customError = SPELL_CUSTOM_ERROR_NONE;
|
||||
m_skipCheck = skipCheck;
|
||||
@@ -825,8 +839,16 @@ void Spell::SelectSpellTargets()
|
||||
|
||||
if (m_spellInfo->IsChanneled())
|
||||
{
|
||||
// maybe do this for all spells?
|
||||
if (!focusObject && m_UniqueTargetInfo.empty() && m_UniqueGOTargetInfo.empty() && m_UniqueItemInfo.empty() && !m_targets.HasDst())
|
||||
{
|
||||
SendCastResult(SPELL_FAILED_BAD_IMPLICIT_TARGETS);
|
||||
finish(false);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 mask = (1 << i);
|
||||
for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
|
||||
for (auto ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
|
||||
{
|
||||
if (ihit->effectMask & mask)
|
||||
{
|
||||
@@ -838,22 +860,18 @@ void Spell::SelectSpellTargets()
|
||||
else if (m_auraScaleMask)
|
||||
{
|
||||
bool checkLvl = !m_UniqueTargetInfo.empty();
|
||||
for (std::list<TargetInfo>::iterator itr = m_UniqueTargetInfo.begin(); itr != m_UniqueTargetInfo.end(); ++itr)
|
||||
m_UniqueTargetInfo.erase(std::remove_if(std::begin(m_UniqueTargetInfo), std::end(m_UniqueTargetInfo), [&](TargetInfo const& targetInfo) -> bool
|
||||
{
|
||||
// remove targets which did not pass min level check
|
||||
if (m_auraScaleMask && itr->effectMask == m_auraScaleMask)
|
||||
if (m_auraScaleMask && targetInfo.effectMask == m_auraScaleMask)
|
||||
{
|
||||
bool needErase = false;
|
||||
|
||||
if (!itr->scaleAura && itr->targetGUID != m_caster->GetGUID())
|
||||
needErase = true;
|
||||
|
||||
sScriptMgr->OnRemoveAuraScaleTargets(this, *itr, m_auraScaleMask, needErase);
|
||||
|
||||
if (needErase)
|
||||
m_UniqueTargetInfo.erase(itr);
|
||||
if (!targetInfo.scaleAura && targetInfo.targetGUID != m_caster->GetGUID())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}), std::end(m_UniqueTargetInfo));
|
||||
|
||||
if (checkLvl && m_UniqueTargetInfo.empty())
|
||||
{
|
||||
SendCastResult(SPELL_FAILED_LOWLEVEL);
|
||||
@@ -862,20 +880,35 @@ void Spell::SelectSpellTargets()
|
||||
}
|
||||
}
|
||||
|
||||
if (uint64 dstDelay = CalculateDelayMomentForDst())
|
||||
m_delayMoment = dstDelay;
|
||||
}
|
||||
|
||||
uint64 Spell::CalculateDelayMomentForDst() const
|
||||
{
|
||||
if (m_targets.HasDst())
|
||||
{
|
||||
if (m_targets.HasTraj())
|
||||
{
|
||||
float speed = m_targets.GetSpeedXY();
|
||||
if (speed > 0.0f)
|
||||
m_delayTrajectory = (uint64)floor(m_targets.GetDist2d() / speed * 1000.0f);
|
||||
return (uint64)floor(m_targets.GetDist2d() / speed * 1000.0f);
|
||||
}
|
||||
else if (m_spellInfo->Speed > 0.0f)
|
||||
{
|
||||
float dist = m_caster->GetExactDist(m_targets.GetDstPos());
|
||||
m_delayTrajectory = (uint64) floor(dist / m_spellInfo->Speed * 1000.0f);
|
||||
// We should not subtract caster size from dist calculation (fixes execution time desync with animation on client, eg. Malleable Goo cast by PP)
|
||||
float dist = m_caster->GetExactDist(*m_targets.GetDstPos());
|
||||
return (uint64)std::floor(dist / m_spellInfo->Speed * 1000.0f);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Spell::RecalculateDelayMomentForDst()
|
||||
{
|
||||
m_delayMoment = CalculateDelayMomentForDst();
|
||||
m_caster->m_Events.ModifyEventTime(_spellEvent, Milliseconds(GetDelayStart() + m_delayMoment));
|
||||
}
|
||||
|
||||
void Spell::SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32& processedEffectMask)
|
||||
@@ -898,11 +931,12 @@ void Spell::SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTar
|
||||
for (uint32 j = effIndex + 1; j < MAX_SPELL_EFFECTS; ++j)
|
||||
{
|
||||
SpellEffectInfo const* effects = GetSpellInfo()->Effects;
|
||||
if (effects[effIndex].TargetA.GetTarget() == effects[j].TargetA.GetTarget() &&
|
||||
effects[effIndex].TargetB.GetTarget() == effects[j].TargetB.GetTarget() &&
|
||||
effects[effIndex].ImplicitTargetConditions == effects[j].ImplicitTargetConditions &&
|
||||
effects[effIndex].CalcRadius(m_caster) == effects[j].CalcRadius(m_caster) &&
|
||||
CheckScriptEffectImplicitTargets(effIndex, j))
|
||||
if (effects[j].IsEffect() &&
|
||||
effects[effIndex].TargetA.GetTarget() == effects[j].TargetA.GetTarget() &&
|
||||
effects[effIndex].TargetB.GetTarget() == effects[j].TargetB.GetTarget() &&
|
||||
effects[effIndex].ImplicitTargetConditions == effects[j].ImplicitTargetConditions &&
|
||||
effects[effIndex].CalcRadius(m_caster) == effects[j].CalcRadius(m_caster) &&
|
||||
CheckScriptEffectImplicitTargets(effIndex, j))
|
||||
{
|
||||
effectMask |= 1 << j;
|
||||
}
|
||||
@@ -928,9 +962,8 @@ void Spell::SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTar
|
||||
SelectImplicitAreaTargets(effIndex, targetType, effectMask);
|
||||
break;
|
||||
case TARGET_SELECT_CATEGORY_TRAJ:
|
||||
// xinef: just in case there is no dest, explanation in SelectImplicitDestDestTargets
|
||||
if (!m_targets.HasDst())
|
||||
m_targets.SetDst(*m_caster);
|
||||
// just in case there is no dest, explanation in SelectImplicitDestDestTargets
|
||||
CheckDst();
|
||||
|
||||
SelectImplicitTrajTargets(effIndex, targetType);
|
||||
break;
|
||||
@@ -1513,7 +1546,7 @@ void Spell::SelectImplicitCasterObjectTargets(SpellEffIndex effIndex, SpellImpli
|
||||
break;
|
||||
case TARGET_UNIT_SUMMONER:
|
||||
if (m_caster->IsSummon())
|
||||
target = m_caster->ToTempSummon()->GetSummoner();
|
||||
target = m_caster->ToTempSummon()->GetSummonerUnit();
|
||||
break;
|
||||
case TARGET_UNIT_VEHICLE:
|
||||
target = m_caster->GetVehicleBase();
|
||||
@@ -3208,8 +3241,8 @@ SpellCastResult Spell::prepare(SpellCastTargets const* targets, AuraEffect const
|
||||
}
|
||||
|
||||
// create and add update event for this spell
|
||||
SpellEvent* Event = new SpellEvent(this);
|
||||
m_caster->m_Events.AddEvent(Event, m_caster->m_Events.CalculateTime(1));
|
||||
_spellEvent = new SpellEvent(this);
|
||||
m_caster->m_Events.AddEvent(_spellEvent, m_caster->m_Events.CalculateTime(1));
|
||||
|
||||
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, m_caster))
|
||||
{
|
||||
|
||||
@@ -20,7 +20,9 @@ class DynamicObject;
|
||||
class WorldObject;
|
||||
class Aura;
|
||||
class SpellScript;
|
||||
class SpellEvent;
|
||||
class ByteBuffer;
|
||||
class BasicEvent;
|
||||
|
||||
#define SPELL_CHANNEL_UPDATE_INTERVAL (1 * IN_MILLISECONDS)
|
||||
|
||||
@@ -521,6 +523,8 @@ public:
|
||||
uint64 GetDelayMoment() const { return m_delayMoment; }
|
||||
uint64 GetDelayTrajectory() const { return m_delayTrajectory; }
|
||||
|
||||
uint64 CalculateDelayMomentForDst() const;
|
||||
void RecalculateDelayMomentForDst();
|
||||
bool IsNeedSendToClient(bool go) const;
|
||||
|
||||
CurrentSpellTypes GetCurrentContainer() const;
|
||||
@@ -710,6 +714,7 @@ protected:
|
||||
uint32 m_spellState;
|
||||
int32 m_timer;
|
||||
|
||||
SpellEvent* _spellEvent;
|
||||
TriggerCastFlags _triggeredCastFlags;
|
||||
|
||||
// if need this can be replaced by Aura copy
|
||||
@@ -788,29 +793,16 @@ namespace Acore
|
||||
|
||||
typedef void(Spell::*pEffect)(SpellEffIndex effIndex);
|
||||
|
||||
class SpellEvent : public BasicEvent
|
||||
{
|
||||
public:
|
||||
SpellEvent(Spell* spell);
|
||||
~SpellEvent() override;
|
||||
|
||||
bool Execute(uint64 e_time, uint32 p_time) override;
|
||||
void Abort(uint64 e_time) override;
|
||||
bool IsDeletable() const override;
|
||||
protected:
|
||||
Spell* m_Spell;
|
||||
};
|
||||
|
||||
class ReflectEvent : public BasicEvent
|
||||
{
|
||||
public:
|
||||
ReflectEvent(Unit* caster, ObjectGuid targetGUID, const SpellInfo* spellInfo) : _caster(caster), _targetGUID(targetGUID), _spellInfo(spellInfo) { }
|
||||
bool Execute(uint64 e_time, uint32 p_time) override;
|
||||
public:
|
||||
ReflectEvent(Unit* caster, ObjectGuid targetGUID, const SpellInfo* spellInfo) : _caster(caster), _targetGUID(targetGUID), _spellInfo(spellInfo) { }
|
||||
bool Execute(uint64 e_time, uint32 p_time) override;
|
||||
|
||||
protected:
|
||||
Unit* _caster;
|
||||
ObjectGuid _targetGUID;
|
||||
const SpellInfo* _spellInfo;
|
||||
protected:
|
||||
Unit* _caster;
|
||||
ObjectGuid _targetGUID;
|
||||
const SpellInfo* _spellInfo;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -840,8 +840,9 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry)
|
||||
SchoolMask = spellEntry->SchoolMask;
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
Effects[i] = SpellEffectInfo(spellEntry, this, i);
|
||||
ExplicitTargetMask = _GetExplicitTargetMask();
|
||||
|
||||
ChainEntry = nullptr;
|
||||
ExplicitTargetMask = 0;
|
||||
|
||||
// Mine
|
||||
_isStackableWithRanks = false;
|
||||
@@ -2537,7 +2538,7 @@ bool SpellInfo::IsHighRankOf(SpellInfo const* spellInfo) const
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 SpellInfo::_GetExplicitTargetMask() const
|
||||
void SpellInfo::_InitializeExplicitTargetMask()
|
||||
{
|
||||
bool srcSet = false;
|
||||
bool dstSet = false;
|
||||
@@ -2562,7 +2563,7 @@ uint32 SpellInfo::_GetExplicitTargetMask() const
|
||||
effectTargetMask &= ~(TARGET_FLAG_UNIT_MASK | TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_CORPSE_MASK | TARGET_FLAG_DEST_LOCATION);
|
||||
targetMask |= effectTargetMask;
|
||||
}
|
||||
return targetMask;
|
||||
ExplicitTargetMask = targetMask;
|
||||
}
|
||||
|
||||
bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const
|
||||
|
||||
@@ -503,7 +503,7 @@ public:
|
||||
bool IsHighRankOf(SpellInfo const* spellInfo) const;
|
||||
|
||||
// loading helpers
|
||||
uint32 _GetExplicitTargetMask() const;
|
||||
void _InitializeExplicitTargetMask();
|
||||
bool _IsPositiveEffect(uint8 effIndex, bool deep) const;
|
||||
bool _IsPositiveSpell() const;
|
||||
static bool _IsPositiveTarget(uint32 targetA, uint32 targetB);
|
||||
|
||||
@@ -2665,10 +2665,8 @@ void SpellMgr::LoadSpellInfoStore()
|
||||
void SpellMgr::UnloadSpellInfoStore()
|
||||
{
|
||||
for (uint32 i = 0; i < mSpellInfoMap.size(); ++i)
|
||||
{
|
||||
if (mSpellInfoMap[i])
|
||||
delete mSpellInfoMap[i];
|
||||
}
|
||||
delete mSpellInfoMap[i];
|
||||
|
||||
mSpellInfoMap.clear();
|
||||
}
|
||||
|
||||
@@ -3282,6 +3280,7 @@ void SpellMgr::LoadSpellCustomAttr()
|
||||
spellInfo->Effects[EFFECT_0].MiscValue = 127;
|
||||
break;
|
||||
}
|
||||
spellInfo->_InitializeExplicitTargetMask();
|
||||
}
|
||||
|
||||
// Xinef: addition for binary spells, ommit spells triggering other spells
|
||||
|
||||
Reference in New Issue
Block a user