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 
22 //Filename		: OAI_INFO.CPP
23 //Description	: AI - A.I. info structure
24 
25 #include <OSYS.h>
26 #include <OTOWN.h>
27 #include <OF_MARK.h>
28 #include <OU_CARA.h>
29 #include <ONATION.h>
30 
31 
32 //--------- Begin of function Nation::update_ai_firm_array --------//
33 //
34 // <int> firmId - determine which firm array to be returned
35 //
36 // <int> actionType: 1  - add a record to the array
37 //							0  - no addition or deletion, just return
38 //							-1 - del a record from the array
39 //
40 // <int> actionRecno : the recno to be deleted, if actionType is -1.
41 //							   the recno to be added, if actionType is 1.
42 //	<int> arrayCount:	for return the count of the AI info array
43 //
update_ai_firm_array(int firmId,int actionType,int actionRecno,int & arrayCount)44 short* Nation::update_ai_firm_array(int firmId, int actionType, int actionRecno, int& arrayCount)
45 {
46 	short* rc;
47 
48 	switch(firmId)
49 	{
50 		case FIRM_BASE:
51 			rc = update_ai_array(ai_base_count, ai_base_size, &ai_base_array,
52 					 AI_BASE_INC_SIZE, actionType, actionRecno);
53 			arrayCount = ai_base_count;
54 			break;
55 
56 		case FIRM_CAMP:
57 			rc = update_ai_array(ai_camp_count, ai_camp_size, &ai_camp_array,
58 					 AI_CAMP_INC_SIZE, actionType, actionRecno);
59 			arrayCount = ai_camp_count;
60 			break;
61 
62 		case FIRM_FACTORY:
63 			rc = update_ai_array(ai_factory_count, ai_factory_size, &ai_factory_array,
64 					 AI_FACTORY_INC_SIZE, actionType, actionRecno);
65 			arrayCount = ai_factory_count;
66 			break;
67 
68 		case FIRM_MARKET:
69 			rc = update_ai_array(ai_market_count, ai_market_size, &ai_market_array,
70 					 AI_MARKET_INC_SIZE, actionType, actionRecno);
71 			arrayCount = ai_market_count;
72 			break;
73 
74 		case FIRM_INN:
75 			rc = update_ai_array(ai_inn_count, ai_inn_size, &ai_inn_array,
76 					 AI_INN_INC_SIZE, actionType, actionRecno);
77 			arrayCount = ai_inn_count;
78 			break;
79 
80 		case FIRM_MINE:
81 			rc = update_ai_array(ai_mine_count, ai_mine_size, &ai_mine_array,
82 				  AI_MINE_INC_SIZE, actionType, actionRecno);
83 			arrayCount = ai_mine_count;
84 			break;
85 
86 		case FIRM_RESEARCH:
87 			rc = update_ai_array(ai_research_count, ai_research_size, &ai_research_array,
88 					 AI_RESEARCH_INC_SIZE, actionType, actionRecno);
89 			arrayCount = ai_research_count;
90 			break;
91 
92 		case FIRM_WAR_FACTORY:
93 			rc = update_ai_array(ai_war_count, ai_war_size, &ai_war_array,
94 					 AI_WAR_INC_SIZE, actionType, actionRecno);
95 			arrayCount = ai_war_count;
96 			break;
97 
98 		case FIRM_HARBOR:
99 			rc = update_ai_array(ai_harbor_count, ai_harbor_size, &ai_harbor_array,
100 					 AI_HARBOR_INC_SIZE, actionType, actionRecno);
101 			arrayCount = ai_harbor_count;
102 			break;
103 
104 		default:
105 			err_here();
106 			return 0;
107 	}
108 
109 	return rc;
110 }
111 //---------- End of function Nation::update_ai_firm_array --------//
112 
113 
114 //--------- Begin of function Nation::update_ai_array --------//
115 //
116 // <short&> aiInfoCount - the count of the AI info array.
117 // <short&> aiInfoSize  - the size of the AI info array.
118 // <short**> aiInfoArray - poniter to the AI info array.
119 // <int>    arrayIncSize - the increment size of the array.
120 //
121 // <int> actionType: 1  - add a record to the array
122 //							0  - no addition or deletion, just return
123 //							-1 - del a record from the array
124 //
125 // [int] actionRecno : the recno to be deleted, if actionType is -1.
126 //							  the recno to be added, if actionType is 1.
127 //
update_ai_array(short & aiInfoCount,short & aiInfoSize,short ** aiInfoArrayPtr,int arrayIncSize,int actionType,int actionRecno)128 short* Nation::update_ai_array(short& aiInfoCount, short& aiInfoSize,
129 					short** aiInfoArrayPtr, int arrayIncSize, int actionType, int actionRecno)
130 {
131 	err_when( aiInfoCount<0 );
132 	err_when( aiInfoCount > aiInfoSize );
133 	err_when( actionType<-1 || actionType>1 );
134 
135 	short* aiInfoArray = *aiInfoArrayPtr;
136 
137 	if( actionType == -1 )
138 	{
139 		short* aiInfoPtr = aiInfoArray;
140 
141 		for( int i=0 ; i<aiInfoCount ; i++, aiInfoPtr++ )
142 		{
143 			if( *aiInfoPtr == actionRecno )
144 			{
145 				if( i+1==aiInfoCount )		// the record to be deleted is the last record
146 				{
147 					*aiInfoPtr = 0;
148 				}
149 				else	// the record to be deleted is not the last record, somewhere in the array
150 				{
151 					//---- copy the last record to this slot which has been marked for deletion
152 
153 					*aiInfoPtr = aiInfoArray[aiInfoCount-1];
154 					aiInfoArray[aiInfoCount-1] = 0;
155 				}
156 
157 				aiInfoCount--;
158 				return aiInfoArray;
159 			}
160 		}
161 
162 		err_here();		// not found, this shouldn't happen.
163 	}
164 	else if( actionType == 1 )
165 	{
166 		if( aiInfoCount == aiInfoSize )
167 		{
168 			#ifdef DEBUG
169 			short saveDate1 = aiInfoArray[0];		// for vertification of resizing that old data are kept
170 			short saveDate2 = aiInfoArray[aiInfoCount-1];
171 			#endif
172 
173 			aiInfoSize += arrayIncSize;
174 
175 			*aiInfoArrayPtr = (short*) mem_resize( aiInfoArray, aiInfoSize*sizeof(short) );
176 
177 			aiInfoArray = *aiInfoArrayPtr;
178 
179 			err_when( saveDate1 != aiInfoArray[0] );		// for vertification of resizing that old data are kept
180 			err_when( saveDate2 != aiInfoArray[aiInfoCount-1] );
181 		}
182 
183 		aiInfoArray[aiInfoCount++] = actionRecno;
184 	}
185 
186 	return aiInfoArray;
187 }
188 //---------- End of function Nation::update_ai_array --------//
189 
190 
191 //--------- Begin of function Nation::add_firm_info --------//
192 //
add_firm_info(char firmId,short firmRecno)193 void Nation::add_firm_info(char firmId, short firmRecno)
194 {
195 	err_when( !firmId || !firmRecno );
196 
197 	int aiFirmCount;
198 
199 	update_ai_firm_array(firmId, 1, firmRecno, aiFirmCount);
200 }
201 //---------- End of function Nation::add_firm_info --------//
202 
203 
204 //--------- Begin of function Nation::del_firm_info --------//
205 
del_firm_info(char firmId,short firmRecno)206 void Nation::del_firm_info(char firmId, short firmRecno)
207 {
208 	err_when( !firmId || !firmRecno );
209 
210 	int aiFirmCount;
211 
212 	update_ai_firm_array(firmId, -1, firmRecno, aiFirmCount);
213 }
214 //---------- End of function Nation::del_firm_info --------//
215 
216 
217 //--------- Begin of function Nation::update_ai_region --------//
218 
update_ai_region()219 void Nation::update_ai_region()
220 {
221 	Town* townPtr;
222 	int	regionRecno;
223 
224 	memset( ai_region_array, 0, sizeof(ai_region_array) );
225 	ai_region_count = 0;
226 
227 	for( int i=0 ; i<ai_town_count ; i++ )
228 	{
229 		townPtr = town_array[ ai_town_array[i] ];
230 
231 		//---- see if this region has been included -------//
232 
233 		regionRecno=0;
234 
235 		for( int j=0 ; j<ai_region_count ; j++ )
236 		{
237 			if( ai_region_array[j].region_id == townPtr->region_id )
238 			{
239 				regionRecno = j+1;
240 				break;
241 			}
242 		}
243 
244 		if( !regionRecno )		// not included yet
245 		{
246 			if( ai_region_count == MAX_AI_REGION )		// no space for adding new region
247 				continue;
248 
249 			err_when( ai_region_count > MAX_AI_REGION );
250 
251 			ai_region_array[ai_region_count++].region_id = townPtr->region_id;
252 
253 			regionRecno = ai_region_count;
254 		}
255 
256 		//--- increase the town and base_town_count of the nation ---//
257 
258 		ai_region_array[regionRecno-1].town_count++;
259 
260 		if( townPtr->is_base_town )
261 			ai_region_array[regionRecno-1].base_town_count++;
262 	}
263 }
264 //---------- End of function Nation::update_ai_region --------//
265 
266 
267 //--------- Begin of function Nation::add_town_info --------//
268 
add_town_info(short townRecno)269 void Nation::add_town_info(short townRecno)
270 {
271 	update_ai_array(ai_town_count, ai_town_size, &ai_town_array,
272 						 AI_TOWN_INC_SIZE, 1, townRecno);
273 
274 	update_ai_region();
275 }
276 //---------- End of function Nation::add_town_info --------//
277 
278 
279 //--------- Begin of function Nation::del_town_info --------//
280 
del_town_info(short townRecno)281 void Nation::del_town_info(short townRecno)
282 {
283 	err_when( ai_base_town_count<0 );
284 
285 	//--- if this is a base town, decrease the base town counter ---//
286 
287 	if( town_array[townRecno]->is_base_town )
288 	{
289 		ai_base_town_count--;
290 		err_when( ai_base_town_count<0 );
291 	}
292 
293 	//------- delete the record from ai_town_array ------//
294 
295 	update_ai_array(ai_town_count, ai_town_size, &ai_town_array,
296 						 AI_TOWN_INC_SIZE, -1, townRecno);
297 
298 	update_ai_region();
299 }
300 //---------- End of function Nation::del_town_info --------//
301 
302 
303 //--------- Begin of function Nation::add_general_info --------//
304 
add_general_info(short unitRecno)305 void Nation::add_general_info(short unitRecno)
306 {
307 	Unit* unitPtr = unit_array[unitRecno];
308 
309 	err_when( unitPtr->rank_id != RANK_KING && unitPtr->rank_id != RANK_GENERAL );
310 
311 	update_ai_array(ai_general_count, ai_general_size,
312 						 &ai_general_array, AI_GENERAL_INC_SIZE, 1, unitRecno);
313 }
314 //---------- End of function Nation::add_general_info --------//
315 
316 
317 //--------- Begin of function Nation::del_general_info --------//
318 
del_general_info(short unitRecno)319 void Nation::del_general_info(short unitRecno)
320 {
321 	Unit* unitPtr = unit_array[unitRecno];
322 
323 	err_when( unitPtr->rank_id != RANK_KING && unitPtr->rank_id != RANK_GENERAL );
324 
325 	update_ai_array(ai_general_count, ai_general_size,
326 						 &ai_general_array, AI_GENERAL_INC_SIZE, -1, unitRecno);
327 }
328 //---------- End of function Nation::del_general_info --------//
329 
330 
331 //--------- Begin of function Nation::add_caravan_info --------//
332 
add_caravan_info(short unitRecno)333 void Nation::add_caravan_info(short unitRecno)
334 {
335 	update_ai_array(ai_caravan_count, ai_caravan_size, &ai_caravan_array,
336 						 AI_CARAVAN_INC_SIZE, 1, unitRecno);
337 }
338 //---------- End of function Nation::add_caravan_info --------//
339 
340 
341 //--------- Begin of function Nation::del_caravan_info --------//
342 
del_caravan_info(short unitRecno)343 void Nation::del_caravan_info(short unitRecno)
344 {
345 	update_ai_array(ai_caravan_count, ai_caravan_size, &ai_caravan_array,
346 						 AI_CARAVAN_INC_SIZE, -1, unitRecno);
347 }
348 //---------- End of function Nation::del_caravan_info --------//
349 
350 
351 //--------- Begin of function Nation::is_caravan_exist --------//
352 //
353 // Check whether there is an existing caravan travelling along
354 // the specific route.
355 //
356 // <int> firstStop, secondStop - firm recno of the first and second stops.
357 // [int] setStopInterval 		 - if this is given, then only caravans
358 //											that have been set stop within the given
359 //											days will be counted as existing ones.
360 //
is_caravan_exist(int firstStop,int secondStop,int setStopInterval)361 int Nation::is_caravan_exist(int firstStop, int secondStop, int setStopInterval)
362 {
363 	UnitCaravan* unitCaravan;
364 
365 	for( int i=0; i<ai_caravan_count; i++ )
366 	{
367 		unitCaravan = (UnitCaravan*) unit_array[ ai_caravan_array[i] ];
368 
369 		if( ( unitCaravan->stop_array[0].firm_recno == firstStop &&
370 				unitCaravan->stop_array[1].firm_recno == secondStop ) ||
371 			 ( unitCaravan->stop_array[1].firm_recno == firstStop &&
372 				unitCaravan->stop_array[0].firm_recno == secondStop ) )
373 		{
374 			if( setStopInterval )
375 			{
376 				if( info.game_date - unitCaravan->last_set_stop_date < setStopInterval )
377 					return unitCaravan->sprite_recno;
378 			}
379 			else
380 				return unitCaravan->sprite_recno;
381 		}
382 	}
383 
384 	return 0;
385 }
386 //---------- End of function Nation::is_caravan_exist --------//
387 
388 
389 //--------- Begin of function Nation::add_ship_info --------//
390 
add_ship_info(short unitRecno)391 void Nation::add_ship_info(short unitRecno)
392 {
393 	update_ai_array(ai_ship_count, ai_ship_size, &ai_ship_array,
394 						 AI_SHIP_INC_SIZE, 1, unitRecno);
395 }
396 //---------- End of function Nation::add_ship_info --------//
397 
398 
399 //--------- Begin of function Nation::del_ship_info --------//
400 
del_ship_info(short unitRecno)401 void Nation::del_ship_info(short unitRecno)
402 {
403 	update_ai_array(ai_ship_count, ai_ship_size, &ai_ship_array,
404 						 AI_SHIP_INC_SIZE, -1, unitRecno);
405 }
406 //---------- End of function Nation::del_ship_info --------//
407 
408 
409 //--------- Begin of function Nation::has_base_town_in_region --------//
410 //
411 // Return whether this nation has any base town in the given region.
412 //
has_base_town_in_region(int regionId)413 int Nation::has_base_town_in_region(int regionId)
414 {
415 	for( int i=0 ; i<ai_region_count ; i++ )
416 	{
417 		if( ai_region_array[i].region_id == regionId )
418 			return ai_region_array[i].base_town_count > 0;
419 	}
420 
421 	return 0;
422 }
423 //---------- End of function Nation::has_base_town_in_region --------//
424 
425 
426 //--------- Begin of function Nation::get_ai_region --------//
427 //
428 // Return the AIRegion of the given region id.
429 //
get_ai_region(int regionId)430 AIRegion* Nation::get_ai_region(int regionId)
431 {
432 	for( int i=0 ; i<ai_region_count ; i++ )
433 	{
434 		if( ai_region_array[i].region_id == regionId )
435 			return ai_region_array+i;
436 	}
437 
438 	return 0;
439 }
440 //---------- End of function Nation::get_ai_region --------//
441 
442