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 #include "bg_public.h"
24 #include "bg_vehicles.h"
25
26 #ifdef _GAME
27 #include "g_local.h"
28 #elif _CGAME
29 #include "cgame/cg_local.h"
30 #endif
31
32 extern float DotToSpot( vec3_t spot, vec3_t from, vec3_t fromAngles );
33 #ifdef _GAME //SP or gameside MP
34 extern vmCvar_t cg_thirdPersonAlpha;
35 extern vec3_t playerMins;
36 extern vec3_t playerMaxs;
37 extern void ChangeWeapon( gentity_t *ent, int newWeapon );
38 extern int PM_AnimLength( int index, animNumber_t anim );
39 extern void G_VehicleTrace( trace_t *results, const vec3_t start, const vec3_t tMins, const vec3_t tMaxs, const vec3_t end, int passEntityNum, int contentmask );
40 #endif
41
42 extern qboolean BG_UnrestrainedPitchRoll( playerState_t *ps, Vehicle_t *pVeh );
43 extern void BG_SetAnim(playerState_t *ps, animation_t *animations, int setAnimParts,int anim,int setAnimFlags);
44 extern int BG_GetTime(void);
45
46 //this stuff has got to be predicted, so..
BG_FighterUpdate(Vehicle_t * pVeh,const usercmd_t * pUcmd,vec3_t trMins,vec3_t trMaxs,float gravity,void (* traceFunc)(trace_t * results,const vec3_t start,const vec3_t lmins,const vec3_t lmaxs,const vec3_t end,int passEntityNum,int contentMask))47 qboolean BG_FighterUpdate(Vehicle_t *pVeh, const usercmd_t *pUcmd, vec3_t trMins, vec3_t trMaxs, float gravity, void (*traceFunc)( trace_t *results, const vec3_t start, const vec3_t lmins, const vec3_t lmaxs, const vec3_t end, int passEntityNum, int contentMask ))
48 {
49 vec3_t bottom;
50 playerState_t *parentPS;
51 //qboolean isDead = qfalse;
52 #ifdef _GAME //don't do this on client
53 int i;
54
55 // Make sure the riders are not visible or collidable.
56 pVeh->m_pVehicleInfo->Ghost( pVeh, pVeh->m_pPilot );
57 for ( i = 0; i < pVeh->m_pVehicleInfo->maxPassengers; i++ )
58 {
59 pVeh->m_pVehicleInfo->Ghost( pVeh, pVeh->m_ppPassengers[i] );
60 }
61 #endif
62
63
64 parentPS = pVeh->m_pParentEntity->playerState;
65
66 if (!parentPS)
67 {
68 Com_Error(ERR_DROP, "NULL PS in BG_FighterUpdate (%s)", pVeh->m_pVehicleInfo->name);
69 return qfalse;
70 }
71
72 // If we have a pilot, take out gravity (it's a flying craft...).
73 if ( pVeh->m_pPilot )
74 {
75 parentPS->gravity = 0;
76 }
77 else
78 {
79 if (pVeh->m_pVehicleInfo->gravity)
80 {
81 parentPS->gravity = pVeh->m_pVehicleInfo->gravity;
82 }
83 else
84 { //it doesn't have gravity specified apparently
85 parentPS->gravity = gravity;
86 }
87 }
88
89 /*
90 isDead = (qboolean)((parentPS->eFlags&EF_DEAD)!=0);
91
92 if ( isDead ||
93 (pVeh->m_pVehicleInfo->surfDestruction &&
94 pVeh->m_iRemovedSurfaces ) )
95 {//can't land if dead or spiralling out of control
96 pVeh->m_LandTrace.fraction = 1.0f;
97 pVeh->m_LandTrace.contents = pVeh->m_LandTrace.surfaceFlags = 0;
98 VectorClear( pVeh->m_LandTrace.plane.normal );
99 pVeh->m_LandTrace.allsolid = qfalse;
100 pVeh->m_LandTrace.startsolid = qfalse;
101 }
102 else
103 {
104 */
105 //argh, no, I need to have a way to see when they impact the ground while damaged. -rww
106
107 // Check to see if the fighter has taken off yet (if it's a certain height above ground).
108 VectorCopy( parentPS->origin, bottom );
109 bottom[2] -= pVeh->m_pVehicleInfo->landingHeight;
110
111 traceFunc( &pVeh->m_LandTrace, parentPS->origin, trMins, trMaxs, bottom, pVeh->m_pParentEntity->s.number, (MASK_NPCSOLID&~CONTENTS_BODY) );
112 //}
113
114 return qtrue;
115 }
116
117 #ifdef _GAME //ONLY in SP or on server, not cgame
118
119 // Like a think or move command, this updates various vehicle properties.
Update(Vehicle_t * pVeh,const usercmd_t * pUcmd)120 static qboolean Update( Vehicle_t *pVeh, const usercmd_t *pUcmd )
121 {
122 assert(pVeh->m_pParentEntity);
123 if (!BG_FighterUpdate(pVeh, pUcmd, ((gentity_t *)pVeh->m_pParentEntity)->r.mins,
124 ((gentity_t *)pVeh->m_pParentEntity)->r.maxs,
125 g_gravity.value,
126 G_VehicleTrace))
127 {
128 return qfalse;
129 }
130
131 if ( !g_vehicleInfo[VEHICLE_BASE].Update( pVeh, pUcmd ) )
132 {
133 return qfalse;
134 }
135
136 return qtrue;
137 }
138
139 // Board this Vehicle (get on). The first entity to board an empty vehicle becomes the Pilot.
Board(Vehicle_t * pVeh,bgEntity_t * pEnt)140 static qboolean Board( Vehicle_t *pVeh, bgEntity_t *pEnt )
141 {
142 if ( !g_vehicleInfo[VEHICLE_BASE].Board( pVeh, pEnt ) )
143 return qfalse;
144
145 // Set the board wait time (they won't be able to do anything, including getting off, for this amount of time).
146 pVeh->m_iBoarding = level.time + 1500;
147
148 return qtrue;
149 }
150
151 // Eject an entity from the vehicle.
Eject(Vehicle_t * pVeh,bgEntity_t * pEnt,qboolean forceEject)152 static qboolean Eject( Vehicle_t *pVeh, bgEntity_t *pEnt, qboolean forceEject )
153 {
154 if ( g_vehicleInfo[VEHICLE_BASE].Eject( pVeh, pEnt, forceEject ) )
155 {
156 return qtrue;
157 }
158
159 return qfalse;
160 }
161
162 #endif //end game-side only
163
164 //method of decrementing the given angle based on the given taking variable frame times into account
PredictedAngularDecrement(float scale,float timeMod,float originalAngle)165 static float PredictedAngularDecrement(float scale, float timeMod, float originalAngle)
166 {
167 float fixedBaseDec = originalAngle*0.05f;
168 float r = 0.0f;
169
170 if (fixedBaseDec < 0.0f)
171 {
172 fixedBaseDec = -fixedBaseDec;
173 }
174
175 fixedBaseDec *= (1.0f+(1.0f-scale));
176
177 if (fixedBaseDec < 0.1f)
178 { //don't increment in incredibly small fractions, it would eat up unnecessary bandwidth.
179 fixedBaseDec = 0.1f;
180 }
181
182 fixedBaseDec *= (timeMod*0.1f);
183 if (originalAngle > 0.0f)
184 { //subtract
185 r = (originalAngle-fixedBaseDec);
186 if (r < 0.0f)
187 {
188 r = 0.0f;
189 }
190 }
191 else if (originalAngle < 0.0f)
192 { //add
193 r = (originalAngle+fixedBaseDec);
194 if (r > 0.0f)
195 {
196 r = 0.0f;
197 }
198 }
199
200 return r;
201 }
202
203 #ifdef _GAME//only do this check on game side, because if it's cgame, it's being predicted, and it's only predicted if the local client is the driver
FighterIsInSpace(gentity_t * gParent)204 qboolean FighterIsInSpace( gentity_t *gParent )
205 {
206 if ( gParent
207 && gParent->client
208 && gParent->client->inSpaceIndex
209 && gParent->client->inSpaceIndex < ENTITYNUM_WORLD )
210 {
211 return qtrue;
212 }
213 return qfalse;
214 }
215 #endif
216
FighterOverValidLandingSurface(Vehicle_t * pVeh)217 qboolean FighterOverValidLandingSurface( Vehicle_t *pVeh )
218 {
219 if ( pVeh->m_LandTrace.fraction < 1.0f //ground present
220 && pVeh->m_LandTrace.plane.normal[2] >= MIN_LANDING_SLOPE )//flat enough
221 //FIXME: also check for a certain surface flag ... "landing zones"?
222 {
223 return qtrue;
224 }
225 return qfalse;
226 }
227
FighterIsLanded(Vehicle_t * pVeh,playerState_t * parentPS)228 qboolean FighterIsLanded( Vehicle_t *pVeh, playerState_t *parentPS )
229 {
230 if ( FighterOverValidLandingSurface( pVeh )
231 && !parentPS->speed )//stopped
232 {
233 return qtrue;
234 }
235 return qfalse;
236 }
237
FighterIsLanding(Vehicle_t * pVeh,playerState_t * parentPS)238 qboolean FighterIsLanding( Vehicle_t *pVeh, playerState_t *parentPS )
239 {
240
241 if ( FighterOverValidLandingSurface( pVeh )
242 #ifdef _GAME//only do this check on game side, because if it's cgame, it's being predicted, and it's only predicted if the local client is the driver
243 && pVeh->m_pVehicleInfo->Inhabited( pVeh )//has to have a driver in order to be capable of landing
244 #endif
245 && (pVeh->m_ucmd.forwardmove < 0||pVeh->m_ucmd.upmove<0) //decelerating or holding crouch button
246 && parentPS->speed <= MIN_LANDING_SPEED )//going slow enough to start landing - was using pVeh->m_pVehicleInfo->speedIdle, but that's still too fast
247 {
248 return qtrue;
249 }
250 return qfalse;
251 }
252
FighterIsLaunching(Vehicle_t * pVeh,playerState_t * parentPS)253 qboolean FighterIsLaunching( Vehicle_t *pVeh, playerState_t *parentPS )
254 {
255
256 if ( FighterOverValidLandingSurface( pVeh )
257 #ifdef _GAME//only do this check on game side, because if it's cgame, it's being predicted, and it's only predicted if the local client is the driver
258 && pVeh->m_pVehicleInfo->Inhabited( pVeh )//has to have a driver in order to be capable of landing
259 #endif
260 && pVeh->m_ucmd.upmove > 0 //trying to take off
261 && parentPS->speed <= 200.0f )//going slow enough to start landing - was using pVeh->m_pVehicleInfo->speedIdle, but that's still too fast
262 {
263 return qtrue;
264 }
265 return qfalse;
266 }
267
FighterSuspended(Vehicle_t * pVeh,playerState_t * parentPS)268 qboolean FighterSuspended( Vehicle_t *pVeh, playerState_t *parentPS )
269 {
270 #ifdef _GAME//only do this check on game side, because if it's cgame, it's being predicted, and it's only predicted if the local client is the driver
271 if (!pVeh->m_pPilot//empty
272 && !parentPS->speed//not moving
273 && pVeh->m_ucmd.forwardmove <= 0//not trying to go forward for whatever reason
274 && pVeh->m_pParentEntity != NULL
275 && (((gentity_t *)pVeh->m_pParentEntity)->spawnflags&2) )//SUSPENDED spawnflag is on
276 {
277 return qtrue;
278 }
279 return qfalse;
280 #elif _CGAME
281 return qfalse;
282 #endif
283 }
284
285 //MP RULE - ALL PROCESSMOVECOMMANDS FUNCTIONS MUST BE BG-COMPATIBLE!!!
286 //If you really need to violate this rule for SP, then use ifdefs.
287 //By BG-compatible, I mean no use of game-specific data - ONLY use
288 //stuff available in the MP bgEntity (in SP, the bgEntity is #defined
289 //as a gentity, but the MP-compatible access restrictions are based
290 //on the bgEntity structure in the MP codebase) -rww
291 // ProcessMoveCommands the Vehicle.
292 #define FIGHTER_MIN_TAKEOFF_FRACTION 0.7f
ProcessMoveCommands(Vehicle_t * pVeh)293 static void ProcessMoveCommands( Vehicle_t *pVeh )
294 {
295 /************************************************************************************/
296 /* BEGIN Here is where we move the vehicle (forward or back or whatever). BEGIN */
297 /************************************************************************************/
298
299 //Client sets ucmds and such for speed alterations
300 float speedInc, speedIdleDec, speedIdle, speedIdleAccel, speedMin, speedMax;
301 bgEntity_t *parent = pVeh->m_pParentEntity;
302 qboolean isLandingOrLaunching = qfalse;
303 //this function should only be called from pmove.. if it gets called elsehwere,
304 //obviously this will explode.
305 int curTime = pm->cmd.serverTime;
306
307 playerState_t *parentPS = parent->playerState;
308
309 if ( parentPS->hyperSpaceTime
310 && curTime - parentPS->hyperSpaceTime < HYPERSPACE_TIME )
311 {//Going to Hyperspace
312 //totally override movement
313 float timeFrac = ((float)(curTime-parentPS->hyperSpaceTime))/HYPERSPACE_TIME;
314 if ( timeFrac < HYPERSPACE_TELEPORT_FRAC )
315 {//for first half, instantly jump to top speed!
316 if ( !(parentPS->eFlags2&EF2_HYPERSPACE) )
317 {//waiting to face the right direction, do nothing
318 parentPS->speed = 0.0f;
319 }
320 else
321 {
322 if ( parentPS->speed < HYPERSPACE_SPEED )
323 {//just started hyperspace
324 //MIKE: This is going to play the sound twice for the predicting client, I suggest using
325 //a predicted event or only doing it game-side. -rich
326 #ifdef _GAME
327 //G_EntitySound( ((gentity_t *)(pVeh->m_pParentEntity)), CHAN_LOCAL, pVeh->m_pVehicleInfo->soundHyper );
328 #elif _CGAME
329 trap->S_StartSound( NULL, pm->ps->clientNum, CHAN_LOCAL, pVeh->m_pVehicleInfo->soundHyper );
330 #endif
331 }
332
333 parentPS->speed = HYPERSPACE_SPEED;
334 }
335 }
336 else
337 {//slow from top speed to 200...
338 parentPS->speed = 200.0f + ((1.0f-timeFrac)*(1.0f/HYPERSPACE_TELEPORT_FRAC)*(HYPERSPACE_SPEED-200.0f));
339 //don't mess with acceleration, just pop to the high velocity
340 if ( VectorLength( parentPS->velocity ) < parentPS->speed )
341 {
342 VectorScale( parentPS->moveDir, parentPS->speed, parentPS->velocity );
343 }
344 }
345 return;
346 }
347
348 if ( pVeh->m_iDropTime >= curTime )
349 {//no speed, just drop
350 parentPS->speed = 0.0f;
351 parentPS->gravity = 800;
352 return;
353 }
354
355 isLandingOrLaunching = (FighterIsLanding( pVeh, parentPS )||FighterIsLaunching( pVeh, parentPS ));
356
357 // If we are hitting the ground, just allow the fighter to go up and down.
358 if ( isLandingOrLaunching//going slow enough to start landing
359 && (pVeh->m_ucmd.forwardmove<=0||pVeh->m_LandTrace.fraction<=FIGHTER_MIN_TAKEOFF_FRACTION) )//not trying to accelerate away already (or: you are trying to, but not high enough off the ground yet)
360 {//FIXME: if start to move forward and fly over something low while still going relatively slow, you may try to land even though you don't mean to...
361 //float fInvFrac = 1.0f - pVeh->m_LandTrace.fraction;
362
363 if ( pVeh->m_ucmd.upmove > 0 )
364 {
365 if ( parentPS->velocity[2] <= 0
366 && pVeh->m_pVehicleInfo->soundTakeOff )
367 {//taking off for the first time
368 #ifdef _GAME//MP GAME-side
369 G_EntitySound( ((gentity_t *)(pVeh->m_pParentEntity)), CHAN_AUTO, pVeh->m_pVehicleInfo->soundTakeOff );
370 #endif
371 }
372 parentPS->velocity[2] += pVeh->m_pVehicleInfo->acceleration * pVeh->m_fTimeModifier;// * ( /*fInvFrac **/ 1.5f );
373 }
374 else if ( pVeh->m_ucmd.upmove < 0 )
375 {
376 parentPS->velocity[2] -= pVeh->m_pVehicleInfo->acceleration * pVeh->m_fTimeModifier;// * ( /*fInvFrac **/ 1.8f );
377 }
378 else if ( pVeh->m_ucmd.forwardmove < 0 )
379 {
380 if ( pVeh->m_LandTrace.fraction != 0.0f )
381 {
382 parentPS->velocity[2] -= pVeh->m_pVehicleInfo->acceleration * pVeh->m_fTimeModifier;
383 }
384
385 if ( pVeh->m_LandTrace.fraction <= FIGHTER_MIN_TAKEOFF_FRACTION )
386 {
387 //pVeh->m_pParentEntity->client->ps.velocity[0] *= pVeh->m_LandTrace.fraction;
388 //pVeh->m_pParentEntity->client->ps.velocity[1] *= pVeh->m_LandTrace.fraction;
389
390 //remember to always base this stuff on the time modifier! otherwise, you create
391 //framerate-dependancy issues and break prediction in MP -rww
392 //parentPS->velocity[2] *= pVeh->m_LandTrace.fraction;
393 //it's not an angle, but hey
394 parentPS->velocity[2] = PredictedAngularDecrement(pVeh->m_LandTrace.fraction, pVeh->m_fTimeModifier*5.0f, parentPS->velocity[2]);
395
396 parentPS->speed = 0;
397 }
398 }
399
400 // Make sure they don't pitch as they near the ground.
401 //pVeh->m_vOrientation[PITCH] *= 0.7f;
402 pVeh->m_vOrientation[PITCH] = PredictedAngularDecrement(0.7f, pVeh->m_fTimeModifier*10.0f, pVeh->m_vOrientation[PITCH]);
403
404 return;
405 }
406
407 if ( (pVeh->m_ucmd.upmove > 0) && pVeh->m_pVehicleInfo->turboSpeed )
408 {
409 if ((curTime - pVeh->m_iTurboTime)>pVeh->m_pVehicleInfo->turboRecharge)
410 {
411 pVeh->m_iTurboTime = (curTime + pVeh->m_pVehicleInfo->turboDuration);
412
413 #ifdef _GAME//MP GAME-side
414 //NOTE: turbo sound can't be part of effect if effect is played on every muzzle!
415 if ( pVeh->m_pVehicleInfo->soundTurbo )
416 {
417 G_EntitySound( ((gentity_t *)(pVeh->m_pParentEntity)), CHAN_AUTO, pVeh->m_pVehicleInfo->soundTurbo );
418 }
419 #endif
420 }
421 }
422 speedInc = pVeh->m_pVehicleInfo->acceleration * pVeh->m_fTimeModifier;
423 if ( curTime < pVeh->m_iTurboTime )
424 {//going turbo speed
425 speedMax = pVeh->m_pVehicleInfo->turboSpeed;
426 //double our acceleration
427 //speedInc *= 2.0f;
428 //no no no! this would el breako el predictiono! we want the following... -rww
429 speedInc = (pVeh->m_pVehicleInfo->acceleration*2.0f) * pVeh->m_fTimeModifier;
430
431 //force us to move forward
432 pVeh->m_ucmd.forwardmove = 127;
433 //add flag to let cgame know to draw the iTurboFX effect
434 parentPS->eFlags |= EF_JETPACK_ACTIVE;
435 }
436 /*
437 //FIXME: if turbotime is up and we're waiting for it to recharge, should our max speed drop while we recharge?
438 else if ( (curTime - pVeh->m_iTurboTime)<3000 )
439 {//still waiting for the recharge
440 speedMax = pVeh->m_pVehicleInfo->speedMax*0.75;
441 }
442 */
443 else
444 {//normal max speed
445 speedMax = pVeh->m_pVehicleInfo->speedMax;
446 if ( (parentPS->eFlags&EF_JETPACK_ACTIVE) )
447 {//stop cgame from playing the turbo exhaust effect
448 parentPS->eFlags &= ~EF_JETPACK_ACTIVE;
449 }
450 }
451 speedIdleDec = pVeh->m_pVehicleInfo->decelIdle * pVeh->m_fTimeModifier;
452 speedIdle = pVeh->m_pVehicleInfo->speedIdle;
453 speedIdleAccel = pVeh->m_pVehicleInfo->accelIdle * pVeh->m_fTimeModifier;
454 speedMin = pVeh->m_pVehicleInfo->speedMin;
455
456 if ( (parentPS->brokenLimbs&(1<<SHIPSURF_DAMAGE_BACK_HEAVY)) )
457 {//engine has taken heavy damage
458 speedMax *= 0.8f;//at 80% speed
459 }
460 else if ( (parentPS->brokenLimbs&(1<<SHIPSURF_DAMAGE_BACK_LIGHT)) )
461 {//engine has taken light damage
462 speedMax *= 0.6f;//at 60% speed
463 }
464
465 if (pVeh->m_iRemovedSurfaces
466 || parentPS->electrifyTime>=curTime)
467 { //go out of control
468 parentPS->speed += speedInc;
469 //Why set forwardmove? PMove code doesn't use it... does it?
470 pVeh->m_ucmd.forwardmove = 127;
471 }
472 #ifdef _GAME //well, the thing is always going to be inhabited if it's being predicted!
473 else if ( FighterSuspended( pVeh, parentPS ) )
474 {
475 parentPS->speed = 0;
476 pVeh->m_ucmd.forwardmove = 0;
477 }
478 else if ( !pVeh->m_pVehicleInfo->Inhabited( pVeh )
479 && parentPS->speed > 0 )
480 {//pilot jumped out while we were moving forward (not landing or landed) so just keep the throttle locked
481 //Why set forwardmove? PMove code doesn't use it... does it?
482 pVeh->m_ucmd.forwardmove = 127;
483 }
484 #endif
485 else if ( ( parentPS->speed || parentPS->groundEntityNum == ENTITYNUM_NONE ||
486 pVeh->m_ucmd.forwardmove || pVeh->m_ucmd.upmove > 0 ) && pVeh->m_LandTrace.fraction >= 0.05f )
487 {
488 if ( pVeh->m_ucmd.forwardmove > 0 && speedInc )
489 {
490 parentPS->speed += speedInc;
491 pVeh->m_ucmd.forwardmove = 127;
492 }
493 else if ( pVeh->m_ucmd.forwardmove < 0
494 || pVeh->m_ucmd.upmove < 0 )
495 {//decelerating or braking
496 if ( pVeh->m_ucmd.upmove < 0 )
497 {//braking (trying to land?), slow down faster
498 if ( pVeh->m_ucmd.forwardmove )
499 {//decelerator + brakes
500 speedInc += pVeh->m_pVehicleInfo->braking;
501 speedIdleDec += pVeh->m_pVehicleInfo->braking;
502 }
503 else
504 {//just brakes
505 speedInc = speedIdleDec = pVeh->m_pVehicleInfo->braking;
506 }
507 }
508 if ( parentPS->speed > speedIdle )
509 {
510 parentPS->speed -= speedInc;
511 }
512 else if ( parentPS->speed > speedMin )
513 {
514 if ( FighterOverValidLandingSurface( pVeh ) )
515 {//there's ground below us and we're trying to slow down, slow down faster
516 parentPS->speed -= speedInc;
517 }
518 else
519 {
520 parentPS->speed -= speedIdleDec;
521 if ( parentPS->speed < MIN_LANDING_SPEED )
522 {//unless you can land, don't drop below the landing speed!!! This way you can't come to a dead stop in mid-air
523 parentPS->speed = MIN_LANDING_SPEED;
524 }
525 }
526 }
527 if ( pVeh->m_pVehicleInfo->type == VH_FIGHTER )
528 {
529 pVeh->m_ucmd.forwardmove = 127;
530 }
531 else if ( speedMin >= 0 )
532 {
533 pVeh->m_ucmd.forwardmove = 0;
534 }
535 }
536 //else not accel, decel or braking
537 else if ( pVeh->m_pVehicleInfo->throttleSticks )
538 {//we're using a throttle that sticks at current speed
539 if ( parentPS->speed <= MIN_LANDING_SPEED )
540 {//going less than landing speed
541 if ( FighterOverValidLandingSurface( pVeh ) )
542 {//close to ground and not going very fast
543 //slow to a stop if within landing height and not accel/decel/braking
544 if ( parentPS->speed > 0 )
545 {//slow down
546 parentPS->speed -= speedIdleDec;
547 }
548 else if ( parentPS->speed < 0 )
549 {//going backwards, slow down
550 parentPS->speed += speedIdleDec;
551 }
552 }
553 else
554 {//not over a valid landing surf, but going too slow
555 //speed up to idle speed if not over a valid landing surf and not accel/decel/braking
556 if ( parentPS->speed < speedIdle )
557 {
558 parentPS->speed += speedIdleAccel;
559 if ( parentPS->speed > speedIdle )
560 {
561 parentPS->speed = speedIdle;
562 }
563 }
564 }
565 }
566 }
567 else
568 {//then speed up or slow down to idle speed
569 //accelerate to cruising speed only, otherwise, just coast
570 // If they've launched, apply some constant motion.
571 if ( (pVeh->m_LandTrace.fraction >= 1.0f //no ground
572 || pVeh->m_LandTrace.plane.normal[2] < MIN_LANDING_SLOPE )//or can't land on ground below us
573 && speedIdle > 0 )
574 {//not above ground and have an idle speed
575 //float fSpeed = pVeh->m_pParentEntity->client->ps.speed;
576 if ( parentPS->speed < speedIdle )
577 {
578 parentPS->speed += speedIdleAccel;
579 if ( parentPS->speed > speedIdle )
580 {
581 parentPS->speed = speedIdle;
582 }
583 }
584 else if ( parentPS->speed > 0 )
585 {//slow down
586 parentPS->speed -= speedIdleDec;
587
588 if ( parentPS->speed < speedIdle )
589 {
590 parentPS->speed = speedIdle;
591 }
592 }
593 }
594 else//either close to ground or no idle speed
595 {//slow to a stop if no idle speed or within landing height and not accel/decel/braking
596 if ( parentPS->speed > 0 )
597 {//slow down
598 parentPS->speed -= speedIdleDec;
599 }
600 else if ( parentPS->speed < 0 )
601 {//going backwards, slow down
602 parentPS->speed += speedIdleDec;
603 }
604 }
605 }
606 }
607 else
608 {
609 if ( pVeh->m_ucmd.forwardmove < 0 )
610 {
611 pVeh->m_ucmd.forwardmove = 0;
612 }
613 if ( pVeh->m_ucmd.upmove < 0 )
614 {
615 pVeh->m_ucmd.upmove = 0;
616 }
617 }
618
619 #if 1//This is working now, but there are some transitional jitters... Rich?
620 //STRAFING==============================================================================
621 if ( pVeh->m_pVehicleInfo->strafePerc
622 #ifdef _GAME//only do this check on game side, because if it's cgame, it's being predicted, and it's only predicted if the local client is the driver
623 && pVeh->m_pVehicleInfo->Inhabited( pVeh )//has to have a driver in order to be capable of landing
624 #endif
625 && !pVeh->m_iRemovedSurfaces
626 && parentPS->electrifyTime<curTime
627 && (pVeh->m_LandTrace.fraction >= 1.0f//no grounf
628 ||pVeh->m_LandTrace.plane.normal[2] < MIN_LANDING_SLOPE//can't land here
629 ||parentPS->speed>MIN_LANDING_SPEED)//going too fast to land
630 && pVeh->m_ucmd.rightmove )
631 {//strafe
632 vec3_t vAngles, vRight;
633 float strafeSpeed = (pVeh->m_pVehicleInfo->strafePerc*speedMax)*5.0f;
634 VectorCopy( pVeh->m_vOrientation, vAngles );
635 vAngles[PITCH] = vAngles[ROLL] = 0;
636 AngleVectors( vAngles, NULL, vRight, NULL );
637
638 if ( pVeh->m_ucmd.rightmove > 0 )
639 {//strafe right
640 //FIXME: this will probably make it possible to cheat and
641 // go faster than max speed if you keep turning and strafing...
642 if ( parentPS->hackingTime > -MAX_STRAFE_TIME )
643 {//can strafe right for 2 seconds
644 float curStrafeSpeed = DotProduct( parentPS->velocity, vRight );
645 if ( curStrafeSpeed > 0.0f )
646 {//if > 0, already strafing right
647 strafeSpeed -= curStrafeSpeed;//so it doesn't add up
648 }
649 if ( strafeSpeed > 0 )
650 {
651 VectorMA( parentPS->velocity, strafeSpeed*pVeh->m_fTimeModifier, vRight, parentPS->velocity );
652 }
653 parentPS->hackingTime -= 50*pVeh->m_fTimeModifier;
654 }
655 }
656 else
657 {//strafe left
658 if ( parentPS->hackingTime < MAX_STRAFE_TIME )
659 {//can strafe left for 2 seconds
660 float curStrafeSpeed = DotProduct( parentPS->velocity, vRight );
661 if ( curStrafeSpeed < 0.0f )
662 {//if < 0, already strafing left
663 strafeSpeed += curStrafeSpeed;//so it doesn't add up
664 }
665 if ( strafeSpeed > 0 )
666 {
667 VectorMA( parentPS->velocity, -strafeSpeed*pVeh->m_fTimeModifier, vRight, parentPS->velocity );
668 }
669 parentPS->hackingTime += 50*pVeh->m_fTimeModifier;
670 }
671 }
672 //strafing takes away from forward speed? If so, strafePerc above should use speedMax
673 //parentPS->speed *= (1.0f-pVeh->m_pVehicleInfo->strafePerc);
674 }
675 else//if ( parentPS->hackingTimef )
676 {
677 if ( parentPS->hackingTime > 0 )
678 {
679 parentPS->hackingTime -= 50*pVeh->m_fTimeModifier;
680 if ( parentPS->hackingTime < 0 )
681 {
682 parentPS->hackingTime = 0.0f;
683 }
684 }
685 else if ( parentPS->hackingTime < 0 )
686 {
687 parentPS->hackingTime += 50*pVeh->m_fTimeModifier;
688 if ( parentPS->hackingTime > 0 )
689 {
690 parentPS->hackingTime = 0.0f;
691 }
692 }
693 }
694 //STRAFING==============================================================================
695 #endif
696
697 if ( parentPS->speed > speedMax )
698 {
699 parentPS->speed = speedMax;
700 }
701 else if ( parentPS->speed < speedMin )
702 {
703 parentPS->speed = speedMin;
704 }
705
706 #ifdef _GAME//FIXME: get working in game and cgame
707 if ((pVeh->m_vOrientation[PITCH]*0.1f) > 10.0f)
708 { //pitched downward, increase speed more and more based on our tilt
709 if ( FighterIsInSpace( (gentity_t *)parent ) )
710 {//in space, do nothing with speed base on pitch...
711 }
712 else
713 {
714 //really should only do this when on a planet
715 float mult = pVeh->m_vOrientation[PITCH]*0.1f;
716 if (mult < 1.0f)
717 {
718 mult = 1.0f;
719 }
720 parentPS->speed = PredictedAngularDecrement(mult, pVeh->m_fTimeModifier*10.0f, parentPS->speed);
721 }
722 }
723
724 if (pVeh->m_iRemovedSurfaces
725 || parentPS->electrifyTime>=curTime)
726 { //going down
727 if ( FighterIsInSpace( (gentity_t *)parent ) )
728 {//we're in a valid trigger_space brush
729 //simulate randomness
730 if ( !(parent->s.number&3) )
731 {//even multiple of 3, don't do anything
732 parentPS->gravity = 0;
733 }
734 else if ( !(parent->s.number&2) )
735 {//even multiple of 2, go up
736 parentPS->gravity = -500.0f;
737 parentPS->velocity[2] = 80.0f;
738 }
739 else
740 {//odd number, go down
741 parentPS->gravity = 500.0f;
742 parentPS->velocity[2] = -80.0f;
743 }
744 }
745 else
746 {//over a planet
747 parentPS->gravity = 500.0f;
748 parentPS->velocity[2] = -80.0f;
749 }
750 }
751 else if ( FighterSuspended( pVeh, parentPS ) )
752 {
753 parentPS->gravity = 0;
754 }
755 else if ( (!parentPS->speed||parentPS->speed < speedIdle) && pVeh->m_ucmd.upmove <= 0 )
756 {//slowing down or stopped and not trying to take off
757 if ( FighterIsInSpace( (gentity_t *)parent ) )
758 {//we're in space, stopping doesn't make us drift downward
759 if ( FighterOverValidLandingSurface( pVeh ) )
760 {//well, there's something below us to land on, so go ahead and lower us down to it
761 parentPS->gravity = (speedIdle - parentPS->speed)/4;
762 }
763 }
764 else
765 {//over a planet
766 parentPS->gravity = (speedIdle - parentPS->speed)/4;
767 }
768 }
769 else
770 {
771 parentPS->gravity = 0;
772 }
773 #else//FIXME: get above checks working in game and cgame
774 parentPS->gravity = 0;
775 #endif
776
777 /********************************************************************************/
778 /* END Here is where we move the vehicle (forward or back or whatever). END */
779 /********************************************************************************/
780 }
781
782 extern void BG_VehicleTurnRateForSpeed( Vehicle_t *pVeh, float speed, float *mPitchOverride, float *mYawOverride );
FighterWingMalfunctionCheck(Vehicle_t * pVeh,playerState_t * parentPS)783 static void FighterWingMalfunctionCheck( Vehicle_t *pVeh, playerState_t *parentPS )
784 {
785 float mPitchOverride = 1.0f;
786 float mYawOverride = 1.0f;
787 BG_VehicleTurnRateForSpeed( pVeh, parentPS->speed, &mPitchOverride, &mYawOverride );
788 //check right wing damage
789 if ( (parentPS->brokenLimbs&(1<<SHIPSURF_DAMAGE_RIGHT_HEAVY)) )
790 {//right wing has taken heavy damage
791 pVeh->m_vOrientation[ROLL] += (sin( pVeh->m_ucmd.serverTime*0.001 )+1.0f)*pVeh->m_fTimeModifier*mYawOverride*50.0f;
792 }
793 else if ( (parentPS->brokenLimbs&(1<<SHIPSURF_DAMAGE_RIGHT_LIGHT)) )
794 {//right wing has taken light damage
795 pVeh->m_vOrientation[ROLL] += (sin( pVeh->m_ucmd.serverTime*0.001 )+1.0f)*pVeh->m_fTimeModifier*mYawOverride*12.5f;
796 }
797
798 //check left wing damage
799 if ( (parentPS->brokenLimbs&(1<<SHIPSURF_DAMAGE_LEFT_HEAVY)) )
800 {//left wing has taken heavy damage
801 pVeh->m_vOrientation[ROLL] -= (sin( pVeh->m_ucmd.serverTime*0.001 )+1.0f)*pVeh->m_fTimeModifier*mYawOverride*50.0f;
802 }
803 else if ( (parentPS->brokenLimbs&(1<<SHIPSURF_DAMAGE_LEFT_LIGHT)) )
804 {//left wing has taken light damage
805 pVeh->m_vOrientation[ROLL] -= (sin( pVeh->m_ucmd.serverTime*0.001 )+1.0f)*pVeh->m_fTimeModifier*mYawOverride*12.5f;
806 }
807
808 }
809
FighterNoseMalfunctionCheck(Vehicle_t * pVeh,playerState_t * parentPS)810 static void FighterNoseMalfunctionCheck( Vehicle_t *pVeh, playerState_t *parentPS )
811 {
812 float mPitchOverride = 1.0f;
813 float mYawOverride = 1.0f;
814 BG_VehicleTurnRateForSpeed( pVeh, parentPS->speed, &mPitchOverride, &mYawOverride );
815 //check nose damage
816 if ( (parentPS->brokenLimbs&(1<<SHIPSURF_DAMAGE_FRONT_HEAVY)) )
817 {//nose has taken heavy damage
818 //pitch up and down over time
819 pVeh->m_vOrientation[PITCH] += sin( pVeh->m_ucmd.serverTime*0.001 )*pVeh->m_fTimeModifier*mPitchOverride*50.0f;
820 }
821 else if ( (parentPS->brokenLimbs&(1<<SHIPSURF_DAMAGE_FRONT_LIGHT)) )
822 {//nose has taken heavy damage
823 //pitch up and down over time
824 pVeh->m_vOrientation[PITCH] += sin( pVeh->m_ucmd.serverTime*0.001 )*pVeh->m_fTimeModifier*mPitchOverride*20.0f;
825 }
826 }
827
FighterDamageRoutine(Vehicle_t * pVeh,bgEntity_t * parent,playerState_t * parentPS,playerState_t * riderPS,qboolean isDead)828 static void FighterDamageRoutine( Vehicle_t *pVeh, bgEntity_t *parent, playerState_t *parentPS, playerState_t *riderPS, qboolean isDead )
829 {
830 if ( !pVeh->m_iRemovedSurfaces )
831 {//still in one piece
832 if ( pVeh->m_pParentEntity && isDead )
833 {//death spiral
834 pVeh->m_ucmd.upmove = 0;
835 //FIXME: don't bias toward pitching down when not in space
836 /*
837 if ( FighterIsInSpace( pVeh->m_pParentEntity ) )
838 {
839 }
840 else
841 */
842 if ( !(pVeh->m_pParentEntity->s.number%3) )
843 {//NOT everyone should do this
844 pVeh->m_vOrientation[PITCH] += pVeh->m_fTimeModifier;
845 if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
846 {
847 if ( pVeh->m_vOrientation[PITCH] > 60.0f )
848 {
849 pVeh->m_vOrientation[PITCH] = 60.0f;
850 }
851 }
852 }
853 else if ( !(pVeh->m_pParentEntity->s.number%2) )
854 {
855 pVeh->m_vOrientation[PITCH] -= pVeh->m_fTimeModifier;
856 if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
857 {
858 if ( pVeh->m_vOrientation[PITCH] > -60.0f )
859 {
860 pVeh->m_vOrientation[PITCH] = -60.0f;
861 }
862 }
863 }
864 if ( (pVeh->m_pParentEntity->s.number%2) )
865 {
866 pVeh->m_vOrientation[YAW] += pVeh->m_fTimeModifier;
867 pVeh->m_vOrientation[ROLL] += pVeh->m_fTimeModifier*4.0f;
868 }
869 else
870 {
871 pVeh->m_vOrientation[YAW] -= pVeh->m_fTimeModifier;
872 pVeh->m_vOrientation[ROLL] -= pVeh->m_fTimeModifier*4.0f;
873 }
874 }
875 return;
876 }
877
878 //if we get into here we have at least one broken piece
879 pVeh->m_ucmd.upmove = 0;
880
881 //if you're off the ground and not suspended, pitch down
882 //FIXME: not in space!
883 if ( pVeh->m_LandTrace.fraction >= 0.1f )
884 {
885 if ( !FighterSuspended( pVeh, parentPS ) )
886 {
887 //pVeh->m_ucmd.forwardmove = 0;
888 //FIXME: don't bias towards pitching down when in space...
889 if ( !(pVeh->m_pParentEntity->s.number%2) )
890 {//NOT everyone should do this
891 pVeh->m_vOrientation[PITCH] += pVeh->m_fTimeModifier;
892 if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
893 {
894 if ( pVeh->m_vOrientation[PITCH] > 60.0f )
895 {
896 pVeh->m_vOrientation[PITCH] = 60.0f;
897 }
898 }
899 }
900 else if ( !(pVeh->m_pParentEntity->s.number%3) )
901 {
902 pVeh->m_vOrientation[PITCH] -= pVeh->m_fTimeModifier;
903 if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
904 {
905 if ( pVeh->m_vOrientation[PITCH] > -60.0f )
906 {
907 pVeh->m_vOrientation[PITCH] = -60.0f;
908 }
909 }
910 }
911 //else: just keep going forward
912 }
913 }
914 #ifdef _GAME
915 if ( pVeh->m_LandTrace.fraction < 1.0f )
916 { //if you land at all when pieces of your ship are missing, then die
917 gentity_t *vparent = (gentity_t *)pVeh->m_pParentEntity;
918 gentity_t *killer = vparent;
919 if (vparent->client->ps.otherKiller < ENTITYNUM_WORLD &&
920 vparent->client->ps.otherKillerTime > level.time)
921 {
922 gentity_t *potentialKiller = &g_entities[vparent->client->ps.otherKiller];
923
924 if (potentialKiller->inuse && potentialKiller->client)
925 { //he's valid I guess
926 killer = potentialKiller;
927 }
928 }
929 G_Damage(vparent, killer, killer, vec3_origin, vparent->client->ps.origin, 99999, DAMAGE_NO_ARMOR, MOD_SUICIDE);
930 }
931 #endif
932
933 if ( ((pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_C) ||
934 (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_D)) &&
935 ((pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_E) ||
936 (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_F)) )
937 { //wings on both side broken
938 float factor = 2.0f;
939 if ((pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_E) &&
940 (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_F) &&
941 (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_C) &&
942 (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_D))
943 { //all wings broken
944 factor *= 2.0f;
945 }
946
947 if ( !(pVeh->m_pParentEntity->s.number%4)||!(pVeh->m_pParentEntity->s.number%5) )
948 {//won't yaw, so increase roll factor
949 factor *= 4.0f;
950 }
951
952 pVeh->m_vOrientation[ROLL] += (pVeh->m_fTimeModifier*factor); //do some spiralling
953 }
954 else if ((pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_C) ||
955 (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_D))
956 { //left wing broken
957 float factor = 2.0f;
958 if ((pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_C) &&
959 (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_D))
960 { //if both are broken..
961 factor *= 2.0f;
962 }
963
964 if ( !(pVeh->m_pParentEntity->s.number%4)||!(pVeh->m_pParentEntity->s.number%5) )
965 {//won't yaw, so increase roll factor
966 factor *= 4.0f;
967 }
968
969 pVeh->m_vOrientation[ROLL] += factor*pVeh->m_fTimeModifier;
970 }
971 else if ((pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_E) ||
972 (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_F))
973 { //right wing broken
974 float factor = 2.0f;
975 if ((pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_E) &&
976 (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_F))
977 { //if both are broken..
978 factor *= 2.0f;
979 }
980
981 if ( !(pVeh->m_pParentEntity->s.number%4)||!(pVeh->m_pParentEntity->s.number%5) )
982 {//won't yaw, so increase roll factor
983 factor *= 4.0f;
984 }
985
986 pVeh->m_vOrientation[ROLL] -= factor*pVeh->m_fTimeModifier;
987 }
988 }
989
990 #ifdef VEH_CONTROL_SCHEME_4
991
992 #define FIGHTER_TURNING_MULTIPLIER 0.8f//was 1.6f //magic number hackery
993 #define FIGHTER_TURNING_DEADZONE 0.25f//no turning if offset is this much
FighterRollAdjust(Vehicle_t * pVeh,playerState_t * riderPS,playerState_t * parentPS)994 void FighterRollAdjust(Vehicle_t *pVeh, playerState_t *riderPS, playerState_t *parentPS)
995 {
996 /*
997 float angDif = AngleSubtract(pVeh->m_vOrientation[YAW], riderPS->viewangles[YAW]);
998 */
999 float angDif = AngleSubtract(pVeh->m_vPrevRiderViewAngles[YAW],riderPS->viewangles[YAW]);///2.0f;//AngleSubtract(pVeh->m_vPrevRiderViewAngles[YAW], riderPS->viewangles[YAW]);
1000 /*
1001 if ( fabs( angDif ) < FIGHTER_TURNING_DEADZONE )
1002 {
1003 angDif = 0.0f;
1004 }
1005 else if ( angDif >= FIGHTER_TURNING_DEADZONE )
1006 {
1007 angDif -= FIGHTER_TURNING_DEADZONE;
1008 }
1009 else if ( angDif <= -FIGHTER_TURNING_DEADZONE )
1010 {
1011 angDif += FIGHTER_TURNING_DEADZONE;
1012 }
1013 */
1014
1015 angDif *= 0.5f;
1016 if ( angDif > 0.0f )
1017 {
1018 angDif *= angDif;
1019 }
1020 else if ( angDif < 0.0f )
1021 {
1022 angDif *= -angDif;
1023 }
1024
1025 if (parentPS && parentPS->speed)
1026 {
1027 float maxDif = pVeh->m_pVehicleInfo->turningSpeed*FIGHTER_TURNING_MULTIPLIER;
1028
1029 if ( pVeh->m_pVehicleInfo->speedDependantTurning )
1030 {
1031 float speedFrac = 1.0f;
1032 if ( pVeh->m_LandTrace.fraction >= 1.0f
1033 || pVeh->m_LandTrace.plane.normal[2] < MIN_LANDING_SLOPE )
1034 {
1035 float s = parentPS->speed;
1036 if (s < 0.0f)
1037 {
1038 s = -s;
1039 }
1040 speedFrac = (s/(pVeh->m_pVehicleInfo->speedMax*0.75f));
1041 if ( speedFrac < 0.25f )
1042 {
1043 speedFrac = 0.25f;
1044 }
1045 else if ( speedFrac > 1.0f )
1046 {
1047 speedFrac = 1.0f;
1048 }
1049 }
1050 angDif *= speedFrac;
1051 }
1052 if (angDif > maxDif)
1053 {
1054 angDif = maxDif;
1055 }
1056 else if (angDif < -maxDif)
1057 {
1058 angDif = -maxDif;
1059 }
1060 pVeh->m_vOrientation[ROLL] = AngleNormalize180(pVeh->m_vOrientation[ROLL] + angDif*(pVeh->m_fTimeModifier*0.2f));
1061 }
1062 }
1063
FighterYawAdjust(Vehicle_t * pVeh,playerState_t * riderPS,playerState_t * parentPS)1064 void FighterYawAdjust(Vehicle_t *pVeh, playerState_t *riderPS, playerState_t *parentPS)
1065 {
1066 float angDif = AngleSubtract(pVeh->m_vPrevRiderViewAngles[YAW],riderPS->viewangles[YAW]);///2.0f;//AngleSubtract(pVeh->m_vPrevRiderViewAngles[YAW], riderPS->viewangles[YAW]);
1067 if ( fabs( angDif ) < FIGHTER_TURNING_DEADZONE )
1068 {
1069 angDif = 0.0f;
1070 }
1071 else if ( angDif >= FIGHTER_TURNING_DEADZONE )
1072 {
1073 angDif -= FIGHTER_TURNING_DEADZONE;
1074 }
1075 else if ( angDif <= -FIGHTER_TURNING_DEADZONE )
1076 {
1077 angDif += FIGHTER_TURNING_DEADZONE;
1078 }
1079
1080 angDif *= 0.5f;
1081 if ( angDif > 0.0f )
1082 {
1083 angDif *= angDif;
1084 }
1085 else if ( angDif < 0.0f )
1086 {
1087 angDif *= -angDif;
1088 }
1089
1090 if (parentPS && parentPS->speed)
1091 {
1092 float maxDif = pVeh->m_pVehicleInfo->turningSpeed*FIGHTER_TURNING_MULTIPLIER;
1093
1094 if ( pVeh->m_pVehicleInfo->speedDependantTurning )
1095 {
1096 float speedFrac = 1.0f;
1097 if ( pVeh->m_LandTrace.fraction >= 1.0f
1098 || pVeh->m_LandTrace.plane.normal[2] < MIN_LANDING_SLOPE )
1099 {
1100 float s = parentPS->speed;
1101 if (s < 0.0f)
1102 {
1103 s = -s;
1104 }
1105 speedFrac = (s/(pVeh->m_pVehicleInfo->speedMax*0.75f));
1106 if ( speedFrac < 0.25f )
1107 {
1108 speedFrac = 0.25f;
1109 }
1110 else if ( speedFrac > 1.0f )
1111 {
1112 speedFrac = 1.0f;
1113 }
1114 }
1115 angDif *= speedFrac;
1116 }
1117 if (angDif > maxDif)
1118 {
1119 angDif = maxDif;
1120 }
1121 else if (angDif < -maxDif)
1122 {
1123 angDif = -maxDif;
1124 }
1125 pVeh->m_vOrientation[YAW] = AngleNormalize180(pVeh->m_vOrientation[YAW] - (angDif*(pVeh->m_fTimeModifier*0.2f)) );
1126 }
1127 }
1128
FighterPitchAdjust(Vehicle_t * pVeh,playerState_t * riderPS,playerState_t * parentPS)1129 void FighterPitchAdjust(Vehicle_t *pVeh, playerState_t *riderPS, playerState_t *parentPS)
1130 {
1131 float angDif = AngleSubtract(0,riderPS->viewangles[PITCH]);//AngleSubtract(pVeh->m_vPrevRiderViewAngles[PITCH], riderPS->viewangles[PITCH]);
1132 if ( fabs( angDif ) < FIGHTER_TURNING_DEADZONE )
1133 {
1134 angDif = 0.0f;
1135 }
1136 else if ( angDif >= FIGHTER_TURNING_DEADZONE )
1137 {
1138 angDif -= FIGHTER_TURNING_DEADZONE;
1139 }
1140 else if ( angDif <= -FIGHTER_TURNING_DEADZONE )
1141 {
1142 angDif += FIGHTER_TURNING_DEADZONE;
1143 }
1144
1145 angDif *= 0.5f;
1146 if ( angDif > 0.0f )
1147 {
1148 angDif *= angDif;
1149 }
1150 else if ( angDif < 0.0f )
1151 {
1152 angDif *= -angDif;
1153 }
1154
1155 if (parentPS && parentPS->speed)
1156 {
1157 float maxDif = pVeh->m_pVehicleInfo->turningSpeed*FIGHTER_TURNING_MULTIPLIER;
1158
1159 if ( pVeh->m_pVehicleInfo->speedDependantTurning )
1160 {
1161 float speedFrac = 1.0f;
1162 if ( pVeh->m_LandTrace.fraction >= 1.0f
1163 || pVeh->m_LandTrace.plane.normal[2] < MIN_LANDING_SLOPE )
1164 {
1165 float s = parentPS->speed;
1166 if (s < 0.0f)
1167 {
1168 s = -s;
1169 }
1170 speedFrac = (s/(pVeh->m_pVehicleInfo->speedMax*0.75f));
1171 if ( speedFrac < 0.25f )
1172 {
1173 speedFrac = 0.25f;
1174 }
1175 else if ( speedFrac > 1.0f )
1176 {
1177 speedFrac = 1.0f;
1178 }
1179 }
1180 angDif *= speedFrac;
1181 }
1182 if (angDif > maxDif)
1183 {
1184 angDif = maxDif;
1185 }
1186 else if (angDif < -maxDif)
1187 {
1188 angDif = -maxDif;
1189 }
1190 pVeh->m_vOrientation[PITCH] = AngleNormalize180(pVeh->m_vOrientation[PITCH] - (angDif*(pVeh->m_fTimeModifier*0.2f)) );
1191 }
1192 }
1193
1194 #else// VEH_CONTROL_SCHEME_4
1195
FighterYawAdjust(Vehicle_t * pVeh,playerState_t * riderPS,playerState_t * parentPS)1196 void FighterYawAdjust(Vehicle_t *pVeh, playerState_t *riderPS, playerState_t *parentPS)
1197 {
1198 float angDif = AngleSubtract(pVeh->m_vOrientation[YAW], riderPS->viewangles[YAW]);
1199
1200 if (parentPS && parentPS->speed)
1201 {
1202 float s = parentPS->speed;
1203 float maxDif = pVeh->m_pVehicleInfo->turningSpeed*0.8f; //magic number hackery
1204
1205 if (s < 0.0f)
1206 {
1207 s = -s;
1208 }
1209 angDif *= s/pVeh->m_pVehicleInfo->speedMax;
1210 if (angDif > maxDif)
1211 {
1212 angDif = maxDif;
1213 }
1214 else if (angDif < -maxDif)
1215 {
1216 angDif = -maxDif;
1217 }
1218 pVeh->m_vOrientation[YAW] = AngleNormalize180(pVeh->m_vOrientation[YAW] - angDif*(pVeh->m_fTimeModifier*0.2f));
1219 }
1220 }
1221
FighterPitchAdjust(Vehicle_t * pVeh,playerState_t * riderPS,playerState_t * parentPS)1222 void FighterPitchAdjust(Vehicle_t *pVeh, playerState_t *riderPS, playerState_t *parentPS)
1223 {
1224 float angDif = AngleSubtract(pVeh->m_vOrientation[PITCH], riderPS->viewangles[PITCH]);
1225
1226 if (parentPS && parentPS->speed)
1227 {
1228 float s = parentPS->speed;
1229 float maxDif = pVeh->m_pVehicleInfo->turningSpeed*0.8f; //magic number hackery
1230
1231 if (s < 0.0f)
1232 {
1233 s = -s;
1234 }
1235 angDif *= s/pVeh->m_pVehicleInfo->speedMax;
1236 if (angDif > maxDif)
1237 {
1238 angDif = maxDif;
1239 }
1240 else if (angDif < -maxDif)
1241 {
1242 angDif = -maxDif;
1243 }
1244 pVeh->m_vOrientation[PITCH] = AngleNormalize360(pVeh->m_vOrientation[PITCH] - angDif*(pVeh->m_fTimeModifier*0.2f));
1245 }
1246 }
1247 #endif// VEH_CONTROL_SCHEME_4
1248
FighterPitchClamp(Vehicle_t * pVeh,playerState_t * riderPS,playerState_t * parentPS,int curTime)1249 void FighterPitchClamp(Vehicle_t *pVeh, playerState_t *riderPS, playerState_t *parentPS, int curTime )
1250 {
1251 if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
1252 {//cap pitch reasonably
1253 if ( pVeh->m_pVehicleInfo->pitchLimit != -1
1254 && !pVeh->m_iRemovedSurfaces
1255 && parentPS->electrifyTime < curTime )
1256 {
1257 if (pVeh->m_vOrientation[PITCH] > pVeh->m_pVehicleInfo->pitchLimit )
1258 {
1259 pVeh->m_vOrientation[PITCH] = pVeh->m_pVehicleInfo->pitchLimit;
1260 }
1261 else if (pVeh->m_vOrientation[PITCH] < -pVeh->m_pVehicleInfo->pitchLimit)
1262 {
1263 pVeh->m_vOrientation[PITCH] = -pVeh->m_pVehicleInfo->pitchLimit;
1264 }
1265 }
1266 }
1267 }
1268
1269 //MP RULE - ALL PROCESSORIENTCOMMANDS FUNCTIONS MUST BE BG-COMPATIBLE!!!
1270 //If you really need to violate this rule for SP, then use ifdefs.
1271 //By BG-compatible, I mean no use of game-specific data - ONLY use
1272 //stuff available in the MP bgEntity (in SP, the bgEntity is #defined
1273 //as a gentity, but the MP-compatible access restrictions are based
1274 //on the bgEntity structure in the MP codebase) -rww
1275 // ProcessOrientCommands the Vehicle.
ProcessOrientCommands(Vehicle_t * pVeh)1276 static void ProcessOrientCommands( Vehicle_t *pVeh )
1277 {
1278 /********************************************************************************/
1279 /* BEGIN Here is where make sure the vehicle is properly oriented. BEGIN */
1280 /********************************************************************************/
1281
1282 bgEntity_t *parent = pVeh->m_pParentEntity;
1283 playerState_t *parentPS, *riderPS;
1284 float angleTimeMod;
1285 #ifdef _GAME
1286 const float groundFraction = 0.1f;
1287 #endif
1288 float curRoll = 0.0f;
1289 qboolean isDead = qfalse;
1290 qboolean isLandingOrLanded = qfalse;
1291 #ifdef _GAME
1292 int curTime = level.time;
1293 #elif _CGAME
1294 //FIXME: pass in ucmd? Not sure if this is reliable...
1295 int curTime = pm->cmd.serverTime;
1296 #endif
1297
1298 bgEntity_t *rider = NULL;
1299 if (parent->s.owner != ENTITYNUM_NONE)
1300 {
1301 rider = PM_BGEntForNum(parent->s.owner); //&g_entities[parent->r.ownerNum];
1302 }
1303
1304 if ( !rider )
1305 {
1306 rider = parent;
1307 }
1308
1309 parentPS = parent->playerState;
1310 riderPS = rider->playerState;
1311 isDead = (qboolean)((parentPS->eFlags&EF_DEAD)!=0);
1312
1313 #ifdef VEH_CONTROL_SCHEME_4
1314 if ( parentPS->hyperSpaceTime
1315 && (curTime - parentPS->hyperSpaceTime) < HYPERSPACE_TIME )
1316 {//Going to Hyperspace
1317 //VectorCopy( riderPS->viewangles, pVeh->m_vOrientation );
1318 //VectorCopy( riderPS->viewangles, parentPS->viewangles );
1319 VectorCopy( parentPS->viewangles, pVeh->m_vOrientation );
1320 VectorClear( pVeh->m_vPrevRiderViewAngles );
1321 pVeh->m_vPrevRiderViewAngles[YAW] = AngleNormalize180(riderPS->viewangles[YAW]);
1322 FighterPitchClamp( pVeh, riderPS, parentPS, curTime );
1323 return;
1324 }
1325 else if ( parentPS->vehTurnaroundIndex
1326 && parentPS->vehTurnaroundTime > curTime )
1327 {//in turn-around brush
1328 //VectorCopy( riderPS->viewangles, pVeh->m_vOrientation );
1329 //VectorCopy( riderPS->viewangles, parentPS->viewangles );
1330 VectorCopy( parentPS->viewangles, pVeh->m_vOrientation );
1331 VectorClear( pVeh->m_vPrevRiderViewAngles );
1332 pVeh->m_vPrevRiderViewAngles[YAW] = AngleNormalize180(riderPS->viewangles[YAW]);
1333 FighterPitchClamp( pVeh, riderPS, parentPS, curTime );
1334 return;
1335 }
1336
1337 #else// VEH_CONTROL_SCHEME_4
1338
1339 if ( parentPS->hyperSpaceTime
1340 && (curTime - parentPS->hyperSpaceTime) < HYPERSPACE_TIME )
1341 {//Going to Hyperspace
1342 VectorCopy( riderPS->viewangles, pVeh->m_vOrientation );
1343 VectorCopy( riderPS->viewangles, parentPS->viewangles );
1344 return;
1345 }
1346 #endif// VEH_CONTROL_SCHEME_4
1347
1348 if ( pVeh->m_iDropTime >= curTime )
1349 {//you can only YAW during this
1350 parentPS->viewangles[YAW] = pVeh->m_vOrientation[YAW] = riderPS->viewangles[YAW];
1351 #ifdef VEH_CONTROL_SCHEME_4
1352 VectorClear( pVeh->m_vPrevRiderViewAngles );
1353 pVeh->m_vPrevRiderViewAngles[YAW] = AngleNormalize180(riderPS->viewangles[YAW]);
1354 #endif// VEH_CONTROL_SCHEME_4
1355 return;
1356 }
1357
1358 angleTimeMod = pVeh->m_fTimeModifier;
1359
1360 if ( isDead || parentPS->electrifyTime>=curTime ||
1361 (pVeh->m_pVehicleInfo->surfDestruction &&
1362 pVeh->m_iRemovedSurfaces &&
1363 (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_C) &&
1364 (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_D) &&
1365 (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_E) &&
1366 (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_F)) )
1367 { //do some special stuff for when all the wings are torn off
1368 FighterDamageRoutine(pVeh, parent, parentPS, riderPS, isDead);
1369 pVeh->m_vOrientation[ROLL] = AngleNormalize180( pVeh->m_vOrientation[ROLL] );
1370 return;
1371 }
1372
1373 if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
1374 {
1375 pVeh->m_vOrientation[ROLL] = PredictedAngularDecrement(0.95f, angleTimeMod*2.0f, pVeh->m_vOrientation[ROLL]);
1376 }
1377
1378 isLandingOrLanded = (FighterIsLanding( pVeh, parentPS )||FighterIsLanded( pVeh, parentPS ));
1379
1380 if (!isLandingOrLanded)
1381 { //don't do this stuff while landed.. I guess. I don't want ships spinning in place, looks silly.
1382 int m = 0;
1383 float aVelDif;
1384 float dForVel;
1385
1386 FighterWingMalfunctionCheck( pVeh, parentPS );
1387
1388 while (m < 3)
1389 {
1390 aVelDif = pVeh->m_vFullAngleVelocity[m];
1391
1392 if (aVelDif != 0.0f)
1393 {
1394 dForVel = (aVelDif*0.1f)*pVeh->m_fTimeModifier;
1395 if (dForVel > 1.0f || dForVel < -1.0f)
1396 {
1397 pVeh->m_vOrientation[m] += dForVel;
1398 pVeh->m_vOrientation[m] = AngleNormalize180(pVeh->m_vOrientation[m]);
1399 if (m == PITCH)
1400 { //don't pitch downward into ground even more.
1401 if (pVeh->m_vOrientation[m] > 90.0f && (pVeh->m_vOrientation[m]-dForVel) < 90.0f)
1402 {
1403 pVeh->m_vOrientation[m] = 90.0f;
1404 pVeh->m_vFullAngleVelocity[m] = -pVeh->m_vFullAngleVelocity[m];
1405 }
1406 }
1407 pVeh->m_vFullAngleVelocity[m] -= dForVel;
1408 }
1409 else
1410 {
1411 pVeh->m_vFullAngleVelocity[m] = 0.0f;
1412 }
1413 }
1414
1415 m++;
1416 }
1417 }
1418 else
1419 { //clear decr/incr angles once landed.
1420 VectorClear(pVeh->m_vFullAngleVelocity);
1421 }
1422
1423 curRoll = pVeh->m_vOrientation[ROLL];
1424
1425 // If we're landed, we shouldn't be able to do anything but take off.
1426 if ( isLandingOrLanded //going slow enough to start landing
1427 && !pVeh->m_iRemovedSurfaces
1428 && parentPS->electrifyTime<curTime)//not spiraling out of control
1429 {
1430 if ( parentPS->speed > 0.0f )
1431 {//Uh... what? Why?
1432 if ( pVeh->m_LandTrace.fraction < 0.3f )
1433 {
1434 pVeh->m_vOrientation[PITCH] = 0.0f;
1435 }
1436 else
1437 {
1438 pVeh->m_vOrientation[PITCH] = PredictedAngularDecrement(0.83f, angleTimeMod*10.0f, pVeh->m_vOrientation[PITCH]);
1439 }
1440 }
1441 if ( pVeh->m_LandTrace.fraction > 0.1f
1442 || pVeh->m_LandTrace.plane.normal[2] < MIN_LANDING_SLOPE )
1443 {//off the ground, at least (or not on a valid landing surf)
1444 // Dampen the turn rate based on the current height.
1445 FighterYawAdjust(pVeh, riderPS, parentPS);
1446 }
1447 #ifdef VEH_CONTROL_SCHEME_4
1448 else
1449 {
1450 VectorClear( pVeh->m_vPrevRiderViewAngles );
1451 pVeh->m_vPrevRiderViewAngles[YAW] = AngleNormalize180(riderPS->viewangles[YAW]);
1452 }
1453 #endif// VEH_CONTROL_SCHEME_4
1454 }
1455 else if ( (pVeh->m_iRemovedSurfaces||parentPS->electrifyTime>=curTime)//spiralling out of control
1456 && (!(pVeh->m_pParentEntity->s.number%4)||!(pVeh->m_pParentEntity->s.number%5)) )
1457 {//no yaw control
1458 }
1459 else if ( pVeh->m_pPilot && pVeh->m_pPilot->s.number < MAX_CLIENTS && parentPS->speed > 0.0f )//&& !( pVeh->m_ucmd.forwardmove > 0 && pVeh->m_LandTrace.fraction != 1.0f ) )
1460 {
1461 #ifdef VEH_CONTROL_SCHEME_4
1462 if ( 0 )
1463 #else// VEH_CONTROL_SCHEME_4
1464 if ( BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
1465 #endif// VEH_CONTROL_SCHEME_4
1466 {
1467 VectorCopy( riderPS->viewangles, pVeh->m_vOrientation );
1468 VectorCopy( riderPS->viewangles, parentPS->viewangles );
1469
1470 curRoll = pVeh->m_vOrientation[ROLL];
1471
1472 FighterNoseMalfunctionCheck( pVeh, parentPS );
1473
1474 //VectorCopy( pVeh->m_vOrientation, parentPS->viewangles );
1475 }
1476 else
1477 {
1478 /*
1479 float fTurnAmt[3];
1480 //PITCH
1481 fTurnAmt[PITCH] = riderPS->viewangles[PITCH] * 0.08f;
1482 //YAW
1483 fTurnAmt[YAW] = riderPS->viewangles[YAW] * 0.065f;
1484 fTurnAmt[YAW] *= fTurnAmt[YAW];
1485 // Dampen the turn rate based on the current height.
1486 if ( riderPS->viewangles[YAW] < 0 )
1487 {//must keep it negative because squaring a negative makes it positive
1488 fTurnAmt[YAW] = -fTurnAmt[YAW];
1489 }
1490 fTurnAmt[YAW] *= pVeh->m_LandTrace.fraction;
1491 //ROLL
1492 fTurnAmt[2] = 0.0f;
1493 */
1494
1495 //Actal YAW
1496 /*
1497 pVeh->m_vOrientation[ROLL] = curRoll;
1498 FighterRollAdjust(pVeh, riderPS, parentPS);
1499 curRoll = pVeh->m_vOrientation[ROLL];
1500 */
1501 FighterYawAdjust(pVeh, riderPS, parentPS);
1502
1503 // If we are not hitting the ground, allow the fighter to pitch up and down.
1504 if ( !FighterOverValidLandingSurface( pVeh )
1505 || parentPS->speed > MIN_LANDING_SPEED )
1506 //if ( ( pVeh->m_LandTrace.fraction >= 1.0f || pVeh->m_ucmd.forwardmove != 0 ) && pVeh->m_LandTrace.fraction >= 0.0f )
1507 {
1508 float fYawDelta;
1509
1510 FighterPitchAdjust(pVeh, riderPS, parentPS);
1511 #ifdef VEH_CONTROL_SCHEME_4
1512 FighterPitchClamp( pVeh, riderPS, parentPS, curTime );
1513 #endif// VEH_CONTROL_SCHEME_4
1514
1515 FighterNoseMalfunctionCheck( pVeh, parentPS );
1516
1517 // Adjust the roll based on the turn amount and dampen it a little.
1518 fYawDelta = AngleSubtract(pVeh->m_vOrientation[YAW], pVeh->m_vPrevOrientation[YAW]); //pVeh->m_vOrientation[YAW] - pVeh->m_vPrevOrientation[YAW];
1519 if ( fYawDelta > 8.0f )
1520 {
1521 fYawDelta = 8.0f;
1522 }
1523 else if ( fYawDelta < -8.0f )
1524 {
1525 fYawDelta = -8.0f;
1526 }
1527 curRoll -= fYawDelta;
1528 curRoll = PredictedAngularDecrement(0.93f, angleTimeMod*2.0f, curRoll);
1529
1530 //cap it reasonably
1531 //NOTE: was hardcoded to 40.0f, now using extern data
1532 #ifdef VEH_CONTROL_SCHEME_4
1533 if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
1534 {
1535 if ( pVeh->m_pVehicleInfo->rollLimit != -1 )
1536 {
1537 if (curRoll > pVeh->m_pVehicleInfo->rollLimit )
1538 {
1539 curRoll = pVeh->m_pVehicleInfo->rollLimit;
1540 }
1541 else if (curRoll < -pVeh->m_pVehicleInfo->rollLimit)
1542 {
1543 curRoll = -pVeh->m_pVehicleInfo->rollLimit;
1544 }
1545 }
1546 }
1547 #else// VEH_CONTROL_SCHEME_4
1548 if ( pVeh->m_pVehicleInfo->rollLimit != -1 )
1549 {
1550 if (curRoll > pVeh->m_pVehicleInfo->rollLimit )
1551 {
1552 curRoll = pVeh->m_pVehicleInfo->rollLimit;
1553 }
1554 else if (curRoll < -pVeh->m_pVehicleInfo->rollLimit)
1555 {
1556 curRoll = -pVeh->m_pVehicleInfo->rollLimit;
1557 }
1558 }
1559 #endif// VEH_CONTROL_SCHEME_4
1560 }
1561 }
1562 }
1563
1564 // If you are directly impacting the ground, even out your pitch.
1565 if ( isLandingOrLanded )
1566 {//only if capable of landing
1567 if ( !isDead
1568 && parentPS->electrifyTime<curTime
1569 && (!pVeh->m_pVehicleInfo->surfDestruction || !pVeh->m_iRemovedSurfaces ) )
1570 {//not crashing or spiralling out of control...
1571 if ( pVeh->m_vOrientation[PITCH] > 0 )
1572 {
1573 pVeh->m_vOrientation[PITCH] = PredictedAngularDecrement(0.2f, angleTimeMod*10.0f, pVeh->m_vOrientation[PITCH]);
1574 }
1575 else
1576 {
1577 pVeh->m_vOrientation[PITCH] = PredictedAngularDecrement(0.75f, angleTimeMod*10.0f, pVeh->m_vOrientation[PITCH]);
1578 }
1579 }
1580 }
1581
1582
1583 /*
1584 //NOTE: all this is redundant now since we have the FighterDamageRoutine func...
1585 if ( isDead )
1586 {//going to explode
1587 //FIXME: maybe make it erratically jerk or spin or start and stop?
1588 if (1)
1589 {
1590 pVeh->m_ucmd.rightmove = Q_irand( -64, 64 );
1591 }
1592 else
1593 {
1594 pVeh->m_ucmd.rightmove = 0;
1595 }
1596 pVeh->m_ucmd.forwardmove = Q_irand( -32, 127 );
1597 pVeh->m_ucmd.upmove = Q_irand( -127, 127 );
1598 pVeh->m_vOrientation[YAW] += Q_flrand( -10, 10 );
1599 pVeh->m_vOrientation[PITCH] += pVeh->m_fTimeModifier;
1600 if ( pVeh->m_vOrientation[PITCH] > 60.0f )
1601 {
1602 pVeh->m_vOrientation[PITCH] = 60.0f;
1603 }
1604 if ( pVeh->m_LandTrace.fraction != 0.0f )
1605 {
1606 parentPS->velocity[2] -= pVeh->m_pVehicleInfo->acceleration * pVeh->m_fTimeModifier;
1607 }
1608 }
1609 */
1610 // If no one is in this vehicle and it's up in the sky, pitch it forward as it comes tumbling down.
1611 #ifdef _GAME //never gonna happen on client anyway, we can't be getting predicted unless the predicting client is boarded
1612 if ( !pVeh->m_pVehicleInfo->Inhabited( pVeh )
1613 && pVeh->m_LandTrace.fraction >= groundFraction
1614 && !FighterIsInSpace( (gentity_t *)parent )
1615 && !FighterSuspended( pVeh, parentPS ) )
1616 {
1617 pVeh->m_ucmd.upmove = 0;
1618 //pVeh->m_ucmd.forwardmove = 0;
1619 pVeh->m_vOrientation[PITCH] += pVeh->m_fTimeModifier;
1620 if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
1621 {
1622 if ( pVeh->m_vOrientation[PITCH] > 60.0f )
1623 {
1624 pVeh->m_vOrientation[PITCH] = 60.0f;
1625 }
1626 }
1627 }
1628 #endif
1629
1630 if ( !parentPS->hackingTime )
1631 {//use that roll
1632 pVeh->m_vOrientation[ROLL] = curRoll;
1633 //NOTE: this seems really backwards...
1634 if ( pVeh->m_vOrientation[ROLL] )
1635 { //continually adjust the yaw based on the roll..
1636 if ( (pVeh->m_iRemovedSurfaces||parentPS->electrifyTime>=curTime)//spiralling out of control
1637 && (!(pVeh->m_pParentEntity->s.number%4)||!(pVeh->m_pParentEntity->s.number%5)) )
1638 {//leave YAW alone
1639 }
1640 else
1641 {
1642 if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
1643 {
1644 pVeh->m_vOrientation[YAW] -= ((pVeh->m_vOrientation[ROLL])*0.05f)*pVeh->m_fTimeModifier;
1645 }
1646 }
1647 }
1648 }
1649 else
1650 {//add in strafing roll
1651 float strafeRoll = (parentPS->hackingTime/MAX_STRAFE_TIME)*pVeh->m_pVehicleInfo->rollLimit;//pVeh->m_pVehicleInfo->bankingSpeed*
1652 float strafeDif = AngleSubtract(strafeRoll, pVeh->m_vOrientation[ROLL]);
1653 pVeh->m_vOrientation[ROLL] += (strafeDif*0.1f)*pVeh->m_fTimeModifier;
1654 if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
1655 {//cap it reasonably
1656 if ( pVeh->m_pVehicleInfo->rollLimit != -1
1657 && !pVeh->m_iRemovedSurfaces
1658 && parentPS->electrifyTime<curTime)
1659 {
1660 if (pVeh->m_vOrientation[ROLL] > pVeh->m_pVehicleInfo->rollLimit )
1661 {
1662 pVeh->m_vOrientation[ROLL] = pVeh->m_pVehicleInfo->rollLimit;
1663 }
1664 else if (pVeh->m_vOrientation[ROLL] < -pVeh->m_pVehicleInfo->rollLimit)
1665 {
1666 pVeh->m_vOrientation[ROLL] = -pVeh->m_pVehicleInfo->rollLimit;
1667 }
1668 }
1669 }
1670 }
1671
1672 if (pVeh->m_pVehicleInfo->surfDestruction)
1673 {
1674 FighterDamageRoutine(pVeh, parent, parentPS, riderPS, isDead);
1675 }
1676 pVeh->m_vOrientation[ROLL] = AngleNormalize180( pVeh->m_vOrientation[ROLL] );
1677
1678 /********************************************************************************/
1679 /* END Here is where make sure the vehicle is properly oriented. END */
1680 /********************************************************************************/
1681 }
1682
1683 #ifdef _GAME //ONLY on server, not cgame
1684
1685 // This function makes sure that the vehicle is properly animated.
AnimateVehicle(Vehicle_t * pVeh)1686 static void AnimateVehicle( Vehicle_t *pVeh )
1687 {
1688 int Anim = -1;
1689 int iFlags = SETANIM_FLAG_NORMAL;
1690 qboolean isLanding = qfalse, isLanded = qfalse;
1691 playerState_t *parentPS = pVeh->m_pParentEntity->playerState;
1692 int curTime = level.time;
1693
1694 if ( parentPS->hyperSpaceTime
1695 && curTime - parentPS->hyperSpaceTime < HYPERSPACE_TIME )
1696 {//Going to Hyperspace
1697 //close the wings (FIXME: makes sense on X-Wing, not Shuttle?)
1698 if ( pVeh->m_ulFlags & VEH_WINGSOPEN )
1699 {
1700 pVeh->m_ulFlags &= ~VEH_WINGSOPEN;
1701 Anim = BOTH_WINGS_CLOSE;
1702 }
1703 }
1704 else
1705 {
1706 isLanding = FighterIsLanding( pVeh, parentPS );
1707 isLanded = FighterIsLanded( pVeh, parentPS );
1708
1709 // if we're above launch height (way up in the air)...
1710 if ( !isLanding && !isLanded )
1711 {
1712 if ( !( pVeh->m_ulFlags & VEH_WINGSOPEN ) )
1713 {
1714 pVeh->m_ulFlags |= VEH_WINGSOPEN;
1715 pVeh->m_ulFlags &= ~VEH_GEARSOPEN;
1716 Anim = BOTH_WINGS_OPEN;
1717 }
1718 }
1719 // otherwise we're below launch height and still taking off.
1720 else
1721 {
1722 if ( (pVeh->m_ucmd.forwardmove < 0 || pVeh->m_ucmd.upmove < 0||isLanded)
1723 && pVeh->m_LandTrace.fraction <= 0.4f
1724 && pVeh->m_LandTrace.plane.normal[2] >= MIN_LANDING_SLOPE )
1725 {//already landed or trying to land and close to ground
1726 // Open gears.
1727 if ( !( pVeh->m_ulFlags & VEH_GEARSOPEN ) )
1728 {
1729 if ( pVeh->m_pVehicleInfo->soundLand )
1730 {//just landed?
1731 G_EntitySound( ((gentity_t *)(pVeh->m_pParentEntity)), CHAN_AUTO, pVeh->m_pVehicleInfo->soundLand );
1732 }
1733 pVeh->m_ulFlags |= VEH_GEARSOPEN;
1734 Anim = BOTH_GEARS_OPEN;
1735 }
1736 }
1737 else
1738 {//trying to take off and almost halfway off the ground
1739 // Close gears (if they're open).
1740 if ( pVeh->m_ulFlags & VEH_GEARSOPEN )
1741 {
1742 pVeh->m_ulFlags &= ~VEH_GEARSOPEN;
1743 Anim = BOTH_GEARS_CLOSE;
1744 //iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD;
1745 }
1746 // If gears are closed, and we are below launch height, close the wings.
1747 else
1748 {
1749 if ( pVeh->m_ulFlags & VEH_WINGSOPEN )
1750 {
1751 pVeh->m_ulFlags &= ~VEH_WINGSOPEN;
1752 Anim = BOTH_WINGS_CLOSE;
1753 }
1754 }
1755 }
1756 }
1757 }
1758
1759 if ( Anim != -1 )
1760 {
1761 BG_SetAnim(pVeh->m_pParentEntity->playerState, bgAllAnims[pVeh->m_pParentEntity->localAnimIndex].anims, SETANIM_BOTH, Anim, iFlags);
1762 }
1763 }
1764
1765 // This function makes sure that the rider's in this vehicle are properly animated.
AnimateRiders(Vehicle_t * pVeh)1766 static void AnimateRiders( Vehicle_t *pVeh )
1767 {
1768 }
1769
1770 #endif //game-only
1771
1772 #ifdef _CGAME
1773 void AttachRidersGeneric( Vehicle_t *pVeh );
1774 #endif
1775
G_SetFighterVehicleFunctions(vehicleInfo_t * pVehInfo)1776 void G_SetFighterVehicleFunctions( vehicleInfo_t *pVehInfo )
1777 {
1778 #ifdef _GAME //ONLY in SP or on server, not cgame
1779 pVehInfo->AnimateVehicle = AnimateVehicle;
1780 pVehInfo->AnimateRiders = AnimateRiders;
1781 // pVehInfo->ValidateBoard = ValidateBoard;
1782 // pVehInfo->SetParent = SetParent;
1783 // pVehInfo->SetPilot = SetPilot;
1784 // pVehInfo->AddPassenger = AddPassenger;
1785 // pVehInfo->Animate = Animate;
1786 pVehInfo->Board = Board;
1787 pVehInfo->Eject = Eject;
1788 // pVehInfo->EjectAll = EjectAll;
1789 // pVehInfo->StartDeathDelay = StartDeathDelay;
1790 // pVehInfo->DeathUpdate = DeathUpdate;
1791 // pVehInfo->RegisterAssets = RegisterAssets;
1792 // pVehInfo->Initialize = Initialize;
1793 pVehInfo->Update = Update;
1794 // pVehInfo->UpdateRider = UpdateRider;
1795 #endif //game-only
1796 pVehInfo->ProcessMoveCommands = ProcessMoveCommands;
1797 pVehInfo->ProcessOrientCommands = ProcessOrientCommands;
1798
1799 #ifdef _CGAME //cgame prediction attachment func
1800 pVehInfo->AttachRiders = AttachRidersGeneric;
1801 #endif
1802 // pVehInfo->AttachRiders = AttachRiders;
1803 // pVehInfo->Ghost = Ghost;
1804 // pVehInfo->UnGhost = UnGhost;
1805 // pVehInfo->Inhabited = Inhabited;
1806 }
1807
1808 // Following is only in game, not in namespace
1809 #ifdef _GAME
1810 extern void G_AllocateVehicleObject(Vehicle_t **pVeh);
1811 #endif
1812
1813 // Create/Allocate a new Animal Vehicle (initializing it as well).
G_CreateFighterNPC(Vehicle_t ** pVeh,const char * strType)1814 void G_CreateFighterNPC( Vehicle_t **pVeh, const char *strType )
1815 {
1816 // Allocate the Vehicle.
1817 #ifdef _GAME
1818 //these will remain on entities on the client once allocated because the pointer is
1819 //never stomped. on the server, however, when an ent is freed, the entity struct is
1820 //memset to 0, so this memory would be lost..
1821 G_AllocateVehicleObject(pVeh);
1822 #else
1823 if (!*pVeh)
1824 { //only allocate a new one if we really have to
1825 (*pVeh) = (Vehicle_t *) BG_Alloc( sizeof(Vehicle_t) );
1826 }
1827 #endif
1828 memset(*pVeh, 0, sizeof(Vehicle_t));
1829 (*pVeh)->m_pVehicleInfo = &g_vehicleInfo[BG_VehicleGetIndex( strType )];
1830 }
1831