diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 10 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 81 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 12 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 6 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.h | 2 |
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; |