Browse Source

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.
ArseniyShestakov 10 năm trước cách đây
mục cha
commit
fe12b8f664
2 tập tin đã thay đổi với 70 bổ sung52 xóa
  1. 68 51
      lib/CPathfinder.cpp
  2. 2 1
      lib/CPathfinder.h

+ 68 - 51
lib/CPathfinder.cpp

@@ -321,10 +321,13 @@ bool CPathfinder::isLayerTransitionPossible() const
 
 bool CPathfinder::isMovementToDestPossible() const
 {
+	if(dp->accessible == CGPathNode::BLOCKED)
+		return false;
+
 	switch(dp->layer)
 	{
 	case ELayer::LAND:
-		if(!canMoveBetween(cp->coord, dp->coord) || dp->accessible == CGPathNode::BLOCKED)
+		if(!canMoveBetween(cp->coord, dp->coord))
 			return false;
 		if(isSourceGuarded())
 		{
@@ -338,7 +341,7 @@ bool CPathfinder::isMovementToDestPossible() const
 		break;
 
 	case ELayer::SAIL:
-		if(!canMoveBetween(cp->coord, dp->coord) || dp->accessible == CGPathNode::BLOCKED)
+		if(!canMoveBetween(cp->coord, dp->coord))
 			return false;
 		if(isSourceGuarded())
 		{
@@ -531,17 +534,10 @@ bool CPathfinder::isDestinationGuardian() const
 
 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 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;
-		}
+		auto accessibility = evaluateAccessibility(pos, tinfo, layer);
 		node->update(pos, layer, accessibility);
 	};
 
@@ -555,65 +551,86 @@ void CPathfinder::initializeGraph()
 				const TerrainTile * tinfo = getTile(pos);
 				switch(tinfo->terType)
 				{
-					case ETerrainType::ROCK:
-						break;
-					case ETerrainType::WATER:
-						updateNode(pos, ELayer::SAIL, tinfo, false);
-						if(options.useFlying)
-							updateNode(pos, ELayer::AIR, tinfo, true);
-						if(options.useWaterWalking)
-							updateNode(pos, ELayer::WATER, tinfo, false);
-						break;
-					default:
-						updateNode(pos, ELayer::LAND, tinfo, false);
-						if(options.useFlying)
-							updateNode(pos, ELayer::AIR, tinfo, true);
-						break;
+				case ETerrainType::ROCK:
+					break;
+
+				case ETerrainType::WATER:
+					updateNode(pos, ELayer::SAIL, tinfo);
+					if(options.useFlying)
+						updateNode(pos, ELayer::AIR, tinfo);
+					if(options.useWaterWalking)
+						updateNode(pos, ELayer::WATER, tinfo);
+					break;
+
+				default:
+					updateNode(pos, ELayer::LAND, tinfo);
+					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))
 		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
-		{
-			return CGPathNode::BLOCKED;
-		}
-		else
+	case ELayer::LAND:
+	case ELayer::SAIL:
+		if(tinfo->visitable)
 		{
-			for(const CGObjectInstance * obj : tinfo->visitableObjects)
+			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
 			{
-				if(obj->passableFor(hero->tempOwner))
-				{
-					ret = CGPathNode::ACCESSIBLE;
-				}
-				else if(obj->blockVisit)
-				{
-					return CGPathNode::BLOCKVIS;
-				}
-				else if(obj->ID != Obj::EVENT) //pathfinder should ignore placed events
+				return CGPathNode::BLOCKED;
+			}
+			else
+			{
+				for(const CGObjectInstance * obj : tinfo->visitableObjects)
 				{
-					ret = CGPathNode::VISITABLE;
+					if(obj->passableFor(hero->tempOwner))
+					{
+						return CGPathNode::ACCESSIBLE;
+					}
+					else if(obj->blockVisit)
+					{
+						return CGPathNode::BLOCKVIS;
+					}
+					else if(obj->ID != Obj::EVENT) //pathfinder should ignore placed events
+					{
+						return CGPathNode::VISITABLE;
+					}
 				}
 			}
 		}
-	}
-	else if(guardingCreaturePosition(pos).valid() && !tinfo->blocked)
-	{
-		// Monster close by; blocked visit for battle.
-		return CGPathNode::BLOCKVIS;
+		else if(guardingCreaturePosition(pos).valid() && !tinfo->blocked)
+		{
+			// Monster close by; blocked visit for battle
+			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

+ 2 - 1
lib/CPathfinder.h

@@ -43,6 +43,7 @@ struct DLL_LINKAGE CGPathNode
 		ACCESSIBLE = 1, //tile can be entered and passed
 		VISITABLE, //tile can be entered as the last tile in path
 		BLOCKVIS,  //visitable from neighbouring tile but not passable
+		FLYABLE, //can only be accessed in air layer
 		BLOCKED //tile can't be entered nor visited
 	};
 
@@ -181,7 +182,7 @@ private:
 
 	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 isAllowedTeleportEntrance(const CGTeleport * obj) const;