OAI_MAR2.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  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 : OAI_MAR2.CPP
  21. //Description: AI functions for processing AI marine actions
  22. #include <OTOWN.h>
  23. #include <OREGIONS.h>
  24. #include <OU_MARI.h>
  25. #include <OF_HARB.h>
  26. #include <ONATION.h>
  27. //-------- Begin of function Nation::ai_sea_travel -------//
  28. //
  29. // action_x_loc, action_y_loc - location of the destination
  30. //
  31. // group_unit_array - array of units that will do the sea travel
  32. // instance_count - no. of units in the array
  33. //
  34. // action_para - the action of units after they have arrived the region,
  35. // it is one of the following:
  36. //
  37. // SEA_ACTION_SETTLE - settle into a town
  38. // SEA_ACTION_BUILD_CAMP - build and assign to a firm
  39. // SEA_ACTION_ASSIGN_TO_FIRM - assign to a firm
  40. // SEA_ACTION_MOVE - just move to the destination
  41. // (this include moving to the location of a battle field.)
  42. //
  43. //---------------------------------------------//
  44. //
  45. // Procedures:
  46. // * 1. Locate a ship, build one if cannot locate any.
  47. // * 2. Assign the units to the ship.
  48. // 3. Move the ship to the destination region.
  49. // 4. Units disembark on the coast.
  50. // 5. Units move to the destination.
  51. //
  52. // This function deal with the 1st and 2nd procedures,
  53. // when they are finished, action ACTION_AI_SEA_TRAVEL2
  54. // will be added.
  55. //
  56. //---------------------------------------------//
  57. //
  58. int Nation::ai_sea_travel(ActionNode* actionNode)
  59. {
  60. err_when( actionNode->instance_count < 1 ||
  61. actionNode->instance_count > ActionNode::MAX_ACTION_GROUP_UNIT );
  62. Unit* unitPtr = unit_array[actionNode->group_unit_array[0]];
  63. err_when( unitPtr->nation_recno != nation_recno );
  64. err_when( !unitPtr->is_visible() );
  65. //---- figure out the sea region id which the ship should appear ----//
  66. int unitRegionId = world.get_region_id(unitPtr->next_x_loc(), unitPtr->next_y_loc());
  67. int destRegionId = world.get_region_id(actionNode->action_x_loc, actionNode->action_y_loc);
  68. int seaRegionId = region_array.get_sea_path_region_id(unitRegionId, destRegionId);
  69. //------- 1. try to locate a ship --------//
  70. int shipUnitRecno = ai_find_transport_ship(seaRegionId, unitPtr->next_x_loc(), unitPtr->next_y_loc());
  71. if( !shipUnitRecno )
  72. return -1; // must return -1 instead of 0 as the action must be executed immediately otherwise the units will be assigned with other action and the unit list may no longer be valid
  73. //---- if this ship is in the harbor, sail it out ----//
  74. UnitMarine* unitMarine = (UnitMarine*) unit_array[shipUnitRecno];
  75. if( unitMarine->unit_mode == UNIT_MODE_IN_HARBOR )
  76. {
  77. FirmHarbor* firmHarbor = (FirmHarbor*) firm_array[unitMarine->unit_mode_para];
  78. firmHarbor->sail_ship(unitMarine->sprite_recno, COMMAND_AI);
  79. }
  80. if( !unitMarine->is_visible() ) // no space in the sea for placing the ship
  81. return -1;
  82. //------ 2. Assign the units to the ship -------//
  83. unitMarine->ai_action_id = actionNode->action_id;
  84. err_when( unit_res[unitMarine->unit_id]->unit_class != UNIT_CLASS_SHIP );
  85. // ##### patch begin Gilbert 5/8 #######//
  86. unit_array.assign_to_ship(unitMarine->next_x_loc(), unitMarine->next_y_loc(), 0, actionNode->group_unit_array, actionNode->instance_count, COMMAND_AI, unitMarine->sprite_recno );
  87. // ##### patch end Gilbert 5/8 #######//
  88. for( int i=0 ; i<actionNode->instance_count ; i++ )
  89. unit_array[ actionNode->group_unit_array[i] ]->ai_action_id = actionNode->action_id;
  90. actionNode->instance_count++; // +1 for the ship
  91. actionNode->processing_instance_count = actionNode->instance_count-1; // -1 because when we return 1, it will be increased by 1 automatically
  92. actionNode->action_para2 = 0; // reset it, it is set in Nation::action_finished()
  93. return 1;
  94. }
  95. //-------- End of function Nation::ai_sea_travel -------//
  96. //-------- Begin of function Nation::ai_sea_travel2 -------//
  97. //
  98. // action_x_loc, action_y_loc - location of the destination
  99. // action_para2 - the recno of the ship
  100. // (this is set when the ship has moved to the beach,
  101. // the function responsible for setting this is Nation::action_finished() )
  102. //
  103. //---------------------------------------------//
  104. //
  105. // Procedures:
  106. // 1. Locate a ship, build one if cannot locate any.
  107. // 2. Assign the units to the ship.
  108. // * 3. Move the ship to the destination region.
  109. // 4. Units disembark on the coast.
  110. // 5. Units move to the destination.
  111. //
  112. //---------------------------------------------//
  113. //
  114. int Nation::ai_sea_travel2(ActionNode* actionNode)
  115. {
  116. if( unit_array.is_deleted(actionNode->action_para2) )
  117. return -1;
  118. UnitMarine* unitMarine = (UnitMarine*) unit_array[actionNode->action_para2];
  119. if( unit_res[unitMarine->unit_id]->unit_class != UNIT_CLASS_SHIP )
  120. return -1;
  121. if( unitMarine->nation_recno != nation_recno )
  122. return -1;
  123. //--------------------------------------------------------//
  124. int realDestXLoc, realDestYLoc; // reference vars for returning vars.
  125. unitMarine->ship_to_beach( actionNode->action_x_loc, actionNode->action_y_loc, realDestXLoc, realDestYLoc ); // the real destination the ship is moving towards.
  126. unitMarine->ai_action_id = actionNode->action_id;
  127. return 1;
  128. }
  129. //-------- End of function Nation::ai_sea_travel2 -------//
  130. //-------- Begin of function Nation::ai_sea_travel3 -------//
  131. //
  132. // action_x_loc, action_y_loc - location of the destination
  133. // action_para2 - the recno of the ship
  134. //
  135. //---------------------------------------------//
  136. //
  137. // Procedures:
  138. // 1. Locate a ship, build one if cannot locate any.
  139. // 2. Assign the units to the ship.
  140. // 3. Move the ship to the destination region.
  141. // * 4. Units disembark on the coast.
  142. // * 5. Units move to the destination.
  143. //
  144. //---------------------------------------------//
  145. //
  146. int Nation::ai_sea_travel3(ActionNode* actionNode)
  147. {
  148. if( unit_array.is_deleted(actionNode->action_para2) )
  149. return -1;
  150. UnitMarine* unitMarine = (UnitMarine*) unit_array[actionNode->action_para2];
  151. if( unit_res[unitMarine->unit_id]->unit_class != UNIT_CLASS_SHIP )
  152. return -1;
  153. if( unitMarine->nation_recno != nation_recno )
  154. return -1;
  155. //-------- 4. Units disembark on the coast. -------//
  156. if( !unitMarine->can_unload_unit() )
  157. return 0;
  158. //--- make a copy of the recnos of the unit on the ship ---//
  159. short unitRecnoArray[MAX_UNIT_IN_SHIP];
  160. short unitCount;
  161. memcpy( unitRecnoArray, unitMarine->unit_recno_array, sizeof(unitRecnoArray) );
  162. unitCount = unitMarine->unit_count;
  163. unitMarine->unload_all_units(COMMAND_AI); // unload all units now
  164. return 1; // finish the action.
  165. /*
  166. //---------- 5. Validate all units ----------//
  167. for( int i=unitCount-1 ; i>=0 ; i-- )
  168. {
  169. if( unit_array.is_deleted( unitRecnoArray[i] ) ||
  170. unit_array[ unitRecnoArray[i] ]->nation_recno != nation_recno )
  171. {
  172. err_when( unitCount > MAX_UNIT_IN_SHIP );
  173. m.del_array_rec( unitRecnoArray, unitCount, sizeof(unitRecnoArray[0]), i+1 );
  174. unitCount--;
  175. }
  176. }
  177. if( unitCount==0 )
  178. return -1;
  179. err_when( unitCount < 0 );
  180. //--- 6. Unit actions after they have arrived the destination region ----//
  181. int destXLoc = actionNode->action_x_loc;
  182. int destYLoc = actionNode->action_y_loc;
  183. Location* locPtr = world.get_loc(destXLoc, destYLoc);
  184. switch(actionNode->action_para)
  185. {
  186. case SEA_ACTION_SETTLE:
  187. if( locPtr->is_town() && town_array[locPtr->town_recno()]->nation_recno == nation_recno )
  188. {
  189. Town *townPtr = town_array[locPtr->town_recno()];
  190. unit_array.assign(townPtr->loc_x1, townPtr->loc_y1, 0, COMMAND_AI, unitRecnoArray, unitCount); // assign to an existing town
  191. }
  192. else //-- if there is no town there, the unit will try to settle, if there is no space for settle, settle() will just have the units move to the destination
  193. {
  194. unit_array.settle(destXLoc, destYLoc, 0, COMMAND_AI, unitRecnoArray, unitCount); // settle as a new town
  195. }
  196. break;
  197. case SEA_ACTION_BUILD_CAMP:
  198. {
  199. Unit* unitPtr = unit_array[ unitRecnoArray[0] ];
  200. unitPtr->build_firm(destXLoc, destYLoc, FIRM_CAMP, COMMAND_AI );
  201. unitPtr->ai_action_id = actionNode->action_id;
  202. actionNode->processing_instance_count++;
  203. break;
  204. }
  205. case SEA_ACTION_ASSIGN_TO_FIRM:
  206. if( check_firm_ready(destXLoc, destYLoc) )
  207. unit_array.assign(destXLoc, destYLoc, 0, COMMAND_AI, unitRecnoArray, unitCount);
  208. break;
  209. case SEA_ACTION_MOVE:
  210. unit_array.move_to(destXLoc, destYLoc, 0, unitRecnoArray, unitCount, COMMAND_AI);
  211. break;
  212. case SEA_ACTION_NONE: // just transport them to the specific region and disemark and wait for their own actions
  213. break;
  214. }
  215. //---------- set the action id. of the units ---------//
  216. if( actionNode->action_para != SEA_ACTION_BUILD_CAMP ) // with the exception of SEA_ACTION_BUILD_CAMP, units in all other actions are immediately executed
  217. {
  218. for( int i=unitCount-1 ; i>=0 ; i-- )
  219. {
  220. unit_array[ unitRecnoArray[i] ]->ai_action_id = actionNode->action_id;
  221. actionNode->processing_instance_count++;
  222. }
  223. }
  224. //---------------------------------------------//
  225. actionNode->processing_instance_count--; // decrease it by one as it will be increased in process_action()
  226. actionNode->instance_count = actionNode->processing_instance_count+1; // set the instance count so process_action() won't cause error.
  227. return 1;
  228. */
  229. }
  230. //-------- End of function Nation::ai_sea_travel3 -------//
  231. //-------- Begin of function Nation::ai_find_transport_ship -------//
  232. //
  233. // Locate a ship for transporting units.
  234. //
  235. // <int> seaRegionId - region id. of the sea which the ship should appear in.
  236. // <int> unitXLoc, unitYLoc - the location of the units to be picked up,
  237. // try to select a harbor close to this location.
  238. // [int] findBest - whether need to find the best ship or just return
  239. // one if there is one found. (default: 1)
  240. //
  241. // return: <int> the recno of the ship located.
  242. //
  243. int Nation::ai_find_transport_ship(int seaRegionId, int unitXLoc, int unitYLoc, int findBest)
  244. {
  245. //------- locate a suitable ship --------//
  246. UnitMarine* unitMarine;
  247. int curRating, bestRating=0, bestUnitRecno=0;
  248. for( int i=0 ; i<ai_ship_count ; i++ )
  249. {
  250. unitMarine = (UnitMarine*) unit_array[ ai_ship_array[i] ];
  251. err_when( unit_res[unitMarine->unit_id]->unit_class != UNIT_CLASS_SHIP );
  252. if( unitMarine->unit_count > 0 || // if there are already units in the ship
  253. unit_res[unitMarine->unit_id]->carry_unit_capacity==0 ) // if the ship does not carry units
  254. {
  255. continue;
  256. }
  257. //------- if this ship is in the harbor ---------//
  258. if( unitMarine->unit_mode == UNIT_MODE_IN_HARBOR )
  259. {
  260. FirmHarbor* firmHarbor = (FirmHarbor*) firm_array[unitMarine->unit_mode_para];
  261. err_when( firmHarbor->firm_id != FIRM_HARBOR );
  262. if( firmHarbor->sea_region_id != seaRegionId )
  263. continue;
  264. }
  265. //--------- if this ship is on the sea ----------//
  266. else
  267. {
  268. if( !unitMarine->is_ai_all_stop() )
  269. continue;
  270. if( unitMarine->region_id() != seaRegionId )
  271. continue;
  272. err_when( !unitMarine->is_visible() );
  273. if( !unitMarine->is_visible() )
  274. continue;
  275. }
  276. //--------- check if the sea region is matched ---------//
  277. if( !findBest ) // return immediately when a suitable one is found
  278. return unitMarine->sprite_recno;
  279. curRating = world.distance_rating( unitXLoc, unitYLoc,
  280. unitMarine->next_x_loc(), unitMarine->next_y_loc() );
  281. curRating += (int)unitMarine->hit_points/10 // damage
  282. + (int)unitMarine->max_hit_points/10; // ship class
  283. if( curRating > bestRating )
  284. {
  285. bestRating = curRating;
  286. bestUnitRecno = unitMarine->sprite_recno;
  287. }
  288. }
  289. return bestUnitRecno;
  290. }
  291. //-------- End of function Nation::ai_find_transport_ship -------//
  292. //-------- Begin of function Nation::ai_build_ship -------//
  293. //
  294. // <int> seaRegionId - region id. of the sea the ship will sail on.
  295. //
  296. // <int> preferXLoc, preferYLoc - prefer selecting a harbor that
  297. // is close to this location.
  298. //
  299. // <int> needTransportUnit - 1 if need to transport units
  300. // 0 if the ship is for trading
  301. //
  302. // return: <int> the recno of the ship that the harbor has building.
  303. //
  304. int Nation::ai_build_ship(int seaRegionId, int preferXLoc, int preferYLoc, int needTransportUnit)
  305. {
  306. //------ select the harbor for building ship -----//
  307. FirmHarbor *firmHarbor, *bestHarbor=NULL;
  308. int curRating, bestRating=0;
  309. for( int i=0 ; i<ai_harbor_count ; i++ )
  310. {
  311. firmHarbor = (FirmHarbor*) firm_array[ ai_harbor_array[i] ];
  312. err_when( firmHarbor->nation_recno != nation_recno );
  313. if( !firmHarbor->can_build_ship() )
  314. continue;
  315. if( firmHarbor->sea_region_id != seaRegionId )
  316. continue;
  317. curRating = world.distance_rating( preferXLoc, preferYLoc,
  318. firmHarbor->center_x, firmHarbor->center_y );
  319. if( curRating > bestRating )
  320. {
  321. bestRating = curRating;
  322. bestHarbor = firmHarbor;
  323. }
  324. }
  325. if( !bestHarbor )
  326. return 0;
  327. //------ think about the type of ship to build -----//
  328. int unitId;
  329. if( needTransportUnit )
  330. {
  331. if( unit_res[UNIT_GALLEON]->get_nation_tech_level(nation_recno) > 0 )
  332. unitId = UNIT_GALLEON;
  333. else if( unit_res[UNIT_CARAVEL]->get_nation_tech_level(nation_recno) > 0 )
  334. unitId = UNIT_GALLEON;
  335. else
  336. unitId = UNIT_VESSEL;
  337. }
  338. else
  339. {
  340. if( unit_res[UNIT_GALLEON]->get_nation_tech_level(nation_recno) > 0 )
  341. unitId = UNIT_GALLEON;
  342. else // don't use Caravel as it can only transport 5 units at a time
  343. unitId = UNIT_TRANSPORT;
  344. }
  345. bestHarbor->build_ship( unitId, COMMAND_AI );
  346. return 1;
  347. }
  348. //-------- End of function Nation::ai_build_ship -------//