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    : OR_RANK.CPP
22 //Description : Ranking report
23 
24 #include <ODATE.h>
25 #include <OFONT.h>
26 #include <OGAME.h>
27 #include <OCONFIG.h>
28 #include <OVBROWIF.h>
29 #include <ONATION.h>
30 #include <OINFO.h>
31 #include <vga_util.h>
32 #include "gettext.h"
33 
34 //------------- Define coordinations -----------//
35 
36 enum { NATION_BROWSE_X1 = ZOOM_X1+6,
37 		 NATION_BROWSE_Y1 = ZOOM_Y1+6,
38 		 NATION_BROWSE_X2 = ZOOM_X2-6,
39 		 NATION_BROWSE_Y2 = NATION_BROWSE_Y1+220,
40 	 };
41 
42 enum { NATION_SCORE_X1 = ZOOM_X1+6,
43 		 NATION_SCORE_Y1 = NATION_BROWSE_Y2+6,
44 		 NATION_SCORE_X2 = ZOOM_X2-6,
45 		 NATION_SCORE_Y2 = NATION_SCORE_Y1+150,
46 	 };
47 
48 enum { NATION_GOAL_X1 = ZOOM_X1+6,
49 		 NATION_GOAL_Y1 = NATION_SCORE_Y2+6,
50 		 NATION_GOAL_X2 = ZOOM_X2-6,
51 		 NATION_GOAL_Y2 = NATION_GOAL_Y1+110,
52 	 };
53 
54 enum { PLAY_TIME_X1 = ZOOM_X1+6,
55 		 PLAY_TIME_X2 = ZOOM_X2-6,
56 	 };
57 
58 //----------- Define static variables ----------//
59 
60 static VBrowseIF 	browse_nation;
61 static int		 	nation_rank_data_array[MAX_RANK_TYPE][MAX_NATION];
62 
63 //----------- Define static functions ----------//
64 
65 static void  put_nation_rec(int recNo, int x, int y, int refreshFlag);
66 static int   nation_filter(int recNo=0);
67 static void  disp_score();
68 static void	 disp_goal();
69 static void	 disp_play_time(int y1);
70 static void put_heading(char justify, int x1, int y1, int x2, int y2, const char *textPtr);
71 
72 #define J_L Font::LEFT_JUSTIFY
73 #define J_C Font::CENTER_JUSTIFY
74 #define J_R Font::RIGHT_JUSTIFY
75 
76 //--------- Begin of function Info::disp_rank ---------//
77 //
disp_rank(int refreshFlag)78 void Info::disp_rank(int refreshFlag)
79 {
80 	set_rank_data(1);		// 1-only set those nations that have contact with us
81 
82 	int x=NATION_BROWSE_X1+9;
83 	int y=NATION_BROWSE_Y1+3;
84 
85 	vga_back.d3_panel_up(NATION_BROWSE_X1, NATION_BROWSE_Y1, NATION_BROWSE_X2, NATION_BROWSE_Y1+32 );
86 
87 	put_heading( J_L, x    , y, x+180, y+29, _("Kingdom") );
88 	put_heading( J_C, x+180, y, x+264, y+29, _("Population") );
89 	put_heading( J_L, x+264, y, x+332, y+29, _("Military") );
90 	put_heading( J_L, x+332, y, x+406, y+29, _("Economy") );
91 	put_heading( J_L, x+406, y, x+484, y+29, _("Reputation") );
92 	put_heading( J_L, x+484, y, NATION_BROWSE_X2-20, y+29, _("Fryhtan Battling") );
93 
94 	if( refreshFlag == INFO_REPAINT )
95 	{
96 		browse_nation.init( NATION_BROWSE_X1, NATION_BROWSE_Y1+34, NATION_BROWSE_X2, NATION_BROWSE_Y2,
97 								  0, 22, nation_filter(), put_nation_rec, 1 );
98 
99 		browse_nation.open(browse_nation_recno);
100 	}
101 	else
102 	{
103 		browse_nation.paint();
104 		browse_nation.open(browse_nation_recno, nation_filter());
105 	}
106 
107 	//----- display score -------//
108 
109 	disp_score();
110 
111 	//------ display goal -------//
112 
113 	if( !game.game_has_ended )	// if the ending screen has already appeared once, don't display the goal
114 	{
115 		disp_goal();
116 		y = NATION_GOAL_Y2+6;
117 	}
118 	else
119 	{
120 		y = NATION_GOAL_Y1;
121 	}
122 
123 	//----- display total playing time -----//
124 
125 	disp_play_time(y);
126 }
127 //----------- End of function Info::disp_rank -----------//
128 
129 
130 //--------- Begin of static function disp_score ---------//
131 //
disp_score()132 static void disp_score()
133 {
134 	int x=NATION_SCORE_X1+6, y=NATION_SCORE_Y1+6;
135 
136 	static const char* rankStrArray[] =
137 	{ N_("Population Score"), N_("Military Score"), N_("Economic Score"),
138 	  N_("Reputation Score"), N_("Fryhtan Battling Score") };
139 
140 	vga_util.d3_panel_down( NATION_SCORE_X1, NATION_SCORE_Y1, NATION_SCORE_X2, NATION_SCORE_Y2 );
141 
142 	//------ display individual scores ---------//
143 
144 	int rankScore, totalScore=0;
145 	int viewNationRecno = nation_filter(browse_nation.recno());
146 
147 	for( int i=0 ; i<MAX_RANK_TYPE ; i++, y+=16 )
148 	{
149 		rankScore   = info.get_rank_score(i+1, viewNationRecno);
150 		totalScore += rankScore;
151 
152 		font_san.put( x    , y, _(rankStrArray[i]) );
153 		font_san.put( x+300, y, rankScore, 1 );
154 	}
155 
156 	vga_back.bar( x, y, x+340, y+1, V_BLACK );
157 	y+=4;
158 
159 	//-------- display thte total score --------//
160 
161 	font_san.put( x    , y+2, _("Total Score") );
162 	font_san.put( x+300, y+2, totalScore, 1 );
163 	y+=20;
164 
165 	vga_back.bar( x, y, x+340, y+1, V_BLACK );
166 	y+=4;
167 
168 	//-------- display the final score ---------//
169 
170  	int	 difficultyRating = config.difficulty_rating;
171 	int	 finalScore = totalScore * difficultyRating / 100;
172 	String str;
173 
174 	str  = _("Final Score");
175 	str += ":  ";
176 	str += misc.format(totalScore);
177 	str += " X ";
178 
179 	int x2 = font_san.put( x, y+12, str ) + 5;
180 
181 	str  = misc.format(difficultyRating);
182 	str += " ";
183 	str += _("(Difficulty Rating)");
184 
185 	font_san.center_put( x2, y+1, x2+156, y+15, str );
186 	vga_back.bar( x2   , y+16, x2+156, y+17, V_BLACK );
187 	font_san.put( x2+65, y+19, 100 );
188 
189 	//------- if the player has cheated -------//
190 
191 	if( nation_array[viewNationRecno]->cheat_enabled_flag )
192 	{
193 		str  = "X  0 ";
194 		str += _("(Cheated)");
195 		str += "  ";
196 
197 		finalScore = 0;
198 	}
199 	else
200 	{
201 		str = "";
202 	}
203 
204 	str += "=  ";
205 	str += finalScore;
206 
207 	font_san.put( x2+170, y+12, str);
208 
209 	y+=36;
210 }
211 //----------- End of static function disp_score -----------//
212 
213 
214 //--------- Begin of static function disp_goal ---------//
215 //
disp_goal()216 static void disp_goal()
217 {
218 	//----- if the ending screen has already appeared once -----//
219 
220 	if( game.game_has_ended )
221 		return;
222 
223 	//------------------------------------//
224 
225 	int x=NATION_GOAL_X1+6, y=NATION_GOAL_Y1+6;
226 
227 	int goalCount = 1 + config.goal_destroy_monster +
228 						 config.goal_population_flag +
229 						 config.goal_economic_score_flag +
230 						 config.goal_total_score_flag;
231 
232 	vga_util.d3_panel_down( NATION_GOAL_X1, NATION_GOAL_Y1, NATION_GOAL_X2, NATION_GOAL_Y2 );
233 
234 	//------------------------------------//
235 
236 	String str;
237 
238 	if( goalCount > 1 )
239 	{
240 		if( config.goal_year_limit_flag )
241 		{
242 			// TRANSLATORS: GOAL: Achieve One of the Following Before <Date>:
243 			snprintf( str, MAX_STR_LEN+1, _("GOAL: Achieve One of the Following Before %s:"), date.date_str(info.goal_deadline) );
244 		}
245 		else
246 		{
247 			str = _("GOAL: Achieve One of the Following:");
248 		}
249 	}
250 	else
251 	{
252 		if( config.goal_year_limit_flag )
253 		{
254 			// TRANSLATORS: GOAL: Defeat All Other Kingdoms Before <Date>.
255 			snprintf( str, MAX_STR_LEN+1, _("GOAL: Defeat All Other Kingdoms Before %s."), date.date_str( info.goal_deadline ) );
256 		}
257 		else
258 		{
259 			str = _("GOAL: Defeat All Other Kingdoms.");
260 		}
261 	}
262 
263 	//--------------------------------------//
264 
265 	font_san.put( x, y, str );
266 
267 	y+=18;
268 
269 	if( goalCount==1 )
270 		return;
271 
272 	//-----------------------------------//
273 
274 	str = _("Defeat All Other Kingdoms.");
275 
276 	font_san.put( x, y, str );
277 	y+=16;
278 
279 	//-----------------------------------//
280 
281 	if( config.goal_destroy_monster )
282 	{
283 		str = _("Destroy All Fryhtans.");
284 
285 		font_san.put( x, y, str );
286 
287 		y+=16;
288 	}
289 
290 	//-----------------------------------//
291 
292 	if( config.goal_population_flag )
293 	{
294 		// TRANSLATORS: Achieve a Population of <Number>.
295 		snprintf( str, MAX_STR_LEN+1, _("Achieve a Population of %s."), misc.format(config.goal_population) );
296 
297 		font_san.put( x, y, str );
298 
299 		y+=16;
300 	}
301 
302 	//-----------------------------------//
303 
304 	if( config.goal_economic_score_flag )
305 	{
306 		// TRANSLATORS: Achieve an Economic Score of <Number>.
307 		snprintf( str, MAX_STR_LEN+1, _("Achieve an Economic Score of %s."), misc.format(config.goal_economic_score) );
308 
309 		font_san.put( x, y, str );
310 
311 		y+=16;
312 	}
313 
314 	//-----------------------------------//
315 
316 	if( config.goal_total_score_flag )
317 	{
318 		// TRANSLATORS: Achieve a Total Score of <Number>.
319 		snprintf( str, MAX_STR_LEN+1, _("Achieve a Total Score of %s."), misc.format(config.goal_total_score) );
320 
321 		font_san.put( x, y, str );
322 
323 		y+=16;
324 	}
325 }
326 //----------- End of static function disp_goal -----------//
327 
328 
329 //--------- Begin of static function disp_play_time ---------//
330 //
disp_play_time(int y1)331 static void disp_play_time(int y1)
332 {
333 	vga_util.d3_panel_down( PLAY_TIME_X1, y1, PLAY_TIME_X2, y1+24 );
334 
335 	String str;
336 
337 	// TRANSLATORS: Total Playing Time: <Time duration>
338 	snprintf( str, MAX_STR_LEN+1, _("Total Playing Time: %s"), info.play_time_str() );
339 
340 	font_san.put( PLAY_TIME_X1+6, y1+6, str );
341 }
342 //----------- End of static function disp_play_time -----------//
343 
344 
345 //--------- Begin of function Info::detect_rank ---------//
346 //
detect_rank()347 void Info::detect_rank()
348 {
349 	//------- detect nation browser ------//
350 
351 	if( browse_nation.detect() )
352 	{
353 		browse_nation_recno = browse_nation.recno();
354 		return;
355 	}
356 }
357 //----------- End of function Info::detect_rank -----------//
358 
359 
360 //-------- Begin of static function nation_filter --------//
361 //
362 // This function has dual purpose :
363 //
364 // 1. when <int> recNo is not given :
365 //    - return the total no. of nations of this nation
366 //
367 // 2. when <int> recNo is given :
368 //    - return the nation recno in nation_array of the given recno.
369 //
nation_filter(int recNo)370 static int nation_filter(int recNo)
371 {
372 	int    	i, nationCount=0;
373 	Nation*  viewingNation = NULL;
374 
375 	if( nation_array.player_recno )
376 		viewingNation = nation_array[info.viewing_nation_recno];
377 
378 	for( i=1 ; i<=nation_array.size() ; i++ )
379 	{
380 		if( nation_array.is_deleted(i) )
381 			continue;
382 
383 		if( i==info.viewing_nation_recno ||
384 			 !viewingNation ||
385 			 viewingNation->get_relation(i)->has_contact )
386 		{
387 			nationCount++;
388 		}
389 
390 		if( recNo && nationCount==recNo )
391 			return i;
392 	}
393 
394 	err_when( recNo );   // the recNo is not found, it is out of range
395 
396 	return nationCount;
397 }
398 //----------- End of static function nation_filter -----------//
399 
400 
401 //-------- Begin of static function put_nation_rec --------//
402 //
put_nation_rec(int recNo,int x,int y,int refreshFlag)403 static void put_nation_rec(int recNo, int x, int y, int refreshFlag)
404 {
405 	int	  nationRecno = nation_filter(recNo);
406 	Nation* nationPtr   = nation_array[nationRecno];
407 
408 	x+=3;
409 	y+=5;
410 
411 	nationPtr->disp_nation_color(x, y+4);
412 
413 	font_san.put( x+20, y, nationPtr->nation_name() );
414 
415 	font_san.put( x+210, y, info.get_rank_pos_str(1, nationRecno) );
416 	font_san.put( x+270, y, info.get_rank_pos_str(2, nationRecno) );
417 	font_san.put( x+352, y, info.get_rank_pos_str(3, nationRecno) );
418 	font_san.put( x+435, y, info.get_rank_pos_str(4, nationRecno) );
419   	font_san.put( x+500, y, info.get_rank_pos_str(5, nationRecno) );
420 }
421 //----------- End of static function put_nation_rec -----------//
422 
423 
424 //-------- Begin of function Info::set_rank_data --------//
425 //
426 // <int> onlyHasContact - if this is 1, then only nations
427 //								  that have contact with the viewing
428 //								  nation is counted. Otherwise all nations
429 //								  are counted.
430 //
set_rank_data(int onlyHasContact)431 void Info::set_rank_data(int onlyHasContact)
432 {
433 	Nation* viewingNation = NULL;
434 	Nation* nationPtr;
435 	int 	  rankPos=0;
436 
437 	if( nation_array.player_recno && !nation_array.is_deleted(info.viewing_nation_recno) )
438 		viewingNation = nation_array[info.viewing_nation_recno];
439 
440 	memset( nation_rank_data_array, 0, sizeof(nation_rank_data_array) );
441 
442 	for( int i=1 ; i<=nation_array.size() ; i++ )
443 	{
444 		if( nation_array.is_deleted(i) )
445 			continue;
446 
447 		if( onlyHasContact )
448 		{
449 			if( viewingNation && !viewingNation->get_relation(i)->has_contact )
450 				continue;
451 		}
452 
453 		nationPtr = nation_array[i];
454 
455 		nation_rank_data_array[0][i-1] = nationPtr->population_rating;
456 
457 		nation_rank_data_array[1][i-1] = nationPtr->military_rating;
458 
459 		nation_rank_data_array[2][i-1] = nationPtr->economic_rating;
460 
461 		nation_rank_data_array[3][i-1] = (int) nationPtr->reputation;
462 
463 		nation_rank_data_array[4][i-1] = (int) nationPtr->kill_monster_score;
464 	}
465 }
466 //----------- End of static function Info::set_rank_data -----------//
467 
468 
469 const char *rank_num_th[MAX_NATION] =
470 {
471 	// TRANSLATORS: Ordinal number for ranking players
472 	N_("1st"),
473 	N_("2nd"),
474 	N_("3rd"),
475 	N_("4th"),
476 	N_("5th"),
477 	N_("6th"),
478 	N_("7th"),
479 };
480 //-------- Begin of function Info::get_rank_pos_str --------//
481 //
get_rank_pos_str(int rankType,int nationRecno)482 char* Info::get_rank_pos_str(int rankType, int nationRecno)
483 {
484 	static String rank_pos_msg;
485 	Nation* viewingNation = NULL;
486 	int curNationRankData = nation_rank_data_array[rankType-1][nationRecno-1];
487 	int rankPos=1;
488 
489 	if( nation_array.player_recno && !nation_array.is_deleted(info.viewing_nation_recno) )
490 		viewingNation = nation_array[info.viewing_nation_recno];
491 
492 	for( int i=1 ; i<=nation_array.size() ; i++ )
493 	{
494 		if( nation_array.is_deleted(i) || i == nationRecno )
495 			continue;
496 
497 		if( viewingNation && !viewingNation->get_relation(i)->has_contact )
498 			continue;
499 
500 		if( nation_rank_data_array[rankType-1][i-1] > curNationRankData )		// if another nation's value is higher than the given nation's value
501 			rankPos++;
502 	}
503 
504 	rank_pos_msg = _(rank_num_th[rankPos-1]);
505 	return rank_pos_msg;
506 }
507 //----------- End of function Info::get_rank_pos_str -----------//
508 
509 
510 //-------- Begin of function Info::get_rank_score --------//
511 //
512 // Get the score of the given nation in the given ranking type.
513 //
get_rank_score(int rankType,int nationRecno)514 int Info::get_rank_score(int rankType, int nationRecno)
515 {
516 	int maxValue;
517 
518 	switch( rankType )
519 	{
520 		case 1:     	// population
521 			maxValue = 100;
522 			break;
523 
524 		case 2:        // military strength
525 			maxValue = 200;
526 			break;
527 
528 		case 3:        // economic strength
529 			maxValue = 6000;
530 			break;
531 
532 		case 4:        // reputation
533 			maxValue = 100;				// so the maximum score of the reputation portion is 50 only
534 			break;
535 
536 		case 5: 			// monsters slain score
537 			maxValue = 1000;
538 			break;
539 	}
540 
541 	int rankScore = 100 * nation_rank_data_array[rankType-1][nationRecno-1] / maxValue;
542 
543 	return MAX(0, rankScore);
544 }
545 //----------- End of function Info::get_rank_score -----------//
546 
547 
548 //-------- Begin of function Info::get_total_score --------//
549 //
550 // Get the score of the given nation.
551 //
get_total_score(int nationRecno)552 int Info::get_total_score(int nationRecno)
553 {
554 	int totalScore=0;
555 
556 	for( int i=0 ; i<MAX_RANK_TYPE ; i++ )
557 	{
558 		totalScore += get_rank_score(i+1, nationRecno);
559 	}
560 
561 	return totalScore;
562 }
563 //----------- End of function Info::get_total_score -----------//
564 
565 
566 //-------- Begin of static function put_heading --------//
567 //
put_heading(char justify,int x1,int y1,int x2,int y2,const char * textPtr)568 static void put_heading(char justify, int x1, int y1, int x2, int y2, const char *textPtr)
569 {
570 	int dispLines=0;
571 	int totalLines=0;
572 	font_san.count_line(x1,y1,x2,y2,textPtr,0,dispLines,totalLines);
573 	if( dispLines > 1 )
574 		font_san.put_paragraph(x1,y1,x2,y2,textPtr,-1,1,1,justify);
575 	else if( y1+7<y2 )
576 		font_san.put_paragraph(x1,y1+7,x2,y2,textPtr,-1,1,1,justify);
577 }
578 //----------- End of static function put_heading -----------//
579