summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Object/Position.cpp7
-rw-r--r--src/server/game/Entities/Object/Position.h1
-rw-r--r--src/server/game/Handlers/SpellHandler.cpp3
-rw-r--r--src/server/game/Spells/Spell.cpp164
-rw-r--r--src/server/game/Spells/Spell.h1
-rw-r--r--src/server/game/Spells/SpellMgr.cpp9
-rw-r--r--src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp44
-rw-r--r--src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_utgarde_pinnacle.cpp15
8 files changed, 85 insertions, 159 deletions
diff --git a/src/server/game/Entities/Object/Position.cpp b/src/server/game/Entities/Object/Position.cpp
index fee50be6e8..65c2ede216 100644
--- a/src/server/game/Entities/Object/Position.cpp
+++ b/src/server/game/Entities/Object/Position.cpp
@@ -42,9 +42,16 @@ void Position::RelocatePolarOffset(float angle, float dist, float z /*= 0.0f*/)
bool Position::HasInLine(Position const* pos, float width) const
{
+ return HasInLine(pos, 0, width);
+}
+
+bool Position::HasInLine(Position const* pos, float objSize, float width) const
+{
if (!HasInArc(float(M_PI), pos))
return false;
+ width += objSize;
+
float angle = GetRelativeAngle(pos);
return std::fabs(std::sin(angle)) * GetExactDist2d(pos->GetPositionX(), pos->GetPositionY()) < width;
}
diff --git a/src/server/game/Entities/Object/Position.h b/src/server/game/Entities/Object/Position.h
index 39751a12a8..baeff5a80d 100644
--- a/src/server/game/Entities/Object/Position.h
+++ b/src/server/game/Entities/Object/Position.h
@@ -231,6 +231,7 @@ struct Position
[[nodiscard]] bool IsWithinBox(const Position& center, float xradius, float yradius, float zradius) const;
bool HasInArc(float arcangle, const Position* pos, float targetRadius = 0.0f) const;
bool HasInLine(Position const* pos, float width) const;
+ bool HasInLine(Position const* pos, float objSize, float width) const;
[[nodiscard]] std::string ToString() const;
// modulos a radian orientation to the range of 0..2PI
diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp
index 7d6b5bd2e8..6117637db6 100644
--- a/src/server/game/Handlers/SpellHandler.cpp
+++ b/src/server/game/Handlers/SpellHandler.cpp
@@ -855,6 +855,9 @@ void WorldSession::HandleUpdateProjectilePosition(WorldPacket& recvPacket)
pos.Relocate(x, y, z);
spell->m_targets.ModDst(pos);
+ // we changed dest, recalculate flight time
+ spell->RecalculateDelayMomentForDst();
+
WorldPacket data(SMSG_SET_PROJECTILE_POSITION, 21);
data << casterGuid;
data << uint8(castCount);
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index e851a039b4..4ae8bfca43 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -1744,9 +1744,6 @@ void Spell::SelectImplicitDestDestTargets(SpellEffIndex effIndex, SpellImplicitT
case TARGET_DEST_DYNOBJ_NONE:
case TARGET_DEST_DEST:
return;
- case TARGET_DEST_TRAJ:
- SelectImplicitTrajTargets(effIndex, targetType);
- return;
default:
{
float angle = targetType.CalcDirectionAngle();
@@ -1885,14 +1882,14 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex, SpellImplicitTarge
if (!dist2d)
return;
- float srcToDestDelta = m_targets.GetDstPos()->m_positionZ - m_targets.GetSrcPos()->m_positionZ;
+ Position srcPos = *m_targets.GetSrcPos();
+ srcPos.SetOrientation(m_caster->GetOrientation());
+ float srcToDestDelta = m_targets.GetDstPos()->m_positionZ - srcPos.m_positionZ;
- // xinef: supply correct target type, DEST_DEST and similar are ALWAYS undefined
- // xinef: correct target is stored in TRIGGERED SPELL, however as far as i noticed, all checks are ENTRY, ENEMY
std::list<WorldObject*> targets;
- Acore::WorldObjectSpellTrajTargetCheck check(dist2d, m_targets.GetSrcPos(), m_caster, m_spellInfo, TARGET_CHECK_ENEMY /*targetCheckType*/, m_spellInfo->Effects[effIndex].ImplicitTargetConditions);
+ Acore::WorldObjectSpellTrajTargetCheck check(dist2d, &srcPos, m_caster, m_spellInfo, targetType.GetCheckType(), m_spellInfo->Effects[effIndex].ImplicitTargetConditions);
Acore::WorldObjectListSearcher<Acore::WorldObjectSpellTrajTargetCheck> searcher(m_caster, targets, check, GRID_MAP_TYPE_MASK_ALL);
- SearchTargets<Acore::WorldObjectListSearcher<Acore::WorldObjectSpellTrajTargetCheck> > (searcher, GRID_MAP_TYPE_MASK_ALL, m_caster, m_targets.GetSrcPos(), dist2d);
+ SearchTargets<Acore::WorldObjectListSearcher<Acore::WorldObjectSpellTrajTargetCheck> > (searcher, GRID_MAP_TYPE_MASK_ALL, m_caster, &srcPos, dist2d);
if (targets.empty())
return;
@@ -1901,136 +1898,59 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex, SpellImplicitTarge
float b = tangent(m_targets.GetElevation());
float a = (srcToDestDelta - dist2d * b) / (dist2d * dist2d);
if (a > -0.0001f)
- a = 0;
-
- LOG_DEBUG("spells", "Spell::SelectTrajTargets: a {} b {}", a, b);
+ a = 0.f;
- // Xinef: hack for distance, many trajectory spells have RangeEntry 1 (self)
- float bestDist = m_spellInfo->GetMaxRange(false) * 2;
- if (bestDist < 1.0f)
- bestDist = 300.0f;
+ // We should check if triggered spell has greater range (which is true in many cases, and initial spell has too short max range)
+ // limit max range to 300 yards, sometimes triggered spells can have 50000yds
+ float bestDist = m_spellInfo->GetMaxRange(false);
+ if (SpellInfo const* triggerSpellInfo = sSpellMgr->GetSpellInfo(m_spellInfo->Effects[effIndex].TriggerSpell))
+ bestDist = std::min(std::max(bestDist, triggerSpellInfo->GetMaxRange(false)), std::min(dist2d, 300.0f));
- std::list<WorldObject*>::const_iterator itr = targets.begin();
- for (; itr != targets.end(); ++itr)
+ // GameObjects don't cast traj
+ Unit* unitCaster = ASSERT_NOTNULL(m_caster->ToUnit());
+ for (auto itr = targets.begin(); itr != targets.end(); ++itr)
{
- if (Unit* unitTarget = (*itr)->ToUnit())
- if (m_caster == *itr || m_caster->IsOnVehicle(unitTarget) || (unitTarget)->GetVehicle())//(*itr)->IsOnVehicle(m_caster))
- continue;
-
- const float size = std::max((*itr)->GetObjectSize() * 0.7f, 1.0f); // 1/sqrt(3)
- /// @todo: all calculation should be based on src instead of m_caster
- const float objDist2d = std::fabs(m_targets.GetSrcPos()->GetExactDist2d(*itr) * cos(m_targets.GetSrcPos()->GetRelativeAngle(*itr)));
- const float dz = std::fabs((*itr)->GetPositionZ() - m_targets.GetSrcPos()->m_positionZ);
-
- LOG_DEBUG("spells", "Spell::SelectTrajTargets: check {}, dist between {} {}, height between {} {}.",
- (*itr)->GetEntry(), objDist2d - size, objDist2d + size, dz - size, dz + size);
-
- float dist = objDist2d - size;
- float height = dist * (a * dist + b);
-
- LOG_DEBUG("spells", "Spell::SelectTrajTargets: dist {}, height {}.", dist, height);
-
- if (dist < bestDist && height < dz + size && height > dz - size)
- {
- bestDist = dist > 0 ? dist : 0;
- break;
- }
-
-#define CHECK_DIST {\
- LOG_DEBUG("spells", "Spell::SelectTrajTargets: dist {}, height {}.", dist, height);\
- if (dist > bestDist)\
- continue;\
- if (dist < objDist2d + size && dist > objDist2d - size)\
- {\
- bestDist = dist;\
- break;\
- }\
- }
-
- // RP-GG only, search in straight line, as item have no trajectory
- if (m_CastItem)
- {
- if (dist < bestDist && std::fabs(dz) < 6.0f) // closes target, also check Z difference)
- {
- bestDist = dist;
- break;
- }
-
+ if (m_spellInfo->CheckTarget(unitCaster, *itr, true) != SPELL_CAST_OK)
continue;
- }
- if (!a)
+ if (Unit* unit = (*itr)->ToUnit())
{
- // Xinef: everything remade
- dist = m_targets.GetSrcPos()->GetExactDist(*itr);
- height = m_targets.GetSrcPos()->GetExactDist2d(*itr) * b;
+ if (unitCaster == *itr || unitCaster->IsOnVehicle(unit) || unit->GetVehicle())
+ continue;
- if (height < dz + size * (b + 1) && height > dz - size * (b + 1) && dist < bestDist)
+ if (Creature* creatureTarget = unit->ToCreature())
{
- bestDist = dist;
- break;
+ if (!(creatureTarget->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_COLLIDE_WITH_MISSILES))
+ continue;
}
-
- continue;
}
- height = dz - size;
- float sqrt1 = b * b + 4 * a * height;
- if (sqrt1 > 0)
- {
- sqrt1 = std::sqrt(sqrt1);
- dist = (sqrt1 - b) / (2 * a);
- CHECK_DIST;
- }
+ float const size = std::max((*itr)->GetCombatReach(), 1.0f);
+ float const objDist2d = srcPos.GetExactDist2d(*itr);
+ float const dz = (*itr)->GetPositionZ() - srcPos.m_positionZ;
- height = dz + size;
- float sqrt2 = b * b + 4 * a * height;
- if (sqrt2 > 0)
- {
- sqrt2 = std::sqrt(sqrt2);
- dist = (sqrt2 - b) / (2 * a);
- CHECK_DIST;
+ float const horizontalDistToTraj = std::fabs(objDist2d * std::sin(srcPos.GetRelativeAngle(*itr)));
+ float const sizeFactor = std::cos((horizontalDistToTraj / size) * (M_PI / 2.0f));
+ float const distToHitPoint = std::max(objDist2d * std::cos(srcPos.GetRelativeAngle(*itr)) - size * sizeFactor, 0.0f);
+ float const height = distToHitPoint * (a * distToHitPoint + b);
- dist = (-sqrt2 - b) / (2 * a);
- CHECK_DIST;
- }
+ if (fabs(dz - height) > size + b / 2.0f + TRAJECTORY_MISSILE_SIZE)
+ continue;
- if (sqrt1 > 0)
+ if (distToHitPoint < bestDist)
{
- dist = (-sqrt1 - b) / (2 * a);
- CHECK_DIST;
+ bestDist = distToHitPoint;
+ break;
}
}
- if (m_targets.GetSrcPos()->GetExactDist2d(m_targets.GetDstPos()) > bestDist)
+ if (dist2d > bestDist)
{
- float x = m_targets.GetSrcPos()->m_positionX + cos(m_caster->GetOrientation()) * bestDist;
- float y = m_targets.GetSrcPos()->m_positionY + std::sin(m_caster->GetOrientation()) * bestDist;
+ float x = m_targets.GetSrcPos()->m_positionX + std::cos(unitCaster->GetOrientation()) * bestDist;
+ float y = m_targets.GetSrcPos()->m_positionY + std::sin(unitCaster->GetOrientation()) * bestDist;
float z = m_targets.GetSrcPos()->m_positionZ + bestDist * (a * bestDist + b);
- if (itr != targets.end())
- {
- float distSq = (*itr)->GetExactDistSq(x, y, z);
- float sizeSq = (*itr)->GetObjectSize();
- sizeSq *= sizeSq;
- LOG_DEBUG("spells", "Spell::SelectTrajTargets: Initial {} {} {} {} {}", x, y, z, distSq, sizeSq);
- if (distSq > sizeSq)
- {
- float factor = 1 - std::sqrt(sizeSq / distSq);
- x += factor * ((*itr)->GetPositionX() - x);
- y += factor * ((*itr)->GetPositionY() - y);
- z += factor * ((*itr)->GetPositionZ() - z);
-
- distSq = (*itr)->GetExactDistSq(x, y, z);
- LOG_DEBUG("spells", "Spell::SelectTrajTargets: Initial {} {} {} {} {}", x, y, z, distSq, sizeSq);
- }
- }
-
- Position trajDst;
- trajDst.Relocate(x, y, z, m_caster->GetOrientation());
- SpellDestination dest(*m_targets.GetDst());
- dest.Relocate(trajDst);
-
+ SpellDestination dest(x, y, z, unitCaster->GetOrientation());
CallScriptDestinationTargetSelectHandlers(dest, effIndex, targetType);
m_targets.ModDst(dest);
}
@@ -9119,7 +9039,7 @@ namespace Acore
}
else if (_spellInfo->HasAttribute(SPELL_ATTR0_CU_CONE_LINE))
{
- if (!_caster->HasInLine(target, _caster->GetObjectSize() + target->GetObjectSize()))
+ if (!_caster->HasInLine(target, target->GetObjectSize(), _caster->GetObjectSize()))
return false;
}
else
@@ -9139,9 +9059,13 @@ namespace Acore
bool WorldObjectSpellTrajTargetCheck::operator()(WorldObject* target)
{
// return all targets on missile trajectory (0 - size of a missile)
- if (!_caster->HasInLine(target, target->GetObjectSize()))
+ if (!_caster->HasInLine(target, target->GetCombatReach(), TRAJECTORY_MISSILE_SIZE))
return false;
- return WorldObjectSpellAreaTargetCheck::operator ()(target);
+
+ if (target->GetExactDist2d(_position) > _range)
+ return false;
+
+ return WorldObjectSpellTargetCheck::operator ()(target);
}
} //namespace Acore
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index bb8f2cb7bb..3025e803e6 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -39,6 +39,7 @@ class ByteBuffer;
class BasicEvent;
#define SPELL_CHANNEL_UPDATE_INTERVAL (1 * IN_MILLISECONDS)
+#define TRAJECTORY_MISSILE_SIZE 3.0f
enum SpellCastFlags
{
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 534388fd4f..b9ee0a9b31 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3405,15 +3405,6 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
}
// Xinef: Cooldown overwrites
- // Jotunheim Rapid-Fire Harpoon: Energy Reserve
- case 56585:
- spellInfo->RecoveryTime = 30000;
- spellInfo->_requireCooldownInfo = true;
- break;
- // Jotunheim Rapid-Fire Harpoon: Rapid-Fire Harpoon
- case 56570:
- spellInfo->RecoveryTime = 200;
- break;
// Burst of Speed
case 57493:
spellInfo->RecoveryTime = 60000;
diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp
index c67253561e..cf6318747d 100644
--- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp
+++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp
@@ -143,10 +143,7 @@ public:
SecondPhase = false;
EventStarted = false;
- me->RemoveAllAuras();
- me->SetControlled(false, UNIT_STATE_ROOT);
- me->UpdatePosition(343.02f, -507.325f, 104.567f, M_PI, true);
- me->StopMovingOnCurrentPos();
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
if (m_pInstance)
{
@@ -160,29 +157,28 @@ public:
Creature* GetGrauf() { return ObjectAccessor::GetCreature(*me, GraufGUID); }
- void JustEngagedWith(Unit* /*pWho*/) override
+ void DoAction(int32 param) override
{
- if (!EventStarted)
+ if (param == ACTION_START_EVENT)
{
- EventStarted = true;
- Talk(SAY_AGGRO);
- if (m_pInstance)
+ if (!EventStarted)
{
- if (IsHeroic())
- m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_LODI_DODI);
+ EventStarted = true;
+ Talk(SAY_AGGRO);
+ if (m_pInstance)
+ {
+ if (IsHeroic())
+ m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_LODI_DODI);
- m_pInstance->SetData(DATA_SKADI_THE_RUTHLESS, IN_PROGRESS);
- }
+ m_pInstance->SetData(DATA_SKADI_THE_RUTHLESS, IN_PROGRESS);
+ }
- me->SetControlled(true, UNIT_STATE_ROOT);
- me->SetInCombatWithZone();
- events.RescheduleEvent(EVENT_SKADI_START, 2s);
+ me->SetControlled(true, UNIT_STATE_ROOT);
+ me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ events.RescheduleEvent(EVENT_SKADI_START, 2s);
+ }
}
- }
-
- void DoAction(int32 param) override
- {
- if (param == ACTION_PHASE2)
+ else if (param == ACTION_PHASE2)
{
SecondPhase = true;
events.ScheduleEvent(EVENT_SKADI_CRUSH, 8s);
@@ -190,7 +186,7 @@ public:
events.ScheduleEvent(EVENT_SKADI_WHIRLWIND, 15s);
if (me->GetVictim())
- me->GetMotionMaster()->MoveChase(me->GetVictim());
+ me->ResumeChasingVictim();
else
me->SetInCombatWithZone();
}
@@ -415,7 +411,7 @@ public:
Map::PlayerList const& pList = me->GetMap()->GetPlayers();
for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr)
{
- if (itr->GetSource()->GetPositionX() < 320.0f || itr->GetSource()->IsGameMaster() || !itr->GetSource()->IsAlive())
+ if (itr->GetSource()->GetPositionY() > -490.0f || itr->GetSource()->IsGameMaster() || !itr->GetSource()->IsAlive())
continue;
return;
@@ -456,7 +452,7 @@ public:
SpawnHelpers(0);
SpawnHelpers(0);
- events.ScheduleEvent(EVENT_GRAUF_MOVE, 15s);
+ events.ScheduleEvent(EVENT_GRAUF_MOVE, 5s);
events.ScheduleEvent(EVENT_GRAUF_SUMMON_HELPERS, 20s);
break;
}
diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_utgarde_pinnacle.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_utgarde_pinnacle.cpp
index 5a36f5e841..47588a7bf8 100644
--- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_utgarde_pinnacle.cpp
+++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_utgarde_pinnacle.cpp
@@ -20,6 +20,12 @@
#include "ScriptedCreature.h"
#include "utgarde_pinnacle.h"
+ObjectData const creatureData[] =
+{
+ { NPC_SKADI_THE_RUTHLESS, DATA_SKADI_THE_RUTHLESS },
+ { 0, 0 }
+};
+
class instance_utgarde_pinnacle : public InstanceMapScript
{
public:
@@ -36,7 +42,6 @@ public:
ObjectGuid SvalaSorrowgrave;
ObjectGuid GortokPalehoof;
- ObjectGuid SkadiRuthless;
ObjectGuid KingYmiron;
ObjectGuid FrenziedWorgen;
ObjectGuid RavenousFurbolg;
@@ -59,6 +64,7 @@ public:
void Initialize() override
{
SetHeaders(DataHeader);
+ LoadObjectData(creatureData, nullptr);
SkadiHits = 0;
SkadiInRange = 0;
@@ -88,9 +94,6 @@ public:
case NPC_GORTOK_PALEHOOF:
GortokPalehoof = pCreature->GetGUID();
break;
- case NPC_SKADI_THE_RUTHLESS:
- SkadiRuthless = pCreature->GetGUID();
- break;
case NPC_KING_YMIRON:
KingYmiron = pCreature->GetGUID();
break;
@@ -110,6 +113,8 @@ public:
Grauf = pCreature->GetGUID();
break;
}
+
+ InstanceScript::OnCreatureCreate(pCreature);
}
void OnGameObjectCreate(GameObject* pGo) override
@@ -238,8 +243,6 @@ public:
return SvalaSorrowgrave;
case DATA_GORTOK_PALEHOOF:
return GortokPalehoof;
- case DATA_SKADI_THE_RUTHLESS:
- return SkadiRuthless;
case DATA_KING_YMIRON:
return KingYmiron;
case DATA_NPC_FRENZIED_WORGEN: