Core/AI: Clean up charm AI handling.
Port From (https://github.com/TrinityCore/TrinityCore/commit/e4e8c1c59c8b37216814526b4d2551f23934f465)
This commit is contained in:
@@ -322,11 +322,12 @@ namespace Game.AI
|
|||||||
|
|
||||||
public override void AttackStart(Unit victim) { }
|
public override void AttackStart(Unit victim) { }
|
||||||
|
|
||||||
public override void OnCharmed(bool apply)
|
public override void OnCharmed(bool isNew)
|
||||||
{
|
{
|
||||||
if (!me.GetVehicleKit().IsVehicleInUse() && !apply && _hasConditions)//was used and has conditions
|
bool charmed = me.IsCharmed();
|
||||||
|
if (!me.GetVehicleKit().IsVehicleInUse() && !charmed && _hasConditions)//was used and has conditions
|
||||||
_doDismiss = true;//needs reset
|
_doDismiss = true;//needs reset
|
||||||
else if (apply)
|
else if (charmed)
|
||||||
_doDismiss = false;//in use again
|
_doDismiss = false;//in use again
|
||||||
|
|
||||||
_dismissTimer = VEHICLE_DISMISS_TIME;//reset timer
|
_dismissTimer = VEHICLE_DISMISS_TIME;//reset timer
|
||||||
|
|||||||
@@ -44,13 +44,20 @@ namespace Game.AI
|
|||||||
_moveInLineOfSightLocked = false;
|
_moveInLineOfSightLocked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnCharmed(bool apply)
|
public override void OnCharmed(bool isNew)
|
||||||
{
|
{
|
||||||
if (apply)
|
if (isNew && !me.IsCharmed() && !me.LastCharmerGUID.IsEmpty())
|
||||||
{
|
{
|
||||||
me.NeedChangeAI = true;
|
if (!me.HasReactState(ReactStates.Passive))
|
||||||
me.IsAIEnabled = false;
|
{
|
||||||
|
Unit lastCharmer = Global.ObjAccessor.GetUnit(me, me.LastCharmerGUID);
|
||||||
|
if (lastCharmer != null)
|
||||||
|
me.EngageWithTarget(lastCharmer);
|
||||||
|
}
|
||||||
|
me.LastCharmerGUID.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base.OnCharmed(isNew);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Talk(uint id, WorldObject whisperTarget = null)
|
public void Talk(uint id, WorldObject whisperTarget = null)
|
||||||
|
|||||||
@@ -76,12 +76,6 @@ namespace Game.AI
|
|||||||
me.RemoveDynamicFlag(UnitDynFlags.Lootable);
|
me.RemoveDynamicFlag(UnitDynFlags.Lootable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnCharmed(bool apply)
|
|
||||||
{
|
|
||||||
me.NeedChangeAI = true;
|
|
||||||
me.IsAIEnabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void MoveInLineOfSight(Unit who) { }
|
public override void MoveInLineOfSight(Unit who) { }
|
||||||
|
|
||||||
public override void EnterEvadeMode(EvadeReason why) { }
|
public override void EnterEvadeMode(EvadeReason why) { }
|
||||||
@@ -98,7 +92,7 @@ namespace Game.AI
|
|||||||
public override void AttackStart(Unit unit) { }
|
public override void AttackStart(Unit unit) { }
|
||||||
public override void UpdateAI(uint diff) { }
|
public override void UpdateAI(uint diff) { }
|
||||||
public override void EnterEvadeMode(EvadeReason why) { }
|
public override void EnterEvadeMode(EvadeReason why) { }
|
||||||
public override void OnCharmed(bool apply) { }
|
public override void OnCharmed(bool isNew) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CritterAI : PassiveAI
|
public class CritterAI : PassiveAI
|
||||||
|
|||||||
@@ -601,12 +601,6 @@ namespace Game.AI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnCharmed(bool apply)
|
|
||||||
{
|
|
||||||
me.NeedChangeAI = true;
|
|
||||||
me.IsAIEnabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearCharmInfoFlags()
|
void ClearCharmInfoFlags()
|
||||||
{
|
{
|
||||||
// Quick access to set all flags to FALSE
|
// Quick access to set all flags to FALSE
|
||||||
|
|||||||
@@ -463,7 +463,18 @@ namespace Game.AI
|
|||||||
|
|
||||||
public virtual void Reset() { }
|
public virtual void Reset() { }
|
||||||
|
|
||||||
public virtual void OnCharmed(bool apply) { }
|
/// <summary>
|
||||||
|
// Called when unit's charm state changes with isNew = false
|
||||||
|
// Implementation should call me->ScheduleAIChange() if AI replacement is desired
|
||||||
|
// If this call is made, AI will be replaced on the next tick
|
||||||
|
// When replacement is made, OnCharmed is called with isNew = true
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="apply"></param>
|
||||||
|
public virtual void OnCharmed(bool isNew)
|
||||||
|
{
|
||||||
|
if (!isNew)
|
||||||
|
me.ScheduleAIChange();
|
||||||
|
}
|
||||||
|
|
||||||
public virtual bool ShouldSparWith(Unit target) { return false; }
|
public virtual bool ShouldSparWith(Unit target) { return false; }
|
||||||
|
|
||||||
|
|||||||
@@ -655,8 +655,6 @@ namespace Game.AI
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnCharmed(bool apply) { }
|
|
||||||
|
|
||||||
// helper functions to determine player info
|
// helper functions to determine player info
|
||||||
public bool IsHealer(Player who = null)
|
public bool IsHealer(Player who = null)
|
||||||
{
|
{
|
||||||
@@ -710,7 +708,14 @@ namespace Game.AI
|
|||||||
{
|
{
|
||||||
Unit charmer = me.GetCharmer();
|
Unit charmer = me.GetCharmer();
|
||||||
if (charmer)
|
if (charmer)
|
||||||
return charmer.IsAIEnabled ? charmer.GetAI().SelectTarget(SelectAggroTarget.Random, 0, new ValidTargetSelectPredicate(this)) : charmer.GetVictim();
|
{
|
||||||
|
UnitAI charmerAI = charmer.GetAI();
|
||||||
|
if (charmerAI != null)
|
||||||
|
return charmerAI.SelectTarget(SelectAggroTarget.Random, 0, new ValidTargetSelectPredicate(this));
|
||||||
|
|
||||||
|
return charmer.GetVictim();
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1344,9 +1349,9 @@ namespace Game.AI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnCharmed(bool apply)
|
public override void OnCharmed(bool isNew)
|
||||||
{
|
{
|
||||||
if (apply)
|
if (me.IsCharmed())
|
||||||
{
|
{
|
||||||
me.CastStop();
|
me.CastStop();
|
||||||
me.AttackStop();
|
me.AttackStop();
|
||||||
@@ -1362,6 +1367,8 @@ namespace Game.AI
|
|||||||
me.GetMotionMaster().Clear();
|
me.GetMotionMaster().Clear();
|
||||||
me.StopMoving();
|
me.StopMoving();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base.OnCharmed(isNew);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -673,7 +673,7 @@ namespace Game.AI
|
|||||||
foreach (var id in this)
|
foreach (var id in this)
|
||||||
{
|
{
|
||||||
Creature summon = ObjectAccessor.GetCreature(_me, id);
|
Creature summon = ObjectAccessor.GetCreature(_me, id);
|
||||||
if (summon && summon.IsAIEnabled && (entry == 0 || summon.GetEntry() == entry))
|
if (summon && summon.IsAIEnabled() && (entry == 0 || summon.GetEntry() == entry))
|
||||||
{
|
{
|
||||||
summon.GetAI().DoZoneInCombat(null);
|
summon.GetAI().DoZoneInCombat(null);
|
||||||
}
|
}
|
||||||
@@ -760,7 +760,7 @@ namespace Game.AI
|
|||||||
foreach (var guid in summons)
|
foreach (var guid in summons)
|
||||||
{
|
{
|
||||||
Creature summon = ObjectAccessor.GetCreature(_me, guid);
|
Creature summon = ObjectAccessor.GetCreature(_me, guid);
|
||||||
if (summon && summon.IsAIEnabled)
|
if (summon && summon.IsAIEnabled())
|
||||||
summon.GetAI().DoAction(action);
|
summon.GetAI().DoAction(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -714,17 +714,18 @@ namespace Game.AI
|
|||||||
GetScript().ProcessEventsFor(apply ? SmartEvents.PassengerBoarded : SmartEvents.PassengerRemoved, passenger, (uint)seatId, 0, apply);
|
GetScript().ProcessEventsFor(apply ? SmartEvents.PassengerBoarded : SmartEvents.PassengerRemoved, passenger, (uint)seatId, 0, apply);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnCharmed(bool apply)
|
public override void OnCharmed(bool isNew)
|
||||||
{
|
{
|
||||||
if (apply) // do this before we change charmed state, as charmed state might prevent these things from processing
|
bool charmed = me.IsCharmed();
|
||||||
|
if (charmed) // do this before we change charmed state, as charmed state might prevent these things from processing
|
||||||
{
|
{
|
||||||
if (HasEscortState(SmartEscortState.Escorting | SmartEscortState.Paused | SmartEscortState.Returning))
|
if (HasEscortState(SmartEscortState.Escorting | SmartEscortState.Paused | SmartEscortState.Returning))
|
||||||
EndPath(true);
|
EndPath(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
_isCharmed = apply;
|
_isCharmed = charmed;
|
||||||
|
|
||||||
if (!apply && !me.IsInEvadeMode())
|
if (!charmed && !me.IsInEvadeMode())
|
||||||
{
|
{
|
||||||
if (_repeatWaypointPath)
|
if (_repeatWaypointPath)
|
||||||
StartPath(_run, GetScript().GetPathId(), true);
|
StartPath(_run, GetScript().GetPathId(), true);
|
||||||
@@ -736,7 +737,7 @@ namespace Game.AI
|
|||||||
AttackStart(charmer);
|
AttackStart(charmer);
|
||||||
}
|
}
|
||||||
|
|
||||||
GetScript().ProcessEventsFor(SmartEvents.Charmed, null, 0, 0, apply);
|
GetScript().ProcessEventsFor(SmartEvents.Charmed, null, 0, 0, charmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DoAction(int param)
|
public override void DoAction(int param)
|
||||||
|
|||||||
@@ -958,7 +958,7 @@ namespace Game.AI
|
|||||||
}
|
}
|
||||||
case SmartActions.SetInCombatWithZone:
|
case SmartActions.SetInCombatWithZone:
|
||||||
{
|
{
|
||||||
if (_me != null && _me.IsAIEnabled)
|
if (_me != null && _me.IsAIEnabled())
|
||||||
{
|
{
|
||||||
_me.GetAI().DoZoneInCombat();
|
_me.GetAI().DoZoneInCombat();
|
||||||
Log.outDebug(LogFilter.ScriptsAi, $"SmartScript.ProcessAction: SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: Creature: {_me.GetGUID()}");
|
Log.outDebug(LogFilter.ScriptsAi, $"SmartScript.ProcessAction: SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: Creature: {_me.GetGUID()}");
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ namespace Game.Chat
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
Creature target = handler.GetSelectedCreature();
|
Creature target = handler.GetSelectedCreature();
|
||||||
if (!target || !target.IsAIEnabled || target.GetAI() == null)
|
if (!target || !target.IsAIEnabled())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
string fill_str = args.NextString();
|
string fill_str = args.NextString();
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ namespace Game.Chat
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!creatureTarget.IsAIEnabled)
|
if (!creatureTarget.IsAIEnabled())
|
||||||
{
|
{
|
||||||
handler.SendSysMessage(CypherStrings.CreatureNotAiEnabled);
|
handler.SendSysMessage(CypherStrings.CreatureNotAiEnabled);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
using Framework.Constants;
|
using Framework.Constants;
|
||||||
|
using Game.AI;
|
||||||
using Game.Entities;
|
using Game.Entities;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -209,8 +210,11 @@ namespace Game.Combat
|
|||||||
pair.Value.Suppress(_owner);
|
pair.Value.Suppress(_owner);
|
||||||
|
|
||||||
if (UpdateOwnerCombatState())
|
if (UpdateOwnerCombatState())
|
||||||
if (_owner.IsAIEnabled)
|
{
|
||||||
_owner.GetAI().JustExitedCombat();
|
UnitAI ownerAI = _owner.GetAI();
|
||||||
|
if (ownerAI != null)
|
||||||
|
ownerAI.JustExitedCombat();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EndAllPvECombat()
|
public void EndAllPvECombat()
|
||||||
@@ -230,8 +234,9 @@ namespace Game.Combat
|
|||||||
|
|
||||||
public static void NotifyAICombat(Unit me, Unit other)
|
public static void NotifyAICombat(Unit me, Unit other)
|
||||||
{
|
{
|
||||||
if (!me.IsAIEnabled)
|
if (!me.IsAIEnabled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
me.GetAI().JustEnteredCombat(other);
|
me.GetAI().JustEnteredCombat(other);
|
||||||
|
|
||||||
Creature cMe = me.ToCreature();
|
Creature cMe = me.ToCreature();
|
||||||
@@ -334,10 +339,18 @@ namespace Game.Combat
|
|||||||
bool needSecondAI = second.GetCombatManager().UpdateOwnerCombatState();
|
bool needSecondAI = second.GetCombatManager().UpdateOwnerCombatState();
|
||||||
|
|
||||||
// ...and if that happened, also notify the AI of it...
|
// ...and if that happened, also notify the AI of it...
|
||||||
if (needFirstAI && first.IsAIEnabled)
|
if (needFirstAI)
|
||||||
first.GetAI().JustExitedCombat();
|
{
|
||||||
if (needSecondAI && second.IsAIEnabled)
|
UnitAI firstAI = first.GetAI();
|
||||||
second.GetAI().JustExitedCombat();
|
if (firstAI != null)
|
||||||
|
firstAI.JustExitedCombat();
|
||||||
|
}
|
||||||
|
if (needSecondAI)
|
||||||
|
{
|
||||||
|
UnitAI secondAI = second.GetAI();
|
||||||
|
if (secondAI != null)
|
||||||
|
secondAI.JustExitedCombat();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Unit GetOther(Unit me) { return (first == me) ? second : first; }
|
public Unit GetOther(Unit me) { return (first == me) ? second : first; }
|
||||||
@@ -383,12 +396,15 @@ namespace Game.Combat
|
|||||||
CombatManager.NotifyAICombat(second, first);
|
CombatManager.NotifyAICombat(second, first);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SuppressFor(Unit who)
|
public void SuppressFor(Unit who)
|
||||||
{
|
{
|
||||||
Suppress(who);
|
Suppress(who);
|
||||||
if (who.GetCombatManager().UpdateOwnerCombatState())
|
if (who.GetCombatManager().UpdateOwnerCombatState())
|
||||||
if (who.IsAIEnabled)
|
{
|
||||||
who.GetAI().JustExitedCombat();
|
UnitAI ai = who.GetAI();
|
||||||
|
if (ai != null)
|
||||||
|
ai.JustExitedCombat();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// suppressed combat refs do not generate a combat state for one side of the relation
|
// suppressed combat refs do not generate a combat state for one side of the relation
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
using Framework.Constants;
|
using Framework.Constants;
|
||||||
|
using Game.AI;
|
||||||
using Game.Entities;
|
using Game.Entities;
|
||||||
using Game.Networking.Packets;
|
using Game.Networking.Packets;
|
||||||
using Game.Spells;
|
using Game.Spells;
|
||||||
@@ -198,7 +199,7 @@ namespace Game.Combat
|
|||||||
static void SaveCreatureHomePositionIfNeed(Creature c)
|
static void SaveCreatureHomePositionIfNeed(Creature c)
|
||||||
{
|
{
|
||||||
MovementGeneratorType movetype = c.GetMotionMaster().GetCurrentMovementGeneratorType();
|
MovementGeneratorType movetype = c.GetMotionMaster().GetCurrentMovementGeneratorType();
|
||||||
if (movetype == MovementGeneratorType.Waypoint || movetype == MovementGeneratorType.Point || (c.IsAIEnabled && c.GetAI().IsEscorted()))
|
if (movetype == MovementGeneratorType.Waypoint || movetype == MovementGeneratorType.Point || (c.IsAIEnabled() && c.GetAI().IsEscorted()))
|
||||||
c.SetHomePosition(c.GetPosition());
|
c.SetHomePosition(c.GetPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,8 +312,9 @@ namespace Game.Combat
|
|||||||
Creature cOwner = _owner.ToCreature();
|
Creature cOwner = _owner.ToCreature();
|
||||||
Cypher.Assert(cOwner != null); // if we got here the owner can have a threat list, and must be a creature!
|
Cypher.Assert(cOwner != null); // if we got here the owner can have a threat list, and must be a creature!
|
||||||
SaveCreatureHomePositionIfNeed(cOwner);
|
SaveCreatureHomePositionIfNeed(cOwner);
|
||||||
if (cOwner.IsAIEnabled)
|
CreatureAI ownerAI = cOwner.GetAI();
|
||||||
cOwner.GetAI().JustEngagedWith(target);
|
if (ownerAI != null)
|
||||||
|
ownerAI.JustEngagedWith(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -835,7 +837,7 @@ namespace Game.Combat
|
|||||||
if (!FlagsAllowFighting(_owner, _victim) || !FlagsAllowFighting(_victim, _owner))
|
if (!FlagsAllowFighting(_owner, _victim) || !FlagsAllowFighting(_victim, _owner))
|
||||||
return OnlineState.Offline;
|
return OnlineState.Offline;
|
||||||
|
|
||||||
if (_owner.IsAIEnabled && !_owner.GetAI().CanAIAttack(_victim))
|
if (_owner.IsAIEnabled() && !_owner.GetAI().CanAIAttack(_victim))
|
||||||
return OnlineState.Offline;
|
return OnlineState.Offline;
|
||||||
|
|
||||||
// next, check suppression (immunity to chosen melee attack school)
|
// next, check suppression (immunity to chosen melee attack school)
|
||||||
|
|||||||
@@ -58,13 +58,6 @@ namespace Game.Entities
|
|||||||
_currentWaypointNodeInfo = new();
|
_currentWaypointNodeInfo = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
|
||||||
{
|
|
||||||
i_AI = null;
|
|
||||||
|
|
||||||
base.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void AddToWorld()
|
public override void AddToWorld()
|
||||||
{
|
{
|
||||||
// Register the creature for guid lookup
|
// Register the creature for guid lookup
|
||||||
@@ -170,8 +163,9 @@ namespace Game.Entities
|
|||||||
//DestroyForNearbyPlayers(); // old UpdateObjectVisibility()
|
//DestroyForNearbyPlayers(); // old UpdateObjectVisibility()
|
||||||
loot.Clear();
|
loot.Clear();
|
||||||
uint respawnDelay = m_respawnDelay;
|
uint respawnDelay = m_respawnDelay;
|
||||||
if (IsAIEnabled)
|
CreatureAI ai = GetAI();
|
||||||
GetAI().CorpseRemoved(respawnDelay);
|
if (ai != null)
|
||||||
|
ai.CorpseRemoved(respawnDelay);
|
||||||
|
|
||||||
if (destroyForNearbyPlayers)
|
if (destroyForNearbyPlayers)
|
||||||
DestroyForNearbyPlayers();
|
DestroyForNearbyPlayers();
|
||||||
@@ -429,7 +423,7 @@ namespace Game.Entities
|
|||||||
|
|
||||||
public override void Update(uint diff)
|
public override void Update(uint diff)
|
||||||
{
|
{
|
||||||
if (IsAIEnabled && triggerJustAppeared && m_deathState != DeathState.Dead)
|
if (IsAIEnabled() && triggerJustAppeared && m_deathState != DeathState.Dead)
|
||||||
{
|
{
|
||||||
if (m_respawnCompatibilityMode && VehicleKit != null)
|
if (m_respawnCompatibilityMode && VehicleKit != null)
|
||||||
VehicleKit.Reset();
|
VehicleKit.Reset();
|
||||||
@@ -541,24 +535,8 @@ namespace Game.Entities
|
|||||||
m_shouldReacquireTarget = false;
|
m_shouldReacquireTarget = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if creature is charmed, switch to charmed AI (and back)
|
|
||||||
if (NeedChangeAI)
|
|
||||||
{
|
|
||||||
UpdateCharmAI();
|
|
||||||
NeedChangeAI = false;
|
|
||||||
IsAIEnabled = true;
|
|
||||||
if (!IsInEvadeMode() && !LastCharmerGUID.IsEmpty())
|
|
||||||
{
|
|
||||||
Unit charmer = Global.ObjAccessor.GetUnit(this, LastCharmerGUID);
|
|
||||||
if (charmer)
|
|
||||||
EngageWithTarget(charmer);
|
|
||||||
}
|
|
||||||
|
|
||||||
LastCharmerGUID.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// periodic check to see if the creature has passed an evade boundary
|
// periodic check to see if the creature has passed an evade boundary
|
||||||
if (IsAIEnabled && !IsInEvadeMode() && IsEngaged())
|
if (IsAIEnabled() && !IsInEvadeMode() && IsEngaged())
|
||||||
{
|
{
|
||||||
if (diff >= m_boundaryCheckTime)
|
if (diff >= m_boundaryCheckTime)
|
||||||
{
|
{
|
||||||
@@ -593,13 +571,10 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsInEvadeMode() && IsAIEnabled)
|
// do not allow the AI to be changed during update
|
||||||
{
|
m_AI_locked = true;
|
||||||
// do not allow the AI to be changed during update
|
base.AIUpdateTick(diff);
|
||||||
m_AI_locked = true;
|
m_AI_locked = false;
|
||||||
i_AI.UpdateAI(diff);
|
|
||||||
m_AI_locked = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsAlive())
|
if (!IsAlive())
|
||||||
break;
|
break;
|
||||||
@@ -633,8 +608,11 @@ namespace Game.Entities
|
|||||||
{
|
{
|
||||||
m_cannotReachTimer += diff;
|
m_cannotReachTimer += diff;
|
||||||
if (m_cannotReachTimer >= SharedConst.CreatureNoPathEvadeTime)
|
if (m_cannotReachTimer >= SharedConst.CreatureNoPathEvadeTime)
|
||||||
if (IsAIEnabled)
|
{
|
||||||
GetAI().EnterEvadeMode(EvadeReason.NoPath);
|
CreatureAI ai = GetAI();
|
||||||
|
if (ai != null)
|
||||||
|
ai.EnterEvadeMode(EvadeReason.NoPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -747,19 +725,15 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AIDestory()
|
bool DestoryAI()
|
||||||
{
|
{
|
||||||
if (m_AI_locked)
|
if (m_AI_locked)
|
||||||
{
|
{
|
||||||
Log.outDebug(LogFilter.Scripts, "AIM_Destroy: failed to destroy, locked.");
|
Log.outDebug(LogFilter.Scripts, "DestroyAI: failed to destroy, locked.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Cypher.Assert(i_disabledAI == null, "The disabled AI wasn't cleared!");
|
SetAI(null);
|
||||||
|
|
||||||
i_AI = null;
|
|
||||||
|
|
||||||
IsAIEnabled = false;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -772,14 +746,15 @@ namespace Game.Entities
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AIDestory();
|
if (ai == null)
|
||||||
|
ai = AISelector.SelectAI(this);
|
||||||
|
|
||||||
|
SetAI(ai);
|
||||||
|
|
||||||
InitializeMovementAI();
|
InitializeMovementAI();
|
||||||
|
|
||||||
i_AI = ai ?? AISelector.SelectAI(this);
|
|
||||||
|
|
||||||
IsAIEnabled = true;
|
|
||||||
i_AI.InitializeAI();
|
i_AI.InitializeAI();
|
||||||
|
|
||||||
// Initialize vehicle
|
// Initialize vehicle
|
||||||
if (GetVehicleKit() != null)
|
if (GetVehicleKit() != null)
|
||||||
GetVehicleKit().Reset();
|
GetVehicleKit().Reset();
|
||||||
@@ -1108,10 +1083,11 @@ namespace Game.Entities
|
|||||||
|
|
||||||
public bool IsEscortNPC(bool onlyIfActive = true)
|
public bool IsEscortNPC(bool onlyIfActive = true)
|
||||||
{
|
{
|
||||||
if (!IsAIEnabled)
|
CreatureAI ai = GetAI();
|
||||||
return false;
|
if (ai != null)
|
||||||
|
return ai.IsEscortNPC(onlyIfActive);
|
||||||
|
|
||||||
return GetAI().IsEscortNPC(onlyIfActive);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsMovementPreventedByCasting()
|
public override bool IsMovementPreventedByCasting()
|
||||||
@@ -1695,7 +1671,7 @@ namespace Game.Entities
|
|||||||
|
|
||||||
public override bool CanAlwaysSee(WorldObject obj)
|
public override bool CanAlwaysSee(WorldObject obj)
|
||||||
{
|
{
|
||||||
if (IsAIEnabled && GetAI<CreatureAI>().CanSeeAlways(obj))
|
if (IsAIEnabled() && GetAI<CreatureAI>().CanSeeAlways(obj))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -1936,8 +1912,9 @@ namespace Game.Entities
|
|||||||
//Re-initialize reactstate that could be altered by movementgenerators
|
//Re-initialize reactstate that could be altered by movementgenerators
|
||||||
InitializeReactState();
|
InitializeReactState();
|
||||||
|
|
||||||
if (IsAIEnabled) // reset the AI to be sure no dirty or uninitialized values will be used till next tick
|
UnitAI ai = GetAI();
|
||||||
GetAI().Reset();
|
if (ai != null) // reset the AI to be sure no dirty or uninitialized values will be used till next tick
|
||||||
|
ai.Reset();
|
||||||
|
|
||||||
triggerJustAppeared = true;
|
triggerJustAppeared = true;
|
||||||
|
|
||||||
@@ -2299,7 +2276,7 @@ namespace Game.Entities
|
|||||||
if (!victim.IsInAccessiblePlaceFor(this))
|
if (!victim.IsInAccessiblePlaceFor(this))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (IsAIEnabled && !GetAI().CanAIAttack(victim))
|
if (IsAIEnabled() && !GetAI().CanAIAttack(victim))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// we cannot attack in evade mode
|
// we cannot attack in evade mode
|
||||||
|
|||||||
@@ -390,14 +390,7 @@ namespace Game.Entities
|
|||||||
aura.SetDuration(aura.GetSpellInfo().GetMaxDuration());
|
aura.SetDuration(aura.GetSpellInfo().GetMaxDuration());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsAIEnabled && GetAI() != null)
|
AIUpdateTick(diff);
|
||||||
GetAI().UpdateAI(diff);
|
|
||||||
else if (NeedChangeAI)
|
|
||||||
{
|
|
||||||
UpdateCharmAI();
|
|
||||||
NeedChangeAI = false;
|
|
||||||
IsAIEnabled = GetAI() != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update items that have just a limited lifetime
|
// Update items that have just a limited lifetime
|
||||||
if (now > m_Last_tick)
|
if (now > m_Last_tick)
|
||||||
@@ -5175,6 +5168,7 @@ namespace Game.Entities
|
|||||||
if (guildId != 0)
|
if (guildId != 0)
|
||||||
{
|
{
|
||||||
SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.GuildGUID), ObjectGuid.Create(HighGuid.Guild, guildId));
|
SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.GuildGUID), ObjectGuid.Create(HighGuid.Guild, guildId));
|
||||||
|
SetUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.GuildClubMemberID), GetGUID().GetCounter());
|
||||||
AddPlayerFlag(PlayerFlags.GuildLevelEnabled);
|
AddPlayerFlag(PlayerFlags.GuildLevelEnabled);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -207,9 +207,9 @@ namespace Game.Entities
|
|||||||
Unit owner = GetSummoner();
|
Unit owner = GetSummoner();
|
||||||
if (owner != null)
|
if (owner != null)
|
||||||
{
|
{
|
||||||
if (owner.IsTypeId(TypeId.Unit) && owner.ToCreature().IsAIEnabled)
|
if (owner.IsTypeId(TypeId.Unit) && owner.ToCreature().IsAIEnabled())
|
||||||
owner.ToCreature().GetAI().JustSummoned(this);
|
owner.ToCreature().GetAI().JustSummoned(this);
|
||||||
if (IsAIEnabled)
|
if (IsAIEnabled())
|
||||||
GetAI().IsSummonedBy(owner);
|
GetAI().IsSummonedBy(owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -243,7 +243,7 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
|
|
||||||
Unit owner = GetSummoner();
|
Unit owner = GetSummoner();
|
||||||
if (owner != null && owner.IsTypeId(TypeId.Unit) && owner.ToCreature().IsAIEnabled)
|
if (owner != null && owner.IsTypeId(TypeId.Unit) && owner.ToCreature().IsAIEnabled())
|
||||||
owner.ToCreature().GetAI().SummonedCreatureDespawn(this);
|
owner.ToCreature().GetAI().SummonedCreatureDespawn(this);
|
||||||
|
|
||||||
AddObjectToRemoveList();
|
AddObjectToRemoveList();
|
||||||
|
|||||||
@@ -16,10 +16,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
using Framework.Constants;
|
using Framework.Constants;
|
||||||
|
using Game.AI;
|
||||||
using Game.BattleFields;
|
using Game.BattleFields;
|
||||||
using Game.BattleGrounds;
|
using Game.BattleGrounds;
|
||||||
using Game.Combat;
|
using Game.Combat;
|
||||||
using Game.DataStorage;
|
|
||||||
using Game.Loots;
|
using Game.Loots;
|
||||||
using Game.Maps;
|
using Game.Maps;
|
||||||
using Game.Networking.Packets;
|
using Game.Networking.Packets;
|
||||||
@@ -354,8 +354,11 @@ namespace Game.Entities
|
|||||||
{
|
{
|
||||||
Creature cControlled = controlled.ToCreature();
|
Creature cControlled = controlled.ToCreature();
|
||||||
if (cControlled != null)
|
if (cControlled != null)
|
||||||
if (cControlled.IsAIEnabled)
|
{
|
||||||
cControlled.GetAI().OwnerAttacked(victim);
|
CreatureAI controlledAI = cControlled.GetAI();
|
||||||
|
if (controlledAI != null)
|
||||||
|
controlledAI.OwnerAttacked(victim);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -880,7 +883,7 @@ namespace Game.Entities
|
|||||||
plrVictim.SendDurabilityLoss(plrVictim, loss);
|
plrVictim.SendDurabilityLoss(plrVictim, loss);
|
||||||
}
|
}
|
||||||
// Call KilledUnit for creatures
|
// Call KilledUnit for creatures
|
||||||
if (attacker != null && attacker.IsCreature() && attacker.IsAIEnabled)
|
if (attacker != null && attacker.IsCreature() && attacker.IsAIEnabled())
|
||||||
attacker.ToCreature().GetAI().KilledUnit(victim);
|
attacker.ToCreature().GetAI().KilledUnit(victim);
|
||||||
|
|
||||||
// last damage from non duel opponent or opponent controlled creature
|
// last damage from non duel opponent or opponent controlled creature
|
||||||
@@ -907,19 +910,20 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Call KilledUnit for creatures, this needs to be called after the lootable flag is set
|
// Call KilledUnit for creatures, this needs to be called after the lootable flag is set
|
||||||
if (attacker != null && attacker.IsCreature() && attacker.IsAIEnabled)
|
if (attacker != null && attacker.IsCreature() && attacker.IsAIEnabled())
|
||||||
attacker.ToCreature().GetAI().KilledUnit(victim);
|
attacker.ToCreature().GetAI().KilledUnit(victim);
|
||||||
|
|
||||||
// Call creature just died function
|
// Call creature just died function
|
||||||
if (creature.IsAIEnabled)
|
CreatureAI ai = creature.GetAI();
|
||||||
creature.GetAI().JustDied(attacker);
|
if (ai != null)
|
||||||
|
ai.JustDied(attacker);
|
||||||
|
|
||||||
TempSummon summon = creature.ToTempSummon();
|
TempSummon summon = creature.ToTempSummon();
|
||||||
if (summon != null)
|
if (summon != null)
|
||||||
{
|
{
|
||||||
Unit summoner = summon.GetSummoner();
|
Unit summoner = summon.GetSummoner();
|
||||||
if (summoner != null)
|
if (summoner != null)
|
||||||
if (summoner.IsTypeId(TypeId.Unit) && summoner.IsAIEnabled)
|
if (summoner.IsTypeId(TypeId.Unit) && summoner.IsAIEnabled())
|
||||||
summoner.ToCreature().GetAI().SummonedCreatureDies(creature, attacker);
|
summoner.ToCreature().GetAI().SummonedCreatureDies(creature, attacker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,6 @@ namespace Game.Entities
|
|||||||
//AI
|
//AI
|
||||||
protected UnitAI i_AI;
|
protected UnitAI i_AI;
|
||||||
protected UnitAI i_disabledAI;
|
protected UnitAI i_disabledAI;
|
||||||
public bool IsAIEnabled { get; set; }
|
|
||||||
public bool NeedChangeAI { get; set; }
|
|
||||||
|
|
||||||
//Movement
|
//Movement
|
||||||
protected float[] m_speed_rate = new float[(int)UnitMoveType.Max];
|
protected float[] m_speed_rate = new float[(int)UnitMoveType.Max];
|
||||||
|
|||||||
@@ -48,83 +48,48 @@ namespace Game.Entities
|
|||||||
|
|
||||||
public void UpdateCharmAI()
|
public void UpdateCharmAI()
|
||||||
{
|
{
|
||||||
switch (GetTypeId())
|
if (IsCharmed())
|
||||||
{
|
{
|
||||||
case TypeId.Unit:
|
UnitAI newAI = null;
|
||||||
if (i_disabledAI != null) // disabled AI must be primary AI
|
if (IsPlayer())
|
||||||
|
{
|
||||||
|
Unit charmer = GetCharmer();
|
||||||
|
if (charmer != null)
|
||||||
{
|
{
|
||||||
if (!IsCharmed())
|
// first, we check if the creature's own AI specifies an override playerai for its owned players
|
||||||
|
Creature creatureCharmer = charmer.ToCreature();
|
||||||
|
if (creatureCharmer != null)
|
||||||
{
|
{
|
||||||
i_AI = i_disabledAI;
|
CreatureAI charmerAI = creatureCharmer.GetAI();
|
||||||
i_disabledAI = null;
|
if (charmerAI != null)
|
||||||
|
newAI = charmerAI.GetAIForCharmedPlayer(ToPlayer());
|
||||||
if (IsTypeId(TypeId.Unit))
|
|
||||||
ToCreature().GetAI().OnCharmed(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (IsCharmed())
|
|
||||||
{
|
|
||||||
i_disabledAI = i_AI;
|
|
||||||
if (IsPossessed() || IsVehicle())
|
|
||||||
i_AI = new PossessedAI(ToCreature());
|
|
||||||
else
|
|
||||||
i_AI = new PetAI(ToCreature());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TypeId.Player:
|
|
||||||
{
|
|
||||||
if (IsCharmed()) // if we are currently being charmed, then we should apply charm AI
|
|
||||||
{
|
|
||||||
i_disabledAI = i_AI;
|
|
||||||
|
|
||||||
UnitAI newAI = null;
|
|
||||||
// first, we check if the creature's own AI specifies an override playerai for its owned players
|
|
||||||
Unit charmer = GetCharmer();
|
|
||||||
if (charmer)
|
|
||||||
{
|
|
||||||
Creature creatureCharmer = charmer.ToCreature();
|
|
||||||
if (creatureCharmer)
|
|
||||||
{
|
|
||||||
PlayerAI charmAI = creatureCharmer.IsAIEnabled ? creatureCharmer.GetAI().GetAIForCharmedPlayer(ToPlayer()) : null;
|
|
||||||
if (charmAI != null)
|
|
||||||
newAI = charmAI;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log.outError(LogFilter.Misc, "Attempt to assign charm AI to player {0} who is charmed by non-creature {1}.", GetGUID().ToString(), GetCharmerGUID().ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (newAI == null) // otherwise, we default to the generic one
|
|
||||||
newAI = new SimpleCharmedPlayerAI(ToPlayer());
|
|
||||||
i_AI = newAI;
|
|
||||||
newAI.OnCharmed(true);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
Log.outError(LogFilter.Misc, $"Attempt to assign charm AI to player {GetGUID()} who is charmed by non-creature {GetCharmerGUID()}.");
|
||||||
if (i_AI != null)
|
|
||||||
{
|
|
||||||
// we allow the charmed PlayerAI to clean up
|
|
||||||
i_AI.OnCharmed(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log.outError(LogFilter.Misc, "Attempt to remove charm AI from player {0} who doesn't currently have charm AI.", GetGUID().ToString());
|
|
||||||
}
|
|
||||||
// and restore our previous PlayerAI (if we had one)
|
|
||||||
i_AI = i_disabledAI;
|
|
||||||
i_disabledAI = null;
|
|
||||||
// IsAIEnabled gets handled in the caller
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
default:
|
if (newAI == null) // otherwise, we default to the generic one
|
||||||
Log.outError(LogFilter.Misc, "Attempt to update charm AI for unit {0}, which is neither player nor creature.", GetGUID().ToString());
|
newAI = new SimpleCharmedPlayerAI(ToPlayer());
|
||||||
break;
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
Cypher.Assert(IsCreature());
|
||||||
|
if (IsPossessed() || IsVehicle())
|
||||||
|
newAI = new PossessedAI(ToCreature());
|
||||||
|
else
|
||||||
|
newAI = new PetAI(ToCreature());
|
||||||
|
}
|
||||||
|
|
||||||
|
Cypher.Assert(newAI != null);
|
||||||
|
i_AI = newAI;
|
||||||
|
newAI.OnCharmed(true);
|
||||||
|
AIUpdateTick(0, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RestoreDisabledAI();
|
||||||
|
if (i_AI != null)
|
||||||
|
i_AI.OnCharmed(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetMinion(Minion minion, bool apply)
|
public void SetMinion(Minion minion, bool apply)
|
||||||
@@ -365,7 +330,12 @@ namespace Game.Entities
|
|||||||
|
|
||||||
StopMoving();
|
StopMoving();
|
||||||
|
|
||||||
ToCreature().GetAI().OnCharmed(true);
|
// AI will schedule its own change if appropriate
|
||||||
|
UnitAI ai = GetAI();
|
||||||
|
if (ai != null)
|
||||||
|
ai.OnCharmed(false);
|
||||||
|
else
|
||||||
|
ScheduleAIChange();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -378,12 +348,11 @@ namespace Game.Entities
|
|||||||
if (charmer.IsTypeId(TypeId.Unit)) // we are charmed by a creature
|
if (charmer.IsTypeId(TypeId.Unit)) // we are charmed by a creature
|
||||||
{
|
{
|
||||||
// change AI to charmed AI on next Update tick
|
// change AI to charmed AI on next Update tick
|
||||||
NeedChangeAI = true;
|
UnitAI ai = GetAI();
|
||||||
if (IsAIEnabled)
|
if (ai != null)
|
||||||
{
|
ai.OnCharmed(false);
|
||||||
IsAIEnabled = false;
|
else
|
||||||
player.GetAI().OnCharmed(true);
|
player.ScheduleAIChange();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
player.SetClientControl(this, false);
|
player.SetClientControl(this, false);
|
||||||
@@ -482,17 +451,9 @@ namespace Game.Entities
|
|||||||
///@todo Handle SLOT_IDLE motion resume
|
///@todo Handle SLOT_IDLE motion resume
|
||||||
GetMotionMaster().InitializeDefault();
|
GetMotionMaster().InitializeDefault();
|
||||||
|
|
||||||
Creature creature = ToCreature();
|
// Vehicle should not attack its passenger after he exists the seat
|
||||||
if (creature)
|
if (type != CharmType.Vehicle)
|
||||||
{
|
LastCharmerGUID = charmer.GetGUID();
|
||||||
// Creature will restore its old AI on next update
|
|
||||||
if (creature.GetAI() != null)
|
|
||||||
creature.GetAI().OnCharmed(false);
|
|
||||||
|
|
||||||
// Vehicle should not attack its passenger after he exists the seat
|
|
||||||
if (type != CharmType.Vehicle)
|
|
||||||
LastCharmerGUID = charmer ? charmer.GetGUID() : ObjectGuid.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If charmer still exists
|
// If charmer still exists
|
||||||
if (!charmer)
|
if (!charmer)
|
||||||
@@ -539,17 +500,12 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Player player = ToPlayer();
|
if (!IsPlayer() || charmer.IsCreature())
|
||||||
if (player)
|
GetAI().OnCharmed(false); // AI will potentially schedule a charm ai update
|
||||||
{
|
|
||||||
if (charmer.IsTypeId(TypeId.Unit)) // charmed by a creature, this means we had PlayerAI
|
|
||||||
{
|
|
||||||
NeedChangeAI = true;
|
|
||||||
IsAIEnabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Player player = ToPlayer();
|
||||||
|
if (player != null)
|
||||||
player.SetClientControl(this, true);
|
player.SetClientControl(this, true);
|
||||||
}
|
|
||||||
|
|
||||||
// a guardian should always have charminfo
|
// a guardian should always have charminfo
|
||||||
if (playerCharmer && this != charmer.GetFirstControlled())
|
if (playerCharmer && this != charmer.GetFirstControlled())
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
using Framework.Constants;
|
using Framework.Constants;
|
||||||
using Framework.Dynamic;
|
using Framework.Dynamic;
|
||||||
|
using Game.AI;
|
||||||
using Game.BattleGrounds;
|
using Game.BattleGrounds;
|
||||||
using Game.Networking.Packets;
|
using Game.Networking.Packets;
|
||||||
using Game.Spells;
|
using Game.Spells;
|
||||||
@@ -1801,14 +1802,13 @@ namespace Game.Entities
|
|||||||
Unit victim = healInfo.GetTarget();
|
Unit victim = healInfo.GetTarget();
|
||||||
uint addhealth = healInfo.GetHeal();
|
uint addhealth = healInfo.GetHeal();
|
||||||
|
|
||||||
if (healer)
|
UnitAI victimAI = victim.GetAI();
|
||||||
{
|
if (victimAI != null)
|
||||||
if (victim.IsAIEnabled)
|
victimAI.HealReceived(healer, addhealth);
|
||||||
victim.GetAI().HealReceived(healer, addhealth);
|
|
||||||
|
|
||||||
if (healer.IsAIEnabled)
|
UnitAI healerAI = healer != null ? healer.GetAI() : null;
|
||||||
healer.GetAI().HealDone(victim, addhealth);
|
if (healerAI != null)
|
||||||
}
|
healerAI.HealDone(victim, addhealth);
|
||||||
|
|
||||||
if (addhealth != 0)
|
if (addhealth != 0)
|
||||||
gain = (int)victim.ModifyHealth(addhealth);
|
gain = (int)victim.ModifyHealth(addhealth);
|
||||||
@@ -2424,7 +2424,7 @@ namespace Game.Entities
|
|||||||
spell.SetReferencedFromCurrent(false);
|
spell.SetReferencedFromCurrent(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsCreature() && IsAIEnabled)
|
if (IsCreature() && IsAIEnabled())
|
||||||
ToCreature().GetAI().OnSpellCastInterrupt(spell.GetSpellInfo());
|
ToCreature().GetAI().OnSpellCastInterrupt(spell.GetSpellInfo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2595,7 +2595,7 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
|
|
||||||
Creature creature = ToCreature();
|
Creature creature = ToCreature();
|
||||||
if (creature && creature.IsAIEnabled)
|
if (creature && creature.IsAIEnabled())
|
||||||
creature.GetAI().OnSpellClick(clicker, ref spellClickHandled);
|
creature.GetAI().OnSpellClick(clicker, ref spellClickHandled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -172,6 +172,9 @@ namespace Game.Entities
|
|||||||
|
|
||||||
UpdateSplineMovement(diff);
|
UpdateSplineMovement(diff);
|
||||||
GetMotionMaster().Update(diff);
|
GetMotionMaster().Update(diff);
|
||||||
|
|
||||||
|
if (i_AI == null && (!IsPlayer() || IsCharmed()))
|
||||||
|
UpdateCharmAI();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _UpdateSpells(uint diff)
|
void _UpdateSpells(uint diff)
|
||||||
@@ -438,8 +441,9 @@ namespace Game.Entities
|
|||||||
if (IsInWorld)
|
if (IsInWorld)
|
||||||
{
|
{
|
||||||
m_duringRemoveFromWorld = true;
|
m_duringRemoveFromWorld = true;
|
||||||
if (IsAIEnabled)
|
UnitAI ai = GetAI();
|
||||||
GetAI().LeavingWorld();
|
if (ai != null)
|
||||||
|
ai.LeavingWorld();
|
||||||
|
|
||||||
if (IsVehicle())
|
if (IsVehicle())
|
||||||
RemoveVehicleKit(true);
|
RemoveVehicleKit(true);
|
||||||
@@ -537,14 +541,14 @@ namespace Game.Entities
|
|||||||
public void _RegisterDynObject(DynamicObject dynObj)
|
public void _RegisterDynObject(DynamicObject dynObj)
|
||||||
{
|
{
|
||||||
m_dynObj.Add(dynObj);
|
m_dynObj.Add(dynObj);
|
||||||
if (IsTypeId(TypeId.Unit) && IsAIEnabled)
|
if (IsTypeId(TypeId.Unit) && IsAIEnabled())
|
||||||
ToCreature().GetAI().JustRegisteredDynObject(dynObj);
|
ToCreature().GetAI().JustRegisteredDynObject(dynObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void _UnregisterDynObject(DynamicObject dynObj)
|
public void _UnregisterDynObject(DynamicObject dynObj)
|
||||||
{
|
{
|
||||||
m_dynObj.Remove(dynObj);
|
m_dynObj.Remove(dynObj);
|
||||||
if (IsTypeId(TypeId.Unit) && IsAIEnabled)
|
if (IsTypeId(TypeId.Unit) && IsAIEnabled())
|
||||||
ToCreature().GetAI().JustUnregisteredDynObject(dynObj);
|
ToCreature().GetAI().JustUnregisteredDynObject(dynObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -611,7 +615,7 @@ namespace Game.Entities
|
|||||||
GetSpellHistory().StartCooldown(createBySpell, 0, null, true);
|
GetSpellHistory().StartCooldown(createBySpell, 0, null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsTypeId(TypeId.Unit) && ToCreature().IsAIEnabled)
|
if (IsTypeId(TypeId.Unit) && ToCreature().IsAIEnabled())
|
||||||
ToCreature().GetAI().JustSummonedGameobject(gameObj);
|
ToCreature().GetAI().JustSummonedGameobject(gameObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -646,7 +650,7 @@ namespace Game.Entities
|
|||||||
|
|
||||||
m_gameObj.Remove(gameObj);
|
m_gameObj.Remove(gameObj);
|
||||||
|
|
||||||
if (IsTypeId(TypeId.Unit) && ToCreature().IsAIEnabled)
|
if (IsTypeId(TypeId.Unit) && ToCreature().IsAIEnabled())
|
||||||
ToCreature().GetAI().SummonedGameobjectDespawn(gameObj);
|
ToCreature().GetAI().SummonedGameobjectDespawn(gameObj);
|
||||||
|
|
||||||
if (del)
|
if (del)
|
||||||
@@ -694,14 +698,14 @@ namespace Game.Entities
|
|||||||
public void _RegisterAreaTrigger(AreaTrigger areaTrigger)
|
public void _RegisterAreaTrigger(AreaTrigger areaTrigger)
|
||||||
{
|
{
|
||||||
m_areaTrigger.Add(areaTrigger);
|
m_areaTrigger.Add(areaTrigger);
|
||||||
if (IsTypeId(TypeId.Unit) && IsAIEnabled)
|
if (IsTypeId(TypeId.Unit) && IsAIEnabled())
|
||||||
ToCreature().GetAI().JustRegisteredAreaTrigger(areaTrigger);
|
ToCreature().GetAI().JustRegisteredAreaTrigger(areaTrigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void _UnregisterAreaTrigger(AreaTrigger areaTrigger)
|
public void _UnregisterAreaTrigger(AreaTrigger areaTrigger)
|
||||||
{
|
{
|
||||||
m_areaTrigger.Remove(areaTrigger);
|
m_areaTrigger.Remove(areaTrigger);
|
||||||
if (IsTypeId(TypeId.Unit) && IsAIEnabled)
|
if (IsTypeId(TypeId.Unit) && IsAIEnabled())
|
||||||
ToCreature().GetAI().JustUnregisteredAreaTrigger(areaTrigger);
|
ToCreature().GetAI().JustUnregisteredAreaTrigger(areaTrigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1160,8 +1164,51 @@ namespace Game.Entities
|
|||||||
return m_vehicle != null && m_vehicle == vehicle.GetVehicleKit();
|
return m_vehicle != null && m_vehicle == vehicle.GetVehicleKit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsAIEnabled() { return i_AI != null; }
|
||||||
|
|
||||||
public virtual UnitAI GetAI() { return i_AI; }
|
public virtual UnitAI GetAI() { return i_AI; }
|
||||||
public void SetAI(UnitAI newAI) { i_AI = newAI; }
|
|
||||||
|
public void AIUpdateTick(uint diff, bool force = false)
|
||||||
|
{
|
||||||
|
if (diff == 0) // some places call with diff = 0, which does nothing (for now), see PR #22296
|
||||||
|
return;
|
||||||
|
|
||||||
|
UnitAI ai = GetAI();
|
||||||
|
if (ai != null)
|
||||||
|
ai.UpdateAI(diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetAI(UnitAI newAI)
|
||||||
|
{
|
||||||
|
if (i_AI != null)
|
||||||
|
AIUpdateTick(0, true); // old AI gets a final tick if enabled
|
||||||
|
|
||||||
|
i_AI = newAI;
|
||||||
|
AIUpdateTick(0, true); // new AI gets its initial tick
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ScheduleAIChange()
|
||||||
|
{
|
||||||
|
bool charmed = IsCharmed();
|
||||||
|
// if charm is applied, we can't have disabled AI already, and vice versa
|
||||||
|
if (charmed)
|
||||||
|
Cypher.Assert(i_disabledAI == null, "Attempt to schedule charm AI change on unit that already has disabled AI");
|
||||||
|
else if (!IsPlayer())
|
||||||
|
Cypher.Assert(i_disabledAI != null, "Attempt to schedule charm ID change on unit that doesn't have disabled AI");
|
||||||
|
|
||||||
|
if (charmed)
|
||||||
|
i_disabledAI = i_AI;
|
||||||
|
else
|
||||||
|
i_AI = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RestoreDisabledAI()
|
||||||
|
{
|
||||||
|
Cypher.Assert(IsPlayer() || i_disabledAI != null, "Attempt to restore disabled AI on creature without disabled AI");
|
||||||
|
i_AI = i_disabledAI;
|
||||||
|
AIUpdateTick(0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public bool IsPossessing()
|
public bool IsPossessing()
|
||||||
{
|
{
|
||||||
@@ -2270,11 +2317,13 @@ namespace Game.Entities
|
|||||||
|
|
||||||
public static uint DealDamage(Unit attacker, Unit victim, uint damage, CleanDamage cleanDamage = null, DamageEffectType damagetype = DamageEffectType.Direct, SpellSchoolMask damageSchoolMask = SpellSchoolMask.Normal, SpellInfo spellProto = null, bool durabilityLoss = true)
|
public static uint DealDamage(Unit attacker, Unit victim, uint damage, CleanDamage cleanDamage = null, DamageEffectType damagetype = DamageEffectType.Direct, SpellSchoolMask damageSchoolMask = SpellSchoolMask.Normal, SpellInfo spellProto = null, bool durabilityLoss = true)
|
||||||
{
|
{
|
||||||
if (victim.IsAIEnabled)
|
UnitAI victimAI = victim.GetAI();
|
||||||
victim.GetAI().DamageTaken(attacker, ref damage);
|
if (victimAI != null)
|
||||||
|
victimAI.DamageTaken(attacker, ref damage);
|
||||||
|
|
||||||
if (attacker != null && attacker.IsAIEnabled)
|
UnitAI attackerAI = attacker ? attacker.GetAI() : null;
|
||||||
attacker.GetAI().DamageDealt(victim, ref damage, damagetype);
|
if (attackerAI != null)
|
||||||
|
attackerAI.DamageDealt(victim, ref damage, damagetype);
|
||||||
|
|
||||||
// Hook for OnDamage Event
|
// Hook for OnDamage Event
|
||||||
Global.ScriptMgr.OnDamage(attacker, victim, ref damage);
|
Global.ScriptMgr.OnDamage(attacker, victim, ref damage);
|
||||||
@@ -2288,8 +2337,11 @@ namespace Game.Entities
|
|||||||
{
|
{
|
||||||
Creature cControlled = controlled.ToCreature();
|
Creature cControlled = controlled.ToCreature();
|
||||||
if (cControlled != null)
|
if (cControlled != null)
|
||||||
if (cControlled.IsAIEnabled)
|
{
|
||||||
cControlled.GetAI().OwnerAttackedBy(attacker);
|
CreatureAI controlledAI = cControlled.GetAI();
|
||||||
|
if (controlledAI != null)
|
||||||
|
controlledAI.OwnerAttackedBy(attacker);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
using Framework.Constants;
|
using Framework.Constants;
|
||||||
using Framework.Dynamic;
|
using Framework.Dynamic;
|
||||||
|
using Game.AI;
|
||||||
using Game.BattleGrounds;
|
using Game.BattleGrounds;
|
||||||
using Game.DataStorage;
|
using Game.DataStorage;
|
||||||
using Game.Movement;
|
using Game.Movement;
|
||||||
@@ -361,7 +362,7 @@ namespace Game.Entities
|
|||||||
if (unit.IsFlying())
|
if (unit.IsFlying())
|
||||||
_me.CastSpell(unit, SharedConst.VehicleSpellParachute, true);
|
_me.CastSpell(unit, SharedConst.VehicleSpellParachute, true);
|
||||||
|
|
||||||
if (_me.IsTypeId(TypeId.Unit) && _me.ToCreature().IsAIEnabled)
|
if (_me.IsTypeId(TypeId.Unit) && _me.ToCreature().IsAIEnabled())
|
||||||
_me.ToCreature().GetAI().PassengerBoarded(unit, seat.Key, false);
|
_me.ToCreature().GetAI().PassengerBoarded(unit, seat.Key, false);
|
||||||
|
|
||||||
if (GetBase().IsTypeId(TypeId.Unit))
|
if (GetBase().IsTypeId(TypeId.Unit))
|
||||||
@@ -646,8 +647,9 @@ namespace Game.Entities
|
|||||||
Creature creature = Target.GetBase().ToCreature();
|
Creature creature = Target.GetBase().ToCreature();
|
||||||
if (creature != null)
|
if (creature != null)
|
||||||
{
|
{
|
||||||
if (creature.IsAIEnabled)
|
CreatureAI ai = creature.GetAI();
|
||||||
creature.GetAI().PassengerBoarded(Passenger, Seat.Key, true);
|
if (ai != null)
|
||||||
|
ai.PassengerBoarded(Passenger, Seat.Key, true);
|
||||||
|
|
||||||
Global.ScriptMgr.OnAddPassenger(Target, Passenger, Seat.Key);
|
Global.ScriptMgr.OnAddPassenger(Target, Passenger, Seat.Key);
|
||||||
|
|
||||||
|
|||||||
@@ -1749,7 +1749,7 @@ namespace Game
|
|||||||
for (var i = 0; i < objs.Count; ++i)
|
for (var i = 0; i < objs.Count; ++i)
|
||||||
{
|
{
|
||||||
Creature creature = objs[i];
|
Creature creature = objs[i];
|
||||||
if (creature.IsInWorld && creature.IsAIEnabled)
|
if (creature.IsInWorld && creature.IsAIEnabled())
|
||||||
creature.GetAI().OnGameEvent(_activate, _eventId);
|
creature.GetAI().OnGameEvent(_activate, _eventId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+154
-154
@@ -165,68 +165,68 @@ namespace Game
|
|||||||
charmInfo.SetIsFollowing(false);
|
charmInfo.SetIsFollowing(false);
|
||||||
break;
|
break;
|
||||||
case CommandStates.Attack: //spellid=1792 //ATTACK
|
case CommandStates.Attack: //spellid=1792 //ATTACK
|
||||||
|
{
|
||||||
|
// Can't attack if owner is pacified
|
||||||
|
if (GetPlayer().HasAuraType(AuraType.ModPacify))
|
||||||
{
|
{
|
||||||
// Can't attack if owner is pacified
|
// @todo Send proper error message to client
|
||||||
if (GetPlayer().HasAuraType(AuraType.ModPacify))
|
return;
|
||||||
{
|
}
|
||||||
// @todo Send proper error message to client
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// only place where pet can be player
|
// only place where pet can be player
|
||||||
Unit TargetUnit = Global.ObjAccessor.GetUnit(GetPlayer(), guid2);
|
Unit TargetUnit = Global.ObjAccessor.GetUnit(GetPlayer(), guid2);
|
||||||
if (!TargetUnit)
|
if (!TargetUnit)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Unit owner = pet.GetOwner();
|
||||||
|
if (owner)
|
||||||
|
if (!owner.IsValidAttackTarget(TargetUnit))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Unit owner = pet.GetOwner();
|
pet.ClearUnitState(UnitState.Follow);
|
||||||
if (owner)
|
// This is true if pet has no target or has target but targets differs.
|
||||||
if (!owner.IsValidAttackTarget(TargetUnit))
|
if (pet.GetVictim() != TargetUnit || !pet.GetCharmInfo().IsCommandAttack())
|
||||||
return;
|
{
|
||||||
|
if (pet.GetVictim())
|
||||||
|
pet.AttackStop();
|
||||||
|
|
||||||
pet.ClearUnitState(UnitState.Follow);
|
if (!pet.IsTypeId(TypeId.Player) && pet.ToCreature().IsAIEnabled())
|
||||||
// This is true if pet has no target or has target but targets differs.
|
|
||||||
if (pet.GetVictim() != TargetUnit || !pet.GetCharmInfo().IsCommandAttack())
|
|
||||||
{
|
{
|
||||||
if (pet.GetVictim())
|
charmInfo.SetIsCommandAttack(true);
|
||||||
pet.AttackStop();
|
charmInfo.SetIsAtStay(false);
|
||||||
|
charmInfo.SetIsFollowing(false);
|
||||||
|
charmInfo.SetIsCommandFollow(false);
|
||||||
|
charmInfo.SetIsReturning(false);
|
||||||
|
|
||||||
if (!pet.IsTypeId(TypeId.Player) && pet.ToCreature().IsAIEnabled)
|
CreatureAI AI = pet.ToCreature().GetAI();
|
||||||
|
if (AI is PetAI)
|
||||||
|
((PetAI)AI)._AttackStart(TargetUnit); // force target switch
|
||||||
|
else
|
||||||
|
AI.AttackStart(TargetUnit);
|
||||||
|
|
||||||
|
//10% chance to play special pet attack talk, else growl
|
||||||
|
if (pet.IsPet() && pet.ToPet().GetPetType() == PetType.Summon && pet != TargetUnit && RandomHelper.IRand(0, 100) < 10)
|
||||||
|
pet.SendPetTalk(PetTalk.Attack);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
charmInfo.SetIsCommandAttack(true);
|
// 90% chance for pet and 100% chance for charmed creature
|
||||||
charmInfo.SetIsAtStay(false);
|
|
||||||
charmInfo.SetIsFollowing(false);
|
|
||||||
charmInfo.SetIsCommandFollow(false);
|
|
||||||
charmInfo.SetIsReturning(false);
|
|
||||||
|
|
||||||
CreatureAI AI = pet.ToCreature().GetAI();
|
|
||||||
if (AI is PetAI)
|
|
||||||
((PetAI)AI)._AttackStart(TargetUnit); // force target switch
|
|
||||||
else
|
|
||||||
AI.AttackStart(TargetUnit);
|
|
||||||
|
|
||||||
//10% chance to play special pet attack talk, else growl
|
|
||||||
if (pet.IsPet() && pet.ToPet().GetPetType() == PetType.Summon && pet != TargetUnit && RandomHelper.IRand(0, 100) < 10)
|
|
||||||
pet.SendPetTalk(PetTalk.Attack);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 90% chance for pet and 100% chance for charmed creature
|
|
||||||
pet.SendPetAIReaction(guid1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // charmed player
|
|
||||||
{
|
|
||||||
charmInfo.SetIsCommandAttack(true);
|
|
||||||
charmInfo.SetIsAtStay(false);
|
|
||||||
charmInfo.SetIsFollowing(false);
|
|
||||||
charmInfo.SetIsCommandFollow(false);
|
|
||||||
charmInfo.SetIsReturning(false);
|
|
||||||
|
|
||||||
pet.Attack(TargetUnit, true);
|
|
||||||
pet.SendPetAIReaction(guid1);
|
pet.SendPetAIReaction(guid1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
else // charmed player
|
||||||
|
{
|
||||||
|
charmInfo.SetIsCommandAttack(true);
|
||||||
|
charmInfo.SetIsAtStay(false);
|
||||||
|
charmInfo.SetIsFollowing(false);
|
||||||
|
charmInfo.SetIsCommandFollow(false);
|
||||||
|
charmInfo.SetIsReturning(false);
|
||||||
|
|
||||||
|
pet.Attack(TargetUnit, true);
|
||||||
|
pet.SendPetAIReaction(guid1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case CommandStates.Abandon: // abandon (hunter pet) or dismiss (summoned pet)
|
case CommandStates.Abandon: // abandon (hunter pet) or dismiss (summoned pet)
|
||||||
if (pet.GetCharmerGUID() == GetPlayer().GetGUID())
|
if (pet.GetCharmerGUID() == GetPlayer().GetGUID())
|
||||||
GetPlayer().StopCastingCharm();
|
GetPlayer().StopCastingCharm();
|
||||||
@@ -280,127 +280,127 @@ namespace Game
|
|||||||
case ActiveStates.Disabled: // 0x81 spell (disabled), ignore
|
case ActiveStates.Disabled: // 0x81 spell (disabled), ignore
|
||||||
case ActiveStates.Passive: // 0x01
|
case ActiveStates.Passive: // 0x01
|
||||||
case ActiveStates.Enabled: // 0xC1 spell
|
case ActiveStates.Enabled: // 0xC1 spell
|
||||||
|
{
|
||||||
|
Unit unit_target = null;
|
||||||
|
|
||||||
|
if (!guid2.IsEmpty())
|
||||||
|
unit_target = Global.ObjAccessor.GetUnit(GetPlayer(), guid2);
|
||||||
|
|
||||||
|
// do not cast unknown spells
|
||||||
|
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellid, pet.GetMap().GetDifficultyID());
|
||||||
|
if (spellInfo == null)
|
||||||
{
|
{
|
||||||
Unit unit_target = null;
|
Log.outError(LogFilter.Network, "WORLD: unknown PET spell id {0}", spellid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!guid2.IsEmpty())
|
foreach (var spellEffectInfo in spellInfo.GetEffects())
|
||||||
unit_target = Global.ObjAccessor.GetUnit(GetPlayer(), guid2);
|
{
|
||||||
|
if (spellEffectInfo.TargetA.GetTarget() == Targets.UnitSrcAreaEnemy || spellEffectInfo.TargetA.GetTarget() == Targets.UnitDestAreaEnemy || spellEffectInfo.TargetA.GetTarget() == Targets.DestDynobjEnemy)
|
||||||
// do not cast unknown spells
|
|
||||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellid, pet.GetMap().GetDifficultyID());
|
|
||||||
if (spellInfo == null)
|
|
||||||
{
|
|
||||||
Log.outError(LogFilter.Network, "WORLD: unknown PET spell id {0}", spellid);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var spellEffectInfo in spellInfo.GetEffects())
|
// do not cast not learned spells
|
||||||
|
if (!pet.HasSpell(spellid) || spellInfo.IsPassive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Clear the flags as if owner clicked 'attack'. AI will reset them
|
||||||
|
// after AttackStart, even if spell failed
|
||||||
|
if (pet.GetCharmInfo() != null)
|
||||||
|
{
|
||||||
|
pet.GetCharmInfo().SetIsAtStay(false);
|
||||||
|
pet.GetCharmInfo().SetIsCommandAttack(true);
|
||||||
|
pet.GetCharmInfo().SetIsReturning(false);
|
||||||
|
pet.GetCharmInfo().SetIsFollowing(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Spell spell = new(pet, spellInfo, TriggerCastFlags.None);
|
||||||
|
|
||||||
|
SpellCastResult result = spell.CheckPetCast(unit_target);
|
||||||
|
|
||||||
|
//auto turn to target unless possessed
|
||||||
|
if (result == SpellCastResult.UnitNotInfront && !pet.IsPossessed() && !pet.IsVehicle())
|
||||||
|
{
|
||||||
|
Unit unit_target2 = spell.m_targets.GetUnitTarget();
|
||||||
|
if (unit_target)
|
||||||
{
|
{
|
||||||
if (spellEffectInfo.TargetA.GetTarget() == Targets.UnitSrcAreaEnemy || spellEffectInfo.TargetA.GetTarget() == Targets.UnitDestAreaEnemy || spellEffectInfo.TargetA.GetTarget() == Targets.DestDynobjEnemy)
|
if (!pet.IsFocusing())
|
||||||
return;
|
pet.SetInFront(unit_target);
|
||||||
|
Player player = unit_target.ToPlayer();
|
||||||
|
if (player)
|
||||||
|
pet.SendUpdateToPlayer(player);
|
||||||
}
|
}
|
||||||
|
else if (unit_target2)
|
||||||
// do not cast not learned spells
|
|
||||||
if (!pet.HasSpell(spellid) || spellInfo.IsPassive())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Clear the flags as if owner clicked 'attack'. AI will reset them
|
|
||||||
// after AttackStart, even if spell failed
|
|
||||||
if (pet.GetCharmInfo() != null)
|
|
||||||
{
|
{
|
||||||
pet.GetCharmInfo().SetIsAtStay(false);
|
if (!pet.IsFocusing())
|
||||||
pet.GetCharmInfo().SetIsCommandAttack(true);
|
pet.SetInFront(unit_target2);
|
||||||
pet.GetCharmInfo().SetIsReturning(false);
|
Player player = unit_target2.ToPlayer();
|
||||||
pet.GetCharmInfo().SetIsFollowing(false);
|
if (player)
|
||||||
|
pet.SendUpdateToPlayer(player);
|
||||||
}
|
}
|
||||||
|
Unit powner = pet.GetCharmerOrOwner();
|
||||||
Spell spell = new(pet, spellInfo, TriggerCastFlags.None);
|
if (powner)
|
||||||
|
|
||||||
SpellCastResult result = spell.CheckPetCast(unit_target);
|
|
||||||
|
|
||||||
//auto turn to target unless possessed
|
|
||||||
if (result == SpellCastResult.UnitNotInfront && !pet.IsPossessed() && !pet.IsVehicle())
|
|
||||||
{
|
{
|
||||||
Unit unit_target2 = spell.m_targets.GetUnitTarget();
|
Player player = powner.ToPlayer();
|
||||||
if (unit_target)
|
if (player)
|
||||||
{
|
pet.SendUpdateToPlayer(player);
|
||||||
if (!pet.IsFocusing())
|
|
||||||
pet.SetInFront(unit_target);
|
|
||||||
Player player = unit_target.ToPlayer();
|
|
||||||
if (player)
|
|
||||||
pet.SendUpdateToPlayer(player);
|
|
||||||
}
|
|
||||||
else if (unit_target2)
|
|
||||||
{
|
|
||||||
if (!pet.IsFocusing())
|
|
||||||
pet.SetInFront(unit_target2);
|
|
||||||
Player player = unit_target2.ToPlayer();
|
|
||||||
if (player)
|
|
||||||
pet.SendUpdateToPlayer(player);
|
|
||||||
}
|
|
||||||
Unit powner = pet.GetCharmerOrOwner();
|
|
||||||
if (powner)
|
|
||||||
{
|
|
||||||
Player player = powner.ToPlayer();
|
|
||||||
if (player)
|
|
||||||
pet.SendUpdateToPlayer(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = SpellCastResult.SpellCastOk;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == SpellCastResult.SpellCastOk)
|
result = SpellCastResult.SpellCastOk;
|
||||||
{
|
}
|
||||||
unit_target = spell.m_targets.GetUnitTarget();
|
|
||||||
|
|
||||||
//10% chance to play special pet attack talk, else growl
|
if (result == SpellCastResult.SpellCastOk)
|
||||||
//actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
|
{
|
||||||
if (pet.IsPet() && (pet.ToPet().GetPetType() == PetType.Summon) && (pet != unit_target) && (RandomHelper.IRand(0, 100) < 10))
|
unit_target = spell.m_targets.GetUnitTarget();
|
||||||
pet.SendPetTalk(PetTalk.SpecialSpell);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pet.SendPetAIReaction(guid1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unit_target && !GetPlayer().IsFriendlyTo(unit_target) && !pet.IsPossessed() && !pet.IsVehicle())
|
//10% chance to play special pet attack talk, else growl
|
||||||
{
|
//actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
|
||||||
// This is true if pet has no target or has target but targets differs.
|
if (pet.IsPet() && (pet.ToPet().GetPetType() == PetType.Summon) && (pet != unit_target) && (RandomHelper.IRand(0, 100) < 10))
|
||||||
if (pet.GetVictim() != unit_target)
|
pet.SendPetTalk(PetTalk.SpecialSpell);
|
||||||
{
|
|
||||||
pet.GetMotionMaster().Clear();
|
|
||||||
if (pet.ToCreature().IsAIEnabled)
|
|
||||||
{
|
|
||||||
CreatureAI AI = pet.ToCreature().GetAI();
|
|
||||||
PetAI petAI = (PetAI)AI;
|
|
||||||
if (petAI != null)
|
|
||||||
petAI._AttackStart(unit_target); // force victim switch
|
|
||||||
else
|
|
||||||
AI.AttackStart(unit_target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spell.Prepare(spell.m_targets);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (pet.IsPossessed() || pet.IsVehicle()) // @todo: confirm this check
|
pet.SendPetAIReaction(guid1);
|
||||||
Spell.SendCastResult(GetPlayer(), spellInfo, spell.m_SpellVisual, spell.m_castId, result);
|
|
||||||
else
|
|
||||||
spell.SendPetCastResult(result);
|
|
||||||
|
|
||||||
if (!pet.GetSpellHistory().HasCooldown(spellid))
|
|
||||||
pet.GetSpellHistory().ResetCooldown(spellid, true);
|
|
||||||
|
|
||||||
spell.Finish(false);
|
|
||||||
spell.Dispose();
|
|
||||||
|
|
||||||
// reset specific flags in case of spell fail. AI will reset other flags
|
|
||||||
if (pet.GetCharmInfo() != null)
|
|
||||||
pet.GetCharmInfo().SetIsCommandAttack(false);
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
if (unit_target && !GetPlayer().IsFriendlyTo(unit_target) && !pet.IsPossessed() && !pet.IsVehicle())
|
||||||
|
{
|
||||||
|
// This is true if pet has no target or has target but targets differs.
|
||||||
|
if (pet.GetVictim() != unit_target)
|
||||||
|
{
|
||||||
|
pet.GetMotionMaster().Clear();
|
||||||
|
CreatureAI ai = pet.ToCreature().GetAI();
|
||||||
|
if (ai != null)
|
||||||
|
{
|
||||||
|
PetAI petAI = (PetAI)ai;
|
||||||
|
if (petAI != null)
|
||||||
|
petAI._AttackStart(unit_target); // force victim switch
|
||||||
|
else
|
||||||
|
ai.AttackStart(unit_target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spell.Prepare(spell.m_targets);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (pet.IsPossessed() || pet.IsVehicle()) // @todo: confirm this check
|
||||||
|
Spell.SendCastResult(GetPlayer(), spellInfo, spell.m_SpellVisual, spell.m_castId, result);
|
||||||
|
else
|
||||||
|
spell.SendPetCastResult(result);
|
||||||
|
|
||||||
|
if (!pet.GetSpellHistory().HasCooldown(spellid))
|
||||||
|
pet.GetSpellHistory().ResetCooldown(spellid, true);
|
||||||
|
|
||||||
|
spell.Finish(false);
|
||||||
|
spell.Dispose();
|
||||||
|
|
||||||
|
// reset specific flags in case of spell fail. AI will reset other flags
|
||||||
|
if (pet.GetCharmInfo() != null)
|
||||||
|
pet.GetCharmInfo().SetIsCommandAttack(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
Log.outError(LogFilter.Network, "WORLD: unknown PET flag Action {0} and spellid {1}.", flag, spellid);
|
Log.outError(LogFilter.Network, "WORLD: unknown PET flag Action {0} and spellid {1}.", flag, spellid);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -45,11 +45,11 @@ namespace Game.Maps
|
|||||||
|
|
||||||
if (!c.HasUnitState(UnitState.Sightless))
|
if (!c.HasUnitState(UnitState.Sightless))
|
||||||
{
|
{
|
||||||
if (c.IsAIEnabled && c.CanSeeOrDetect(u, false, true))
|
if (c.IsAIEnabled() && c.CanSeeOrDetect(u, false, true))
|
||||||
c.GetAI().MoveInLineOfSight_Safe(u);
|
c.GetAI().MoveInLineOfSight_Safe(u);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (u.IsTypeId(TypeId.Player) && u.HasStealthAura() && c.IsAIEnabled && c.CanSeeOrDetect(u, false, true, true))
|
if (u.IsTypeId(TypeId.Player) && u.HasStealthAura() && c.IsAIEnabled() && c.CanSeeOrDetect(u, false, true, true))
|
||||||
c.GetAI().TriggerAlert(u);
|
c.GetAI().TriggerAlert(u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -939,8 +939,7 @@ namespace Game.Maps
|
|||||||
if (!u.IsWithinLOSInMap(i_enemy))
|
if (!u.IsWithinLOSInMap(i_enemy))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (u.GetAI() != null)
|
u.EngageWithTarget(i_enemy);
|
||||||
u.GetAI().AttackStart(i_enemy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Unit i_funit;
|
Unit i_funit;
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ namespace Game.Maps
|
|||||||
{
|
{
|
||||||
creature.CombatStop();
|
creature.CombatStop();
|
||||||
creature.GetThreatManager().ClearAllThreat();
|
creature.GetThreatManager().ClearAllThreat();
|
||||||
if (creature.IsAIEnabled)
|
if (creature.IsAIEnabled())
|
||||||
creature.GetAI().EnterEvadeMode();
|
creature.GetAI().EnterEvadeMode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -255,9 +255,9 @@ namespace Game.Movement
|
|||||||
if (!owner.IsCreature())
|
if (!owner.IsCreature())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Creature creatureOwner = owner.ToCreature();
|
CreatureAI ai = owner.ToCreature().GetAI();
|
||||||
if (creatureOwner.IsAIEnabled && creatureOwner.GetAI() != null)
|
if (ai != null)
|
||||||
creatureOwner.GetAI().MovementInform(MovementGeneratorType.Chase, (uint)target.GetGUID().GetCounter());
|
ai.MovementInform(MovementGeneratorType.Chase, (uint)target.GetGUID().GetCounter());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Unit GetTarget()
|
public Unit GetTarget()
|
||||||
|
|||||||
@@ -217,9 +217,9 @@ namespace Game.Movement
|
|||||||
if (!owner.IsCreature())
|
if (!owner.IsCreature())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Creature creatureOwner = owner.ToCreature();
|
CreatureAI ai = owner.ToCreature().GetAI();
|
||||||
if (creatureOwner.IsAIEnabled && creatureOwner.GetAI() != null)
|
if (ai != null)
|
||||||
creatureOwner.GetAI().MovementInform(MovementGeneratorType.Follow, (uint)target.GetGUID().GetCounter());
|
ai.MovementInform(MovementGeneratorType.Follow, (uint)target.GetGUID().GetCounter());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
using Framework.Constants;
|
using Framework.Constants;
|
||||||
using Framework.GameMath;
|
using Framework.GameMath;
|
||||||
|
using Game.AI;
|
||||||
using Game.Entities;
|
using Game.Entities;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -164,9 +165,9 @@ namespace Game.Movement
|
|||||||
|
|
||||||
if (movementInform && HasFlag(MovementGeneratorFlags.InformEnabled))
|
if (movementInform && HasFlag(MovementGeneratorFlags.InformEnabled))
|
||||||
{
|
{
|
||||||
Creature ownerCreature = owner.ToCreature();
|
CreatureAI ai = owner.ToCreature().GetAI();
|
||||||
if (ownerCreature != null && ownerCreature.IsAIEnabled)
|
if (ai != null)
|
||||||
ownerCreature.GetAI().MovementInform(MovementGeneratorType.SplineChain, _id);
|
ai.MovementInform(MovementGeneratorType.SplineChain, _id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
using Framework.Constants;
|
using Framework.Constants;
|
||||||
|
using Game.AI;
|
||||||
using Game.Entities;
|
using Game.Entities;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -116,8 +117,9 @@ namespace Game.Movement
|
|||||||
_nextMoveTime.Reset(1000);
|
_nextMoveTime.Reset(1000);
|
||||||
|
|
||||||
// inform AI
|
// inform AI
|
||||||
if (owner.IsAIEnabled)
|
CreatureAI ai = owner.GetAI();
|
||||||
owner.GetAI().WaypointPathStarted(_path.id);
|
if (ai != null)
|
||||||
|
ai.WaypointPathStarted(_path.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DoReset(Creature owner)
|
public override void DoReset(Creature owner)
|
||||||
@@ -230,8 +232,9 @@ namespace Game.Movement
|
|||||||
|
|
||||||
void MovementInform(Creature owner)
|
void MovementInform(Creature owner)
|
||||||
{
|
{
|
||||||
if (owner.IsAIEnabled)
|
CreatureAI ai = owner.GetAI();
|
||||||
owner.GetAI().MovementInform(MovementGeneratorType.Waypoint, (uint)_currentNode);
|
if (ai != null)
|
||||||
|
ai.MovementInform(MovementGeneratorType.Waypoint, (uint)_currentNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnArrived(Creature owner)
|
void OnArrived(Creature owner)
|
||||||
@@ -255,10 +258,11 @@ namespace Game.Movement
|
|||||||
}
|
}
|
||||||
|
|
||||||
// inform AI
|
// inform AI
|
||||||
if (owner.IsAIEnabled)
|
CreatureAI ai = owner.GetAI();
|
||||||
|
if (ai != null)
|
||||||
{
|
{
|
||||||
owner.GetAI().MovementInform(MovementGeneratorType.Waypoint, (uint)_currentNode);
|
ai.MovementInform(MovementGeneratorType.Waypoint, (uint)_currentNode);
|
||||||
owner.GetAI().WaypointReached(waypoint.id, _path.id);
|
ai.WaypointReached(waypoint.id, _path.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
owner.UpdateCurrentWaypointInfo(waypoint.id, _path.id);
|
owner.UpdateCurrentWaypointInfo(waypoint.id, _path.id);
|
||||||
@@ -284,8 +288,9 @@ namespace Game.Movement
|
|||||||
{
|
{
|
||||||
Cypher.Assert(_currentNode < _path.nodes.Count, $"WaypointMovementGenerator.StartMove: tried to reference a node id ({_currentNode}) which is not included in path ({_path.id})");
|
Cypher.Assert(_currentNode < _path.nodes.Count, $"WaypointMovementGenerator.StartMove: tried to reference a node id ({_currentNode}) which is not included in path ({_path.id})");
|
||||||
// inform AI
|
// inform AI
|
||||||
if (owner.IsAIEnabled)
|
CreatureAI ai = owner.GetAI();
|
||||||
owner.GetAI().WaypointStarted(_path.nodes[_currentNode].id, _path.id);
|
if (ai != null)
|
||||||
|
ai.WaypointStarted(_path.nodes[_currentNode].id, _path.id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -314,8 +319,9 @@ namespace Game.Movement
|
|||||||
owner.UpdateCurrentWaypointInfo(0, 0);
|
owner.UpdateCurrentWaypointInfo(0, 0);
|
||||||
|
|
||||||
// inform AI
|
// inform AI
|
||||||
if (owner.IsAIEnabled)
|
CreatureAI ai = owner.GetAI();
|
||||||
owner.GetAI().WaypointPathEnded(currentWaypoint.id, _path.id);
|
if (ai != null)
|
||||||
|
ai.WaypointPathEnded(currentWaypoint.id, _path.id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -324,8 +330,9 @@ namespace Game.Movement
|
|||||||
AddFlag(MovementGeneratorFlags.Initialized);
|
AddFlag(MovementGeneratorFlags.Initialized);
|
||||||
|
|
||||||
// inform AI
|
// inform AI
|
||||||
if (owner.IsAIEnabled)
|
CreatureAI ai = owner.GetAI();
|
||||||
owner.GetAI().WaypointStarted(_path.nodes[_currentNode].id, _path.id);
|
if (ai != null)
|
||||||
|
ai.WaypointStarted(_path.nodes[_currentNode].id, _path.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Cypher.Assert(_currentNode < _path.nodes.Count, $"WaypointMovementGenerator.StartMove: tried to reference a node id ({_currentNode}) which is not included in path ({_path.id})");
|
Cypher.Assert(_currentNode < _path.nodes.Count, $"WaypointMovementGenerator.StartMove: tried to reference a node id ({_currentNode}) which is not included in path ({_path.id})");
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
using Framework.Constants;
|
using Framework.Constants;
|
||||||
using Framework.Dynamic;
|
using Framework.Dynamic;
|
||||||
|
using Game.AI;
|
||||||
using Game.BattleFields;
|
using Game.BattleFields;
|
||||||
using Game.BattleGrounds;
|
using Game.BattleGrounds;
|
||||||
using Game.Conditions;
|
using Game.Conditions;
|
||||||
@@ -2507,8 +2508,11 @@ namespace Game.Spells
|
|||||||
{
|
{
|
||||||
Creature cControlled = controlled.ToCreature();
|
Creature cControlled = controlled.ToCreature();
|
||||||
if (cControlled != null)
|
if (cControlled != null)
|
||||||
if (cControlled.IsAIEnabled)
|
{
|
||||||
cControlled.GetAI().OwnerAttacked(target);
|
CreatureAI controlledAI = cControlled.GetAI();
|
||||||
|
if (controlledAI != null)
|
||||||
|
controlledAI.OwnerAttacked(target);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2778,7 +2782,7 @@ namespace Game.Spells
|
|||||||
// Call CreatureAI hook OnSuccessfulSpellCast
|
// Call CreatureAI hook OnSuccessfulSpellCast
|
||||||
Creature caster = m_originalCaster.ToCreature();
|
Creature caster = m_originalCaster.ToCreature();
|
||||||
if (caster)
|
if (caster)
|
||||||
if (caster.IsAIEnabled)
|
if (caster.IsAIEnabled())
|
||||||
caster.GetAI().OnSuccessfulSpellCast(GetSpellInfo());
|
caster.GetAI().OnSuccessfulSpellCast(GetSpellInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8005,18 +8009,20 @@ namespace Game.Spells
|
|||||||
if (_spellHitTarget)
|
if (_spellHitTarget)
|
||||||
{
|
{
|
||||||
//AI functions
|
//AI functions
|
||||||
if (_spellHitTarget.IsCreature())
|
Creature cHitTarget = _spellHitTarget.ToCreature();
|
||||||
|
if (cHitTarget != null)
|
||||||
{
|
{
|
||||||
if (_spellHitTarget.ToCreature().IsAIEnabled)
|
CreatureAI hitTargetAI = cHitTarget.GetAI();
|
||||||
|
if (hitTargetAI != null)
|
||||||
{
|
{
|
||||||
if (spell.GetCaster().IsGameObject())
|
if (spell.GetCaster().IsGameObject())
|
||||||
_spellHitTarget.ToCreature().GetAI().SpellHit(spell.GetCaster().ToGameObject(), spell.m_spellInfo);
|
hitTargetAI.SpellHit(spell.GetCaster().ToGameObject(), spell.m_spellInfo);
|
||||||
else
|
else
|
||||||
_spellHitTarget.ToCreature().GetAI().SpellHit(spell.GetCaster().ToUnit(), spell.m_spellInfo);
|
hitTargetAI.SpellHit(spell.GetCaster().ToUnit(), spell.m_spellInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spell.GetCaster().IsCreature() && spell.GetCaster().ToCreature().IsAIEnabled)
|
if (spell.GetCaster().IsCreature() && spell.GetCaster().ToCreature().IsAIEnabled())
|
||||||
spell.GetCaster().ToCreature().GetAI().SpellHitTarget(_spellHitTarget, spell.m_spellInfo);
|
spell.GetCaster().ToCreature().GetAI().SpellHitTarget(_spellHitTarget, spell.m_spellInfo);
|
||||||
else if (spell.GetCaster().IsGameObject() && spell.GetCaster().ToGameObject().GetAI() != null)
|
else if (spell.GetCaster().IsGameObject() && spell.GetCaster().ToGameObject().GetAI() != null)
|
||||||
spell.GetCaster().ToGameObject().GetAI().SpellHitTarget(_spellHitTarget, spell.m_spellInfo);
|
spell.GetCaster().ToGameObject().GetAI().SpellHitTarget(_spellHitTarget, spell.m_spellInfo);
|
||||||
@@ -8072,7 +8078,7 @@ namespace Game.Spells
|
|||||||
go.GetAI().SpellHit(spell.GetCaster().ToUnit(), spell.m_spellInfo);
|
go.GetAI().SpellHit(spell.GetCaster().ToUnit(), spell.m_spellInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spell.GetCaster().IsCreature() && spell.GetCaster().ToCreature().IsAIEnabled)
|
if (spell.GetCaster().IsCreature() && spell.GetCaster().ToCreature().IsAIEnabled())
|
||||||
spell.GetCaster().ToCreature().GetAI().SpellHitTarget(go, spell.m_spellInfo);
|
spell.GetCaster().ToCreature().GetAI().SpellHitTarget(go, spell.m_spellInfo);
|
||||||
else if (spell.GetCaster().IsGameObject() && spell.GetCaster().ToGameObject().GetAI() != null)
|
else if (spell.GetCaster().IsGameObject() && spell.GetCaster().ToGameObject().GetAI() != null)
|
||||||
spell.GetCaster().ToGameObject().GetAI().SpellHitTarget(go, spell.m_spellInfo);
|
spell.GetCaster().ToGameObject().GetAI().SpellHitTarget(go, spell.m_spellInfo);
|
||||||
|
|||||||
@@ -1549,7 +1549,7 @@ namespace Scripts.Spells.Generic
|
|||||||
GetUnitOwner().GetAllMinionsByEntry(minionList, CreatureIds.EtherealSoulTrader);
|
GetUnitOwner().GetAllMinionsByEntry(minionList, CreatureIds.EtherealSoulTrader);
|
||||||
foreach (Creature minion in minionList)
|
foreach (Creature minion in minionList)
|
||||||
{
|
{
|
||||||
if (minion.IsAIEnabled)
|
if (minion.IsAIEnabled())
|
||||||
{
|
{
|
||||||
minion.GetAI().Talk(TextIds.SayStealEssence);
|
minion.GetAI().Talk(TextIds.SayStealEssence);
|
||||||
minion.CastSpell(eventInfo.GetProcTarget(), SpellIds.StealEssenceVisual);
|
minion.CastSpell(eventInfo.GetProcTarget(), SpellIds.StealEssenceVisual);
|
||||||
|
|||||||
@@ -327,8 +327,8 @@ namespace Scripts.Spells.Quest
|
|||||||
if (!creatureTarget.IsPet() && creatureTarget.GetEntry() == _originalEntry)
|
if (!creatureTarget.IsPet() && creatureTarget.GetEntry() == _originalEntry)
|
||||||
{
|
{
|
||||||
creatureTarget.UpdateEntry(_newEntry);
|
creatureTarget.UpdateEntry(_newEntry);
|
||||||
if (_shouldAttack && creatureTarget.IsAIEnabled)
|
if (_shouldAttack)
|
||||||
creatureTarget.GetAI().AttackStart(GetCaster());
|
creatureTarget.EngageWithTarget(GetCaster());
|
||||||
|
|
||||||
if (_despawnTime != 0)
|
if (_despawnTime != 0)
|
||||||
creatureTarget.DespawnOrUnsummon(_despawnTime);
|
creatureTarget.DespawnOrUnsummon(_despawnTime);
|
||||||
|
|||||||
Reference in New Issue
Block a user