Core/Movement: waypoint movement

Port From (https://github.com/TrinityCore/TrinityCore/commit/97585597f0b1aff93873fe4d757556731bc0c1b2)
This commit is contained in:
hondacrx
2020-08-24 17:02:02 -04:00
parent c9e535bb3a
commit 3d3fd0f55f
31 changed files with 960 additions and 950 deletions
+4
View File
@@ -526,6 +526,10 @@ namespace Game.AI
// Called when the dialog status between a player and the creature is requested. // Called when the dialog status between a player and the creature is requested.
public virtual QuestGiverStatus GetDialogStatus(Player player) { return QuestGiverStatus.ScriptedNoStatus; } public virtual QuestGiverStatus GetDialogStatus(Player player) { return QuestGiverStatus.ScriptedNoStatus; }
public virtual void WaypointStarted(uint nodeId, uint pathId) { }
public virtual void WaypointReached(uint nodeId, uint pathId) { }
public AISpellInfoType GetAISpellInfo(uint spellId, Difficulty difficulty) public AISpellInfoType GetAISpellInfo(uint spellId, Difficulty difficulty)
{ {
return AISpellInfo.LookupByKey((spellId, difficulty)); return AISpellInfo.LookupByKey((spellId, difficulty));
+212 -324
View File
@@ -19,30 +19,27 @@ using Framework.Constants;
using Game.Entities; using Game.Entities;
using Game.Groups; using Game.Groups;
using Game.Maps; using Game.Maps;
using Game.Movement;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace Game.AI namespace Game.AI
{ {
public class NpcEscortAI : ScriptedAI public class EscortAI : ScriptedAI
{ {
public NpcEscortAI(Creature creature) : base(creature) public EscortAI(Creature creature) : base(creature)
{ {
m_uiPlayerGUID = ObjectGuid.Empty; _pauseTimer = 2500;
m_uiWPWaitTimer = 2500; _playerCheckTimer = 1000;
m_uiPlayerCheckTimer = 1000; _maxPlayerDistance = 50;
m_uiEscortState = EscortState.None; _activeAttacker = true;
MaxPlayerDistance = 50; _despawnAtEnd = true;
m_pQuestForEscort = null; _despawnAtFar = true;
m_bIsActiveAttacker = true; }
m_bIsRunning = false;
m_bCanInstantRespawn = false; public Player GetPlayerForEscort()
m_bCanReturnToStart = false; {
DespawnAtEnd = true; return Global.ObjAccessor.GetPlayer(me, _playerGUID);
DespawnAtFar = true;
ScriptWP = false;
HasImmuneToNPCFlags = false;
} }
public override void AttackStart(Unit target) public override void AttackStart(Unit target)
@@ -66,6 +63,9 @@ namespace Game.AI
if (!who || !who.GetVictim()) if (!who || !who.GetVictim())
return false; return false;
if (me.HasReactState(ReactStates.Passive))
return false;
//experimental (unknown) flag not present //experimental (unknown) flag not present
if (!me.GetCreatureTemplate().TypeFlags.HasAnyFlag(CreatureTypeFlags.CanAssist)) if (!me.GetCreatureTemplate().TypeFlags.HasAnyFlag(CreatureTypeFlags.CanAssist))
return false; return false;
@@ -75,23 +75,14 @@ namespace Game.AI
return false; return false;
//never attack friendly //never attack friendly
if (me.IsFriendlyTo(who)) if (me.IsValidAssistTarget(who.GetVictim()))
return false; return false;
//too far away and no free sight? //too far away and no free sight?
if (me.IsWithinDistInMap(who, GetMaxPlayerDistance()) && me.IsWithinLOSInMap(who)) if (me.IsWithinDistInMap(who, GetMaxPlayerDistance()) && me.IsWithinLOSInMap(who))
{ {
//already fighting someone? me.EngageWithTarget(who);
if (!me.GetVictim()) return true;
{
AttackStart(who);
return true;
}
else
{
me.EngageWithTarget(who);
return true;
}
} }
return false; return false;
@@ -99,28 +90,20 @@ namespace Game.AI
public override void MoveInLineOfSight(Unit who) public override void MoveInLineOfSight(Unit who)
{ {
if (me.HasReactState(ReactStates.Aggressive) && !me.HasUnitState(UnitState.Stunned) && who.IsTargetableForAttack() && who.IsInAccessiblePlaceFor(me)) if (who == null)
{ return;
if (HasEscortState(EscortState.Escorting) && AssistPlayerInCombatAgainst(who))
return;
if (!me.CanFly() && me.GetDistanceZ(who) > SharedConst.CreatureAttackRangeZ) if (HasEscortState(EscortState.Escorting) && AssistPlayerInCombatAgainst(who))
return; return;
if (me.IsHostileTo(who)) base.MoveInLineOfSight(who);
{
float fAttackRadius = me.GetAttackDistance(who);
if (me.IsWithinDistInMap(who, fAttackRadius) && me.IsWithinLOSInMap(who))
me.EngageWithTarget(who);
}
}
} }
public override void JustDied(Unit killer) public override void JustDied(Unit killer)
{ {
if (!HasEscortState(EscortState.Escorting) || m_uiPlayerGUID.IsEmpty() || m_pQuestForEscort == null) if (!HasEscortState(EscortState.Escorting) || _playerGUID.IsEmpty() || _escortQuest == null)
return; return;
Player player = GetPlayerForEscort(); Player player = GetPlayerForEscort();
if (player) if (player)
{ {
@@ -132,23 +115,23 @@ namespace Game.AI
Player member = groupRef.GetSource(); Player member = groupRef.GetSource();
if (member) if (member)
if (member.IsInMap(player)) if (member.IsInMap(player))
member.FailQuest(m_pQuestForEscort.Id); member.FailQuest(_escortQuest.Id);
} }
} }
else else
player.FailQuest(m_pQuestForEscort.Id); player.FailQuest(_escortQuest.Id);
} }
} }
public override void JustAppeared() public override void JustAppeared()
{ {
m_uiEscortState = EscortState.None; _escortState = EscortState.None;
if (!IsCombatMovementAllowed()) if (!IsCombatMovementAllowed())
SetCombatMovement(true); SetCombatMovement(true);
//add a small delay before going to first waypoint, normal in near all cases //add a small delay before going to first waypoint, normal in near all cases
m_uiWPWaitTimer = 2500; _pauseTimer = 2000;
if (me.GetFaction() != me.GetCreatureTemplate().Faction) if (me.GetFaction() != me.GetCreatureTemplate().Faction)
me.RestoreFaction(); me.RestoreFaction();
@@ -172,12 +155,12 @@ namespace Game.AI
{ {
AddEscortState(EscortState.Returning); AddEscortState(EscortState.Returning);
ReturnToLastPoint(); ReturnToLastPoint();
Log.outDebug(LogFilter.Scripts, "EscortAI has left combat and is now returning to last point"); Log.outDebug(LogFilter.Scripts, "EscortAI.EnterEvadeMode has left combat and is now returning to last point");
} }
else else
{ {
me.GetMotionMaster().MoveTargetedHome(); me.GetMotionMaster().MoveTargetedHome();
if (HasImmuneToNPCFlags) if (_hasImmuneToNPCFlags)
me.AddUnitFlag(UnitFlags.ImmuneToNpc); me.AddUnitFlag(UnitFlags.ImmuneToNpc);
Reset(); Reset();
} }
@@ -209,87 +192,78 @@ namespace Game.AI
public override void UpdateAI(uint diff) public override void UpdateAI(uint diff)
{ {
//Waypoint Updating //Waypoint Updating
if (HasEscortState(EscortState.Escorting) && !me.GetVictim() && m_uiWPWaitTimer != 0 && !HasEscortState(EscortState.Returning)) if (HasEscortState(EscortState.Escorting) && !me.IsEngaged() && !HasEscortState(EscortState.Returning))
{ {
if (m_uiWPWaitTimer <= diff) if (_pauseTimer <= diff)
{ {
//End of the line
if (WaypointList[CurrentWPIndex] == null)
{
m_uiWPWaitTimer = 0;
if (DespawnAtEnd)
{
Log.outDebug(LogFilter.Scripts, "EscortAI reached end of waypoints");
if (m_bCanReturnToStart)
{
float fRetX, fRetY, fRetZ;
me.GetRespawnPosition(out fRetX, out fRetY, out fRetZ);
me.GetMotionMaster().MovePoint(EscortPointIds.Home, fRetX, fRetY, fRetZ);
m_uiWPWaitTimer = 0;
Log.outDebug(LogFilter.Scripts, $"EscortAI are returning home to spawn location: {EscortPointIds.Home}, {fRetX}, {fRetY}, {fRetZ}");
return;
}
if (m_bCanInstantRespawn && !WorldConfig.GetBoolValue(WorldCfg.RespawnDynamicEscortNpc))
{
me.SetDeathState(DeathState.JustDied);
me.Respawn();
}
else
{
if (WorldConfig.GetBoolValue(WorldCfg.RespawnDynamicEscortNpc))
me.GetMap().RemoveRespawnTime(SpawnObjectType.Creature, me.GetSpawnId(), true);
me.DespawnOrUnsummon();
}
return;
}
else
{
Log.outDebug(LogFilter.Scripts, "EscortAI reached end of waypoints with Despawn off");
return;
}
}
if (!HasEscortState(EscortState.Paused)) if (!HasEscortState(EscortState.Paused))
{ {
var currentWp = WaypointList[CurrentWPIndex]; _pauseTimer = 0;
me.GetMotionMaster().MovePoint(currentWp.Id, currentWp.X, currentWp.Y, currentWp.Z);
Log.outDebug(LogFilter.Scripts, $"EscortAI start waypoint {currentWp.Id} ({currentWp.X}, {currentWp.Y}, {currentWp.Z}).");
WaypointStart(currentWp.Id); if (_ended)
{
_ended = false;
me.GetMotionMaster().MoveIdle();
m_uiWPWaitTimer = 0; if (_despawnAtEnd)
{
Log.outDebug(LogFilter.Scripts, "EscortAI.UpdateAI: reached end of waypoints, despawning at end");
if (_returnToStart)
{
Position respawnPosition = new Position();
float orientation;
me.GetRespawnPosition(out respawnPosition.posX, out respawnPosition.posY, out respawnPosition.posZ, out orientation);
respawnPosition.SetOrientation(orientation);
me.GetMotionMaster().MovePoint(EscortPointIds.Home, respawnPosition);
Log.outDebug(LogFilter.Scripts, $"EscortAI.UpdateAI: returning to spawn location: {respawnPosition}");
}
else if (_instantRespawn)
me.Respawn();
else
me.DespawnOrUnsummon();
}
Log.outDebug(LogFilter.Scripts, "EscortAI.UpdateAI: reached end of waypoints");
RemoveEscortState(EscortState.Escorting);
return;
}
if (!_started)
{
_started = true;
me.GetMotionMaster().MovePath(_path, false);
}
else if (_resume)
{
_resume = false;
IMovementGenerator movementGenerator = me.GetMotionMaster().GetMotionSlot(MovementSlot.Idle);
if (movementGenerator != null)
movementGenerator.Resume(0);
}
} }
} }
else
_pauseTimer -= diff;
} }
//Check if player or any member of his group is within range //Check if player or any member of his group is within range
if (HasEscortState(EscortState.Escorting) && !m_uiPlayerGUID.IsEmpty() && !me.GetVictim() && !HasEscortState(EscortState.Returning)) if (_despawnAtFar && HasEscortState(EscortState.Escorting) && !_playerGUID.IsEmpty() && !me.GetVictim() && !HasEscortState(EscortState.Returning))
{ {
if (m_uiPlayerCheckTimer <= diff) if (_playerCheckTimer <= diff)
{ {
if (DespawnAtFar && !IsPlayerOrGroupInRange()) if (!IsPlayerOrGroupInRange())
{ {
Log.outDebug(LogFilter.Scripts, "EscortAI failed because player/group was to far away or not found"); Log.outDebug(LogFilter.Scripts, "EscortAI failed because player/group was to far away or not found");
bool isEscort = false; bool isEscort = false;
CreatureData cdata = me.GetCreatureData(); CreatureData creatureData = me.GetCreatureData();
if (cdata != null) if (creatureData != null)
isEscort = (WorldConfig.GetBoolValue(WorldCfg.RespawnDynamicEscortNpc) && cdata.spawnGroupData.flags.HasAnyFlag(SpawnGroupFlags.EscortQuestNpc)); isEscort = (WorldConfig.GetBoolValue(WorldCfg.RespawnDynamicEscortNpc) && creatureData.spawnGroupData.flags.HasAnyFlag(SpawnGroupFlags.EscortQuestNpc));
if (m_bCanInstantRespawn && !isEscort) if (_instantRespawn && !isEscort)
{ me.DespawnOrUnsummon(0, TimeSpan.FromSeconds(1));
me.SetDeathState(DeathState.JustDied); else if (_instantRespawn && isEscort)
me.Respawn();
}
else if (m_bCanInstantRespawn && isEscort)
me.GetMap().RemoveRespawnTime(SpawnObjectType.Creature, me.GetSpawnId(), true); me.GetMap().RemoveRespawnTime(SpawnObjectType.Creature, me.GetSpawnId(), true);
else else
me.DespawnOrUnsummon(); me.DespawnOrUnsummon();
@@ -297,10 +271,10 @@ namespace Game.AI
return; return;
} }
m_uiPlayerCheckTimer = 1000; _playerCheckTimer = 1000;
} }
else else
m_uiPlayerCheckTimer -= diff; _playerCheckTimer -= diff;
} }
UpdateEscortAI(diff); UpdateEscortAI(diff);
@@ -314,90 +288,94 @@ namespace Game.AI
DoMeleeAttackIfReady(); DoMeleeAttackIfReady();
} }
public override void MovementInform(MovementGeneratorType moveType, uint pointId) public override void MovementInform(MovementGeneratorType moveType, uint Id)
{ {
if (moveType != MovementGeneratorType.Point || !HasEscortState(EscortState.Escorting)) // no action allowed if there is no escort
if (!HasEscortState(EscortState.Escorting))
return; return;
//Combat start position reached, continue waypoint movement //Combat start position reached, continue waypoint movement
if (pointId == EscortPointIds.LastPoint) if (moveType == MovementGeneratorType.Point)
{ {
Log.outDebug(LogFilter.Scripts, "EscortAI has returned to original position before combat"); if (_pauseTimer == 0)
_pauseTimer = 2000;
me.SetWalk(!m_bIsRunning); if (Id == EscortPointIds.LastPoint)
RemoveEscortState(EscortState.Returning);
if (m_uiWPWaitTimer == 0)
m_uiWPWaitTimer = 1;
}
else if (pointId == EscortPointIds.Home)
{
Log.outDebug(LogFilter.Scripts, "EscortAI has returned to original home location and will continue from beginning of waypoint list.");
CurrentWPIndex = 0;
m_uiWPWaitTimer = 1;
}
else
{
var currentWp = WaypointList[CurrentWPIndex];
//Make sure that we are still on the right waypoint
if (currentWp.Id != pointId)
{ {
Log.outError(LogFilter.Misc, $"TSCR ERROR: EscortAI reached waypoint out of order {pointId}, expected {currentWp.Id}, creature entry {me.GetEntry()}"); Log.outDebug(LogFilter.Scripts, "EscortAI.MovementInform has returned to original position before combat");
return;
me.SetWalk(!_running);
RemoveEscortState(EscortState.Returning);
} }
else if (Id == EscortPointIds.Home)
{
Log.outDebug(LogFilter.Scripts, "EscortAI.MovementInform: returned to home location and restarting waypoint path");
_started = false;
}
}
else if (moveType == MovementGeneratorType.Waypoint)
{
Cypher.Assert(Id < _path.nodes.Count, $"EscortAI.MovementInform: referenced movement id ({Id}) points to non-existing node in loaded path");
WaypointNode waypoint = _path.nodes[(int)Id];
Log.outDebug(LogFilter.Scripts, $"EscortAI Waypoint {currentWp.Id} reached"); Log.outDebug(LogFilter.Scripts, $"EscortAI.MovementInform: waypoint node {waypoint.id} reached");
//Call WP function // last point
WaypointReached(currentWp.Id); if (Id == _path.nodes.Count - 1)
{
m_uiWPWaitTimer = currentWp.WaitTimeMs + 1; _started = false;
_ended = true;
++CurrentWPIndex; _pauseTimer = 1000;
}
} }
} }
public void AddWaypoint(uint id, float x, float y, float z, uint waitTime = 0) public void AddWaypoint(uint id, float x, float y, float z, float orientation = 0, uint waitTime = 0)
{ {
Escort_Waypoint t = new Escort_Waypoint(id, x, y, z, waitTime); GridDefines.NormalizeMapCoord(ref x);
GridDefines.NormalizeMapCoord(ref y);
WaypointList.Add(t); WaypointNode waypoint = new WaypointNode();
waypoint.id = id;
waypoint.x = x;
waypoint.y = y;
waypoint.z = z;
waypoint.orientation = orientation;
waypoint.moveType = _running ? WaypointMoveType.Run : WaypointMoveType.Walk;
waypoint.delay = waitTime;
waypoint.eventId = 0;
waypoint.eventChance = 100;
_path.nodes.Add(waypoint);
ScriptWP = true; _manualPath = true;
} }
void FillPointMovementListForCreature() void FillPointMovementListForCreature()
{ {
var movePoints = Global.ScriptMgr.GetPointMoveList(me.GetEntry()); WaypointPath path = Global.WaypointMgr.GetPath(me.GetEntry());
if (movePoints.Empty()) if (path == null)
return; return;
foreach (var point in movePoints) foreach (WaypointNode value in path.nodes)
{ {
Escort_Waypoint wayPoint = new Escort_Waypoint(point.uiPointId, point.fX, point.fY, point.fZ, point.uiWaitTime); WaypointNode node = value;
WaypointList.Add(wayPoint); GridDefines.NormalizeMapCoord(ref node.x);
GridDefines.NormalizeMapCoord(ref node.y);
node.moveType = _running ? WaypointMoveType.Run : WaypointMoveType.Walk;
_path.nodes.Add(node);
} }
} }
public void SetRun(bool on = true) public void SetRun(bool on = true)
{ {
if (on) if (on && !_running)
{ me.SetWalk(false);
if (!m_bIsRunning) else if (!on && _running)
me.SetWalk(false); me.SetWalk(true);
else
Log.outDebug(LogFilter.Scripts, "EscortAI attempt to set run mode, but is already running.");
}
else
{
if (m_bIsRunning)
me.SetWalk(true);
else
Log.outDebug(LogFilter.Scripts, "EscortAI attempt to set walk mode, but is already walking.");
}
m_bIsRunning = on; _running = on;
} }
/// todo get rid of this many variables passed in function. /// todo get rid of this many variables passed in function.
@@ -424,69 +402,54 @@ namespace Game.AI
if (me.GetVictim()) if (me.GetVictim())
{ {
Log.outError(LogFilter.Server, "TSCR ERROR: EscortAI (script: {0}, creature entry: {1}) attempts to Start while in combat", me.GetScriptName(), me.GetEntry()); Log.outError(LogFilter.Scripts, $"EscortAI.Start: (script: {me.GetScriptName()}, creature entry: {me.GetEntry()}) attempts to Start while in combat");
return; return;
} }
if (HasEscortState(EscortState.Escorting)) if (HasEscortState(EscortState.Escorting))
{ {
Log.outError(LogFilter.Scripts, "EscortAI (script: {0}, creature entry: {1}) attempts to Start while already escorting", me.GetScriptName(), me.GetEntry()); Log.outError(LogFilter.Scripts, $"EscortAI.Start: (script: {me.GetScriptName()}, creature entry: {me.GetEntry()}) attempts to Start while already escorting");
return; return;
} }
if (!ScriptWP && resetWaypoints) if (!_manualPath && resetWaypoints)
{
if (!WaypointList.Empty())
WaypointList.Clear();
FillPointMovementListForCreature(); FillPointMovementListForCreature();
}
if (_path.nodes.Empty())
if (WaypointList.Empty())
{ {
Log.outError(LogFilter.Scripts, $"EscortAI (script: {me.GetScriptName()}, creature entry: {me.GetEntry()}) starts with 0 waypoints (possible missing entry in script_waypoint. Quest: {(quest != null ? quest.Id : 0)})."); Log.outError(LogFilter.Scripts, $"EscortAI.Start: (script: {me.GetScriptName()}, creature entry: {me.GetEntry()}) starts with 0 waypoints (possible missing entry in script_waypoint. Quest: {(quest != null ? quest.Id : 0)}).");
return; return;
} }
//set variables // set variables
m_bIsActiveAttacker = isActiveAttacker; _activeAttacker = isActiveAttacker;
m_bIsRunning = run; _running = run;
_playerGUID = playerGUID;
_escortQuest = quest;
_instantRespawn = instantRespawn;
_returnToStart = canLoopPath;
m_uiPlayerGUID = playerGUID; if (_returnToStart && _instantRespawn)
m_pQuestForEscort = quest; Log.outError(LogFilter.Scripts, $"EscortAI.Start: (script: {me.GetScriptName()}, creature entry: {me.GetEntry()}) is set to return home after waypoint end and instant respawn at waypoint end. Creature will never despawn.");
m_bCanInstantRespawn = instantRespawn; me.GetMotionMaster().MoveIdle();
m_bCanReturnToStart = canLoopPath; me.GetMotionMaster().Clear(MovementSlot.Active);
if (m_bCanReturnToStart && m_bCanInstantRespawn)
Log.outDebug(LogFilter.Scripts, "EscortAI is set to return home after waypoint end and instant respawn at waypoint end. Creature will never despawn.");
if (me.GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Waypoint)
{
me.GetMotionMaster().MovementExpired();
me.GetMotionMaster().MoveIdle();
Log.outDebug(LogFilter.Scripts, "EscortAI start with WAYPOINT_MOTION_TYPE, changed to MoveIdle.");
}
//disable npcflags //disable npcflags
me.SetNpcFlags(NPCFlags.None); me.SetNpcFlags(NPCFlags.None);
me.SetNpcFlags2(NPCFlags2.None); me.SetNpcFlags2(NPCFlags2.None);
if (me.HasUnitFlag(UnitFlags.ImmuneToNpc)) if (me.HasUnitFlag(UnitFlags.ImmuneToNpc))
{ {
HasImmuneToNPCFlags = true; _hasImmuneToNPCFlags = true;
me.RemoveUnitFlag(UnitFlags.ImmuneToNpc); me.RemoveUnitFlag(UnitFlags.ImmuneToNpc);
} }
Log.outDebug(LogFilter.Scripts, $"EscortAI started. ActiveAttacker = {m_bIsActiveAttacker}, Run = {m_bIsRunning}, PlayerGUID = {m_uiPlayerGUID}"); Log.outDebug(LogFilter.Scripts, $"EscortAI.Start: (script: {me.GetScriptName()}, creature entry: {me.GetEntry()}) started with {_path.nodes.Count} waypoints. ActiveAttacker = {_activeAttacker}, Run = {_running}, Player = {_playerGUID}");
CurrentWPIndex = 0; // set initial speed
me.SetWalk(!_running);
//Set initial speed
if (m_bIsRunning)
me.SetWalk(false);
else
me.SetWalk(true);
_started = false;
AddEscortState(EscortState.Escorting); AddEscortState(EscortState.Escorting);
} }
@@ -496,75 +459,17 @@ namespace Game.AI
return; return;
if (on) if (on)
{
AddEscortState(EscortState.Paused); AddEscortState(EscortState.Paused);
IMovementGenerator movementGenerator = me.GetMotionMaster().GetMotionSlot(MovementSlot.Idle);
if (movementGenerator != null)
movementGenerator.Pause(0);
}
else else
{
RemoveEscortState(EscortState.Paused); RemoveEscortState(EscortState.Paused);
} _resume = true;
bool SetNextWaypoint(uint pointId, float x, float y, float z, float orientation)
{
me.UpdatePosition(x, y, z, orientation);
return SetNextWaypoint(pointId, false, true);
}
bool SetNextWaypoint(uint pointId, bool setPosition, bool resetWaypointsOnFail)
{
if (!WaypointList.Empty())
WaypointList.Clear();
FillPointMovementListForCreature();
if (WaypointList.Empty())
return false;
int size = WaypointList.Count;
Escort_Waypoint waypoint;
do
{
waypoint = WaypointList.First();
WaypointList.RemoveAt(0);
if (waypoint.Id == pointId)
{
if (setPosition)
me.UpdatePosition(waypoint.X, waypoint.Y, waypoint.Z, me.GetOrientation());
CurrentWPIndex = 0;
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.Count)
{
if (!WaypointList.Empty())
WaypointList.Clear();
FillPointMovementListForCreature();
}
return false;
}
bool GetWaypointPosition(uint pointId, ref float x, ref float y, ref float z)
{
var waypoints = Global.ScriptMgr.GetPointMoveList(me.GetEntry());
if (waypoints == null)
return false;
foreach (var pointMove in waypoints)
{
if (pointMove.uiPointId == pointId)
{
x = pointMove.fX;
y = pointMove.fY;
z = pointMove.fZ;
return true;
}
}
return false;
} }
public override bool IsEscortNPC(bool onlyIfActive) public override bool IsEscortNPC(bool onlyIfActive)
@@ -577,72 +482,55 @@ namespace Game.AI
return false; return false;
} }
public virtual void WaypointReached(uint pointId) { }
public virtual void WaypointStart(uint pointId) { }
public bool HasEscortState(EscortState escortState) { return m_uiEscortState.HasAnyFlag(escortState); } void SetPauseTimer(uint Timer) { _pauseTimer = Timer; }
public override bool IsEscorted() { return m_uiEscortState.HasAnyFlag(EscortState.Escorting); }
public void SetMaxPlayerDistance(float newMax) { MaxPlayerDistance = newMax; } public bool HasEscortState(EscortState escortState) { return (_escortState & escortState) != 0; }
public float GetMaxPlayerDistance() { return MaxPlayerDistance; } public override bool IsEscorted() { return _escortState.HasAnyFlag(EscortState.Escorting); }
public void SetDespawnAtEnd(bool despawn) { DespawnAtEnd = despawn; } void SetMaxPlayerDistance(float newMax) { _maxPlayerDistance = newMax; }
public void SetDespawnAtFar(bool despawn) { DespawnAtFar = despawn; } float GetMaxPlayerDistance() { return _maxPlayerDistance; }
public bool GetAttack() { return m_bIsActiveAttacker; }//used in EnterEvadeMode override
public void SetCanAttack(bool attack) { m_bIsActiveAttacker = attack; }
public ObjectGuid GetEventStarterGUID() { return m_uiPlayerGUID; }
public Player GetPlayerForEscort() { return Global.ObjAccessor.GetPlayer(me, m_uiPlayerGUID); } public void SetDespawnAtEnd(bool despawn) { _despawnAtEnd = despawn; }
public void SetDespawnAtFar(bool despawn) { _despawnAtFar = despawn; }
void AddEscortState(EscortState escortState) { m_uiEscortState |= escortState; } bool GetAttack() { return _activeAttacker; } // used in EnterEvadeMode override
void RemoveEscortState(EscortState escortState) { m_uiEscortState &= ~escortState; } void SetCanAttack(bool attack) { _activeAttacker = attack; }
ObjectGuid m_uiPlayerGUID; ObjectGuid GetEventStarterGUID() { return _playerGUID; }
uint m_uiWPWaitTimer;
uint m_uiPlayerCheckTimer;
EscortState m_uiEscortState;
float MaxPlayerDistance;
Quest m_pQuestForEscort; //generally passed in Start() when regular escort script. void AddEscortState(EscortState escortState) { _escortState |= escortState; }
void RemoveEscortState(EscortState escortState) { _escortState &= ~escortState; }
List<Escort_Waypoint> WaypointList = new List<Escort_Waypoint>(); ObjectGuid _playerGUID;
int CurrentWPIndex; uint _pauseTimer;
uint _playerCheckTimer;
EscortState _escortState;
float _maxPlayerDistance;
bool m_bIsActiveAttacker; //obsolete, determined by faction. Quest _escortQuest; //generally passed in Start() when regular escort script.
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) WaypointPath _path;
bool m_bCanReturnToStart; //if creature can walk same path (loop) without despawn. Not for regular escort quests.
bool DespawnAtEnd; bool _activeAttacker; // obsolete, determined by faction.
bool DespawnAtFar; bool _running; // all creatures are walking by default (has flag MOVEMENTFLAG_WALK)
bool ScriptWP; bool _instantRespawn; // if creature should respawn instantly after escort over (if not, database respawntime are used)
bool HasImmuneToNPCFlags; bool _returnToStart; // if creature can walk same path (loop) without despawn. Not for regular escort quests.
bool _despawnAtEnd;
bool _despawnAtFar;
bool _manualPath;
bool _hasImmuneToNPCFlags;
bool _started;
bool _ended;
bool _resume;
} }
public enum EscortState public enum EscortState
{ {
None = 0x000, //nothing in progress None = 0x00, //nothing in progress
Escorting = 0x001, //escort are in progress Escorting = 0x01, //escort are in progress
Returning = 0x002, //escort is returning after being in combat Returning = 0x02, //escort is returning after being in combat
Paused = 0x004 //will not proceed with waypoints before state is removed Paused = 0x04 //will not proceed with waypoints before state is removed
}
class Escort_Waypoint
{
public Escort_Waypoint(uint id, float x, float y, float z, uint w)
{
Id = id;
X = x;
Y = y;
Z = z;
WaitTimeMs = w;
}
public uint Id;
public float X;
public float Y;
public float Z;
public uint WaitTimeMs;
} }
struct EscortPointIds struct EscortPointIds
+227 -244
View File
@@ -18,6 +18,7 @@
using Framework.Constants; using Framework.Constants;
using Game.Entities; using Game.Entities;
using Game.Groups; using Game.Groups;
using Game.Maps;
using Game.Spells; using Game.Spells;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -32,18 +33,11 @@ namespace Game.AI
public SmartAI(Creature creature) : base(creature) public SmartAI(Creature creature) : base(creature)
{ {
// Spawn in run mode _escortInvokerCheckTimer = 1000;
me.SetWalk(false);
mRun = true; mRun = true;
mLastOOCPos = me.GetPosition();
mCanAutoAttack = true; mCanAutoAttack = true;
mCanCombatMove = true; mCanCombatMove = true;
mEscortInvokerCheckTimer = 1000;
mFollowGuid = ObjectGuid.Empty;
mHasConditions = Global.ConditionMgr.HasConditionsForNotGroupedEntry(ConditionSourceType.CreatureTemplateVehicle, creature.GetEntry()); mHasConditions = Global.ConditionMgr.HasConditionsForNotGroupedEntry(ConditionSourceType.CreatureTemplateVehicle, creature.GetEntry());
} }
@@ -72,70 +66,43 @@ namespace Game.AI
mDespawnTime -= diff; mDespawnTime -= diff;
} }
public override void Reset() public void StartPath(bool run = false, uint pathId = 0, bool repeat = false, Unit invoker = null, uint nodeId = 1)
{
if (!HasEscortState(SmartEscortState.Escorting))//dont mess up escort movement after combat
SetRun(mRun);
GetScript().OnReset();
}
WayPoint GetNextWayPoint()
{
if (mWayPoints.Empty())
return null;
mCurrentWPID++;
var wayPoint = mWayPoints.Find(p => p.Id == mCurrentWPID);
if (wayPoint != null)
{
mLastWP = wayPoint;
if (mLastWP.Id != mCurrentWPID)
{
Log.outError(LogFilter.Misc, "SmartAI.GetNextWayPoint: Got not expected waypoint id {mLastWP.id}, expected {mCurrentWPID}");
}
return wayPoint;
}
return null;
}
public void StartPath(bool run = false, uint path = 0, bool repeat = false, Unit invoker = null)
{ {
if (me.IsInCombat())// no wp movement in combat if (me.IsInCombat())// no wp movement in combat
{ {
Log.outError(LogFilter.Server, "SmartAI.StartPath: Creature entry {0} wanted to start waypoint movement while in combat, ignoring.", me.GetEntry()); Log.outError(LogFilter.Server, $"SmartAI.StartPath: Creature entry {me.GetEntry()} wanted to start waypoint movement while in combat, ignoring.");
return; return;
} }
if (HasEscortState(SmartEscortState.Escorting)) if (HasEscortState(SmartEscortState.Escorting))
StopPath(); StopPath();
if (path != 0) if (pathId != 0)
{ {
if (!LoadPath(path)) if (!LoadPath(pathId))
return; return;
} }
if (mWayPoints.Empty()) if (_path.nodes.Empty())
return; return;
WayPoint wp = GetNextWayPoint(); _currentWaypointNode = nodeId;
if (wp != null) _waypointPathEnded = false;
_repeatWaypointPath = repeat;
// Do not use AddEscortState, removing everything from previous
_escortState = SmartEscortState.Escorting;
if (invoker && invoker.IsPlayer())
{ {
AddEscortState(SmartEscortState.Escorting); _escortNPCFlags = me.m_unitData.NpcFlags[0];
mCanRepeatPath = repeat; me.SetNpcFlags((NPCFlags)0);
SetRun(run);
if (invoker != null && invoker.GetTypeId() == TypeId.Player)
{
mEscortNPCFlags = me.m_unitData.NpcFlags[0];
me.SetNpcFlags(NPCFlags.None);
}
mLastOOCPos = me.GetPosition();
me.GetMotionMaster().MovePoint(wp.Id, wp.X, wp.Y, wp.Z);
GetScript().ProcessEventsFor(SmartEvents.WaypointStart, null, wp.Id, GetScript().GetPathId());
} }
GetScript().ProcessEventsFor(SmartEvents.WaypointStart, null, _currentWaypointNode, GetScript().GetPathId());
me.GetMotionMaster().MovePath(_path, _repeatWaypointPath);
} }
bool LoadPath(uint entry) bool LoadPath(uint entry)
@@ -143,13 +110,22 @@ namespace Game.AI
if (HasEscortState(SmartEscortState.Escorting)) if (HasEscortState(SmartEscortState.Escorting))
return false; return false;
mWayPoints = Global.SmartAIMgr.GetPath(entry); WaypointPath path = Global.SmartAIMgr.GetPath(entry);
if (mWayPoints == null) if (path == null || path.nodes.Empty())
{ {
GetScript().SetPathId(0); GetScript().SetPathId(0);
return false; return false;
} }
_path.id = path.id;
_path.nodes = path.nodes;
foreach (WaypointNode waypoint in _path.nodes)
{
GridDefines.NormalizeMapCoord(ref waypoint.x);
GridDefines.NormalizeMapCoord(ref waypoint.y);
waypoint.moveType = mRun ? WaypointMoveType.Run : WaypointMoveType.Walk;
}
GetScript().SetPathId(entry); GetScript().SetPathId(entry);
return true; return true;
} }
@@ -165,20 +141,23 @@ namespace Game.AI
return; return;
} }
mForcedPaused = forced; _waypointPauseTimer = delay;
mLastOOCPos = me.GetPosition();
AddEscortState(SmartEscortState.Paused);
mWPPauseTimer = delay;
if (forced) if (forced)
{ {
_waypointPauseForced = forced;
SetRun(mRun); SetRun(mRun);
me.StopMoving();//force stop me.PauseMovement();
me.GetMotionMaster().MoveIdle();//force stop me.SetHomePosition(me.GetPosition());
} }
GetScript().ProcessEventsFor(SmartEvents.WaypointPaused, null, mLastWP.Id, GetScript().GetPathId()); else
_waypointReached = false;
AddEscortState(SmartEscortState.Paused);
GetScript().ProcessEventsFor(SmartEvents.WaypointPaused, null, _currentWaypointNode, GetScript().GetPathId());
} }
public void StopPath(uint DespawnTime = 0, uint quest = 0, bool fail = false) public void StopPath(uint despawnTime = 0, uint quest = 0, bool fail = false)
{ {
if (!HasEscortState(SmartEscortState.Escorting)) if (!HasEscortState(SmartEscortState.Escorting))
return; return;
@@ -186,40 +165,28 @@ namespace Game.AI
if (quest != 0) if (quest != 0)
mEscortQuestID = quest; mEscortQuestID = quest;
SetDespawnTime(DespawnTime); if (mDespawnState != 2)
//mDespawnTime = DespawnTime; SetDespawnTime(despawnTime);
mLastOOCPos = me.GetPosition();
me.StopMoving();//force stop
me.GetMotionMaster().MoveIdle(); me.GetMotionMaster().MoveIdle();
GetScript().ProcessEventsFor(SmartEvents.WaypointStopped, null, mLastWP.Id, GetScript().GetPathId());
GetScript().ProcessEventsFor(SmartEvents.WaypointStopped, null, _currentWaypointNode, GetScript().GetPathId());
EndPath(fail); EndPath(fail);
} }
public void EndPath(bool fail = false) public void EndPath(bool fail = false)
{ {
GetScript().ProcessEventsFor(SmartEvents.WaypointEnded, null, mLastWP.Id, GetScript().GetPathId());
RemoveEscortState(SmartEscortState.Escorting | SmartEscortState.Paused | SmartEscortState.Returning); RemoveEscortState(SmartEscortState.Escorting | SmartEscortState.Paused | SmartEscortState.Returning);
mWayPoints = null; _path.nodes.Clear();
mCurrentWPID = 0; _waypointPauseTimer = 0;
mWPPauseTimer = 0;
mLastWP = null;
if (mEscortNPCFlags != 0) if (_escortNPCFlags != 0)
{ {
me.SetNpcFlags((NPCFlags)mEscortNPCFlags); me.SetNpcFlags((NPCFlags)_escortNPCFlags);
mEscortNPCFlags = 0; _escortNPCFlags = 0;
} }
if (mCanRepeatPath)
{
if (IsAIControlled())
StartPath(mRun, GetScript().GetPathId(), true);
}
else
GetScript().SetPathId(0);
List<WorldObject> targets = GetScript().GetStoredTargetList(SharedConst.SmartEscortTargets, me); List<WorldObject> targets = GetScript().GetStoredTargetList(SharedConst.SmartEscortTargets, me);
if (targets != null && mEscortQuestID != 0) if (targets != null && mEscortQuestID != 0)
{ {
@@ -264,16 +231,36 @@ namespace Game.AI
} }
} }
// 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(SmartEvents.WaypointEnded, null, _currentWaypointNode, GetScript().GetPathId());
if (_repeatWaypointPath)
{
if (IsAIControlled())
StartPath(mRun, GetScript().GetPathId(), _repeatWaypointPath);
}
else
GetScript().SetPathId(0);
if (mDespawnState == 1) if (mDespawnState == 1)
StartDespawn(); StartDespawn();
} }
public void ResumePath() public void ResumePath()
{ {
SetRun(mRun); GetScript().ProcessEventsFor(SmartEvents.WaypointResumed, null, _currentWaypointNode, GetScript().GetPathId());
if (mLastWP != null) RemoveEscortState(SmartEscortState.Paused);
me.GetMotionMaster().MovePoint(mLastWP.Id, mLastWP.X, mLastWP.Y, mLastWP.Z);
_waypointPauseForced = false;
_waypointReached = false;
_waypointPauseTimer = 0;
SetRun(mRun);
me.ResumeMovement();
} }
void ReturnToLastOOCPos() void ReturnToLastOOCPos()
@@ -281,8 +268,8 @@ namespace Game.AI
if (!IsAIControlled()) if (!IsAIControlled())
return; return;
SetRun(mRun); me.SetWalk(false);
me.GetMotionMaster().MovePoint(EventId.SmartEscortLastOCCPoint, mLastOOCPos); me.GetMotionMaster().MovePoint(EventId.SmartEscortLastOCCPoint, me.GetHomePosition());
} }
void UpdatePath(uint diff) void UpdatePath(uint diff)
@@ -290,77 +277,48 @@ namespace Game.AI
if (!HasEscortState(SmartEscortState.Escorting)) if (!HasEscortState(SmartEscortState.Escorting))
return; return;
if (mEscortInvokerCheckTimer < diff) if (_escortInvokerCheckTimer < diff)
{ {
// Escort failed, no players in range
if (!IsEscortInvokerInRange()) if (!IsEscortInvokerInRange())
{ {
StopPath(0, mEscortQuestID, true); StopPath(0, mEscortQuestID, true);
// allow to properly hook out of range despawn action, which in most cases should perform the same operation as dying // allow to properly hook out of range despawn action, which in most cases should perform the same operation as dying
GetScript().ProcessEventsFor(SmartEvents.Death, me); GetScript().ProcessEventsFor(SmartEvents.Death, me);
me.DespawnOrUnsummon(1); me.DespawnOrUnsummon();
return; return;
} }
mEscortInvokerCheckTimer = 1000; _escortInvokerCheckTimer = 1000;
} }
else else
mEscortInvokerCheckTimer -= diff; _escortInvokerCheckTimer -= diff;
// handle pause // handle pause
if (HasEscortState(SmartEscortState.Paused)) if (HasEscortState(SmartEscortState.Paused) && (_waypointReached || _waypointPauseForced))
{ {
if (mWPPauseTimer < diff) if (_waypointPauseTimer < diff)
{ {
if (!me.IsInCombat() && !HasEscortState(SmartEscortState.Returning) && (mWPReached || mLastWPIDReached == EventId.SmartEscortLastOCCPoint || mForcedPaused)) if (!me.IsInCombat() && !HasEscortState(SmartEscortState.Returning))
{ ResumePath();
GetScript().ProcessEventsFor(SmartEvents.WaypointResumed, null, mLastWP.Id, GetScript().GetPathId());
RemoveEscortState(SmartEscortState.Paused);
if (mForcedPaused)// if paused between 2 wps resend movement
{
ResumePath();
mWPReached = false;
mForcedPaused = false;
}
if (mLastWPIDReached == EventId.SmartEscortLastOCCPoint)
mWPReached = true;
}
mWPPauseTimer = 0;
} }
else else
mWPPauseTimer -= diff; _waypointPauseTimer -= diff;
}
else if (_waypointPathEnded) // end path
{
_waypointPathEnded = false;
StopPath();
return;
} }
if (HasEscortState(SmartEscortState.Returning)) if (HasEscortState(SmartEscortState.Returning))
{ {
if (mWPReached)//reached OOC WP if (_OOCReached)//reached OOC WP
{ {
_OOCReached = false;
RemoveEscortState(SmartEscortState.Returning); RemoveEscortState(SmartEscortState.Returning);
if (!HasEscortState(SmartEscortState.Paused)) if (!HasEscortState(SmartEscortState.Paused))
ResumePath(); ResumePath();
mWPReached = false;
}
}
if ((!me.HasReactState(ReactStates.Passive) && me.IsInCombat()) || HasEscortState(SmartEscortState.Paused | SmartEscortState.Returning))
return;
// handle next wp
if (mWPReached)//reached WP
{
mWPReached = false;
if (mCurrentWPID == GetWPCount())
{
EndPath();
}
else
{
WayPoint wp = GetNextWayPoint();
if (wp != null)
{
SetRun(mRun);
me.GetMotionMaster().MovePoint(wp.Id, wp.X, wp.Y, wp.Z);
}
} }
} }
} }
@@ -372,7 +330,21 @@ namespace Game.AI
UpdatePath(diff); UpdatePath(diff);
UpdateDespawn(diff); UpdateDespawn(diff);
UpdateFollow(diff); if (!mFollowGuid.IsEmpty())
{
if (mFollowArrivedTimer < diff)
{
if (me.FindNearestCreature(mFollowArrivedEntry, SharedConst.InteractionDistance, true))
{
StopFollow(true);
return;
}
mFollowArrivedTimer = 1000;
}
else
mFollowArrivedTimer -= diff;
}
if (!IsAIControlled()) if (!IsAIControlled())
return; return;
@@ -427,25 +399,44 @@ namespace Game.AI
return true; return true;
} }
void MovepointReached(uint id) public override void WaypointStarted(uint nodeId, uint pathId)
{ {
if (id != EventId.SmartEscortLastOCCPoint && mLastWPIDReached != id)
GetScript().ProcessEventsFor(SmartEvents.WaypointReached, null, id);
mLastWPIDReached = id;
mWPReached = true;
} }
public override void MovementInform(MovementGeneratorType MovementType, uint Data) public override void WaypointReached(uint nodeId, uint pathId)
{ {
if ((MovementType == MovementGeneratorType.Point && Data == EventId.SmartEscortLastOCCPoint) || MovementType == MovementGeneratorType.Follow) _currentWaypointNode = nodeId;
GetScript().ProcessEventsFor(SmartEvents.WaypointReached, null, _currentWaypointNode, pathId);
if (_waypointPauseTimer != 0 && !_waypointPauseForced)
{
_waypointReached = true;
me.PauseMovement();
me.SetHomePosition(me.GetPosition());
}
else if (HasEscortState(SmartEscortState.Escorting) && me.GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Waypoint)
{
if (_currentWaypointNode == _path.nodes.Count)
_waypointPathEnded = true;
else
SetRun(mRun);
}
}
public override void MovementInform(MovementGeneratorType movementType, uint id)
{
if (movementType == MovementGeneratorType.Point && id == EventId.SmartEscortLastOCCPoint)
me.ClearUnitState(UnitState.Evade); me.ClearUnitState(UnitState.Evade);
GetScript().ProcessEventsFor(SmartEvents.Movementinform, null, (uint)MovementType, Data); GetScript().ProcessEventsFor(SmartEvents.Movementinform, null, (uint)movementType, id);
if (MovementType != MovementGeneratorType.Point || !HasEscortState(SmartEscortState.Escorting))
if (!HasEscortState(SmartEscortState.Escorting))
return; return;
MovepointReached(Data); if (movementType != MovementGeneratorType.Point && id == EventId.SmartEscortLastOCCPoint)
_OOCReached = true;
} }
public override void EnterEvadeMode(EvadeReason why = EvadeReason.Other) public override void EnterEvadeMode(EvadeReason why = EvadeReason.Other)
@@ -470,7 +461,6 @@ namespace Game.AI
GetScript().ProcessEventsFor(SmartEvents.Evade);//must be after aura clear so we can cast spells from db GetScript().ProcessEventsFor(SmartEvents.Evade);//must be after aura clear so we can cast spells from db
SetRun(mRun); SetRun(mRun);
if (HasEscortState(SmartEscortState.Escorting)) if (HasEscortState(SmartEscortState.Escorting))
{ {
AddEscortState(SmartEscortState.Returning); AddEscortState(SmartEscortState.Returning);
@@ -496,8 +486,8 @@ namespace Game.AI
me.GetMotionMaster().MoveTargetedHome(); me.GetMotionMaster().MoveTargetedHome();
} }
if (!HasEscortState(SmartEscortState.Escorting)) //dont mess up escort movement after combat if (!me.HasUnitState(UnitState.Evade))
SetRun(mRun); GetScript().OnReset();
} }
public override void MoveInLineOfSight(Unit who) public override void MoveInLineOfSight(Unit who)
@@ -510,7 +500,7 @@ namespace Game.AI
if (!IsAIControlled()) if (!IsAIControlled())
return; return;
if (AssistPlayerInCombatAgainst(who)) if (HasEscortState(SmartEscortState.Escorting) && AssistPlayerInCombatAgainst(who))
return; return;
base.MoveInLineOfSight(who); base.MoveInLineOfSight(who);
@@ -537,11 +527,24 @@ namespace Game.AI
if (who.GetVictim().GetCharmerOrOwnerPlayerOrPlayerItself() == null) if (who.GetVictim().GetCharmerOrOwnerPlayerOrPlayerItself() == null)
return false; return false;
//never attack friendly if (!who.IsInAccessiblePlaceFor(me))
return false;
if (!CanAIAttack(who))
return false;
// we cannot attack in evade mode
if (me.IsInEvadeMode())
return false;
// or if enemy is in evade mode
if (who.IsCreature() && who.ToCreature().IsInEvadeMode())
return false;
if (!me.IsValidAssistTarget(who.GetVictim())) if (!me.IsValidAssistTarget(who.GetVictim()))
return false; 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)) if (me.IsWithinDistInMap(who, SMART_MAX_AID_DIST) && me.IsWithinLOSInMap(who))
{ {
me.EngageWithTarget(who); me.EngageWithTarget(who);
@@ -556,7 +559,7 @@ namespace Game.AI
mDespawnTime = 0; mDespawnTime = 0;
mRespawnTime = 0; mRespawnTime = 0;
mDespawnState = 0; mDespawnState = 0;
mEscortState = SmartEscortState.None; _escortState = SmartEscortState.None;
me.SetVisible(true); me.SetVisible(true);
if (me.GetFaction() != me.GetCreatureTemplate().Faction) if (me.GetFaction() != me.GetCreatureTemplate().Faction)
me.RestoreFaction(); me.RestoreFaction();
@@ -579,9 +582,18 @@ namespace Game.AI
{ {
GetScript().ProcessEventsFor(SmartEvents.ReachedHome); GetScript().ProcessEventsFor(SmartEvents.ReachedHome);
if (!UpdateVictim() && me.GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Idle && me.GetWaypointPath() != 0) CreatureGroup formation = me.GetFormation();
me.GetMotionMaster().MovePath(me.GetWaypointPath(), true); 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
} }
mJustReset = false; mJustReset = false;
} }
@@ -591,25 +603,14 @@ namespace Game.AI
me.InterruptNonMeleeSpells(false); // must be before ProcessEvents me.InterruptNonMeleeSpells(false); // must be before ProcessEvents
GetScript().ProcessEventsFor(SmartEvents.Aggro, victim); GetScript().ProcessEventsFor(SmartEvents.Aggro, victim);
if (!IsAIControlled())
return;
mLastOOCPos = me.GetPosition();
SetRun(mRun);
if (me.GetMotionMaster().GetMotionSlotType(MovementSlot.Active) == MovementGeneratorType.Point)
me.GetMotionMaster().MovementExpired();
} }
public override void JustDied(Unit killer) public override void JustDied(Unit killer)
{ {
GetScript().ProcessEventsFor(SmartEvents.Death, killer);
if (HasEscortState(SmartEscortState.Escorting)) if (HasEscortState(SmartEscortState.Escorting))
{
EndPath(true); EndPath(true);
me.StopMoving();//force stop
me.GetMotionMaster().MoveIdle(); GetScript().ProcessEventsFor(SmartEvents.Death, killer);
}
} }
public override void KilledUnit(Unit victim) public override void KilledUnit(Unit victim)
@@ -627,26 +628,32 @@ namespace Game.AI
// dont allow charmed npcs to act on their own // dont allow charmed npcs to act on their own
if (!IsAIControlled()) if (!IsAIControlled())
{ {
if (who != null && mCanAutoAttack) if (who != null)
me.Attack(who, true); me.Attack(who, mCanAutoAttack);
return; return;
} }
if (who != null && me.Attack(who, me.IsWithinMeleeRange(who))) if (who != null && me.Attack(who, mCanAutoAttack))
{ {
me.GetMotionMaster().Clear(MovementSlot.Active);
me.PauseMovement();
if (mCanCombatMove) if (mCanCombatMove)
{
SetRun(mRun);
me.GetMotionMaster().MoveChase(who); me.GetMotionMaster().MoveChase(who);
}
} }
} }
public override void SpellHit(Unit caster, SpellInfo spell) public override void SpellHit(Unit caster, SpellInfo spellInfo)
{ {
GetScript().ProcessEventsFor(SmartEvents.SpellHit, caster, 0, 0, false, spell); GetScript().ProcessEventsFor(SmartEvents.SpellHit, caster, 0, 0, false, spellInfo);
} }
public override void SpellHitTarget(Unit target, SpellInfo spell) public override void SpellHitTarget(Unit target, SpellInfo spellInfo)
{ {
GetScript().ProcessEventsFor(SmartEvents.SpellHitTarget, target, 0, 0, false, spell); GetScript().ProcessEventsFor(SmartEvents.SpellHitTarget, target, 0, 0, false, spellInfo);
} }
public override void DamageTaken(Unit attacker, ref uint damage) public override void DamageTaken(Unit attacker, ref uint damage)
@@ -698,10 +705,10 @@ namespace Game.AI
public override void InitializeAI() public override void InitializeAI()
{ {
mScript.OnInitialize(me); mScript.OnInitialize(me);
if (!me.IsDead()) if (!me.IsDead())
{ {
mJustReset = true; GetScript().OnReset();
JustReachedHome();
GetScript().ProcessEventsFor(SmartEvents.Respawn); GetScript().ProcessEventsFor(SmartEvents.Respawn);
} }
} }
@@ -712,13 +719,13 @@ namespace Game.AI
{ {
if (HasEscortState(SmartEscortState.Escorting | SmartEscortState.Paused | SmartEscortState.Returning)) if (HasEscortState(SmartEscortState.Escorting | SmartEscortState.Paused | SmartEscortState.Returning))
EndPath(true); EndPath(true);
me.StopMoving();
} }
mIsCharmed = apply; mIsCharmed = apply;
if (!apply && !me.IsInEvadeMode()) if (!apply && !me.IsInEvadeMode())
{ {
if (mCanRepeatPath) if (_repeatWaypointPath)
StartPath(mRun, GetScript().GetPathId(), true); StartPath(mRun, GetScript().GetPathId(), true);
else else
me.SetWalk(!mRun); me.SetWalk(!mRun);
@@ -808,41 +815,25 @@ namespace Game.AI
GetScript().ProcessEventsFor(SmartEvents.RewardQuest, player, quest.Id, opt); GetScript().ProcessEventsFor(SmartEvents.RewardQuest, player, quest.Id, opt);
} }
public override void OnGameEvent(bool start, ushort eventId)
{
GetScript().ProcessEventsFor(start ? SmartEvents.GameEventStart : SmartEvents.GameEventEnd, null, eventId);
}
public void SetCombatMove(bool on) public void SetCombatMove(bool on)
{ {
if (mCanCombatMove == on) if (mCanCombatMove == on)
return; return;
mCanCombatMove = on; mCanCombatMove = on;
if (!IsAIControlled()) if (!IsAIControlled())
return; return;
if (!HasEscortState(SmartEscortState.Escorting)) if (me.IsEngaged())
{ {
if (on && me.GetVictim() != null) if (on && !me.HasReactState(ReactStates.Passive) && me.GetVictim() && me.GetMotionMaster().GetMotionSlotType(MovementSlot.Active) == MovementGeneratorType.Max)
{ {
if (me.GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Idle) SetRun(mRun);
{ me.GetMotionMaster().MoveChase(me.GetVictim());
SetRun(mRun);
me.GetMotionMaster().MoveChase(me.GetVictim());
me.CastStop();
}
}
else
{
if (me.HasUnitState(UnitState.ConfusedMove | UnitState.FleeingMove))
return;
me.GetMotionMaster().MovementExpired();
me.GetMotionMaster().Clear(true);
me.StopMoving();
me.GetMotionMaster().MoveIdle();
} }
else if (!on && me.GetMotionMaster().GetMotionSlotType(MovementSlot.Active) == MovementGeneratorType.Chase)
me.GetMotionMaster().Clear(MovementSlot.Active);
} }
} }
@@ -901,6 +892,11 @@ namespace Game.AI
GetScript().SetScript9(e, entry); GetScript().SetScript9(e, entry);
} }
public override void OnGameEvent(bool start, ushort eventId)
{
GetScript().ProcessEventsFor(start ? SmartEvents.GameEventStart : SmartEvents.GameEventEnd, null, eventId);
}
public override void OnSpellClick(Unit clicker, ref bool result) public override void OnSpellClick(Unit clicker, ref bool result)
{ {
if (!result) if (!result)
@@ -943,29 +939,18 @@ namespace Game.AI
mConditionsTimer -= diff; mConditionsTimer -= diff;
} }
public void UpdateFollow(uint diff) public override void Reset()
{ {
if (!mFollowGuid.IsEmpty()) if (!HasEscortState(SmartEscortState.Escorting))//dont mess up escort movement after combat
{ SetRun(mRun);
if (mFollowArrivedTimer < diff) GetScript().OnReset();
{
if (me.FindNearestCreature(mFollowArrivedEntry, SharedConst.InteractionDistance, true) != null)
{
StopFollow(true);
return;
}
mFollowArrivedTimer = 1000;
}
else
mFollowArrivedTimer -= diff;
}
} }
bool HasEscortState(SmartEscortState uiEscortState) { return mEscortState.HasAnyFlag(uiEscortState); } public bool HasEscortState(SmartEscortState uiEscortState) { return (_escortState & uiEscortState) != 0; }
void AddEscortState(SmartEscortState uiEscortState) { mEscortState |= uiEscortState; } public void AddEscortState(SmartEscortState uiEscortState) { _escortState |= uiEscortState; }
void RemoveEscortState(SmartEscortState uiEscortState) { mEscortState &= ~uiEscortState; } public void RemoveEscortState(SmartEscortState uiEscortState) { _escortState &= ~uiEscortState; }
public void SetAutoAttack(bool on) { mCanAutoAttack = on; } public void SetAutoAttack(bool on) { mCanAutoAttack = on; }
public bool CanCombatMove() { return mCanCombatMove; } public bool CanCombatMove() { return mCanCombatMove; }
public SmartScript GetScript() { return mScript; } public SmartScript GetScript() { return mScript; }
@@ -976,17 +961,19 @@ namespace Game.AI
{ {
mDespawnTime = t; mDespawnTime = t;
mRespawnTime = r; mRespawnTime = r;
mDespawnState = (uint)(t != 0 ? 1 : 0); mDespawnState = t != 0 ? 1 : 0u;
} }
public void StartDespawn() { mDespawnState = 2; } public void StartDespawn() { mDespawnState = 2; }
uint GetWPCount() { return (uint)mWayPoints?.Count; } public void SetWPPauseTimer(uint time) { _waypointPauseTimer = time; }
public void SetWPPauseTimer(uint time) { mWPPauseTimer = time; }
public void SetGossipReturn(bool val) { _gossipReturn = val; } public void SetGossipReturn(bool val) { _gossipReturn = val; }
public uint mEscortQuestID;
SmartScript mScript = new SmartScript();
bool mIsCharmed; bool mIsCharmed;
uint mFollowCreditType; uint mFollowCreditType;
uint mFollowArrivedTimer; uint mFollowArrivedTimer;
@@ -996,31 +983,27 @@ namespace Game.AI
float mFollowDist; float mFollowDist;
float mFollowAngle; float mFollowAngle;
SmartScript mScript = new SmartScript(); SmartEscortState _escortState;
List<WayPoint> mWayPoints; uint _escortNPCFlags;
SmartEscortState mEscortState; uint _escortInvokerCheckTimer;
uint mCurrentWPID; WaypointPath _path;
uint mLastWPIDReached; uint _currentWaypointNode;
bool mWPReached; bool _waypointReached;
uint mWPPauseTimer; uint _waypointPauseTimer;
uint mEscortNPCFlags; bool _waypointPauseForced;
WayPoint mLastWP; bool _repeatWaypointPath;
Position mLastOOCPos;//set on enter combat bool _OOCReached;
bool mCanRepeatPath; bool _waypointPathEnded;
bool mRun; bool mRun;
bool mEvadeDisabled; bool mEvadeDisabled;
bool mCanAutoAttack; bool mCanAutoAttack;
bool mCanCombatMove; bool mCanCombatMove;
bool mForcedPaused;
uint mInvincibilityHpLevel; uint mInvincibilityHpLevel;
uint mDespawnTime; uint mDespawnTime;
uint mRespawnTime; uint mRespawnTime;
uint mDespawnState; uint mDespawnState;
public uint mEscortQuestID;
uint mEscortInvokerCheckTimer;
bool mJustReset; bool mJustReset;
// Vehicle conditions // Vehicle conditions
+29 -36
View File
@@ -22,6 +22,7 @@ using Game.Entities;
using Game.Spells; using Game.Spells;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Game.AI namespace Game.AI
@@ -296,11 +297,12 @@ namespace Game.AI
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} SmartAI scripts in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); Log.outInfo(LogFilter.ServerLoading, "Loaded {0} SmartAI scripts in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime));
} }
public void LoadWaypointFromDB() public void LoadWaypointFromDB()
{ {
uint oldMSTime = Time.GetMSTime(); uint oldMSTime = Time.GetMSTime();
waypoint_map.Clear(); _waypointStore.Clear();
PreparedStatement stmt = DB.World.GetPreparedStatement(WorldStatements.SEL_SMARTAI_WP); PreparedStatement stmt = DB.World.GetPreparedStatement(WorldStatements.SEL_SMARTAI_WP);
SQLResult result = DB.World.Query(stmt); SQLResult result = DB.World.Query(stmt);
@@ -314,8 +316,8 @@ namespace Game.AI
uint count = 0; uint count = 0;
uint total = 0; uint total = 0;
uint last_entry = 0; uint lastEntry = 0;
uint last_id = 1; uint lastId = 1;
do do
{ {
@@ -325,25 +327,30 @@ namespace Game.AI
float y = result.Read<float>(3); float y = result.Read<float>(3);
float z = result.Read<float>(4); float z = result.Read<float>(4);
if (last_entry != entry) if (lastEntry != entry)
{ {
last_id = 1; lastId = 1;
count++; ++count;
} }
if (last_id != id) if (lastId != id)
Log.outError(LogFilter.Sql, "SmartWaypointMgr.LoadFromDB: Path entry {0}, unexpected point id {1}, expected {2}.", entry, id, last_id); Log.outError(LogFilter.Sql, $"SmartWaypointMgr.LoadFromDB: Path entry {entry}, unexpected point id {id}, expected {lastId}.");
last_id++; ++lastId;
waypoint_map.Add(entry, new WayPoint(id, x, y, z)); if (!_waypointStore.ContainsKey(entry))
_waypointStore[entry] = new WaypointPath();
last_entry = entry; WaypointPath path = _waypointStore[entry];
total++; path.id = entry;
path.nodes.Add(new WaypointNode(id, x, y, z));
lastEntry = entry;
++total;
} }
while (result.NextRow()); while (result.NextRow());
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} SmartAI waypoint paths (total {1} waypoints) in {2} ms", count, total, Time.GetMSTimeDiffToNow(oldMSTime)); Log.outInfo(LogFilter.ServerLoading, $"Loaded {count} SmartAI waypoint paths (total {total} waypoints) in {Time.GetMSTimeDiffToNow(oldMSTime)} ms");
} }
bool IsTargetValid(SmartScriptHolder e) bool IsTargetValid(SmartScriptHolder e)
@@ -1110,17 +1117,19 @@ namespace Game.AI
break; break;
case SmartActions.WpStart: case SmartActions.WpStart:
{ {
List<WayPoint> path = Global.SmartAIMgr.GetPath(e.Action.wpStart.pathID); WaypointPath path = GetPath(e.Action.wpStart.pathID);
if (path.Empty()) if (path == null || path.nodes.Empty())
{ {
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Creature {0} Event {1} Action {2} uses non-existent WaypointPath id {3}, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.Action.wpStart.pathID); Log.outError(LogFilter.ScriptsAi, $"SmartAIMgr: {e} uses non-existent WaypointPath id {e.Action.wpStart.pathID}, skipped.");
return false; return false;
} }
if (e.Action.wpStart.quest != 0 && !IsQuestValid(e, e.Action.wpStart.quest)) if (e.Action.wpStart.quest != 0 && !IsQuestValid(e, e.Action.wpStart.quest))
return false; return false;
if (e.Action.wpStart.reactState > (uint)ReactStates.Aggressive) if (e.Action.wpStart.reactState > (uint)ReactStates.Aggressive)
{ {
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Creature {0} Event {1} Action {2} uses invalid React State {3}, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.Action.wpStart.reactState); Log.outError(LogFilter.ScriptsAi, $"SmartAIMgr: {e} uses invalid React State {e.Action.wpStart.reactState}, skipped.");
return false; return false;
} }
break; break;
@@ -1558,9 +1567,9 @@ namespace Game.AI
return temp; return temp;
} }
public List<WayPoint> GetPath(uint id) public WaypointPath GetPath(uint id)
{ {
return waypoint_map.LookupByKey(id); return _waypointStore.LookupByKey(id);
} }
public SmartScriptHolder FindLinkedSourceEvent(List<SmartScriptHolder> list, uint eventId) public SmartScriptHolder FindLinkedSourceEvent(List<SmartScriptHolder> list, uint eventId)
@@ -1582,7 +1591,7 @@ namespace Game.AI
} }
MultiMap<int, SmartScriptHolder>[] mEventMap = new MultiMap<int, SmartScriptHolder>[(int)SmartScriptType.Max]; MultiMap<int, SmartScriptHolder>[] mEventMap = new MultiMap<int, SmartScriptHolder>[(int)SmartScriptType.Max];
MultiMap<uint, WayPoint> waypoint_map = new MultiMap<uint, WayPoint>(); Dictionary<uint, WaypointPath> _waypointStore = new Dictionary<uint, WaypointPath>();
Dictionary<SmartScriptType, uint> SmartAITypeMask = new Dictionary<SmartScriptType, uint> Dictionary<SmartScriptType, uint> SmartAITypeMask = new Dictionary<SmartScriptType, uint>
{ {
@@ -1688,22 +1697,6 @@ namespace Game.AI
}; };
} }
public class WayPoint
{
public WayPoint(uint id, float x, float y, float z)
{
Id = id;
X = x;
Y = y;
Z = z;
}
public uint Id;
public float X;
public float Y;
public float Z;
}
public class SmartScriptHolder public class SmartScriptHolder
{ {
public SmartScriptHolder() { } public SmartScriptHolder() { }
+11 -10
View File
@@ -1988,7 +1988,8 @@ namespace Game.AI
waypoints.Add(id); waypoints.Add(id);
float distanceToClosest = float.MaxValue; float distanceToClosest = float.MaxValue;
WayPoint closestWp = null; uint closestPathId = 0;
uint closestWaypointId = 0;
foreach (var target in targets) foreach (var target in targets)
{ {
@@ -1997,26 +1998,26 @@ namespace Game.AI
{ {
if (IsSmart(creature)) if (IsSmart(creature))
{ {
foreach (uint wpId in waypoints) foreach (uint pathId in waypoints)
{ {
var path = Global.SmartAIMgr.GetPath(wpId); WaypointPath path = Global.SmartAIMgr.GetPath(pathId);
if (path == null || path.Empty()) if (path == null || path.nodes.Empty())
continue; continue;
WayPoint wp = path[0]; foreach (var waypoint in path.nodes)
if (wp != null)
{ {
float distToThisPath = creature.GetDistance(wp.X, wp.Y, wp.Z); float distToThisPath = creature.GetDistance(waypoint.x, waypoint.y, waypoint.z);
if (distToThisPath < distanceToClosest) if (distToThisPath < distanceToClosest)
{ {
distanceToClosest = distToThisPath; distanceToClosest = distToThisPath;
closestWp = wp; closestPathId = pathId;
closestWaypointId = waypoint.id;
} }
} }
} }
if (closestWp != null) if (closestPathId != 0)
((SmartAI)creature.GetAI()).StartPath(false, closestWp.Id, true); ((SmartAI)creature.GetAI()).StartPath(false, closestPathId, true, null, closestWaypointId);
} }
} }
} }
+42
View File
@@ -105,6 +105,21 @@ namespace Game.Entities
ForcedDespawn(0); ForcedDespawn(0);
} }
public override void PauseMovement(uint timer = 0, MovementSlot slot = 0)
{
base.PauseMovement(timer, slot);
SetHomePosition(GetPosition());
}
public bool IsReturningHome()
{
if (GetMotionMaster().GetMotionSlotType(MovementSlot.Active) == MovementGeneratorType.Home)
return true;
return false;
}
public void SearchFormation() public void SearchFormation()
{ {
if (IsSummon()) if (IsSummon())
@@ -119,6 +134,33 @@ namespace Game.Entities
FormationMgr.AddCreatureToGroup(frmdata.leaderGUID, this); FormationMgr.AddCreatureToGroup(frmdata.leaderGUID, this);
} }
public bool IsFormationLeader()
{
if (m_formation == null)
return false;
return m_formation.IsLeader(this);
}
public void SignalFormationMovement(Position destination, uint id = 0, WaypointMoveType moveType = 0, bool orientation = false)
{
if (m_formation == null)
return;
if (!m_formation.IsLeader(this))
return;
m_formation.LeaderMoveTo(destination, id, moveType, orientation);
}
public bool IsFormationLeaderMoveAllowed()
{
if (m_formation == null)
return false;
return m_formation.CanLeaderStartMoving();
}
public void RemoveCorpse(bool setSpawnTime = true, bool destroyForNearbyPlayers = true) public void RemoveCorpse(bool setSpawnTime = true, bool destroyForNearbyPlayers = true)
{ {
if (GetDeathState() != DeathState.Corpse) if (GetDeathState() != DeathState.Corpse)
@@ -216,7 +216,7 @@ namespace Game.Entities
m_Formed = !dismiss; m_Formed = !dismiss;
} }
public void LeaderMoveTo(Position destination, uint id = 0, uint moveType = 0, bool orientation = false) public void LeaderMoveTo(Position destination, uint id = 0, WaypointMoveType moveType = 0, bool orientation = false)
{ {
//! To do: This should probably get its own movement generator or use WaypointMovementGenerator. //! To do: This should probably get its own movement generator or use WaypointMovementGenerator.
//! If the leader's path is known, member's path can be plotted as well using formation offsets. //! If the leader's path is known, member's path can be plotted as well using formation offsets.
@@ -258,11 +258,26 @@ namespace Game.Entities
} }
} }
public bool CanLeaderStartMoving()
{
foreach (var itr in m_members)
{
if (itr.Key != m_leader && itr.Key.IsAlive())
{
if (itr.Key.IsEngaged() || itr.Key.IsReturningHome())
return false;
}
}
return true;
}
public Creature GetLeader() { return m_leader; } public Creature GetLeader() { return m_leader; }
public uint GetId() { return m_groupID; } public uint GetId() { return m_groupID; }
public bool IsEmpty() { return m_members.Empty(); } public bool IsEmpty() { return m_members.Empty(); }
public bool IsFormed() { return m_Formed; } public bool IsFormed() { return m_Formed; }
public bool IsLeader(Creature creature) { return m_leader == creature; }
Creature m_leader; Creature m_leader;
Dictionary<Creature, FormationInfo> m_members = new Dictionary<Creature, FormationInfo>(); Dictionary<Creature, FormationInfo> m_members = new Dictionary<Creature, FormationInfo>();
@@ -159,6 +159,28 @@ namespace Game.Entities
init.Stop(); init.Stop();
} }
public virtual void PauseMovement(uint timer = 0, MovementSlot slot = 0)
{
if (slot >= MovementSlot.Max)
return;
IMovementGenerator movementGenerator = GetMotionMaster().GetMotionSlot(slot);
if (movementGenerator != null)
movementGenerator.Pause(timer);
StopMoving();
}
public void ResumeMovement(uint timer = 0, MovementSlot slot = 0)
{
if (slot >= MovementSlot.Max)
return;
IMovementGenerator movementGenerator = GetMotionMaster().GetMotionSlot(slot);
if (movementGenerator != null)
movementGenerator.Resume(timer);
}
public void SetInFront(WorldObject target) public void SetInFront(WorldObject target)
{ {
if (!HasUnitState(UnitState.CannotTurn)) if (!HasUnitState(UnitState.CannotTurn))
+10 -1
View File
@@ -17,6 +17,7 @@
using Framework.Constants; using Framework.Constants;
using Game.AI; using Game.AI;
using Game.Movement;
using Game.Networking.Packets; using Game.Networking.Packets;
using Game.Spells; using Game.Spells;
using System.Collections.Generic; using System.Collections.Generic;
@@ -351,8 +352,15 @@ namespace Game.Entities
if (IsTypeId(TypeId.Unit)) if (IsTypeId(TypeId.Unit))
{ {
IMovementGenerator movementGenerator = GetMotionMaster().GetMotionSlot(MovementSlot.Idle);
if (movementGenerator != null)
movementGenerator.Pause(0);
GetMotionMaster().Clear(MovementSlot.Active);
StopMoving();
ToCreature().GetAI().OnCharmed(true); ToCreature().GetAI().OnCharmed(true);
GetMotionMaster().MoveIdle();
} }
else else
{ {
@@ -466,6 +474,7 @@ namespace Game.Entities
else else
RestoreFaction(); RestoreFaction();
///@todo Handle SLOT_IDLE motion resume
GetMotionMaster().InitDefault(); GetMotionMaster().InitDefault();
Creature creature = ToCreature(); Creature creature = ToCreature();
+1 -1
View File
@@ -39,7 +39,7 @@ namespace Game
return; return;
// Stop the npc if moving // Stop the npc if moving
unit.StopMoving(); unit.PauseMovement(WorldConfig.GetUIntValue(WorldCfg.CreatureStopForPlayer));
BattlegroundTypeId bgTypeId = Global.BattlegroundMgr.GetBattleMasterBG(unit.GetEntry()); BattlegroundTypeId bgTypeId = Global.BattlegroundMgr.GetBattleMasterBG(unit.GetEntry());
+2 -2
View File
@@ -340,8 +340,8 @@ namespace Game
if (!seamlessTeleport) if (!seamlessTeleport)
{ {
// short preparations to continue flight // short preparations to continue flight
FlightPathMovementGenerator flight = (FlightPathMovementGenerator)GetPlayer().GetMotionMaster().Top(); IMovementGenerator movementGenerator = GetPlayer().GetMotionMaster().Top();
flight.Initialize(GetPlayer()); movementGenerator.Initialize(GetPlayer());
} }
return; return;
} }
+3 -5
View File
@@ -143,9 +143,8 @@ namespace Game
GetPlayer().RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Talk); GetPlayer().RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Talk);
// and if he has pure gossip or is banker and moves or is tabard designer? // Stop the npc if moving
//if (unit->IsArmorer() || unit->IsCivilian() || unit->IsQuestGiver() || unit->IsServiceProvider() || unit->IsGuard()) unit.PauseMovement(WorldConfig.GetUIntValue(WorldCfg.CreatureStopForPlayer));
unit.StopMoving();
// If spiritguide, no need for gossip menu, just put player into resurrect queue // If spiritguide, no need for gossip menu, just put player into resurrect queue
if (unit.IsSpiritGuide()) if (unit.IsSpiritGuide())
@@ -464,8 +463,7 @@ namespace Game
GetPlayer().RemoveAurasByType(AuraType.FeignDeath); GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
// Stop the npc if moving // Stop the npc if moving
if (vendor.HasUnitState(UnitState.Moving)) vendor.PauseMovement(WorldConfig.GetUIntValue(WorldCfg.CreatureStopForPlayer));
vendor.StopMoving();
VendorItemData vendorItems = vendor.GetVendorItems(); VendorItemData vendorItems = vendor.GetVendorItems();
int rawItemCount = vendorItems != null ? vendorItems.GetItemCount() : 0; int rawItemCount = vendorItems != null ? vendorItems.GetItemCount() : 0;
+2 -1
View File
@@ -71,8 +71,9 @@ namespace Game
// remove fake death // remove fake death
if (GetPlayer().HasUnitState(UnitState.Died)) if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath); GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
// Stop the npc if moving // Stop the npc if moving
creature.StopMoving(); creature.PauseMovement(WorldConfig.GetUIntValue(WorldCfg.CreatureStopForPlayer));
_player.PlayerTalkClass.ClearMenus(); _player.PlayerTalkClass.ClearMenus();
if (creature.GetAI().GossipHello(_player)) if (creature.GetAI().GossipHello(_player))
+1 -2
View File
@@ -130,8 +130,7 @@ namespace Game
if (GetPlayer().HasUnitState(UnitState.Died)) if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath); GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
while (GetPlayer().GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Flight) GetPlayer().GetMotionMaster().Clear(MovementSlot.Controlled);
GetPlayer().GetMotionMaster().MovementExpired(false);
if (mountDisplayId != 0) if (mountDisplayId != 0)
GetPlayer().Mount(mountDisplayId); GetPlayer().Mount(mountDisplayId);
@@ -22,7 +22,7 @@ namespace Game.Movement
{ {
public class FormationMovementGenerator : MovementGeneratorMedium<Creature> public class FormationMovementGenerator : MovementGeneratorMedium<Creature>
{ {
public FormationMovementGenerator(uint id, Position destination, uint moveType, bool run, bool orientation) public FormationMovementGenerator(uint id, Position destination, WaypointMoveType moveType, bool run, bool orientation)
{ {
_movementId = id; _movementId = id;
_destination = destination; _destination = destination;
@@ -51,16 +51,16 @@ namespace Game.Movement
switch (_moveType) switch (_moveType)
{ {
case 2: // WAYPOINT_MOVE_TYPE_LAND case WaypointMoveType.Land:
init.SetAnimation(AnimType.ToGround); init.SetAnimation(AnimType.ToGround);
break; break;
case 3: // WAYPOINT_MOVE_TYPE_TAKEOFF case WaypointMoveType.Takeoff:
init.SetAnimation(AnimType.ToFly); init.SetAnimation(AnimType.ToFly);
break; break;
case 1: // WAYPOINT_MOVE_TYPE_RUN case WaypointMoveType.Run:
init.SetWalk(false); init.SetWalk(false);
break; break;
case 0: // WAYPOINT_MOVE_TYPE_WALK case WaypointMoveType.Walk:
init.SetWalk(true); init.SetWalk(true);
break; break;
} }
@@ -103,16 +103,16 @@ namespace Game.Movement
switch (_moveType) switch (_moveType)
{ {
case 2: // WAYPOINT_MOVE_TYPE_LAND case WaypointMoveType.Land:
init.SetAnimation(AnimType.ToGround); init.SetAnimation(AnimType.ToGround);
break; break;
case 3: // WAYPOINT_MOVE_TYPE_TAKEOFF case WaypointMoveType.Takeoff:
init.SetAnimation(AnimType.ToFly); init.SetAnimation(AnimType.ToFly);
break; break;
case 1: // WAYPOINT_MOVE_TYPE_RUN case WaypointMoveType.Run:
init.SetWalk(false); init.SetWalk(false);
break; break;
case 0: // WAYPOINT_MOVE_TYPE_WALK case WaypointMoveType.Walk:
init.SetWalk(true); init.SetWalk(true);
break; break;
} }
@@ -151,7 +151,7 @@ namespace Game.Movement
uint _movementId; uint _movementId;
Position _destination; Position _destination;
uint _moveType; WaypointMoveType _moveType;
bool _run; bool _run;
bool _orientation; bool _orientation;
bool _recalculateSpeed; bool _recalculateSpeed;
@@ -34,7 +34,11 @@ namespace Game.Movement
public abstract MovementGeneratorType GetMovementGeneratorType(); public abstract MovementGeneratorType GetMovementGeneratorType();
public virtual void UnitSpeedChanged() { } public virtual void UnitSpeedChanged() { }
public virtual void Pause(uint timer = 0) { }
public virtual void Resume(uint overrideTimer = 0) { }
// used by Evade code for select point to evade with expected restart default movement // used by Evade code for select point to evade with expected restart default movement
public virtual bool GetResetPosition(Unit u, out float x, out float y, out float z) public virtual bool GetResetPosition(Unit u, out float x, out float y, out float z)
{ {
@@ -68,8 +68,7 @@ namespace Game.Movement
// Call for creature group update // Call for creature group update
Creature creature = owner.ToCreature(); Creature creature = owner.ToCreature();
if (creature != null) if (creature != null)
if (creature.GetFormation() != null && creature.GetFormation().GetLeader() == creature) creature.SignalFormationMovement(_destination, _movementId);
creature.GetFormation().LeaderMoveTo(_destination, _movementId);
} }
public override void DoReset(T owner) public override void DoReset(T owner)
@@ -109,8 +108,7 @@ namespace Game.Movement
// Call for creature group update // Call for creature group update
Creature creature = owner.ToCreature(); Creature creature = owner.ToCreature();
if (creature != null) if (creature != null)
if (creature.GetFormation() != null && creature.GetFormation().GetLeader() == creature) creature.SignalFormationMovement(_destination, _movementId);
creature.GetFormation().LeaderMoveTo(_destination, _movementId);
} }
return !owner.MoveSpline.Finalized(); return !owner.MoveSpline.Finalized();
@@ -117,8 +117,7 @@ namespace Game.Movement
_timer.Reset(traveltime + resetTimer); _timer.Reset(traveltime + resetTimer);
// Call for creature group update // Call for creature group update
if (owner.GetFormation() != null && owner.GetFormation().GetLeader() == owner) owner.SignalFormationMovement(position);
owner.GetFormation().LeaderMoveTo(position);
} }
public override MovementGeneratorType GetMovementGeneratorType() public override MovementGeneratorType GetMovementGeneratorType()
@@ -28,21 +28,45 @@ namespace Game.Movement
{ {
public class WaypointMovementGenerator : MovementGeneratorMedium<Creature> public class WaypointMovementGenerator : MovementGeneratorMedium<Creature>
{ {
const int FLIGHT_TRAVEL_UPDATE = 100; public WaypointMovementGenerator(uint pathId = 0, bool repeating = true)
const int TIMEDIFF_NEXT_WP = 250;
public WaypointMovementGenerator(uint pathid = 0, bool _repeating = true)
{ {
nextMoveTime = new TimeTrackerSmall(0); _nextMoveTime = new TimeTrackerSmall(0);
isArrivalDone = false; _pathId = pathId;
pathId = pathid; _repeating = repeating;
repeating = _repeating; _loadedFromDB = true;
} }
public override void DoReset(Creature creature) public WaypointMovementGenerator(WaypointPath path, bool repeating = true)
{ {
creature.AddUnitState(UnitState.Roaming | UnitState.RoamingMove); _nextMoveTime = new TimeTrackerSmall(0);
StartMoveNow(creature); _repeating = repeating;
_path = path;
}
void LoadPath(Creature creature)
{
if (_loadedFromDB)
{
if (_pathId == 0)
_pathId = creature.GetWaypointPath();
_path = Global.WaypointMgr.GetPath(_pathId);
}
if (_path == null)
{
// No path id found for entry
Log.outError(LogFilter.Sql, $"WaypointMovementGenerator.LoadPath: creature {creature.GetName()} ({creature.GetGUID()} DB GUID: {creature.GetSpawnId()}) doesn't have waypoint path id: {_pathId}");
return;
}
_nextMoveTime.Reset(1000);
}
public override void DoInitialize(Creature creature)
{
_done = false;
LoadPath(creature);
} }
public override void DoFinalize(Creature creature) public override void DoFinalize(Creature creature)
@@ -51,110 +75,75 @@ namespace Game.Movement
creature.SetWalk(false); creature.SetWalk(false);
} }
public override void DoInitialize(Creature creature) public override void DoReset(Creature creature)
{ {
LoadPath(creature); if (!_done && CanMove(creature))
creature.AddUnitState(UnitState.Roaming | UnitState.RoamingMove); StartMoveNow(creature);
else if (_done)
{
// mimic IdleMovementGenerator
if (!creature.IsStopped())
creature.StopMoving();
}
} }
public override bool DoUpdate(Creature creature, uint time_diff) void OnArrived(Creature creature)
{ {
// Waypoint movement can be switched on/off if (_path == null || _path.nodes.Empty())
// This is quite handy for escort quests and other stuff return;
if (creature.HasUnitState(UnitState.NotMove))
WaypointNode waypoint = _path.nodes.ElementAt((int)_currentNode);
if (waypoint.delay != 0)
{ {
creature.ClearUnitState(UnitState.RoamingMove); creature.ClearUnitState(UnitState.RoamingMove);
return true; _nextMoveTime.Reset((int)waypoint.delay);
} }
// prevent a crash at empty waypoint path. if (waypoint.eventId != 0 && RandomHelper.URand(0, 99) < waypoint.eventChance)
if (path == null || path.Empty())
return false;
if (Stopped())
{ {
if (CanMove((int)time_diff)) Log.outDebug(LogFilter.MapsScript, $"Creature movement start script {waypoint.eventId} at point {_currentNode} for {creature.GetGUID()}.");
return StartMove(creature); creature.ClearUnitState(UnitState.RoamingMove);
} creature.GetMap().ScriptsStart(ScriptsType.Waypoint, waypoint.eventId, creature, null);
else
{
// Set home position at place on waypoint movement.
if (creature.GetTransGUID().IsEmpty())
creature.SetHomePosition(creature.GetPosition());
if (creature.IsStopped())
Stop(WorldConfig.GetIntValue(WorldCfg.CreatureStopForPlayer));
else if (creature.MoveSpline.Finalized())
{
OnArrived(creature);
return StartMove(creature);
}
} }
return true; // inform AI
}
void MovementInform(Creature creature)
{
if (creature.IsAIEnabled) if (creature.IsAIEnabled)
creature.GetAI().MovementInform(MovementGeneratorType.Waypoint, currentNode); {
} creature.GetAI().MovementInform(MovementGeneratorType.Waypoint, (uint)_currentNode);
public override bool GetResetPosition(Unit u, out float x, out float y, out float z) 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);
x = y = z = 0; }
// prevent a crash at empty waypoint path.
if (path == null || path.Empty())
return false;
var node = path.LookupByIndex((int)currentNode); creature.UpdateWaypointID((uint)_currentNode);
x = node.x;
y = node.y;
z = node.z;
return true;
}
void Stop(int time)
{
nextMoveTime.Reset(time);
}
bool Stopped()
{
return !nextMoveTime.Passed();
}
bool CanMove(int diff)
{
nextMoveTime.Update(diff);
return nextMoveTime.Passed();
}
void StartMoveNow(Creature creature)
{
nextMoveTime.Reset(0);
StartMove(creature);
} }
bool StartMove(Creature creature) bool StartMove(Creature creature)
{ {
if (path == null || path.Empty()) if (!creature || !creature.IsAlive())
return false;
if (Stopped())
return true; return true;
if (_done || _path == null || _path.nodes.Empty())
return true;
// if the owner is the leader of its formation, check members status
if (creature.IsFormationLeader() && !creature.IsFormationLeaderMoveAllowed())
{
_nextMoveTime.Reset(1000);
return true;
}
bool transportPath = creature.GetTransport() != null; bool transportPath = creature.GetTransport() != null;
if (isArrivalDone) if (_isArrivalDone)
{ {
if ((currentNode == path.Count - 1) && !repeating) // If that's our last waypoint if ((_currentNode == _path.nodes.Count - 1) && !_repeating) // If that's our last waypoint
{ {
WaypointData waypoint = path.LookupByIndex((int)currentNode); WaypointNode lastWaypoint = _path.nodes.ElementAt(_currentNode);
float x = waypoint.x; float x = lastWaypoint.x;
float y = waypoint.y; float y = lastWaypoint.y;
float z = waypoint.z; float z = lastWaypoint.z;
float o = creature.GetOrientation(); float o = creature.GetOrientation();
if (!transportPath) if (!transportPath)
@@ -173,21 +162,28 @@ namespace Game.Movement
transportPath = false; transportPath = false;
// else if (vehicle) - this should never happen, vehicle offsets are const // else if (vehicle) - this should never happen, vehicle offsets are const
} }
_done = true;
creature.GetMotionMaster().Initialize(); return true;
return false;
} }
currentNode = (uint)((currentNode + 1) % path.Count); _currentNode = (_currentNode + 1) % _path.nodes.Count;
// 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);
}
} }
var node = path.LookupByIndex((int)currentNode); 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);
isArrivalDone = false; _isArrivalDone = false;
_recalculateSpeed = false;
creature.AddUnitState(UnitState.RoamingMove); creature.AddUnitState(UnitState.RoamingMove);
Position formationDest = new Position(node.x, node.y, node.z, (node.orientation != 0 && node.delay != 0) ? node.orientation : 0.0f);
MoveSplineInit init = new MoveSplineInit(creature); MoveSplineInit init = new MoveSplineInit(creature);
//! If creature is on transport, we assume waypoints set in DB are already transport offsets //! If creature is on transport, we assume waypoints set in DB are already transport offsets
@@ -205,13 +201,13 @@ namespace Game.Movement
//! Do not use formationDest here, MoveTo requires transport offsets due to DisableTransportPathTransformations() call //! Do not use formationDest here, MoveTo requires transport offsets due to DisableTransportPathTransformations() call
//! but formationDest contains global coordinates //! but formationDest contains global coordinates
init.MoveTo(node.x, node.y, node.z); init.MoveTo(waypoint.x, waypoint.y, waypoint.z);
//! Accepts angles such as 0.00001 and -0.00001, 0 must be ignored, default value in waypoint table //! Accepts angles such as 0.00001 and -0.00001, 0 must be ignored, default value in waypoint table
if (node.orientation != 0 && node.delay != 0) if (waypoint.orientation != 0 && waypoint.delay != 0)
init.SetFacing(node.orientation); init.SetFacing(waypoint.orientation);
switch (node.moveType) switch (waypoint.moveType)
{ {
case WaypointMoveType.Land: case WaypointMoveType.Land:
init.SetAnimation(AnimType.ToGround); init.SetAnimation(AnimType.ToGround);
@@ -229,82 +225,146 @@ namespace Game.Movement
init.Launch(); init.Launch();
//Call for creature group update // inform formation
if (creature.GetFormation() != null && creature.GetFormation().GetLeader() == creature) creature.SignalFormationMovement(formationDest, waypoint.id, waypoint.moveType, (waypoint.orientation != 0 && waypoint.delay != 0) ? true : false);
creature.GetFormation().LeaderMoveTo(formationDest, node.id, (uint)node.moveType, (node.orientation != 0 && node.delay != 0) ? true : false);
return true; return true;
} }
void LoadPath(Creature creature) public override bool DoUpdate(Creature creature, uint diff)
{ {
if (pathId == 0) if (!creature || !creature.IsAlive())
pathId = creature.GetWaypointPath(); return true;
path = Global.WaypointMgr.GetPath(pathId); if (_done || _path == null || _path.nodes.Empty())
return true;
if (path == null) if (_stalled || creature.HasUnitState(UnitState.NotMove) || creature.IsMovementPreventedByCasting())
{ {
// No movement found for entry creature.StopMoving();
Log.outError(LogFilter.ScriptsAi, "WaypointMovementGenerator.LoadPath: creature {0} (Entry: {1} GUID: {2}) doesn't have waypoint path id: {3}", creature.GetName(), creature.GetEntry(), creature.GetGUID().ToString(), pathId); return true;
return;
} }
StartMoveNow(creature);
}
void OnArrived(Creature creature) if (!_nextMoveTime.Passed())
{
if (path == null || path.Empty())
return;
if (isArrivalDone)
return;
isArrivalDone = true;
var current = path.LookupByIndex((int)currentNode);
if (current.eventId != 0 && RandomHelper.URand(0, 99) < current.eventChance)
{ {
Log.outDebug(LogFilter.Unit, "Creature movement start script {0} at point {1} for {2}.", current.eventId, currentNode, creature.GetGUID()); _nextMoveTime.Update((int)diff);
creature.ClearUnitState(UnitState.RoamingMove); if (_nextMoveTime.Passed())
creature.GetMap().ScriptsStart(ScriptsType.Waypoint, current.eventId, creature, null); return StartMoveNow(creature);
}
else
{
// Set home position at place on waypoint movement.
if (creature.GetTransGUID().IsEmpty())
creature.SetHomePosition(creature.GetPosition());
if (creature.MoveSpline.Finalized())
{
OnArrived(creature);
_isArrivalDone = true;
if (_nextMoveTime.Passed())
return StartMove(creature);
}
else if (_recalculateSpeed)
{
if (_nextMoveTime.Passed())
StartMove(creature);
}
} }
// Inform script return true;
MovementInform(creature);
creature.UpdateWaypointID(currentNode);
if (current.delay != 0)
{
creature.ClearUnitState(UnitState.RoamingMove);
Stop((int)current.delay);
}
} }
public override MovementGeneratorType GetMovementGeneratorType() void MovementInform(Creature creature)
{ {
return MovementGeneratorType.Waypoint; if (creature.IsAIEnabled)
creature.GetAI().MovementInform(MovementGeneratorType.Waypoint, (uint)_currentNode);
} }
public uint GetCurrentNode() { return currentNode; } public override bool GetResetPosition(Unit u, out float x, out float y, out float z)
{
x = y = z = 0;
// prevent a crash at empty waypoint path.
// prevent a crash at empty waypoint path.
if (_path == null || _path.nodes.Empty())
return false;
TimeTrackerSmall nextMoveTime; WaypointNode waypoint = _path.nodes.ElementAt(_currentNode);
bool isArrivalDone; x = waypoint.x;
uint pathId; y = waypoint.y;
bool repeating; z = waypoint.z;
List<WaypointData> path; return true;
uint currentNode; }
public override void Pause(uint timer = 0)
{
_stalled = timer != 0 ? false : true;
_nextMoveTime.Reset(timer != 0 ? (int)timer : 1);
}
public override void Resume(uint overrideTimer = 0)
{
_stalled = false;
if (overrideTimer != 0)
_nextMoveTime.Reset((int)overrideTimer);
}
bool CanMove(Creature creature)
{
return _nextMoveTime.Passed() && !creature.HasUnitState(UnitState.NotMove) && !creature.IsMovementPreventedByCasting();
}
public override MovementGeneratorType GetMovementGeneratorType() { return MovementGeneratorType.Waypoint; }
public override void UnitSpeedChanged() { _recalculateSpeed = true; }
bool StartMoveNow(Creature creature)
{
_nextMoveTime.Reset(0);
return StartMove(creature);
}
TimeTrackerSmall _nextMoveTime;
bool _recalculateSpeed;
bool _isArrivalDone;
uint _pathId;
bool _repeating;
bool _loadedFromDB;
bool _stalled;
bool _done;
WaypointPath _path;
int _currentNode;
} }
public class FlightPathMovementGenerator : MovementGeneratorMedium<Player> public class FlightPathMovementGenerator : MovementGeneratorMedium<Player>
{ {
uint GetPathAtMapEnd()
{
if (_currentNode >= _path.Count)
return (uint)_path.Count;
uint curMapId = _path[_currentNode].ContinentID;
for (int i = _currentNode; i < _path.Count; ++i)
{
if (_path[i].ContinentID != curMapId)
return (uint)i;
}
return (uint)_path.Count;
}
bool IsNodeIncludedInShortenedPath(TaxiPathNodeRecord p1, TaxiPathNodeRecord p2)
{
return p1.ContinentID != p2.ContinentID || Math.Pow(p1.Loc.X - p2.Loc.X, 2) + Math.Pow(p1.Loc.Y - p2.Loc.Y, 2) > (40.0f * 40.0f);
}
public void LoadPath(Player player, uint startNode = 0) public void LoadPath(Player player, uint startNode = 0)
{ {
i_path.Clear(); _path.Clear();
i_currentNode = (int)startNode; _currentNode = (int)startNode;
_pointsForPathSwitch.Clear(); _pointsForPathSwitch.Clear();
var taxi = player.m_taxi.GetPath(); var taxi = player.m_taxi.GetPath();
float discount = player.GetReputationPriceDiscount(player.m_taxi.GetFlightMasterFactionTemplate()); float discount = player.GetReputationPriceDiscount(player.m_taxi.GetFlightMasterFactionTemplate());
@@ -324,24 +384,24 @@ namespace Game.Movement
bool passedPreviousSegmentProximityCheck = false; bool passedPreviousSegmentProximityCheck = false;
for (uint i = 0; i < nodes.Length; ++i) for (uint i = 0; i < nodes.Length; ++i)
{ {
if (passedPreviousSegmentProximityCheck || src == 0 || i_path.Empty() || IsNodeIncludedInShortenedPath(i_path.Last(), nodes[i])) if (passedPreviousSegmentProximityCheck || src == 0 || _path.Empty() || IsNodeIncludedInShortenedPath(_path.Last(), nodes[i]))
{ {
if ((src == 0 || (IsNodeIncludedInShortenedPath(start, nodes[i]) && i >= 2)) && if ((src == 0 || (IsNodeIncludedInShortenedPath(start, nodes[i]) && i >= 2)) &&
(dst == taxi.Count - 1 || (IsNodeIncludedInShortenedPath(end, nodes[i]) && i < nodes.Length - 1))) (dst == taxi.Count - 1 || (IsNodeIncludedInShortenedPath(end, nodes[i]) && i < nodes.Length - 1)))
{ {
passedPreviousSegmentProximityCheck = true; passedPreviousSegmentProximityCheck = true;
i_path.Add(nodes[i]); _path.Add(nodes[i]);
} }
} }
else else
{ {
i_path.RemoveAt(i_path.Count - 1); _path.RemoveAt(_path.Count - 1);
_pointsForPathSwitch[_pointsForPathSwitch.Count - 1].PathIndex -= 1; _pointsForPathSwitch[_pointsForPathSwitch.Count - 1].PathIndex -= 1;
} }
} }
} }
_pointsForPathSwitch.Add(new TaxiNodeChangeInfo((uint)(i_path.Count - 1), (long)Math.Ceiling(cost * discount))); _pointsForPathSwitch.Add(new TaxiNodeChangeInfo((uint)(_path.Count - 1), (long)Math.Ceiling(cost * discount)));
} }
} }
@@ -384,7 +444,7 @@ namespace Game.Movement
init.args.path = new Vector3[end]; init.args.path = new Vector3[end];
for (int i = (int)GetCurrentNode(); i != end; ++i) for (int i = (int)GetCurrentNode(); i != end; ++i)
{ {
Vector3 vertice = new Vector3(i_path[i].Loc.X, i_path[i].Loc.Y, i_path[i].Loc.Z); Vector3 vertice = new Vector3(_path[i].Loc.X, _path[i].Loc.Y, _path[i].Loc.Z);
init.args.path[i] = vertice; init.args.path[i] = vertice;
} }
init.SetFirstPointId((int)GetCurrentNode()); init.SetFirstPointId((int)GetCurrentNode());
@@ -399,13 +459,13 @@ namespace Game.Movement
public override bool DoUpdate(Player player, uint time_diff) public override bool DoUpdate(Player player, uint time_diff)
{ {
uint pointId = (uint)player.MoveSpline.CurrentPathIdx(); uint pointId = (uint)player.MoveSpline.CurrentPathIdx();
if (pointId > i_currentNode) if (pointId > _currentNode)
{ {
bool departureEvent = true; bool departureEvent = true;
do do
{ {
DoEventIfAny(player, i_path[i_currentNode], departureEvent); DoEventIfAny(player, _path[_currentNode], departureEvent);
while (!_pointsForPathSwitch.Empty() && _pointsForPathSwitch[0].PathIndex <= i_currentNode) while (!_pointsForPathSwitch.Empty() && _pointsForPathSwitch[0].PathIndex <= _currentNode)
{ {
_pointsForPathSwitch.RemoveAt(0); _pointsForPathSwitch.RemoveAt(0);
player.m_taxi.NextTaxiDestination(); player.m_taxi.NextTaxiDestination();
@@ -416,31 +476,31 @@ namespace Game.Movement
} }
} }
if (pointId == i_currentNode) if (pointId == _currentNode)
break; break;
if (i_currentNode == _preloadTargetNode) if (_currentNode == _preloadTargetNode)
PreloadEndGrid(); PreloadEndGrid();
i_currentNode += (departureEvent ? 1 : 0); _currentNode += (departureEvent ? 1 : 0);
departureEvent = !departureEvent; departureEvent = !departureEvent;
} }
while (true); while (true);
} }
return i_currentNode < (i_path.Count - 1); return _currentNode < (_path.Count - 1);
} }
public void SetCurrentNodeAfterTeleport() public void SetCurrentNodeAfterTeleport()
{ {
if (i_path.Empty() || i_currentNode >= i_path.Count) if (_path.Empty() || _currentNode >= _path.Count)
return; return;
uint map0 = i_path[i_currentNode].ContinentID; uint map0 = _path[_currentNode].ContinentID;
for (int i = i_currentNode + 1; i < i_path.Count; ++i) for (int i = _currentNode + 1; i < _path.Count; ++i)
{ {
if (i_path[i].ContinentID != map0) if (_path[i].ContinentID != map0)
{ {
i_currentNode = i; _currentNode = i;
return; return;
} }
} }
@@ -459,7 +519,7 @@ namespace Game.Movement
bool GetResetPos(Player player, out float x, out float y, out float z) bool GetResetPos(Player player, out float x, out float y, out float z)
{ {
TaxiPathNodeRecord node = i_path[i_currentNode]; TaxiPathNodeRecord node = _path[_currentNode];
x = node.Loc.X; x = node.Loc.X;
y = node.Loc.Y; y = node.Loc.Y;
z = node.Loc.Z; z = node.Loc.Z;
@@ -468,11 +528,11 @@ namespace Game.Movement
void InitEndGridInfo() void InitEndGridInfo()
{ {
int nodeCount = i_path.Count; //! Number of nodes in path. int nodeCount = _path.Count; //! Number of nodes in path.
_endMapId = i_path[nodeCount - 1].ContinentID; //! MapId of last node _endMapId = _path[nodeCount - 1].ContinentID; //! MapId of last node
_preloadTargetNode = (uint)nodeCount - 3; _preloadTargetNode = (uint)nodeCount - 3;
_endGridX = i_path[nodeCount - 1].Loc.X; _endGridX = _path[nodeCount - 1].Loc.X;
_endGridY = i_path[nodeCount - 1].Loc.Y; _endGridY = _path[nodeCount - 1].Loc.Y;
} }
void PreloadEndGrid() void PreloadEndGrid()
@@ -483,51 +543,30 @@ namespace Game.Movement
// Load the grid // Load the grid
if (endMap != null) if (endMap != null)
{ {
Log.outInfo(LogFilter.Server, "Preloading grid ({0}, {1}) for map {2} at node index {3}/{4}", _endGridX, _endGridY, _endMapId, _preloadTargetNode, i_path.Count - 1); Log.outInfo(LogFilter.Server, "Preloading grid ({0}, {1}) for map {2} at node index {3}/{4}", _endGridX, _endGridY, _endMapId, _preloadTargetNode, _path.Count - 1);
endMap.LoadGrid(_endGridX, _endGridY); endMap.LoadGrid(_endGridX, _endGridY);
} }
else else
Log.outInfo(LogFilter.Server, "Unable to determine map to preload flightmaster grid"); Log.outInfo(LogFilter.Server, "Unable to determine map to preload flightmaster grid");
} }
uint GetPathAtMapEnd()
{
if (i_currentNode >= i_path.Count)
return (uint)i_path.Count;
uint curMapId = i_path[i_currentNode].ContinentID;
for (int i = i_currentNode; i < i_path.Count; ++i)
{
if (i_path[i].ContinentID != curMapId)
return (uint)i;
}
return (uint)i_path.Count;
}
bool IsNodeIncludedInShortenedPath(TaxiPathNodeRecord p1, TaxiPathNodeRecord p2)
{
return p1.ContinentID != p2.ContinentID || Math.Pow(p1.Loc.X - p2.Loc.X, 2) + Math.Pow(p1.Loc.Y - p2.Loc.Y, 2) > (40.0f * 40.0f);
}
public override MovementGeneratorType GetMovementGeneratorType() { return MovementGeneratorType.Flight; } public override MovementGeneratorType GetMovementGeneratorType() { return MovementGeneratorType.Flight; }
public List<TaxiPathNodeRecord> GetPath() { return i_path; } public List<TaxiPathNodeRecord> GetPath() { return _path; }
bool HasArrived() { return (i_currentNode >= i_path.Count); } bool HasArrived() { return (_currentNode >= _path.Count); }
public void SkipCurrentNode() { ++i_currentNode; } public void SkipCurrentNode() { ++_currentNode; }
public uint GetCurrentNode() { return (uint)i_currentNode; }
public uint GetCurrentNode() { return (uint)_currentNode; }
float _endGridX; //! X coord of last node location float _endGridX; //! X coord of last node location
float _endGridY; //! Y coord of last node location float _endGridY; //! Y coord of last node location
uint _endMapId; //! map Id of last node location uint _endMapId; //! map Id of last node location
uint _preloadTargetNode; //! node index where preloading starts uint _preloadTargetNode; //! node index where preloading starts
int i_currentNode; List<TaxiPathNodeRecord> _path = new List<TaxiPathNodeRecord>();
List<TaxiPathNodeRecord> i_path = new List<TaxiPathNodeRecord>(); int _currentNode;
List<TaxiNodeChangeInfo> _pointsForPathSwitch = new List<TaxiNodeChangeInfo>(); //! node indexes and costs where TaxiPath changes List<TaxiNodeChangeInfo> _pointsForPathSwitch = new List<TaxiNodeChangeInfo>(); //! node indexes and costs where TaxiPath changes
class TaxiNodeChangeInfo class TaxiNodeChangeInfo
+10 -5
View File
@@ -102,7 +102,7 @@ namespace Game.Movement
DirectClean(reset); DirectClean(reset);
} }
void Clear(MovementSlot slot) public void Clear(MovementSlot slot)
{ {
if (Empty() || slot >= MovementSlot.Max) if (Empty() || slot >= MovementSlot.Max)
return; return;
@@ -593,12 +593,17 @@ namespace Game.Movement
StartMovement(new DistractMovementGenerator(timer), MovementSlot.Controlled); StartMovement(new DistractMovementGenerator(timer), MovementSlot.Controlled);
} }
public void MovePath(uint path_id, bool repeatable) public void MovePath(uint pathId, bool repeatable)
{ {
if (path_id == 0) if (pathId == 0)
return; return;
StartMovement(new WaypointMovementGenerator(path_id, repeatable), MovementSlot.Idle); StartMovement(new WaypointMovementGenerator(pathId, repeatable), MovementSlot.Idle);
}
public void MovePath(WaypointPath path, bool repeatable)
{
StartMovement(new WaypointMovementGenerator(path, repeatable), MovementSlot.Idle);
} }
void MoveRotate(uint time, RotateDirection direction) void MoveRotate(uint time, RotateDirection direction)
@@ -609,7 +614,7 @@ namespace Game.Movement
StartMovement(new RotateMovementGenerator(time, direction), MovementSlot.Active); StartMovement(new RotateMovementGenerator(time, direction), MovementSlot.Active);
} }
public void MoveFormation(uint id, Position destination, uint moveType, bool forceRun = false, bool forceOrientation = false) public void MoveFormation(uint id, Position destination, WaypointMoveType moveType, bool forceRun = false, bool forceOrientation = false)
{ {
if (_owner.GetTypeId() == TypeId.Unit) if (_owner.GetTypeId() == TypeId.Unit)
StartMovement(new FormationMovementGenerator(id, destination, moveType, forceRun, forceOrientation), MovementSlot.Active); StartMovement(new FormationMovementGenerator(id, destination, moveType, forceRun, forceOrientation), MovementSlot.Active);
+55 -37
View File
@@ -23,10 +23,7 @@ namespace Game
{ {
public sealed class WaypointManager : Singleton<WaypointManager> public sealed class WaypointManager : Singleton<WaypointManager>
{ {
WaypointManager() WaypointManager() { }
{
_waypointStore = new MultiMap<uint, WaypointData>();
}
public void Load() public void Load()
{ {
@@ -55,29 +52,35 @@ namespace Game
GridDefines.NormalizeMapCoord(ref x); GridDefines.NormalizeMapCoord(ref x);
GridDefines.NormalizeMapCoord(ref y); GridDefines.NormalizeMapCoord(ref y);
WaypointData wp = new WaypointData(); WaypointNode waypoint = new WaypointNode();
wp.id = result.Read<uint>(1); waypoint.id = result.Read<uint>(1);
wp.x = x; waypoint.x = x;
wp.y = y; waypoint.y = y;
wp.z = z; waypoint.z = z;
wp.orientation = o; waypoint.orientation = o;
wp.moveType = (WaypointMoveType)result.Read<uint>(6); waypoint.moveType = (WaypointMoveType)result.Read<uint>(6);
if (wp.moveType >= WaypointMoveType.Max) if (waypoint.moveType >= WaypointMoveType.Max)
{ {
Log.outError(LogFilter.Sql, "Waypoint {0} in waypoint_data has invalid move_type, ignoring", wp.id); Log.outError(LogFilter.Sql, $"Waypoint {waypoint.id} in waypoint_data has invalid move_type, ignoring");
continue; continue;
} }
wp.delay = result.Read<uint>(7); waypoint.delay = result.Read<uint>(7);
wp.eventId = result.Read<uint>(8); waypoint.eventId = result.Read<uint>(8);
wp.eventChance = result.Read<byte>(9); waypoint.eventChance = result.Read<byte>(9);
if (!_waypointStore.ContainsKey(pathId))
_waypointStore[pathId] = new WaypointPath();
WaypointPath path = _waypointStore[pathId];
path.id = pathId;
path.nodes.Add(waypoint);
_waypointStore.Add(pathId, wp);
++count; ++count;
} while (result.NextRow()); } while (result.NextRow());
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} waypoints in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); Log.outInfo(LogFilter.ServerLoading, $"Loaded {count} waypoints in {Time.GetMSTimeDiffToNow(oldMSTime)} ms");
} }
public void ReloadPath(uint id) public void ReloadPath(uint id)
@@ -91,6 +94,7 @@ namespace Game
if (result.IsEmpty()) if (result.IsEmpty())
return; return;
List<WaypointNode> values = new List<WaypointNode>();
do do
{ {
float x = result.Read<float>(1); float x = result.Read<float>(1);
@@ -101,42 +105,43 @@ namespace Game
GridDefines.NormalizeMapCoord(ref x); GridDefines.NormalizeMapCoord(ref x);
GridDefines.NormalizeMapCoord(ref y); GridDefines.NormalizeMapCoord(ref y);
WaypointData wp = new WaypointData(); WaypointNode waypoint = new WaypointNode();
wp.id = result.Read<uint>(0); waypoint.id = result.Read<uint>(0);
wp.x = x; waypoint.x = x;
wp.y = y; waypoint.y = y;
wp.z = z; waypoint.z = z;
wp.orientation = o; waypoint.orientation = o;
wp.moveType = (WaypointMoveType)result.Read<uint>(5); waypoint.moveType = (WaypointMoveType)result.Read<uint>(5);
if (wp.moveType >= WaypointMoveType.Max) if (waypoint.moveType >= WaypointMoveType.Max)
{ {
Log.outError(LogFilter.Sql, "Waypoint {0} in waypoint_data has invalid move_type, ignoring", wp.id); Log.outError(LogFilter.Sql, $"Waypoint {waypoint.id} in waypoint_data has invalid move_type, ignoring");
continue; continue;
} }
wp.delay = result.Read<uint>(6); waypoint.delay = result.Read<uint>(6);
wp.eventId = result.Read<uint>(7); waypoint.eventId = result.Read<uint>(7);
wp.eventChance = result.Read<byte>(8); waypoint.eventChance = result.Read<byte>(8);
_waypointStore.Add(id, wp);
values.Add(waypoint);
} }
while (result.NextRow()); while (result.NextRow());
_waypointStore[id] = new WaypointPath(id, values);
} }
public List<WaypointData> GetPath(uint id) public WaypointPath GetPath(uint id)
{ {
return _waypointStore.LookupByKey(id); return _waypointStore.LookupByKey(id);
} }
MultiMap<uint, WaypointData> _waypointStore; Dictionary<uint, WaypointPath> _waypointStore = new Dictionary<uint, WaypointPath>();
} }
public class WaypointData public class WaypointNode
{ {
public WaypointData() { moveType = WaypointMoveType.Run; } public WaypointNode() { moveType = WaypointMoveType.Run; }
public WaypointData(uint _id, float _x, float _y, float _z, float _orientation = 0.0f, uint _delay = 0) public WaypointNode(uint _id, float _x, float _y, float _z, float _orientation = 0.0f, uint _delay = 0)
{ {
id = _id; id = _id;
x = _x; x = _x;
@@ -157,6 +162,19 @@ namespace Game
public byte eventChance; public byte eventChance;
} }
public class WaypointPath
{
public WaypointPath() { }
public WaypointPath(uint _id, List<WaypointNode> _nodes)
{
id = _id;
nodes = _nodes;
}
public List<WaypointNode> nodes = new List<WaypointNode>();
public uint id;
}
public enum WaypointMoveType public enum WaypointMoveType
{ {
Walk, Walk,
+32 -37
View File
@@ -197,22 +197,22 @@ namespace Game.Scripting
LoadScriptWaypoints(); LoadScriptWaypoints();
LoadScriptSplineChains(); LoadScriptSplineChains();
} }
void LoadScriptWaypoints() void LoadScriptWaypoints()
{ {
uint oldMSTime = Time.GetMSTime(); uint oldMSTime = Time.GetMSTime();
// Drop Existing Waypoint list // Drop Existing Waypoint list
_waypointStore.Clear();
m_mPointMoveMap.Clear(); ulong entryCount = 0;
ulong uiCreatureCount = 0;
// Load Waypoints // Load Waypoints
SQLResult result = DB.World.Query("SELECT COUNT(entry) FROM script_waypoint GROUP BY entry"); SQLResult result = DB.World.Query("SELECT COUNT(entry) FROM script_waypoint GROUP BY entry");
if (!result.IsEmpty()) if (!result.IsEmpty())
uiCreatureCount = result.Read<uint>(0); entryCount = result.Read<uint>(0);
Log.outInfo(LogFilter.ServerLoading, "Loading Script Waypoints for {0} creature(s)...", uiCreatureCount); Log.outInfo(LogFilter.ServerLoading, $"Loading Script Waypoints for {entryCount} creature(s)...");
// 0 1 2 3 4 5 // 0 1 2 3 4 5
result = DB.World.Query("SELECT entry, pointid, location_x, location_y, location_z, waittime FROM script_waypoint ORDER BY pointid"); result = DB.World.Query("SELECT entry, pointid, location_x, location_y, location_z, waittime FROM script_waypoint ORDER BY pointid");
@@ -227,28 +227,30 @@ namespace Game.Scripting
do do
{ {
ScriptPointMove temp = new ScriptPointMove(); uint entry = result.Read<uint>(0);
uint id = result.Read<uint>(1);
float x = result.Read<float>(2);
float y = result.Read<float>(3);
float z = result.Read<float>(4);
uint waitTime = result.Read<uint>(5);
temp.uiCreatureEntry = result.Read<uint>(0); CreatureTemplate info = Global.ObjectMgr.GetCreatureTemplate(entry);
uint uiEntry = temp.uiCreatureEntry; if (info == null)
temp.uiPointId = result.Read<uint>(1);
temp.fX = result.Read<float>(2);
temp.fY = result.Read<float>(3);
temp.fZ = result.Read<float>(4);
temp.uiWaitTime = result.Read<uint>(5);
CreatureTemplate pCInfo = Global.ObjectMgr.GetCreatureTemplate(temp.uiCreatureEntry);
if (pCInfo == null)
{ {
Log.outError(LogFilter.Sql, "TSCR: DB table script_waypoint has waypoint for non-existant creature entry {0}", temp.uiCreatureEntry); Log.outError(LogFilter.Sql, $"SystemMgr: DB table script_waypoint has waypoint for non-existant creature entry {entry}");
continue; continue;
} }
if (pCInfo.ScriptID == 0) if (info.ScriptID == 0)
Log.outError(LogFilter.Sql, "TSCR: DB table script_waypoint has waypoint for creature entry {0}, but creature does not have ScriptName defined and then useless.", temp.uiCreatureEntry); Log.outError(LogFilter.Sql, $"SystemMgr: DB table script_waypoint has waypoint for creature entry {entry}, but creature does not have ScriptName defined and then useless.");
if (!_waypointStore.ContainsKey(entry))
_waypointStore[entry] = new WaypointPath();
WaypointPath path = _waypointStore[entry];
path.id = entry;
path.nodes.Add(new WaypointNode(id, x, y, z, 0.0f, waitTime));
m_mPointMoveMap.Add(uiEntry, temp);
++count; ++count;
} }
while (result.NextRow()); while (result.NextRow());
@@ -256,6 +258,7 @@ namespace Game.Scripting
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} Script Waypoint nodes in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); Log.outInfo(LogFilter.ServerLoading, "Loaded {0} Script Waypoint nodes in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime));
} }
void LoadScriptSplineChains() void LoadScriptSplineChains()
{ {
uint oldMSTime = Time.GetMSTime(); uint oldMSTime = Time.GetMSTime();
@@ -332,15 +335,22 @@ namespace Game.Scripting
Log.outInfo(LogFilter.ServerLoading, "Loaded spline chain data for {0} chains, consisting of {1} splines with {2} waypoints in {3} ms", chainCount, splineCount, wpCount, Time.GetMSTimeDiffToNow(oldMSTime)); Log.outInfo(LogFilter.ServerLoading, "Loaded spline chain data for {0} chains, consisting of {1} splines with {2} waypoints in {3} ms", chainCount, splineCount, wpCount, Time.GetMSTimeDiffToNow(oldMSTime));
} }
} }
public void FillSpellSummary() public void FillSpellSummary()
{ {
UnitAI.FillAISpellInfo(); UnitAI.FillAISpellInfo();
} }
public WaypointPath GetPath(uint creatureEntry)
{
return _waypointStore.LookupByKey(creatureEntry);
}
public List<SplineChainLink> GetSplineChain(Creature who, ushort chainId) public List<SplineChainLink> GetSplineChain(Creature who, ushort chainId)
{ {
return GetSplineChain(who.GetEntry(), chainId); return GetSplineChain(who.GetEntry(), chainId);
} }
List<SplineChainLink> GetSplineChain(uint entry, ushort chainId) List<SplineChainLink> GetSplineChain(uint entry, ushort chainId)
{ {
return m_mSplineChainsMap.LookupByKey(Tuple.Create(entry, chainId)); return m_mSplineChainsMap.LookupByKey(Tuple.Create(entry, chainId));
@@ -1242,11 +1252,6 @@ namespace Game.Scripting
GetScriptRegistry<T>().AddScript(script); GetScriptRegistry<T>().AddScript(script);
} }
public List<ScriptPointMove> GetPointMoveList(uint creatureEntry)
{
return m_mPointMoveMap.LookupByKey(creatureEntry);
}
ScriptRegistry<T> GetScriptRegistry<T>() where T : ScriptObject ScriptRegistry<T> GetScriptRegistry<T>() where T : ScriptObject
{ {
if (ScriptStorage.ContainsKey(typeof(T))) if (ScriptStorage.ContainsKey(typeof(T)))
@@ -1259,7 +1264,7 @@ namespace Game.Scripting
public Dictionary<uint, SpellSummary> spellSummaryStorage = new Dictionary<uint, SpellSummary>(); public Dictionary<uint, SpellSummary> spellSummaryStorage = new Dictionary<uint, SpellSummary>();
Hashtable ScriptStorage = new Hashtable(); Hashtable ScriptStorage = new Hashtable();
MultiMap<uint, ScriptPointMove> m_mPointMoveMap = new MultiMap<uint, ScriptPointMove>(); Dictionary<uint, WaypointPath> _waypointStore = new Dictionary<uint, WaypointPath>();
// creature entry + chain ID // creature entry + chain ID
MultiMap<Tuple<uint, ushort>, SplineChainLink> m_mSplineChainsMap = new MultiMap<Tuple<uint, ushort>, SplineChainLink>(); // spline chains MultiMap<Tuple<uint, ushort>, SplineChainLink> m_mSplineChainsMap = new MultiMap<Tuple<uint, ushort>, SplineChainLink>(); // spline chains
@@ -1348,16 +1353,6 @@ namespace Game.Scripting
Dictionary<uint, TValue> ScriptMap = new Dictionary<uint, TValue>(); Dictionary<uint, TValue> ScriptMap = new Dictionary<uint, TValue>();
} }
public class ScriptPointMove
{
public uint uiCreatureEntry;
public uint uiPointId;
public float fX;
public float fY;
public float fZ;
public uint uiWaitTime;
}
public class SpellSummary public class SpellSummary
{ {
public byte Targets; // set of enum SelectTarget public byte Targets; // set of enum SelectTarget
@@ -1379,7 +1379,7 @@ namespace Scripts.EasternKingdoms.Karazhan.OperaEvent
{ {
public npc_barnes() : base("npc_barnes") { } public npc_barnes() : base("npc_barnes") { }
class npc_barnesAI : NpcEscortAI class npc_barnesAI : EscortAI
{ {
public npc_barnesAI(Creature creature) : base(creature) public npc_barnesAI(Creature creature) : base(creature)
{ {
@@ -1418,7 +1418,7 @@ namespace Scripts.EasternKingdoms.Karazhan.OperaEvent
public override void EnterCombat(Unit who) { } public override void EnterCombat(Unit who) { }
public override void WaypointReached(uint waypointId) public override void WaypointReached(uint waypointId, uint pathId)
{ {
switch (waypointId) switch (waypointId)
{ {
@@ -947,7 +947,7 @@ namespace Scripts.EasternKingdoms
} }
[Script] [Script]
class npc_scarlet_miner : NpcEscortAI class npc_scarlet_miner : EscortAI
{ {
public npc_scarlet_miner(Creature creature) : base(creature) public npc_scarlet_miner(Creature creature) : base(creature)
{ {
@@ -1012,7 +1012,7 @@ namespace Scripts.EasternKingdoms
SetDespawnAtFar(false); SetDespawnAtFar(false);
} }
public override void WaypointReached(uint waypointId) public override void WaypointReached(uint waypointId, uint pathId)
{ {
switch (waypointId) switch (waypointId)
{ {
+4 -4
View File
@@ -111,7 +111,7 @@ namespace Scripts.Kalimdor.ZoneAshenvale
[Script] [Script]
class npc_ruul_snowhoof : NpcEscortAI class npc_ruul_snowhoof : EscortAI
{ {
public npc_ruul_snowhoof(Creature creature) : base(creature) { } public npc_ruul_snowhoof(Creature creature) : base(creature) { }
@@ -138,7 +138,7 @@ namespace Scripts.Kalimdor.ZoneAshenvale
} }
} }
public override void WaypointReached(uint waypointId) public override void WaypointReached(uint waypointId, uint pathId)
{ {
Player player = GetPlayerForEscort(); Player player = GetPlayerForEscort();
if (!player) if (!player)
@@ -170,7 +170,7 @@ namespace Scripts.Kalimdor.ZoneAshenvale
} }
[Script] [Script]
public class npc_muglash : NpcEscortAI public class npc_muglash : EscortAI
{ {
public npc_muglash(Creature creature) : base(creature) public npc_muglash(Creature creature) : base(creature)
{ {
@@ -228,7 +228,7 @@ namespace Scripts.Kalimdor.ZoneAshenvale
} }
} }
public override void WaypointReached(uint waypointId) public override void WaypointReached(uint waypointId, uint pathId)
{ {
Player player = GetPlayerForEscort(); Player player = GetPlayerForEscort();
if (player) if (player)
@@ -72,7 +72,7 @@ namespace Scripts.Northrend.CrusadersColiseum.TrialOfTheChampion
} }
[Script] [Script]
class generic_vehicleAI_toc5 : NpcEscortAI class generic_vehicleAI_toc5 : EscortAI
{ {
public generic_vehicleAI_toc5(Creature creature) : base(creature) public generic_vehicleAI_toc5(Creature creature) : base(creature)
{ {
@@ -124,7 +124,7 @@ namespace Scripts.Northrend.CrusadersColiseum.TrialOfTheChampion
Start(false, true); Start(false, true);
} }
public override void WaypointReached(uint waypointId) public override void WaypointReached(uint waypointId, uint pathId)
{ {
switch (waypointId) switch (waypointId)
{ {
@@ -666,7 +666,7 @@ namespace Scripts.Northrend.IcecrownCitadel
} }
[Script] [Script]
class npc_crok_scourgebane : NpcEscortAI class npc_crok_scourgebane : EscortAI
{ {
public npc_crok_scourgebane(Creature creature) : base(creature) public npc_crok_scourgebane(Creature creature) : base(creature)
{ {
@@ -748,7 +748,7 @@ namespace Scripts.Northrend.IcecrownCitadel
} }
} }
public override void WaypointReached(uint waypointId) public override void WaypointReached(uint waypointId, uint pathId)
{ {
switch (waypointId) switch (waypointId)
{ {
@@ -780,7 +780,7 @@ namespace Scripts.Northrend.IcecrownCitadel
} }
} }
public override void WaypointStart(uint waypointId) public override void WaypointStarted(uint waypointId, uint pathId)
{ {
_currentWPid = waypointId; _currentWPid = waypointId;
switch (waypointId) switch (waypointId)
@@ -867,7 +867,7 @@ namespace Scripts.Northrend.Ulduar.FlameLeviathan
} }
[Script] [Script]
class npc_mimirons_inferno : NpcEscortAI class npc_mimirons_inferno : EscortAI
{ {
public npc_mimirons_inferno(Creature creature) public npc_mimirons_inferno(Creature creature)
: base(creature) : base(creature)
@@ -877,10 +877,7 @@ namespace Scripts.Northrend.Ulduar.FlameLeviathan
me.SetReactState(ReactStates.Passive); me.SetReactState(ReactStates.Passive);
} }
public override void WaypointReached(uint waypointId) public override void WaypointReached(uint waypointId, uint pathId) { }
{
}
public override void Reset() public override void Reset()
{ {
+4 -4
View File
@@ -115,7 +115,7 @@ namespace Scripts.Outlands
} }
[Script] [Script]
class npc_ancestral_wolf : NpcEscortAI class npc_ancestral_wolf : EscortAI
{ {
public npc_ancestral_wolf(Creature creature) : base(creature) public npc_ancestral_wolf(Creature creature) : base(creature)
{ {
@@ -146,7 +146,7 @@ namespace Scripts.Outlands
base.MoveInLineOfSight(who); base.MoveInLineOfSight(who);
} }
public override void WaypointReached(uint waypointId) public override void WaypointReached(uint waypointId, uint pathId)
{ {
switch (waypointId) switch (waypointId)
{ {
@@ -167,7 +167,7 @@ namespace Scripts.Outlands
} }
[Script] [Script]
class npc_wounded_blood_elf : NpcEscortAI class npc_wounded_blood_elf : EscortAI
{ {
public npc_wounded_blood_elf(Creature creature) : base(creature) { } public npc_wounded_blood_elf(Creature creature) : base(creature) { }
@@ -193,7 +193,7 @@ namespace Scripts.Outlands
} }
} }
public override void WaypointReached(uint waypointId) public override void WaypointReached(uint waypointId, uint pathId)
{ {
Player player = GetPlayerForEscort(); Player player = GetPlayerForEscort();
if (!player) if (!player)
+2 -2
View File
@@ -289,13 +289,13 @@ namespace Scripts.Outlands
{ {
public npc_kayra_longmane() : base("npc_kayra_longmane") { } public npc_kayra_longmane() : base("npc_kayra_longmane") { }
class npc_kayra_longmaneAI : NpcEscortAI class npc_kayra_longmaneAI : EscortAI
{ {
public npc_kayra_longmaneAI(Creature creature) : base(creature) { } public npc_kayra_longmaneAI(Creature creature) : base(creature) { }
public override void Reset() { } public override void Reset() { }
public override void WaypointReached(uint waypointId) public override void WaypointReached(uint waypointId, uint pathId)
{ {
Player player = GetPlayerForEscort(); Player player = GetPlayerForEscort();
if (!player) if (!player)
+2 -2
View File
@@ -1163,7 +1163,7 @@ namespace Scripts.World.NpcSpecial
} }
[Script] [Script]
class npc_garments_of_quests : NpcEscortAI class npc_garments_of_quests : EscortAI
{ {
public npc_garments_of_quests(Creature creature) : base(creature) public npc_garments_of_quests(Creature creature) : base(creature)
{ {
@@ -1254,7 +1254,7 @@ namespace Scripts.World.NpcSpecial
} }
} }
public override void WaypointReached(uint waypointId) public override void WaypointReached(uint waypointId, uint pathId)
{ {
} }