aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/AI/SmartScripts
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/AI/SmartScripts')
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp399
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.h70
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp29
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp59
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h39
5 files changed, 260 insertions, 336 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index 71cb6f7fdad..58f8f72d47b 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -17,6 +17,7 @@
#include "SmartAI.h"
#include "Creature.h"
+#include "CreatureGroups.h"
#include "DBCStructure.h"
#include "GameObject.h"
#include "Group.h"
@@ -28,54 +29,12 @@
#include "ScriptMgr.h"
#include "Vehicle.h"
-SmartAI::SmartAI(Creature* c) : CreatureAI(c)
+SmartAI::SmartAI(Creature* creature) : CreatureAI(creature), mIsCharmed(false), mFollowCreditType(0), mFollowArrivedTimer(0), mFollowCredit(0), mFollowArrivedEntry(0), mFollowDist(0.f), mFollowAngle(0.f),
+ _escortState(SMART_ESCORT_NONE), _escortNPCFlags(0), _escortInvokerCheckTimer(1000), _currentWaypointNode(0), _waypointReached(false), _waypointPauseTimer(0), _waypointPauseForced(false), _repeatWaypointPath(false),
+ _OOCReached(false), _waypointPathEnded(false), mRun(true), mEvadeDisabled(false), mCanAutoAttack(true), mCanCombatMove(true), mInvincibilityHpLevel(0), mDespawnTime(0), mDespawnState(0), mJustReset(false),
+ mConditionsTimer(0), _gossipReturn(false)
{
- 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;
- mEscortNPCFlags = 0;
- mLastWP = nullptr;
-
- mCanRepeatPath = 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;
-
- mDespawnTime = 0;
- mDespawnState = 0;
-
- mEscortInvokerCheckTimer = 1000;
- mFollowGuid.Clear();
- mFollowDist = 0;
- mFollowAngle = 0;
- mFollowCredit = 0;
- mFollowArrivedEntry = 0;
- mFollowCreditType = 0;
- mFollowArrivedTimer = 0;
- mInvincibilityHpLevel = 0;
-
- mJustReset = false;
- mConditionsTimer = 0;
- mHasConditions = sConditionMgr->HasConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE, c->GetEntry());
-
- _gossipReturn = false;
+ mHasConditions = sConditionMgr->HasConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE, creature->GetEntry());
}
bool SmartAI::IsAIControlled() const
@@ -101,74 +60,68 @@ void SmartAI::UpdateDespawn(uint32 diff)
} else mDespawnTime -= diff;
}
-WayPoint* SmartAI::GetNextWayPoint()
+void SmartAI::StartPath(bool run/* = false*/, uint32 pathId/* = 0*/, bool repeat/* = false*/, Unit* invoker/* = nullptr*/, uint32 nodeId/* = 1*/)
{
- if (!mWayPoints || mWayPoints->empty())
- return nullptr;
-
- mCurrentWPID++;
- WPPath::const_iterator itr = mWayPoints->find(mCurrentWPID);
- if (itr != mWayPoints->end())
+ if (me->IsInCombat()) // no wp movement in combat
{
- 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());
+ TC_LOG_ERROR("misc", "SmartAI::StartPath: Creature entry %u wanted to start waypoint movement (%u) while in combat, ignoring.", me->GetEntry(), pathId);
return;
}
if (HasEscortState(SMART_ESCORT_ESCORTING))
StopPath();
- if (path)
+ SetRun(run);
+
+ if (pathId)
{
- if (!LoadPath(path))
+ if (!LoadPath(pathId))
return;
}
- if (!mWayPoints || mWayPoints->empty())
+ if (_path.nodes.empty())
return;
- if (WayPoint* wp = GetNextWayPoint())
- {
- AddEscortState(SMART_ESCORT_ESCORTING);
- mCanRepeatPath = repeat;
+ _currentWaypointNode = nodeId;
+ _waypointPathEnded = false;
- SetRun(run);
+ _repeatWaypointPath = repeat;
- if (invoker && invoker->GetTypeId() == TYPEID_PLAYER)
- {
- mEscortNPCFlags = me->GetUInt32Value(UNIT_NPC_FLAGS);
- me->SetUInt32Value(UNIT_NPC_FLAGS, 0);
- }
+ // Do not use AddEscortState, removing everything from previous
+ _escortState = SMART_ESCORT_ESCORTING;
- 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());
+ if (invoker && invoker->GetTypeId() == TYPEID_PLAYER)
+ {
+ _escortNPCFlags = me->GetUInt32Value(UNIT_NPC_FLAGS);
+ me->SetFlag(UNIT_NPC_FLAGS, 0);
}
+
+ GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_START, nullptr, _currentWaypointNode, GetScript()->GetPathId());
+
+ me->GetMotionMaster()->MovePath(_path, _repeatWaypointPath);
}
bool SmartAI::LoadPath(uint32 entry)
{
if (HasEscortState(SMART_ESCORT_ESCORTING))
return false;
- mWayPoints = sSmartWaypointMgr->GetPath(entry);
- if (!mWayPoints)
+
+ WaypointPath const* path = sSmartWaypointMgr->GetPath(entry);
+ if (!path || path->nodes.empty())
{
GetScript()->SetPathId(0);
return false;
}
+
+ _path.id = path->id;
+ _path.nodes = path->nodes;
+ for (WaypointNode& waypoint : _path.nodes)
+ {
+ Trinity::NormalizeMapCoord(waypoint.x);
+ Trinity::NormalizeMapCoord(waypoint.y);
+ waypoint.moveType = mRun ? WAYPOINT_MOVE_TYPE_RUN : WAYPOINT_MOVE_TYPE_WALK;
+ }
+
GetScript()->SetPathId(entry);
return true;
}
@@ -177,22 +130,26 @@ void SmartAI::PausePath(uint32 delay, bool forced)
{
if (!HasEscortState(SMART_ESCORT_ESCORTING))
return;
+
if (HasEscortState(SMART_ESCORT_PAUSED))
{
- TC_LOG_ERROR("misc", "SmartAI::PausePath: Creature entry %u wanted to pause waypoint movement while already paused, ignoring.", me->GetEntry());
+ TC_LOG_ERROR("misc", "SmartAI::PausePath: Creature entry %u wanted to pause waypoint (current waypoint: %u) movement while already paused, ignoring.", me->GetEntry(), _currentWaypointNode);
return;
}
- mForcedPaused = forced;
- mLastOOCPos = me->GetPosition();
- AddEscortState(SMART_ESCORT_PAUSED);
- mWPPauseTimer = delay;
+
+ _waypointPauseTimer = delay;
+
if (forced)
{
+ _waypointPauseForced = forced;
SetRun(mRun);
- me->StopMoving();//force stop
- me->GetMotionMaster()->MoveIdle();//force stop
+ me->PauseMovement();
}
- GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_PAUSED, nullptr, mLastWP->id, GetScript()->GetPathId());
+ else
+ _waypointReached = false;
+
+ AddEscortState(SMART_ESCORT_PAUSED);
+ GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_PAUSED, nullptr, _currentWaypointNode, GetScript()->GetPathId());
}
void SmartAI::StopPath(uint32 DespawnTime, uint32 quest, bool fail)
@@ -202,40 +159,29 @@ void SmartAI::StopPath(uint32 DespawnTime, uint32 quest, bool fail)
if (quest)
mEscortQuestID = quest;
- SetDespawnTime(DespawnTime);
- //mDespawnTime = DespawnTime;
- mLastOOCPos = me->GetPosition();
- me->StopMoving();//force stop
+ if (mDespawnState != 2)
+ SetDespawnTime(DespawnTime);
+
me->GetMotionMaster()->MoveIdle();
- GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_STOPPED, nullptr, mLastWP->id, GetScript()->GetPathId());
+
+ GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_STOPPED, nullptr, _currentWaypointNode, GetScript()->GetPathId());
+
EndPath(fail);
}
void SmartAI::EndPath(bool fail)
{
- GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_ENDED, nullptr, mLastWP->id, GetScript()->GetPathId());
-
RemoveEscortState(SMART_ESCORT_ESCORTING | SMART_ESCORT_PAUSED | SMART_ESCORT_RETURNING);
- mWayPoints = nullptr;
- mCurrentWPID = 0;
- mWPPauseTimer = 0;
- mLastWP = nullptr;
+ _path.nodes.clear();
+ _waypointPauseTimer = 0;
- if (mEscortNPCFlags)
+ if (_escortNPCFlags)
{
- me->SetUInt32Value(UNIT_NPC_FLAGS, mEscortNPCFlags);
- mEscortNPCFlags = 0;
+ me->SetFlag(UNIT_NPC_FLAGS, _escortNPCFlags);
+ _escortNPCFlags = 0;
}
- if (mCanRepeatPath)
- {
- if (IsAIControlled())
- StartPath(mRun, GetScript()->GetPathId(), true);
- }
- else
- GetScript()->SetPathId(0);
-
ObjectVector const* targets = GetScript()->GetStoredTargetVector(SMART_ESCORT_TARGETS, *me);
if (targets && mEscortQuestID)
{
@@ -279,15 +225,36 @@ void SmartAI::EndPath(bool fail)
}
}
+ // End Path events should be only processed if it was SUCCESSFUL stop or stop called by SMART_ACTION_WAYPOINT_STOP
+ if (fail)
+ return;
+
+ GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_ENDED, nullptr, _currentWaypointNode, GetScript()->GetPathId());
+
+ if (_repeatWaypointPath)
+ {
+ if (IsAIControlled())
+ StartPath(mRun, GetScript()->GetPathId(), _repeatWaypointPath);
+ }
+ else
+ GetScript()->SetPathId(0);
+
if (mDespawnState == 1)
StartDespawn();
}
void SmartAI::ResumePath()
{
+ GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_RESUMED, nullptr, _currentWaypointNode, GetScript()->GetPathId());
+
+ RemoveEscortState(SMART_ESCORT_PAUSED);
+
+ _waypointPauseForced = false;
+ _waypointReached = false;
+ _waypointPauseTimer = 0;
+
SetRun(mRun);
- if (mLastWP)
- me->GetMotionMaster()->MovePoint(mLastWP->id, mLastWP->x, mLastWP->y, mLastWP->z);
+ me->ResumeMovement();
}
void SmartAI::ReturnToLastOOCPos()
@@ -295,82 +262,57 @@ void SmartAI::ReturnToLastOOCPos()
if (!IsAIControlled())
return;
- SetRun(mRun);
- me->GetMotionMaster()->MovePoint(SMART_ESCORT_LAST_OOC_POINT, mLastOOCPos);
+ me->SetWalk(false);
+ me->GetMotionMaster()->MovePoint(SMART_ESCORT_LAST_OOC_POINT, me->GetHomePosition());
}
void SmartAI::UpdatePath(const uint32 diff)
{
if (!HasEscortState(SMART_ESCORT_ESCORTING))
return;
- if (mEscortInvokerCheckTimer < diff)
+
+ if (_escortInvokerCheckTimer < diff)
{
- // Escort failed, no players in range
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);
+ me->DespawnOrUnsummon();
return;
}
- mEscortInvokerCheckTimer = 1000;
+ _escortInvokerCheckTimer = 1000;
}
else
- mEscortInvokerCheckTimer -= diff;
+ _escortInvokerCheckTimer -= diff;
// handle pause
- if (HasEscortState(SMART_ESCORT_PAUSED))
+ if (HasEscortState(SMART_ESCORT_PAUSED) && (_waypointReached || _waypointPauseForced))
{
- if (mWPPauseTimer < diff)
+ if (_waypointPauseTimer <= diff)
{
- if (!me->IsInCombat() && !HasEscortState(SMART_ESCORT_RETURNING) && (mWPReached || mLastWPIDReached == SMART_ESCORT_LAST_OOC_POINT || mForcedPaused))
- {
- GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_RESUMED, nullptr, mLastWP->id, GetScript()->GetPathId());
- RemoveEscortState(SMART_ESCORT_PAUSED);
- if (mForcedPaused)// if paused between 2 wps resend movement
- {
- ResumePath();
- mWPReached = false;
- mForcedPaused = false;
- }
- if (mLastWPIDReached == SMART_ESCORT_LAST_OOC_POINT)
- mWPReached = true;
- }
-
- mWPPauseTimer = 0;
+ if (!me->IsInCombat() && !HasEscortState(SMART_ESCORT_RETURNING))
+ ResumePath();
}
else
- mWPPauseTimer -= diff;
+ _waypointPauseTimer -= diff;
+ }
+ else if (_waypointPathEnded) // end path
+ {
+ _waypointPathEnded = false;
+ StopPath();
+ return;
}
if (HasEscortState(SMART_ESCORT_RETURNING))
{
- if (mWPReached)//reached OOC WP
+ if (_OOCReached) // reached OOC WP
{
+ _OOCReached = 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);
}
}
}
@@ -450,24 +392,43 @@ bool SmartAI::IsEscortInvokerInRange()
return true;
}
-void SmartAI::MovepointReached(uint32 id)
+///@todo Implement new smart event SMART_EVENT_WAYPOINT_STARTED
+void SmartAI::WaypointStarted(uint32 /*nodeId*/, uint32 /*pathId*/)
{
- if (id != SMART_ESCORT_LAST_OOC_POINT && mLastWPIDReached != id)
- GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_REACHED, nullptr, id);
+}
+
+void SmartAI::WaypointReached(uint32 nodeId, uint32 pathId)
+{
+ _currentWaypointNode = nodeId;
+
+ GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_REACHED, nullptr, _currentWaypointNode, pathId);
- mLastWPIDReached = id;
- mWPReached = true;
+ if (_waypointPauseTimer && !_waypointPauseForced)
+ {
+ _waypointReached = true;
+ me->PauseMovement();
+ }
+ else if (HasEscortState(SMART_ESCORT_ESCORTING) && me->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE)
+ {
+ if (_currentWaypointNode == _path.nodes.size())
+ _waypointPathEnded = true;
+ else
+ SetRun(mRun);
+ }
}
-void SmartAI::MovementInform(uint32 MovementType, uint32 Data)
+void SmartAI::MovementInform(uint32 type, uint32 id)
{
- if ((MovementType == POINT_MOTION_TYPE && Data == SMART_ESCORT_LAST_OOC_POINT) || MovementType == FOLLOW_MOTION_TYPE)
+ if (type == POINT_MOTION_TYPE && id == SMART_ESCORT_LAST_OOC_POINT)
me->ClearUnitState(UNIT_STATE_EVADE);
- GetScript()->ProcessEventsFor(SMART_EVENT_MOVEMENTINFORM, nullptr, MovementType, Data);
- if (MovementType != POINT_MOTION_TYPE || !HasEscortState(SMART_ESCORT_ESCORTING))
+ GetScript()->ProcessEventsFor(SMART_EVENT_MOVEMENTINFORM, nullptr, type, id);
+
+ if (!HasEscortState(SMART_ESCORT_ESCORTING))
return;
- MovepointReached(Data);
+
+ if (type == POINT_MOTION_TYPE && id == SMART_ESCORT_LAST_OOC_POINT)
+ _OOCReached = true;
}
void SmartAI::EnterEvadeMode(EvadeReason /*why*/)
@@ -511,8 +472,8 @@ void SmartAI::EnterEvadeMode(EvadeReason /*why*/)
else
me->GetMotionMaster()->MoveTargetedHome();
- if (!HasEscortState(SMART_ESCORT_ESCORTING)) //dont mess up escort movement after combat
- SetRun(mRun);
+ if (!me->HasUnitState(UNIT_STATE_EVADE))
+ GetScript()->OnReset();
}
void SmartAI::MoveInLineOfSight(Unit* who)
@@ -544,19 +505,19 @@ bool SmartAI::AssistPlayerInCombatAgainst(Unit* who)
if (!who || !who->GetVictim())
return false;
- //experimental (unknown) flag not present
+ // 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
+ // 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, SMART_MAX_AID_DIST) && me->IsWithinLOSInMap(who))
{
me->EngageWithTarget(who);
@@ -570,14 +531,14 @@ void SmartAI::JustAppeared()
{
mDespawnTime = 0;
mDespawnState = 0;
- mEscortState = SMART_ESCORT_NONE;
+ _escortState = SMART_ESCORT_NONE;
me->SetVisible(true);
if (me->GetFaction() != me->GetCreatureTemplate()->faction)
me->RestoreFaction();
mJustReset = true;
JustReachedHome();
GetScript()->ProcessEventsFor(SMART_EVENT_RESPAWN);
- mFollowGuid.Clear();//do not reset follower on Reset(), we need it after combat evade
+ mFollowGuid.Clear(); // do not reset follower on Reset(), we need it after combat evade
mFollowDist = 0;
mFollowAngle = 0;
mFollowCredit = 0;
@@ -594,8 +555,16 @@ void SmartAI::JustReachedHome()
{
GetScript()->ProcessEventsFor(SMART_EVENT_REACHED_HOME);
- if (!UpdateVictim() && me->GetMotionMaster()->GetCurrentMovementGeneratorType() == IDLE_MOTION_TYPE && me->GetWaypointPath())
- me->GetMotionMaster()->MovePath(me->GetWaypointPath(), true);
+ CreatureGroup* formation = me->GetFormation();
+ if (!formation || formation->getLeader() == me || !formation->isFormed())
+ {
+ if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == IDLE_MOTION_TYPE && me->GetWaypointPath())
+ me->GetMotionMaster()->MovePath(me->GetWaypointPath(), true);
+ else
+ me->ResumeMovement();
+ }
+ else if (formation->isFormed())
+ me->GetMotionMaster()->MoveIdle(); // wait the order of leader
}
mJustReset = false;
@@ -607,24 +576,14 @@ 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();
- }
+
+ GetScript()->ProcessEventsFor(SMART_EVENT_DEATH, killer);
}
void SmartAI::KilledUnit(Unit* victim)
@@ -642,15 +601,21 @@ void SmartAI::AttackStart(Unit* who)
// dont allow charmed npcs to act on their own
if (!IsAIControlled())
{
- if (who && mCanAutoAttack)
- me->Attack(who, true);
+ if (who)
+ me->Attack(who, mCanAutoAttack);
return;
}
- if (who && me->Attack(who, me->IsWithinMeleeRange(who)))
+ if (who && me->Attack(who, mCanAutoAttack))
{
+ me->GetMotionMaster()->Clear(MOTION_SLOT_ACTIVE);
+ me->PauseMovement();
+
if (mCanCombatMove)
+ {
+ SetRun(mRun);
me->GetMotionMaster()->MoveChase(who);
+ }
}
}
@@ -713,10 +678,10 @@ void SmartAI::PassengerBoarded(Unit* who, int8 seatId, bool apply)
void SmartAI::InitializeAI()
{
GetScript()->OnInitialize(me);
+
if (!me->isDead())
{
- mJustReset = true;
- JustReachedHome();
+ GetScript()->OnReset();
GetScript()->ProcessEventsFor(SMART_EVENT_RESPAWN);
}
}
@@ -727,13 +692,13 @@ void SmartAI::OnCharmed(bool apply)
{
if (HasEscortState(SMART_ESCORT_ESCORTING | SMART_ESCORT_PAUSED | SMART_ESCORT_RETURNING))
EndPath(true);
- me->StopMoving();
}
+
mIsCharmed = apply;
if (!apply && !me->IsInEvadeMode())
{
- if (mCanRepeatPath)
+ if (_repeatWaypointPath)
StartPath(mRun, GetScript()->GetPathId(), true);
else
me->SetWalk(!mRun);
@@ -826,30 +791,21 @@ void SmartAI::SetCombatMove(bool on)
{
if (mCanCombatMove == on)
return;
+
mCanCombatMove = on;
+
if (!IsAIControlled())
return;
- if (!HasEscortState(SMART_ESCORT_ESCORTING))
+
+ if (me->IsEngaged())
{
- if (on && me->GetVictim())
+ if (on && !me->HasReactState(REACT_PASSIVE) && me->GetVictim() && me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_ACTIVE) == MAX_MOTION_TYPE)
{
- if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == IDLE_MOTION_TYPE)
- {
- SetRun(mRun);
- me->GetMotionMaster()->MoveChase(me->GetVictim());
- me->CastStop();
- }
- }
- else
- {
- if (me->HasUnitState(UNIT_STATE_CONFUSED_MOVE | UNIT_STATE_FLEEING_MOVE))
- return;
-
- me->GetMotionMaster()->MovementExpired();
- me->GetMotionMaster()->Clear(true);
- me->StopMoving();
- me->GetMotionMaster()->MoveIdle();
+ SetRun(mRun);
+ me->GetMotionMaster()->MoveChase(me->GetVictim());
}
+ else if (!on && me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_ACTIVE) == CHASE_MOTION_TYPE)
+ me->GetMotionMaster()->Clear(MOTION_SLOT_ACTIVE);
}
}
@@ -881,7 +837,6 @@ void SmartAI::StopFollow(bool complete)
mFollowArrivedTimer = 1000;
mFollowArrivedEntry = 0;
mFollowCreditType = 0;
- me->StopMoving();
me->GetMotionMaster()->MoveIdle();
if (!complete)
diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h
index 3834fd01d07..9c22b509bc9 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.h
+++ b/src/server/game/AI/SmartScripts/SmartAI.h
@@ -23,8 +23,7 @@
#include "GameObjectAI.h"
#include "Position.h"
#include "SmartScript.h"
-
-struct WayPoint;
+#include "WaypointDefines.h"
enum SmartEscortState
{
@@ -43,32 +42,37 @@ enum SmartEscortVars
class TC_GAME_API SmartAI : public CreatureAI
{
public:
- ~SmartAI(){ }
+ ~SmartAI() { }
explicit SmartAI(Creature* c);
+ // core related
+ static int32 Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; }
+
// Check whether we are currently permitted to make the creature take action
bool IsAIControlled() const;
// Start moving to the desired MovePoint
- void StartPath(bool run = false, uint32 path = 0, bool repeat = false, Unit* invoker = nullptr);
+ void StartPath(bool run = false, uint32 pathId = 0, bool repeat = false, Unit* invoker = nullptr, uint32 nodeId = 1);
bool LoadPath(uint32 entry);
void PausePath(uint32 delay, bool forced = false);
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; }
+ bool HasEscortState(uint32 uiEscortState) const { return (_escortState & uiEscortState) != 0; }
+ void AddEscortState(uint32 uiEscortState) { _escortState |= uiEscortState; }
+ void RemoveEscortState(uint32 uiEscortState) { _escortState &= ~uiEscortState; }
void SetAutoAttack(bool on) { mCanAutoAttack = on; }
void SetCombatMove(bool on);
bool CanCombatMove() { return mCanCombatMove; }
void SetFollow(Unit* target, float dist = 0.0f, float angle = 0.0f, uint32 credit = 0, uint32 end = 0, uint32 creditType = 0);
void StopFollow(bool complete);
+ bool IsEscortInvokerInRange();
+
+ void WaypointStarted(uint32 nodeId, uint32 pathId) override;
+ void WaypointReached(uint32 nodeId, uint32 pathId) override;
void SetScript9(SmartScriptHolder& e, uint32 entry, Unit* invoker);
SmartScript* GetScript() { return &mScript; }
- bool IsEscortInvokerInRange();
// Called when creature is spawned or respawned
void JustAppeared() override;
@@ -157,12 +161,6 @@ class TC_GAME_API SmartAI : public CreatureAI
// Used in scripts to share variables
ObjectGuid GetGUID(int32 id = 0) const override;
- //core related
- static int32 Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; }
-
- // Called at movepoint reached
- void MovepointReached(uint32 id);
-
// Makes the creature run/walk
void SetRun(bool run = true);
@@ -194,11 +192,20 @@ class TC_GAME_API SmartAI : public CreatureAI
void OnSpellClick(Unit* clicker, bool& result) override;
- void SetWPPauseTimer(uint32 time) { mWPPauseTimer = time; }
+ void SetWPPauseTimer(uint32 time) { _waypointPauseTimer = time; }
void SetGossipReturn(bool val) { _gossipReturn = val; }
private:
+ bool AssistPlayerInCombatAgainst(Unit* who);
+ void ReturnToLastOOCPos();
+ void UpdatePath(const uint32 diff);
+ void UpdateDespawn(uint32 diff);
+ // Vehicle conditions
+ void CheckConditions(uint32 diff);
+
+ SmartScript mScript;
+
bool mIsCharmed;
uint32 mFollowCreditType;
uint32 mFollowArrivedTimer;
@@ -208,36 +215,29 @@ class TC_GAME_API SmartAI : public CreatureAI
float mFollowDist;
float mFollowAngle;
- void ReturnToLastOOCPos();
- void UpdatePath(const uint32 diff);
- SmartScript mScript;
- WPPath* mWayPoints;
- uint32 mEscortState;
- uint32 mCurrentWPID;
- uint32 mLastWPIDReached;
- bool mWPReached;
- uint32 mWPPauseTimer;
- uint32 mEscortNPCFlags;
- WayPoint* mLastWP;
- Position mLastOOCPos;//set on enter combat
- uint32 GetWPCount() const { return mWayPoints ? uint32(mWayPoints->size()) : 0; }
- bool mCanRepeatPath;
+ uint32 _escortState;
+ uint32 _escortNPCFlags;
+ uint32 _escortInvokerCheckTimer;
+ WaypointPath _path;
+ uint32 _currentWaypointNode;
+ bool _waypointReached;
+ uint32 _waypointPauseTimer;
+ bool _waypointPauseForced;
+ bool _repeatWaypointPath;
+ bool _OOCReached;
+ bool _waypointPathEnded;
+
bool mRun;
bool mEvadeDisabled;
bool mCanAutoAttack;
bool mCanCombatMove;
- bool mForcedPaused;
uint32 mInvincibilityHpLevel;
- bool AssistPlayerInCombatAgainst(Unit* who);
uint32 mDespawnTime;
uint32 mDespawnState;
- void UpdateDespawn(uint32 diff);
- uint32 mEscortInvokerCheckTimer;
bool mJustReset;
// Vehicle conditions
- void CheckConditions(uint32 diff);
bool mHasConditions;
uint32 mConditionsTimer;
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index 79f3b7ce652..7f002ed6671 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -39,6 +39,7 @@
#include "SpellMgr.h"
#include "TemporarySummon.h"
#include "Vehicle.h"
+#include "WaypointDefines.h"
#include <G3D/Quat.h>
SmartScript::SmartScript()
@@ -1990,7 +1991,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
std::back_inserter(waypoints), [](uint32 wp) { return wp != 0; });
float distanceToClosest = std::numeric_limits<float>::max();
- WayPoint* closestWp = nullptr;
+ std::pair<uint32, uint32> closest = { 0, 0 };
for (WorldObject* target : targets)
{
@@ -1998,29 +1999,27 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
if (IsSmart(creature))
{
- for (uint32 wp : waypoints)
+ for (uint32 pathId : waypoints)
{
- WPPath* path = sSmartWaypointMgr->GetPath(wp);
- if (!path || path->empty())
+ WaypointPath const* path = sSmartWaypointMgr->GetPath(pathId);
+ if (!path || path->nodes.empty())
continue;
- auto itrWp = path->find(0);
- if (itrWp != path->end())
+ for (auto itr = path->nodes.begin(); itr != path->nodes.end(); ++itr)
{
- if (WayPoint* wp = itrWp->second)
+ WaypointNode const waypoint = *itr;
+ float distamceToThisNode = creature->GetDistance(waypoint.x, waypoint.y, waypoint.z);
+ if (distamceToThisNode < distanceToClosest)
{
- float distToThisPath = creature->GetDistance(wp->x, wp->y, wp->z);
- if (distToThisPath < distanceToClosest)
- {
- distanceToClosest = distToThisPath;
- closestWp = wp;
- }
+ distanceToClosest = distamceToThisNode;
+ closest.first = pathId;
+ closest.second = waypoint.id;
}
}
}
- if (closestWp)
- CAST_AI(SmartAI, creature->AI())->StartPath(false, closestWp->id, true);
+ if (closest.first != 0)
+ CAST_AI(SmartAI, creature->AI())->StartPath(false, closest.first, true, nullptr, closest.second);
}
}
}
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index 3555575b2b2..b4713b7ed4d 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -29,6 +29,7 @@
#include "SpellMgr.h"
#include "Timer.h"
#include "UnitDefines.h"
+#include "WaypointDefines.h"
SmartWaypointMgr* SmartWaypointMgr::instance()
{
@@ -40,15 +41,7 @@ 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();
+ _waypointStore.clear();
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_SMARTAI_WP);
PreparedQueryResult result = WorldDatabase.Query(stmt);
@@ -62,50 +55,47 @@ void SmartWaypointMgr::LoadFromDB()
uint32 count = 0;
uint32 total = 0;
- uint32 last_entry = 0;
- uint32 last_id = 1;
+ uint32 lastEntry = 0;
+ uint32 lastId = 1;
do
{
Field* fields = result->Fetch();
uint32 entry = fields[0].GetUInt32();
uint32 id = fields[1].GetUInt32();
- float x, y, z;
- x = fields[2].GetFloat();
- y = fields[3].GetFloat();
- z = fields[4].GetFloat();
+ float x = fields[2].GetFloat();
+ float y = fields[3].GetFloat();
+ float z = fields[4].GetFloat();
- if (last_entry != entry)
+ if (lastEntry != entry)
{
- waypoint_map[entry] = new WPPath();
- last_id = 1;
- count++;
+ lastId = 1;
+ ++count;
}
- if (last_id != id)
- TC_LOG_ERROR("sql.sql", "SmartWaypointMgr::LoadFromDB: Path entry %u, unexpected point id %u, expected %u.", entry, id, last_id);
+ if (lastId != id)
+ TC_LOG_ERROR("sql.sql", "SmartWaypointMgr::LoadFromDB: Path entry %u, unexpected point id %u, expected %u.", entry, id, lastId);
- last_id++;
- (*waypoint_map[entry])[id] = new WayPoint(id, x, y, z);
+ ++lastId;
+ WaypointPath& path = _waypointStore[entry];
+ path.id = entry;
+ path.nodes.emplace_back(id, x, y, z);
- last_entry = entry;
- total++;
+ lastEntry = entry;
+ ++total;
}
while (result->NextRow());
TC_LOG_INFO("server.loading", ">> Loaded %u SmartAI waypoint paths (total %u waypoints) in %u ms", count, total, GetMSTimeDiffToNow(oldMSTime));
}
-SmartWaypointMgr::~SmartWaypointMgr()
+WaypointPath const* SmartWaypointMgr::GetPath(uint32 id)
{
- 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;
- }
+ auto itr = _waypointStore.find(id);
+ if (itr != _waypointStore.end())
+ return &itr->second;
+ return nullptr;
}
SmartAIMgr* SmartAIMgr::instance()
@@ -1314,7 +1304,8 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
break;
case SMART_ACTION_WP_START:
{
- if (!sSmartWaypointMgr->GetPath(e.action.wpStart.pathID))
+ WaypointPath const* path = sSmartWaypointMgr->GetPath(e.action.wpStart.pathID);
+ if (!path || path->nodes.empty())
{
TC_LOG_ERROR("sql.sql", "SmartAIMgr: Creature %d Event %u Action %u uses non-existent WaypointPath id %u, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.wpStart.pathID);
return false;
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index f2ba244aaae..747b3c3d2c4 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -20,6 +20,7 @@
#include "Define.h"
#include "ObjectGuid.h"
+#include "WaypointDefines.h"
#include <map>
#include <string>
#include <unordered_map>
@@ -27,22 +28,6 @@
class WorldObject;
enum SpellEffIndex : uint8;
-struct WayPoint
-{
- WayPoint(uint32 _id, float _x, float _y, float _z)
- {
- id = _id;
- x = _x;
- y = _y;
- z = _z;
- }
-
- uint32 id;
- float x;
- float y;
- float z;
-};
-
enum eSmartAI
{
SMART_EVENT_PARAM_COUNT = 4,
@@ -1514,8 +1499,6 @@ struct SmartScriptHolder
operator bool() const { return entryOrGuid != 0; }
};
-typedef std::unordered_map<uint32, WayPoint*> WPPath;
-
typedef std::vector<WorldObject*> ObjectVector;
class ObjectGuidVector
@@ -1542,26 +1525,22 @@ typedef std::unordered_map<uint32, ObjectGuidVector> ObjectVectorMap;
class TC_GAME_API SmartWaypointMgr
{
- private:
- SmartWaypointMgr() { }
- ~SmartWaypointMgr();
-
public:
static SmartWaypointMgr* instance();
void LoadFromDB();
- WPPath* GetPath(uint32 id)
- {
- if (waypoint_map.find(id) != waypoint_map.end())
- return waypoint_map[id];
- else return nullptr;
- }
+ WaypointPath const* GetPath(uint32 id);
private:
- std::unordered_map<uint32, WPPath*> waypoint_map;
+ SmartWaypointMgr() { }
+ ~SmartWaypointMgr() { }
+
+ std::unordered_map<uint32, WaypointPath> _waypointStore;
};
+#define sSmartWaypointMgr SmartWaypointMgr::instance()
+
// all events for a single entry
typedef std::vector<SmartScriptHolder> SmartAIEventList;
typedef std::vector<SmartScriptHolder> SmartAIEventStoredList;
@@ -1627,5 +1606,5 @@ class TC_GAME_API SmartAIMgr
};
#define sSmartScriptMgr SmartAIMgr::instance()
-#define sSmartWaypointMgr SmartWaypointMgr::instance()
+
#endif