mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
This reverts commit05fb27dae4. (cherrypicked froma3c6880579)
This commit is contained in:
@@ -31,8 +31,6 @@ EndScriptData */
|
||||
#include "MotionMaster.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Player.h"
|
||||
#include "WaypointDefines.h"
|
||||
#include "WaypointMovementGenerator.h"
|
||||
|
||||
enum Points
|
||||
{
|
||||
@@ -41,11 +39,10 @@ enum Points
|
||||
};
|
||||
|
||||
npc_escortAI::npc_escortAI(Creature* creature) : ScriptedAI(creature),
|
||||
m_uiWPWaitTimer(1000),
|
||||
m_uiPlayerCheckTimer(0),
|
||||
m_uiWPWaitTimer(2500),
|
||||
m_uiPlayerCheckTimer(1000),
|
||||
m_uiEscortState(STATE_ESCORT_NONE),
|
||||
MaxPlayerDistance(DEFAULT_MAX_PLAYER_DISTANCE),
|
||||
LastWP(0),
|
||||
m_pQuestForEscort(NULL),
|
||||
m_bIsActiveAttacker(true),
|
||||
m_bIsRunning(false),
|
||||
@@ -54,11 +51,24 @@ npc_escortAI::npc_escortAI(Creature* creature) : ScriptedAI(creature),
|
||||
DespawnAtEnd(true),
|
||||
DespawnAtFar(true),
|
||||
ScriptWP(false),
|
||||
HasImmuneToNPCFlags(false),
|
||||
m_bStarted(false),
|
||||
m_bEnded(false)
|
||||
HasImmuneToNPCFlags(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);
|
||||
@@ -104,15 +114,38 @@ 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->CanStartAttack(who, false))
|
||||
AttackStart(who);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void npc_escortAI::JustDied(Unit* /*killer*/)
|
||||
@@ -136,13 +169,13 @@ void npc_escortAI::JustDied(Unit* /*killer*/)
|
||||
|
||||
void npc_escortAI::JustRespawned()
|
||||
{
|
||||
RemoveEscortState(STATE_ESCORT_ESCORTING | STATE_ESCORT_RETURNING | STATE_ESCORT_PAUSED);
|
||||
m_uiEscortState = STATE_ESCORT_NONE;
|
||||
|
||||
if (!IsCombatMovementAllowed())
|
||||
SetCombatMovement(true);
|
||||
|
||||
//add a small delay before going to first waypoint, normal in near all cases
|
||||
m_uiWPWaitTimer = 1000;
|
||||
m_uiWPWaitTimer = 2500;
|
||||
|
||||
if (me->getFaction() != me->GetCreatureTemplate()->faction)
|
||||
me->RestoreFaction();
|
||||
@@ -152,7 +185,6 @@ 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);
|
||||
@@ -200,57 +232,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)
|
||||
{
|
||||
if (!HasEscortState(STATE_ESCORT_PAUSED))
|
||||
//End of the line
|
||||
if (CurrentWP == WaypointList.end())
|
||||
{
|
||||
m_uiWPWaitTimer = 0;
|
||||
|
||||
if (m_bEnded)
|
||||
if (DespawnAtEnd)
|
||||
{
|
||||
me->StopMoving();
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
TC_LOG_DEBUG("scripts", "EscortAI reached end of waypoints");
|
||||
|
||||
m_bEnded = false;
|
||||
|
||||
if (DespawnAtEnd)
|
||||
if (m_bCanReturnToStart)
|
||||
{
|
||||
TC_LOG_DEBUG("scripts", "EscortAI reached end of waypoints");
|
||||
float fRetX, fRetY, fRetZ;
|
||||
me->GetRespawnPosition(fRetX, fRetY, fRetZ);
|
||||
|
||||
if (m_bCanReturnToStart)
|
||||
{
|
||||
float fRetX, fRetY, fRetZ;
|
||||
me->GetRespawnPosition(fRetX, fRetY, fRetZ);
|
||||
me->GetMotionMaster()->MovePoint(POINT_HOME, fRetX, fRetY, fRetZ);
|
||||
|
||||
me->GetMotionMaster()->MovePoint(POINT_HOME, fRetX, fRetY, fRetZ);
|
||||
m_uiWPWaitTimer = 0;
|
||||
|
||||
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();
|
||||
TC_LOG_DEBUG("scripts", "EscortAI are returning home to spawn location: %u, %f, %f, %f", POINT_HOME, fRetX, fRetY, fRetZ);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_bCanInstantRespawn)
|
||||
{
|
||||
me->setDeathState(JUST_DIED);
|
||||
me->Respawn();
|
||||
}
|
||||
else
|
||||
TC_LOG_DEBUG("scripts", "EscortAI reached end of waypoints with Despawn off");
|
||||
me->DespawnOrUnsummon();
|
||||
|
||||
RemoveEscortState(STATE_ESCORT_ESCORTING);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_bStarted)
|
||||
else
|
||||
{
|
||||
m_bStarted = true;
|
||||
me->GetMotionMaster()->MovePath(_path, false);
|
||||
TC_LOG_DEBUG("scripts", "EscortAI reached end of waypoints with Despawn off");
|
||||
|
||||
return;
|
||||
}
|
||||
else if (WaypointMovementGenerator<Creature>* move = dynamic_cast<WaypointMovementGenerator<Creature>*>(me->GetMotionMaster()->top()))
|
||||
WaypointStart(move->GetCurrentNode());
|
||||
}
|
||||
|
||||
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
|
||||
@@ -260,11 +292,12 @@ 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))
|
||||
{
|
||||
m_uiPlayerCheckTimer += diff;
|
||||
if (m_uiPlayerCheckTimer > 1000)
|
||||
if (m_uiPlayerCheckTimer <= diff)
|
||||
{
|
||||
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);
|
||||
@@ -276,8 +309,10 @@ void npc_escortAI::UpdateAI(uint32 diff)
|
||||
return;
|
||||
}
|
||||
|
||||
m_uiPlayerCheckTimer = 0;
|
||||
m_uiPlayerCheckTimer = 1000;
|
||||
}
|
||||
else
|
||||
m_uiPlayerCheckTimer -= diff;
|
||||
}
|
||||
|
||||
UpdateEscortAI(diff);
|
||||
@@ -293,63 +328,44 @@ void npc_escortAI::UpdateEscortAI(uint32 /*diff*/)
|
||||
|
||||
void npc_escortAI::MovementInform(uint32 moveType, uint32 pointId)
|
||||
{
|
||||
// no action allowed if there is no escort
|
||||
if (!HasEscortState(STATE_ESCORT_ESCORTING))
|
||||
if (moveType != POINT_MOTION_TYPE || !HasEscortState(STATE_ESCORT_ESCORTING))
|
||||
return;
|
||||
|
||||
if (moveType == POINT_MOTION_TYPE)
|
||||
//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);
|
||||
|
||||
if (!m_uiWPWaitTimer)
|
||||
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 if (moveType == WAYPOINT_MOTION_TYPE)
|
||||
else if (pointId == POINT_HOME)
|
||||
{
|
||||
//Call WP function
|
||||
WaypointReached(pointId);
|
||||
TC_LOG_DEBUG("scripts", "EscortAI has returned to original home location and will continue from beginning of waypoint list.");
|
||||
|
||||
//End of the line
|
||||
if (LastWP && LastWP == pointId)
|
||||
CurrentWP = WaypointList.begin();
|
||||
m_uiWPWaitTimer = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Make sure that we are still on the right waypoint
|
||||
if (CurrentWP->id != pointId)
|
||||
{
|
||||
LastWP = 0;
|
||||
|
||||
m_bStarted = false;
|
||||
m_bEnded = true;
|
||||
|
||||
m_uiWPWaitTimer = 50;
|
||||
|
||||
TC_LOG_ERROR("misc", "TSCR ERROR: EscortAI reached waypoint out of order %u, expected %u, creature entry %u", pointId, CurrentWP->id, me->GetEntry());
|
||||
return;
|
||||
}
|
||||
|
||||
TC_LOG_DEBUG("scripts", "EscortAI Waypoint %u reached", pointId);
|
||||
TC_LOG_DEBUG("scripts", "EscortAI Waypoint %u reached", CurrentWP->id);
|
||||
|
||||
WaypointMovementGenerator<Creature>* move = dynamic_cast<WaypointMovementGenerator<Creature>*>(me->GetMotionMaster()->top());
|
||||
//Call WP function
|
||||
WaypointReached(CurrentWP->id);
|
||||
|
||||
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());
|
||||
|
||||
if (m_bIsRunning)
|
||||
me->SetWalk(false);
|
||||
else
|
||||
me->SetWalk(true);
|
||||
++CurrentWP;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,24 +390,9 @@ void npc_escortAI::OnPossess(bool apply)
|
||||
|
||||
void npc_escortAI::AddWaypoint(uint32 id, float x, float y, float z, uint32 waitTime)
|
||||
{
|
||||
Trinity::NormalizeMapCoord(x);
|
||||
Trinity::NormalizeMapCoord(y);
|
||||
Escort_Waypoint t(id, x, y, z, waitTime);
|
||||
|
||||
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;
|
||||
WaypointList.push_back(t);
|
||||
|
||||
// i think SD2 no longer uses this function
|
||||
ScriptWP = true;
|
||||
@@ -411,30 +412,10 @@ void npc_escortAI::FillPointMovementListForCreature()
|
||||
if (!movePoints)
|
||||
return;
|
||||
|
||||
LastWP = movePoints->back().uiPointId;
|
||||
|
||||
for (const ScriptPointMove &point : *movePoints)
|
||||
for (ScriptPointVector::const_iterator itr = movePoints->begin(); itr != movePoints->end(); ++itr)
|
||||
{
|
||||
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));
|
||||
Escort_Waypoint point(itr->uiPointId, itr->fX, itr->fY, itr->fZ, itr->uiWaitTime);
|
||||
WaypointList.push_back(point);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,6 +454,20 @@ 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;
|
||||
@@ -483,16 +478,12 @@ 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->StopMoving();
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
me->GetMotionMaster()->MovementExpired();
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
TC_LOG_DEBUG("scripts", "EscortAI start with WAYPOINT_MOTION_TYPE, changed to MoveIdle.");
|
||||
}
|
||||
@@ -506,7 +497,9 @@ void npc_escortAI::Start(bool isActiveAttacker /* = true*/, bool run /* = false
|
||||
me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC);
|
||||
}
|
||||
|
||||
TC_LOG_DEBUG("scripts", "EscortAI started. ActiveAttacker = %d, Run = %d, PlayerGUID = %s", uint32(m_bIsActiveAttacker), uint32(m_bIsRunning), m_uiPlayerGUID.ToString().c_str());
|
||||
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();
|
||||
|
||||
//Set initial speed
|
||||
if (m_bIsRunning)
|
||||
@@ -514,8 +507,6 @@ void npc_escortAI::Start(bool isActiveAttacker /* = true*/, bool run /* = false
|
||||
else
|
||||
me->SetWalk(true);
|
||||
|
||||
m_bStarted = false;
|
||||
|
||||
AddEscortState(STATE_ESCORT_ESCORTING);
|
||||
}
|
||||
|
||||
@@ -525,14 +516,73 @@ void npc_escortAI::SetEscortPaused(bool on)
|
||||
return;
|
||||
|
||||
if (on)
|
||||
{
|
||||
AddEscortState(STATE_ESCORT_PAUSED);
|
||||
me->StopMoving();
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveEscortState(STATE_ESCORT_PAUSED);
|
||||
if (WaypointMovementGenerator<Creature>* move = dynamic_cast<WaypointMovementGenerator<Creature>*>(me->GetMotionMaster()->top()))
|
||||
move->GetTrackerTimer().Reset(1);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (itr->uiPointId == pointId)
|
||||
{
|
||||
x = itr->fX;
|
||||
y = itr->fY;
|
||||
z = itr->fZ;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -21,12 +21,29 @@
|
||||
|
||||
#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
|
||||
@@ -42,6 +59,7 @@ struct TC_GAME_API npc_escortAI : public ScriptedAI
|
||||
~npc_escortAI() { }
|
||||
|
||||
// CreatureAI functions
|
||||
void AttackStart(Unit* who) override;
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override;
|
||||
|
||||
@@ -61,6 +79,15 @@ 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*/) { }
|
||||
|
||||
@@ -80,7 +107,6 @@ 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();
|
||||
@@ -98,12 +124,12 @@ struct TC_GAME_API npc_escortAI : public ScriptedAI
|
||||
uint32 m_uiPlayerCheckTimer;
|
||||
uint32 m_uiEscortState;
|
||||
float MaxPlayerDistance;
|
||||
uint32 LastWP;
|
||||
|
||||
WaypointPath _path;
|
||||
|
||||
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)
|
||||
@@ -112,7 +138,5 @@ struct TC_GAME_API npc_escortAI : public ScriptedAI
|
||||
bool DespawnAtFar;
|
||||
bool ScriptWP;
|
||||
bool HasImmuneToNPCFlags;
|
||||
bool m_bStarted;
|
||||
bool m_bEnded;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -26,31 +26,33 @@
|
||||
#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;
|
||||
mOOCReached = false;
|
||||
mEscortNPCFlags = 0;
|
||||
mLastWP = nullptr;
|
||||
|
||||
mCanRepeatPath = false;
|
||||
|
||||
// Spawn in run mode
|
||||
mRun = true;
|
||||
m_Ended = false;
|
||||
// spawn in run mode
|
||||
me->SetWalk(false);
|
||||
mRun = false;
|
||||
mEvadeDisabled = false;
|
||||
|
||||
mLastOOCPos = me->GetPosition();
|
||||
|
||||
mCanAutoAttack = true;
|
||||
mCanCombatMove = true;
|
||||
|
||||
mForcedPaused = false;
|
||||
mLastWPIDReached = 0;
|
||||
|
||||
mEscortQuestID = 0;
|
||||
|
||||
@@ -70,10 +72,6 @@ SmartAI::SmartAI(Creature* c) : CreatureAI(c)
|
||||
mJustReset = false;
|
||||
}
|
||||
|
||||
SmartAI::~SmartAI()
|
||||
{
|
||||
}
|
||||
|
||||
bool SmartAI::IsAIControlled() const
|
||||
{
|
||||
return !mIsCharmed;
|
||||
@@ -97,79 +95,63 @@ void SmartAI::UpdateDespawn(const uint32 diff)
|
||||
} else mDespawnTime -= diff;
|
||||
}
|
||||
|
||||
void SmartAI::StartPath(bool run, uint32 path, bool repeat, Unit* invoker)
|
||||
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*/)
|
||||
{
|
||||
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 (_path.nodes.empty())
|
||||
if (!mWayPoints || mWayPoints->empty())
|
||||
return;
|
||||
|
||||
mCurrentWPID = 1;
|
||||
m_Ended = false;
|
||||
|
||||
// Do not use AddEscortState, removing everything from previous cycle
|
||||
mEscortState = SMART_ESCORT_ESCORTING;
|
||||
AddEscortState(SMART_ESCORT_ESCORTING);
|
||||
mCanRepeatPath = repeat;
|
||||
|
||||
if (invoker && invoker->GetTypeId() == TYPEID_PLAYER)
|
||||
SetRun(run);
|
||||
|
||||
if (WayPoint* wp = GetNextWayPoint())
|
||||
{
|
||||
mEscortNPCFlags = me->m_unitData->NpcFlags[0];
|
||||
me->SetNpcFlags(UNIT_NPC_FLAG_NONE);
|
||||
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());
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
WPPath const* path = sSmartWaypointMgr->GetPath(entry);
|
||||
if (!path || path->empty())
|
||||
mWayPoints = sSmartWaypointMgr->GetPath(entry);
|
||||
if (!mWayPoints)
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -178,22 +160,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 (current waypoint: %u) movement while already paused, ignoring.", me->GetEntry(), mCurrentWPID);
|
||||
TC_LOG_ERROR("misc", "SmartAI::PausePath: Creature entry %u wanted to pause waypoint movement while already paused, ignoring.", me->GetEntry());
|
||||
return;
|
||||
}
|
||||
|
||||
mForcedPaused = forced;
|
||||
mLastOOCPos = me->GetPosition();
|
||||
AddEscortState(SMART_ESCORT_PAUSED);
|
||||
mWPPauseTimer = delay;
|
||||
if (forced && !mWPReached)
|
||||
if (forced)
|
||||
{
|
||||
mForcedPaused = forced;
|
||||
SetRun(mRun);
|
||||
me->StopMoving();
|
||||
me->StopMoving();//force stop
|
||||
me->GetMotionMaster()->MoveIdle();//force stop
|
||||
}
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_PAUSED, nullptr, mCurrentWPID, GetScript()->GetPathId());
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_PAUSED, nullptr, mLastWP->id, GetScript()->GetPathId());
|
||||
}
|
||||
|
||||
void SmartAI::StopPath(uint32 DespawnTime, uint32 quest, bool fail)
|
||||
@@ -203,28 +185,33 @@ void SmartAI::StopPath(uint32 DespawnTime, uint32 quest, bool fail)
|
||||
|
||||
if (quest)
|
||||
mEscortQuestID = quest;
|
||||
SetDespawnTime(DespawnTime);
|
||||
//mDespawnTime = DespawnTime;
|
||||
|
||||
if (mDespawnState != 2)
|
||||
SetDespawnTime(DespawnTime);
|
||||
|
||||
me->StopMoving();
|
||||
me->GetMotionMaster()->MovementExpired(false);
|
||||
mLastOOCPos = me->GetPosition();
|
||||
me->StopMoving();//force stop
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_STOPPED, nullptr, mCurrentWPID, GetScript()->GetPathId());
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_STOPPED, nullptr, mLastWP->id, GetScript()->GetPathId());
|
||||
EndPath(fail);
|
||||
}
|
||||
|
||||
void SmartAI::EndPath(bool fail)
|
||||
{
|
||||
RemoveEscortState(SMART_ESCORT_ESCORTING | SMART_ESCORT_PAUSED | SMART_ESCORT_RETURNING);
|
||||
_path.nodes.clear();
|
||||
mWPPauseTimer = 0;
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_ENDED, nullptr, mLastWP->id, GetScript()->GetPathId());
|
||||
|
||||
if (mEscortNPCFlags)
|
||||
RemoveEscortState(SMART_ESCORT_ESCORTING | SMART_ESCORT_PAUSED | SMART_ESCORT_RETURNING);
|
||||
mWayPoints = nullptr;
|
||||
mCurrentWPID = 0;
|
||||
mWPPauseTimer = 0;
|
||||
mLastWP = nullptr;
|
||||
|
||||
if (mCanRepeatPath)
|
||||
{
|
||||
me->SetNpcFlags(NPCFlags(mEscortNPCFlags));
|
||||
mEscortNPCFlags = 0;
|
||||
if (IsAIControlled())
|
||||
StartPath(mRun, GetScript()->GetPathId(), true);
|
||||
}
|
||||
else
|
||||
GetScript()->SetPathId(0);
|
||||
|
||||
ObjectList* targets = GetScript()->GetTargetList(SMART_ESCORT_TARGETS);
|
||||
if (targets && mEscortQuestID)
|
||||
@@ -268,36 +255,15 @@ 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 (WaypointMovementGenerator<Creature>* move = dynamic_cast<WaypointMovementGenerator<Creature>*>(me->GetMotionMaster()->top()))
|
||||
move->GetTrackerTimer().Reset(1);
|
||||
if (mLastWP)
|
||||
me->GetMotionMaster()->MovePoint(mLastWP->id, mLastWP->x, mLastWP->y, mLastWP->z);
|
||||
}
|
||||
|
||||
void SmartAI::ReturnToLastOOCPos()
|
||||
@@ -305,61 +271,69 @@ void SmartAI::ReturnToLastOOCPos()
|
||||
if (!IsAIControlled())
|
||||
return;
|
||||
|
||||
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);
|
||||
SetRun(mRun);
|
||||
me->GetMotionMaster()->MovePoint(SMART_ESCORT_LAST_OOC_POINT, mLastOOCPos);
|
||||
}
|
||||
|
||||
void SmartAI::UpdatePath(const uint32 diff)
|
||||
{
|
||||
if (!HasEscortState(SMART_ESCORT_ESCORTING))
|
||||
return;
|
||||
|
||||
if (mEscortInvokerCheckTimer < diff)
|
||||
{
|
||||
if (!IsEscortInvokerInRange())
|
||||
{
|
||||
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;
|
||||
StopPath(mDespawnTime, mEscortQuestID, true);
|
||||
}
|
||||
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 || mForcedPaused))
|
||||
if (!me->IsInCombat() && !HasEscortState(SMART_ESCORT_RETURNING) && (mWPReached || mLastWPIDReached == SMART_ESCORT_LAST_OOC_POINT || mForcedPaused))
|
||||
{
|
||||
ResumePath();
|
||||
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;
|
||||
}
|
||||
}
|
||||
else
|
||||
mWPPauseTimer = 0;
|
||||
} else {
|
||||
mWPPauseTimer -= diff;
|
||||
}
|
||||
}
|
||||
else if (m_Ended) // end path
|
||||
{
|
||||
m_Ended = false;
|
||||
StopPath();
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasEscortState(SMART_ESCORT_RETURNING))
|
||||
{
|
||||
if (mOOCReached)//reached OOC WP
|
||||
if (mWPReached)//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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -435,44 +409,22 @@ bool SmartAI::IsEscortInvokerInRange()
|
||||
|
||||
void SmartAI::MovepointReached(uint32 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
|
||||
if (id != SMART_ESCORT_LAST_OOC_POINT && mLastWPIDReached != id)
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_REACHED, nullptr, id);
|
||||
|
||||
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)
|
||||
if ((MovementType == POINT_MOTION_TYPE && Data == SMART_ESCORT_LAST_OOC_POINT) || MovementType == FOLLOW_MOTION_TYPE)
|
||||
me->ClearUnitState(UNIT_STATE_EVADE);
|
||||
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_MOVEMENTINFORM, nullptr, MovementType, Data);
|
||||
if (!HasEscortState(SMART_ESCORT_ESCORTING))
|
||||
if (MovementType != POINT_MOTION_TYPE || !HasEscortState(SMART_ESCORT_ESCORTING))
|
||||
return;
|
||||
|
||||
if (MovementType == WAYPOINT_MOTION_TYPE || (MovementType == POINT_MOTION_TYPE && Data == SMART_ESCORT_LAST_OOC_POINT))
|
||||
MovepointReached(Data);
|
||||
MovepointReached(Data);
|
||||
}
|
||||
|
||||
void SmartAI::EnterEvadeMode(EvadeReason /*why*/)
|
||||
@@ -500,7 +452,6 @@ 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())
|
||||
{
|
||||
@@ -510,8 +461,8 @@ void SmartAI::EnterEvadeMode(EvadeReason /*why*/)
|
||||
else
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
|
||||
if (!me->HasUnitState(UNIT_STATE_EVADE))
|
||||
GetScript()->OnReset();
|
||||
if (!HasEscortState(SMART_ESCORT_ESCORTING)) //dont mess up escort movement after combat
|
||||
SetRun(mRun);
|
||||
}
|
||||
|
||||
void SmartAI::MoveInLineOfSight(Unit* who)
|
||||
@@ -624,13 +575,24 @@ 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)
|
||||
@@ -645,26 +607,10 @@ void SmartAI::JustSummoned(Creature* creature)
|
||||
|
||||
void SmartAI::AttackStart(Unit* who)
|
||||
{
|
||||
// dont allow charmed npcs to act on their own
|
||||
if (me->HasUnitFlag(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -832,7 +778,6 @@ void SmartAI::SetCombatMove(bool on)
|
||||
{
|
||||
if (mCanCombatMove == on)
|
||||
return;
|
||||
|
||||
mCanCombatMove = on;
|
||||
if (!IsAIControlled())
|
||||
return;
|
||||
@@ -849,9 +794,12 @@ 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
#include "GameObjectAI.h"
|
||||
#include "Position.h"
|
||||
#include "SmartScript.h"
|
||||
#include "WaypointDefines.h"
|
||||
|
||||
struct WayPoint;
|
||||
|
||||
enum SmartEscortState
|
||||
{
|
||||
@@ -42,7 +43,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
|
||||
@@ -55,6 +56,7 @@ 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; }
|
||||
@@ -207,13 +209,15 @@ 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;
|
||||
uint32 mEscortNPCFlags;
|
||||
WayPoint* mLastWP;
|
||||
Position mLastOOCPos;//set on enter combat
|
||||
uint32 GetWPCount() const { return mWayPoints ? uint32(mWayPoints->size()) : 0; }
|
||||
bool mCanRepeatPath;
|
||||
bool mRun;
|
||||
bool mEvadeDisabled;
|
||||
@@ -223,7 +227,6 @@ class TC_GAME_API SmartAI : public CreatureAI
|
||||
uint32 mInvincibilityHpLevel;
|
||||
bool AssistPlayerInCombatAgainst(Unit* who);
|
||||
|
||||
WaypointPath _path;
|
||||
uint32 mDespawnTime;
|
||||
uint32 mRespawnTime;
|
||||
uint32 mDespawnState;
|
||||
|
||||
@@ -2533,6 +2533,64 @@ 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;
|
||||
|
||||
@@ -41,6 +41,14 @@ 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();
|
||||
|
||||
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_SMARTAI_WP);
|
||||
@@ -68,10 +76,9 @@ 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++;
|
||||
}
|
||||
@@ -80,14 +87,7 @@ 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 point;
|
||||
point.id = id;
|
||||
point.x = x;
|
||||
point.y = y;
|
||||
point.z = z;
|
||||
|
||||
path.push_back(std::move(point));
|
||||
(*waypoint_map[entry])[id] = new WayPoint(id, x, y, z);
|
||||
|
||||
last_entry = entry;
|
||||
total++;
|
||||
@@ -97,6 +97,17 @@ 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;
|
||||
@@ -1240,8 +1251,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
break;
|
||||
case SMART_ACTION_WP_START:
|
||||
{
|
||||
WPPath const* path = sSmartWaypointMgr->GetPath(e.action.wpStart.pathID);
|
||||
if (!path || path->empty())
|
||||
if (!sSmartWaypointMgr->GetPath(e.action.wpStart.pathID))
|
||||
{
|
||||
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;
|
||||
@@ -1403,6 +1413,7 @@ 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:
|
||||
|
||||
@@ -29,7 +29,13 @@ enum SpellEffIndex : uint8;
|
||||
|
||||
struct WayPoint
|
||||
{
|
||||
WayPoint() : id(0), x(0.0f), y(0.0f), z(0.0f) { }
|
||||
WayPoint(uint32 _id, float _x, float _y, float _z)
|
||||
{
|
||||
id = _id;
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
}
|
||||
|
||||
uint32 id;
|
||||
float x;
|
||||
@@ -558,7 +564,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
|
||||
// Not used = 113,
|
||||
SMART_ACTION_START_CLOSEST_WAYPOINT = 113, // wp1, wp2, wp3, wp4, wp5, wp6, wp7
|
||||
SMART_ACTION_MOVE_OFFSET = 114,
|
||||
SMART_ACTION_RANDOM_SOUND = 115, // soundId1, soundId2, soundId3, soundId4, soundId5, onlySelf
|
||||
SMART_ACTION_SET_CORPSE_DELAY = 116, // timer
|
||||
@@ -1463,7 +1469,7 @@ struct SmartScriptHolder
|
||||
operator bool() const { return entryOrGuid != 0; }
|
||||
};
|
||||
|
||||
typedef std::vector<WayPoint> WPPath;
|
||||
typedef std::unordered_map<uint32, WayPoint*> WPPath;
|
||||
|
||||
typedef std::list<WorldObject*> ObjectList;
|
||||
|
||||
@@ -1495,23 +1501,22 @@ class TC_GAME_API SmartWaypointMgr
|
||||
{
|
||||
private:
|
||||
SmartWaypointMgr() { }
|
||||
~SmartWaypointMgr() { }
|
||||
~SmartWaypointMgr();
|
||||
|
||||
public:
|
||||
static SmartWaypointMgr* instance();
|
||||
|
||||
void LoadFromDB();
|
||||
|
||||
WPPath const* GetPath(uint32 id)
|
||||
WPPath* GetPath(uint32 id)
|
||||
{
|
||||
auto itr = waypoint_map.find(id);
|
||||
if (itr != waypoint_map.end())
|
||||
return &itr->second;
|
||||
return nullptr;
|
||||
if (waypoint_map.find(id) != waypoint_map.end())
|
||||
return waypoint_map[id];
|
||||
else return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<uint32, WPPath> waypoint_map;
|
||||
std::unordered_map<uint32, WPPath*> waypoint_map;
|
||||
};
|
||||
|
||||
// all events for a single entry
|
||||
|
||||
@@ -702,14 +702,6 @@ 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)
|
||||
|
||||
@@ -32,7 +32,6 @@ class PathGenerator;
|
||||
struct Position;
|
||||
struct SplineChainLink;
|
||||
struct SplineChainResumeInfo;
|
||||
struct WaypointPath;
|
||||
|
||||
namespace G3D
|
||||
{
|
||||
@@ -181,7 +180,6 @@ 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:
|
||||
|
||||
190
src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
Executable file → Normal file
190
src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
Executable file → Normal file
@@ -25,18 +25,14 @@
|
||||
#include "MoveSplineInit.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Transport.h"
|
||||
#include "WaypointManager.h"
|
||||
#include "World.h"
|
||||
|
||||
void WaypointMovementGenerator<Creature>::LoadPath(Creature* creature)
|
||||
{
|
||||
if (LoadedFromDB)
|
||||
{
|
||||
if (!path_id)
|
||||
path_id = creature->GetWaypointPath();
|
||||
if (!path_id)
|
||||
path_id = creature->GetWaypointPath();
|
||||
|
||||
i_path = sWaypointMgr->GetPath(path_id);
|
||||
}
|
||||
i_path = sWaypointMgr->GetPath(path_id);
|
||||
|
||||
if (!i_path)
|
||||
{
|
||||
@@ -45,95 +41,74 @@ void WaypointMovementGenerator<Creature>::LoadPath(Creature* creature)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Stopped())
|
||||
StartMoveNow(creature);
|
||||
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)
|
||||
{
|
||||
if (!Stopped())
|
||||
StartMoveNow(creature);
|
||||
creature->AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
|
||||
StartMoveNow(creature);
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::OnArrived(Creature* creature)
|
||||
{
|
||||
if (!i_path || i_path->nodes.empty())
|
||||
if (!i_path || i_path->empty())
|
||||
return;
|
||||
if (m_isArrivalDone)
|
||||
return;
|
||||
|
||||
WaypointNode const &waypoint = i_path->nodes.at(i_currentNode);
|
||||
if (waypoint.delay)
|
||||
{
|
||||
creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
|
||||
Stop(waypoint.delay);
|
||||
}
|
||||
m_isArrivalDone = true;
|
||||
|
||||
if (waypoint.eventId && urand(0, 99) < waypoint.eventChance)
|
||||
if (i_path->at(i_currentNode)->event_id && urand(0, 99) < i_path->at(i_currentNode)->event_chance)
|
||||
{
|
||||
TC_LOG_DEBUG("maps.script", "Creature movement start script %u at point %u for %s.", waypoint.eventId, i_currentNode, creature->GetGUID().ToString().c_str());
|
||||
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());
|
||||
creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
|
||||
creature->GetMap()->ScriptsStart(sWaypointScripts, waypoint.eventId, creature, nullptr);
|
||||
creature->GetMap()->ScriptsStart(sWaypointScripts, i_path->at(i_currentNode)->event_id, creature, NULL);
|
||||
}
|
||||
|
||||
// Inform script
|
||||
MovementInform(creature);
|
||||
creature->UpdateWaypointID(i_currentNode);
|
||||
|
||||
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)
|
||||
if (i_path->at(i_currentNode)->delay)
|
||||
{
|
||||
if (TransportBase* trans = creature->GetDirectTransport())
|
||||
trans->CalculatePassengerPosition(formationDest.x, formationDest.y, formationDest.z, &formationDest.orientation);
|
||||
creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
|
||||
Stop(i_path->at(i_currentNode)->delay);
|
||||
}
|
||||
|
||||
// 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 (!creature || !creature->IsAlive())
|
||||
return false;
|
||||
|
||||
if (!i_path || i_path->nodes.empty())
|
||||
if (!i_path || i_path->empty())
|
||||
return false;
|
||||
|
||||
if (Stopped())
|
||||
return true;
|
||||
|
||||
bool transportPath = creature->GetTransport() != nullptr;
|
||||
if (Stopped())
|
||||
return true;
|
||||
|
||||
if (IsArrivalDone)
|
||||
bool transportPath = creature->GetTransport() != NULL;
|
||||
|
||||
if (m_isArrivalDone)
|
||||
{
|
||||
if ((i_currentNode == i_path->nodes.size() - 1) && !repeating) // If that's our last waypoint
|
||||
if ((i_currentNode == i_path->size() - 1) && !repeating) // If that's our last waypoint
|
||||
{
|
||||
WaypointNode const &waypoint = i_path->nodes.at(i_currentNode);
|
||||
|
||||
float x = waypoint.x;
|
||||
float y = waypoint.y;
|
||||
float z = waypoint.z;
|
||||
float x = i_path->at(i_currentNode)->x;
|
||||
float y = i_path->at(i_currentNode)->y;
|
||||
float z = i_path->at(i_currentNode)->z;
|
||||
float o = creature->GetOrientation();
|
||||
|
||||
if (!transportPath)
|
||||
@@ -151,45 +126,23 @@ 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->nodes.size();
|
||||
i_currentNode = (i_currentNode+1) % i_path->size();
|
||||
}
|
||||
|
||||
float finalOrient = 0.0f;
|
||||
uint8 finalMove = WAYPOINT_MOVE_TYPE_WALK;
|
||||
WaypointData const* node = i_path->at(i_currentNode);
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
m_isArrivalDone = 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)
|
||||
{
|
||||
@@ -198,9 +151,15 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
|
||||
trans->CalculatePassengerPosition(formationDest.x, formationDest.y, formationDest.z, &formationDest.orientation);
|
||||
}
|
||||
|
||||
init.MovebyPath(pathing, i_currentNode);
|
||||
//! 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);
|
||||
|
||||
switch (finalMove)
|
||||
//! 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);
|
||||
|
||||
switch (node->move_type)
|
||||
{
|
||||
case WAYPOINT_MOVE_TYPE_LAND:
|
||||
init.SetAnimation(Movement::ToGround);
|
||||
@@ -216,23 +175,20 @@ 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))
|
||||
@@ -240,15 +196,14 @@ 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->nodes.empty())
|
||||
if (!i_path || i_path->empty())
|
||||
return false;
|
||||
|
||||
if (Stopped())
|
||||
{
|
||||
if (CanMove(diff))
|
||||
return StartMoveNow(creature);
|
||||
return StartMove(creature);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -257,45 +212,15 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* creature, uint32 di
|
||||
creature->SetHomePosition(creature->GetPosition());
|
||||
|
||||
if (creature->IsStopped())
|
||||
Stop(LoadedFromDB ? sWorld->getIntConfig(CONFIG_CREATURE_STOP_FOR_PLAYER) : 2 * HOUR * IN_MILLISECONDS);
|
||||
Stop(sWorld->getIntConfig(CONFIG_CREATURE_STOP_FOR_PLAYER));
|
||||
else if (creature->movespline->Finalized())
|
||||
{
|
||||
OnArrived(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 StartMove(creature);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::MovementInform(Creature* creature)
|
||||
{
|
||||
@@ -306,14 +231,11 @@ 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->nodes.empty())
|
||||
if (!i_path || i_path->empty())
|
||||
return false;
|
||||
|
||||
WaypointNode const &waypoint = i_path->nodes.at(i_currentNode);
|
||||
|
||||
x = waypoint.x;
|
||||
y = waypoint.y;
|
||||
z = waypoint.z;
|
||||
const WaypointData* node = i_path->at(i_currentNode);
|
||||
x = node->x; y = node->y; z = node->z;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -421,12 +343,12 @@ void FlightPathMovementGenerator::DoReset(Player* player)
|
||||
|
||||
Movement::MoveSplineInit init(player);
|
||||
uint32 end = GetPathAtMapEnd();
|
||||
for (uint32 i = i_currentNode; i != end; ++i)
|
||||
for (uint32 i = GetCurrentNode(); 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(i_currentNode);
|
||||
init.SetFirstPointId(GetCurrentNode());
|
||||
init.SetFly();
|
||||
init.SetSmooth();
|
||||
init.SetUncompressed();
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "DB2Stores.h"
|
||||
#include "Player.h"
|
||||
#include "Timer.h"
|
||||
#include "WaypointManager.h"
|
||||
|
||||
#define FLIGHT_TRAVEL_UPDATE 100
|
||||
#define TIMEDIFF_NEXT_WP 250
|
||||
@@ -57,16 +58,8 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium< Crea
|
||||
{
|
||||
public:
|
||||
WaypointMovementGenerator(uint32 _path_id = 0, bool _repeating = true)
|
||||
: 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; }
|
||||
|
||||
: i_nextMoveTime(0), m_isArrivalDone(false), path_id(_path_id), repeating(_repeating) { }
|
||||
~WaypointMovementGenerator() { i_path = NULL; }
|
||||
void DoInitialize(Creature*);
|
||||
void DoFinalize(Creature*);
|
||||
void DoReset(Creature*);
|
||||
@@ -81,10 +74,6 @@ 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);}
|
||||
@@ -99,21 +88,17 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium< Crea
|
||||
|
||||
void OnArrived(Creature*);
|
||||
bool StartMove(Creature*);
|
||||
void FormationMove(Creature*);
|
||||
|
||||
bool StartMoveNow(Creature* creature)
|
||||
void StartMoveNow(Creature* creature)
|
||||
{
|
||||
i_nextMoveTime.Reset(0);
|
||||
return StartMove(creature);
|
||||
StartMove(creature);
|
||||
}
|
||||
|
||||
TimeTrackerSmall i_nextMoveTime;
|
||||
bool i_recalculateSpeed;
|
||||
|
||||
bool IsArrivalDone;
|
||||
bool m_isArrivalDone;
|
||||
uint32 path_id;
|
||||
bool repeating;
|
||||
bool LoadedFromDB;
|
||||
};
|
||||
|
||||
/** FlightPathMovementGenerator generates movement of the player for the paths
|
||||
|
||||
@@ -24,6 +24,19 @@
|
||||
|
||||
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();
|
||||
@@ -42,6 +55,7 @@ void WaypointMgr::Load()
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
WaypointData* wp = new WaypointData();
|
||||
|
||||
uint32 pathId = fields[0].GetUInt32();
|
||||
WaypointPath& path = _waypointStore[pathId];
|
||||
@@ -54,25 +68,25 @@ void WaypointMgr::Load()
|
||||
Trinity::NormalizeMapCoord(x);
|
||||
Trinity::NormalizeMapCoord(y);
|
||||
|
||||
WaypointNode wp;
|
||||
wp.id = fields[1].GetUInt32();
|
||||
wp.x = x;
|
||||
wp.y = y;
|
||||
wp.z = z;
|
||||
wp.orientation = o;
|
||||
wp.moveType = fields[6].GetUInt32();
|
||||
wp->id = fields[1].GetUInt32();
|
||||
wp->x = x;
|
||||
wp->y = y;
|
||||
wp->z = z;
|
||||
wp->orientation = o;
|
||||
wp->move_type = fields[6].GetUInt32();
|
||||
|
||||
if (wp.moveType >= WAYPOINT_MOVE_TYPE_MAX)
|
||||
if (wp->move_type >= WAYPOINT_MOVE_TYPE_MAX)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "Waypoint %u in waypoint_data has invalid move_type, ignoring", wp.id);
|
||||
TC_LOG_ERROR("sql.sql", "Waypoint %u in waypoint_data has invalid move_type, ignoring", wp->id);
|
||||
delete wp;
|
||||
continue;
|
||||
}
|
||||
|
||||
wp.delay = fields[7].GetUInt32();
|
||||
wp.eventId = fields[8].GetUInt32();
|
||||
wp.eventChance = fields[9].GetInt16();
|
||||
wp->delay = fields[7].GetUInt32();
|
||||
wp->event_id = fields[8].GetUInt32();
|
||||
wp->event_chance = fields[9].GetInt16();
|
||||
|
||||
path.nodes.push_back(std::move(wp));
|
||||
path.push_back(wp);
|
||||
++count;
|
||||
}
|
||||
while (result->NextRow());
|
||||
@@ -91,6 +105,9 @@ 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);
|
||||
}
|
||||
|
||||
@@ -108,6 +125,7 @@ void WaypointMgr::ReloadPath(uint32 id)
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
WaypointData* wp = new WaypointData();
|
||||
|
||||
float x = fields[1].GetFloat();
|
||||
float y = fields[2].GetFloat();
|
||||
@@ -117,25 +135,25 @@ void WaypointMgr::ReloadPath(uint32 id)
|
||||
Trinity::NormalizeMapCoord(x);
|
||||
Trinity::NormalizeMapCoord(y);
|
||||
|
||||
WaypointNode wp;
|
||||
wp.id = fields[0].GetUInt32();
|
||||
wp.x = x;
|
||||
wp.y = y;
|
||||
wp.z = z;
|
||||
wp.orientation = o;
|
||||
wp.moveType = fields[5].GetUInt32();
|
||||
wp->id = fields[0].GetUInt32();
|
||||
wp->x = x;
|
||||
wp->y = y;
|
||||
wp->z = z;
|
||||
wp->orientation = o;
|
||||
wp->move_type = fields[5].GetUInt32();
|
||||
|
||||
if (wp.moveType >= WAYPOINT_MOVE_TYPE_MAX)
|
||||
if (wp->move_type >= WAYPOINT_MOVE_TYPE_MAX)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "Waypoint %u in waypoint_data has invalid move_type, ignoring", wp.id);
|
||||
TC_LOG_ERROR("sql.sql", "Waypoint %u in waypoint_data has invalid move_type, ignoring", wp->id);
|
||||
delete wp;
|
||||
continue;
|
||||
}
|
||||
|
||||
wp.delay = fields[6].GetUInt32();
|
||||
wp.eventId = fields[7].GetUInt32();
|
||||
wp.eventChance = fields[8].GetUInt8();
|
||||
wp->delay = fields[6].GetUInt32();
|
||||
wp->event_id = fields[7].GetUInt32();
|
||||
wp->event_chance = fields[8].GetUInt8();
|
||||
|
||||
path.nodes.push_back(std::move(wp));
|
||||
path.push_back(wp);
|
||||
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
@@ -20,9 +20,30 @@
|
||||
#define TRINITY_WAYPOINTMANAGER_H
|
||||
|
||||
#include "Define.h"
|
||||
#include "WaypointDefines.h"
|
||||
#include <vector>
|
||||
#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
|
||||
@@ -43,14 +64,14 @@ class TC_GAME_API WaypointMgr
|
||||
if (itr != _waypointStore.end())
|
||||
return &itr->second;
|
||||
|
||||
return nullptr;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
WaypointMgr();
|
||||
~WaypointMgr() { }
|
||||
~WaypointMgr();
|
||||
|
||||
std::unordered_map<uint32, WaypointPath> _waypointStore;
|
||||
WaypointPathContainer _waypointStore;
|
||||
};
|
||||
|
||||
#define sWaypointMgr WaypointMgr::instance()
|
||||
|
||||
@@ -89,7 +89,6 @@
|
||||
#include "VMapFactory.h"
|
||||
#include "VMapManager2.h"
|
||||
#include "WardenCheckMgr.h"
|
||||
#include "WaypointManager.h"
|
||||
#include "WaypointMovementGenerator.h"
|
||||
#include "WeatherMgr.h"
|
||||
#include "WhoListStorage.h"
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "PassiveAI.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ScriptedEscortAI.h"
|
||||
#include "Spell.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellScript.h"
|
||||
@@ -877,15 +876,11 @@ class npc_brann_bronzebeard_algalon : public CreatureScript
|
||||
public:
|
||||
npc_brann_bronzebeard_algalon() : CreatureScript("npc_brann_bronzebeard_algalon") { }
|
||||
|
||||
struct npc_brann_bronzebeard_algalonAI : public npc_escortAI
|
||||
struct npc_brann_bronzebeard_algalonAI : public CreatureAI
|
||||
{
|
||||
npc_brann_bronzebeard_algalonAI(Creature* creature) : npc_escortAI(creature)
|
||||
npc_brann_bronzebeard_algalonAI(Creature* creature) : CreatureAI(creature)
|
||||
{
|
||||
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());
|
||||
_currentPoint = 0;
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
@@ -893,12 +888,14 @@ class npc_brann_bronzebeard_algalon : public CreatureScript
|
||||
switch (action)
|
||||
{
|
||||
case ACTION_START_INTRO:
|
||||
_currentPoint = 0;
|
||||
_events.Reset();
|
||||
Start(false, true);
|
||||
me->SetWalk(false);
|
||||
_events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 1);
|
||||
break;
|
||||
case ACTION_FINISH_INTRO:
|
||||
Talk(SAY_BRANN_ALGALON_INTRO_2);
|
||||
SetEscortPaused(false);
|
||||
_events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 1);
|
||||
break;
|
||||
case ACTION_OUTRO:
|
||||
me->GetMotionMaster()->MovePoint(POINT_BRANN_OUTRO, BrannOutroPos[1]);
|
||||
@@ -908,27 +905,38 @@ class npc_brann_bronzebeard_algalon : public CreatureScript
|
||||
}
|
||||
}
|
||||
|
||||
void WaypointReached(uint32 pointId) override
|
||||
void MovementInform(uint32 movementType, uint32 pointId) override
|
||||
{
|
||||
if (movementType != POINT_MOTION_TYPE)
|
||||
return;
|
||||
|
||||
uint32 delay = 1;
|
||||
_currentPoint = pointId + 1;
|
||||
switch (pointId)
|
||||
{
|
||||
case 2:
|
||||
SetEscortPaused(true);
|
||||
_events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 8000);
|
||||
SetRun(false);
|
||||
delay = 8000;
|
||||
me->SetWalk(true);
|
||||
break;
|
||||
case 5:
|
||||
SetRun(true);
|
||||
SetEscortPaused(true);
|
||||
me->SetWalk(false);
|
||||
Talk(SAY_BRANN_ALGALON_INTRO_1);
|
||||
_events.ScheduleEvent(EVENT_SUMMON_ALGALON, 7500);
|
||||
break;
|
||||
return;
|
||||
case 9:
|
||||
me->DespawnOrUnsummon(1);
|
||||
return;
|
||||
case POINT_BRANN_OUTRO:
|
||||
case POINT_BRANN_OUTRO_END:
|
||||
return;
|
||||
}
|
||||
|
||||
_events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, delay);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
npc_escortAI::UpdateAI(diff);
|
||||
UpdateVictim();
|
||||
|
||||
if (_events.Empty())
|
||||
return;
|
||||
@@ -940,7 +948,8 @@ class npc_brann_bronzebeard_algalon : public CreatureScript
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_BRANN_MOVE_INTRO:
|
||||
SetEscortPaused(false);
|
||||
if (_currentPoint < MAX_BRANN_WAYPOINTS_INTRO)
|
||||
me->GetMotionMaster()->MovePoint(_currentPoint, BrannIntroWaypoint[_currentPoint]);
|
||||
break;
|
||||
case EVENT_SUMMON_ALGALON:
|
||||
if (Creature* algalon = me->GetMap()->SummonCreature(NPC_ALGALON, AlgalonSummonPos))
|
||||
@@ -958,6 +967,7 @@ class npc_brann_bronzebeard_algalon : public CreatureScript
|
||||
|
||||
private:
|
||||
EventMap _events;
|
||||
uint32 _currentPoint;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
|
||||
Reference in New Issue
Block a user