aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp10
-rw-r--r--src/server/game/Spells/Spell.cpp81
-rw-r--r--src/server/game/Spells/SpellEffects.cpp12
-rw-r--r--src/server/game/Spells/SpellInfo.cpp6
-rw-r--r--src/server/game/Spells/SpellInfo.h2
5 files changed, 69 insertions, 42 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 3e6be7289ec..89d545458ca 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -6324,10 +6324,16 @@ Unit* Unit::GetMagicHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo)
&& _IsValidAttackTarget(magnet, spellInfo))
{
/// @todo handle this charge drop by proc in cast phase on explicit target
- if (spellInfo->Speed > 0.0f)
+ if (spellInfo->HasHitDelay())
{
// Set up missile speed based delay
- uint32 delay = uint32(std::floor(std::max<float>(victim->GetDistance(this), 5.0f) / spellInfo->Speed * 1000.0f));
+ float hitDelay = spellInfo->LaunchDelay;
+ if (spellInfo->HasAttribute(SPELL_ATTR9_SPECIAL_DELAY_CALCULATION))
+ hitDelay += spellInfo->Speed;
+ else if (spellInfo->Speed > 0.0f)
+ hitDelay += std::max(victim->GetDistance(this), 5.0f) / spellInfo->Speed;
+
+ uint32 delay = uint32(std::floor(hitDelay * 1000.0f));
// Schedule charge drop
(*itr)->GetBase()->DropChargeDelayed(delay, AURA_REMOVE_BY_EXPIRE);
}
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 73113822149..c32a202662b 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -806,17 +806,18 @@ uint64 Spell::CalculateDelayMomentForDst() const
{
float speed = m_targets.GetSpeedXY();
if (speed > 0.0f)
- return (uint64)floor(m_targets.GetDist2d() / speed * 1000.0f);
+ return uint64(std::floor((m_targets.GetDist2d() / speed + m_spellInfo->LaunchDelay) * 1000.0f));
}
+ else if (m_spellInfo->HasAttribute(SPELL_ATTR9_SPECIAL_DELAY_CALCULATION))
+ return uint64(std::floor((m_spellInfo->Speed + m_spellInfo->LaunchDelay) * 1000.0f));
else if (m_spellInfo->Speed > 0.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());
- if (!m_spellInfo->HasAttribute(SPELL_ATTR9_SPECIAL_DELAY_CALCULATION))
- return (uint64)std::floor(dist / m_spellInfo->Speed * 1000.0f);
- else
- return (uint64)std::floor(m_spellInfo->Speed * 1000.0f);
+ return uint64(std::floor((dist / m_spellInfo->Speed + m_spellInfo->LaunchDelay) * 1000.0f));
}
+
+ return uint64(std::floor(m_spellInfo->LaunchDelay * 1000.0f));
}
return 0;
@@ -2082,19 +2083,20 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
// Spell have speed - need calculate incoming time
// Incoming time is zero for self casts. At least I think so.
- if (m_spellInfo->Speed > 0.0f && m_caster != target)
+ if (m_caster != target)
{
- // calculate spell incoming interval
- /// @todo this is a hack
- float dist = m_caster->GetDistance(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ());
-
- if (dist < 5.0f)
- dist = 5.0f;
+ float hitDelay = m_spellInfo->LaunchDelay;
+ if (m_spellInfo->HasAttribute(SPELL_ATTR9_SPECIAL_DELAY_CALCULATION))
+ hitDelay += m_spellInfo->Speed;
+ else if (m_spellInfo->Speed > 0.0f)
+ {
+ // calculate spell incoming interval
+ /// @todo this is a hack
+ float dist = std::max(m_caster->GetDistance(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()), 5.0f);
+ hitDelay += dist / m_spellInfo->Speed;
+ }
- if (!m_spellInfo->HasAttribute(SPELL_ATTR9_SPECIAL_DELAY_CALCULATION))
- targetInfo.timeDelay = uint64(std::floor(dist / m_spellInfo->Speed * 1000.0f));
- else
- targetInfo.timeDelay = uint64(m_spellInfo->Speed * 1000.0f);
+ targetInfo.timeDelay = uint64(std::floor(hitDelay * 1000.0f));
}
else
targetInfo.timeDelay = 0ULL;
@@ -2155,23 +2157,22 @@ void Spell::AddGOTarget(GameObject* go, uint32 effectMask)
target.processed = false; // Effects not apply on target
// Spell have speed - need calculate incoming time
- if (m_spellInfo->Speed > 0.0f)
+ if (static_cast<WorldObject*>(m_caster) != go)
{
- // calculate spell incoming interval
- float dist = m_caster->GetDistance(go->GetPositionX(), go->GetPositionY(), go->GetPositionZ());
- if (dist < 5.0f)
- dist = 5.0f;
-
- if (!m_spellInfo->HasAttribute(SPELL_ATTR9_SPECIAL_DELAY_CALCULATION))
- target.timeDelay = uint64(floor(dist / m_spellInfo->Speed * 1000.0f));
- else
- target.timeDelay = uint64(m_spellInfo->Speed * 1000.0f);
+ float hitDelay = m_spellInfo->LaunchDelay;
+ if (m_spellInfo->HasAttribute(SPELL_ATTR9_SPECIAL_DELAY_CALCULATION))
+ hitDelay += m_spellInfo->Speed;
+ else if (m_spellInfo->Speed > 0.0f)
+ {
+ // calculate spell incoming interval
+ float dist = std::max(m_caster->GetDistance(go->GetPositionX(), go->GetPositionY(), go->GetPositionZ()), 5.0f);
+ hitDelay += dist / m_spellInfo->Speed;
+ }
- if (!m_delayMoment || m_delayMoment > target.timeDelay)
- m_delayMoment = target.timeDelay;
+ target.timeDelay = uint64(std::floor(hitDelay * 1000.0f));
}
else
- target.timeDelay = 0LL;
+ target.timeDelay = 0ULL;
// Add target to list
m_UniqueGOTargetInfo.push_back(target);
@@ -2510,7 +2511,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask)
return SPELL_MISS_EVADE;
// For delayed spells immunity may be applied between missile launch and hit - check immunity for that case
- if (m_spellInfo->Speed && unit->IsImmunedToSpell(m_spellInfo, m_caster))
+ if (m_spellInfo->HasHitDelay() && unit->IsImmunedToSpell(m_spellInfo, m_caster))
return SPELL_MISS_IMMUNE;
// disable effects to which unit is immune
@@ -2539,7 +2540,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask)
if (m_caster != unit)
{
// Recheck UNIT_FLAG_NON_ATTACKABLE for delayed spells
- if (m_spellInfo->Speed > 0.0f && unit->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE) && unit->GetCharmerOrOwnerGUID() != m_caster->GetGUID())
+ if (m_spellInfo->HasHitDelay() && unit->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE) && unit->GetCharmerOrOwnerGUID() != m_caster->GetGUID())
return SPELL_MISS_EVADE;
if (m_caster->_IsValidAttackTarget(unit, m_spellInfo))
@@ -2549,7 +2550,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask)
// for delayed spells ignore negative spells (after duel end) for friendly targets
/// @todo this cause soul transfer bugged
// 63881 - Malady of the Mind jump spell (Yogg-Saron)
- if (m_spellInfo->Speed > 0.0f && unit->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->IsPositive() && m_spellInfo->Id != 63881)
+ if (m_spellInfo->HasHitDelay() && unit->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->IsPositive() && m_spellInfo->Id != 63881)
return SPELL_MISS_EVADE;
// assisting case, healing and resurrection
@@ -3229,7 +3230,7 @@ void Spell::_cast(bool skipCheck)
SendSpellGo();
// Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
- if ((m_spellInfo->Speed > 0.0f && !m_spellInfo->IsChanneled()) || m_spellInfo->HasAttribute(SPELL_ATTR4_UNK4))
+ if ((m_spellInfo->HasHitDelay() && !m_spellInfo->IsChanneled()) || m_spellInfo->HasAttribute(SPELL_ATTR4_UNK4))
{
// Remove used for cast item if need (it can be already NULL after TakeReagents call
// in case delayed spell remove item at cast delay start
@@ -6923,23 +6924,23 @@ bool Spell::CheckEffectTarget(Unit const* target, SpellEffectInfo const* effect,
{
if (target->IsWithinLOSInMap(m_caster, VMAP::ModelIgnoreFlags::M2) && target->HasUnitFlag(UNIT_FLAG_SKINNABLE))
return true;
-
+
return false;
}
-
+
Corpse* corpse = ObjectAccessor::GetCorpse(*m_caster, m_targets.GetCorpseTargetGUID());
if (!corpse)
return false;
-
+
if (target->GetGUID() != corpse->GetOwnerGUID())
return false;
-
+
if (!corpse->HasDynamicFlag(CORPSE_DYNFLAG_LOOTABLE))
return false;
-
+
if (!corpse->IsWithinLOSInMap(m_caster, VMAP::ModelIgnoreFlags::M2))
return false;
-
+
break;
}
default:
@@ -7026,7 +7027,7 @@ bool Spell::IsAutoActionResetSpell() const
bool Spell::IsNeedSendToClient() const
{
return m_SpellVisual || m_spellInfo->IsChanneled() ||
- (m_spellInfo->HasAttribute(SPELL_ATTR8_AURA_SEND_AMOUNT)) || m_spellInfo->Speed > 0.0f || (!m_triggeredByAuraSpell && !IsTriggered());
+ (m_spellInfo->HasAttribute(SPELL_ATTR8_AURA_SEND_AMOUNT)) || m_spellInfo->HasHitDelay() || (!m_triggeredByAuraSpell && !IsTriggered());
}
bool Spell::HaveTargetsForEffect(uint8 effect) const
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 7ac90a7fa64..e195fd9f146 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -4227,6 +4227,7 @@ void Spell::EffectCharge(SpellEffIndex /*effIndex*/)
m_caster->ToPlayer()->SetFallInformation(0, m_caster->GetPositionZ());
float speed = G3D::fuzzyGt(m_spellInfo->Speed, 0.0f) ? m_spellInfo->Speed : SPEED_CHARGE;
+
Optional<Movement::SpellEffectExtraData> spellEffectExtraData;
if (effectInfo->MiscValueB)
{
@@ -4239,10 +4240,21 @@ void Spell::EffectCharge(SpellEffIndex /*effIndex*/)
{
//unitTarget->GetContactPoint(m_caster, pos.m_positionX, pos.m_positionY, pos.m_positionZ);
Position pos = unitTarget->GetFirstCollisionPosition(unitTarget->GetObjectSize(), unitTarget->GetRelativeAngle(m_caster));
+ if (m_spellInfo->HasAttribute(SPELL_ATTR9_SPECIAL_DELAY_CALCULATION))
+ speed = pos.GetExactDist(m_caster) / speed;
+
m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speed, EVENT_CHARGE, false, unitTarget, spellEffectExtraData.get_ptr());
}
else
+ {
+ if (m_spellInfo->HasAttribute(SPELL_ATTR9_SPECIAL_DELAY_CALCULATION))
+ {
+ G3D::Vector3 pos = m_preGeneratedPath->GetActualEndPosition();
+ speed = Position(pos.x, pos.y, pos.z).GetExactDist(m_caster) / speed;
+ }
+
m_caster->GetMotionMaster()->MoveCharge(*m_preGeneratedPath, speed, unitTarget, spellEffectExtraData.get_ptr());
+ }
}
if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT_TARGET)
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index c93ceb775d1..e231c194522 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -1078,6 +1078,7 @@ SpellInfo::SpellInfo(SpellInfoLoadHelper const& data, SpellEffectEntryMap const&
RangeIndex = _misc ? _misc->RangeIndex : 0;
RangeEntry = _misc ? (_misc->RangeIndex ? sSpellRangeStore.LookupEntry(_misc->RangeIndex) : NULL) : NULL;
Speed = _misc ? _misc->Speed : 0;
+ LaunchDelay = _misc ? _misc->LaunchDelay : 0;
SchoolMask = _misc ? _misc->SchoolMask : 0;
AttributesCu = 0;
IconFileDataId = _misc ? _misc->SpellIconFileDataID : 0;
@@ -1659,6 +1660,11 @@ bool SpellInfo::HasInitialAggro() const
return !(HasAttribute(SPELL_ATTR1_NO_THREAT) || HasAttribute(SPELL_ATTR3_NO_INITIAL_AGGRO));
}
+bool SpellInfo::HasHitDelay() const
+{
+ return Speed > 0.0f || LaunchDelay > 0.0f;
+}
+
WeaponAttackType SpellInfo::GetAttackType() const
{
WeaponAttackType result;
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index f253f4ed065..ef2f083e41b 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -488,6 +488,7 @@ class TC_GAME_API SpellInfo
uint32 RangeIndex;
SpellRangeEntry const* RangeEntry;
float Speed;
+ float LaunchDelay;
uint32 StackAmount;
uint32 Totem[MAX_SPELL_TOTEMS];
int32 Reagent[MAX_SPELL_REAGENTS];
@@ -594,6 +595,7 @@ class TC_GAME_API SpellInfo
bool IsRangedWeaponSpell() const;
bool IsAutoRepeatRangedSpell() const;
bool HasInitialAggro() const;
+ bool HasHitDelay() const;
WeaponAttackType GetAttackType() const;