1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-21 21:17:49 +02:00

Pathfinding: re-introduce EAccessibility::FLYABLE

That let us get rid of really hacky code in initializeGraph and also fix flying over tiles that aren't visible.
This commit is contained in:
ArseniyShestakov 2015-11-17 03:59:02 +03:00
parent c2ba3e3faf
commit fe12b8f664
2 changed files with 70 additions and 52 deletions

View File

@ -321,10 +321,13 @@ bool CPathfinder::isLayerTransitionPossible() const
bool CPathfinder::isMovementToDestPossible() const bool CPathfinder::isMovementToDestPossible() const
{ {
if(dp->accessible == CGPathNode::BLOCKED)
return false;
switch(dp->layer) switch(dp->layer)
{ {
case ELayer::LAND: case ELayer::LAND:
if(!canMoveBetween(cp->coord, dp->coord) || dp->accessible == CGPathNode::BLOCKED) if(!canMoveBetween(cp->coord, dp->coord))
return false; return false;
if(isSourceGuarded()) if(isSourceGuarded())
{ {
@ -338,7 +341,7 @@ bool CPathfinder::isMovementToDestPossible() const
break; break;
case ELayer::SAIL: case ELayer::SAIL:
if(!canMoveBetween(cp->coord, dp->coord) || dp->accessible == CGPathNode::BLOCKED) if(!canMoveBetween(cp->coord, dp->coord))
return false; return false;
if(isSourceGuarded()) if(isSourceGuarded())
{ {
@ -531,17 +534,10 @@ bool CPathfinder::isDestinationGuardian() const
void CPathfinder::initializeGraph() void CPathfinder::initializeGraph()
{ {
auto updateNode = [&](int3 pos, ELayer layer, const TerrainTile * tinfo, bool blockNotAccessible) auto updateNode = [&](int3 pos, ELayer layer, const TerrainTile * tinfo)
{ {
auto node = out.getNode(pos, layer); auto node = out.getNode(pos, layer);
auto accessibility = evaluateAccessibility(pos, tinfo, layer);
auto accessibility = evaluateAccessibility(pos, tinfo);
/// TODO: Probably this shouldn't be handled by initializeGraph
if(blockNotAccessible
&& (accessibility != CGPathNode::ACCESSIBLE || tinfo->terType == ETerrainType::WATER))
{
accessibility = CGPathNode::BLOCKED;
}
node->update(pos, layer, accessibility); node->update(pos, layer, accessibility);
}; };
@ -555,65 +551,86 @@ void CPathfinder::initializeGraph()
const TerrainTile * tinfo = getTile(pos); const TerrainTile * tinfo = getTile(pos);
switch(tinfo->terType) switch(tinfo->terType)
{ {
case ETerrainType::ROCK: case ETerrainType::ROCK:
break; break;
case ETerrainType::WATER:
updateNode(pos, ELayer::SAIL, tinfo, false); case ETerrainType::WATER:
if(options.useFlying) updateNode(pos, ELayer::SAIL, tinfo);
updateNode(pos, ELayer::AIR, tinfo, true); if(options.useFlying)
if(options.useWaterWalking) updateNode(pos, ELayer::AIR, tinfo);
updateNode(pos, ELayer::WATER, tinfo, false); if(options.useWaterWalking)
break; updateNode(pos, ELayer::WATER, tinfo);
default: break;
updateNode(pos, ELayer::LAND, tinfo, false);
if(options.useFlying) default:
updateNode(pos, ELayer::AIR, tinfo, true); updateNode(pos, ELayer::LAND, tinfo);
break; if(options.useFlying)
updateNode(pos, ELayer::AIR, tinfo);
break;
} }
} }
} }
} }
} }
CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const int3 & pos, const TerrainTile * tinfo) const CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const int3 & pos, const TerrainTile * tinfo, const ELayer layer) const
{ {
CGPathNode::EAccessibility ret = (tinfo->blocked ? CGPathNode::BLOCKED : CGPathNode::ACCESSIBLE);
if(tinfo->terType == ETerrainType::ROCK || !isVisible(pos, hero->tempOwner)) if(tinfo->terType == ETerrainType::ROCK || !isVisible(pos, hero->tempOwner))
return CGPathNode::BLOCKED; return CGPathNode::BLOCKED;
if(tinfo->visitable) switch(layer)
{ {
if(tinfo->visitableObjects.front()->ID == Obj::SANCTUARY && tinfo->visitableObjects.back()->ID == Obj::HERO && tinfo->visitableObjects.back()->tempOwner != hero->tempOwner) //non-owned hero stands on Sanctuary case ELayer::LAND:
case ELayer::SAIL:
if(tinfo->visitable)
{ {
return CGPathNode::BLOCKED; if(tinfo->visitableObjects.front()->ID == Obj::SANCTUARY && tinfo->visitableObjects.back()->ID == Obj::HERO && tinfo->visitableObjects.back()->tempOwner != hero->tempOwner) //non-owned hero stands on Sanctuary
}
else
{
for(const CGObjectInstance * obj : tinfo->visitableObjects)
{ {
if(obj->passableFor(hero->tempOwner)) return CGPathNode::BLOCKED;
}
else
{
for(const CGObjectInstance * obj : tinfo->visitableObjects)
{ {
ret = CGPathNode::ACCESSIBLE; if(obj->passableFor(hero->tempOwner))
} {
else if(obj->blockVisit) return CGPathNode::ACCESSIBLE;
{ }
return CGPathNode::BLOCKVIS; else if(obj->blockVisit)
} {
else if(obj->ID != Obj::EVENT) //pathfinder should ignore placed events return CGPathNode::BLOCKVIS;
{ }
ret = CGPathNode::VISITABLE; else if(obj->ID != Obj::EVENT) //pathfinder should ignore placed events
{
return CGPathNode::VISITABLE;
}
} }
} }
} }
} else if(guardingCreaturePosition(pos).valid() && !tinfo->blocked)
else if(guardingCreaturePosition(pos).valid() && !tinfo->blocked) {
{ // Monster close by; blocked visit for battle
// Monster close by; blocked visit for battle. return CGPathNode::BLOCKVIS;
return CGPathNode::BLOCKVIS; }
else if(tinfo->blocked)
return CGPathNode::BLOCKED;
break;
case ELayer::WATER:
if(tinfo->blocked || tinfo->terType != ETerrainType::WATER)
return CGPathNode::BLOCKED;
break;
case ELayer::AIR:
if(tinfo->blocked || tinfo->terType == ETerrainType::WATER)
return CGPathNode::FLYABLE;
break;
} }
return ret; return CGPathNode::ACCESSIBLE;
} }
bool CPathfinder::canMoveBetween(const int3 & a, const int3 & b) const bool CPathfinder::canMoveBetween(const int3 & a, const int3 & b) const

