Scripts/FollowerAI: Some cleanup:
Port From (https://github.com/TrinityCore/TrinityCore/commit/8c3eb07889f72955879c8a0e0881b51befb60067)
This commit is contained in:
@@ -493,6 +493,7 @@ namespace Game.AI
|
|||||||
public virtual void SpellHitTarget(Unit target, SpellInfo spellInfo) { }
|
public virtual void SpellHitTarget(Unit target, SpellInfo spellInfo) { }
|
||||||
public virtual void SpellHitTargetGameObject(GameObject target, SpellInfo spellInfo) { }
|
public virtual void SpellHitTargetGameObject(GameObject target, SpellInfo spellInfo) { }
|
||||||
|
|
||||||
|
// Should return true if the NPC is currently being escorted
|
||||||
public virtual bool IsEscorted() { return false; }
|
public virtual bool IsEscorted() { return false; }
|
||||||
|
|
||||||
public virtual void MovementInform(MovementGeneratorType type, uint id) { }
|
public virtual void MovementInform(MovementGeneratorType type, uint id) { }
|
||||||
@@ -565,14 +566,6 @@ namespace Game.AI
|
|||||||
// Object destruction is handled by Unit::RemoveCharmedBy
|
// Object destruction is handled by Unit::RemoveCharmedBy
|
||||||
public virtual PlayerAI GetAIForCharmedPlayer(Player who) { return null; }
|
public virtual PlayerAI GetAIForCharmedPlayer(Player who) { return null; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Should return true if the NPC is target of an escort quest
|
|
||||||
/// If onlyIfActive is set, should return true only if the escort quest is currently active
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="onlyIfActive"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public virtual bool IsEscortNPC(bool onlyIfActive) { return false; }
|
|
||||||
|
|
||||||
public List<AreaBoundary> GetBoundary() { return _boundary; }
|
public List<AreaBoundary> GetBoundary() { return _boundary; }
|
||||||
|
|
||||||
public bool IsEngaged() { return _isEngaged; }
|
public bool IsEngaged() { return _isEngaged; }
|
||||||
|
|||||||
@@ -382,15 +382,8 @@ namespace Game.AI
|
|||||||
CreatureData cdata = me.GetCreatureData();
|
CreatureData cdata = me.GetCreatureData();
|
||||||
if (cdata != null)
|
if (cdata != null)
|
||||||
{
|
{
|
||||||
SpawnGroupTemplateData groupdata = cdata.spawnGroupData;
|
if (WorldConfig.GetBoolValue(WorldCfg.RespawnDynamicEscortNpc) && cdata.spawnGroupData.flags.HasFlag(SpawnGroupFlags.EscortQuestNpc))
|
||||||
if (groupdata != null)
|
me.SaveRespawnTime(me.GetRespawnDelay());
|
||||||
{
|
|
||||||
if (WorldConfig.GetBoolValue(WorldCfg.RespawnDynamicEscortNpc) && groupdata.flags.HasAnyFlag(SpawnGroupFlags.EscortQuestNpc) && map.GetCreatureRespawnTime(me.GetSpawnId()) == 0)
|
|
||||||
{
|
|
||||||
me.SetRespawnTime(me.GetRespawnDelay());
|
|
||||||
me.SaveRespawnTime();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,21 +460,10 @@ namespace Game.AI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsEscortNPC(bool onlyIfActive)
|
|
||||||
{
|
|
||||||
if (!onlyIfActive)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (!GetEventStarterGUID().IsEmpty())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetPauseTimer(uint Timer) { _pauseTimer = Timer; }
|
void SetPauseTimer(uint Timer) { _pauseTimer = Timer; }
|
||||||
|
|
||||||
public bool HasEscortState(EscortState escortState) { return (_escortState & escortState) != 0; }
|
public bool HasEscortState(EscortState escortState) { return (_escortState & escortState) != 0; }
|
||||||
public override bool IsEscorted() { return _escortState.HasAnyFlag(EscortState.Escorting); }
|
public override bool IsEscorted() { return !_playerGUID.IsEmpty(); }
|
||||||
|
|
||||||
void SetMaxPlayerDistance(float newMax) { _maxPlayerDistance = newMax; }
|
void SetMaxPlayerDistance(float newMax) { _maxPlayerDistance = newMax; }
|
||||||
float GetMaxPlayerDistance() { return _maxPlayerDistance; }
|
float GetMaxPlayerDistance() { return _maxPlayerDistance; }
|
||||||
|
|||||||
@@ -18,19 +18,19 @@
|
|||||||
using Framework.Constants;
|
using Framework.Constants;
|
||||||
using Game.Entities;
|
using Game.Entities;
|
||||||
using Game.Groups;
|
using Game.Groups;
|
||||||
|
using Game.Maps;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Game.AI
|
namespace Game.AI
|
||||||
{
|
{
|
||||||
enum FollowState
|
enum FollowState
|
||||||
{
|
{
|
||||||
None = 0x000,
|
None = 0x00,
|
||||||
Inprogress = 0x001, //must always have this state for any follow
|
Inprogress = 0x01, //must always have this state for any follow
|
||||||
Returning = 0x002, //when returning to combat start after being in combat
|
Paused = 0x02, //disables following
|
||||||
Paused = 0x004, //disables following
|
Complete = 0x04, //follow is completed and may end
|
||||||
Complete = 0x008, //follow is completed and may end
|
PreEvent = 0x08, //not implemented (allow pre event to run, before follow is initiated)
|
||||||
PreEvent = 0x010, //not implemented (allow pre event to run, before follow is initiated)
|
PostEvent = 0x10 //can be set at complete and allow post event to run
|
||||||
PostEvent = 0x020 //can be set at complete and allow post event to run
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class FollowerAI : ScriptedAI
|
class FollowerAI : ScriptedAI
|
||||||
@@ -38,45 +38,17 @@ namespace Game.AI
|
|||||||
ObjectGuid _leaderGUID;
|
ObjectGuid _leaderGUID;
|
||||||
uint _updateFollowTimer;
|
uint _updateFollowTimer;
|
||||||
FollowState _followState;
|
FollowState _followState;
|
||||||
|
uint _questForFollow;
|
||||||
Quest _questForFollow; //normally we have a quest
|
|
||||||
|
|
||||||
public FollowerAI(Creature creature) : base(creature)
|
public FollowerAI(Creature creature) : base(creature)
|
||||||
{
|
{
|
||||||
_updateFollowTimer = 2500;
|
_updateFollowTimer = 2500;
|
||||||
_followState = FollowState.None;
|
_followState = FollowState.None;
|
||||||
_questForFollow = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void MovementInform(MovementGeneratorType motionType, uint pointId)
|
|
||||||
{
|
|
||||||
if (motionType != MovementGeneratorType.Point || !HasFollowState(FollowState.Inprogress))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (pointId == 0xFFFFFF)
|
|
||||||
{
|
|
||||||
if (GetLeaderForFollower())
|
|
||||||
{
|
|
||||||
if (!HasFollowState(FollowState.Paused))
|
|
||||||
AddFollowState(FollowState.Returning);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
me.DespawnOrUnsummon();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void AttackStart(Unit who)
|
|
||||||
{
|
|
||||||
base.AttackStart(who);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void MoveInLineOfSight(Unit who)
|
public override void MoveInLineOfSight(Unit who)
|
||||||
{
|
{
|
||||||
// TODO: what in the world is this?
|
if (HasFollowState(FollowState.Inprogress) && !ShouldAssistPlayerInCombatAgainst(who))
|
||||||
if (me.HasReactState(ReactStates.Aggressive) && !me.HasUnitState(UnitState.Stunned) && who.IsTargetableForAttack() && who.IsInAccessiblePlaceFor(me))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (HasFollowState(FollowState.Inprogress) && AssistPlayerInCombatAgainst(who))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
base.MoveInLineOfSight(who);
|
base.MoveInLineOfSight(who);
|
||||||
@@ -84,7 +56,7 @@ namespace Game.AI
|
|||||||
|
|
||||||
public override void JustDied(Unit killer)
|
public override void JustDied(Unit killer)
|
||||||
{
|
{
|
||||||
if (!HasFollowState(FollowState.Inprogress) || _leaderGUID.IsEmpty() || _questForFollow == null)
|
if (!HasFollowState(FollowState.Inprogress) || _leaderGUID.IsEmpty() || _questForFollow == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// @todo need a better check for quests with time limit.
|
// @todo need a better check for quests with time limit.
|
||||||
@@ -99,59 +71,39 @@ 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(_questForFollow.Id);
|
member.FailQuest(_questForFollow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
player.FailQuest(_questForFollow.Id);
|
player.FailQuest(_questForFollow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void JustAppeared()
|
public override void JustReachedHome()
|
||||||
{
|
{
|
||||||
_followState = FollowState.None;
|
if (!HasFollowState(FollowState.Inprogress))
|
||||||
|
|
||||||
if (!IsCombatMovementAllowed())
|
|
||||||
SetCombatMovement(true);
|
|
||||||
|
|
||||||
if (me.GetFaction() != me.GetCreatureTemplate().Faction)
|
|
||||||
me.SetFaction(me.GetCreatureTemplate().Faction);
|
|
||||||
|
|
||||||
Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void EnterEvadeMode(EvadeReason why)
|
|
||||||
{
|
|
||||||
if (!me.IsAlive())
|
|
||||||
{
|
|
||||||
EngagementOver();
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
me.RemoveAllAuras();
|
Player player = GetLeaderForFollower();
|
||||||
me.CombatStop(true);
|
if (player != null)
|
||||||
me.SetLootRecipient(null);
|
|
||||||
me.SetCannotReachTarget(false);
|
|
||||||
me.DoNotReacquireTarget();
|
|
||||||
|
|
||||||
EngagementOver();
|
|
||||||
|
|
||||||
if (HasFollowState(FollowState.Inprogress))
|
|
||||||
{
|
{
|
||||||
Log.outDebug(LogFilter.Scripts, "FollowerAI left combat, returning to CombatStartPosition.");
|
if (HasFollowState(FollowState.Paused))
|
||||||
|
return;
|
||||||
if (me.HasUnitState(UnitState.Chase))
|
me.GetMotionMaster().MoveFollow(player, SharedConst.PetFollowDist, SharedConst.PetFollowAngle);
|
||||||
me.GetMotionMaster().Remove(MovementGeneratorType.Chase);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
me.GetMotionMaster().MoveTargetedHome();
|
me.DespawnOrUnsummon();
|
||||||
|
}
|
||||||
|
|
||||||
Reset();
|
public override void OwnerAttackedBy(Unit attacker)
|
||||||
|
{
|
||||||
|
if (!me.HasReactState(ReactStates.Passive) && ShouldAssistPlayerInCombatAgainst(attacker))
|
||||||
|
me.EngageWithTarget(attacker);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateAI(uint uiDiff)
|
public override void UpdateAI(uint uiDiff)
|
||||||
{
|
{
|
||||||
if (HasFollowState(FollowState.Inprogress) && !me.GetVictim())
|
if (HasFollowState(FollowState.Inprogress) && !me.IsEngaged())
|
||||||
{
|
{
|
||||||
if (_updateFollowTimer <= uiDiff)
|
if (_updateFollowTimer <= uiDiff)
|
||||||
{
|
{
|
||||||
@@ -162,43 +114,49 @@ namespace Game.AI
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bIsMaxRangeExceeded = true;
|
bool maxRangeExceeded = true;
|
||||||
|
bool questAbandoned = (_questForFollow != 0);
|
||||||
|
|
||||||
Player player = GetLeaderForFollower();
|
Player player = GetLeaderForFollower();
|
||||||
if (player)
|
if (player)
|
||||||
{
|
{
|
||||||
if (HasFollowState(FollowState.Returning))
|
|
||||||
{
|
|
||||||
Log.outDebug(LogFilter.Scripts, "FollowerAI is returning to leader.");
|
|
||||||
|
|
||||||
RemoveFollowState(FollowState.Returning);
|
|
||||||
me.GetMotionMaster().MoveFollow(player, SharedConst.PetFollowDist, SharedConst.PetFollowAngle);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Group group = player.GetGroup();
|
Group group = player.GetGroup();
|
||||||
if (group)
|
if (group)
|
||||||
{
|
{
|
||||||
for (GroupReference groupRef = group.GetFirstMember(); groupRef != null; groupRef = groupRef.Next())
|
for (GroupReference groupRef = group.GetFirstMember(); groupRef != null && (maxRangeExceeded || questAbandoned); groupRef = groupRef.Next())
|
||||||
{
|
{
|
||||||
Player member = groupRef.GetSource();
|
Player member = groupRef.GetSource();
|
||||||
if (member && me.IsWithinDistInMap(member, 100.0f))
|
if (member == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (maxRangeExceeded && me.IsWithinDistInMap(member, 100.0f))
|
||||||
|
maxRangeExceeded = false;
|
||||||
|
|
||||||
|
if (questAbandoned)
|
||||||
{
|
{
|
||||||
bIsMaxRangeExceeded = false;
|
QuestStatus status = member.GetQuestStatus(_questForFollow);
|
||||||
break;
|
if ((status == QuestStatus.Complete) || (status == QuestStatus.Incomplete))
|
||||||
|
questAbandoned = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (me.IsWithinDistInMap(player, 100.0f))
|
if (me.IsWithinDistInMap(player, 100.0f))
|
||||||
bIsMaxRangeExceeded = false;
|
maxRangeExceeded = false;
|
||||||
|
|
||||||
|
if (questAbandoned)
|
||||||
|
{
|
||||||
|
QuestStatus status = player.GetQuestStatus(_questForFollow);
|
||||||
|
if ((status == QuestStatus.Complete) || (status == QuestStatus.Incomplete))
|
||||||
|
questAbandoned = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bIsMaxRangeExceeded)
|
if (maxRangeExceeded || questAbandoned)
|
||||||
{
|
{
|
||||||
Log.outDebug(LogFilter.Scripts, "FollowerAI failed because player/group was to far away or not found");
|
Log.outDebug(LogFilter.Scripts, $"FollowerAI::UpdateAI: failed because player/group was to far away or not found ({me.GetGUID()})");
|
||||||
me.DespawnOrUnsummon();
|
me.DespawnOrUnsummon();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -222,15 +180,26 @@ namespace Game.AI
|
|||||||
|
|
||||||
public void StartFollow(Player player, uint factionForFollower = 0, Quest quest = null)
|
public void StartFollow(Player player, uint factionForFollower = 0, Quest quest = null)
|
||||||
{
|
{
|
||||||
if (me.GetVictim())
|
Map map = me.GetMap();
|
||||||
|
if (map != null)
|
||||||
{
|
{
|
||||||
Log.outDebug(LogFilter.Scripts, "FollowerAI attempt to StartFollow while in combat.");
|
CreatureData cdata = me.GetCreatureData();
|
||||||
|
if (cdata != null)
|
||||||
|
{
|
||||||
|
if (WorldConfig.GetBoolValue(WorldCfg.RespawnDynamicEscortNpc) && cdata.spawnGroupData.flags.HasFlag(SpawnGroupFlags.EscortQuestNpc))
|
||||||
|
me.SaveRespawnTime(me.GetRespawnDelay());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (me.IsEngaged())
|
||||||
|
{
|
||||||
|
Log.outDebug(LogFilter.Scripts, $"FollowerAI::StartFollow: attempt to StartFollow while in combat. ({me.GetGUID()})");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HasFollowState(FollowState.Inprogress))
|
if (HasFollowState(FollowState.Inprogress))
|
||||||
{
|
{
|
||||||
Log.outError(LogFilter.Scenario, "FollowerAI attempt to StartFollow while already following.");
|
Log.outError(LogFilter.Scenario, $"FollowerAI::StartFollow: attempt to StartFollow while already following. ({me.GetGUID()})");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +209,7 @@ namespace Game.AI
|
|||||||
if (factionForFollower != 0)
|
if (factionForFollower != 0)
|
||||||
me.SetFaction(factionForFollower);
|
me.SetFaction(factionForFollower);
|
||||||
|
|
||||||
_questForFollow = quest;
|
_questForFollow = quest.Id;
|
||||||
|
|
||||||
me.GetMotionMaster().Clear(MovementGeneratorPriority.Normal);
|
me.GetMotionMaster().Clear(MovementGeneratorPriority.Normal);
|
||||||
me.PauseMovement();
|
me.PauseMovement();
|
||||||
@@ -252,7 +221,7 @@ namespace Game.AI
|
|||||||
|
|
||||||
me.GetMotionMaster().MoveFollow(player, SharedConst.PetFollowDist, SharedConst.PetFollowAngle);
|
me.GetMotionMaster().MoveFollow(player, SharedConst.PetFollowDist, SharedConst.PetFollowAngle);
|
||||||
|
|
||||||
Log.outDebug(LogFilter.Scripts, "FollowerAI start follow {0} ({1})", player.GetName(), _leaderGUID.ToString());
|
Log.outDebug(LogFilter.Scripts, $"FollowerAI::StartFollow: start follow {player.GetName()} - {_leaderGUID} ({me.GetGUID()})");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetFollowPaused(bool paused)
|
public void SetFollowPaused(bool paused)
|
||||||
@@ -310,7 +279,7 @@ namespace Game.AI
|
|||||||
Player member = groupRef.GetSource();
|
Player member = groupRef.GetSource();
|
||||||
if (member && me.IsWithinDistInMap(member, 100.0f) && member.IsAlive())
|
if (member && me.IsWithinDistInMap(member, 100.0f) && member.IsAlive())
|
||||||
{
|
{
|
||||||
Log.outDebug(LogFilter.Scripts, "FollowerAI GetLeader changed and returned new leader.");
|
Log.outDebug(LogFilter.Scripts, $"FollowerAI::GetLeaderForFollower: GetLeader changed and returned new leader. ({me.GetGUID()})");
|
||||||
_leaderGUID = member.GetGUID();
|
_leaderGUID = member.GetGUID();
|
||||||
return member;
|
return member;
|
||||||
}
|
}
|
||||||
@@ -319,29 +288,22 @@ namespace Game.AI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.outDebug(LogFilter.Scripts, "FollowerAI GetLeader can not find suitable leader.");
|
Log.outDebug(LogFilter.Scripts, $"FollowerAI::GetLeaderForFollower: GetLeader can not find suitable leader. ({me.GetGUID()})");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//This part provides assistance to a player that are attacked by who, even if out of normal aggro range
|
//This part provides assistance to a player that are attacked by who, even if out of normal aggro range
|
||||||
//It will cause me to attack who that are attacking _any_ player (which has been confirmed may happen also on offi)
|
//It will cause me to attack who that are attacking _any_ player (which has been confirmed may happen also on offi)
|
||||||
//The flag (type_flag) is unconfirmed, but used here for further research and is a good candidate.
|
//The flag (type_flag) is unconfirmed, but used here for further research and is a good candidate.
|
||||||
bool AssistPlayerInCombatAgainst(Unit who)
|
bool ShouldAssistPlayerInCombatAgainst(Unit who)
|
||||||
{
|
{
|
||||||
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;
|
||||||
|
|
||||||
//not a player
|
|
||||||
if (!who.GetVictim().GetCharmerOrOwnerPlayerOrPlayerItself())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!who.IsInAccessiblePlaceFor(me))
|
if (!who.IsInAccessiblePlaceFor(me))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -361,18 +323,18 @@ namespace Game.AI
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
//too far away and no free sight?
|
//too far away and no free sight?
|
||||||
if (me.IsWithinDistInMap(who, 100.0f) && me.IsWithinLOSInMap(who))
|
if (!me.IsWithinDistInMap(who, 100.0f) || !me.IsWithinLOSInMap(who))
|
||||||
{
|
return false;
|
||||||
me.EngageWithTarget(who);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
public override bool IsEscorted() { return HasFollowState(FollowState.Inprogress); }
|
||||||
}
|
|
||||||
|
|
||||||
bool HasFollowState(FollowState uiFollowState) { return (_followState & uiFollowState) != 0; }
|
bool HasFollowState(FollowState uiFollowState) { return (_followState & uiFollowState) != 0; }
|
||||||
|
|
||||||
void AddFollowState(FollowState uiFollowState) { _followState |= uiFollowState; }
|
void AddFollowState(FollowState uiFollowState) { _followState |= uiFollowState; }
|
||||||
|
|
||||||
void RemoveFollowState(FollowState uiFollowState) { _followState &= ~uiFollowState; }
|
void RemoveFollowState(FollowState uiFollowState) { _followState &= ~uiFollowState; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1100,11 +1100,11 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsEscortNPC(bool onlyIfActive = true)
|
public bool IsEscorted()
|
||||||
{
|
{
|
||||||
CreatureAI ai = GetAI();
|
CreatureAI ai = GetAI();
|
||||||
if (ai != null)
|
if (ai != null)
|
||||||
return ai.IsEscortNPC(onlyIfActive);
|
return ai.IsEscorted();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2302,7 +2302,9 @@ namespace Game.Entities
|
|||||||
if (!victim.IsInAccessiblePlaceFor(this))
|
if (!victim.IsInAccessiblePlaceFor(this))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (IsAIEnabled() && !GetAI().CanAIAttack(victim))
|
CreatureAI ai = GetAI();
|
||||||
|
if (ai != null)
|
||||||
|
if (!ai.CanAIAttack(victim))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// we cannot attack in evade mode
|
// we cannot attack in evade mode
|
||||||
|
|||||||
@@ -2348,7 +2348,7 @@ namespace Game.Maps
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// escort NPCs are allowed to respawn as long as all other instances are already escorting
|
// escort NPCs are allowed to respawn as long as all other instances are already escorting
|
||||||
if (isEscort && creature.IsEscortNPC(true))
|
if (isEscort && creature.IsEscorted())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
doDelete = true;
|
doDelete = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user