]> icculus.org git repositories - btb/d2x.git/blob - main/movie.c
whitespace
[btb/d2x.git] / main / movie.c
1 /* $Id: movie.c,v 1.9 2002-08-26 06:50:45 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.9 2002-08-26 06:50:45 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 "mvelib.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 typedef struct {
74         char name[FILENAME_LEN];
75         int offset,len;
76 } ml_entry;
77
78 #define MLF_ON_CD    1
79 #define MAX_MOVIES_PER_LIB    50    //determines size of malloc
80
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 int MVEPaletteCalls = 0;
101
102 //do we have the robot movies available
103 int robot_movies = 0; //0 means none, 1 means lowres, 2 means hires
104
105 int MovieHires = 0;   //default for now is lores
106
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
113 void change_filename_ext( char *dest, char *src, char *ext );
114 void decode_text_line(char *p);
115 void draw_subtitles(int frame_num);
116
117
118 //filename will actually get modified to be either low-res or high-res
119 //returns status.  see values in movie.h
120 int PlayMovie(const char *filename, int must_have)
121 {
122         char name[FILENAME_LEN],*p;
123         int c, ret;
124 #if 0
125         int save_sample_rate;
126 #endif
127
128 #ifndef RELEASE
129         //if (FindArg("-nomovies"))
130         if (!FindArg("-movies"))
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 #if 0
151         save_sample_rate = digi_sample_rate;
152         digi_sample_rate = SAMPLE_RATE_22K;             //always 22K for movies
153         digi_reset(); digi_reset();
154 #else
155         digi_close();
156 #endif
157
158         ret = RunMovie(name,MovieHires,must_have,-1,-1);
159
160 #if 0
161         gr_palette_clear();             //clear out palette in case movie aborted
162 #endif
163
164 #if 0
165         digi_sample_rate = save_sample_rate;            //restore rate for game
166         digi_reset(); digi_reset();
167 #else
168         digi_init();
169 #endif
170
171         Screen_mode = -1;               //force screen reset
172
173         return ret;
174 }
175
176 void initializeMovie(MVESTREAM *mve);
177 void shutdownMovie(MVESTREAM *mve);
178
179 //returns status.  see movie.h
180 int RunMovie(char *filename, int hires_flag, int must_have,int dx,int dy)
181 {
182         int filehndl;
183         int result=1,aborted=0;
184         int frame_num;
185         MVESTREAM *mve;
186
187         result=1;
188         con_printf(DEBUG_LEVEL, "movie: RunMovie: %s %d %d %d %d\n", filename, hires_flag, must_have, dx, dy);
189
190         // Open Movie file.  If it doesn't exist, no movie, just return.
191
192         filehndl = open_movie_file(filename,must_have);
193
194         if (filehndl == -1) {
195 #ifndef EDITOR
196                 if (must_have)
197                         Warning("movie: RunMovie: Cannot open movie file <%s>\n",filename);
198 #endif
199                 return MOVIE_NOT_PLAYED;
200         }
201
202 #if 0
203         if (hires_flag)
204                 gr_set_mode(SM(640,480));
205         else
206                 gr_set_mode(SM(320,200));
207 #endif
208
209         frame_num = 0;
210
211         FontHires = hires_flag;
212
213     mve = mve_open(filehndl);
214     if (mve == NULL)
215     {
216         fprintf(stderr, "can't open MVE file '%s'\n", filename);
217         return 1;
218     }
219
220 #if 1
221     initializeMovie(mve);
222
223         while((result = mve_play_next_chunk(mve))) {
224                 int key;
225
226                 draw_subtitles(frame_num);
227
228                 key = key_inkey();
229
230                 // If ESCAPE pressed, then quit movie.
231                 if (key == KEY_ESC) {
232                         result = 0;
233                         aborted = 1;
234                         break;
235                 }
236
237                 // If PAUSE pressed, then pause movie
238                 if (key == KEY_PAUSE) {
239                         //MVE_rmHoldMovie();
240                         //show_pause_message(TXT_PAUSE);
241                         while (!key_inkey()) ;
242                         //clear_pause_message();
243                 }
244
245                 frame_num++;
246         }
247
248         Assert(aborted || !result);      ///movie should be over
249
250     shutdownMovie(mve);
251 #endif
252
253     mve_close(mve);
254
255         close(filehndl);                           // Close Movie File
256
257         // Restore old graphic state
258
259         Screen_mode=-1;  //force reset of screen mode
260
261         return (aborted?MOVIE_ABORTED:MOVIE_PLAYED_FULL);
262 }
263
264
265 int InitMovieBriefing()
266 {
267 #if 0
268         if (MenuHires)
269                 gr_set_mode(SM(640,480));
270         else
271                 gr_set_mode(SM(320,200));
272 #endif
273         return 1;
274 }
275
276
277 void RotateRobot()
278 {
279         con_printf(DEBUG_LEVEL, "STUB: movie: RotateRobot\n");
280 }
281
282
283 void DeInitRobotMovie(void)
284 {
285         con_printf(DEBUG_LEVEL, "STUB: movie: DeInitRobotMovie\n");
286 }
287
288
289 int InitRobotMovie(char *filename)
290 {
291         con_printf(DEBUG_LEVEL, "STUB: movie: InitRobotMovie: %s\n", filename);
292
293 #if 0
294         FlipFlop=0;
295
296         RobBufCount=0; PlayingBuf=0; RobBufLimit=0;
297
298         //if (FindArg("-nomovies"))
299         if (!FindArg("-movies"))
300                 return 0;
301    
302 //   digi_stop_all();
303
304 //@@   if (MovieHires)
305 //@@            filename[4]='h';
306 //@@    else
307 //@@            filename[4]='l';
308   
309         if ((FirstVid=calloc (65000L,1))==NULL) {
310                 FreeRoboBuffer(49);
311                 return (NULL);
312         }
313         if ((SecondVid=calloc (65000L,1))==NULL) {
314                 free (FirstVid);
315                 FreeRoboBuffer(49);
316                 return (NULL);
317         }
318
319 #if 0
320         MVE_SOS_sndInit(-1);            //tell movies to play no sound for robots
321
322         MVE_memCallbacks(MPlayAlloc, MPlayFree);
323         MVE_ioCallbacks(FileRead);
324         MVE_memVID (FirstVid,SecondVid,65000);
325 #endif
326
327         RoboFile = open_movie_file(filename,1);
328
329         if (RoboFile == -1) {
330                 free (FirstVid);
331                 free (SecondVid);       
332                 FreeRoboBuffer (49);
333 #ifdef RELEASE
334                 Error("movie: InitRobotMovie: Cannot open movie file <%s>",filename);
335 #else
336                 return MOVIE_NOT_PLAYED;
337 #endif
338         }
339
340         Vid_State = VID_PLAY;                           
341
342 #if 0
343         if (MVE_rmPrepMovie(RoboFile, 280, 200, 0)) {
344                 Int3();
345                 free (FirstVid);
346                 free (SecondVid);       
347                 FreeRoboBuffer (49);
348                 return 0;
349         }
350
351         MVE_palCallbacks (PaletteChecker);
352 #endif
353
354         RoboFilePos=lseek (RoboFile,0L,SEEK_CUR);
355
356         return 1;
357 #else
358         return 0;
359 #endif
360 }
361
362
363 /*
364  *              Subtitle system code
365  */
366
367 ubyte *subtitle_raw_data;
368
369
370 //search for next field following whitespace 
371 ubyte *next_field(ubyte *p)
372 {
373         while (*p && !isspace(*p))
374                 p++;
375
376         if (!*p)
377                 return NULL;
378
379         while (*p && isspace(*p))
380                 p++;
381
382         if (!*p)
383                 return NULL;
384
385         return p;
386 }
387
388
389 int init_subtitles(char *filename)
390 {
391         CFILE *ifile;
392         int size,read_count;
393         ubyte *p;
394         int have_binary = 0;
395
396         Num_subtitles = 0;
397
398         if (! FindArg("-subtitles"))
399                 return 0;
400
401         ifile = cfopen(filename,"rb");          //try text version
402
403         if (!ifile) {                                                           //no text version, try binary version
404                 char filename2[FILENAME_LEN];
405                 change_filename_ext(filename2,filename,".TXB");
406                 ifile = cfopen(filename2,"rb");
407                 if (!ifile)
408                         return 0;
409                 have_binary = 1;
410         }
411
412         size = cfilelength(ifile);
413    
414         MALLOC (subtitle_raw_data, ubyte, size+1);
415
416         read_count = cfread(subtitle_raw_data, 1, size, ifile);
417
418         cfclose(ifile);
419
420         subtitle_raw_data[size] = 0;
421
422         if (read_count != size) {
423                 d_free(subtitle_raw_data);
424                 return 0;
425         }
426
427         p = subtitle_raw_data;
428
429         while (p && p < subtitle_raw_data+size) {
430                 char *endp;
431
432                 endp = strchr(p,'\n'); 
433                 if (endp) {
434                         if (endp[-1] == '\r')
435                                 endp[-1] = 0;           //handle 0d0a pair
436                         *endp = 0;                      //string termintor
437                 }
438
439                 if (have_binary)
440                         decode_text_line(p);
441
442                 if (*p != ';') {
443                         Subtitles[Num_subtitles].first_frame = atoi(p);
444                         p = next_field(p); if (!p) continue;
445                         Subtitles[Num_subtitles].last_frame = atoi(p);
446                         p = next_field(p); if (!p) continue;
447                         Subtitles[Num_subtitles].msg = p;
448
449                         Assert(Num_subtitles==0 || Subtitles[Num_subtitles].first_frame >= Subtitles[Num_subtitles-1].first_frame);
450                         Assert(Subtitles[Num_subtitles].last_frame >= Subtitles[Num_subtitles].first_frame);
451
452                         Num_subtitles++;
453                 }
454
455                 p = endp+1;
456
457         }
458
459         return 1;
460 }
461
462
463 void close_subtitles()
464 {
465         if (subtitle_raw_data)
466                 d_free(subtitle_raw_data);
467         subtitle_raw_data = NULL;
468         Num_subtitles = 0;
469 }
470
471
472 //draw the subtitles for this frame
473 void draw_subtitles(int frame_num)
474 {
475         static int active_subtitles[MAX_ACTIVE_SUBTITLES];
476         static int num_active_subtitles,next_subtitle,line_spacing;
477         int t,y;
478         int must_erase=0;
479
480         if (frame_num == 0) {
481                 num_active_subtitles = 0;
482                 next_subtitle = 0;
483                 gr_set_curfont( GAME_FONT );
484                 line_spacing = grd_curcanv->cv_font->ft_h + (grd_curcanv->cv_font->ft_h >> 2);
485                 gr_set_fontcolor(255,-1);
486         }
487
488         //get rid of any subtitles that have expired
489         for (t=0;t<num_active_subtitles;)
490                 if (frame_num > Subtitles[active_subtitles[t]].last_frame) {
491                         int t2;
492                         for (t2=t;t2<num_active_subtitles-1;t2++)
493                                 active_subtitles[t2] = active_subtitles[t2+1];
494                         num_active_subtitles--;
495                         must_erase = 1;
496                 }
497                 else
498                         t++;
499
500         //get any subtitles new for this frame 
501         while (next_subtitle < Num_subtitles && frame_num >= Subtitles[next_subtitle].first_frame) {
502                 if (num_active_subtitles >= MAX_ACTIVE_SUBTITLES)
503                         Error("Too many active subtitles!");
504                 active_subtitles[num_active_subtitles++] = next_subtitle;
505                 next_subtitle++;
506         }
507
508         //find y coordinate for first line of subtitles
509         y = grd_curcanv->cv_bitmap.bm_h-((line_spacing+1)*MAX_ACTIVE_SUBTITLES+2);
510
511         //erase old subtitles if necessary
512         if (must_erase) {
513                 gr_setcolor(0);
514                 gr_rect(0,y,grd_curcanv->cv_bitmap.bm_w-1,grd_curcanv->cv_bitmap.bm_h-1);
515         }
516
517         //now draw the current subtitles
518         for (t=0;t<num_active_subtitles;t++)
519                 if (active_subtitles[t] != -1) {
520                         gr_string(0x8000,y,Subtitles[active_subtitles[t]].msg);
521                         y += line_spacing+1;
522                 }
523 }
524
525
526 int request_cd(void)
527 {
528         con_printf(DEBUG_LEVEL, "STUB: movie: request_cd\n");
529         return 0;
530 }
531
532
533 movielib *init_new_movie_lib(char *filename,FILE *fp)
534 {
535         int nfiles,offset;
536         int i,n;
537         movielib *table;
538
539         //read movie file header
540
541         nfiles = file_read_int(fp);             //get number of files
542
543         //table = d_malloc(sizeof(*table) + sizeof(ml_entry)*nfiles);
544         MALLOC(table, movielib, 1);
545         MALLOC(table->movies, ml_entry, nfiles);
546
547         strcpy(table->name,filename);
548         table->n_movies = nfiles;
549
550         offset = 4+4+nfiles*(13+4);     //id + nfiles + nfiles * (filename + size)
551
552         for (i=0;i<nfiles;i++) {
553                 int len;
554
555                 n = fread( table->movies[i].name, 13, 1, fp );
556                 if ( n != 1 )
557                         break;          //end of file (probably)
558
559                 len = file_read_int(fp);
560
561                 table->movies[i].len = len;
562                 table->movies[i].offset = offset;
563
564                 offset += table->movies[i].len;
565
566         }
567
568         fclose(fp);
569
570         table->flags = 0;
571
572         return table;
573
574 }
575
576
577 movielib *init_old_movie_lib(char *filename,FILE *fp)
578 {
579         int nfiles,size;
580         int i;
581         movielib *table,*table2;
582
583         nfiles = 0;
584
585         //allocate big table
586         table = d_malloc(sizeof(*table) + sizeof(ml_entry)*MAX_MOVIES_PER_LIB);
587
588         while( 1 ) {
589                 int len;
590
591                 i = fread( table->movies[nfiles].name, 13, 1, fp );
592                 if ( i != 1 )
593                         break;          //end of file (probably)
594
595                 i = fread( &len, 4, 1, fp );
596                 if ( i != 1 )
597                         Error("error reading movie library <%s>",filename);
598
599                 table->movies[nfiles].len = INTEL_INT(len);
600                 table->movies[nfiles].offset = ftell( fp );
601
602                 fseek( fp, INTEL_INT(len), SEEK_CUR );          //skip data
603
604                 nfiles++;
605         }
606
607         //allocate correct-sized table
608         size = sizeof(*table) + sizeof(ml_entry)*nfiles;
609         table2 = d_malloc(size);
610         memcpy(table2,table,size);
611         d_free(table);
612         table = table2;
613
614         strcpy(table->name,filename);
615
616         table->n_movies = nfiles;
617
618         fclose(fp);
619
620         table->flags = 0;
621
622         return table;
623
624 }
625
626
627 //find the specified movie library, and read in list of movies in it
628 movielib *init_movie_lib(char *filename)
629 {
630         //note: this based on cfile_init_hogfile()
631
632         char id[4];
633         FILE * fp;
634
635         fp = fopen( filename, "rb" );
636
637         if ((fp == NULL) && (AltHogdir_initialized)) {
638                 char temp[128];
639                 strcpy(temp, AltHogDir);
640                 strcat(temp, "/");
641                 strcat(temp, filename);
642                 fp = fopen(temp, "rb");
643         }
644
645         if ( fp == NULL )
646                 return NULL;
647
648         fread( id, 4, 1, fp );
649         if ( !strncmp( id, "DMVL", 4 ) )
650                 return init_new_movie_lib(filename,fp);
651         else if ( !strncmp( id, "DHF", 3 ) ) {
652                 fseek(fp,-1,SEEK_CUR);          //old file had 3 char id
653                 return init_old_movie_lib(filename,fp);
654         }
655         else {
656                 fclose(fp);
657                 return NULL;
658         }
659 }
660
661
662 void close_movie(int i)
663 {
664         if (movie_libs[i]) {
665                 d_free(movie_libs[i]->movies);
666                 d_free(movie_libs[i]);
667         }
668 }
669
670
671 void close_movies()
672 {
673         int i;
674
675         for (i=0;i<N_MOVIE_LIBS;i++)
676                 close_movie(i);
677 }
678
679
680 void init_movie(char *filename,int libnum,int is_robots,int required)
681 {
682         int high_res;
683
684 #ifndef RELEASE
685         //if (FindArg("-nomovies")) {
686         if (!FindArg("-movies")) {
687                 movie_libs[libnum] = NULL;
688                 return;
689         }
690 #endif
691
692         //for robots, load highres versions if highres menus set
693         if (is_robots)
694                 high_res = MenuHiresAvailable;
695         else
696                 high_res = MovieHires;
697
698         if (high_res)
699                 strchr(filename,'.')[-1] = 'h';
700
701 #if defined(D2_OEM)
702 try_again:;
703 #endif
704
705         if ((movie_libs[libnum] = init_movie_lib(filename)) == NULL) {
706                 char name2[100];
707
708                 strcpy(name2,CDROM_dir);
709                 strcat(name2,filename);
710                 movie_libs[libnum] = init_movie_lib(name2);
711
712                 if (movie_libs[libnum] != NULL)
713                         movie_libs[libnum]->flags |= MLF_ON_CD;
714                 else {
715                         if (required) {
716 #if defined(RELEASE) && !defined(D2_OEM)                //allow no movies if not release
717                                         strupr(filename);
718                                         Error("Cannot open movie file <%s>",filename);
719 #endif
720                         }
721 #if defined(D2_OEM)             //if couldn't get highres, try low
722                         if (is_robots == 1) {   //first try, try again with lowres
723                                 strchr(filename,'.')[-1] = 'l';
724                                 high_res = 0;
725                                 is_robots++;
726                                 goto try_again;
727                         }
728                         else if (is_robots == 2) {              //failed twice. bail with error
729                                 strupr(filename);
730                                 Error("Cannot open movie file <%s>",filename);
731                         }
732 #endif
733                 }
734         }
735
736         if (is_robots && movie_libs[libnum]!=NULL)
737                 robot_movies = high_res?2:1;
738 }
739
740
741 //find and initialize the movie libraries
742 void init_movies()
743 {
744         int i;
745         int is_robots;
746
747         for (i=0;i<N_BUILTIN_MOVIE_LIBS;i++) {
748
749                 if (!strnicmp(movielib_files[i],"robot",5))
750                         is_robots = 1;
751                 else
752                         is_robots = 0;
753
754                 init_movie(movielib_files[i],i,is_robots,1);
755         }
756
757         movie_libs[EXTRA_ROBOT_LIB] = NULL;
758
759         atexit(close_movies);
760 }
761
762
763 void init_extra_robot_movie(char *f)
764 {
765         con_printf(DEBUG_LEVEL, "STUB: movie: init_extra_robot_movie: %s\n", f);
766 }
767
768
769 //looks through a movie library for a movie file
770 //returns filehandle, with fileposition at movie, or -1 if can't find
771 int search_movie_lib(movielib *lib,char *filename,int must_have)
772 {
773         int i;
774         int filehandle;
775
776         if (lib == NULL)
777                 return -1;
778
779         for (i=0;i<lib->n_movies;i++)
780                 if (!stricmp(filename,lib->movies[i].name)) {   //found the movie in a library 
781                         int from_cd;
782
783                         from_cd = (lib->flags & MLF_ON_CD);
784
785                         if (from_cd)
786                                 songs_stop_redbook();           //ready to read from CD
787
788                         do {            //keep trying until we get the file handle
789
790                                 /* movie_handle = */ filehandle = open(lib->name, O_RDONLY);
791
792                                 if ((filehandle == -1) && (AltHogdir_initialized)) {
793                                         char temp[128];
794                                         strcpy(temp, AltHogDir);
795                                         strcat(temp, "/");
796                                         strcat(temp, lib->name);
797                                         filehandle = open(temp, O_RDONLY);
798                                 }
799
800                                 if (must_have && from_cd && filehandle == -1) {         //didn't get file!
801
802                                         if (request_cd() == -1)         //ESC from requester
803                                                 break;                                          //bail from here. will get error later
804                                 }
805
806                         } while (must_have && from_cd && filehandle == -1);
807
808                         if (filehandle != -1)
809                                 lseek(filehandle,(/* movie_start = */ lib->movies[i].offset),SEEK_SET);
810
811                         return filehandle;
812                 }
813
814         return -1;
815 }
816
817
818 //returns file handle
819 int open_movie_file(char *filename,int must_have)
820 {
821         int filehandle,i;
822
823         for (i=0;i<N_MOVIE_LIBS;i++) {
824                 if ((filehandle = search_movie_lib(movie_libs[i],filename,must_have)) != -1)
825                         return filehandle;
826         }
827
828         return -1;              //couldn't find it
829 }
830
831