]> icculus.org git repositories - btb/d2x.git/blob - main/movie.c
many improvements to mve code. Fixes (at least) bugs #41, #348, #350, and #359.
[btb/d2x.git] / main / movie.c
1 /* $Id: movie.c,v 1.17 2003-02-18 07:05:14 btb 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 #ifdef HAVE_CONFIG_H
16 #include <conf.h>
17 #endif
18
19 #ifdef RCS
20 static char rcsid[] = "$Id: movie.c,v 1.17 2003-02-18 07:05:14 btb Exp $";
21 #endif
22
23 #define DEBUG_LEVEL CON_NORMAL
24
25 #include <string.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <ctype.h>
31
32 #include "movie.h"
33 #include "console.h"
34 #include "args.h"
35 #include "key.h"
36 #include "digi.h"
37 #include "songs.h"
38 #include "inferno.h"
39 #include "palette.h"
40 #include "strutil.h"
41 #include "error.h"
42 #include "u_mem.h"
43 #include "byteswap.h"
44 #include "gr.h"
45 #include "gamefont.h"
46 #include "cfile.h"
47 #include "menu.h"
48 #include "mveplay.h"
49 #include "text.h"
50 #include "fileutil.h"
51
52 extern int MenuHiresAvailable;
53 extern char CDROM_dir[];
54
55 #define VID_PLAY 0
56 #define VID_PAUSE 1
57
58 int Vid_State;
59
60
61 // Subtitle data
62 typedef struct {
63         short first_frame,last_frame;
64         char *msg;
65 } subtitle;
66
67 #define MAX_SUBTITLES 500
68 #define MAX_ACTIVE_SUBTITLES 3
69 subtitle Subtitles[MAX_SUBTITLES];
70 int Num_subtitles;
71
72
73 // Movielib data
74 typedef struct {
75         char name[FILENAME_LEN];
76         int offset,len;
77 } ml_entry;
78
79 #define MLF_ON_CD    1
80 #define MAX_MOVIES_PER_LIB    50    //determines size of malloc
81
82 typedef struct {
83         char     name[100]; //[FILENAME_LEN];
84         int      n_movies;
85         ubyte    flags,pad[3];
86         ml_entry *movies;
87 } movielib;
88
89 #ifdef D2_OEM
90 char movielib_files[][FILENAME_LEN] = {"intro-l.mvl","other-l.mvl","robots-l.mvl","oem-l.mvl"};
91 #else
92 char movielib_files[][FILENAME_LEN] = {"intro-l.mvl","other-l.mvl","robots-l.mvl"};
93 #endif
94
95 #define N_BUILTIN_MOVIE_LIBS (sizeof(movielib_files)/sizeof(*movielib_files))
96 #define N_MOVIE_LIBS (N_BUILTIN_MOVIE_LIBS+1)
97 #define EXTRA_ROBOT_LIB N_BUILTIN_MOVIE_LIBS
98 movielib *movie_libs[N_MOVIE_LIBS];
99
100
101 //do we have the robot movies available
102 int robot_movies = 0; //0 means none, 1 means lowres, 2 means hires
103
104 int MovieHires = 0;   //default for now is lores
105
106 int RoboFile = 0, RoboFilePos = 0;
107
108 // Function Prototypes
109 int RunMovie(char *filename, int highres_flag, int allow_abort,int dx,int dy);
110
111 int open_movie_file(char *filename,int must_have);
112 int reset_movie_file(int handle);
113
114 void change_filename_ext( char *dest, char *src, char *ext );
115 void decode_text_line(char *p);
116 void draw_subtitles(int frame_num);
117
118
119 //-----------------------------------------------------------------------
120
121
122 //filename will actually get modified to be either low-res or high-res
123 //returns status.  see values in movie.h
124 int PlayMovie(const char *filename, int must_have)
125 {
126         char name[FILENAME_LEN],*p;
127         int c, ret;
128
129 #ifndef RELEASE
130         if (FindArg("-nomovies"))
131                 return MOVIE_NOT_PLAYED;
132 #endif
133
134         strcpy(name,filename);
135
136         if ((p=strchr(name,'.')) == NULL)               //add extension, if missing
137                 strcat(name,".mve");
138
139         //check for escape already pressed & abort if so
140         while ((c=key_inkey()) != 0)
141                 if (c == KEY_ESC)
142                         return MOVIE_ABORTED;
143
144         // Stop all digital sounds currently playing.
145         digi_stop_all();
146
147         // Stop all songs
148         songs_stop_all();
149
150         digi_close();
151
152         ret = RunMovie(name,MovieHires,must_have,-1,-1);
153
154         if (!FindArg("-nosound"))
155                 digi_init();
156
157         Screen_mode = -1;               //force screen reset
158
159         return ret;
160 }
161
162
163 #if 0
164 typedef struct bkg {
165         short x, y, w, h;           // The location of the menu.
166         grs_bitmap * bmp;               // The background under the menu.
167 } bkg;
168
169 bkg movie_bg = {0,0,0,0,NULL};
170 #endif
171
172 #define BOX_BORDER (MenuHires?40:20)
173
174
175 void show_pause_message(char *msg)
176 {
177         int w,h,aw;
178         int x,y;
179
180         gr_set_current_canvas(NULL);
181         gr_set_curfont( SMALL_FONT );
182
183         gr_get_string_size(msg,&w,&h,&aw);
184
185         x = (grd_curscreen->sc_w-w)/2;
186         y = (grd_curscreen->sc_h-h)/2;
187
188 #if 0
189         if (movie_bg.bmp) {
190                 gr_free_bitmap(movie_bg.bmp);
191                 movie_bg.bmp = NULL;
192         }
193
194         // Save the background of the display
195         movie_bg.x=x; movie_bg.y=y; movie_bg.w=w; movie_bg.h=h;
196
197         movie_bg.bmp = gr_create_bitmap( w+BOX_BORDER, h+BOX_BORDER );
198
199         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 );
200 #endif
201
202         gr_setcolor(0);
203         gr_rect(x-BOX_BORDER/2,y-BOX_BORDER/2,x+w+BOX_BORDER/2-1,y+h+BOX_BORDER/2-1);
204
205         gr_set_fontcolor( 255, -1 );
206
207         gr_ustring( 0x8000, y, msg );
208
209         gr_update();
210 }
211
212 void clear_pause_message()
213 {
214 #if 0
215         if (movie_bg.bmp) {
216
217                 gr_bitmap(movie_bg.x-BOX_BORDER/2, movie_bg.y-BOX_BORDER/2, movie_bg.bmp);
218
219                 gr_free_bitmap(movie_bg.bmp);
220                 movie_bg.bmp = NULL;
221         }
222 #endif
223 }
224
225
226 //returns status.  see movie.h
227 int RunMovie(char *filename, int hires_flag, int must_have,int dx,int dy)
228 {
229         int filehndl;
230         int result=1,aborted=0;
231         int track = 0;
232         int frame_num;
233         int key;
234
235         result=1;
236
237         // Open Movie file.  If it doesn't exist, no movie, just return.
238
239         filehndl = open_movie_file(filename,must_have);
240
241         if (filehndl == -1) {
242                 if (must_have)
243                         Warning("movie: RunMovie: Cannot open movie <%s>\n",filename);
244                 return MOVIE_NOT_PLAYED;
245         }
246
247         if (hires_flag) {
248                 gr_set_mode(SM(640,480));
249         } else {
250                 gr_set_mode(SM(320,200));
251         }
252
253         if (MVE_rmPrepMovie(filehndl, dx, dy, track)) {
254                 Int3();
255                 return MOVIE_NOT_PLAYED;
256         }
257
258         frame_num = 0;
259
260         FontHires = FontHiresAvailable && hires_flag;
261
262         while((result = MVE_rmStepMovie()) == 0) {
263
264                 draw_subtitles(frame_num);
265
266                 gr_update();
267
268                 key = key_inkey();
269
270                 // If ESCAPE pressed, then quit movie.
271                 if (key == KEY_ESC) {
272                         result = aborted = 1;
273                         break;
274                 }
275
276                 // If PAUSE pressed, then pause movie
277                 if (key == KEY_PAUSE) {
278                         MVE_rmHoldMovie();
279                         show_pause_message(TXT_PAUSE);
280                         while (!key_inkey()) ;
281                         clear_pause_message();
282                 }
283
284 #ifdef GR_SUPPORTS_FULLSCREEN_TOGGLE
285                 if ((key == KEY_CTRLED+KEY_SHIFTED+KEY_PADENTER) ||
286                         (key == KEY_ALTED+KEY_CTRLED+KEY_PADENTER) ||
287                         (key == KEY_ALTED+KEY_SHIFTED+KEY_PADENTER))
288                         gr_toggle_fullscreen();
289 #endif
290
291                 frame_num++;
292         }
293
294         Assert(aborted || result == MVE_ERR_EOF);        ///movie should be over
295
296     MVE_rmEndMovie();
297
298         close(filehndl);                           // Close Movie File
299
300         // Restore old graphic state
301
302         Screen_mode=-1;  //force reset of screen mode
303
304         return (aborted?MOVIE_ABORTED:MOVIE_PLAYED_FULL);
305 }
306
307
308 int InitMovieBriefing()
309 {
310         if (MenuHires)
311                 gr_set_mode(SM(640,480));
312         else
313                 gr_set_mode(SM(320,200));
314
315         return 1;
316 }
317
318
319 //returns 1 if frame updated ok
320 int RotateRobot()
321 {
322         int err;
323
324         err = MVE_rmStepMovie();
325
326         if (err == MVE_ERR_EOF)     //end of movie, so reset
327         {
328                 reset_movie_file(RoboFile);
329                 if (MVE_rmPrepMovie(RoboFile, MenuHires?280:140, MenuHires?200:80, 0)) {
330                         Int3();
331                         return 0;
332                 }
333         }
334         else if (err) {
335                 Int3();
336                 return 0;
337         }
338
339         return 1;
340 }
341
342
343 void DeInitRobotMovie(void)
344 {
345         MVE_rmEndMovie();
346         close(RoboFile);                           // Close Movie File
347 }
348
349
350 int InitRobotMovie(char *filename)
351 {
352         if (FindArg("-nomovies"))
353                 return 0;
354
355         con_printf(DEBUG_LEVEL, "RoboFile=%s\n", filename);
356
357         RoboFile = open_movie_file(filename, 1);
358
359         if (RoboFile == -1) {
360                 Warning("movie: InitRobotMovie: Cannot open movie file <%s>",filename);
361                 return MOVIE_NOT_PLAYED;
362         }
363
364         Vid_State = VID_PLAY;
365
366         if (MVE_rmPrepMovie(RoboFile, MenuHires?280:140, MenuHires?200:80, 0)) {
367                 Int3();
368                 return 0;
369         }
370
371         RoboFilePos=lseek (RoboFile,0L,SEEK_CUR);
372
373         con_printf(DEBUG_LEVEL, "RoboFilePos=%d!\n", RoboFilePos);
374
375         return 1;
376 }
377
378
379 /*
380  *              Subtitle system code
381  */
382
383 ubyte *subtitle_raw_data;
384
385
386 //search for next field following whitespace 
387 ubyte *next_field(ubyte *p)
388 {
389         while (*p && !isspace(*p))
390                 p++;
391
392         if (!*p)
393                 return NULL;
394
395         while (*p && isspace(*p))
396                 p++;
397
398         if (!*p)
399                 return NULL;
400
401         return p;
402 }
403
404
405 int init_subtitles(char *filename)
406 {
407         CFILE *ifile;
408         int size,read_count;
409         ubyte *p;
410         int have_binary = 0;
411
412         Num_subtitles = 0;
413
414         if (! FindArg("-subtitles"))
415                 return 0;
416
417         ifile = cfopen(filename,"rb");          //try text version
418
419         if (!ifile) {                                                           //no text version, try binary version
420                 char filename2[FILENAME_LEN];
421                 change_filename_ext(filename2,filename,".TXB");
422                 ifile = cfopen(filename2,"rb");
423                 if (!ifile)
424                         return 0;
425                 have_binary = 1;
426         }
427
428         size = cfilelength(ifile);
429
430         MALLOC (subtitle_raw_data, ubyte, size+1);
431
432         read_count = cfread(subtitle_raw_data, 1, size, ifile);
433
434         cfclose(ifile);
435
436         subtitle_raw_data[size] = 0;
437
438         if (read_count != size) {
439                 d_free(subtitle_raw_data);
440                 return 0;
441         }
442
443         p = subtitle_raw_data;
444
445         while (p && p < subtitle_raw_data+size) {
446                 char *endp;
447
448                 endp = strchr(p,'\n'); 
449                 if (endp) {
450                         if (endp[-1] == '\r')
451                                 endp[-1] = 0;           //handle 0d0a pair
452                         *endp = 0;                      //string termintor
453                 }
454
455                 if (have_binary)
456                         decode_text_line(p);
457
458                 if (*p != ';') {
459                         Subtitles[Num_subtitles].first_frame = atoi(p);
460                         p = next_field(p); if (!p) continue;
461                         Subtitles[Num_subtitles].last_frame = atoi(p);
462                         p = next_field(p); if (!p) continue;
463                         Subtitles[Num_subtitles].msg = p;
464
465                         Assert(Num_subtitles==0 || Subtitles[Num_subtitles].first_frame >= Subtitles[Num_subtitles-1].first_frame);
466                         Assert(Subtitles[Num_subtitles].last_frame >= Subtitles[Num_subtitles].first_frame);
467
468                         Num_subtitles++;
469                 }
470
471                 p = endp+1;
472
473         }
474
475         return 1;
476 }
477
478
479 void close_subtitles()
480 {
481         if (subtitle_raw_data)
482                 d_free(subtitle_raw_data);
483         subtitle_raw_data = NULL;
484         Num_subtitles = 0;
485 }
486
487
488 //draw the subtitles for this frame
489 void draw_subtitles(int frame_num)
490 {
491         static int active_subtitles[MAX_ACTIVE_SUBTITLES];
492         static int num_active_subtitles,next_subtitle,line_spacing;
493         int t,y;
494         int must_erase=0;
495
496         if (frame_num == 0) {
497                 num_active_subtitles = 0;
498                 next_subtitle = 0;
499                 gr_set_curfont( GAME_FONT );
500                 line_spacing = grd_curcanv->cv_font->ft_h + (grd_curcanv->cv_font->ft_h >> 2);
501                 gr_set_fontcolor(255,-1);
502         }
503
504         //get rid of any subtitles that have expired
505         for (t=0;t<num_active_subtitles;)
506                 if (frame_num > Subtitles[active_subtitles[t]].last_frame) {
507                         int t2;
508                         for (t2=t;t2<num_active_subtitles-1;t2++)
509                                 active_subtitles[t2] = active_subtitles[t2+1];
510                         num_active_subtitles--;
511                         must_erase = 1;
512                 }
513                 else
514                         t++;
515
516         //get any subtitles new for this frame 
517         while (next_subtitle < Num_subtitles && frame_num >= Subtitles[next_subtitle].first_frame) {
518                 if (num_active_subtitles >= MAX_ACTIVE_SUBTITLES)
519                         Error("Too many active subtitles!");
520                 active_subtitles[num_active_subtitles++] = next_subtitle;
521                 next_subtitle++;
522         }
523
524         //find y coordinate for first line of subtitles
525         y = grd_curcanv->cv_bitmap.bm_h-((line_spacing+1)*MAX_ACTIVE_SUBTITLES+2);
526
527         //erase old subtitles if necessary
528         if (must_erase) {
529                 gr_setcolor(0);
530                 gr_rect(0,y,grd_curcanv->cv_bitmap.bm_w-1,grd_curcanv->cv_bitmap.bm_h-1);
531         }
532
533         //now draw the current subtitles
534         for (t=0;t<num_active_subtitles;t++)
535                 if (active_subtitles[t] != -1) {
536                         gr_string(0x8000,y,Subtitles[active_subtitles[t]].msg);
537                         y += line_spacing+1;
538                 }
539 }
540
541
542 movielib *init_new_movie_lib(char *filename,FILE *fp)
543 {
544         int nfiles,offset;
545         int i,n;
546         movielib *table;
547
548         //read movie file header
549
550         nfiles = file_read_int(fp);             //get number of files
551
552         //table = d_malloc(sizeof(*table) + sizeof(ml_entry)*nfiles);
553         MALLOC(table, movielib, 1);
554         MALLOC(table->movies, ml_entry, nfiles);
555
556         strcpy(table->name,filename);
557         table->n_movies = nfiles;
558
559         offset = 4+4+nfiles*(13+4);     //id + nfiles + nfiles * (filename + size)
560
561         for (i=0;i<nfiles;i++) {
562                 int len;
563
564                 n = fread( table->movies[i].name, 13, 1, fp );
565                 if ( n != 1 )
566                         break;          //end of file (probably)
567
568                 len = file_read_int(fp);
569
570                 table->movies[i].len = len;
571                 table->movies[i].offset = offset;
572
573                 offset += table->movies[i].len;
574
575         }
576
577         fclose(fp);
578
579         table->flags = 0;
580
581         return table;
582
583 }
584
585
586 movielib *init_old_movie_lib(char *filename,FILE *fp)
587 {
588         int nfiles,size;
589         int i;
590         movielib *table,*table2;
591
592         nfiles = 0;
593
594         //allocate big table
595         table = d_malloc(sizeof(*table) + sizeof(ml_entry)*MAX_MOVIES_PER_LIB);
596
597         while( 1 ) {
598                 int len;
599
600                 i = fread( table->movies[nfiles].name, 13, 1, fp );
601                 if ( i != 1 )
602                         break;          //end of file (probably)
603
604                 i = fread( &len, 4, 1, fp );
605                 if ( i != 1 )
606                         Error("error reading movie library <%s>",filename);
607
608                 table->movies[nfiles].len = INTEL_INT(len);
609                 table->movies[nfiles].offset = ftell( fp );
610
611                 fseek( fp, INTEL_INT(len), SEEK_CUR );          //skip data
612
613                 nfiles++;
614         }
615
616         //allocate correct-sized table
617         size = sizeof(*table) + sizeof(ml_entry)*nfiles;
618         table2 = d_malloc(size);
619         memcpy(table2,table,size);
620         d_free(table);
621         table = table2;
622
623         strcpy(table->name,filename);
624
625         table->n_movies = nfiles;
626
627         fclose(fp);
628
629         table->flags = 0;
630
631         return table;
632
633 }
634
635
636 //find the specified movie library, and read in list of movies in it
637 movielib *init_movie_lib(char *filename)
638 {
639         //note: this based on cfile_init_hogfile()
640
641         char id[4];
642         FILE * fp;
643
644         fp = fopen( filename, "rb" );
645
646         if ((fp == NULL) && (AltHogdir_initialized)) {
647                 char temp[128];
648                 strcpy(temp, AltHogDir);
649                 strcat(temp, "/");
650                 strcat(temp, filename);
651                 fp = fopen(temp, "rb");
652         }
653
654         if ( fp == NULL )
655                 return NULL;
656
657         fread( id, 4, 1, fp );
658         if ( !strncmp( id, "DMVL", 4 ) )
659                 return init_new_movie_lib(filename,fp);
660         else if ( !strncmp( id, "DHF", 3 ) ) {
661                 fseek(fp,-1,SEEK_CUR);          //old file had 3 char id
662                 return init_old_movie_lib(filename,fp);
663         }
664         else {
665                 fclose(fp);
666                 return NULL;
667         }
668 }
669
670
671 void close_movie(int i)
672 {
673         if (movie_libs[i]) {
674                 d_free(movie_libs[i]->movies);
675                 d_free(movie_libs[i]);
676         }
677 }
678
679
680 void close_movies()
681 {
682         int i;
683
684         for (i=0;i<N_MOVIE_LIBS;i++)
685                 close_movie(i);
686 }
687
688
689 //ask user to put the D2 CD in.
690 //returns -1 if ESC pressed, 0 if OK chosen
691 //CD may not have been inserted
692 int request_cd(void)
693 {
694 #if 0
695         ubyte save_pal[256*3];
696         grs_canvas *save_canv,*tcanv;
697         int ret,was_faded=gr_palette_faded_out;
698
699         gr_palette_clear();
700
701         save_canv = grd_curcanv;
702         tcanv = gr_create_canvas(grd_curcanv->cv_w,grd_curcanv->cv_h);
703
704         gr_set_current_canvas(tcanv);
705         gr_ubitmap(0,0,&save_canv->cv_bitmap);
706         gr_set_current_canvas(save_canv);
707
708         gr_clear_canvas(BM_XRGB(0,0,0));
709
710         memcpy(save_pal,gr_palette,sizeof(save_pal));
711
712         memcpy(gr_palette,last_palette_for_color_fonts,sizeof(gr_palette));
713
714  try_again:;
715
716         ret = nm_messagebox( "CD ERROR", 1, "Ok", "Please insert your Descent II CD");
717
718         if (ret == -1) {
719                 int ret2;
720
721                 ret2 = nm_messagebox( "CD ERROR", 2, "Try Again", "Leave Game", "You must insert your\nDescent II CD to Continue");
722
723                 if (ret2 == -1 || ret2 == 0)
724                         goto try_again;
725         }
726
727         force_rb_register = 1;  //disc has changed; force register new CD
728
729         gr_palette_clear();
730
731         memcpy(gr_palette,save_pal,sizeof(save_pal));
732
733         gr_ubitmap(0,0,&tcanv->cv_bitmap);
734
735         if (!was_faded)
736                 gr_palette_load(gr_palette);
737
738         gr_free_canvas(tcanv);
739
740         return ret;
741 #else
742         con_printf(DEBUG_LEVEL, "STUB: movie: request_cd\n");
743         return 0;
744 #endif
745 }
746
747
748 void init_movie(char *filename,int libnum,int is_robots,int required)
749 {
750         int high_res;
751         int try = 0;
752
753 #ifndef RELEASE
754         if (FindArg("-nomovies")) {
755                 movie_libs[libnum] = NULL;
756                 return;
757         }
758 #endif
759
760         //for robots, load highres versions if highres menus set
761         if (is_robots)
762                 high_res = MenuHiresAvailable;
763         else
764                 high_res = MovieHires;
765
766         if (high_res)
767                 strchr(filename,'.')[-1] = 'h';
768
769 try_again:;
770
771         if ((movie_libs[libnum] = init_movie_lib(filename)) == NULL) {
772                 char name2[100];
773
774                 strcpy(name2,CDROM_dir);
775                 strcat(name2,filename);
776                 movie_libs[libnum] = init_movie_lib(name2);
777
778                 if (movie_libs[libnum] != NULL)
779                         movie_libs[libnum]->flags |= MLF_ON_CD;
780                 else {
781                         if (required) {
782                                 Warning("Cannot open movie file <%s>\n",filename);
783                         }
784
785                         if (!try) {                                         // first try
786                                 if (strchr(filename, '.')[-1] == 'h') {         // try again with lowres
787                                         strchr(filename, '.')[-1] = 'l';
788                                         high_res = 0;
789                                         Warning("Trying to open movie file <%s> instead\n", filename);
790                                         try++;
791                                         goto try_again;
792                                 } else if (strchr(filename, '.')[-1] == 'l') {  // try again with highres
793                                         strchr(filename, '.')[-1] = 'h';
794                                         high_res = 1;
795                                         Warning("Trying to open movie file <%s> instead\n", filename);
796                                         try++;
797                                         goto try_again;
798                                 }
799                         }
800                 }
801         }
802
803         if (is_robots && movie_libs[libnum]!=NULL)
804                 robot_movies = high_res?2:1;
805 }
806
807
808 //find and initialize the movie libraries
809 void init_movies()
810 {
811         int i;
812         int is_robots;
813
814         for (i=0;i<N_BUILTIN_MOVIE_LIBS;i++) {
815
816                 if (!strnicmp(movielib_files[i],"robot",5))
817                         is_robots = 1;
818                 else
819                         is_robots = 0;
820
821                 init_movie(movielib_files[i],i,is_robots,1);
822         }
823
824         movie_libs[EXTRA_ROBOT_LIB] = NULL;
825
826         atexit(close_movies);
827 }
828
829
830 void init_extra_robot_movie(char *filename)
831 {
832         close_movie(EXTRA_ROBOT_LIB);
833         init_movie(filename,EXTRA_ROBOT_LIB,1,0);
834 }
835
836
837 int movie_handle,movie_start;
838
839 //looks through a movie library for a movie file
840 //returns filehandle, with fileposition at movie, or -1 if can't find
841 int search_movie_lib(movielib *lib,char *filename,int must_have)
842 {
843         int i;
844         int filehandle;
845
846         if (lib == NULL)
847                 return -1;
848
849         for (i=0;i<lib->n_movies;i++)
850                 if (!stricmp(filename,lib->movies[i].name)) {   //found the movie in a library 
851                         int from_cd;
852
853                         from_cd = (lib->flags & MLF_ON_CD);
854
855                         if (from_cd)
856                                 songs_stop_redbook();           //ready to read from CD
857
858                         do {            //keep trying until we get the file handle
859
860 #ifdef O_BINARY
861                                 movie_handle = filehandle = open(lib->name, O_RDONLY | O_BINARY);
862 #else
863                                 movie_handle = filehandle = open(lib->name, O_RDONLY);
864 #endif
865
866                                 if ((filehandle == -1) && (AltHogdir_initialized)) {
867                                         char temp[128];
868                                         strcpy(temp, AltHogDir);
869                                         strcat(temp, "/");
870                                         strcat(temp, lib->name);
871 #ifdef O_BINARY
872                                         movie_handle = filehandle = open(temp, O_RDONLY | O_BINARY);
873 #else
874                                         movie_handle = filehandle = open(temp, O_RDONLY);
875 #endif
876                                 }
877
878                                 if (must_have && from_cd && filehandle == -1) {         //didn't get file!
879
880                                         if (request_cd() == -1)         //ESC from requester
881                                                 break;                                          //bail from here. will get error later
882                                 }
883
884                         } while (must_have && from_cd && filehandle == -1);
885
886                         if (filehandle != -1)
887                                 lseek(filehandle,(movie_start=lib->movies[i].offset),SEEK_SET);
888
889                         return filehandle;
890                 }
891
892         return -1;
893 }
894
895
896 //returns file handle
897 int open_movie_file(char *filename,int must_have)
898 {
899         int filehandle,i;
900
901         for (i=0;i<N_MOVIE_LIBS;i++) {
902                 if ((filehandle = search_movie_lib(movie_libs[i],filename,must_have)) != -1)
903                         return filehandle;
904         }
905
906         return -1;              //couldn't find it
907 }
908
909 //sets the file position to the start of this already-open file
910 int reset_movie_file(int handle)
911 {
912         Assert(handle == movie_handle);
913
914         lseek(handle,movie_start,SEEK_SET);
915
916         return 0;       //everything is cool
917 }