Core/Movement: ported missing random movement changes from movement generator cleanup

This commit is contained in:
Ovahlord
2018-08-02 13:29:22 +02:00
parent 64796f1121
commit 62efe280b7
2 changed files with 109 additions and 135 deletions

View File

@@ -16,166 +16,134 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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<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.x, _reference.y, _reference.z);
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.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<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, 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;
}

View File

@@ -26,18 +26,24 @@ 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*, 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