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    : OSPY2.CPP
22 //Description : Spy AI functions
23 
24 #include <OINFO.h>
25 #include <OFIRM.h>
26 #include <OTOWN.h>
27 #include <ONATION.h>
28 #include <OSPY.h>
29 
30 #define THIS ptr()
31 
32 //--------- Begin of function SpyProcess::process_ai ----------//
33 //
process_ai()34 void SpyProcess::process_ai()
35 {
36 	if( spy_recno%30 == info.game_date%30 )		// think about changing actions once 30 days
37 		think_reward();
38 
39 	switch( THIS->spy_place )
40 	{
41 		case SPY_TOWN:
42 			if( spy_recno%30 == info.game_date%30 )
43 				think_town_spy();
44 			break;
45 
46 		case SPY_FIRM:
47 			if( spy_recno%30 == info.game_date%30 )
48 				think_firm_spy();
49 			break;
50 
51 		case SPY_MOBILE:
52 			if( spy_recno%5 == info.game_date%5 )
53 				think_mobile_spy();
54 			break;
55 	}
56 }
57 //---------- End of function SpyProcess::process_ai ----------//
58 
59 
60 //--------- Begin of function SpyProcess::think_town_spy ----------//
61 //
think_town_spy()62 void SpyProcess::think_town_spy()
63 {
64 	Town* townPtr = town_array[THIS->spy_place_para];
65 
66 	if( townPtr->nation_recno == THIS->true_nation_recno )		// anti-spy
67 		return;
68 
69 	//------ if it's an independent town ------//
70 
71 	if( townPtr->nation_recno == 0 )
72 	{
73 		THIS->set_action_mode(SPY_SOW_DISSENT);
74 
75 		//--- if the resistance has already drop low enough, the spy no longer needs to be in the town ---//
76 
77 		if( townPtr->race_loyalty_array[THIS->race_id-1] < MIN_INDEPENDENT_DEFEND_LOYALTY  )
78 		{
79 			THIS->mobilize_town_spy();
80 		}
81 	}
82 	else
83 	{
84 		//-------------- if it's a nation town -------------//
85 		//
86 		// Set to sleep mode in most time so the spying skill can increase
87 		// gradually, when the loyalty level of the village falls to near
88 		// rebel level, set all of your spies in the village to sow dissent
89 		// mode and cause rebellion in the enemy village.
90 		//
91 		//--------------------------------------------------//
92 
93 		Nation* trueNation = nation_array[THIS->true_nation_recno];
94 
95 		if( townPtr->average_loyalty() < 50 - trueNation->pref_loyalty_concern/10 )		// pref_loyalty_concern actually does apply to here, we just use a preference var so that the decision making process will vary between nations
96 		{
97 			THIS->set_action_mode(SPY_SOW_DISSENT);
98 		}
99 		else
100 		{
101 			if( misc.random(5)==0 )			// 20% chance of sowing dissents.
102 				THIS->set_action_mode(SPY_SOW_DISSENT);
103 			else
104 				THIS->set_action_mode(SPY_IDLE);
105 		}
106 	}
107 }
108 //---------- End of function SpyProcess::think_town_spy ----------//
109 
110 
111 //--------- Begin of function SpyProcess::think_firm_spy ----------//
112 //
think_firm_spy()113 void SpyProcess::think_firm_spy()
114 {
115 	Firm* firmPtr = firm_array[THIS->spy_place_para];
116 
117 	if( firmPtr->nation_recno == THIS->true_nation_recno )		// anti-spy
118 		return;
119 
120 	//-------- try to capturing the firm --------//
121 
122 	if( THIS->capture_firm() )
123 		return;
124 
125 	//-------- think about bribing ---------//
126 
127 	if( think_bribe() )
128 		return;
129 
130 	//-------- think about assassinating ---------//
131 
132 	if( think_assassinate() )
133 		return;
134 
135 	//------ think about changing spy mode ----//
136 
137 	else if( misc.random(3)==0 )           // 1/10 chance to set it to idle to prevent from being caught
138 	{
139 		THIS->set_action_mode(SPY_IDLE);
140 	}
141 	else if( misc.random(2)==0 &&
142 				THIS->can_sabotage() && firmPtr->is_operating() && firmPtr->productivity >= 20 )
143 	{
144 		THIS->set_action_mode(SPY_SABOTAGE);
145 	}
146 	else
147 	{
148 		THIS->set_action_mode(SPY_SOW_DISSENT);
149 	}
150 }
151 //---------- End of function SpyProcess::think_firm_spy ----------//
152 
153 
154 //--------- Begin of function SpyProcess::think_bribe ----------//
155 //
think_bribe()156 int SpyProcess::think_bribe()
157 {
158 	Firm* firmPtr = firm_array[THIS->spy_place_para];
159 
160 	//--- only bribe enemies in military camps ---//
161 
162 	if( firmPtr->firm_id != FIRM_CAMP )
163 		return 0;
164 
165    //----- only if there is an overseer in the camp -----//
166 
167 	if( !firmPtr->overseer_recno )
168 		return 0;
169 
170 	//---- see if the overseer can be bribe (kings and your own spies can't be bribed) ----//
171 
172 	if( !firmPtr->can_spy_bribe(0, THIS->true_nation_recno ) )		// 0-bribe the overseer
173 		return 0;
174 
175 	//------ first check our financial status ------//
176 
177 	Nation* ownNation = nation_array[THIS->true_nation_recno];
178 	Unit*   overseerUnit = unit_array[firmPtr->overseer_recno];
179 
180 	if( THIS->spy_skill < MIN(50, overseerUnit->skill.skill_level) ||
181 		 !ownNation->ai_should_spend(30) )
182 	{
183 		return 0;
184 	}
185 
186 	//----- think about how important is this firm -----//
187 
188 	int firmImportance = 0;
189 	Town* townPtr;
190 
191 	for( int i=firmPtr->linked_town_count-1 ; i>=0 ; i-- )
192 	{
193 		townPtr = town_array[ firmPtr->linked_town_array[i] ];
194 
195 		if( townPtr->nation_recno == firmPtr->nation_recno )
196 			firmImportance += townPtr->population * 2;
197 		else
198 			firmImportance += townPtr->population;
199 	}
200 
201 	//------- think about which one to bribe -------//
202 
203 	//-- first get the succeedChange if the bribe amount is zero --//
204 
205 	int succeedChange = firmPtr->spy_bribe_succeed_chance( 0, spy_recno, 0 );		// first 0 - $0 bribe amount, 3rd 0 - bribe the overseer
206 
207 	//-- then based on it, figure out how much we have to offer to bribe successfully --//
208 
209 	int bribeAmount = MAX_BRIBE_AMOUNT * (100-succeedChange) / 100;
210 
211 	bribeAmount = MAX(100, bribeAmount);
212 
213 	//--- only bribe when the nation has enough money ---//
214 
215 	if( !ownNation->ai_should_spend(30, (float)bribeAmount) )
216 		return 0;
217 
218 	//------- try to bribe the commander ----//
219 
220 	int newSpyRecno = firmPtr->spy_bribe(bribeAmount, spy_recno, 0);
221 
222 	if( !newSpyRecno )		// bribing failed
223 		return 1;				// return 1 as the spy has been killed
224 
225 	Spy* newSpy = spy_array[newSpyRecno];
226 
227 	err_when( newSpy->true_nation_recno != THIS->true_nation_recno );
228 	err_when( newSpy->spy_place != SPY_FIRM );
229 
230 	if( newSpy->capture_firm() )			// try to capture the firm now
231 	{
232 		err_when( firm_array[newSpy->spy_place_para]->nation_recno != THIS->true_nation_recno );
233 
234 		newSpy->drop_spy_identity();		// drop the spy identity of the newly bribed spy if the capture is successful, this will save the spying costs
235 	}
236 
237 	return 1;
238 }
239 //---------- End of function SpyProcess::think_bribe ----------//
240 
241 
242 //--------- Begin of function SpyProcess::think_reward ----------//
243 //
244 // Think about rewarding this spy.
245 //
think_reward()246 int SpyProcess::think_reward()
247 {
248 	Nation* ownNation = nation_array[THIS->true_nation_recno];
249 
250 	//----------------------------------------------------------//
251 	// The need to secure high loyalty on this unit is based on:
252 	// -its skill
253 	// -its combat level
254 	// -soldiers commanded by this unit
255 	//----------------------------------------------------------//
256 
257 	int neededLoyalty = THIS->spy_skill * (100+ownNation->pref_loyalty_concern) / 100;
258 
259 	neededLoyalty = MAX( UNIT_BETRAY_LOYALTY+10, neededLoyalty );		// 10 points above the betray loyalty level to prevent betrayal
260 	neededLoyalty = MIN( 100, neededLoyalty );
261 
262 	//------- if the loyalty is already high enough ------//
263 
264 	if( THIS->spy_loyalty >= neededLoyalty )
265 		return 0;
266 
267 	//---------- see how many cash & profit we have now ---------//
268 
269 	int rewardNeedRating = neededLoyalty - THIS->spy_loyalty;
270 
271 	if( THIS->spy_loyalty < UNIT_BETRAY_LOYALTY+5 )
272 		rewardNeedRating += 50;
273 
274 	if( ownNation->ai_should_spend(rewardNeedRating) )
275 	{
276 		THIS->reward(COMMAND_AI);
277 		return 1;
278 	}
279 
280 	return 0;
281 }
282 //---------- End of function SpyProcess::think_reward ----------//
283 
284 
285 //--------- Begin of function SpyProcess::think_mobile_spy ----------//
286 //
think_mobile_spy()287 int SpyProcess::think_mobile_spy()
288 {
289 	Unit* unitPtr = unit_array[THIS->spy_place_para];
290 
291    //--- if the spy is on the ship, nothing can be done ---//
292 
293 	if( !unitPtr->is_visible() )
294 		return 0;
295 
296 	//---- if the spy has stopped and there is no new action ----//
297 
298 	if( unitPtr->is_ai_all_stop() &&
299 		 (!THIS->notify_cloaked_nation_flag || THIS->cloaked_nation_recno==0) )
300 	{
301 		return think_mobile_spy_new_action();
302 	}
303 
304 	return 0;
305 }
306 //---------- End of function SpyProcess::think_mobile_spy ----------//
307 
308 
309 //-------- Begin of function SpyProcess::think_mobile_spy_new_action --------//
310 //
think_mobile_spy_new_action()311 int SpyProcess::think_mobile_spy_new_action()
312 {
313 	Nation* trueNation = nation_array[THIS->true_nation_recno];
314 
315 	err_when( THIS->spy_place != SPY_MOBILE );
316 
317 	int spyRegionId = unit_array[THIS->spy_place_para]->region_id();
318 
319 	//----- try to sneak into an enemy camp ------//
320 
321 	int firmRecno = trueNation->think_assign_spy_target_camp(THIS->race_id, spyRegionId);
322 
323 	if( firmRecno )
324 	{
325 		Firm* firmPtr = firm_array[firmRecno];
326 
327 		return add_assign_spy_action( firmPtr->loc_x1, firmPtr->loc_y1, firmPtr->nation_recno );
328 	}
329 
330 	//--- try to sneak into an enemy town or an independent town ---//
331 
332 	int townRecno = trueNation->think_assign_spy_target_town(THIS->race_id, spyRegionId);
333 
334 	if( townRecno )
335 	{
336 		Town* townPtr = town_array[townRecno];
337 
338 		return add_assign_spy_action( townPtr->loc_x1, townPtr->loc_y1, townPtr->nation_recno );
339 	}
340 
341 	//------ think if we should drop the spy identity -------//
342 
343 	int dropIdentity = 0;
344 
345 	//-------- if we already have too many spies --------//
346 
347 	if( trueNation->total_spy_count > trueNation->total_population * (10+trueNation->pref_spy/5) / 100 )		// 10% to 30%
348 	{
349 		dropIdentity = 1;
350 	}
351 
352 	//--- the expense of spies should not be too large ---//
353 
354 	else if( trueNation->expense_365days(EXPENSE_SPY) >
355 		 trueNation->expense_365days() * (50+trueNation->pref_counter_spy) / 400 )
356 	{
357 		dropIdentity = 1;
358 	}
359 
360 	else //------- try to assign to one of our own towns -------//
361 	{
362 		int townRecno = trueNation->think_assign_spy_own_town(THIS->race_id, spyRegionId);
363 
364 		if( townRecno )
365 		{
366 			Town* townPtr = town_array[townRecno];
367 
368 			return add_assign_spy_action( townPtr->loc_x1, townPtr->loc_y1, townPtr->nation_recno );
369 		}
370 		else
371 		{
372 			dropIdentity = 1;
373 		}
374 	}
375 
376 	//---------- drop spy identity now --------//
377 
378 	if( dropIdentity )
379 	{
380 		THIS->drop_spy_identity();
381 		return 1;
382 	}
383 
384 	return 0;
385 }
386 //---------- End of function SpyProcess::think_mobile_spy_new_action --------//
387 
388 
389 //-------- Begin of function SpyProcess::add_assign_spy_action --------//
390 //
add_assign_spy_action(int destXLoc,int destYLoc,int cloakedNationRecno)391 int SpyProcess::add_assign_spy_action(int destXLoc, int destYLoc, int cloakedNationRecno)
392 {
393 	err_when( THIS->spy_place != SPY_MOBILE );
394 	err_when( unit_array.is_deleted(THIS->spy_place_para) );
395 
396 	return nation_array[THIS->true_nation_recno]->add_action( destXLoc, destYLoc,
397 			 -1, -1, ACTION_AI_ASSIGN_SPY, cloakedNationRecno, 1, THIS->spy_place_para );
398 }
399 //---------- End of function SpyProcess::add_assign_spy_action --------//
400 
401 
402 //--------- Begin of function Spy::ai_spy_being_attacked ----------//
403 //
404 // This function is called when this spy is under attack.
405 //
406 // <int> attackerUnitRecno - recno of the attacker unit.
407 //
ai_spy_being_attacked(int attackerUnitRecno)408 int Spy::ai_spy_being_attacked(int attackerUnitRecno)
409 {
410 	err_when( spy_place != SPY_MOBILE );
411 
412 	Unit*   attackerUnit = unit_array[attackerUnitRecno];
413 	Unit*   spyUnit     = unit_array[spy_place_para];
414 	Nation* trueNation = nation_array[true_nation_recno];
415 
416 	//----- if we are attacking our own units -----//
417 
418 	if( attackerUnit->true_nation_recno() == true_nation_recno )
419 	{
420 		if( spy_skill > 50-trueNation->pref_spy/10 ||
421 			 spyUnit->hit_points < spyUnit->max_hit_points * (100-trueNation->pref_military_courage/2) / 100 )
422 		{
423 			change_cloaked_nation( true_nation_recno );
424 			return 1;
425 		}
426 	}
427 	else
428 	{
429 		//---- if this unit is attacking units of other nations -----//
430 		//
431 		// If the nation this spy cloaked into is at war with the spy's
432 		// true nation and the nation which the spy is currently attacking
433 		// is not at war with the spy's true nation, then change
434 		// the spy's cloak to the non-hostile nation.
435 		//
436 		//-----------------------------------------------------------//
437 
438 		if( trueNation->get_relation_status(attackerUnit->nation_recno) != NATION_HOSTILE &&
439 			 trueNation->get_relation_status(cloaked_nation_recno) == NATION_HOSTILE )
440 		{
441 			if( spy_skill > 50-trueNation->pref_spy/10 ||
442 				 spyUnit->hit_points < spyUnit->max_hit_points * (100-trueNation->pref_military_courage/2) / 100 )
443 			{
444 				change_cloaked_nation( true_nation_recno );
445 				return 1;
446 			}
447 		}
448 	}
449 
450    return 0;
451 }
452 //---------- End of function Spy::ai_spy_being_attacked ----------//
453 
454 
455 //--------- Begin of function SpyProcess::think_assassinate ----------//
456 //
think_assassinate()457 int SpyProcess::think_assassinate()
458 {
459 	Firm* firmPtr = firm_array[THIS->spy_place_para];
460 
461 	//--- only bribe enemies in military camps ---//
462 
463 	if( firmPtr->firm_id != FIRM_CAMP )
464 		return 0;
465 
466 	//----- only if there is an overseer in the camp -----//
467 
468 	if( !firmPtr->overseer_recno )
469 		return 0;
470 
471 	//---- get the attack and defense rating ----//
472 
473 	int attackRating, defenseRating, otherDefenderCount;
474 
475 	if( !THIS->get_assassinate_rating(firmPtr->overseer_recno, attackRating, defenseRating, otherDefenderCount) )		// return 0 if assassination is not possible
476 		return 0;
477 
478 	Nation* trueNation = nation_array[THIS->true_nation_recno];
479 
480 	if( attackRating + misc.random(20+trueNation->pref_spy/2) > defenseRating )		// the random number is to increase the chance of attempting assassination
481 	{
482 		THIS->assassinate(firmPtr->overseer_recno, COMMAND_AI);
483 		return 1;
484 	}
485 
486 	return 0;
487 }
488 //---------- End of function SpyProcess::think_assassinate ----------//
489 
490