[3.3.5] Core/Movement: MotionMaster & MovementGenerators cleaning (#19361)

(cherry picked from commit 21b8c4997a)
This commit is contained in:
ccrs
2017-04-07 21:35:23 +02:00
committed by funjoker
parent 7f64eaa3ee
commit 14c6a4d823
20 changed files with 845 additions and 766 deletions

View File

@@ -8658,7 +8658,7 @@ void Unit::SetSpeedRate(UnitMoveType mtype, float rate)
m_speed_rate[mtype] = rate;
propagateSpeedChange();
PropagateSpeedChange();
// Spline packets are for creatures and move_update are for players
static OpcodeServer const moveTypeToOpcode[MAX_MOVE_TYPE][3] =
@@ -10661,9 +10661,9 @@ void Unit::SendPetAIReaction(ObjectGuid guid)
owner->ToPlayer()->SendDirectMessage(packet.Write());
}
void Unit::propagateSpeedChange()
void Unit::PropagateSpeedChange()
{
GetMotionMaster()->propagateSpeedChange();
GetMotionMaster()->PropagateSpeedChange();
}
///----------End of Pet responses methods----------

View File

@@ -1915,7 +1915,7 @@ class TC_GAME_API Unit : public WorldObject
void SendPetAIReaction(ObjectGuid guid);
///----------End of Pet responses methods----------
void propagateSpeedChange();
void PropagateSpeedChange();
// reactive attacks
void ClearAllReactives();

View File

@@ -32,6 +32,7 @@
#include "SplineChainMovementGenerator.h"
#include "MoveSpline.h"
#include "MoveSplineInit.h"
#include "PathGenerator.h"
inline bool IsStatic(MovementGenerator* movement)
{
@@ -76,7 +77,7 @@ void MotionMaster::InitDefault()
if (_owner->GetTypeId() == TYPEID_UNIT)
{
MovementGenerator* movement = FactorySelector::selectMovementGenerator(_owner->ToCreature());
Mutate(movement == NULL ? &si_idleMovement : movement, MOTION_SLOT_IDLE);
Mutate(movement == nullptr ? &si_idleMovement : movement, MOTION_SLOT_IDLE);
}
else
{
@@ -89,9 +90,6 @@ void MotionMaster::UpdateMotion(uint32 diff)
if (!_owner)
return;
if (_owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) // what about UNIT_STATE_DISTRACTED? Why is this not included?
return;
ASSERT(!empty());
_cleanFlag |= MMCF_UPDATE;
@@ -174,12 +172,12 @@ MovementGenerator* MotionMaster::GetMotionSlot(int slot) const
return _slot[slot];
}
void MotionMaster::propagateSpeedChange()
void MotionMaster::PropagateSpeedChange()
{
for (int i = 0; i <= _top; ++i)
{
if (_slot[i])
_slot[i]->unitSpeedChanged();
_slot[i]->UnitSpeedChanged();
}
}

View File

@@ -125,7 +125,7 @@ class TC_GAME_API MotionMaster
MovementGeneratorType GetMotionSlotType(int slot) const;
MovementGenerator* GetMotionSlot(int slot) const;
void propagateSpeedChange();
void PropagateSpeedChange();
bool GetDestination(float &x, float &y, float &z);

View File

@@ -33,14 +33,12 @@ class TC_GAME_API MovementGenerator
virtual void Initialize(Unit*) = 0;
virtual void Finalize(Unit*) = 0;
virtual void Reset(Unit*) = 0;
virtual bool Update(Unit*, uint32 time_diff) = 0;
virtual bool Update(Unit*, uint32 diff) = 0;
virtual MovementGeneratorType GetMovementGeneratorType() const = 0;
virtual void unitSpeedChanged() { }
virtual void UnitSpeedChanged() { }
// used by Evade code for select point to evade with expected restart default movement
virtual bool GetResetPosition(Unit*, float& /*x*/, float& /*y*/, float& /*z*/) { return false; }
@@ -52,42 +50,39 @@ class MovementGeneratorMedium : public MovementGenerator
public:
void Initialize(Unit* u) override
{
//u->AssertIsType<T>();
(static_cast<D*>(this))->DoInitialize(static_cast<T*>(u));
}
void Finalize(Unit* u) override
{
//u->AssertIsType<T>();
(static_cast<D*>(this))->DoFinalize(static_cast<T*>(u));
}
void Reset(Unit* u) override
{
//u->AssertIsType<T>();
(static_cast<D*>(this))->DoReset(static_cast<T*>(u));
}
bool Update(Unit* u, uint32 time_diff) override
{
//u->AssertIsType<T>();
return (static_cast<D*>(this))->DoUpdate(static_cast<T*>(u), time_diff);
}
};
struct SelectableMovement : public FactoryHolder<MovementGenerator, MovementGeneratorType>
{
SelectableMovement(MovementGeneratorType mgt) : FactoryHolder<MovementGenerator, MovementGeneratorType>(mgt) { }
SelectableMovement(MovementGeneratorType movementGeneratorType) : FactoryHolder<MovementGenerator, MovementGeneratorType>(movementGeneratorType) { }
};
template<class REAL_MOVEMENT>
template<class Movement>
struct MovementGeneratorFactory : public SelectableMovement
{
MovementGeneratorFactory(MovementGeneratorType mgt) : SelectableMovement(mgt) { }
MovementGeneratorFactory(MovementGeneratorType movementGeneratorType) : SelectableMovement(movementGeneratorType) { }
MovementGenerator* Create(void *) const override;
};
typedef FactoryHolder<MovementGenerator, MovementGeneratorType> MovementGeneratorCreator;
typedef FactoryHolder<MovementGenerator, MovementGeneratorType>::FactoryHolderRegistry MovementGeneratorRegistry;
#endif

View File

@@ -20,10 +20,10 @@
#include "MovementGenerator.h"
template<class MOVEMENT_GEN>
inline MovementGenerator*
MovementGeneratorFactory<MOVEMENT_GEN>::Create(void * /*data*/) const
template<class Movement>
inline MovementGenerator* MovementGeneratorFactory<Movement>::Create(void * /*data*/) const
{
return (new MOVEMENT_GEN());
return (new Movement());
}
#endif

View File

@@ -16,92 +16,95 @@
*/
#include "Creature.h"
#include "ConfusedMovementGenerator.h"
#include "Player.h"
#include "PathGenerator.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
#include "Player.h"
#include "Random.h"
#include "ConfusedMovementGenerator.h"
template<class T>
void ConfusedMovementGenerator<T>::DoInitialize(T* unit)
ConfusedMovementGenerator<T>::~ConfusedMovementGenerator()
{
unit->AddUnitState(UNIT_STATE_CONFUSED);
unit->AddUnitFlag(UNIT_FLAG_CONFUSED);
unit->GetPosition(i_x, i_y, i_z);
if (!unit->IsAlive() || unit->IsStopped())
return;
unit->StopMoving();
unit->AddUnitState(UNIT_STATE_CONFUSED_MOVE);
delete _path;
}
template<class T>
void ConfusedMovementGenerator<T>::DoReset(T* unit)
void ConfusedMovementGenerator<T>::DoInitialize(T* owner)
{
i_nextMoveTime.Reset(0);
if (!unit->IsAlive() || unit->IsStopped())
if (!owner || !owner->IsAlive())
return;
unit->StopMoving();
unit->AddUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE);
owner->AddUnitState(UNIT_STATE_CONFUSED);
owner->AddUnitFlag(UNIT_FLAG_CONFUSED);
owner->StopMoving();
_timer.Reset(0);
owner->GetPosition(_reference.m_positionX, _reference.m_positionY, _reference.m_positionZ);
}
template<class T>
bool ConfusedMovementGenerator<T>::DoUpdate(T* unit, uint32 diff)
void ConfusedMovementGenerator<T>::DoReset(T* owner)
{
if (unit->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED))
return true;
DoInitialize(owner);
}
if (i_nextMoveTime.Passed())
template<class T>
bool ConfusedMovementGenerator<T>::DoUpdate(T* owner, uint32 diff)
{
if (!owner || !owner->IsAlive())
return false;
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
{
// currently moving, update location
unit->AddUnitState(UNIT_STATE_CONFUSED_MOVE);
if (unit->movespline->Finalized())
i_nextMoveTime.Reset(urand(800, 1500));
_interrupt = true;
owner->StopMoving();
return true;
}
else
_interrupt = false;
// waiting for next move
_timer.Update(diff);
if (!_interrupt && _timer.Passed() && owner->movespline->Finalized())
{
// waiting for next move
i_nextMoveTime.Update(diff);
if (i_nextMoveTime.Passed())
// start moving
owner->AddUnitState(UNIT_STATE_CONFUSED_MOVE);
Position destination(_reference);
float distance = 4.0f * frand(0.0f, 1.0f) - 2.0f;
float angle = frand(0.0f, 1.0f) * float(M_PI) * 2.0f;
owner->MovePositionToFirstCollision(destination, distance, angle);
if (!_path)
_path = new PathGenerator(owner);
_path->SetPathLengthLimit(30.0f);
bool result = _path->CalculatePath(destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ());
if (!result || (_path->GetPathType() & PATHFIND_NOPATH))
{
// start moving
unit->AddUnitState(UNIT_STATE_CONFUSED_MOVE);
float dest = 4.0f * (float)rand_norm() - 2.0f;
Position pos;
pos.Relocate(i_x, i_y, i_z);
unit->MovePositionToFirstCollision(pos, dest, 0.0f);
PathGenerator path(unit);
path.SetPathLengthLimit(30.0f);
bool result = path.CalculatePath(pos.m_positionX, pos.m_positionY, pos.m_positionZ);
if (!result || (path.GetPathType() & PATHFIND_NOPATH))
{
i_nextMoveTime.Reset(100);
return true;
}
Movement::MoveSplineInit init(unit);
init.MovebyPath(path.GetPath());
init.SetWalk(true);
init.Launch();
_timer.Reset(100);
return true;
}
Movement::MoveSplineInit init(owner);
init.MovebyPath(_path->GetPath());
init.SetWalk(true);
int32 traveltime = init.Launch();
_timer.Reset(traveltime + urand(800, 1500));
}
return true;
}
template<class T>
void ConfusedMovementGenerator<T>::DoFinalize(T*) { }
template<>
void ConfusedMovementGenerator<Player>::DoFinalize(Player* unit)
{
unit->RemoveUnitFlag(UNIT_FLAG_CONFUSED);
unit->ClearUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE);
unit->ClearUnitState(UNIT_STATE_CONFUSED);
unit->StopMoving();
}
@@ -114,6 +117,8 @@ void ConfusedMovementGenerator<Creature>::DoFinalize(Creature* unit)
unit->SetTarget(unit->EnsureVictim()->GetGUID());
}
template ConfusedMovementGenerator<Player>::~ConfusedMovementGenerator();
template ConfusedMovementGenerator<Creature>::~ConfusedMovementGenerator();
template void ConfusedMovementGenerator<Player>::DoInitialize(Player*);
template void ConfusedMovementGenerator<Creature>::DoInitialize(Creature*);
template void ConfusedMovementGenerator<Player>::DoReset(Player*);

View File

@@ -25,16 +25,21 @@ template<class T>
class ConfusedMovementGenerator : public MovementGeneratorMedium< T, ConfusedMovementGenerator<T> >
{
public:
explicit ConfusedMovementGenerator() : i_nextMoveTime(0), i_x(0), i_y(0), i_z(0) { }
explicit ConfusedMovementGenerator() : _path(nullptr), _timer(0), _reference(0.f, 0.f, 0.f), _interrupt(false) { }
~ConfusedMovementGenerator();
MovementGeneratorType GetMovementGeneratorType() const override { return CONFUSED_MOTION_TYPE; }
void DoInitialize(T*);
void DoFinalize(T*);
void DoReset(T*);
bool DoUpdate(T*, uint32);
MovementGeneratorType GetMovementGeneratorType() const override { return CONFUSED_MOTION_TYPE; }
private:
TimeTracker i_nextMoveTime;
float i_x, i_y, i_z;
PathGenerator* _path;
TimeTracker _timer;
Position _reference;
bool _interrupt;
};
#endif

View File

@@ -15,106 +15,24 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Creature.h"
#include "VMapFactory.h"
#include "CreatureAI.h"
#include "FleeingMovementGenerator.h"
#include "PathGenerator.h"
#include "ObjectAccessor.h"
#include "Creature.h"
#include "Player.h"
#include "PathGenerator.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
#include "PhasingHandler.h"
#include "Player.h"
#include "VMapFactory.h"
#include "FleeingMovementGenerator.h"
#define MIN_QUIET_DISTANCE 28.0f
#define MAX_QUIET_DISTANCE 43.0f
template<class T>
void FleeingMovementGenerator<T>::_setTargetLocation(T* owner)
FleeingMovementGenerator<T>::~FleeingMovementGenerator()
{
if (!owner)
return;
if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
return;
if (owner->IsMovementPreventedByCasting())
{
owner->CastStop();
return;
}
owner->AddUnitState(UNIT_STATE_FLEEING_MOVE);
float x, y, z;
_getPoint(owner, x, y, z);
// Add LOS check for target point
Position mypos = owner->GetPosition();
bool isInLOS = VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(
PhasingHandler::GetTerrainMapId(owner->GetPhaseShift(), owner->GetMap(), mypos.m_positionX, mypos.m_positionY),
mypos.m_positionX, mypos.m_positionY, mypos.m_positionZ + 2.0f, x, y, z + 2.0f, VMAP::ModelIgnoreFlags::Nothing);
if (!isInLOS)
{
i_nextCheckTime.Reset(200);
return;
}
PathGenerator path(owner);
path.SetPathLengthLimit(30.0f);
bool result = path.CalculatePath(x, y, z);
if (!result || (path.GetPathType() & PATHFIND_NOPATH))
{
i_nextCheckTime.Reset(100);
return;
}
Movement::MoveSplineInit init(owner);
init.MovebyPath(path.GetPath());
init.SetWalk(false);
int32 traveltime = init.Launch();
i_nextCheckTime.Reset(traveltime + urand(800, 1500));
}
template<class T>
void FleeingMovementGenerator<T>::_getPoint(T* owner, float &x, float &y, float &z)
{
float dist_from_caster, angle_to_caster;
if (Unit* fright = ObjectAccessor::GetUnit(*owner, i_frightGUID))
{
dist_from_caster = fright->GetDistance(owner);
if (dist_from_caster > 0.2f)
angle_to_caster = fright->GetAngle(owner);
else
angle_to_caster = frand(0, 2 * static_cast<float>(M_PI));
}
else
{
dist_from_caster = 0.0f;
angle_to_caster = frand(0, 2 * static_cast<float>(M_PI));
}
float dist, angle;
if (dist_from_caster < MIN_QUIET_DISTANCE)
{
dist = frand(0.4f, 1.3f)*(MIN_QUIET_DISTANCE - dist_from_caster);
angle = angle_to_caster + frand(-static_cast<float>(M_PI)/8, static_cast<float>(M_PI)/8);
}
else if (dist_from_caster > MAX_QUIET_DISTANCE)
{
dist = frand(0.4f, 1.0f)*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE);
angle = -angle_to_caster + frand(-static_cast<float>(M_PI)/4, static_cast<float>(M_PI)/4);
}
else // we are inside quiet range
{
dist = frand(0.6f, 1.2f)*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE);
angle = frand(0, 2*static_cast<float>(M_PI));
}
Position pos = owner->GetFirstCollisionPosition(dist, angle);
x = pos.m_positionX;
y = pos.m_positionY;
z = pos.m_positionZ;
delete _path;
}
template<class T>
@@ -124,15 +42,20 @@ void FleeingMovementGenerator<T>::DoInitialize(T* owner)
return;
owner->AddUnitFlag(UNIT_FLAG_FLEEING);
owner->AddUnitState(UNIT_STATE_FLEEING | UNIT_STATE_FLEEING_MOVE);
_setTargetLocation(owner);
owner->AddUnitState(UNIT_STATE_FLEEING);
SetTargetLocation(owner);
}
template<class T>
void FleeingMovementGenerator<T>::DoFinalize(T *)
{
}
template<>
void FleeingMovementGenerator<Player>::DoFinalize(Player* owner)
{
owner->RemoveUnitFlag(UNIT_FLAG_FLEEING);
owner->ClearUnitState(UNIT_STATE_FLEEING | UNIT_STATE_FLEEING_MOVE);
owner->ClearUnitState(UNIT_STATE_FLEEING);
owner->StopMoving();
}
@@ -140,7 +63,7 @@ template<>
void FleeingMovementGenerator<Creature>::DoFinalize(Creature* owner)
{
owner->RemoveUnitFlag(UNIT_FLAG_FLEEING);
owner->ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE);
owner->ClearUnitState(UNIT_STATE_FLEEING | UNIT_STATE_FLEEING_MOVE);
if (owner->GetVictim())
owner->SetTarget(owner->EnsureVictim()->GetGUID());
}
@@ -152,39 +75,143 @@ void FleeingMovementGenerator<T>::DoReset(T* owner)
}
template<class T>
bool FleeingMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
bool FleeingMovementGenerator<T>::DoUpdate(T* owner, uint32 diff)
{
if (!owner || !owner->IsAlive())
return false;
if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
{
owner->ClearUnitState(UNIT_STATE_FLEEING_MOVE);
_interrupt = true;
owner->StopMoving();
return true;
}
else
_interrupt = false;
i_nextCheckTime.Update(time_diff);
if (i_nextCheckTime.Passed() && owner->movespline->Finalized())
_setTargetLocation(owner);
_timer.Update(diff);
if (!_interrupt && _timer.Passed() && owner->movespline->Finalized())
SetTargetLocation(owner);
return true;
}
template<class T>
void FleeingMovementGenerator<T>::SetTargetLocation(T* owner)
{
if (!owner)
return;
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
{
_interrupt = true;
owner->StopMoving();
return;
}
owner->AddUnitState(UNIT_STATE_FLEEING_MOVE);
Position destination = owner->GetPosition();
GetPoint(owner, destination);
// Add LOS check for target point
Position currentPosition = owner->GetPosition();
if (!VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(PhasingHandler::GetTerrainMapId(owner->GetPhaseShift(), owner->GetMap(), currentPosition.m_positionX, currentPosition.m_positionY), currentPosition.m_positionX, currentPosition.m_positionY, currentPosition.m_positionZ + 2.0f, destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ() + 2.0f, VMAP::ModelIgnoreFlags::Nothing))
{
_timer.Reset(200);
return;
}
if (!_path)
_path = new PathGenerator(owner);
_path->SetPathLengthLimit(30.0f);
bool result = _path->CalculatePath(destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ());
if (!result || (_path->GetPathType() & PATHFIND_NOPATH))
{
_timer.Reset(100);
return;
}
Movement::MoveSplineInit init(owner);
init.MovebyPath(_path->GetPath());
init.SetWalk(false);
int32 traveltime = init.Launch();
_timer.Reset(traveltime + urand(800, 1500));
}
template<class T>
void FleeingMovementGenerator<T>::GetPoint(T* owner, Position &position)
{
float casterDistance, casterAngle;
if (Unit* fleeTarget = ObjectAccessor::GetUnit(*owner, _fleeTargetGUID))
{
casterDistance = fleeTarget->GetDistance(owner);
if (casterDistance > 0.2f)
casterAngle = fleeTarget->GetAngle(owner);
else
casterAngle = frand(0.0f, 2.0f * float(M_PI));
}
else
{
casterDistance = 0.0f;
casterAngle = frand(0.0f, 2.0f * float(M_PI));
}
float distance, angle;
if (casterDistance < MIN_QUIET_DISTANCE)
{
distance = frand(0.4f, 1.3f) * (MIN_QUIET_DISTANCE - casterDistance);
angle = casterAngle + frand(-float(M_PI) / 8.0f, float(M_PI) / 8.0f);
}
else if (casterDistance > MAX_QUIET_DISTANCE)
{
distance = frand(0.4f, 1.0f) * (MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE);
angle = -casterAngle + frand(-float(M_PI) / 4.0f, float(M_PI) / 4.0f);
}
else // we are inside quiet range
{
distance = frand(0.6f, 1.2f) * (MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE);
angle = frand(0.0f, 2.0f * float(M_PI));
}
owner->MovePositionToFirstCollision(position, distance, angle);
}
template FleeingMovementGenerator<Player>::~FleeingMovementGenerator();
template FleeingMovementGenerator<Creature>::~FleeingMovementGenerator();
template void FleeingMovementGenerator<Player>::DoInitialize(Player*);
template void FleeingMovementGenerator<Creature>::DoInitialize(Creature*);
template void FleeingMovementGenerator<Player>::_getPoint(Player*, float&, float&, float&);
template void FleeingMovementGenerator<Creature>::_getPoint(Creature*, float&, float&, float&);
template void FleeingMovementGenerator<Player>::_setTargetLocation(Player*);
template void FleeingMovementGenerator<Creature>::_setTargetLocation(Creature*);
template void FleeingMovementGenerator<Player>::DoReset(Player*);
template void FleeingMovementGenerator<Creature>::DoReset(Creature*);
template bool FleeingMovementGenerator<Player>::DoUpdate(Player*, uint32);
template bool FleeingMovementGenerator<Creature>::DoUpdate(Creature*, uint32);
template void FleeingMovementGenerator<Player>::SetTargetLocation(Player*);
template void FleeingMovementGenerator<Creature>::SetTargetLocation(Creature*);
template void FleeingMovementGenerator<Player>::GetPoint(Player*, Position &);
template void FleeingMovementGenerator<Creature>::GetPoint(Creature*, Position &);
//---- TimedFleeingMovementGenerator
bool TimedFleeingMovementGenerator::Update(Unit* owner, uint32 time_diff)
{
if (!owner->IsAlive())
return false;
_totalFleeTime.Update(time_diff);
if (_totalFleeTime.Passed())
return false;
// This calls grant-parent Update method hiden by FleeingMovementGenerator::Update(Creature &, uint32) version
// This is done instead of casting Unit& to Creature& and call parent method, then we can use Unit directly
return MovementGeneratorMedium< Creature, FleeingMovementGenerator<Creature> >::Update(owner, time_diff);
}
void TimedFleeingMovementGenerator::Finalize(Unit* owner)
{
owner->RemoveUnitFlag(UNIT_FLAG_FLEEING);
owner->ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE);
owner->ClearUnitState(UNIT_STATE_FLEEING);
owner->StopMoving();
if (Unit* victim = owner->GetVictim())
{
if (owner->IsAlive())
@@ -194,23 +221,3 @@ void TimedFleeingMovementGenerator::Finalize(Unit* owner)
}
}
}
bool TimedFleeingMovementGenerator::Update(Unit* owner, uint32 time_diff)
{
if (!owner->IsAlive())
return false;
if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
{
owner->ClearUnitState(UNIT_STATE_FLEEING_MOVE);
return true;
}
i_totalFleeTime.Update(time_diff);
if (i_totalFleeTime.Passed())
return false;
// This calls grant-parent Update method hiden by FleeingMovementGenerator::Update(Creature &, uint32) version
// This is done instead of casting Unit& to Creature& and call parent method, then we can use Unit directly
return MovementGeneratorMedium< Creature, FleeingMovementGenerator<Creature> >::Update(owner, time_diff);
}

View File

@@ -19,41 +19,43 @@
#define TRINITY_FLEEINGMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
#include "Timer.h"
template<class T>
class FleeingMovementGenerator : public MovementGeneratorMedium< T, FleeingMovementGenerator<T> >
{
public:
FleeingMovementGenerator(ObjectGuid fright) : i_frightGUID(fright), i_nextCheckTime(0) { }
explicit FleeingMovementGenerator(ObjectGuid fleeTargetGUID) : _path(nullptr), _fleeTargetGUID(fleeTargetGUID), _timer(0), _interrupt(false) { }
~FleeingMovementGenerator();
MovementGeneratorType GetMovementGeneratorType() const override { return FLEEING_MOTION_TYPE; }
void DoInitialize(T*);
void DoFinalize(T*);
void DoReset(T*);
bool DoUpdate(T*, uint32);
MovementGeneratorType GetMovementGeneratorType() const override { return FLEEING_MOTION_TYPE; }
private:
void _setTargetLocation(T*);
void _getPoint(T*, float &x, float &y, float &z);
void SetTargetLocation(T*);
void GetPoint(T*, Position &position);
ObjectGuid i_frightGUID;
TimeTracker i_nextCheckTime;
PathGenerator* _path;
ObjectGuid _fleeTargetGUID;
TimeTracker _timer;
bool _interrupt;
};
class TimedFleeingMovementGenerator : public FleeingMovementGenerator<Creature>
{
public:
TimedFleeingMovementGenerator(ObjectGuid fright, uint32 time) :
FleeingMovementGenerator<Creature>(fright),
i_totalFleeTime(time) { }
explicit TimedFleeingMovementGenerator(ObjectGuid fleeTargetGUID, uint32 time) : FleeingMovementGenerator<Creature>(fleeTargetGUID), _totalFleeTime(time) { }
MovementGeneratorType GetMovementGeneratorType() const override { return TIMED_FLEEING_MOTION_TYPE; }
bool Update(Unit*, uint32) override;
void Finalize(Unit*) override;
private:
TimeTracker i_totalFleeTime;
TimeTracker _totalFleeTime;
};
#endif

View File

@@ -15,36 +15,31 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "HomeMovementGenerator.h"
#include "Creature.h"
#include "CreatureAI.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
#include "PathGenerator.h"
#include "HomeMovementGenerator.h"
void HomeMovementGenerator<Creature>::DoInitialize(Creature* owner)
template<class T>
HomeMovementGenerator<T>::~HomeMovementGenerator() { }
template<>
HomeMovementGenerator<Creature>::~HomeMovementGenerator()
{
_setTargetLocation(owner);
delete _path;
}
void HomeMovementGenerator<Creature>::DoFinalize(Creature* owner)
{
if (arrived)
{
owner->ClearUnitState(UNIT_STATE_EVADE);
owner->SetWalk(true);
owner->LoadCreaturesAddon();
owner->AI()->JustReachedHome();
owner->SetSpawnHealth();
}
}
template<class T>
void HomeMovementGenerator<T>::SetTargetLocation(T*) { }
void HomeMovementGenerator<Creature>::DoReset(Creature*) { }
void HomeMovementGenerator<Creature>::_setTargetLocation(Creature* owner)
template<>
void HomeMovementGenerator<Creature>::SetTargetLocation(Creature* owner)
{
if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED))
{ // if we are ROOT/STUNNED/DISTRACTED even after aura clear, finalize on next update - otherwise we would get stuck in evade
skipToHome = true;
_skipToHome = true;
return;
}
@@ -60,14 +55,55 @@ void HomeMovementGenerator<Creature>::_setTargetLocation(Creature* owner)
init.SetWalk(false);
init.Launch();
skipToHome = false;
arrived = false;
_skipToHome = false;
_arrived = false;
owner->ClearUnitState(UNIT_STATE_ALL_ERASABLE & ~UNIT_STATE_EVADE);
}
bool HomeMovementGenerator<Creature>::DoUpdate(Creature* owner, const uint32 /*time_diff*/)
template<class T>
void HomeMovementGenerator<T>::DoInitialize(T*) { }
template<>
void HomeMovementGenerator<Creature>::DoInitialize(Creature* owner)
{
arrived = skipToHome || owner->movespline->Finalized();
return !arrived;
SetTargetLocation(owner);
}
template<class T>
void HomeMovementGenerator<T>::DoFinalize(T*) { }
template<>
void HomeMovementGenerator<Creature>::DoFinalize(Creature* owner)
{
if (_arrived)
{
owner->ClearUnitState(UNIT_STATE_EVADE);
owner->SetWalk(true);
owner->LoadCreaturesAddon();
owner->AI()->JustReachedHome();
owner->SetSpawnHealth();
}
}
template<class T>
void HomeMovementGenerator<T>::DoReset(T*) { }
template<>
void HomeMovementGenerator<Creature>::DoReset(Creature* owner)
{
DoInitialize(owner);
}
template<class T>
bool HomeMovementGenerator<T>::DoUpdate(T*, uint32)
{
return false;
}
template<>
bool HomeMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 /*diff*/)
{
_arrived = _skipToHome || owner->movespline->Finalized();
return !_arrived;
}

View File

@@ -20,28 +20,26 @@
#include "MovementGenerator.h"
class Creature;
template < class T >
class HomeMovementGenerator;
template <>
class HomeMovementGenerator<Creature> : public MovementGeneratorMedium< Creature, HomeMovementGenerator<Creature> >
template <class T>
class HomeMovementGenerator : public MovementGeneratorMedium< T, HomeMovementGenerator<T> >
{
public:
explicit HomeMovementGenerator() : _path(nullptr), _arrived(false), _skipToHome(false) { }
~HomeMovementGenerator();
HomeMovementGenerator() : arrived(false), skipToHome(false) { }
~HomeMovementGenerator() { }
void DoInitialize(Creature*);
void DoFinalize(Creature*);
void DoReset(Creature*);
bool DoUpdate(Creature*, const uint32);
MovementGeneratorType GetMovementGeneratorType() const override { return HOME_MOTION_TYPE; }
void DoInitialize(T*);
void DoFinalize(T*);
void DoReset(T*);
bool DoUpdate(T*, uint32);
private:
void _setTargetLocation(Creature*);
bool arrived;
bool skipToHome;
void SetTargetLocation(T*);
PathGenerator* _path;
bool _arrived;
bool _skipToHome;
};
#endif

View File

