Core/Spells: Implement SpellMisc::LaunchDelay

This commit is contained in:
Traesh
2019-08-31 11:11:23 +02:00
committed by Shauren
parent 7d2cbd4e7c
commit c924840ce7
5 changed files with 69 additions and 42 deletions
+8 -2
View File
@@ -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);
}
+41 -40
View File
@@ -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());
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 (dist < 5.0f)
dist = 5.0f;
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;
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_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);
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
+12
View File
@@ -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)
+6
View File
@@ -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;
+2
View File
@@ -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;