本文整理汇总了C++中Creature::CanFly方法的典型用法代码示例。如果您正苦于以下问题:C++ Creature::CanFly方法的具体用法?C++ Creature::CanFly怎么用?C++ Creature::CanFly使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类Creature
的用法示例。
在下文中一共展示了Creature::CanFly方法的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: init
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
{
float respX, respY, respZ, respO, wander_distance;
creature.GetRespawnCoord(respX, respY, respZ, &respO, &wander_distance);
const float angle = rand_norm_f() * (M_PI_F*2.0f);
const float range = rand_norm_f() * wander_distance;
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, true);
init.SetWalk(true);
init.Launch();
if (creature.CanFly())
i_nextMoveTime.Reset(0);
else
i_nextMoveTime.Reset(urand(500, 10000));
}
示例2: init
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;
float destX,destY,destZ;
creature.GetNearPoint(&creature, destX, destY, destZ, creature.GetObjectBoundingRadius(), range, angle);
creature.UpdateAllowedPositionZ(destX, destY, destZ);
float dx = i_x - destX;
float dy = i_y - destY;
// TODO: Limitation creatutre travel range.
if (sqrt((dx*dx) + (dy*dy)) > i_radius)
{
destX = i_x;
destY = i_y;
destZ = i_z;
}
creature.addUnitState(UNIT_STAT_ROAMING_MOVE);
Movement::MoveSplineInit init(creature);
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));
}
示例3: init
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);
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
{
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
}
}
示例4: init
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
{
Position dest;
creature.GetRespawnCoord(dest.x, dest.y, dest.z, &dest.o, &wander_distance);
bool is_air_ok = creature.CanFly();
const float angle = frand(0.0f, M_PI*2.0f);
const float range = frand(0.0f, wander_distance);
creature.GetValidPointInAngle(dest, range, angle, false);
static_cast<MovementGenerator*>(this)->_recalculateTravel = false;
if (is_air_ok)
i_nextMoveTime.Reset(0);
else
{
if (roll_chance_i(MOVEMENT_RANDOM_MMGEN_CHANCE_NO_BREAK))
i_nextMoveTime.Reset(0);
else
i_nextMoveTime.Reset(urand(500, 10000));
}
creature.addUnitState(UNIT_STAT_ROAMING);
Movement::MoveSplineInit init(creature);
init.MoveTo(dest.x, dest.y, dest.z);
init.SetWalk(true);
init.Launch();
// Call for creature group update
if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature)
creature.GetFormation()->LeaderMoveTo(dest.x, dest.y, dest.z);
}
示例5: traveller
void WaypointMovementGenerator<Creature>::StartMove(Creature &creature)
{
if (!i_path || i_path->empty())
return;
if (Stopped())
return;
if (WaypointBehavior *behavior = i_path->at(i_currentNode).behavior)
{
if (behavior->model2 != 0)
creature.SetDisplayId(behavior->model2);
creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
}
if (m_isArrivalDone)
i_currentNode = (i_currentNode+1) % i_path->size();
m_isArrivalDone = false;
if (creature.CanFly())
creature.AddSplineFlag(SPLINEFLAG_FLYING);
creature.addUnitState(UNIT_STAT_ROAMING_MOVE);
const WaypointNode &node = i_path->at(i_currentNode);
CreatureTraveller traveller(creature);
i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
}
示例6: traveller
bool RandomMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff)
{
if (creature.hasUnitState(UNIT_STAT_NOT_MOVE))
{
i_nextMoveTime.Update(i_nextMoveTime.GetExpiry()); // Expire the timer
creature.clearUnitState(UNIT_STAT_ROAMING_MOVE);
return true;
}
i_nextMoveTime.Update(diff);
if (i_destinationHolder.HasArrived() && !creature.IsStopped() && !creature.CanFly())
creature.clearUnitState(UNIT_STAT_ROAMING_MOVE);
if (!i_destinationHolder.HasArrived() && creature.IsStopped())
creature.addUnitState(UNIT_STAT_ROAMING_MOVE);
CreatureTraveller traveller(creature);
if (i_destinationHolder.UpdateTraveller(traveller, diff, false, true))
{
if (!IsActive(creature)) // force stop processing (movement can move out active zone with cleanup movegens list)
return true; // not expire now, but already lost
if (i_nextMoveTime.Passed())
{
float x,y,z;
if(i_destinationHolder.HasDestination())
i_destinationHolder.GetLocationNowNoMicroMovement(x,y,z);
else
creature.GetPosition(x,y,z);
if (creature.CanFly() && !(creature.CanWalk() && creature.IsAtGroundLevel(x,y,z)))
creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7);
else
creature.AddSplineFlag(SPLINEFLAG_WALKMODE);
_setRandomLocation(creature);
}
else if (creature.IsPet() && creature.GetOwner() && !creature.IsWithinDist(creature.GetOwner(), PET_FOLLOW_DIST+2.5f))
{
creature.AddSplineFlag(SPLINEFLAG_WALKMODE);
_setRandomLocation(creature);
}
}
return true;
}
示例7:
void RandomMovementGenerator<Creature>::Initialize(Creature &creature)
{
if (!creature.isAlive())
return;
if (creature.CanFly())
creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7);
else
creature.AddSplineFlag(SPLINEFLAG_WALKMODE);
creature.addUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
_setRandomLocation(creature);
}
示例8: init
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
{
Position dest;
creature.GetRespawnCoord(dest.x, dest.y, dest.z, &dest.o, &wander_distance);
bool is_air_ok = creature.CanFly();
const float angle = frand(0.0f, M_PI*2.0f);
const float range = frand(0.0f, wander_distance);
creature.GetValidPointInAngle(dest, range, angle, false);
Movement::MoveSplineInit init(creature);
init.MoveTo(dest.x, dest.y, dest.z);
init.SetWalk(true);
init.Launch();
static_cast<MovementGenerator*>(this)->_recalculateTravel = false;
i_nextMoveTime.Reset(urand(500, 10000));
}
示例9: traveller
//-----------------------------------------------//
void WaypointMovementGenerator<Creature>::LoadPath(Creature &creature)
{
DETAIL_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "LoadPath: loading waypoint path for creature %u, %u", creature.GetGUIDLow(), creature.GetDBTableGUIDLow());
i_path = sWaypointMgr.GetPath(creature.GetDBTableGUIDLow());
// We may LoadPath() for several occasions:
// 1: When creature.MovementType=2
// 1a) Path is selected by creature.guid == creature_movement.id
// 1b) Path for 1a) does not exist and then use path from creature.GetEntry() == creature_movement_template.entry
// 2: When creature_template.MovementType=2
// 2a) Creature is summoned and has creature_template.MovementType=2
// Creators need to be sure that creature_movement_template is always valid for summons.
// Mob that can be summoned anywhere should not have creature_movement_template for example.
// No movement found for guid
if (!i_path)
{
i_path = sWaypointMgr.GetPathTemplate(creature.GetEntry());
// No movement found for entry
if (!i_path)
{
sLog.outErrorDb("WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %u) doesn't have waypoint path",
creature.GetName(), creature.GetEntry(), creature.GetDBTableGUIDLow());
return;
}
}
// We have to set the destination here (for the first point), right after Initialize. Without, we may not have valid xyz for GetResetPosition
CreatureTraveller traveller(creature);
if (creature.CanFly())
creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7);
const WaypointNode &node = i_path->at(i_currentNode);
i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
}
示例10: init
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;
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);
creature.addUnitState(UNIT_STAT_ROAMING_MOVE);
Movement::MoveSplineInit init(creature);
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));
}
示例11: BuildPolyPath
void PathInfo::BuildPolyPath(PathNode startPos, PathNode endPos)
{
// *** getting start/end poly logic ***
float distToStartPoly, distToEndPoly;
float startPoint[VERTEX_SIZE] = {startPos.y, startPos.z, startPos.x};
float endPoint[VERTEX_SIZE] = {endPos.y, endPos.z, endPos.x};
dtPolyRef startPoly = getPolyByLocation(startPoint, &distToStartPoly);
dtPolyRef endPoly = getPolyByLocation(endPoint, &distToEndPoly);
// we have a hole in our mesh
// make shortcut path and mark it as NOPATH ( with flying exception )
// its up to caller how he will use this info
if (startPoly == INVALID_POLYREF || endPoly == INVALID_POLYREF)
{
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: (startPoly == 0 || endPoly == 0)\n");
BuildShortcut();
m_type = (m_sourceUnit->GetTypeId() == TYPEID_UNIT && ((Creature*)m_sourceUnit)->CanFly())
? PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH) : PATHFIND_NOPATH;
return;
}
// we may need a better number here
bool farFromPoly = (distToStartPoly > 7.0f || distToEndPoly > 7.0f);
if (farFromPoly)
{
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: farFromPoly distToStartPoly=%.3f distToEndPoly=%.3f\n", distToStartPoly, distToEndPoly);
bool buildShotrcut = false;
if (m_sourceUnit->GetTypeId() == TYPEID_UNIT)
{
Creature* owner = (Creature*)m_sourceUnit;
PathNode p = (distToStartPoly > 7.0f) ? startPos : endPos;
if (m_sourceUnit->GetTerrain()->IsUnderWater(p.x, p.y, p.z))
{
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: underWater case\n");
if (owner->CanSwim())
buildShotrcut = true;
}
else
{
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: flying case\n");
if (owner->CanFly())
buildShotrcut = true;
}
}
if (buildShotrcut)
{
BuildShortcut();
m_type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
return;
}
else
{
float closestPoint[VERTEX_SIZE];
// we may want to use closestPointOnPolyBoundary instead
if (DT_SUCCESS == m_navMeshQuery->closestPointOnPoly(endPoly, endPoint, closestPoint))
{
dtVcopy(endPoint, closestPoint);
setActualEndPosition(PathNode(endPoint[2],endPoint[0],endPoint[1]));
}
m_type = PATHFIND_INCOMPLETE;
}
}
// *** poly path generating logic ***
// start and end are on same polygon
// just need to move in straight line
if (startPoly == endPoly)
{
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: (startPoly == endPoly)\n");
BuildShortcut();
m_pathPolyRefs[0] = startPoly;
m_polyLength = 1;
m_type = farFromPoly ? PATHFIND_INCOMPLETE : PATHFIND_NORMAL;
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: path type %d\n", m_type);
return;
}
// look for startPoly/endPoly in current path
// TODO: we can merge it with getPathPolyByPosition() loop
bool startPolyFound = false;
bool endPolyFound = false;
uint32 pathStartIndex, pathEndIndex;
if (m_polyLength)
{
for (pathStartIndex = 0; pathStartIndex < m_polyLength; ++pathStartIndex)
{
// here to carch few bugs
MANGOS_ASSERT(m_pathPolyRefs[pathStartIndex] != INVALID_POLYREF);
//.........这里部分代码省略.........
示例12: init
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature)
{
float respX, respY, respZ, respO, destX, destY, destZ, travelDistZ;
creature.GetHomePosition(respX, respY, respZ, respO);
Map const* map = creature.GetBaseMap();
// 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 = float(rand_norm()) * static_cast<float>(M_PI*2.0f);
const float range = float(rand_norm()) * wander_distance;
const float distanceX = range * std::cos(angle);
const float distanceY = range * std::sin(angle);
destX = respX + distanceX;
destY = respY + distanceY;
// prevent invalid coordinates generation
Trinity::NormalizeMapCoord(destX);
Trinity::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 = float(rand_norm()) * 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(creature.GetPhaseMask(), destX, destY, respZ+travelDistZ-2.0f, false);
if (fabs(destZ - respZ) > travelDistZ) // Map check
{
// Vmap Horizontal or above
destZ = map->GetHeight(creature.GetPhaseMask(), destX, destY, respZ - 2.0f, true);
if (fabs(destZ - respZ) > travelDistZ)
{
// Vmap Higher
destZ = map->GetHeight(creature.GetPhaseMask(), 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));
creature.AddUnitState(UNIT_STATE_ROAMING_MOVE);
Movement::MoveSplineInit init(creature);
init.MoveTo(destX, destY, destZ);
init.SetWalk(true);
init.Launch();
//Call for creature group update
if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature)
creature.GetFormation()->LeaderMoveTo(destX, destY, destZ);
}
示例13: BuildPolyPath
void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 const& endPos)
{
// *** getting start/end poly logic ***
float distToStartPoly, distToEndPoly;
float startPoint[VERTEX_SIZE] = {startPos.y, startPos.z, startPos.x};
float endPoint[VERTEX_SIZE] = {endPos.y, endPos.z, endPos.x};
dtPolyRef startPoly = GetPolyByLocation(startPoint, &distToStartPoly);
dtPolyRef endPoly = GetPolyByLocation(endPoint, &distToEndPoly);
// we have a hole in our mesh
// make shortcut path and mark it as NOPATH ( with flying and swimming exception )
// its up to caller how he will use this info
if (startPoly == INVALID_POLYREF || endPoly == INVALID_POLYREF)
{
TC_LOG_DEBUG("maps", "++ BuildPolyPath :: (startPoly == 0 || endPoly == 0)\n");
BuildShortcut();
bool path = _sourceUnit->GetTypeId() == TYPEID_UNIT && _sourceUnit->ToCreature()->CanFly();
bool waterPath = _sourceUnit->GetTypeId() == TYPEID_UNIT && _sourceUnit->ToCreature()->CanSwim();
if (waterPath)
{
// Check both start and end points, if they're both in water, then we can *safely* let the creature move
for (uint32 i = 0; i < _pathPoints.size(); ++i)
{
ZLiquidStatus status = _sourceUnit->GetBaseMap()->getLiquidStatus(_pathPoints[i].x, _pathPoints[i].y, _pathPoints[i].z, MAP_ALL_LIQUIDS, NULL);
// One of the points is not in the water, cancel movement.
if (status == LIQUID_MAP_NO_WATER)
{
waterPath = false;
break;
}
}
}
_type = (path || waterPath) ? PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH) : PATHFIND_NOPATH;
return;
}
// we may need a better number here
bool farFromPoly = (distToStartPoly > 7.0f || distToEndPoly > 7.0f);
if (farFromPoly)
{
TC_LOG_DEBUG("maps", "++ BuildPolyPath :: farFromPoly distToStartPoly=%.3f distToEndPoly=%.3f\n", distToStartPoly, distToEndPoly);
bool buildShotrcut = false;
if (_sourceUnit->GetTypeId() == TYPEID_UNIT)
{
Creature* owner = (Creature*)_sourceUnit;
G3D::Vector3 const& p = (distToStartPoly > 7.0f) ? startPos : endPos;
if (_sourceUnit->GetBaseMap()->IsUnderWater(p.x, p.y, p.z))
{
TC_LOG_DEBUG("maps", "++ BuildPolyPath :: underWater case\n");
if (owner->CanSwim())
buildShotrcut = true;
}
else
{
TC_LOG_DEBUG("maps", "++ BuildPolyPath :: flying case\n");
if (owner->CanFly())
buildShotrcut = true;
}
}
if (buildShotrcut)
{
BuildShortcut();
_type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
return;
}
else
{
float closestPoint[VERTEX_SIZE];
// we may want to use closestPointOnPolyBoundary instead
if (dtStatusSucceed(_navMeshQuery->closestPointOnPoly(endPoly, endPoint, closestPoint, NULL)))
{
dtVcopy(endPoint, closestPoint);
SetActualEndPosition(G3D::Vector3(endPoint[2], endPoint[0], endPoint[1]));
}
_type = PATHFIND_INCOMPLETE;
}
}
// *** poly path generating logic ***
// start and end are on same polygon
// just need to move in straight line
if (startPoly == endPoly)
{
TC_LOG_DEBUG("maps", "++ BuildPolyPath :: (startPoly == endPoly)\n");
BuildShortcut();
_pathPolyRefs[0] = startPoly;
_polyLength = 1;
_type = farFromPoly ? PATHFIND_INCOMPLETE : PATHFIND_NORMAL;
//.........这里部分代码省略.........
示例14: cos
void
RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
{
float respX, respY, respZ, respO, currZ, destX, destY, destZ, wander_distance, travelDistZ;
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
{
destZ = respZ;
if(!map->IsNextZcoordOK(destX, destY, destZ, travelDistZ))
return; // let's forget this bad coords where a z cannot be find and retry at next tick
creature.UpdateGroundPositionZ(destX, destY, destZ, travelDistZ);
}
Traveller<Creature> traveller(creature);
creature.SetOrientation(creature.GetAngle(destX, destY));
i_destinationHolder.SetDestination(traveller, destX, destY, destZ);
creature.addUnitState(UNIT_STAT_ROAMING_MOVE);
if (is_air_ok)
{
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7);
}
//else if (is_water_ok) // Swimming mode to be done with more than this check
else
{
i_nextMoveTime.Reset(urand(500+i_destinationHolder.GetTotalTravelTime(), 10000+i_destinationHolder.GetTotalTravelTime()));
creature.AddSplineFlag(SPLINEFLAG_WALKMODE);
}
}
示例15: cos
void
RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
{
float respX, respY, respZ, respO, currZ, destX, destY, destZ, wander_distance, travelDistZ;
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;
}
}
}
Traveller<Creature> traveller(creature);
creature.SetOrientation(creature.GetAngle(destX, destY));
i_destinationHolder.SetDestination(traveller, destX, destY, destZ);
creature.addUnitState(UNIT_STAT_ROAMING_MOVE);
if (is_air_ok)
{
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
creature.AddSplineFlag(SPLINEFLAG_FLYING);
}
//else if (is_water_ok) // Swimming mode to be done with more than this check
else
{
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime() + urand(500, 10000));
creature.AddSplineFlag(SPLINEFLAG_WALKMODE);
}
}