Core/Movement: Implement spline movement subsystem.
Spline movement controls movements of server-side controlled units (monster movement, taxi movement, etc). Proper implementation of effects such as charge, jump, cyclic movement will rely on it. However, need improve our states system before. Technical changes: * Added linear, catmullrom and bezier3 splines which based on client's algorthims. They can be reused for proper transport position interpolation. * Precission increased. There are no more position desync issues since client's position calculation formulas used. * Now possible to move by paths with multiple points, send whole path to client. -- Original author of research and implementation: SilverIce. Massive kudos. Original port for Trinity (ref #4629) Chaplain and Venugh With the following incremental fixes during my review: - Restore flightmaster end grid pre-loading - Fix uninitialized Creature::m_path_id - Add missing trinity_string entries for .movegens command - Fix a bug in WaypointMovementGenerator that would trigger unexpected pausing at waypoints for various amounts of time Known issues: - Errors like WaypointMovementGenerator::LoadPath creature XXX (Entry: YYYYY GUID: ZZZZZZ) doesn't have waypoint path id: 0. This is caused by bad DB data. This commit didn't "break" it. Do not forget to re-run CMake before compiling.
This commit is contained in:
@@ -18,10 +18,10 @@
|
||||
|
||||
#include "Creature.h"
|
||||
#include "MapManager.h"
|
||||
#include "Opcodes.h"
|
||||
#include "ConfusedMovementGenerator.h"
|
||||
#include "DestinationHolderImp.h"
|
||||
#include "VMapFactory.h"
|
||||
#include "MoveSplineInit.h"
|
||||
#include "MoveSpline.h"
|
||||
|
||||
#ifdef MAP_BASED_RAND_GEN
|
||||
#define rand_norm() unit.rand_norm()
|
||||
@@ -31,8 +31,8 @@
|
||||
template<class T>
|
||||
void ConfusedMovementGenerator<T>::Initialize(T &unit)
|
||||
{
|
||||
float const wanderDistance = 4;
|
||||
float x, y, z;
|
||||
const float wander_distance=4;
|
||||
float x,y,z;
|
||||
x = unit.GetPositionX();
|
||||
y = unit.GetPositionY();
|
||||
z = unit.GetPositionZ();
|
||||
@@ -44,52 +44,33 @@ void ConfusedMovementGenerator<T>::Initialize(T &unit)
|
||||
bool is_water_ok, is_land_ok;
|
||||
_InitSpecific(unit, is_water_ok, is_land_ok);
|
||||
|
||||
for (uint8 idx = 0; idx <= MAX_CONF_WAYPOINTS; ++idx)
|
||||
for (uint8 idx = 0; idx < MAX_CONF_WAYPOINTS + 1; ++idx)
|
||||
{
|
||||
float wanderX = x + wanderDistance * (float)rand_norm() - wanderDistance/2;
|
||||
float wanderY = y + wanderDistance * (float)rand_norm() - wanderDistance/2;
|
||||
Trinity::NormalizeMapCoord(wanderX);
|
||||
Trinity::NormalizeMapCoord(wanderY);
|
||||
const float wanderX=wander_distance*(float)rand_norm() - wander_distance/2;
|
||||
const float wanderY=wander_distance*(float)rand_norm() - wander_distance/2;
|
||||
|
||||
float new_z = map->GetHeight(wanderX, wanderY, z, true);
|
||||
if (new_z > INVALID_HEIGHT && unit.IsWithinLOS(wanderX, wanderY, new_z))
|
||||
{
|
||||
// Don't move in water if we're not already in
|
||||
// Don't move on land if we're not already on it either
|
||||
bool is_water_now = map->IsInWater(x, y, z);
|
||||
bool is_water_next = map->IsInWater(wanderX, wanderY, new_z);
|
||||
if ((is_water_now && !is_water_next && !is_land_ok) || (!is_water_now && is_water_next && !is_water_ok))
|
||||
{
|
||||
i_waypoints[idx][0] = idx > 0 ? i_waypoints[idx-1][0] : x; // Back to previous location
|
||||
i_waypoints[idx][1] = idx > 0 ? i_waypoints[idx-1][1] : y;
|
||||
i_waypoints[idx][2] = idx > 0 ? i_waypoints[idx-1][2] : z;
|
||||
continue;
|
||||
}
|
||||
i_waypoints[idx][0] = x + wanderX;
|
||||
i_waypoints[idx][1] = y + wanderY;
|
||||
|
||||
// Taken from FleeingMovementGenerator
|
||||
if (!(new_z - z) || wanderDistance / fabs(new_z - z) > 1.0f)
|
||||
{
|
||||
i_waypoints[idx][0] = wanderX;
|
||||
i_waypoints[idx][1] = wanderY;
|
||||
i_waypoints[idx][2] = new_z;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else // Back to previous location
|
||||
// prevent invalid coordinates generation
|
||||
Trinity::NormalizeMapCoord(i_waypoints[idx][0]);
|
||||
Trinity::NormalizeMapCoord(i_waypoints[idx][1]);
|
||||
|
||||
bool is_water = map->IsInWater(i_waypoints[idx][0],i_waypoints[idx][1],z);
|
||||
// if generated wrong path just ignore
|
||||
if ((is_water && !is_water_ok) || (!is_water && !is_land_ok))
|
||||
{
|
||||
i_waypoints[idx][0] = idx > 0 ? i_waypoints[idx-1][0] : x;
|
||||
i_waypoints[idx][1] = idx > 0 ? i_waypoints[idx-1][1] : y;
|
||||
i_waypoints[idx][2] = idx > 0 ? i_waypoints[idx-1][2] : z;
|
||||
continue;
|
||||
}
|
||||
|
||||
unit.UpdateAllowedPositionZ(i_waypoints[idx][0], i_waypoints[idx][1], z);
|
||||
i_waypoints[idx][2] = z;
|
||||
}
|
||||
|
||||
unit.SetTarget(0);
|
||||
unit.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
|
||||
unit.CastStop();
|
||||
unit.StopMoving();
|
||||
unit.AddUnitMovementFlag(MOVEMENTFLAG_WALKING); // Should actually be splineflag
|
||||
unit.AddUnitState(UNIT_STAT_CONFUSED);
|
||||
unit.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
|
||||
unit.AddUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE);
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -111,69 +92,70 @@ void ConfusedMovementGenerator<T>::Reset(T &unit)
|
||||
{
|
||||
i_nextMove = 1;
|
||||
i_nextMoveTime.Reset(0);
|
||||
i_destinationHolder.ResetUpdate();
|
||||
unit.StopMoving();
|
||||
unit.AddUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool ConfusedMovementGenerator<T>::Update(T &unit, const uint32 diff)
|
||||
bool ConfusedMovementGenerator<T>::Update(T &unit, const uint32 &diff)
|
||||
{
|
||||
if (!&unit)
|
||||
return true;
|
||||
|
||||
if (unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
|
||||
return true;
|
||||
|
||||
if (i_nextMoveTime.Passed())
|
||||
{
|
||||
// currently moving, update location
|
||||
Traveller<T> traveller(unit);
|
||||
if (i_destinationHolder.UpdateTraveller(traveller, diff))
|
||||
{
|
||||
if (i_destinationHolder.HasArrived())
|
||||
{
|
||||
// arrived, stop and wait a bit
|
||||
unit.ClearUnitState(UNIT_STAT_MOVE);
|
||||
unit.AddUnitState(UNIT_STAT_CONFUSED_MOVE);
|
||||
|
||||
i_nextMove = urand(1, MAX_CONF_WAYPOINTS);
|
||||
i_nextMoveTime.Reset(urand(100, 1000));
|
||||
}
|
||||
if (unit.movespline->Finalized())
|
||||
{
|
||||
i_nextMove = urand(1,MAX_CONF_WAYPOINTS);
|
||||
i_nextMoveTime.Reset(urand(0, 1500-1)); // TODO: check the minimum reset time, should be probably higher
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// waiting for next move
|
||||
i_nextMoveTime.Update(diff);
|
||||
if (i_nextMoveTime.Passed())
|
||||
if(i_nextMoveTime.Passed() )
|
||||
{
|
||||
// start moving
|
||||
ASSERT(i_nextMove <= MAX_CONF_WAYPOINTS);
|
||||
const float x = i_waypoints[i_nextMove][0];
|
||||
const float y = i_waypoints[i_nextMove][1];
|
||||
const float z = i_waypoints[i_nextMove][2];
|
||||
Traveller<T> traveller(unit);
|
||||
i_destinationHolder.SetDestination(traveller, x, y, z);
|
||||
unit.AddUnitState(UNIT_STAT_CONFUSED_MOVE);
|
||||
|
||||
ASSERT( i_nextMove <= MAX_CONF_WAYPOINTS );
|
||||
float x = i_waypoints[i_nextMove][0];
|
||||
float y = i_waypoints[i_nextMove][1];
|
||||
float z = i_waypoints[i_nextMove][2];
|
||||
Movement::MoveSplineInit init(unit);
|
||||
init.MoveTo(x, y, z);
|
||||
init.SetWalk(true);
|
||||
init.Launch();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void ConfusedMovementGenerator<T>::Finalize(T &unit)
|
||||
template<>
|
||||
void ConfusedMovementGenerator<Player>::Finalize(Player &unit)
|
||||
{
|
||||
unit.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
|
||||
unit.ClearUnitState(UNIT_STAT_CONFUSED);
|
||||
unit.ClearUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE);
|
||||
}
|
||||
|
||||
if (unit.GetTypeId() == TYPEID_UNIT && unit.getVictim())
|
||||
template<>
|
||||
void ConfusedMovementGenerator<Creature>::Finalize(Creature &unit)
|
||||
{
|
||||
unit.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
|
||||
unit.ClearUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE);
|
||||
if (unit.getVictim())
|
||||
unit.SetTarget(unit.getVictim()->GetGUID());
|
||||
}
|
||||
|
||||
template void ConfusedMovementGenerator<Player>::Initialize(Player &player);
|
||||
template void ConfusedMovementGenerator<Creature>::Initialize(Creature &creature);
|
||||
template void ConfusedMovementGenerator<Player>::Finalize(Player &player);
|
||||
template void ConfusedMovementGenerator<Creature>::Finalize(Creature &creature);
|
||||
template void ConfusedMovementGenerator<Player>::Reset(Player &player);
|
||||
template void ConfusedMovementGenerator<Creature>::Reset(Creature &creature);
|
||||
template bool ConfusedMovementGenerator<Player>::Update(Player &player, const uint32 diff);
|
||||
template bool ConfusedMovementGenerator<Creature>::Update(Creature &creature, const uint32 diff);
|
||||
template bool ConfusedMovementGenerator<Player>::Update(Player &player, const uint32 &diff);
|
||||
template bool ConfusedMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff);
|
||||
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
#define TRINITY_CONFUSEDGENERATOR_H
|
||||
|
||||
#include "MovementGenerator.h"
|
||||
#include "DestinationHolder.h"
|
||||
#include "Traveller.h"
|
||||
#include "Timer.h"
|
||||
|
||||
#define MAX_CONF_WAYPOINTS 24
|
||||
|
||||
@@ -35,21 +34,13 @@ class ConfusedMovementGenerator
|
||||
void Initialize(T &);
|
||||
void Finalize(T &);
|
||||
void Reset(T &);
|
||||
bool Update(T &, const uint32);
|
||||
|
||||
bool GetDestination(float &x, float &y, float &z) const
|
||||
{
|
||||
if (i_destinationHolder.HasArrived()) return false;
|
||||
i_destinationHolder.GetDestination(x, y, z);
|
||||
return true;
|
||||
}
|
||||
bool Update(T &, const uint32 &);
|
||||
|
||||
MovementGeneratorType GetMovementGeneratorType() { return CONFUSED_MOTION_TYPE; }
|
||||
private:
|
||||
void _InitSpecific(T &, bool &, bool &);
|
||||
TimeTracker i_nextMoveTime;
|
||||
float i_waypoints[MAX_CONF_WAYPOINTS+1][3];
|
||||
DestinationHolder< Traveller<T> > i_destinationHolder;
|
||||
uint32 i_nextMove;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
#include "CreatureAI.h"
|
||||
#include "MapManager.h"
|
||||
#include "FleeingMovementGenerator.h"
|
||||
#include "DestinationHolderImp.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "MoveSplineInit.h"
|
||||
#include "MoveSpline.h"
|
||||
|
||||
#define MIN_QUIET_DISTANCE 28.0f
|
||||
#define MAX_QUIET_DISTANCE 43.0f
|
||||
@@ -43,25 +44,12 @@ FleeingMovementGenerator<T>::_setTargetLocation(T &owner)
|
||||
if (!_getPoint(owner, x, y, z))
|
||||
return;
|
||||
|
||||
owner.AddUnitState(UNIT_STAT_FLEEING | UNIT_STAT_ROAMING);
|
||||
Traveller<T> traveller(owner);
|
||||
i_destinationHolder.SetDestination(traveller, x, y, z);
|
||||
}
|
||||
owner.AddUnitState(UNIT_STAT_FLEEING_MOVE);
|
||||
|
||||
template<>
|
||||
bool FleeingMovementGenerator<Creature>::GetDestination(float &x, float &y, float &z) const
|
||||
{
|
||||
if (i_destinationHolder.HasArrived())
|
||||
return false;
|
||||
|
||||
i_destinationHolder.GetDestination(x, y, z);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool FleeingMovementGenerator<Player>::GetDestination(float & /*x*/, float & /*y*/, float & /*z*/) const
|
||||
{
|
||||
return false;
|
||||
Movement::MoveSplineInit init(owner);
|
||||
init.MoveTo(x,y,z);
|
||||
init.SetWalk(false);
|
||||
init.Launch();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
@@ -75,10 +63,10 @@ FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
|
||||
y = owner.GetPositionY();
|
||||
z = owner.GetPositionZ();
|
||||
|
||||
float temp_x, temp_y, angle = 0;
|
||||
float temp_x, temp_y, angle;
|
||||
const Map* _map = owner.GetBaseMap();
|
||||
//primitive path-finding
|
||||
for (uint8 i = 0; i < 18; ++i)
|
||||
for(uint8 i = 0; i < 18; ++i)
|
||||
{
|
||||
if (i_only_forward && i > 2)
|
||||
break;
|
||||
@@ -143,11 +131,11 @@ FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
|
||||
distance /= 4;
|
||||
break;
|
||||
case 15:
|
||||
angle = i_cur_angle + static_cast<float>(M_PI*3/4);
|
||||
angle = i_cur_angle + static_cast<float>(3*M_PI/4);
|
||||
distance /= 2;
|
||||
break;
|
||||
case 16:
|
||||
angle = i_cur_angle - static_cast<float>(M_PI*3/4);
|
||||
angle = i_cur_angle - static_cast<float>(3*M_PI/4);
|
||||
distance /= 2;
|
||||
break;
|
||||
case 17:
|
||||
@@ -161,9 +149,9 @@ FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
|
||||
Trinity::NormalizeMapCoord(temp_y);
|
||||
if (owner.IsWithinLOS(temp_x, temp_y, z))
|
||||
{
|
||||
bool is_water_now = _map->IsInWater(x, y, z);
|
||||
bool is_water_now = _map->IsInWater(x,y,z);
|
||||
|
||||
if (is_water_now && _map->IsInWater(temp_x, temp_y, z))
|
||||
if (is_water_now && _map->IsInWater(temp_x,temp_y,z))
|
||||
{
|
||||
x = temp_x;
|
||||
y = temp_y;
|
||||
@@ -181,8 +169,8 @@ FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
|
||||
|
||||
if (!(new_z - z) || distance / fabs(new_z - z) > 1.0f)
|
||||
{
|
||||
float new_z_left = _map->GetHeight(temp_x + (float)(cos(angle+M_PI/2)), temp_y + (float)(sin(angle+M_PI/2)), z, true);
|
||||
float new_z_right = _map->GetHeight(temp_x + (float)(cos(angle-M_PI/2)), temp_y + (float)(sin(angle-M_PI/2)), z, true);
|
||||
float new_z_left = _map->GetHeight(temp_x + 1.0f*cos(angle+static_cast<float>(M_PI/2)),temp_y + 1.0f*sin(angle+static_cast<float>(M_PI/2)),z,true);
|
||||
float new_z_right = _map->GetHeight(temp_x + 1.0f*cos(angle-static_cast<float>(M_PI/2)),temp_y + 1.0f*sin(angle-static_cast<float>(M_PI/2)),z,true);
|
||||
if (fabs(new_z_left - new_z) < 1.2f && fabs(new_z_right - new_z) < 1.2f)
|
||||
{
|
||||
x = temp_x;
|
||||
@@ -194,7 +182,7 @@ FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
|
||||
}
|
||||
}
|
||||
i_to_distance_from_caster = 0.0f;
|
||||
i_nextCheckTime.Reset(urand(500, 1000));
|
||||
i_nextCheckTime.Reset( urand(500,1000) );
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -213,12 +201,12 @@ FleeingMovementGenerator<T>::_setMoveData(T &owner)
|
||||
(i_last_distance_from_caster < i_to_distance_from_caster && cur_dist_xyz > i_to_distance_from_caster) ||
|
||||
// if we reach bigger distance
|
||||
(cur_dist_xyz > MAX_QUIET_DISTANCE) || // if we are too far
|
||||
(i_last_distance_from_caster > MIN_QUIET_DISTANCE && cur_dist_xyz < MIN_QUIET_DISTANCE))
|
||||
(i_last_distance_from_caster > MIN_QUIET_DISTANCE && cur_dist_xyz < MIN_QUIET_DISTANCE) )
|
||||
// if we leave 'quiet zone'
|
||||
{
|
||||
// we are very far or too close, stopping
|
||||
i_to_distance_from_caster = 0.0f;
|
||||
i_nextCheckTime.Reset(urand(500, 1000));
|
||||
i_nextCheckTime.Reset( urand(500,1000) );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@@ -232,9 +220,7 @@ FleeingMovementGenerator<T>::_setMoveData(T &owner)
|
||||
float cur_dist;
|
||||
float angle_to_caster;
|
||||
|
||||
Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGUID);
|
||||
|
||||
if (fright)
|
||||
if (Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGUID))
|
||||
{
|
||||
cur_dist = fright->GetDistance(&owner);
|
||||
if (cur_dist < cur_dist_xyz)
|
||||
@@ -284,7 +270,7 @@ FleeingMovementGenerator<T>::_setMoveData(T &owner)
|
||||
i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + (float)rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
|
||||
}
|
||||
|
||||
int8 sign = rand_norm() > 0.5f ? 1 : -1;
|
||||
int8 sign = (float)rand_norm() > 0.5f ? 1 : -1;
|
||||
i_cur_angle = sign*angle + angle_to_caster;
|
||||
|
||||
// current distance
|
||||
@@ -300,14 +286,12 @@ FleeingMovementGenerator<T>::Initialize(T &owner)
|
||||
if (!&owner)
|
||||
return;
|
||||
|
||||
_Init(owner);
|
||||
owner.CastStop();
|
||||
owner.AddUnitState(UNIT_STAT_FLEEING | UNIT_STAT_ROAMING);
|
||||
owner.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
|
||||
owner.SetTarget(0);
|
||||
owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||
owner.AddUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE);
|
||||
|
||||
if (Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGUID))
|
||||
_Init(owner);
|
||||
|
||||
if (Unit *fright = ObjectAccessor::GetUnit(owner, i_frightGUID))
|
||||
{
|
||||
i_caster_x = fright->GetPositionX();
|
||||
i_caster_y = fright->GetPositionY();
|
||||
@@ -334,6 +318,7 @@ FleeingMovementGenerator<Creature>::_Init(Creature &owner)
|
||||
if (!&owner)
|
||||
return;
|
||||
|
||||
//owner.SetTargetGuid(ObjectGuid());
|
||||
is_water_ok = owner.canSwim();
|
||||
is_land_ok = owner.canWalk();
|
||||
}
|
||||
@@ -346,51 +331,44 @@ FleeingMovementGenerator<Player>::_Init(Player &)
|
||||
is_land_ok = true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
FleeingMovementGenerator<T>::Finalize(T &owner)
|
||||
template<>
|
||||
void FleeingMovementGenerator<Player>::Finalize(Player &owner)
|
||||
{
|
||||
owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
|
||||
owner.ClearUnitState(UNIT_STAT_FLEEING | UNIT_STAT_ROAMING);
|
||||
if (owner.GetTypeId() == TYPEID_UNIT && owner.getVictim())
|
||||
owner.ClearUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE);
|
||||
}
|
||||
|
||||
template<>
|
||||
void FleeingMovementGenerator<Creature>::Finalize(Creature &owner)
|
||||
{
|
||||
owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
|
||||
owner.ClearUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE);
|
||||
if (owner.getVictim())
|
||||
owner.SetTarget(owner.getVictim()->GetGUID());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
FleeingMovementGenerator<T>::Reset(T &owner)
|
||||
void FleeingMovementGenerator<T>::Reset(T &owner)
|
||||
{
|
||||
Initialize(owner);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
FleeingMovementGenerator<T>::Update(T &owner, const uint32 time_diff)
|
||||
FleeingMovementGenerator<T>::Update(T &owner, const uint32 &time_diff)
|
||||
{
|
||||
if (!&owner || !owner.isAlive())
|
||||
return false;
|
||||
if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED))
|
||||
{
|
||||
owner.ClearUnitState(UNIT_STAT_FLEEING_MOVE);
|
||||
return true;
|
||||
|
||||
Traveller<T> traveller(owner);
|
||||
}
|
||||
|
||||
i_nextCheckTime.Update(time_diff);
|
||||
|
||||
if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || !i_destinationHolder.HasDestination())
|
||||
{
|
||||
if (i_nextCheckTime.Passed() && owner.movespline->Finalized())
|
||||
_setTargetLocation(owner);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (i_destinationHolder.UpdateTraveller(traveller, time_diff))
|
||||
{
|
||||
i_destinationHolder.ResetUpdate(50);
|
||||
if (i_nextCheckTime.Passed() && i_destinationHolder.HasArrived())
|
||||
{
|
||||
_setTargetLocation(owner);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -402,17 +380,15 @@ template bool FleeingMovementGenerator<Player>::_getPoint(Player &, float &, flo
|
||||
template bool FleeingMovementGenerator<Creature>::_getPoint(Creature &, float &, float &, float &);
|
||||
template void FleeingMovementGenerator<Player>::_setTargetLocation(Player &);
|
||||
template void FleeingMovementGenerator<Creature>::_setTargetLocation(Creature &);
|
||||
template void FleeingMovementGenerator<Player>::Finalize(Player &);
|
||||
template void FleeingMovementGenerator<Creature>::Finalize(Creature &);
|
||||
template void FleeingMovementGenerator<Player>::Reset(Player &);
|
||||
template void FleeingMovementGenerator<Creature>::Reset(Creature &);
|
||||
template bool FleeingMovementGenerator<Player>::Update(Player &, const uint32);
|
||||
template bool FleeingMovementGenerator<Creature>::Update(Creature &, const uint32);
|
||||
template bool FleeingMovementGenerator<Player>::Update(Player &, const uint32 &);
|
||||
template bool FleeingMovementGenerator<Creature>::Update(Creature &, const uint32 &);
|
||||
|
||||
void TimedFleeingMovementGenerator::Finalize(Unit &owner)
|
||||
{
|
||||
owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
|
||||
owner.ClearUnitState(UNIT_STAT_FLEEING | UNIT_STAT_ROAMING);
|
||||
owner.ClearUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE);
|
||||
if (Unit* victim = owner.getVictim())
|
||||
{
|
||||
if (owner.isAlive())
|
||||
@@ -429,13 +405,20 @@ bool TimedFleeingMovementGenerator::Update(Unit & owner, const uint32 time_diff)
|
||||
return false;
|
||||
|
||||
if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED))
|
||||
{
|
||||
owner.ClearUnitState(UNIT_STAT_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 &, const uint32) version
|
||||
i_totalFleeTime.Update(time_diff);
|
||||
if (i_totalFleeTime.Passed())
|
||||
return false;
|
||||
|
||||
// This calls grant-parent Update method hiden by FleeingMovementGenerator::Update(Creature &, const 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);
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
#define TRINITY_FLEEINGMOVEMENTGENERATOR_H
|
||||
|
||||
#include "MovementGenerator.h"
|
||||
#include "DestinationHolder.h"
|
||||
#include "Traveller.h"
|
||||
|
||||
template<class T>
|
||||
class FleeingMovementGenerator
|
||||
@@ -33,8 +31,7 @@ class FleeingMovementGenerator
|
||||
void Initialize(T &);
|
||||
void Finalize(T &);
|
||||
void Reset(T &);
|
||||
bool Update(T &, const uint32);
|
||||
bool GetDestination(float &x, float &y, float &z) const;
|
||||
bool Update(T &, const uint32 &);
|
||||
|
||||
MovementGeneratorType GetMovementGeneratorType() { return FLEEING_MOTION_TYPE; }
|
||||
|
||||
@@ -56,8 +53,6 @@ class FleeingMovementGenerator
|
||||
float i_cur_angle;
|
||||
uint64 i_frightGUID;
|
||||
TimeTracker i_nextCheckTime;
|
||||
|
||||
DestinationHolder< Traveller<T> > i_destinationHolder;
|
||||
};
|
||||
|
||||
class TimedFleeingMovementGenerator
|
||||
|
||||
@@ -19,22 +19,16 @@
|
||||
#include "HomeMovementGenerator.h"
|
||||
#include "Creature.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "Traveller.h"
|
||||
#include "DestinationHolderImp.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "MoveSplineInit.h"
|
||||
#include "MoveSpline.h"
|
||||
|
||||
void HomeMovementGenerator<Creature>::Initialize(Creature & owner)
|
||||
{
|
||||
owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||
owner.AddUnitState(UNIT_STAT_EVADE);
|
||||
_setTargetLocation(owner);
|
||||
}
|
||||
|
||||
void HomeMovementGenerator<Creature>::Finalize(Creature & owner)
|
||||
{
|
||||
owner.ClearUnitState(UNIT_STAT_EVADE);
|
||||
}
|
||||
|
||||
void HomeMovementGenerator<Creature>::Reset(Creature &)
|
||||
{
|
||||
}
|
||||
@@ -47,42 +41,35 @@ void HomeMovementGenerator<Creature>::_setTargetLocation(Creature & owner)
|
||||
if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
|
||||
return;
|
||||
|
||||
float x, y, z;
|
||||
owner.GetHomePosition(x, y, z, ori);
|
||||
Movement::MoveSplineInit init(owner);
|
||||
float x, y, z, o;
|
||||
// at apply we can select more nice return points base at current movegen
|
||||
//if (owner.GetMotionMaster()->empty() || !owner.GetMotionMaster()->top()->GetResetPosition(owner,x,y,z))
|
||||
//{
|
||||
owner.GetHomePosition(x, y, z, o);
|
||||
init.SetFacing(o);
|
||||
//}
|
||||
init.MoveTo(x,y,z);
|
||||
init.SetWalk(false);
|
||||
init.Launch();
|
||||
|
||||
CreatureTraveller traveller(owner);
|
||||
|
||||
uint32 travel_time = i_destinationHolder.SetDestination(traveller, x, y, z);
|
||||
modifyTravelTime(travel_time);
|
||||
owner.ClearUnitState(uint32(UNIT_STAT_ALL_STATE & ~UNIT_STAT_EVADE));
|
||||
arrived = false;
|
||||
owner.ClearUnitState(UNIT_STAT_ALL_STATE & ~UNIT_STAT_EVADE);
|
||||
}
|
||||
|
||||
bool HomeMovementGenerator<Creature>::Update(Creature &owner, const uint32 time_diff)
|
||||
{
|
||||
CreatureTraveller traveller(owner);
|
||||
i_destinationHolder.UpdateTraveller(traveller, time_diff);
|
||||
arrived = owner.movespline->Finalized();
|
||||
return !arrived;
|
||||
}
|
||||
|
||||
if (time_diff > i_travel_timer)
|
||||
void HomeMovementGenerator<Creature>::Finalize(Creature& owner)
|
||||
{
|
||||
if (arrived)
|
||||
{
|
||||
owner.AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||
|
||||
// restore orientation of not moving creature at returning to home
|
||||
if (owner.GetDefaultMovementType() == IDLE_MOTION_TYPE)
|
||||
{
|
||||
//sLog->outDebug("Entering HomeMovement::GetDestination(z, y, z)");
|
||||
owner.SetOrientation(ori);
|
||||
WorldPacket packet;
|
||||
owner.BuildHeartBeatMsg(&packet);
|
||||
owner.SendMessageToSet(&packet, false);
|
||||
}
|
||||
|
||||
owner.ClearUnitState(UNIT_STAT_EVADE);
|
||||
owner.SetWalk(true);
|
||||
owner.LoadCreaturesAddon(true);
|
||||
owner.AI()->JustReachedHome();
|
||||
return false;
|
||||
}
|
||||
|
||||
i_travel_timer -= time_diff;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
#define TRINITY_HOMEMOVEMENTGENERATOR_H
|
||||
|
||||
#include "MovementGenerator.h"
|
||||
#include "DestinationHolder.h"
|
||||
#include "Traveller.h"
|
||||
|
||||
class Creature;
|
||||
|
||||
@@ -34,24 +32,18 @@ class HomeMovementGenerator<Creature>
|
||||
{
|
||||
public:
|
||||
|
||||
HomeMovementGenerator() {}
|
||||
HomeMovementGenerator() : arrived(false) {}
|
||||
~HomeMovementGenerator() {}
|
||||
|
||||
void Initialize(Creature &);
|
||||
void Finalize(Creature &);
|
||||
void Reset(Creature &);
|
||||
bool Update(Creature &, const uint32);
|
||||
void modifyTravelTime(uint32 travel_time) { i_travel_timer = travel_time; }
|
||||
MovementGeneratorType GetMovementGeneratorType() { return HOME_MOTION_TYPE; }
|
||||
|
||||
bool GetDestination(float& x, float& y, float& z) const { i_destinationHolder.GetDestination(x, y, z); return true; }
|
||||
|
||||
private:
|
||||
void _setTargetLocation(Creature &);
|
||||
DestinationHolder< Traveller<Creature> > i_destinationHolder;
|
||||
|
||||
float ori;
|
||||
uint32 i_travel_timer;
|
||||
bool arrived;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
@@ -20,61 +20,59 @@
|
||||
#include "Errors.h"
|
||||
#include "Creature.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "DestinationHolderImp.h"
|
||||
#include "World.h"
|
||||
#include "MoveSplineInit.h"
|
||||
#include "MoveSpline.h"
|
||||
|
||||
//----- Point Movement Generator
|
||||
template<class T>
|
||||
void PointMovementGenerator<T>::Initialize(T &unit)
|
||||
{
|
||||
unit.StopMoving();
|
||||
Traveller<T> traveller(unit);
|
||||
// OLD: knockback effect has UNIT_STAT_JUMPING set, so if here we disable sentmonstermove there will be creature position sync problem between client and server
|
||||
// NEW: reactivated this check - UNIT_STAT_JUMPING is only used in MoveJump, which sends its own packet
|
||||
i_destinationHolder.SetDestination(traveller, i_x, i_y, i_z, /*true*/ !unit.HasUnitState(UNIT_STAT_JUMPING));
|
||||
if (!unit.IsStopped())
|
||||
unit.StopMoving();
|
||||
|
||||
unit.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
|
||||
Movement::MoveSplineInit init(unit);
|
||||
init.MoveTo(i_x, i_y, i_z);
|
||||
if (speed > 0.0f)
|
||||
init.SetVelocity(speed);
|
||||
init.Launch();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool PointMovementGenerator<T>::Update(T &unit, const uint32 diff)
|
||||
bool PointMovementGenerator<T>::Update(T &unit, const uint32 &diff)
|
||||
{
|
||||
if (!&unit)
|
||||
return false;
|
||||
|
||||
if (unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED))
|
||||
if(unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED))
|
||||
{
|
||||
if (unit.HasUnitState(UNIT_STAT_CHARGING))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
unit.ClearUnitState(UNIT_STAT_ROAMING_MOVE);
|
||||
return true;
|
||||
}
|
||||
|
||||
Traveller<T> traveller(unit);
|
||||
|
||||
i_destinationHolder.UpdateTraveller(traveller, diff);
|
||||
|
||||
if (i_destinationHolder.HasArrived())
|
||||
{
|
||||
unit.ClearUnitState(UNIT_STAT_MOVE);
|
||||
arrived = true;
|
||||
return false;
|
||||
}
|
||||
else if (!unit.HasUnitState(UNIT_STAT_MOVE) && !unit.HasUnitState(UNIT_STAT_JUMPING))
|
||||
{
|
||||
i_destinationHolder.StartTravel(traveller);
|
||||
}
|
||||
|
||||
return true;
|
||||
unit.AddUnitState(UNIT_STAT_ROAMING_MOVE);
|
||||
return !unit.movespline->Finalized();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void PointMovementGenerator<T>:: Finalize(T &unit)
|
||||
{
|
||||
if (unit.HasUnitState(UNIT_STAT_CHARGING))
|
||||
unit.ClearUnitState(UNIT_STAT_CHARGING | UNIT_STAT_JUMPING);
|
||||
if (arrived) // without this crash!
|
||||
unit.ClearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
|
||||
|
||||
if (unit.movespline->Finalized())
|
||||
MovementInform(unit);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void PointMovementGenerator<T>::Reset(T &unit)
|
||||
{
|
||||
if (!unit.IsStopped())
|
||||
unit.StopMoving();
|
||||
|
||||
unit.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void PointMovementGenerator<T>::MovementInform(T & /*unit*/)
|
||||
{
|
||||
@@ -82,22 +80,23 @@ void PointMovementGenerator<T>::MovementInform(T & /*unit*/)
|
||||
|
||||
template <> void PointMovementGenerator<Creature>::MovementInform(Creature &unit)
|
||||
{
|
||||
if (id == EVENT_FALL_GROUND)
|
||||
{
|
||||
unit.setDeathState(JUST_DIED);
|
||||
unit.SetFlying(true);
|
||||
}
|
||||
unit.AI()->MovementInform(POINT_MOTION_TYPE, id);
|
||||
//if (id == EVENT_FALL_GROUND)
|
||||
//{
|
||||
// unit.setDeathState(JUST_DIED);
|
||||
// unit.SetFlying(true);
|
||||
//}
|
||||
if (unit.AI())
|
||||
unit.AI()->MovementInform(POINT_MOTION_TYPE, id);
|
||||
}
|
||||
|
||||
template void PointMovementGenerator<Player>::Initialize(Player&);
|
||||
template bool PointMovementGenerator<Player>::Update(Player &, const uint32 diff);
|
||||
template void PointMovementGenerator<Player>::MovementInform(Player&);
|
||||
template void PointMovementGenerator<Player>::Finalize(Player&);
|
||||
|
||||
template void PointMovementGenerator<Creature>::Initialize(Creature&);
|
||||
template bool PointMovementGenerator<Creature>::Update(Creature&, const uint32 diff);
|
||||
template void PointMovementGenerator<Player>::Finalize(Player&);
|
||||
template void PointMovementGenerator<Creature>::Finalize(Creature&);
|
||||
template void PointMovementGenerator<Player>::Reset(Player&);
|
||||
template void PointMovementGenerator<Creature>::Reset(Creature&);
|
||||
template bool PointMovementGenerator<Player>::Update(Player &, const uint32 &);
|
||||
template bool PointMovementGenerator<Creature>::Update(Creature&, const uint32 &);
|
||||
|
||||
void AssistanceMovementGenerator::Finalize(Unit &unit)
|
||||
{
|
||||
@@ -107,3 +106,24 @@ void AssistanceMovementGenerator::Finalize(Unit &unit)
|
||||
unit.GetMotionMaster()->MoveSeekAssistanceDistract(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY));
|
||||
}
|
||||
|
||||
bool EffectMovementGenerator::Update(Unit &unit, const uint32)
|
||||
{
|
||||
return !unit.movespline->Finalized();
|
||||
}
|
||||
|
||||
void EffectMovementGenerator::Finalize(Unit &unit)
|
||||
{
|
||||
if (unit.GetTypeId() != TYPEID_UNIT)
|
||||
return;
|
||||
|
||||
if (((Creature&)unit).AI() && unit.movespline->Finalized())
|
||||
((Creature&)unit).AI()->MovementInform(EFFECT_MOTION_TYPE, m_Id);
|
||||
// Need restore previous movement since we have no proper states system
|
||||
//if (unit.isAlive() && !unit.HasUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_FLEEING))
|
||||
//{
|
||||
// if (Unit * victim = unit.getVictim())
|
||||
// unit.GetMotionMaster()->MoveChase(victim);
|
||||
// else
|
||||
// unit.GetMotionMaster()->Initialize();
|
||||
//}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
#define TRINITY_POINTMOVEMENTGENERATOR_H
|
||||
|
||||
#include "MovementGenerator.h"
|
||||
#include "DestinationHolder.h"
|
||||
#include "Traveller.h"
|
||||
#include "FollowerReference.h"
|
||||
|
||||
template<class T>
|
||||
@@ -29,13 +27,13 @@ class PointMovementGenerator
|
||||
: public MovementGeneratorMedium< T, PointMovementGenerator<T> >
|
||||
{
|
||||
public:
|
||||
PointMovementGenerator(uint32 _id, float _x, float _y, float _z) : id(_id),
|
||||
i_x(_x), i_y(_y), i_z(_z), i_nextMoveTime(0), arrived(false) {}
|
||||
PointMovementGenerator(uint32 _id, float _x, float _y, float _z, float _speed = 0.0f) : id(_id),
|
||||
i_x(_x), i_y(_y), i_z(_z), speed(_speed) {}
|
||||
|
||||
void Initialize(T &);
|
||||
void Finalize(T &unit);
|
||||
void Reset(T &unit){unit.StopMoving();}
|
||||
bool Update(T &, const uint32 diff);
|
||||
void Finalize(T &);
|
||||
void Reset(T &);
|
||||
bool Update(T &, const uint32 &);
|
||||
|
||||
void MovementInform(T &);
|
||||
|
||||
@@ -45,9 +43,7 @@ class PointMovementGenerator
|
||||
private:
|
||||
uint32 id;
|
||||
float i_x, i_y, i_z;
|
||||
TimeTracker i_nextMoveTime;
|
||||
DestinationHolder< Traveller<T> > i_destinationHolder;
|
||||
bool arrived;
|
||||
float speed;
|
||||
};
|
||||
|
||||
class AssistanceMovementGenerator
|
||||
@@ -61,5 +57,19 @@ class AssistanceMovementGenerator
|
||||
void Finalize(Unit &);
|
||||
};
|
||||
|
||||
// Does almost nothing - just doesn't allows previous movegen interrupt current effect.
|
||||
class EffectMovementGenerator : public MovementGenerator
|
||||
{
|
||||
public:
|
||||
explicit EffectMovementGenerator(uint32 Id) : m_Id(Id) {}
|
||||
void Initialize(Unit &) {}
|
||||
void Finalize(Unit &unit);
|
||||
void Reset(Unit &) {}
|
||||
bool Update(Unit &u, const uint32);
|
||||
MovementGeneratorType GetMovementGeneratorType() { return EFFECT_MOTION_TYPE; }
|
||||
private:
|
||||
uint32 m_Id;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -19,123 +19,103 @@
|
||||
#include "Creature.h"
|
||||
#include "MapManager.h"
|
||||
#include "RandomMovementGenerator.h"
|
||||
#include "Traveller.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "DestinationHolderImp.h"
|
||||
#include "Map.h"
|
||||
#include "Util.h"
|
||||
#include "CreatureGroups.h"
|
||||
#include "MoveSplineInit.h"
|
||||
#include "MoveSpline.h"
|
||||
|
||||
#define RUNNING_CHANCE_RANDOMMV 20 //will be "1 / RUNNING_CHANCE_RANDOMMV"
|
||||
|
||||
template<>
|
||||
bool
|
||||
RandomMovementGenerator<Creature>::GetDestination(float &x, float &y, float &z) const
|
||||
{
|
||||
if (i_destinationHolder.HasArrived())
|
||||
return false;
|
||||
|
||||
i_destinationHolder.GetDestination(x, y, z);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef MAP_BASED_RAND_GEN
|
||||
#define rand_norm() creature.rand_norm()
|
||||
#endif
|
||||
|
||||
template<>
|
||||
void
|
||||
RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
|
||||
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
|
||||
{
|
||||
float X, Y, Z, nx, ny, nz, ori, dist;
|
||||
|
||||
creature.GetHomePosition(X, Y, Z, ori);
|
||||
|
||||
float respX, respY, respZ, respO, currZ, destX, destY, destZ, travelDistZ;
|
||||
creature.GetHomePosition(respX, respY, respZ, respO);
|
||||
currZ = creature.GetPositionZ();
|
||||
Map const* map = creature.GetBaseMap();
|
||||
|
||||
// For 2D/3D system selection
|
||||
//bool is_land_ok = creature.canWalk();
|
||||
//bool is_water_ok = creature.canSwim();
|
||||
bool is_air_ok = creature.canFly();
|
||||
//bool is_land_ok = creature.CanWalk(); // not used?
|
||||
//bool is_water_ok = creature.CanSwim(); // not used?
|
||||
bool is_air_ok = creature.canFly();
|
||||
|
||||
for (uint32 i = 0; ; ++i)
|
||||
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 * cos(angle);
|
||||
const float distanceY = range * sin(angle);
|
||||
|
||||
destX = respX + distanceX;
|
||||
destY = respY + distanceY;
|
||||
|
||||
// prevent invalid coordinates generation
|
||||
Trinity::NormalizeMapCoord(destX);
|
||||
Trinity::NormalizeMapCoord(destY);
|
||||
|
||||
travelDistZ = distanceX*distanceX + distanceY*distanceY;
|
||||
|
||||
if (is_air_ok) // 3D system above ground and above water (flying mode)
|
||||
{
|
||||
const float angle = (float)rand_norm()*static_cast<float>(M_PI*2);
|
||||
const float range = (float)rand_norm()*wander_distance;
|
||||
const float distanceX = range * cos(angle);
|
||||
const float distanceY = range * sin(angle);
|
||||
// Limit height change
|
||||
const float distanceZ = float(rand_norm()) * sqrtf(travelDistZ)/2.0f;
|
||||
destZ = respZ + distanceZ;
|
||||
float levelZ = map->GetWaterOrGroundLevel(destX, destY, destZ-2.0f);
|
||||
|
||||
nx = X + distanceX;
|
||||
ny = Y + distanceY;
|
||||
// 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 >= 100.0f ? 10.0f : sqrtf(travelDistZ);
|
||||
|
||||
// prevent invalid coordinates generation
|
||||
Trinity::NormalizeMapCoord(nx);
|
||||
Trinity::NormalizeMapCoord(ny);
|
||||
// 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(destX, destY, respZ+travelDistZ-2.0f, false);
|
||||
|
||||
dist = (nx - X)*(nx - X) + (ny - Y)*(ny - Y);
|
||||
|
||||
if (i == 5)
|
||||
if (fabs(destZ - respZ) > travelDistZ) // Map check
|
||||
{
|
||||
nz = Z;
|
||||
break;
|
||||
}
|
||||
// Vmap Horizontal or above
|
||||
destZ = map->GetHeight(destX, destY, respZ - 2.0f, true);
|
||||
|
||||
if (is_air_ok) // 3D system above ground and above water (flying mode)
|
||||
{
|
||||
const float distanceZ = (float)(rand_norm()) * sqrtf(dist)/2; // Limit height change
|
||||
nz = Z + distanceZ;
|
||||
float tz = map->GetHeight(nx, ny, nz-2.0f, false); // Map check only, vmap needed here but need to alter vmaps checks for height.
|
||||
float wz = map->GetWaterLevel(nx, ny);
|
||||
if (tz >= nz || wz >= nz)
|
||||
continue; // Problem here, we must fly above the ground and water, not under. Let's try on next tick
|
||||
}
|
||||
//else if (is_water_ok) // 3D system under water and above ground (swimming mode)
|
||||
else // 2D only
|
||||
{
|
||||
dist = dist >= 100.0f ? 10.0f : sqrtf(dist); // 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE)
|
||||
|
||||
// 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.
|
||||
nz = map->GetHeight(nx, ny, Z+dist-2.0f, false); // Map check
|
||||
if (fabs(nz-Z)>dist)
|
||||
if (fabs(destZ - respZ) > travelDistZ)
|
||||
{
|
||||
nz = map->GetHeight(nx, ny, Z-2.0f, true); // Vmap Horizontal or above
|
||||
if (fabs(nz-Z)>dist)
|
||||
{
|
||||
nz = map->GetHeight(nx, ny, Z+dist-2.0f, true); // Vmap Higher
|
||||
if (fabs(nz-Z)>dist)
|
||||
continue; // let's forget this bad coords where a z cannot be find and retry at next tick
|
||||
}
|
||||
// Vmap Higher
|
||||
destZ = map->GetHeight(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 (fabs(destZ - respZ) > travelDistZ)
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Traveller<Creature> traveller(creature);
|
||||
creature.SetOrientation(creature.GetAngle(nx, ny));
|
||||
i_destinationHolder.SetDestination(traveller, nx, ny, nz);
|
||||
creature.AddUnitState(UNIT_STAT_ROAMING);
|
||||
if (is_air_ok)
|
||||
{
|
||||
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
|
||||
}
|
||||
//else if (is_water_ok) // Swimming mode to be done with more than this check
|
||||
i_nextMoveTime.Reset(0);
|
||||
else
|
||||
{
|
||||
i_nextMoveTime.Reset(urand(500+i_destinationHolder.GetTotalTravelTime(), 5000+i_destinationHolder.GetTotalTravelTime()));
|
||||
creature.AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||
}
|
||||
i_nextMoveTime.Reset(urand(500, 10000));
|
||||
|
||||
creature.AddUnitState(UNIT_STAT_ROAMING_MOVE);
|
||||
|
||||
Movement::MoveSplineInit init(creature);
|
||||
init.MoveTo(destX, destY, destZ);
|
||||
init.SetWalk(true);
|
||||
init.Launch();
|
||||
|
||||
//Call for creature group update
|
||||
if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature)
|
||||
{
|
||||
creature.GetFormation()->LeaderMoveTo(nx, ny, nz);
|
||||
}
|
||||
creature.GetFormation()->LeaderMoveTo(destX, destY, destZ);
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
RandomMovementGenerator<Creature>::Initialize(Creature &creature)
|
||||
void RandomMovementGenerator<Creature>::Initialize(Creature &creature)
|
||||
{
|
||||
if (!creature.isAlive())
|
||||
return;
|
||||
@@ -143,8 +123,7 @@ RandomMovementGenerator<Creature>::Initialize(Creature &creature)
|
||||
if (!wander_distance)
|
||||
wander_distance = creature.GetRespawnRadius();
|
||||
|
||||
if (irand(0, RUNNING_CHANCE_RANDOMMV) > 0)
|
||||
creature.AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||
creature.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
|
||||
_setRandomLocation(creature);
|
||||
}
|
||||
|
||||
@@ -156,8 +135,11 @@ RandomMovementGenerator<Creature>::Reset(Creature &creature)
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
RandomMovementGenerator<Creature>::Finalize(Creature & /*creature*/){}
|
||||
void RandomMovementGenerator<Creature>::Finalize(Creature &creature)
|
||||
{
|
||||
creature.ClearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
|
||||
creature.SetWalk(false);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool
|
||||
@@ -165,35 +147,29 @@ RandomMovementGenerator<Creature>::Update(Creature &creature, const uint32 diff)
|
||||
{
|
||||
if (creature.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
|
||||
{
|
||||
i_nextMoveTime.Update(i_nextMoveTime.GetExpiry()); // Expire the timer
|
||||
creature.ClearUnitState(UNIT_STAT_ROAMING);
|
||||
i_nextMoveTime.Reset(0); // Expire the timer
|
||||
creature.ClearUnitState(UNIT_STAT_ROAMING_MOVE);
|
||||
return true;
|
||||
}
|
||||
|
||||
i_nextMoveTime.Update(diff);
|
||||
|
||||
if (i_destinationHolder.HasArrived() && !creature.IsStopped() && !creature.canFly())
|
||||
creature.ClearUnitState(UNIT_STAT_ROAMING | UNIT_STAT_MOVE);
|
||||
|
||||
if (!i_destinationHolder.HasArrived() && creature.IsStopped())
|
||||
creature.AddUnitState(UNIT_STAT_ROAMING);
|
||||
|
||||
CreatureTraveller traveller(creature);
|
||||
|
||||
if (i_destinationHolder.UpdateTraveller(traveller, diff, true))
|
||||
if (creature.movespline->Finalized())
|
||||
{
|
||||
i_nextMoveTime.Update(diff);
|
||||
if (i_nextMoveTime.Passed())
|
||||
{
|
||||
if (irand(0, RUNNING_CHANCE_RANDOMMV) > 0)
|
||||
creature.AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||
_setRandomLocation(creature);
|
||||
}
|
||||
else if (creature.isPet() && creature.GetOwner() && !creature.IsWithinDist(creature.GetOwner(), PET_FOLLOW_DIST+2.5f))
|
||||
{
|
||||
creature.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||
_setRandomLocation(creature);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool RandomMovementGenerator<Creature>::GetResetPosition(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);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -20,15 +20,12 @@
|
||||
#define TRINITY_RANDOMMOTIONGENERATOR_H
|
||||
|
||||
#include "MovementGenerator.h"
|
||||
#include "DestinationHolder.h"
|
||||
#include "Traveller.h"
|
||||
|
||||
template<class T>
|
||||
class RandomMovementGenerator
|
||||
: public MovementGeneratorMedium< T, RandomMovementGenerator<T> >
|
||||
{
|
||||
public:
|
||||
// Wander dist is related on db spawn dist. So what if we wanna set eandom movement on summoned creature?!
|
||||
RandomMovementGenerator(float spawn_dist = 0.0f) : i_nextMoveTime(0), wander_distance(spawn_dist) {}
|
||||
|
||||
void _setRandomLocation(T &);
|
||||
@@ -36,18 +33,13 @@ class RandomMovementGenerator
|
||||
void Finalize(T &);
|
||||
void Reset(T &);
|
||||
bool Update(T &, const uint32);
|
||||
bool GetDestination(float &x, float &y, float &z) const;
|
||||
void UpdateMapPosition(uint32 mapid, float &x, float &y, float &z)
|
||||
{
|
||||
i_destinationHolder.GetLocationNow(mapid, x, y, z);
|
||||
}
|
||||
bool GetResetPosition(T&, float& x, float& y, float& z);
|
||||
MovementGeneratorType GetMovementGeneratorType() { return RANDOM_MOTION_TYPE; }
|
||||
private:
|
||||
TimeTrackerSmall i_nextMoveTime;
|
||||
|
||||
DestinationHolder< Traveller<T> > i_destinationHolder;
|
||||
float wander_distance;
|
||||
uint32 i_nextMove;
|
||||
float wander_distance;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
@@ -21,106 +21,42 @@
|
||||
#include "Errors.h"
|
||||
#include "Creature.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "DestinationHolderImp.h"
|
||||
#include "World.h"
|
||||
|
||||
#define SMALL_ALPHA 0.05f
|
||||
#include "MoveSplineInit.h"
|
||||
#include "MoveSpline.h"
|
||||
|
||||
#include <cmath>
|
||||
/*
|
||||
struct StackCleaner
|
||||
{
|
||||
Creature &i_creature;
|
||||
StackCleaner(Creature &creature) : i_creature(creature) {}
|
||||
void Done(void) { i_creature.StopMoving(); }
|
||||
~StackCleaner()
|
||||
{
|
||||
i_creature->Clear();
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
template<class T>
|
||||
TargetedMovementGenerator<T>::TargetedMovementGenerator(Unit &target, float offset, float angle)
|
||||
: TargetedMovementGeneratorBase(target)
|
||||
, i_offset(offset), i_angle(angle), i_recalculateTravel(false)
|
||||
{
|
||||
target.GetPosition(i_targetX, i_targetY, i_targetZ);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
TargetedMovementGenerator<T>::_setTargetLocation(T &owner)
|
||||
template<class T, typename D>
|
||||
void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T &owner)
|
||||
{
|
||||
if (!i_target.isValid() || !i_target->IsInWorld())
|
||||
return false;
|
||||
return;
|
||||
|
||||
if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
|
||||
return false;
|
||||
if (owner.HasUnitState(UNIT_STAT_NOT_MOVE))
|
||||
return;
|
||||
|
||||
float x, y, z;
|
||||
Traveller<T> traveller(owner);
|
||||
if (i_destinationHolder.HasDestination())
|
||||
|
||||
if (i_offset && i_target->IsWithinDistInMap(&owner,2*i_offset))
|
||||
{
|
||||
if (i_destinationHolder.HasArrived())
|
||||
{
|
||||
// prevent redundant micro-movement
|
||||
if (!i_offset)
|
||||
{
|
||||
if (i_target->IsWithinMeleeRange(&owner))
|
||||
return false;
|
||||
}
|
||||
else if (!i_angle && !owner.HasUnitState(UNIT_STAT_FOLLOW))
|
||||
{
|
||||
if (i_target->IsWithinDistInMap(&owner, i_offset))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i_target->IsWithinDistInMap(&owner, i_offset + 1.0f))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool stop = false;
|
||||
if (!i_offset)
|
||||
{
|
||||
if (i_target->IsWithinMeleeRange(&owner, 0))
|
||||
stop = true;
|
||||
}
|
||||
else if (!i_angle && !owner.HasUnitState(UNIT_STAT_FOLLOW))
|
||||
{
|
||||
if (i_target->IsWithinDist(&owner, i_offset * 0.8f))
|
||||
stop = true;
|
||||
}
|
||||
if (!owner.movespline->Finalized())
|
||||
return;
|
||||
|
||||
if (stop)
|
||||
{
|
||||
owner.GetPosition(x, y, z);
|
||||
i_destinationHolder.SetDestination(traveller, x, y, z);
|
||||
i_destinationHolder.StartTravel(traveller, false);
|
||||
owner.StopMoving();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (i_target->GetExactDistSq(i_targetX, i_targetY, i_targetZ) < 0.01f)
|
||||
return false;
|
||||
owner.GetPosition(x, y, z);
|
||||
}
|
||||
|
||||
if (!i_offset)
|
||||
else if (!i_offset)
|
||||
{
|
||||
if (i_target->IsWithinMeleeRange(&owner))
|
||||
return;
|
||||
|
||||
// to nearest random contact position
|
||||
i_target->GetRandomContactPoint(&owner, x, y, z, 0, MELEE_RANGE - 0.5f);
|
||||
}
|
||||
else if (!i_angle && !owner.HasUnitState(UNIT_STAT_FOLLOW))
|
||||
{
|
||||
// caster chase
|
||||
i_target->GetContactPoint(&owner, x, y, z, i_offset * urand(80, 95) * 0.01f);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i_target->IsWithinDistInMap(&owner, i_offset + 1.0f))
|
||||
return;
|
||||
// to at i_offset distance from target and i_angle from target facing
|
||||
i_target->GetClosePoint(x, y, z, owner.GetObjectSize(), i_offset, i_angle);
|
||||
}
|
||||
@@ -137,55 +73,65 @@ TargetedMovementGenerator<T>::_setTargetLocation(T &owner)
|
||||
ralf
|
||||
|
||||
//We don't update Mob Movement, if the difference between New destination and last destination is < BothObjectSize
|
||||
float bothObjectSize = i_target->GetObjectSize() + owner.GetObjectSize() + CONTACT_DISTANCE;
|
||||
if (i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x, y, z) < bothObjectSize)
|
||||
float bothObjectSize = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius() + CONTACT_DISTANCE;
|
||||
if( i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x,y,z) < bothObjectSize )
|
||||
return;
|
||||
*/
|
||||
i_destinationHolder.SetDestination(traveller, x, y, z);
|
||||
owner.AddUnitState(UNIT_STAT_CHASE);
|
||||
i_destinationHolder.StartTravel(traveller);
|
||||
return true;
|
||||
|
||||
|
||||
D::_addUnitStateMove(owner);
|
||||
i_targetReached = false;
|
||||
i_recalculateTravel = false;
|
||||
|
||||
Movement::MoveSplineInit init(owner);
|
||||
init.MoveTo(x,y,z);
|
||||
init.SetWalk(((D*)this)->EnableWalking());
|
||||
init.Launch();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
TargetedMovementGenerator<T>::Initialize(T &owner)
|
||||
template<>
|
||||
void TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::UpdateFinalDistance(float /*fDistance*/)
|
||||
{
|
||||
if (owner.isInCombat())
|
||||
owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||
|
||||
_setTargetLocation(owner);
|
||||
// nothing to do for Player
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
TargetedMovementGenerator<T>::Finalize(T &owner)
|
||||
template<>
|
||||
void TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::UpdateFinalDistance(float /*fDistance*/)
|
||||
{
|
||||
owner.ClearUnitState(UNIT_STAT_CHASE);
|
||||
// nothing to do for Player
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
TargetedMovementGenerator<T>::Reset(T &owner)
|
||||
template<>
|
||||
void TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::UpdateFinalDistance(float fDistance)
|
||||
{
|
||||
Initialize(owner);
|
||||
i_offset = fDistance;
|
||||
i_recalculateTravel = true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
TargetedMovementGenerator<T>::Update(T &owner, const uint32 time_diff)
|
||||
template<>
|
||||
void TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::UpdateFinalDistance(float fDistance)
|
||||
{
|
||||
i_offset = fDistance;
|
||||
i_recalculateTravel = true;
|
||||
}
|
||||
|
||||
template<class T, typename D>
|
||||
bool TargetedMovementGeneratorMedium<T,D>::Update(T &owner, const uint32 & time_diff)
|
||||
{
|
||||
if (!i_target.isValid() || !i_target->IsInWorld())
|
||||
return false;
|
||||
|
||||
if (!&owner || !owner.isAlive())
|
||||
if (!owner.isAlive())
|
||||
return true;
|
||||
|
||||
if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_DISTRACTED))
|
||||
if (owner.HasUnitState(UNIT_STAT_NOT_MOVE))
|
||||
{
|
||||
D::_clearUnitStateMove(owner);
|
||||
return true;
|
||||
}
|
||||
|
||||
// prevent movement while casting spells with cast time or channel time
|
||||
if (owner.HasUnitState(UNIT_STAT_CASTING))
|
||||
if (owner.IsNonMeleeSpellCasted(false, false, true))
|
||||
{
|
||||
if (!owner.IsStopped())
|
||||
owner.StopMoving();
|
||||
@@ -193,85 +139,170 @@ TargetedMovementGenerator<T>::Update(T &owner, const uint32 time_diff)
|
||||
}
|
||||
|
||||
// prevent crash after creature killed pet
|
||||
if (!owner.HasUnitState(UNIT_STAT_FOLLOW) && owner.getVictim() != i_target.getTarget())
|
||||
return true;
|
||||
|
||||
Traveller<T> traveller(owner);
|
||||
|
||||
if (!i_destinationHolder.HasDestination())
|
||||
_setTargetLocation(owner);
|
||||
else if (owner.IsStopped() && !i_destinationHolder.HasArrived())
|
||||
if (static_cast<D*>(this)->_lostTarget(owner))
|
||||
{
|
||||
owner.AddUnitState(UNIT_STAT_CHASE);
|
||||
i_destinationHolder.StartTravel(traveller);
|
||||
D::_clearUnitStateMove(owner);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (i_destinationHolder.UpdateTraveller(traveller, time_diff))
|
||||
i_recheckDistance.Update(time_diff);
|
||||
if (i_recheckDistance.Passed())
|
||||
{
|
||||
// put targeted movement generators on a higher priority
|
||||
//if (owner.GetObjectSize())
|
||||
//i_destinationHolder.ResetUpdate(50);
|
||||
i_recheckDistance.Reset(50);
|
||||
//More distance let have better performance, less distance let have more sensitive reaction at target move.
|
||||
float allowed_dist = i_target->GetObjectSize() + owner.GetObjectSize() + MELEE_RANGE - 0.5f;
|
||||
float dist = (owner.movespline->FinalDestination() - G3D::Vector3(i_target->GetPositionX(),i_target->GetPositionY(),i_target->GetPositionZ())).squaredLength();
|
||||
if (dist >= allowed_dist * allowed_dist)
|
||||
_setTargetLocation(owner);
|
||||
}
|
||||
|
||||
// target moved
|
||||
if (i_targetX != i_target->GetPositionX() || i_targetY != i_target->GetPositionY()
|
||||
|| i_targetZ != i_target->GetPositionZ())
|
||||
{
|
||||
if (_setTargetLocation(owner) || !owner.HasUnitState(UNIT_STAT_FOLLOW))
|
||||
owner.SetInFront(i_target.getTarget());
|
||||
i_target->GetPosition(i_targetX, i_targetY, i_targetZ);
|
||||
}
|
||||
|
||||
if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || i_recalculateTravel)
|
||||
{
|
||||
i_recalculateTravel = false;
|
||||
//Angle update will take place into owner.StopMoving()
|
||||
if (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());
|
||||
|
||||
owner.StopMoving();
|
||||
if (owner.IsWithinMeleeRange(i_target.getTarget()) && !owner.HasUnitState(UNIT_STAT_FOLLOW))
|
||||
owner.Attack(i_target.getTarget(), true);
|
||||
if (!i_targetReached)
|
||||
{
|
||||
i_targetReached = true;
|
||||
static_cast<D*>(this)->_reachTarget(owner);
|
||||
}
|
||||
}
|
||||
|
||||
// Implemented for PetAI to handle resetting flags when pet owner reached
|
||||
if (i_destinationHolder.HasArrived())
|
||||
MovementInform(owner);
|
||||
|
||||
else
|
||||
{
|
||||
if (i_recalculateTravel)
|
||||
_setTargetLocation(owner);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------//
|
||||
template<class T>
|
||||
Unit*
|
||||
TargetedMovementGenerator<T>::GetTarget() const
|
||||
void ChaseMovementGenerator<T>::_reachTarget(T &owner)
|
||||
{
|
||||
return i_target.getTarget();
|
||||
if (owner.IsWithinMeleeRange(this->i_target.getTarget()))
|
||||
owner.Attack(this->i_target.getTarget(),true);
|
||||
}
|
||||
|
||||
template<>
|
||||
void ChaseMovementGenerator<Player>::Initialize(Player &owner)
|
||||
{
|
||||
owner.AddUnitState(UNIT_STAT_CHASE|UNIT_STAT_CHASE_MOVE);
|
||||
_setTargetLocation(owner);
|
||||
}
|
||||
|
||||
template<>
|
||||
void ChaseMovementGenerator<Creature>::Initialize(Creature &owner)
|
||||
{
|
||||
owner.SetWalk(false);
|
||||
owner.AddUnitState(UNIT_STAT_CHASE|UNIT_STAT_CHASE_MOVE);
|
||||
_setTargetLocation(owner);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void TargetedMovementGenerator<T>::MovementInform(T & /*unit*/)
|
||||
void ChaseMovementGenerator<T>::Finalize(T &owner)
|
||||
{
|
||||
owner.ClearUnitState(UNIT_STAT_CHASE|UNIT_STAT_CHASE_MOVE);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void ChaseMovementGenerator<T>::Reset(T &owner)
|
||||
{
|
||||
Initialize(owner);
|
||||
}
|
||||
|
||||
//-----------------------------------------------//
|
||||
template<>
|
||||
bool FollowMovementGenerator<Creature>::EnableWalking() const
|
||||
{
|
||||
return i_target.isValid() && i_target->IsWalking();
|
||||
}
|
||||
|
||||
template<>
|
||||
bool FollowMovementGenerator<Player>::EnableWalking() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
void FollowMovementGenerator<Player>::_updateSpeed(Player &/*u*/)
|
||||
{
|
||||
// nothing to do for Player
|
||||
}
|
||||
|
||||
template<>
|
||||
void FollowMovementGenerator<Creature>::_updateSpeed(Creature &u)
|
||||
{
|
||||
// pet only sync speed with owner
|
||||
if (!((Creature&)u).isPet() || !i_target.isValid() || i_target->GetGUID() != u.GetOwnerGUID())
|
||||
return;
|
||||
|
||||
u.UpdateSpeed(MOVE_RUN,true);
|
||||
u.UpdateSpeed(MOVE_WALK,true);
|
||||
u.UpdateSpeed(MOVE_SWIM,true);
|
||||
}
|
||||
|
||||
template<>
|
||||
void FollowMovementGenerator<Player>::Initialize(Player &owner)
|
||||
{
|
||||
owner.AddUnitState(UNIT_STAT_FOLLOW|UNIT_STAT_FOLLOW_MOVE);
|
||||
_updateSpeed(owner);
|
||||
_setTargetLocation(owner);
|
||||
}
|
||||
|
||||
template<>
|
||||
void FollowMovementGenerator<Creature>::Initialize(Creature &owner)
|
||||
{
|
||||
owner.AddUnitState(UNIT_STAT_FOLLOW|UNIT_STAT_FOLLOW_MOVE);
|
||||
_updateSpeed(owner);
|
||||
_setTargetLocation(owner);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void FollowMovementGenerator<T>::Finalize(T &owner)
|
||||
{
|
||||
owner.ClearUnitState(UNIT_STAT_FOLLOW|UNIT_STAT_FOLLOW_MOVE);
|
||||
_updateSpeed(owner);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void FollowMovementGenerator<T>::Reset(T &owner)
|
||||
{
|
||||
Initialize(owner);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void FollowMovementGenerator<T>::MovementInform(T & /*unit*/)
|
||||
{
|
||||
}
|
||||
|
||||
template <> void TargetedMovementGenerator<Creature>::MovementInform(Creature &unit)
|
||||
template<>
|
||||
void FollowMovementGenerator<Creature>::MovementInform(Creature &unit)
|
||||
{
|
||||
// Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle
|
||||
unit.AI()->MovementInform(TARGETED_MOTION_TYPE, i_target.getTarget()->GetGUIDLow());
|
||||
if (unit.AI())
|
||||
unit.AI()->MovementInform(FOLLOW_MOTION_TYPE, i_target.getTarget()->GetGUIDLow());
|
||||
}
|
||||
|
||||
template void TargetedMovementGenerator<Player>::MovementInform(Player&); // Not implemented for players
|
||||
template TargetedMovementGenerator<Player>::TargetedMovementGenerator(Unit &target, float offset, float angle);
|
||||
template TargetedMovementGenerator<Creature>::TargetedMovementGenerator(Unit &target, float offset, float angle);
|
||||
template bool TargetedMovementGenerator<Player>::_setTargetLocation(Player &);
|
||||
template bool TargetedMovementGenerator<Creature>::_setTargetLocation(Creature &);
|
||||
template void TargetedMovementGenerator<Player>::Initialize(Player &);
|
||||
template void TargetedMovementGenerator<Creature>::Initialize(Creature &);
|
||||
template void TargetedMovementGenerator<Player>::Finalize(Player &);
|
||||
template void TargetedMovementGenerator<Creature>::Finalize(Creature &);
|
||||
template void TargetedMovementGenerator<Player>::Reset(Player &);
|
||||
template void TargetedMovementGenerator<Creature>::Reset(Creature &);
|
||||
template bool TargetedMovementGenerator<Player>::Update(Player &, const uint32);
|
||||
template bool TargetedMovementGenerator<Creature>::Update(Creature &, const uint32);
|
||||
template Unit* TargetedMovementGenerator<Player>::GetTarget() const;
|
||||
template Unit* TargetedMovementGenerator<Creature>::GetTarget() const;
|
||||
//-----------------------------------------------//
|
||||
template void TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::_setTargetLocation(Player &);
|
||||
template void TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::_setTargetLocation(Player &);
|
||||
template void TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::_setTargetLocation(Creature &);
|
||||
template void TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::_setTargetLocation(Creature &);
|
||||
template bool TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::Update(Player &, const uint32 &);
|
||||
template bool TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::Update(Player &, const uint32 &);
|
||||
template bool TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::Update(Creature &, const uint32 &);
|
||||
template bool TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::Update(Creature &, const uint32 &);
|
||||
|
||||
template void ChaseMovementGenerator<Player>::_reachTarget(Player &);
|
||||
template void ChaseMovementGenerator<Creature>::_reachTarget(Creature &);
|
||||
template void ChaseMovementGenerator<Player>::Finalize(Player &);
|
||||
template void ChaseMovementGenerator<Creature>::Finalize(Creature &);
|
||||
template void ChaseMovementGenerator<Player>::Reset(Player &);
|
||||
template void ChaseMovementGenerator<Creature>::Reset(Creature &);
|
||||
|
||||
template void FollowMovementGenerator<Player>::Finalize(Player &);
|
||||
template void FollowMovementGenerator<Creature>::Finalize(Creature &);
|
||||
template void FollowMovementGenerator<Player>::Reset(Player &);
|
||||
template void FollowMovementGenerator<Creature>::Reset(Creature &);
|
||||
template void FollowMovementGenerator<Player>::MovementInform(Player &unit);
|
||||
|
||||
@@ -20,9 +20,8 @@
|
||||
#define TRINITY_TARGETEDMOVEMENTGENERATOR_H
|
||||
|
||||
#include "MovementGenerator.h"
|
||||
#include "DestinationHolder.h"
|
||||
#include "Traveller.h"
|
||||
#include "FollowerReference.h"
|
||||
#include "Timer.h"
|
||||
|
||||
class TargetedMovementGeneratorBase
|
||||
{
|
||||
@@ -33,41 +32,84 @@ class TargetedMovementGeneratorBase
|
||||
FollowerReference i_target;
|
||||
};
|
||||
|
||||
template<class T, typename D>
|
||||
class TargetedMovementGeneratorMedium
|
||||
: public MovementGeneratorMedium< T, D >, public TargetedMovementGeneratorBase
|
||||
{
|
||||
protected:
|
||||
TargetedMovementGeneratorMedium(Unit &target, float offset, float angle) :
|
||||
TargetedMovementGeneratorBase(target), i_offset(offset), i_angle(angle),
|
||||
i_recalculateTravel(false), i_targetReached(false), i_recheckDistance(0)
|
||||
{
|
||||
}
|
||||
~TargetedMovementGeneratorMedium() {}
|
||||
|
||||
public:
|
||||
bool Update(T &, const uint32 &);
|
||||
Unit* GetTarget() const { return i_target.getTarget(); }
|
||||
|
||||
void unitSpeedChanged() { i_recalculateTravel=true; }
|
||||
void UpdateFinalDistance(float fDistance);
|
||||
|
||||
protected:
|
||||
void _setTargetLocation(T &);
|
||||
|
||||
TimeTrackerSmall i_recheckDistance;
|
||||
float i_offset;
|
||||
float i_angle;
|
||||
bool i_recalculateTravel : 1;
|
||||
bool i_targetReached : 1;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class TargetedMovementGenerator
|
||||
: public MovementGeneratorMedium< T, TargetedMovementGenerator<T> >, public TargetedMovementGeneratorBase
|
||||
class ChaseMovementGenerator : public TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >
|
||||
{
|
||||
public:
|
||||
TargetedMovementGenerator(Unit &target, float offset = 0, float angle = 0);
|
||||
~TargetedMovementGenerator() {}
|
||||
ChaseMovementGenerator(Unit &target)
|
||||
: TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >(target) {}
|
||||
ChaseMovementGenerator(Unit &target, float offset, float angle)
|
||||
: TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >(target, offset, angle) {}
|
||||
~ChaseMovementGenerator() {}
|
||||
|
||||
MovementGeneratorType GetMovementGeneratorType() { return CHASE_MOTION_TYPE; }
|
||||
|
||||
void Initialize(T &);
|
||||
void Finalize(T &);
|
||||
void Reset(T &);
|
||||
bool Update(T &, const uint32);
|
||||
MovementGeneratorType GetMovementGeneratorType() { return TARGETED_MOTION_TYPE; }
|
||||
void MovementInform(T &){}
|
||||
|
||||
static void _clearUnitStateMove(T &u) { u.ClearUnitState(UNIT_STAT_CHASE_MOVE); }
|
||||
static void _addUnitStateMove(T &u) { u.AddUnitState(UNIT_STAT_CHASE_MOVE); }
|
||||
bool EnableWalking() const { return false;}
|
||||
bool _lostTarget(T &u) const { return u.getVictim() != this->GetTarget(); }
|
||||
void _reachTarget(T &);
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class FollowMovementGenerator : public TargetedMovementGeneratorMedium<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() {}
|
||||
|
||||
MovementGeneratorType GetMovementGeneratorType() { return FOLLOW_MOTION_TYPE; }
|
||||
|
||||
void Initialize(T &);
|
||||
void Finalize(T &);
|
||||
void Reset(T &);
|
||||
void MovementInform(T &);
|
||||
|
||||
Unit* GetTarget() const;
|
||||
|
||||
bool GetDestination(float &x, float &y, float &z) const
|
||||
{
|
||||
if (i_destinationHolder.HasArrived() || !i_destinationHolder.HasDestination()) return false;
|
||||
i_destinationHolder.GetDestination(x, y, z);
|
||||
return true;
|
||||
}
|
||||
|
||||
void unitSpeedChanged() { i_recalculateTravel=true; }
|
||||
static void _clearUnitStateMove(T &u) { u.ClearUnitState(UNIT_STAT_FOLLOW_MOVE); }
|
||||
static void _addUnitStateMove(T &u) { u.AddUnitState(UNIT_STAT_FOLLOW_MOVE); }
|
||||
bool EnableWalking() const;
|
||||
bool _lostTarget(T &) const { return false; }
|
||||
void _reachTarget(T &) {}
|
||||
private:
|
||||
|
||||
bool _setTargetLocation(T &);
|
||||
|
||||
float i_offset;
|
||||
float i_angle;
|
||||
DestinationHolder< Traveller<T> > i_destinationHolder;
|
||||
bool i_recalculateTravel;
|
||||
float i_targetX, i_targetY, i_targetZ;
|
||||
void _updateSpeed(T &u);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -17,222 +17,165 @@
|
||||
*/
|
||||
//Basic headers
|
||||
#include "WaypointMovementGenerator.h"
|
||||
#include "DestinationHolderImp.h"
|
||||
//Extended headers
|
||||
#include "ObjectMgr.h"
|
||||
#include "World.h"
|
||||
#include "MapManager.h" // for flightmaster grid preloading
|
||||
//Flightmaster grid preloading
|
||||
#include "MapManager.h"
|
||||
//Creature-specific headers
|
||||
#include "Creature.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "CreatureGroups.h"
|
||||
//Player-specific
|
||||
#include "Player.h"
|
||||
#include "MoveSplineInit.h"
|
||||
#include "MoveSpline.h"
|
||||
|
||||
template<class T>
|
||||
void
|
||||
WaypointMovementGenerator<T>::Initialize(T & /*u*/){}
|
||||
|
||||
template<>
|
||||
void
|
||||
WaypointMovementGenerator<Creature>::Finalize(Creature & /*u*/){}
|
||||
|
||||
template<>
|
||||
void
|
||||
WaypointMovementGenerator<Player>::Finalize(Player & /*u*/){}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
WaypointMovementGenerator<T>::MovementInform(T & /*unit*/){}
|
||||
|
||||
template<>
|
||||
void WaypointMovementGenerator<Creature>::MovementInform(Creature &unit)
|
||||
void WaypointMovementGenerator<Creature>::LoadPath(Creature &creature)
|
||||
{
|
||||
unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
|
||||
if (!path_id)
|
||||
path_id = creature.GetWaypointPath();
|
||||
|
||||
i_path = sWaypointMgr->GetPath(path_id);
|
||||
|
||||
if (!i_path)
|
||||
{
|
||||
// No movement found for entry
|
||||
sLog->outErrorDb("WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %u) doesn't have waypoint path id: %u", creature.GetName(), creature.GetEntry(), creature.GetGUIDLow(), path_id);
|
||||
return;
|
||||
}
|
||||
|
||||
StartMoveNow(creature);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool WaypointMovementGenerator<Creature>::GetDestination(float &x, float &y, float &z) const
|
||||
void WaypointMovementGenerator<Creature>::Initialize(Creature &creature)
|
||||
{
|
||||
if (i_destinationHolder.HasArrived())
|
||||
return false;
|
||||
LoadPath(creature);
|
||||
creature.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::Finalize(Creature &creature)
|
||||
{
|
||||
creature.ClearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
|
||||
creature.SetWalk(false);
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::Reset(Creature &creature)
|
||||
{
|
||||
creature.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
|
||||
StartMoveNow(creature);
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::OnArrived(Creature& creature)
|
||||
{
|
||||
if (!i_path || i_path->empty())
|
||||
return;
|
||||
if (m_isArrivalDone)
|
||||
return;
|
||||
|
||||
creature.ClearUnitState(UNIT_STAT_ROAMING_MOVE);
|
||||
m_isArrivalDone = true;
|
||||
|
||||
if (i_path->at(i_currentNode)->event_id && urand(0, 99) < i_path->at(i_currentNode)->event_chance)
|
||||
{
|
||||
sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Creature movement start script %u at point %u for %u.", i_path->at(i_currentNode)->event_id, i_currentNode, creature.GetGUID());
|
||||
creature.GetMap()->ScriptsStart(sWaypointScripts, i_path->at(i_currentNode)->event_id, &creature, NULL/*, false*/);
|
||||
}
|
||||
|
||||
// Inform script
|
||||
MovementInform(creature);
|
||||
Stop(i_path->at(i_currentNode)->delay);
|
||||
}
|
||||
|
||||
bool WaypointMovementGenerator<Creature>::StartMove(Creature &creature)
|
||||
{
|
||||
if (!i_path || i_path->empty())
|
||||
return false;
|
||||
if (Stopped())
|
||||
return true;
|
||||
|
||||
const WaypointData *node = i_path->at(i_currentNode);
|
||||
|
||||
if (m_isArrivalDone)
|
||||
{
|
||||
if ((i_currentNode == i_path->size() - 1) && !repeating) // If that's our last waypoint
|
||||
{
|
||||
creature.SetHomePosition(node->x, node->y, node->z, creature.GetOrientation());
|
||||
creature.GetMotionMaster()->Initialize();
|
||||
return false;
|
||||
}
|
||||
|
||||
i_currentNode = (i_currentNode+1) % i_path->size();
|
||||
}
|
||||
|
||||
m_isArrivalDone = false;
|
||||
|
||||
creature.AddUnitState(UNIT_STAT_ROAMING_MOVE);
|
||||
|
||||
Movement::MoveSplineInit init(creature);
|
||||
init.MoveTo(node->x, node->y, node->z);
|
||||
|
||||
if (node->orientation != 100 && node->delay != 0)
|
||||
init.SetFacing(node->orientation);
|
||||
|
||||
init.SetWalk(!node->run);
|
||||
init.Launch();
|
||||
|
||||
//Call for creature group update
|
||||
if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature)
|
||||
creature.GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
|
||||
|
||||
i_destinationHolder.GetDestination(x, y, z);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool WaypointMovementGenerator<Player>::GetDestination(float & /*x*/, float & /*y*/, float & /*z*/) const
|
||||
bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
void WaypointMovementGenerator<Creature>::Reset(Creature & /*unit*/)
|
||||
{
|
||||
StopedByPlayer = true;
|
||||
i_nextMoveTime.Reset(0);
|
||||
}
|
||||
|
||||
template<>
|
||||
void WaypointMovementGenerator<Player>::Reset(Player & /*unit*/){}
|
||||
|
||||
template<>
|
||||
void WaypointMovementGenerator<Creature>::InitTraveller(Creature &unit, const WaypointData &node)
|
||||
{
|
||||
node.run ? unit.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING):
|
||||
unit.AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||
|
||||
unit.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
|
||||
unit.SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
|
||||
|
||||
// TODO: make this part of waypoint node, so that creature can walk when desired?
|
||||
if (unit.canFly())
|
||||
unit.SetByteFlag(UNIT_FIELD_BYTES_1, 3, 0x02);
|
||||
|
||||
unit.AddUnitState(UNIT_STAT_ROAMING);
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
WaypointMovementGenerator<Creature>::Initialize(Creature &u)
|
||||
{
|
||||
u.StopMoving();
|
||||
//i_currentNode = -1; // uint32, become 0 in the first update
|
||||
//i_nextMoveTime.Reset(0);
|
||||
StopedByPlayer = false;
|
||||
if (!path_id)
|
||||
path_id = u.GetWaypointPath();
|
||||
waypoints = sWaypointMgr->GetPath(path_id);
|
||||
i_currentNode = 0;
|
||||
if (waypoints && waypoints->size())
|
||||
{
|
||||
node = waypoints->front();
|
||||
Traveller<Creature> traveller(u);
|
||||
InitTraveller(u, *node);
|
||||
i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z);
|
||||
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
|
||||
|
||||
//Call for creature group update
|
||||
if (u.GetFormation() && u.GetFormation()->getLeader() == &u)
|
||||
u.GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
|
||||
}
|
||||
else
|
||||
node = NULL;
|
||||
}
|
||||
|
||||
template<>
|
||||
void WaypointMovementGenerator<Player>::InitTraveller(Player & /*unit*/, const WaypointData & /*node*/){}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
WaypointMovementGenerator<T>::Update(T & /*unit*/, const uint32 /*diff*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool
|
||||
WaypointMovementGenerator<Creature>::Update(Creature &unit, const uint32 diff)
|
||||
{
|
||||
if (!&unit)
|
||||
return true;
|
||||
|
||||
if (!path_id)
|
||||
return false;
|
||||
|
||||
// Waypoint movement can be switched on/off
|
||||
// This is quite handy for escort quests and other stuff
|
||||
if (unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
|
||||
if (creature.HasUnitState(UNIT_STAT_NOT_MOVE))
|
||||
{
|
||||
creature.ClearUnitState(UNIT_STAT_ROAMING_MOVE);
|
||||
return true;
|
||||
|
||||
// Clear the generator if the path doesn't exist
|
||||
if (!waypoints || !waypoints->size())
|
||||
}
|
||||
// prevent a crash at empty waypoint path.
|
||||
if (!i_path || i_path->empty())
|
||||
return false;
|
||||
|
||||
Traveller<Creature> traveller(unit);
|
||||
|
||||
i_nextMoveTime.Update(diff);
|
||||
i_destinationHolder.UpdateTraveller(traveller, diff, true);
|
||||
|
||||
if (i_nextMoveTime.GetExpiry() < TIMEDIFF_NEXT_WP)
|
||||
if (Stopped())
|
||||
{
|
||||
if (unit.IsStopped())
|
||||
{
|
||||
if (StopedByPlayer)
|
||||
{
|
||||
ASSERT(node);
|
||||
InitTraveller(unit, *node);
|
||||
i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z);
|
||||
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
|
||||
StopedByPlayer = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (i_currentNode == waypoints->size() - 1) // If that's our last waypoint
|
||||
{
|
||||
if (repeating) // If the movement is repeating
|
||||
i_currentNode = 0; // Start moving all over again
|
||||
else
|
||||
{
|
||||
unit.SetHomePosition(node->x, node->y, node->z, unit.GetOrientation());
|
||||
unit.GetMotionMaster()->Initialize();
|
||||
return false; // Clear the waypoint movement
|
||||
}
|
||||
}
|
||||
else
|
||||
++i_currentNode;
|
||||
|
||||
node = waypoints->at(i_currentNode);
|
||||
InitTraveller(unit, *node);
|
||||
i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z);
|
||||
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
|
||||
|
||||
//Call for creature group update
|
||||
if (unit.GetFormation() && unit.GetFormation()->getLeader() == &unit)
|
||||
unit.GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Determine waittime
|
||||
if (node->delay)
|
||||
i_nextMoveTime.Reset(node->delay);
|
||||
|
||||
//note: disable "start" for mtmap
|
||||
if (node->event_id && urand(0, 99) < node->event_chance)
|
||||
unit.GetMap()->ScriptsStart(sWaypointScripts, node->event_id, &unit, NULL/*, false*/);
|
||||
|
||||
i_destinationHolder.ResetTravelTime();
|
||||
MovementInform(unit);
|
||||
unit.UpdateWaypointID(i_currentNode);
|
||||
unit.ClearUnitState(UNIT_STAT_ROAMING);
|
||||
if (node->orientation)
|
||||
{
|
||||
unit.Relocate(node->x, node->y, node->z, node->orientation);
|
||||
unit.SetFacing(node->orientation, NULL);
|
||||
}
|
||||
else
|
||||
unit.Relocate(node->x, node->y, node->z);
|
||||
}
|
||||
if (CanMove(diff))
|
||||
return StartMove(creature);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
if (unit.IsStopped() && !i_destinationHolder.HasArrived())
|
||||
if (creature.IsStopped())
|
||||
Stop(STOP_TIME_FOR_PLAYER);
|
||||
else if (creature.movespline->Finalized())
|
||||
{
|
||||
if (!StopedByPlayer)
|
||||
{
|
||||
i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER);
|
||||
i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER);
|
||||
StopedByPlayer = true;
|
||||
}
|
||||
}
|
||||
OnArrived(creature);
|
||||
return StartMove(creature);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::MovementInform(Creature &creature)
|
||||
{
|
||||
if (creature.AI())
|
||||
creature.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
|
||||
}
|
||||
|
||||
bool WaypointMovementGenerator<Creature>::GetResetPosition(Creature&, float& x, float& y, float& z)
|
||||
{
|
||||
// prevent a crash at empty waypoint path.
|
||||
if (!i_path || i_path->empty())
|
||||
return false;
|
||||
|
||||
const WaypointData* node = i_path->at(i_currentNode);
|
||||
x = node->x; y = node->y; z = node->z;
|
||||
return true;
|
||||
}
|
||||
|
||||
template void WaypointMovementGenerator<Player>::Initialize(Player &);
|
||||
template bool WaypointMovementGenerator<Player>::Update(Player &, const uint32);
|
||||
template void WaypointMovementGenerator<Player>::MovementInform(Player &);
|
||||
|
||||
//----------------------------------------------------//
|
||||
|
||||
@@ -253,71 +196,72 @@ uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const
|
||||
|
||||
void FlightPathMovementGenerator::Initialize(Player &player)
|
||||
{
|
||||
player.getHostileRefManager().setOnlineOfflineState(false);
|
||||
player.AddUnitState(UNIT_STAT_IN_FLIGHT);
|
||||
player.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
|
||||
Traveller<Player> traveller(player);
|
||||
// do not send movement, it was sent already
|
||||
i_destinationHolder.SetDestination(traveller, (*i_path)[i_currentNode].x, (*i_path)[i_currentNode].y, (*i_path)[i_currentNode].z, false);
|
||||
// For preloading end grid
|
||||
Reset(player);
|
||||
InitEndGridInfo();
|
||||
player.SendMonsterMoveByPath(GetPath(), GetCurrentNode(), GetPathAtMapEnd());
|
||||
}
|
||||
|
||||
void FlightPathMovementGenerator::Finalize(Player & player)
|
||||
{
|
||||
// remove flag to prevent send object build movement packets for flight state and crash (movement generator already not at top of stack)
|
||||
player.ClearUnitState(UNIT_STAT_IN_FLIGHT);
|
||||
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
float z = 0;
|
||||
i_destinationHolder.GetLocationNow(player.GetBaseMap(), x, y, z);
|
||||
player.UpdatePosition(x, y, z, player.GetOrientation());
|
||||
player.Dismount();
|
||||
player.RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
|
||||
|
||||
if(player.m_taxi.empty())
|
||||
{
|
||||
player.getHostileRefManager().setOnlineOfflineState(true);
|
||||
if(player.pvpInfo.inHostileArea)
|
||||
player.CastSpell(&player, 2479, true);
|
||||
|
||||
// update z position to ground and orientation for landing point
|
||||
// this prevent cheating with landing point at lags
|
||||
// when client side flight end early in comparison server side
|
||||
player.StopMoving();
|
||||
}
|
||||
}
|
||||
|
||||
#define PLAYER_FLIGHT_SPEED 32.0f
|
||||
|
||||
void FlightPathMovementGenerator::Reset(Player & player)
|
||||
{
|
||||
player.getHostileRefManager().setOnlineOfflineState(false);
|
||||
player.AddUnitState(UNIT_STAT_IN_FLIGHT);
|
||||
player.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
|
||||
|
||||
Movement::MoveSplineInit init(player);
|
||||
uint32 end = GetPathAtMapEnd();
|
||||
for (uint32 i = GetCurrentNode(); i != end; ++i)
|
||||
{
|
||||
G3D::Vector3 vertice((*i_path)[i].x,(*i_path)[i].y,(*i_path)[i].z);
|
||||
init.Path().push_back(vertice);
|
||||
}
|
||||
init.SetFirstPointId(GetCurrentNode());
|
||||
init.SetFly();
|
||||
init.SetVelocity(PLAYER_FLIGHT_SPEED);
|
||||
init.Launch();
|
||||
}
|
||||
|
||||
bool FlightPathMovementGenerator::Update(Player &player, const uint32 diff)
|
||||
{
|
||||
if (MovementInProgress())
|
||||
uint32 pointId = (uint32)player.movespline->currentPathIdx();
|
||||
if (pointId > i_currentNode)
|
||||
{
|
||||
Traveller<Player> traveller(player);
|
||||
if (i_destinationHolder.UpdateTraveller(traveller, diff))
|
||||
bool departureEvent = true;
|
||||
do
|
||||
{
|
||||
i_destinationHolder.ResetUpdate(FLIGHT_TRAVEL_UPDATE);
|
||||
if (i_destinationHolder.HasArrived())
|
||||
{
|
||||
DoEventIfAny(player, (*i_path)[i_currentNode], false);
|
||||
|
||||
uint32 curMap = (*i_path)[i_currentNode].mapid;
|
||||
++i_currentNode;
|
||||
if (MovementInProgress())
|
||||
{
|
||||
DoEventIfAny(player, (*i_path)[i_currentNode], true);
|
||||
|
||||
sLog->outStaticDebug("loading node %u for player %s", i_currentNode, player.GetName());
|
||||
if ((*i_path)[i_currentNode].mapid == curMap)
|
||||
{
|
||||
// do not send movement, it was sent already
|
||||
i_destinationHolder.SetDestination(traveller, (*i_path)[i_currentNode].x, (*i_path)[i_currentNode].y, (*i_path)[i_currentNode].z, false);
|
||||
}
|
||||
|
||||
// check if it's time to preload the flightmaster grid at path end
|
||||
if (i_currentNode == m_preloadTargetNode)
|
||||
PreloadEndGrid();
|
||||
|
||||
return true;
|
||||
}
|
||||
//else HasArrived()
|
||||
}
|
||||
else
|
||||
return true;
|
||||
DoEventIfAny(player, (*i_path)[i_currentNode], departureEvent);
|
||||
if (pointId == i_currentNode)
|
||||
break;
|
||||
if (i_currentNode == _preloadTargetNode)
|
||||
PreloadEndGrid();
|
||||
i_currentNode += (uint32)departureEvent;
|
||||
departureEvent = !departureEvent;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
while (true);
|
||||
}
|
||||
|
||||
// we have arrived at the end of the path
|
||||
return false;
|
||||
return i_currentNode < (i_path->size()-1);
|
||||
}
|
||||
|
||||
void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
|
||||
@@ -336,33 +280,6 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
|
||||
}
|
||||
}
|
||||
|
||||
void FlightPathMovementGenerator::InitEndGridInfo()
|
||||
{
|
||||
// Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will
|
||||
// be reinitialized for each flightmaster at the end of each spline (or stop) in the flight.
|
||||
|
||||
uint32 nodeCount = (*i_path).size(); // Get the number of nodes in the path.
|
||||
m_endMapId = (*i_path)[nodeCount -1].mapid; // Get the map ID from the last node
|
||||
m_preloadTargetNode = nodeCount - 3; // 2 nodes before the final node, we pre-load the grid
|
||||
m_endGridX = (*i_path)[nodeCount -1].x; // Get the X position from the last node
|
||||
m_endGridY = (*i_path)[nodeCount -1].y; // Get the Y position from the last node
|
||||
}
|
||||
|
||||
void FlightPathMovementGenerator::PreloadEndGrid()
|
||||
{
|
||||
// used to preload the final grid where the flightmaster is
|
||||
Map* endMap = sMapMgr->FindBaseNonInstanceMap(m_endMapId);
|
||||
|
||||
// Load the grid
|
||||
if (endMap)
|
||||
{
|
||||
sLog->outDetail("Preloading flightmaster at grid (%f, %f) for map %u", m_endGridX, m_endGridY, m_endMapId);
|
||||
endMap->LoadGrid(m_endGridX, m_endGridY);
|
||||
}
|
||||
else
|
||||
sLog->outDetail("Unable to determine map to preload flightmaster grid");
|
||||
}
|
||||
|
||||
void FlightPathMovementGenerator::DoEventIfAny(Player& player, TaxiPathNodeEntry const& node, bool departure)
|
||||
{
|
||||
if (uint32 eventid = departure ? node.departureEventID : node.arrivalEventID)
|
||||
@@ -372,6 +289,39 @@ void FlightPathMovementGenerator::DoEventIfAny(Player& player, TaxiPathNodeEntry
|
||||
}
|
||||
}
|
||||
|
||||
bool FlightPathMovementGenerator::GetResetPosition(Player&, float& x, float& y, float& z)
|
||||
{
|
||||
const TaxiPathNodeEntry& node = (*i_path)[i_currentNode];
|
||||
x = node.x; y = node.y; z = node.z;
|
||||
return true;
|
||||
}
|
||||
|
||||
void FlightPathMovementGenerator::InitEndGridInfo()
|
||||
{
|
||||
/*! Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will
|
||||
be reinitialized for each flightmaster at the end of each spline (or stop) in the flight. */
|
||||
uint32 nodeCount = (*i_path).size(); //! Number of nodes in path.
|
||||
_endMapId = (*i_path)[nodeCount - 1].mapid; //! MapId of last node
|
||||
_preloadTargetNode = nodeCount - 3;
|
||||
_endGridX = (*i_path)[nodeCount - 1].x;
|
||||
_endGridY = (*i_path)[nodeCount - 1].y;
|
||||
}
|
||||
|
||||
void FlightPathMovementGenerator::PreloadEndGrid()
|
||||
{
|
||||
// used to preload the final grid where the flightmaster is
|
||||
Map* endMap = sMapMgr->FindBaseNonInstanceMap(_endMapId);
|
||||
|
||||
// Load the grid
|
||||
if (endMap)
|
||||
{
|
||||
sLog->outDetail("Preloading rid (%f, %f) for map %u at node index %u/%u", _endGridX, _endGridY, _endMapId, _preloadTargetNode, (uint32)(i_path->size()-1));
|
||||
endMap->LoadGrid(_endGridX, _endGridY);
|
||||
}
|
||||
else
|
||||
sLog->outDetail("Unable to determine map to preload flightmaster grid");
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Unique1's ASTAR Pathfinding Code... For future use & reference...
|
||||
|
||||
@@ -26,10 +26,8 @@
|
||||
*/
|
||||
|
||||
#include "MovementGenerator.h"
|
||||
#include "DestinationHolder.h"
|
||||
#include "WaypointManager.h"
|
||||
#include "Path.h"
|
||||
#include "Traveller.h"
|
||||
|
||||
#include "Player.h"
|
||||
|
||||
@@ -44,49 +42,68 @@ template<class T, class P>
|
||||
class PathMovementBase
|
||||
{
|
||||
public:
|
||||
PathMovementBase() : i_currentNode(0) {}
|
||||
PathMovementBase() : i_currentNode(0), i_path(NULL) {}
|
||||
virtual ~PathMovementBase() {};
|
||||
|
||||
bool MovementInProgress(void) const { return i_currentNode < i_path->size(); }
|
||||
|
||||
// template pattern, not defined .. override required
|
||||
void LoadPath(T &);
|
||||
void ReloadPath(T &);
|
||||
uint32 GetCurrentNode() const { return i_currentNode; }
|
||||
|
||||
bool GetDestination(float& x, float& y, float& z) const { i_destinationHolder.GetDestination(x, y, z); return true; }
|
||||
bool GetPosition(float& x, float& y, float& z) const { i_destinationHolder.GetLocationNowNoMicroMovement(x, y, z); return true; }
|
||||
|
||||
protected:
|
||||
uint32 i_currentNode;
|
||||
DestinationHolder< Traveller<T> > i_destinationHolder;
|
||||
P i_path;
|
||||
uint32 i_currentNode;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class WaypointMovementGenerator;
|
||||
|
||||
class WaypointMovementGenerator
|
||||
: public MovementGeneratorMedium< T, WaypointMovementGenerator<T> >, public PathMovementBase<T, WaypointPath const*>
|
||||
template<>
|
||||
class WaypointMovementGenerator<Creature>
|
||||
: public MovementGeneratorMedium< Creature, WaypointMovementGenerator<Creature> >,
|
||||
public PathMovementBase<Creature, WaypointPath const*>
|
||||
{
|
||||
public:
|
||||
WaypointMovementGenerator(uint32 _path_id = 0, bool _repeating = true) :
|
||||
node(NULL), path_id(_path_id), i_nextMoveTime(0), repeating(_repeating), StopedByPlayer(false) {}
|
||||
WaypointMovementGenerator(uint32 _path_id = 0, bool _repeating = true) : i_nextMoveTime(0), path_id(_path_id), m_isArrivalDone(false), repeating(_repeating) {}
|
||||
~WaypointMovementGenerator() { i_path = NULL; }
|
||||
void Initialize(Creature &);
|
||||
void Finalize(Creature &);
|
||||
void Reset(Creature &);
|
||||
bool Update(Creature &, const uint32 &diff);
|
||||
|
||||
void MovementInform(Creature &);
|
||||
|
||||
void Initialize(T &);
|
||||
void Finalize(T &);
|
||||
void MovementInform(T &);
|
||||
void InitTraveller(T &, const WaypointData &);
|
||||
void GeneratePathId(T &);
|
||||
void Reset(T &unit);
|
||||
bool Update(T &, const uint32);
|
||||
bool GetDestination(float &x, float &y, float &z) const;
|
||||
MovementGeneratorType GetMovementGeneratorType() { return WAYPOINT_MOTION_TYPE; }
|
||||
|
||||
// now path movement implmementation
|
||||
void LoadPath(Creature &c);
|
||||
|
||||
bool GetResetPosition(Creature&, float& x, float& y, float& z);
|
||||
|
||||
private:
|
||||
WaypointData* node;
|
||||
uint32 path_id;
|
||||
|
||||
void Stop(int32 time) { i_nextMoveTime.Reset(time);}
|
||||
|
||||
bool Stopped() { return !i_nextMoveTime.Passed();}
|
||||
|
||||
bool CanMove(int32 diff)
|
||||
{
|
||||
i_nextMoveTime.Update(diff);
|
||||
return i_nextMoveTime.Passed();
|
||||
}
|
||||
|
||||
void OnArrived(Creature&);
|
||||
bool StartMove(Creature&);
|
||||
|
||||
void StartMoveNow(Creature& creature)
|
||||
{
|
||||
i_nextMoveTime.Reset(0);
|
||||
StartMove(creature);
|
||||
}
|
||||
|
||||
TimeTrackerSmall i_nextMoveTime;
|
||||
WaypointPath const* waypoints;
|
||||
bool repeating, StopedByPlayer;
|
||||
bool m_isArrivalDone;
|
||||
uint32 path_id;
|
||||
bool repeating;
|
||||
};
|
||||
|
||||
/** FlightPathMovementGenerator generates movement of the player for the paths
|
||||
@@ -103,7 +120,7 @@ public PathMovementBase<Player, TaxiPathNodeList const*>
|
||||
i_currentNode = startNode;
|
||||
}
|
||||
void Initialize(Player &);
|
||||
void Reset(Player & /*u*/){};
|
||||
void Reset(Player &);
|
||||
void Finalize(Player &);
|
||||
bool Update(Player &, const uint32);
|
||||
MovementGeneratorType GetMovementGeneratorType() { return FLIGHT_MOTION_TYPE; }
|
||||
@@ -115,17 +132,16 @@ public PathMovementBase<Player, TaxiPathNodeList const*>
|
||||
void SkipCurrentNode() { ++i_currentNode; }
|
||||
void DoEventIfAny(Player& player, TaxiPathNodeEntry const& node, bool departure);
|
||||
|
||||
bool GetDestination(float& x, float& y, float& z) const { return PathMovementBase<Player, TaxiPathNodeList const*>::GetDestination(x, y, z); }
|
||||
bool GetResetPosition(Player&, float& x, float& y, float& z);
|
||||
|
||||
void PreloadEndGrid();
|
||||
void InitEndGridInfo();
|
||||
void PreloadEndGrid();
|
||||
|
||||
private:
|
||||
// storage for preloading the flightmaster grid at end
|
||||
// before reaching final waypoint
|
||||
uint32 m_endMapId;
|
||||
uint32 m_preloadTargetNode;
|
||||
float m_endGridX;
|
||||
float m_endGridY;
|
||||
float _endGridX; //! X coord of last node location
|
||||
float _endGridY; //! Y coord of last node location
|
||||
uint32 _endMapId; //! map Id of last node location
|
||||
uint32 _preloadTargetNode; //! node index where preloading starts
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user