OAI_CAPT.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  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_CAPT.CPP
  21. //Description: AI - capturing independent towns
  22. #include <ALL.h>
  23. #include <OREMOTE.h>
  24. #include <OCONFIG.h>
  25. #include <OUNIT.h>
  26. #include <OF_CAMP.h>
  27. #include <OF_INN.h>
  28. #include <ONATION.h>
  29. //------- define struct CaptureTown -------//
  30. struct CaptureTown
  31. {
  32. short town_recno;
  33. short min_resistance;
  34. };
  35. //------ Declare static functions --------//
  36. static int sort_capture_town_function( const void *a, const void *b );
  37. //--------- Begin of function Nation::think_capture --------//
  38. //
  39. int Nation::think_capture()
  40. {
  41. if( ai_camp_count==0 ) // this can happen when a new nation has just emerged
  42. return 0;
  43. //--- don't capture if the AI is using growth and capture strategy (as opposite to build mine strategy) ---//
  44. if( ai_mine_count==0 && total_population < 25 )
  45. return 0;
  46. //-----------------------------------------//
  47. if( think_capture_independent() )
  48. return 1;
  49. return 0;
  50. }
  51. //---------- End of function Nation::think_capture ---------//
  52. //--------- Begin of function Nation::think_capture_independent --------//
  53. //
  54. // Think about capturing independent towns.
  55. //
  56. int Nation::think_capture_independent()
  57. {
  58. //------- Capture target choices -------//
  59. #define MAX_CAPTURE_TOWN 30
  60. CaptureTown capture_town_array[MAX_CAPTURE_TOWN];
  61. short capture_town_count=0;
  62. //--- find the town that makes most sense to capture ---//
  63. int townRecno;
  64. Town* townPtr;
  65. for(townRecno=town_array.size(); townRecno>0; townRecno--)
  66. {
  67. if(town_array.is_deleted(townRecno))
  68. continue;
  69. townPtr = town_array[townRecno];
  70. if( townPtr->nation_recno ) // only capture independent towns
  71. continue;
  72. if( townPtr->no_neighbor_space ) // if there is no space in the neighbor area for building a new firm.
  73. continue;
  74. if( townPtr->rebel_recno ) // towns controlled by rebels will not drop in resistance even if a command base is present
  75. continue;
  76. //------ only if we have a presence/a base town in this region -----//
  77. if( !has_base_town_in_region(townPtr->region_id) )
  78. continue;
  79. //---- check if there are already camps linked to this town ----//
  80. int i;
  81. for( i=townPtr->linked_firm_count-1 ; i>=0 ; i-- )
  82. {
  83. Firm* firmPtr = firm_array[ townPtr->linked_firm_array[i] ];
  84. if( firmPtr->firm_id != FIRM_CAMP )
  85. continue;
  86. //------ if we already have a camp linked to this town -----//
  87. if( firmPtr->nation_recno == nation_recno )
  88. break;
  89. //--- if there is an overseer with high leadership and right race in the opponent's camp, do bother to compete with him ---//
  90. if( firmPtr->overseer_recno )
  91. {
  92. Unit* unitPtr = unit_array[firmPtr->overseer_recno];
  93. if( unitPtr->skill.skill_level >= 70 &&
  94. unitPtr->race_id == townPtr->majority_race() )
  95. {
  96. break;
  97. }
  98. }
  99. }
  100. if( i>=0 ) // there is already a camp linked to this town and we don't want to get involved with its capturing plan
  101. continue;
  102. //-- if the town has linked military camps of the same nation --//
  103. int targetResistance = capture_expected_resistance(townRecno);
  104. int averageResistance = townPtr->average_resistance(nation_recno);
  105. int minResistance = min( averageResistance, targetResistance );
  106. if( minResistance < 50 - pref_peacefulness/5 ) // 30 to 50 depending on
  107. {
  108. capture_town_array[capture_town_count].town_recno = townRecno;
  109. capture_town_array[capture_town_count].min_resistance = minResistance;
  110. capture_town_count++;
  111. }
  112. }
  113. //------ sort the capture target choices by min_resistance ----//
  114. qsort( &capture_town_array, capture_town_count, sizeof(capture_town_array[0]), sort_capture_town_function );
  115. //------- try to capture the town in their resistance order ----//
  116. for( int i=0 ; i<capture_town_count ; i++ )
  117. {
  118. err_when( town_array.is_deleted(capture_town_array[i].town_recno) );
  119. //-------------------------------------------//
  120. // If the map is set to unexplored, wait for a
  121. // reasonable amount of time before moving out
  122. // to build the mine.
  123. //-------------------------------------------//
  124. if( !config.explore_whole_map )
  125. {
  126. Town* targetTown = town_array[ capture_town_array[i].town_recno ];
  127. int j;
  128. for( j=0 ; j<ai_town_count ; j++ )
  129. {
  130. Town* ownTown = town_array[ ai_town_array[j] ];
  131. int townDistance = m.points_distance(targetTown->center_x, targetTown->center_y,
  132. ownTown->center_x, ownTown->center_y);
  133. if( info.game_date-info.game_start_date >
  134. townDistance * (5-config.ai_aggressiveness) / 5 ) // 3 to 5 / 5
  135. {
  136. break;
  137. }
  138. }
  139. if( j==ai_town_count )
  140. continue;
  141. }
  142. if( start_capture( capture_town_array[i].town_recno ) )
  143. return 1;
  144. }
  145. return 0;
  146. }
  147. //---------- End of function Nation::think_capture_independent ---------//
  148. //--------- Begin of function Nation::should_use_cash_to_capture --------//
  149. //
  150. int Nation::should_use_cash_to_capture()
  151. {
  152. //--- if we have plenty of cash, use cash to decrease the resistance of the villagers ---//
  153. return military_rank_rating() < 50+pref_peacefulness/5 && // 50 to 70
  154. ai_should_spend(pref_loyalty_concern/4);
  155. }
  156. //---------- End of function Nation::should_use_cash_to_capture ---------//
  157. //--------- Begin of function Nation::capture_expected_resistance --------//
  158. //
  159. // The lowest resistance can be expected if we are going to capture the
  160. // town.
  161. //
  162. int Nation::capture_expected_resistance(int townRecno)
  163. {
  164. //--- we have plenty of cash, use cash to decrease the resistance of the villagers ---//
  165. if( should_use_cash_to_capture() )
  166. return 0; // return zero resistance
  167. //----- the average resistance determines the captureRating ------//
  168. int captureRating = 0;
  169. Town* townPtr = town_array[townRecno];
  170. int averageResistance;
  171. if( townPtr->nation_recno )
  172. averageResistance = townPtr->average_loyalty();
  173. else
  174. averageResistance = townPtr->average_resistance(nation_recno);
  175. //----- get the id. of the most populated races in the town -----//
  176. int majorityRace = townPtr->majority_race();
  177. err_when( !majorityRace ); // this should not happen
  178. //---- see if there are general available for capturing this town ---//
  179. int targetResistance=0;
  180. if( !find_best_capturer(townRecno, majorityRace, targetResistance) )
  181. return 100;
  182. int resultResistance =
  183. ( targetResistance * townPtr->race_pop_array[majorityRace-1] +
  184. averageResistance * (townPtr->population - townPtr->race_pop_array[majorityRace-1]) )
  185. / townPtr->population;
  186. return resultResistance;
  187. }
  188. //---------- End of function Nation::capture_expected_resistance ---------//
  189. //--------- Begin of function Nation::start_capture --------//
  190. //
  191. int Nation::start_capture(int townRecno)
  192. {
  193. //--- find the two races with most population in the town ---//
  194. Town* townPtr = town_array[townRecno];
  195. int majorityRace=0;
  196. //--- if it's an independent town, the race of the commander must match with the race of the town ---//
  197. if( townPtr->nation_recno == 0 )
  198. {
  199. majorityRace = townPtr->majority_race();
  200. err_when( !majorityRace ); // this shouldn't happen
  201. }
  202. //---- see if we have generals in the most populated race, if so build a camp next to the town ----//
  203. return capture_build_camp(townRecno, majorityRace);
  204. }
  205. //---------- End of function Nation::start_capture ---------//
  206. //--------- Begin of function Nation::capture_build_camp --------//
  207. //
  208. int Nation::capture_build_camp(int townRecno, int raceId)
  209. {
  210. Town* captureTown = town_array[townRecno];
  211. //---- find the best available general for the capturing action ---//
  212. int targetResistance;
  213. int unitRecno = find_best_capturer(townRecno, raceId, targetResistance);
  214. if( !unitRecno )
  215. unitRecno = hire_best_capturer(townRecno, raceId);
  216. if( !unitRecno )
  217. {
  218. //--- if we have plenty of cash and can use cash to decrease the resistance of the independent villagers ---//
  219. if( should_use_cash_to_capture() )
  220. {
  221. char resultFlag;
  222. Unit* skilledUnit = find_skilled_unit(SKILL_LEADING, raceId,
  223. captureTown->center_x, captureTown->center_y, resultFlag);
  224. if( skilledUnit )
  225. unitRecno = skilledUnit->sprite_recno;
  226. }
  227. if( !unitRecno )
  228. return 0;
  229. }
  230. //------- locate a place to build the camp -------//
  231. short buildXLoc, buildYLoc;
  232. if( !find_best_firm_loc(FIRM_CAMP, captureTown->loc_x1, captureTown->loc_y1, buildXLoc, buildYLoc) )
  233. {
  234. captureTown->no_neighbor_space = 1;
  235. return 0;
  236. }
  237. //--- if the picked unit is an overseer of an existng camp ---//
  238. if( !mobilize_capturer(unitRecno) )
  239. return 0;
  240. //---------- add the action to the queue now ----------//
  241. err_when( captureTown->nation_recno==0 &&
  242. unit_array[unitRecno]->race_id != captureTown->majority_race() );
  243. int actionRecno = add_action( buildXLoc, buildYLoc, captureTown->loc_x1, captureTown->loc_y1,
  244. ACTION_AI_BUILD_FIRM, FIRM_CAMP, 1, unitRecno );
  245. if( actionRecno )
  246. process_action(actionRecno);
  247. return 1;
  248. }
  249. //---------- End of function Nation::capture_build_camp ---------//
  250. //-------- Begin of function Nation::find_best_capturer ------//
  251. //
  252. // Find an existing unit as the capturer of the town.
  253. //
  254. // <int> townRecno - recno of the town to capture
  255. // <int> raceId - race id. of the capturer. 0 if any races.
  256. // <int&> bestTargetResistance - a reference var for returning the target resistance if the returned unit is assigned as the overseer
  257. //
  258. // return: <int> the recno of the unit found.
  259. //
  260. int Nation::find_best_capturer(int townRecno, int raceId, int& bestTargetResistance)
  261. {
  262. #define MIN_CAPTURE_RESISTANCE_DEC 20 // if we assign a unit as the commander, the minimum expected resistance decrease should be 20, otherwise we don't do it.
  263. Unit* unitPtr;
  264. Town* targetTown = town_array[townRecno];
  265. Firm* firmPtr;
  266. int targetResistance;
  267. int bestUnitRecno=0;
  268. bestTargetResistance = 100;
  269. for( int i=ai_general_count-1 ; i>=0 ; i-- )
  270. {
  271. unitPtr = unit_array[ ai_general_array[i] ];
  272. if( raceId && unitPtr->race_id != raceId )
  273. continue;
  274. err_when( unitPtr->nation_recno != nation_recno );
  275. err_when( unitPtr->rank_id != RANK_KING && unitPtr->rank_id != RANK_GENERAL );
  276. if( unitPtr->nation_recno != nation_recno )
  277. continue;
  278. //---- if this unit is on a mission ----//
  279. if( unitPtr->home_camp_firm_recno )
  280. continue;
  281. //---- don't use the king to build camps next to capture enemy towns, only next to independent towns ----//
  282. if( unitPtr->rank_id == RANK_KING && targetTown->nation_recno )
  283. continue;
  284. //----- if this unit is in a camp -------//
  285. if( unitPtr->unit_mode == UNIT_MODE_OVERSEE )
  286. {
  287. firmPtr = firm_array[unitPtr->unit_mode_para];
  288. //--- check if the unit currently in a command base trying to take over an independent town ---//
  289. int j;
  290. for( j=firmPtr->linked_town_count-1 ; j>=0 ; j-- )
  291. {
  292. Town* townPtr = town_array[ firmPtr->linked_town_array[j] ];
  293. //--- if the unit is trying to capture an independent town and he is still influencing the town to decrease resistance ---//
  294. if( townPtr->nation_recno==0 &&
  295. townPtr->average_target_resistance(nation_recno) <
  296. townPtr->average_resistance(nation_recno) )
  297. {
  298. break; // then don't use this unit
  299. }
  300. }
  301. if( j>=0 ) // if so, don't use this unit
  302. continue;
  303. }
  304. //--- if this unit is idle and the region ids are matched ---//
  305. if( unitPtr->action_mode != ACTION_STOP ||
  306. unitPtr->region_id() != targetTown->region_id )
  307. {
  308. continue;
  309. }
  310. //------- get the unit's influence index --------//
  311. err_when( unitPtr->skill.skill_id != SKILL_LEADING );
  312. targetResistance = 100-targetTown->camp_influence(unitPtr->sprite_recno); // influence of this unit if he is assigned as a commander of a military camp
  313. //-- see if this unit's rating is higher than the current best --//
  314. if( targetResistance < bestTargetResistance )
  315. {
  316. bestTargetResistance = targetResistance;
  317. bestUnitRecno = unitPtr->sprite_recno;
  318. }
  319. }
  320. return bestUnitRecno;
  321. }
  322. //-------- End of function Nation::find_best_capturer -------//
  323. //-------- Begin of function Nation::mobilize_capturer ------//
  324. //
  325. // Mobilize the capturer unit if he isn't mobilized yet.
  326. //
  327. int Nation::mobilize_capturer(int unitRecno)
  328. {
  329. //--- if the picked unit is an overseer of an existng camp ---//
  330. Unit* unitPtr = unit_array[unitRecno];
  331. if( unitPtr->unit_mode == UNIT_MODE_OVERSEE )
  332. {
  333. Firm* firmPtr = firm_array[unitPtr->unit_mode_para];
  334. Town* townPtr;
  335. //-- can recruit from either a command base or seat of power --//
  336. //-- train a villager with leadership to replace current overseer --//
  337. int i;
  338. for( i=0 ; i<firmPtr->linked_town_count ; i++ )
  339. {
  340. townPtr = town_array[ firmPtr->linked_town_array[i] ];
  341. if( townPtr->nation_recno != nation_recno )
  342. continue;
  343. //--- first try to train a unit who is racially homogenous to the commander ---//
  344. int unitRecno = townPtr->recruit( SKILL_LEADING, firmPtr->majority_race(), COMMAND_AI );
  345. //--- if unsucessful, then try to train a unit whose race is the same as the majority of the town ---//
  346. if( !unitRecno )
  347. unitRecno = townPtr->recruit( SKILL_LEADING, townPtr->majority_race(), COMMAND_AI );
  348. if( unitRecno )
  349. {
  350. add_action(townPtr->loc_x1, townPtr->loc_y1, -1, -1, ACTION_AI_ASSIGN_OVERSEER, FIRM_CAMP);
  351. break;
  352. }
  353. }
  354. if( i==firmPtr->linked_town_count ) // unsuccessful
  355. return 0;
  356. //------- mobilize the current overseer --------//
  357. firmPtr->mobilize_overseer();
  358. }
  359. return 1;
  360. }
  361. //-------- End of function Nation::mobilize_capturer -------//
  362. //-------- Begin of function Nation::hire_best_capturer ------//
  363. //
  364. // Hire the best unit you can find in one of the existing inns.
  365. //
  366. // <int> townRecno - recno of the town to capture
  367. // <int> raceId - race id. of the unit to hire
  368. //
  369. // return: <int> the recno of the unit hired.
  370. //
  371. int Nation::hire_best_capturer(int townRecno, int raceId)
  372. {
  373. if( !ai_should_hire_unit(30) ) // 30 - importance rating
  374. return 0;
  375. FirmInn *firmInn;
  376. Firm *firmPtr;
  377. InnUnit *innUnit;
  378. Skill *innUnitSkill;
  379. int i, j, innUnitCount, curRating;
  380. int bestRating=0, bestInnRecno=0, bestInnUnitId=0;
  381. Town* townPtr = town_array[townRecno];
  382. int destRegionId = world.get_region_id(townPtr->loc_x1, townPtr->loc_y1);
  383. for(i=0; i<ai_inn_count; i++)
  384. {
  385. firmPtr = (FirmInn*) firm_array[ai_inn_array[i]];
  386. err_when( firmPtr->firm_id != FIRM_INN );
  387. if( firmPtr->region_id != destRegionId )
  388. continue;
  389. firmInn = firmPtr->cast_to_FirmInn();
  390. innUnitCount=firmInn->inn_unit_count;
  391. if( !innUnitCount )
  392. continue;
  393. innUnit = firmInn->inn_unit_array + innUnitCount - 1;
  394. //------- check units in the inn ---------//
  395. for(j=innUnitCount; j>0; j--, innUnit--)
  396. {
  397. innUnitSkill = &(innUnit->skill);
  398. if( innUnitSkill->skill_id==SKILL_LEADING &&
  399. unit_res[innUnit->unit_id]->race_id == raceId &&
  400. cash >= innUnit->hire_cost )
  401. {
  402. //----------------------------------------------//
  403. // evalute a unit on:
  404. // -its race, whether it's the same as the nation's race
  405. // -the inn's distance from the destination
  406. // -the skill level of the unit.
  407. //----------------------------------------------//
  408. curRating = innUnitSkill->skill_level;
  409. if( curRating > bestRating )
  410. {
  411. bestRating = curRating;
  412. bestInnRecno = firmInn->firm_recno;
  413. bestInnUnitId = j;
  414. }
  415. }
  416. }
  417. }
  418. if( !bestInnUnitId )
  419. return 0;
  420. //----------------------------------------------------//
  421. firmInn = (FirmInn*) firm_array[bestInnRecno];
  422. int unitRecno = firmInn->hire(bestInnUnitId);
  423. if( !unitRecno )
  424. return 0;
  425. unit_array[unitRecno]->set_rank(RANK_GENERAL);
  426. return unitRecno;
  427. }
  428. //-------- End of function Nation::hire_best_capturer -------//
  429. //------ Begin of function sort_capture_town_function ------//
  430. //
  431. static int sort_capture_town_function( const void *a, const void *b )
  432. {
  433. return ((CaptureTown*)a)->min_resistance - ((CaptureTown*)b)->min_resistance;
  434. }
  435. //------- End of function sort_capture_town_function ------//