18 #include "precompiled.h"
245 "<a:help>Provides the unit with the ability to move around the world by itself.</a:help>"
247 "<WalkSpeed>7.0</WalkSpeed>"
248 "<PassabilityClass>default</PassabilityClass>"
249 "<CostClass>infantry</CostClass>"
251 "<element name='FormationController'>"
252 "<data type='boolean'/>"
254 "<element name='WalkSpeed' a:help='Basic movement speed (in metres per second)'>"
255 "<ref name='positiveDecimal'/>"
258 "<element name='Run'>"
260 "<element name='Speed'><ref name='positiveDecimal'/></element>"
261 "<element name='Range'><ref name='positiveDecimal'/></element>"
262 "<element name='RangeMin'><ref name='nonNegativeDecimal'/></element>"
263 "<element name='RegenTime'><ref name='positiveDecimal'/></element>"
264 "<element name='DecayTime'><ref name='positiveDecimal'/></element>"
268 "<element name='PassabilityClass' a:help='Identifies the terrain passability class (values are defined in special/pathfinder.xml)'>"
271 "<element name='CostClass' a:help='Identifies the movement speed/cost class (values are defined in special/pathfinder.xml)'>"
330 serialize.NumberFixed_Unbounded(
"radius",
m_Radius);
338 serialize.NumberFixed_Unbounded(
"target pos x",
m_TargetPos.
X);
339 serialize.NumberFixed_Unbounded(
"target pos y",
m_TargetPos.
Y);
345 serialize.NumberFixed_Unbounded(
"speed",
m_Speed);
612 if (ticket != m_ExpectedPathTicket)
615 m_ExpectedPathTicket = 0;
617 if (m_PathState == PATHSTATE_WAITING_REQUESTING_LONG)
620 m_ShortPath.m_Waypoints.clear();
626 if (m_LongPath.m_Waypoints.empty())
629 m_LongPath.m_Waypoints.push_back(wp);
633 if (!cmpPosition || !cmpPosition->
IsInWorld())
641 if (!PickNextLongWaypoint(pos, ShouldAvoidMovingUnits()))
648 m_PathState = PATHSTATE_WAITING_REQUESTING_SHORT;
650 else if (m_PathState == PATHSTATE_WAITING_REQUESTING_SHORT)
655 if (m_ShortPath.m_Waypoints.empty())
657 if (!IsFormationMember())
666 GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg);
671 if (!cmpPosition || !cmpPosition->
IsInWorld())
678 m_PathState = PATHSTATE_FOLLOWING;
682 else if (m_PathState == PATHSTATE_FOLLOWING_REQUESTING_LONG)
692 if (m_LongPath.m_Waypoints.empty())
695 m_LongPath.m_Waypoints.push_back(wp);
699 if (!cmpPosition || !cmpPosition->
IsInWorld())
707 if (!PickNextLongWaypoint(pos, ShouldAvoidMovingUnits()))
714 m_PathState = PATHSTATE_FOLLOWING_REQUESTING_SHORT;
720 else if (m_PathState == PATHSTATE_FOLLOWING_REQUESTING_SHORT)
726 if (m_ShortPath.m_Waypoints.empty())
730 if (!IsFormationMember())
739 GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg);
743 m_PathState = PATHSTATE_FOLLOWING;
745 else if (m_PathState == PATHSTATE_FOLLOWING_REQUESTING_SHORT_APPEND)
748 m_ShortPath.m_Waypoints.insert(m_ShortPath.m_Waypoints.begin(), path.m_Waypoints.begin(), path.m_Waypoints.end());
754 if (path.m_Waypoints.empty())
755 m_LongPath.m_Waypoints.clear();
757 m_PathState = PATHSTATE_FOLLOWING;
761 LOGWARNING(L
"unexpected PathResult (%u %d %d)", GetEntityId(), m_State, m_PathState);
811 if (!cmpPosition || !cmpPosition->
IsInWorld())
840 bool wasObstructed =
false;
856 if (!offset.IsZero())
859 cmpPosition->
TurnTo(angle);
866 fixed offsetLength = offset.Length();
867 if (offsetLength <= maxdist)
874 timeLeft = timeLeft - (offsetLength / maxSpeed);
882 wasObstructed =
true;
889 offset.Normalize(maxdist);
890 target = pos + offset;
900 wasObstructed =
true;
907 if (pos != initialPos)
962 if (cmpUnitMotion && !cmpUnitMotion->
IsMoving())
1006 if (!cmpPosition || !cmpPosition->
IsInWorld())
1031 if ((targetPos - from).CompareLength(DIRECT_PATH_RANGE) > 0)
1040 goal.
x = targetPos.
X;
1041 goal.
z = targetPos.
Y;
1070 if ((targetPos - oldTargetPos).CompareLength(minDelta) < 0)
1084 if (cmpRangeManager)
1115 distLeft -= delta.
Length();
1126 if (!cmpPosition || !cmpPosition->
IsInWorld())
1144 cmpPosition->
TurnTo(angle);
1232 if ((w - pos).CompareLength(WAYPOINT_ADVANCE_MAX) > 0)
1271 if (!cmpPosition || !cmpPosition->
IsInWorld())
1285 if (!cmpObstructionManager)
1295 goal.
x = obstruction.
x;
1296 goal.
z = obstruction.
z;
1297 goal.
u = obstruction.
u;
1298 goal.
v = obstruction.
v;
1315 if (distance < minRange)
1338 goal.
hw = goalDistance;
1356 if (!cmpPosition || !cmpPosition->
IsInWorld())
1361 bool hasObstruction =
false;
1364 if (cmpObstructionManager)
1367 if (minRange.
IsZero() && maxRange.
IsZero() && hasObstruction)
1374 if (distance < minRange)
1387 if (distance < minRange)
1412 entity_pos_t errCircle = circleRadius - std::min(hw, hh);
1414 return (errCircle < errSquare);
1422 if (!cmpPosition || !cmpPosition->
IsInWorld())
1428 if (!cmpObstructionManager)
1431 bool hasObstruction =
false;
1466 goal.
x = obstruction.
x;
1467 goal.
z = obstruction.
z;
1471 if (distance < minRange)
1480 goal.
u = obstruction.
u;
1481 goal.
v = obstruction.
v;
1483 goal.
hw = obstruction.
hw + delta;
1484 goal.
hh = obstruction.
hh + delta;
1509 if (circleDistance < maxRange)
1520 goal.
hw = circleRadius + goalDistance;
1530 goal.
u = obstruction.
u;
1531 goal.
v = obstruction.
v;
1533 goal.
hw = obstruction.
hw + delta;
1534 goal.
hh = obstruction.
hh + delta;
1554 if (!cmpTargetPosition || !cmpTargetPosition->
IsInWorld())
1569 if (!cmpPosition || !cmpPosition->
IsInWorld())
1575 if (!cmpObstructionManager)
1578 bool hasObstruction =
false;
1590 if (distance < minRange)
1606 if (circleDistance <= maxRange)
1615 if (!cmpTargetPosition || !cmpTargetPosition->
IsInWorld())
1622 if (minRange <= distance && (maxRange <
entity_pos_t::Zero() || distance <= maxRange))
1632 if (!cmpPosition || !cmpPosition->
IsInWorld())
1658 bool floating =
false;
1664 std::vector<float> waypointCoords;
1665 for (
size_t i = 0; i < path.
m_Waypoints.size(); ++i)
1669 waypointCoords.push_back(x);
1670 waypointCoords.push_back(z);
1672 lines.back().m_Color = color;
1676 lines.back().m_Color = color;
int CompareLength(fixed cmp) const
Returns -1, 0, +1 depending on whether length is less/equal/greater than the argument.
An entity initialisation parameter node.
virtual pass_class_t GetPassabilityClass(const std::string &name)=0
Get the tag for a given passability class name.
void SubscribeToMessageType(MessageTypeId mtid)
Subscribe the current component type to the given message type.
A simple fixed-point number class.
static const int WAYPOINT_ADVANCE_LOOKAHEAD_TURNS
When advancing along the long path, we'll pick a new waypoint to move towards if we expect to reach t...
void PathResult(u32 ticket, const ICmpPathfinder::Path &path)
Handle the result of an asynchronous path query.
bool ShouldAvoidMovingUnits()
#define REGISTER_COMPONENT_TYPE(cname)
void RequestShortPath(CFixedVector2D from, const ICmpPathfinder::Goal &goal, bool avoidMovingUnits)
Start an asynchronous short path query.
Helper templates for serializing/deserializing common objects.
ICmpPathfinder::Path m_LongPath
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
Line-based overlay, with world-space coordinates, rendered in the world potentially behind other obje...
ControlGroupMovementObstructionFilter GetObstructionFilter(bool forceAvoidMovingUnits=false)
Returns an appropriate obstruction filter for use with path requests.
bool ToBool() const
Parses the content of this node as a boolean ("true" == true, anything else == false) ...
virtual void Deserialize(const CParamNode ¶mNode, IDeserializer &deserialize)
virtual u32 ComputeShortPathAsync(entity_pos_t x0, entity_pos_t z0, entity_pos_t r, entity_pos_t range, const Goal &goal, pass_class_t passClass, bool avoidMovingUnits, entity_id_t group, entity_id_t notify)=0
Asynchronous version of ComputeShortPath (using ControlGroupObstructionFilter).
const ssize_t TERRAIN_TILE_SIZE
metres [world space units] per tile in x and z
void RequestLongPath(CFixedVector2D from, const ICmpPathfinder::Goal &goal)
Start an asynchronous long path query.
CFixedVector2D m_TargetOffset
void RenderSubmit(SceneCollector &collector)
const std::string ToUTF8() const
Returns the content of this node as an 8-bit string.
bool IsOk() const
Returns true if this is a valid CParamNode, false if it represents a non-existent node...
ICmpPathfinder::cost_class_t m_CostClass
virtual fixed GetMovementSpeed(entity_pos_t x0, entity_pos_t z0, cost_class_t costClass)=0
Find the speed factor (typically around 1.0) for a unit of the given cost class at the given position...
Serialization interface; see serialization overview.
Obstruction test filter that reject shapes in a given control group, and rejects shapes that don't bl...
Add renderable objects to the scene collector.
Sent by CCmpUnitMotion during Update, whenever the motion status has changed since the previous updat...
static std::string GetSchema()
static void out(const wchar_t *fmt,...)
std::vector< SOverlayLine > m_DebugOverlayShortPathLines
virtual CFixedVector3D GetRotation()=0
Returns the current rotation (relative to the upwards axis), as Euler angles with X=pitch...
virtual fixed GetCurrentSpeed()
Get the current movement speed.
virtual void SetUnitRadius(fixed radius)
Override the default obstruction radius, used for planning paths and checking for collisions...
std::vector< Waypoint > m_Waypoints
virtual void FaceTowardsPoint(entity_pos_t x, entity_pos_t z)
Turn to look towards the given point.
virtual bool GetObstructionSquare(ICmpObstructionManager::ObstructionSquare &out)=0
Gets the square corresponding to this obstruction shape.
virtual cost_class_t GetCostClass(const std::string &name)=0
Get the tag for a given movement cost class name.
virtual fixed GetWalkSpeed()
Get the default speed that this unit will have when walking, in metres per second.
Update phase for non-formation-controller unit movement.
entity_pos_t m_TargetMinRange
void FaceTowardsPointFromPos(CFixedVector2D pos, entity_pos_t x, entity_pos_t z)
Rotate to face towards the target point, given the current pos.
virtual fixed GetRunSpeed()
Get the default speed that this unit will have when running, in metres per second.
static const entity_pos_t WAYPOINT_ADVANCE_MAX
When advancing along the long path, and picking a new waypoint to move towards, we'll pick one that's...
virtual void MoveToFormationOffset(entity_id_t target, entity_pos_t x, entity_pos_t z)
Join a formation, and move towards a given offset relative to the formation controller entity...
CFixedVector2D Rotate(fixed angle)
Rotate the vector by the given angle (anticlockwise).
bool m_DebugOverlayEnabled
virtual void Serialize(ISerializer &serialize)
virtual bool MoveToTargetRange(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange)
Attempt to walk into range of a given target entity, or as close as possible.
virtual bool IsInWorld()=0
Returns true if the entity currently exists at a defined position in the world.
virtual ELosVisibility GetLosVisibility(CEntityHandle ent, player_id_t player, bool forceRetainInFog=false)=0
Returns the visibility status of the given entity, with respect to the given player.
This interface accepts renderable objects.
Motion interface for entities with complex movement capabilities.
CEntityHandle GetEntityHandle() const
fixed ToFixed() const
Parses the content of this node as a fixed-point number.
virtual void StopMoving()
Stop moving immediately.
bool PickNextLongWaypoint(const CFixedVector2D &pos, bool avoidMovingUnits)
Select a next long waypoint, given the current unit position.
virtual void HandleMessage(const CMessage &msg, bool global)
static const entity_pos_t CHECK_TARGET_MOVEMENT_AT_MAX_DIST
If we're following something but it's more than this distance away along our path, then don't bother trying to repath regardless of how much it has moved, until we get this close to the end of our old path.
virtual fixed GetDistanceTravelled()=0
Returns the distance that the unit will be interpolated over, i.e.
entity_id_t GetEntityId() const
virtual void SetMovingFlag(bool enabled)=0
virtual bool IsInPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t minRange, entity_pos_t maxRange)
Determine wether the givven point is within the given range, using the same measurement as MoveToPoin...
entity_pos_t m_TargetMaxRange
virtual int GetType() const =0
bool ComputeTargetPosition(CFixedVector2D &out)
Computes the current location of our target entity (plus offset).
const CParamNode & GetChild(const char *name) const
Returns the (unique) child node with the given name, or a node with IsOk() == false if there is none...
virtual bool CheckMovement(const IObstructionTestFilter &filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, pass_class_t passClass)=0
Check whether the given movement line is valid and doesn't hit any obstructions or impassable terrain...
void ConstructLineOnGround(const CSimContext &context, const std::vector< float > &xz, SOverlayLine &overlay, bool floating, float heightOffset=0.25f)
Constructs overlay line from given points, conforming to terrain.
virtual bool MoveToPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t minRange, entity_pos_t maxRange)
Attempt to walk into range of a to a given point, or as close as possible.
static void ClassInit(CComponentManager &componentManager)
void Move(fixed dt)
Do the per-turn movement and other updates.
bool m_FacePointAfterMove
virtual void Init(const CParamNode ¶mNode)
virtual void TurnTo(entity_angle_t y)=0
Rotate smoothly to the given angle around the upwards axis.
bool ShouldTreatTargetAsCircle(entity_pos_t range, entity_pos_t hw, entity_pos_t hh, entity_pos_t circleRadius)
Decide whether to approximate the given range from a square target as a circle, rather than as a squa...
static const entity_pos_t DIRECT_PATH_RANGE
If we are this close to our target entity/point, then think about heading for it in a straight line i...
CFixed Multiply(CFixed n) const
Multiply by a CFixed.
static const entity_pos_t CHECK_TARGET_MOVEMENT_MIN_DELTA_FORMATION
If we're following as part of a formation, but can't move to our assigned target point in a straight ...
CFixedVector2D m_TargetPos
virtual CFixedVector2D GetPosition2D()=0
Returns the current x,z position (no interpolation).
void SerializeCommon(S &serialize)
virtual player_id_t GetOwner()=0
bool CheckTargetMovement(CFixedVector2D from, entity_pos_t minDelta)
Returns whether the target entity has moved more than minDelta since our last path computations...
void RenderPath(const ICmpPathfinder::Path &path, std::vector< SOverlayLine > &lines, CColor color)
Convert a path into a renderable list of lines.
bool m_FormationController
bool PathIsShort(const ICmpPathfinder::Path &path, CFixedVector2D from, entity_pos_t minDistance)
Returns whether the length of the given path, plus the distance from 'from' to the first waypoints...
virtual void MoveTo(entity_pos_t x, entity_pos_t z)=0
Move smoothly to the given location.
static const entity_pos_t g_GoalDelta
#define DEFAULT_COMPONENT_ALLOCATOR(cname)
virtual u32 ComputePathAsync(entity_pos_t x0, entity_pos_t z0, const Goal &goal, pass_class_t passClass, cost_class_t costClass, entity_id_t notify)=0
Asynchronous version of ComputePath.
const CSimContext & GetSimContext() const
virtual bool IsInTargetRange(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange)
Determine whether the target is within the given range, using the same measurement as MoveToTargetRan...
A simplified syntax for accessing entity components.
virtual bool IsMoving()
Get whether the unit is moving.
CEntityHandle GetSystemEntity() const
static CFixed FromInt(int n)
Helper functions related to rendering.
virtual entity_pos_t GetUnitRadius()=0
void PostMessage(entity_id_t ent, const CMessage &msg) const
Send a message, targeted at a particular entity.
ICmpPathfinder::Path m_ShortPath
fixed Length() const
Returns the length of the vector.
bool TryGoingStraightToTargetEntity(CFixedVector2D from)
Attempts to replace the current path with a straight line to the target entity, if it's close enough ...
virtual void SetDebugPath(entity_pos_t x0, entity_pos_t z0, const Goal &goal, pass_class_t passClass, cost_class_t costClass)=0
If the debug overlay is enabled, render the path that will computed by ComputePath.
enum ICmpPathfinder::Goal::Type type
entity_id_t m_TargetEntity
Sent by CCmpPathfinder after async path requests.
bool IsZero() const
Returns true if the number is precisely 0.
SceneCollector & collector
virtual void SetSpeed(fixed speed)
Set the current movement speed.
virtual bool IsMoving()=0
Get whether the unit is moving.
virtual void SetFacePointAfterMove(bool facePointAfterMove)
Set whether the unit will turn to face the target point after finishing moving.
void ConstructSquareOnGround(const CSimContext &context, float x, float z, float w, float h, float a, SOverlayLine &overlay, bool floating, float heightOffset=0.25f)
Constructs overlay line as rectangle with given center and dimensions, conforming to terrain...
static const CColor OVERLAY_COLOUR_SHORT_PATH(1, 0, 0, 1)
fixed DistanceToSquare(CFixedVector2D point, CFixedVector2D u, CFixedVector2D v, CFixedVector2D halfSize)
ICmpPathfinder::Path path
void BeginPathing(CFixedVector2D from, const ICmpPathfinder::Goal &goal)
Start moving to the given goal, from our current position 'from'.
virtual ICmpPathfinder::pass_class_t GetPassabilityClass()
Get the unit's passability class.
CFixed_15_16 atan2_approx(CFixed_15_16 y, CFixed_15_16 x)
Inaccurate approximation of atan2 over fixed-point numbers.
virtual CFixedVector2D GetNearestPointOnGoal(CFixedVector2D pos, const Goal &goal)=0
Returns the coordinates of the point on the goal that is closest to pos in a straight line...
virtual bool FindMostImportantObstruction(const IObstructionTestFilter &filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, ObstructionSquare &square)=0
Find a single obstruction that blocks a unit at the given point with the given radius.
static float Length(const SVec3 v)
const entity_id_t INVALID_ENTITY
Invalid entity ID.
u32 entity_id_t
Entity ID type.
virtual void Submit(CPatch *patch)=0
Submit a terrain patch that is part of the scene.
virtual void SetDebugOverlay(bool enabled)
Toggle the rendering of debug info.
static const entity_pos_t CHECK_TARGET_MOVEMENT_MIN_DELTA
If we're following a target entity, we will recompute our path if the target has moved more than this...
static const entity_pos_t SHORT_PATH_GOAL_RADIUS
When short-pathing to an intermediate waypoint, we aim for a circle of this radius around the waypoin...
Standard representation for all types of shapes, for use with geometry processing code...
static const CColor OVERLAY_COLOUR_LONG_PATH(1, 1, 1, 1)
Helper functions related to geometry algorithms.
std::vector< SOverlayLine > m_DebugOverlayLongPathLines
CComponentManager & GetComponentManager() const
Deserialization interface; see serialization overview.
ICmpPathfinder::Goal m_FinalGoal
static const entity_pos_t SHORT_PATH_SEARCH_RANGE
Maximum range to restrict short path queries to.
virtual bool IsFloating()=0
Returns whether the entity floats on water.
ICmpPathfinder::pass_class_t m_PassClass