@@ -35,6 +35,8 @@ void IdleMovementGenerator::Reset(Unit* owner)
owner->StopMoving();
}
//----------------------------------------------------//
void RotateMovementGenerator::Initialize(Unit* owner)
{
if (!owner->IsStopped())
@@ -50,27 +52,29 @@ void RotateMovementGenerator::Initialize(Unit* owner)
bool RotateMovementGenerator::Update(Unit* owner, uint32 diff)
{
float angle = owner->GetOrientation();
angle += (float(diff) * static_cast<float>(M_PI * 2) / m_maxDuration) * (m_direction == ROTATE_DIRECTION_LEFT ? 1.0f : -1.0f);
angle += (float(diff) * static_cast<float>(M_PI * 2) / _maxDuration) * (_direction == ROTATE_DIRECTION_LEFT ? 1.0f : -1.0f);
angle = G3D::wrap(angle, 0.0f, float(G3D::twoPi()));
owner->SetOrientation(angle); // UpdateSplinePosition does not set orientation with UNIT_STATE_ROTATING
owner->SetFacingTo(angle); // Send spline movement to clients
if (m_duration > diff)
m_duration -= diff;
if (_duration > diff)
_duration -= diff;
else
return false;
return true;
}
void RotateMovementGenerator::Finalize(Unit* unit)
void RotateMovementGenerator::Finalize(Unit* owner)
{
unit->ClearUnitState(UNIT_STATE_ROTATING);
if (unit->GetTypeId() == TYPEID_UNIT)
unit->ToCreature()->AI()->MovementInform(ROTATE_MOTION_TYPE, 0);
owner->ClearUnitState(UNIT_STATE_ROTATING);
if (owner->GetTypeId() == TYPEID_UNIT)
owner->ToCreature()->AI()->MovementInform(ROTATE_MOTION_TYPE, 0);
}
//----------------------------------------------------//
void DistractMovementGenerator::Initialize(Unit* owner)
{
// Distracted creatures stand up if not standing
@@ -92,17 +96,19 @@ void DistractMovementGenerator::Finalize(Unit* owner)
}
}
bool DistractMovementGenerator::Update(Unit* /*owner*/, uint32 time_diff)
bool DistractMovementGenerator::Update(Unit* /*owner*/, uint32 diff)
{
if (time_diff > m_timer)
if (diff > _timer)
return false;
m_timer -= time_diff;
_timer -= diff;
return true;
}
void AssistanceDistractMovementGenerator::Finalize(Unit* unit)
//----------------------------------------------------//
void AssistanceDistractMovementGenerator::Finalize(Unit* owner)
{
unit->ClearUnitState(UNIT_STATE_DISTRACTED);
unit->ToCreature()->SetReactState(REACT_AGGRESSIVE);
owner->ClearUnitState(UNIT_STATE_DISTRACTED);
owner->ToCreature()->SetReactState(REACT_AGGRESSIVE);
}

View File

@@ -19,11 +19,11 @@
#define TRINITY_IDLEMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
#include "Timer.h"
class IdleMovementGenerator : public MovementGenerator
{
public:
void Initialize(Unit*) override;
void Finalize(Unit*) override { }
void Reset(Unit*) override;
@@ -36,7 +36,7 @@ TC_GAME_API extern IdleMovementGenerator si_idleMovement;
class RotateMovementGenerator : public MovementGenerator
{
public:
explicit RotateMovementGenerator(uint32 time, RotateDirection direction) : m_duration(time), m_maxDuration(time), m_direction(direction) { }
explicit RotateMovementGenerator(uint32 time, RotateDirection direction) : _duration(time), _maxDuration(time), _direction(direction) { }
void Initialize(Unit*) override;
void Finalize(Unit*) override;
@@ -45,14 +45,14 @@ class RotateMovementGenerator : public MovementGenerator
MovementGeneratorType GetMovementGeneratorType() const override { return ROTATE_MOTION_TYPE; }
private:
uint32 m_duration, m_maxDuration;
RotateDirection m_direction;
uint32 _duration, _maxDuration;
RotateDirection _direction;
};
class DistractMovementGenerator : public MovementGenerator
{
public:
explicit DistractMovementGenerator(uint32 timer) : m_timer(timer) { }
explicit DistractMovementGenerator(uint32 timer) : _timer(timer) { }
void Initialize(Unit*) override;
void Finalize(Unit*) override;
@@ -61,14 +61,13 @@ class DistractMovementGenerator : public MovementGenerator
MovementGeneratorType GetMovementGeneratorType() const override { return DISTRACT_MOTION_TYPE; }
private:
uint32 m_timer;
uint32 _timer;
};
class AssistanceDistractMovementGenerator : public DistractMovementGenerator
{
public:
AssistanceDistractMovementGenerator(uint32 timer) :
DistractMovementGenerator(timer) { }
explicit AssistanceDistractMovementGenerator(uint32 timer) : DistractMovementGenerator(timer) { }
MovementGeneratorType GetMovementGeneratorType() const override { return ASSISTANCE_DISTRACT_MOTION_TYPE; }
void Finalize(Unit*) override;

View File

@@ -15,33 +15,42 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "PointMovementGenerator.h"
#include "Errors.h"
#include "Creature.h"
#include "CreatureAI.h"
#include "World.h"
#include "Creature.h"
#include "CreatureGroups.h"
#include "Player.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
#include "Player.h"
#include "CreatureGroups.h"
#include "ObjectAccessor.h"
#include "World.h"
#include "PointMovementGenerator.h"
//----- Point Movement Generator
template<class T>
void PointMovementGenerator<T>::DoInitialize(T* unit)
void PointMovementGenerator<T>::DoInitialize(T* owner)
{
if (!unit->IsStopped())
unit->StopMoving();
unit->AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
if (id == EVENT_CHARGE_PREPATH)
if (_movementId == EVENT_CHARGE_PREPATH)
{
owner->AddUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE);
return;
}
Movement::MoveSplineInit init(unit);
init.MoveTo(i_x, i_y, i_z, m_generatePath);
if (speed > 0.0f)
init.SetVelocity(speed);
owner->AddUnitState(UNIT_STATE_ROAMING);
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
{
_interrupt = true;
owner->StopMoving();
return;
}
owner->AddUnitState(UNIT_STATE_ROAMING_MOVE);
Movement::MoveSplineInit init(owner);
init.MoveTo(_destination.GetPositionX(), _destination.GetPositionY(), _destination.GetPositionZ(), _generatePath);
if (_speed > 0.0f)
init.SetVelocity(_speed);
if (i_faceTarget)
init.SetFacing(i_faceTarget);
if (i_spellEffectExtra)
@@ -49,69 +58,73 @@ void PointMovementGenerator<T>::DoInitialize(T* unit)
init.Launch();
// Call for creature group update
if (Creature* creature = unit->ToCreature())
if (Creature* creature = owner->ToCreature())
if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature)
creature->GetFormation()->LeaderMoveTo(i_x, i_y, i_z);
creature->GetFormation()->LeaderMoveTo(_destination.GetPositionX(), _destination.GetPositionY(), _destination.GetPositionZ());
}
template<class T>
bool PointMovementGenerator<T>::DoUpdate(T* unit, uint32 /*diff*/)
bool PointMovementGenerator<T>::DoUpdate(T* owner, uint32 /*diff*/)
{
if (!unit)
if (!owner)
return false;
if (unit->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
if (_movementId == EVENT_CHARGE_PREPATH)
return !owner->movespline->Finalized();
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
{
unit->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
_interrupt = true;
owner->StopMoving();
return true;
}
unit->AddUnitState(UNIT_STATE_ROAMING_MOVE);
if (id != EVENT_CHARGE_PREPATH && i_recalculateSpeed && !unit->movespline->Finalized())
if ((_interrupt && owner->movespline->Finalized()) || (_recalculateSpeed && !owner->movespline->Finalized()))
{
i_recalculateSpeed = false;
Movement::MoveSplineInit init(unit);
init.MoveTo(i_x, i_y, i_z, m_generatePath);
if (speed > 0.0f) // Default value for point motion type is 0.0, if 0.0 spline will use GetSpeed on unit
init.SetVelocity(speed);
_recalculateSpeed = false;
_interrupt = false;
owner->AddUnitState(UNIT_STATE_ROAMING_MOVE);
Movement::MoveSplineInit init(owner);
init.MoveTo(_destination.GetPositionX(), _destination.GetPositionY(), _destination.GetPositionZ(), _generatePath);
if (_speed > 0.0f) // Default value for point motion type is 0.0, if 0.0 spline will use GetSpeed on unit
init.SetVelocity(_speed);
init.Launch();
// Call for creature group update
if (Creature* creature = unit->ToCreature())
if (Creature* creature = owner->ToCreature())
if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature)
creature->GetFormation()->LeaderMoveTo(i_x, i_y, i_z);
creature->GetFormation()->LeaderMoveTo(_destination.GetPositionX(), _destination.GetPositionY(), _destination.GetPositionZ());
}
return !unit->movespline->Finalized();
return !owner->movespline->Finalized();
}
template<class T>
void PointMovementGenerator<T>::DoFinalize(T* unit)
void PointMovementGenerator<T>::DoFinalize(T* owner)
{
if (unit->HasUnitState(UNIT_STATE_CHARGING))
unit->ClearUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE);
owner->ClearUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE);
if (unit->movespline->Finalized())
MovementInform(unit);
if (owner->movespline->Finalized())
MovementInform(owner);
}
template<class T>
void PointMovementGenerator<T>::DoReset(T* unit)
void PointMovementGenerator<T>::DoReset(T* owner)
{
if (!unit->IsStopped())
unit->StopMoving();
unit->AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
owner->StopMoving();
DoInitialize(owner);
}
template<class T>
void PointMovementGenerator<T>::MovementInform(T* /*unit*/) { }
void PointMovementGenerator<T>::MovementInform(T*) { }
template <> void PointMovementGenerator<Creature>::MovementInform(Creature* unit)
template <>
void PointMovementGenerator<Creature>::MovementInform(Creature* owner)
{
if (unit->AI())
unit->AI()->MovementInform(POINT_MOTION_TYPE, id);
if (owner->AI())
owner->AI()->MovementInform(POINT_MOTION_TYPE, _movementId);
}
template void PointMovementGenerator<Player>::DoInitialize(Player*);
@@ -123,34 +136,36 @@ template void PointMovementGenerator<Creature>::DoReset(Creature*);
template bool PointMovementGenerator<Player>::DoUpdate(Player*, uint32);
template bool PointMovementGenerator<Creature>::DoUpdate(Creature*, uint32);
void AssistanceMovementGenerator::Finalize(Unit* unit)
//---- AssistanceMovementGenerator
void AssistanceMovementGenerator::Finalize(Unit* owner)
{
unit->ToCreature()->SetNoCallAssistance(false);
unit->ToCreature()->CallAssistance();
if (unit->IsAlive())
unit->GetMotionMaster()->MoveSeekAssistanceDistract(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY));
owner->ClearUnitState(UNIT_STATE_ROAMING);
owner->StopMoving();
owner->ToCreature()->SetNoCallAssistance(false);
owner->ToCreature()->CallAssistance();
if (owner->IsAlive())
owner->GetMotionMaster()->MoveSeekAssistanceDistract(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY));
}
bool EffectMovementGenerator::Update(Unit* unit, uint32)
//---- EffectMovementGenerator
bool EffectMovementGenerator::Update(Unit* owner, uint32 /*diff*/)
{
return !unit->movespline->Finalized();
return !owner->movespline->Finalized();
}
void EffectMovementGenerator::Finalize(Unit* unit)
void EffectMovementGenerator::Finalize(Unit* owner)
{
MovementInform(owner);
}
void EffectMovementGenerator::MovementInform(Unit* owner)
{
if (_arrivalSpellId)
unit->CastSpell(ObjectAccessor::GetUnit(*unit, _arrivalSpellTargetGuid), _arrivalSpellId, true);
owner->CastSpell(ObjectAccessor::GetUnit(*owner, _arrivalSpellTargetGuid), _arrivalSpellId, true);
if (unit->GetTypeId() != TYPEID_UNIT)
return;
// Need restore previous movement since we have no proper states system
if (unit->IsAlive() && !unit->HasUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_FLEEING))
{
if (Unit* victim = unit->GetVictim())
unit->GetMotionMaster()->MoveChase(victim);
}
if (unit->ToCreature()->AI())
unit->ToCreature()->AI()->MovementInform(EFFECT_MOTION_TYPE, _id);
if (Creature* creature = owner->ToCreature())
if (creature->AI())
creature->AI()->MovementInform(EFFECT_MOTION_TYPE, _pointId);
}

