fix(Core/Creatures): Added new AI function OnTeleportUnreacheablePlayer to teleport all unreachable players. (#12193)

* fix(Core/Creatures): Implemented CREATURE_FLAG_EXTRA_TELEPORT_UNREACHABLE_PLAYERS.

Fixed #11750

* Update.

* Update.

* Update.
This commit is contained in:
UltraNix
2022-07-24 18:10:41 +02:00
committed by GitHub
parent aa39e6ab86
commit 801e68b1dd
9 changed files with 274 additions and 191 deletions
+1 -1
View File
@@ -306,7 +306,7 @@ bool CreatureAI::_EnterEvadeMode(EvadeReason /*why*/)
me->SetLootRecipient(nullptr); me->SetLootRecipient(nullptr);
me->ResetPlayerDamageReq(); me->ResetPlayerDamageReq();
me->SetLastDamagedTime(0); me->SetLastDamagedTime(0);
me->SetCannotReachTarget(false); me->SetCannotReachTarget();
if (me->IsInEvadeMode()) if (me->IsInEvadeMode())
{ {
+3
View File
@@ -88,6 +88,7 @@ public:
EVADE_REASON_NO_HOSTILES, // the creature's threat list is empty EVADE_REASON_NO_HOSTILES, // the creature's threat list is empty
EVADE_REASON_BOUNDARY, // the creature has moved outside its evade boundary EVADE_REASON_BOUNDARY, // the creature has moved outside its evade boundary
EVADE_REASON_SEQUENCE_BREAK, // this is a boss and the pre-requisite encounters for engaging it are not defeated yet EVADE_REASON_SEQUENCE_BREAK, // this is a boss and the pre-requisite encounters for engaging it are not defeated yet
EVADE_REASON_NO_PATH, // the creature was unable to reach its target for over 5 seconds
EVADE_REASON_OTHER EVADE_REASON_OTHER
}; };
@@ -210,6 +211,8 @@ public:
virtual void CalculateThreat(Unit* /*hatedUnit*/, float& /*threat*/, SpellInfo const* /*threatSpell*/) { } virtual void CalculateThreat(Unit* /*hatedUnit*/, float& /*threat*/, SpellInfo const* /*threatSpell*/) { }
virtual bool OnTeleportUnreacheablePlayer(Player* /*player*/) { return false; }
protected: protected:
virtual void MoveInLineOfSight(Unit* /*who*/); virtual void MoveInLineOfSight(Unit* /*who*/);
+7 -1
View File
@@ -261,13 +261,19 @@ HostileReference* ThreatContainer::getReferenceByTarget(Unit* victim) const
if (!victim) if (!victim)
return nullptr; return nullptr;
ObjectGuid const guid = victim->GetGUID(); return getReferenceByTarget(victim->GetGUID());
}
HostileReference* ThreatContainer::getReferenceByTarget(ObjectGuid const& guid) const
{
for (ThreatContainer::StorageType::const_iterator i = iThreatList.begin(); i != iThreatList.end(); ++i) for (ThreatContainer::StorageType::const_iterator i = iThreatList.begin(); i != iThreatList.end(); ++i)
{ {
HostileReference* ref = (*i); HostileReference* ref = (*i);
if (ref && ref->getUnitGuid() == guid) if (ref && ref->getUnitGuid() == guid)
{
return ref; return ref;
} }
}
return nullptr; return nullptr;
} }
+1
View File
@@ -164,6 +164,7 @@ public:
} }
HostileReference* getReferenceByTarget(Unit* victim) const; HostileReference* getReferenceByTarget(Unit* victim) const;
HostileReference* getReferenceByTarget(ObjectGuid const& guid) const;
[[nodiscard]] StorageType const& getThreatList() const { return iThreatList; } [[nodiscard]] StorageType const& getThreatList() const { return iThreatList; }
+59 -8
View File
@@ -220,7 +220,7 @@ Creature::Creature(bool isWorldObject): Unit(isWorldObject), MovableMapObject(),
m_transportCheckTimer(1000), lootPickPocketRestoreTime(0), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE), m_transportCheckTimer(1000), lootPickPocketRestoreTime(0), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE),
m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false), m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false),
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_moveInLineOfSightDisabled(false), m_moveInLineOfSightStrictlyDisabled(false), m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_moveInLineOfSightDisabled(false), m_moveInLineOfSightStrictlyDisabled(false),
m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_detectionDistance(20.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), _lastDamagedTime(nullptr), m_cannotReachTarget(false), m_cannotReachTimer(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_detectionDistance(20.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), _lastDamagedTime(nullptr), m_cannotReachTimer(0),
_isMissingSwimmingFlagOutOfCombat(false), m_assistanceTimer(0), _playerDamageReq(0), _damagedByPlayer(false) _isMissingSwimmingFlagOutOfCombat(false), m_assistanceTimer(0), _playerDamageReq(0), _damagedByPlayer(false)
{ {
m_regenTimer = CREATURE_REGEN_INTERVAL; m_regenTimer = CREATURE_REGEN_INTERVAL;
@@ -718,7 +718,8 @@ void Creature::Update(uint32 diff)
{ {
AI()->CheckInRoom(); AI()->CheckInRoom();
m_boundaryCheckTime = 2500; m_boundaryCheckTime = 2500;
} else }
else
m_boundaryCheckTime -= diff; m_boundaryCheckTime -= diff;
} }
@@ -728,7 +729,7 @@ void Creature::Update(uint32 diff)
RemoveCharmAuras(); RemoveCharmAuras();
} }
if (Unit *victim = GetVictim()) if (Unit* victim = GetVictim())
{ {
// If we are closer than 50% of the combat reach we are going to reposition the victim // If we are closer than 50% of the combat reach we are going to reposition the victim
if (diff >= m_moveBackwardsMovementTime) if (diff >= m_moveBackwardsMovementTime)
@@ -818,15 +819,45 @@ void Creature::Update(uint32 diff)
m_regenTimer += CREATURE_REGEN_INTERVAL; m_regenTimer += CREATURE_REGEN_INTERVAL;
} }
if (CanNotReachTarget() && !IsInEvadeMode() && !GetMap()->IsRaid()) if (CanNotReachTarget() && !IsInEvadeMode())
{ {
m_cannotReachTimer += diff; m_cannotReachTimer += diff;
if (IsNotReachable() && IsAIEnabled) if (m_cannotReachTimer >= (sWorld->getIntConfig(CONFIG_NPC_EVADE_IF_NOT_REACHABLE) * IN_MILLISECONDS))
{ {
AI()->EnterEvadeMode(); Player* cannotReachPlayer = ObjectAccessor::GetPlayer(*this, m_cannotReachTarget);
if (cannotReachPlayer && IsEngagedBy(cannotReachPlayer) && IsAIEnabled && AI()->OnTeleportUnreacheablePlayer(cannotReachPlayer))
{
SetCannotReachTarget();
} }
else if (!GetMap()->IsRaid())
{
auto EnterEvade = [&]()
{
if (CreatureAI* ai = AI())
{
ai->EnterEvadeMode(CreatureAI::EvadeReason::EVADE_REASON_NO_PATH);
} }
};
if (GetThreatMgr().getThreatList().size() <= 1)
{
EnterEvade();
}
else
{
if (HostileReference* ref = GetThreatMgr().getOnlineContainer().getReferenceByTarget(m_cannotReachTarget))
{
ref->removeReference();
SetCannotReachTarget();
}
else
{
EnterEvade();
}
}
}
}
}
break; break;
} }
default: default:
@@ -1926,7 +1957,7 @@ void Creature::setDeathState(DeathState s, bool despawn)
SetFullHealth(); SetFullHealth();
SetLootRecipient(nullptr); SetLootRecipient(nullptr);
ResetPlayerDamageReq(); ResetPlayerDamageReq();
SetCannotReachTarget(false); SetCannotReachTarget();
CreatureTemplate const* cinfo = GetCreatureTemplate(); CreatureTemplate const* cinfo = GetCreatureTemplate();
// Xinef: npc run by default // Xinef: npc run by default
//SetWalk(true); //SetWalk(true);
@@ -3457,15 +3488,35 @@ bool Creature::IsMovementPreventedByCasting() const
return false; return false;
} }
void Creature::SetCannotReachTarget(bool cannotReach) void Creature::SetCannotReachTarget(ObjectGuid const& cannotReach)
{ {
if (cannotReach == m_cannotReachTarget) if (cannotReach == m_cannotReachTarget)
{
return; return;
}
m_cannotReachTarget = cannotReach; m_cannotReachTarget = cannotReach;
m_cannotReachTimer = 0; m_cannotReachTimer = 0;
if (cannotReach) if (cannotReach)
{
LOG_DEBUG("entities.unit", "Creature::SetCannotReachTarget() called with true. Details: {}", GetDebugInfo()); LOG_DEBUG("entities.unit", "Creature::SetCannotReachTarget() called with true. Details: {}", GetDebugInfo());
}
}
bool Creature::CanNotReachTarget() const
{
return m_cannotReachTarget;
}
bool Creature::IsNotReachableAndNeedRegen() const
{
if (CanNotReachTarget())
{
return m_cannotReachTimer >= (sWorld->getIntConfig(CONFIG_NPC_REGEN_TIME_IF_NOT_REACHABLE_IN_RAID) * IN_MILLISECONDS);
}
return false;
} }
time_t Creature::GetLastDamagedTime() const time_t Creature::GetLastDamagedTime() const
+4 -5
View File
@@ -309,10 +309,9 @@ public:
return m_charmInfo->GetCharmSpell(pos)->GetAction(); return m_charmInfo->GetCharmSpell(pos)->GetAction();
} }
void SetCannotReachTarget(bool cannotReach); void SetCannotReachTarget(ObjectGuid const& target = ObjectGuid::Empty);
[[nodiscard]] bool CanNotReachTarget() const { return m_cannotReachTarget; } [[nodiscard]] bool CanNotReachTarget() const;
[[nodiscard]] bool IsNotReachable() const { return (m_cannotReachTimer >= (sWorld->getIntConfig(CONFIG_NPC_EVADE_IF_NOT_REACHABLE) * IN_MILLISECONDS)) && m_cannotReachTarget; } [[nodiscard]] bool IsNotReachableAndNeedRegen() const;
[[nodiscard]] bool IsNotReachableAndNeedRegen() const { return (m_cannotReachTimer >= (sWorld->getIntConfig(CONFIG_NPC_REGEN_TIME_IF_NOT_REACHABLE_IN_RAID) * IN_MILLISECONDS)) && m_cannotReachTarget; }
void SetPosition(float x, float y, float z, float o); void SetPosition(float x, float y, float z, float o);
void SetPosition(const Position& pos) { SetPosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()); } void SetPosition(const Position& pos) { SetPosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()); }
@@ -456,7 +455,7 @@ private:
mutable std::shared_ptr<time_t> _lastDamagedTime; // Part of Evade mechanics mutable std::shared_ptr<time_t> _lastDamagedTime; // Part of Evade mechanics
bool m_cannotReachTarget; ObjectGuid m_cannotReachTarget;
uint32 m_cannotReachTimer; uint32 m_cannotReachTimer;
Spell const* _focusSpell; ///> Locks the target during spell cast for proper facing Spell const* _focusSpell; ///> Locks the target during spell cast for proper facing
@@ -80,8 +80,7 @@ enum CreatureFlagsExtra : uint32
CREATURE_FLAG_EXTRA_HARD_RESET = 0x80000000, CREATURE_FLAG_EXTRA_HARD_RESET = 0x80000000,
// Masks // Masks
CREATURE_FLAG_EXTRA_UNUSED = (CREATURE_FLAG_EXTRA_UNUSED_12 | CREATURE_FLAG_EXTRA_UNUSED_26 | CREATURE_FLAG_EXTRA_UNUSED = (CREATURE_FLAG_EXTRA_UNUSED_12 | CREATURE_FLAG_EXTRA_UNUSED_26 | CREATURE_FLAG_EXTRA_UNUSED_27 | CREATURE_FLAG_EXTRA_UNUSED_28), // SKIP
CREATURE_FLAG_EXTRA_UNUSED_27 | CREATURE_FLAG_EXTRA_UNUSED_28), // SKIP
CREATURE_FLAG_EXTRA_DB_ALLOWED = (0xFFFFFFFF & ~(CREATURE_FLAG_EXTRA_UNUSED | CREATURE_FLAG_EXTRA_DUNGEON_BOSS)) // SKIP CREATURE_FLAG_EXTRA_DB_ALLOWED = (0xFFFFFFFF & ~(CREATURE_FLAG_EXTRA_UNUSED | CREATURE_FLAG_EXTRA_DUNGEON_BOSS)) // SKIP
}; };
@@ -63,7 +63,7 @@ bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
_lastTargetPosition.reset(); _lastTargetPosition.reset();
if (Creature* cOwner2 = owner->ToCreature()) if (Creature* cOwner2 = owner->ToCreature())
{ {
cOwner2->SetCannotReachTarget(false); cOwner2->SetCannotReachTarget();
} }
return true; return true;
@@ -91,13 +91,14 @@ bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
if (i_recalculateTravel && PositionOkay(owner, target, _movingTowards ? maxTarget : Optional<float>(), angle)) if (i_recalculateTravel && PositionOkay(owner, target, _movingTowards ? maxTarget : Optional<float>(), angle))
{ {
i_recalculateTravel = false;
i_path = nullptr;
if (Creature* cOwner2 = owner->ToCreature()) if (Creature* cOwner2 = owner->ToCreature())
{ {
cOwner2->SetCannotReachTarget(false); cOwner2->SetCannotReachTarget(i_path && i_path->GetPathType() & PATHFIND_INCOMPLETE ? target->GetGUID() : ObjectGuid::Empty);
} }
i_recalculateTravel = false;
i_path = nullptr;
owner->StopMoving(); owner->StopMoving();
owner->SetInFront(target); owner->SetInFront(target);
MovementInform(owner); MovementInform(owner);
@@ -107,15 +108,25 @@ bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
if (owner->HasUnitState(UNIT_STATE_CHASE_MOVE) && owner->movespline->Finalized()) if (owner->HasUnitState(UNIT_STATE_CHASE_MOVE) && owner->movespline->Finalized())
{ {
i_recalculateTravel = false;
i_path = nullptr;
owner->ClearUnitState(UNIT_STATE_CHASE_MOVE); owner->ClearUnitState(UNIT_STATE_CHASE_MOVE);
owner->SetInFront(target); owner->SetInFront(target);
MovementInform(owner); MovementInform(owner);
if (owner->IsWithinMeleeRange(this->i_target.getTarget())) if (owner->IsWithinMeleeRange(this->i_target.getTarget()))
{
owner->Attack(this->i_target.getTarget(), true); owner->Attack(this->i_target.getTarget(), true);
} }
else if (i_path && i_path->GetPathType() & PATHFIND_INCOMPLETE)
{
if (Creature* cOwner2 = owner->ToCreature())
{
cOwner2->SetCannotReachTarget(this->i_target.getTarget()->GetGUID());
}
}
i_recalculateTravel = false;
i_path = nullptr;
}
if (_lastTargetPosition && i_target->GetPosition() == _lastTargetPosition.value() && mutualChase == _mutualChase) if (_lastTargetPosition && i_target->GetPosition() == _lastTargetPosition.value() && mutualChase == _mutualChase)
return true; return true;
@@ -139,7 +150,7 @@ bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
// can we get to the target? // can we get to the target?
if (cOwner && !target->isInAccessiblePlaceFor(cOwner)) if (cOwner && !target->isInAccessiblePlaceFor(cOwner))
{ {
cOwner->SetCannotReachTarget(true); cOwner->SetCannotReachTarget(target->GetGUID());
cOwner->StopMoving(); cOwner->StopMoving();
i_path = nullptr; i_path = nullptr;
return true; return true;
@@ -176,7 +187,10 @@ bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
if (!success || i_path->GetPathType() & PATHFIND_NOPATH) if (!success || i_path->GetPathType() & PATHFIND_NOPATH)
{ {
if (cOwner) if (cOwner)
cOwner->SetCannotReachTarget(true); {
cOwner->SetCannotReachTarget(target->GetGUID());
}
return true; return true;
} }
@@ -184,7 +198,9 @@ bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
i_path->ShortenPathUntilDist(G3D::Vector3(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()), maxTarget); i_path->ShortenPathUntilDist(G3D::Vector3(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()), maxTarget);
if (cOwner) if (cOwner)
cOwner->SetCannotReachTarget(false); {
cOwner->SetCannotReachTarget();
}
bool walk = false; bool walk = false;
if (cOwner && !cOwner->IsPet()) if (cOwner && !cOwner->IsPet())
@@ -239,7 +255,9 @@ void ChaseMovementGenerator<T>::DoFinalize(T* owner)
{ {
owner->ClearUnitState(UNIT_STATE_CHASE | UNIT_STATE_CHASE_MOVE); owner->ClearUnitState(UNIT_STATE_CHASE | UNIT_STATE_CHASE_MOVE);
if (Creature* cOwner = owner->ToCreature()) if (Creature* cOwner = owner->ToCreature())
cOwner->SetCannotReachTarget(false); {
cOwner->SetCannotReachTarget();
}
} }
template<class T> template<class T>
@@ -313,6 +313,12 @@ public:
} }
} }
bool OnTeleportUnreacheablePlayer(Player* player) override
{
DoCast(player, SPELL_SUMMON_PLAYER, true);
return true;
}
void DoMeleeAttackIfReady(bool ignoreCasting) void DoMeleeAttackIfReady(bool ignoreCasting)
{ {
if (!ignoreCasting && me->HasUnitState(UNIT_STATE_CASTING)) if (!ignoreCasting && me->HasUnitState(UNIT_STATE_CASTING))