1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

Fixed pathfinding with free ship boarding (Admiral's Hat)

This commit is contained in:
Ivan Savenko
2023-06-22 14:42:24 +03:00
parent 08cfbe79cf
commit 03c3797945
2 changed files with 46 additions and 24 deletions

View File

@@ -63,7 +63,7 @@ struct DLL_LINKAGE CGPathNode
CGPathNode * theNodeBefore; CGPathNode * theNodeBefore;
int3 coord; //coordinates int3 coord; //coordinates
ELayer layer; ELayer layer;
ui32 moveRemains; //remaining movement points after hero reaches the tile int moveRemains; //remaining movement points after hero reaches the tile
ui8 turns; //how many turns we have to wait before reaching the tile - 0 means current turn ui8 turns; //how many turns we have to wait before reaching the tile - 0 means current turn
EPathAccessibility accessible; EPathAccessibility accessible;

View File

@@ -27,43 +27,65 @@ void MovementCostRule::process(
const PathfinderConfig * pathfinderConfig, const PathfinderConfig * pathfinderConfig,
CPathfinderHelper * pathfinderHelper) const CPathfinderHelper * pathfinderHelper) const
{ {
float costAtNextTile = destination.cost; const float currentCost = destination.cost;
int turnAtNextTile = destination.turn; const int currentTurnsUsed = destination.turn;
int moveAtNextTile = destination.movementLeft; const int currentMovePointsLeft = destination.movementLeft;
int cost = pathfinderHelper->getMovementCost(source, destination, moveAtNextTile); const int sourceLayerMaxMovePoints = pathfinderHelper->getMaxMovePoints(source.node->layer);
int remains = moveAtNextTile - cost;
int sourceLayerMaxMovePoints = pathfinderHelper->getMaxMovePoints(source.node->layer);
if(remains < 0) int moveCostPoints = pathfinderHelper->getMovementCost(source, destination, currentMovePointsLeft);
float destinationCost = currentCost;
int destTurnsUsed = currentTurnsUsed;
int destMovePointsLeft = currentMovePointsLeft;
if(currentMovePointsLeft < moveCostPoints)
{ {
//occurs rarely, when hero with low movepoints tries to leave the road // occurs rarely, when hero with low movepoints tries to leave the road
costAtNextTile += static_cast<float>(moveAtNextTile) / sourceLayerMaxMovePoints;//we spent all points of current turn // in this case, all remaining movement points from current turn are spent
pathfinderHelper->updateTurnInfo(++turnAtNextTile); // and actual movement will happen on next turn, spending points from next turn pool
int destinationLayerMaxMovePoints = pathfinderHelper->getMaxMovePoints(destination.node->layer); destinationCost += static_cast<float>(currentMovePointsLeft) / sourceLayerMaxMovePoints;
destTurnsUsed += 1;
destMovePointsLeft = sourceLayerMaxMovePoints;
moveAtNextTile = destinationLayerMaxMovePoints; // update move cost - it might have changed since hero now makes next turn and replenished his pool
moveCostPoints = pathfinderHelper->getMovementCost(source, destination, destMovePointsLeft);
cost = pathfinderHelper->getMovementCost(source, destination, moveAtNextTile); //cost must be updated, movement points changed :( pathfinderHelper->updateTurnInfo(destTurnsUsed);
remains = moveAtNextTile - cost;
} }
if(destination.action == EPathNodeAction::EMBARK || destination.action == EPathNodeAction::DISEMBARK) if(destination.action == EPathNodeAction::EMBARK || destination.action == EPathNodeAction::DISEMBARK)
{ {
/// FREE_SHIP_BOARDING bonus only remove additional penalty // FREE_SHIP_BOARDING bonus only remove additional penalty
/// land <-> sail transition still cost movement points as normal movement // land <-> sail transition still cost movement points as normal movement
remains = pathfinderHelper->movementPointsAfterEmbark(moveAtNextTile, cost, (destination.action == EPathNodeAction::DISEMBARK));
cost = moveAtNextTile - remains; const int movementPointsAfterEmbark = pathfinderHelper->movementPointsAfterEmbark(destMovePointsLeft, moveCostPoints, (destination.action == EPathNodeAction::DISEMBARK));
const int destinationLayerMaxMovePoints = pathfinderHelper->getMaxMovePoints(destination.node->layer);
const float costBeforeConversion = static_cast<float>(destMovePointsLeft) / sourceLayerMaxMovePoints;
const float costAfterConversion = static_cast<float>(movementPointsAfterEmbark) / destinationLayerMaxMovePoints;
const float costDelta = costBeforeConversion - costAfterConversion;
assert(costDelta >= 0);
destMovePointsLeft = movementPointsAfterEmbark;
destinationCost += costDelta;
}
else
{
// Standard movement
assert(destMovePointsLeft >= moveCostPoints);
destMovePointsLeft -= moveCostPoints;
destinationCost += static_cast<float>(moveCostPoints) / sourceLayerMaxMovePoints;
} }
costAtNextTile += static_cast<float>(cost) / sourceLayerMaxMovePoints; // pathfinder / priority queue does not supports negative costs
assert(destinationCost >= currentCost);
destination.cost = costAtNextTile; destination.cost = destinationCost;
destination.turn = turnAtNextTile; destination.turn = destTurnsUsed;
destination.movementLeft = remains; destination.movementLeft = destMovePointsLeft;
if(destination.isBetterWay() && if(destination.isBetterWay() &&
((source.node->turns == turnAtNextTile && remains) || pathfinderHelper->passOneTurnLimitCheck(source))) ((source.node->turns == destTurnsUsed && destMovePointsLeft) || pathfinderHelper->passOneTurnLimitCheck(source)))
{ {
pathfinderConfig->nodeStorage->commit(destination, source); pathfinderConfig->nodeStorage->commit(destination, source);