aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRiztazz <felianther15@gmail.com>2016-11-25 00:31:10 +0100
committerjoschiwald <joschiwald.trinity@gmail.com>2018-02-11 15:53:32 +0100
commit05fb27dae4e8af859e01e5b9e52b082cba217657 (patch)
treeda858a540a26344d3e6af66017d46d7b1df7eb71
parent27cdd4b257d01005d9e342b39a4fdf76567d13cf (diff)
[3.3.5][master] Core/Movement: Smooth movement #13467 (#18020)
Implement smooth movement for all waypoint pathing and escortai (cherry picked from commit 28050f338dfc66e0c40b6a3915bf96e38e0613e5)
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp350
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedEscortAI.h38
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp299
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.h15
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp58
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp35
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h25
-rw-r--r--src/server/game/Movement/MotionMaster.cpp8
-rw-r--r--src/server/game/Movement/MotionMaster.h2
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp188
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h27
-rw-r--r--src/server/game/Movement/Waypoints/WaypointDefines.h71
-rw-r--r--src/server/game/Movement/Waypoints/WaypointManager.cpp70
-rw-r--r--src/server/game/Movement/Waypoints/WaypointManager.h29
-rw-r--r--src/server/game/World/World.cpp1
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/instance_forge_of_souls.cpp1
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp48
17 files changed, 646 insertions, 619 deletions
diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
index 09545c3b394..7619446bfd0 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
@@ -31,6 +31,8 @@ EndScriptData */
#include "MotionMaster.h"
#include "ObjectAccessor.h"
#include "Player.h"
+#include "WaypointDefines.h"
+#include "WaypointMovementGenerator.h"
enum Points
{
@@ -39,10 +41,11 @@ enum Points
};
npc_escortAI::npc_escortAI(Creature* creature) : ScriptedAI(creature),
- m_uiWPWaitTimer(2500),
- m_uiPlayerCheckTimer(1000),
+ m_uiWPWaitTimer(1000),
+ m_uiPlayerCheckTimer(0),
m_uiEscortState(STATE_ESCORT_NONE),
MaxPlayerDistance(DEFAULT_MAX_PLAYER_DISTANCE),
+ LastWP(0),
m_pQuestForEscort(NULL),
m_bIsActiveAttacker(true),
m_bIsRunning(false),
@@ -51,24 +54,11 @@ npc_escortAI::npc_escortAI(Creature* creature) : ScriptedAI(creature),
DespawnAtEnd(true),
DespawnAtFar(true),
ScriptWP(false),
- HasImmuneToNPCFlags(false)
+ HasImmuneToNPCFlags(false),
+ m_bStarted(false),
+ m_bEnded(false)
{ }
-void npc_escortAI::AttackStart(Unit* who)
-{
- if (!who)
- return;
-
- if (me->Attack(who, true))
- {
- if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE)
- me->GetMotionMaster()->MovementExpired();
-
- if (IsCombatMovementAllowed())
- me->GetMotionMaster()->MoveChase(who);
- }
-}
-
Player* npc_escortAI::GetPlayerForEscort()
{
return ObjectAccessor::GetPlayer(*me, m_uiPlayerGUID);
@@ -114,38 +104,15 @@ bool npc_escortAI::AssistPlayerInCombatAgainst(Unit* who)
void npc_escortAI::MoveInLineOfSight(Unit* who)
{
+ if (me->GetVictim())
+ return;
+
if (me->HasReactState(REACT_AGGRESSIVE) && !me->HasUnitState(UNIT_STATE_STUNNED) && who->isTargetableForAttack() && who->isInAccessiblePlaceFor(me))
- {
if (HasEscortState(STATE_ESCORT_ESCORTING) && AssistPlayerInCombatAgainst(who))
return;
- if (!me->CanFly() && me->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
- return;
-
- if (me->IsHostileTo(who))
- {
- float fAttackRadius = me->GetAttackDistance(who);
- if (me->IsWithinDistInMap(who, fAttackRadius) && me->IsWithinLOSInMap(who))
- {
- if (!me->GetVictim())
- {
- // Clear distracted state on combat
- if (me->HasUnitState(UNIT_STATE_DISTRACTED))
- {
- me->ClearUnitState(UNIT_STATE_DISTRACTED);
- me->GetMotionMaster()->Clear();
- }
-
- AttackStart(who);
- }
- else if (me->GetMap()->IsDungeon())
- {
- who->SetInCombatWith(me);
- me->AddThreat(who, 0.0f);
- }
- }
- }
- }
+ if (me->CanStartAttack(who, false))
+ AttackStart(who);
}
void npc_escortAI::JustDied(Unit* /*killer*/)
@@ -168,13 +135,13 @@ void npc_escortAI::JustDied(Unit* /*killer*/)
void npc_escortAI::JustRespawned()
{
- m_uiEscortState = STATE_ESCORT_NONE;
+ RemoveEscortState(STATE_ESCORT_ESCORTING | STATE_ESCORT_RETURNING | STATE_ESCORT_PAUSED);
if (!IsCombatMovementAllowed())
SetCombatMovement(true);
//add a small delay before going to first waypoint, normal in near all cases
- m_uiWPWaitTimer = 2500;
+ m_uiWPWaitTimer = 1000;
if (me->getFaction() != me->GetCreatureTemplate()->faction)
me->RestoreFaction();
@@ -184,6 +151,7 @@ void npc_escortAI::JustRespawned()
void npc_escortAI::ReturnToLastPoint()
{
+ me->SetWalk(false);
float x, y, z, o;
me->GetHomePosition(x, y, z, o);
me->GetMotionMaster()->MovePoint(POINT_LAST_POINT, x, y, z);
@@ -231,57 +199,57 @@ bool npc_escortAI::IsPlayerOrGroupInRange()
void npc_escortAI::UpdateAI(uint32 diff)
{
- //Waypoint Updating
if (HasEscortState(STATE_ESCORT_ESCORTING) && !me->GetVictim() && m_uiWPWaitTimer && !HasEscortState(STATE_ESCORT_RETURNING))
{
if (m_uiWPWaitTimer <= diff)
{
- //End of the line
- if (CurrentWP == WaypointList.end())
+ if (!HasEscortState(STATE_ESCORT_PAUSED))
{
- if (DespawnAtEnd)
- {
- TC_LOG_DEBUG("scripts", "EscortAI reached end of waypoints");
-
- if (m_bCanReturnToStart)
- {
- float fRetX, fRetY, fRetZ;
- me->GetRespawnPosition(fRetX, fRetY, fRetZ);
-
- me->GetMotionMaster()->MovePoint(POINT_HOME, fRetX, fRetY, fRetZ);
+ m_uiWPWaitTimer = 0;
- m_uiWPWaitTimer = 0;
+ if (m_bEnded)
+ {
+ me->StopMoving();
+ me->GetMotionMaster()->Clear(false);
+ me->GetMotionMaster()->MoveIdle();
- TC_LOG_DEBUG("scripts", "EscortAI are returning home to spawn location: %u, %f, %f, %f", POINT_HOME, fRetX, fRetY, fRetZ);
- return;
- }
+ m_bEnded = false;
- if (m_bCanInstantRespawn)
+ if (DespawnAtEnd)
{
- me->setDeathState(JUST_DIED);
- me->Respawn();
+ TC_LOG_DEBUG("scripts", "EscortAI reached end of waypoints");
+
+ if (m_bCanReturnToStart)
+ {
+ float fRetX, fRetY, fRetZ;
+ me->GetRespawnPosition(fRetX, fRetY, fRetZ);
+
+ me->GetMotionMaster()->MovePoint(POINT_HOME, fRetX, fRetY, fRetZ);
+
+ TC_LOG_DEBUG("scripts", "EscortAI are returning home to spawn location: %u, %f, %f, %f", POINT_HOME, fRetX, fRetY, fRetZ);
+ }
+ else if (m_bCanInstantRespawn)
+ {
+ me->setDeathState(JUST_DIED);
+ me->Respawn();
+ }
+ else
+ me->DespawnOrUnsummon();
}
else
- me->DespawnOrUnsummon();
+ TC_LOG_DEBUG("scripts", "EscortAI reached end of waypoints with Despawn off");
+ RemoveEscortState(STATE_ESCORT_ESCORTING);
return;
}
- else
- {
- TC_LOG_DEBUG("scripts", "EscortAI reached end of waypoints with Despawn off");
- return;
+ if (!m_bStarted)
+ {
+ m_bStarted = true;
+ me->GetMotionMaster()->MovePath(_path, false);
}
- }
-
- if (!HasEscortState(STATE_ESCORT_PAUSED))
- {
- me->GetMotionMaster()->MovePoint(CurrentWP->id, CurrentWP->x, CurrentWP->y, CurrentWP->z);
- TC_LOG_DEBUG("scripts", "EscortAI start waypoint %u (%f, %f, %f).", CurrentWP->id, CurrentWP->x, CurrentWP->y, CurrentWP->z);
-
- WaypointStart(CurrentWP->id);
-
- m_uiWPWaitTimer = 0;
+ else if (WaypointMovementGenerator<Creature>* move = dynamic_cast<WaypointMovementGenerator<Creature>*>(me->GetMotionMaster()->top()))
+ WaypointStart(move->GetCurrentNode());
}
}
else
@@ -291,12 +259,11 @@ void npc_escortAI::UpdateAI(uint32 diff)
//Check if player or any member of his group is within range
if (HasEscortState(STATE_ESCORT_ESCORTING) && !m_uiPlayerGUID.IsEmpty() && !me->GetVictim() && !HasEscortState(STATE_ESCORT_RETURNING))
{
- if (m_uiPlayerCheckTimer <= diff)
+ m_uiPlayerCheckTimer += diff;
+ if (m_uiPlayerCheckTimer > 1000)
{
if (DespawnAtFar && !IsPlayerOrGroupInRange())
{
- TC_LOG_DEBUG("scripts", "EscortAI failed because player/group was to far away or not found");
-
if (m_bCanInstantRespawn)
{
me->setDeathState(JUST_DIED);
@@ -308,10 +275,8 @@ void npc_escortAI::UpdateAI(uint32 diff)
return;
}
- m_uiPlayerCheckTimer = 1000;
+ m_uiPlayerCheckTimer = 0;
}
- else
- m_uiPlayerCheckTimer -= diff;
}
UpdateEscortAI(diff);
@@ -327,44 +292,63 @@ void npc_escortAI::UpdateEscortAI(uint32 /*diff*/)
void npc_escortAI::MovementInform(uint32 moveType, uint32 pointId)
{
- if (moveType != POINT_MOTION_TYPE || !HasEscortState(STATE_ESCORT_ESCORTING))
+ // no action allowed if there is no escort
+ if (!HasEscortState(STATE_ESCORT_ESCORTING))
return;
- //Combat start position reached, continue waypoint movement
- if (pointId == POINT_LAST_POINT)
+ if (moveType == POINT_MOTION_TYPE)
{
- TC_LOG_DEBUG("scripts", "EscortAI has returned to original position before combat");
-
- me->SetWalk(!m_bIsRunning);
- RemoveEscortState(STATE_ESCORT_RETURNING);
-
if (!m_uiWPWaitTimer)
m_uiWPWaitTimer = 1;
- }
- else if (pointId == POINT_HOME)
- {
- TC_LOG_DEBUG("scripts", "EscortAI has returned to original home location and will continue from beginning of waypoint list.");
- CurrentWP = WaypointList.begin();
- m_uiWPWaitTimer = 1;
+ //Combat start position reached, continue waypoint movement
+ if (pointId == POINT_LAST_POINT)
+ {
+ TC_LOG_DEBUG("scripts", "EscortAI has returned to original position before combat");
+
+ me->SetWalk(!m_bIsRunning);
+ RemoveEscortState(STATE_ESCORT_RETURNING);
+ }
+ else if (pointId == POINT_HOME)
+ {
+ TC_LOG_DEBUG("scripts", "EscortAI has returned to original home location and will continue from beginning of waypoint list.");
+
+ m_bStarted = false;
+ }
}
- else
+ else if (moveType == WAYPOINT_MOTION_TYPE)
{
- //Make sure that we are still on the right waypoint
- if (CurrentWP->id != pointId)
+ //Call WP function
+ WaypointReached(pointId);
+
+ //End of the line
+ if (LastWP && LastWP == pointId)
{
- TC_LOG_ERROR("misc", "TSCR ERROR: EscortAI reached waypoint out of order %u, expected %u, creature entry %u", pointId, CurrentWP->id, me->GetEntry());
+ LastWP = 0;
+
+ m_bStarted = false;
+ m_bEnded = true;
+
+ m_uiWPWaitTimer = 50;
+
return;
}
- TC_LOG_DEBUG("scripts", "EscortAI Waypoint %u reached", CurrentWP->id);
+ TC_LOG_DEBUG("scripts", "EscortAI Waypoint %u reached", pointId);
- //Call WP function
- WaypointReached(CurrentWP->id);
+ WaypointMovementGenerator<Creature>* move = dynamic_cast<WaypointMovementGenerator<Creature>*>(me->GetMotionMaster()->top());
+
+ if (move)
+ m_uiWPWaitTimer = move->GetTrackerTimer().GetExpiry();
- m_uiWPWaitTimer = CurrentWP->WaitTimeMs + 1;
+ //Call WP start function
+ if (!m_uiWPWaitTimer && !HasEscortState(STATE_ESCORT_PAUSED) && move)
+ WaypointStart(move->GetCurrentNode());
- ++CurrentWP;
+ if (m_bIsRunning)
+ me->SetWalk(false);
+ else
+ me->SetWalk(true);
}
}
@@ -389,9 +373,24 @@ void npc_escortAI::OnPossess(bool apply)
void npc_escortAI::AddWaypoint(uint32 id, float x, float y, float z, uint32 waitTime)
{
- Escort_Waypoint t(id, x, y, z, waitTime);
+ Trinity::NormalizeMapCoord(x);
+ Trinity::NormalizeMapCoord(y);
- WaypointList.push_back(t);
+ WaypointNode wp;
+
+ wp.id = id;
+ wp.x = x;
+ wp.y = y;
+ wp.z = z;
+ wp.orientation = 0.f;
+ wp.moveType = m_bIsRunning ? WAYPOINT_MOVE_TYPE_RUN : WAYPOINT_MOVE_TYPE_WALK;
+ wp.delay = waitTime;
+ wp.eventId = 0;
+ wp.eventChance = 100;
+
+ _path.nodes.push_back(std::move(wp));
+
+ LastWP = id;
// i think SD2 no longer uses this function
ScriptWP = true;
@@ -411,10 +410,30 @@ void npc_escortAI::FillPointMovementListForCreature()
if (!movePoints)
return;
- for (ScriptPointVector::const_iterator itr = movePoints->begin(); itr != movePoints->end(); ++itr)
+ LastWP = movePoints->back().uiPointId;
+
+ for (const ScriptPointMove &point : *movePoints)
{
- Escort_Waypoint point(itr->uiPointId, itr->fX, itr->fY, itr->fZ, itr->uiWaitTime);
- WaypointList.push_back(point);
+ WaypointNode wp;
+
+ float x = point.fX;
+ float y = point.fY;
+ float z = point.fZ;
+
+ Trinity::NormalizeMapCoord(x);
+ Trinity::NormalizeMapCoord(y);
+
+ wp.id = point.uiPointId;
+ wp.x = x;
+ wp.y = y;
+ wp.z = z;
+ wp.orientation = 0.f;
+ wp.moveType = m_bIsRunning ? WAYPOINT_MOVE_TYPE_RUN : WAYPOINT_MOVE_TYPE_WALK;
+ wp.delay = point.uiWaitTime;
+ wp.eventId = 0;
+ wp.eventChance = 100;
+
+ _path.nodes.push_back(std::move(wp));
}
}
@@ -453,20 +472,6 @@ void npc_escortAI::Start(bool isActiveAttacker /* = true*/, bool run /* = false
return;
}
- if (!ScriptWP && resetWaypoints) // sd2 never adds wp in script, but tc does
- {
- if (!WaypointList.empty())
- WaypointList.clear();
- FillPointMovementListForCreature();
- }
-
- if (WaypointList.empty())
- {
- TC_LOG_ERROR("scripts", "EscortAI (script: %s, creature entry: %u) starts with 0 waypoints (possible missing entry in script_waypoint. Quest: %u).",
- me->GetScriptName().c_str(), me->GetEntry(), quest ? quest->GetQuestId() : 0);
- return;
- }
-
//set variables
m_bIsActiveAttacker = isActiveAttacker;
m_bIsRunning = run;
@@ -477,12 +482,16 @@ void npc_escortAI::Start(bool isActiveAttacker /* = true*/, bool run /* = false
m_bCanInstantRespawn = instantRespawn;
m_bCanReturnToStart = canLoopPath;
+ if (!ScriptWP && resetWaypoints) // sd2 never adds wp in script, but tc does
+ FillPointMovementListForCreature();
+
if (m_bCanReturnToStart && m_bCanInstantRespawn)
TC_LOG_DEBUG("scripts", "EscortAI is set to return home after waypoint end and instant respawn at waypoint end. Creature will never despawn.");
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE)
{
- me->GetMotionMaster()->MovementExpired();
+ me->StopMoving();
+ me->GetMotionMaster()->Clear(false);
me->GetMotionMaster()->MoveIdle();
TC_LOG_DEBUG("scripts", "EscortAI start with WAYPOINT_MOTION_TYPE, changed to MoveIdle.");
}
@@ -495,9 +504,7 @@ void npc_escortAI::Start(bool isActiveAttacker /* = true*/, bool run /* = false
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC);
}
- TC_LOG_DEBUG("scripts", "EscortAI started with " UI64FMTD " waypoints. ActiveAttacker = %d, Run = %d, %s", uint64(WaypointList.size()), m_bIsActiveAttacker, m_bIsRunning, m_uiPlayerGUID.ToString().c_str());
-
- CurrentWP = WaypointList.begin();
+ TC_LOG_DEBUG("scripts", "EscortAI started. ActiveAttacker = %d, Run = %d, PlayerGUID = %s", uint32(m_bIsActiveAttacker), uint32(m_bIsRunning), m_uiPlayerGUID.ToString().c_str());
//Set initial speed
if (m_bIsRunning)
@@ -505,6 +512,8 @@ void npc_escortAI::Start(bool isActiveAttacker /* = true*/, bool run /* = false
else
me->SetWalk(true);
+ m_bStarted = false;
+
AddEscortState(STATE_ESCORT_ESCORTING);
}
@@ -514,73 +523,14 @@ void npc_escortAI::SetEscortPaused(bool on)
return;
if (on)
- AddEscortState(STATE_ESCORT_PAUSED);
- else
- RemoveEscortState(STATE_ESCORT_PAUSED);
-}
-
-bool npc_escortAI::SetNextWaypoint(uint32 pointId, float x, float y, float z, float orientation)
-{
- me->UpdatePosition(x, y, z, orientation);
- return SetNextWaypoint(pointId, false, true);
-}
-
-bool npc_escortAI::SetNextWaypoint(uint32 pointId, bool setPosition, bool resetWaypointsOnFail)
-{
- if (!WaypointList.empty())
- WaypointList.clear();
-
- FillPointMovementListForCreature();
-
- if (WaypointList.empty())
- return false;
-
- size_t const size = WaypointList.size();
- Escort_Waypoint waypoint(0, 0, 0, 0, 0);
- do
- {
- waypoint = WaypointList.front();
- WaypointList.pop_front();
- if (waypoint.id == pointId)
- {
- if (setPosition)
- me->UpdatePosition(waypoint.x, waypoint.y, waypoint.z, me->GetOrientation());
-
- CurrentWP = WaypointList.begin();
- return true;
- }
- }
- while (!WaypointList.empty());
-
- // we failed.
- // we reset the waypoints in the start; if we pulled any, reset it again
- if (resetWaypointsOnFail && size != WaypointList.size())
{
- if (!WaypointList.empty())
- WaypointList.clear();
-
- FillPointMovementListForCreature();
+ AddEscortState(STATE_ESCORT_PAUSED);
+ me->StopMoving();
}
-
- return false;
-}
-
-bool npc_escortAI::GetWaypointPosition(uint32 pointId, float& x, float& y, float& z)
-{
- ScriptPointVector const* waypoints = sScriptSystemMgr->GetPointMoveList(me->GetEntry());
- if (!waypoints)
- return false;
-
- for (ScriptPointVector::const_iterator itr = waypoints->begin(); itr != waypoints->end(); ++itr)
+ else
{
- if (itr->uiPointId == pointId)
- {
- x = itr->fX;
- y = itr->fY;
- z = itr->fZ;
- return true;
- }
+ RemoveEscortState(STATE_ESCORT_PAUSED);
+ if (WaypointMovementGenerator<Creature>* move = dynamic_cast<WaypointMovementGenerator<Creature>*>(me->GetMotionMaster()->top()))
+ move->GetTrackerTimer().Reset(1);
}
-
- return false;
}
diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h
index bc3be71af68..91646c53270 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h
+++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h
@@ -21,29 +21,12 @@
#include "ScriptedCreature.h"
#include "ScriptSystem.h"
+#include "WaypointDefines.h"
class Quest;
#define DEFAULT_MAX_PLAYER_DISTANCE 50
-struct Escort_Waypoint
-{
- Escort_Waypoint(uint32 _id, float _x, float _y, float _z, uint32 _w)
- {
- id = _id;
- x = _x;
- y = _y;
- z = _z;
- WaitTimeMs = _w;
- }
-
- uint32 id;
- float x;
- float y;
- float z;
- uint32 WaitTimeMs;
-};
-
enum eEscortState
{
STATE_ESCORT_NONE = 0x000, //nothing in progress
@@ -59,7 +42,6 @@ struct TC_GAME_API npc_escortAI : public ScriptedAI
~npc_escortAI() { }
// CreatureAI functions
- void AttackStart(Unit* who) override;
void MoveInLineOfSight(Unit* who) override;
@@ -79,15 +61,6 @@ struct TC_GAME_API npc_escortAI : public ScriptedAI
// EscortAI functions
void AddWaypoint(uint32 id, float x, float y, float z, uint32 waitTime = 0); // waitTime is in ms
- //this will set the current position to x/y/z/o, and the current WP to pointId.
- bool SetNextWaypoint(uint32 pointId, float x, float y, float z, float orientation);
-
- //this will set the current position to WP start position (if setPosition == true),
- //and the current WP to pointId
- bool SetNextWaypoint(uint32 pointId, bool setPosition = true, bool resetWaypointsOnFail = true);
-
- bool GetWaypointPosition(uint32 pointId, float& x, float& y, float& z);
-
virtual void WaypointReached(uint32 pointId) = 0;
virtual void WaypointStart(uint32 /*pointId*/) { }
@@ -107,6 +80,7 @@ struct TC_GAME_API npc_escortAI : public ScriptedAI
bool GetAttack() const { return m_bIsActiveAttacker; }//used in EnterEvadeMode override
void SetCanAttack(bool attack) { m_bIsActiveAttacker = attack; }
ObjectGuid GetEventStarterGUID() const { return m_uiPlayerGUID; }
+ void SetWaitTimer(uint32 Timer) { m_uiWPWaitTimer = Timer; }
protected:
Player* GetPlayerForEscort();
@@ -124,11 +98,11 @@ struct TC_GAME_API npc_escortAI : public ScriptedAI
uint32 m_uiPlayerCheckTimer;
uint32 m_uiEscortState;
float MaxPlayerDistance;
+ uint32 LastWP;
- Quest const* m_pQuestForEscort; //generally passed in Start() when regular escort script.
+ WaypointPath _path;
- std::list<Escort_Waypoint> WaypointList;
- std::list<Escort_Waypoint>::iterator CurrentWP;
+ Quest const* m_pQuestForEscort; //generally passed in Start() when regular escort script.
bool m_bIsActiveAttacker; //obsolete, determined by faction.
bool m_bIsRunning; //all creatures are walking by default (has flag MOVEMENTFLAG_WALK)
@@ -138,5 +112,7 @@ struct TC_GAME_API npc_escortAI : public ScriptedAI
bool DespawnAtFar;
bool ScriptWP;
bool HasImmuneToNPCFlags;
+ bool m_bStarted;
+ bool m_bEnded;
};
#endif
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index e1c3d879265..d0b9a9b23b0 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -26,33 +26,30 @@
#include "PetDefines.h"
#include "Player.h"
#include "ScriptMgr.h"
+#include "WaypointMovementGenerator.h"
SmartAI::SmartAI(Creature* c) : CreatureAI(c)
{
mIsCharmed = false;
// copy script to local (protection for table reload)
- mWayPoints = nullptr;
mEscortState = SMART_ESCORT_NONE;
mCurrentWPID = 0;//first wp id is 1 !!
mWPReached = false;
mWPPauseTimer = 0;
- mLastWP = nullptr;
+ mOOCReached = false;
+ mEscortNPCFlags = 0;
mCanRepeatPath = false;
- // spawn in run mode
- me->SetWalk(false);
- mRun = false;
- mEvadeDisabled = false;
-
- mLastOOCPos = me->GetPosition();
+ // Spawn in run mode
+ mRun = true;
+ m_Ended = false;
mCanAutoAttack = true;
mCanCombatMove = true;
mForcedPaused = false;
- mLastWPIDReached = 0;
mEscortQuestID = 0;
@@ -72,6 +69,10 @@ SmartAI::SmartAI(Creature* c) : CreatureAI(c)
mJustReset = false;
}
+SmartAI::~SmartAI()
+{
+}
+
bool SmartAI::IsAIControlled() const
{
return !mIsCharmed;
@@ -95,63 +96,79 @@ void SmartAI::UpdateDespawn(const uint32 diff)
} else mDespawnTime -= diff;
}
-WayPoint* SmartAI::GetNextWayPoint()
-{
- if (!mWayPoints || mWayPoints->empty())
- return nullptr;
-
- mCurrentWPID++;
- WPPath::const_iterator itr = mWayPoints->find(mCurrentWPID);
- if (itr != mWayPoints->end())
- {
- mLastWP = (*itr).second;
- if (mLastWP->id != mCurrentWPID)
- {
- TC_LOG_ERROR("misc", "SmartAI::GetNextWayPoint: Got not expected waypoint id %u, expected %u", mLastWP->id, mCurrentWPID);
- }
- return (*itr).second;
- }
- return nullptr;
-}
-
-void SmartAI::StartPath(bool run, uint32 path, bool repeat, Unit* /*invoker*/)
+void SmartAI::StartPath(bool run, uint32 path, bool repeat, Unit* invoker)
{
if (me->IsInCombat())// no wp movement in combat
{
TC_LOG_ERROR("misc", "SmartAI::StartPath: Creature entry %u wanted to start waypoint movement while in combat, ignoring.", me->GetEntry());
return;
}
+
if (HasEscortState(SMART_ESCORT_ESCORTING))
StopPath();
+
+ SetRun(run);
+
if (path)
if (!LoadPath(path))
return;
- if (!mWayPoints || mWayPoints->empty())
+
+ if (_path.nodes.empty())
return;
- AddEscortState(SMART_ESCORT_ESCORTING);
- mCanRepeatPath = repeat;
+ mCurrentWPID = 1;
+ m_Ended = false;
- SetRun(run);
+ // Do not use AddEscortState, removing everything from previous cycle
+ mEscortState = SMART_ESCORT_ESCORTING;
+ mCanRepeatPath = repeat;
- if (WayPoint* wp = GetNextWayPoint())
+ if (invoker && invoker->GetTypeId() == TYPEID_PLAYER)
{
- mLastOOCPos = me->GetPosition();
- me->GetMotionMaster()->MovePoint(wp->id, wp->x, wp->y, wp->z);
- GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_START, nullptr, wp->id, GetScript()->GetPathId());
+ mEscortNPCFlags = me->GetUInt32Value(UNIT_NPC_FLAGS);
+ me->SetFlag(UNIT_NPC_FLAGS, 0);
}
+
+ GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_START, nullptr, mCurrentWPID, GetScript()->GetPathId());
+
+ me->GetMotionMaster()->MovePath(_path, mCanRepeatPath);
}
bool SmartAI::LoadPath(uint32 entry)
{
if (HasEscortState(SMART_ESCORT_ESCORTING))
return false;
- mWayPoints = sSmartWaypointMgr->GetPath(entry);
- if (!mWayPoints)
+
+ WPPath const* path = sSmartWaypointMgr->GetPath(entry);
+ if (!path || path->empty())
{
GetScript()->SetPathId(0);
return false;
}
+
+ for (WayPoint const &waypoint : *path)
+ {
+ float x = waypoint.x;
+ float y = waypoint.y;
+ float z = waypoint.z;
+
+ Trinity::NormalizeMapCoord(x);
+ Trinity::NormalizeMapCoord(y);
+
+ WaypointNode wp;
+ wp.id = waypoint.id;
+ wp.x = x;
+ wp.y = y;
+ wp.z = z;
+ wp.orientation = 0.f;
+ wp.moveType = mRun ? WAYPOINT_MOVE_TYPE_RUN : WAYPOINT_MOVE_TYPE_WALK;
+ wp.delay = 0;
+ wp.eventId = 0;
+ wp.eventChance = 100;
+
+ _path.nodes.push_back(std::move(wp));
+ }
+
GetScript()->SetPathId(entry);
return true;
}
@@ -160,22 +177,22 @@ void SmartAI::PausePath(uint32 delay, bool forced)
{
if (!HasEscortState(SMART_ESCORT_ESCORTING))
return;
+
if (HasEscortState(SMART_ESCORT_PAUSED))
{
- TC_LOG_ERROR("misc", "SmartAI::PausePath: Creature entry %u wanted to pause waypoint movement while already paused, ignoring.", me->GetEntry());
+ TC_LOG_ERROR("misc", "SmartAI::PausePath: Creature entry %u wanted to pause waypoint (current waypoint: %u) movement while already paused, ignoring.", me->GetEntry(), mCurrentWPID);
return;
}
- mForcedPaused = forced;
- mLastOOCPos = me->GetPosition();
+
AddEscortState(SMART_ESCORT_PAUSED);
mWPPauseTimer = delay;
- if (forced)
+ if (forced && !mWPReached)
{
+ mForcedPaused = forced;
SetRun(mRun);
- me->StopMoving();//force stop
- me->GetMotionMaster()->MoveIdle();//force stop
+ me->StopMoving();
}
- GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_PAUSED, nullptr, mLastWP->id, GetScript()->GetPathId());
+ GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_PAUSED, nullptr, mCurrentWPID, GetScript()->GetPathId());
}
void SmartAI::StopPath(uint32 DespawnTime, uint32 quest, bool fail)
@@ -185,33 +202,28 @@ void SmartAI::StopPath(uint32 DespawnTime, uint32 quest, bool fail)
if (quest)
mEscortQuestID = quest;
- SetDespawnTime(DespawnTime);
- //mDespawnTime = DespawnTime;
- mLastOOCPos = me->GetPosition();
- me->StopMoving();//force stop
+ if (mDespawnState != 2)
+ SetDespawnTime(DespawnTime);
+
+ me->StopMoving();
+ me->GetMotionMaster()->MovementExpired(false);
me->GetMotionMaster()->MoveIdle();
- GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_STOPPED, nullptr, mLastWP->id, GetScript()->GetPathId());
+ GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_STOPPED, nullptr, mCurrentWPID, GetScript()->GetPathId());
EndPath(fail);
}
void SmartAI::EndPath(bool fail)
{
- GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_ENDED, nullptr, mLastWP->id, GetScript()->GetPathId());
-
RemoveEscortState(SMART_ESCORT_ESCORTING | SMART_ESCORT_PAUSED | SMART_ESCORT_RETURNING);
- mWayPoints = nullptr;
- mCurrentWPID = 0;
+ _path.nodes.clear();
mWPPauseTimer = 0;
- mLastWP = nullptr;
- if (mCanRepeatPath)
+ if (mEscortNPCFlags)
{
- if (IsAIControlled())
- StartPath(mRun, GetScript()->GetPathId(), true);
+ me->SetFlag(UNIT_NPC_FLAGS, mEscortNPCFlags);
+ mEscortNPCFlags = 0;
}
- else
- GetScript()->SetPathId(0);
ObjectList* targets = GetScript()->GetTargetList(SMART_ESCORT_TARGETS);
if (targets && mEscortQuestID)
@@ -253,15 +265,36 @@ void SmartAI::EndPath(bool fail)
}
}
}
+
+ // End Path events should be only processed if it was SUCCESSFUL stop or stop called by SMART_ACTION_WAYPOINT_STOP
+ if (fail)
+ return;
+
+ GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_ENDED, nullptr, mCurrentWPID, GetScript()->GetPathId());
+
+ if (mCanRepeatPath)
+ {
+ if (IsAIControlled())
+ StartPath(mRun, GetScript()->GetPathId(), mCanRepeatPath);
+ }
+ else
+ GetScript()->SetPathId(0);
+
if (mDespawnState == 1)
StartDespawn();
}
void SmartAI::ResumePath()
{
+ GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_RESUMED, NULL, mCurrentWPID, GetScript()->GetPathId());
+ RemoveEscortState(SMART_ESCORT_PAUSED);
+ mForcedPaused = false;
+ mWPReached = false;
+ mWPPauseTimer = 0;
SetRun(mRun);
- if (mLastWP)
- me->GetMotionMaster()->MovePoint(mLastWP->id, mLastWP->x, mLastWP->y, mLastWP->z);
+
+ if (WaypointMovementGenerator<Creature>* move = dynamic_cast<WaypointMovementGenerator<Creature>*>(me->GetMotionMaster()->top()))
+ move->GetTrackerTimer().Reset(1);
}
void SmartAI::ReturnToLastOOCPos()
@@ -269,69 +302,61 @@ void SmartAI::ReturnToLastOOCPos()
if (!IsAIControlled())
return;
- SetRun(mRun);
- me->GetMotionMaster()->MovePoint(SMART_ESCORT_LAST_OOC_POINT, mLastOOCPos);
+ me->SetWalk(false);
+ float x, y, z, o;
+ me->GetHomePosition(x, y, z, o);
+ me->GetMotionMaster()->MovePoint(SMART_ESCORT_LAST_OOC_POINT, x, y, z);
}
void SmartAI::UpdatePath(const uint32 diff)
{
if (!HasEscortState(SMART_ESCORT_ESCORTING))
return;
+
if (mEscortInvokerCheckTimer < diff)
{
if (!IsEscortInvokerInRange())
{
- StopPath(mDespawnTime, mEscortQuestID, true);
+ StopPath(0, mEscortQuestID, true);
+
+ // allow to properly hook out of range despawn action, which in most cases should perform the same operation as dying
+ GetScript()->ProcessEventsFor(SMART_EVENT_DEATH, me);
+ me->DespawnOrUnsummon(1);
+ return;
}
mEscortInvokerCheckTimer = 1000;
- } else mEscortInvokerCheckTimer -= diff;
+ }
+ else
+ mEscortInvokerCheckTimer -= diff;
+
// handle pause
if (HasEscortState(SMART_ESCORT_PAUSED))
{
- if (mWPPauseTimer < diff)
+ if (mWPPauseTimer <= diff)
{
- if (!me->IsInCombat() && !HasEscortState(SMART_ESCORT_RETURNING) && (mWPReached || mLastWPIDReached == SMART_ESCORT_LAST_OOC_POINT || mForcedPaused))
+ if (!me->IsInCombat() && !HasEscortState(SMART_ESCORT_RETURNING) && (mWPReached || mForcedPaused))
{
- GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_RESUMED, nullptr, mLastWP->id, GetScript()->GetPathId());
- RemoveEscortState(SMART_ESCORT_PAUSED);
- if (mForcedPaused)// if paused between 2 wps resend movement
- {
- ResumePath();
- mWPReached = false;
- mForcedPaused = false;
- }
- if (mLastWPIDReached == SMART_ESCORT_LAST_OOC_POINT)
- mWPReached = true;
+ ResumePath();
}
- mWPPauseTimer = 0;
- } else {
- mWPPauseTimer -= diff;
}
+ else
+ mWPPauseTimer -= diff;
}
+ else if (m_Ended) // end path
+ {
+ m_Ended = false;
+ StopPath();
+ return;
+ }
+
if (HasEscortState(SMART_ESCORT_RETURNING))
{
- if (mWPReached)//reached OOC WP
+ if (mOOCReached)//reached OOC WP
{
+ mOOCReached = false;
RemoveEscortState(SMART_ESCORT_RETURNING);
if (!HasEscortState(SMART_ESCORT_PAUSED))
ResumePath();
- mWPReached = false;
- }
- }
- if ((!me->HasReactState(REACT_PASSIVE) && me->IsInCombat()) || HasEscortState(SMART_ESCORT_PAUSED | SMART_ESCORT_RETURNING))
- return;
- // handle next wp
- if (mWPReached)//reached WP
- {
- mWPReached = false;
- if (mCurrentWPID == GetWPCount())
- {
- EndPath();
- }
- else if (WayPoint* wp = GetNextWayPoint())
- {
- SetRun(mRun);
- me->GetMotionMaster()->MovePoint(wp->id, wp->x, wp->y, wp->z);
}
}
}
@@ -408,22 +433,44 @@ bool SmartAI::IsEscortInvokerInRange()
void SmartAI::MovepointReached(uint32 id)
{
- if (id != SMART_ESCORT_LAST_OOC_POINT && mLastWPIDReached != id)
- GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_REACHED, nullptr, id);
+ // override the id, path can be resumed any time and counter will reset
+ // mCurrentWPID holds proper id
+
+ // both point movement and escort generator can enter this function
+ if (id == SMART_ESCORT_LAST_OOC_POINT)
+ {
+ mOOCReached = true;
+ return;
+ }
+
+ mCurrentWPID = id + 1; // in SmartAI increase by 1
- mLastWPIDReached = id;
mWPReached = true;
+ GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_REACHED, nullptr, mCurrentWPID, GetScript()->GetPathId());
+
+ if (HasEscortState(SMART_ESCORT_PAUSED))
+ me->StopMoving();
+ else if (HasEscortState(SMART_ESCORT_ESCORTING) && me->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE)
+ {
+ mWPReached = false;
+ if (mCurrentWPID == _path.nodes.size())
+ m_Ended = true;
+ else
+ SetRun(mRun);
+ }
}
void SmartAI::MovementInform(uint32 MovementType, uint32 Data)
{
- if ((MovementType == POINT_MOTION_TYPE && Data == SMART_ESCORT_LAST_OOC_POINT) || MovementType == FOLLOW_MOTION_TYPE)
+ if (MovementType == POINT_MOTION_TYPE && Data == SMART_ESCORT_LAST_OOC_POINT)
me->ClearUnitState(UNIT_STATE_EVADE);
GetScript()->ProcessEventsFor(SMART_EVENT_MOVEMENTINFORM, nullptr, MovementType, Data);
- if (MovementType != POINT_MOTION_TYPE || !HasEscortState(SMART_ESCORT_ESCORTING))
+ if (!HasEscortState(SMART_ESCORT_ESCORTING))
return;
- MovepointReached(Data);
+
+ if (MovementType == WAYPOINT_MOTION_TYPE || (MovementType == POINT_MOTION_TYPE && Data == SMART_ESCORT_LAST_OOC_POINT))
+ MovepointReached(Data);
}
void SmartAI::EnterEvadeMode(EvadeReason /*why*/)
@@ -451,6 +498,7 @@ void SmartAI::EnterEvadeMode(EvadeReason /*why*/)
me->GetMotionMaster()->MoveFollow(target, mFollowDist, mFollowAngle);
// evade is not cleared in MoveFollow, so we can't keep it
me->ClearUnitState(UNIT_STATE_EVADE);
+ GetScript()->OnReset();
}
else if (Unit* owner = me->GetCharmerOrOwner())
{
@@ -460,8 +508,8 @@ void SmartAI::EnterEvadeMode(EvadeReason /*why*/)
else
me->GetMotionMaster()->MoveTargetedHome();
- if (!HasEscortState(SMART_ESCORT_ESCORTING)) //dont mess up escort movement after combat
- SetRun(mRun);
+ if (!me->HasUnitState(UNIT_STATE_EVADE))
+ GetScript()->OnReset();
}
void SmartAI::MoveInLineOfSight(Unit* who)
@@ -574,24 +622,13 @@ void SmartAI::EnterCombat(Unit* enemy)
me->InterruptNonMeleeSpells(false); // must be before ProcessEvents
GetScript()->ProcessEventsFor(SMART_EVENT_AGGRO, enemy);
-
- if (!IsAIControlled())
- return;
- mLastOOCPos = me->GetPosition();
- SetRun(mRun);
- if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_ACTIVE) == POINT_MOTION_TYPE)
- me->GetMotionMaster()->MovementExpired();
}
void SmartAI::JustDied(Unit* killer)
{
GetScript()->ProcessEventsFor(SMART_EVENT_DEATH, killer);
if (HasEscortState(SMART_ESCORT_ESCORTING))
- {
EndPath(true);
- me->StopMoving();//force stop
- me->GetMotionMaster()->MoveIdle();
- }
}
void SmartAI::KilledUnit(Unit* victim)
@@ -606,10 +643,26 @@ void SmartAI::JustSummoned(Creature* creature)
void SmartAI::AttackStart(Unit* who)
{
+ // dont allow charmed npcs to act on their own
+ if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED))
+ {
+ if (who && mCanAutoAttack)
+ me->Attack(who, true);
+ return;
+ }
+
if (who && me->Attack(who, me->IsWithinMeleeRange(who)))
{
if (mCanCombatMove)
+ {
+ SetRun(mRun);
+
+ MovementGeneratorType type = me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_ACTIVE);
+ if (type == WAYPOINT_MOTION_TYPE || type == POINT_MOTION_TYPE)
+ me->StopMoving();
+
me->GetMotionMaster()->MoveChase(who);
+ }
}
}
@@ -777,6 +830,7 @@ void SmartAI::SetCombatMove(bool on)
{
if (mCanCombatMove == on)
return;
+
mCanCombatMove = on;
if (!IsAIControlled())
return;
@@ -793,12 +847,9 @@ void SmartAI::SetCombatMove(bool on)
}
else
{
- if (me->HasUnitState(UNIT_STATE_CONFUSED_MOVE | UNIT_STATE_FLEEING_MOVE))
- return;
-
- me->GetMotionMaster()->MovementExpired();
- me->GetMotionMaster()->Clear(true);
me->StopMoving();
+ if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
+ me->GetMotionMaster()->Clear(false);
me->GetMotionMaster()->MoveIdle();
}
}
diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h
index fbfa2783db8..4e46339bcaa 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.h
+++ b/src/server/game/AI/SmartScripts/SmartAI.h
@@ -23,8 +23,7 @@
#include "GameObjectAI.h"
#include "Position.h"
#include "SmartScript.h"
-
-struct WayPoint;
+#include "WaypointDefines.h"
enum SmartEscortState
{
@@ -43,7 +42,7 @@ enum SmartEscortVars
class TC_GAME_API SmartAI : public CreatureAI
{
public:
- ~SmartAI(){ }
+ ~SmartAI();
explicit SmartAI(Creature* c);
// Check whether we are currently permitted to make the creature take action
@@ -56,7 +55,6 @@ class TC_GAME_API SmartAI : public CreatureAI
void StopPath(uint32 DespawnTime = 0, uint32 quest = 0, bool fail = false);
void EndPath(bool fail = false);
void ResumePath();
- WayPoint* GetNextWayPoint();
bool HasEscortState(uint32 uiEscortState) const { return (mEscortState & uiEscortState) != 0; }
void AddEscortState(uint32 uiEscortState) { mEscortState |= uiEscortState; }
void RemoveEscortState(uint32 uiEscortState) { mEscortState &= ~uiEscortState; }
@@ -209,15 +207,13 @@ class TC_GAME_API SmartAI : public CreatureAI
void ReturnToLastOOCPos();
void UpdatePath(const uint32 diff);
SmartScript mScript;
- WPPath* mWayPoints;
uint32 mEscortState;
uint32 mCurrentWPID;
- uint32 mLastWPIDReached;
bool mWPReached;
+ bool mOOCReached;
+ bool m_Ended;
uint32 mWPPauseTimer;
- WayPoint* mLastWP;
- Position mLastOOCPos;//set on enter combat
- uint32 GetWPCount() const { return mWayPoints ? uint32(mWayPoints->size()) : 0; }
+ uint32 mEscortNPCFlags;
bool mCanRepeatPath;
bool mRun;
bool mEvadeDisabled;
@@ -227,6 +223,7 @@ class TC_GAME_API SmartAI : public CreatureAI
uint32 mInvincibilityHpLevel;
bool AssistPlayerInCombatAgainst(Unit* who);
+ WaypointPath _path;
uint32 mDespawnTime;
uint32 mRespawnTime;
uint32 mDespawnState;
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index b20329cd319..f5ccf93006b 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -2461,64 +2461,6 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
sGameEventMgr->StartEvent(eventId, true);
break;
}
- case SMART_ACTION_START_CLOSEST_WAYPOINT:
- {
- uint32 waypoints[SMART_ACTION_PARAM_COUNT];
- waypoints[0] = e.action.closestWaypointFromList.wp1;
- waypoints[1] = e.action.closestWaypointFromList.wp2;
- waypoints[2] = e.action.closestWaypointFromList.wp3;
- waypoints[3] = e.action.closestWaypointFromList.wp4;
- waypoints[4] = e.action.closestWaypointFromList.wp5;
- waypoints[5] = e.action.closestWaypointFromList.wp6;
- float distanceToClosest = std::numeric_limits<float>::max();
- WayPoint* closestWp = nullptr;
-
- ObjectList* targets = GetTargets(e, unit);
- if (targets)
- {
- for (ObjectList::iterator itr = targets->begin(); itr != targets->end(); ++itr)
- {
- if (Creature* target = (*itr)->ToCreature())
- {
- if (IsSmart(target))
- {
- for (uint8 i = 0; i < SMART_ACTION_PARAM_COUNT; i++)
- {
- if (!waypoints[i])
- continue;
-
- WPPath* path = sSmartWaypointMgr->GetPath(waypoints[i]);
-
- if (!path || path->empty())
- continue;
-
- WPPath::const_iterator itrWp = path->find(0);
-
- if (itrWp != path->end())
- {
- if (WayPoint* wp = itrWp->second)
- {
- float distToThisPath = target->GetDistance(wp->x, wp->y, wp->z);
-
- if (distToThisPath < distanceToClosest)
- {
- distanceToClosest = distToThisPath;
- closestWp = wp;
- }
- }
- }
- }
-
- if (closestWp)
- CAST_AI(SmartAI, target->AI())->StartPath(false, closestWp->id, true);
- }
- }
- }
-
- delete targets;
- }
- break;
- }
case SMART_ACTION_RANDOM_SOUND:
{
std::vector<uint32> sounds;
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index 30433bc328b..60b5e63936b 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -41,14 +41,6 @@ void SmartWaypointMgr::LoadFromDB()
{
uint32 oldMSTime = getMSTime();
- for (std::unordered_map<uint32, WPPath*>::iterator itr = waypoint_map.begin(); itr != waypoint_map.end(); ++itr)
- {
- for (WPPath::iterator pathItr = itr->second->begin(); pathItr != itr->second->end(); ++pathItr)
- delete pathItr->second;
-
- delete itr->second;
- }
-
waypoint_map.clear();
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_SMARTAI_WP);
@@ -76,9 +68,10 @@ void SmartWaypointMgr::LoadFromDB()
y = fields[3].GetFloat();
z = fields[4].GetFloat();
+ WPPath& path = waypoint_map[entry];
+
if (last_entry != entry)
{
- waypoint_map[entry] = new WPPath();
last_id = 1;
count++;
}
@@ -87,7 +80,14 @@ void SmartWaypointMgr::LoadFromDB()
TC_LOG_ERROR("sql.sql", "SmartWaypointMgr::LoadFromDB: Path entry %u, unexpected point id %u, expected %u.", entry, id, last_id);
last_id++;
- (*waypoint_map[entry])[id] = new WayPoint(id, x, y, z);
+
+ WayPoint point;
+ point.id = id;
+ point.x = x;
+ point.y = y;
+ point.z = z;
+
+ path.push_back(std::move(point));
last_entry = entry;
total++;
@@ -97,17 +97,6 @@ void SmartWaypointMgr::LoadFromDB()
TC_LOG_INFO("server.loading", ">> Loaded %u SmartAI waypoint paths (total %u waypoints) in %u ms", count, total, GetMSTimeDiffToNow(oldMSTime));
}
-SmartWaypointMgr::~SmartWaypointMgr()
-{
- for (std::unordered_map<uint32, WPPath*>::iterator itr = waypoint_map.begin(); itr != waypoint_map.end(); ++itr)
- {
- for (WPPath::iterator pathItr = itr->second->begin(); pathItr != itr->second->end(); ++pathItr)
- delete pathItr->second;
-
- delete itr->second;
- }
-}
-
SmartAIMgr* SmartAIMgr::instance()
{
static SmartAIMgr instance;
@@ -1249,7 +1238,8 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
break;
case SMART_ACTION_WP_START:
{
- if (!sSmartWaypointMgr->GetPath(e.action.wpStart.pathID))
+ WPPath const* path = sSmartWaypointMgr->GetPath(e.action.wpStart.pathID);
+ if (!path || path->empty())
{
TC_LOG_ERROR("sql.sql", "SmartAIMgr: Creature " SI64FMTD " Event %u Action %u uses non-existent WaypointPath id %u, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.wpStart.pathID);
return false;
@@ -1411,7 +1401,6 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
break;
}
- case SMART_ACTION_START_CLOSEST_WAYPOINT:
case SMART_ACTION_FOLLOW:
case SMART_ACTION_SET_ORIENTATION:
case SMART_ACTION_STORE_TARGET_LIST:
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index 2c2768830fd..87d142aa0ab 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -29,13 +29,7 @@ enum SpellEffIndex : uint8;
struct WayPoint
{
- WayPoint(uint32 _id, float _x, float _y, float _z)
- {
- id = _id;
- x = _x;
- y = _y;
- z = _z;
- }
+ WayPoint() : id(0), x(0.0f), y(0.0f), z(0.0f) { }
uint32 id;
float x;
@@ -563,7 +557,7 @@ enum SMART_ACTION
SMART_ACTION_REMOVE_POWER = 110, // PowerType, newPower
SMART_ACTION_GAME_EVENT_STOP = 111, // GameEventId
SMART_ACTION_GAME_EVENT_START = 112, // GameEventId
- SMART_ACTION_START_CLOSEST_WAYPOINT = 113, // wp1, wp2, wp3, wp4, wp5, wp6, wp7
+ // Not used = 113,
SMART_ACTION_MOVE_OFFSET = 114,
SMART_ACTION_RANDOM_SOUND = 115, // soundId1, soundId2, soundId3, soundId4, soundId5, onlySelf
SMART_ACTION_SET_CORPSE_DELAY = 116, // timer
@@ -1460,7 +1454,7 @@ struct SmartScriptHolder
operator bool() const { return entryOrGuid != 0; }
};
-typedef std::unordered_map<uint32, WayPoint*> WPPath;
+typedef std::vector<WayPoint> WPPath;
typedef std::list<WorldObject*> ObjectList;
@@ -1492,22 +1486,23 @@ class TC_GAME_API SmartWaypointMgr
{
private:
SmartWaypointMgr() { }
- ~SmartWaypointMgr();
+ ~SmartWaypointMgr() { }
public:
static SmartWaypointMgr* instance();
void LoadFromDB();
- WPPath* GetPath(uint32 id)
+ WPPath const* GetPath(uint32 id)
{
- if (waypoint_map.find(id) != waypoint_map.end())
- return waypoint_map[id];
- else return nullptr;
+ auto itr = waypoint_map.find(id);
+ if (itr != waypoint_map.end())
+ return &itr->second;
+ return nullptr;
}
private:
- std::unordered_map<uint32, WPPath*> waypoint_map;
+ std::unordered_map<uint32, WPPath> waypoint_map;
};
// all events for a single entry
diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp
index 463ba3a5da1..f8836d01e52 100644
--- a/src/server/game/Movement/MotionMaster.cpp
+++ b/src/server/game/Movement/MotionMaster.cpp
@@ -701,6 +701,14 @@ void MotionMaster::MovePath(uint32 path_id, bool repeatable)
_owner->GetGUID().ToString().c_str(), path_id, repeatable ? "YES" : "NO");
}
+void MotionMaster::MovePath(WaypointPath& path, bool repeatable)
+{
+ Mutate(new WaypointMovementGenerator<Creature>(path, repeatable), MOTION_SLOT_IDLE);
+
+ TC_LOG_DEBUG("misc", "%s starts moving over path (repeatable: %s).",
+ _owner->GetGUID().ToString().c_str(), repeatable ? "YES" : "NO");
+}
+
void MotionMaster::MoveRotate(uint32 time, RotateDirection direction)
{
if (!time)
diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h
index fcf20e2aa7e..57dbbf29634 100644
--- a/src/server/game/Movement/MotionMaster.h
+++ b/src/server/game/Movement/MotionMaster.h
@@ -32,6 +32,7 @@ class PathGenerator;
struct Position;
struct SplineChainLink;
struct SplineChainResumeInfo;
+struct WaypointPath;
namespace G3D
{
@@ -180,6 +181,7 @@ class TC_GAME_API MotionMaster
void MoveTaxiFlight(uint32 path, uint32 pathnode);
void MoveDistract(uint32 time);
void MovePath(uint32 path_id, bool repeatable);
+ void MovePath(WaypointPath& path, bool repeatable);
void MoveRotate(uint32 time, RotateDirection direction);
private:
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
index 05116f42e97..f766909a796 100755
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
@@ -25,14 +25,18 @@
#include "MoveSplineInit.h"
#include "ObjectMgr.h"
#include "Transport.h"
+#include "WaypointManager.h"
#include "World.h"
void WaypointMovementGenerator<Creature>::LoadPath(Creature* creature)
{
- if (!path_id)
- path_id = creature->GetWaypointPath();
+ if (LoadedFromDB)
+ {
+ if (!path_id)
+ path_id = creature->GetWaypointPath();
- i_path = sWaypointMgr->GetPath(path_id);
+ i_path = sWaypointMgr->GetPath(path_id);
+ }
if (!i_path)
{
@@ -41,71 +45,92 @@ void WaypointMovementGenerator<Creature>::LoadPath(Creature* creature)
return;
}
- StartMoveNow(creature);
+ if (!Stopped())
+ StartMoveNow(creature);
}
void WaypointMovementGenerator<Creature>::DoInitialize(Creature* creature)
{
LoadPath(creature);
- creature->AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
}
void WaypointMovementGenerator<Creature>::DoFinalize(Creature* creature)
{
- creature->ClearUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
+ creature->ClearUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE);
creature->SetWalk(false);
}
void WaypointMovementGenerator<Creature>::DoReset(Creature* creature)
{
- creature->AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
- StartMoveNow(creature);
+ if (!Stopped())
+ StartMoveNow(creature);
}
void WaypointMovementGenerator<Creature>::OnArrived(Creature* creature)
{
- if (!i_path || i_path->empty())
- return;
- if (m_isArrivalDone)
+ if (!i_path || i_path->nodes.empty())
return;
- m_isArrivalDone = true;
+ WaypointNode const &waypoint = i_path->nodes.at(i_currentNode);
+ if (waypoint.delay)
+ {
+ creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
+ Stop(waypoint.delay);
+ }
- if (i_path->at(i_currentNode)->event_id && urand(0, 99) < i_path->at(i_currentNode)->event_chance)
+ if (waypoint.eventId && urand(0, 99) < waypoint.eventChance)
{
- TC_LOG_DEBUG("maps.script", "Creature movement start script %u at point %u for %s.", i_path->at(i_currentNode)->event_id, i_currentNode, creature->GetGUID().ToString().c_str());
+ TC_LOG_DEBUG("maps.script", "Creature movement start script %u at point %u for %s.", waypoint.eventId, i_currentNode, creature->GetGUID().ToString().c_str());
creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
- creature->GetMap()->ScriptsStart(sWaypointScripts, i_path->at(i_currentNode)->event_id, creature, NULL);
+ creature->GetMap()->ScriptsStart(sWaypointScripts, waypoint.eventId, creature, nullptr);
}
// Inform script
MovementInform(creature);
creature->UpdateWaypointID(i_currentNode);
- if (i_path->at(i_currentNode)->delay)
+ creature->SetWalk(waypoint.moveType != WAYPOINT_MOVE_TYPE_RUN);
+}
+
+void WaypointMovementGenerator<Creature>::FormationMove(Creature* creature)
+{
+ bool transportPath = creature->GetTransport() != nullptr;
+
+ WaypointNode const &waypoint = i_path->nodes.at(i_currentNode);
+
+ Movement::Location formationDest(waypoint.x, waypoint.y, waypoint.z, 0.0f);
+
+ //! If creature is on transport, we assume waypoints set in DB are already transport offsets
+ if (transportPath)
{
- creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
- Stop(i_path->at(i_currentNode)->delay);
+ if (TransportBase* trans = creature->GetDirectTransport())
+ trans->CalculatePassengerPosition(formationDest.x, formationDest.y, formationDest.z, &formationDest.orientation);
}
+
+ // Call for creature group update
+ if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature)
+ creature->GetFormation()->LeaderMoveTo(formationDest.x, formationDest.y, formationDest.z);
}
bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
{
- if (!i_path || i_path->empty())
+ if (!creature || !creature->IsAlive())
return false;
- if (Stopped())
- return true;
+ if (!i_path || i_path->nodes.empty())
+ return false;
- bool transportPath = creature->GetTransport() != NULL;
+ bool transportPath = creature->GetTransport() != nullptr;
- if (m_isArrivalDone)
+ if (IsArrivalDone)
{
- if ((i_currentNode == i_path->size() - 1) && !repeating) // If that's our last waypoint
+ if ((i_currentNode == i_path->nodes.size() - 1) && !repeating) // If that's our last waypoint
{
- float x = i_path->at(i_currentNode)->x;
- float y = i_path->at(i_currentNode)->y;
- float z = i_path->at(i_currentNode)->z;
+ WaypointNode const &waypoint = i_path->nodes.at(i_currentNode);
+
+ float x = waypoint.x;
+ float y = waypoint.y;
+ float z = waypoint.z;
float o = creature->GetOrientation();
if (!transportPath)
@@ -123,23 +148,45 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
transportPath = false;
// else if (vehicle) - this should never happen, vehicle offsets are const
}
-
- creature->GetMotionMaster()->Initialize();
return false;
}
- i_currentNode = (i_currentNode+1) % i_path->size();
+ i_currentNode = (i_currentNode + 1) % i_path->nodes.size();
}
- WaypointData const* node = i_path->at(i_currentNode);
+ float finalOrient = 0.0f;
+ uint8 finalMove = WAYPOINT_MOVE_TYPE_WALK;
+
+ Movement::PointsArray pathing;
+ pathing.reserve((i_path->nodes.size() - i_currentNode) + 1);
+
+ pathing.push_back(G3D::Vector3(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ()));
+ for (uint32 i = i_currentNode; i < i_path->nodes.size(); ++i)
+ {
+ WaypointNode const &waypoint = i_path->nodes.at(i);
- m_isArrivalDone = false;
+ pathing.push_back(G3D::Vector3(waypoint.x, waypoint.y, waypoint.z));
+
+ finalOrient = waypoint.orientation;
+ finalMove = waypoint.moveType;
+
+ if (waypoint.delay)
+ break;
+ }
+
+ // if we have only 1 point, only current position, we shall return
+ if (pathing.size() < 2)
+ return false;
+
+ IsArrivalDone = false;
+ i_recalculateSpeed = false;
creature->AddUnitState(UNIT_STATE_ROAMING_MOVE);
- Movement::Location formationDest(node->x, node->y, node->z, 0.0f);
Movement::MoveSplineInit init(creature);
+ Movement::Location formationDest(i_path->nodes.at(i_currentNode).x, i_path->nodes.at(i_currentNode).y, i_path->nodes.at(i_currentNode).z, 0.0f);
+
//! If creature is on transport, we assume waypoints set in DB are already transport offsets
if (transportPath)
{
@@ -148,15 +195,9 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
trans->CalculatePassengerPosition(formationDest.x, formationDest.y, formationDest.z, &formationDest.orientation);
}
- //! Do not use formationDest here, MoveTo requires transport offsets due to DisableTransportPathTransformations() call
- //! but formationDest contains global coordinates
- init.MoveTo(node->x, node->y, node->z);
-
- //! Accepts angles such as 0.00001 and -0.00001, 0 must be ignored, default value in waypoint table
- if (node->orientation && node->delay)
- init.SetFacing(node->orientation);
+ init.MovebyPath(pathing, i_currentNode);
- switch (node->move_type)
+ switch (finalMove)
{
case WAYPOINT_MOVE_TYPE_LAND:
init.SetAnimation(Movement::ToGround);
@@ -172,20 +213,23 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
break;
}
+ if (finalOrient != 0.0f)
+ init.SetFacing(finalOrient);
+
init.Launch();
//Call for creature group update
if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature)
- {
- creature->SetWalk(node->move_type != WAYPOINT_MOVE_TYPE_RUN);
creature->GetFormation()->LeaderMoveTo(formationDest.x, formationDest.y, formationDest.z);
- }
return true;
}
bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* creature, uint32 diff)
{
+ if (!creature || !creature->IsAlive())
+ return false;
+
// Waypoint movement can be switched on/off
// This is quite handy for escort quests and other stuff
if (creature->HasUnitState(UNIT_STATE_NOT_MOVE))
@@ -193,14 +237,15 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* creature, uint32 di
creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
return true;
}
+
// prevent a crash at empty waypoint path.
- if (!i_path || i_path->empty())
+ if (!i_path || i_path->nodes.empty())
return false;
if (Stopped())
{
if (CanMove(diff))
- return StartMove(creature);
+ return StartMoveNow(creature);
}
else
{
@@ -209,15 +254,45 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* creature, uint32 di
creature->SetHomePosition(creature->GetPosition());
if (creature->IsStopped())
- Stop(sWorld->getIntConfig(CONFIG_CREATURE_STOP_FOR_PLAYER));
+ Stop(LoadedFromDB ? sWorld->getIntConfig(CONFIG_CREATURE_STOP_FOR_PLAYER) : 2 * HOUR * IN_MILLISECONDS);
else if (creature->movespline->Finalized())
{
OnArrived(creature);
- return StartMove(creature);
+
+ IsArrivalDone = true;
+
+ if (!Stopped())
+ {
+ if (creature->IsStopped())
+ Stop(LoadedFromDB ? sWorld->getIntConfig(CONFIG_CREATURE_STOP_FOR_PLAYER) : 2 * HOUR * IN_MILLISECONDS);
+ else
+ return StartMove(creature);
+ }
+ }
+ else
+ {
+ // speed changed during path execution, calculate remaining path and launch it once more
+ if (i_recalculateSpeed)
+ {
+ i_recalculateSpeed = false;
+
+ if (!Stopped())
+ return StartMove(creature);
+ }
+ else
+ {
+ uint32 pointId = uint32(creature->movespline->currentPathIdx());
+ if (pointId > i_currentNode)
+ {
+ OnArrived(creature);
+ i_currentNode = pointId;
+ FormationMove(creature);
+ }
+ }
}
}
- return true;
- }
+ return true;
+}
void WaypointMovementGenerator<Creature>::MovementInform(Creature* creature)
{
@@ -228,11 +303,14 @@ void WaypointMovementGenerator<Creature>::MovementInform(Creature* creature)
bool WaypointMovementGenerator<Creature>::GetResetPos(Creature*, float& x, float& y, float& z)
{
// prevent a crash at empty waypoint path.
- if (!i_path || i_path->empty())
+ if (!i_path || i_path->nodes.empty())
return false;
- const WaypointData* node = i_path->at(i_currentNode);
- x = node->x; y = node->y; z = node->z;
+ WaypointNode const &waypoint = i_path->nodes.at(i_currentNode);
+
+ x = waypoint.x;
+ y = waypoint.y;
+ z = waypoint.z;
return true;
}
@@ -338,12 +416,12 @@ void FlightPathMovementGenerator::DoReset(Player* player)
Movement::MoveSplineInit init(player);
uint32 end = GetPathAtMapEnd();
- for (uint32 i = GetCurrentNode(); i != end; ++i)
+ for (uint32 i = i_currentNode; i != end; ++i)
{
G3D::Vector3 vertice(i_path[i]->Loc.X, i_path[i]->Loc.Y, i_path[i]->Loc.Z);
init.Path().push_back(vertice);
}
- init.SetFirstPointId(GetCurrentNode());
+ init.SetFirstPointId(i_currentNode);
init.SetFly();
init.SetSmooth();
init.SetUncompressed();
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h
index b63f9eb91c8..03c1585090a 100755
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h
@@ -30,7 +30,6 @@
#include "DB2Stores.h"
#include "Player.h"
#include "Timer.h"
-#include "WaypointManager.h"
#define FLIGHT_TRAVEL_UPDATE 100
#define TIMEDIFF_NEXT_WP 250
@@ -58,8 +57,16 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium< Crea
{
public:
WaypointMovementGenerator(uint32 _path_id = 0, bool _repeating = true)
- : i_nextMoveTime(0), m_isArrivalDone(false), path_id(_path_id), repeating(_repeating) { }
- ~WaypointMovementGenerator() { i_path = NULL; }
+ : i_nextMoveTime(0), IsArrivalDone(false), path_id(_path_id), repeating(_repeating), LoadedFromDB(true) { }
+
+ WaypointMovementGenerator(WaypointPath& path, bool _repeating = true)
+ : i_nextMoveTime(0), IsArrivalDone(false), path_id(0), repeating(_repeating), LoadedFromDB(false)
+ {
+ i_path = &path;
+ }
+
+ ~WaypointMovementGenerator() { i_path = nullptr; }
+
void DoInitialize(Creature*);
void DoFinalize(Creature*);
void DoReset(Creature*);
@@ -74,6 +81,10 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium< Crea
bool GetResetPos(Creature*, float& x, float& y, float& z);
+ TimeTrackerSmall & GetTrackerTimer() { return i_nextMoveTime; }
+
+ void UnitSpeedChanged() { i_recalculateSpeed = true; }
+
private:
void Stop(int32 time) { i_nextMoveTime.Reset(time);}
@@ -88,17 +99,21 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium< Crea
void OnArrived(Creature*);
bool StartMove(Creature*);
+ void FormationMove(Creature*);
- void StartMoveNow(Creature* creature)
+ bool StartMoveNow(Creature* creature)
{
i_nextMoveTime.Reset(0);
- StartMove(creature);
+ return StartMove(creature);
}
TimeTrackerSmall i_nextMoveTime;
- bool m_isArrivalDone;
+ bool i_recalculateSpeed;
+
+ bool IsArrivalDone;
uint32 path_id;
bool repeating;
+ bool LoadedFromDB;
};
/** FlightPathMovementGenerator generates movement of the player for the paths
diff --git a/src/server/game/Movement/Waypoints/WaypointDefines.h b/src/server/game/Movement/Waypoints/WaypointDefines.h
new file mode 100644
index 00000000000..063f7ffdd2b
--- /dev/null
+++ b/src/server/game/Movement/Waypoints/WaypointDefines.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
+ *
+ * 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 TRINITY_WAYPOINTDEFINES_H
+#define TRINITY_WAYPOINTDEFINES_H
+
+#include "Define.h"
+#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), orientation(0.f), delay(0), eventId(0), moveType(WAYPOINT_MOVE_TYPE_RUN), eventChance(0) { }
+ WaypointNode(uint32 _id, float _x, float _y, float _z, float _orientation = 0.f, uint32 _delay = 0)
+ {
+ id = _id;
+ x = _x;
+ y = _y;
+ z = _z;
+ orientation = _orientation;
+ delay = _delay;
+ eventId = 0;
+ moveType = WAYPOINT_MOVE_TYPE_WALK;
+ eventChance = 100;
+ }
+
+ uint32 id;
+ float x, y, z, orientation;
+ uint32 delay;
+ uint32 eventId;
+ uint32 moveType;
+ uint8 eventChance;
+};
+
+struct WaypointPath
+{
+ WaypointPath() : id(0) { }
+ WaypointPath(uint32 _id, std::vector<WaypointNode>&& _nodes)
+ {
+ id = _id;
+ nodes = _nodes;
+ }
+
+ std::vector<WaypointNode> nodes;
+ uint32 id;
+};
+
+#endif
diff --git a/src/server/game/Movement/Waypoints/WaypointManager.cpp b/src/server/game/Movement/Waypoints/WaypointManager.cpp
index c83684763f5..404ad2f9be6 100644
--- a/src/server/game/Movement/Waypoints/WaypointManager.cpp
+++ b/src/server/game/Movement/Waypoints/WaypointManager.cpp
@@ -24,19 +24,6 @@
WaypointMgr::WaypointMgr() { }
-WaypointMgr::~WaypointMgr()
-{
- for (WaypointPathContainer::iterator itr = _waypointStore.begin(); itr != _waypointStore.end(); ++itr)
- {
- for (WaypointPath::const_iterator it = itr->second.begin(); it != itr->second.end(); ++it)
- delete *it;
-
- itr->second.clear();
- }
-
- _waypointStore.clear();
-}
-
void WaypointMgr::Load()
{
uint32 oldMSTime = getMSTime();
@@ -55,7 +42,6 @@ void WaypointMgr::Load()
do
{
Field* fields = result->Fetch();
- WaypointData* wp = new WaypointData();
uint32 pathId = fields[0].GetUInt32();
WaypointPath& path = _waypointStore[pathId];
@@ -68,25 +54,25 @@ void WaypointMgr::Load()
Trinity::NormalizeMapCoord(x);
Trinity::NormalizeMapCoord(y);
- wp->id = fields[1].GetUInt32();
- wp->x = x;
- wp->y = y;
- wp->z = z;
- wp->orientation = o;
- wp->move_type = fields[6].GetUInt32();
+ WaypointNode wp;
+ wp.id = fields[1].GetUInt32();
+ wp.x = x;
+ wp.y = y;
+ wp.z = z;
+ wp.orientation = o;
+ wp.moveType = fields[6].GetUInt32();
- if (wp->move_type >= WAYPOINT_MOVE_TYPE_MAX)
+ if (wp.moveType >= WAYPOINT_MOVE_TYPE_MAX)
{
- TC_LOG_ERROR("sql.sql", "Waypoint %u in waypoint_data has invalid move_type, ignoring", wp->id);
- delete wp;
+ TC_LOG_ERROR("sql.sql", "Waypoint %u in waypoint_data has invalid move_type, ignoring", wp.id);
continue;
}
- wp->delay = fields[7].GetUInt32();
- wp->event_id = fields[8].GetUInt32();
- wp->event_chance = fields[9].GetInt16();
+ wp.delay = fields[7].GetUInt32();
+ wp.eventId = fields[8].GetUInt32();
+ wp.eventChance = fields[9].GetInt16();
- path.push_back(wp);
+ path.nodes.push_back(std::move(wp));
++count;
}
while (result->NextRow());
@@ -105,9 +91,6 @@ void WaypointMgr::ReloadPath(uint32 id)
WaypointPathContainer::iterator itr = _waypointStore.find(id);
if (itr != _waypointStore.end())
{
- for (WaypointPath::const_iterator it = itr->second.begin(); it != itr->second.end(); ++it)
- delete *it;
-
_waypointStore.erase(itr);
}
@@ -125,7 +108,6 @@ void WaypointMgr::ReloadPath(uint32 id)
do
{
Field* fields = result->Fetch();
- WaypointData* wp = new WaypointData();
float x = fields[1].GetFloat();
float y = fields[2].GetFloat();
@@ -135,25 +117,25 @@ void WaypointMgr::ReloadPath(uint32 id)
Trinity::NormalizeMapCoord(x);
Trinity::NormalizeMapCoord(y);
- wp->id = fields[0].GetUInt32();
- wp->x = x;
- wp->y = y;
- wp->z = z;
- wp->orientation = o;
- wp->move_type = fields[5].GetUInt32();
+ WaypointNode wp;
+ wp.id = fields[0].GetUInt32();
+ wp.x = x;
+ wp.y = y;
+ wp.z = z;
+ wp.orientation = o;
+ wp.moveType = fields[5].GetUInt32();
- if (wp->move_type >= WAYPOINT_MOVE_TYPE_MAX)
+ if (wp.moveType >= WAYPOINT_MOVE_TYPE_MAX)
{
- TC_LOG_ERROR("sql.sql", "Waypoint %u in waypoint_data has invalid move_type, ignoring", wp->id);
- delete wp;
+ TC_LOG_ERROR("sql.sql", "Waypoint %u in waypoint_data has invalid move_type, ignoring", wp.id);
continue;
}
- wp->delay = fields[6].GetUInt32();
- wp->event_id = fields[7].GetUInt32();
- wp->event_chance = fields[8].GetUInt8();
+ wp.delay = fields[6].GetUInt32();
+ wp.eventId = fields[7].GetUInt32();
+ wp.eventChance = fields[8].GetUInt8();
- path.push_back(wp);
+ path.nodes.push_back(std::move(wp));
}
while (result->NextRow());
diff --git a/src/server/game/Movement/Waypoints/WaypointManager.h b/src/server/game/Movement/Waypoints/WaypointManager.h
index d7b9ff2016a..76fe4d67384 100644
--- a/src/server/game/Movement/Waypoints/WaypointManager.h
+++ b/src/server/game/Movement/Waypoints/WaypointManager.h
@@ -20,30 +20,9 @@
#define TRINITY_WAYPOINTMANAGER_H
#include "Define.h"
-#include <vector>
+#include "WaypointDefines.h"
#include <unordered_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, orientation;
- uint32 delay;
- uint32 event_id;
- uint32 move_type;
- uint8 event_chance;
-};
-
-typedef std::vector<WaypointData*> WaypointPath;
typedef std::unordered_map<uint32, WaypointPath> WaypointPathContainer;
class TC_GAME_API WaypointMgr
@@ -64,14 +43,14 @@ class TC_GAME_API WaypointMgr
if (itr != _waypointStore.end())
return &itr->second;
- return NULL;
+ return nullptr;
}
private:
WaypointMgr();
- ~WaypointMgr();
+ ~WaypointMgr() { }
- WaypointPathContainer _waypointStore;
+ std::unordered_map<uint32, WaypointPath> _waypointStore;
};
#define sWaypointMgr WaypointMgr::instance()
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 5d714db551f..90b6da26a3b 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -86,6 +86,7 @@
#include "VMapFactory.h"
#include "VMapManager2.h"
#include "WardenCheckMgr.h"
+#include "WaypointManager.h"
#include "WaypointMovementGenerator.h"
#include "WeatherMgr.h"
#include "WorldSession.h"
diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/instance_forge_of_souls.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/instance_forge_of_souls.cpp
index 09f7f8e7c07..9dc5d5bed5b 100644
--- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/instance_forge_of_souls.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/instance_forge_of_souls.cpp
@@ -15,6 +15,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "AreaBoundary.h"
#include "ScriptMgr.h"
#include "Creature.h"
#include "forge_of_souls.h"
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp
index a0a390f9aa5..6aeaafbd4ec 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp
@@ -27,6 +27,7 @@
#include "PassiveAI.h"
#include "Player.h"
#include "ScriptedCreature.h"
+#include "ScriptedEscortAI.h"
#include "Spell.h"
#include "SpellInfo.h"
#include "SpellScript.h"
@@ -876,11 +877,15 @@ class npc_brann_bronzebeard_algalon : public CreatureScript
public:
npc_brann_bronzebeard_algalon() : CreatureScript("npc_brann_bronzebeard_algalon") { }
- struct npc_brann_bronzebeard_algalonAI : public CreatureAI
+ struct npc_brann_bronzebeard_algalonAI : public npc_escortAI
{
- npc_brann_bronzebeard_algalonAI(Creature* creature) : CreatureAI(creature)
+ npc_brann_bronzebeard_algalonAI(Creature* creature) : npc_escortAI(creature)
{
- _currentPoint = 0;
+ SetDespawnAtEnd(false);
+ SetDespawnAtFar(false);
+
+ for (uint8 i = 0; i < MAX_BRANN_WAYPOINTS_INTRO; ++i)
+ AddWaypoint(i, BrannIntroWaypoint[i].GetPositionX(), BrannIntroWaypoint[i].GetPositionY(), BrannIntroWaypoint[i].GetPositionZ());
}
void DoAction(int32 action) override
@@ -888,14 +893,12 @@ class npc_brann_bronzebeard_algalon : public CreatureScript
switch (action)
{
case ACTION_START_INTRO:
- _currentPoint = 0;
_events.Reset();
- me->SetWalk(false);
- _events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 1);
+ Start(false, true);
break;
case ACTION_FINISH_INTRO:
Talk(SAY_BRANN_ALGALON_INTRO_2);
- _events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 1);
+ SetEscortPaused(false);
break;
case ACTION_OUTRO:
me->GetMotionMaster()->MovePoint(POINT_BRANN_OUTRO, BrannOutroPos[1]);
@@ -905,38 +908,27 @@ class npc_brann_bronzebeard_algalon : public CreatureScript
}
}
- void MovementInform(uint32 movementType, uint32 pointId) override
+ void WaypointReached(uint32 pointId) override
{
- if (movementType != POINT_MOTION_TYPE)
- return;
-
- uint32 delay = 1;
- _currentPoint = pointId + 1;
switch (pointId)
{
case 2:
- delay = 8000;
- me->SetWalk(true);
+ SetEscortPaused(true);
+ _events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 8000);
+ SetRun(false);
break;
case 5:
- me->SetWalk(false);
+ SetRun(true);
+ SetEscortPaused(true);
Talk(SAY_BRANN_ALGALON_INTRO_1);
_events.ScheduleEvent(EVENT_SUMMON_ALGALON, 7500);
- return;
- case 9:
- me->DespawnOrUnsummon(1);
- return;
- case POINT_BRANN_OUTRO:
- case POINT_BRANN_OUTRO_END:
- return;
+ break;
}
-
- _events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, delay);
}
void UpdateAI(uint32 diff) override
{
- UpdateVictim();
+ npc_escortAI::UpdateAI(diff);
if (_events.Empty())
return;
@@ -948,8 +940,7 @@ class npc_brann_bronzebeard_algalon : public CreatureScript
switch (eventId)
{
case EVENT_BRANN_MOVE_INTRO:
- if (_currentPoint < MAX_BRANN_WAYPOINTS_INTRO)
- me->GetMotionMaster()->MovePoint(_currentPoint, BrannIntroWaypoint[_currentPoint]);
+ SetEscortPaused(false);
break;
case EVENT_SUMMON_ALGALON:
if (Creature* algalon = me->GetMap()->SummonCreature(NPC_ALGALON, AlgalonSummonPos))
@@ -967,7 +958,6 @@ class npc_brann_bronzebeard_algalon : public CreatureScript
private:
EventMap _events;
- uint32 _currentPoint;
};
CreatureAI* GetAI(Creature* creature) const override