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