Core/SmartAI: Various fixes and extensions for smart scripts:
Port From (https://github.com/TrinityCore/TrinityCore/commit/a32d5cfa1762ae1158ee2f40b4c9b36e5b41913a)
This commit is contained in:
@@ -50,17 +50,42 @@ namespace Framework.Constants
|
|||||||
|
|
||||||
public enum SmartPhase
|
public enum SmartPhase
|
||||||
{
|
{
|
||||||
ALWAYS = 0,
|
Always = 0,
|
||||||
Phase1 = 1,
|
Phase1 = 1,
|
||||||
Phase2 = 2,
|
Phase2 = 2,
|
||||||
Phase3 = 3,
|
Phase3 = 3,
|
||||||
Phase4 = 4,
|
Phase4 = 4,
|
||||||
Phase5 = 5,
|
Phase5 = 5,
|
||||||
Phase6 = 6,
|
Phase6 = 6,
|
||||||
Max = 7,
|
Phase7 = 7,
|
||||||
All = (Phase1 | Phase2 | Phase3 | Phase4 | Phase5 | Phase6),
|
Phase8 = 8,
|
||||||
|
Phase9 = 9,
|
||||||
|
Phase10 = 10,
|
||||||
|
Phase11 = 11,
|
||||||
|
Phase12 = 12,
|
||||||
|
Max = 13,
|
||||||
|
|
||||||
Count = 6
|
Count = 12
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PhaseBits
|
||||||
|
{
|
||||||
|
PhaseAlwaysBit = 0,
|
||||||
|
Phase1Bit = 1,
|
||||||
|
Phase2Bit = 2,
|
||||||
|
Phase3Bit = 4,
|
||||||
|
Phase4Bit = 8,
|
||||||
|
Phase5Bit = 16,
|
||||||
|
Phase6Bit = 32,
|
||||||
|
Phase7Bit = 64,
|
||||||
|
Phase8Bit = 128,
|
||||||
|
Phase9Bit = 256,
|
||||||
|
Phase10Bit = 512,
|
||||||
|
Phase11Bit = 1024,
|
||||||
|
Phase12Bit = 2048,
|
||||||
|
All = Phase1Bit + Phase2Bit + Phase3Bit + Phase4Bit + Phase5Bit +
|
||||||
|
Phase6Bit + Phase7Bit + Phase8Bit + Phase9Bit + Phase10Bit +
|
||||||
|
Phase11Bit + Phase12Bit
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SmartEventFlags
|
public enum SmartEventFlags
|
||||||
@@ -114,7 +139,7 @@ namespace Framework.Constants
|
|||||||
{
|
{
|
||||||
UpdateIc = 0, // Initialmin, Initialmax, Repeatmin, Repeatmax
|
UpdateIc = 0, // Initialmin, Initialmax, Repeatmin, Repeatmax
|
||||||
UpdateOoc = 1, // Initialmin, Initialmax, Repeatmin, Repeatmax
|
UpdateOoc = 1, // Initialmin, Initialmax, Repeatmin, Repeatmax
|
||||||
HealtPct = 2, // Hpmin%, Hpmax%, Repeatmin, Repeatmax
|
HealthPct = 2, // Hpmin%, Hpmax%, Repeatmin, Repeatmax
|
||||||
ManaPct = 3, // Manamin%, Manamax%, Repeatmin, Repeatmax
|
ManaPct = 3, // Manamin%, Manamax%, Repeatmin, Repeatmax
|
||||||
Aggro = 4, // None
|
Aggro = 4, // None
|
||||||
Kill = 5, // Cooldownmin0, Cooldownmax1, Playeronly2, Else Creature Entry3
|
Kill = 5, // Cooldownmin0, Cooldownmax1, Playeronly2, Else Creature Entry3
|
||||||
@@ -176,7 +201,7 @@ namespace Framework.Constants
|
|||||||
Link = 61, // Internal Usage, No Params, Used To Link Together Multiple Events, Does Not Use Any Extra Resources To Iterate Event Lists Needlessly
|
Link = 61, // Internal Usage, No Params, Used To Link Together Multiple Events, Does Not Use Any Extra Resources To Iterate Event Lists Needlessly
|
||||||
GossipSelect = 62, // Menuid, Actionid
|
GossipSelect = 62, // Menuid, Actionid
|
||||||
JustCreated = 63, // None
|
JustCreated = 63, // None
|
||||||
GossipHello = 64, // None
|
GossipHello = 64, // noReportUse (for GOs)
|
||||||
FollowCompleted = 65, // None
|
FollowCompleted = 65, // None
|
||||||
DummyEffect = 66, // Spellid, Effectindex
|
DummyEffect = 66, // Spellid, Effectindex
|
||||||
IsBehindTarget = 67, // Cooldownmin, Cooldownmax
|
IsBehindTarget = 67, // Cooldownmin, Cooldownmax
|
||||||
@@ -232,7 +257,7 @@ namespace Framework.Constants
|
|||||||
FleeForAssist = 25, // With Emote
|
FleeForAssist = 25, // With Emote
|
||||||
CallGroupeventhappens = 26, // Questid
|
CallGroupeventhappens = 26, // Questid
|
||||||
CombatStop = 27, //
|
CombatStop = 27, //
|
||||||
Removeaurasfromspell = 28, // Spellid, 0 Removes All Auras
|
RemoveAurasFromSpell = 28, // Spellid, 0 Removes All Auras
|
||||||
Follow = 29, // Distance (0 = Default), Angle (0 = Default), Endcreatureentry, Credit, Credittype (0monsterkill, 1event)
|
Follow = 29, // Distance (0 = Default), Angle (0 = Default), Endcreatureentry, Credit, Credittype (0monsterkill, 1event)
|
||||||
RandomPhase = 30, // Phaseid1, Phaseid2, Phaseid3...
|
RandomPhase = 30, // Phaseid1, Phaseid2, Phaseid3...
|
||||||
RandomPhaseRange = 31, // Phasemin, Phasemax
|
RandomPhaseRange = 31, // Phasemin, Phasemax
|
||||||
@@ -264,7 +289,7 @@ namespace Framework.Constants
|
|||||||
RemoveItem = 57, // Itemid, Count
|
RemoveItem = 57, // Itemid, Count
|
||||||
InstallAiTemplate = 58, // Aitemplateid
|
InstallAiTemplate = 58, // Aitemplateid
|
||||||
SetRun = 59, // 0/1
|
SetRun = 59, // 0/1
|
||||||
SetFly = 60, // 0/1
|
SetDisableGravity = 60, // 0/1
|
||||||
SetSwim = 61, // 0/1
|
SetSwim = 61, // 0/1
|
||||||
Teleport = 62, // Mapid,
|
Teleport = 62, // Mapid,
|
||||||
SetCounter = 63, // id, value, reset (0/1)
|
SetCounter = 63, // id, value, reset (0/1)
|
||||||
@@ -323,7 +348,15 @@ namespace Framework.Constants
|
|||||||
SetCorpseDelay = 116, // timer
|
SetCorpseDelay = 116, // timer
|
||||||
DisableEvade = 117, // 0/1 (1 = disabled, 0 = enabled)
|
DisableEvade = 117, // 0/1 (1 = disabled, 0 = enabled)
|
||||||
GoSetGoState = 118,
|
GoSetGoState = 118,
|
||||||
// 119 - 127 : 3.3.5 reserved
|
SetCanFly = 119, // 0/1
|
||||||
|
RemoveAurasByType = 120, // type
|
||||||
|
SetSightDist = 121, // sightDistance
|
||||||
|
Flee = 122, // fleeTime
|
||||||
|
AddThreat = 123, // +threat, -threat
|
||||||
|
LoadEquipment = 124, // id
|
||||||
|
TriggerRandomTimedEvent = 125, // id min range, id max range
|
||||||
|
RemoveAllGameobjects = 126,
|
||||||
|
StopMotion = 127, // stopMoving, movementExpired
|
||||||
PlayAnimkit = 128,
|
PlayAnimkit = 128,
|
||||||
ScenePlay = 129, // sceneId
|
ScenePlay = 129, // sceneId
|
||||||
SceneCancel = 130, // sceneId
|
SceneCancel = 130, // sceneId
|
||||||
@@ -337,10 +370,10 @@ namespace Framework.Constants
|
|||||||
None = 0, // None, Defaulting To Invoket
|
None = 0, // None, Defaulting To Invoket
|
||||||
Self = 1, // Self Cast
|
Self = 1, // Self Cast
|
||||||
Victim = 2, // Our Current Target (Ie: Highest Aggro)
|
Victim = 2, // Our Current Target (Ie: Highest Aggro)
|
||||||
HostileSecondAggro = 3, // Second Highest Aggro
|
HostileSecondAggro = 3, // Second highest aggro, maxdist, playerOnly, powerType + 1
|
||||||
HostileLastAggro = 4, // Dead Last On Aggro
|
HostileLastAggro = 4, // Dead last on aggro, maxdist, playerOnly, powerType + 1
|
||||||
HostileRandom = 5, // Just Any Random Target On Our Threat List
|
HostileRandom = 5, // Just any random target on our threat list, maxdist, playerOnly, powerType + 1
|
||||||
HostileRandomNotTop = 6, // Any Random Target Except Top Threat
|
HostileRandomNotTop = 6, // Any random target except top threat, maxdist, playerOnly, powerType + 1
|
||||||
ActionInvoker = 7, // Unit Who Caused This Event To Occur
|
ActionInvoker = 7, // Unit Who Caused This Event To Occur
|
||||||
Position = 8, // Use Xyz From Event Params
|
Position = 8, // Use Xyz From Event Params
|
||||||
CreatureRange = 9, // Creatureentry(0any), Mindist, Maxdist
|
CreatureRange = 9, // Creatureentry(0any), Mindist, Maxdist
|
||||||
@@ -357,8 +390,8 @@ namespace Framework.Constants
|
|||||||
ClosestGameobject = 20, // Entry(0any), Maxdist
|
ClosestGameobject = 20, // Entry(0any), Maxdist
|
||||||
ClosestPlayer = 21, // Maxdist
|
ClosestPlayer = 21, // Maxdist
|
||||||
ActionInvokerVehicle = 22, // Unit'S Vehicle Who Caused This Event To Occur
|
ActionInvokerVehicle = 22, // Unit'S Vehicle Who Caused This Event To Occur
|
||||||
OwnerOrSummoner = 23, // Unit'S Owner Or Summoner
|
OwnerOrSummoner = 23, // Unit's owner or summoner, Use Owner/Charmer of this unit
|
||||||
ThreatList = 24, // All Units On Creature'S Threat List
|
ThreatList = 24, // All units on creature's threat list, maxdist
|
||||||
ClosestEnemy = 25, // maxDist, playerOnly
|
ClosestEnemy = 25, // maxDist, playerOnly
|
||||||
ClosestFriendly = 26, // maxDist, playerOnly
|
ClosestFriendly = 26, // maxDist, playerOnly
|
||||||
LootRecipients = 27, // all players that have tagged this creature (for kill credit)
|
LootRecipients = 27, // all players that have tagged this creature (for kill credit)
|
||||||
|
|||||||
@@ -316,34 +316,35 @@ namespace Game.AI
|
|||||||
|
|
||||||
void CheckConditions(uint diff)
|
void CheckConditions(uint diff)
|
||||||
{
|
{
|
||||||
if (m_ConditionsTimer < diff)
|
if (!m_HasConditions)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_ConditionsTimer <= diff)
|
||||||
{
|
{
|
||||||
if (m_HasConditions)
|
Vehicle vehicleKit = me.GetVehicleKit();
|
||||||
|
if (vehicleKit)
|
||||||
{
|
{
|
||||||
Vehicle vehicleKit = me.GetVehicleKit();
|
foreach (var pair in vehicleKit.Seats)
|
||||||
if (vehicleKit)
|
|
||||||
{
|
{
|
||||||
foreach (var pair in vehicleKit.Seats)
|
Unit passenger = Global.ObjAccessor.GetUnit(me, pair.Value.Passenger.Guid);
|
||||||
|
if (passenger)
|
||||||
{
|
{
|
||||||
Unit passenger = Global.ObjAccessor.GetUnit(me, pair.Value.Passenger.Guid);
|
Player player = passenger.ToPlayer();
|
||||||
if (passenger)
|
if (player)
|
||||||
{
|
{
|
||||||
Player player = passenger.ToPlayer();
|
if (!Global.ConditionMgr.IsObjectMeetingNotGroupedConditions(ConditionSourceType.CreatureTemplateVehicle, me.GetEntry(), player, me))
|
||||||
if (player)
|
|
||||||
{
|
{
|
||||||
if (!Global.ConditionMgr.IsObjectMeetingNotGroupedConditions(ConditionSourceType.CreatureTemplateVehicle, me.GetEntry(), player, me))
|
player.ExitVehicle();
|
||||||
{
|
return;//check other pessanger in next tick
|
||||||
player.ExitVehicle();
|
|
||||||
return;//check other pessanger in next tick
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ConditionsTimer = VEHICLE_CONDITION_CHECK_TIME;
|
m_ConditionsTimer = VEHICLE_CONDITION_CHECK_TIME;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_ConditionsTimer -= diff;
|
m_ConditionsTimer -= diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
using Framework.Dynamic;
|
using Framework.Dynamic;
|
||||||
using Game.Entities;
|
using Game.Entities;
|
||||||
|
using Game.Spells;
|
||||||
|
|
||||||
namespace Game.AI
|
namespace Game.AI
|
||||||
{
|
{
|
||||||
@@ -40,7 +41,7 @@ namespace Game.AI
|
|||||||
public virtual void SetGUID(ulong guid, int id = 0) { }
|
public virtual void SetGUID(ulong guid, int id = 0) { }
|
||||||
public virtual ulong GetGUID(int id = 0) { return 0; }
|
public virtual ulong GetGUID(int id = 0) { return 0; }
|
||||||
|
|
||||||
public virtual bool GossipHello(Player player, bool isUse) { return false; }
|
public virtual bool GossipHello(Player player, bool reportUse) { return false; }
|
||||||
public virtual bool GossipSelect(Player player, uint sender, uint action) { return false; }
|
public virtual bool GossipSelect(Player player, uint sender, uint action) { return false; }
|
||||||
public virtual bool GossipSelectCode(Player player, uint sender, uint action, string code) { return false; }
|
public virtual bool GossipSelectCode(Player player, uint sender, uint action, string code) { return false; }
|
||||||
public virtual bool QuestAccept(Player player, Quest quest) { return false; }
|
public virtual bool QuestAccept(Player player, Quest quest) { return false; }
|
||||||
@@ -55,6 +56,7 @@ namespace Game.AI
|
|||||||
public virtual void OnGameEvent(bool start, ushort eventId) { }
|
public virtual void OnGameEvent(bool start, ushort eventId) { }
|
||||||
public virtual void OnStateChanged(uint state, Unit unit) { }
|
public virtual void OnStateChanged(uint state, Unit unit) { }
|
||||||
public virtual void EventInform(uint eventId) { }
|
public virtual void EventInform(uint eventId) { }
|
||||||
|
public virtual void SpellHit(Unit unit, SpellInfo spellInfo) { }
|
||||||
|
|
||||||
protected TaskScheduler _scheduler;
|
protected TaskScheduler _scheduler;
|
||||||
protected EventMap _events;
|
protected EventMap _events;
|
||||||
|
|||||||
@@ -571,4 +571,74 @@ namespace Game.AI
|
|||||||
Unit _source;
|
Unit _source;
|
||||||
bool _playerOnly;
|
bool _playerOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Simple selector for units using mana
|
||||||
|
class PowerUsersSelector : ISelector
|
||||||
|
{
|
||||||
|
public PowerUsersSelector(Unit unit, PowerType power, float dist, bool playerOnly)
|
||||||
|
{
|
||||||
|
_me = unit;
|
||||||
|
_power = power;
|
||||||
|
_dist = dist;
|
||||||
|
_playerOnly = playerOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Check(Unit target)
|
||||||
|
{
|
||||||
|
if (_me == null || target == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (target.GetPowerType() != _power)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (_playerOnly && target.GetTypeId() != TypeId.Player)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (_dist > 0.0f && !_me.IsWithinCombatRange(target, _dist))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (_dist < 0.0f && _me.IsWithinCombatRange(target, -_dist))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Unit _me;
|
||||||
|
PowerType _power;
|
||||||
|
float _dist;
|
||||||
|
bool _playerOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
class FarthestTargetSelector : ISelector
|
||||||
|
{
|
||||||
|
public FarthestTargetSelector(Unit unit, float dist, bool playerOnly, bool inLos)
|
||||||
|
{
|
||||||
|
_me = unit;
|
||||||
|
_dist = dist;
|
||||||
|
_playerOnly = playerOnly;
|
||||||
|
_inLos = inLos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Check(Unit target)
|
||||||
|
{
|
||||||
|
if (_me == null || target == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (_playerOnly && target.GetTypeId() != TypeId.Player)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (_dist > 0.0f && !_me.IsWithinCombatRange(target, _dist))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (_inLos && !_me.IsWithinLOSInMap(target))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Unit _me;
|
||||||
|
float _dist;
|
||||||
|
bool _playerOnly;
|
||||||
|
bool _inLos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,20 +30,11 @@ namespace Game.AI
|
|||||||
{
|
{
|
||||||
public class SmartAI : CreatureAI
|
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;
|
const int SMART_MAX_AID_DIST = SMART_ESCORT_MAX_PLAYER_DIST / 2;
|
||||||
|
|
||||||
public SmartAI(Creature creature) : base(creature)
|
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
|
// Spawn in run mode
|
||||||
me.SetWalk(false);
|
me.SetWalk(false);
|
||||||
mRun = true;
|
mRun = true;
|
||||||
@@ -53,21 +44,10 @@ namespace Game.AI
|
|||||||
mCanAutoAttack = true;
|
mCanAutoAttack = true;
|
||||||
mCanCombatMove = true;
|
mCanCombatMove = true;
|
||||||
|
|
||||||
mForcedPaused = false;
|
|
||||||
mLastWPIDReached = 0;
|
|
||||||
mEscortQuestID = 0;
|
|
||||||
|
|
||||||
mDespawnTime = 0;
|
|
||||||
mDespawnState = 0;
|
|
||||||
|
|
||||||
mEscortInvokerCheckTimer = 1000;
|
mEscortInvokerCheckTimer = 1000;
|
||||||
mFollowGuid = ObjectGuid.Empty;
|
mFollowGuid = ObjectGuid.Empty;
|
||||||
mFollowDist = 0;
|
|
||||||
mFollowAngle = 0;
|
mHasConditions = Global.ConditionMgr.HasConditionsForNotGroupedEntry(ConditionSourceType.CreatureTemplateVehicle, creature.GetEntry());
|
||||||
mFollowCredit = 0;
|
|
||||||
mFollowArrivedEntry = 0;
|
|
||||||
mFollowCreditType = 0;
|
|
||||||
mInvincibilityHpLevel = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsAIControlled()
|
bool IsAIControlled()
|
||||||
@@ -133,20 +113,28 @@ namespace Game.AI
|
|||||||
StopPath();
|
StopPath();
|
||||||
|
|
||||||
if (path != 0)
|
if (path != 0)
|
||||||
|
{
|
||||||
if (!LoadPath(path))
|
if (!LoadPath(path))
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (mWayPoints.Empty())
|
if (mWayPoints.Empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AddEscortState(SmartEscortState.Escorting);
|
|
||||||
mCanRepeatPath = repeat;
|
|
||||||
|
|
||||||
SetRun(run);
|
|
||||||
|
|
||||||
WayPoint wp = GetNextWayPoint();
|
WayPoint wp = GetNextWayPoint();
|
||||||
if (wp != null)
|
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();
|
mLastOOCPos = me.GetPosition();
|
||||||
me.GetMotionMaster().MovePoint(wp.Id, wp.X, wp.Y, wp.Z);
|
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, wp.Id, GetScript().GetPathId());
|
||||||
@@ -221,6 +209,12 @@ namespace Game.AI
|
|||||||
mWPPauseTimer = 0;
|
mWPPauseTimer = 0;
|
||||||
mLastWP = null;
|
mLastWP = null;
|
||||||
|
|
||||||
|
if (mEscortNPCFlags != 0)
|
||||||
|
{
|
||||||
|
me.SetNpcFlags((NPCFlags)mEscortNPCFlags);
|
||||||
|
mEscortNPCFlags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (mCanRepeatPath)
|
if (mCanRepeatPath)
|
||||||
{
|
{
|
||||||
if (IsAIControlled())
|
if (IsAIControlled())
|
||||||
@@ -301,9 +295,15 @@ namespace Game.AI
|
|||||||
|
|
||||||
if (mEscortInvokerCheckTimer < diff)
|
if (mEscortInvokerCheckTimer < diff)
|
||||||
{
|
{
|
||||||
|
// Escort failed, no players in range
|
||||||
if (!IsEscortInvokerInRange())
|
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;
|
mEscortInvokerCheckTimer = 1000;
|
||||||
}
|
}
|
||||||
@@ -347,6 +347,7 @@ namespace Game.AI
|
|||||||
|
|
||||||
if ((!me.HasReactState(ReactStates.Passive) && me.IsInCombat()) || HasEscortState(SmartEscortState.Paused | SmartEscortState.Returning))
|
if ((!me.HasReactState(ReactStates.Passive) && me.IsInCombat()) || HasEscortState(SmartEscortState.Paused | SmartEscortState.Returning))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// handle next wp
|
// handle next wp
|
||||||
if (mWPReached)//reached WP
|
if (mWPReached)//reached WP
|
||||||
{
|
{
|
||||||
@@ -369,6 +370,7 @@ namespace Game.AI
|
|||||||
|
|
||||||
public override void UpdateAI(uint diff)
|
public override void UpdateAI(uint diff)
|
||||||
{
|
{
|
||||||
|
CheckConditions(diff);
|
||||||
GetScript().OnUpdate(diff);
|
GetScript().OnUpdate(diff);
|
||||||
UpdatePath(diff);
|
UpdatePath(diff);
|
||||||
UpdateDespawn(diff);
|
UpdateDespawn(diff);
|
||||||
@@ -390,10 +392,11 @@ namespace Game.AI
|
|||||||
var targets = GetScript().GetTargetList(SharedConst.SmartEscortTargets);
|
var targets = GetScript().GetTargetList(SharedConst.SmartEscortTargets);
|
||||||
if (targets != null)
|
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()))
|
if (targets.Count == 1 && GetScript().IsPlayer(targets.First()))
|
||||||
{
|
{
|
||||||
Player player = targets.First().ToPlayer();
|
Player player = targets.First().ToPlayer();
|
||||||
if (me.GetDistance(player) <= SMART_ESCORT_MAX_PLAYER_DIST)
|
if (me.GetDistance(player) <= checkDist)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
Group group = player.GetGroup();
|
Group group = player.GetGroup();
|
||||||
@@ -402,7 +405,7 @@ namespace Game.AI
|
|||||||
for (GroupReference groupRef = group.GetFirstMember(); groupRef != null; groupRef = groupRef.next())
|
for (GroupReference groupRef = group.GetFirstMember(); groupRef != null; groupRef = groupRef.next())
|
||||||
{
|
{
|
||||||
Player groupGuy = groupRef.GetSource();
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -413,13 +416,18 @@ namespace Game.AI
|
|||||||
{
|
{
|
||||||
if (GetScript().IsPlayer(obj))
|
if (GetScript().IsPlayer(obj))
|
||||||
{
|
{
|
||||||
if (me.GetDistance(obj.ToPlayer()) <= SMART_ESCORT_MAX_PLAYER_DIST)
|
if (me.GetDistance(obj.ToPlayer()) <= checkDist)
|
||||||
return true;
|
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)
|
void MovepointReached(uint id)
|
||||||
@@ -462,6 +470,12 @@ namespace Game.AI
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!IsAIControlled())
|
||||||
|
{
|
||||||
|
me.AttackStop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!_EnterEvadeMode())
|
if (!_EnterEvadeMode())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -538,7 +552,7 @@ 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?
|
||||||
@@ -634,7 +648,15 @@ namespace Game.AI
|
|||||||
|
|
||||||
public override void AttackStart(Unit who)
|
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)
|
if (mCanCombatMove)
|
||||||
me.GetMotionMaster().MoveChase(who);
|
me.GetMotionMaster().MoveChase(who);
|
||||||
@@ -701,9 +723,11 @@ namespace Game.AI
|
|||||||
{
|
{
|
||||||
mScript.OnInitialize(me);
|
mScript.OnInitialize(me);
|
||||||
if (!me.IsDead())
|
if (!me.IsDead())
|
||||||
|
{
|
||||||
mJustReset = true;
|
mJustReset = true;
|
||||||
JustReachedHome();
|
JustReachedHome();
|
||||||
GetScript().ProcessEventsFor(SmartEvents.Respawn);
|
GetScript().ProcessEventsFor(SmartEvents.Respawn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnCharmed(bool apply)
|
public override void OnCharmed(bool apply)
|
||||||
@@ -759,9 +783,14 @@ namespace Game.AI
|
|||||||
mRun = run;
|
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)
|
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)
|
public void SetFollow(Unit target, float dist, float angle, uint credit, uint end, uint creditType)
|
||||||
{
|
{
|
||||||
if (target == null)
|
if (target == null)
|
||||||
|
{
|
||||||
|
StopFollow(false);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mFollowGuid = target.GetGUID();
|
mFollowGuid = target.GetGUID();
|
||||||
mFollowDist = dist >= 0.0f ? dist : SharedConst.PetFollowDist;
|
mFollowDist = dist;
|
||||||
mFollowAngle = angle >= 0.0f ? angle : me.GetFollowAngle();
|
mFollowAngle = angle;
|
||||||
mFollowArrivedTimer = 1000;
|
mFollowArrivedTimer = 1000;
|
||||||
mFollowCredit = credit;
|
mFollowCredit = credit;
|
||||||
mFollowArrivedEntry = end;
|
mFollowArrivedEntry = end;
|
||||||
@@ -851,6 +883,35 @@ namespace Game.AI
|
|||||||
me.GetMotionMaster().MoveFollow(target, mFollowDist, mFollowAngle);
|
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)
|
public void SetScript9(SmartScriptHolder e, uint entry, Unit invoker)
|
||||||
{
|
{
|
||||||
if (invoker != null)
|
if (invoker != null)
|
||||||
@@ -871,6 +932,40 @@ namespace Game.AI
|
|||||||
GetScript().ProcessEventsFor(SmartEvents.OnSpellclick, clicker);
|
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)
|
public void UpdateFollow(uint diff)
|
||||||
{
|
{
|
||||||
if (!mFollowGuid.IsEmpty())
|
if (!mFollowGuid.IsEmpty())
|
||||||
@@ -879,31 +974,14 @@ namespace Game.AI
|
|||||||
{
|
{
|
||||||
if (me.FindNearestCreature(mFollowArrivedEntry, SharedConst.InteractionDistance, true) != null)
|
if (me.FindNearestCreature(mFollowArrivedEntry, SharedConst.InteractionDistance, true) != null)
|
||||||
{
|
{
|
||||||
Player player = Global.ObjAccessor.GetPlayer(me, mFollowGuid);
|
StopFollow(true);
|
||||||
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);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mFollowArrivedTimer = 1000;
|
mFollowArrivedTimer = 1000;
|
||||||
}
|
}
|
||||||
else mFollowArrivedTimer -= diff;
|
else
|
||||||
|
mFollowArrivedTimer -= diff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -928,6 +1006,8 @@ namespace Game.AI
|
|||||||
|
|
||||||
uint GetWPCount() { return (uint)mWayPoints?.Count; }
|
uint GetWPCount() { return (uint)mWayPoints?.Count; }
|
||||||
|
|
||||||
|
public void SetWPPauseTimer(uint time) { mWPPauseTimer = time; }
|
||||||
|
|
||||||
bool mIsCharmed;
|
bool mIsCharmed;
|
||||||
uint mFollowCreditType;
|
uint mFollowCreditType;
|
||||||
uint mFollowArrivedTimer;
|
uint mFollowArrivedTimer;
|
||||||
@@ -944,6 +1024,7 @@ namespace Game.AI
|
|||||||
uint mLastWPIDReached;
|
uint mLastWPIDReached;
|
||||||
bool mWPReached;
|
bool mWPReached;
|
||||||
uint mWPPauseTimer;
|
uint mWPPauseTimer;
|
||||||
|
uint mEscortNPCFlags;
|
||||||
WayPoint mLastWP;
|
WayPoint mLastWP;
|
||||||
Position mLastOOCPos;//set on enter combat
|
Position mLastOOCPos;//set on enter combat
|
||||||
bool mCanRepeatPath;
|
bool mCanRepeatPath;
|
||||||
@@ -962,6 +1043,10 @@ namespace Game.AI
|
|||||||
|
|
||||||
uint mEscortInvokerCheckTimer;
|
uint mEscortInvokerCheckTimer;
|
||||||
bool mJustReset;
|
bool mJustReset;
|
||||||
|
|
||||||
|
// Vehicle conditions
|
||||||
|
bool mHasConditions;
|
||||||
|
uint mConditionsTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SmartGameObjectAI : GameObjectAI
|
public class SmartGameObjectAI : GameObjectAI
|
||||||
@@ -979,18 +1064,23 @@ namespace Game.AI
|
|||||||
public override void InitializeAI()
|
public override void InitializeAI()
|
||||||
{
|
{
|
||||||
GetScript().OnInitialize(go);
|
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()
|
public override void Reset()
|
||||||
{
|
{
|
||||||
|
// call respawn event on reset
|
||||||
|
GetScript().ProcessEventsFor(SmartEvents.Respawn);
|
||||||
|
|
||||||
GetScript().OnReset();
|
GetScript().OnReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool GossipHello(Player player, bool isUse)
|
public override bool GossipHello(Player player, bool reportUse)
|
||||||
{
|
{
|
||||||
Log.outDebug(LogFilter.ScriptsAi, "SmartGameObjectAI.GossipHello");
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1054,6 +1144,11 @@ namespace Game.AI
|
|||||||
GetScript().ProcessEventsFor(SmartEvents.GoEventInform, null, eventId);
|
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; }
|
public SmartScript GetScript() { return mScript; }
|
||||||
|
|
||||||
SmartScript mScript;
|
SmartScript mScript;
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ namespace Game.AI
|
|||||||
temp.event_id = result.Read<ushort>(2);
|
temp.event_id = result.Read<ushort>(2);
|
||||||
temp.link = result.Read<ushort>(3);
|
temp.link = result.Read<ushort>(3);
|
||||||
temp.Event.type = (SmartEvents)result.Read<byte>(4);
|
temp.Event.type = (SmartEvents)result.Read<byte>(4);
|
||||||
temp.Event.event_phase_mask = result.Read<byte>(5);
|
temp.Event.event_phase_mask = result.Read<ushort>(5);
|
||||||
temp.Event.event_chance = result.Read<byte>(6);
|
temp.Event.event_chance = result.Read<byte>(6);
|
||||||
temp.Event.event_flags = (SmartEventFlags)result.Read<ushort>(7);
|
temp.Event.event_flags = (SmartEventFlags)result.Read<ushort>(7);
|
||||||
|
|
||||||
@@ -165,6 +165,47 @@ namespace Game.AI
|
|||||||
if (!IsEventValid(temp))
|
if (!IsEventValid(temp))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// specific check for timed events
|
||||||
|
switch (temp.Event.type)
|
||||||
|
{
|
||||||
|
case SmartEvents.Update:
|
||||||
|
case SmartEvents.UpdateOoc:
|
||||||
|
case SmartEvents.UpdateIc:
|
||||||
|
case SmartEvents.HealthPct:
|
||||||
|
case SmartEvents.TargetHealthPct:
|
||||||
|
case SmartEvents.ManaPct:
|
||||||
|
case SmartEvents.TargetManaPct:
|
||||||
|
case SmartEvents.Range:
|
||||||
|
case SmartEvents.FriendlyHealth:
|
||||||
|
case SmartEvents.FriendlyHealthPCT:
|
||||||
|
case SmartEvents.FriendlyMissingBuff:
|
||||||
|
case SmartEvents.HasAura:
|
||||||
|
case SmartEvents.TargetBuffed:
|
||||||
|
if (temp.Event.minMaxRepeat.repeatMin == 0 && temp.Event.minMaxRepeat.repeatMax == 0 && !temp.Event.event_flags.HasAnyFlag(SmartEventFlags.NotRepeatable) && temp.source_type != SmartScriptType.TimedActionlist)
|
||||||
|
{
|
||||||
|
temp.Event.event_flags |= SmartEventFlags.NotRepeatable;
|
||||||
|
Log.outError(LogFilter.Sql, $"SmartAIMgr.LoadSmartAIFromDB: Entry {temp.entryOrGuid} SourceType {temp.GetScriptType()}, Event {temp.event_id}, Missing Repeat flag.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SmartEvents.VictimCasting:
|
||||||
|
case SmartEvents.IsBehindTarget:
|
||||||
|
if (temp.Event.minMaxRepeat.min == 0 && temp.Event.minMaxRepeat.max == 0 && !temp.Event.event_flags.HasAnyFlag(SmartEventFlags.NotRepeatable) && temp.source_type != SmartScriptType.TimedActionlist)
|
||||||
|
{
|
||||||
|
temp.Event.event_flags |= SmartEventFlags.NotRepeatable;
|
||||||
|
Log.outError(LogFilter.Sql, $"SmartAIMgr.LoadSmartAIFromDB: Entry {temp.entryOrGuid} SourceType {temp.GetScriptType()}, Event {temp.event_id}, Missing Repeat flag.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SmartEvents.FriendlyIsCc:
|
||||||
|
if (temp.Event.friendlyCC.repeatMin == 0 && temp.Event.friendlyCC.repeatMax == 0 && !temp.Event.event_flags.HasAnyFlag(SmartEventFlags.NotRepeatable) && temp.source_type != SmartScriptType.TimedActionlist)
|
||||||
|
{
|
||||||
|
temp.Event.event_flags |= SmartEventFlags.NotRepeatable;
|
||||||
|
Log.outError(LogFilter.Sql, $"SmartAIMgr.LoadSmartAIFromDB: Entry {temp.entryOrGuid} SourceType {temp.GetScriptType()}, Event {temp.event_id}, Missing Repeat flag.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// creature entry / guid not found in storage, create empty event list for it and increase counters
|
// creature entry / guid not found in storage, create empty event list for it and increase counters
|
||||||
if (!mEventMap[(int)source_type].ContainsKey(temp.entryOrGuid))
|
if (!mEventMap[(int)source_type].ContainsKey(temp.entryOrGuid))
|
||||||
++count;
|
++count;
|
||||||
@@ -331,6 +372,7 @@ namespace Game.AI
|
|||||||
case SmartTargets.ClosestFriendly:
|
case SmartTargets.ClosestFriendly:
|
||||||
case SmartTargets.Stored:
|
case SmartTargets.Stored:
|
||||||
case SmartTargets.LootRecipients:
|
case SmartTargets.LootRecipients:
|
||||||
|
case SmartTargets.Farthest:
|
||||||
case SmartTargets.VehicleAccessory:
|
case SmartTargets.VehicleAccessory:
|
||||||
case SmartTargets.SpellTarget:
|
case SmartTargets.SpellTarget:
|
||||||
break;
|
break;
|
||||||
@@ -360,7 +402,7 @@ namespace Game.AI
|
|||||||
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: EntryOrGuid {0} using event({1}) has invalid action type ({2}), skipped.", e.entryOrGuid, e.event_id, e.GetActionType());
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: EntryOrGuid {0} using event({1}) has invalid action type ({2}), skipped.", e.entryOrGuid, e.event_id, e.GetActionType());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (e.Event.event_phase_mask > (uint)SmartPhase.All)
|
if (e.Event.event_phase_mask > (uint)PhaseBits.All)
|
||||||
{
|
{
|
||||||
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: EntryOrGuid {0} using event({1}) has invalid phase mask ({2}), skipped.", e.entryOrGuid, e.event_id, e.Event.event_phase_mask);
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: EntryOrGuid {0} using event({1}) has invalid phase mask ({2}), skipped.", e.entryOrGuid, e.event_id, e.Event.event_phase_mask);
|
||||||
return false;
|
return false;
|
||||||
@@ -391,7 +433,7 @@ namespace Game.AI
|
|||||||
case SmartEvents.Update:
|
case SmartEvents.Update:
|
||||||
case SmartEvents.UpdateIc:
|
case SmartEvents.UpdateIc:
|
||||||
case SmartEvents.UpdateOoc:
|
case SmartEvents.UpdateOoc:
|
||||||
case SmartEvents.HealtPct:
|
case SmartEvents.HealthPct:
|
||||||
case SmartEvents.ManaPct:
|
case SmartEvents.ManaPct:
|
||||||
case SmartEvents.TargetHealthPct:
|
case SmartEvents.TargetHealthPct:
|
||||||
case SmartEvents.TargetManaPct:
|
case SmartEvents.TargetManaPct:
|
||||||
@@ -768,7 +810,7 @@ namespace Game.AI
|
|||||||
|
|
||||||
if (e.Action.animKit.type > 3)
|
if (e.Action.animKit.type > 3)
|
||||||
{
|
{
|
||||||
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses invalid AnimKit type {4}, skipped.",
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses invalid AnimKit type {4}, skipped.",
|
||||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.animKit.type);
|
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.animKit.type);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -830,6 +872,12 @@ namespace Game.AI
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SmartActions.CrossCast:
|
||||||
|
{
|
||||||
|
if (!IsSpellValid(e, e.Action.crossCast.spell))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case SmartActions.AddAura:
|
case SmartActions.AddAura:
|
||||||
case SmartActions.InvokerCast:
|
case SmartActions.InvokerCast:
|
||||||
if (!IsSpellValid(e, e.Action.cast.spell))
|
if (!IsSpellValid(e, e.Action.cast.spell))
|
||||||
@@ -871,7 +919,7 @@ namespace Game.AI
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SmartActions.Removeaurasfromspell:
|
case SmartActions.RemoveAurasFromSpell:
|
||||||
if (e.Action.removeAura.spell != 0 && !IsSpellValid(e, e.Action.removeAura.spell))
|
if (e.Action.removeAura.spell != 0 && !IsSpellValid(e, e.Action.removeAura.spell))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
@@ -965,20 +1013,6 @@ namespace Game.AI
|
|||||||
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Map entry {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.teleport.mapID);
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Map entry {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.teleport.mapID);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case SmartActions.SetCounter:
|
|
||||||
if (e.Action.setCounter.counterId == 0)
|
|
||||||
{
|
|
||||||
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses wrong counterId {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.setCounter.counterId);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.Action.setCounter.value == 0)
|
|
||||||
{
|
|
||||||
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses wrong value {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.setCounter.value);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case SmartActions.InstallAiTemplate:
|
case SmartActions.InstallAiTemplate:
|
||||||
if (e.Action.installTtemplate.id >= (uint)SmartAITemplate.End)
|
if (e.Action.installTtemplate.id >= (uint)SmartAITemplate.End)
|
||||||
@@ -1155,6 +1189,15 @@ namespace Game.AI
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SmartActions.RemoveAurasByType:
|
||||||
|
{
|
||||||
|
if (e.Action.auraType.type >= (uint)AuraType.Total)
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Sql, $"Entry {e.entryOrGuid} SourceType {e.GetScriptType()} Event {e.event_id} Action {e.GetActionType()} uses invalid data type {e.Action.auraType.type} (value range 0-TOTAL_AURAS), skipped.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SmartActions.StartClosestWaypoint:
|
case SmartActions.StartClosestWaypoint:
|
||||||
@@ -1181,7 +1224,8 @@ namespace Game.AI
|
|||||||
case SmartActions.SetData:
|
case SmartActions.SetData:
|
||||||
case SmartActions.SetVisibility:
|
case SmartActions.SetVisibility:
|
||||||
case SmartActions.WpPause:
|
case SmartActions.WpPause:
|
||||||
case SmartActions.SetFly:
|
case SmartActions.SetDisableGravity:
|
||||||
|
case SmartActions.SetCanFly:
|
||||||
case SmartActions.SetRun:
|
case SmartActions.SetRun:
|
||||||
case SmartActions.SetSwim:
|
case SmartActions.SetSwim:
|
||||||
case SmartActions.ForceDespawn:
|
case SmartActions.ForceDespawn:
|
||||||
@@ -1202,7 +1246,6 @@ namespace Game.AI
|
|||||||
case SmartActions.SetNpcFlag:
|
case SmartActions.SetNpcFlag:
|
||||||
case SmartActions.AddNpcFlag:
|
case SmartActions.AddNpcFlag:
|
||||||
case SmartActions.RemoveNpcFlag:
|
case SmartActions.RemoveNpcFlag:
|
||||||
case SmartActions.CrossCast:
|
|
||||||
case SmartActions.CallRandomTimedActionlist:
|
case SmartActions.CallRandomTimedActionlist:
|
||||||
case SmartActions.RandomMove:
|
case SmartActions.RandomMove:
|
||||||
case SmartActions.SetUnitFieldBytes1:
|
case SmartActions.SetUnitFieldBytes1:
|
||||||
@@ -1227,6 +1270,13 @@ namespace Game.AI
|
|||||||
case SmartActions.MoveOffset:
|
case SmartActions.MoveOffset:
|
||||||
case SmartActions.SetCorpseDelay:
|
case SmartActions.SetCorpseDelay:
|
||||||
case SmartActions.DisableEvade:
|
case SmartActions.DisableEvade:
|
||||||
|
case SmartActions.SetSightDist:
|
||||||
|
case SmartActions.Flee:
|
||||||
|
case SmartActions.AddThreat:
|
||||||
|
case SmartActions.LoadEquipment:
|
||||||
|
case SmartActions.TriggerRandomTimedEvent:
|
||||||
|
case SmartActions.SetCounter:
|
||||||
|
case SmartActions.RemoveAllGameobjects:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Not handled action_type({0}), event_type({1}), Entry {2} SourceType {3} Event {4}, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Not handled action_type({0}), event_type({1}), Entry {2} SourceType {3} Event {4}, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
|
||||||
@@ -1452,7 +1502,7 @@ namespace Game.AI
|
|||||||
{
|
{
|
||||||
{ SmartEvents.UpdateIc, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.TimedActionlist },
|
{ SmartEvents.UpdateIc, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.TimedActionlist },
|
||||||
{ SmartEvents.UpdateOoc, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject + SmartScriptTypeMaskId.Instance },
|
{ SmartEvents.UpdateOoc, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject + SmartScriptTypeMaskId.Instance },
|
||||||
{ SmartEvents.HealtPct, SmartScriptTypeMaskId.Creature },
|
{ SmartEvents.HealthPct, SmartScriptTypeMaskId.Creature },
|
||||||
{ SmartEvents.ManaPct, SmartScriptTypeMaskId.Creature },
|
{ SmartEvents.ManaPct, SmartScriptTypeMaskId.Creature },
|
||||||
{ SmartEvents.Aggro, SmartScriptTypeMaskId.Creature },
|
{ SmartEvents.Aggro, SmartScriptTypeMaskId.Creature },
|
||||||
{ SmartEvents.Kill, SmartScriptTypeMaskId.Creature },
|
{ SmartEvents.Kill, SmartScriptTypeMaskId.Creature },
|
||||||
@@ -1679,6 +1729,9 @@ namespace Game.AI
|
|||||||
[FieldOffset(16)]
|
[FieldOffset(16)]
|
||||||
public TimedEvent timedEvent;
|
public TimedEvent timedEvent;
|
||||||
|
|
||||||
|
[FieldOffset(16)]
|
||||||
|
public GossipHello gossipHello;
|
||||||
|
|
||||||
[FieldOffset(16)]
|
[FieldOffset(16)]
|
||||||
public Gossip gossip;
|
public Gossip gossip;
|
||||||
|
|
||||||
@@ -1865,6 +1918,10 @@ namespace Game.AI
|
|||||||
{
|
{
|
||||||
public uint id;
|
public uint id;
|
||||||
}
|
}
|
||||||
|
public struct GossipHello
|
||||||
|
{
|
||||||
|
public uint noReportUse;
|
||||||
|
}
|
||||||
public struct Gossip
|
public struct Gossip
|
||||||
{
|
{
|
||||||
public uint sender;
|
public uint sender;
|
||||||
@@ -2083,6 +2140,9 @@ namespace Game.AI
|
|||||||
[FieldOffset(4)]
|
[FieldOffset(4)]
|
||||||
public SetRun setRun;
|
public SetRun setRun;
|
||||||
|
|
||||||
|
[FieldOffset(4)]
|
||||||
|
public SetDisableGravity setDisableGravity;
|
||||||
|
|
||||||
[FieldOffset(4)]
|
[FieldOffset(4)]
|
||||||
public SetFly setFly;
|
public SetFly setFly;
|
||||||
|
|
||||||
@@ -2137,6 +2197,9 @@ namespace Game.AI
|
|||||||
[FieldOffset(4)]
|
[FieldOffset(4)]
|
||||||
public Jump jump;
|
public Jump jump;
|
||||||
|
|
||||||
|
[FieldOffset(4)]
|
||||||
|
public FleeAssist fleeAssist;
|
||||||
|
|
||||||
[FieldOffset(4)]
|
[FieldOffset(4)]
|
||||||
public Flee flee;
|
public Flee flee;
|
||||||
|
|
||||||
@@ -2194,6 +2257,21 @@ namespace Game.AI
|
|||||||
[FieldOffset(4)]
|
[FieldOffset(4)]
|
||||||
public DisableEvade disableEvade;
|
public DisableEvade disableEvade;
|
||||||
|
|
||||||
|
[FieldOffset(4)]
|
||||||
|
public AuraType auraType;
|
||||||
|
|
||||||
|
[FieldOffset(4)]
|
||||||
|
public SightDistance sightDistance;
|
||||||
|
|
||||||
|
[FieldOffset(4)]
|
||||||
|
public LoadEquipment loadEquipment;
|
||||||
|
|
||||||
|
[FieldOffset(4)]
|
||||||
|
public RandomTimedEvent randomTimedEvent;
|
||||||
|
|
||||||
|
[FieldOffset(4)]
|
||||||
|
public StopMotion stopMotion;
|
||||||
|
|
||||||
[FieldOffset(4)]
|
[FieldOffset(4)]
|
||||||
public AnimKit animKit;
|
public AnimKit animKit;
|
||||||
|
|
||||||
@@ -2255,6 +2333,7 @@ namespace Game.AI
|
|||||||
public uint spell;
|
public uint spell;
|
||||||
public uint castFlags;
|
public uint castFlags;
|
||||||
public uint triggerFlags;
|
public uint triggerFlags;
|
||||||
|
public uint targetsLimit;
|
||||||
}
|
}
|
||||||
public struct CrossCast
|
public struct CrossCast
|
||||||
{
|
{
|
||||||
@@ -2460,6 +2539,10 @@ namespace Game.AI
|
|||||||
{
|
{
|
||||||
public uint run;
|
public uint run;
|
||||||
}
|
}
|
||||||
|
public struct SetDisableGravity
|
||||||
|
{
|
||||||
|
public uint disable;
|
||||||
|
}
|
||||||
public struct SetFly
|
public struct SetFly
|
||||||
{
|
{
|
||||||
public uint fly;
|
public uint fly;
|
||||||
@@ -2557,10 +2640,14 @@ namespace Game.AI
|
|||||||
public uint speedxy;
|
public uint speedxy;
|
||||||
public uint speedz;
|
public uint speedz;
|
||||||
}
|
}
|
||||||
public struct Flee
|
public struct FleeAssist
|
||||||
{
|
{
|
||||||
public uint withEmote;
|
public uint withEmote;
|
||||||
}
|
}
|
||||||
|
public struct Flee
|
||||||
|
{
|
||||||
|
public uint fleeTime;
|
||||||
|
}
|
||||||
public struct RespawnTarget
|
public struct RespawnTarget
|
||||||
{
|
{
|
||||||
public uint goRespawnTime;
|
public uint goRespawnTime;
|
||||||
@@ -2650,6 +2737,29 @@ namespace Game.AI
|
|||||||
{
|
{
|
||||||
public uint disable;
|
public uint disable;
|
||||||
}
|
}
|
||||||
|
public struct AuraType
|
||||||
|
{
|
||||||
|
public uint type;
|
||||||
|
}
|
||||||
|
public struct SightDistance
|
||||||
|
{
|
||||||
|
public uint dist;
|
||||||
|
}
|
||||||
|
public struct LoadEquipment
|
||||||
|
{
|
||||||
|
public uint id;
|
||||||
|
public uint force;
|
||||||
|
}
|
||||||
|
public struct RandomTimedEvent
|
||||||
|
{
|
||||||
|
public uint minId;
|
||||||
|
public uint maxId;
|
||||||
|
}
|
||||||
|
public struct StopMotion
|
||||||
|
{
|
||||||
|
public uint stopMovement;
|
||||||
|
public uint movementExpired;
|
||||||
|
}
|
||||||
public struct AnimKit
|
public struct AnimKit
|
||||||
{
|
{
|
||||||
public uint animKit;
|
public uint animKit;
|
||||||
@@ -2689,6 +2799,12 @@ namespace Game.AI
|
|||||||
[FieldOffset(16)]
|
[FieldOffset(16)]
|
||||||
public float o;
|
public float o;
|
||||||
|
|
||||||
|
[FieldOffset(20)]
|
||||||
|
public HostilRandom hostilRandom;
|
||||||
|
|
||||||
|
[FieldOffset(20)]
|
||||||
|
public Farthest farthest;
|
||||||
|
|
||||||
[FieldOffset(20)]
|
[FieldOffset(20)]
|
||||||
public UnitRange unitRange;
|
public UnitRange unitRange;
|
||||||
|
|
||||||
@@ -2728,6 +2844,9 @@ namespace Game.AI
|
|||||||
[FieldOffset(20)]
|
[FieldOffset(20)]
|
||||||
public ClosestFriendly closestFriendly;
|
public ClosestFriendly closestFriendly;
|
||||||
|
|
||||||
|
[FieldOffset(20)]
|
||||||
|
public Owner owner;
|
||||||
|
|
||||||
[FieldOffset(20)]
|
[FieldOffset(20)]
|
||||||
public Vehicle vehicle;
|
public Vehicle vehicle;
|
||||||
|
|
||||||
@@ -2735,7 +2854,18 @@ namespace Game.AI
|
|||||||
public Raw raw;
|
public Raw raw;
|
||||||
|
|
||||||
#region Structs
|
#region Structs
|
||||||
|
public struct HostilRandom
|
||||||
|
{
|
||||||
|
public uint maxDist;
|
||||||
|
public uint playerOnly;
|
||||||
|
public uint powerType;
|
||||||
|
}
|
||||||
|
public struct Farthest
|
||||||
|
{
|
||||||
|
public uint maxDist;
|
||||||
|
public uint playerOnly;
|
||||||
|
public uint isInLos;
|
||||||
|
}
|
||||||
public struct UnitRange
|
public struct UnitRange
|
||||||
{
|
{
|
||||||
public uint creature;
|
public uint creature;
|
||||||
@@ -2799,6 +2929,10 @@ namespace Game.AI
|
|||||||
{
|
{
|
||||||
public uint maxDist;
|
public uint maxDist;
|
||||||
}
|
}
|
||||||
|
public struct Owner
|
||||||
|
{
|
||||||
|
public uint useCharmerOrOwner;
|
||||||
|
}
|
||||||
public struct Vehicle
|
public struct Vehicle
|
||||||
{
|
{
|
||||||
public uint seat;
|
public uint seat;
|
||||||
|
|||||||
@@ -103,8 +103,7 @@ namespace Game.AI
|
|||||||
case SmartActions.Talk:
|
case SmartActions.Talk:
|
||||||
{
|
{
|
||||||
List<WorldObject> targets = GetTargets(e, unit);
|
List<WorldObject> targets = GetTargets(e, unit);
|
||||||
Creature talker = me;
|
Creature talker = e.Target.type == 0 ? me : null;
|
||||||
Player targetPlayer = null;
|
|
||||||
Unit talkTarget = null;
|
Unit talkTarget = null;
|
||||||
|
|
||||||
if (!targets.Empty())
|
if (!targets.Empty())
|
||||||
@@ -114,31 +113,33 @@ namespace Game.AI
|
|||||||
if (IsCreature(obj) && !obj.ToCreature().IsPet()) // Prevented sending text to pets.
|
if (IsCreature(obj) && !obj.ToCreature().IsPet()) // Prevented sending text to pets.
|
||||||
{
|
{
|
||||||
if (e.Action.talk.useTalkTarget != 0)
|
if (e.Action.talk.useTalkTarget != 0)
|
||||||
|
{
|
||||||
|
talker = me;
|
||||||
talkTarget = obj.ToCreature();
|
talkTarget = obj.ToCreature();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
talker = obj.ToCreature();
|
talker = obj.ToCreature();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (IsPlayer(obj))
|
else if (IsPlayer(obj))
|
||||||
{
|
{
|
||||||
targetPlayer = obj.ToPlayer();
|
talker = me;
|
||||||
|
talkTarget = obj.ToPlayer();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!talker)
|
if (talkTarget == null)
|
||||||
|
talkTarget = GetLastInvoker();
|
||||||
|
|
||||||
|
if (talker == null)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
mTalkerEntry = talker.GetEntry();
|
mTalkerEntry = talker.GetEntry();
|
||||||
mLastTextID = e.Action.talk.textGroupId;
|
mLastTextID = e.Action.talk.textGroupId;
|
||||||
mTextTimer = e.Action.talk.duration;
|
mTextTimer = e.Action.talk.duration;
|
||||||
|
|
||||||
if (IsPlayer(GetLastInvoker())) // used for $vars in texts and whisper target
|
|
||||||
talkTarget = GetLastInvoker();
|
|
||||||
else if (targetPlayer != null)
|
|
||||||
talkTarget = targetPlayer;
|
|
||||||
|
|
||||||
mUseTextTimer = true;
|
mUseTextTimer = true;
|
||||||
Global.CreatureTextMgr.SendChat(talker, (byte)e.Action.talk.textGroupId, talkTarget);
|
Global.CreatureTextMgr.SendChat(talker, (byte)e.Action.talk.textGroupId, talkTarget);
|
||||||
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction: SMART_ACTION_TALK: talker: {0} (Guid: {1}), textGuid: {2}",
|
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction: SMART_ACTION_TALK: talker: {0} (Guid: {1}), textGuid: {2}",
|
||||||
@@ -464,8 +465,17 @@ namespace Game.AI
|
|||||||
if (targets.Empty())
|
if (targets.Empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (e.Action.cast.targetsLimit > 0 && targets.Count > e.Action.cast.targetsLimit)
|
||||||
|
targets.RandomResize(e.Action.cast.targetsLimit);
|
||||||
|
|
||||||
foreach (var obj in targets)
|
foreach (var obj in targets)
|
||||||
{
|
{
|
||||||
|
if (go)
|
||||||
|
{
|
||||||
|
// may be nullptr
|
||||||
|
go.CastSpell(obj.ToUnit(), e.Action.cast.spell);
|
||||||
|
}
|
||||||
|
|
||||||
if (!IsUnit(obj))
|
if (!IsUnit(obj))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -548,6 +558,9 @@ namespace Game.AI
|
|||||||
if (targets.Empty())
|
if (targets.Empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (e.Action.cast.targetsLimit > 0 && targets.Count > e.Action.cast.targetsLimit)
|
||||||
|
targets.RandomResize(e.Action.cast.targetsLimit);
|
||||||
|
|
||||||
foreach (var obj in targets)
|
foreach (var obj in targets)
|
||||||
{
|
{
|
||||||
if (!IsUnit(obj))
|
if (!IsUnit(obj))
|
||||||
@@ -748,8 +761,8 @@ namespace Game.AI
|
|||||||
if (GetBaseObject() == null)
|
if (GetBaseObject() == null)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
IncPhase((int)e.Action.incEventPhase.inc);
|
IncPhase(e.Action.incEventPhase.inc);
|
||||||
DecPhase((int)e.Action.incEventPhase.dec);
|
DecPhase(e.Action.incEventPhase.dec);
|
||||||
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction. SMART_ACTION_INC_EVENT_PHASE: Creature {0} inc event phase by {1}, " +
|
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction. SMART_ACTION_INC_EVENT_PHASE: Creature {0} inc event phase by {1}, " +
|
||||||
"decrease by {2}", GetBaseObject().GetGUID().ToString(), e.Action.incEventPhase.inc, e.Action.incEventPhase.dec);
|
"decrease by {2}", GetBaseObject().GetGUID().ToString(), e.Action.incEventPhase.inc, e.Action.incEventPhase.dec);
|
||||||
break;
|
break;
|
||||||
@@ -769,7 +782,7 @@ namespace Game.AI
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
me.DoFleeToGetAssistance();
|
me.DoFleeToGetAssistance();
|
||||||
if (e.Action.flee.withEmote != 0)
|
if (e.Action.fleeAssist.withEmote != 0)
|
||||||
{
|
{
|
||||||
var builder = new BroadcastTextBuilder(me, ChatMsg.MonsterEmote, (uint)BroadcastTextIds.FleeForAssist, me.GetGender());
|
var builder = new BroadcastTextBuilder(me, ChatMsg.MonsterEmote, (uint)BroadcastTextIds.FleeForAssist, me.GetGender());
|
||||||
Global.CreatureTextMgr.SendChatPacket(me, builder, ChatMsg.Emote);
|
Global.CreatureTextMgr.SendChatPacket(me, builder, ChatMsg.Emote);
|
||||||
@@ -782,9 +795,11 @@ namespace Game.AI
|
|||||||
if (unit == null)
|
if (unit == null)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (IsPlayer(unit) && GetBaseObject() != null)
|
// If invoker was pet or charm
|
||||||
|
Player player = unit.GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||||
|
if (player && GetBaseObject() != null)
|
||||||
{
|
{
|
||||||
unit.ToPlayer().GroupEventHappens(e.Action.quest.questId, GetBaseObject());
|
player.GroupEventHappens(e.Action.quest.questId, GetBaseObject());
|
||||||
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction: SMART_ACTION_CALL_GROUPEVENTHAPPENS: Player {0}, group credit for quest {1}",
|
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction: SMART_ACTION_CALL_GROUPEVENTHAPPENS: Player {0}, group credit for quest {1}",
|
||||||
unit.GetGUID().ToString(), e.Action.quest.questId);
|
unit.GetGUID().ToString(), e.Action.quest.questId);
|
||||||
}
|
}
|
||||||
@@ -795,9 +810,9 @@ namespace Game.AI
|
|||||||
{
|
{
|
||||||
foreach (var seat in vehicle.Seats)
|
foreach (var seat in vehicle.Seats)
|
||||||
{
|
{
|
||||||
Player player = Global.ObjAccessor.GetPlayer(unit, seat.Value.Passenger.Guid);
|
Player player1 = Global.ObjAccessor.GetPlayer(unit, seat.Value.Passenger.Guid);
|
||||||
if (player != null)
|
if (player1 != null)
|
||||||
player.GroupEventHappens(e.Action.quest.questId, GetBaseObject());
|
player1.GroupEventHappens(e.Action.quest.questId, GetBaseObject());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -811,7 +826,7 @@ namespace Game.AI
|
|||||||
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction: SMART_ACTION_COMBAT_STOP: {0} CombatStop", me.GetGUID().ToString());
|
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction: SMART_ACTION_COMBAT_STOP: {0} CombatStop", me.GetGUID().ToString());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SmartActions.Removeaurasfromspell:
|
case SmartActions.RemoveAurasFromSpell:
|
||||||
{
|
{
|
||||||
List<WorldObject> targets = GetTargets(e, unit);
|
List<WorldObject> targets = GetTargets(e, unit);
|
||||||
if (targets.Empty())
|
if (targets.Empty())
|
||||||
@@ -841,13 +856,17 @@ namespace Game.AI
|
|||||||
|
|
||||||
List<WorldObject> targets = GetTargets(e, unit);
|
List<WorldObject> targets = GetTargets(e, unit);
|
||||||
if (targets.Empty())
|
if (targets.Empty())
|
||||||
|
{
|
||||||
|
((SmartAI)me.GetAI()).StopFollow(false);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var obj in targets)
|
foreach (var obj in targets)
|
||||||
{
|
{
|
||||||
if (IsUnit(obj))
|
if (IsUnit(obj))
|
||||||
{
|
{
|
||||||
((SmartAI)me.GetAI()).SetFollow(obj.ToUnit(), e.Action.follow.dist, e.Action.follow.angle, e.Action.follow.credit, e.Action.follow.entry, e.Action.follow.creditType);
|
float angle = e.Action.follow.angle > 6 ? (e.Action.follow.angle * (float)Math.PI / 180.0f) : e.Action.follow.angle;
|
||||||
|
((SmartAI)me.GetAI()).SetFollow(obj.ToUnit(), e.Action.follow.dist + 0.1f, angle, e.Action.follow.credit, e.Action.follow.entry, e.Action.follow.creditType);
|
||||||
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction: SMART_ACTION_FOLLOW: Creature {0} following target {1}",
|
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction: SMART_ACTION_FOLLOW: Creature {0} following target {1}",
|
||||||
me.GetGUID().ToString(), obj.GetGUID().ToString());
|
me.GetGUID().ToString(), obj.GetGUID().ToString());
|
||||||
break;
|
break;
|
||||||
@@ -1026,24 +1045,39 @@ namespace Game.AI
|
|||||||
}
|
}
|
||||||
case SmartActions.SetInCombatWithZone:
|
case SmartActions.SetInCombatWithZone:
|
||||||
{
|
{
|
||||||
if (me != null)
|
var targets = GetTargets(e, unit);
|
||||||
|
if (targets.Empty())
|
||||||
|
break;
|
||||||
|
|
||||||
|
foreach (var obj in targets)
|
||||||
{
|
{
|
||||||
me.SetInCombatWithZone();
|
if (IsCreature(obj))
|
||||||
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction: SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: Creature {0}", me.GetGUID().ToString());
|
{
|
||||||
|
me.SetInCombatWithZone();
|
||||||
|
Log.outDebug(LogFilter.ScriptsAi, $"SmartScript.ProcessAction: SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: Creature: {me.GetGUID().ToString()}, Target: {obj.GetGUID().ToString()}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SmartActions.CallForHelp:
|
case SmartActions.CallForHelp:
|
||||||
{
|
{
|
||||||
if (me != null)
|
var targets = GetTargets(e, unit);
|
||||||
|
if (targets.Empty())
|
||||||
|
break;
|
||||||
|
|
||||||
|
foreach (var obj in targets)
|
||||||
{
|
{
|
||||||
me.CallForHelp(e.Action.callHelp.range);
|
if (IsCreature(obj))
|
||||||
if (e.Action.callHelp.withEmote != 0)
|
|
||||||
{
|
{
|
||||||
var builder = new BroadcastTextBuilder(me, ChatMsg.Emote, (uint)BroadcastTextIds.CallForHelp, me.GetGender());
|
obj.ToCreature().CallForHelp(e.Action.callHelp.range);
|
||||||
Global.CreatureTextMgr.SendChatPacket(me, builder, ChatMsg.MonsterEmote);
|
if (e.Action.callHelp.withEmote != 0)
|
||||||
|
{
|
||||||
|
var builder = new BroadcastTextBuilder(me, ChatMsg.Emote, (uint)BroadcastTextIds.CallForHelp, me.GetGender());
|
||||||
|
Global.CreatureTextMgr.SendChatPacket(me, builder, ChatMsg.MonsterEmote);
|
||||||
|
}
|
||||||
|
Log.outDebug(LogFilter.ScriptsAi, $"SmartScript.ProcessAction: SMART_ACTION_CALL_FOR_HELP: Creature: {me.GetGUID().ToString()}, Target: {obj.GetGUID().ToString()}");
|
||||||
}
|
}
|
||||||
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction: SMART_ACTION_CALL_FOR_HELP: Creature {0}", me.GetGUID().ToString());
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1156,18 +1190,25 @@ namespace Game.AI
|
|||||||
}
|
}
|
||||||
case SmartActions.SetInvincibilityHpLevel:
|
case SmartActions.SetInvincibilityHpLevel:
|
||||||
{
|
{
|
||||||
if (me == null)
|
List<WorldObject> targets = GetTargets(e, unit);
|
||||||
|
if (targets.Empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
SmartAI ai = ((SmartAI)me.GetAI());
|
foreach (var obj in targets)
|
||||||
|
{
|
||||||
|
if (IsCreature(obj))
|
||||||
|
{
|
||||||
|
SmartAI ai = (SmartAI)me.GetAI();
|
||||||
|
if (ai == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (ai == null)
|
if (e.Action.invincHP.percent != 0)
|
||||||
break;
|
ai.SetInvincibilityHpLevel((uint)obj.ToCreature().CountPctFromMaxHealth((int)e.Action.invincHP.percent));
|
||||||
|
else
|
||||||
|
ai.SetInvincibilityHpLevel(e.Action.invincHP.minHP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (e.Action.invincHP.percent != 0)
|
|
||||||
ai.SetInvincibilityHpLevel((uint)me.CountPctFromMaxHealth((int)e.Action.invincHP.percent));
|
|
||||||
else
|
|
||||||
ai.SetInvincibilityHpLevel(e.Action.invincHP.minHP);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SmartActions.SetData:
|
case SmartActions.SetData:
|
||||||
@@ -1214,15 +1255,25 @@ namespace Game.AI
|
|||||||
}
|
}
|
||||||
case SmartActions.SetVisibility:
|
case SmartActions.SetVisibility:
|
||||||
{
|
{
|
||||||
if (me != null)
|
List<WorldObject> targets = GetTargets(e, unit);
|
||||||
me.SetVisible(Convert.ToBoolean(e.Action.visibility.state));
|
if (targets.Empty())
|
||||||
|
break;
|
||||||
|
|
||||||
|
foreach (var obj in targets)
|
||||||
|
if (IsUnit(obj))
|
||||||
|
obj.ToUnit().SetVisible(e.Action.visibility.state != 0);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SmartActions.SetActive:
|
case SmartActions.SetActive:
|
||||||
{
|
{
|
||||||
WorldObject baseObj = GetBaseObject();
|
List<WorldObject> targets = GetTargets(e, unit);
|
||||||
if (baseObj != null)
|
if (targets.Empty())
|
||||||
baseObj.setActive(e.Action.active.state != 0);
|
break;
|
||||||
|
|
||||||
|
foreach (var obj in targets)
|
||||||
|
obj.setActive(e.Action.active.state != 0);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SmartActions.AttackStart:
|
case SmartActions.AttackStart:
|
||||||
@@ -1234,15 +1285,9 @@ namespace Game.AI
|
|||||||
if (targets.Empty())
|
if (targets.Empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
foreach (var obj in targets)
|
Unit target = targets.SelectRandom().ToUnit();
|
||||||
{
|
if (target != null)
|
||||||
if (IsUnit(obj))
|
me.GetAI().AttackStart(target);
|
||||||
{
|
|
||||||
me.GetAI().AttackStart(obj.ToUnit());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1290,20 +1335,19 @@ namespace Game.AI
|
|||||||
{
|
{
|
||||||
foreach (var obj in targets)
|
foreach (var obj in targets)
|
||||||
{
|
{
|
||||||
if (!IsUnit(obj))
|
// allow gameobjects to summon gameobjects
|
||||||
continue;
|
//if (!IsUnit(*itr))
|
||||||
|
// continue;
|
||||||
|
|
||||||
Position pos = obj.GetPositionWithOffset(new Position(e.Target.x, e.Target.y, e.Target.z, e.Target.o));
|
Position pos = obj.GetPositionWithOffset(new Position(e.Target.x, e.Target.y, e.Target.z, e.Target.o));
|
||||||
Quaternion rot = Quaternion.fromEulerAnglesZYX(pos.GetOrientation(), 0.0f, 0.0f);
|
summoner.SummonGameObject(e.Action.summonGO.entry, pos, Quaternion.fromEulerAnglesZYX(pos.GetOrientation(), 0.0f, 0.0f), e.Action.summonGO.despawnTime);
|
||||||
summoner.SummonGameObject(e.Action.summonGO.entry, pos, rot, e.Action.summonGO.despawnTime);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.GetTargetType() != SmartTargets.Position)
|
if (e.GetTargetType() != SmartTargets.Position)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
Quaternion rot1 = Quaternion.fromEulerAnglesZYX(e.Target.o, 0.0f, 0.0f);
|
summoner.SummonGameObject(e.Action.summonGO.entry, new Position(e.Target.x, e.Target.y, e.Target.z, e.Target.o), Quaternion.fromEulerAnglesZYX(e.Target.o, 0.0f, 0.0f), e.Action.summonGO.despawnTime);
|
||||||
summoner.SummonGameObject(e.Action.summonGO.entry, new Position(e.Target.x, e.Target.y, e.Target.z, e.Target.o), rot1, e.Action.summonGO.despawnTime);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SmartActions.KillUnit:
|
case SmartActions.KillUnit:
|
||||||
@@ -1379,12 +1423,20 @@ namespace Game.AI
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SmartActions.SetFly:
|
case SmartActions.SetDisableGravity:
|
||||||
{
|
{
|
||||||
if (!IsSmart())
|
if (!IsSmart())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
((SmartAI)me.GetAI()).SetFly(e.Action.setFly.fly != 0 ? true : false);
|
((SmartAI)me.GetAI()).SetDisableGravity(e.Action.setDisableGravity.disable != 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SmartActions.SetCanFly:
|
||||||
|
{
|
||||||
|
if (!IsSmart())
|
||||||
|
break;
|
||||||
|
|
||||||
|
((SmartAI)me.GetAI()).SetCanFly(e.Action.setFly.fly != 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SmartActions.SetRun:
|
case SmartActions.SetRun:
|
||||||
@@ -1438,11 +1490,24 @@ namespace Game.AI
|
|||||||
if (!IsSmart())
|
if (!IsSmart())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
bool run = e.Action.wpStart.run != 0 ? true : false;
|
bool run = e.Action.wpStart.run != 0;
|
||||||
uint entry = e.Action.wpStart.pathID;
|
uint entry = e.Action.wpStart.pathID;
|
||||||
bool repeat = e.Action.wpStart.repeat != 0 ? true : false;
|
bool repeat = e.Action.wpStart.repeat != 0;
|
||||||
|
|
||||||
|
// ensure that SMART_ESCORT_TARGETS contains at least one player reference
|
||||||
List<WorldObject> targets = GetTargets(e, unit);
|
List<WorldObject> targets = GetTargets(e, unit);
|
||||||
StoreTargetList(targets, SharedConst.SmartEscortTargets);
|
if (!targets.Empty())
|
||||||
|
{
|
||||||
|
foreach (var obj in targets)
|
||||||
|
{
|
||||||
|
if (IsPlayer(obj))
|
||||||
|
{
|
||||||
|
StoreTargetList(targets, SharedConst.SmartEscortTargets);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
me.SetReactState((ReactStates)e.Action.wpStart.reactState);
|
me.SetReactState((ReactStates)e.Action.wpStart.reactState);
|
||||||
((SmartAI)me.GetAI()).StartPath(run, entry, repeat, unit);
|
((SmartAI)me.GetAI()).StartPath(run, entry, repeat, unit);
|
||||||
|
|
||||||
@@ -1477,7 +1542,7 @@ namespace Game.AI
|
|||||||
if (!IsSmart())
|
if (!IsSmart())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
((SmartAI)me.GetAI()).ResumePath();
|
((SmartAI)me.GetAI()).SetWPPauseTimer(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SmartActions.SetOrientation:
|
case SmartActions.SetOrientation:
|
||||||
@@ -1520,34 +1585,32 @@ namespace Game.AI
|
|||||||
|
|
||||||
WorldObject target = null;
|
WorldObject target = null;
|
||||||
|
|
||||||
if (e.GetTargetType() == SmartTargets.CreatureRange || e.GetTargetType() == SmartTargets.CreatureGuid ||
|
/*if (e.GetTargetType() == SmartTargets.CreatureRange || e.GetTargetType() == SmartTargets.CreatureGuid ||
|
||||||
e.GetTargetType() == SmartTargets.CreatureDistance || e.GetTargetType() == SmartTargets.GameobjectRange ||
|
e.GetTargetType() == SmartTargets.CreatureDistance || e.GetTargetType() == SmartTargets.GameobjectRange ||
|
||||||
e.GetTargetType() == SmartTargets.GameobjectGuid || e.GetTargetType() == SmartTargets.GameobjectDistance ||
|
e.GetTargetType() == SmartTargets.GameobjectGuid || e.GetTargetType() == SmartTargets.GameobjectDistance ||
|
||||||
e.GetTargetType() == SmartTargets.ClosestCreature || e.GetTargetType() == SmartTargets.ClosestGameobject ||
|
e.GetTargetType() == SmartTargets.ClosestCreature || e.GetTargetType() == SmartTargets.ClosestGameobject ||
|
||||||
e.GetTargetType() == SmartTargets.OwnerOrSummoner || e.GetTargetType() == SmartTargets.ActionInvoker ||
|
e.GetTargetType() == SmartTargets.OwnerOrSummoner || e.GetTargetType() == SmartTargets.ActionInvoker ||
|
||||||
e.GetTargetType() == SmartTargets.ClosestEnemy || e.GetTargetType() == SmartTargets.ClosestFriendly)
|
e.GetTargetType() == SmartTargets.ClosestEnemy || e.GetTargetType() == SmartTargets.ClosestFriendly)*/
|
||||||
{
|
{
|
||||||
List<WorldObject> targets = GetTargets(e, unit);
|
List<WorldObject> targets = GetTargets(e, unit);
|
||||||
if (targets.Empty())
|
if (targets.Empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
target = targets.First();
|
// we want to move to random element
|
||||||
|
target = targets.SelectRandom();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!target)
|
if (!target)
|
||||||
{
|
{
|
||||||
float x = e.Target.x;
|
Position dest = new Position(e.Target.x, e.Target.y, e.Target.z);
|
||||||
float y = e.Target.y;
|
|
||||||
float z = e.Target.z;
|
|
||||||
float o = 0;
|
|
||||||
if (e.Action.moveToPos.transport != 0)
|
if (e.Action.moveToPos.transport != 0)
|
||||||
{
|
{
|
||||||
ITransport trans = me.GetDirectTransport();
|
ITransport trans = me.GetDirectTransport();
|
||||||
if (trans != null)
|
if (trans != null)
|
||||||
trans.CalculatePassengerPosition(ref x, ref y, ref z, ref o);
|
trans.CalculatePassengerPosition(ref dest.posX, ref dest.posY, ref dest.posZ, ref dest.Orientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
me.GetMotionMaster().MovePoint(e.Action.moveToPos.pointId, x, y, z, e.Action.moveToPos.disablePathfinding == 0);
|
me.GetMotionMaster().MovePoint(e.Action.moveToPos.pointId, dest, e.Action.moveToPos.disablePathfinding == 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1555,7 +1618,7 @@ namespace Game.AI
|
|||||||
target.GetPosition(out x, out y, out z);
|
target.GetPosition(out x, out y, out z);
|
||||||
if (e.Action.moveToPos.contactDistance > 0)
|
if (e.Action.moveToPos.contactDistance > 0)
|
||||||
target.GetContactPoint(me, out x, out y, out z, e.Action.moveToPos.contactDistance);
|
target.GetContactPoint(me, out x, out y, out z, e.Action.moveToPos.contactDistance);
|
||||||
me.GetMotionMaster().MovePoint(e.Action.moveToPos.pointId, x, y, z, e.Action.moveToPos.disablePathfinding == 0);
|
me.GetMotionMaster().MovePoint(e.Action.moveToPos.pointId, x + e.Target.x, y + e.Target.y, z + e.Target.z, e.Action.moveToPos.disablePathfinding == 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1570,10 +1633,15 @@ namespace Game.AI
|
|||||||
if (IsCreature(obj))
|
if (IsCreature(obj))
|
||||||
obj.ToCreature().Respawn();
|
obj.ToCreature().Respawn();
|
||||||
else if (IsGameObject(obj))
|
else if (IsGameObject(obj))
|
||||||
obj.ToGameObject().SetRespawnTime((int)e.Action.respawnTarget.goRespawnTime);
|
{
|
||||||
|
// do not modify respawndelay of already spawned gameobjects
|
||||||
|
if (obj.ToGameObject().isSpawnedByDefault())
|
||||||
|
obj.ToGameObject().Respawn();
|
||||||
|
else
|
||||||
|
obj.ToGameObject().SetRespawnTime((int)e.Action.respawnTarget.goRespawnTime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SmartActions.CloseGossip:
|
case SmartActions.CloseGossip:
|
||||||
@@ -1664,6 +1732,10 @@ namespace Game.AI
|
|||||||
}
|
}
|
||||||
case SmartActions.TriggerTimedEvent:
|
case SmartActions.TriggerTimedEvent:
|
||||||
ProcessEventsFor(SmartEvents.TimedEventTriggered, null, e.Action.timeEvent.id);
|
ProcessEventsFor(SmartEvents.TimedEventTriggered, null, e.Action.timeEvent.id);
|
||||||
|
|
||||||
|
// remove this event if not repeatable
|
||||||
|
if (e.Event.event_flags.HasAnyFlag(SmartEventFlags.NotRepeatable))
|
||||||
|
mRemIDs.Add(e.Action.timeEvent.id);
|
||||||
break;
|
break;
|
||||||
case SmartActions.RemoveTimedEvent:
|
case SmartActions.RemoveTimedEvent:
|
||||||
mRemIDs.Add(e.Action.timeEvent.id);
|
mRemIDs.Add(e.Action.timeEvent.id);
|
||||||
@@ -2306,7 +2378,7 @@ namespace Game.AI
|
|||||||
WayPoint closestWp = null;
|
WayPoint closestWp = null;
|
||||||
|
|
||||||
var targets = GetTargets(e, unit);
|
var targets = GetTargets(e, unit);
|
||||||
if (targets != null)
|
if (!targets.Empty())
|
||||||
{
|
{
|
||||||
foreach (var obj in targets)
|
foreach (var obj in targets)
|
||||||
{
|
{
|
||||||
@@ -2357,7 +2429,7 @@ namespace Game.AI
|
|||||||
bool onlySelf = e.Action.randomSound.onlySelf != 0;
|
bool onlySelf = e.Action.randomSound.onlySelf != 0;
|
||||||
|
|
||||||
var targets = GetTargets(e, unit);
|
var targets = GetTargets(e, unit);
|
||||||
if (targets != null)
|
if (!targets.Empty())
|
||||||
{
|
{
|
||||||
foreach (var obj in targets)
|
foreach (var obj in targets)
|
||||||
{
|
{
|
||||||
@@ -2375,7 +2447,7 @@ namespace Game.AI
|
|||||||
case SmartActions.SetCorpseDelay:
|
case SmartActions.SetCorpseDelay:
|
||||||
{
|
{
|
||||||
var targets = GetTargets(e, unit);
|
var targets = GetTargets(e, unit);
|
||||||
if (targets == null)
|
if (targets.Empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
foreach (var obj in targets)
|
foreach (var obj in targets)
|
||||||
@@ -2392,6 +2464,104 @@ namespace Game.AI
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
((SmartAI)me.GetAI()).SetEvadeDisabled(e.Action.disableEvade.disable != 0);
|
((SmartAI)me.GetAI()).SetEvadeDisabled(e.Action.disableEvade.disable != 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SmartActions.RemoveAurasByType: // can be used to exit vehicle for example
|
||||||
|
{
|
||||||
|
var targets = GetTargets(e, unit);
|
||||||
|
if (targets.Empty())
|
||||||
|
break;
|
||||||
|
|
||||||
|
foreach (var obj in targets)
|
||||||
|
if (IsUnit(obj))
|
||||||
|
obj.ToUnit().RemoveAurasByType((AuraType)e.Action.auraType.type);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SmartActions.SetSightDist:
|
||||||
|
{
|
||||||
|
var targets = GetTargets(e, unit);
|
||||||
|
if (targets.Empty())
|
||||||
|
break;
|
||||||
|
|
||||||
|
foreach (var obj in targets)
|
||||||
|
if (IsCreature(obj))
|
||||||
|
obj.ToCreature().m_SightDistance = e.Action.sightDistance.dist;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SmartActions.Flee:
|
||||||
|
{
|
||||||
|
var targets = GetTargets(e, unit);
|
||||||
|
if (targets.Empty())
|
||||||
|
break;
|
||||||
|
|
||||||
|
foreach (var obj in targets)
|
||||||
|
if (IsCreature(obj))
|
||||||
|
obj.ToCreature().GetMotionMaster().MoveFleeing(me, e.Action.flee.fleeTime);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SmartActions.AddThreat:
|
||||||
|
{
|
||||||
|
var targets = GetTargets(e, unit);
|
||||||
|
if (targets.Empty())
|
||||||
|
break;
|
||||||
|
|
||||||
|
foreach (var obj in targets)
|
||||||
|
if (IsUnit(obj))
|
||||||
|
me.AddThreat(obj.ToUnit(), (float)e.Action.threatPCT.threatINC - (float)e.Action.threatPCT.threatDEC);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SmartActions.LoadEquipment:
|
||||||
|
{
|
||||||
|
var targets = GetTargets(e, unit);
|
||||||
|
if (targets.Empty())
|
||||||
|
break;
|
||||||
|
|
||||||
|
foreach (var obj in targets)
|
||||||
|
if (IsCreature(obj))
|
||||||
|
obj.ToCreature().LoadEquipment((int)e.Action.loadEquipment.id, e.Action.loadEquipment.force != 0);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SmartActions.TriggerRandomTimedEvent:
|
||||||
|
{
|
||||||
|
uint eventId = RandomHelper.URand(e.Action.randomTimedEvent.minId, e.Action.randomTimedEvent.maxId);
|
||||||
|
ProcessEventsFor(SmartEvents.TimedEventTriggered, null, eventId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SmartActions.RemoveAllGameobjects:
|
||||||
|
{
|
||||||
|
var targets = GetTargets(e, unit);
|
||||||
|
if (targets.Empty())
|
||||||
|
break;
|
||||||
|
|
||||||
|
foreach (var obj in targets)
|
||||||
|
if (IsUnit(obj))
|
||||||
|
obj.ToUnit().RemoveAllGameObjects();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SmartActions.StopMotion:
|
||||||
|
{
|
||||||
|
var targets = GetTargets(e, unit);
|
||||||
|
if (targets.Empty())
|
||||||
|
break;
|
||||||
|
|
||||||
|
foreach (var obj in targets)
|
||||||
|
{
|
||||||
|
if (IsUnit(obj))
|
||||||
|
{
|
||||||
|
if (e.Action.stopMotion.stopMovement != 0)
|
||||||
|
obj.ToUnit().StopMoving();
|
||||||
|
if (e.Action.stopMotion.movementExpired != 0)
|
||||||
|
obj.ToUnit().GetMotionMaster().MovementExpired();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SmartActions.PlayAnimkit:
|
case SmartActions.PlayAnimkit:
|
||||||
@@ -2471,10 +2641,15 @@ namespace Game.AI
|
|||||||
|
|
||||||
void ProcessTimedAction(SmartScriptHolder e, uint min, uint max, Unit unit = null, uint var0 = 0, uint var1 = 0, bool bvar = false, SpellInfo spell = null, GameObject gob = null, string varString = "")
|
void ProcessTimedAction(SmartScriptHolder e, uint min, uint max, Unit unit = null, uint var0 = 0, uint var1 = 0, bool bvar = false, SpellInfo spell = null, GameObject gob = null, string varString = "")
|
||||||
{
|
{
|
||||||
|
// We may want to execute action rarely and because of this if condition is not fulfilled the action will be rechecked in a long time
|
||||||
if (Global.ConditionMgr.IsObjectMeetingSmartEventConditions(e.entryOrGuid, e.event_id, e.source_type, unit, GetBaseObject()))
|
if (Global.ConditionMgr.IsObjectMeetingSmartEventConditions(e.entryOrGuid, e.event_id, e.source_type, unit, GetBaseObject()))
|
||||||
|
{
|
||||||
ProcessAction(e, unit, var0, var1, bvar, spell, gob, varString);
|
ProcessAction(e, unit, var0, var1, bvar, spell, gob, varString);
|
||||||
|
|
||||||
RecalcTimer(e, min, max);
|
RecalcTimer(e, min, max);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
RecalcTimer(e, Math.Min(min, 5000), Math.Min(min, 5000));
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstallTemplate(SmartScriptHolder e)
|
void InstallTemplate(SmartScriptHolder e)
|
||||||
@@ -2615,36 +2790,79 @@ namespace Game.AI
|
|||||||
case SmartTargets.HostileSecondAggro:
|
case SmartTargets.HostileSecondAggro:
|
||||||
if (me != null)
|
if (me != null)
|
||||||
{
|
{
|
||||||
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.TopAggro, 1);
|
if (e.Target.hostilRandom.powerType != 0)
|
||||||
if (u != null)
|
{
|
||||||
l.Add(u);
|
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.TopAggro, 1, new PowerUsersSelector(me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0));
|
||||||
|
if (u != null)
|
||||||
|
l.Add(u);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.TopAggro, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0);
|
||||||
|
if (u != null)
|
||||||
|
l.Add(u);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SmartTargets.HostileLastAggro:
|
case SmartTargets.HostileLastAggro:
|
||||||
if (me != null)
|
if (me != null)
|
||||||
{
|
{
|
||||||
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.BottomAggro, 0);
|
if (e.Target.hostilRandom.powerType != 0)
|
||||||
if (u != null)
|
{
|
||||||
l.Add(u);
|
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.BottomAggro, 1, new PowerUsersSelector(me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0));
|
||||||
|
if (u != null)
|
||||||
|
l.Add(u);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.BottomAggro, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0);
|
||||||
|
if (u != null)
|
||||||
|
l.Add(u);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SmartTargets.HostileRandom:
|
case SmartTargets.HostileRandom:
|
||||||
if (me != null)
|
if (me != null)
|
||||||
{
|
{
|
||||||
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.Random, 0);
|
if (e.Target.hostilRandom.powerType != 0)
|
||||||
if (u != null)
|
{
|
||||||
l.Add(u);
|
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.Random, 1, new PowerUsersSelector(me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0));
|
||||||
|
if (u != null)
|
||||||
|
l.Add(u);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.Random, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0);
|
||||||
|
if (u != null)
|
||||||
|
l.Add(u);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SmartTargets.HostileRandomNotTop:
|
case SmartTargets.HostileRandomNotTop:
|
||||||
if (me != null)
|
if (me != null)
|
||||||
{
|
{
|
||||||
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.Random, 1);
|
if (e.Target.hostilRandom.powerType != 0)
|
||||||
|
{
|
||||||
|
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.Random, 1, new PowerUsersSelector(me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0));
|
||||||
|
if (u != null)
|
||||||
|
l.Add(u);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.Random, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0);
|
||||||
|
if (u != null)
|
||||||
|
l.Add(u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SmartTargets.Farthest:
|
||||||
|
if (me)
|
||||||
|
{
|
||||||
|
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.Farthest, 0, new FarthestTargetSelector(me, (float)e.Target.farthest.maxDist, e.Target.farthest.playerOnly != 0, e.Target.farthest.isInLos != 0));
|
||||||
if (u != null)
|
if (u != null)
|
||||||
l.Add(u);
|
l.Add(u);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SmartTargets.None:
|
|
||||||
case SmartTargets.ActionInvoker:
|
case SmartTargets.ActionInvoker:
|
||||||
if (scriptTrigger != null)
|
if (scriptTrigger != null)
|
||||||
l.Add(scriptTrigger);
|
l.Add(scriptTrigger);
|
||||||
@@ -2794,7 +3012,7 @@ namespace Game.AI
|
|||||||
if (!list.Empty())
|
if (!list.Empty())
|
||||||
l.AddRange(list);
|
l.AddRange(list);
|
||||||
|
|
||||||
return l;
|
break;
|
||||||
}
|
}
|
||||||
case SmartTargets.ClosestCreature:
|
case SmartTargets.ClosestCreature:
|
||||||
{
|
{
|
||||||
@@ -2812,9 +3030,10 @@ namespace Game.AI
|
|||||||
}
|
}
|
||||||
case SmartTargets.ClosestPlayer:
|
case SmartTargets.ClosestPlayer:
|
||||||
{
|
{
|
||||||
if (me)
|
WorldObject obj = GetBaseObject();
|
||||||
|
if (obj != null)
|
||||||
{
|
{
|
||||||
Player target = me.SelectNearestPlayer(e.Target.playerDistance.dist);
|
Player target = obj.SelectNearestPlayer(e.Target.playerDistance.dist);
|
||||||
if (target)
|
if (target)
|
||||||
l.Add(target);
|
l.Add(target);
|
||||||
}
|
}
|
||||||
@@ -2843,6 +3062,23 @@ namespace Game.AI
|
|||||||
if (owner != null)
|
if (owner != null)
|
||||||
l.Add(owner);
|
l.Add(owner);
|
||||||
}
|
}
|
||||||
|
else if (go != null)
|
||||||
|
{
|
||||||
|
Unit owner = Global.ObjAccessor.GetUnit(go, go.GetOwnerGUID());
|
||||||
|
if (owner)
|
||||||
|
l.Add(owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get owner of owner
|
||||||
|
if (e.Target.owner.useCharmerOrOwner != 0 && !l.Empty())
|
||||||
|
{
|
||||||
|
Unit owner = l.First().ToUnit();
|
||||||
|
l.Clear();
|
||||||
|
|
||||||
|
Unit unitBase = Global.ObjAccessor.GetUnit(owner, owner.GetCharmerOrOwnerGUID());
|
||||||
|
if (unitBase != null)
|
||||||
|
l.Add(unitBase);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SmartTargets.ThreatList:
|
case SmartTargets.ThreatList:
|
||||||
@@ -2854,7 +3090,8 @@ namespace Game.AI
|
|||||||
{
|
{
|
||||||
Unit temp = Global.ObjAccessor.GetUnit(me, i.getUnitGuid());
|
Unit temp = Global.ObjAccessor.GetUnit(me, i.getUnitGuid());
|
||||||
if (temp != null)
|
if (temp != null)
|
||||||
l.Add(temp);
|
if (e.Target.hostilRandom.maxDist == 0 || me.IsWithinCombatRange(temp, (float)e.Target.hostilRandom.maxDist))
|
||||||
|
l.Add(temp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -2971,7 +3208,7 @@ namespace Game.AI
|
|||||||
return;
|
return;
|
||||||
ProcessTimedAction(e, e.Event.minMaxRepeat.repeatMin, e.Event.minMaxRepeat.repeatMax);
|
ProcessTimedAction(e, e.Event.minMaxRepeat.repeatMin, e.Event.minMaxRepeat.repeatMax);
|
||||||
break;
|
break;
|
||||||
case SmartEvents.HealtPct:
|
case SmartEvents.HealthPct:
|
||||||
{
|
{
|
||||||
if (me == null || !me.IsInCombat() || me.GetMaxHealth() == 0)
|
if (me == null || !me.IsInCombat() || me.GetMaxHealth() == 0)
|
||||||
return;
|
return;
|
||||||
@@ -3018,6 +3255,8 @@ namespace Game.AI
|
|||||||
|
|
||||||
if (me.IsInRange(me.GetVictim(), e.Event.minMaxRepeat.min, e.Event.minMaxRepeat.max))
|
if (me.IsInRange(me.GetVictim(), e.Event.minMaxRepeat.min, e.Event.minMaxRepeat.max))
|
||||||
ProcessTimedAction(e, e.Event.minMaxRepeat.repeatMin, e.Event.minMaxRepeat.repeatMax, me.GetVictim());
|
ProcessTimedAction(e, e.Event.minMaxRepeat.repeatMin, e.Event.minMaxRepeat.repeatMax, me.GetVictim());
|
||||||
|
else // make it predictable
|
||||||
|
RecalcTimer(e, 500, 500);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SmartEvents.VictimCasting:
|
case SmartEvents.VictimCasting:
|
||||||
@@ -3048,7 +3287,12 @@ namespace Game.AI
|
|||||||
|
|
||||||
Unit target = DoSelectLowestHpFriendly(e.Event.friendlyHealth.radius, e.Event.friendlyHealth.hpDeficit);
|
Unit target = DoSelectLowestHpFriendly(e.Event.friendlyHealth.radius, e.Event.friendlyHealth.hpDeficit);
|
||||||
if (target == null || !target.IsInCombat())
|
if (target == null || !target.IsInCombat())
|
||||||
|
{
|
||||||
|
// if there are at least two same npcs, they will perform the same action immediately even if this is useless...
|
||||||
|
RecalcTimer(e, 1000, 3000);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ProcessTimedAction(e, e.Event.friendlyHealth.repeatMin, e.Event.friendlyHealth.repeatMax, target);
|
ProcessTimedAction(e, e.Event.friendlyHealth.repeatMin, e.Event.friendlyHealth.repeatMax, target);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -3060,7 +3304,12 @@ namespace Game.AI
|
|||||||
List<Creature> pList = new List<Creature>();
|
List<Creature> pList = new List<Creature>();
|
||||||
DoFindFriendlyCC(pList, e.Event.friendlyCC.radius);
|
DoFindFriendlyCC(pList, e.Event.friendlyCC.radius);
|
||||||
if (pList.Empty())
|
if (pList.Empty())
|
||||||
|
{
|
||||||
|
// if there are at least two same npcs, they will perform the same action immediately even if this is useless...
|
||||||
|
RecalcTimer(e, 1000, 3000);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ProcessTimedAction(e, e.Event.friendlyCC.repeatMin, e.Event.friendlyCC.repeatMax, pList.First());
|
ProcessTimedAction(e, e.Event.friendlyCC.repeatMin, e.Event.friendlyCC.repeatMax, pList.First());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -3072,7 +3321,7 @@ namespace Game.AI
|
|||||||
if (pList.Empty())
|
if (pList.Empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ProcessTimedAction(e, e.Event.missingBuff.repeatMin, e.Event.missingBuff.repeatMax, pList.First());
|
ProcessTimedAction(e, e.Event.missingBuff.repeatMin, e.Event.missingBuff.repeatMax, pList.SelectRandom());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SmartEvents.HasAura:
|
case SmartEvents.HasAura:
|
||||||
@@ -3118,11 +3367,17 @@ namespace Game.AI
|
|||||||
case SmartEvents.JustSummoned:
|
case SmartEvents.JustSummoned:
|
||||||
case SmartEvents.Reset:
|
case SmartEvents.Reset:
|
||||||
case SmartEvents.JustCreated:
|
case SmartEvents.JustCreated:
|
||||||
case SmartEvents.GossipHello:
|
|
||||||
case SmartEvents.FollowCompleted:
|
case SmartEvents.FollowCompleted:
|
||||||
case SmartEvents.OnSpellclick:
|
case SmartEvents.OnSpellclick:
|
||||||
ProcessAction(e, unit, var0, var1, bvar, spell, gob);
|
ProcessAction(e, unit, var0, var1, bvar, spell, gob);
|
||||||
break;
|
break;
|
||||||
|
case SmartEvents.GossipHello:
|
||||||
|
{
|
||||||
|
if (e.Event.gossipHello.noReportUse != 0 && var0 != 0)
|
||||||
|
return;
|
||||||
|
ProcessAction(e, unit, var0, var1, bvar, spell, gob);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case SmartEvents.IsBehindTarget:
|
case SmartEvents.IsBehindTarget:
|
||||||
{
|
{
|
||||||
if (me == null)
|
if (me == null)
|
||||||
@@ -3266,6 +3521,13 @@ namespace Game.AI
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SmartEvents.SummonDespawned:
|
case SmartEvents.SummonDespawned:
|
||||||
|
{
|
||||||
|
if (e.Event.summoned.creature != 0 && e.Event.summoned.creature != var0)
|
||||||
|
return;
|
||||||
|
ProcessAction(e, unit, var0);
|
||||||
|
RecalcTimer(e, e.Event.summoned.cooldownMin, e.Event.summoned.cooldownMax);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case SmartEvents.InstancePlayerEnter:
|
case SmartEvents.InstancePlayerEnter:
|
||||||
{
|
{
|
||||||
if (e.Event.instancePlayerEnter.team != 0 && var0 != e.Event.instancePlayerEnter.team)
|
if (e.Event.instancePlayerEnter.team != 0 && var0 != e.Event.instancePlayerEnter.team)
|
||||||
@@ -3480,8 +3742,10 @@ namespace Game.AI
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SmartEvents.CounterSet:
|
case SmartEvents.CounterSet:
|
||||||
if (GetCounterId(e.Event.counter.id) != 0 && GetCounterValue(e.Event.counter.id) == e.Event.counter.value)
|
if (e.Event.counter.id != var0 || GetCounterValue(e.Event.counter.id) != e.Event.counter.value)
|
||||||
ProcessTimedAction(e, e.Event.counter.cooldownMin, e.Event.counter.cooldownMax);
|
return;
|
||||||
|
|
||||||
|
ProcessTimedAction(e, e.Event.counter.cooldownMin, e.Event.counter.cooldownMax);
|
||||||
break;
|
break;
|
||||||
case SmartEvents.SceneStart:
|
case SmartEvents.SceneStart:
|
||||||
case SmartEvents.SceneCancel:
|
case SmartEvents.SceneCancel:
|
||||||
@@ -3570,7 +3834,7 @@ namespace Game.AI
|
|||||||
// Delay flee for assist event if stunned or rooted
|
// Delay flee for assist event if stunned or rooted
|
||||||
if (e.GetActionType() == SmartActions.FleeForAssist)
|
if (e.GetActionType() == SmartActions.FleeForAssist)
|
||||||
{
|
{
|
||||||
if (me && me.HasUnitState(UnitState.Root | UnitState.Stunned))
|
if (me && me.HasUnitState(UnitState.Root | UnitState.LostControl))
|
||||||
{
|
{
|
||||||
e.timer = 1;
|
e.timer = 1;
|
||||||
return;
|
return;
|
||||||
@@ -3583,7 +3847,7 @@ namespace Game.AI
|
|||||||
case SmartEvents.Update:
|
case SmartEvents.Update:
|
||||||
case SmartEvents.UpdateIc:
|
case SmartEvents.UpdateIc:
|
||||||
case SmartEvents.UpdateOoc:
|
case SmartEvents.UpdateOoc:
|
||||||
case SmartEvents.HealtPct:
|
case SmartEvents.HealthPct:
|
||||||
case SmartEvents.TargetHealthPct:
|
case SmartEvents.TargetHealthPct:
|
||||||
case SmartEvents.ManaPct:
|
case SmartEvents.ManaPct:
|
||||||
case SmartEvents.TargetManaPct:
|
case SmartEvents.TargetManaPct:
|
||||||
@@ -3676,9 +3940,9 @@ namespace Game.AI
|
|||||||
if (!mRemIDs.Empty())
|
if (!mRemIDs.Empty())
|
||||||
{
|
{
|
||||||
foreach (var id in mRemIDs)
|
foreach (var id in mRemIDs)
|
||||||
{
|
|
||||||
RemoveStoredEvent(id);
|
RemoveStoredEvent(id);
|
||||||
}
|
|
||||||
|
mRemIDs.Clear();
|
||||||
}
|
}
|
||||||
if (mUseTextTimer && me != null)
|
if (mUseTextTimer && me != null)
|
||||||
{
|
{
|
||||||
@@ -4078,19 +4342,14 @@ namespace Game.AI
|
|||||||
if (mCounterList.ContainsKey(id))
|
if (mCounterList.ContainsKey(id))
|
||||||
{
|
{
|
||||||
if (reset == 0)
|
if (reset == 0)
|
||||||
value += GetCounterValue(id);
|
mCounterList[id] += value;
|
||||||
mCounterList.Remove(id);
|
else
|
||||||
|
mCounterList[id] = value;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
mCounterList.Add(id, value);
|
||||||
|
|
||||||
mCounterList.Add(id, value);
|
ProcessEventsFor(SmartEvents.CounterSet, null, id);
|
||||||
ProcessEventsFor(SmartEvents.CounterSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint GetCounterId(uint id)
|
|
||||||
{
|
|
||||||
if (mCounterList.ContainsKey(id))
|
|
||||||
return id;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint GetCounterValue(uint id)
|
uint GetCounterValue(uint id)
|
||||||
@@ -4152,22 +4411,26 @@ namespace Game.AI
|
|||||||
meOrigGUID.Clear();
|
meOrigGUID.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IncPhase(int p = 1)
|
void IncPhase(uint p)
|
||||||
{
|
{
|
||||||
if (p >= 0)
|
// protect phase from overflowing
|
||||||
mEventPhase += (uint)p;
|
mEventPhase = Math.Min((uint)SmartPhase.Phase12, mEventPhase + p);
|
||||||
else
|
|
||||||
DecPhase(-p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecPhase(int p = 1)
|
void DecPhase(uint p)
|
||||||
{
|
{
|
||||||
if (mEventPhase > p)
|
if (p >= mEventPhase)
|
||||||
mEventPhase -= (uint)p;
|
|
||||||
else
|
|
||||||
mEventPhase = 0;
|
mEventPhase = 0;
|
||||||
|
else
|
||||||
|
mEventPhase -= p;
|
||||||
|
}
|
||||||
|
bool IsInPhase(uint p)
|
||||||
|
{
|
||||||
|
if (mEventPhase == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return ((1 << (int)(mEventPhase - 1)) & p) != 0;
|
||||||
}
|
}
|
||||||
bool IsInPhase(uint p) { return Convert.ToBoolean((1 << (int)(mEventPhase - 1)) & p); }
|
|
||||||
void SetPhase(uint p = 0) { mEventPhase = p; }
|
void SetPhase(uint p = 0) { mEventPhase = p; }
|
||||||
|
|
||||||
void RemoveStoredEvent(uint id)
|
void RemoveStoredEvent(uint id)
|
||||||
|
|||||||
@@ -1909,14 +1909,6 @@ namespace Game.Entities
|
|||||||
return searcher.GetTarget();
|
return searcher.GetTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Player SelectNearestPlayer(float distance)
|
|
||||||
{
|
|
||||||
var checker = new NearestPlayerInObjectRangeCheck(this, distance);
|
|
||||||
var searcher = new PlayerLastSearcher(this, checker);
|
|
||||||
Cell.VisitAllObjects(this, searcher, distance);
|
|
||||||
return searcher.GetTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendAIReaction(AiReaction reactionType)
|
public void SendAIReaction(AiReaction reactionType)
|
||||||
{
|
{
|
||||||
AIReaction packet = new AIReaction();
|
AIReaction packet = new AIReaction();
|
||||||
|
|||||||
@@ -569,6 +569,11 @@ namespace Game.Entities
|
|||||||
SetLootState(LootState.JustDeactivated);
|
SetLootState(LootState.JustDeactivated);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call AI Reset (required for example in SmartAI to clear one time events)
|
||||||
|
if (GetAI() != null)
|
||||||
|
GetAI().Reset();
|
||||||
|
|
||||||
// respawn timer
|
// respawn timer
|
||||||
uint poolid = GetSpawnId() != 0 ? Global.PoolMgr.IsPartOfAPool<GameObject>(GetSpawnId()) : 0;
|
uint poolid = GetSpawnId() != 0 ? Global.PoolMgr.IsPartOfAPool<GameObject>(GetSpawnId()) : 0;
|
||||||
if (poolid != 0)
|
if (poolid != 0)
|
||||||
@@ -1305,7 +1310,7 @@ namespace Game.Entities
|
|||||||
if (Global.ScriptMgr.OnGossipHello(playerUser, this))
|
if (Global.ScriptMgr.OnGossipHello(playerUser, this))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (GetAI().GossipHello(playerUser, true))
|
if (GetAI().GossipHello(playerUser, false))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1544,6 +1544,14 @@ namespace Game.Entities
|
|||||||
return searcher.GetTarget();
|
return searcher.GetTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Player SelectNearestPlayer(float distance)
|
||||||
|
{
|
||||||
|
var checker = new NearestPlayerInObjectRangeCheck(this, distance);
|
||||||
|
var searcher = new PlayerLastSearcher(this, checker);
|
||||||
|
Cell.VisitAllObjects(this, searcher, distance);
|
||||||
|
return searcher.GetTarget();
|
||||||
|
}
|
||||||
|
|
||||||
public void GetGameObjectListWithEntryInGrid(List<GameObject> gameobjectList, uint entry = 0, float maxSearchRange = 250.0f)
|
public void GetGameObjectListWithEntryInGrid(List<GameObject> gameobjectList, uint entry = 0, float maxSearchRange = 250.0f)
|
||||||
{
|
{
|
||||||
var check = new AllGameObjectsWithEntryInRange(this, entry, maxSearchRange);
|
var check = new AllGameObjectsWithEntryInRange(this, entry, maxSearchRange);
|
||||||
|
|||||||
@@ -3147,7 +3147,7 @@ namespace Game.Entities
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsValidAssistTarget(Unit target)
|
public bool IsValidAssistTarget(Unit target)
|
||||||
{
|
{
|
||||||
return _IsValidAssistTarget(target, null);
|
return _IsValidAssistTarget(target, null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ namespace Game
|
|||||||
GameObject go = GetPlayer().GetGameObjectIfCanInteractWith(packet.Guid);
|
GameObject go = GetPlayer().GetGameObjectIfCanInteractWith(packet.Guid);
|
||||||
if (go)
|
if (go)
|
||||||
{
|
{
|
||||||
if (go.GetAI().GossipHello(GetPlayer(), false))
|
if (go.GetAI().GossipHello(GetPlayer(), true))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GetPlayer().UpdateCriteria(CriteriaTypes.UseGameobject, go.GetEntry());
|
GetPlayer().UpdateCriteria(CriteriaTypes.UseGameobject, go.GetEntry());
|
||||||
|
|||||||
@@ -2232,6 +2232,9 @@ namespace Game.Spells
|
|||||||
if (effect != null && Convert.ToBoolean(effectMask & (1 << (int)effect.EffectIndex)))
|
if (effect != null && Convert.ToBoolean(effectMask & (1 << (int)effect.EffectIndex)))
|
||||||
HandleEffects(null, null, go, effect.EffectIndex, SpellEffectHandleMode.HitTarget);
|
HandleEffects(null, null, go, effect.EffectIndex, SpellEffectHandleMode.HitTarget);
|
||||||
|
|
||||||
|
if (go.GetAI() != null)
|
||||||
|
go.GetAI().SpellHit(m_caster, m_spellInfo);
|
||||||
|
|
||||||
CallScriptOnHitHandlers();
|
CallScriptOnHitHandlers();
|
||||||
CallScriptAfterHitHandlers();
|
CallScriptAfterHitHandlers();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1350,7 +1350,7 @@ namespace Game.Spells
|
|||||||
if (Global.ScriptMgr.OnGossipHello(player, gameObjTarget))
|
if (Global.ScriptMgr.OnGossipHello(player, gameObjTarget))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (gameObjTarget.GetAI().GossipHello(player, true))
|
if (gameObjTarget.GetAI().GossipHello(player, false))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (gameObjTarget.GetGoType())
|
switch (gameObjTarget.GetGoType())
|
||||||
|
|||||||
@@ -760,9 +760,9 @@ namespace Scripts.World
|
|||||||
{
|
{
|
||||||
public go_soulwellAI(GameObject go) : base(go) { }
|
public go_soulwellAI(GameObject go) : base(go) { }
|
||||||
|
|
||||||
public override bool GossipHello(Player player, bool isUse)
|
public override bool GossipHello(Player player, bool reportUse)
|
||||||
{
|
{
|
||||||
if (!isUse)
|
if (!reportUse)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
Unit owner = go.GetOwner();
|
Unit owner = go.GetOwner();
|
||||||
|
|||||||
Reference in New Issue
Block a user