OUNITAT3.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978
  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. //Filename : OUNITAT3.CPP
  21. //Description : Object Unit's decision making functions for attacking same or different type of target and reactivating
  22. // idle unit that are ordered to attack
  23. //Owner : Alex
  24. #include <ALL.h>
  25. #include <OWORLD.h>
  26. #include <OUNIT.h>
  27. #include <OGAME.h>
  28. #ifdef NO_DEBUG_UNIT
  29. #undef err_when
  30. #undef err_here
  31. #undef err_if
  32. #undef err_else
  33. #undef err_now
  34. #define err_when(cond)
  35. #define err_here()
  36. #define err_if(cond)
  37. #define err_else
  38. #define err_now(msg)
  39. #undef DEBUG
  40. #endif
  41. //--------- Begin of function Unit::move_try_to_range_attack ---------//
  42. // return 1 if it is possible to reach a location to attack the target
  43. // return 0 otherwise
  44. //
  45. // <Unit*> targetUnit - pointer to target unit
  46. //
  47. int Unit::move_try_to_range_attack(Unit* targetUnit)
  48. {
  49. int curXLoc = next_x_loc();
  50. int curYLoc = next_y_loc();
  51. int targetXLoc = targetUnit->next_x_loc();
  52. int targetYLoc = targetUnit->next_y_loc();
  53. if(world.get_loc(curXLoc, curYLoc)->region_id==world.get_loc(targetXLoc, targetYLoc)->region_id)
  54. {
  55. //------------ for same region id, search now ---------------//
  56. if(search(targetXLoc, targetYLoc, 1, SEARCH_MODE_TO_ATTACK, action_para))
  57. return 1;
  58. else // search failure,
  59. {
  60. stop2(KEEP_DEFENSE_MODE);
  61. return 0;
  62. }
  63. }
  64. else
  65. {
  66. //--------------- different territory ------------------//
  67. int targetWidth = targetUnit->sprite_info->loc_width;
  68. int targetHeight = targetUnit->sprite_info->loc_height;
  69. int maxRange = max_attack_range();
  70. if(possible_place_for_range_attack(targetXLoc, targetYLoc, targetWidth, targetHeight, maxRange))
  71. {
  72. //---------------------------------------------------------------------------------//
  73. // space is found, attack target now
  74. //---------------------------------------------------------------------------------//
  75. if(move_to_range_attack(targetXLoc, targetYLoc, targetUnit->sprite_id, SEARCH_MODE_ATTACK_UNIT_BY_RANGE, maxRange))
  76. return 1;
  77. else
  78. {
  79. stop2(KEEP_DEFENSE_MODE);
  80. return 0;
  81. }
  82. return 1;
  83. }
  84. else
  85. {
  86. //---------------------------------------------------------------------------------//
  87. // unable to find location to attack the target, stop or move to the target
  88. //---------------------------------------------------------------------------------//
  89. if(action_mode2!=ACTION_AUTO_DEFENSE_ATTACK_TARGET && action_mode2!=ACTION_DEFEND_TOWN_ATTACK_TARGET &&
  90. action_mode2!=ACTION_MONSTER_DEFEND_ATTACK_TARGET)
  91. move_to(targetXLoc, targetYLoc, 1); // abort attacking, just call move_to() instead
  92. else
  93. stop2(KEEP_DEFENSE_MODE);
  94. return 0;
  95. }
  96. }
  97. return 0;
  98. }
  99. //----------- End of function Unit::move_try_to_range_attack -----------//
  100. //--------- Begin of function Unit::move_to_range_attack ---------//
  101. // search and attack target
  102. //
  103. // <int> targetXLoc - target x location
  104. // <int> targetYLoc - target y location
  105. // <short> miscNo - is sprite_id if target is a unit
  106. // is firm_id if target is a firm
  107. // is 0 if target is a town or a wall
  108. // <short> searchMode - search mode being used
  109. // <short> maxRange - max attack range of this unit
  110. //
  111. int Unit::move_to_range_attack(int targetXLoc, int targetYLoc, short miscNo, short searchMode, short maxRange)
  112. {
  113. //---------------------------------------------------------------------------------//
  114. // part 1, searching
  115. //---------------------------------------------------------------------------------//
  116. seek_path.set_attack_range_para(maxRange);
  117. search(targetXLoc, targetYLoc, 1, searchMode, miscNo);
  118. seek_path.reset_attack_range_para();
  119. //search(targetXLoc, targetYLoc, 1, searchMode, maxRange);
  120. if(result_node_array==NULL || result_node_count==0)
  121. return 0;
  122. //---------------------------------------------------------------------------------//
  123. // part 2, editing result path
  124. //---------------------------------------------------------------------------------//
  125. Location *locPtr = world.get_loc(next_x_loc(), next_y_loc());
  126. err_when(!locPtr);
  127. int regionId = locPtr->region_id; // the region_id this unit in
  128. //----------------------------------------------------//
  129. err_when(result_node_count<2);
  130. ResultNode* editNode1 = result_node_array + result_node_count - 1;
  131. ResultNode* editNode2 = editNode1-1;
  132. int vecX = editNode1->node_x - editNode2->node_x;
  133. int vecY = editNode1->node_y - editNode2->node_y;
  134. if(vecX)
  135. vecX = ((vecX>0) ? 1 : -1)*move_step_magn();
  136. if(vecY)
  137. vecY = ((vecY>0) ? 1 : -1)*move_step_magn();
  138. int x = editNode1->node_x;
  139. int y = editNode1->node_y;
  140. int i, found=0, removedStep=0, preX, preY;
  141. for(i=result_node_count; i>1; i--)
  142. {
  143. while(x!=editNode2->node_x || y!=editNode2->node_y)
  144. {
  145. locPtr = world.get_loc(x, y);
  146. if(locPtr->region_id == regionId)
  147. {
  148. found = i;
  149. preX = x;
  150. preY = y;
  151. break;
  152. }
  153. x -= vecX;
  154. y -= vecY;
  155. removedStep++;
  156. }
  157. if(found)
  158. break;
  159. editNode1 = editNode2;
  160. editNode2--;
  161. vecX = editNode1->node_x - editNode2->node_x;
  162. vecY = editNode1->node_y - editNode2->node_y;
  163. if(vecX)
  164. vecX = ((vecX>0) ? 1 : -1)*move_step_magn();
  165. if(vecY)
  166. vecY = ((vecY>0) ? 1 : -1)*move_step_magn();
  167. x = editNode1->node_x;
  168. y = editNode1->node_y;
  169. }
  170. //---------------------------------------------------------------------------//
  171. // update unit parameters
  172. //---------------------------------------------------------------------------//
  173. if(found)
  174. {
  175. result_node_count = found;
  176. ResultNode* lastNode = result_node_array + result_node_count - 1;
  177. int goX = go_x>>ZOOM_X_SHIFT_COUNT;
  178. int goY = go_y>>ZOOM_Y_SHIFT_COUNT;
  179. //---------------------------------------------------------------------//
  180. // note: build?Loc-1, build?Loc+width, build?Loc+height may <0 or
  181. // >MAX_WORLD_?_LOC. To prevent errors from occuring, goX, goY
  182. // must not be outside the map boundary
  183. //---------------------------------------------------------------------//
  184. if(goX==editNode1->node_x && goY==editNode1->node_y)
  185. {
  186. go_x = preX*ZOOM_LOC_WIDTH;
  187. go_y = preY*ZOOM_LOC_HEIGHT;
  188. }
  189. else if(result_node_count==2)
  190. {
  191. int magnCG = m.points_distance(cur_x, cur_y, go_x, go_y);
  192. int magnNG = m.points_distance(next_x, next_y, go_x, go_y);
  193. err_when(magnCG==0 && magnNG==0);
  194. if(magnCG && magnNG)
  195. {
  196. //---------- lie on the same line -----------//
  197. if( (go_x-cur_x)/magnCG==(go_x-next_x)/magnNG && (go_y-cur_y)/magnCG==(go_y-next_y)/magnNG )
  198. {
  199. go_x = preX*ZOOM_LOC_WIDTH;
  200. go_y = preY*ZOOM_LOC_HEIGHT;
  201. }
  202. }
  203. }
  204. lastNode->node_x = preX;
  205. lastNode->node_y = preY;
  206. move_to_x_loc = lastNode->node_x;
  207. move_to_y_loc = lastNode->node_y;
  208. result_path_dist -= (removedStep)*move_step_magn();
  209. err_when((cur_x!=next_x || cur_y!=next_y) && // is not blocked
  210. (check_unit_dir1=get_dir(cur_x, cur_y, next_x, next_y))!=(check_unit_dir2=get_dir(cur_x, cur_y, go_x, go_y)));
  211. }
  212. return found;
  213. }
  214. //----------- End of function Unit::move_to_range_attack -----------//
  215. //--------- Begin of function Unit::can_attack_different_type_target ---------//
  216. // return 1 if able to use range_attack
  217. // return 0 otherwise
  218. //
  219. int Unit::can_attack_different_target_type()
  220. {
  221. int maxRange = max_attack_range();
  222. if(mobile_type==UNIT_LAND && !maxRange)
  223. return 0; // unable to do range attack or cannot attack
  224. if(maxRange>1)
  225. return maxRange;
  226. else
  227. return 0;
  228. }
  229. //----------- End of function Unit::can_attack_different_type_target -----------//
  230. //--------- Begin of function Unit::possible_place_for_range_attack ---------//
  231. // check whether there is any place for this unit to attack the target
  232. //
  233. // <int> targetXLoc - target x location
  234. // <int> targetYLoc - target y location
  235. // <int> targetWidth - target width
  236. // <int> targetHeight - target height
  237. // <int> maxRange - max attack range of this unit
  238. //
  239. // return 1 if place found
  240. // return 0 otherwise
  241. //
  242. int Unit::possible_place_for_range_attack(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight, int maxRange)
  243. {
  244. err_when(targetXLoc<0 || targetXLoc>=MAX_WORLD_X_LOC || targetYLoc<0 || targetYLoc>=MAX_WORLD_Y_LOC);
  245. err_when(maxRange==0);
  246. if(mobile_type==UNIT_AIR)
  247. return 1; // air unit can reach any region
  248. int curXLoc = next_x_loc();
  249. int curYLoc = next_y_loc();
  250. if(abs(curXLoc-targetXLoc)<=maxRange && abs(curYLoc-targetYLoc)<=maxRange) // inside the attack range
  251. return 1;
  252. //----------------- init parameters -----------------//
  253. Location *locPtr = world.get_loc(curXLoc, curYLoc);
  254. int regionId = locPtr->region_id;
  255. int xLoc1 = max(targetXLoc-maxRange, 0);
  256. int yLoc1 = max(targetYLoc-maxRange, 0);
  257. int xLoc2 = min(targetXLoc+targetWidth-1+maxRange, MAX_WORLD_X_LOC-1);
  258. int yLoc2 = min(targetYLoc+targetHeight-1+maxRange, MAX_WORLD_Y_LOC-1);
  259. int checkXLoc, checkYLoc;
  260. //--------- do adjustment for UNIT_SEA and UNIT_AIR ---------//
  261. if(mobile_type!=UNIT_LAND)
  262. {
  263. if(xLoc1%2)
  264. xLoc1++;
  265. if(yLoc1%2)
  266. yLoc1++;
  267. if(xLoc2%2)
  268. xLoc2--;
  269. if(yLoc2%2)
  270. yLoc2--;
  271. }
  272. //-------- checking for surrounding location ----------//
  273. switch(mobile_type)
  274. {
  275. case UNIT_LAND:
  276. for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++)
  277. {
  278. locPtr = world.get_loc(checkXLoc, yLoc1);
  279. if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
  280. return 1;
  281. locPtr = world.get_loc(checkXLoc, yLoc2);
  282. if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
  283. return 1;
  284. }
  285. for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++)
  286. {
  287. locPtr = world.get_loc(xLoc1, checkYLoc);
  288. if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
  289. return 1;
  290. locPtr = world.get_loc(xLoc2, checkYLoc);
  291. if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
  292. return 1;
  293. }
  294. break;
  295. case UNIT_SEA:
  296. for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++)
  297. {
  298. if(checkXLoc%2==0 && yLoc1%2==0)
  299. {
  300. locPtr = world.get_loc(checkXLoc, yLoc1);
  301. if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
  302. return 1;
  303. }
  304. if(checkXLoc%2==0 && yLoc2%2==0)
  305. {
  306. locPtr = world.get_loc(checkXLoc, yLoc2);
  307. if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
  308. return 1;
  309. }
  310. }
  311. for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++)
  312. {
  313. if(xLoc1%2==0 && checkYLoc%2==0)
  314. {
  315. locPtr = world.get_loc(xLoc1, checkYLoc);
  316. if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
  317. return 1;
  318. }
  319. if(xLoc2%2==0 && checkYLoc%2==0)
  320. {
  321. locPtr = world.get_loc(xLoc2, checkYLoc);
  322. if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
  323. return 1;
  324. }
  325. }
  326. break;
  327. case UNIT_AIR:
  328. for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++)
  329. {
  330. if(checkXLoc%2==0 && yLoc1%2==0)
  331. {
  332. locPtr = world.get_loc(checkXLoc, yLoc1);
  333. if(locPtr->is_accessible(mobile_type))
  334. return 1;
  335. }
  336. if(checkXLoc%2==0 && yLoc2%2==0)
  337. {
  338. locPtr = world.get_loc(checkXLoc, yLoc2);
  339. if(locPtr->is_accessible(mobile_type))
  340. return 1;
  341. }
  342. }
  343. for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++)
  344. {
  345. if(xLoc1%2==0 && checkYLoc%2==0)
  346. {
  347. locPtr = world.get_loc(xLoc1, checkYLoc);
  348. if(locPtr->is_accessible(mobile_type))
  349. return 1;
  350. }
  351. if(xLoc2%2==0 && checkYLoc%2==0)
  352. {
  353. locPtr = world.get_loc(xLoc2, checkYLoc);
  354. if(locPtr->is_accessible(mobile_type))
  355. return 1;
  356. }
  357. }
  358. break;
  359. default: err_here();
  360. break;
  361. }
  362. return 0;
  363. }
  364. //----------- End of function Unit::possible_place_for_range_attack -----------//
  365. //=====================================================================================//
  366. //--------- Begin of function Unit::space_for_attack ---------//
  367. // check whether there is any place for the unit to attack target.
  368. //
  369. // <int> targetXLoc - target x location
  370. // <int> targetYLoc - target y location
  371. // <char> targetMobileType - target mobile type
  372. // <int> targetWidth - target width
  373. // <int> targetHeight - target height
  374. //
  375. int Unit::space_for_attack(int targetXLoc, int targetYLoc, char targetMobileType, int targetWidth, int targetHeight)
  376. {
  377. if(mobile_type==UNIT_LAND && targetMobileType==UNIT_LAND)
  378. return space_around_target(targetXLoc, targetYLoc, targetWidth, targetHeight);
  379. if((mobile_type==UNIT_SEA && targetMobileType==UNIT_SEA) ||
  380. (mobile_type==UNIT_AIR && targetMobileType==UNIT_AIR))
  381. return space_around_target_ver2(targetXLoc, targetYLoc, targetWidth, targetHeight);
  382. //-------------------------------------------------------------------------//
  383. // mobile_type is differet from that of target unit
  384. //-------------------------------------------------------------------------//
  385. Location *locPtr = world.get_loc(next_x_loc(), next_y_loc());
  386. if(mobile_type==UNIT_LAND && targetMobileType==UNIT_SEA &&
  387. !can_attack_different_target_type() &&
  388. ship_surr_has_free_land(targetXLoc, targetYLoc, locPtr->region_id))
  389. return 1;
  390. int maxRange = max_attack_range();
  391. if(maxRange==1)
  392. return 0;
  393. if(free_space_for_range_attack(targetXLoc, targetYLoc, targetWidth, targetHeight, targetMobileType, maxRange))
  394. return 1;
  395. return 0;
  396. }
  397. //----------- End of function Unit::space_for_attack -----------//
  398. //--------- Begin of function Unit::space_around_target ---------//
  399. // check the surroundung location around a square, and the result is
  400. // stored in the blocked_edge[] by bit
  401. //
  402. // <int> squareXLoc - upper left x location of target
  403. // <int> squareYLoc - upper left y location of target
  404. // <int> width - target width
  405. // <int> height - target height
  406. //
  407. // return 1 if the surrounding location that can_move is not equal to
  408. // the result in the blocked_edge stored previously.
  409. // return 0 otherwise (i.e. all location situation is same as before)
  410. //
  411. int Unit::space_around_target(int squareXLoc, int squareYLoc, int width, int height)
  412. {
  413. err_when(width<=0 || height<=0);
  414. // edge 1
  415. // 1 1 4
  416. // edge 2 2 x 4 edge 4
  417. // 2 3 3
  418. // edge3
  419. Location *locPtr;
  420. Unit *unitPtr;
  421. char sum, locWeight;
  422. int testXLoc, testYLoc, i, equal=1;
  423. //------------------ top edge ---------------//
  424. sum = 0;
  425. if((testYLoc=squareYLoc-1) >= 0)
  426. {
  427. if(squareXLoc>=1) // have upper left corner
  428. {
  429. i=-1;
  430. locWeight = 1;
  431. }
  432. else
  433. {
  434. i = 0;
  435. locWeight = 2;
  436. }
  437. for(; i<width; i++, locWeight<<=1)
  438. {
  439. locPtr = world.get_loc(squareXLoc+i, testYLoc);
  440. if(locPtr->can_move(mobile_type))
  441. sum ^= locWeight;
  442. else if(locPtr->has_unit(mobile_type))
  443. {
  444. unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
  445. if(unitPtr->cur_action!=SPRITE_ATTACK)
  446. sum ^= locWeight;
  447. }
  448. }
  449. }
  450. if(blocked_edge[0]!=sum)
  451. {
  452. blocked_edge[0] = sum;
  453. equal = 0;
  454. }
  455. //----------------- left edge -----------------//
  456. sum = 0;
  457. if((testXLoc=squareXLoc-1) >= 0)
  458. {
  459. if(squareYLoc+height<=MAX_WORLD_Y_LOC-1) // have lower left corner
  460. {
  461. i = height;
  462. locWeight = 1;
  463. }
  464. else
  465. {
  466. i = height - 1;
  467. locWeight = 2;
  468. }
  469. for(; i>=0; i--, locWeight<<=1)
  470. {
  471. locPtr = world.get_loc(testXLoc, squareYLoc+i);
  472. if(locPtr->can_move(mobile_type))
  473. sum ^= locWeight;
  474. else if(locPtr->has_unit(mobile_type))
  475. {
  476. unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
  477. if(unitPtr->cur_action!=SPRITE_ATTACK)
  478. sum ^= locWeight;
  479. }
  480. }
  481. }
  482. if(blocked_edge[1]!=sum)
  483. {
  484. blocked_edge[1] = sum;
  485. equal = 0;
  486. }
  487. //------------------- bottom edge ------------------//
  488. sum = 0;
  489. if((testYLoc=squareYLoc+height) <= MAX_WORLD_Y_LOC-1)
  490. {
  491. if(squareXLoc+width<=MAX_WORLD_X_LOC-1) // have lower right corner
  492. {
  493. i = width;
  494. locWeight = 1;
  495. }
  496. else
  497. {
  498. i = width - 1;
  499. locWeight = 2;
  500. }
  501. for(; i>=0; i--, locWeight<<=1)
  502. {
  503. locPtr = world.get_loc(squareXLoc+i, testYLoc);
  504. if(locPtr->can_move(mobile_type))
  505. sum ^= locWeight;
  506. else if(locPtr->has_unit(mobile_type))
  507. {
  508. unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
  509. if(unitPtr->cur_action!=SPRITE_ATTACK)
  510. sum ^= locWeight;
  511. }
  512. }
  513. }
  514. if(blocked_edge[2]!=sum)
  515. {
  516. blocked_edge[2] = sum;
  517. equal = 0;
  518. }
  519. //---------------------- right edge ----------------------//
  520. sum = 0;
  521. if((testXLoc=squareXLoc+width) <= MAX_WORLD_X_LOC-1)
  522. {
  523. if(squareYLoc>=1) // have upper right corner
  524. {
  525. i = -1;
  526. locWeight = 1;
  527. }
  528. else
  529. {
  530. i = 0;
  531. locWeight = 2;
  532. }
  533. for(; i<height; i++, locWeight<<=1)
  534. {
  535. locPtr = world.get_loc(testXLoc, squareYLoc+i);
  536. if(locPtr->can_move(mobile_type))
  537. sum ^= locWeight;
  538. else if(locPtr->has_unit(mobile_type))
  539. {
  540. unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
  541. if(unitPtr->cur_action!=SPRITE_ATTACK)
  542. sum ^= locWeight;
  543. }
  544. }
  545. }
  546. if(blocked_edge[3]!=sum)
  547. {
  548. blocked_edge[3] = sum;
  549. equal = 0;
  550. }
  551. return !equal;
  552. }
  553. //----------- End of function Unit::space_around_target -----------//
  554. //--------- Begin of function Unit::space_around_target_ver2 ---------//
  555. // similar function as space_around_target()
  556. // This version is for sea unit and air unit only
  557. //
  558. int Unit::space_around_target_ver2(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight)
  559. {
  560. err_when(targetWidth<=0 || targetHeight<=0);
  561. Location *locPtr;
  562. Unit *unitPtr;
  563. char sum, locWeight;
  564. int xLoc1, yLoc1, xLoc2, yLoc2;
  565. int i, equal=1;
  566. //int testXLoc, testYLoc,
  567. xLoc1 = targetXLoc%2 ? targetXLoc-1 : targetXLoc-2;
  568. yLoc1 = targetYLoc%2 ? targetYLoc-1 : targetYLoc-2;
  569. xLoc2 = (targetXLoc+targetWidth-1)%2 ? targetXLoc+targetWidth : targetXLoc+targetWidth+1;
  570. yLoc2 = (targetYLoc+targetHeight-1)%2 ? targetYLoc+targetHeight : targetYLoc+targetHeight+1;
  571. //------------------------ top edge ------------------------//
  572. sum = 0;
  573. if(yLoc1>=0)
  574. {
  575. if(xLoc1>=0)
  576. {
  577. i = xLoc1;
  578. locWeight = 1;
  579. }
  580. else
  581. {
  582. i = xLoc1 + 2;
  583. err_when(i<0);
  584. locWeight = 2;
  585. }
  586. for(; i<=xLoc2; i+=2, locWeight<<=1)
  587. {
  588. locPtr = world.get_loc(i, yLoc1);
  589. if(locPtr->can_move(mobile_type))
  590. sum ^= locWeight;
  591. else if(locPtr->has_unit(mobile_type))
  592. {
  593. unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
  594. if(unitPtr->cur_action!=SPRITE_ATTACK)
  595. sum ^= locWeight;
  596. }
  597. }
  598. }
  599. if(blocked_edge[0]!=sum)
  600. {
  601. blocked_edge[0] = sum;
  602. equal = 0;
  603. }
  604. //---------------------- left edge -----------------------//
  605. sum = 0;
  606. if(xLoc1>=0)
  607. {
  608. if(yLoc2<=MAX_WORLD_Y_LOC-1)
  609. {
  610. i = yLoc2;
  611. locWeight = 1;
  612. }
  613. else
  614. {
  615. i = yLoc2-2;
  616. err_when(i>=MAX_WORLD_Y_LOC);
  617. locWeight = 2;
  618. }
  619. for(; i>yLoc1; i-=2, locWeight<<=1)
  620. {
  621. locPtr = world.get_loc(xLoc1, i);
  622. if(locPtr->can_move(mobile_type))
  623. sum ^= locWeight;
  624. else if(locPtr->has_unit(mobile_type))
  625. {
  626. unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
  627. if(unitPtr->cur_action!=SPRITE_ATTACK)
  628. sum ^= locWeight;
  629. }
  630. }
  631. }
  632. if(blocked_edge[1]!=sum)
  633. {
  634. blocked_edge[1] = sum;
  635. equal = 0;
  636. }
  637. //----------------------- bottom edge ---------------------------//
  638. sum = 0;
  639. if(yLoc2<=MAX_WORLD_Y_LOC-1)
  640. {
  641. if(xLoc2<=MAX_WORLD_X_LOC-1)
  642. {
  643. i = xLoc2;
  644. locWeight = 1;
  645. }
  646. else
  647. {
  648. i = xLoc2-2;
  649. err_when(i>=MAX_WORLD_X_LOC);
  650. locWeight = 2;
  651. }
  652. for(; i>xLoc1; i-=2, locWeight<<=1)
  653. {
  654. locPtr = world.get_loc(i, yLoc2);
  655. if(locPtr->can_move(mobile_type))
  656. sum ^= locWeight;
  657. else if(locPtr->has_unit(mobile_type))
  658. {
  659. unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
  660. if(unitPtr->cur_action!=SPRITE_ATTACK)
  661. sum ^= locWeight;
  662. }
  663. }
  664. }
  665. if(blocked_edge[2]!=sum)
  666. {
  667. blocked_edge[2] = sum;
  668. equal = 0;
  669. }
  670. //---------------------- right edge ------------------------//
  671. sum = 0;
  672. if(xLoc2<=MAX_WORLD_X_LOC-1)
  673. {
  674. if(yLoc1>=0)
  675. {
  676. i = yLoc1;
  677. locWeight = 1;
  678. }
  679. else
  680. {
  681. i = yLoc1+2;
  682. err_when(i<0);
  683. locWeight = 2;
  684. }
  685. for(; i<yLoc2; i+=2, locWeight<<=1)
  686. {
  687. locPtr = world.get_loc(xLoc2, i);
  688. if(locPtr->can_move(mobile_type))
  689. sum ^= locWeight;
  690. else if(locPtr->has_unit(mobile_type))
  691. {
  692. unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
  693. if(unitPtr->cur_action!=SPRITE_ATTACK)
  694. sum ^= locWeight;
  695. }
  696. }
  697. }
  698. if(blocked_edge[3]!=sum)
  699. {
  700. blocked_edge[3] = sum;
  701. equal = 0;
  702. }
  703. return !equal;
  704. }
  705. //----------- End of function Unit::space_around_target_ver2 -----------//
  706. //--------- Begin of function Unit::ship_surr_has_free_land ---------//
  707. // check surrounding place for close attack by land units
  708. //
  709. // <int> targetXLoc - target x loc
  710. // <int> targetYLoc - target y loc
  711. // <UCHAR> regionId - region id
  712. //
  713. // return 1 if there is space for the land unit to move to ship surrounding for close attack
  714. // return 0 otherwise
  715. //
  716. int Unit::ship_surr_has_free_land(int targetXLoc, int targetYLoc, UCHAR regionId)
  717. {
  718. err_when(mobile_type!=UNIT_LAND);
  719. Location *locPtr;
  720. int xShift, yShift, checkXLoc, checkYLoc;
  721. for(int i=2; i<9; i++)
  722. {
  723. m.cal_move_around_a_point(i, 3, 3, xShift, yShift);
  724. checkXLoc = targetXLoc+xShift;
  725. checkYLoc = targetYLoc+yShift;
  726. if(checkXLoc<0 || checkXLoc>=MAX_WORLD_X_LOC || checkYLoc<0 || checkYLoc>=MAX_WORLD_Y_LOC)
  727. continue;
  728. locPtr = world.get_loc(checkXLoc, checkYLoc);
  729. if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
  730. return 1;
  731. }
  732. return 0;
  733. }
  734. //----------- End of function Unit::ship_surr_has_free_land -----------//
  735. //--------- Begin of function Unit::free_space_for_range_attack ---------//
  736. // similar to possible_place_for_range_attack() but checking can_move() rather than is_accessible()
  737. //
  738. int Unit::free_space_for_range_attack(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight, int targetMobileType, int maxRange)
  739. {
  740. err_when(targetXLoc<0 || targetXLoc>=MAX_WORLD_X_LOC || targetYLoc<0 || targetYLoc>=MAX_WORLD_Y_LOC);
  741. err_when(maxRange==0);
  742. //if(mobile_type==UNIT_AIR)
  743. // return 1; // air unit can reach any region
  744. int curXLoc = next_x_loc();
  745. int curYLoc = next_y_loc();
  746. if(abs(curXLoc-targetXLoc)<=maxRange && abs(curYLoc-targetYLoc)<=maxRange) // inside the attack range
  747. return 1;
  748. Location *locPtr = world.get_loc(curXLoc, curYLoc);
  749. int regionId = locPtr->region_id;
  750. int xLoc1 = max(targetXLoc-maxRange, 0);
  751. int yLoc1 = max(targetYLoc-maxRange, 0);
  752. int xLoc2 = min(targetXLoc+targetWidth-1+maxRange, MAX_WORLD_X_LOC-1);
  753. int yLoc2 = min(targetYLoc+targetHeight-1+maxRange, MAX_WORLD_Y_LOC-1);
  754. int checkXLoc, checkYLoc;
  755. //--------- do adjustment for UNIT_SEA and UNIT_AIR ---------//
  756. if(mobile_type!=UNIT_LAND)
  757. {
  758. if(xLoc1%2)
  759. xLoc1++;
  760. if(yLoc1%2)
  761. yLoc1++;
  762. if(xLoc2%2)
  763. xLoc2--;
  764. if(yLoc2%2)
  765. yLoc2--;
  766. }
  767. //-------- checking for surrounding location ----------//
  768. switch(mobile_type)
  769. {
  770. case UNIT_LAND:
  771. for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++)
  772. {
  773. locPtr = world.get_loc(checkXLoc, yLoc1);
  774. if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
  775. return 1;
  776. locPtr = world.get_loc(checkXLoc, yLoc2);
  777. if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
  778. return 1;
  779. }
  780. for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++)
  781. {
  782. locPtr = world.get_loc(xLoc1, checkYLoc);
  783. if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
  784. return 1;
  785. locPtr = world.get_loc(xLoc2, checkYLoc);
  786. if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
  787. return 1;
  788. }
  789. break;
  790. case UNIT_SEA:
  791. for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++)
  792. {
  793. if(checkXLoc%2==0 && yLoc1%2==0)
  794. {
  795. locPtr = world.get_loc(checkXLoc, yLoc1);
  796. if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
  797. return 1;
  798. }
  799. if(checkXLoc%2==0 && yLoc2%2==0)
  800. {
  801. locPtr = world.get_loc(checkXLoc, yLoc2);
  802. if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
  803. return 1;
  804. }
  805. }
  806. for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++)
  807. {
  808. if(xLoc1%2==0 && checkYLoc%2==0)
  809. {
  810. locPtr = world.get_loc(xLoc1, checkYLoc);
  811. if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
  812. return 1;
  813. }
  814. if(xLoc2%2==0 && checkYLoc%2==0)
  815. {
  816. locPtr = world.get_loc(xLoc2, checkYLoc);
  817. if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
  818. return 1;
  819. }
  820. }
  821. break;
  822. case UNIT_AIR:
  823. for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++)
  824. {
  825. if(checkXLoc%2==0 && yLoc1%2==0)
  826. {
  827. locPtr = world.get_loc(checkXLoc, yLoc1);
  828. if(locPtr->can_move(mobile_type))
  829. return 1;
  830. }
  831. if(checkXLoc%2==0 && yLoc2%2==0)
  832. {
  833. locPtr = world.get_loc(checkXLoc, yLoc2);
  834. if(locPtr->can_move(mobile_type))
  835. return 1;
  836. }
  837. }
  838. for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++)
  839. {
  840. if(xLoc1%2==0 && checkYLoc%2==0)
  841. {
  842. locPtr = world.get_loc(xLoc1, checkYLoc);
  843. if(locPtr->can_move(mobile_type))
  844. return 1;
  845. }
  846. if(xLoc2%2==0 && checkYLoc%2==0)
  847. {
  848. locPtr = world.get_loc(xLoc2, checkYLoc);
  849. if(locPtr->can_move(mobile_type))
  850. return 1;
  851. }
  852. }
  853. break;
  854. default: err_here();
  855. break;
  856. }
  857. return 0;
  858. }
  859. //----------- End of function Unit::free_space_for_range_attack -----------//