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