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