Jelajahi Sumber

Pathfinder: implement new feature - node action

No action going to simplify isMovementAfterDestPossible and should be as well useful for cost calculations.
It's can be also used by client interface to show appropriate cursors and path.
ArseniyShestakov 10 tahun lalu
induk
melakukan
82048cbf2d
2 mengubah file dengan 58 tambahan dan 13 penghapusan
  1. 45 12
      lib/CPathfinder.cpp
  2. 13 1
      lib/CPathfinder.h

+ 45 - 12
lib/CPathfinder.cpp

@@ -106,7 +106,6 @@ void CPathfinder::calculatePaths()
 			dt = &gs->map->getTile(neighbour);
 			dt = &gs->map->getTile(neighbour);
 			for(EPathfindingLayer i = EPathfindingLayer::LAND; i <= EPathfindingLayer::AIR; i.advance(1))
 			for(EPathfindingLayer i = EPathfindingLayer::LAND; i <= EPathfindingLayer::AIR; i.advance(1))
 			{
 			{
-				useEmbarkCost = 0; //0 - usual movement; 1 - embark; 2 - disembark
 				dp = out.getNode(neighbour, i);
 				dp = out.getNode(neighbour, i);
 				if(dp->accessible == CGPathNode::NOT_SET)
 				if(dp->accessible == CGPathNode::NOT_SET)
 					continue;
 					continue;
@@ -117,14 +116,15 @@ void CPathfinder::calculatePaths()
 				if(cp->layer != i && !isLayerTransitionPossible())
 				if(cp->layer != i && !isLayerTransitionPossible())
 					continue;
 					continue;
 
 
+				destAction = CGPathNode::UNKNOWN;
 				if(!isMovementToDestPossible())
 				if(!isMovementToDestPossible())
 					continue;
 					continue;
 
 
 				int cost = gs->getMovementCost(hero, cp->coord, dp->coord, movement);
 				int cost = gs->getMovementCost(hero, cp->coord, dp->coord, movement);
 				int remains = movement - cost;
 				int remains = movement - cost;
-				if(useEmbarkCost)
+				if(destAction == CGPathNode::EMBARK || destAction == CGPathNode::DISEMBARK)
 				{
 				{
-					remains = hero->movementPointsAfterEmbark(movement, cost, useEmbarkCost - 1);
+					remains = hero->movementPointsAfterEmbark(movement, cost, destAction - 1);
 					cost = movement - remains;
 					cost = movement - remains;
 				}
 				}
 
 
@@ -144,6 +144,7 @@ void CPathfinder::calculatePaths()
 					dp->moveRemains = remains;
 					dp->moveRemains = remains;
 					dp->turns = turnAtNextTile;
 					dp->turns = turnAtNextTile;
 					dp->theNodeBefore = cp;
 					dp->theNodeBefore = cp;
+					dp->action = destAction;
 
 
 					if(isMovementAfterDestPossible())
 					if(isMovementAfterDestPossible())
 						pq.push(dp);
 						pq.push(dp);
@@ -166,6 +167,7 @@ void CPathfinder::calculatePaths()
 					dp->moveRemains = movement;
 					dp->moveRemains = movement;
 					dp->turns = turn;
 					dp->turns = turn;
 					dp->theNodeBefore = cp;
 					dp->theNodeBefore = cp;
+					dp->action = CGPathNode::NORMAL;
 					pq.push(dp);
 					pq.push(dp);
 				}
 				}
 			}
 			}
@@ -258,24 +260,18 @@ bool CPathfinder::isLayerTransitionPossible()
 		if((dp->accessible != CGPathNode::ACCESSIBLE && (dp->accessible != CGPathNode::BLOCKVIS || dt->blocked))
 		if((dp->accessible != CGPathNode::ACCESSIBLE && (dp->accessible != CGPathNode::BLOCKVIS || dt->blocked))
 			|| dt->visitable)  //TODO: passableness problem -> town says it's passable (thus accessible) but we obviously can't disembark onto town gate
 			|| dt->visitable)  //TODO: passableness problem -> town says it's passable (thus accessible) but we obviously can't disembark onto town gate
 			return false;
 			return false;
