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