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