From d5a050d3a56cecfb13557ef50047dad1cbe5fe54 Mon Sep 17 00:00:00 2001 From: Jarod42 Date: Sun, 18 Aug 2024 09:40:44 +0200 Subject: [PATCH 1/2] Change `NextPathElement` to have current direction in `unit.output.Path` --- src/action/action_move.cpp | 10 ++++++---- src/pathfinder/pathfinder.cpp | 4 ++-- tests/stratagus/test_pathfinder.cpp | 10 +++++----- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/action/action_move.cpp b/src/action/action_move.cpp index 6ef00d1ec7..67aaca47cd 100644 --- a/src/action/action_move.cpp +++ b/src/action/action_move.cpp @@ -242,9 +242,11 @@ int DoActionMove(CUnit &unit) unit.Frame = unit.Type->StillFrame; UnitHeadingFromDeltaXY(unit, posd); } else { - posd.x = Heading2X[unit.Direction / NextDirection]; - posd.y = Heading2Y[unit.Direction / NextDirection]; - d = unit.pathFinderData->output.Length + 1; + const auto direction = + unit.pathFinderData->output.Path[unit.pathFinderData->output.Length - 1]; + posd.x = Heading2X[direction]; + posd.y = Heading2Y[direction]; + d = unit.pathFinderData->output.Length; } unit.pathFinderData->output.Cycles++;// reset have to be manualy controlled by caller. @@ -266,7 +268,7 @@ int DoActionMove(CUnit &unit) // Finished move to next tile, set Moving to 0 so we recalculate the path // next frame - if ((!unit.Anim.Unbreakable && !unit.IX && !unit.IY) || reached_next_tile ) { + if ((!unit.Anim.Unbreakable && !unit.IX && !unit.IY) || reached_next_tile) { unit.Moving = 0; } return d; diff --git a/src/pathfinder/pathfinder.cpp b/src/pathfinder/pathfinder.cpp index 8b8d1dc25f..a4a3020e41 100644 --- a/src/pathfinder/pathfinder.cpp +++ b/src/pathfinder/pathfinder.cpp @@ -445,12 +445,13 @@ std::pair NextPathElement(CUnit &unit) if (result == PF_REACHED) { return {result, {}}; } + } else { + output.Length--; } Vec2i dir(Heading2X[(int) output.Path[output.Length - 1]], Heading2Y[(int) output.Path[output.Length - 1]]); int result = output.Length; - output.Length--; if (!UnitCanBeAt(unit, unit.tilePos + dir)) { // If obstructing unit is moving, wait for a bit. if (output.Fast) { @@ -474,7 +475,6 @@ std::pair NextPathElement(CUnit &unit) dir = {0, 0}; } else { result = output.Length; - output.Length--; } } } diff --git a/tests/stratagus/test_pathfinder.cpp b/tests/stratagus/test_pathfinder.cpp index 670ac67a1c..4bbfaa8c42 100644 --- a/tests/stratagus/test_pathfinder.cpp +++ b/tests/stratagus/test_pathfinder.cpp @@ -115,8 +115,8 @@ TEST_CASE("PathFinding on clear map 128x128") CHECK(d == dist); - CHECK(unit.pathFinderData->output.Length == dist - 1); - CHECK(dest == FollowedPath(unit.tilePos + dir, unit.pathFinderData->output)); + CHECK(unit.pathFinderData->output.Length == dist); + CHECK(dest == FollowedPath(unit.tilePos, unit.pathFinderData->output)); unit.Orders.clear(); } @@ -132,10 +132,10 @@ TEST_CASE("PathFinding on clear map 128x128") CHECK(0 < d); CHECK(d <= std::size(unit.pathFinderData->output.Path)); - CHECK(unit.pathFinderData->output.Length + unit.pathFinderData->output.OverflowLength == dist - 1); + CHECK(unit.pathFinderData->output.Length + unit.pathFinderData->output.OverflowLength == dist); - CHECK(unit.pathFinderData->output.Length == d - 1); - CHECK(unit.tilePos + Vec2i(0, d) == FollowedPath(unit.tilePos + dir, unit.pathFinderData->output)); + CHECK(unit.pathFinderData->output.Length == d); + CHECK(unit.tilePos + Vec2i(0, d) == FollowedPath(unit.tilePos, unit.pathFinderData->output)); unit.Orders.clear(); } From 09719a01e3ffc930c1e6b4e44694596366b9ba73 Mon Sep 17 00:00:00 2001 From: Jarod42 Date: Sun, 18 Aug 2024 11:29:12 +0200 Subject: [PATCH 2/2] "Fix" `DoActionMove` for war1gus: war1gus' move animation is of the form `{"unbreakable begin", "frame 5", "move N", "wait 2", "wait 1", "unbreakable begin", "frame 0", "wait 1"}`; // ^^^^ Computation here (unbreakable) :/ ^^^^^ and can be break here (whereas wargus one is `{"unbreakable begin", "frame 5", "move N1", "wait 2", "frame 4", "move N2", "unbreakable begin", "frame 0", "wait 1"}`) // ^^^^^ computation here (breakable) Computation on path (and IX/IY) was done on next (finished) `"wait X"` after reaching the tile (so was done **inside** the `unbreakable` section for war1gus). Workaround is to do the computation only on new animation cycle. Alternative: - Grouping `"wait N1", "wait N2"` into `"wait N1+N2"` would not be enough (but would be fine). - Compute path on first `"move"` is problematic (for Wait/unreachable). --- src/action/action_move.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/action/action_move.cpp b/src/action/action_move.cpp index 67aaca47cd..b93fca339e 100644 --- a/src/action/action_move.cpp +++ b/src/action/action_move.cpp @@ -156,7 +156,9 @@ int DoActionMove(CUnit &unit) Vec2i posd{}; // movement in tile. int d{}; - if (unit.Moving != 1 && (&unit.Type->Animations->Move != unit.Anim.CurrAnim || !unit.Anim.Wait)) { + if (unit.Moving != 1 + && (&unit.Type->Animations->Move != unit.Anim.CurrAnim + || (unit.Anim.Wait == 0 && unit.Anim.Anim == 0))) { if (unit.Anim.Unbreakable && unit.Moving > 1) { // subtile movement, we're finished, but inside an unbreakable animation that we have to finish int m = UnitShowAnimationScaled(unit, &unit.Type->Animations->Move, 1) >> 1;