Quellcode durchsuchen

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 vor 10 Jahren
Ursprung
Commit
82048cbf2d
2 geänderte Dateien mit 58 neuen und 13 gelöschten Zeilen
  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);
 			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);
 				if(dp->accessible == CGPathNode::NOT_SET)
 					continue;
@@ -117,14 +116,15 @@ void CPathfinder::calculatePaths()
 				if(cp->layer != i && !isLayerTransitionPossible())
 					continue;
 
+				destAction = CGPathNode::UNKNOWN;
 				if(!isMovementToDestPossible())
 					continue;
 
 				int cost = gs->getMovementCost(hero, cp->coord, dp->coord, movement);
 				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;
 				}
 
@@ -144,6 +144,7 @@ void CPathfinder::calculatePaths()
 					dp->moveRemains = remains;
 					dp->turns = turnAtNextTile;
 					dp->theNodeBefore = cp;
+					dp->action = destAction;
 
 					if(isMovementAfterDestPossible())
 						pq.push(dp);
@@ -166,6 +167,7 @@ void CPathfinder::calculatePaths()
 					dp->moveRemains = movement;
 					dp->turns = turn;
 					dp->theNodeBefore = cp;
+					dp->action = CGPathNode::NORMAL;
 					pq.push(dp);
 				}
 			}
@@ -258,24 +260,18 @@ bool CPathfinder::isLayerTransitionPossible()
 		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
 			return false;
-
-		useEmbarkCost = 2;
 	}
 	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;
-		if(destTopVisObjID == Obj::BOAT)
-			useEmbarkCost = 1;
 	}
 	return true;
 }
 
 bool CPathfinder::isMovementToDestPossible()
 {
+	auto obj = dt->topVisitableObj();
 	switch(dp->layer)
 	{
 		case EPathfindingLayer::LAND:
@@ -284,6 +280,9 @@ bool CPathfinder::isMovementToDestPossible()
 			if(isSourceGuarded() && !isDestinationGuardian()) // Can step into tile of guard
 				return false;
 
+			if(cp->layer == EPathfindingLayer::SAIL)
+				destAction = CGPathNode::DISEMBARK;
+
 			break;
 		case EPathfindingLayer::SAIL:
 			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
 				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;
 
 		case EPathfindingLayer::AIR:
@@ -308,6 +317,29 @@ bool CPathfinder::isMovementToDestPossible()
 			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;
 }
@@ -330,7 +362,7 @@ bool CPathfinder::isMovementAfterDestPossible()
 				if(!whirlpool || options.useTeleportWhirlpool)
 					return true;
 			}
-			if(useEmbarkCost && options.useEmbarkAndDisembark)
+			if((destAction == CGPathNode::EMBARK || destAction == CGPathNode::DISEMBARK) && options.useEmbarkAndDisembark)
 				return true;
 			break;
 
@@ -527,6 +559,7 @@ void CGPathNode::reset()
 	moveRemains = 0;
 	turns = 255;
 	theNodeBefore = nullptr;
+	action = UNKNOWN;
 }
 
 bool CGPathNode::reachable() const

+ 13 - 1
lib/CPathfinder.h

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