CPathfinder.cpp 10 KB

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