Created
September 9, 2010 03:14
-
-
Save vermie/571299 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/contrib/mmap/src/generator.cpp b/contrib/mmap/src/generator.cpp | |
index 33f2686..4cc5e94 100644 | |
--- a/contrib/mmap/src/generator.cpp | |
+++ b/contrib/mmap/src/generator.cpp | |
@@ -66,6 +66,12 @@ void handleArgs(int argc, char** argv, | |
if(strcmp(argv[i], "--maxAngle") == 0) | |
{ | |
param = argv[++i]; | |
+ if(!param) | |
+ { | |
+ badParam = true; | |
+ return; | |
+ } | |
+ | |
float maxangle = atof(param); | |
if(maxangle <= 90.f && maxangle >= 45.f) | |
maxAngle = maxangle; | |
@@ -75,6 +81,12 @@ void handleArgs(int argc, char** argv, | |
else if(strcmp(argv[i], "--tile") == 0) | |
{ | |
param = argv[++i]; | |
+ if(!param) | |
+ { | |
+ badParam = true; | |
+ return; | |
+ } | |
+ | |
char* stileX = strtok(param, ","); | |
char* stileY = strtok(NULL, ","); | |
int tilex = atoi(stileX); | |
@@ -94,6 +106,12 @@ void handleArgs(int argc, char** argv, | |
else if(strcmp(argv[i], "--skipLiquid") == 0) | |
{ | |
param = argv[++i]; | |
+ if(!param) | |
+ { | |
+ badParam = true; | |
+ return; | |
+ } | |
+ | |
if(strcmp(param, "true") == 0) | |
skipLiquid = true; | |
else if(strcmp(param, "false") == 0) | |
@@ -104,6 +122,12 @@ void handleArgs(int argc, char** argv, | |
else if(strcmp(argv[i], "--skipContinents") == 0) | |
{ | |
param = argv[++i]; | |
+ if(!param) | |
+ { | |
+ badParam = true; | |
+ return; | |
+ } | |
+ | |
if(strcmp(param, "true") == 0) | |
skipContinents = true; | |
else if(strcmp(param, "false") == 0) | |
@@ -114,6 +138,12 @@ void handleArgs(int argc, char** argv, | |
else if(strcmp(argv[i], "--skipJunkMaps") == 0) | |
{ | |
param = argv[++i]; | |
+ if(!param) | |
+ { | |
+ badParam = true; | |
+ return; | |
+ } | |
+ | |
if(strcmp(param, "true") == 0) | |
skipJunkMaps = true; | |
else if(strcmp(param, "false") == 0) | |
@@ -124,6 +154,12 @@ void handleArgs(int argc, char** argv, | |
else if(strcmp(argv[i], "--skipBattlegrounds") == 0) | |
{ | |
param = argv[++i]; | |
+ if(!param) | |
+ { | |
+ badParam = true; | |
+ return; | |
+ } | |
+ | |
if(strcmp(param, "true") == 0) | |
skipBattlegrounds = true; | |
else if(strcmp(param, "false") == 0) | |
@@ -134,6 +170,12 @@ void handleArgs(int argc, char** argv, | |
else if(strcmp(argv[i], "--hiResHeightmaps") == 0) | |
{ | |
param = argv[++i]; | |
+ if(!param) | |
+ { | |
+ badParam = true; | |
+ return; | |
+ } | |
+ | |
if(strcmp(param, "true") == 0) | |
hiResHeightmaps = true; | |
else if(strcmp(param, "false") == 0) | |
@@ -144,6 +186,12 @@ void handleArgs(int argc, char** argv, | |
else if(strcmp(argv[i], "--debugOutput") == 0) | |
{ | |
param = argv[++i]; | |
+ if(!param) | |
+ { | |
+ badParam = true; | |
+ return; | |
+ } | |
+ | |
if(strcmp(param, "true") == 0) | |
debugOutput = true; | |
else if(strcmp(param, "false") == 0) | |
diff --git a/src/game/HomeMovementGenerator.cpp b/src/game/HomeMovementGenerator.cpp | |
index a73d727..8eeed7d 100644 | |
--- a/src/game/HomeMovementGenerator.cpp | |
+++ b/src/game/HomeMovementGenerator.cpp | |
@@ -48,49 +48,31 @@ HomeMovementGenerator<Creature>::_setTargetLocation(Creature & owner) | |
if (owner.GetMotionMaster()->empty() || !owner.GetMotionMaster()->top()->GetResetPosition(owner,x,y,z)) | |
owner.GetRespawnCoord(x, y, z); | |
- if(!i_path) | |
- i_path = new PathInfo(&owner, x, y, z); | |
- else | |
- i_path->Update(x, y, z); | |
+ CreatureTraveller traveller(owner); | |
+ i_destinationHolder.SetDestination(traveller, x, y, z, false); | |
- // we always have a path to the target - shortcut in worst case | |
- // even is this map don't have mmaps at all | |
- i_path->getNextPosition(x, y, z); | |
+ PathInfo i_path(&owner, x, y, z); | |
+ PointPath myPath = i_path.getFullPath(); | |
- CreatureTraveller traveller(owner); | |
- i_destinationHolder.SetDestination(traveller, x, y, z); | |
+ float speed = traveller.Speed()*0.001f; // in ms | |
+ uint32 traveltime = uint32(myPath.GetTotalLength()/speed); | |
+ modifyTravelTime(traveltime); | |
+ | |
+ owner.SendMonsterMoveByPath(myPath, 0, myPath.size(), owner.GetSplineFlags(), traveltime); | |
owner.clearUnitState(UNIT_STAT_ALL_STATE); | |
} | |
bool | |
HomeMovementGenerator<Creature>::Update(Creature &owner, const uint32& time_diff) | |
{ | |
- CreatureTraveller traveller( owner); | |
- bool reachedHome = false; | |
- | |
+ CreatureTraveller traveller(owner); | |
if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false)) | |
{ | |
if (!IsActive(owner)) // force stop processing (movement can move out active zone with cleanup movegens list) | |
return true; // not expire now, but already lost | |
- | |
- bool needNewDest = false; | |
- if(i_path && i_destinationHolder.HasArrived()) | |
- { | |
- float end_x, end_y, end_z, next_x, next_y, next_z, cur_x, cur_y, cur_z; | |
- float dist = owner.GetObjectBoundingRadius(); | |
- i_path->getNextPosition(next_x, next_y, next_z); | |
- i_path->getEndPosition(end_x, end_y, end_z); | |
- i_destinationHolder.GetLocationNow(owner.GetBaseMap(), cur_x, cur_y, cur_z); | |
- | |
- reachedHome = isSamePoint(dist, cur_x, cur_y, cur_z, end_x, end_y, end_z); | |
- needNewDest = !isSamePoint(dist, next_x, next_y, next_z, end_x, end_y, end_z); | |
- } | |
- | |
- if (!i_path || needNewDest) | |
- _setTargetLocation(owner); | |
} | |
- if (reachedHome) | |
+ if (time_diff > i_travel_timer) | |
{ | |
owner.AddSplineFlag(SPLINEFLAG_WALKMODE); | |
@@ -111,5 +93,7 @@ HomeMovementGenerator<Creature>::Update(Creature &owner, const uint32& time_diff | |
return false; | |
} | |
+ i_travel_timer -= time_diff; | |
+ | |
return true; | |
} | |
diff --git a/src/game/HomeMovementGenerator.h b/src/game/HomeMovementGenerator.h | |
index 7b9d04c..af9ded0 100644 | |
--- a/src/game/HomeMovementGenerator.h | |
+++ b/src/game/HomeMovementGenerator.h | |
@@ -35,14 +35,15 @@ class MANGOS_DLL_SPEC HomeMovementGenerator<Creature> | |
{ | |
public: | |
- HomeMovementGenerator():i_path(NULL){} | |
- ~HomeMovementGenerator() { delete i_path; } | |
+ HomeMovementGenerator(){} | |
+ ~HomeMovementGenerator(){} | |
void Initialize(Creature &); | |
void Finalize(Creature &) {} | |
void Interrupt(Creature &) {} | |
void Reset(Creature &); | |
bool Update(Creature &, const uint32 &); | |
+ void modifyTravelTime(uint32 travel_time) { i_travel_timer = travel_time; } | |
MovementGeneratorType GetMovementGeneratorType() const { return HOME_MOTION_TYPE; } | |
bool GetDestination(float& x, float& y, float& z) const { i_destinationHolder.GetDestination(x,y,z); return true; } | |
@@ -50,6 +51,6 @@ class MANGOS_DLL_SPEC HomeMovementGenerator<Creature> | |
void _setTargetLocation(Creature &); | |
DestinationHolder< Traveller<Creature> > i_destinationHolder; | |
- PathInfo* i_path; | |
+ uint32 i_travel_timer; | |
}; | |
#endif | |
diff --git a/src/game/PathFinder.cpp b/src/game/PathFinder.cpp | |
index 9731875..a7b8c9d 100644 | |
--- a/src/game/PathFinder.cpp | |
+++ b/src/game/PathFinder.cpp | |
@@ -24,11 +24,10 @@ | |
////////////////// PathInfo ////////////////// | |
PathInfo::PathInfo(const WorldObject* from, const float x, const float y, const float z) : | |
- m_navMesh(NULL), m_navMeshQuery(NULL), | |
- m_polyLength(0), m_pathPolyRefs(NULL), m_pointLength(0), m_pathPoints(NULL), | |
+ m_navMesh(NULL), m_navMeshQuery(NULL), m_polyLength(0), m_pathPolyRefs(NULL), | |
m_pointPathPointer(0), m_sourceObject(from), m_type(PATHFIND_BLANK) | |
{ | |
- setEndPosition(x, y, z); | |
+ setEndPosition(PathNode(x, y, z)); | |
if(m_navMesh = m_sourceObject->GetMap()->GetNavMesh()) | |
{ | |
@@ -38,16 +37,13 @@ PathInfo::PathInfo(const WorldObject* from, const float x, const float y, const | |
BuildFreshPath(); | |
} | |
else | |
- { | |
- setNextPosition(x, y, z); | |
- m_type = PATHFIND_SHORTCUT; | |
- } | |
+ shortcut(); | |
} | |
PathInfo::~PathInfo() | |
{ | |
- delete [] m_pathPolyRefs; | |
- delete [] m_pathPoints; | |
+ if(m_pathPolyRefs) | |
+ delete [] m_pathPolyRefs; | |
if(m_navMesh && m_navMeshQuery) | |
dtFreeNavMeshQuery(m_navMeshQuery); | |
@@ -55,7 +51,7 @@ PathInfo::~PathInfo() | |
dtPolyRef PathInfo::getPathPolyByPosition(float x, float y, float z) | |
{ | |
- if(!m_navMesh) | |
+ if(!m_navMesh || !m_pathPolyRefs) | |
return 0; // navmesh isn't loaded | |
float distance; // not used | |
@@ -121,7 +117,7 @@ void PathInfo::BuildFreshPath() | |
float x, y, z; | |
// set start and a default next position | |
m_sourceObject->GetPosition(x, y, z); | |
- setStartPosition(x, y, z); | |
+ setStartPosition(PathNode(x, y, z)); | |
float extents[VERTEX_SIZE] = {2.0f, 4.0f, 2.0f}; // defines bounds of box for search area | |
dtQueryFilter filter = dtQueryFilter(); // use general filter so we know if we are near navmesh | |
@@ -158,17 +154,13 @@ void PathInfo::BuildPath(dtPolyRef startPoly, float* startPos, dtPolyRef endPoly | |
if(startPoly == endPoly) | |
{ | |
//printf("++ PathInfo::BuildPath :: (startPoly == endPoly) %u\n",m_sourceObject->GetGUID()); | |
+ shortcut(); | |
- // PATHFIND TODO: prevent walking/swimming mobs from flying into the air | |
- clear(); | |
m_pathPolyRefs = new dtPolyRef[1]; | |
m_pathPolyRefs[0] = startPoly; | |
m_polyLength = 1; | |
- float x,y,z; | |
- getEndPosition(x, y, z); | |
- setNextPosition(x, y, z); | |
- m_type = PathType(PATHFIND_NORMAL); | |
+ m_type = PATHFIND_NORMAL; | |
return; | |
} | |
@@ -312,20 +304,17 @@ void PathInfo::BuildPath(dtPolyRef startPoly, float* startPos, dtPolyRef endPoly | |
memcpy(m_pathPolyRefs, pathPolys, m_polyLength*sizeof(dtPolyRef)); | |
} | |
- if(m_polyLength >= MAX_PATH_LENGTH) | |
- m_type = PathType(m_type | PATHFIND_INCOMPLETE); | |
- | |
// generate the point-path out of our up-to-date poly-path | |
updateNextPosition(); | |
} | |
void PathInfo::Update(const float destX, const float destY, const float destZ) | |
{ | |
- // make sure navMesh works - we can run on map w/o mmap | |
+ // make sure navMesh works - we can run on map w/o mmap | |
// can we switch map/get different mesh? | |
if(!m_navMesh || m_navMesh != m_sourceObject->GetMap()->GetNavMesh()) | |
{ | |
- setEndPosition(destX, destY, destZ); | |
+ setEndPosition(PathNode(destX, destY, destZ)); | |
shortcut(); | |
return; | |
} | |
@@ -341,15 +330,16 @@ void PathInfo::Update(const float destX, const float destY, const float destZ) | |
float x, y, z; | |
m_sourceObject->GetPosition(x, y, z); | |
- setStartPosition(x, y, z); | |
+ setStartPosition(PathNode(x, y, z)); | |
// check if destination moved - if not we can optimize something here | |
// we are following old, precalculated path? | |
float dist = m_sourceObject->GetObjectBoundingRadius(); | |
- float oldEnd_x, oldEnd_y, oldEnd_z; | |
- getEndPosition(oldEnd_x, oldEnd_y, oldEnd_z); | |
- if(isSamePoint(dist, oldEnd_x, oldEnd_y, oldEnd_z, destX, destY, destZ) | |
- && m_pointLength > 2 && m_pointPathPointer < m_pointLength) | |
+ PathNode oldDest = getEndPosition(); | |
+ PathNode newDest = PathNode(destX, destY, destZ); | |
+ | |
+ if(inRange(oldDest, newDest, dist, 2*dist) | |
+ && m_pathPoints.size() > 2 && m_pointPathPointer+1 < m_pathPoints.size()) | |
{ | |
// our target is not moving - we just coming closer | |
if(!m_pointPathPointer) | |
@@ -364,7 +354,7 @@ void PathInfo::Update(const float destX, const float destY, const float destZ) | |
else | |
{ | |
m_pointPathPointer = 0; | |
- setEndPosition(destX, destY, destZ); | |
+ setEndPosition(newDest); | |
} | |
if(!m_pointPathPointer) | |
@@ -404,9 +394,7 @@ void PathInfo::updateNextPosition() | |
if(m_pointPathPointer) | |
{ | |
//printf("++ PathInfo::updateNextPosition :: precalculated path %u\n",m_sourceObject->GetGUID()); | |
- setNextPosition(m_pathPoints[m_pointPathPointer*VERTEX_SIZE+2], | |
- m_pathPoints[m_pointPathPointer*VERTEX_SIZE], | |
- m_pathPoints[m_pointPathPointer*VERTEX_SIZE+1]); | |
+ setNextPosition(m_pathPoints[m_pointPathPointer]); | |
return; | |
} | |
@@ -417,7 +405,9 @@ void PathInfo::updateNextPosition() | |
getEndPosition(x, y, z); | |
float endPos[VERTEX_SIZE] = {y, z, x}; | |
- float* pathPoints = new float[MAX_PATH_LENGTH*VERTEX_SIZE]; | |
+#ifndef _USE_SMOOTH_PATH_ | |
+ | |
+ float pathPoints[MAX_PATH_LENGTH*VERTEX_SIZE]; | |
uint32 pointCount = m_navMeshQuery->findStraightPath( | |
startPos, // start position | |
endPos, // end position | |
@@ -428,50 +418,64 @@ void PathInfo::updateNextPosition() | |
0, // [out] shortened path PATHFIND TODO: see if this is usable (IE, doesn't leave gaps in path) | |
MAX_PATH_LENGTH); // maximum number of points/polygons to use | |
- // TODO: imitate PATHFIND_ITER code from RecastDemo so that terrain following is smoother | |
- // example in NavMeshTesterTool::recalc() | |
- // but it is pretty costy | |
+#else | |
- if(pointCount == 0) | |
- { | |
- delete [] pathPoints; | |
+ float pathPoints[MAX_SMOOTH_PATH_LENGTH*VERTEX_SIZE]; | |
+ uint32 pointCount = findSmoothPath( | |
+ startPos, // start position | |
+ endPos, // end position | |
+ m_pathPolyRefs, // current path | |
+ m_polyLength, // lenth of current path | |
+ pathPoints, // [out] path corner points | |
+ MAX_SMOOTH_PATH_LENGTH); // maximum number of points/polygons to use | |
+ | |
+#endif | |
+ if(pointCount < 2) | |
+ { | |
// only happens if pass bad data to findStraightPath or navmesh is broken | |
- sLog.outError("%u's UpdateNextPosition failed: 0 length path", m_sourceObject->GetGUID()); | |
+ sLog.outError("%u's UpdateNextPosition failed: %u length path", m_sourceObject->GetGUID(), pointCount); | |
shortcut(); | |
return; | |
} | |
- // first point is always our current location - we need the next one | |
- setNextPosition(pathPoints[VERTEX_SIZE+2], pathPoints[VERTEX_SIZE], pathPoints[VERTEX_SIZE+1]); | |
+ m_pathPoints.clear(); | |
+ m_pathPoints.resize(pointCount); | |
+ for(uint32 i = 0; i < pointCount; ++i) | |
+ m_pathPoints.set(i, PathNode(pathPoints[i*VERTEX_SIZE+2], pathPoints[i*VERTEX_SIZE], pathPoints[i*VERTEX_SIZE+1])); | |
- delete [] m_pathPoints; | |
- m_pathPoints = pathPoints; | |
- m_pointLength = pointCount; | |
m_pointPathPointer = 0; | |
- m_type = PathType(m_type | PATHFIND_NORMAL); | |
- | |
- // place we want to go, there is likely no complete path | |
- // findStraightPath() will always return the closest location | |
- // to our destination, if not rechable | |
- // we used shortcut() if no path at all found. | |
- endPos[0] = m_pathPoints[(m_pointLength-1)*VERTEX_SIZE+2]; | |
- endPos[1] = m_pathPoints[(m_pointLength-1)*VERTEX_SIZE]; | |
- endPos[2] = m_pathPoints[(m_pointLength-1)*VERTEX_SIZE+1]; | |
+ // first point is always our current location - we need the next one | |
+ setNextPosition(m_pathPoints[1]); | |
+ // if our destination, if not rechable due to lenght limit or something else | |
+ // last point in outpur array is the closest we can get | |
float dist = 2*m_sourceObject->GetObjectBoundingRadius(); | |
- if(!isSamePoint(dist, endPos, m_endPosition)) | |
- m_type = PathType(m_type | PATHFIND_INCOMPLETE); | |
+ if(inRange(m_pathPoints[pointCount-1], m_endPosition, dist, 2*dist)) | |
+ m_type = PATHFIND_NORMAL; | |
+ else if(pointCount < MAX_SMOOTH_PATH_LENGTH) | |
+ m_type = PATHFIND_NOPATH; | |
+ else | |
+ m_type = PATHFIND_INCOMPLETE; | |
} | |
void PathInfo::shortcut() | |
{ | |
clear(); | |
+ // make two point path, our curr pos is the start, and dest is the end | |
+ m_pathPoints.resize(2); | |
+ | |
float x, y, z; | |
+ // set start and a default next position | |
+ m_sourceObject->GetPosition(x, y, z); | |
+ m_pathPoints.set(0, PathNode(x,y,z)); | |
+ | |
getEndPosition(x, y, z); | |
- setNextPosition(x, y, z); | |
+ m_pathPoints.set(1, PathNode(x,y,z)); | |
+ | |
+ setNextPosition(m_pathPoints[1]); | |
m_type = PATHFIND_SHORTCUT; | |
} | |
@@ -526,11 +530,7 @@ bool PathInfo::canSwim() | |
NavTerrain PathInfo::getNavTerrain(float x, float y, float z) | |
{ | |
GridMapLiquidData data; | |
- m_sourceObject->GetMap()->getLiquidStatus(x, | |
- y, | |
- z, | |
- MAP_ALL_LIQUIDS, | |
- &data); | |
+ m_sourceObject->GetMap()->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &data); | |
switch(data.type) | |
{ | |
@@ -548,7 +548,218 @@ NavTerrain PathInfo::getNavTerrain(float x, float y, float z) | |
bool PathInfo::noPath() | |
{ | |
- // basically: | |
- // endOfPath != destination && completePath | |
return (m_type & PATHFIND_NOPATH) && !(m_type & PATHFIND_INCOMPLETE); | |
} | |
+ | |
+uint32 PathInfo::fixupCorridor(dtPolyRef* path, const uint32 npath, const uint32 maxPath, | |
+ const dtPolyRef* visited, const uint32 nvisited) | |
+{ | |
+ int32 furthestPath = -1; | |
+ int32 furthestVisited = -1; | |
+ | |
+ // Find furthest common polygon. | |
+ for (int32 i = npath-1; i >= 0; --i) | |
+ { | |
+ bool found = false; | |
+ for (int32 j = nvisited-1; j >= 0; --j) | |
+ { | |
+ if (path[i] == visited[j]) | |
+ { | |
+ furthestPath = i; | |
+ furthestVisited = j; | |
+ found = true; | |
+ } | |
+ } | |
+ if (found) | |
+ break; | |
+ } | |
+ | |
+ // If no intersection found just return current path. | |
+ if (furthestPath == -1 || furthestVisited == -1) | |
+ return npath; | |
+ | |
+ // Concatenate paths. | |
+ | |
+ // Adjust beginning of the buffer to include the visited. | |
+ uint32 req = nvisited - furthestVisited; | |
+ uint32 orig = uint32(furthestPath+1) < npath ? furthestPath+1 : npath; | |
+ uint32 size = npath-orig > 0 ? npath-orig : 0; | |
+ if (req+size > maxPath) | |
+ size = maxPath-req; | |
+ | |
+ if (size) | |
+ memmove(path+req, path+orig, size*sizeof(dtPolyRef)); | |
+ | |
+ // Store visited | |
+ for (uint32 i = 0; i < req; ++i) | |
+ path[i] = visited[(nvisited-1)-i]; | |
+ | |
+ return req+size; | |
+} | |
+ | |
+bool PathInfo::getSteerTarget(const float* startPos, const float* endPos, | |
+ const float minTargetDist, const dtPolyRef* path, const uint32 pathSize, | |
+ float* steerPos, unsigned char& steerPosFlag, dtPolyRef& steerPosRef, | |
+ float* outPoints, uint32* outPointCount) | |
+{ | |
+ // Find steer target. | |
+ static const uint32 MAX_STEER_POINTS = 3; | |
+ float steerPath[MAX_STEER_POINTS*VERTEX_SIZE]; | |
+ unsigned char steerPathFlags[MAX_STEER_POINTS]; | |
+ dtPolyRef steerPathPolys[MAX_STEER_POINTS]; | |
+ uint32 nsteerPath = m_navMeshQuery->findStraightPath(startPos, endPos, path, pathSize, | |
+ steerPath, steerPathFlags, steerPathPolys, MAX_STEER_POINTS); | |
+ if (!nsteerPath) | |
+ return false; | |
+ | |
+ if (outPoints && outPointCount) | |
+ { | |
+ *outPointCount = nsteerPath; | |
+ for (uint32 i = 0; i < nsteerPath; ++i) | |
+ dtVcopy(&outPoints[i*VERTEX_SIZE], &steerPath[i*VERTEX_SIZE]); | |
+ } | |
+ | |
+ // Find vertex far enough to steer to. | |
+ uint32 ns = 0; | |
+ while (ns < nsteerPath) | |
+ { | |
+ // Stop at Off-Mesh link or when point is further than slop away. | |
+ if ((steerPathFlags[ns] & DT_STRAIGHTPATH_OFFMESH_CONNECTION) || | |
+ !inRangeYZX(&steerPath[ns*VERTEX_SIZE], startPos, minTargetDist, 1000.0f)) | |
+ break; | |
+ ns++; | |
+ } | |
+ // Failed to find good point to steer to. | |
+ if (ns >= nsteerPath) | |
+ return false; | |
+ | |
+ dtVcopy(steerPos, &steerPath[ns*VERTEX_SIZE]); | |
+ steerPos[1] = startPos[1]; | |
+ steerPosFlag = steerPathFlags[ns]; | |
+ steerPosRef = steerPathPolys[ns]; | |
+ | |
+ return true; | |
+} | |
+ | |
+uint32 PathInfo::findSmoothPath(const float* startPos, const float* endPos, | |
+ const dtPolyRef* path, const uint32 pathSize, | |
+ float* smoothPath, const uint32 maxSmoothPathSize) | |
+{ | |
+ uint32 m_nsmoothPath = 0; | |
+ | |
+ dtPolyRef polys[MAX_PATH_LENGTH]; | |
+ memcpy(polys, path, sizeof(dtPolyRef)*pathSize); | |
+ uint32 npolys = pathSize; | |
+ | |
+ float iterPos[VERTEX_SIZE], targetPos[VERTEX_SIZE]; | |
+ m_navMeshQuery->closestPointOnPolyBoundary(polys[0], startPos, iterPos); | |
+ m_navMeshQuery->closestPointOnPolyBoundary(polys[npolys-1], endPos, targetPos); | |
+ | |
+ dtVcopy(&smoothPath[m_nsmoothPath*VERTEX_SIZE], iterPos); | |
+ m_nsmoothPath++; | |
+ | |
+ // Move towards target a small advancement at a time until target reached or | |
+ // when ran out of memory to store the path. | |
+ while (npolys && m_nsmoothPath < maxSmoothPathSize) | |
+ { | |
+ // Find location to steer towards. | |
+ float steerPos[VERTEX_SIZE]; | |
+ unsigned char steerPosFlag; | |
+ dtPolyRef steerPosRef; | |
+ | |
+ if (!getSteerTarget(iterPos, targetPos, SMOOTH_PATH_SLOP, polys, npolys, steerPos, steerPosFlag, steerPosRef)) | |
+ break; | |
+ | |
+ bool endOfPath = (steerPosFlag & DT_STRAIGHTPATH_END); | |
+ bool offMeshConnection = (steerPosFlag & DT_STRAIGHTPATH_OFFMESH_CONNECTION); | |
+ | |
+ // Find movement delta. | |
+ float delta[VERTEX_SIZE], len = 0.0f; | |
+ dtVsub(delta, steerPos, iterPos); | |
+ len = dtSqrt(dtVdot(delta,delta)); | |
+ // If the steer target is end of path or off-mesh link, do not move past the location. | |
+ if ((endOfPath || offMeshConnection) && len < SMOOTH_PATH_STEP_SIZE) | |
+ len = 1.0f; | |
+ else | |
+ len = SMOOTH_PATH_STEP_SIZE / len; | |
+ | |
+ float moveTgt[VERTEX_SIZE]; | |
+ dtVmad(moveTgt, iterPos, delta, len); | |
+ | |
+ // Move | |
+ float result[VERTEX_SIZE]; | |
+ dtPolyRef visited[16]; | |
+ dtQueryFilter filter = createFilter(); | |
+ | |
+ uint32 nvisited = m_navMeshQuery->moveAlongSurface(polys[0], iterPos, moveTgt, &filter, result, visited, 16); | |
+ | |
+ npolys = fixupCorridor(polys, npolys, MAX_PATH_LENGTH, visited, nvisited); | |
+ float h = 0; | |
+ m_navMeshQuery->getPolyHeight(polys[0], result, &h); | |
+ result[1] = h; | |
+ dtVcopy(iterPos, result); | |
+ | |
+ // Handle end of path and off-mesh links when close enough. | |
+ if (endOfPath && inRangeYZX(iterPos, steerPos, SMOOTH_PATH_SLOP, 2.0f)) | |
+ { | |
+ // Reached end of path. | |
+ dtVcopy(iterPos, targetPos); | |
+ if (m_nsmoothPath < MAX_SMOOTH_PATH_LENGTH) | |
+ { | |
+ dtVcopy(&smoothPath[m_nsmoothPath*VERTEX_SIZE], iterPos); | |
+ m_nsmoothPath++; | |
+ } | |
+ break; | |
+ } | |
+ else if (offMeshConnection && inRangeYZX(iterPos, steerPos, SMOOTH_PATH_SLOP, 2.0f)) | |
+ { | |
+ // Reached off-mesh connection. | |
+ float startPos[VERTEX_SIZE], endPos[VERTEX_SIZE]; | |
+ | |
+ // Advance the path up to and over the off-mesh connection. | |
+ dtPolyRef prevRef = 0, polyRef = polys[0]; | |
+ uint32 npos = 0; | |
+ while (npos < npolys && polyRef != steerPosRef) | |
+ { | |
+ prevRef = polyRef; | |
+ polyRef = polys[npos]; | |
+ npos++; | |
+ } | |
+ | |
+ for (uint32 i = npos; i < npolys; ++i) | |
+ polys[i-npos] = polys[i]; | |
+ | |
+ npolys -= npos; | |
+ | |
+ // Handle the connection. | |
+ if (m_navMesh->getOffMeshConnectionPolyEndPoints(prevRef, polyRef, startPos, endPos)) | |
+ { | |
+ if (m_nsmoothPath < maxSmoothPathSize) | |
+ { | |
+ dtVcopy(&smoothPath[m_nsmoothPath*VERTEX_SIZE], startPos); | |
+ m_nsmoothPath++; | |
+ // Hack to make the dotted path not visible during off-mesh connection. | |
+ if (m_nsmoothPath & 1) | |
+ { | |
+ dtVcopy(&smoothPath[m_nsmoothPath*VERTEX_SIZE], startPos); | |
+ m_nsmoothPath++; | |
+ } | |
+ } | |
+ // Move position at the other side of the off-mesh link. | |
+ dtVcopy(iterPos, endPos); | |
+ float h; | |
+ m_navMeshQuery->getPolyHeight(polys[0], iterPos, &h); | |
+ iterPos[1] = h; | |
+ } | |
+ } | |
+ | |
+ // Store results. | |
+ if (m_nsmoothPath < maxSmoothPathSize) | |
+ { | |
+ dtVcopy(&smoothPath[m_nsmoothPath*VERTEX_SIZE], iterPos); | |
+ m_nsmoothPath++; | |
+ } | |
+ } | |
+ | |
+ return m_nsmoothPath; | |
+} | |
diff --git a/src/game/PathFinder.h b/src/game/PathFinder.h | |
index 8340cd5..edec62b 100644 | |
--- a/src/game/PathFinder.h | |
+++ b/src/game/PathFinder.h | |
@@ -28,6 +28,11 @@ class WorldObject; | |
#define MAX_PATH_LENGTH 256 | |
#define VERTEX_SIZE 3 | |
+#define _USE_SMOOTH_PATH_ | |
+#define MAX_SMOOTH_PATH_LENGTH 2048 | |
+#define SMOOTH_PATH_STEP_SIZE 8.0f | |
+#define SMOOTH_PATH_SLOP 0.5f | |
+ | |
// see contrib/mmap/src/TileBuilder.h | |
enum NavTerrain | |
{ | |
@@ -49,17 +54,31 @@ enum PathType | |
PATHFIND_NOPATH = 0x0010 // could not find a path | |
}; | |
+struct PathNode | |
+{ | |
+ PathNode():x(0.0f), y(0.0f), z(0.0f){} | |
+ PathNode(float _x, float _y, float _z) : x(_x), y(_y), z(_z){} | |
+ float x,y,z; | |
+}; | |
+ | |
+typedef Path<PathNode> PointPath; | |
+ | |
class PathInfo | |
{ | |
public: | |
PathInfo(const WorldObject* from, const float x, const float y, const float z); | |
~PathInfo(); | |
- inline void getStartPosition(float &x, float &y, float &z) { x = m_startPosition[0]; y = m_startPosition[1]; z = m_startPosition[2]; } | |
- inline void getNextPosition(float &x, float &y, float &z) { x = m_nextPosition[0]; y = m_nextPosition[1]; z = m_nextPosition[2]; } | |
- inline void getEndPosition(float &x, float &y, float &z) { x = m_endPosition[0]; y = m_endPosition[1]; z = m_endPosition[2]; } | |
+ inline void getStartPosition(float &x, float &y, float &z) { x = m_startPosition.x; y = m_startPosition.y; z = m_startPosition.z; } | |
+ inline void getNextPosition(float &x, float &y, float &z) { x = m_nextPosition.x; y = m_nextPosition.y; z = m_nextPosition.z; } | |
+ inline void getEndPosition(float &x, float &y, float &z) { x = m_endPosition.x; y = m_endPosition.y; z = m_endPosition.z; } | |
+ | |
+ inline PathNode getStartPosition() { return m_startPosition; } | |
+ inline PathNode getNextPosition() { return m_nextPosition; } | |
+ inline PathNode getEndPosition() { return m_endPosition; } | |
- inline uint32 getFullPath(float **pathPoints) { *pathPoints = m_pathPoints; return m_pointLength; }; | |
+ inline uint32 getPathPointer() { return (m_pointPathPointer ? m_pointPathPointer-1 : 0);} | |
+ inline PointPath& getFullPath() { return m_pathPoints; } | |
void Update(const float x, const float y, const float z); | |
bool noPath(); | |
@@ -75,33 +94,29 @@ class PathInfo | |
dtPolyRef * m_pathPolyRefs; // array of detour polygon references | |
uint32 m_polyLength; // number of polygons in the path | |
- float * m_pathPoints; // array of float[3] for (x, y, z) coords | |
- uint32 m_pointLength; // number of points in the path | |
+ PointPath m_pathPoints; // out actual (x,y,z) path to the target | |
uint32 m_pointPathPointer; // points to current triple in m_pathPoints - used when dest do not change | |
- float m_startPosition[VERTEX_SIZE]; // {x, y, z} of current location | |
- float m_nextPosition[VERTEX_SIZE]; // {x, y, z} of next location on the path | |
- float m_endPosition[VERTEX_SIZE]; // {x, y, z} of the destination | |
+ PathNode m_startPosition; // {x, y, z} of current location | |
+ PathNode m_nextPosition; // {x, y, z} of next location on the path | |
+ PathNode m_endPosition; // {x, y, z} of the destination | |
const WorldObject * m_sourceObject; // the object that is moving (safe pointer because PathInfo is only accessed from the mover?) | |
dtNavMesh * m_navMesh; // the nav mesh | |
dtNavMeshQuery* m_navMeshQuery; // the nav mesh query used to find the path | |
PathType m_type; // tells what kind of path this is | |
- inline void setNextPosition(float x, float y, float z) { m_nextPosition[0] = x; m_nextPosition[1] = y; m_nextPosition[2] = z; } | |
- inline void setStartPosition(float x, float y, float z) { m_startPosition[0] = x; m_startPosition[1] = y; m_startPosition[2] = z; } | |
- inline void setEndPosition(float x, float y, float z) { m_endPosition[0] = x; m_endPosition[1] = y; m_endPosition[2] = z; } | |
+ inline void setNextPosition(PathNode point) { m_nextPosition = point; } | |
+ inline void setStartPosition(PathNode point) { m_startPosition = point; } | |
+ inline void setEndPosition(PathNode point) { m_endPosition = point; } | |
inline void clear() | |
{ | |
delete [] m_pathPolyRefs; | |
m_pathPolyRefs = NULL; | |
- | |
- delete [] m_pathPoints; | |
- m_pathPoints = NULL; | |
- | |
m_polyLength = 0; | |
- m_pointLength = 0; | |
+ | |
+ m_pathPoints.clear(); | |
m_pointPathPointer = 0; | |
} | |
@@ -120,22 +135,34 @@ class PathInfo | |
bool canFly(); | |
bool canSwim(); | |
NavTerrain getNavTerrain(float x, float y, float z); | |
+ | |
+ | |
+ uint32 fixupCorridor(dtPolyRef* path, const uint32 npath, const uint32 maxPath, | |
+ const dtPolyRef* visited, const uint32 nvisited); | |
+ bool getSteerTarget(const float* startPos, const float* endPos, const float minTargetDist, | |
+ const dtPolyRef* path, const uint32 pathSize, float* steerPos, | |
+ unsigned char& steerPosFlag, dtPolyRef& steerPosRef, | |
+ float* outPoints = 0, uint32* outPointCount = 0); | |
+ uint32 findSmoothPath(const float* startPos, const float* endPos, | |
+ const dtPolyRef* path, const uint32 pathSize, | |
+ float* smoothPath, const uint32 maxSmoothPathSize); | |
}; | |
-// using == for two float numbers wont do us much good, use diff | |
-inline bool isSamePoint(const float diff, const float* point1, const float* point2) | |
+inline bool inRangeYZX(const float* v1, const float* v2, const float r, const float h) | |
{ | |
- return (abs(point1[0] - point2[0]) <= diff && | |
- abs(point1[1] - point2[1]) <= diff && | |
- abs(point1[2] - point2[2]) <= diff); | |
+ const float dx = v2[0] - v1[0]; | |
+ const float dy = v2[1] - v1[1]; | |
+ const float dz = v2[2] - v1[2]; | |
+ return (dx*dx + dz*dz) < r*r && fabsf(dy) < h; | |
} | |
-inline bool isSamePoint(const float diff, const float x1, const float y1, const float z1, | |
- const float x2, const float y2, const float z2) | |
+inline bool inRange(const PathNode p1, const PathNode p2, | |
+ const float r, const float h) | |
{ | |
- return (abs(x1 - x2) <= diff && | |
- abs(y1 - y2) <= diff && | |
- abs(z1 - z2) <= diff); | |
+ const float dx = p2.x - p1.x; | |
+ const float dy = p2.y - p1.y; | |
+ const float dz = p2.z - p1.z; | |
+ return (dx*dx + dy*dy) < r*r && fabsf(dz) < h; | |
} | |
#endif | |
diff --git a/src/game/TargetedMovementGenerator.cpp b/src/game/TargetedMovementGenerator.cpp | |
index ebf3878..f7bb443 100644 | |
--- a/src/game/TargetedMovementGenerator.cpp | |
+++ b/src/game/TargetedMovementGenerator.cpp | |
@@ -79,18 +79,34 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T &owner) | |
// and then has the wrong z to use when creature try follow unit in the air. | |
if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly()) | |
z = i_target->GetPositionZ(); | |
- | |
+ | |
if(!i_path) | |
i_path = new PathInfo(&owner, x, y, z); | |
else | |
i_path->Update(x, y, z); | |
- // we always have a path to the target - shortcut in worst case | |
- // even is this map don't have mmaps at all | |
i_path->getNextPosition(x, y, z); | |
+ | |
+ PointPath myPath = i_path->getFullPath(); | |
+ uint32 pathStartPointer = i_path->getPathPointer(); | |
+ uint32 actualPathLength = myPath.size() - pathStartPointer; | |
+ if(pathPointsSent > 0) | |
+ --pathPointsSent; | |
+ | |
+ bool sendPath = (actualPathLength > 5 && !pathPointsSent); | |
Traveller<T> traveller(owner); | |
- i_destinationHolder.SetDestination(traveller, x, y, z); | |
+ i_destinationHolder.SetDestination(traveller, x, y, z, !sendPath); | |
+ | |
+ if(sendPath) | |
+ { | |
+ uint32 pathEndPointer = pathStartPointer + uint32(actualPathLength*0.6f + 0.6f); | |
+ float speed = traveller.Speed()*0.001f; // in ms | |
+ uint32 traveltime = uint32(myPath.GetTotalLength(pathStartPointer, pathEndPointer)/speed); | |
+ SplineFlags flags = (owner.GetTypeId() == TYPEID_UNIT) ? ((Creature*)&owner)->GetSplineFlags() : SPLINEFLAG_WALKMODE; | |
+ owner.SendMonsterMoveByPath(myPath, pathStartPointer, pathEndPointer, flags, traveltime); | |
+ pathPointsSent = pathEndPointer - pathStartPointer; | |
+ } | |
D::_addUnitStateMove(owner); | |
if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly()) | |
@@ -174,25 +190,28 @@ bool TargetedMovementGeneratorMedium<T,D>::Update(T &owner, const uint32 & time_ | |
// put targeted movement generators on a higher priority | |
if (owner.GetObjectBoundingRadius()) | |
- i_destinationHolder.ResetUpdate(100); | |
+ i_destinationHolder.ResetUpdate(50); | |
float dist = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius() + sWorld.getConfig(CONFIG_FLOAT_RATE_TARGET_POS_RECALCULATION_RANGE); | |
//More distance let have better performance, less distance let have more sensitive reaction at target move. | |
bool targetMoved = false, needNewDest = false; | |
- float end_x, end_y, end_z; | |
- float next_x = i_target->GetPositionX(); | |
- float next_y = i_target->GetPositionY(); | |
- float next_z = i_target->GetPositionZ(); | |
+ PathNode next_point(i_target->GetPositionX(), i_target->GetPositionY(), i_target->GetPositionZ()); | |
if(i_path) | |
{ | |
- i_path->getNextPosition(next_x, next_y, next_z); | |
- i_path->getEndPosition(end_x, end_y, end_z); | |
- | |
- needNewDest = i_destinationHolder.HasArrived() && !isSamePoint(dist, next_x, next_y, next_z, end_x, end_y, end_z); | |
- targetMoved = i_target->GetDistanceSqr(end_x, end_y, end_z) >= dist*dist; | |
+ PathNode end_point = i_path->getEndPosition(); | |
+ next_point = i_path->getNextPosition(); | |
+ | |
+ needNewDest = i_destinationHolder.HasArrived() && !inRange(next_point, end_point, dist, 2*dist); | |
+ | |
+ // current code in GetClosePoint() will always return ground level for non-flying creatures | |
+ // if the the target is flying, targetMoved will always be set due to 3d out of range check | |
+ if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly()) | |
+ targetMoved = i_target->GetDistanceSqr(end_point.x, end_point.y, end_point.z) >= dist*dist; | |
+ else | |
+ targetMoved = i_target->GetDistance2d(end_point.x, end_point.y) >= dist; | |
} | |
if (!i_path || targetMoved || needNewDest) | |
@@ -202,22 +221,22 @@ bool TargetedMovementGeneratorMedium<T,D>::Update(T &owner, const uint32 & time_ | |
if(i_path) | |
{ | |
- i_path->getNextPosition(next_x, next_y, next_z); | |
+ next_point = i_path->getNextPosition(); | |
// Set new Angle For Map:: | |
- owner.SetOrientation(owner.GetAngle(next_x, next_y)); | |
+ owner.SetOrientation(owner.GetAngle(next_point.x, next_point.y)); | |
} | |
} | |
// Update the Angle of the target only for Map::, no need to send packet for player | |
- else if (!i_angle && !owner.HasInArc(0.01f, next_x, next_y)) | |
- owner.SetOrientation(owner.GetAngle(next_x, next_y)); | |
+ else if (!i_angle && !owner.HasInArc(0.01f, next_point.x, next_point.y)) | |
+ owner.SetOrientation(owner.GetAngle(next_point.x, next_point.y)); | |
if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || i_recalculateTravel) | |
{ | |
i_recalculateTravel = false; | |
//Angle update will take place into owner.StopMoving() | |
- owner.SetOrientation(owner.GetAngle(next_x, next_y)); | |
+ owner.SetOrientation(owner.GetAngle(next_point.x, next_point.y)); | |
owner.StopMoving(); | |
static_cast<D*>(this)->_reachTarget(owner); | |
diff --git a/src/game/TargetedMovementGenerator.h b/src/game/TargetedMovementGenerator.h | |
index 8a8d918..d0423f8 100644 | |
--- a/src/game/TargetedMovementGenerator.h | |
+++ b/src/game/TargetedMovementGenerator.h | |
@@ -40,11 +40,11 @@ class MANGOS_DLL_SPEC TargetedMovementGeneratorMedium | |
{ | |
protected: | |
TargetedMovementGeneratorMedium() | |
- : TargetedMovementGeneratorBase(), i_offset(0), i_angle(0), i_recalculateTravel(false), i_path(NULL) {} | |
+ : TargetedMovementGeneratorBase(), i_offset(0), i_angle(0), i_recalculateTravel(false), i_path(NULL), pathPointsSent(0) {} | |
TargetedMovementGeneratorMedium(Unit &target) | |
- : TargetedMovementGeneratorBase(target), i_offset(0), i_angle(0), i_recalculateTravel(false), i_path(NULL) {} | |
+ : TargetedMovementGeneratorBase(target), i_offset(0), i_angle(0), i_recalculateTravel(false), i_path(NULL), pathPointsSent(0) {} | |
TargetedMovementGeneratorMedium(Unit &target, float offset, float angle) | |
- : TargetedMovementGeneratorBase(target), i_offset(offset), i_angle(angle), i_recalculateTravel(false), i_path(NULL) {} | |
+ : TargetedMovementGeneratorBase(target), i_offset(offset), i_angle(angle), i_recalculateTravel(false), i_path(NULL), pathPointsSent(0) {} | |
~TargetedMovementGeneratorMedium() { delete i_path; } | |
public: | |
@@ -71,6 +71,7 @@ class MANGOS_DLL_SPEC TargetedMovementGeneratorMedium | |
bool i_recalculateTravel; | |
PathInfo* i_path; | |
+ uint32 pathPointsSent; | |
}; | |
template<class T> | |
diff --git a/src/game/Unit.h b/src/game/Unit.h | |
index 4fda849..30f3200 100644 | |
--- a/src/game/Unit.h | |
+++ b/src/game/Unit.h | |
@@ -1429,7 +1429,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject | |
void SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime = 0, Player* player = NULL); | |
template<typename PathElem, typename PathNode> | |
- void SendMonsterMoveByPath(Path<PathElem,PathNode> const& path, uint32 start, uint32 end, SplineFlags flags); | |
+ void SendMonsterMoveByPath(Path<PathElem,PathNode> const& path, uint32 start, uint32 end, SplineFlags flags, uint32 traveltime); | |
void SendHighestThreatUpdate(HostileReference* pHostileReference); | |
void SendThreatClear(); | |
@@ -2029,11 +2029,20 @@ bool Unit::CheckAllControlledUnits(Func const& func, bool withTotems, bool withG | |
} | |
template<typename Elem, typename Node> | |
-inline void Unit::SendMonsterMoveByPath(Path<Elem,Node> const& path, uint32 start, uint32 end, SplineFlags flags) | |
+inline void Unit::SendMonsterMoveByPath(Path<Elem,Node> const& path, uint32 start, uint32 end, SplineFlags flags, uint32 traveltime) | |
{ | |
- uint32 traveltime = uint32(path.GetTotalLength(start, end) * 32); | |
- | |
uint32 pathSize = end - start; | |
+ if(!pathSize || !traveltime) | |
+ { | |
+ SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), SPLINETYPE_STOP, flags, 0); | |
+ return; | |
+ } | |
+ | |
+ if(pathSize < 3) | |
+ { | |
+ SendMonsterMove(path[pathSize-1].x, path[pathSize-1].y, path[pathSize-1].z, SPLINETYPE_NORMAL, flags, traveltime); | |
+ return; | |
+ } | |
WorldPacket data( SMSG_MONSTER_MOVE, (GetPackGUID().size()+1+4+4+4+4+1+4+4+4+pathSize*4*3) ); | |
data << GetPackGUID(); | |
@@ -2047,12 +2056,18 @@ inline void Unit::SendMonsterMoveByPath(Path<Elem,Node> const& path, uint32 star | |
data << uint32(traveltime); | |
data << uint32(pathSize); | |
- for(uint32 i = start; i < end; ++i) | |
- { | |
- data << float(path[i].x); | |
- data << float(path[i].y); | |
- data << float(path[i].z); | |
- } | |
+ // destination | |
+ data << path[end-1].x; | |
+ data << path[end-1].y; | |
+ data << path[end-1].z; | |
+ | |
+ // all other points are relative | |
+ float mid_X = (path[start].x + path[end-1].x ) * 0.5f; | |
+ float mid_Y = (path[start].y + path[end-1].y ) * 0.5f; | |
+ float mid_Z = (path[start].z + path[end-1].z ) * 0.5f; | |
+ | |
+ for(uint32 i = start; i < end-1; ++i) | |
+ data.appendPackXYZ(mid_X - path[i].x, mid_Y - path[i].y, mid_Z - path[i].z); | |
SendMessageToSet(&data, true); | |
} | |
diff --git a/src/game/WaypointMovementGenerator.cpp b/src/game/WaypointMovementGenerator.cpp | |
index 6a9aa05..ddbf992 100644 | |
--- a/src/game/WaypointMovementGenerator.cpp | |
+++ b/src/game/WaypointMovementGenerator.cpp | |
@@ -368,7 +368,10 @@ void FlightPathMovementGenerator::Reset(Player & 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); | |
- player.SendMonsterMoveByPath(GetPath(),GetCurrentNode(),GetPathAtMapEnd(), SplineFlags(SPLINEFLAG_WALKMODE|SPLINEFLAG_FLYING)); | |
+ TaxiPathNodeList path = GetPath(); | |
+ uint32 pathEndPoint = GetPathAtMapEnd(); | |
+ uint32 traveltime = uint32(32.0f*path.GetTotalLength(GetCurrentNode(),pathEndPoint)); | |
+ player.SendMonsterMoveByPath(path,GetCurrentNode(),pathEndPoint, SplineFlags(SPLINEFLAG_WALKMODE|SPLINEFLAG_FLYING), traveltime ); | |
} | |
bool FlightPathMovementGenerator::Update(Player &player, const uint32 &diff) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment