Original diff D2512
Reported on forum by gameboy:
https://wildfiregames.com/forum/index.php?/topic/27384-strange-landing-on-the-island-and-unable-to-attack/
Units with goal where minrange = maxrange rarely arrive to destination,
because they miss it.
See Todo in unitmotion
Relative part:
In the meantime, one should avoid that 'Speed over a turn' > MaxRange -
MinRange, in case where min-range is not 0 and max-range is not
infinity.
For that reason avoid passing minrange = maxrange from ai.
Also warn in cpp unitmoition when getting this kind of command.
Differential revision: D3149
Reviewed by: @wraitii
This was SVN commit r24315.
Fix in b1a78ce285 actually worked by accident, and introduced more
serious issue with minimal range.
Differential revision: D3148
Fixes: #5864
Reviewed by: wraitii
This was SVN commit r24264.
ComputeTargetPosition called Dot() with large enough vectors that it
overflowed. Avoid that by not actually doing the full dot product.
Reported by: Itms
Fixes#5852
Differential Revision: https://code.wildfiregames.com/D3061
This was SVN commit r24152.
Summary:
As reported by @bb and @Angen , 375c319639 broke formation walking in a
few situations.
The issue is that f489ab3a16/D2871 requires formation members to get no
messages until the controller is stopped, but 375c319639 didn't use the
correct function (on account of a missed rebase), so members stopped too
early.
Reported by: bb, Angen
Reviewed By: bb
Differential Revision: https://code.wildfiregames.com/D3006
This was SVN commit r24029.
As reported by Freagarach following a7da40ac2f.
32e8ed51aa introduced a "MoveObstructed" message, that could be sent
when the entity ran into obstructions, to stop early.
In HandleObstructedMove, my intention, as written in the comment, was
that the caller would do its thing (call StopMoving(), move out of the
world etc.) and thus ComputeGoal would return early.
However, I mistakenly left the `cmpPosition->GetPosition2D()` in between
that and ComputeGoal, which would then fail.
This fixes that by moving it after the `ComputeGoal` call.
Also add a sanity StopMoving() call to a7da40ac2f's move-out-of-world
call.
Reported by: Freagarach
Differential Revision: https://code.wildfiregames.com/D2935
This was SVN commit r23940.
Improve unitAI: don't move if the requester can reach us and we are
close enough. This avoids an issue where ships moved more than necessary
when picking up many units.
Also improve requester UnitAI -> retry pickup if the target entity is
Idle.
Improve unitMotion: periodically recompute paths in "known bad path"
mode to adapt to moving targets.
Expose UnitMotion reachability to scripts and other code.
This adds a test map for some common and some tricky pickup cases, using
triggers.
Based on a patch by: causative
Reviewed By: Freagarach
Fixes#3472
Differential Revision: https://code.wildfiregames.com/D665
This was SVN commit r23925.
Units in formation can occasionally request many short paths (and thus
introduce crippling lag) if their offset is obstructed.
This particularly happen when the formation is idle, since the offset
then always remains obstructed.
To prevent this, it is OK to immediately stop pathing on any motion
message (obstructed, failure, success). This does not break formation
movement since messages are only sent when the formation controller is
not moving (this finishes what was started in 0535eb9b92).
Ideally, this hack could be removed if the short-pathfinder was quick
enough / units were better at aborting.
Fixes concern raised by Freagarach on a7da40ac2f.
Refs #5624 in that the max-short-path range is the source of the lag.
Reviewed By: Angen
Differential Revision: https://code.wildfiregames.com/D2871
This was SVN commit r23867.
This fixes an off-by-one error that led to entities sometimes getting
stuck against obstructions.
It also increases the max-range of the short pathfinder to help entities
find their way around corridors and house blocks.
Fixes 2ff8614ce2 (off-by-one error) and reverts the range changes from
32e8ed51aa
Reported By: Freagarach
Fixes#5586 . Refs #5624
Differential Revision: https://code.wildfiregames.com/D2754
This was SVN commit r23699.
Fail movement for formationmember when cannot find path to destination
and formationcontroller is not moving so formationmember will enter idle
state or follow next command relying on member stopping movement first.
Introduced in a1dc9cadd8.
Differentail Revision: https://code.wildfiregames.com/D2438
This was SVN commit r23496.
Problem description:
When unit gets command to move to the range exactly X units from some
point/entity, what means minRange == maxRange, that triggers computing
goal when distance < minRange with result distance(goal, target) >
maxRange, because minRange computation uses clearance even when is
treating target as circle.
Solution:
Do not use clearance when treating target as circle, so computation when
distance < minimum range is done in same way as computation when
distance > maximum range and so computed goal has correct position.
Reported on forum:
https://wildfiregames.com/forum/index.php?/topic/27384-strange-landing-on-the-island-and-unable-to-attack/
Differential Revision: https://code.wildfiregames.com/D2512
Tested by: gameboy
This was SVN commit r23283.
D1987/99a341f379 introduced logic to predict the target movement, which
fixed unit chasing. However, sometimes fleeing units would then predict
that their target will end up in front of them, so they turned around
towards the attacker.
This is fixed by not anticipating the position when it would cause the
vector towards to target to change direction.
Reported By: Freagarach
Tested By: Freagarach
Fixes#5541
Differential Revision: https://code.wildfiregames.com/D2275
This was SVN commit r22885.
In some rare cases, units could be stuck in the special state of 3
failed path computations, making them always compute long paths instead
of trying short paths again. This can happen when they compute a long
path successfully, but the unit cannot actually move as it gets
obstructed right away.
Make sure this state is never kept for more than one turn to fix this
problem.
Refs #5569 (probable fix but kept open for further investigating).
Differential Revision: https://code.wildfiregames.com/D2239
This was SVN commit r22815.
Use the "pretend correct path" behaviour for short goals too. This is a
fix for #5545, since the position check now works correctly without
needing to add a tricky check for path-vs-path distance.
Simplify HandleObstructedMove to use ComputePathToGoal more. This means
we occasionally compute a long path when stuck, which fixes two cases of
stuck units reported in #5547.
Move some common calls into functions for convenience.
Make sure the short-path-waypoint-range-relaxing introduced in
32e8ed51aa doesn't happen for the last waypoint, which caused units to
occasionally never get in range of the last waypoint.
Clear short path waypoints when computing a long path.
This won't fix all instances of unit dancing, but it should improve most
of them.
Fixes#5545, Fixes#5547
Differential Revision: https://code.wildfiregames.com/D2135
This was SVN commit r22609.
BeginPathing renamed to ComputePathToGoal, as that is what this function
does.
IsMoving renamed to IsMoveRequested, as the function returns true when
the unit has a move request going on, not when it is actually moving
across the map, which was misleading.
UpdateMovementState's implementation moved closer to where it is used.
PathIsShort and WAYPOINT_ADVANCE_MAX are currently unused, thus deleted.
Differential Revision: https://code.wildfiregames.com/D2067
This was SVN commit r22568.
This helps with #3144 and units not going idle when ordered to clump
together.
By rejecting paths that would not take the unit closer to the goal than
it is, we can avoid the case where a unit at A finds a short path to B,
goes there, gets stuck, finds a new short path to A, etc. ad infinitum.
It doesn't completely fix the problem since two units moving might still
occasionally become stuck against one another, but it makes it rarer
(unit pushing would probably finish solving this).
This assumes that being as close as possible to the goal is the best
behaviour when trying to move somewhere, even when it is unreachable.
Refs #3144
Differential Revision: https://code.wildfiregames.com/D2075
This was SVN commit r22566.
This fixes a regression introduced by 055c848c1a: when an entity is
ordered to move to a target within short path distance (or direct path
distance), it no longer computed at least one long path, which meant it
could be stuck forever if the target was not actually reachable (such as
behind a wall).
To fix this, compute a long path after 3 failed computations, which
should result in a delay of 1-3 turns. The previous code did this after
1 failed try - the decision to make it 3 is mostly based on the idea
that in most cases, being stuck means we ran into units, not that we
were ordered somewhere close. Should there be complaints, it could be
lowered to 2 or 1.
This fixes a second issue, reported in #4473: units sometimes get stuck,
particularly when trying to garrison a turret from 'inside' the walls.
The issue is that the turret is not accessible via the inside as its
obstruction + garrison range is blocked by the surrounding walls.
However, as introduced by 6e05a00929, TryGoingStraightToTargetEntity
ignores all entities with the obstruction group of the target (the
reason for this being that otherwise it would never succeed, since the
line towards the target would likely go through the target).
For walls and formations, this means ignoring possibly too many
entities, and in the case of #4473, ignoring wall pieces. The unit thus
mistakenly thought it could direct-path to the turret, and got stuck.
To fix this, we can ignore specifically the targeted entity's
obstruction tag. This can be considered a fix to 6e05a00929.
temple accepted an earlier version of this patch (specifically elexis'
version).
Fixes#4473
Based on a patch by: elexis
Differential Revision: https://code.wildfiregames.com/D1424
This was SVN commit r22533.
As reported by #5521, Ordering units to walk to a point in a forest can
lag terribly, as units will end up computing long short paths in the
forest, which can result in `ComputeShortPath` calls that individually
take upwards of 80ms.
This can be alleviated by allowing units to stop a bit earlier. A23
handled this in UnitMotion directly, but it's better to handle this in
UnitAI to avoid surprises and to make it customisable on a per-state
level.
This diff further speeds up using the short pathfinder by starting with
a smaller search range, limiting the max-range more and moving the range
slightly towards the goal.
This also refactors UM sending messages to UnitAI so that we may in the
future push more information (in particular, the entity_id that a unit
was obstructed by could be interesting for COMBAT).
This doesn't fix the possibility of lag, but it reduces its occurrence
to levels that should be similar to A23 and thus acceptable enough.
Tested By: Freagarach
Fixes#5521
Differential Revision: https://code.wildfiregames.com/D2105
This was SVN commit r22526.
Units right now try going to their next long waypoint using the
short-range pathfinder. This works, but it tends to leads to units
clumping together when shuttling for example.
By switching to short paths earlier, and by scrapping the long waypoints
when doing so, we can make movement more natural until we have unit
pushing.
Some cleanup in how the short-path domain range gets handled, and
increase the max-range by one tile to improve rare cases.
Differential Revision: https://code.wildfiregames.com/D2095
This was SVN commit r22507.
As reported by @bb in #5512, catapults and other big-range units might
not approach targets correctly when trying to get in range.
To be sure that we will be in range of a square obstruction approximated
as a circle, we need to consider the inscribed circle and not the
circumscribed circle.
Reported by: bb
Fixes#5512
Differential Revision: https://code.wildfiregames.com/D2086
This was SVN commit r22495.
Three changes:
- Assume a certain incertain based on distance to the target, to avoid
recompute paths every turn when the target is far way and moving.
- Handle cases where the target is unreachable to the long-range
pathfinder and we would be recomputing every turn.
- If we went straight, assume we don't need to recompute a path.
These together make moving entities recompute paths far less often,
speeding up the game.
Differential Revision: https://code.wildfiregames.com/D2066
This was SVN commit r22474.
Since m_ExpectedPathTicket.m_Type is uninitialised before being used,
serialisation could fail with an out of bouds error. This fixes it by
giving it an (arbitrary) default value.
Reported by: gameboy
Confirmed and debugged by: Angen
Reviewed By: Angen
Differential Revision: https://code.wildfiregames.com/D2074
This was SVN commit r22470.
Reorder code flow, handle long paths and short paths in a more explicit
manner, and only fail after a certain number of failed path computations
to avoid going idle too easily.
Make sure WALKING orders in UnitAI stop when the move fails to avoid
units being stuck.
Differential Revision: https://code.wildfiregames.com/D1907
This was SVN commit r22464.
As reported by @Freagarach on #5496, there can be broken behaviour as
UnitMotion::PathResult may call RequestLongPath with an uninitialised
path goal when ComputeGoal fails.
To fix this, check the return value everywhere and react accordingly in
case of failure.
Fixes#5496
Differential Revision: https://code.wildfiregames.com/D2063
This was SVN commit r22458.
m_PathState kept 3 pieces of information that can be deduced using other
variables:
- whether the entity was following a path. This can be better deduced
by checking if the entity has short/long waypoints.
- whether a path is currently being requested. This can be better
deduced by checking the value of m_ExpectedPathTicket
- whether the requested path is long or short. This can be stored
directly alonside the path request ticket number, making it more obvious
why it exists.
With these changes, m_PathState can be removed.
Differential Revision: https://code.wildfiregames.com/D1903
This was SVN commit r22456.
It is generally better to use the movement request data as that is our
actual target and goals are just a representation of that at any given
time. Where a PathGoal is required, compute this lazily.
This allow failing easily in MoveToX() functions if the goal cannot be
computed.
Differential Revision: https://code.wildfiregames.com/D1902
This was SVN commit r22452.
MoveToPoint and MoveToTarget both compute a goal from a move request.
They can be combined to reduce duplication and streamline the code.
Differential Revision: https://code.wildfiregames.com/D1984
This was SVN commit r22450.
HandleObstructedMove contains logic to drop long waypoints, should they
be occupied by units (because that can get the pathfinder stuck, since
the long-range pathfinder can find a path, but not the vertex one).
However PathResult already drops waypoints this way, so this code can be
removed for simplification.
Differential Revision: https://code.wildfiregames.com/D1981
This was SVN commit r22448.
This fixes a number of issues with formations:
- Gives the controller an obstruction. This fixes the bug where units in
formations can't gather from a tree.
- Stop special-casing formation members in PathResult. This fixes
formation members being stuck in-place when they run in an obstruction.
- Makes sure units stay in Formation.IDle when they are idle so that
D1337/D1901 can work correctly in the IDLE state.
- Warn if animals enter this state.
- Make sure that formation members that end up in INDIVIDUAL.IDLE go
back to FORMATION.IDLE for sanity and for better housekeeping (refs
#3144 - fixed completely upstream).
Differential Revision: https://code.wildfiregames.com/D2048
This was SVN commit r22447.
Use UpdateMovementState to inform the visual actor of the unit's speed,
which cill update the movement animation accordingly.
The removes the need for UnitAI to handle movement animation using the
special "move" state.
Differential Revision: https://code.wildfiregames.com/D1901
This was SVN commit r22446.
Following D1899/98f609df1d, we have logic that can handle calling
MoveSucceeded() even if we don't go through the special STATE_STOPPING
state, and following D1898/8ac104b07a we no longer need STATE_STOPPING
for animation sync either.
m_State can therefore be entirely removed as it is redundant with other
information.
Differential Revision: https://code.wildfiregames.com/D1900
This was SVN commit r22441.
After the recent UM changes, units sometimes chase/flee forever as they
can never actually get in range.
This is because moving to the current target's position is not enough
when the target is moving.
By accounting for the target movement's in ComputeTargetPosition, the
behaviour is much improved.
Differential Revision: https://code.wildfiregames.com/D1987
This was SVN commit r22431.
This new version compares the final waypoint with the target's
obtruction shape and uses reachability checks to know if we will be in
range or not.
Differential Revision: https://code.wildfiregames.com/D1983
This was SVN commit r22430.
This is a partial revert of 4fda917f46, which skipped the
"MoveToTargetAttackingRange" in APPROACHING. I (incorrectly) assumed
that the original order was still perfectly fine, but in fact the
attacker's max range may have changed as that depends on the relative
elevation between attack and target - and so the original order might
never get us in range!
This was introduced originally in 8c74df2acd.
Add a comment to clarify this.
Further, this makes sure UnitMotion still is aware that it has a target
even if it is in range from the beginning, as that could lead
to stuckiness (and did when chasing sometimes). This was done in D1984
anyways.
Fixes#5478.
Differential Revision: https://code.wildfiregames.com/D2035
This was SVN commit r22429.
This makes it possible to merge the TryGoingStraightTo family of
function.
This means it is now called even for point goals and decreases the
likelihood of stuck units (as we take over from the long-range
pathfinder which brings units to navcell centers, which may not be in
the goal).
Differential Revision: https://code.wildfiregames.com/D1982
This was SVN commit r22426.
D981/c219ee54b2 changed IsInXChecks to use edge-to-edge distance instead
of centre-to-edge, which broke UnitMotion's min-range movement, which
assumed distance to the center.
Since units are represented as squares, the diagonal point may be closer
to the target than the "real" clearance by a factor √2, so the delta
between minimum range and maximum range should be at least `(√2 - 1) *
clearance` to be safe in all situations (this is generally not a problem
for regular units which have a clearance of 0.8, but could be one for
catapults or elephants).
Differential Revision: https://code.wildfiregames.com/D1969
This was SVN commit r22422.
Previously, unitMotion had no code that checked particularly if the
target was still in the world.
When the target moved out of the world, unitMotion would follow the path
to its last known position, then send a "MoveSucceeded" message once
there.
Following 98f609df1d, this message was no longer sent. Thus unit would
follow their path to its last waypoint and stay there, unable to carry
on or finish the order. UnitMotion now explcitly sends a "MoveFailed"
message.
This still changes behaviour from A23, requiring further revisions to
UnitAI (see D1992 for one such case).
Minohaka tested an earlier version of this change (which incorporated
D1992) and accepted it.
Differential Revision: https://code.wildfiregames.com/D1979
This was SVN commit r22415.
Due to an issue in 4a15cc3b9f, animals incorrectly tried going towards
the roaming point instead of away from it.
With that fixed, MovementUpdate still did not trigger as the min and max
range were the same.
Use -1 as max range (= infinite) instead since we want to move
arbitrarily away.
Having an infinite max range was broken in c219ee54b2, this
re-implements that.
Further, other calls with equal min and max range have been changed
likewise.
This does not entirely fix whales, which run in other problems because
of their large roaming range.
Differential Revision: https://code.wildfiregames.com/D1980
This was SVN commit r22413.
UnitMotion will now send hints that a move may be completed if:
- it is a formation member and the formation member has stopped moving.
- it isn't and it is in range from its target.
Differential Revision: https://code.wildfiregames.com/D1899
This was SVN commit r22366.
Units in 0 A.D. exhibited a "gliding" behaviour at the end of a
movement, e.g. they switched to the Idle animation and still moved a
little bit.
The reason for this behaviour is that entities check if they reached
their destination after moving. Other components (unitAI mostly) will
then possibly change animations and such, resulting in a movement over
the turn while the entity is possibly now in another animation state
than "move".
Instead, what should be done is checking if the entity has arrived
before moving, so if UnitAI calls StopMoving, then entity won't move at
all on the same turn, and the gliding effect vanishes.
The STATE_STOPPING state is made un-necessary by this change, since this
off-by-one mistake was the reason for its existence. It can be removed
(see downstream).
Differential Revision: https://code.wildfiregames.com/D1898
This was SVN commit r22365.
Move() is generally 4 parts:
- Moving
- Updating our state
- Handling obstructed moves
- Checking if we are at destination.
These can all be put in their own functions, clarifying logic and making
it harder to make mistakes.
Differential Revision: https://code.wildfiregames.com/D1897
This was SVN commit r22364.
In preparation for D1897, this logic isn't related to the "movement"
part of Move(), and can be called earlier.
Differential Revision: https://code.wildfiregames.com/D1896
This was SVN commit r22363.
The obstruction manager keeps a flag of moving units. This should be
updated in the same location as the entity's current speed, since they
have similar properties.
Differential Revision: https://code.wildfiregames.com/D1895
This was SVN commit r22362.
VisualActor refers to unit motion's `m_CurSpeed` to know what animation
to display in the special walk mode. However that variable was
inconsistently updated. By making sure we reach that codepath in one
place, we remove opportunities for issues.
This should fix most existing instances of moonwalking, another upstream
diff will fix the rest.
Differential Revision: https://code.wildfiregames.com/D1894
This was SVN commit r22361.
FacePointAfterMoving intends for the unit to face the destination once a
move is done. Since 4fda917f46, stopping is the responsibility of UnitAI
(through a call to StopMoving()). Thus we should move that code in that
function, as this ensures we don't forget to do it and removes
duplications.
Differential Revision: https://code.wildfiregames.com/D1889
This was SVN commit r22355.
The variable is not necessary since having a target is equivalent,
removing it thus reduces redundant state.
Differential Revision: https://code.wildfiregames.com/D1888
This was SVN commit r22354.
These variables together held the state for the target of UnitMotion, as
set by the MoveTo[X] family of functions.
Wrapping them in a struct reduces the chances that one will accidentally
forget to reset part of the state and makes it explicit in-code that
these are grouped together.
Calling StopMoving() resets this target, which wasn't before and left
the component in an incoherent state.
Differential Revision: https://code.wildfiregames.com/D1887
This was SVN commit r22352.
UnitAI is now solely in charge of moving and stopping, making UnitMotion
behaviour easier to predict, which will ultimately help with unitAI
development. It might temporarily make units more resilient than before
however.
UnitMotion also tells UnitAI that it's arrived with "MoveCompleted"
messages, but these actually could be wrong - unitAI could decide that
we didn't want to stop after all - so change the name for something less
misleading.
Differential Revision: https://code.wildfiregames.com/D1886
This was SVN commit r22351.