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