Improve confused, random and fleeing movement generators.

Improve random movement generator. (c2607) @cyberium

Now creatures will have possibility to move up/down on swim/fly situation.
Random groundpoint  will have more accurracy and the creature have less chance to go throught object.

Note:
- Some creature may have invalid value like inhabit type and other flags in relation of movement in water. If its the case the result is not so good. DB must be corrected for these creatures.
- we have to find a way to handle correctly movement flags.

Make sure player stop moving when confused aura is removed. (c2629) @cyberium
modified version of @kvipka work

Improve confused movement generator. (c2630) @cyberium

Improve fleeing movement generator. (c2631) @cyberium
This commit is contained in:
cyberium 2015-03-25 11:34:39 +00:00 committed by Antz
parent fec7b5cd5f
commit c6210ba12c
6 changed files with 284 additions and 44 deletions

View File

@ -1 +1 @@
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

View File

@ -89,25 +89,21 @@ bool ConfusedMovementGenerator<T>::Update(T& unit, const uint32& diff)
// start moving
unit.addUnitState(UNIT_STAT_CONFUSED_MOVE);
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;
float destX = i_x;
float destY = i_y;
float destZ = i_z;
unit.UpdateAllowedPositionZ(x, y, z);
PathFinder path(&unit);
path.setPathLengthLimit(30.0f);
path.calculate(x, y, z);
if (path.getPathType() & PATHFIND_NOPATH)
// check if new random position is assigned, GetReachableRandomPosition may fail
if (unit.GetMap()->GetReachableRandomPosition(&unit, destX, destY, destZ, 10.0f))
{
i_nextMoveTime.Reset(urand(800, 1000));
return true;
Movement::MoveSplineInit init(unit);
init.MoveTo(destX, destY, destZ, true);
init.SetWalk(true);
init.Launch();
i_nextMoveTime.Reset(urand(800, 1000)); // Keep a short wait time
}
Movement::MoveSplineInit init(unit);
init.MovebyPath(path.getPath());
init.SetWalk(true);
init.Launch();
else
i_nextMoveTime.Reset(50); // Retry later
}
}
@ -118,7 +114,7 @@ template<>
void ConfusedMovementGenerator<Player>::Finalize(Player& unit)
{
unit.clearUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_CONFUSED_MOVE);
unit.StopMoving();
unit.StopMoving(true);
}
template<>

View File

@ -46,7 +46,11 @@ void FleeingMovementGenerator<T>::_setTargetLocation(T& owner)
float x, y, z;
if (!_getPoint(owner, x, y, z))
{ return; }
{
// random point not found recheck later
i_nextCheckTime.Reset(50);
return;
}
owner.addUnitState(UNIT_STAT_FLEEING_MOVE);
@ -55,7 +59,8 @@ void FleeingMovementGenerator<T>::_setTargetLocation(T& owner)
path.calculate(x, y, z);
if (path.getPathType() & PATHFIND_NOPATH)
{
i_nextCheckTime.Reset(urand(1000, 1500));
// path not found recheck later
i_nextCheckTime.Reset(50);
return;
}
@ -109,12 +114,23 @@ bool FleeingMovementGenerator<T>::_getPoint(T& owner, float& x, float& y, float&
x = curr_x + dist * cos(angle);
y = curr_y + dist * sin(angle);
z = curr_z;
z = curr_z + 0.5f;
// try to fix z
if (!owner.GetMap()->GetHeightInRange(x, y, z))
return false;
if (owner.GetTypeId() == TYPEID_PLAYER)
{ owner.GetMap()->GetHitPosition(curr_x, curr_y, curr_z, x, y, z, -0.1f); }
owner.UpdateAllowedPositionZ(x, y, z);
{
// check any collision
float testZ = z + 0.5f; // needed to avoid some false positive hit detection of terrain or passable little object
if (owner.GetMap()->GetHitPosition(curr_x, curr_y, curr_z + 0.5f, x, y, testZ, -0.1f))
{
z = testZ;
if (!owner.GetMap()->GetHeightInRange(x, y, z))
return false;
}
}
return true;
}

View File

