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_MARI.CPP
22 //Description: AI functions on sea exploration, trading
23
24 #include <OTOWN.h>
25 #include <OREGIONS.h>
26 #include <OU_MARI.h>
27 #include <OUNITRES.h>
28 #include <OSITE.h>
29 #include <OF_HARB.h>
30 #include <OF_CAMP.h>
31 #include <ONATION.h>
32
33 //--------- Begin of function Nation::think_marine --------//
34 //
think_marine()35 void Nation::think_marine()
36 {
37 if( pref_use_marine < 50 ) // don't use marine at all
38 return;
39
40 if( !ai_should_spend(20+pref_use_marine/2) ) // 20 to 70 importance rating
41 return;
42
43 //--- think over building harbor network ---//
44
45 think_build_harbor_network();
46
47 if( ai_harbor_count == 0 )
48 return;
49
50 //------ think about sea attack enemies -------//
51
52 if( misc.random(3)==0 ) // 33% chance
53 {
54 if( think_sea_attack_enemy() )
55 return;
56 }
57
58 //---- check if it is safe for sea travel now ----//
59
60 if( !ai_is_sea_travel_safe() )
61 return;
62
63 //----- think over moving between regions -----//
64
65 think_move_between_region();
66
67 // think_move_to_region_with_mine();
68 }
69 //---------- End of function Nation::think_marine --------//
70
71
72 //----- Begin of function Nation::think_build_harbor_network ----//
73 //
74 // Think about thinking a harbor network so that we have harbors
75 // from every region to any other regions.
76 //
think_build_harbor_network()77 int Nation::think_build_harbor_network()
78 {
79 //--- only build one harbor at a time, to avoid double building ---//
80
81 if( is_action_exist( ACTION_AI_BUILD_FIRM, FIRM_HARBOR ) )
82 return 0;
83
84 //--------------------------------------------//
85
86 RegionStat* regionStat = region_array.region_stat_array;
87 RegionPath* regionPath;
88
89 for( int i=0 ; i<region_array.region_stat_count ; i++, regionStat++ )
90 {
91 //--- only build on those regions that this nation has base towns ---//
92
93 if( !regionStat->base_town_nation_count_array[nation_recno-1] )
94 continue;
95
96 if( regionStat->harbor_nation_count_array[nation_recno-1] > 0 ) // if we already have a harbor in this region
97 continue;
98
99 err_when( regionStat->harbor_nation_count_array[nation_recno-1] > 1 ); // this shouldn't happen if the AI works properly
100
101 //-----------------------------------------------------------------------//
102 //
103 // Scan thru all regions which this region can be connected to thru sea.
104 // If one of them is worth our landing, then builld a harbor in this
105 // region so we can sail to that region.
106 //
107 //-----------------------------------------------------------------------//
108
109 regionPath = regionStat->reachable_region_array;
110
111 for( int j=0 ; j<regionStat->reachable_region_count ; j++, regionPath++ )
112 {
113 err_when( regionPath->land_region_stat_id == i+1 ); // pointing back to its own
114
115 //--------------------------------------//
116
117 if( ai_harbor_count == 0 && // if we have already built one harbor, then we should continue to build others asa single harbor isn't useful
118 ai_should_sail_to_rating(regionPath->land_region_stat_id) <= 0 )
119 {
120 continue;
121 }
122
123 //--------- build a harbor now ---------//
124
125 if( ai_build_harbor( regionStat->region_id, regionPath->sea_region_id ) )
126 return 1;
127 }
128 }
129
130 return 0;
131 }
132 //----- End of function Nation::think_build_harbor_network ----//
133
134
135 //----- Begin of function Nation::ai_should_sail_to_rating ----//
136 //
ai_should_sail_to_rating(int regionStatId)137 int Nation::ai_should_sail_to_rating(int regionStatId)
138 {
139 RegionStat* regionStat = region_array.get_region_stat2(regionStatId);
140
141 int curRating;
142
143 curRating = regionStat->raw_count * 100
144 + regionStat->independent_town_count * 20
145 + regionStat->nation_presence_count * 30;
146 /*
147 - (regionStat->total_town_count - regionStat->town_nation_count_array[nation_recno-1] ) * 10 // towns of other nations
148 - (regionStat->total_firm_count - regionStat->firm_nation_count_array[nation_recno-1] ) * 5 // firms of other nations
149 - (regionStat->total_unit_count - regionStat->unit_nation_count_array[nation_recno-1] ) * 2 // units of other nations
150 - regionStat->independent_unit_count * 2; // monsters or rebel units
151 */
152 return curRating > 0;
153 }
154 //----- End of function Nation::ai_should_sail_to_rating ----//
155
156
157 //--------- Begin of function Nation::ai_build_harbor --------//
158 //
159 // Build a harbor across the given land and sea region id.
160 //
161 // <int> landRegionId - the land region id.
162 // <int> seaRegionId - the sea region id.
163 //
164 // return: <int> 1 - a suitable location is found and the
165 // building action has been queued.
166 // 0 - not suitable location is found.
167 //
ai_build_harbor(int landRegionId,int seaRegionId)168 int Nation::ai_build_harbor(int landRegionId, int seaRegionId)
169 {
170 #define ADEQUATE_ENEMY_HARBOR_DISTANCE 10
171
172 //---- randomly pick a base town of this nation ----//
173
174 Town* townPtr;
175 int townSeq = misc.random(ai_town_count);
176
177 int i;
178 for( i=0 ; i<ai_town_count ; i++ )
179 {
180 if( ++townSeq >= ai_town_count )
181 townSeq=0;
182
183 townPtr = town_array[ ai_town_array[townSeq] ];
184
185 if( townPtr->is_base_town && landRegionId==townPtr->region_id )
186 break;
187 }
188
189 if( i==ai_town_count ) // not found
190 return 0;
191
192 int homeXLoc = townPtr->center_x;
193 int homeYLoc = townPtr->center_y;
194
195 //---- scan out from the town and find the nearest suitable location to build the harbor ----//
196
197 int xOffset, yOffset;
198 int xLoc, yLoc, bestXLoc= -1, bestYLoc= -1, maxEnemyDistance=0;
199 Location* locPtr;
200
201 for( i=2 ; i<MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC ; i++ )
202 {
203 misc.cal_move_around_a_point(i, MAX_WORLD_X_LOC, MAX_WORLD_Y_LOC, xOffset, yOffset);
204
205 xLoc = homeXLoc + xOffset;
206 yLoc = homeYLoc + yOffset;
207
208 xLoc = MAX(0, xLoc);
209 xLoc = MIN(MAX_WORLD_X_LOC-1, xLoc);
210
211 yLoc = MAX(0, yLoc);
212 yLoc = MIN(MAX_WORLD_Y_LOC-1, yLoc);
213
214 locPtr = world.get_loc(xLoc, yLoc);
215
216 if( !locPtr->can_build_whole_harbor() )
217 continue;
218
219 if( !world.is_adjacent_region(xLoc, yLoc, seaRegionId) )
220 continue;
221
222 if( !world.can_build_firm(xLoc, yLoc, FIRM_HARBOR) )
223 continue;
224
225 //--------------------------------------//
226
227 int enemyDistance = closest_enemy_firm_distance(FIRM_HARBOR, xLoc, yLoc);
228
229 if( enemyDistance > maxEnemyDistance )
230 {
231 maxEnemyDistance = enemyDistance;
232 bestXLoc = xLoc;
233 bestYLoc = yLoc;
234
235 if( enemyDistance >= ADEQUATE_ENEMY_HARBOR_DISTANCE )
236 break;
237 }
238 }
239
240 //--------------------------------//
241
242 if( bestXLoc >= 0 )
243 {
244 add_action(xLoc, yLoc, homeXLoc, homeYLoc, ACTION_AI_BUILD_FIRM, FIRM_HARBOR);
245 return 1;
246 }
247
248 return 0;
249 }
250 //---------- End of function Nation::ai_build_harbor --------//
251
252
253 //--------- Begin of function Nation::closest_enemy_firm_distance --------//
254 //
255 // Return how close is the cloeset enemy harbor to the given location.
256 //
257 // <int> firmId - firm id.
258 // <int> xLoc, yLoc - the given location
259 //
closest_enemy_firm_distance(int firmId,int xLoc,int yLoc)260 int Nation::closest_enemy_firm_distance(int firmId, int xLoc, int yLoc)
261 {
262 int curDistance, minDistance=0x7FFF;
263
264 for( int i=firm_array.size() ; i>0 ; i-- )
265 {
266 if( firm_array.is_deleted(i) )
267 continue;
268
269 Firm* firmPtr = firm_array[i];
270
271 if( firmPtr->firm_id != firmId ||
272 firmPtr->nation_recno == nation_recno ) // belonging to own nation, not enemy nation
273 {
274 continue;
275 }
276
277 curDistance = misc.points_distance(firmPtr->center_x, firmPtr->center_y, xLoc, yLoc);
278
279 if( curDistance < minDistance )
280 minDistance = curDistance;
281 }
282
283 return minDistance;
284 }
285 //---------- End of function Nation::closest_enemy_firm_distance --------//
286
287
288 //------ Begin of function Nation::think_move_between_region ------//
289 //
think_move_between_region()290 int Nation::think_move_between_region()
291 {
292 if( think_move_people_between_region() )
293 return 1;
294
295 if( think_move_troop_between_region() )
296 return 1;
297
298 return 0;
299 }
300 //------ End of function Nation::think_move_between_region -------//
301
302
303 //------ Begin of function Nation::think_move_troop_between_region ------//
304 //
305 // Thing about moving units between regions
306 //
think_move_troop_between_region()307 int Nation::think_move_troop_between_region()
308 {
309 //----- find the region with the least population -----//
310
311 int campCount, maxCampCount=0, minCampCount=0x1000;
312 int maxRegionId=0, minRegionId=0;
313 RegionStat* regionStat = region_array.region_stat_array;
314 int curRating, minRegionRating=0;
315
316 int i;
317 for( i=0 ; i<region_array.region_stat_count ; i++, regionStat++ )
318 {
319 if( regionStat->nation_presence_count==0 &&
320 regionStat->independent_town_count==0 &&
321 regionStat->raw_count==0 )
322 {
323 continue;
324 }
325
326 campCount = regionStat->camp_nation_count_array[nation_recno-1];
327
328 if( campCount > maxCampCount )
329 {
330 maxCampCount = campCount;
331 maxRegionId = regionStat->region_id;
332 }
333
334 if( campCount <= minCampCount )
335 {
336 curRating = ai_should_sail_to_rating(i+1);
337
338 if( campCount < minCampCount || curRating >= minRegionRating )
339 {
340 minCampCount = campCount;
341 minRegionId = regionStat->region_id;
342 minRegionRating = curRating;
343 }
344 }
345 }
346
347 if( !maxRegionId || !minRegionId || maxRegionId==minRegionId )
348 return 0;
349
350 //----- only move if the difference is big enough ------//
351
352 int minJoblessPop = region_array.get_region_stat(minRegionId)->nation_jobless_population_array[nation_recno-1];
353 int maxJoblessPop = region_array.get_region_stat(maxRegionId)->nation_jobless_population_array[nation_recno-1];
354
355 if( pref_use_marine < 90 ) // if > 90, it will ignore all these and move anyway
356 {
357 if( minCampCount==0 )
358 {
359 if( maxJoblessPop - minJoblessPop < 200 - pref_use_marine ) // 150 to 200 (pref_use_marine is always >= 50, if it is < 50, marine functions are not called at all
360 return 0;
361 }
362 else
363 {
364 if( maxJoblessPop - minJoblessPop < 150 - pref_use_marine ) // 100 to 150 (pref_use_marine is always >= 50, if it is < 50, marine functions are not called at all
365 return 0;
366 }
367 }
368 else
369 {
370 if( maxJoblessPop < 20 ) // don't move if we only have a few jobless people
371 return 0;
372 }
373
374 //------------ see if we have any camps in the region -----------//
375
376 int destRegionId = minRegionId;
377 Firm* firmPtr;
378
379 for( i=ai_camp_count-1 ; i>=0 ; i-- )
380 {
381 firmPtr = firm_array[ai_camp_array[i]];
382
383 if( firmPtr->region_id == destRegionId &&
384 !firmPtr->under_construction ) // if it's under construction there may be unit waiting outside of the camp
385 {
386 //--- if there is one, must move the troop close to it ---//
387
388 return ai_patrol_to_region(firmPtr->center_x, firmPtr->center_y, SEA_ACTION_NONE);
389 }
390 }
391 //----- if we don't have any camps in the region, build one ----//
392
393 int xLoc=0, yLoc=0;
394 FirmInfo* firmInfo = firm_res[FIRM_CAMP];
395
396 if(world.locate_space_random(xLoc, yLoc, MAX_WORLD_X_LOC-1,
397 MAX_WORLD_Y_LOC-1, firmInfo->loc_width, firmInfo->loc_height,
398 MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC, destRegionId, 1))
399 {
400 return ai_patrol_to_region(xLoc, yLoc, SEA_ACTION_BUILD_CAMP);
401 }
402
403 return 0;
404 }
405 //------ End of function Nation::think_move_troop_between_region -------//
406
407
408 //------ Begin of function Nation::think_move_people_between_region ------//
409 //
410 // Thing about moving units between regions
411 //
think_move_people_between_region()412 int Nation::think_move_people_between_region()
413 {
414 //----- find the region with the least population -----//
415
416 int joblessPop, maxJoblessPop=0, minJoblessPop=0x1000;
417 int maxRegionId=0, minRegionId=0;
418 RegionStat* regionStat = region_array.region_stat_array;
419
420 int i;
421 for( i=0 ; i<region_array.region_stat_count ; i++, regionStat++ )
422 {
423 //--- only move to regions in which we have camps ---//
424
425 if( regionStat->camp_nation_count_array[nation_recno-1] == 0 )
426 continue;
427
428 joblessPop = regionStat->nation_jobless_population_array[nation_recno-1];
429
430 if( joblessPop > maxJoblessPop )
431 {
432 maxJoblessPop = joblessPop;
433 maxRegionId = regionStat->region_id;
434 }
435
436 if( joblessPop < minJoblessPop )
437 {
438 minJoblessPop = joblessPop;
439 minRegionId = regionStat->region_id;
440 }
441 }
442
443 if( !maxRegionId || !minRegionId || maxRegionId==minRegionId )
444 return 0;
445
446 //----- only move if the difference is big enough ------//
447
448 if( pref_use_marine < 90 ) // if > 90, it will ignore all these and move anyway
449 {
450 if( maxJoblessPop - minJoblessPop < 150 - pref_use_marine ) // 100 to 150 (pref_use_marine is always >= 50, if it is < 50, marine functions are not called at all
451 return 0;
452 }
453 else
454 {
455 if( maxJoblessPop < 20 ) // don't move if we only have a few jobless people
456 return 0;
457 }
458
459 //------------ see if we have any towns in the region -----------//
460
461 int destRegionId = minRegionId;
462 Town* townPtr;
463
464 for( i=ai_town_count-1 ; i>=0 ; i-- )
465 {
466 townPtr = town_array[ai_town_array[i]];
467
468 if( townPtr->region_id == destRegionId )
469 {
470 //--- if there is one, must move the people to it ---//
471
472 return ai_settle_to_region(townPtr->center_x, townPtr->center_y, SEA_ACTION_NONE);
473 }
474 }
475
476 //----- if we don't have any towns in the region, settle one ----//
477
478 int xLoc=0, yLoc=0;
479
480 if(world.locate_space_random(xLoc, yLoc, MAX_WORLD_X_LOC-1,
481 MAX_WORLD_Y_LOC-1, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT,
482 MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC, destRegionId, 1))
483 {
484 return ai_settle_to_region(xLoc, yLoc, SEA_ACTION_SETTLE);
485 }
486
487 return 0;
488 }
489 //------ End of function Nation::think_move_people_between_region -------//
490
491
492 //------ Begin of function Nation::ai_is_sea_travel_safe ------//
493 //
494 // return: <int> 1 - it's safe for sea travel
495 // 0 - it's not safe for sea travel
496 //
ai_is_sea_travel_safe()497 int Nation::ai_is_sea_travel_safe()
498 {
499 //--- count the no. of battle ships owned by each nation ---//
500
501 Unit* unitPtr;
502 short nationShipCountArray[MAX_NATION];
503
504 memset( nationShipCountArray, 0, sizeof(nationShipCountArray) );
505
506 int i;
507 for( i=unit_array.size() ; i>0 ; i-- )
508 {
509 if( unit_array.is_deleted(i) )
510 continue;
511
512 unitPtr = unit_array[i];
513
514 if( unitPtr->unit_id != UNIT_CARAVEL &&
515 unitPtr->unit_id != UNIT_GALLEON )
516 {
517 continue;
518 }
519
520 err_when( unitPtr->nation_recno < 1 || unitPtr->nation_recno > MAX_NATION );
521
522 nationShipCountArray[unitPtr->nation_recno-1]++;
523 }
524
525 //--- compare the no. of ships of ours and those of the human players ---//
526
527 int ourBattleShipCount = nationShipCountArray[nation_recno-1];
528 int nationRecno = misc.random(nation_array.size())+1;
529
530 for( i=nation_array.size() ; i>0 ; i-- )
531 {
532 if( ++nationRecno > nation_array.size() )
533 nationRecno = 1;
534
535 if( nation_array.is_deleted(nationRecno) )
536 continue;
537
538 if( get_relation(nationRecno)->status != NATION_HOSTILE ) // only check enemies
539 continue;
540
541 if( nation_array[nationRecno]->is_ai() ) // only check human players
542 continue;
543
544 //-- if enemy has battle ships, it is not safe for sea travel, destroy them first ---//
545
546 if( nationShipCountArray[nationRecno-1] > 0 )
547 {
548 //--- if enemy ships significantly outnumber ours, don't do any sea travel ---//
549
550 if( nationShipCountArray[nationRecno-1] - ourBattleShipCount >
551 pref_military_courage/3 ) // 0 to 3
552 {
553 return 0;
554 }
555 }
556 }
557
558 return 1;
559 }
560 //----- End of function Nation::ai_is_sea_travel_safe -----//
561
562
563 //------ Begin of function Nation::max_human_battle_ship_count ------//
564 //
565 // return: <int> the number of ships owned by the human player who
566 // is strongest on sea power.
567 //
max_human_battle_ship_count()568 int Nation::max_human_battle_ship_count()
569 {
570 //--- count the no. of battle ships owned by each nation ---//
571
572 Unit* unitPtr;
573 short nationShipCountArray[MAX_NATION];
574
575 memset( nationShipCountArray, 0, sizeof(nationShipCountArray) );
576
577 int i;
578 for( i=unit_array.size() ; i>0 ; i-- )
579 {
580 if( unit_array.is_deleted(i) )
581 continue;
582
583 unitPtr = unit_array[i];
584
585 if( unitPtr->unit_id != UNIT_CARAVEL &&
586 unitPtr->unit_id != UNIT_GALLEON )
587 {
588 continue;
589 }
590
591 err_when( unitPtr->nation_recno < 1 || unitPtr->nation_recno > MAX_NATION );
592
593 nationShipCountArray[unitPtr->nation_recno-1]++;
594 }
595
596 //--- compare the no. of ships of ours and those of the human players ---//
597
598 int maxShipCount=0;
599
600 for( i=nation_array.size() ; i>0 ; i-- )
601 {
602 if( nation_array.is_deleted(i) )
603 continue;
604
605 if( nation_array[i]->is_ai() ) // only check human players
606 continue;
607
608 //-- if enemy has battle ships, it is not safe for sea travel, destroy them first ---//
609
610 if( nationShipCountArray[i-1] > maxShipCount )
611 {
612 maxShipCount = nationShipCountArray[i-1];
613 }
614 }
615
616 return maxShipCount;
617 }
618 //----- End of function Nation::max_human_battle_ship_count -----//
619
620
621 //------ Begin of function Nation::think_sea_attack_enemy ------//
622 //
623 // Think about attacking enemy harbors and ships.
624 //
think_sea_attack_enemy()625 int Nation::think_sea_attack_enemy()
626 {
627 if( total_ship_combat_level < 700 - (pref_military_courage + pref_use_marine)*2 ) // 300 to 700
628 return 0;
629
630 //-----------------------------------------//
631
632 int totalFirm = firm_array.size();
633 int firmRecno = misc.random(totalFirm)+1;
634 Firm* firmPtr;
635
636 for( int i=0 ; i<totalFirm ; i++ )
637 {
638 if( ++firmRecno > totalFirm )
639 firmRecno = 1;
640
641 if( firm_array.is_deleted(firmRecno) )
642 continue;
643
644 firmPtr = firm_array[firmRecno];
645
646 if( firmPtr->firm_id != FIRM_HARBOR )
647 continue;
648
649 if( get_relation_status(firmPtr->nation_recno) != NATION_HOSTILE )
650 continue;
651
652 //--- if the AI has more powerful fleets than the enemy ---//
653
654 if( total_ship_combat_level >
655 nation_array[firmPtr->nation_recno]->total_ship_combat_level )
656 {
657 ai_sea_attack_target(firmPtr->center_x, firmPtr->center_y);
658 return 1;
659 }
660 }
661
662 return 0;
663 }
664 //----- End of function Nation::think_sea_attack_enemy -----//
665