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->