aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/AI/CoreAI/PetAI.cpp38
-rw-r--r--src/server/game/AI/CoreAI/PetAI.h6
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.h1
-rw-r--r--src/server/game/AI/CreatureAI.cpp27
-rw-r--r--src/server/game/AI/CreatureAI.h8
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp27
-rw-r--r--src/server/game/Handlers/PetHandler.cpp15
-rw-r--r--src/server/game/Spells/Spell.cpp8
-rw-r--r--src/server/scripts/EasternKingdoms/zone_wetlands.cpp11
-rw-r--r--src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp11
10 files changed, 61 insertions, 91 deletions
diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp
index c16e1f945eb..a1c1b72e9b0 100644
--- a/src/server/game/AI/CoreAI/PetAI.cpp
+++ b/src/server/game/AI/CoreAI/PetAI.cpp
@@ -128,7 +128,7 @@ void PetAI::UpdateAI(uint32 diff)
// 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
// 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(REACT_AGGRESSIVE));
if (nextTarget)
@@ -322,8 +322,18 @@ void PetAI::KilledUnit(Unit* victim)
void PetAI::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 || target == me)
+ return;
+
+ if (me->GetVictim() && me->EnsureVictim()->IsAlive())
+ return;
+
+ _AttackStart(target);
+}
+void PetAI::_AttackStart(Unit* target)
+{
// Check all pet states to decide if we can attack this target
if (!CanAttack(target))
return;
@@ -337,7 +347,7 @@ void PetAI::OwnerAttackedBy(Unit* attacker)
// Called when owner takes damage. This function helps keep pets from running off
// simply due to owner gaining aggro.
- if (!attacker)
+ if (!attacker || !me->IsAlive())
return;
// Passive pets don't do anything
@@ -358,7 +368,7 @@ void PetAI::OwnerAttacked(Unit* target)
// that they need to assist
// Target might be NULL if called from spell with invalid cast targets
- if (!target)
+ if (!target || !me->IsAlive())
return;
// Passive pets don't do anything
@@ -626,23 +636,3 @@ void PetAI::ClearCharmInfoFlags()
ci->SetIsReturning(false);
}
}
-
-void PetAI::AttackedBy(Unit* attacker)
-{
- // 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(REACT_PASSIVE))
- return;
-
- // Prevent pet from disengaging from current target
- if (me->GetVictim() && me->EnsureVictim()->IsAlive())
- return;
-
- // Continue to evaluate and attack if necessary
- AttackStart(attacker);
-}
diff --git a/src/server/game/AI/CoreAI/PetAI.h b/src/server/game/AI/CoreAI/PetAI.h
index 4455c1cd494..e243d06debc 100644
--- a/src/server/game/AI/CoreAI/PetAI.h
+++ b/src/server/game/AI/CoreAI/PetAI.h
@@ -36,11 +36,12 @@ class TC_GAME_API PetAI : public CreatureAI
static int32 Permissible(Creature const* creature);
void KilledUnit(Unit* /*victim*/) override;
- void AttackStart(Unit* target) override;
+ void AttackStart(Unit* target) override; // only start attacking if not attacking something else already
+ void _AttackStart(Unit* target); // always start attacking if possible
void MovementInform(uint32 moveType, uint32 data) override;
void OwnerAttackedBy(Unit* attacker) override;
void OwnerAttacked(Unit* target) override;
- void AttackedBy(Unit* attacker) override;
+ void DamageTaken(Unit* attacker, uint32& /*damage*/) override { AttackStart(attacker); }
void ReceiveEmote(Player* player, uint32 textEmote) override;
// The following aren't used by the PetAI but need to be defined to override
@@ -53,7 +54,6 @@ class TC_GAME_API PetAI : public CreatureAI
void OnCharmed(bool /*apply*/) override;
private:
- bool _isVisible(Unit*) const;
bool _needToStop(void);
void _stopAttack(void);
diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h
index 508d9e70d70..39f54dff66a 100644
--- a/src/server/game/AI/CoreAI/UnitAI.h
+++ b/src/server/game/AI/CoreAI/UnitAI.h
@@ -246,7 +246,6 @@ class TC_GAME_API UnitAI
// Called at any Damage from any attacker (before damage apply)
// Note: it for recalculation damage or special reaction at damage
- // for attack reaction use AttackedBy called for not DOT damage in Unit::DealDamage also
virtual void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) { }
// Called when the creature receives heal
diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp
index 80d59e4e7cc..54fbabd0b50 100644
--- a/src/server/game/AI/CreatureAI.cpp
+++ b/src/server/game/AI/CreatureAI.cpp
@@ -147,15 +147,22 @@ void CreatureAI::MoveInLineOfSight(Unit* who)
if (me->GetVictim())
return;
- if (me->GetCreatureType() == CREATURE_TYPE_NON_COMBAT_PET) // non-combat pets should just stand there and look good;)
- return;
-
if (me->HasReactState(REACT_AGGRESSIVE) && me->CanStartAttack(who, false))
AttackStart(who);
- //else if (who->GetVictim() && me->IsFriendlyTo(who)
- // && me->IsWithinDistInMap(who, sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS))
- // && me->CanStartAttack(who->GetVictim(), true)) /// @todo if we use true, it will not attack it when it arrives
- // me->GetMotionMaster()->MoveChase(who->GetVictim());
+}
+
+void CreatureAI::_OnOwnerCombatInteraction(Unit* target)
+{
+ if (!target || !me->IsAlive())
+ return;
+
+ if (!me->HasReactState(REACT_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
@@ -211,12 +218,6 @@ void CreatureAI::EnterEvadeMode(EvadeReason why)
me->GetVehicleKit()->Reset(true);
}
-/*void CreatureAI::AttackedBy(Unit* attacker)
-{
- if (!me->GetVictim())
- AttackStart(attacker);
-}*/
-
void CreatureAI::SetGazeOn(Unit* target)
{
if (me->IsValidAttackTarget(target))
diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h
index 41e6ab2501d..754e936862d 100644
--- a/src/server/game/AI/CreatureAI.h
+++ b/src/server/game/AI/CreatureAI.h
@@ -119,8 +119,6 @@ class TC_GAME_API CreatureAI : public UnitAI
// Called when spell hits a target
virtual void SpellHitTarget(Unit* /*target*/, SpellInfo const* /*spell*/) { }
- // Called when the creature is target of hostile action: swing, hostile spell landed, fear/etc)
- virtual void AttackedBy(Unit* /*attacker*/) { }
virtual bool IsEscorted() const { return false; }
// Called when creature is spawned or respawned
@@ -146,15 +144,14 @@ class TC_GAME_API CreatureAI : public UnitAI
virtual void ReceiveEmote(Player* /*player*/, uint32 /*emoteId*/) { }
// Called when owner takes damage
- virtual void OwnerAttackedBy(Unit* /*attacker*/) { }
+ virtual void OwnerAttackedBy(Unit* attacker) { _OnOwnerCombatInteraction(attacker); }
// Called when owner attacks something
- virtual void OwnerAttacked(Unit* /*target*/) { }
+ virtual void OwnerAttacked(Unit* target) { _OnOwnerCombatInteraction(target); }
/// == Triggered Actions Requested ==================
// Called when creature attack expected (if creature can and no have current victim)
- // Note: for reaction at hostile action must be called AttackedBy function.
//virtual void AttackStart(Unit*) { }
// Called at World update tick
@@ -202,6 +199,7 @@ class TC_GAME_API CreatureAI : public UnitAI
private:
bool m_MoveInLineOfSight_locked;
+ void _OnOwnerCombatInteraction(Unit* target);
};
enum Permitions : int32
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index e089a9974a7..088e9345a44 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -730,20 +730,16 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
// Signal to pets that their owner was attacked - except when DOT.
if (damagetype != DOT)
{
- Pet* pet = victim->ToPlayer()->GetPet();
-
- if (pet && pet->IsAlive())
- pet->AI()->OwnerAttackedBy(this);
+ for (Unit* controlled : victim->m_Controlled)
+ if (Creature* cControlled = controlled->ToCreature())
+ if (cControlled->IsAIEnabled)
+ cControlled->AI()->OwnerAttackedBy(this);
}
if (victim->ToPlayer()->GetCommandStatus(CHEAT_GOD))
return 0;
}
- // Signal the pet it was attacked so the AI can respond if needed
- if (victim->GetTypeId() == TYPEID_UNIT && this != victim && victim->IsPet() && victim->IsAlive())
- victim->ToPet()->AI()->AttackedBy(this);
-
if (damagetype != NODAMAGE)
{
// interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras)
@@ -5762,10 +5758,10 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
// Spells such as auto-shot and others handled in WorldSession::HandleCastSpellOpcode
if (GetTypeId() == TYPEID_PLAYER)
{
- Pet* playerPet = this->ToPlayer()->GetPet();
-
- if (playerPet && playerPet->IsAlive())
- playerPet->AI()->OwnerAttacked(victim);
+ for (Unit* controlled : m_Controlled)
+ if (Creature* cControlled = controlled->ToCreature())
+ if (cControlled->IsAIEnabled)
+ cControlled->AI()->OwnerAttacked(victim);
}
return true;
@@ -8001,12 +7997,7 @@ void Unit::CombatStart(Unit* target, bool initialAggro)
if (!target->IsInCombat() && target->GetTypeId() != TYPEID_PLAYER
&& !target->ToCreature()->HasReactState(REACT_PASSIVE) && target->ToCreature()->IsAIEnabled)
- {
- if (target->IsPet())
- target->ToCreature()->AI()->AttackedBy(this); // PetAI has special handler before AttackStart()
- else
- target->ToCreature()->AI()->AttackStart(this);
- }
+ target->ToCreature()->AI()->AttackStart(this);
SetInCombatWith(target);
target->SetInCombatWith(this);
diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp
index 3d91ce9afaa..ffc3108c1db 100644
--- a/src/server/game/Handlers/PetHandler.cpp
+++ b/src/server/game/Handlers/PetHandler.cpp
@@ -35,6 +35,7 @@
#include "SpellInfo.h"
#include "SpellMgr.h"
#include "SpellPackets.h"
+#include "PetAI.h"
#include "Util.h"
#include "World.h"
#include "WorldPacket.h"
@@ -211,7 +212,11 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe
charmInfo->SetIsCommandFollow(false);
charmInfo->SetIsReturning(false);
- pet->ToCreature()->AI()->AttackStart(TargetUnit);
+ CreatureAI* AI = pet->ToCreature()->AI();
+ if (PetAI* petAI = dynamic_cast<PetAI*>(AI))
+ petAI->_AttackStart(TargetUnit); // force target switch
+ else
+ AI->AttackStart(TargetUnit);
//10% chance to play special pet attack talk, else growl
if (pet->IsPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != TargetUnit && urand(0, 100) < 10)
@@ -372,7 +377,13 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe
{
pet->GetMotionMaster()->Clear();
if (pet->ToCreature()->IsAIEnabled)
- pet->ToCreature()->AI()->AttackStart(unit_target);
+ {
+ CreatureAI* AI = pet->ToCreature()->AI();
+ if (PetAI* petAI = dynamic_cast<PetAI*>(AI))
+ petAI->_AttackStart(unit_target); // force victim switch
+ else
+ AI->AttackStart(unit_target);
+ }
}
}
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index f0e999141f1..94d1b67a895 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -3170,9 +3170,11 @@ void Spell::_cast(bool skipCheck)
// Let any pets know we've attacked something. Check DmgClass for harmful spells only
// This prevents spells such as Hunter's Mark from triggering pet attack
if (this->GetSpellInfo()->DmgClass != SPELL_DAMAGE_CLASS_NONE)
- if (Pet* playerPet = playerCaster->GetPet())
- if (playerPet->IsAlive() && playerPet->isControlled() && (m_targets.GetTargetMask() & TARGET_FLAG_UNIT))
- playerPet->AI()->OwnerAttacked(m_targets.GetUnitTarget());
+ if (Unit* unitTarget = m_targets.GetUnitTarget())
+ for (Unit* controlled : playerCaster->m_Controlled)
+ if (Creature* cControlled = controlled->ToCreature())
+ if (cControlled->IsAIEnabled)
+ cControlled->AI()->OwnerAttacked(unitTarget);
}
SetExecutedCurrently(true);
diff --git a/src/server/scripts/EasternKingdoms/zone_wetlands.cpp b/src/server/scripts/EasternKingdoms/zone_wetlands.cpp
index f192a4bcf8f..c7c4dbbeb5b 100644
--- a/src/server/scripts/EasternKingdoms/zone_wetlands.cpp
+++ b/src/server/scripts/EasternKingdoms/zone_wetlands.cpp
@@ -105,17 +105,6 @@ public:
summoned->AI()->AttackStart(player);
}
- void AttackedBy(Unit* pAttacker) override
- {
- if (me->GetVictim())
- return;
-
- if (me->IsFriendlyTo(pAttacker))
- return;
-
- AttackStart(pAttacker);
- }
-
void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override
{
if (HealthBelowPct(20))
diff --git a/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp b/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp
index 88429574c30..fe11aefc77d 100644
--- a/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp
+++ b/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp
@@ -120,17 +120,6 @@ public:
me->RestoreFaction();
}
- void AttackedBy(Unit* pAttacker) override
- {
- if (me->GetVictim())
- return;
-
- if (me->IsFriendlyTo(pAttacker))
- return;
-
- AttackStart(pAttacker);
- }
-
void DamageTaken(Unit* pDoneBy, uint32 &Damage) override
{
if (Damage > me->GetHealth() || me->HealthBelowPctDamaged(20, Damage))