codemp/game/bg_vehicleLoad.c

Go to the documentation of this file.
00001 //bg_vehicleLoad.c
00002 
00003 #ifdef _JK2 //SP does not have this preprocessor for game like MP does
00004 #ifndef _JK2MP
00005 #define _JK2MP
00006 #endif
00007 #endif
00008 
00009 #ifdef _JK2MP
00010         #include "q_shared.h"
00011         #include "bg_public.h"
00012         #include "bg_vehicles.h"
00013         #include "bg_weapons.h"
00014 
00015         //Could use strap stuff but I don't particularly care at the moment anyway.
00016 #include "../namespace_begin.h"
00017         extern int      trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
00018         extern void     trap_FS_Read( void *buffer, int len, fileHandle_t f );
00019         extern void     trap_FS_Write( const void *buffer, int len, fileHandle_t f );
00020         extern void     trap_FS_FCloseFile( fileHandle_t f );
00021         extern int      trap_FS_GetFileList(  const char *path, const char *extension, char *listbuf, int bufsize );
00022 #include "../namespace_end.h"
00023 #else
00024         #include "g_local.h"
00025         #define QAGAME
00026 #endif
00027 
00028 
00029 #ifdef _JK2MP
00030 #ifndef QAGAME
00031 #ifndef CGAME
00032 #define WE_ARE_IN_THE_UI
00033 #include "../ui/ui_local.h"
00034 #endif
00035 #endif
00036 #endif
00037 
00038 #ifndef _JK2MP
00039 #include "..\Ratl\string_vs.h"
00040 #endif
00041 
00042 #ifdef QAGAME
00043 extern void G_SetSharedVehicleFunctions( vehicleInfo_t *pVehInfo );
00044 extern int G_ModelIndex( const char *name );
00045 extern int G_SoundIndex( const char *name );
00046         #ifdef _JK2MP
00047                 extern int G_EffectIndex( const char *name );
00048         #endif
00049 #elif CGAME
00050 #include "../namespace_begin.h"
00051 extern qhandle_t        trap_R_RegisterModel( const char *name );                       // returns rgb axis if not found
00052 extern qhandle_t        trap_R_RegisterSkin( const char *name );                        // returns all white if not found
00053 extern qhandle_t        trap_R_RegisterShader( const char *name );
00054 extern qhandle_t        trap_R_RegisterShaderNoMip( const char *name );
00055 extern int                      trap_FX_RegisterEffect(const char *file);
00056 extern sfxHandle_t      trap_S_RegisterSound( const char *sample);              // returns buzz if not found
00057 #include "../namespace_end.h"
00058 #else//UI
00059 #include "../namespace_begin.h"
00060 extern qhandle_t        trap_R_RegisterModel( const char *name );                       // returns rgb axis if not found
00061 extern qhandle_t        trap_R_RegisterSkin( const char *name );                        // returns all white if not found
00062 extern qhandle_t        trap_R_RegisterShader( const char *name );                      // returns all white if not found
00063 extern qhandle_t        trap_R_RegisterShaderNoMip( const char *name );                 // returns all white if not found
00064 extern sfxHandle_t      trap_S_RegisterSound( const char *sample);              // returns buzz if not found
00065 #include "../namespace_end.h"
00066 #endif
00067 
00068 extern stringID_table_t animTable [MAX_ANIMATIONS+1];
00069 
00070 // These buffers are filled in with the same contents and then just read from in
00071 // a few places. We only need one copy on Xbox.
00072 #define MAX_VEH_WEAPON_DATA_SIZE 0x4000
00073 #define MAX_VEHICLE_DATA_SIZE 0x10000
00074 
00075 #if !defined(_XBOX) || defined(QAGAME)
00076         char    VehWeaponParms[MAX_VEH_WEAPON_DATA_SIZE];
00077         char    VehicleParms[MAX_VEHICLE_DATA_SIZE];
00078 
00079 void BG_ClearVehicleParseParms(void)
00080 {
00081         //You can't strcat to these forever without clearing them!
00082         VehWeaponParms[0] = 0;
00083         VehicleParms[0] = 0;
00084 }
00085 
00086 #else
00087         extern char VehWeaponParms[MAX_VEH_WEAPON_DATA_SIZE];
00088         extern char VehicleParms[MAX_VEHICLE_DATA_SIZE];
00089 #endif
00090 
00091 #ifdef _JK2MP
00092 #include "../namespace_begin.h"
00093 #endif
00094 
00095 #ifndef WE_ARE_IN_THE_UI
00096 //These funcs are actually shared in both projects
00097 extern void G_SetAnimalVehicleFunctions( vehicleInfo_t *pVehInfo );
00098 extern void G_SetSpeederVehicleFunctions( vehicleInfo_t *pVehInfo );
00099 extern void G_SetWalkerVehicleFunctions( vehicleInfo_t *pVehInfo );
00100 extern void G_SetFighterVehicleFunctions( vehicleInfo_t *pVehInfo );
00101 #endif
00102 
00103 vehWeaponInfo_t g_vehWeaponInfo[MAX_VEH_WEAPONS];
00104 int             numVehicleWeapons = 1;//first one is null/default
00105 
00106 vehicleInfo_t g_vehicleInfo[MAX_VEHICLES];
00107 int             numVehicles = 0;//first one is null/default
00108 
00109 void BG_VehicleLoadParms( void );
00110 
00111 typedef enum {
00112         VF_IGNORE,
00113         VF_INT,
00114         VF_FLOAT,
00115         VF_LSTRING,     // string on disk, pointer in memory, TAG_LEVEL
00116         VF_VECTOR,
00117         VF_BOOL,
00118         VF_VEHTYPE,
00119         VF_ANIM,
00120         VF_WEAPON,      // take string, resolve into index into VehWeaponParms
00121         VF_MODEL,       // take the string, get the G_ModelIndex
00122         VF_MODEL_CLIENT,        // (cgame only) take the string, get the G_ModelIndex
00123         VF_EFFECT,      // take the string, get the G_EffectIndex
00124         VF_EFFECT_CLIENT,       // (cgame only) take the string, get the index
00125         VF_SHADER,      // (cgame only) take the string, call trap_R_RegisterShader
00126         VF_SHADER_NOMIP,// (cgame only) take the string, call trap_R_RegisterShaderNoMip
00127         VF_SOUND,       // take the string, get the G_SoundIndex
00128         VF_SOUND_CLIENT // (cgame only) take the string, get the index
00129 } vehFieldType_t;
00130 
00131 typedef struct
00132 {
00133         char    *name;
00134         int             ofs;
00135         vehFieldType_t  type;
00136 } vehField_t;
00137 
00138 vehField_t vehWeaponFields[NUM_VWEAP_PARMS] = 
00139 {
00140         {"name", VWFOFS(name), VF_LSTRING},     //unique name of the vehicle
00141         {"projectile", VWFOFS(bIsProjectile), VF_BOOL}, //traceline or entity?
00142         {"hasGravity", VWFOFS(bHasGravity), VF_BOOL},   //if a projectile, drops
00143         {"ionWeapon", VWFOFS(bIonWeapon), VF_BOOL},     //disables ship shields and sends them out of control
00144         {"saberBlockable", VWFOFS(bSaberBlockable), VF_BOOL},   //lightsabers can deflect this projectile
00145         {"muzzleFX", VWFOFS(iMuzzleFX), VF_EFFECT_CLIENT},      //index of Muzzle Effect
00146         {"model", VWFOFS(iModel), VF_MODEL_CLIENT},     //handle to the model used by this projectile
00147         {"shotFX", VWFOFS(iShotFX), VF_EFFECT_CLIENT},  //index of Shot Effect
00148         {"impactFX", VWFOFS(iImpactFX), VF_EFFECT_CLIENT},      //index of Impact Effect
00149         {"g2MarkShader", VWFOFS(iG2MarkShaderHandle), VF_SHADER},       //index of shader to use for G2 marks made on other models when hit by this projectile
00150         {"g2MarkSize", VWFOFS(fG2MarkSize), VF_FLOAT},  //size (diameter) of the ghoul2 mark
00151         {"loopSound", VWFOFS(iLoopSound), VF_SOUND_CLIENT},     //index of loopSound
00152         {"speed", VWFOFS(fSpeed), VF_FLOAT},            //speed of projectile/range of traceline
00153         {"homing", VWFOFS(fHoming), VF_FLOAT},          //0.0 = not homing, 0.5 = half vel to targ, half cur vel, 1.0 = all vel to targ
00154         {"homingFOV", VWFOFS(fHomingFOV), VF_FLOAT},//missile will lose lock on if DotProduct of missile direction and direction to target ever drops below this (-1 to 1, -1 = never lose target, 0 = lose if ship gets behind missile, 1 = pretty much will lose it's target right away)
00155         {"lockOnTime", VWFOFS(iLockOnTime), VF_INT},    //0 = no lock time needed, else # of ms needed to lock on
00156         {"damage", VWFOFS(iDamage), VF_INT},            //damage done when traceline or projectile directly hits target
00157         {"splashDamage", VWFOFS(iSplashDamage), VF_INT},//damage done to ents in splashRadius of end of traceline or projectile origin on impact
00158         {"splashRadius", VWFOFS(fSplashRadius), VF_FLOAT},//radius that ent must be in to take splashDamage (linear fall-off)
00159         {"ammoPerShot", VWFOFS(iAmmoPerShot), VF_INT},//how much "ammo" each shot takes
00160         {"health", VWFOFS(iHealth), VF_INT},            //if non-zero, projectile can be shot, takes this much damage before being destroyed
00161         {"width", VWFOFS(fWidth), VF_FLOAT},            //width of traceline or bounding box of projecile (non-rotating!)
00162         {"height", VWFOFS(fHeight), VF_FLOAT},          //height of traceline or bounding box of projecile (non-rotating!)
00163         {"lifetime", VWFOFS(iLifeTime), VF_INT},        //removes itself after this amount of time
00164         {"explodeOnExpire", VWFOFS(bExplodeOnExpire), VF_BOOL}, //when iLifeTime is up, explodes rather than simply removing itself
00165 };
00166 
00167 static qboolean BG_ParseVehWeaponParm( vehWeaponInfo_t *vehWeapon, char *parmName, char *pValue )
00168 {
00169         int             i;
00170         vec3_t  vec;
00171         byte    *b = (byte *)vehWeapon;
00172         int             _iFieldsRead = 0;
00173         vehicleType_t vehType;
00174         char    value[1024];
00175 
00176         Q_strncpyz( value, pValue, sizeof(value) );
00177 
00178         // Loop through possible parameters
00179         for ( i = 0; i < NUM_VWEAP_PARMS; i++ )
00180         {
00181                 if ( vehWeaponFields[i].name && !Q_stricmp( vehWeaponFields[i].name, parmName ) )
00182                 {
00183                         // found it
00184                         switch( vehWeaponFields[i].type ) 
00185                         {
00186                         case VF_INT:
00187                                 *(int *)(b+vehWeaponFields[i].ofs) = atoi(value);
00188                                 break;
00189                         case VF_FLOAT:
00190                                 *(float *)(b+vehWeaponFields[i].ofs) = atof(value);
00191                                 break;
00192                         case VF_LSTRING:        // string on disk, pointer in memory, TAG_LEVEL
00193                                 if (!*(char **)(b+vehWeaponFields[i].ofs))
00194                                 { //just use 1024 bytes in case we want to write over the string
00195 #ifdef _JK2MP
00196                                         *(char **)(b+vehWeaponFields[i].ofs) = (char *)BG_Alloc(1024);//(char *)BG_Alloc(strlen(value));
00197                                         strcpy(*(char **)(b+vehWeaponFields[i].ofs), value);
00198 #else
00199                                         (*(char **)(b+vehWeaponFields[i].ofs)) = G_NewString( value );
00200 #endif
00201                                 }
00202                                 
00203                                 break;
00204                         case VF_VECTOR:
00205                                 _iFieldsRead = sscanf (value, "%f %f %f", &vec[0], &vec[1], &vec[2]);
00206                                 assert(_iFieldsRead==3 );
00207                                 if (_iFieldsRead!=3)
00208                                 {
00209                                         Com_Printf (S_COLOR_YELLOW"BG_ParseVehWeaponParm: VEC3 sscanf() failed to read 3 floats ('angle' key bug?)\n");
00210                                 }
00211                                 ((float *)(b+vehWeaponFields[i].ofs))[0] = vec[0];
00212                                 ((float *)(b+vehWeaponFields[i].ofs))[1] = vec[1];
00213                                 ((float *)(b+vehWeaponFields[i].ofs))[2] = vec[2];
00214                                 break;
00215                         case VF_BOOL:
00216                                 *(qboolean *)(b+vehWeaponFields[i].ofs) = (qboolean)(atof(value)!=0);
00217                                 break;
00218                         case VF_VEHTYPE:
00219                                 vehType = (vehicleType_t)GetIDForString( VehicleTable, value );
00220                                 *(vehicleType_t *)(b+vehWeaponFields[i].ofs) = vehType;
00221                                 break;
00222                         case VF_ANIM:
00223                                 {
00224                                         int anim = GetIDForString( animTable, value );
00225                                         *(int *)(b+vehWeaponFields[i].ofs) = anim;
00226                                 }
00227                                 break;
00228                         case VF_WEAPON: // take string, resolve into index into VehWeaponParms
00229                                 //*(int *)(b+vehWeaponFields[i].ofs) = VEH_VehWeaponIndexForName( value );
00230                                 break;
00231                         case VF_MODEL:// take the string, get the G_ModelIndex
00232 #ifdef QAGAME
00233                                 *(int *)(b+vehWeaponFields[i].ofs) = G_ModelIndex( value );
00234 #else
00235                                 *(int *)(b+vehWeaponFields[i].ofs) = trap_R_RegisterModel( value );
00236 #endif
00237                                 break;
00238                         case VF_MODEL_CLIENT:   // (MP cgame only) take the string, get the G_ModelIndex
00239 #ifndef _JK2MP
00240                                 *(int *)(b+vehWeaponFields[i].ofs) = G_ModelIndex( value );
00241 #elif QAGAME
00242                                 //*(int *)(b+vehWeaponFields[i].ofs) = G_ModelIndex( value );
00243 #else
00244                                 *(int *)(b+vehWeaponFields[i].ofs) = trap_R_RegisterModel( value );
00245 #endif
00246                                 break;
00247                         case VF_EFFECT: // take the string, get the G_EffectIndex
00248 #ifdef QAGAME
00249                                 *(int *)(b+vehWeaponFields[i].ofs) = G_EffectIndex( value );
00250 #elif CGAME
00251                                 *(int *)(b+vehWeaponFields[i].ofs) = trap_FX_RegisterEffect( value );
00252 #endif
00253                                 break;
00254                         case VF_EFFECT_CLIENT:  // (MP cgame only) take the string, get the index
00255 #ifndef _JK2MP
00256                                 *(int *)(b+vehWeaponFields[i].ofs) = G_EffectIndex( value );
00257 #elif QAGAME
00258                                 //*(int *)(b+vehWeaponFields[i].ofs) = G_EffectIndex( value );
00259 #elif CGAME
00260                                 *(int *)(b+vehWeaponFields[i].ofs) = trap_FX_RegisterEffect( value );
00261 #endif
00262                                 break;
00263                         case VF_SHADER: // (cgame only) take the string, call trap_R_RegisterShader
00264 #ifdef WE_ARE_IN_THE_UI
00265                                 *(int *)(b+vehWeaponFields[i].ofs) = trap_R_RegisterShaderNoMip( value );
00266 #elif CGAME
00267                                 *(int *)(b+vehWeaponFields[i].ofs) = trap_R_RegisterShader( value );
00268 #endif
00269                                 break;
00270                         case VF_SHADER_NOMIP:// (cgame only) take the string, call trap_R_RegisterShaderNoMip
00271 #ifndef QAGAME
00272                                 *(int *)(b+vehWeaponFields[i].ofs) = trap_R_RegisterShaderNoMip( value );
00273 #endif
00274                                 break;
00275                         case VF_SOUND:  // take the string, get the G_SoundIndex
00276 #ifdef QAGAME
00277                                 *(int *)(b+vehWeaponFields[i].ofs) = G_SoundIndex( value );
00278 #else
00279                                 *(int *)(b+vehWeaponFields[i].ofs) = trap_S_RegisterSound( value );
00280 #endif
00281                                 break;
00282                         case VF_SOUND_CLIENT:   // (MP cgame only) take the string, get the index
00283 #ifndef _JK2MP
00284                                 *(int *)(b+vehWeaponFields[i].ofs) = G_SoundIndex( value );
00285 #elif QAGAME
00286                                 //*(int *)(b+vehWeaponFields[i].ofs) = G_SoundIndex( value );
00287 #else
00288                                 *(int *)(b+vehWeaponFields[i].ofs) = trap_S_RegisterSound( value );
00289 #endif
00290                                 break;
00291                         default:
00292                                 //Unknown type?
00293                                 return qfalse;
00294                                 break;
00295                         }
00296                         break;
00297                 }
00298         }
00299         if ( i == NUM_VWEAP_PARMS )
00300         {
00301         return qfalse;
00302         }
00303         else
00304         {
00305                 return qtrue;
00306         }
00307 }
00308 
00309 int VEH_LoadVehWeapon( const char *vehWeaponName )
00310 {//load up specified vehWeapon and save in array: g_vehWeaponInfo
00311         const char      *token;
00312         char            parmName[128];//we'll assume that no parm name is longer than 128
00313         char            *value;
00314         const char      *p;
00315         vehWeaponInfo_t *vehWeapon = NULL;
00316 
00317         //BG_VehWeaponSetDefaults( &g_vehWeaponInfo[0] );//set the first vehicle to default data
00318 
00319         //try to parse data out
00320         p = VehWeaponParms;
00321 
00322 #ifdef _JK2MP
00323         COM_BeginParseSession("vehWeapons");
00324 #else
00325         COM_BeginParseSession();
00326 #endif
00327 
00328         vehWeapon = &g_vehWeaponInfo[numVehicleWeapons];
00329         // look for the right vehicle weapon
00330         while ( p ) 
00331         {
00332                 token = COM_ParseExt( &p, qtrue );
00333                 if ( token[0] == 0 )
00334                 {
00335                         return qfalse;
00336                 }
00337 
00338                 if ( !Q_stricmp( token, vehWeaponName ) ) 
00339                 {
00340                         break;
00341                 }
00342 
00343                 SkipBracedSection( &p );
00344         }
00345         if ( !p ) 
00346         {
00347                 return qfalse;
00348         }
00349 
00350         token = COM_ParseExt( &p, qtrue );
00351         if ( token[0] == 0 )
00352         {//barf
00353                 return VEH_WEAPON_NONE;
00354         }
00355 
00356         if ( Q_stricmp( token, "{" ) != 0 ) 
00357         {
00358                 return VEH_WEAPON_NONE;
00359         }
00360         
00361         // parse the vehWeapon info block
00362         while ( 1 ) 
00363         {
00364                 SkipRestOfLine( &p );
00365                 token = COM_ParseExt( &p, qtrue );
00366                 if ( !token[0] ) 
00367                 {
00368                         Com_Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing Vehicle Weapon '%s'\n", vehWeaponName );
00369                         return VEH_WEAPON_NONE;
00370                 }
00371 
00372                 if ( !Q_stricmp( token, "}" ) ) 
00373                 {
00374                         break;
00375                 }
00376                 Q_strncpyz( parmName, token, sizeof(parmName) );
00377                 value = COM_ParseExt( &p, qtrue );
00378                 if ( !value || !value[0] )
00379                 {
00380                         Com_Printf( S_COLOR_RED"ERROR: Vehicle Weapon token '%s' has no value!\n", parmName );
00381                 }
00382                 else
00383                 {
00384                         if ( !BG_ParseVehWeaponParm( vehWeapon, parmName, value ) )
00385                         {
00386                                 Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle Weapon key/value pair '%s','%s'!\n", parmName, value );
00387                         }
00388                 }
00389         }
00390         if ( vehWeapon->fHoming )
00391         {//all lock-on weapons use these 2 sounds
00392 #ifdef QAGAME
00393                 //Hmm, no need fo have server register this, is there?
00394                 //G_SoundIndex( "sound/weapons/torpedo/tick.wav" );
00395                 //G_SoundIndex( "sound/weapons/torpedo/lock.wav" );
00396 #elif CGAME
00397                 trap_S_RegisterSound( "sound/vehicles/weapons/common/tick.wav" );
00398                 trap_S_RegisterSound( "sound/vehicles/weapons/common/lock.wav" );
00399                 trap_S_RegisterSound( "sound/vehicles/common/lockalarm1.wav" );
00400                 trap_S_RegisterSound( "sound/vehicles/common/lockalarm2.wav" );
00401                 trap_S_RegisterSound( "sound/vehicles/common/lockalarm3.wav" );
00402 #else
00403                 trap_S_RegisterSound( "sound/vehicles/weapons/common/tick.wav" );
00404                 trap_S_RegisterSound( "sound/vehicles/weapons/common/lock.wav" );
00405                 trap_S_RegisterSound( "sound/vehicles/common/lockalarm1.wav" );
00406                 trap_S_RegisterSound( "sound/vehicles/common/lockalarm2.wav" );
00407                 trap_S_RegisterSound( "sound/vehicles/common/lockalarm3.wav" );
00408 #endif
00409         }
00410         return (numVehicleWeapons++);
00411 }
00412 
00413 int VEH_VehWeaponIndexForName( const char *vehWeaponName )
00414 {
00415         int vw;
00416         if ( !vehWeaponName || !vehWeaponName[0] )
00417         {
00418                 Com_Printf( S_COLOR_RED"ERROR: Trying to read Vehicle Weapon with no name!\n" );
00419                 return VEH_WEAPON_NONE;
00420         }
00421         for ( vw = VEH_WEAPON_BASE; vw < numVehicleWeapons; vw++ )
00422         {
00423                 if ( g_vehWeaponInfo[vw].name
00424                         && Q_stricmp( g_vehWeaponInfo[vw].name, vehWeaponName ) == 0 )
00425                 {//already loaded this one
00426                         return vw;
00427                 }
00428         }
00429         //haven't loaded it yet
00430         if ( vw >= MAX_VEH_WEAPONS )
00431         {//no more room!
00432                 Com_Printf( S_COLOR_RED"ERROR: Too many Vehicle Weapons (max 16), aborting load on %s!\n", vehWeaponName );
00433                 return VEH_WEAPON_NONE;
00434         }
00435         //we have room for another one, load it up and return the index
00436         //HMM... should we not even load the .vwp file until we want to?
00437         vw = VEH_LoadVehWeapon( vehWeaponName );
00438         if ( vw == VEH_WEAPON_NONE )
00439         {
00440                 Com_Printf( S_COLOR_RED"ERROR: Could not find Vehicle Weapon %s!\n", vehWeaponName );
00441         }
00442         return vw;
00443 }
00444 
00445 vehField_t vehicleFields[] = 
00446 {
00447         {"name", VFOFS(name), VF_LSTRING},      //unique name of the vehicle
00448 
00449         //general data
00450         {"type", VFOFS(type), VF_VEHTYPE},      //what kind of vehicle
00451         {"numHands", VFOFS(numHands), VF_INT},  //if 2 hands, no weapons, if 1 hand, can use 1-handed weapons, if 0 hands, can use 2-handed weapons
00452         {"lookPitch", VFOFS(lookPitch), VF_FLOAT},      //How far you can look up and down off the forward of the vehicle
00453         {"lookYaw", VFOFS(lookYaw), VF_FLOAT},  //How far you can look left and right off the forward of the vehicle
00454         {"length", VFOFS(length), VF_FLOAT},            //how long it is - used for body length traces when turning/moving?
00455         {"width", VFOFS(width), VF_FLOAT},              //how wide it is - used for body length traces when turning/moving?
00456         {"height", VFOFS(height), VF_FLOAT},            //how tall it is - used for body length traces when turning/moving?
00457         {"centerOfGravity", VFOFS(centerOfGravity), VF_VECTOR},//offset from origin: {forward, right, up} as a modifier on that dimension (-1.0f is all the way back, 1.0f is all the way forward)
00458 
00459         //speed stats
00460         {"speedMax", VFOFS(speedMax), VF_FLOAT},                //top speed
00461         {"turboSpeed", VFOFS(turboSpeed), VF_FLOAT},    //turbo speed
00462         {"speedMin", VFOFS(speedMin), VF_FLOAT},                //if < 0, can go in reverse
00463         {"speedIdle", VFOFS(speedIdle), VF_FLOAT},              //what speed it drifts to when no accel/decel input is given
00464         {"accelIdle", VFOFS(accelIdle), VF_FLOAT},              //if speedIdle > 0, how quickly it goes up to that speed
00465         {"acceleration", VFOFS(acceleration), VF_FLOAT},        //when pressing on accelerator
00466         {"decelIdle", VFOFS(decelIdle), VF_FLOAT},              //when giving no input, how quickly it drops to speedIdle
00467         {"throttleSticks", VFOFS(throttleSticks), VF_BOOL},//if true, speed stays at whatever you accel/decel to, unless you turbo or brake
00468         {"strafePerc", VFOFS(strafePerc), VF_FLOAT},            //multiplier on current speed for strafing.  If 1.0f, you can strafe at the same speed as you're going forward, 0.5 is half, 0 is no strafing
00469 
00470         //handling stats
00471         {"bankingSpeed", VFOFS(bankingSpeed), VF_FLOAT},        //how quickly it pitches and rolls (not under player control)
00472         {"pitchLimit", VFOFS(pitchLimit), VF_FLOAT},            //how far it can roll forward or backward
00473         {"rollLimit", VFOFS(rollLimit), VF_FLOAT},              //how far it can roll to either side
00474         {"braking", VFOFS(braking), VF_FLOAT},          //when pressing on decelerator
00475         {"mouseYaw", VFOFS(mouseYaw), VF_FLOAT},                        // The mouse yaw override.
00476         {"mousePitch", VFOFS(mousePitch), VF_FLOAT},                    // The mouse yaw override.
00477         {"turningSpeed", VFOFS(turningSpeed), VF_FLOAT},        //how quickly you can turn
00478         {"turnWhenStopped", VFOFS(turnWhenStopped), VF_BOOL},//whether or not you can turn when not moving
00479         {"traction", VFOFS(traction), VF_FLOAT},                //how much your command input affects velocity
00480         {"friction", VFOFS(friction), VF_FLOAT},                //how much velocity is cut on its own
00481         {"maxSlope", VFOFS(maxSlope), VF_FLOAT},                //the max slope that it can go up with control
00482         {"speedDependantTurning", VFOFS(speedDependantTurning), VF_BOOL},//vehicle turns faster the faster it's going
00483         
00484         //durability stats
00485         {"mass", VFOFS(mass), VF_INT},                  //for momentum and impact force (player mass is 10)
00486         {"armor", VFOFS(armor), VF_INT},                        //total points of damage it can take
00487         {"shields", VFOFS(shields), VF_INT},                    //energy shield damage points
00488         {"shieldRechargeMS", VFOFS(shieldRechargeMS), VF_INT},//energy shield milliseconds per point recharged
00489         {"toughness", VFOFS(toughness), VF_FLOAT},              //modifies incoming damage, 1.0 is normal, 0.5 is half, etc.  Simulates being made of tougher materials/construction
00490         {"malfunctionArmorLevel", VFOFS(malfunctionArmorLevel), VF_INT},//when armor drops to or below this point, start malfunctioning
00491         {"surfDestruction", VFOFS(surfDestruction), VF_INT},
00492 
00493         //visuals & sounds
00494         {"model", VFOFS(model), VF_LSTRING},                    //what model to use - if make it an NPC's primary model, don't need this?
00495         {"skin", VFOFS(skin), VF_LSTRING},                              //what skin to use - if make it an NPC's primary model, don't need this?
00496         {"g2radius", VFOFS(g2radius), VF_INT},                  //render radius (really diameter, but...) for the ghoul2 model
00497         {"riderAnim", VFOFS(riderAnim), VF_ANIM},               //what animation the rider uses
00498         {"droidNPC", VFOFS(droidNPC), VF_LSTRING},              //NPC to attach to *droidunit tag (if it exists in the model)
00499 
00500 #ifdef _JK2MP
00501         {"radarIcon", VFOFS(radarIconHandle), VF_SHADER_NOMIP},         //what icon to show on radar in MP
00502         {"dmgIndicFrame", VFOFS(dmgIndicFrameHandle), VF_SHADER_NOMIP}, //what image to use for the frame of the damage indicator
00503         {"dmgIndicShield", VFOFS(dmgIndicShieldHandle), VF_SHADER_NOMIP},//what image to use for the shield of the damage indicator
00504         {"dmgIndicBackground", VFOFS(dmgIndicBackgroundHandle), VF_SHADER_NOMIP},//what image to use for the background of the damage indicator
00505         {"icon_front", VFOFS(iconFrontHandle), VF_SHADER_NOMIP},        //what image to use for the front of the ship on the damage indicator
00506         {"icon_back", VFOFS(iconBackHandle), VF_SHADER_NOMIP},          //what image to use for the back of the ship on the damage indicator
00507         {"icon_right", VFOFS(iconRightHandle), VF_SHADER_NOMIP},        //what image to use for the right of the ship on the damage indicator
00508         {"icon_left", VFOFS(iconLeftHandle), VF_SHADER_NOMIP},          //what image to use for the left of the ship on the damage indicator
00509         {"crosshairShader", VFOFS(crosshairShaderHandle), VF_SHADER_NOMIP},     //what image to use as the crosshair
00510         {"shieldShader", VFOFS(shieldShaderHandle), VF_SHADER},         //What shader to use when drawing the shield shell
00511 
00512         //individual "area" health -rww
00513         {"health_front", VFOFS(health_front), VF_INT},
00514         {"health_back", VFOFS(health_back), VF_INT},
00515         {"health_right", VFOFS(health_right), VF_INT},
00516         {"health_left", VFOFS(health_left), VF_INT},
00517 #else
00518         {"radarIcon", 0, VF_IGNORE},            //what icon to show on radar in MP
00519 #endif
00520 
00521         {"soundOn",                     VFOFS(soundOn),                 VF_SOUND},//sound to play when get on it
00522         {"soundOff",            VFOFS(soundOff),                VF_SOUND},//sound to play when get off
00523         {"soundLoop",           VFOFS(soundLoop),               VF_SOUND},//sound to loop while riding it
00524         {"soundTakeOff",        VFOFS(soundTakeOff),    VF_SOUND},//sound to play when ship takes off
00525         {"soundEngineStart",VFOFS(soundEngineStart),VF_SOUND_CLIENT},//sound to play when ship's thrusters first activate
00526         {"soundSpin",           VFOFS(soundSpin),               VF_SOUND},//sound to loop while spiraling out of control
00527         {"soundTurbo",          VFOFS(soundTurbo),              VF_SOUND},//sound to play when turbo/afterburner kicks in
00528         {"soundHyper",          VFOFS(soundHyper),              VF_SOUND_CLIENT},//sound to play when hits hyperspace
00529         {"soundLand",           VFOFS(soundLand),               VF_SOUND},//sound to play when ship lands
00530         {"soundFlyBy",          VFOFS(soundFlyBy),              VF_SOUND_CLIENT},//sound to play when they buzz you
00531         {"soundFlyBy2",         VFOFS(soundFlyBy2),             VF_SOUND_CLIENT},//alternate sound to play when they buzz you
00532         {"soundShift1",         VFOFS(soundShift1),             VF_SOUND},//sound to play when changing speeds
00533         {"soundShift2",         VFOFS(soundShift2),             VF_SOUND},//sound to play when changing speeds
00534         {"soundShift3",         VFOFS(soundShift3),             VF_SOUND},//sound to play when changing speeds
00535         {"soundShift4",         VFOFS(soundShift4),             VF_SOUND},//sound to play when changing speeds
00536 
00537         {"exhaustFX", VFOFS(iExhaustFX), VF_EFFECT_CLIENT},             //exhaust effect, played from "*exhaust" bolt(s)
00538         {"turboFX", VFOFS(iTurboFX), VF_EFFECT_CLIENT},         //turbo exhaust effect, played from "*exhaust" bolt(s) when ship is in "turbo" mode
00539         {"turboStartFX", VFOFS(iTurboStartFX), VF_EFFECT},              //turbo start effect, played from "*exhaust" bolt(s) when ship is in "turbo" mode
00540         {"trailFX", VFOFS(iTrailFX), VF_EFFECT_CLIENT},         //trail effect, played from "*trail" bolt(s)
00541         {"impactFX", VFOFS(iImpactFX), VF_EFFECT_CLIENT},               //impact effect, for when it bumps into something
00542         {"explodeFX", VFOFS(iExplodeFX), VF_EFFECT},            //explosion effect, for when it blows up (should have the sound built into explosion effect)
00543         {"wakeFX", VFOFS(iWakeFX), VF_EFFECT_CLIENT},           //effect it makes when going across water
00544         {"dmgFX", VFOFS(iDmgFX), VF_EFFECT_CLIENT},             //effect to play on damage from a weapon or something
00545 #ifdef _JK2MP
00546         {"injureFX", VFOFS(iInjureFX), VF_EFFECT_CLIENT}, //effect to play on partially damaged ship surface
00547         {"noseFX", VFOFS(iNoseFX), VF_EFFECT_CLIENT},           //effect for nose piece flying away when blown off
00548         {"lwingFX", VFOFS(iLWingFX), VF_EFFECT_CLIENT},         //effect for left wing piece flying away when blown off
00549         {"rwingFX", VFOFS(iRWingFX), VF_EFFECT_CLIENT},         //effect for right wing piece flying away when blown off
00550 #else
00551         {"armorLowFX", VFOFS(iArmorLowFX), VF_EFFECT_CLIENT},           //effect to play on damage from a weapon or something
00552         {"armorGoneFX", VFOFS(iArmorGoneFX), VF_EFFECT_CLIENT},         //effect to play on damage from a weapon or something
00553 #endif
00554 
00555         // Weapon stuff:
00556         {"weap1", VFOFS(weapon[0].ID), VF_WEAPON},      //weapon used when press fire
00557         {"weap2", VFOFS(weapon[1].ID), VF_WEAPON},//weapon used when press alt-fire
00558         // The delay between shots for this weapon.
00559         {"weap1Delay", VFOFS(weapon[0].delay), VF_INT},
00560         {"weap2Delay", VFOFS(weapon[1].delay), VF_INT},
00561         // Whether or not all the muzzles for each weapon can be linked together (linked delay = weapon delay * number of muzzles linked!)
00562         {"weap1Link", VFOFS(weapon[0].linkable), VF_INT},
00563         {"weap2Link", VFOFS(weapon[1].linkable), VF_INT},
00564         // Whether or not to auto-aim the projectiles at the thing under the crosshair when we fire
00565         {"weap1Aim", VFOFS(weapon[0].aimCorrect), VF_BOOL},
00566         {"weap2Aim", VFOFS(weapon[1].aimCorrect), VF_BOOL},
00567         //maximum ammo
00568         {"weap1AmmoMax", VFOFS(weapon[0].ammoMax), VF_INT},
00569         {"weap2AmmoMax", VFOFS(weapon[1].ammoMax), VF_INT},
00570         //ammo recharge rate - milliseconds per unit (minimum of 100, which is 10 ammo per second)
00571         {"weap1AmmoRechargeMS", VFOFS(weapon[0].ammoRechargeMS), VF_INT},
00572         {"weap2AmmoRechargeMS", VFOFS(weapon[1].ammoRechargeMS), VF_INT},
00573         //sound to play when out of ammo (plays default "no ammo" sound if none specified)
00574         {"weap1SoundNoAmmo", VFOFS(weapon[0].soundNoAmmo), VF_SOUND_CLIENT},//sound to play when try to fire weapon 1 with no ammo
00575         {"weap2SoundNoAmmo", VFOFS(weapon[1].soundNoAmmo), VF_SOUND_CLIENT},//sound to play when try to fire weapon 2 with no ammo
00576         
00577         // Which weapon a muzzle fires (has to match one of the weapons this vehicle has).
00578         {"weapMuzzle1", VFOFS(weapMuzzle[0]), VF_WEAPON},
00579         {"weapMuzzle2", VFOFS(weapMuzzle[1]), VF_WEAPON},
00580         {"weapMuzzle3", VFOFS(weapMuzzle[2]), VF_WEAPON},
00581         {"weapMuzzle4", VFOFS(weapMuzzle[3]), VF_WEAPON},
00582         {"weapMuzzle5", VFOFS(weapMuzzle[4]), VF_WEAPON},
00583         {"weapMuzzle6", VFOFS(weapMuzzle[5]), VF_WEAPON},
00584         {"weapMuzzle7", VFOFS(weapMuzzle[6]), VF_WEAPON},
00585         {"weapMuzzle8", VFOFS(weapMuzzle[7]), VF_WEAPON},
00586         {"weapMuzzle9", VFOFS(weapMuzzle[8]), VF_WEAPON},
00587         {"weapMuzzle10", VFOFS(weapMuzzle[9]), VF_WEAPON},
00588 
00589         // The max height before this ship (?) starts (auto)landing.
00590         {"landingHeight", VFOFS(landingHeight), VF_FLOAT},
00591 
00592         //other misc stats
00593         {"gravity", VFOFS(gravity), VF_INT},                    //normal is 800
00594         {"hoverHeight", VFOFS(hoverHeight), VF_FLOAT},  //if 0, it's a ground vehicle
00595         {"hoverStrength", VFOFS(hoverStrength), VF_FLOAT},      //how hard it pushes off ground when less than hover height... causes "bounce", like shocks
00596         {"waterProof", VFOFS(waterProof), VF_BOOL},             //can drive underwater if it has to
00597         {"bouyancy", VFOFS(bouyancy), VF_FLOAT},                //when in water, how high it floats (1 is neutral bouyancy)
00598         {"fuelMax", VFOFS(fuelMax), VF_INT},            //how much fuel it can hold (capacity)
00599         {"fuelRate", VFOFS(fuelRate), VF_INT},          //how quickly is uses up fuel
00600         {"turboDuration", VFOFS(turboDuration), VF_INT},                //how long turbo lasts
00601         {"turboRecharge", VFOFS(turboRecharge), VF_INT},                //how long turbo takes to recharge
00602         {"visibility", VFOFS(visibility), VF_INT},              //for sight alerts
00603         {"loudness", VFOFS(loudness), VF_INT},          //for sound alerts
00604         {"explosionRadius", VFOFS(explosionRadius), VF_FLOAT},//range of explosion
00605         {"explosionDamage", VFOFS(explosionDamage), VF_INT},//damage of explosion
00606 
00607         //new stuff
00608         {"maxPassengers", VFOFS(maxPassengers), VF_INT},        // The max number of passengers this vehicle may have (Default = 0).
00609         {"hideRider", VFOFS(hideRider), VF_BOOL},                       // rider (and passengers?) should not be drawn
00610         {"killRiderOnDeath", VFOFS(killRiderOnDeath), VF_BOOL},//if rider is on vehicle when it dies, they should die
00611         {"flammable", VFOFS(flammable), VF_BOOL},                       //whether or not the vehicle should catch on fire before it explodes
00612         {"explosionDelay", VFOFS(explosionDelay), VF_INT},      //how long the vehicle should be on fire/dying before it explodes
00613         //camera stuff
00614         {"cameraOverride", VFOFS(cameraOverride), VF_BOOL},//override the third person camera with the below values - normal is 0 (off)
00615         {"cameraRange", VFOFS(cameraRange), VF_FLOAT},          //how far back the camera should be - normal is 80
00616         {"cameraVertOffset", VFOFS(cameraVertOffset), VF_FLOAT},//how high over the vehicle origin the camera should be - normal is 16
00617         {"cameraHorzOffset", VFOFS(cameraHorzOffset), VF_FLOAT},//how far to left/right (negative/positive) of of the vehicle origin the camera should be - normal is 0
00618         {"cameraPitchOffset", VFOFS(cameraPitchOffset), VF_FLOAT},//a modifier on the camera's pitch (up/down angle) to the vehicle - normal is 0
00619         {"cameraFOV", VFOFS(cameraFOV), VF_FLOAT},                      //third person camera FOV, default is 80
00620         {"cameraAlpha", VFOFS(cameraAlpha), VF_FLOAT},          //fade out the vehicle to this alpha (0.1-1.0f) if it's in the way of the crosshair
00621         {"cameraPitchDependantVertOffset", VFOFS(cameraPitchDependantVertOffset), VF_BOOL},             //use the hacky AT-ST pitch dependant vertical offset
00622 //===TURRETS===========================================================================
00623         //Turret 1
00624         {"turret1Weap", VFOFS(turret[0].iWeapon), VF_WEAPON},
00625         {"turret1Delay", VFOFS(turret[0].iDelay), VF_INT},
00626         {"turret1AmmoMax", VFOFS(turret[0].iAmmoMax), VF_INT},
00627         {"turret1AmmoRechargeMS", VFOFS(turret[0].iAmmoRechargeMS), VF_INT},
00628         {"turret1YawBone", VFOFS(turret[0].yawBone), VF_LSTRING},
00629         {"turret1PitchBone", VFOFS(turret[0].pitchBone), VF_LSTRING},
00630         {"turret1YawAxis", VFOFS(turret[0].yawAxis), VF_INT},
00631         {"turret1PitchAxis", VFOFS(turret[0].pitchAxis), VF_INT},
00632         {"turret1ClampYawL", VFOFS(turret[0].yawClampLeft), VF_FLOAT},  //how far the turret is allowed to turn left
00633         {"turret1ClampYawR", VFOFS(turret[0].yawClampRight), VF_FLOAT}, //how far the turret is allowed to turn right
00634         {"turret1ClampPitchU", VFOFS(turret[0].pitchClampUp), VF_FLOAT},        //how far the turret is allowed to title up
00635         {"turret1ClampPitchD", VFOFS(turret[0].pitchClampDown), VF_FLOAT}, //how far the turret is allowed to tilt down
00636         {"turret1Muzzle1", VFOFS(turret[0].iMuzzle[0]), VF_INT},
00637         {"turret1Muzzle2", VFOFS(turret[0].iMuzzle[1]), VF_INT},
00638         {"turret1TurnSpeed", VFOFS(turret[0].fTurnSpeed), VF_FLOAT},
00639         {"turret1AI", VFOFS(turret[0].bAI), VF_BOOL},
00640         {"turret1AILead", VFOFS(turret[0].bAILead), VF_BOOL},
00641         {"turret1AIRange", VFOFS(turret[0].fAIRange), VF_FLOAT},
00642         {"turret1PassengerNum", VFOFS(turret[0].passengerNum), VF_INT},//which number passenger can control this turret
00643         {"turret1GunnerViewTag", VFOFS(turret[0].gunnerViewTag), VF_LSTRING},
00644         
00645         //Turret 2
00646         {"turret2Weap", VFOFS(turret[1].iWeapon), VF_WEAPON},
00647         {"turret2Delay", VFOFS(turret[1].iDelay), VF_INT},
00648         {"turret2AmmoMax", VFOFS(turret[1].iAmmoMax), VF_INT},
00649         {"turret2AmmoRechargeMS", VFOFS(turret[1].iAmmoRechargeMS), VF_INT},
00650         {"turret2YawBone", VFOFS(turret[1].yawBone), VF_LSTRING},
00651         {"turret2PitchBone", VFOFS(turret[1].pitchBone), VF_LSTRING},
00652         {"turret2YawAxis", VFOFS(turret[1].yawAxis), VF_INT},
00653         {"turret2PitchAxis", VFOFS(turret[1].pitchAxis), VF_INT},
00654         {"turret2ClampYawL", VFOFS(turret[1].yawClampLeft), VF_FLOAT},  //how far the turret is allowed to turn left
00655         {"turret2ClampYawR", VFOFS(turret[1].yawClampRight), VF_FLOAT}, //how far the turret is allowed to turn right
00656         {"turret2ClampPitchU", VFOFS(turret[1].pitchClampUp), VF_FLOAT},        //how far the turret is allowed to title up
00657         {"turret2ClampPitchD", VFOFS(turret[1].pitchClampDown), VF_FLOAT}, //how far the turret is allowed to tilt down
00658         {"turret2Muzzle1", VFOFS(turret[1].iMuzzle[0]), VF_INT},
00659         {"turret2Muzzle2", VFOFS(turret[1].iMuzzle[1]), VF_INT},
00660         {"turret2TurnSpeed", VFOFS(turret[1].fTurnSpeed), VF_FLOAT},
00661         {"turret2AI", VFOFS(turret[1].bAI), VF_BOOL},
00662         {"turret2AILead", VFOFS(turret[1].bAILead), VF_BOOL},
00663         {"turret2AIRange", VFOFS(turret[1].fAIRange), VF_FLOAT},
00664         {"turret2PassengerNum", VFOFS(turret[1].passengerNum), VF_INT},//which number passenger can control this turret
00665         {"turret2GunnerViewTag", VFOFS(turret[1].gunnerViewTag), VF_LSTRING},
00666 //===END TURRETS===========================================================================
00667         //terminating entry
00668         {0, -1, VF_INT}
00669 };
00670 
00671 stringID_table_t VehicleTable[VH_NUM_VEHICLES+1] =
00672 {
00673         ENUM2STRING(VH_NONE),
00674         ENUM2STRING(VH_WALKER),         //something you ride inside of, it walks like you, like an AT-ST
00675         ENUM2STRING(VH_FIGHTER),        //something you fly inside of, like an X-Wing or TIE fighter
00676         ENUM2STRING(VH_SPEEDER),        //something you ride on that hovers, like a speeder or swoop
00677         ENUM2STRING(VH_ANIMAL),         //animal you ride on top of that walks, like a tauntaun
00678         ENUM2STRING(VH_FLIER),          //animal you ride on top of that flies, like a giant mynoc?
00679         0,      -1
00680 };
00681 
00682 // Setup the shared functions (one's that all vehicles would generally use).
00683 void BG_SetSharedVehicleFunctions( vehicleInfo_t *pVehInfo )
00684 {
00685 #ifdef QAGAME
00686         //only do the whole thing if we're on game
00687         G_SetSharedVehicleFunctions(pVehInfo);
00688 #endif
00689 
00690 #ifndef WE_ARE_IN_THE_UI
00691         switch( pVehInfo->type )
00692         {
00693                 case VH_SPEEDER:
00694                         G_SetSpeederVehicleFunctions( pVehInfo );
00695                         break;
00696                 case VH_ANIMAL:
00697                         G_SetAnimalVehicleFunctions( pVehInfo );
00698                         break;
00699                 case VH_FIGHTER:
00700                         G_SetFighterVehicleFunctions( pVehInfo );
00701                         break;
00702                 case VH_WALKER:
00703                         G_SetWalkerVehicleFunctions( pVehInfo );
00704                         break;
00705         }
00706 #endif
00707 }
00708 
00709 void BG_VehicleSetDefaults( vehicleInfo_t *vehicle )
00710 {
00711         memset(vehicle, 0, sizeof(vehicleInfo_t));
00712 /*
00713 #if _JK2MP
00714         if (!vehicle->name)
00715         {
00716                 vehicle->name = (char *)BG_Alloc(1024);
00717         }
00718         strcpy(vehicle->name, "default");
00719 #else
00720         vehicle->name = G_NewString( "default" );
00721 #endif
00722 
00723         //general data
00724         vehicle->type = VH_SPEEDER;                             //what kind of vehicle
00725         //FIXME: no saber or weapons if numHands = 2, should switch to speeder weapon, no attack anim on player
00726         vehicle->numHands = 0;                                  //if 2 hands, no weapons, if 1 hand, can use 1-handed weapons, if 0 hands, can use 2-handed weapons
00727         vehicle->lookPitch = 0;                         //How far you can look up and down off the forward of the vehicle
00728         vehicle->lookYaw = 5;                                   //How far you can look left and right off the forward of the vehicle
00729         vehicle->length = 0;                                    //how long it is - used for body length traces when turning/moving?
00730         vehicle->width = 0;                                             //how wide it is - used for body length traces when turning/moving?
00731         vehicle->height = 0;                                    //how tall it is - used for body length traces when turning/moving?
00732         VectorClear( vehicle->centerOfGravity );//offset from origin: {forward, right, up} as a modifier on that dimension (-1.0f is all the way back, 1.0f is all the way forward)
00733 
00734         //speed stats - note: these are DESIRED speed, not actual current speed/velocity
00735         vehicle->speedMax = VEH_DEFAULT_SPEED_MAX;      //top speed
00736         vehicle->turboSpeed = 0;                                        //turboBoost
00737         vehicle->speedMin = 0;                                          //if < 0, can go in reverse
00738         vehicle->speedIdle = 0;                                         //what speed it drifts to when no accel/decel input is given
00739         vehicle->accelIdle = 0;                                         //if speedIdle > 0, how quickly it goes up to that speed
00740         vehicle->acceleration = VEH_DEFAULT_ACCEL;      //when pressing on accelerator (1/2 this when going in reverse)
00741         vehicle->decelIdle = VEH_DEFAULT_DECEL;         //when giving no input, how quickly it desired speed drops to speedIdle
00742         vehicle->strafePerc = VEH_DEFAULT_STRAFE_PERC;//multiplier on current speed for strafing.  If 1.0f, you can strafe at the same speed as you're going forward, 0.5 is half, 0 is no strafing
00743 
00744         //handling stats
00745         vehicle->bankingSpeed = VEH_DEFAULT_BANKING_SPEED;      //how quickly it pitches and rolls (not under player control)
00746         vehicle->rollLimit = VEH_DEFAULT_ROLL_LIMIT;            //how far it can roll to either side
00747         vehicle->pitchLimit = VEH_DEFAULT_PITCH_LIMIT;          //how far it can pitch forward or backward
00748         vehicle->braking = VEH_DEFAULT_BRAKING;                         //when pressing on decelerator (backwards)
00749         vehicle->turningSpeed = VEH_DEFAULT_TURNING_SPEED;      //how quickly you can turn
00750         vehicle->turnWhenStopped = qfalse;                                      //whether or not you can turn when not moving   
00751         vehicle->traction = VEH_DEFAULT_TRACTION;                       //how much your command input affects velocity
00752         vehicle->friction = VEH_DEFAULT_FRICTION;                       //how much velocity is cut on its own
00753         vehicle->maxSlope = VEH_DEFAULT_MAX_SLOPE;                      //the max slope that it can go up with control
00754 
00755         //durability stats
00756         vehicle->mass = VEH_DEFAULT_MASS;                       //for momentum and impact force (player mass is 10)
00757         vehicle->armor = VEH_DEFAULT_MAX_ARMOR;         //total points of damage it can take
00758         vehicle->toughness = VEH_DEFAULT_TOUGHNESS;     //modifies incoming damage, 1.0 is normal, 0.5 is half, etc.  Simulates being made of tougher materials/construction
00759         vehicle->malfunctionArmorLevel = 0;                     //when armor drops to or below this point, start malfunctioning
00760 
00761         //visuals & sounds
00762         //vehicle->model = "models/map_objects/ships/swoop.md3";        //what model to use - if make it an NPC's primary model, don't need this?
00763         if (!vehicle->model)
00764         {
00765                 vehicle->model = (char *)BG_Alloc(1024);
00766         }
00767         strcpy(vehicle->model, "models/map_objects/ships/swoop.md3");
00768 
00769         vehicle->modelIndex = 0;                                                        //set internally, not until this vehicle is spawned into the level
00770         vehicle->skin = NULL;                                                           //what skin to use - if make it an NPC's primary model, don't need this?
00771         vehicle->riderAnim = BOTH_GUNSIT1;                                      //what animation the rider uses
00772 
00773         vehicle->soundOn = NULL;                                                        //sound to play when get on it
00774         vehicle->soundLoop = NULL;                                                      //sound to loop while riding it
00775         vehicle->soundOff = NULL;                                                       //sound to play when get off
00776         vehicle->exhaustFX = NULL;                                                      //exhaust effect, played from "*exhaust" bolt(s)
00777         vehicle->trailFX = NULL;                                                        //trail effect, played from "*trail" bolt(s)
00778         vehicle->impactFX = NULL;                                                       //explosion effect, for when it blows up (should have the sound built into explosion effect)
00779         vehicle->explodeFX = NULL;                                                      //explosion effect, for when it blows up (should have the sound built into explosion effect)
00780         vehicle->wakeFX = NULL;                                                         //effect itmakes when going across water
00781 
00782         //other misc stats
00783         vehicle->gravity = VEH_DEFAULT_GRAVITY;                         //normal is 800
00784         vehicle->hoverHeight = 0;//VEH_DEFAULT_HOVER_HEIGHT;    //if 0, it's a ground vehicle
00785         vehicle->hoverStrength = 0;//VEH_DEFAULT_HOVER_STRENGTH;//how hard it pushes off ground when less than hover height... causes "bounce", like shocks
00786         vehicle->waterProof = qtrue;                                            //can drive underwater if it has to
00787         vehicle->bouyancy = 1.0f;                                                       //when in water, how high it floats (1 is neutral bouyancy)
00788         vehicle->fuelMax = 1000;                                                        //how much fuel it can hold (capacity)
00789         vehicle->fuelRate = 1;                                                          //how quickly is uses up fuel
00790         vehicle->visibility = VEH_DEFAULT_VISIBILITY;           //radius for sight alerts
00791         vehicle->loudness = VEH_DEFAULT_LOUDNESS;                       //radius for sound alerts
00792         vehicle->explosionRadius = VEH_DEFAULT_EXP_RAD;
00793         vehicle->explosionDamage = VEH_DEFAULT_EXP_DMG;
00794         vehicle->maxPassengers = 0;
00795 
00796         //new stuff
00797         vehicle->hideRider = qfalse;                                            // rider (and passengers?) should not be drawn
00798         vehicle->killRiderOnDeath = qfalse;                                     //if rider is on vehicle when it dies, they should die
00799         vehicle->flammable = qfalse;                                            //whether or not the vehicle should catch on fire before it explodes
00800         vehicle->explosionDelay = 0;                                            //how long the vehicle should be on fire/dying before it explodes
00801         //camera stuff
00802         vehicle->cameraOverride = qfalse;                                       //whether or not to use all of the following 3rd person camera override values
00803         vehicle->cameraRange = 0.0f;                                            //how far back the camera should be - normal is 80
00804         vehicle->cameraVertOffset = 0.0f;                                       //how high over the vehicle origin the camera should be - normal is 16
00805         vehicle->cameraHorzOffset = 0.0f;                                       //how far to left/right (negative/positive) of of the vehicle origin the camera should be - normal is 0
00806         vehicle->cameraPitchOffset = 0.0f;                                      //a modifier on the camera's pitch (up/down angle) to the vehicle - normal is 0
00807         vehicle->cameraFOV = 0.0f;                                                      //third person camera FOV, default is 80
00808         vehicle->cameraAlpha = qfalse;                                          //fade out the vehicle if it's in the way of the crosshair
00809 */
00810 }
00811 
00812 void BG_VehicleClampData( vehicleInfo_t *vehicle )
00813 {//sanity check and clamp the vehicle's data
00814         int             i;
00815 
00816         for ( i = 0; i < 3; i++ )
00817         {
00818                 if ( vehicle->centerOfGravity[i] > 1.0f )
00819                 {
00820                         vehicle->centerOfGravity[i] = 1.0f;
00821                 }
00822                 else if ( vehicle->centerOfGravity[i] < -1.0f )
00823                 {
00824                         vehicle->centerOfGravity[i] = -1.0f;
00825                 }
00826         }
00827 
00828         // Validate passenger max.
00829         if ( vehicle->maxPassengers > VEH_MAX_PASSENGERS )
00830         {
00831                 vehicle->maxPassengers = VEH_MAX_PASSENGERS;
00832         }
00833         else if ( vehicle->maxPassengers < 0 )
00834         {
00835                 vehicle->maxPassengers = 0;
00836         }
00837 }
00838 
00839 static qboolean BG_ParseVehicleParm( vehicleInfo_t *vehicle, char *parmName, char *pValue )
00840 {
00841         int             i;
00842         vec3_t  vec;
00843         byte    *b = (byte *)vehicle;
00844         int             _iFieldsRead = 0;
00845         vehicleType_t vehType;
00846         char value[1024];
00847 
00848         Q_strncpyz( value, pValue, sizeof(value) );
00849 
00850         // Loop through possible parameters
00851         for ( i = 0; vehicleFields[i].ofs != -1; i++ )
00852         {
00853                 if ( !Q_stricmp( vehicleFields[i].name, parmName ) )
00854                 {
00855                         // found it
00856                         switch( vehicleFields[i].type ) 
00857                         {
00858                         case VF_IGNORE:
00859                                 break;
00860                         case VF_INT:
00861                                 *(int *)(b+vehicleFields[i].ofs) = atoi(value);
00862                                 break;
00863                         case VF_FLOAT:
00864                                 *(float *)(b+vehicleFields[i].ofs) = atof(value);
00865                                 break;
00866                         case VF_LSTRING:        // string on disk, pointer in memory, TAG_LEVEL
00867                                 if (!*(char **)(b+vehicleFields[i].ofs))
00868                                 { //just use 128 bytes in case we want to write over the string
00869 #ifdef _JK2MP
00870                                         *(char **)(b+vehicleFields[i].ofs) = (char *)BG_Alloc(128);//(char *)BG_Alloc(strlen(value));
00871                                         strcpy(*(char **)(b+vehicleFields[i].ofs), value);
00872 #else
00873                                         (*(char **)(b+vehicleFields[i].ofs)) = G_NewString( value );
00874 #endif
00875                                 }
00876                                 
00877                                 break;
00878                         case VF_VECTOR:
00879                                 _iFieldsRead = sscanf (value, "%f %f %f", &vec[0], &vec[1], &vec[2]);
00880                                 assert(_iFieldsRead==3 );
00881                                 if (_iFieldsRead!=3)
00882                                 {
00883                                         Com_Printf (S_COLOR_YELLOW"BG_ParseVehicleParm: VEC3 sscanf() failed to read 3 floats ('angle' key bug?)\n");
00884                                 }
00885                                 ((float *)(b+vehWeaponFields[i].ofs))[0] = vec[0];
00886                                 ((float *)(b+vehWeaponFields[i].ofs))[1] = vec[1];
00887                                 ((float *)(b+vehWeaponFields[i].ofs))[2] = vec[2];
00888                                 break;
00889                         case VF_BOOL:
00890                                 *(qboolean *)(b+vehicleFields[i].ofs) = (qboolean)(atof(value)!=0);
00891                                 break;
00892                         case VF_VEHTYPE:
00893                                 vehType = (vehicleType_t)GetIDForString( VehicleTable, value );
00894                                 *(vehicleType_t *)(b+vehicleFields[i].ofs) = vehType;
00895                                 break;
00896                         case VF_ANIM:
00897                                 {
00898                                         int anim = GetIDForString( animTable, value );
00899                                         *(int *)(b+vehicleFields[i].ofs) = anim;
00900                                 }
00901                                 break;
00902                         case VF_WEAPON: // take string, resolve into index into VehWeaponParms
00903                                 *(int *)(b+vehicleFields[i].ofs) = VEH_VehWeaponIndexForName( value );
00904                                 break;
00905                         case VF_MODEL:  // take the string, get the G_ModelIndex
00906 #ifdef QAGAME
00907                                 *(int *)(b+vehicleFields[i].ofs) = G_ModelIndex( value );
00908 #else
00909                                 *(int *)(b+vehicleFields[i].ofs) = trap_R_RegisterModel( value );
00910 #endif
00911                                 break;
00912                         case VF_MODEL_CLIENT:   // (MP cgame only) take the string, get the G_ModelIndex
00913 #ifndef _JK2MP
00914                                 *(int *)(b+vehicleFields[i].ofs) = G_ModelIndex( value );
00915 #elif QAGAME
00916                                 //*(int *)(b+vehicleFields[i].ofs) = G_ModelIndex( value );
00917 #else
00918                                 *(int *)(b+vehicleFields[i].ofs) = trap_R_RegisterModel( value );
00919 #endif
00920                                 break;
00921                         case VF_EFFECT: // take the string, get the G_EffectIndex
00922 #ifdef QAGAME
00923                                 *(int *)(b+vehicleFields[i].ofs) = G_EffectIndex( value );
00924 #elif CGAME
00925                                 *(int *)(b+vehicleFields[i].ofs) = trap_FX_RegisterEffect( value );
00926 #endif
00927                                 break;
00928                         case VF_EFFECT_CLIENT:  // (MP cgame only) take the string, get the G_EffectIndex
00929 #ifndef _JK2MP
00930                                 *(int *)(b+vehicleFields[i].ofs) = G_EffectIndex( value );
00931 #elif QAGAME
00932                                 //*(int *)(b+vehicleFields[i].ofs) = G_EffectIndex( value );
00933 #elif CGAME
00934                                 *(int *)(b+vehicleFields[i].ofs) = trap_FX_RegisterEffect( value );
00935 #endif
00936                                 break;
00937                         case VF_SHADER: // (cgame only) take the string, call trap_R_RegisterShader
00938 #ifdef WE_ARE_IN_THE_UI
00939                                 *(int *)(b+vehicleFields[i].ofs) = trap_R_RegisterShaderNoMip( value );
00940 #elif CGAME
00941                                 *(int *)(b+vehicleFields[i].ofs) = trap_R_RegisterShader( value );
00942 #endif
00943                                 break;
00944                         case VF_SHADER_NOMIP:// (cgame only) take the string, call trap_R_RegisterShaderNoMip
00945 #ifndef QAGAME
00946                                 *(int *)(b+vehicleFields[i].ofs) = trap_R_RegisterShaderNoMip( value );
00947 #endif
00948                                 break;
00949                         case VF_SOUND:  // take the string, get the G_SoundIndex
00950 #ifdef QAGAME
00951                                 *(int *)(b+vehicleFields[i].ofs) = G_SoundIndex( value );
00952 #else
00953                                 *(int *)(b+vehicleFields[i].ofs) = trap_S_RegisterSound( value );
00954 #endif
00955                                 break;
00956                         case VF_SOUND_CLIENT:   // (MP cgame only) take the string, get the G_SoundIndex
00957 #ifndef _JK2MP
00958                                 *(int *)(b+vehicleFields[i].ofs) = G_SoundIndex( value );
00959 #elif QAGAME
00960                                 //*(int *)(b+vehicleFields[i].ofs) = G_SoundIndex( value );
00961 #else
00962                                 *(int *)(b+vehicleFields[i].ofs) = trap_S_RegisterSound( value );
00963 #endif
00964                                 break;
00965                         default:
00966                                 //Unknown type?
00967                                 return qfalse;
00968                                 break;
00969                         }
00970                         break;
00971                 }
00972         }
00973         if ( vehicleFields[i].ofs == -1 )
00974         {
00975         return qfalse;
00976         }
00977         else
00978         {
00979                 return qtrue;
00980         }
00981 }
00982 
00983 int VEH_LoadVehicle( const char *vehicleName )
00984 {//load up specified vehicle and save in array: g_vehicleInfo
00985         const char      *token;
00986         //we'll assume that no parm name is longer than 128
00987         char            parmName[128] = { 0 };
00988         char            weap1[128] = { 0 }, weap2[128] = { 0 };
00989         char            weapMuzzle1[128] = { 0 };
00990         char            weapMuzzle2[128] = { 0 };
00991         char            weapMuzzle3[128] = { 0 };
00992         char            weapMuzzle4[128] = { 0 };
00993         char            weapMuzzle5[128] = { 0 };
00994         char            weapMuzzle6[128] = { 0 };
00995         char            weapMuzzle7[128] = { 0 };
00996         char            weapMuzzle8[128] = { 0 };
00997         char            weapMuzzle9[128] = { 0 };
00998         char            weapMuzzle10[128] = { 0 };
00999         char            *value = NULL;
01000         const char      *p = NULL;
01001         vehicleInfo_t   *vehicle = NULL;
01002 
01003         // Load the vehicle parms if no vehicles have been loaded yet.
01004         if ( numVehicles == 0 ) 
01005         {
01006                 BG_VehicleLoadParms();
01007         }
01008 
01009         //try to parse data out
01010         p = VehicleParms;
01011 
01012 #ifdef _JK2MP
01013         COM_BeginParseSession("vehicles");
01014 #else
01015         COM_BeginParseSession();
01016 #endif
01017 
01018         vehicle = &g_vehicleInfo[numVehicles];
01019         // look for the right vehicle
01020         while ( p ) 
01021         {
01022                 token = COM_ParseExt( &p, qtrue );
01023                 if ( token[0] == 0 )
01024                 {
01025                         return VEHICLE_NONE;
01026                 }
01027 
01028                 if ( !Q_stricmp( token, vehicleName ) ) 
01029                 {
01030                         break;
01031                 }
01032 
01033                 SkipBracedSection( &p );
01034         }
01035 
01036         if ( !p )
01037         {
01038                 return VEHICLE_NONE;
01039         }
01040 
01041         token = COM_ParseExt( &p, qtrue );
01042         if ( token[0] == 0 )
01043         {//barf
01044                 return VEHICLE_NONE;
01045         }
01046 
01047         if ( Q_stricmp( token, "{" ) != 0 ) 
01048         {
01049                 return VEHICLE_NONE;
01050         }
01051         
01052         BG_VehicleSetDefaults( vehicle );
01053         // parse the vehicle info block
01054         while ( 1 ) 
01055         {
01056                 SkipRestOfLine( &p );
01057                 token = COM_ParseExt( &p, qtrue );
01058                 if ( !token[0] ) 
01059                 {
01060                         Com_Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing Vehicle '%s'\n", vehicleName );
01061                         return VEHICLE_NONE;
01062                 }
01063 
01064                 if ( !Q_stricmp( token, "}" ) ) 
01065                 {
01066                         break;
01067                 }
01068                 Q_strncpyz( parmName, token, sizeof(parmName) );
01069                 value = COM_ParseExt( &p, qtrue );
01070                 if ( !value || !value[0] )
01071                 {
01072                         Com_Printf( S_COLOR_RED"ERROR: Vehicle token '%s' has no value!\n", parmName );
01073                 }
01074                 else if ( Q_stricmp( "weap1", parmName ) == 0 )
01075                 {//hmm, store this off because we don't want to call another one of these text parsing routines while we're in the middle of one...
01076                         Q_strncpyz( weap1, value, sizeof(weap1) );
01077                 }
01078                 else if ( Q_stricmp( "weap2", parmName ) == 0 )
01079                 {//hmm, store this off because we don't want to call another one of these text parsing routines while we're in the middle of one...
01080                         Q_strncpyz( weap2, value, sizeof(weap2) );
01081                 }
01082                 else if ( Q_stricmp( "weapMuzzle1", parmName ) == 0 )
01083                 {//hmm, store this off because we don't want to call another one of these text parsing routines while we're in the middle of one...
01084                         Q_strncpyz( weapMuzzle1, value, sizeof(weapMuzzle1) );
01085                 }
01086                 else if ( Q_stricmp( "weapMuzzle2", parmName ) == 0 )
01087                 {//hmm, store this off because we don't want to call another one of these text parsing routines while we're in the middle of one...
01088                         Q_strncpyz( weapMuzzle2, value, sizeof(weapMuzzle2) );
01089                 }
01090                 else if ( Q_stricmp( "weapMuzzle3", parmName ) == 0 )
01091                 {//hmm, store this off because we don't want to call another one of these text parsing routines while we're in the middle of one...
01092                         Q_strncpyz( weapMuzzle3, value, sizeof(weapMuzzle3) );
01093                 }
01094                 else if ( Q_stricmp( "weapMuzzle4", parmName ) == 0 )
01095                 {//hmm, store this off because we don't want to call another one of these text parsing routines while we're in the middle of one...
01096                         Q_strncpyz( weapMuzzle4, value, sizeof(weapMuzzle4) );
01097                 }
01098                 else if ( Q_stricmp( "weapMuzzle5", parmName ) == 0 )
01099                 {//hmm, store this off because we don't want to call another one of these text parsing routines while we're in the middle of one...
01100                         Q_strncpyz( weapMuzzle5, value, sizeof(weapMuzzle5) );
01101                 }
01102                 else if ( Q_stricmp( "weapMuzzle6", parmName ) == 0 )
01103                 {//hmm, store this off because we don't want to call another one of these text parsing routines while we're in the middle of one...
01104                         Q_strncpyz( weapMuzzle6, value, sizeof(weapMuzzle6) );
01105                 }
01106                 else if ( Q_stricmp( "weapMuzzle7", parmName ) == 0 )
01107                 {//hmm, store this off because we don't want to call another one of these text parsing routines while we're in the middle of one...
01108                         Q_strncpyz( weapMuzzle7, value, sizeof(weapMuzzle7) );
01109                 }
01110                 else if ( Q_stricmp( "weapMuzzle8", parmName ) == 0 )
01111                 {//hmm, store this off because we don't want to call another one of these text parsing routines while we're in the middle of one...
01112                         Q_strncpyz( weapMuzzle8, value, sizeof(weapMuzzle8) );
01113                 }
01114                 else if ( Q_stricmp( "weapMuzzle9", parmName ) == 0 )
01115                 {//hmm, store this off because we don't want to call another one of these text parsing routines while we're in the middle of one...
01116                         Q_strncpyz( weapMuzzle9, value, sizeof(weapMuzzle9) );
01117                 }
01118                 else if ( Q_stricmp( "weapMuzzle10", parmName ) == 0 )
01119                 {//hmm, store this off because we don't want to call another one of these text parsing routines while we're in the middle of one...
01120                         Q_strncpyz( weapMuzzle10, value, sizeof(weapMuzzle10) );
01121                 }
01122                 else
01123                 {
01124                         if ( !BG_ParseVehicleParm( vehicle, parmName, value ) )
01125                         {
01126 #ifndef FINAL_BUILD
01127                                 Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair '%s', '%s'!\n", parmName, value );
01128 #endif
01129                         }
01130                 }
01131         }
01132         //NOW: if we have any weapons, go ahead and load them
01133         if ( weap1[0] )
01134         {
01135                 if ( !BG_ParseVehicleParm( vehicle, "weap1", weap1 ) )
01136                 {
01137 #ifndef FINAL_BUILD
01138                         Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weap1', '%s'!\n", weap1 );
01139 #endif
01140                 }
01141         }
01142         if ( weap2[0] )
01143         {
01144                 if ( !BG_ParseVehicleParm( vehicle, "weap2", weap2 ) )
01145                 {
01146 #ifndef FINAL_BUILD
01147                         Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weap2', '%s'!\n", weap2 );
01148 #endif
01149                 }
01150         }
01151         if ( weapMuzzle1[0] )
01152         {
01153                 if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle1", weapMuzzle1 ) )
01154                 {
01155 #ifndef FINAL_BUILD
01156                         Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle1', '%s'!\n", weapMuzzle1 );
01157 #endif
01158                 }
01159         }
01160         if ( weapMuzzle2[0] )
01161         {
01162                 if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle2", weapMuzzle2 ) )
01163                 {
01164 #ifndef FINAL_BUILD
01165                         Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle2', '%s'!\n", weapMuzzle2 );
01166 #endif
01167                 }
01168         }
01169         if ( weapMuzzle3[0] )
01170         {
01171                 if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle3", weapMuzzle3 ) )
01172                 {
01173 #ifndef FINAL_BUILD
01174                         Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle3', '%s'!\n", weapMuzzle3 );
01175 #endif
01176                 }
01177         }
01178         if ( weapMuzzle4[0] )
01179         {
01180                 if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle4", weapMuzzle4 ) )
01181                 {
01182 #ifndef FINAL_BUILD
01183                         Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle4', '%s'!\n", weapMuzzle4 );
01184 #endif
01185                 }
01186         }
01187         if ( weapMuzzle5[0] )
01188         {
01189                 if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle5", weapMuzzle5 ) )
01190                 {
01191 #ifndef FINAL_BUILD
01192                         Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle5', '%s'!\n", weapMuzzle5 );
01193 #endif
01194                 }
01195         }
01196         if ( weapMuzzle6[0] )
01197         {
01198                 if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle6", weapMuzzle6 ) )
01199                 {
01200 #ifndef FINAL_BUILD
01201                         Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle6', '%s'!\n", weapMuzzle6 );
01202 #endif
01203                 }
01204         }
01205         if ( weapMuzzle7[0] )
01206         {
01207                 if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle7", weapMuzzle7 ) )
01208                 {
01209 #ifndef FINAL_BUILD
01210                         Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle7', '%s'!\n", weapMuzzle7 );
01211 #endif
01212                 }
01213         }
01214         if ( weapMuzzle8[0] )
01215         {
01216                 if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle8", weapMuzzle8 ) )
01217                 {
01218 #ifndef FINAL_BUILD
01219                         Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle8', '%s'!\n", weapMuzzle8 );
01220 #endif
01221                 }
01222         }
01223         if ( weapMuzzle9[0] )
01224         {
01225                 if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle9", weapMuzzle9 ) )
01226                 {
01227 #ifndef FINAL_BUILD
01228                         Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle9', '%s'!\n", weapMuzzle9 );
01229 #endif
01230                 }
01231         }
01232         if ( weapMuzzle10[0] )
01233         {
01234                 if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle10", weapMuzzle10 ) )
01235                 {
01236 #ifndef FINAL_BUILD
01237                         Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle10', '%s'!\n", weapMuzzle10 );
01238 #endif
01239                 }
01240         }
01241 
01242 #ifdef _JK2MP
01243         //let's give these guys some defaults
01244         if (!vehicle->health_front)
01245         {
01246                 vehicle->health_front = vehicle->armor/4;
01247         }
01248         if (!vehicle->health_back)
01249         {
01250                 vehicle->health_back = vehicle->armor/4;
01251         }
01252         if (!vehicle->health_right)
01253         {
01254                 vehicle->health_right = vehicle->armor/4;
01255         }
01256         if (!vehicle->health_left)
01257         {
01258                 vehicle->health_left = vehicle->armor/4;
01259         }
01260 #endif
01261 
01262         if ( vehicle->model )
01263         {
01264 #ifdef QAGAME
01265                 vehicle->modelIndex = G_ModelIndex( va( "models/players/%s/model.glm", vehicle->model ) );
01266 #else
01267                 vehicle->modelIndex = trap_R_RegisterModel( va( "models/players/%s/model.glm", vehicle->model ) );
01268 #endif
01269         }
01270 
01271 #ifndef _JK2MP
01272         //SP
01273         if ( vehicle->skin
01274                 && vehicle->skin[0] )
01275         {
01276                 ratl::string_vs<256>                    skins(vehicle->skin);
01277                 for (ratl::string_vs<256>::tokenizer i = skins.begin("|"); i!=skins.end(); i++)
01278                 {
01279                         //this will just turn off surfs if there is a *off shader on a surf, the skin will actually get thrown away when cgame starts
01280                         gi.RE_RegisterSkin( va( "models/players/%s/model_%s.skin", vehicle->model, *i) );
01281                         //this is for the server-side call, it will propgate down to cgame with configstrings and register it at the same time as all the other skins for ghoul2 models
01282                         G_SkinIndex( va( "models/players/%s/model_%s.skin", vehicle->model, *i) );
01283                 }
01284         }
01285         else
01286         {
01287                 //this will just turn off surfs if there is a *off shader on a surf, the skin will actually get thrown away when cgame starts
01288                 gi.RE_RegisterSkin( va( "models/players/%s/model_default.skin", vehicle->model) );
01289                 //this is for the server-side call, it will propgate down to cgame with configstrings and register it at the same time as all the other skins for ghoul2 models
01290                 G_SkinIndex( va( "models/players/%s/model_default.skin", vehicle->model) );
01291         }
01292 #else
01293 #ifndef QAGAME
01294         if ( vehicle->skin
01295                 && vehicle->skin[0] )
01296         {
01297                 trap_R_RegisterSkin( va( "models/players/%s/model_%s.skin", vehicle->model, vehicle->skin) );
01298         }
01299 #endif
01300 #endif
01301         //sanity check and clamp the vehicle's data
01302         BG_VehicleClampData( vehicle );
01303         // Setup the shared function pointers.
01304         BG_SetSharedVehicleFunctions( vehicle );
01305         //misc effects... FIXME: not even used in MP, are they?
01306         if ( vehicle->explosionDamage )
01307         {
01308 #ifdef QAGAME
01309                 G_EffectIndex( "ships/ship_explosion_mark" );
01310 #elif CGAME
01311                 trap_FX_RegisterEffect( "ships/ship_explosion_mark" );
01312 #endif
01313         }
01314         if ( vehicle->flammable )
01315         {
01316 #ifdef QAGAME
01317                 G_SoundIndex( "sound/vehicles/common/fire_lp.wav" );
01318 #elif CGAME
01319                 trap_S_RegisterSound( "sound/vehicles/common/fire_lp.wav" );
01320 #else
01321                 trap_S_RegisterSound( "sound/vehicles/common/fire_lp.wav" );
01322 #endif
01323         }
01324 
01325         if ( vehicle->hoverHeight > 0 )
01326         {
01327 #ifndef _JK2MP
01328                 G_EffectIndex( "ships/swoop_dust" );
01329 #elif QAGAME
01330                 G_EffectIndex( "ships/swoop_dust" );
01331 #elif CGAME
01332                 trap_FX_RegisterEffect( "ships/swoop_dust" );
01333 #endif
01334         }
01335 
01336 #ifdef QAGAME
01337         G_EffectIndex( "volumetric/black_smoke" );
01338         G_EffectIndex( "ships/fire" );
01339         G_SoundIndex( "sound/vehicles/common/release.wav" );
01340 #elif CGAME
01341         trap_R_RegisterShader( "gfx/menus/radar/bracket" );
01342         trap_R_RegisterShader( "gfx/menus/radar/lead" );
01343         trap_R_RegisterShaderNoMip( "gfx/menus/radar/asteroid" );
01344         trap_S_RegisterSound( "sound/vehicles/common/impactalarm.wav" );
01345         trap_S_RegisterSound( "sound/vehicles/common/linkweaps.wav" );
01346         trap_S_RegisterSound( "sound/vehicles/common/release.wav" );
01347         trap_FX_RegisterEffect("effects/ships/dest_burning.efx");
01348         trap_FX_RegisterEffect("effects/ships/dest_destroyed.efx");
01349         trap_FX_RegisterEffect( "volumetric/black_smoke" );
01350         trap_FX_RegisterEffect( "ships/fire" );
01351         trap_FX_RegisterEffect("ships/hyperspace_stars");
01352 
01353         if ( vehicle->hideRider )
01354         {
01355                 trap_R_RegisterShaderNoMip( "gfx/menus/radar/circle_base" );
01356                 trap_R_RegisterShaderNoMip( "gfx/menus/radar/circle_base_frame" );
01357                 trap_R_RegisterShaderNoMip( "gfx/menus/radar/circle_base_shield" );
01358         }
01359 #endif
01360 
01361         return (numVehicles++);
01362 }
01363 
01364 int VEH_VehicleIndexForName( const char *vehicleName )
01365 {
01366         int v;
01367         if ( !vehicleName || !vehicleName[0] )
01368         {
01369                 Com_Printf( S_COLOR_RED"ERROR: Trying to read Vehicle with no name!\n" );
01370                 return VEHICLE_NONE;
01371         }
01372         for (  v = VEHICLE_BASE; v < numVehicles; v++ )
01373         {
01374                 if ( g_vehicleInfo[v].name
01375                         && Q_stricmp( g_vehicleInfo[v].name, vehicleName ) == 0 )
01376                 {//already loaded this one
01377                         return v;
01378                 }
01379         }
01380         //haven't loaded it yet
01381         if ( v >= MAX_VEHICLES )
01382         {//no more room!
01383                 Com_Printf( S_COLOR_RED"ERROR: Too many Vehicles (max 64), aborting load on %s!\n", vehicleName );
01384                 return VEHICLE_NONE;
01385         }
01386         //we have room for another one, load it up and return the index
01387         //HMM... should we not even load the .veh file until we want to?
01388         v = VEH_LoadVehicle( vehicleName ); 
01389         if ( v == VEHICLE_NONE )
01390         {
01391                 Com_Printf( S_COLOR_RED"ERROR: Could not find Vehicle %s!\n", vehicleName );
01392         }
01393         return v;
01394 }
01395 
01396 void BG_VehWeaponLoadParms( void ) 
01397 {
01398         int                     len, totallen, vehExtFNLen, mainBlockLen, fileCnt, i;
01399         char            *holdChar, *marker;
01400         char            vehWeaponExtensionListBuf[2048];                        //      The list of file names read in
01401         fileHandle_t    f;
01402         char            *tempReadBuffer;
01403 
01404         len = 0;
01405 
01406         //remember where to store the next one
01407         totallen = mainBlockLen = len;
01408         marker = VehWeaponParms+totallen;
01409         *marker = 0;
01410 
01411         //now load in the extra .veh extensions
01412 #ifdef _JK2MP
01413         fileCnt = trap_FS_GetFileList("ext_data/vehicles/weapons", ".vwp", vehWeaponExtensionListBuf, sizeof(vehWeaponExtensionListBuf) );
01414 #else
01415         fileCnt = gi.FS_GetFileList("ext_data/vehicles/weapons", ".vwp", vehWeaponExtensionListBuf, sizeof(vehWeaponExtensionListBuf) );
01416 #endif
01417 
01418         holdChar = vehWeaponExtensionListBuf;
01419 
01420 #ifdef _JK2MP
01421         tempReadBuffer = (char *)BG_TempAlloc(MAX_VEH_WEAPON_DATA_SIZE);
01422 #else
01423         tempReadBuffer = (char *)gi.Malloc( MAX_VEH_WEAPON_DATA_SIZE, TAG_G_ALLOC, qtrue );
01424 #endif
01425         
01426         // NOTE: Not use TempAlloc anymore...
01427         //Make ABSOLUTELY CERTAIN that BG_Alloc/etc. is not used before
01428         //the subsequent BG_TempFree or the pool will be screwed. 
01429 
01430         for ( i = 0; i < fileCnt; i++, holdChar += vehExtFNLen + 1 ) 
01431         {
01432                 vehExtFNLen = strlen( holdChar );
01433 
01434 //              Com_Printf( "Parsing %s\n", holdChar );
01435 
01436 #ifdef _JK2MP
01437                 len = trap_FS_FOpenFile(va( "ext_data/vehicles/weapons/%s", holdChar), &f, FS_READ);
01438 #else
01439 //              len = gi.FS_ReadFile( va( "ext_data/vehicles/weapons/%s", holdChar), (void **) &buffer );
01440                 len = gi.FS_FOpenFile(va( "ext_data/vehicles/weapons/%s", holdChar), &f, FS_READ);
01441 #endif
01442 
01443                 if ( len == -1 ) 
01444                 {
01445                         Com_Printf( "error reading file\n" );
01446                 }
01447                 else
01448                 {
01449 #ifdef _JK2MP
01450                         trap_FS_Read(tempReadBuffer, len, f);
01451                         tempReadBuffer[len] = 0;
01452 #else
01453                         gi.FS_Read(tempReadBuffer, len, f);
01454                         tempReadBuffer[len] = 0;
01455 #endif
01456 
01457                         // Don't let it end on a } because that should be a stand-alone token.
01458                         if ( totallen && *(marker-1) == '}' )
01459                         {
01460                                 strcat( marker, " " );
01461                                 totallen++;
01462                                 marker++; 
01463                         }
01464 
01465                         if ( totallen + len >= MAX_VEH_WEAPON_DATA_SIZE ) {
01466                                 Com_Error(ERR_DROP, "Vehicle Weapon extensions (*.vwp) are too large" );
01467                         }
01468                         strcat( marker, tempReadBuffer );
01469 #ifdef _JK2MP
01470                         trap_FS_FCloseFile( f );
01471 #else
01472                         gi.FS_FCloseFile( f );
01473 #endif
01474 
01475                         totallen += len;
01476                         marker = VehWeaponParms+totallen;
01477                 }
01478         }
01479 
01480 #ifdef _JK2MP
01481         BG_TempFree(MAX_VEH_WEAPON_DATA_SIZE);
01482 #else
01483         gi.Free(tempReadBuffer);        tempReadBuffer = NULL;
01484 #endif
01485 }
01486 
01487 void BG_VehicleLoadParms( void ) 
01488 {//HMM... only do this if there's a vehicle on the level?
01489         int                     len, totallen, vehExtFNLen, mainBlockLen, fileCnt, i;
01490 //      const char      *filename = "ext_data/vehicles.dat";
01491         char            *holdChar, *marker;
01492         char            vehExtensionListBuf[2048];                      //      The list of file names read in
01493         fileHandle_t    f;
01494         char            *tempReadBuffer;
01495 
01496         len = 0;
01497 
01498         //remember where to store the next one
01499         totallen = mainBlockLen = len;
01500         marker = VehicleParms+totallen;
01501         *marker = 0;
01502 
01503         //now load in the extra .veh extensions
01504 #ifdef _JK2MP
01505         fileCnt = trap_FS_GetFileList("ext_data/vehicles", ".veh", vehExtensionListBuf, sizeof(vehExtensionListBuf) );
01506 #else
01507         fileCnt = gi.FS_GetFileList("ext_data/vehicles", ".veh", vehExtensionListBuf, sizeof(vehExtensionListBuf) );
01508 #endif
01509 
01510         holdChar = vehExtensionListBuf;
01511 
01512 #ifdef _JK2MP
01513         tempReadBuffer = (char *)BG_TempAlloc(MAX_VEHICLE_DATA_SIZE);
01514 #else
01515         tempReadBuffer = (char *)gi.Malloc( MAX_VEHICLE_DATA_SIZE, TAG_G_ALLOC, qtrue );
01516 #endif
01517         
01518         // NOTE: Not use TempAlloc anymore...
01519         //Make ABSOLUTELY CERTAIN that BG_Alloc/etc. is not used before
01520         //the subsequent BG_TempFree or the pool will be screwed. 
01521 
01522         for ( i = 0; i < fileCnt; i++, holdChar += vehExtFNLen + 1 ) 
01523         {
01524                 vehExtFNLen = strlen( holdChar );
01525 
01526 //              Com_Printf( "Parsing %s\n", holdChar );
01527 
01528 #ifdef _JK2MP
01529                 len = trap_FS_FOpenFile(va( "ext_data/vehicles/%s", holdChar), &f, FS_READ);
01530 #else
01531 //              len = gi.FS_ReadFile( va( "ext_data/vehicles/%s", holdChar), (void **) &buffer );
01532                 len = gi.FS_FOpenFile(va( "ext_data/vehicles/%s", holdChar), &f, FS_READ);
01533 #endif
01534 
01535                 if ( len == -1 ) 
01536                 {
01537                         Com_Printf( "error reading file\n" );
01538                 }
01539                 else
01540                 {
01541 #ifdef _JK2MP
01542                         trap_FS_Read(tempReadBuffer, len, f);
01543                         tempReadBuffer[len] = 0;
01544 #else
01545                         gi.FS_Read(tempReadBuffer, len, f);
01546                         tempReadBuffer[len] = 0;
01547 #endif
01548 
01549                         // Don't let it end on a } because that should be a stand-alone token.
01550                         if ( totallen && *(marker-1) == '}' )
01551                         {
01552                                 strcat( marker, " " );
01553                                 totallen++;
01554                                 marker++; 
01555                         }
01556 
01557                         if ( totallen + len >= MAX_VEHICLE_DATA_SIZE ) {
01558                                 Com_Error(ERR_DROP, "Vehicle extensions (*.veh) are too large" );
01559                         }
01560                         strcat( marker, tempReadBuffer );
01561 #ifdef _JK2MP
01562                         trap_FS_FCloseFile( f );
01563 #else
01564                         gi.FS_FCloseFile( f );
01565 #endif
01566 
01567                         totallen += len;
01568                         marker = VehicleParms+totallen;
01569                 }
01570         }
01571 
01572 #ifdef _JK2MP
01573         BG_TempFree(MAX_VEHICLE_DATA_SIZE);
01574 #else
01575         gi.Free(tempReadBuffer);        tempReadBuffer = NULL;
01576 #endif
01577         
01578         numVehicles = 1;//first one is null/default
01579         //set the first vehicle to default data
01580         BG_VehicleSetDefaults( &g_vehicleInfo[VEHICLE_BASE] );
01581         //sanity check and clamp the vehicle's data
01582         BG_VehicleClampData( &g_vehicleInfo[VEHICLE_BASE] );
01583         // Setup the shared function pointers.
01584         BG_SetSharedVehicleFunctions( &g_vehicleInfo[VEHICLE_BASE] );
01585 
01586         //Load the Vehicle Weapons data, too
01587         BG_VehWeaponLoadParms();
01588 }
01589 
01590 int BG_VehicleGetIndex( const char *vehicleName )
01591 {
01592         return (VEH_VehicleIndexForName( vehicleName ));
01593 }
01594 
01595 //We get the vehicle name passed in as modelname
01596 //with a $ in front of it.
01597 //we are expected to then get the model for the
01598 //vehicle and stomp over modelname with it.
01599 void BG_GetVehicleModelName(char *modelname)
01600 {
01601         char *vehName = &modelname[1];
01602         int vIndex = BG_VehicleGetIndex(vehName);
01603         assert(modelname[0] == '$');
01604         
01605         if (vIndex == VEHICLE_NONE)
01606         {
01607                 Com_Error(ERR_DROP, "BG_GetVehicleModelName:  couldn't find vehicle %s", vehName);
01608         }
01609 
01610     strcpy(modelname, g_vehicleInfo[vIndex].model);     
01611 }
01612 
01613 void BG_GetVehicleSkinName(char *skinname)
01614 {
01615         char *vehName = &skinname[1];
01616         int vIndex = BG_VehicleGetIndex(vehName);
01617         assert(skinname[0] == '$');
01618         
01619         if (vIndex == VEHICLE_NONE)
01620         {
01621                 Com_Error(ERR_DROP, "BG_GetVehicleSkinName:  couldn't find vehicle %s", vehName);
01622         }
01623 
01624     if ( !g_vehicleInfo[vIndex].skin 
01625                 || !g_vehicleInfo[vIndex].skin[0] )
01626         {
01627                 skinname[0] = 0;
01628         }
01629         else
01630         {
01631                 strcpy(skinname, g_vehicleInfo[vIndex].skin);   
01632         }
01633 }
01634 
01635 #ifdef _JK2MP
01636 #ifndef WE_ARE_IN_THE_UI
01637 //so cgame can assign the function pointer for the vehicle attachment without having to
01638 //bother with all the other funcs that don't really exist cgame-side.
01639 extern int BG_GetTime(void);
01640 extern int trap_G2API_AddBolt(void *ghoul2, int modelIndex, const char *boneName);
01641 extern qboolean trap_G2API_GetBoltMatrix(void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix,
01642                                                                 const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale);
01643 void AttachRidersGeneric( Vehicle_t *pVeh )
01644 {
01645         // If we have a pilot, attach him to the driver tag.
01646         if ( pVeh->m_pPilot )
01647         {
01648                 mdxaBone_t boltMatrix;
01649                 vec3_t  yawOnlyAngles;
01650                 bgEntity_t *parent = pVeh->m_pParentEntity;
01651                 bgEntity_t *pilot = pVeh->m_pPilot;
01652                 int crotchBolt = trap_G2API_AddBolt(parent->ghoul2, 0, "*driver");
01653 
01654                 assert(parent->playerState);
01655 
01656                 VectorSet(yawOnlyAngles, 0, parent->playerState->viewangles[YAW], 0);
01657 
01658                 // Get the driver tag.
01659                 trap_G2API_GetBoltMatrix( parent->ghoul2, 0, crotchBolt, &boltMatrix,
01660                                                                 yawOnlyAngles, parent->playerState->origin,
01661                                                                 BG_GetTime(), NULL, parent->modelScale );
01662                 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, pilot->playerState->origin );
01663         }
01664 }
01665 #endif
01666 
01667 #include "../namespace_end.h"
01668 
01669 #endif // _JK2MP
01670