00001
00002
00003
00004
00005
00006
00007
00008 #include "cg_local.h"
00009
00010 static pmove_t cg_pmove;
00011
00012 static int cg_numSolidEntities;
00013 static centity_t *cg_solidEntities[MAX_ENTITIES_IN_SNAPSHOT];
00014 static int cg_numTriggerEntities;
00015 static centity_t *cg_triggerEntities[MAX_ENTITIES_IN_SNAPSHOT];
00016
00017
00018 static CGAME_INLINE qboolean CG_Piloting(int vehNum)
00019 {
00020 centity_t *veh;
00021
00022 if (!vehNum)
00023 {
00024 return qfalse;
00025 }
00026
00027 veh = &cg_entities[vehNum];
00028
00029 if (veh->currentState.owner != cg.predictedPlayerState.clientNum)
00030 {
00031 return qfalse;
00032 }
00033
00034 return qtrue;
00035 }
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 void CG_BuildSolidList( void ) {
00047 int i;
00048 centity_t *cent;
00049 snapshot_t *snap;
00050 entityState_t *ent;
00051 vec3_t difference;
00052 float dsquared;
00053
00054 cg_numSolidEntities = 0;
00055 cg_numTriggerEntities = 0;
00056
00057 if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {
00058 snap = cg.nextSnap;
00059 } else {
00060 snap = cg.snap;
00061 }
00062
00063 for ( i = 0 ; i < snap->numEntities ; i++ ) {
00064 cent = &cg_entities[ snap->entities[ i ].number ];
00065 ent = ¢->currentState;
00066
00067 if ( ent->eType == ET_ITEM || ent->eType == ET_PUSH_TRIGGER || ent->eType == ET_TELEPORT_TRIGGER ) {
00068 cg_triggerEntities[cg_numTriggerEntities] = cent;
00069 cg_numTriggerEntities++;
00070 continue;
00071 }
00072
00073 if ( cent->nextState.solid ) {
00074 cg_solidEntities[cg_numSolidEntities] = cent;
00075 cg_numSolidEntities++;
00076 continue;
00077 }
00078 }
00079
00080
00081
00082
00083
00084
00085
00086
00087 if (cg_numSolidEntities < MAX_ENTITIES_IN_SNAPSHOT)
00088 {
00089 vec3_t playerMins = {-15, -15, DEFAULT_MINS_2};
00090 vec3_t playerMaxs = {15, 15, DEFAULT_MAXS_2};
00091 int i, j, k;
00092
00093 i = playerMaxs[0];
00094 if (i<1)
00095 i = 1;
00096 if (i>255)
00097 i = 255;
00098
00099
00100 j = (-playerMins[2]);
00101 if (j<1)
00102 j = 1;
00103 if (j>255)
00104 j = 255;
00105
00106
00107 k = (playerMaxs[2]+32);
00108 if (k<1)
00109 k = 1;
00110 if (k>255)
00111 k = 255;
00112
00113 cg_solidEntities[cg_numSolidEntities] = &cg_entities[cg.predictedPlayerState.clientNum];
00114 cg_solidEntities[cg_numSolidEntities]->currentState.solid = (k<<16) | (j<<8) | i;
00115
00116 cg_numSolidEntities++;
00117 }
00118
00119 dsquared = 5000+500;
00120 dsquared *= dsquared;
00121
00122 for(i=0;i<cg_numpermanents;i++)
00123 {
00124 cent = cg_permanents[i];
00125 VectorSubtract(cent->lerpOrigin, snap->ps.origin, difference);
00126 if (cent->currentState.eType == ET_TERRAIN ||
00127 ((difference[0]*difference[0]) + (difference[1]*difference[1]) + (difference[2]*difference[2])) <= dsquared)
00128 {
00129 cent->currentValid = qtrue;
00130 if ( cent->nextState.solid )
00131 {
00132 cg_solidEntities[cg_numSolidEntities] = cent;
00133 cg_numSolidEntities++;
00134 }
00135 }
00136 else
00137 {
00138 cent->currentValid = qfalse;
00139 }
00140 }
00141 }
00142
00143 static CGAME_INLINE qboolean CG_VehicleClipCheck(centity_t *ignored, trace_t *trace)
00144 {
00145 if (!trace || trace->entityNum < 0 || trace->entityNum >= ENTITYNUM_WORLD)
00146 {
00147 return qtrue;
00148 }
00149
00150 if (ignored->currentState.eType != ET_PLAYER &&
00151 ignored->currentState.eType != ET_NPC)
00152 {
00153 return qtrue;
00154 }
00155
00156 if (ignored->currentState.m_iVehicleNum)
00157 {
00158
00159 centity_t *otherguy = &cg_entities[trace->entityNum];
00160
00161 if (otherguy->currentState.eType != ET_PLAYER &&
00162 otherguy->currentState.eType != ET_NPC)
00163 {
00164 return qtrue;
00165 }
00166
00167 if (otherguy->currentState.m_iVehicleNum)
00168 {
00169 int index;
00170
00171 if (ignored->currentState.eType == ET_PLAYER
00172 || (ignored->currentState.eType == ET_NPC && ignored->currentState.NPC_class != CLASS_VEHICLE) )
00173 {
00174 index = ignored->currentState.m_iVehicleNum;
00175 }
00176 else
00177 {
00178 index = ignored->currentState.m_iVehicleNum-1;
00179 }
00180
00181 if (index == otherguy->currentState.number)
00182 {
00183 return qfalse;
00184 }
00185 else
00186 {
00187 if (otherguy->currentState.eType == ET_PLAYER
00188 || (otherguy->currentState.eType == ET_NPC && otherguy->currentState.NPC_class != CLASS_VEHICLE) )
00189 {
00190 if (otherguy->currentState.m_iVehicleNum==ignored->currentState.number)
00191 {
00192 return qfalse;
00193 }
00194 }
00195 }
00196 }
00197 }
00198
00199 return qtrue;
00200 }
00201
00202
00203
00204 #pragma warning(disable : 4701) //local variable may be used without having been initialized
00205
00206
00207
00208
00209
00210
00211 #include "../namespace_begin.h"
00212 extern void BG_VehicleAdjustBBoxForOrientation( Vehicle_t *veh, vec3_t origin, vec3_t mins, vec3_t maxs,
00213 int clientNum, int tracemask,
00214 void (*localTrace)(trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentMask));
00215 #include "../namespace_end.h"
00216 static void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
00217 int skipNumber, int mask, trace_t *tr, qboolean g2Check ) {
00218 int i, x, zd, zu;
00219 trace_t trace, oldTrace;
00220 entityState_t *ent;
00221 clipHandle_t cmodel;
00222 vec3_t bmins, bmaxs;
00223 vec3_t origin, angles;
00224 centity_t *cent;
00225 centity_t *ignored = NULL;
00226
00227 if (skipNumber != -1 && skipNumber != ENTITYNUM_NONE)
00228 {
00229 ignored = &cg_entities[skipNumber];
00230 }
00231
00232 for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
00233 cent = cg_solidEntities[ i ];
00234 ent = ¢->currentState;
00235
00236 if ( ent->number == skipNumber ) {
00237 continue;
00238 }
00239
00240 if ( ent->number > MAX_CLIENTS &&
00241 (ent->genericenemyindex-MAX_GENTITIES==cg.predictedPlayerState.clientNum || ent->genericenemyindex-MAX_GENTITIES==cg.predictedVehicleState.clientNum) )
00242
00243 {
00244 continue;
00245 }
00246
00247 if ( ent->solid == SOLID_BMODEL ) {
00248
00249 cmodel = trap_CM_InlineModel( ent->modelindex );
00250 VectorCopy( cent->lerpAngles, angles );
00251 BG_EvaluateTrajectory( ¢->currentState.pos, cg.physicsTime, origin );
00252 } else {
00253
00254 x = (ent->solid & 255);
00255 zd = ((ent->solid>>8) & 255);
00256 zu = ((ent->solid>>16) & 255) - 32;
00257
00258 bmins[0] = bmins[1] = -x;
00259 bmaxs[0] = bmaxs[1] = x;
00260 bmins[2] = -zd;
00261 bmaxs[2] = zu;
00262
00263 if (ent->eType == ET_NPC && ent->NPC_class == CLASS_VEHICLE &&
00264 cent->m_pVehicle)
00265 {
00266 float *old = cent->m_pVehicle->m_vOrientation;
00267 cent->m_pVehicle->m_vOrientation = ¢->lerpAngles[0];
00268 BG_VehicleAdjustBBoxForOrientation(cent->m_pVehicle, cent->lerpOrigin, bmins, bmaxs,
00269 cent->currentState.number, MASK_PLAYERSOLID, NULL);
00270 cent->m_pVehicle->m_vOrientation = old;
00271 }
00272
00273 cmodel = trap_CM_TempBoxModel( bmins, bmaxs );
00274 VectorCopy( vec3_origin, angles );
00275
00276 VectorCopy( cent->lerpOrigin, origin );
00277 }
00278
00279
00280 trap_CM_TransformedBoxTrace ( &trace, start, end,
00281 mins, maxs, cmodel, mask, origin, angles);
00282 trace.entityNum = trace.fraction != 1.0 ? ent->number : ENTITYNUM_NONE;
00283
00284 if (g2Check || (ignored && ignored->currentState.m_iVehicleNum))
00285 {
00286
00287
00288 oldTrace = *tr;
00289 }
00290
00291 if (trace.allsolid || trace.fraction < tr->fraction) {
00292 trace.entityNum = ent->number;
00293 *tr = trace;
00294 } else if (trace.startsolid) {
00295 tr->startsolid = qtrue;
00296
00297
00298 tr->entityNum = trace.entityNum = ent->number;
00299 }
00300 if ( tr->allsolid )
00301 {
00302 if (ignored && ignored->currentState.m_iVehicleNum)
00303 {
00304 trace.entityNum = ent->number;
00305 if (CG_VehicleClipCheck(ignored, &trace))
00306 {
00307 return;
00308 }
00309 else
00310 {
00311 trace = oldTrace;
00312 *tr = trace;
00313 }
00314 }
00315 else
00316 {
00317 return;
00318 }
00319 }
00320
00321 if (g2Check)
00322 {
00323 if (trace.entityNum == ent->number && cent->ghoul2)
00324 {
00325 CG_G2TraceCollide(&trace, mins, maxs, start, end);
00326
00327 if (trace.entityNum == ENTITYNUM_NONE)
00328 {
00329 trace = oldTrace;
00330 *tr = trace;
00331 }
00332 }
00333 }
00334
00335 if (ignored && ignored->currentState.m_iVehicleNum)
00336 {
00337 centity_t *hit = &cg_entities[trace.entityNum];
00338 if (!CG_VehicleClipCheck(ignored, &trace))
00339 {
00340 trace = oldTrace;
00341 *tr = trace;
00342 }
00343 else if (hit->currentState.eType == ET_MISSILE &&
00344 hit->currentState.owner == ignored->currentState.number)
00345 {
00346 trace = oldTrace;
00347 *tr = trace;
00348 }
00349 }
00350 }
00351 }
00352 #pragma warning(default : 4701) //local variable may be used without having been initialized
00353
00354
00355
00356
00357
00358
00359 void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
00360 int skipNumber, int mask ) {
00361 trace_t t;
00362
00363 trap_CM_BoxTrace ( &t, start, end, mins, maxs, 0, mask);
00364 t.entityNum = t.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
00365
00366 CG_ClipMoveToEntities (start, mins, maxs, end, skipNumber, mask, &t, qfalse);
00367
00368 *result = t;
00369 }
00370
00371
00372
00373
00374
00375
00376 void CG_G2Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
00377 int skipNumber, int mask ) {
00378 trace_t t;
00379
00380 trap_CM_BoxTrace ( &t, start, end, mins, maxs, 0, mask);
00381 t.entityNum = t.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
00382
00383 CG_ClipMoveToEntities (start, mins, maxs, end, skipNumber, mask, &t, qtrue);
00384
00385 *result = t;
00386 }
00387
00388
00389
00390
00391
00392
00393 int CG_PointContents( const vec3_t point, int passEntityNum ) {
00394 int i;
00395 entityState_t *ent;
00396 centity_t *cent;
00397 clipHandle_t cmodel;
00398 int contents;
00399
00400 contents = trap_CM_PointContents (point, 0);
00401
00402 for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
00403 cent = cg_solidEntities[ i ];
00404
00405 ent = ¢->currentState;
00406
00407 if ( ent->number == passEntityNum ) {
00408 continue;
00409 }
00410
00411 if (ent->solid != SOLID_BMODEL) {
00412 continue;
00413 }
00414
00415 cmodel = trap_CM_InlineModel( ent->modelindex );
00416 if ( !cmodel ) {
00417 continue;
00418 }
00419
00420 contents |= trap_CM_TransformedPointContents( point, cmodel, ent->origin, ent->angles );
00421 }
00422
00423 return contents;
00424 }
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435 static void CG_InterpolatePlayerState( qboolean grabAngles ) {
00436 float f;
00437 int i;
00438 playerState_t *out;
00439 snapshot_t *prev, *next;
00440
00441 out = &cg.predictedPlayerState;
00442 prev = cg.snap;
00443 next = cg.nextSnap;
00444
00445 *out = cg.snap->ps;
00446
00447
00448 if ( grabAngles ) {
00449 usercmd_t cmd;
00450 int cmdNum;
00451
00452 cmdNum = trap_GetCurrentCmdNumber();
00453 trap_GetUserCmd( cmdNum, &cmd );
00454
00455 PM_UpdateViewAngles( out, &cmd );
00456 }
00457
00458
00459 if ( cg.nextFrameTeleport ) {
00460 return;
00461 }
00462
00463 if ( !next || next->serverTime <= prev->serverTime ) {
00464 return;
00465 }
00466
00467 f = (float)( cg.time - prev->serverTime ) / ( next->serverTime - prev->serverTime );
00468
00469 i = next->ps.bobCycle;
00470 if ( i < prev->ps.bobCycle ) {
00471 i += 256;
00472 }
00473 out->bobCycle = prev->ps.bobCycle + f * ( i - prev->ps.bobCycle );
00474
00475 for ( i = 0 ; i < 3 ; i++ ) {
00476 out->origin[i] = prev->ps.origin[i] + f * (next->ps.origin[i] - prev->ps.origin[i] );
00477 if ( !grabAngles ) {
00478 out->viewangles[i] = LerpAngle(
00479 prev->ps.viewangles[i], next->ps.viewangles[i], f );
00480 }
00481 out->velocity[i] = prev->ps.velocity[i] +
00482 f * (next->ps.velocity[i] - prev->ps.velocity[i] );
00483 }
00484
00485 }
00486
00487 static void CG_InterpolateVehiclePlayerState( qboolean grabAngles ) {
00488 float f;
00489 int i;
00490 playerState_t *out;
00491 snapshot_t *prev, *next;
00492
00493 out = &cg.predictedVehicleState;
00494 prev = cg.snap;
00495 next = cg.nextSnap;
00496
00497 *out = cg.snap->vps;
00498
00499
00500 if ( grabAngles ) {
00501 usercmd_t cmd;
00502 int cmdNum;
00503
00504 cmdNum = trap_GetCurrentCmdNumber();
00505 trap_GetUserCmd( cmdNum, &cmd );
00506
00507 PM_UpdateViewAngles( out, &cmd );
00508 }
00509
00510
00511 if ( cg.nextFrameTeleport ) {
00512 return;
00513 }
00514
00515 if ( !next || next->serverTime <= prev->serverTime ) {
00516 return;
00517 }
00518
00519 f = (float)( cg.time - prev->serverTime ) / ( next->serverTime - prev->serverTime );
00520
00521 i = next->vps.bobCycle;
00522 if ( i < prev->vps.bobCycle ) {
00523 i += 256;
00524 }
00525 out->bobCycle = prev->vps.bobCycle + f * ( i - prev->vps.bobCycle );
00526
00527 for ( i = 0 ; i < 3 ; i++ ) {
00528 out->origin[i] = prev->vps.origin[i] + f * (next->vps.origin[i] - prev->vps.origin[i] );
00529 if ( !grabAngles ) {
00530 out->viewangles[i] = LerpAngle(
00531 prev->vps.viewangles[i], next->vps.viewangles[i], f );
00532 }
00533 out->velocity[i] = prev->vps.velocity[i] +
00534 f * (next->vps.velocity[i] - prev->vps.velocity[i] );
00535 }
00536
00537 }
00538
00539
00540
00541
00542
00543
00544 static void CG_TouchItem( centity_t *cent ) {
00545 gitem_t *item;
00546
00547 if ( !cg_predictItems.integer ) {
00548 return;
00549 }
00550 if ( !BG_PlayerTouchesItem( &cg.predictedPlayerState, ¢->currentState, cg.time ) ) {
00551 return;
00552 }
00553
00554 if (cent->currentState.brokenLimbs)
00555 {
00556 return;
00557 }
00558
00559 if (cent->currentState.eFlags & EF_ITEMPLACEHOLDER)
00560 {
00561 return;
00562 }
00563
00564 if (cent->currentState.eFlags & EF_NODRAW)
00565 {
00566 return;
00567 }
00568
00569
00570 if ( cent->miscTime == cg.time ) {
00571 return;
00572 }
00573
00574 if ( !BG_CanItemBeGrabbed( cgs.gametype, ¢->currentState, &cg.predictedPlayerState ) ) {
00575 return;
00576 }
00577
00578 item = &bg_itemlist[ cent->currentState.modelindex ];
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615 if( cgs.gametype == GT_CTF || cgs.gametype == GT_CTY ) {
00616 if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_RED &&
00617 item->giTag == PW_REDFLAG)
00618 return;
00619 if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_BLUE &&
00620 item->giTag == PW_BLUEFLAG)
00621 return;
00622 }
00623
00624 if (item->giType == IT_POWERUP &&
00625 (item->giTag == PW_FORCE_ENLIGHTENED_LIGHT || item->giTag == PW_FORCE_ENLIGHTENED_DARK))
00626 {
00627 if (item->giTag == PW_FORCE_ENLIGHTENED_LIGHT)
00628 {
00629 if (cg.predictedPlayerState.fd.forceSide != FORCE_LIGHTSIDE)
00630 {
00631 return;
00632 }
00633 }
00634 else
00635 {
00636 if (cg.predictedPlayerState.fd.forceSide != FORCE_DARKSIDE)
00637 {
00638 return;
00639 }
00640 }
00641 }
00642
00643
00644
00645 BG_AddPredictableEventToPlayerstate( EV_ITEM_PICKUP, cent->currentState.number , &cg.predictedPlayerState);
00646
00647
00648 cent->currentState.eFlags |= EF_NODRAW;
00649
00650
00651 cent->miscTime = cg.time;
00652
00653
00654 if ( item->giType == IT_WEAPON ) {
00655 cg.predictedPlayerState.stats[ STAT_WEAPONS ] |= 1 << item->giTag;
00656 if ( !cg.predictedPlayerState.ammo[ item->giTag ] ) {
00657 cg.predictedPlayerState.ammo[ item->giTag ] = 1;
00658 }
00659 }
00660 }
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670 static void CG_TouchTriggerPrediction( void ) {
00671 int i;
00672 trace_t trace;
00673 entityState_t *ent;
00674 clipHandle_t cmodel;
00675 centity_t *cent;
00676 qboolean spectator;
00677
00678
00679 if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
00680 return;
00681 }
00682
00683 spectator = ( cg.predictedPlayerState.pm_type == PM_SPECTATOR );
00684
00685 if ( cg.predictedPlayerState.pm_type != PM_NORMAL && cg.predictedPlayerState.pm_type != PM_JETPACK && cg.predictedPlayerState.pm_type != PM_FLOAT && !spectator ) {
00686 return;
00687 }
00688
00689 for ( i = 0 ; i < cg_numTriggerEntities ; i++ ) {
00690 cent = cg_triggerEntities[ i ];
00691 ent = ¢->currentState;
00692
00693 if ( ent->eType == ET_ITEM && !spectator ) {
00694 CG_TouchItem( cent );
00695 continue;
00696 }
00697
00698 if ( ent->solid != SOLID_BMODEL ) {
00699 continue;
00700 }
00701
00702 cmodel = trap_CM_InlineModel( ent->modelindex );
00703 if ( !cmodel ) {
00704 continue;
00705 }
00706
00707 trap_CM_BoxTrace( &trace, cg.predictedPlayerState.origin, cg.predictedPlayerState.origin,
00708 cg_pmove.mins, cg_pmove.maxs, cmodel, -1 );
00709
00710 if ( !trace.startsolid ) {
00711 continue;
00712 }
00713
00714 if ( ent->eType == ET_TELEPORT_TRIGGER ) {
00715 cg.hyperspace = qtrue;
00716 } else if ( ent->eType == ET_PUSH_TRIGGER ) {
00717 BG_TouchJumpPad( &cg.predictedPlayerState, ent );
00718 }
00719 }
00720
00721
00722 if ( cg.predictedPlayerState.jumppad_frame != cg.predictedPlayerState.pmove_framecount ) {
00723 cg.predictedPlayerState.jumppad_frame = 0;
00724 cg.predictedPlayerState.jumppad_ent = 0;
00725 }
00726 }
00727
00728 #if 0
00729 static ID_INLINE void CG_EntityStateToPlayerState( entityState_t *s, playerState_t *ps )
00730 {
00731
00732 ps->clientNum = s->number;
00733 VectorCopy( s->pos.trBase, ps->origin );
00734 VectorCopy( s->pos.trDelta, ps->velocity );
00735 ps->saberLockFrame = s->forceFrame;
00736 ps->legsAnim = s->legsAnim;
00737 ps->torsoAnim = s->torsoAnim;
00738 ps->legsFlip = s->legsFlip;
00739 ps->torsoFlip = s->torsoFlip;
00740 ps->clientNum = s->clientNum;
00741 ps->saberMove = s->saberMove;
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834 }
00835 #endif
00836
00837
00838
00839
00840 #ifdef _XBOX
00841
00842 struct psLinkedNode_t
00843 {
00844 playerState_t ps;
00845 psLinkedNode_t *next;
00846 };
00847
00848 #define CG_SEND_PS_POOL_SIZE 64
00849 psLinkedNode_t cgSendPSPool[ CG_SEND_PS_POOL_SIZE ];
00850 psLinkedNode_t *cgSendPSFreeList;
00851
00852 #else
00853 playerState_t cgSendPSPool[ MAX_GENTITIES ];
00854 #endif
00855
00856 playerState_t *cgSendPS[MAX_GENTITIES];
00857
00858 #ifdef _XBOX
00859 void AllocSendPlayerstate(int entNum)
00860 {
00861 if (cgSendPS[entNum])
00862 {
00863
00864 return;
00865 }
00866
00867 if (!cgSendPSFreeList)
00868 Com_Error( ERR_DROP, "ERROR: No free playerstates! Increase CG_SEND_PS_POOL_SIZE\n" );
00869
00870 cgSendPS[entNum] = &cgSendPSFreeList->ps;
00871 cgSendPSFreeList = cgSendPSFreeList->next;
00872 }
00873 #endif
00874
00875
00876
00877 #ifdef _PROFILE_ES_TO_PS
00878 int g_cgEStoPSTime = 0;
00879 #endif
00880
00881
00882
00883
00884 void CG_PmoveClientPointerUpdate()
00885 {
00886 int i;
00887
00888 memset(&cgSendPSPool[0], 0, sizeof(cgSendPSPool));
00889
00890 for ( i = 0 ; i < MAX_GENTITIES ; i++ )
00891 {
00892 #ifdef _XBOX
00893 cgSendPS[i] = NULL;
00894 #else
00895 cgSendPS[i] = &cgSendPSPool[i];
00896 #endif
00897
00898
00899 cg_entities[i].playerState = cgSendPS[i];
00900 }
00901
00902 #ifdef _XBOX
00903 for ( i = 0; i < CG_SEND_PS_POOL_SIZE - 1; i++ )
00904 {
00905 cgSendPSPool[i].next = &cgSendPSPool[i+1];
00906 }
00907
00908
00909 cgSendPSFreeList = &cgSendPSPool[0];
00910 #endif
00911
00912
00913 cg_pmove.baseEnt = (bgEntity_t *)cg_entities;
00914 cg_pmove.entSize = sizeof(centity_t);
00915
00916 cg_pmove.ghoul2 = NULL;
00917 }
00918
00919
00920 qboolean CG_UsingEWeb(void)
00921 {
00922 if (cg.predictedPlayerState.weapon == WP_EMPLACED_GUN && cg.predictedPlayerState.emplacedIndex &&
00923 cg_entities[cg.predictedPlayerState.emplacedIndex].currentState.weapon == WP_NONE)
00924 {
00925 return qtrue;
00926 }
00927
00928 return qfalse;
00929 }
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957 extern void CG_Cube( vec3_t mins, vec3_t maxs, vec3_t color, float alpha );
00958 extern vmCvar_t cg_showVehBounds;
00959 pmove_t cg_vehPmove;
00960 qboolean cg_vehPmoveSet = qfalse;
00961
00962 #pragma warning(disable : 4701) //local variable may be used without having been initialized
00963 void CG_PredictPlayerState( void ) {
00964 int cmdNum, current, i;
00965 playerState_t oldPlayerState;
00966 playerState_t oldVehicleState;
00967 qboolean moved;
00968 usercmd_t oldestCmd;
00969 usercmd_t latestCmd;
00970 centity_t *pEnt;
00971 clientInfo_t *ci;
00972
00973 cg.hyperspace = qfalse;
00974
00975
00976
00977
00978 if ( !cg.validPPS ) {
00979 cg.validPPS = qtrue;
00980 cg.predictedPlayerState = cg.snap->ps;
00981 if (CG_Piloting(cg.snap->ps.m_iVehicleNum))
00982 {
00983 cg.predictedVehicleState = cg.snap->vps;
00984 }
00985 }
00986
00987
00988 if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ) {
00989 CG_InterpolatePlayerState( qfalse );
00990 if (CG_Piloting(cg.predictedPlayerState.m_iVehicleNum))
00991 {
00992 CG_InterpolateVehiclePlayerState(qfalse);
00993 }
00994 return;
00995 }
00996
00997
00998 if ( cg_nopredict.integer || cg_synchronousClients.integer || CG_UsingEWeb() ) {
00999 CG_InterpolatePlayerState( qtrue );
01000 if (CG_Piloting(cg.predictedPlayerState.m_iVehicleNum))
01001 {
01002 CG_InterpolateVehiclePlayerState(qtrue);
01003 }
01004 return;
01005 }
01006
01007
01008 cg_pmove.ps = &cg.predictedPlayerState;
01009 cg_pmove.trace = CG_Trace;
01010 cg_pmove.pointcontents = CG_PointContents;
01011
01012 pEnt = &cg_entities[cg.predictedPlayerState.clientNum];
01013
01014 if (cg_pmove.ghoul2 != pEnt->ghoul2)
01015 {
01016 if (cg.snap &&
01017 pEnt->ghoul2 &&
01018 !(cg.snap->ps.pm_flags & PMF_FOLLOW) &&
01019 cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR)
01020 {
01021 cg_pmove.ghoul2 = pEnt->ghoul2;
01022 cg_pmove.g2Bolts_LFoot = trap_G2API_AddBolt(pEnt->ghoul2, 0, "*l_leg_foot");
01023 cg_pmove.g2Bolts_RFoot = trap_G2API_AddBolt(pEnt->ghoul2, 0, "*r_leg_foot");
01024 }
01025 else
01026 {
01027 cg_pmove.ghoul2 = NULL;
01028 }
01029 }
01030
01031 ci = &cgs.clientinfo[cg.predictedPlayerState.clientNum];
01032
01033
01034 VectorCopy(pEnt->modelScale, cg_pmove.modelScale);
01035
01036
01037 if ( cg_pmove.ps->pm_type == PM_DEAD ) {
01038 cg_pmove.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
01039 }
01040 else {
01041 cg_pmove.tracemask = MASK_PLAYERSOLID;
01042 }
01043 if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
01044 cg_pmove.tracemask &= ~CONTENTS_BODY;
01045 }
01046 cg_pmove.noFootsteps = ( cgs.dmflags & DF_NO_FOOTSTEPS ) > 0;
01047
01048
01049 oldPlayerState = cg.predictedPlayerState;
01050 if (CG_Piloting(cg.predictedPlayerState.m_iVehicleNum))
01051 {
01052 oldVehicleState = cg.predictedVehicleState;
01053 }
01054
01055 current = trap_GetCurrentCmdNumber();
01056
01057
01058
01059
01060 cmdNum = current - CMD_BACKUP + 1;
01061 trap_GetUserCmd( cmdNum, &oldestCmd );
01062 if ( oldestCmd.serverTime > cg.snap->ps.commandTime
01063 && oldestCmd.serverTime < cg.time ) {
01064 if ( cg_showmiss.integer ) {
01065 CG_Printf ("exceeded PACKET_BACKUP on commands\n");
01066 }
01067 return;
01068 }
01069
01070
01071 trap_GetUserCmd( current, &latestCmd );
01072
01073
01074
01075
01076
01077 if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {
01078 cg.nextSnap->ps.slopeRecalcTime = cg.predictedPlayerState.slopeRecalcTime;
01079 cg.predictedPlayerState = cg.nextSnap->ps;
01080 if (CG_Piloting(cg.nextSnap->ps.m_iVehicleNum))
01081 {
01082 cg.predictedVehicleState = cg.nextSnap->vps;
01083 }
01084 cg.physicsTime = cg.nextSnap->serverTime;
01085 } else {
01086 cg.snap->ps.slopeRecalcTime = cg.predictedPlayerState.slopeRecalcTime;
01087 cg.predictedPlayerState = cg.snap->ps;
01088 if (CG_Piloting(cg.snap->ps.m_iVehicleNum))
01089 {
01090 cg.predictedVehicleState = cg.snap->vps;
01091 }
01092 cg.physicsTime = cg.snap->serverTime;
01093 }
01094
01095 if ( pmove_msec.integer < 8 ) {
01096 trap_Cvar_Set("pmove_msec", "8");
01097 }
01098 else if (pmove_msec.integer > 33) {
01099 trap_Cvar_Set("pmove_msec", "33");
01100 }
01101
01102 cg_pmove.pmove_fixed = pmove_fixed.integer;
01103 cg_pmove.pmove_msec = pmove_msec.integer;
01104
01105 for ( i = 0 ; i < MAX_GENTITIES ; i++ )
01106 {
01107
01108
01109
01110
01111
01112 if (cg_entities[i].currentState.eType == ET_PLAYER ||
01113 cg_entities[i].currentState.eType == ET_NPC)
01114 {
01115
01116 #ifdef _XBOX
01117 AllocSendPlayerstate(i);
01118 #endif
01119 VectorCopy( cg_entities[i].currentState.pos.trBase, cgSendPS[i]->origin );
01120 VectorCopy( cg_entities[i].currentState.pos.trDelta, cgSendPS[i]->velocity );
01121 cgSendPS[i]->saberLockFrame = cg_entities[i].currentState.forceFrame;
01122 cgSendPS[i]->legsAnim = cg_entities[i].currentState.legsAnim;
01123 cgSendPS[i]->torsoAnim = cg_entities[i].currentState.torsoAnim;
01124 cgSendPS[i]->legsFlip = cg_entities[i].currentState.legsFlip;
01125 cgSendPS[i]->torsoFlip = cg_entities[i].currentState.torsoFlip;
01126 cgSendPS[i]->clientNum = cg_entities[i].currentState.clientNum;
01127 cgSendPS[i]->saberMove = cg_entities[i].currentState.saberMove;
01128 }
01129 }
01130
01131 if (CG_Piloting(cg.predictedPlayerState.m_iVehicleNum))
01132 {
01133 cg_entities[cg.predictedPlayerState.clientNum].playerState = &cg.predictedPlayerState;
01134 cg_entities[cg.predictedPlayerState.m_iVehicleNum].playerState = &cg.predictedVehicleState;
01135
01136
01137
01138 cg.predictedVehicleState.commandTime = cg.predictedPlayerState.commandTime;
01139 }
01140
01141
01142 moved = qfalse;
01143 for ( cmdNum = current - CMD_BACKUP + 1 ; cmdNum <= current ; cmdNum++ ) {
01144
01145 trap_GetUserCmd( cmdNum, &cg_pmove.cmd );
01146
01147 if ( cg_pmove.pmove_fixed ) {
01148 PM_UpdateViewAngles( cg_pmove.ps, &cg_pmove.cmd );
01149 }
01150
01151
01152 if ( cg_pmove.cmd.serverTime <= cg.predictedPlayerState.commandTime )
01153 {
01154 continue;
01155 }
01156
01157
01158 if ( cg_pmove.cmd.serverTime > latestCmd.serverTime ) {
01159 continue;
01160 }
01161
01162
01163
01164
01165
01166
01167 if ( CG_Piloting(oldPlayerState.m_iVehicleNum) &&
01168 cg.predictedVehicleState.commandTime == oldVehicleState.commandTime )
01169 {
01170 vec3_t delta;
01171 float len;
01172
01173 if ( cg.thisFrameTeleport ) {
01174
01175 VectorClear( cg.predictedError );
01176 if ( cg_showVehMiss.integer ) {
01177 CG_Printf( "VEH PredictionTeleport\n" );
01178 }
01179 cg.thisFrameTeleport = qfalse;
01180 } else {
01181 vec3_t adjusted;
01182 CG_AdjustPositionForMover( cg.predictedVehicleState.origin,
01183 cg.predictedVehicleState.groundEntityNum, cg.physicsTime, cg.oldTime, adjusted );
01184
01185 if ( cg_showVehMiss.integer ) {
01186 if (!VectorCompare( oldVehicleState.origin, adjusted )) {
01187 CG_Printf("VEH prediction error\n");
01188 }
01189 }
01190 VectorSubtract( oldVehicleState.origin, adjusted, delta );
01191 len = VectorLength( delta );
01192 if ( len > 0.1 ) {
01193 if ( cg_showVehMiss.integer ) {
01194 CG_Printf("VEH Prediction miss: %f\n", len);
01195 }
01196 if ( cg_errorDecay.integer ) {
01197 int t;
01198 float f;
01199
01200 t = cg.time - cg.predictedErrorTime;
01201 f = ( cg_errorDecay.value - t ) / cg_errorDecay.value;
01202 if ( f < 0 ) {
01203 f = 0;
01204 }
01205 if ( f > 0 && cg_showVehMiss.integer ) {
01206 CG_Printf("VEH Double prediction decay: %f\n", f);
01207 }
01208 VectorScale( cg.predictedError, f, cg.predictedError );
01209 } else {
01210 VectorClear( cg.predictedError );
01211 }
01212 VectorAdd( delta, cg.predictedError, cg.predictedError );
01213 cg.predictedErrorTime = cg.oldTime;
01214 }
01215
01216 if ( cg_showVehMiss.integer ) {
01217 if (!VectorCompare( oldVehicleState.vehOrientation, cg.predictedVehicleState.vehOrientation )) {
01218 CG_Printf("VEH orient prediction error\n");
01219 CG_Printf("VEH pitch prediction miss: %f\n", AngleSubtract( oldVehicleState.vehOrientation[0], cg.predictedVehicleState.vehOrientation[0] ) );
01220 CG_Printf("VEH yaw prediction miss: %f\n", AngleSubtract( oldVehicleState.vehOrientation[1], cg.predictedVehicleState.vehOrientation[1] ) );
01221 CG_Printf("VEH roll prediction miss: %f\n", AngleSubtract( oldVehicleState.vehOrientation[2], cg.predictedVehicleState.vehOrientation[2] ) );
01222 }
01223 }
01224 }
01225 }
01226 else if ( !oldPlayerState.m_iVehicleNum &&
01227 cg.predictedPlayerState.commandTime == oldPlayerState.commandTime )
01228 {
01229 vec3_t delta;
01230 float len;
01231
01232 if ( cg.thisFrameTeleport ) {
01233
01234 VectorClear( cg.predictedError );
01235 if ( cg_showmiss.integer ) {
01236 CG_Printf( "PredictionTeleport\n" );
01237 }
01238 cg.thisFrameTeleport = qfalse;
01239 } else {
01240 vec3_t adjusted;
01241 CG_AdjustPositionForMover( cg.predictedPlayerState.origin,
01242 cg.predictedPlayerState.groundEntityNum, cg.physicsTime, cg.oldTime, adjusted );
01243
01244 if ( cg_showmiss.integer ) {
01245 if (!VectorCompare( oldPlayerState.origin, adjusted )) {
01246 CG_Printf("prediction error\n");
01247 }
01248 }
01249 VectorSubtract( oldPlayerState.origin, adjusted, delta );
01250 len = VectorLength( delta );
01251 if ( len > 0.1 ) {
01252 if ( cg_showmiss.integer ) {
01253 CG_Printf("Prediction miss: %f\n", len);
01254 }
01255 if ( cg_errorDecay.integer ) {
01256 int t;
01257 float f;
01258
01259 t = cg.time - cg.predictedErrorTime;
01260 f = ( cg_errorDecay.value - t ) / cg_errorDecay.value;
01261 if ( f < 0 ) {
01262 f = 0;
01263 }
01264 if ( f > 0 && cg_showmiss.integer ) {
01265 CG_Printf("Double prediction decay: %f\n", f);
01266 }
01267 VectorScale( cg.predictedError, f, cg.predictedError );
01268 } else {
01269 VectorClear( cg.predictedError );
01270 }
01271 VectorAdd( delta, cg.predictedError, cg.predictedError );
01272 cg.predictedErrorTime = cg.oldTime;
01273 }
01274 }
01275 }
01276
01277 if ( cg_pmove.pmove_fixed ) {
01278 cg_pmove.cmd.serverTime = ((cg_pmove.cmd.serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer;
01279 }
01280
01281 cg_pmove.animations = bgAllAnims[pEnt->localAnimIndex].anims;
01282 cg_pmove.gametype = cgs.gametype;
01283
01284 cg_pmove.debugMelee = cgs.debugMelee;
01285 cg_pmove.stepSlideFix = cgs.stepSlideFix;
01286 cg_pmove.noSpecMove = cgs.noSpecMove;
01287
01288 cg_pmove.nonHumanoid = (pEnt->localAnimIndex > 0);
01289
01290 if (cg.snap && cg.snap->ps.saberLockTime > cg.time)
01291 {
01292 centity_t *blockOpp = &cg_entities[cg.snap->ps.saberLockEnemy];
01293
01294 if (blockOpp)
01295 {
01296 vec3_t lockDir, lockAng;
01297
01298 VectorSubtract( blockOpp->lerpOrigin, cg.snap->ps.origin, lockDir );
01299 vectoangles(lockDir, lockAng);
01300
01301 VectorCopy(lockAng, cg_pmove.ps->viewangles);
01302 }
01303 }
01304
01305
01306 cg_pmove.ps->fd.saberAnimLevelBase = cg_pmove.ps->fd.saberAnimLevel;
01307 if ( cg_pmove.ps->saberHolstered == 1 )
01308 {
01309 if ( ci->saber[0].numBlades > 0 )
01310 {
01311 cg_pmove.ps->fd.saberAnimLevelBase = SS_STAFF;
01312 }
01313 else if ( ci->saber[1].model[0] )
01314 {
01315 cg_pmove.ps->fd.saberAnimLevelBase = SS_DUAL;
01316 }
01317 }
01318
01319 Pmove (&cg_pmove);
01320
01321 if (CG_Piloting(cg.predictedPlayerState.m_iVehicleNum) &&
01322 cg.predictedPlayerState.pm_type != PM_INTERMISSION)
01323 {
01324 centity_t *veh = &cg_entities[cg.predictedPlayerState.m_iVehicleNum];
01325 int x, zd, zu;
01326
01327 if (veh->m_pVehicle)
01328 {
01329 veh->m_pVehicle->m_vOrientation = &cg.predictedVehicleState.vehOrientation[0];
01330
01331
01332 veh->m_pVehicle->m_iRemovedSurfaces = cg.predictedVehicleState.vehSurfaces;
01333
01334 trap_GetUserCmd( cmdNum, &veh->m_pVehicle->m_ucmd );
01335
01336 if ( veh->m_pVehicle->m_ucmd.buttons & BUTTON_TALK )
01337 {
01338 veh->m_pVehicle->m_ucmd.buttons = BUTTON_TALK;
01339 veh->m_pVehicle->m_ucmd.forwardmove = 0;
01340 veh->m_pVehicle->m_ucmd.rightmove = 0;
01341 veh->m_pVehicle->m_ucmd.upmove = 0;
01342 }
01343 cg_vehPmove.ps = &cg.predictedVehicleState;
01344 cg_vehPmove.animations = bgAllAnims[veh->localAnimIndex].anims;
01345
01346 memcpy(&cg_vehPmove.cmd, &veh->m_pVehicle->m_ucmd, sizeof(usercmd_t));
01347
01348
01349
01350
01351
01352 cg_vehPmove.gametype = cgs.gametype;
01353 cg_vehPmove.ghoul2 = veh->ghoul2;
01354
01355 cg_vehPmove.nonHumanoid = (veh->localAnimIndex > 0);
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368 x = (veh->currentState.solid)&255;
01369 zd = (veh->currentState.solid>>8)&255;
01370 zu = (veh->currentState.solid>>15)&255;
01371
01372 zu -= 32;
01373 zd = -zd;
01374
01375
01376 cg_vehPmove.mins[0] = cg_vehPmove.mins[1] = -x;
01377 cg_vehPmove.maxs[0] = cg_vehPmove.maxs[1] = x;
01378 cg_vehPmove.mins[2] = zd;
01379 cg_vehPmove.maxs[2] = zu;
01380
01381 VectorCopy(veh->modelScale, cg_vehPmove.modelScale);
01382
01383 if (!cg_vehPmoveSet)
01384 {
01385 cg_vehPmove.trace = CG_Trace;
01386 cg_vehPmove.pointcontents = CG_PointContents;
01387 cg_vehPmove.tracemask = MASK_PLAYERSOLID;
01388 cg_vehPmove.debugLevel = 0;
01389 cg_vehPmove.g2Bolts_LFoot = -1;
01390 cg_vehPmove.g2Bolts_RFoot = -1;
01391
01392 cg_vehPmove.baseEnt = (bgEntity_t *)cg_entities;
01393 cg_vehPmove.entSize = sizeof(centity_t);
01394
01395 cg_vehPmoveSet = qtrue;
01396 }
01397
01398 cg_vehPmove.noFootsteps = ( cgs.dmflags & DF_NO_FOOTSTEPS ) > 0;
01399 cg_vehPmove.pmove_fixed = pmove_fixed.integer;
01400 cg_vehPmove.pmove_msec = pmove_msec.integer;
01401
01402 cg_entities[cg.predictedPlayerState.clientNum].playerState = &cg.predictedPlayerState;
01403 veh->playerState = &cg.predictedVehicleState;
01404
01405
01406 veh->m_pVehicle->m_iBoarding = cg.predictedVehicleState.vehBoarding;
01407
01408 Pmove(&cg_vehPmove);
01409
01410
01411
01412
01413
01414
01415 if ( cg_showVehBounds.integer )
01416 {
01417 vec3_t NPCDEBUG_RED = {1.0, 0.0, 0.0};
01418 vec3_t absmin, absmax;
01419 VectorAdd( cg_vehPmove.ps->origin, cg_vehPmove.mins, absmin );
01420 VectorAdd( cg_vehPmove.ps->origin, cg_vehPmove.maxs, absmax );
01421 CG_Cube( absmin, absmax, NPCDEBUG_RED, 0.25 );
01422 }
01423 }
01424 }
01425
01426 moved = qtrue;
01427
01428
01429 CG_TouchTriggerPrediction();
01430
01431
01432
01433 }
01434
01435 if ( cg_showmiss.integer > 1 ) {
01436 CG_Printf( "[%i : %i] ", cg_pmove.cmd.serverTime, cg.time );
01437 }
01438
01439 if ( !moved ) {
01440 if ( cg_showmiss.integer ) {
01441 CG_Printf( "not moved\n" );
01442 }
01443 goto revertES;
01444 }
01445
01446 if (CG_Piloting(cg.predictedPlayerState.m_iVehicleNum))
01447 {
01448 CG_AdjustPositionForMover( cg.predictedVehicleState.origin,
01449 cg.predictedVehicleState.groundEntityNum,
01450 cg.physicsTime, cg.time, cg.predictedVehicleState.origin );
01451 }
01452 else
01453 {
01454
01455 CG_AdjustPositionForMover( cg.predictedPlayerState.origin,
01456 cg.predictedPlayerState.groundEntityNum,
01457 cg.physicsTime, cg.time, cg.predictedPlayerState.origin );
01458 }
01459
01460 if ( cg_showmiss.integer ) {
01461 if (cg.predictedPlayerState.eventSequence > oldPlayerState.eventSequence + MAX_PS_EVENTS) {
01462 CG_Printf("WARNING: dropped event\n");
01463 }
01464 }
01465
01466
01467 CG_TransitionPlayerState( &cg.predictedPlayerState, &oldPlayerState );
01468
01469 if ( cg_showmiss.integer ) {
01470 if (cg.eventSequence > cg.predictedPlayerState.eventSequence) {
01471 CG_Printf("WARNING: double event\n");
01472 cg.eventSequence = cg.predictedPlayerState.eventSequence;
01473 }
01474 }
01475
01476 if (cg.predictedPlayerState.m_iVehicleNum &&
01477 !CG_Piloting(cg.predictedPlayerState.m_iVehicleNum))
01478 {
01479 centity_t *veh = &cg_entities[cg.predictedPlayerState.m_iVehicleNum];
01480 VectorCopy(veh->lerpAngles, cg.predictedPlayerState.viewangles);
01481 VectorCopy(veh->lerpOrigin, cg.predictedPlayerState.origin);
01482 }
01483
01484 revertES:
01485 if (CG_Piloting(cg.predictedPlayerState.m_iVehicleNum))
01486 {
01487 centity_t *veh = &cg_entities[cg.predictedPlayerState.m_iVehicleNum];
01488
01489 if (veh->m_pVehicle)
01490 {
01491
01492 veh->m_pVehicle->m_vOrientation = &cgSendPS[veh->currentState.number]->vehOrientation[0];
01493 }
01494
01495 cg_entities[cg.predictedPlayerState.clientNum].playerState = cgSendPS[cg.predictedPlayerState.clientNum];
01496 veh->playerState = cgSendPS[veh->currentState.number];
01497 }
01498
01499
01500 for ( i = 0 ; i < MAX_GENTITIES ; i++ )
01501 {
01502 if (cg_entities[i].currentState.eType == ET_PLAYER ||
01503 cg_entities[i].currentState.eType == ET_NPC)
01504 {
01505 cg_entities[i].currentState.torsoAnim = cgSendPS[i]->torsoAnim;
01506 cg_entities[i].currentState.legsAnim = cgSendPS[i]->legsAnim;
01507 cg_entities[i].currentState.forceFrame = cgSendPS[i]->saberLockFrame;
01508 cg_entities[i].currentState.saberMove = cgSendPS[i]->saberMove;
01509 }
01510 }
01511 }
01512 #pragma warning(default : 4701) //local variable may be used without having been initialized