path.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "../common/cbasetypes.h"
  4. #include "../common/nullpo.h"
  5. #include "../common/random.h"
  6. #include "../common/showmsg.h"
  7. #include "../common/malloc.h"
  8. #include "map.h"
  9. #include "battle.h"
  10. #include "path.h"
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #define MAX_HEAP 150
  15. struct tmp_path { short x,y,dist,before,cost,flag;};
  16. #define calc_index(x,y) (((x)+(y)*MAX_WALKPATH) & (MAX_WALKPATH*MAX_WALKPATH-1))
  17. const char walk_choices [3][3] =
  18. {
  19. {1,0,7},
  20. {2,-1,6},
  21. {3,4,5},
  22. };
  23. /*==========================================
  24. * heap push (helper function)
  25. *------------------------------------------*/
  26. static void push_heap_path(int *heap,struct tmp_path *tp,int index)
  27. {
  28. int i,h;
  29. h = heap[0];
  30. heap[0]++;
  31. for( i = (h-1)/2; h > 0 && tp[index].cost < tp[heap[i+1]].cost; i = (h-1)/2 )
  32. heap[h+1] = heap[i+1], h = i;
  33. heap[h+1] = index;
  34. }
  35. /*==========================================
  36. * heap update (helper function)
  37. * costが減ったので根の方へ移動
  38. *------------------------------------------*/
  39. static void update_heap_path(int *heap,struct tmp_path *tp,int index)
  40. {
  41. int i,h;
  42. ARR_FIND( 0, heap[0], h, heap[h+1] == index );
  43. if( h == heap[0] )
  44. {
  45. ShowError("update_heap_path bug\n");
  46. exit(EXIT_FAILURE);
  47. }
  48. for( i = (h-1)/2; h > 0 && tp[index].cost < tp[heap[i+1]].cost; i = (h-1)/2 )
  49. heap[h+1] = heap[i+1], h = i;
  50. heap[h+1] = index;
  51. }
  52. /*==========================================
  53. * heap pop (helper function)
  54. *------------------------------------------*/
  55. static int pop_heap_path(int *heap,struct tmp_path *tp)
  56. {
  57. int i,h,k;
  58. int ret,last;
  59. if( heap[0] <= 0 )
  60. return -1;
  61. ret = heap[1];
  62. last = heap[heap[0]];
  63. heap[0]--;
  64. for( h = 0, k = 2; k < heap[0]; k = k*2+2 )
  65. {
  66. if( tp[heap[k+1]].cost > tp[heap[k]].cost )
  67. k--;
  68. heap[h+1] = heap[k+1], h = k;
  69. }
  70. if( k == heap[0] )
  71. heap[h+1] = heap[k], h = k-1;
  72. for( i = (h-1)/2; h > 0 && tp[heap[i+1]].cost > tp[last].cost; i = (h-1)/2 )
  73. heap[h+1] = heap[i+1], h = i;
  74. heap[h+1]=last;
  75. return ret;
  76. }
  77. /*==========================================
  78. * calculate cost for the specified position
  79. *------------------------------------------*/
  80. static int calc_cost(struct tmp_path *p,int x1,int y1)
  81. {
  82. int xd = abs(x1 - p->x);
  83. int yd = abs(y1 - p->y);
  84. return (xd + yd)*10 + p->dist;
  85. }
  86. /*==========================================
  87. * attach/adjust path if neccessary
  88. *------------------------------------------*/
  89. static int add_path(int *heap,struct tmp_path *tp,int x,int y,int dist,int before,int cost)
  90. {
  91. int i;
  92. i = calc_index(x,y);
  93. if( tp[i].x == x && tp[i].y == y )
  94. {
  95. if( tp[i].dist > dist )
  96. {
  97. tp[i].dist = dist;
  98. tp[i].before = before;
  99. tp[i].cost = cost;
  100. if( tp[i].flag )
  101. push_heap_path(heap,tp,i);
  102. else
  103. update_heap_path(heap,tp,i);
  104. tp[i].flag = 0;
  105. }
  106. return 0;
  107. }
  108. if( tp[i].x || tp[i].y )
  109. return 1;
  110. tp[i].x = x;
  111. tp[i].y = y;
  112. tp[i].dist = dist;
  113. tp[i].before = before;
  114. tp[i].cost = cost;
  115. tp[i].flag = 0;
  116. push_heap_path(heap,tp,i);
  117. return 0;
  118. }
  119. /*==========================================
  120. * Find the closest reachable cell, 'count' cells away from (x0,y0) in direction (dx,dy).
  121. *
  122. * 吹き飛ばしたあとの座標を所得
  123. *------------------------------------------*/
  124. int path_blownpos(int m,int x0,int y0,int dx,int dy,int count)
  125. {
  126. struct map_data *md;
  127. if( !map[m].cell )
  128. return -1;
  129. md = &map[m];
  130. if( count>25 ){ //Cap to prevent too much processing...?
  131. ShowWarning("path_blownpos: count too many %d !\n",count);
  132. count=25;
  133. }
  134. if( dx > 1 || dx < -1 || dy > 1 || dy < -1 ){
  135. ShowError("path_blownpos: illegal dx=%d or dy=%d !\n",dx,dy);
  136. dx=(dx>0)?1:((dx<0)?-1:0);
  137. dy=(dy>0)?1:((dy<0)?-1:0);
  138. }
  139. while( count > 0 && (dx != 0 || dy != 0) )
  140. {
  141. if( !map_getcellp(md,x0+dx,y0+dy,CELL_CHKPASS) )
  142. {// attempt partial movement
  143. int fx = ( dx != 0 && map_getcellp(md,x0+dx,y0,CELL_CHKPASS) );
  144. int fy = ( dy != 0 && map_getcellp(md,x0,y0+dy,CELL_CHKPASS) );
  145. if( fx && fy )
  146. {
  147. if(rnd()&1)
  148. dx=0;
  149. else
  150. dy=0;
  151. }
  152. if( !fx )
  153. dx=0;
  154. if( !fy )
  155. dy=0;
  156. }
  157. x0 += dx;
  158. y0 += dy;
  159. count--;
  160. }
  161. return (x0<<16)|y0; //TODO: use 'struct point' here instead?
  162. }
  163. /*==========================================
  164. * is ranged attack from (x0,y0) to (x1,y1) possible?
  165. *------------------------------------------*/
  166. bool path_search_long(struct shootpath_data *spd,int m,int x0,int y0,int x1,int y1,cell_chk cell)
  167. {
  168. int dx, dy;
  169. int wx = 0, wy = 0;
  170. int weight;
  171. struct map_data *md;
  172. struct shootpath_data s_spd;
  173. if( spd == NULL )
  174. spd = &s_spd; // use dummy output variable
  175. if (!map[m].cell)
  176. return false;
  177. md = &map[m];
  178. dx = (x1 - x0);
  179. if (dx < 0) {
  180. swap(x0, x1);
  181. swap(y0, y1);
  182. dx = -dx;
  183. }
  184. dy = (y1 - y0);
  185. spd->rx = spd->ry = 0;
  186. spd->len = 1;
  187. spd->x[0] = x0;
  188. spd->y[0] = y0;
  189. if (map_getcellp(md,x1,y1,cell))
  190. return false;
  191. if (dx > abs(dy)) {
  192. weight = dx;
  193. spd->ry = 1;
  194. } else {
  195. weight = abs(y1 - y0);
  196. spd->rx = 1;
  197. }
  198. while (x0 != x1 || y0 != y1)
  199. {
  200. if (map_getcellp(md,x0,y0,cell))
  201. return false;
  202. wx += dx;
  203. wy += dy;
  204. if (wx >= weight) {
  205. wx -= weight;
  206. x0++;
  207. }
  208. if (wy >= weight) {
  209. wy -= weight;
  210. y0++;
  211. } else if (wy < 0) {
  212. wy += weight;
  213. y0--;
  214. }
  215. if( spd->len<MAX_WALKPATH )
  216. {
  217. spd->x[spd->len] = x0;
  218. spd->y[spd->len] = y0;
  219. spd->len++;
  220. }
  221. }
  222. return true;
  223. }
  224. /*==========================================
  225. * path search (x0,y0)->(x1,y1)
  226. * wpd: path info will be written here
  227. * flag: &1 = easy path search only
  228. * cell: type of obstruction to check for
  229. *------------------------------------------*/
  230. bool path_search(struct walkpath_data *wpd,int m,int x0,int y0,int x1,int y1,int flag,cell_chk cell)
  231. {
  232. int heap[MAX_HEAP+1];
  233. struct tmp_path tp[MAX_WALKPATH*MAX_WALKPATH];
  234. register int i,j,len,x,y,dx,dy;
  235. int rp,xs,ys;
  236. struct map_data *md;
  237. struct walkpath_data s_wpd;
  238. if( wpd == NULL )
  239. wpd = &s_wpd; // use dummy output variable
  240. if( !map[m].cell )
  241. return false;
  242. md = &map[m];
  243. #ifdef CELL_NOSTACK
  244. //Do not check starting cell as that would get you stuck.
  245. if( x0 < 0 || x0 >= md->xs || y0 < 0 || y0 >= md->ys )
  246. #else
  247. if( x0 < 0 || x0 >= md->xs || y0 < 0 || y0 >= md->ys /*|| map_getcellp(md,x0,y0,cell)*/ )
  248. #endif
  249. return false;
  250. if( x1 < 0 || x1 >= md->xs || y1 < 0 || y1 >= md->ys || map_getcellp(md,x1,y1,cell) )
  251. return false;
  252. // calculate (sgn(x1-x0), sgn(y1-y0))
  253. dx = ((dx = x1-x0)) ? ((dx<0) ? -1 : 1) : 0;
  254. dy = ((dy = y1-y0)) ? ((dy<0) ? -1 : 1) : 0;
  255. // try finding direct path to target
  256. x = x0;
  257. y = y0;
  258. i = 0;
  259. while( i < ARRAYLENGTH(wpd->path) )
  260. {
  261. wpd->path[i] = walk_choices[-dy + 1][dx + 1];
  262. i++;
  263. x += dx;
  264. y += dy;
  265. if( x == x1 ) dx = 0;
  266. if( y == y1 ) dy = 0;
  267. if( dx == 0 && dy == 0 )
  268. break; // success
  269. if( map_getcellp(md,x,y,cell) )
  270. break; // obstacle = failure
  271. }
  272. if( x == x1 && y == y1 )
  273. { //easy path successful.
  274. wpd->path_len = i;
  275. wpd->path_pos = 0;
  276. return true;
  277. }
  278. if( flag&1 )
  279. return false;
  280. memset(tp,0,sizeof(tp));
  281. i=calc_index(x0,y0);
  282. tp[i].x=x0;
  283. tp[i].y=y0;
  284. tp[i].dist=0;
  285. tp[i].before=0;
  286. tp[i].cost=calc_cost(&tp[i],x1,y1);
  287. tp[i].flag=0;
  288. heap[0]=0;
  289. push_heap_path(heap,tp,calc_index(x0,y0));
  290. xs = md->xs-1; // あらかじめ1減算しておく
  291. ys = md->ys-1;
  292. for(;;)
  293. {
  294. int e=0,f=0,dist,cost,dc[4]={0,0,0,0};
  295. if(heap[0]==0)
  296. return false;
  297. rp = pop_heap_path(heap,tp);
  298. x = tp[rp].x;
  299. y = tp[rp].y;
  300. dist = tp[rp].dist + 10;
  301. cost = tp[rp].cost;
  302. if(x==x1 && y==y1)
  303. break;
  304. // dc[0] : y++ の時のコスト増分
  305. // dc[1] : x-- の時のコスト増分
  306. // dc[2] : y-- の時のコスト増分
  307. // dc[3] : x++ の時のコスト増分
  308. if(y < ys && !map_getcellp(md,x ,y+1,cell)) {
  309. f |= 1; dc[0] = (y >= y1 ? 20 : 0);
  310. e+=add_path(heap,tp,x ,y+1,dist,rp,cost+dc[0]); // (x, y+1)
  311. }
  312. if(x > 0 && !map_getcellp(md,x-1,y ,cell)) {
  313. f |= 2; dc[1] = (x <= x1 ? 20 : 0);
  314. e+=add_path(heap,tp,x-1,y ,dist,rp,cost+dc[1]); // (x-1, y )
  315. }
  316. if(y > 0 && !map_getcellp(md,x ,y-1,cell)) {
  317. f |= 4; dc[2] = (y <= y1 ? 20 : 0);
  318. e+=add_path(heap,tp,x ,y-1,dist,rp,cost+dc[2]); // (x , y-1)
  319. }
  320. if(x < xs && !map_getcellp(md,x+1,y ,cell)) {
  321. f |= 8; dc[3] = (x >= x1 ? 20 : 0);
  322. e+=add_path(heap,tp,x+1,y ,dist,rp,cost+dc[3]); // (x+1, y )
  323. }
  324. if( (f & (2+1)) == (2+1) && !map_getcellp(md,x-1,y+1,cell))
  325. e+=add_path(heap,tp,x-1,y+1,dist+4,rp,cost+dc[1]+dc[0]-6); // (x-1, y+1)
  326. if( (f & (2+4)) == (2+4) && !map_getcellp(md,x-1,y-1,cell))
  327. e+=add_path(heap,tp,x-1,y-1,dist+4,rp,cost+dc[1]+dc[2]-6); // (x-1, y-1)
  328. if( (f & (8+4)) == (8+4) && !map_getcellp(md,x+1,y-1,cell))
  329. e+=add_path(heap,tp,x+1,y-1,dist+4,rp,cost+dc[3]+dc[2]-6); // (x+1, y-1)
  330. if( (f & (8+1)) == (8+1) && !map_getcellp(md,x+1,y+1,cell))
  331. e+=add_path(heap,tp,x+1,y+1,dist+4,rp,cost+dc[3]+dc[0]-6); // (x+1, y+1)
  332. tp[rp].flag=1;
  333. if(e || heap[0]>=MAX_HEAP-5)
  334. return false;
  335. }
  336. if( !(x==x1 && y==y1) ) // will never happen...
  337. return false;
  338. for(len=0,i=rp;len<100 && i!=calc_index(x0,y0);i=tp[i].before,len++);
  339. if(len==100 || len>=sizeof(wpd->path))
  340. return false;
  341. wpd->path_len = len;
  342. wpd->path_pos = 0;
  343. for(i=rp,j=len-1;j>=0;i=tp[i].before,j--) {
  344. int dx = tp[i].x - tp[tp[i].before].x;
  345. int dy = tp[i].y - tp[tp[i].before].y;
  346. int dir;
  347. if( dx == 0 ) {
  348. dir = (dy > 0 ? 0 : 4);
  349. } else if( dx > 0 ) {
  350. dir = (dy == 0 ? 6 : (dy < 0 ? 5 : 7) );
  351. } else {
  352. dir = (dy == 0 ? 2 : (dy > 0 ? 1 : 3) );
  353. }
  354. wpd->path[j] = dir;
  355. }
  356. return true;
  357. }
  358. //Distance functions, taken from http://www.flipcode.com/articles/article_fastdistance.shtml
  359. int check_distance(int dx, int dy, int distance)
  360. {
  361. #ifdef CIRCULAR_AREA
  362. //In this case, we just do a square comparison. Add 1 tile grace for diagonal range checks.
  363. return (dx*dx + dy*dy <= distance*distance + (dx&&dy?1:0));
  364. #else
  365. if (dx < 0) dx = -dx;
  366. if (dy < 0) dy = -dy;
  367. return ((dx<dy?dy:dx) <= distance);
  368. #endif
  369. }
  370. unsigned int distance(int dx, int dy)
  371. {
  372. #ifdef CIRCULAR_AREA
  373. unsigned int min, max;
  374. if ( dx < 0 ) dx = -dx;
  375. if ( dy < 0 ) dy = -dy;
  376. //There appears to be something wrong with the aproximation below when either dx/dy is 0! [Skotlex]
  377. if ( dx == 0 ) return dy;
  378. if ( dy == 0 ) return dx;
  379. if ( dx < dy )
  380. {
  381. min = dx;
  382. max = dy;
  383. } else {
  384. min = dy;
  385. max = dx;
  386. }
  387. // coefficients equivalent to ( 123/128 * max ) and ( 51/128 * min )
  388. return ((( max << 8 ) + ( max << 3 ) - ( max << 4 ) - ( max << 1 ) +
  389. ( min << 7 ) - ( min << 5 ) + ( min << 3 ) - ( min << 1 )) >> 8 );
  390. #else
  391. if (dx < 0) dx = -dx;
  392. if (dy < 0) dy = -dy;
  393. return (dx<dy?dy:dx);
  394. #endif
  395. }