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