OSPREOFF.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966
  1. /*
  2. * Seven Kingdoms: Ancient Adversaries
  3. *
  4. * Copyright 1997,1998 Enlight Software Ltd.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. #include <OSPREUSE.h>
  21. #include <OUNIT.h>
  22. #include <OWORLD.h>
  23. #include <OMISC.h>
  24. #ifdef NO_DEBUG_SEARCH
  25. #undef err_when
  26. #undef err_here
  27. #undef err_if
  28. #undef err_else
  29. #undef err_now
  30. #define err_when(cond)
  31. #define err_here()
  32. #define err_if(cond)
  33. #define err_else
  34. #define err_now(msg)
  35. #undef debug_reuse_check_path
  36. #define debug_reuse_check_path()
  37. #undef DEBUG
  38. #endif
  39. #ifdef DEBUG
  40. #include <OSYS.h>
  41. #endif
  42. //------------------- static function --------------------//
  43. // check whether a location can be walked. This function is
  44. // similar to that in SeekPath. However, only several search
  45. // mode is useful here. i.e. search mode 1 and 2.
  46. //
  47. int SeekPathReuse::can_walk(int xLoc, int yLoc)
  48. {
  49. if(xLoc>=MAX_WORLD_X_LOC || yLoc>=MAX_WORLD_Y_LOC)
  50. return 0;
  51. Location *locPtr = world.get_loc(xLoc, yLoc);
  52. short recno = (mobile_type!=UNIT_AIR) ? locPtr->cargo_recno : locPtr->air_cargo_recno;
  53. Unit *unitPtr;
  54. UCHAR unitCurAction;
  55. //------ check terrain id. -------//
  56. switch(mobile_type)
  57. {
  58. case UNIT_LAND:
  59. if(reuse_search_sub_mode==SEARCH_SUB_MODE_PASSABLE && locPtr->power_nation_recno &&
  60. !reuse_nation_passable[locPtr->power_nation_recno])
  61. return 0;
  62. if(!locPtr->walkable())
  63. return 0;
  64. if(!recno)
  65. return 1;
  66. unitPtr = unit_array[recno];
  67. if(search_mode==SEARCH_MODE_A_UNIT_IN_GROUP)
  68. return unitPtr->cur_action==SPRITE_MOVE;
  69. else
  70. {
  71. unitCurAction = unitPtr->cur_action;
  72. return (unitPtr->unit_group_id==cur_group_id && unitCurAction!=SPRITE_ATTACK) ||
  73. (unitCurAction==SPRITE_MOVE && unitPtr->cur_x-unitPtr->next_x<=ZOOM_LOC_WIDTH/2 &&
  74. unitPtr->cur_y-unitPtr->next_y<=ZOOM_LOC_HEIGHT/2) ||
  75. (unitPtr->nation_recno==unit_nation_recno && unitCurAction==SPRITE_IDLE);
  76. }
  77. break;
  78. case UNIT_SEA:
  79. if(!locPtr->sailable())
  80. return 0;
  81. if(!recno)
  82. return 1;
  83. unitPtr = unit_array[recno];
  84. if(search_mode==SEARCH_MODE_A_UNIT_IN_GROUP)
  85. return unitPtr->cur_action==SPRITE_MOVE;
  86. else
  87. {
  88. unitCurAction = unitPtr->cur_action;
  89. return (unitPtr->unit_group_id==cur_group_id && unitCurAction!=SPRITE_ATTACK) ||
  90. unitCurAction==SPRITE_MOVE ||
  91. (unitPtr->nation_recno==unit_nation_recno && unitCurAction==SPRITE_IDLE);
  92. }
  93. break;
  94. case UNIT_AIR:
  95. if(!recno)
  96. return 1;
  97. unitPtr = unit_array[recno];
  98. if(search_mode==SEARCH_MODE_A_UNIT_IN_GROUP)
  99. return unitPtr->cur_action==SPRITE_MOVE;
  100. else
  101. {
  102. unitCurAction = unitPtr->cur_action;
  103. return (unitPtr->unit_group_id==cur_group_id && unitCurAction!=SPRITE_ATTACK) ||
  104. unitCurAction==SPRITE_MOVE ||
  105. (unitPtr->nation_recno==unit_nation_recno && unitCurAction==SPRITE_IDLE);
  106. }
  107. break;
  108. }
  109. return 0;
  110. }
  111. //------------ End of static function ----------------//
  112. //------------------- static function --------------------//
  113. int SeekPathReuse::can_walk_s2(int xLoc, int yLoc)
  114. {
  115. if(xLoc>=MAX_WORLD_X_LOC-1 || yLoc>=MAX_WORLD_Y_LOC-1)
  116. return 0;
  117. if(can_walk(xLoc, yLoc) && can_walk(xLoc+1,yLoc) && can_walk(xLoc,yLoc+1) && can_walk(xLoc+1,yLoc+1))
  118. return 1;
  119. else
  120. return 0;
  121. }
  122. //------------ End of static function ----------------//
  123. //------------------- static function --------------------//
  124. void SeekPathReuse::sys_yield()
  125. {
  126. //sys.yield();
  127. }
  128. //------------ End of static function ----------------//
  129. //-------- Begin of function SeekPathReuse::seek_path_offset ---------//
  130. void SeekPathReuse::seek_path_offset()
  131. {
  132. if(!is_leader_path_valid())
  133. return;
  134. if(is_node_avail_empty())
  135. {
  136. copy_leader_path_offset();
  137. return;
  138. }
  139. //------------ construct data structure to store result node ----------------//
  140. result_node_array_def_size += result_node_array_reset_amount;
  141. path_reuse_result_node_ptr = (ResultNode*) mem_add(sizeof(ResultNode)* result_node_array_def_size);
  142. memset(path_reuse_result_node_ptr, 0, sizeof(ResultNode)* result_node_array_def_size);
  143. cur_result_node_ptr = path_reuse_result_node_ptr;
  144. num_of_result_node = 0;
  145. //---------------- set starting point ----------------------//
  146. add_result(start_x, start_y);
  147. //-----------------initialize offset path reuse ------------//
  148. cur_leader_node_ptr = reuse_leader_path_backup+1;
  149. cur_leader_node_num = 2;
  150. use_offset_method(reuse_leader_path_backup[0].node_x, reuse_leader_path_backup[0].node_y); // using offset path method directly
  151. //----------------------------------------------------------------------//
  152. // checking for incomplete searching
  153. //----------------------------------------------------------------------//
  154. ResultNode *lastNode = path_reuse_result_node_ptr + num_of_result_node - 1;
  155. if((lastNode->node_x!=vir_dest_x || lastNode->node_y!=vir_dest_y) && is_node_avail_empty())
  156. {
  157. incomplete_search++;
  158. reuse_path_status = REUSE_PATH_INCOMPLETE_SEARCH;
  159. }
  160. }
  161. //--------- End of function SeekPathReuse::seek_path_offset ---------//
  162. //-------- Begin of function SeekPathReuse::seek_path_join_offset ---------//
  163. // The join-offset-path method.
  164. //
  165. void SeekPathReuse::seek_path_join_offset()
  166. {
  167. if(!is_leader_path_valid())
  168. return;
  169. //----------------------------------------------------------------------//
  170. // checking for incomplete searching
  171. //----------------------------------------------------------------------//
  172. if(is_node_avail_empty())
  173. {
  174. incomplete_search++;
  175. reuse_path_status = REUSE_PATH_INCOMPLETE_SEARCH;
  176. return;
  177. }
  178. err_when(unit_size!=1);
  179. memset(reuse_node_matrix, 0, sizeof(short)*MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC/4);
  180. path_reuse_result_node_ptr = NULL;
  181. //--------------------------------------------------------------//
  182. // initialization and declaring variables
  183. //--------------------------------------------------------------//
  184. int connectResultNodeNum;
  185. ResultNode* connectResultNodePtr=NULL;
  186. cur_leader_node_ptr = reuse_leader_path_backup;
  187. cur_leader_node_num = 1;
  188. int leaderNodeXLoc = cur_leader_node_ptr->node_x;
  189. int leaderNodeYLoc = cur_leader_node_ptr->node_y;
  190. #ifdef DEBUG
  191. int debugLoopCount = 0;
  192. #endif
  193. do
  194. {
  195. err_when(++debugLoopCount>10000);
  196. set_index_in_node_matrix(leaderNodeXLoc+x_offset, leaderNodeYLoc+y_offset);
  197. }while(get_next_offset_loc(leaderNodeXLoc, leaderNodeYLoc));
  198. //--------------------------------------------------------------//
  199. // copy the node_matrix to that node_matrix used in class SeekPath
  200. //--------------------------------------------------------------//
  201. err_when(unit_size!=1);
  202. seek_path.set_node_matrix(reuse_node_matrix);
  203. //--------------------------------------------------------------//
  204. // process shortest path searching to find a walkable point in
  205. // the offset path for connection
  206. //--------------------------------------------------------------//
  207. //--- if the starting location is already in the offset path, process it immediately ---//
  208. err_when(unit_size!=1);
  209. short *locNode = reuse_node_matrix + MAX_WORLD_X_LOC/2*(start_y/2) + (start_x/2);
  210. if(*locNode > max_node && mobile_type==UNIT_LAND) // starting point on the reuse offset path
  211. {
  212. connectResultNodePtr = (ResultNode*) mem_add(sizeof(ResultNode)*2);
  213. ResultNode* curNode = connectResultNodePtr;
  214. curNode->node_x = start_x;
  215. curNode->node_y = start_y;
  216. connectResultNodeNum = 1;
  217. curNode++;
  218. switch(*locNode-max_node)
  219. {
  220. case 1: if(start_x%2 || start_y%2)
  221. {
  222. curNode->node_x = (start_x%2) ? start_x-1 : start_x;
  223. curNode->node_y = (start_y%2) ? start_y-1 : start_y;
  224. connectResultNodeNum++;
  225. }
  226. break;
  227. case 2: if(!(start_x%2 && start_y%2==0))
  228. {
  229. curNode->node_x = (start_x%2) ? start_x : start_x+1;
  230. curNode->node_y = (start_y%2) ? start_y-1 : start_y;
  231. connectResultNodeNum++;
  232. }
  233. break;
  234. case 3: if(!(start_x%2==0 && start_y%2))
  235. {
  236. curNode->node_x = (start_x%2) ? start_x-1 : start_x;
  237. curNode->node_y = (start_y%2) ? start_y : start_y+1;
  238. connectResultNodeNum++;
  239. }
  240. break;
  241. case 4: if(start_x%2==0 || start_y%2==0)
  242. {
  243. curNode->node_x = (start_x%2) ? start_x : start_x+1;
  244. curNode->node_y = (start_y%2) ? start_y : start_y+1;
  245. connectResultNodeNum++;
  246. }
  247. break;
  248. }
  249. //********BUGHERE
  250. // unable to handle this blocked case now, abort path-reuse and seeking instead
  251. if(connectResultNodeNum>1 && !can_walk(curNode->node_x, curNode->node_y))
  252. {
  253. path_reuse_result_node_ptr = call_seek(start_x, start_y, vir_dest_x, vir_dest_y, cur_group_id, mobile_type, SEARCH_MODE_IN_A_GROUP, num_of_result_node);
  254. mem_del(connectResultNodePtr);
  255. return;
  256. }
  257. }
  258. else
  259. {
  260. //------------- seek for connection point ------------//
  261. connectResultNodePtr = call_seek(start_x, start_y, vir_dest_x, vir_dest_y, cur_group_id, mobile_type,
  262. SEARCH_MODE_REUSE, connectResultNodeNum);
  263. err_when(connectResultNodePtr!=NULL && connectResultNodeNum<2);
  264. if(connectResultNodePtr==NULL || connectResultNodeNum==0) // cannot reach the destination
  265. {
  266. if(connectResultNodePtr!=NULL)
  267. mem_del(connectResultNodePtr);
  268. return;
  269. }
  270. }
  271. //--------------------------------------------------------------//
  272. // constructing data structure
  273. //--------------------------------------------------------------//
  274. result_node_array_def_size += result_node_array_reset_amount;
  275. path_reuse_result_node_ptr = (ResultNode*) mem_add(sizeof(ResultNode)* result_node_array_def_size);
  276. memset(path_reuse_result_node_ptr, 0, sizeof(ResultNode)* result_node_array_def_size);
  277. cur_result_node_ptr = path_reuse_result_node_ptr;
  278. num_of_result_node = 0;
  279. //--------------------------------------------------------------//
  280. // add the result path
  281. //--------------------------------------------------------------//
  282. ResultNode* curResultNode = connectResultNodePtr;
  283. for(int i=0; i<connectResultNodeNum; i++)
  284. {
  285. add_result(curResultNode->node_x, curResultNode->node_y);
  286. curResultNode++;
  287. }
  288. //--------------------------------------------------------------//
  289. // determine the joining point in the offset path
  290. //--------------------------------------------------------------//
  291. cur_leader_node_ptr = reuse_leader_path_backup;
  292. cur_leader_node_num = 1;
  293. ResultNode *endNode = connectResultNodePtr + connectResultNodeNum - 1;
  294. short findConnectionPoint = 0;
  295. if(endNode->node_x==vir_dest_x && endNode->node_y==vir_dest_y)
  296. {
  297. if(connectResultNodePtr!=NULL);
  298. mem_del(connectResultNodePtr);
  299. return; // already the destination location
  300. }
  301. //------------------------------------------------------------------------------------//
  302. // find a offset-reference point in leader path
  303. //------------------------------------------------------------------------------------//
  304. leaderNodeXLoc = cur_leader_node_ptr->node_x;
  305. leaderNodeYLoc = cur_leader_node_ptr->node_y;
  306. short notEnd = 1;
  307. sys_yield(); // update cursor position
  308. int unitDestX, unitDestY; // for the current searching unit, using the leader path
  309. do
  310. {
  311. //---------- boundary checking -----------//
  312. bound_check_x((unitDestX = leaderNodeXLoc+x_offset));
  313. bound_check_y((unitDestY = leaderNodeYLoc+y_offset));
  314. if(endNode->node_x==unitDestX && endNode->node_y==unitDestY)
  315. findConnectionPoint = 1; // ok, connected
  316. else
  317. notEnd = get_next_offset_loc(leaderNodeXLoc, leaderNodeYLoc);
  318. if(!notEnd)
  319. break;
  320. }while(!findConnectionPoint);
  321. sys_yield(); // update cursor position
  322. //-------------- clear the temporary path ------------//
  323. if(connectResultNodePtr!=NULL)
  324. mem_del(connectResultNodePtr);
  325. //-----------------------------------------------------------------------------//
  326. // return since cannot find a connection point
  327. //-----------------------------------------------------------------------------//
  328. if(!findConnectionPoint)
  329. {
  330. //----------------------------------------------------------------------//
  331. // checking for incomplete searching
  332. //----------------------------------------------------------------------//
  333. if(is_node_avail_empty())
  334. {
  335. incomplete_search++;
  336. reuse_path_status = REUSE_PATH_INCOMPLETE_SEARCH;
  337. }
  338. if(num_of_result_node==1)
  339. {
  340. mem_del(path_reuse_result_node_ptr);
  341. path_reuse_result_node_ptr = NULL;
  342. num_of_result_node = 0;
  343. }
  344. return;
  345. }
  346. //-----------------------------------------------------------------------------//
  347. // update pointer cur_leader_node_ptr if necessary
  348. //-----------------------------------------------------------------------------//
  349. if(leaderNodeXLoc==cur_leader_node_ptr->node_x && leaderNodeYLoc==cur_leader_node_ptr->node_y) // at the turning point
  350. {
  351. if(cur_leader_node_num < reuse_leader_path_node_num)
  352. {
  353. cur_leader_node_num++;
  354. cur_leader_node_ptr++;
  355. }
  356. else // join at the end of the offset path, search finished
  357. return;
  358. }
  359. //----------------------------------------------------------------------------------------//
  360. // at this moment, the searching unit has a offset path to the leader path.
  361. // There are not processed leader nodes. These nodes are pointed by cur_leader_node_ptr.
  362. //----------------------------------------------------------------------------------------//
  363. use_offset_method(leaderNodeXLoc, leaderNodeYLoc); // changed to offset method for the rest
  364. //----------------------------------------------------------------------//
  365. // checking for incomplete searching
  366. //----------------------------------------------------------------------//
  367. ResultNode *lastNode = path_reuse_result_node_ptr + num_of_result_node - 1;
  368. if((lastNode->node_x!=vir_dest_x || lastNode->node_y!=vir_dest_y) && is_node_avail_empty())
  369. {
  370. incomplete_search++;
  371. reuse_path_status = REUSE_PATH_INCOMPLETE_SEARCH;
  372. }
  373. }
  374. //--------- End of function SeekPathReuse::seek_path_join_offset ---------//
  375. //-------- Begin of function SeekPathReuse::use_offset_method ---------//
  376. void SeekPathReuse::use_offset_method(int xLoc, int yLoc)
  377. {
  378. //----------------------------------------------------------------------//
  379. // checking for incomplete searching
  380. //----------------------------------------------------------------------//
  381. if(is_node_avail_empty())
  382. {
  383. incomplete_search++;
  384. reuse_path_status = REUSE_PATH_INCOMPLETE_SEARCH;
  385. return;
  386. }
  387. //-----------------------------------------------------//
  388. int leaderNodeXLoc = xLoc; // hold the currently referred leader node
  389. int leaderNodeYLoc = yLoc;
  390. leader_vec_x = cur_leader_node_ptr->node_x - leaderNodeXLoc;
  391. leader_vec_y = cur_leader_node_ptr->node_y - leaderNodeYLoc;
  392. if(leader_vec_x!=0)
  393. leader_vec_x /= abs(leader_vec_x);
  394. if(leader_vec_y!=0)
  395. leader_vec_y /= abs(leader_vec_y);
  396. ResultNode *partOfResultNodePtr, *curNodePtr;
  397. int partOfResultNodeNum, restNode;
  398. partOfResultNodePtr = NULL;
  399. partOfResultNodeNum = 0;
  400. //-----------------------------------------------------//
  401. int unitNodeXLoc, unitNodeYLoc;
  402. int preNonblockedXLoc, preNonblockedYLoc;
  403. int nextNonblockedLeaderXLoc, nextNonblockedLeaderYLoc;
  404. int preLeaderVecX, preLeaderVecY;
  405. int virDestX, virDestY;
  406. int pathSeekResult, canReach;
  407. //-----------------------------------------------------//
  408. // start walking along the leader path
  409. //-----------------------------------------------------//
  410. #ifdef DEBUG
  411. int debugPreLeaderNodeXLoc, debugPreLeaderNodeYLoc;
  412. while(debugPreLeaderNodeXLoc=leaderNodeXLoc, debugPreLeaderNodeYLoc=leaderNodeYLoc,
  413. get_next_offset_loc(leaderNodeXLoc, leaderNodeYLoc)) // get next location in the leader path
  414. #else
  415. while(get_next_offset_loc(leaderNodeXLoc, leaderNodeYLoc)) // get next location in the leader path
  416. #endif
  417. {
  418. err_when(leaderNodeXLoc<0 || leaderNodeXLoc>=MAX_WORLD_X_LOC);
  419. err_when(leaderNodeYLoc<0 || leaderNodeYLoc>=MAX_WORLD_Y_LOC);
  420. err_when(partOfResultNodePtr!=NULL);
  421. sys_yield(); // update cursor position
  422. unitNodeXLoc = leaderNodeXLoc+x_offset; // calculate the corresponding location in the offset path.
  423. unitNodeYLoc = leaderNodeYLoc+y_offset;
  424. if(unitNodeXLoc>=0 && unitNodeXLoc<MAX_WORLD_X_LOC && unitNodeYLoc>=0 && unitNodeYLoc<MAX_WORLD_Y_LOC &&
  425. ((move_scale==1 && can_walk(unitNodeXLoc, unitNodeYLoc)) ||
  426. (move_scale==2 && can_walk(unitNodeXLoc, unitNodeYLoc) &&
  427. can_walk(unitNodeXLoc-leader_vec_x, unitNodeYLoc-leader_vec_y)) ))
  428. {
  429. //----------------------------------------------------------------------------//
  430. // offset node exists, so add it to the result path
  431. //----------------------------------------------------------------------------//
  432. add_result(unitNodeXLoc, unitNodeYLoc); // add result if location can be reached
  433. if(unitNodeXLoc==vir_dest_x && unitNodeYLoc==vir_dest_y)
  434. break;
  435. }
  436. else
  437. {
  438. //----------------------------------------------------------------------------//
  439. // get the next non-blocked location calculated by offset
  440. //----------------------------------------------------------------------------//
  441. nextNonblockedLeaderXLoc = leaderNodeXLoc; // used as reference
  442. nextNonblockedLeaderYLoc = leaderNodeYLoc;
  443. preLeaderVecX = leader_vec_x;
  444. preLeaderVecY = leader_vec_y;
  445. //========================================================================//
  446. //========================================================================//
  447. if(get_next_nonblocked_offset_loc(nextNonblockedLeaderXLoc, nextNonblockedLeaderYLoc)) // get the next nonblocked location for joining
  448. {
  449. if(is_node_avail_empty())
  450. {
  451. incomplete_search++;
  452. reuse_path_status = REUSE_PATH_INCOMPLETE_SEARCH;
  453. return;
  454. }
  455. //--- seek from the current location to the next non-blocked location ---//
  456. err_when(num_of_result_node<1);
  457. preNonblockedXLoc = (cur_result_node_ptr-1)->node_x;
  458. preNonblockedYLoc = (cur_result_node_ptr-1)->node_y;
  459. //bound_check_x((preNonblockedXLoc = unitNodeXLoc-preLeaderVecX*move_scale));
  460. //bound_check_y((preNonblockedYLoc = unitNodeYLoc-preLeaderVecY*move_scale));
  461. err_when(preNonblockedXLoc<0 || preNonblockedXLoc>=MAX_WORLD_X_LOC);
  462. err_when(preNonblockedYLoc<0 || preNonblockedYLoc>=MAX_WORLD_Y_LOC);
  463. //-------- find a path to the next non-blocked location ----------//
  464. bound_check_x((virDestX = nextNonblockedLeaderXLoc+x_offset));
  465. bound_check_y((virDestY = nextNonblockedLeaderYLoc+y_offset));
  466. err_when(partOfResultNodePtr!=NULL);
  467. err_when(unit_size!=1);
  468. pathSeekResult = seek_path.seek(preNonblockedXLoc, preNonblockedYLoc, virDestX, virDestY,
  469. cur_group_id, mobile_type, SEARCH_MODE_IN_A_GROUP);
  470. partOfResultNodePtr = seek_path.get_result(partOfResultNodeNum, reuse_path_dist);
  471. //--------------------------------------------------------------------------//
  472. // go to destination directly if cannot reach the next nonblocked lcoation
  473. //--------------------------------------------------------------------------//
  474. if(partOfResultNodePtr==NULL || partOfResultNodeNum==0)
  475. canReach = 0;
  476. else
  477. {
  478. #ifdef DEBUG
  479. int ddX = abs((cur_result_node_ptr-1)->node_x-partOfResultNodePtr[0].node_x);
  480. int ddY = abs((cur_result_node_ptr-1)->node_y-partOfResultNodePtr[0].node_y);
  481. err_when(ddX && ddY && ddX!=ddY);
  482. #endif
  483. ResultNode *curNode = partOfResultNodePtr + partOfResultNodeNum-1;
  484. if(curNode->node_x==virDestX && curNode->node_y==virDestY)
  485. canReach = 1;
  486. else
  487. {
  488. canReach = 0;
  489. mem_del(partOfResultNodePtr);
  490. partOfResultNodePtr = NULL;
  491. }
  492. }
  493. if(canReach==0) // unable to reach the location specified
  494. {
  495. if(is_node_avail_empty())
  496. {
  497. incomplete_search++;
  498. reuse_path_status = REUSE_PATH_INCOMPLETE_SEARCH;
  499. return;
  500. }
  501. bound_check_x((virDestX = dest_x));
  502. bound_check_y((virDestY = dest_y));
  503. err_when(partOfResultNodePtr!=NULL);
  504. err_when(unit_size!=1);
  505. int pathSeekResult= seek_path.seek(preNonblockedXLoc, preNonblockedYLoc, virDestX, virDestY, cur_group_id, mobile_type, SEARCH_MODE_IN_A_GROUP);
  506. partOfResultNodePtr = seek_path.get_result(partOfResultNodeNum, reuse_path_dist);
  507. #ifdef DEBUG
  508. if(partOfResultNodePtr!=NULL)
  509. {
  510. int ddX = abs((cur_result_node_ptr-1)->node_x-partOfResultNodePtr[0].node_x);
  511. int ddY = abs((cur_result_node_ptr-1)->node_y-partOfResultNodePtr[0].node_y);
  512. err_when(ddX && ddY && ddX!=ddY);
  513. }
  514. #endif
  515. }
  516. //---------------------- connect the two paths ----------------------//
  517. if(partOfResultNodePtr!=NULL)
  518. {
  519. restNode = partOfResultNodeNum;
  520. curNodePtr = partOfResultNodePtr;
  521. err_when(preNonblockedXLoc!=partOfResultNodePtr->node_x || preNonblockedYLoc!=partOfResultNodePtr->node_y);
  522. restNode--;
  523. curNodePtr++;
  524. while(restNode)
  525. {
  526. add_result(curNodePtr->node_x, curNodePtr->node_y);
  527. curNodePtr++;
  528. restNode--;
  529. }
  530. debug_reuse_check_path(); //-************** debug checking
  531. mem_del(partOfResultNodePtr);
  532. partOfResultNodePtr = NULL;
  533. }
  534. err_when(partOfResultNodePtr!=NULL);
  535. if(canReach)
  536. {
  537. leaderNodeXLoc = nextNonblockedLeaderXLoc;
  538. leaderNodeYLoc = nextNonblockedLeaderYLoc;
  539. }
  540. else
  541. {
  542. //------------------------------------------------//
  543. // incomplete search
  544. //------------------------------------------------//
  545. if(is_node_avail_empty())
  546. {
  547. incomplete_search++;
  548. reuse_path_status = REUSE_PATH_INCOMPLETE_SEARCH;
  549. return;
  550. }
  551. break;
  552. }
  553. if(pathSeekResult!=PATH_FOUND && pathSeekResult!=PATH_REUSE_FOUND)
  554. break;
  555. }
  556. //========================================================================//
  557. //========================================================================//
  558. else // no next non-blocked offset location, searching directly to the destinaton
  559. {
  560. //-------------------------------------------------------------//
  561. // move directly to the destination from the current location
  562. //
  563. // This case occurs when the destination cannot be reached.
  564. //-------------------------------------------------------------//
  565. //--- seek from the current location to the destination ---//
  566. //bound_check_x((preNonblockedXLoc = unitNodeXLoc-preLeaderVecX*move_scale));
  567. //bound_check_y((preNonblockedYLoc = unitNodeYLoc-preLeaderVecY*move_scale));
  568. err_when(num_of_result_node<1);
  569. preNonblockedXLoc = (cur_result_node_ptr-1)->node_x;
  570. preNonblockedYLoc = (cur_result_node_ptr-1)->node_y;
  571. err_when(preNonblockedXLoc<0 || preNonblockedXLoc>=MAX_WORLD_X_LOC);
  572. err_when(preNonblockedYLoc<0 || preNonblockedYLoc>=MAX_WORLD_Y_LOC);
  573. bound_check_x((virDestX = nextNonblockedLeaderXLoc+x_offset));
  574. bound_check_y((virDestY = nextNonblockedLeaderYLoc+y_offset));
  575. err_when(partOfResultNodePtr!=NULL);
  576. //------------------------------------------------//
  577. // set to incomplete_search for later searching
  578. //------------------------------------------------//
  579. incomplete_search++;
  580. reuse_path_status = REUSE_PATH_INCOMPLETE_SEARCH;
  581. #ifdef DEBUG
  582. int ddX1 = abs((cur_result_node_ptr-1)->node_x-preNonblockedXLoc);
  583. int ddY1 = abs((cur_result_node_ptr-1)->node_y-preNonblockedYLoc);
  584. err_when(ddX1 && ddY1 && ddX1!=ddY1);
  585. #endif
  586. err_when(unit_size!=1);
  587. seek_path.seek(preNonblockedXLoc, preNonblockedYLoc, virDestX, virDestY, cur_group_id, mobile_type, 1);
  588. partOfResultNodePtr = seek_path.get_result(partOfResultNodeNum, reuse_path_dist);
  589. //---------------- connect the two paths together ----------------//
  590. if(partOfResultNodePtr!=NULL)
  591. {
  592. #ifdef DEBUG
  593. int ddX = abs((cur_result_node_ptr-1)->node_x-partOfResultNodePtr[0].node_x);
  594. int ddY = abs((cur_result_node_ptr-1)->node_y-partOfResultNodePtr[0].node_y);
  595. err_when(ddX && ddY && ddX!=ddY);
  596. #endif
  597. err_when(preNonblockedXLoc!=partOfResultNodePtr->node_x || preNonblockedYLoc!=partOfResultNodePtr->node_y);
  598. restNode = partOfResultNodeNum-1;
  599. curNodePtr = partOfResultNodePtr+1;
  600. while(restNode)
  601. {
  602. add_result(curNodePtr->node_x, curNodePtr->node_y);
  603. curNodePtr++;
  604. restNode--;
  605. }
  606. debug_reuse_check_path(); //-************** debug checking
  607. mem_del(partOfResultNodePtr);
  608. partOfResultNodePtr = NULL;
  609. }
  610. }//end if get_next_nonblocked_offset_loc()
  611. //-------------------------------------------------------------------------------------------------//
  612. // update leaderNode?Loc since it may be changed after calling get_next_nonblocked_offset_loc()
  613. //-------------------------------------------------------------------------------------------------//
  614. leaderNodeXLoc = nextNonblockedLeaderXLoc;
  615. leaderNodeYLoc = nextNonblockedLeaderYLoc;
  616. }
  617. debug_reuse_check_path(); //-************** debug checking
  618. err_when(partOfResultNodePtr!=NULL);
  619. } // end while
  620. err_when(partOfResultNodePtr!=NULL);
  621. debug_reuse_check_path(); //-************** debug checking
  622. }
  623. //--------- End of function SeekPathReuse::use_offset_method ---------//
  624. //-------- Begin of function SeekPathReuse::get_next_nonblocked_offset_loc ---------//
  625. // find the next nonblocked offset location if the inputed location is blocked
  626. // return 1 if found, 0 for none
  627. //
  628. int SeekPathReuse::get_next_nonblocked_offset_loc(int& nextXLoc, int&nextYLoc)
  629. {
  630. int found = 0;
  631. int unitDestX, unitDestY;
  632. /*#ifdef DEBUG
  633. int debugLoopCount = 0;
  634. #endif
  635. while(!found)
  636. {
  637. err_when(++debugLoopCount>10000);
  638. if(!get_next_offset_loc(nextXLoc, nextYLoc))
  639. break; // all nodes visited
  640. unitDestX = nextXLoc+x_offset;
  641. unitDestY = nextYLoc+y_offset;
  642. err_when(unit_size!=1);
  643. if(unitDestX>=0 && unitDestX<MAX_WORLD_X_LOC && unitDestY>=0 && unitDestY<MAX_WORLD_Y_LOC &&
  644. can_walk(unitDestX, unitDestY))
  645. found = 1;
  646. }
  647. return found;*/
  648. while(!found)
  649. {
  650. if(nextXLoc != cur_leader_node_ptr->node_x || nextYLoc != cur_leader_node_ptr->node_y)
  651. {
  652. nextXLoc += leader_vec_x;
  653. nextYLoc += leader_vec_y;
  654. unitDestX = nextXLoc+x_offset;
  655. unitDestY = nextYLoc+y_offset;
  656. err_when(unit_size!=1);
  657. if(unitDestX>=0 && unitDestX<MAX_WORLD_X_LOC && unitDestY>=0 && unitDestY<MAX_WORLD_Y_LOC &&
  658. can_walk(unitDestX, unitDestY))
  659. found = 1;
  660. }
  661. else
  662. {
  663. if(cur_leader_node_num < reuse_leader_path_node_num)
  664. {
  665. cur_leader_node_num++;
  666. cur_leader_node_ptr++;
  667. leader_vec_x = cur_leader_node_ptr->node_x - nextXLoc;
  668. leader_vec_y = cur_leader_node_ptr->node_y - nextYLoc;
  669. if(leader_vec_x!=0)
  670. {
  671. leader_vec_x /= abs(leader_vec_x);
  672. nextXLoc += leader_vec_x;
  673. }
  674. if(leader_vec_y!=0)
  675. {
  676. leader_vec_y /= abs(leader_vec_y);
  677. nextYLoc += leader_vec_y;
  678. }
  679. unitDestX = nextXLoc+x_offset;
  680. unitDestY = nextYLoc+y_offset;
  681. err_when(unit_size!=1);
  682. if(unitDestX>=0 && unitDestX<MAX_WORLD_X_LOC && unitDestY>=0 && unitDestY<MAX_WORLD_Y_LOC &&
  683. can_walk(unitDestX, unitDestY))
  684. found = 1;
  685. }
  686. else
  687. break; // or return 0;
  688. }
  689. sys_yield(); // update cursor position
  690. }
  691. return found;
  692. }
  693. //--------- End of function SeekPathReuse::get_next_nonblocked_offset_loc ---------//
  694. //-------- Begin of function SeekPathReuse::get_next_offset_loc ---------//
  695. // get the next location along the main path (reuse reference path)
  696. // return 1 if found, 0 for end of the path
  697. //
  698. int SeekPathReuse::get_next_offset_loc(int& nextXLoc, int& nextYLoc)
  699. {
  700. if(nextXLoc != cur_leader_node_ptr->node_x || nextYLoc != cur_leader_node_ptr->node_y)
  701. {
  702. //--------- point in a the middle of two nodes ----------//
  703. nextXLoc += leader_vec_x*move_scale;
  704. nextYLoc += leader_vec_y*move_scale;
  705. return 1;
  706. }
  707. else if(cur_leader_node_num < reuse_leader_path_node_num)
  708. {
  709. //------------- the end of a node ----------//
  710. cur_leader_node_num++;
  711. cur_leader_node_ptr++;
  712. leader_vec_x = cur_leader_node_ptr->node_x - nextXLoc;
  713. leader_vec_y = cur_leader_node_ptr->node_y - nextYLoc;
  714. err_when(leader_vec_x!=0 && leader_vec_y!=0 && abs(leader_vec_x)!=abs(leader_vec_y));
  715. if(leader_vec_x!=0)
  716. {
  717. leader_vec_x /= abs(leader_vec_x);
  718. nextXLoc += leader_vec_x*move_scale;
  719. }
  720. if(leader_vec_y!=0)
  721. {
  722. leader_vec_y /= abs(leader_vec_y);
  723. nextYLoc += leader_vec_y*move_scale;
  724. }
  725. err_when(nextXLoc<0 || nextXLoc>=MAX_WORLD_X_LOC);
  726. err_when(nextYLoc<0 || nextYLoc>=MAX_WORLD_Y_LOC);
  727. return 1;
  728. }
  729. else
  730. return 0;
  731. }
  732. //--------- End of function SeekPathReuse::get_next_offset_loc ---------//
  733. //-------- Begin of function SeekPathReuse::copy_leader_path_offset ---------//
  734. void SeekPathReuse::copy_leader_path_offset()
  735. {
  736. if(!is_leader_path_valid())
  737. {
  738. incomplete_search++;
  739. reuse_path_status = REUSE_PATH_INCOMPLETE_SEARCH;
  740. return;
  741. }
  742. err_when(leader_path_num<0 || leader_path_num>total_num_of_path);
  743. cur_leader_node_ptr = reuse_leader_path_backup;
  744. cur_leader_node_num = 1;
  745. ResultNode *curNodePtr = cur_leader_node_ptr;
  746. err_when(curNodePtr->node_x+x_offset<0 || curNodePtr->node_x+x_offset>=MAX_WORLD_X_LOC ||
  747. curNodePtr->node_y+y_offset<0 || curNodePtr->node_y+y_offset>=MAX_WORLD_Y_LOC);
  748. int preXLoc = curNodePtr->node_x+x_offset;
  749. int preYLoc = curNodePtr->node_y+y_offset;
  750. add_result(preXLoc, preYLoc);
  751. int curXLoc, curYLoc;
  752. curNodePtr++;
  753. int status = 0; // 0 for current position inside map, 1 for outside map
  754. int checkXLoc, checkYLoc;
  755. int vecX, vecY, magnX, magnY, magn;
  756. int i, quitLoop;
  757. Location *locPtr;
  758. while(cur_leader_node_num++<reuse_leader_path_node_num)
  759. {
  760. curXLoc = curNodePtr->node_x+x_offset;
  761. curYLoc = curNodePtr->node_y+y_offset;
  762. //----------------------------------------------------------------------//
  763. // offset method is terminated when the path leaves the map region for
  764. // this version.
  765. //----------------------------------------------------------------------//
  766. if(curXLoc>=0 && curXLoc<MAX_WORLD_X_LOC && curYLoc>=0 && curYLoc<MAX_WORLD_Y_LOC) // inside map
  767. {
  768. //----------------------------------------------------------------------//
  769. // checking passable condition
  770. //----------------------------------------------------------------------//
  771. if(reuse_search_sub_mode==SEARCH_SUB_MODE_PASSABLE)
  772. {
  773. vecX = curXLoc-preXLoc;
  774. vecY = curYLoc-preYLoc;
  775. magn = ((magnX=abs(vecX)) > (magnY=abs(vecY))) ? magnX : magnY;
  776. if(magnX) vecX /= magnX;
  777. if(magnY) vecY /= magnY;
  778. checkXLoc = preXLoc;
  779. checkYLoc = preYLoc;
  780. quitLoop = 0;
  781. for(i=0; i<magn; ++i)
  782. {
  783. checkXLoc += vecX;
  784. checkYLoc += vecY;
  785. locPtr = world.get_loc(checkXLoc, checkYLoc);
  786. if(locPtr->power_nation_recno && !reuse_nation_passable[locPtr->power_nation_recno])
  787. {
  788. quitLoop = 1;
  789. break; // can't handle this case: not passable and copying leader path
  790. }
  791. }
  792. if(quitLoop)
  793. break;
  794. }
  795. status = 0;
  796. if(!status) // inside
  797. move_within_map(preXLoc, preYLoc, curXLoc, curYLoc);
  798. else // outside
  799. //move_inside_map(preXLoc, preYLoc, curXLoc, curYLoc);
  800. break;
  801. }
  802. else // outside
  803. {
  804. //----------------------------------------------------------------------//
  805. // checking passable condition
  806. //----------------------------------------------------------------------//
  807. if(reuse_search_sub_mode==SEARCH_SUB_MODE_PASSABLE)
  808. break;
  809. status = 1;
  810. if(!status) // inside
  811. {
  812. move_outside_map(preXLoc, preYLoc, curXLoc, curYLoc);
  813. break;
  814. }
  815. else // outside
  816. //move_beyond_map(preXLoc, preYLoc, curXLoc, curYLoc);
  817. break;
  818. }
  819. debug_reuse_check_path(); //-************** debug checking
  820. preXLoc = curXLoc;
  821. preYLoc = curYLoc;
  822. curNodePtr++;
  823. }
  824. debug_reuse_check_path(); //-************** debug checking
  825. }
  826. //--------- End of function SeekPathReuse::copy_leader_path_offset ---------//