fix(Core/SAI): idle casters (#23005)

This commit is contained in:
killerwife
2025-09-24 01:45:48 +02:00
committed by GitHub
parent bc30a6fba6
commit 8e6d35c9b2
12 changed files with 270 additions and 149 deletions

View File

@@ -310,12 +310,29 @@ void MotionMaster::MoveConfused()
/**
* @brief Force the unit to chase this target. Doesn't work with UNIT_FLAG_DISABLE_MOVE
*/
void MotionMaster::MoveChase(Unit* target, std::optional<ChaseRange> dist, std::optional<ChaseAngle> angle)
void MotionMaster::MoveChase(Unit* target, std::optional<ChaseRange> dist, std::optional<ChaseAngle> angle)
{
// ignore movement request if target not exist
if (!target || target == _owner || _owner->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE))
return;
if (GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
{
if (_owner->IsPlayer())
{
ChaseMovementGenerator<Player>* gen = (ChaseMovementGenerator<Player>*)top();
gen->SetOffsetAndAngle(dist, angle);
gen->SetNewTarget(target);
}
else
{
ChaseMovementGenerator<Creature>* gen = (ChaseMovementGenerator<Creature>*)top();
gen->SetOffsetAndAngle(dist, angle);
gen->SetNewTarget(target);
}
return;
}
//_owner->ClearUnitState(UNIT_STATE_FOLLOW);
if (_owner->IsPlayer())
{
@@ -331,6 +348,24 @@ void MotionMaster::MoveChase(Unit* target, std::optional<ChaseRange> dist, std:
}
}
void MotionMaster::DistanceYourself(float dist)
{
if (GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
{
if (_owner->IsPlayer())
{
ChaseMovementGenerator<Player>* gen = (ChaseMovementGenerator<Player>*)top();
gen->DistanceYourself((Player*)_owner, dist);
}
else
{
ChaseMovementGenerator<Creature>* gen = (ChaseMovementGenerator<Creature>*)top();
gen->DistanceYourself((Creature*)_owner, dist);
}
return;
}
}
void MotionMaster::MoveBackwards(Unit* target, float dist)
{
if (!target)

View File

@@ -247,6 +247,8 @@ public:
void ReinitializeMovement();
bool GetDestination(float& x, float& y, float& z);
void DistanceYourself(float range);
private:
void Mutate(MovementGenerator* m, MovementSlot slot); // use Move* functions instead

View File

@@ -62,6 +62,81 @@ bool ChaseMovementGenerator<T>::PositionOkay(T* owner, Unit* target, Optional<fl
return true;
}
template<class T>
void ChaseMovementGenerator<T>::SetOffsetAndAngle(std::optional<ChaseRange> dist, std::optional<ChaseAngle> angle)
{
_range = dist;
_angle = angle;
_lastTargetPosition.reset();
}
template<class T>
void ChaseMovementGenerator<T>::SetNewTarget(Unit* target)
{
i_target.link(target, this);
_lastTargetPosition.reset();
}
template<class T>
void ChaseMovementGenerator<T>::DistanceYourself(T* owner, float distance)
{
// make a new path if we have to...
if (!i_path)
i_path = std::make_unique<PathGenerator>(owner);
float x, y, z;
i_target->GetNearPoint(owner, x, y, z, owner->GetBoundaryRadius(), distance, i_target->GetAngle(owner));
if (DispatchSplineToPosition(owner, x, y, z, false, false, 0.f, false, false))
{
m_currentMode = CHASE_MODE_DISTANCING;
if constexpr (!std::is_same_v<T, Player>)
{
owner->AI()->DistancingStarted();
}
}
}
template<class T>
bool ChaseMovementGenerator<T>::DispatchSplineToPosition(T* owner, float x, float y, float z, bool walk, bool cutPath, float maxTarget, bool forceDest, bool target)
{
Creature* cOwner = owner->ToCreature();
if (owner->IsHovering())
owner->UpdateAllowedPositionZ(x, y, z);
bool success = i_path->CalculatePath(x, y, z, forceDest);
if (!success || i_path->GetPathType() & PATHFIND_NOPATH)
{
if (cOwner)
{
cOwner->SetCannotReachTarget(i_target.getTarget()->GetGUID());
}
owner->StopMoving();
return true;
}
if (cutPath)
i_path->ShortenPathUntilDist(G3D::Vector3(x, y, z), maxTarget);
if (cOwner)
{
cOwner->SetCannotReachTarget();
}
owner->AddUnitState(UNIT_STATE_CHASE_MOVE);
i_recalculateTravel = true;
Movement::MoveSplineInit init(owner);
init.MovebyPath(i_path->GetPath());
if (target)
init.SetFacing(i_target.getTarget());
init.SetWalk(walk);
init.Launch();
return false;
}
template<class T>
bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
{
@@ -71,6 +146,13 @@ bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
if (!owner || !owner->IsAlive())
return false;
if (owner->HasUnitState(UNIT_STATE_NO_COMBAT_MOVEMENT)) // script paused combat movement
{
owner->StopMoving();
_lastTargetPosition.reset();
return true;
}
Creature* cOwner = owner->ToCreature();
bool isStoppedBecauseOfCasting = cOwner && cOwner->IsMovementPreventedByCasting();
@@ -243,53 +325,23 @@ bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
shortenPath = false;
}
if (owner->IsHovering())
owner->UpdateAllowedPositionZ(x, y, z);
bool success = i_path->CalculatePath(x, y, z, forceDest);
if (!success || i_path->GetPathType() & PATHFIND_NOPATH)
{
if (cOwner)
{
cOwner->SetCannotReachTarget(target->GetGUID());
}
owner->StopMoving();
return true;
}
if (shortenPath)
i_path->ShortenPathUntilDist(G3D::Vector3(x, y, z), maxTarget);
if (cOwner)
{
cOwner->SetCannotReachTarget();
}
bool walk = false;
if (cOwner && !cOwner->IsPet())
{
switch (cOwner->GetMovementTemplate().GetChase())
{
case CreatureChaseMovementType::CanWalk:
walk = owner->IsWalking();
break;
case CreatureChaseMovementType::AlwaysWalk:
walk = true;
break;
default:
break;
case CreatureChaseMovementType::CanWalk:
walk = owner->IsWalking();
break;
case CreatureChaseMovementType::AlwaysWalk:
walk = true;
break;
default:
break;
}
}
owner->AddUnitState(UNIT_STATE_CHASE_MOVE);
i_recalculateTravel = true;
Movement::MoveSplineInit init(owner);
init.MovebyPath(i_path->GetPath());
init.SetFacing(target);
init.SetWalk(walk);
init.Launch();
DispatchSplineToPosition(owner, x, y, z, walk, shortenPath, maxTarget, forceDest, true);
}
}
@@ -339,9 +391,24 @@ void ChaseMovementGenerator<T>::MovementInform(T* owner)
if (!owner->IsCreature())
return;
// Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle
if (CreatureAI* AI = owner->ToCreature()->AI())
AI->MovementInform(CHASE_MOTION_TYPE, i_target.getTarget()->GetGUID().GetCounter());
switch (m_currentMode)
{
default:
{
// Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle
if (CreatureAI* AI = owner->ToCreature()->AI())
AI->MovementInform(CHASE_MOTION_TYPE, i_target.getTarget()->GetGUID().GetCounter());
break;
}
case CHASE_MODE_DISTANCING:
{
if (CreatureAI* AI = owner->ToCreature()->AI())
AI->DistancingEnded();
break;
}
}
m_currentMode = CHASE_MODE_NORMAL;
}
//-----------------------------------------------//
@@ -604,6 +671,13 @@ template bool ChaseMovementGenerator<Player>::DoUpdate(Player*, uint32);
template bool ChaseMovementGenerator<Creature>::DoUpdate(Creature*, uint32);
template void ChaseMovementGenerator<Unit>::MovementInform(Unit*);
template void ChaseMovementGenerator<Creature>::SetOffsetAndAngle(std::optional<ChaseRange>, std::optional<ChaseAngle>);
template void ChaseMovementGenerator<Creature>::SetNewTarget(Unit*);
template void ChaseMovementGenerator<Creature>::DistanceYourself(Creature*, float);
template void ChaseMovementGenerator<Player>::SetOffsetAndAngle(std::optional<ChaseRange>, std::optional<ChaseAngle>);
template void ChaseMovementGenerator<Player>::SetNewTarget(Unit*);
template void ChaseMovementGenerator<Player>::DistanceYourself(Player*, float);
template void FollowMovementGenerator<Player>::DoInitialize(Player*);
template void FollowMovementGenerator<Creature>::DoInitialize(Creature*);
template void FollowMovementGenerator<Player>::DoFinalize(Player*);

View File

@@ -34,12 +34,20 @@ protected:
FollowerReference i_target;
};
enum ChaseMovementMode
{
CHASE_MODE_NORMAL, // chasing target
CHASE_MODE_BACKPEDAL, // collision movement
CHASE_MODE_DISTANCING, // running away from melee
CHASE_MODE_FANNING, // mob collision movement
};
template<class T>
class ChaseMovementGenerator : public MovementGeneratorMedium<T, ChaseMovementGenerator<T>>, public TargetedMovementGeneratorBase
{
public:
ChaseMovementGenerator(Unit* target, Optional<ChaseRange> range = {}, Optional<ChaseAngle> angle = {})
: TargetedMovementGeneratorBase(target), i_leashExtensionTimer(5000), i_path(nullptr), i_recheckDistance(0), i_recalculateTravel(true), _range(range), _angle(angle) {}
: TargetedMovementGeneratorBase(target), i_leashExtensionTimer(5000), i_path(nullptr), i_recheckDistance(0), i_recalculateTravel(true), _range(range), _angle(angle), m_currentMode(CHASE_MODE_NORMAL) {}
~ChaseMovementGenerator() { }
MovementGeneratorType GetMovementGeneratorType() { return CHASE_MOTION_TYPE; }
@@ -58,6 +66,11 @@ public:
bool EnableWalking() const { return false; }
bool HasLostTarget(Unit* unit) const { return unit->GetVictim() != this->GetTarget(); }
void SetOffsetAndAngle(std::optional<ChaseRange> dist, std::optional<ChaseAngle> angle);
void SetNewTarget(Unit* target);
void DistanceYourself(T* owner, float distance);
bool DispatchSplineToPosition(T* owner, float x, float y, float z, bool walk, bool cutPath, float maxTarget, bool forceDest, bool target = false);
private:
TimeTrackerSmall i_leashExtensionTimer;
std::unique_ptr<PathGenerator> i_path;
@@ -65,10 +78,12 @@ private:
bool i_recalculateTravel;
Optional<Position> _lastTargetPosition;
Optional<ChaseRange> const _range;
Optional<ChaseAngle> const _angle;
Optional<ChaseRange> _range;
Optional<ChaseAngle> _angle;
bool _movingTowards = true;
bool _mutualChase = true;
ChaseMovementMode m_currentMode;
};
template<class T>