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