Bläddra i källkod

* reverted pathfinder with necessary updates including handling of visitDir and code cleanup (needs a bit of testing but Zamolxis will probably do it for us ;])

mateuszb 17 år sedan
förälder
incheckning
32505ec161
6 ändrade filer med 172 tillägg och 452 borttagningar
  1. 4 5
      CAdvmapInterface.cpp
  2. 2 2
      CCallback.cpp
  3. 1 1
      CMT.cpp
  4. 148 354
      CPathfinder.cpp
  5. 14 87
      CPathfinder.h
  6. 3 3
      CPlayerInterface.cpp

+ 4 - 5
CAdvmapInterface.cpp

@@ -414,11 +414,10 @@ endchkpt:
 		int3 bufpos = currentHero->getPosition(false);
 		if (mres)
 		{
-			vector<Coordinate>* p;
-			p = CGI->pathf->GetPath(Coordinate(bufpos),Coordinate(mp),currentHero);
-			//Convert to old format.
-			currentPath = LOCPLINT->adventureInt->heroList.items[LOCPLINT->adventureInt->heroList.selected].second = CGI->pathf->ConvertToOldFormat(p);
-			delete p;
+			CPath * path;
+			path = CGI->pathf->getPath(bufpos, mp, currentHero);
+			//assign
+			currentPath = LOCPLINT->adventureInt->heroList.items[LOCPLINT->adventureInt->heroList.selected].second = path;
 		}
 		return;
 	}

+ 2 - 2
CCallback.cpp

@@ -32,14 +32,14 @@ int gcd(int x, int y)
 {
 	int temp;
 	if (y > x)
-		swap(x,y);
+		std::swap(x,y);
 	while (y != 0)
 	{
 		temp = y;
 		y = x-y;
 		x = temp;
 		if (y > x)
-			swap(x,y);
+			std::swap(x,y);
 	}
 	return x;
 }

+ 1 - 1
CMT.cpp

@@ -65,7 +65,7 @@ int main(int argc, char** argv)
 	CClient *client = NULL;
 	boost::thread *console = NULL;
 
-	std::cout.flags(ios::unitbuf);
+	std::cout.flags(std::ios::unitbuf);
 	logfile = new std::ofstream("VCMI_Client_log.txt");
 	::console = new CConsoleHandler;
 	*::console->cb = boost::bind(processCommand,_1,boost::ref(client));

+ 148 - 354
CPathfinder.cpp

@@ -8,371 +8,152 @@
 #include "hch/CObjectHandler.h"
 #include "hch/CDefObjInfoHandler.h"
 
-using namespace std;
+using namespace boost::logic;
 
-vector<Coordinate>* CPathfinder::GetPath(Coordinate start, Coordinate end, const CGHeroInstance* hero)
+int3 CPath::startPos()
 {
-	Start = start;
-	End = end;
-	return GetPath(hero);
+	return int3(nodes[nodes.size()-1].coord.x,nodes[nodes.size()-1].coord.y,nodes[nodes.size()-1].coord.z);
+}
+int3 CPath::endPos()
+{
+	return int3(nodes[0].coord.x,nodes[0].coord.y,nodes[0].coord.z);
 }
 
