Pet/Guardian AI hook re-organizing
Port From (https://github.com/TrinityCore/TrinityCore/commit/f7a7d02a7f50400cdc2be3c4722afeefe7efce80)
This commit is contained in:
@@ -129,13 +129,24 @@ namespace Game.AI
|
|||||||
if (me.GetVictim() != null)
|
if (me.GetVictim() != null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (me.GetCreatureType() == CreatureType.NonCombatPet)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (me.HasReactState(ReactStates.Aggressive) && me.CanStartAttack(who, false))
|
if (me.HasReactState(ReactStates.Aggressive) && me.CanStartAttack(who, false))
|
||||||
AttackStart(who);
|
AttackStart(who);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _OnOwnerCombatInteraction(Unit target)
|
||||||
|
{
|
||||||
|
if (target == null || !me.IsAlive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!me.HasReactState(ReactStates.Passive) && me.CanStartAttack(target, true))
|
||||||
|
{
|
||||||
|
if (me.IsInCombat())
|
||||||
|
me.AddThreat(target, 0.0f);
|
||||||
|
else
|
||||||
|
AttackStart(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Distract creature, if player gets too close while stealthed/prowling
|
// Distract creature, if player gets too close while stealthed/prowling
|
||||||
public void TriggerAlert(Unit who)
|
public void TriggerAlert(Unit who)
|
||||||
{
|
{
|
||||||
@@ -433,8 +444,6 @@ namespace Game.AI
|
|||||||
// Called when spell hits a target
|
// Called when spell hits a target
|
||||||
public virtual void SpellHitTarget(Unit target, SpellInfo spell) {}
|
public virtual void SpellHitTarget(Unit target, SpellInfo spell) {}
|
||||||
|
|
||||||
// Called when the creature is target of hostile action: swing, hostile spell landed, fear/etc)
|
|
||||||
public virtual void AttackedBy(Unit attacker) { }
|
|
||||||
public virtual bool IsEscorted() { return false; }
|
public virtual bool IsEscorted() { return false; }
|
||||||
|
|
||||||
// Called when creature is spawned or respawned
|
// Called when creature is spawned or respawned
|
||||||
@@ -455,10 +464,10 @@ namespace Game.AI
|
|||||||
public virtual void ReceiveEmote(Player player, TextEmotes emoteId) { }
|
public virtual void ReceiveEmote(Player player, TextEmotes emoteId) { }
|
||||||
|
|
||||||
// Called when owner takes damage
|
// Called when owner takes damage
|
||||||
public virtual void OwnerAttackedBy(Unit attacker) {}
|
public virtual void OwnerAttackedBy(Unit attacker) { _OnOwnerCombatInteraction(attacker); }
|
||||||
|
|
||||||
// Called when owner attacks something
|
// Called when owner attacks something
|
||||||
public virtual void OwnerAttacked(Unit target) {}
|
public virtual void OwnerAttacked(Unit target) { _OnOwnerCombatInteraction(target); }
|
||||||
|
|
||||||
// called when the corpse of this creature gets removed
|
// called when the corpse of this creature gets removed
|
||||||
public virtual void CorpseRemoved(long respawnDelay) {}
|
public virtual void CorpseRemoved(long respawnDelay) {}
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ namespace Game.AI
|
|||||||
// Aggressive - Allow auto select if owner or pet don't have a target
|
// Aggressive - Allow auto select if owner or pet don't have a target
|
||||||
// Stay - Only pick from pet or owner targets / attackers so targets won't run by
|
// Stay - Only pick from pet or owner targets / attackers so targets won't run by
|
||||||
// while chasing our owner. Don't do auto select.
|
// while chasing our owner. Don't do auto select.
|
||||||
// All other cases (ie: defensive) - Targets are assigned by AttackedBy(), OwnerAttackedBy(), OwnerAttacked(), etc.
|
// All other cases (ie: defensive) - Targets are assigned by DamageTaken(), OwnerAttackedBy(), OwnerAttacked(), etc.
|
||||||
Unit nextTarget = SelectNextTarget(me.HasReactState(ReactStates.Aggressive));
|
Unit nextTarget = SelectNextTarget(me.HasReactState(ReactStates.Aggressive));
|
||||||
|
|
||||||
if (nextTarget)
|
if (nextTarget)
|
||||||
@@ -307,16 +307,26 @@ namespace Game.AI
|
|||||||
HandleReturnMovement(); // Return
|
HandleReturnMovement(); // Return
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AttackStart(Unit victim)
|
public override void AttackStart(Unit target)
|
||||||
{
|
{
|
||||||
// Overrides Unit.AttackStart to correctly evaluate Pet states
|
// Overrides Unit.AttackStart to prevent pet from switching off its assigned target
|
||||||
|
if (target == null || target == me)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (me.GetVictim() != null && me.GetVictim().IsAlive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
_AttackStart(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void _AttackStart(Unit target)
|
||||||
|
{
|
||||||
// Check all pet states to decide if we can attack this target
|
// Check all pet states to decide if we can attack this target
|
||||||
if (!CanAIAttack(victim))
|
if (!CanAIAttack(target))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Only chase if not commanded to stay or if stay but commanded to attack
|
// Only chase if not commanded to stay or if stay but commanded to attack
|
||||||
DoAttack(victim, (!me.GetCharmInfo().HasCommandState(CommandStates.Stay) || me.GetCharmInfo().IsCommandAttack()));
|
DoAttack(target, (!me.GetCharmInfo().HasCommandState(CommandStates.Stay) || me.GetCharmInfo().IsCommandAttack()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OwnerAttackedBy(Unit attacker)
|
public override void OwnerAttackedBy(Unit attacker)
|
||||||
@@ -324,7 +334,7 @@ namespace Game.AI
|
|||||||
// Called when owner takes damage. This function helps keep pets from running off
|
// Called when owner takes damage. This function helps keep pets from running off
|
||||||
// simply due to owner gaining aggro.
|
// simply due to owner gaining aggro.
|
||||||
|
|
||||||
if (!attacker)
|
if (attacker == null || !me.IsAlive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Passive pets don't do anything
|
// Passive pets don't do anything
|
||||||
@@ -345,7 +355,7 @@ namespace Game.AI
|
|||||||
// that they need to assist
|
// that they need to assist
|
||||||
|
|
||||||
// Target might be null if called from spell with invalid cast targets
|
// Target might be null if called from spell with invalid cast targets
|
||||||
if (!target)
|
if (target == null || !me.IsAlive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Passive pets don't do anything
|
// Passive pets don't do anything
|
||||||
@@ -620,23 +630,8 @@ namespace Game.AI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AttackedBy(Unit attacker)
|
public override void DamageTaken(Unit attacker, ref uint damage)
|
||||||
{
|
{
|
||||||
// Called when pet takes damage. This function helps keep pets from running off
|
|
||||||
// simply due to gaining aggro.
|
|
||||||
|
|
||||||
if (!attacker)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Passive pets don't do anything
|
|
||||||
if (me.HasReactState( ReactStates.Passive))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Prevent pet from disengaging from current target
|
|
||||||
if (me.GetVictim() && me.GetVictim().IsAlive())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Continue to evaluate and attack if necessary
|
|
||||||
AttackStart(attacker);
|
AttackStart(attacker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -468,10 +468,13 @@ namespace Game.Entities
|
|||||||
// Spells such as auto-shot and others handled in WorldSession.HandleCastSpellOpcode
|
// Spells such as auto-shot and others handled in WorldSession.HandleCastSpellOpcode
|
||||||
if (IsTypeId(TypeId.Player))
|
if (IsTypeId(TypeId.Player))
|
||||||
{
|
{
|
||||||
Pet playerPet = ToPlayer().GetPet();
|
foreach (Unit controlled in m_Controlled)
|
||||||
|
{
|
||||||
if (playerPet != null && playerPet.IsAlive())
|
Creature cControlled = controlled.ToCreature();
|
||||||
playerPet.GetAI().OwnerAttacked(victim);
|
if (cControlled != null)
|
||||||
|
if (cControlled.IsAIEnabled)
|
||||||
|
cControlled.GetAI().OwnerAttacked(victim);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -962,20 +965,19 @@ namespace Game.Entities
|
|||||||
// Signal to pets that their owner was attacked - except when DOT.
|
// Signal to pets that their owner was attacked - except when DOT.
|
||||||
if (damagetype != DamageEffectType.DOT)
|
if (damagetype != DamageEffectType.DOT)
|
||||||
{
|
{
|
||||||
Pet pet = victim.ToPlayer().GetPet();
|
foreach (Unit controlled in victim.m_Controlled)
|
||||||
|
{
|
||||||
if (pet != null && pet.IsAlive())
|
Creature cControlled = controlled.ToCreature();
|
||||||
pet.GetAI().OwnerAttackedBy(this);
|
if (cControlled != null)
|
||||||
|
if (cControlled.IsAIEnabled)
|
||||||
|
cControlled.GetAI().OwnerAttackedBy(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (victim.ToPlayer().GetCommandStatus(PlayerCommandStates.God))
|
if (victim.ToPlayer().GetCommandStatus(PlayerCommandStates.God))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signal the pet it was attacked so the AI can respond if needed
|
|
||||||
if (victim.IsTypeId(TypeId.Unit) && this != victim && victim.IsPet() && victim.IsAlive())
|
|
||||||
victim.ToPet().GetAI().AttackedBy(this);
|
|
||||||
|
|
||||||
if (damagetype != DamageEffectType.NoDamage)
|
if (damagetype != DamageEffectType.NoDamage)
|
||||||
{
|
{
|
||||||
// interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras)
|
// interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras)
|
||||||
@@ -1322,12 +1324,7 @@ namespace Game.Entities
|
|||||||
|
|
||||||
if (!target.IsInCombat() && !target.IsTypeId(TypeId.Player)
|
if (!target.IsInCombat() && !target.IsTypeId(TypeId.Player)
|
||||||
&& !target.ToCreature().HasReactState(ReactStates.Passive) && target.ToCreature().IsAIEnabled)
|
&& !target.ToCreature().HasReactState(ReactStates.Passive) && target.ToCreature().IsAIEnabled)
|
||||||
{
|
|
||||||
if (target.IsPet())
|
|
||||||
target.ToCreature().GetAI().AttackedBy(this); // PetAI has special handler before AttackStart()
|
|
||||||
else
|
|
||||||
target.ToCreature().GetAI().AttackStart(this);
|
target.ToCreature().GetAI().AttackStart(this);
|
||||||
}
|
|
||||||
|
|
||||||
SetInCombatWith(target);
|
SetInCombatWith(target);
|
||||||
target.SetInCombatWith(this);
|
target.SetInCombatWith(this);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
using Framework.Constants;
|
using Framework.Constants;
|
||||||
using Framework.Database;
|
using Framework.Database;
|
||||||
|
using Game.AI;
|
||||||
using Game.Entities;
|
using Game.Entities;
|
||||||
using Game.Networking;
|
using Game.Networking;
|
||||||
using Game.Networking.Packets;
|
using Game.Networking.Packets;
|
||||||
@@ -199,7 +200,12 @@ namespace Game
|
|||||||
charmInfo.SetIsCommandFollow(false);
|
charmInfo.SetIsCommandFollow(false);
|
||||||
charmInfo.SetIsReturning(false);
|
charmInfo.SetIsReturning(false);
|
||||||
|
|
||||||
pet.ToCreature().GetAI().AttackStart(TargetUnit);
|
CreatureAI AI = pet.ToCreature().GetAI();
|
||||||
|
PetAI petAI = (PetAI)AI;
|
||||||
|
if (petAI != null)
|
||||||
|
petAI._AttackStart(TargetUnit); // force target switch
|
||||||
|
else
|
||||||
|
AI.AttackStart(TargetUnit);
|
||||||
|
|
||||||
//10% chance to play special pet attack talk, else growl
|
//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)
|
if (pet.IsPet() && pet.ToPet().GetPetType() == PetType.Summon && pet != TargetUnit && RandomHelper.IRand(0, 100) < 10)
|
||||||
@@ -367,7 +373,14 @@ namespace Game
|
|||||||
{
|
{
|
||||||
pet.GetMotionMaster().Clear();
|
pet.GetMotionMaster().Clear();
|
||||||
if (pet.ToCreature().IsAIEnabled)
|
if (pet.ToCreature().IsAIEnabled)
|
||||||
pet.ToCreature().GetAI().AttackStart(unit_target);
|
{
|
||||||
|
CreatureAI AI = pet.ToCreature().GetAI();
|
||||||
|
PetAI petAI = (PetAI)AI;
|
||||||
|
if (petAI != null)
|
||||||
|
petAI._AttackStart(unit_target); // force victim switch
|
||||||
|
else
|
||||||
|
AI.AttackStart(unit_target);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2678,10 +2678,17 @@ namespace Game.Spells
|
|||||||
// This prevents spells such as Hunter's Mark from triggering pet attack
|
// This prevents spells such as Hunter's Mark from triggering pet attack
|
||||||
if (m_spellInfo.DmgClass != SpellDmgClass.None)
|
if (m_spellInfo.DmgClass != SpellDmgClass.None)
|
||||||
{
|
{
|
||||||
Pet playerPet = playerCaster.GetPet();
|
Unit unitTarget = m_targets.GetUnitTarget();
|
||||||
if (playerPet != null)
|
if (unitTarget)
|
||||||
if (playerPet.IsAlive() && playerPet.IsControlled() && Convert.ToBoolean(m_targets.GetTargetMask() & SpellCastTargetFlags.Unit))
|
{
|
||||||
playerPet.GetAI().OwnerAttacked(m_targets.GetUnitTarget());
|
foreach (Unit controlled in playerCaster.m_Controlled)
|
||||||
|
{
|
||||||
|
Creature cControlled = controlled.ToCreature();
|
||||||
|
if (cControlled != null)
|
||||||
|
if (cControlled.IsAIEnabled)
|
||||||
|
cControlled.GetAI().OwnerAttacked(unitTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user