Core/AI: Clean up charm AI handling.

Port From (https://github.com/TrinityCore/TrinityCore/commit/e4e8c1c59c8b37216814526b4d2551f23934f465)
This commit is contained in:
hondacrx
2021-10-31 13:55:26 -04:00
parent 7050fda482
commit 26940fa650
33 changed files with 472 additions and 443 deletions
+4 -3
View File
@@ -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
+11 -4
View File
@@ -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)
+1 -7
View File
@@ -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
-6
View File
@@ -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
+12 -1
View File
@@ -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; }
+12 -5
View File
@@ -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);
} }
} }
+2 -2
View File
@@ -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);
} }
} }
+6 -5
View File
@@ -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)
+1 -1
View File
@@ -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()}");
+1 -1
View File
@@ -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();
+1 -1
View File
@@ -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;
+26 -10
View File
@@ -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
+6 -4
View File
@@ -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)
+28 -51
View File
@@ -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 // do not allow the AI to be changed during update
m_AI_locked = true; m_AI_locked = true;
i_AI.UpdateAI(diff); base.AIUpdateTick(diff);
m_AI_locked = false; 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
+2 -8
View File
@@ -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
+3 -3
View File
@@ -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();
+12 -8
View File
@@ -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);
} }
-2
View File
@@ -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];
+40 -84
View File
@@ -47,84 +47,49 @@ namespace Game.Entities
} }
public void UpdateCharmAI() public void UpdateCharmAI()
{
switch (GetTypeId())
{
case TypeId.Unit:
if (i_disabledAI != null) // disabled AI must be primary AI
{
if (!IsCharmed())
{
i_AI = i_disabledAI;
i_disabledAI = null;
if (IsTypeId(TypeId.Unit))
ToCreature().GetAI().OnCharmed(false);
}
}
else
{ {
if (IsCharmed()) 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; UnitAI newAI = null;
// first, we check if the creature's own AI specifies an override playerai for its owned players if (IsPlayer())
{
Unit charmer = GetCharmer(); Unit charmer = GetCharmer();
if (charmer) if (charmer != null)
{ {
// first, we check if the creature's own AI specifies an override playerai for its owned players
Creature creatureCharmer = charmer.ToCreature(); Creature creatureCharmer = charmer.ToCreature();
if (creatureCharmer) if (creatureCharmer != null)
{ {
PlayerAI charmAI = creatureCharmer.IsAIEnabled ? creatureCharmer.GetAI().GetAIForCharmedPlayer(ToPlayer()) : null; CreatureAI charmerAI = creatureCharmer.GetAI();
if (charmAI != null) if (charmerAI != null)
newAI = charmAI; newAI = charmerAI.GetAIForCharmedPlayer(ToPlayer());
} }
else else
{ Log.outError(LogFilter.Misc, $"Attempt to assign charm AI to player {GetGUID()} who is charmed by non-creature {GetCharmerGUID()}.");
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 if (newAI == null) // otherwise, we default to the generic one
newAI = new SimpleCharmedPlayerAI(ToPlayer()); newAI = new SimpleCharmedPlayerAI(ToPlayer());
i_AI = newAI;
newAI.OnCharmed(true);
} }
else else
{ {
if (i_AI != null) Cypher.Assert(IsCreature());
{ if (IsPossessed() || IsVehicle())
// we allow the charmed PlayerAI to clean up newAI = new PossessedAI(ToCreature());
i_AI.OnCharmed(false);
}
else else
{ newAI = new PetAI(ToCreature());
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:
Log.outError(LogFilter.Misc, "Attempt to update charm AI for unit {0}, which is neither player nor creature.", GetGUID().ToString());
break;
} }
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();
if (creature)
{
// 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 // Vehicle should not attack its passenger after he exists the seat
if (type != CharmType.Vehicle) if (type != CharmType.Vehicle)
LastCharmerGUID = charmer ? charmer.GetGUID() : ObjectGuid.Empty; LastCharmerGUID = charmer.GetGUID();
}
// 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())
+9 -9
View File
@@ -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);
} }
+67 -15
View File
@@ -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);
}
} }
} }
+5 -3
View File
@@ -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);
+1 -1
View File
@@ -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);
} }
} }
+5 -5
View File
@@ -190,7 +190,7 @@ namespace Game
if (pet.GetVictim()) if (pet.GetVictim())
pet.AttackStop(); pet.AttackStop();
if (!pet.IsTypeId(TypeId.Player) && pet.ToCreature().IsAIEnabled) if (!pet.IsTypeId(TypeId.Player) && pet.ToCreature().IsAIEnabled())
{ {
charmInfo.SetIsCommandAttack(true); charmInfo.SetIsCommandAttack(true);
charmInfo.SetIsAtStay(false); charmInfo.SetIsAtStay(false);
@@ -368,14 +368,14 @@ namespace Game
if (pet.GetVictim() != unit_target) if (pet.GetVictim() != unit_target)
{ {
pet.GetMotionMaster().Clear(); pet.GetMotionMaster().Clear();
if (pet.ToCreature().IsAIEnabled) CreatureAI ai = pet.ToCreature().GetAI();
if (ai != null)
{ {
CreatureAI AI = pet.ToCreature().GetAI(); PetAI petAI = (PetAI)ai;
PetAI petAI = (PetAI)AI;
if (petAI != null) if (petAI != null)
petAI._AttackStart(unit_target); // force victim switch petAI._AttackStart(unit_target); // force victim switch
else else
AI.AttackStart(unit_target); ai.AttackStart(unit_target);
} }
} }
} }
+3 -4
View File
@@ -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;
+1 -1
View File
@@ -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})");
+15 -9
View File
@@ -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);
+1 -1
View File
@@ -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);
+2 -2
View File
@@ -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);