// loads all sprites and objects etc from the base and mod folders
void FIL_LoadGameData()
{
int i;
char filename[FILENAME_LEN];
FIL_UnloadGameData();
// load wave files
AUD_LoadWaveFiles();
FIL_CreateDefaultThings();
// init items
MSG_BigMessage( BUTTON_RUN, "Initialising items");
ITEMS_Init();
// read game defs file (BEFORE DATA LOADER)
strcpy( filename, FILE_GAME_DEFS);
FIL_GetFirstFilename( filename);
MSG_Message("FIL_LoadGameData: Using game defs file %s", filename);
FIL_ReadGameInfoFile(filename,1);
//*************************************************
// *** load game data ***
// Ensure that each type of data (images, sprites etc) is entirely loaded
// before loading the next type. This is important for modded data.
// images
if( DAT_UsingMod)
FIL_LoadImages(1);
FIL_LoadImages(0);
// textures
if( DAT_UsingMod)
FIL_LoadTextures(1);
FIL_LoadTextures(0);
// sprites
if( DAT_UsingMod)
FIL_LoadSprites(1);
FIL_LoadSprites(0);
// projectiles
if( DAT_UsingMod)
FIL_LoadProjectiles(1);
FIL_LoadProjectiles(0);
// weapons
if( DAT_UsingMod)
FIL_LoadWeapons(1);
FIL_LoadWeapons(0);
// objects
if( DAT_UsingMod)
FIL_LoadObjects(1);
FIL_LoadObjects(0);
// *** end loading game data
//*************************************************
// read game defs file (AGAIN AFTER DATA LOADER)
FIL_ReadGameInfoFile(filename,0);
// set power up sprite numbers
for( i=0; i<DAT_ItemsData.PowerUpsCount; ++i)
{
DAT_ItemsData.PowerUps[i].SpriteNumber = SPR_GetSpriteNumberForName( DAT_ItemsData.PowerUps[i].SpriteName);
}
// set driver object numbers for object types
for( i=0; i<DAT_LoadedObjectTypes.count; ++i)
{
DAT_LoadedObjectTypes.objects[i].a_DefaultDriverObjectNumber = OBJED_ResolveDriverObjectName( DAT_LoadedObjectTypes.objects[i].DefaultDriverObjectName);
}
// set special numbers
DAT_GameDefs.FireSpriteNumber = SPR_GetSpriteNumberForName( "effects\\fire.spr");
DAT_GameDefs.DefaultShrapnelSpriteNumber = SPR_GetSpriteNumberForName("effects\\shrapnel.spr");
DAT_GameDefs.HitPointItemNumber = ITEMS_GetItemNumber( "Hit Point");
DAT_GameDefs.VehicleHitPointItemNumber = ITEMS_GetItemNumber( "Vehicle Hit Point");
DAT_GameDefs.GodModeItemNumber = ITEMS_GetItemNumber( "God Mode");
DAT_GameDefs.FlashlightItemNumber = ITEMS_GetItemNumber( "Flashlight");
DAT_GameDefs.HudAmmoSpriteNumber = SPR_GetSpriteNumberForName( "hud\\ammo.spr");
DAT_GameDefs.HudKillsSpriteNumber = SPR_GetSpriteNumberForName( "hud\\frags.spr");
DAT_GameDefs.PowerUpTimerSpriteNumber = SPR_GetSpriteNumberForName( "objects\\timer.spr");
DAT_GameDefs.SmokeSpriteNumber = SPR_GetSpriteNumberForName( "effects\\smoke.spr");
DAT_GameDefs.LaserDotSpriteNumber = SPR_GetSpriteNumberForName( "effects\\LaserDot.spr");
DAT_GameDefs.BulletLineImageNumber = GFX_GetImageNumForName( "effects\\BulletLine01_01.pcx");
DAT_GameDefs.LaserLineImageNumber = GFX_GetImageNumForName( "effects\\LaserLine01_01.pcx");
DAT_GameDefs.LaserLine2ImageNumber = GFX_GetImageNumForName( "effects\\LaserLine02_01.pcx");
DAT_GameDefs.HealthIconNumber_Human = SPR_GetSpriteNumberForName( "hud\\HealthIcon_Human.spr");
DAT_GameDefs.HealthIconNumber_Tank = SPR_GetSpriteNumberForName( "hud\\HealthIcon_Tank.spr");
// generate side images
GFX_GenerateSideImages();
// check for data errors (do this before loading the menu background)
DE_ScanForDataErrors();
// load menu background bitmap
MENU_LoadMenuBackdrop();
// reset weapon type id numbers
ID_ResetAllWeaponTypeIds();
GameDataLoaded = 1;
}
void FIL_LoadImages( char inUseModFolder)
{
char FullPath[FILENAME_LEN], filename[FILENAME_LEN];
TDIRLIST list;
int loaded, i;
MSG_BigMessage( BUTTON_RUN, "Loading images");
strcpy( FullPath, PATH_IMAGES);
FIL_AddBasePathPrefix( FullPath, inUseModFolder);
JDIR_CreateDirectoryList( &list, FullPath, "*.*", DIRMODE_FILES, 1);
loaded = 0;
for( i=0; i<list.count; ++i)
{
if( DAT_LoadedImages.count >= MAX_LOADED_IMAGES)
{
MSG_Message("Can not load more than %d images!", MAX_LOADED_IMAGES);
i = list.count; // break loop
}
else
{
if( list.items[i].filename != NULL)
{
// MSG_Message("Loading image from %s", list.items[i].filename);
if( !FIL_IsImageAlreadyLoaded( list.items[i].filename))
{
DAT_LoadedImages.ImageData = realloc( DAT_LoadedImages.ImageData, sizeof(TLOADED_IMAGE) * (DAT_LoadedImages.count+1) );
if( DAT_LoadedImages.ImageData == NULL)
APP_FatalError("Unable to reallocate images buffer");
strcpy( filename, list.items[i].filename);
JDIR_AddPathToFront( filename, FullPath);
if(( DAT_LoadedImages.ImageData[ DAT_LoadedImages.count].image = IO_LoadBitmap( filename)) != NULL)
{
MEM_StrAllocCopy( &DAT_LoadedImages.ImageData[ DAT_LoadedImages.count].filename, list.items[i].filename);
DAT_LoadedImages.ImageData[ DAT_LoadedImages.count ].HasSideImages = 0;
DAT_LoadedImages.count++;
loaded ++;
// MSG_Message("Loaded image from %s, number = %d", filename, DAT_LoadedImages.count-1);
}
else
MSG_Message("Error Loading image from %s", filename);
}
}
}
}
JDIR_DestroyDirectoryList( &list);
MSG_Message("Loaded %d images(s) from \"%s\"", loaded, FullPath);
}
void FIL_LoadTextures( char inUseModFolder)
{
char FullPath[FILENAME_LEN], filename[FILENAME_LEN];
TDIRLIST list;
int loaded, i;
BITMAP *TempMinimapBitmap;
MSG_BigMessage( BUTTON_RUN, "Loading textures");
TempMinimapBitmap = MISC_NewBitmap( 1, 1);
sprintf( FullPath, "%s", PATH_TEXTURES);
FIL_AddBasePathPrefix( FullPath, inUseModFolder);
JDIR_CreateDirectoryList( &list, FullPath, "*.*", DIRMODE_FILES, 1);
loaded = 0;
for( i=0; i<list.count; ++i)
{
if( DAT_LoadedTextures.count >= MAX_LOADED_TEXTURES)
{
MSG_Message("Can not load more than %d textures!", MAX_LOADED_TEXTURES);
i = list.count; // break loop
}
else
{
if( list.items[i].filename != NULL)
{
strcpy( filename, JDIR_GetFilenameForNumber( &list, i) );
if( filename != NULL)
{
if( !MISC_DoesStringExistInArray( list.items[i].filename, DAT_LoadedTextures.names, DAT_LoadedTextures.count))
{
// store full path filename
strcpy( filename, list.items[i].filename);
JDIR_AddPathToFront( filename, FullPath);
MEM_StrAllocCopy( &DAT_LoadedTextures.TextureData[ DAT_LoadedTextures.count].FullPathFilename, filename);
// store filename (no path)
MEM_StrAllocCopy( &DAT_LoadedTextures.names[ DAT_LoadedTextures.count], list.items[i].filename);
// set unloaded texture image
TEX_SetDefaultTextureImage( DAT_LoadedTextures.count);
DAT_LoadedTextures.TextureData[ DAT_LoadedTextures.count].loaded = 0;
DAT_LoadedTextures.count++;
loaded ++;
}
}
}
}
}
JDIR_DestroyDirectoryList( &list);
MSG_Message("Loaded %d textures(s) from \"%s\"", loaded, FullPath);
}
void FIL_LoadSprites( char inUseModFolder)
{
char FullPath[FILENAME_LEN], filename[FILENAME_LEN];
TDIRLIST list;
int loaded, i;
MSG_BigMessage( BUTTON_RUN, "Loading sprites");
strcpy( FullPath, PATH_SPRITES);
FIL_AddBasePathPrefix( FullPath, inUseModFolder);
JDIR_CreateDirectoryList( &list, FullPath, "*.*", DIRMODE_FILES, 1);
loaded = 0;
for( i=0; i<list.count; ++i)
{
if( DAT_LoadedSprites.count>=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))
{
#ifdef DEBUG_MODE
MSG_Message("Loading sprite from %s", list.items[i].filename);
#endif
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 ++;
}
#ifdef DEBUG_MODE
MSG_Message("Done loading sprite");
#endif
}
}
}
}
JDIR_DestroyDirectoryList( &list);
MSG_Message("Loaded %d sprite(s) from \"%s\"", loaded, FullPath);
}
void FIL_LoadProjectiles( char inUseModFolder)
{
char FullPath[FILENAME_LEN], filename[FILENAME_LEN];
TDIRLIST list;
int loaded, i;
MSG_BigMessage( BUTTON_RUN, "Loading projectiles");
strcpy( FullPath, PATH_PROJECTILES);
FIL_AddBasePathPrefix( FullPath, inUseModFolder);
JDIR_CreateDirectoryList( &list, FullPath, "*.*", DIRMODE_FILES, 1);
loaded = 0;
for( i=0; i<list.count; ++i)
{
if( DAT_LoadedProjectiles.count>=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 ++;
}
}
}
}
}
JDIR_DestroyDirectoryList( &list);
MSG_Message("Loaded %d projectile(s) from \"%s\"", loaded, FullPath);
}
void FIL_LoadWeapons( char inUseModFolder)
{
char FullPath[FILENAME_LEN], filename[FILENAME_LEN];
TDIRLIST list;
int loaded, i;
MSG_BigMessage( BUTTON_RUN, "Loading weapons");
strcpy( FullPath, PATH_WEAPONS);
FIL_AddBasePathPrefix( FullPath, inUseModFolder);
JDIR_CreateDirectoryList( &list, FullPath, "*.*", DIRMODE_FILES, 1);
loaded = 0;
for( i=0; i<list.count; ++i)
{
if( DAT_LoadedWeapons.count >= 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], 0))
{
MEM_StrAllocCopy( &DAT_LoadedWeapons.names[ DAT_LoadedWeapons.count], list.items[i].filename);
DAT_LoadedWeapons.count++;
loaded ++;
}
}
}
}
}
JDIR_DestroyDirectoryList( &list);
MSG_Message("Loaded %d weapons(s) from \"%s\"", loaded, FullPath);
}
void FIL_LoadObjects( char inUseModFolder)
{
char FullPath[FILENAME_LEN], filename[FILENAME_LEN];
TDIRLIST list;
int loaded, i;
MSG_BigMessage( BUTTON_RUN, "Loading objects");
strcpy( FullPath, PATH_OBJECTS);
FIL_AddBasePathPrefix( FullPath, inUseModFolder);
JDIR_CreateDirectoryList( &list, FullPath, "*.*", DIRMODE_FILES, 1);
loaded = 0;
for( i=0; i<list.count; ++i)
{
if( DAT_LoadedWeapons.count >= MAX_OBJECT_TYPES)
{
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_LoadedObjectTypes.names, DAT_LoadedObjectTypes.count))
{
strcpy( filename, list.items[i].filename);
JDIR_AddPathToFront( filename, FullPath);
if( FIL_ReadObjectFile( filename, &DAT_LoadedObjectTypes.objects[ DAT_LoadedObjectTypes.count], 0))
{
MEM_StrAllocCopy( &DAT_LoadedObjectTypes.names[ DAT_LoadedObjectTypes.count], list.items[i].filename);
DAT_LoadedObjectTypes.count++;
loaded ++;
}
}
}
}
}
JDIR_DestroyDirectoryList( &list);
MSG_Message("Loaded %d objects(s) from \"%s\"", loaded, FullPath);
}
int FIL_ReadSpriteFile( char *filename, TSPRITE *s, int inDestroyCurrent)
{
int i;
char TempBuf[2];
TSTANDARD_FILE_HEADER hdr;
FILE *f;
if( !FIL_OpenFile( &f, filename, "rb"))
return 0;
#ifdef DEBUG_MODE
MSG_Message("FIL_ReadSpriteFile: Reading sprite from %s", filename);
#endif
// check for old ini sprite format
fread( TempBuf, 1, 1, f);
fseek( f, 0, 0);
if( TempBuf[0] != SPRITE_ID[0])
{
// ** old ini sprite file format **
// reopen as text/ini
fclose(f);
if( !FIL_OpenFile( &f, filename, "r"))
return 0;
if( !IOL_ReadOldSpriteFile( f, s, inDestroyCurrent, filename))
return 0;
}
else
{
// ** newer binary format **
// read and check header
fread( &hdr, sizeof(hdr), 1, f);
if( !JG_CheckFileHeader( &hdr, SPRITE_ID, SPRITE_VERSION, filename, 0, 0))
{
MSG_Message("%s: Bad file version", filename);
fclose(f);
return 0;
}
// destroy current?
if( inDestroyCurrent)
SB_DestroySprite( s);
// read basic info
JG_ReadString( f, s->name);
JG_ReadByte( f, &s->NumFrames);
JG_ReadByte( f, &s->NumSubs);
JG_ReadByte( f, &s->NumLights);
JG_ReadString( f, s->LoopSoundName);
s->a_LoopSoundNumber = AUD_GetSoundNumberForName( s->LoopSoundName);
// check frame count is not too high
if( s->NumFrames > MAX_SPRITE_FRAMES)
{
fclose(f);
APP_FatalError("FIL_ReadSpriteFile: %s, frame count exceeds %d", filename, MAX_SPRITE_FRAMES);
}
// set currrent frame
s->a_CurrentFrame = 0;
// read frames
for( i=0; i< s->NumFrames; ++i)
{
JG_ReadInt( f, &s->frames[i].DisplayTime);
JG_ReadString( f, s->frames[i].ImageName);
s->frames[i].a_ImageNumber = GFX_GetImageNumForName( s->frames[i].ImageName);
JG_ReadString( f, s->frames[i].SoundName);
// calc
s->frames[i].a_SoundNumber = AUD_GetSoundNumberForName(s->frames[i].SoundName);
}
// read subs
for( i=0; i<s->NumSubs; ++i)
{
JG_ReadString( f, s->subs[i].name);
JG_ReadInt( f, &s->subs[i].xp);
JG_ReadInt( f, &s->subs[i].yp);
JG_ReadInt( f, &s->subs[i].rotate);
JG_ReadString( f, s->subs[i].ImageName);
s->subs[i].a_ImageNumber = GFX_GetImageNumForName( s->subs[i].ImageName);
}
// read lights
for( i=0; i<s->NumLights; ++i)
{
LT_ReadLightObjectFromBinaryFile( f, &s->lights[i].light);
JG_ReadInt( f, &s->lights[i].x);
JG_ReadInt( f, &s->lights[i].y);
// allocate light object
LT_InitLightObject( &s->lights[i].light, 0);
}
fclose( f);
}
// create RID for this sprite (based on 1st frame)
JG_CreateRotatedImageData( &s->rid, DAT_LoadedImages.ImageData[ s->frames[ 0].a_ImageNumber].image, 1);
// do calc stuff for subs
for( i=0; i<s->NumSubs; ++i)
{
// MSG_Message("Creating RID for sub %d", i);
JG_CreateRotatedImageData( &s->subs[i].rid, M_SPRITE_SUB_BITMAP(s, i), 1);
// MSG_Message("Creating rotated offsets for sub %d", i);
s->subs[i].RotatedOffsetsAllocated = 0;
SUB_UpdateSubRotatedOffsets( s, i);
// MSG_Message("Done with sub %d", i);
}
// do calc stuff for lights
for( i=0; i<s->NumLights; ++i)
{
// create and update rotated offsets
s->lights[i].RotatedOffsetsAllocated = 0;
SB_UpdateRotatedLightOffsets( s, i);
}
// clear sprite's default animation data
SPR_ResetAnimationData( &s->DefaultAnimationData);
#ifdef DEBUG_MODE
MSG_Message("FIL_ReadSpriteFile: Loaded sprite from %s", filename);
#endif
return 1;
}
int FIL_WriteSpriteFile( char *filename, TSPRITE *s)
{
int i;
FILE *f;
TSTANDARD_FILE_HEADER hdr;
if( !FIL_OpenFile( &f, filename, "wb"))
return 0;
JG_SetStandardFileHeaderDetails( &hdr, SPRITE_ID, SPRITE_VERSION);
fwrite( &hdr, sizeof(hdr), 1, f);
JG_WriteString( f, s->name);
JG_WriteByte( f, s->NumFrames);
JG_WriteByte( f, s->NumSubs);
JG_WriteByte( f, s->NumLights);
JG_WriteString( f, s->LoopSoundName);
// write frames
for( i=0; i< s->NumFrames; ++i)
{
JG_WriteInt( f, s->frames[i].DisplayTime);
JG_WriteString( f, s->frames[i].ImageName);
JG_WriteString( f, s->frames[i].SoundName);
}
// write subs
for( i=0; i<s->NumSubs; ++i)
{
JG_WriteString( f, s->subs[i].name);
JG_WriteInt( f, s->subs[i].xp);
JG_WriteInt( f, s->subs[i].yp);
JG_WriteInt( f, s->subs[i].rotate);
JG_WriteString( f, s->subs[i].ImageName);
}
// write lights
for( i=0; i<s->NumLights; ++i)
{
LT_WriteLightObjectToBinaryFile( f, &s->lights[i].light);
JG_WriteInt( f, s->lights[i].x);
JG_WriteInt( f, s->lights[i].y);
}
fclose( f);
return 1;
}
int FIL_ReadObjectFile( char *filename, TOBJECT_TYPE *r, int inDestroyCurrent)
{
FILE *f;
int i, a;
double bear, dist, TraceX, TraceY;
double cx, cy, MountCentreX, MountCentreY;
unsigned char TraceBearing;
char section[ 32];
if( !FIL_OpenFile( &f, filename, "r"))
return 0;
if( !FIL_CheckINIFileHeader( f, OBJECT_ID, OBJECT_VERSION, filename))
{
fclose( f);
return 0;
}
if( inDestroyCurrent)
OBJED_DestroyObject( r);
strcpy( section, "info");
strcpy( r->desc, JINI_ReadString( f, section, "desc", NONE));
r->ObjectClass = JINI_ReadInt( f, section, "ObjectClass", OC_INFANTRY);
r->hp = JINI_ReadInt( f, section, "hp", 20);
r->ArmourResist = JINI_ReadInt( f, section, "ArmourResist", 0);
r->sight = JINI_ReadInt( f, section, "sight", 20);
r->speed = JINI_ReadInt( f, section, "speed.AmountToMove", 4);
r->MaxHeight = JINI_ReadInt( f, section, "MaxHeight", 15);
r->vehicle = JINI_ReadByte( f, section, "vehicle", 0);
r->WeaponsRotate = JINI_ReadByte( f, section, "WeaponsRotate", 0);
r->AllowShadow = JINI_ReadByte( f, section, "AllowShadow", 1);
r->WhiteColourSwapOnly = JINI_ReadByte( f, section, "WhiteColourSwapOnly", 1);
r->explodes = JINI_ReadByte( f, section, "explodes", 0);
r->ExplodeRadius = JINI_ReadInt( f, section, "ExplodeRadius", 40);
r->ExplodeDamage = JINI_ReadInt( f, section, "ExplodeDamage", 60);
r->DefaultAiType = JINI_ReadInt( f, section, "DefaultAiType", AI_ROAMING);
r->organic = JINI_ReadByte( f, section, "organic", 0);
r->RunDown = JINI_ReadByte( f, section, "RunDown", 1);
r->IsMechanic = JINI_ReadByte( f, section, "IsMechanic", 0);
r->IsMedic = JINI_ReadByte( f, section, "IsMedic", 0);
strcpy( r->StillSpriteName, JINI_ReadString( f, section, "StillSpriteName", ""));
strcpy( r->MovingSpriteName, JINI_ReadString( f, section, "MovingSpriteName", ""));
strcpy( r->WastedSpriteName, JINI_ReadString( f, section, "WastedSpriteName", ""));
r->HasFixedLaser = JINI_ReadByte( f, section, "HasFixedLaser", 0);
r->FixedLaserColour.r = JINI_ReadByte( f, section, "FixedLaserColour.r", 255);
r->FixedLaserColour.g = JINI_ReadByte( f, section, "FixedLaserColour.g", 0);
r->FixedLaserColour.b = JINI_ReadByte( f, section, "FixedLaserColour.b", 0);
strcpy( r->RandomSoundName, JINI_ReadString( f, section, "RandomSoundName", NOSOUND));
strcpy( r->DestroyedSoundName, JINI_ReadString( f, section, "DestroyedSoundName", NOSOUND));
strcpy( r->HooterSoundName, JINI_ReadString( f, section, "HooterSoundName", SOUND_VEHICLE_HOOTER));
strcpy( r->HurtSoundName, JINI_ReadString( f, section, "HurtSoundName", NOSOUND));
strcpy( r->EnterSoundName, JINI_ReadString( f, section, "EnterSoundName", SOUND_VEHICLE_IN));
strcpy( r->ExitSoundName, JINI_ReadString( f, section, "ExitSoundName", SOUND_VEHICLE_OUT));
strcpy( r->DefaultDriverObjectName, JINI_ReadString( f, section, "DefaultDriverObjectName", DAT_GameDefs.DefaultDriverObject) );
r->DefaultCrewCount = JINI_ReadInt( f, section, "DefaultCrewCount", 1);
strcpy( r->DropPowerUpName, JINI_ReadString( f, section, "DropPowerUpName", ""));
strcpy( r->DropPowerUpName2, JINI_ReadString( f, section, "DropPowerUpName2", ""));
strcpy( r->DropPowerUpNameMP, JINI_ReadString( f, section, "DropPowerUpNameMP", ""));
r->NumMounts = JINI_ReadInt( f, section, "NumMounts", 0);
// * do offsets before setting weapon mounts! *
// calc data
r->a_StillSpriteNumber = SPR_GetSpriteNumberForName( r->StillSpriteName);
r->a_MovingSpriteNumber = SPR_GetSpriteNumberForName( r->MovingSpriteName);
// DO NOT STORE DefaultDriverObjectNumber HERE AS ALL OBJECTS MAY NOT BE LOADED
if( strlen( r->WastedSpriteName) < 1)
r->a_WastedSpriteNumber = -1;
else
{
r->a_WastedSpriteNumber = SPR_GetSpriteNumberForName( r->WastedSpriteName);
}
// read weapon mounts
r->a_HasLaser = 0;
for( i=0; i<r->NumMounts; ++i)
{
sprintf( section, "WeaponMount%d", i);
r->WeaponMounts[i].x = JINI_ReadInt( f, section, "x", 0);
r->WeaponMounts[i].y = JINI_ReadInt( f, section, "y", 0);
strcpy( r->WeaponMounts[i].WeaponName, JINI_ReadString( f, section, "WeaponName", ""));
// set weapon number
r->WeaponMounts[i].a_WeaponNumber = WED_GetWeaponNumberForName( r->WeaponMounts[i].WeaponName);
if( !r->a_HasLaser)
r->a_HasLaser = DAT_LoadedWeapons.weapons[ r->WeaponMounts[i].a_WeaponNumber].HasLaser;
// create/update weapon draw offsets
OBJED_UpdateWeaponMountOffsets( r, i);
// *************************************************************
// ** calculate firing point offsets **
// * calculate mount centre offsets *
// this is the arc that the centre of the mount travels along when the object rotates
// get the coords of the centre of the object's canvas
cx = M_OBJECT_PTR_STILL_IMAGE( r)->w /2;
cy = M_OBJECT_PTR_STILL_IMAGE( r)->h /2;
// get the mount centre pos on the object (add offsets and half width/height)
MountCentreX = r->WeaponMounts[i].x + ( M_SPRITEN_W( DAT_LoadedWeapons.weapons[ r->WeaponMounts[ i].a_WeaponNumber].SpriteNumber, 0) / 2);
MountCentreY = r->WeaponMounts[i].y + ( M_SPRITEN_H( DAT_LoadedWeapons.weapons[ r->WeaponMounts[ i].a_WeaponNumber].SpriteNumber, 0) / 2);
// get the bearing from the canvas centre to the mount centre
bear = JG_GetBearing( cx, cy, MountCentreX, MountCentreY);
// and the distance
dist = JG_GetDistanceBetweenPoints( cx, cy, MountCentreX, MountCentreY);
// trace from the centre at 1 degree intervals to buld arc offsets
for( a=0; a<256; ++a)
{
TraceX = cx;
TraceY = cy;
// rotate bearing
TraceBearing = bear + a;
// trace the offsets from centre on the rotated bearing
JG_MoveForwardOnPlane( &TraceX, &TraceY, TraceBearing, dist);
// assign new values as offsets (simply add to objects coords for the real coords)
r->WeaponMounts[ i].MountCentreOffsetsX[a] = TraceX;
r->WeaponMounts[ i].MountCentreOffsetsY[a] = TraceY;
}
// *************************************************************
// ** calculate firing point offsets (from mount centre) **
// get the centre of the mount bitmap (half width/height)
MountCentreX = M_SPRITEN_W( DAT_LoadedWeapons.weapons[ r->WeaponMounts[ i].a_WeaponNumber].SpriteNumber, 0) / 2;
MountCentreY = M_SPRITEN_H( DAT_LoadedWeapons.weapons[ r->WeaponMounts[ i].a_WeaponNumber].SpriteNumber, 0) / 2;
// get the bearing from the mount's centre to the firing coords
bear = JG_GetBearing(
MountCentreX, MountCentreY,
DAT_LoadedWeapons.weapons[ r->WeaponMounts[ i].a_WeaponNumber].FireX,
DAT_LoadedWeapons.weapons[ r->WeaponMounts[ i].a_WeaponNumber].FireY);
// and the distance
dist = JG_GetDistanceBetweenPoints(
MountCentreX, MountCentreY,
DAT_LoadedWeapons.weapons[ r->WeaponMounts[ i].a_WeaponNumber].FireX,
DAT_LoadedWeapons.weapons[ r->WeaponMounts[ i].a_WeaponNumber].FireY);
// trace from the mount centre at 1 degree intervals to buld firing pos offsets
for( a=0; a<256; ++a)
{
TraceX = MountCentreX;
TraceY = MountCentreY;
// rotate bearing
TraceBearing = bear + a;
// trace the offsets from centre on the rotated bearing
JG_MoveForwardOnPlane( &TraceX, &TraceY, TraceBearing, dist);
// assign new values as offsets (simply add to objects coords for the real coords)
r->WeaponMounts[ i].MountCentreToFirePosOffsetsX[a] = TraceX - MountCentreX;
r->WeaponMounts[ i].MountCentreToFirePosOffsetsY[a] = TraceY - MountCentreY;
}
}
fclose( f);
// validate ObjectClass
if( (r->ObjectClass < 0) || ( r->ObjectClass >= NUM_OBJECT_CLASSES) )
r->ObjectClass = OC_INFANTRY;
// validate vehicle
if( (r->vehicle < 0) || (r->vehicle >= NUM_VEHICLE_TYPES) )
r->vehicle = VT_NONE;
// validate crew count
if( r->DefaultCrewCount < 0)
r->DefaultCrewCount = 0;
// calc sound names
r->a_DestroyedSoundNumber = AUD_GetSoundNumberForName( r->DestroyedSoundName);
r->a_RandomSoundNumber = AUD_GetSoundNumberForName( r->RandomSoundName);
r->a_HooterSoundNumber = AUD_GetSoundNumberForName( r->HooterSoundName);
r->a_HurtSoundNumber = AUD_GetSoundNumberForName( r->HurtSoundName);
r->a_EnterSoundNumber = AUD_GetSoundNumberForName( r->EnterSoundName);
r->a_ExitSoundNumber = AUD_GetSoundNumberForName( r->ExitSoundName);
return 1;
}