feat(Core/Movement): port smooth waypoint movement from Cataclysm Preservation Project (#25106)
Co-authored-by: blinkysc <blinkysc@users.noreply.github.com> Co-authored-by: Ovahlord <dreadkiller@gmx.de> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Kitzunu <Kitzunu@users.noreply.github.com>
This commit is contained in:
parent
3da6e30196
commit
4201acddd5
69 changed files with 844 additions and 386 deletions
|
|
@ -0,0 +1,15 @@
|
|||
-- Add velocity and smoothTransition columns to waypoint_data
|
||||
ALTER TABLE `waypoint_data`
|
||||
ADD COLUMN `velocity` FLOAT NOT NULL DEFAULT 0 AFTER `orientation`,
|
||||
ADD COLUMN `smoothTransition` TINYINT NOT NULL DEFAULT 0 AFTER `delay`;
|
||||
|
||||
-- Create waypoint_data_addon table for custom spline points
|
||||
CREATE TABLE IF NOT EXISTS `waypoint_data_addon` (
|
||||
`PathID` INT UNSIGNED NOT NULL,
|
||||
`PointID` INT UNSIGNED NOT NULL,
|
||||
`SplinePointIndex` INT UNSIGNED NOT NULL,
|
||||
`PositionX` FLOAT NOT NULL DEFAULT 0,
|
||||
`PositionY` FLOAT NOT NULL DEFAULT 0,
|
||||
`PositionZ` FLOAT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`PathID`, `PointID`, `SplinePointIndex`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
|
@ -52,7 +52,7 @@ void WorldDatabaseConnection::DoPrepareStatements()
|
|||
PrepareStatement(WORLD_UPD_WAYPOINT_DATA_WPGUID, "UPDATE waypoint_data SET wpguid = ? WHERE id = ? and point = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(WORLD_SEL_WAYPOINT_DATA_MAX_ID, "SELECT MAX(id) FROM waypoint_data", CONNECTION_SYNCH);
|
||||
PrepareStatement(WORLD_SEL_WAYPOINT_DATA_MAX_POINT, "SELECT MAX(point) FROM waypoint_data WHERE id = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(WORLD_SEL_WAYPOINT_DATA_BY_ID, "SELECT point, position_x, position_y, position_z, orientation, move_type, delay, action, action_chance FROM waypoint_data WHERE id = ? ORDER BY point", CONNECTION_SYNCH);
|
||||
PrepareStatement(WORLD_SEL_WAYPOINT_DATA_BY_ID, "SELECT point, position_x, position_y, position_z, orientation, velocity, delay, smoothTransition, move_type, action, action_chance FROM waypoint_data WHERE id = ? ORDER BY point", CONNECTION_SYNCH);
|
||||
PrepareStatement(WORLD_SEL_WAYPOINT_DATA_POS_BY_ID, "SELECT point, position_x, position_y, position_z FROM waypoint_data WHERE id = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(WORLD_SEL_WAYPOINT_DATA_POS_FIRST_BY_ID, "SELECT position_x, position_y, position_z FROM waypoint_data WHERE point = 1 AND id = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(WORLD_SEL_WAYPOINT_DATA_POS_LAST_BY_ID, "SELECT position_x, position_y, position_z, orientation FROM waypoint_data WHERE id = ? ORDER BY point DESC LIMIT 1", CONNECTION_SYNCH);
|
||||
|
|
|
|||
|
|
@ -186,6 +186,13 @@ public:
|
|||
// Called at MovePath End
|
||||
virtual void PathEndReached(uint32 /*pathId*/) {}
|
||||
|
||||
/// == Waypoints system =============================
|
||||
|
||||
virtual void WaypointPathStarted(uint32 /*pathId*/) { }
|
||||
virtual void WaypointStarted(uint32 /*nodeId*/, uint32 /*pathId*/) { }
|
||||
virtual void WaypointReached(uint32 /*nodeId*/, uint32 /*pathId*/) { }
|
||||
virtual void WaypointPathEnded(uint32 /*nodeId*/, uint32 /*pathId*/) { }
|
||||
|
||||
void OnCharmed(bool apply) override;
|
||||
|
||||
// Called at reaching home after evade
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ public:
|
|||
|
||||
void GenerateWaypointArray(Movement::PointsArray* points);
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
virtual void WaypointReached(uint32 pointId) = 0;
|
||||
virtual void WaypointStart(uint32 /*pointId*/) {}
|
||||
|
||||
|
|
|
|||
|
|
@ -148,27 +148,28 @@ void SmartAI::UpdateFollow(const uint32 diff)
|
|||
}
|
||||
}
|
||||
|
||||
WaypointData const* SmartAI::GetNextWayPoint()
|
||||
WaypointNode const* SmartAI::GetNextWayPoint()
|
||||
{
|
||||
if (!mWayPoints || mWayPoints->empty())
|
||||
if (!mWayPoints || mWayPoints->Nodes.empty())
|
||||
return nullptr;
|
||||
|
||||
mCurrentWPID++;
|
||||
auto itr = mWayPoints->find(mCurrentWPID);
|
||||
if (itr != mWayPoints->end())
|
||||
{
|
||||
mLastWP = &(*itr).second;
|
||||
if (mLastWP->id != mCurrentWPID)
|
||||
LOG_ERROR("scripts.ai.sai", "SmartAI::GetNextWayPoint: Got not expected waypoint id {}, expected {}", mLastWP->id, mCurrentWPID);
|
||||
// mCurrentWPID is 1-based for SmartAI escort paths
|
||||
if (mCurrentWPID > mWayPoints->Nodes.size())
|
||||
return nullptr;
|
||||
|
||||
return &(*itr).second;
|
||||
}
|
||||
return nullptr;
|
||||
// Nodes are 0-indexed, mCurrentWPID is 1-based
|
||||
WaypointNode const& node = mWayPoints->Nodes[mCurrentWPID - 1];
|
||||
mLastWP = &node;
|
||||
if (mLastWP->Id != mCurrentWPID)
|
||||
LOG_ERROR("scripts.ai.sai", "SmartAI::GetNextWayPoint: Got not expected waypoint id {}, expected {}", mLastWP->Id, mCurrentWPID);
|
||||
|
||||
return mLastWP;
|
||||
}
|
||||
|
||||
void SmartAI::GenerateWayPointArray(Movement::PointsArray* points)
|
||||
{
|
||||
if (!mWayPoints || mWayPoints->empty())
|
||||
if (!mWayPoints || mWayPoints->Nodes.empty())
|
||||
return;
|
||||
|
||||
// Flying unit, just fill array
|
||||
|
|
@ -177,16 +178,12 @@ void SmartAI::GenerateWayPointArray(Movement::PointsArray* points)
|
|||
// xinef: first point in vector is unit real position
|
||||
points->clear();
|
||||
points->push_back(G3D::Vector3(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()));
|
||||
uint32 wpCounter = mCurrentWPID;
|
||||
auto itr = mWayPoints->find(wpCounter++);
|
||||
do
|
||||
// mCurrentWPID is 1-based
|
||||
for (uint32 i = mCurrentWPID > 0 ? mCurrentWPID - 1 : 0; i < mWayPoints->Nodes.size(); ++i)
|
||||
{
|
||||
WaypointData const& wp = (*itr).second;
|
||||
points->push_back(G3D::Vector3(wp.x, wp.y, wp.z));
|
||||
|
||||
itr = mWayPoints->find(wpCounter++);
|
||||
WaypointNode const& wp = mWayPoints->Nodes[i];
|
||||
points->push_back(G3D::Vector3(wp.X, wp.Y, wp.Z));
|
||||
}
|
||||
while (itr != mWayPoints->end());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -195,15 +192,15 @@ void SmartAI::GenerateWayPointArray(Movement::PointsArray* points)
|
|||
std::vector<G3D::Vector3> pVector;
|
||||
// xinef: first point in vector is unit real position
|
||||
pVector.push_back(G3D::Vector3(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()));
|
||||
uint32 wpCounter = mCurrentWPID;
|
||||
|
||||
uint32 length = (mWayPoints->size() - mCurrentWPID) * size;
|
||||
uint32 startIdx = mCurrentWPID > 0 ? mCurrentWPID - 1 : 0;
|
||||
uint32 length = (uint32)((mWayPoints->Nodes.size() - startIdx) * size);
|
||||
|
||||
uint32 cnt = 0;
|
||||
for (auto itr = mWayPoints->find(wpCounter); itr != mWayPoints->end() && cnt++ <= length; ++itr)
|
||||
for (uint32 i = startIdx; i < mWayPoints->Nodes.size() && cnt++ <= length; ++i)
|
||||
{
|
||||
WaypointData const& wp = (*itr).second;
|
||||
pVector.push_back(G3D::Vector3(wp.x, wp.y, wp.z));
|
||||
WaypointNode const& wp = mWayPoints->Nodes[i];
|
||||
pVector.push_back(G3D::Vector3(wp.X, wp.Y, wp.Z));
|
||||
}
|
||||
|
||||
if (pVector.size() > 2) // more than source + dest
|
||||
|
|
@ -243,10 +240,10 @@ void SmartAI::StartPath(ForcedMovement forcedMovement, uint32 path, bool repeat,
|
|||
return;
|
||||
}
|
||||
|
||||
if (!mWayPoints || mWayPoints->empty())
|
||||
if (!mWayPoints || mWayPoints->Nodes.empty())
|
||||
return;
|
||||
|
||||
if (WaypointData const* wp = GetNextWayPoint())
|
||||
if (WaypointNode const* wp = GetNextWayPoint())
|
||||
{
|
||||
AddEscortState(SMART_ESCORT_ESCORTING);
|
||||
mCanRepeatPath = repeat;
|
||||
|
|
@ -262,7 +259,7 @@ void SmartAI::StartPath(ForcedMovement forcedMovement, uint32 path, bool repeat,
|
|||
GenerateWayPointArray(&pathPoints);
|
||||
|
||||
me->GetMotionMaster()->MoveSplinePath(&pathPoints, mForcedMovement);
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_ESCORT_START, nullptr, wp->id, GetScript()->GetPathId());
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_ESCORT_START, nullptr, wp->Id, GetScript()->GetPathId());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -321,10 +318,11 @@ void SmartAI::PausePath(uint32 delay, bool forced)
|
|||
me->StopMoving();
|
||||
me->GetMotionMaster()->MoveIdle();//force stop
|
||||
|
||||
auto waypoint = mWayPoints->find(mCurrentWPID);
|
||||
if (waypoint->second.orientation.has_value())
|
||||
if (mCurrentWPID > 0 && mCurrentWPID <= mWayPoints->Nodes.size())
|
||||
{
|
||||
me->SetFacingTo(*waypoint->second.orientation);
|
||||
WaypointNode const& waypoint = mWayPoints->Nodes[mCurrentWPID - 1];
|
||||
if (waypoint.Orientation.has_value())
|
||||
me->SetFacingTo(*waypoint.Orientation);
|
||||
}
|
||||
}
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_ESCORT_PAUSED, nullptr, mCurrentWPID, GetScript()->GetPathId());
|
||||
|
|
@ -655,7 +653,7 @@ void SmartAI::MovepointReached(uint32 id)
|
|||
|
||||
if (mLastWP)
|
||||
{
|
||||
me->SetPosition(mLastWP->x, mLastWP->y, mLastWP->z, me->GetOrientation());
|
||||
me->SetPosition(mLastWP->X, mLastWP->Y, mLastWP->Z, me->GetOrientation());
|
||||
me->SetHomePosition(me->GetPosition());
|
||||
}
|
||||
|
||||
|
|
@ -1278,6 +1276,32 @@ void SmartAI::PathEndReached(uint32 /*pathId*/)
|
|||
me->LoadPath(0);
|
||||
}
|
||||
|
||||
void SmartAI::WaypointPathStarted(uint32 /*pathId*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::WaypointStarted(uint32 /*nodeId*/, uint32 /*pathId*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::WaypointReached(uint32 nodeId, uint32 pathId)
|
||||
{
|
||||
if (!HasEscortState(SMART_ESCORT_ESCORTING))
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_REACHED, nullptr, nodeId, pathId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void SmartAI::WaypointPathEnded(uint32 nodeId, uint32 pathId)
|
||||
{
|
||||
if (!HasEscortState(SMART_ESCORT_ESCORTING))
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_ENDED, nullptr, nodeId, pathId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void SmartAI::DistancingEnded()
|
||||
{
|
||||
SetCurrentRangeMode(true, _pendingDistancing);
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public:
|
|||
void StopPath(uint32 DespawnTime = 0, uint32 quest = 0, bool fail = false);
|
||||
void EndPath(bool fail = false);
|
||||
void ResumePath();
|
||||
WaypointData const* GetNextWayPoint();
|
||||
WaypointNode const* GetNextWayPoint();
|
||||
void GenerateWayPointArray(Movement::PointsArray* points);
|
||||
bool HasEscortState(uint32 uiEscortState) { return (mEscortState & uiEscortState); }
|
||||
void AddEscortState(uint32 uiEscortState) { mEscortState |= uiEscortState; }
|
||||
|
|
@ -206,6 +206,11 @@ public:
|
|||
|
||||
void PathEndReached(uint32 pathId) override;
|
||||
|
||||
void WaypointPathStarted(uint32 pathId) override;
|
||||
void WaypointStarted(uint32 nodeId, uint32 pathId) override;
|
||||
void WaypointReached(uint32 nodeId, uint32 pathId) override;
|
||||
void WaypointPathEnded(uint32 nodeId, uint32 pathId) override;
|
||||
|
||||
bool CanRespawn() override { return mcanSpawn; };
|
||||
void SetCanRespawn(bool canSpawn) { mcanSpawn = canSpawn; }
|
||||
|
||||
|
|
@ -239,9 +244,9 @@ private:
|
|||
bool mWPReached;
|
||||
bool mOOCReached;
|
||||
uint32 mWPPauseTimer;
|
||||
WaypointData const* mLastWP;
|
||||
WaypointNode const* mLastWP;
|
||||
uint32 mEscortNPCFlags;
|
||||
uint32 GetWPCount() { return mWayPoints ? mWayPoints->size() : 0; }
|
||||
uint32 GetWPCount() { return mWayPoints ? mWayPoints->Nodes.size() : 0; }
|
||||
bool mCanRepeatPath;
|
||||
bool mEvadeDisabled;
|
||||
bool mCanAutoAttack;
|
||||
|
|
|
|||
|
|
@ -2533,14 +2533,12 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
|||
break;
|
||||
}
|
||||
|
||||
if (!path || path->empty())
|
||||
if (!path || path->Nodes.empty())
|
||||
continue;
|
||||
|
||||
auto itrWp = path->find(1);
|
||||
if (itrWp != path->end())
|
||||
{
|
||||
WaypointData const& wpData = itrWp->second;
|
||||
float distToThisPath = creature->GetExactDistSq(wpData.x, wpData.y, wpData.z);
|
||||
WaypointNode const& wpData = path->Nodes[0];
|
||||
float distToThisPath = creature->GetExactDistSq(wpData.X, wpData.Y, wpData.Z);
|
||||
|
||||
if (distToThisPath < distanceToClosest)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -48,11 +48,6 @@ void SmartWaypointMgr::LoadFromDB()
|
|||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
for (auto itr : waypoint_map)
|
||||
{
|
||||
delete itr.second;
|
||||
}
|
||||
|
||||
waypoint_map.clear();
|
||||
|
||||
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_SMARTAI_WP);
|
||||
|
|
@ -78,14 +73,15 @@ void SmartWaypointMgr::LoadFromDB()
|
|||
float x = fields[2].Get<float>();
|
||||
float y = fields[3].Get<float>();
|
||||
float z = fields[4].Get<float>();
|
||||
Optional<float> o;
|
||||
std::optional<float> o;
|
||||
if (!fields[5].IsNull())
|
||||
o = fields[5].Get<float>();
|
||||
uint32 delay = fields[6].Get<uint32>();
|
||||
|
||||
if (last_entry != entry)
|
||||
{
|
||||
waypoint_map[entry] = new WaypointPath();
|
||||
waypoint_map[entry] = WaypointPath();
|
||||
waypoint_map[entry].Id = entry;
|
||||
last_id = 1;
|
||||
count++;
|
||||
}
|
||||
|
|
@ -94,15 +90,15 @@ void SmartWaypointMgr::LoadFromDB()
|
|||
LOG_ERROR("sql.sql", "SmartWaypointMgr::LoadFromDB: Path entry {}, unexpected point id {}, expected {}.", entry, id, last_id);
|
||||
|
||||
last_id++;
|
||||
WaypointData data;
|
||||
data.id = id;
|
||||
data.x = x;
|
||||
data.y = y;
|
||||
data.z = z;
|
||||
data.orientation = o;
|
||||
data.delay = delay;
|
||||
data.move_type = WAYPOINT_MOVE_TYPE_MAX;
|
||||
(*waypoint_map[entry]).emplace(id, data);
|
||||
WaypointNode node;
|
||||
node.Id = id;
|
||||
node.X = x;
|
||||
node.Y = y;
|
||||
node.Z = z;
|
||||
node.Orientation = o;
|
||||
node.Delay = delay;
|
||||
node.MoveType = WAYPOINT_MOVE_TYPE_MAX;
|
||||
waypoint_map[entry].Nodes.push_back(std::move(node));
|
||||
|
||||
last_entry = entry;
|
||||
total++;
|
||||
|
|
@ -112,14 +108,6 @@ void SmartWaypointMgr::LoadFromDB()
|
|||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
SmartWaypointMgr::~SmartWaypointMgr()
|
||||
{
|
||||
for (auto itr : waypoint_map)
|
||||
{
|
||||
delete itr.second;
|
||||
}
|
||||
}
|
||||
|
||||
SmartAIMgr* SmartAIMgr::instance()
|
||||
{
|
||||
static SmartAIMgr instance;
|
||||
|
|
|
|||
|
|
@ -2064,21 +2064,22 @@ class SmartWaypointMgr
|
|||
{
|
||||
SmartWaypointMgr() {}
|
||||
public:
|
||||
~SmartWaypointMgr();
|
||||
~SmartWaypointMgr() = default;
|
||||
|
||||
static SmartWaypointMgr* instance();
|
||||
|
||||
void LoadFromDB();
|
||||
|
||||
WaypointPath* GetPath(uint32 id)
|
||||
WaypointPath const* GetPath(uint32 id) const
|
||||
{
|
||||
if (waypoint_map.find(id) != waypoint_map.end())
|
||||
return waypoint_map[id];
|
||||
else return 0;
|
||||
auto itr = waypoint_map.find(id);
|
||||
if (itr != waypoint_map.end())
|
||||
return &itr->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<uint32, WaypointPath*> waypoint_map;
|
||||
std::unordered_map<uint32, WaypointPath> waypoint_map;
|
||||
};
|
||||
|
||||
// all events for a single entry
|
||||
|
|
|
|||
|
|
@ -388,6 +388,33 @@ void Creature::SearchFormation()
|
|||
}
|
||||
}
|
||||
|
||||
bool Creature::IsFormationLeader() const
|
||||
{
|
||||
if (!m_formation)
|
||||
return false;
|
||||
|
||||
return m_formation->GetLeader() == this;
|
||||
}
|
||||
|
||||
void Creature::SignalFormationMovement()
|
||||
{
|
||||
if (!m_formation)
|
||||
return;
|
||||
|
||||
if (!m_formation->GetLeader() || m_formation->GetLeader() != this)
|
||||
return;
|
||||
|
||||
m_formation->LeaderStartedMoving();
|
||||
}
|
||||
|
||||
bool Creature::IsFormationLeaderMoveAllowed() const
|
||||
{
|
||||
if (!m_formation)
|
||||
return true;
|
||||
|
||||
return m_formation->CanLeaderStartMoving();
|
||||
}
|
||||
|
||||
void Creature::RemoveCorpse(bool setSpawnTime, bool skipVisibility)
|
||||
{
|
||||
if (getDeathState() != DeathState::Corpse)
|
||||
|
|
|
|||
|
|
@ -358,6 +358,14 @@ public:
|
|||
[[nodiscard]] uint32 GetCurrentWaypointID() const { return m_waypointID; }
|
||||
void UpdateWaypointID(uint32 wpID) { m_waypointID = wpID; }
|
||||
|
||||
// nodeId, pathId
|
||||
std::pair<uint32, uint32> GetCurrentWaypointInfo() const { return _currentWaypointNodeInfo; }
|
||||
void UpdateCurrentWaypointInfo(uint32 nodeId, uint32 pathId) { _currentWaypointNodeInfo = { nodeId, pathId }; }
|
||||
|
||||
bool IsFormationLeader() const;
|
||||
void SignalFormationMovement();
|
||||
bool IsFormationLeaderMoveAllowed() const;
|
||||
|
||||
void SearchFormation();
|
||||
[[nodiscard]] CreatureGroup const* GetFormation() const { return m_formation; }
|
||||
[[nodiscard]] CreatureGroup* GetFormation() { return m_formation; }
|
||||
|
|
@ -519,6 +527,7 @@ private:
|
|||
// WaypointMovementGenerator variable
|
||||
uint32 m_waypointID;
|
||||
uint32 m_path_id;
|
||||
std::pair<uint32, uint32> _currentWaypointNodeInfo{0, 0};
|
||||
|
||||
// Formation variable
|
||||
CreatureGroup* m_formation;
|
||||
|
|
|
|||
|
|
@ -538,9 +538,9 @@ void MotionMaster::MovePath(uint32 path_id, ForcedMovement forcedMovement, PathS
|
|||
}
|
||||
|
||||
Movement::PointsArray points;
|
||||
for (auto& point : *path)
|
||||
for (auto const& node : path->Nodes)
|
||||
{
|
||||
points.push_back(G3D::Vector3(point.second.x, point.second.y, point.second.z));
|
||||
points.push_back(G3D::Vector3(node.X, node.Y, node.Z));
|
||||
}
|
||||
|
||||
// pass the new PointsArray* to the appropriate MoveSplinePath function
|
||||
|
|
@ -918,7 +918,7 @@ void MotionMaster::MoveWaypoint(uint32 path_id, bool repeatable, PathSource path
|
|||
if (_owner->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE))
|
||||
return;
|
||||
|
||||
Mutate(new WaypointMovementGenerator<Creature>(path_id, pathSource, repeatable), MOTION_SLOT_IDLE);
|
||||
Mutate(new WaypointMovementGenerator<Creature>(path_id, repeatable, pathSource), MOTION_SLOT_IDLE);
|
||||
|
||||
LOG_DEBUG("movement.motionmaster", "{} ({}) start moving over path(Id:{}, repeatable: {})",
|
||||
_owner->IsPlayer() ? "Player" : "Creature", _owner->GetGUID().ToString(), path_id, repeatable ? "YES" : "NO");
|
||||
|
|
|
|||
|
|
@ -27,181 +27,283 @@
|
|||
#include "Player.h"
|
||||
#include "Spell.h"
|
||||
#include "Transport.h"
|
||||
#include "World.h"
|
||||
#include "SmartScriptMgr.h"
|
||||
#include "World.h"
|
||||
|
||||
void WaypointMovementGenerator<Creature>::LoadPath(Creature* creature)
|
||||
inline G3D::Vector3 PositionToVector3(Position const& p) { return { p.GetPositionX(), p.GetPositionY(), p.GetPositionZ() }; }
|
||||
|
||||
WaypointMovementGenerator<Creature>::WaypointMovementGenerator(uint32 pathId, bool repeating, PathSource pathSource) : PathMovementBase((WaypointPath const*)nullptr),
|
||||
_lastSplineId(0), _pathId(pathId), _waypointDelay(0),
|
||||
_waypointReached(true), _recalculateSpeed(false), _repeating(repeating), _loadedFromDB(true), _stalled(false), _hasBeenStalled(false), _done(false), _pathSource(pathSource),
|
||||
_smoothSplineLaunched(false), _lastPassedSplineIdx(0)
|
||||
{
|
||||
switch (i_pathSource)
|
||||
{
|
||||
case PathSource::WAYPOINT_MGR:
|
||||
{
|
||||
if (!path_id)
|
||||
path_id = creature->GetWaypointPath();
|
||||
}
|
||||
|
||||
i_path = sWaypointMgr->GetPath(path_id);
|
||||
break;
|
||||
}
|
||||
case PathSource::SMART_WAYPOINT_MGR:
|
||||
WaypointMovementGenerator<Creature>::WaypointMovementGenerator(WaypointPath& path, bool repeating) : PathMovementBase((WaypointPath const*)nullptr),
|
||||
_lastSplineId(0), _pathId(0), _waypointDelay(0),
|
||||
_waypointReached(true), _recalculateSpeed(false), _repeating(repeating), _loadedFromDB(false), _stalled(false), _hasBeenStalled(false), _done(false), _pathSource(PathSource::WAYPOINT_MGR),
|
||||
_smoothSplineLaunched(false), _lastPassedSplineIdx(0)
|
||||
{
|
||||
i_path = &path;
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::DoInitialize(Creature* creature)
|
||||
{
|
||||
_done = false;
|
||||
|
||||
if (_loadedFromDB)
|
||||
{
|
||||
if (!_pathId)
|
||||
_pathId = creature->GetWaypointPath();
|
||||
|
||||
switch (_pathSource)
|
||||
{
|
||||
i_path = sSmartWaypointMgr->GetPath(path_id);
|
||||
break;
|
||||
default:
|
||||
case PathSource::WAYPOINT_MGR:
|
||||
i_path = sWaypointMgr->GetPath(_pathId);
|
||||
break;
|
||||
case PathSource::SMART_WAYPOINT_MGR:
|
||||
i_path = sSmartWaypointMgr->GetPath(_pathId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!i_path)
|
||||
{
|
||||
// No movement found for entry
|
||||
LOG_ERROR("sql.sql", "WaypointMovementGenerator::LoadPath: creature {} ({}) doesn't have waypoint path id: {}",
|
||||
creature->GetName(), creature->GetGUID().ToString(), path_id);
|
||||
LOG_ERROR("sql.sql", "WaypointMovementGenerator::DoInitialize: creature {} ({}) doesn't have waypoint path id: {}",
|
||||
creature->GetName(), creature->GetGUID().ToString(), _pathId);
|
||||
return;
|
||||
}
|
||||
|
||||
i_currentNode = i_path->begin()->first;
|
||||
// Determine our first waypoint from the creature's stored waypoint
|
||||
if (CreatureData const* creatureData = creature->GetCreatureData())
|
||||
{
|
||||
if (i_path->Nodes.size() > creatureData->currentwaypoint)
|
||||
{
|
||||
creature->UpdateCurrentWaypointInfo(creatureData->currentwaypoint, i_path->Id);
|
||||
i_currentNode = creatureData->currentwaypoint;
|
||||
}
|
||||
}
|
||||
|
||||
StartMoveNow(creature);
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::DoInitialize(Creature* creature)
|
||||
{
|
||||
LoadPath(creature);
|
||||
creature->AddUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE);
|
||||
|
||||
// Inform AI
|
||||
if (CreatureAI* AI = creature->AI())
|
||||
AI->WaypointPathStarted(i_path->Id);
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::DoFinalize(Creature* creature)
|
||||
{
|
||||
creature->ClearUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE);
|
||||
creature->SetWalk(false);
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::DoReset(Creature* creature)
|
||||
{
|
||||
if (stalled)
|
||||
// We did not reach our last waypoint before reset, treat this scenario as resuming movement.
|
||||
if (!_done && !_waypointReached)
|
||||
_hasBeenStalled = true;
|
||||
else if (_done)
|
||||
{
|
||||
return;
|
||||
}
|
||||
creature->AddUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE);
|
||||
StartMoveNow(creature);
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::OnArrived(Creature* creature)
|
||||
{
|
||||
if (!i_path || i_path->empty())
|
||||
return;
|
||||
if (m_isArrivalDone)
|
||||
return;
|
||||
|
||||
creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
|
||||
m_isArrivalDone = true;
|
||||
|
||||
auto currentNodeItr = i_path->find(i_currentNode);
|
||||
|
||||
if (currentNodeItr->second.event_id && urand(0, 99) < currentNodeItr->second.event_chance)
|
||||
{
|
||||
LOG_DEBUG("maps.script", "Creature movement start script {} at point {} for {}.",
|
||||
currentNodeItr->second.event_id, i_currentNode, creature->GetGUID().ToString());
|
||||
creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
|
||||
creature->GetMap()->ScriptsStart(sWaypointScripts, currentNodeItr->second.event_id, creature, nullptr);
|
||||
}
|
||||
|
||||
// Inform script
|
||||
MovementInform(creature);
|
||||
creature->UpdateWaypointID(i_currentNode);
|
||||
|
||||
if (currentNodeItr->second.delay)
|
||||
{
|
||||
creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
|
||||
Stop(currentNodeItr->second.delay);
|
||||
// mimic IdleMovementGenerator
|
||||
if (!creature->IsStopped())
|
||||
creature->StopMoving();
|
||||
}
|
||||
}
|
||||
|
||||
bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
|
||||
inline void UpdateHomePosition(Creature* creature, WaypointNode const& waypointNode)
|
||||
{
|
||||
if (!i_path || i_path->empty())
|
||||
return false;
|
||||
|
||||
// Xinef: Dont allow dead creatures to move
|
||||
if (!creature->IsAlive())
|
||||
return false;
|
||||
|
||||
if (Stopped())
|
||||
return true;
|
||||
float x = waypointNode.X;
|
||||
float y = waypointNode.Y;
|
||||
float z = waypointNode.Z;
|
||||
float o = creature->GetOrientation();
|
||||
|
||||
bool transportPath = creature->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && creature->GetTransGUID();
|
||||
|
||||
if (m_isArrivalDone)
|
||||
if (!transportPath)
|
||||
creature->SetHomePosition(x, y, z, o);
|
||||
else
|
||||
{
|
||||
if (Transport* trans = (creature->GetTransport() ? creature->GetTransport()->ToMotionTransport() : nullptr))
|
||||
{
|
||||
auto currentNodeItr = i_path->find(i_currentNode);
|
||||
float x = currentNodeItr->second.x;
|
||||
float y = currentNodeItr->second.y;
|
||||
float z = currentNodeItr->second.z;
|
||||
float o = creature->GetOrientation();
|
||||
o -= trans->GetOrientation();
|
||||
creature->SetTransportHomePosition(x, y, z, o);
|
||||
trans->CalculatePassengerPosition(x, y, z, &o);
|
||||
creature->SetHomePosition(x, y, z, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!transportPath)
|
||||
creature->SetHomePosition(x, y, z, o);
|
||||
else
|
||||
void WaypointMovementGenerator<Creature>::ProcessWaypointArrival(Creature* creature, WaypointNode const& waypoint)
|
||||
{
|
||||
if (_waypointReached)
|
||||
return;
|
||||
|
||||
if (waypoint.Delay > 0)
|
||||
{
|
||||
creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
|
||||
_waypointDelay = waypoint.Delay;
|
||||
}
|
||||
|
||||
// Check if the waypoint path has reached its end and may not repeat. Inform AI.
|
||||
if ((i_currentNode == i_path->Nodes.size() - 1) && !_repeating && !_done)
|
||||
{
|
||||
_done = true;
|
||||
creature->UpdateCurrentWaypointInfo(0, 0);
|
||||
|
||||
if (CreatureAI* AI = creature->AI())
|
||||
{
|
||||
AI->PathEndReached(i_path->Id);
|
||||
AI->WaypointPathEnded(waypoint.Id, i_path->Id);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateHomePosition(creature, waypoint);
|
||||
|
||||
if (waypoint.EventId && urand(0, 99) < waypoint.EventChance)
|
||||
{
|
||||
LOG_DEBUG("maps.script", "Creature movement start script {} at point {} for {}.",
|
||||
waypoint.EventId, i_currentNode, creature->GetGUID().ToString());
|
||||
creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
|
||||
creature->GetMap()->ScriptsStart(sWaypointScripts, waypoint.EventId, creature, nullptr);
|
||||
}
|
||||
|
||||
creature->UpdateWaypointID(waypoint.Id);
|
||||
creature->UpdateCurrentWaypointInfo(waypoint.Id, i_path->Id);
|
||||
|
||||
// Inform AI
|
||||
if (CreatureAI* AI = creature->AI())
|
||||
{
|
||||
AI->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
|
||||
AI->WaypointReached(waypoint.Id, i_path->Id);
|
||||
}
|
||||
|
||||
if (Unit* owner = creature->GetCharmerOrOwner())
|
||||
{
|
||||
if (UnitAI* AI = owner->GetAI())
|
||||
AI->SummonMovementInform(creature, WAYPOINT_MOTION_TYPE, i_currentNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TempSummon* tempSummon = creature->ToTempSummon())
|
||||
if (Unit* owner2 = tempSummon->GetSummonerUnit())
|
||||
if (UnitAI* AI = owner2->GetAI())
|
||||
AI->SummonMovementInform(creature, WAYPOINT_MOTION_TYPE, i_currentNode);
|
||||
}
|
||||
|
||||
// All hooks called and infos updated. Time to increment the waypoint node id
|
||||
if (i_path && !i_path->Nodes.empty()) // ensure that the path has not been changed in one of the hooks.
|
||||
i_currentNode = (i_currentNode + 1) % i_path->Nodes.size();
|
||||
|
||||
_waypointReached = true;
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::StartMove(Creature* creature, bool relaunch /*= false*/)
|
||||
{
|
||||
// Formation checks. Do not launch a new spline when one of our formation members is currently in combat.
|
||||
if (!relaunch)
|
||||
{
|
||||
if (!IsAllowedToMove(creature) || (creature->IsFormationLeader() && !creature->IsFormationLeaderMoveAllowed()))
|
||||
{
|
||||
_waypointDelay = 1000;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Dont allow dead creatures to move
|
||||
if (!creature->IsAlive())
|
||||
return;
|
||||
|
||||
// Step two: node selection is done, build spline data
|
||||
creature->AddUnitState(UNIT_STATE_ROAMING_MOVE);
|
||||
WaypointNode const& waypoint = i_path->Nodes.at(i_currentNode);
|
||||
bool const useTransportPath = creature->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && creature->GetTransGUID();
|
||||
|
||||
Movement::MoveSplineInit init(creature);
|
||||
//! If the creature is on transport, we assume waypoints set in DB are already transport offsets
|
||||
if (useTransportPath)
|
||||
init.DisableTransportPathTransformations();
|
||||
|
||||
if (waypoint.SmoothTransition && i_path->Nodes.size() > 2)
|
||||
{
|
||||
// Build a catmullrom spline segment, stopping at delay waypoints
|
||||
init.Path().push_back(PositionToVector3(creature->GetPosition()));
|
||||
|
||||
bool hasDelayInSegment = false;
|
||||
uint32 segmentNodes = 0;
|
||||
for (uint32 i = 0; i < i_path->Nodes.size(); ++i)
|
||||
{
|
||||
uint32 idx = (i_currentNode + i) % i_path->Nodes.size();
|
||||
WaypointNode const& node = i_path->Nodes.at(idx);
|
||||
init.Path().push_back(G3D::Vector3(node.X, node.Y, node.Z));
|
||||
segmentNodes++;
|
||||
|
||||
// Stop the segment at a waypoint with a delay
|
||||
if (node.Delay > 0)
|
||||
{
|
||||
if (Transport* trans = (creature->GetTransport() ? creature->GetTransport()->ToMotionTransport() : nullptr))
|
||||
{
|
||||
o -= trans->GetOrientation();
|
||||
creature->SetTransportHomePosition(x, y, z, o);
|
||||
trans->CalculatePassengerPosition(x, y, z, &o);
|
||||
creature->SetHomePosition(x, y, z, o);
|
||||
}
|
||||
else
|
||||
transportPath = false;
|
||||
// else if (vehicle) - this should never happen, vehicle offsets are const
|
||||
hasDelayInSegment = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Xinef: moved the upper IF here
|
||||
uint32 lastPoint = i_path->rbegin()->first;
|
||||
if ((i_currentNode == lastPoint) && !repeating) // If that's our last waypoint
|
||||
// If no delays found and repeating, add wrap-around points for seamless loop
|
||||
if (!hasDelayInSegment && _repeating)
|
||||
{
|
||||
creature->AI()->PathEndReached(path_id);
|
||||
creature->GetMotionMaster()->Initialize();
|
||||
return false;
|
||||
for (uint32 i = 0; i < std::min<uint32>(3, i_path->Nodes.size()); ++i)
|
||||
{
|
||||
uint32 idx = (i_currentNode + i) % i_path->Nodes.size();
|
||||
WaypointNode const& node = i_path->Nodes.at(idx);
|
||||
init.Path().push_back(G3D::Vector3(node.X, node.Y, node.Z));
|
||||
}
|
||||
}
|
||||
|
||||
++i_currentNode;
|
||||
if (lastPoint < i_currentNode)
|
||||
i_currentNode = i_path->begin()->first;
|
||||
// Need at least 3 waypoints for a meaningful catmullrom spline
|
||||
if (segmentNodes >= 3)
|
||||
{
|
||||
init.SetFirstPointId(i_currentNode);
|
||||
init.SetSmooth();
|
||||
_smoothSplineLaunched = true;
|
||||
_lastPassedSplineIdx = i_currentNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Too few points for catmullrom, fall back to linear point-to-point
|
||||
init.Path().clear();
|
||||
init.MoveTo(G3D::Vector3(waypoint.X, waypoint.Y, waypoint.Z));
|
||||
}
|
||||
}
|
||||
|
||||
// xinef: do not initialize motion if we got stunned in movementinform
|
||||
if (creature->HasUnitState(UNIT_STATE_NOT_MOVE) || creature->IsMovementPreventedByCasting())
|
||||
else if (!waypoint.SplinePoints.empty())
|
||||
{
|
||||
return true;
|
||||
// We have spline points in waypoint_data_addon table
|
||||
int32 splineIndex = 0;
|
||||
|
||||
auto itr = waypoint.SplinePoints.begin();
|
||||
if (splineIndex)
|
||||
std::advance(itr, splineIndex);
|
||||
|
||||
init.Path().reserve(waypoint.SplinePoints.size() - splineIndex);
|
||||
std::copy(itr, waypoint.SplinePoints.end(), std::back_inserter(init.Path()));
|
||||
|
||||
// Add starting vertex and destination
|
||||
init.Path().insert(init.Path().begin(), PositionToVector3(creature->GetPosition()));
|
||||
init.Path().insert(init.Path().end(), G3D::Vector3(waypoint.X, waypoint.Y, waypoint.Z));
|
||||
}
|
||||
|
||||
auto currentNodeItr = i_path->find(i_currentNode);
|
||||
WaypointData const& node = currentNodeItr->second;
|
||||
|
||||
m_isArrivalDone = false;
|
||||
|
||||
creature->AddUnitState(UNIT_STATE_ROAMING_MOVE);
|
||||
|
||||
Movement::Location formationDest(node.x, node.y, node.z, 0.0f);
|
||||
Movement::MoveSplineInit init(creature);
|
||||
|
||||
//! If creature is on transport, we assume waypoints set in DB are already transport offsets
|
||||
if (transportPath)
|
||||
else
|
||||
{
|
||||
init.DisableTransportPathTransformations();
|
||||
if (TransportBase* trans = creature->GetDirectTransport())
|
||||
trans->CalculatePassengerPosition(formationDest.x, formationDest.y, formationDest.z, &formationDest.orientation);
|
||||
// Smooth transition for short paths (<=2 nodes): use previous spline endpoint as start
|
||||
if (waypoint.SmoothTransition && !creature->movespline->Finalized() && _lastSplineId == creature->movespline->GetId())
|
||||
{
|
||||
init.MoveTo(creature->movespline->FinalDestination(), G3D::Vector3(waypoint.X, waypoint.Y, waypoint.Z));
|
||||
if (!init.Path().empty())
|
||||
init.Path().insert(init.Path().begin(), PositionToVector3(creature->GetPosition()));
|
||||
}
|
||||
else
|
||||
init.MoveTo(PositionToVector3(creature->GetPosition()), G3D::Vector3(waypoint.X, waypoint.Y, waypoint.Z));
|
||||
}
|
||||
|
||||
float z = node.z;
|
||||
creature->UpdateAllowedPositionZ(node.x, node.y, z);
|
||||
//! Do not use formationDest here, MoveTo requires transport offsets due to DisableTransportPathTransformations() call
|
||||
//! but formationDest contains global coordinates
|
||||
init.MoveTo(node.x, node.y, z, true, true);
|
||||
if (waypoint.Orientation.has_value() && waypoint.Delay > 0)
|
||||
init.SetFacing(*waypoint.Orientation);
|
||||
|
||||
if (node.orientation.has_value() && node.delay > 0)
|
||||
init.SetFacing(*node.orientation);
|
||||
|
||||
switch (node.move_type)
|
||||
switch (waypoint.MoveType)
|
||||
{
|
||||
case WAYPOINT_MOVE_TYPE_LAND:
|
||||
init.SetAnimation(AnimTier::Ground);
|
||||
|
|
@ -219,89 +321,203 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
|
|||
break;
|
||||
}
|
||||
|
||||
if (creature->CanFly())
|
||||
init.SetFly();
|
||||
|
||||
if (waypoint.Velocity > 0.f)
|
||||
init.SetVelocity(waypoint.Velocity);
|
||||
|
||||
init.Launch();
|
||||
|
||||
//Call for creature group update
|
||||
if (creature->GetFormation() && creature->GetFormation()->GetLeader() == creature && creature->GetFormation()->CanLeaderStartMoving())
|
||||
creature->GetFormation()->LeaderStartedMoving();
|
||||
if (!creature->movespline->Finalized())
|
||||
_lastSplineId = creature->movespline->GetId();
|
||||
|
||||
return true;
|
||||
// Inform formation
|
||||
creature->SignalFormationMovement();
|
||||
|
||||
// Inform AI
|
||||
if (!relaunch)
|
||||
if (CreatureAI* AI = creature->AI())
|
||||
AI->WaypointStarted(waypoint.Id, i_path->Id);
|
||||
|
||||
_waypointReached = false;
|
||||
_recalculateSpeed = false;
|
||||
_hasBeenStalled = false;
|
||||
}
|
||||
|
||||
bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* creature, uint32 diff)
|
||||
{
|
||||
// Waypoint movement can be switched on/off
|
||||
// This is quite handy for escort quests and other stuff
|
||||
if (stalled)
|
||||
{
|
||||
Stop(1000);
|
||||
if (!creature || !creature->IsAlive())
|
||||
return true;
|
||||
}
|
||||
if (creature->HasUnitState(UNIT_STATE_NOT_MOVE) || creature->IsMovementPreventedByCasting())
|
||||
|
||||
if (_done || !i_path || i_path->Nodes.empty())
|
||||
return true;
|
||||
|
||||
// Stop movement if paused, rooted, or casting
|
||||
if (!IsAllowedToMove(creature) && !creature->movespline->Finalized())
|
||||
{
|
||||
creature->StopMoving();
|
||||
Stop(1000);
|
||||
_lastSplineId = 0;
|
||||
_smoothSplineLaunched = false;
|
||||
}
|
||||
|
||||
// Set home position to current position.
|
||||
if (!creature->movespline->Finalized())
|
||||
{
|
||||
bool transportPath = creature->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && creature->GetTransGUID();
|
||||
if (!transportPath)
|
||||
creature->SetHomePosition(creature->GetPosition());
|
||||
}
|
||||
|
||||
// Smooth spline: track waypoint passages without rebuilding
|
||||
if (_smoothSplineLaunched && creature->movespline->GetId() == _lastSplineId)
|
||||
{
|
||||
int32 currentIdx = creature->movespline->currentPathIdx();
|
||||
|
||||
// Process passed waypoints
|
||||
while (_lastPassedSplineIdx < currentIdx)
|
||||
{
|
||||
_lastPassedSplineIdx++;
|
||||
WaypointNode const& passedWp = i_path->Nodes.at(i_currentNode);
|
||||
|
||||
UpdateHomePosition(creature, passedWp);
|
||||
creature->UpdateWaypointID(passedWp.Id);
|
||||
creature->UpdateCurrentWaypointInfo(passedWp.Id, i_path->Id);
|
||||
|
||||
if (passedWp.EventId && urand(0, 99) < passedWp.EventChance)
|
||||
{
|
||||
creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
|
||||
creature->GetMap()->ScriptsStart(sWaypointScripts, passedWp.EventId, creature, nullptr);
|
||||
}
|
||||
|
||||
if (CreatureAI* AI = creature->AI())
|
||||
{
|
||||
AI->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
|
||||
AI->WaypointReached(passedWp.Id, i_path->Id);
|
||||
}
|
||||
|
||||
// Advance node
|
||||
i_currentNode = (i_currentNode + 1) % i_path->Nodes.size();
|
||||
|
||||
// If this waypoint has a delay, stop the spline and pause
|
||||
if (passedWp.Delay > 0)
|
||||
{
|
||||
creature->StopMoving();
|
||||
creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
|
||||
_waypointDelay = passedWp.Delay;
|
||||
_waypointReached = true;
|
||||
_smoothSplineLaunched = false;
|
||||
if (passedWp.Orientation.has_value())
|
||||
creature->SetFacingTo(*passedWp.Orientation);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (creature->movespline->Finalized())
|
||||
{
|
||||
if (!_repeating)
|
||||
{
|
||||
// Path ended
|
||||
_done = true;
|
||||
_smoothSplineLaunched = false;
|
||||
creature->UpdateCurrentWaypointInfo(0, 0);
|
||||
if (CreatureAI* AI = creature->AI())
|
||||
{
|
||||
AI->PathEndReached(i_path->Id);
|
||||
AI->WaypointPathEnded(i_path->Nodes.at(i_currentNode).Id, i_path->Id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Repeating: rebuild spline
|
||||
_smoothSplineLaunched = false;
|
||||
StartMove(creature);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// prevent a crash at empty waypoint path.
|
||||
if (!i_path || i_path->empty())
|
||||
return false;
|
||||
// Non-smooth: per-waypoint logic
|
||||
WaypointNode const& waypoint = i_path->Nodes.at(i_currentNode);
|
||||
UpdateWaypointState(creature, waypoint);
|
||||
|
||||
// Xinef: Dont allow dead creatures to move
|
||||
if (!creature->IsAlive())
|
||||
return false;
|
||||
// Process movement preventing timers
|
||||
if (_waypointDelay > 0)
|
||||
{
|
||||
_waypointDelay -= diff;
|
||||
if (_waypointDelay > 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Stopped())
|
||||
if (_pauseTime.has_value())
|
||||
{
|
||||
if (CanMove(diff))
|
||||
return StartMove(creature);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (creature->movespline->Finalized())
|
||||
{
|
||||
OnArrived(creature);
|
||||
return StartMove(creature);
|
||||
}
|
||||
*_pauseTime -= diff;
|
||||
if (*_pauseTime > 0)
|
||||
return true;
|
||||
else
|
||||
_pauseTime.reset();
|
||||
}
|
||||
|
||||
// Timers are ready, let's try to move
|
||||
if (IsAllowedToMove(creature) && (_waypointReached || _recalculateSpeed || _hasBeenStalled))
|
||||
StartMove(creature, _recalculateSpeed || _hasBeenStalled);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::MovementInform(Creature* creature)
|
||||
void WaypointMovementGenerator<Creature>::Pause(uint32 timer /*= 0*/)
|
||||
{
|
||||
if (creature->AI())
|
||||
creature->AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
|
||||
|
||||
if (Unit* owner = creature->GetCharmerOrOwner())
|
||||
{
|
||||
if (UnitAI* AI = owner->GetAI())
|
||||
AI->SummonMovementInform(creature, WAYPOINT_MOTION_TYPE, i_currentNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TempSummon* tempSummon = creature->ToTempSummon())
|
||||
if (Unit* owner = tempSummon->GetSummonerUnit())
|
||||
if (UnitAI* AI = owner->GetAI())
|
||||
AI->SummonMovementInform(creature, WAYPOINT_MOTION_TYPE, i_currentNode);
|
||||
}
|
||||
_stalled = timer ? false : true;
|
||||
_hasBeenStalled = !_waypointReached;
|
||||
_pauseTime = timer;
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::Pause(uint32 timer)
|
||||
void WaypointMovementGenerator<Creature>::Resume(uint32 overrideTimer /*= 0*/)
|
||||
{
|
||||
if (timer)
|
||||
i_nextMoveTime.Reset(timer);
|
||||
else
|
||||
{
|
||||
// No timer? Will be paused forever until ::Resume is called
|
||||
stalled = true;
|
||||
i_nextMoveTime.Reset(1);
|
||||
}
|
||||
_hasBeenStalled = !_waypointReached;
|
||||
_stalled = false;
|
||||
if (overrideTimer)
|
||||
_pauseTime = overrideTimer;
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::Resume(uint32 /*overrideTimer/*/)
|
||||
bool WaypointMovementGenerator<Creature>::GetResetPosition(float& x, float& y, float& z)
|
||||
{
|
||||
stalled = false;
|
||||
// prevent a crash at empty waypoint path.
|
||||
if (!i_path || i_path->Nodes.empty())
|
||||
return false;
|
||||
|
||||
ASSERT(i_currentNode < i_path->Nodes.size(), "WaypointMovementGenerator::GetResetPos: tried to reference a node id ({}) which is not included in path ({})", i_currentNode, i_path->Id);
|
||||
WaypointNode const& waypoint = i_path->Nodes.at(i_currentNode);
|
||||
|
||||
x = waypoint.X;
|
||||
y = waypoint.Y;
|
||||
z = waypoint.Z;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WaypointMovementGenerator<Creature>::IsAllowedToMove(Creature* creature) const
|
||||
{
|
||||
if (_stalled || _done)
|
||||
return false;
|
||||
|
||||
if (_pauseTime.has_value())
|
||||
return false;
|
||||
|
||||
if (creature->HasUnitState(UNIT_STATE_NOT_MOVE) || creature->IsMovementPreventedByCasting())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::UpdateWaypointState(Creature* creature, WaypointNode const& waypointNode)
|
||||
{
|
||||
if (creature->movespline->GetId() != _lastSplineId)
|
||||
return;
|
||||
|
||||
if (creature->movespline->Finalized())
|
||||
ProcessWaypointArrival(creature, waypointNode);
|
||||
}
|
||||
|
||||
//----------------------------------------------------//
|
||||
|
|
|
|||
|
|
@ -54,49 +54,43 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium< Crea
|
|||
public PathMovementBase<Creature, WaypointPath const*>
|
||||
{
|
||||
public:
|
||||
WaypointMovementGenerator(uint32 _path_id = 0, PathSource pathSource = PathSource::WAYPOINT_MGR, bool _repeating = true, bool _stalled = false)
|
||||
: PathMovementBase((WaypointPath const*)nullptr), i_nextMoveTime(0), m_isArrivalDone(false), path_id(_path_id), repeating(_repeating), stalled(_stalled), i_pathSource(pathSource) {}
|
||||
explicit WaypointMovementGenerator(uint32 pathId = 0, bool repeating = true, PathSource pathSource = PathSource::WAYPOINT_MGR);
|
||||
explicit WaypointMovementGenerator(WaypointPath& path, bool repeating = true);
|
||||
~WaypointMovementGenerator() { i_path = nullptr; }
|
||||
|
||||
void DoInitialize(Creature*);
|
||||
void DoFinalize(Creature*);
|
||||
void DoReset(Creature*);
|
||||
bool DoUpdate(Creature*, uint32 diff);
|
||||
void Pause(uint32 timer = 0);
|
||||
void Resume(uint32 overrideTimer/* = 0*/);
|
||||
|
||||
void MovementInform(Creature*);
|
||||
void unitSpeedChanged() override { _recalculateSpeed = true; }
|
||||
void Pause(uint32 timer = 0) override;
|
||||
void Resume(uint32 overrideTimer = 0) override;
|
||||
bool GetResetPosition(float& x, float& y, float& z) override;
|
||||
|
||||
MovementGeneratorType GetMovementGeneratorType() { return WAYPOINT_MOTION_TYPE; }
|
||||
|
||||
// now path movement implmementation
|
||||
void LoadPath(Creature*);
|
||||
MovementGeneratorType GetMovementGeneratorType() override { return WAYPOINT_MOTION_TYPE; }
|
||||
|
||||
private:
|
||||
void Stop(int32 time) { i_nextMoveTime.Reset(time);}
|
||||
void ProcessWaypointArrival(Creature*, WaypointNode const&);
|
||||
void StartMove(Creature*, bool relaunch = false);
|
||||
bool IsAllowedToMove(Creature*) const;
|
||||
void UpdateWaypointState(Creature*, WaypointNode const&);
|
||||
|
||||
bool Stopped() { return !i_nextMoveTime.Passed();}
|
||||
uint32 _lastSplineId;
|
||||
uint32 _pathId;
|
||||
int32 _waypointDelay;
|
||||
std::optional<int32> _pauseTime;
|
||||
bool _waypointReached;
|
||||
|
||||
bool CanMove(int32 diff)
|
||||
{
|
||||
i_nextMoveTime.Update(diff);
|
||||
return i_nextMoveTime.Passed();
|
||||
}
|
||||
|
||||
void OnArrived(Creature*);
|
||||
bool StartMove(Creature*);
|
||||
|
||||
void StartMoveNow(Creature* creature)
|
||||
{
|
||||
i_nextMoveTime.Reset(0);
|
||||
StartMove(creature);
|
||||
}
|
||||
|
||||
TimeTrackerSmall i_nextMoveTime;
|
||||
bool m_isArrivalDone;
|
||||
uint32 path_id;
|
||||
bool repeating;
|
||||
bool stalled;
|
||||
PathSource i_pathSource;
|
||||
bool _recalculateSpeed;
|
||||
bool _repeating;
|
||||
bool _loadedFromDB;
|
||||
bool _stalled;
|
||||
bool _hasBeenStalled;
|
||||
bool _done;
|
||||
PathSource _pathSource;
|
||||
bool _smoothSplineLaunched;
|
||||
int32 _lastPassedSplineIdx;
|
||||
};
|
||||
|
||||
/** FlightPathMovementGenerator generates movement of the player for the paths
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ namespace Movement
|
|||
[[nodiscard]] Vector3 FinalDestination() const { return Initialized() ? spline.getPoint(spline.last()) : Vector3(); }
|
||||
[[nodiscard]] Vector3 CurrentDestination() const { return Initialized() ? spline.getPoint(point_Idx + 1) : Vector3(); }
|
||||
[[nodiscard]] int32 currentPathIdx() const;
|
||||
[[nodiscard]] int32 MaxPathIdx() const { return spline.last() - 1; }
|
||||
|
||||
[[nodiscard]] bool HasAnimation() const { return splineflags.animation; }
|
||||
[[nodiscard]] uint8 GetAnimationType() const { return splineflags.animId; }
|
||||
|
|
|
|||
|
|
@ -199,6 +199,25 @@ namespace Movement
|
|||
args.flags.EnableFacingAngle();
|
||||
}
|
||||
|
||||
void MoveSplineInit::MoveTo(Vector3 const& start, Vector3 const& dest, bool generatePath, bool forceDestination)
|
||||
{
|
||||
if (generatePath)
|
||||
{
|
||||
PathGenerator path(unit);
|
||||
bool result = path.CalculatePath(start.x, start.y, start.z, dest.x, dest.y, dest.z, forceDestination);
|
||||
if (result && !(path.GetPathType() & PATHFIND_NOPATH))
|
||||
{
|
||||
MovebyPath(path.GetPath());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
args.path_Idx_offset = 0;
|
||||
args.path.resize(2);
|
||||
TransportPathTransform transform(unit, args.TransformForTransport);
|
||||
args.path[1] = transform(dest);
|
||||
}
|
||||
|
||||
void MoveSplineInit::MoveTo(const Vector3& dest, bool generatePath, bool forceDestination)
|
||||
{
|
||||
if (generatePath)
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ namespace Movement
|
|||
|
||||
/* Initializes simple A to B motion, A is current unit's position, B is destination
|
||||
*/
|
||||
void MoveTo(Vector3 const& start, Vector3 const& destination, bool generatePath = true, bool forceDestination = false);
|
||||
void MoveTo(const Vector3& destination, bool generatePath = false, bool forceDestination = false);
|
||||
void MoveTo(float x, float y, float z, bool generatePath = false, bool forceDestination = false);
|
||||
|
||||
|
|
|
|||
72
src/server/game/Movement/Waypoints/WaypointDefines.h
Normal file
72
src/server/game/Movement/Waypoints/WaypointDefines.h
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ACORE_WAYPOINTDEFINES_H
|
||||
#define ACORE_WAYPOINTDEFINES_H
|
||||
|
||||
#include "Define.h"
|
||||
#include "G3D/Vector3.h"
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
enum WaypointMoveType
|
||||
{
|
||||
WAYPOINT_MOVE_TYPE_WALK,
|
||||
WAYPOINT_MOVE_TYPE_RUN,
|
||||
WAYPOINT_MOVE_TYPE_LAND,
|
||||
WAYPOINT_MOVE_TYPE_TAKEOFF,
|
||||
|
||||
WAYPOINT_MOVE_TYPE_MAX
|
||||
};
|
||||
|
||||
struct WaypointNode
|
||||
{
|
||||
WaypointNode() : Id(0), X(0.f), Y(0.f), Z(0.f), Velocity(0.f), Delay(0), EventId(0), MoveType(WAYPOINT_MOVE_TYPE_RUN), EventChance(0), SmoothTransition(false) { }
|
||||
WaypointNode(uint32 id, float x, float y, float z, std::optional<float> orientation = { }, float velocity = 0.f, uint32 delay = 0, bool smoothTransition = false) :
|
||||
Id(id), X(x), Y(y), Z(z), Orientation(orientation), Velocity(velocity), Delay(delay), SmoothTransition(smoothTransition)
|
||||
{
|
||||
EventId = 0;
|
||||
MoveType = WAYPOINT_MOVE_TYPE_WALK;
|
||||
EventChance = 100;
|
||||
}
|
||||
|
||||
uint32 Id;
|
||||
float X, Y, Z;
|
||||
std::optional<float> Orientation;
|
||||
float Velocity;
|
||||
uint32 Delay;
|
||||
uint32 EventId;
|
||||
uint32 MoveType;
|
||||
uint8 EventChance;
|
||||
bool SmoothTransition;
|
||||
std::vector<G3D::Vector3> SplinePoints;
|
||||
};
|
||||
|
||||
struct WaypointPath
|
||||
{
|
||||
WaypointPath() : Id(0) { }
|
||||
WaypointPath(uint32 _id, std::vector<WaypointNode>&& _nodes)
|
||||
{
|
||||
Id = _id;
|
||||
Nodes = _nodes;
|
||||
}
|
||||
|
||||
std::vector<WaypointNode> Nodes;
|
||||
uint32 Id;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -22,20 +22,6 @@
|
|||
#include "QueryResult.h"
|
||||
#include "Timer.h"
|
||||
|
||||
WaypointMgr::WaypointMgr()
|
||||
{
|
||||
}
|
||||
|
||||
WaypointMgr::~WaypointMgr()
|
||||
{
|
||||
for (WaypointPathContainer::iterator itr = _waypointStore.begin(); itr != _waypointStore.end(); ++itr)
|
||||
{
|
||||
itr->second.clear();
|
||||
}
|
||||
|
||||
_waypointStore.clear();
|
||||
}
|
||||
|
||||
WaypointMgr* WaypointMgr::instance()
|
||||
{
|
||||
static WaypointMgr instance;
|
||||
|
|
@ -46,8 +32,8 @@ void WaypointMgr::Load()
|
|||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8 9
|
||||
QueryResult result = WorldDatabase.Query("SELECT id, point, position_x, position_y, position_z, orientation, move_type, delay, action, action_chance FROM waypoint_data ORDER BY id, point");
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11
|
||||
QueryResult result = WorldDatabase.Query("SELECT id, point, position_x, position_y, position_z, orientation, velocity, delay, smoothTransition, move_type, action, action_chance FROM waypoint_data ORDER BY id, point");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
|
|
@ -61,66 +47,113 @@ void WaypointMgr::Load()
|
|||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
WaypointData data;
|
||||
|
||||
uint32 pathId = fields[0].Get<uint32>();
|
||||
WaypointPath& path = _waypointStore[pathId];
|
||||
|
||||
float x = fields[2].Get<float>();
|
||||
float y = fields[3].Get<float>();
|
||||
float z = fields[4].Get<float>();
|
||||
std::optional<float > o;
|
||||
std::optional<float> o;
|
||||
if (!fields[5].IsNull())
|
||||
o = fields[5].Get<float>();
|
||||
|
||||
float velocity = fields[6].Get<float>();
|
||||
|
||||
Acore::NormalizeMapCoord(x);
|
||||
Acore::NormalizeMapCoord(y);
|
||||
|
||||
data.id = fields[1].Get<uint32>();
|
||||
data.x = x;
|
||||
data.y = y;
|
||||
data.z = z;
|
||||
data.orientation = o;
|
||||
data.move_type = fields[6].Get<uint32>();
|
||||
WaypointNode waypoint;
|
||||
waypoint.Id = fields[1].Get<uint32>();
|
||||
waypoint.X = x;
|
||||
waypoint.Y = y;
|
||||
waypoint.Z = z;
|
||||
if (o.has_value())
|
||||
waypoint.Orientation = o;
|
||||
waypoint.Velocity = velocity;
|
||||
waypoint.Delay = fields[7].Get<uint32>();
|
||||
waypoint.SmoothTransition = fields[8].Get<bool>();
|
||||
waypoint.MoveType = fields[9].Get<uint32>();
|
||||
|
||||
if (data.move_type >= WAYPOINT_MOVE_TYPE_MAX)
|
||||
if (waypoint.MoveType >= WAYPOINT_MOVE_TYPE_MAX)
|
||||
{
|
||||
//LOG_ERROR("sql.sql", "Waypoint {} in waypoint_data has invalid move_type, ignoring", wp->id);
|
||||
LOG_ERROR("sql.sql", "Waypoint {} in waypoint_data has invalid move_type, ignoring", waypoint.Id);
|
||||
continue;
|
||||
}
|
||||
|
||||
data.delay = fields[7].Get<uint32>();
|
||||
data.event_id = fields[8].Get<uint32>();
|
||||
data.event_chance = fields[9].Get<int16>();
|
||||
waypoint.EventId = fields[10].Get<uint32>();
|
||||
waypoint.EventChance = fields[11].Get<int16>();
|
||||
|
||||
path.emplace(data.id, data);
|
||||
WaypointPath& path = _waypointStore[pathId];
|
||||
path.Id = pathId;
|
||||
path.Nodes.push_back(std::move(waypoint));
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
for (auto itr = _waypointStore.begin(); itr != _waypointStore.end(); )
|
||||
{
|
||||
uint32 first = itr->second.begin()->first;
|
||||
uint32 last = itr->second.rbegin()->first;
|
||||
if (last - first + 1 != itr->second.size())
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Waypoint {} in waypoint_data has non-contiguous pointids, skipping", itr->first);
|
||||
itr = _waypointStore.erase(itr);
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} waypoints in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
void WaypointMgr::LoadWaypointAddons()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
// 0 1 2 3 4 5
|
||||
QueryResult result = WorldDatabase.Query("SELECT PathID, PointID, SplinePointIndex, PositionX, PositionY, PositionZ FROM waypoint_data_addon ORDER BY PathID, PointID, SplinePointIndex");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LOG_INFO("server.loading", ">> Loaded 0 waypoint addon data. DB table `waypoint_data_addon` is empty!");
|
||||
LOG_INFO("server.loading", " ");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 pathId = fields[0].Get<uint32>();
|
||||
|
||||
auto it = _waypointStore.find(pathId);
|
||||
if (it == _waypointStore.end())
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Tried to load waypoint_data_addon data for PathID {} but there is no such path in waypoint_data. Ignoring.", pathId);
|
||||
continue;
|
||||
}
|
||||
|
||||
WaypointPath& path = it->second;
|
||||
uint32 pointId = fields[1].Get<uint32>();
|
||||
|
||||
auto itr = std::find_if(path.Nodes.begin(), path.Nodes.end(), [pointId](WaypointNode const& node)
|
||||
{
|
||||
return node.Id == pointId;
|
||||
});
|
||||
|
||||
if (itr == path.Nodes.end())
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Tried to load waypoint_data_addon data for PointID {} of PathID {} but there is no such point in waypoint_data. Ignoring.", pointId, pathId);
|
||||
continue;
|
||||
}
|
||||
|
||||
float x = fields[3].Get<float>();
|
||||
float y = fields[4].Get<float>();
|
||||
float z = fields[5].Get<float>();
|
||||
|
||||
Acore::NormalizeMapCoord(x);
|
||||
Acore::NormalizeMapCoord(y);
|
||||
|
||||
itr->SplinePoints.push_back(G3D::Vector3(x, y, z));
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} waypoint addon data in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
void WaypointMgr::ReloadPath(uint32 id)
|
||||
{
|
||||
WaypointPathContainer::iterator itr = _waypointStore.find(id);
|
||||
auto itr = _waypointStore.find(id);
|
||||
if (itr != _waypointStore.end())
|
||||
{
|
||||
_waypointStore.erase(itr);
|
||||
}
|
||||
|
||||
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_BY_ID);
|
||||
|
||||
|
|
@ -131,13 +164,10 @@ void WaypointMgr::ReloadPath(uint32 id)
|
|||
if (!result)
|
||||
return;
|
||||
|
||||
WaypointPath& path = _waypointStore[id];
|
||||
|
||||
std::vector<WaypointNode> values;
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
WaypointData data;
|
||||
|
||||
float x = fields[1].Get<float>();
|
||||
float y = fields[2].Get<float>();
|
||||
float z = fields[3].Get<float>();
|
||||
|
|
@ -145,26 +175,34 @@ void WaypointMgr::ReloadPath(uint32 id)
|
|||
if (!fields[4].IsNull())
|
||||
o = fields[4].Get<float>();
|
||||
|
||||
float velocity = fields[5].Get<float>();
|
||||
|
||||
Acore::NormalizeMapCoord(x);
|
||||
Acore::NormalizeMapCoord(y);
|
||||
|
||||
data.id = fields[0].Get<uint32>();
|
||||
data.x = x;
|
||||
data.y = y;
|
||||
data.z = z;
|
||||
data.orientation = o;
|
||||
data.move_type = fields[5].Get<uint32>();
|
||||
WaypointNode waypoint;
|
||||
waypoint.Id = fields[0].Get<uint32>();
|
||||
waypoint.X = x;
|
||||
waypoint.Y = y;
|
||||
waypoint.Z = z;
|
||||
if (o.has_value())
|
||||
waypoint.Orientation = o;
|
||||
waypoint.Velocity = velocity;
|
||||
waypoint.Delay = fields[6].Get<uint32>();
|
||||
waypoint.SmoothTransition = fields[7].Get<bool>();
|
||||
waypoint.MoveType = fields[8].Get<uint32>();
|
||||
|
||||
if (data.move_type >= WAYPOINT_MOVE_TYPE_MAX)
|
||||
if (waypoint.MoveType >= WAYPOINT_MOVE_TYPE_MAX)
|
||||
{
|
||||
//LOG_ERROR("sql.sql", "Waypoint {} in waypoint_data has invalid move_type, ignoring", wp->id);
|
||||
LOG_ERROR("sql.sql", "Waypoint {} in waypoint_data has invalid move_type, ignoring", waypoint.Id);
|
||||
continue;
|
||||
}
|
||||
|
||||
data.delay = fields[6].Get<uint32>();
|
||||
data.event_id = fields[7].Get<uint32>();
|
||||
data.event_chance = fields[8].Get<uint8>();
|
||||
waypoint.EventId = fields[9].Get<uint32>();
|
||||
waypoint.EventChance = fields[10].Get<uint8>();
|
||||
|
||||
path.emplace(data.id, data);
|
||||
values.push_back(std::move(waypoint));
|
||||
} while (result->NextRow());
|
||||
|
||||
_waypointStore[id] = WaypointPath(id, std::move(values));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,35 +18,8 @@
|
|||
#ifndef ACORE_WAYPOINTMANAGER_H
|
||||
#define ACORE_WAYPOINTMANAGER_H
|
||||
|
||||
#include "Define.h"
|
||||
#include <optional>
|
||||
#include "WaypointDefines.h"
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
enum WaypointMoveType
|
||||
{
|
||||
WAYPOINT_MOVE_TYPE_WALK,
|
||||
WAYPOINT_MOVE_TYPE_RUN,
|
||||
WAYPOINT_MOVE_TYPE_LAND,
|
||||
WAYPOINT_MOVE_TYPE_TAKEOFF,
|
||||
|
||||
WAYPOINT_MOVE_TYPE_MAX
|
||||
};
|
||||
|
||||
struct WaypointData
|
||||
{
|
||||
uint32 id;
|
||||
float x, y, z;
|
||||
std::optional<float> orientation;
|
||||
uint32 delay;
|
||||
uint32 event_id = 0;
|
||||
uint32 move_type = 0;
|
||||
uint8 event_chance = 0;
|
||||
};
|
||||
|
||||
typedef std::map<uint32, WaypointData> WaypointPath;
|
||||
typedef std::unordered_map<uint32, WaypointPath> WaypointPathContainer;
|
||||
|
||||
class WaypointMgr
|
||||
{
|
||||
|
|
@ -59,10 +32,13 @@ public:
|
|||
// Loads all paths from database, should only run on startup
|
||||
void Load();
|
||||
|
||||
// Loads additional path data for waypoints from database. Should only be called on startup.
|
||||
void LoadWaypointAddons();
|
||||
|
||||
// Returns the path from a given id
|
||||
WaypointPath const* GetPath(uint32 id) const
|
||||
{
|
||||
WaypointPathContainer::const_iterator itr = _waypointStore.find(id);
|
||||
auto itr = _waypointStore.find(id);
|
||||
if (itr != _waypointStore.end())
|
||||
return &itr->second;
|
||||
|
||||
|
|
@ -70,10 +46,9 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
WaypointMgr();
|
||||
~WaypointMgr();
|
||||
WaypointMgr() { }
|
||||
|
||||
WaypointPathContainer _waypointStore;
|
||||
std::unordered_map<uint32, WaypointPath> _waypointStore;
|
||||
};
|
||||
|
||||
#define sWaypointMgr WaypointMgr::instance()
|
||||
|
|
|
|||
|
|
@ -779,6 +779,9 @@ void World::SetInitialWorldSettings()
|
|||
LOG_INFO("server.loading", "Loading Waypoints...");
|
||||
sWaypointMgr->Load();
|
||||
|
||||
LOG_INFO("server.loading", "Loading Waypoint Addons...");
|
||||
sWaypointMgr->LoadWaypointAddons();
|
||||
|
||||
LOG_INFO("server.loading", "Loading SmartAI Waypoints...");
|
||||
sSmartWaypointMgr->LoadFromDB();
|
||||
|
||||
|
|
|
|||
|
|
@ -213,6 +213,7 @@ struct npc_grimstone : public npc_escortAI
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
switch (waypointId)
|
||||
|
|
@ -568,6 +569,7 @@ struct npc_rocknot : public npc_escortAI
|
|||
go->SetGoState((GOState)state);
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
switch (waypointId)
|
||||
|
|
|
|||
|
|
@ -176,6 +176,7 @@ public:
|
|||
|
||||
void JustEngagedWith(Unit* /*who*/) override { }
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
switch (waypointId)
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ public:
|
|||
{
|
||||
npc_professor_phizzlethorpeAI(Creature* creature) : npc_escortAI(creature) { }
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ struct npc_ranger_lilatha : public npc_escortAI
|
|||
{
|
||||
npc_ranger_lilatha(Creature* creature) : npc_escortAI(creature) { }
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ public:
|
|||
{
|
||||
npc_deathstalker_erlandAI(Creature* creature) : npc_escortAI(creature) { }
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
switch (waypointId)
|
||||
|
|
@ -318,6 +319,7 @@ public:
|
|||
uiPhase = 0;
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
switch (waypointId)
|
||||
|
|
|
|||
|
|
@ -1423,6 +1423,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
switch (waypointId)
|
||||
|
|
@ -2820,6 +2821,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
switch (waypointId)
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ public:
|
|||
textCounter = SAY_DS_DOWN_1;
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ public:
|
|||
IsFriendSummoned = false;
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
switch (waypointId)
|
||||
|
|
|
|||
|
|
@ -527,6 +527,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 uiPointId) override
|
||||
{
|
||||
switch (uiPointId)
|
||||
|
|
|
|||
|
|
@ -303,6 +303,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
switch (waypointId)
|
||||
|
|
@ -1014,6 +1015,7 @@ public:
|
|||
Start(false);
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
if (waypointId == 7)
|
||||
|
|
|
|||
|
|
@ -227,6 +227,7 @@ struct npc_general_andorov : public npc_escortAI
|
|||
events.ScheduleEvent(EVENT_STRIKE, 2s, 5s);
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
switch (waypointId)
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
if (Player* player = GetPlayerForEscort())
|
||||
|
|
|
|||
|
|
@ -246,6 +246,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
if (Player* player = GetPlayerForEscort())
|
||||
|
|
|
|||
|
|
@ -330,6 +330,7 @@ public:
|
|||
// pSummoned->AI()->AttackStart(me);
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
if (Player* player = GetPlayerForEscort())
|
||||
|
|
|
|||
|
|
@ -257,6 +257,7 @@ public:
|
|||
me->SetFaction(faction);
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
RelocateSummons();
|
||||
|
|
|
|||
|
|
@ -553,6 +553,7 @@ public:
|
|||
else if (EventOnWait) EventTimer -= diff;
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
CurrWP = waypointId;
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ public:
|
|||
{
|
||||
npc_kaya_flathoofAI(Creature* creature) : npc_escortAI(creature) {}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
|
|||
|
|
@ -168,6 +168,7 @@ public:
|
|||
{
|
||||
npc_custodian_of_timeAI(Creature* creature) : npc_escortAI(creature) { }
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
if (Player* player = GetPlayerForEscort())
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ public:
|
|||
|
||||
void Reset() override { }
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
@ -494,6 +495,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
switch (waypointId)
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ public:
|
|||
|
||||
void Reset() override { }
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
switch (waypointId)
|
||||
|
|
@ -170,6 +171,7 @@ public:
|
|||
|
||||
void Reset() override { }
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
switch (waypointId)
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ public:
|
|||
|
||||
uint32 DemoralizingShoutTimer;
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
if (Player* player = GetPlayerForEscort())
|
||||
|
|
|
|||
|
|
@ -383,6 +383,7 @@ public:
|
|||
StartNextDialogueText(SAY_PRIESTESS_ALTAR_3);
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 pointId) override
|
||||
{
|
||||
switch (pointId)
|
||||
|
|
|
|||
|
|
@ -233,6 +233,7 @@ public:
|
|||
zarithrian->AI()->JustSummoned(me);
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
if (waypointId == MAX_PATH_FLAMECALLER_WAYPOINTS)
|
||||
|
|
|
|||
|
|
@ -519,6 +519,7 @@ public:
|
|||
bCheck = false;
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 uiPoint) override
|
||||
{
|
||||
if (uiPoint == 1)
|
||||
|
|
|
|||
|
|
@ -340,6 +340,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 i) override
|
||||
{
|
||||
if (i == 12)
|
||||
|
|
|
|||
|
|
@ -592,6 +592,7 @@ public:
|
|||
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override {}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 i) override
|
||||
{
|
||||
if (!pInstance)
|
||||
|
|
|
|||
|
|
@ -791,6 +791,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
switch (waypointId)
|
||||
|
|
|
|||
|
|
@ -267,6 +267,7 @@ struct boss_bjarngrim : public npc_escortAI
|
|||
m_uiStance = stance;
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 Point) override
|
||||
{
|
||||
if (Point == 1)
|
||||
|
|
|
|||
|
|
@ -312,6 +312,7 @@ public:
|
|||
TalkEvent = false;
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 id) override;
|
||||
void InitializeEvent();
|
||||
|
||||
|
|
|
|||
|
|
@ -974,6 +974,7 @@ struct npc_mimirons_inferno : public npc_escortAI
|
|||
|
||||
void AttackStart(Unit*) override { }
|
||||
void MoveInLineOfSight(Unit*) override { }
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 /*waypointId*/) override { }
|
||||
|
||||
void DoAction(int32 param) override
|
||||
|
|
|
|||
|
|
@ -895,6 +895,7 @@ struct boss_thorim_lightning_orb : public npc_escortAI
|
|||
me->CastSpell(me, SPELL_LIGHTNING_DESTRUCTION, true);
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 /*point*/) override
|
||||
{
|
||||
}
|
||||
|
|
@ -960,6 +961,7 @@ struct boss_thorim_sif_blizzard : public npc_escortAI
|
|||
me->CastSpell(me, SPELL_BLIZZARD, true);
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 /*point*/) override
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -934,6 +934,7 @@ struct boss_yoggsaron_cloud : public npc_escortAI
|
|||
|
||||
void MoveInLineOfSight(Unit* /*who*/) override {}
|
||||
void AttackStart(Unit* /*who*/) override {}
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 /*point*/) override {}
|
||||
|
||||
void Reset() override
|
||||
|
|
|
|||
|
|
@ -312,6 +312,7 @@ struct violet_hold_trashAI : public npc_escortAI
|
|||
CreatureStartAttackDoor();
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 id) override
|
||||
{
|
||||
if (PLoc < 6)
|
||||
|
|
@ -1021,6 +1022,7 @@ public:
|
|||
uint32 timer;
|
||||
uint8 count;
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 uiWPointId) override
|
||||
{
|
||||
if (!pInstance)
|
||||
|
|
|
|||
|
|
@ -377,6 +377,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
switch (waypointId)
|
||||
|
|
@ -752,6 +753,7 @@ public:
|
|||
player->FailQuest(QUEST_ESCAPING_THE_MIST);
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
@ -849,6 +851,7 @@ public:
|
|||
else Bonker_agro = 0;
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ public:
|
|||
summoned->AI()->AttackStart(me->GetVictim());
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ public:
|
|||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
@ -210,6 +211,7 @@ public:
|
|||
Start(false, summonerGUID);
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
if (waypointId != 26)
|
||||
|
|
|
|||
|
|
@ -747,6 +747,7 @@ public:
|
|||
summons.Despawn(summon);
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 pointId) override
|
||||
{
|
||||
switch (pointId)
|
||||
|
|
|
|||
|
|
@ -521,6 +521,7 @@ public:
|
|||
|
||||
uint32 m_uiChatTimer;
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ struct npc_frosthound : public npc_escortAI
|
|||
return;
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
@ -568,6 +569,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 /*waypointId*/) override { }
|
||||
void JustDied(Unit* /*killer*/) override { }
|
||||
void OnCharmed(bool /*apply*/) override { }
|
||||
|
|
|
|||
|
|
@ -195,6 +195,7 @@ public:
|
|||
npc_escortAI::MoveInLineOfSight(who);
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
switch (waypointId)
|
||||
|
|
@ -320,6 +321,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
switch (waypointId)
|
||||
|
|
@ -340,6 +341,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
switch (waypointId)
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 i) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
@ -626,6 +627,7 @@ public:
|
|||
player->FailQuest(Q_ALMABTRIEB);
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
@ -709,6 +711,7 @@ public:
|
|||
uiTakeTimer = 3000;
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ public:
|
|||
public:
|
||||
npc_kservantAI(Creature* creature) : npc_escortAI(creature) { }
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
|
|||
|
|
@ -374,6 +374,7 @@ public:
|
|||
{
|
||||
npc_isla_starmaneAI(Creature* creature) : npc_escortAI(creature) { }
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
|
|
|
|||
|
|
@ -1356,6 +1356,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using CreatureAI::WaypointReached;
|
||||
void WaypointReached(uint32 /*waypointId*/) override
|
||||
{
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue