#include "global.h" #include "ext.h" // file header info #define TILE_ID "JbS Type 4 Tileset" #define TILE_VERSION 6 #define SPRITE_ID "JbS Sprite File" #define SPRITE_VERSION 6 #define RACE_ID "JbS Race File" #define RACE_VERSION 5 #define PROJECTILE_ID "JbS Projectile File" #define PROJECTILE_VERSION 4 #define WEAPON_ID "JbS Weapon File" #define WEAPON_VERSION 3 #define CHARACTER_ID "JbS Character File" #define CHARACTER_VERSION 6 // changed to 4 and then 5 in v1.2 to support long filenames/hoverboard offsets #define MAP_LIST_ID "Meteor Map List" #define MAP_LIST_VERSION 1 // file header structures typedef struct{ int x, y; // x and y map pos int unit; // race id int angle; int ai; // this the unit's AI type (i.e. AI_NORMAL) }TOLD_MAP_UNIT; typedef struct{ int x, y; int sprite; int angle; }TOLD_MAP_SPRITE; // * code * void FIL_AddBasePathPrefix( char *outPathString, char AllowModBasePath) { char temp[ 256]; // reject absolute paths if( (outPathString[0] == '/') || (outPathString[0] == '\\') || (outPathString[0] == '.') || (outPathString[1]==':') ) return; strcpy( temp, outPathString); if( (AllowModBasePath) && (DAT_UsingMod) ) { strcpy( outPathString, DAT_ModifiedBaseDir); } else { strcpy( outPathString, PATH_ROOT); } put_backslash( outPathString); strcat( outPathString, temp); } void FIL_BuildGameDataLookUpTables() { int i; // weapons - store sprite and projectile numbers for each weapon for( i=0; i< DAT_LoadedWeapons.count; ++i) { DAT_LoadedWeapons.weapons[i].SpriteNumber = SPR_GetSpriteNumberForName( DAT_LoadedWeapons.weapons[i].SpriteName); DAT_LoadedWeapons.weapons[i].ProjectileNumber = PED_GetProjectileNumberForName( DAT_LoadedWeapons.weapons[i].ProjectileName); } // races - store sprite numbers for( i=0; i=MAX_TSPRITES) { MSG_Message("Can not load more than %d sprites!", MAX_TSPRITES); i = list.count; // break loop } else { if( list.items[i].filename != NULL) { if( !MISC_DoesStringExistInArray( list.items[i].filename, DAT_LoadedSprites.names, DAT_LoadedSprites.count)) { strcpy( filename, list.items[i].filename); JDIR_AddPathToFront( filename, FullPath); if( FIL_ReadSpriteFile( filename, &DAT_LoadedSprites.sprites[ DAT_LoadedSprites.count], 0 )) { MEM_StrAllocCopy( &DAT_LoadedSprites.names[ DAT_LoadedSprites.count], list.items[i].filename); DAT_LoadedSprites.count++; loaded ++; } } } } } MSG_Message("Loaded %d sprite(s) from \"%s\"", loaded, FullPath); // ********************************************************************************* // load projectiles // ********************************************************************************* strcpy( FullPath, PATH_PROJECTILES); FIL_AddBasePathPrefix( FullPath, inUseModFolder); JDIR_CreateDirectoryList( &list, FullPath, "*.*", DIRMODE_FILES, 0); loaded = 0; for( i=0; i=MAX_PTILE_TYPES) { MSG_Message("Can not load more than %d projectiles!", MAX_PTILE_TYPES); i = list.count; // break loop } else { if( list.items[i].filename != NULL) { if( !MISC_DoesStringExistInArray( list.items[i].filename, DAT_LoadedProjectiles.names, DAT_LoadedProjectiles.count)) { strcpy( filename, list.items[i].filename); JDIR_AddPathToFront( filename, FullPath); if( FIL_ReadProjectileFile( filename, &DAT_LoadedProjectiles.projectiles[ DAT_LoadedProjectiles.count], 0)) { MEM_StrAllocCopy( &DAT_LoadedProjectiles.names[ DAT_LoadedProjectiles.count], list.items[i].filename); DAT_LoadedProjectiles.count++; loaded ++; } } } } } MSG_Message("Loaded %d projectile(s) from \"%s\"", loaded, FullPath); // ********************************************************************************* // load weapons // ********************************************************************************* strcpy( FullPath, PATH_WEAPONS); FIL_AddBasePathPrefix( FullPath, inUseModFolder); JDIR_CreateDirectoryList( &list, FullPath, "*.*", DIRMODE_FILES, 0); loaded = 0; for( i=0; i= MAX_WEAPONS) { MSG_Message("Can not load more than %d weapons!", MAX_WEAPONS); i = list.count; // break loop } else { if( list.items[i].filename != NULL) { if( !MISC_DoesStringExistInArray( list.items[i].filename, DAT_LoadedWeapons.names, DAT_LoadedWeapons.count)) { strcpy( filename, list.items[i].filename); JDIR_AddPathToFront( filename, FullPath); if( FIL_ReadWeaponFile( filename, &DAT_LoadedWeapons.weapons[ DAT_LoadedWeapons.count])) { MEM_StrAllocCopy( &DAT_LoadedWeapons.names[ DAT_LoadedWeapons.count], list.items[i].filename); DAT_LoadedWeapons.count++; loaded ++; } } } } } MSG_Message("Loaded %d weapons(s) from \"%s\"", loaded, FullPath); // ********************************************************************************* // load races // ********************************************************************************* strcpy( FullPath, PATH_RACES); FIL_AddBasePathPrefix( FullPath, inUseModFolder); JDIR_CreateDirectoryList( &list, FullPath, "*.*", DIRMODE_FILES, 0); loaded = 0; for( i=0; i= MAX_RACES) { MSG_Message("Can not load more than %d races!", MAX_RACES); i = list.count; // break loop } else { if( list.items[i].filename != NULL) { if( !MISC_DoesStringExistInArray( list.items[i].filename, DAT_LoadedRaces.names, DAT_LoadedRaces.count)) { strcpy( filename, list.items[i].filename); JDIR_AddPathToFront( filename, FullPath); if( FIL_ReadRaceFile( filename, &DAT_LoadedRaces.races[ DAT_LoadedRaces.count], 0 )) { // PCX export code (used for making docs images!) /*strcpy( tTempString, str); JDIR_RemovePath( tTempString); JDIR_RemoveFileExt( tTempString); sprintf( tPcxFilename, "racegfx\\%s.pcx", tTempString); if( loaded < 1) JG_MessageBox( tPcxFilename); RACEED_ExportRaceImageFile( str, tPcxFilename); */ MEM_StrAllocCopy( &DAT_LoadedRaces.names[ DAT_LoadedRaces.count], list.items[i].filename); DAT_LoadedRaces.count++; loaded ++; } } } } } MSG_Message("Loaded %d races(s) from \"%s\"", loaded, FullPath); } void FIL_UnloadGameData() { int i; /* The loaded races and weapons do not contain any allocated memory so they do not require destroying The sprites and projectiles contain allocated memory which must be destroyed */ // lose sprites for( i=0; iid, 0, sizeof( h->id) ); strcpy( h->id, id); h->version = version; } BITMAP *FIL_LoadPcx( char *filename) { BITMAP *b; RGB pal[256]; b = load_pcx( filename, pal); return b; } void *FIL_LoadDataObject( char *name) { DATAFILE *data; data=load_datafile_object( FILE_MAINDATA, name ); if( data == NULL) { APP_ProgramError("FIL_LoadDataFileObject: Object not found \"%s\" or out of memory", name); } return data[0].dat; } void *FIL_LoadDataObjectFromDataFile( char *DataFilename, char *name) { DATAFILE *data; data=load_datafile_object( DataFilename, name ); if( data == NULL) { MSG_Message("FIL_LoadDataFileObjectFromDataFile: Could not read \"%s\" from \"%s\"", name, DataFilename); return NULL; } return data[0].dat; } int FIL_ReadMapListFile( char *filename, TMAP_LIST *m, char DestroyOld) { FILE *f; int i, size; TSTANDARD_FILE_HEADER hdr; if(( f=fopen( filename, "rb")) == NULL) return 0; if( DestroyOld) ML_DestroyMapList( m); fread( &hdr, sizeof( hdr), 1, f); if( !FIL_CheckHeader( &hdr, MAP_LIST_ID, MAP_LIST_VERSION, filename, 0)) { fclose( f); return 0; } fread( m->ListTitle, 64, 1, f); fread( &m->count, sizeof( char), 1, f); for( i=0; icount; ++i) { fread( &size, sizeof( int), 1, f); m->entries[i].MapFilename = MEM_AllocateBuf( size); fread( m->entries[i].MapFilename, size, 1, f); fread( &size, sizeof( int), 1, f); m->entries[i].MusicFilename = MEM_AllocateBuf( size); fread( m->entries[i].MusicFilename, size, 1, f); } fclose(f); return 1; } int FIL_WriteMapListFile( char *filename, TMAP_LIST *m) { FILE *f; int i, size; TSTANDARD_FILE_HEADER hdr; if(( f=fopen( filename, "wb")) == NULL) return 0; memset( hdr.id, 0, sizeof( hdr.id) ); strcpy( hdr.id, MAP_LIST_ID); hdr.version = MAP_LIST_VERSION; fwrite( &hdr, sizeof( hdr), 1, f); fwrite( m->ListTitle, 64, 1, f); fwrite( &m->count, sizeof( char), 1, f); for( i=0; icount; ++i) { size = strlen( m->entries[i].MapFilename) +1; fwrite( &size, sizeof( int), 1, f); fwrite( m->entries[i].MapFilename, size, 1, f); size = strlen( m->entries[i].MusicFilename) +1; fwrite( &size, sizeof( int), 1, f); fwrite( m->entries[i].MusicFilename, size, 1, f); } fclose(f); return 1; } int FIL_LoadTileset( char *filename, int start) { FILE *f; unsigned char *buf; int i, InvalidDestroyedTileCount; unsigned char index; TSTANDARD_FILE_HEADER hdr; OLD_TILE_HEADER OldTileHeader; MSG_Message("FIL_LoadTileset: Loading tileset from %s", filename); if(( f=fopen( filename, "rb")) == NULL) return 0; fread( &hdr, sizeof( hdr), 1, f); if( !FIL_CheckHeader( &hdr, TILE_ID, TILE_VERSION, filename, 1)) { fclose( f); return 0; } // allocate buffer for 16bpp tile pixel data buf = malloc( (TILE_X * TILE_Y) * 2 ); if( buf == NULL) { fclose(f); MSG_Message("Unable to allocate temp read tile buffer"); return 0; } // * legacy loader * if( hdr.version < 5) { // pre v1.2 8 bit tileset fread( &OldTileHeader, sizeof( OldTileHeader), 1, f); // convert old pick up colours for( i=0; i= MAX_TILES) ) { TileData[i].DestroyedTile = 0; MSG_Message("WARNING: \"Destroyed Tile\" for tile %d was invalid, defaulted to 0", i+1); InvalidDestroyedTileCount++; } // make sure that the destroyed tile is not the same as the current tile /*if( TileData[i].DestroyedTile == i) { MSG_Message("WARINING: \"Destroyed Tile\" is the same as the current tile, changing to %d", i+1); TileData[i].DestroyedTile = i+1; }*/ // reassign destroyed tiles if start > 0 if( start > 0) { TileData[i].DestroyedTile += start; } } if( InvalidDestroyedTileCount > 0) { MSG_Message("Found %d invalid \"Destroyed Tiles\" while loading tileset", InvalidDestroyedTileCount); MSG_Message("Check and reassign \"Destroyed Tiles\""); } for( i=start; i= 6) { fread( &DAT_SpecialTileData[i].SpecialTypeNumber, sizeof(char), 1, f); fread( &DAT_SpecialTileData[i].UsedTileNumber, sizeof(int), 1, f); fread( &DAT_SpecialTileData[i].LinkTile, sizeof(int), 1,f); fread( &DAT_SpecialTileData[i].UsedLinkTile, sizeof(int),1 ,f); fread( &DAT_SpecialTileData[i].EventSound, FILENAME_LEN, 1, f); fread( &DAT_SpecialTileData[i].RequiredItem, 32, 1, f); fread( &DAT_SpecialTileData[i].NumberRequired, sizeof(int), 1, f); // calc DAT_SpecialTileData[i].a_EventSoundNumber = AUD_GetSoundNumberForName( DAT_SpecialTileData[i].EventSound); } else { if( hdr.version >= 4) fread( &DAT_SpecialTileData[i], 68, 1, f); else { fread( &DAT_SpecialTileData[i], 64, 1, f); DAT_SpecialTileData[i].NumberRequired = 1; } } // we need to reassign any referenced special tile numbers to // cater for the offset in the tileset if( start > 0) { DAT_SpecialTileData[i].SpecialTypeNumber += start; DAT_SpecialTileData[i].UsedTileNumber += start; DAT_SpecialTileData[i].LinkTile += start; DAT_SpecialTileData[i].UsedLinkTile += start; } } // MSG_Message("FIL_LoadTileset: Reading tile image data"); for( i=start; iw * b->h)*2 ); MISC_BitmapToBuf( buf, b, b->w, b->h); x = b->w; y = b->h; fwrite( &x, sizeof( x), 1, f); fwrite( &y, sizeof( x), 1, f); // write 16 bit pixel buffer fwrite( buf, (b->w*b->h)*2, 1, f); free( buf); } BITMAP *FIL_ReadBitmap( FILE *f, char inEightBit) { BITMAP *b; int sx, sy; unsigned char *buf; // read dimensions fread( &sx, sizeof( sx), 1, f); fread( &sy, sizeof( sy), 1, f); if( inEightBit) { // allocate 8 bit pixel buffer buf = MEM_AllocateBuf( sx*sy); // read 8 bit pixel data fread( buf, sx*sy, 1, f); } else { // allocate 16 bit pixel buffer buf = MEM_AllocateBuf( (sx*sy)*2 ); // read 16 bit pixel data fread( buf, (sx*sy)*2, 1, f); } b = MISC_NewBitmap( sx, sy); // convert buffer to bitmap MISC_BufToBitmap( b, buf, sx, sy, inEightBit); free( buf); return b; } int FIL_ReadSpriteFile( char *filename, TSPRITE *s, int inDestroyCurrentData) { int i; FILE *f; TSTANDARD_FILE_HEADER hdr; int dummy; if(( f=fopen( filename, "rb")) == NULL) return 0; if( inDestroyCurrentData) { SPED_DestroySprite( s); } //read header fread( &hdr, sizeof( hdr), 1, f); if( !FIL_CheckHeader( &hdr, SPRITE_ID, SPRITE_VERSION, filename, 1)) { fclose( f); return 0; } fread( s->name, sizeof( s->name), 1, f); fread( &s->NumFrames, sizeof( s->NumFrames), 1, f); fread( &s->NumSubs, sizeof( s->NumSubs), 1, f); fread( &s->rotate, sizeof( s->rotate), 1, f); if( hdr.version > 5) { fread( &s->LoopSound, sizeof(s->LoopSound), 1, f); } else { memset( s->LoopSound, 0, sizeof(s->LoopSound) ); strcpy( s->LoopSound, NOSOUND); } s->a_LoopSoundNumber = AUD_GetSoundNumberForName( s->LoopSound); // read subs for( i=0; iNumSubs; ++i) { fread( s->subs[i].name, sizeof( s->subs[i].name), 1, f); fread( &s->subs[i].xp, sizeof( s->subs[i].xp), 1, f); fread( &s->subs[i].yp, sizeof( s->subs[i].yp), 1, f); fread( &s->subs[i].rotate, sizeof( s->subs[i].rotate), 1, f); if( hdr.version < 4) { memset( s->subs[i].SourceFilename, 0, FILENAME_LEN); s->subs[i].image = FIL_ReadBitmap( f, 1); // 8 bit } else { fread( s->subs[i].SourceFilename, FILENAME_LEN, 1, f); s->subs[i].image = FIL_ReadBitmap( f, 0); // 16 bit } // ** note that calc stuff is done after loading the frames below ** } // read frames s->a_HasFrameSounds = 0; for( i=0; i< s->NumFrames; ++i) { fread( &s->frames[i].DisplayTime, sizeof( s->frames[i].DisplayTime), 1, f); if( hdr.version < 4) { memset( s->frames[i].SourceFilename, 0, FILENAME_LEN); s->frames[i].image = FIL_ReadBitmap( f, 1); // 8 bit } else { fread( s->frames[i].SourceFilename, FILENAME_LEN, 1, f); s->frames[i].image = FIL_ReadBitmap( f, 0); // 16 bit } if( hdr.version > 5) { fread( &s->frames[i].SoundName, sizeof(s->frames[i].SoundName), 1, f); } else { memset( s->frames[i].SoundName, 0, sizeof(s->frames[i].SoundName) ); strcpy( s->frames[i].SoundName, NOSOUND); } s->frames[i].a_SoundNumber = AUD_GetSoundNumberForName( s->frames[i].SoundName); if( s->frames[i].a_SoundNumber != -1) { s->a_HasFrameSounds = 1; } } // do calc stuff for subs for( i=0; iNumSubs; ++i) { SUB_CalcSubRotatedOffsets( s, i); JG_CreateRotatedImageData( &s->subs[i].rid, s->subs[i].image, 1); } // read terrain type fread( &s->TerrainType, sizeof( s->TerrainType), 1, f); if( hdr.version >= 2) // version 2+ fread( &s->DestroyType, sizeof( s->DestroyType), 1, f); else s->DestroyType = DT_CANT_BE_DESTROYED; // translucent was introduced in v3 and axed in v4 if( hdr.version == 3) fread( &dummy, sizeof( dummy), 1, f); // lighting (introduced in v5 18/6/2005) if( hdr.version >= 5) { fread( &s->LightSize, sizeof(s->LightSize), 1, f); fread( &s->LightColour.r, sizeof(s->LightColour.r), 1, f); fread( &s->LightColour.g, sizeof(s->LightColour.g), 1, f); fread( &s->LightColour.b, sizeof(s->LightColour.b), 1, f); } else { s->LightSize = 0; s->LightColour.r = 255; s->LightColour.g = 255; s->LightColour.b = 255; } fclose( f); // ********************************************************* // calc // create RID for this sprite (based on 1st frame) JG_CreateRotatedImageData( &s->rid, s->frames[0].image, 1); // clear sprite's default animation data SPR_ResetAnimationData( &s->DefaultAnimationData); // create light? if( s->LightSize > 0) { s->LightBitmap = LT_CreateBasicLight( s->LightSize/2, s->LightColour); s->LightBitmapAllocated = 1; s->LightDrawOffX = ( s->frames[0].image->w - s->LightBitmap->w) / 2; s->LightDrawOffY = ( s->frames[0].image->h - s->LightBitmap->h) / 2; } else { s->LightBitmapAllocated = 0; s->LightDrawOffX = 0; s->LightDrawOffY = 0; } return 1; } int FIL_WriteSpriteFile( char *filename, TSPRITE *s) { int i; FILE *f; TSTANDARD_FILE_HEADER hdr; if(( f=fopen( filename, "wb")) == NULL) return 0; memset( hdr.id, 0, sizeof( hdr.id) ); strcpy( hdr.id, SPRITE_ID); hdr.version = SPRITE_VERSION; // write header fwrite( &hdr, sizeof( hdr), 1, f); fwrite( s->name, sizeof( s->name), 1, f); fwrite( &s->NumFrames, sizeof( s->NumFrames), 1, f); fwrite( &s->NumSubs, sizeof( s->NumSubs), 1, f); fwrite( &s->rotate, sizeof( s->rotate), 1, f); fwrite( &s->LoopSound, sizeof( s->LoopSound), 1, f); // write subs for( i=0; iNumSubs; ++i) { fwrite( s->subs[i].name, sizeof( s->subs[i].name), 1, f); fwrite( &s->subs[i].xp, sizeof( s->subs[i].xp), 1, f); fwrite( &s->subs[i].yp, sizeof( s->subs[i].yp), 1, f); fwrite( &s->subs[i].rotate, sizeof( s->subs[i].rotate), 1, f); fwrite( s->subs[i].SourceFilename, FILENAME_LEN, 1, f); FIL_WriteBitmap( f, s->subs[i].image); } // write frames for( i=0; i< s->NumFrames; ++i) { fwrite( &s->frames[i].DisplayTime, sizeof( s->frames[i].DisplayTime), 1, f); fwrite( s->frames[i].SourceFilename, FILENAME_LEN, 1, f); FIL_WriteBitmap( f, s->frames[i].image); fwrite( s->frames[i].SoundName, sizeof(s->frames[i].SoundName), 1, f); } // write terrain type fwrite( &s->TerrainType, sizeof( s->TerrainType), 1, f); // version 2+ fwrite( &s->DestroyType, sizeof( s->DestroyType), 1, f); // lighting (version 5) fwrite( &s->LightSize, sizeof(s->LightSize), 1, f); fwrite( &s->LightColour.r, sizeof(s->LightColour.r), 1, f); fwrite( &s->LightColour.g, sizeof(s->LightColour.g), 1, f); fwrite( &s->LightColour.b, sizeof(s->LightColour.b), 1, f); fclose( f); return 1; } int FIL_ReadRaceFile( char *filename, TCHAR_RACE *r, int inDoRelationalData) { FILE *f; TSTANDARD_FILE_HEADER hdr; int i, dummy; if(( f=fopen( filename, "rb")) == NULL) return 0; fread( &hdr, sizeof( hdr), 1, f); if( !FIL_CheckHeader( &hdr, RACE_ID, RACE_VERSION, filename, 1)) { fclose( f); return 0; } // read data fread( r->desc, 32, 1, f); fread( &r->UnitClass, sizeof( r->UnitClass), 1, f); fread( &r->side, sizeof( r->side), 1, f); fread( &r->hp, sizeof( r->hp), 1, f); if( hdr.version < 4) { // sight was removed in file v4 fread( &dummy, sizeof( dummy), 1, f); } fread( &r->speed, sizeof( r->speed), 1, f); fread( &r->MaxHeight, sizeof( r->MaxHeight), 1, f); fread( &r->NumMounts, sizeof( r->NumMounts), 1, f); if( hdr.version < 3) { fread( r->DestroyedSound, 32, 1, f); fread( r->StillSpriteName, 13, 1, f); fread( r->MovingSpriteName, 13, 1, f); } else { fread( r->DestroyedSound, FILENAME_LEN, 1, f); fread( r->StillSpriteName, FILENAME_LEN, 1, f); fread( r->MovingSpriteName, FILENAME_LEN, 1, f); } if( hdr.version == 1) { memset( r->WastedSpriteName, 0, 32); memset( r->DropPowerUpName, 0, 32); memset( r->DropPowerUpName2, 0, 32); r->ProjectileStop = 1; } else if( hdr.version == 2) { fread( &dummy, sizeof( int), 1, f); // hop fread( &dummy, sizeof( int), 1, f); // PassableObject fread( r->WastedSpriteName, 32, 1, f); fread( r->DropPowerUpName, 32, 1, f); fread( r->DropPowerUpName2, 32, 1, f); memset( r->DropPowerUpNameMP, 0, 64); r->ProjectileStop = 1; } else if (hdr.version >= 3) { fread( &r->ProjectileStop, sizeof( r->ProjectileStop), 1, f); fread( r->WastedSpriteName, FILENAME_LEN, 1, f); fread( r->DropPowerUpName, 64, 1, f); fread( r->DropPowerUpName2, 64, 1, f); if( hdr.version >= 5) fread( r->DropPowerUpNameMP, 64, 1, f); else memset( r->DropPowerUpNameMP, 0, 64); } // read weapon mounts for( i=0; iNumMounts; ++i) { fread( &r->WeaponMounts[i].x, sizeof( r->WeaponMounts[i].x), 1, f); fread( &r->WeaponMounts[i].y, sizeof( r->WeaponMounts[i].y), 1, f); if( hdr.version < 3) fread( r->WeaponMounts[i].WeaponName, 13, 1, f); else fread( r->WeaponMounts[i].WeaponName, FILENAME_LEN, 1, f); // set weapon mount sprite number (must be done when ALL data is loaded, JB 16/12/2003) if( inDoRelationalData) { r->WeaponMounts[i].WeaponNumber = WED_GetWeaponNumberForName( r->WeaponMounts[i].WeaponName); } JG_CalculateRotatedSubBitmapOffsets( r->WeaponMounts[i].RotatedOffsets, RACE_STILL_BITMAP( r)->w, RACE_STILL_BITMAP( r)->h, RACE_WEAPON_SPRITE(r,i).frames[0].image->w, RACE_WEAPON_SPRITE(r,i).frames[0].image->h, r->WeaponMounts[i].x, r->WeaponMounts[i].y ); } // side compatability if( r->side >= NUM_SIDES) r->side = SIDE_NEUTRAL; fclose( f); r->a_DestroyedSoundNumber = AUD_GetSoundNumberForName( r->DestroyedSound); return 1; } int FIL_WriteRaceFile( char *filename, TCHAR_RACE *r) { FILE *f; TSTANDARD_FILE_HEADER hdr; int i; if(( f=fopen( filename, "wb")) == NULL) return 0; strcpy( hdr.id, RACE_ID); hdr.version = RACE_VERSION; fwrite( &hdr, sizeof( hdr), 1, f); // write data fwrite( r->desc, 32, 1, f); fwrite( &r->UnitClass, sizeof( r->UnitClass), 1, f); fwrite( &r->side, sizeof( r->side), 1, f); fwrite( &r->hp, sizeof( r->hp), 1, f); fwrite( &r->speed, sizeof( r->speed), 1, f); fwrite( &r->MaxHeight, sizeof( r->MaxHeight), 1, f); fwrite( &r->NumMounts, sizeof( r->NumMounts), 1, f); fwrite( r->DestroyedSound, FILENAME_LEN, 1, f); fwrite( r->StillSpriteName, FILENAME_LEN, 1, f); fwrite( r->MovingSpriteName, FILENAME_LEN, 1, f); fwrite( &r->ProjectileStop, sizeof( r->ProjectileStop), 1, f); fwrite( r->WastedSpriteName, FILENAME_LEN, 1, f); fwrite( r->DropPowerUpName, 64, 1, f); fwrite( r->DropPowerUpName2, 64, 1, f); fwrite( r->DropPowerUpNameMP, 64, 1, f); // write weapon mounts for( i=0; iNumMounts; ++i) { fwrite( &r->WeaponMounts[i].x, sizeof( r->WeaponMounts[i].x), 1, f); fwrite( &r->WeaponMounts[i].y, sizeof( r->WeaponMounts[i].y), 1, f); fwrite( r->WeaponMounts[i].WeaponName, FILENAME_LEN, 1, f); } fclose( f); return 1; } int FIL_ReadWeaponFile( char *filename, TWEAPON *w) { FILE *f; TOLD_WEAPON ow; TSTANDARD_FILE_HEADER hdr; // open file if(( f=fopen( filename, "rb")) == NULL) return 0; // read header fread( &hdr, sizeof( hdr), 1, f); if( !FIL_CheckHeader( &hdr, WEAPON_ID, WEAPON_VERSION, filename, YES)) { fclose( f); return 0; } if( hdr.version < 3) { // * use legacy loader * if( hdr.version == 1) { fread( &ow, sizeof( ow) - sizeof( ow.SpriteNumber) - sizeof( ow.ProjectileNumber) - sizeof( ow.MultiFire), 1, f); ow.MultiFire = 0; } else { fread( &ow, sizeof( ow) - sizeof( ow.SpriteNumber) - sizeof( ow.ProjectileNumber), 1, f); } // * convert * // desc memset( w->desc, 0, sizeof( w->desc) ); strcpy( w->desc, ow.desc); // fire sound memset( w->FireSound, 0, sizeof( w->FireSound) ); strcpy( w->FireSound, ow.FireSound); // sprite name memset( w->SpriteName, 0, sizeof( w->SpriteName) ); strcpy( w->SpriteName, ow.SpriteName); // projectile name memset( w->ProjectileName, 0, sizeof( w->ProjectileName) ); strcpy( w->ProjectileName, ow.ProjectileName); // values w->FireX = ow.FireX; w->FireY = ow.FireY; w->rotate = ow.rotate; w->rof = ow.rof; w->MultiFire = ow.MultiFire; } else { // * read v3+ file format (no typedef) * fread( w->desc, 32, 1, f); fread( w->FireSound, FILENAME_LEN, 1, f); fread( w->SpriteName, FILENAME_LEN, 1, f); fread( w->ProjectileName, FILENAME_LEN, 1, f); fread( &w->FireX, sizeof( int), 1, f); fread( &w->FireY, sizeof( int), 1, f); fread( &w->rotate, sizeof( int), 1, f); fread( &w->rof, sizeof( int), 1, f); fread( &w->MultiFire, sizeof( int), 1, f); } fclose(f); w->a_FireSoundNumber = AUD_GetSoundNumberForName( w->FireSound); return 1; } int FIL_WriteWeaponFile( char *filename, TWEAPON *w) { FILE *f; TSTANDARD_FILE_HEADER hdr; // open file if(( f=fopen( filename, "wb")) == NULL) return 0; // set header details FIL_SetStandardHeaderDetails( &hdr, WEAPON_ID, WEAPON_VERSION); // write header fwrite( &hdr, sizeof( hdr), 1, f); // write data fwrite( w->desc, 32, 1, f); fwrite( w->FireSound, FILENAME_LEN, 1, f); fwrite( w->SpriteName, FILENAME_LEN, 1, f); fwrite( w->ProjectileName, FILENAME_LEN, 1, f); fwrite( &w->FireX, sizeof( int), 1, f); fwrite( &w->FireY, sizeof( int), 1, f); fwrite( &w->rotate, sizeof( int), 1, f); fwrite( &w->rof, sizeof( int), 1, f); fwrite( &w->MultiFire, sizeof( int), 1, f); fclose(f); return 1; } int FIL_ReadProjectileFile( char *filename, TPROJECTILE *p, char inDestroyOld) { char DummyChar; FILE *f; TSTANDARD_FILE_HEADER hdr; if(( f=fopen( filename, "rb")) == NULL) return 0; // read header fread( &hdr, sizeof( hdr), 1, f); if( !FIL_CheckHeader( &hdr, PROJECTILE_ID, PROJECTILE_VERSION, filename, 1)) { fclose( f); return 0; } if( inDestroyOld) { PED_DestroyProjectile( p); } // read data fread( p->desc, 32, 1, f); // use 16 bit pixel data for v3+ if( hdr.version < 3) p->image = FIL_ReadBitmap( f, 1); else p->image = FIL_ReadBitmap( f, 0); fread( &p->range, sizeof( p->range), 1, f); fread( &p->damage, sizeof( p->damage), 1, f); fread( &p->speed, sizeof( p->speed), 1, f); // char SelfGuide was removed in v3 if( hdr.version < 3) fread( &DummyChar, sizeof( DummyChar), 1, f); fread( &p->BlastRadius, sizeof( p->BlastRadius), 1, f); // ContactSound filename length was increased in v3 if( hdr.version < 3) fread( p->ContactSound, 32, 1, f); else fread( p->ContactSound, FILENAME_LEN, 1, f); fread( &p->LightRadius, sizeof( p->LightRadius), 1, f); if( hdr.version > 3) { fread( &p->LightColour.r, sizeof(p->LightColour.r), 1, f); fread( &p->LightColour.g, sizeof(p->LightColour.g), 1, f); fread( &p->LightColour.b, sizeof(p->LightColour.b), 1, f); } else { p->LightColour.r = 255; p->LightColour.g = 255; p->LightColour.b = 255; } fread( &p->height, sizeof( p->height), 1, f); fread( &p->VapourLen, sizeof( p->VapourLen), 1, f); // char missile; and char patriot were removed for v3 if( hdr.version < 3) { fread( &DummyChar, sizeof( DummyChar), 1, f); fread( &DummyChar, sizeof( DummyChar), 1, f); } // bounce; was added in v2 if( hdr.version < 2) p->bounce = 0; else fread( &p->bounce, sizeof( p->bounce), 1, f); // source filename was added v3 if( hdr.version < 3) memset( p->SourceFilename, 0, FILENAME_LEN); else fread( p->SourceFilename, FILENAME_LEN, 1, f); // create RID JG_CreateRotatedImageData( &p->rid, p->image, 1); // create light bitmap? if( p->LightRadius > 0) { p->LightBitmap = LT_CreateBasicLight( max( p->image->w, p->image->h) + (p->LightRadius*2), p->LightColour); p->LightBitmapAllocated = 1; p->LightDrawOffX = (p->image->w - p->LightBitmap->w) / 2; p->LightDrawOffY = (p->image->h - p->LightBitmap->h) / 2; } else { p->LightBitmapAllocated = 0; p->LightDrawOffX = 0; p->LightDrawOffY = 0; } fclose(f); p->a_ContactSoundNumber = AUD_GetSoundNumberForName( p->ContactSound); return 1; } int FIL_WriteProjectileFile( char *filename, TPROJECTILE *p) { FILE *f; TSTANDARD_FILE_HEADER hdr; if(( f=fopen( filename, "wb")) == NULL) return 0; // set header details FIL_SetStandardHeaderDetails( &hdr, PROJECTILE_ID, PROJECTILE_VERSION); // write header fwrite( &hdr, sizeof( hdr), 1, f); // write data fwrite( p->desc, 32, 1, f); FIL_WriteBitmap( f, p->image); fwrite( &p->range, sizeof( p->range), 1, f); fwrite( &p->damage, sizeof( p->damage), 1, f); fwrite( &p->speed, sizeof( p->speed), 1, f); fwrite( &p->BlastRadius, sizeof( p->BlastRadius), 1, f); fwrite( p->ContactSound, FILENAME_LEN, 1, f); fwrite( &p->LightRadius, sizeof( p->LightRadius), 1, f); fwrite( &p->LightColour.r, sizeof(p->LightColour.r), 1, f); fwrite( &p->LightColour.g, sizeof(p->LightColour.g), 1, f); fwrite( &p->LightColour.b, sizeof(p->LightColour.b), 1, f); fwrite( &p->height, sizeof( p->height), 1, f); fwrite( &p->VapourLen, sizeof( p->VapourLen), 1, f); fwrite( &p->bounce, sizeof( p->bounce), 1, f); fwrite( p->SourceFilename, FILENAME_LEN, 1, f); // close file fclose( f); return 1; } int FIL_CheckHeader( TSTANDARD_FILE_HEADER *hdr, char *ExpectedId, int ExpectedVersion, char *filename, char AllowOldVersions) { // the filename parameter is simply passed for error messages if( strcmp( hdr->id, ExpectedId)) { MSG_Message("Error, \"%s\" is not valid!", filename); return 0; } if( !AllowOldVersions) { if( hdr->version < ExpectedVersion) { MSG_Message("Error, \"%s\" is in an obselete file version!", filename); return 0; } } if( hdr->version > ExpectedVersion) { MSG_Message("Error, \"%s\" is in an advanced file version!", filename); return 0; } return 1; } // pass filename only, no path void FIL_InitTileset( char *filename, char extended, char autotexture) { int i, x, y; BITMAP *temp; char str[ FILENAME_LEN]; int start; char HasWater, HasLava, HasAcid, HasLand; int colour; if( extended == YES) start = MAX_TILES; else start = 0; strcpy( str, PATH_TILES); JDIR_AddPath( str, filename); FIL_GetFirstFilename( str); if( !FIL_LoadTileset( str, start)) APP_ProgramError("FIL_InitTileset: Unable to load tileset from \"%s\"", str); if( !autotexture) { MSG_Message("FIL_InitTileset: Not autotexturing tileset"); return; } // MSG_Message("FIL_InitTileset: Autotexturing tileset"); // set the last pickup colour to that of the map's theatre // use x for GrassStart and y for GrassRand switch( MapHeader.GrassTheatre) { case THEATRE_GRASS: x=makecol16( 75,159, 63); y=5; break; case THEATRE_SNOW: x=makecol16(203,203,203); y=6; break; case THEATRE_MUD: x=makecol16(172, 97, 57); y=6; break; case THEATRE_SAND: x=makecol16(180,161, 0); y=4; break; case THEATRE_CUSTOM: x = MapHeader.GrassPickup.start; y = MapHeader.GrassPickup.range; break; default: MSG_Message("FIL_InitTiles: Unsupported map theatre value: %d", MapHeader.GrassTheatre); x=makecol( 0,255, 0); y=0; break; } // set the last (reserved) pick up colour for the map's theatre TileHeader.PickUpColours[MAX_PICKUP_COLOURS-1].used = 1; TileHeader.PickUpColours[MAX_PICKUP_COLOURS-1].pickup = CL_GRASS; TileHeader.PickUpColours[MAX_PICKUP_COLOURS-1].start = x; TileHeader.PickUpColours[MAX_PICKUP_COLOURS-1].range = y; // used for tile colour map temp = MISC_NewBitmap( 1, 1); // MSG_Message("FIL_InitTileset: Applying pick up colours and building tile minimap colour index"); for( i=start; ih; ++y) { for( x=0; xw; ++x) { colour = _getpixel16( Tiles[i], x, y); if( colour == CL_WATER) HasWater =1; else if( colour == CL_LAVA) HasLava = 1; else if( colour == CL_ACID) HasAcid = 1; else HasLand = 1; } } /* Each tile can only have one type of terrain being (in order) - Standard (ordinary tiles, walls and floors) - Animated water - Animated lava - Animated acid */ if( (!HasWater) && (!HasLava) && ( !HasAcid) ) { // tile is all land DAT_TileWaterMap[i] = WM_NONE; } else { if( HasLand) { if( HasWater) { // some water DAT_TileWaterMap[i] = WM_SOME_WATER; } else if( HasLava) { // some lava DAT_TileWaterMap[i] = WM_SOME_LAVA; } else if( HasAcid) { // some acid DAT_TileWaterMap[i] = WM_SOME_ACID; } } else { if( HasWater) { // all water DAT_TileWaterMap[i] = WM_ALL_WATER; } else if( HasLava) { // all lava DAT_TileWaterMap[i] = WM_ALL_LAVA; } else if( HasAcid) { // all acid DAT_TileWaterMap[i] = WM_ALL_ACID; } } } stretch_blit( Tiles[i], temp, 0, 0, Tiles[i]->w, Tiles[i]->h, 0, 0, temp->w, temp->h); TileColourMap[i] = _getpixel16( temp, 0, 0); } destroy_bitmap( temp); } int FIL_ReadCharacterFile( char *filename, TCHARACTER *c) { FILE *f; TSTANDARD_FILE_HEADER hdr; int i; if(( f=fopen( filename, "rb"))==NULL) return 0; fread( &hdr, sizeof( hdr), 1, f); if( !FIL_CheckHeader( &hdr, CHARACTER_ID, CHARACTER_VERSION, filename, YES)) { fclose( f); return 0; } if( hdr.version < 3) { fclose(f); MSG_Message("Character file is too old (pre version 3)"); return 0; } if( hdr.version == 3) { fread( c->desc, 32, 1, f); fread( c->StillSpriteName, 13, 1, f); fread( c->MovingSpriteName, 13, 1, f); } else { fread( c->desc, 128, 1, f); fread( c->StillSpriteName, FILENAME_LEN, 1, f); fread( c->MovingSpriteName, FILENAME_LEN, 1, f); } // weapons fread( &c->NumberOfWeapons, sizeof( c->NumberOfWeapons), 1, f); for( i=0; iNumberOfWeapons; ++i) { fread( &c->WeaponMounts[i].x, sizeof( c->WeaponMounts[i].x), 1, f); fread( &c->WeaponMounts[i].y, sizeof( c->WeaponMounts[i].y), 1, f); fread( c->WeaponMounts[i].WeaponItemName, 64, 1, f); fread( c->WeaponMounts[i].AmmoItemName, 64, 1, f); if( hdr.version == 3) { fread( c->WeaponMounts[i].HudSpriteName, 13, 1, f); fread( c->WeaponMounts[i].WeaponFilename, 13, 1, f); } else { fread( c->WeaponMounts[i].HudSpriteName, FILENAME_LEN, 1, f); fread( c->WeaponMounts[i].WeaponFilename, FILENAME_LEN, 1, f); } } // sounds if( hdr.version == 3) { fread( c->HurtSound, 13, 1, f); fread( c->WastedSound, 13, 1, f); } else { fread( c->HurtSound, FILENAME_LEN, 1, f); fread( c->WastedSound, FILENAME_LEN, 1, f); } // misc fread( &c->TerrainType, sizeof( c->TerrainType), 1, f); fread( &c->side, sizeof( c->side), 1, f); fread( &c->hp, sizeof( c->hp), 1, f); if( hdr.version == 3) c->height = 0; else fread( &c->height, sizeof( c->height), 1, f); if( hdr.version == 3) { fread( c->FaceSpriteName, 13, 1, f); } else { fread( c->FaceSpriteName, FILENAME_LEN, 1, f); } fread( &c->ControlType, sizeof( c->ControlType), 1, f); // hoverboard offsets - added in v5 if( hdr.version > 4) { fread( &c->HoverboardOffX, sizeof( c->HoverboardOffX), 1, f); fread( &c->HoverboardOffY, sizeof( c->HoverboardOffY), 1, f); } else { c->HoverboardOffX = 0; c->HoverboardOffY = 0; } // MP power ups - added in v6 if( hdr.version > 5) { fread( c->DropPowerUpNameMP, 64, 1, f); fread( c->DropPowerUpNameMP2, 64, 1, f); } else { memset( c->DropPowerUpNameMP, 0, 64); memset( c->DropPowerUpNameMP2, 0, 64); } fclose( f); CHED_UpdateCalculatedCharacterData( &*c); return 1; } int FIL_WriteCharacterFile( char *filename, TCHARACTER *c) { FILE *f; TSTANDARD_FILE_HEADER hdr; int i; if(( f=fopen( filename, "wb"))==NULL) return 0; FIL_SetStandardHeaderDetails( &hdr, CHARACTER_ID, CHARACTER_VERSION); fwrite( &hdr, sizeof( hdr), 1, f); fwrite( c->desc, 128, 1, f); fwrite( c->StillSpriteName, FILENAME_LEN, 1, f); fwrite( c->MovingSpriteName, FILENAME_LEN, 1, f); // weapons fwrite( &c->NumberOfWeapons, sizeof( c->NumberOfWeapons), 1, f); for( i=0; iNumberOfWeapons; ++i) { fwrite( &c->WeaponMounts[i].x, sizeof( c->WeaponMounts[i].x), 1, f); fwrite( &c->WeaponMounts[i].y, sizeof( c->WeaponMounts[i].y), 1, f); fwrite( c->WeaponMounts[i].WeaponItemName, 64, 1, f); fwrite( c->WeaponMounts[i].AmmoItemName, 64, 1, f); fwrite( c->WeaponMounts[i].HudSpriteName, FILENAME_LEN, 1, f); fwrite( c->WeaponMounts[i].WeaponFilename, FILENAME_LEN, 1, f); } // sounds fwrite( c->HurtSound, FILENAME_LEN, 1, f); fwrite( c->WastedSound, FILENAME_LEN, 1, f); // misc fwrite( &c->TerrainType, sizeof( c->TerrainType), 1, f); fwrite( &c->side, sizeof( c->side), 1, f); fwrite( &c->hp, sizeof( c->hp), 1, f); fwrite( &c->height, sizeof( c->height), 1, f); fwrite( c->FaceSpriteName, FILENAME_LEN, 1, f); fwrite( &c->ControlType, sizeof( c->ControlType), 1, f); fwrite( &c->HoverboardOffX, sizeof( c->HoverboardOffX), 1, f); fwrite( &c->HoverboardOffY, sizeof( c->HoverboardOffY), 1, f); // MP power ups fwrite( c->DropPowerUpNameMP, 64, 1, f); fwrite( c->DropPowerUpNameMP2, 64, 1, f); fclose( f); return 1; } /* Pass this function a filename from the base folder (i.e. "maps\rescue.map") and it will return the first filename found between the main base folder and the modified game folder. The first folder searched will be the modifed game folder. If the file is not found in either folders then the string will remain untouched and 0 will be returned. If it is found then the appropriate path will be added to the front of the string and 1 will be returned. */ int FIL_GetFirstFilename( char *path) { char temp[ FILENAME_LEN]; // check mod root folder if( DAT_UsingMod) { strcpy( temp, DAT_ModifiedBaseDir); JDIR_AddPath( temp, path); if( exists( temp)) { strcpy( path, temp); return 1; } } // check standard root folder strcpy( temp, PATH_ROOT); JDIR_AddPath( temp, path); if( exists( temp)) { strcpy( path, temp); return 1; } // MSG_Message("FIL_GetFirstFilename: No file found for \"%s\"", path); // file not found return 0; } /* This routine converts a full base folder filename path to a relative path, it also works if there are subfolders (like base\maps\HeadToHead\) inputs: Full Path: An absoulute path to the target file (i.e. c:\games\meteor\base\maps\HeadToHead\HH_Fortress.map) SubFolderName: The data folder in the base (i.e. maps\ or tiles\ or music\ etc) */ void FIL_RemoveBaseAndSubPath( char *FullPath, char *SubFolderName) { char PathToRoot[ FILENAME_LEN]; // * start with mod base folder if applicable) * if( DAT_UsingMod) { // start with sub folder (i.e. maps\) strcpy( PathToRoot, SubFolderName); // add mod base (i.e. MyMod\maps\) FIL_AddBasePathPrefix( PathToRoot, 1); // make root path absolute (i.e. c:\games\meteor\MyMod\maps\) fix_filename_path( PathToRoot, PathToRoot, FILENAME_LEN-1); // remove root path from the path if its found at the front if( JDIR_MakePathRelative( FullPath, PathToRoot) ) return; } // * try with standard base folder * // start with sub folder (i.e. maps\) strcpy( PathToRoot, SubFolderName); // add base (i.e. base\maps\) FIL_AddBasePathPrefix( PathToRoot, 0); // make root path absolute (i.e. c:\games\meteor\base\maps\) fix_filename_path( PathToRoot, PathToRoot, FILENAME_LEN-1); // remove root path from the path if its found at the front if( JDIR_MakePathRelative( FullPath, PathToRoot) ) return; // are we still here? If so then just remove the whole path as it must be elsewhere. JDIR_RemovePath( FullPath); }