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;
int3 coord; //coordinates
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
EPathAccessibility accessible;

View File

@@ -27,43 +27,65 @@ void MovementCostRule::process(
const PathfinderConfig * pathfinderConfig,
CPathfinderHelper * pathfinderHelper) const
{
float costAtNextTile = destination.cost;
int turnAtNextTile = destination.turn;
int moveAtNextTile = destination.movementLeft;
int cost = pathfinderHelper->getMovementCost(source, destination, moveAtNextTile);
int remains = moveAtNextTile - cost;
int sourceLayerMaxMovePoints = pathfinderHelper->getMaxMovePoints(source.node->layer);
const float currentCost = destination.cost;
const int currentTurnsUsed = destination.turn;
const int currentMovePointsLeft = destination.movementLeft;
const 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
costAtNextTile += static_cast<float>(moveAtNextTile) / sourceLayerMaxMovePoints;//we spent all points of current turn
pathfinderHelper->updateTurnInfo(++turnAtNextTile);
// in this case, all remaining movement points from current turn are spent
// 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 :(
remains = moveAtNextTile - cost;
pathfinderHelper->updateTurnInfo(destTurnsUsed);
}
if(destination.action == EPathNodeAction::EMBARK || destination.action == EPathNodeAction::DISEMBARK)
{
/// FREE_SHIP_BOARDING bonus only remove additional penalty
/// land <-> sail transition still cost movement points as normal movement
remains = pathfinderHelper->movementPointsAfterEmbark(moveAtNextTile, cost, (destination.action == EPathNodeAction::DISEMBARK));
cost = moveAtNextTile - remains;
// FREE_SHIP_BOARDING bonus only remove additional penalty
// land <-> sail transition still cost movement points as normal movement
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.turn = turnAtNextTile;
destination.movementLeft = remains;
destination.cost = destinationCost;
destination.turn = destTurnsUsed;
destination.movementLeft = destMovePointsLeft;
if(destination.isBetterWay() &&
((source.node->turns == turnAtNextTile && remains) || pathfinderHelper->passOneTurnLimitCheck(source)))
((source.node->turns == destTurnsUsed && destMovePointsLeft) || pathfinderHelper->passOneTurnLimitCheck(source)))
{
pathfinderConfig->nodeStorage->commit(destination, source);