00001
00002
00003
00004
00005
00006 #include "q_shared.h"
00007 #include "bg_public.h"
00008 #include "bg_local.h"
00009 #include "bg_strap.h"
00010 #include "../ghoul2/G2.h"
00011
00012 #ifdef QAGAME
00013 #include "g_local.h"
00014 #endif
00015
00016 #define MAX_WEAPON_CHARGE_TIME 5000
00017
00018 #ifdef QAGAME
00019 extern void G_CheapWeaponFire(int entNum, int ev);
00020 extern qboolean TryGrapple(gentity_t *ent);
00021 extern void trap_FX_PlayEffect( const char *file, vec3_t org, vec3_t fwd, int vol, int rad );
00022 #endif
00023
00024 #include "../namespace_begin.h"
00025 extern qboolean BG_FullBodyTauntAnim( int anim );
00026 extern float PM_WalkableGroundDistance(void);
00027 extern qboolean PM_GroundSlideOkay( float zNormal );
00028 extern saberInfo_t *BG_MySaber( int clientNum, int saberNum );
00029
00030 pmove_t *pm;
00031 pml_t pml;
00032
00033 bgEntity_t *pm_entSelf = NULL;
00034 bgEntity_t *pm_entVeh = NULL;
00035
00036 qboolean gPMDoSlowFall = qfalse;
00037
00038 qboolean pm_cancelOutZoom = qfalse;
00039
00040
00041 float pm_stopspeed = 100.0f;
00042 float pm_duckScale = 0.50f;
00043 float pm_swimScale = 0.50f;
00044 float pm_wadeScale = 0.70f;
00045
00046 float pm_vehicleaccelerate = 36.0f;
00047 float pm_accelerate = 10.0f;
00048 float pm_airaccelerate = 1.0f;
00049 float pm_wateraccelerate = 4.0f;
00050 float pm_flyaccelerate = 8.0f;
00051
00052 float pm_friction = 6.0f;
00053 float pm_waterfriction = 1.0f;
00054 float pm_flightfriction = 3.0f;
00055 float pm_spectatorfriction = 5.0f;
00056
00057 int c_pmove = 0;
00058
00059 float forceSpeedLevels[4] =
00060 {
00061 1,
00062 1.25,
00063 1.5,
00064 1.75
00065 };
00066
00067 int forcePowerNeeded[NUM_FORCE_POWER_LEVELS][NUM_FORCE_POWERS] =
00068 {
00069 {
00070 999,
00071 999,
00072 999,
00073 999,
00074 999,
00075 999,
00076 999,
00077 999,
00078 999,
00079 999,
00080 999,
00081 999,
00082 999,
00083 999,
00084 999,
00085 999,
00086 999,
00087 999
00088
00089 },
00090 {
00091 65,
00092 10,
00093 50,
00094 20,
00095 20,
00096 20,
00097 30,
00098 1,
00099 50,
00100 50,
00101 50,
00102 50,
00103 50,
00104 20,
00105 20,
00106 0,
00107 2,
00108 20
00109
00110 },
00111 {
00112 60,
00113 10,
00114 50,
00115 20,
00116 20,
00117 20,
00118 30,
00119 1,
00120 50,
00121 25,
00122 25,
00123 33,
00124 33,
00125 20,
00126 20,
00127 0,
00128 1,
00129 20
00130
00131 },
00132 {
00133 50,
00134 10,
00135 50,
00136 20,
00137 20,
00138 20,
00139 60,
00140 1,
00141 50,
00142 10,
00143 10,
00144 25,
00145 25,
00146 20,
00147 20,
00148 0,
00149 0,
00150 20
00151
00152 }
00153 };
00154
00155 float forceJumpHeight[NUM_FORCE_POWER_LEVELS] =
00156 {
00157 32,
00158 96,
00159 192,
00160 384
00161 };
00162
00163 float forceJumpStrength[NUM_FORCE_POWER_LEVELS] =
00164 {
00165 JUMP_VELOCITY,
00166 420,
00167 590,
00168 840
00169 };
00170
00171
00172 bgEntity_t *PM_BGEntForNum( int num )
00173 {
00174 bgEntity_t *ent;
00175
00176 if (!pm)
00177 {
00178 assert(!"You cannot call PM_BGEntForNum outside of pm functions!");
00179 return NULL;
00180 }
00181
00182 if (!pm->baseEnt)
00183 {
00184 assert(!"Base entity address not set");
00185 return NULL;
00186 }
00187
00188 if (!pm->entSize)
00189 {
00190 assert(!"sizeof(ent) is 0, impossible (not set?)");
00191 return NULL;
00192 }
00193
00194 assert(num >= 0 && num < MAX_GENTITIES);
00195
00196 ent = (bgEntity_t *)((byte *)pm->baseEnt + pm->entSize*(num));
00197
00198 return ent;
00199 }
00200
00201 qboolean BG_SabersOff( playerState_t *ps )
00202 {
00203 if ( !ps->saberHolstered )
00204 {
00205 return qfalse;
00206 }
00207 if ( ps->fd.saberAnimLevelBase == SS_DUAL
00208 || ps->fd.saberAnimLevelBase == SS_STAFF )
00209 {
00210 if ( ps->saberHolstered < 2 )
00211 {
00212 return qfalse;
00213 }
00214 }
00215 return qtrue;
00216 }
00217
00218 qboolean BG_KnockDownable(playerState_t *ps)
00219 {
00220 if (!ps)
00221 {
00222 return qfalse;
00223 }
00224
00225 if (ps->m_iVehicleNum)
00226 {
00227 return qfalse;
00228 }
00229
00230 if (ps->emplacedIndex)
00231 {
00232 return qfalse;
00233 }
00234
00235
00236 return qtrue;
00237 }
00238
00239
00240 #ifndef __LCC__
00241 #define PM_INLINE ID_INLINE
00242 #else
00243 #define PM_INLINE //none
00244 #endif
00245
00246
00247 qboolean PM_INLINE PM_IsRocketTrooper(void)
00248 {
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258 return qfalse;
00259 }
00260
00261 int PM_GetSaberStance(void)
00262 {
00263 int anim = BOTH_STAND2;
00264 saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
00265 saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
00266
00267 if (!pm->ps->saberEntityNum)
00268 {
00269 return BOTH_STAND1;
00270 }
00271
00272 if ( BG_SabersOff( pm->ps ) )
00273 {
00274 return BOTH_STAND1;
00275 }
00276
00277 if ( saber1
00278 && saber1->readyAnim != -1 )
00279 {
00280 return saber1->readyAnim;
00281 }
00282
00283 if ( saber2
00284 && saber2->readyAnim != -1 )
00285 {
00286 return saber2->readyAnim;
00287 }
00288
00289 if ( saber1
00290 && saber2
00291 && !pm->ps->saberHolstered )
00292 {
00293 return BOTH_SABERDUAL_STANCE;
00294 }
00295
00296 switch ( pm->ps->fd.saberAnimLevel )
00297 {
00298 case SS_DUAL:
00299 anim = BOTH_SABERDUAL_STANCE;
00300 break;
00301 case SS_STAFF:
00302 anim = BOTH_SABERSTAFF_STANCE;
00303 break;
00304 case SS_FAST:
00305 case SS_TAVION:
00306 anim = BOTH_SABERFAST_STANCE;
00307 break;
00308 case SS_STRONG:
00309 anim = BOTH_SABERSLOW_STANCE;
00310 break;
00311 case SS_NONE:
00312 case SS_MEDIUM:
00313 case SS_DESANN:
00314 default:
00315 anim = BOTH_STAND2;
00316 break;
00317 }
00318 return anim;
00319 }
00320
00321 qboolean PM_DoSlowFall(void)
00322 {
00323 if ( ( (pm->ps->legsAnim) == BOTH_WALL_RUN_RIGHT || (pm->ps->legsAnim) == BOTH_WALL_RUN_LEFT ) && pm->ps->legsTimer > 500 )
00324 {
00325 return qtrue;
00326 }
00327
00328 return qfalse;
00329 }
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346 void PM_pitch_roll_for_slope( bgEntity_t *forwhom, vec3_t pass_slope, vec3_t storeAngles )
00347 {
00348 vec3_t slope;
00349 vec3_t nvf, ovf, ovr, startspot, endspot, new_angles = { 0, 0, 0 };
00350 float pitch, mod, dot;
00351
00352
00353 if( !pass_slope || VectorCompare( vec3_origin, pass_slope ) )
00354 {
00355 trace_t trace;
00356
00357 VectorCopy( pm->ps->origin, startspot );
00358 startspot[2] += pm->mins[2] + 4;
00359 VectorCopy( startspot, endspot );
00360 endspot[2] -= 300;
00361 pm->trace( &trace, pm->ps->origin, vec3_origin, vec3_origin, endspot, forwhom->s.number, MASK_SOLID );
00362
00363
00364
00365 if ( trace.fraction >= 1.0 )
00366 return;
00367
00368 if( !( &trace.plane ) )
00369 return;
00370
00371 if ( VectorCompare( vec3_origin, trace.plane.normal ) )
00372 return;
00373
00374 VectorCopy( trace.plane.normal, slope );
00375 }
00376 else
00377 {
00378 VectorCopy( pass_slope, slope );
00379 }
00380
00381 if ( forwhom->s.NPC_class == CLASS_VEHICLE )
00382 {
00383 Vehicle_t *pVeh = forwhom->m_pVehicle;
00384 vec3_t tempAngles;
00385
00386 tempAngles[PITCH] = tempAngles[ROLL] = 0;
00387 tempAngles[YAW] = pVeh->m_vOrientation[YAW];
00388 AngleVectors( tempAngles, ovf, ovr, NULL );
00389 }
00390 else
00391 {
00392 AngleVectors( pm->ps->viewangles, ovf, ovr, NULL );
00393 }
00394
00395 vectoangles( slope, new_angles );
00396 pitch = new_angles[PITCH] + 90;
00397 new_angles[ROLL] = new_angles[PITCH] = 0;
00398
00399 AngleVectors( new_angles, nvf, NULL, NULL );
00400
00401 mod = DotProduct( nvf, ovr );
00402
00403 if ( mod<0 )
00404 mod = -1;
00405 else
00406 mod = 1;
00407
00408 dot = DotProduct( nvf, ovf );
00409
00410 if ( storeAngles )
00411 {
00412 storeAngles[PITCH] = dot * pitch;
00413 storeAngles[ROLL] = ((1-Q_fabs(dot)) * pitch * mod);
00414 }
00415 else
00416 {
00417 float oldmins2;
00418
00419 pm->ps->viewangles[PITCH] = dot * pitch;
00420 pm->ps->viewangles[ROLL] = ((1-Q_fabs(dot)) * pitch * mod);
00421 oldmins2 = pm->mins[2];
00422 pm->mins[2] = -24 + 12 * fabs(pm->ps->viewangles[PITCH])/180.0f;
00423
00424 if ( oldmins2 > pm->mins[2] )
00425 {
00426
00427 pm->ps->origin[2] += (oldmins2 - pm->mins[2]);
00428
00429
00430 }
00431 }
00432
00433
00434
00435
00436
00437
00438
00439 }
00440
00441 #define FLY_NONE 0
00442 #define FLY_NORMAL 1
00443 #define FLY_VEHICLE 2
00444 #define FLY_HOVER 3
00445 static int pm_flying = FLY_NONE;
00446
00447 void PM_SetSpecialMoveValues (void)
00448 {
00449 bgEntity_t *pEnt;
00450
00451 if (pm->ps->clientNum < MAX_CLIENTS)
00452 {
00453 pm_flying = FLY_NONE;
00454 return;
00455 }
00456
00457
00458 pm_flying = FLY_NONE;
00459
00460 pEnt = pm_entSelf;
00461
00462 if ( pEnt )
00463 {
00464 if ( (pm->ps->eFlags2&EF2_FLYING) )
00465 {
00466 pm_flying = FLY_NORMAL;
00467 }
00468 else if ( pEnt->s.NPC_class == CLASS_VEHICLE )
00469 {
00470 if ( pEnt->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER )
00471 {
00472 pm_flying = FLY_VEHICLE;
00473 }
00474 else if ( pEnt->m_pVehicle->m_pVehicleInfo->hoverHeight > 0 )
00475 {
00476 pm_flying = FLY_HOVER;
00477 }
00478 }
00479 }
00480 }
00481
00482 static void PM_SetVehicleAngles( vec3_t normal )
00483 {
00484 bgEntity_t *pEnt = pm_entSelf;
00485 Vehicle_t *pVeh;
00486 vec3_t vAngles;
00487 float vehicleBankingSpeed;
00488 float pitchBias;
00489 int i;
00490
00491 if ( !pEnt || pEnt->s.NPC_class != CLASS_VEHICLE )
00492 {
00493 return;
00494 }
00495
00496 pVeh = pEnt->m_pVehicle;
00497
00498
00499 vehicleBankingSpeed = (pVeh->m_pVehicleInfo->bankingSpeed*32.0f)*pml.frametime;
00500
00501 if ( vehicleBankingSpeed <= 0
00502 || ( pVeh->m_pVehicleInfo->pitchLimit == 0 && pVeh->m_pVehicleInfo->rollLimit == 0 ) )
00503 {
00504 return;
00505 }
00506
00507
00508
00509
00510 if ( pVeh->m_pVehicleInfo->type == VH_FIGHTER )
00511 {
00512 pitchBias = 0.0f;
00513 }
00514 else
00515 {
00516
00517
00518 pitchBias = 90.0f*pVeh->m_pVehicleInfo->centerOfGravity[0];
00519 }
00520
00521 VectorClear( vAngles );
00522 if ( pm->waterlevel > 0 )
00523 {
00524
00525
00526 vAngles[PITCH] += (pm->ps->viewangles[PITCH]-vAngles[PITCH])*0.75f + (pitchBias*0.5);
00527 }
00528 else if ( normal )
00529 {
00530 PM_pitch_roll_for_slope( pEnt, normal, vAngles );
00531 if ( (pml.groundTrace.contents&(CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) )
00532 {
00533
00534
00535 vAngles[PITCH] += (pm->ps->viewangles[PITCH]-vAngles[PITCH])*0.5f + (pitchBias*0.5f);
00536 }
00537 }
00538 else
00539 {
00540
00541 vAngles[PITCH] = pm->ps->viewangles[PITCH]*0.5f + pitchBias;
00542
00543 vehicleBankingSpeed *= (0.125f*pml.frametime);
00544 }
00545
00546
00547 if ( pVeh->m_pVehicleInfo->rollLimit > 0 )
00548 {
00549
00550 vec3_t velocity;
00551 float speed;
00552 VectorCopy( pm->ps->velocity, velocity );
00553 velocity[2] = 0.0f;
00554 speed = VectorNormalize( velocity );
00555 if ( speed > 32.0f || speed < -32.0f )
00556 {
00557 vec3_t rt, tempVAngles;
00558 float side;
00559 float dp;
00560
00561
00562
00563 speed *= sin( (150 + pml.frametime) * 0.003 );
00564
00565
00566 if ( speed > 60 )
00567 speed = 60;
00568
00569 VectorCopy( pVeh->m_vOrientation, tempVAngles );
00570 tempVAngles[ROLL] = 0;
00571 AngleVectors( tempVAngles, NULL, rt, NULL );
00572 dp = DotProduct( velocity, rt );
00573 side = speed * dp;
00574 vAngles[ROLL] -= side;
00575 }
00576 }
00577
00578
00579 if ( pVeh->m_pVehicleInfo->pitchLimit != -1 )
00580 {
00581 if ( vAngles[PITCH] > pVeh->m_pVehicleInfo->pitchLimit )
00582 {
00583 vAngles[PITCH] = pVeh->m_pVehicleInfo->pitchLimit;
00584 }
00585 else if ( vAngles[PITCH] < -pVeh->m_pVehicleInfo->pitchLimit )
00586 {
00587 vAngles[PITCH] = -pVeh->m_pVehicleInfo->pitchLimit;
00588 }
00589 }
00590
00591 if ( vAngles[ROLL] > pVeh->m_pVehicleInfo->rollLimit )
00592 {
00593 vAngles[ROLL] = pVeh->m_pVehicleInfo->rollLimit;
00594 }
00595 else if ( vAngles[ROLL] < -pVeh->m_pVehicleInfo->rollLimit )
00596 {
00597 vAngles[ROLL] = -pVeh->m_pVehicleInfo->rollLimit;
00598 }
00599
00600
00601 for ( i = 0; i < 3; i++ )
00602 {
00603 if ( i == YAW )
00604 {
00605 continue;
00606 }
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620 {
00621 if ( pVeh->m_vOrientation[i] >= vAngles[i] + vehicleBankingSpeed )
00622 {
00623 pVeh->m_vOrientation[i] -= vehicleBankingSpeed;
00624 }
00625 else if ( pVeh->m_vOrientation[i] <= vAngles[i] - vehicleBankingSpeed )
00626 {
00627 pVeh->m_vOrientation[i] += vehicleBankingSpeed;
00628 }
00629 else
00630 {
00631 pVeh->m_vOrientation[i] = vAngles[i];
00632 }
00633 }
00634 }
00635 }
00636
00637 #ifndef QAGAME
00638 extern vmCvar_t cg_paused;
00639 #endif
00640
00641 void BG_ExternThisSoICanRecompileInDebug( Vehicle_t *pVeh, playerState_t *riderPS )
00642 {
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674 }
00675
00676 void BG_VehicleTurnRateForSpeed( Vehicle_t *pVeh, float speed, float *mPitchOverride, float *mYawOverride )
00677 {
00678 if ( pVeh && pVeh->m_pVehicleInfo )
00679 {
00680 float speedFrac = 1.0f;
00681 if ( pVeh->m_pVehicleInfo->speedDependantTurning )
00682 {
00683 if ( pVeh->m_LandTrace.fraction >= 1.0f
00684 || pVeh->m_LandTrace.plane.normal[2] < MIN_LANDING_SLOPE )
00685 {
00686 speedFrac = (speed/(pVeh->m_pVehicleInfo->speedMax*0.75f));
00687 if ( speedFrac < 0.25f )
00688 {
00689 speedFrac = 0.25f;
00690 }
00691 else if ( speedFrac > 1.0f )
00692 {
00693 speedFrac = 1.0f;
00694 }
00695 }
00696 }
00697 if ( pVeh->m_pVehicleInfo->mousePitch )
00698 {
00699 *mPitchOverride = pVeh->m_pVehicleInfo->mousePitch*speedFrac;
00700 }
00701 if ( pVeh->m_pVehicleInfo->mouseYaw )
00702 {
00703 *mYawOverride = pVeh->m_pVehicleInfo->mouseYaw*speedFrac;
00704 }
00705 }
00706 }
00707
00708 #include "../namespace_end.h"
00709
00710
00711 #ifdef QAGAME
00712 typedef struct gentity_s gentity_t;
00713 gentity_t *G_PlayEffectID(const int fxID, vec3_t org, vec3_t ang);
00714 #endif
00715
00716 #include "../namespace_begin.h"
00717
00718 static void PM_GroundTraceMissed( void );
00719 void PM_HoverTrace( void )
00720 {
00721 Vehicle_t *pVeh;
00722 float hoverHeight;
00723 vec3_t point, vAng, fxAxis[3];
00724 trace_t *trace;
00725 float relativeWaterLevel;
00726
00727 bgEntity_t *pEnt = pm_entSelf;
00728 if ( !pEnt || pEnt->s.NPC_class != CLASS_VEHICLE )
00729 {
00730 return;
00731 }
00732
00733 pVeh = pEnt->m_pVehicle;
00734 hoverHeight = pVeh->m_pVehicleInfo->hoverHeight;
00735 trace = &pml.groundTrace;
00736
00737 pml.groundPlane = qfalse;
00738
00739
00740 relativeWaterLevel = pm->waterlevel;
00741 if ( pm->waterlevel && relativeWaterLevel >= 0 )
00742 {
00743 if ( pVeh->m_pVehicleInfo->bouyancy <= 0.0f )
00744 {
00745 }
00746 else
00747 {
00748 float floatHeight = (pVeh->m_pVehicleInfo->bouyancy * ((pm->maxs[2]-pm->mins[2])*0.5f)) - (hoverHeight*0.5f);
00749 if ( relativeWaterLevel > floatHeight )
00750 {
00751 pm->ps->velocity[2] += (relativeWaterLevel - floatHeight) * pVeh->m_fTimeModifier;
00752 }
00753 }
00754
00755 if (pm->waterlevel <= 1)
00756 {
00757 if ( fabs(pm->ps->velocity[0]) + fabs(pm->ps->velocity[1]) > 100 )
00758 {
00759 if ( Q_irand( pml.frametime, 100 ) >= 50 )
00760 {
00761 vec3_t wakeOrg;
00762
00763 vAng[PITCH] = vAng[ROLL] = 0;
00764 vAng[YAW] = pVeh->m_vOrientation[YAW];
00765 AngleVectors( vAng, fxAxis[2], fxAxis[1], fxAxis[0] );
00766 VectorCopy( pm->ps->origin, wakeOrg );
00767
00768 if (pm->waterlevel >= 2)
00769 {
00770 wakeOrg[2] = pm->ps->origin[2]+16;
00771 }
00772 else
00773 {
00774 wakeOrg[2] = pm->ps->origin[2];
00775 }
00776 #ifdef QAGAME //yeah, this is kind of crappy and makes no use of prediction whatsoever
00777 if ( pVeh->m_pVehicleInfo->iWakeFX )
00778 {
00779
00780
00781 G_AddEvent((gentity_t *)pEnt, EV_PLAY_EFFECT_ID, pVeh->m_pVehicleInfo->iWakeFX);
00782 }
00783 #endif
00784 }
00785 }
00786 }
00787 }
00788 else
00789 {
00790 int traceContents;
00791 float minNormal = (float)MIN_WALK_NORMAL;
00792 minNormal = pVeh->m_pVehicleInfo->maxSlope;
00793
00794 point[0] = pm->ps->origin[0];
00795 point[1] = pm->ps->origin[1];
00796 point[2] = pm->ps->origin[2] - hoverHeight;
00797
00798
00799
00800
00801
00802
00803 traceContents = pm->tracemask;
00804 if ( pVeh->m_pVehicleInfo->bouyancy >= 2.0f )
00805 {
00806 traceContents |= (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA);
00807 }
00808 pm->trace( trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, traceContents );
00809 if (trace->plane.normal[0] > 0.5f || trace->plane.normal[0] < -0.5f ||
00810 trace->plane.normal[1] > 0.5f || trace->plane.normal[1] < -0.5f)
00811 {
00812 float d = fabs(trace->plane.normal[0]);
00813 float e = fabs(trace->plane.normal[1]);
00814 if (e > d)
00815 {
00816 d = e;
00817 }
00818 pm->ps->velocity[2] = -300.0f*d;
00819 }
00820 else if ( trace->plane.normal[2] >= minNormal )
00821 {
00822 if ( trace->fraction < 1.0f )
00823 {
00824 float hoverForce = pVeh->m_pVehicleInfo->hoverStrength;
00825 if ( trace->fraction > 0.5f )
00826 {
00827 pm->ps->velocity[2] += (1.0f-trace->fraction)*hoverForce*pVeh->m_fTimeModifier;
00828 }
00829 else
00830 {
00831 pm->ps->velocity[2] += (0.5f-(trace->fraction*trace->fraction))*hoverForce*2.0f*pVeh->m_fTimeModifier;
00832 }
00833 if ( (trace->contents&(CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) )
00834 {
00835 if ( fabs(pm->ps->velocity[0]) + fabs(pm->ps->velocity[1]) > 100 )
00836 {
00837 if ( Q_irand( pml.frametime, 100 ) >= 50 )
00838 {
00839 vAng[PITCH] = vAng[ROLL] = 0;
00840 vAng[YAW] = pVeh->m_vOrientation[YAW];
00841 AngleVectors( vAng, fxAxis[2], fxAxis[1], fxAxis[0] );
00842 #ifdef QAGAME
00843 if ( pVeh->m_pVehicleInfo->iWakeFX )
00844 {
00845 G_PlayEffectID( pVeh->m_pVehicleInfo->iWakeFX, trace->endpos, fxAxis[0] );
00846 }
00847 #endif
00848 }
00849 }
00850 }
00851 pml.groundPlane = qtrue;
00852 }
00853 }
00854 }
00855 if ( pml.groundPlane )
00856 {
00857 PM_SetVehicleAngles( pml.groundTrace.plane.normal );
00858
00859 pVeh->m_ulFlags &= ~VEH_FLYING;
00860
00861 pVeh->m_vAngularVelocity = 0.0f;
00862 }
00863 else
00864 {
00865 PM_SetVehicleAngles( NULL );
00866
00867 pVeh->m_ulFlags |= VEH_FLYING;
00868
00869
00870 if (pVeh->m_vAngularVelocity==0.0f)
00871 {
00872 pVeh->m_vAngularVelocity = pVeh->m_vOrientation[YAW] - pVeh->m_vPrevOrientation[YAW];
00873 if (pVeh->m_vAngularVelocity<-15.0f)
00874 {
00875 pVeh->m_vAngularVelocity = -15.0f;
00876 }
00877 if (pVeh->m_vAngularVelocity> 15.0f)
00878 {
00879 pVeh->m_vAngularVelocity = 15.0f;
00880 }
00881 }
00882
00883 if (pVeh->m_vAngularVelocity > 0.0f)
00884 {
00885 pVeh->m_vAngularVelocity -= pml.frametime;
00886 if (pVeh->m_vAngularVelocity < 0.0f)
00887 {
00888 pVeh->m_vAngularVelocity = 0.0f;
00889 }
00890 }
00891 else if (pVeh->m_vAngularVelocity < 0.0f)
00892 {
00893 pVeh->m_vAngularVelocity += pml.frametime;
00894 if (pVeh->m_vAngularVelocity > 0.0f)
00895 {
00896 pVeh->m_vAngularVelocity = 0.0f;
00897 }
00898 }
00899 }
00900 PM_GroundTraceMissed();
00901 }
00902
00903
00904
00905
00906
00907
00908
00909
00910 void PM_AddEvent( int newEvent ) {
00911 BG_AddPredictableEventToPlayerstate( newEvent, 0, pm->ps );
00912 }
00913
00914 void PM_AddEventWithParm( int newEvent, int parm )
00915 {
00916 BG_AddPredictableEventToPlayerstate( newEvent, parm, pm->ps );
00917 }
00918
00919
00920
00921
00922
00923
00924 void PM_AddTouchEnt( int entityNum ) {
00925 int i;
00926
00927 if ( entityNum == ENTITYNUM_WORLD ) {
00928 return;
00929 }
00930 if ( pm->numtouch == MAXTOUCH ) {
00931 return;
00932 }
00933
00934
00935 for ( i = 0 ; i < pm->numtouch ; i++ ) {
00936 if ( pm->touchents[ i ] == entityNum ) {
00937 return;
00938 }
00939 }
00940
00941
00942 pm->touchents[pm->numtouch] = entityNum;
00943 pm->numtouch++;
00944 }
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954 void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ) {
00955 float backoff;
00956 float change;
00957 float oldInZ;
00958 int i;
00959
00960 if ( (pm->ps->pm_flags&PMF_STUCK_TO_WALL) )
00961 {
00962 VectorCopy( in, out );
00963 return;
00964 }
00965 oldInZ = in[2];
00966
00967 backoff = DotProduct (in, normal);
00968
00969 if ( backoff < 0 ) {
00970 backoff *= overbounce;
00971 } else {
00972 backoff /= overbounce;
00973 }
00974
00975 for ( i=0 ; i<3 ; i++ ) {
00976 change = normal[i]*backoff;
00977 out[i] = in[i] - change;
00978 }
00979 if ( pm->stepSlideFix )
00980 {
00981 if ( pm->ps->clientNum < MAX_CLIENTS
00982 && pm->ps->groundEntityNum != ENTITYNUM_NONE
00983 && normal[2] < MIN_WALK_NORMAL )
00984 {
00985 out[2] = oldInZ;
00986 }
00987 }
00988 }
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998 static void PM_Friction( void ) {
00999 vec3_t vec;
01000 float *vel;
01001 float speed, newspeed, control;
01002 float drop;
01003 bgEntity_t *pEnt = NULL;
01004
01005 vel = pm->ps->velocity;
01006
01007 VectorCopy( vel, vec );
01008 if ( pml.walking ) {
01009 vec[2] = 0;
01010 }
01011
01012 speed = VectorLength(vec);
01013 if (speed < 1) {
01014 vel[0] = 0;
01015 vel[1] = 0;
01016 if (pm->ps->pm_type == PM_SPECTATOR)
01017 {
01018 vel[2] = 0;
01019 }
01020
01021 return;
01022 }
01023
01024 drop = 0;
01025
01026 if (pm->ps->clientNum >= MAX_CLIENTS)
01027 {
01028 pEnt = pm_entSelf;
01029 }
01030
01031
01032 if (pm_flying != FLY_VEHICLE &&
01033 pEnt &&
01034 pEnt->s.NPC_class == CLASS_VEHICLE &&
01035 pEnt->m_pVehicle &&
01036 pEnt->m_pVehicle->m_pVehicleInfo->type != VH_ANIMAL &&
01037 pEnt->m_pVehicle->m_pVehicleInfo->type != VH_WALKER &&
01038 pEnt->m_pVehicle->m_pVehicleInfo->friction )
01039 {
01040 float friction = pEnt->m_pVehicle->m_pVehicleInfo->friction;
01041 if ( !(pm->ps->pm_flags & PMF_TIME_KNOCKBACK) )
01042 {
01043 control = speed < pm_stopspeed ? pm_stopspeed : speed;
01044 drop += control*friction*pml.frametime;
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066 }
01067 }
01068 else if ( pm_flying != FLY_NORMAL && pm_flying != FLY_VEHICLE )
01069 {
01070
01071 if ( pm->waterlevel <= 1 ) {
01072 if ( pml.walking && !(pml.groundTrace.surfaceFlags & SURF_SLICK) ) {
01073
01074 if ( ! (pm->ps->pm_flags & PMF_TIME_KNOCKBACK) ) {
01075 control = speed < pm_stopspeed ? pm_stopspeed : speed;
01076 drop += control*pm_friction*pml.frametime;
01077 }
01078 }
01079 }
01080 }
01081
01082 if ( pm_flying == FLY_VEHICLE )
01083 {
01084 if ( !(pm->ps->pm_flags & PMF_TIME_KNOCKBACK) )
01085 {
01086 control = speed;
01087 drop += control*pm_friction*pml.frametime;
01088 }
01089 }
01090
01091
01092 if ( pm->waterlevel ) {
01093 drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime;
01094 }
01095
01096 else if ( pm->ps->groundEntityNum < MAX_CLIENTS )
01097 {
01098 drop = 0;
01099 }
01100
01101 if ( pm->ps->pm_type == PM_SPECTATOR || pm->ps->pm_type == PM_FLOAT )
01102 {
01103 if (pm->ps->pm_type == PM_FLOAT)
01104 {
01105 drop += speed*0.1*pml.frametime;
01106 }
01107 else
01108 {
01109 drop += speed*pm_spectatorfriction*pml.frametime;
01110 }
01111 }
01112
01113
01114 newspeed = speed - drop;
01115 if (newspeed < 0) {
01116 newspeed = 0;
01117 }
01118 newspeed /= speed;
01119
01120 vel[0] = vel[0] * newspeed;
01121 vel[1] = vel[1] * newspeed;
01122 vel[2] = vel[2] * newspeed;
01123 }
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133 static void PM_Accelerate( vec3_t wishdir, float wishspeed, float accel )
01134 {
01135 if (pm->gametype != GT_SIEGE
01136 || pm->ps->m_iVehicleNum
01137 || pm->ps->clientNum >= MAX_CLIENTS
01138 || pm->ps->pm_type != PM_NORMAL)
01139 {
01140 int i;
01141 float addspeed, accelspeed, currentspeed;
01142
01143 currentspeed = DotProduct (pm->ps->velocity, wishdir);
01144 addspeed = wishspeed - currentspeed;
01145 if (addspeed <= 0 && pm->ps->clientNum < MAX_CLIENTS) {
01146 return;
01147 }
01148
01149 if (addspeed < 0)
01150 {
01151 accelspeed = (-accel)*pml.frametime*wishspeed;
01152 if (accelspeed < addspeed) {
01153 accelspeed = addspeed;
01154 }
01155 }
01156 else
01157 {
01158 accelspeed = accel*pml.frametime*wishspeed;
01159 if (accelspeed > addspeed) {
01160 accelspeed = addspeed;
01161 }
01162 }
01163
01164 for (i=0 ; i<3 ; i++) {
01165 pm->ps->velocity[i] += accelspeed*wishdir[i];
01166 }
01167 }
01168 else
01169 {
01170 vec3_t wishVelocity;
01171 vec3_t pushDir;
01172 float pushLen;
01173 float canPush;
01174
01175 VectorScale( wishdir, wishspeed, wishVelocity );
01176 VectorSubtract( wishVelocity, pm->ps->velocity, pushDir );
01177 pushLen = VectorNormalize( pushDir );
01178
01179 canPush = accel*pml.frametime*wishspeed;
01180 if (canPush > pushLen) {
01181 canPush = pushLen;
01182 }
01183
01184 VectorMA( pm->ps->velocity, canPush, pushDir, pm->ps->velocity );
01185 }
01186 }
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199 static float PM_CmdScale( usercmd_t *cmd ) {
01200 int max;
01201 float total;
01202 float scale;
01203 int umove = 0;
01204
01205
01206 max = abs( cmd->forwardmove );
01207 if ( abs( cmd->rightmove ) > max ) {
01208 max = abs( cmd->rightmove );
01209 }
01210 if ( abs( umove ) > max ) {
01211 max = abs( umove );
01212 }
01213 if ( !max ) {
01214 return 0;
01215 }
01216
01217 total = sqrt( (float)(cmd->forwardmove * cmd->forwardmove
01218 + cmd->rightmove * cmd->rightmove + umove * umove) );
01219 scale = (float)pm->ps->speed * max / ( 127.0 * total );
01220
01221 return scale;
01222 }
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233 static void PM_SetMovementDir( void ) {
01234 if ( pm->cmd.forwardmove || pm->cmd.rightmove ) {
01235 if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove > 0 ) {
01236 pm->ps->movementDir = 0;
01237 } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove > 0 ) {
01238 pm->ps->movementDir = 1;
01239 } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove == 0 ) {
01240 pm->ps->movementDir = 2;
01241 } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove < 0 ) {
01242 pm->ps->movementDir = 3;
01243 } else if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove < 0 ) {
01244 pm->ps->movementDir = 4;
01245 } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove < 0 ) {
01246 pm->ps->movementDir = 5;
01247 } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove == 0 ) {
01248 pm->ps->movementDir = 6;
01249 } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove > 0 ) {
01250 pm->ps->movementDir = 7;
01251 }
01252 } else {
01253
01254
01255
01256 if ( pm->ps->movementDir == 2 ) {
01257 pm->ps->movementDir = 1;
01258 } else if ( pm->ps->movementDir == 6 ) {
01259 pm->ps->movementDir = 7;
01260 }
01261 }
01262 }
01263
01264 #define METROID_JUMP 1
01265
01266 qboolean PM_ForceJumpingUp(void)
01267 {
01268 if ( !(pm->ps->fd.forcePowersActive&(1<<FP_LEVITATION)) && pm->ps->fd.forceJumpCharge )
01269 {
01270 return qfalse;
01271 }
01272
01273 if ( BG_InSpecialJump( pm->ps->legsAnim ) )
01274 {
01275 return qfalse;
01276 }
01277
01278 if (BG_SaberInSpecial(pm->ps->saberMove))
01279 {
01280 return qfalse;
01281 }
01282
01283 if (BG_SaberInSpecialAttack(pm->ps->legsAnim))
01284 {
01285 return qfalse;
01286 }
01287
01288 if (BG_HasYsalamiri(pm->gametype, pm->ps))
01289 {
01290 return qfalse;
01291 }
01292
01293 if (!BG_CanUseFPNow(pm->gametype, pm->ps, pm-&g