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