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.