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    : OFIRMAI.CPP
22 //Description : AI functions for the class Firm
23 
24 #include <OF_INN.h>
25 #include <OF_MINE.h>
26 #include <OF_FACT.h>
27 #include <OF_CAMP.h>
28 #include <OF_MARK.h>
29 #include <OUNITRES.h>
30 #include <OTALKRES.h>
31 #include <ONATION.h>
32 
33 //--------- Begin of function Firm::process_common_ai --------//
34 //
35 // AI processing functions common for all firm types.
36 //
process_common_ai()37 void Firm::process_common_ai()
38 {
39 	if( info.game_date%30==firm_recno%30 )
40 		think_repair();
41 
42 	//------ think about closing this firm ------//
43 
44 	if( !should_close_flag )
45 	{
46 		if( ai_should_close() )
47 		{
48 			should_close_flag = 1;
49 			nation_array[nation_recno]->firm_should_close_array[firm_id-1]++;
50 		}
51 	}
52 }
53 //--------- End of function Firm::process_common_ai --------//
54 
55 
56 //------- Begin of function Firm::think_repair -----------//
57 //
think_repair()58 void Firm::think_repair()
59 {
60 	Nation* ownNation = nation_array[nation_recno];
61 
62 	//----- check if the damage is serious enough -----//
63 
64 	if( hit_points >=
65 		 max_hit_points * (70+ownNation->pref_repair_concern/4) / 100 )	// 70% to 95%
66 	{
67 		return;
68 	}
69 
70 	//--- if it's no too heavily damaged, it is just that the AI has a high concern on this ---//
71 
72 	if( hit_points >= max_hit_points * 80 / 100 )
73 	{
74 		if( ownNation->total_jobless_population < 15 )
75 			return;
76 	}
77 
78 	//------- queue assigning a construction worker now ------//
79 
80 	ownNation->add_action(loc_x1, loc_y1, -1, -1, ACTION_AI_ASSIGN_CONSTRUCTION_WORKER, firm_id);
81 }
82 //--------- End of function Firm::think_repair -----------//
83 
84 
85 //------- Begin of function Firm::ai_del_firm -----------//
86 //
87 // Delete the firm no matter what status this firm is in.
88 //
ai_del_firm()89 void Firm::ai_del_firm()
90 {
91 	if( under_construction )
92 	{
93 		cancel_construction(COMMAND_AI);
94 	}
95 	else
96 	{
97 		if( can_sell() )
98 			sell_firm(COMMAND_AI);
99 		else
100 			destruct_firm(COMMAND_AI);
101 	}
102 }
103 //--------- End of function Firm::ai_del_firm -----------//
104 
105 
106 //------- Begin of function Firm::ai_should_close -----------//
107 //
108 // This is function is for derived class to overload.
109 //
ai_should_close()110 int Firm::ai_should_close()
111 {
112 	return 0;
113 }
114 //--------- End of function Firm::ai_should_close -----------//
115 
116 
117 //------- Begin of function Firm::think_hire_inn_unit -------//
118 //
think_hire_inn_unit()119 int Firm::think_hire_inn_unit()
120 {
121 	if( !nation_array[nation_recno]->ai_should_hire_unit(30) )		// 30 - importance rating
122 		return 0;
123 
124 	//---- one firm only hire one foreign race worker ----//
125 
126 	int i, foreignRaceCount=0;
127 	int majorityRace = majority_race();
128 
129 	if( majorityRace )
130 	{
131 		for( i=0 ; i<worker_count ; i++ )
132 		{
133 			if( worker_array[i].race_id != majorityRace )
134 				foreignRaceCount++;
135 		}
136 	}
137 
138 	//-------- try to get skilled workers from inns --------//
139 
140 	Nation*  nationPtr = nation_array[nation_recno];
141 	FirmInn* firmInn, *bestInn=NULL;
142 	int		curRating, bestRating=0, bestInnUnitId=0;
143 	int		prefTownHarmony = nationPtr->pref_town_harmony;
144 
145 	for( i=0 ; i<nationPtr->ai_inn_count ; i++ )
146 	{
147 		firmInn = (FirmInn*) firm_array[ nationPtr->ai_inn_array[i] ];
148 
149 		if( firmInn->region_id != region_id )
150 			continue;
151 
152 		InnUnit* innUnit = firmInn->inn_unit_array;
153 
154 		for( int j=0 ; j<firmInn->inn_unit_count ; j++, innUnit++ )
155 		{
156 			if( innUnit->skill.skill_id != firm_skill_id )
157 				continue;
158 
159 			//-------------------------------------------//
160 			// Rating of a unit to be hired is based on:
161 			//
162 			// -distance between the inn and this firm.
163 			// -whether the unit is racially homogenous to the majority of the firm workers
164 			//
165 			//-------------------------------------------//
166 
167 			curRating = world.distance_rating( center_x, center_y,
168 							firmInn->center_x, firmInn->center_y );
169 
170 			curRating += innUnit->skill.skill_level;
171 
172 			if( majorityRace == unit_res[innUnit->unit_id]->race_id )
173 			{
174 				curRating += prefTownHarmony;
175 			}
176 			else
177 			{
178 				//----------------------------------------------------//
179 				// Don't pick this unit if it isn't racially homogenous
180 				// to the villagers, and its pref_town_harmony is higher
181 				// than its skill level. (This means if its skill level
182 				// is low, its chance of being selected is lower.
183 				//----------------------------------------------------//
184 
185 				if( majorityRace )
186 				{
187 					if( foreignRaceCount>0 || prefTownHarmony > innUnit->skill.skill_level-50 )
188 						continue;
189 				}
190 			}
191 
192 			if( curRating > bestRating )
193 			{
194 				bestRating    = curRating;
195 				bestInn       = firmInn;
196 				bestInnUnitId = j+1;
197 			}
198 		}
199 	}
200 
201 	//-----------------------------------------//
202 
203 	if( bestInn )
204 	{
205 		int unitRecno = bestInn->hire(bestInnUnitId);
206 
207 		if( unitRecno )
208 		{
209 			unit_array[unitRecno]->assign(loc_x1, loc_y1);
210 			return 1;
211 		}
212 	}
213 
214 	return 0;
215 }
216 //--------- End of function Firm::think_hire_inn_unit -------//
217 
218 
219 //------- Begin of function Firm::being_attacked -----------//
220 //
being_attacked(int attackerUnitRecno)221 void Firm::being_attacked(int attackerUnitRecno)
222 {
223 	last_attacked_date = info.game_date;
224 
225 	if( nation_recno && firm_ai )
226 	{
227 		if( unit_array[attackerUnitRecno]->nation_recno == nation_recno )		// this can happen when the unit has just changed nation
228 			return;
229 
230 		nation_array[nation_recno]->ai_defend(attackerUnitRecno);
231 	}
232 }
233 //--------- End of function Firm::being_attacked -----------//
234 
235 
236 //------- Begin of function Firm::ai_recruit_worker -----------//
237 //
ai_recruit_worker()238 int Firm::ai_recruit_worker()
239 {
240 	if( worker_count == MAX_WORKER )
241 		return 0;
242 
243 	Nation* nationPtr = nation_array[nation_recno];
244 	Town*   townPtr;
245 
246 	for( int i=0; i<linked_town_count ; i++ )
247 	{
248 		if( linked_town_enable_array[i] != LINK_EE )
249 			continue;
250 
251 		townPtr = town_array[ linked_town_array[i] ];
252 
253 		//-- only recruit workers from towns of other nations if we don't have labor ourselves
254 
255 		if( townPtr->nation_recno != nation_recno &&
256 			 nationPtr->total_jobless_population > MAX_WORKER )
257 		{
258 			continue;
259 		}
260 
261 		if( townPtr->jobless_population > 0 )
262 			return 0;		// don't order units to move into it as they will be recruited from the town automatically
263 	}
264 
265 	//---- order workers to move into the firm ----//
266 
267 	nationPtr->add_action(loc_x1, loc_y1, -1, -1, ACTION_AI_ASSIGN_WORKER, firm_id, MAX_WORKER-worker_count);
268 
269 	return 1;
270 }
271 //--------- End of function Firm::ai_recruit_worker -----------//
272 
273 
274 //------- Begin of function Firm::ai_build_neighbor_firm -----------//
275 //
ai_build_neighbor_firm(int firmId)276 int Firm::ai_build_neighbor_firm(int firmId)
277 {
278 	short   buildXLoc, buildYLoc;
279 	Nation* nationPtr = nation_array[nation_recno];
280 
281 	if( !nationPtr->find_best_firm_loc(firmId, loc_x1, loc_y1, buildXLoc, buildYLoc) )
282 	{
283 		no_neighbor_space = 1;
284 		return 0;
285 	}
286 
287 	nationPtr->add_action(buildXLoc, buildYLoc, loc_x1, loc_y1, ACTION_AI_BUILD_FIRM, firmId);
288 	return 1;
289 }
290 //--------- End of function Firm::ai_build_neighbor_firm -----------//
291 
292 
293 //--------- Begin of function Firm::ai_update_link_status ---------//
294 //
295 // Updating link status of this firm with towns.
296 //
ai_update_link_status()297 void Firm::ai_update_link_status()
298 {
299 	err_when( firm_id == FIRM_CAMP );		// FirmCamp has its own ai_update_link_status(), this version shouldn't be called.
300 
301 	if( !worker_array )		// if this firm does not need any workers.
302 		return;
303 
304 	if( is_worker_full() )	// if this firm already has all the workers it needs.
305 		return;
306 
307 	//------------------------------------------------//
308 
309 	Nation* ownNation = nation_array[nation_recno];
310 	int	  i, rc;
311 
312 	for( i=0 ; i<linked_town_count ; i++ )
313 	{
314 		Town* townPtr = town_array[linked_town_array[i]];
315 
316 		//--- enable link to hire people from the town ---//
317 
318 		rc = townPtr->nation_recno==0 ||		// either it's an independent town or it's friendly or allied to our nation
319 			  ownNation->get_relation_status(townPtr->nation_recno) >= NATION_FRIENDLY;
320 
321 		toggle_town_link( i+1, rc, COMMAND_AI );
322 	}
323 }
324 //----------- End of function Firm::ai_update_link_status ----------//
325 
326 
327 //------- Begin of function Firm::think_build_factory -----------//
328 //
think_build_factory(int rawId)329 int Firm::think_build_factory(int rawId)
330 {
331 	if( no_neighbor_space )		// if there is no space in the neighbor area for building a new firm.
332 		return 0;
333 
334 	Nation* nationPtr = nation_array[nation_recno];
335 
336 	//--- check whether the AI can build a new firm next this firm ---//
337 
338 	if( !nationPtr->can_ai_build(FIRM_FACTORY) )
339 		return 0;
340 
341 	//---------------------------------------------------//
342 
343 	int 			 factoryCount=0;
344 	FirmFactory* firmPtr;
345 	Firm*			 firmMarket;
346 
347 	for(int i=0; i<linked_firm_count; i++)
348 	{
349 		err_when(!linked_firm_array[i] || firm_array.is_deleted(linked_firm_array[i]));
350 
351 		firmPtr = (FirmFactory*) firm_array[linked_firm_array[i]];
352 
353 		if(firmPtr->firm_id!=FIRM_FACTORY)
354 			continue;
355 
356 		if( firmPtr->nation_recno != nation_recno )
357 			continue;
358 
359 		if( firmPtr->product_raw_id != rawId )
360 			continue;
361 
362 		//--- if one of own factories still has not recruited enough workers ---//
363 
364 		if( firmPtr->worker_count < MAX_WORKER )
365 			return 0;
366 
367 		//---------------------------------------------------//
368 		//
369 		// If this factory has a medium to high level of stock,
370 		// this means the bottleneck is not at the factories,
371 		// building more factories won't solve the problem.
372 		//
373 		//---------------------------------------------------//
374 
375 		if( firmPtr->stock_qty > firmPtr->max_stock_qty * 0.1 )
376 			return 0;
377 
378 		//---------------------------------------------------//
379 		//
380 		// Check if this factory is just outputing goods to
381 		// a market and it is actually not overcapacity.
382 		//
383 		//---------------------------------------------------//
384 
385 		for( int j=firmPtr->linked_firm_count-1 ; j>=0 ; j-- )
386 		{
387 			if( firmPtr->linked_firm_enable_array[j] != LINK_EE )
388 				continue;
389 
390 			firmMarket = firm_array[ firmPtr->linked_firm_array[j] ];
391 
392 			if( firmMarket->firm_id != FIRM_MARKET )
393 				continue;
394 
395 			//--- if this factory is producing enough goods to the market place, then it means it is still quite efficient
396 
397 			MarketGoods *marketGoods = ((FirmMarket*)firmMarket)->market_product_array[rawId-1];
398 
399 			if( marketGoods && marketGoods->stock_qty > 100 )
400 				return 0;
401 		}
402 
403 		//----------------------------------------------//
404 
405 		factoryCount++;
406 	}
407 
408 	//---- don't build additional factory if we don't have enough peasants ---//
409 
410 	if( factoryCount>=1 && !nationPtr->ai_has_enough_food() )
411 		return 0;
412 
413 	//-- if there isn't much raw reserve left, don't build new factories --//
414 
415 	if( firm_id == FIRM_MINE )
416 	{
417 		if( ((FirmMine*)this)->reserve_qty < 1000 && factoryCount>=1 )
418 			return 0;
419 	}
420 
421 	//--- only build additional factories if we have a surplus of labor ---//
422 
423 	if( nationPtr->total_jobless_population < factoryCount * MAX_WORKER )
424 		return 0;
425 
426 	//--- only when we have checked it three times and all say it needs a factory, we then build a factory ---//
427 
428 	if( ++ai_should_build_factory_count >= 3 )
429 	{
430 		short buildXLoc, buildYLoc;
431 
432 		if( !nationPtr->find_best_firm_loc(FIRM_FACTORY, loc_x1, loc_y1, buildXLoc, buildYLoc) )
433 		{
434 			no_neighbor_space = 1;
435 			return 0;
436 		}
437 
438 		nationPtr->add_action(buildXLoc, buildYLoc, loc_x1, loc_y1, ACTION_AI_BUILD_FIRM, FIRM_FACTORY);
439 
440 		ai_should_build_factory_count = 0;
441 	}
442 
443 	return 1;
444 }
445 //--------- End of function Firm::think_build_factory -----------//
446 
447 
448 //------- Begin of function Firm::think_capture -----------//
449 //
think_capture()450 int Firm::think_capture()
451 {
452 	Nation* nationPtr;
453 
454 	int i;
455 	for( i=nation_array.size() ; i>0 ; i-- )
456 	{
457 		if( nation_array.is_deleted(i) )
458 			continue;
459 
460 		nationPtr = nation_array[i];
461 
462 		if( nationPtr->is_ai() && can_worker_capture(i) )
463 			break;
464 	}
465 
466 	if( i==0 )
467 		return 0;
468 
469 	//------- capture the firm --------//
470 
471 	capture_firm(i);
472 
473 	//------ order troops to attack nearby enemy camps -----//
474 
475 	Firm *firmPtr, *bestTarget=NULL;
476 	int  curDistance, minDistance=0x1000;
477 
478 	for( i=firm_array.size() ; i>0 ; i-- )
479 	{
480 		if( firm_array.is_deleted(i) )
481 			continue;
482 
483 		firmPtr = firm_array[i];
484 
485 		//----- only attack enemy camps -----//
486 
487 		if( firmPtr->nation_recno != nation_recno ||
488 			 firmPtr->firm_id != FIRM_CAMP )
489 		{
490 			continue;
491 		}
492 
493 		curDistance = misc.points_distance(center_x, center_y,
494 						  firmPtr->center_x, firmPtr->center_y );
495 
496 		//--- only attack camps within 15 location distance to this firm ---//
497 
498 		if( curDistance < 15 && curDistance < minDistance )
499 		{
500 			minDistance = curDistance;
501 			bestTarget  = firmPtr;
502 		}
503 	}
504 
505 	if( bestTarget )
506 	{
507 		int useAllCamp = nationPtr->pref_military_courage > 60 || misc.random(3)==0;
508 
509 		nationPtr->ai_attack_target( bestTarget->loc_x1, bestTarget->loc_y1,
510 			((FirmCamp*)bestTarget)->total_combat_level(), 0, 0, 0, 0, useAllCamp );
511 	}
512 
513 	return 1;
514 }
515 //--------- End of function Firm::think_capture -----------//
516 
517 
518 //------- Begin of function Firm::think_linked_town_change_nation ------//
519 //
520 // This function is called by Town::set_nation() when a town linked
521 // to this firm has changed nation.
522 //
523 // <int> linkedTownRecno - the recno of the town that has changed nation.
524 // <int> oldNationRecno  - the old nation recno of the town
525 // <int> newNationRecno  - the new nation recno of the town
526 //
think_linked_town_change_nation(int linkedTownRecno,int oldNationRecno,int newNationRecno)527 void Firm::think_linked_town_change_nation(int linkedTownRecno, int oldNationRecno, int newNationRecno)
528 {
529 
530 }
531 //-------- End of function Firm::think_linked_town_change_nation ------//
532 
533 
534 //--------- Begin of function Firm::ai_firm_captured --------//
535 //
536 // This is function is called when the AI's firm is just
537 // about to be captured.
538 //
ai_firm_captured(int capturerNationRecno)539 void Firm::ai_firm_captured(int capturerNationRecno)
540 {
541 	Nation* ownNation = nation_array[nation_recno];
542 
543 	if( !ownNation->is_ai() )			//**BUGHERE
544 		return;
545 
546 	if( ownNation->get_relation(capturerNationRecno)->status >= NATION_FRIENDLY )
547 		ownNation->ai_end_treaty(capturerNationRecno);
548 
549 	talk_res.ai_send_talk_msg(capturerNationRecno, nation_recno, TALK_DECLARE_WAR);
550 }
551 //--------- End of function Firm::ai_firm_captured --------//
552 
553