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_MAR3.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 
34 //------ Begin of function Nation::ai_settle_to_region ------//
35 //
36 // <int> destXLoc, destYLoc - the location of the destination to settle.
37 // <int> seaActionId			 - SEA_ACTION_???
38 //
ai_settle_to_region(int destXLoc,int destYLoc,int seaActionId)39 int Nation::ai_settle_to_region(int destXLoc, int destYLoc, int seaActionId)
40 {
41 	#define SETTLE_REGION_UNIT_COUNT 	9		// no. of units to move to settle on a new region each time
42 
43 	//---- think about which town to recruit the people -----//
44 
45 	int  destRegionId = world.get_region_id(destXLoc, destYLoc);
46 	int  curRating, bestRating=0, seaRegionId;
47 	Town *townPtr, *bestTown=NULL;
48 
49 	for( int i=0 ; i<ai_town_count ; i++ )
50 	{
51 		townPtr = town_array[ ai_town_array[i] ];
52 
53 		if( townPtr->has_linked_own_camp==0 )		// if there is no command base linked to this town, we cannot recruit any peasants from it
54 			continue;
55 
56 		if( townPtr->jobless_population < SETTLE_REGION_UNIT_COUNT )		// don't get peasant from this town if the jobless population is less than 20
57 			continue;
58 
59 		//--- only send units from this region if we have a harbor in that region ---//
60 
61 		// region_stat_id of a region may be zero
62 		if(
63 			region_array[townPtr->region_id]->region_stat_id == 0 ||
64 			region_array.get_region_stat(townPtr->region_id)->harbor_nation_count_array[nation_recno-1] == 0 )
65 			continue;
66 
67 		curRating  = world.distance_rating(destXLoc, destYLoc, townPtr->center_x, townPtr->center_y);
68 
69 		curRating += townPtr->jobless_population;
70 
71 		curRating += townPtr->average_loyalty();		// select a town with high loyalty
72 
73 		if( curRating <= bestRating )
74 			continue;
75 
76 		//------- see if we have ships ready currently -----//
77 
78 		seaRegionId = region_array.get_sea_path_region_id(townPtr->region_id, destRegionId);
79 
80 		if( !ai_find_transport_ship(seaRegionId, townPtr->center_x, townPtr->center_y, 0) )		// 0-don't have to find the best, return immediately whenever a suitable one is found
81 			continue;
82 
83 		bestRating = curRating;
84 		bestTown   = townPtr;
85 	}
86 
87 	if( !bestTown )
88 		return 0;
89 
90 	//------- try to recruit 9 units from one of our towns --------//
91 
92 	short recruitedUnitArray[SETTLE_REGION_UNIT_COUNT];
93 	int recruitedCount=0;
94 	int raceId = bestTown->majority_race();
95 	int unitRecno;
96 	int loopCount=0;
97 
98 	while( recruitedCount < SETTLE_REGION_UNIT_COUNT )
99 	{
100 		err_when( ++loopCount > 100 );
101 
102 		if( bestTown->recruitable_race_pop( raceId, 1 ) )
103 		{
104 			unitRecno = bestTown->recruit(-1, raceId, COMMAND_AI);
105 
106 			if( !unitRecno )		// no space for new unit
107 				break;
108 
109 			err_when( unit_array.is_deleted(unitRecno) );
110 			err_when( !unit_array[unitRecno]->is_visible() );
111 
112 			recruitedUnitArray[recruitedCount++] = unitRecno;
113 		}
114 		else
115 		{
116 			raceId = bestTown->pick_random_race(0, 1);		// 0-recruitable only, 1-will also pick spies
117 
118 			if( !raceId )
119 				break;
120 		}
121 	}
122 
123 	//--- if due to some reasons that the no. of units recruited is less than half of what we need, do not continue to sea travel.
124 
125 	if( recruitedCount < SETTLE_REGION_UNIT_COUNT/2 )
126 		return 0;
127 
128 	int actionRecno = add_action( destXLoc, destYLoc, 0, 0, ACTION_AI_SEA_TRAVEL, seaActionId,
129 											recruitedCount, 0, 0, recruitedUnitArray );
130 
131 	if( actionRecno )						// must process it immediately otherwise the recruited units will do something else
132 		return process_action(actionRecno);
133 	else
134 		return 0;
135 }
136 //------ End of function Nation::ai_settle_to_region -------//
137 
138 
139 //------ Begin of function Nation::ai_patrol_to_region ------//
140 //
141 // Look for a military camp for moving all of its soldiers to
142 // a new region and set up a new military camp to host the soldiers.
143 //
144 // <int> destXLoc, destYLoc - the location of the destination to set up
145 //										a military camp.
146 // <int> seaActionId			 - SEA_ACTION_???
147 //
ai_patrol_to_region(int destXLoc,int destYLoc,int seaActionId)148 int Nation::ai_patrol_to_region(int destXLoc, int destYLoc, int seaActionId)
149 {
150 	#define SETTLE_REGION_UNIT_COUNT 	9		// no. of units to move to settle on a new region each time
151 
152 	//---- think about which town to recruit the people -----//
153 
154 	int  		destRegionId = world.get_region_id(destXLoc, destYLoc);
155 	int  		curRating, bestRating=0, seaRegionId;
156 	int		kingRecno = nation_array[nation_recno]->king_unit_recno;
157 	FirmCamp *firmCamp, *bestCamp=NULL;
158 
159 	for( int i=0 ; i<ai_camp_count ; i++ )
160 	{
161 		firmCamp = (FirmCamp*) firm_array[ ai_camp_array[i] ];
162 
163 		if( !(firmCamp->overseer_recno && firmCamp->worker_count==MAX_WORKER) )		// only when the camp is filled with workers
164 			continue;
165 
166 		if( firmCamp->ai_capture_town_recno )     // the base is trying to capture an independent town
167 			continue;
168 
169 		if( firmCamp->is_attack_camp )
170 			continue;
171 
172 		if( firmCamp->overseer_recno == kingRecno )		// if the king oversees this firm
173 			continue;
174 
175 		//--- only send units from this region if we have a harbor in that region ---//
176 
177 		if(
178 			region_array[firmCamp->region_id]->region_stat_id == 0 ||
179 			region_array.get_region_stat(firmCamp->region_id)->harbor_nation_count_array[nation_recno-1] == 0 )
180 			continue;
181 
182 		curRating  = world.distance_rating(destXLoc, destYLoc, firmCamp->center_x, firmCamp->center_y);
183 
184 		if( curRating <= bestRating )
185 			continue;
186 
187 		//------- see if we have ships ready currently -----//
188 
189 		seaRegionId = region_array.get_sea_path_region_id(firmCamp->region_id, destRegionId);
190 
191 		if( !ai_find_transport_ship(seaRegionId, firmCamp->center_x, firmCamp->center_y, 0) )		// 0-don't have to find the best, return immediately whenever a suitable one is found
192 			continue;
193 
194 		bestRating = curRating;
195 		bestCamp   = firmCamp;
196 	}
197 
198 	if( !bestCamp )
199 		return 0;
200 
201 	//----- patrol the camp troop ajnd assign it to a ship -----//
202 
203 	bestCamp->patrol();
204 
205 	if( bestCamp->patrol_unit_count > 0 )     // there could be chances that there are no some for mobilizing the units
206 	{
207 		int actionRecno = add_action( destXLoc, destYLoc, 0, 0, ACTION_AI_SEA_TRAVEL, seaActionId,
208 												bestCamp->patrol_unit_count, 0, 0, bestCamp->patrol_unit_array );
209 
210 		if( actionRecno )						// must process it immediately otherwise the recruited units will do something else
211 			return process_action(actionRecno);
212 	}
213 
214 	return 0;
215 }
216 //------ End of function Nation::ai_patrol_to_region -------//
217 
218 
219 
220 //------- Begin of function Nation::has_trade_ship -----------//
221 //
222 // Whether this nation already has a trade ship travelling between
223 // the two given harbors.
224 //
225 // return: <int> recno of the ship.
226 //					  0 - if there isn't any yet.
227 //
has_trade_ship(int firmRecno1,int firmRecno2)228 int Nation::has_trade_ship(int firmRecno1, int firmRecno2)
229 {
230 	UnitMarine* unitMarine;
231 
232 	for( int i=ai_ship_count-1 ; i>=0 ; i-- )
233 	{
234 		unitMarine = (UnitMarine*) unit_array[ ai_ship_array[i] ];
235 
236 		err_when( unit_res[ unitMarine->unit_id ]->unit_class != UNIT_CLASS_SHIP );
237 
238 		if( unitMarine->stop_defined_num < 2 )
239 			continue;
240 
241 		if( ( unitMarine->stop_array[0].firm_recno == firmRecno1 &&
242 				unitMarine->stop_array[1].firm_recno == firmRecno2 ) ||
243 			 ( unitMarine->stop_array[1].firm_recno == firmRecno1 &&
244 				unitMarine->stop_array[0].firm_recno == firmRecno2 ) )
245 		{
246 			return unitMarine->sprite_recno;
247 		}
248 	}
249 
250 	return 0;
251 }
252 //--------- End of function Nation::has_trade_ship -----------//
253 
254 
255 //------ Begin of function Nation::think_move_to_region_with_mine ------//
256 //
257 // Think about moving to a region with mines and settle a town next to
258 // the mine.
259 //
think_move_to_region_with_mine()260 int Nation::think_move_to_region_with_mine()
261 {
262 	if( total_jobless_population < 30 )
263 		return 0;
264 
265 	//---------------------------------------------------//
266 
267 	int curRating, bestRating=0, bestRegionId=0;
268 	RegionStat* regionStat = region_array.region_stat_array;
269 
270 	int i;
271 	for( i=0 ; i<region_array.region_stat_count ; i++, regionStat++ )
272 	{
273 		if( regionStat->town_nation_count_array[nation_recno-1] > 0 )		// if we already have towns there
274 			continue;
275 
276 		if( regionStat->raw_count==0 )
277 			continue;
278 
279 		//-- if we have already build one camp there, just waiting for sending a few peasants there, then process it first --//
280 
281 		if( regionStat->camp_nation_count_array[nation_recno-1] > 0 )
282 		{
283 			bestRegionId = regionStat->region_id;
284 			break;
285 		}
286 
287 		//-----------------------------------------------//
288 
289 		curRating = regionStat->raw_count*3 - regionStat->nation_presence_count;
290 
291 		if( curRating > bestRating )
292 		{
293 			bestRating   = curRating;
294 			bestRegionId = regionStat->region_id;
295 		}
296 	}
297 
298 	if( !bestRegionId )
299 		return 0;
300 
301 	//----- select the raw site to acquire -----//
302 
303 	Site* sitePtr;
304 
305 	for( i=site_array.size() ; i>0 ; i-- )
306 	{
307 		if( site_array.is_deleted(i) )
308 			continue;
309 
310 		sitePtr = site_array[i];
311 
312 		if( sitePtr->region_id == bestRegionId )
313 			break;
314 	}
315 
316 	if( i==0 )
317 		return 0;
318 
319 	//----- decide the location of the settlement -----//
320 
321 	return ai_build_camp_town_next_to( sitePtr->map_x_loc-1, sitePtr->map_y_loc-1,
322 												  sitePtr->map_x_loc+1, sitePtr->map_y_loc+1  );
323 }
324 //------ End of function Nation::think_move_to_region_with_mine -------//
325 
326 
327 //------ Begin of function Nation::ai_build_camp_town_next_to ------//
328 //
329 // Build a new camp and settle a new town next to the given location.
330 //
331 // <int> xLoc1, yLoc1, xLoc2, yLoc2 - the location that the new camp
332 //												  and town should be built next to.
333 //
ai_build_camp_town_next_to(int xLoc1,int yLoc1,int xLoc2,int yLoc2)334 int Nation::ai_build_camp_town_next_to(int xLoc1, int yLoc1, int xLoc2, int yLoc2)
335 {
336 	//---- first see if we already have a camp in the region ---//
337 
338 	int regionId = world.get_region_id(xLoc1, yLoc1);
339 
340 	if( region_array[regionId]->region_stat_id == 0)
341 		return 0;
342 
343 	if( region_array.get_region_stat(regionId)->camp_nation_count_array[nation_recno-1] == 0 )
344 	{
345 		//--- if we don't have one yet, build one next to the destination ---//
346 
347 		if( !world.locate_space( &xLoc1, &yLoc1, xLoc2, yLoc2,
348 									 3, 3, UNIT_LAND, regionId, 1 ) )		// 1-locating the space for building
349 		{
350 			return 0;
351 		}
352 
353 		if( !world.can_build_firm( xLoc1, yLoc1, FIRM_CAMP ) )
354 			return 0;
355 
356 		return ai_patrol_to_region(xLoc1, yLoc1, SEA_ACTION_BUILD_CAMP);
357 	}
358 	else //-- if there's already a camp there, then set people there to settle --//
359 	{
360 		FirmCamp* firmCamp;
361 
362 		for( int i=0 ; i<ai_camp_count ; i++ )
363 		{
364 			firmCamp = (FirmCamp*) firm_array[ ai_camp_array[i] ];
365 
366 			if( firmCamp->region_id != regionId )
367 				continue;
368 
369 			xLoc1 = firmCamp->loc_x1;
370 			yLoc1 = firmCamp->loc_y1;
371 			xLoc2 = firmCamp->loc_x2;
372 			yLoc2 = firmCamp->loc_y2;
373 
374 			if( world.locate_space( &xLoc1, &yLoc1, xLoc2, yLoc2,
375 				 STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, UNIT_LAND, regionId, 1 ) )		// 1-locating the space for building
376 			{
377 				if( world.can_build_town( xLoc1, yLoc1 ) )
378 					return ai_settle_to_region(xLoc1, yLoc1, SEA_ACTION_SETTLE);
379 			}
380 		}
381 	}
382 
383 	return 0;
384 }
385 //------ End of function Nation::ai_build_camp_town_next_to -------//
386 
387 
388 //------ Begin of function Nation::ai_sea_attack_target ------//
389 //
390 // <int> targetXLoc, targetYLoc - the location of the target.
391 //
ai_sea_attack_target(int targetXLoc,int targetYLoc)392 int Nation::ai_sea_attack_target(int targetXLoc, int targetYLoc)
393 {
394 	UnitMarine* unitMarine;
395 	int 		   targetRegionId = world.get_region_id(targetXLoc, targetYLoc);
396 	int			rc = 0;
397 
398 	for( int i=0 ; i<ai_ship_count ; i++ )
399 	{
400 		unitMarine = (UnitMarine*) unit_array[ ai_ship_array[i] ];
401 
402 		if( unitMarine->attack_count==0 )
403 			continue;
404 
405 		if( !unitMarine->is_ai_all_stop() )
406 			continue;
407 
408 		//----- if the ship is in the harbor now -----//
409 
410 		if( unitMarine->unit_mode == UNIT_MODE_IN_HARBOR )
411 		{
412 			FirmHarbor*	firmHarbor = (FirmHarbor*) firm_array[unitMarine->unit_mode_para];
413 
414 			if( firmHarbor->sea_region_id != targetRegionId )
415 				continue;
416 
417 			firmHarbor->sail_ship(unitMarine->sprite_recno, COMMAND_AI);
418 		}
419 
420 		if( !unitMarine->is_visible() )		// no space in the sea for placing the ship
421 			continue;
422 
423 		if( unitMarine->region_id() != targetRegionId )
424 			continue;
425 
426 		//------ order the ship to attack the target ------//
427 
428 		unitMarine->attack_unit( targetXLoc, targetYLoc );
429 		rc = 1;
430 	}
431 
432 	return rc;
433 }
434 //-------- End of function Nation::ai_sea_attack_target -------//
435