1 /*
2 ===========================================================================
3 Copyright (C) 2000 - 2013, Raven Software, Inc.
4 Copyright (C) 2001 - 2013, Activision, Inc.
5 Copyright (C) 2013 - 2015, OpenJK contributors
6 
7 This file is part of the OpenJK source code.
8 
9 OpenJK is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, see <http://www.gnu.org/licenses/>.
20 ===========================================================================
21 */
22 
23 //seems to be a compiler bug, it doesn't clean out the #ifdefs between dif-compiles
24 //or something, so the headers spew errors on these defs from the previous compile.
25 //this fixes that. -rww
26 #ifdef _JK2MP
27 //get rid of all the crazy defs we added for this file
28 #undef currentAngles
29 #undef currentOrigin
30 #undef mins
31 #undef maxs
32 #undef legsAnimTimer
33 #undef torsoAnimTimer
34 #undef bool
35 #undef false
36 #undef true
37 
38 #undef sqrtf
39 #undef Q_flrand
40 
41 #undef MOD_EXPLOSIVE
42 #endif
43 
44 #ifdef _JK2 //SP does not have this preprocessor for game like MP does
45 #ifndef _JK2MP
46 #define _JK2MP
47 #endif
48 #endif
49 
50 #ifndef _JK2MP //if single player
51 #ifndef QAGAME //I don't think we have a QAGAME define
52 #define QAGAME //but define it cause in sp we're always in the game
53 #endif
54 #endif
55 
56 #ifdef QAGAME //including game headers on cgame is FORBIDDEN ^_^
57 #include "g_local.h"
58 #elif defined _JK2MP
59 #include "bg_public.h"
60 #endif
61 
62 #ifndef _JK2MP
63 #include "g_functions.h"
64 #include "g_vehicles.h"
65 #include "../game/wp_saber.h"
66 #include "../cgame/cg_local.h"
67 #else
68 #include "bg_vehicles.h"
69 #endif
70 
71 #ifdef _JK2MP
72 //this is really horrible, but it works! just be sure not to use any locals or anything
73 //with these names (exluding bool, false, true). -rww
74 #define currentAngles r.currentAngles
75 #define currentOrigin r.currentOrigin
76 #define mins r.mins
77 #define maxs r.maxs
78 #define legsAnimTimer legsTimer
79 #define torsoAnimTimer torsoTimer
80 #define bool qboolean
81 #define false qfalse
82 #define true qtrue
83 
84 #define sqrtf sqrt
85 #define Q_flrand flrand
86 
87 #define MOD_EXPLOSIVE MOD_SUICIDE
88 #else
89 #define bgEntity_t gentity_t
90 extern void NPC_SetAnim(gentity_t	*ent,int setAnimParts,int anim,int setAnimFlags, int iBlend);
91 #endif
92 
93 extern float DotToSpot( vec3_t spot, vec3_t from, vec3_t fromAngles );
94 #ifdef QAGAME //SP or gameside MP
95 extern vmCvar_t	cg_thirdPersonAlpha;
96 extern vec3_t playerMins;
97 extern vec3_t playerMaxs;
98 extern cvar_t	*g_speederControlScheme;
99 extern void ChangeWeapon( gentity_t *ent, int newWeapon );
100 extern void PM_SetAnim(pmove_t	*pm,int setAnimParts,int anim,int setAnimFlags, int blendTime);
101 extern int PM_AnimLength( int index, animNumber_t anim );
102 #endif
103 
104 #ifdef _JK2MP
105 
106 #include "../namespace_begin.h"
107 
108 extern void BG_SetAnim(playerState_t *ps, animation_t *animations, int setAnimParts,int anim,int setAnimFlags, int blendTime);
109 extern int BG_GetTime(void);
110 #endif
111 
112 //Alright, actually, most of this file is shared between game and cgame for MP.
113 //I would like to keep it this way, so when modifying for SP please keep in
114 //mind the bgEntity restrictions imposed. -rww
115 
116 #define	STRAFERAM_DURATION	8
117 #define	STRAFERAM_ANGLE		8
118 
119 
120 #ifndef _JK2MP
VEH_StartStrafeRam(Vehicle_t * pVeh,bool Right)121 bool	VEH_StartStrafeRam(Vehicle_t *pVeh, bool Right)
122 {
123 	if (!(pVeh->m_ulFlags&VEH_STRAFERAM))
124 	{
125 		float	speed = VectorLength(pVeh->m_pParentEntity->client->ps.velocity);
126 		if (speed>400.0f)
127 		{
128 			// Compute Pos3
129 			//--------------
130 			vec3_t	right;
131 			AngleVectors(pVeh->m_vOrientation, 0, right, 0);
132  			VectorMA(pVeh->m_pParentEntity->client->ps.velocity, (Right)?( speed):(-speed), right, pVeh->m_pParentEntity->pos3);
133 
134 			pVeh->m_ulFlags				|= VEH_STRAFERAM;
135 			pVeh->m_fStrafeTime			 = (Right)?(STRAFERAM_DURATION):(-STRAFERAM_DURATION);
136 
137 			if (pVeh->m_iSoundDebounceTimer<level.time && Q_irand(0,1)==0)
138 			{
139 				int	shiftSound = Q_irand(1,4);
140 				switch (shiftSound)
141 				{
142 				case 1: shiftSound=pVeh->m_pVehicleInfo->soundShift1; break;
143 				case 2: shiftSound=pVeh->m_pVehicleInfo->soundShift2; break;
144 				case 3: shiftSound=pVeh->m_pVehicleInfo->soundShift3; break;
145 				case 4: shiftSound=pVeh->m_pVehicleInfo->soundShift4; break;
146 				}
147 				if (shiftSound)
148 				{
149 					pVeh->m_iSoundDebounceTimer = level.time + Q_irand(1000, 4000);
150 					G_SoundIndexOnEnt( pVeh->m_pParentEntity, CHAN_AUTO, shiftSound);
151 				}
152 			}
153 			return true;
154 		}
155 	}
156 	return false;
157 }
158 #else
VEH_StartStrafeRam(Vehicle_t * pVeh,bool Right,int Duration)159 bool	VEH_StartStrafeRam(Vehicle_t *pVeh, bool Right, int Duration)
160 {
161 	return false;
162 }
163 #endif
164 
165 
166 #ifdef QAGAME //game-only.. for now
167 // Like a think or move command, this updates various vehicle properties.
Update(Vehicle_t * pVeh,const usercmd_t * pUcmd)168 bool Update( Vehicle_t *pVeh, const usercmd_t *pUcmd )
169 {
170 	if ( !g_vehicleInfo[VEHICLE_BASE].Update( pVeh, pUcmd ) )
171 	{
172 		return false;
173 	}
174 
175 	// See whether this vehicle should be exploding.
176 	if ( pVeh->m_iDieTime != 0 )
177 	{
178 		pVeh->m_pVehicleInfo->DeathUpdate( pVeh );
179 	}
180 
181 	// Update move direction.
182 #ifndef _JK2MP //this makes prediction unhappy, and rightfully so.
183 	gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
184 
185 	if ( pVeh->m_ulFlags & VEH_FLYING )
186 	{
187 		vec3_t vVehAngles;
188 		VectorSet(vVehAngles, 0, pVeh->m_vOrientation[YAW], 0 );
189 		AngleVectors( vVehAngles, parent->client->ps.moveDir, NULL, NULL );
190 	}
191 	else
192 	{
193 		vec3_t vVehAngles;
194 		VectorSet(vVehAngles, pVeh->m_vOrientation[PITCH], pVeh->m_vOrientation[YAW], 0 );
195 		AngleVectors( vVehAngles, parent->client->ps.moveDir, NULL, NULL );
196 	}
197 
198 	// Check For A Strafe Ram
199 	//------------------------
200 	if (!(pVeh->m_ulFlags&VEH_STRAFERAM) && !(pVeh->m_ulFlags&VEH_FLYING))
201 	{
202 		// Started A Strafe
203 		//------------------
204 		if (pVeh->m_ucmd.rightmove && !pVeh->m_fStrafeTime)
205 		{
206 			pVeh->m_fStrafeTime = (pVeh->m_ucmd.rightmove>0)?(level.time):(-1*level.time);
207 		}
208 
209 		// Ended A Strafe
210 		//----------------
211 		else if (!pVeh->m_ucmd.rightmove && pVeh->m_fStrafeTime)
212 		{
213 			// If It Was A Short Burst, Start The Strafe Ram
214 			//-----------------------------------------------
215 			if ((level.time - abs(pVeh->m_fStrafeTime))<300)
216 			{
217 				if (!VEH_StartStrafeRam(pVeh, (pVeh->m_fStrafeTime>0)))
218 				{
219 					pVeh->m_fStrafeTime = 0;
220 				}
221 			}
222 
223 			// Otherwise, Clear The Timer
224 			//----------------------------
225 			else
226 			{
227 				pVeh->m_fStrafeTime = 0;
228 			}
229 		}
230 	}
231 
232 	// If Currently In A StrafeRam, Check To See If It Is Done (Timed Out)
233 	//---------------------------------------------------------------------
234   	else if (!pVeh->m_fStrafeTime)
235 	{
236 		pVeh->m_ulFlags &=~VEH_STRAFERAM;
237 	}
238 
239 
240 	// Exhaust Effects Start And Stop When The Accelerator Is Pressed
241 	//----------------------------------------------------------------
242 	if (pVeh->m_pVehicleInfo->iExhaustFX)
243 	{
244 		// Start It On Each Exhaust Bolt
245 		//-------------------------------
246 		if (pVeh->m_ucmd.forwardmove && !(pVeh->m_ulFlags&VEH_ACCELERATORON))
247 		{
248 			pVeh->m_ulFlags |= VEH_ACCELERATORON;
249 			for (int i=0; (i<MAX_VEHICLE_EXHAUSTS && pVeh->m_iExhaustTag[i]!=-1); i++)
250 			{
251 				G_PlayEffect(pVeh->m_pVehicleInfo->iExhaustFX, parent->playerModel, pVeh->m_iExhaustTag[i], parent->s.number, parent->currentOrigin, 1,	qtrue);
252 			}
253 		}
254 
255 		// Stop It On Each Exhaust Bolt
256 		//------------------------------
257 		else if (!pVeh->m_ucmd.forwardmove && (pVeh->m_ulFlags&VEH_ACCELERATORON))
258 		{
259 			pVeh->m_ulFlags &=~VEH_ACCELERATORON;
260 			for (int i=0; (i<MAX_VEHICLE_EXHAUSTS && pVeh->m_iExhaustTag[i]!=-1); i++)
261 			{
262 				G_StopEffect(pVeh->m_pVehicleInfo->iExhaustFX, parent->playerModel, pVeh->m_iExhaustTag[i], parent->s.number);
263 			}
264 		}
265 	}
266 
267 	if (!(pVeh->m_ulFlags&VEH_ARMORLOW) && (pVeh->m_iArmor <= pVeh->m_pVehicleInfo->armor/3))
268 	{
269 		pVeh->m_ulFlags |= VEH_ARMORLOW;
270 
271 	}
272 
273 	// Armor Gone Effects (Fire)
274 	//---------------------------
275 	if (pVeh->m_pVehicleInfo->iArmorGoneFX)
276 	{
277 		if (!(pVeh->m_ulFlags&VEH_ARMORGONE) && (pVeh->m_iArmor <= 0))
278 		{
279 			pVeh->m_ulFlags |= VEH_ARMORGONE;
280 			G_PlayEffect(pVeh->m_pVehicleInfo->iArmorGoneFX, parent->playerModel, parent->crotchBolt, parent->s.number, parent->currentOrigin, 1, qtrue);
281 			parent->s.loopSound = G_SoundIndex( "sound/vehicles/common/fire_lp.wav" );
282 		}
283 	}
284 #endif
285 
286 	return true;
287 }
288 #endif //QAGAME
289 
290 //MP RULE - ALL PROCESSMOVECOMMANDS FUNCTIONS MUST BE BG-COMPATIBLE!!!
291 //If you really need to violate this rule for SP, then use ifdefs.
292 //By BG-compatible, I mean no use of game-specific data - ONLY use
293 //stuff available in the MP bgEntity (in SP, the bgEntity is #defined
294 //as a gentity, but the MP-compatible access restrictions are based
295 //on the bgEntity structure in the MP codebase) -rww
296 // ProcessMoveCommands the Vehicle.
ProcessMoveCommands(Vehicle_t * pVeh)297 static void ProcessMoveCommands( Vehicle_t *pVeh )
298 {
299 	/************************************************************************************/
300 	/*	BEGIN	Here is where we move the vehicle (forward or back or whatever). BEGIN	*/
301 	/************************************************************************************/
302 	//Client sets ucmds and such for speed alterations
303 	float speedInc, speedIdleDec, speedIdle, /*speedIdleAccel, */speedMin, speedMax;
304 	playerState_t *parentPS;
305 	//playerState_t *pilotPS = NULL;
306 	int	curTime;
307 
308 #ifdef _JK2MP
309 	parentPS = pVeh->m_pParentEntity->playerState;
310 	if (pVeh->m_pPilot)
311 	{
312 		//pilotPS = pVeh->m_pPilot->playerState;
313 	}
314 #else
315 	parentPS = &pVeh->m_pParentEntity->client->ps;
316 	if (pVeh->m_pPilot)
317 	{
318 		//pilotPS = &pVeh->m_pPilot->client->ps;
319 	}
320 #endif
321 
322 
323 	// If we're flying, make us accelerate at 40% (about half) acceleration rate, and restore the pitch
324 	// to origin (straight) position (at 5% increments).
325 	if ( pVeh->m_ulFlags & VEH_FLYING )
326 	{
327 		speedInc = pVeh->m_pVehicleInfo->acceleration * pVeh->m_fTimeModifier * 0.4f;
328 	}
329 #ifdef _JK2MP
330 	else if ( !parentPS->m_iVehicleNum )
331 #else
332 	else if ( !pVeh->m_pVehicleInfo->Inhabited( pVeh ) )
333 #endif
334 	{//drifts to a stop
335 		speedInc = 0;
336 		//pVeh->m_ucmd.forwardmove = 127;
337 	}
338 	else
339 	{
340 		speedInc = pVeh->m_pVehicleInfo->acceleration * pVeh->m_fTimeModifier;
341 	}
342 	speedIdleDec = pVeh->m_pVehicleInfo->decelIdle * pVeh->m_fTimeModifier;
343 
344 #ifndef _JK2MP//SP
345 	curTime = level.time;
346 #elif defined QAGAME//MP GAME
347 	curTime = level.time;
348 #elif defined CGAME//MP CGAME
349 	//FIXME: pass in ucmd?  Not sure if this is reliable...
350 	curTime = pm->cmd.serverTime;
351 #endif
352 
353 
354 
355 	if ( (pVeh->m_pPilot /*&& (pilotPS->weapon == WP_NONE || pilotPS->weapon == WP_MELEE )*/ &&
356 		(pVeh->m_ucmd.buttons & BUTTON_ALT_ATTACK) && pVeh->m_pVehicleInfo->turboSpeed)
357 #ifdef _JK2MP
358 		||
359 		(parentPS && parentPS->electrifyTime > curTime && pVeh->m_pVehicleInfo->turboSpeed) //make them go!
360 #endif
361 		)
362 	{
363 #ifdef _JK2MP
364 		if ( (parentPS && parentPS->electrifyTime > curTime) ||
365 			 (pVeh->m_pPilot->playerState &&
366 			  (pVeh->m_pPilot->playerState->weapon == WP_MELEE ||
367 			  (pVeh->m_pPilot->playerState->weapon == WP_SABER && pVeh->m_pPilot->playerState->saberHolstered))) )
368 		{
369 #endif
370 			if ((curTime - pVeh->m_iTurboTime)>pVeh->m_pVehicleInfo->turboRecharge)
371 			{
372 				pVeh->m_iTurboTime = (curTime + pVeh->m_pVehicleInfo->turboDuration);
373 				if (pVeh->m_pVehicleInfo->iTurboStartFX)
374 				{
375 					int i;
376 					for (i=0; (i<MAX_VEHICLE_EXHAUSTS && pVeh->m_iExhaustTag[i]!=-1); i++)
377 					{
378 						#ifndef _JK2MP//SP
379 							// Start The Turbo Fx Start
380 							//--------------------------
381 							G_PlayEffect(pVeh->m_pVehicleInfo->iTurboStartFX, pVeh->m_pParentEntity->playerModel, pVeh->m_iExhaustTag[i], pVeh->m_pParentEntity->s.number, pVeh->m_pParentEntity->currentOrigin );
382 
383 							// Start The Looping Effect
384 							//--------------------------
385 							if (pVeh->m_pVehicleInfo->iTurboFX)
386 							{
387 								G_PlayEffect(pVeh->m_pVehicleInfo->iTurboFX,	  pVeh->m_pParentEntity->playerModel, pVeh->m_iExhaustTag[i], pVeh->m_pParentEntity->s.number, pVeh->m_pParentEntity->currentOrigin, pVeh->m_pVehicleInfo->turboDuration, qtrue);
388 							}
389 
390 						#else
391 							#ifdef QAGAME
392 								if (pVeh->m_pParentEntity &&
393 									pVeh->m_pParentEntity->ghoul2 &&
394 									pVeh->m_pParentEntity->playerState)
395 								{ //fine, I'll use a tempent for this, but only because it's played only once at the start of a turbo.
396 									vec3_t boltOrg, boltDir;
397 									mdxaBone_t boltMatrix;
398 
399 									VectorSet(boltDir, 0.0f, pVeh->m_pParentEntity->playerState->viewangles[YAW], 0.0f);
400 
401 									trap_G2API_GetBoltMatrix(pVeh->m_pParentEntity->ghoul2, 0, pVeh->m_iExhaustTag[i], &boltMatrix, boltDir, pVeh->m_pParentEntity->playerState->origin, level.time, NULL, pVeh->m_pParentEntity->modelScale);
402 									BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, boltOrg);
403 									BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, boltDir);
404 									G_PlayEffectID(pVeh->m_pVehicleInfo->iTurboStartFX, boltOrg, boltDir);
405 								}
406 							#endif
407 						#endif
408 					}
409 				}
410 	#ifndef _JK2MP //kill me now
411 				if (pVeh->m_pVehicleInfo->soundTurbo)
412 				{
413 					G_SoundIndexOnEnt(pVeh->m_pParentEntity, CHAN_AUTO, pVeh->m_pVehicleInfo->soundTurbo);
414 				}
415 	#endif
416 				parentPS->speed = pVeh->m_pVehicleInfo->turboSpeed;	// Instantly Jump To Turbo Speed
417 			}
418 #ifdef _JK2MP
419 		}
420 #endif
421 	}
422 
423 	// Slide Breaking
424 	if (pVeh->m_ulFlags&VEH_SLIDEBREAKING)
425 	{
426 		if (pVeh->m_ucmd.forwardmove>=0
427 #ifndef _JK2MP
428 			|| ((level.time - pVeh->m_pParentEntity->lastMoveTime)>500)
429 #endif
430 			)
431 		{
432 			pVeh->m_ulFlags &= ~VEH_SLIDEBREAKING;
433 		}
434 		parentPS->speed = 0;
435 	}
436 	else if (
437 		(curTime > pVeh->m_iTurboTime) &&
438 		!(pVeh->m_ulFlags&VEH_FLYING) &&
439 		pVeh->m_ucmd.forwardmove<0 &&
440 		fabs(pVeh->m_vOrientation[ROLL])>25.0f)
441 	{
442 		pVeh->m_ulFlags |= VEH_SLIDEBREAKING;
443 	}
444 
445 
446 	if ( curTime < pVeh->m_iTurboTime )
447 	{
448 		speedMax = pVeh->m_pVehicleInfo->turboSpeed;
449 		if (parentPS)
450 		{
451 			parentPS->eFlags |= EF_JETPACK_ACTIVE;
452 		}
453 	}
454 	else
455 	{
456 		speedMax = pVeh->m_pVehicleInfo->speedMax;
457 		if (parentPS)
458 		{
459 			parentPS->eFlags &= ~EF_JETPACK_ACTIVE;
460 		}
461 	}
462 
463 
464 	speedIdle = pVeh->m_pVehicleInfo->speedIdle;
465 	//speedIdleAccel = pVeh->m_pVehicleInfo->accelIdle * pVeh->m_fTimeModifier;
466 	speedMin = pVeh->m_pVehicleInfo->speedMin;
467 
468 	if ( parentPS->speed || parentPS->groundEntityNum == ENTITYNUM_NONE  ||
469 		 pVeh->m_ucmd.forwardmove || pVeh->m_ucmd.upmove > 0 )
470 	{
471 		if ( pVeh->m_ucmd.forwardmove > 0 && speedInc )
472 		{
473 			parentPS->speed += speedInc;
474 		}
475 		else if ( pVeh->m_ucmd.forwardmove < 0 )
476 		{
477 			if ( parentPS->speed > speedIdle )
478 			{
479 				parentPS->speed -= speedInc;
480 			}
481 			else if ( parentPS->speed > speedMin )
482 			{
483 				parentPS->speed -= speedIdleDec;
484 			}
485 		}
486 		// No input, so coast to stop.
487 		else if ( parentPS->speed > 0.0f )
488 		{
489 			parentPS->speed -= speedIdleDec;
490 			if ( parentPS->speed < 0.0f )
491 			{
492 				parentPS->speed = 0.0f;
493 			}
494 		}
495 		else if ( parentPS->speed < 0.0f )
496 		{
497 			parentPS->speed += speedIdleDec;
498 			if ( parentPS->speed > 0.0f )
499 			{
500 				parentPS->speed = 0.0f;
501 			}
502 		}
503 	}
504 	else
505 	{
506 		if ( !pVeh->m_pVehicleInfo->strafePerc
507 #ifdef _JK2MP
508 			|| (0 && pVeh->m_pParentEntity->s.number < MAX_CLIENTS) )
509 #else
510 			|| (!g_speederControlScheme->value && !pVeh->m_pParentEntity->s.number) )
511 #endif
512 		{//if in a strafe-capable vehicle, clear strafing unless using alternate control scheme
513 			//pVeh->m_ucmd.rightmove = 0;
514 		}
515 	}
516 
517 	if ( parentPS->speed > speedMax )
518 	{
519 		parentPS->speed = speedMax;
520 	}
521 	else if ( parentPS->speed < speedMin )
522 	{
523 		parentPS->speed = speedMin;
524 	}
525 
526 #ifndef _JK2MP
527 	// In SP, The AI Pilots Can Directly Control The Speed Of Their Bike In Order To
528 	// Match The Speed Of The Person They Are Trying To Chase
529 	//-------------------------------------------------------------------------------
530 	if (pVeh->m_pPilot && (pVeh->m_ucmd.buttons&BUTTON_VEH_SPEED))
531 	{
532 		parentPS->speed = pVeh->m_pPilot->client->ps.speed;
533 	}
534 #endif
535 
536 
537 	/********************************************************************************/
538 	/*	END Here is where we move the vehicle (forward or back or whatever). END	*/
539 	/********************************************************************************/
540 }
541 
542 //MP RULE - ALL PROCESSORIENTCOMMANDS FUNCTIONS MUST BE BG-COMPATIBLE!!!
543 //If you really need to violate this rule for SP, then use ifdefs.
544 //By BG-compatible, I mean no use of game-specific data - ONLY use
545 //stuff available in the MP bgEntity (in SP, the bgEntity is #defined
546 //as a gentity, but the MP-compatible access restrictions are based
547 //on the bgEntity structure in the MP codebase) -rww
548 //Oh, and please, use "< MAX_CLIENTS" to check for "player" and not
549 //"!s.number", this is a universal check that will work for both SP
550 //and MP. -rww
551 // ProcessOrientCommands the Vehicle.
552 #ifdef _JK2MP //temp hack til mp speeder controls are sorted -rww
553 extern void AnimalProcessOri(Vehicle_t *pVeh);
554 #endif
ProcessOrientCommands(Vehicle_t * pVeh)555 void ProcessOrientCommands( Vehicle_t *pVeh )
556 {
557 	/********************************************************************************/
558 	/*	BEGIN	Here is where make sure the vehicle is properly oriented.	BEGIN	*/
559 	/********************************************************************************/
560 	playerState_t *riderPS;
561 
562 #ifdef _JK2MP
563 	playerState_t *parentPS;
564 	float angDif;
565 
566 	if (pVeh->m_pPilot)
567 	{
568 		riderPS = pVeh->m_pPilot->playerState;
569 	}
570 	else
571 	{
572 		riderPS = pVeh->m_pParentEntity->playerState;
573 	}
574 	//parentPS = pVeh->m_pParentEntity->playerState;
575 
576 	//pVeh->m_vOrientation[YAW] = 0.0f;//riderPS->viewangles[YAW];
577 	angDif = AngleSubtract(pVeh->m_vOrientation[YAW], riderPS->viewangles[YAW]);
578 	if (parentPS && parentPS->speed)
579 	{
580 		float s = parentPS->speed;
581 		float maxDif = pVeh->m_pVehicleInfo->turningSpeed*4.0f; //magic number hackery
582 		if (s < 0.0f)
583 		{
584 			s = -s;
585 		}
586 		angDif *= s/pVeh->m_pVehicleInfo->speedMax;
587 		if (angDif > maxDif)
588 		{
589 			angDif = maxDif;
590 		}
591 		else if (angDif < -maxDif)
592 		{
593 			angDif = -maxDif;
594 		}
595 		pVeh->m_vOrientation[YAW] = AngleNormalize180(pVeh->m_vOrientation[YAW] - angDif*(pVeh->m_fTimeModifier*0.2f));
596 
597 		if (parentPS->electrifyTime > pm->cmd.serverTime)
598 		{ //do some crazy stuff
599 			pVeh->m_vOrientation[YAW] += (sin(pm->cmd.serverTime/1000.0f)*3.0f)*pVeh->m_fTimeModifier;
600 		}
601 	}
602 
603 #else
604  	gentity_t *rider = pVeh->m_pParentEntity->owner;
605 	if ( !rider || !rider->client )
606 	{
607 		riderPS = &pVeh->m_pParentEntity->client->ps;
608 	}
609 	else
610 	{
611 		riderPS = &rider->client->ps;
612 	}
613 	//parentPS = &pVeh->m_pParentEntity->client->ps;
614 
615 	if (pVeh->m_ulFlags & VEH_FLYING)
616 	{
617 		pVeh->m_vOrientation[YAW] += pVeh->m_vAngularVelocity;
618 	}
619 	else if (
620 		(pVeh->m_ulFlags & VEH_SLIDEBREAKING) ||	// No Angles Control While Out Of Control
621 		(pVeh->m_ulFlags & VEH_OUTOFCONTROL) 		// No Angles Control While Out Of Control
622 		)
623 	{
624 		// Any ability to change orientation?
625 	}
626 	else if (
627 		(pVeh->m_ulFlags & VEH_STRAFERAM)			// No Angles Control While Strafe Ramming
628 		)
629 	{
630 		if (pVeh->m_fStrafeTime>0)
631 		{
632 			pVeh->m_fStrafeTime--;
633 			pVeh->m_vOrientation[ROLL] += (pVeh->m_fStrafeTime<( STRAFERAM_DURATION/2))?(-STRAFERAM_ANGLE):( STRAFERAM_ANGLE);
634 		}
635 		else if (pVeh->m_fStrafeTime<0)
636 		{
637 			pVeh->m_fStrafeTime++;
638 			pVeh->m_vOrientation[ROLL] += (pVeh->m_fStrafeTime>(-STRAFERAM_DURATION/2))?( STRAFERAM_ANGLE):(-STRAFERAM_ANGLE);
639 		}
640 	}
641 	else
642 	{
643 		pVeh->m_vOrientation[YAW] = riderPS->viewangles[YAW];
644 	}
645 #endif
646 
647 	/********************************************************************************/
648 	/*	END	Here is where make sure the vehicle is properly oriented.	END			*/
649 	/********************************************************************************/
650 }
651 
652 #ifdef QAGAME
653 
654 extern void PM_SetAnim(pmove_t	*pm,int setAnimParts,int anim,int setAnimFlags, int blendTime);
655 extern int PM_AnimLength( int index, animNumber_t anim );
656 
657 // This function makes sure that the vehicle is properly animated.
AnimateVehicle(Vehicle_t * pVeh)658 void AnimateVehicle( Vehicle_t *pVeh )
659 {
660 }
661 
662 #endif //QAGAME
663 
664 //rest of file is shared
665 
666 #ifndef	_JK2MP
667 extern void CG_ChangeWeapon( int num );
668 #endif
669 
670 
671 #ifndef _JK2MP
672 extern void G_StartMatrixEffect( gentity_t *ent, int meFlags = 0, int length = 1000, float timeScale = 0.0f, int spinTime = 0 );
673 #endif
674 
675 
676 //NOTE NOTE NOTE NOTE NOTE NOTE
677 //I want to keep this function BG too, because it's fairly generic already, and it
678 //would be nice to have proper prediction of animations. -rww
679 // This function makes sure that the rider's in this vehicle are properly animated.
AnimateRiders(Vehicle_t * pVeh)680 void AnimateRiders( Vehicle_t *pVeh )
681 {
682 	animNumber_t Anim = BOTH_VS_IDLE;
683 	//float fSpeedPercToMax;
684 	int iFlags = SETANIM_FLAG_NORMAL, iBlend = 300;
685 	playerState_t *pilotPS;
686 	//playerState_t *parentPS;
687 	int curTime;
688 
689 
690 	// Boarding animation.
691 	if ( pVeh->m_iBoarding != 0 )
692 	{
693 		// We've just started moarding, set the amount of time it will take to finish moarding.
694 		if ( pVeh->m_iBoarding < 0 )
695 		{
696 			int iAnimLen;
697 
698 			// Boarding from left...
699 			if ( pVeh->m_iBoarding == -1 )
700 			{
701 				Anim = BOTH_VS_MOUNT_L;
702 			}
703 			else if ( pVeh->m_iBoarding == -2 )
704 			{
705 				Anim = BOTH_VS_MOUNT_R;
706 			}
707 			else if ( pVeh->m_iBoarding == -3 )
708 			{
709 				Anim = BOTH_VS_MOUNTJUMP_L;
710 			}
711 			else if ( pVeh->m_iBoarding == VEH_MOUNT_THROW_LEFT)
712 			{
713 				iBlend = 0;
714 				Anim = BOTH_VS_MOUNTTHROW_R;
715 			}
716 			else if ( pVeh->m_iBoarding == VEH_MOUNT_THROW_RIGHT)
717 			{
718 				iBlend = 0;
719 				Anim = BOTH_VS_MOUNTTHROW_L;
720 			}
721 
722 			// Set the delay time (which happens to be the time it takes for the animation to complete).
723 			// NOTE: Here I made it so the delay is actually 40% (0.4f) of the animation time.
724 #ifdef _JK2MP
725 			iAnimLen = BG_AnimLength( pVeh->m_pPilot->localAnimIndex, Anim ) * 0.4f;
726 			pVeh->m_iBoarding = BG_GetTime() + iAnimLen;
727 #else
728  			iAnimLen = PM_AnimLength( pVeh->m_pPilot->client->clientInfo.animFileIndex, Anim );// * 0.4f;
729 			if (pVeh->m_iBoarding!=VEH_MOUNT_THROW_LEFT && pVeh->m_iBoarding!=VEH_MOUNT_THROW_RIGHT)
730 			{
731 				pVeh->m_iBoarding = level.time + (iAnimLen*0.4f);
732 			}
733 			else
734 			{
735 				pVeh->m_iBoarding = level.time + iAnimLen;
736 			}
737 #endif
738 			// Set the animation, which won't be interrupted until it's completed.
739 			// TODO: But what if he's killed? Should the animation remain persistant???
740 			iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD;
741 
742 #ifdef _JK2MP
743 			BG_SetAnim(pVeh->m_pPilot->playerState, bgAllAnims[pVeh->m_pPilot->localAnimIndex].anims,
744 				SETANIM_BOTH, Anim, iFlags, iBlend);
745 #else
746 			NPC_SetAnim( pVeh->m_pPilot, SETANIM_BOTH, Anim, iFlags, iBlend );
747 			if (pVeh->m_pOldPilot)
748 			{
749 				iAnimLen = PM_AnimLength( pVeh->m_pPilot->client->clientInfo.animFileIndex, BOTH_VS_MOUNTTHROWEE);
750 				NPC_SetAnim( pVeh->m_pOldPilot, SETANIM_BOTH, BOTH_VS_MOUNTTHROWEE, iFlags, iBlend );
751 			}
752 #endif
753 		}
754 
755 #ifndef _JK2MP
756 		if (pVeh->m_pOldPilot && pVeh->m_pOldPilot->client->ps.torsoAnimTimer<=0)
757 		{
758 			if (Q_irand(0, player->count)==0)
759 			{
760 				player->count++;
761  				player->lastEnemy = pVeh->m_pOldPilot;
762 				G_StartMatrixEffect(player, MEF_LOOK_AT_ENEMY|MEF_NO_RANGEVAR|MEF_NO_VERTBOB|MEF_NO_SPIN, 1000);
763 			}
764 
765  			gentity_t*	oldPilot = pVeh->m_pOldPilot;
766 			pVeh->m_pVehicleInfo->Eject(pVeh, pVeh->m_pOldPilot, qtrue);		// will set pointer to zero
767 
768 			// Kill Him
769 			//----------
770 			oldPilot->client->noRagTime = -1;	// no ragdoll for you
771 			G_Damage(oldPilot, pVeh->m_pPilot, pVeh->m_pPilot, pVeh->m_pPilot->currentAngles, pVeh->m_pPilot->currentOrigin, 1000, 0, MOD_CRUSH);
772 
773 			// Compute THe Throw Direction As Backwards From The Vehicle's Velocity
774 			//----------------------------------------------------------------------
775 			vec3_t		throwDir;
776 			VectorScale(pVeh->m_pParentEntity->client->ps.velocity, -1.0f, throwDir);
777 			VectorNormalize(throwDir);
778 			throwDir[2] += 0.3f;	// up a little
779 
780 			// Now Throw Him Out
781 			//-------------------
782 			G_Throw(oldPilot, throwDir, VectorLength(pVeh->m_pParentEntity->client->ps.velocity)/10.0f);
783 			NPC_SetAnim(oldPilot, SETANIM_BOTH, BOTH_DEATHBACKWARD1, SETANIM_FLAG_OVERRIDE, iBlend );
784 		}
785 #endif
786 
787 		return;
788 	}
789 
790 #ifdef _JK2MP //fixme
791 	if (1) return;
792 #endif
793 
794 #ifdef _JK2MP
795 	pilotPS = pVeh->m_pPilot->playerState;
796 	//parentPS = pVeh->m_pPilot->playerState;
797 #else
798 	pilotPS = &pVeh->m_pPilot->client->ps;
799 	//parentPS = &pVeh->m_pParentEntity->client->ps;
800 #endif
801 
802 #ifndef _JK2MP//SP
803 	curTime = level.time;
804 #elif defined QAGAME//MP GAME
805 	curTime = level.time;
806 #elif defined CGAME//MP CGAME
807 	//FIXME: pass in ucmd?  Not sure if this is reliable...
808 	curTime = pm->cmd.serverTime;
809 #endif
810 
811 	// Percentage of maximum speed relative to current speed.
812 	//fSpeedPercToMax = parentPS->speed / pVeh->m_pVehicleInfo->speedMax;
813 
814 /*	// Going in reverse...
815 #ifdef _JK2MP
816 	if ( pVeh->m_ucmd.forwardmove < 0 && !(pVeh->m_ulFlags & VEH_SLIDEBREAKING))
817 #else
818 	if ( fSpeedPercToMax < -0.018f && !(pVeh->m_ulFlags & VEH_SLIDEBREAKING))
819 #endif
820 	{
821 		Anim = BOTH_VS_REV;
822 		iBlend = 500;
823 		bool		HasWeapon	= ((pilotPS->weapon != WP_NONE) && (pilotPS->weapon != WP_MELEE));
824 		if (HasWeapon)
825 		{
826 			if (pVeh->m_pPilot->s.number<MAX_CLIENTS)
827 			{
828 				CG_ChangeWeapon(WP_NONE);
829 			}
830 
831 			pVeh->m_pPilot->client->ps.weapon = WP_NONE;
832 			G_RemoveWeaponModels(pVeh->m_pPilot);
833 		}
834 	}
835 	else
836 */
837 	{
838 		bool		HasWeapon	= ((pilotPS->weapon != WP_NONE) && (pilotPS->weapon != WP_MELEE));
839 		bool		Attacking	= (HasWeapon && !!(pVeh->m_ucmd.buttons&BUTTON_ATTACK));
840 #ifdef _JK2MP //fixme: flying tends to spaz out a lot
841 		bool		Flying		= false;
842 		bool		Crashing	= false;
843 #else
844 		bool		Flying		= !!(pVeh->m_ulFlags & VEH_FLYING);
845 		bool		Crashing	= !!(pVeh->m_ulFlags & VEH_CRASHING);
846 #endif
847 		bool		Right		= (pVeh->m_ucmd.rightmove>0);
848 		bool		Left		= (pVeh->m_ucmd.rightmove<0);
849 		bool		Turbo		= (curTime<pVeh->m_iTurboTime);
850 		EWeaponPose	WeaponPose	= WPOSE_NONE;
851 
852 
853 		// Remove Crashing Flag
854 		//----------------------
855 		pVeh->m_ulFlags &= ~VEH_CRASHING;
856 
857 
858 		// Put Away Saber When It Is Not Active
859 		//--------------------------------------
860 #ifndef _JK2MP
861 		if (HasWeapon &&
862 			(pVeh->m_pPilot->s.number>=MAX_CLIENTS || (cg.weaponSelectTime+500)<cg.time) &&
863 			(Turbo || (pilotPS->weapon==WP_SABER && !pilotPS->SaberActive())))
864 		{
865 			if (pVeh->m_pPilot->s.number<MAX_CLIENTS)
866 			{
867 				pVeh->m_pPilot->client->ps.stats[ STAT_WEAPONS ] |= 1;					// Riding means you get WP_NONE
868 				CG_ChangeWeapon(WP_NONE);
869 			}
870 
871 			pVeh->m_pPilot->client->ps.weapon = WP_NONE;
872 			G_RemoveWeaponModels(pVeh->m_pPilot);
873 		}
874 #endif
875 
876 		// Don't Interrupt Attack Anims
877 		//------------------------------
878 #ifdef _JK2MP
879 		if (pilotPS->weaponTime>0)
880 		{
881 			return;
882 		}
883 #else
884 		if (pilotPS->torsoAnim>=BOTH_VS_ATL_S && pilotPS->torsoAnim<=BOTH_VS_ATF_G)
885 		{
886 			float		bodyCurrent	  = 0.0f;
887 			int			bodyEnd		  = 0;
888 			if (!!gi.G2API_GetBoneAnimIndex(&pVeh->m_pPilot->ghoul2[pVeh->m_pPilot->playerModel], pVeh->m_pPilot->rootBone, level.time, &bodyCurrent, NULL, &bodyEnd, NULL, NULL, NULL))
889 			{
890 				if (bodyCurrent<=((float)(bodyEnd)-1.5f))
891 				{
892 					return;
893 				}
894 			}
895 		}
896 #endif
897 
898 		// Compute The Weapon Pose
899 		//--------------------------
900 		if (pilotPS->weapon==WP_BLASTER)
901 		{
902 			WeaponPose = WPOSE_BLASTER;
903 		}
904 		else if (pilotPS->weapon==WP_SABER)
905 		{
906 			if ( (pVeh->m_ulFlags&VEH_SABERINLEFTHAND) && pilotPS->torsoAnim==BOTH_VS_ATL_TO_R_S)
907 			{
908 				pVeh->m_ulFlags	&= ~VEH_SABERINLEFTHAND;
909 			}
910 			if (!(pVeh->m_ulFlags&VEH_SABERINLEFTHAND) && pilotPS->torsoAnim==BOTH_VS_ATR_TO_L_S)
911 			{
912 				pVeh->m_ulFlags	|=  VEH_SABERINLEFTHAND;
913 			}
914 			WeaponPose = (pVeh->m_ulFlags&VEH_SABERINLEFTHAND)?(WPOSE_SABERLEFT):(WPOSE_SABERRIGHT);
915 		}
916 
917 
918  		if (Attacking && WeaponPose)
919 		{// Attack!
920 			iBlend	= 100;
921  			iFlags	= SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_RESTART;
922 
923 			// Auto Aiming
924 			//===============================================
925 			if (!Left && !Right)		// Allow player strafe keys to override
926 			{
927 #ifndef _JK2MP
928 				if (pVeh->m_pPilot->enemy)
929 				{
930 					vec3_t	toEnemy;
931 					//float	toEnemyDistance;
932 					vec3_t	actorRight;
933 					float	actorRightDot;
934 
935 					VectorSubtract(pVeh->m_pPilot->currentOrigin, pVeh->m_pPilot->enemy->currentOrigin, toEnemy);
936 					/*toEnemyDistance = */VectorNormalize(toEnemy);
937 
938 					AngleVectors(pVeh->m_pParentEntity->currentAngles, 0, actorRight, 0);
939 					actorRightDot = DotProduct(toEnemy, actorRight);
940 
941 	 				if (fabsf(actorRightDot)>0.5f || pilotPS->weapon==WP_SABER)
942 					{
943 						Left	= (actorRightDot>0.0f);
944 						Right	= !Left;
945 					}
946 					else
947 					{
948 						Right = Left = false;
949 					}
950 				}
951 				else
952 #endif
953 				if (pilotPS->weapon==WP_SABER && !Left && !Right)
954 				{
955 					Left = (WeaponPose==WPOSE_SABERLEFT);
956 					Right	= !Left;
957 				}
958 			}
959 
960 
961 			if (Left)
962 			{// Attack Left
963 				switch(WeaponPose)
964 				{
965 				case WPOSE_BLASTER:		Anim = BOTH_VS_ATL_G;		break;
966 				case WPOSE_SABERLEFT:	Anim = BOTH_VS_ATL_S;		break;
967 				case WPOSE_SABERRIGHT:	Anim = BOTH_VS_ATR_TO_L_S;	break;
968 				default:				assert(0);
969 				}
970 			}
971 			else if (Right)
972 			{// Attack Right
973 				switch(WeaponPose)
974 				{
975 				case WPOSE_BLASTER:		Anim = BOTH_VS_ATR_G;		break;
976 				case WPOSE_SABERLEFT:	Anim = BOTH_VS_ATL_TO_R_S;	break;
977 				case WPOSE_SABERRIGHT:	Anim = BOTH_VS_ATR_S;		break;
978 				default:				assert(0);
979 				}
980 			}
981 			else
982 			{// Attack Ahead
983 				switch(WeaponPose)
984 				{
985 				case WPOSE_BLASTER:		Anim = BOTH_VS_ATF_G;		break;
986 				default:				assert(0);
987 				}
988 			}
989 
990 		}
991 		else if (Left && pVeh->m_ucmd.buttons&BUTTON_USE)
992 		{// Look To The Left Behind
993 			iBlend	= 400;
994 			iFlags	= SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD;
995 			switch(WeaponPose)
996 			{
997 			case WPOSE_SABERLEFT:	Anim = BOTH_VS_IDLE_SL;		break;
998 			case WPOSE_SABERRIGHT:	Anim = BOTH_VS_IDLE_SR;		break;
999 			default:				Anim = BOTH_VS_LOOKLEFT;
1000 			}
1001 		}
1002 		else if (Right && pVeh->m_ucmd.buttons&BUTTON_USE)
1003 		{// Look To The Right Behind
1004 			iBlend	= 400;
1005 			iFlags	= SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD;
1006 			switch(WeaponPose)
1007 			{
1008 			case WPOSE_SABERLEFT:	Anim = BOTH_VS_IDLE_SL;		break;
1009 			case WPOSE_SABERRIGHT:	Anim = BOTH_VS_IDLE_SR;		break;
1010 			default:				Anim = BOTH_VS_LOOKRIGHT;
1011 			}
1012 		}
1013 		else if (Turbo)
1014 		{// Kicked In Turbo
1015 			iBlend	= 50;
1016 			iFlags	= SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLDLESS;
1017 			Anim	= BOTH_VS_TURBO;
1018 		}
1019 		else if (Flying)
1020 		{// Off the ground in a jump
1021 			iBlend	= 800;
1022 			iFlags	= SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD;
1023 
1024 			switch(WeaponPose)
1025 			{
1026 			case WPOSE_NONE:		Anim = BOTH_VS_AIR;			break;
1027 			case WPOSE_BLASTER:		Anim = BOTH_VS_AIR_G;		break;
1028 			case WPOSE_SABERLEFT:	Anim = BOTH_VS_AIR_SL;		break;
1029 			case WPOSE_SABERRIGHT:	Anim = BOTH_VS_AIR_SR;		break;
1030 			default:				assert(0);
1031 			}
1032 		}
1033 		else if (Crashing)
1034 		{// Hit the ground!
1035 			iBlend	= 100;
1036 			iFlags	= SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLDLESS;
1037 
1038 			switch(WeaponPose)
1039 			{
1040 			case WPOSE_NONE:		Anim = BOTH_VS_LAND;		break;
1041 			case WPOSE_BLASTER:		Anim = BOTH_VS_LAND_G;		break;
1042 			case WPOSE_SABERLEFT:	Anim = BOTH_VS_LAND_SL;		break;
1043 			case WPOSE_SABERRIGHT:	Anim = BOTH_VS_LAND_SR;		break;
1044 			default:				assert(0);
1045 			}
1046 		}
1047 		else
1048 		{// No Special Moves
1049 			iBlend	= 300;
1050  			iFlags	= SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLDLESS;
1051 
1052 			if (pVeh->m_vOrientation[ROLL] <= -20)
1053 			{// Lean Left
1054 				switch(WeaponPose)
1055 				{
1056 				case WPOSE_NONE:		Anim = BOTH_VS_LEANL;			break;
1057 				case WPOSE_BLASTER:		Anim = BOTH_VS_LEANL_G;			break;
1058 				case WPOSE_SABERLEFT:	Anim = BOTH_VS_LEANL_SL;		break;
1059 				case WPOSE_SABERRIGHT:	Anim = BOTH_VS_LEANL_SR;		break;
1060 				default:				assert(0);
1061 				}
1062 			}
1063 			else if (pVeh->m_vOrientation[ROLL] >= 20)
1064 			{// Lean Right
1065 				switch(WeaponPose)
1066 				{
1067 				case WPOSE_NONE:		Anim = BOTH_VS_LEANR;			break;
1068 				case WPOSE_BLASTER:		Anim = BOTH_VS_LEANR_G;			break;
1069 				case WPOSE_SABERLEFT:	Anim = BOTH_VS_LEANR_SL;		break;
1070 				case WPOSE_SABERRIGHT:	Anim = BOTH_VS_LEANR_SR;		break;
1071 				default:				assert(0);
1072 				}
1073 			}
1074 			else
1075 			{// No Lean
1076 				switch(WeaponPose)
1077 				{
1078 				case WPOSE_NONE:		Anim = BOTH_VS_IDLE;			break;
1079 				case WPOSE_BLASTER:		Anim = BOTH_VS_IDLE_G;			break;
1080 				case WPOSE_SABERLEFT:	Anim = BOTH_VS_IDLE_SL;			break;
1081 				case WPOSE_SABERRIGHT:	Anim = BOTH_VS_IDLE_SR;			break;
1082 				default:				assert(0);
1083 				}
1084 			}
1085 		}// No Special Moves
1086 	}// Going backwards?
1087 
1088 #ifdef _JK2MP
1089 	iFlags &= ~SETANIM_FLAG_OVERRIDE;
1090 	if (pVeh->m_pPilot->playerState->torsoAnim == Anim)
1091 	{
1092 		pVeh->m_pPilot->playerState->torsoTimer = BG_AnimLength(pVeh->m_pPilot->localAnimIndex, Anim);
1093 	}
1094 	if (pVeh->m_pPilot->playerState->legsAnim == Anim)
1095 	{
1096 		pVeh->m_pPilot->playerState->legsTimer = BG_AnimLength(pVeh->m_pPilot->localAnimIndex, Anim);
1097 	}
1098 	BG_SetAnim(pVeh->m_pPilot->playerState, bgAllAnims[pVeh->m_pPilot->localAnimIndex].anims,
1099 		SETANIM_BOTH, Anim, iFlags|SETANIM_FLAG_HOLD, iBlend);
1100 #else
1101 	NPC_SetAnim( pVeh->m_pPilot, SETANIM_BOTH, Anim, iFlags, iBlend );
1102 #endif
1103 }
1104 
1105 #ifndef QAGAME
1106 void AttachRidersGeneric( Vehicle_t *pVeh );
1107 #endif
1108 
G_SetSpeederVehicleFunctions(vehicleInfo_t * pVehInfo)1109 void G_SetSpeederVehicleFunctions( vehicleInfo_t *pVehInfo )
1110 {
1111 #ifdef QAGAME
1112 	pVehInfo->AnimateVehicle			=		AnimateVehicle;
1113 	pVehInfo->AnimateRiders				=		AnimateRiders;
1114 //	pVehInfo->ValidateBoard				=		ValidateBoard;
1115 //	pVehInfo->SetParent					=		SetParent;
1116 //	pVehInfo->SetPilot					=		SetPilot;
1117 //	pVehInfo->AddPassenger				=		AddPassenger;
1118 //	pVehInfo->Animate					=		Animate;
1119 //	pVehInfo->Board						=		Board;
1120 //	pVehInfo->Eject						=		Eject;
1121 //	pVehInfo->EjectAll					=		EjectAll;
1122 //	pVehInfo->StartDeathDelay			=		StartDeathDelay;
1123 //	pVehInfo->DeathUpdate				=		DeathUpdate;
1124 //	pVehInfo->RegisterAssets			=		RegisterAssets;
1125 //	pVehInfo->Initialize				=		Initialize;
1126 	pVehInfo->Update					=		Update;
1127 //	pVehInfo->UpdateRider				=		UpdateRider;
1128 #endif
1129 
1130 	//shared
1131 	pVehInfo->ProcessMoveCommands		=		ProcessMoveCommands;
1132 	pVehInfo->ProcessOrientCommands		=		ProcessOrientCommands;
1133 
1134 #ifndef QAGAME //cgame prediction attachment func
1135 	pVehInfo->AttachRiders				=		AttachRidersGeneric;
1136 #endif
1137 //	pVehInfo->AttachRiders				=		AttachRiders;
1138 //	pVehInfo->Ghost						=		Ghost;
1139 //	pVehInfo->UnGhost					=		UnGhost;
1140 //	pVehInfo->Inhabited					=		Inhabited;
1141 }
1142 
1143 // Following is only in game, not in namespace
1144 #ifdef _JK2MP
1145 #include "../namespace_end.h"
1146 #endif
1147 
1148 #ifdef QAGAME
1149 extern void G_AllocateVehicleObject(Vehicle_t **pVeh);
1150 #endif
1151 
1152 #ifdef _JK2MP
1153 #include "../namespace_begin.h"
1154 #endif
1155 
1156 // Create/Allocate a new Animal Vehicle (initializing it as well).
G_CreateSpeederNPC(Vehicle_t ** pVeh,const char * strType)1157 void G_CreateSpeederNPC( Vehicle_t **pVeh, const char *strType )
1158 {
1159 #ifdef _JK2MP
1160 #ifdef QAGAME
1161 	//these will remain on entities on the client once allocated because the pointer is
1162 	//never stomped. on the server, however, when an ent is freed, the entity struct is
1163 	//memset to 0, so this memory would be lost..
1164     G_AllocateVehicleObject(pVeh);
1165 #else
1166 	if (!*pVeh)
1167 	{ //only allocate a new one if we really have to
1168 		(*pVeh) = (Vehicle_t *) BG_Alloc( sizeof(Vehicle_t) );
1169 	}
1170 #endif
1171 	memset(*pVeh, 0, sizeof(Vehicle_t));
1172 	(*pVeh)->m_pVehicleInfo = &g_vehicleInfo[BG_VehicleGetIndex( strType )];
1173 #else
1174 	// Allocate the Vehicle.
1175 	(*pVeh) = (Vehicle_t *) gi.Malloc( sizeof(Vehicle_t), TAG_G_ALLOC, qtrue );
1176 	(*pVeh)->m_pVehicleInfo = &g_vehicleInfo[BG_VehicleGetIndex( strType )];
1177 #endif
1178 }
1179 
1180 #ifdef _JK2MP
1181 
1182 #include "../namespace_end.h"
1183 
1184 //get rid of all the crazy defs we added for this file
1185 #undef currentAngles
1186 #undef currentOrigin
1187 #undef mins
1188 #undef maxs
1189 #undef legsAnimTimer
1190 #undef torsoAnimTimer
1191 #undef bool
1192 #undef false
1193 #undef true
1194 
1195 #undef sqrtf
1196 #undef Q_flrand
1197 
1198 #undef MOD_EXPLOSIVE
1199 #endif
1200