mirror of
https://github.com/mangosfour/server.git
synced 2025-12-13 22:37:03 +00:00
[11912] Use mmaps for MovementGenerators
This commit is contained in:
parent
e738c27714
commit
2f0ed05566
15 changed files with 130 additions and 744 deletions
|
|
@ -22,68 +22,18 @@
|
|||
#include "Player.h"
|
||||
#include "movement/MoveSplineInit.h"
|
||||
#include "movement/MoveSpline.h"
|
||||
#include "PathFinder.h"
|
||||
|
||||
template<class T>
|
||||
void
|
||||
ConfusedMovementGenerator<T>::Initialize(T &unit)
|
||||
void ConfusedMovementGenerator<T>::Initialize(T &unit)
|
||||
{
|
||||
const float wander_distance=11;
|
||||
float x,y,z;
|
||||
x = unit.GetPositionX();
|
||||
y = unit.GetPositionY();
|
||||
z = unit.GetPositionZ();
|
||||
|
||||
TerrainInfo const* map = unit.GetTerrain();
|
||||
|
||||
i_nextMove = 1;
|
||||
|
||||
bool is_water_ok, is_land_ok;
|
||||
_InitSpecific(unit, is_water_ok, is_land_ok);
|
||||
|
||||
for(unsigned int idx=0; idx < MAX_CONF_WAYPOINTS+1; ++idx)
|
||||
{
|
||||
const float wanderX=wander_distance*rand_norm_f() - wander_distance/2;
|
||||
const float wanderY=wander_distance*rand_norm_f() - wander_distance/2;
|
||||
|
||||
i_waypoints[idx][0] = x + wanderX;
|
||||
i_waypoints[idx][1] = y + wanderY;
|
||||
|
||||
// prevent invalid coordinates generation
|
||||
MaNGOS::NormalizeMapCoord(i_waypoints[idx][0]);
|
||||
MaNGOS::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;
|
||||
}
|
||||
|
||||
unit.UpdateAllowedPositionZ(i_waypoints[idx][0],i_waypoints[idx][1],z);
|
||||
i_waypoints[idx][2] = z;
|
||||
}
|
||||
// set initial position
|
||||
unit.GetPosition(i_x, i_y, i_z);
|
||||
|
||||
unit.StopMoving();
|
||||
unit.addUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE);
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
ConfusedMovementGenerator<Creature>::_InitSpecific(Creature &creature, bool &is_water_ok, bool &is_land_ok)
|
||||
{
|
||||
is_water_ok = creature.CanSwim();
|
||||
is_land_ok = creature.CanWalk();
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
ConfusedMovementGenerator<Player>::_InitSpecific(Player &, bool &is_water_ok, bool &is_land_ok)
|
||||
{
|
||||
is_water_ok = true;
|
||||
is_land_ok = true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void ConfusedMovementGenerator<T>::Interrupt(T &unit)
|
||||
{
|
||||
|
|
@ -94,7 +44,6 @@ void ConfusedMovementGenerator<T>::Interrupt(T &unit)
|
|||
template<class T>
|
||||
void ConfusedMovementGenerator<T>::Reset(T &unit)
|
||||
{
|
||||
i_nextMove = 1;
|
||||
i_nextMoveTime.Reset(0);
|
||||
unit.StopMoving();
|
||||
unit.addUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE);
|
||||
|
|
@ -113,10 +62,7 @@ bool ConfusedMovementGenerator<T>::Update(T &unit, const uint32 &diff)
|
|||
unit.addUnitState(UNIT_STAT_CONFUSED_MOVE);
|
||||
|
||||
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
|
||||
}
|
||||
i_nextMoveTime.Reset(urand(800, 1500));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -127,16 +73,28 @@ bool ConfusedMovementGenerator<T>::Update(T &unit, const uint32 &diff)
|
|||
// start moving
|
||||
unit.addUnitState(UNIT_STAT_CONFUSED_MOVE);
|
||||
|
||||
MANGOS_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];
|
||||
float x = i_x + 10.0f*(rand_norm_f() - 0.5f);
|
||||
float y = i_y + 10.0f*(rand_norm_f() - 0.5f);
|
||||
float z = i_z;
|
||||
|
||||
unit.UpdateAllowedPositionZ(x, y, z);
|
||||
|
||||
PathFinder path(&unit);
|
||||
path.setPathLengthLimit(30.0f);
|
||||
path.calculate(x, y, z);
|
||||
if(path.getPathType() & PATHFIND_NOPATH)
|
||||
{
|
||||
i_nextMoveTime.Reset(urand(800, 1000));
|
||||
return true;
|
||||
}
|
||||
|
||||
Movement::MoveSplineInit init(unit);
|
||||
init.MoveTo(x, y, z);
|
||||
init.MovebyPath(path.getPath());
|
||||
init.SetWalk(true);
|
||||
init.Launch();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -144,6 +102,7 @@ template<>
|
|||
void ConfusedMovementGenerator<Player>::Finalize(Player &unit)
|
||||
{
|
||||
unit.clearUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE);
|
||||
unit.StopMoving();
|
||||
}
|
||||
|
||||
template<>
|
||||
|
|
|
|||
|
|
@ -22,8 +22,6 @@
|
|||
#include "MovementGenerator.h"
|
||||
#include "Timer.h"
|
||||
|
||||
#define MAX_CONF_WAYPOINTS 24
|
||||
|
||||
template<class T>
|
||||
class MANGOS_DLL_SPEC ConfusedMovementGenerator
|
||||
: public MovementGeneratorMedium< T, ConfusedMovementGenerator<T> >
|
||||
|
|
@ -39,9 +37,7 @@ class MANGOS_DLL_SPEC ConfusedMovementGenerator
|
|||
|
||||
MovementGeneratorType GetMovementGeneratorType() const { return CONFUSED_MOTION_TYPE; }
|
||||
private:
|
||||
void _InitSpecific(T &, bool &, bool &);
|
||||
TimeTracker i_nextMoveTime;
|
||||
float i_waypoints[MAX_CONF_WAYPOINTS+1][3];
|
||||
uint32 i_nextMove;
|
||||
float i_x, i_y, i_z;
|
||||
};
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -23,13 +23,13 @@
|
|||
#include "ObjectAccessor.h"
|
||||
#include "movement/MoveSplineInit.h"
|
||||
#include "movement/MoveSpline.h"
|
||||
#include "PathFinder.h"
|
||||
|
||||
#define MIN_QUIET_DISTANCE 28.0f
|
||||
#define MAX_QUIET_DISTANCE 43.0f
|
||||
|
||||
template<class T>
|
||||
void
|
||||
FleeingMovementGenerator<T>::_setTargetLocation(T &owner)
|
||||
void FleeingMovementGenerator<T>::_setTargetLocation(T &owner)
|
||||
{
|
||||
if(!&owner)
|
||||
return;
|
||||
|
|
@ -38,297 +38,95 @@ FleeingMovementGenerator<T>::_setTargetLocation(T &owner)
|
|||
if (owner.hasUnitState(UNIT_STAT_CAN_NOT_REACT & ~UNIT_STAT_FLEEING))
|
||||
return;
|
||||
|
||||
if(!_setMoveData(owner))
|
||||
return;
|
||||
|
||||
float x, y, z;
|
||||
if(!_getPoint(owner, x, y, z))
|
||||
return;
|
||||
|
||||
owner.addUnitState(UNIT_STAT_FLEEING_MOVE);
|
||||
|
||||
PathFinder path(&owner);
|
||||
path.setPathLengthLimit(30.0f);
|
||||
path.calculate(x, y, z);
|
||||
if(path.getPathType() & PATHFIND_NOPATH)
|
||||
{
|
||||
i_nextCheckTime.Reset(urand(1000, 1500));
|
||||
return;
|
||||
}
|
||||
|
||||
Movement::MoveSplineInit init(owner);
|
||||
init.MoveTo(x,y,z);
|
||||
init.MovebyPath(path.getPath());
|
||||
init.SetWalk(false);
|
||||
init.Launch();
|
||||
int32 traveltime = init.Launch();
|
||||
i_nextCheckTime.Reset(traveltime + urand(800, 1500));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
|
||||
bool FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
|
||||
{
|
||||
if(!&owner)
|
||||
return false;
|
||||
|
||||
x = owner.GetPositionX();
|
||||
y = owner.GetPositionY();
|
||||
z = owner.GetPositionZ();
|
||||
|
||||
float temp_x, temp_y, angle;
|
||||
const TerrainInfo * _map = owner.GetTerrain();
|
||||
//primitive path-finding
|
||||
for(uint8 i = 0; i < 18; ++i)
|
||||
float dist_from_caster, angle_to_caster;
|
||||
if(Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGuid))
|
||||
{
|
||||
if(i_only_forward && i > 2)
|
||||
break;
|
||||
|
||||
float distance = 5.0f;
|
||||
|
||||
switch(i)
|
||||
{
|
||||
case 0:
|
||||
angle = i_cur_angle;
|
||||
break;
|
||||
case 1:
|
||||
angle = i_cur_angle;
|
||||
distance /= 2;
|
||||
break;
|
||||
case 2:
|
||||
angle = i_cur_angle;
|
||||
distance /= 4;
|
||||
break;
|
||||
case 3:
|
||||
angle = i_cur_angle + M_PI_F/4.0f;
|
||||
break;
|
||||
case 4:
|
||||
angle = i_cur_angle - M_PI_F/4.0f;
|
||||
break;
|
||||
case 5:
|
||||
angle = i_cur_angle + M_PI_F/4.0f;
|
||||
distance /= 2;
|
||||
break;
|
||||
case 6:
|
||||
angle = i_cur_angle - M_PI_F/4.0f;
|
||||
distance /= 2;
|
||||
break;
|
||||
case 7:
|
||||
angle = i_cur_angle + M_PI_F/2.0f;
|
||||
break;
|
||||
case 8:
|
||||
angle = i_cur_angle - M_PI_F/2.0f;
|
||||
break;
|
||||
case 9:
|
||||
angle = i_cur_angle + M_PI_F/2.0f;
|
||||
distance /= 2;
|
||||
break;
|
||||
case 10:
|
||||
angle = i_cur_angle - M_PI_F/2.0f;
|
||||
distance /= 2;
|
||||
break;
|
||||
case 11:
|
||||
angle = i_cur_angle + M_PI_F/4.0f;
|
||||
distance /= 4;
|
||||
break;
|
||||
case 12:
|
||||
angle = i_cur_angle - M_PI_F/4.0f;
|
||||
distance /= 4;
|
||||
break;
|
||||
case 13:
|
||||
angle = i_cur_angle + M_PI_F/2.0f;
|
||||
distance /= 4;
|
||||
break;
|
||||
case 14:
|
||||
angle = i_cur_angle - M_PI_F/2.0f;
|
||||
distance /= 4;
|
||||
break;
|
||||
case 15:
|
||||
angle = i_cur_angle + M_PI_F*3/4.0f;
|
||||
distance /= 2;
|
||||
break;
|
||||
case 16:
|
||||
angle = i_cur_angle - M_PI_F*3/4.0f;
|
||||
distance /= 2;
|
||||
break;
|
||||
case 17:
|
||||
angle = i_cur_angle + M_PI_F;
|
||||
distance /= 2;
|
||||
break;
|
||||
}
|
||||
temp_x = x + distance * cos(angle);
|
||||
temp_y = y + distance * sin(angle);
|
||||
MaNGOS::NormalizeMapCoord(temp_x);
|
||||
MaNGOS::NormalizeMapCoord(temp_y);
|
||||
if( owner.IsWithinLOS(temp_x,temp_y,z))
|
||||
{
|
||||
bool is_water_now = _map->IsInWater(x,y,z);
|
||||
|
||||
if(is_water_now && _map->IsInWater(temp_x,temp_y,z))
|
||||
{
|
||||
x = temp_x;
|
||||
y = temp_y;
|
||||
return true;
|
||||
}
|
||||
float new_z = _map->GetHeight(temp_x,temp_y,z,true);
|
||||
|
||||
if(new_z <= INVALID_HEIGHT)
|
||||
continue;
|
||||
|
||||
bool is_water_next = _map->IsInWater(temp_x,temp_y,new_z);
|
||||
|
||||
if((is_water_now && !is_water_next && !is_land_ok) || (!is_water_now && is_water_next && !is_water_ok))
|
||||
continue;
|
||||
|
||||
if( !(new_z - z) || distance / fabs(new_z - z) > 1.0f)
|
||||
{
|
||||
float new_z_left = _map->GetHeight(temp_x + 1.0f*cos(angle+M_PI_F/2),temp_y + 1.0f*sin(angle+M_PI_F/2),z,true);
|
||||
float new_z_right = _map->GetHeight(temp_x + 1.0f*cos(angle-M_PI_F/2),temp_y + 1.0f*sin(angle-M_PI_F/2),z,true);
|
||||
if(fabs(new_z_left - new_z) < 1.2f && fabs(new_z_right - new_z) < 1.2f)
|
||||
{
|
||||
x = temp_x;
|
||||
y = temp_y;
|
||||
z = new_z;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
i_to_distance_from_caster = 0.0f;
|
||||
i_nextCheckTime.Reset( urand(500,1000) );
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
FleeingMovementGenerator<T>::_setMoveData(T &owner)
|
||||
{
|
||||
float cur_dist_xyz = owner.GetDistance(i_caster_x, i_caster_y, i_caster_z);
|
||||
|
||||
if (i_to_distance_from_caster > 0.0f)
|
||||
{
|
||||
if ((i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz < i_to_distance_from_caster) ||
|
||||
// if we reach lower distance
|
||||
(i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz > i_last_distance_from_caster) ||
|
||||
// if we can't be close
|
||||
(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) )
|
||||
// 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) );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// now we are running, continue
|
||||
i_last_distance_from_caster = cur_dist_xyz;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
float cur_dist;
|
||||
float angle_to_caster;
|
||||
|
||||
if (Unit* fright = owner.GetMap()->GetUnit(i_frightGuid))
|
||||
{
|
||||
cur_dist = fright->GetDistance(&owner);
|
||||
if (cur_dist < cur_dist_xyz)
|
||||
{
|
||||
i_caster_x = fright->GetPositionX();
|
||||
i_caster_y = fright->GetPositionY();
|
||||
i_caster_z = fright->GetPositionZ();
|
||||
dist_from_caster = fright->GetDistance(&owner);
|
||||
if(dist_from_caster > 0.2f)
|
||||
angle_to_caster = fright->GetAngle(&owner);
|
||||
else
|
||||
angle_to_caster = frand(0, 2*M_PI_F);
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_dist = cur_dist_xyz;
|
||||
angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + M_PI_F;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_dist = cur_dist_xyz;
|
||||
angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + M_PI_F;
|
||||
dist_from_caster = 0.0f;
|
||||
angle_to_caster = frand(0, 2*M_PI_F);
|
||||
}
|
||||
|
||||
// if we too close may use 'path-finding' else just stop
|
||||
i_only_forward = cur_dist >= MIN_QUIET_DISTANCE/3;
|
||||
|
||||
//get angle and 'distance from caster' to run
|
||||
float angle;
|
||||
|
||||
if(i_cur_angle == 0.0f && i_last_distance_from_caster == 0.0f) //just started, first time
|
||||
float dist, angle;
|
||||
if(dist_from_caster < MIN_QUIET_DISTANCE)
|
||||
{
|
||||
angle = rand_norm_f()*(1.0f - cur_dist/MIN_QUIET_DISTANCE) * M_PI_F/3 + rand_norm_f()*M_PI_F*2/3;
|
||||
i_to_distance_from_caster = MIN_QUIET_DISTANCE;
|
||||
i_only_forward = true;
|
||||
dist = frand(0.4f, 1.3f)*(MIN_QUIET_DISTANCE - dist_from_caster);
|
||||
angle = angle_to_caster + frand(-M_PI_F/8, M_PI_F/8);
|
||||
}
|
||||
else if(cur_dist < MIN_QUIET_DISTANCE)
|
||||
else if(dist_from_caster > MAX_QUIET_DISTANCE)
|
||||
{
|
||||
angle = M_PI_F/6 + rand_norm_f()*M_PI_F*2/3;
|
||||
i_to_distance_from_caster = cur_dist*2/3 + rand_norm_f()*(MIN_QUIET_DISTANCE - cur_dist*2/3);
|
||||
dist = frand(0.4f, 1.0f)*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE);
|
||||
angle = -angle_to_caster + frand(-M_PI_F/4, M_PI_F/4);
|
||||
}
|
||||
else if(cur_dist > MAX_QUIET_DISTANCE)
|
||||
else // we are inside quiet range
|
||||
{
|
||||
angle = rand_norm_f()*M_PI_F/3 + M_PI_F*2/3;
|
||||
i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + rand_norm_f()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
angle = rand_norm_f()*M_PI_F;
|
||||
i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + rand_norm_f()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
|
||||
dist = frand(0.6f, 1.2f)*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE);
|
||||
angle = frand(0, 2*M_PI_F);
|
||||
}
|
||||
|
||||
int8 sign = rand_norm_f() > 0.5f ? 1 : -1;
|
||||
i_cur_angle = sign*angle + angle_to_caster;
|
||||
float curr_x, curr_y, curr_z;
|
||||
owner.GetPosition(curr_x, curr_y, curr_z);
|
||||
|
||||
// current distance
|
||||
i_last_distance_from_caster = cur_dist;
|
||||
x = curr_x + dist*cos(angle);
|
||||
y = curr_y + dist*sin(angle);
|
||||
z = curr_z;
|
||||
|
||||
owner.UpdateAllowedPositionZ(x, y, z);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
FleeingMovementGenerator<T>::Initialize(T &owner)
|
||||
void FleeingMovementGenerator<T>::Initialize(T &owner)
|
||||
{
|
||||
owner.addUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE);
|
||||
owner.StopMoving();
|
||||
|
||||
_Init(owner);
|
||||
|
||||
if (Unit * fright = owner.GetMap()->GetUnit(i_frightGuid))
|
||||
{
|
||||
i_caster_x = fright->GetPositionX();
|
||||
i_caster_y = fright->GetPositionY();
|
||||
i_caster_z = fright->GetPositionZ();
|
||||
}
|
||||
else
|
||||
{
|
||||
i_caster_x = owner.GetPositionX();
|
||||
i_caster_y = owner.GetPositionY();
|
||||
i_caster_z = owner.GetPositionZ();
|
||||
}
|
||||
|
||||
i_only_forward = true;
|
||||
i_cur_angle = 0.0f;
|
||||
i_last_distance_from_caster = 0.0f;
|
||||
i_to_distance_from_caster = 0.0f;
|
||||
_setTargetLocation(owner);
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
FleeingMovementGenerator<Creature>::_Init(Creature &owner)
|
||||
{
|
||||
if(owner.GetTypeId() == TYPEID_UNIT)
|
||||
owner.SetTargetGuid(ObjectGuid());
|
||||
is_water_ok = owner.CanSwim();
|
||||
is_land_ok = owner.CanWalk();
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
FleeingMovementGenerator<Player>::_Init(Player &)
|
||||
{
|
||||
is_water_ok = true;
|
||||
is_land_ok = true;
|
||||
_setTargetLocation(owner);
|
||||
}
|
||||
|
||||
template<>
|
||||
void FleeingMovementGenerator<Player>::Finalize(Player &owner)
|
||||
{
|
||||
owner.clearUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE);
|
||||
owner.StopMoving();
|
||||
}
|
||||
|
||||
template<>
|
||||
|
|
@ -372,8 +170,6 @@ bool FleeingMovementGenerator<T>::Update(T &owner, const uint32 & time_diff)
|
|||
|
||||
template void FleeingMovementGenerator<Player>::Initialize(Player &);
|
||||
template void FleeingMovementGenerator<Creature>::Initialize(Creature &);
|
||||
template bool FleeingMovementGenerator<Player>::_setMoveData(Player &);
|
||||
template bool FleeingMovementGenerator<Creature>::_setMoveData(Creature &);
|
||||
template bool FleeingMovementGenerator<Player>::_getPoint(Player &, float &, float &, float &);
|
||||
template bool FleeingMovementGenerator<Creature>::_getPoint(Creature &, float &, float &, float &);
|
||||
template void FleeingMovementGenerator<Player>::_setTargetLocation(Player &);
|
||||
|
|
|
|||
|
|
@ -40,19 +40,7 @@ class MANGOS_DLL_SPEC FleeingMovementGenerator
|
|||
private:
|
||||
void _setTargetLocation(T &owner);
|
||||
bool _getPoint(T &owner, float &x, float &y, float &z);
|
||||
bool _setMoveData(T &owner);
|
||||
void _Init(T &);
|
||||
|
||||
bool is_water_ok :1;
|
||||
bool is_land_ok :1;
|
||||
bool i_only_forward:1;
|
||||
|
||||
float i_caster_x;
|
||||
float i_caster_y;
|
||||
float i_caster_z;
|
||||
float i_last_distance_from_caster;
|
||||
float i_to_distance_from_caster;
|
||||
float i_cur_angle;
|
||||
ObjectGuid i_frightGuid;
|
||||
TimeTracker i_nextCheckTime;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -46,7 +46,8 @@ void HomeMovementGenerator<Creature>::_setTargetLocation(Creature & owner)
|
|||
owner.GetRespawnCoord(x, y, z, &o);
|
||||
init.SetFacing(o);
|
||||
}
|
||||
init.MoveTo(x,y,z);
|
||||
|
||||
init.MoveTo(x, y, z, true);
|
||||
init.SetWalk(false);
|
||||
init.Launch();
|
||||
|
||||
|
|
|
|||
|
|
@ -312,14 +312,14 @@ void MotionMaster::MoveFollow(Unit* target, float dist, float angle)
|
|||
Mutate(new FollowMovementGenerator<Creature>(*target,dist,angle));
|
||||
}
|
||||
|
||||
void MotionMaster::MovePoint(uint32 id, float x, float y, float z)
|
||||
void MotionMaster::MovePoint(uint32 id, float x, float y, float z, bool generatePath)
|
||||
{
|
||||
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "%s targeted point (Id: %u X: %f Y: %f Z: %f)", m_owner->GetGuidStr().c_str(), id, x, y, z );
|
||||
|
||||
if (m_owner->GetTypeId() == TYPEID_PLAYER)
|
||||
Mutate(new PointMovementGenerator<Player>(id,x,y,z));
|
||||
Mutate(new PointMovementGenerator<Player>(id,x,y,z,generatePath));
|
||||
else
|
||||
Mutate(new PointMovementGenerator<Creature>(id,x,y,z));
|
||||
Mutate(new PointMovementGenerator<Creature>(id,x,y,z,generatePath));
|
||||
}
|
||||
|
||||
void MotionMaster::MoveSeekAssistance(float x, float y, float z)
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ class MANGOS_DLL_SPEC MotionMaster : private std::stack<MovementGenerator *>
|
|||
void MoveChase(Unit* target, float dist = 0.0f, float angle = 0.0f);
|
||||
void MoveConfused();
|
||||
void MoveFleeing(Unit* enemy, uint32 timeLimit = 0);
|
||||
void MovePoint(uint32 id, float x,float y,float z);
|
||||
void MovePoint(uint32 id, float x,float y,float z, bool generatePath = true);
|
||||
void MoveSeekAssistance(float x,float y,float z);
|
||||
void MoveSeekAssistanceDistract(uint32 timer);
|
||||
void MoveWaypoint();
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@ class MANGOS_DLL_SPEC MovementGenerator
|
|||
// used by Evade code for select point to evade with expected restart default movement
|
||||
virtual bool GetResetPosition(Unit &, float& /*x*/, float& /*y*/, float& /*z*/) { return false; }
|
||||
|
||||
// given destination unreachable? due to pathfinsing or other
|
||||
virtual bool IsReachable() const { return true; }
|
||||
|
||||
// used for check from Update call is movegen still be active (top movement generator)
|
||||
// after some not safe for this calls
|
||||
bool IsActive(Unit& u);
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ void PointMovementGenerator<T>::Initialize(T &unit)
|
|||
|
||||
unit.addUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
|
||||
Movement::MoveSplineInit init(unit);
|
||||
init.MoveTo(i_x, i_y, i_z);
|
||||
init.MoveTo(i_x, i_y, i_z, m_generatePath);
|
||||
init.Launch();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ class MANGOS_DLL_SPEC 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) {}
|
||||
PointMovementGenerator(uint32 _id, float _x, float _y, float _z, bool _generatePath) :
|
||||
id(_id), i_x(_x), i_y(_y), i_z(_z), m_generatePath(_generatePath) {}
|
||||
|
||||
void Initialize(T &);
|
||||
void Finalize(T &);
|
||||
|
|
@ -45,6 +45,7 @@ class MANGOS_DLL_SPEC PointMovementGenerator
|
|||
private:
|
||||
uint32 id;
|
||||
float i_x,i_y,i_z;
|
||||
bool m_generatePath;
|
||||
};
|
||||
|
||||
class MANGOS_DLL_SPEC AssistanceMovementGenerator
|
||||
|
|
@ -52,7 +53,7 @@ class MANGOS_DLL_SPEC AssistanceMovementGenerator
|
|||
{
|
||||
public:
|
||||
AssistanceMovementGenerator(float _x, float _y, float _z) :
|
||||
PointMovementGenerator<Creature>(0, _x, _y, _z) {}
|
||||
PointMovementGenerator<Creature>(0, _x, _y, _z, true) {}
|
||||
|
||||
MovementGeneratorType GetMovementGeneratorType() const { return ASSISTANCE_MOTION_TYPE; }
|
||||
void Finalize(Unit &);
|
||||
|
|
|
|||
|
|
@ -25,84 +25,30 @@
|
|||
#include "movement/MoveSpline.h"
|
||||
|
||||
template<>
|
||||
void
|
||||
RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
|
||||
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
|
||||
{
|
||||
float respX, respY, respZ, respO, currZ, destX, destY, destZ, wander_distance, travelDistZ;
|
||||
|
||||
float respX, respY, respZ, respO, wander_distance;
|
||||
creature.GetRespawnCoord(respX, respY, respZ, &respO, &wander_distance);
|
||||
|
||||
currZ = creature.GetPositionZ();
|
||||
TerrainInfo const* map = creature.GetTerrain();
|
||||
|
||||
// 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();
|
||||
|
||||
const float angle = rand_norm_f() * (M_PI_F*2.0f);
|
||||
const float range = rand_norm_f() * wander_distance;
|
||||
const float distanceX = range * cos(angle);
|
||||
const float distanceY = range * sin(angle);
|
||||
|
||||
destX = respX + distanceX;
|
||||
destY = respY + distanceY;
|
||||
|
||||
// prevent invalid coordinates generation
|
||||
MaNGOS::NormalizeMapCoord(destX);
|
||||
MaNGOS::NormalizeMapCoord(destY);
|
||||
|
||||
travelDistZ = distanceX*distanceX + distanceY*distanceY;
|
||||
|
||||
if (is_air_ok) // 3D system above ground and above water (flying mode)
|
||||
{
|
||||
// Limit height change
|
||||
const float distanceZ = rand_norm_f() * sqrtf(travelDistZ)/2.0f;
|
||||
destZ = respZ + distanceZ;
|
||||
float levelZ = map->GetWaterOrGroundLevel(destX, destY, destZ-2.0f);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
if (fabs(destZ - respZ) > travelDistZ) // Map check
|
||||
{
|
||||
// Vmap Horizontal or above
|
||||
destZ = map->GetHeight(destX, destY, respZ - 2.0f, true);
|
||||
|
||||
if (fabs(destZ - respZ) > travelDistZ)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_air_ok)
|
||||
i_nextMoveTime.Reset(0);
|
||||
else
|
||||
i_nextMoveTime.Reset(urand(500, 10000));
|
||||
float destX = respX + range * cos(angle);
|
||||
float destY = respY + range * sin(angle);
|
||||
float destZ = creature.GetPositionZ();
|
||||
creature.UpdateAllowedPositionZ(destX, destY, destZ);
|
||||
|
||||
creature.addUnitState(UNIT_STAT_ROAMING_MOVE);
|
||||
|
||||
Movement::MoveSplineInit init(creature);
|
||||
init.MoveTo(destX, destY, destZ);
|
||||
init.MoveTo(destX, destY, destZ, true);
|
||||
init.SetWalk(true);
|
||||
init.Launch();
|
||||
|
||||
if (creature.CanFly())
|
||||
i_nextMoveTime.Reset(0);
|
||||
else
|
||||
i_nextMoveTime.Reset(urand(500, 10000));
|
||||
}
|
||||
|
||||
template<>
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@
|
|||
#include "movement/MoveSplineInit.h"
|
||||
#include "movement/MoveSpline.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
//-----------------------------------------------//
|
||||
template<class T, typename D>
|
||||
void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T &owner)
|
||||
|
|
@ -75,13 +73,22 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T &owner)
|
|||
return;
|
||||
*/
|
||||
|
||||
if(!i_path)
|
||||
i_path = new PathFinder(&owner);
|
||||
|
||||
// allow pets following their master to cheat while generating paths
|
||||
bool forceDest = (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->IsPet()
|
||||
&& owner.hasUnitState(UNIT_STAT_FOLLOW));
|
||||
i_path->calculate(x, y, z, forceDest);
|
||||
if(i_path->getPathType() & PATHFIND_NOPATH)
|
||||
return;
|
||||
|
||||
D::_addUnitStateMove(owner);
|
||||
i_targetReached = false;
|
||||
i_recalculateTravel = false;
|
||||
|
||||
Movement::MoveSplineInit init(owner);
|
||||
init.MoveTo(x,y,z);
|
||||
init.MovebyPath(i_path->getPath());
|
||||
init.SetWalk(((D*)this)->EnableWalking());
|
||||
init.Launch();
|
||||
}
|
||||
|
|
@ -145,13 +152,19 @@ bool TargetedMovementGeneratorMedium<T,D>::Update(T &owner, const uint32 & time_
|
|||
i_recheckDistance.Update(time_diff);
|
||||
if (i_recheckDistance.Passed())
|
||||
{
|
||||
i_recheckDistance.Reset(50);
|
||||
i_recheckDistance.Reset(100);
|
||||
|
||||
//More distance let have better performance, less distance let have more sensitive reaction at target move.
|
||||
float allowed_dist = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius()
|
||||
+ sWorld.getConfig(CONFIG_FLOAT_RATE_TARGET_POS_RECALCULATION_RANGE);
|
||||
float dist = (owner.movespline->FinalDestination() -
|
||||
G3D::Vector3(i_target->GetPositionX(),i_target->GetPositionY(),i_target->GetPositionZ())).squaredLength();
|
||||
if (dist >= allowed_dist * allowed_dist)
|
||||
float allowed_dist = owner.GetObjectBoundingRadius() + sWorld.getConfig(CONFIG_FLOAT_RATE_TARGET_POS_RECALCULATION_RANGE);
|
||||
G3D::Vector3 dest = owner.movespline->FinalDestination();
|
||||
|
||||
bool targetMoved = false;
|
||||
if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->CanFly())
|
||||
targetMoved = !i_target->IsWithinDist3d(dest.x, dest.y, dest.z, allowed_dist);
|
||||
else
|
||||
targetMoved = !i_target->IsWithinDist2d(dest.x, dest.y, allowed_dist);
|
||||
|
||||
if (targetMoved)
|
||||
_setTargetLocation(owner);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "MovementGenerator.h"
|
||||
#include "FollowerReference.h"
|
||||
#include "PathFinder.h"
|
||||
#include "Unit.h"
|
||||
|
||||
class MANGOS_DLL_SPEC TargetedMovementGeneratorBase
|
||||
|
|
@ -39,14 +40,20 @@ class MANGOS_DLL_SPEC TargetedMovementGeneratorMedium
|
|||
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)
|
||||
i_recalculateTravel(false), i_targetReached(false), i_recheckDistance(0),
|
||||
i_path(NULL)
|
||||
{
|
||||
}
|
||||
~TargetedMovementGeneratorMedium() {}
|
||||
~TargetedMovementGeneratorMedium() { delete i_path; }
|
||||
|
||||
public:
|
||||
bool Update(T &, const uint32 &);
|
||||
|
||||
bool IsReachable() const
|
||||
{
|
||||
return (i_path) ? (i_path->getPathType() & PATHFIND_NORMAL) : true;
|
||||
}
|
||||
|
||||
Unit* GetTarget() const { return i_target.getTarget(); }
|
||||
|
||||
void unitSpeedChanged() { i_recalculateTravel=true; }
|
||||
|
|
@ -60,6 +67,8 @@ class MANGOS_DLL_SPEC TargetedMovementGeneratorMedium
|
|||
float i_angle;
|
||||
bool i_recalculateTravel : 1;
|
||||
bool i_targetReached : 1;
|
||||
|
||||
PathFinder* i_path;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature &creature)
|
|||
|
||||
const WaypointNode &node = i_path->at(i_currentNode);
|
||||
Movement::MoveSplineInit init(creature);
|
||||
init.MoveTo(node.x, node.y, node.z);
|
||||
init.MoveTo(node.x, node.y, node.z, true);
|
||||
|
||||
if (node.orientation != 100 && node.delay != 0)
|
||||
init.SetFacing(node.orientation);
|
||||
|
|
@ -363,329 +363,3 @@ bool FlightPathMovementGenerator::GetResetPosition(Player&, float& x, float& y,
|
|||
x = node.x; y = node.y; z = node.z;
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Unique1's ASTAR Pathfinding Code... For future use & reference...
|
||||
//
|
||||
|
||||
#ifdef __PATHFINDING__
|
||||
|
||||
int GetFCost(int to, int num, int parentNum, float *gcost); // Below...
|
||||
|
||||
int ShortenASTARRoute(short int *pathlist, int number)
|
||||
{ // Wrote this to make the routes a little smarter (shorter)... No point looping back to the same places... Unique1
|
||||
short int temppathlist[MAX_PATHLIST_NODES];
|
||||
int count = 0;
|
||||
// int count2 = 0;
|
||||
int temp, temp2;
|
||||
int link;
|
||||
int upto = 0;
|
||||
|
||||
for (temp = number; temp >= 0; temp--)
|
||||
{
|
||||
qboolean shortened = qfalse;
|
||||
|
||||
for (temp2 = 0; temp2 < temp; temp2++)
|
||||
{
|
||||
for (link = 0; link < nodes[pathlist[temp]].enodenum; link++)
|
||||
{
|
||||
if (nodes[pathlist[temp]].links[link].flags & PATH_BLOCKED)
|
||||
continue;
|
||||
|
||||
//if ((bot->client->ps.eFlags & EF_TANK) && nodes[bot->current_node].links[link].flags & PATH_NOTANKS) //if this path is blocked, skip it
|
||||
// continue;
|
||||
|
||||
//if (nodes[nodes[pathlist[temp]].links[link].targetNode].origin[2] > nodes[pathlist[temp]].origin[2] + 32)
|
||||
// continue;
|
||||
|
||||
if (nodes[pathlist[temp]].links[link].targetNode == pathlist[temp2])
|
||||
{ // Found a shorter route...
|
||||
//if (OrgVisible(nodes[pathlist[temp2]].origin, nodes[pathlist[temp]].origin, -1))
|
||||
{
|
||||
temppathlist[count] = pathlist[temp2];
|
||||
temp = temp2;
|
||||
++count;
|
||||
shortened = qtrue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!shortened)
|
||||
{
|
||||
temppathlist[count] = pathlist[temp];
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
upto = count;
|
||||
|
||||
for (temp = 0; temp < count; temp++)
|
||||
{
|
||||
pathlist[temp] = temppathlist[upto];
|
||||
--upto;
|
||||
}
|
||||
|
||||
G_Printf("ShortenASTARRoute: Path size reduced from %i to %i nodes...n", number, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
===========================================================================
|
||||
CreatePathAStar
|
||||
This function uses the A* pathfinding algorithm to determine the
|
||||
shortest path between any two nodes.
|
||||
It's fairly complex, so I'm not really going to explain it much.
|
||||
Look up A* and binary heaps for more info.
|
||||
pathlist stores the ideal path between the nodes, in reverse order,
|
||||
and the return value is the number of nodes in that path
|
||||
===========================================================================
|
||||
*/
|
||||
int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist)
|
||||
{
|
||||
//all the data we have to hold...since we can't do dynamic allocation, has to be MAX_NODES
|
||||
//we can probably lower this later - eg, the open list should never have more than at most a few dozen items on it
|
||||
short int openlist[MAX_NODES+1]; //add 1 because it's a binary heap, and they don't use 0 - 1 is the first used index
|
||||
float gcost[MAX_NODES];
|
||||
int fcost[MAX_NODES];
|
||||
char list[MAX_NODES]; //0 is neither, 1 is open, 2 is closed - char because it's the smallest data type
|
||||
short int parent[MAX_NODES];
|
||||
|
||||
short int numOpen = 0;
|
||||
short int atNode, temp, newnode=-1;
|
||||
qboolean found = qfalse;
|
||||
int count = -1;
|
||||
float gc;
|
||||
int i, u, v, m;
|
||||
vec3_t vec;
|
||||
|
||||
//clear out all the arrays
|
||||
memset(openlist, 0, sizeof(short int)*(MAX_NODES+1));
|
||||
memset(fcost, 0, sizeof(int)*MAX_NODES);
|
||||
memset(list, 0, sizeof(char)*MAX_NODES);
|
||||
memset(parent, 0, sizeof(short int)*MAX_NODES);
|
||||
memset(gcost, -1, sizeof(float)*MAX_NODES);
|
||||
|
||||
//make sure we have valid data before calculating everything
|
||||
if ((from == NODE_INVALID) || (to == NODE_INVALID) || (from >= MAX_NODES) || (to >= MAX_NODES) || (from == to))
|
||||
return -1;
|
||||
|
||||
openlist[1] = from; //add the starting node to the open list
|
||||
++numOpen;
|
||||
gcost[from] = 0; //its f and g costs are obviously 0
|
||||
fcost[from] = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (numOpen != 0) //if there are still items in the open list
|
||||
{
|
||||
//pop the top item off of the list
|
||||
atNode = openlist[1];
|
||||
list[atNode] = 2; //put the node on the closed list so we don't check it again
|
||||
--numOpen;
|
||||
|
||||
openlist[1] = openlist[numOpen+1]; //move the last item in the list to the top position
|
||||
v = 1;
|
||||
|
||||
//this while loop reorders the list so that the new lowest fcost is at the top again
|
||||
while (1)
|
||||
{
|
||||
u = v;
|
||||
if ((2*u+1) < numOpen) //if both children exist
|
||||
{
|
||||
if (fcost[openlist[u]] >= fcost[openlist[2*u]])
|
||||
v = 2*u;
|
||||
if (fcost[openlist[v]] >= fcost[openlist[2*u+1]])
|
||||
v = 2*u+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((2*u) < numOpen) //if only one child exists
|
||||
{
|
||||
if (fcost[openlist[u]] >= fcost[openlist[2*u]])
|
||||
v = 2*u;
|
||||
}
|
||||
}
|
||||
|
||||
if (u != v) //if they're out of order, swap this item with its parent
|
||||
{
|
||||
temp = openlist[u];
|
||||
openlist[u] = openlist[v];
|
||||
openlist[v] = temp;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < nodes[atNode].enodenum; ++i) //loop through all the links for this node
|
||||
{
|
||||
newnode = nodes[atNode].links[i].targetNode;
|
||||
|
||||
//if this path is blocked, skip it
|
||||
if (nodes[atNode].links[i].flags & PATH_BLOCKED)
|
||||
continue;
|
||||
//if this path is blocked, skip it
|
||||
if (bot->client && (bot->client->ps.eFlags & EF_TANK) && nodes[atNode].links[i].flags & PATH_NOTANKS)
|
||||
continue;
|
||||
//skip any unreachable nodes
|
||||
if (bot->client && (nodes[newnode].type & NODE_ALLY_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_ALLIES))
|
||||
continue;
|
||||
if (bot->client && (nodes[newnode].type & NODE_AXIS_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_AXIS))
|
||||
continue;
|
||||
|
||||
if (list[newnode] == 2) //if this node is on the closed list, skip it
|
||||
continue;
|
||||
|
||||
if (list[newnode] != 1) //if this node is not already on the open list
|
||||
{
|
||||
openlist[++numOpen] = newnode; //add the new node to the open list
|
||||
list[newnode] = 1;
|
||||
parent[newnode] = atNode; //record the node's parent
|
||||
|
||||
if (newnode == to) //if we've found the goal, don't keep computing paths!
|
||||
break; //this will break the 'for' and go all the way to 'if (list[to] == 1)'
|
||||
|
||||
//store it's f cost value
|
||||
fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost);
|
||||
|
||||
//this loop re-orders the heap so that the lowest fcost is at the top
|
||||
m = numOpen;
|
||||
while (m != 1) //while this item isn't at the top of the heap already
|
||||
{
|
||||
//if it has a lower fcost than its parent
|
||||
if (fcost[openlist[m]] <= fcost[openlist[m/2]])
|
||||
{
|
||||
temp = openlist[m/2];
|
||||
openlist[m/2] = openlist[m];
|
||||
openlist[m] = temp; //swap them
|
||||
m /= 2;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
else //if this node is already on the open list
|
||||
{
|
||||
gc = gcost[atNode];
|
||||
VectorSubtract(nodes[newnode].origin, nodes[atNode].origin, vec);
|
||||
gc += VectorLength(vec); //calculate what the gcost would be if we reached this node along the current path
|
||||
|
||||
if (gc < gcost[newnode]) //if the new gcost is less (ie, this path is shorter than what we had before)
|
||||
{
|
||||
parent[newnode] = atNode; //set the new parent for this node
|
||||
gcost[newnode] = gc; //and the new g cost
|
||||
|
||||
for (i = 1; i < numOpen; ++i) //loop through all the items on the open list
|
||||
{
|
||||
if (openlist[i] == newnode) //find this node in the list
|
||||
{
|
||||
//calculate the new fcost and store it
|
||||
fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost);
|
||||
|
||||
//reorder the list again, with the lowest fcost item on top
|
||||
m = i;
|
||||
while (m != 1)
|
||||
{
|
||||
//if the item has a lower fcost than it's parent
|
||||
if (fcost[openlist[m]] < fcost[openlist[m/2]])
|
||||
{
|
||||
temp = openlist[m/2];
|
||||
openlist[m/2] = openlist[m];
|
||||
openlist[m] = temp; //swap them
|
||||
m /= 2;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
break; //exit the 'for' loop because we already changed this node
|
||||
} //if
|
||||
} //for
|
||||
} //if (gc < gcost[newnode])
|
||||
} //if (list[newnode] != 1) --> else
|
||||
} //for (loop through links)
|
||||
} //if (numOpen != 0)
|
||||
else
|
||||
{
|
||||
found = qfalse; //there is no path between these nodes
|
||||
break;
|
||||
}
|
||||
|
||||
if (list[to] == 1) //if the destination node is on the open list, we're done
|
||||
{
|
||||
found = qtrue;
|
||||
break;
|
||||
}
|
||||
} //while (1)
|
||||
|
||||
if (found == qtrue) //if we found a path
|
||||
{
|
||||
//G_Printf("%s - path found!n", bot->client->pers.netname);
|
||||
count = 0;
|
||||
|
||||
temp = to; //start at the end point
|
||||
while (temp != from) //travel along the path (backwards) until we reach the starting point
|
||||
{
|
||||
pathlist[count++] = temp; //add the node to the pathlist and increment the count
|
||||
temp = parent[temp]; //move to the parent of this node to continue the path
|
||||
}
|
||||
|
||||
pathlist[count++] = from; //add the beginning node to the end of the pathlist
|
||||
|
||||
#ifdef __BOT_SHORTEN_ROUTING__
|
||||
count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1
|
||||
#endif //__BOT_SHORTEN_ROUTING__
|
||||
}
|
||||
else
|
||||
{
|
||||
//G_Printf("^1*** ^4BOT DEBUG^5: (CreatePathAStar) There is no route between node ^7%i^5 and node ^7%i^5.n", from, to);
|
||||
count = CreateDumbRoute(from, to, pathlist);
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
#ifdef __BOT_SHORTEN_ROUTING__
|
||||
count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1
|
||||
#endif //__BOT_SHORTEN_ROUTING__
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
return count; //return the number of nodes in the path, -1 if not found
|
||||
}
|
||||
|
||||
/*
|
||||
===========================================================================
|
||||
GetFCost
|
||||
Utility function used by A* pathfinding to calculate the
|
||||
cost to move between nodes towards a goal. Using the A*
|
||||
algorithm F = G + H, G here is the distance along the node
|
||||
paths the bot must travel, and H is the straight-line distance
|
||||
to the goal node.
|
||||
Returned as an int because more precision is unnecessary and it
|
||||
will slightly speed up heap access
|
||||
===========================================================================
|
||||
*/
|
||||
int GetFCost(int to, int num, int parentNum, float *gcost)
|
||||
{
|
||||
float gc = 0;
|
||||
float hc = 0;
|
||||
vec3_t v;
|
||||
|
||||
if (gcost[num] == -1)
|
||||
{
|
||||
if (parentNum != -1)
|
||||
{
|
||||
gc = gcost[parentNum];
|
||||
VectorSubtract(nodes[num].origin, nodes[parentNum].origin, v);
|
||||
gc += VectorLength(v);
|
||||
}
|
||||
gcost[num] = gc;
|
||||
}
|
||||
else
|
||||
gc = gcost[num];
|
||||
|
||||
VectorSubtract(nodes[to].origin, nodes[num].origin, v);
|
||||
hc = VectorLength(v);
|
||||
|
||||
return (int)(gc + hc);
|
||||
}
|
||||
#endif //__PATHFINDING__
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef __REVISION_NR_H__
|
||||
#define __REVISION_NR_H__
|
||||
#define REVISION_NR "11911"
|
||||
#define REVISION_NR "11912"
|
||||
#endif // __REVISION_NR_H__
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue