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