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.
19 static char rcsid[] = "$Id: piggy.c,v 1.13 2002-07-30 11:05:53 btb Exp $";
58 #include <Strings.h> // MacOS Toolbox header
63 //#define NO_DUMP_SOUNDS 1 //if set, dump bitmaps but not sounds
65 #define DEFAULT_PIGFILE_REGISTERED "groupa.pig"
66 #define DEFAULT_PIGFILE_SHAREWARE "d2demo.pig"
70 #define DEFAULT_HAMFILE "d2demo.ham"
71 #define DEFAULT_PIGFILE DEFAULT_PIGFILE_SHAREWARE
72 #define DEFAULT_SNDFILE DEFAULT_HAMFILE //"descent2.s11"
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
79 ubyte *BitmapBits = NULL;
80 ubyte *SoundBits = NULL;
82 typedef struct BitmapFile {
86 typedef struct SoundFile {
90 hashtable AllBitmapsNames;
91 hashtable AllDigiSndNames;
93 int Num_bitmap_files = 0;
94 int Num_sound_files = 0;
96 digi_sound GameSounds[MAX_SOUND_FILES];
97 int SoundOffset[MAX_SOUND_FILES];
98 grs_bitmap GameBitmaps[MAX_BITMAP_FILES];
100 alias alias_list[MAX_ALIASES];
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 ];
109 int piggy_low_memory = 0;
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];
118 #define PIGGY_BUFFER_SIZE (2400*1024)
121 #define PIGGY_SMALL_BUFFER_SIZE (1400*1024) // size of buffer when piggy_low_memory is set
124 #undef PIGGY_BUFFER_SIZE
125 #undef PIGGY_SMALL_BUFFER_SIZE
127 #define PIGGY_BUFFER_SIZE (2000*1024)
128 #define PIGGY_SMALL_BUFFER_SIZE (1100 * 1024)
133 int piggy_page_flushed = 0;
135 #define DBM_FLAG_ABM 64
140 extern short cd_VRefNum;
141 extern void ConcatPStr(StringPtr dst, StringPtr src);
142 extern int ConvertPToCStr(StringPtr inPStr, char* outCStrBuf);
143 extern int ConvertCToPStr(char* inCStr, StringPtr outPStrBuf);
146 int piggy_is_substitutable_bitmap( char * name, char * subst_name );
149 void piggy_write_pigfile(char *filename);
150 static void write_int(int i,FILE *file);
152 void swap_0_255(grs_bitmap *bmp)
156 for (i = 0; i < bmp->bm_h * bmp->bm_w; i++) {
157 if(bmp->bm_data[i] == 0)
158 bmp->bm_data[i] = 255;
159 else if (bmp->bm_data[i] == 255)
165 bitmap_index piggy_register_bitmap( grs_bitmap * bmp, char * name, int in_file )
168 Assert( Num_bitmap_files < MAX_BITMAP_FILES );
170 temp.index = Num_bitmap_files;
174 if ( FindArg("-macdata") )
177 if ( !BigPig ) gr_bitmap_rle_compress( bmp );
178 Num_bitmap_files_new++;
181 strncpy( AllBitmaps[Num_bitmap_files].name, name, 12 );
182 hashtable_insert( &AllBitmapsNames, AllBitmaps[Num_bitmap_files].name, Num_bitmap_files );
183 GameBitmaps[Num_bitmap_files] = *bmp;
185 GameBitmapOffset[Num_bitmap_files] = 0;
186 GameBitmapFlags[Num_bitmap_files] = bmp->bm_flags;
193 int piggy_register_sound( digi_sound * snd, char * name, int in_file )
197 Assert( Num_sound_files < MAX_SOUND_FILES );
199 strncpy( AllSounds[Num_sound_files].name, name, 12 );
200 hashtable_insert( &AllDigiSndNames, AllSounds[Num_sound_files].name, Num_sound_files );
201 GameSounds[Num_sound_files] = *snd;
203 SoundOffset[Num_sound_files] = 0;
209 Num_sound_files_new++;
215 bitmap_index piggy_find_bitmap( char * name )
223 if ((t=strchr(name,'#'))!=NULL)
226 for (i=0;i<Num_aliases;i++)
227 if (stricmp(name,alias_list[i].alias_name)==0) {
228 if (t) { //extra stuff for ABMs
229 static char temp[FILENAME_LEN];
230 _splitpath(alias_list[i].file_name, NULL, NULL, temp, NULL );
236 name=alias_list[i].file_name;
243 i = hashtable_search( &AllBitmapsNames, name );
252 int piggy_find_sound( char * name )
256 i = hashtable_search( &AllDigiSndNames, name );
264 CFILE * Piggy_fp = NULL;
266 #define FILENAME_LEN 13
268 char Current_pigfile[FILENAME_LEN] = "";
270 void piggy_close_file()
275 Current_pigfile[0] = 0;
279 int Pigfile_initialized=0;
281 #define PIGFILE_ID MAKE_SIG('G','I','P','P') //PPIG
282 #define PIGFILE_VERSION 2
284 extern char CDROM_dir[];
286 int request_cd(void);
291 //copies a pigfile from the CD to the current dir
292 //retuns file handle of new pig
293 CFILE *copy_pigfile_from_cd(char *filename) // MACINTOSH VERSION
296 char sourcePathAndFileCStr[255] = "";
297 char destPathAndFileCStr[255] = "";
299 FILE* sourceFile = NULL;
300 FILE* destFile = NULL;
301 const int BUF_SIZE = 4096;
305 Str255 sourcePathAndFilePStr = "\p";
306 Str255 destPathAndFilePStr = "\p";
307 Str255 pigfileNamePStr = "\p";
308 HParamBlockRec theSourcePigHFSParams;
309 HParamBlockRec theDestPigHFSParams;
310 OSErr theErr = noErr;
311 char oldDirCStr[255] = "";
313 getcwd(oldDirCStr, 255);
315 show_boxed_message("Copying bitmap data from CD...");
316 gr_palette_load(gr_palette); //I don't think this line is really needed
319 //First, delete all PIG files currently in the directory
320 if( !FileFindFirst( "*.pig", &find ) )
325 } while( !FileFindNext( &find ) );
331 //Now, copy over new pig
332 songs_stop_redbook(); //so we can read off the cd
334 // make the source path "<cd volume>:Data:filename.pig"
335 //MWA ConvertCToPStr(filename, pigfileNamePStr);
337 //MWA ConcatPStr(sourcePathAndFilePStr, "\pDescent II:Data:"); // volume ID is cd_VRefNum
338 //MWA ConcatPStr(sourcePathAndFilePStr, pigfileNamePStr);
341 strcpy(sourcePathAndFileCStr, "Descent II:Data:");
342 strcat(sourcePathAndFileCStr, filename);
344 // make the destination path "<default directory>:Data:filename.pig"
345 //MWA ConcatPStr(destPathAndFilePStr, "\p:Data:");
346 //MWA ConcatPStr(destPathAndFilePStr, pigfileNamePStr);
347 //MWA ConvertPToCStr(sourcePathAndFilePStr, sourcePathAndFileCStr);
348 //MWA ConvertPToCStr(destPathAndFilePStr, destPathAndFileCStr);
350 strcpy(destPathAndFileCStr, ":Data:");
351 strcat(destPathAndFileCStr, filename);
353 strcpy(sourcePathAndFilePStr, sourcePathAndFileCStr);
354 strcpy(destPathAndFilePStr, destPathAndFileCStr);
355 c2pstr(sourcePathAndFilePStr);
356 c2pstr(destPathAndFilePStr);
359 // Open the source file
360 sourceFile = fopen(sourcePathAndFileCStr,"rb");
364 if (request_cd() == -1)
365 Error("Cannot load file <%s> from CD",filename);
368 } while (!sourceFile);
371 // Get the time stamp from the source file
372 theSourcePigHFSParams.fileParam.ioCompletion = nil;
373 theSourcePigHFSParams.fileParam.ioNamePtr = sourcePathAndFilePStr;
374 theSourcePigHFSParams.fileParam.ioVRefNum = cd_VRefNum;
375 theSourcePigHFSParams.fileParam.ioFDirIndex = 0;
376 theSourcePigHFSParams.fileParam.ioDirID = 0;
378 theErr = PBHGetFInfo(&theSourcePigHFSParams, false);
381 // Error getting file time stamp!! Why? JTS
382 Error("Can't get old file time stamp: <%s>\n", sourcePathAndFileCStr);
385 // Copy the file over
388 // Open the destination file
389 destFile = fopen(destPathAndFileCStr,"wb");
392 Error("Cannot create file: <%s>\n", destPathAndFileCStr);
395 // Copy bytes until the end of the source file
396 while (!feof(sourceFile))
401 bytes_read = fread(buf,1,BUF_SIZE,sourceFile);
402 if (ferror(sourceFile))
403 Error("Cannot read from file <%s>: %s", sourcePathAndFileCStr, strerror(errno));
405 // Assert is bogus Assert(bytes_read == BUF_SIZE || feof(sourceFile));
407 fwrite(buf,1,bytes_read,destFile);
408 if (ferror(destFile))
409 Error("Cannot write to file <%s>: %s",destPathAndFileCStr, strerror(errno));
412 // close the source/dest files
413 if (fclose(sourceFile))
414 Error("Error closing file <%s>: %s", sourcePathAndFileCStr, strerror(errno));
415 if (fclose(destFile))
416 Error("Error closing file <%s>: %s", destPathAndFileCStr, strerror(errno));
418 // Get the current hfs data for the new file
419 theDestPigHFSParams.fileParam.ioCompletion = nil;
420 theDestPigHFSParams.fileParam.ioNamePtr = destPathAndFilePStr;
421 theDestPigHFSParams.fileParam.ioVRefNum = 0;
422 theDestPigHFSParams.fileParam.ioFDirIndex = 0;
423 theDestPigHFSParams.fileParam.ioDirID = 0;
424 theErr = PBHGetFInfo(&theDestPigHFSParams, false);
425 if ((theErr != noErr) || (theDestPigHFSParams.fileParam.ioResult != noErr))
427 // Error getting file time stamp!! Why? JTS
428 Error("Can't get destination pig file information: <%s>\n", destPathAndFileCStr);
431 // Reset this data !!!!! or else the relative pathname won't work, could use just filename instead but, oh well.
432 theDestPigHFSParams.fileParam.ioNamePtr = destPathAndFilePStr;
433 theDestPigHFSParams.fileParam.ioVRefNum = 0;
434 theDestPigHFSParams.fileParam.ioFDirIndex = 0;
435 theDestPigHFSParams.fileParam.ioDirID = 0;
437 // Copy the time stamp from the source file info
438 theDestPigHFSParams.fileParam.ioFlCrDat = theSourcePigHFSParams.fileParam.ioFlCrDat;
439 theDestPigHFSParams.fileParam.ioFlMdDat = theSourcePigHFSParams.fileParam.ioFlMdDat;
440 theDestPigHFSParams.fileParam.ioFlFndrInfo.fdType = 'PGGY';
441 theDestPigHFSParams.fileParam.ioFlFndrInfo.fdCreator = 'DCT2';
443 // Set the dest file's time stamp to the source file's time stamp values
444 theErr = PBHSetFInfo(&theDestPigHFSParams, false);
446 if ((theErr != noErr) || (theDestPigHFSParams.fileParam.ioResult != noErr))
448 Error("Can't set destination pig file time stamp: <%s>\n", destPathAndFileCStr);
451 theErr = PBHGetFInfo(&theDestPigHFSParams, false);
453 return cfopen(destPathAndFileCStr, "rb");
456 #else //PC Version of copy_pigfile_from_cd is below
458 //copies a pigfile from the CD to the current dir
459 //retuns file handle of new pig
460 CFILE *copy_pigfile_from_cd(char *filename)
466 return cfopen(filename, "rb");
467 show_boxed_message("Copying bitmap data from CD...");
468 gr_palette_load(gr_palette); //I don't think this line is really needed
470 //First, delete all PIG files currently in the directory
472 if( !FileFindFirst( "*.pig", &find ) ) {
475 } while( !FileFindNext( &find ) );
479 //Now, copy over new pig
481 songs_stop_redbook(); //so we can read off the cd
483 //new code to unarj file
484 strcpy(name,CDROM_dir);
485 strcat(name,"descent2.sow");
488 // ret = unarj_specific_file(name,filename,filename);
493 if (ret != EXIT_SUCCESS) {
495 //delete file, so we don't leave partial file
499 if (request_cd() == -1)
501 //NOTE LINK TO ABOVE IF
502 Error("Cannot load file <%s> from CD",filename);
505 } while (ret != EXIT_SUCCESS);
507 return cfopen(filename, "rb");
510 #endif // end of ifdef MAC around copy_pigfile_from_cd
512 //initialize a pigfile, reading headers
513 //returns the size of all the bitmap data
514 void piggy_init_pigfile(char *filename)
518 char temp_name_read[16];
519 grs_bitmap temp_bitmap;
520 DiskBitmapHeader bmh;
521 int header_size, N_bitmaps, data_size, data_start;
523 char name[255]; // filename + path for the mac
526 piggy_close_file(); //close old pig if still open
528 #ifdef SHAREWARE //rename pigfile for shareware
529 if (stricmp(filename,DEFAULT_PIGFILE_REGISTERED)==0)
530 filename = DEFAULT_PIGFILE_SHAREWARE;
534 Piggy_fp = cfopen( filename, "rb" );
536 sprintf(name, ":Data:%s", filename);
537 Piggy_fp = cfopen( name, "rb" );
539 #ifdef SHAREWARE // if we are in the shareware version, we must have the pig by now.
540 if (Piggy_fp == NULL)
542 Error("Cannot load required file <%s>",name);
544 #endif // end of if def shareware
550 return; //if editor, ok to not have pig, because we'll build one
552 Piggy_fp = copy_pigfile_from_cd(filename);
556 if (Piggy_fp) { //make sure pig is valid type file & is up-to-date
557 int pig_id,pig_version;
559 pig_id = cfile_read_int(Piggy_fp);
560 pig_version = cfile_read_int(Piggy_fp);
561 if (pig_id != PIGFILE_ID || pig_version != PIGFILE_VERSION) {
562 cfclose(Piggy_fp); //out of date pig
563 Piggy_fp = NULL; //..so pretend it's not here
570 return; //if editor, ok to not have pig, because we'll build one
572 Error("Cannot load required file <%s>",filename);
576 strncpy(Current_pigfile,filename,sizeof(Current_pigfile));
578 N_bitmaps = cfile_read_int(Piggy_fp);
580 header_size = N_bitmaps*DISKBITMAPHEADER_SIZE;
582 data_start = header_size + cftell(Piggy_fp);
584 data_size = cfilelength(Piggy_fp) - data_start;
586 Num_bitmap_files = 1;
588 for (i=0; i<N_bitmaps; i++ ) {
589 DiskBitmapHeader_read(&bmh, Piggy_fp);
590 memcpy( temp_name_read, bmh.name, 8 );
591 temp_name_read[8] = 0;
592 if ( bmh.dflags & DBM_FLAG_ABM )
593 sprintf( temp_name, "%s#%d", temp_name_read, bmh.dflags & 63 );
595 strcpy( temp_name, temp_name_read );
596 memset( &temp_bitmap, 0, sizeof(grs_bitmap) );
597 temp_bitmap.bm_w = temp_bitmap.bm_rowsize = bmh.width + ((short) (bmh.wh_extra&0x0f)<<8);
598 temp_bitmap.bm_h = bmh.height + ((short) (bmh.wh_extra&0xf0)<<4);
599 temp_bitmap.bm_flags = BM_FLAG_PAGED_OUT;
600 temp_bitmap.avg_color = bmh.avg_color;
601 temp_bitmap.bm_data = Piggy_bitmap_cache_data;
603 GameBitmapFlags[i+1] = 0;
604 if ( bmh.flags & BM_FLAG_TRANSPARENT ) GameBitmapFlags[i+1] |= BM_FLAG_TRANSPARENT;
605 if ( bmh.flags & BM_FLAG_SUPER_TRANSPARENT ) GameBitmapFlags[i+1] |= BM_FLAG_SUPER_TRANSPARENT;
606 if ( bmh.flags & BM_FLAG_NO_LIGHTING ) GameBitmapFlags[i+1] |= BM_FLAG_NO_LIGHTING;
607 if ( bmh.flags & BM_FLAG_RLE ) GameBitmapFlags[i+1] |= BM_FLAG_RLE;
608 if ( bmh.flags & BM_FLAG_RLE_BIG ) GameBitmapFlags[i+1] |= BM_FLAG_RLE_BIG;
610 GameBitmapOffset[i+1] = bmh.offset + data_start;
611 Assert( (i+1) == Num_bitmap_files );
612 piggy_register_bitmap( &temp_bitmap, temp_name, 1 );
616 Piggy_bitmap_cache_size = data_size + (data_size/10); //extra mem for new bitmaps
617 Assert( Piggy_bitmap_cache_size > 0 );
619 Piggy_bitmap_cache_size = PIGGY_BUFFER_SIZE;
621 if (piggy_low_memory)
622 Piggy_bitmap_cache_size = PIGGY_SMALL_BUFFER_SIZE;
625 BitmapBits = d_malloc( Piggy_bitmap_cache_size );
626 if ( BitmapBits == NULL )
627 Error( "Not enough memory to load bitmaps\n" );
628 Piggy_bitmap_cache_data = BitmapBits;
629 Piggy_bitmap_cache_next = 0;
631 #if defined(MACINTOSH) && defined(SHAREWARE)
632 // load_exit_models();
635 Pigfile_initialized=1;
638 #define FILENAME_LEN 13
639 #define MAX_BITMAPS_PER_BRUSH 30
641 extern int compute_average_pixel(grs_bitmap *new);
643 //reads in a new pigfile (for new palette)
644 //returns the size of all the bitmap data
645 void piggy_new_pigfile(char *pigname)
649 char temp_name_read[16];
650 grs_bitmap temp_bitmap;
651 DiskBitmapHeader bmh;
652 int header_size, N_bitmaps, data_size, data_start;
653 int must_rewrite_pig = 0;
660 #ifdef SHAREWARE //rename pigfile for shareware
661 if (stricmp(pigname,DEFAULT_PIGFILE_REGISTERED)==0)
662 pigname = DEFAULT_PIGFILE_SHAREWARE;
665 if (strnicmp(Current_pigfile,pigname,sizeof(Current_pigfile))==0)
666 return; //already have correct pig
668 if (!Pigfile_initialized) { //have we ever opened a pigfile?
669 piggy_init_pigfile(pigname); //..no, so do initialization stuff
673 piggy_close_file(); //close old pig if still open
675 Piggy_bitmap_cache_next = 0; //free up cache
677 strncpy(Current_pigfile,pigname,sizeof(Current_pigfile));
680 Piggy_fp = cfopen( pigname, "rb" );
682 sprintf(name, ":Data:%s", pigname);
683 Piggy_fp = cfopen( name, "rb" );
685 #ifdef SHAREWARE // if we are in the shareware version, we must have the pig by now.
686 if (Piggy_fp == NULL)
688 Error("Cannot load required file <%s>",name);
690 #endif // end of if def shareware
695 Piggy_fp = copy_pigfile_from_cd(pigname);
698 if (Piggy_fp) { //make sure pig is valid type file & is up-to-date
699 int pig_id,pig_version;
701 pig_id = cfile_read_int(Piggy_fp);
702 pig_version = cfile_read_int(Piggy_fp);
703 if (pig_id != PIGFILE_ID || pig_version != PIGFILE_VERSION) {
704 cfclose(Piggy_fp); //out of date pig
705 Piggy_fp = NULL; //..so pretend it's not here
710 if (!Piggy_fp) Error ("Piggy_fp not defined in piggy_new_pigfile.");
715 N_bitmaps = cfile_read_int(Piggy_fp);
717 header_size = N_bitmaps*DISKBITMAPHEADER_SIZE;
719 data_start = header_size + cftell(Piggy_fp);
721 data_size = cfilelength(Piggy_fp) - data_start;
723 for (i=1; i<=N_bitmaps; i++ ) {
724 DiskBitmapHeader_read(&bmh, Piggy_fp);
725 memcpy( temp_name_read, bmh.name, 8 );
726 temp_name_read[8] = 0;
728 if ( bmh.dflags & DBM_FLAG_ABM )
729 sprintf( temp_name, "%s#%d", temp_name_read, bmh.dflags & 63 );
731 strcpy( temp_name, temp_name_read );
733 //Make sure name matches
734 if (strcmp(temp_name,AllBitmaps[i].name)) {
735 //Int3(); //this pig is out of date. Delete it
739 strcpy(AllBitmaps[i].name,temp_name);
741 memset( &temp_bitmap, 0, sizeof(grs_bitmap) );
743 temp_bitmap.bm_w = temp_bitmap.bm_rowsize = bmh.width + ((short) (bmh.wh_extra&0x0f)<<8);
744 temp_bitmap.bm_h = bmh.height + ((short) (bmh.wh_extra&0xf0)<<4);
745 temp_bitmap.bm_flags = BM_FLAG_PAGED_OUT;
746 temp_bitmap.avg_color = bmh.avg_color;
747 temp_bitmap.bm_data = Piggy_bitmap_cache_data;
749 GameBitmapFlags[i] = 0;
751 if ( bmh.flags & BM_FLAG_TRANSPARENT ) GameBitmapFlags[i] |= BM_FLAG_TRANSPARENT;
752 if ( bmh.flags & BM_FLAG_SUPER_TRANSPARENT ) GameBitmapFlags[i] |= BM_FLAG_SUPER_TRANSPARENT;
753 if ( bmh.flags & BM_FLAG_NO_LIGHTING ) GameBitmapFlags[i] |= BM_FLAG_NO_LIGHTING;
754 if ( bmh.flags & BM_FLAG_RLE ) GameBitmapFlags[i] |= BM_FLAG_RLE;
755 if ( bmh.flags & BM_FLAG_RLE_BIG ) GameBitmapFlags[i] |= BM_FLAG_RLE_BIG;
757 GameBitmapOffset[i] = bmh.offset + data_start;
759 GameBitmaps[i] = temp_bitmap;
763 N_bitmaps = 0; //no pigfile, so no bitmaps
767 Assert(N_bitmaps == Num_bitmap_files-1);
771 if (must_rewrite_pig || (N_bitmaps < Num_bitmap_files-1)) {
774 //re-read the bitmaps that aren't in this pig
776 for (i=N_bitmaps+1;i<Num_bitmap_files;i++) {
779 p = strchr(AllBitmaps[i].name,'#');
781 if (p) { //this is an ABM
782 char abmname[FILENAME_LEN];
784 grs_bitmap * bm[MAX_BITMAPS_PER_BRUSH];
785 int iff_error; //reference parm to avoid warning message
787 char basename[FILENAME_LEN];
790 strcpy(basename,AllBitmaps[i].name);
791 basename[p-AllBitmaps[i].name] = 0; //cut off "#nn" part
793 sprintf( abmname, "%s.abm", basename );
795 iff_error = iff_read_animbrush(abmname,bm,MAX_BITMAPS_PER_BRUSH,&nframes,newpal);
797 if (iff_error != IFF_NO_ERROR) {
798 mprintf((1,"File %s - IFF error: %s",abmname,iff_errormsg(iff_error)));
799 Error("File %s - IFF error: %s",abmname,iff_errormsg(iff_error));
802 for (fnum=0;fnum<nframes; fnum++) {
806 sprintf( tempname, "%s#%d", basename, fnum );
808 //SuperX = (GameBitmaps[i+fnum].bm_flags&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
809 SuperX = (GameBitmapFlags[i+fnum]&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
810 //above makes assumption that supertransparent color is 254
812 if ( iff_has_transparency )
813 gr_remap_bitmap_good( bm[fnum], newpal, iff_transparent_color, SuperX );
815 gr_remap_bitmap_good( bm[fnum], newpal, -1, SuperX );
817 bm[fnum]->avg_color = compute_average_pixel(bm[fnum]);
820 if ( FindArg("-macdata") )
821 swap_0_255( bm[fnum] );
823 if ( !BigPig ) gr_bitmap_rle_compress( bm[fnum] );
825 if (bm[fnum]->bm_flags & BM_FLAG_RLE)
826 size = *((int *) bm[fnum]->bm_data);
828 size = bm[fnum]->bm_w * bm[fnum]->bm_h;
830 memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next],bm[fnum]->bm_data,size);
831 d_free(bm[fnum]->bm_data);
832 bm[fnum]->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next];
833 Piggy_bitmap_cache_next += size;
835 GameBitmaps[i+fnum] = *bm[fnum];
837 // -- mprintf( (0, "U" ));
841 i += nframes-1; //filled in multiple bitmaps
843 else { //this is a BBM
848 char bbmname[FILENAME_LEN];
851 MALLOC( new, grs_bitmap, 1 );
853 sprintf( bbmname, "%s.bbm", AllBitmaps[i].name );
854 iff_error = iff_read_bitmap(bbmname,new,BM_LINEAR,newpal);
857 if (iff_error != IFF_NO_ERROR) {
858 mprintf((1, "File %s - IFF error: %s",bbmname,iff_errormsg(iff_error)));
859 Error("File %s - IFF error: %s",bbmname,iff_errormsg(iff_error));
862 SuperX = (GameBitmapFlags[i]&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
863 //above makes assumption that supertransparent color is 254
865 if ( iff_has_transparency )
866 gr_remap_bitmap_good( new, newpal, iff_transparent_color, SuperX );
868 gr_remap_bitmap_good( new, newpal, -1, SuperX );
870 new->avg_color = compute_average_pixel(new);
873 if ( FindArg("-macdata") )
876 if ( !BigPig ) gr_bitmap_rle_compress( new );
878 if (new->bm_flags & BM_FLAG_RLE)
879 size = *((int *) new->bm_data);
881 size = new->bm_w * new->bm_h;
883 memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next],new->bm_data,size);
884 d_free(new->bm_data);
885 new->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next];
886 Piggy_bitmap_cache_next += size;
888 GameBitmaps[i] = *new;
892 // -- mprintf( (0, "U" ));
896 //@@Dont' do these things which are done when writing
897 //@@for (i=0; i < Num_bitmap_files; i++ ) {
898 //@@ bitmap_index bi;
900 //@@ PIGGY_PAGE_IN( bi );
903 //@@piggy_close_file();
905 piggy_write_pigfile(pigname);
907 Current_pigfile[0] = 0; //say no pig, to force reload
909 piggy_new_pigfile(pigname); //read in just-generated pig
913 #endif //ifdef EDITOR
917 ubyte bogus_data[64*64];
918 grs_bitmap bogus_bitmap;
919 ubyte bogus_bitmap_initialized=0;
920 digi_sound bogus_sound;
922 extern void bm_read_all(CFILE * fp);
924 #define HAMFILE_ID MAKE_SIG('!','M','A','H') //HAM!
926 #define HAMFILE_VERSION 2
928 #define HAMFILE_VERSION 3
930 //version 1 -> 2: save marker_model_num
931 //version 2 -> 3: removed sound files
933 #define SNDFILE_ID MAKE_SIG('D','N','S','D') //DSND
934 #define SNDFILE_VERSION 1
938 CFILE * ham_fp = NULL;
939 int ham_id,ham_version;
940 int sound_offset = 0;
946 ham_fp = cfopen( DEFAULT_HAMFILE, "rb" );
948 sprintf(name, ":Data:%s", DEFAULT_HAMFILE );
949 ham_fp = cfopen( name, "rb" );
952 if (ham_fp == NULL) {
953 Must_write_hamfile = 1;
957 //make sure ham is valid type file & is up-to-date
958 ham_id = cfile_read_int(ham_fp);
959 ham_version = cfile_read_int(ham_fp);
960 if (ham_id != HAMFILE_ID || ham_version != HAMFILE_VERSION) {
961 Must_write_hamfile = 1;
962 cfclose(ham_fp); //out of date ham
966 if (ham_version < 3) // hamfile contains sound info
967 sound_offset = cfile_read_int(ham_fp);
973 bm_read_all( ham_fp ); // Note connection to above if!!!
974 cfread( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
976 //for (i = 0; i < MAX_BITMAP_FILES; i++) {
977 //GameBitmapXlat[i] = INTEL_SHORT(GameBitmapXlat[i]);
978 //printf("GameBitmapXlat[%d] = %d\n", i, GameBitmapXlat[i]);
983 if (ham_version < 3) {
988 DiskSoundHeader sndh;
989 digi_sound temp_sound;
990 char temp_name_read[16];
993 cfseek(ham_fp, sound_offset, SEEK_SET);
994 N_sounds = cfile_read_int(ham_fp);
996 sound_start = cftell(ham_fp);
998 header_size = N_sounds * DISKSOUNDHEADER_SIZE;
1002 for (i=0; i<N_sounds; i++ ) {
1003 DiskSoundHeader_read(&sndh, ham_fp);
1004 temp_sound.length = sndh.length;
1005 temp_sound.data = (ubyte *)(sndh.offset + header_size + sound_start);
1006 SoundOffset[Num_sound_files] = sndh.offset + header_size + sound_start;
1007 memcpy( temp_name_read, sndh.name, 8 );
1008 temp_name_read[8] = 0;
1009 piggy_register_sound( &temp_sound, temp_name_read, 1 );
1011 if (piggy_is_needed(i))
1012 #endif // note link to if.
1013 sbytes += sndh.length;
1014 //mprintf(( 0, "%d bytes of sound\n", sbytes ));
1017 SoundBits = d_malloc( sbytes + 16 );
1018 if ( SoundBits == NULL )
1019 Error( "Not enough memory to load sounds\n" );
1021 mprintf(( 0, "\nBitmaps: %d KB Sounds: %d KB\n", Piggy_bitmap_cache_size/1024, sbytes/1024 ));
1023 // piggy_read_sounds(ham_fp);
1035 CFILE * snd_fp = NULL;
1036 int snd_id,snd_version;
1041 DiskSoundHeader sndh;
1042 digi_sound temp_sound;
1043 char temp_name_read[16];
1050 snd_fp = cfopen( DEFAULT_SNDFILE, "rb" );
1052 sprintf( name, ":Data:%s", DEFAULT_SNDFILE );
1053 snd_fp = cfopen( name, "rb");
1059 //make sure soundfile is valid type file & is up-to-date
1060 snd_id = cfile_read_int(snd_fp);
1061 snd_version = cfile_read_int(snd_fp);
1062 if (snd_id != SNDFILE_ID || snd_version != SNDFILE_VERSION) {
1063 cfclose(snd_fp); //out of date sound file
1067 N_sounds = cfile_read_int(snd_fp);
1069 sound_start = cftell(snd_fp);
1070 size = cfilelength(snd_fp) - sound_start;
1072 mprintf( (0, "\nReading data (%d KB) ", size/1024 ));
1074 header_size = N_sounds*sizeof(DiskSoundHeader);
1078 for (i=0; i<N_sounds; i++ ) {
1079 DiskSoundHeader_read(&sndh, 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 );
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 ));
1094 SoundBits = d_malloc( sbytes + 16 );
1095 if ( SoundBits == NULL )
1096 Error( "Not enough memory to load sounds\n" );
1098 mprintf(( 0, "\nBitmaps: %d KB Sounds: %d KB\n", Piggy_bitmap_cache_size/1024, sbytes/1024 ));
1100 // piggy_read_sounds(snd_fp);
1107 int piggy_init(void)
1109 int ham_ok=0,snd_ok=0;
1112 hashtable_init( &AllBitmapsNames, MAX_BITMAP_FILES );
1113 hashtable_init( &AllDigiSndNames, MAX_SOUND_FILES );
1115 for (i=0; i<MAX_SOUND_FILES; i++ ) {
1116 GameSounds[i].length = 0;
1117 GameSounds[i].data = NULL;
1121 for (i=0; i<MAX_BITMAP_FILES; i++ )
1122 GameBitmapXlat[i] = i;
1124 if ( !bogus_bitmap_initialized ) {
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;
1139 piggy_register_bitmap( &bogus_bitmap, "bogus", 1 );
1140 bogus_sound.length = 64*64;
1141 bogus_sound.data = bogus_data;
1142 GameBitmapOffset[0] = 0;
1145 if ( FindArg( "-bigpig" ))
1148 if ( FindArg( "-lowmem" ))
1149 piggy_low_memory = 1;
1151 if ( FindArg( "-nolowmem" ))
1152 piggy_low_memory = 0;
1154 if (piggy_low_memory)
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));
1164 piggy_init_pigfile(DEFAULT_PIGFILE);
1168 ham_ok = read_hamfile();
1169 snd_ok = read_sndfile();
1171 snd_ok = ham_ok = read_hamfile();
1174 atexit(piggy_close);
1176 mprintf ((0,"HamOk=%d SndOk=%d\n",ham_ok,snd_ok));
1177 return (ham_ok && snd_ok); //read ok
1180 int piggy_is_needed(int soundnum)
1184 if ( !digi_lomem ) return 1;
1186 for (i=0; i<MAX_SOUNDS; i++ ) {
1187 if ( (AltSounds[i] < 255) && (Sounds[AltSounds[i]] == soundnum) )
1194 void piggy_read_sounds(void)
1207 fp = cfopen( DEFAULT_SNDFILE, "rb" );
1209 sprintf( name, ":Data:%s", DEFAULT_SNDFILE );
1210 fp = cfopen( name, "rb");
1216 for (i=0; i<Num_sound_files; i++ ) {
1217 digi_sound *snd = &GameSounds[i];
1219 if ( SoundOffset[i] > 0 ) {
1220 if ( piggy_is_needed(i) ) {
1221 cfseek( fp, SoundOffset[i], SEEK_SET );
1223 // Read in the sound data!!!
1226 sbytes += snd->length;
1227 cfread( snd->data, snd->length, 1, fp );
1230 snd->data = (ubyte *) -1;
1236 mprintf(( 0, "\nActual Sound usage: %d KB\n", sbytes/1024 ));
1241 extern int descent_critical_error;
1242 extern unsigned descent_critical_deverror;
1243 extern unsigned descent_critical_errcode;
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" };
1249 void piggy_critical_error()
1251 grs_canvas * save_canv;
1252 grs_font * save_font;
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' );
1260 gr_set_current_canvas(save_canv);
1261 grd_curcanv->cv_font = save_font;
1264 void piggy_bitmap_page_in( bitmap_index bitmap )
1273 Assert( i < MAX_BITMAP_FILES );
1274 Assert( i < Num_bitmap_files );
1275 Assert( Piggy_bitmap_cache_size > 0 );
1277 if ( i < 1 ) return;
1278 if ( i >= MAX_BITMAP_FILES ) return;
1279 if ( i >= Num_bitmap_files ) return;
1281 if ( GameBitmapOffset[i] == 0 ) return; // A read-from-disk bitmap!!!
1283 if ( piggy_low_memory ) {
1285 i = GameBitmapXlat[i]; // Xlat for low-memory settings!
1288 bmp = &GameBitmaps[i];
1290 if ( bmp->bm_flags & BM_FLAG_PAGED_OUT ) {
1294 descent_critical_error = 0;
1295 cfseek( Piggy_fp, GameBitmapOffset[i], SEEK_SET );
1296 if ( descent_critical_error ) {
1297 piggy_critical_error();
1301 bmp->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next];
1302 bmp->bm_flags = GameBitmapFlags[i];
1304 if ( bmp->bm_flags & BM_FLAG_RLE ) {
1306 descent_critical_error = 0;
1307 zsize = cfile_read_int(Piggy_fp);
1308 if ( descent_critical_error ) {
1309 piggy_critical_error();
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 ) {
1317 piggy_bitmap_page_out_all();
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();
1328 Piggy_bitmap_cache_next += zsize-4;
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();
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();
1342 Piggy_bitmap_cache_next+=bmp->bm_h*bmp->bm_w;
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" );
1355 if ( piggy_low_memory ) {
1357 GameBitmaps[org_i] = GameBitmaps[i];
1360 //@@Removed from John's code:
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" );
1370 void piggy_bitmap_page_out_all()
1374 Piggy_bitmap_cache_next = 0;
1376 piggy_page_flushed++;
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;
1388 mprintf(( 0, "Flushing piggy bitmap cache\n" ));
1391 void piggy_load_level_data()
1393 piggy_bitmap_page_out_all();
1399 void change_filename_ext( char *dest, char *src, char *ext );
1401 void piggy_write_pigfile(char *filename)
1404 int bitmap_data_start,data_offset;
1405 DiskBitmapHeader bmh;
1407 char subst_name[32];
1410 char tname[FILENAME_LEN];
1412 // -- mprintf( (0, "Paging in all piggy bitmaps..." ));
1413 for (i=0; i < Num_bitmap_files; i++ ) {
1416 PIGGY_PAGE_IN( bi );
1418 // -- mprintf( (0, "\n" ));
1422 // -- mprintf( (0, "Creating %s...",filename ));
1424 pig_fp = fopen( filename, "wb" ); //open PIG file
1425 Assert( pig_fp!=NULL );
1427 write_int(PIGFILE_ID,pig_fp);
1428 write_int(PIGFILE_VERSION,pig_fp);
1431 fwrite( &Num_bitmap_files, sizeof(int), 1, pig_fp );
1434 bitmap_data_start = ftell(pig_fp);
1435 bitmap_data_start += (Num_bitmap_files-1)*DISKBITMAPHEADER_SIZE;
1436 data_offset = bitmap_data_start;
1438 change_filename_ext(tname,filename,"lst");
1439 fp1 = fopen( tname, "wt" );
1440 change_filename_ext(tname,filename,"all");
1441 fp2 = fopen( tname, "wt" );
1443 for (i=1; i < Num_bitmap_files; i++ ) {
1449 p = strchr(AllBitmaps[i].name,'#');
1456 fprintf( fp2, "%s.abm\n", AllBitmaps[i].name );
1457 memcpy( bmh.name, AllBitmaps[i].name, 8 );
1459 bmh.dflags = DBM_FLAG_ABM + n;
1463 fprintf( fp2, "%s.bbm\n", AllBitmaps[i].name );
1464 memcpy( bmh.name, AllBitmaps[i].name, 8 );
1468 bmp = &GameBitmaps[i];
1470 Assert( !(bmp->bm_flags&BM_FLAG_PAGED_OUT) );
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 );
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;
1483 fprintf( fp1, ", and is already compressed to %d bytes.\n", *size );
1485 fwrite( bmp->bm_data, sizeof(ubyte), bmp->bm_rowsize * bmp->bm_h, pig_fp );
1486 data_offset += bmp->bm_rowsize * bmp->bm_h;
1488 fprintf( fp1, ".\n" );
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 ));
1506 bmh.flags &= ~BM_FLAG_PAGED_OUT;
1508 bmh.avg_color=GameBitmaps[i].avg_color;
1509 fwrite( &bmh, DISKBITMAPHEADER_SIZE, 1, pig_fp ); // Mark as a bitmap
1514 mprintf( (0, " Dumped %d assorted bitmaps.\n", Num_bitmap_files ));
1515 fprintf( fp1, " Dumped %d assorted bitmaps.\n", Num_bitmap_files );
1522 static void write_int(int i,FILE *file)
1524 if (fwrite( &i, sizeof(i), 1, file) != 1)
1525 Error( "Error reading int in gamesave.c" );
1529 void piggy_dump_all()
1533 int org_offset,data_offset=0;
1534 DiskSoundHeader sndh;
1535 int sound_data_start=0;
1538 #ifdef NO_DUMP_SOUNDS
1539 Num_sound_files = 0;
1540 Num_sound_files_new = 0;
1543 if (!Must_write_hamfile && (Num_bitmap_files_new == 0) && (Num_sound_files_new == 0) )
1546 fp1 = fopen( "ham.lst", "wt" );
1547 fp2 = fopen( "ham.all", "wt" );
1549 if (Must_write_hamfile || Num_bitmap_files_new) {
1551 mprintf( (0, "Creating %s...",DEFAULT_HAMFILE));
1553 ham_fp = fopen( DEFAULT_HAMFILE, "wb" ); //open HAM file
1554 Assert( ham_fp!=NULL );
1556 write_int(HAMFILE_ID,ham_fp);
1557 write_int(HAMFILE_VERSION,ham_fp);
1559 bm_write_all(ham_fp);
1560 xlat_offset = ftell(ham_fp);
1561 fwrite( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
1564 if (Num_bitmap_files_new)
1565 piggy_write_pigfile(DEFAULT_PIGFILE);
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);
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 );
1576 mprintf( (0, "\n" ));
1579 if (Num_sound_files_new) {
1581 mprintf( (0, "Creating %s...",DEFAULT_HAMFILE));
1582 // Now dump sound file
1583 ham_fp = fopen( DEFAULT_SNDFILE, "wb" );
1584 Assert( ham_fp!=NULL );
1586 write_int(SNDFILE_ID,ham_fp);
1587 write_int(SNDFILE_VERSION,ham_fp);
1589 fwrite( &Num_sound_files, sizeof(int), 1, ham_fp );
1591 mprintf( (0, "\nDumping sounds..." ));
1593 sound_data_start = ftell(ham_fp);
1594 sound_data_start += Num_sound_files*sizeof(DiskSoundHeader);
1595 data_offset = sound_data_start;
1597 for (i=0; i < Num_sound_files; i++ ) {
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;
1605 org_offset = ftell(ham_fp);
1606 fseek( ham_fp, data_offset, SEEK_SET );
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
1614 fprintf( fp1, "SND: %s, size %d bytes\n", AllSounds[i].name, snd->length );
1615 fprintf( fp2, "%s.raw\n", AllSounds[i].name );
1619 mprintf( (0, "\n" ));
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 );
1629 // Never allow the game to run after building ham.
1643 d_free( SoundBits );
1645 hashtable_free( &AllBitmapsNames );
1646 hashtable_free( &AllDigiSndNames );
1650 int piggy_does_bitmap_exist_slow( char * name )
1654 for (i=0; i<Num_bitmap_files; i++ ) {
1655 if ( !strcmp( AllBitmaps[i].name, name) )
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",
1679 int piggy_is_gauge_bitmap( char * base_name )
1682 for (i=0; i<NUM_GAUGE_BITMAPS; i++ ) {
1683 if ( !stricmp( base_name, gauge_bitmap_names[i] ))
1690 int piggy_is_substitutable_bitmap( char * name, char * subst_name )
1694 char base_name[ 16 ];
1696 strcpy( subst_name, name );
1697 p = strchr( subst_name, '#' );
1699 frame = atoi( &p[1] );
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 ) ) {
1706 sprintf( subst_name, "%s#%d", base_name, frame-1 );
1712 strcpy( subst_name, name );
1719 // New Windows stuff
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.
1725 void piggy_bitmap_page_in_w( bitmap_index bitmap, int ddraw )
1730 // Essential when switching video modes!
1732 void piggy_bitmap_page_out_all_w()
1739 * reads a bitmap_index structure from a CFILE
1741 void bitmap_index_read(bitmap_index *bi, CFILE *fp)
1743 bi->index = cfile_read_short(fp);
1747 * reads a DiskBitmapHeader structure from a CFILE
1749 void DiskBitmapHeader_read(DiskBitmapHeader *dbh, CFILE *fp)
1751 cfread(dbh->name, 8, 1, fp);
1752 dbh->dflags = cfile_read_byte(fp);
1753 dbh->width = cfile_read_byte(fp);
1754 dbh->height = cfile_read_byte(fp);
1755 dbh->wh_extra = cfile_read_byte(fp);
1756 dbh->flags = cfile_read_byte(fp);
1757 dbh->avg_color = cfile_read_byte(fp);
1758 dbh->offset = cfile_read_int(fp);
1762 * reads a DiskSoundHeader structure from a CFILE
1764 void DiskSoundHeader_read(DiskSoundHeader *dsh, CFILE *fp)
1766 cfread(dsh->name, 8, 1, fp);
1767 dsh->length = cfile_read_int(fp);
1768 dsh->data_length = cfile_read_int(fp);
1769 dsh->offset = cfile_read_int(fp);