-/*
- * Does basic input checking and setup for the path calculation.
-*/
-vector<Coordinate>* CPathfinder::GetPath(const CGHeroInstance* hero)
+CPath * CPathfinder::getPath(int3 src, int3 dest, const CGHeroInstance * hero, unsigned char type) //TODO: test it (seems to be finished, but relies on unwritten functions :()
 {
 	//check input
-	if ((Start.x < 0)||(Start.y < 0)||(Start.z < 0)||(End.x < 0)||(End.y < 0)||(End.z < 0))
+	if ((src.x < 0)||(src.y < 0)||(src.z < 0)||(dest.x < 0)||(dest.y < 0)||(dest.z < 0))
 	{
 		return NULL;
 	}
-	if ((Start.x >= CGI->mh->sizes.x)||(Start.y >= CGI->mh->sizes.y)||(Start.z >= CGI->mh->sizes.z)
-			||(End.x >= CGI->mh->sizes.x)||(End.y >= CGI->mh->sizes.y)||(End.z >= CGI->mh->sizes.z))
+	if ((src.x >= CGI->mh->sizes.x)||(src.y >= CGI->mh->sizes.y)||(src.z >= CGI->mh->sizes.z)
+			||(dest.x >= CGI->mh->sizes.x)||(dest.y >= CGI->mh->sizes.y)||(dest.z >= CGI->mh->sizes.z))
 	{
 		return NULL;
 	}
 
-	Hero = hero;
+	int3 hpos = hero->getPosition(false);
 
-	//Reset the queues
-	Open = priority_queue < vector<Coordinate>, vector<vector<Coordinate> >, Compare>();
-	Closed.clear();
-
-	//Determine if the hero can move on water
-	int3 hpos = Hero->getPosition(false);
-	if (!Hero->canWalkOnSea())
+	tribool blockLandSea; //true - blocks sea, false - blocks land, indeterminate - allows all
+	if (!hero->canWalkOnSea())
 	{
-		if (CGI->mh->ttiles[hpos.x][hpos.y][hpos.z].tileInfo->tertype==water)
+		if (CGI->mh->ttiles[hpos.x][hpos.y][hpos.z].tileInfo->tertype==EterrainType::water)
 			blockLandSea=false;
 		else
 			blockLandSea=true;
 	}
 	else
 	{
-		blockLandSea = boost::logic::indeterminate;
-	}
-
-	CalcG(&Start);
-	Start.h = 0;
-	CalcG(&End);
-	CalcH(&End);
-
-	//If it is impossible to get to where the user clicked, dont return a path.
-	if(End.h == -1)
-	{
-		return NULL;
+		blockLandSea = indeterminate;
 	}
 
-	//Add the Start node to the open list.
-	vector<Coordinate> startPath;
-	startPath.push_back(Start);
-	Open.push(startPath);
-
-	//Calculate the path.
-	vector<Coordinate>* toReturn =  CalcPath();
-
-	if(toReturn != NULL)
+	//graph initialization
+	graph.resize(CGI->mh->sizes.x);
+	for(int i=0; i<graph.size(); ++i)
 	{
-		//Flip the route since it is calculated in reverse
-		int size = toReturn->size();
-		for(int i = 0; i < size/2; i++)
+		graph[i].resize(CGI->mh->sizes.y);
+		for(int j=0; j<graph[i].size(); ++j)
 		{
-			Coordinate t = toReturn->at(i);
-			(*toReturn)[i] = toReturn->at(size-1-i);
-			(*toReturn)[size-1-i] = t;
+			graph[i][j].accesible = !CGI->mh->ttiles[i][j][src.z].tileInfo->blocked;
+			if(i==dest.x && j==dest.y && CGI->mh->ttiles[i][j][src.z].tileInfo->visitable)
+				graph[i][j].accesible = true; //for allowing visiting objects
+			graph[i][j].dist = -1;
+			graph[i][j].theNodeBefore = NULL;
+			graph[i][j].visited = false;
+			graph[i][j].coord.x = i;
+			graph[i][j].coord.y = j;
+			graph[i][j].coord.z = dest.z;
+			if (CGI->mh->ttiles[i][j][src.z].tileInfo->tertype==EterrainType::rock)
+				graph[i][j].accesible = false;
+			if ((blockLandSea) && (CGI->mh->ttiles[i][j][src.z].tileInfo->tertype==EterrainType::water))
+				graph[i][j].accesible = false;
+			else if ((!blockLandSea) && (CGI->mh->ttiles[i][j][src.z].tileInfo->tertype!=EterrainType::water))
+				graph[i][j].accesible = false;
+			if(graph[i][j].accesible)
+				graph[i][j].accesible = CGI->state->players[hero->tempOwner].fogOfWarMap[i][j][src.z];
 		}
 	}
 
-	return toReturn;
-}
+	//graph initialized
 
