00001
00002
00003
00004
00005 #include "q_shared.h"
00006 #include "bg_public.h"
00007 #include "bg_local.h"
00008
00009 #ifdef QAGAME //yeah, this is kind of bad
00010 #include "g_local.h"
00011 #endif
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef QAGAME
00025 extern void G_FlyVehicleSurfaceDestruction(gentity_t *veh, trace_t *trace, int magnitude, qboolean force );
00026 extern qboolean G_CanBeEnemy(gentity_t *self, gentity_t *enemy);
00027 #endif
00028
00029 extern qboolean BG_UnrestrainedPitchRoll( playerState_t *ps, Vehicle_t *pVeh );
00030
00031 #include "../namespace_begin.h"
00032
00033 extern bgEntity_t *pm_entSelf;
00034 extern bgEntity_t *pm_entVeh;
00035
00036
00037 #ifndef QAGAME //kind of hacky
00038 extern void trap_FX_PlayEffectID( int id, vec3_t org, vec3_t fwd, int vol, int rad );
00039 #endif
00040
00041 #ifdef QAGAME
00042 extern qboolean FighterIsLanded( Vehicle_t *pVeh, playerState_t *parentPS );
00043 #endif
00044
00045 extern void PM_SetPMViewAngle(playerState_t *ps, vec3_t angle, usercmd_t *ucmd);
00046
00047 #define MAX_IMPACT_TURN_ANGLE 45.0f
00048 void PM_VehicleImpact(bgEntity_t *pEnt, trace_t *trace)
00049 {
00050
00051 Vehicle_t *pSelfVeh = pEnt->m_pVehicle;
00052 float magnitude = VectorLength( pm->ps->velocity ) * pSelfVeh->m_pVehicleInfo->mass / 50.0f;
00053 qboolean forceSurfDestruction = qfalse;
00054 #ifdef QAGAME
00055 gentity_t *hitEnt = trace!=NULL?&g_entities[trace->entityNum]:NULL;
00056
00057 if (!hitEnt ||
00058 (pSelfVeh && pSelfVeh->m_pPilot &&
00059 hitEnt && hitEnt->s.eType == ET_MISSILE && hitEnt->inuse &&
00060 hitEnt->r.ownerNum == pSelfVeh->m_pPilot->s.number)
00061 )
00062 {
00063 return;
00064 }
00065
00066 if ( pSelfVeh
00067 && pSelfVeh->m_iRemovedSurfaces )
00068 {
00069 if ( hitEnt->s.NPC_class == CLASS_VEHICLE )
00070 {
00071
00072 gentity_t *parent = (gentity_t *)pSelfVeh->m_pParentEntity;
00073 gentity_t *killer = NULL;
00074 if (parent->client->ps.otherKiller < ENTITYNUM_WORLD &&
00075 parent->client->ps.otherKillerTime > level.time)
00076 {
00077 gentity_t *potentialKiller = &g_entities[parent->client->ps.otherKiller];
00078
00079 if (potentialKiller->inuse && potentialKiller->client)
00080 {
00081 killer = potentialKiller;
00082 }
00083 }
00084
00085 G_Damage( (gentity_t *)pEnt, killer, killer, NULL, pm->ps->origin, 999999, DAMAGE_NO_ARMOR, MOD_FALLING );
00086 return;
00087 }
00088 else if ( !VectorCompare( trace->plane.normal, vec3_origin )
00089 && (trace->entityNum == ENTITYNUM_WORLD || hitEnt->r.bmodel ) )
00090 {
00091 vec3_t moveDir;
00092 float impactDot;
00093 VectorCopy( pm->ps->velocity, moveDir );
00094 VectorNormalize( moveDir );
00095 impactDot = DotProduct( moveDir, trace->plane.normal );
00096 if ( impactDot <= -0.7f )
00097 {
00098
00099 gentity_t *parent = (gentity_t *)pSelfVeh->m_pParentEntity;
00100 gentity_t *killer = NULL;
00101 if (parent->client->ps.otherKiller < ENTITYNUM_WORLD &&
00102 parent->client->ps.otherKillerTime > level.time)
00103 {
00104 gentity_t *potentialKiller = &g_entities[parent->client->ps.otherKiller];
00105
00106 if (potentialKiller->inuse && potentialKiller->client)
00107 {
00108 killer = potentialKiller;
00109 }
00110 }
00111 G_Damage( (gentity_t *)pEnt, killer, killer, NULL, pm->ps->origin, 999999, DAMAGE_NO_ARMOR, MOD_FALLING );
00112 return;
00113 }
00114 }
00115 }
00116
00117 if ( trace->entityNum < ENTITYNUM_WORLD
00118 && hitEnt->s.eType == ET_MOVER
00119 && hitEnt->s.apos.trType != TR_STATIONARY
00120 && (hitEnt->spawnflags&16)
00121 && Q_stricmp( "func_rotating", hitEnt->classname ) == 0 )
00122 {
00123
00124 forceSurfDestruction = qtrue;
00125 }
00126 else if ( (fabs(pm->ps->velocity[0])+fabs(pm->ps->velocity[1])) < 100.0f
00127 && pm->ps->velocity[2] > -100.0f )
00128 #else
00129 if ( (fabs(pm->ps->velocity[0])+fabs(pm->ps->velocity[1])) < 100.0f
00130 && pm->ps->velocity[2] > -100.0f )
00131 #endif
00132
00133
00134
00135
00136
00137 {
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152 #ifdef QAGAME
00153 if (hitEnt && (hitEnt->s.eType == ET_PLAYER || hitEnt->s.eType == ET_NPC) && pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
00154 {
00155 }
00156 else
00157 #endif
00158 {
00159 return;
00160 }
00161 }
00162 if ( pSelfVeh &&
00163 (pSelfVeh->m_pVehicleInfo->type == VH_SPEEDER || pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER) &&
00164 (magnitude >= 100||forceSurfDestruction) )
00165 {
00166 if ( pEnt->m_pVehicle->m_iHitDebounce < pm->cmd.serverTime
00167 || forceSurfDestruction )
00168 {
00169
00170
00171 vec3_t vehUp;
00172 #ifndef QAGAME
00173 bgEntity_t *hitEnt;
00174 #endif
00175
00176 if ( trace && !pSelfVeh->m_iRemovedSurfaces && !forceSurfDestruction )
00177 {
00178 qboolean turnFromImpact = qfalse, turnHitEnt = qfalse;
00179 float l = pm->ps->speed*0.5f;
00180 vec3_t bounceDir;
00181 #ifndef QAGAME
00182 bgEntity_t *hitEnt = PM_BGEntForNum(trace->entityNum);
00183 #endif
00184 if ( (trace->entityNum == ENTITYNUM_WORLD || hitEnt->s.solid == SOLID_BMODEL)
00185 && !VectorCompare(trace->plane.normal, vec3_origin) )
00186 {
00187 if (pSelfVeh->m_pVehicleInfo->type == VH_SPEEDER)
00188 {
00189 pm->ps->speed *= pml.frametime;
00190 VectorCopy(trace->plane.normal, bounceDir);
00191 }
00192 else if ( trace->plane.normal[2] >= MIN_LANDING_SLOPE
00193 && pSelfVeh->m_LandTrace.fraction < 1.0f
00194 && pm->ps->speed <= MIN_LANDING_SPEED )
00195 {
00196 return;
00197 }
00198 else
00199 {
00200 if (pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
00201 {
00202 turnFromImpact = qtrue;
00203 }
00204 VectorCopy(trace->plane.normal, bounceDir);
00205 }
00206 }
00207 else if ( pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER )
00208 {
00209 #ifndef QAGAME
00210 bgEntity_t *hitEnt = PM_BGEntForNum(trace->entityNum);
00211 #endif
00212 if ( hitEnt->s.NPC_class == CLASS_VEHICLE
00213 && hitEnt->m_pVehicle
00214 && hitEnt->m_pVehicle->m_pVehicleInfo
00215 && hitEnt->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER )
00216 {
00217 turnFromImpact = qtrue;
00218 turnHitEnt = qtrue;
00219 #ifndef QAGAME
00220 VectorSubtract( pm->ps->origin, hitEnt->s.origin, bounceDir );
00221 #else
00222 VectorSubtract( pm->ps->origin, hitEnt->r.currentOrigin, bounceDir );
00223 #endif
00224 VectorNormalize( bounceDir );
00225 }
00226 }
00227 if ( turnFromImpact )
00228 {
00229 vec3_t pushDir={0}, turnAwayAngles, turnDelta;
00230 float turnStrength, pitchTurnStrength, yawTurnStrength;
00231 vec3_t moveDir;
00232 float bounceDot, turnDivider;
00233
00234 if ( !turnHitEnt )
00235 {
00236 VectorScale(bounceDir, (pm->ps->speed*0.25f/pSelfVeh->m_pVehicleInfo->mass), pushDir);
00237 }
00238 else
00239 {
00240 #ifndef QAGAME
00241 VectorScale( bounceDir, (pm->ps->speed+hitEnt->s.speed)*0.5f, bounceDir );
00242 #else
00243 if ( hitEnt->client )
00244 {
00245 VectorScale( bounceDir, (pm->ps->speed+hitEnt->client->ps.speed)*0.5f, pushDir );
00246 }
00247 else
00248 {
00249 VectorScale( bounceDir, (pm->ps->speed+hitEnt->s.speed)*0.5f, pushDir );
00250 }
00251 #endif
00252 VectorScale(pushDir, (l/pSelfVeh->m_pVehicleInfo->mass), pushDir);
00253 VectorScale(pushDir, 0.1f, pushDir);
00254 }
00255 VectorNormalize2( pm->ps->velocity, moveDir );
00256 bounceDot = DotProduct( moveDir, bounceDir )*-1;
00257 if ( bounceDot < 0.1f )
00258 {
00259 bounceDot = 0.1f;
00260 }
00261 VectorScale( pushDir, bounceDot, pushDir );
00262 VectorAdd(pm->ps->velocity, pushDir, pm->ps->velocity);
00263
00264 turnDivider = (pSelfVeh->m_pVehicleInfo->mass/400.0f);
00265 if ( turnHitEnt )
00266 {
00267 turnDivider *= 4.0f;
00268 }
00269 if ( turnDivider < 0.5f )
00270 {
00271 turnDivider = 0.5f;
00272 }
00273 turnStrength = (magnitude/2000.0f);
00274 if ( turnStrength < 0.1f )
00275 {
00276 turnStrength = 0.1f;
00277 }
00278 else if ( turnStrength > 2.0f )
00279 {
00280 turnStrength = 2.0f;
00281 }
00282
00283 vectoangles( bounceDir, turnAwayAngles );
00284
00285 AnglesSubtract( turnAwayAngles, pSelfVeh->m_vOrientation, turnDelta );
00286
00287 if ( !bounceDir[2] )
00288 {
00289 }
00290 else
00291 {
00292 pitchTurnStrength = turnStrength*turnDelta[PITCH];
00293 if ( pitchTurnStrength > MAX_IMPACT_TURN_ANGLE )
00294 {
00295 pitchTurnStrength = MAX_IMPACT_TURN_ANGLE;
00296 }
00297 else if ( pitchTurnStrength < -MAX_IMPACT_TURN_ANGLE )
00298 {
00299 pitchTurnStrength = -MAX_IMPACT_TURN_ANGLE;
00300 }
00301
00302 pSelfVeh->m_vFullAngleVelocity[PITCH] = AngleNormalize180(pSelfVeh->m_vOrientation[PITCH]+pitchTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
00303 }
00304
00305 if ( !bounceDir[0]
00306 && !bounceDir[1] )
00307 {
00308 }
00309 else
00310 {
00311 yawTurnStrength = turnStrength*turnDelta[YAW];
00312 if ( yawTurnStrength > MAX_IMPACT_TURN_ANGLE )
00313 {
00314 yawTurnStrength = MAX_IMPACT_TURN_ANGLE;
00315 }
00316 else if ( yawTurnStrength < -MAX_IMPACT_TURN_ANGLE )
00317 {
00318 yawTurnStrength = -MAX_IMPACT_TURN_ANGLE;
00319 }
00320
00321 pSelfVeh->m_vFullAngleVelocity[ROLL] = AngleNormalize180(pSelfVeh->m_vOrientation[ROLL]-yawTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
00322 }
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335 #ifdef QAGAME//server-side, turn the guy we hit away from us, too
00336 if ( turnHitEnt
00337 && hitEnt->client
00338 && !FighterIsLanded( hitEnt->m_pVehicle, &hitEnt->client->ps )
00339 && !(hitEnt->spawnflags&2) )
00340 {
00341 l = hitEnt->client->ps.speed;
00342
00343
00344 VectorScale( bounceDir, -1, bounceDir );
00345
00346 VectorScale( bounceDir, (pm->ps->speed+l)*0.5f, pushDir );
00347 VectorScale(pushDir, (l*0.5f/hitEnt->m_pVehicle->m_pVehicleInfo->mass), pushDir);
00348 VectorNormalize2( hitEnt->client->ps.velocity, moveDir );
00349 bounceDot = DotProduct( moveDir, bounceDir )*-1;
00350 if ( bounceDot < 0.1f )
00351 {
00352 bounceDot = 0.1f;
00353 }
00354 VectorScale( pushDir, bounceDot, pushDir );
00355 VectorAdd(hitEnt->client->ps.velocity, pushDir, hitEnt->client->ps.velocity);
00356
00357 turnDivider = (hitEnt->m_pVehicle->m_pVehicleInfo->mass/400.0f);
00358 if ( turnHitEnt )
00359 {
00360 turnDivider *= 4.0f;
00361 }
00362 if ( turnDivider < 0.5f )
00363 {
00364 turnDivider = 0.5f;
00365 }
00366
00367 vectoangles( bounceDir, turnAwayAngles );
00368
00369 AnglesSubtract( turnAwayAngles, hitEnt->m_pVehicle->m_vOrientation, turnDelta );
00370
00371 if ( !bounceDir[2] )
00372 {
00373 }
00374 else
00375 {
00376 pitchTurnStrength = turnStrength*turnDelta[PITCH];
00377 if ( pitchTurnStrength > MAX_IMPACT_TURN_ANGLE )
00378 {
00379 pitchTurnStrength = MAX_IMPACT_TURN_ANGLE;
00380 }
00381 else if ( pitchTurnStrength < -MAX_IMPACT_TURN_ANGLE )
00382 {
00383 pitchTurnStrength = -MAX_IMPACT_TURN_ANGLE;
00384 }
00385
00386 hitEnt->m_pVehicle->m_vFullAngleVelocity[PITCH] = AngleNormalize180(hitEnt->m_pVehicle->m_vOrientation[PITCH]+pitchTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
00387 }
00388
00389 if ( !bounceDir[0]
00390 && !bounceDir[1] )
00391 {
00392 }
00393 else
00394 {
00395 yawTurnStrength = turnStrength*turnDelta[YAW];
00396 if ( yawTurnStrength > MAX_IMPACT_TURN_ANGLE )
00397 {
00398 yawTurnStrength = MAX_IMPACT_TURN_ANGLE;
00399 }
00400 else if ( yawTurnStrength < -MAX_IMPACT_TURN_ANGLE )
00401 {
00402 yawTurnStrength = -MAX_IMPACT_TURN_ANGLE;
00403 }
00404
00405 hitEnt->m_pVehicle->m_vFullAngleVelocity[ROLL] = AngleNormalize180(hitEnt->m_pVehicle->m_vOrientation[ROLL]-yawTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
00406 }
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419 }
00420 #endif
00421 }
00422 }
00423
00424 #ifdef QAGAME
00425 if (!hitEnt)
00426 {
00427 return;
00428 }
00429
00430 AngleVectors( pSelfVeh->m_vOrientation, NULL, NULL, vehUp );
00431 if ( pSelfVeh->m_pVehicleInfo->iImpactFX )
00432 {
00433
00434
00435 G_AddEvent((gentity_t *)pEnt, EV_PLAY_EFFECT_ID, pSelfVeh->m_pVehicleInfo->iImpactFX);
00436 }
00437 pEnt->m_pVehicle->m_iHitDebounce = pm->cmd.serverTime + 200;
00438 magnitude /= pSelfVeh->m_pVehicleInfo->toughness * 50.0f;
00439
00440 if (hitEnt && (hitEnt->s.eType != ET_TERRAIN || !(hitEnt->spawnflags & 1) || pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER))
00441 {
00442 if (pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
00443 {
00444 float mult = (pSelfVeh->m_vOrientation[PITCH]*0.1f);
00445 if (mult < 1.0f)
00446 {
00447 mult = 1.0f;
00448 }
00449 if (hitEnt->inuse && hitEnt->takedamage)
00450 {
00451
00452 if (hitEnt->s.eType == ET_NPC &&
00453 hitEnt->s.NPC_class == CLASS_VEHICLE &&
00454 hitEnt->m_pVehicle)
00455 {
00456 mult = 1.5f;
00457 }
00458 else
00459 {
00460 mult = 0.5f;
00461 }
00462 }
00463
00464 magnitude *= mult;
00465 }
00466 pSelfVeh->m_iLastImpactDmg = magnitude;
00467
00468
00469 G_Damage( (gentity_t *)pEnt, NULL, NULL, NULL, pm->ps->origin, magnitude*5, DAMAGE_NO_ARMOR, MOD_FALLING );
00470
00471 if (pSelfVeh->m_pVehicleInfo->surfDestruction)
00472 {
00473 G_FlyVehicleSurfaceDestruction((gentity_t *)pEnt, trace, magnitude, forceSurfDestruction );
00474 }
00475
00476 pSelfVeh->m_ulFlags |= VEH_CRASHING;
00477 }
00478
00479 if (hitEnt &&
00480 hitEnt->inuse &&
00481 hitEnt->takedamage)
00482 {
00483 float pmult = 1.0f;
00484 int finalD;
00485 gentity_t *attackEnt;
00486
00487 if ( (hitEnt->s.eType == ET_PLAYER && hitEnt->s.number < MAX_CLIENTS) ||
00488 (hitEnt->s.eType == ET_NPC && hitEnt->s.NPC_class != CLASS_VEHICLE) )
00489 {
00490 if (pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
00491 {
00492 pmult = 2000.0f;
00493 }
00494 else
00495 {
00496 pmult = 40.0f;
00497 }
00498
00499 if (hitEnt->client &&
00500 BG_KnockDownable(&hitEnt->client->ps) &&
00501 G_CanBeEnemy((gentity_t *)pEnt, hitEnt))
00502 {
00503 if (hitEnt->client->ps.forceHandExtend != HANDEXTEND_KNOCKDOWN)
00504 {
00505 hitEnt->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN;
00506 hitEnt->client->ps.forceHandExtendTime = pm->cmd.serverTime + 1100;
00507 hitEnt->client->ps.forceDodgeAnim = 0;
00508 }
00509
00510 hitEnt->client->ps.otherKiller = pEnt->s.number;
00511 hitEnt->client->ps.otherKillerTime = pm->cmd.serverTime + 5000;
00512 hitEnt->client->ps.otherKillerDebounceTime = pm->cmd.serverTime + 100;
00513
00514
00515 VectorAdd(hitEnt->client->ps.velocity, pm->ps->velocity, hitEnt->client->ps.velocity);
00516
00517 hitEnt->client->ps.velocity[2] += 200.0f;
00518 }
00519 }
00520
00521 if (pSelfVeh->m_pPilot)
00522 {
00523 attackEnt = (gentity_t *)pSelfVeh->m_pPilot;
00524 }
00525 else
00526 {
00527 attackEnt = (gentity_t *)pEnt;
00528 }
00529
00530 finalD = magnitude*pmult;
00531 if (finalD < 1)
00532 {
00533 finalD = 1;
00534 }
00535 G_Damage( hitEnt, attackEnt, attackEnt, NULL, pm->ps->origin, finalD, 0, MOD_MELEE );
00536 }
00537 #else //this is gonna result in "double effects" for the client doing the prediction.
00538
00539 hitEnt = PM_BGEntForNum(trace->entityNum);
00540
00541 if (!hitEnt || hitEnt->s.owner != pEnt->s.number)
00542 {
00543 AngleVectors( pSelfVeh->m_vOrientation, NULL, NULL, vehUp );
00544 pEnt->m_pVehicle->m_iHitDebounce = pm->cmd.serverTime + 200;
00545 trap_FX_PlayEffectID( pSelfVeh->m_pVehicleInfo->iImpactFX, pm->ps->origin, vehUp, -1, -1 );
00546
00547 pSelfVeh->m_ulFlags |= VEH_CRASHING;
00548 }
00549 #endif
00550 }
00551 }
00552 }
00553
00554 qboolean PM_GroundSlideOkay( float zNormal )
00555 {
00556 if ( zNormal > 0 )
00557 {
00558 if ( pm->ps->velocity[2] > 0 )
00559 {
00560 if ( pm->ps->legsAnim == BOTH_WALL_RUN_RIGHT
00561 || pm->ps->legsAnim == BOTH_WALL_RUN_LEFT
00562 || pm->ps->legsAnim == BOTH_WALL_RUN_RIGHT_STOP
00563 || pm->ps->legsAnim == BOTH_WALL_RUN_LEFT_STOP
00564 || pm->ps->legsAnim == BOTH_FORCEWALLRUNFLIP_START
00565 || pm->ps->legsAnim == BOTH_FORCELONGLEAP_START
00566 || pm->ps->legsAnim == BOTH_FORCELONGLEAP_ATTACK
00567 || pm->ps->legsAnim == BOTH_FORCELONGLEAP_LAND
00568 || BG_InReboundJump( pm->ps->legsAnim ))
00569 {
00570 return qfalse;
00571 }
00572 }
00573 }
00574 return qtrue;
00575 }
00576
00577
00578
00579
00580
00581
00582
00583 #ifdef QAGAME
00584 extern void Client_CheckImpactBBrush( gentity_t *self, gentity_t *other );
00585 qboolean PM_ClientImpact( trace_t *trace )
00586 {
00587
00588 gentity_t *traceEnt;
00589 int otherEntityNum = trace->entityNum;
00590
00591 if ( !pm_entSelf )
00592 {
00593 return qfalse;
00594 }
00595
00596 if ( otherEntityNum >= ENTITYNUM_WORLD )
00597 {
00598 return qfalse;
00599 }
00600
00601 traceEnt = &g_entities[otherEntityNum];
00602
00603 if( VectorLength( pm->ps->velocity ) >= 100
00604 && pm_entSelf->s.NPC_class != CLASS_VEHICLE
00605 && pm->ps->lastOnGround+100 < level.time )
00606
00607 {
00608 Client_CheckImpactBBrush( (gentity_t *)(pm_entSelf), &g_entities[otherEntityNum] );
00609 }
00610
00611 if ( !traceEnt
00612 || !(traceEnt->r.contents&pm->tracemask) )
00613 {
00614 return qtrue;
00615 }
00616
00617 return qfalse;
00618 }
00619 #endif
00620
00621
00622
00623
00624
00625
00626
00627
00628 #define MAX_CLIP_PLANES 5
00629 qboolean PM_SlideMove( qboolean gravity ) {
00630 int bumpcount, numbumps;
00631 vec3_t dir;
00632 float d;
00633 int numplanes;
00634 vec3_t normal, planes[MAX_CLIP_PLANES];
00635 vec3_t primal_velocity;
00636 vec3_t clipVelocity;
00637 int i, j, k;
00638 trace_t trace;
00639 vec3_t end;
00640 float time_left;
00641 float into;
00642 vec3_t endVelocity;
00643 vec3_t endClipVelocity;
00644
00645
00646 numbumps = 4;
00647
00648 VectorCopy (pm->ps->velocity, primal_velocity);
00649
00650 if ( gravity ) {
00651 VectorCopy( pm->ps->velocity, endVelocity );
00652 endVelocity[2] -= pm->ps->gravity * pml.frametime;
00653 pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5;
00654 primal_velocity[2] = endVelocity[2];
00655 if ( pml.groundPlane ) {
00656 if ( PM_GroundSlideOkay( pml.groundTrace.plane.normal[2] ) )
00657 {
00658 PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
00659 pm->ps->velocity, OVERCLIP );
00660 }
00661 }
00662 }
00663
00664 time_left = pml.frametime;
00665
00666
00667 if ( pml.groundPlane ) {
00668 numplanes = 1;
00669 VectorCopy( pml.groundTrace.plane.normal, planes[0] );
00670 if ( !PM_GroundSlideOkay( planes[0][2] ) )
00671 {
00672 planes[0][2] = 0;
00673 VectorNormalize( planes[0] );
00674 }
00675 } else {
00676 numplanes = 0;
00677 }
00678
00679
00680 VectorNormalize2( pm->ps->velocity, planes[numplanes] );
00681 numplanes++;
00682
00683 for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) {
00684
00685
00686 VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );
00687
00688
00689 pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask);
00690
00691 if (trace.allsolid) {
00692
00693 pm->ps->velocity[2] = 0;
00694 return qtrue;
00695 }
00696
00697 if (trace.fraction > 0) {
00698
00699 VectorCopy (trace.endpos, pm->ps->origin);
00700 }
00701
00702 if (trace.fraction == 1) {
00703 break;
00704 }
00705
00706
00707 PM_AddTouchEnt( trace.entityNum );
00708
00709 if (pm->ps->clientNum >= MAX_CLIENTS)
00710 {
00711 bgEntity_t *pEnt = pm_entSelf;
00712
00713 if (pEnt && pEnt->s.eType == ET_NPC && pEnt->s.NPC_class == CLASS_VEHICLE &&
00714 pEnt->m_pVehicle)
00715 {
00716 PM_VehicleImpact(pEnt, &trace);
00717 }
00718 }
00719 #ifdef QAGAME
00720 else
00721 {
00722 if ( PM_ClientImpact( &trace ) )
00723 {
00724 continue;
00725 }
00726 }
00727 #endif
00728
00729 time_left -= time_left * trace.fraction;
00730
00731 if (numplanes >= MAX_CLIP_PLANES) {
00732
00733 VectorClear( pm->ps->velocity );
00734 return qtrue;
00735 }
00736
00737 VectorCopy( trace.plane.normal, normal );
00738
00739 if ( !PM_GroundSlideOkay( normal[2] ) )
00740 {
00741
00742 normal[2] = 0;
00743 VectorNormalize( normal );
00744 }
00745
00746
00747
00748
00749
00750 if ( !(pm->ps->pm_flags&PMF_STUCK_TO_WALL) )
00751 {
00752 for ( i = 0 ; i < numplanes ; i++ ) {
00753 if ( VectorCompare( normal, planes[i] ) ) {
00754 VectorAdd( normal, pm->ps->velocity, pm->ps->velocity );
00755 break;
00756 }
00757 }
00758 if ( i < numplanes ) {
00759 continue;
00760 }
00761 }
00762 VectorCopy (normal, planes[numplanes]);
00763 numplanes++;
00764
00765
00766
00767
00768
00769
00770 for ( i = 0 ; i < numplanes ; i++ ) {
00771 into = DotProduct( pm->ps->velocity, planes[i] );
00772 if ( into >= 0.1 ) {
00773 continue;
00774 }
00775
00776
00777 if ( -into > pml.impactSpeed ) {
00778 pml.impactSpeed = -into;
00779 }
00780
00781
00782 PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP );
00783
00784
00785 PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP );
00786
00787
00788 for ( j = 0 ; j < numplanes ; j++ ) {
00789 if ( j == i ) {
00790 continue;
00791 }
00792 if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) {
00793 continue;
00794 }
00795
00796
00797 PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP );
00798 PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP );
00799
00800
00801 if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) {
00802 continue;
00803 }
00804
00805
00806 CrossProduct (planes[i], planes[j], dir);
00807 VectorNormalize( dir );
00808 d = DotProduct( dir, pm->ps->velocity );
00809 VectorScale( dir, d, clipVelocity );
00810
00811 CrossProduct (planes[i], planes[j], dir);
00812 VectorNormalize( dir );
00813 d = DotProduct( dir, endVelocity );
00814 VectorScale( dir, d, endClipVelocity );
00815
00816
00817 for ( k = 0 ; k < numplanes ; k++ ) {
00818 if ( k == i || k == j ) {
00819 continue;
00820 }
00821 if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) {
00822 continue;
00823 }
00824
00825
00826 VectorClear( pm->ps->velocity );
00827 return qtrue;
00828 }
00829 }
00830
00831
00832 VectorCopy( clipVelocity, pm->ps->velocity );
00833 VectorCopy( endClipVelocity, endVelocity );
00834 break;
00835 }
00836 }
00837
00838 if ( gravity ) {
00839 VectorCopy( endVelocity, pm->ps->velocity );
00840 }
00841
00842
00843 if ( pm->ps->pm_time ) {
00844 VectorCopy( primal_velocity, pm->ps->velocity );
00845 }
00846
00847 return ( bumpcount != 0 );
00848 }
00849
00850
00851
00852
00853
00854
00855
00856 void PM_StepSlideMove( qboolean gravity ) {
00857 vec3_t start_o, start_v;
00858 vec3_t down_o, down_v;
00859 trace_t trace;
00860
00861
00862 vec3_t up, down;
00863 float stepSize;
00864 qboolean isGiant = qfalse;
00865 bgEntity_t *pEnt;
00866 qboolean skipStep = qfalse;
00867
00868 VectorCopy (pm->ps->origin, start_o);
00869 VectorCopy (pm->ps->velocity, start_v);
00870
00871 if ( BG_InReboundHold( pm->ps->legsAnim ) )
00872 {
00873 gravity = qfalse;
00874 }
00875
00876 if ( PM_SlideMove( gravity ) == 0 ) {
00877 return;
00878 }
00879
00880 pEnt = pm_entSelf;
00881
00882 if (pm->ps->clientNum >= MAX_CLIENTS)
00883 {
00884 if (pEnt && pEnt->s.NPC_class == CLASS_VEHICLE &&
00885 pEnt->m_pVehicle && pEnt->m_pVehicle->m_pVehicleInfo->hoverHeight > 0)
00886 {
00887 return;
00888 }
00889 }
00890
00891 VectorCopy(start_o, down);
00892 down[2] -= STEPSIZE;
00893 pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);
00894 VectorSet(up, 0, 0, 1);
00895
00896 if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 ||
00897 DotProduct(trace.plane.normal, up) < 0.7))
00898 {
00899 return;
00900 }
00901
00902 VectorCopy (pm->ps->origin, down_o);
00903 VectorCopy (pm->ps->velocity, down_v);
00904
00905 VectorCopy (start_o, up);
00906
00907 if (pm->ps->clientNum >= MAX_CLIENTS)
00908 {
00909
00910 if (pEnt &&
00911 pEnt->s.NPC_class == CLASS_ATST ||
00912 (pEnt->s.NPC_class == CLASS_VEHICLE &&
00913 pEnt->m_pVehicle &&
00914 pEnt->m_pVehicle->m_pVehicleInfo->type == VH_WALKER)
00915 )
00916 {
00917 up[2] += 66.0f;
00918 isGiant = qtrue;
00919 }
00920 else if ( pEnt && pEnt->s.NPC_class == CLASS_RANCOR )
00921 {
00922 up[2] += 64.0f;
00923 isGiant = qtrue;
00924 }
00925 else
00926 {
00927 up[2] += STEPSIZE;
00928 }
00929 }
00930 else
00931 {
00932 up[2] += STEPSIZE;
00933 }
00934
00935
00936 pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask);
00937 if ( trace.allsolid ) {
00938 if ( pm->debugLevel ) {
00939 Com_Printf("%i:bend can't step\n", c_pmove);
00940 }
00941 return;
00942 }
00943
00944 stepSize = trace.endpos[2] - start_o[2];
00945
00946 VectorCopy (trace.endpos, pm->ps->origin);
00947 VectorCopy (start_v, pm->ps->velocity);
00948
00949 PM_SlideMove( gravity );
00950
00951
00952 VectorCopy (pm->ps->origin, down);
00953 down[2] -= stepSize;
00954 pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);
00955
00956 if ( pm->stepSlideFix )
00957 {
00958 if ( pm->ps->clientNum < MAX_CLIENTS
00959 && trace.plane.normal[2] < MIN_WALK_NORMAL )
00960 {
00961 vec3_t stepVec;
00962
00963
00964
00965
00966
00967
00968
00969 VectorSubtract( trace.endpos, down_o, stepVec );
00970 VectorNormalize( stepVec );
00971 if ( stepVec[2] > (1.0f-MIN_WALK_NORMAL) )
00972 {
00973 skipStep = qtrue;
00974 }
00975 }
00976 }
00977
00978 if ( !trace.allsolid
00979 && !skipStep )
00980 {
00981 if ( pm->ps->clientNum >= MAX_CLIENTS
00982 && isGiant
00983 && trace.entityNum < MAX_CLIENTS
00984 && pEnt
00985 && pEnt->s.NPC_class == CLASS_RANCOR )
00986 {
00987 if ( pm->stepSlideFix )
00988 {
00989 VectorCopy (down_o, pm->ps->origin);
00990 VectorCopy (down_v, pm->ps->velocity);
00991 }
00992 else
00993 {
00994 VectorCopy (start_o, pm->ps->origin);
00995 VectorCopy (start_v, pm->ps->velocity);
00996 }
00997 }
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010 else
01011 {
01012 VectorCopy (trace.endpos, pm->ps->origin);
01013 if ( pm->stepSlideFix )
01014 {
01015 if ( trace.fraction < 1.0 ) {
01016 PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
01017 }
01018 }
01019 }
01020 }
01021 else
01022 {
01023 if ( pm->stepSlideFix )
01024 {
01025 VectorCopy (down_o, pm->ps->origin);
01026 VectorCopy (down_v, pm->ps->velocity);
01027 }
01028 }
01029 if ( !pm->stepSlideFix )
01030 {
01031 if ( trace.fraction < 1.0 ) {
01032 PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
01033 }
01034 }
01035
01036 #if 0
01037
01038 pm->trace( &trace, pm->ps->origin, pm->