00001
00002 #include "g_headers.h"
00003
00004 #include "q_shared.h"
00005 #include "g_local.h"
00006
00007 #ifdef _JK2 //SP does not have this preprocessor for game like MP does
00008 #ifndef _JK2MP
00009 #define _JK2MP
00010 #endif
00011 #endif
00012
00013 #ifndef _JK2MP
00014 #include "g_functions.h"
00015 #include "g_vehicles.h"
00016 #include "../CGame/cg_Local.h"
00017 #else
00018 #include "bg_vehicles.h"
00019 #endif
00020
00021 #ifdef _JK2MP
00022
00023
00024 #define currentAngles r.currentAngles
00025 #define currentOrigin r.currentOrigin
00026 #define mins r.mins
00027 #define maxs r.maxs
00028 #define legsAnimTimer legsTimer
00029 #define torsoAnimTimer torsoTimer
00030 #define bool qboolean
00031 #define false qfalse
00032 #define true qtrue
00033
00034 #define sqrtf sqrt
00035
00036 #define MOD_EXPLOSIVE MOD_SUICIDE
00037 #endif
00038
00039 #ifndef _JK2MP
00040 #define GAME_INLINE inline
00041 #define bgEntity_t gentity_t
00042 #endif
00043
00044 #ifdef _JK2MP
00045 extern gentity_t *NPC_Spawn_Do( gentity_t *ent );
00046 extern void NPC_SetAnim(gentity_t *ent,int setAnimParts,int anim,int setAnimFlags);
00047 #else
00048 extern gentity_t *NPC_Spawn_Do( gentity_t *pEnt, qboolean fullSpawnNow );
00049 extern qboolean G_ClearLineOfSight(const vec3_t point1, const vec3_t point2, int ignore, int clipmask);
00050
00051 extern qboolean G_SetG2PlayerModelInfo( gentity_t *pEnt, const char *modelName, const char *customSkin, const char *surfOff, const char *surfOn );
00052 extern void G_RemovePlayerModel( gentity_t *pEnt );
00053 extern void G_ChangePlayerModel( gentity_t *pEnt, const char *newModel );
00054 extern void G_RemoveWeaponModels( gentity_t *pEnt );
00055 extern void CG_ChangeWeapon( int num );
00056 extern float DotToSpot( vec3_t spot, vec3_t from, vec3_t fromAngles );
00057 extern qboolean Q3_TaskIDPending( gentity_t *ent, taskID_t taskType );
00058 extern void SetClientViewAngle( gentity_t *ent, vec3_t angle );
00059
00060 extern vmCvar_t cg_thirdPersonAlpha;
00061 extern vec3_t playerMins;
00062 extern vec3_t playerMaxs;
00063 extern cvar_t *g_speederControlScheme;
00064 extern cvar_t *in_joystick;
00065 extern void PM_SetAnim(pmove_t *pm,int setAnimParts,int anim,int setAnimFlags, int blendTime);
00066 extern int PM_AnimLength( int index, animNumber_t anim );
00067 extern void NPC_SetAnim(gentity_t *ent,int setAnimParts,int anim,int setAnimFlags, int iBlend);
00068 extern void G_Knockdown( gentity_t *self, gentity_t *attacker, const vec3_t pushDir, float strength, qboolean breakSaberLock );
00069 #endif
00070
00071 #ifdef _JK2MP
00072 #include "../namespace_begin.h"
00073 extern void BG_SetAnim(playerState_t *ps, animation_t *animations, int setAnimParts,int anim,int setAnimFlags, int blendTime);
00074 extern void BG_SetLegsAnimTimer(playerState_t *ps, int time );
00075 extern void BG_SetTorsoAnimTimer(playerState_t *ps, int time );
00076 #include "../namespace_end.h"
00077 void G_VehUpdateShields( gentity_t *targ );
00078 #ifdef QAGAME
00079 extern void VEH_TurretThink( Vehicle_t *pVeh, gentity_t *parent, int turretNum );
00080 #endif
00081 #else
00082 extern void PM_SetTorsoAnimTimer( gentity_t *ent, int *torsoAnimTimer, int time );
00083 extern void PM_SetLegsAnimTimer( gentity_t *ent, int *legsAnimTimer, int time );
00084 #endif
00085
00086 extern qboolean BG_UnrestrainedPitchRoll( playerState_t *ps, Vehicle_t *pVeh );
00087
00088 void Vehicle_SetAnim(gentity_t *ent,int setAnimParts,int anim,int setAnimFlags, int iBlend)
00089 {
00090 #ifdef _JK2MP
00091 assert(ent->client);
00092 BG_SetAnim(&ent->client->ps, bgAllAnims[ent->localAnimIndex].anims, setAnimParts, anim, setAnimFlags, iBlend);
00093 ent->s.legsAnim = ent->client->ps.legsAnim;
00094 #else
00095 NPC_SetAnim(ent, setAnimParts, anim, setAnimFlags, iBlend);
00096 #endif
00097 }
00098
00099 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 )
00100 {
00101 #ifdef _JK2MP
00102 trap_Trace(results, start, tMins, tMaxs, end, passEntityNum, contentmask);
00103 #else
00104 gi.trace( results, start, tMins, tMaxs, end, passEntityNum, contentmask );
00105 #endif
00106 }
00107
00108 Vehicle_t *G_IsRidingVehicle( gentity_t *pEnt )
00109 {
00110 gentity_t *ent = (gentity_t *)pEnt;
00111
00112 if ( ent && ent->client && ent->client->NPC_class != CLASS_VEHICLE && ent->s.m_iVehicleNum != 0 )
00113 {
00114 return g_entities[ent->s.m_iVehicleNum].m_pVehicle;
00115 }
00116 return NULL;
00117 }
00118
00119
00120
00121 float G_CanJumpToEnemyVeh(Vehicle_t *pVeh, const usercmd_t *pUcmd )
00122 {
00123 #ifndef _JK2MP
00124 gentity_t* rider = pVeh->m_pPilot;
00125
00126
00127
00128 if (rider &&
00129 rider->enemy &&
00130 pUcmd->rightmove &&
00131 fabsf(rider->enemy->currentOrigin[2] - rider->currentOrigin[2])<50.0f)
00132 {
00133 if (level.time<pVeh->m_safeJumpMountTime)
00134 {
00135 return pVeh->m_safeJumpMountRightDot;
00136 }
00137
00138
00139
00140
00141 Vehicle_t* enemyVeh = G_IsRidingVehicle(rider->enemy);
00142 if (enemyVeh)
00143 {
00144 vec3_t enemyFwd;
00145 vec3_t toEnemy;
00146 float toEnemyDistance;
00147 vec3_t riderFwd;
00148 vec3_t riderRight;
00149 float riderRightDot;
00150
00151
00152
00153 VectorSubtract(rider->enemy->currentOrigin, rider->currentOrigin, toEnemy);
00154 toEnemyDistance = VectorNormalize(toEnemy);
00155 if (toEnemyDistance<70.0f &&
00156 pVeh->m_pParentEntity->resultspeed>100.0f &&
00157 fabsf(pVeh->m_pParentEntity->resultspeed - enemyVeh->m_pParentEntity->resultspeed)<100.0f)
00158 {
00159
00160
00161 AngleVectors(rider->currentAngles, riderFwd, riderRight, 0);
00162 riderRightDot = DotProduct(riderRight, toEnemy);
00163 if ((pUcmd->rightmove>0 && riderRightDot>0.2) || (pUcmd->rightmove<0 &&riderRightDot<-0.2))
00164 {
00165
00166
00167 AngleVectors(rider->enemy->currentAngles, enemyFwd, 0, 0);
00168 if (DotProduct(enemyFwd, riderFwd)>0.2f)
00169 {
00170 pVeh->m_safeJumpMountTime = level.time + Q_irand(3000, 4000);
00171 pVeh->m_safeJumpMountRightDot = riderRightDot;
00172 return riderRightDot;
00173 }
00174 }
00175 }
00176 }
00177 }
00178 #endif
00179 return 0.0f;
00180 }
00181
00182
00183 void G_VehicleSpawn( gentity_t *self )
00184 {
00185 float yaw;
00186 gentity_t *vehEnt;
00187
00188 VectorCopy( self->currentOrigin, self->s.origin );
00189
00190 #ifdef _JK2MP
00191 trap_LinkEntity( self );
00192 #else
00193 gi.linkentity( self );
00194 #endif
00195
00196 if ( !self->count )
00197 {
00198 self->count = 1;
00199 }
00200
00201
00202 yaw = self->s.angles[YAW];
00203
00204 #ifdef _JK2MP
00205 vehEnt = NPC_Spawn_Do( self );
00206 #else
00207 vehEnt = NPC_Spawn_Do( self, qtrue );
00208 #endif
00209
00210 if ( !vehEnt )
00211 {
00212 return;
00213 }
00214
00215 vehEnt->s.angles[YAW] = yaw;
00216 if ( vehEnt->m_pVehicle->m_pVehicleInfo->type != VH_ANIMAL )
00217 {
00218 vehEnt->NPC->behaviorState = BS_CINEMATIC;
00219 }
00220
00221 #ifdef _JK2MP //special check in case someone disconnects/dies while boarding
00222 if (vehEnt->spawnflags & 1)
00223 {
00224 if (!vehEnt->damage)
00225 {
00226 vehEnt->damage = 10000;
00227 }
00228 if (!vehEnt->speed)
00229 {
00230 vehEnt->speed = 512.0f;
00231 }
00232 vehEnt->m_pVehicle->m_iPilotTime = level.time + vehEnt->damage;
00233 }
00234 #else
00235 if (vehEnt->spawnflags & 1)
00236 {
00237 vehEnt->m_pVehicle->m_iPilotTime = level.time + vehEnt->endFrame;
00238 }
00239 #endif
00240
00241 }
00242
00243
00244 void G_AttachToVehicle( gentity_t *pEnt, usercmd_t **ucmd )
00245 {
00246 gentity_t *vehEnt;
00247 mdxaBone_t boltMatrix;
00248 gentity_t *ent;
00249 #ifdef _JK2MP
00250 int crotchBolt;
00251 #endif
00252
00253 if ( !pEnt || !ucmd )
00254 return;
00255
00256 ent = (gentity_t *)pEnt;
00257
00258 #ifdef _JK2MP
00259 vehEnt = &g_entities[ent->r.ownerNum];
00260 #else
00261 vehEnt = ent->owner;
00262 #endif
00263 ent->waypoint = vehEnt->waypoint;
00264
00265 if ( !vehEnt->m_pVehicle )
00266 return;
00267
00268 #ifdef _JK2MP
00269 crotchBolt = trap_G2API_AddBolt(vehEnt->ghoul2, 0, "*driver");
00270
00271
00272 trap_G2API_GetBoltMatrix( vehEnt->ghoul2, 0, crotchBolt, &boltMatrix,
00273 vehEnt->m_pVehicle->m_vOrientation, vehEnt->currentOrigin,
00274 level.time, NULL, vehEnt->modelScale );
00275 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, ent->client->ps.origin );
00276 G_SetOrigin(ent, ent->client->ps.origin);
00277 trap_LinkEntity( ent );
00278 #else
00279
00280 gi.G2API_GetBoltMatrix( vehEnt->ghoul2, vehEnt->playerModel, vehEnt->crotchBolt, &boltMatrix,
00281 vehEnt->m_pVehicle->m_vOrientation, vehEnt->currentOrigin,
00282 (cg.time?cg.time:level.time), NULL, vehEnt->s.modelScale );
00283 gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, ent->client->ps.origin );
00284 gi.linkentity( ent );
00285 #endif
00286 }
00287
00288 #ifndef _JK2MP
00289 void G_KnockOffVehicle( gentity_t *pRider, gentity_t *self, qboolean bPull )
00290 {
00291 Vehicle_t *pVeh = NULL;
00292 vec3_t riderAngles, fDir, rDir, dir2Me;
00293 float fDot, rDot;
00294
00295 if ( !pRider || !pRider->client )
00296 {
00297 return;
00298 }
00299
00300 pVeh = G_IsRidingVehicle( pRider );
00301
00302 if ( !pVeh || !pVeh->m_pVehicleInfo )
00303 {
00304 return;
00305 }
00306
00307 VectorCopy( pRider->currentAngles, riderAngles );
00308 riderAngles[0] = 0;
00309 AngleVectors( riderAngles, fDir, rDir, NULL );
00310 VectorSubtract( self->currentOrigin, pRider->currentOrigin, dir2Me );
00311 dir2Me[2] = 0;
00312 VectorNormalize( dir2Me );
00313 fDot = DotProduct( fDir, dir2Me );
00314 if ( fDot >= 0.5f )
00315 {
00316 if ( bPull )
00317 {
00318 pVeh->m_EjectDir = VEH_EJECT_FRONT;
00319 }
00320 else
00321 {
00322 pVeh->m_EjectDir = VEH_EJECT_REAR;
00323 }
00324 }
00325 else if ( fDot <= -0.5f )
00326 {
00327 if ( bPull )
00328 {
00329 pVeh->m_EjectDir = VEH_EJECT_REAR;
00330 }
00331 else
00332 {
00333 pVeh->m_EjectDir = VEH_EJECT_FRONT;
00334 }
00335 }
00336 else
00337 {
00338 rDot = DotProduct( fDir, dir2Me );
00339 if ( rDot >= 0.0f )
00340 {
00341 if ( bPull )
00342 {
00343 pVeh->m_EjectDir = VEH_EJECT_RIGHT;
00344 }
00345 else
00346 {
00347 pVeh->m_EjectDir = VEH_EJECT_LEFT;
00348 }
00349 }
00350 else
00351 {
00352 if ( bPull )
00353 {
00354 pVeh->m_EjectDir = VEH_EJECT_LEFT;
00355 }
00356 else
00357 {
00358 pVeh->m_EjectDir = VEH_EJECT_RIGHT;
00359 }
00360 }
00361 }
00362
00363 pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qtrue );
00364 }
00365 #endif
00366
00367 #ifndef _JK2MP //don't want this in mp at least for now
00368 void G_DrivableATSTDie( gentity_t *self )
00369 {
00370 }
00371
00372 void G_DriveATST( gentity_t *pEnt, gentity_t *atst )
00373 {
00374 if ( pEnt->NPC_type && pEnt->client && (pEnt->client->NPC_class == CLASS_ATST) )
00375 {
00376
00377 G_RemovePlayerModel( pEnt );
00378 pEnt->NPC_type = "player";
00379 pEnt->client->NPC_class = CLASS_PLAYER;
00380 pEnt->flags &= ~FL_SHIELDED;
00381 pEnt->client->ps.eFlags &= ~EF_IN_ATST;
00382
00383 VectorCopy( playerMins, pEnt->mins );
00384 VectorCopy( playerMaxs, pEnt->maxs );
00385 pEnt->client->crouchheight = CROUCH_MAXS_2;
00386 pEnt->client->standheight = DEFAULT_MAXS_2;
00387 G_ChangePlayerModel( pEnt, pEnt->NPC_type );
00388
00389
00390
00391 pEnt->client->ps.stats[STAT_WEAPONS] &= ~(( 1 << WP_ATST_MAIN )|( 1 << WP_ATST_SIDE ));
00392 pEnt->client->ps.ammo[weaponData[WP_ATST_MAIN].ammoIndex] = 0;
00393 pEnt->client->ps.ammo[weaponData[WP_ATST_SIDE].ammoIndex] = 0;
00394 CG_ChangeWeapon( WP_BLASTER );
00395
00396
00397 {
00398 gi.cvar_set( "cg_thirdperson", "0" );
00399 }
00400 cg.overrides.active &= ~(CG_OVERRIDE_3RD_PERSON_RNG|CG_OVERRIDE_3RD_PERSON_VOF|CG_OVERRIDE_3RD_PERSON_POF|CG_OVERRIDE_3RD_PERSON_APH);
00401 cg.overrides.thirdPersonRange = cg.overrides.thirdPersonVertOffset = cg.overrides.thirdPersonPitchOffset = 0;
00402 cg.overrides.thirdPersonAlpha = cg_thirdPersonAlpha.value;
00403 pEnt->client->ps.viewheight = pEnt->maxs[2] + STANDARD_VIEWHEIGHT_OFFSET;
00404
00405 }
00406 else
00407 {
00408 pEnt->NPC_type = "atst";
00409 pEnt->client->NPC_class = CLASS_ATST;
00410 pEnt->client->ps.eFlags |= EF_IN_ATST;
00411 pEnt->flags |= FL_SHIELDED;
00412
00413 VectorSet( pEnt->mins, ATST_MINS0, ATST_MINS1, ATST_MINS2 );
00414 VectorSet( pEnt->maxs, ATST_MAXS0, ATST_MAXS1, ATST_MAXS2 );
00415 pEnt->client->crouchheight = ATST_MAXS2;
00416 pEnt->client->standheight = ATST_MAXS2;
00417 if ( !atst )
00418 {
00419 G_ChangePlayerModel( pEnt, "atst" );
00420
00421 NPC_SetAnim( pEnt, SETANIM_BOTH, BOTH_STAND1, SETANIM_FLAG_OVERRIDE, 200 );
00422 }
00423 else
00424 {
00425 G_RemovePlayerModel( pEnt );
00426 G_RemoveWeaponModels( pEnt );
00427 gi.G2API_CopyGhoul2Instance( atst->ghoul2, pEnt->ghoul2 );
00428 pEnt->playerModel = 0;
00429 G_SetG2PlayerModelInfo( pEnt, "atst", NULL, NULL, NULL );
00430
00431 gi.G2API_SetSurfaceOnOff( &pEnt->ghoul2[pEnt->playerModel], "head_hatchcover", 0x00000002 );
00432 G_Sound( pEnt, G_SoundIndex( "sound/chars/atst/atst_hatch_close" ));
00433 }
00434 pEnt->s.radius = 320;
00435
00436 gitem_t *item = FindItemForWeapon( WP_ATST_MAIN );
00437 CG_RegisterItemSounds( (item-bg_itemlist) );
00438 CG_RegisterItemVisuals( (item-bg_itemlist) );
00439 item = FindItemForWeapon( WP_ATST_SIDE );
00440 CG_RegisterItemSounds( (item-bg_itemlist) );
00441 CG_RegisterItemVisuals( (item-bg_itemlist) );
00442 pEnt->client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_ATST_MAIN )|( 1 << WP_ATST_SIDE );
00443 pEnt->client->ps.ammo[weaponData[WP_ATST_MAIN].ammoIndex] = ammoData[weaponData[WP_ATST_MAIN].ammoIndex].max;
00444 pEnt->client->ps.ammo[weaponData[WP_ATST_SIDE].ammoIndex] = ammoData[weaponData[WP_ATST_SIDE].ammoIndex].max;
00445 CG_ChangeWeapon( WP_ATST_MAIN );
00446
00447 item = FindItemForWeapon( WP_EMPLACED_GUN );
00448 CG_RegisterItemSounds( (item-bg_itemlist) );
00449 CG_RegisterItemVisuals( (item-bg_itemlist) );
00450 item = FindItemForWeapon( WP_ROCKET_LAUNCHER );
00451 CG_RegisterItemSounds( (item-bg_itemlist) );
00452 CG_RegisterItemVisuals( (item-bg_itemlist) );
00453 item = FindItemForWeapon( WP_BOWCASTER );
00454 CG_RegisterItemSounds( (item-bg_itemlist) );
00455 CG_RegisterItemVisuals( (item-bg_itemlist) );
00456
00457
00458
00459 gi.cvar_set( "cg_thirdperson", "1" );
00460 cg.overrides.active |= CG_OVERRIDE_3RD_PERSON_RNG;
00461 cg.overrides.thirdPersonRange = 240;
00462
00463
00464
00465 pEnt->client->ps.viewheight = 120;
00466
00467
00468
00469
00470
00471
00472
00473 }
00474 }
00475 #endif //_JK2MP
00476
00477
00478 void Animate( Vehicle_t *pVeh )
00479 {
00480
00481 if ( pVeh->m_pPilot )
00482 {
00483 if (pVeh->m_pVehicleInfo->AnimateRiders)
00484 {
00485 pVeh->m_pVehicleInfo->AnimateRiders( pVeh );
00486 }
00487 }
00488
00489 pVeh->m_pVehicleInfo->AnimateVehicle( pVeh );
00490 }
00491
00492
00493 bool ValidateBoard( Vehicle_t *pVeh, bgEntity_t *pEnt )
00494 {
00495
00496 vec3_t vVehToEnt;
00497 vec3_t vVehDir;
00498 const gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
00499 const gentity_t *ent = (gentity_t *)pEnt;
00500 vec3_t vVehAngles;
00501 float fDot;
00502
00503 if ( pVeh->m_iDieTime>0)
00504 {
00505 return false;
00506 }
00507
00508 if ( pVeh->m_pPilot != NULL )
00509 {
00510 if ( pVeh->m_pVehicleInfo->type == VH_FIGHTER )
00511 {
00512
00513 if ( pVeh->m_iNumPassengers < pVeh->m_pVehicleInfo->maxPassengers )
00514 {
00515 return true;
00516 }
00517 else
00518 {
00519 return false;
00520 }
00521 }
00522 else if ( pVeh->m_pVehicleInfo->type == VH_WALKER )
00523 {
00524 if ( !ent->client || ent->client->ps.groundEntityNum != parent->s.number )
00525 {
00526 return false;
00527 }
00528 }
00529 else if (pVeh->m_pVehicleInfo->type == VH_SPEEDER)
00530 {
00531 return (pVeh->m_iBoarding==VEH_MOUNT_THROW_LEFT || pVeh->m_iBoarding==VEH_MOUNT_THROW_RIGHT);
00532 }
00533 }
00534
00535
00536 else if ( pVeh->m_pVehicleInfo->type == VH_FIGHTER )
00537 {
00538
00539 return true;
00540 }
00541
00542
00543 VectorSet(vVehAngles, 0, parent->currentAngles[YAW], 0);
00544
00545
00546 VectorSubtract( ent->currentOrigin, parent->currentOrigin, vVehToEnt );
00547 vVehToEnt[2] = 0;
00548 VectorNormalize( vVehToEnt );
00549
00550
00551 AngleVectors( vVehAngles, NULL, vVehDir, NULL );
00552 VectorNormalize( vVehDir );
00553
00554
00555 fDot = DotProduct( vVehToEnt, vVehDir );
00556
00557
00558 if ( fDot >= 0.5f )
00559 {
00560
00561 pVeh->m_iBoarding = -2;
00562 }
00563 else if ( fDot <= -0.5f )
00564 {
00565
00566 pVeh->m_iBoarding = -1;
00567 }
00568
00569 else
00570 {
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580 {
00581
00582 pVeh->m_iBoarding = -3;
00583 }
00584 }
00585
00586
00587 if ( pVeh->m_iBoarding > -1 )
00588 return false;
00589
00590 return true;
00591 }
00592
00593 #ifdef VEH_CONTROL_SCHEME_4
00594 void FighterStorePilotViewAngles( Vehicle_t *pVeh, bgEntity_t *parent )
00595 {
00596 playerState_t *riderPS;
00597 #ifdef _JK2MP
00598 bgEntity_t *rider = NULL;
00599 if (parent->s.owner != ENTITYNUM_NONE)
00600 {
00601 rider = PM_BGEntForNum(parent->s.owner);
00602 }
00603 #else
00604 gentity_t *rider = parent->owner;
00605 #endif
00606
00607 #ifdef _JK2MP
00608 if ( !rider )
00609 #else
00610 if ( !rider || !rider->client )
00611 #endif
00612 {
00613 rider = parent;
00614 }
00615
00616 #ifdef _JK2MP
00617 riderPS = rider->playerState;
00618 #else
00619 riderPS = &rider->client->ps;
00620 #endif
00621 VectorClear( pVeh->m_vPrevRiderViewAngles );
00622 pVeh->m_vPrevRiderViewAngles[YAW] = AngleNormalize180(riderPS->viewangles[YAW]);
00623 }
00624 #endif// VEH_CONTROL_SCHEME_4
00625
00626
00627 bool Board( Vehicle_t *pVeh, bgEntity_t *pEnt )
00628 {
00629 vec3_t vPlayerDir;
00630 gentity_t *ent = (gentity_t *)pEnt;
00631 gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
00632
00633
00634
00635
00636 if ( !ent || parent->health <= 0 || (pVeh->m_iBoarding > 0) ||
00637 #ifdef _JK2MP
00638 ( ent->client->ps.m_iVehicleNum ) )
00639 #else
00640 ( ent->s.m_iVehicleNum != 0 ) )
00641 #endif
00642 return false;
00643
00644
00645 if ( pVeh->m_ulFlags & VEH_BUCKING )
00646 return false;
00647
00648
00649 if ( !pVeh->m_pVehicleInfo->ValidateBoard( pVeh, pEnt ) )
00650 return false;
00651
00652
00653
00654
00655
00656
00657 if ( ent->s.number < MAX_CLIENTS )
00658 {
00659 pVeh->m_pOldPilot = pVeh->m_pPilot;
00660
00661
00662 #ifdef _JK2MP
00663 if ( !pVeh->m_pPilot )
00664 {
00665 pVeh->m_pVehicleInfo->SetPilot( pVeh, (bgEntity_t *)ent );
00666 }
00667
00668 else if ( pVeh->m_iNumPassengers < pVeh->m_pVehicleInfo->maxPassengers )
00669 {
00670 int i;
00671
00672 for ( i = 0; i < pVeh->m_pVehicleInfo->maxPassengers; i++ )
00673 {
00674 if ( pVeh->m_ppPassengers[i] == NULL )
00675 {
00676 pVeh->m_ppPassengers[i] = (bgEntity_t *)ent;
00677 #ifdef QAGAME
00678
00679 if ( ent->client )
00680 {
00681 ent->client->ps.generic1 = i+1;
00682 }
00683 #endif
00684 break;
00685 }
00686 }
00687 pVeh->m_iNumPassengers++;
00688 }
00689
00690 else
00691 {
00692 return false;
00693 }
00694 ent->s.m_iVehicleNum = parent->s.number;
00695 if (ent->client)
00696 {
00697 ent->client->ps.m_iVehicleNum = ent->s.m_iVehicleNum;
00698 }
00699 if ( pVeh->m_pPilot == (bgEntity_t *)ent )
00700 {
00701 parent->r.ownerNum = ent->s.number;
00702 parent->s.owner = parent->r.ownerNum;
00703 }
00704 #else
00705 pVeh->m_pVehicleInfo->SetPilot( pVeh, ent );
00706 ent->s.m_iVehicleNum = parent->s.number;
00707 parent->owner = ent;
00708 #endif
00709
00710 #ifdef QAGAME
00711 {
00712 gentity_t *gParent = (gentity_t *)parent;
00713 if ( (gParent->spawnflags&2) )
00714 {
00715 gParent->spawnflags &= ~2;
00716
00717 G_Sound( gParent, CHAN_AUTO, G_SoundIndex( "sound/vehicles/common/release.wav" ) );
00718 if ( gParent->fly_sound_debounce_time )
00719 {
00720 pVeh->m_iDropTime = level.time + gParent->fly_sound_debounce_time;
00721 }
00722 }
00723 }
00724 #endif
00725
00726 #ifndef _JK2MP
00727 gi.cvar_set( "cg_thirdperson", "1" );
00728 CG_CenterPrint( "@SP_INGAME_EXIT_VIEW", SCREEN_HEIGHT * 0.95 );
00729 #endif
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740 if ( pVeh->m_pVehicleInfo->soundLoop )
00741 {
00742 #ifdef _JK2MP
00743 parent->client->ps.loopSound = parent->s.loopSound = pVeh->m_pVehicleInfo->soundLoop;
00744 #else
00745 parent->s.loopSound = pVeh->m_pVehicleInfo->soundLoop;
00746 #endif
00747 }
00748 }
00749 else
00750 {
00751
00752 if ( pVeh->m_pPilot == NULL )
00753 {
00754 #ifdef _JK2MP
00755 pVeh->m_pVehicleInfo->SetPilot( pVeh, (bgEntity_t *)ent );
00756
00757 parent->r.ownerNum = ent->s.number;
00758 parent->s.owner = parent->r.ownerNum;
00759 #else
00760 pVeh->m_pVehicleInfo->SetPilot( pVeh, ent );
00761
00762 parent->owner = ent;
00763 #endif
00764
00765 if ( pVeh->m_pVehicleInfo->soundLoop )
00766 {
00767 #ifdef _JK2MP
00768 parent->client->ps.loopSound = parent->s.loopSound = pVeh->m_pVehicleInfo->soundLoop;
00769 #else
00770 parent->s.loopSound = pVeh->m_pVehicleInfo->soundLoop;
00771 #endif
00772 }
00773
00774 parent->client->ps.speed = 0;
00775 memset( &pVeh->m_ucmd, 0, sizeof( usercmd_t ) );
00776 }
00777
00778 else if ( pVeh->m_iNumPassengers < pVeh->m_pVehicleInfo->maxPassengers )
00779 {
00780 int i;
00781
00782 for ( i = 0; i < pVeh->m_pVehicleInfo->maxPassengers; i++ )
00783 {
00784 if ( pVeh->m_ppPassengers[i] == NULL )
00785 {
00786 #ifdef _JK2MP
00787 pVeh->m_ppPassengers[i] = (bgEntity_t *)ent;
00788 #ifdef QAGAME
00789
00790 if ( ent->client )
00791 {
00792 ent->client->ps.generic1 = i+1;
00793 }
00794 #endif
00795 #else
00796 pVeh->m_ppPassengers[i] = ent;
00797 #endif
00798 break;
00799 }
00800 }
00801 pVeh->m_iNumPassengers++;
00802 }
00803
00804 else
00805 {
00806 return false;
00807 }
00808 }
00809
00810
00811 #ifdef _JK2MP
00812 ent->client->ps.m_iVehicleNum = parent->s.number;
00813 ent->r.ownerNum = parent->s.number;
00814 ent->s.owner = ent->r.ownerNum;
00815 if (pVeh->m_pPilot == (bgEntity_t *)ent)
00816 {
00817 parent->client->ps.m_iVehicleNum = ent->s.number+1;
00818 }
00819 #else
00820 ent->s.m_iVehicleNum = parent->s.number;
00821 ent->owner = parent;
00822 parent->s.m_iVehicleNum = ent->s.number+1;
00823 #endif
00824
00825
00826
00827
00828 if ( pVeh->m_pVehicleInfo->numHands == 2 )
00829 {
00830 #ifndef _JK2MP //rwwFIXMEFIXMEFIXME
00831 if (ent->s.number<MAX_CLIENTS)
00832 {
00833 CG_ChangeWeapon(WP_NONE);
00834 }
00835
00836 ent->client->ps.weapon = WP_NONE;
00837 G_RemoveWeaponModels( ent );
00838 #endif
00839 }
00840
00841 if ( pVeh->m_pVehicleInfo->hideRider )
00842 {
00843 pVeh->m_pVehicleInfo->Ghost( pVeh, (bgEntity_t *)ent );
00844 }
00845
00846
00847 if ( pVeh->m_pVehicleInfo->soundOn )
00848 {
00849 #ifdef _JK2MP
00850 G_Sound( parent, CHAN_AUTO, pVeh->m_pVehicleInfo->soundOn );
00851 #else
00852
00853 G_SoundIndexOnEnt( parent, CHAN_AUTO, pVeh->m_pVehicleInfo->soundOn );
00854 #endif
00855 }
00856
00857 #ifdef VEH_CONTROL_SCHEME_4
00858 if ( pVeh->m_pVehicleInfo->type == VH_FIGHTER )
00859 {
00860 FighterStorePilotViewAngles( pVeh, (bgEntity_t *)parent );
00861 }
00862 #endif //VEH_CONTROL_SCHEME_4
00863
00864 VectorCopy( pVeh->m_vOrientation, vPlayerDir );
00865 vPlayerDir[ROLL] = 0;
00866 SetClientViewAngle( ent, vPlayerDir );
00867
00868 return true;
00869 }
00870
00871 bool VEH_TryEject( Vehicle_t *pVeh,
00872 gentity_t *parent,
00873 gentity_t *ent,
00874 int ejectDir,
00875 vec3_t vExitPos )
00876 {
00877 float fBias;
00878 float fVehDiag;
00879 float fEntDiag;
00880 int oldOwner;
00881 vec3_t vEntMins, vEntMaxs, vVehLeaveDir, vVehAngles;
00882 trace_t m_ExitTrace;
00883
00884
00885
00886 VectorSet(vVehAngles, 0, parent->currentAngles[YAW], 0);
00887 switch ( ejectDir )
00888 {
00889
00890 case VEH_EJECT_LEFT:
00891 AngleVectors( vVehAngles, NULL, vVehLeaveDir, NULL );
00892 vVehLeaveDir[0] = -vVehLeaveDir[0];
00893 vVehLeaveDir[1] = -vVehLeaveDir[1];
00894 vVehLeaveDir[2] = -vVehLeaveDir[2];
00895 break;
00896
00897 case VEH_EJECT_RIGHT:
00898 AngleVectors( vVehAngles, NULL, vVehLeaveDir, NULL );
00899 break;
00900
00901 case VEH_EJECT_FRONT:
00902 AngleVectors( vVehAngles, vVehLeaveDir, NULL, NULL );
00903 break;
00904
00905 case VEH_EJECT_REAR:
00906 AngleVectors( vVehAngles, vVehLeaveDir, NULL, NULL );
00907 vVehLeaveDir[0] = -vVehLeaveDir[0];
00908 vVehLeaveDir[1] = -vVehLeaveDir[1];
00909 vVehLeaveDir[2] = -vVehLeaveDir[2];
00910 break;
00911
00912 case VEH_EJECT_TOP:
00913 AngleVectors( vVehAngles, NULL, NULL, vVehLeaveDir );
00914 break;
00915
00916 case VEH_EJECT_BOTTOM:
00917 break;
00918 }
00919 VectorNormalize( vVehLeaveDir );
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929 fBias = 1.0f;
00930 if (pVeh->m_pVehicleInfo->type == VH_WALKER)
00931 {
00932 fBias += 0.2f;
00933 }
00934 VectorCopy( ent->currentOrigin, vExitPos );
00935 fVehDiag = sqrtf( ( parent->maxs[0] * parent->maxs[0] ) + ( parent->maxs[1] * parent->maxs[1] ) );
00936 VectorCopy( ent->maxs, vEntMaxs );
00937 #ifdef _JK2MP
00938 if ( ent->s.number < MAX_CLIENTS )
00939 {
00940 vEntMaxs[0] = 15;
00941 vEntMaxs[1] = 15;
00942 }
00943 #endif
00944 fEntDiag = sqrtf( ( vEntMaxs[0] * vEntMaxs[0] ) + ( vEntMaxs[1] * vEntMaxs[1] ) );
00945 vVehLeaveDir[0] *= ( fVehDiag + fEntDiag ) * fBias;
00946 vVehLeaveDir[1] *= ( fVehDiag + fEntDiag ) * fBias;
00947 vVehLeaveDir[2] *= ( fVehDiag + fEntDiag ) * fBias;
00948 VectorAdd( vExitPos, vVehLeaveDir, vExitPos );
00949
00950
00951
00952 #ifdef _JK2MP
00953 VectorSet(vEntMins, -15.0f, -15.0f, DEFAULT_MINS_2);
00954 VectorSet(vEntMaxs, 15.0f, 15.0f, DEFAULT_MAXS_2);
00955 #else
00956 VectorCopy(ent->mins, vEntMins);
00957 VectorCopy(ent->maxs, vEntMaxs);
00958 #endif
00959 oldOwner = ent->r.ownerNum;
00960 ent->r.ownerNum = ENTITYNUM_NONE;
00961 G_VehicleTrace( &m_ExitTrace, ent->currentOrigin, vEntMins, vEntMaxs, vExitPos, ent->s.number, ent->clipmask );
00962 ent->r.ownerNum = oldOwner;
00963
00964 if ( m_ExitTrace.allsolid
00965 || m_ExitTrace.startsolid)
00966 {
00967 return false;
00968 }
00969
00970 if ( m_ExitTrace.fraction < 1.0f )
00971 {
00972 #ifdef _JK2MP
00973
00974 #else
00975 if ( (parent->clipmask&ent->contents) )
00976 #endif
00977 {
00978 return false;
00979 }
00980
00981 VectorCopy( m_ExitTrace.endpos, vExitPos );
00982 }
00983 return true;
00984 }
00985
00986 void G_EjectDroidUnit( Vehicle_t *pVeh, qboolean kill )
00987 {
00988 pVeh->m_pDroidUnit->s.m_iVehicleNum = ENTITYNUM_NONE;
00989 #ifdef _JK2MP
00990 pVeh->m_pDroidUnit->s.owner = ENTITYNUM_NONE;
00991 #else
00992 pVeh->m_pDroidUnit->owner = NULL;
00993 #endif
00994
00995 #ifdef QAGAME
00996 {
00997 gentity_t *droidEnt = (gentity_t *)pVeh->m_pDroidUnit;
00998 droidEnt->flags &= ~FL_UNDYING;
00999 droidEnt->r.ownerNum = ENTITYNUM_NONE;
01000 if ( droidEnt->client )
01001 {
01002 droidEnt->client->ps.m_iVehicleNum = ENTITYNUM_NONE;
01003 }
01004 if ( kill )
01005 {
01006
01007 G_MuteSound(droidEnt->s.number, CHAN_VOICE);
01008 G_Damage( droidEnt, NULL, NULL, NULL, droidEnt->s.origin, 10000, 0, MOD_SUICIDE );
01009 }
01010 }
01011 #endif
01012 pVeh->m_pDroidUnit = NULL;
01013 }
01014
01015
01016 bool Eject( Vehicle_t *pVeh, bgEntity_t *pEnt, qboolean forceEject )
01017 {
01018 gentity_t *parent;
01019 vec3_t vExitPos;
01020 #ifndef _JK2MP
01021 vec3_t vPlayerDir;
01022 #endif
01023 gentity_t *ent = (gentity_t *)pEnt;
01024 int firstEjectDir;
01025
01026 #ifdef _JK2MP
01027 qboolean taintedRider = qfalse;
01028 qboolean deadRider = qfalse;
01029
01030 if ( pEnt == pVeh->m_pDroidUnit )
01031 {
01032 G_EjectDroidUnit( pVeh, qfalse );
01033 return true;
01034 }
01035
01036 if (ent)
01037 {
01038 if (!ent->inuse || !ent->client || ent->client->pers.connected != CON_CONNECTED)
01039 {
01040 taintedRider = qtrue;
01041 parent = (gentity_t *)pVeh->m_pParentEntity;
01042 goto getItOutOfMe;
01043 }
01044 else if (ent->health < 1)
01045 {
01046 deadRider = qtrue;
01047 }
01048 }
01049 #endif
01050
01051
01052 if ( !ent )
01053 {
01054 return false;
01055 }
01056 if ( !forceEject )
01057 {
01058 if ( !( pVeh->m_iBoarding == 0 || pVeh->m_iBoarding == -999 || ( pVeh->m_iBoarding < -3 && pVeh->m_iBoarding >= -9 ) ) )
01059 {
01060 #ifdef _JK2MP //I don't care, if he's dead get him off even if he died while boarding
01061 deadRider = qtrue;
01062 pVeh->m_iBoarding = 0;
01063 pVeh->m_bWasBoarding = false;
01064 #else
01065 return false;
01066 #endif
01067 }
01068 }
01069
01070 #ifndef _JK2MP //rwwFIXMEFIXMEFIXME
01071 if (ent->s.number<MAX_CLIENTS)
01072 {
01073 CG_ChangeWeapon(WP_NONE);
01074 }
01075 ent->client->ps.weapon = WP_NONE;
01076 G_RemoveWeaponModels( ent );
01077 #endif
01078
01079 parent = (gentity_t *)pVeh->m_pParentEntity;
01080
01081
01082 if ( pVeh->m_EjectDir < VEH_EJECT_LEFT )
01083 {
01084 pVeh->m_EjectDir = VEH_EJECT_LEFT;
01085 }
01086 else if ( pVeh->m_EjectDir > VEH_EJECT_BOTTOM )
01087 {
01088 pVeh->m_EjectDir = VEH_EJECT_BOTTOM;
01089 }
01090 firstEjectDir = pVeh->m_EjectDir;
01091 while ( !VEH_TryEject( pVeh, parent, ent, pVeh->m_EjectDir, vExitPos ) )
01092 {
01093 pVeh->m_EjectDir++;
01094 if ( pVeh->m_EjectDir > VEH_EJECT_BOTTOM )
01095 {
01096 pVeh->m_EjectDir = VEH_EJECT_LEFT;
01097 }
01098 if ( pVeh->m_EjectDir == firstEjectDir )
01099 {
01100 #ifdef _JK2MP
01101 if (!deadRider)
01102 {
01103 return false;
01104 }
01105 #endif
01106 if ( forceEject )
01107 {
01108 VectorCopy( ent->currentOrigin, vExitPos );
01109 break;
01110 }
01111 else
01112 {
01113 return false;
01114 }
01115 }
01116 }
01117
01118
01119 G_SetOrigin( ent, vExitPos );
01120 #ifdef _JK2MP
01121 VectorCopy(ent->currentOrigin, ent->client->ps.origin);
01122 trap_LinkEntity( ent );
01123 #else
01124 gi.linkentity( ent );
01125 #endif
01126
01127
01128 if ( ent->s.number < MAX_CLIENTS )
01129 {
01130 #ifndef _JK2MP
01131 cg.overrides.active = 0;
01132 #else
01133
01134 #endif
01135 }
01136
01137 #ifdef _JK2MP //in MP if someone disconnects on us, we still have to clear our owner
01138 getItOutOfMe:
01139 #endif
01140
01141
01142 if ( (gentity_t *)pVeh->m_pPilot == ent )
01143 {
01144 #ifdef _JK2MP
01145 int j = 0;
01146 #endif
01147
01148 pVeh->m_pPilot = NULL;
01149 #ifdef _JK2MP
01150 parent->r.ownerNum = ENTITYNUM_NONE;
01151 parent->s.owner = parent->r.ownerNum;
01152
01153
01154
01155 memset( &parent->client->pers.cmd, 0, sizeof( usercmd_t ) );
01156 #else
01157 parent->owner = NULL;
01158
01159
01160
01161 memset( &parent->client->usercmd, 0, sizeof( usercmd_t ) );
01162 #endif
01163 memset( &pVeh->m_ucmd, 0, sizeof( usercmd_t ) );
01164
01165 #ifdef _JK2MP //if there are some passengers, promote the first passenger to pilot
01166 while (j < pVeh->m_iNumPassengers)
01167 {
01168 if (pVeh->m_ppPassengers[j])
01169 {
01170 int k = 1;
01171 pVeh->m_pVehicleInfo->SetPilot( pVeh, pVeh->m_ppPassengers[j] );
01172 parent->r.ownerNum = pVeh->m_ppPassengers[j]->s.number;
01173 parent->s.owner = parent->r.ownerNum;
01174 parent->client->ps.m_iVehicleNum = pVeh->m_ppPassengers[j]->s.number+1;
01175
01176
01177 #ifdef QAGAME
01178
01179 if ( ((gentity_t *)pVeh->m_ppPassengers[j])->client )
01180 {
01181 ((gentity_t *)pVeh->m_ppPassengers[j])->client->ps.generic1 = 0;
01182 }
01183 #endif
01184 pVeh->m_ppPassengers[j] = NULL;
01185 while (k < pVeh->m_iNumPassengers)
01186 {
01187 if (!pVeh->m_ppPassengers[k-1])
01188 {
01189 pVeh->m_ppPassengers[k-1] = pVeh->m_ppPassengers[k];
01190 pVeh->m_ppPassengers[k] = NULL;
01191 #ifdef QAGAME
01192
01193 if ( ((gentity_t *)pVeh->m_ppPassengers[k-1])->client )
01194 {
01195 ((gentity_t *)pVeh->m_ppPassengers[k-1])->client->ps.generic1 = k;
01196 }
01197 #endif
01198 }
01199 k++;
01200 }
01201 pVeh->m_iNumPassengers--;
01202
01203 break;
01204 }
01205 j++;
01206 }
01207 #endif
01208 }
01209 else if (ent==(gentity_t *)pVeh->m_pOldPilot)
01210 {
01211 pVeh->m_pOldPilot = 0;
01212 }
01213 else
01214 {
01215 int i;
01216
01217 for ( i = 0; i < pVeh->m_pVehicleInfo->maxPassengers; i++ )
01218 {
01219
01220 if ( (gentity_t *)pVeh->m_ppPassengers[i] == ent )
01221 {
01222 #ifdef QAGAME
01223
01224 if ( ((gentity_t *)pVeh->m_ppPassengers[i])->client )
01225 {
01226 ((gentity_t *)pVeh->m_ppPassengers[i])->client->ps.generic1 = 0;
01227 }
01228 #endif
01229 pVeh->m_ppPassengers[i] = NULL;
01230 pVeh->m_iNumPassengers--;
01231 break;
01232 }
01233 }
01234
01235
01236 if ( i == pVeh->m_pVehicleInfo->maxPassengers )
01237 {
01238 return false;
01239 }
01240 }
01241
01242 #ifdef _JK2MP //I hate adding these!
01243 if (!taintedRider)
01244 {
01245 #endif
01246 if ( pVeh->m_pVehicleInfo->hideRider )
01247 {
01248 pVeh->m_pVehicleInfo->UnGhost( pVeh, (bgEntity_t *)ent );
01249 }
01250 #ifdef _JK2MP
01251 }
01252 #endif
01253
01254
01255 if ( pVeh->m_pPilot == NULL )
01256 {
01257 #ifdef _JK2MP
01258 parent->client->ps.loopSound = parent->s.loopSound = 0;
01259 #else
01260 parent->s.loopSound = 0;
01261 #endif
01262
01263 if ( pVeh->m_iNumPassengers == 0 )
01264 {
01265 #ifdef _JK2MP
01266 parent->client->ps.m_iVehicleNum = 0;
01267 #else
01268 parent->s.m_iVehicleNum = 0;
01269 #endif
01270 }
01271 }
01272
01273 #ifdef _JK2MP
01274 if (taintedRider)
01275 {
01276 pVeh->m_iBoarding = level.time + 1000;
01277 return true;
01278 }
01279 #endif
01280
01281
01282 #ifdef _JK2MP
01283 ent->client->ps.m_iVehicleNum = 0;
01284 ent->r.ownerNum = ENTITYNUM_NONE;
01285 ent->s.owner = ent->r.ownerNum;
01286
01287 ent->client->ps.viewangles[PITCH] = 0.0f;
01288 ent->client->ps.viewangles[ROLL] = 0.0f;
01289 ent->client->ps.viewangles[YAW] = pVeh->m_vOrientation[YAW];
01290 SetClientViewAngle(ent, ent->client->ps.viewangles);
01291
01292 if (ent->client->solidHack)
01293 {
01294 ent->client->solidHack = 0;
01295 ent->r.contents = CONTENTS_BODY;
01296 }
01297 #else
01298 ent->owner = NULL;
01299 #endif
01300 ent->s.m_iVehicleNum = 0;
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313 #ifndef _JK2MP
01314 VectorCopy( pVeh->m_vOrientation, vPlayerDir );
01315 vPlayerDir[ROLL] = 0;
01316 SetClientViewAngle( ent, vPlayerDir );
01317 #endif
01318
01319
01320 if ( ent->client->ps.weapon == WP_NONE )
01321 {
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346 }
01347 else
01348 {
01349
01350
01351
01352 }
01353
01354
01355
01356
01357
01358
01359 #ifdef _JK2MP
01360 BG_SetLegsAnimTimer( &ent->client->ps, 0 );
01361 BG_SetTorsoAnimTimer( &ent->client->ps, 0 );
01362 #else
01363 PM_SetLegsAnimTimer( ent, &ent->client->ps.legsAnimTimer, 0 );
01364 PM_SetTorsoAnimTimer( ent, &ent->client->ps.torsoAnimTimer, 0 );
01365 #endif
01366
01367
01368 pVeh->m_iBoarding = level.time + 1000;
01369
01370 return true;
01371 }
01372
01373
01374 bool EjectAll( Vehicle_t *pVeh )
01375 {
01376
01377
01378 pVeh->m_EjectDir = VEH_EJECT_TOP;
01379
01380 pVeh->m_iBoarding = 0;
01381 pVeh->m_bWasBoarding = false;
01382
01383
01384 if ( pVeh->m_pPilot )
01385 {
01386 #ifdef QAGAME
01387 gentity_t *pilot = (gentity_t*)pVeh->m_pPilot;
01388 #endif
01389 pVeh->m_pVehicleInfo->Eject( pVeh, pVeh->m_pPilot, qtrue );
01390 #ifdef QAGAME
01391 if ( pVeh->m_pVehicleInfo->killRiderOnDeath && pilot )
01392 {
01393
01394 G_MuteSound(pilot->s.number, CHAN_VOICE);
01395 G_Damage( pilot, NULL, NULL, NULL, pilot->s.origin, 10000, 0, MOD_SUICIDE );
01396 }
01397 #endif
01398 }
01399 if ( pVeh->m_pOldPilot )
01400 {
01401 #ifdef QAGAME
01402 gentity_t *pilot = (gentity_t*)pVeh->m_pOldPilot;
01403 #endif
01404 pVeh->m_pVehicleInfo->Eject( pVeh, pVeh->m_pOldPilot, qtrue );
01405 #ifdef QAGAME
01406 if ( pVeh->m_pVehicleInfo->killRiderOnDeath && pilot )
01407 {
01408
01409 G_MuteSound(pilot->s.number, CHAN_VOICE);
01410 G_Damage( pilot, NULL, NULL, NULL, pilot->s.origin, 10000, 0, MOD_SUICIDE );
01411 }
01412 #endif
01413 }
01414 if ( pVeh->m_iNumPassengers )
01415 {
01416 int i;
01417
01418 for ( i = 0; i < pVeh->m_pVehicleInfo->maxPassengers; i++ )
01419 {
01420 if ( pVeh->m_ppPassengers[i] )
01421 {
01422 #ifdef QAGAME
01423 gentity_t *rider = (gentity_t*)pVeh->m_ppPassengers[i];
01424 #endif
01425 pVeh->m_pVehicleInfo->Eject( pVeh, pVeh->m_ppPassengers[i], qtrue );
01426 #ifdef QAGAME
01427 if ( pVeh->m_pVehicleInfo->killRiderOnDeath && rider )
01428 {
01429
01430 G_MuteSound(rider->s.number, CHAN_VOICE);
01431 G_Damage( rider, NULL, NULL, NULL, rider->s.origin, 10000, 0, MOD_SUICIDE );
01432 }
01433 #endif
01434 }
01435 }
01436 pVeh->m_iNumPassengers = 0;
01437 }
01438
01439 if ( pVeh->m_pDroidUnit )
01440 {
01441 G_EjectDroidUnit( pVeh, pVeh->m_pVehicleInfo->killRiderOnDeath );
01442 }
01443
01444 return true;
01445 }
01446
01447
01448 static void StartDeathDelay( Vehicle_t *pVeh, int iDelayTimeOverride )
01449 {
01450 gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
01451
01452 if ( iDelayTimeOverride )
01453 {
01454 pVeh->m_iDieTime = level.time + iDelayTimeOverride;
01455 }
01456 else
01457 {
01458 pVeh->m_iDieTime = level.time + pVeh->m_pVehicleInfo->explosionDelay;
01459 }
01460
01461 #ifdef _JK2MP
01462 if ( pVeh->m_pVehicleInfo->flammable )
01463 {
01464 parent->client->ps.loopSound = parent->s.loopSound = G_SoundIndex( "sound/vehicles/common/fire_lp.wav" );
01465 }
01466 #else
01467
01468
01469 if (pVeh->m_pVehicleInfo->iArmorGoneFX)
01470 {
01471 if (!(pVeh->m_ulFlags&VEH_ARMORGONE) && (pVeh->m_iArmor <= 0))
01472 {
01473 pVeh->m_ulFlags |= VEH_ARMORGONE;
01474 G_PlayEffect(pVeh->m_pVehicleInfo->iArmorGoneFX, parent->playerModel, parent->crotchBolt, parent->s.number, parent->currentOrigin, 1, qtrue);
01475 parent->s.loopSound = G_SoundIndex( "sound/vehicles/common/fire_lp.wav" );
01476 }
01477 }
01478 #endif
01479 }
01480
01481
01482 static void DeathUpdate( Vehicle_t *pVeh )
01483 {
01484 gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
01485
01486 if ( level.time >= pVeh->m_iDieTime )
01487 {
01488
01489 if ( pVeh->m_pVehicleInfo->Inhabited( pVeh ) )
01490 {
01491 #ifndef _JK2MP
01492 if (pVeh->m_pPilot)
01493 {
01494 pVeh->m_pPilot->client->noRagTime = -1;
01495 }
01496 #endif
01497
01498 pVeh->m_pVehicleInfo->EjectAll( pVeh );
01499 #ifdef _JK2MP
01500 if ( pVeh->m_pVehicleInfo->Inhabited( pVeh ) )
01501 {
01502 if ( pVeh->m_pPilot )
01503 {
01504
01505 G_Damage((gentity_t *)pVeh->m_pPilot, (gentity_t *)pVeh->m_pParentEntity, (gentity_t *)pVeh->m_pParentEntity,
01506 NULL, pVeh->m_pParentEntity->playerState->origin, 999, DAMAGE_NO_PROTECTION, MOD_EXPLOSIVE);
01507 }
01508 if ( pVeh->m_iNumPassengers )
01509 {
01510 int i;
01511
01512 for ( i = 0; i < pVeh->m_pVehicleInfo->maxPassengers; i++ )
01513 {
01514 if ( pVeh->m_ppPassengers[i] )
01515 {
01516
01517 G_Damage((gentity_t *)pVeh->m_ppPassengers[i], (gentity_t *)pVeh->m_pParentEntity, (gentity_t *)pVeh->m_pParentEntity,
01518 NULL, pVeh->m_pParentEntity->playerState->origin, 999, DAMAGE_NO_PROTECTION, MOD_EXPLOSIVE);
01519 }
01520 }
01521 }
01522 }
01523 #endif
01524 }
01525
01526 if ( !pVeh->m_pVehicleInfo->Inhabited( pVeh ) )
01527 {
01528 vec3_t lMins, lMaxs, bottom;
01529 trace_t trace;
01530
01531
01532 #ifndef _JK2MP
01533
01534
01535 if (pVeh->m_pVehicleInfo->iExhaustFX)
01536 {
01537 for (int i=0; (i<MAX_VEHICLE_EXHAUSTS && pVeh->m_iExhaustTag[i]!=-1); i++)
01538 {
01539 G_StopEffect(pVeh->m_pVehicleInfo->iExhaustFX, parent->playerModel, pVeh->m_iExhaustTag[i], parent->s.number);
01540 }
01541 }
01542 if (pVeh->m_pVehicleInfo->iArmorLowFX)
01543 {
01544 G_StopEffect(pVeh->m_pVehicleInfo->iArmorLowFX, parent->playerModel, parent->crotchBolt, parent->s.number);
01545 }
01546 if (pVeh->m_pVehicleInfo->iArmorGoneFX)
01547 {
01548 G_StopEffect(pVeh->m_pVehicleInfo->iArmorGoneFX, parent->playerModel, parent->crotchBolt, parent->s.number);
01549 }
01550
01551 #endif
01552 if ( pVeh->m_pVehicleInfo->iExplodeFX )
01553 {
01554 #ifdef _JK2MP
01555 vec3_t fxAng;
01556
01557 VectorSet(fxAng, -90.0f, 0.0f, 0.0f);
01558 G_PlayEffectID( pVeh->m_pVehicleInfo->iExplodeFX, parent->currentOrigin, fxAng );
01559 #else
01560 G_PlayEffect( pVeh->m_pVehicleInfo->iExplodeFX, parent->currentOrigin, vec3_origin );
01561 #endif
01562
01563 VectorCopy( parent->currentOrigin, bottom );
01564 bottom[2] -= 80;
01565 G_VehicleTrace( &trace, parent->currentOrigin, vec3_origin, vec3_origin, bottom, parent->s.number, CONTENTS_SOLID );
01566 if ( trace.fraction < 1.0f )
01567 {
01568 VectorCopy( trace.endpos, bottom );
01569 bottom[2] += 2;
01570 #ifdef _JK2MP
01571 VectorSet(fxAng, -90.0f, 0.0f, 0.0f);
01572 G_PlayEffectID( G_EffectIndex("ships/ship_explosion_mark"), trace.endpos, fxAng );
01573 #else
01574 G_PlayEffect( "ships/ship_explosion_mark", trace.endpos );
01575 #endif
01576 }
01577 }
01578
01579 parent->takedamage = qfalse;
01580 if ( pVeh->m_pVehicleInfo->explosionRadius > 0 && pVeh->m_pVehicleInfo->explosionDamage > 0 )
01581 {
01582 VectorCopy( parent->mins, lMins );
01583 lMins[2] = -4;
01584 VectorCopy( parent->maxs, lMaxs );
01585 VectorCopy( parent->currentOrigin, bottom );
01586 bottom[2] += parent->mins[2] - 32;
01587 G_VehicleTrace( &trace, parent->currentOrigin, lMins, lMaxs, bottom, parent->s.number, CONTENTS_SOLID );
01588 #ifdef _JK2MP
01589 G_RadiusDamage( trace.endpos, NULL, pVeh->m_pVehicleInfo->explosionDamage, pVeh->m_pVehicleInfo->explosionRadius, NULL, NULL, MOD_EXPLOSIVE );
01590 #else
01591 G_RadiusDamage( trace.endpos, NULL, pVeh->m_pVehicleInfo->explosionDamage, pVeh->m_pVehicleInfo->explosionRadius, NULL, MOD_EXPLOSIVE );
01592 #endif
01593 }
01594
01595 #ifdef _JK2MP
01596 parent->think = G_FreeEntity;
01597 #else
01598 parent->e_ThinkFunc = thinkF_G_FreeEntity;
01599 #endif
01600 parent->nextthink = level.time + FRAMETIME;
01601 }
01602 }
01603 #ifndef _JK2MP
01604 else
01605 {
01606 if ( !Q_irand( 0, 10 ) )
01607 {
01608 AddSoundEvent( parent, parent->currentOrigin, 512, AEL_DANGER );
01609 AddSightEvent( parent, parent->currentOrigin, 512, AEL_DANGER, 100 );
01610 }
01611 }
01612 #endif
01613 }
01614
01615
01616 void RegisterAssets( Vehicle_t *pVeh )
01617 {
01618 }
01619
01620 extern void ChangeWeapon( gentity_t *ent, int newWeapon );
01621
01622
01623 bool Initialize( Vehicle_t *pVeh )
01624 {
01625 gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
01626 int i = 0;
01627
01628 if ( !parent || !parent->client )
01629 return false;
01630
01631 #ifdef _JK2MP
01632 parent->client->ps.m_iVehicleNum = 0;
01633 #endif
01634 parent->s.m_iVehicleNum = 0;
01635 {
01636 pVeh->m_iArmor = pVeh->m_pVehicleInfo->armor;
01637 parent->client->pers.maxHealth = parent->client->ps.stats[STAT_MAX_HEALTH] = parent->NPC->stats.health = parent->health = parent->client->ps.stats[STAT_HEALTH] = pVeh->m_iArmor;
01638 pVeh->m_iShields = pVeh->m_pVehicleInfo->shields;
01639 #ifdef _JK2MP
01640 G_VehUpdateShields( parent );
01641 #endif
01642 parent->client->ps.stats[STAT_ARMOR] = pVeh->m_iShields;
01643 }
01644 parent->mass = pVeh->m_pVehicleInfo->mass;
01645
01646 for ( i = 0; i < MAX_VEHICLE_WEAPONS; i++ )
01647 {
01648 parent->client->ps.ammo[i] = pVeh->weaponStatus[i].ammo = pVeh->m_pVehicleInfo->weapon[i].ammoMax;
01649 }
01650 for ( i = 0; i < MAX_VEHICLE_TURRETS; i++ )
01651 {
01652 pVeh->turretStatus[i].nextMuzzle = (pVeh->m_pVehicleInfo->turret[i].iMuzzle[i]-1);
01653 parent->client->ps.ammo[MAX_VEHICLE_WEAPONS+i] = pVeh->turretStatus[i].ammo = pVeh->m_pVehicleInfo->turret[i].iAmmoMax;
01654 if ( pVeh->m_pVehicleInfo->turret[i].bAI )
01655 {
01656 pVeh->turretStatus[i].enemyEntNum = ENTITYNUM_NONE;
01657 }
01658 }
01659
01660 parent->client->ps.speed = 0;
01661
01662 VectorClear( pVeh->m_vOrientation );
01663 pVeh->m_vOrientation[YAW] = parent->s.angles[YAW];
01664
01665 #ifdef _JK2MP
01666 if ( pVeh->m_pVehicleInfo->gravity &&
01667 pVeh->m_pVehicleInfo->gravity != g_gravity.value )
01668 {
01669 if ( parent->NPC )
01670 {
01671 parent->NPC->aiFlags |= NPCAI_CUSTOM_GRAVITY;
01672 }
01673 parent->client->ps.gravity = pVeh->m_pVehicleInfo->gravity;
01674 }
01675 #else
01676 if ( pVeh->m_pVehicleInfo->gravity &&
01677 pVeh->m_pVehicleInfo->gravity != g_gravity->value )
01678 {
01679 parent->svFlags |= SVF_CUSTOM_GRAVITY;
01680 parent->client->ps.gravity = pVeh->m_pVehicleInfo->gravity;
01681 }
01682 #endif
01683
01684 if ( pVeh->m_pVehicleInfo->maxPassengers > 0 )
01685 {
01686 int i;
01687
01688
01689 #ifndef _JK2MP //this is kind of silly if you ask me, I'm just using a static pointer array
01690 pVeh->m_ppPassengers = (gentity_t**)G_Alloc ( sizeof(gentity_t*) * pVeh->m_pVehicleInfo->maxPassengers );
01691 #endif
01692 for ( i = 0; i < pVeh->m_pVehicleInfo->maxPassengers; i++ )
01693 {
01694 pVeh->m_ppPassengers[i] = NULL;
01695 }
01696 }
01697
01698 pVeh->m_iNumPassengers = 0;
01699
01700
01701
01702
01703
01704
01705
01706
01707 {
01708 pVeh->m_ulFlags = 0;
01709 }
01710 pVeh->m_fTimeModifier = 1.0f;
01711 pVeh->m_iBoarding = 0;
01712 pVeh->m_bWasBoarding = false;
01713 pVeh->m_pOldPilot = NULL;
01714 VectorClear(pVeh->m_vBoardingVelocity);
01715 pVeh->m_pPilot = NULL;
01716 memset( &pVeh->m_ucmd, 0, sizeof( usercmd_t ) );
01717 pVeh->m_iDieTime = 0;
01718 pVeh->m_EjectDir = VEH_EJECT_LEFT;
01719
01720
01721
01722
01723
01724
01725
01726
01727 memset( pVeh->m_iExhaustTag, -1, sizeof( int ) * MAX_VEHICLE_EXHAUSTS );
01728 memset( pVeh->m_iMuzzleTag, -1, sizeof( int ) * MAX_VEHICLE_MUZZLES );
01729
01730 #ifndef _JK2MP //blargh, fixme
01731 memset( pVeh->m_Muzzles, 0, sizeof( Muzzle ) * MAX_VEHICLE_MUZZLES );
01732 #endif
01733 pVeh->m_iDroidUnitTag = -1;
01734
01735
01736 parent->client->ps.weapon = WP_BLASTER;
01737 parent->client->ps.weaponstate = WEAPON_READY;
01738 parent->client->ps.stats[STAT_WEAPONS] |= (1<<WP_BLASTER);
01739
01740
01741 {
01742 int iFlags = SETANIM_FLAG_NORMAL, iBlend = 300;
01743 #ifdef _JK2MP
01744 pVeh->m_ulFlags |= VEH_GEARSOPEN;
01745 BG_SetAnim(pVeh->m_pParentEntity->playerState,
01746 bgAllAnims[pVeh->m_pParentEntity->localAnimIndex].anims,
01747 SETANIM_BOTH, BOTH_VS_IDLE, iFlags, iBlend);
01748 #else
01749 NPC_SetAnim( pVeh->m_pParentEntity, SETANIM_BOTH, BOTH_VS_IDLE, iFlags, iBlend );
01750 #endif
01751 }
01752
01753 return true;
01754 }
01755
01756
01757 #ifdef _JK2MP
01758 void G_VehicleDamageBoxSizing(Vehicle_t *pVeh);
01759 #endif
01760 static bool Update( Vehicle_t *pVeh, const usercmd_t *pUmcd )
01761 {
01762 gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
01763 gentity_t *pilotEnt;
01764
01765 vec3_t vVehAngles;
01766 int i;
01767 int prevSpeed;
01768 int nextSpeed;
01769 int curTime;
01770 int halfMaxSpeed;
01771 playerState_t *parentPS;
01772 qboolean linkHeld = qfalse;
01773
01774
01775 #ifdef _JK2MP
01776 parentPS = pVeh->m_pParentEntity->playerState;
01777 #else
01778 parentPS = &pVeh->m_pParentEntity->client->ps;
01779 #endif
01780
01781 #ifndef _JK2MP//SP
01782 curTime = level.time;
01783 #elif QAGAME//MP GAME
01784 curTime = level.time;
01785 #elif CGAME//MP CGAME
01786
01787 curTime = pm->cmd.serverTime;
01788 #endif
01789
01790
01791 for ( i = 0; i < MAX_VEHICLE_WEAPONS; i++ )
01792 {
01793 if ( pVeh->m_pVehicleInfo->weapon[i].ID > VEH_WEAPON_BASE
01794 && pVeh->m_pVehicleInfo->weapon[i].ammoRechargeMS
01795 && pVeh->weaponStatus[i].ammo < pVeh->m_pVehicleInfo->weapon[i].ammoMax
01796 && pUmcd->serverTime-pVeh->weaponStatus[i].lastAmmoInc >= pVeh->m_pVehicleInfo->weapon[i].ammoRechargeMS )
01797 {
01798 pVeh->weaponStatus[i].lastAmmoInc = pUmcd->serverTime;
01799 pVeh->weaponStatus[i].ammo++;
01800
01801 if ( parent && parent->client )
01802 {
01803 parent->client->ps.ammo[i] = pVeh->weaponStatus[i].ammo;
01804 }
01805 }
01806 }
01807 for ( i = 0; i < MAX_VEHICLE_TURRETS; i++ )
01808 {
01809 if ( pVeh->m_pVehicleInfo->turret[i].iWeapon > VEH_WEAPON_BASE
01810 && pVeh->m_pVehicleInfo->turret[i].iAmmoRechargeMS
01811 && pVeh->turretStatus[i].ammo < pVeh->m_pVehicleInfo->turret[i].iAmmoMax
01812 && pUmcd->serverTime-pVeh->turretStatus[i].lastAmmoInc >= pVeh->m_pVehicleInfo->turret[i].iAmmoRechargeMS )
01813 {
01814 pVeh->turretStatus[i].lastAmmoInc = pUmcd->serverTime;
01815 pVeh->turretStatus[i].ammo++;
01816
01817 if ( parent && parent->client )
01818 {
01819 parent->client->ps.ammo[MAX_VEHICLE_WEAPONS+i] = pVeh->turretStatus[i].ammo;
01820 }
01821 }
01822 }
01823
01824
01825 if ( pVeh->m_pVehicleInfo->shieldRechargeMS
01826 && parentPS->stats[STAT_ARMOR] > 0
01827 && parentPS->stats[STAT_ARMOR] < pVeh->m_pVehicleInfo->shields
01828 && pUmcd->serverTime-pVeh->lastShieldInc >= pVeh->m_pVehicleInfo->shieldRechargeMS )
01829 {
01830 parentPS->stats[STAT_ARMOR]++;
01831 if ( parentPS->stats[STAT_ARMOR] > pVeh->m_pVehicleInfo->shields )
01832 {
01833 parentPS->stats[STAT_ARMOR] = pVeh->m_pVehicleInfo->shields;
01834 }
01835 pVeh->m_iShields = parentPS->stats[STAT_ARMOR];
01836 #ifdef _JK2MP
01837 G_VehUpdateShields( parent );
01838 #endif
01839 }
01840
01841 #ifdef _JK2MP //sometimes this gets out of whack, probably init'ing
01842 if (parent && parent->r.ownerNum != parent->s.owner)
01843 {
01844 parent->s.owner = parent->r.ownerNum;
01845 }
01846
01847
01848 if (pVeh->m_iBoarding)
01849 {
01850 parent->client->ps.vehBoarding = qtrue;
01851 }
01852 else
01853 {
01854 parent->client->ps.vehBoarding = qfalse;
01855 }
01856 #endif
01857
01858
01859 if ( pVeh->m_iDieTime != 0
01860 #ifndef _JK2MP //sometimes this gets out of whack, probably init'ing
01861 || (parent->health <= 0)
01862 #endif
01863 )
01864 {
01865
01866 VectorCopy( pVeh->m_vOrientation, pVeh->m_vPrevOrientation );
01867
01868
01869 pVeh->m_pVehicleInfo->ProcessOrientCommands( pVeh );
01870
01871 SetClientViewAngle( parent, pVeh->m_vOrientation );
01872 if ( pVeh->m_pPilot )
01873 {
01874 SetClientViewAngle( (gentity_t *)pVeh->m_pPilot, pVeh->m_vOrientation );
01875 }
01876
01877
01878
01879
01880
01881
01882
01883
01884
01885
01886
01887 pVeh->m_pVehicleInfo->ProcessMoveCommands( pVeh );
01888
01889
01890 if ( pVeh->m_pVehicleInfo->type == VH_FIGHTER )
01891 {
01892 AngleVectors( pVeh->m_vOrientation, parent->client->ps.moveDir, NULL, NULL );
01893 }
01894 else
01895 {
01896 VectorSet(vVehAngles, 0, pVeh->m_vOrientation[YAW], 0);
01897 AngleVectors( vVehAngles, parent->client->ps.moveDir, NULL, NULL );
01898 }
01899 pVeh->m_pVehicleInfo->DeathUpdate( pVeh );
01900 return false;
01901 }
01902
01903
01904 #ifdef _JK2MP
01905 else if ( parent->health <= 0 )
01906 {
01907
01908 if (pVeh->m_pVehicleInfo->type == VH_FIGHTER &&
01909 pVeh->m_iLastImpactDmg > 500)
01910 {
01911 pVeh->m_pVehicleInfo->StartDeathDelay( pVeh, -1);
01912 }
01913 else
01914 {
01915 pVeh->m_pVehicleInfo->StartDeathDelay( pVeh, 0 );
01916 }
01917 pVeh->m_pVehicleInfo->DeathUpdate( pVeh );
01918 return false;
01919 }
01920 #endif
01921
01922 #ifdef _JK2MP //special check in case someone disconnects/dies while boarding
01923 #ifdef QAGAME
01924 if (parent->spawnflags & 1)
01925 {
01926 if (pVeh->m_pPilot || !pVeh->m_bHasHadPilot)
01927 {
01928 if (pVeh->m_pPilot && !pVeh->m_bHasHadPilot)
01929 {
01930 pVeh->m_bHasHadPilot = qtrue;
01931 pVeh->m_iPilotLastIndex = pVeh->m_pPilot->s.number;
01932 }
01933 pVeh->m_iPilotTime = level.time + parent->damage;
01934 }
01935 else if (pVeh->m_iPilotTime)
01936 {
01937 gentity_t *oldPilot = &g_entities[pVeh->m_iPilotLastIndex];
01938
01939 if (!oldPilot->inuse || !oldPilot->client ||
01940 oldPilot->client->pers.connected != CON_CONNECTED)
01941 {
01942 G_Damage(parent, parent, parent, NULL, parent->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, MOD_SUICIDE);
01943 }
01944 else
01945 {
01946 vec3_t v;
01947 VectorSubtract(parent->client->ps.origin, oldPilot->client->ps.origin, v);
01948
01949 if (VectorLength(v) < parent->speed)
01950 {
01951 pVeh->m_iPilotTime = level.time + parent->damage;
01952 }
01953 else if (pVeh->m_iPilotTime < level.time)
01954 {
01955 G_Damage(parent, parent, parent, NULL, parent->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, MOD_SUICIDE);
01956 }
01957 }
01958 }
01959 }
01960 #endif
01961 #else
01962 if (parent->spawnflags & 1)
01963 {
01964 if (pVeh->m_iPilotTime < level.time)
01965 {
01966 if ( !player || G_ClearLineOfSight(pVeh->m_pParentEntity->currentOrigin, player->currentOrigin, pVeh->m_pParentEntity->s.number, MASK_OPAQUE ) )
01967 {
01968 pVeh->m_iPilotTime = level.time + pVeh->m_pParentEntity->endFrame;
01969 }
01970 }
01971 if (pVeh->m_iPilotTime && pVeh->m_iPilotTime < level.time)
01972 {
01973
01974 G_Damage(parent, parent, parent, NULL, parent->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, MOD_SUICIDE);
01975 }
01976 }
01977 #endif
01978
01979 #ifndef _JK2MP
01980
01981
01982 {
01983 vec3_t dir;
01984 vec3_t projectedPosition;
01985 VectorCopy(parent->client->ps.velocity, dir);
01986 VectorMA(parent->currentOrigin, 0.1f, dir, projectedPosition);
01987
01988 float force = VectorNormalize(dir);
01989 force /= 10.0f;
01990 if (force>30.0f)
01991 {
01992 trace_t tr;
01993 G_VehicleTrace(&tr, parent->currentOrigin, parent->mins, parent->maxs, projectedPosition, parent->s.number, CONTENTS_BODY);
01994 if (tr.fraction<1.0f &&
01995 !tr.allsolid &&
01996 !tr.startsolid &&
01997 tr.entityNum!=ENTITYNUM_NONE &&
01998 tr.entityNum!=ENTITYNUM_WORLD &&
01999 (level.time<pVeh->m_iTurboTime || Q_irand(0,3)==0))
02000 {
02001 gentity_t* other = &g_entities[tr.entityNum];
02002 if (other && other->client && !other->s.m_iVehicleNum)
02003 {
02004 G_Throw( other, dir, force/10.0f );
02005 G_Knockdown( other, parent, dir, force, qtrue );
02006 G_Damage( other, parent, parent, parent->client->ps.velocity, parent->currentOrigin, force, DAMAGE_NO_ARMOR|DAMAGE_EXTRA_KNOCKBACK, MOD_IMPACT);
02007 }
02008 }
02009 }
02010 }
02011 #endif
02012
02013 #ifdef _JK2MP //special check in case someone disconnects/dies while boarding
02014 if (pVeh->m_iBoarding != 0)
02015 {
02016 pilotEnt = (gentity_t *)pVeh->m_pPilot;
02017 if (pilotEnt)
02018 {
02019 if (!pilotEnt->inuse || !pilotEnt->client || pilotEnt->health <= 0 ||
02020 pilotEnt->client->pers.connected != CON_CONNECTED)
02021 {
02022 pVeh->m_pVehicleInfo->Eject( pVeh, pVeh->m_pPilot, qtrue );
02023 return false;
02024 }
02025 }
02026 }
02027 #endif
02028
02029
02030 if ( pVeh->m_iBoarding != 0 )
02031 {
02032 if (!pVeh->m_bWasBoarding)
02033 {
02034 VectorCopy(parentPS->velocity, pVeh->m_vBoardingVelocity);
02035 pVeh->m_bWasBoarding = true;
02036 }
02037
02038
02039 if ( pVeh->m_iBoarding > -1 && pVeh->m_iBoarding <= level.time )
02040 {
02041 pVeh->m_bWasBoarding = false;
02042 pVeh->m_iBoarding = 0;
02043 }
02044 else
02045 {
02046 #ifdef _JK2MP
02047 goto maintainSelfDuringBoarding;
02048 #else
02049 return false;
02050 #endif
02051 }
02052 }
02053
02054 parent = (gentity_t *)pVeh->m_pParentEntity;
02055
02056
02057 if ( !parent || !parent->client || parent->health <= 0 )
02058 return false;
02059
02060
02061 if ( pVeh->m_pPilot )
02062 {
02063 pilotEnt = (gentity_t *)pVeh->m_pPilot;
02064
02065 #ifdef _JK2MP
02066 if (!pilotEnt->inuse || !pilotEnt->client || pilotEnt->health <= 0 ||
02067 pilotEnt->client->pers.connected != CON_CONNECTED)
02068 #else
02069 if (pilotEnt->health <= 0)
02070 #endif
02071 {
02072 pVeh->m_pVehicleInfo->Eject( pVeh, pVeh->m_pPilot, qtrue );
02073 }
02074 }
02075
02076 if ( pVeh->m_iNumPassengers > 0 )
02077 {
02078 gentity_t *psngr;
02079
02080 for ( i = 0; i < pVeh->m_pVehicleInfo->maxPassengers; i++ )
02081 {
02082 psngr = (gentity_t *)pVeh->m_ppPassengers[i];
02083
02084 #ifdef _JK2MP
02085 if ( psngr &&
02086 (!psngr->inuse || !psngr->client || psngr->health <= 0 || psngr->client->pers.connected != CON_CONNECTED) )
02087 #else
02088 if ( psngr && psngr->health <= 0 )
02089 #endif
02090 {
02091 pVeh->m_pVehicleInfo->Eject( pVeh, pVeh->m_ppPassengers[i], qtrue );
02092 pVeh->m_iNumPassengers--;
02093 }
02094 }
02095 }
02096
02097 #ifdef _JK2MP
02098
02099 memcpy( &parent->client->pers.cmd, &pVeh->m_ucmd, sizeof( usercmd_t ) );
02100 pVeh->m_ucmd.buttons &= ~(BUTTON_TALK);
02101 #else
02102
02103 memcpy( &pVeh->m_ucmd, pUmcd, sizeof( usercmd_t ) );
02104 memcpy( &parent->client->pers.lastCommand, pUmcd, sizeof( usercmd_t ) );
02105 #endif
02106
02107
02108
02109
02110
02111
02112
02113
02114
02115
02116
02117
02118
02119
02120
02121
02122
02123
02124 for ( i = 0; i < MAX_VEHICLE_WEAPONS; i++ )
02125 {
02126 if ( pVeh->m_pVehicleInfo->weapon[i].linkable == 2 )
02127 {
02128
02129 if ( !pVeh->weaponStatus[i].linked )
02130 {
02131 pVeh->weaponStatus[i].linked = qtrue;
02132 }
02133 }
02134 #ifdef _JK2MP
02135 else if ( (pVeh->m_ucmd.buttons&BUTTON_USE_HOLDABLE) )
02136 #else
02137
02138 else if ( 0 )
02139 #endif
02140 {
02141 playerState_t *pilotPS;
02142 #ifdef _JK2MP
02143 bgEntity_t *rider = NULL;
02144 if (parent->s.owner != ENTITYNUM_NONE)
02145 {
02146 rider = PM_BGEntForNum(parent->s.owner);
02147 }
02148 pilotPS = rider->playerState;
02149 #else
02150 gentity_t *rider = parent->owner;
02151 pilotPS = &rider->client->ps;
02152 #endif
02153 if ( !pVeh->linkWeaponToggleHeld )
02154 {
02155 if ( pVeh->m_pVehicleInfo->weapon[i].linkable == 1 )
02156 {
02157 pVeh->weaponStatus[i].linked = !pVeh->weaponStatus[i].linked;
02158 }
02159 }
02160 linkHeld = qtrue;
02161 }
02162 }
02163 if ( linkHeld )
02164 {
02165
02166 pVeh->linkWeaponToggleHeld = qtrue;
02167 }
02168 else
02169 {
02170
02171 pVeh->linkWeaponToggleHeld = qfalse;
02172 }
02173 #ifdef _JK2MP
02174
02175
02176 parentPS->vehWeaponsLinked = qfalse;
02177 for ( i = 0; i < MAX_VEHICLE_WEAPONS; i++ )
02178 {
02179 if ( pVeh->weaponStatus[i].linked )
02180 {
02181 parentPS->vehWeaponsLinked = qtrue;
02182 }
02183 }
02184 #endif
02185
02186 #ifdef QAGAME
02187 for ( i = 0; i < MAX_VEHICLE_TURRETS; i++ )
02188 {
02189 VEH_TurretThink( pVeh, parent, i );
02190 }
02191 #endif
02192
02193 #ifdef _JK2MP
02194 maintainSelfDuringBoarding:
02195
02196 if (pVeh->m_pPilot && pVeh->m_pPilot->playerState && pVeh->m_iBoarding != 0)
02197 {
02198 VectorCopy(pVeh->m_vOrientation, pVeh->m_pPilot->playerState->viewangles);
02199 pVeh->m_ucmd.buttons = 0;
02200 pVeh->m_ucmd.forwardmove = 0;
02201 pVeh->m_ucmd.rightmove = 0;
02202 pVeh->m_ucmd.upmove = 0;
02203 }
02204 #endif
02205
02206
02207 VectorCopy( pVeh->m_vOrientation, pVeh->m_vPrevOrientation );
02208
02209
02210 pVeh->m_pVehicleInfo->ProcessOrientCommands( pVeh );
02211
02212 SetClientViewAngle( parent, pVeh->m_vOrientation );
02213 if ( pVeh->m_pPilot )
02214 {
02215 #ifdef _JK2MP
02216 if ( !BG_UnrestrainedPitchRoll( pVeh->m_pPilot->playerState, pVeh ) )
02217 {
02218 vec3_t newVAngle;
02219 newVAngle[PITCH] = pVeh->m_pPilot->playerState->viewangles[PITCH];
02220 newVAngle[YAW] = pVeh->m_pPilot->playerState->viewangles[YAW];
02221 newVAngle[ROLL] = pVeh->m_vOrientation[ROLL];
02222 SetClientViewAngle( (gentity_t *)pVeh->m_pPilot, newVAngle );
02223 }
02224 #else
02225 if ( !BG_UnrestrainedPitchRoll( &pVeh->m_pPilot->client->ps, pVeh ) )
02226 {
02227 SetClientViewAngle( (gentity_t *)pVeh->m_pPilot, pVeh->m_vOrientation );
02228 }
02229 #endif
02230 }
02231
02232
02233
02234
02235
02236
02237
02238
02239
02240
02241
02242 prevSpeed = parentPS->speed;
02243 pVeh->m_pVehicleInfo->ProcessMoveCommands( pVeh );
02244 nextSpeed = parentPS->speed;
02245 halfMaxSpeed = pVeh->m_pVehicleInfo->speedMax*0.5f;
02246
02247
02248
02249
02250 if (pVeh->m_iTurboTime<curTime &&
02251 pVeh->m_iSoundDebounceTimer<curTime &&
02252 ((nextSpeed>prevSpeed && nextSpeed>halfMaxSpeed && prevSpeed<halfMaxSpeed) || (nextSpeed>halfMaxSpeed && !Q_irand(0,1000)))
02253 )
02254 {
02255 int shiftSound = Q_irand(1,4);
02256 switch (shiftSound)
02257 {
02258 case 1: shiftSound=pVeh->m_pVehicleInfo->soundShift1; break;
02259 case 2: shiftSound=pVeh->m_pVehicleInfo->soundShift2; break;
02260 case 3: shiftSound=pVeh->m_pVehicleInfo->soundShift3; break;
02261 case 4: shiftSound=pVeh->m_pVehicleInfo->soundShift4; break;
02262 }
02263 if (shiftSound)
02264 {
02265 pVeh->m_iSoundDebounceTimer = curTime + Q_irand(1000, 4000);
02266 #ifdef _JK2MP
02267
02268 #else
02269
02270 G_SoundIndexOnEnt( pVeh->m_pParentEntity, CHAN_AUTO, shiftSound);
02271 #endif
02272 }
02273 }
02274
02275
02276
02277
02278 if ( pVeh->m_pVehicleInfo->type == VH_FIGHTER )
02279 {
02280 AngleVectors( pVeh->m_vOrientation, parent->client->ps.moveDir, NULL, NULL );
02281 }
02282 else
02283 {
02284 VectorSet(vVehAngles, 0, pVeh->m_vOrientation[YAW], 0);
02285 AngleVectors( vVehAngles, parent->client->ps.moveDir, NULL, NULL );
02286 }
02287
02288 #ifdef _JK2MP
02289 if (pVeh->m_pVehicleInfo->surfDestruction)
02290 {
02291 if (pVeh->m_iRemovedSurfaces)
02292 {
02293 gentity_t *killer = parent;
02294 float dmg;
02295 G_VehicleDamageBoxSizing(pVeh);
02296
02297
02298 if (parent->client->ps.otherKiller < ENTITYNUM_WORLD &&
02299 parent->client->ps.otherKillerTime > level.time)
02300 {
02301 gentity_t *potentialKiller = &g_entities[parent->client->ps.otherKiller];
02302
02303 if (potentialKiller->inuse && potentialKiller->client)
02304 {
02305 killer = potentialKiller;
02306 }
02307 }
02308
02309
02310
02311 dmg = (float)parent->client->ps.stats[STAT_MAX_HEALTH] * pVeh->m_fTimeModifier / 180.0f;
02312 G_Damage(parent, killer, killer, NULL, parent->client->ps.origin, dmg, DAMAGE_NO_SELF_PROTECTION|DAMAGE_NO_HIT_LOC|DAMAGE_NO_PROTECTION|DAMAGE_NO_ARMOR, MOD_SUICIDE);
02313 }
02314
02315
02316 parent->client->ps.vehSurfaces = pVeh->m_iRemovedSurfaces;
02317 }
02318 #endif
02319
02320 #ifdef _JK2MP
02321
02322 if (pVeh->m_iBoarding)
02323 {
02324 parent->client->ps.vehBoarding = qtrue;
02325 }
02326 else
02327 {
02328 parent->client->ps.vehBoarding = qfalse;
02329 }
02330 #endif
02331
02332 #ifndef _JK2MP
02333
02334 if ( pVeh->m_pPilot )
02335 {
02336 parent->enemy = pVeh->m_pPilot->enemy;
02337 }
02338 #endif
02339
02340
02341 return true;
02342 }
02343
02344
02345
02346 static bool UpdateRider( Vehicle_t *pVeh, bgEntity_t *pRider, usercmd_t *pUmcd )
02347 {
02348 gentity_t *parent;
02349 gentity_t *rider;
02350
02351 if ( pVeh->m_iBoarding != 0 && pVeh->m_iDieTime==0)
02352 return true;
02353
02354 parent = (gentity_t *)pVeh->m_pParentEntity;
02355 rider = (gentity_t *)pRider;
02356 #ifdef _JK2MP
02357
02358 if ( rider && rider->client
02359 && parent && parent->client )
02360 {
02361 rider->client->ps.rocketLockIndex = parent->client->ps.rocketLockIndex;
02362 rider->client->ps.rocketLockTime = parent->client->ps.rocketLockTime;
02363 rider->client->ps.rocketTargetTime = parent->client->ps.rocketTargetTime;
02364 }
02365 #endif
02366
02367 if ( pUmcd->buttons & BUTTON_USE && pVeh->m_pVehicleInfo->type!=VH_SPEEDER)
02368 {
02369 if ( pVeh->m_pVehicleInfo->type == VH_WALKER )
02370 {
02371 pVeh->m_EjectDir = VEH_EJECT_REAR;
02372 if ( pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qfalse ) )
02373 return false;
02374 }
02375 else if ( !(pVeh->m_ulFlags & VEH_FLYING))
02376 {
02377
02378 if ((parent->client->ps.speed<=600) && pUmcd->rightmove!=0)
02379 {
02380 if ( pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qfalse ) )
02381 {
02382 animNumber_t Anim;
02383 int iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD | SETANIM_FLAG_HOLDLESS, iBlend = 300;
02384 if ( pUmcd->rightmove > 0 )
02385 {
02386 Anim = BOTH_ROLL_R;
02387 pVeh->m_EjectDir = VEH_EJECT_RIGHT;
02388 }
02389 else
02390 {
02391 Anim = BOTH_ROLL_L;
02392 pVeh->m_EjectDir = VEH_EJECT_LEFT;
02393 }
02394 VectorScale( parent->client->ps.velocity, 0.25f, rider->client->ps.velocity );
02395 #if 1
02396 Vehicle_SetAnim( rider, SETANIM_BOTH, Anim, iFlags, iBlend );
02397 #else
02398
02399 #endif
02400
02401 rider->client->ps.weaponTime = rider->client->ps.torsoAnimTimer - 200;
02402 G_AddEvent( rider, EV_ROLL, 0 );
02403 return false;
02404 }
02405 }
02406 else
02407 {
02408
02409 animNumber_t Anim;
02410 int iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD, iBlend = 500;
02411 if ( pUmcd->rightmove > 0 )
02412 {
02413 Anim = BOTH_VS_DISMOUNT_R;
02414 pVeh->m_EjectDir = VEH_EJECT_RIGHT;
02415 }
02416 else
02417 {
02418 Anim = BOTH_VS_DISMOUNT_L;
02419 pVeh->m_EjectDir = VEH_EJECT_LEFT;
02420 }
02421
02422 if ( pVeh->m_iBoarding <= 1 )
02423 {
02424 int iAnimLen;
02425
02426
02427 #ifdef _JK2MP
02428 iAnimLen = BG_AnimLength( rider->localAnimIndex, Anim );
02429 #else
02430 iAnimLen = PM_AnimLength( pRider->client->clientInfo.animFileIndex, Anim );
02431 #endif
02432 pVeh->m_iBoarding = level.time + iAnimLen;
02433
02434
02435 #ifdef _JK2MP
02436 rider->flags |= FL_VEH_BOARDING;
02437 #else
02438 rider->client->ps.eFlags |= EF_VEH_BOARDING;
02439 #endif
02440
02441
02442 rider->client->ps.weaponTime = iAnimLen;
02443 }
02444
02445 VectorScale( parent->client->ps.velocity, 0.25f, rider->client->ps.velocity );
02446
02447 Vehicle_SetAnim( rider, SETANIM_BOTH, Anim, iFlags, iBlend );
02448 }
02449 }
02450
02451 else
02452 {
02453 pVeh->m_EjectDir = VEH_EJECT_LEFT;
02454 if ( pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qfalse ) )
02455 return false;
02456 }
02457 }
02458
02459
02460 #ifdef _JK2MP
02461 if ( pVeh->m_iBoarding < level.time && (rider->flags & FL_VEH_BOARDING) )
02462 {
02463 rider->flags &= ~FL_VEH_BOARDING;
02464 #else
02465 if ( pVeh->m_iBoarding < level.time && (rider->client->ps.eFlags & EF_VEH_BOARDING) )
02466 {
02467 rider->client->ps.eFlags &= ~EF_VEH_BOARDING;
02468 #endif
02469
02470 if ( pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qfalse ) )
02471 {
02472 return false;
02473 }
02474 }
02475
02476 if ( pVeh->m_pVehicleInfo->type != VH_FIGHTER
02477 && pVeh->m_pVehicleInfo->type != VH_WALKER )
02478 {
02479
02480 if ( pUmcd->upmove > 0 )
02481 {
02482
02483
02484
02485 #ifndef _JK2MP
02486 float riderRightDot = G_CanJumpToEnemyVeh(pVeh, pUmcd);
02487 if (riderRightDot!=0.0f)
02488 {
02489
02490
02491 pVeh->m_EjectDir = VEH_EJECT_TOP;
02492 pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qtrue );
02493
02494
02495
02496 pVeh->m_pVehicleInfo->StartDeathDelay(pVeh, 10000);
02497 pVeh->m_ulFlags |= (VEH_OUTOFCONTROL);
02498 VectorScale(pVeh->m_pParentEntity->client->ps.velocity, 1.0f, pVeh->m_pParentEntity->pos3);
02499
02500
02501
02502 vec3_t toEnemy;
02503 VectorSubtract(pVeh->m_pParentEntity->currentOrigin, rider->enemy->currentOrigin, toEnemy);
02504 VectorNormalize(toEnemy);
02505 G_Throw(pVeh->m_pParentEntity, toEnemy, 50);
02506
02507
02508
02509 Vehicle_t* enemyVeh = G_IsRidingVehicle(rider->enemy);
02510 enemyVeh->m_iBoarding = (riderRightDot>0)?(VEH_MOUNT_THROW_RIGHT):(VEH_MOUNT_THROW_LEFT);
02511 enemyVeh->m_pVehicleInfo->Board(enemyVeh, rider);
02512 }
02513
02514
02515 else if (pUmcd->rightmove && (parent->client->ps.speed>=10))
02516 {
02517 return true;
02518 }
02519 #endif
02520
02521
02522 if ( pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qfalse ) )
02523 {
02524
02525 VectorScale( parent->client->ps.velocity, 0.5f, rider->client->ps.velocity );
02526 rider->client->ps.velocity[2] += JUMP_VELOCITY;
02527 #ifdef _JK2MP
02528 rider->client->ps.fd.forceJumpZStart = rider->client->ps.origin[2];
02529
02530 if (!trap_ICARUS_TaskIDPending(rider, TID_CHAN_VOICE))
02531 #else
02532 rider->client->ps.pm_flags |= ( PMF_JUMPING | PMF_JUMP_HELD );
02533 rider->client->ps.forceJumpZStart = rider->client->ps.origin[2];
02534
02535 if ( !Q3_TaskIDPending( rider, TID_CHAN_VOICE ) )
02536 #endif
02537 {
02538 G_AddEvent( rider, EV_JUMP, 0 );
02539 }
02540 #if 1
02541 Vehicle_SetAnim( rider, SETANIM_BOTH, BOTH_JUMP1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD, 300 );
02542 #else
02543
02544 #endif
02545 return false;
02546 }
02547 }
02548
02549
02550 if ( pUmcd->upmove < 0 )
02551 {
02552 animNumber_t Anim = BOTH_ROLL_B;
02553 pVeh->m_EjectDir = VEH_EJECT_REAR;
02554 if ( pUmcd->rightmove > 0 )
02555 {
02556 Anim = BOTH_ROLL_R;
02557 pVeh->m_EjectDir = VEH_EJECT_RIGHT;
02558 }
02559 else if ( pUmcd->rightmove < 0 )
02560 {
02561 Anim = BOTH_ROLL_L;
02562 pVeh->m_EjectDir = VEH_EJECT_LEFT;
02563 }
02564 else if ( pUmcd->forwardmove < 0 )
02565 {
02566 Anim = BOTH_ROLL_B;
02567 pVeh->m_EjectDir = VEH_EJECT_REAR;
02568 }
02569 else if ( pUmcd->forwardmove > 0 )
02570 {
02571 Anim = BOTH_ROLL_F;
02572 pVeh->m_EjectDir = VEH_EJECT_FRONT;
02573 }
02574
02575 if ( pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qfalse ) )
02576 {
02577 if ( !(pVeh->m_ulFlags & VEH_FLYING) )
02578 {
02579 VectorScale( parent->client->ps.velocity, 0.25f, rider->client->ps.velocity );
02580 #if 1
02581 Vehicle_SetAnim( rider, SETANIM_BOTH, Anim, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD | SETANIM_FLAG_HOLDLESS, 300 );
02582 #else
02583
02584 #endif
02585
02586 rider->client->ps.weaponTime = rider->client->ps.torsoAnimTimer - 200;
02587 G_AddEvent( rider, EV_ROLL, 0 );
02588 }
02589 return false;
02590 }
02591
02592 }
02593 }
02594
02595 return true;
02596 }
02597
02598 #ifdef _JK2MP //we want access to this one clientside, but it's the only
02599
02600 #include "../namespace_begin.h"
02601 extern void AttachRidersGeneric( Vehicle_t *pVeh );
02602 #include "../namespace_end.h"
02603 #endif
02604
02605
02606 static void AttachRiders( Vehicle_t *pVeh )
02607 {
02608 #ifdef _JK2MP
02609 int i = 0;
02610
02611 AttachRidersGeneric(pVeh);
02612
02613 if (pVeh->m_pPilot)
02614 {
02615 gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
02616 gentity_t *pilot = (gentity_t *)pVeh->m_pPilot;
02617 pilot->waypoint = parent->waypoint;
02618
02619
02620 G_SetOrigin( pilot, pilot->client->ps.origin );
02621 trap_LinkEntity( pilot );
02622 }
02623
02624 if (pVeh->m_pOldPilot)
02625 {
02626 gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
02627 gentity_t *oldpilot = (gentity_t *)pVeh->m_pOldPilot;
02628 oldpilot->waypoint = parent->waypoint;
02629
02630
02631 G_SetOrigin( oldpilot, oldpilot->client->ps.origin );
02632 trap_LinkEntity( oldpilot );
02633 }
02634
02635
02636 while (i < pVeh->m_iNumPassengers)
02637 {
02638 if (pVeh->m_ppPassengers[i])
02639 {
02640 mdxaBone_t boltMatrix;
02641 vec3_t yawOnlyAngles;
02642 gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
02643 gentity_t *pilot = (gentity_t *)pVeh->m_ppPassengers[i];
02644 int crotchBolt;
02645
02646 assert(parent->ghoul2);
02647 crotchBolt = trap_G2API_AddBolt(parent->ghoul2, 0, "*driver");
02648 assert(parent->client);
02649 assert(pilot->client);
02650
02651 VectorSet(yawOnlyAngles, 0, parent->client->ps.viewangles[YAW], 0);
02652
02653
02654 trap_G2API_GetBoltMatrix( parent->ghoul2, 0, crotchBolt, &boltMatrix,
02655 yawOnlyAngles, parent->client->ps.origin,
02656 level.time, NULL, parent->modelScale );
02657 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, pilot->client->ps.origin );
02658
02659 G_SetOrigin( pilot, pilot->client->ps.origin );
02660 trap_LinkEntity( pilot );
02661 }
02662 i++;
02663 }
02664
02665
02666 if (pVeh->m_pDroidUnit
02667 && pVeh->m_iDroidUnitTag != -1)
02668 {
02669 mdxaBone_t boltMatrix;
02670 vec3_t yawOnlyAngles, fwd;
02671 gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
02672 gentity_t *droid = (gentity_t *)pVeh->m_pDroidUnit;
02673
02674 assert(parent->ghoul2);
02675 assert(parent->client);
02676
02677
02678 if ( droid->client )
02679 {
02680 VectorSet(yawOnlyAngles, 0, parent->client->ps.viewangles[YAW], 0);
02681
02682
02683 trap_G2API_GetBoltMatrix( parent->ghoul2, 0, pVeh->m_iDroidUnitTag, &boltMatrix,
02684 yawOnlyAngles, parent->currentOrigin,
02685 level.time, NULL, parent->modelScale );
02686 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, droid->client->ps.origin );
02687 BG_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_Y, fwd );
02688 vectoangles( fwd, droid->client->ps.viewangles );
02689
02690 G_SetOrigin( droid, droid->client->ps.origin );
02691 G_SetAngles( droid, droid->client->ps.viewangles);
02692 SetClientViewAngle( droid, droid->client->ps.viewangles );
02693 trap_LinkEntity( droid );
02694
02695 if ( droid->NPC )
02696 {
02697 NPC_SetAnim( droid, SETANIM_BOTH, BOTH_STAND2, (SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD) );
02698 droid->client->ps.legsTimer = 500;
02699 droid->client->ps.torsoTimer = 500;
02700 }
02701 }
02702 }
02703 #else
02704
02705 if ( pVeh->m_pPilot )
02706 {
02707 gentity_t * const parent = pVeh->m_pParentEntity;
02708 gentity_t * const pilot = pVeh->m_pPilot;
02709 mdxaBone_t boltMatrix;
02710
02711 pilot->waypoint = parent->waypoint;
02712
02713
02714 gi.G2API_GetBoltMatrix( parent->ghoul2, parent->playerModel, parent->crotchBolt, &boltMatrix,
02715 pVeh->m_vOrientation, parent->currentOrigin,
02716 (cg.time?cg.time:level.time), NULL, parent->s.modelScale );
02717 gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, pilot->client->ps.origin );
02718 G_SetOrigin( pilot, pilot->client->ps.origin );
02719 gi.linkentity( pilot );
02720 }
02721
02722 if ( pVeh->m_pOldPilot )
02723 {
02724 gentity_t * const parent = pVeh->m_pParentEntity;
02725 gentity_t * const pilot = pVeh->m_pOldPilot;
02726 mdxaBone_t boltMatrix;
02727
02728 pilot->waypoint = parent->waypoint;
02729
02730
02731 gi.G2API_GetBoltMatrix( parent->ghoul2, parent->playerModel, parent->crotchBolt, &boltMatrix,
02732 pVeh->m_vOrientation, parent->currentOrigin,
02733 (cg.time?cg.time:level.time), NULL, parent->s.modelScale );
02734 gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, pilot->client->ps.origin );
02735 G_SetOrigin( pilot, pilot->client->ps.origin );
02736 gi.linkentity( pilot );
02737 }
02738 #endif
02739 }
02740
02741
02742 static void Ghost( Vehicle_t *pVeh, bgEntity_t *pEnt )
02743 {
02744 gentity_t *ent;
02745
02746 if ( !pEnt )
02747 return;
02748
02749 ent = (gentity_t *)pEnt;
02750
02751
02752 ent->r.svFlags |= SVF_NOCLIENT;
02753
02754 ent->s.eFlags |= EF_NODRAW;
02755 if ( ent->client )
02756 {
02757 ent->client->ps.eFlags |= EF_NODRAW;
02758 }
02759 #ifdef _JK2MP
02760 ent->r.contents = 0;
02761 #else
02762 ent->contents = 0;
02763 #endif
02764 }
02765
02766
02767 static void UnGhost( Vehicle_t *pVeh, bgEntity_t *pEnt )
02768 {
02769 gentity_t *ent;
02770
02771 if ( !pEnt )
02772 return;
02773
02774 ent = (gentity_t *)pEnt;
02775
02776
02777 ent->r.svFlags &= ~SVF_NOCLIENT;
02778
02779 ent->s.eFlags &= ~EF_NODRAW;
02780 if ( ent->client )
02781 {
02782 ent->client->ps.eFlags &= ~EF_NODRAW;
02783 }
02784 #ifdef _JK2MP
02785 ent->r.contents = CONTENTS_BODY;
02786 #else
02787 ent->contents = CONTENTS_BODY;
02788 #endif
02789 }
02790
02791 #ifdef _JK2MP
02792
02793 void G_VehicleDamageBoxSizing(Vehicle_t *pVeh)
02794 {
02795 vec3_t fwd, right, up;
02796 vec3_t nose;
02797 vec3_t back;
02798 trace_t trace;
02799 const float fDist = 256.0f;
02800 const float bDist = 256.0f;
02801 const float wDist = 32.0f;
02802 const float hDist = 32.0f;
02803 gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
02804
02805 if (!parent->ghoul2 || !parent->m_pVehicle || !parent->client)
02806 {
02807 return;
02808 }
02809
02810
02811
02812
02813 if (!(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_C) ||
02814 !(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_D) ||
02815 !(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_E) ||
02816 !(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_F) )
02817 {
02818 return;
02819 }
02820
02821
02822 AngleVectors(pVeh->m_vOrientation, fwd, right, up);
02823
02824
02825 VectorMA(vec3_origin, fDist, fwd, nose);
02826 VectorMA(vec3_origin, -bDist, fwd, back);
02827
02828
02829 VectorMA(nose, wDist, right, nose);
02830 VectorMA(nose, -wDist, right, back);
02831
02832
02833 VectorMA(nose, hDist, up, nose);
02834 VectorMA(nose, -hDist, up, back);
02835
02836
02837 trap_Trace(&trace, parent->client->ps.origin, back, nose, parent->client->ps.origin, parent->s.number, parent->clipmask);
02838 if (!trace.allsolid && !trace.startsolid && trace.fraction == 1.0f)
02839 {
02840 VectorCopy(nose, parent->maxs);
02841 VectorCopy(back, parent->mins);
02842 }
02843 else
02844 {
02845
02846 G_Damage(parent, parent, parent, NULL, parent->client->ps.origin, 9999, DAMAGE_NO_PROTECTION, MOD_SUICIDE);
02847 }
02848 }
02849
02850
02851 int G_FlyVehicleImpactDir(gentity_t *veh, trace_t *trace)
02852 {
02853 float impactAngle;
02854 float relativeAngle;
02855 trace_t localTrace;
02856 vec3_t testMins, testMaxs;
02857 vec3_t rWing, lWing;
02858 vec3_t fwd, right;
02859 vec3_t fPos;
02860 Vehicle_t *pVeh = veh->m_pVehicle;
02861 qboolean noseClear = qfalse;
02862
02863 if (!trace || !pVeh || !veh->client)
02864 {
02865 return -1;
02866 }
02867
02868 AngleVectors(veh->client->ps.viewangles, fwd, right, 0);
02869 VectorSet(testMins, -24.0f, -24.0f, -24.0f);
02870 VectorSet(testMaxs, 24.0f, 24.0f, 24.0f);
02871
02872
02873 VectorMA(veh->client->ps.origin, 256.0f, fwd, fPos);
02874 trap_Trace(&localTrace, veh->client->ps.origin, testMins, testMaxs, fPos, veh->s.number, veh->clipmask);
02875 if (!localTrace.startsolid && !localTrace.allsolid && localTrace.fraction == 1.0f)
02876 {
02877 noseClear = qtrue;
02878 }
02879
02880 if (noseClear)
02881 {
02882
02883
02884
02885 VectorMA(veh->client->ps.origin, 128.0f, right, rWing);
02886 VectorMA(veh->client->ps.origin, -128.0f, right, lWing);
02887
02888
02889 if (!(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_E) ||
02890 !(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_F))
02891 {
02892 VectorMA(rWing, 256.0f, fwd, fPos);
02893 trap_Trace(&localTrace, rWing, testMins, testMaxs, fPos, veh->s.number, veh->clipmask);
02894 if (localTrace.startsolid || localTrace.allsolid || localTrace.fraction != 1.0f)
02895 {
02896 return SHIPSURF_RIGHT;
02897 }
02898 }
02899
02900
02901 if (!(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_C) ||
02902 !(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_D))
02903 {
02904 VectorMA(lWing, 256.0f, fwd, fPos);
02905 trap_Trace(&localTrace, lWing, testMins, testMaxs, fPos, veh->s.number, veh->clipmask);
02906 if (localTrace.startsolid || localTrace.allsolid || localTrace.fraction != 1.0f)
02907 {
02908 return SHIPSURF_LEFT;
02909 }
02910 }
02911 }
02912
02913
02914 impactAngle = vectoyaw(trace->plane.normal);
02915 relativeAngle = AngleSubtract(impactAngle, veh->client->ps.viewangles[YAW]);
02916
02917 if (relativeAngle > 130 ||
02918 relativeAngle < -130)
02919 {
02920 return SHIPSURF_FRONT;
02921 }
02922 else if (relativeAngle > 0)
02923 {
02924 return SHIPSURF_RIGHT;
02925 }
02926 else if (relativeAngle < 0)
02927 {
02928 return SHIPSURF_LEFT;
02929 }
02930
02931 return SHIPSURF_BACK;
02932 }
02933
02934
02935 #define TURN_ON 0x00000000
02936 #define TURN_OFF 0x00000100
02937 extern void NPC_SetSurfaceOnOff(gentity_t *ent, const char *surfaceName, int surfaceFlags);
02938 int G_ShipSurfaceForSurfName( const char *surfaceName )
02939 {
02940 if ( !surfaceName )
02941 {
02942 return -1;
02943 }
02944 if ( !Q_strncmp( "nose", surfaceName, 4 )
02945 || !Q_strncmp( "f_gear", surfaceName, 6 )
02946 || !Q_strncmp( "glass", surfaceName, 5 ) )
02947 {
02948 return SHIPSURF_FRONT;
02949 }
02950 if ( !Q_strncmp( "body", surfaceName, 4 ) )
02951 {
02952 return SHIPSURF_BACK;
02953 }
02954 if ( !Q_strncmp( "r_wing1", surfaceName, 7 )
02955 || !Q_strncmp( "r_wing2", surfaceName, 7 )
02956 || !Q_strncmp( "r_gear", surfaceName, 6 ) )
02957 {
02958 return SHIPSURF_RIGHT;
02959 }
02960 if ( !Q_strncmp( "l_wing1", surfaceName, 7 )
02961 || !Q_strncmp( "l_wing2", surfaceName, 7 )
02962 || !Q_strncmp( "l_gear", surfaceName, 6 ) )
02963 {
02964 return SHIPSURF_LEFT;
02965 }
02966 return -1;
02967 }
02968
02969 void G_SetVehDamageFlags( gentity_t *veh, int shipSurf, int damageLevel )
02970 {
02971 int dmgFlag;
02972 switch ( damageLevel )
02973 {
02974 case 3:
02975
02976
02977 dmgFlag = SHIPSURF_DAMAGE_FRONT_HEAVY+(shipSurf-SHIPSURF_FRONT);
02978 veh->client->ps.brokenLimbs |= (1<<dmgFlag);
02979
02980 dmgFlag = SHIPSURF_DAMAGE_FRONT_LIGHT+(shipSurf-SHIPSURF_FRONT);
02981 veh->client->ps.brokenLimbs |= (1<<dmgFlag);
02982
02983 veh->s.brokenLimbs = veh->client->ps.brokenLimbs;
02984
02985 if ( shipSurf == SHIPSURF_BACK )
02986 {
02987 if ( veh->m_pVehicle
02988 && veh->m_pVehicle->m_pDroidUnit )
02989 {
02990 gentity_t *droidEnt = (gentity_t *)veh->m_pVehicle->m_pDroidUnit;
02991 if ( droidEnt
02992 && ((droidEnt->flags&FL_UNDYING) || droidEnt->health > 0) )
02993 {
02994
02995 droidEnt->flags &= ~FL_UNDYING;
02996
02997 G_Damage( droidEnt, veh->enemy, veh->enemy, NULL, NULL, 99999, 0, MOD_UNKNOWN );
02998 }
02999 }
03000 }
03001 break;
03002 case 2:
03003 dmgFlag = SHIPSURF_DAMAGE_FRONT_HEAVY+(shipSurf-SHIPSURF_FRONT);
03004 veh->client->ps.brokenLimbs |= (1<<dmgFlag);
03005
03006 dmgFlag = SHIPSURF_DAMAGE_FRONT_LIGHT+(shipSurf-SHIPSURF_FRONT);
03007 veh->client->ps.brokenLimbs &= ~(1<<dmgFlag);
03008
03009 veh->s.brokenLimbs = veh->client->ps.brokenLimbs;
03010
03011 if ( shipSurf == SHIPSURF_BACK )
03012 {
03013 if ( veh->m_pVehicle
03014 && veh->m_pVehicle->m_pDroidUnit )
03015 {
03016 gentity_t *droidEnt = (gentity_t *)veh->m_pVehicle->m_pDroidUnit;
03017 if ( droidEnt
03018 && (droidEnt->flags&FL_UNDYING) )
03019 {
03020 droidEnt->flags &= ~FL_UNDYING;
03021 }
03022 }
03023 }
03024 break;
03025 case 1:
03026
03027 dmgFlag = SHIPSURF_DAMAGE_FRONT_LIGHT+(shipSurf-SHIPSURF_FRONT);
03028 veh->client->ps.brokenLimbs |= (1<<dmgFlag);
03029
03030 dmgFlag = SHIPSURF_DAMAGE_FRONT_HEAVY+(shipSurf-SHIPSURF_FRONT);
03031 veh->client->ps.brokenLimbs &= ~(1<<dmgFlag);
03032
03033 veh->s.brokenLimbs = veh->client->ps.brokenLimbs;
03034 break;
03035 case 0:
03036 default:
03037
03038 dmgFlag = SHIPSURF_DAMAGE_FRONT_HEAVY+(shipSurf-SHIPSURF_FRONT);
03039 veh->client->ps.brokenLimbs &= ~(1<<dmgFlag);
03040
03041 dmgFlag = SHIPSURF_DAMAGE_FRONT_LIGHT+(shipSurf-SHIPSURF_FRONT);
03042 veh->client->ps.brokenLimbs &= ~(1<<dmgFlag);
03043
03044 veh->s.brokenLimbs = veh->client->ps.brokenLimbs;
03045 break;
03046 }
03047 }
03048
03049 void G_VehicleSetDamageLocFlags( gentity_t *veh, int impactDir, int deathPoint )
03050 {
03051 if ( !veh->client )
03052 {
03053 return;
03054 }
03055 else
03056 {
03057 int deathPoint, heavyDamagePoint, lightDamagePoint;
03058 switch(impactDir)
03059 {
03060 case SHIPSURF_FRONT:
03061 deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_front;
03062 break;
03063 case SHIPSURF_BACK:
03064 deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_back;
03065 break;
03066 case SHIPSURF_RIGHT:
03067 deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_right;
03068 break;
03069 case SHIPSURF_LEFT:
03070 deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_left;
03071 break;
03072 default:
03073 return;
03074 break;
03075 }
03076 if ( veh->m_pVehicle
03077 && veh->m_pVehicle->m_pVehicleInfo
03078 && veh->m_pVehicle->m_pVehicleInfo->malfunctionArmorLevel
03079 && veh->m_pVehicle->m_pVehicleInfo->armor )
03080 {
03081 float perc = ((float)veh->m_pVehicle->m_pVehicleInfo->malfunctionArmorLevel/(float)veh->m_pVehicle->m_pVehicleInfo->armor);
03082 if ( perc > 0.99f )
03083 {
03084 perc = 0.99f;
03085 }
03086 lightDamagePoint = ceil( deathPoint*perc*0.25f );
03087 heavyDamagePoint = ceil( deathPoint*perc );
03088 }
03089 else
03090 {
03091 heavyDamagePoint = ceil( deathPoint*0.66f );
03092 lightDamagePoint = ceil( deathPoint*0.14f );
03093 }
03094
03095 if ( veh->locationDamage[impactDir] >= deathPoint)
03096 {
03097 G_SetVehDamageFlags( veh, impactDir, 3 );
03098 }
03099 else if ( veh->locationDamage[impactDir] <= lightDamagePoint )
03100 {
03101 G_SetVehDamageFlags( veh, impactDir, 1 );
03102 }
03103 else if ( veh->locationDamage[impactDir] <= heavyDamagePoint )
03104 {
03105 G_SetVehDamageFlags( veh, impactDir, 2 );
03106 }
03107 }
03108 }
03109
03110 qboolean G_FlyVehicleDestroySurface( gentity_t *veh, int surface )
03111 {
03112 char *surfName[4];
03113 int numSurfs = 0;
03114 int smashedBits = 0;
03115
03116 if (surface == -1)
03117 {
03118 return qfalse;
03119 }
03120
03121 switch(surface)
03122 {
03123 case SHIPSURF_FRONT:
03124 surfName[0] = "nose";
03125
03126 smashedBits = (SHIPSURF_BROKEN_G);
03127
03128 numSurfs = 1;
03129 break;
03130 case SHIPSURF_BACK:
03131 surfName[0] = "r_wing2";
03132 surfName[1] = "l_wing2";
03133
03134
03135 surfName[2] = "r_gear";
03136 surfName[3] = "l_gear";
03137
03138 smashedBits = (SHIPSURF_BROKEN_A|SHIPSURF_BROKEN_B|SHIPSURF_BROKEN_D|SHIPSURF_BROKEN_F);
03139
03140 numSurfs = 4;
03141 break;
03142 case SHIPSURF_RIGHT:
03143 surfName[0] = "r_wing1";
03144 surfName[1] = "r_wing2";
03145
03146
03147 surfName[2] = "r_gear";
03148
03149 smashedBits = (SHIPSURF_BROKEN_B|SHIPSURF_BROKEN_E|SHIPSURF_BROKEN_F);
03150
03151 numSurfs = 3;
03152 break;
03153 case SHIPSURF_LEFT:
03154 surfName[0] = "l_wing1";
03155 surfName[1] = "l_wing2";
03156
03157
03158 surfName[2] = "l_gear";
03159
03160 smashedBits = (SHIPSURF_BROKEN_A|SHIPSURF_BROKEN_C|SHIPSURF_BROKEN_D);
03161
03162 numSurfs = 3;
03163 break;
03164 default:
03165 break;
03166 }
03167
03168 if (numSurfs < 1)
03169 {
03170 return qfalse;
03171 }
03172
03173 while (numSurfs > 0)
03174 {
03175 numSurfs--;
03176 NPC_SetSurfaceOnOff(veh, surfName[numSurfs], TURN_OFF);
03177 }
03178
03179 if ( !veh->m_pVehicle->m_iRemovedSurfaces )
03180 {
03181 if ( veh->m_pVehicle->m_pPilot )
03182 {
03183 G_EntitySound((gentity_t*)veh->m_pVehicle->m_pPilot, CHAN_VOICE, G_SoundIndex("*falling1.wav"));
03184 }
03185 }
03186
03187 veh->m_pVehicle->m_iRemovedSurfaces |= smashedBits;
03188
03189
03190 G_RadiusDamage(veh->client->ps.origin, veh, 100, 500, veh, NULL, MOD_SUICIDE);
03191
03192
03193 veh->client->ps.electrifyTime = level.time + 10000;
03194
03195 return qtrue;
03196 }
03197
03198 void G_FlyVehicleSurfaceDestruction(gentity_t *veh, trace_t *trace, int magnitude, qboolean force)
03199 {
03200 int impactDir;
03201 int secondImpact;
03202 int deathPoint = -1;
03203 qboolean alreadyRebroken = qfalse;
03204
03205 if (!veh->ghoul2 || !veh->m_pVehicle)
03206 {
03207 return;
03208 }
03209
03210 impactDir = G_FlyVehicleImpactDir(veh, trace);
03211
03212 anotherImpact:
03213 if (impactDir == -1)
03214 {
03215 return;
03216 }
03217
03218 veh->locationDamage[impactDir] += magnitude*7;
03219
03220 switch(impactDir)
03221 {
03222 case SHIPSURF_FRONT:
03223 deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_front;
03224 break;
03225 case SHIPSURF_BACK:
03226 deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_back;
03227 break;
03228 case SHIPSURF_RIGHT:
03229 deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_right;
03230 break;
03231 case SHIPSURF_LEFT:
03232 deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_left;
03233 break;
03234 default:
03235 break;
03236 }
03237
03238 if ( deathPoint != -1 )
03239 {
03240 if ( force && veh->locationDamage[impactDir] < deathPoint )
03241 {
03242 veh->locationDamage[impactDir] = deathPoint;
03243 }
03244 if ( veh->locationDamage[impactDir] >= deathPoint)
03245 {
03246 if ( G_FlyVehicleDestroySurface( veh, impactDir ) )
03247 {
03248 G_VehicleSetDamageLocFlags( veh, impactDir, deathPoint );
03249 }
03250 }
03251 else
03252 {
03253 G_VehicleSetDamageLocFlags( veh, impactDir, deathPoint );
03254 }
03255 }
03256
03257 if (!alreadyRebroken)
03258 {
03259 secondImpact = G_FlyVehicleImpactDir(veh, trace);
03260 if (impactDir != secondImpact)
03261 {
03262 alreadyRebroken = qtrue;
03263 impactDir = secondImpact;
03264 goto anotherImpact;
03265 }
03266 }
03267 }
03268
03269 void G_VehUpdateShields( gentity_t *targ )
03270 {
03271 if ( !targ || !targ->client
03272 || !targ->m_pVehicle || !targ->m_pVehicle->m_pVehicleInfo )
03273 {
03274 return;
03275 }
03276 if ( targ->m_pVehicle->m_pVehicleInfo->shields <= 0 )
03277 {
03278 return;
03279 }
03280 targ->client->ps.activeForcePass = floor(((float)targ->m_pVehicle->m_iShields/(float)targ->m_pVehicle->m_pVehicleInfo->shields)*10.0f);
03281 }
03282 #endif
03283
03284
03285 GAME_INLINE void SetParent( Vehicle_t *pVeh, bgEntity_t *pParentEntity ) { pVeh->m_pParentEntity = pParentEntity; }
03286
03287
03288 GAME_INLINE void SetPilot( Vehicle_t *pVeh, bgEntity_t *pPilot ) { pVeh->m_pPilot = pPilot; }
03289
03290
03291 GAME_INLINE bool AddPassenger( Vehicle_t *pVeh ) { return false; }
03292
03293
03294 GAME_INLINE bool Inhabited( Vehicle_t *pVeh ) { return ( pVeh->m_pPilot || pVeh->m_iNumPassengers ) ? true : false; }
03295
03296
03297
03298 void G_SetSharedVehicleFunctions( vehicleInfo_t *pVehInfo )
03299 {
03300
03301
03302 pVehInfo->ValidateBoard = ValidateBoard;
03303 pVehInfo->SetParent = SetParent;
03304 pVehInfo->SetPilot = SetPilot;
03305 pVehInfo->AddPassenger = AddPassenger;
03306 pVehInfo->Animate = Animate;
03307 pVehInfo->Board = Board;
03308 pVehInfo->Eject = Eject;
03309 pVehInfo->EjectAll = EjectAll;
03310 pVehInfo->StartDeathDelay = StartDeathDelay;
03311 pVehInfo->DeathUpdate = DeathUpdate;
03312 pVehInfo->RegisterAssets = RegisterAssets;
03313 pVehInfo->Initialize = Initialize;
03314 pVehInfo->Update = Update;
03315 pVehInfo->UpdateRider = UpdateRider;
03316
03317
03318 pVehInfo->AttachRiders = AttachRiders;
03319 pVehInfo->Ghost = Ghost;
03320 pVehInfo->UnGhost = UnGhost;
03321 pVehInfo->Inhabited = Inhabited;
03322 }
03323
03324 #ifdef _JK2MP
03325
03326 #undef currentAngles
03327 #undef currentOrigin
03328 #undef mins
03329 #undef maxs
03330 #undef legsAnimTimer
03331 #undef torsoAnimTimer
03332 #undef bool
03333 #undef false
03334 #undef true
03335
03336 #undef sqrtf
03337
03338 #undef MOD_EXPLOSIVE
03339 #endif