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    : OF_BASE.CPP
22 //Description : Firm Base
23 
24 #include <OINFO.h>
25 #include <OVGA.h>
26 #include <vga_util.h>
27 #include <ODATE.h>
28 #include <OMOUSE.h>
29 #include <OIMGRES.h>
30 #include <OHELP.h>
31 #include <OSTR.h>
32 #include <OFONT.h>
33 #include <OCONFIG.h>
34 #include <OUNIT.h>
35 #include <OSPY.h>
36 #include <OGAME.h>
37 #include <OBUTT3D.h>
38 #include <ONATION.h>
39 #include <ORACERES.h>
40 #include <OWALLRES.h>
41 #include <OGODRES.h>
42 #include <OPOWER.h>
43 #include <OTOWN.h>
44 #include <OWORLD.h>
45 #include <OF_BASE.h>
46 #include <OREMOTE.h>
47 #include <OSERES.h>
48 #include <OSE.h>
49 #include "gettext.h"
50 
51 //----------- Define static vars -------------//
52 
53 static Button3D   button_invoke, button_reward;
54 static Button3D	button_vacate_firm;
55 
56 //--------- Begin of function FirmBase::FirmBase ---------//
57 //
FirmBase()58 FirmBase::FirmBase()
59 {
60 	firm_skill_id = SKILL_PRAYING;
61 }
62 //----------- End of function FirmBase::FirmBase -----------//
63 
64 
65 //--------- Begin of function FirmBase::~FirmBase ---------//
66 //
~FirmBase()67 FirmBase::~FirmBase()
68 {
69 	err_when( race_id<1 || race_id>MAX_RACE );
70 
71 	nation_array[nation_recno]->base_count_array[race_id-1]--;
72 
73 	err_when( nation_array[nation_recno]->base_count_array[race_id-1] < 0 );
74 }
75 //----------- End of function FirmBase::~FirmBase -----------//
76 
77 
78 //--------- Begin of function FirmBase::init_derived ---------//
79 //
init_derived()80 void FirmBase::init_derived()
81 {
82 	pray_points = (float) 0;
83 
84 	//------ increase NationBase::base_count_array[] -----//
85 
86 	err_when( race_id<1 || race_id>MAX_RACE );
87 
88 	nation_array[nation_recno]->base_count_array[race_id-1]++;
89 
90 	//---------- set the god id. ----------//
91 
92 	god_id = 0 ;
93 	god_unit_recno = 0;
94 
95 	for( int i=1 ; i<=god_res.god_count ; i++ )
96 	{
97 		if( god_res[i]->race_id == race_id &&
98 			 god_res[i]->is_nation_know(nation_recno) )
99 		{
100 			god_id = i;
101 			break;
102 		}
103 	}
104 
105 	err_when( god_id==0 );
106 }
107 //----------- End of function FirmBase::init_derived -----------//
108 
109 
110 //--------- Begin of function FirmBase::assign_unit ---------//
111 //
assign_unit(int unitRecno)112 void FirmBase::assign_unit(int unitRecno)
113 {
114 	Unit* unitPtr = unit_array[unitRecno];
115 
116 	//### begin alex 18/9 ###//
117 	/*//------ only assign units of the right race ------//
118 
119 	if( unitPtr->race_id != race_id )
120 		return;*/
121 	//#### end alex 18/9 ####//
122 
123 	//------- if this is a construction worker -------//
124 
125 	if( unitPtr->skill.skill_id == SKILL_CONSTRUCTION )
126 	{
127 		set_builder(unitRecno);
128 		return;
129 	}
130 
131 	//### begin alex 18/9 ###//
132 	//------ only assign units of the right race ------//
133 
134 	if( unitPtr->race_id != race_id )
135 		return;
136 	//#### end alex 18/9 ####//
137 
138 	//-------- assign the unit ----------//
139 
140 	int rankId = unit_array[unitRecno]->rank_id;
141 
142 	if( rankId == RANK_GENERAL || rankId==RANK_KING )
143 	{
144 		assign_overseer(unitRecno);
145 	}
146 	else
147 	{
148 		assign_worker(unitRecno);
149 	}
150 }
151 //----------- End of function FirmBase::assign_unit -----------//
152 
153 
154 //--------- Begin of function FirmBase::assign_overseer ---------//
155 //
assign_overseer(int overseerRecno)156 void FirmBase::assign_overseer(int overseerRecno)
157 {
158 	//---- reset the team member count of the general ----//
159 
160 	if( overseerRecno )
161 	{
162 		Unit* unitPtr = unit_array[overseerRecno];
163 
164 		err_when( !unitPtr->race_id );
165 		err_when( unitPtr->rank_id != RANK_GENERAL && unitPtr->rank_id != RANK_KING );
166 		err_when( !unitPtr->team_info );
167 
168 		unitPtr->team_info->member_count = 0;
169 	}
170 
171 	//----- assign the overseer now -------//
172 
173 	Firm::assign_overseer(overseerRecno);
174 }
175 //----------- End of function FirmBase::assign_overseer -----------//
176 
177 
178 //--------- Begin of function FirmBase::put_info ---------//
179 //
put_info(int refreshFlag)180 void FirmBase::put_info(int refreshFlag)
181 {
182 	disp_basic_info(INFO_Y1, refreshFlag);
183 
184 	if( !should_show_info() )
185 		return;
186 
187 	disp_base_info(INFO_Y1+54, refreshFlag);
188 	disp_worker_list(INFO_Y1+104, refreshFlag);
189 	disp_worker_info(INFO_Y1+168, refreshFlag);
190 	disp_god_info(INFO_Y1+226, refreshFlag);
191 
192 	//------ display button -------//
193 
194 	int x, y=INFO_Y1+279;
195 
196 	if( own_firm() )
197 	{
198 		if( refreshFlag==INFO_REPAINT )
199 		{
200 			button_invoke.paint( INFO_X1, y, 'A', "INVOKE" );
201 			button_reward.paint( INFO_X1 + BUTTON_ACTION_WIDTH, y, 'A', "REWARDSP" );
202 			button_vacate_firm.paint(INFO_X1 + BUTTON_ACTION_WIDTH * 2, y, 'A', "RECRUIT");
203 			button_vacate_firm.set_help_code("MOBILIZE");
204 		}
205 
206 		if( can_invoke() )
207 			button_invoke.enable();
208 		else
209 			button_invoke.disable();
210 
211 		if( nation_array[nation_recno]->cash >= REWARD_COST &&
212 			 ( (overseer_recno && unit_array[overseer_recno]->rank_id != RANK_KING)
213 			  || selected_worker_id ) )
214 		{
215 			button_reward.enable();
216 		}
217 		else
218 		{
219 			button_reward.disable();
220 		}
221 
222 		if( have_own_workers() )
223 			button_vacate_firm.enable();
224 		else
225 			button_vacate_firm.disable();
226 
227 		x=INFO_X1+BUTTON_ACTION_WIDTH * 3;
228 	}
229 	else
230 		x=INFO_X1;
231 
232 	disp_spy_button(x, y, refreshFlag);
233 }
234 //----------- End of function FirmBase::put_info -----------//
235 
236 
237 //--------- Begin of function FirmBase::detect_info ---------//
238 //
detect_info()239 int FirmBase::detect_info()
240 {
241 	if( detect_basic_info() )
242 		return 1;
243 
244 	if( !should_show_info() )
245 		return 0;
246 
247 	//------ detect the overseer button -----//
248 
249 	int rc = mouse.any_click(INFO_X1+6, INFO_Y1+58, INFO_X1+5+UNIT_LARGE_ICON_WIDTH, INFO_Y1+57+UNIT_LARGE_ICON_HEIGHT, LEFT_BUTTON) ? 1
250 		: mouse.any_click(INFO_X1+6, INFO_Y1+58, INFO_X1+5+UNIT_LARGE_ICON_WIDTH, INFO_Y1+57+UNIT_LARGE_ICON_HEIGHT, RIGHT_BUTTON) ? 2 : 0;
251 
252 	if( rc==1 )		// display this overseer's info
253 	{
254 		selected_worker_id = 0;
255 		disp_base_info(INFO_Y1+54, INFO_UPDATE);
256 		disp_worker_list(INFO_Y1+104, INFO_UPDATE);
257 		disp_worker_info(INFO_Y1+168, INFO_UPDATE);
258 		return 1;
259 	}
260 
261 	//--------- detect soldier info ---------//
262 
263 	if( detect_worker_list() )
264 	{
265 		disp_base_info(INFO_Y1+54, INFO_UPDATE);
266 		disp_worker_list(INFO_Y1+104, INFO_UPDATE);
267 		disp_worker_info(INFO_Y1+168, INFO_UPDATE);
268 		return 1;
269 	}
270 
271 	//---------- detect spy button ----------//
272 
273 	if( detect_spy_button() )
274 		return 1;
275 
276 	if( !own_firm() )
277 		return 0;
278 
279 	//------ detect the overseer button -----//
280 
281 	if( rc==2 )
282 	{
283 		if(remote.is_enable())
284 		{
285 			// packet structure : <firm recno>
286 			short *shortPtr=(short *)remote.new_send_queue_msg(MSG_FIRM_MOBL_OVERSEER, sizeof(short));
287 			shortPtr[0] = firm_recno;
288 		}
289 		else
290 		{
291 			assign_overseer(0);		// the overseer quits the camp
292 		}
293 		return 1;
294 	}
295 
296 	//----------- detect invoke -----------//
297 
298 	if( button_invoke.detect() )
299 	{
300 		if(remote.is_enable())
301 		{
302 			// ##### begin Gilbert 14/10 #######//
303 			// packet structure : <firm recno>
304 			short *shortPtr=(short *)remote.new_send_queue_msg(MSG_F_BASE_INVOKE_GOD, sizeof(short));
305 			shortPtr[0] = firm_recno;
306 			// ##### end Gilbert 14/10 #######//
307 		}
308 		else
309 		{
310 			invoke_god();
311 		}
312 		return 1;
313 	}
314 
315 	//----------- detect reward -----------//
316 
317 	if( button_reward.detect() )
318 	{
319 		reward(selected_worker_id, COMMAND_PLAYER);
320 		// ##### begin Gilbert 26/9 ########//
321 		se_ctrl.immediate_sound("TURN_ON");
322 		// ##### end Gilbert 26/9 ########//
323 		return 1;
324 	}
325 
326 	//-------- detect mobilize button ----------//
327 
328 	if( button_vacate_firm.detect() )
329 	{
330 		mobilize_all_workers(COMMAND_PLAYER);
331 		return 1;
332 	}
333 
334 	return 0;
335 }
336 //----------- End of function FirmBase::detect_info -----------//
337 
338 
339 //--------- Begin of function FirmBase::disp_base_info ---------//
340 //
disp_base_info(int dispY1,int refreshFlag)341 void FirmBase::disp_base_info(int dispY1, int refreshFlag)
342 {
343 	//---------------- paint the panel --------------//
344 
345 	if( refreshFlag == INFO_REPAINT )
346 		vga_util.d3_panel_up( INFO_X1, dispY1, INFO_X2, dispY1+46);
347 
348 	if( !overseer_recno )
349 		return;
350 
351 	//------------ display overseer info -------------//
352 
353 	Unit* overseerUnit = unit_array[overseer_recno];
354 
355 	int x=INFO_X1+6, y=dispY1+4, x1=x+UNIT_LARGE_ICON_WIDTH+8;
356 
357 	if( selected_worker_id == 0 )
358 	{
359 		vga_front.rect( x-2, y-2, x+UNIT_LARGE_ICON_WIDTH+1, y+UNIT_LARGE_ICON_HEIGHT+1, 2, V_YELLOW );
360 	}
361 	else
362 	{
363 		vga_util.blt_buf( x-2, y-2, x+UNIT_LARGE_ICON_WIDTH+1, y-1, 0 );
364 		vga_util.blt_buf( x-2, y+UNIT_LARGE_ICON_HEIGHT+1, x+UNIT_LARGE_ICON_WIDTH+1, y+UNIT_LARGE_ICON_HEIGHT+2, 0 );
365 		vga_util.blt_buf( x-2, y-2, x-1, y+UNIT_LARGE_ICON_HEIGHT+2, 0 );
366 		vga_util.blt_buf( x+UNIT_LARGE_ICON_WIDTH, y-2, x+UNIT_LARGE_ICON_WIDTH+1, y+UNIT_LARGE_ICON_HEIGHT+2, 0 );
367 	}
368 
369 	//-------------------------------------//
370 
371 	if( refreshFlag == INFO_REPAINT )
372 	{
373 		vga_front.put_bitmap(x, y, unit_res[overseerUnit->unit_id]->get_large_icon_ptr(overseerUnit->rank_id) );
374 	}
375 
376 	//-------- set help parameters --------//
377 
378 	if( mouse.in_area(x, y, x+UNIT_LARGE_ICON_WIDTH+3, y+UNIT_LARGE_ICON_HEIGHT+3) )
379 		help.set_unit_help( overseerUnit->unit_id, overseerUnit->rank_id, x, y, x+UNIT_LARGE_ICON_WIDTH+3, y+UNIT_LARGE_ICON_HEIGHT+3);
380 
381 	//-------------------------------------//
382 
383 	if( overseerUnit->rank_id == RANK_KING )
384 	{
385 		if( refreshFlag == INFO_REPAINT )
386 			font_san.put( x1, y, _("King") );
387 
388 		y+=14;
389 	}
390 
391 	if( refreshFlag == INFO_REPAINT )
392 		font_san.put( x1, y, overseerUnit->unit_name(0), 0, INFO_X2-2 );		// 0-ask unit_name() not to return the title of the unit
393 
394 	y+=14;
395 
396 	//------- display leadership -------//
397 
398 	String str;
399 
400 	str  = _("Leadership");
401 	str += ": ";
402 	str += overseerUnit->skill.get_skill(SKILL_LEADING);
403 
404 	font_san.disp( x1, y, str, INFO_X2-10 );
405 	y+=14;
406 
407 	//--------- display loyalty ----------//
408 
409 	if( overseerUnit->rank_id != RANK_KING )
410 	{
411 		str  = _("Loyalty");
412 		str += ":";
413 		x1 = font_san.put( x1, y, str );
414 
415 		int x2 = info.disp_loyalty( x1, y-1, x1, overseerUnit->loyalty, overseerUnit->target_loyalty, nation_recno, refreshFlag );
416 
417 		if( overseerUnit->spy_recno )
418 		{
419 			//------ if this is the player's spy -------//
420 
421 			if( overseerUnit->true_nation_recno() == nation_array.player_recno )
422 			{
423 				vga_front.put_bitmap( x2+5, y+1, image_icon.get_ptr("U_SPY") );
424 				x2 += 15;
425 			}
426 		}
427 
428 		vga_util.blt_buf( x2, y-1, INFO_X2-2, dispY1+44, 0 );
429 	}
430 }
431 //----------- End of function FirmBase::disp_base_info -----------//
432 
433 
434 //--------- Begin of function FirmBase::next_day ---------//
435 //
next_day()436 void FirmBase::next_day()
437 {
438 	//----- call next_day() of the base class -----//
439 
440 	Firm::next_day();
441 
442 	//--------------------------------------//
443 
444 	calc_productivity();
445 
446 	//--------------------------------------//
447 
448 	if( info.game_date%15 == firm_recno%15 )			// once a week
449 	{
450 		train_unit();
451 		recover_hit_point();
452 	}
453 
454 	//------- increase pray points --------//
455 
456 	if( overseer_recno && pray_points < MAX_PRAY_POINTS )
457 	{
458 		// ###### patch begin Gilbert 21/1 #######//
459 		if( config.fast_build )
460 			pray_points += productivity/10;
461 		else
462 			pray_points += productivity/100;
463 		// ###### patch end Gilbert 21/1 #######//
464 
465 		if( pray_points > MAX_PRAY_POINTS )
466 			pray_points = (float) MAX_PRAY_POINTS;
467 	}
468 
469 	//------ validate god_unit_recno ------//
470 
471 	if( god_unit_recno )
472 	{
473 		if( unit_array.is_deleted(god_unit_recno) )
474 			god_unit_recno = 0;
475 
476 	#ifdef DEBUG
477 		if( god_unit_recno )
478 		{
479 			err_when( !unit_array[god_unit_recno]->is_visible() );
480 			err_when( unit_array[god_unit_recno]->nation_recno != nation_recno );
481 		}
482 	#endif
483 	}
484 }
485 //----------- End of function FirmBase::next_day -----------//
486 
487 
488 //------- Begin of function FirmBase::change_nation ---------//
489 //
change_nation(int newNationRecno)490 void FirmBase::change_nation(int newNationRecno)
491 {
492 	//--- update the UnitInfo vars of the workers in this firm ---//
493 
494 	for( int i=0 ; i<worker_count ; i++ )
495 		unit_res[ worker_array[i].unit_id ]->unit_change_nation(newNationRecno, nation_recno, worker_array[i].rank_id );
496 
497 	//------ update base_count_array[] --------//
498 
499 	err_when( race_id<1 || race_id>MAX_RACE );
500 
501 	nation_array[nation_recno]->base_count_array[race_id-1]--;
502 
503 	err_when( nation_array[nation_recno]->base_count_array[race_id-1] < 0 );
504 
505 	nation_array[newNationRecno]->base_count_array[race_id-1]++;
506 
507 	//----- change the nation recno of the god invoked by the base if there is any ----//
508 
509 	if( god_unit_recno && !unit_array.is_deleted(god_unit_recno) )
510 		unit_array[god_unit_recno]->change_nation(newNationRecno);
511 
512 	//-------- change the nation of this firm now ----------//
513 
514 	Firm::change_nation(newNationRecno);
515 }
516 //-------- End of function FirmBase::change_nation ---------//
517 
518 
519 //------- Begin of function FirmBase::train_unit -------//
520 //
521 // Increase the praying skills of the prayers.
522 //
train_unit()523 void FirmBase::train_unit()
524 {
525 	if( !overseer_recno )
526 		return;
527 
528 	Unit* overseerUnit = unit_array[overseer_recno];
529 	int 	overseerSkill = overseerUnit->skill.skill_level;
530 	int	incValue;
531 
532 	//------- increase the commander's leadership ---------//
533 
534 	if( worker_count > 0 && overseerUnit->skill.skill_level < 100 )
535 	{
536 		//-- the more soldiers this commander has, the higher the leadership will increase ---//
537 
538 		incValue = 3 * worker_count
539 					  * (int) overseerUnit->hit_points / overseerUnit->max_hit_points
540 					  * (100+overseerUnit->skill.skill_potential*2) / 100;
541 
542 		overseerUnit->skill.skill_level_minor += incValue;
543 
544 		if( overseerUnit->skill.skill_level_minor >= 100 )
545 		{
546 			overseerUnit->skill.skill_level_minor -= 100;
547 			overseerUnit->skill.skill_level++;
548 		}
549 	}
550 
551 	//------- increase the prayer's skill level ------//
552 
553 	int	  levelMinor;
554 	Worker* workerPtr = worker_array;
555 
556 	for( int i=0 ; i<worker_count ; i++, workerPtr++ )
557 	{
558 		//------- increase prayer skill -----------//
559 
560 		if( workerPtr->skill_level < overseerSkill )
561 		{
562 			incValue = MAX(20, overseerSkill-workerPtr->skill_level)
563 						  * workerPtr->hit_points / workerPtr->max_hit_points()
564 						  * (100+workerPtr->skill_potential*2) / 100;
565 
566 			levelMinor = workerPtr->skill_level_minor + incValue;		// with random factors, resulting in 75% to 125% of the original
567 
568 			while( levelMinor >= 100 )
569 			{
570 				levelMinor -= 100;
571 				workerPtr->skill_level++;
572 			}
573 
574 			workerPtr->skill_level_minor = levelMinor;
575 		}
576 	}
577 }
578 //-------- End of function FirmBase::train_unit --------//
579 
580 
581 //------- Begin of function FirmBase::recover_hit_point -------//
582 //
583 // Prayers recover their hit points.
584 //
585 // No need to recover the hit points of the general here as
586 // this is taken care in the Unit class function of the general.
587 //
recover_hit_point()588 void FirmBase::recover_hit_point()
589 {
590 	Worker* workerPtr = worker_array;
591 
592 	for( int i=0 ; i<worker_count ; i++, workerPtr++ )
593 	{
594 		//------- increase worker hit points --------//
595 
596 		if( workerPtr->hit_points < workerPtr->max_hit_points() )
597 			workerPtr->hit_points++;
598 	}
599 }
600 //------- End of function FirmBase::recover_hit_point -------//
601 
602 //--------- Begin of function FirmBase::disp_god_info ---------//
603 //
disp_god_info(int dispY1,int refreshFlag)604 void FirmBase::disp_god_info(int dispY1, int refreshFlag)
605 {
606 	//---------------- paint the panel --------------//
607 
608 	if( refreshFlag == INFO_REPAINT )
609 		vga_util.d3_panel_up( INFO_X1, dispY1, INFO_X2, dispY1+50 );
610 
611 	//-------- display the icon of the mythical creature -------//
612 
613 	int 		 x=INFO_X1+4, y=dispY1+4;
614 	UnitInfo* unitInfo = unit_res[ god_res[god_id]->unit_id ];
615 
616 	if( refreshFlag == INFO_REPAINT )
617 	{
618 		vga_util.d3_panel_down( x, y, x+UNIT_LARGE_ICON_WIDTH+3, y+UNIT_LARGE_ICON_HEIGHT+3, 2 );
619 		vga_front.put_bitmap( x+2, y+2, unitInfo->get_large_icon_ptr(0) );
620 
621 		//----------- display text ------------//
622 
623 		x += UNIT_LARGE_ICON_WIDTH+10;
624 
625 		font_san.put( x, y+2, _(unitInfo->name) );
626 	}
627 	else
628 	{
629 		x += UNIT_LARGE_ICON_WIDTH+10;
630 	}
631 
632 	vga_front.indicator( 0x00, x-3, y+18, pray_points, (float) MAX_PRAY_POINTS, 0 );
633 }
634 //----------- End of function FirmBase::disp_god_info -----------//
635 
636 
637 //--------- Begin of function FirmBase::invoke_god ---------//
638 //
639 // Invoke God.
640 //
invoke_god()641 void FirmBase::invoke_god()
642 {
643 	god_unit_recno = god_res[god_id]->invoke(firm_recno, center_x, center_y);
644 }
645 //----------- End of function FirmBase::invoke_god -----------//
646 
647 
648 //--------- Begin of function FirmBase::can_invoke ---------//
649 //
can_invoke()650 int FirmBase::can_invoke()
651 {
652 	//----- if the base's god creature has been destroyed -----//
653 
654 	if( god_unit_recno && unit_array.is_deleted(god_unit_recno) )
655 		god_unit_recno = 0;
656 
657 	//---------------------------------------------------------//
658 
659 	return !god_unit_recno &&		// one base can only support one god
660 			 overseer_recno &&
661 			 pray_points >= MAX_PRAY_POINTS/10;		// there must be at least 10% of the maximum pray points to cast a creature
662 }
663 //----------- End of function FirmBase::can_invoke -----------//
664