PeAI update
* Better handle target selection for defensive pets. Adds triggers for when owner is damaged or begins attacking something. * Defensive pets no longer run off as soon as a mob aggros the owner but rather at first damage to owner or owner first attack * Pets on stay will continue to attack unless target unreachable
This commit is contained in:
@@ -108,18 +108,26 @@ void PetAI::UpdateAI(const uint32 diff)
|
|||||||
DoMeleeAttackIfReady();
|
DoMeleeAttackIfReady();
|
||||||
}
|
}
|
||||||
else if (owner && me->GetCharmInfo()) //no victim
|
else if (owner && me->GetCharmInfo()) //no victim
|
||||||
|
{
|
||||||
|
// Only aggressive pets do target search every update.
|
||||||
|
// Defensive pets do target search only in these cases:
|
||||||
|
// * Owner attacks something - handled by OwnerAttacked()
|
||||||
|
// * Owner receives damage - handled by OwnerDamagedBy()
|
||||||
|
// * Pet is in combat and current target dies - handled by KilledUnit()
|
||||||
|
if (me->HasReactState(REACT_AGGRESSIVE))
|
||||||
{
|
{
|
||||||
Unit* nextTarget = SelectNextTarget();
|
Unit* nextTarget = SelectNextTarget();
|
||||||
|
|
||||||
if (me->HasReactState(REACT_PASSIVE))
|
if (nextTarget)
|
||||||
_stopAttack();
|
|
||||||
else if (nextTarget)
|
|
||||||
AttackStart(nextTarget);
|
AttackStart(nextTarget);
|
||||||
else
|
else
|
||||||
HandleReturnMovement();
|
HandleReturnMovement();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
HandleReturnMovement();
|
||||||
|
}
|
||||||
else if (owner && !me->HasUnitState(UNIT_STATE_FOLLOW)) // no charm info and no victim
|
else if (owner && !me->HasUnitState(UNIT_STATE_FOLLOW)) // no charm info and no victim
|
||||||
me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle());
|
HandleReturnMovement();
|
||||||
|
|
||||||
if (!me->GetCharmInfo())
|
if (!me->GetCharmInfo())
|
||||||
return;
|
return;
|
||||||
@@ -302,6 +310,47 @@ void PetAI::AttackStart(Unit* target)
|
|||||||
DoAttack(target, true);
|
DoAttack(target, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PetAI::OwnerDamagedBy(Unit* attacker)
|
||||||
|
{
|
||||||
|
// Called when owner takes damage. Allows defensive pets to know
|
||||||
|
// that their owner might need help
|
||||||
|
|
||||||
|
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->getVictim()->isAlive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Continue to evaluate and attack if necessary
|
||||||
|
AttackStart(attacker);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PetAI::OwnerAttacked(Unit* target)
|
||||||
|
{
|
||||||
|
// Called when owner attacks something. Allows defensive pets to know
|
||||||
|
// that they need to assist
|
||||||
|
|
||||||
|
// Target might be NULL if called from spell with invalid cast targets
|
||||||
|
if (!target)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Passive pets don't do anything
|
||||||
|
if (me->HasReactState(REACT_PASSIVE))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Prevent pet from disengaging from current target
|
||||||
|
if (me->getVictim() && me->getVictim()->isAlive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Continue to evaluate and attack if necessary
|
||||||
|
AttackStart(target);
|
||||||
|
}
|
||||||
|
|
||||||
Unit* PetAI::SelectNextTarget()
|
Unit* PetAI::SelectNextTarget()
|
||||||
{
|
{
|
||||||
// Provides next target selection after current target death
|
// Provides next target selection after current target death
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ class PetAI : public CreatureAI
|
|||||||
void KilledUnit(Unit* /*victim*/);
|
void KilledUnit(Unit* /*victim*/);
|
||||||
void AttackStart(Unit* target);
|
void AttackStart(Unit* target);
|
||||||
void MovementInform(uint32 moveType, uint32 data);
|
void MovementInform(uint32 moveType, uint32 data);
|
||||||
|
void OwnerDamagedBy(Unit* attacker);
|
||||||
|
void OwnerAttacked(Unit* target);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _isVisible(Unit*) const;
|
bool _isVisible(Unit*) const;
|
||||||
|
|||||||
@@ -138,6 +138,12 @@ class CreatureAI : public UnitAI
|
|||||||
// Called at text emote receive from player
|
// Called at text emote receive from player
|
||||||
virtual void ReceiveEmote(Player* /*player*/, uint32 /*emoteId*/) {}
|
virtual void ReceiveEmote(Player* /*player*/, uint32 /*emoteId*/) {}
|
||||||
|
|
||||||
|
// Called when owner takes damage
|
||||||
|
virtual void OwnerDamagedBy(Unit* /*attacker*/) {}
|
||||||
|
|
||||||
|
// Called when owner attacks something
|
||||||
|
virtual void OwnerAttacked(Unit* /*target*/) {}
|
||||||
|
|
||||||
/// == Triggered Actions Requested ==================
|
/// == Triggered Actions Requested ==================
|
||||||
|
|
||||||
// Called when creature attack expected (if creature can and no have current victim)
|
// Called when creature attack expected (if creature can and no have current victim)
|
||||||
|
|||||||
@@ -572,6 +572,15 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
|
|||||||
if (IsAIEnabled)
|
if (IsAIEnabled)
|
||||||
GetAI()->DamageDealt(victim, damage, damagetype);
|
GetAI()->DamageDealt(victim, damage, damagetype);
|
||||||
|
|
||||||
|
// Signal to pets that their owner was attacked
|
||||||
|
if (victim->GetTypeId() == TYPEID_PLAYER)
|
||||||
|
{
|
||||||
|
Pet* pet = victim->ToPlayer()->GetPet();
|
||||||
|
|
||||||
|
if (pet && pet->isAlive())
|
||||||
|
pet->AI()->OwnerDamagedBy(this);
|
||||||
|
}
|
||||||
|
|
||||||
if (damagetype != NODAMAGE)
|
if (damagetype != 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)
|
||||||
@@ -9515,6 +9524,16 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
|
|||||||
if (meleeAttack)
|
if (meleeAttack)
|
||||||
SendMeleeAttackStart(victim);
|
SendMeleeAttackStart(victim);
|
||||||
|
|
||||||
|
// Let the pet know we've started attacking someting. Handles melee attacks only
|
||||||
|
// Spells such as auto-shot and others handled in WorldSession::HandleCastSpellOpcode
|
||||||
|
if (this->GetTypeId() == TYPEID_PLAYER)
|
||||||
|
{
|
||||||
|
Pet* playerPet = this->ToPlayer()->GetPet();
|
||||||
|
|
||||||
|
if (playerPet && playerPet->isAlive())
|
||||||
|
playerPet->AI()->OwnerAttacked(victim);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -153,8 +153,6 @@ void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint16 spellid
|
|||||||
switch (spellid)
|
switch (spellid)
|
||||||
{
|
{
|
||||||
case COMMAND_STAY: //flat=1792 //STAY
|
case COMMAND_STAY: //flat=1792 //STAY
|
||||||
pet->AttackStop();
|
|
||||||
pet->InterruptNonMeleeSpells(false);
|
|
||||||
pet->StopMoving();
|
pet->StopMoving();
|
||||||
pet->GetMotionMaster()->Clear(false);
|
pet->GetMotionMaster()->Clear(false);
|
||||||
pet->GetMotionMaster()->MoveIdle();
|
pet->GetMotionMaster()->MoveIdle();
|
||||||
|
|||||||
@@ -3101,11 +3101,22 @@ void Spell::cast(bool skipCheck)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Player* playerCaster = m_caster->ToPlayer())
|
||||||
|
{
|
||||||
// now that we've done the basic check, now run the scripts
|
// now that we've done the basic check, now run the scripts
|
||||||
// should be done before the spell is actually executed
|
// should be done before the spell is actually executed
|
||||||
if (Player* playerCaster = m_caster->ToPlayer())
|
|
||||||
sScriptMgr->OnPlayerSpellCast(playerCaster, this, skipCheck);
|
sScriptMgr->OnPlayerSpellCast(playerCaster, this, skipCheck);
|
||||||
|
|
||||||
|
// Let any pets know we've attacked something. As of 3.0.2 pets begin
|
||||||
|
// attacking their owner's target immediately
|
||||||
|
if (Pet* playerPet = playerCaster->GetPet())
|
||||||
|
{
|
||||||
|
if (playerPet->isAlive() && playerPet->isControlled() && (m_targets.GetTargetMask() & TARGET_FLAG_UNIT))
|
||||||
|
{
|
||||||
|
playerPet->AI()->OwnerAttacked(m_targets.GetObjectTarget()->ToUnit());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
SetExecutedCurrently(true);
|
SetExecutedCurrently(true);
|
||||||
|
|
||||||
if (m_caster->GetTypeId() != TYPEID_PLAYER && m_targets.GetUnitTarget() && m_targets.GetUnitTarget() != m_caster)
|
if (m_caster->GetTypeId() != TYPEID_PLAYER && m_targets.GetUnitTarget() && m_targets.GetUnitTarget() != m_caster)
|
||||||
|
|||||||
Reference in New Issue
Block a user