Got rid of all compiler warnings, for non-OpenGL on linux, anyway...
[btb/d2x.git] / main / piggy.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14
15 #ifdef RCS
16 static char rcsid[] = "$Id: piggy.c,v 1.2 2001-01-20 13:49:17 bradleyb Exp $";
17 #endif
18
19 #include <conf.h>
20
21 #include <stdio.h>
22 #include <string.h>
23
24 #include "pstypes.h"
25 #include "strutil.h"
26 #include "inferno.h"
27 #include "gr.h"
28 #include "u_mem.h"
29 #include "iff.h"
30 #include "mono.h"
31 #include "error.h"
32 #include "sounds.h"
33 #include "songs.h"
34 #include "bm.h"
35 #include "bmread.h"
36 #include "hash.h"
37 #include "args.h"
38 #include "palette.h"
39 #include "gamefont.h"
40 #include "rle.h"
41 #include "screens.h"
42 #include "piggy.h"
43 #include "texmerge.h"
44 #include "paging.h"
45 #include "game.h"
46 #include "text.h"
47 #include "cfile.h"
48 #include "newmenu.h"
49 #include "byteswap.h"
50 #include "findfile.h"
51
52 #ifndef MACINTOSH
53 //      #include "unarj.h"
54 #else
55         #include <Strings.h>            // MacOS Toolbox header
56         #include <Files.h>
57         #include <unistd.h>
58 #endif
59
60 //#define NO_DUMP_SOUNDS        1               //if set, dump bitmaps but not sounds
61
62 #define DEFAULT_PIGFILE_REGISTERED      "groupa.pig"
63 #define DEFAULT_PIGFILE_SHAREWARE       "d2demo.pig"
64
65
66 #ifdef SHAREWARE
67         #define DEFAULT_HAMFILE         "d2demo.ham"
68         #define DEFAULT_PIGFILE         DEFAULT_PIGFILE_SHAREWARE
69         #define DEFAULT_SNDFILE                 "descent2.s11"
70 #else
71         #define DEFAULT_HAMFILE         "descent2.ham"
72         #define DEFAULT_PIGFILE         DEFAULT_PIGFILE_REGISTERED
73         #define DEFAULT_SNDFILE                 ((digi_sample_rate==SAMPLE_RATE_22K)?"descent2.s22":"descent2.s11")
74 #endif  // end of ifdef SHAREWARE
75
76 ubyte *BitmapBits = NULL;
77 ubyte *SoundBits = NULL;
78
79 typedef struct BitmapFile       {
80         char                    name[15];
81 } BitmapFile;
82
83 typedef struct SoundFile        {
84         char                    name[15];
85 } SoundFile;
86
87 hashtable AllBitmapsNames;
88 hashtable AllDigiSndNames;
89
90 int Num_bitmap_files = 0;
91 int Num_sound_files = 0;
92
93 digi_sound GameSounds[MAX_SOUND_FILES];
94 int SoundOffset[MAX_SOUND_FILES];
95 grs_bitmap GameBitmaps[MAX_BITMAP_FILES];
96
97 alias alias_list[MAX_ALIASES];
98 int Num_aliases=0;
99
100 int Must_write_hamfile = 0;
101 int Num_bitmap_files_new = 0;
102 int Num_sound_files_new = 0;
103 BitmapFile AllBitmaps[ MAX_BITMAP_FILES ];
104 static SoundFile AllSounds[ MAX_SOUND_FILES ];
105
106 int piggy_low_memory = 0;
107
108 int Piggy_bitmap_cache_size = 0;
109 int Piggy_bitmap_cache_next = 0;
110 ubyte * Piggy_bitmap_cache_data = NULL;
111 static int GameBitmapOffset[MAX_BITMAP_FILES];
112 static ubyte GameBitmapFlags[MAX_BITMAP_FILES];
113 ushort GameBitmapXlat[MAX_BITMAP_FILES];
114
115 #define PIGGY_BUFFER_SIZE (2400*1024)
116
117 #ifdef MACINTOSH
118 #define PIGGY_SMALL_BUFFER_SIZE (1400*1024)             // size of buffer when piggy_low_memory is set
119
120 #ifdef SHAREWARE
121 #undef PIGGY_BUFFER_SIZE
122 #undef PIGGY_SMALL_BUFFER_SIZE
123
124 #define PIGGY_BUFFER_SIZE (2000*1024)
125 #define PIGGY_SMALL_BUFFER_SIZE (1100 * 1024)
126 #endif          // SHAREWARE
127
128 #endif
129
130 int piggy_page_flushed = 0;
131
132 #define DBM_FLAG_ABM            64
133
134 typedef struct DiskBitmapHeader {
135         char name[8];
136         ubyte dflags;                   //bits 0-5 anim frame num, bit 6 abm flag
137         ubyte width;                    //low 8 bits here, 4 more bits in wh_extra
138         ubyte height;                   //low 8 bits here, 4 more bits in wh_extra
139         ubyte   wh_extra;               //bits 0-3 width, bits 4-7 height
140         ubyte flags;
141         ubyte avg_color;
142         int offset;
143 } __pack__ DiskBitmapHeader;
144
145 typedef struct DiskSoundHeader {
146         char name[8];
147         int length;
148         int data_length;
149         int offset;
150 } __pack__ DiskSoundHeader;
151
152 ubyte BigPig = 0;
153
154 #ifdef MACINTOSH
155         extern short    cd_VRefNum;
156         extern void             ConcatPStr(StringPtr dst, StringPtr src);
157         extern int              ConvertPToCStr(StringPtr inPStr, char* outCStrBuf);
158         extern int              ConvertCToPStr(char* inCStr, StringPtr outPStrBuf);
159 #endif
160
161 #ifdef EDITOR
162 void swap_0_255(grs_bitmap *bmp)
163 {
164         int i;
165
166         for (i = 0; i < bmp->bm_h * bmp->bm_w; i++) {
167                 if(bmp->bm_data[i] == 0)
168                         bmp->bm_data[i] = 255;
169                 else if (bmp->bm_data[i] == 255)
170                         bmp->bm_data[i] = 0;
171         }
172 }
173 #endif
174
175 bitmap_index piggy_register_bitmap( grs_bitmap * bmp, char * name, int in_file )
176 {
177         bitmap_index temp;
178         Assert( Num_bitmap_files < MAX_BITMAP_FILES );
179
180         temp.index = Num_bitmap_files;
181
182         if (!in_file)   {
183 #ifdef EDITOR
184                 if ( args_find("-macdata") )
185                         swap_0_255( bmp );
186 #endif
187                 if ( !BigPig )  gr_bitmap_rle_compress( bmp );
188                 Num_bitmap_files_new++;
189         }
190
191         strncpy( AllBitmaps[Num_bitmap_files].name, name, 12 );
192         hashtable_insert( &AllBitmapsNames, AllBitmaps[Num_bitmap_files].name, Num_bitmap_files );
193         GameBitmaps[Num_bitmap_files] = *bmp;
194         if ( !in_file ) {
195                 GameBitmapOffset[Num_bitmap_files] = 0;
196                 GameBitmapFlags[Num_bitmap_files] = bmp->bm_flags;
197         }
198         Num_bitmap_files++;
199
200         return temp;
201 }
202
203 int piggy_register_sound( digi_sound * snd, char * name, int in_file )
204 {
205         int i;
206
207         Assert( Num_sound_files < MAX_SOUND_FILES );
208
209         strncpy( AllSounds[Num_sound_files].name, name, 12 );
210         hashtable_insert( &AllDigiSndNames, AllSounds[Num_sound_files].name, Num_sound_files );
211         GameSounds[Num_sound_files] = *snd;
212         if ( !in_file ) {
213                 SoundOffset[Num_sound_files] = 0;       
214         }
215
216         i = Num_sound_files;
217    
218         if (!in_file)
219                 Num_sound_files_new++;
220
221         Num_sound_files++;
222         return i;
223 }
224
225 bitmap_index piggy_find_bitmap( char * name )   
226 {
227         bitmap_index bmp;
228         int i;
229         char *t;
230
231         bmp.index = 0;
232
233         if ((t=strchr(name,'#'))!=NULL)
234                 *t=0;
235
236         for (i=0;i<Num_aliases;i++)
237                 if (stricmp(name,alias_list[i].alias_name)==0) {
238                         if (t) {                //extra stuff for ABMs
239                                 static char temp[FILENAME_LEN];
240                                 _splitpath(alias_list[i].file_name, NULL, NULL, temp, NULL );
241                                 name = temp;
242                                 strcat(name,"#");
243                                 strcat(name,t+1);
244                         }
245                         else
246                                 name=alias_list[i].file_name; 
247                         break;
248                 }
249
250         if (t)
251                 *t = '#';
252
253         i = hashtable_search( &AllBitmapsNames, name );
254         Assert( i != 0 );
255         if ( i < 0 )
256                 return bmp;
257
258         bmp.index = i;
259         return bmp;
260 }
261
262 int piggy_find_sound( char * name )     
263 {
264         int i;
265
266         i = hashtable_search( &AllDigiSndNames, name );
267
268         if ( i < 0 )
269                 return 255;
270
271         return i;
272 }
273
274 CFILE * Piggy_fp = NULL;
275
276 #define FILENAME_LEN 13
277
278 char Current_pigfile[FILENAME_LEN] = "";
279
280 void piggy_close_file()
281 {
282         if ( Piggy_fp ) {
283                 cfclose( Piggy_fp );
284                 Piggy_fp        = NULL;
285                 Current_pigfile[0] = 0;
286         }
287 }
288
289 int Pigfile_initialized=0;
290
291 #define PIGFILE_ID              "PPIG"          //PPIG
292 #define PIGFILE_VERSION         2
293
294 extern char CDROM_dir[];
295
296 int request_cd(void);
297
298
299 #ifdef MACINTOSH
300
301 //copies a pigfile from the CD to the current dir
302 //retuns file handle of new pig
303 CFILE *copy_pigfile_from_cd(char *filename)             // MACINTOSH VERSION
304 {
305         // C Stuff
306         char                    sourcePathAndFileCStr[255] = "";
307         char                    destPathAndFileCStr[255]        = "";
308         FILEFINDSTRUCT  find;
309         FILE*                   sourceFile      = NULL;
310         FILE*                   destFile        = NULL;
311         const int               BUF_SIZE = 4096;
312         ubyte                   buf[BUF_SIZE];
313
314         // Mac Stuff
315         Str255                  sourcePathAndFilePStr = "\p";
316         Str255                  destPathAndFilePStr = "\p";
317         Str255                  pigfileNamePStr = "\p";
318         HParamBlockRec  theSourcePigHFSParams;
319         HParamBlockRec  theDestPigHFSParams;
320         OSErr                   theErr = noErr;
321         char                    oldDirCStr[255] = "";
322
323         getcwd(oldDirCStr, 255);
324         
325         show_boxed_message("Copying bitmap data from CD...");
326         gr_palette_load(gr_palette);    //I don't think this line is really needed
327
328         chdir(":Data");
329         //First, delete all PIG files currently in the directory
330         if( !FileFindFirst( "*.pig", &find ) )
331         {
332                 do
333                 {
334                         remove(find.name);
335                 } while( !FileFindNext( &find ) );
336                 
337                 FileFindClose();
338         }
339         chdir(oldDirCStr);
340
341         //Now, copy over new pig
342         songs_stop_redbook();           //so we can read off the cd
343
344         // make the source path "<cd volume>:Data:filename.pig"
345 //MWA   ConvertCToPStr(filename, pigfileNamePStr);
346
347 //MWA   ConcatPStr(sourcePathAndFilePStr, "\pDescent II:Data:");        // volume ID is cd_VRefNum
348 //MWA   ConcatPStr(sourcePathAndFilePStr, pigfileNamePStr);
349
350         strupr(filename);
351         strcpy(sourcePathAndFileCStr, "Descent II:Data:");
352         strcat(sourcePathAndFileCStr, filename);
353         
354         // make the destination path "<default directory>:Data:filename.pig"
355 //MWA   ConcatPStr(destPathAndFilePStr, "\p:Data:");
356 //MWA   ConcatPStr(destPathAndFilePStr, pigfileNamePStr);
357 //MWA   ConvertPToCStr(sourcePathAndFilePStr, sourcePathAndFileCStr);
358 //MWA   ConvertPToCStr(destPathAndFilePStr, destPathAndFileCStr);
359
360         strcpy(destPathAndFileCStr, ":Data:");
361         strcat(destPathAndFileCStr, filename);
362
363         strcpy(sourcePathAndFilePStr, sourcePathAndFileCStr);
364         strcpy(destPathAndFilePStr, destPathAndFileCStr);
365         c2pstr(sourcePathAndFilePStr);
366         c2pstr(destPathAndFilePStr);
367         
368         do {
369                 // Open the source file
370                 sourceFile = fopen(sourcePathAndFileCStr,"rb");
371
372                 if (!sourceFile) {
373
374                         if (request_cd() == -1)
375                                 Error("Cannot load file <%s> from CD",filename);
376                 }
377
378         } while (!sourceFile);
379
380
381         // Get the time stamp from the source file
382         theSourcePigHFSParams.fileParam.ioCompletion    = nil;
383         theSourcePigHFSParams.fileParam.ioNamePtr               = sourcePathAndFilePStr;
384         theSourcePigHFSParams.fileParam.ioVRefNum               = cd_VRefNum;
385         theSourcePigHFSParams.fileParam.ioFDirIndex     = 0;
386         theSourcePigHFSParams.fileParam.ioDirID         = 0;
387         
388         theErr = PBHGetFInfo(&theSourcePigHFSParams, false);
389         if (theErr != noErr)
390         {
391                 // Error getting file time stamp!! Why? JTS
392                 Error("Can't get old file time stamp: <%s>\n", sourcePathAndFileCStr);
393         }
394         
395         // Copy the file over
396         // C Stuff......
397         
398         // Open the destination file
399         destFile = fopen(destPathAndFileCStr,"wb");
400         if (!destFile)
401         {
402                 Error("Cannot create file: <%s>\n", destPathAndFileCStr);
403         }
404         
405         // Copy bytes until the end of the source file
406         while (!feof(sourceFile))
407         {
408                 int bytes_read;
409                 int x;
410
411                 bytes_read = fread(buf,1,BUF_SIZE,sourceFile);
412                 if (ferror(sourceFile))
413                         Error("Cannot read from file <%s>: %s", sourcePathAndFileCStr, strerror(errno));
414
415 // Assert is bogus              Assert(bytes_read == BUF_SIZE || feof(sourceFile));
416
417                 fwrite(buf,1,bytes_read,destFile);
418                 if (ferror(destFile))
419                         Error("Cannot write to file <%s>: %s",destPathAndFileCStr, strerror(errno));
420         }
421
422         // close the source/dest files
423         if (fclose(sourceFile))
424                 Error("Error closing file <%s>: %s", sourcePathAndFileCStr, strerror(errno));
425         if (fclose(destFile))
426                 Error("Error closing file <%s>: %s", destPathAndFileCStr, strerror(errno));
427
428         // Get the current hfs data for the new file
429         theDestPigHFSParams.fileParam.ioCompletion      = nil;
430         theDestPigHFSParams.fileParam.ioNamePtr         = destPathAndFilePStr;
431         theDestPigHFSParams.fileParam.ioVRefNum         = 0;
432         theDestPigHFSParams.fileParam.ioFDirIndex       = 0;
433         theDestPigHFSParams.fileParam.ioDirID           = 0;
434         theErr = PBHGetFInfo(&theDestPigHFSParams, false);
435         if ((theErr != noErr) || (theDestPigHFSParams.fileParam.ioResult != noErr))
436         {
437                 // Error getting file time stamp!! Why? JTS
438                 Error("Can't get destination pig file information: <%s>\n", destPathAndFileCStr);
439         }
440
441         // Reset this data !!!!! or else the relative pathname won't work, could use just filename instead but, oh well.
442         theDestPigHFSParams.fileParam.ioNamePtr         = destPathAndFilePStr;
443         theDestPigHFSParams.fileParam.ioVRefNum         = 0;
444         theDestPigHFSParams.fileParam.ioFDirIndex       = 0;
445         theDestPigHFSParams.fileParam.ioDirID           = 0;
446
447         // Copy the time stamp from the source file info
448         theDestPigHFSParams.fileParam.ioFlCrDat = theSourcePigHFSParams.fileParam.ioFlCrDat;
449         theDestPigHFSParams.fileParam.ioFlMdDat = theSourcePigHFSParams.fileParam.ioFlMdDat;
450         theDestPigHFSParams.fileParam.ioFlFndrInfo.fdType = 'PGGY';
451         theDestPigHFSParams.fileParam.ioFlFndrInfo.fdCreator = 'DCT2';
452         
453         // Set the dest file's time stamp to the source file's time stamp values
454         theErr = PBHSetFInfo(&theDestPigHFSParams, false);
455
456         if ((theErr != noErr) || (theDestPigHFSParams.fileParam.ioResult != noErr))
457         {
458                 Error("Can't set destination pig file time stamp: <%s>\n", destPathAndFileCStr);
459         }
460
461         theErr = PBHGetFInfo(&theDestPigHFSParams, false);
462
463         return cfopen(destPathAndFileCStr, "rb");
464 }
465
466 #else   //PC Version of copy_pigfile_from_cd is below
467
468 //copies a pigfile from the CD to the current dir
469 //retuns file handle of new pig
470 CFILE *copy_pigfile_from_cd(char *filename)
471 {
472         char name[80];
473         FILEFINDSTRUCT find;
474         int ret;
475
476         return cfopen(filename, "rb");
477         show_boxed_message("Copying bitmap data from CD...");
478         gr_palette_load(gr_palette);    //I don't think this line is really needed
479
480         //First, delete all PIG files currently in the directory
481
482         if( !FileFindFirst( "*.pig", &find ) ) {
483                 do      {
484                         remove(find.name);
485                 } while( !FileFindNext( &find ) );
486                 FileFindClose();
487         }
488
489         //Now, copy over new pig
490
491         songs_stop_redbook();           //so we can read off the cd
492
493         //new code to unarj file
494         strcpy(name,CDROM_dir);
495         strcat(name,"descent2.sow");
496
497         do {
498 //              ret = unarj_specific_file(name,filename,filename);
499 // DPH:FIXME
500
501                 ret = !EXIT_SUCCESS;
502
503                 if (ret != EXIT_SUCCESS) {
504
505                         //delete file, so we don't leave partial file
506                         remove(filename);
507
508                         #ifndef MACINTOSH
509                         if (request_cd() == -1)
510                         #endif
511                                 //NOTE LINK TO ABOVE IF
512                                 Error("Cannot load file <%s> from CD",filename);
513                 }
514
515         } while (ret != EXIT_SUCCESS);
516
517         return cfopen(filename, "rb");
518 }
519
520 #endif // end of ifdef MAC around copy_pigfile_from_cd
521
522 //initialize a pigfile, reading headers
523 //returns the size of all the bitmap data
524 void piggy_init_pigfile(char *filename)
525 {
526         int i;
527         char temp_name[16];
528         char temp_name_read[16];
529         grs_bitmap temp_bitmap;
530         DiskBitmapHeader bmh;
531         int header_size, N_bitmaps, data_size, data_start;
532         #ifdef MACINTOSH
533         char name[255];         // filename + path for the mac
534         #endif
535
536         piggy_close_file();             //close old pig if still open
537
538         #ifdef SHAREWARE                //rename pigfile for shareware
539         if (stricmp(filename,DEFAULT_PIGFILE_REGISTERED)==0)
540                 filename = DEFAULT_PIGFILE_SHAREWARE;
541         #endif
542
543         #ifndef MACINTOSH
544                 Piggy_fp = cfopen( filename, "rb" );
545         #else
546                 sprintf(name, ":Data:%s", filename);
547                 Piggy_fp = cfopen( name, "rb" );
548         
549                 #ifdef SHAREWARE        // if we are in the shareware version, we must have the pig by now.
550                         if (Piggy_fp == NULL)
551                         {
552                                 Error("Cannot load required file <%s>",name);
553                         }
554                 #endif  // end of if def shareware
555         
556         #endif
557
558         if (!Piggy_fp) {
559                 #ifdef EDITOR
560                         return;         //if editor, ok to not have pig, because we'll build one
561                 #else
562                         Piggy_fp = copy_pigfile_from_cd(filename);
563                 #endif
564         }
565
566         if (Piggy_fp) {                         //make sure pig is valid type file & is up-to-date
567                 int pig_version;
568                 char pig_id[4];
569
570                 cfread(&pig_id, 1, 4, Piggy_fp);
571                 pig_version = cfile_read_int(Piggy_fp);
572                 if (memcmp(pig_id, PIGFILE_ID, 4) || pig_version != PIGFILE_VERSION) {
573                         cfclose(Piggy_fp);              //out of date pig
574                         Piggy_fp = NULL;                        //..so pretend it's not here
575                 }
576         }
577
578         if (!Piggy_fp) {
579
580                 #ifdef EDITOR
581                         return;         //if editor, ok to not have pig, because we'll build one
582                 #else
583                         Error("Cannot load required file <%s>",filename);
584                 #endif
585         }
586
587         strncpy(Current_pigfile,filename,sizeof(Current_pigfile));
588
589         N_bitmaps = cfile_read_int(Piggy_fp);
590
591         header_size = N_bitmaps*sizeof(DiskBitmapHeader);
592
593         data_start = header_size + cftell(Piggy_fp);
594
595         data_size = cfilelength(Piggy_fp) - data_start;
596
597         Num_bitmap_files = 1;
598
599         for (i=0; i<N_bitmaps; i++ )    {
600 #ifndef MACINTOSH
601                 cfread( &bmh, sizeof(DiskBitmapHeader), 1, Piggy_fp );
602 #else
603                 cfread(bmh.name, 8, 1, Piggy_fp);
604                 bmh.dflags = cfile_read_byte(Piggy_fp);
605                 bmh.width = cfile_read_byte(Piggy_fp);
606                 bmh.height = cfile_read_byte(Piggy_fp);
607                 bmh.wh_extra = cfile_read_byte(Piggy_fp);
608                 bmh.flags = cfile_read_byte(Piggy_fp);
609                 bmh.avg_color = cfile_read_byte(Piggy_fp);
610                 bmh.offset = cfile_read_int(Piggy_fp);
611 #endif
612                 memcpy( temp_name_read, bmh.name, 8 );
613                 temp_name_read[8] = 0;
614                 if ( bmh.dflags & DBM_FLAG_ABM )        
615                         sprintf( temp_name, "%s#%d", temp_name_read, bmh.dflags & 63 );
616                 else
617                         strcpy( temp_name, temp_name_read );
618                 memset( &temp_bitmap, 0, sizeof(grs_bitmap) );
619                 temp_bitmap.bm_w = temp_bitmap.bm_rowsize = bmh.width + ((short) (bmh.wh_extra&0x0f)<<8);
620                 temp_bitmap.bm_h = bmh.height + ((short) (bmh.wh_extra&0xf0)<<4);
621                 temp_bitmap.bm_flags = BM_FLAG_PAGED_OUT;
622                 temp_bitmap.avg_color = bmh.avg_color;
623                 temp_bitmap.bm_data = Piggy_bitmap_cache_data;
624
625                 GameBitmapFlags[i+1] = 0;
626                 if ( bmh.flags & BM_FLAG_TRANSPARENT ) GameBitmapFlags[i+1] |= BM_FLAG_TRANSPARENT;
627                 if ( bmh.flags & BM_FLAG_SUPER_TRANSPARENT ) GameBitmapFlags[i+1] |= BM_FLAG_SUPER_TRANSPARENT;
628                 if ( bmh.flags & BM_FLAG_NO_LIGHTING ) GameBitmapFlags[i+1] |= BM_FLAG_NO_LIGHTING;
629                 if ( bmh.flags & BM_FLAG_RLE ) GameBitmapFlags[i+1] |= BM_FLAG_RLE;
630                 if ( bmh.flags & BM_FLAG_RLE_BIG ) GameBitmapFlags[i+1] |= BM_FLAG_RLE_BIG;
631
632                 GameBitmapOffset[i+1] = bmh.offset + data_start;
633                 Assert( (i+1) == Num_bitmap_files );
634                 piggy_register_bitmap( &temp_bitmap, temp_name, 1 );
635         }
636
637 #ifdef EDITOR
638         Piggy_bitmap_cache_size = data_size + (data_size/10);   //extra mem for new bitmaps
639         Assert( Piggy_bitmap_cache_size > 0 );
640 #else
641         Piggy_bitmap_cache_size = PIGGY_BUFFER_SIZE;
642         #ifdef MACINTOSH
643         if (piggy_low_memory)
644                 Piggy_bitmap_cache_size = PIGGY_SMALL_BUFFER_SIZE;
645         #endif
646 #endif
647         BitmapBits = d_malloc( Piggy_bitmap_cache_size );
648         if ( BitmapBits == NULL )
649                 Error( "Not enough memory to load bitmaps\n" );
650         Piggy_bitmap_cache_data = BitmapBits;   
651         Piggy_bitmap_cache_next = 0;
652         
653         #if defined(MACINTOSH) && defined(SHAREWARE)
654 //      load_exit_models();
655         #endif
656
657         Pigfile_initialized=1;  
658 }
659
660 #define FILENAME_LEN 13
661 #define MAX_BITMAPS_PER_BRUSH 30
662
663 extern int compute_average_pixel(grs_bitmap *new);
664
665 //reads in a new pigfile (for new palette)
666 //returns the size of all the bitmap data
667 void piggy_new_pigfile(char *pigname)
668 {
669         int i;
670         char temp_name[16];
671         char temp_name_read[16];
672         grs_bitmap temp_bitmap;
673         DiskBitmapHeader bmh;
674         int header_size, N_bitmaps, data_size, data_start;
675         int must_rewrite_pig = 0;
676         #ifdef MACINTOSH
677         char name[255];
678         #endif
679
680         strlwr(pigname);
681
682         #ifdef SHAREWARE                //rename pigfile for shareware
683         if (stricmp(pigname,DEFAULT_PIGFILE_REGISTERED)==0)
684                 pigname = DEFAULT_PIGFILE_SHAREWARE;
685         #endif
686
687         if (strnicmp(Current_pigfile,pigname,sizeof(Current_pigfile))==0)
688                 return;         //already have correct pig
689
690         if (!Pigfile_initialized) {                     //have we ever opened a pigfile?
691                 piggy_init_pigfile(pigname);            //..no, so do initialization stuff
692                 return;
693         }
694         else
695                 piggy_close_file();             //close old pig if still open
696
697         Piggy_bitmap_cache_next = 0;            //free up cache
698
699         strncpy(Current_pigfile,pigname,sizeof(Current_pigfile));
700
701         #ifndef MACINTOSH
702                 Piggy_fp = cfopen( pigname, "rb" );
703         #else
704                 sprintf(name, ":Data:%s", pigname);
705                 Piggy_fp = cfopen( name, "rb" );
706
707                 #ifdef SHAREWARE        // if we are in the shareware version, we must have the pig by now.
708                         if (Piggy_fp == NULL)
709                         {
710                                 Error("Cannot load required file <%s>",name);
711                         }
712                 #endif  // end of if def shareware
713         #endif
714
715         #ifndef EDITOR
716         if (!Piggy_fp)
717                 Piggy_fp = copy_pigfile_from_cd(pigname);
718         #endif
719
720         if (Piggy_fp) {                         //make sure pig is valid type file & is up-to-date
721                 int pig_version;
722                 char pig_id[4];
723
724                 cfread(&pig_id, 1, 4, Piggy_fp);
725                 pig_version = cfile_read_int(Piggy_fp);
726                 if (memcmp(pig_id, PIGFILE_ID, 4) || pig_version != PIGFILE_VERSION) {
727                         cfclose(Piggy_fp);              //out of date pig
728                         Piggy_fp = NULL;                        //..so pretend it's not here
729                 }
730         }
731
732         #ifndef EDITOR
733         if (!Piggy_fp) Error ("Piggy_fp not defined in piggy_new_pigfile.");
734         #endif
735
736         if (Piggy_fp) {
737
738                 N_bitmaps = cfile_read_int(Piggy_fp);
739         
740                 header_size = N_bitmaps*sizeof(DiskBitmapHeader);
741         
742                 data_start = header_size + cftell(Piggy_fp);
743
744                 data_size = cfilelength(Piggy_fp) - data_start;
745         
746                 for (i=1; i<=N_bitmaps; i++ )   {
747 #ifndef MACINTOSH       
748                         cfread( &bmh, sizeof(DiskBitmapHeader), 1, Piggy_fp );
749 #else
750                         cfread(bmh.name, 8, 1, Piggy_fp);
751                         bmh.dflags = cfile_read_byte(Piggy_fp);
752                         bmh.width = cfile_read_byte(Piggy_fp);
753                         bmh.height = cfile_read_byte(Piggy_fp);
754                         bmh.wh_extra = cfile_read_byte(Piggy_fp);
755                         bmh.flags = cfile_read_byte(Piggy_fp);
756                         bmh.avg_color = cfile_read_byte(Piggy_fp);
757                         bmh.offset = cfile_read_int(Piggy_fp);
758 #endif
759                         memcpy( temp_name_read, bmh.name, 8 );
760                         temp_name_read[8] = 0;
761         
762                         if ( bmh.dflags & DBM_FLAG_ABM )        
763                                 sprintf( temp_name, "%s#%d", temp_name_read, bmh.dflags & 63 );
764                         else
765                                 strcpy( temp_name, temp_name_read );
766         
767                         //Make sure name matches
768                         if (strcmp(temp_name,AllBitmaps[i].name)) {
769                                 //Int3();       //this pig is out of date.  Delete it
770                                 must_rewrite_pig=1;
771                         }
772         
773                         strcpy(AllBitmaps[i].name,temp_name);
774
775                         memset( &temp_bitmap, 0, sizeof(grs_bitmap) );
776         
777                         temp_bitmap.bm_w = temp_bitmap.bm_rowsize = bmh.width + ((short) (bmh.wh_extra&0x0f)<<8);
778                         temp_bitmap.bm_h = bmh.height + ((short) (bmh.wh_extra&0xf0)<<4);
779                         temp_bitmap.bm_flags = BM_FLAG_PAGED_OUT;
780                         temp_bitmap.avg_color = bmh.avg_color;
781                         temp_bitmap.bm_data = Piggy_bitmap_cache_data;
782         
783                         GameBitmapFlags[i] = 0;
784         
785                         if ( bmh.flags & BM_FLAG_TRANSPARENT ) GameBitmapFlags[i] |= BM_FLAG_TRANSPARENT;
786                         if ( bmh.flags & BM_FLAG_SUPER_TRANSPARENT ) GameBitmapFlags[i] |= BM_FLAG_SUPER_TRANSPARENT;
787                         if ( bmh.flags & BM_FLAG_NO_LIGHTING ) GameBitmapFlags[i] |= BM_FLAG_NO_LIGHTING;
788                         if ( bmh.flags & BM_FLAG_RLE ) GameBitmapFlags[i] |= BM_FLAG_RLE;
789                         if ( bmh.flags & BM_FLAG_RLE_BIG ) GameBitmapFlags[i] |= BM_FLAG_RLE_BIG;
790         
791                         GameBitmapOffset[i] = bmh.offset + data_start;
792         
793                         GameBitmaps[i] = temp_bitmap;
794                 }
795         }
796         else
797                 N_bitmaps = 0;          //no pigfile, so no bitmaps
798
799         #ifndef EDITOR
800
801         Assert(N_bitmaps == Num_bitmap_files-1);
802
803         #else
804
805         if (must_rewrite_pig || (N_bitmaps < Num_bitmap_files-1)) {
806                 int size;
807
808                 //re-read the bitmaps that aren't in this pig
809
810                 for (i=N_bitmaps+1;i<Num_bitmap_files;i++) {
811                         char *p;
812
813                         p = strchr(AllBitmaps[i].name,'#');
814
815                         if (p) {                //this is an ABM
816                                 char abmname[FILENAME_LEN];
817                                 int fnum;
818                                 grs_bitmap * bm[MAX_BITMAPS_PER_BRUSH];
819                                 int iff_error;          //reference parm to avoid warning message
820                                 ubyte newpal[768];
821                                 char basename[FILENAME_LEN];
822                                 int nframes;
823                         
824                                 strcpy(basename,AllBitmaps[i].name);
825                                 basename[p-AllBitmaps[i].name] = 0;             //cut off "#nn" part
826                                 
827                                 sprintf( abmname, "%s.abm", basename );
828
829                       iff_error = iff_read_animbrush(abmname,bm,MAX_BITMAPS_PER_BRUSH,&nframes,newpal);
830
831                                 if (iff_error != IFF_NO_ERROR)  {
832                                         mprintf((1,"File %s - IFF error: %s",abmname,iff_errormsg(iff_error)));
833                                         Error("File %s - IFF error: %s",abmname,iff_errormsg(iff_error));
834                                 }
835                         
836                                 for (fnum=0;fnum<nframes; fnum++)       {
837                                         char tempname[20];
838                                         int SuperX;
839
840                                         sprintf( tempname, "%s#%d", basename, fnum );
841
842                                         //SuperX = (GameBitmaps[i+fnum].bm_flags&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
843                                         SuperX = (GameBitmapFlags[i+fnum]&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
844                                         //above makes assumption that supertransparent color is 254
845
846                                         if ( iff_has_transparency )
847                                                 gr_remap_bitmap_good( bm[fnum], newpal, iff_transparent_color, SuperX );
848                                         else
849                                                 gr_remap_bitmap_good( bm[fnum], newpal, -1, SuperX );
850                         
851                                         bm[fnum]->avg_color = compute_average_pixel(bm[fnum]);
852
853 #ifdef EDITOR
854                                         if ( args_find("-macdata") )
855                                                 swap_0_255( bm[fnum] );
856 #endif
857                                         if ( !BigPig ) gr_bitmap_rle_compress( bm[fnum] );
858
859                                         if (bm[fnum]->bm_flags & BM_FLAG_RLE)
860                                                 size = *((int *) bm[fnum]->bm_data);
861                                         else
862                                                 size = bm[fnum]->bm_w * bm[fnum]->bm_h;
863
864                                         memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next],bm[fnum]->bm_data,size);
865                                         d_free(bm[fnum]->bm_data);
866                                         bm[fnum]->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next];
867                                         Piggy_bitmap_cache_next += size;
868
869                                         GameBitmaps[i+fnum] = *bm[fnum];
870
871                                         // -- mprintf( (0, "U" ));
872                                         d_free( bm[fnum] );
873                                 }
874
875                                 i += nframes-1;         //filled in multiple bitmaps
876                         }
877                         else {          //this is a BBM
878
879                                 grs_bitmap * new;
880                                 ubyte newpal[256*3];
881                                 int iff_error;
882                                 char bbmname[FILENAME_LEN];
883                                 int SuperX;
884
885                                 MALLOC( new, grs_bitmap, 1 );
886
887                                 sprintf( bbmname, "%s.bbm", AllBitmaps[i].name );
888                                 iff_error = iff_read_bitmap(bbmname,new,BM_LINEAR,newpal);
889
890                                 new->bm_handle=0;
891                                 if (iff_error != IFF_NO_ERROR)          {
892                                         mprintf((1, "File %s - IFF error: %s",bbmname,iff_errormsg(iff_error)));
893                                         Error("File %s - IFF error: %s",bbmname,iff_errormsg(iff_error));
894                                 }
895                         
896                                 SuperX = (GameBitmapFlags[i]&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
897                                 //above makes assumption that supertransparent color is 254
898
899                                 if ( iff_has_transparency )
900                                         gr_remap_bitmap_good( new, newpal, iff_transparent_color, SuperX );
901                                 else
902                                         gr_remap_bitmap_good( new, newpal, -1, SuperX );
903                         
904                                 new->avg_color = compute_average_pixel(new);
905                         
906 #ifdef EDITOR
907                                         if ( args_find("-macdata") )
908                                                 swap_0_255( new );
909 #endif
910                                 if ( !BigPig )  gr_bitmap_rle_compress( new );
911
912                                 if (new->bm_flags & BM_FLAG_RLE)
913                                         size = *((int *) new->bm_data);
914                                 else
915                                         size = new->bm_w * new->bm_h;
916
917                                 memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next],new->bm_data,size);
918                                 d_free(new->bm_data);
919                                 new->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next];
920                                 Piggy_bitmap_cache_next += size;
921
922                                 GameBitmaps[i] = *new;
923         
924                                 d_free( new );
925
926                                 // -- mprintf( (0, "U" ));
927                         }
928                 }
929
930                 //@@Dont' do these things which are done when writing
931                 //@@for (i=0; i < Num_bitmap_files; i++ )       {
932                 //@@    bitmap_index bi;
933                 //@@    bi.index = i;
934                 //@@    PIGGY_PAGE_IN( bi );
935                 //@@}
936                 //@@
937                 //@@piggy_close_file();
938
939                 piggy_write_pigfile(pigname);
940
941                 Current_pigfile[0] = 0;                 //say no pig, to force reload
942                 
943                 piggy_new_pigfile(pigname);             //read in just-generated pig
944
945
946         }
947         #endif  //ifdef EDITOR
948
949 }
950
951 ubyte bogus_data[64*64];
952 grs_bitmap bogus_bitmap;
953 ubyte bogus_bitmap_initialized=0;
954 digi_sound bogus_sound;
955
956 extern void bm_read_all(CFILE * fp);
957
958 #define HAMFILE_ID              "HAM!"          //HAM!
959 #define HAMFILE_VERSION 3
960 //version 1 -> 2:  save marker_model_num
961 //version 2 -> 3:  removed sound files
962
963 #define SNDFILE_ID              "DSND"          //DSND
964 #define SNDFILE_VERSION 1
965
966 int read_hamfile()
967 {
968         CFILE * ham_fp = NULL;
969         int ham_version;
970         char ham_id[4];
971         #ifdef MACINTOSH
972         char name[255];
973         #endif
974         
975         #ifndef MACINTOSH
976         ham_fp = cfopen( DEFAULT_HAMFILE, "rb" );
977         #else
978         sprintf(name, ":Data:%s", DEFAULT_HAMFILE );
979         ham_fp = cfopen( name, "rb" );
980         #endif
981         
982         if (ham_fp == NULL) {
983                 Must_write_hamfile = 1;
984                 return 0;
985         }
986
987         //make sure ham is valid type file & is up-to-date
988         cfread( &ham_id, 1, 4, ham_fp );
989         ham_version = cfile_read_int(ham_fp);
990         if (memcmp(ham_id, HAMFILE_ID, 4) || ham_version != HAMFILE_VERSION) {
991                 Must_write_hamfile = 1;
992                 cfclose(ham_fp);                                                //out of date ham
993                 return 0;
994         }
995
996         #ifndef EDITOR
997         {
998                 bm_read_all( ham_fp );  // Note connection to above if!!!
999                 cfread( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
1000                 #ifdef MACINTOSH
1001                 {
1002                         int i;
1003                         
1004                         for (i = 0; i < MAX_BITMAP_FILES; i++)
1005                                 GameBitmapXlat[i] = SWAPSHORT(GameBitmapXlat[i]);
1006                 }
1007                 #endif
1008         }
1009         #endif
1010
1011         cfclose(ham_fp);
1012
1013         return 1;
1014
1015 }
1016
1017 int read_sndfile()
1018 {
1019         CFILE * snd_fp = NULL;
1020         int snd_version;
1021         char snd_id[4];
1022         int N_sounds;
1023         int sound_start;
1024         int header_size;
1025         int i,size, length;
1026         DiskSoundHeader sndh;
1027         digi_sound temp_sound;
1028         char temp_name_read[16];
1029         int sbytes = 0;
1030         #ifdef MACINTOSH
1031         char name[255];
1032         #endif
1033
1034         #ifndef MACINTOSH
1035         snd_fp = cfopen( DEFAULT_SNDFILE, "rb" );
1036         #else
1037         sprintf( name, ":Data:%s", DEFAULT_SNDFILE );
1038         snd_fp = cfopen( name, "rb");
1039         #endif
1040         
1041         if (snd_fp == NULL)
1042                 return 0;
1043
1044         //make sure soundfile is valid type file & is up-to-date
1045         cfread( &snd_id, 1, 4, snd_fp );
1046         snd_version = cfile_read_int(snd_fp);
1047         if (memcmp(snd_id, SNDFILE_ID, 4) || snd_version != SNDFILE_VERSION) {
1048                 cfclose(snd_fp);                                                //out of date sound file
1049                 return 0;
1050         }
1051
1052         N_sounds = cfile_read_int(snd_fp);
1053
1054         sound_start = cftell(snd_fp);
1055         size = cfilelength(snd_fp) - sound_start;
1056         length = size;
1057         mprintf( (0, "\nReading data (%d KB) ", size/1024 ));
1058
1059         header_size = N_sounds*sizeof(DiskSoundHeader);
1060
1061         //Read sounds
1062
1063         for (i=0; i<N_sounds; i++ )     {
1064                 cfread( sndh.name, 8, 1, snd_fp);
1065                 sndh.length = cfile_read_int(snd_fp);
1066                 sndh.data_length = cfile_read_int(snd_fp);
1067                 sndh.offset = cfile_read_int(snd_fp);
1068 //              cfread( &sndh, sizeof(DiskSoundHeader), 1, snd_fp );
1069                 //size -= sizeof(DiskSoundHeader);
1070                 temp_sound.length = sndh.length;
1071                 temp_sound.data = (ubyte *)(sndh.offset + header_size + sound_start);
1072                 SoundOffset[Num_sound_files] = sndh.offset + header_size + sound_start;
1073                 memcpy( temp_name_read, sndh.name, 8 );
1074                 temp_name_read[8] = 0;
1075                 piggy_register_sound( &temp_sound, temp_name_read, 1 );
1076                 #ifdef MACINTOSH
1077                 if (piggy_is_needed(i))
1078                 #endif          // note link to if.
1079                 sbytes += sndh.length;
1080                 //mprintf(( 0, "%d bytes of sound\n", sbytes ));
1081         }
1082
1083         SoundBits = d_malloc( sbytes + 16 );
1084         if ( SoundBits == NULL )
1085                 Error( "Not enough memory to load sounds\n" );
1086
1087         mprintf(( 0, "\nBitmaps: %d KB   Sounds: %d KB\n", Piggy_bitmap_cache_size/1024, sbytes/1024 ));
1088
1089 //      piggy_read_sounds(snd_fp);
1090
1091         cfclose(snd_fp);
1092
1093         return 1;
1094 }
1095
1096 int piggy_init(void)
1097 {
1098         int ham_ok=0,snd_ok=0;
1099         int i;
1100
1101         hashtable_init( &AllBitmapsNames, MAX_BITMAP_FILES );
1102         hashtable_init( &AllDigiSndNames, MAX_SOUND_FILES );
1103
1104         for (i=0; i<MAX_SOUND_FILES; i++ )      {
1105                 GameSounds[i].length = 0;
1106                 GameSounds[i].data = NULL;
1107                 SoundOffset[i] = 0;
1108         }
1109
1110         for (i=0; i<MAX_BITMAP_FILES; i++ )     
1111                 GameBitmapXlat[i] = i;
1112
1113         if ( !bogus_bitmap_initialized )        {
1114                 int i;
1115                 ubyte c;
1116                 bogus_bitmap_initialized = 1;
1117                 memset( &bogus_bitmap, 0, sizeof(grs_bitmap) );
1118                 bogus_bitmap.bm_w = bogus_bitmap.bm_h = bogus_bitmap.bm_rowsize = 64;
1119                 bogus_bitmap.bm_data = bogus_data;
1120                 c = gr_find_closest_color( 0, 0, 63 );
1121                 for (i=0; i<4096; i++ ) bogus_data[i] = c;
1122                 c = gr_find_closest_color( 63, 0, 0 );
1123                 // Make a big red X !
1124                 for (i=0; i<64; i++ )   {
1125                         bogus_data[i*64+i] = c;
1126                         bogus_data[i*64+(63-i)] = c;
1127                 }
1128                 piggy_register_bitmap( &bogus_bitmap, "bogus", 1 );
1129                 bogus_sound.length = 64*64;
1130                 bogus_sound.data = bogus_data;
1131                 GameBitmapOffset[0] = 0;
1132         }
1133
1134         if ( args_find( "-bigpig" ))
1135                 BigPig = 1;
1136
1137         if ( args_find( "-lowmem" ))
1138                 piggy_low_memory = 1;
1139
1140         if ( args_find( "-nolowmem" ))
1141                 piggy_low_memory = 0;
1142
1143         if (piggy_low_memory)
1144                 digi_lomem = 1;
1145
1146         WIN(DDGRLOCK(dd_grd_curcanv));
1147                 gr_set_curfont( SMALL_FONT );
1148                 gr_set_fontcolor(gr_find_closest_color_current( 20, 20, 20 ),-1 );
1149                 gr_printf( 0x8000, grd_curcanv->cv_h-20, "%s...", TXT_LOADING_DATA );
1150         WIN(DDGRUNLOCK(dd_grd_curcanv));
1151                 
1152         #ifdef EDITOR
1153         piggy_init_pigfile(DEFAULT_PIGFILE);
1154         #endif
1155
1156         ham_ok = read_hamfile();
1157
1158         snd_ok = read_sndfile();
1159
1160         atexit(piggy_close);
1161
1162    mprintf ((0,"HamOk=%d SndOk=%d\n",ham_ok,snd_ok));
1163         return (ham_ok && snd_ok);               //read ok
1164 }
1165
1166 int piggy_is_needed(int soundnum)
1167 {
1168         int i;
1169
1170         if ( !digi_lomem ) return 1;
1171
1172         for (i=0; i<MAX_SOUNDS; i++ )   {
1173                 if ( (AltSounds[i] < 255) && (Sounds[AltSounds[i]] == soundnum) )
1174                         return 1;
1175         }
1176         return 0;
1177 }
1178
1179
1180 void piggy_read_sounds(void)
1181 {
1182         CFILE * fp = NULL;
1183         ubyte * ptr;
1184         int i, sbytes;
1185         #ifdef MACINTOSH
1186         char name[255];
1187         #endif
1188
1189         ptr = SoundBits;
1190         sbytes = 0;
1191
1192         #ifndef MACINTOSH
1193         fp = cfopen( DEFAULT_SNDFILE, "rb" );
1194         #else
1195         sprintf( name, ":Data:%s", DEFAULT_SNDFILE );
1196         fp = cfopen( name, "rb");
1197         #endif
1198
1199         if (fp == NULL)
1200                 return;
1201
1202         for (i=0; i<Num_sound_files; i++ )      {
1203                 digi_sound *snd = &GameSounds[i];
1204
1205                 if ( SoundOffset[i] > 0 )       {
1206                         if ( piggy_is_needed(i) )       {
1207                                 cfseek( fp, SoundOffset[i], SEEK_SET );
1208         
1209                                 // Read in the sound data!!!
1210                                 snd->data = ptr;
1211                                 ptr += snd->length;
1212                                 sbytes += snd->length;
1213                                 cfread( snd->data, snd->length, 1, fp );
1214                         }
1215                         else
1216                                 snd->data = (ubyte *) -1;
1217                 }
1218         }
1219
1220         cfclose(fp);
1221
1222         mprintf(( 0, "\nActual Sound usage: %d KB\n", sbytes/1024 ));
1223
1224 }
1225
1226
1227 extern int descent_critical_error;
1228 extern unsigned descent_critical_deverror;
1229 extern unsigned descent_critical_errcode;
1230
1231 char * crit_errors[13] = { "Write Protected", "Unknown Unit", "Drive Not Ready", "Unknown Command", "CRC Error", \
1232 "Bad struct length", "Seek Error", "Unknown media type", "Sector not found", "Printer out of paper", "Write Fault", \
1233 "Read fault", "General Failure" };
1234
1235 void piggy_critical_error()
1236 {
1237         grs_canvas * save_canv;
1238         grs_font * save_font;
1239         int i;
1240         save_canv = grd_curcanv;
1241         save_font = grd_curcanv->cv_font;
1242         gr_palette_load( gr_palette );
1243         i = nm_messagebox( "Disk Error", 2, "Retry", "Exit", "%s\non drive %c:", crit_errors[descent_critical_errcode&0xf], (descent_critical_deverror&0xf)+'A'  );
1244         if ( i == 1 )
1245                 exit(1);
1246         gr_set_current_canvas(save_canv);
1247         grd_curcanv->cv_font = save_font;
1248 }
1249
1250 void piggy_bitmap_page_in( bitmap_index bitmap )
1251 {
1252         grs_bitmap * bmp;
1253         int i,org_i,temp;
1254
1255         org_i = 0;
1256                         
1257         i = bitmap.index;
1258         Assert( i >= 0 );
1259         Assert( i < MAX_BITMAP_FILES );
1260         Assert( i < Num_bitmap_files );
1261         Assert( Piggy_bitmap_cache_size > 0 );
1262
1263         if ( i < 1 ) return;
1264         if ( i >= MAX_BITMAP_FILES ) return;
1265         if ( i >= Num_bitmap_files ) return;
1266         
1267         if ( GameBitmapOffset[i] == 0 ) return;         // A read-from-disk bitmap!!!
1268
1269         if ( piggy_low_memory ) {
1270                 org_i = i;
1271                 i = GameBitmapXlat[i];          // Xlat for low-memory settings!
1272         }
1273         
1274         bmp = &GameBitmaps[i];
1275
1276         if ( bmp->bm_flags & BM_FLAG_PAGED_OUT )        {
1277                 stop_time();
1278
1279         ReDoIt:
1280                 descent_critical_error = 0;
1281                 cfseek( Piggy_fp, GameBitmapOffset[i], SEEK_SET );
1282                 if ( descent_critical_error )   {
1283                         piggy_critical_error();
1284                         goto ReDoIt;
1285                 }
1286                 
1287                 bmp->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next];
1288                 bmp->bm_flags = GameBitmapFlags[i];
1289         
1290                 if ( bmp->bm_flags & BM_FLAG_RLE )      {
1291                         int zsize = 0;
1292                         descent_critical_error = 0;
1293                         zsize = cfile_read_int(Piggy_fp);
1294                         if ( descent_critical_error )   {
1295                                 piggy_critical_error();
1296                                 goto ReDoIt;
1297                         }
1298         
1299                         // GET JOHN NOW IF YOU GET THIS ASSERT!!!
1300                         //Assert( Piggy_bitmap_cache_next+zsize < Piggy_bitmap_cache_size );      
1301                         if ( Piggy_bitmap_cache_next+zsize >= Piggy_bitmap_cache_size ) {
1302                                 Int3();
1303                                 piggy_bitmap_page_out_all();
1304                                 goto ReDoIt;
1305                         }
1306                         memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], &zsize, sizeof(int) );
1307                         Piggy_bitmap_cache_next += sizeof(int);
1308                         descent_critical_error = 0;
1309                         temp = cfread( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], 1, zsize-4, Piggy_fp );
1310                         if ( descent_critical_error )   {
1311                                 piggy_critical_error();
1312                                 goto ReDoIt;
1313                         }
1314                         Piggy_bitmap_cache_next += zsize-4;
1315                 } else {
1316                         // GET JOHN NOW IF YOU GET THIS ASSERT!!!
1317                         Assert( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) < Piggy_bitmap_cache_size );      
1318                         if ( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) >= Piggy_bitmap_cache_size ) {
1319                                 piggy_bitmap_page_out_all();
1320                                 goto ReDoIt;
1321                         }
1322                         descent_critical_error = 0;
1323                         temp = cfread( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], 1, bmp->bm_h*bmp->bm_w, Piggy_fp );
1324                         if ( descent_critical_error )   {
1325                                 piggy_critical_error();
1326                                 goto ReDoIt;
1327                         }
1328                         Piggy_bitmap_cache_next+=bmp->bm_h*bmp->bm_w;
1329                 }
1330         
1331                 //@@if ( bmp->bm_selector ) {
1332                 //@@#if !defined(WINDOWS) && !defined(MACINTOSH)
1333                 //@@    if (!dpmi_modify_selector_base( bmp->bm_selector, bmp->bm_data ))
1334                 //@@            Error( "Error modifying selector base in piggy.c\n" );
1335                 //@@#endif
1336                 //@@}
1337
1338                 start_time();
1339         }
1340
1341         if ( piggy_low_memory ) {
1342                 if ( org_i != i )
1343                         GameBitmaps[org_i] = GameBitmaps[i];
1344         }
1345
1346 //@@Removed from John's code:
1347 //@@#ifndef WINDOWS
1348 //@@    if ( bmp->bm_selector ) {
1349 //@@            if (!dpmi_modify_selector_base( bmp->bm_selector, bmp->bm_data ))
1350 //@@                    Error( "Error modifying selector base in piggy.c\n" );
1351 //@@    }
1352 //@@#endif
1353
1354 }
1355
1356 void piggy_bitmap_page_out_all()
1357 {
1358         int i;
1359         
1360         Piggy_bitmap_cache_next = 0;
1361
1362         piggy_page_flushed++;
1363
1364         texmerge_flush();
1365         rle_cache_flush();
1366
1367         for (i=0; i<Num_bitmap_files; i++ )             {
1368                 if ( GameBitmapOffset[i] > 0 )  {       // Don't page out bitmaps read from disk!!!
1369                         GameBitmaps[i].bm_flags = BM_FLAG_PAGED_OUT;
1370                         GameBitmaps[i].bm_data = Piggy_bitmap_cache_data;
1371                 }
1372         }
1373
1374         mprintf(( 0, "Flushing piggy bitmap cache\n" ));
1375 }
1376
1377 void piggy_load_level_data()
1378 {
1379         piggy_bitmap_page_out_all();
1380         paging_touch_all();
1381 }
1382
1383 #ifdef EDITOR
1384
1385 void change_filename_ext( char *dest, char *src, char *ext );
1386
1387 void piggy_write_pigfile(char *filename)
1388 {
1389         FILE *pig_fp;
1390         int bitmap_data_start,data_offset;
1391         DiskBitmapHeader bmh;
1392         int org_offset;
1393         char subst_name[32];
1394         int i;
1395         FILE *fp1,*fp2;
1396         char tname[FILENAME_LEN];
1397
1398         // -- mprintf( (0, "Paging in all piggy bitmaps..." ));
1399         for (i=0; i < Num_bitmap_files; i++ )   {
1400                 bitmap_index bi;
1401                 bi.index = i;
1402                 PIGGY_PAGE_IN( bi );
1403         }
1404         // -- mprintf( (0, "\n" ));
1405
1406         piggy_close_file();
1407
1408         // -- mprintf( (0, "Creating %s...",filename ));
1409
1410         pig_fp = fopen( filename, "wb" );       //open PIG file
1411         Assert( pig_fp!=NULL );
1412
1413         write_int(PIGFILE_ID,pig_fp);
1414         write_int(PIGFILE_VERSION,pig_fp);
1415
1416         Num_bitmap_files--;
1417         fwrite( &Num_bitmap_files, sizeof(int), 1, pig_fp );
1418         Num_bitmap_files++;
1419
1420         bitmap_data_start = ftell(pig_fp);
1421         bitmap_data_start += (Num_bitmap_files-1)*sizeof(DiskBitmapHeader); 
1422         data_offset = bitmap_data_start;
1423
1424         change_filename_ext(tname,filename,"lst");
1425         fp1 = fopen( tname, "wt" );
1426         change_filename_ext(tname,filename,"all");
1427         fp2 = fopen( tname, "wt" );
1428
1429         for (i=1; i < Num_bitmap_files; i++ )   {
1430                 int *size;
1431                 grs_bitmap *bmp;
1432
1433                 {               
1434                         char * p, *p1;
1435                         p = strchr(AllBitmaps[i].name,'#');
1436                         if (p)  {
1437                                 int n;
1438                                 p1 = p; p1++; 
1439                                 n = atoi(p1);
1440                                 *p = 0;
1441                                 if (fp2 && n==0)
1442                                         fprintf( fp2, "%s.abm\n", AllBitmaps[i].name );
1443                                 memcpy( bmh.name, AllBitmaps[i].name, 8 );
1444                                 Assert( n <= 63 );
1445                                 bmh.dflags = DBM_FLAG_ABM + n;
1446                                 *p = '#';
1447                         }else {
1448                                 if (fp2)
1449                                         fprintf( fp2, "%s.bbm\n", AllBitmaps[i].name );
1450                                 memcpy( bmh.name, AllBitmaps[i].name, 8 );
1451                                 bmh.dflags = 0;
1452                         }
1453                 }
1454                 bmp = &GameBitmaps[i];
1455
1456                 Assert( !(bmp->bm_flags&BM_FLAG_PAGED_OUT) );
1457
1458                 if (fp1)
1459                         fprintf( fp1, "BMP: %s, size %d bytes", AllBitmaps[i].name, bmp->bm_rowsize * bmp->bm_h );
1460                 org_offset = ftell(pig_fp);
1461                 bmh.offset = data_offset - bitmap_data_start;
1462                 fseek( pig_fp, data_offset, SEEK_SET );
1463
1464                 if ( bmp->bm_flags & BM_FLAG_RLE )      {
1465                         size = (int *)bmp->bm_data;
1466                         fwrite( bmp->bm_data, sizeof(ubyte), *size, pig_fp );
1467                         data_offset += *size;
1468                         if (fp1)
1469                                 fprintf( fp1, ", and is already compressed to %d bytes.\n", *size );
1470                 } else {
1471                         fwrite( bmp->bm_data, sizeof(ubyte), bmp->bm_rowsize * bmp->bm_h, pig_fp );
1472                         data_offset += bmp->bm_rowsize * bmp->bm_h;
1473                         if (fp1)
1474                                 fprintf( fp1, ".\n" );
1475                 }
1476                 fseek( pig_fp, org_offset, SEEK_SET );
1477                 Assert( GameBitmaps[i].bm_w < 4096 );
1478                 bmh.width = (GameBitmaps[i].bm_w & 0xff);
1479                 bmh.wh_extra = ((GameBitmaps[i].bm_w >> 8) & 0x0f);
1480                 Assert( GameBitmaps[i].bm_h < 4096 );
1481                 bmh.height = GameBitmaps[i].bm_h;
1482                 bmh.wh_extra |= ((GameBitmaps[i].bm_h >> 4) & 0xf0);
1483                 bmh.flags = GameBitmaps[i].bm_flags;
1484                 if (piggy_is_substitutable_bitmap( AllBitmaps[i].name, subst_name ))    {
1485                         bitmap_index other_bitmap;
1486                         other_bitmap = piggy_find_bitmap( subst_name );
1487                         GameBitmapXlat[i] = other_bitmap.index;
1488                         bmh.flags |= BM_FLAG_PAGED_OUT;
1489                         //mprintf(( 0, "Skipping bitmap %d\n", i ));
1490                         //mprintf(( 0, "Marking '%s' as substitutible\n", AllBitmaps[i].name ));
1491                 } else  {
1492                         bmh.flags &= ~BM_FLAG_PAGED_OUT;
1493                 }
1494                 bmh.avg_color=GameBitmaps[i].avg_color;
1495                 fwrite( &bmh, sizeof(DiskBitmapHeader), 1, pig_fp );                    // Mark as a bitmap
1496         }
1497
1498         fclose(pig_fp);
1499
1500         mprintf( (0, " Dumped %d assorted bitmaps.\n", Num_bitmap_files ));
1501         fprintf( fp1, " Dumped %d assorted bitmaps.\n", Num_bitmap_files );
1502
1503         fclose(fp1);
1504         fclose(fp2);
1505
1506 }
1507
1508 static void write_int(int i,FILE *file)
1509 {
1510         if (fwrite( &i, sizeof(i), 1, file) != 1)
1511                 Error( "Error reading int in gamesave.c" );
1512
1513 }
1514
1515 void piggy_dump_all()
1516 {
1517         int i, xlat_offset;
1518         FILE * ham_fp;
1519         int org_offset,data_offset;
1520         DiskSoundHeader sndh;
1521         int sound_data_start;
1522         FILE *fp1,*fp2;
1523
1524         #ifdef NO_DUMP_SOUNDS
1525         Num_sound_files = 0;
1526         Num_sound_files_new = 0;
1527         #endif
1528
1529         if (!Must_write_hamfile && (Num_bitmap_files_new == 0) && (Num_sound_files_new == 0) )
1530                 return;
1531
1532         fp1 = fopen( "ham.lst", "wt" );
1533         fp2 = fopen( "ham.all", "wt" );
1534
1535         if (Must_write_hamfile || Num_bitmap_files_new) {
1536
1537                 mprintf( (0, "Creating %s...",DEFAULT_HAMFILE));
1538         
1539                 ham_fp = fopen( DEFAULT_HAMFILE, "wb" );                       //open HAM file
1540                 Assert( ham_fp!=NULL );
1541         
1542                 write_int(HAMFILE_ID,ham_fp);
1543                 write_int(HAMFILE_VERSION,ham_fp);
1544         
1545                 bm_write_all(ham_fp);
1546                 xlat_offset = ftell(ham_fp);
1547                 fwrite( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
1548                 //Dump bitmaps
1549         
1550                 if (Num_bitmap_files_new)
1551                         piggy_write_pigfile(DEFAULT_PIGFILE);
1552         
1553                 //free up memeory used by new bitmaps
1554                 for (i=Num_bitmap_files-Num_bitmap_files_new;i<Num_bitmap_files;i++)
1555                         d_free(GameBitmaps[i].bm_data);
1556         
1557                 //next thing must be done after pig written
1558                 fseek( ham_fp, xlat_offset, SEEK_SET );
1559                 fwrite( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
1560         
1561                 fclose(ham_fp);
1562                 mprintf( (0, "\n" ));
1563         }
1564         
1565         if (Num_sound_files_new) {
1566
1567                 mprintf( (0, "Creating %s...",DEFAULT_HAMFILE));
1568                 // Now dump sound file
1569                 ham_fp = fopen( DEFAULT_SNDFILE, "wb" );
1570                 Assert( ham_fp!=NULL );
1571         
1572                 write_int(SNDFILE_ID,ham_fp);
1573                 write_int(SNDFILE_VERSION,ham_fp);
1574
1575                 fwrite( &Num_sound_files, sizeof(int), 1, ham_fp );
1576         
1577                 mprintf( (0, "\nDumping sounds..." ));
1578         
1579                 sound_data_start = ftell(ham_fp);
1580                 sound_data_start += Num_sound_files*sizeof(DiskSoundHeader);
1581                 data_offset = sound_data_start;
1582         
1583                 for (i=0; i < Num_sound_files; i++ )    {
1584                         digi_sound *snd;
1585         
1586                         snd = &GameSounds[i];
1587                         strcpy( sndh.name, AllSounds[i].name );
1588                         sndh.length = GameSounds[i].length;
1589                         sndh.offset = data_offset - sound_data_start;
1590         
1591                         org_offset = ftell(ham_fp);
1592                         fseek( ham_fp, data_offset, SEEK_SET );
1593         
1594                         sndh.data_length = GameSounds[i].length;
1595                         fwrite( snd->data, sizeof(ubyte), snd->length, ham_fp );
1596                         data_offset += snd->length;
1597                         fseek( ham_fp, org_offset, SEEK_SET );
1598                         fwrite( &sndh, sizeof(DiskSoundHeader), 1, ham_fp );                    // Mark as a bitmap
1599         
1600                         fprintf( fp1, "SND: %s, size %d bytes\n", AllSounds[i].name, snd->length );
1601                         fprintf( fp2, "%s.raw\n", AllSounds[i].name );
1602                 }
1603
1604                 fclose(ham_fp);
1605                 mprintf( (0, "\n" ));
1606         }
1607
1608         fprintf( fp1, "Total sound size: %d bytes\n", data_offset-sound_data_start);
1609         mprintf( (0, " Dumped %d assorted sounds.\n", Num_sound_files ));
1610         fprintf( fp1, " Dumped %d assorted sounds.\n", Num_sound_files );
1611
1612         fclose(fp1);
1613         fclose(fp2);
1614
1615         // Never allow the game to run after building ham.
1616         exit(0);
1617 }
1618
1619 #endif
1620
1621 void piggy_close()
1622 {
1623         piggy_close_file();
1624
1625         if (BitmapBits)
1626                 d_free(BitmapBits);
1627
1628         if ( SoundBits )
1629                 d_free( SoundBits );
1630
1631         hashtable_free( &AllBitmapsNames );
1632         hashtable_free( &AllDigiSndNames );
1633
1634 }
1635
1636 int piggy_does_bitmap_exist_slow( char * name )
1637 {
1638         int i;
1639
1640         for (i=0; i<Num_bitmap_files; i++ )     {
1641                 if ( !strcmp( AllBitmaps[i].name, name) )
1642                         return 1;
1643         }
1644         return 0;
1645 }
1646
1647
1648 #define NUM_GAUGE_BITMAPS 23
1649 char * gauge_bitmap_names[NUM_GAUGE_BITMAPS] = {
1650         "gauge01", "gauge01b",
1651         "gauge02", "gauge02b",
1652         "gauge06", "gauge06b",
1653         "targ01", "targ01b",
1654         "targ02", "targ02b", 
1655         "targ03", "targ03b",
1656         "targ04", "targ04b",
1657         "targ05", "targ05b",
1658         "targ06", "targ06b",
1659         "gauge18", "gauge18b",
1660         "gauss1", "helix1",
1661         "phoenix1"
1662 };
1663
1664
1665 int piggy_is_gauge_bitmap( char * base_name )
1666 {
1667         int i;
1668         for (i=0; i<NUM_GAUGE_BITMAPS; i++ )    {
1669                 if ( !stricmp( base_name, gauge_bitmap_names[i] ))      
1670                         return 1;
1671         }
1672
1673         return 0;       
1674 }
1675
1676 int piggy_is_substitutable_bitmap( char * name, char * subst_name )
1677 {
1678         int frame;
1679         char * p;
1680         char base_name[ 16 ];
1681         
1682         strcpy( subst_name, name );
1683         p = strchr( subst_name, '#' );
1684         if ( p )        {
1685                 frame = atoi( &p[1] );
1686                 *p = 0;
1687                 strcpy( base_name, subst_name );
1688                 if ( !piggy_is_gauge_bitmap( base_name ))       {
1689                         sprintf( subst_name, "%s#%d", base_name, frame+1 );
1690                         if ( piggy_does_bitmap_exist_slow( subst_name )  )      {
1691                                 if ( frame & 1 ) {
1692                                         sprintf( subst_name, "%s#%d", base_name, frame-1 );
1693                                         return 1;
1694                                 }
1695                         }
1696                 }
1697         }
1698         strcpy( subst_name, name );
1699         return 0;
1700 }
1701
1702
1703
1704 #ifdef WINDOWS
1705 //      New Windows stuff
1706
1707 //      windows bitmap page in
1708 //              Page in a bitmap, if ddraw, then page it into a ddsurface in 
1709 //              'video' memory.  if that fails, page it in normally.
1710
1711 void piggy_bitmap_page_in_w( bitmap_index bitmap, int ddraw )
1712 {
1713 }
1714
1715
1716 //      Essential when switching video modes!
1717
1718 void piggy_bitmap_page_out_all_w()
1719 {
1720 }
1721
1722
1723 #endif
1724
1725