-/*
- * Does the actual path calculation.  Don't call this directly, call GetPath instead.
-*/
-vector<Coordinate>* CPathfinder::CalcPath()
-{
-	if(Open.empty())
-	{
-		return NULL;
-	}
+	graph[src.x][src.y].dist = 0;
 
-	//Find the path in open with the smallest cost (f = g + h)
-	//and remove it from open
-	vector<Coordinate>* branch = new vector<Coordinate>();
-	*branch = Open.top();
-	Open.pop();
+	std::queue<CPathNode> mq;
+	mq.push(graph[src.x][src.y]);
 
-	//Don't search elements in the closed list, for they have been visited already.
-	if(!ExistsInClosed(branch->back()))
-	{
-		//Add it to the closed list.
-		Closed.push_back(branch->back());
+	unsigned int curDist = 4000000000;
 
-		//If it is the destination
-		if(branch->back().x == End.x && branch->back().y == End.y && branch->back().z == End.z)
+	while(!mq.empty())
+	{
+		CPathNode cp = mq.front();
+		mq.pop();
+		if ((cp.coord.x == dest.x) && (cp.coord.y==dest.y))
 		{
-			return branch;
+			if (cp.dist < curDist)
+				curDist=cp.dist;
 		}
-
-		//Add neighbors to the open list
-		AddNeighbors(branch);
-	}
-	delete branch;
-
-	return CalcPath();
-}
-
-/*
- * Determines if the given node exists in the closed list, returns true if it does.  This is
- * used to ensure you dont check the same node twice.
-*/
-bool CPathfinder::ExistsInClosed(const Coordinate & node) const
-{
-	for(int i = 0; i < Closed.size(); i++)
-	{
-		if(node.x == Closed[i].x && node.y == Closed[i].y && node.z == Closed[i].z)
-			return true;
-	}
-
-	return false;
-}
-
-/*
- * Adds the neighbors of the current node to the open cue so they can be considered in the
- * path creation.  If the node has a cost (f = g + h) less than zero, it isn't added to Open.
-*/
-void CPathfinder::AddNeighbors(vector<Coordinate>* branch)
-{
-	//8 possible Nodes to add
-	//
-	//   1  2  3
-	//   4  X  5
-	//   6  7  8
-
-	Coordinate node = branch->back();
-	Coordinate c;
-
-	for(int i = node.x-1; i<node.x+2;i++)
-	{
-		for(int j = node.y-1; j < node.y+2; j++)
+		else
 		{
-			if(i >= 0 && j >= 0 && i < CGI->mh->sizes.x && j < CGI->mh->sizes.y && (i!=node.x || j!=node.y))
-			{
-				c = Coordinate(i,j,node.z);
-
-				//Calculate the distance from the end node
-				CalcG(&c);
-
-				//Calculate the movement cost
-				CalcH(&c);
-
-				if(i!=node.x && j!=node.y)
-					c.diagonal = true;
-				else
-					c.diagonal = false;
-
-				if(c.g != -1 && c.h != -1)
-				{
-					bool pass = true; //checking for allowed visiting direction
-					for(int b=0; b<CGI->mh->ttiles[i][j][node.z].tileInfo->visitableObjects.size(); ++b) //checking destination tile
-					{
-						const TerrainTile * pom = CGI->mh->ttiles[i][j][node.z].tileInfo;
-						if(!vstd::contains(pom->blockingObjects,pom->visitableObjects[b]))
-							break;
-						CGDefInfo * di = pom->visitableObjects[b]->defInfo;
-						if( (i == node.x-1 && j == node.y-1) && !(di->visitDir & (1<<4)) )
-						{
-							pass = false; break;
-						}
-						if( (i == node.x && j == node.y-1) && !(di->visitDir & (1<<5)) )
-						{
-							pass = false; break;
-						}
-						if( (i == node.x+1 && j == node.y-1) && !(di->visitDir & (1<<6)) )
-						{
-							pass = false; break;
-						}
-						if( (i == node.x+1 && j == node.y) && !(di->visitDir & (1<<7)) )
-						{
-							pass = false; break;
-						}
-						if( (i == node.x+1 && j == node.y+1) && !(di->visitDir & (1<<0)) )
-						{
-							pass = false; break;
-						}
-						if( (i == node.x && j == node.y+1) && !(di->visitDir & (1<<1)) )
-						{
-							pass = false; break;
-						}
-						if( (i == node.x-1 && j == node.y+1) && !(di->visitDir & (1<<2)) )
-						{
-							pass = false; break;
-						}
-						if( (i == node.x-1 && j == node.y) && !(di->visitDir & (1<<3)) )
-						{
-							pass = false; break;
-						}
-					}
-					for(int b=0; b<CGI->mh->ttiles[node.x][node.y][node.z].tileInfo->visitableObjects.size(); ++b) //checking source tile
-					{
-						const TerrainTile * pom = CGI->mh->ttiles[node.x][node.y][node.z].tileInfo;
-						if(!vstd::contains(pom->blockingObjects,pom->visitableObjects[b]))
-							break;
-						CGDefInfo * di = pom->visitableObjects[b]->defInfo;
-						if( (i == node.x-1 && j == node.y-1) && !(di->visitDir & (1<<0)) )
-						{
-							pass = false; break;
-						}
-						if( (i == node.x && j == node.y-1) && !(di->visitDir & (1<<1)) )
-						{
-							pass = false; break;
-						}
-						if( (i == node.x+1 && j == node.y-1) && !(di->visitDir & (1<<2)) )
-						{
-							pass = false; break;
-						}
-						if( (i == node.x+1 && j == node.y) && !(di->visitDir & (1<<3)) )
-						{
-							pass = false; break;
-						}
-						if( (i == node.x+1 && j == node.y+1) && !(di->visitDir & (1<<4)) )
-						{
-							pass = false; break;
-						}
-						if( (i == node.x && j == node.y+1) && !(di->visitDir & (1<<5)) )
-						{
-							pass = false; break;
-						}
-						if( (i == node.x-1 && j == node.y+1) && !(di->visitDir & (1<<6)) )
-						{
-							pass = false; break;
-						}
-						if( (i == node.x-1 && j == node.y) && !(di->visitDir & (1<<7)) )
-						{
-							pass = false; break;
-						}
-					}
-					if(pass)
-					{
-						vector<Coordinate> toAdd = *branch;
-						toAdd.push_back(c);
-						Open.push(toAdd);
-					}
-				}
-			}
+			if (cp.dist > curDist)
+				continue;
 		}
-	}
-
-}
-
-/*
- * Calculates the movement cost of the node.  Returns -1 if it is impossible to travel on.
-*/
-void CPathfinder::CalcH(Coordinate* node)
-{
-	/*
-	 * If the terrain is blocked
-	 * If the terrain is rock
-	 * If the Hero cant walk on water and node is in water
-	 * If the Hero is on water and the node is not.
-	 * If there is fog of war on the node.
-	 *  => Impossible to move there.
-	 */
-	const TerrainTile *pom = CGI->mh->ttiles[node->x][node->y][node->z].tileInfo;
-	if( (pom->blocked && !(node->x==End.x && node->y==End.y && pom->visitable)) ||
-		(pom->tertype==rock) ||
-		((blockLandSea) && (pom->tertype==water)) ||
-		(!CGI->state->players[Hero->tempOwner].fogOfWarMap[node->x][node->y][node->z]) ||
-		((!blockLandSea) && (pom->tertype!=water)))
-	{
-		//Impossible.
-
-		node->h = -1;
-		return;
-	}
-
-	int ret=-1;
-	int x = node->x;
-	int y = node->y;
-	if(node->x>=CGI->mh->map->width)
-		x = CGI->mh->map->width-1;
-	if(node->y>=CGI->mh->map->height)
-		y = CGI->mh->map->height-1;
-
-	//Get the movement cost.
-	ret = Hero->getTileCost(CGI->mh->ttiles[x][y][node->z].tileInfo->tertype, CGI->mh->map->terrain[x][y][node->z].malle,CGI->mh->map->terrain[x][y][node->z].nuine);
-
-	node->h = ret;
-}
-
-/*
- * Calculates distance from node to end node.
-*/
-void CPathfinder::CalcG(Coordinate* node)
-{
-	float dist = (End.x-node->x) * (End.x-node->x) + (End.y-node->y) * (End.y-node->y);
-	node->g = sqrt(dist);
-	return;
-}
-
-/*
- * Converts the old Pathfinder format for compatibility reasons. This should be replaced
- * eventually by making the need for it obsolete.
-*/
-CPath* CPathfinder::ConvertToOldFormat(vector<Coordinate>* p)
-{
-	if(p == NULL)
-		return NULL;
-
-	CPath* path = new CPath();
-
-	std::vector<int> costs; //vector with costs of tiles
-
-	for(int i = 0; i < p->size(); i++)
-	{
-		CPathNode temp;
-
-		//Set coord
-		temp.coord = int3(p->at(i).x,p->at(i).y,p->at(i).z);
-
-		//Set accesible
-		if(p->at(i).h == -1)
+		if(cp.coord.x>0)
 		{
-			temp.accesible = false;
+			CPathNode & dp = graph[cp.coord.x-1][cp.coord.y];
+			processNode(dp, hero, mq, cp, src, false);
 		}
-		else
+		if(cp.coord.y>0)
 		{
-			temp.accesible = true;
+			CPathNode & dp = graph[cp.coord.x][cp.coord.y-1];
+			processNode(dp, hero, mq, cp, src, false);
 		}
-		//set diagonality
-		float diagonal = 1.0f; //by default
-		if(i>0)
+		if(cp.coord.x>0 && cp.coord.y>0)
 		{
-			if(p->at(i-1).x != temp.coord.x && p->at(i-1).y != temp.coord.y)
-			{
-				diagonal = sqrt(2.0f);
-			}
+			CPathNode & dp = graph[cp.coord.x-1][cp.coord.y-1];
+			processNode(dp, hero, mq, cp, src, true);
 		}
+		if(cp.coord.x<graph.size()-1)
+		{
+			CPathNode & dp = graph[cp.coord.x+1][cp.coord.y];
+			processNode(dp, hero, mq, cp, src, false);
+		}
+		if(cp.coord.y<graph[0].size()-1)
+		{
+			CPathNode & dp = graph[cp.coord.x][cp.coord.y+1];
+			processNode(dp, hero, mq, cp, src, false);
+		}
+		if(cp.coord.x<graph.size()-1 && cp.coord.y<graph[0].size()-1)
+		{
+			CPathNode & dp = graph[cp.coord.x+1][cp.coord.y+1];
+			processNode(dp, hero, mq, cp, src, true);
+		}
+		if(cp.coord.x>0 && cp.coord.y<graph[0].size()-1)
+		{
+			CPathNode & dp = graph[cp.coord.x-1][cp.coord.y+1];
+			processNode(dp, hero, mq, cp, src, true);
+		}
+		if(cp.coord.x<graph.size()-1 && cp.coord.y>0)
+		{
+			CPathNode & dp = graph[cp.coord.x+1][cp.coord.y-1];
+			processNode(dp, hero, mq, cp, src, true);
+		}
+	}
 
-		//Set distance
-		costs.push_back( i==0 ? 0 : p->at(i - 1).h * diagonal );
-
-		//theNodeBefore is never used outside of pathfinding?
-
-		//Set visited
-		temp.visited = false;
+	CPathNode curNode = graph[dest.x][dest.y];
+	if(!curNode.theNodeBefore)
+		return NULL;
 
-		path->nodes.push_back(temp);
-	}
+	CPath * ret = new CPath;
 
-	costs.push_back(0);
-	for(int i=path->nodes.size()-1; i>=0; --i)
+	while(curNode.coord!=graph[src.x][src.y].coord)
 	{
-		path->nodes[i].dist = costs[i+1] + ((i == path->nodes.size()-1) ? 0 : path->nodes[i+1].dist);
+		ret->nodes.push_back(curNode);
+		curNode = *(curNode.theNodeBefore);
 	}
 
-	return path;
+	ret->nodes.push_back(graph[src.x][src.y]);
+
+	return ret;
 }
 
 void CPathfinder::convertPath(CPath * path, unsigned int mode) //mode=0 -> from 'manifest' to 'object'
