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