diff --git a/src/game/ConfusedMovementGenerator.cpp b/src/game/ConfusedMovementGenerator.cpp index 811cfc13d..01d4a5ac4 100644 --- a/src/game/ConfusedMovementGenerator.cpp +++ b/src/game/ConfusedMovementGenerator.cpp @@ -22,68 +22,18 @@ #include "Player.h" #include "movement/MoveSplineInit.h" #include "movement/MoveSpline.h" +#include "PathFinder.h" template -void -ConfusedMovementGenerator::Initialize(T &unit) +void ConfusedMovementGenerator::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::_InitSpecific(Creature &creature, bool &is_water_ok, bool &is_land_ok) -{ - is_water_ok = creature.CanSwim(); - is_land_ok = creature.CanWalk(); -} - -template<> -void -ConfusedMovementGenerator::_InitSpecific(Player &, bool &is_water_ok, bool &is_land_ok) -{ - is_water_ok = true; - is_land_ok = true; -} - template void ConfusedMovementGenerator::Interrupt(T &unit) { @@ -94,7 +44,6 @@ void ConfusedMovementGenerator::Interrupt(T &unit) template void ConfusedMovementGenerator::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::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::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::Finalize(Player &unit) { unit.clearUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE); + unit.StopMoving(); } template<> diff --git a/src/game/ConfusedMovementGenerator.h b/src/game/ConfusedMovementGenerator.h index 87b4b8b7c..b6956669f 100644 --- a/src/game/ConfusedMovementGenerator.h +++ b/src/game/ConfusedMovementGenerator.h @@ -22,8 +22,6 @@ #include "MovementGenerator.h" #include "Timer.h" -#define MAX_CONF_WAYPOINTS 24 - template class MANGOS_DLL_SPEC ConfusedMovementGenerator : public MovementGeneratorMedium< T, ConfusedMovementGenerator > @@ -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 diff --git a/src/game/FleeingMovementGenerator.cpp b/src/game/FleeingMovementGenerator.cpp index 2ed929809..72346425e 100644 --- a/src/game/FleeingMovementGenerator.cpp +++ b/src/game/FleeingMovementGenerator.cpp @@ -23,312 +23,110 @@ #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 -void -FleeingMovementGenerator::_setTargetLocation(T &owner) +void FleeingMovementGenerator::_setTargetLocation(T &owner) { - if( !&owner ) + if(!&owner) return; // ignore in case other no reaction state 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 -bool -FleeingMovementGenerator::_getPoint(T &owner, float &x, float &y, float &z) +bool FleeingMovementGenerator::_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 -bool -FleeingMovementGenerator::_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 - { - cur_dist = cur_dist_xyz; - angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + M_PI_F; - } + 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; + 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 -void -FleeingMovementGenerator::Initialize(T &owner) +void FleeingMovementGenerator::Initialize(T &owner) { owner.addUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE); + owner.StopMoving(); - _Init(owner); + if(owner.GetTypeId() == TYPEID_UNIT) + owner.SetTargetGuid(ObjectGuid()); - 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::_Init(Creature &owner) -{ - owner.SetTargetGuid(ObjectGuid()); - is_water_ok = owner.CanSwim(); - is_land_ok = owner.CanWalk(); -} - -template<> -void -FleeingMovementGenerator::_Init(Player &) -{ - is_water_ok = true; - is_land_ok = true; -} - template<> void FleeingMovementGenerator::Finalize(Player &owner) { owner.clearUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE); + owner.StopMoving(); } template<> @@ -372,8 +170,6 @@ bool FleeingMovementGenerator::Update(T &owner, const uint32 & time_diff) template void FleeingMovementGenerator::Initialize(Player &); template void FleeingMovementGenerator::Initialize(Creature &); -template bool FleeingMovementGenerator::_setMoveData(Player &); -template bool FleeingMovementGenerator::_setMoveData(Creature &); template bool FleeingMovementGenerator::_getPoint(Player &, float &, float &, float &); template bool FleeingMovementGenerator::_getPoint(Creature &, float &, float &, float &); template void FleeingMovementGenerator::_setTargetLocation(Player &); diff --git a/src/game/FleeingMovementGenerator.h b/src/game/FleeingMovementGenerator.h index da18339ef..bda63481e 100644 --- a/src/game/FleeingMovementGenerator.h +++ b/src/game/FleeingMovementGenerator.h @@ -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; }; diff --git a/src/game/HomeMovementGenerator.cpp b/src/game/HomeMovementGenerator.cpp index 17b926928..13f207c7b 100644 --- a/src/game/HomeMovementGenerator.cpp +++ b/src/game/HomeMovementGenerator.cpp @@ -46,7 +46,8 @@ void HomeMovementGenerator::_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(); diff --git a/src/game/MotionMaster.cpp b/src/game/MotionMaster.cpp index 66938be75..183bac227 100644 --- a/src/game/MotionMaster.cpp +++ b/src/game/MotionMaster.cpp @@ -312,14 +312,14 @@ void MotionMaster::MoveFollow(Unit* target, float dist, float angle) Mutate(new FollowMovementGenerator(*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(id,x,y,z)); + Mutate(new PointMovementGenerator(id,x,y,z,generatePath)); else - Mutate(new PointMovementGenerator(id,x,y,z)); + Mutate(new PointMovementGenerator(id,x,y,z,generatePath)); } void MotionMaster::MoveSeekAssistance(float x, float y, float z) diff --git a/src/game/MotionMaster.h b/src/game/MotionMaster.h index 8b73836fc..f238f28f3 100644 --- a/src/game/MotionMaster.h +++ b/src/game/MotionMaster.h @@ -102,7 +102,7 @@ class MANGOS_DLL_SPEC MotionMaster : private std::stack 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(); diff --git a/src/game/MovementGenerator.h b/src/game/MovementGenerator.h index 019c4c1cc..ebd7bdd16 100644 --- a/src/game/MovementGenerator.h +++ b/src/game/MovementGenerator.h @@ -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); diff --git a/src/game/PointMovementGenerator.cpp b/src/game/PointMovementGenerator.cpp index 91262a2ba..2abe26750 100644 --- a/src/game/PointMovementGenerator.cpp +++ b/src/game/PointMovementGenerator.cpp @@ -34,7 +34,7 @@ void PointMovementGenerator::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(); } diff --git a/src/game/PointMovementGenerator.h b/src/game/PointMovementGenerator.h index 9926f2a48..6e972b0f8 100644 --- a/src/game/PointMovementGenerator.h +++ b/src/game/PointMovementGenerator.h @@ -28,8 +28,8 @@ class MANGOS_DLL_SPEC PointMovementGenerator : public MovementGeneratorMedium< T, PointMovementGenerator > { 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(0, _x, _y, _z) {} + PointMovementGenerator(0, _x, _y, _z, true) {} MovementGeneratorType GetMovementGeneratorType() const { return ASSISTANCE_MOTION_TYPE; } void Finalize(Unit &); diff --git a/src/game/RandomMovementGenerator.cpp b/src/game/RandomMovementGenerator.cpp index 37f94917a..40684d1b1 100644 --- a/src/game/RandomMovementGenerator.cpp +++ b/src/game/RandomMovementGenerator.cpp @@ -25,84 +25,30 @@ #include "movement/MoveSpline.h" template<> -void -RandomMovementGenerator::_setRandomLocation(Creature &creature) +void RandomMovementGenerator::_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<> diff --git a/src/game/TargetedMovementGenerator.cpp b/src/game/TargetedMovementGenerator.cpp index b86773e59..0f8271acf 100644 --- a/src/game/TargetedMovementGenerator.cpp +++ b/src/game/TargetedMovementGenerator.cpp @@ -25,8 +25,6 @@ #include "movement/MoveSplineInit.h" #include "movement/MoveSpline.h" -#include - //-----------------------------------------------// template void TargetedMovementGeneratorMedium::_setTargetLocation(T &owner) @@ -75,13 +73,22 @@ void TargetedMovementGeneratorMedium::_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::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); } diff --git a/src/game/TargetedMovementGenerator.h b/src/game/TargetedMovementGenerator.h index 519cdd576..d05e0d471 100644 --- a/src/game/TargetedMovementGenerator.h +++ b/src/game/TargetedMovementGenerator.h @@ -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 diff --git a/src/game/WaypointMovementGenerator.cpp b/src/game/WaypointMovementGenerator.cpp index b33acfb5a..fb3012aac 100644 --- a/src/game/WaypointMovementGenerator.cpp +++ b/src/game/WaypointMovementGenerator.cpp @@ -181,7 +181,7 @@ void WaypointMovementGenerator::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__ diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 080d5d15d..505f5cd3d 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "11911" + #define REVISION_NR "11912" #endif // __REVISION_NR_H__