00001
00002
00003
00004 #include "g_local.h"
00005 #include "bg_saga.h"
00006
00007 extern void Jedi_Cloak( gentity_t *self );
00008 extern void Jedi_Decloak( gentity_t *self );
00009
00010 #include "../namespace_begin.h"
00011 qboolean PM_SaberInTransition( int move );
00012 qboolean PM_SaberInStart( int move );
00013 qboolean PM_SaberInReturn( int move );
00014 qboolean WP_SaberStyleValidForSaber( saberInfo_t *saber1, saberInfo_t *saber2, int saberHolstered, int saberAnimLevel );
00015 #include "../namespace_end.h"
00016 qboolean saberCheckKnockdown_DuelLoss(gentity_t *saberent, gentity_t *saberOwner, gentity_t *other);
00017
00018 extern vmCvar_t g_saberLockRandomNess;
00019
00020 void P_SetTwitchInfo(gclient_t *client)
00021 {
00022 client->ps.painTime = level.time;
00023 client->ps.painDirection ^= 1;
00024 }
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 void P_DamageFeedback( gentity_t *player ) {
00037 gclient_t *client;
00038 float count;
00039 vec3_t angles;
00040
00041 client = player->client;
00042 if ( client->ps.pm_type == PM_DEAD ) {
00043 return;
00044 }
00045
00046
00047 count = client->damage_blood + client->damage_armor;
00048 if ( count == 0 ) {
00049 return;
00050 }
00051
00052 if ( count > 255 ) {
00053 count = 255;
00054 }
00055
00056
00057
00058
00059
00060 if ( client->damage_fromWorld ) {
00061 client->ps.damagePitch = 255;
00062 client->ps.damageYaw = 255;
00063
00064 client->damage_fromWorld = qfalse;
00065 } else {
00066 vectoangles( client->damage_from, angles );
00067 client->ps.damagePitch = angles[PITCH]/360.0 * 256;
00068 client->ps.damageYaw = angles[YAW]/360.0 * 256;
00069
00070
00071 if (client->ps.damagePitch < 0)
00072 {
00073 client->ps.damagePitch = 0;
00074 }
00075 if (client->ps.damageYaw < 0)
00076 {
00077 client->ps.damageYaw = 0;
00078 }
00079 }
00080
00081
00082 if ( (level.time > player->pain_debounce_time) && !(player->flags & FL_GODMODE) && !(player->s.eFlags & EF_DEAD) ) {
00083
00084
00085
00086 if ( level.time - client->ps.painTime < 500 || count < 10) {
00087 return;
00088 }
00089 P_SetTwitchInfo(client);
00090 player->pain_debounce_time = level.time + 700;
00091
00092 G_AddEvent( player, EV_PAIN, player->health );
00093 client->ps.damageEvent++;
00094
00095 if (client->damage_armor && !client->damage_blood)
00096 {
00097 client->ps.damageType = 1;
00098 }
00099 else if (client->damage_armor)
00100 {
00101 client->ps.damageType = 2;
00102 }
00103 else
00104 {
00105 client->ps.damageType = 0;
00106 }
00107 }
00108
00109
00110 client->ps.damageCount = count;
00111
00112
00113
00114
00115 client->damage_blood = 0;
00116 client->damage_armor = 0;
00117 client->damage_knockback = 0;
00118 }
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 void P_WorldEffects( gentity_t *ent ) {
00130 qboolean envirosuit;
00131 int waterlevel;
00132
00133 if ( ent->client->noclip ) {
00134 ent->client->airOutTime = level.time + 12000;
00135 return;
00136 }
00137
00138 waterlevel = ent->waterlevel;
00139
00140 envirosuit = ent->client->ps.powerups[PW_BATTLESUIT] > level.time;
00141
00142
00143
00144
00145 if ( waterlevel == 3 ) {
00146
00147 if ( envirosuit ) {
00148 ent->client->airOutTime = level.time + 10000;
00149 }
00150
00151
00152 if ( ent->client->airOutTime < level.time) {
00153
00154 ent->client->airOutTime += 1000;
00155 if ( ent->health > 0 ) {
00156
00157 ent->damage += 2;
00158 if (ent->damage > 15)
00159 ent->damage = 15;
00160
00161
00162 if (ent->health <= ent->damage) {
00163 G_Sound(ent, CHAN_VOICE, G_SoundIndex("sound/player/gurp1.wav"));
00164 } else if (rand()&1) {
00165 G_Sound(ent, CHAN_VOICE, G_SoundIndex("sound/player/gurp1.wav"));
00166 } else {
00167 G_Sound(ent, CHAN_VOICE, G_SoundIndex("sound/player/gurp2.wav"));
00168 }
00169
00170
00171 ent->pain_debounce_time = level.time + 200;
00172
00173 G_Damage (ent, NULL, NULL, NULL, NULL,
00174 ent->damage, DAMAGE_NO_ARMOR, MOD_WATER);
00175 }
00176 }
00177 } else {
00178 ent->client->airOutTime = level.time + 12000;
00179 ent->damage = 2;
00180 }
00181
00182
00183
00184
00185 if (waterlevel &&
00186 (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) {
00187 if (ent->health > 0
00188 && ent->pain_debounce_time <= level.time ) {
00189
00190 if ( envirosuit ) {
00191 G_AddEvent( ent, EV_POWERUP_BATTLESUIT, 0 );
00192 } else {
00193 if (ent->watertype & CONTENTS_LAVA) {
00194 G_Damage (ent, NULL, NULL, NULL, NULL,
00195 30*waterlevel, 0, MOD_LAVA);
00196 }
00197
00198 if (ent->watertype & CONTENTS_SLIME) {
00199 G_Damage (ent, NULL, NULL, NULL, NULL,
00200 10*waterlevel, 0, MOD_SLIME);
00201 }
00202 }
00203 }
00204 }
00205 }
00206
00207
00208
00209
00210
00211
00212 extern void G_ApplyKnockback( gentity_t *targ, vec3_t newDir, float knockback );
00213 void DoImpact( gentity_t *self, gentity_t *other, qboolean damageSelf )
00214 {
00215 float magnitude, my_mass;
00216 vec3_t velocity;
00217 int cont;
00218 qboolean easyBreakBrush = qtrue;
00219
00220 if( self->client )
00221 {
00222 VectorCopy( self->client->ps.velocity, velocity );
00223 if( !self->mass )
00224 {
00225 my_mass = 10;
00226 }
00227 else
00228 {
00229 my_mass = self->mass;
00230 }
00231 }
00232 else
00233 {
00234 VectorCopy( self->s.pos.trDelta, velocity );
00235 if ( self->s.pos.trType == TR_GRAVITY )
00236 {
00237 velocity[2] -= 0.25f * g_gravity.value;
00238 }
00239 if( !self->mass )
00240 {
00241 my_mass = 1;
00242 }
00243 else if ( self->mass <= 10 )
00244 {
00245 my_mass = 10;
00246 }
00247 else
00248 {
00249 my_mass = self->mass;
00250 }
00251 }
00252
00253 magnitude = VectorLength( velocity ) * my_mass / 10;
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265 if ( other->material == MAT_GLASS
00266 || other->material == MAT_GLASS_METAL
00267 || other->material == MAT_GRATE1
00268 || ((other->flags&FL_BBRUSH)&&(other->spawnflags&8))
00269 || (other->r.svFlags&SVF_GLASS_BRUSH) )
00270 {
00271 easyBreakBrush = qtrue;
00272 }
00273
00274 if ( !self->client || self->client->ps.lastOnGround+300<level.time || ( self->client->ps.lastOnGround+100 < level.time && easyBreakBrush ) )
00275 {
00276 vec3_t dir1, dir2;
00277 float force = 0, dot;
00278
00279 if ( easyBreakBrush )
00280 magnitude *= 2;
00281
00282
00283 if ( magnitude >= 100 && other->s.number < ENTITYNUM_WORLD )
00284 {
00285 VectorCopy( velocity, dir1 );
00286 VectorNormalize( dir1 );
00287 if( VectorCompare( other->r.currentOrigin, vec3_origin ) )
00288 {
00289 VectorCopy ( dir1, dir2 );
00290 }
00291 else
00292 {
00293 VectorSubtract( other->r.currentOrigin, self->r.currentOrigin, dir2 );
00294 VectorNormalize( dir2 );
00295 }
00296
00297 dot = DotProduct( dir1, dir2 );
00298
00299 if ( dot >= 0.2 )
00300 {
00301 force = dot;
00302 }
00303 else
00304 {
00305 force = 0;
00306 }
00307
00308 force *= (magnitude/50);
00309
00310 cont = trap_PointContents( other->r.absmax, other->s.number );
00311 if( (cont&CONTENTS_WATER) )
00312 {
00313 force /= 3;
00314 }
00315
00316
00317
00318
00319
00320
00321 if( ( force >= 1 && other->s.number != 0 ) || force >= 10)
00322 {
00323
00324
00325
00326
00327
00328
00329
00330 if ( other->r.svFlags & SVF_GLASS_BRUSH )
00331 {
00332 other->splashRadius = (float)(self->r.maxs[0] - self->r.mins[0])/4.0f;
00333 }
00334 if ( other->takedamage )
00335 {
00336 G_Damage( other, self, self, velocity, self->r.currentOrigin, force, DAMAGE_NO_ARMOR, MOD_CRUSH);
00337 }
00338 else
00339 {
00340 G_ApplyKnockback( other, dir2, force );
00341 }
00342 }
00343 }
00344
00345 if ( damageSelf && self->takedamage )
00346 {
00347
00348
00349 if ( self->client && self->client->ps.fd.forceJumpZStart )
00350 {
00351 if ( self->r.currentOrigin[2] >= self->client->ps.fd.forceJumpZStart )
00352 {
00353 magnitude = 0;
00354 }
00355 else
00356 {
00357 magnitude = (self->client->ps.fd.forceJumpZStart-self->r.currentOrigin[2])/3;
00358 }
00359 }
00360
00361 if( ( magnitude >= 100 + self->health && self->s.number != 0 && self->s.weapon != WP_SABER ) || ( magnitude >= 700 ) )
00362 {
00363 if ( (self->s.weapon == WP_SABER || self->s.number == 0) && self->client && self->client->ps.groundEntityNum < ENTITYNUM_NONE && magnitude < 1000 )
00364 {
00365
00366 magnitude /= 2;
00367
00368
00369
00370
00371
00372
00373 }
00374 magnitude /= 40;
00375 magnitude = magnitude - force/2;
00376 if ( magnitude >= 1 )
00377 {
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390 G_Damage( self, NULL, NULL, NULL, self->r.currentOrigin, magnitude/2, DAMAGE_NO_ARMOR, MOD_FALLING );
00391 }
00392 }
00393 }
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404 }
00405 }
00406
00407 void Client_CheckImpactBBrush( gentity_t *self, gentity_t *other )
00408 {
00409 if ( !other || !other->inuse )
00410 {
00411 return;
00412 }
00413 if (!self || !self->inuse || !self->client ||
00414 self->client->tempSpectate >= level.time ||
00415 self->client->sess.sessionTeam == TEAM_SPECTATOR)
00416 {
00417 return;
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427 if ( other->material == MAT_GLASS
00428 || other->material == MAT_GLASS_METAL
00429 || other->material == MAT_GRATE1
00430 || ((other->flags&FL_BBRUSH)&&(other->spawnflags&8))
00431 || ((other->flags&FL_BBRUSH)&&(other->health<=10))
00432 || (other->r.svFlags&SVF_GLASS_BRUSH) )
00433 {
00434 DoImpact( self, other, qfalse );
00435 }
00436 }
00437
00438
00439
00440
00441
00442
00443
00444 void G_SetClientSound( gentity_t *ent ) {
00445 if (ent->client && ent->client->isHacking)
00446 {
00447 ent->client->ps.loopSound = level.snd_hack;
00448 ent->s.loopIsSoundset = qfalse;
00449 }
00450 else if (ent->client && ent->client->isMedHealed > level.time)
00451 {
00452 ent->client->ps.loopSound = level.snd_medHealed;
00453 ent->s.loopIsSoundset = qfalse;
00454 }
00455 else if (ent->client && ent->client->isMedSupplied > level.time)
00456 {
00457 ent->client->ps.loopSound = level.snd_medSupplied;
00458 ent->s.loopIsSoundset = qfalse;
00459 }
00460 else if (ent->waterlevel && (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) {
00461 ent->client->ps.loopSound = level.snd_fry;
00462 ent->s.loopIsSoundset = qfalse;
00463 } else {
00464 ent->client->ps.loopSound = 0;
00465 ent->s.loopIsSoundset = qfalse;
00466 }
00467 }
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478 void ClientImpacts( gentity_t *ent, pmove_t *pm ) {
00479 int i, j;
00480 trace_t trace;
00481 gentity_t *other;
00482
00483 memset( &trace, 0, sizeof( trace ) );
00484 for (i=0 ; i<pm->numtouch ; i++) {
00485 for (j=0 ; j<i ; j++) {
00486 if (pm->touchents[j] == pm->touchents[i] ) {
00487 break;
00488 }
00489 }
00490 if (j != i) {
00491 continue;
00492 }
00493 other = &g_entities[ pm->touchents[i] ];
00494
00495 if ( ( ent->r.svFlags & SVF_BOT ) && ( ent->touch ) ) {
00496 ent->touch( ent, other, &trace );
00497 }
00498
00499 if ( !other->touch ) {
00500 continue;
00501 }
00502
00503 other->touch( other, ent, &trace );
00504 }
00505
00506 }
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516 void G_TouchTriggers( gentity_t *ent ) {
00517 int i, num;
00518 int touch[MAX_GENTITIES];
00519 gentity_t *hit;
00520 trace_t trace;
00521 vec3_t mins, maxs;
00522 static vec3_t range = { 40, 40, 52 };
00523
00524 if ( !ent->client ) {
00525 return;
00526 }
00527
00528
00529 if ( ent->client->ps.stats[STAT_HEALTH] <= 0 ) {
00530 return;
00531 }
00532
00533 VectorSubtract( ent->client->ps.origin, range, mins );
00534 VectorAdd( ent->client->ps.origin, range, maxs );
00535
00536 num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
00537
00538
00539 VectorAdd( ent->client->ps.origin, ent->r.mins, mins );
00540 VectorAdd( ent->client->ps.origin, ent->r.maxs, maxs );
00541
00542 for ( i=0 ; i<num ; i++ ) {
00543 hit = &g_entities[touch[i]];
00544
00545 if ( !hit->touch && !ent->touch ) {
00546 continue;
00547 }
00548 if ( !( hit->r.contents & CONTENTS_TRIGGER ) ) {
00549 continue;
00550 }
00551
00552
00553 if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
00554 if ( hit->s.eType != ET_TELEPORT_TRIGGER &&
00555
00556
00557 hit->touch != Touch_DoorTrigger) {
00558 continue;
00559 }
00560 }
00561
00562
00563
00564 if ( hit->s.eType == ET_ITEM ) {
00565 if ( !BG_PlayerTouchesItem( &ent->client->ps, &hit->s, level.time ) ) {
00566 continue;
00567 }
00568 } else {
00569 if ( !trap_EntityContact( mins, maxs, hit ) ) {
00570 continue;
00571 }
00572 }
00573
00574 memset( &trace, 0, sizeof(trace) );
00575
00576 if ( hit->touch ) {
00577 hit->touch (hit, ent, &trace);
00578 }
00579
00580 if ( ( ent->r.svFlags & SVF_BOT ) && ( ent->touch ) ) {
00581 ent->touch( ent, hit, &trace );
00582 }
00583 }
00584
00585
00586 if ( ent->client->ps.jumppad_frame != ent->client->ps.pmove_framecount ) {
00587 ent->client->ps.jumppad_frame = 0;
00588 ent->client->ps.jumppad_ent = 0;
00589 }
00590 }
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601 void G_MoverTouchPushTriggers( gentity_t *ent, vec3_t oldOrg )
00602 {
00603 int i, num;
00604 float step, stepSize, dist;
00605 int touch[MAX_GENTITIES];
00606 gentity_t *hit;
00607 trace_t trace;
00608 vec3_t mins, maxs, dir, size, checkSpot;
00609 const vec3_t range = { 40, 40, 52 };
00610
00611
00612 if ( !VectorLengthSquared( ent->s.pos.trDelta ) )
00613 {
00614 return;
00615 }
00616
00617 VectorSubtract( ent->r.mins, ent->r.maxs, size );
00618 stepSize = VectorLength( size );
00619 if ( stepSize < 1 )
00620 {
00621 stepSize = 1;
00622 }
00623
00624 VectorSubtract( ent->r.currentOrigin, oldOrg, dir );
00625 dist = VectorNormalize( dir );
00626 for ( step = 0; step <= dist; step += stepSize )
00627 {
00628 VectorMA( ent->r.currentOrigin, step, dir, checkSpot );
00629 VectorSubtract( checkSpot, range, mins );
00630 VectorAdd( checkSpot, range, maxs );
00631
00632 num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
00633
00634
00635 VectorAdd( checkSpot, ent->r.mins, mins );
00636 VectorAdd( checkSpot, ent->r.maxs, maxs );
00637
00638 for ( i=0 ; i<num ; i++ )
00639 {
00640 hit = &g_entities[touch[i]];
00641
00642 if ( hit->s.eType != ET_PUSH_TRIGGER )
00643 {
00644 continue;
00645 }
00646
00647 if ( hit->touch == NULL )
00648 {
00649 continue;
00650 }
00651
00652 if ( !( hit->r.contents & CONTENTS_TRIGGER ) )
00653 {
00654 continue;
00655 }
00656
00657
00658 if ( !trap_EntityContact( mins, maxs, hit ) )
00659 {
00660 continue;
00661 }
00662
00663 memset( &trace, 0, sizeof(trace) );
00664
00665 if ( hit->touch != NULL )
00666 {
00667 hit->touch(hit, ent, &trace);
00668 }
00669 }
00670 }
00671 }
00672
00673
00674
00675
00676
00677
00678 void SpectatorThink( gentity_t *ent, usercmd_t *ucmd ) {
00679 pmove_t pm;
00680 gclient_t *client;
00681
00682 client = ent->client;
00683
00684 if ( client->sess.spectatorState != SPECTATOR_FOLLOW ) {
00685 client->ps.pm_type = PM_SPECTATOR;
00686 client->ps.speed = 400;
00687 client->ps.basespeed = 400;
00688
00689
00690
00691 client->ps.legsAnim = 0;
00692 client->ps.legsTimer = 0;
00693 client->ps.torsoAnim = 0;
00694 client->ps.torsoTimer = 0;
00695
00696
00697 memset (&pm, 0, sizeof(pm));
00698 pm.ps = &client->ps;
00699 pm.cmd = *ucmd;
00700 pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
00701 pm.trace = trap_Trace;
00702 pm.pointcontents = trap_PointContents;
00703
00704 pm.noSpecMove = g_noSpecMove.integer;
00705
00706 pm.animations = NULL;
00707 pm.nonHumanoid = qfalse;
00708
00709
00710 pm.baseEnt = (bgEntity_t *)g_entities;
00711 pm.entSize = sizeof(gentity_t);
00712
00713
00714 Pmove (&pm);
00715
00716 VectorCopy( client->ps.origin, ent->s.origin );
00717
00718 if (ent->client->tempSpectate < level.time)
00719 {
00720 G_TouchTriggers( ent );
00721 }
00722 trap_UnlinkEntity( ent );
00723 }
00724
00725 client->oldbuttons = client->buttons;
00726 client->buttons = ucmd->buttons;
00727
00728 if (client->tempSpectate < level.time)
00729 {
00730
00731 if ( ( client->buttons & BUTTON_ATTACK ) && ! ( client->oldbuttons & BUTTON_ATTACK ) ) {
00732 Cmd_FollowCycle_f( ent, 1 );
00733 }
00734
00735 if (client->sess.spectatorState == SPECTATOR_FOLLOW && (ucmd->upmove > 0))
00736 {
00737 StopFollowing(ent);
00738 }
00739 }
00740 }
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751 qboolean ClientInactivityTimer( gclient_t *client ) {
00752 if ( ! g_inactivity.integer ) {
00753
00754
00755 client->inactivityTime = level.time + 60 * 1000;
00756 client->inactivityWarning = qfalse;
00757 } else if ( client->pers.cmd.forwardmove ||
00758 client->pers.cmd.rightmove ||
00759 client->pers.cmd.upmove ||
00760 (client->pers.cmd.buttons & (BUTTON_ATTACK|BUTTON_ALT_ATTACK)) ) {
00761 client->inactivityTime = level.time + g_inactivity.integer * 1000;
00762 client->inactivityWarning = qfalse;
00763 } else if ( !client->pers.localClient ) {
00764 if ( level.time > client->inactivityTime ) {
00765 trap_DropClient( client - level.clients, "Dropped due to inactivity" );
00766 return qfalse;
00767 }
00768 if ( level.time > client->inactivityTime - 10000 && !client->inactivityWarning ) {
00769 client->inactivityWarning = qtrue;
00770 trap_SendServerCommand( client - level.clients, "cp \"Ten seconds until inactivity drop!\n\"" );
00771 }
00772 }
00773 return qtrue;
00774 }
00775
00776
00777
00778
00779
00780
00781
00782
00783 void ClientTimerActions( gentity_t *ent, int msec ) {
00784 gclient_t *client;
00785
00786 client = ent->client;
00787 client->timeResidual += msec;
00788
00789 while ( client->timeResidual >= 1000 )
00790 {
00791 client->timeResidual -= 1000;
00792
00793
00794 if ( ent->health > client->ps.stats[STAT_MAX_HEALTH] ) {
00795 ent->health--;
00796 }
00797
00798
00799 if ( client->ps.stats[STAT_ARMOR] > client->ps.stats[STAT_MAX_HEALTH] ) {
00800 client->ps.stats[STAT_ARMOR]--;
00801 }
00802 }
00803 }
00804
00805
00806
00807
00808
00809
00810 void ClientIntermissionThink( gclient_t *client ) {
00811 client->ps.eFlags &= ~EF_TALK;
00812 client->ps.eFlags &= ~EF_FIRING;
00813
00814
00815
00816
00817 client->oldbuttons = client->buttons;
00818 client->buttons = client->pers.cmd.buttons;
00819 if ( client->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) & ( client->oldbuttons ^ client->buttons ) ) {
00820
00821 client->readyToExit = 1;
00822 }
00823 }
00824
00825 extern void NPC_SetAnim(gentity_t *ent,int setAnimParts,int anim,int setAnimFlags);
00826 void G_VehicleAttachDroidUnit( gentity_t *vehEnt )
00827 {
00828 if ( vehEnt && vehEnt->m_pVehicle && vehEnt->m_pVehicle->m_pDroidUnit != NULL )
00829 {
00830 gentity_t *droidEnt = (gentity_t *)vehEnt->m_pVehicle->m_pDroidUnit;
00831 mdxaBone_t boltMatrix;
00832 vec3_t fwd;
00833
00834 trap_G2API_GetBoltMatrix(vehEnt->ghoul2, 0, vehEnt->m_pVehicle->m_iDroidUnitTag, &boltMatrix, vehEnt->r.currentAngles, vehEnt->r.currentOrigin, level.time,
00835 NULL, vehEnt->modelScale);
00836 BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, droidEnt->r.currentOrigin);
00837 BG_GiveMeVectorFromMatrix(&boltMatrix, NEGATIVE_Y, fwd);
00838 vectoangles( fwd, droidEnt->r.currentAngles );
00839
00840 if ( droidEnt->client )
00841 {
00842 VectorCopy( droidEnt->r.currentAngles, droidEnt->client->ps.viewangles );
00843 VectorCopy( droidEnt->r.currentOrigin, droidEnt->client->ps.origin );
00844 }
00845
00846 G_SetOrigin( droidEnt, droidEnt->r.currentOrigin );
00847 trap_LinkEntity( droidEnt );
00848
00849 if ( droidEnt->NPC )
00850 {
00851 NPC_SetAnim( droidEnt, SETANIM_BOTH, BOTH_STAND2, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00852 }
00853 }
00854 }
00855
00856
00857 void G_CheapWeaponFire(int entNum, int ev)
00858 {
00859 gentity_t *ent = &g_entities[entNum];
00860
00861 if (!ent->inuse || !ent->client)
00862 {
00863 return;
00864 }
00865
00866 switch (ev)
00867 {
00868 case EV_FIRE_WEAPON:
00869 if (ent->m_pVehicle && ent->m_pVehicle->m_pVehicleInfo->type == VH_SPEEDER &&
00870 ent->client && ent->client->ps.m_iVehicleNum)
00871 {
00872 gentity_t *rider = &g_entities[ent->client->ps.m_iVehicleNum-1];
00873 if (rider->inuse && rider->client)
00874 {
00875 if (rider->client->ps.weapon != WP_MELEE &&
00876 (rider->client->ps.weapon != WP_SABER || !rider->client->ps.saberHolstered))
00877 {
00878 break;
00879 }
00880 }
00881 }
00882
00883 FireWeapon( ent, qfalse );
00884 ent->client->dangerTime = level.time;
00885 ent->client->ps.eFlags &= ~EF_INVULNERABLE;
00886 ent->client->invulnerableTimer = 0;
00887 break;
00888 case EV_ALT_FIRE:
00889 FireWeapon( ent, qtrue );
00890 ent->client->dangerTime = level.time;
00891 ent->client->ps.eFlags &= ~EF_INVULNERABLE;
00892 ent->client->invulnerableTimer = 0;
00893 break;
00894 }
00895 }
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905 #include "../namespace_begin.h"
00906 qboolean BG_InKnockDownOnly( int anim );
00907 #include "../namespace_end.h"
00908
00909 void ClientEvents( gentity_t *ent, int oldEventSequence ) {
00910 int i;
00911 int event;
00912 gclient_t *client;
00913 int damage;
00914 vec3_t dir;
00915
00916
00917
00918
00919
00920 client = ent->client;
00921
00922 if ( oldEventSequence < client->ps.eventSequence - MAX_PS_EVENTS ) {
00923 oldEventSequence = client->ps.eventSequence - MAX_PS_EVENTS;
00924 }
00925 for ( i = oldEventSequence ; i < client->ps.eventSequence ; i++ ) {
00926 event = client->ps.events[ i & (MAX_PS_EVENTS-1) ];
00927
00928 switch ( event ) {
00929 case EV_FALL:
00930 case EV_ROLL:
00931 {
00932 int delta = client->ps.eventParms[ i & (MAX_PS_EVENTS-1) ];
00933 qboolean knockDownage = qfalse;
00934
00935 if (ent->client && ent->client->ps.fallingToDeath)
00936 {
00937 break;
00938 }
00939
00940 if ( ent->s.eType != ET_PLAYER )
00941 {
00942 break;
00943 }
00944
00945 if ( g_dmflags.integer & DF_NO_FALLING )
00946 {
00947 break;
00948 }
00949
00950 if (BG_InKnockDownOnly(ent->client->ps.legsAnim))
00951 {
00952 if (delta <= 14)
00953 {
00954 break;
00955 }
00956 knockDownage = qtrue;
00957 }
00958 else
00959 {
00960 if (delta <= 44)
00961 {
00962 break;
00963 }
00964 }
00965
00966 if (knockDownage)
00967 {
00968 damage = delta*1;
00969 }
00970 else
00971 {
00972 if (g_gametype.integer == GT_SIEGE &&
00973 delta > 60)
00974 {
00975 damage = delta*1;
00976 }
00977 else
00978 {
00979 damage = delta*0.16;
00980 }
00981 }
00982
00983 VectorSet (dir, 0, 0, 1);
00984 ent->pain_debounce_time = level.time + 200;
00985 G_Damage (ent, NULL, NULL, NULL, NULL, damage, DAMAGE_NO_ARMOR, MOD_FALLING);
00986
00987 if (ent->health < 1)
00988 {
00989 G_Sound(ent, CHAN_AUTO, G_SoundIndex( "sound/player/fallsplat.wav" ));
00990 }
00991 }
00992 break;
00993 case EV_FIRE_WEAPON:
00994 FireWeapon( ent, qfalse );
00995 ent->client->dangerTime = level.time;
00996 ent->client->ps.eFlags &= ~EF_INVULNERABLE;
00997 ent->client->invulnerableTimer = 0;
00998 break;
00999
01000 case EV_ALT_FIRE:
01001 FireWeapon( ent, qtrue );
01002 ent->client->dangerTime = level.time;
01003 ent->client->ps.eFlags &= ~EF_INVULNERABLE;
01004 ent->client->invulnerableTimer = 0;
01005 break;
01006
01007 case EV_SABER_ATTACK:
01008 ent->client->dangerTime = level.time;
01009 ent->client->ps.eFlags &= ~EF_INVULNERABLE;
01010 ent->client->invulnerableTimer = 0;
01011 break;
01012
01013
01014 case EV_USE_ITEM1:
01015 ItemUse_Seeker(ent);
01016 break;
01017 case EV_USE_ITEM2:
01018 ItemUse_Shield(ent);
01019 break;
01020 case EV_USE_ITEM3:
01021 ItemUse_MedPack(ent);
01022 break;
01023 case EV_USE_ITEM4:
01024 ItemUse_MedPack_Big(ent);
01025 break;
01026 case EV_USE_ITEM5:
01027 ItemUse_Binoculars(ent);
01028 break;
01029 case EV_USE_ITEM6:
01030 ItemUse_Sentry(ent);
01031 break;
01032 case EV_USE_ITEM7:
01033 ItemUse_Jetpack(ent);
01034 break;
01035 case EV_USE_ITEM8:
01036
01037 break;
01038 case EV_USE_ITEM9:
01039
01040 break;
01041 case EV_USE_ITEM10:
01042 ItemUse_UseEWeb(ent);
01043 break;
01044 case EV_USE_ITEM11:
01045 ItemUse_UseCloak(ent);
01046 break;
01047 default:
01048 break;
01049 }
01050 }
01051
01052 }
01053
01054
01055
01056
01057
01058
01059 void SendPendingPredictableEvents( playerState_t *ps ) {
01060 gentity_t *t;
01061 int event, seq;
01062 int extEvent, number;
01063
01064
01065 if ( ps->entityEventSequence < ps->eventSequence ) {
01066
01067
01068 seq = ps->entityEventSequence & (MAX_PS_EVENTS-1);
01069 event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 );
01070
01071 extEvent = ps->externalEvent;
01072 ps->externalEvent = 0;
01073
01074 t = G_TempEntity( ps->origin, event );
01075 number = t->s.number;
01076 BG_PlayerStateToEntityState( ps, &t->s, qtrue );
01077 t->s.number = number;
01078 t->s.eType = ET_EVENTS + event;
01079 t->s.eFlags |= EF_PLAYER_EVENT;
01080 t->s.otherEntityNum = ps->clientNum;
01081
01082 t->r.svFlags |= SVF_NOTSINGLECLIENT;
01083 t->r.singleClient = ps->clientNum;
01084
01085 ps->externalEvent = extEvent;
01086 }
01087 }
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097 #define MAX_JEDIMASTER_DISTANCE 2500
01098 #define MAX_JEDIMASTER_FOV 100
01099
01100 #define MAX_SIGHT_DISTANCE 1500
01101 #define MAX_SIGHT_FOV 100
01102
01103 static void G_UpdateForceSightBroadcasts ( gentity_t *self )
01104 {
01105 int i;
01106
01107
01108 for ( i = 0; i < level.numConnectedClients; i ++ )
01109 {
01110 gentity_t *ent = &g_entities[level.sortedClients[i]];
01111 float dist;
01112 vec3_t angles;
01113
01114 if ( ent == self )
01115 {
01116 continue;
01117 }
01118
01119
01120 if ( !(ent->client->ps.fd.forcePowersActive & (1<<FP_SEE) ) )
01121 {
01122 continue;
01123 }
01124
01125 VectorSubtract( self->client->ps.origin, ent->client->ps.origin, angles );
01126 dist = VectorLengthSquared ( angles );
01127 vectoangles ( angles, angles );
01128
01129
01130 if ( dist > MAX_SIGHT_DISTANCE * MAX_SIGHT_DISTANCE )
01131 {
01132 continue;
01133 }
01134
01135
01136 if ( !InFieldOfVision ( ent->client->ps.viewangles, MAX_SIGHT_FOV, angles ) )
01137 {
01138 break;
01139 }
01140
01141
01142
01143 self->r.broadcastClients[ent->s.clientNum/32] |= (1 << (ent->s.clientNum%32));
01144
01145 break;
01146 }
01147 }
01148
01149 static void G_UpdateJediMasterBroadcasts ( gentity_t *self )
01150 {
01151 int i;
01152
01153
01154 if ( g_gametype.integer != GT_JEDIMASTER )
01155 {
01156 return;
01157 }
01158
01159
01160 if ( !self->client->ps.isJediMaster )
01161 {
01162 return;
01163 }
01164
01165
01166 for ( i = 0; i < level.numConnectedClients; i ++ )
01167 {
01168 gentity_t *ent = &g_entities[level.sortedClients[i]];
01169 float dist;
01170 vec3_t angles;
01171
01172 if ( ent == self )
01173 {
01174 continue;
01175 }
01176
01177 VectorSubtract( self->client->ps.origin, ent->client->ps.origin, angles );
01178 dist = VectorLengthSquared ( angles );
01179 vectoangles ( angles, angles );
01180
01181
01182 if ( dist > MAX_JEDIMASTER_DISTANCE * MAX_JEDIMASTER_DISTANCE )
01183 {
01184 continue;
01185 }
01186
01187
01188 if ( !InFieldOfVision ( ent->client->ps.viewangles, MAX_JEDIMASTER_FOV, angles ) )
01189 {
01190 continue;
01191 }
01192
01193
01194
01195 self->r.broadcastClients[ent->s.clientNum/32] |= (1 << (ent->s.clientNum%32));
01196 }
01197 }
01198
01199 void G_UpdateClientBroadcasts ( gentity_t *self )
01200 {
01201
01202 memset ( self->r.broadcastClients, 0, sizeof ( self->r.broadcastClients ) );
01203
01204
01205 G_UpdateJediMasterBroadcasts ( self );
01206
01207
01208 G_UpdateForceSightBroadcasts ( self );
01209 }
01210
01211 void G_AddPushVecToUcmd( gentity_t *self, usercmd_t *ucmd )
01212 {
01213 vec3_t forward, right, moveDir;
01214 float pushSpeed, fMove, rMove;
01215
01216 if ( !self->client )
01217 {
01218 return;
01219 }
01220 pushSpeed = VectorLengthSquared(self->client->pushVec);
01221 if(!pushSpeed)
01222 {
01223 return;
01224 }
01225
01226 AngleVectors(self->client->ps.viewangles, forward, right, NULL);
01227 VectorScale(forward, ucmd->forwardmove/127.0f * self->client->ps.speed, moveDir);
01228 VectorMA(moveDir, ucmd->rightmove/127.0f * self->client->ps.speed, right, moveDir);
01229
01230
01231 VectorAdd(moveDir, self->client->pushVec, moveDir);
01232 self->client->ps.speed = VectorNormalize(moveDir);
01233
01234
01235 fMove = 127.0 * DotProduct(forward, moveDir);
01236 rMove = 127.0 * DotProduct(right, moveDir);
01237 ucmd->forwardmove = floor(fMove);
01238 ucmd->rightmove = floor(rMove);
01239
01240 if ( self->client->pushVecTime < level.time )
01241 {
01242 VectorClear( self->client->pushVec );
01243 }
01244 }
01245
01246 qboolean G_StandingAnim( int anim )
01247 {
01248 switch ( anim )
01249 {
01250 case BOTH_STAND1:
01251 case BOTH_STAND2:
01252 case BOTH_STAND3:
01253 case BOTH_STAND4:
01254 return qtrue;
01255 break;
01256 }
01257 return qfalse;
01258 }
01259
01260 qboolean G_ActionButtonPressed(int buttons)
01261 {
01262 if (buttons & BUTTON_ATTACK)
01263 {
01264 return qtrue;
01265 }
01266 else if (buttons & BUTTON_USE_HOLDABLE)
01267 {
01268 return qtrue;
01269 }
01270 else if (buttons & BUTTON_GESTURE)
01271 {
01272 return qtrue;
01273 }
01274 else if (buttons & BUTTON_USE)
01275 {
01276 return qtrue;
01277 }
01278 else if (buttons & BUTTON_FORCEGRIP)
01279 {
01280 return qtrue;
01281 }
01282 else if (buttons & BUTTON_ALT_ATTACK)
01283 {
01284 return qtrue;
01285 }
01286 else if (buttons & BUTTON_FORCEPOWER)
01287 {
01288 return qtrue;
01289 }
01290 else if (buttons & BUTTON_FORCE_LIGHTNING)
01291 {
01292 return qtrue;
01293 }
01294 else if (buttons & BUTTON_FORCE_DRAIN)
01295 {
01296 return qtrue;
01297 }
01298
01299 return qfalse;
01300 }
01301
01302 void G_CheckClientIdle( gentity_t *ent, usercmd_t *ucmd )
01303 {
01304 vec3_t viewChange;
01305 qboolean actionPressed;
01306 int buttons;
01307
01308 if ( !ent || !ent->client || ent->health <= 0 || ent->client->ps.stats[STAT_HEALTH] <= 0 ||
01309 ent->client->sess.sessionTeam == TEAM_SPECTATOR || (ent->client->ps.pm_flags & PMF_FOLLOW))
01310 {
01311 return;
01312 }
01313
01314 buttons = ucmd->buttons;
01315
01316 if (ent->r.svFlags & SVF_BOT)
01317 {
01318 buttons &= ~BUTTON_USE;
01319 }
01320 actionPressed = G_ActionButtonPressed(buttons);
01321
01322 VectorSubtract(ent->client->ps.viewangles, ent->client->idleViewAngles, viewChange);
01323 if ( !VectorCompare( vec3_origin, ent->client->ps.velocity )
01324 || actionPressed || ucmd->forwardmove || ucmd->rightmove || ucmd->upmove
01325 || !G_StandingAnim( ent->client->ps.legsAnim )
01326 || (ent->health+ent->client->ps.stats[STAT_ARMOR]) != ent->client->idleHealth
01327 || VectorLength(viewChange) > 10
01328 || ent->client->ps.legsTimer > 0
01329 || ent->client->ps.torsoTimer > 0
01330 || ent->client->ps.weaponTime > 0
01331 || ent->client->ps.weaponstate == WEAPON_CHARGING
01332 || ent->client->ps.weaponstate == WEAPON_CHARGING_ALT
01333 || ent->client->ps.zoomMode
01334 || (ent->client->ps.weaponstate != WEAPON_READY && ent->client->ps.weapon != WP_SABER)
01335 || ent->client->ps.forceHandExtend != HANDEXTEND_NONE
01336 || ent->client->ps.saberBlocked != BLOCKED_NONE
01337 || ent->client->ps.saberBlocking >= level.time
01338 || ent->client->ps.weapon == WP_MELEE
01339 || (ent->client->ps.weapon != ent->client->pers.cmd.weapon && ent->s.eType != ET_NPC))
01340 {
01341 qboolean brokeOut = qfalse;
01342
01343 if ( !VectorCompare( vec3_origin, ent->client->ps.velocity )
01344 || actionPressed || ucmd->forwardmove || ucmd->rightmove || ucmd->upmove
01345 || (ent->health+ent->client->ps.stats[STAT_ARMOR]) != ent->client->idleHealth
01346 || ent->client->ps.zoomMode
01347 || (ent->client->ps.weaponstate != WEAPON_READY && ent->client->ps.weapon != WP_SABER)
01348 || (ent->client->ps.weaponTime > 0 && ent->client->ps.weapon == WP_SABER)
01349 || ent->client->ps.weaponstate == WEAPON_CHARGING
01350 || ent->client->ps.weaponstate == WEAPON_CHARGING_ALT
01351 || ent->client->ps.forceHandExtend != HANDEXTEND_NONE
01352 || ent->client->ps.saberBlocked != BLOCKED_NONE
01353 || ent->client->ps.saberBlocking >= level.time
01354 || ent->client->ps.weapon == WP_MELEE
01355 || (ent->client->ps.weapon != ent->client->pers.cmd.weapon && ent->s.eType != ET_NPC))
01356 {
01357
01358 switch ( ent->client->ps.legsAnim )
01359 {
01360 case BOTH_STAND1IDLE1:
01361 case BOTH_STAND2IDLE1:
01362 case BOTH_STAND2IDLE2:
01363 case BOTH_STAND3IDLE1:
01364 case BOTH_STAND5IDLE1:
01365 ent->client->ps.legsTimer = 0;
01366 brokeOut = qtrue;
01367 break;
01368 }
01369 switch ( ent->client->ps.torsoAnim )
01370 {
01371 case BOTH_STAND1IDLE1:
01372 case BOTH_STAND2IDLE1:
01373 case BOTH_STAND2IDLE2:
01374 case BOTH_STAND3IDLE1:
01375 case BOTH_STAND5IDLE1:
01376 ent->client->ps.torsoTimer = 0;
01377 ent->client->ps.weaponTime = 0;
01378 ent->client->ps.saberMove = LS_READY;
01379 brokeOut = qtrue;
01380 break;
01381 }
01382 }
01383
01384 ent->client->idleHealth = (ent->health+ent->client->ps.stats[STAT_ARMOR]);
01385 VectorCopy(ent->client->ps.viewangles, ent->client->idleViewAngles);
01386 if ( ent->client->idleTime < level.time )
01387 {
01388 ent->client->idleTime = level.time;
01389 }
01390
01391 if (brokeOut &&
01392 (ent->client->ps.weaponstate == WEAPON_CHARGING || ent->client->ps.weaponstate == WEAPON_CHARGING_ALT))
01393 {
01394 ent->client->ps.torsoAnim = TORSO_RAISEWEAP1;
01395 }
01396 }
01397 else if ( level.time - ent->client->idleTime > 5000 )
01398 {
01399 int idleAnim = -1;
01400 switch ( ent->client->ps.legsAnim )
01401 {
01402 case BOTH_STAND1:
01403 idleAnim = BOTH_STAND1IDLE1;
01404 break;
01405 case BOTH_STAND2:
01406 idleAnim = BOTH_STAND2IDLE1;
01407 break;
01408 case BOTH_STAND3:
01409 idleAnim = BOTH_STAND3IDLE1;
01410 break;
01411 case BOTH_STAND5:
01412 idleAnim = BOTH_STAND5IDLE1;
01413 break;
01414 }
01415
01416 if (idleAnim == BOTH_STAND2IDLE1 && Q_irand(1, 10) <= 5)
01417 {
01418 idleAnim = BOTH_STAND2IDLE2;
01419 }
01420
01421 if ( idleAnim != -1 && idleAnim > 0 && idleAnim < MAX_ANIMATIONS )
01422 {
01423 G_SetAnim(ent, ucmd, SETANIM_BOTH, idleAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0);
01424
01425
01426
01427 ent->client->idleTime = level.time + ent->client->ps.legsTimer + Q_irand( 0, 2000 );
01428 }
01429 }
01430 }
01431
01432 void NPC_Accelerate( gentity_t *ent, qboolean fullWalkAcc, qboolean fullRunAcc )
01433 {
01434 if ( !ent->client || !ent->NPC )
01435 {
01436 return;
01437 }
01438
01439 if ( !ent->NPC->stats.acceleration )
01440 {
01441 ent->NPC->currentSpeed = ent->NPC->desiredSpeed;
01442 }
01443
01444 else if ( ent->NPC->desiredSpeed <= ent->NPC->stats.walkSpeed )
01445 {
01446 if ( ent->NPC->desiredSpeed > ent->NPC->currentSpeed + ent->NPC->stats.acceleration )
01447 {
01448
01449 ent->NPC->currentSpeed += ent->NPC->stats.acceleration;
01450 }
01451 else if ( ent->NPC->desiredSpeed > ent->NPC->currentSpeed )
01452 {
01453
01454 ent->NPC->currentSpeed = ent->NPC->desiredSpeed;
01455 }
01456 else if ( fullWalkAcc && ent->NPC->desiredSpeed < ent->NPC->currentSpeed - ent->NPC->stats.acceleration )
01457 {
01458 ent->NPC->currentSpeed -= ent->NPC->stats.acceleration;
01459 }
01460 else if ( ent->NPC->desiredSpeed < ent->NPC->currentSpeed )
01461 {
01462 ent->NPC->currentSpeed = ent->NPC->desiredSpeed;
01463 }
01464 }
01465 else
01466 {
01467 if ( fullRunAcc && ent->NPC->desiredSpeed > ent->NPC->currentSpeed + ent->NPC->stats.acceleration )
01468 {
01469
01470 ent->NPC->currentSpeed += ent->NPC->stats.acceleration;
01471 }
01472 else if ( ent->NPC->desiredSpeed > ent->NPC->currentSpeed )
01473 {
01474
01475 ent->NPC->currentSpeed = ent->NPC->desiredSpeed;
01476 }
01477 else if ( fullRunAcc && ent->NPC->desiredSpeed < ent->NPC->currentSpeed - ent->NPC->stats.acceleration )
01478 {
01479 ent->NPC->currentSpeed -= ent->NPC->stats.acceleration;
01480 }
01481 else if ( ent->NPC->desiredSpeed < ent->NPC->currentSpeed )
01482 {
01483 ent->NPC->currentSpeed = ent->NPC->desiredSpeed;
01484 }
01485 }
01486 }
01487
01488
01489
01490
01491
01492
01493
01494 static int NPC_GetWalkSpeed( gentity_t *ent )
01495 {
01496 int walkSpeed = 0;
01497
01498 if ( ( ent->client == NULL ) || ( ent->NPC == NULL ) )
01499 return 0;
01500
01501 switch ( ent->client->playerTeam )
01502 {
01503 case NPCTEAM_PLAYER:
01504 default:
01505 walkSpeed = ent->NPC->stats.walkSpeed;
01506 break;
01507 }
01508
01509 return walkSpeed;
01510 }
01511
01512
01513
01514
01515
01516
01517 static int NPC_GetRunSpeed( gentity_t *ent )
01518 {
01519 int runSpeed = 0;
01520
01521 if ( ( ent->client == NULL ) || ( ent->NPC == NULL ) )
01522 return 0;
01523
01524
01525
01526
01527
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551 switch( ent->client->NPC_class)
01552 {
01553 case CLASS_PROBE:
01554 case CLASS_GONK:
01555 case CLASS_R2D2:
01556 case CLASS_R5D2:
01557 case CLASS_MARK1:
01558 case CLASS_MARK2:
01559 case CLASS_PROTOCOL:
01560 case CLASS_ATST:
01561 case CLASS_MOUSE:
01562 case CLASS_SEEKER:
01563 case CLASS_REMOTE:
01564 runSpeed = ent->NPC->stats.runSpeed;
01565 break;
01566
01567 default:
01568 runSpeed = ent->NPC->stats.runSpeed*1.3f;
01569 break;
01570 }
01571
01572 return runSpeed;
01573 }
01574
01575
01576 extern qboolean FlyingCreature( gentity_t *ent );
01577 void G_CheckMovingLoopingSounds( gentity_t *ent, usercmd_t *ucmd )
01578 {
01579 if ( ent->client )
01580 {
01581 if ( (ent->NPC&&!VectorCompare( vec3_origin, ent->client->ps.moveDir ))
01582 || ucmd->forwardmove || ucmd->rightmove
01583 || (ucmd->upmove&&FlyingCreature( ent ))
01584 || (FlyingCreature( ent )&&!VectorCompare( vec3_origin, ent->client->ps.velocity )&&ent->health>0))
01585 {
01586 switch( ent->client->NPC_class )
01587 {
01588 case CLASS_R2D2:
01589 ent->s.loopSound = G_SoundIndex( "sound/chars/r2d2/misc/r2_move_lp.wav" );
01590 break;
01591 case CLASS_R5D2:
01592 ent->s.loopSound = G_SoundIndex( "sound/chars/r2d2/misc/r2_move_lp2.wav" );
01593 break;
01594 case CLASS_MARK2:
01595 ent->s.loopSound = G_SoundIndex( "sound/chars/mark2/misc/mark2_move_lp" );
01596 break;
01597 case CLASS_MOUSE:
01598 ent->s.loopSound = G_SoundIndex( "sound/chars/mouse/misc/mouse_lp" );
01599 break;
01600 case CLASS_PROBE:
01601 ent->s.loopSound = G_SoundIndex( "sound/chars/probe/misc/probedroidloop" );
01602 }
01603 }
01604 else
01605 {
01606 if ( ent->client->NPC_class == CLASS_R2D2 || ent->client->NPC_class == CLASS_R5D2
01607 || ent->client->NPC_class == CLASS_MARK2 || ent->client->NPC_class == CLASS_MOUSE
01608 || ent->client->NPC_class == CLASS_PROBE )
01609 {
01610 ent->s.loopSound = 0;
01611 }
01612 }
01613 }
01614 }
01615
01616 void G_HeldByMonster( gentity_t *ent, usercmd_t **ucmd )
01617 {
01618 if ( ent
01619 && ent->client
01620 && ent->client->ps.hasLookTarget )
01621 {
01622 gentity_t *monster = &g_entities[ent->client->ps.lookTarget];
01623 if ( monster && monster->client )
01624 {
01625
01626 ent->waypoint = monster->waypoint;
01627 if ( monster->s.NPC_class == CLASS_RANCOR )
01628 {
01629 BG_AttachToRancor( monster->ghoul2,
01630 monster->r.currentAngles[YAW],
01631 monster->r.currentOrigin,
01632 level.time,
01633 NULL,
01634 monster->modelScale,
01635 (monster->client->ps.eFlags2&EF2_GENERIC_NPC_FLAG),
01636 ent->client->ps.origin,
01637 ent->client->ps.viewangles,
01638 NULL );
01639 }
01640 VectorClear( ent->client->ps.velocity );
01641 G_SetOrigin( ent, ent->client->ps.origin );
01642 SetClientViewAngle( ent, ent->client->ps.viewangles );
01643 G_SetAngles( ent, ent->client->ps.viewangles );
01644 trap_LinkEntity( ent );
01645 }
01646 }
01647
01648 (*ucmd)->forwardmove = 0;
01649 (*ucmd)->rightmove = 0;
01650 (*ucmd)->upmove = 0;
01651 }
01652
01653 typedef enum
01654 {
01655 TAUNT_TAUNT = 0,
01656 TAUNT_BOW,
01657 TAUNT_MEDITATE,
01658 TAUNT_FLOURISH,
01659 TAUNT_GLOAT
01660 };
01661
01662 void G_SetTauntAnim( gentity_t *ent, int taunt )
01663 {
01664 if (ent->client->pers.cmd.upmove ||
01665 ent->client->pers.cmd.forwardmove ||
01666 ent->client->pers.cmd.rightmove)
01667 {
01668 return;
01669 }
01670 if ( taunt != TAUNT_TAUNT )
01671 {
01672 if ( g_gametype.integer != GT_DUEL
01673 && g_gametype.integer != GT_POWERDUEL )
01674 {
01675 return;
01676 }
01677 }
01678 if ( ent->client->ps.torsoTimer < 1
01679 && ent->client->ps.forceHandExtend == HANDEXTEND_NONE
01680 && ent->client->ps.legsTimer < 1
01681 && ent->client->ps.weaponTime < 1
01682 && ent->client->ps.saberLockTime < level.time )
01683 {
01684 int anim = -1;
01685 switch ( taunt )
01686 {
01687 case TAUNT_TAUNT:
01688 if ( ent->client->ps.weapon != WP_SABER )
01689 {
01690 anim = BOTH_ENGAGETAUNT;
01691 }
01692 else if ( ent->client->saber[0].tauntAnim != -1 )
01693 {
01694 anim = ent->client->saber[0].tauntAnim;
01695 }
01696 else if ( ent->client->saber[1].model
01697 && ent->client->saber[1].model[0]
01698 && ent->client->saber[1].tauntAnim != -1 )
01699 {
01700 anim = ent->client->saber[1].tauntAnim;
01701 }
01702 else
01703 {
01704 switch ( ent->client->ps.fd.saberAnimLevel )
01705 {
01706 case SS_FAST:
01707 case SS_TAVION:
01708 if ( ent->client->ps.saberHolstered == 1
01709 && ent->client->saber[1].model
01710 && ent->client->saber[1].model[0] )
01711 {
01712 G_Sound( ent, CHAN_WEAPON, ent->client->saber[1].soundOff );
01713 }
01714 else if ( ent->client->ps.saberHolstered == 0 )
01715 {
01716 G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOff );
01717 }
01718 ent->client->ps.saberHolstered = 2;
01719 anim = BOTH_GESTURE1;
01720 break;
01721 case SS_MEDIUM:
01722 case SS_STRONG:
01723 case SS_DESANN:
01724 anim = BOTH_ENGAGETAUNT;
01725 break;
01726 case SS_DUAL:
01727 if ( ent->client->ps.saberHolstered == 1
01728 && ent->client->saber[1].model
01729 && ent->client->saber[1].model[0] )
01730 {
01731 G_Sound( ent, CHAN_WEAPON, ent->client->saber[1].soundOn );
01732 }
01733 else if ( ent->client->ps.saberHolstered == 2 )
01734 {
01735 G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOn );
01736 }
01737 ent->client->ps.saberHolstered = 0;
01738 anim = BOTH_DUAL_TAUNT;
01739 break;
01740 case SS_STAFF:
01741 if ( ent->client->ps.saberHolstered > 0 )
01742 {
01743 G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOn );
01744 }
01745 ent->client->ps.saberHolstered = 0;
01746 anim = BOTH_STAFF_TAUNT;
01747 break;
01748 }
01749 }
01750 break;
01751 case TAUNT_BOW:
01752 if ( ent->client->saber[0].bowAnim != -1 )
01753 {
01754 anim = ent->client->saber[0].bowAnim;
01755 }
01756 else if ( ent->client->saber[1].model
01757 && ent->client->saber[1].model[0]
01758 && ent->client->saber[1].bowAnim != -1 )
01759 {
01760 anim = ent->client->saber[1].bowAnim;
01761 }
01762 else
01763 {
01764 anim = BOTH_BOW;
01765 }
01766 if ( ent->client->ps.saberHolstered == 1
01767 && ent->client->saber[1].model
01768 && ent->client->saber[1].model[0] )
01769 {
01770 G_Sound( ent, CHAN_WEAPON, ent->client->saber[1].soundOff );
01771 }
01772 else if ( ent->client->ps.saberHolstered == 0 )
01773 {
01774 G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOff );
01775 }
01776 ent->client->ps.saberHolstered = 2;
01777 break;
01778 case TAUNT_MEDITATE:
01779 if ( ent->client->saber[0].meditateAnim != -1 )
01780 {
01781 anim = ent->client->saber[0].meditateAnim;
01782 }
01783 else if ( ent->client->saber[1].model
01784 && ent->client->saber[1].model[0]
01785 && ent->client->saber[1].meditateAnim != -1 )
01786 {
01787 anim = ent->client->saber[1].meditateAnim;
01788 }
01789 else
01790 {
01791 anim = BOTH_MEDITATE;
01792 }
01793 if ( ent->client->ps.saberHolstered == 1
01794 && ent->client->saber[1].model
01795 && ent->client->saber[1].model[0] )
01796 {
01797 G_Sound( ent, CHAN_WEAPON, ent->client->saber[1].soundOff );
01798 }
01799 else if ( ent->client->ps.saberHolstered == 0 )
01800 {
01801 G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOff );
01802 }
01803 ent->client->ps.saberHolstered = 2;
01804 break;
01805 case TAUNT_FLOURISH:
01806 if ( ent->client->ps.weapon == WP_SABER )
01807 {
01808 if ( ent->client->ps.saberHolstered == 1
01809 && ent->client->saber[1].model
01810 && ent->client->saber[1].model[0] )
01811 {
01812 G_Sound( ent, CHAN_WEAPON, ent->client->saber[1].soundOn );
01813 }
01814 else if ( ent->client->ps.saberHolstered == 2 )
01815 {
01816 G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOn );
01817 }
01818 ent->client->ps.saberHolstered = 0;
01819 if ( ent->client->saber[0].flourishAnim != -1 )
01820 {
01821 anim = ent->client->saber[0].flourishAnim;
01822 }
01823 else if ( ent->client->saber[1].model
01824 && ent->client->saber[1].model[0]
01825 && ent->client->saber[1].flourishAnim != -1 )
01826 {
01827 anim = ent->client->saber[1].flourishAnim;
01828 }
01829 else
01830 {
01831 switch ( ent->client->ps.fd.saberAnimLevel )
01832 {
01833 case SS_FAST:
01834 case SS_TAVION:
01835 anim = BOTH_SHOWOFF_FAST;
01836 break;
01837 case SS_MEDIUM:
01838 anim = BOTH_SHOWOFF_MEDIUM;
01839 break;
01840 case SS_STRONG:
01841 case SS_DESANN:
01842 anim = BOTH_SHOWOFF_STRONG;
01843 break;
01844 case SS_DUAL:
01845 anim = BOTH_SHOWOFF_DUAL;
01846 break;
01847 case SS_STAFF:
01848 anim = BOTH_SHOWOFF_STAFF;
01849 break;
01850 }
01851 }
01852 }
01853 break;
01854 case TAUNT_GLOAT:
01855 if ( ent->client->saber[0].gloatAnim != -1 )
01856 {
01857 anim = ent->client->saber[0].gloatAnim;
01858 }
01859 else if ( ent->client->saber[1].model
01860 && ent->client->saber[1].model[0]
01861 && ent->client->saber[1].gloatAnim != -1 )
01862 {
01863 anim = ent->client->saber[1].gloatAnim;
01864 }
01865 else
01866 {
01867 switch ( ent->client->ps.fd.saberAnimLevel )
01868 {
01869 case SS_FAST:
01870 case SS_TAVION:
01871 anim = BOTH_VICTORY_FAST;
01872 break;
01873 case SS_MEDIUM:
01874 anim = BOTH_VICTORY_MEDIUM;
01875 break;
01876 case SS_STRONG:
01877 case SS_DESANN:
01878 if ( ent->client->ps.saberHolstered )
01879 {
01880 G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOn );
01881 }
01882 ent->client->ps.saberHolstered = 0;
01883 anim = BOTH_VICTORY_STRONG;
01884 break;
01885 case SS_DUAL:
01886 if ( ent->client->ps.saberHolstered == 1
01887 && ent->client->saber[1].model
01888 && ent->client->saber[1].model[0] )
01889 {
01890 G_Sound( ent, CHAN_WEAPON, ent->client->saber[1].soundOn );
01891 }
01892 else if ( ent->client->ps.saberHolstered == 2 )
01893 {
01894 G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOn );
01895 }
01896 ent->client->ps.saberHolstered = 0;
01897 anim = BOTH_VICTORY_DUAL;
01898 break;
01899 case SS_STAFF:
01900 if ( ent->client->ps.saberHolstered )
01901 {
01902 G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOn );
01903 }
01904 ent->client->ps.saberHolstered = 0;
01905 anim = BOTH_VICTORY_STAFF;
01906 break;
01907 }
01908 }
01909 break;
01910 }
01911 if ( anim != -1 )
01912 {
01913 if ( ent->client->ps.groundEntityNum != ENTITYNUM_NONE )
01914 {
01915 ent->client->ps.forceHandExtend = HANDEXTEND_TAUNT;
01916 ent->client->ps.forceDodgeAnim = anim;
01917 ent->client->ps.forceHandExtendTime = level.time + BG_AnimLength(ent->localAnimIndex, (animNumber_t)anim);
01918 }
01919 if ( taunt != TAUNT_MEDITATE
01920 && taunt != TAUNT_BOW )
01921 {
01922 G_AddEvent( ent, EV_TAUNT, taunt );
01923 }
01924 }
01925 }
01926 }
01927
01928
01929
01930
01931
01932
01933
01934
01935
01936
01937
01938
01939 void ClientThink_real( gentity_t *ent ) {
01940 gclient_t *client;
01941 pmove_t pm;
01942 int oldEventSequence;
01943 int msec;
01944 usercmd_t *ucmd;
01945 qboolean isNPC = qfalse;
01946 qboolean controlledByPlayer = qfalse;
01947 qboolean killJetFlags = qtrue;
01948
01949 client = ent->client;
01950
01951 if (ent->s.eType == ET_NPC)
01952 {
01953 isNPC = qtrue;
01954 }
01955
01956
01957 if (client->pers.connected != CON_CONNECTED && !isNPC) {
01958 return;
01959 }
01960
01961
01962
01963 if ( ent->s.number < MAX_CLIENTS && ent->client->ps.m_iVehicleNum )
01964 {
01965 if (g_entities[ent->client->ps.m_iVehicleNum].client)
01966 {
01967 gentity_t *veh = &g_entities[ent->client->ps.m_iVehicleNum];
01968
01969 if (veh->m_pVehicle &&
01970 veh->m_pVehicle->m_pPilot == (bgEntity_t *)ent)
01971 {
01972 veh->client->ps.commandTime = ent->client->ps.commandTime;
01973 memcpy(&veh->m_pVehicle->m_ucmd, &ent->client->pers.cmd, sizeof(usercmd_t));
01974 if ( veh->m_pVehicle->m_ucmd.buttons & BUTTON_TALK )
01975 {
01976 veh->m_pVehicle->m_ucmd.buttons = BUTTON_TALK;
01977 veh->m_pVehicle->m_ucmd.forwardmove = 0;
01978 veh->m_pVehicle->m_ucmd.rightmove = 0;
01979 veh->m_pVehicle->m_ucmd.upmove = 0;
01980 }
01981 }
01982 }
01983 }
01984
01985 if (!(client->ps.pm_flags & PMF_FOLLOW))
01986 {
01987 if (g_gametype.integer == GT_SIEGE &&
01988 client->siegeClass != -1 &&
01989 bgSiegeClasses[client->siegeClass].saberStance)
01990 {
01991 if (!(bgSiegeClasses[client->siegeClass].saberStance & (1 << client->ps.fd.saberAnimLevel)))
01992 {
01993 int i = SS_FAST;
01994
01995 while (i < SS_NUM_SABER_STYLES)
01996 {
01997 if (bgSiegeClasses[client->siegeClass].saberStance & (1 << i))
01998 {
01999 if (i == SS_DUAL
02000 && client->ps.saberHolstered == 1 )
02001 {
02002 client->ps.fd.saberAnimLevelBase = i;
02003 client->ps.fd.saberAnimLevel = SS_FAST;
02004 client->ps.fd.saberDrawAnimLevel = client->ps.fd.saberAnimLevel;
02005 }
02006 else if ( i == SS_STAFF
02007 && client->ps.saberHolstered == 1
02008 && client->saber[0].singleBladeStyle != SS_NONE)
02009 {
02010 client->ps.fd.saberAnimLevelBase = i;
02011 client->ps.fd.saberAnimLevel = client->saber[0].singleBladeStyle;
02012 client->ps.fd.saberDrawAnimLevel = client->ps.fd.saberAnimLevel;
02013 }
02014 else
02015 {
02016 client->ps.fd.saberAnimLevelBase = client->ps.fd.saberAnimLevel = i;
02017 client->ps.fd.saberDrawAnimLevel = i;
02018 }
02019 break;
02020 }
02021
02022 i++;
02023 }
02024 }
02025 }
02026 else if (client->saber[0].model[0] && client->saber[1].model[0])
02027 {
02028 if ( client->ps.saberHolstered == 1 )
02029 {
02030 client->ps.fd.saberAnimLevelBase = SS_DUAL;
02031 client->ps.fd.saberAnimLevel = SS_FAST;
02032 client->ps.fd.saberDrawAnimLevel = client->ps.fd.saberAnimLevel;
02033 }
02034 else
02035 {
02036 if ( !WP_SaberStyleValidForSaber( &client->saber[0], &client->saber[1], client->ps.saberHolstered, client->ps.fd.saberAnimLevel ) )
02037 {
02038 client->ps.fd.saberAnimLevelBase = client->ps.fd.saberAnimLevel = SS_DUAL;
02039 }
02040 client->ps.fd.saberDrawAnimLevel = client->ps.fd.saberAnimLevel;
02041 }
02042 }
02043 else
02044 {
02045 if (client->saber[0].stylesLearned == (1<<SS_STAFF) )
02046 {
02047 client->ps.fd.saberAnimLevelBase = SS_STAFF;
02048 }
02049 if ( client->ps.fd.saberAnimLevelBase == SS_STAFF )
02050 {
02051 if ( client->ps.saberHolstered == 1
02052 && client->saber[0].singleBladeStyle != SS_NONE)
02053 {
02054 client->ps.fd.saberAnimLevel = client->saber[0].singleBladeStyle;
02055 client->ps.fd.saberDrawAnimLevel = client->ps.fd.saberAnimLevel;
02056 }
02057 else
02058 {
02059 client->ps.fd.saberAnimLevel = SS_STAFF;
02060 client->ps.fd.saberDrawAnimLevel = client->ps.fd.saberAnimLevel;
02061 }
02062 }
02063 }
02064 }
02065
02066
02067 ucmd = &ent->client->pers.cmd;
02068
02069 if ( client && (client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
02070 {
02071 G_HeldByMonster( ent, &ucmd );
02072 }
02073
02074
02075 if ( ucmd->serverTime > level.time + 200 ) {
02076 ucmd->serverTime = level.time + 200;
02077
02078 }
02079 if ( ucmd->serverTime < level.time - 1000 ) {
02080 ucmd->serverTime = level.time - 1000;
02081
02082 }
02083
02084 if (isNPC && (ucmd->serverTime - client->ps.commandTime) < 1)
02085 {
02086 ucmd->serverTime = client->ps.commandTime + 100;
02087 }
02088
02089 msec = ucmd->serverTime - client->ps.commandTime;
02090
02091
02092 if ( msec < 1 && client->sess.spectatorState != SPECTATOR_FOLLOW ) {
02093 return;
02094 }
02095
02096 if ( msec > 200 ) {
02097 msec = 200;
02098 }
02099
02100 if ( pmove_msec.integer < 8 ) {
02101 trap_Cvar_Set("pmove_msec", "8");
02102 }
02103 else if (pmove_msec.integer > 33) {
02104 trap_Cvar_Set("pmove_msec", "33");
02105 }
02106
02107 if ( pmove_fixed.integer || client->pers.pmoveFixed ) {
02108 ucmd->serverTime = ((ucmd->serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer;
02109
02110
02111 }
02112
02113
02114
02115
02116 if ( level.intermissiontime )
02117 {
02118 if ( ent->s.number < MAX_CLIENTS
02119 || client->NPC_class == CLASS_VEHICLE )
02120 {
02121 ClientIntermissionThink( client );
02122 return;
02123 }
02124 }
02125
02126
02127 if ( client->sess.sessionTeam == TEAM_SPECTATOR || client->tempSpectate > level.time ) {
02128 if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) {
02129 return;
02130 }
02131 SpectatorThink( ent, ucmd );
02132 return;
02133 }
02134
02135 if (ent && ent->client && (ent->client->ps.eFlags & EF_INVULNERABLE))
02136 {
02137 if (ent->client->invulnerableTimer <= level.time)
02138 {
02139 ent->client->ps.eFlags &= ~EF_INVULNERABLE;
02140 }
02141 }
02142
02143 if (ent->s.eType != ET_NPC)
02144 {
02145
02146 if ( !ClientInactivityTimer( client ) ) {
02147 return;
02148 }
02149 }
02150
02151
02152 if (client->pushEffectTime > level.time)
02153 {
02154 client->ps.eFlags |= EF_BODYPUSH;
02155 }
02156 else if (client->pushEffectTime)
02157 {
02158 client->pushEffectTime = 0;
02159 client->ps.eFlags &= ~EF_BODYPUSH;
02160 }
02161
02162 if (client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_JETPACK))
02163 {
02164 client->ps.eFlags |= EF_JETPACK;
02165 }
02166 else
02167 {
02168 client->ps.eFlags &= ~EF_JETPACK;
02169 }
02170
02171 if ( client->noclip ) {
02172 client->ps.pm_type = PM_NOCLIP;
02173 } else if ( client->ps.eFlags & EF_DISINTEGRATION ) {
02174 client->ps.pm_type = PM_NOCLIP;
02175 } else if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
02176 client->ps.pm_type = PM_DEAD;
02177 } else {
02178 if (client->ps.forceGripChangeMovetype)
02179 {
02180 client->ps.pm_type = client->ps.forceGripChangeMovetype;
02181 }
02182 else
02183 {
02184 if (client->jetPackOn)
02185 {
02186 client->ps.pm_type = PM_JETPACK;
02187 client->ps.eFlags |= EF_JETPACK_ACTIVE;
02188 killJetFlags = qfalse;
02189 }
02190 else
02191 {
02192 client->ps.pm_type = PM_NORMAL;
02193 }
02194 }
02195 }
02196
02197 if (killJetFlags)
02198 {
02199 client->ps.eFlags &= ~EF_JETPACK_ACTIVE;
02200 client->ps.eFlags &= ~EF_JETPACK_FLAMING;
02201 }
02202
02203 #define SLOWDOWN_DIST 128.0f
02204 #define MIN_NPC_SPEED 16.0f
02205
02206 if (client->bodyGrabIndex != ENTITYNUM_NONE)
02207 {
02208 gentity_t *grabbed = &g_entities[client->bodyGrabIndex];
02209
02210 if (!grabbed->inuse || grabbed->s.eType != ET_BODY ||
02211 (grabbed->s.eFlags & EF_DISINTEGRATION) ||
02212 (grabbed->s.eFlags & EF_NODRAW))
02213 {
02214 if (grabbed->inuse && grabbed->s.eType == ET_BODY)
02215 {
02216 grabbed->s.ragAttach = 0;
02217 }
02218 client->bodyGrabIndex = ENTITYNUM_NONE;
02219 }
02220 else
02221 {
02222 mdxaBone_t rhMat;
02223 vec3_t rhOrg, tAng;
02224 vec3_t bodyDir;
02225 float bodyDist;
02226
02227 ent->client->ps.forceHandExtend = HANDEXTEND_DRAGGING;
02228
02229 if (ent->client->ps.forceHandExtendTime < level.time + 500)
02230 {
02231 ent->client->ps.forceHandExtendTime = level.time + 1000;
02232 }
02233
02234 VectorSet(tAng, 0, ent->client->ps.viewangles[YAW], 0);
02235 trap_G2API_GetBoltMatrix(ent->ghoul2, 0, 0, &rhMat, tAng, ent->client->ps.origin, level.time,
02236 NULL, ent->modelScale);
02237 BG_GiveMeVectorFromMatrix(&rhMat, ORIGIN, rhOrg);
02238
02239 VectorSubtract(rhOrg, grabbed->r.currentOrigin, bodyDir);
02240 bodyDist = VectorLength(bodyDir);
02241
02242 if (bodyDist > 40.0f)
02243 {
02244 grabbed->s.ragAttach = 0;
02245 client->bodyGrabIndex = ENTITYNUM_NONE;
02246 }
02247 else if (bodyDist > 24.0f)
02248 {
02249 bodyDir[2] = 0;
02250
02251 VectorAdd(grabbed->epVelocity, bodyDir, grabbed->epVelocity);
02252 G_Sound(grabbed, CHAN_AUTO, G_SoundIndex("sound/player/roll1.wav"));
02253 }
02254 }
02255 }
02256 else if (ent->client->ps.forceHandExtend == HANDEXTEND_DRAGGING)
02257 {
02258 ent->client->ps.forceHandExtend = HANDEXTEND_WEAPONREADY;
02259 }
02260
02261 if (ent->NPC && ent->s.NPC_class != CLASS_VEHICLE)
02262 {
02263
02264 if ( ent->NPC->combatMove == qfalse )
02265 {
02266
02267 if (1)
02268 {
02269 qboolean Flying = (ucmd->upmove && (ent->client->ps.eFlags2&EF2_FLYING));
02270 qboolean Climbing = (ucmd->upmove && ent->watertype&CONTENTS_LADDER );
02271
02272
02273
02274 if ( ucmd->forwardmove || ucmd->rightmove || Flying )
02275 {
02276
02277 {
02278 if ( ucmd->buttons & BUTTON_WALKING )
02279 {
02280 ent->NPC->desiredSpeed = NPC_GetWalkSpeed( ent );
02281 }
02282 else
02283 {
02284 ent->NPC->desiredSpeed = NPC_GetRunSpeed( ent );
02285 }
02286
02287 if ( ent->NPC->currentSpeed >= 80 && !controlledByPlayer )
02288 {
02289
02290
02291 if ( ent->NPC->distToGoal < SLOWDOWN_DIST && !(ent->NPC->aiFlags&NPCAI_NO_SLOWDOWN) )
02292 {
02293 if ( ent->NPC->desiredSpeed > MIN_NPC_SPEED )
02294 {
02295 float slowdownSpeed = ((float)ent->NPC->desiredSpeed) * ent->NPC->distToGoal / SLOWDOWN_DIST;
02296
02297 ent->NPC->desiredSpeed = ceil(slowdownSpeed);
02298 if ( ent->NPC->desiredSpeed < MIN_NPC_SPEED )
02299 {
02300 ent->NPC->desiredSpeed = MIN_NPC_SPEED;
02301 }
02302 }
02303 }
02304 }
02305 }
02306 }
02307 else if ( Climbing )
02308 {
02309 ent->NPC->desiredSpeed = ent->NPC->stats.walkSpeed;
02310 }
02311 else
02312 {
02313 ent->NPC->desiredSpeed = 0;
02314 }
02315
02316 NPC_Accelerate( ent, qfalse, qfalse );
02317
02318 if ( ent->NPC->currentSpeed <= 24 && ent->NPC->desiredSpeed < ent->NPC->currentSpeed )
02319 {
02320 client->ps.speed = ent->NPC->currentSpeed = 0;
02321 ucmd->forwardmove = 0;
02322 ucmd->rightmove = 0;
02323 }
02324 else
02325 {
02326 if ( ent->NPC->currentSpeed <= ent->NPC->stats.walkSpeed )
02327 {
02328 ucmd->buttons |= BUTTON_WALKING;
02329 }
02330 else
02331 {
02332 ucmd->buttons &= ~BUTTON_WALKING;
02333 }
02334
02335 if ( ent->NPC->currentSpeed > 0 )
02336 {
02337 if ( Climbing || Flying )
02338 {
02339 if ( !ucmd->upmove )
02340 {
02341 ucmd->upmove = ent->NPC->last_ucmd.upmove;
02342 }
02343 }
02344 else if ( !ucmd->forwardmove && !ucmd->rightmove )
02345 {
02346 ucmd->forwardmove = ent->NPC->last_ucmd.forwardmove;
02347 ucmd->rightmove = ent->NPC->last_ucmd.rightmove;
02348 }
02349 }
02350
02351 client->ps.speed = ent->NPC->currentSpeed;
02352
02353
02354
02355
02356
02357 if (1)
02358 {
02359
02360 float turndelta = 0;
02361
02362
02363 if (0)
02364 {
02365 turndelta = (180 - fabs( AngleDelta( ent->r.currentAngles[YAW], ent->NPC->lockedDesiredYaw ) ))/180;
02366 }
02367 else
02368 {
02369 turndelta = (180 - fabs( AngleDelta( ent->r.currentAngles[YAW], ent->NPC->desiredYaw ) ))/180;
02370 }
02371
02372 if ( turndelta < 0.75f )
02373 {
02374 client->ps.speed = 0;
02375 }
02376 else if ( ent->NPC->distToGoal < 100 && turndelta < 1.0 )
02377 {
02378 client->ps.speed = floor(((float)(client->ps.speed))*turndelta);
02379 }
02380 }
02381 }
02382 }
02383 }
02384 else
02385 {
02386 ent->NPC->desiredSpeed = ( ucmd->buttons & BUTTON_WALKING ) ? NPC_GetWalkSpeed( ent ) : NPC_GetRunSpeed( ent );
02387
02388 client->ps.speed = ent->NPC->desiredSpeed;
02389 }
02390
02391 if (ucmd->buttons & BUTTON_WALKING)
02392 {
02393
02394
02395
02396
02397
02398
02399
02400 if (ucmd->forwardmove > 64)
02401 {
02402 ucmd->forwardmove = 64;
02403 }
02404 else if (ucmd->forwardmove < -64)
02405 {
02406 ucmd->forwardmove = -64;
02407 }
02408
02409 if (ucmd->rightmove > 64)
02410 {
02411 ucmd->rightmove = 64;
02412 }
02413 else if ( ucmd->rightmove < -64)
02414 {
02415 ucmd->rightmove = -64;
02416 }
02417
02418
02419 }
02420 client->ps.basespeed = client->ps.speed;
02421 }
02422 else if (!client->ps.m_iVehicleNum &&
02423 (!ent->NPC || ent->s.NPC_class != CLASS_VEHICLE))
02424 {
02425
02426 client->ps.speed = g_speed.value;
02427
02428
02429 if (g_gametype.integer == GT_SIEGE &&
02430 client->siegeClass != -1)
02431 {
02432 client->ps.speed *= bgSiegeClasses[client->siegeClass].speed;
02433 }
02434
02435 if (client->bodyGrabIndex != ENTITYNUM_NONE)
02436 {
02437 client->ps.speed *= 0.2f;
02438 }
02439
02440 client->ps.basespeed = client->ps.speed;
02441 }
02442
02443 if ( !ent->NPC || !(ent->NPC->aiFlags&NPCAI_CUSTOM_GRAVITY) )
02444 {
02445 if (ent->NPC && ent->s.NPC_class == CLASS_VEHICLE &&
02446 ent->m_pVehicle && ent->m_pVehicle->m_pVehicleInfo->gravity)
02447 {
02448 client->ps.gravity = ent->m_pVehicle->m_pVehicleInfo->gravity;
02449 }
02450 else
02451 {
02452 if (ent->client->inSpaceIndex && ent->client->inSpaceIndex != ENTITYNUM_NONE)
02453 {
02454 client->ps.gravity = 1.0f;
02455 if (ent->s.number < MAX_CLIENTS)
02456 {
02457 VectorScale(client->ps.velocity, 0.8f, client->ps.velocity);
02458 }
02459 }
02460 else
02461 {
02462 if (client->ps.eFlags2 & EF2_SHIP_DEATH)
02463 {
02464 VectorClear(client->ps.velocity);
02465 client->ps.gravity = 1.0f;
02466 }
02467 else
02468 {
02469 client->ps.gravity = g_gravity.value;
02470 }
02471 }
02472 }
02473 }
02474
02475 if (ent->client->ps.duelInProgress)
02476 {
02477 gentity_t *duelAgainst = &g_entities[ent->client->ps.duelIndex];
02478
02479
02480
02481
02482 ent->client->ps.fd.privateDuelTime = level.time + 10000;
02483
02484 if (ent->client->ps.duelTime < level.time)
02485 {
02486
02487 if (ent->client->ps.weapon == WP_SABER
02488 && ent->client->ps.saberHolstered
02489 && ent->client->ps.duelTime )
02490 {
02491 ent->client->ps.saberHolstered = 0;
02492
02493 if (ent->client->saber[0].soundOn)
02494 {
02495 G_Sound(ent, CHAN_AUTO, ent->client->saber[0].soundOn);
02496 }
02497 if (ent->client->saber[1].soundOn)
02498 {
02499 G_Sound(ent, CHAN_AUTO, ent->client->saber[1].soundOn);
02500 }
02501
02502 G_AddEvent(ent, EV_PRIVATE_DUEL, 2);
02503
02504 ent->client->ps.duelTime = 0;
02505 }
02506
02507 if (duelAgainst
02508 && duelAgainst->client
02509 && duelAgainst->inuse
02510 && duelAgainst->client->ps.weapon == WP_SABER
02511 && duelAgainst->client->ps.saberHolstered
02512 && duelAgainst->client->ps.duelTime)
02513 {
02514 duelAgainst->client->ps.saberHolstered = 0;
02515
02516 if (duelAgainst->client->saber[0].soundOn)
02517 {
02518 G_Sound(duelAgainst, CHAN_AUTO, duelAgainst->client->saber[0].soundOn);
02519 }
02520 if (duelAgainst->client->saber[1].soundOn)
02521 {
02522 G_Sound(duelAgainst, CHAN_AUTO, duelAgainst->client->saber[1].soundOn);
02523 }
02524
02525 G_AddEvent(duelAgainst, EV_PRIVATE_DUEL, 2);
02526
02527 duelAgainst->client->ps.duelTime = 0;
02528 }
02529 }
02530 else
02531 {
02532 client->ps.speed = 0;
02533 client->ps.basespeed = 0;
02534 ucmd->forwardmove = 0;
02535 ucmd->rightmove = 0;
02536 ucmd->upmove = 0;
02537 }
02538
02539 if (!duelAgainst || !duelAgainst->client || !duelAgainst->inuse ||
02540 duelAgainst->client->ps.duelIndex != ent->s.number)
02541 {
02542 ent->client->ps.duelInProgress = 0;
02543 G_AddEvent(ent, EV_PRIVATE_DUEL, 0);
02544 }
02545 else if (duelAgainst->health < 1 || duelAgainst->client->ps.stats[STAT_HEALTH] < 1)
02546 {
02547 ent->client->ps.duelInProgress = 0;
02548 duelAgainst->client->ps.duelInProgress = 0;
02549
02550 G_AddEvent(ent, EV_PRIVATE_DUEL, 0);
02551 G_AddEvent(duelAgainst, EV_PRIVATE_DUEL, 0);
02552
02553
02554 if (ent->health > 0 && ent->client->ps.stats[STAT_HEALTH] > 0)
02555 {
02556 if (ent->health < ent->client->ps.stats[STAT_MAX_HEALTH])
02557 {
02558 ent->client->ps.stats[STAT_HEALTH] = ent->health = ent->client->ps.stats[STAT_MAX_HEALTH];
02559 }
02560
02561 if (g_spawnInvulnerability.integer)
02562 {
02563 ent->client->ps.eFlags |= EF_INVULNERABLE;
02564 ent->client->invulnerableTimer = level.time + g_spawnInvulnerability.integer;
02565 }
02566 }
02567
02568
02569
02570
02571
02572
02573 if (ent->health > 0 && ent->client->ps.stats[STAT_HEALTH] > 0)
02574 {
02575 trap_SendServerCommand( -1, va("cp \"%s %s %s!\n\"", ent->client->pers.netname, G_GetStringEdString("MP_SVGAME", "PLDUELWINNER"), duelAgainst->client->pers.netname) );
02576 }
02577 else
02578 {
02579 trap_SendServerCommand( -1, va("cp \"%s\n\"", G_GetStringEdString("MP_SVGAME", "PLDUELTIE")) );
02580 }
02581 }
02582 else
02583 {
02584 vec3_t vSub;
02585 float subLen = 0;
02586
02587 VectorSubtract(ent->client->ps.origin, duelAgainst->client->ps.origin, vSub);
02588 subLen = VectorLength(vSub);
02589
02590 if (subLen >= 1024)
02591 {
02592 ent->client->ps.duelInProgress = 0;
02593 duelAgainst->client->ps.duelInProgress = 0;
02594
02595 G_AddEvent(ent, EV_PRIVATE_DUEL, 0);
02596 G_AddEvent(duelAgainst, EV_PRIVATE_DUEL, 0);
02597
02598 trap_SendServerCommand( -1, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME", "PLDUELSTOP")) );
02599 }
02600 }
02601 }
02602
02603 if (ent->client->doingThrow > level.time)
02604 {
02605 gentity_t *throwee = &g_entities[ent->client->throwingIndex];
02606
02607 if (!throwee->inuse || !throwee->client || throwee->health < 1 ||
02608 throwee->client->sess.sessionTeam == TEAM_SPECTATOR ||
02609 (throwee->client->ps.pm_flags & PMF_FOLLOW) ||
02610 throwee->client->throwingIndex != ent->s.number)
02611 {
02612 ent->client->doingThrow = 0;
02613 ent->client->ps.forceHandExtend = HANDEXTEND_NONE;
02614
02615 if (throwee->inuse && throwee->client)
02616 {
02617 throwee->client->ps.heldByClient = 0;
02618 throwee->client->beingThrown = 0;
02619
02620 if (throwee->client->ps.forceHandExtend != HANDEXTEND_POSTTHROWN)
02621 {
02622 throwee->client->ps.forceHandExtend = HANDEXTEND_NONE;
02623 }
02624 }
02625 }
02626 }
02627
02628 if (ent->client->beingThrown > level.time)
02629 {
02630 gentity_t *thrower = &g_entities[ent->client->throwingIndex];
02631
02632 if (!thrower->inuse || !thrower->client || thrower->health < 1 ||
02633 thrower->client->sess.sessionTeam == TEAM_SPECTATOR ||
02634 (thrower->client->ps.pm_flags & PMF_FOLLOW) ||
02635 thrower->client->throwingIndex != ent->s.number)
02636 {
02637 ent->client->ps.heldByClient = 0;
02638 ent->client->beingThrown = 0;
02639
02640 if (ent->client->ps.forceHandExtend != HANDEXTEND_POSTTHROWN)
02641 {
02642 ent->client->ps.forceHandExtend = HANDEXTEND_NONE;
02643 }
02644
02645 if (thrower->inuse && thrower->client)
02646 {
02647 thrower->client->doingThrow = 0;
02648 thrower->client->ps.forceHandExtend = HANDEXTEND_NONE;
02649 }
02650 }
02651 else if (thrower->inuse && thrower->client && thrower->ghoul2 &&
02652 trap_G2_HaveWeGhoul2Models(thrower->ghoul2))
02653 {
02654 #if 0
02655 int lHandBolt = trap_G2API_AddBolt(thrower->ghoul2, 0, "*l_hand");
02656 int pelBolt = trap_G2API_AddBolt(thrower->ghoul2, 0, "pelvis");
02657
02658
02659 if (lHandBolt != -1 && pelBolt != -1)
02660 #endif
02661 {
02662 float pDif = 40.0f;
02663 vec3_t boltOrg, pBoltOrg;
02664 vec3_t tAngles;
02665 vec3_t vDif;
02666 vec3_t entDir, otherAngles;
02667 vec3_t fwd, right;
02668
02669
02670 VectorSubtract( thrower->client->ps.origin, ent->client->ps.origin, entDir );
02671 VectorCopy( ent->client->ps.viewangles, otherAngles );
02672 otherAngles[YAW] = vectoyaw( entDir );
02673 SetClientViewAngle( ent, otherAngles );
02674
02675 VectorCopy(thrower->client->ps.viewangles, tAngles);
02676 tAngles[PITCH] = tAngles[ROLL] = 0;
02677
02678
02679 #if 0
02680 mdxaBone_t boltMatrix, pBoltMatrix;
02681
02682 trap_G2API_GetBoltMatrix(thrower->ghoul2, 0, lHandBolt, &boltMatrix, tAngles, thrower->client->ps.origin, level.time, 0, thrower->modelScale);
02683 boltOrg[0] = boltMatrix.matrix[0][3];
02684 boltOrg[1] = boltMatrix.matrix[1][3];
02685 boltOrg[2] = boltMatrix.matrix[2][3];
02686
02687 trap_G2API_GetBoltMatrix(thrower->ghoul2, 0, pelBolt, &pBoltMatrix, tAngles, thrower->client->ps.origin, level.time, 0, thrower->modelScale);
02688 pBoltOrg[0] = pBoltMatrix.matrix[0][3];
02689 pBoltOrg[1] = pBoltMatrix.matrix[1][3];
02690 pBoltOrg[2] = pBoltMatrix.matrix[2][3];
02691 #else //above tends to not work once in a while, for various reasons I suppose.
02692 VectorCopy(thrower->client->ps.origin, pBoltOrg);
02693 AngleVectors(tAngles, fwd, right, 0);
02694 boltOrg[0] = pBoltOrg[0] + fwd[0]*8 + right[0]*pDif;
02695 boltOrg[1] = pBoltOrg[1] + fwd[1]*8 + right[1]*pDif;
02696 boltOrg[2] = pBoltOrg[2];
02697 #endif
02698
02699
02700 VectorSubtract(ent->client->ps.origin, boltOrg, vDif);
02701 if (VectorLength(vDif) > 32.0f && (thrower->client->doingThrow - level.time) < 4500)
02702 {
02703 ent->client->ps.heldByClient = 0;
02704 ent->client->beingThrown = 0;
02705 thrower->client->doingThrow = 0;
02706
02707 thrower->client->ps.forceHandExtend = HANDEXTEND_NONE;
02708 G_EntitySound( thrower, CHAN_VOICE, G_SoundIndex("*pain25.wav") );
02709
02710 ent->client->ps.forceDodgeAnim = 2;
02711 ent->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN;
02712 ent->client->ps.forceHandExtendTime = level.time + 500;
02713 ent->client->ps.velocity[2] = 400;
02714 G_PreDefSound(ent->client->ps.origin, PDSOUND_FORCEJUMP);
02715 }
02716 else if ((client->beingThrown - level.time) < 4000)
02717 {
02718 float vScale = 400.0f;
02719 ent->client->ps.forceHandExtend = HANDEXTEND_POSTTHROWN;
02720 ent->client->ps.forceHandExtendTime = level.time + 1200;
02721 ent->client->ps.forceDodgeAnim = 0;
02722
02723 thrower->client->ps.forceHandExtend = HANDEXTEND_POSTTHROW;
02724 thrower->client->ps.forceHandExtendTime = level.time + 200;
02725
02726 ent->client->ps.heldByClient = 0;
02727
02728 ent->client->ps.heldByClient = 0;
02729 ent->client->beingThrown = 0;
02730 thrower->client->doingThrow = 0;
02731
02732 AngleVectors(thrower->client->ps.viewangles, vDif, 0, 0);
02733 ent->client->ps.velocity[0] = vDif[0]*vScale;
02734 ent->client->ps.velocity[1] = vDif[1]*vScale;
02735 ent->client->ps.velocity[2] = 400;
02736
02737 G_EntitySound( ent, CHAN_VOICE, G_SoundIndex("*pain100.wav") );
02738 G_EntitySound( thrower, CHAN_VOICE, G_SoundIndex("*jump1.wav") );
02739
02740
02741 ent->client->ps.otherKiller = thrower->s.number;
02742 ent->client->ps.otherKillerTime = level.time + 8000;
02743 ent->client->ps.otherKillerDebounceTime = level.time + 100;
02744 }
02745 else
02746 {
02747 vec3_t intendedOrigin;
02748 trace_t tr;
02749 trace_t tr2;
02750
02751 VectorSubtract(boltOrg, pBoltOrg, vDif);
02752 VectorNormalize(vDif);
02753
02754 VectorClear(ent->client->ps.velocity);
02755 intendedOrigin[0] = pBoltOrg[0] + vDif[0]*pDif;
02756 intendedOrigin[1] = pBoltOrg[1] + vDif[1]*pDif;
02757 intendedOrigin[2] = thrower->client->ps.origin[2];
02758
02759 trap_Trace(&tr, intendedOrigin, ent->r.mins, ent->r.maxs, intendedOrigin, ent->s.number, ent->clipmask);
02760 trap_Trace(&tr2, ent->client->ps.origin, ent->r.mins, ent->r.maxs, intendedOrigin, ent->s.number, CONTENTS_SOLID);
02761
02762 if (tr.fraction == 1.0 && !tr.startsolid && tr2.fraction == 1.0 && !tr2.startsolid)
02763 {
02764 VectorCopy(intendedOrigin, ent->client->ps.origin);
02765
02766 if ((client->beingThrown - level.time) < 4800)
02767 {
02768 ent->client->ps.heldByClient = thrower->s.number+1;
02769 }
02770 }
02771 else
02772 {
02773 ent->client->ps.heldByClient = 0;
02774 ent->client->beingThrown = 0;
02775 thrower->client->doingThrow = 0;
02776
02777 thrower->client->ps.forceHandExtend = HANDEXTEND_NONE;
02778 G_EntitySound( thrower, CHAN_VOICE, G_SoundIndex("*pain25.wav") );
02779
02780 ent->client->ps.forceDodgeAnim = 2;
02781 ent->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN;
02782 ent->client->ps.forceHandExtendTime = level.time + 500;
02783 ent->client->ps.velocity[2] = 400;
02784 G_PreDefSound(ent->client->ps.origin, PDSOUND_FORCEJUMP);
02785 }
02786 }
02787 }
02788 }
02789 }
02790 else if (ent->client->ps.heldByClient)
02791 {
02792 ent->client->ps.heldByClient = 0;
02793 }
02794
02795
02796
02797
02798
02799
02800
02801
02802
02803
02804
02805
02806
02807
02808
02809
02810
02811
02812
02813
02814
02815
02816
02817
02818
02819
02820
02821
02822 oldEventSequence = client->ps.eventSequence;
02823
02824 memset (&pm, 0, sizeof(pm));
02825
02826 if ( ent->flags & FL_FORCE_GESTURE ) {
02827 ent->flags &= ~FL_FORCE_GESTURE;
02828 ent->client->pers.cmd.buttons |= BUTTON_GESTURE;
02829 }
02830
02831 if (ent->client && ent->client->ps.fallingToDeath &&
02832 (level.time - FALL_FADE_TIME) > ent->client->ps.fallingToDeath)
02833 {
02834 if (ent->health > 0)
02835 {
02836 gentity_t *otherKiller = ent;
02837 if (ent->client->ps.otherKillerTime > level.time &&
02838 ent->client->ps.otherKiller != ENTITYNUM_NONE)
02839 {
02840 otherKiller = &g_entities[ent->client->ps.otherKiller];
02841
02842 if (!otherKiller->inuse)
02843 {
02844 otherKiller = ent;
02845 }
02846 }
02847 G_Damage(ent, otherKiller, otherKiller, NULL, ent->client->ps.origin, 9999, DAMAGE_NO_PROTECTION, MOD_FALLING);
02848
02849
02850
02851
02852
02853
02854
02855 G_MuteSound(ent->s.number, CHAN_VOICE);
02856 }
02857 }
02858
02859 if (ent->client->ps.otherKillerTime > level.time &&
02860 ent->client->ps.groundEntityNum != ENTITYNUM_NONE &&
02861 ent->client->ps.otherKillerDebounceTime < level.time)
02862 {
02863 ent->client->ps.otherKillerTime = 0;
02864 ent->client->ps.otherKiller = ENTITYNUM_NONE;
02865 }
02866 else if (ent->client->ps.otherKillerTime > level.time &&
02867 ent->client->ps.groundEntityNum == ENTITYNUM_NONE)
02868 {
02869 if (ent->client->ps.otherKillerDebounceTime < (level.time + 100))
02870 {
02871 ent->client->ps.otherKillerDebounceTime = level.time + 100;
02872 }
02873 }
02874
02875
02876
02877
02878
02879 if ( ent->client->ps.useDelay > level.time
02880 && ent->client->ps.m_iVehicleNum )
02881 {
02882 ucmd->buttons &= ~BUTTON_USE;
02883 }
02884
02885
02886 G_AddPushVecToUcmd( ent, ucmd );
02887
02888
02889 G_CheckMovingLoopingSounds( ent, ucmd );
02890
02891 pm.ps = &client->ps;
02892 pm.cmd = *ucmd;
02893 if ( pm.ps->pm_type == PM_DEAD ) {
02894 pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
02895 }
02896 else if ( ent->r.svFlags & SVF_BOT ) {
02897 pm.tracemask = MASK_PLAYERSOLID | CONTENTS_MONSTERCLIP;
02898 }
02899 else {
02900 pm.tracemask = MASK_PLAYERSOLID;
02901 }
02902 pm.trace = trap_Trace;
02903 pm.pointcontents = trap_PointContents;
02904 pm.debugLevel = g_debugMove.integer;
02905 pm.noFootsteps = ( g_dmflags.integer & DF_NO_FOOTSTEPS ) > 0;
02906
02907 pm.pmove_fixed = pmove_fixed.integer | client->pers.pmoveFixed;
02908 pm.pmove_msec = pmove_msec.integer;
02909
02910 pm.animations = bgAllAnims[ent->localAnimIndex].anims;
02911
02912
02913 pm.ghoul2 = NULL;
02914
02915 #ifdef _DEBUG
02916 if (g_disableServerG2.integer)
02917 {
02918
02919 }
02920 else
02921 #endif
02922 if (ent->ghoul2)
02923 {
02924 if (ent->localAnimIndex > 1)
02925 {
02926 pm.ghoul2 = NULL;
02927 }
02928 else
02929 {
02930 pm.ghoul2 = ent->ghoul2;
02931 pm.g2Bolts_LFoot = trap_G2API_AddBolt(ent->ghoul2, 0, "*l_leg_foot");
02932 pm.g2Bolts_RFoot = trap_G2API_AddBolt(ent->ghoul2, 0, "*r_leg_foot");
02933 }
02934 }
02935
02936
02937 #if 0
02938 k = 0;
02939 while (k < MAX_SABERS)
02940 {
02941 if (ent->client->saber[k].model[0])
02942 {
02943 pm.saber[k] = &ent->client->saber[k];
02944 }
02945 else
02946 {
02947 pm.saber[k] = NULL;
02948 }
02949 k++;
02950 }
02951 #endif
02952
02953
02954 VectorCopy(ent->modelScale, pm.modelScale);
02955
02956
02957 pm.gametype = g_gametype.integer;
02958 pm.debugMelee = g_debugMelee.integer;
02959 pm.stepSlideFix = g_stepSlideFix.integer;
02960
02961 pm.noSpecMove = g_noSpecMove.integer;
02962
02963 pm.nonHumanoid = (ent->localAnimIndex > 0);
02964
02965 VectorCopy( client->ps.origin, client->oldOrigin );
02966
02967
02968
02969
02970
02971
02972
02973
02974
02975
02976
02977
02978
02979
02980
02981
02982
02983 pm.baseEnt = (bgEntity_t *)g_entities;
02984 pm.entSize = sizeof(gentity_t);
02985
02986 if (ent->client->ps.saberLockTime > level.time)
02987 {
02988 gentity_t *blockOpp = &g_entities[ent->client->ps.saberLockEnemy];
02989
02990 if (blockOpp && blockOpp->inuse && blockOpp->client)
02991 {
02992 vec3_t lockDir, lockAng;
02993
02994
02995 VectorSubtract( blockOpp->r.currentOrigin, ent->r.currentOrigin, lockDir );
02996
02997 vectoangles(lockDir, lockAng);
02998 SetClientViewAngle( ent, lockAng );
02999 }
03000
03001 if ( ent->client->ps.saberLockHitCheckTime < level.time )
03002 {
03003 ent->client->ps.saberLockHitCheckTime = level.time;
03004 if ( ( ent->client->buttons & BUTTON_ATTACK ) && ! ( ent->client->oldbuttons & BUTTON_ATTACK ) )
03005 {
03006 if ( ent->client->ps.saberLockHitIncrementTime < level.time )
03007 {
03008 int lockHits = 0;
03009 ent->client->ps.saberLockHitIncrementTime = level.time;
03010
03011 if ( (ent->client->ps.fd.forcePowersActive&(1<<FP_RAGE)) )
03012 {
03013 lockHits = 1+ent->client->ps.fd.forcePowerLevel[FP_RAGE];
03014 }
03015 else
03016 {
03017 switch ( ent->client->ps.fd.saberAnimLevel )
03018 {
03019 case SS_FAST:
03020 lockHits = 1;
03021 break;
03022 case SS_MEDIUM:
03023 case SS_TAVION:
03024 case SS_DUAL:
03025 case SS_STAFF:
03026 lockHits = 2;
03027 break;
03028 case SS_STRONG:
03029 case SS_DESANN:
03030 lockHits = 3;
03031 break;
03032 }
03033 }
03034 if ( ent->client->ps.fd.forceRageRecoveryTime > level.time
03035 && Q_irand( 0, 1 ) )
03036 {
03037 lockHits -= 1;
03038 }
03039 lockHits += ent->client->saber[0].lockBonus;
03040 if ( ent->client->saber[1].model
03041 && ent->client->saber[1].model[0]
03042 && !ent->client->ps.saberHolstered )
03043 {
03044 lockHits += ent->client->saber[1].lockBonus;
03045 }
03046 ent->client->ps.saberLockHits += lockHits;
03047 if ( g_saberLockRandomNess.integer )
03048 {
03049 ent->client->ps.saberLockHits += Q_irand( 0, g_saberLockRandomNess.integer );
03050 if ( ent->client->ps.saberLockHits < 0 )
03051 {
03052 ent->client->ps.saberLockHits = 0;
03053 }
03054 }
03055 }
03056 }
03057 if ( ent->client->ps.saberLockHits > 0 )
03058 {
03059 if ( !ent->client->ps.saberLockAdvance )
03060 {
03061 ent->client->ps.saberLockHits--;
03062 }
03063 ent->client->ps.saberLockAdvance = qtrue;
03064 }
03065 }
03066 }
03067 else
03068 {
03069 ent->client->ps.saberLockFrame = 0;
03070
03071 if ( (pm.cmd.generic_cmd == GENCMD_ENGAGE_DUEL) && (g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL) )
03072 {
03073 pm.cmd.buttons |= BUTTON_GESTURE;
03074 }
03075 }
03076
03077 if (ent->s.number >= MAX_CLIENTS)
03078 {
03079 VectorCopy(ent->r.mins, pm.mins);
03080 VectorCopy(ent->r.maxs, pm.maxs);
03081 #if 1
03082 if (ent->s.NPC_class == CLASS_VEHICLE &&
03083 ent->m_pVehicle )
03084 {
03085 if ( ent->m_pVehicle->m_pPilot)
03086 {
03087 if ((level.time - ent->m_pVehicle->m_ucmd.serverTime) > 2000)
03088 {
03089 ent->m_pVehicle->m_ucmd.serverTime = level.time;
03090 ent->client->ps.commandTime = level.time-100;
03091 msec = 100;
03092 }
03093
03094 memcpy(&pm.cmd, &ent->m_pVehicle->m_ucmd, sizeof(usercmd_t));
03095
03096
03097 pm.cmd.rightmove = 0;
03098
03099 pm.cmd.upmove = 0;
03100
03101
03102 assert(g_entities[ent->m_pVehicle->m_pPilot->s.number].client);
03103 pm.cmd.buttons = (g_entities[ent->m_pVehicle->m_pPilot->s.number].client->pers.cmd.buttons&(BUTTON_ATTACK|BUTTON_ALT_ATTACK));
03104 }
03105 if ( ent->m_pVehicle->m_pVehicleInfo->type == VH_WALKER )
03106 {
03107 if ( ent->client->ps.groundEntityNum != ENTITYNUM_NONE )
03108 {
03109 gentity_t *under = &g_entities[ent->client->ps.groundEntityNum];
03110 if ( under && under->health && under->takedamage )
03111 {
03112 vec3_t down = {0,0,-1};
03113
03114 G_Damage( under, ent, ent, down, under->r.currentOrigin, 100, 0, MOD_CRUSH );
03115 }
03116 }
03117 }
03118 }
03119 #endif
03120 }
03121
03122 Pmove (&pm);
03123
03124 if (ent->client->solidHack)
03125 {
03126 if (ent->client->solidHack > level.time)
03127 {
03128 ent->r.contents = 0;
03129 }
03130 else
03131 {
03132 ent->r.contents = CONTENTS_BODY;
03133 ent->client->solidHack = 0;
03134 }
03135 }
03136
03137 if ( ent->NPC )
03138 {
03139 VectorCopy( ent->client->ps.viewangles, ent->r.currentAngles );
03140 }
03141
03142 if (pm.checkDuelLoss)
03143 {
03144 if (pm.checkDuelLoss > 0 && (pm.checkDuelLoss <= MAX_CLIENTS || (pm.checkDuelLoss < (MAX_GENTITIES-1) && g_entities[pm.checkDuelLoss-1].s.eType == ET_NPC) ) )
03145 {
03146 gentity_t *clientLost = &g_entities[pm.checkDuelLoss-1];
03147
03148 if (clientLost && clientLost->inuse && clientLost->client && Q_irand(0, 40) > clientLost->health)
03149 {
03150 vec3_t attDir;
03151 VectorSubtract(ent->client->ps.origin, clientLost->client->ps.origin, attDir);
03152 VectorNormalize(attDir);
03153
03154 VectorClear(clientLost->client->ps.velocity);
03155 clientLost->client->ps.forceHandExtend = HANDEXTEND_NONE;
03156 clientLost->client->ps.forceHandExtendTime = 0;
03157
03158 gGAvoidDismember = 1;
03159 G_Damage(clientLost, ent, ent, attDir, clientLost->client->ps.origin, 9999, DAMAGE_NO_PROTECTION, MOD_SABER);
03160
03161 if (clientLost->health < 1)
03162 {
03163 gGAvoidDismember = 2;
03164 G_CheckForDismemberment(clientLost, ent, clientLost->client->ps.origin, 999, (clientLost->client->ps.legsAnim), qfalse);
03165 }
03166
03167 gGAvoidDismember = 0;
03168 }
03169 else if (clientLost && clientLost->inuse && clientLost->client &&
03170 clientLost->client->ps.forceHandExtend != HANDEXTEND_KNOCKDOWN && clientLost->client->ps.saberEntityNum)
03171 {
03172 saberCheckKnockdown_DuelLoss(&g_entities[clientLost->client->ps.saberEntityNum], clientLost, ent);
03173 }
03174 }
03175
03176 pm.checkDuelLoss = 0;
03177 }
03178
03179 if (pm.cmd.generic_cmd &&
03180 (pm.cmd.generic_cmd != ent->client->lastGenCmd || ent->client->lastGenCmdTime < level.time))
03181 {
03182 ent->client->lastGenCmd = pm.cmd.generic_cmd;
03183 if (pm.cmd.generic_cmd != GENCMD_FORCE_THROW &&
03184 pm.cmd.generic_cmd != GENCMD_FORCE_PULL)
03185 {
03186 ent->client->lastGenCmdTime = level.time + 300;
03187 }
03188
03189 switch(pm.cmd.generic_cmd)
03190 {
03191 case 0:
03192 break;
03193 case GENCMD_SABERSWITCH:
03194 Cmd_ToggleSaber_f(ent);
03195 break;
03196 case GENCMD_ENGAGE_DUEL:
03197 if ( g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL )
03198 {
03199 }
03200 else
03201 {
03202 Cmd_EngageDuel_f(ent);
03203 }
03204 break;
03205 case GENCMD_FORCE_HEAL:
03206 ForceHeal(ent);
03207 break;
03208 case GENCMD_FORCE_SPEED:
03209 ForceSpeed(ent, 0);
03210 break;
03211 case GENCMD_FORCE_THROW:
03212 ForceThrow(ent, qfalse);
03213 break;
03214 case GENCMD_FORCE_PULL:
03215 ForceThrow(ent, qtrue);
03216 break;
03217 case GENCMD_FORCE_DISTRACT:
03218 ForceTelepathy(ent);
03219 break;
03220 case GENCMD_FORCE_RAGE:
03221 ForceRage(ent);
03222 break;
03223 case GENCMD_FORCE_PROTECT:
03224 ForceProtect(ent);
03225 break;
03226 case GENCMD_FORCE_ABSORB:
03227 ForceAbsorb(ent);
03228 break;
03229 case GENCMD_FORCE_HEALOTHER:
03230 ForceTeamHeal(ent);
03231 break;
03232 case GENCMD_FORCE_FORCEPOWEROTHER:
03233 ForceTeamForceReplenish(ent);
03234 break;
03235 case GENCMD_FORCE_SEEING:
03236 ForceSeeing(ent);
03237 break;
03238 case GENCMD_USE_SEEKER:
03239 if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_SEEKER)) &&
03240 G_ItemUsable(&ent->client->ps, HI_SEEKER) )
03241 {
03242 ItemUse_Seeker(ent);
03243 G_AddEvent(ent, EV_USE_ITEM0+HI_SEEKER, 0);
03244 ent->client->ps.stats[STAT_HOLDABLE_ITEMS] &= ~(1 << HI_SEEKER);
03245 }
03246 break;
03247 case GENCMD_USE_FIELD:
03248 if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_SHIELD)) &&
03249 G_ItemUsable(&ent->client->ps, HI_SHIELD) )
03250 {
03251 ItemUse_Shield(ent);
03252 G_AddEvent(ent, EV_USE_ITEM0+HI_SHIELD, 0);
03253 ent->client->ps.stats[STAT_HOLDABLE_ITEMS] &= ~(1 << HI_SHIELD);
03254 }
03255 break;
03256 case GENCMD_USE_BACTA:
03257 if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_MEDPAC)) &&
03258 G_ItemUsable(&ent->client->ps, HI_MEDPAC) )
03259 {
03260 ItemUse_MedPack(ent);
03261 G_AddEvent(ent, EV_USE_ITEM0+HI_MEDPAC, 0);
03262 ent->client->ps.stats[STAT_HOLDABLE_ITEMS] &= ~(1 << HI_MEDPAC);
03263 }
03264 break;
03265 case GENCMD_USE_BACTABIG:
03266 if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_MEDPAC_BIG)) &&
03267 G_ItemUsable(&ent->client->ps, HI_MEDPAC_BIG) )
03268 {
03269 ItemUse_MedPack_Big(ent);
03270 G_AddEvent(ent, EV_USE_ITEM0+HI_MEDPAC_BIG, 0);
03271 ent->client->ps.stats[STAT_HOLDABLE_ITEMS] &= ~(1 << HI_MEDPAC_BIG);
03272 }
03273 break;
03274 case GENCMD_USE_ELECTROBINOCULARS:
03275 if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_BINOCULARS)) &&
03276 G_ItemUsable(&ent->client->ps, HI_BINOCULARS) )
03277 {
03278 ItemUse_Binoculars(ent);
03279 if (ent->client->ps.zoomMode == 0)
03280 {
03281 G_AddEvent(ent, EV_USE_ITEM0+HI_BINOCULARS, 1);
03282 }
03283 else
03284 {
03285 G_AddEvent(ent, EV_USE_ITEM0+HI_BINOCULARS, 2);
03286 }
03287 }
03288 break;
03289 case GENCMD_ZOOM:
03290 if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_BINOCULARS)) &&
03291 G_ItemUsable(&ent->client->ps, HI_BINOCULARS) )
03292 {
03293 ItemUse_Binoculars(ent);
03294 if (ent->client->ps.zoomMode == 0)
03295 {
03296 G_AddEvent(ent, EV_USE_ITEM0+HI_BINOCULARS, 1);
03297 }
03298 else
03299 {
03300 G_AddEvent(ent, EV_USE_ITEM0+HI_BINOCULARS, 2);
03301 }
03302 }
03303 break;
03304 case GENCMD_USE_SENTRY:
03305 if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_SENTRY_GUN)) &&
03306 G_ItemUsable(&ent->client->ps, HI_SENTRY_GUN) )
03307 {
03308 ItemUse_Sentry(ent);
03309 G_AddEvent(ent, EV_USE_ITEM0+HI_SENTRY_GUN, 0);
03310 ent->client->ps.stats[STAT_HOLDABLE_ITEMS] &= ~(1 << HI_SENTRY_GUN);
03311 }
03312 break;
03313 case GENCMD_USE_JETPACK:
03314 if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_JETPACK)) &&
03315 G_ItemUsable(&ent->client->ps, HI_JETPACK) )
03316 {
03317 ItemUse_Jetpack(ent);
03318 G_AddEvent(ent, EV_USE_ITEM0+HI_JETPACK, 0);
03319
03320
03321
03322
03323
03324
03325
03326
03327
03328
03329 }
03330 break;
03331 case GENCMD_USE_HEALTHDISP:
03332 if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_HEALTHDISP)) &&
03333 G_ItemUsable(&ent->client->ps, HI_HEALTHDISP) )
03334 {
03335
03336 G_AddEvent(ent, EV_USE_ITEM0+HI_HEALTHDISP, 0);
03337 }
03338 break;
03339 case GENCMD_USE_AMMODISP:
03340 if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_AMMODISP)) &&
03341 G_ItemUsable(&ent->client->ps, HI_AMMODISP) )
03342 {
03343
03344 G_AddEvent(ent, EV_USE_ITEM0+HI_AMMODISP, 0);
03345 }
03346 break;
03347 case GENCMD_USE_EWEB:
03348 if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_EWEB)) &&
03349 G_ItemUsable(&ent->client->ps, HI_EWEB) )
03350 {
03351 ItemUse_UseEWeb(ent);
03352 G_AddEvent(ent, EV_USE_ITEM0+HI_EWEB, 0);
03353 }
03354 break;
03355 case GENCMD_USE_CLOAK:
03356 if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_CLOAK)) &&
03357 G_ItemUsable(&ent->client->ps, HI_CLOAK) )
03358 {
03359 if ( ent->client->ps.powerups[PW_CLOAKED] )
03360 {
03361 Jedi_Decloak( ent );
03362 }
03363 else
03364 {
03365 Jedi_Cloak( ent );
03366 }
03367 }
03368 break;
03369 case GENCMD_SABERATTACKCYCLE:
03370 Cmd_SaberAttackCycle_f(ent);
03371 break;
03372 case GENCMD_TAUNT:
03373 G_SetTauntAnim( ent, TAUNT_TAUNT );
03374 break;
03375 case GENCMD_BOW:
03376 G_SetTauntAnim( ent, TAUNT_BOW );
03377 break;
03378 case GENCMD_MEDITATE:
03379 G_SetTauntAnim( ent, TAUNT_MEDITATE );
03380 break;
03381 case GENCMD_FLOURISH:
03382 G_SetTauntAnim( ent, TAUNT_FLOURISH );
03383 break;
03384 case GENCMD_GLOAT:
03385 G_SetTauntAnim( ent, TAUNT_GLOAT );
03386 break;
03387 default:
03388 break;
03389 }
03390 }
03391
03392
03393 if ( ent->client->ps.eventSequence != oldEventSequence ) {
03394 ent->eventTime = level.time;
03395 }
03396 if (g_smoothClients.integer) {
03397 BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qfalse );
03398
03399 }
03400 else {
03401 BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qfalse );
03402 }
03403
03404 if (isNPC)
03405 {
03406 ent->s.eType = ET_NPC;
03407 }
03408
03409 SendPendingPredictableEvents( &ent->client->ps );
03410
03411 if ( !( ent->client->ps.eFlags & EF_FIRING ) ) {
03412 client->fireHeld = qfalse;
03413 }
03414
03415
03416 VectorCopy( ent->s.pos.trBase, ent->r.currentOrigin );
03417
03418 if (ent->s.eType != ET_NPC ||
03419 ent->s.NPC_class != CLASS_VEHICLE ||
03420 !ent->m_pVehicle ||
03421 !ent->m_pVehicle->m_iRemovedSurfaces)
03422 {
03423 VectorCopy (pm.mins, ent->r.mins);
03424 VectorCopy (pm.maxs, ent->r.maxs);
03425 }
03426
03427 ent->waterlevel = pm.waterlevel;
03428 ent->watertype = pm.watertype;
03429
03430
03431 ClientEvents( ent, oldEventSequence );
03432
03433 if ( pm.useEvent )
03434 {
03435
03436
03437 }
03438 if ((ent->client->pers.cmd.buttons & BUTTON_USE) && ent->client->ps.useDelay < level.time)
03439 {
03440 TryUse(ent);
03441 ent->client->ps.useDelay = level.time + 100;
03442 }
03443
03444
03445 trap_LinkEntity (ent);
03446 if ( !ent->client->noclip ) {
03447 G_TouchTriggers( ent );
03448 }
03449
03450
03451 VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );
03452
03453
03454
03455
03456
03457 ClientImpacts( ent, &pm );
03458
03459
03460 if (ent->client->ps.eventSequence != oldEventSequence) {
03461 ent->eventTime = level.time;
03462 }
03463
03464
03465 client->oldbuttons = client->buttons;
03466 client->buttons = ucmd->buttons;
03467 client->latched_buttons |= client->buttons & ~client->oldbuttons;
03468
03469
03470
03471
03472 if (client->ps.forceKickFlip)
03473 {
03474 gentity_t *faceKicked = &g_entities[client->ps.forceKickFlip-1];
03475
03476 if (faceKicked && faceKicked->client && (!OnSameTeam(ent, faceKicked) || g_friendlyFire.integer) &&
03477 (!faceKicked->client->ps.duelInProgress || faceKicked->client->ps.duelIndex == ent->s.number) &&
03478 (!ent->client->ps.duelInProgress || ent->client->ps.duelIndex == faceKicked->s.number))
03479 {
03480 if ( faceKicked && faceKicked->client && faceKicked->health && faceKicked->takedamage )
03481 {
03482 vec3_t oppDir;
03483 int strength = (int)VectorNormalize2( client->ps.velocity, oppDir );
03484
03485 strength *= 0.05;
03486
03487 VectorScale( oppDir, -1, oppDir );
03488
03489 G_Damage( faceKicked, ent, ent, oppDir, client->ps.origin, strength, DAMAGE_NO_ARMOR, MOD_MELEE );
03490
03491 if ( faceKicked->client->ps.weapon != WP_SABER ||
03492 faceKicked->client->ps.fd.saberAnimLevel != FORCE_LEVEL_3 ||
03493 (!BG_SaberInAttack(faceKicked->client->ps.saberMove) && !PM_SaberInStart(faceKicked->client->ps.saberMove) && !PM_SaberInReturn(faceKicked->client->ps.saberMove) && !PM_SaberInTransition(faceKicked->client->ps.saberMove)) )
03494 {
03495 if (faceKicked->health > 0 &&
03496 faceKicked->client->ps.stats[STAT_HEALTH] > 0 &&
03497 faceKicked->client->ps.forceHandExtend != HANDEXTEND_KNOCKDOWN)
03498 {
03499 if (BG_KnockDownable(&faceKicked->client->ps) && Q_irand(1, 10) <= 3)
03500 {
03501 faceKicked->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN;
03502 faceKicked->client->ps.forceHandExtendTime = level.time + 1100;
03503 faceKicked->client->ps.forceDodgeAnim = 0;
03504 }
03505
03506 faceKicked->client->ps.otherKiller = ent->s.number;
03507 faceKicked->client->ps.otherKillerTime = level.time + 5000;
03508 faceKicked->client->ps.otherKillerDebounceTime = level.time + 100;
03509
03510 faceKicked->client->ps.velocity[0] = oppDir[0]*(strength*40);
03511 faceKicked->client->ps.velocity[1] = oppDir[1]*(strength*40);
03512 faceKicked->client->ps.velocity[2] = 200;
03513 }
03514 }
03515
03516 G_Sound( faceKicked, CHAN_AUTO, G_SoundIndex( va("sound/weapons/melee/punch%d", Q_irand(1, 4)) ) );
03517 }
03518 }
03519
03520 client->ps.forceKickFlip = 0;
03521 }
03522
03523
03524 if ( client->ps.stats[STAT_HEALTH] <= 0
03525 && !(client->ps.eFlags2&EF2_HELD_BY_MONSTER)
03526 && ent->s.eType != ET_NPC ) {
03527
03528 if ( level.time > client->respawnTime && !gDoSlowMoDuel ) {
03529
03530 int forceRes = g_forcerespawn.integer;
03531
03532 if (g_gametype.integer == GT_POWERDUEL)
03533 {
03534 forceRes = 1;
03535 }
03536 else if (g_gametype.integer == GT_SIEGE &&
03537 g_siegeRespawn.integer)
03538 {
03539 forceRes = 1;
03540 }
03541
03542 if ( forceRes > 0 &&
03543 ( level.time - client->respawnTime ) > forceRes * 1000 ) {
03544 respawn( ent );
03545 return;
03546 }
03547
03548
03549 if ( ucmd->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) ) {
03550 respawn( ent );
03551 }
03552 }
03553 else if (gDoSlowMoDuel)
03554 {
03555 client->respawnTime = level.time + 1000;
03556 }
03557 return;
03558 }
03559
03560
03561 ClientTimerActions( ent, msec );
03562
03563 G_UpdateClientBroadcasts ( ent );
03564
03565
03566 G_CheckClientIdle( ent, ucmd );
03567
03568
03569
03570 if ( ent->s.number < MAX_CLIENTS && ent->client->ps.m_iVehicleNum )
03571 {
03572
03573 if (g_entities[ent->client->ps.m_iVehicleNum].inuse && g_entities[ent->client->ps.m_iVehicleNum].client)
03574 {
03575 ClientThink(ent->client->ps.m_iVehicleNum, &g_entities[ent->client->ps.m_iVehicleNum].m_pVehicle->m_ucmd);
03576 }
03577 else
03578 {
03579 ent->client->ps.m_iVehicleNum = 0;
03580 }
03581 }
03582
03583 }
03584
03585
03586
03587
03588
03589
03590
03591
03592 void G_CheckClientTimeouts ( gentity_t *ent )
03593 {
03594
03595 if ( !g_timeouttospec.integer )
03596 {
03597 return;
03598 }
03599
03600
03601 if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR )
03602 {
03603 return;
03604 }
03605
03606
03607
03608 if ( level.time - ent->client->pers.cmd.serverTime > g_timeouttospec.integer * 1000 )
03609 {
03610 SetTeam ( ent, "spectator" );
03611 }
03612 }
03613
03614
03615
03616
03617
03618
03619
03620
03621 void ClientThink( int clientNum,usercmd_t *ucmd ) {
03622 gentity_t *ent;
03623
03624 ent = g_entities + clientNum;
03625 if (clientNum < MAX_CLIENTS)
03626 {
03627 trap_GetUsercmd( clientNum, &ent->client->pers.cmd );
03628 }
03629
03630
03631
03632 ent->client->lastCmdTime = level.time;
03633
03634 if (ucmd)
03635 {
03636 ent->client->pers.cmd = *ucmd;
03637 }
03638
03639
03640
03641
03642
03643
03644
03645
03646
03647
03648
03649
03650
03651
03652
03653
03654
03655
03656
03657
03658
03659
03660
03661
03662
03663
03664
03665 if ( !(ent->r.svFlags & SVF_BOT) && !g_synchronousClients.integer ) {
03666 ClientThink_real( ent );
03667 }
03668
03669
03670 else if ( clientNum >= MAX_CLIENTS ) {
03671 ClientThink_real( ent );
03672 }
03673
03674
03675
03676
03677
03678
03679
03680
03681
03682
03683
03684
03685
03686
03687
03688
03689
03690
03691
03692 }
03693
03694
03695 void G_RunClient( gentity_t *ent ) {
03696 if ( !(ent->r.svFlags & SVF_BOT) && !g_synchronousClients.integer ) {
03697 return;
03698 }
03699 ent->client->pers.cmd.serverTime = level.time;
03700 ClientThink_real( ent );
03701 }
03702
03703
03704
03705
03706
03707
03708
03709
03710 void SpectatorClientEndFrame( gentity_t *ent ) {
03711 gclient_t *cl;
03712
03713 if (ent->s.eType == ET_NPC)
03714 {
03715 assert(0);
03716 return;
03717 }
03718
03719
03720 if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) {
03721 int clientNum;
03722
03723 clientNum = ent->client->sess.spectatorClient;
03724
03725
03726 if ( clientNum == -1 ) {
03727 clientNum = level.follow1;
03728 } else if ( clientNum == -2 ) {
03729 clientNum = level.follow2;
03730 }
03731 if ( clientNum >= 0 ) {
03732 cl = &level.clients[ clientNum ];
03733 if ( cl->pers.connected == CON_CONNECTED && cl->sess.sessionTeam != TEAM_SPECTATOR ) {
03734
03735
03736 ent->client->ps.eFlags = cl->ps.eFlags;
03737 ent->client->ps = cl->ps;
03738 ent->client->ps.pm_flags |= PMF_FOLLOW;
03739 return;
03740 } else {
03741
03742 if ( ent->client->sess.spectatorClient >= 0 ) {
03743 ent->client->sess.spectatorState = SPECTATOR_FREE;
03744 ClientBegin( ent->client - level.clients, qtrue );
03745 }
03746 }
03747 }
03748 }
03749
03750 if ( ent->client->sess.spectatorState == SPECTATOR_SCOREBOARD ) {
03751 ent->client->ps.pm_flags |= PMF_SCOREBOARD;
03752 } else {
03753 ent->client->ps.pm_flags &= ~PMF_SCOREBOARD;
03754 }
03755 }
03756
03757
03758
03759
03760
03761
03762
03763
03764
03765
03766 void ClientEndFrame( gentity_t *ent ) {
03767 int i;
03768 clientPersistant_t *pers;
03769 qboolean isNPC = qfalse;
03770
03771 if (ent->s.eType == ET_NPC)
03772 {
03773 isNPC = qtrue;
03774 }
03775
03776 if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
03777 SpectatorClientEndFrame( ent );
03778 return;
03779 }
03780
03781 pers = &ent->client->pers;
03782
03783
03784 for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
03785 if ( ent->client->ps.powerups[ i ] < level.time ) {
03786 ent->client->ps.powerups[ i ] = 0;
03787 }
03788 }
03789
03790
03791 #if 0
03792 if ( !g_synchronousClients->integer && (ent->client->ps.pm_type == PM_NORMAL || ent->client->ps.pm_type == PM_JETPACK || ent->client->ps.pm_type == PM_FLOAT) ) {
03793
03794 VectorClear( ent->client->ps.viewangles );
03795 }
03796 #endif
03797
03798
03799
03800
03801
03802 if ( level.intermissiontime ) {
03803 if ( ent->s.number < MAX_CLIENTS
03804 || ent->client->NPC_class == CLASS_VEHICLE )
03805 {
03806 return;
03807 }
03808 }
03809
03810
03811 P_WorldEffects (ent);
03812
03813
03814 P_DamageFeedback (ent);
03815
03816
03817 if ( level.time - ent->client->lastCmdTime > 1000 ) {
03818 ent->s.eFlags |= EF_CONNECTION;
03819 } else {
03820 ent->s.eFlags &= ~EF_CONNECTION;
03821 }
03822
03823 ent->client->ps.stats[STAT_HEALTH] = ent->health;
03824
03825 G_SetClientSound (ent);
03826
03827
03828 if (g_smoothClients.integer) {
03829 BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qfalse );
03830
03831 }
03832 else {
03833 BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qfalse );
03834 }
03835
03836 if (isNPC)
03837 {
03838 ent->s.eType = ET_NPC;
03839 }
03840
03841 SendPendingPredictableEvents( &ent->client->ps );
03842
03843
03844
03845
03846 }
03847
03848