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 : OSPY.CPP
22 //Description : Object Spy
23
24 #include <OPOWER.h>
25 #include <OGAME.h>
26 #include <ODATE.h>
27 #include <ONEWS.h>
28 #include <OFONT.h>
29 #include <OUNIT.h>
30 #include <OWORLD.h>
31 #include <OBUTTON.h>
32 #include <OFIRM.h>
33 #include <OTOWN.h>
34 #include <ONATION.h>
35 #include <ORACERES.h>
36 #include <OSYS.h>
37 #include <OSPY.h>
38 #include <OREMOTE.h>
39 // ###### begin Gilbert 10/10 #######//
40 #include <OSE.h>
41 // ###### end Gilbert 10/10 #######//
42 #include "gettext.h"
43
44
45 //--------- Begin of function Spy::Spy ----------//
46 //
Spy()47 Spy::Spy()
48 {
49 memset( this, 0, sizeof(Spy) );
50 }
51 //---------- End of function Spy::Spy ----------//
52
53
54 //--------- Begin of function Spy::deinit ----------//
55 //
deinit()56 void Spy::deinit()
57 {
58 set_place(SPY_UNDEFINED, 0); // reset spy place vars
59
60 race_res[race_id]->free_name_id(name_id);
61
62 spy_recno = 0;
63 }
64 //---------- End of function Spy::deinit ----------//
65
66
67 //--------- Begin of function Spy::set_action_mode ----------//
68 //
set_action_mode(int actionMode)69 void Spy::set_action_mode(int actionMode)
70 {
71 action_mode = actionMode;
72 }
73 //---------- End of function Spy::set_action_mode ----------//
74
75
76 //--------- Begin of function Spy::set_place ----------//
77 //
78 // Meaning of spy_place_para:
79 //
80 // SPY_MOBILE - unit recno of the spy
81 // SPY_TOWN - town recno
82 // SPY_FIRM - firm recno
83 // SPY_SHIP - unit recno of the ship
84 //
set_place(int spyPlace,int spyPlacePara)85 void Spy::set_place(int spyPlace, int spyPlacePara)
86 {
87 //----- reset spy counter of the current place ----//
88
89 if( spy_place == SPY_FIRM )
90 {
91 if( true_nation_recno == nation_array.player_recno )
92 {
93 if( !firm_array.is_deleted(spy_place_para) )
94 {
95 firm_array[spy_place_para]->player_spy_count--;
96 err_when( firm_array[spy_place_para]->player_spy_count<0 );
97 }
98 }
99 }
100
101 else if( spy_place == SPY_TOWN )
102 {
103 if( !town_array.is_deleted(spy_place_para) )
104 {
105 town_array[spy_place_para]->race_spy_count_array[race_id-1]--;
106 err_when( town_array[spy_place_para]->race_spy_count_array[race_id-1]<0 );
107 }
108 }
109
110 //------- set the spy place now ---------//
111
112 spy_place = spyPlace;
113 spy_place_para = spyPlacePara;
114
115 action_mode = SPY_IDLE; // reset the spy mode
116
117 //------- set the spy counter of the new place ------//
118
119 if( spy_place == SPY_FIRM )
120 {
121 if( true_nation_recno == nation_array.player_recno )
122 firm_array[spy_place_para]->player_spy_count++;
123
124 cloaked_nation_recno = (char) firm_array[spy_place_para]->nation_recno;
125
126 if( firm_array[spy_place_para]->nation_recno != true_nation_recno )
127 notify_cloaked_nation_flag = 1; // when a spy has been assigned to a firm, its notification flag should be set to 1, so the nation can control it as it is one of its own units
128 }
129 else if( spy_place == SPY_TOWN )
130 {
131 town_array[spy_place_para]->race_spy_count_array[race_id-1]++;
132
133 //-----------------------------------------------------------//
134 // We need to update it here as this spy may have resigned from
135 // a foreign firm and go back to its home village. And the
136 // nation recno of the foreign firm and the home village are
137 // different.
138 //-----------------------------------------------------------//
139
140 cloaked_nation_recno = (char) town_array[spy_place_para]->nation_recno;
141
142 if( town_array[spy_place_para]->nation_recno != true_nation_recno ) // if it's our own town, don't change notify_cloaked_nation_flag
143 notify_cloaked_nation_flag = 1;
144 }
145 }
146 //---------- End of function Spy::set_place ----------//
147
148
149 //--------- Begin of function Spy::get_loc ----------//
150 //
151 // Return the location of the spy.
152 //
153 // <int&> xLoc, yLoc - vars for returning the locatin.
154 //
get_loc(int & xLoc,int & yLoc)155 int Spy::get_loc(int& xLoc, int& yLoc)
156 {
157 switch( spy_place )
158 {
159 case SPY_FIRM:
160 if( !firm_array.is_deleted(spy_place_para) )
161 {
162 xLoc = firm_array[spy_place_para]->center_x;
163 yLoc = firm_array[spy_place_para]->center_y;
164 return 1;
165 }
166 break;
167
168 case SPY_TOWN:
169 if( !town_array.is_deleted(spy_place_para) )
170 {
171 xLoc = town_array[spy_place_para]->center_x;
172 yLoc = town_array[spy_place_para]->center_y;
173 return 1;
174 }
175 break;
176
177 case SPY_MOBILE:
178 if( !unit_array.is_deleted(spy_place_para) )
179 {
180 xLoc = unit_array[spy_place_para]->next_x_loc();
181 yLoc = unit_array[spy_place_para]->next_y_loc();
182 return 1;
183 }
184 break;
185 }
186
187 return 0;
188 }
189 //---------- End of function Spy::get_loc ----------//
190
191
192 //------ Begin of function Spy::spy_place_nation_recno -------//
193 //
194 // Return the nation recno of the place where the spy stays.
195 //
spy_place_nation_recno()196 int Spy::spy_place_nation_recno()
197 {
198 if( spy_place == SPY_TOWN )
199 return town_array[spy_place_para]->nation_recno;
200
201 else if( spy_place == SPY_FIRM )
202 return firm_array[spy_place_para]->nation_recno;
203
204 else
205 return 0;
206 }
207 //-------- End of function Spy::spy_place_nation_recno --------//
208
209
210 //--------- Begin of function Spy::next_day ----------//
211 //
next_day()212 void Spy::next_day()
213 {
214 SpyArrayLock arrayLock;
215
216 //------- pay expenses --------//
217
218 pay_expense();
219
220 //------ when the spy has been exposed -------//
221
222 if( exposed_flag )
223 {
224 //-- he will be killed immediately unless he is back in his original nation color ---//
225
226 if( true_nation_recno != cloaked_nation_recno )
227 {
228 get_killed();
229 return;
230 }
231 else
232 exposed_flag = 0; // reset exposed_flag.
233 }
234
235 //------ process actions ---------//
236
237 if( info.game_date%30 == spy_recno%30 )
238 {
239 if( spy_place == SPY_TOWN )
240 process_town_action();
241
242 else if( spy_place == SPY_FIRM )
243 process_firm_action();
244 }
245
246 //------ increase skill --------//
247
248 int rc;
249
250 if( action_mode==SPY_IDLE ) // increase slower when in sleep mode
251 rc = info.game_date%80 == spy_recno%80;
252 else
253 rc = info.game_date%40 == spy_recno%40;
254
255 if( rc && spy_skill < 100 )
256 spy_skill++;
257
258 //----- update loyalty & think betray -------//
259
260 if( info.game_date%60 == spy_recno%60 )
261 {
262 update_loyalty();
263
264 if( think_betray() )
265 return;
266 }
267
268 //----------- visit map (for fog of war) ----------//
269
270 if( true_nation_recno == nation_array.player_recno )
271 {
272 if( spy_place == SPY_TOWN )
273 {
274 Town* townPtr = town_array[spy_place_para];
275 world.visit( townPtr->loc_x1, townPtr->loc_y1, townPtr->loc_x2, townPtr->loc_y2, EXPLORE_RANGE-1 );
276 }
277 else if( spy_place == SPY_FIRM )
278 {
279 Firm* firmPtr = firm_array[spy_place_para];
280 world.visit( firmPtr->loc_x1, firmPtr->loc_y1, firmPtr->loc_x2, firmPtr->loc_y2, EXPLORE_RANGE-1 );
281 }
282 }
283
284 //---------- debug code -----------//
285
286 #ifdef DEBUG
287
288 err_when( race_id<1 || race_id>MAX_RACE );
289
290 switch( spy_place )
291 {
292 case SPY_MOBILE:
293 {
294 Unit* unitPtr = unit_array[spy_place_para];
295
296 err_when( unitPtr->rank_id == RANK_KING );
297 err_when( unitPtr->spy_recno != spy_recno );
298 err_when( unitPtr->skill.skill_id == SKILL_SPYING );
299 break;
300 }
301
302 case SPY_TOWN:
303 err_when( town_array[spy_place_para]->nation_recno != cloaked_nation_recno );
304 break;
305
306 case SPY_FIRM:
307 err_when( firm_array.is_deleted(spy_place_para) );
308 {
309 Firm* firmPtr = firm_array[spy_place_para];
310
311 int i;
312 for( i=0 ; i<firmPtr->worker_count ; i++ )
313 {
314 if( firmPtr->worker_array[i].spy_recno==spy_recno )
315 break;
316 }
317
318 if( i==firmPtr->worker_count ) // not found in worker_array
319 {
320 err_when( !firmPtr->overseer_recno ||
321 unit_array[firmPtr->overseer_recno]->spy_recno != spy_recno );
322 }
323 }
324 break;
325 }
326 #endif
327 }
328 //---------- End of function Spy::next_day ----------//
329
330
331 //--------- Begin of function Spy::process_town_action ----------//
332 //
process_town_action()333 void Spy::process_town_action()
334 {
335 SpyArrayLock arrayLock;
336
337 Town* townPtr = town_array[spy_place_para];
338
339 if( action_mode == SPY_SOW_DISSENT )
340 {
341 if( townPtr->race_pop_array[race_id-1] > townPtr->race_spy_count_array[race_id-1] ) // only when there are non-spy people
342 {
343 float decValue = (float)spy_skill / 5 / townPtr->race_pop_array[race_id-1]; // the more people there, the longer it takes to decrease the loyalty
344
345 //----- if this is an independent town -----//
346
347 if( townPtr->nation_recno==0 )
348 {
349 townPtr->race_resistance_array[race_id-1][true_nation_recno-1] -= decValue;
350
351 if( townPtr->race_resistance_array[race_id-1][true_nation_recno-1] < 0 )
352 townPtr->race_resistance_array[race_id-1][true_nation_recno-1] = (float) 0;
353 }
354
355 //--- if this is an enemy town, decrease the town people's loyalty ---//
356
357 else
358 {
359 townPtr->race_loyalty_array[race_id-1] -= decValue;
360
361 if( townPtr->race_loyalty_array[race_id-1] < (float) 0 )
362 townPtr->race_loyalty_array[race_id-1] = (float) 0;
363 }
364 }
365 }
366 }
367 //---------- End of function Spy::process_town_action ----------//
368
369
370 //--------- Begin of function Spy::process_firm_action ----------//
371 //
process_firm_action()372 void Spy::process_firm_action()
373 {
374 SpyArrayLock arrayLock;
375
376 Firm* firmPtr = firm_array[spy_place_para];
377
378 //---------- Sow Dissent ----------//
379
380 if( action_mode == SPY_SOW_DISSENT )
381 {
382 //---- decrease the loyalty of the overseer if there is any -----//
383
384 if( firmPtr->overseer_recno )
385 {
386 Unit* unitPtr = unit_array[firmPtr->overseer_recno];
387
388 if( unitPtr->race_id == race_id )
389 {
390 if( misc.random(10 - spy_skill/10 + unitPtr->skill.skill_level/10)==0 // a commander with a higher leadership skill will be less influenced by the spy's dissents
391 && unitPtr->loyalty>0 )
392 {
393 unitPtr->change_loyalty( -1 );
394 }
395 }
396 }
397
398 //----- decrease the loyalty of the workers in the firm -----//
399
400 Worker* workerPtr = firmPtr->worker_array;
401
402 for( int i=0 ; i<firmPtr->worker_count ; i++, workerPtr++ )
403 {
404 if( workerPtr->race_id != race_id )
405 continue;
406
407 //---- if the worker lives in a town ----//
408
409 if( workerPtr->town_recno )
410 {
411 Town* townPtr = town_array[workerPtr->town_recno];
412 int raceId = workerPtr->race_id;
413
414 if( townPtr->race_pop_array[raceId-1] > townPtr->race_spy_count_array[raceId-1] ) // only when there are non-spy people
415 {
416 townPtr->change_loyalty( raceId, (float) -spy_skill / 5 / townPtr->race_pop_array[raceId-1] ); // the more people there, the longer it takes to decrease the loyalty
417 }
418 }
419 else //---- if the worker does not live in a town ----//
420 {
421 if( !workerPtr->spy_recno ) // the loyalty of the spy himself does not change
422 {
423 if( misc.random(10-spy_skill/10)==0 && workerPtr->worker_loyalty>0 )
424 workerPtr->worker_loyalty--;
425 }
426 }
427 }
428 }
429 }
430 //---------- End of function Spy::process_firm_action ----------//
431
432
433 //--------- Begin of function Spy::set_next_action_mode ----------//
434 //
set_next_action_mode()435 void Spy::set_next_action_mode()
436 {
437 if( spy_place==SPY_TOWN )
438 {
439 if( action_mode == SPY_IDLE )
440 set_action_mode(SPY_SOW_DISSENT);
441 else
442 set_action_mode(SPY_IDLE);
443 }
444 else if( spy_place==SPY_FIRM )
445 {
446 switch( action_mode )
447 {
448 case SPY_IDLE:
449 if( can_sabotage() )
450 {
451 set_action_mode(SPY_SABOTAGE);
452 break;
453 }
454
455 case SPY_SABOTAGE:
456 set_action_mode(SPY_SOW_DISSENT);
457 break;
458
459 case SPY_SOW_DISSENT:
460 set_action_mode(SPY_IDLE);
461 break;
462 }
463 }
464 else
465 err_here();
466 }
467 //---------- End of function Spy::set_next_action_mode ----------//
468
469
470 //--------- Begin of function Spy::can_sabotage ----------//
471 //
can_sabotage()472 int Spy::can_sabotage()
473 {
474 return spy_place == SPY_FIRM &&
475 firm_array[spy_place_para]->firm_id != FIRM_CAMP; // no sabotage actino for military camp
476 }
477 //---------- End of function Spy::can_sabotage ----------//
478
479
480 //--------- Begin of function Spy::get_killed ----------//
481 //
482 // [int] dispNews - whether display a news message or not
483 // (default: 1)
484 //
get_killed(int dispNews)485 void Spy::get_killed(int dispNews)
486 {
487 SpyArrayLock arrayLock;
488
489 //-------- add news --------//
490
491 if( true_nation_recno == nation_array.player_recno || // the player's spy is killed
492 cloaked_nation_recno == nation_array.player_recno ) // a spy cloaked as the player's people is killed in the player's firm or firm
493 {
494 news_array.spy_killed(spy_recno);
495 // ####### begin Gilbert 10/10 #######//
496 se_ctrl.immediate_sound("SPY_DIE");
497 // ####### end Gilbert 10/10 #######//
498 }
499
500 //--- If a spy is caught, the spy's nation's reputation wil decrease ---//
501
502 nation_array[true_nation_recno]->change_reputation((float)-SPY_KILLED_REPUTATION_DECREASE);
503
504 //------- if the spy is in a town -------//
505
506 int hostNationRecno=0;
507 //### begin alex 31/3 ###//
508 int mobileUnit = 0;
509 //#### end alex 31/3 ####//
510
511 if( spy_place==SPY_TOWN )
512 {
513 Town* townPtr = town_array[spy_place_para];
514
515 hostNationRecno = townPtr->nation_recno;
516
517 townPtr->dec_pop(race_id, 0);
518 }
519
520 //------- if the spy is in a firm -------//
521
522 else if( spy_place==SPY_FIRM )
523 {
524 Firm* firmPtr = firm_array[spy_place_para];
525
526 hostNationRecno = firmPtr->nation_recno;
527
528 //------- check if the overseer is the spy -------//
529
530 if( firmPtr->overseer_recno )
531 {
532 Unit* unitPtr = unit_array[firmPtr->overseer_recno];
533
534 if( unitPtr->spy_recno == spy_recno )
535 {
536 firmPtr->kill_overseer();
537 return;
538 }
539 }
540
541 //---- check if any of the workers is the spy ----//
542
543 for( int i=0 ; i<firmPtr->worker_count ; i++ )
544 {
545 if( firmPtr->worker_array[i].spy_recno == spy_recno )
546 {
547 firmPtr->kill_worker(i+1);
548 return;
549 }
550 }
551
552 err_here(); // the spy is not found here
553 }
554 else if( spy_place == SPY_MOBILE )
555 {
556 //### begin alex 31/3 ###//
557 //err_here(); // only spies in towns and firms will get killed instantly
558 unit_array.del(spy_place_para);
559 mobileUnit = 1;
560 //#### end alex 31/3 ####//
561 }
562 else
563 {
564 err_here();
565 }
566
567 //--- If the spy is in an AI town or firm, the AI's relationship towards the spy's owner nation will decrease ---//
568
569 if( hostNationRecno && nation_array[hostNationRecno]->is_ai() )
570 {
571 nation_array[hostNationRecno]->change_ai_relation_level(true_nation_recno, -5);
572 }
573
574 //---- delete the spy from spy_array ----//
575 //### begin alex 31/3 ###//
576 if(!mobileUnit)
577 spy_array.del_spy(spy_recno);
578 //else spy_array.del_spy() is called in unit_array.del()
579 //#### end alex 31/3 ####//
580 }
581 //---------- End of function Spy::get_killed ----------//
582
583
584 //--------- Begin of function Spy::action_str ----------//
585 //
action_str()586 const char* Spy::action_str()
587 {
588 switch( action_mode )
589 {
590 case SPY_IDLE:
591 {
592 //---- if the spy is in a firm or town of its own nation ---//
593
594 if( (spy_place==SPY_TOWN &&
595 town_array[spy_place_para]->nation_recno == true_nation_recno) ||
596 (spy_place==SPY_FIRM &&
597 firm_array[spy_place_para]->nation_recno == true_nation_recno) )
598 {
599 return _("Counter-Spy");
600 }
601 else
602 return _("Sleep");
603 }
604
605 case SPY_SOW_DISSENT:
606 return _("Sow Dissent");
607
608 case SPY_SABOTAGE:
609 return _("Sabotage");
610
611 default:
612 err_here();
613 }
614
615 return "";
616 }
617 //---------- End of function Spy::action_str ----------//
618
619
620 //--------- Begin of function Spy::pay_expense ---------//
621 //
622 // -Each spy costs $5 dollars to maintain per month.
623 //
624 // -If your spies are mobile:
625 // >your nation pays them 1 food and $5 dollars per month
626 //
627 // -If your spies are in an enemy's town or firm:
628 // >the enemy pays them 1 food and the normal salary of their jobs.
629 // >your nation pays them $5 dollars per month. (your nation pays them no food)
630 //
631 // -If your spies are in your own town or firm:
632 // >your nation pays them 1 food and $5 dollars per month
633 //
pay_expense()634 void Spy::pay_expense()
635 {
636 Nation* nationPtr = nation_array[true_nation_recno];
637
638 //---------- reduce cash -----------//
639
640 if( nationPtr->cash > 0 )
641 {
642 nationPtr->add_expense( EXPENSE_SPY, (float) SPY_YEAR_SALARY / 365, 1 );
643 }
644 else // decrease loyalty if the nation cannot pay the unit
645 {
646 change_loyalty(-1);
647 }
648
649 //---------- reduce food -----------//
650
651 int inOwnFirm=0;
652
653 if( spy_place == SPY_FIRM )
654 {
655 Firm* firmPtr = firm_array[spy_place_para];
656
657 if( firmPtr->nation_recno == true_nation_recno &&
658 firmPtr->overseer_recno &&
659 unit_array[firmPtr->overseer_recno]->spy_recno == spy_recno )
660 {
661 inOwnFirm = 1;
662 }
663 }
664
665 if( spy_place == SPY_MOBILE || inOwnFirm )
666 {
667 if( nationPtr->food > 0 )
668 {
669 nationPtr->consume_food((float) PERSON_FOOD_YEAR_CONSUMPTION / 365);
670 }
671 else
672 {
673 if( info.game_date%NO_FOOD_LOYALTY_DECREASE_INTERVAL == 0 ) // decrease 1 loyalty point every 2 days
674 change_loyalty(-1);
675 }
676 }
677 }
678 //----------- End of function Spy::pay_expense -----------//
679
680
681 //--------- Begin of function Spy::update_loyalty ----------//
682 //
update_loyalty()683 void Spy::update_loyalty()
684 {
685 Nation* ownNation = nation_array[true_nation_recno];
686
687 int targetLoyalty = 50 + (int)ownNation->reputation/4 +
688 ownNation->overall_rank_rating()/4;
689
690 if( race_id == ownNation->race_id )
691 targetLoyalty += 20;
692
693 targetLoyalty = MIN( targetLoyalty, 100 );
694
695 if( spy_loyalty > targetLoyalty )
696 spy_loyalty--;
697
698 else if( spy_loyalty < targetLoyalty )
699 spy_loyalty++;
700 }
701 //---------- End of function Spy::update_loyalty ----------//
702
703
704 //--------- Begin of function Spy::change_loyalty ----------//
705 //
change_loyalty(int changeAmt)706 void Spy::change_loyalty(int changeAmt)
707 {
708 int newLoyalty = spy_loyalty + changeAmt;
709
710 newLoyalty = MAX(0, newLoyalty);
711
712 spy_loyalty = MIN(100, newLoyalty);
713 }
714 //---------- End of function Spy::change_loyalty ----------//
715
716
717 //--------- Begin of function Spy::think_betray ----------//
718 //
719 // Think about turning towards to the current cloaked nation,
720 // become a normal unit and lose its spy identity.
721 //
think_betray()722 int Spy::think_betray()
723 {
724 SpyArrayLock arrayLock;
725
726 if( spy_loyalty >= UNIT_BETRAY_LOYALTY ) // you when unit is
727 return 0;
728
729 if( cloaked_nation_recno == true_nation_recno || cloaked_nation_recno==0 )
730 return 0;
731
732 //--- think whether the spy should turn towards the nation ---//
733
734 Nation* nationPtr = nation_array[cloaked_nation_recno];
735
736 int nationScore = (int) nationPtr->reputation; // reputation can be negative
737
738 if( race_res.is_same_race(nationPtr->race_id, race_id) )
739 nationScore += 30;
740
741 if( spy_loyalty < nationScore || spy_loyalty==0 )
742 {
743 drop_spy_identity();
744 return 1;
745 }
746
747 return 0;
748 }
749 //---------- End of function Spy::think_betray ----------//
750
751
752 //--------- Begin of function Spy::drop_spy_identity ----------//
753 //
754 // Drop its spy identity. If it is currently cloaked to another
755 // nation, it will become units of that nation.
756 //
drop_spy_identity()757 void Spy::drop_spy_identity()
758 {
759 SpyArrayLock arrayLock;
760
761 if( spy_place == SPY_FIRM )
762 {
763 Firm* firmPtr = firm_array[spy_place_para];
764 int rc = 0;
765
766 if( firmPtr->overseer_recno )
767 {
768 Unit* unitPtr = unit_array[firmPtr->overseer_recno];
769
770 if( unitPtr->spy_recno == spy_recno )
771 {
772 unitPtr->spy_recno = 0;
773 rc = 1;
774 }
775 }
776
777 if( !rc )
778 {
779 for( int i=0 ; i<firmPtr->worker_count ; i++ )
780 {
781 if( firmPtr->worker_array[i].spy_recno==spy_recno )
782 {
783 firmPtr->worker_array[i].spy_recno = 0;
784 rc = 1;
785 break;
786 }
787 }
788
789 err_when( !rc );
790 }
791 }
792 else if( spy_place == SPY_MOBILE )
793 {
794 Unit* unitPtr = unit_array[spy_place_para];
795
796 unitPtr->spy_recno = 0;
797 }
798
799 //------ delete this Spy record from spy_array ----//
800
801 spy_array.del_spy(spy_recno); // Spy::deinit() will take care of the rest of the initialization for the spy
802 }
803 //---------- End of function Spy::drop_spy_identity ----------//
804
805
806 //--------- Begin of function Spy::change_true_nation ----------//
807 //
808 // Change the spy's true nation recno.
809 //
change_true_nation(int newNationRecno)810 void Spy::change_true_nation(int newNationRecno)
811 {
812 SpyArrayLock arrayLock;
813
814 err_when( nation_array.is_deleted(newNationRecno) );
815
816 true_nation_recno = newNationRecno;
817
818 //--- update Firm::player_spy_count if the spy is in a firm ---//
819
820 if( spy_place == SPY_FIRM )
821 {
822 spy_array.update_firm_spy_count(spy_place_para);
823 }
824 }
825 //---------- End of function Spy::change_true_nation ----------//
826
827
828 //--------- Begin of function Spy::change_cloaked_nation ----------//
829 //
830 // Change a spy's cloaked nation. This nation is when the caller
831 // only have spy_recno as the reference. While Unit::spy_change_nation()
832 // is called when the caller has unit_recno as the reference.
833 //
834 // <int> newNationRecno - the new nation the spy changes its cloack to
835 //
change_cloaked_nation(int newNationRecno)836 void Spy::change_cloaked_nation(int newNationRecno)
837 {
838 SpyArrayLock arrayLock;
839
840 if( newNationRecno == cloaked_nation_recno )
841 return;
842
843 //--- only mobile units and overseers can change nation, spies in firms or towns cannot change nation, their nation recno must be the same as the town or the firm's nation recno
844
845 if( spy_place == SPY_MOBILE )
846 {
847 unit_array[spy_place_para]->spy_change_nation(newNationRecno, COMMAND_AUTO);
848 return;
849 }
850 else if( spy_place == SPY_FIRM )
851 {
852 Firm* firmPtr = firm_array[spy_place_para];
853
854 if( firmPtr->overseer_recno &&
855 unit_array[firmPtr->overseer_recno]->spy_recno == spy_recno )
856 {
857 unit_array[firmPtr->overseer_recno]->spy_change_nation(newNationRecno, COMMAND_AUTO);
858 return;
859 }
860 }
861
862 err_here(); // cannot change a spy's cloaked_nation_recno in a firm and town as the spy's cloaked nation recno must be the same as the firm and town's nation recno
863 }
864 //---------- End of function Spy::change_cloaked_nation ----------//
865
866
867 //--------- Begin of function Spy::can_change_cloaked_nation ----------//
868 //
869 // Return whether this spy can change its cloaked to the specific
870 // nation right now.
871 //
872 // <int> newNationRecno - the new nation the spy changes its cloak to
873 //
can_change_cloaked_nation(int newNationRecno)874 int Spy::can_change_cloaked_nation(int newNationRecno)
875 {
876 //---- can always change back to its original nation ----//
877
878 if( newNationRecno == true_nation_recno )
879 return 1;
880
881 //--- only mobile units and overseers can change nation, spies in firms or towns cannot change nation, their nation recno must be the same as the town or the firm's nation recno
882
883 if( spy_place == SPY_MOBILE )
884 {
885 return unit_array[spy_place_para]->can_spy_change_nation();
886 }
887 else // can't change in firms or towns.
888 {
889 return 0;
890 }
891 }
892 //---------- End of function Spy::can_change_cloaked_nation ----------//
893
894
895 //--------- Begin of function Spy::capture_firm ----------//
896 //
897 // Order the spy to capture the firm he currently stays.
898 //
capture_firm()899 int Spy::capture_firm()
900 {
901 SpyArrayLock arrayLock;
902
903 if( spy_place != SPY_FIRM )
904 return 0;
905
906 Firm* firmPtr = firm_array[spy_place_para];
907
908 //------- if the spy is the overseer of the firm --------//
909
910 if( firm_res[firmPtr->firm_id]->need_overseer )
911 {
912 //-----------------------------------------------------//
913 //
914 // If the firm needs an overseer, the firm can only be
915 // captured if the spy is the overseer of the firm.
916 //
917 //-----------------------------------------------------//
918
919 if( !firmPtr->overseer_recno ||
920 unit_array[firmPtr->overseer_recno]->spy_recno != spy_recno )
921 {
922 return 0;
923 }
924
925 //---------------------------------------------------//
926 //
927 // For those soldiers who disagree with the spy general will
928 // leave the command base and attack it. Soldiers who are not
929 // racially homogenous to the spy general tend to disagree. Also
930 // if the spy has a higher leadership, there will be a higher
931 // chance for the soldiers to follow the general.
932 //
933 //---------------------------------------------------//
934
935 Unit* unitPtr = unit_array[firmPtr->overseer_recno];
936
937 if( !firm_res[firmPtr->firm_id]->live_in_town ) // if the workers of the firm do not live in towns
938 {
939 Worker* workerPtr = firmPtr->worker_array;
940 int unitLeadership = unitPtr->skill.skill_level;
941 int nationReputation = (int) nation_array[true_nation_recno]->reputation;
942 int obeyChance, obeyFlag;
943
944 for( int i=0 ; i<firmPtr->worker_count ; i++, workerPtr++ )
945 {
946 //-- if this worker is a spy, it will stay with you --//
947
948 if( workerPtr->spy_recno )
949 continue;
950
951 //---- if this is a normal worker -----//
952
953 obeyChance = unitLeadership/2 + nationReputation/2;
954
955 if( race_res.is_same_race(workerPtr->race_id, race_id) )
956 obeyChance += 50;
957
958 obeyFlag = misc.random(100) < obeyChance; // if obeyChance >= 100, all units will object the overseer
959
960 //--- if the worker obey, update its loyalty ---//
961
962 if( obeyFlag )
963 workerPtr->worker_loyalty = MAX(UNIT_BETRAY_LOYALTY, obeyChance/2);
964
965 //--- if the worker does not obey, it is mobilized and attack the base ---//
966
967 else
968 firmPtr->mobilize_worker(i+1, COMMAND_AUTO);
969 }
970 }
971
972 //--------- add news message --------//
973
974 if( firmPtr->nation_recno == nation_array.player_recno )
975 news_array.firm_captured(spy_place_para, true_nation_recno, 1); // 1 - the capturer is a spy
976
977 //-------- if this is an AI firm --------//
978
979 if( firmPtr->firm_ai )
980 firmPtr->ai_firm_captured(true_nation_recno);
981
982 //----- the spy change nation and capture the firm -------//
983
984 unitPtr->spy_change_nation(true_nation_recno, COMMAND_AUTO);
985 }
986 else
987 {
988 //------ otherwise the spy is a worker of the firm -------//
989
990 //---- check whether it's true that the only units in the firms are our spies ---//
991
992 Worker* workerPtr = firmPtr->worker_array;
993
994 for( int i=0 ; i<firmPtr->worker_count ; i++, workerPtr++ )
995 {
996 if( !workerPtr->spy_recno ) // this worker is not a spy
997 return 0;
998
999 if( spy_array[workerPtr->spy_recno]->true_nation_recno != true_nation_recno )
1000 return 0; // this worker is a spy, but not belong to the same nation
1001 }
1002
1003 //--------- add news message --------//
1004
1005 if( firmPtr->nation_recno == nation_array.player_recno )
1006 news_array.firm_captured(spy_place_para, true_nation_recno, 1); // 1 - the capturer is a spy
1007
1008 //-------- if this is an AI firm --------//
1009
1010 if( firmPtr->firm_ai )
1011 firmPtr->ai_firm_captured(true_nation_recno);
1012
1013 //----- change the firm's nation recno -----//
1014
1015 firmPtr->change_nation(true_nation_recno); // the firm change nation and the spies inside the firm will have their cloaked nation recno changed
1016 }
1017
1018 return 1;
1019 }
1020 //---------- End of function Spy::capture_firm ----------//
1021
1022
1023 //-------- Begin of function Spy::mobilize_spy ------//
1024 //
1025 // return: recno of the mobilized unit.
1026 //
mobilize_spy()1027 int Spy::mobilize_spy()
1028 {
1029 SpyArrayLock arrayLock;
1030
1031 switch( spy_place )
1032 {
1033 case SPY_TOWN:
1034 return mobilize_town_spy();
1035
1036 case SPY_FIRM:
1037 return mobilize_firm_spy();
1038
1039 case SPY_MOBILE:
1040 err_when( !unit_array[spy_place_para]->is_visible() );
1041 return spy_place_para;
1042
1043 default:
1044 return 0;
1045 }
1046 }
1047 //---------- End of function Spy::mobilize_spy --------//
1048
1049
1050 //-------- Begin of function Spy::mobilize_town_spy ------//
1051 //
1052 // [int] decPop - whether need to decrease the population of town when the spy is mobilized.
1053 // should set to no when it's calling from training a unit. (default: 1)
1054 //
1055 // return: recno of the mobilized unit.
1056 //
mobilize_town_spy(int decPop)1057 int Spy::mobilize_town_spy(int decPop)
1058 {
1059 SpyArrayLock arrayLock;
1060
1061 err_when( spy_place != SPY_TOWN );
1062
1063 if( spy_place != SPY_TOWN )
1064 return 0;
1065
1066 Town* townPtr = town_array[spy_place_para];
1067
1068 int unitRecno = townPtr->mobilize_town_people(race_id, decPop, 1); //1-mobilize spies
1069
1070 if( !unitRecno )
1071 return 0;
1072
1073 Unit* unitPtr = unit_array[unitRecno]; // set the spy vars of the mobilized unit
1074
1075 err_when( !unitPtr->is_visible() );
1076
1077 unitPtr->spy_recno = spy_recno;
1078 unitPtr->set_name(name_id); // set the name id. of this unit
1079
1080 set_place(SPY_MOBILE, unitRecno);
1081
1082 return unitRecno;
1083 }
1084 //---------- End of function Spy::mobilize_town_spy --------//
1085
1086
1087 //-------- Begin of function Spy::mobilize_firm_spy ------//
1088 //
1089 // return: <int> unit recno of the spy mobilized.
1090 //
mobilize_firm_spy()1091 int Spy::mobilize_firm_spy()
1092 {
1093 SpyArrayLock arrayLock;
1094
1095 err_when( spy_place != SPY_FIRM );
1096
1097 if( spy_place != SPY_FIRM )
1098 return 0;
1099
1100 Firm* firmPtr = firm_array[spy_place_para];
1101 int spyUnitRecno=0;
1102
1103 //---- check if the spy is the overseer of the firm -----//
1104
1105 if( firmPtr->overseer_recno )
1106 {
1107 Unit* unitPtr = unit_array[firmPtr->overseer_recno];
1108
1109 if( unitPtr->spy_recno == spy_recno )
1110 spyUnitRecno = firmPtr->mobilize_overseer();
1111 }
1112
1113 //---- check if the spy is one of the workers of the firm ----//
1114
1115 if( !spyUnitRecno )
1116 {
1117 int i;
1118 for( i=0 ; i<firmPtr->worker_count ; i++ )
1119 {
1120 if( firmPtr->worker_array[i].spy_recno == spy_recno )
1121 break;
1122 }
1123
1124 err_when( i==firmPtr->worker_count );
1125
1126 //---------- create a mobile unit ---------//
1127
1128 spyUnitRecno = firmPtr->mobilize_worker(i+1, COMMAND_AUTO); // note: mobilize_woker() will decrease Firm::player_spy_count
1129 }
1130
1131 return spyUnitRecno;
1132 }
1133 //---------- End of function Spy::mobilize_firm_spy --------//
1134
1135
1136 //-------- Begin of function Spy::think_become_king ------//
1137 //
1138 // If a nation has picked your spy to succeed to the died king,
1139 // you spy will either:
1140 //
1141 // >he captures the entire nation for you.
1142 // >he betrays you and rule his new empire.
1143 //
think_become_king()1144 void Spy::think_become_king()
1145 {
1146 SpyArrayLock arrayLock;
1147
1148 err_when( spy_place != SPY_MOBILE ); // it must be mobile
1149
1150 int hisNationPower = nation_array[cloaked_nation_recno]->overall_rating;
1151 int parentNationPower = nation_array[true_nation_recno]->overall_rating;
1152
1153 //--- if his nation is more power than the player's nation, the chance of handing his nation over to his parent nation will be low unless the loyalty is very high ---//
1154
1155 int acceptLoyalty = 90 + hisNationPower - parentNationPower;
1156
1157 if( spy_loyalty >= acceptLoyalty &&
1158 nation_array[cloaked_nation_recno]->is_ai() ) // never will a spy take over the player's nation
1159 {
1160 //------ hand his nation over to his parent nation ------//
1161
1162 nation_array[cloaked_nation_recno]->surrender(true_nation_recno);
1163 }
1164 else //--- betray his parent nation and rule the nation himself ---//
1165 {
1166 drop_spy_identity();
1167 }
1168 }
1169 //---------- End of function Spy::think_become_king --------//
1170
1171
1172 //-------- Begin of function Spy::cloaked_rank_id ------//
1173 //
1174 // Return the cloaked rank id. of this spy.
1175 //
cloaked_rank_id()1176 int Spy::cloaked_rank_id()
1177 {
1178 switch( spy_place )
1179 {
1180 case SPY_TOWN:
1181 return RANK_SOLDIER;
1182
1183 case SPY_FIRM:
1184 {
1185 Firm* firmPtr = firm_array[spy_place_para];
1186
1187 if( firmPtr->overseer_recno &&
1188 unit_array[firmPtr->overseer_recno]->spy_recno == spy_recno )
1189 {
1190 return RANK_GENERAL;
1191 }
1192 else
1193 {
1194 return RANK_SOLDIER;
1195 }
1196 }
1197
1198 case SPY_MOBILE:
1199 return unit_array[spy_place_para]->rank_id;
1200
1201 default:
1202 return RANK_SOLDIER;
1203 }
1204 }
1205 //---------- End of function Spy::cloaked_rank_id --------//
1206
1207
1208 //-------- Begin of function Spy::cloaked_skill_id ------//
1209 //
1210 // Return the cloaked skill id. of this spy.
1211 //
cloaked_skill_id()1212 int Spy::cloaked_skill_id()
1213 {
1214 switch( spy_place )
1215 {
1216 case SPY_TOWN:
1217 return 0;
1218
1219 case SPY_FIRM:
1220 return firm_array[spy_place_para]->firm_skill_id;
1221
1222 case SPY_MOBILE:
1223 return unit_array[spy_place_para]->skill.skill_id;
1224
1225 default:
1226 return 0;
1227 }
1228 }
1229 //---------- End of function Spy::cloaked_skill_id --------//
1230
1231
1232 //-------- Begin of function Spy::reward ------//
1233 //
1234 // The owner nation of the spy rewards him.
1235 //
reward(int remoteAction)1236 void Spy::reward(int remoteAction)
1237 {
1238 if( !remoteAction && remote.is_enable() )
1239 {
1240 // packet structure <spy recno>
1241 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_SPY_REWARD, sizeof(short));
1242 shortPtr[0] = spy_recno;
1243 return;
1244 }
1245
1246 change_loyalty(REWARD_LOYALTY_INCREASE);
1247
1248 nation_array[true_nation_recno]->add_expense(EXPENSE_REWARD_UNIT, (float)REWARD_COST);
1249 }
1250 //---------- End of function Spy::reward --------//
1251
1252
1253 //-------- Begin of function Spy::set_exposed ------//
1254 //
1255 // Enable the exposed_flag of the spy. The spy will get killed
1256 // should when he has been exposed.
1257 //
set_exposed(int remoteAction)1258 void Spy::set_exposed(int remoteAction)
1259 {
1260 // ##### begin Gilbert 26/9 #######//
1261 if( !remoteAction && remote.is_enable() )
1262 {
1263 // packet structure <spy recno>
1264 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_SPY_EXPOSED, sizeof(short));
1265 shortPtr[0] = spy_recno;
1266 return;
1267 }
1268 // ##### end Gilbert 26/9 #######//
1269 exposed_flag = 1;
1270 }
1271 //---------- End of function Spy::set_exposed --------//
1272
1273
1274 //-------- Begin of function Spy::assassinate ------//
1275 //
1276 // <int> targetUnitRecno - the recno of the unit to assassinate.
1277 // <int> remoteAction - remote action type.
1278 //
1279 // If this is a player's spy, the result of the assassination
1280 // will be set to Firm::assassinate_result.
1281 //
assassinate(int targetUnitRecno,int remoteAction)1282 int Spy::assassinate(int targetUnitRecno, int remoteAction)
1283 {
1284 if( !remoteAction && remote.is_enable() )
1285 {
1286 // packet structure <spy recno>
1287 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_SPY_ASSASSINATE, sizeof(short)*2);
1288 shortPtr[0] = spy_recno;
1289 shortPtr[1] = targetUnitRecno;
1290 return 0;
1291 }
1292
1293 //---------- validate first -----------//
1294
1295 if( spy_place != SPY_FIRM )
1296 return 0;
1297
1298 Unit* targetUnit = unit_array[targetUnitRecno];
1299
1300 if( targetUnit->unit_mode != UNIT_MODE_OVERSEE )
1301 return 0;
1302
1303 Firm* firmPtr = firm_array[ targetUnit->unit_mode_para ];
1304
1305 if( firmPtr->firm_recno != spy_place_para )
1306 return 0;
1307
1308 //---- get the attack and defense rating ----//
1309
1310 int attackRating, defenseRating, otherDefenderCount;
1311
1312 if( !get_assassinate_rating(targetUnitRecno, attackRating, defenseRating, otherDefenderCount) )
1313 return 0;
1314
1315 //-------------------------------------------//
1316
1317 int rc;
1318 int trueNationRecno = true_nation_recno; // need to save it first as the spy may be killed later
1319
1320 if( attackRating >= defenseRating )
1321 {
1322 //--- whether the spy will be get caught and killed in the mission ---//
1323
1324 int spyKillFlag = otherDefenderCount > 0 && attackRating - defenseRating < 80;
1325
1326 //--- if the unit assassinated is the player's unit ---//
1327
1328 if( targetUnit->nation_recno == nation_array.player_recno )
1329 news_array.unit_assassinated(targetUnit->sprite_recno, spyKillFlag);
1330
1331 firmPtr->kill_overseer();
1332
1333 //-----------------------------------------------------//
1334 // If there are other defenders in the firm and
1335 // the difference between the attack rating and defense rating
1336 // is small, then then spy will be caught and executed.
1337 //-----------------------------------------------------//
1338
1339 if( spyKillFlag )
1340 {
1341 get_killed(0); // 0 - don't display new message for the spy being killed
1342
1343 rc = ASSASSINATE_SUCCEED_KILLED;
1344 }
1345 else
1346 {
1347 rc = ASSASSINATE_SUCCEED_AT_LARGE;
1348 }
1349 }
1350 else //----- if the assassination fails --------//
1351 {
1352 //-- if the spy is attempting to assassinate the player's general or king --//
1353
1354 // don't display the below news message as the killing of the spy will already be displayed in news_array.spy_killed()
1355
1356 // if( targetUnit->nation_recno == nation_array.player_recno )
1357 // news_array.assassinator_caught(spy_recno, targetUnit->rank_id);
1358
1359 get_killed(0); // 0 - don't display new message for the spy being killed
1360
1361 rc = ASSASSINATE_FAIL;
1362 }
1363
1364 //--- if this firm is the selected firm and the spy is the player's spy ---//
1365
1366 if( trueNationRecno == nation_array.player_recno &&
1367 firmPtr->firm_recno == firm_array.selected_recno )
1368 {
1369 firmPtr->assassinate_result = rc;
1370 firmPtr->firm_menu_mode = FIRM_MENU_ASSASSINATE_RESULT;
1371 info.disp();
1372 }
1373
1374 return rc;
1375 }
1376 //---------- End of function Spy::assassinate --------//
1377
1378
1379 //-------- Begin of function Spy::get_assassinate_rating ------//
1380 //
get_assassinate_rating(int targetUnitRecno,int & attackRating,int & defenseRating,int & otherDefenderCount)1381 int Spy::get_assassinate_rating(int targetUnitRecno, int& attackRating, int& defenseRating, int& otherDefenderCount)
1382 {
1383 //---------- validate first -----------//
1384
1385 if( spy_place != SPY_FIRM )
1386 return 0;
1387
1388 Unit* targetUnit = unit_array[targetUnitRecno];
1389
1390 if( targetUnit->unit_mode != UNIT_MODE_OVERSEE )
1391 return 0;
1392
1393 Firm* firmPtr = firm_array[ targetUnit->unit_mode_para ];
1394
1395 if( firmPtr->firm_recno != spy_place_para )
1396 return 0;
1397
1398 //------ get the hit points of the spy ----//
1399
1400 int spyHitPoints;
1401
1402 int i;
1403 for( i=0 ; i<firmPtr->worker_count ; i++ )
1404 {
1405 if( firmPtr->worker_array[i].spy_recno == spy_recno )
1406 {
1407 spyHitPoints = firmPtr->worker_array[i].hit_points;
1408 break;
1409 }
1410 }
1411
1412 err_when( i==firmPtr->worker_count );
1413
1414 //------ calculate success chance ------//
1415
1416 attackRating = spy_skill + spyHitPoints/2;
1417 defenseRating = (int) targetUnit->hit_points/2;
1418 otherDefenderCount=0;
1419
1420 if( targetUnit->spy_recno )
1421 defenseRating += spy_array[targetUnit->spy_recno]->spy_skill;
1422
1423 if( targetUnit->rank_id == RANK_KING )
1424 defenseRating += 50;
1425
1426 for( i=0 ; i<firmPtr->worker_count ; i++ )
1427 {
1428 int spyRecno = firmPtr->worker_array[i].spy_recno;
1429
1430 //------ if this worker is a spy ------//
1431
1432 if( spyRecno )
1433 {
1434 Spy* spyPtr = spy_array[spyRecno];
1435
1436 if( spyPtr->true_nation_recno == true_nation_recno ) // our spy
1437 {
1438 attackRating += spyPtr->spy_skill/4;
1439 }
1440 else if( spyPtr->true_nation_recno == firmPtr->nation_recno ) // enemy spy
1441 {
1442 defenseRating += spyPtr->spy_skill/2;
1443 otherDefenderCount++;
1444 }
1445 }
1446 else //----- if this worker is not a spy ------//
1447 {
1448 defenseRating += 4 + firmPtr->worker_array[i].hit_points/30;
1449 otherDefenderCount++;
1450 }
1451 }
1452
1453 //-------- if the assassination succeeds -------//
1454
1455 defenseRating += 30 + misc.random(30);
1456
1457 return 1;
1458 }
1459 //---------- End of function Spy::get_assassinate_rating --------//
1460