View File

@@ -19,7 +19,6 @@
#define TRINITY_POINTMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
#include "FollowerReference.h"
class Creature;
namespace Movement
@@ -31,56 +30,54 @@ template<class T>
class PointMovementGenerator : public MovementGeneratorMedium< T, PointMovementGenerator<T> >
{
public:
PointMovementGenerator(uint32 _id, float _x, float _y, float _z, bool _generatePath, float _speed = 0.0f, Unit const* faceTarget = nullptr,
Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr) : id(_id),
i_x(_x), i_y(_y), i_z(_z), speed(_speed), i_faceTarget(faceTarget), i_spellEffectExtra(spellEffectExtraData),
m_generatePath(_generatePath), i_recalculateSpeed(false) { }
explicit PointMovementGenerator(uint32 id, float x, float y, float z, bool generatePath, float speed = 0.0f, Unit const* faceTarget = nullptr, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr) : _movementId(id), _destination(x, y, z), _speed(speed), i_faceTarget(faceTarget), i_spellEffectExtra(spellEffectExtraData), _generatePath(generatePath), _recalculateSpeed(false), _interrupt(false) { }
MovementGeneratorType GetMovementGeneratorType() const override { return POINT_MOTION_TYPE; }
void DoInitialize(T*);
void DoFinalize(T*);
void DoReset(T*);
bool DoUpdate(T*, uint32);
void UnitSpeedChanged() override { _recalculateSpeed = true; }
private:
void MovementInform(T*);
void unitSpeedChanged() override { i_recalculateSpeed = true; }
MovementGeneratorType GetMovementGeneratorType() const override { return POINT_MOTION_TYPE; }
void GetDestination(float& x, float& y, float& z) const { x = i_x; y = i_y; z = i_z; }
private:
uint32 id;
float i_x, i_y, i_z;
float speed;
uint32 _movementId;
Position _destination;
float _speed;
Unit const* i_faceTarget;
Movement::SpellEffectExtraData const* i_spellEffectExtra;
bool m_generatePath;
bool i_recalculateSpeed;
bool _generatePath;
bool _recalculateSpeed;
bool _interrupt;
};
class AssistanceMovementGenerator : public PointMovementGenerator<Creature>
{
public:
AssistanceMovementGenerator(float _x, float _y, float _z) :
PointMovementGenerator<Creature>(0, _x, _y, _z, true) { }
explicit AssistanceMovementGenerator(float _x, float _y, float _z) : PointMovementGenerator<Creature>(0, _x, _y, _z, true) { }
MovementGeneratorType GetMovementGeneratorType() const override { return ASSISTANCE_MOTION_TYPE; }
void Finalize(Unit*) override;
};
// Does almost nothing - just doesn't allows previous movegen interrupt current effect.
class EffectMovementGenerator : public MovementGenerator
{
public:
EffectMovementGenerator(uint32 id, uint32 arrivalSpellId = 0, ObjectGuid const& arrivalSpellTargetGuid = ObjectGuid::Empty)
: _id(id), _arrivalSpellId(arrivalSpellId), _arrivalSpellTargetGuid(arrivalSpellTargetGuid) { }
explicit EffectMovementGenerator(uint32 id, uint32 arrivalSpellId = 0, ObjectGuid const& arrivalSpellTargetGuid = ObjectGuid::Empty) : _pointId(id), _arrivalSpellId(arrivalSpellId), _arrivalSpellTargetGuid(arrivalSpellTargetGuid) { }
void Initialize(Unit*) override { }
void Finalize(Unit*) override;
void Reset(Unit*) override { }
bool Update(Unit*, uint32) override;
MovementGeneratorType GetMovementGeneratorType() const override { return EFFECT_MOTION_TYPE; }
private:
uint32 _id;
void MovementInform(Unit*);
uint32 _pointId;
uint32 _arrivalSpellId;
ObjectGuid _arrivalSpellTargetGuid;
};

View File

@@ -16,165 +16,133 @@
*/
#include "Creature.h"
#include "RandomMovementGenerator.h"
#include "Map.h"
#include "Util.h"
#include "CreatureGroups.h"
#include "Map.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
#include "PathGenerator.h"
#include "Random.h"
#include "RandomMovementGenerator.h"
#define RUNNING_CHANCE_RANDOMMV 20 //will be "1 / RUNNING_CHANCE_RANDOMMV"
template<class T>
RandomMovementGenerator<T>::~RandomMovementGenerator() { }
template<>
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature* creature)
RandomMovementGenerator<Creature>::~RandomMovementGenerator()
{
if (creature->IsMovementPreventedByCasting())
delete _path;
}
template<class T>
void RandomMovementGenerator<T>::DoInitialize(T*) { }
template<>
void RandomMovementGenerator<Creature>::DoInitialize(Creature* owner)
{
if (!owner || !owner->IsAlive())
return;
owner->AddUnitState(UNIT_STATE_ROAMING);
owner->GetPosition(_reference.m_positionX, _reference.m_positionY, _reference.m_positionZ);
owner->StopMoving();
if (!_wanderDistance)
_wanderDistance = owner->GetRespawnRadius();
_timer.Reset(0);
}
template<class T>
void RandomMovementGenerator<T>::DoFinalize(T*) { }
template<>
void RandomMovementGenerator<Creature>::DoFinalize(Creature* owner)
{
owner->ClearUnitState(UNIT_STATE_ROAMING);
owner->StopMoving();
owner->SetWalk(false);
}
template<class T>
void RandomMovementGenerator<T>::DoReset(T*) { }
template<>
void RandomMovementGenerator<Creature>::DoReset(Creature* owner)
{
DoInitialize(owner);
}
template<class T>
void RandomMovementGenerator<T>::SetRandomLocation(T*) { }
template<>
void RandomMovementGenerator<Creature>::SetRandomLocation(Creature* owner)
{
if (!owner)
return;
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
{
creature->CastStop();
_interrupt = true;
owner->StopMoving();
return;
}
float respX, respY, respZ, respO, destX, destY, destZ, travelDistZ;
creature->GetHomePosition(respX, respY, respZ, respO);
Map const* map = creature->GetMap();
owner->AddUnitState(UNIT_STATE_ROAMING_MOVE);
// For 2D/3D system selection
//bool is_land_ok = creature.CanWalk(); // not used?
//bool is_water_ok = creature.CanSwim(); // not used?
bool is_air_ok = creature->CanFly();
Position position(_reference);
float distance = frand(0.f, 1.f) * _wanderDistance;
float angle = frand(0.f, 1.f) * float(M_PI) * 2.f;
owner->MovePositionToFirstCollision(position, distance, angle);
const float angle = float(rand_norm()) * static_cast<float>(M_PI*2.0f);
const float range = float(rand_norm()) * wander_distance;
const float distanceX = range * std::cos(angle);
const float distanceY = range * std::sin(angle);
uint32 resetTimer = roll_chance_i(50) ? urand(5000, 10000) : urand(1000, 2000);
destX = respX + distanceX;
destY = respY + distanceY;
if (!_path)
_path = new PathGenerator(owner);
// prevent invalid coordinates generation
Trinity::NormalizeMapCoord(destX);
Trinity::NormalizeMapCoord(destY);
travelDistZ = range; // sin^2+cos^2=1, so travelDistZ=range^2; no need for sqrt below
if (is_air_ok) // 3D system above ground and above water (flying mode)
_path->SetPathLengthLimit(30.0f);
bool result = _path->CalculatePath(position.GetPositionX(), position.GetPositionY(), position.GetPositionZ());
if (!result || (_path->GetPathType() & PATHFIND_NOPATH))
{
// Limit height change
const float distanceZ = float(rand_norm()) * travelDistZ/2.0f;
destZ = respZ + distanceZ;
float levelZ = map->GetWaterOrGroundLevel(creature->GetPhaseShift(), destX, destY, destZ-2.5f);
// Problem here, we must fly above the ground and water, not under. Let's try on next tick
if (levelZ >= destZ)
return;
}
//else if (is_water_ok) // 3D system under water and above ground (swimming mode)
else // 2D only
{
// 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE)
travelDistZ = travelDistZ >= 10.0f ? 10.0f : travelDistZ;
// The fastest way to get an accurate result 90% of the time.
// Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long.
destZ = map->GetHeight(creature->GetPhaseShift(), destX, destY, respZ+travelDistZ-2.0f, false);
if (std::fabs(destZ - respZ) > travelDistZ) // Map check
{
// Vmap Horizontal or above
destZ = map->GetHeight(creature->GetPhaseShift(), destX, destY, respZ - 2.0f, true);
if (std::fabs(destZ - respZ) > travelDistZ)
{
// Vmap Higher
destZ = map->GetHeight(creature->GetPhaseShift(), destX, destY, respZ+travelDistZ-2.0f, true);
// let's forget this bad coords where a z cannot be find and retry at next tick
if (std::fabs(destZ - respZ) > travelDistZ)
return;
}
}
_timer.Reset(100);
return;
}
if (is_air_ok)
i_nextMoveTime.Reset(0);
else
{
if (roll_chance_i(50))
i_nextMoveTime.Reset(urand(5000, 10000));
else
i_nextMoveTime.Reset(urand(50, 400));
}
creature->AddUnitState(UNIT_STATE_ROAMING_MOVE);
Movement::MoveSplineInit init(creature);
init.MoveTo(destX, destY, destZ);
Movement::MoveSplineInit init(owner);
init.MovebyPath(_path->GetPath());
init.SetWalk(true);
init.Launch();
int32 traveltime = init.Launch();
_timer.Reset(traveltime + resetTimer);
//Call for creature group update
if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature)
creature->GetFormation()->LeaderMoveTo(destX, destY, destZ);
// Call for creature group update
if (owner->GetFormation() && owner->GetFormation()->getLeader() == owner)
owner->GetFormation()->LeaderMoveTo(position.m_positionX, position.m_positionY, position.m_positionZ);
}
template<class T>
bool RandomMovementGenerator<T>::DoUpdate(T*, uint32)
{
return false;
}
template<>
void RandomMovementGenerator<Creature>::DoInitialize(Creature* creature)
bool RandomMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 diff)
{
if (!creature->IsAlive())
return;
if (!wander_distance)
wander_distance = creature->GetRespawnRadius();
creature->AddUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE);
_setRandomLocation(creature);
}
template<>
void RandomMovementGenerator<Creature>::DoReset(Creature* creature)
{
DoInitialize(creature);
}
template<>
void RandomMovementGenerator<Creature>::DoFinalize(Creature* creature)
{
creature->ClearUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
creature->SetWalk(false);
}
template<>
bool RandomMovementGenerator<Creature>::DoUpdate(Creature* creature, const uint32 diff)
{
if (!creature || !creature->IsAlive())
if (!owner || !owner->IsAlive())
return false;
if (creature->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED))
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
{
i_nextMoveTime.Reset(0); // Expire the timer
creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
_interrupt = true;
owner->StopMoving();
return true;
}
else
_interrupt = false;
if (creature->movespline->Finalized())
{
i_nextMoveTime.Update(diff);
if (i_nextMoveTime.Passed())
_setRandomLocation(creature);
}
return true;
}
template<>
bool RandomMovementGenerator<Creature>::GetResetPos(Creature* creature, float& x, float& y, float& z)
{
float radius;
creature->GetRespawnPosition(x, y, z, NULL, &radius);
// use current if in range
if (creature->IsWithinDist2d(x, y, radius))
creature->GetPosition(x, y, z);
_timer.Update(diff);
if (!_interrupt && _timer.Passed() && owner->movespline->Finalized())
SetRandomLocation(owner);
return true;
}

