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