]> icculus.org git repositories - taylor/freespace2.git/blob - src/menuui/credits.cpp
GCC 3.4 fixes.
[taylor/freespace2.git] / src / menuui / credits.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/MenuUI/Credits.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * C source file for displaying game credits
16  *
17  * $Log$
18  * Revision 1.8  2004/09/20 01:31:44  theoddone33
19  * GCC 3.4 fixes.
20  *
21  * Revision 1.7  2003/08/03 16:10:29  taylor
22  * cleanup; compile warning fixes
23  *
24  * Revision 1.6  2003/06/11 18:30:32  taylor
25  * plug memory leaks
26  *
27  * Revision 1.5  2003/05/25 02:30:42  taylor
28  * Freespace 1 support
29  *
30  * Revision 1.4  2002/06/09 04:41:22  relnev
31  * added copyright header
32  *
33  * Revision 1.3  2002/05/27 22:43:02  theoddone33
34  * Fix more glide symbols
35  *
36  * Revision 1.2  2002/05/07 03:16:46  theoddone33
37  * The Great Newline Fix
38  *
39  * Revision 1.1.1.1  2002/05/03 03:28:09  root
40  * Initial import.
41  *
42  * 
43  * 20    9/14/99 5:14a Dave
44  * Fixed credits drawing in Glide.
45  * 
46  * 19    9/13/99 1:53p Dave
47  * Fixed completely brain dead code in credits_init().
48  * 
49  * 18    9/09/99 10:55a Jefff
50  * 
51  * 17    9/03/99 11:45a Jefff
52  * 
53  * 16    9/01/99 5:28p Jefff
54  * hi res art shows up now
55  * 
56  * 15    9/01/99 4:20p Jefff
57  * mo' pictures
58  * 
59  * 14    9/01/99 12:19p Jefff
60  * text splitting for long lines
61  * 
62  * 13    7/19/99 2:13p Dave
63  * Added some new strings for Heiko.
64  * 
65  * 12    2/03/99 6:06p Dave
66  * Groundwork for FS2 PXO usertracker support.  Gametracker support next.
67  * 
68  * 11    2/03/99 11:44a Dave
69  * Fixed d3d transparent textures.
70  * 
71  * 10    2/01/99 5:55p Dave
72  * Removed the idea of explicit bitmaps for buttons. Fixed text
73  * highlighting for disabled gadgets.
74  * 
75  * 9     1/30/99 9:01p Dave
76  * Coord fixes.
77  * 
78  * 8     1/30/99 5:08p Dave
79  * More new hi-res stuff.Support for nice D3D textures.
80  * 
81  * 7     1/29/99 12:47a Dave
82  * Put in sounds for beam weapon. A bunch of interface screens (tech
83  * database stuff).
84  * 
85  * 6     1/28/99 1:46a Dave
86  * Updated coords and bitmaps.
87  * 
88  * 5     1/14/99 5:15p Neilk
89  * changed credits, command debrief interfaces to high resolution support
90  * 
91  * 4     11/20/98 4:08p Dave
92  * Fixed flak effect in multiplayer.
93  * 
94  * 3     10/13/98 9:28a Dave
95  * Started neatening up freespace.h. Many variables renamed and
96  * reorganized. Added AlphaColors.[h,cpp]
97  * 
98  * 2     10/07/98 10:53a Dave
99  * Initial checkin.
100  * 
101  * 1     10/07/98 10:49a Dave
102  * 
103  * 18    6/19/98 3:51p Lawrance
104  * deal with foreign chars in the credits
105  * 
106  * 17    6/01/98 11:43a John
107  * JAS & MK:  Classified all strings for localization.
108  * 
109  * 16    5/24/98 9:01p Lawrance
110  * Add commit sounds when accept is pressed
111  * 
112  * 15    5/20/98 1:04p Hoffoss
113  * Made credits screen use new artwork and removed rating field usage from
114  * Fred (a goal struct member).
115  * 
116  * 14    5/12/98 4:17p Hoffoss
117  * Make ctrl-arrows (up/down) switch between tech room screens.
118  * 
119  * 13    5/12/98 11:21a Hoffoss
120  * Disabled cutscene screen and simulator room.
121  * 
122  * 12    5/11/98 8:04p Hoffoss
123  * Fixed minor bugs.
124  * 
125  * 11    4/22/98 3:35p John
126  * String externalization marking
127  * 
128  * 10    4/22/98 10:46a Hoffoss
129  * Added images to credits screen.
130  * 
131  * 9     4/21/98 7:07p Hoffoss
132  * Fixed problem where when switching screens flashes old tab hilight once
133  * before switching to new state.
134  * 
135  * 8     4/17/98 3:28p Hoffoss
136  * Added new credits screen code.
137  * 
138  * 7     3/05/98 11:15p Hoffoss
139  * Changed non-game key checking to use game_check_key() instead of
140  * game_poll().
141  * 
142  * 6     2/22/98 12:19p John
143  * Externalized some strings
144  * 
145  * 5     1/05/98 2:30p John
146  * made credits.tbl display
147  * 
148  * 4     9/19/97 5:14p Lawrance
149  * use new naming convention for spooled music
150  * 
151  * 3     8/31/97 6:38p Lawrance
152  * pass in frametime to do_frame loop
153  * 
154  * 2     4/22/97 11:06a Lawrance
155  * credits music playing, credits screen is a separate state
156  *
157  * $NoKeywords: $
158  */
159
160 #include <stdlib.h>
161
162 #include "gamesequence.h"
163 #include "font.h"
164 #include "key.h"
165 #include "bmpman.h"
166 #include "2d.h"
167 #include "timer.h"
168 #include "gamesnd.h"
169 #include "audiostr.h"
170 #include "eventmusic.h" /* for Master_event_music_volume */
171 #include "cfile.h"
172 #include "ui.h"
173 #include "missionscreencommon.h"
174 #include "player.h"
175 #include "freespace.h"
176 #include "alphacolors.h"
177 #include "localize.h"
178
179 #define CREDITS_MUSIC_DELAY     2000
180 #define CREDITS_SCROLL_RATE     15.0f
181 #define CREDITS_ARTWORK_DISPLAY_TIME    9.0f
182 #define CREDITS_ARTWORK_FADE_TIME               1.0f
183
184 #define NUM_BUTTONS                             5
185 #define NUM_IMAGES                              46
186
187 #define TECH_DATABASE_BUTTON    0
188 #define SIMULATOR_BUTTON                1
189 #define CUTSCENES_BUTTON                2
190 #define CREDITS_BUTTON                  3
191 #define EXIT_BUTTON                             4
192
193 // inidicies for coordinates
194 #define CREDITS_X_COORD 0
195 #define CREDITS_Y_COORD 1
196 #define CREDITS_W_COORD 2
197 #define CREDITS_H_COORD 3
198
199 static char* Credits_bitmap_fname[GR_NUM_RESOLUTIONS] = {
200         "Credits",                      // GR_640
201         "2_Credits"
202 };
203
204 static char* Credits_bitmap_mask_fname[GR_NUM_RESOLUTIONS] = {
205         "Credits-M",                    // GR_640
206         "2_Credits-M"
207 };
208
209 int Credits_image_coords[GR_NUM_RESOLUTIONS][4] = {
210         {
211 #ifdef MAKE_FS1
212                 225, 15, 400, 292
213 #else
214                 219, 15, 394, 286                       // GR_640
215 #endif
216         },
217         {
218                 351, 25, 629, 455                       // GR_1024
219         }
220 };
221
222 // x, y, w, h
223 int Credits_text_coords[GR_NUM_RESOLUTIONS][4] = {
224         {
225 #ifdef MAKE_FS1
226                 46, 321, 450, 134
227 #else
228                 26, 316, 482, 157                       // GR_640
229 #endif
230         },
231         {
232                 144, 507, 568, 249                      // GR_640
233         }
234 };
235
236 struct credits_screen_buttons {
237         char *filename;
238         int x, y, xt, yt;
239         int hotspot;
240         UI_BUTTON button;  // because we have a class inside this struct, we need the constructor below..
241
242         credits_screen_buttons(char *name, int x1, int y1, int xt1, int yt1, int h) : filename(name), x(x1), y(y1), xt(xt1), yt(yt1), hotspot(h) {}
243 };
244
245 static int Background_bitmap;
246 #ifdef MAKE_FS1
247 static int CreditsWin01 = -1;
248 static int CreditsWin02 = -1;
249 static int CreditsWin03 = -1;
250 static int CreditsWin04 = -1;
251 #endif
252
253 static UI_WINDOW Ui_window;
254
255 static credits_screen_buttons Buttons[NUM_BUTTONS][GR_NUM_RESOLUTIONS] = {
256 //XSTR:OFF
257 #ifdef MAKE_FS1
258     {
259                         credits_screen_buttons("TDB_00", 0, 0, -1, -1, 0),              // GR_640
260                         credits_screen_buttons("2_TDB_00", 12, 5, 59, 12, 0)            // GR_1024
261     },
262     {
263                         credits_screen_buttons("TDB_01", 0, 19, -1, -1, 1),             // GR_640
264                         credits_screen_buttons("2_TDB_01", 12, 31, 59, 37, 1)           // GR_1024
265     },
266     {
267                         credits_screen_buttons("TDB_02", 0, 35, -1, -1, 2),             // GR_640
268                         credits_screen_buttons("2_TDB_02", 12, 56, 59, 62, 2)           // GR_1024
269     },
270     {
271                         credits_screen_buttons("TDB_03", 0, 56, -1, -1, 3),             // GR_640
272                         credits_screen_buttons("2_TDB_03", 12, 81, 59, 88, 3)           // GR_1024
273     },
274     {
275                         credits_screen_buttons("CRB_04", 561, 411, -1, -1, 4),  // GR_640
276                         credits_screen_buttons("2_CRB_04", 914, 681, 953, 68, 4)        // GR_1024
277     }
278 #else
279         {
280                         credits_screen_buttons("TDB_00", 7, 3, 37, 7, 0),                       // GR_640
281                         credits_screen_buttons("2_TDB_00", 12, 5, 59, 12, 0)                    // GR_1024
282         },
283         {
284                         credits_screen_buttons("TDB_01", 7, 18, 37, 23, 1),             // GR_640
285                         credits_screen_buttons("2_TDB_01", 12, 31, 59, 37, 1)           // GR_1024
286         },
287         {
288                         credits_screen_buttons("TDB_02", 7, 34, 37, 38, 2),             // GR_640
289                         credits_screen_buttons("2_TDB_02", 12, 56, 59, 62, 2)           // GR_1024
290         },
291         {
292                         credits_screen_buttons("TDB_03", 7, 49, 37, 54, 3),             // GR_640
293                         credits_screen_buttons("2_TDB_03", 12, 81, 59, 88, 3)           // GR_1024
294         },
295         {
296                         credits_screen_buttons("CRB_04", 571, 425, 588, 413, 4),        // GR_640
297                         credits_screen_buttons("2_CRB_04", 914, 681, 953, 668, 4)       // GR_1024
298         }
299 #endif
300 //XSTR:ON
301 };
302
303 static int      Credits_music_handle = -1;
304 static int      Credits_music_begin_timestamp;
305
306 static int      Credits_frametime;              // frametime of credits_do_frame() loop in ms
307 static int      Credits_last_time;              // timestamp used to calc frametime (in ms)
308 static float Credits_counter;
309 static int Credits_artwork_index;
310 static int Credits_bmps[NUM_IMAGES];
311
312 char *Credit_text = NULL;
313 int Credit_text_malloced = 0;                   // TRUE if credit_text was malloced
314
315 // Positions for credits...
316 float Credit_start_pos, Credit_stop_pos, Credit_position = 0.0f;
317
318 void credits_stop_music()
319 {
320         if ( Credits_music_handle != -1 ) {
321                 audiostream_close_file(Credits_music_handle);
322                 Credits_music_handle = -1;
323         }
324 }
325
326 void credits_load_music(char* fname)
327 {
328         if ( Credits_music_handle != -1 ){
329                 return;
330         }
331
332         if ( fname ){
333                 Credits_music_handle = audiostream_open( fname, ASF_EVENTMUSIC );
334         }
335 }
336
337 void credits_start_music()
338 {
339         if (Credits_music_handle != -1) {
340                 if ( !audiostream_is_playing(Credits_music_handle) ){
341                         audiostream_play(Credits_music_handle, Master_event_music_volume);
342                 }
343         } else {
344                 nprintf(("Warning", "Cannot play credits music\n"));
345         }
346 }
347
348 int credits_screen_button_pressed(int n)
349 {
350         switch (n) {
351         case TECH_DATABASE_BUTTON:
352                 gamesnd_play_iface(SND_SWITCH_SCREENS);
353                 gameseq_post_event(GS_EVENT_TECH_MENU);
354                 return 1;
355
356         case SIMULATOR_BUTTON:
357                 gamesnd_play_iface(SND_SWITCH_SCREENS);
358                 gameseq_post_event(GS_EVENT_SIMULATOR_ROOM);
359                 return 1;
360
361         case CUTSCENES_BUTTON:
362                 gamesnd_play_iface(SND_SWITCH_SCREENS);
363                 gameseq_post_event(GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN);
364                 return 1;
365
366         case EXIT_BUTTON:
367                 gamesnd_play_iface(SND_COMMIT_PRESSED);
368                 gameseq_post_event(GS_EVENT_MAIN_MENU);
369                 game_flush();
370                 break;
371         }
372
373         return 0;
374 }
375
376 void credits_init()
377 {
378         int i, w, h;
379         credits_screen_buttons *b;
380         char line[512] = "";    
381         char *linep1, *linep2;  
382
383         int credits_spooled_music_index = event_music_get_spooled_music_index("Cinema");        
384         if(credits_spooled_music_index != -1){
385                 char *credits_wavfile_name = Spooled_music[credits_spooled_music_index].filename;               
386                 if(credits_wavfile_name != NULL){
387                         credits_load_music(credits_wavfile_name);
388                 }
389         }
390
391         // Use this id to trigger the start of music playing on the briefing screen
392         Credits_music_begin_timestamp = timestamp(CREDITS_MUSIC_DELAY);
393
394         Credits_frametime = 0;
395         Credits_last_time = timer_get_milliseconds();
396
397         Credit_text = NULL;
398         Credit_text_malloced = 0;
399
400         // allocate enough space for credits text
401         CFILE *fp = cfopen( NOX("credits.tbl"), "rb" );
402         if(fp != NULL){
403                 int size;
404                 size = cfilelength(fp);
405                 Credit_text = (char *) malloc(size + 200);
406                 Credit_text_malloced = 1;
407                 cfclose(fp);
408
409                 // open localization and parse
410                 lcl_ext_open();
411                 read_file_text("credits.tbl");
412                 reset_parse();
413
414                 // keep reading everything in
415                 strcpy(Credit_text,"");         
416 #ifndef MAKE_FS1
417                 while(!check_for_string_raw("#end")){
418 #else
419                 char *ugh = Mp;
420                 char ch;
421                 int line_count = 0;
422
423                 // get the line count, probably a crappy way to do it but it's the best way i've
424                 // found to step through the credits without crashing problems since there's no
425                 // definite end line in FS1
426                 while (*ugh && *ugh != EOF_CHAR) {
427                         ch = *ugh;
428
429                         if (ch == '\n'){
430                                 line_count++;
431                         }
432                         ugh++;
433                 }
434
435                 while(line_count > 0){
436                         line_count--;
437 #endif
438                         stuff_string_line(line, 511);
439                         linep1 = line;
440
441                         do {
442                                 linep2 = split_str_once(linep1, Credits_text_coords[gr_screen.res][2]);
443                                 strcat(Credit_text, linep1);
444                                 strcat(Credit_text, "\n");                      
445                                 linep1 = linep2;
446                         } while (linep2 != NULL);
447                 }               
448
449                 // close localization
450                 lcl_ext_close();        
451         } else {
452                 Credit_text = NOX("No credits available.\n");
453         }       
454
455         int ch;
456         for ( i = 0; Credit_text[i]; i++ ) {
457                         ch = Credit_text[i];
458                         switch (ch) {
459                         case -4:
460                                 ch = 129;
461                                 break;
462
463                         case -28:
464                                 ch = 132;
465                                 break;
466
467                         case -10:
468                                 ch = 148;
469                                 break;
470
471                         case -23:
472                                 ch = 130;
473                                 break;
474
475                         case -30:
476                                 ch = 131;
477                                 break;
478
479                         case -25:
480                                 ch = 135;
481                                 break;
482
483                         case -21:
484                                 ch = 137;
485                                 break;
486
487                         case -24:
488                                 ch = 138;
489                                 break;
490
491                         case -17:
492                                 ch = 139;
493                                 break;
494
495                         case -18:
496                                 ch = 140;
497                                 break;
498
499                         case -60:
500                                 ch = 142;
501                                 break;
502
503                         case -55:
504                                 ch = 144;
505                                 break;
506
507                         case -12:
508                                 ch = 147;
509                                 break;
510
511                         case -14:
512                                 ch = 149;
513                                 break;
514
515                         case -5:
516                                 ch = 150;
517                                 break;
518
519                         case -7:
520                                 ch = 151;
521                                 break;
522
523                         case -42:
524                                 ch = 153;
525                                 break;
526
527                         case -36:
528                                 ch = 154;
529                                 break;
530
531                         case -31:
532                                 ch = 160;
533                                 break;
534
535                         case -19:
536                                 ch = 161;
537                                 break;
538
539                         case -13:
540                                 ch = 162;
541                                 break;
542
543                         case -6:
544                                 ch = 163;
545                                 break;
546
547                         case -32:
548                                 ch = 133;
549                                 break;
550
551                         case -22:
552                                 ch = 136;
553                                 break;
554
555                         case -20:
556                                 ch = 141;
557                                 break;
558                         }
559                         Credit_text[i] = (char)ch;
560         }
561
562         gr_get_string_size(&w, &h, Credit_text);
563
564         Credit_start_pos = i2fl(Credits_text_coords[gr_screen.res][CREDITS_H_COORD]);
565         Credit_stop_pos = -i2fl(h);
566         Credit_position = Credit_start_pos;
567
568         Ui_window.create(0, 0, gr_screen.max_w, gr_screen.max_h, 0);
569         Ui_window.set_mask_bmap(Credits_bitmap_mask_fname[gr_screen.res]);
570         common_set_interface_palette("InterfacePalette");  // set the interface palette
571
572         for (i=0; i<NUM_BUTTONS; i++) {
573                 b = &Buttons[i][gr_screen.res];
574
575                 b->button.create(&Ui_window, "", b->x, b->y, 60, 30, (i < 2), 1);
576                 // set up callback for when a mouse first goes over a button
577                 b->button.set_highlight_action(common_play_highlight_sound);
578                 b->button.set_bmaps(b->filename);
579                 b->button.link_hotspot(b->hotspot);
580         }
581
582 #ifndef MAKE_FS1
583         // add some text
584         Ui_window.add_XSTR("Technical Database", 1055, Buttons[TECH_DATABASE_BUTTON][gr_screen.res].xt,  Buttons[TECH_DATABASE_BUTTON][gr_screen.res].yt, &Buttons[TECH_DATABASE_BUTTON][gr_screen.res].button, UI_XSTR_COLOR_GREEN);
585         Ui_window.add_XSTR("Mission Simulator", 1056, Buttons[SIMULATOR_BUTTON][gr_screen.res].xt,  Buttons[SIMULATOR_BUTTON][gr_screen.res].yt, &Buttons[SIMULATOR_BUTTON][gr_screen.res].button, UI_XSTR_COLOR_GREEN);
586         Ui_window.add_XSTR("Cutscenes", 1057, Buttons[CUTSCENES_BUTTON][gr_screen.res].xt,  Buttons[CUTSCENES_BUTTON][gr_screen.res].yt, &Buttons[CUTSCENES_BUTTON][gr_screen.res].button, UI_XSTR_COLOR_GREEN);
587         Ui_window.add_XSTR("Credits", 1058, Buttons[CREDITS_BUTTON][gr_screen.res].xt,  Buttons[CREDITS_BUTTON][gr_screen.res].yt, &Buttons[CREDITS_BUTTON][gr_screen.res].button, UI_XSTR_COLOR_GREEN);
588         Ui_window.add_XSTR("Exit", 1420, Buttons[EXIT_BUTTON][gr_screen.res].xt,  Buttons[EXIT_BUTTON][gr_screen.res].yt, &Buttons[EXIT_BUTTON][gr_screen.res].button, UI_XSTR_COLOR_PINK);
589 #endif
590
591         if (Player->flags & PLAYER_FLAGS_IS_MULTI) {
592                 Buttons[SIMULATOR_BUTTON][gr_screen.res].button.disable();
593                 Buttons[CUTSCENES_BUTTON][gr_screen.res].button.disable();
594         }
595
596         Buttons[EXIT_BUTTON][gr_screen.res].button.set_hotkey(KEY_CTRLED | KEY_ENTER);
597
598         Background_bitmap = bm_load(Credits_bitmap_fname[gr_screen.res]);
599         Credits_artwork_index = rand() % NUM_IMAGES;
600         for (i=0; i<NUM_IMAGES; i++){
601                 Credits_bmps[i] = -1;
602         }
603
604 #ifdef MAKE_FS1
605         CreditsWin01 = bm_load(NOX("CreditsWin01"));
606         CreditsWin02 = bm_load(NOX("CreditsWin02"));
607         CreditsWin03 = bm_load(NOX("CreditsWin03"));
608         CreditsWin04 = bm_load(NOX("CreditsWin04"));
609 #endif
610 }
611
612 void credits_close()
613 {       
614         int i;
615
616 #ifdef MAKE_FS1
617         if (CreditsWin01 != -1){
618                 bm_unload(CreditsWin01);
619                 CreditsWin01 = -1;
620         }
621         if (CreditsWin02 != -1){
622                 bm_unload(CreditsWin02);
623                 CreditsWin02 = -1;
624         }
625         if (CreditsWin03 != -1){
626                 bm_unload(CreditsWin03);
627                 CreditsWin03 = -1;
628         }
629         if (CreditsWin04 != -1){
630                 bm_unload(CreditsWin04);
631                 CreditsWin04 = -1;
632         }
633 #endif
634
635         for (i=0; i<NUM_IMAGES; i++){
636                 if (Credits_bmps[i] >= 0){
637                         bm_unload(Credits_bmps[i]);
638                         Credits_bmps[i] = -1;
639                 }
640         }       
641
642         credits_stop_music();
643
644         if (Credit_text) {
645                 if (Credit_text_malloced){
646                         free(Credit_text);
647                 }
648
649                 Credit_text = NULL;
650         }
651
652         if (Background_bitmap){
653                 bm_unload(Background_bitmap);
654         }
655
656         Ui_window.destroy();
657         common_free_interface_palette();                // restore game palette
658 }
659
660 void credits_do_frame(float frametime)
661 {
662         int i, k, next, percent, bm1, bm2;
663         int bx1, by1, bw1, bh1;
664         int bx2, by2, bw2, bh2;
665
666         // Use this id to trigger the start of music playing on the credits screen
667         if ( timestamp_elapsed(Credits_music_begin_timestamp) ) {
668                 Credits_music_begin_timestamp = 0;
669                 credits_start_music();
670         }
671
672         k = Ui_window.process();
673         switch (k) {
674         case KEY_ESC:
675                 gameseq_post_event(GS_EVENT_MAIN_MENU);
676                 key_flush();
677                 break;
678
679         case KEY_CTRLED | KEY_UP:
680         case KEY_SHIFTED | KEY_TAB:
681                 if ( !(Player->flags & PLAYER_FLAGS_IS_MULTI) ) {
682                         credits_screen_button_pressed(CUTSCENES_BUTTON);
683                         break;
684                 }
685                 // else, react like tab key.
686
687         case KEY_CTRLED | KEY_DOWN:
688         case KEY_TAB:
689                 credits_screen_button_pressed(TECH_DATABASE_BUTTON);
690                 break;
691
692         default:
693                 break;
694         } // end switch
695
696         for (i=0; i<NUM_BUTTONS; i++){
697                 if (Buttons[i][gr_screen.res].button.pressed()){
698                         if (credits_screen_button_pressed(i)){
699                                 return;
700                         }
701                 }
702         }
703
704         gr_reset_clip();        
705         GR_MAYBE_CLEAR_RES(Background_bitmap);
706         if (Background_bitmap >= 0) {
707                 gr_set_bitmap(Background_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
708                 gr_bitmap(0, 0);
709         } 
710
711         percent = (int) (100.0f - (CREDITS_ARTWORK_DISPLAY_TIME - Credits_counter) * 100.0f / CREDITS_ARTWORK_FADE_TIME);
712         if (percent < 0){
713                 percent = 0;
714         }
715
716         next = Credits_artwork_index + 1;
717         if (next >= NUM_IMAGES){
718                 next = 0;
719         }
720
721         if (Credits_bmps[Credits_artwork_index] < 0) {
722                 char buf[40];
723
724                 if (gr_screen.res == GR_1024) {
725                         sprintf(buf, NOX("2_CrIm%.2d"), Credits_artwork_index);
726                 } else {
727                         sprintf(buf, NOX("CrIm%.2d"), Credits_artwork_index);
728                 }
729                 Credits_bmps[Credits_artwork_index] = bm_load(buf);
730         }
731
732         if (Credits_bmps[next] < 0) {
733                 char buf[40];
734
735                 if (gr_screen.res == GR_1024) {
736                         sprintf(buf, NOX("2_CrIm%.2d"), Credits_artwork_index);
737                 } else {
738                         sprintf(buf, NOX("CrIm%.2d"), next);
739                 }
740                 Credits_bmps[next] = bm_load(buf);
741         }
742
743         bm1 = Credits_bmps[Credits_artwork_index];
744         bm2 = Credits_bmps[next];
745
746         if((bm1 != -1) && (bm2 != -1)){
747                 Assert(percent >= 0 && percent <= 100);
748
749                 // get width and height
750                 bm_get_info(bm1, &bw1, &bh1, NULL, NULL, NULL); 
751                 bm_get_info(bm2, &bw2, &bh2, NULL, NULL, NULL); 
752         
753                 // determine where to draw the coords
754                 bx1 = Credits_image_coords[gr_screen.res][CREDITS_X_COORD] + ((Credits_image_coords[gr_screen.res][CREDITS_W_COORD] - bw1)/2);
755                 by1 = Credits_image_coords[gr_screen.res][CREDITS_Y_COORD] + ((Credits_image_coords[gr_screen.res][CREDITS_H_COORD] - bh1)/2);
756                 bx2 = Credits_image_coords[gr_screen.res][CREDITS_X_COORD] + ((Credits_image_coords[gr_screen.res][CREDITS_W_COORD] - bw2)/2);
757                 by2 = Credits_image_coords[gr_screen.res][CREDITS_Y_COORD] + ((Credits_image_coords[gr_screen.res][CREDITS_H_COORD] - bh2)/2);
758
759                 gr_cross_fade(bm1, bm2, bx1, by1, bx2, by2, (float)percent / 100.0f);
760         }
761
762 #ifdef MAKE_FS1
763         if (CreditsWin01 != -1) {
764                 gr_set_bitmap(CreditsWin01);
765                 gr_bitmap(233, 5);
766         }
767
768         if (CreditsWin02 != -1) {
769                 gr_set_bitmap(CreditsWin02);
770                 gr_bitmap(616, 8);
771         }
772
773         if (CreditsWin03 != -1) {
774                 gr_set_bitmap(CreditsWin03);
775                 gr_bitmap(233, 299);
776         }
777
778         if (CreditsWin04 != -1) {
779                 gr_set_bitmap(CreditsWin04);
780                 gr_bitmap(215, 8);
781         }
782 #endif
783
784         Ui_window.draw();
785
786         for (i=TECH_DATABASE_BUTTON; i<=CREDITS_BUTTON; i++){
787                 if (Buttons[i][gr_screen.res].button.button_down()){
788                         break;
789                 }
790         }
791
792         if (i > CREDITS_BUTTON){
793                 Buttons[CREDITS_BUTTON][gr_screen.res].button.draw_forced(2);
794         }
795
796         gr_set_clip(Credits_text_coords[gr_screen.res][CREDITS_X_COORD], Credits_text_coords[gr_screen.res][CREDITS_Y_COORD], Credits_text_coords[gr_screen.res][CREDITS_W_COORD], Credits_text_coords[gr_screen.res][CREDITS_H_COORD]);
797         gr_set_font(FONT1);
798         gr_set_color_fast(&Color_normal);
799
800         int sy;
801         if ( Credit_position > 0 ) {
802                 sy = fl2i(Credit_position+0.5f);
803         } else {
804                 sy = fl2i(Credit_position-0.5f);
805         }
806
807         // HACK - I don't want to change the string code, so we'll just use a special version here
808         if(gr_screen.mode == GR_GLIDE){
809 #ifndef PLAT_UNIX
810                 extern void gr_glide_string_hack(int sx, int sy, char *s);
811                 gr_glide_string_hack(0x8000, sy, Credit_text);
812 #endif
813         } else {
814                 gr_string(0x8000, sy, Credit_text);
815         }
816
817         int temp_time;
818         temp_time = timer_get_milliseconds();
819
820         Credits_frametime = temp_time - Credits_last_time;
821         Credits_last_time = temp_time;
822         timestamp_inc(Credits_frametime / 1000.0f);
823
824         float fl_frametime = i2fl(Credits_frametime) / 1000.f;
825         if (keyd_pressed[KEY_LSHIFT]) {
826                 Credit_position -= fl_frametime * CREDITS_SCROLL_RATE * 4.0f;
827         } else {
828                 Credit_position -= fl_frametime * CREDITS_SCROLL_RATE;
829         }
830
831         if (Credit_position < Credit_stop_pos){
832                 Credit_position = Credit_start_pos;
833         }
834
835         Credits_counter += fl_frametime;
836         while (Credits_counter >= CREDITS_ARTWORK_DISPLAY_TIME) {
837                 Credits_counter -= CREDITS_ARTWORK_DISPLAY_TIME;
838                 Credits_artwork_index = next;
839         }
840
841         gr_flip();
842 }
843