OAI_CAP2.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  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_CAP2.CPP
  21. //Description: AI - capturing AI towns
  22. #include <stdlib.h>
  23. #include <ALL.h>
  24. #include <OGAME.h>
  25. #include <OCONFIG.h>
  26. #include <OUNIT.h>
  27. #include <OFIRMALL.h>
  28. #include <OTALKRES.h>
  29. #include <ONATION.h>
  30. //--------- Begin of function Nation::think_capture_new_enemy_town --------//
  31. //
  32. // <Town*> capturerTown - our town to capture enemy towns.
  33. // [int] useAllCamp - whether use troops in all camps to attack the enemy town
  34. // (default: 0)
  35. //
  36. int Nation::think_capture_new_enemy_town(Town* capturerTown, int useAllCamp)
  37. {
  38. if( ai_camp_count==0 ) // this can happen when a new nation has just emerged
  39. return 0;
  40. if( ai_capture_enemy_town_recno ) // no new action if we are still trying to capture a town
  41. return 0;
  42. //---- only attack when we have enough money to support the war ----//
  43. if( cash < 1000 + 2000 * pref_cash_reserve / 100 ) // if the cash is really too low now
  44. return 0;
  45. //--------------------------------------//
  46. Town* targetTown = think_capture_enemy_town_target(capturerTown);
  47. if( !targetTown )
  48. return 0;
  49. //---- attack enemy's defending forces on the target town ----//
  50. int rc = attack_enemy_town_defense(targetTown, useAllCamp);
  51. if( rc==0 ) // 0 means we don't have enough troop to attack the enemy
  52. return 0;
  53. else if( rc == 1 ) // 1 means a troop has been sent to attack the town
  54. {
  55. ai_capture_enemy_town_recno = targetTown->town_recno; // this nation is currently trying to capture this town
  56. ai_capture_enemy_town_plan_date = info.game_date;
  57. ai_capture_enemy_town_start_attack_date = 0;
  58. ai_capture_enemy_town_use_all_camp = useAllCamp;
  59. return 1;
  60. }
  61. else if( rc == -1 ) // -1 means no defense on the target town, no attacking is needed.
  62. {
  63. return start_capture( targetTown->town_recno ); // call AI functions in OAI_CAPT.CPP to capture the town
  64. }
  65. return 0;
  66. }
  67. //---------- End of function Nation::think_capture_new_enemy_town --------//
  68. //--------- Begin of function Nation::think_capturing_enemy_town --------//
  69. void Nation::think_capturing_enemy_town()
  70. {
  71. if( !ai_capture_enemy_town_recno )
  72. return;
  73. if( town_array.is_deleted(ai_capture_enemy_town_recno) ||
  74. town_array[ai_capture_enemy_town_recno]->nation_recno == nation_recno ) // this town has been captured already
  75. {
  76. ai_capture_enemy_town_recno = 0;
  77. return;
  78. }
  79. //--- check the enemy's mobile defense combat level around the town ---//
  80. Town* targetTown = town_array[ai_capture_enemy_town_recno];
  81. int hasWar;
  82. int mobileCombatLevel = mobile_defense_combat_level(targetTown->center_x, targetTown->center_y, targetTown->nation_recno, 0, hasWar); // 0-don't return immediately even if there is war around this town
  83. //---- if we haven't started attacking the town yet -----//
  84. if( !ai_capture_enemy_town_start_attack_date )
  85. {
  86. if( hasWar==2 ) // we are at war with the nation now
  87. ai_capture_enemy_town_start_attack_date = info.game_date;
  88. if( info.game_date > ai_capture_enemy_town_plan_date + 90 ) // when 3 months have gone and there still hasn't been any attack on the town, there must be something bad happened to our troop, cancel the entire action
  89. ai_capture_enemy_town_recno = 0;
  90. return; // do nothing if the attack hasn't started yet
  91. }
  92. //--------- check if we need reinforcement --------//
  93. //-----------------------------------------------------------//
  94. // Check how long we have started attacking because only
  95. // when the it has been started for a while, our force
  96. // will reach the target and the offensive and defensive force
  97. // total can be calculated accurately.
  98. //-----------------------------------------------------------//
  99. if( info.game_date - ai_capture_enemy_town_start_attack_date >= 15 )
  100. {
  101. //-------- check if we need any reinforcement --------//
  102. if( mobileCombatLevel > 0 && hasWar==2 ) // we are still in war with the enemy
  103. {
  104. ai_attack_target(targetTown->center_x, targetTown->center_y, mobileCombatLevel, 0, 1 ); // 1-just all move there and wait for the units to attack the enemies automatically
  105. return;
  106. }
  107. }
  108. //----- there is currently no war at the town -----//
  109. //
  110. // - either we are defeated or we have destroyed their command base.
  111. //
  112. //--------------------------------------------------//
  113. if( hasWar != 2 )
  114. {
  115. //---- attack enemy's defending forces on the target town ----//
  116. int rc = attack_enemy_town_defense(targetTown, ai_capture_enemy_town_use_all_camp);
  117. if( rc == 1 ) // 1 means a troop has been sent to attack the town
  118. {
  119. ai_capture_enemy_town_start_attack_date = 0;
  120. return;
  121. }
  122. //---------- reset the vars --------//
  123. ai_capture_enemy_town_recno = 0;
  124. ai_capture_enemy_town_start_attack_date = 0;
  125. //--------- other situations --------//
  126. if( rc == -1 ) // -1 means no defense on the target town, no attacking is needed.
  127. {
  128. start_capture( targetTown->town_recno ); // call AI functions in OAI_CAPT.CPP to capture the town
  129. }
  130. // 0 means we don't have enough troop to attack the enemy
  131. }
  132. }
  133. //---------- End of function Nation::think_capturing_enemy_town --------//
  134. //--------- Begin of function Nation::attack_enemy_town_defense --------//
  135. //
  136. // Attack enemy's defending forces on the target town.
  137. //
  138. // <Town*> targetTown - the pointer to the target town.
  139. // [int] useAllCamp - whether use troops in all camps to attack the enemy town
  140. // (default: 0)
  141. //
  142. // return: <int> 1 - a troop has been sent to attack the target.
  143. // 0 - we don't have sufficient troops for attacking the target.
  144. // -1 - no defense on the target town, no attacking is needed.
  145. //
  146. int Nation::attack_enemy_town_defense(Town* targetTown, int useAllCamp)
  147. {
  148. err_when( targetTown->nation_recno == nation_recno ); // cannot attack itself
  149. if( targetTown->nation_recno == 0 )
  150. return -1;
  151. //--- if there are any command bases linked to the town, attack them first ---//
  152. int campCombatLevel, maxCampCombatLevel= -1;
  153. Firm *firmPtr, *bestTargetFirm=NULL;
  154. for( int i=targetTown->linked_firm_count-1 ; i>=0 ; i-- )
  155. {
  156. firmPtr = firm_array[ targetTown->linked_firm_array[i] ];
  157. if( firmPtr->nation_recno == targetTown->nation_recno &&
  158. firmPtr->firm_id == FIRM_CAMP )
  159. {
  160. campCombatLevel = ((FirmCamp*)firmPtr)->total_combat_level();
  161. if( campCombatLevel > maxCampCombatLevel )
  162. {
  163. maxCampCombatLevel = campCombatLevel;
  164. bestTargetFirm = firmPtr;
  165. }
  166. }
  167. }
  168. //----- get the defense combat level of the mobile units around the town ----//
  169. int hasWar;
  170. int townMobileCombatLevel = mobile_defense_combat_level(targetTown->center_x, targetTown->center_y, targetTown->nation_recno, 0, hasWar);
  171. int totalDefenseCombatLevel = maxCampCombatLevel + townMobileCombatLevel;
  172. //----------------------------------------//
  173. if( bestTargetFirm )
  174. {
  175. Nation* targetNation = nation_array[bestTargetFirm->nation_recno];
  176. if( targetNation->is_at_war() ) // use all camps force if the nation is at war
  177. useAllCamp = 1;
  178. return ai_attack_target(bestTargetFirm->loc_x1, bestTargetFirm->loc_y1, totalDefenseCombatLevel,
  179. 0, 0, 0, 0, useAllCamp );
  180. }
  181. else
  182. {
  183. //--- if there are any mobile defense force around the town ----//
  184. if( townMobileCombatLevel > 0 )
  185. return ai_attack_target(targetTown->center_x, targetTown->center_y, totalDefenseCombatLevel, 0, 1 ); // 1-just all move there and wait for the units to attack the enemies automatically
  186. }
  187. return -1;
  188. }
  189. //---------- End of function Nation::attack_enemy_town_defense --------//
  190. //--------- Begin of function Nation::think_capture_enemy_town_target --------//
  191. //
  192. // <Town*> capturerTown - our town to capture enemy towns.
  193. //
  194. // Motives for attacking another nation:
  195. //
  196. // 1. Capture towns
  197. // 2. Conquer land
  198. // 3. Defeat enemies
  199. //
  200. Town* Nation::think_capture_enemy_town_target(Town* capturerTown)
  201. {
  202. int townRecno, curRating;
  203. Town* targetTown, *bestTown=NULL;
  204. Firm* firmPtr;
  205. int ourMilitary = military_rank_rating();
  206. Nation* ownNation = nation_array[nation_recno];
  207. int bestRating = -1000;
  208. int hasWar;
  209. int neededCombatLevel=0;
  210. for( townRecno=town_array.size() ; townRecno>0 ; townRecno-- )
  211. {
  212. if( town_array.is_deleted(townRecno) )
  213. continue;
  214. targetTown = town_array[townRecno];
  215. if( targetTown->nation_recno == 0 ||
  216. targetTown->nation_recno == nation_recno )
  217. {
  218. continue;
  219. }
  220. if( targetTown->region_id != capturerTown->region_id )
  221. continue;
  222. //----- if we have already built a camp next to this town -----//
  223. if( targetTown->has_linked_camp(nation_recno, 0) ) //0-count both camps with or without overseers
  224. continue;
  225. //--------- only attack enemies -----------//
  226. NationRelation* nationRelation = get_relation(targetTown->nation_recno);
  227. int rc=0;
  228. if( nationRelation->status == NATION_HOSTILE )
  229. rc = 1;
  230. else if( nationRelation->ai_relation_level < 10 ) // even if the relation is not hostile, if the ai_relation_level is < 10, attack anyway
  231. rc = 1;
  232. else if( nationRelation->status <= NATION_NEUTRAL &&
  233. targetTown->nation_recno == nation_array.max_overall_nation_recno && // if this is our biggest enemy
  234. nationRelation->ai_relation_level < 30 )
  235. {
  236. rc = 1;
  237. }
  238. if( !rc )
  239. continue;
  240. //----- if this town does not have any linked camps, capture this town immediately -----//
  241. if( targetTown->has_linked_camp(targetTown->nation_recno, 0) ) //0-count both camps with or without overseers
  242. return targetTown;
  243. //--- if the enemy is very powerful overall, don't attack it yet ---//
  244. if( nation_array[targetTown->nation_recno]->military_rank_rating() >
  245. ourMilitary * (80+pref_military_courage/2) / 100 )
  246. {
  247. continue;
  248. }
  249. //------ only attack if we have enough money to support the war ----//
  250. if( !ai_should_spend_war( nation_array[targetTown->nation_recno]->military_rank_rating() ) )
  251. continue;
  252. //-------------------------------------------------------//
  253. int townCombatLevel = enemy_town_combat_level(targetTown, 1, hasWar); // 1-return a rating if there is war with the town
  254. if( townCombatLevel == -1 ) // do not attack this town because a battle is already going on
  255. continue;
  256. //------- calculate the rating --------------//
  257. curRating = world.distance_rating(capturerTown->center_x, capturerTown->center_y,
  258. targetTown->center_x, targetTown->center_y);
  259. curRating -= townCombatLevel/10;
  260. curRating -= targetTown->average_loyalty();
  261. curRating += targetTown->population; // put a preference on capturing villages with large population
  262. //----- the power of between the nation also affect the rating ----//
  263. curRating += 2 * (ourMilitary - nation_array[targetTown->nation_recno]->military_rank_rating());
  264. //-- AI Aggressive is set above Low, than the AI will try to capture the player's town first ---//
  265. if( !targetTown->ai_town )
  266. {
  267. if( game.game_mode == GAME_TUTORIAL ) // next attack the player in a tutorial game
  268. {
  269. continue;
  270. }
  271. else
  272. {
  273. switch( config.ai_aggressiveness )
  274. {
  275. case OPTION_MODERATE:
  276. curRating += 100;
  277. break;
  278. case OPTION_HIGH:
  279. curRating += 300;
  280. break;
  281. case OPTION_VERY_HIGH:
  282. curRating += 500;
  283. break;
  284. }
  285. }
  286. }
  287. //--- if there are mines linked to this town, increase its rating ---//
  288. for( int i=targetTown->linked_firm_count-1 ; i>=0 ; i-- )
  289. {
  290. firmPtr = firm_array[ targetTown->linked_firm_array[i] ];
  291. if( firmPtr->nation_recno != targetTown->nation_recno )
  292. continue;
  293. if( firmPtr->firm_id == FIRM_MINE )
  294. {
  295. //--- if this mine's raw materials is one that we don't have --//
  296. if( raw_count_array[ ((FirmMine*)firmPtr)->raw_id-1 ]==0 )
  297. curRating += 150 * (int) ((FirmMine*)firmPtr)->reserve_qty / MAX_RAW_RESERVE_QTY;
  298. }
  299. }
  300. //--- more linked towns increase the attractiveness rating ---//
  301. curRating += targetTown->linked_firm_count*5;
  302. //-------- compare with the current best rating ---------//
  303. if( curRating > bestRating )
  304. {
  305. bestRating = curRating;
  306. bestTown = targetTown;
  307. neededCombatLevel = townCombatLevel;
  308. }
  309. }
  310. return bestTown;
  311. }
  312. //-------- End of function Nation::think_capture_enemy_town_target ------//
  313. //--------- Begin of function Nation::enemy_town_combat_level --------//
  314. //
  315. // <Town*> targetTown - the target town
  316. // <int> returnIfWar - return -1 if there is any war around the town
  317. // <int&> hasWar - a reference var for returning whether there is any war
  318. //
  319. // return: <int> the enemy's total defense combat level minus the player's
  320. // combat level.
  321. /// return -1 if there is war and returnIfWar is 1
  322. //
  323. int Nation::enemy_town_combat_level(Town* targetTown, int returnIfWar, int hasWar)
  324. {
  325. int enemyCombatLevel = mobile_defense_combat_level(targetTown->center_x, targetTown->center_y, targetTown->nation_recno, returnIfWar, hasWar); //0-don't return even there are wars around the town
  326. if( enemyCombatLevel < 0 ) // there is a war going on
  327. return -1;
  328. //---- calculate the attack rating of this target town ----//
  329. // enemyCombatLevel += targetTown->jobless_population * 5; //**BUGHERE
  330. //--- calculate the combat level of enemy camps linked to this town ---//
  331. Firm* firmPtr;
  332. for( int i=targetTown->linked_firm_count-1 ; i>=0 ; i-- )
  333. {
  334. firmPtr = firm_array[ targetTown->linked_firm_array[i] ];
  335. if( firmPtr->nation_recno == targetTown->nation_recno &&
  336. firmPtr->firm_id == FIRM_CAMP )
  337. {
  338. enemyCombatLevel += ((FirmCamp*)firmPtr)->total_combat_level();
  339. }
  340. }
  341. /*
  342. //----- add this and neighbor town's needed combat level ----//
  343. Town* townPtr;
  344. for( i=targetTown->linked_town_count-1 ; i>=0 ; i-- )
  345. {
  346. townPtr = town_array[ targetTown->linked_town_array[i] ];
  347. if( townPtr->nation_recno == targetTown->nation_recno ) //**BUGHERE
  348. enemyCombatLevel += townPtr->jobless_population * 5;
  349. }
  350. */
  351. return enemyCombatLevel;
  352. }
  353. //-------- End of function Nation::enemy_town_combat_level ------//
  354. //--------- Begin of function Nation::enemy_firm_combat_level --------//
  355. //
  356. // <Firm*> targetFirm - the target firm
  357. // <int> returnIfWar - return -1 if there is any war around the town
  358. // <int&> hasWar - a reference var for returning whether there is any war
  359. //
  360. // return: <int> the enemy's total defense combat level minus the player's
  361. // combat level.
  362. /// return -1 if there is war and returnIfWar is 1
  363. //
  364. int Nation::enemy_firm_combat_level(Firm* targetFirm, int returnIfWar, int hasWar)
  365. {
  366. int enemyCombatLevel = mobile_defense_combat_level(targetFirm->center_x, targetFirm->center_y, targetFirm->nation_recno, returnIfWar, hasWar); //0-don't return even there are wars around the town
  367. if( enemyCombatLevel < 0 ) // there is a war going on
  368. return -1;
  369. //--- calculate the combat level of enemy camps linked to this towns that are linked to this mine ---//
  370. Town* linkedTown;
  371. Firm* firmPtr;
  372. int targetNationRecno = targetFirm->nation_recno;
  373. //---- scan towns linked to this mine -----//
  374. for( int i=targetFirm->linked_town_count-1 ; i>=0 ; i-- )
  375. {
  376. linkedTown = town_array[ targetFirm->linked_town_array[i] ];
  377. if( linkedTown->nation_recno != targetNationRecno )
  378. continue;
  379. //------ scan firms linked to this town -------//
  380. for( int j=linkedTown->linked_firm_count-1 ; j>=0 ; j-- )
  381. {
  382. firmPtr = firm_array[ linkedTown->linked_firm_array[j] ];
  383. if( firmPtr->nation_recno == targetNationRecno &&
  384. firmPtr->firm_id == FIRM_CAMP )
  385. {
  386. enemyCombatLevel += ((FirmCamp*)firmPtr)->total_combat_level();
  387. }
  388. }
  389. }
  390. return enemyCombatLevel;
  391. }
  392. //-------- End of function Nation::enemy_firm_combat_level ------//
  393. //------- Begin of function Nation::mobile_defense_combat_level ------//
  394. //
  395. // Take into account of the mobile units around this target location
  396. // when considering attacking it.
  397. //
  398. // <int> targetXLoc, targetYLoc - the target location
  399. // <int> targetNationRecno - nation recno of the target
  400. // <int> returnIfWar - whether return -1 if there is war
  401. // around the given area.
  402. // <int&> hasWar - a var for returning whether there is war
  403. // around the given area.
  404. // 1 - if there is war
  405. // 2 - if our nation is involved in the war
  406. //
  407. // return : >= 0 the defense rating of this location, the rating can be < 0,
  408. // if we have our own units there.
  409. //
  410. // -1 don't attack this town because a battle is already
  411. // going on.
  412. //
  413. int Nation::mobile_defense_combat_level(int targetXLoc, int targetYLoc, int targetNationRecno, int returnIfWar, int& hasWar)
  414. {
  415. //--- the scanning distance is determined by the AI aggressiveness setting ---//
  416. int scanRangeX = 5 + config.ai_aggressiveness * 2;
  417. int scanRangeY = scanRangeX;
  418. int xLoc1 = targetXLoc - scanRangeX;
  419. int yLoc1 = targetYLoc - scanRangeY;
  420. int xLoc2 = targetXLoc + scanRangeX;
  421. int yLoc2 = targetYLoc + scanRangeY;
  422. xLoc1 = max( xLoc1, 0 );
  423. yLoc1 = max( yLoc1, 0 );
  424. xLoc2 = min( xLoc2, MAX_WORLD_X_LOC-1 );
  425. yLoc2 = min( yLoc2, MAX_WORLD_Y_LOC-1 );
  426. //------------------------------------------//
  427. float totalCombatLevel=(float)0; // the higher the rating, the easier we can attack the target town.
  428. int xLoc, yLoc;
  429. Unit* unitPtr;
  430. Location* locPtr;
  431. hasWar = 0;
  432. for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
  433. {
  434. locPtr = world.get_loc(xLoc1, yLoc);
  435. for( xLoc=xLoc1 ; xLoc<=xLoc2 ; xLoc++, locPtr++ )
  436. {
  437. if( !locPtr->has_unit(UNIT_LAND) )
  438. continue;
  439. unitPtr = unit_array[ locPtr->unit_recno(UNIT_LAND) ];
  440. //--------------------------------------------------//
  441. // If there is already a battle going on in this town,
  442. // do not attack this town.
  443. //--------------------------------------------------//
  444. if( unitPtr->cur_action == SPRITE_ATTACK )
  445. {
  446. if( returnIfWar )
  447. return -1;
  448. else
  449. {
  450. if( unitPtr->nation_recno == nation_recno )
  451. hasWar = 2;
  452. else
  453. hasWar = 1;
  454. }
  455. }
  456. //---- if this unit is guarding the town -----//
  457. if( unitPtr->nation_recno == targetNationRecno )
  458. {
  459. totalCombatLevel += unitPtr->unit_power();
  460. }
  461. //------- if this is our own unit ------//
  462. else if( unitPtr->nation_recno == nation_recno )
  463. {
  464. if( unitPtr->cur_action == SPRITE_ATTACK || // only units that are currently attacking or idle are counted, moving units may just be passing by
  465. unitPtr->cur_action == SPRITE_IDLE )
  466. {
  467. totalCombatLevel -= unitPtr->unit_power();
  468. }
  469. }
  470. }
  471. }
  472. if( totalCombatLevel == -1 ) // -1 is reserved for returning don't attack
  473. return 0;
  474. else
  475. return (int) totalCombatLevel;
  476. }
  477. //-------- End of function Nation::mobile_defense_combat_level ------//