View File

@@ -19,23 +19,30 @@
#define TRINITY_RANDOMMOTIONGENERATOR_H
#include "MovementGenerator.h"
#include "Timer.h"
template<class T>
class RandomMovementGenerator : public MovementGeneratorMedium< T, RandomMovementGenerator<T> >
{
public:
RandomMovementGenerator(float spawn_dist = 0.0f) : i_nextMoveTime(0), wander_distance(spawn_dist) { }
explicit RandomMovementGenerator(float distance = 0.0f) : _path(nullptr), _timer(0), _reference(0.f, 0.f, 0.f), _wanderDistance(distance), _interrupt(false) { }
~RandomMovementGenerator();
MovementGeneratorType GetMovementGeneratorType() const override { return RANDOM_MOTION_TYPE; }
void _setRandomLocation(T*);
void DoInitialize(T*);
void DoFinalize(T*);
void DoReset(T*);
bool DoUpdate(T*, const uint32);
bool GetResetPos(T*, float& x, float& y, float& z);
MovementGeneratorType GetMovementGeneratorType() const override { return RANDOM_MOTION_TYPE; }
private:
TimeTrackerSmall i_nextMoveTime;
bool DoUpdate(T*, uint32);
float wander_distance;
private:
void SetRandomLocation(T*);
PathGenerator* _path;
TimeTracker _timer;
Position _reference;
float _wanderDistance;
bool _interrupt;
};
#endif

View File

