OAI_ATTK.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924
  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_ATTK.CPP
  21. //Description: AI - attacking
  22. #include <stdlib.h>
  23. #include <ALL.h>
  24. #include <OUNIT.h>
  25. #include <OCONFIG.h>
  26. #include <OFIRMALL.h>
  27. #include <OTALKRES.h>
  28. #include <ONATION.h>
  29. //------ Declare static functions --------//
  30. static int get_target_nation_recno(int targetXLoc, int targetYLoc);
  31. static int sort_attack_camp_function( const void *a, const void *b );
  32. //--------- Begin of function Nation::ai_attack_target --------//
  33. //
  34. // Think about attacking a specific target.
  35. //
  36. // <int> targetXLoc, targetYLoc - location of the target
  37. // <int> targetCombatLevel - the combat level of the target, will
  38. // only attack the target if the attacker's
  39. // force is larger than it.
  40. // [int] defenseMode - whether the attack is basically for
  41. // defending against an attack
  42. // (default: 0)
  43. // [int] justMoveToFlag - whether just all move there and wait for
  44. // the units to attack the enemies automatically
  45. // (default: 0)
  46. // [int] attackerMinCombatLevel - the minimum combat level of the attacker,
  47. // do not send troops whose combat level
  48. // is lower than this.
  49. // (default: 0)
  50. // [int] leadAttackCampRecno - if this is given, this camp will be
  51. // included in the attacker list by passing
  52. // checking on it.
  53. // (default: 0)
  54. // [int] useAllCamp - use all camps to attack even if defenseMode is 0
  55. // (default: defenseMode, which is default to 0)
  56. //
  57. // return: <int> 0 - no attack action
  58. // >0 - the total combat level of attacking force.
  59. //
  60. int Nation::ai_attack_target(int targetXLoc, int targetYLoc, int targetCombatLevel, int defenseMode, int justMoveToFlag, int attackerMinCombatLevel, int leadAttackCampRecno, int useAllCamp)
  61. {
  62. /* // this will be called when the AI tries to capture the town and attack the town's defense.
  63. #ifdef DEBUG //----- check for attacking own objects error ------//
  64. {
  65. int targetNationRecno = get_target_nation_recno(targetXLoc, targetYLoc);
  66. if( targetNationRecno )
  67. {
  68. err_when( get_relation(targetNationRecno)->status >= NATION_FRIENDLY );
  69. }
  70. }
  71. #endif
  72. */
  73. //--- order nearby mobile units who are on their way to home camps to join this attack mission. ---//
  74. if( defenseMode )
  75. useAllCamp = 1;
  76. if( defenseMode ) // only for defense mode, for attack mission, we should plan and organize it better
  77. {
  78. int originalTargetCombatLevel;
  79. targetCombatLevel = ai_attack_order_nearby_mobile(targetXLoc, targetYLoc, targetCombatLevel);
  80. if( targetCombatLevel < 0 ) // the mobile force alone can finish all the enemies
  81. return originalTargetCombatLevel;
  82. }
  83. //--- try to send troop with maxTargetCombatLevel, and don't send troop if available combat level < minTargetCombatLevel ---//
  84. int maxTargetCombatLevel = targetCombatLevel * (150+pref_force_projection/2) / 100; // 150% to 200%
  85. int minTargetCombatLevel;
  86. if( defenseMode )
  87. minTargetCombatLevel = targetCombatLevel * (100-pref_military_courage/2) / 100; // 50% to 100%
  88. else
  89. minTargetCombatLevel = targetCombatLevel * (125+pref_force_projection/4) / 100; // 125% to 150%
  90. //--- if the AI is already on an attack mission ---//
  91. if( attack_camp_count )
  92. return 0;
  93. //---- first locate for camps that do not need to protect any towns ---//
  94. #define MAX_SUITABLE_TOWN_CAMP 10 // no. of camps in a town
  95. FirmCamp* firmCamp;
  96. int i, j;
  97. int targetRegionId = world.get_loc(targetXLoc, targetYLoc)->region_id;
  98. err_when( targetXLoc < 0 || targetXLoc >= MAX_WORLD_X_LOC );
  99. err_when( targetYLoc < 0 || targetYLoc >= MAX_WORLD_Y_LOC );
  100. ai_attack_target_x_loc = targetXLoc;
  101. ai_attack_target_y_loc = targetYLoc;
  102. ai_attack_target_nation_recno = get_target_nation_recno(targetXLoc, targetYLoc);
  103. attack_camp_count=0;
  104. AttackCamp townCampArray[MAX_SUITABLE_TOWN_CAMP];
  105. short townCampCount;
  106. //------- if there is a pre-selected camp -------//
  107. lead_attack_camp_recno = leadAttackCampRecno;
  108. if( leadAttackCampRecno )
  109. {
  110. err_when( firm_array[leadAttackCampRecno]->nation_recno != nation_recno );
  111. err_when( firm_array[leadAttackCampRecno]->firm_id != FIRM_CAMP );
  112. attack_camp_array[attack_camp_count].firm_recno = leadAttackCampRecno;
  113. attack_camp_array[attack_camp_count].combat_level = ((FirmCamp*)firm_array[leadAttackCampRecno])->total_combat_level();
  114. err_when( attack_camp_array[attack_camp_count].combat_level < 0 );
  115. attack_camp_count++;
  116. }
  117. //---- if the military courage is low or the king is injured, don't send the king out to battles ---//
  118. Nation* ownNation = nation_array[nation_recno];
  119. int kingFirmRecno=0;
  120. if( king_unit_recno )
  121. {
  122. Unit* kingUnit = unit_array[king_unit_recno];
  123. if( kingUnit->unit_mode == UNIT_MODE_OVERSEE )
  124. {
  125. Firm* kingFirm = firm_array[kingUnit->unit_mode_para];
  126. int rc = 0;
  127. if( ai_camp_count > 3 + (100-ownNation->pref_military_courage)/20 ) // don't use the king if we have other generals, the king won't be used if we have 3 to 8 camps. The higher the military courage is, the smaller will be the number of camps
  128. rc = 1;
  129. //--- if the military courage is low or the king is injured ---//
  130. else if( kingUnit->hit_points < 230-ownNation->pref_military_courage ) // 130 to 230, if over 200, the king will not fight
  131. rc = 1;
  132. //--- if the King does have a full troop ----//
  133. else if( kingFirm->worker_count < MAX_WORKER )
  134. rc = 1;
  135. //-------------------------------------------//
  136. if( rc )
  137. {
  138. kingFirmRecno = kingUnit->unit_mode_para;
  139. //--- if the king is very close to the target, ask him to attack also ---//
  140. if( kingFirmRecno &&
  141. kingUnit->hit_points >= 150-ownNation->pref_military_courage/4 ) // if the king is not heavily injured
  142. {
  143. firmCamp = (FirmCamp*) firm_array[kingFirmRecno];
  144. if( firmCamp->worker_count == MAX_WORKER ) // the king shouldn't go out alone
  145. {
  146. if( m.points_distance(firmCamp->center_x, firmCamp->center_y,
  147. targetXLoc, targetYLoc) <= EFFECTIVE_FIRM_TOWN_DISTANCE )
  148. {
  149. kingFirmRecno = 0;
  150. }
  151. }
  152. }
  153. }
  154. }
  155. }
  156. //--------- locate for camps that are not linked to towns ---------//
  157. int rc;
  158. for( i=0 ; i<ai_camp_count ; i++ )
  159. {
  160. firmCamp = (FirmCamp*) firm_array[ ai_camp_array[i] ];
  161. err_when( firmCamp->firm_id != FIRM_CAMP );
  162. if( firmCamp->region_id != targetRegionId )
  163. continue;
  164. if( !firmCamp->overseer_recno || !firmCamp->worker_count )
  165. continue;
  166. if( firmCamp->patrol_unit_count > 0 ) // if there are units patrolling out
  167. continue;
  168. if( firmCamp->ai_capture_town_recno ) // the base is trying to capture an independent town
  169. continue;
  170. if( firmCamp->is_attack_camp )
  171. continue;
  172. if( firmCamp->firm_recno == kingFirmRecno )
  173. continue;
  174. //---- don't order this camp if the overseer is injured ----//
  175. Unit* overseerUnit = unit_array[firmCamp->overseer_recno];
  176. if( overseerUnit->hit_points < overseerUnit->max_hit_points &&
  177. overseerUnit->hit_points < 100-ownNation->pref_military_courage/2 ) // 50 to 100
  178. {
  179. continue;
  180. }
  181. //----------------------------------------------------------//
  182. if( attackerMinCombatLevel )
  183. {
  184. if( firmCamp->average_combat_level() < attackerMinCombatLevel )
  185. continue;
  186. }
  187. //-------------------------------------//
  188. //
  189. // Add this camp if:
  190. // 1. we are in defense mode, and have to get all the forces available to defend against the attack.
  191. // 2. this camp isn't linked to any of our towns.
  192. //
  193. //-------------------------------------//
  194. if( useAllCamp )
  195. rc = 1;
  196. else
  197. {
  198. rc = firmCamp->linked_town_count==0; // don't use this camp as it may be in the process of capturing an indepdendent town or an enemy town
  199. /*
  200. for( int j=firmCamp->linked_town_count-1 ; j>=0 ; j-- )
  201. {
  202. if( town_array[firmCamp->linked_town_array[j]]->nation_recno == nation_recno )
  203. break;
  204. }
  205. rc = j<0; // j<0 means not linked to any of our towns.
  206. */
  207. }
  208. if( rc )
  209. {
  210. //--- if this camp into the list of suitable attacker firm ---//
  211. if( attack_camp_count < MAX_SUITABLE_ATTACK_CAMP )
  212. {
  213. err_when( firmCamp->nation_recno != nation_recno );
  214. attack_camp_array[attack_camp_count].firm_recno = firmCamp->firm_recno;
  215. attack_camp_array[attack_camp_count].combat_level = firmCamp->total_combat_level();
  216. err_when( attack_camp_array[attack_camp_count].combat_level < 0 );
  217. attack_camp_count++;
  218. }
  219. }
  220. }
  221. //---- locate for camps that are extra for protecting towns (there are basic ones doing the protection job only) ----//
  222. int totalCombatLevel, protectionNeeded;
  223. Town* townPtr;
  224. Firm* firmPtr;
  225. if( !useAllCamp ) // in defense mode, every camp has been already counted
  226. {
  227. for( i=0 ; i<ai_town_count ; i++ )
  228. {
  229. townPtr = town_array[ ai_town_array[i] ];
  230. if( townPtr->region_id != targetRegionId )
  231. continue;
  232. err_when( townPtr->nation_recno != nation_recno );
  233. //----- calculate the protection needed for this town ----//
  234. protectionNeeded = townPtr->protection_needed();
  235. townCampCount =0;
  236. totalCombatLevel=0;
  237. for( j=townPtr->linked_firm_count-1 ; j>=0 ; j-- )
  238. {
  239. firmPtr = firm_array[ townPtr->linked_firm_array[j] ];
  240. if( firmPtr->nation_recno != nation_recno )
  241. continue;
  242. if( firmPtr->firm_recno == kingFirmRecno )
  243. continue;
  244. //----- if this is a camp, add combat level points -----//
  245. if( firmPtr->firm_id == FIRM_CAMP )
  246. {
  247. if( !firmPtr->overseer_recno && !firmPtr->worker_count )
  248. continue;
  249. firmCamp = (FirmCamp*) firmPtr;
  250. if( firmCamp->patrol_unit_count > 0 ) // if there are units patrolling out
  251. continue;
  252. if( firmCamp->ai_capture_town_recno ) // the base is trying to capture an independent town
  253. continue;
  254. if( firmCamp->is_attack_camp )
  255. continue;
  256. totalCombatLevel += firmCamp->total_combat_level();
  257. if( townCampCount < MAX_SUITABLE_TOWN_CAMP )
  258. {
  259. err_when( firmCamp->nation_recno != nation_recno );
  260. townCampArray[townCampCount].firm_recno = firmCamp->firm_recno;
  261. townCampArray[townCampCount].combat_level = firmCamp->total_combat_level();
  262. err_when( townCampArray[townCampCount].combat_level < 0 );
  263. townCampCount++;
  264. }
  265. }
  266. //--- if this is a civilian firm, add needed protection points ---//
  267. else
  268. {
  269. if( firmPtr->firm_id == FIRM_MARKET )
  270. protectionNeeded += ((FirmMarket*)firmPtr)->stock_value_index();
  271. else
  272. protectionNeeded += (int) firmPtr->productivity;
  273. }
  274. }
  275. //--- see if the current combat level is larger than the protection needed ---//
  276. if( totalCombatLevel > protectionNeeded )
  277. {
  278. //--- see if the protection is still enough if we put one of the camps into the upcoming battle ---//
  279. for( int j=0 ; j<townCampCount ; j++ )
  280. {
  281. if( totalCombatLevel - townCampArray[j].combat_level > protectionNeeded )
  282. {
  283. //--- if so, add this camp to the suitable camp list ---//
  284. if( attack_camp_count < MAX_SUITABLE_ATTACK_CAMP )
  285. {
  286. //--- this camp can be linked to a town previously processed already (in this case, two towns linked to the same camp) ---//
  287. int k;
  288. for( k=0 ; k<attack_camp_count ; k++ )
  289. {
  290. if( attack_camp_array[k].firm_recno == townCampArray[j].firm_recno )
  291. break;
  292. }
  293. //---- if this camp hasn't been added yet ----//
  294. if( k==attack_camp_count )
  295. {
  296. err_when( firm_array[townCampArray[j].firm_recno]->nation_recno != nation_recno );
  297. attack_camp_array[attack_camp_count] = townCampArray[j];
  298. attack_camp_count++;
  299. totalCombatLevel -= townCampArray[j].combat_level; // reduce it from the total combat level as its combat level has just been used, and is no longer available
  300. }
  301. }
  302. }
  303. }
  304. }
  305. }
  306. }
  307. //---- now we get all suitable camps in the list, it's time to attack ---//
  308. //----- think about which ones in the list should be used -----//
  309. //--- first calculate the total combat level of these camps ---//
  310. totalCombatLevel = 0;
  311. for( i=0 ; i<attack_camp_count ; i++ )
  312. totalCombatLevel += attack_camp_array[i].combat_level;
  313. //--- see if we are not strong enough to attack yet -----//
  314. if( totalCombatLevel < minTargetCombatLevel ) // if we are not strong enough to attack yet
  315. {
  316. attack_camp_count=0;
  317. return 0;
  318. }
  319. //----- build an array of the distance data first -----//
  320. for( i=0 ; i<attack_camp_count ; i++ )
  321. {
  322. firmPtr = firm_array[ attack_camp_array[i].firm_recno ];
  323. err_when( firmPtr->nation_recno != nation_recno );
  324. attack_camp_array[i].distance = m.points_distance( firmPtr->center_x, firmPtr->center_y,
  325. targetXLoc, targetYLoc );
  326. err_when( attack_camp_array[i].distance < 0 );
  327. }
  328. //---- now sort the camps based on their distances & combat levels ----//
  329. qsort( &attack_camp_array, attack_camp_count, sizeof(attack_camp_array[0]), sort_attack_camp_function );
  330. //----- now take out the lowest rating ones -----//
  331. for( i=attack_camp_count-1 ; i>=0 ; i-- )
  332. {
  333. if( totalCombatLevel - attack_camp_array[i].combat_level > maxTargetCombatLevel )
  334. {
  335. totalCombatLevel -= attack_camp_array[i].combat_level;
  336. attack_camp_count--;
  337. }
  338. }
  339. err_when( attack_camp_count < 0 );
  340. //------- synchronize the attack date for different camps ----//
  341. ai_attack_target_sync();
  342. ai_attack_target_execute(!justMoveToFlag);
  343. return totalCombatLevel;
  344. }
  345. //---------- End of function Nation::ai_attack_target --------//
  346. //--------- Begin of function Nation::ai_attack_order_nearby_mobile --------//
  347. //
  348. // Order nearby mobile units who are on their way to home camps to
  349. // join this attack mission.
  350. //
  351. // <int> targetXLoc, targetYLoc - location of the target
  352. // <int> targetCombatLevel - the combat level of the target, will
  353. // only attack the target if the attacker's
  354. // force is larger than it.
  355. //
  356. // return: <int> the remaining target combat level of the target
  357. // after ordering the mobile units to deal with some of them.
  358. //
  359. int Nation::ai_attack_order_nearby_mobile(int targetXLoc, int targetYLoc, int targetCombatLevel)
  360. {
  361. int scanRange = 15+pref_military_development/20; // 15 to 20
  362. int xOffset, yOffset;
  363. int xLoc, yLoc;
  364. int targetRegionId = world.get_region_id(targetXLoc, targetYLoc);
  365. Location* locPtr;
  366. for( int i=2 ; i<scanRange*scanRange ; i++ )
  367. {
  368. m.cal_move_around_a_point(i, scanRange, scanRange, xOffset, yOffset);
  369. xLoc = targetXLoc + xOffset;
  370. yLoc = targetYLoc + yOffset;
  371. xLoc = max(0, xLoc);
  372. xLoc = min(MAX_WORLD_X_LOC-1, xLoc);
  373. yLoc = max(0, yLoc);
  374. yLoc = min(MAX_WORLD_Y_LOC-1, yLoc);
  375. locPtr = world.get_loc(xLoc, yLoc);
  376. if( locPtr->region_id != targetRegionId )
  377. continue;
  378. if( !locPtr->has_unit(UNIT_LAND) )
  379. continue;
  380. //----- if there is a unit on the location ------//
  381. int unitRecno = locPtr->unit_recno(UNIT_LAND);
  382. if( unit_array.is_deleted(unitRecno) ) // the unit is dying
  383. continue;
  384. Unit* unitPtr = unit_array[unitRecno];
  385. //--- if if this is our own military unit ----//
  386. if( unitPtr->nation_recno != nation_recno ||
  387. unitPtr->skill.skill_id != SKILL_LEADING )
  388. {
  389. continue;
  390. }
  391. //--------- if this unit is injured ----------//
  392. if( unitPtr->hit_points <
  393. unitPtr->max_hit_points * (150-pref_military_courage/2) / 200 )
  394. {
  395. continue;
  396. }
  397. //---- only if this is not assigned to an action ---//
  398. if( unitPtr->ai_action_id )
  399. continue;
  400. //---- if this unit is stop or assigning to a firm ----//
  401. if( unitPtr->action_mode2 == ACTION_STOP ||
  402. unitPtr->action_mode2 == ACTION_ASSIGN_TO_FIRM )
  403. {
  404. //-------- set should_attack on the target to 1 --------//
  405. enable_should_attack_on_target(targetXLoc, targetYLoc);
  406. //---------- attack now -----------//
  407. unitPtr->attack_unit(targetXLoc, targetYLoc);
  408. targetCombatLevel -= (int) unitPtr->hit_points; // reduce the target combat level
  409. if( targetCombatLevel <= 0 )
  410. break;
  411. }
  412. }
  413. return targetCombatLevel;
  414. }
  415. //--------- End of function Nation::ai_attack_order_nearby_mobile --------//
  416. //
  417. //--------- Begin of function Nation::ai_attack_target_sync --------//
  418. //
  419. // Synchronize the timing of attacking a target. Camps that are further
  420. // away from the target will move first while camps that are closer
  421. // to the target will move later.
  422. //
  423. void Nation::ai_attack_target_sync()
  424. {
  425. //---- find the distance of the camp that is farest to the target ----//
  426. int maxDistance=0;
  427. int i;
  428. for( i=0 ; i<attack_camp_count ; i++ )
  429. {
  430. err_when( attack_camp_array[i].distance < 0 );
  431. if( attack_camp_array[i].distance > maxDistance )
  432. maxDistance = attack_camp_array[i].distance;
  433. }
  434. int maxTravelDays = sprite_res[ unit_res[UNIT_NORMAN]->sprite_id ]->travel_days(maxDistance);
  435. //------ set the date which the troop should start moving -----//
  436. int travelDays;
  437. for( i=0 ; i<attack_camp_count ; i++ )
  438. {
  439. travelDays = maxTravelDays * attack_camp_array[i].distance / maxDistance;
  440. attack_camp_array[i].patrol_date = info.game_date + (maxTravelDays-travelDays);
  441. }
  442. //----- set the is_attack_camp flag of the camps ------//
  443. for( i=0 ; i<attack_camp_count ; i++ )
  444. {
  445. Firm* firmPtr = firm_array[ attack_camp_array[i].firm_recno ];
  446. err_when( firmPtr->firm_id != FIRM_CAMP );
  447. err_when( firmPtr->nation_recno != nation_recno );
  448. ((FirmCamp*)firmPtr)->is_attack_camp = 1;
  449. }
  450. }
  451. //---------- End of function Nation::ai_attack_target_sync --------//
  452. //--------- Begin of function Nation::ai_attack_target_execute --------//
  453. //
  454. // Synchronize the timing of attacking a target. Camps that are further
  455. // away from the target will move first while camps that are closer
  456. // to the target will move later.
  457. //
  458. // <int> directAttack - whether directly attack the target or
  459. // just move close to the target.
  460. //
  461. void Nation::ai_attack_target_execute(int directAttack)
  462. {
  463. FirmCamp* firmCamp;
  464. int firmRecno;
  465. err_when( ai_attack_target_x_loc < 0 || ai_attack_target_x_loc >= MAX_WORLD_X_LOC );
  466. err_when( ai_attack_target_y_loc < 0 || ai_attack_target_y_loc >= MAX_WORLD_Y_LOC );
  467. //---- if the target no longer exist -----//
  468. if( ai_attack_target_nation_recno != get_target_nation_recno(ai_attack_target_x_loc, ai_attack_target_y_loc) )
  469. {
  470. reset_ai_attack_target();
  471. }
  472. //----------------------------------------//
  473. for( int i=attack_camp_count-1 ; i>=0 ; i-- )
  474. {
  475. //----- if it's still not the date to move to attack ----//
  476. if( info.game_date < attack_camp_array[i].patrol_date )
  477. continue;
  478. //-------------------------------------------------------//
  479. firmRecno = attack_camp_array[i].firm_recno;
  480. firmCamp = (FirmCamp*) firm_array[firmRecno];
  481. if( firmCamp->overseer_recno || firmCamp->worker_count )
  482. {
  483. //--- if this is the lead attack camp, don't mobilize the overseer ---//
  484. if( lead_attack_camp_recno == firmRecno )
  485. firmCamp->patrol_all_soldier(); // don't mobilize the overseer
  486. else
  487. firmCamp->patrol(); // mobilize the overseer and the soldiers
  488. //----------------------------------------//
  489. if( firmCamp->patrol_unit_count > 0 ) // there could be chances that there are no some for mobilizing the units
  490. {
  491. //------- declare war with the target nation -------//
  492. if( ai_attack_target_nation_recno )
  493. talk_res.ai_send_talk_msg(ai_attack_target_nation_recno, nation_recno, TALK_DECLARE_WAR);
  494. //--- in defense mode, just move close to the target, the unit will start attacking themselves as their relationship is hostile already ---//
  495. if( !directAttack )
  496. {
  497. unit_array.move_to(ai_attack_target_x_loc, ai_attack_target_y_loc, 0, firmCamp->patrol_unit_array,
  498. firmCamp->patrol_unit_count, COMMAND_AI);
  499. }
  500. else
  501. {
  502. //-------- set should_attack on the target to 1 --------//
  503. enable_should_attack_on_target(ai_attack_target_x_loc, ai_attack_target_y_loc);
  504. //---------- attack now -----------//
  505. // ##### patch begin Gilbert 5/8 ######//
  506. unit_array.attack(ai_attack_target_x_loc, ai_attack_target_y_loc, 0, firmCamp->patrol_unit_array,
  507. firmCamp->patrol_unit_count, COMMAND_AI, 0);
  508. // ##### patch end Gilbert 5/8 ######//
  509. }
  510. }
  511. }
  512. //--------- reset FirmCamp::is_attack_camp ---------//
  513. firmCamp->is_attack_camp = 0;
  514. //------- remove this from attack_camp_array -------//
  515. m.del_array_rec(attack_camp_array, attack_camp_count, sizeof(AttackCamp), i+1 );
  516. attack_camp_count--;
  517. }
  518. }
  519. //---------- End of function Nation::ai_attack_target_execute --------//
  520. //--------- Begin of function Nation::reset_ai_attack_target --------//
  521. //
  522. void Nation::reset_ai_attack_target()
  523. {
  524. //------ reset all is_attack_camp -------//
  525. for( int i=0 ; i<attack_camp_count ; i++ )
  526. {
  527. Firm* firmPtr = firm_array[ attack_camp_array[i].firm_recno ];
  528. err_when( firmPtr->firm_id != FIRM_CAMP ||
  529. firmPtr->nation_recno != nation_recno );
  530. ((FirmCamp*)firmPtr)->is_attack_camp = 0;
  531. }
  532. //--------------------------------------//
  533. attack_camp_count = 0;
  534. }
  535. //---------- End of function Nation::reset_ai_attack_target --------//
  536. //--------- Begin of function Nation::enable_should_attack_on_target --------//
  537. //
  538. void Nation::enable_should_attack_on_target(int targetXLoc, int targetYLoc)
  539. {
  540. //------ set should attack to 1 --------//
  541. int targetNationRecno = 0;
  542. Location* locPtr = world.get_loc(targetXLoc, targetYLoc);
  543. if( locPtr->has_unit(UNIT_LAND) )
  544. targetNationRecno = unit_array[ locPtr->unit_recno(UNIT_LAND) ]->nation_recno;
  545. else if( locPtr->is_firm() )
  546. targetNationRecno = firm_array[locPtr->firm_recno()]->nation_recno;
  547. else if( locPtr->is_town() )
  548. targetNationRecno = town_array[locPtr->town_recno()]->nation_recno;
  549. if( targetNationRecno )
  550. {
  551. set_relation_should_attack(targetNationRecno, 1, COMMAND_AI);
  552. }
  553. }
  554. //--------- End of function Nation::enable_should_attack_on_target --------//
  555. //--------- Begin of static function get_target_nation_recno --------//
  556. //
  557. // Return the nation recno of the target.
  558. //
  559. static int get_target_nation_recno(int targetXLoc, int targetYLoc)
  560. {
  561. Location* locPtr = world.get_loc(targetXLoc, targetYLoc);
  562. if( locPtr->is_firm() )
  563. {
  564. return firm_array[locPtr->firm_recno()]->nation_recno;
  565. }
  566. else if( locPtr->is_town() )
  567. {
  568. return town_array[locPtr->town_recno()]->nation_recno;
  569. }
  570. else if( locPtr->has_unit(UNIT_LAND) )
  571. {
  572. return unit_array[locPtr->unit_recno(UNIT_LAND)]->nation_recno;
  573. }
  574. return 0;
  575. }
  576. //---------- End of static function get_target_nation_recno --------//
  577. //------ Begin of function sort_attack_camp_function ------//
  578. //
  579. static int sort_attack_camp_function( const void *a, const void *b )
  580. {
  581. int ratingA = ((AttackCamp*)a)->combat_level - ((AttackCamp*)a)->distance;
  582. int ratingB = ((AttackCamp*)b)->combat_level - ((AttackCamp*)b)->distance;
  583. return ratingB - ratingA;
  584. }
  585. //------- End of function sort_attack_camp_function ------//
  586. //--------- Begin of function Nation::think_secret_attack --------//
  587. //
  588. // Think about secret assault plans.
  589. //
  590. int Nation::think_secret_attack()
  591. {
  592. //--- never secret attack if its peacefulness >= 80 ---//
  593. if( pref_peacefulness >= 80 )
  594. return 0;
  595. //--- don't try to get new enemies if we already have many ---//
  596. int totalEnemyMilitary = total_enemy_military();
  597. if( totalEnemyMilitary > 20+pref_military_courage-pref_peacefulness )
  598. return 0;
  599. //---------------------------------------------//
  600. int curRating=0, bestRating=0, bestNationRecno=0;
  601. int ourMilitary = military_rank_rating();
  602. int relationStatus, tradeRating;
  603. Nation* nationPtr;
  604. NationRelation* nationRelation;
  605. for( int i=1 ; i<=nation_array.size() ; i++ )
  606. {
  607. if( nation_array.is_deleted(i) || nation_recno == i )
  608. continue;
  609. nationPtr = nation_array[i];
  610. nationRelation = get_relation(i);
  611. relationStatus = nationRelation->status;
  612. //---- if the secret attack flag is not enabled yet ----//
  613. if( !nationRelation->ai_secret_attack )
  614. {
  615. //---- if we have a friendly treaty with this nation ----//
  616. if( relationStatus == NATION_FRIENDLY )
  617. {
  618. if( totalEnemyMilitary > 0 ) // do not attack if we still have enemies
  619. continue;
  620. }
  621. //-------- never attacks an ally ---------//
  622. else if( relationStatus == NATION_ALLIANCE )
  623. {
  624. continue;
  625. }
  626. //---- don't attack if we have a big trade volume with the nation ---//
  627. tradeRating = trade_rating(i)/2 + // existing trade
  628. ai_trade_with_rating(i)/2; // possible trade
  629. if( tradeRating > (50-pref_trading_tendency/2) ) // 0 to 50, 0 if trade tendency is 100, it is 0
  630. {
  631. continue;
  632. }
  633. }
  634. //--------- calculate the rating ----------//
  635. curRating = (ourMilitary - nationPtr->military_rank_rating()) * 2
  636. + (overall_rank_rating() - 50) // if <50 negative, if >50 positive
  637. - tradeRating*2
  638. - get_relation(i)->ai_relation_level/2
  639. - pref_peacefulness/2;
  640. //------- if aggressiveness config is medium or high ----//
  641. if( !nationPtr->is_ai() ) // more aggressive towards human players
  642. {
  643. switch( config.ai_aggressiveness )
  644. {
  645. case OPTION_MODERATE:
  646. curRating += 100;
  647. break;
  648. case OPTION_HIGH:
  649. curRating += 300;
  650. break;
  651. case OPTION_VERY_HIGH:
  652. curRating += 500;
  653. break;
  654. }
  655. }
  656. //----- if the secret attack is already on -----//
  657. if( nationRelation->ai_secret_attack )
  658. {
  659. //--- cancel secret attack if the situation has changed ---//
  660. if( curRating < 0 )
  661. {
  662. nationRelation->ai_secret_attack = 0;
  663. continue;
  664. }
  665. }
  666. //--------- compare ratings -----------//
  667. if( curRating > bestRating )
  668. {
  669. bestRating = curRating;
  670. bestNationRecno = i;
  671. }
  672. }
  673. //-------------------------------//
  674. if( bestNationRecno )
  675. {
  676. get_relation(bestNationRecno)->ai_secret_attack = 1;
  677. return 1;
  678. }
  679. return 0;
  680. }
  681. //---------- End of function Nation::think_secret_attack --------//