bg_vehicleload.c 65 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679
  1. //bg_vehicleLoad.c
  2. #ifdef _JK2 //SP does not have this preprocessor for game like MP does
  3. #ifndef _JK2MP
  4. #define _JK2MP
  5. #endif
  6. #endif
  7. #ifdef _JK2MP
  8. #include "q_shared.h"
  9. #include "bg_public.h"
  10. #include "bg_vehicles.h"
  11. #include "bg_weapons.h"
  12. //Could use strap stuff but I don't particularly care at the moment anyway.
  13. #include "../namespace_begin.h"
  14. extern int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
  15. extern void trap_FS_Read( void *buffer, int len, fileHandle_t f );
  16. extern void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
  17. extern void trap_FS_FCloseFile( fileHandle_t f );
  18. extern int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
  19. #include "../namespace_end.h"
  20. #else
  21. #include "g_local.h"
  22. #define QAGAME
  23. #endif
  24. #ifdef _JK2MP
  25. #ifndef QAGAME
  26. #ifndef CGAME
  27. #define WE_ARE_IN_THE_UI
  28. #include "../ui/ui_local.h"
  29. #endif
  30. #endif
  31. #endif
  32. #ifndef _JK2MP
  33. #include "..\Ratl\string_vs.h"
  34. #endif
  35. #ifdef QAGAME
  36. extern void G_SetSharedVehicleFunctions( vehicleInfo_t *pVehInfo );
  37. extern int G_ModelIndex( const char *name );
  38. extern int G_SoundIndex( const char *name );
  39. #ifdef _JK2MP
  40. extern int G_EffectIndex( const char *name );
  41. #endif
  42. #elif CGAME
  43. #include "../namespace_begin.h"
  44. extern qhandle_t trap_R_RegisterModel( const char *name ); // returns rgb axis if not found
  45. extern qhandle_t trap_R_RegisterSkin( const char *name ); // returns all white if not found
  46. extern qhandle_t trap_R_RegisterShader( const char *name );
  47. extern qhandle_t trap_R_RegisterShaderNoMip( const char *name );
  48. extern int trap_FX_RegisterEffect(const char *file);
  49. extern sfxHandle_t trap_S_RegisterSound( const char *sample); // returns buzz if not found
  50. #include "../namespace_end.h"
  51. #else//UI
  52. #include "../namespace_begin.h"
  53. extern qhandle_t trap_R_RegisterModel( const char *name ); // returns rgb axis if not found
  54. extern qhandle_t trap_R_RegisterSkin( const char *name ); // returns all white if not found
  55. extern qhandle_t trap_R_RegisterShader( const char *name ); // returns all white if not found
  56. extern qhandle_t trap_R_RegisterShaderNoMip( const char *name ); // returns all white if not found
  57. extern sfxHandle_t trap_S_RegisterSound( const char *sample); // returns buzz if not found
  58. #include "../namespace_end.h"
  59. #endif
  60. extern stringID_table_t animTable [MAX_ANIMATIONS+1];
  61. // These buffers are filled in with the same contents and then just read from in
  62. // a few places. We only need one copy on Xbox.
  63. #define MAX_VEH_WEAPON_DATA_SIZE 0x4000
  64. #define MAX_VEHICLE_DATA_SIZE 0x10000
  65. #if !defined(_XBOX) || defined(QAGAME)
  66. char VehWeaponParms[MAX_VEH_WEAPON_DATA_SIZE];
  67. char VehicleParms[MAX_VEHICLE_DATA_SIZE];
  68. void BG_ClearVehicleParseParms(void)
  69. {
  70. //You can't strcat to these forever without clearing them!
  71. VehWeaponParms[0] = 0;
  72. VehicleParms[0] = 0;
  73. }
  74. #else
  75. extern char VehWeaponParms[MAX_VEH_WEAPON_DATA_SIZE];
  76. extern char VehicleParms[MAX_VEHICLE_DATA_SIZE];
  77. #endif
  78. #ifdef _JK2MP
  79. #include "../namespace_begin.h"
  80. #endif
  81. #ifndef WE_ARE_IN_THE_UI
  82. //These funcs are actually shared in both projects
  83. extern void G_SetAnimalVehicleFunctions( vehicleInfo_t *pVehInfo );
  84. extern void G_SetSpeederVehicleFunctions( vehicleInfo_t *pVehInfo );
  85. extern void G_SetWalkerVehicleFunctions( vehicleInfo_t *pVehInfo );
  86. extern void G_SetFighterVehicleFunctions( vehicleInfo_t *pVehInfo );
  87. #endif
  88. vehWeaponInfo_t g_vehWeaponInfo[MAX_VEH_WEAPONS];
  89. int numVehicleWeapons = 1;//first one is null/default
  90. vehicleInfo_t g_vehicleInfo[MAX_VEHICLES];
  91. int numVehicles = 0;//first one is null/default
  92. // Used by Xbox to reset all the kruft between levels
  93. void BG_ClearVehicles(void)
  94. {
  95. numVehicleWeapons = 1;
  96. memset( g_vehWeaponInfo, 0, sizeof(g_vehWeaponInfo) );
  97. numVehicles = 0;
  98. memset( g_vehicleInfo, 0, sizeof(g_vehicleInfo) );
  99. }
  100. void BG_VehicleLoadParms( void );
  101. typedef enum {
  102. VF_IGNORE,
  103. VF_INT,
  104. VF_FLOAT,
  105. VF_LSTRING, // string on disk, pointer in memory, TAG_LEVEL
  106. VF_VECTOR,
  107. VF_BOOL,
  108. VF_VEHTYPE,
  109. VF_ANIM,
  110. VF_WEAPON, // take string, resolve into index into VehWeaponParms
  111. VF_MODEL, // take the string, get the G_ModelIndex
  112. VF_MODEL_CLIENT, // (cgame only) take the string, get the G_ModelIndex
  113. VF_EFFECT, // take the string, get the G_EffectIndex
  114. VF_EFFECT_CLIENT, // (cgame only) take the string, get the index
  115. VF_SHADER, // (cgame only) take the string, call trap_R_RegisterShader
  116. VF_SHADER_NOMIP,// (cgame only) take the string, call trap_R_RegisterShaderNoMip
  117. VF_SOUND, // take the string, get the G_SoundIndex
  118. VF_SOUND_CLIENT // (cgame only) take the string, get the index
  119. } vehFieldType_t;
  120. typedef struct
  121. {
  122. char *name;
  123. int ofs;
  124. vehFieldType_t type;
  125. } vehField_t;
  126. vehField_t vehWeaponFields[NUM_VWEAP_PARMS] =
  127. {
  128. {"name", VWFOFS(name), VF_LSTRING}, //unique name of the vehicle
  129. {"projectile", VWFOFS(bIsProjectile), VF_BOOL}, //traceline or entity?
  130. {"hasGravity", VWFOFS(bHasGravity), VF_BOOL}, //if a projectile, drops
  131. {"ionWeapon", VWFOFS(bIonWeapon), VF_BOOL}, //disables ship shields and sends them out of control
  132. {"saberBlockable", VWFOFS(bSaberBlockable), VF_BOOL}, //lightsabers can deflect this projectile
  133. {"muzzleFX", VWFOFS(iMuzzleFX), VF_EFFECT_CLIENT}, //index of Muzzle Effect
  134. {"model", VWFOFS(iModel), VF_MODEL_CLIENT}, //handle to the model used by this projectile
  135. {"shotFX", VWFOFS(iShotFX), VF_EFFECT_CLIENT}, //index of Shot Effect
  136. {"impactFX", VWFOFS(iImpactFX), VF_EFFECT_CLIENT}, //index of Impact Effect
  137. {"g2MarkShader", VWFOFS(iG2MarkShaderHandle), VF_SHADER}, //index of shader to use for G2 marks made on other models when hit by this projectile
  138. {"g2MarkSize", VWFOFS(fG2MarkSize), VF_FLOAT}, //size (diameter) of the ghoul2 mark
  139. {"loopSound", VWFOFS(iLoopSound), VF_SOUND_CLIENT}, //index of loopSound
  140. {"speed", VWFOFS(fSpeed), VF_FLOAT}, //speed of projectile/range of traceline
  141. {"homing", VWFOFS(fHoming), VF_FLOAT}, //0.0 = not homing, 0.5 = half vel to targ, half cur vel, 1.0 = all vel to targ
  142. {"lockOnTime", VWFOFS(iLockOnTime), VF_INT}, //0 = no lock time needed, else # of ms needed to lock on
  143. {"damage", VWFOFS(iDamage), VF_INT}, //damage done when traceline or projectile directly hits target
  144. {"splashDamage", VWFOFS(iSplashDamage), VF_INT},//damage done to ents in splashRadius of end of traceline or projectile origin on impact
  145. {"splashRadius", VWFOFS(fSplashRadius), VF_FLOAT},//radius that ent must be in to take splashDamage (linear fall-off)
  146. {"ammoPerShot", VWFOFS(iAmmoPerShot), VF_INT},//how much "ammo" each shot takes
  147. {"health", VWFOFS(iHealth), VF_INT}, //if non-zero, projectile can be shot, takes this much damage before being destroyed
  148. {"width", VWFOFS(fWidth), VF_FLOAT}, //width of traceline or bounding box of projecile (non-rotating!)
  149. {"height", VWFOFS(fHeight), VF_FLOAT}, //height of traceline or bounding box of projecile (non-rotating!)
  150. {"lifetime", VWFOFS(iLifeTime), VF_INT}, //removes itself after this amount of time
  151. {"explodeOnExpire", VWFOFS(bExplodeOnExpire), VF_BOOL}, //when iLifeTime is up, explodes rather than simply removing itself
  152. };
  153. static qboolean BG_ParseVehWeaponParm( vehWeaponInfo_t *vehWeapon, char *parmName, char *pValue )
  154. {
  155. int i;
  156. vec3_t vec;
  157. byte *b = (byte *)vehWeapon;
  158. int _iFieldsRead = 0;
  159. vehicleType_t vehType;
  160. char value[1024];
  161. Q_strncpyz( value, pValue, sizeof(value) );
  162. // Loop through possible parameters
  163. for ( i = 0; i < NUM_VWEAP_PARMS; i++ )
  164. {
  165. if ( vehWeaponFields[i].name && !Q_stricmp( vehWeaponFields[i].name, parmName ) )
  166. {
  167. // found it
  168. switch( vehWeaponFields[i].type )
  169. {
  170. case VF_INT:
  171. *(int *)(b+vehWeaponFields[i].ofs) = atoi(value);
  172. break;
  173. case VF_FLOAT:
  174. *(float *)(b+vehWeaponFields[i].ofs) = atof(value);
  175. break;
  176. case VF_LSTRING: // string on disk, pointer in memory, TAG_LEVEL
  177. if (!*(char **)(b+vehWeaponFields[i].ofs))
  178. { //just use 1024 bytes in case we want to write over the string
  179. #ifdef _JK2MP
  180. *(char **)(b+vehWeaponFields[i].ofs) = (char *)BG_Alloc(1024);//(char *)BG_Alloc(strlen(value));
  181. strcpy(*(char **)(b+vehWeaponFields[i].ofs), value);
  182. #else
  183. (*(char **)(b+vehWeaponFields[i].ofs)) = G_NewString( value );
  184. #endif
  185. }
  186. break;
  187. case VF_VECTOR:
  188. _iFieldsRead = sscanf (value, "%f %f %f", &vec[0], &vec[1], &vec[2]);
  189. assert(_iFieldsRead==3 );
  190. if (_iFieldsRead!=3)
  191. {
  192. Com_Printf (S_COLOR_YELLOW"BG_ParseVehWeaponParm: VEC3 sscanf() failed to read 3 floats ('angle' key bug?)\n");
  193. }
  194. ((float *)(b+vehWeaponFields[i].ofs))[0] = vec[0];
  195. ((float *)(b+vehWeaponFields[i].ofs))[1] = vec[1];
  196. ((float *)(b+vehWeaponFields[i].ofs))[2] = vec[2];
  197. break;
  198. case VF_BOOL:
  199. *(qboolean *)(b+vehWeaponFields[i].ofs) = (qboolean)(atof(value)!=0);
  200. break;
  201. case VF_VEHTYPE:
  202. vehType = (vehicleType_t)GetIDForString( VehicleTable, value );
  203. *(vehicleType_t *)(b+vehWeaponFields[i].ofs) = vehType;
  204. break;
  205. case VF_ANIM:
  206. {
  207. int anim = GetIDForString( animTable, value );
  208. *(int *)(b+vehWeaponFields[i].ofs) = anim;
  209. }
  210. break;
  211. case VF_WEAPON: // take string, resolve into index into VehWeaponParms
  212. //*(int *)(b+vehWeaponFields[i].ofs) = VEH_VehWeaponIndexForName( value );
  213. break;
  214. case VF_MODEL:// take the string, get the G_ModelIndex
  215. #ifdef QAGAME
  216. *(int *)(b+vehWeaponFields[i].ofs) = G_ModelIndex( value );
  217. #else
  218. *(int *)(b+vehWeaponFields[i].ofs) = trap_R_RegisterModel( value );
  219. #endif
  220. break;
  221. case VF_MODEL_CLIENT: // (MP cgame only) take the string, get the G_ModelIndex
  222. #ifndef _JK2MP
  223. *(int *)(b+vehWeaponFields[i].ofs) = G_ModelIndex( value );
  224. #elif QAGAME
  225. //*(int *)(b+vehWeaponFields[i].ofs) = G_ModelIndex( value );
  226. #else
  227. *(int *)(b+vehWeaponFields[i].ofs) = trap_R_RegisterModel( value );
  228. #endif
  229. break;
  230. case VF_EFFECT: // take the string, get the G_EffectIndex
  231. #ifdef QAGAME
  232. *(int *)(b+vehWeaponFields[i].ofs) = G_EffectIndex( value );
  233. #elif CGAME
  234. *(int *)(b+vehWeaponFields[i].ofs) = trap_FX_RegisterEffect( value );
  235. #endif
  236. break;
  237. case VF_EFFECT_CLIENT: // (MP cgame only) take the string, get the index
  238. #ifndef _JK2MP
  239. *(int *)(b+vehWeaponFields[i].ofs) = G_EffectIndex( value );
  240. #elif QAGAME
  241. //*(int *)(b+vehWeaponFields[i].ofs) = G_EffectIndex( value );
  242. #elif CGAME
  243. *(int *)(b+vehWeaponFields[i].ofs) = trap_FX_RegisterEffect( value );
  244. #endif
  245. break;
  246. case VF_SHADER: // (cgame only) take the string, call trap_R_RegisterShader
  247. #ifdef WE_ARE_IN_THE_UI
  248. *(int *)(b+vehWeaponFields[i].ofs) = trap_R_RegisterShaderNoMip( value );
  249. #elif CGAME
  250. *(int *)(b+vehWeaponFields[i].ofs) = trap_R_RegisterShader( value );
  251. #endif
  252. break;
  253. case VF_SHADER_NOMIP:// (cgame only) take the string, call trap_R_RegisterShaderNoMip
  254. #ifndef QAGAME
  255. *(int *)(b+vehWeaponFields[i].ofs) = trap_R_RegisterShaderNoMip( value );
  256. #endif
  257. break;
  258. case VF_SOUND: // take the string, get the G_SoundIndex
  259. #ifdef QAGAME
  260. *(int *)(b+vehWeaponFields[i].ofs) = G_SoundIndex( value );
  261. #else
  262. *(int *)(b+vehWeaponFields[i].ofs) = trap_S_RegisterSound( value );
  263. #endif
  264. break;
  265. case VF_SOUND_CLIENT: // (MP cgame only) take the string, get the index
  266. #ifndef _JK2MP
  267. *(int *)(b+vehWeaponFields[i].ofs) = G_SoundIndex( value );
  268. #elif QAGAME
  269. //*(int *)(b+vehWeaponFields[i].ofs) = G_SoundIndex( value );
  270. #else
  271. *(int *)(b+vehWeaponFields[i].ofs) = trap_S_RegisterSound( value );
  272. #endif
  273. break;
  274. default:
  275. //Unknown type?
  276. return qfalse;
  277. break;
  278. }
  279. break;
  280. }
  281. }
  282. if ( i == NUM_VWEAP_PARMS )
  283. {
  284. return qfalse;
  285. }
  286. else
  287. {
  288. return qtrue;
  289. }
  290. }
  291. int VEH_LoadVehWeapon( const char *vehWeaponName )
  292. {//load up specified vehWeapon and save in array: g_vehWeaponInfo
  293. const char *token;
  294. char parmName[128];//we'll assume that no parm name is longer than 128
  295. char *value;
  296. const char *p;
  297. vehWeaponInfo_t *vehWeapon = NULL;
  298. //BG_VehWeaponSetDefaults( &g_vehWeaponInfo[0] );//set the first vehicle to default data
  299. //try to parse data out
  300. p = VehWeaponParms;
  301. #ifdef _JK2MP
  302. COM_BeginParseSession("vehWeapons");
  303. #else
  304. COM_BeginParseSession();
  305. #endif
  306. vehWeapon = &g_vehWeaponInfo[numVehicleWeapons];
  307. // look for the right vehicle weapon
  308. while ( p )
  309. {
  310. token = COM_ParseExt( &p, qtrue );
  311. if ( token[0] == 0 )
  312. {
  313. return qfalse;
  314. }
  315. if ( !Q_stricmp( token, vehWeaponName ) )
  316. {
  317. break;
  318. }
  319. SkipBracedSection( &p );
  320. }
  321. if ( !p )
  322. {
  323. return qfalse;
  324. }
  325. token = COM_ParseExt( &p, qtrue );
  326. if ( token[0] == 0 )
  327. {//barf
  328. return VEH_WEAPON_NONE;
  329. }
  330. if ( Q_stricmp( token, "{" ) != 0 )
  331. {
  332. return VEH_WEAPON_NONE;
  333. }
  334. // parse the vehWeapon info block
  335. while ( 1 )
  336. {
  337. SkipRestOfLine( &p );
  338. token = COM_ParseExt( &p, qtrue );
  339. if ( !token[0] )
  340. {
  341. Com_Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing Vehicle Weapon '%s'\n", vehWeaponName );
  342. return VEH_WEAPON_NONE;
  343. }
  344. if ( !Q_stricmp( token, "}" ) )
  345. {
  346. break;
  347. }
  348. Q_strncpyz( parmName, token, sizeof(parmName) );
  349. value = COM_ParseExt( &p, qtrue );
  350. if ( !value || !value[0] )
  351. {
  352. Com_Printf( S_COLOR_RED"ERROR: Vehicle Weapon token '%s' has no value!\n", parmName );
  353. }
  354. else
  355. {
  356. if ( !BG_ParseVehWeaponParm( vehWeapon, parmName, value ) )
  357. {
  358. Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle Weapon key/value pair '%s','%s'!\n", parmName, value );
  359. }
  360. }
  361. }
  362. if ( vehWeapon->fHoming )
  363. {//all lock-on weapons use these 2 sounds
  364. #ifdef QAGAME
  365. //Hmm, no need fo have server register this, is there?
  366. //G_SoundIndex( "sound/weapons/torpedo/tick.wav" );
  367. //G_SoundIndex( "sound/weapons/torpedo/lock.wav" );
  368. #elif CGAME
  369. trap_S_RegisterSound( "sound/vehicles/weapons/common/tick.wav" );
  370. trap_S_RegisterSound( "sound/vehicles/weapons/common/lock.wav" );
  371. trap_S_RegisterSound( "sound/vehicles/common/lockalarm1.wav" );
  372. trap_S_RegisterSound( "sound/vehicles/common/lockalarm2.wav" );
  373. trap_S_RegisterSound( "sound/vehicles/common/lockalarm3.wav" );
  374. #else
  375. trap_S_RegisterSound( "sound/vehicles/weapons/common/tick.wav" );
  376. trap_S_RegisterSound( "sound/vehicles/weapons/common/lock.wav" );
  377. trap_S_RegisterSound( "sound/vehicles/common/lockalarm1.wav" );
  378. trap_S_RegisterSound( "sound/vehicles/common/lockalarm2.wav" );
  379. trap_S_RegisterSound( "sound/vehicles/common/lockalarm3.wav" );
  380. #endif
  381. }
  382. return (numVehicleWeapons++);
  383. }
  384. int VEH_VehWeaponIndexForName( const char *vehWeaponName )
  385. {
  386. int vw;
  387. if ( !vehWeaponName || !vehWeaponName[0] )
  388. {
  389. Com_Printf( S_COLOR_RED"ERROR: Trying to read Vehicle Weapon with no name!\n" );
  390. return VEH_WEAPON_NONE;
  391. }
  392. for ( vw = VEH_WEAPON_BASE; vw < numVehicleWeapons; vw++ )
  393. {
  394. if ( g_vehWeaponInfo[vw].name
  395. && Q_stricmp( g_vehWeaponInfo[vw].name, vehWeaponName ) == 0 )
  396. {//already loaded this one
  397. return vw;
  398. }
  399. }
  400. //haven't loaded it yet
  401. if ( vw >= MAX_VEH_WEAPONS )
  402. {//no more room!
  403. Com_Printf( S_COLOR_RED"ERROR: Too many Vehicle Weapons (max 16), aborting load on %s!\n", vehWeaponName );
  404. return VEH_WEAPON_NONE;
  405. }
  406. //we have room for another one, load it up and return the index
  407. //HMM... should we not even load the .vwp file until we want to?
  408. vw = VEH_LoadVehWeapon( vehWeaponName );
  409. if ( vw == VEH_WEAPON_NONE )
  410. {
  411. Com_Printf( S_COLOR_RED"ERROR: Could not find Vehicle Weapon %s!\n", vehWeaponName );
  412. }
  413. return vw;
  414. }
  415. vehField_t vehicleFields[] =
  416. {
  417. {"name", VFOFS(name), VF_LSTRING}, //unique name of the vehicle
  418. //general data
  419. {"type", VFOFS(type), VF_VEHTYPE}, //what kind of vehicle
  420. {"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
  421. {"lookPitch", VFOFS(lookPitch), VF_FLOAT}, //How far you can look up and down off the forward of the vehicle
  422. {"lookYaw", VFOFS(lookYaw), VF_FLOAT}, //How far you can look left and right off the forward of the vehicle
  423. {"length", VFOFS(length), VF_FLOAT}, //how long it is - used for body length traces when turning/moving?
  424. {"width", VFOFS(width), VF_FLOAT}, //how wide it is - used for body length traces when turning/moving?
  425. {"height", VFOFS(height), VF_FLOAT}, //how tall it is - used for body length traces when turning/moving?
  426. {"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)
  427. //speed stats
  428. {"speedMax", VFOFS(speedMax), VF_FLOAT}, //top speed
  429. {"turboSpeed", VFOFS(turboSpeed), VF_FLOAT}, //turbo speed
  430. {"speedMin", VFOFS(speedMin), VF_FLOAT}, //if < 0, can go in reverse
  431. {"speedIdle", VFOFS(speedIdle), VF_FLOAT}, //what speed it drifts to when no accel/decel input is given
  432. {"accelIdle", VFOFS(accelIdle), VF_FLOAT}, //if speedIdle > 0, how quickly it goes up to that speed
  433. {"acceleration", VFOFS(acceleration), VF_FLOAT}, //when pressing on accelerator
  434. {"decelIdle", VFOFS(decelIdle), VF_FLOAT}, //when giving no input, how quickly it drops to speedIdle
  435. {"throttleSticks", VFOFS(throttleSticks), VF_BOOL},//if true, speed stays at whatever you accel/decel to, unless you turbo or brake
  436. {"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
  437. //handling stats
  438. {"bankingSpeed", VFOFS(bankingSpeed), VF_FLOAT}, //how quickly it pitches and rolls (not under player control)
  439. {"pitchLimit", VFOFS(pitchLimit), VF_FLOAT}, //how far it can roll forward or backward
  440. {"rollLimit", VFOFS(rollLimit), VF_FLOAT}, //how far it can roll to either side
  441. {"braking", VFOFS(braking), VF_FLOAT}, //when pressing on decelerator
  442. {"mouseYaw", VFOFS(mouseYaw), VF_FLOAT}, // The mouse yaw override.
  443. {"mousePitch", VFOFS(mousePitch), VF_FLOAT}, // The mouse yaw override.
  444. {"turningSpeed", VFOFS(turningSpeed), VF_FLOAT}, //how quickly you can turn
  445. {"turnWhenStopped", VFOFS(turnWhenStopped), VF_BOOL},//whether or not you can turn when not moving
  446. {"traction", VFOFS(traction), VF_FLOAT}, //how much your command input affects velocity
  447. {"friction", VFOFS(friction), VF_FLOAT}, //how much velocity is cut on its own
  448. {"maxSlope", VFOFS(maxSlope), VF_FLOAT}, //the max slope that it can go up with control
  449. {"speedDependantTurning", VFOFS(speedDependantTurning), VF_BOOL},//vehicle turns faster the faster it's going
  450. //durability stats
  451. {"mass", VFOFS(mass), VF_INT}, //for momentum and impact force (player mass is 10)
  452. {"armor", VFOFS(armor), VF_INT}, //total points of damage it can take
  453. {"shields", VFOFS(shields), VF_INT}, //energy shield damage points
  454. {"shieldRechargeMS", VFOFS(shieldRechargeMS), VF_INT},//energy shield milliseconds per point recharged
  455. {"toughness", VFOFS(toughness), VF_FLOAT}, //modifies incoming damage, 1.0 is normal, 0.5 is half, etc. Simulates being made of tougher materials/construction
  456. {"malfunctionArmorLevel", VFOFS(malfunctionArmorLevel), VF_INT},//when armor drops to or below this point, start malfunctioning
  457. {"surfDestruction", VFOFS(surfDestruction), VF_INT},
  458. //visuals & sounds
  459. {"model", VFOFS(model), VF_LSTRING}, //what model to use - if make it an NPC's primary model, don't need this?
  460. {"skin", VFOFS(skin), VF_LSTRING}, //what skin to use - if make it an NPC's primary model, don't need this?
  461. {"g2radius", VFOFS(g2radius), VF_INT}, //render radius (really diameter, but...) for the ghoul2 model
  462. {"riderAnim", VFOFS(riderAnim), VF_ANIM}, //what animation the rider uses
  463. {"droidNPC", VFOFS(droidNPC), VF_LSTRING}, //NPC to attach to *droidunit tag (if it exists in the model)
  464. #ifdef _JK2MP
  465. {"radarIcon", VFOFS(radarIconHandle), VF_SHADER_NOMIP}, //what icon to show on radar in MP
  466. {"dmgIndicFrame", VFOFS(dmgIndicFrameHandle), VF_SHADER_NOMIP}, //what image to use for the frame of the damage indicator
  467. {"dmgIndicShield", VFOFS(dmgIndicShieldHandle), VF_SHADER_NOMIP},//what image to use for the shield of the damage indicator
  468. {"dmgIndicBackground", VFOFS(dmgIndicBackgroundHandle), VF_SHADER_NOMIP},//what image to use for the background of the damage indicator
  469. {"icon_front", VFOFS(iconFrontHandle), VF_SHADER_NOMIP}, //what image to use for the front of the ship on the damage indicator
  470. {"icon_back", VFOFS(iconBackHandle), VF_SHADER_NOMIP}, //what image to use for the back of the ship on the damage indicator
  471. {"icon_right", VFOFS(iconRightHandle), VF_SHADER_NOMIP}, //what image to use for the right of the ship on the damage indicator
  472. {"icon_left", VFOFS(iconLeftHandle), VF_SHADER_NOMIP}, //what image to use for the left of the ship on the damage indicator
  473. {"crosshairShader", VFOFS(crosshairShaderHandle), VF_SHADER_NOMIP}, //what image to use as the crosshair
  474. {"shieldShader", VFOFS(shieldShaderHandle), VF_SHADER}, //What shader to use when drawing the shield shell
  475. //individual "area" health -rww
  476. {"health_front", VFOFS(health_front), VF_INT},
  477. {"health_back", VFOFS(health_back), VF_INT},
  478. {"health_right", VFOFS(health_right), VF_INT},
  479. {"health_left", VFOFS(health_left), VF_INT},
  480. #else
  481. {"radarIcon", 0, VF_IGNORE}, //what icon to show on radar in MP
  482. #endif
  483. {"soundOn", VFOFS(soundOn), VF_SOUND},//sound to play when get on it
  484. {"soundOff", VFOFS(soundOff), VF_SOUND},//sound to play when get off
  485. {"soundLoop", VFOFS(soundLoop), VF_SOUND},//sound to loop while riding it
  486. {"soundTakeOff", VFOFS(soundTakeOff), VF_SOUND},//sound to play when ship takes off
  487. {"soundEngineStart",VFOFS(soundEngineStart),VF_SOUND_CLIENT},//sound to play when ship's thrusters first activate
  488. {"soundSpin", VFOFS(soundSpin), VF_SOUND},//sound to loop while spiraling out of control
  489. {"soundTurbo", VFOFS(soundTurbo), VF_SOUND},//sound to play when turbo/afterburner kicks in
  490. {"soundHyper", VFOFS(soundHyper), VF_SOUND_CLIENT},//sound to play when hits hyperspace
  491. {"soundLand", VFOFS(soundLand), VF_SOUND},//sound to play when ship lands
  492. {"soundFlyBy", VFOFS(soundFlyBy), VF_SOUND_CLIENT},//sound to play when they buzz you
  493. {"soundFlyBy2", VFOFS(soundFlyBy2), VF_SOUND_CLIENT},//alternate sound to play when they buzz you
  494. {"soundShift1", VFOFS(soundShift1), VF_SOUND},//sound to play when changing speeds
  495. {"soundShift2", VFOFS(soundShift2), VF_SOUND},//sound to play when changing speeds
  496. {"soundShift3", VFOFS(soundShift3), VF_SOUND},//sound to play when changing speeds
  497. {"soundShift4", VFOFS(soundShift4), VF_SOUND},//sound to play when changing speeds
  498. {"exhaustFX", VFOFS(iExhaustFX), VF_EFFECT_CLIENT}, //exhaust effect, played from "*exhaust" bolt(s)
  499. {"turboFX", VFOFS(iTurboFX), VF_EFFECT_CLIENT}, //turbo exhaust effect, played from "*exhaust" bolt(s) when ship is in "turbo" mode
  500. {"turboStartFX", VFOFS(iTurboStartFX), VF_EFFECT}, //turbo start effect, played from "*exhaust" bolt(s) when ship is in "turbo" mode
  501. {"trailFX", VFOFS(iTrailFX), VF_EFFECT_CLIENT}, //trail effect, played from "*trail" bolt(s)
  502. {"impactFX", VFOFS(iImpactFX), VF_EFFECT_CLIENT}, //impact effect, for when it bumps into something
  503. {"explodeFX", VFOFS(iExplodeFX), VF_EFFECT}, //explosion effect, for when it blows up (should have the sound built into explosion effect)
  504. {"wakeFX", VFOFS(iWakeFX), VF_EFFECT_CLIENT}, //effect it makes when going across water
  505. {"dmgFX", VFOFS(iDmgFX), VF_EFFECT_CLIENT}, //effect to play on damage from a weapon or something
  506. #ifdef _JK2MP
  507. {"injureFX", VFOFS(iInjureFX), VF_EFFECT_CLIENT}, //effect to play on partially damaged ship surface
  508. {"noseFX", VFOFS(iNoseFX), VF_EFFECT_CLIENT}, //effect for nose piece flying away when blown off
  509. {"lwingFX", VFOFS(iLWingFX), VF_EFFECT_CLIENT}, //effect for left wing piece flying away when blown off
  510. {"rwingFX", VFOFS(iRWingFX), VF_EFFECT_CLIENT}, //effect for right wing piece flying away when blown off
  511. #else
  512. {"armorLowFX", VFOFS(iArmorLowFX), VF_EFFECT_CLIENT}, //effect to play on damage from a weapon or something
  513. {"armorGoneFX", VFOFS(iArmorGoneFX), VF_EFFECT_CLIENT}, //effect to play on damage from a weapon or something
  514. #endif
  515. // Weapon stuff:
  516. {"weap1", VFOFS(weapon[0].ID), VF_WEAPON}, //weapon used when press fire
  517. {"weap2", VFOFS(weapon[1].ID), VF_WEAPON},//weapon used when press alt-fire
  518. // The delay between shots for this weapon.
  519. {"weap1Delay", VFOFS(weapon[0].delay), VF_INT},
  520. {"weap2Delay", VFOFS(weapon[1].delay), VF_INT},
  521. // Whether or not all the muzzles for each weapon can be linked together (linked delay = weapon delay * number of muzzles linked!)
  522. {"weap1Link", VFOFS(weapon[0].linkable), VF_INT},
  523. {"weap2Link", VFOFS(weapon[1].linkable), VF_INT},
  524. // Whether or not to auto-aim the projectiles at the thing under the crosshair when we fire
  525. {"weap1Aim", VFOFS(weapon[0].aimCorrect), VF_BOOL},
  526. {"weap2Aim", VFOFS(weapon[1].aimCorrect), VF_BOOL},
  527. //maximum ammo
  528. {"weap1AmmoMax", VFOFS(weapon[0].ammoMax), VF_INT},
  529. {"weap2AmmoMax", VFOFS(weapon[1].ammoMax), VF_INT},
  530. //ammo recharge rate - milliseconds per unit (minimum of 100, which is 10 ammo per second)
  531. {"weap1AmmoRechargeMS", VFOFS(weapon[0].ammoRechargeMS), VF_INT},
  532. {"weap2AmmoRechargeMS", VFOFS(weapon[1].ammoRechargeMS), VF_INT},
  533. //sound to play when out of ammo (plays default "no ammo" sound if none specified)
  534. {"weap1SoundNoAmmo", VFOFS(weapon[0].soundNoAmmo), VF_SOUND_CLIENT},//sound to play when try to fire weapon 1 with no ammo
  535. {"weap2SoundNoAmmo", VFOFS(weapon[1].soundNoAmmo), VF_SOUND_CLIENT},//sound to play when try to fire weapon 2 with no ammo
  536. // Which weapon a muzzle fires (has to match one of the weapons this vehicle has).
  537. {"weapMuzzle1", VFOFS(weapMuzzle[0]), VF_WEAPON},
  538. {"weapMuzzle2", VFOFS(weapMuzzle[1]), VF_WEAPON},
  539. {"weapMuzzle3", VFOFS(weapMuzzle[2]), VF_WEAPON},
  540. {"weapMuzzle4", VFOFS(weapMuzzle[3]), VF_WEAPON},
  541. {"weapMuzzle5", VFOFS(weapMuzzle[4]), VF_WEAPON},
  542. {"weapMuzzle6", VFOFS(weapMuzzle[5]), VF_WEAPON},
  543. {"weapMuzzle7", VFOFS(weapMuzzle[6]), VF_WEAPON},
  544. {"weapMuzzle8", VFOFS(weapMuzzle[7]), VF_WEAPON},
  545. {"weapMuzzle9", VFOFS(weapMuzzle[8]), VF_WEAPON},
  546. {"weapMuzzle10", VFOFS(weapMuzzle[9]), VF_WEAPON},
  547. // The max height before this ship (?) starts (auto)landing.
  548. {"landingHeight", VFOFS(landingHeight), VF_FLOAT},
  549. //other misc stats
  550. {"gravity", VFOFS(gravity), VF_INT}, //normal is 800
  551. {"hoverHeight", VFOFS(hoverHeight), VF_FLOAT}, //if 0, it's a ground vehicle
  552. {"hoverStrength", VFOFS(hoverStrength), VF_FLOAT}, //how hard it pushes off ground when less than hover height... causes "bounce", like shocks
  553. {"waterProof", VFOFS(waterProof), VF_BOOL}, //can drive underwater if it has to
  554. {"bouyancy", VFOFS(bouyancy), VF_FLOAT}, //when in water, how high it floats (1 is neutral bouyancy)
  555. {"fuelMax", VFOFS(fuelMax), VF_INT}, //how much fuel it can hold (capacity)
  556. {"fuelRate", VFOFS(fuelRate), VF_INT}, //how quickly is uses up fuel
  557. {"turboDuration", VFOFS(turboDuration), VF_INT}, //how long turbo lasts
  558. {"turboRecharge", VFOFS(turboRecharge), VF_INT}, //how long turbo takes to recharge
  559. {"visibility", VFOFS(visibility), VF_INT}, //for sight alerts
  560. {"loudness", VFOFS(loudness), VF_INT}, //for sound alerts
  561. {"explosionRadius", VFOFS(explosionRadius), VF_FLOAT},//range of explosion
  562. {"explosionDamage", VFOFS(explosionDamage), VF_INT},//damage of explosion
  563. //new stuff
  564. {"maxPassengers", VFOFS(maxPassengers), VF_INT}, // The max number of passengers this vehicle may have (Default = 0).
  565. {"hideRider", VFOFS(hideRider), VF_BOOL}, // rider (and passengers?) should not be drawn
  566. {"killRiderOnDeath", VFOFS(killRiderOnDeath), VF_BOOL},//if rider is on vehicle when it dies, they should die
  567. {"flammable", VFOFS(flammable), VF_BOOL}, //whether or not the vehicle should catch on fire before it explodes
  568. {"explosionDelay", VFOFS(explosionDelay), VF_INT}, //how long the vehicle should be on fire/dying before it explodes
  569. //camera stuff
  570. {"cameraOverride", VFOFS(cameraOverride), VF_BOOL},//override the third person camera with the below values - normal is 0 (off)
  571. {"cameraRange", VFOFS(cameraRange), VF_FLOAT}, //how far back the camera should be - normal is 80
  572. {"cameraVertOffset", VFOFS(cameraVertOffset), VF_FLOAT},//how high over the vehicle origin the camera should be - normal is 16
  573. {"cameraHorzOffset", VFOFS(cameraHorzOffset), VF_FLOAT},//how far to left/right (negative/positive) of of the vehicle origin the camera should be - normal is 0
  574. {"cameraPitchOffset", VFOFS(cameraPitchOffset), VF_FLOAT},//a modifier on the camera's pitch (up/down angle) to the vehicle - normal is 0
  575. {"cameraFOV", VFOFS(cameraFOV), VF_FLOAT}, //third person camera FOV, default is 80
  576. {"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
  577. {"cameraPitchDependantVertOffset", VFOFS(cameraPitchDependantVertOffset), VF_BOOL}, //use the hacky AT-ST pitch dependant vertical offset
  578. //===TURRETS===========================================================================
  579. //Turret 1
  580. {"turret1Weap", VFOFS(turret[0].iWeapon), VF_WEAPON},
  581. {"turret1Delay", VFOFS(turret[0].iDelay), VF_INT},
  582. {"turret1AmmoMax", VFOFS(turret[0].iAmmoMax), VF_INT},
  583. {"turret1AmmoRechargeMS", VFOFS(turret[0].iAmmoRechargeMS), VF_INT},
  584. {"turret1YawBone", VFOFS(turret[0].yawBone), VF_LSTRING},
  585. {"turret1PitchBone", VFOFS(turret[0].pitchBone), VF_LSTRING},
  586. {"turret1YawAxis", VFOFS(turret[0].yawAxis), VF_INT},
  587. {"turret1PitchAxis", VFOFS(turret[0].pitchAxis), VF_INT},
  588. {"turret1ClampYawL", VFOFS(turret[0].yawClampLeft), VF_FLOAT}, //how far the turret is allowed to turn left
  589. {"turret1ClampYawR", VFOFS(turret[0].yawClampRight), VF_FLOAT}, //how far the turret is allowed to turn right
  590. {"turret1ClampPitchU", VFOFS(turret[0].pitchClampUp), VF_FLOAT}, //how far the turret is allowed to title up
  591. {"turret1ClampPitchD", VFOFS(turret[0].pitchClampDown), VF_FLOAT}, //how far the turret is allowed to tilt down
  592. {"turret1Muzzle1", VFOFS(turret[0].iMuzzle[0]), VF_INT},
  593. {"turret1Muzzle2", VFOFS(turret[0].iMuzzle[1]), VF_INT},
  594. {"turret1TurnSpeed", VFOFS(turret[0].fTurnSpeed), VF_FLOAT},
  595. {"turret1AI", VFOFS(turret[0].bAI), VF_BOOL},
  596. {"turret1AILead", VFOFS(turret[0].bAILead), VF_BOOL},
  597. {"turret1AIRange", VFOFS(turret[0].fAIRange), VF_FLOAT},
  598. {"turret1PassengerNum", VFOFS(turret[0].passengerNum), VF_INT},//which number passenger can control this turret
  599. {"turret1GunnerViewTag", VFOFS(turret[0].gunnerViewTag), VF_LSTRING},
  600. //Turret 2
  601. {"turret2Weap", VFOFS(turret[1].iWeapon), VF_WEAPON},
  602. {"turret2Delay", VFOFS(turret[1].iDelay), VF_INT},
  603. {"turret2AmmoMax", VFOFS(turret[1].iAmmoMax), VF_INT},
  604. {"turret2AmmoRechargeMS", VFOFS(turret[1].iAmmoRechargeMS), VF_INT},
  605. {"turret2YawBone", VFOFS(turret[1].yawBone), VF_LSTRING},
  606. {"turret2PitchBone", VFOFS(turret[1].pitchBone), VF_LSTRING},
  607. {"turret2YawAxis", VFOFS(turret[1].yawAxis), VF_INT},
  608. {"turret2PitchAxis", VFOFS(turret[1].pitchAxis), VF_INT},
  609. {"turret2ClampYawL", VFOFS(turret[1].yawClampLeft), VF_FLOAT}, //how far the turret is allowed to turn left
  610. {"turret2ClampYawR", VFOFS(turret[1].yawClampRight), VF_FLOAT}, //how far the turret is allowed to turn right
  611. {"turret2ClampPitchU", VFOFS(turret[1].pitchClampUp), VF_FLOAT}, //how far the turret is allowed to title up
  612. {"turret2ClampPitchD", VFOFS(turret[1].pitchClampDown), VF_FLOAT}, //how far the turret is allowed to tilt down
  613. {"turret2Muzzle1", VFOFS(turret[1].iMuzzle[0]), VF_INT},
  614. {"turret2Muzzle2", VFOFS(turret[1].iMuzzle[1]), VF_INT},
  615. {"turret2TurnSpeed", VFOFS(turret[1].fTurnSpeed), VF_FLOAT},
  616. {"turret2AI", VFOFS(turret[1].bAI), VF_BOOL},
  617. {"turret2AILead", VFOFS(turret[1].bAILead), VF_BOOL},
  618. {"turret2AIRange", VFOFS(turret[1].fAIRange), VF_FLOAT},
  619. {"turret2PassengerNum", VFOFS(turret[1].passengerNum), VF_INT},//which number passenger can control this turret
  620. {"turret2GunnerViewTag", VFOFS(turret[1].gunnerViewTag), VF_LSTRING},
  621. //===END TURRETS===========================================================================
  622. //terminating entry
  623. {0, -1, VF_INT}
  624. };
  625. stringID_table_t VehicleTable[VH_NUM_VEHICLES+1] =
  626. {
  627. ENUM2STRING(VH_NONE),
  628. ENUM2STRING(VH_WALKER), //something you ride inside of, it walks like you, like an AT-ST
  629. ENUM2STRING(VH_FIGHTER), //something you fly inside of, like an X-Wing or TIE fighter
  630. ENUM2STRING(VH_SPEEDER), //something you ride on that hovers, like a speeder or swoop
  631. ENUM2STRING(VH_ANIMAL), //animal you ride on top of that walks, like a tauntaun
  632. ENUM2STRING(VH_FLIER), //animal you ride on top of that flies, like a giant mynoc?
  633. 0, -1
  634. };
  635. // Setup the shared functions (one's that all vehicles would generally use).
  636. void BG_SetSharedVehicleFunctions( vehicleInfo_t *pVehInfo )
  637. {
  638. #ifdef QAGAME
  639. //only do the whole thing if we're on game
  640. G_SetSharedVehicleFunctions(pVehInfo);
  641. #endif
  642. #ifndef WE_ARE_IN_THE_UI
  643. switch( pVehInfo->type )
  644. {
  645. case VH_SPEEDER:
  646. G_SetSpeederVehicleFunctions( pVehInfo );
  647. break;
  648. case VH_ANIMAL:
  649. G_SetAnimalVehicleFunctions( pVehInfo );
  650. break;
  651. case VH_FIGHTER:
  652. G_SetFighterVehicleFunctions( pVehInfo );
  653. break;
  654. case VH_WALKER:
  655. G_SetWalkerVehicleFunctions( pVehInfo );
  656. break;
  657. }
  658. #endif
  659. }
  660. void BG_VehicleSetDefaults( vehicleInfo_t *vehicle )
  661. {
  662. memset(vehicle, 0, sizeof(vehicleInfo_t));
  663. /*
  664. #if _JK2MP
  665. if (!vehicle->name)
  666. {
  667. vehicle->name = (char *)BG_Alloc(1024);
  668. }
  669. strcpy(vehicle->name, "default");
  670. #else
  671. vehicle->name = G_NewString( "default" );
  672. #endif
  673. //general data
  674. vehicle->type = VH_SPEEDER; //what kind of vehicle
  675. //FIXME: no saber or weapons if numHands = 2, should switch to speeder weapon, no attack anim on player
  676. vehicle->numHands = 0; //if 2 hands, no weapons, if 1 hand, can use 1-handed weapons, if 0 hands, can use 2-handed weapons
  677. vehicle->lookPitch = 0; //How far you can look up and down off the forward of the vehicle
  678. vehicle->lookYaw = 5; //How far you can look left and right off the forward of the vehicle
  679. vehicle->length = 0; //how long it is - used for body length traces when turning/moving?
  680. vehicle->width = 0; //how wide it is - used for body length traces when turning/moving?
  681. vehicle->height = 0; //how tall it is - used for body length traces when turning/moving?
  682. 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)
  683. //speed stats - note: these are DESIRED speed, not actual current speed/velocity
  684. vehicle->speedMax = VEH_DEFAULT_SPEED_MAX; //top speed
  685. vehicle->turboSpeed = 0; //turboBoost
  686. vehicle->speedMin = 0; //if < 0, can go in reverse
  687. vehicle->speedIdle = 0; //what speed it drifts to when no accel/decel input is given
  688. vehicle->accelIdle = 0; //if speedIdle > 0, how quickly it goes up to that speed
  689. vehicle->acceleration = VEH_DEFAULT_ACCEL; //when pressing on accelerator (1/2 this when going in reverse)
  690. vehicle->decelIdle = VEH_DEFAULT_DECEL; //when giving no input, how quickly it desired speed drops to speedIdle
  691. 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
  692. //handling stats
  693. vehicle->bankingSpeed = VEH_DEFAULT_BANKING_SPEED; //how quickly it pitches and rolls (not under player control)
  694. vehicle->rollLimit = VEH_DEFAULT_ROLL_LIMIT; //how far it can roll to either side
  695. vehicle->pitchLimit = VEH_DEFAULT_PITCH_LIMIT; //how far it can pitch forward or backward
  696. vehicle->braking = VEH_DEFAULT_BRAKING; //when pressing on decelerator (backwards)
  697. vehicle->turningSpeed = VEH_DEFAULT_TURNING_SPEED; //how quickly you can turn
  698. vehicle->turnWhenStopped = qfalse; //whether or not you can turn when not moving
  699. vehicle->traction = VEH_DEFAULT_TRACTION; //how much your command input affects velocity
  700. vehicle->friction = VEH_DEFAULT_FRICTION; //how much velocity is cut on its own
  701. vehicle->maxSlope = VEH_DEFAULT_MAX_SLOPE; //the max slope that it can go up with control
  702. //durability stats
  703. vehicle->mass = VEH_DEFAULT_MASS; //for momentum and impact force (player mass is 10)
  704. vehicle->armor = VEH_DEFAULT_MAX_ARMOR; //total points of damage it can take
  705. vehicle->toughness = VEH_DEFAULT_TOUGHNESS; //modifies incoming damage, 1.0 is normal, 0.5 is half, etc. Simulates being made of tougher materials/construction
  706. vehicle->malfunctionArmorLevel = 0; //when armor drops to or below this point, start malfunctioning
  707. //visuals & sounds
  708. //vehicle->model = "models/map_objects/ships/swoop.md3"; //what model to use - if make it an NPC's primary model, don't need this?
  709. if (!vehicle->model)
  710. {
  711. vehicle->model = (char *)BG_Alloc(1024);
  712. }
  713. strcpy(vehicle->model, "models/map_objects/ships/swoop.md3");
  714. vehicle->modelIndex = 0; //set internally, not until this vehicle is spawned into the level
  715. vehicle->skin = NULL; //what skin to use - if make it an NPC's primary model, don't need this?
  716. vehicle->riderAnim = BOTH_GUNSIT1; //what animation the rider uses
  717. vehicle->soundOn = NULL; //sound to play when get on it
  718. vehicle->soundLoop = NULL; //sound to loop while riding it
  719. vehicle->soundOff = NULL; //sound to play when get off
  720. vehicle->exhaustFX = NULL; //exhaust effect, played from "*exhaust" bolt(s)
  721. vehicle->trailFX = NULL; //trail effect, played from "*trail" bolt(s)
  722. vehicle->impactFX = NULL; //explosion effect, for when it blows up (should have the sound built into explosion effect)
  723. vehicle->explodeFX = NULL; //explosion effect, for when it blows up (should have the sound built into explosion effect)
  724. vehicle->wakeFX = NULL; //effect itmakes when going across water
  725. //other misc stats
  726. vehicle->gravity = VEH_DEFAULT_GRAVITY; //normal is 800
  727. vehicle->hoverHeight = 0;//VEH_DEFAULT_HOVER_HEIGHT; //if 0, it's a ground vehicle
  728. vehicle->hoverStrength = 0;//VEH_DEFAULT_HOVER_STRENGTH;//how hard it pushes off ground when less than hover height... causes "bounce", like shocks
  729. vehicle->waterProof = qtrue; //can drive underwater if it has to
  730. vehicle->bouyancy = 1.0f; //when in water, how high it floats (1 is neutral bouyancy)
  731. vehicle->fuelMax = 1000; //how much fuel it can hold (capacity)
  732. vehicle->fuelRate = 1; //how quickly is uses up fuel
  733. vehicle->visibility = VEH_DEFAULT_VISIBILITY; //radius for sight alerts
  734. vehicle->loudness = VEH_DEFAULT_LOUDNESS; //radius for sound alerts
  735. vehicle->explosionRadius = VEH_DEFAULT_EXP_RAD;
  736. vehicle->explosionDamage = VEH_DEFAULT_EXP_DMG;
  737. vehicle->maxPassengers = 0;
  738. //new stuff
  739. vehicle->hideRider = qfalse; // rider (and passengers?) should not be drawn
  740. vehicle->killRiderOnDeath = qfalse; //if rider is on vehicle when it dies, they should die
  741. vehicle->flammable = qfalse; //whether or not the vehicle should catch on fire before it explodes
  742. vehicle->explosionDelay = 0; //how long the vehicle should be on fire/dying before it explodes
  743. //camera stuff
  744. vehicle->cameraOverride = qfalse; //whether or not to use all of the following 3rd person camera override values
  745. vehicle->cameraRange = 0.0f; //how far back the camera should be - normal is 80
  746. vehicle->cameraVertOffset = 0.0f; //how high over the vehicle origin the camera should be - normal is 16
  747. vehicle->cameraHorzOffset = 0.0f; //how far to left/right (negative/positive) of of the vehicle origin the camera should be - normal is 0
  748. vehicle->cameraPitchOffset = 0.0f; //a modifier on the camera's pitch (up/down angle) to the vehicle - normal is 0
  749. vehicle->cameraFOV = 0.0f; //third person camera FOV, default is 80
  750. vehicle->cameraAlpha = qfalse; //fade out the vehicle if it's in the way of the crosshair
  751. */
  752. }
  753. void BG_VehicleClampData( vehicleInfo_t *vehicle )
  754. {//sanity check and clamp the vehicle's data
  755. int i;
  756. for ( i = 0; i < 3; i++ )
  757. {
  758. if ( vehicle->centerOfGravity[i] > 1.0f )
  759. {
  760. vehicle->centerOfGravity[i] = 1.0f;
  761. }
  762. else if ( vehicle->centerOfGravity[i] < -1.0f )
  763. {
  764. vehicle->centerOfGravity[i] = -1.0f;
  765. }
  766. }
  767. // Validate passenger max.
  768. if ( vehicle->maxPassengers > VEH_MAX_PASSENGERS )
  769. {
  770. vehicle->maxPassengers = VEH_MAX_PASSENGERS;
  771. }
  772. else if ( vehicle->maxPassengers < 0 )
  773. {
  774. vehicle->maxPassengers = 0;
  775. }
  776. }
  777. static qboolean BG_ParseVehicleParm( vehicleInfo_t *vehicle, char *parmName, char *pValue )
  778. {
  779. int i;
  780. vec3_t vec;
  781. byte *b = (byte *)vehicle;
  782. int _iFieldsRead = 0;
  783. vehicleType_t vehType;
  784. char value[1024];
  785. Q_strncpyz( value, pValue, sizeof(value) );
  786. // Loop through possible parameters
  787. for ( i = 0; vehicleFields[i].ofs != -1; i++ )
  788. {
  789. if ( !Q_stricmp( vehicleFields[i].name, parmName ) )
  790. {
  791. // found it
  792. switch( vehicleFields[i].type )
  793. {
  794. case VF_IGNORE:
  795. break;
  796. case VF_INT:
  797. *(int *)(b+vehicleFields[i].ofs) = atoi(value);
  798. break;
  799. case VF_FLOAT:
  800. *(float *)(b+vehicleFields[i].ofs) = atof(value);
  801. break;
  802. case VF_LSTRING: // string on disk, pointer in memory, TAG_LEVEL
  803. if (!*(char **)(b+vehicleFields[i].ofs))
  804. { //just use 128 bytes in case we want to write over the string
  805. #ifdef _JK2MP
  806. *(char **)(b+vehicleFields[i].ofs) = (char *)BG_Alloc(128);//(char *)BG_Alloc(strlen(value));
  807. strcpy(*(char **)(b+vehicleFields[i].ofs), value);
  808. #else
  809. (*(char **)(b+vehicleFields[i].ofs)) = G_NewString( value );
  810. #endif
  811. }
  812. break;
  813. case VF_VECTOR:
  814. _iFieldsRead = sscanf (value, "%f %f %f", &vec[0], &vec[1], &vec[2]);
  815. assert(_iFieldsRead==3 );
  816. if (_iFieldsRead!=3)
  817. {
  818. Com_Printf (S_COLOR_YELLOW"BG_ParseVehicleParm: VEC3 sscanf() failed to read 3 floats ('angle' key bug?)\n");
  819. }
  820. ((float *)(b+vehWeaponFields[i].ofs))[0] = vec[0];
  821. ((float *)(b+vehWeaponFields[i].ofs))[1] = vec[1];
  822. ((float *)(b+vehWeaponFields[i].ofs))[2] = vec[2];
  823. break;
  824. case VF_BOOL:
  825. *(qboolean *)(b+vehicleFields[i].ofs) = (qboolean)(atof(value)!=0);
  826. break;
  827. case VF_VEHTYPE:
  828. vehType = (vehicleType_t)GetIDForString( VehicleTable, value );
  829. *(vehicleType_t *)(b+vehicleFields[i].ofs) = vehType;
  830. break;
  831. case VF_ANIM:
  832. {
  833. int anim = GetIDForString( animTable, value );
  834. *(int *)(b+vehicleFields[i].ofs) = anim;
  835. }
  836. break;
  837. case VF_WEAPON: // take string, resolve into index into VehWeaponParms
  838. *(int *)(b+vehicleFields[i].ofs) = VEH_VehWeaponIndexForName( value );
  839. break;
  840. case VF_MODEL: // take the string, get the G_ModelIndex
  841. #ifdef QAGAME
  842. *(int *)(b+vehicleFields[i].ofs) = G_ModelIndex( value );
  843. #else
  844. *(int *)(b+vehicleFields[i].ofs) = trap_R_RegisterModel( value );
  845. #endif
  846. break;
  847. case VF_MODEL_CLIENT: // (MP cgame only) take the string, get the G_ModelIndex
  848. #ifndef _JK2MP
  849. *(int *)(b+vehicleFields[i].ofs) = G_ModelIndex( value );
  850. #elif QAGAME
  851. //*(int *)(b+vehicleFields[i].ofs) = G_ModelIndex( value );
  852. #else
  853. *(int *)(b+vehicleFields[i].ofs) = trap_R_RegisterModel( value );
  854. #endif
  855. break;
  856. case VF_EFFECT: // take the string, get the G_EffectIndex
  857. #ifdef QAGAME
  858. *(int *)(b+vehicleFields[i].ofs) = G_EffectIndex( value );
  859. #elif CGAME
  860. *(int *)(b+vehicleFields[i].ofs) = trap_FX_RegisterEffect( value );
  861. #endif
  862. break;
  863. case VF_EFFECT_CLIENT: // (MP cgame only) take the string, get the G_EffectIndex
  864. #ifndef _JK2MP
  865. *(int *)(b+vehicleFields[i].ofs) = G_EffectIndex( value );
  866. #elif QAGAME
  867. //*(int *)(b+vehicleFields[i].ofs) = G_EffectIndex( value );
  868. #elif CGAME
  869. *(int *)(b+vehicleFields[i].ofs) = trap_FX_RegisterEffect( value );
  870. #endif
  871. break;
  872. case VF_SHADER: // (cgame only) take the string, call trap_R_RegisterShader
  873. #ifdef WE_ARE_IN_THE_UI
  874. *(int *)(b+vehicleFields[i].ofs) = trap_R_RegisterShaderNoMip( value );
  875. #elif CGAME
  876. *(int *)(b+vehicleFields[i].ofs) = trap_R_RegisterShader( value );
  877. #endif
  878. break;
  879. case VF_SHADER_NOMIP:// (cgame only) take the string, call trap_R_RegisterShaderNoMip
  880. #ifndef QAGAME
  881. *(int *)(b+vehicleFields[i].ofs) = trap_R_RegisterShaderNoMip( value );
  882. #endif
  883. break;
  884. case VF_SOUND: // take the string, get the G_SoundIndex
  885. #ifdef QAGAME
  886. *(int *)(b+vehicleFields[i].ofs) = G_SoundIndex( value );
  887. #else
  888. *(int *)(b+vehicleFields[i].ofs) = trap_S_RegisterSound( value );
  889. #endif
  890. break;
  891. case VF_SOUND_CLIENT: // (MP cgame only) take the string, get the G_SoundIndex
  892. #ifndef _JK2MP
  893. *(int *)(b+vehicleFields[i].ofs) = G_SoundIndex( value );
  894. #elif QAGAME
  895. //*(int *)(b+vehicleFields[i].ofs) = G_SoundIndex( value );
  896. #else
  897. *(int *)(b+vehicleFields[i].ofs) = trap_S_RegisterSound( value );
  898. #endif
  899. break;
  900. default:
  901. //Unknown type?
  902. return qfalse;
  903. break;
  904. }
  905. break;
  906. }
  907. }
  908. if ( vehicleFields[i].ofs == -1 )
  909. {
  910. return qfalse;
  911. }
  912. else
  913. {
  914. return qtrue;
  915. }
  916. }
  917. int VEH_LoadVehicle( const char *vehicleName )
  918. {//load up specified vehicle and save in array: g_vehicleInfo
  919. const char *token;
  920. //we'll assume that no parm name is longer than 128
  921. char parmName[128] = { 0 };
  922. char weap1[128] = { 0 }, weap2[128] = { 0 };
  923. char weapMuzzle1[128] = { 0 };
  924. char weapMuzzle2[128] = { 0 };
  925. char weapMuzzle3[128] = { 0 };
  926. char weapMuzzle4[128] = { 0 };
  927. char weapMuzzle5[128] = { 0 };
  928. char weapMuzzle6[128] = { 0 };
  929. char weapMuzzle7[128] = { 0 };
  930. char weapMuzzle8[128] = { 0 };
  931. char weapMuzzle9[128] = { 0 };
  932. char weapMuzzle10[128] = { 0 };
  933. char *value = NULL;
  934. const char *p = NULL;
  935. vehicleInfo_t *vehicle = NULL;
  936. // Load the vehicle parms if no vehicles have been loaded yet.
  937. if ( numVehicles == 0 )
  938. {
  939. BG_VehicleLoadParms();
  940. }
  941. //try to parse data out
  942. p = VehicleParms;
  943. #ifdef _JK2MP
  944. COM_BeginParseSession("vehicles");
  945. #else
  946. COM_BeginParseSession();
  947. #endif
  948. vehicle = &g_vehicleInfo[numVehicles];
  949. // look for the right vehicle
  950. while ( p )
  951. {
  952. token = COM_ParseExt( &p, qtrue );
  953. if ( token[0] == 0 )
  954. {
  955. return VEHICLE_NONE;
  956. }
  957. if ( !Q_stricmp( token, vehicleName ) )
  958. {
  959. break;
  960. }
  961. SkipBracedSection( &p );
  962. }
  963. if ( !p )
  964. {
  965. return VEHICLE_NONE;
  966. }
  967. token = COM_ParseExt( &p, qtrue );
  968. if ( token[0] == 0 )
  969. {//barf
  970. return VEHICLE_NONE;
  971. }
  972. if ( Q_stricmp( token, "{" ) != 0 )
  973. {
  974. return VEHICLE_NONE;
  975. }
  976. BG_VehicleSetDefaults( vehicle );
  977. // parse the vehicle info block
  978. while ( 1 )
  979. {
  980. SkipRestOfLine( &p );
  981. token = COM_ParseExt( &p, qtrue );
  982. if ( !token[0] )
  983. {
  984. Com_Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing Vehicle '%s'\n", vehicleName );
  985. return VEHICLE_NONE;
  986. }
  987. if ( !Q_stricmp( token, "}" ) )
  988. {
  989. break;
  990. }
  991. Q_strncpyz( parmName, token, sizeof(parmName) );
  992. value = COM_ParseExt( &p, qtrue );
  993. if ( !value || !value[0] )
  994. {
  995. Com_Printf( S_COLOR_RED"ERROR: Vehicle token '%s' has no value!\n", parmName );
  996. }
  997. else if ( Q_stricmp( "weap1", parmName ) == 0 )
  998. {//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...
  999. Q_strncpyz( weap1, value, sizeof(weap1) );
  1000. }
  1001. else if ( Q_stricmp( "weap2", parmName ) == 0 )
  1002. {//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...
  1003. Q_strncpyz( weap2, value, sizeof(weap2) );
  1004. }
  1005. else if ( Q_stricmp( "weapMuzzle1", parmName ) == 0 )
  1006. {//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...
  1007. Q_strncpyz( weapMuzzle1, value, sizeof(weapMuzzle1) );
  1008. }
  1009. else if ( Q_stricmp( "weapMuzzle2", parmName ) == 0 )
  1010. {//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...
  1011. Q_strncpyz( weapMuzzle2, value, sizeof(weapMuzzle2) );
  1012. }
  1013. else if ( Q_stricmp( "weapMuzzle3", parmName ) == 0 )
  1014. {//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...
  1015. Q_strncpyz( weapMuzzle3, value, sizeof(weapMuzzle3) );
  1016. }
  1017. else if ( Q_stricmp( "weapMuzzle4", parmName ) == 0 )
  1018. {//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...
  1019. Q_strncpyz( weapMuzzle4, value, sizeof(weapMuzzle4) );
  1020. }
  1021. else if ( Q_stricmp( "weapMuzzle5", parmName ) == 0 )
  1022. {//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...
  1023. Q_strncpyz( weapMuzzle5, value, sizeof(weapMuzzle5) );
  1024. }
  1025. else if ( Q_stricmp( "weapMuzzle6", parmName ) == 0 )
  1026. {//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...
  1027. Q_strncpyz( weapMuzzle6, value, sizeof(weapMuzzle6) );
  1028. }
  1029. else if ( Q_stricmp( "weapMuzzle7", parmName ) == 0 )
  1030. {//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...
  1031. Q_strncpyz( weapMuzzle7, value, sizeof(weapMuzzle7) );
  1032. }
  1033. else if ( Q_stricmp( "weapMuzzle8", parmName ) == 0 )
  1034. {//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...
  1035. Q_strncpyz( weapMuzzle8, value, sizeof(weapMuzzle8) );
  1036. }
  1037. else if ( Q_stricmp( "weapMuzzle9", parmName ) == 0 )
  1038. {//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...
  1039. Q_strncpyz( weapMuzzle9, value, sizeof(weapMuzzle9) );
  1040. }
  1041. else if ( Q_stricmp( "weapMuzzle10", parmName ) == 0 )
  1042. {//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...
  1043. Q_strncpyz( weapMuzzle10, value, sizeof(weapMuzzle10) );
  1044. }
  1045. else
  1046. {
  1047. if ( !BG_ParseVehicleParm( vehicle, parmName, value ) )
  1048. {
  1049. #ifndef FINAL_BUILD
  1050. Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair '%s', '%s'!\n", parmName, value );
  1051. #endif
  1052. }
  1053. }
  1054. }
  1055. //NOW: if we have any weapons, go ahead and load them
  1056. if ( weap1[0] )
  1057. {
  1058. if ( !BG_ParseVehicleParm( vehicle, "weap1", weap1 ) )
  1059. {
  1060. #ifndef FINAL_BUILD
  1061. Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weap1', '%s'!\n", weap1 );
  1062. #endif
  1063. }
  1064. }
  1065. if ( weap2[0] )
  1066. {
  1067. if ( !BG_ParseVehicleParm( vehicle, "weap2", weap2 ) )
  1068. {
  1069. #ifndef FINAL_BUILD
  1070. Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weap2', '%s'!\n", weap2 );
  1071. #endif
  1072. }
  1073. }
  1074. if ( weapMuzzle1[0] )
  1075. {
  1076. if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle1", weapMuzzle1 ) )
  1077. {
  1078. #ifndef FINAL_BUILD
  1079. Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle1', '%s'!\n", weapMuzzle1 );
  1080. #endif
  1081. }
  1082. }
  1083. if ( weapMuzzle2[0] )
  1084. {
  1085. if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle2", weapMuzzle2 ) )
  1086. {
  1087. #ifndef FINAL_BUILD
  1088. Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle2', '%s'!\n", weapMuzzle2 );
  1089. #endif
  1090. }
  1091. }
  1092. if ( weapMuzzle3[0] )
  1093. {
  1094. if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle3", weapMuzzle3 ) )
  1095. {
  1096. #ifndef FINAL_BUILD
  1097. Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle3', '%s'!\n", weapMuzzle3 );
  1098. #endif
  1099. }
  1100. }
  1101. if ( weapMuzzle4[0] )
  1102. {
  1103. if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle4", weapMuzzle4 ) )
  1104. {
  1105. #ifndef FINAL_BUILD
  1106. Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle4', '%s'!\n", weapMuzzle4 );
  1107. #endif
  1108. }
  1109. }
  1110. if ( weapMuzzle5[0] )
  1111. {
  1112. if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle5", weapMuzzle5 ) )
  1113. {
  1114. #ifndef FINAL_BUILD
  1115. Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle5', '%s'!\n", weapMuzzle5 );
  1116. #endif
  1117. }
  1118. }
  1119. if ( weapMuzzle6[0] )
  1120. {
  1121. if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle6", weapMuzzle6 ) )
  1122. {
  1123. #ifndef FINAL_BUILD
  1124. Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle6', '%s'!\n", weapMuzzle6 );
  1125. #endif
  1126. }
  1127. }
  1128. if ( weapMuzzle7[0] )
  1129. {
  1130. if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle7", weapMuzzle7 ) )
  1131. {
  1132. #ifndef FINAL_BUILD
  1133. Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle7', '%s'!\n", weapMuzzle7 );
  1134. #endif
  1135. }
  1136. }
  1137. if ( weapMuzzle8[0] )
  1138. {
  1139. if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle8", weapMuzzle8 ) )
  1140. {
  1141. #ifndef FINAL_BUILD
  1142. Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle8', '%s'!\n", weapMuzzle8 );
  1143. #endif
  1144. }
  1145. }
  1146. if ( weapMuzzle9[0] )
  1147. {
  1148. if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle9", weapMuzzle9 ) )
  1149. {
  1150. #ifndef FINAL_BUILD
  1151. Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle9', '%s'!\n", weapMuzzle9 );
  1152. #endif
  1153. }
  1154. }
  1155. if ( weapMuzzle10[0] )
  1156. {
  1157. if ( !BG_ParseVehicleParm( vehicle, "weapMuzzle10", weapMuzzle10 ) )
  1158. {
  1159. #ifndef FINAL_BUILD
  1160. Com_Printf( S_COLOR_RED"ERROR: Unknown Vehicle key/value pair 'weapMuzzle10', '%s'!\n", weapMuzzle10 );
  1161. #endif
  1162. }
  1163. }
  1164. #ifdef _JK2MP
  1165. //let's give these guys some defaults
  1166. if (!vehicle->health_front)
  1167. {
  1168. vehicle->health_front = vehicle->armor/4;
  1169. }
  1170. if (!vehicle->health_back)
  1171. {
  1172. vehicle->health_back = vehicle->armor/4;
  1173. }
  1174. if (!vehicle->health_right)
  1175. {
  1176. vehicle->health_right = vehicle->armor/4;
  1177. }
  1178. if (!vehicle->health_left)
  1179. {
  1180. vehicle->health_left = vehicle->armor/4;
  1181. }
  1182. #endif
  1183. if ( vehicle->model )
  1184. {
  1185. #ifdef QAGAME
  1186. vehicle->modelIndex = G_ModelIndex( va( "models/players/%s/model.glm", vehicle->model ) );
  1187. #else
  1188. vehicle->modelIndex = trap_R_RegisterModel( va( "models/players/%s/model.glm", vehicle->model ) );
  1189. #endif
  1190. }
  1191. #ifndef _JK2MP
  1192. //SP
  1193. if ( vehicle->skin
  1194. && vehicle->skin[0] )
  1195. {
  1196. ratl::string_vs<256> skins(vehicle->skin);
  1197. for (ratl::string_vs<256>::tokenizer i = skins.begin("|"); i!=skins.end(); i++)
  1198. {
  1199. //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
  1200. gi.RE_RegisterSkin( va( "models/players/%s/model_%s.skin", vehicle->model, *i) );
  1201. //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
  1202. G_SkinIndex( va( "models/players/%s/model_%s.skin", vehicle->model, *i) );
  1203. }
  1204. }
  1205. else
  1206. {
  1207. //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
  1208. gi.RE_RegisterSkin( va( "models/players/%s/model_default.skin", vehicle->model) );
  1209. //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
  1210. G_SkinIndex( va( "models/players/%s/model_default.skin", vehicle->model) );
  1211. }
  1212. #else
  1213. #ifndef QAGAME
  1214. if ( vehicle->skin
  1215. && vehicle->skin[0] )
  1216. {
  1217. trap_R_RegisterSkin( va( "models/players/%s/model_%s.skin", vehicle->model, vehicle->skin) );
  1218. }
  1219. #endif
  1220. #endif
  1221. //sanity check and clamp the vehicle's data
  1222. BG_VehicleClampData( vehicle );
  1223. // Setup the shared function pointers.
  1224. BG_SetSharedVehicleFunctions( vehicle );
  1225. //misc effects... FIXME: not even used in MP, are they?
  1226. if ( vehicle->explosionDamage )
  1227. {
  1228. #ifdef QAGAME
  1229. G_EffectIndex( "ships/ship_explosion_mark" );
  1230. #elif CGAME
  1231. trap_FX_RegisterEffect( "ships/ship_explosion_mark" );
  1232. #endif
  1233. }
  1234. if ( vehicle->flammable )
  1235. {
  1236. #ifdef QAGAME
  1237. G_SoundIndex( "sound/vehicles/common/fire_lp.wav" );
  1238. #elif CGAME
  1239. trap_S_RegisterSound( "sound/vehicles/common/fire_lp.wav" );
  1240. #else
  1241. trap_S_RegisterSound( "sound/vehicles/common/fire_lp.wav" );
  1242. #endif
  1243. }
  1244. if ( vehicle->hoverHeight > 0 )
  1245. {
  1246. #ifndef _JK2MP
  1247. G_EffectIndex( "ships/swoop_dust" );
  1248. #elif QAGAME
  1249. G_EffectIndex( "ships/swoop_dust" );
  1250. #elif CGAME
  1251. trap_FX_RegisterEffect( "ships/swoop_dust" );
  1252. #endif
  1253. }
  1254. #ifdef QAGAME
  1255. G_EffectIndex( "volumetric/black_smoke" );
  1256. G_EffectIndex( "ships/fire" );
  1257. G_SoundIndex( "sound/vehicles/common/release.wav" );
  1258. #elif CGAME
  1259. trap_R_RegisterShader( "gfx/menus/radar/bracket" );
  1260. trap_R_RegisterShaderNoMip( "gfx/menus/radar/asteroid" );
  1261. trap_S_RegisterSound( "sound/vehicles/common/impactalarm.wav" );
  1262. trap_S_RegisterSound( "sound/vehicles/common/linkweaps.wav" );
  1263. trap_S_RegisterSound( "sound/vehicles/common/release.wav" );
  1264. trap_FX_RegisterEffect("effects/ships/dest_burning.efx");
  1265. trap_FX_RegisterEffect("effects/ships/dest_destroyed.efx");
  1266. trap_FX_RegisterEffect( "volumetric/black_smoke" );
  1267. trap_FX_RegisterEffect( "ships/fire" );
  1268. trap_FX_RegisterEffect("ships/hyperspace_stars");
  1269. if ( vehicle->hideRider )
  1270. {
  1271. trap_R_RegisterShaderNoMip( "gfx/menus/radar/circle_base" );
  1272. trap_R_RegisterShaderNoMip( "gfx/menus/radar/circle_base_frame" );
  1273. trap_R_RegisterShaderNoMip( "gfx/menus/radar/circle_base_shield" );
  1274. }
  1275. #endif
  1276. return (numVehicles++);
  1277. }
  1278. int VEH_VehicleIndexForName( const char *vehicleName )
  1279. {
  1280. int v;
  1281. if ( !vehicleName || !vehicleName[0] )
  1282. {
  1283. Com_Printf( S_COLOR_RED"ERROR: Trying to read Vehicle with no name!\n" );
  1284. return VEHICLE_NONE;
  1285. }
  1286. for ( v = VEHICLE_BASE; v < numVehicles; v++ )
  1287. {
  1288. if ( g_vehicleInfo[v].name
  1289. && Q_stricmp( g_vehicleInfo[v].name, vehicleName ) == 0 )
  1290. {//already loaded this one
  1291. return v;
  1292. }
  1293. }
  1294. //haven't loaded it yet
  1295. if ( v >= MAX_VEHICLES )
  1296. {//no more room!
  1297. Com_Printf( S_COLOR_RED"ERROR: Too many Vehicles (max 64), aborting load on %s!\n", vehicleName );
  1298. return VEHICLE_NONE;
  1299. }
  1300. //we have room for another one, load it up and return the index
  1301. //HMM... should we not even load the .veh file until we want to?
  1302. v = VEH_LoadVehicle( vehicleName );
  1303. if ( v == VEHICLE_NONE )
  1304. {
  1305. Com_Printf( S_COLOR_RED"ERROR: Could not find Vehicle %s!\n", vehicleName );
  1306. }
  1307. return v;
  1308. }
  1309. void BG_VehWeaponLoadParms( void )
  1310. {
  1311. int len, totallen, vehExtFNLen, mainBlockLen, fileCnt, i;
  1312. char *holdChar, *marker;
  1313. char vehWeaponExtensionListBuf[2048]; // The list of file names read in
  1314. fileHandle_t f;
  1315. char *tempReadBuffer;
  1316. len = 0;
  1317. //remember where to store the next one
  1318. totallen = mainBlockLen = len;
  1319. marker = VehWeaponParms+totallen;
  1320. *marker = 0;
  1321. //now load in the extra .veh extensions
  1322. #ifdef _JK2MP
  1323. fileCnt = trap_FS_GetFileList("ext_data/vehicles/weapons", ".vwp", vehWeaponExtensionListBuf, sizeof(vehWeaponExtensionListBuf) );
  1324. #else
  1325. fileCnt = gi.FS_GetFileList("ext_data/vehicles/weapons", ".vwp", vehWeaponExtensionListBuf, sizeof(vehWeaponExtensionListBuf) );
  1326. #endif
  1327. holdChar = vehWeaponExtensionListBuf;
  1328. #ifdef _JK2MP
  1329. tempReadBuffer = (char *)BG_TempAlloc(MAX_VEH_WEAPON_DATA_SIZE);
  1330. #else
  1331. tempReadBuffer = (char *)gi.Malloc( MAX_VEH_WEAPON_DATA_SIZE, TAG_G_ALLOC, qtrue );
  1332. #endif
  1333. // NOTE: Not use TempAlloc anymore...
  1334. //Make ABSOLUTELY CERTAIN that BG_Alloc/etc. is not used before
  1335. //the subsequent BG_TempFree or the pool will be screwed.
  1336. for ( i = 0; i < fileCnt; i++, holdChar += vehExtFNLen + 1 )
  1337. {
  1338. vehExtFNLen = strlen( holdChar );
  1339. // Com_Printf( "Parsing %s\n", holdChar );
  1340. #ifdef _JK2MP
  1341. len = trap_FS_FOpenFile(va( "ext_data/vehicles/weapons/%s", holdChar), &f, FS_READ);
  1342. #else
  1343. // len = gi.FS_ReadFile( va( "ext_data/vehicles/weapons/%s", holdChar), (void **) &buffer );
  1344. len = gi.FS_FOpenFile(va( "ext_data/vehicles/weapons/%s", holdChar), &f, FS_READ);
  1345. #endif
  1346. if ( len == -1 )
  1347. {
  1348. Com_Printf( "error reading file\n" );
  1349. }
  1350. else
  1351. {
  1352. #ifdef _JK2MP
  1353. trap_FS_Read(tempReadBuffer, len, f);
  1354. tempReadBuffer[len] = 0;
  1355. #else
  1356. gi.FS_Read(tempReadBuffer, len, f);
  1357. tempReadBuffer[len] = 0;
  1358. #endif
  1359. // Don't let it end on a } because that should be a stand-alone token.
  1360. if ( totallen && *(marker-1) == '}' )
  1361. {
  1362. strcat( marker, " " );
  1363. totallen++;
  1364. marker++;
  1365. }
  1366. if ( totallen + len >= MAX_VEH_WEAPON_DATA_SIZE ) {
  1367. Com_Error(ERR_DROP, "Vehicle Weapon extensions (*.vwp) are too large" );
  1368. }
  1369. strcat( marker, tempReadBuffer );
  1370. #ifdef _JK2MP
  1371. trap_FS_FCloseFile( f );
  1372. #else
  1373. gi.FS_FCloseFile( f );
  1374. #endif
  1375. totallen += len;
  1376. marker = VehWeaponParms+totallen;
  1377. }
  1378. }
  1379. #ifdef _JK2MP
  1380. BG_TempFree(MAX_VEH_WEAPON_DATA_SIZE);
  1381. #else
  1382. gi.Free(tempReadBuffer); tempReadBuffer = NULL;
  1383. #endif
  1384. }
  1385. void BG_VehicleLoadParms( void )
  1386. {//HMM... only do this if there's a vehicle on the level?
  1387. int len, totallen, vehExtFNLen, mainBlockLen, fileCnt, i;
  1388. // const char *filename = "ext_data/vehicles.dat";
  1389. char *holdChar, *marker;
  1390. char vehExtensionListBuf[2048]; // The list of file names read in
  1391. fileHandle_t f;
  1392. char *tempReadBuffer;
  1393. len = 0;
  1394. //remember where to store the next one
  1395. totallen = mainBlockLen = len;
  1396. marker = VehicleParms+totallen;
  1397. *marker = 0;
  1398. //now load in the extra .veh extensions
  1399. #ifdef _JK2MP
  1400. fileCnt = trap_FS_GetFileList("ext_data/vehicles", ".veh", vehExtensionListBuf, sizeof(vehExtensionListBuf) );
  1401. #else
  1402. fileCnt = gi.FS_GetFileList("ext_data/vehicles", ".veh", vehExtensionListBuf, sizeof(vehExtensionListBuf) );
  1403. #endif
  1404. holdChar = vehExtensionListBuf;
  1405. #ifdef _JK2MP
  1406. tempReadBuffer = (char *)BG_TempAlloc(MAX_VEHICLE_DATA_SIZE);
  1407. #else
  1408. tempReadBuffer = (char *)gi.Malloc( MAX_VEHICLE_DATA_SIZE, TAG_G_ALLOC, qtrue );
  1409. #endif
  1410. // NOTE: Not use TempAlloc anymore...
  1411. //Make ABSOLUTELY CERTAIN that BG_Alloc/etc. is not used before
  1412. //the subsequent BG_TempFree or the pool will be screwed.
  1413. for ( i = 0; i < fileCnt; i++, holdChar += vehExtFNLen + 1 )
  1414. {
  1415. vehExtFNLen = strlen( holdChar );
  1416. // Com_Printf( "Parsing %s\n", holdChar );
  1417. #ifdef _JK2MP
  1418. len = trap_FS_FOpenFile(va( "ext_data/vehicles/%s", holdChar), &f, FS_READ);
  1419. #else
  1420. // len = gi.FS_ReadFile( va( "ext_data/vehicles/%s", holdChar), (void **) &buffer );
  1421. len = gi.FS_FOpenFile(va( "ext_data/vehicles/%s", holdChar), &f, FS_READ);
  1422. #endif
  1423. if ( len == -1 )
  1424. {
  1425. Com_Printf( "error reading file\n" );
  1426. }
  1427. else
  1428. {
  1429. #ifdef _JK2MP
  1430. trap_FS_Read(tempReadBuffer, len, f);
  1431. tempReadBuffer[len] = 0;
  1432. #else
  1433. gi.FS_Read(tempReadBuffer, len, f);
  1434. tempReadBuffer[len] = 0;
  1435. #endif
  1436. // Don't let it end on a } because that should be a stand-alone token.
  1437. if ( totallen && *(marker-1) == '}' )
  1438. {
  1439. strcat( marker, " " );
  1440. totallen++;
  1441. marker++;
  1442. }
  1443. if ( totallen + len >= MAX_VEHICLE_DATA_SIZE ) {
  1444. Com_Error(ERR_DROP, "Vehicle extensions (*.veh) are too large" );
  1445. }
  1446. strcat( marker, tempReadBuffer );
  1447. #ifdef _JK2MP
  1448. trap_FS_FCloseFile( f );
  1449. #else
  1450. gi.FS_FCloseFile( f );
  1451. #endif
  1452. totallen += len;
  1453. marker = VehicleParms+totallen;
  1454. }
  1455. }
  1456. #ifdef _JK2MP
  1457. BG_TempFree(MAX_VEHICLE_DATA_SIZE);
  1458. #else
  1459. gi.Free(tempReadBuffer); tempReadBuffer = NULL;
  1460. #endif
  1461. numVehicles = 1;//first one is null/default
  1462. //set the first vehicle to default data
  1463. BG_VehicleSetDefaults( &g_vehicleInfo[VEHICLE_BASE] );
  1464. //sanity check and clamp the vehicle's data
  1465. BG_VehicleClampData( &g_vehicleInfo[VEHICLE_BASE] );
  1466. // Setup the shared function pointers.
  1467. BG_SetSharedVehicleFunctions( &g_vehicleInfo[VEHICLE_BASE] );
  1468. //Load the Vehicle Weapons data, too
  1469. BG_VehWeaponLoadParms();
  1470. }
  1471. int BG_VehicleGetIndex( const char *vehicleName )
  1472. {
  1473. return (VEH_VehicleIndexForName( vehicleName ));
  1474. }
  1475. //We get the vehicle name passed in as modelname
  1476. //with a $ in front of it.
  1477. //we are expected to then get the model for the
  1478. //vehicle and stomp over modelname with it.
  1479. void BG_GetVehicleModelName(char *modelname)
  1480. {
  1481. char *vehName = &modelname[1];
  1482. int vIndex = BG_VehicleGetIndex(vehName);
  1483. assert(modelname[0] == '$');
  1484. if (vIndex == VEHICLE_NONE)
  1485. {
  1486. Com_Error(ERR_DROP, "BG_GetVehicleModelName: couldn't find vehicle %s", vehName);
  1487. }
  1488. strcpy(modelname, g_vehicleInfo[vIndex].model);
  1489. }
  1490. void BG_GetVehicleSkinName(char *skinname)
  1491. {
  1492. char *vehName = &skinname[1];
  1493. int vIndex = BG_VehicleGetIndex(vehName);
  1494. assert(skinname[0] == '$');
  1495. if (vIndex == VEHICLE_NONE)
  1496. {
  1497. Com_Error(ERR_DROP, "BG_GetVehicleSkinName: couldn't find vehicle %s", vehName);
  1498. }
  1499. if ( !g_vehicleInfo[vIndex].skin
  1500. || !g_vehicleInfo[vIndex].skin[0] )
  1501. {
  1502. skinname[0] = 0;
  1503. }
  1504. else
  1505. {
  1506. strcpy(skinname, g_vehicleInfo[vIndex].skin);
  1507. }
  1508. }
  1509. #ifdef _JK2MP
  1510. #ifndef WE_ARE_IN_THE_UI
  1511. //so cgame can assign the function pointer for the vehicle attachment without having to
  1512. //bother with all the other funcs that don't really exist cgame-side.
  1513. extern int BG_GetTime(void);
  1514. extern int trap_G2API_AddBolt(void *ghoul2, int modelIndex, const char *boneName);
  1515. extern qboolean trap_G2API_GetBoltMatrix(void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix,
  1516. const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale);
  1517. void AttachRidersGeneric( Vehicle_t *pVeh )
  1518. {
  1519. // If we have a pilot, attach him to the driver tag.
  1520. if ( pVeh->m_pPilot )
  1521. {
  1522. mdxaBone_t boltMatrix;
  1523. vec3_t yawOnlyAngles;
  1524. bgEntity_t *parent = pVeh->m_pParentEntity;
  1525. bgEntity_t *pilot = pVeh->m_pPilot;
  1526. int crotchBolt = trap_G2API_AddBolt(parent->ghoul2, 0, "*driver");
  1527. assert(parent->playerState);
  1528. VectorSet(yawOnlyAngles, 0, parent->playerState->viewangles[YAW], 0);
  1529. // Get the driver tag.
  1530. trap_G2API_GetBoltMatrix( parent->ghoul2, 0, crotchBolt, &boltMatrix,
  1531. yawOnlyAngles, parent->playerState->origin,
  1532. BG_GetTime(), NULL, parent->modelScale );
  1533. BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, pilot->playerState->origin );
  1534. }
  1535. }
  1536. #endif
  1537. #include "../namespace_end.h"
  1538. #endif // _JK2MP