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    : OGAMEND.CPP
22 //Description : Game ending screen
23 
24 #include <OVGA.h>
25 #include <vga_util.h>
26 #include <OVGALOCK.h>
27 #include <ODATE.h>
28 #include <OREMOTE.h>
29 #include <OBOX.h>
30 #include <OCONFIG.h>
31 #include <OSTR.h>
32 #include <OSYS.h>
33 #include <OFONT.h>
34 #include <OMOUSE.h>
35 #include <OIMGRES.h>
36 #include <ORACERES.h>
37 #include <OGAME.h>
38 #include <OGAMHALL.h>
39 #include <ONATION.h>
40 #include <OMOUSECR.h>
41 #include <OMUSIC.h>
42 #include <OOPTMENU.h>
43 #include <OINGMENU.h>
44 #include <PlayerStats.h>
45 // ####### begin Gilbert 29/10 ########//
46 #include <OPOWER.h>
47 // ####### end Gilbert 29/10 ########//
48 #include "gettext.h"
49 
50 
51 
52 //-------- Declare static vars & functions ---------//
53 
54 static int  disp_score(int winFlag);
55 static void disp_goal_str(int winNationRecno);
56 static void disp_losing_str(int surrenderToNationRecno);
57 static void disp_retire_str();
58 static void disp_ranking();
59 static void disp_stat();
60 
61 static void put_stat(int y, const char* desStr, const char* dispStr);
62 static void put_stat(int y, const char* desStr, int dispValue);
63 static void put_ranking(int y, int nationRecno);
64 static void put_heading(char justify, int x1, int y1, int x2, int y2, const char *textPtr);
65 static void split_line(char *line);
66 
67 //---------- Begin of function Game::game_end --------//
68 //
69 // <int> winNationRecno - the recno of the nation that won the game.
70 //								  0 - if you are just defeated or surrender
71 //										to another kingdom, and no other kingdom
72 //									   has won yet.
73 // [int] playerDestroyed - whether the player's nation has been destroyed or not.
74 //									(default: 0)
75 // [int] surrenderToNationRecno - the nation your surrender to.
76 // [int] retireFlag		 - 1 if the player retires
77 //
game_end(int winNationRecno,int playerDestroyed,int surrenderToNationRecno,int retireFlag)78 void Game::game_end(int winNationRecno, int playerDestroyed, int surrenderToNationRecno, int retireFlag)
79 {
80 	//--- set scenario as complete if they didn't retire ---//
81 	if(!retireFlag)
82 		playerStats.set_scenario_play_status(scenario_file_name, nsPlayerStats::PlayStatus::COMPLETED);
83 
84 	//--- skip all game ending screens if in demo mode ---//
85 
86 	if( game_mode == GAME_DEMO )
87 	{
88 		sys.signal_exit_flag = 2;
89 		return;
90 	}
91 
92 	//--- if the player has already won/lost the game and is just staying/observing the game ---//
93 
94 	if( game_has_ended && !retireFlag )		// don't repeat displaying the winning/losing screen
95 		return;
96 
97 	// ------ quit any menu mode ------//
98 	if( option_menu.is_active() )
99 	{
100 		option_menu.abort();
101 	}
102 	if( ::in_game_menu.is_active() )
103 	{
104 		::in_game_menu.abort();
105 	}
106 
107 	//------ set the quit siginal -------//
108 
109 	sys.signal_exit_flag = 2;		// set it first to disable Power::mouse.handler()
110 	mouse_cursor.set_frame(0);
111 	// ####### begin Gilbert 29/10 #######//
112 	mouse_cursor.set_icon(CURSOR_NORMAL);
113 	// ####### end Gilbert 29/10 #######//
114 
115 	info.save_game_scr();
116 
117 	int useBackBuf = vga.use_back_buf;
118 
119 	vga.use_front();
120 
121 	//------- display the winning/losing picture -------//
122 
123 	int songId = 10;
124 	int winFlag = 0;
125 
126 	if( !retireFlag )		// don't display this when retire
127 	{
128 		const char* fileName;
129 
130 		if( winNationRecno && (winNationRecno == nation_array.player_recno) )
131 		{
132 			fileName = race_res[(~nation_array)->race_id]->code;
133 			songId = 9;
134 			winFlag = 1;
135 		}
136 		else
137 			fileName = "LOSEGAME";
138 
139 		vga_util.disp_image_file(fileName);
140 
141 		music.play(songId, sys.cdrom_drive ? MUSIC_CD_THEN_WAV : 0);
142 		mouse.wait_press(60);		// 60 seconds to time out
143 	}
144 	else
145 	{
146 		music.play(songId, sys.cdrom_drive ? MUSIC_CD_THEN_WAV : 0);
147 	}
148 
149 	//------- display the statistic -------//
150 
151 	vga_util.disp_image_file("RESULTS");
152 
153 	if( winNationRecno )
154 	{
155 		disp_goal_str(winNationRecno);
156 	}
157 	else if( retireFlag )
158 	{
159 		disp_retire_str();
160 	}
161 	else
162 	{
163 		disp_losing_str(surrenderToNationRecno);
164 	}
165 
166 	disp_stat();
167 
168 	mouse.wait_press(60);		// 60 seconds to time out
169 
170 	//-------- display ranking and score ----------//
171 
172 	vga_util.disp_image_file("RESULTS");
173 
174 	info.set_rank_data(0);		// count all nations, not only those that have contact with the player
175 
176 	disp_ranking();
177 
178 	int totalScore = disp_score(winFlag);
179 
180 	mouse.wait_press(60);		// 60 seconds to time out
181 
182 	//--- if the player has managed to get into the hall of fame ---//
183 
184 	if( !game_has_ended )
185 	{
186 		if( !hall_of_fame.add_hall_of_fame(totalScore) )
187 			vga_util.finish_disp_image_file();		// if add_hall_of_fame() has displayed the bitmap, it should have called vga_util.finish_disp_image_file() already
188 	}
189 	else
190 	{
191 		vga_util.finish_disp_image_file();
192 	}
193 
194 	//--------- set game_has_ended to 1 --------//
195 
196 	music.stop();
197 	game_has_ended = 1;
198 
199 	//----------- reset all goals -----------//
200 
201 	config.goal_destroy_monster     = 0;
202 	config.goal_population_flag     = 0;
203 	config.goal_economic_score_flag = 0;
204 	config.goal_total_score_flag 	  = 0;
205 	config.goal_year_limit_flag     = 0;
206 
207 	//--- otherwise, ask if the player wants to stay in the game ---//
208 
209 	#ifndef DEMO		// cannot continue to stay in the game in the demo version
210 
211 	if( !retireFlag && !remote.is_enable() )		// can't stay in the game in a multiplayer game
212 	{
213 		vga_front.bar( 0, 0, VGA_WIDTH-1, VGA_HEIGHT-1, V_BLACK );		// clear the screen
214 
215 		// ###### begin Gilbert 29/10 ######//
216 		char powerWinFlag = power.win_opened;
217 		power.win_opened = 1;
218 		if( box.ask( _("Do you want to continue to stay in the game?"), _("Yes"), _("No") ) )
219 			sys.signal_exit_flag = 0;
220 		power.win_opened = powerWinFlag;
221 		// ###### end Gilbert 29/10 ######//
222 	}
223 
224 	#endif
225 
226 	//-------- if it quits now ----------//
227 
228 	if( sys.signal_exit_flag )
229 	{
230 		info.free_game_scr();
231 
232 		vga.use_back_buf = useBackBuf;
233 	}
234 	else
235 	{
236 		//---- otherwise restore the screen and continue to play ----//
237 
238 		info.rest_game_scr();
239 
240 		vga.use_back_buf = useBackBuf;
241 
242 		//---- reveal the whole world for staying in the game after being destroyed ----//
243 
244 		if( playerDestroyed && !retireFlag )
245 		{
246 			world.unveil(0, 0, MAX_WORLD_X_LOC-1, MAX_WORLD_Y_LOC-1);
247 			world.visit(0, 0, MAX_WORLD_X_LOC-1, MAX_WORLD_Y_LOC-1, 0, 0);
248 
249 			config.blacken_map = 0;
250 			config.fog_of_war  = 0;
251 		}
252 	}
253 }
254 //----------- End of function Game::game_end ---------//
255 
256 
257 //----------- Begin of static function disp_goal_str -----------//
258 
disp_goal_str(int winNationRecno)259 static void disp_goal_str(int winNationRecno)
260 {
261 	Nation* winNation = nation_array[winNationRecno];
262 	String  str, str2;
263 
264 	str = "";
265 
266 	if( winNationRecno != nation_array.player_recno )
267 	{
268 		str += _("You Have Lost the Game !");
269 		str += "\n";
270 	}
271 
272 	//---- if the player has achieved one of its goals ----//
273 
274 	if( winNation->goal_destroy_monster_achieved() )
275 	{
276 		str += _("All Fryhtans have been Destroyed !");
277 		if( winNationRecno == nation_array.player_recno )
278 		{
279 			str += "\n";
280 			str += _("Your Kingdom has Achieved the Highest Fryhtan Battling Score !");
281 		}
282 		else
283 		{
284 			str += "\n";
285 			// TRANSLATORS: <King>'s Kingdom has Achieved the Highest Fryhtan Battling Score !
286 			str.catf(_("%s's Kingdom has Achieved the Highest Fryhtan Battling Score !"), nation_array[winNationRecno]->king_name(1));
287 		}
288 	}
289 
290 	//-----------------------------------//
291 
292 	else if( winNation->goal_population_achieved() )
293 	{
294 		if( winNationRecno == nation_array.player_recno )
295 		{
296 			// TRANSLATORS: Your Kingdom has Reached its Population/Economic Score/Total Score Goal of <Number> !
297 			snprintf(str2, MAX_STR_LEN+1, _("Your Kingdom has Reached its Population Goal of %s !"), misc.format(config.goal_population));
298 		}
299 		else
300 		{
301 			// TRANSLATORS: <King>'s Kingdom has Reached its Population/Economic Score/Total Score Goal of <Number> !
302 			snprintf(str2, MAX_STR_LEN+1, _("%s's Kingdom has Reached its Population Goal of %s !"), nation_array[winNationRecno]->king_name(1), misc.format(config.goal_population));
303 		}
304 		split_line(str2);
305 		str += str2;
306 	}
307 
308 	//-----------------------------------//
309 
310 	else if( winNation->goal_economic_score_achieved() )
311 	{
312 		if( winNationRecno == nation_array.player_recno )
313 		{
314 			// TRANSLATORS: Your Kingdom has Reached its Population/Economic Score/Total Score Goal of <Number> !
315 			snprintf(str2, MAX_STR_LEN+1, _("Your Kingdom has Reached its Economic Score Goal of %s !"), misc.format(config.goal_economic_score));
316 		}
317 		else
318 		{
319 			// TRANSLATORS: <King>'s Kingdom has Reached its Population/Economic Score/Total Score Goal of <Number> !
320 			snprintf(str2, MAX_STR_LEN+1, _("%s's Kingdom has Reached its Economic Score Goal of %s !"), nation_array[winNationRecno]->king_name(1), misc.format(config.goal_economic_score));
321 		}
322 		split_line(str2);
323 		str += str2;
324 	}
325 
326 	//-----------------------------------//
327 
328 	else if( winNation->goal_total_score_achieved() )
329 	{
330 		if( winNationRecno == nation_array.player_recno )
331 		{
332 			// TRANSLATORS: Your Kingdom has Reached its Population/Economic Score/Total Score Goal of <Number> !
333 			snprintf(str2, MAX_STR_LEN+1, _("Your Kingdom has Reached its Total Score Goal of %s !"), misc.format(config.goal_total_score));
334 		}
335 		else
336 		{
337 			// TRANSLATORS: <King>'s Kingdom has Reached its Population/Economic Score/Total Score Goal of <Number> !
338 			snprintf(str2, MAX_STR_LEN+1, _("%s's Kingdom has Reached its Total Score Goal of %s !"), nation_array[winNationRecno]->king_name(1), misc.format(config.goal_total_score));
339 		}
340 		split_line(str2);
341 		str += str2;
342 	}
343 
344 	//-----------------------------------//
345 
346 	else			// ( winNation->goal_destroy_nation_achieved() )
347 	{
348 		if( winNationRecno == nation_array.player_recno )
349 		{
350 			str += _("Your Kingdom has Defeated All Other Kingdoms !");
351 		}
352 		else
353 		{
354 			// TRANSLATORS: <King>'s Kingdom has Defeated All Other Kingdoms !
355 			str.catf(_("%s's Kingdom has Defeated All Other Kingdoms !"), nation_array[winNationRecno]->king_name(1));
356 		}
357 	}
358 
359 	//-----------------------------------//
360 
361 	int y=30;
362 	int dispLines, totalLines;
363 
364 	font_bible.count_line(0, y, VGA_WIDTH-1, y+90, str, 10, dispLines, totalLines);
365 	if( totalLines < 3 )
366 		y=40;
367 
368 	font_bible.put_paragraph(0, y, VGA_WIDTH-1, y+90, str, 10, 1, 1, Font::CENTER_JUSTIFY);
369 }
370 //----------- End of static function disp_goal_str -----------//
371 
372 
373 //----------- Begin of static function disp_losing_str -----------//
374 
disp_losing_str(int surrenderToNationRecno)375 static void disp_losing_str(int surrenderToNationRecno)
376 {
377 	String str;
378 
379 	if( surrenderToNationRecno )		// you surrender to another kingdom
380 	{
381 		// TRANSLATORS: You Surrendered to <King>'s Kingdom on <Date>.
382 		snprintf(str, MAX_STR_LEN+1, _("You Surrendered to %s's Kingdom on %s."), nation_array[surrenderToNationRecno]->king_name(1), date.date_str(info.game_date));
383 	}
384 
385 	// You failed to achieve the goal within the time limit
386 
387 	else if( config.goal_year_limit_flag && info.game_date >= info.goal_deadline )
388 	{
389 		str = _("Your Kingdom has Failed to Achieve its Goal Within the Time Limit.");
390 	}
391 	else		// you're defeated by another kingdom
392 	{
393 		str = _("Your Kingdom has Gone Down to Ignominious Defeat !");
394 	}
395 
396 	font_bible.center_put(0, 0, VGA_WIDTH-1, 139, str );
397 }
398 //----------- End of static function disp_losing_str -----------//
399 
400 
401 //----------- Begin of static function disp_retire_str -----------//
402 
disp_retire_str()403 static void disp_retire_str()
404 {
405 	String str;
406 
407 	// TRANSLATORS: You Retired on <Date>.
408 	snprintf(str, MAX_STR_LEN+1, _("You Retired on %s."), date.date_str( info.game_date ));
409 
410 	font_bible.center_put(0, 0, VGA_WIDTH-1, 139, str );
411 }
412 //----------- End of static function disp_retire_str -----------//
413 
414 
415 //-------- Begin of static function disp_stat --------//
416 //
disp_stat()417 static void disp_stat()
418 {
419 	int y=140;
420 
421 	Nation* nationPtr = ~nation_array;
422 
423 	put_stat( y		, _("Duration of Your Rule"), info.game_duration_str() );
424 	put_stat( y+=20, _("Total Gaming Time"), info.play_time_str() );
425 
426 	put_stat( y+=30, _("Final Population"), nationPtr->all_population() );
427 	put_stat( y+=20, _("Final Treasure")  , misc.format((int)nationPtr->cash,2) );
428 
429 	put_stat( y+=30, _("Enemy Soldiers Dispatched"), nationPtr->enemy_soldier_killed );
430 	put_stat( y+=20, _("King's Soldiers Martyred")  , nationPtr->own_soldier_killed );
431 
432 	put_stat( y+=30, _("Enemy Weapons Destroyed")		  , nationPtr->enemy_weapon_destroyed );
433 	put_stat( y+=20, _("King's Weapons Rendered Obsolete"), nationPtr->own_weapon_destroyed );
434 
435 	put_stat( y+=30, _("Enemy Ships Sunk")   , nationPtr->enemy_ship_destroyed );
436 	put_stat( y+=20, _("King's Ships Missing"), nationPtr->own_ship_destroyed );
437 
438 	put_stat( y+=30, _("Enemy Buildings Destroyed")   , nationPtr->enemy_firm_destroyed );
439 	put_stat( y+=20, _("King's Buildings Cleared"), nationPtr->own_firm_destroyed );
440 
441 	put_stat( y+=30, _("Enemy Civilians Collaterally Damaged"), nationPtr->enemy_civilian_killed );
442 	put_stat( y+=20, _("King's Civilians Cruelly Murdered")    , nationPtr->own_civilian_killed );
443 }
444 //----------- End of static function disp_stat -----------//
445 
446 
447 //-------- Begin of static function put_stat --------//
448 //
put_stat(int y,const char * desStr,const char * dispStr)449 static void put_stat(int y, const char* desStr, const char* dispStr)
450 {
451 	font_bible.put( 140, y, desStr );
452 	font_bible.put( 570, y, dispStr );
453 }
454 //----------- End of static function put_stat -----------//
455 
456 
457 //-------- Begin of static function put_stat --------//
458 //
put_stat(int y,const char * desStr,int dispValue)459 static void put_stat(int y, const char* desStr, int dispValue)
460 {
461 	font_bible.put( 140, y, desStr );
462 	font_bible.put( 570, y, misc.format(dispValue) );
463 }
464 //----------- End of static function put_stat -----------//
465 
466 
467 //-------- Begin of static function disp_ranking --------//
468 //
disp_ranking()469 static void disp_ranking()
470 {
471 	//--------- display descriptions ---------//
472 
473 	int x=20, y=76;
474 
475 	font_bible.put( x+20 , y+7, _("Kingdom") );
476 	font_bible.put( x+260, y+7, _("Population") );
477 	font_bible.put( x+370, y+7, _("Military") );
478 	font_bible.put( x+470, y+7, _("Economy") );
479 	font_bible.put( x+562, y+7, _("Reputation") );
480 
481 	put_heading( Font::LEFT_JUSTIFY, x+670, y, x+760, y+42, _("Fryhtan Battling") );
482 
483 	//--------- display rankings -----------//
484 
485 	put_ranking(y+=36, nation_array.player_recno);
486 
487 	for( int i=1 ; i<=nation_array.size() ; i++ )
488 	{
489 		if( nation_array.is_deleted(i) || i==nation_array.player_recno )
490 			continue;
491 
492 		put_ranking( y+=30, i );
493 	}
494 }
495 //----------- End of static function disp_ranking -----------//
496 
497 
498 //-------- Begin of static function put_ranking --------//
499 //
put_ranking(int y,int nationRecno)500 static void put_ranking(int y, int nationRecno)
501 {
502 	Nation* nationPtr = nation_array[nationRecno];
503 
504 	int x=20;
505 
506 	nationPtr->disp_nation_color(x, y+5);
507 
508 	font_bible.put( x+20, y, nationPtr->nation_name() );
509 
510 	int y2 = y+font_bible.height()-1;
511 
512 	font_bible.center_put( x+260, y, x+340, y2, info.get_rank_pos_str(1, nationRecno) );
513 	font_bible.center_put( x+370, y, x+435, y2, info.get_rank_pos_str(2, nationRecno) );
514 	font_bible.center_put( x+470, y, x+540, y2, info.get_rank_pos_str(3, nationRecno) );
515 	font_bible.center_put( x+562, y, x+640, y2, info.get_rank_pos_str(4, nationRecno) );
516 	font_bible.center_put( x+670, y, x+730, y2, info.get_rank_pos_str(5, nationRecno) );
517 }
518 //----------- End of static function put_ranking -----------//
519 
520 
521 //--------- Begin of static function disp_score ---------//
522 //
disp_score(int winFlag)523 static int disp_score(int winFlag)
524 {
525 	int x=200, y=360;
526 
527 	static const char* rankStrArray[] =
528 	{ N_("Population Score"), N_("Military Score"), N_("Economic Score"),
529 	  N_("Reputation Score"), N_("Fryhtan Battling Score") };
530 
531 	//------ display individual scores ---------//
532 
533 	int rankScore, totalScore=0;
534 	int viewNationRecno = nation_array.player_recno;
535 
536 	for( int i=0 ; i<MAX_RANK_TYPE ; i++, y+=22 )
537 	{
538 		rankScore   = info.get_rank_score(i+1, viewNationRecno);
539 		totalScore += rankScore;
540 
541 		font_bible.put( x    , y, _(rankStrArray[i]) );
542 		font_bible.put( x+300, y, rankScore );
543 	}
544 
545 	vga_front.bar( x, y, x+340, y+1, V_BLACK );
546 	y+=7;
547 
548 	//-------- display thte total score --------//
549 
550 	font_bible.put( x    , y+2, _("Total Score") );
551 	font_bible.put( x+300, y+2, totalScore );
552 	y+=28;
553 
554 	vga_front.bar( x, y, x+340, y+1, V_BLACK );
555 	y+=4;
556 
557 	//-------- display the final score ---------//
558 
559 	int	 difficultyRating = config.difficulty_rating;
560 	int	 finalScore = totalScore * difficultyRating / 100;
561 	String str;
562 
563 	str  = _("Final Score");
564 	str += ":  ";
565 	str += misc.format(totalScore);
566 	str += " X ";
567 
568 	x = font_bible.put( x, y+20, str )+5;
569 
570 	str  = misc.format(difficultyRating);
571 	str += " ";
572 	str += _("(Difficulty Rating)");
573 
574 	font_bible.center_put( x, y+4, x+170, y+1+font_bible.height(), str );
575 	vga_front.bar( x, y+27, x+170, y+28, V_BLACK );
576 	font_bible.put( x+70, y+30, 100 );
577 
578 	//---- if this is a scenario and there are score bonus ----//
579 
580 	str = "";
581 
582 	if( info.goal_score_bonus && winFlag &&
583 		 !nation_array[viewNationRecno]->cheat_enabled_flag )		// if cheated, don't display bonus score, as there is no space for displaying both
584 	{
585 		str += "+  ";
586 		str += info.goal_score_bonus;
587 		str += " ";
588 		str += _("(Bonus)");
589 		str += "  ";
590 		finalScore += info.goal_score_bonus;
591 	}
592 
593 	//------- if the player has cheated -------//
594 
595 	if( nation_array[viewNationRecno]->cheat_enabled_flag )
596 	{
597 		str  = "X  0 ";
598 		str += _("(Cheated)");
599 		str += "  ";
600 
601 		finalScore = 0;
602 	}
603 
604 	str += "=  ";
605 	str += finalScore;
606 
607 	font_bible.put( x+180, y+18, str);
608 
609 	return finalScore;
610 }
611 //----------- End of static function disp_score -----------//
612 
613 
614 //-------- Begin of static function put_heading --------//
615 //
put_heading(char justify,int x1,int y1,int x2,int y2,const char * textPtr)616 static void put_heading(char justify, int x1, int y1, int x2, int y2, const char *textPtr)
617 {
618 	int dispLines=0;
619 	int totalLines=0;
620 	int lineSpacing=-7;
621 	font_bible.count_line(x1,y1,x2,y2,textPtr,lineSpacing,dispLines,totalLines);
622 	if( dispLines > 1 )
623 		font_bible.put_paragraph(x1,y1,x2,y2,textPtr,lineSpacing,1,1,justify);
624 	else if( y1+7<y2 )
625 		font_bible.put_paragraph(x1,y1+7,x2,y2,textPtr,lineSpacing,1,1,justify);
626 }
627 //----------- End of static function put_heading -----------//
628 
629 
630 //-------- Begin of static function split_line --------//
631 //
632 // splits a line with a line break
633 //
split_line(char * line)634 static void split_line(char *line)
635 {
636 	size_t len = strlen(line);
637 	if( len < 3 )
638 		return;
639 
640 	size_t mid = len/2;
641 
642 	line += mid;
643 	while( *line )
644 	{
645 		if( *line == ' ' )
646 		{
647 			*line = '\n';
648 			break;
649 		}
650 		line++;
651 	}
652 }
653 //----------- End of static function split_heading -----------//
654