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