Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Portions of this file are copyright Rebirth contributors and licensed as
  3.  * described in COPYING.txt.
  4.  * Portions of this file are copyright Parallax Software and licensed
  5.  * according to the Parallax license below.
  6.  * See COPYING.txt for license details.
  7.  
  8. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  9. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  10. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  11. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  12. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  13. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  14. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  15. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  16. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  17. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  18. */
  19.  
  20. /*
  21.  *
  22.  * Routines to display the credits.
  23.  *
  24.  */
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <stdarg.h>
  30. #include <ctype.h>
  31. #include <utility>
  32.  
  33. #include "dxxerror.h"
  34. #include "pstypes.h"
  35. #include "gr.h"
  36. #include "window.h"
  37. #include "key.h"
  38. #include "mouse.h"
  39. #include "palette.h"
  40. #include "game.h"
  41. #include "timer.h"
  42. #include "gamefont.h"
  43. #include "pcx.h"
  44. #include "credits.h"
  45. #include "u_mem.h"
  46. #include "screens.h"
  47. #include "digi.h"
  48. #include "rbaudio.h"
  49. #include "text.h"
  50. #include "songs.h"
  51. #include "menu.h"
  52. #include "config.h"
  53. #include "physfsx.h"
  54. #if defined(DXX_BUILD_DESCENT_II)
  55. #include "mission.h"
  56. #include "gamepal.h"
  57. #include "args.h"
  58. #endif
  59. #include "piggy.h"
  60. #include <memory>
  61.  
  62. #define ROW_SPACING                     (SHEIGHT / 17)
  63. #define NUM_LINES                       20 //14
  64. #define MAKE_CREDITS_PAIR(F)    std::pair<const char *, int>(F ".tex", sizeof(F) + 1)
  65. #if defined(DXX_BUILD_DESCENT_I)
  66. #define CREDITS_FILE                    MAKE_CREDITS_PAIR("credits")
  67. #elif defined(DXX_BUILD_DESCENT_II)
  68. #define CREDITS_FILE                    (       \
  69.         PHYSFSX_exists("mcredits.tex", 1)       \
  70.                 ? MAKE_CREDITS_PAIR("mcredits") \
  71.                 : PHYSFSX_exists("ocredits.tex", 1)     \
  72.                         ? MAKE_CREDITS_PAIR("ocredits")         \
  73.                         : MAKE_CREDITS_PAIR("credits")  \
  74.         )
  75. #define ALLOWED_CHAR                    (!Current_mission ? 'R' : (is_SHAREWARE ? 'S' : 'R'))
  76. #endif
  77.  
  78. namespace {
  79.  
  80. struct credits : ignore_window_pointer_t
  81. {
  82.         RAIIPHYSFS_File file;
  83.         int have_bin_file;
  84.         std::array<PHYSFSX_gets_line_t<80>, NUM_LINES> buffer;
  85.         int buffer_line;
  86.         int first_line_offset;
  87.         int extra_inc;
  88.         int done;
  89.         int row;
  90.         grs_main_bitmap backdrop;
  91. };
  92.  
  93. }
  94.  
  95. namespace dsx {
  96. static window_event_result credits_handler(window *, const d_event &event, credits *cr)
  97. {
  98.         int l, y;
  99.         window_event_result result;
  100.  
  101.         switch (event.type)
  102.         {
  103.                 case EVENT_KEY_COMMAND:
  104.                         if ((result = call_default_handler(event)) == window_event_result::ignored)     // if not print screen, debug etc
  105.                         {
  106.                                 return window_event_result::close;
  107.                         }
  108.                         return result;
  109.  
  110.                 case EVENT_MOUSE_BUTTON_DOWN:
  111.                 case EVENT_MOUSE_BUTTON_UP:
  112.                         if (event_mouse_get_button(event) == MBTN_LEFT || event_mouse_get_button(event) == MBTN_RIGHT)
  113.                         {
  114.                                 return window_event_result::close;
  115.                         }
  116.                         break;
  117.  
  118.                 case EVENT_JOYSTICK_BUTTON_DOWN:
  119.                         return window_event_result::close;
  120.  
  121.                 case EVENT_IDLE:
  122.                         if (cr->done>NUM_LINES)
  123.                         {
  124.                                 return window_event_result::close;
  125.                         }
  126.                         break;
  127.                        
  128.                 case EVENT_WINDOW_DRAW:
  129.                         {
  130. #if defined(DXX_BUILD_DESCENT_I)
  131.                         timer_delay(F1_0/17);
  132. #elif defined(DXX_BUILD_DESCENT_II)
  133.                         timer_delay(F1_0/28);
  134. #endif
  135.                        
  136.                         if (cr->row == 0)
  137.                         {
  138.                                 do {
  139.                                         cr->buffer_line = (cr->buffer_line+1) % NUM_LINES;
  140. #if defined(DXX_BUILD_DESCENT_II)
  141.                                 get_line:;
  142. #endif
  143.                                         if (PHYSFSX_fgets( cr->buffer[cr->buffer_line], cr->file ))     {
  144.                                                 char *p;
  145.                                                 if (cr->have_bin_file) // is this a binary tbl file
  146.                                                         decode_text_line (cr->buffer[cr->buffer_line]);
  147. #if defined(DXX_BUILD_DESCENT_I)
  148.                                                 p = strchr(&cr->buffer[cr->buffer_line][0],'\n');
  149.                                                 if (p) *p = '\0';
  150. #elif defined(DXX_BUILD_DESCENT_II)
  151.                                                 p = cr->buffer[cr->buffer_line];
  152.                                                 if (p[0] == ';')
  153.                                                         goto get_line;
  154.                                                
  155.                                                 if (p[0] == '%')
  156.                                                 {
  157.                                                         if (p[1] == ALLOWED_CHAR)
  158.                                                         {
  159.                                                                 for (int i = 0; p[i]; i++)
  160.                                                                         p[i] = p[i+2];
  161.                                                         }
  162.                                                         else
  163.                                                                 goto get_line;
  164.                                                 }
  165. #endif 
  166.                                         } else  {
  167.                                                 //fseek( file, 0, SEEK_SET);
  168.                                                 cr->buffer[cr->buffer_line][0] = 0;
  169.                                                 cr->done++;
  170.                                         }
  171.                                 } while (cr->extra_inc--);
  172.                                 cr->extra_inc = 0;
  173.                         }
  174.  
  175.                         // cheap but effective: towards end of credits sequence, fade out the music volume
  176.                         if (cr->done >= NUM_LINES-16)
  177.                         {
  178.                                 static int curvol = -10;
  179.                                 if (curvol == -10)
  180.                                         curvol = GameCfg.MusicVolume;
  181.                                 if (curvol > (NUM_LINES-cr->done)/2)
  182.                                 {
  183.                                         curvol = (NUM_LINES-cr->done)/2;
  184.                                         songs_set_volume(curvol);
  185.                                 }
  186.                         }
  187.                        
  188.                         y = cr->first_line_offset - cr->row;
  189.                         auto &canvas = *grd_curcanv;
  190.                         show_fullscr(canvas, cr->backdrop);
  191.                         for (uint_fast32_t j=0; j != NUM_LINES; ++j, y += ROW_SPACING)
  192.                         {
  193.                                 l = (cr->buffer_line + j + 1 ) %  NUM_LINES;
  194.                                 const char *s = cr->buffer[l];
  195.                                 if (!s)
  196.                                         continue;
  197.                                
  198.                                 const grs_font *cv_font;
  199.                                 if ( s[0] == '!' ) {
  200.                                         s++;
  201.                                         cv_font = canvas.cv_font;
  202.                                 } else
  203.                                 {
  204.                                         const auto c = s[0];
  205.                                         cv_font = (c == '$'
  206.                                                 ? (++s, HUGE_FONT)
  207.                                                 : (c == '*')
  208.                                                         ? (++s, MEDIUM3_FONT)
  209.                                                         : MEDIUM2_FONT
  210.                                                 ).get();
  211.                                 }
  212.                                
  213.                                 const auto tempp = strchr( s, '\t' );
  214.                                 if ( !tempp )   {
  215.                                         // Wacky Fast Credits thing
  216.                                         gr_string(canvas, *cv_font, 0x8000, y, s);
  217.                                 }
  218.                         }
  219.                        
  220.                         cr->row += SHEIGHT/200;
  221.                         if (cr->row >= ROW_SPACING)
  222.                                 cr->row = 0;
  223.                         break;
  224.                         }
  225.  
  226.                 case EVENT_WINDOW_CLOSE:
  227.                         songs_set_volume(GameCfg.MusicVolume);
  228.                         songs_play_song( SONG_TITLE, 1 );
  229.                         std::default_delete<credits>()(cr);
  230.                         break;
  231.                 default:
  232.                         break;
  233.         }
  234.         return window_event_result::ignored;
  235. }
  236. }
  237.  
  238. namespace dsx {
  239.  
  240. static void credits_show_common(RAIIPHYSFS_File file, const int have_bin_file)
  241. {
  242.         palette_array_t backdrop_palette;
  243.         auto cr = std::make_unique<credits>();
  244.         *cr = {};
  245.         cr->file = std::move(file);
  246.         cr->have_bin_file = have_bin_file;
  247.  
  248.         set_screen_mode(SCREEN_MENU);
  249. #if defined(DXX_BUILD_DESCENT_II)
  250.         gr_use_palette_table( "credits.256" );
  251. #endif
  252.         cr->backdrop.bm_data=NULL;
  253.  
  254.         const auto pcx_error = pcx_read_bitmap(STARS_BACKGROUND, cr->backdrop,backdrop_palette);
  255.         if (pcx_error != pcx_result::SUCCESS)
  256.         {
  257.                 return;
  258.         }
  259.  
  260.         songs_play_song( SONG_CREDITS, 1 );
  261.  
  262.         gr_remap_bitmap_good(cr->backdrop,backdrop_palette, -1, -1);
  263.  
  264.         gr_set_default_canvas();
  265.         show_fullscr(*grd_curcanv, cr->backdrop);
  266.         gr_palette_load( gr_palette );
  267.  
  268.         key_flush();
  269.  
  270.         credits *pcr = cr.get();
  271.         const auto wind = window_create(grd_curscreen->sc_canvas, 0, 0, SWIDTH, SHEIGHT, credits_handler, cr.release());
  272.         if (!wind)
  273.         {
  274.                 d_event event = { EVENT_WINDOW_CLOSE };
  275.                 credits_handler(NULL, event, pcr);
  276.                 return;
  277.         }
  278.  
  279.         event_process_all();
  280. }
  281.  
  282. void credits_show(const char *const filename)
  283. {
  284.         if (auto &&file = PHYSFSX_openReadBuffered(filename))
  285.                 credits_show_common(std::move(file), 1);
  286. }
  287.  
  288. void credits_show()
  289. {
  290.         const auto &&credits_file = CREDITS_FILE;
  291.         int have_bin_file = 0;
  292.         auto file = PHYSFSX_openReadBuffered(credits_file.first);
  293.         if (!file)
  294.         {
  295.                 char nfile[32];
  296.                 snprintf(nfile, sizeof(nfile), "%.*sxb", credits_file.second, credits_file.first);
  297.                 file = PHYSFSX_openReadBuffered(nfile);
  298.                 if (!file)
  299.                         Error("Missing CREDITS.TEX and CREDITS.TXB file\n");
  300.                 have_bin_file = 1;
  301.         }
  302.         credits_show_common(std::move(file), have_bin_file);
  303. }
  304.  
  305. }
  306.