feat(Core/CreatureAI): improve npc position during the combat (#3369)
+ tangent equation to find correct angle and distance when moving + implemented proper backward * Improved performance + random angle margin * chore: add tollerance calculation in instance * improved LOS checks with movements * implemented collisions using raycast (imported by TC) + improved collision detection for CanReachPositionAndGetCoords + improved collision check + set correct flags for the backward movement + first implementation of slope angle (to improve) Co-authored-by: Yehonal <yehonal.azeroth@gmail.com>
This commit is contained in:
@@ -586,6 +586,36 @@ void Creature::Update(uint32 diff)
|
||||
RemoveCharmAuras();
|
||||
}
|
||||
|
||||
// Circling the target
|
||||
if (diff >= m_moveCircleMovementTime)
|
||||
{
|
||||
AI()->MoveCircleChecks();
|
||||
m_moveCircleMovementTime = urand(MOVE_CIRCLE_CHECK_INTERVAL * 2, MOVE_CIRCLE_CHECK_INTERVAL * 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_moveCircleMovementTime -= diff;
|
||||
}
|
||||
|
||||
// If we are closer than 50% of the combat reach we are going to reposition the victim
|
||||
if (Unit *victim = GetVictim();
|
||||
victim && GetDistance(victim->GetPosition()) < CalculatePct(GetCombatReach() + victim->GetCombatReach(), 50)) {
|
||||
if (diff >= m_moveBackwardsMovementTime)
|
||||
{
|
||||
AI()->MoveBackwardsChecks();
|
||||
m_moveBackwardsMovementTime = urand(MOVE_BACKWARDS_CHECK_INTERVAL/2, MOVE_BACKWARDS_CHECK_INTERVAL * 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_moveBackwardsMovementTime -= diff;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_moveBackwardsMovementTime = MOVE_BACKWARDS_CHECK_INTERVAL;
|
||||
}
|
||||
|
||||
|
||||
if (!IsInEvadeMode() && IsAIEnabled)
|
||||
{
|
||||
// do not allow the AI to be changed during update
|
||||
@@ -620,7 +650,7 @@ void Creature::Update(uint32 diff)
|
||||
{
|
||||
AI()->EnterEvadeMode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -655,6 +685,20 @@ void Creature::Update(uint32 diff)
|
||||
}
|
||||
}
|
||||
|
||||
bool Creature::IsFreeToMove()
|
||||
{
|
||||
uint32 moveFlags = m_movementInfo.GetMovementFlags();
|
||||
// Do not reposition ourself when we are not allowed to move
|
||||
if ((IsMovementPreventedByCasting() || isMoving() || !CanFreeMove()) &&
|
||||
(GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE ||
|
||||
moveFlags & MOVEMENTFLAG_SPLINE_ENABLED))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Creature::Regenerate(Powers power)
|
||||
{
|
||||
uint32 curValue = GetPower(power);
|
||||
@@ -1522,8 +1566,10 @@ bool Creature::CanStartAttack(Unit const* who) const
|
||||
|
||||
// This set of checks is should be done only for creatures
|
||||
if ((HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC) && who->GetTypeId() != TYPEID_PLAYER) || // flag is valid only for non player characters
|
||||
(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC) && who->GetTypeId() == TYPEID_PLAYER)) // immune to PC and target is a player, return false
|
||||
(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC) && who->GetTypeId() == TYPEID_PLAYER)) // immune to PC and target is a player, return false
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Unit* owner = who->GetOwner())
|
||||
if (owner->GetTypeId() == TYPEID_PLAYER && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC)) // immune to PC and target has player owner
|
||||
@@ -2833,6 +2879,16 @@ void Creature::FocusTarget(Spell const* focusSpell, WorldObject const* target)
|
||||
SetInFront(target);
|
||||
}
|
||||
|
||||
bool Creature::HasSpellFocus(Spell const* focusSpell) const
|
||||
{
|
||||
if (isDead()) // dead creatures cannot focus
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return focusSpell ? (focusSpell == _spellFocusInfo.Spell) : (_spellFocusInfo.Spell || _spellFocusInfo.Delay);
|
||||
}
|
||||
|
||||
void Creature::ReleaseFocus(Spell const* focusSpell)
|
||||
{
|
||||
// focused to something else
|
||||
@@ -2890,3 +2946,25 @@ float Creature::GetAttackDistance(Unit const* player) const
|
||||
|
||||
return (retDistance * aggroRate);
|
||||
}
|
||||
|
||||
bool Creature::IsMovementPreventedByCasting() const
|
||||
{
|
||||
Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL];
|
||||
// first check if currently a movement allowed channel is active and we're not casting
|
||||
if (!!spell && spell->getState() != SPELL_STATE_FINISHED && spell->IsChannelActive() && spell->GetSpellInfo()->IsMoveAllowedChannel())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HasSpellFocus())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -385,7 +385,7 @@ typedef std::list<VendorItemCount> VendorItemCounts;
|
||||
|
||||
struct TrainerSpell
|
||||
{
|
||||
TrainerSpell()
|
||||
TrainerSpell()
|
||||
{
|
||||
for (unsigned int & i : learnedSpell)
|
||||
i = 0;
|
||||
@@ -510,6 +510,15 @@ public:
|
||||
bool SetWaterWalking(bool enable, bool packetOnly = false) override;
|
||||
bool SetFeatherFall(bool enable, bool packetOnly = false) override;
|
||||
bool SetHover(bool enable, bool packetOnly = false) override;
|
||||
bool HasSpellFocus(Spell const* focusSpell = nullptr) const;
|
||||
|
||||
struct
|
||||
{
|
||||
::Spell const* Spell = nullptr;
|
||||
uint32 Delay = 0; // ms until the creature's target should snap back (0 = no snapback scheduled)
|
||||
uint64 Target; // the creature's "real" target while casting
|
||||
float Orientation = 0.0f; // the creature's "real" orientation while casting
|
||||
} _spellFocusInfo;
|
||||
|
||||
[[nodiscard]] uint32 GetShieldBlockValue() const override
|
||||
{
|
||||
@@ -714,11 +723,18 @@ public:
|
||||
void SetTarget(uint64 guid) override;
|
||||
void FocusTarget(Spell const* focusSpell, WorldObject const* target);
|
||||
void ReleaseFocus(Spell const* focusSpell);
|
||||
bool IsMovementPreventedByCasting() const;
|
||||
|
||||
// Part of Evade mechanics
|
||||
[[nodiscard]] time_t GetLastDamagedTime() const { return _lastDamagedTime; }
|
||||
void SetLastDamagedTime(time_t val) { _lastDamagedTime = val; }
|
||||
|
||||
bool IsFreeToMove();
|
||||
static constexpr uint32 MOVE_CIRCLE_CHECK_INTERVAL = 1500;
|
||||
static constexpr uint32 MOVE_BACKWARDS_CHECK_INTERVAL = 2000;
|
||||
uint32 m_moveCircleMovementTime = MOVE_CIRCLE_CHECK_INTERVAL;
|
||||
uint32 m_moveBackwardsMovementTime = MOVE_BACKWARDS_CHECK_INTERVAL;
|
||||
|
||||
protected:
|
||||
bool CreateFromProto(uint32 guidlow, uint32 Entry, uint32 vehId, const CreatureData* data = nullptr);
|
||||
bool InitEntry(uint32 entry, const CreatureData* data = nullptr);
|
||||
@@ -787,7 +803,7 @@ private:
|
||||
|
||||
bool m_cannotReachTarget;
|
||||
uint32 m_cannotReachTimer;
|
||||
|
||||
|
||||
Spell const* _focusSpell; ///> Locks the target during spell cast for proper facing
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user