-
-		useEmbarkCost = 2;
 	}
 	}
 	else if(cp->layer == EPathfindingLayer::LAND && dp->layer == EPathfindingLayer::SAIL)
 	else if(cp->layer == EPathfindingLayer::LAND && dp->layer == EPathfindingLayer::SAIL)
 	{
 	{
-		Obj destTopVisObjID = dt->topVisitableId();
-		if(dp->accessible == CGPathNode::ACCESSIBLE || destTopVisObjID < 0) //cannot enter empty water tile from land -> it has to be visitable
-			return false;
-		if(destTopVisObjID != Obj::HERO && destTopVisObjID != Obj::BOAT) //only boat or hero can be accessed from land
+		if(dp->accessible == CGPathNode::ACCESSIBLE) //cannot enter empty water tile from land -> it has to be visitable
 			return false;
 			return false;
-		if(destTopVisObjID == Obj::BOAT)
-			useEmbarkCost = 1;
 	}
 	}
 	return true;
 	return true;
 }
 }
 
 
 bool CPathfinder::isMovementToDestPossible()
 bool CPathfinder::isMovementToDestPossible()
 {
 {
+	auto obj = dt->topVisitableObj();
 	switch(dp->layer)
 	switch(dp->layer)
 	{
 	{
 		case EPathfindingLayer::LAND:
 		case EPathfindingLayer::LAND:
@@ -284,6 +280,9 @@ bool CPathfinder::isMovementToDestPossible()
 			if(isSourceGuarded() && !isDestinationGuardian()) // Can step into tile of guard
 			if(isSourceGuarded() && !isDestinationGuardian()) // Can step into tile of guard
 				return false;
 				return false;
 
 
+			if(cp->layer == EPathfindingLayer::SAIL)
+				destAction = CGPathNode::DISEMBARK;
+
 			break;
 			break;
 		case EPathfindingLayer::SAIL:
 		case EPathfindingLayer::SAIL:
 			if(!canMoveBetween(cp->coord, dp->coord) || dp->accessible == CGPathNode::BLOCKED)
 			if(!canMoveBetween(cp->coord, dp->coord) || dp->accessible == CGPathNode::BLOCKED)
@@ -291,6 +290,16 @@ bool CPathfinder::isMovementToDestPossible()
 			if(isSourceGuarded() && !isDestinationGuardian()) // Can step into tile of guard
 			if(isSourceGuarded() && !isDestinationGuardian()) // Can step into tile of guard
 				return false;
 				return false;
 
 
+			if(cp->layer == EPathfindingLayer::LAND)
+			{
+				if(!obj)
+					return false;
+
+				if(obj->ID == Obj::BOAT)
+					destAction = CGPathNode::EMBARK;
+				else if(obj->ID != Obj::HERO)
+					return false;
+			}
 			break;
 			break;
 
 
 		case EPathfindingLayer::AIR:
 		case EPathfindingLayer::AIR:
@@ -308,6 +317,29 @@ bool CPathfinder::isMovementToDestPossible()
 			break;
 			break;
 	}
 	}
 
 
+	if(destAction == CGPathNode::UNKNOWN)
+	{
+		destAction = CGPathNode::NORMAL;
+		if(dp->layer == EPathfindingLayer::LAND || dp->layer == EPathfindingLayer::SAIL)
+		{
+			if(obj)
+			{
+				if(obj->ID == Obj::HERO || obj->ID == Obj::TOWN)
+				{
+					if(getPlayerRelations(obj->tempOwner, hero->tempOwner) == PlayerRelations::ENEMIES)
+						destAction = CGPathNode::BATTLE;
+					else
+						destAction = CGPathNode::BLOCKING_VISIT; // TODO: Probably you should be able to go into air from town too
+				}
+				else if(obj->blockVisit)
+					destAction = CGPathNode::BLOCKING_VISIT;
+				else
+					destAction = CGPathNode::VISIT;
+			}
+			else if(isDestinationGuarded())
+				destAction = CGPathNode::BATTLE;
+		}
+	}
 
 
 	return true;
 	return true;
 }
 }
@@ -330,7 +362,7 @@ bool CPathfinder::isMovementAfterDestPossible()
 				if(!whirlpool || options.useTeleportWhirlpool)
 				if(!whirlpool || options.useTeleportWhirlpool)
 					return true;
 					return true;
 			}
 			}
-			if(useEmbarkCost && options.useEmbarkAndDisembark)
+			if((destAction == CGPathNode::EMBARK || destAction == CGPathNode::DISEMBARK) && options.useEmbarkAndDisembark)
 				return true;
 				return true;
 			break;
 			break;
 
 
@@ -527,6 +559,7 @@ void CGPathNode::reset()
 	moveRemains = 0;
 	moveRemains = 0;
 	turns = 255;
 	turns = 255;
 	theNodeBefore = nullptr;
 	theNodeBefore = nullptr;
+	action = UNKNOWN;
 }
 }
 
 
 bool CGPathNode::reachable() const
 bool CGPathNode::reachable() const

+ 13 - 1
lib/CPathfinder.h

@@ -23,6 +23,17 @@ struct TerrainTile;
 
 
 struct DLL_LINKAGE CGPathNode
 struct DLL_LINKAGE CGPathNode
 {
 {
+	enum ENodeAction
+	{
+		UNKNOWN = -1,
+		NORMAL = 0,
+		EMBARK = 1,
+		DISEMBARK, //2
+		BATTLE,//3
+		VISIT,//4
+		BLOCKING_VISIT//5
+	};
+
 	enum EAccessibility
 	enum EAccessibility
 	{
 	{
 		NOT_SET = 0,
 		NOT_SET = 0,
@@ -40,6 +51,7 @@ struct DLL_LINKAGE CGPathNode
 	CGPathNode * theNodeBefore;
 	CGPathNode * theNodeBefore;
 	int3 coord; //coordinates
 	int3 coord; //coordinates
 	EPathfindingLayer layer;
 	EPathfindingLayer layer;
+	ENodeAction action;
 
 
 	CGPathNode(int3 Coord, EPathfindingLayer Layer);
 	CGPathNode(int3 Coord, EPathfindingLayer Layer);
 	void reset();
 	void reset();
@@ -120,7 +132,7 @@ private:
 	CGPathNode *dp; //destination node -> it's a neighbour of cp that we consider
 	CGPathNode *dp; //destination node -> it's a neighbour of cp that we consider
 	const TerrainTile *ct, *dt; //tile info for both nodes
 	const TerrainTile *ct, *dt; //tile info for both nodes
 	const CGObjectInstance *sTileObj;
 	const CGObjectInstance *sTileObj;
-	ui8 useEmbarkCost; //0 - usual movement; 1 - embark; 2 - disembark
+	CGPathNode::ENodeAction destAction;
 
 
 	void addNeighbours(const int3 &coord);
 	void addNeighbours(const int3 &coord);
 	void addTeleportExits(bool noTeleportExcludes = false);
 	void addTeleportExits(bool noTeleportExcludes = false);