@@ -386,47 +167,60 @@ void CPathfinder::convertPath(CPath * path, unsigned int mode) //mode=0 -> from
 	}
 }
 
-int3 CPath::startPos() const
-{
-	return int3(nodes[nodes.size()-1].coord.x,nodes[nodes.size()-1].coord.y,nodes[nodes.size()-1].coord.z);
-}
-int3 CPath::endPos() const
-{
-	return int3(nodes[0].coord.x,nodes[0].coord.y,nodes[0].coord.z);
-}
-
-/*
- * The function used by the priority cue to determine which node to put at the top.
-*/
-bool Compare::operator()(const vector<Coordinate>& a, const vector<Coordinate>& b)
+void CPathfinder::processNode(CPathNode & dp, const CGHeroInstance * hero, std::queue<CPathNode> & mq, const CPathNode & cp, const int3 & src, bool diagonal)
 {
-	double aTotal=0;
-	double bTotal=0;
-
-	for(int i = 0; i < a.size(); i++)
-	{
-		double add = a[i].g*a[i].h;
-		if(a[i].diagonal)
-			add*=1.41421356;
-		aTotal += add;
-	}
-	for(int i = 0; i < b.size(); i++)
+	const TerrainTile * tinfo = CGI->mh->ttiles[dp.coord.x][dp.coord.y][src.z].tileInfo;
+	int cost = hero->getTileCost(tinfo->tertype, tinfo->malle, tinfo->nuine);
+	if(diagonal)
+		cost *= std::sqrt(2.0);
+	if((dp.dist==-1 || (dp.dist > cp.dist + cost)) && dp.accesible && checkForVisitableDir(cp.coord, dp.coord) && checkForVisitableDir(dp.coord, cp.coord))
 	{
-		double add = b[i].g*b[i].h;
-		if(b[i].diagonal)
-			add*=1.41421356;
-		bTotal += add;
+		dp.dist = cp.dist + cost;
+		dp.theNodeBefore = &graph[cp.coord.x][cp.coord.y];
+		mq.push(dp);
 	}
-
-	return aTotal > bTotal;
 }
 
