OUNIT2.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  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: OUNIT2.CPP
  21. //Description: Unit functions
  22. #include <OWORLD.h>
  23. #include <ONATION.h>
  24. #include <OFIRM.h>
  25. #include <OTOWN.h>
  26. #include <OUNIT.h>
  27. //------- Begin of function Unit::think_aggressive_action --------//
  28. //
  29. // This function is called when the unit is in aggressive mode.
  30. //
  31. int Unit::think_aggressive_action()
  32. {
  33. //------ think about resuming the original action -----//
  34. if( original_action_mode && cur_action!=SPRITE_ATTACK ) // if it is currently attacking somebody, don't think about resuming the original action
  35. {
  36. return think_resume_original_action();
  37. }
  38. //---- think about attacking nearby units if this unit is attacking a town or a firm ---//
  39. if( aggressive_mode && unit_mode==0 && cur_action==SPRITE_ATTACK ) // only in attack mode, as if the unit is still moving the target may be far away from the current position
  40. {
  41. //--- only when the unit is currently attacking a firm or a town ---//
  42. if( action_mode2 == ACTION_ATTACK_FIRM ||
  43. action_mode2 == ACTION_ATTACK_TOWN )
  44. {
  45. if( info.game_date%5==0 ) // check once every 5 days
  46. return think_change_attack_target();
  47. }
  48. }
  49. return 0;
  50. }
  51. //-------- End of function Unit::think_aggressive_action --------//
  52. //--------- Begin of function Unit::think_resume_original_action --------//
  53. //
  54. // If this unit is chasing a target to attack. Stop the chase
  55. // if the target is being far away from its original location.
  56. //
  57. int Unit::think_resume_original_action()
  58. {
  59. if( !is_visible() ) // if the unit is no longer visible, cancel the saved orignal action
  60. {
  61. original_action_mode = 0;
  62. return 0;
  63. }
  64. //---- if the unit is in defense mode now, don't do anything ----//
  65. if( in_any_defense_mode() )
  66. return 0;
  67. //----------------------------------------------------//
  68. //
  69. // If the action has been changed or the target unit has been deleted,
  70. // stop the chase right and move back to the original position
  71. // before the auto guard attack.
  72. //
  73. //----------------------------------------------------//
  74. if(action_mode2!=ACTION_ATTACK_UNIT || unit_array.is_deleted(action_para2))
  75. {
  76. resume_original_action();
  77. return 1;
  78. }
  79. //-----------------------------------------------------//
  80. //
  81. // Stop the chase if the target is being far away from
  82. // its original location and move back to its original
  83. // position before the auto guard attack.
  84. //
  85. //-----------------------------------------------------//
  86. #define AUTO_GUARD_CHASE_ATTACK_DISTANCE 5
  87. Unit* targetUnit = unit_array[action_para2];
  88. int curDistance = m.points_distance( targetUnit->next_x_loc(), targetUnit->next_y_loc(),
  89. original_target_x_loc, original_target_y_loc );
  90. if( curDistance > AUTO_GUARD_CHASE_ATTACK_DISTANCE )
  91. {
  92. resume_original_action();
  93. return 1;
  94. }
  95. return 0;
  96. }
  97. //---------- End of function Unit::think_resume_original_action --------//
  98. //------- Begin of function Unit::think_change_attack_target -------//
  99. //
  100. // When the unit is attacking a firm or town, look out for enemy units
  101. // to attack. Enemy units should be attacked first.
  102. //
  103. int Unit::think_change_attack_target()
  104. {
  105. err_when( !nation_recno ); // only for nation units
  106. //----------------------------------------------//
  107. int attackRange = max(attack_range, 8);
  108. int attackScanRange = attackRange*2+1;
  109. int xOffset, yOffset;
  110. int xLoc, yLoc;
  111. Location* locPtr;
  112. int curXLoc = next_x_loc(), curYLoc = next_y_loc();
  113. BYTE regionId = world.get_region_id(curXLoc, curYLoc);
  114. for( int i=2 ; i<attackScanRange*attackScanRange ; i++ )
  115. {
  116. m.cal_move_around_a_point(i, attackScanRange, attackScanRange, xOffset, yOffset);
  117. xLoc = curXLoc + xOffset;
  118. yLoc = curYLoc + yOffset;
  119. xLoc = max(0, xLoc);
  120. xLoc = min(MAX_WORLD_X_LOC-1, xLoc);
  121. yLoc = max(0, yLoc);
  122. yLoc = min(MAX_WORLD_Y_LOC-1, yLoc);
  123. locPtr = world.get_loc(xLoc, yLoc);
  124. if( locPtr->region_id != regionId )
  125. continue;
  126. //----- if there is a unit on the location ------//
  127. if( locPtr->has_unit(UNIT_LAND) )
  128. {
  129. int unitRecno = locPtr->unit_recno(UNIT_LAND);
  130. if( unit_array.is_deleted(unitRecno) )
  131. continue;
  132. if( unit_array[unitRecno]->nation_recno != nation_recno &&
  133. idle_detect_unit_checking(unitRecno) )
  134. {
  135. save_original_action();
  136. original_target_x_loc = xLoc;
  137. original_target_y_loc = yLoc;
  138. attack_unit(xLoc, yLoc);
  139. return 1;
  140. }
  141. }
  142. }
  143. return 0;
  144. }
  145. //---------- End of function Unit::think_change_attack_target ------//
  146. //----------- Begin of function Unit::save_original_action -------//
  147. void Unit::save_original_action()
  148. {
  149. if( original_action_mode==0 )
  150. {
  151. original_action_mode = action_mode2;
  152. original_action_para = action_para2;
  153. original_action_x_loc = action_x_loc2;
  154. original_action_y_loc = action_y_loc2;
  155. }
  156. }
  157. //----------- End of function Unit::save_original_action -------//
  158. //----------- Begin of function Unit::resume_original_action -------//
  159. void Unit::resume_original_action()
  160. {
  161. if( !original_action_mode )
  162. return;
  163. //--------- If it is an attack action ---------//
  164. if( original_action_mode == ACTION_ATTACK_UNIT ||
  165. original_action_mode == ACTION_ATTACK_FIRM ||
  166. original_action_mode == ACTION_ATTACK_TOWN )
  167. {
  168. resume_original_attack_action();
  169. return;
  170. }
  171. //--------------------------------------------//
  172. if( original_action_x_loc<0 || original_action_x_loc>=MAX_WORLD_X_LOC ||
  173. original_action_y_loc<0 || original_action_y_loc>=MAX_WORLD_Y_LOC )
  174. {
  175. original_action_mode = 0;
  176. return;
  177. }
  178. short selectedArray[1];
  179. selectedArray[0] = sprite_recno; // use unit_array.attack() instead of unit.attack_???() as we are unsure about what type of object the target is.
  180. Location* locPtr = world.get_loc(original_action_x_loc, original_action_y_loc);
  181. //--------- resume assign to town -----------//
  182. if( original_action_mode == ACTION_ASSIGN_TO_TOWN && locPtr->is_town() )
  183. {
  184. if( locPtr->town_recno() == original_action_para &&
  185. town_array[original_action_para]->nation_recno == nation_recno )
  186. {
  187. unit_array.assign( original_action_x_loc, original_action_y_loc, 0,
  188. COMMAND_AUTO, selectedArray, 1 );
  189. }
  190. }
  191. //--------- resume assign to firm ----------//
  192. else if( original_action_mode == ACTION_ASSIGN_TO_FIRM && locPtr->is_firm() )
  193. {
  194. if( locPtr->firm_recno() == original_action_para &&
  195. firm_array[original_action_para]->nation_recno == nation_recno )
  196. {
  197. unit_array.assign( original_action_x_loc, original_action_y_loc, 0,
  198. COMMAND_AUTO, selectedArray, 1 );
  199. }
  200. }
  201. //--------- resume build firm ---------//
  202. else if( original_action_mode == ACTION_BUILD_FIRM )
  203. {
  204. if( world.can_build_firm( original_action_x_loc, original_action_y_loc,
  205. original_action_para, sprite_recno ) )
  206. {
  207. build_firm( original_action_x_loc, original_action_y_loc,
  208. original_action_para, COMMAND_AUTO );
  209. }
  210. }
  211. //--------- resume settle ---------//
  212. else if( original_action_mode == ACTION_SETTLE )
  213. {
  214. if( world.can_build_town( original_action_x_loc, original_action_y_loc, sprite_recno ) )
  215. {
  216. unit_array.settle( original_action_x_loc, original_action_y_loc,
  217. 0, COMMAND_AUTO, selectedArray, 1 );
  218. }
  219. }
  220. //--------- resume move ----------//
  221. else if( original_action_mode == ACTION_MOVE )
  222. {
  223. unit_array.move_to( original_action_x_loc, original_action_y_loc, 0,
  224. selectedArray, 1, COMMAND_AUTO );
  225. }
  226. original_action_mode = 0;
  227. }
  228. //----------- End of function Unit::resume_original_action -------//
  229. //----------- Begin of function Unit::resume_original_attack_action -------//
  230. //
  231. void Unit::resume_original_attack_action()
  232. {
  233. if( !original_action_mode )
  234. return;
  235. if( original_action_mode != ACTION_ATTACK_UNIT &&
  236. original_action_mode != ACTION_ATTACK_FIRM &&
  237. original_action_mode != ACTION_ATTACK_TOWN )
  238. {
  239. original_action_mode = 0;
  240. return;
  241. }
  242. //--------------------------------------------//
  243. err_when( original_action_x_loc<0 || original_action_x_loc>=MAX_WORLD_X_LOC );
  244. err_when( original_action_y_loc<0 || original_action_y_loc>=MAX_WORLD_Y_LOC );
  245. Location* locPtr = world.get_loc(original_action_x_loc, original_action_y_loc);
  246. int targetNationRecno = -1;
  247. if( original_action_mode == ACTION_ATTACK_UNIT && locPtr->has_unit(UNIT_LAND) )
  248. {
  249. int unitRecno = locPtr->unit_recno(UNIT_LAND);
  250. if( unitRecno == original_action_para )
  251. targetNationRecno = unit_array[unitRecno]->nation_recno;
  252. }
  253. else if( original_action_mode == ACTION_ATTACK_FIRM && locPtr->is_firm() )
  254. {
  255. int firmRecno = locPtr->firm_recno();
  256. if( firmRecno == original_action_para )
  257. targetNationRecno = firm_array[firmRecno]->nation_recno;
  258. }
  259. else if( original_action_mode == ACTION_ATTACK_TOWN && locPtr->is_town() )
  260. {
  261. int townRecno = locPtr->town_recno();
  262. if( townRecno == original_action_para )
  263. targetNationRecno = town_array[townRecno]->nation_recno;
  264. }
  265. //----- the original target is no longer valid ----//
  266. if( targetNationRecno == -1 )
  267. {
  268. original_action_mode = 0;
  269. return;
  270. }
  271. //---- only resume attacking the target if the target nation is at war with us currently ---//
  272. if( !targetNationRecno || (targetNationRecno &&
  273. targetNationRecno != nation_recno &&
  274. nation_array[nation_recno]->get_relation_status(targetNationRecno) == NATION_HOSTILE ))
  275. {
  276. short selectedArray[1];
  277. selectedArray[0] = sprite_recno; // use unit_array.attack() instead of unit.attack_???() as we are unsure about what type of object the target is.
  278. // #### begin Gilbert 5/8 ########//
  279. unit_array.attack(original_action_x_loc, original_action_y_loc, 0, selectedArray, 1, COMMAND_AI, 0 );
  280. // #### end Gilbert 5/8 ########//
  281. }
  282. original_action_mode = 0;
  283. }
  284. //----------- End of function Unit::resume_original_attack_action -------//
  285. //------- Begin of function Unit::ask_team_help_attack --------//
  286. //
  287. // It returns whether any of the co-member of this unit in a troop
  288. // is under attack.
  289. //
  290. // <Unit*> attackerUnit - the unit pointer of the attacker
  291. //
  292. void Unit::ask_team_help_attack(Unit* attackerUnit)
  293. {
  294. //--- if the attacking unit is our unit (this can happen if the unit is porcupine) ---//
  295. if( attackerUnit->nation_recno == nation_recno )
  296. return;
  297. //-----------------------------------------//
  298. int leaderUnitRecno=0;
  299. if( leader_unit_recno ) // if the current unit is a soldier, get its leader's recno
  300. leaderUnitRecno = leader_unit_recno;
  301. else if( team_info ) // this unit is the commander
  302. leaderUnitRecno = sprite_recno;
  303. if( leaderUnitRecno )
  304. {
  305. TeamInfo* teamInfo = unit_array[leaderUnitRecno]->team_info;
  306. err_when( !teamInfo );
  307. for( int i=teamInfo->member_count-1 ; i>=0 ; i-- )
  308. {
  309. int unitRecno = teamInfo->member_unit_array[i];
  310. if( unit_array.is_deleted(unitRecno) )
  311. continue;
  312. Unit* unitPtr = unit_array[ unitRecno ];
  313. if( unitPtr->cur_action==SPRITE_IDLE && unitPtr->is_visible() )
  314. {
  315. unitPtr->attack_unit(attackerUnit->sprite_recno);
  316. return;
  317. }
  318. }
  319. }
  320. }
  321. //-------- End of function Unit::ask_team_help_attack --------//