Core/Misc: waypoint movement

Port From (https://github.com/TrinityCore/TrinityCore/commit/bf12bae46746149d870cd3e52ccd610f0a975047)
This commit is contained in:
hondacrx
2021-02-04 10:32:48 -05:00
parent bd80c99864
commit 0e77439e20
10 changed files with 130 additions and 55 deletions
+4
View File
@@ -531,10 +531,14 @@ namespace Game.AI
// Called when the dialog status between a player and the creature is requested.
public virtual QuestGiverStatus GetDialogStatus(Player player) { return QuestGiverStatus.ScriptedDefault; }
public virtual void WaypointPathStarted(uint nodeId, uint pathId) { }
public virtual void WaypointStarted(uint nodeId, uint pathId) { }
public virtual void WaypointReached(uint nodeId, uint pathId) { }
public virtual void WaypointPathEnded(uint nodeId, uint pathId) { }
public AISpellInfoType GetAISpellInfo(uint spellId, Difficulty difficulty)
{
return AISpellInfo.LookupByKey((spellId, difficulty));
+86 -27
View File
@@ -133,6 +133,17 @@ namespace Game.AI
public void PausePath(uint delay, bool forced)
{
if (!HasEscortState(SmartEscortState.Escorting))
{
me.PauseMovement(delay, MovementSlot.Idle, forced);
if (me.GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Waypoint)
{
var waypointInfo = me.GetCurrentWaypointInfo();
GetScript().ProcessEventsFor(SmartEvents.WaypointPaused, null, waypointInfo.nodeId, waypointInfo.pathId);
}
return;
}
if (HasEscortState(SmartEscortState.Paused))
{
Log.outError(LogFilter.Server, $"SmartAI.PausePath: Creature entry {me.GetEntry()} wanted to pause waypoint movement while already paused, ignoring.");
@@ -157,6 +168,30 @@ namespace Game.AI
public void StopPath(uint despawnTime = 0, uint quest = 0, bool fail = false)
{
if (!HasEscortState(SmartEscortState.Escorting))
{
(uint nodeId, uint pathId) waypointInfo = new ();
if (me.GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Waypoint)
waypointInfo = me.GetCurrentWaypointInfo();
if (mDespawnState != 2)
SetDespawnTime(despawnTime);
me.GetMotionMaster().MoveIdle();
if (waypointInfo.Item1 != 0)
GetScript().ProcessEventsFor(SmartEvents.WaypointStopped, null, waypointInfo.Item1, waypointInfo.Item2);
if (!fail)
{
if (waypointInfo.Item1 != 0)
GetScript().ProcessEventsFor(SmartEvents.WaypointEnded, null, waypointInfo.Item1, waypointInfo.Item2);
if (mDespawnState == 1)
StartDespawn();
}
return;
}
if (quest != 0)
mEscortQuestID = quest;
@@ -269,6 +304,9 @@ namespace Game.AI
void UpdatePath(uint diff)
{
if (!HasEscortState(SmartEscortState.Escorting))
return;
if (_escortInvokerCheckTimer < diff)
{
if (!IsEscortInvokerInRange())
@@ -391,6 +429,15 @@ namespace Game.AI
return true;
}
public override void WaypointPathStarted(uint nodeId, uint pathId)
{
if (!HasEscortState(SmartEscortState.Escorting))
{
GetScript().ProcessEventsFor(SmartEvents.WaypointStart, null, nodeId, pathId);
return;
}
}
public override void WaypointStarted(uint nodeId, uint pathId)
{
@@ -398,6 +445,12 @@ namespace Game.AI
public override void WaypointReached(uint nodeId, uint pathId)
{
if (!HasEscortState(SmartEscortState.Escorting))
{
GetScript().ProcessEventsFor(SmartEvents.WaypointReached, null, nodeId, pathId);
return;
}
_currentWaypointNode = nodeId;
GetScript().ProcessEventsFor(SmartEvents.WaypointReached, null, _currentWaypointNode, pathId);
@@ -417,6 +470,15 @@ namespace Game.AI
}
}
public override void WaypointPathEnded(uint nodeId, uint pathId)
{
if (!HasEscortState(SmartEscortState.Escorting))
{
GetScript().ProcessEventsFor(SmartEvents.WaypointEnded, null, nodeId, pathId);
return;
}
}
public override void MovementInform(MovementGeneratorType movementType, uint id)
{
if (movementType == MovementGeneratorType.Point && id == EventId.SmartEscortLastOCCPoint)
@@ -450,10 +512,17 @@ namespace Game.AI
me.AddUnitState(UnitState.Evade);
GetScript().ProcessEventsFor(SmartEvents.Evade);//must be after aura clear so we can cast spells from db
GetScript().ProcessEventsFor(SmartEvents.Evade); // must be after _EnterEvadeMode (spells, auras, ...)
SetRun(mRun);
if (HasEscortState(SmartEscortState.Escorting))
Unit owner = me.GetCharmerOrOwner();
if (owner != null)
{
me.GetMotionMaster().MoveFollow(owner, SharedConst.PetFollowDist, SharedConst.PetFollowAngle);
me.ClearUnitState(UnitState.Evade);
}
else if (HasEscortState(SmartEscortState.Escorting))
{
AddEscortState(SmartEscortState.Returning);
ReturnToLastOOCPos();
@@ -461,19 +530,12 @@ namespace Game.AI
else
{
Unit target = !mFollowGuid.IsEmpty() ? Global.ObjAccessor.GetUnit(me, mFollowGuid) : null;
Unit owner = me.GetCharmerOrOwner();
if (target)
{
me.GetMotionMaster().MoveFollow(target, mFollowDist, mFollowAngle);
// evade is not cleared in MoveFollow, so we can't keep it
me.ClearUnitState(UnitState.Evade);
}
else if (owner)
{
me.GetMotionMaster().MoveFollow(owner, SharedConst.PetFollowDist, SharedConst.PetFollowAngle);
me.ClearUnitState(UnitState.Evade);
}
else
me.GetMotionMaster().MoveTargetedHome();
}
@@ -552,12 +614,15 @@ namespace Game.AI
mRespawnTime = 0;
mDespawnState = 0;
_escortState = SmartEscortState.None;
me.SetVisible(true);
if (me.GetFaction() != me.GetCreatureTemplate().Faction)
me.RestoreFaction();
mJustReset = true;
JustReachedHome();
GetScript().OnReset();
GetScript().ProcessEventsFor(SmartEvents.Respawn);
mFollowGuid.Clear();//do not reset follower on Reset(), we need it after combat evade
mFollowDist = 0;
mFollowAngle = 0;
@@ -570,23 +635,18 @@ namespace Game.AI
public override void JustReachedHome()
{
GetScript().OnReset();
if (!mJustReset)
GetScript().ProcessEventsFor(SmartEvents.ReachedHome);
CreatureGroup formation = me.GetFormation();
if (formation == null || formation.GetLeader() == me || !formation.IsFormed())
{
GetScript().ProcessEventsFor(SmartEvents.ReachedHome);
CreatureGroup formation = me.GetFormation();
if (formation == null || formation.GetLeader() == me || !formation.IsFormed())
{
if (me.GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Idle && me.GetWaypointPath() != 0)
me.GetMotionMaster().MovePath(me.GetWaypointPath(), true);
else
me.ResumeMovement();
}
else if (formation.IsFormed())
me.GetMotionMaster().MoveIdle(); // wait the order of leader
if (me.GetMotionMaster().GetMotionSlotType(MovementSlot.Idle) != MovementGeneratorType.Waypoint && me.GetWaypointPath() != 0)
me.GetMotionMaster().MovePath(me.GetWaypointPath(), true);
else
me.ResumeMovement();
}
mJustReset = false;
else if (formation.IsFormed())
me.GetMotionMaster().MoveIdle(); // wait the order of leader
}
public override void EnterCombat(Unit victim)
@@ -993,7 +1053,6 @@ namespace Game.AI
uint mDespawnTime;
uint mRespawnTime;
uint mDespawnState;
bool mJustReset;
// Vehicle conditions
bool mHasConditions;
+1 -1
View File
@@ -3189,7 +3189,7 @@ namespace Game.AI
case SmartEvents.WaypointStopped:
case SmartEvents.WaypointEnded:
{
if (me == null || (e.Event.waypoint.pointID != 0 && var0 != e.Event.waypoint.pointID) || (e.Event.waypoint.pathID != 0 && GetPathId() != e.Event.waypoint.pathID))
if (me == null || (e.Event.waypoint.pointID != 0 && var0 != e.Event.waypoint.pointID) || (e.Event.waypoint.pathID != 0 && var1 != e.Event.waypoint.pathID))
return;
ProcessAction(e, unit);
break;
+1 -1
View File
@@ -998,7 +998,7 @@ namespace Game.Chat.Commands
stmt.AddValue(0, guidLow);
DB.World.Execute(stmt);
target.UpdateWaypointID(0);
target.UpdateCurrentWaypointInfo(0, 0);
stmt = DB.World.GetPreparedStatement(WorldStatements.UPD_CREATURE_MOVEMENT_TYPE);
stmt.AddValue(0, (byte)MovementGeneratorType.Idle);
@@ -67,9 +67,9 @@ namespace Game.Entities
LootModes m_LootMode; // Bitmask (default: LOOT_MODE_DEFAULT) that determines what loot will be lootable
//WaypointMovementGenerator vars
uint m_waypointID;
uint m_path_id;
// Waypoint path
uint _waypointPathId;
(uint nodeId, uint pathId) _currentWaypointNodeInfo;
//Formation var
CreatureGroup m_formation;
+8 -6
View File
@@ -53,6 +53,8 @@ namespace Game.Entities
ResetLootMode(); // restore default loot mode
m_homePosition = new WorldLocation();
_currentWaypointNodeInfo = new();
}
public override void Dispose()
@@ -2334,7 +2336,7 @@ namespace Game.Entities
//Load Path
if (cainfo.path_id != 0)
m_path_id = cainfo.path_id;
_waypointPathId = cainfo.path_id;
if (cainfo.auras != null)
{
@@ -3200,12 +3202,12 @@ namespace Game.Entities
public void GetTransportHomePosition(out float x, out float y, out float z, out float ori) { m_transportHomePosition.GetPosition(out x, out y, out z, out ori); }
public Position GetTransportHomePosition() { return m_transportHomePosition; }
public uint GetWaypointPath() { return m_path_id; }
public void LoadPath(uint pathid) { m_path_id = pathid; }
public uint GetCurrentWaypointID() { return m_waypointID; }
public void UpdateWaypointID(uint wpID) { m_waypointID = wpID; }
public uint GetWaypointPath() { return _waypointPathId; }
public void LoadPath(uint pathid) { _waypointPathId = pathid; }
public (uint nodeId, uint pathId) GetCurrentWaypointInfo() { return _currentWaypointNodeInfo; }
public void UpdateCurrentWaypointInfo(uint nodeId, uint pathId) { _currentWaypointNodeInfo = (nodeId, pathId); }
public CreatureGroup GetFormation() { return m_formation; }
public void SetFormation(CreatureGroup formation) { m_formation = formation; }
@@ -235,7 +235,7 @@ namespace Game.Entities
continue;
if (pair.Value.point_1 != 0)
if (m_leader.GetCurrentWaypointID() == pair.Value.point_1 - 1 || m_leader.GetCurrentWaypointID() == pair.Value.point_2 - 1)
if (m_leader.GetCurrentWaypointInfo().nodeId == pair.Value.point_1 - 1 || m_leader.GetCurrentWaypointInfo().nodeId == pair.Value.point_2 - 1)
pair.Value.follow_angle = (float)Math.PI * 2 - pair.Value.follow_angle;
float angle = pair.Value.follow_angle;
+3 -2
View File
@@ -159,7 +159,7 @@ namespace Game.Entities
init.Stop();
}
public void PauseMovement(uint timer = 0, MovementSlot slot = 0)
public void PauseMovement(uint timer = 0, MovementSlot slot = 0, bool forced = true)
{
if (slot >= MovementSlot.Max)
return;
@@ -168,7 +168,8 @@ namespace Game.Entities
if (movementGenerator != null)
movementGenerator.Pause(timer);
StopMoving();
if (forced)
StopMoving();
}
public void ResumeMovement(uint timer = 0, MovementSlot slot = 0)
@@ -61,6 +61,10 @@ namespace Game.Movement
}
_nextMoveTime.Reset(1000);
// inform AI
if (creature.GetAI() != null)
creature.GetAI().WaypointPathStarted(1, _path.id);
}
public override void DoInitialize(Creature creature)
@@ -92,6 +96,7 @@ namespace Game.Movement
if (_path == null || _path.nodes.Empty())
return;
Cypher.Assert(_currentNode < _path.nodes.Count, $"WaypointMovementGenerator.OnArrived: tried to reference a node id ({_currentNode}) which is not included in path ({_path.id})");
WaypointNode waypoint = _path.nodes.ElementAt((int)_currentNode);
if (waypoint.delay != 0)
{
@@ -110,12 +115,10 @@ namespace Game.Movement
if (creature.IsAIEnabled)
{
creature.GetAI().MovementInform(MovementGeneratorType.Waypoint, (uint)_currentNode);
Cypher.Assert(_currentNode < _path.nodes.Count, $"WaypointMovementGenerator.OnArrived: tried to reference a node id ({_currentNode}) which is not included in path ({_path.id})");
creature.GetAI().WaypointReached(_path.nodes[_currentNode].id, _path.id);
creature.GetAI().WaypointReached(waypoint.id, _path.id);
}
creature.UpdateWaypointID((uint)_currentNode);
creature.UpdateCurrentWaypointInfo(waypoint.id, _path.id);
}
bool StartMove(Creature creature)
@@ -137,10 +140,10 @@ namespace Game.Movement
if (_isArrivalDone)
{
Cypher.Assert(_currentNode < _path.nodes.Count, $"WaypointMovementGenerator.StartMove: tried to reference a node id ({_currentNode}) which is not included in path ({_path.id})");
WaypointNode lastWaypoint = _path.nodes.ElementAt(_currentNode);
if ((_currentNode == _path.nodes.Count - 1) && !_repeating) // If that's our last waypoint
{
WaypointNode lastWaypoint = _path.nodes.ElementAt(_currentNode);
float x = lastWaypoint.x;
float y = lastWaypoint.y;
float z = lastWaypoint.z;
@@ -163,6 +166,11 @@ namespace Game.Movement
// else if (vehicle) - this should never happen, vehicle offsets are const
}
_done = true;
creature.UpdateCurrentWaypointInfo(0, 0);
// inform AI
if (creature.IsAIEnabled)
creature.GetAI().WaypointPathEnded(lastWaypoint.id, _path.id);
return true;
}
@@ -170,12 +178,10 @@ namespace Game.Movement
// inform AI
if (creature.IsAIEnabled)
{
Cypher.Assert(_currentNode < _path.nodes.Count, $"WaypointMovementGenerator.StartMove: tried to reference a node id ({_currentNode}) which is not included in path ({_path.id})");
creature.GetAI().WaypointStarted(_path.nodes[(int)_currentNode].id, _path.id);
}
creature.GetAI().WaypointStarted(lastWaypoint.id, _path.id);
}
Cypher.Assert(_currentNode < _path.nodes.Count, $"WaypointMovementGenerator.StartMove: tried to reference a node id ({_currentNode}) which is not included in path ({_path.id})");
WaypointNode waypoint = _path.nodes.ElementAt(_currentNode);
Position formationDest = new Position(waypoint.x, waypoint.y, waypoint.z, (waypoint.orientation != 0 && waypoint.delay != 0) ? waypoint.orientation : 0.0f);
@@ -288,6 +294,7 @@ namespace Game.Movement
if (_path == null || _path.nodes.Empty())
return false;
Cypher.Assert(_currentNode < _path.nodes.Count, $"WaypointMovementGenerator.GetResetPos: tried to reference a node id ({_currentNode}) which is not included in path ({_path.id})");
WaypointNode waypoint = _path.nodes.ElementAt(_currentNode);
x = waypoint.x;
+6 -4
View File
@@ -137,15 +137,17 @@ namespace Game.Movement
public MovementGeneratorType GetMotionSlotType(MovementSlot slot)
{
if (_slot[(int)slot] == null)
if (Empty() || slot >= MovementSlot.Max || _slot[(int)slot] == null)
return MovementGeneratorType.Max;
else
return _slot[(int)slot].GetMovementGeneratorType();
return _slot[(int)slot].GetMovementGeneratorType();
}
public IMovementGenerator GetMotionSlot(MovementSlot slot)
{
Cypher.Assert((int)slot >= 0);
if (Empty() || slot >= MovementSlot.Max || _slot[(int)slot] == null)
return null;
return _slot[(int)slot];
}