aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/AI/ScriptedAI
diff options
context:
space:
mode:
authorccrs <ccrs@users.noreply.github.com>2017-08-12 01:40:25 +0200
committerShauren <shauren.trinity@gmail.com>2020-08-23 00:45:46 +0200
commit97585597f0b1aff93873fe4d757556731bc0c1b2 (patch)
treefda9b11c6e7abb9e4d3a6108a09def640c3eb2af /src/server/game/AI/ScriptedAI
parenta86870622dd02921c4d2e32983a5a98ee91e5263 (diff)
Core/Movement: waypoint movement (#20121)
Following the work done in #19361 this is the cleanup and improvement of the related logic of waypoint management. Ref 28050f3 #18020 (taking the good parts and ignoring the incomplete work) (cherry picked from commit 7fff83d67526efff63867d41b9e036a19a9287b3)
Diffstat (limited to 'src/server/game/AI/ScriptedAI')
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp521
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedEscortAI.h132
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h2
3 files changed, 238 insertions, 417 deletions
diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
index 6acb4cd446a..b9da6840474 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
@@ -15,21 +15,16 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* ScriptData
-SDName: Npc_EscortAI
-SD%Complete: 100
-SDComment:
-SDCategory: Npc
-EndScriptData */
-
#include "ScriptedEscortAI.h"
#include "Creature.h"
#include "Group.h"
#include "Log.h"
#include "Map.h"
#include "MotionMaster.h"
+#include "MovementGenerator.h"
#include "ObjectAccessor.h"
#include "Player.h"
+#include "ScriptSystem.h"
#include "World.h"
enum Points
@@ -38,101 +33,62 @@ enum Points
POINT_HOME = 0xFFFFFE
};
-npc_escortAI::npc_escortAI(Creature* creature) : ScriptedAI(creature),
- m_uiWPWaitTimer(2500),
- m_uiPlayerCheckTimer(1000),
- m_uiEscortState(STATE_ESCORT_NONE),
- MaxPlayerDistance(DEFAULT_MAX_PLAYER_DISTANCE),
- m_pQuestForEscort(nullptr),
- m_bIsActiveAttacker(true),
- m_bIsRunning(false),
- m_bCanInstantRespawn(false),
- m_bCanReturnToStart(false),
- DespawnAtEnd(true),
- DespawnAtFar(true),
- ScriptWP(false),
- HasImmuneToNPCFlags(false)
-{ }
-
-void npc_escortAI::AttackStart(Unit* who)
+EscortAI::EscortAI(Creature* creature) : ScriptedAI(creature), _pauseTimer(2500), _playerCheckTimer(1000), _escortState(STATE_ESCORT_NONE), _maxPlayerDistance(DEFAULT_MAX_PLAYER_DISTANCE),
+ _escortQuest(nullptr), _activeAttacker(true), _running(false), _instantRespawn(false), _returnToStart(false), _despawnAtEnd(true), _despawnAtFar(true), _manualPath(false),
+ _hasImmuneToNPCFlags(false), _started(false), _ended(false), _resume(false)
{
- 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()
+Player* EscortAI::GetPlayerForEscort()
{
- return ObjectAccessor::GetPlayer(*me, m_uiPlayerGUID);
+ return ObjectAccessor::GetPlayer(*me, _playerGUID);
}
-//see followerAI
-bool npc_escortAI::AssistPlayerInCombatAgainst(Unit* who)
+// see followerAI
+bool EscortAI::AssistPlayerInCombatAgainst(Unit* who)
{
if (!who || !who->GetVictim())
return false;
- //experimental (unknown) flag not present
+ if (me->HasReactState(REACT_PASSIVE))
+ return false;
+
+ // experimental (unknown) flag not present
if (!(me->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_CAN_ASSIST))
return false;
- //not a player
+ // not a player
if (!who->EnsureVictim()->GetCharmerOrOwnerPlayerOrPlayerItself())
return false;
- //never attack friendly
- if (me->IsFriendlyTo(who))
+ // never attack friendly
+ if (!me->IsValidAssistTarget(who->GetVictim()))
return false;
- //too far away and no free sight?
+ // too far away and no free sight?
if (me->IsWithinDistInMap(who, GetMaxPlayerDistance()) && me->IsWithinLOSInMap(who))
{
- //already fighting someone?
- if (!me->GetVictim())
- {
- AttackStart(who);
- return true;
- }
- else
- {
- me->EngageWithTarget(who);
- return true;
- }
+ me->EngageWithTarget(who);
+ return true;
}
return false;
}
-void npc_escortAI::MoveInLineOfSight(Unit* who)
+void EscortAI::MoveInLineOfSight(Unit* who)
{
- if (me->HasReactState(REACT_AGGRESSIVE) && !me->HasUnitState(UNIT_STATE_STUNNED) && who->isTargetableForAttack() && who->isInAccessiblePlaceFor(me))
- {
- if (HasEscortState(STATE_ESCORT_ESCORTING) && AssistPlayerInCombatAgainst(who))
- return;
+ if (!who)
+ return;
- if (!me->CanFly() && me->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
- return;
+ if (HasEscortState(STATE_ESCORT_ESCORTING) && AssistPlayerInCombatAgainst(who))
+ return;
- if (me->IsHostileTo(who))
- {
- float fAttackRadius = me->GetAttackDistance(who);
- if (me->IsWithinDistInMap(who, fAttackRadius) && me->IsWithinLOSInMap(who))
- me->EngageWithTarget(who);
- }
- }
+ ScriptedAI::MoveInLineOfSight(who);
}
-void npc_escortAI::JustDied(Unit* /*killer*/)
+void EscortAI::JustDied(Unit* /*killer*/)
{
- if (!HasEscortState(STATE_ESCORT_ESCORTING) || !m_uiPlayerGUID || !m_pQuestForEscort)
+ if (!HasEscortState(STATE_ESCORT_ESCORTING) || !_playerGUID || !_escortQuest)
return;
if (Player* player = GetPlayerForEscort())
@@ -140,24 +96,26 @@ void npc_escortAI::JustDied(Unit* /*killer*/)
if (Group* group = player->GetGroup())
{
for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next())
+ {
if (Player* member = groupRef->GetSource())
if (member->IsInMap(player))
- member->FailQuest(m_pQuestForEscort->GetQuestId());
+ member->FailQuest(_escortQuest->GetQuestId());
+ }
}
else
- player->FailQuest(m_pQuestForEscort->GetQuestId());
+ player->FailQuest(_escortQuest->GetQuestId());
}
}
-void npc_escortAI::JustAppeared()
+void EscortAI::JustAppeared()
{
- m_uiEscortState = STATE_ESCORT_NONE;
+ _escortState = STATE_ESCORT_NONE;
if (!IsCombatMovementAllowed())
SetCombatMovement(true);
- //add a small delay before going to first waypoint, normal in near all cases
- m_uiWPWaitTimer = 2500;
+ // add a small delay before going to first waypoint, normal in near all cases
+ _pauseTimer = 2000;
if (me->GetFaction() != me->GetCreatureTemplate()->faction)
me->RestoreFaction();
@@ -165,14 +123,12 @@ void npc_escortAI::JustAppeared()
Reset();
}
-void npc_escortAI::ReturnToLastPoint()
+void EscortAI::ReturnToLastPoint()
{
- float x, y, z, o;
- me->GetHomePosition(x, y, z, o);
- me->GetMotionMaster()->MovePoint(POINT_LAST_POINT, x, y, z);
+ me->GetMotionMaster()->MovePoint(POINT_LAST_POINT, me->GetHomePosition());
}
-void npc_escortAI::EnterEvadeMode(EvadeReason /*why*/)
+void EscortAI::EnterEvadeMode(EvadeReason /*why*/)
{
me->RemoveAllAuras();
me->GetThreatManager().ClearAllThreat();
@@ -183,27 +139,29 @@ void npc_escortAI::EnterEvadeMode(EvadeReason /*why*/)
{
AddEscortState(STATE_ESCORT_RETURNING);
ReturnToLastPoint();
- TC_LOG_DEBUG("scripts", "EscortAI has left combat and is now returning to last point");
+ TC_LOG_DEBUG("scripts", "EscortAI::EnterEvadeMode: left combat and is now returning to last point");
}
else
{
me->GetMotionMaster()->MoveTargetedHome();
- if (HasImmuneToNPCFlags)
+ if (_hasImmuneToNPCFlags)
me->SetImmuneToNPC(true);
Reset();
}
}
-bool npc_escortAI::IsPlayerOrGroupInRange()
+bool EscortAI::IsPlayerOrGroupInRange()
{
if (Player* player = GetPlayerForEscort())
{
if (Group* group = player->GetGroup())
{
for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next())
+ {
if (Player* member = groupRef->GetSource())
if (me->IsWithinDistInMap(member, GetMaxPlayerDistance()))
return true;
+ }
}
else if (me->IsWithinDistInMap(player, GetMaxPlayerDistance()))
return true;
@@ -212,88 +170,77 @@ bool npc_escortAI::IsPlayerOrGroupInRange()
return false;
}
-void npc_escortAI::UpdateAI(uint32 diff)
+void EscortAI::UpdateAI(uint32 diff)
{
- //Waypoint Updating
- if (HasEscortState(STATE_ESCORT_ESCORTING) && !me->GetVictim() && m_uiWPWaitTimer && !HasEscortState(STATE_ESCORT_RETURNING))
+ // Waypoint Updating
+ if (HasEscortState(STATE_ESCORT_ESCORTING) && !me->IsEngaged() && !HasEscortState(STATE_ESCORT_RETURNING))
{
- if (m_uiWPWaitTimer <= diff)
+ if (_pauseTimer <= 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);
+ _pauseTimer = 0;
- m_uiWPWaitTimer = 0;
-
- TC_LOG_DEBUG("scripts", "EscortAI are returning home to spawn location: %u, %f, %f, %f", POINT_HOME, fRetX, fRetY, fRetZ);
- return;
- }
+ if (_ended)
+ {
+ _ended = false;
+ me->GetMotionMaster()->MoveIdle();
- if (m_bCanInstantRespawn && !sWorld->getBoolConfig(CONFIG_RESPAWN_DYNAMIC_ESCORTNPC))
- {
- me->setDeathState(JUST_DIED);
- me->Respawn();
- }
- else
+ if (_despawnAtEnd)
{
- if (sWorld->getBoolConfig(CONFIG_RESPAWN_DYNAMIC_ESCORTNPC))
- me->GetMap()->RemoveRespawnTime(SPAWN_TYPE_CREATURE, me->GetSpawnId(), true);
- me->DespawnOrUnsummon();
+ TC_LOG_DEBUG("scripts", "EscortAI::UpdateAI: reached end of waypoints, despawning at end");
+ if (_returnToStart)
+ {
+ Position respawnPosition;
+ float orientation = 0.f;
+ me->GetRespawnPosition(respawnPosition.m_positionX, respawnPosition.m_positionY, respawnPosition.m_positionZ, &orientation);
+ respawnPosition.SetOrientation(orientation);
+ me->GetMotionMaster()->MovePoint(POINT_HOME, respawnPosition);
+ TC_LOG_DEBUG("scripts", "EscortAI::UpdateAI: returning to spawn location: %s", respawnPosition.ToString().c_str());
+ }
+ else if (_instantRespawn)
+ me->Respawn(true);
+ else
+ me->DespawnOrUnsummon();
}
-
+ TC_LOG_DEBUG("scripts", "EscortAI::UpdateAI: reached end of waypoints");
+ RemoveEscortState(STATE_ESCORT_ESCORTING);
return;
}
- else
- {
- TC_LOG_DEBUG("scripts", "EscortAI reached end of waypoints with Despawn off");
- return;
+ if (!_started)
+ {
+ _started = true;
+ me->GetMotionMaster()->MovePath(_path, false);
+ }
+ else if (_resume)
+ {
+ _resume = false;
+ if (MovementGenerator* movementGenerator = me->GetMotionMaster()->GetMotionSlot(MOTION_SLOT_IDLE))
+ movementGenerator->Resume(0);
}
- }
-
- 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
- m_uiWPWaitTimer -= diff;
+ _pauseTimer -= 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))
+ // Check if player or any member of his group is within range
+ if (_despawnAtFar && HasEscortState(STATE_ESCORT_ESCORTING) && !_playerGUID.IsEmpty() && !me->GetVictim() && !HasEscortState(STATE_ESCORT_RETURNING))
{
- if (m_uiPlayerCheckTimer <= diff)
+ if (_playerCheckTimer <= diff)
{
- if (DespawnAtFar && !IsPlayerOrGroupInRange())
+ if (!IsPlayerOrGroupInRange())
{
- TC_LOG_DEBUG("scripts", "EscortAI failed because player/group was to far away or not found");
+ TC_LOG_DEBUG("scripts", "EscortAI::UpdateAI: failed because player/group was to far away or not found");
bool isEscort = false;
- if (CreatureData const* cdata = me->GetCreatureData())
- isEscort = (sWorld->getBoolConfig(CONFIG_RESPAWN_DYNAMIC_ESCORTNPC) && (cdata->spawnGroupData->flags & SPAWNGROUP_FLAG_ESCORTQUESTNPC));
+ if (CreatureData const* creatureData = me->GetCreatureData())
+ isEscort = (sWorld->getBoolConfig(CONFIG_RESPAWN_DYNAMIC_ESCORTNPC) && (creatureData->spawnGroupData->flags & SPAWNGROUP_FLAG_ESCORTQUESTNPC));
- if (m_bCanInstantRespawn && !isEscort)
- {
- me->setDeathState(JUST_DIED);
- me->Respawn();
- }
- else if (m_bCanInstantRespawn && isEscort)
+ if (_instantRespawn && !isEscort)
+ me->DespawnOrUnsummon(0, Seconds(1));
+ else if (_instantRespawn && isEscort)
me->GetMap()->RemoveRespawnTime(SPAWN_TYPE_CREATURE, me->GetSpawnId(), true);
else
me->DespawnOrUnsummon();
@@ -301,16 +248,16 @@ void npc_escortAI::UpdateAI(uint32 diff)
return;
}
- m_uiPlayerCheckTimer = 1000;
+ _playerCheckTimer = 1000;
}
else
- m_uiPlayerCheckTimer -= diff;
+ _playerCheckTimer -= diff;
}
UpdateEscortAI(diff);
}
-void npc_escortAI::UpdateEscortAI(uint32 /*diff*/)
+void EscortAI::UpdateEscortAI(uint32 /*diff*/)
{
if (!UpdateVictim())
return;
@@ -318,121 +265,103 @@ void npc_escortAI::UpdateEscortAI(uint32 /*diff*/)
DoMeleeAttackIfReady();
}
-void npc_escortAI::MovementInform(uint32 moveType, uint32 pointId)
+void EscortAI::MovementInform(uint32 type, uint32 id)
{
- 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 (type == POINT_MOTION_TYPE)
{
- TC_LOG_DEBUG("scripts", "EscortAI has returned to original position before combat");
+ if (!_pauseTimer)
+ _pauseTimer = 2000;
- me->SetWalk(!m_bIsRunning);
- RemoveEscortState(STATE_ESCORT_RETURNING);
-
- if (!m_uiWPWaitTimer)
- m_uiWPWaitTimer = 1;
+ // continue waypoint movement
+ if (id == POINT_LAST_POINT)
+ {
+ TC_LOG_DEBUG("scripts", "EscortAI::MovementInform: returned to before combat position");
+ me->SetWalk(!_running);
+ RemoveEscortState(STATE_ESCORT_RETURNING);
+ }
+ else if (id == POINT_HOME)
+ {
+ TC_LOG_DEBUG("scripts", "EscortAI::MovementInform: returned to home location and restarting waypoint path");
+ _started = false;
+ }
}
- else if (pointId == POINT_HOME)
+ else if (type == WAYPOINT_MOTION_TYPE)
{
- TC_LOG_DEBUG("scripts", "EscortAI has returned to original home location and will continue from beginning of waypoint list.");
+ ASSERT(id < _path.nodes.size(), "EscortAI::MovementInform: referenced movement id (%u) points to non-existing node in loaded path", id);
+ WaypointNode waypoint = _path.nodes[id];
- CurrentWP = WaypointList.begin();
- m_uiWPWaitTimer = 1;
- }
- else
- {
- //Make sure that we are still on the right waypoint
- if (CurrentWP->id != pointId)
+ TC_LOG_DEBUG("scripts", "EscortAI::MovementInform: waypoint node %u reached", waypoint.id);
+
+ // last point
+ if (id == _path.nodes.size() - 1)
{
- TC_LOG_ERROR("misc", "TSCR ERROR: EscortAI reached waypoint out of order %u, expected %u, creature entry %u", pointId, CurrentWP->id, me->GetEntry());
- return;
+ _started = false;
+ _ended = true;
+ _pauseTimer = 1000;
}
-
- TC_LOG_DEBUG("scripts", "EscortAI Waypoint %u reached", CurrentWP->id);
-
- //Call WP function
- WaypointReached(CurrentWP->id);
-
- m_uiWPWaitTimer = CurrentWP->WaitTimeMs + 1;
-
- ++CurrentWP;
}
}
+///@todo investigate whether if its necessary to handle anything on charm
/*
-void npc_escortAI::OnPossess(bool apply)
+void EscortAI::OnCharmed(bool apply)
{
- // We got possessed in the middle of being escorted, store the point
- // where we left off to come back to when possess is removed
- if (HasEscortState(STATE_ESCORT_ESCORTING))
- {
- if (apply)
- me->GetPosition(LastPos.x, LastPos.y, LastPos.z);
- else
- {
- Returning = true;
- me->GetMotionMaster()->MovementExpired();
- me->GetMotionMaster()->MovePoint(WP_LAST_POINT, LastPos.x, LastPos.y, LastPos.z);
- }
- }
}
*/
-void npc_escortAI::AddWaypoint(uint32 id, float x, float y, float z, uint32 waitTime)
+void EscortAI::AddWaypoint(uint32 id, float x, float y, float z, float orientation/* = 0*/, uint32 waitTime/* = 0*/)
{
- Escort_Waypoint t(id, x, y, z, waitTime);
-
- WaypointList.push_back(t);
-
- // i think SD2 no longer uses this function
- ScriptWP = true;
- /*PointMovement wp;
- wp.m_uiCreatureEntry = me->GetEntry();
- wp.m_uiPointId = id;
- wp.m_fX = x;
- wp.m_fY = y;
- wp.m_fZ = z;
- wp.m_uiWaitTime = WaitTimeMs;
- PointMovementMap[wp.m_uiCreatureEntry].push_back(wp);*/
+ Trinity::NormalizeMapCoord(x);
+ Trinity::NormalizeMapCoord(y);
+
+ WaypointNode waypoint;
+ waypoint.id = id;
+ waypoint.x = x;
+ waypoint.y = y;
+ waypoint.z = z;
+ waypoint.orientation = orientation;
+ waypoint.moveType = _running ? WAYPOINT_MOVE_TYPE_RUN : WAYPOINT_MOVE_TYPE_WALK;
+ waypoint.delay = waitTime;
+ waypoint.eventId = 0;
+ waypoint.eventChance = 100;
+ _path.nodes.push_back(std::move(waypoint));
+
+ _manualPath = true;
}
-void npc_escortAI::FillPointMovementListForCreature()
+void EscortAI::FillPointMovementListForCreature()
{
- ScriptPointVector const* movePoints = sScriptSystemMgr->GetPointMoveList(me->GetEntry());
- if (!movePoints)
+ WaypointPath const* path = sScriptSystemMgr->GetPath(me->GetEntry());
+ if (!path)
return;
- for (ScriptPointVector::const_iterator itr = movePoints->begin(); itr != movePoints->end(); ++itr)
+ for (WaypointNode const& value : path->nodes)
{
- Escort_Waypoint point(itr->uiPointId, itr->fX, itr->fY, itr->fZ, itr->uiWaitTime);
- WaypointList.push_back(point);
+ WaypointNode node = value;
+ Trinity::NormalizeMapCoord(node.x);
+ Trinity::NormalizeMapCoord(node.y);
+ node.moveType = _running ? WAYPOINT_MOVE_TYPE_RUN : WAYPOINT_MOVE_TYPE_WALK;
+
+ _path.nodes.push_back(std::move(node));
}
}
-void npc_escortAI::SetRun(bool on)
+void EscortAI::SetRun(bool on)
{
- if (on)
- {
- if (!m_bIsRunning)
- me->SetWalk(false);
- else
- TC_LOG_DEBUG("scripts", "EscortAI attempt to set run mode, but is already running.");
- }
- else
- {
- if (m_bIsRunning)
- me->SetWalk(true);
- else
- TC_LOG_DEBUG("scripts", "EscortAI attempt to set walk mode, but is already walking.");
- }
+ if (on && !_running)
+ me->SetWalk(false);
+ else if (!on && _running)
+ me->SetWalk(true);
- m_bIsRunning = on;
+ _running = on;
}
/// @todo get rid of this many variables passed in function.
-void npc_escortAI::Start(bool isActiveAttacker /* = true*/, bool run /* = false */, ObjectGuid playerGUID /* = 0 */, Quest const* quest /* = nullptr */, bool instantRespawn /* = false */, bool canLoopPath /* = false */, bool resetWaypoints /* = true */)
+void EscortAI::Start(bool isActiveAttacker /* = true*/, bool run /* = false */, ObjectGuid playerGUID /* = 0 */, Quest const* quest /* = nullptr */, bool instantRespawn /* = false */, bool canLoopPath /* = false */, bool resetWaypoints /* = true */)
{
// Queue respawn from the point it starts
if (Map* map = me->GetMap())
@@ -452,150 +381,76 @@ void npc_escortAI::Start(bool isActiveAttacker /* = true*/, bool run /* = false
if (me->GetVictim())
{
- TC_LOG_ERROR("scripts.escortai", "TSCR ERROR: EscortAI (script: %s, creature entry: %u) attempts to Start while in combat", me->GetScriptName().c_str(), me->GetEntry());
+ TC_LOG_ERROR("scripts", "EscortAI::Start: (script: %s, creature entry: %u) attempts to Start while in combat", me->GetScriptName().c_str(), me->GetEntry());
return;
}
if (HasEscortState(STATE_ESCORT_ESCORTING))
{
- TC_LOG_ERROR("scripts.escortai", "EscortAI (script: %s, creature entry: %u) attempts to Start while already escorting", me->GetScriptName().c_str(), me->GetEntry());
+ TC_LOG_ERROR("scripts", "EscortAI::Start: (script: %s, creature entry: %u) attempts to Start while already escorting", me->GetScriptName().c_str(), me->GetEntry());
return;
}
- if (!ScriptWP && resetWaypoints) // sd2 never adds wp in script, but tc does
- {
- if (!WaypointList.empty())
- WaypointList.clear();
+ if (!_manualPath && resetWaypoints)
FillPointMovementListForCreature();
- }
- if (WaypointList.empty())
+ if (_path.nodes.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);
+ TC_LOG_ERROR("scripts", "EscortAI::Start: (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;
-
- m_uiPlayerGUID = playerGUID;
- m_pQuestForEscort = quest;
+ // set variables
+ _activeAttacker = isActiveAttacker;
+ _running = run;
+ _playerGUID = playerGUID;
+ _escortQuest = quest;
+ _instantRespawn = instantRespawn;
+ _returnToStart = canLoopPath;
- m_bCanInstantRespawn = instantRespawn;
- m_bCanReturnToStart = canLoopPath;
+ if (_returnToStart && _instantRespawn)
+ TC_LOG_DEBUG("scripts", "EscortAI::Start: (script: %s, creature entry: %u) is set to return home after waypoint end and instant respawn at waypoint end. Creature will never despawn.", me->GetScriptName().c_str(), me->GetEntry());
- 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.");
+ me->GetMotionMaster()->MoveIdle();
+ me->GetMotionMaster()->Clear(MOTION_SLOT_ACTIVE);
- if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE)
- {
- me->GetMotionMaster()->MovementExpired();
- me->GetMotionMaster()->MoveIdle();
- TC_LOG_DEBUG("scripts", "EscortAI start with WAYPOINT_MOTION_TYPE, changed to MoveIdle.");
- }
-
- //disable npcflags
+ // disable npcflags
me->SetNpcFlags(UNIT_NPC_FLAG_NONE);
me->SetNpcFlags2(UNIT_NPC_FLAG_2_NONE);
if (me->IsImmuneToNPC())
{
- HasImmuneToNPCFlags = true;
+ _hasImmuneToNPCFlags = true;
me->SetImmuneToNPC(false);
}
- 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::Start: (script: %s, creature entry: %u) started with %u waypoints. ActiveAttacker = %d, Run = %d, Player = %s", me->GetScriptName().c_str(), me->GetEntry(), uint32(_path.nodes.size()), _activeAttacker, _running, _playerGUID.ToString().c_str());
- //Set initial speed
- if (m_bIsRunning)
- me->SetWalk(false);
- else
- me->SetWalk(true);
+ // set initial speed
+ me->SetWalk(!_running);
+ _started = false;
AddEscortState(STATE_ESCORT_ESCORTING);
}
-void npc_escortAI::SetEscortPaused(bool on)
+void EscortAI::SetEscortPaused(bool on)
{
if (!HasEscortState(STATE_ESCORT_ESCORTING))
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);
+ if (MovementGenerator* movementGenerator = me->GetMotionMaster()->GetMotionSlot(MOTION_SLOT_IDLE))
+ movementGenerator->Pause(0);
}
-
- 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);
+ _resume = true;
}
-
- return false;
}
-bool npc_escortAI::IsEscortNPC(bool onlyIfActive) const
+bool EscortAI::IsEscortNPC(bool onlyIfActive) const
{
if (!onlyIfActive)
return true;
diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h
index b91bdd21005..4020d90815e 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h
+++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h
@@ -19,93 +19,59 @@
#define SC_ESCORTAI_H
#include "ScriptedCreature.h"
-#include "ScriptSystem.h"
+#include "WaypointDefines.h"
class Quest;
#define DEFAULT_MAX_PLAYER_DISTANCE 50
-struct Escort_Waypoint
+enum EscortState : uint32
{
- 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;
+ STATE_ESCORT_NONE = 0x00, // nothing in progress
+ STATE_ESCORT_ESCORTING = 0x01, // escort is in progress
+ STATE_ESCORT_RETURNING = 0x02, // escort is returning after being in combat
+ STATE_ESCORT_PAUSED = 0x04 // escort is paused, wont continue with next waypoint
};
-enum eEscortState
-{
- STATE_ESCORT_NONE = 0x000, //nothing in progress
- STATE_ESCORT_ESCORTING = 0x001, //escort are in progress
- STATE_ESCORT_RETURNING = 0x002, //escort is returning after being in combat
- STATE_ESCORT_PAUSED = 0x004 //will not proceed with waypoints before state is removed
-};
-
-struct TC_GAME_API npc_escortAI : public ScriptedAI
+struct TC_GAME_API EscortAI : public ScriptedAI
{
public:
- explicit npc_escortAI(Creature* creature);
- ~npc_escortAI() { }
-
- // CreatureAI functions
- void AttackStart(Unit* who) override;
+ explicit EscortAI(Creature* creature);
+ ~EscortAI() { }
+ void UpdateAI(uint32 diff) override; // the "internal" update, calls UpdateEscortAI()
void MoveInLineOfSight(Unit* who) override;
-
void JustDied(Unit*) override;
-
void JustAppeared() override;
-
void ReturnToLastPoint();
-
void EnterEvadeMode(EvadeReason /*why*/ = EVADE_REASON_OTHER) override;
-
- void UpdateAI(uint32 diff) override; // the "internal" update, calls UpdateEscortAI()
- virtual void UpdateEscortAI(uint32 diff); // used when it's needed to add code in update (abilities, scripted events, etc)
-
void MovementInform(uint32, uint32) override;
- // 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);
+ virtual void UpdateEscortAI(uint32 diff); // used when it's needed to add code in update (abilities, scripted events, etc)
- //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*/) { }
+ void AddWaypoint(uint32 id, float x, float y, float z, float orientation = 0.f, uint32 waitTime = 0); // waitTime is in ms
void Start(bool isActiveAttacker = true, bool run = false, ObjectGuid playerGUID = ObjectGuid::Empty, Quest const* quest = nullptr, bool instantRespawn = false, bool canLoopPath = false, bool resetWaypoints = true);
void SetRun(bool on = true);
+
void SetEscortPaused(bool on);
+ void SetPauseTimer(uint32 Timer) { _pauseTimer = Timer; }
+
+ bool HasEscortState(uint32 escortState) { return (_escortState & escortState) != 0; }
+ virtual bool IsEscorted() const override { return (_escortState & STATE_ESCORT_ESCORTING); }
+
+ void SetMaxPlayerDistance(float newMax) { _maxPlayerDistance = newMax; }
+ float GetMaxPlayerDistance() const { return _maxPlayerDistance; }
- bool HasEscortState(uint32 escortState) { return (m_uiEscortState & escortState) != 0; }
- virtual bool IsEscorted() const override { return (m_uiEscortState & STATE_ESCORT_ESCORTING); }
+ void SetDespawnAtEnd(bool despawn) { _despawnAtEnd = despawn; }
+ void SetDespawnAtFar(bool despawn) { _despawnAtFar = despawn; }
- void SetMaxPlayerDistance(float newMax) { MaxPlayerDistance = newMax; }
- float GetMaxPlayerDistance() const { return MaxPlayerDistance; }
+ bool GetAttack() const { return _activeAttacker; } // used in EnterEvadeMode override
+ void SetCanAttack(bool attack) { _activeAttacker = attack; }
+
+ ObjectGuid GetEventStarterGUID() const { return _playerGUID; }
- void SetDespawnAtEnd(bool despawn) { DespawnAtEnd = despawn; }
- void SetDespawnAtFar(bool despawn) { DespawnAtFar = despawn; }
- bool GetAttack() const { return m_bIsActiveAttacker; }//used in EnterEvadeMode override
- void SetCanAttack(bool attack) { m_bIsActiveAttacker = attack; }
- ObjectGuid GetEventStarterGUID() const { return m_uiPlayerGUID; }
virtual bool IsEscortNPC(bool isEscorting) const override;
protected:
@@ -116,27 +82,29 @@ struct TC_GAME_API npc_escortAI : public ScriptedAI
bool IsPlayerOrGroupInRange();
void FillPointMovementListForCreature();
- void AddEscortState(uint32 escortState) { m_uiEscortState |= escortState; }
- void RemoveEscortState(uint32 escortState) { m_uiEscortState &= ~escortState; }
-
- ObjectGuid m_uiPlayerGUID;
- uint32 m_uiWPWaitTimer;
- uint32 m_uiPlayerCheckTimer;
- uint32 m_uiEscortState;
- float MaxPlayerDistance;
-
- Quest const* m_pQuestForEscort; //generally passed in Start() when regular escort script.
-
- std::list<Escort_Waypoint> WaypointList;
- std::list<Escort_Waypoint>::iterator CurrentWP;
-
- bool m_bIsActiveAttacker; //obsolete, determined by faction.
- bool m_bIsRunning; //all creatures are walking by default (has flag MOVEMENTFLAG_WALK)
- bool m_bCanInstantRespawn; //if creature should respawn instantly after escort over (if not, database respawntime are used)
- bool m_bCanReturnToStart; //if creature can walk same path (loop) without despawn. Not for regular escort quests.
- bool DespawnAtEnd;
- bool DespawnAtFar;
- bool ScriptWP;
- bool HasImmuneToNPCFlags;
+ void AddEscortState(uint32 escortState) { _escortState |= escortState; }
+ void RemoveEscortState(uint32 escortState) { _escortState &= ~escortState; }
+
+ ObjectGuid _playerGUID;
+ uint32 _pauseTimer;
+ uint32 _playerCheckTimer;
+ uint32 _escortState;
+ float _maxPlayerDistance;
+
+ Quest const* _escortQuest; // generally passed in Start() when regular escort script.
+
+ WaypointPath _path;
+
+ bool _activeAttacker; // obsolete, determined by faction.
+ bool _running; // all creatures are walking by default (has flag MOVEMENTFLAG_WALK)
+ bool _instantRespawn; // if creature should respawn instantly after escort over (if not, database respawntime are used)
+ bool _returnToStart; // if creature can walk same path (loop) without despawn. Not for regular escort quests.
+ bool _despawnAtEnd;
+ bool _despawnAtFar;
+ bool _manualPath;
+ bool _hasImmuneToNPCFlags;
+ bool _started;
+ bool _ended;
+ bool _resume;
};
#endif
diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h
index 1a35f9c77ad..0212d8e61d3 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h
+++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h
@@ -40,8 +40,6 @@ class TC_GAME_API FollowerAI : public ScriptedAI
explicit FollowerAI(Creature* creature);
~FollowerAI() { }
- //virtual void WaypointReached(uint32 uiPointId) = 0;
-
void MovementInform(uint32 motionType, uint32 pointId) override;
void AttackStart(Unit*) override;