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 : OFIRMIF3.CPP
22 //Description : Firm interface functions - part 3
23
24 #include <OVGA.h>
25 #include <vga_util.h>
26 #include <OFONT.h>
27 #include <OINFO.h>
28 #include <OSYS.h>
29 #include <OBUTT3D.h>
30 #include <OMOUSE.h>
31 #include <ONEWS.h>
32 #include <OUNIT.h>
33 #include <ORACERES.h>
34 #include <ONATION.h>
35 #include <OSPY.h>
36 #include <OFIRM.h>
37 #include <OREMOTE.h>
38 #include "gettext.h"
39
40 //---------- Define constant ------------//
41
42 #define BRIBE_OPTION_HEIGHT 19
43
44 //-------- Define bribe amounts ---------//
45
46 #define BRIBE_AMOUNT_COUNT 6
47 #define MAX_BRIBE_AMOUNT 4000
48
49 static short bribe_amount_array[] = { 500, 1000, 1500, 2000, 3000, 4000 };
50
51 //-------- Define static vars ---------//
52
53 static Button3D button_cancel;
54
55 //------ declare static functions -------//
56
57 static void disp_bribe_button(int y, int bribeAmount, int buttonUp);
58
59
60 //--------- Begin of function Firm::disp_bribe_menu ---------//
61 //
disp_bribe_menu(int refreshFlag)62 void Firm::disp_bribe_menu(int refreshFlag)
63 {
64 //---- if the briber or bribe target is no longer valid -----//
65
66 if( bribe_result == BRIBE_NONE )
67 {
68 if( !validate_cur_bribe() )
69 {
70 firm_menu_mode = FIRM_MENU_MAIN;
71 bribe_result = BRIBE_NONE;
72 info.disp();
73 return;
74 }
75 }
76
77 //------------------------------------//
78
79 if( refreshFlag != INFO_REPAINT )
80 return;
81
82 //------ display the bribe menu ------//
83
84 if( bribe_result == BRIBE_NONE )
85 {
86 int y=INFO_Y1;
87
88 font_san.d3_put( INFO_X1, y, INFO_X2, y+19, _("Bribe") );
89 y+=22;
90
91 disp_bribe_unit( y );
92 y+=49;
93
94 for( int i=0 ; i<BRIBE_AMOUNT_COUNT ; i++ )
95 {
96 disp_bribe_button( y, bribe_amount_array[i], 1);
97
98 err_when( bribe_amount_array[i] > MAX_BRIBE_AMOUNT );
99
100 y += BRIBE_OPTION_HEIGHT+2;
101 }
102
103 disp_bribe_button( y, 0, 1);
104 }
105
106 //------ display the bribe result -----//
107
108 else
109 {
110 int x=INFO_X1+4, y=INFO_Y1+4, y2=y+font_san.height()-1;
111
112 if( bribe_result == BRIBE_SUCCEED )
113 {
114 vga_util.d3_panel_up( INFO_X1, INFO_Y1, INFO_X2, INFO_Y1+24 );
115
116 font_san.center_put( INFO_X1, y, INFO_X2, y2, _("Bribe Succeeded.") );
117 }
118 else
119 {
120 vga_util.d3_panel_up( INFO_X1, INFO_Y1, INFO_X2, INFO_Y1+62 );
121
122 font_san.center_put( INFO_X1, y , INFO_X2, y2, _("Bribe Failed.") );
123 font_san.center_put( INFO_X1, y+=18, INFO_X2, y2+=18, _("Your Spy Was Caught") );
124 font_san.center_put( INFO_X1, y+=18, INFO_X2, y2+=18, _("And Executed.") );
125 }
126
127 y+=26;
128 button_cancel.paint( INFO_X1, y, 'A', "CONTINUE" );
129 }
130 }
131 //----------- End of function Firm::disp_bribe_menu -----------//
132
133
134 //--------- Begin of function Firm::detect_bribe_menu ---------//
135 //
detect_bribe_menu()136 void Firm::detect_bribe_menu()
137 {
138 //----- if it is display the bribe result right now -----//
139
140 if( bribe_result != BRIBE_NONE )
141 {
142 if( button_cancel.detect() )
143 {
144 firm_menu_mode = FIRM_MENU_MAIN;
145 bribe_result = BRIBE_NONE;
146 info.disp();
147 }
148
149 return;
150 }
151
152 //-------------------------------------------//
153
154 int i, y=INFO_Y1+22+49;
155
156 for( i=0 ; i<BRIBE_AMOUNT_COUNT ; i++ )
157 {
158 if( mouse.single_click(INFO_X1, y, INFO_X2, y+BRIBE_OPTION_HEIGHT-1) )
159 {
160 disp_bribe_button( y, bribe_amount_array[i], 0); // 0-display pressed button
161
162 while( mouse.left_press )
163 {
164 sys.yield();
165 vga.flip();
166 mouse.get_event();
167 }
168
169 //--------- bribe now ---------//
170
171 // ####### begin Gilbert 13/10 #######//
172 if( !remote.is_enable() )
173 {
174 spy_bribe(bribe_amount_array[i], action_spy_recno, selected_worker_id);
175 action_spy_recno = 0;
176 }
177 else
178 {
179 // packet structure <firm recno> <spy recno> <bribe target : worker (0=overseer)> <amount>
180 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_BRIBE, 4*sizeof(short));
181 *shortPtr = firm_recno;
182 shortPtr[1] = action_spy_recno;
183 shortPtr[2] = selected_worker_id;
184 shortPtr[3] = bribe_amount_array[i];
185 }
186 // ####### end Gilbert 13/10 #######//
187 }
188
189 y += BRIBE_OPTION_HEIGHT+2;
190 }
191
192 //------ detect the cancel button --------//
193
194 if( mouse.single_click(INFO_X1, y, INFO_X2, y+BRIBE_OPTION_HEIGHT-1) )
195 {
196 disp_bribe_button( y, 0, 0); // 0-display pressed button
197
198 while( mouse.left_press )
199 {
200 sys.yield();
201 vga.flip();
202 mouse.get_event();
203 }
204
205 firm_menu_mode = FIRM_MENU_MAIN;
206 info.disp();
207 }
208 }
209 //----------- End of function Firm::detect_bribe_menu -----------//
210
211
212 //--------- Begin of function Firm::validate_cur_bribe ---------//
213 //
214 // Whether the current bribe action is still valid.
215 //
validate_cur_bribe()216 int Firm::validate_cur_bribe()
217 {
218 if( spy_array.is_deleted(action_spy_recno) ||
219 spy_array[action_spy_recno]->true_nation_recno != nation_array.player_recno )
220 {
221 return 0;
222 }
223
224 return can_spy_bribe( selected_worker_id, spy_array[action_spy_recno]->true_nation_recno );
225 }
226 //----------- End of function Firm::validate_cur_bribe -----------//
227
228
229 //-------- Begin of static function disp_bribe_button --------//
230 //
disp_bribe_button(int y,int bribeAmount,int buttonUp)231 static void disp_bribe_button(int y, int bribeAmount, int buttonUp)
232 {
233 if( buttonUp )
234 vga_util.d3_panel_up( INFO_X1, y, INFO_X2, y+BRIBE_OPTION_HEIGHT-1 );
235 else
236 vga_util.d3_panel_down( INFO_X1, y, INFO_X2, y+BRIBE_OPTION_HEIGHT-1 );
237
238 //--------- if display cancel button ---------//
239
240 if( bribeAmount==0 )
241 font_san.center_put( INFO_X1, y, INFO_X2, y+BRIBE_OPTION_HEIGHT-1, _("Cancel") );
242 else
243 {
244 String str;
245
246 // TRANSLATORS: Offer <Amount>
247 snprintf( str, MAX_STR_LEN+1, _("Offer %s"), misc.format(bribeAmount,2) );
248
249 font_san.center_put( INFO_X1, y, INFO_X2, y+BRIBE_OPTION_HEIGHT-1, str );
250 }
251 }
252 //--------- End of static function disp_bribe_button ---------//
253
254
255 //--------- Begin of function Firm::can_spy_bribe ---------//
256 //
257 // <int> bribeWorkerId - worker id. in this firm to bribe
258 // 0 - if bribe an overseer.
259 //
260 // <int> briberNationRecno - the nation recno of the briber.
261 //
can_spy_bribe(int bribeWorkerId,int briberNationRecno)262 int Firm::can_spy_bribe(int bribeWorkerId, int briberNationRecno)
263 {
264 int canBribe=0;
265 int spyRecno;
266
267 err_when( bribeWorkerId < 0 || bribeWorkerId > MAX_WORKER );
268
269 if( bribeWorkerId ) // the overseer is selected
270 spyRecno = worker_array[bribeWorkerId-1].spy_recno;
271 else
272 spyRecno = unit_array[overseer_recno]->spy_recno;
273
274 if( spyRecno )
275 {
276 canBribe = spy_array[spyRecno]->true_nation_recno != briberNationRecno; // only when the unit is not yet a spy of the player. Still display the bribe button when it's a spy of another nation
277 }
278 else
279 {
280 if( bribeWorkerId )
281 canBribe = worker_array[bribeWorkerId-1].race_id>0; // cannot bribe if it's a weapon
282 else
283 canBribe = unit_array[overseer_recno]->rank_id != RANK_KING; // cannot bribe a king
284 }
285
286 return canBribe;
287 }
288 //----------- End of function Firm::can_spy_bribe -----------//
289
290
291 //--------- Begin of function Firm::spy_bribe ---------//
292 //
293 // The money the spy offers to bribe the unit.
294 //
295 // <int> bribeAmount - the amount offered
296 // <short> birberSpyRecno - spy recno of the briber
297 // <short> workerId - if 0, then bribe the overseer,
298 // if >0, then bribe a worker.
299 //
300 // return: <int> >0 - bribing succeeded, return the spy recno of the bribed unit (as it has been turned into a spy)
301 // 0 - bribing failed
302 //
spy_bribe(int bribeAmount,short briberSpyRecno,short workerId)303 int Firm::spy_bribe(int bribeAmount, short briberSpyRecno, short workerId)
304 {
305 if( !can_spy_bribe(workerId, spy_array[briberSpyRecno]->true_nation_recno) ) // this can happen in multiplayer as there is a one frame delay when the message is sent and when it is processed
306 return 0;
307
308 //---------------------------------------//
309
310 int succeedChance = spy_bribe_succeed_chance(bribeAmount, briberSpyRecno, workerId);
311
312
313 nation_array[spy_array[briberSpyRecno]->true_nation_recno]->add_expense( EXPENSE_BRIBE, (float) bribeAmount, 0 );
314
315 //------ if the bribe succeeds ------//
316
317 if( succeedChance > 0 && misc.random(100) < succeedChance )
318 {
319 int spyRecno = spy_array.add_spy(); // add a new Spy record
320
321 Spy* spyPtr = spy_array[briberSpyRecno];
322 Spy* newSpy = spy_array[spyRecno];
323
324 newSpy->spy_skill = 10;
325 newSpy->action_mode = SPY_IDLE;
326 newSpy->spy_loyalty = MIN( 100, MAX(30,succeedChance) ); // within the 30-100 range
327
328 newSpy->true_nation_recno = spyPtr->true_nation_recno;
329 newSpy->cloaked_nation_recno = spyPtr->cloaked_nation_recno;
330
331 if( workerId )
332 {
333 Worker* workerPtr = worker_array+workerId-1;
334
335 workerPtr->spy_recno = spyRecno;
336 newSpy->race_id = workerPtr->race_id;
337 newSpy->name_id = workerPtr->name_id;
338
339 err_when( newSpy->race_id < 1 || newSpy->race_id > MAX_RACE );
340
341 if( !newSpy->name_id ) // if this worker does not have a name, give him one now as a spy must reserve a name (see below on use_name_id() for reasons)
342 newSpy->name_id = race_res[newSpy->race_id]->get_new_name_id();
343 }
344 else if( overseer_recno )
345 {
346 Unit* unitPtr = unit_array[overseer_recno];
347
348 unitPtr->spy_recno = spyRecno;
349 newSpy->race_id = unitPtr->race_id;
350 newSpy->name_id = unitPtr->name_id;
351
352 err_when( newSpy->race_id < 1 || newSpy->race_id > MAX_RACE );
353 }
354 else
355 err_here();
356
357 newSpy->set_place( SPY_FIRM, firm_recno );
358
359 //-- Spy always registers its name twice as his name will be freed up in deinit(). Keep an additional right because when a spy is assigned to a town, the normal program will free up the name id., so we have to keep an additional copy
360
361 race_res[newSpy->race_id]->use_name_id(newSpy->name_id);
362
363 bribe_result = BRIBE_SUCCEED;
364
365 if( firm_recno == firm_array.selected_recno )
366 info.disp();
367
368 return newSpy->spy_recno;
369 }
370 else //------- if the bribe fails --------//
371 {
372 spy_array[briberSpyRecno]->get_killed(0); // the spy gets killed when the action failed.
373 // 0 - don't display new message for the spy being killed, so we already display the msg on the interface
374 bribe_result = BRIBE_FAIL;
375
376 if( firm_recno == firm_array.selected_recno )
377 info.disp();
378
379 return 0;
380 }
381 }
382 //----------- End of function Firm::spy_bribe -----------//
383
384
385 //--------- Begin of function Firm::spy_birbe_succeed_chance ---------//
386 //
387 // The money the spy offers to bribe the unit.
388 //
389 // <int> bribeAmount - the amount offered
390 // <short> birberSpyRecno - spy recno of the briber
391 // <short> workerId - if 0, then bribe the overseer,
392 // if >0, then bribe a worker.
393 //
394 // return: <int> 1 - bribing succeeded
395 // 0 - bribing failed
396 //
spy_bribe_succeed_chance(int bribeAmount,short briberSpyRecno,short workerId)397 int Firm::spy_bribe_succeed_chance(int bribeAmount, short briberSpyRecno, short workerId)
398 {
399 Spy* spyPtr = spy_array[briberSpyRecno];
400
401 err_when( spyPtr->spy_place != SPY_FIRM );
402 err_when( spyPtr->spy_place_para != firm_recno );
403
404 //---- if the bribing target is a worker ----//
405
406 int unitLoyalty, unitRaceId, targetSpyRecno, unitCommandPower;
407
408 if( workerId )
409 {
410 Worker* workerPtr = worker_array+workerId-1;
411
412 unitLoyalty = workerPtr->loyalty();
413 unitRaceId = workerPtr->race_id;
414 unitCommandPower = 0;
415 targetSpyRecno = workerPtr->spy_recno;
416 }
417 else if( overseer_recno )
418 {
419 Unit* unitPtr = unit_array[overseer_recno];
420
421 unitLoyalty = unitPtr->loyalty;
422 unitRaceId = unitPtr->race_id;
423 unitCommandPower = unitPtr->commander_power();
424 targetSpyRecno = unitPtr->spy_recno;
425 }
426 else
427 err_here();
428
429 err_when( unitRaceId < 1 || unitRaceId > MAX_RACE );
430
431 //---- determine whether the bribe will be successful ----//
432
433 int succeedChance;
434
435 if( targetSpyRecno ) // if the bribe target is also a spy
436 {
437 err_when( spy_array[targetSpyRecno]->true_nation_recno == spyPtr->true_nation_recno ); // the player shouldn't be able to bribe units of his own
438
439 succeedChance = 0;
440 }
441 else
442 {
443 succeedChance = spyPtr->spy_skill - unitLoyalty - unitCommandPower
444 + (int) nation_array[spyPtr->true_nation_recno]->reputation
445 + 200 * bribeAmount / MAX_BRIBE_AMOUNT;
446
447 //-- the chance is higher if the spy or the spy's king is racially homongenous to the bribe target,
448
449 int spyKingRaceId = nation_array[ spyPtr->true_nation_recno ]->race_id;
450
451 succeedChance += race_res.is_same_race(spyPtr->race_id, unitRaceId) * 10 +
452 race_res.is_same_race(spyKingRaceId, unitRaceId) * 10;
453
454 if( unitLoyalty > 60 ) // harder for bribe units with over 60 loyalty
455 succeedChance -= (unitLoyalty-60);
456
457 if( unitLoyalty > 70 ) // harder for bribe units with over 70 loyalty
458 succeedChance -= (unitLoyalty-70);
459
460 if( unitLoyalty > 80 ) // harder for bribe units with over 80 loyalty
461 succeedChance -= (unitLoyalty-80);
462
463 if( unitLoyalty > 90 ) // harder for bribe units with over 90 loyalty
464 succeedChance -= (unitLoyalty-90);
465
466 if( unitLoyalty == 100 )
467 succeedChance = 0;
468 }
469
470 return succeedChance;
471 }
472 //----------- End of function Firm::spy_birbe_succeed_chance -----------//
473
474
475 //--------- Begin of function Firm::disp_bribe_unit ---------//
476 //
disp_bribe_unit(int dispY1)477 void Firm::disp_bribe_unit(int dispY1)
478 {
479 //---------------- paint the panel -----------------//
480
481 vga_util.d3_panel_up( INFO_X1, dispY1, INFO_X2, dispY1+46);
482
483 //------- get the info of the bribe target ---------//
484
485 // ####### begin Gilbert 8/8 ########//
486 int raceId, unitLoyalty, unitId, rankId;
487 const char* unitName;
488
489 if( selected_worker_id )
490 {
491 Worker* workerPtr = worker_array+selected_worker_id-1;
492
493 raceId = workerPtr->race_id;
494 unitId = workerPtr->unit_id;
495 unitLoyalty = workerPtr->loyalty();
496 unitName = race_res[raceId]->get_name(workerPtr->name_id);
497 rankId = workerPtr->rank_id;
498 }
499 else if( overseer_recno )
500 {
501 Unit* unitPtr = unit_array[overseer_recno];
502
503 raceId = unitPtr->race_id;
504 unitId = unitPtr->unit_id;
505 unitLoyalty = unitPtr->loyalty;
506 unitName = unitPtr->unit_name();
507 rankId = unitPtr->rank_id;
508 }
509 else
510 err_here();
511
512 //--------- display info of the bribe target ---------//
513
514 int x=INFO_X1+6, y=dispY1+4;
515
516 vga_front.put_bitmap(x, y, unit_res[unitId]->get_large_icon_ptr(rankId) );
517 font_san.put( x+UNIT_LARGE_ICON_WIDTH+6, y+4, unitName );
518
519 //------- display skill and productivity ---------//
520
521 String str;
522
523 str = _("Loyalty");
524 str += ": ";
525 str += unitLoyalty;
526
527 font_san.disp( x+UNIT_LARGE_ICON_WIDTH+6, y+20, str, INFO_X2-10 );
528 }
529 //----------- End of function Firm::disp_bribe_unit -----------//
530
531
532 //--------- Begin of function Firm::disp_assassinate_result ---------//
533 //
disp_assassinate_result(int refreshFlag)534 void Firm::disp_assassinate_result(int refreshFlag)
535 {
536 if( refreshFlag != INFO_REPAINT )
537 return;
538
539 int x=INFO_X1+4, y=INFO_Y1+4, y2=y+font_san.height()-1;
540
541 if( assassinate_result == ASSASSINATE_SUCCEED_AT_LARGE )
542 {
543 vga_util.d3_panel_up( INFO_X1, INFO_Y1, INFO_X2, INFO_Y1+43 );
544
545 font_san.center_put( INFO_X1, y, INFO_X2, y2, _("Assassination Succeeded.") );
546 font_san.center_put( INFO_X1, y+=18, INFO_X2, y2+=18, _("Your Spy Escaped.") );
547 }
548 else if( assassinate_result == ASSASSINATE_SUCCEED_KILLED )
549 {
550 #ifdef GERMAN
551 vga_util.d3_panel_up( INFO_X1, INFO_Y1, INFO_X2, INFO_Y1+80 );
552
553 font_san.center_put( INFO_X1, y, INFO_X2, y2, "Assassination Succeeded." );
554 font_san.center_put( INFO_X1, y+=18, INFO_X2, y2+=18, "Your Spy" ); // German text is longer
555 font_san.center_put( INFO_X1, y+=18, INFO_X2, y2+=18, "Was Caught" );
556 font_san.center_put( INFO_X1, y+=18, INFO_X2, y2+=18, "And Executed." );
557 #else
558 vga_util.d3_panel_up( INFO_X1, INFO_Y1, INFO_X2, INFO_Y1+62 );
559
560 font_san.center_put( INFO_X1, y, INFO_X2, y2, _("Assassination Succeeded.") );
561 // TRANSLATORS: Part of "Your Spy Was Caught And Executed."
562 font_san.center_put( INFO_X1, y+=18, INFO_X2, y2+=18, _("Your Spy Was Caught") );
563 // TRANSLATORS: Part of "Your Spy Was Caught And Executed."
564 font_san.center_put( INFO_X1, y+=18, INFO_X2, y2+=18, _("And Executed.") );
565 #endif
566 }
567 else
568 {
569 #ifdef GERMAN
570 vga_util.d3_panel_up( INFO_X1, INFO_Y1, INFO_X2, INFO_Y1+80 );
571
572 font_san.center_put( INFO_X1, y , INFO_X2, y2, "Assassination Failed." );
573 font_san.center_put( INFO_X1, y+=18, INFO_X2, y2+=18, "Your Spy" );
574 font_san.center_put( INFO_X1, y+=18, INFO_X2, y2+=18, "Was Caught" );
575 font_san.center_put( INFO_X1, y+=18, INFO_X2, y2+=18, "And Executed." );
576 #else
577 vga_util.d3_panel_up( INFO_X1, INFO_Y1, INFO_X2, INFO_Y1+62 );
578
579 font_san.center_put( INFO_X1, y , INFO_X2, y2, _("Assassination Failed.") );
580 // TRANSLATORS: Part of "Your Spy Was Caught And Executed."
581 font_san.center_put( INFO_X1, y+=18, INFO_X2, y2+=18, _("Your Spy Was Caught") );
582 // TRANSLATORS: Part of "Your Spy Was Caught And Executed."
583 font_san.center_put( INFO_X1, y+=18, INFO_X2, y2+=18, _("And Executed.") );
584 #endif
585 }
586
587 y+=26;
588 button_cancel.paint( INFO_X1, y, 'A', "CONTINUE" );
589 }
590 //----------- End of function Firm::disp_assassinate_result -----------//
591
592
593 //--------- Begin of function Firm::detect_assassinate_result ---------//
594 //
detect_assassinate_result()595 void Firm::detect_assassinate_result()
596 {
597 //----- if it is display the bribe result right now -----//
598
599 if( button_cancel.detect() )
600 {
601 firm_menu_mode = FIRM_MENU_MAIN;
602 assassinate_result = 0;
603 info.disp();
604 }
605 }
606 //----------- End of function Firm::detect_assassinate_result -----------//
607
608