CPathfinder.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. #include "stdafx.h"
  2. #include "global.h"
  3. #include "CPathfinder.h"
  4. #include "CGameInfo.h"
  5. #include "hch/CAmbarCendamo.h"
  6. #include "mapHandler.h"
  7. #include "CGameState.h"
  8. #include "hch/CObjectHandler.h"
  9. using namespace std;
  10. vector<Coordinate>* CPathfinder::GetPath(Coordinate start, Coordinate end, const CGHeroInstance* hero)
  11. {
  12. Start = start;
  13. End = end;
  14. return GetPath(hero);
  15. }
  16. /*
  17. * Does basic input checking and setup for the path calculation.
  18. */
  19. vector<Coordinate>* CPathfinder::GetPath(const CGHeroInstance* hero)
  20. {
  21. //check input
  22. if ((Start.x < 0)||(Start.y < 0)||(Start.z < 0)||(End.x < 0)||(End.y < 0)||(End.z < 0))
  23. {
  24. return NULL;
  25. }
  26. if ((Start.x >= CGI->mh->sizes.x)||(Start.y >= CGI->mh->sizes.y)||(Start.z >= CGI->mh->sizes.z)
  27. ||(End.x >= CGI->mh->sizes.x)||(End.y >= CGI->mh->sizes.y)||(End.z >= CGI->mh->sizes.z))
  28. {
  29. return NULL;
  30. }
  31. Hero = hero;
  32. //Reset the queues
  33. Open = priority_queue < vector<Coordinate>, vector<vector<Coordinate>>, Compare>();
  34. Closed.clear();
  35. //Determine if the hero can move on water
  36. int3 hpos = Hero->getPosition(false);
  37. if (!Hero->canWalkOnSea())
  38. {
  39. if (CGI->mh->ttiles[hpos.x][hpos.y][hpos.z].tileInfo->tertype==EterrainType::water)
  40. blockLandSea=false;
  41. else
  42. blockLandSea=true;
  43. }
  44. else
  45. {
  46. blockLandSea = boost::logic::indeterminate;
  47. }
  48. CalcG(&Start);
  49. Start.h = 0;
  50. CalcG(&End);
  51. CalcH(&End);
  52. //If it is impossible to get to where the user clicked, dont return a path.
  53. if(End.h == -1)
  54. {
  55. return NULL;
  56. }
  57. //Add the Start node to the open list.
  58. vector<Coordinate> startPath;
  59. startPath.push_back(Start);
  60. Open.push(startPath);
  61. //Calculate the path.
  62. vector<Coordinate>* toReturn = CalcPath();
  63. if(toReturn != NULL)
  64. {
  65. //Flip the route since it is calculated in reverse
  66. int size = toReturn->size();
  67. for(int i = 0; i < size/2; i++)
  68. {
  69. Coordinate t = toReturn->at(i);
  70. (*toReturn)[i] = toReturn->at(size-1-i);
  71. (*toReturn)[size-1-i] = t;
  72. }
  73. }
  74. return toReturn;
  75. }
  76. /*
  77. * Does the actual path calculation. Don't call this directly, call GetPath instead.
  78. */
  79. vector<Coordinate>* CPathfinder::CalcPath()
  80. {
  81. if(Open.empty())
  82. {
  83. return NULL;
  84. }
  85. //Find the path in open with the smallest cost (f = g + h)
  86. //and remove it from open
  87. vector<Coordinate>* branch = new vector<Coordinate>();
  88. *branch = Open.top();
  89. Open.pop();
  90. //Don't search elements in the closed list, for they have been visited already.
  91. if(!ExistsInClosed(branch->back()))
  92. {
  93. //Add it to the closed list.
  94. Closed.push_back(branch->back());
  95. //If it is the destination
  96. if(branch->back().x == End.x && branch->back().y == End.y && branch->back().z == End.z)
  97. {
  98. return branch;
  99. }
  100. //Add neighbors to the open list
  101. AddNeighbors(branch);
  102. }
  103. delete branch;
  104. return CalcPath();
  105. }
  106. /*
  107. * Determines if the given node exists in the closed list, returns true if it does. This is
  108. * used to ensure you dont check the same node twice.
  109. */
  110. bool CPathfinder::ExistsInClosed(Coordinate node)
  111. {
  112. for(int i = 0; i < Closed.size(); i++)
  113. {
  114. if(node.x == Closed[i].x && node.y == Closed[i].y && node.z == Closed[i].z)
  115. return true;
  116. }
  117. return false;
  118. }
  119. /*
  120. * Adds the neighbors of the current node to the open cue so they can be considered in the
  121. * path creation. If the node has a cost (f = g + h) less than zero, it isn't added to Open.
  122. */
  123. void CPathfinder::AddNeighbors(vector<Coordinate>* branch)
  124. {
  125. //8 possible Nodes to add
  126. //
  127. // 1 2 3
  128. // 4 X 5
  129. // 6 7 8
  130. Coordinate node = branch->back();
  131. Coordinate c;
  132. for(int i = node.x-1; i<node.x+2;i++)
  133. {
  134. for(int j = node.y-1; j < node.y+2; j++)
  135. {
  136. if(i >= 0 && j >= 0 && i < CGI->mh->sizes.x && j < CGI->mh->sizes.y)
  137. {
  138. c = Coordinate(i,j,node.z);
  139. //Calculate the distance from the end node
  140. CalcG(&c);
  141. //Calculate the movement cost
  142. CalcH(&c);
  143. if(c.g != -1 && c.h != -1)
  144. {
  145. vector<Coordinate> toAdd = *branch;
  146. toAdd.push_back(c);
  147. Open.push(toAdd);
  148. }
  149. //delete c;
  150. }
  151. }
  152. }
  153. }
  154. /*
  155. * Calculates the movement cost of the node. Returns -1 if it is impossible to travel on.
  156. */
  157. void CPathfinder::CalcH(Coordinate* node)
  158. {
  159. /*
  160. * If the terrain is blocked
  161. * If the terrain is rock
  162. * If the Hero cant walk on water and node is in water
  163. * If the Hero is on water and the node is not.
  164. * If there is fog of war on the node.
  165. * => Impossible to move there.
  166. */
  167. if( (CGI->mh->ttiles[node->x][node->y][node->z].tileInfo->blocked && !(node->x==End.x && node->y==End.y && CGI->mh->ttiles[node->x][node->y][node->z].tileInfo->visitable)) ||
  168. (CGI->mh->ttiles[node->x][node->y][node->z].tileInfo->tertype==EterrainType::rock) ||
  169. ((blockLandSea) && (CGI->mh->ttiles[node->x][node->y][node->z].tileInfo->tertype==EterrainType::water)) ||
  170. (!CGI->state->players[Hero->tempOwner].fogOfWarMap[node->x][node->y][node->z]) ||
  171. ((!blockLandSea) && (CGI->mh->ttiles[node->x][node->y][node->z].tileInfo->tertype!=EterrainType::water)))
  172. {
  173. //Impossible.
  174. node->h = -1;
  175. return;
  176. }
  177. int ret=-1;
  178. int x = node->x;
  179. int y = node->y;
  180. if(node->x>=CGI->mh->map->width)
  181. x = CGI->mh->map->width-1;
  182. if(node->y>=CGI->mh->map->height)
  183. y = CGI->mh->map->height-1;
  184. //Get the movement cost.
  185. ret = Hero->getTileCost(CGI->mh->ttiles[x][y][node->z].tileInfo->tertype, CGI->mh->map->terrain[x][y].malle,CGI->mh->map->terrain[x][y].nuine);
  186. node->h = ret;
  187. }
  188. /*
  189. * Calculates distance from node to end node.
  190. */
  191. void CPathfinder::CalcG(Coordinate* node)
  192. {
  193. float dist = (End.x-node->x) * (End.x-node->x) + (End.y-node->y) * (End.y-node->y);
  194. node->g = sqrt(dist);
  195. return;
  196. }
  197. /*
  198. * Converts the old Pathfinder format for compatibility reasons. This should be replaced
  199. * eventually by making the need for it obsolete.
  200. */
  201. CPath* CPathfinder::ConvertToOldFormat(vector<Coordinate>* p)
  202. {
  203. if(p == NULL)
  204. return NULL;
  205. CPath* path = new CPath();
  206. std::vector<int> costs; //vector with costs of tiles
  207. for(int i = 0; i < p->size(); i++)
  208. {
  209. CPathNode temp;
  210. //Set coord
  211. temp.coord = int3(p->at(i).x,p->at(i).y,p->at(i).z);
  212. //Set accesible
  213. if(p->at(i).h == -1)
  214. {
  215. temp.accesible = false;
  216. }
  217. else
  218. {
  219. temp.accesible = true;
  220. }
  221. //set diagonality
  222. float diagonal = 1.0f; //by default
  223. if(i>0)
  224. {
  225. if(p->at(i-1).x != temp.coord.x && p->at(i-1).y != temp.coord.y)
  226. {
  227. diagonal = sqrt(2.0f);
  228. }
  229. }
  230. //Set distance
  231. costs.push_back( i==0 ? 0 : p->at(i - 1).h * diagonal );
  232. //theNodeBefore is never used outside of pathfinding?
  233. //Set visited
  234. temp.visited = false;
  235. path->nodes.push_back(temp);
  236. }
  237. costs.push_back(0);
  238. for(int i=path->nodes.size()-1; i>=0; --i)
  239. {
  240. path->nodes[i].dist = costs[i+1] + ((i == path->nodes.size()-1) ? 0 : path->nodes[i+1].dist);
  241. }
  242. return path;
  243. }
  244. void CPathfinder::convertPath(CPath * path, unsigned int mode) //mode=0 -> from 'manifest' to 'object'
  245. {
  246. if (mode==0)
  247. {
  248. for (int i=0;i<path->nodes.size();i++)
  249. {
  250. path->nodes[i].coord = CGHeroInstance::convertPosition(path->nodes[i].coord,true);
  251. }
  252. }
  253. }
  254. int3 CPath::startPos()
  255. {
  256. return int3(nodes[nodes.size()-1].coord.x,nodes[nodes.size()-1].coord.y,nodes[nodes.size()-1].coord.z);
  257. }
  258. int3 CPath::endPos()
  259. {
  260. return int3(nodes[0].coord.x,nodes[0].coord.y,nodes[0].coord.z);
  261. }
  262. /*
  263. * The function used by the priority cue to determine which node to put at the top.
  264. */
  265. bool Compare::operator()(const vector<Coordinate>& a, const vector<Coordinate>& b)
  266. {
  267. double aTotal=0;
  268. double bTotal=0;
  269. for(int i = 0; i < a.size(); i++)
  270. {
  271. aTotal += a[i].g*a[i].h;
  272. }
  273. for(int i = 0; i < b.size(); i++)
  274. {
  275. bTotal += b[i].g*b[i].h;
  276. }
  277. return aTotal > bTotal;
  278. }
  279. void Coordinate::operator =(const Coordinate &other)
  280. {
  281. this->x = other.x;
  282. this->y = other.y;
  283. this->z = other.z;
  284. this->g = other.g;
  285. this->h = other.h;
  286. }