diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
index 00eac7db712..5affa7a4e23 100644
--- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
@@ -16,166 +16,134 @@
* with this program. If not, see .
*/
-#include "RandomMovementGenerator.h"
#include "Creature.h"
#include "CreatureGroups.h"
#include "Map.h"
-#include "MoveSpline.h"
#include "MoveSplineInit.h"
+#include "MoveSpline.h"
+#include "PathGenerator.h"
+#include "RandomMovementGenerator.h"
#include "Random.h"
-#include "Util.h"
-#define RUNNING_CHANCE_RANDOMMV 20 //will be "1 / RUNNING_CHANCE_RANDOMMV"
+template
+RandomMovementGenerator::~RandomMovementGenerator() { }
template<>
-void RandomMovementGenerator::_setRandomLocation(Creature* creature)
+RandomMovementGenerator::~RandomMovementGenerator()
{
- if (creature->IsMovementPreventedByCasting())
+ delete _path;
+}
+
+template
+void RandomMovementGenerator::DoInitialize(T*) { }
+
+template<>
+void RandomMovementGenerator::DoInitialize(Creature* owner)
+{
+ if (!owner || !owner->IsAlive())
+ return;
+
+ owner->AddUnitState(UNIT_STATE_ROAMING);
+ owner->GetPosition(_reference.x, _reference.y, _reference.z);
+ owner->StopMoving();
+
+ if (!_wanderDistance)
+ _wanderDistance = owner->GetRespawnRadius();
+
+ _timer.Reset(0);
+}
+
+template
+void RandomMovementGenerator::DoFinalize(T*) { }
+
+template<>
+void RandomMovementGenerator::DoFinalize(Creature* owner)
+{
+ owner->ClearUnitState(UNIT_STATE_ROAMING);
+ owner->StopMoving();
+ owner->SetWalk(false);
+}
+
+template
+void RandomMovementGenerator::DoReset(T*) { }
+
+template<>
+void RandomMovementGenerator::DoReset(Creature* owner)
+{
+ DoInitialize(owner);
+}
+
+template
+void RandomMovementGenerator::SetRandomLocation(T*) { }
+
+template<>
+void RandomMovementGenerator::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.x, _reference.y, _reference.z);
+ 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(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
+bool RandomMovementGenerator::DoUpdate(T*, uint32)
+{
+ return false;
}
template<>
-void RandomMovementGenerator::DoInitialize(Creature* creature)
+bool RandomMovementGenerator::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::DoReset(Creature* creature)
-{
- DoInitialize(creature);
-}
-
-template<>
-void RandomMovementGenerator::DoFinalize(Creature* creature)
-{
- creature->ClearUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
- creature->SetWalk(false);
-}
-
-template<>
-bool RandomMovementGenerator::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::GetResetPos(Creature* creature, float& x, float& y, float& z)
-{
- float radius;
- creature->GetRespawnPosition(x, y, z, nullptr, &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;
}
diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h
index 99edbaa2efd..88485dcaed3 100644
--- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h
@@ -26,18 +26,24 @@ template
class RandomMovementGenerator : public MovementGeneratorMedium< T, RandomMovementGenerator >
{
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*, uint32);
- bool GetResetPos(T*, float& x, float& y, float& z);
- MovementGeneratorType GetMovementGeneratorType() const override { return RANDOM_MOTION_TYPE; }
- private:
- TimeTrackerSmall i_nextMoveTime;
- float wander_distance;
+ private:
+ void SetRandomLocation(T*);
+
+ PathGenerator* _path;
+ TimeTracker _timer;
+ G3D::Vector3 _reference;
+ float _wanderDistance;
+ bool _interrupt;
};
+
#endif