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_RESE.CPP
22 //Description : Firm Magic Tower
23 
24 #include <OINFO.h>
25 #include <OVGA.h>
26 #include <vga_util.h>
27 #include <ODATE.h>
28 #include <OSTR.h>
29 #include <ONEWS.h>
30 #include <OFONT.h>
31 #include <OCONFIG.h>
32 #include <OBUTT3D.h>
33 #include <OMOUSE.h>
34 #include <OSYS.h>
35 #include <OPOWER.h>
36 #include <OUNIT.h>
37 #include <OGAME.h>
38 #include <ONATION.h>
39 #include <OTECHRES.h>
40 #include <OF_RESE.h>
41 #include <OREMOTE.h>
42 #include <OSE.h>
43 #include <OSERES.h>
44 #include <OBUTTCUS.h>
45 #include "gettext.h"
46 
47 //------------- Define constant ------------//
48 
49 #define MAX_RESEARCH_OPTION		6
50 #define RESEARCH_OPTION_HEIGHT 	48
51 
52 //---------- Define constant ------------//
53 
54 enum { RESEARCH_MENU_MAIN,
55 		 RESEARCH_MENU_RESEARCH,
56 	  };
57 
58 //----------- Define static vars -------------//
59 
60 static Button3D button_select_research;
61 static char     research_menu_mode;
62 static char     disable_refresh=0;
63 static ButtonCustom	button_research_array[MAX_RESEARCH_OPTION];
64 // ######## begin Gilbert 16/8 ######//
65 static ButtonCustom	button_cancel;
66 // ######## end Gilbert 16/8 ######//
67 static int added_count;			// no. of buttons in button_research_array
68 static Button3D	button_vacate_firm;
69 
70 //---------- Declare static functions ---------//
71 
72 static void i_disp_research_button(ButtonCustom *, int);
73 static void set_all_research(int techId);
74 
75 //--------- Begin of function FirmResearch::FirmResearch ---------//
76 //
FirmResearch()77 FirmResearch::FirmResearch()
78 {
79 	firm_skill_id = SKILL_RESEARCH;
80 }
81 //----------- End of function FirmResearch::FirmResearch -----------//
82 
83 
84 //--------- Begin of function FirmResearch::~FirmResearch ---------//
85 //
~FirmResearch()86 FirmResearch::~FirmResearch()
87 {
88 	terminate_research();
89 }
90 //----------- End of function FirmResearch::~FirmResearch -----------//
91 
92 
93 //--------- Begin of function FirmResearch::init_derived ---------//
94 //
init_derived()95 void FirmResearch::init_derived()
96 {
97 	tech_id = 0;				   // the id. of the tech this firm is currently researching
98 	complete_percent = (float) 0;		// percent completed on researching the current technology
99 }
100 //----------- End of function FirmResearch::init_derived -----------//
101 
102 
103 //--------- Begin of function FirmResearch::put_info ---------//
104 //
put_info(int refreshFlag)105 void FirmResearch::put_info(int refreshFlag)
106 {
107 	if( refreshFlag==INFO_REPAINT && !disable_refresh )
108 		research_menu_mode = RESEARCH_MENU_MAIN;
109 
110 	switch( research_menu_mode )
111 	{
112 		case RESEARCH_MENU_MAIN:
113 			disp_main_menu(refreshFlag);
114 			break;
115 
116 		case RESEARCH_MENU_RESEARCH:
117 			disp_research_menu(refreshFlag);
118 			break;
119 	}
120 }
121 //----------- End of function FirmResearch::put_info -----------//
122 
123 
124 //--------- Begin of function FirmResearch::detect_info ---------//
125 //
detect_info()126 int FirmResearch::detect_info()
127 {
128 	switch( research_menu_mode )
129 	{
130 		case RESEARCH_MENU_MAIN:
131 			return detect_main_menu();
132 
133 		case RESEARCH_MENU_RESEARCH:
134 			return detect_research_menu();
135 	}
136 
137 	return 0;
138 }
139 //----------- End of function FirmResearch::detect_info -----------//
140 
141 
142 //--------- Begin of function FirmResearch::disp_main_menu ---------//
143 //
disp_main_menu(int refreshFlag)144 void FirmResearch::disp_main_menu(int refreshFlag)
145 {
146 	disp_basic_info(INFO_Y1, refreshFlag);
147 
148 	if( !should_show_info() )
149 		return;
150 
151 	disp_research_info(INFO_Y1+54, refreshFlag);
152 	disp_worker_list(INFO_Y1+107, refreshFlag);
153 	disp_worker_info(INFO_Y1+171, refreshFlag);
154 
155 	//------ display mobilize button -------//
156 
157 	int x = INFO_X1;
158 
159 	if( own_firm() )
160 	{
161 		if (refreshFlag == INFO_REPAINT)
162 		{
163 			button_select_research.paint(INFO_X1, INFO_Y1 + 235, 'A', "RESEARCH");
164 			button_vacate_firm.paint(INFO_X1 + BUTTON_ACTION_WIDTH, INFO_Y1 + 235, 'A', "RECRUIT");
165 			button_vacate_firm.set_help_code("MOBILIZE");
166 		}
167 
168 		if( have_own_workers() )
169 			button_vacate_firm.enable();
170 		else
171 			button_vacate_firm.disable();
172 
173 		x += (BUTTON_ACTION_WIDTH * 2);
174 	}
175 
176 	disp_spy_button( x, INFO_Y1+235, refreshFlag );
177 }
178 //----------- End of function FirmResearch::disp_main_menu -----------//
179 
180 
181 //--------- Begin of function FirmResearch::detect_main_menu ---------//
182 //
detect_main_menu()183 int FirmResearch::detect_main_menu()
184 {
185 	//-------- detect basic info -----------//
186 
187 	if( detect_basic_info() )
188 		return 1;
189 
190 	//----------- detect worker -----------//
191 
192 	if( detect_worker_list() )
193 	{
194 		disp_research_info(INFO_Y1+54, INFO_UPDATE);
195 		disp_worker_info(INFO_Y1+171, INFO_UPDATE);
196 		return 1;
197 	}
198 
199 	//-------- detect spy button ----------//
200 
201 	if( detect_spy_button() )
202 		return 1;
203 
204 	if( !own_firm() )
205 		return 0;
206 
207 	//------ detect the select research button -------//
208 
209 	if( button_select_research.detect(GETKEY(KEYEVENT_FIRM_BUILD)) )
210 	{
211 		research_menu_mode = RESEARCH_MENU_RESEARCH;
212 		disable_refresh = 1;    // static var for disp_info() only
213 		info.disp();
214 		disable_refresh = 0;
215 		return 1;
216 	}
217 
218 	//-------- detect mobilize button ----------//
219 
220 	if (button_vacate_firm.detect())
221 	{
222 		mobilize_all_workers(COMMAND_PLAYER);
223 		return 1;
224 	}
225 
226 	return 0;
227 }
228 //----------- End of function FirmResearch::detect_main_menu -----------//
229 
230 
231 /** \brief Make all Towers of Science research the same tech.
232  *
233  *  \param[in] techId Technology to research.
234  *
235  *  \note This function is only used by human players (via the Tower of Science
236  *  research interface).
237  */
set_all_research(int techId)238 void set_all_research(int techId)
239 {
240 	for( int i=firm_array.size() ; i>0 ; i-- )
241 	{
242 		if( firm_array.is_deleted(i) )
243 			continue;
244 
245 		Firm* firmPtr = firm_array[i];
246 
247 		if( firmPtr->nation_recno == nation_array.player_recno &&
248 			firmPtr->firm_id == FIRM_RESEARCH &&
249 			!firm_array.is_deleted(i) )
250 		{
251 			(dynamic_cast<FirmResearch*>(firmPtr))->start_research(techId, COMMAND_PLAYER);
252 		}
253 	}
254 }
255 
256 
257 //--------- Begin of function FirmResearch::disp_research_menu ---------//
258 //
disp_research_menu(int refreshFlag)259 void FirmResearch::disp_research_menu(int refreshFlag)
260 {
261 	if( refreshFlag != INFO_REPAINT )
262 		return;
263 
264 	int techId, y=INFO_Y1;
265 	added_count=0;
266 
267 	for( techId=1 ; techId<=tech_res.tech_count ; techId++ )
268 	{
269 		if( !tech_res[techId]->can_research(nation_recno) )
270 			continue;
271 
272 		if( added_count < MAX_RESEARCH_OPTION )
273 		{
274 			button_research_array[added_count].paint(INFO_X1, y, INFO_X2, y+RESEARCH_OPTION_HEIGHT-2,
275 				i_disp_research_button, ButtonCustomPara(this, techId) );
276 			added_count++;
277 			y += RESEARCH_OPTION_HEIGHT;
278 		}
279 	}
280 
281 	// ###### begin Gilbert 16/8 ######//
282 	// button_cancel.paint(INFO_X1, y, "CANCEL1", "CANCEL1D" );
283 	button_cancel.paint(INFO_X1, y, INFO_X2, y+RESEARCH_OPTION_HEIGHT*3/4,
284 		ButtonCustom::disp_text_button_func, ButtonCustomPara((void*)_("Cancel"),0) );
285 	// ###### end Gilbert 16/8 ######//
286 }
287 //----------- End of function FirmResearch::disp_research_menu -----------//
288 
289 
290 //--------- Begin of function FirmResearch::detect_research_menu ---------//
291 //
detect_research_menu()292 int FirmResearch::detect_research_menu()
293 {
294 	int i;
295 	for( i = 0; i < added_count; ++i )
296 	{
297 		int rc = button_research_array[i].detect(0, 0, 1, 0);
298 		if( rc )
299 		{
300 			int techId = button_research_array[i].custom_para.value;
301 			if( tech_res[techId]->can_research(nation_recno) )
302 			{
303 				if ( rc == 1 )  // Left click.
304 				{
305 					start_research(techId, COMMAND_PLAYER);
306 				}
307 				else if ( rc == 2 )  // Right click.
308 				{
309 					set_all_research(techId);
310 				}
311 				// ##### begin Gilbert 25/9 ######//
312 				se_ctrl.immediate_sound("TURN_ON");
313 				// ##### end Gilbert 25/9 ######//
314 
315 				research_menu_mode = RESEARCH_MENU_MAIN;
316 				info.disp();
317 			}
318 			else
319 			{
320 				// ##### begin Gilbert 25/9 ######//
321 				se_ctrl.immediate_sound("TURN_OFF");
322 				// ##### end Gilbert 25/9 ######//
323 			}
324 			return 1;
325 		}
326 	}
327 
328 	//------ detect the cancel button --------//
329 
330 	if( i >= added_count )		// no research button has been pressed
331 	{
332 		if( button_cancel.detect() )
333 		{
334 			// ##### begin Gilbert 25/9 ######//
335 			se_ctrl.immediate_sound("TURN_OFF");
336 			// ##### end Gilbert 25/9 ######//
337 			research_menu_mode = RESEARCH_MENU_MAIN;
338 			info.disp();
339 			return 1;
340 		}
341 	}
342 
343 	return 0;
344 }
345 //----------- End of function FirmResearch::detect_research_menu -----------//
346 
347 
348 //-------- Begin of static function i_disp_research_button --------//
349 //
i_disp_research_button(ButtonCustom * button,int repaintBody)350 void i_disp_research_button(ButtonCustom *button, int repaintBody)
351 {
352 	int x1 = button->x1;
353 	int y1 = button->y1;
354 	int x2 = button->x2;
355 	int y2 = button->y2;
356 
357 	if( button->pushed_flag )
358 	{
359 		vga_util.d3_panel2_down(x1, y1, x2, y2);
360 		x1++;
361 		y1++;
362 	}
363 	else
364 	{
365 		vga_util.d3_panel2_up(x1, y1, x2, y2);
366 		x2--;
367 		y2--;
368 	}
369 
370 	//--------------------------------------------//
371 
372 	TechInfo* techInfo = tech_res[button->custom_para.value];
373 
374 	// Vga::active_buf->d3_panel_down(x1+2, y1+2, x1+TECH_LARGE_ICON_WIDTH+7, y1+TECH_LARGE_ICON_HEIGHT+7, 2, 0 );
375 	Vga::active_buf->put_bitmap(x1+4, y1+4, techInfo->tech_large_icon() );
376 
377 	//------ display research description -------//
378 
379 	String str;
380 
381 	str = techInfo->tech_des();
382 
383 	Firm *firmPtr = (Firm *) button->custom_para.ptr;
384 	int researchVersion = techInfo->get_nation_tech_level(firmPtr->nation_recno)+1;		// research the next non-researched version
385 
386 	if( researchVersion > 1 )
387 	{
388 		str += " ";
389 		str += misc.roman_number(researchVersion);
390 	}
391 
392 	font_bible.put( x1+TECH_LARGE_ICON_WIDTH+12, y1+14, str );
393 }
394 //--------- End of static function i_disp_research_button ---------//
395 
396 
397 //--------- Begin of function FirmResearch::disp_research_info ---------//
398 //
disp_research_info(int dispY1,int refreshFlag)399 void FirmResearch::disp_research_info(int dispY1, int refreshFlag)
400 {
401 	static short lastTechId=0;
402 
403 	if( refreshFlag==INFO_UPDATE && lastTechId != tech_id )
404 	{
405 		lastTechId = tech_id;
406 		info.disp();
407 	}
408 
409 	//---------------- paint the panel --------------//
410 
411 	if( refreshFlag == INFO_REPAINT )
412 		vga_util.d3_panel_up( INFO_X1, dispY1, INFO_X2, dispY1+50 );
413 
414 	if( !tech_id )
415 		return;
416 
417 	int x=INFO_X1+4, y=dispY1+4;
418 
419 	//-------- display the icon of the researching item ---------//
420 
421 	TechInfo* techInfo = tech_res[tech_id];
422 
423 	if( refreshFlag == INFO_REPAINT )
424 	{
425 		vga_util.d3_panel_down( x, y, x+TECH_LARGE_ICON_WIDTH+3, y+TECH_LARGE_ICON_HEIGHT+3, 2 );
426 		vga_front.put_bitmap( x+2, y+2, techInfo->tech_large_icon() );
427 
428 		//----------- display text ------------//
429 
430 		x += TECH_LARGE_ICON_WIDTH+10;
431 
432 		String str;
433 
434 		str  = techInfo->tech_des();
435 
436 		int researchVersion = techInfo->get_nation_tech_level(nation_recno)+1;		// research the next non-researched version
437 
438 		if( researchVersion > 1 )
439 		{
440 			str += " ";
441 			str += misc.roman_number(researchVersion);
442 		}
443 
444 		font_san.put( x, y+4, str);
445 	}
446 	else
447 	{
448 		x += TECH_LARGE_ICON_WIDTH+10;
449 	}
450 
451 	vga_front.indicator( 0, x-2, y+21, techInfo->get_progress(nation_recno), (float)100, VGA_GRAY );
452 }
453 //----------- End of function FirmResearch::disp_research_info -----------//
454 
455 
456 //--------- Begin of function FirmResearch::next_day ---------//
457 //
next_day()458 void FirmResearch::next_day()
459 {
460 	//----- call next_day() of the base class -----//
461 
462 	Firm::next_day();
463 
464 	//----------- update population -------------//
465 
466 	recruit_worker();
467 
468 	//-------- train up the skill ------------//
469 
470 	update_worker();
471 
472 	//--------- calculate productivity ----------//
473 
474 	calc_productivity();
475 
476 	//--------- process research ----------//
477 
478 	process_research();
479 }
480 //----------- End of function FirmResearch::next_day -----------//
481 
482 
483 //------- Begin of function FirmResearch::change_nation ---------//
484 //
change_nation(int newNationRecno)485 void FirmResearch::change_nation(int newNationRecno)
486 {
487 	terminate_research();
488 
489 	//-------- change the nation of this firm now ----------//
490 
491 	Firm::change_nation(newNationRecno);
492 }
493 //-------- End of function FirmResearch::change_nation ---------//
494 
495 
496 //--------- Begin of function FirmResearch::start_research --------//
497 //
498 // Start researching on the specific technology.
499 //
500 // <int> techId - id. of the technology to research.
501 //
start_research(int techId,char remoteAction)502 void FirmResearch::start_research(int techId, char remoteAction)
503 {
504 	TechInfo* techInfo = tech_res[techId];
505 
506 	err_when( !techInfo->can_research(nation_recno) );
507 
508 	if( !remoteAction && remote.is_enable())
509 	{
510 		// packet structure : <firm recno> <tech Id>
511 		short *shortPtr = (short *)remote.new_send_queue_msg(MSG_F_RESEARCH_START, 2*sizeof(short) );
512 		shortPtr[0] = firm_recno;
513 		shortPtr[1] = (short) techId;
514 		return;
515 	}
516 
517 	//---- if the firm currently is already researching something ---//
518 
519 	if( tech_id )
520 		terminate_research();
521 
522 	//-------- set self parameters ---------//
523 
524 	tech_id = techId;
525 
526 	//------- set TechRes parameters -------//
527 
528 	techInfo->inc_nation_is_researching(nation_recno);
529 }
530 //----------- End of function FirmResearch::start_research ---------//
531 
532 
533 //--------- Begin of function FirmResearch::process_research --------//
534 //
535 // Process the current research.
536 //
process_research()537 void FirmResearch::process_research()
538 {
539 	if( !tech_id )
540 		return;
541 
542 	//------- make a progress with the research ------//
543 
544 	TechInfo* techInfo = tech_res[tech_id];
545 	float		 progressPoint;
546 
547 	if( config.fast_build && nation_recno==nation_array.player_recno )
548 		progressPoint = (float) productivity / 100 + (float) 0.5;
549 	else
550 		progressPoint = (float) productivity / 300;
551 
552 	int 	newLevel 	 = techInfo->get_nation_tech_level(nation_recno)+1;
553 	float levelDivider = ((float)(newLevel+1)/2);		// from 1.0 to 2.0
554 
555 	progressPoint = progressPoint * (float) 30
556 						 / techInfo->complex_level
557 						 / levelDivider;					// more complex and higher level technology will take longer to research
558 
559 	int techId = tech_id;		// techInfo->progress() will reset tech_id if the current research level is the MAX tech level, so we have to save it now
560 
561 	if( techInfo->progress(nation_recno, progressPoint) )
562 	{
563 		if( tech_id )			// TechRes::progress() may have called terminate_research() if the tech level reaches the maximum
564 		{
565 			int techId = tech_id;
566 
567 			research_complete();
568 
569 			//----- research next level technology automatically -----//
570 
571 			if( !firm_ai )		// for player's firm only
572 			{
573 				if( techInfo->get_nation_tech_level(nation_recno) < techInfo->max_tech_level )
574 				{
575 					start_research( techId, COMMAND_AUTO );
576 
577 					if( firm_recno == firm_array.selected_recno )
578 						info.disp();
579 				}
580 			}
581 		}
582 
583 		//--------- add news ---------//
584 
585 		if( own_firm() )
586 		{
587 			news_array.tech_researched( techId, tech_res[techId]->get_nation_tech_level(nation_recno) );
588 
589 			se_res.far_sound(center_x, center_y, 1, 'F', firm_id, "FINS",
590 				'S', unit_res[tech_res[techId]->unit_id]->sprite_id);
591 		}
592 	}
593 }
594 //----------- End of function FirmResearch::process_research ---------//
595 
596 
597 //--------- Begin of function FirmResearch::research_complete --------//
598 //
research_complete()599 void FirmResearch::research_complete()
600 {
601 	short techId = tech_id;         // backup tech_id
602 
603 	tech_res[tech_id]->dec_nation_is_researching(nation_recno);
604 
605 	tech_id = 0;         		// reset parameters
606 	complete_percent = (float) 0;
607 }
608 //----------- End of function FirmResearch::research_complete ---------//
609 
610 
611 //--------- Begin of function FirmResearch::terminate_research --------//
612 //
terminate_research()613 void FirmResearch::terminate_research()
614 {
615 	if( !tech_id )
616 		return;
617 
618 	tech_res[tech_id]->dec_nation_is_researching(nation_recno);
619 
620 	tech_id = 0;         		// reset parameters
621 	complete_percent = (float) 0;
622 }
623 //----------- End of function FirmResearch::terminate_research ---------//
624