CPathfinder.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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 boost::logic;
  11. int3 CPath::startPos()
  12. {
  13. return int3(nodes[nodes.size()-1].coord.x,nodes[nodes.size()-1].coord.y,nodes[nodes.size()-1].coord.z);
  14. }
  15. int3 CPath::endPos()
  16. {
  17. return int3(nodes[0].coord.x,nodes[0].coord.y,nodes[0].coord.z);
  18. }
  19. 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 :()
  20. {
  21. //check input
  22. if ((src.x < 0)||(src.y < 0)||(src.z < 0)||(dest.x < 0)||(dest.y < 0)||(dest.z < 0))
  23. {
  24. return NULL;
  25. }
  26. if ((src.x >= CGI->mh->sizes.x)||(src.y >= CGI->mh->sizes.y)||(src.z >= CGI->mh->sizes.z)
  27. ||(dest.x >= CGI->mh->sizes.x)||(dest.y >= CGI->mh->sizes.y)||(dest.z >= CGI->mh->sizes.z))
  28. {
  29. return NULL;
  30. }
  31. int3 hpos = hero->getPosition(false);
  32. tribool blockLandSea; //true - blocks sea, false - blocks land, indeterminate - allows all
  33. if (!hero->canWalkOnSea())
  34. {
  35. if (CGI->mh->ttiles[hpos.x][hpos.y][hpos.z].tileInfo->tertype==water)
  36. blockLandSea=false;
  37. else
  38. blockLandSea=true;
  39. }
  40. else
  41. {
  42. blockLandSea = indeterminate;
  43. }
  44. //graph initialization
  45. graph.resize(CGI->mh->sizes.x);
  46. for(int i=0; i<graph.size(); ++i)
  47. {
  48. graph[i].resize(CGI->mh->sizes.y);
  49. for(int j=0; j<graph[i].size(); ++j)
  50. {
  51. graph[i][j].accesible = !CGI->mh->ttiles[i][j][src.z].tileInfo->blocked;
  52. if(i==dest.x && j==dest.y && CGI->mh->ttiles[i][j][src.z].tileInfo->visitable)
  53. graph[i][j].accesible = true; //for allowing visiting objects
  54. graph[i][j].dist = -1;
  55. graph[i][j].theNodeBefore = NULL;
  56. graph[i][j].visited = false;
  57. graph[i][j].coord.x = i;
  58. graph[i][j].coord.y = j;
  59. graph[i][j].coord.z = dest.z;
  60. if (CGI->mh->ttiles[i][j][src.z].tileInfo->tertype==rock)
  61. graph[i][j].accesible = false;
  62. if ((blockLandSea) && (CGI->mh->ttiles[i][j][src.z].tileInfo->tertype==water))
  63. graph[i][j].accesible = false;
  64. else if ((!blockLandSea) && (CGI->mh->ttiles[i][j][src.z].tileInfo->tertype!=water))
  65. graph[i][j].accesible = false;
  66. if(graph[i][j].accesible)
  67. graph[i][j].accesible = CGI->state->players[hero->tempOwner].fogOfWarMap[i][j][src.z];
  68. }
  69. }
  70. //graph initialized
  71. graph[src.x][src.y].dist = 0;
  72. std::queue<CPathNode> mq;
  73. mq.push(graph[src.x][src.y]);
  74. unsigned int curDist = 4000000000;
  75. while(!mq.empty())
  76. {
  77. CPathNode cp = mq.front();
  78. mq.pop();
  79. if ((cp.coord.x == dest.x) && (cp.coord.y==dest.y))
  80. {
  81. if (cp.dist < curDist)
  82. curDist=cp.dist;
  83. }
  84. else
  85. {
  86. if (cp.dist > curDist)
  87. continue;
  88. }
  89. if(cp.coord.x>0)
  90. {
  91. CPathNode & dp = graph[cp.coord.x-1][cp.coord.y];
  92. processNode(dp, hero, mq, cp, src, false);
  93. }
  94. if(cp.coord.y>0)
  95. {
  96. CPathNode & dp = graph[cp.coord.x][cp.coord.y-1];
  97. processNode(dp, hero, mq, cp, src, false);
  98. }
  99. if(cp.coord.x>0 && cp.coord.y>0)
  100. {
  101. CPathNode & dp = graph[cp.coord.x-1][cp.coord.y-1];
  102. processNode(dp, hero, mq, cp, src, true);
  103. }
  104. if(cp.coord.x<graph.size()-1)
  105. {
  106. CPathNode & dp = graph[cp.coord.x+1][cp.coord.y];
  107. processNode(dp, hero, mq, cp, src, false);
  108. }
  109. if(cp.coord.y<graph[0].size()-1)
  110. {
  111. CPathNode & dp = graph[cp.coord.x][cp.coord.y+1];
  112. processNode(dp, hero, mq, cp, src, false);
  113. }
  114. if(cp.coord.x<graph.size()-1 && cp.coord.y<graph[0].size()-1)
  115. {
  116. CPathNode & dp = graph[cp.coord.x+1][cp.coord.y+1];
  117. processNode(dp, hero, mq, cp, src, true);
  118. }
  119. if(cp.coord.x>0 && cp.coord.y<graph[0].size()-1)
  120. {
  121. CPathNode & dp = graph[cp.coord.x-1][cp.coord.y+1];
  122. processNode(dp, hero, mq, cp, src, true);
  123. }
  124. if(cp.coord.x<graph.size()-1 && cp.coord.y>0)
  125. {
  126. CPathNode & dp = graph[cp.coord.x+1][cp.coord.y-1];
  127. processNode(dp, hero, mq, cp, src, true);
  128. }
  129. }
  130. CPathNode curNode = graph[dest.x][dest.y];
  131. if(!curNode.theNodeBefore)
  132. return NULL;
  133. CPath * ret = new CPath;
  134. while(curNode.coord!=graph[src.x][src.y].coord)
  135. {
  136. ret->nodes.push_back(curNode);
  137. curNode = *(curNode.theNodeBefore);
  138. }
  139. ret->nodes.push_back(graph[src.x][src.y]);
  140. return ret;
  141. }
  142. void CPathfinder::convertPath(CPath * path, unsigned int mode) //mode=0 -> from 'manifest' to 'object'
  143. {
  144. if (mode==0)
  145. {
  146. for (int i=0;i<path->nodes.size();i++)
  147. {
  148. path->nodes[i].coord = CGHeroInstance::convertPosition(path->nodes[i].coord,true);
  149. }
  150. }
  151. }
  152. void CPathfinder::processNode(CPathNode & dp, const CGHeroInstance * hero, std::queue<CPathNode> & mq, const CPathNode & cp, const int3 & src, bool diagonal)
  153. {
  154. const TerrainTile * tinfo = CGI->mh->ttiles[dp.coord.x][dp.coord.y][src.z].tileInfo;
  155. int cost = hero->getTileCost(tinfo->tertype, tinfo->malle, tinfo->nuine);
  156. if(diagonal)
  157. cost *= std::sqrt(2.0);
  158. if((dp.dist==-1 || (dp.dist > cp.dist + cost)) && dp.accesible && checkForVisitableDir(cp.coord, dp.coord) && checkForVisitableDir(dp.coord, cp.coord))
  159. {
  160. dp.dist = cp.dist + cost;
  161. dp.theNodeBefore = &graph[cp.coord.x][cp.coord.y];
  162. mq.push(dp);
  163. }
  164. }
  165. bool CPathfinder::checkForVisitableDir(const int3 & src, const int3 & dst) const
  166. {
  167. for(int b=0; b<CGI->mh->ttiles[dst.x][dst.y][dst.z].tileInfo->visitableObjects.size(); ++b) //checking destination tile
  168. {
  169. const TerrainTile * pom = CGI->mh->ttiles[dst.x][dst.y][dst.z].tileInfo;
  170. if(!vstd::contains(pom->blockingObjects, pom->visitableObjects[b]))
  171. continue;
  172. CGDefInfo * di = pom->visitableObjects[b]->defInfo;
  173. if( (dst.x == src.x-1 && dst.y == src.y-1) && !(di->visitDir & (1<<4)) )
  174. {
  175. return false;
  176. }
  177. if( (dst.x == src.x && dst.y == src.y-1) && !(di->visitDir & (1<<5)) )
  178. {
  179. return false;
  180. }
  181. if( (dst.x == src.x+1 && dst.y == src.y-1) && !(di->visitDir & (1<<6)) )
  182. {
  183. return false;
  184. }
  185. if( (dst.x == src.x+1 && dst.y == src.y) && !(di->visitDir & (1<<7)) )
  186. {
  187. return false;
  188. }
  189. if( (dst.x == src.x+1 && dst.y == src.y+1) && !(di->visitDir & (1<<0)) )
  190. {
  191. return false;
  192. }
  193. if( (dst.x == src.x && dst.y == src.y+1) && !(di->visitDir & (1<<1)) )
  194. {
  195. return false;
  196. }
  197. if( (dst.x == src.x-1 && dst.y == src.y+1) && !(di->visitDir & (1<<2)) )
  198. {
  199. return false;
  200. }
  201. if( (dst.x == src.x-1 && dst.y == src.y) && !(di->visitDir & (1<<3)) )
  202. {
  203. return false;
  204. }
  205. }
  206. return true;
  207. }