/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #ifdef HAVE_CONFIG_H #include #endif #ifdef RCS static char rcsid[] = "$Id: piggy.c,v 1.7 2001-11-14 09:34:32 bradleyb Exp $"; #endif #include #include #include "pstypes.h" #include "strutil.h" #include "inferno.h" #include "gr.h" #include "u_mem.h" #include "iff.h" #include "mono.h" #include "error.h" #include "sounds.h" #include "songs.h" #include "bm.h" #include "bmread.h" #include "hash.h" #include "args.h" #include "palette.h" #include "gamefont.h" #include "rle.h" #include "screens.h" #include "piggy.h" #include "texmerge.h" #include "paging.h" #include "game.h" #include "text.h" #include "cfile.h" #include "newmenu.h" #include "byteswap.h" #include "findfile.h" #include "makesig.h" #ifndef MACINTOSH // #include "unarj.h" #else #include // MacOS Toolbox header #include #include #endif //#define NO_DUMP_SOUNDS 1 //if set, dump bitmaps but not sounds #define DEFAULT_PIGFILE_REGISTERED "groupa.pig" #define DEFAULT_PIGFILE_SHAREWARE "d2demo.pig" #ifdef SHAREWARE #define DEFAULT_HAMFILE "d2demo.ham" #define DEFAULT_PIGFILE DEFAULT_PIGFILE_SHAREWARE #define DEFAULT_SNDFILE "descent2.s11" #else #define DEFAULT_HAMFILE "descent2.ham" #define DEFAULT_PIGFILE DEFAULT_PIGFILE_REGISTERED #define DEFAULT_SNDFILE ((digi_sample_rate==SAMPLE_RATE_22K)?"descent2.s22":"descent2.s11") #endif // end of ifdef SHAREWARE ubyte *BitmapBits = NULL; ubyte *SoundBits = NULL; typedef struct BitmapFile { char name[15]; } BitmapFile; typedef struct SoundFile { char name[15]; } SoundFile; hashtable AllBitmapsNames; hashtable AllDigiSndNames; int Num_bitmap_files = 0; int Num_sound_files = 0; digi_sound GameSounds[MAX_SOUND_FILES]; int SoundOffset[MAX_SOUND_FILES]; grs_bitmap GameBitmaps[MAX_BITMAP_FILES]; alias alias_list[MAX_ALIASES]; int Num_aliases=0; int Must_write_hamfile = 0; int Num_bitmap_files_new = 0; int Num_sound_files_new = 0; BitmapFile AllBitmaps[ MAX_BITMAP_FILES ]; static SoundFile AllSounds[ MAX_SOUND_FILES ]; int piggy_low_memory = 0; int Piggy_bitmap_cache_size = 0; int Piggy_bitmap_cache_next = 0; ubyte * Piggy_bitmap_cache_data = NULL; static int GameBitmapOffset[MAX_BITMAP_FILES]; static ubyte GameBitmapFlags[MAX_BITMAP_FILES]; ushort GameBitmapXlat[MAX_BITMAP_FILES]; #define PIGGY_BUFFER_SIZE (2400*1024) #ifdef MACINTOSH #define PIGGY_SMALL_BUFFER_SIZE (1400*1024) // size of buffer when piggy_low_memory is set #ifdef SHAREWARE #undef PIGGY_BUFFER_SIZE #undef PIGGY_SMALL_BUFFER_SIZE #define PIGGY_BUFFER_SIZE (2000*1024) #define PIGGY_SMALL_BUFFER_SIZE (1100 * 1024) #endif // SHAREWARE #endif int piggy_page_flushed = 0; #define DBM_FLAG_ABM 64 typedef struct DiskBitmapHeader { char name[8]; ubyte dflags; //bits 0-5 anim frame num, bit 6 abm flag ubyte width; //low 8 bits here, 4 more bits in wh_extra ubyte height; //low 8 bits here, 4 more bits in wh_extra ubyte wh_extra; //bits 0-3 width, bits 4-7 height ubyte flags; ubyte avg_color; int offset; } __pack__ DiskBitmapHeader; typedef struct DiskSoundHeader { char name[8]; int length; int data_length; int offset; } __pack__ DiskSoundHeader; ubyte BigPig = 0; #ifdef MACINTOSH extern short cd_VRefNum; extern void ConcatPStr(StringPtr dst, StringPtr src); extern int ConvertPToCStr(StringPtr inPStr, char* outCStrBuf); extern int ConvertCToPStr(char* inCStr, StringPtr outPStrBuf); #endif int piggy_is_substitutable_bitmap( char * name, char * subst_name ); #ifdef EDITOR void piggy_write_pigfile(char *filename); static void write_int(int i,FILE *file); void swap_0_255(grs_bitmap *bmp) { int i; for (i = 0; i < bmp->bm_h * bmp->bm_w; i++) { if(bmp->bm_data[i] == 0) bmp->bm_data[i] = 255; else if (bmp->bm_data[i] == 255) bmp->bm_data[i] = 0; } } #endif bitmap_index piggy_register_bitmap( grs_bitmap * bmp, char * name, int in_file ) { bitmap_index temp; Assert( Num_bitmap_files < MAX_BITMAP_FILES ); temp.index = Num_bitmap_files; if (!in_file) { #ifdef EDITOR if ( FindArg("-macdata") ) swap_0_255( bmp ); #endif if ( !BigPig ) gr_bitmap_rle_compress( bmp ); Num_bitmap_files_new++; } strncpy( AllBitmaps[Num_bitmap_files].name, name, 12 ); hashtable_insert( &AllBitmapsNames, AllBitmaps[Num_bitmap_files].name, Num_bitmap_files ); GameBitmaps[Num_bitmap_files] = *bmp; if ( !in_file ) { GameBitmapOffset[Num_bitmap_files] = 0; GameBitmapFlags[Num_bitmap_files] = bmp->bm_flags; } Num_bitmap_files++; return temp; } int piggy_register_sound( digi_sound * snd, char * name, int in_file ) { int i; Assert( Num_sound_files < MAX_SOUND_FILES ); strncpy( AllSounds[Num_sound_files].name, name, 12 ); hashtable_insert( &AllDigiSndNames, AllSounds[Num_sound_files].name, Num_sound_files ); GameSounds[Num_sound_files] = *snd; if ( !in_file ) { SoundOffset[Num_sound_files] = 0; } i = Num_sound_files; if (!in_file) Num_sound_files_new++; Num_sound_files++; return i; } bitmap_index piggy_find_bitmap( char * name ) { bitmap_index bmp; int i; char *t; bmp.index = 0; if ((t=strchr(name,'#'))!=NULL) *t=0; for (i=0;i:Data:filename.pig" //MWA ConvertCToPStr(filename, pigfileNamePStr); //MWA ConcatPStr(sourcePathAndFilePStr, "\pDescent II:Data:"); // volume ID is cd_VRefNum //MWA ConcatPStr(sourcePathAndFilePStr, pigfileNamePStr); strupr(filename); strcpy(sourcePathAndFileCStr, "Descent II:Data:"); strcat(sourcePathAndFileCStr, filename); // make the destination path ":Data:filename.pig" //MWA ConcatPStr(destPathAndFilePStr, "\p:Data:"); //MWA ConcatPStr(destPathAndFilePStr, pigfileNamePStr); //MWA ConvertPToCStr(sourcePathAndFilePStr, sourcePathAndFileCStr); //MWA ConvertPToCStr(destPathAndFilePStr, destPathAndFileCStr); strcpy(destPathAndFileCStr, ":Data:"); strcat(destPathAndFileCStr, filename); strcpy(sourcePathAndFilePStr, sourcePathAndFileCStr); strcpy(destPathAndFilePStr, destPathAndFileCStr); c2pstr(sourcePathAndFilePStr); c2pstr(destPathAndFilePStr); do { // Open the source file sourceFile = fopen(sourcePathAndFileCStr,"rb"); if (!sourceFile) { if (request_cd() == -1) Error("Cannot load file <%s> from CD",filename); } } while (!sourceFile); // Get the time stamp from the source file theSourcePigHFSParams.fileParam.ioCompletion = nil; theSourcePigHFSParams.fileParam.ioNamePtr = sourcePathAndFilePStr; theSourcePigHFSParams.fileParam.ioVRefNum = cd_VRefNum; theSourcePigHFSParams.fileParam.ioFDirIndex = 0; theSourcePigHFSParams.fileParam.ioDirID = 0; theErr = PBHGetFInfo(&theSourcePigHFSParams, false); if (theErr != noErr) { // Error getting file time stamp!! Why? JTS Error("Can't get old file time stamp: <%s>\n", sourcePathAndFileCStr); } // Copy the file over // C Stuff...... // Open the destination file destFile = fopen(destPathAndFileCStr,"wb"); if (!destFile) { Error("Cannot create file: <%s>\n", destPathAndFileCStr); } // Copy bytes until the end of the source file while (!feof(sourceFile)) { int bytes_read; int x; bytes_read = fread(buf,1,BUF_SIZE,sourceFile); if (ferror(sourceFile)) Error("Cannot read from file <%s>: %s", sourcePathAndFileCStr, strerror(errno)); // Assert is bogus Assert(bytes_read == BUF_SIZE || feof(sourceFile)); fwrite(buf,1,bytes_read,destFile); if (ferror(destFile)) Error("Cannot write to file <%s>: %s",destPathAndFileCStr, strerror(errno)); } // close the source/dest files if (fclose(sourceFile)) Error("Error closing file <%s>: %s", sourcePathAndFileCStr, strerror(errno)); if (fclose(destFile)) Error("Error closing file <%s>: %s", destPathAndFileCStr, strerror(errno)); // Get the current hfs data for the new file theDestPigHFSParams.fileParam.ioCompletion = nil; theDestPigHFSParams.fileParam.ioNamePtr = destPathAndFilePStr; theDestPigHFSParams.fileParam.ioVRefNum = 0; theDestPigHFSParams.fileParam.ioFDirIndex = 0; theDestPigHFSParams.fileParam.ioDirID = 0; theErr = PBHGetFInfo(&theDestPigHFSParams, false); if ((theErr != noErr) || (theDestPigHFSParams.fileParam.ioResult != noErr)) { // Error getting file time stamp!! Why? JTS Error("Can't get destination pig file information: <%s>\n", destPathAndFileCStr); } // Reset this data !!!!! or else the relative pathname won't work, could use just filename instead but, oh well. theDestPigHFSParams.fileParam.ioNamePtr = destPathAndFilePStr; theDestPigHFSParams.fileParam.ioVRefNum = 0; theDestPigHFSParams.fileParam.ioFDirIndex = 0; theDestPigHFSParams.fileParam.ioDirID = 0; // Copy the time stamp from the source file info theDestPigHFSParams.fileParam.ioFlCrDat = theSourcePigHFSParams.fileParam.ioFlCrDat; theDestPigHFSParams.fileParam.ioFlMdDat = theSourcePigHFSParams.fileParam.ioFlMdDat; theDestPigHFSParams.fileParam.ioFlFndrInfo.fdType = 'PGGY'; theDestPigHFSParams.fileParam.ioFlFndrInfo.fdCreator = 'DCT2'; // Set the dest file's time stamp to the source file's time stamp values theErr = PBHSetFInfo(&theDestPigHFSParams, false); if ((theErr != noErr) || (theDestPigHFSParams.fileParam.ioResult != noErr)) { Error("Can't set destination pig file time stamp: <%s>\n", destPathAndFileCStr); } theErr = PBHGetFInfo(&theDestPigHFSParams, false); return cfopen(destPathAndFileCStr, "rb"); } #else //PC Version of copy_pigfile_from_cd is below //copies a pigfile from the CD to the current dir //retuns file handle of new pig CFILE *copy_pigfile_from_cd(char *filename) { char name[80]; FILEFINDSTRUCT find; int ret; return cfopen(filename, "rb"); show_boxed_message("Copying bitmap data from CD..."); gr_palette_load(gr_palette); //I don't think this line is really needed //First, delete all PIG files currently in the directory if( !FileFindFirst( "*.pig", &find ) ) { do { remove(find.name); } while( !FileFindNext( &find ) ); FileFindClose(); } //Now, copy over new pig songs_stop_redbook(); //so we can read off the cd //new code to unarj file strcpy(name,CDROM_dir); strcat(name,"descent2.sow"); do { // ret = unarj_specific_file(name,filename,filename); // DPH:FIXME ret = !EXIT_SUCCESS; if (ret != EXIT_SUCCESS) { //delete file, so we don't leave partial file remove(filename); #ifndef MACINTOSH if (request_cd() == -1) #endif //NOTE LINK TO ABOVE IF Error("Cannot load file <%s> from CD",filename); } } while (ret != EXIT_SUCCESS); return cfopen(filename, "rb"); } #endif // end of ifdef MAC around copy_pigfile_from_cd //initialize a pigfile, reading headers //returns the size of all the bitmap data void piggy_init_pigfile(char *filename) { int i; char temp_name[16]; char temp_name_read[16]; grs_bitmap temp_bitmap; DiskBitmapHeader bmh; int header_size, N_bitmaps, data_size, data_start; #ifdef MACINTOSH char name[255]; // filename + path for the mac #endif piggy_close_file(); //close old pig if still open #ifdef SHAREWARE //rename pigfile for shareware if (stricmp(filename,DEFAULT_PIGFILE_REGISTERED)==0) filename = DEFAULT_PIGFILE_SHAREWARE; #endif #ifndef MACINTOSH Piggy_fp = cfopen( filename, "rb" ); #else sprintf(name, ":Data:%s", filename); Piggy_fp = cfopen( name, "rb" ); #ifdef SHAREWARE // if we are in the shareware version, we must have the pig by now. if (Piggy_fp == NULL) { Error("Cannot load required file <%s>",name); } #endif // end of if def shareware #endif if (!Piggy_fp) { #ifdef EDITOR return; //if editor, ok to not have pig, because we'll build one #else Piggy_fp = copy_pigfile_from_cd(filename); #endif } if (Piggy_fp) { //make sure pig is valid type file & is up-to-date int pig_id,pig_version; pig_id = cfile_read_int(Piggy_fp); pig_version = cfile_read_int(Piggy_fp); if (pig_id != PIGFILE_ID || pig_version != PIGFILE_VERSION) { cfclose(Piggy_fp); //out of date pig Piggy_fp = NULL; //..so pretend it's not here } } if (!Piggy_fp) { #ifdef EDITOR return; //if editor, ok to not have pig, because we'll build one #else Error("Cannot load required file <%s>",filename); #endif } strncpy(Current_pigfile,filename,sizeof(Current_pigfile)); N_bitmaps = cfile_read_int(Piggy_fp); header_size = N_bitmaps*sizeof(DiskBitmapHeader); data_start = header_size + cftell(Piggy_fp); data_size = cfilelength(Piggy_fp) - data_start; Num_bitmap_files = 1; for (i=0; i 0 ); #else Piggy_bitmap_cache_size = PIGGY_BUFFER_SIZE; #ifdef MACINTOSH if (piggy_low_memory) Piggy_bitmap_cache_size = PIGGY_SMALL_BUFFER_SIZE; #endif #endif BitmapBits = d_malloc( Piggy_bitmap_cache_size ); if ( BitmapBits == NULL ) Error( "Not enough memory to load bitmaps\n" ); Piggy_bitmap_cache_data = BitmapBits; Piggy_bitmap_cache_next = 0; #if defined(MACINTOSH) && defined(SHAREWARE) // load_exit_models(); #endif Pigfile_initialized=1; } #define FILENAME_LEN 13 #define MAX_BITMAPS_PER_BRUSH 30 extern int compute_average_pixel(grs_bitmap *new); //reads in a new pigfile (for new palette) //returns the size of all the bitmap data void piggy_new_pigfile(char *pigname) { int i; char temp_name[16]; char temp_name_read[16]; grs_bitmap temp_bitmap; DiskBitmapHeader bmh; int header_size, N_bitmaps, data_size, data_start; int must_rewrite_pig = 0; #ifdef MACINTOSH char name[255]; #endif strlwr(pigname); #ifdef SHAREWARE //rename pigfile for shareware if (stricmp(pigname,DEFAULT_PIGFILE_REGISTERED)==0) pigname = DEFAULT_PIGFILE_SHAREWARE; #endif if (strnicmp(Current_pigfile,pigname,sizeof(Current_pigfile))==0) return; //already have correct pig if (!Pigfile_initialized) { //have we ever opened a pigfile? piggy_init_pigfile(pigname); //..no, so do initialization stuff return; } else piggy_close_file(); //close old pig if still open Piggy_bitmap_cache_next = 0; //free up cache strncpy(Current_pigfile,pigname,sizeof(Current_pigfile)); #ifndef MACINTOSH Piggy_fp = cfopen( pigname, "rb" ); #else sprintf(name, ":Data:%s", pigname); Piggy_fp = cfopen( name, "rb" ); #ifdef SHAREWARE // if we are in the shareware version, we must have the pig by now. if (Piggy_fp == NULL) { Error("Cannot load required file <%s>",name); } #endif // end of if def shareware #endif #ifndef EDITOR if (!Piggy_fp) Piggy_fp = copy_pigfile_from_cd(pigname); #endif if (Piggy_fp) { //make sure pig is valid type file & is up-to-date int pig_id,pig_version; pig_id = cfile_read_int(Piggy_fp); pig_version = cfile_read_int(Piggy_fp); if (pig_id != PIGFILE_ID || pig_version != PIGFILE_VERSION) { cfclose(Piggy_fp); //out of date pig Piggy_fp = NULL; //..so pretend it's not here } } #ifndef EDITOR if (!Piggy_fp) Error ("Piggy_fp not defined in piggy_new_pigfile."); #endif if (Piggy_fp) { N_bitmaps = cfile_read_int(Piggy_fp); header_size = N_bitmaps*sizeof(DiskBitmapHeader); data_start = header_size + cftell(Piggy_fp); data_size = cfilelength(Piggy_fp) - data_start; for (i=1; i<=N_bitmaps; i++ ) { #ifndef MACINTOSH cfread( &bmh, sizeof(DiskBitmapHeader), 1, Piggy_fp ); #else cfread(bmh.name, 8, 1, Piggy_fp); bmh.dflags = cfile_read_byte(Piggy_fp); bmh.width = cfile_read_byte(Piggy_fp); bmh.height = cfile_read_byte(Piggy_fp); bmh.wh_extra = cfile_read_byte(Piggy_fp); bmh.flags = cfile_read_byte(Piggy_fp); bmh.avg_color = cfile_read_byte(Piggy_fp); bmh.offset = cfile_read_int(Piggy_fp); #endif memcpy( temp_name_read, bmh.name, 8 ); temp_name_read[8] = 0; if ( bmh.dflags & DBM_FLAG_ABM ) sprintf( temp_name, "%s#%d", temp_name_read, bmh.dflags & 63 ); else strcpy( temp_name, temp_name_read ); //Make sure name matches if (strcmp(temp_name,AllBitmaps[i].name)) { //Int3(); //this pig is out of date. Delete it must_rewrite_pig=1; } strcpy(AllBitmaps[i].name,temp_name); memset( &temp_bitmap, 0, sizeof(grs_bitmap) ); temp_bitmap.bm_w = temp_bitmap.bm_rowsize = bmh.width + ((short) (bmh.wh_extra&0x0f)<<8); temp_bitmap.bm_h = bmh.height + ((short) (bmh.wh_extra&0xf0)<<4); temp_bitmap.bm_flags = BM_FLAG_PAGED_OUT; temp_bitmap.avg_color = bmh.avg_color; temp_bitmap.bm_data = Piggy_bitmap_cache_data; GameBitmapFlags[i] = 0; if ( bmh.flags & BM_FLAG_TRANSPARENT ) GameBitmapFlags[i] |= BM_FLAG_TRANSPARENT; if ( bmh.flags & BM_FLAG_SUPER_TRANSPARENT ) GameBitmapFlags[i] |= BM_FLAG_SUPER_TRANSPARENT; if ( bmh.flags & BM_FLAG_NO_LIGHTING ) GameBitmapFlags[i] |= BM_FLAG_NO_LIGHTING; if ( bmh.flags & BM_FLAG_RLE ) GameBitmapFlags[i] |= BM_FLAG_RLE; if ( bmh.flags & BM_FLAG_RLE_BIG ) GameBitmapFlags[i] |= BM_FLAG_RLE_BIG; GameBitmapOffset[i] = bmh.offset + data_start; GameBitmaps[i] = temp_bitmap; } } else N_bitmaps = 0; //no pigfile, so no bitmaps #ifndef EDITOR Assert(N_bitmaps == Num_bitmap_files-1); #else if (must_rewrite_pig || (N_bitmaps < Num_bitmap_files-1)) { int size; //re-read the bitmaps that aren't in this pig for (i=N_bitmaps+1;iavg_color = compute_average_pixel(bm[fnum]); #ifdef EDITOR if ( FindArg("-macdata") ) swap_0_255( bm[fnum] ); #endif if ( !BigPig ) gr_bitmap_rle_compress( bm[fnum] ); if (bm[fnum]->bm_flags & BM_FLAG_RLE) size = *((int *) bm[fnum]->bm_data); else size = bm[fnum]->bm_w * bm[fnum]->bm_h; memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next],bm[fnum]->bm_data,size); d_free(bm[fnum]->bm_data); bm[fnum]->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next]; Piggy_bitmap_cache_next += size; GameBitmaps[i+fnum] = *bm[fnum]; // -- mprintf( (0, "U" )); d_free( bm[fnum] ); } i += nframes-1; //filled in multiple bitmaps } else { //this is a BBM grs_bitmap * new; ubyte newpal[256*3]; int iff_error; char bbmname[FILENAME_LEN]; int SuperX; MALLOC( new, grs_bitmap, 1 ); sprintf( bbmname, "%s.bbm", AllBitmaps[i].name ); iff_error = iff_read_bitmap(bbmname,new,BM_LINEAR,newpal); new->bm_handle=0; if (iff_error != IFF_NO_ERROR) { mprintf((1, "File %s - IFF error: %s",bbmname,iff_errormsg(iff_error))); Error("File %s - IFF error: %s",bbmname,iff_errormsg(iff_error)); } SuperX = (GameBitmapFlags[i]&BM_FLAG_SUPER_TRANSPARENT)?254:-1; //above makes assumption that supertransparent color is 254 if ( iff_has_transparency ) gr_remap_bitmap_good( new, newpal, iff_transparent_color, SuperX ); else gr_remap_bitmap_good( new, newpal, -1, SuperX ); new->avg_color = compute_average_pixel(new); #ifdef EDITOR if ( FindArg("-macdata") ) swap_0_255( new ); #endif if ( !BigPig ) gr_bitmap_rle_compress( new ); if (new->bm_flags & BM_FLAG_RLE) size = *((int *) new->bm_data); else size = new->bm_w * new->bm_h; memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next],new->bm_data,size); d_free(new->bm_data); new->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next]; Piggy_bitmap_cache_next += size; GameBitmaps[i] = *new; d_free( new ); // -- mprintf( (0, "U" )); } } //@@Dont' do these things which are done when writing //@@for (i=0; i < Num_bitmap_files; i++ ) { //@@ bitmap_index bi; //@@ bi.index = i; //@@ PIGGY_PAGE_IN( bi ); //@@} //@@ //@@piggy_close_file(); piggy_write_pigfile(pigname); Current_pigfile[0] = 0; //say no pig, to force reload piggy_new_pigfile(pigname); //read in just-generated pig } #endif //ifdef EDITOR } ubyte bogus_data[64*64]; grs_bitmap bogus_bitmap; ubyte bogus_bitmap_initialized=0; digi_sound bogus_sound; extern void bm_read_all(CFILE * fp); #define HAMFILE_ID MAKE_SIG('!','M','A','H') //HAM! #ifdef SHAREWARE #define HAMFILE_VERSION 2 #else #define HAMFILE_VERSION 3 #endif //version 1 -> 2: save marker_model_num //version 2 -> 3: removed sound files #define SNDFILE_ID MAKE_SIG('D','N','S','D') //DSND #define SNDFILE_VERSION 1 int read_hamfile() { CFILE * ham_fp = NULL; int ham_id,ham_version; #ifdef MACINTOSH char name[255]; #endif #ifndef MACINTOSH ham_fp = cfopen( DEFAULT_HAMFILE, "rb" ); #else sprintf(name, ":Data:%s", DEFAULT_HAMFILE ); ham_fp = cfopen( name, "rb" ); #endif if (ham_fp == NULL) { Must_write_hamfile = 1; return 0; } //make sure ham is valid type file & is up-to-date ham_id = cfile_read_int(ham_fp); ham_version = cfile_read_int(ham_fp); if (ham_id != HAMFILE_ID || ham_version != HAMFILE_VERSION) { Must_write_hamfile = 1; cfclose(ham_fp); //out of date ham return 0; } if (ham_version < 3) //mystery value cfseek(ham_fp, 4, SEEK_CUR); #ifndef EDITOR { bm_read_all( ham_fp ); // Note connection to above if!!! cfread( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp ); #ifdef MACINTOSH { int i; for (i = 0; i < MAX_BITMAP_FILES; i++) GameBitmapXlat[i] = SWAPSHORT(GameBitmapXlat[i]); } #endif } #endif cfclose(ham_fp); return 1; } int read_sndfile() { CFILE * snd_fp = NULL; int snd_id,snd_version; int N_sounds; int sound_start; int header_size; int i,size, length; DiskSoundHeader sndh; digi_sound temp_sound; char temp_name_read[16]; int sbytes = 0; #ifdef MACINTOSH char name[255]; #endif #ifndef MACINTOSH snd_fp = cfopen( DEFAULT_SNDFILE, "rb" ); #else sprintf( name, ":Data:%s", DEFAULT_SNDFILE ); snd_fp = cfopen( name, "rb"); #endif if (snd_fp == NULL) return 0; //make sure soundfile is valid type file & is up-to-date snd_id = cfile_read_int(snd_fp); snd_version = cfile_read_int(snd_fp); if (snd_id != SNDFILE_ID || snd_version != SNDFILE_VERSION) { cfclose(snd_fp); //out of date sound file return 0; } N_sounds = cfile_read_int(snd_fp); sound_start = cftell(snd_fp); size = cfilelength(snd_fp) - sound_start; length = size; mprintf( (0, "\nReading data (%d KB) ", size/1024 )); header_size = N_sounds*sizeof(DiskSoundHeader); //Read sounds for (i=0; icv_h-20, "%s...", TXT_LOADING_DATA ); WIN(DDGRUNLOCK(dd_grd_curcanv)); #ifdef EDITOR piggy_init_pigfile(DEFAULT_PIGFILE); #endif ham_ok = read_hamfile(); snd_ok = read_sndfile(); atexit(piggy_close); mprintf ((0,"HamOk=%d SndOk=%d\n",ham_ok,snd_ok)); return (ham_ok && snd_ok); //read ok } int piggy_is_needed(int soundnum) { int i; if ( !digi_lomem ) return 1; for (i=0; i 0 ) { if ( piggy_is_needed(i) ) { cfseek( fp, SoundOffset[i], SEEK_SET ); // Read in the sound data!!! snd->data = ptr; ptr += snd->length; sbytes += snd->length; cfread( snd->data, snd->length, 1, fp ); } else snd->data = (ubyte *) -1; } } cfclose(fp); mprintf(( 0, "\nActual Sound usage: %d KB\n", sbytes/1024 )); } extern int descent_critical_error; extern unsigned descent_critical_deverror; extern unsigned descent_critical_errcode; char * crit_errors[13] = { "Write Protected", "Unknown Unit", "Drive Not Ready", "Unknown Command", "CRC Error", \ "Bad struct length", "Seek Error", "Unknown media type", "Sector not found", "Printer out of paper", "Write Fault", \ "Read fault", "General Failure" }; void piggy_critical_error() { grs_canvas * save_canv; grs_font * save_font; int i; save_canv = grd_curcanv; save_font = grd_curcanv->cv_font; gr_palette_load( gr_palette ); i = nm_messagebox( "Disk Error", 2, "Retry", "Exit", "%s\non drive %c:", crit_errors[descent_critical_errcode&0xf], (descent_critical_deverror&0xf)+'A' ); if ( i == 1 ) exit(1); gr_set_current_canvas(save_canv); grd_curcanv->cv_font = save_font; } void piggy_bitmap_page_in( bitmap_index bitmap ) { grs_bitmap * bmp; int i,org_i,temp; org_i = 0; i = bitmap.index; Assert( i >= 0 ); Assert( i < MAX_BITMAP_FILES ); Assert( i < Num_bitmap_files ); Assert( Piggy_bitmap_cache_size > 0 ); if ( i < 1 ) return; if ( i >= MAX_BITMAP_FILES ) return; if ( i >= Num_bitmap_files ) return; if ( GameBitmapOffset[i] == 0 ) return; // A read-from-disk bitmap!!! if ( piggy_low_memory ) { org_i = i; i = GameBitmapXlat[i]; // Xlat for low-memory settings! } bmp = &GameBitmaps[i]; if ( bmp->bm_flags & BM_FLAG_PAGED_OUT ) { stop_time(); ReDoIt: descent_critical_error = 0; cfseek( Piggy_fp, GameBitmapOffset[i], SEEK_SET ); if ( descent_critical_error ) { piggy_critical_error(); goto ReDoIt; } bmp->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next]; bmp->bm_flags = GameBitmapFlags[i]; if ( bmp->bm_flags & BM_FLAG_RLE ) { int zsize = 0; descent_critical_error = 0; zsize = cfile_read_int(Piggy_fp); if ( descent_critical_error ) { piggy_critical_error(); goto ReDoIt; } // GET JOHN NOW IF YOU GET THIS ASSERT!!! //Assert( Piggy_bitmap_cache_next+zsize < Piggy_bitmap_cache_size ); if ( Piggy_bitmap_cache_next+zsize >= Piggy_bitmap_cache_size ) { Int3(); piggy_bitmap_page_out_all(); goto ReDoIt; } memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], &zsize, sizeof(int) ); Piggy_bitmap_cache_next += sizeof(int); descent_critical_error = 0; temp = cfread( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], 1, zsize-4, Piggy_fp ); if ( descent_critical_error ) { piggy_critical_error(); goto ReDoIt; } Piggy_bitmap_cache_next += zsize-4; } else { // GET JOHN NOW IF YOU GET THIS ASSERT!!! Assert( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) < Piggy_bitmap_cache_size ); if ( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) >= Piggy_bitmap_cache_size ) { piggy_bitmap_page_out_all(); goto ReDoIt; } descent_critical_error = 0; temp = cfread( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], 1, bmp->bm_h*bmp->bm_w, Piggy_fp ); if ( descent_critical_error ) { piggy_critical_error(); goto ReDoIt; } Piggy_bitmap_cache_next+=bmp->bm_h*bmp->bm_w; } //@@if ( bmp->bm_selector ) { //@@#if !defined(WINDOWS) && !defined(MACINTOSH) //@@ if (!dpmi_modify_selector_base( bmp->bm_selector, bmp->bm_data )) //@@ Error( "Error modifying selector base in piggy.c\n" ); //@@#endif //@@} start_time(); } if ( piggy_low_memory ) { if ( org_i != i ) GameBitmaps[org_i] = GameBitmaps[i]; } //@@Removed from John's code: //@@#ifndef WINDOWS //@@ if ( bmp->bm_selector ) { //@@ if (!dpmi_modify_selector_base( bmp->bm_selector, bmp->bm_data )) //@@ Error( "Error modifying selector base in piggy.c\n" ); //@@ } //@@#endif } void piggy_bitmap_page_out_all() { int i; Piggy_bitmap_cache_next = 0; piggy_page_flushed++; texmerge_flush(); rle_cache_flush(); for (i=0; i 0 ) { // Don't page out bitmaps read from disk!!! GameBitmaps[i].bm_flags = BM_FLAG_PAGED_OUT; GameBitmaps[i].bm_data = Piggy_bitmap_cache_data; } } mprintf(( 0, "Flushing piggy bitmap cache\n" )); } void piggy_load_level_data() { piggy_bitmap_page_out_all(); paging_touch_all(); } #ifdef EDITOR void change_filename_ext( char *dest, char *src, char *ext ); void piggy_write_pigfile(char *filename) { FILE *pig_fp; int bitmap_data_start,data_offset; DiskBitmapHeader bmh; int org_offset; char subst_name[32]; int i; FILE *fp1,*fp2; char tname[FILENAME_LEN]; // -- mprintf( (0, "Paging in all piggy bitmaps..." )); for (i=0; i < Num_bitmap_files; i++ ) { bitmap_index bi; bi.index = i; PIGGY_PAGE_IN( bi ); } // -- mprintf( (0, "\n" )); piggy_close_file(); // -- mprintf( (0, "Creating %s...",filename )); pig_fp = fopen( filename, "wb" ); //open PIG file Assert( pig_fp!=NULL ); write_int(PIGFILE_ID,pig_fp); write_int(PIGFILE_VERSION,pig_fp); Num_bitmap_files--; fwrite( &Num_bitmap_files, sizeof(int), 1, pig_fp ); Num_bitmap_files++; bitmap_data_start = ftell(pig_fp); bitmap_data_start += (Num_bitmap_files-1)*sizeof(DiskBitmapHeader); data_offset = bitmap_data_start; change_filename_ext(tname,filename,"lst"); fp1 = fopen( tname, "wt" ); change_filename_ext(tname,filename,"all"); fp2 = fopen( tname, "wt" ); for (i=1; i < Num_bitmap_files; i++ ) { int *size; grs_bitmap *bmp; { char * p, *p1; p = strchr(AllBitmaps[i].name,'#'); if (p) { int n; p1 = p; p1++; n = atoi(p1); *p = 0; if (fp2 && n==0) fprintf( fp2, "%s.abm\n", AllBitmaps[i].name ); memcpy( bmh.name, AllBitmaps[i].name, 8 ); Assert( n <= 63 ); bmh.dflags = DBM_FLAG_ABM + n; *p = '#'; }else { if (fp2) fprintf( fp2, "%s.bbm\n", AllBitmaps[i].name ); memcpy( bmh.name, AllBitmaps[i].name, 8 ); bmh.dflags = 0; } } bmp = &GameBitmaps[i]; Assert( !(bmp->bm_flags&BM_FLAG_PAGED_OUT) ); if (fp1) fprintf( fp1, "BMP: %s, size %d bytes", AllBitmaps[i].name, bmp->bm_rowsize * bmp->bm_h ); org_offset = ftell(pig_fp); bmh.offset = data_offset - bitmap_data_start; fseek( pig_fp, data_offset, SEEK_SET ); if ( bmp->bm_flags & BM_FLAG_RLE ) { size = (int *)bmp->bm_data; fwrite( bmp->bm_data, sizeof(ubyte), *size, pig_fp ); data_offset += *size; if (fp1) fprintf( fp1, ", and is already compressed to %d bytes.\n", *size ); } else { fwrite( bmp->bm_data, sizeof(ubyte), bmp->bm_rowsize * bmp->bm_h, pig_fp ); data_offset += bmp->bm_rowsize * bmp->bm_h; if (fp1) fprintf( fp1, ".\n" ); } fseek( pig_fp, org_offset, SEEK_SET ); Assert( GameBitmaps[i].bm_w < 4096 ); bmh.width = (GameBitmaps[i].bm_w & 0xff); bmh.wh_extra = ((GameBitmaps[i].bm_w >> 8) & 0x0f); Assert( GameBitmaps[i].bm_h < 4096 ); bmh.height = GameBitmaps[i].bm_h; bmh.wh_extra |= ((GameBitmaps[i].bm_h >> 4) & 0xf0); bmh.flags = GameBitmaps[i].bm_flags; if (piggy_is_substitutable_bitmap( AllBitmaps[i].name, subst_name )) { bitmap_index other_bitmap; other_bitmap = piggy_find_bitmap( subst_name ); GameBitmapXlat[i] = other_bitmap.index; bmh.flags |= BM_FLAG_PAGED_OUT; //mprintf(( 0, "Skipping bitmap %d\n", i )); //mprintf(( 0, "Marking '%s' as substitutible\n", AllBitmaps[i].name )); } else { bmh.flags &= ~BM_FLAG_PAGED_OUT; } bmh.avg_color=GameBitmaps[i].avg_color; fwrite( &bmh, sizeof(DiskBitmapHeader), 1, pig_fp ); // Mark as a bitmap } fclose(pig_fp); mprintf( (0, " Dumped %d assorted bitmaps.\n", Num_bitmap_files )); fprintf( fp1, " Dumped %d assorted bitmaps.\n", Num_bitmap_files ); fclose(fp1); fclose(fp2); } static void write_int(int i,FILE *file) { if (fwrite( &i, sizeof(i), 1, file) != 1) Error( "Error reading int in gamesave.c" ); } void piggy_dump_all() { int i, xlat_offset; FILE * ham_fp; int org_offset,data_offset=0; DiskSoundHeader sndh; int sound_data_start=0; FILE *fp1,*fp2; #ifdef NO_DUMP_SOUNDS Num_sound_files = 0; Num_sound_files_new = 0; #endif if (!Must_write_hamfile && (Num_bitmap_files_new == 0) && (Num_sound_files_new == 0) ) return; fp1 = fopen( "ham.lst", "wt" ); fp2 = fopen( "ham.all", "wt" ); if (Must_write_hamfile || Num_bitmap_files_new) { mprintf( (0, "Creating %s...",DEFAULT_HAMFILE)); ham_fp = fopen( DEFAULT_HAMFILE, "wb" ); //open HAM file Assert( ham_fp!=NULL ); write_int(HAMFILE_ID,ham_fp); write_int(HAMFILE_VERSION,ham_fp); bm_write_all(ham_fp); xlat_offset = ftell(ham_fp); fwrite( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp ); //Dump bitmaps if (Num_bitmap_files_new) piggy_write_pigfile(DEFAULT_PIGFILE); //free up memeory used by new bitmaps for (i=Num_bitmap_files-Num_bitmap_files_new;idata, sizeof(ubyte), snd->length, ham_fp ); data_offset += snd->length; fseek( ham_fp, org_offset, SEEK_SET ); fwrite( &sndh, sizeof(DiskSoundHeader), 1, ham_fp ); // Mark as a bitmap fprintf( fp1, "SND: %s, size %d bytes\n", AllSounds[i].name, snd->length ); fprintf( fp2, "%s.raw\n", AllSounds[i].name ); } fclose(ham_fp); mprintf( (0, "\n" )); } fprintf( fp1, "Total sound size: %d bytes\n", data_offset-sound_data_start); mprintf( (0, " Dumped %d assorted sounds.\n", Num_sound_files )); fprintf( fp1, " Dumped %d assorted sounds.\n", Num_sound_files ); fclose(fp1); fclose(fp2); // Never allow the game to run after building ham. exit(0); } #endif void piggy_close() { piggy_close_file(); if (BitmapBits) d_free(BitmapBits); if ( SoundBits ) d_free( SoundBits ); hashtable_free( &AllBitmapsNames ); hashtable_free( &AllDigiSndNames ); } int piggy_does_bitmap_exist_slow( char * name ) { int i; for (i=0; i