Core/SmartAI: Various fixes and extensions for smart scripts:

Port From (https://github.com/TrinityCore/TrinityCore/commit/a32d5cfa1762ae1158ee2f40b4c9b36e5b41913a)
This commit is contained in:
hondacrx
2019-08-30 12:00:42 -04:00
parent b85860dd78
commit 1657f720dc
15 changed files with 863 additions and 257 deletions
+160 -65
View File
@@ -30,20 +30,11 @@ namespace Game.AI
{
public class SmartAI : CreatureAI
{
const int SMART_ESCORT_MAX_PLAYER_DIST = 50;
const int SMART_ESCORT_MAX_PLAYER_DIST = 60;
const int SMART_MAX_AID_DIST = SMART_ESCORT_MAX_PLAYER_DIST / 2;
public SmartAI(Creature creature) : base(creature)
{
mIsCharmed = false;
// copy script to local (protection for table reload)
mEscortState = SmartEscortState.None;
mCurrentWPID = 0;//first wp id is 1 !!
mWPReached = false;
mWPPauseTimer = 0;
mCanRepeatPath = false;
// Spawn in run mode
me.SetWalk(false);
mRun = true;
@@ -53,21 +44,10 @@ namespace Game.AI
mCanAutoAttack = true;
mCanCombatMove = true;
mForcedPaused = false;
mLastWPIDReached = 0;
mEscortQuestID = 0;
mDespawnTime = 0;
mDespawnState = 0;
mEscortInvokerCheckTimer = 1000;
mFollowGuid = ObjectGuid.Empty;
mFollowDist = 0;
mFollowAngle = 0;
mFollowCredit = 0;
mFollowArrivedEntry = 0;
mFollowCreditType = 0;
mInvincibilityHpLevel = 0;
mHasConditions = Global.ConditionMgr.HasConditionsForNotGroupedEntry(ConditionSourceType.CreatureTemplateVehicle, creature.GetEntry());
}
bool IsAIControlled()
@@ -133,20 +113,28 @@ namespace Game.AI
StopPath();
if (path != 0)
{
if (!LoadPath(path))
return;
}
if (mWayPoints.Empty())
return;
AddEscortState(SmartEscortState.Escorting);
mCanRepeatPath = repeat;
SetRun(run);
WayPoint wp = GetNextWayPoint();
if (wp != null)
{
AddEscortState(SmartEscortState.Escorting);
mCanRepeatPath = repeat;
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());
@@ -221,6 +209,12 @@ namespace Game.AI
mWPPauseTimer = 0;
mLastWP = null;
if (mEscortNPCFlags != 0)
{
me.SetNpcFlags((NPCFlags)mEscortNPCFlags);
mEscortNPCFlags = 0;
}
if (mCanRepeatPath)
{
if (IsAIControlled())
@@ -301,9 +295,15 @@ namespace Game.AI
if (mEscortInvokerCheckTimer < diff)
{
// Escort failed, no players in range
if (!IsEscortInvokerInRange())
{
StopPath(mDespawnTime, 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
GetScript().ProcessEventsFor(SmartEvents.Death, me);
me.DespawnOrUnsummon(1);
return;
}
mEscortInvokerCheckTimer = 1000;
}
@@ -347,6 +347,7 @@ namespace Game.AI
if ((!me.HasReactState(ReactStates.Passive) && me.IsInCombat()) || HasEscortState(SmartEscortState.Paused | SmartEscortState.Returning))
return;
// handle next wp
if (mWPReached)//reached WP
{
@@ -369,6 +370,7 @@ namespace Game.AI
public override void UpdateAI(uint diff)
{
CheckConditions(diff);
GetScript().OnUpdate(diff);
UpdatePath(diff);
UpdateDespawn(diff);
@@ -390,10 +392,11 @@ namespace Game.AI
var targets = GetScript().GetTargetList(SharedConst.SmartEscortTargets);
if (targets != null)
{
float checkDist = me.GetInstanceScript() != null ? SMART_ESCORT_MAX_PLAYER_DIST * 2 : SMART_ESCORT_MAX_PLAYER_DIST;
if (targets.Count == 1 && GetScript().IsPlayer(targets.First()))
{
Player player = targets.First().ToPlayer();
if (me.GetDistance(player) <= SMART_ESCORT_MAX_PLAYER_DIST)
if (me.GetDistance(player) <= checkDist)
return true;
Group group = player.GetGroup();
@@ -402,7 +405,7 @@ namespace Game.AI
for (GroupReference groupRef = group.GetFirstMember(); groupRef != null; groupRef = groupRef.next())
{
Player groupGuy = groupRef.GetSource();
if (groupGuy.IsInMap(player) && me.GetDistance(groupGuy) <= SMART_ESCORT_MAX_PLAYER_DIST)
if (groupGuy.IsInMap(player) && me.GetDistance(groupGuy) <= checkDist)
return true;
}
}
@@ -413,13 +416,18 @@ namespace Game.AI
{
if (GetScript().IsPlayer(obj))
{
if (me.GetDistance(obj.ToPlayer()) <= SMART_ESCORT_MAX_PLAYER_DIST)
if (me.GetDistance(obj.ToPlayer()) <= checkDist)
return true;
}
}
}
// no valid target found
return false;
}
return true;//escort targets were not set, ignore range check
// no player invoker was stored, just ignore range check
return true;
}
void MovepointReached(uint id)
@@ -462,6 +470,12 @@ namespace Game.AI
return;
}
if (!IsAIControlled())
{
me.AttackStop();
return;
}
if (!_EnterEvadeMode())
return;
@@ -538,7 +552,7 @@ namespace Game.AI
return false;
//never attack friendly
if (me.IsFriendlyTo(who))
if (!me.IsValidAssistTarget(who.GetVictim()))
return false;
//too far away and no free sight?
@@ -634,7 +648,15 @@ namespace Game.AI
public override void AttackStart(Unit who)
{
if (who && me.Attack(who, me.IsWithinMeleeRange(who)))
// dont allow charmed npcs to act on their own
if (!IsAIControlled())
{
if (who != null && mCanAutoAttack)
me.Attack(who, true);
return;
}
if (who != null && me.Attack(who, me.IsWithinMeleeRange(who)))
{
if (mCanCombatMove)
me.GetMotionMaster().MoveChase(who);
@@ -701,9 +723,11 @@ namespace Game.AI
{
mScript.OnInitialize(me);
if (!me.IsDead())
{
mJustReset = true;
JustReachedHome();
GetScript().ProcessEventsFor(SmartEvents.Respawn);
JustReachedHome();
GetScript().ProcessEventsFor(SmartEvents.Respawn);
}
}
public override void OnCharmed(bool apply)
@@ -759,9 +783,14 @@ namespace Game.AI
mRun = run;
}
public void SetFly(bool fly)
public void SetDisableGravity(bool disable = true)
{
me.SetDisableGravity(fly);
me.SetDisableGravity(disable);
}
public void SetCanFly(bool fly = true)
{
me.SetCanFly(fly);
}
public void SetSwim(bool swim)
@@ -838,11 +867,14 @@ namespace Game.AI
public void SetFollow(Unit target, float dist, float angle, uint credit, uint end, uint creditType)
{
if (target == null)
{
StopFollow(false);
return;
}
mFollowGuid = target.GetGUID();
mFollowDist = dist >= 0.0f ? dist : SharedConst.PetFollowDist;
mFollowAngle = angle >= 0.0f ? angle : me.GetFollowAngle();
mFollowDist = dist;
mFollowAngle = angle;
mFollowArrivedTimer = 1000;
mFollowCredit = credit;
mFollowArrivedEntry = end;
@@ -851,6 +883,35 @@ namespace Game.AI
me.GetMotionMaster().MoveFollow(target, mFollowDist, mFollowAngle);
}
public void StopFollow(bool complete)
{
mFollowGuid.Clear();
mFollowDist = 0;
mFollowAngle = 0;
mFollowCredit = 0;
mFollowArrivedTimer = 1000;
mFollowArrivedEntry = 0;
mFollowCreditType = 0;
me.StopMoving();
me.GetMotionMaster().MoveIdle();
if (!complete)
return;
Player player = Global.ObjAccessor.GetPlayer(me, mFollowGuid);
if (player != null)
{
if (mFollowCreditType == 0)
player.RewardPlayerAndGroupAtEvent(mFollowCredit, me);
else
player.GroupEventHappens(mFollowCredit, me);
}
SetDespawnTime(5000);
StartDespawn();
GetScript().ProcessEventsFor(SmartEvents.FollowCompleted);
}
public void SetScript9(SmartScriptHolder e, uint entry, Unit invoker)
{
if (invoker != null)
@@ -871,6 +932,40 @@ namespace Game.AI
GetScript().ProcessEventsFor(SmartEvents.OnSpellclick, clicker);
}
void CheckConditions(uint diff)
{
if (!mHasConditions)
return;
if (mConditionsTimer <= diff)
{
Vehicle vehicleKit = me.GetVehicleKit();
if (vehicleKit != null)
{
foreach (var pair in vehicleKit.Seats)
{
Unit passenger = Global.ObjAccessor.GetUnit(me, pair.Value.Passenger.Guid);
if (passenger != null)
{
Player player = passenger.ToPlayer();
if (player != null)
{
if (!Global.ConditionMgr.IsObjectMeetingNotGroupedConditions(ConditionSourceType.CreatureTemplateVehicle, me.GetEntry(), player, me))
{
player.ExitVehicle();
return; // check other pessanger in next tick
}
}
}
}
}
mConditionsTimer = 1000;
}
else
mConditionsTimer -= diff;
}
public void UpdateFollow(uint diff)
{
if (!mFollowGuid.IsEmpty())
@@ -879,31 +974,14 @@ namespace Game.AI
{
if (me.FindNearestCreature(mFollowArrivedEntry, SharedConst.InteractionDistance, true) != null)
{
Player player = Global.ObjAccessor.GetPlayer(me, mFollowGuid);
if (player != null)
{
if (mFollowCreditType == 0)
player.RewardPlayerAndGroupAtEvent(mFollowCredit, me);
else
player.GroupEventHappens(mFollowCredit, me);
}
mFollowGuid.Clear();
mFollowDist = 0;
mFollowAngle = 0;
mFollowCredit = 0;
mFollowArrivedTimer = 1000;
mFollowArrivedEntry = 0;
mFollowCreditType = 0;
SetDespawnTime(5000);
me.StopMoving();
me.GetMotionMaster().MoveIdle();
StartDespawn();
GetScript().ProcessEventsFor(SmartEvents.FollowCompleted);
StopFollow(true);
return;
}
mFollowArrivedTimer = 1000;
}
else mFollowArrivedTimer -= diff;
else
mFollowArrivedTimer -= diff;
}
}
@@ -928,6 +1006,8 @@ namespace Game.AI
uint GetWPCount() { return (uint)mWayPoints?.Count; }
public void SetWPPauseTimer(uint time) { mWPPauseTimer = time; }
bool mIsCharmed;
uint mFollowCreditType;
uint mFollowArrivedTimer;
@@ -944,6 +1024,7 @@ namespace Game.AI
uint mLastWPIDReached;
bool mWPReached;
uint mWPPauseTimer;
uint mEscortNPCFlags;
WayPoint mLastWP;
Position mLastOOCPos;//set on enter combat
bool mCanRepeatPath;
@@ -962,6 +1043,10 @@ namespace Game.AI
uint mEscortInvokerCheckTimer;
bool mJustReset;
// Vehicle conditions
bool mHasConditions;
uint mConditionsTimer;
}
public class SmartGameObjectAI : GameObjectAI
@@ -979,18 +1064,23 @@ namespace Game.AI
public override void InitializeAI()
{
GetScript().OnInitialize(go);
GetScript().ProcessEventsFor(SmartEvents.Respawn);
// do not call respawn event if go is not spawned
if (go.isSpawned())
GetScript().ProcessEventsFor(SmartEvents.Respawn);
}
public override void Reset()
{
// call respawn event on reset
GetScript().ProcessEventsFor(SmartEvents.Respawn);
GetScript().OnReset();
}
public override bool GossipHello(Player player, bool isUse)
public override bool GossipHello(Player player, bool reportUse)
{
Log.outDebug(LogFilter.ScriptsAi, "SmartGameObjectAI.GossipHello");
GetScript().ProcessEventsFor(SmartEvents.GossipHello, player, 0, 0, false, null, go);
GetScript().ProcessEventsFor(SmartEvents.GossipHello, player, reportUse ? 1 : 0u, 0, false, null, go);
return false;
}
@@ -1054,6 +1144,11 @@ namespace Game.AI
GetScript().ProcessEventsFor(SmartEvents.GoEventInform, null, eventId);
}
public override void SpellHit(Unit unit, SpellInfo spellInfo)
{
GetScript().ProcessEventsFor(SmartEvents.SpellHit, unit, 0, 0, false, spellInfo);
}
public SmartScript GetScript() { return mScript; }
SmartScript mScript;