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