-void Coordinate::operator =(const Coordinate &other)
+bool CPathfinder::checkForVisitableDir(const int3 & src, const int3 & dst) const
 {
-	this->x = other.x;
-	this->y = other.y;
-	this->z = other.z;
-	this->g = other.g;
-	this->h = other.h;
-	this->diagonal = other.diagonal;
+	for(int b=0; b<CGI->mh->ttiles[dst.x][dst.y][dst.z].tileInfo->visitableObjects.size(); ++b) //checking destination tile
+	{
+		const TerrainTile * pom = CGI->mh->ttiles[dst.x][dst.y][dst.z].tileInfo;
+		if(!vstd::contains(pom->blockingObjects, pom->visitableObjects[b]))
+			continue;
+		CGDefInfo * di = pom->visitableObjects[b]->defInfo;
+		if( (dst.x == src.x-1 && dst.y == src.y-1) && !(di->visitDir & (1<<4)) )
+		{
+			return false;
+		}
+		if( (dst.x == src.x && dst.y == src.y-1) && !(di->visitDir & (1<<5)) )
+		{
+			return false;
+		}
+		if( (dst.x == src.x+1 && dst.y == src.y-1) && !(di->visitDir & (1<<6)) )
+		{
+			return false;
+		}
+		if( (dst.x == src.x+1 && dst.y == src.y) && !(di->visitDir & (1<<7)) )
+		{
+			return false;
+		}
+		if( (dst.x == src.x+1 && dst.y == src.y+1) && !(di->visitDir & (1<<0)) )
+		{
+			return false;
+		}
+		if( (dst.x == src.x && dst.y == src.y+1) && !(di->visitDir & (1<<1)) )
+		{
+			return false;
+		}
+		if( (dst.x == src.x-1 && dst.y == src.y+1) && !(di->visitDir & (1<<2)) )
+		{
+			return false;
+		}
+		if( (dst.x == src.x-1 && dst.y == src.y) && !(di->visitDir & (1<<3)) )
+		{
+			return false;
+		}
+	}
+	return true;
 }