@@ -15,226 +15,209 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ByteBuffer.h"
#include "TargetedMovementGenerator.h"
#include "Errors.h"
#include "Creature.h"
#include "CreatureAI.h"
#include "World.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
#include "Creature.h"
#include "Player.h"
#include "VehicleDefines.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
#include "PathGenerator.h"
#include "World.h"
#include "TargetedMovementGenerator.h"
template<class T, typename D>
void TargetedMovementGeneratorMedium<T, D>::_setTargetLocation(T* owner, bool updateDestination)
TargetedMovementGenerator<T, D>::~TargetedMovementGenerator()
{
if (!i_target.isValid() || !i_target->IsInWorld())
return;
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE))
return;
if (owner->IsMovementPreventedByCasting())
return;
if (owner->GetTypeId() == TYPEID_UNIT && !i_target->isInAccessiblePlaceFor(owner->ToCreature()))
{
owner->ToCreature()->SetCannotReachTarget(true);
return;
}
if (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->IsFocusing(nullptr, true))
return;
float x, y, z;
if (updateDestination || !i_path)
{
if (!i_offset)
{
if (i_target->IsWithinDistInMap(owner, CONTACT_DISTANCE))
return;
// to nearest contact position
i_target->GetContactPoint(owner, x, y, z);
}
else
{
float dist;
float size;
// Pets need special handling.
// We need to subtract GetCombatReach() because it gets added back further down the chain
// and that makes pets too far away. Subtracting it allows pets to properly
// be (GetCombatReach() + i_offset) away.
// Only applies when i_target is pet's owner otherwise pets and mobs end up
// doing a "dance" while fighting
if (owner->IsPet() && i_target->GetTypeId() == TYPEID_PLAYER)
{
dist = 1.0f; //i_target->GetCombatReach();
size = 1.0f; //i_target->GetCombatReach() - i_target->GetCombatReach();
}
else
{
dist = i_offset + 1.0f;
size = owner->GetCombatReach();
}
if (i_target->IsWithinDistInMap(owner, dist))
return;
// to at i_offset distance from target and i_angle from target facing
i_target->GetClosePoint(x, y, z, size, i_offset, i_angle);
}
}
else
{
// the destination has not changed, we just need to refresh the path (usually speed change)
G3D::Vector3 end = i_path->GetEndPosition();
x = end.x;
y = end.y;
z = end.z;
}
if (!i_path)
i_path = new PathGenerator(owner);
// allow pets to use shortcut if no path found when following their master
bool forceDest = (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->IsPet()
&& owner->HasUnitState(UNIT_STATE_FOLLOW));
bool result = i_path->CalculatePath(x, y, z, forceDest);
if (!result || (i_path->GetPathType() & PATHFIND_NOPATH))
{
// can't reach target
i_recalculateTravel = true;
if (owner->GetTypeId() == TYPEID_UNIT)
owner->ToCreature()->SetCannotReachTarget(true);
return;
}
D::_addUnitStateMove(owner);
i_targetReached = false;
i_recalculateTravel = false;
owner->AddUnitState(UNIT_STATE_CHASE);
if (owner->GetTypeId() == TYPEID_UNIT)
owner->ToCreature()->SetCannotReachTarget(false);
Movement::MoveSplineInit init(owner);
init.MovebyPath(i_path->GetPath());
init.SetWalk(((D*)this)->EnableWalking());
// Using the same condition for facing target as the one that is used for SetInFront on movement end
// - applies to ChaseMovementGenerator mostly
if (i_angle == 0.f)
init.SetFacing(i_target.getTarget());
init.Launch();
delete _path;
}
template<class T, typename D>
bool TargetedMovementGeneratorMedium<T, D>::DoUpdate(T* owner, uint32 time_diff)
bool TargetedMovementGenerator<T, D>::DoUpdate(T* owner, uint32 diff)
{
if (!i_target.isValid() || !i_target->IsInWorld())
if (!IsTargetValid() || !GetTarget()->IsInWorld())
return false;
if (!owner || !owner->IsAlive())
return false;
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE))
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting() || HasLostTarget(owner)
|| (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->IsFocusing(nullptr, true)))
{
D::_clearUnitStateMove(owner);
_interrupt = true;
owner->StopMoving();
return true;
}
// prevent movement while casting spells with cast time or channel time
if (owner->IsMovementPreventedByCasting())
if (_interrupt || _recalculateTravel)
{
if (!owner->IsStopped())
owner->StopMoving();
return true;
}
// prevent crash after creature killed pet
if (static_cast<D*>(this)->_lostTarget(owner))
{
D::_clearUnitStateMove(owner);
_interrupt = false;
SetTargetLocation(owner, true);
return true;
}
bool targetMoved = false;
i_recheckDistance.Update(time_diff);
if (i_recheckDistance.Passed())
_timer.Update(diff);
if (!_interrupt && _timer.Passed())
{
i_recheckDistance.Reset(100);
_timer.Reset(100);
//More distance let have better performance, less distance let have more sensitive reaction at target move.
float allowed_dist = 0.0f;
float distance = owner->GetCombatReach() + sWorld->getRate(RATE_TARGET_POS_RECALCULATION_RANGE);
if (owner->IsPet() && (owner->GetCharmerOrOwnerGUID() == GetTarget()->GetGUID()))
distance = 1.f; // pet following owner
if (owner->IsPet() && (owner->GetCharmerOrOwnerGUID() == i_target->GetGUID()))
allowed_dist = 1.0f; // pet following owner
else
allowed_dist = owner->GetCombatReach() + sWorld->getRate(RATE_TARGET_POS_RECALCULATION_RANGE);
G3D::Vector3 dest = owner->movespline->FinalDestination();
G3D::Vector3 destination = owner->movespline->FinalDestination();
if (owner->movespline->onTransport)
if (TransportBase* transport = owner->GetDirectTransport())
transport->CalculatePassengerPosition(dest.x, dest.y, dest.z);
transport->CalculatePassengerPosition(destination.x, destination.y, destination.z);
// First check distance
if (owner->GetTypeId() == TYPEID_UNIT && (owner->ToCreature()->CanFly() || owner->ToCreature()->CanSwim()))
targetMoved = !i_target->IsWithinDist3d(dest.x, dest.y, dest.z, allowed_dist);
if (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->CanFly())
targetMoved = !GetTarget()->IsWithinDist3d(destination.x, destination.y, destination.z, distance);
else
targetMoved = !i_target->IsWithinDist2d(dest.x, dest.y, allowed_dist);
targetMoved = !GetTarget()->IsWithinDist2d(destination.x, destination.y, distance);
// then, if the target is in range, check also Line of Sight.
if (!targetMoved)
targetMoved = !i_target->IsWithinLOSInMap(owner);
targetMoved = !GetTarget()->IsWithinLOSInMap(owner);
}
if (i_recalculateTravel || targetMoved)
_setTargetLocation(owner, targetMoved);
if (targetMoved)
SetTargetLocation(owner, targetMoved);
if (owner->movespline->Finalized())
if (!_targetReached && owner->movespline->Finalized())
{
static_cast<D*>(this)->MovementInform(owner);
if (i_angle == 0.f && !owner->HasInArc(0.01f, i_target.getTarget()))
owner->SetInFront(i_target.getTarget());
MovementInform(owner);
if (_angle == 0.f && !owner->HasInArc(0.01f, GetTarget()))
owner->SetInFront(GetTarget());
if (!i_targetReached)
if (!_targetReached)
{
i_targetReached = true;
static_cast<D*>(this)->_reachTarget(owner);
_targetReached = true;
ReachTarget(owner);
}
}
return true;
}
//-----------------------------------------------//
template<class T>
void ChaseMovementGenerator<T>::_reachTarget(T* owner)
template<class T, typename D>
void TargetedMovementGenerator<T, D>::SetTargetLocation(T* owner, bool updateDestination)
{
_clearUnitStateMove(owner);
if (owner->IsWithinMeleeRange(this->i_target.getTarget()))
owner->Attack(this->i_target.getTarget(), true);
if (!IsTargetValid() || !GetTarget()->IsInWorld())
return;
if (!owner || !owner->IsAlive())
return;
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting() || HasLostTarget(owner)
|| (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->IsFocusing(nullptr, true)))
{
_interrupt = true;
owner->StopMoving();
return;
}
if (owner->GetTypeId() == TYPEID_UNIT && !GetTarget()->isInAccessiblePlaceFor(owner->ToCreature()))
{
owner->ToCreature()->SetCannotReachTarget(true);
return;
}
float x, y, z;
if (updateDestination || !_path)
{
if (!_offset)
{
if (GetTarget()->IsWithinDistInMap(owner, CONTACT_DISTANCE))
return;
GetTarget()->GetContactPoint(owner, x, y, z);
}
else
{
float distance = _offset + 1.0f;
float size = owner->GetCombatReach();
if (owner->IsPet() && GetTarget()->GetTypeId() == TYPEID_PLAYER)
{
distance = 1.0f;
size = 1.0f;
}
if (GetTarget()->IsWithinDistInMap(owner, distance))
return;
GetTarget()->GetClosePoint(x, y, z, size, _offset, _angle);
}
}
else
{
// the destination has not changed, we just need to refresh the path (usually speed change)
G3D::Vector3 end = _path->GetEndPosition();
x = end.x;
y = end.y;
z = end.z;
}
if (!_path)
_path = new PathGenerator(owner);
// allow pets to use shortcut if no path found when following their master
bool forceDest = (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->IsPet() && owner->HasUnitState(UNIT_STATE_FOLLOW));
bool result = _path->CalculatePath(x, y, z, forceDest);
if (!result || (_path->GetPathType() & PATHFIND_NOPATH))
{
// can't reach target
_recalculateTravel = true;
if (owner->GetTypeId() == TYPEID_UNIT)
owner->ToCreature()->SetCannotReachTarget(true);
return;
}
_targetReached = false;
_recalculateTravel = false;
AddUnitStateMove(owner);
if (owner->GetTypeId() == TYPEID_UNIT)
owner->ToCreature()->SetCannotReachTarget(false);
Movement::MoveSplineInit init(owner);
init.MovebyPath(_path->GetPath());
init.SetWalk(EnableWalking());
// Using the same condition for facing target as the one that is used for SetInFront on movement end
// - applies to ChaseMovementGenerator mostly
if (_angle == 0.f)
init.SetFacing(GetTarget());
init.Launch();
}
template<class T, typename D>
bool TargetedMovementGenerator<T, D>::IsReachable() const
{
return (_path) ? (_path->GetPathType() & PATHFIND_NORMAL) : true;
}
//---- ChaseMovementGenerator
template<class T>
void ChaseMovementGenerator<T>::DoInitialize(T*) { }
template<>
void ChaseMovementGenerator<Player>::DoInitialize(Player* owner)
{
owner->AddUnitState(UNIT_STATE_CHASE | UNIT_STATE_CHASE_MOVE);
_setTargetLocation(owner, true);
owner->AddUnitState(UNIT_STATE_CHASE);
SetTargetLocation(owner, true);
}
template<>
void ChaseMovementGenerator<Creature>::DoInitialize(Creature* owner)
{
owner->SetWalk(false);
owner->AddUnitState(UNIT_STATE_CHASE | UNIT_STATE_CHASE_MOVE);
_setTargetLocation(owner, true);
owner->AddUnitState(UNIT_STATE_CHASE);
SetTargetLocation(owner, true);
}
template<class T>
@@ -250,41 +233,60 @@ void ChaseMovementGenerator<T>::DoReset(T* owner)
}
template<class T>
void ChaseMovementGenerator<T>::MovementInform(T* /*unit*/) { }
void ChaseMovementGenerator<T>::ClearUnitStateMove(T* owner)
{
owner->ClearUnitState(UNIT_STATE_CHASE_MOVE);
}
template<class T>
void ChaseMovementGenerator<T>::AddUnitStateMove(T* owner)
{
owner->AddUnitState(UNIT_STATE_CHASE_MOVE);
}
template<class T>
bool ChaseMovementGenerator<T>::HasLostTarget(T* owner) const
{
return owner->GetVictim() != TargetedMovementGeneratorBase::GetTarget();
}
template<class T>
void ChaseMovementGenerator<T>::ReachTarget(T* owner)
{
ClearUnitStateMove(owner);
if (owner->IsWithinMeleeRange(TargetedMovementGeneratorBase::GetTarget()))
owner->Attack(TargetedMovementGeneratorBase::GetTarget(), true);
if (owner->GetTypeId() == TYPEID_UNIT)
owner->ToCreature()->SetCannotReachTarget(false);
}
template<class T>
void ChaseMovementGenerator<T>::MovementInform(T*) { }
template<>
void ChaseMovementGenerator<Creature>::MovementInform(Creature* unit)
void ChaseMovementGenerator<Creature>::MovementInform(Creature* owner)
{
// Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle
if (unit->AI())
unit->AI()->MovementInform(CHASE_MOTION_TYPE, i_target.getTarget()->GetGUID().GetCounter());
if (owner->AI())
owner->AI()->MovementInform(CHASE_MOTION_TYPE, GetTarget()->GetGUID().GetCounter());
}
//-----------------------------------------------//
template<>
bool FollowMovementGenerator<Creature>::EnableWalking() const
{
return i_target.isValid() && i_target->IsWalking();
}
//---- FollowMovementGenerator
template<class T>
void FollowMovementGenerator<T>::UpdateSpeed(T*) { }
template<>
bool FollowMovementGenerator<Player>::EnableWalking() const
{
return false;
}
void FollowMovementGenerator<Player>::UpdateSpeed(Player* /*owner*/) { }
template<>
void FollowMovementGenerator<Player>::_updateSpeed(Player* /*owner*/)
void FollowMovementGenerator<Creature>::UpdateSpeed(Creature* owner)
{
// nothing to do for Player
}
template<>
void FollowMovementGenerator<Creature>::_updateSpeed(Creature* owner)
{
// pet only sync speed with owner
/// Make sure we are not in the process of a map change (IsInWorld)
if (!owner->IsPet() || !owner->IsInWorld() || !i_target.isValid() || i_target->GetGUID() != owner->GetOwnerGUID())
// Pet only sync speed with owner
// Make sure we are not in the process of a map change (IsInWorld)
if (!owner->IsPet() || !owner->IsInWorld() || !IsTargetValid() || GetTarget()->GetGUID() != owner->GetOwnerGUID())
return;
owner->UpdateSpeed(MOVE_RUN);
@@ -292,27 +294,19 @@ void FollowMovementGenerator<Creature>::_updateSpeed(Creature* owner)
owner->UpdateSpeed(MOVE_SWIM);
}
template<>
void FollowMovementGenerator<Player>::DoInitialize(Player* owner)
template<class T>
void FollowMovementGenerator<T>::DoInitialize(T* owner)
{
owner->AddUnitState(UNIT_STATE_FOLLOW | UNIT_STATE_FOLLOW_MOVE);
_updateSpeed(owner);
_setTargetLocation(owner, true);
}
template<>
void FollowMovementGenerator<Creature>::DoInitialize(Creature* owner)
{
owner->AddUnitState(UNIT_STATE_FOLLOW | UNIT_STATE_FOLLOW_MOVE);
_updateSpeed(owner);
_setTargetLocation(owner, true);
owner->AddUnitState(UNIT_STATE_FOLLOW);
UpdateSpeed(owner);
TargetedMovementGenerator<T, FollowMovementGenerator<T>>::SetTargetLocation(owner, true);
}
template<class T>
void FollowMovementGenerator<T>::DoFinalize(T* owner)
{
owner->ClearUnitState(UNIT_STATE_FOLLOW | UNIT_STATE_FOLLOW_MOVE);
_updateSpeed(owner);
UpdateSpeed(owner);
}
template<class T>
@@ -322,36 +316,85 @@ void FollowMovementGenerator<T>::DoReset(T* owner)
}
template<class T>
void FollowMovementGenerator<T>::MovementInform(T* /*unit*/) { }
void FollowMovementGenerator<T>::ClearUnitStateMove(T* owner)
{
owner->ClearUnitState(UNIT_STATE_FOLLOW_MOVE);
}
template<class T>
void FollowMovementGenerator<T>::AddUnitStateMove(T* owner)
{
owner->AddUnitState(UNIT_STATE_FOLLOW_MOVE);
}
template<class T>
void FollowMovementGenerator<T>::ReachTarget(T* owner)
{
ClearUnitStateMove(owner);
}
template<>
bool FollowMovementGenerator<Creature>::EnableWalking() const
{
return IsTargetValid() && GetTarget()->IsWalking();
}
template<>
bool FollowMovementGenerator<Player>::EnableWalking() const
{
return false;
}
template<class T>
void FollowMovementGenerator<T>::MovementInform(T*) { }
template<>
void FollowMovementGenerator<Creature>::MovementInform(Creature* unit)
{
// Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle
if (unit->AI())
unit->AI()->MovementInform(FOLLOW_MOTION_TYPE, i_target.getTarget()->GetGUID().GetCounter());
unit->AI()->MovementInform(FOLLOW_MOTION_TYPE, GetTarget()->GetGUID().GetCounter());
}
//-----------------------------------------------//
template void TargetedMovementGeneratorMedium<Player, ChaseMovementGenerator<Player> >::_setTargetLocation(Player*, bool);
template void TargetedMovementGeneratorMedium<Player, FollowMovementGenerator<Player> >::_setTargetLocation(Player*, bool);
template void TargetedMovementGeneratorMedium<Creature, ChaseMovementGenerator<Creature> >::_setTargetLocation(Creature*, bool);
template void TargetedMovementGeneratorMedium<Creature, FollowMovementGenerator<Creature> >::_setTargetLocation(Creature*, bool);
template bool TargetedMovementGeneratorMedium<Player, ChaseMovementGenerator<Player> >::DoUpdate(Player*, uint32);
template bool TargetedMovementGeneratorMedium<Player, FollowMovementGenerator<Player> >::DoUpdate(Player*, uint32);
template bool TargetedMovementGeneratorMedium<Creature, ChaseMovementGenerator<Creature> >::DoUpdate(Creature*, uint32);
template bool TargetedMovementGeneratorMedium<Creature, FollowMovementGenerator<Creature> >::DoUpdate(Creature*, uint32);
template void ChaseMovementGenerator<Player>::_reachTarget(Player*);
template void ChaseMovementGenerator<Creature>::_reachTarget(Creature*);
template TargetedMovementGenerator<Player, ChaseMovementGenerator<Player> >::~TargetedMovementGenerator();
template TargetedMovementGenerator<Player, FollowMovementGenerator<Player> >::~TargetedMovementGenerator();
template TargetedMovementGenerator<Creature, ChaseMovementGenerator<Creature> >::~TargetedMovementGenerator();
template TargetedMovementGenerator<Creature, FollowMovementGenerator<Creature> >::~TargetedMovementGenerator();
template bool TargetedMovementGenerator<Player, ChaseMovementGenerator<Player> >::DoUpdate(Player*, uint32);
template bool TargetedMovementGenerator<Player, FollowMovementGenerator<Player> >::DoUpdate(Player*, uint32);
template bool TargetedMovementGenerator<Creature, ChaseMovementGenerator<Creature> >::DoUpdate(Creature*, uint32);
template bool TargetedMovementGenerator<Creature, FollowMovementGenerator<Creature> >::DoUpdate(Creature*, uint32);
template void TargetedMovementGenerator<Player, ChaseMovementGenerator<Player> >::SetTargetLocation(Player*, bool);
template void TargetedMovementGenerator<Player, FollowMovementGenerator<Player> >::SetTargetLocation(Player*, bool);
template void TargetedMovementGenerator<Creature, ChaseMovementGenerator<Creature> >::SetTargetLocation(Creature*, bool);
template void TargetedMovementGenerator<Creature, FollowMovementGenerator<Creature> >::SetTargetLocation(Creature*, bool);
template void ChaseMovementGenerator<Player>::DoFinalize(Player*);
template void ChaseMovementGenerator<Creature>::DoFinalize(Creature*);
template void ChaseMovementGenerator<Player>::DoReset(Player*);
template void ChaseMovementGenerator<Creature>::DoReset(Creature*);
template void ChaseMovementGenerator<Player>::ClearUnitStateMove(Player*);
template void ChaseMovementGenerator<Creature>::ClearUnitStateMove(Creature*);
template void ChaseMovementGenerator<Player>::AddUnitStateMove(Player*);
template void ChaseMovementGenerator<Creature>::AddUnitStateMove(Creature*);
template bool ChaseMovementGenerator<Player>::HasLostTarget(Player*) const;
template bool ChaseMovementGenerator<Creature>::HasLostTarget(Creature*) const;
template void ChaseMovementGenerator<Player>::ReachTarget(Player*);
template void ChaseMovementGenerator<Creature>::ReachTarget(Creature*);
template void ChaseMovementGenerator<Player>::MovementInform(Player*);
template void FollowMovementGenerator<Player>::DoInitialize(Player*);
template void FollowMovementGenerator<Creature>::DoInitialize(Creature*);
template void FollowMovementGenerator<Player>::DoFinalize(Player*);
template void FollowMovementGenerator<Creature>::DoFinalize(Creature*);
template void FollowMovementGenerator<Player>::DoReset(Player*);
template void FollowMovementGenerator<Creature>::DoReset(Creature*);
template void FollowMovementGenerator<Player>::ClearUnitStateMove(Player*);
template void FollowMovementGenerator<Creature>::ClearUnitStateMove(Creature*);
template void FollowMovementGenerator<Player>::AddUnitStateMove(Player*);
template void FollowMovementGenerator<Creature>::AddUnitStateMove(Creature*);
template void FollowMovementGenerator<Player>::ReachTarget(Player*);
template void FollowMovementGenerator<Creature>::ReachTarget(Creature*);
template void FollowMovementGenerator<Player>::MovementInform(Player*);

