Преглед изворни кода

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 година
родитељ
комит
fe12b8f664
2 измењених фајлова са 70 додато и 52 уклоњено
  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;