1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

CPathfinder: add one turn boundary for flying and water walking

Now when oneTurnSpecialLayersLimit is enabled hero won't be able to stop on blocked or water tiles between turns.
It's default H3 mechanics so it's enabled by default.
This commit is contained in:
ArseniyShestakov 2015-11-08 07:44:00 +03:00
parent 2fb73c55e1
commit 4af9c7c29d
2 changed files with 39 additions and 9 deletions

View File

@ -29,6 +29,7 @@ CPathfinder::PathfinderOptions::PathfinderOptions()
useTeleportWhirlpool = false; useTeleportWhirlpool = false;
lightweightFlyingMode = false; lightweightFlyingMode = false;
oneTurnSpecialLayersLimit = true;
} }
CPathfinder::CPathfinder(CPathsInfo &_out, CGameState *_gs, const CGHeroInstance *_hero) CPathfinder::CPathfinder(CPathsInfo &_out, CGameState *_gs, const CGHeroInstance *_hero)
@ -66,6 +67,19 @@ void CPathfinder::calculatePaths()
return cp->layer == EPathfindingLayer::SAIL ? maxMovePointsWater : maxMovePointsLand; return cp->layer == EPathfindingLayer::SAIL ? maxMovePointsWater : maxMovePointsLand;
}; };
auto passOneTurnLimitCheck = [&](bool shouldCheck) -> bool
{
if(options.oneTurnSpecialLayersLimit && shouldCheck)
{
if((cp->layer == EPathfindingLayer::AIR || cp->layer == EPathfindingLayer::WATER)
&& cp->accessible != CGPathNode::ACCESSIBLE)
{
return false;
}
}
return true;
};
auto isBetterWay = [&](int remains, int turn) -> bool auto isBetterWay = [&](int remains, int turn) -> bool
{ {
if(dp->turns == 0xff) //we haven't been here before if(dp->turns == 0xff) //we haven't been here before
@ -113,9 +127,13 @@ void CPathfinder::calculatePaths()
if(dp->locked) if(dp->locked)
continue; continue;
if(!passOneTurnLimitCheck(cp->turns != turn))
continue;
if(cp->layer != i && !isLayerTransitionPossible()) if(cp->layer != i && !isLayerTransitionPossible())
continue; continue;
destAction = CGPathNode::UNKNOWN; destAction = CGPathNode::UNKNOWN;
if(!isMovementToDestPossible()) if(!isMovementToDestPossible())
continue; continue;
@ -127,7 +145,6 @@ void CPathfinder::calculatePaths()
remains = hero->movementPointsAfterEmbark(movement, cost, destAction - 1); remains = hero->movementPointsAfterEmbark(movement, cost, destAction - 1);
cost = movement - remains; cost = movement - remains;
} }
int turnAtNextTile = turn; int turnAtNextTile = turn;
if(remains < 0) if(remains < 0)
{ {
@ -138,7 +155,8 @@ void CPathfinder::calculatePaths()
remains = moveAtNextTile - cost; remains = moveAtNextTile - cost;
} }
if(isBetterWay(remains, turnAtNextTile)) if(isBetterWay(remains, turnAtNextTile)
&& passOneTurnLimitCheck(cp->turns != turnAtNextTile || !remains))
{ {
assert(dp != cp->theNodeBefore); //two tiles can't point to each other assert(dp != cp->theNodeBefore); //two tiles can't point to each other
dp->moveRemains = remains; dp->moveRemains = remains;
@ -439,11 +457,16 @@ bool CPathfinder::isDestinationGuardian()
void CPathfinder::initializeGraph() void CPathfinder::initializeGraph()
{ {
auto updateNode = [&](int3 pos, EPathfindingLayer layer, const TerrainTile *tinfo) auto updateNode = [&](int3 pos, EPathfindingLayer layer, const TerrainTile *tinfo, bool blockNotAccessible)
{ {
auto node = out.getNode(pos, layer); auto node = out.getNode(pos, layer);
node->reset(); node->reset();
node->accessible = evaluateAccessibility(pos, tinfo);
auto accessibility = evaluateAccessibility(pos, tinfo);
if(blockNotAccessible
&& (accessibility != CGPathNode::ACCESSIBLE || tinfo->terType == ETerrainType::WATER))
accessibility = CGPathNode::BLOCKED;
node->accessible = accessibility;
}; };
int3 pos; int3 pos;
@ -459,16 +482,16 @@ void CPathfinder::initializeGraph()
case ETerrainType::ROCK: case ETerrainType::ROCK:
break; break;
case ETerrainType::WATER: case ETerrainType::WATER:
updateNode(pos, EPathfindingLayer::SAIL, tinfo); updateNode(pos, EPathfindingLayer::SAIL, tinfo, false);
if(options.useFlying) if(options.useFlying)
updateNode(pos, EPathfindingLayer::AIR, tinfo); updateNode(pos, EPathfindingLayer::AIR, tinfo, true);
if(options.useWaterWalking) if(options.useWaterWalking)
updateNode(pos, EPathfindingLayer::WATER, tinfo); updateNode(pos, EPathfindingLayer::WATER, tinfo, true);
break; break;
default: default:
updateNode(pos, EPathfindingLayer::LAND, tinfo); updateNode(pos, EPathfindingLayer::LAND, tinfo, false);
if(options.useFlying) if(options.useFlying)
updateNode(pos, EPathfindingLayer::AIR, tinfo); updateNode(pos, EPathfindingLayer::AIR, tinfo, true);
break; break;
} }
} }

View File

@ -105,6 +105,13 @@ private:
/// Downside is less MP effective paths calculation. /// Downside is less MP effective paths calculation.
bool lightweightFlyingMode; bool lightweightFlyingMode;
/// This option enable one turn limitation for flying and water walking.
/// So if we're out of MP while cp is blocked or water tile we won't add dest tile to queue.
///
/// Following imitation is default H3 mechanics, but someone may want to disable it in mods.
/// After all this limit should benefit performance on maps with tons of water or blocked tiles.
bool oneTurnSpecialLayersLimit;
PathfinderOptions(); PathfinderOptions();
} options; } options;