+ 14 - 87
CPathfinder.h

@@ -1,38 +1,11 @@
-#ifndef CPathfinder_H
-#define CPathfinder_H
+#ifndef CPATHFINDER_H
+#define CPATHFINDER_H
 #include "global.h"
-#include <vector>
 #include <queue>
-#include <math.h>
-class CGHeroInstance;
-
-using namespace std;
-
-class Coordinate
-{
-public:
-	int x;
-	int y;
-	int z;
-	float g; //Distance from goal
-	int h; //Movement cost
-	bool diagonal; //if true, this tile will be crossed by diagonal
-
-	Coordinate() : x(NULL), y(NULL), z(NULL), g(NULL), h(NULL), diagonal(false) {}
-	Coordinate(int3 xyz) : x(xyz.x), y(xyz.y), z(xyz.z), diagonal(false){}
-	Coordinate(int xCor, int yCor, int zCor) : x(xCor), y(yCor), z(zCor), diagonal(false){}
-	Coordinate(int xCor, int yCor, int zCor, int dist, int penalty) : x(xCor), y(yCor), z(zCor), g(dist), h(penalty), diagonal(false){}
-	void operator=(const Coordinate& other);
-};
+#include <vector>
 
-//Class used in priority queue to determine order.
-class Compare
-{
-public:
-	bool operator()(const vector<Coordinate>& a, const vector<Coordinate>& b);
-};
+class CGHeroInstance;
 
