]> icculus.org git repositories - btb/d2x.git/blob - main/movie.c
move change_filename_ext to strutil.c, rename to (and remove old) change_filename_ext...
[btb/d2x.git] / main / movie.c
1 /* $Id: movie.c,v 1.40 2006-02-26 02:29:06 chris Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  *
17  * Movie Playing Stuff
18  *
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <conf.h>
23 #endif
24
25 #ifdef RCS
26 static char rcsid[] = "$Id: movie.c,v 1.40 2006-02-26 02:29:06 chris Exp $";
27 #endif
28
29 #include <string.h>
30 #ifndef macintosh
31 # ifndef _WIN32_WCE
32 #  include <sys/types.h>
33 #  include <sys/stat.h>
34 #  include <fcntl.h>
35 # endif
36 # ifndef _MSC_VER
37 #  include <unistd.h>
38 # endif
39 #endif // ! macintosh
40 #include <ctype.h>
41
42 #include "movie.h"
43 #include "console.h"
44 #include "args.h"
45 #include "key.h"
46 #include "digi.h"
47 #include "songs.h"
48 #include "inferno.h"
49 #include "palette.h"
50 #include "strutil.h"
51 #include "error.h"
52 #include "u_mem.h"
53 #include "byteswap.h"
54 #include "gr.h"
55 #include "gamefont.h"
56 #include "cfile.h"
57 #include "menu.h"
58 #include "libmve.h"
59 #include "text.h"
60 #include "screens.h"
61 #include "physfsrwops.h"
62
63 extern int MenuHiresAvailable;
64 extern char CDROM_dir[];
65
66 #define VID_PLAY 0
67 #define VID_PAUSE 1
68
69 int Vid_State;
70
71
72 // Subtitle data
73 typedef struct {
74         short first_frame,last_frame;
75         char *msg;
76 } subtitle;
77
78 #define MAX_SUBTITLES 500
79 #define MAX_ACTIVE_SUBTITLES 3
80 subtitle Subtitles[MAX_SUBTITLES];
81 int Num_subtitles;
82
83 // Movielib data
84
85 #ifdef D2_OEM
86 char movielib_files[5][FILENAME_LEN] = {"intro","other","robots","oem"};
87 #else
88 char movielib_files[4][FILENAME_LEN] = {"intro","other","robots"};
89 #endif
90
91 #define N_MOVIE_LIBS (sizeof(movielib_files) / sizeof(*movielib_files))
92 #define N_BUILTIN_MOVIE_LIBS (N_MOVIE_LIBS - 1)
93 #define EXTRA_ROBOT_LIB N_BUILTIN_MOVIE_LIBS
94
95 int MovieHires = 1;   //default is highres
96
97 SDL_RWops *RoboFile;
98
99 // Function Prototypes
100 int RunMovie(char *filename, int highres_flag, int allow_abort,int dx,int dy);
101
102 void decode_text_line(char *p);
103 void draw_subtitles(int frame_num);
104
105
106 // ----------------------------------------------------------------------
107 void* MPlayAlloc(unsigned size)
108 {
109     return d_malloc(size);
110 }
111
112 void MPlayFree(void *p)
113 {
114     d_free(p);
115 }
116
117
118 //-----------------------------------------------------------------------
119
120 unsigned int FileRead(void *handle, void *buf, unsigned int count)
121 {
122     unsigned numread;
123     numread = SDL_RWread((SDL_RWops *)handle, buf, 1, count);
124     return (numread == count);
125 }
126
127
128 //-----------------------------------------------------------------------
129
130
131 //filename will actually get modified to be either low-res or high-res
132 //returns status.  see values in movie.h
133 int PlayMovie(const char *filename, int must_have)
134 {
135         char name[FILENAME_LEN],*p;
136         int c, ret;
137
138         if (FindArg("-nomovies"))
139                 return MOVIE_NOT_PLAYED;
140
141         strcpy(name,filename);
142
143         if ((p=strchr(name,'.')) == NULL)               //add extension, if missing
144                 strcat(name,".mve");
145
146         //check for escape already pressed & abort if so
147         while ((c=key_inkey()) != 0)
148                 if (c == KEY_ESC)
149                         return MOVIE_ABORTED;
150
151         // Stop all digital sounds currently playing.
152         digi_stop_all();
153
154         // Stop all songs
155         songs_stop_all();
156
157         digi_close();
158
159         // Start sound
160         if (!FindArg("-nosound"))
161                 MVE_sndInit(1);
162         else
163                 MVE_sndInit(-1);
164
165         ret = RunMovie(name,MovieHires,must_have,-1,-1);
166
167         if (!FindArg("-nosound"))
168                 digi_init();
169
170         Screen_mode = -1;               //force screen reset
171
172         return ret;
173 }
174
175
176 void MovieShowFrame(ubyte *buf, uint bufw, uint bufh, uint sx, uint sy,
177                                         uint w, uint h, uint dstx, uint dsty)
178 {
179         grs_bitmap source_bm;
180
181         //mprintf((0,"MovieShowFrame %d,%d  %d,%d  %d,%d  %d,%d\n",bufw,bufh,sx,sy,w,h,dstx,dsty));
182
183         Assert(bufw == w && bufh == h);
184
185         source_bm.bm_x = source_bm.bm_y = 0;
186         source_bm.bm_w = source_bm.bm_rowsize = bufw;
187         source_bm.bm_h = bufh;
188         source_bm.bm_type = BM_LINEAR;
189         source_bm.bm_flags = 0;
190         source_bm.bm_data = buf;
191
192         gr_bm_ubitblt(bufw,bufh,dstx,dsty,sx,sy,&source_bm,&grd_curcanv->cv_bitmap);
193 }
194
195 //our routine to set the pallete, called from the movie code
196 void MovieSetPalette(unsigned char *p, unsigned start, unsigned count)
197 {
198         if (count == 0)
199                 return;
200
201         //mprintf((0,"SetPalette p=%x, start=%d, count=%d\n",p,start,count));
202
203         //Color 0 should be black, and we get color 255
204         Assert(start>=1 && start+count-1<=254);
205
206         //Set color 0 to be black
207         gr_palette[0] = gr_palette[1] = gr_palette[2] = 0;
208
209         //Set color 255 to be our subtitle color
210         gr_palette[765] = gr_palette[766] = gr_palette[767] = 50;
211
212         //movie libs palette into our array
213         memcpy(gr_palette+start*3,p+start*3,count*3);
214
215         //finally set the palette in the hardware
216         //gr_palette_load(gr_palette);
217
218         //MVE_SetPalette(p, start, count);
219 }
220
221
222 #if 0
223 typedef struct bkg {
224         short x, y, w, h;           // The location of the menu.
225         grs_bitmap * bmp;               // The background under the menu.
226 } bkg;
227
228 bkg movie_bg = {0,0,0,0,NULL};
229 #endif
230
231 #define BOX_BORDER (MenuHires?40:20)
232
233
234 void show_pause_message(char *msg)
235 {
236         int w,h,aw;
237         int x,y;
238
239         gr_set_current_canvas(NULL);
240         gr_set_curfont( SMALL_FONT );
241
242         gr_get_string_size(msg,&w,&h,&aw);
243
244         x = (grd_curscreen->sc_w-w)/2;
245         y = (grd_curscreen->sc_h-h)/2;
246
247 #if 0
248         if (movie_bg.bmp) {
249                 gr_free_bitmap(movie_bg.bmp);
250                 movie_bg.bmp = NULL;
251         }
252
253         // Save the background of the display
254         movie_bg.x=x; movie_bg.y=y; movie_bg.w=w; movie_bg.h=h;
255
256         movie_bg.bmp = gr_create_bitmap( w+BOX_BORDER, h+BOX_BORDER );
257
258         gr_bm_ubitblt(w+BOX_BORDER, h+BOX_BORDER, 0, 0, x-BOX_BORDER/2, y-BOX_BORDER/2, &(grd_curcanv->cv_bitmap), movie_bg.bmp );
259 #endif
260
261         gr_setcolor(0);
262         gr_rect(x-BOX_BORDER/2,y-BOX_BORDER/2,x+w+BOX_BORDER/2-1,y+h+BOX_BORDER/2-1);
263
264         gr_set_fontcolor( 255, -1 );
265
266         gr_ustring( 0x8000, y, msg );
267
268         gr_update();
269 }
270
271 void clear_pause_message()
272 {
273 #if 0
274         if (movie_bg.bmp) {
275
276                 gr_bitmap(movie_bg.x-BOX_BORDER/2, movie_bg.y-BOX_BORDER/2, movie_bg.bmp);
277
278                 gr_free_bitmap(movie_bg.bmp);
279                 movie_bg.bmp = NULL;
280         }
281 #endif
282 }
283
284
285 //returns status.  see movie.h
286 int RunMovie(char *filename, int hires_flag, int must_have,int dx,int dy)
287 {
288         SDL_RWops *filehndl;
289         int result=1,aborted=0;
290         int track = 0;
291         int frame_num;
292         int key;
293 #ifdef OGL
294         ubyte pal_save[768];
295 #endif
296
297         result=1;
298
299         // Open Movie file.  If it doesn't exist, no movie, just return.
300
301         filehndl = PHYSFSRWOPS_openRead(filename);
302
303         if (!filehndl)
304         {
305                 if (must_have)
306                         con_printf(CON_URGENT, "Can't open movie <%s>: %s\n", filename, PHYSFS_getLastError());
307                 return MOVIE_NOT_PLAYED;
308         }
309
310         MVE_memCallbacks(MPlayAlloc, MPlayFree);
311         MVE_ioCallbacks(FileRead);
312
313         if (hires_flag) {
314                 gr_set_mode(SM(640,480));
315         } else {
316                 gr_set_mode(SM(320,200));
317         }
318 #ifdef OGL
319         set_screen_mode(SCREEN_MENU);
320         gr_copy_palette(pal_save, gr_palette, 768);
321         memset(gr_palette, 0, 768);
322         gr_palette_load(gr_palette);
323 #endif
324
325         MVE_sfCallbacks(MovieShowFrame);
326         MVE_palCallbacks(MovieSetPalette);
327
328         if (MVE_rmPrepMovie((void *)filehndl, dx, dy, track)) {
329                 Int3();
330                 return MOVIE_NOT_PLAYED;
331         }
332
333         MVE_sfCallbacks(MovieShowFrame);
334         MVE_palCallbacks(MovieSetPalette);
335
336         frame_num = 0;
337
338         FontHires = FontHiresAvailable && hires_flag;
339
340         while((result = MVE_rmStepMovie()) == 0) {
341
342                 draw_subtitles(frame_num);
343
344                 gr_palette_load(gr_palette); // moved this here because of flashing
345
346                 gr_update();
347
348                 key = key_inkey();
349
350                 // If ESCAPE pressed, then quit movie.
351                 if (key == KEY_ESC) {
352                         result = aborted = 1;
353                         break;
354                 }
355
356                 // If PAUSE pressed, then pause movie
357                 if (key == KEY_PAUSE) {
358                         MVE_rmHoldMovie();
359                         show_pause_message(TXT_PAUSE);
360                         while (!key_inkey()) ;
361                         clear_pause_message();
362                 }
363
364 #ifdef GR_SUPPORTS_FULLSCREEN_TOGGLE
365                 if ((key == KEY_ALTED+KEY_ENTER) ||
366                     (key == KEY_ALTED+KEY_PADENTER))
367                         gr_toggle_fullscreen();
368 #endif
369
370                 frame_num++;
371         }
372
373         Assert(aborted || result == MVE_ERR_EOF);        ///movie should be over
374
375     MVE_rmEndMovie();
376
377         SDL_FreeRW(filehndl);                           // Close Movie File
378
379         // Restore old graphic state
380
381         Screen_mode=-1;  //force reset of screen mode
382 #ifdef OGL
383         gr_copy_palette(gr_palette, pal_save, 768);
384         gr_palette_load(pal_save);
385 #endif
386
387         return (aborted?MOVIE_ABORTED:MOVIE_PLAYED_FULL);
388 }
389
390
391 int InitMovieBriefing()
392 {
393 #if 0
394         if (MenuHires)
395                 gr_set_mode(SM(640,480));
396         else
397                 gr_set_mode(SM(320,200));
398
399         gr_init_sub_canvas( &VR_screen_pages[0], &grd_curscreen->sc_canvas, 0, 0, grd_curscreen->sc_w, grd_curscreen->sc_h );
400         gr_init_sub_canvas( &VR_screen_pages[1], &grd_curscreen->sc_canvas, 0, 0, grd_curscreen->sc_w, grd_curscreen->sc_h );
401 #endif
402
403         return 1;
404 }
405
406
407 //returns 1 if frame updated ok
408 int RotateRobot()
409 {
410         int err;
411
412         err = MVE_rmStepMovie();
413
414         gr_palette_load(gr_palette);
415
416         if (err == MVE_ERR_EOF)     //end of movie, so reset
417         {
418                 SDL_RWseek(RoboFile, 0, SEEK_SET);
419                 if (MVE_rmPrepMovie(RoboFile, MenuHires?280:140, MenuHires?200:80, 0))
420                 {
421                         Int3();
422                         return 0;
423                 }
424         }
425         else if (err) {
426                 Int3();
427                 return 0;
428         }
429
430         return 1;
431 }
432
433
434 void DeInitRobotMovie(void)
435 {
436         MVE_rmEndMovie();
437         SDL_FreeRW(RoboFile);                           // Close Movie File
438 }
439
440
441 int InitRobotMovie(char *filename)
442 {
443         if (FindArg("-nomovies"))
444                 return 0;
445
446         con_printf(CON_DEBUG, "RoboFile=%s\n", filename);
447
448         MVE_sndInit(-1);        //tell movies to play no sound for robots
449
450         RoboFile = PHYSFSRWOPS_openRead(filename);
451
452         if (!RoboFile)
453         {
454                 con_printf(CON_URGENT, "Can't open movie <%s>: %s\n", filename, PHYSFS_getLastError());
455                 return MOVIE_NOT_PLAYED;
456         }
457
458         Vid_State = VID_PLAY;
459
460         if (MVE_rmPrepMovie((void *)RoboFile, MenuHires?280:140, MenuHires?200:80, 0)) {
461                 Int3();
462                 return 0;
463         }
464
465         return 1;
466 }
467
468
469 /*
470  *              Subtitle system code
471  */
472
473 char *subtitle_raw_data;
474
475
476 //search for next field following whitespace 
477 char *next_field (char *p)
478 {
479         while (*p && !isspace(*p))
480                 p++;
481
482         if (!*p)
483                 return NULL;
484
485         while (*p && isspace(*p))
486                 p++;
487
488         if (!*p)
489                 return NULL;
490
491         return p;
492 }
493
494
495 int init_subtitles(char *filename)
496 {
497         CFILE *ifile;
498         int size,read_count;
499         char *p;
500         int have_binary = 0;
501
502         Num_subtitles = 0;
503
504         if (! FindArg("-subtitles"))
505                 return 0;
506
507         ifile = cfopen(filename,"rb");          //try text version
508
509         if (!ifile) {                                                           //no text version, try binary version
510                 char filename2[FILENAME_LEN];
511                 change_filename_extension(filename2, filename, ".TXB");
512                 ifile = cfopen(filename2,"rb");
513                 if (!ifile)
514                         return 0;
515                 have_binary = 1;
516         }
517
518         size = cfilelength(ifile);
519
520         MALLOC (subtitle_raw_data, char, size+1);
521
522         read_count = cfread(subtitle_raw_data, 1, size, ifile);
523
524         cfclose(ifile);
525
526         subtitle_raw_data[size] = 0;
527
528         if (read_count != size) {
529                 d_free(subtitle_raw_data);
530                 return 0;
531         }
532
533         p = subtitle_raw_data;
534
535         while (p && p < subtitle_raw_data+size) {
536                 char *endp;
537
538                 endp = strchr(p,'\n'); 
539                 if (endp) {
540                         if (endp[-1] == '\r')
541                                 endp[-1] = 0;           //handle 0d0a pair
542                         *endp = 0;                      //string termintor
543                 }
544
545                 if (have_binary)
546                         decode_text_line(p);
547
548                 if (*p != ';') {
549                         Subtitles[Num_subtitles].first_frame = atoi(p);
550                         p = next_field(p); if (!p) continue;
551                         Subtitles[Num_subtitles].last_frame = atoi(p);
552                         p = next_field(p); if (!p) continue;
553                         Subtitles[Num_subtitles].msg = p;
554
555                         Assert(Num_subtitles==0 || Subtitles[Num_subtitles].first_frame >= Subtitles[Num_subtitles-1].first_frame);
556                         Assert(Subtitles[Num_subtitles].last_frame >= Subtitles[Num_subtitles].first_frame);
557
558                         Num_subtitles++;
559                 }
560
561                 p = endp+1;
562
563         }
564
565         return 1;
566 }
567
568
569 void close_subtitles()
570 {
571         if (subtitle_raw_data)
572                 d_free(subtitle_raw_data);
573         subtitle_raw_data = NULL;
574         Num_subtitles = 0;
575 }
576
577
578 //draw the subtitles for this frame
579 void draw_subtitles(int frame_num)
580 {
581         static int active_subtitles[MAX_ACTIVE_SUBTITLES];
582         static int num_active_subtitles,next_subtitle,line_spacing;
583         int t,y;
584         int must_erase=0;
585
586         if (frame_num == 0) {
587                 num_active_subtitles = 0;
588                 next_subtitle = 0;
589                 gr_set_curfont( GAME_FONT );
590                 line_spacing = grd_curcanv->cv_font->ft_h + (grd_curcanv->cv_font->ft_h >> 2);
591                 gr_set_fontcolor(255,-1);
592         }
593
594         //get rid of any subtitles that have expired
595         for (t=0;t<num_active_subtitles;)
596                 if (frame_num > Subtitles[active_subtitles[t]].last_frame) {
597                         int t2;
598                         for (t2=t;t2<num_active_subtitles-1;t2++)
599                                 active_subtitles[t2] = active_subtitles[t2+1];
600                         num_active_subtitles--;
601                         must_erase = 1;
602                 }
603                 else
604                         t++;
605
606         //get any subtitles new for this frame 
607         while (next_subtitle < Num_subtitles && frame_num >= Subtitles[next_subtitle].first_frame) {
608                 if (num_active_subtitles >= MAX_ACTIVE_SUBTITLES)
609                         Error("Too many active subtitles!");
610                 active_subtitles[num_active_subtitles++] = next_subtitle;
611                 next_subtitle++;
612         }
613
614         //find y coordinate for first line of subtitles
615         y = grd_curcanv->cv_bitmap.bm_h-((line_spacing+1)*MAX_ACTIVE_SUBTITLES+2);
616
617         //erase old subtitles if necessary
618         if (must_erase) {
619                 gr_setcolor(0);
620                 gr_rect(0,y,grd_curcanv->cv_bitmap.bm_w-1,grd_curcanv->cv_bitmap.bm_h-1);
621         }
622
623         //now draw the current subtitles
624         for (t=0;t<num_active_subtitles;t++)
625                 if (active_subtitles[t] != -1) {
626                         gr_string(0x8000,y,Subtitles[active_subtitles[t]].msg);
627                         y += line_spacing+1;
628                 }
629 }
630
631
632 void close_movie(char *movielib, int is_robots)
633 {
634         int high_res;
635         char filename[FILENAME_LEN];
636
637         if (is_robots)
638                 high_res = MenuHiresAvailable;
639         else
640                 high_res = MovieHires;
641
642         sprintf(filename, "%s-%s.mvl", movielib, high_res?"h":"l");
643
644         if (!cfile_close(filename))
645         {
646                 con_printf(CON_URGENT, "Can't close movielib <%s>: %s\n", filename, PHYSFS_getLastError());
647                 sprintf(filename, "%s-%s.mvl", movielib, high_res?"l":"h");
648
649                 if (!cfile_close(filename))
650                         con_printf(CON_URGENT, "Can't close movielib <%s>: %s\n", filename, PHYSFS_getLastError());
651         }
652 }
653
654 void close_movies()
655 {
656         int i, is_robots;
657
658         for (i = 0 ; i < N_BUILTIN_MOVIE_LIBS ; i++)
659         {
660                 if (!strnicmp(movielib_files[i], "robot", 5))
661                         is_robots = 1;
662                 else
663                         is_robots = 0;
664
665                 close_movie(movielib_files[i], is_robots);
666         }
667 }
668
669
670 //ask user to put the D2 CD in.
671 //returns -1 if ESC pressed, 0 if OK chosen
672 //CD may not have been inserted
673 int request_cd(void)
674 {
675 #if 0
676         ubyte save_pal[256*3];
677         grs_canvas *save_canv,*tcanv;
678         int ret,was_faded=gr_palette_faded_out;
679
680         gr_palette_clear();
681
682         save_canv = grd_curcanv;
683         tcanv = gr_create_canvas(grd_curcanv->cv_w,grd_curcanv->cv_h);
684
685         gr_set_current_canvas(tcanv);
686         gr_ubitmap(0,0,&save_canv->cv_bitmap);
687         gr_set_current_canvas(save_canv);
688
689         gr_clear_canvas(BM_XRGB(0,0,0));
690
691         memcpy(save_pal,gr_palette,sizeof(save_pal));
692
693         memcpy(gr_palette,last_palette_for_color_fonts,sizeof(gr_palette));
694
695  try_again:;
696
697         ret = nm_messagebox( "CD ERROR", 1, "Ok", "Please insert your Descent II CD");
698
699         if (ret == -1) {
700                 int ret2;
701
702                 ret2 = nm_messagebox( "CD ERROR", 2, "Try Again", "Leave Game", "You must insert your\nDescent II CD to Continue");
703
704                 if (ret2 == -1 || ret2 == 0)
705                         goto try_again;
706         }
707
708         force_rb_register = 1;  //disc has changed; force register new CD
709
710         gr_palette_clear();
711
712         memcpy(gr_palette,save_pal,sizeof(save_pal));
713
714         gr_ubitmap(0,0,&tcanv->cv_bitmap);
715
716         if (!was_faded)
717                 gr_palette_load(gr_palette);
718
719         gr_free_canvas(tcanv);
720
721         return ret;
722 #else
723         con_printf(CON_DEBUG, "STUB: movie: request_cd\n");
724         return 0;
725 #endif
726 }
727
728
729 void init_movie(char *movielib, int is_robots, int required)
730 {
731         int high_res;
732         char filename[FILENAME_LEN];
733
734         //for robots, load highres versions if highres menus set
735         if (is_robots)
736                 high_res = MenuHiresAvailable;
737         else
738                 high_res = MovieHires;
739
740         sprintf(filename, "%s-%s.mvl", movielib, high_res?"h":"l");
741
742         if (!cfile_init(filename))
743         {
744                 if (required)
745                         con_printf(CON_URGENT, "Can't open movielib <%s>: %s\n", filename, PHYSFS_getLastError());
746
747                 sprintf(filename, "%s-%s.mvl", movielib, high_res?"l":"h");
748
749                 if (!cfile_init(filename))
750                         if (required)
751                                 con_printf(CON_URGENT, "Can't open movielib <%s>: %s\n", filename, PHYSFS_getLastError());
752         }
753 }
754
755
756 //find and initialize the movie libraries
757 void init_movies()
758 {
759         int i;
760         int is_robots;
761
762         if (FindArg("-nomovies"))
763                 return;
764
765         for (i=0;i<N_BUILTIN_MOVIE_LIBS;i++) {
766
767                 if (!strnicmp(movielib_files[i],"robot",5))
768                         is_robots = 1;
769                 else
770                         is_robots = 0;
771
772                 init_movie(movielib_files[i], is_robots, 1);
773         }
774
775         atexit(close_movies);
776 }
777
778
779 void close_extra_robot_movie(void)
780 {
781         if (strlen(movielib_files[EXTRA_ROBOT_LIB]))
782                 if (!cfile_close(movielib_files[EXTRA_ROBOT_LIB]))
783                         con_printf(CON_URGENT, "Can't close robot movielib: %s\n", PHYSFS_getLastError());
784 }
785
786 void init_extra_robot_movie(char *movielib)
787 {
788         if (FindArg("-nomovies"))
789                 return;
790
791         close_extra_robot_movie();
792         init_movie(movielib, 1, 0);
793         strcpy(movielib_files[EXTRA_ROBOT_LIB], movielib);
794         atexit(close_extra_robot_movie);
795 }