View File

@ -43,6 +43,7 @@ struct DLL_LINKAGE CGPathNode
ACCESSIBLE = 1, //tile can be entered and passed ACCESSIBLE = 1, //tile can be entered and passed
VISITABLE, //tile can be entered as the last tile in path VISITABLE, //tile can be entered as the last tile in path
BLOCKVIS, //visitable from neighbouring tile but not passable BLOCKVIS, //visitable from neighbouring tile but not passable
FLYABLE, //can only be accessed in air layer
BLOCKED //tile can't be entered nor visited BLOCKED //tile can't be entered nor visited
}; };
@ -181,7 +182,7 @@ private:
void initializeGraph(); void initializeGraph();
CGPathNode::EAccessibility evaluateAccessibility(const int3 & pos, const TerrainTile * tinfo) const; CGPathNode::EAccessibility evaluateAccessibility(const int3 & pos, const TerrainTile * tinfo, const ELayer layer) const;
bool canMoveBetween(const int3 & a, const int3 & b) const; //checks only for visitable objects that may make moving between tiles impossible, not other conditions (like tiles itself accessibility) bool canMoveBetween(const int3 & a, const int3 & b) const; //checks only for visitable objects that may make moving between tiles impossible, not other conditions (like tiles itself accessibility)
bool isAllowedTeleportEntrance(const CGTeleport * obj) const; bool isAllowedTeleportEntrance(const CGTeleport * obj) const;