-//Included for old format
 struct CPathNode
 {
 	bool accesible; //true if a hero can be on this node
@@ -42,74 +15,28 @@ struct CPathNode
 	bool visited;
 };
 
-//Included for old format
 struct CPath
 {
 	std::vector<CPathNode> nodes; //just get node by node
 
-	int3 startPos() const; // start point
-	int3 endPos() const; //destination point
+	int3 startPos(); // start point
+	int3 endPos(); //destination point
 };
 
+/**
+ * main pathfinder class
+ */
 class CPathfinder
 {
 private:
-	boost::logic::tribool blockLandSea; //true - blocks sea, false - blocks land, indeterminate - allows all
-
-	/*
-	 * Does the actual path calculation.  Don't call this directly, call GetPath instead.
-	 */
-	vector<Coordinate>* CalcPath();
-
-	/*
- 	 * Determines if the given node exists in the closed list, returns true if it does.  This is
-	 * used to ensure you dont check the same node twice.
-	 */
-	bool ExistsInClosed(const Coordinate & node) const;
-
-	/*
-	 * Adds the neighbors of the current node to the open cue so they can be considered in the
-	 * path creation.  If the node has a cost (f = g + h) less than zero, it isn't added to Open.
-	 */
-	void AddNeighbors(vector<Coordinate>* node);
-
-	/*
-	 * Calculates the movement cost of the node.  Returns -1 if it is impossible to travel on.
-	 */
-	void CalcH(Coordinate* node);
-
-	/*
-	 * Calculates distance from node to end node.
-	 */
-	void CalcG(Coordinate* node);
-
+	std::vector< std::vector<CPathNode> > graph;
+	void processNode(CPathNode & dp, const CGHeroInstance * hero, std::queue<CPathNode> & mq, const CPathNode & cp, const int3 & src, bool diagonal); //helper function for getPath
+	bool checkForVisitableDir(const int3 & src, const int3 & dst) const;
 public:
-	//Contains nodes to be searched
-	priority_queue < vector<Coordinate>, vector<vector<Coordinate> >, Compare > Open;
-
-	//History of nodes you have been to before
-	vector<Coordinate> Closed;
-
-	//The start, or source position.
-	Coordinate Start;
-
-	//The end, or destination position
-	Coordinate End;
-
-	//A reference to the Hero.
-	const CGHeroInstance* Hero;
-
-	/*
-	 * Does basic input checking and setup for the path calculation.
-	 */
-	vector<Coordinate>* GetPath(const CGHeroInstance* hero);
-	vector<Coordinate>* GetPath(Coordinate start, Coordinate end, const CGHeroInstance* hero);
-
-	//Convert to oldformat
-	CPath* ConvertToOldFormat(vector<Coordinate>* p);
+	CPath * getPath(int3 src, int3 dest, const CGHeroInstance * hero, unsigned char type=0); //calculates path between src and dest; returns pointer to CPath or NULL if path does not exists; type - type of calculation: 0 - positions are normal positions of hero; 1 - given places are tiles blocked by hero
+	CPath * getPath(const int3 & src, const int3 & dest, const CGHeroInstance * hero, int (*getDist)(int3 & a, int3 & b), unsigned char type=0); //calculates path between src and dest; returns pointer to CPath or NULL if path does not exists; uses getDist to calculate distance; type - type of calculation: 0 - positions are normal positions of hero; 1 - given places are tiles blocked by hero
 
 	static void convertPath(CPath * path, unsigned int mode); //mode=0 -> from 'manifest' to 'object'
-
 };
 
 #endif //CPATHFINDER_H