View File

@@ -21,95 +21,93 @@
#include "MovementGenerator.h"
#include "FollowerReference.h"
#include "Timer.h"
#include "Unit.h"
#include "PathGenerator.h"
class TargetedMovementGeneratorBase
{
public:
TargetedMovementGeneratorBase(Unit* target) { i_target.link(target, this); }
TargetedMovementGeneratorBase(Unit* target)
{
_target.link(target, this);
}
bool IsTargetValid() const { return _target.isValid(); }
Unit* GetTarget() const { return _target.getTarget(); }
void stopFollowing() { }
protected:
FollowerReference i_target;
private:
FollowerReference _target;
};
template<class T, typename D>
class TargetedMovementGeneratorMedium : public MovementGeneratorMedium< T, D >, public TargetedMovementGeneratorBase
class TargetedMovementGenerator : public MovementGeneratorMedium< T, D >, public TargetedMovementGeneratorBase
{
protected:
TargetedMovementGeneratorMedium(Unit* target, float offset, float angle) :
TargetedMovementGeneratorBase(target), i_path(NULL),
i_recheckDistance(0), i_offset(offset), i_angle(angle),
i_recalculateTravel(false), i_targetReached(false)
{
}
~TargetedMovementGeneratorMedium() { delete i_path; }
public:
explicit TargetedMovementGenerator(Unit* target, float offset, float angle) : TargetedMovementGeneratorBase(target), _path(nullptr), _timer(0), _offset(offset), _angle(angle), _recalculateTravel(false), _targetReached(false), _interrupt(false) { }
~TargetedMovementGenerator();
bool DoUpdate(T*, uint32);
Unit* GetTarget() const { return i_target.getTarget(); }
void unitSpeedChanged() override { i_recalculateTravel = true; }
bool IsReachable() const { return (i_path) ? (i_path->GetPathType() & PATHFIND_NORMAL) : true; }
protected:
void _setTargetLocation(T* owner, bool updateDestination);
void UnitSpeedChanged() override { _recalculateTravel = true; }
PathGenerator* i_path;
TimeTrackerSmall i_recheckDistance;
float i_offset;
float i_angle;
bool i_recalculateTravel : 1;
bool i_targetReached : 1;
virtual void ClearUnitStateMove(T*) { }
virtual void AddUnitStateMove(T*) { }
virtual bool HasLostTarget(T*) const { return false; }
virtual void ReachTarget(T*) { }
virtual bool EnableWalking() const { return false; }
virtual void MovementInform(T*) { }
bool IsReachable() const;
void SetTargetLocation(T* owner, bool updateDestination);
private:
PathGenerator* _path;
TimeTrackerSmall _timer;
float _offset;
float _angle;
bool _recalculateTravel;
bool _targetReached;
bool _interrupt;
};
template<class T>
class ChaseMovementGenerator : public TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >
class ChaseMovementGenerator : public TargetedMovementGenerator<T, ChaseMovementGenerator<T> >
{
public:
ChaseMovementGenerator(Unit* target)
: TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >(target) { }
ChaseMovementGenerator(Unit* target, float offset, float angle)
: TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >(target, offset, angle) { }
~ChaseMovementGenerator() { }
explicit ChaseMovementGenerator(Unit* target, float offset, float angle) : TargetedMovementGenerator<T, ChaseMovementGenerator<T> >(target, offset, angle) { }
MovementGeneratorType GetMovementGeneratorType() const override { return CHASE_MOTION_TYPE; }
void DoInitialize(T*);
void DoFinalize(T*);
void DoReset(T*);
void MovementInform(T*);
static void _clearUnitStateMove(T* u) { u->ClearUnitState(UNIT_STATE_CHASE_MOVE); }
static void _addUnitStateMove(T* u) { u->AddUnitState(UNIT_STATE_CHASE_MOVE); }
bool EnableWalking() const { return false;}
bool _lostTarget(T* u) const { return u->GetVictim() != this->GetTarget(); }
void _reachTarget(T*);
void ClearUnitStateMove(T*) override;
void AddUnitStateMove(T*) override;
bool HasLostTarget(T*) const override;
void ReachTarget(T*) override;
void MovementInform(T*) override;
};
template<class T>
class FollowMovementGenerator : public TargetedMovementGeneratorMedium<T, FollowMovementGenerator<T> >
class FollowMovementGenerator : public TargetedMovementGenerator<T, FollowMovementGenerator<T> >
{
public:
FollowMovementGenerator(Unit* target)
: TargetedMovementGeneratorMedium<T, FollowMovementGenerator<T> >(target){ }
FollowMovementGenerator(Unit* target, float offset, float angle)
: TargetedMovementGeneratorMedium<T, FollowMovementGenerator<T> >(target, offset, angle) { }
~FollowMovementGenerator() { }
explicit FollowMovementGenerator(Unit* target, float offset, float angle) : TargetedMovementGenerator<T, FollowMovementGenerator<T> >(target, offset, angle) { }
MovementGeneratorType GetMovementGeneratorType() const override { return FOLLOW_MOTION_TYPE; }
void DoInitialize(T*);
void DoFinalize(T*);
void DoReset(T*);
void MovementInform(T*);
static void _clearUnitStateMove(T* u) { u->ClearUnitState(UNIT_STATE_FOLLOW_MOVE); }
static void _addUnitStateMove(T* u) { u->AddUnitState(UNIT_STATE_FOLLOW_MOVE); }
bool EnableWalking() const;
bool _lostTarget(T*) const { return false; }
void _reachTarget(T*) { }
void ClearUnitStateMove(T*) override;
void AddUnitStateMove(T*) override;
bool HasLostTarget(T*) const override { return false; }
void ReachTarget(T*) override;
bool EnableWalking() const override;
void MovementInform(T*) override;
private:
void _updateSpeed(T* owner);
void UpdateSpeed(T* owner);
};
#endif