@ -40,39 +40,32 @@ RandomMovementGenerator<Creature>::RandomMovementGenerator(const Creature& creat
i_y = respY;
i_z = respZ;
i_radius = wander_distance;
// TODO - add support for flying mobs using some distance
i_verticalZ = 0.0f;
}
template<>
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature)
{
const float angle = rand_norm_f() * (M_PI_F * 2.0f);
const float range = rand_norm_f() * i_radius;
const float maxPathRange = range * 1.5f;
float destX = i_x + range * cos(angle);
float destY = i_y + range * sin(angle);
float destZ = i_z + frand(-1, 1) * i_verticalZ;
creature.UpdateAllowedPositionZ(destX, destY, destZ);
float destX = i_x;
float destY = i_y;
float destZ = i_z;
creature.addUnitState(UNIT_STAT_ROAMING_MOVE);
Movement::MoveSplineInit init(creature);
init.MoveTo(destX, destY, destZ, true, false, maxPathRange);
init.SetWalk(true);
init.Launch();
if (creature.CanFly())
{ i_nextMoveTime.Reset(0); }
else
// check if new random position is assigned, GetReachableRandomPosition may fail
if (creature.GetMap()->GetReachableRandomPosition(&creature, destX, destY, destZ, i_radius))
{
Movement::MoveSplineInit init(creature);
init.MoveTo(destX, destY, destZ, true);
init.SetWalk(true);
init.Launch();
if (roll_chance_i(MOVEMENT_RANDOM_MMGEN_CHANCE_NO_BREAK))
i_nextMoveTime.Reset(50);
else
i_nextMoveTime.Reset(urand(3000, 10000)); // keep a short wait time
i_nextMoveTime.Reset(urand(3000, 10000)); // Keep a short wait time
}
else
i_nextMoveTime.Reset(50); // Retry later
return;
}
template<>

View File

@ -2050,6 +2050,61 @@ bool Map::GetHitPosition(float srcX, float srcY, float srcZ, float& destX, float
return result0 || result1;
}
// Find an height within a reasonable range of provided Z. This method may fail so we have to handle that case.
bool Map::GetHeightInRange(float x, float y, float& z, float maxSearchDist /*= 4.0f*/) const
{
float height, vmapHeight, mapHeight;
vmapHeight = VMAP_INVALID_HEIGHT_VALUE;
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
if (!vmgr->isLineOfSightCalcEnabled())
vmgr = NULL;
if (vmgr)
{
// pure vmap search
vmapHeight = vmgr->getHeight(i_id, x, y, z + 2.0f, maxSearchDist + 2.0f);
}
// find raw height from .map file on X,Y coordinates
if (GridMap* gmap = const_cast<TerrainInfo*>(m_TerrainData)->GetGrid(x, y)) // TODO:: find a way to remove that const_cast
mapHeight = gmap->getHeight(x, y);
float diffMaps = fabs(fabs(z) - fabs(mapHeight));
float diffVmaps = fabs(fabs(z) - fabs(vmapHeight));
if (diffVmaps < maxSearchDist)
{
if (diffMaps < maxSearchDist)
{
// well we simply have to take the highest as normally there we cannot be on top of cavern is maxSearchDist is not too big
if (vmapHeight > mapHeight)
height = vmapHeight;
else
height = mapHeight;
//sLog.outString("vmap %5.4f, map %5.4f, height %5.4f", vmapHeight, mapHeight, height);
}
else
{
//sLog.outString("vmap %5.4f", vmapHeight);
height = vmapHeight;
}
}
else
{
if (diffMaps < maxSearchDist)
{
//sLog.outString("map %5.4f", mapHeight);
height = mapHeight;
}
else
return false;
}
z = std::max<float>(height, m_dyn_tree.getHeight(x, y, height + 1.0f, maxSearchDist));
return true;
}
float Map::GetHeight(float x, float y, float z) const
{
float staticHeight = m_TerrainData->GetHeightStatic(x, y, z);
@ -2073,3 +2128,178 @@ bool Map::ContainsGameObjectModel(const GameObjectModel& mdl) const
{
return m_dyn_tree.contains(mdl);
}
// This will generate a random point to all directions in water for the provided point in radius range.
bool Map::GetRandomPointUnderWater(float& x, float& y, float& z, float radius, GridMapLiquidData& liquid_status)
{
const float angle = rand_norm_f() * (M_PI_F * 2.0f);
const float range = rand_norm_f() * radius;
float i_x = x + range * cos(angle);
float i_y = y + range * sin(angle);
// get real ground of new point
// the code consider cylinder instead of sphere for possible z
float ground = GetHeight(i_x, i_y, z);
if (ground > INVALID_HEIGHT) // GetHeight can fail
{
float min_z = z - 0.7f * radius; // 0.7 to have a bit a "flat" cylinder, TODO which value looks nicest
if (min_z < ground)
min_z = ground + 0.5f; // Get some space to prevent under map
float liquidLevel = liquid_status.level - 2.0f; // just to make the generated point is in water and not on surface or a bit above
// if not enough space to fit the creature better is to return from here
if (min_z > liquidLevel)
return false;
float max_z = std::max(z + 0.7f * radius, min_z);
max_z = std::min(max_z, liquidLevel);
x = i_x;
y = i_y;
z = min_z + rand_norm_f() * (max_z - min_z);
return true;
}
return false;
}
// This will generate a random point to all directions in air for the provided point in radius range.
bool Map::GetRandomPointInTheAir(float& x, float& y, float& z, float radius)
{
const float angle = rand_norm_f() * (M_PI_F * 2.0f);
const float range = rand_norm_f() * radius;
float i_x = x + range * cos(angle);
float i_y = y + range * sin(angle);
// get real ground of new point
// the code consider cylinder instead of sphere for possible z
float ground = GetHeight(i_x, i_y, z);
if (ground > INVALID_HEIGHT) // GetHeight can fail
{
float min_z = z - 0.7f * radius; // 0.7 to have a bit a "flat" cylinder, TODO which value looks nicest
if (min_z < ground)
min_z = ground + 2.5f; // Get some space to prevent landing
float max_z = std::max(z + 0.7f * radius, min_z);
x = i_x;
y = i_y;
z = min_z + rand_norm_f() * (max_z - min_z);
return true;
}
return false;
}
// supposed to be used for not big radius, usually less than 20.0f
bool Map::GetReachableRandomPointOnGround(float& x, float& y, float& z, float radius)
{
// Generate a random range and direction for the new point
const float angle = rand_norm_f() * (M_PI_F * 2.0f);
const float range = rand_norm_f() * radius;
float i_x = x + range * cos(angle);
float i_y = y + range * sin(angle);
float i_z = z + 1.0f;
GetHitPosition(x, y, z + 1.0f, i_x, i_y, i_z, -0.5f);
i_z = z; // reset i_z to z value to avoid too much difference from original point before GetHeightInRange
if (!GetHeightInRange(i_x, i_y, i_z)) // GetHeight can fail
return false;
// here we have a valid position but the point can have a big Z in some case
// next code will check angle from 2 points
// c
// /|
// / |
// b/__|a
// project vector to get only positive value
float ab = fabs(x - i_x);
float ac = fabs(z - i_z);
// slope represented by c angle (in radian)
float slope = 0;
const float MAX_SLOPE_IN_RADIAN = 50.0f / 180.0f * M_PI_F; // 50(degree) max seem best value for walkable slope
// check ab vector to avoid divide by 0
if (ab > 0.0f)
{
// compute c angle and convert it from radian to degree
slope = atan(ac / ab);
if (slope < MAX_SLOPE_IN_RADIAN)
{
x = i_x;
y = i_y;
z = i_z;
return true;
}
}
return false;
}
// Get random point by handling different situation depending of if the unit is flying/swimming/walking
bool Map::GetReachableRandomPosition(Unit* unit, float& x, float& y, float& z, float radius)
{
float i_x = x;
float i_y = y;
float i_z = z;
bool newDestAssigned = false; // used to check if new random destination is found
bool isFlying = false;
bool isSwimming = true;
switch (unit->GetTypeId())
{
case TYPEID_PLAYER:
isFlying = static_cast<Player*>(unit)->IsFlying();
break;
case TYPEID_UNIT:
isFlying = static_cast<Creature*>(unit)->IsFlying();
isSwimming = static_cast<Creature*>(unit)->IsSwimming();
break;
default:
sLog.outError("Map::GetReachableRandomPosition> Unsupported unit type is passed!");
return false;
}
if (radius < 0.1f)
{
sLog.outError("Map::GetReachableRandomPosition> Unsupported unit type is passed!");
return false;
}
if (isFlying)
{
newDestAssigned = GetRandomPointInTheAir(i_x, i_y, i_z, radius);
/*if (newDestAssigned)
sLog.outString("Generating air random point for %s", GetGuidStr().c_str());*/
}
else
{
GridMapLiquidData liquid_status;
GridMapLiquidStatus res = m_TerrainData->getLiquidStatus(i_x, i_y, i_z, MAP_ALL_LIQUIDS, &liquid_status);
if (isSwimming && (res & (LIQUID_MAP_UNDER_WATER | LIQUID_MAP_IN_WATER)))
{
newDestAssigned = GetRandomPointUnderWater(i_x, i_y, i_z, radius, liquid_status);
/*if (newDestAssigned)
sLog.outString("Generating swim random point for %s", GetGuidStr().c_str());*/
}
else
{
newDestAssigned = GetReachableRandomPointOnGround(i_x, i_y, i_z, radius);
/*if (newDestAssigned)
sLog.outString("Generating ground random point for %s", GetGuidStr().c_str());*/
}
}
if (newDestAssigned)
{
x = i_x;
y = i_y;
z = i_z;
return true;
}
return false;
}

View File

@ -292,6 +292,11 @@ class Map : public GridRefManager<NGridType>
*/
void SetWeather(uint32 zoneId, WeatherType type, float grade, bool permanently);
// Random on map generation
bool GetReachableRandomPosition(Unit* unit, float& x, float& y, float& z, float radius);
bool GetReachableRandomPointOnGround(float& x, float& y, float& z, float radius);
bool GetRandomPointInTheAir(float& x, float& y, float& z, float radius);
bool GetRandomPointUnderWater(float& x, float& y, float& z, float radius, GridMapLiquidData& liquid_status);
private:
void LoadMapAndVMap(int gx, int gy);