+ 3 - 3
CPlayerInterface.cpp

@@ -2305,7 +2305,7 @@ CStatusBar::CStatusBar(int x, int y, std::string name, int maxw)
 	pos.x=x;
 	pos.y=y;
 	if(maxw >= 0)
-		pos.w = min(bg->w,maxw);
+		pos.w = std::min(bg->w,maxw);
 	else
 		pos.w=bg->w;
 	pos.h=bg->h;
@@ -2908,7 +2908,7 @@ void CRecrutationWindow::clickLeft(tribool down)
 		if(isItIn(&genRect(132,102,pos.x+curx,pos.y+64),LOCPLINT->current->motion.x,LOCPLINT->current->motion.y))
 		{
 			which = i;
-			int newAmount = min(amounts[i],creatures[i].amount);
+			int newAmount = std::min(amounts[i],creatures[i].amount);
 			slider->amount = newAmount;
 			if(slider->value > newAmount)
 				slider->moveTo(newAmount);
@@ -3005,7 +3005,7 @@ CRecrutationWindow::CRecrutationWindow(const std::vector<std::pair<int,int> > &C
 	pos.y = screen->h/2 - bitmap->h/2;
 	pos.w = bitmap->w;
 	pos.h = bitmap->h;
-	slider = new CSlider(pos.x+176,pos.y+279,135,boost::bind(&CRecrutationWindow::sliderMoved,this, _1),1,min(amounts[0],creatures[0].amount),0,true);
+	slider = new CSlider(pos.x+176,pos.y+279,135,boost::bind(&CRecrutationWindow::sliderMoved,this, _1),1,std::min(amounts[0],creatures[0].amount),0,true);
 	std::string pom;
 	printAtMiddle(CGI->generaltexth->allTexts[346],113,231,GEOR13,zwykly,bitmap); //cost per troop t
 	printAtMiddle(CGI->generaltexth->allTexts[465],205,231,GEOR13,zwykly,bitmap); //available t