Index: src/game/RandomMovementGenerator.cpp===================================================================--- src/game/RandomMovementGenerator.cpp (revision 5788)+++ src/game/RandomMovementGenerator.cpp (working copy)@@ -21,67 +21,134 @@ #include "Opcodes.h" #include "RandomMovementGenerator.h" #include "DestinationHolderImp.h"+#include "VMapFactory.h"+#include "Map.h"-/*-Here interpolation is disabled by default due to it causing crashing-in some compile environments.-If your server can handle the small amount of lag this may cause-and you can build without experiencing a significant increase in crashes-then you may uncomment the following line to have correct random motion.-*/-// uncomment now for wide testing purpose-#define USE_INTERPOLATION+/**+ * Those define the size of the table of the ground/object heights around the spawn point,+ * bigger they are, more time is needed to calculate.+ */+#define ANGLE_PRECISSION 8+#define RANGE_PRECISSION 8 template<> void RandomMovementGenerator<Creature>::Initialize(Creature &creature) {- float x,y,z,z2, wander_distance;+ float x,y,z,wander_distance;+ float waypoints[(ANGLE_PRECISSION*RANGE_PRECISSION)+1][3];+ int waypoint_count = 1;+ creature.GetRespawnCoord(x, y, z,NULL,&wander_distance); uint32 mapid=creature.GetMapId();+ //float go_height[ANGLE_PRECISSION][RANGE_PRECISSION];+ Map const* map = MapManager::Instance().GetBaseMap(mapid);- // Initialization is done in bulk. Don’t use vamps for that (4. parameter = false). It is too costly when entering a new map grid- z2 = map->GetHeight(x,y,z, false); // use .map base surface height- if( fabs( z2 - z ) < 5 )- z = z2;- i_nextMove = 1;- i_waypoints[0][0] = x;- i_waypoints[0][1] = y;- i_waypoints[0][2] = z;- bool is_water_ok = creature.isCanSwimOrFly(); bool is_land_ok = creature.isCanWalkOrFly();- for(unsigned int idx=1; idx < MAX_RAND_WAYPOINTS+1; ++idx)- {- const float angle = 2*M_PI*rand_norm();- const float range = wander_distance*rand_norm();+ // We need vmap manager, to make creatures walk properly over the objects+ VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();+ float step = wander_distance/RANGE_PRECISSION;- i_waypoints[idx][0] = x+ range * cos(angle);- i_waypoints[idx][1] = y+ range * sin(angle);+ waypoints[0][0] = x;+ waypoints[0][1] = y;+ waypoints[0][2] = z;+ // Build the table of ground/object heights around spawn point+ for(int a = 0; a < ANGLE_PRECISSION; a++)+ {+ float angle = (2*M_PI/ANGLE_PRECISSION) * (float)a;+ // We use the previous Z value as a reference point to find out the map height+ float last_z = z;+ for(int r = 0; r < RANGE_PRECISSION; r++)+ {+ float range = step * ((float) r + 1.0);+ // Calculate the test around the spawn point+ float px = x + range * cos(angle);+ float py = y + range * sin(angle);+ MaNGOS::NormalizeMapCoord(px);+ MaNGOS::NormalizeMapCoord(py);+ float map_height = map->GetHeight(px, py , last_z, true);+ float obj_height;- // prevent invalid coordinates generation- MaNGOS::NormalizeMapCoord(i_waypoints[idx][0]);- MaNGOS::NormalizeMapCoord(i_waypoints[idx][1]);+ // Calculate the object height + vmgr->getObjectHitPos(mapid, + px, py, last_z + 2.0f,+ px, py, ((map_height!=VMAP_INVALID_HEIGHT_VALUE) ? (map_height) : (last_z-2.0f)),+ px, py, obj_height,+ 0.0f);- 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] = i_waypoints[idx-1][0];- i_waypoints[idx][1] = i_waypoints[idx-1][1];- i_waypoints[idx][2] = i_waypoints[idx-1][2];- continue;- }+ float pz = VMAP_INVALID_HEIGHT_VALUE;+ if(obj_height>last_z-2.0f)+ {+ // Z value in the map will be the bigger of the two: map or object+ pz = (((map_height) > (obj_height)) ? (map_height) : (obj_height)); + }- // Initialization is done in bulk. Don’t use vamps for that (4. parameter = false).- // It is too costly when entering a new map grid, use .map base surface height- z2 = map->GetHeight(i_waypoints[idx][0],i_waypoints[idx][1],z, false);- if( fabs( z2 - z ) < 5 )- z = z2;- i_waypoints[idx][2] = z;+ if(pz!=VMAP_INVALID_HEIGHT_VALUE)+ {+ bool is_water = map->IsInWater(px,py,pz); + // If it is bad place for the creature (water for non water creature, ect), just mark it as invalid.+ if(is_water && !is_water_ok || !is_water && !is_land_ok)+ { + pz = VMAP_INVALID_HEIGHT_VALUE;+ }++ // If point is not invalid, add to possible walk points+ if(pz!=VMAP_INVALID_HEIGHT_VALUE)+ {+ last_z = pz;+ waypoints[waypoint_count][0] = px;+ waypoints[waypoint_count][1] = py;+ waypoints[waypoint_count][2] = pz;+ waypoint_count++;+ }+ }+ }+ } ++ // Here, we calculate the walk points+ i_nextMove = 1;+ // First waypoint is always a spawn point, easy here.+ i_waypoints[0][0] = x;+ i_waypoints[0][1] = y;+ i_waypoints[0][2] = z; ++ for(unsigned int idx=1; idx < MAX_RAND_WAYPOINTS+1; ++idx)+ {+ bool goodPoint = false;+ int r = urand(0, waypoint_count-1);+ while(!goodPoint)+ {+ float dx = waypoints[r][0];+ float dy = waypoints[r][1];+ float dz = waypoints[r][2];+ // And check LOS+ vmgr->getObjectHitPos(mapid, + i_waypoints[0][0], i_waypoints[0][1], i_waypoints[0][2] + creature.GetObjectSize()/2.0f,+ dx, dy, dz + creature.GetObjectSize()/2.0f,+ i_waypoints[idx][0], i_waypoints[idx][1], i_waypoints[idx][2],+ creature.GetObjectSize()*2.0);+ i_waypoints[idx][2] = i_waypoints[idx][2]- creature.GetObjectSize()/2.0f;+ float x_dx = i_waypoints[idx][0] - i_waypoints[idx-1][0];+ float x_dy = i_waypoints[idx][1] - i_waypoints[idx-1][1];+ float x_dist = sqrt((x_dx*x_dx) + (x_dy*x_dy));+ float x_dz = i_waypoints[idx][2]-i_waypoints[idx-1][2];+ // Check if creature is not attempting to do >45 deg. walk+ if(abs(x_dz)<=x_dist)+ {+ goodPoint = true;+ } else {+ // If yes, try next point+ r = r + 1;+ if(r==waypoint_count)+ {+ r = 0;+ }+ }+ } } i_nextMoveTime.Reset(urand(0, 10000-1)); // TODO: check the lower bound (it is probably too small) creature.StopMoving();@@ -105,10 +172,8 @@ if(creature.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED)) return true; i_nextMoveTime.Update(diff);- #ifdef USE_INTERPOLATION CreatureTraveller traveller(creature); i_destinationHolder.UpdateTraveller(traveller, diff, false);- #endif if( i_nextMoveTime.Passed() ) { if( creature.IsStopped() )@@ -120,9 +185,7 @@ creature.addUnitState(UNIT_STAT_ROAMING); CreatureTraveller traveller(creature); i_destinationHolder.SetDestination(traveller, x, y, z);- #ifndef USE_INTERPOLATION traveller.Relocation(x,y,z);- #endif i_nextMoveTime.Reset( i_destinationHolder.GetTotalTravelTime() ); } else