summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/game/g_active.c303
-rw-r--r--src/game/g_buildable.c2
-rw-r--r--src/game/g_client.c1
-rw-r--r--src/game/g_combat.c10
-rw-r--r--src/game/g_local.h24
-rw-r--r--src/game/g_main.c29
-rw-r--r--src/game/g_misc.c1
-rw-r--r--src/game/g_weapon.c34
8 files changed, 391 insertions, 13 deletions
diff --git a/src/game/g_active.c b/src/game/g_active.c
index a08d9e48..f4bad98c 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -267,6 +267,13 @@ void ClientImpacts( gentity_t *ent, pmove_t *pm )
other = &g_entities[ pm->touchents[ i ] ];
+ // see G_UnlaggedDetectCollisions(), this is the inverse of that.
+ // if our movement is blocked by another player's real position,
+ // don't use the unlagged position for them because they are
+ // blocking or server-side Pmove() from reaching it
+ if( other->client && other->client->unlaggedCalc.used )
+ other->client->unlaggedCalc.used = qfalse;
+
//charge attack
if( ent->client->ps.weapon == WP_ALEVEL4 &&
ent->client->ps.stats[ STAT_MISC ] > 0 &&
@@ -954,6 +961,288 @@ void SendPendingPredictableEvents( playerState_t *ps )
/*
==============
+ G_UnlaggedStore
+
+ Called on every server frame. Stores position data for the client at that
+ into client->unlaggedHist[] and the time into level.unlaggedTimes[].
+ This data is used by G_UnlaggedCalc()
+==============
+*/
+void G_UnlaggedStore( void )
+{
+ int i = 0;
+ gentity_t *ent;
+ unlagged_t *save;
+
+ if( !g_unlagged.integer )
+ return;
+ level.unlaggedIndex++;
+ if( level.unlaggedIndex >= MAX_UNLAGGED_MARKERS )
+ level.unlaggedIndex = 0;
+
+ level.unlaggedTimes[ level.unlaggedIndex ] = level.time;
+
+ for( i = 0; i < level.maxclients; i++ )
+ {
+ ent = &g_entities[ i ];
+ save = &ent->client->unlaggedHist[ level.unlaggedIndex ];
+ save->used = qfalse;
+ if( !ent->r.linked || !( ent->r.contents & CONTENTS_BODY ) )
+ continue;
+ if( ent->client->pers.connected != CON_CONNECTED )
+ continue;
+ VectorCopy( ent->r.mins, save->mins );
+ VectorCopy( ent->r.maxs, save->maxs );
+ VectorCopy( ent->s.pos.trBase, save->origin );
+ save->used = qtrue;
+ }
+}
+
+/*
+==============
+ G_UnlaggedClear
+
+ Mark all unlaggedHist[] markers for this client invalid. Useful for
+ preventing teleporting and death.
+==============
+*/
+void G_UnlaggedClear( gentity_t *ent )
+{
+ int i;
+
+ for( i = 0; i < MAX_UNLAGGED_MARKERS; i++ )
+ ent->client->unlaggedHist[ i ].used = qfalse;
+}
+
+/*
+==============
+ G_UnlaggedCalc
+
+ Loops through all active clients and calculates their predicted position
+ for time then stores it in client->unlaggedCalc
+==============
+*/
+void G_UnlaggedCalc( int time, gentity_t *rewindEnt )
+{
+ int i = 0;
+ gentity_t *ent;
+ int startIndex = level.unlaggedIndex;
+ int stopIndex = -1;
+ int frameMsec = 0;
+ float lerp = 0.5f;
+
+ if( !g_unlagged.integer )
+ return;
+
+ // clear any calculated values from a previous run
+ for( i = 0; i < level.maxclients; i++ )
+ {
+ ent = &g_entities[ i ];
+ ent->client->unlaggedCalc.used = qfalse;
+ }
+
+ for( i = 0; i < MAX_UNLAGGED_MARKERS; i++ )
+ {
+ if( level.unlaggedTimes[ startIndex ] <= time )
+ break;
+ stopIndex = startIndex;
+ if( --startIndex < 0 )
+ startIndex = MAX_UNLAGGED_MARKERS - 1;
+ }
+ if( i == MAX_UNLAGGED_MARKERS )
+ {
+ // if we searched all markers and the oldest one still isn't old enough
+ // just use the oldest marker with no lerping
+ lerp = 0.0f;
+ }
+
+ // client is on the current frame, no need for unlagged
+ if( stopIndex == -1 )
+ return;
+
+ // lerp between two markers
+ frameMsec = level.unlaggedTimes[ stopIndex ] -
+ level.unlaggedTimes[ startIndex ];
+ if( frameMsec > 0 )
+ {
+ lerp = ( float )( time - level.unlaggedTimes[ startIndex ] )
+ / ( float )frameMsec;
+ }
+
+ for( i = 0; i < level.maxclients; i++ )
+ {
+ ent = &g_entities[ i ];
+ if( ent->s.number == rewindEnt->s.number )
+ continue;
+ if( !ent->r.linked || !( ent->r.contents & CONTENTS_BODY ) )
+ continue;
+ if( ent->client->pers.connected != CON_CONNECTED )
+ continue;
+ if( !ent->client->unlaggedHist[ startIndex ].used )
+ continue;
+ if( !ent->client->unlaggedHist[ stopIndex ].used )
+ continue;
+
+ // between two unlagged markers
+ VectorLerp( lerp, ent->client->unlaggedHist[ startIndex ].mins,
+ ent->client->unlaggedHist[ stopIndex ].mins,
+ ent->client->unlaggedCalc.mins );
+ VectorLerp( lerp, ent->client->unlaggedHist[ startIndex ].maxs,
+ ent->client->unlaggedHist[ stopIndex ].maxs,
+ ent->client->unlaggedCalc.maxs );
+ VectorLerp( lerp, ent->client->unlaggedHist[ startIndex ].origin,
+ ent->client->unlaggedHist[ stopIndex ].origin,
+ ent->client->unlaggedCalc.origin );
+
+ ent->client->unlaggedCalc.used = qtrue;
+ }
+}
+
+/*
+==============
+ G_UnlaggedOff
+
+ Reverses the changes made to all active clients by G_UnlaggedOn()
+==============
+*/
+void G_UnlaggedOff( void )
+{
+ int i = 0;
+ gentity_t *ent;
+
+ if( !g_unlagged.integer )
+ return;
+
+ for( i = 0; i < level.maxclients; i++ )
+ {
+ ent = &g_entities[ i ];
+ if( !ent->client->unlaggedBackup.used )
+ continue;
+ VectorCopy( ent->client->unlaggedBackup.mins, ent->r.mins );
+ VectorCopy( ent->client->unlaggedBackup.maxs, ent->r.maxs );
+ VectorCopy( ent->client->unlaggedBackup.origin, ent->r.currentOrigin );
+ ent->client->unlaggedBackup.used = qfalse;
+ trap_LinkEntity( ent );
+ }
+}
+
+/*
+==============
+ G_UnlaggedOn
+
+ Called after G_UnlaggedCalc() to apply the calculated values to all active
+ clients. Once finished tracing, G_UnlaggedOff() must be called to restore
+ the clients' position data
+
+ As an optimization, all clients that have an unlagged position that is
+ not touchable at "range" from "muzzle" will be ignored. This is required
+ to prevent a huge amount of trap_LinkEntity() calls per user cmd.
+==============
+*/
+
+void G_UnlaggedOn( vec3_t muzzle, float range )
+{
+ int i = 0;
+ gentity_t *ent;
+ unlagged_t *calc;
+
+ if( !g_unlagged.integer )
+ return;
+
+ for( i = 0; i < level.maxclients; i++ )
+ {
+ ent = &g_entities[ i ];
+ calc = &ent->client->unlaggedCalc;
+
+ if( !calc->used )
+ continue;
+ if( ent->client->unlaggedBackup.used )
+ continue;
+ if( !ent->r.linked || !( ent->r.contents & CONTENTS_BODY ) )
+ continue;
+ if( VectorCompare( ent->r.currentOrigin, calc->origin ) )
+ continue;
+ if( muzzle )
+ {
+ float r1 = Distance( calc->origin, calc->maxs );
+ float r2 = Distance( calc->origin, calc->mins );
+ float maxRadius = ( r1 > r2 ) ? r1 : r2;
+
+ if( Distance( muzzle, calc->origin ) > range + maxRadius )
+ continue;
+ }
+
+ // create a backup of the real positions
+ VectorCopy( ent->r.mins, ent->client->unlaggedBackup.mins );
+ VectorCopy( ent->r.maxs, ent->client->unlaggedBackup.maxs );
+ VectorCopy( ent->r.currentOrigin, ent->client->unlaggedBackup.origin );
+ ent->client->unlaggedBackup.used = qtrue;
+
+ // move the client to the calculated unlagged position
+ VectorCopy( calc->mins, ent->r.mins );
+ VectorCopy( calc->maxs, ent->r.maxs );
+ VectorCopy( calc->origin, ent->r.currentOrigin );
+ trap_LinkEntity( ent );
+ }
+}
+/*
+==============
+ G_UnlaggedDetectCollisions
+
+ cgame prediction will predict a client's own position all the way up to
+ the current time, but only updates other player's positions up to the
+ postition sent in the most recent snapshot.
+
+ This allows player X to essentially "move through" the position of player Y
+ when player X's cmd is processed with Pmove() on the server. This is because
+ player Y was clipping player X's Pmove() on his client, but when the same
+ cmd is processed with Pmove on the server it is not clipped.
+
+ Long story short (too late): don't use unlagged positions for players who
+ were blocking this player X's client-side Pmove(). This makes the assumption
+ that if player X's movement was blocked in the client he's going to still
+ be up against player Y when the Pmove() is run on the server with the
+ same cmd.
+
+ NOTE: this must be called after Pmove() and G_UnlaggedCalc()
+==============
+*/
+static void G_UnlaggedDetectCollisions( gentity_t *ent )
+{
+ unlagged_t *calc;
+ trace_t tr;
+ float r1, r2;
+ float range;
+
+ if( !g_unlagged.integer )
+ return;
+
+ calc = &ent->client->unlaggedCalc;
+
+ // if the client isn't moving, this is not necessary
+ if( VectorCompare( ent->client->oldOrigin, ent->client->ps.origin ) )
+ return;
+
+ range = Distance( ent->client->oldOrigin, ent->client->ps.origin );
+
+ // increase the range by the player's largest possible radius since it's
+ // the players bounding box that collides, not their origin
+ r1 = Distance( calc->origin, calc->mins );
+ r2 = Distance( calc->origin, calc->maxs );
+ range += ( r1 > r2 ) ? r1 : r2;
+
+ G_UnlaggedOn( ent->client->oldOrigin, range );
+
+ trap_Trace(&tr, ent->client->oldOrigin, ent->r.mins, ent->r.maxs,
+ ent->client->ps.origin, ent->s.number, MASK_PLAYERSOLID );
+ if( tr.entityNum >= 0 && tr.entityNum < MAX_CLIENTS )
+ g_entities[ tr.entityNum ].client->unlaggedCalc.used = qfalse;
+
+ G_UnlaggedOff( );
+}
+
+/*
+==============
ClientThink
This will be called once for each client frame, which will
@@ -1002,6 +1291,8 @@ void ClientThink_real( gentity_t *ent )
if( msec > 200 )
msec = 200;
+ client->unlaggedTime = ucmd->serverTime;
+
if( pmove_msec.integer < 8 )
trap_Cvar_Set( "pmove_msec", "8" );
else if( pmove_msec.integer > 33 )
@@ -1039,6 +1330,9 @@ void ClientThink_real( gentity_t *ent )
if( !ClientInactivityTimer( client ) )
return;
+ // calculate where ent is currently seeing all the other active clients
+ G_UnlaggedCalc( ent->client->unlaggedTime, ent );
+
if( client->noclip )
client->ps.pm_type = PM_NOCLIP;
else if( client->ps.stats[ STAT_HEALTH ] <= 0 )
@@ -1214,6 +1508,8 @@ void ClientThink_real( gentity_t *ent )
Pmove( &pm );
+ G_UnlaggedDetectCollisions( ent );
+
// save results of pmove
if( ent->client->ps.eventSequence != oldEventSequence )
ent->eventTime = level.time;
@@ -1239,6 +1535,9 @@ void ClientThink_real( gentity_t *ent )
ent->waterlevel = pm.waterlevel;
ent->watertype = pm.watertype;
+ // touch other objects
+ ClientImpacts( ent, &pm );
+
// execute client events
ClientEvents( ent, oldEventSequence );
@@ -1249,9 +1548,6 @@ void ClientThink_real( gentity_t *ent )
VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );
VectorCopy( ent->client->ps.origin, ent->s.origin );
- // touch other objects
- ClientImpacts( ent, &pm );
-
// save results of triggers and client events
if( ent->client->ps.eventSequence != oldEventSequence )
ent->eventTime = level.time;
@@ -1278,6 +1574,7 @@ void ClientThink_real( gentity_t *ent )
//prevent lerping
client->ps.eFlags ^= EF_TELEPORT_BIT;
client->ps.eFlags &= ~EF_NODRAW;
+ G_UnlaggedClear( ent );
//client leaves hovel
client->ps.stats[ STAT_STATE ] &= ~SS_HOVELING;
diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c
index 87f8574a..b7abfbe6 100644
--- a/src/game/g_buildable.c
+++ b/src/game/g_buildable.c
@@ -1190,6 +1190,7 @@ void AHovel_Use( gentity_t *self, gentity_t *other, gentity_t *activator )
//prevent lerping
activator->client->ps.eFlags ^= EF_TELEPORT_BIT;
activator->client->ps.eFlags |= EF_NODRAW;
+ G_UnlaggedClear( activator );
activator->client->ps.stats[ STAT_STATE ] |= SS_HOVELING;
activator->client->hovel = self;
@@ -1276,6 +1277,7 @@ void AHovel_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
//prevent lerping
builder->client->ps.eFlags ^= EF_TELEPORT_BIT;
builder->client->ps.eFlags &= ~EF_NODRAW;
+ G_UnlaggedClear( builder );
G_SetOrigin( builder, newOrigin );
VectorCopy( newOrigin, builder->client->ps.origin );
diff --git a/src/game/g_client.c b/src/game/g_client.c
index 7141f222..aa39c90c 100644
--- a/src/game/g_client.c
+++ b/src/game/g_client.c
@@ -1412,6 +1412,7 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
// toggle the teleport bit so the client knows to not lerp
flags = ent->client->ps.eFlags & ( EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED );
flags ^= EF_TELEPORT_BIT;
+ G_UnlaggedClear( ent );
// clear everything but the persistant data
diff --git a/src/game/g_combat.c b/src/game/g_combat.c
index 95d88412..7fc5a02a 100644
--- a/src/game/g_combat.c
+++ b/src/game/g_combat.c
@@ -684,6 +684,7 @@ G_CalcDamageModifier
*/
static float G_CalcDamageModifier( vec3_t point, gentity_t *targ, gentity_t *attacker, int class, int dflags )
{
+ vec3_t targOrigin;
vec3_t bulletPath;
vec3_t bulletAngle;
vec3_t pMINUSfloor, floor, normal;
@@ -696,6 +697,11 @@ static float G_CalcDamageModifier( vec3_t point, gentity_t *targ, gentity_t *att
if( point == NULL )
return 1.0f;
+ if( g_unlagged.integer && targ->client && targ->client->unlaggedCalc.used )
+ VectorCopy( targ->client->unlaggedCalc.origin, targOrigin );
+ else
+ VectorCopy( targ->r.currentOrigin, targOrigin );
+
clientHeight = targ->r.maxs[ 2 ] - targ->r.mins[ 2 ];
if( targ->client->ps.stats[ STAT_STATE ] & SS_WALLCLIMBING )
@@ -703,7 +709,7 @@ static float G_CalcDamageModifier( vec3_t point, gentity_t *targ, gentity_t *att
else
VectorSet( normal, 0, 0, 1 );
- VectorMA( targ->r.currentOrigin, targ->r.mins[ 2 ], normal, floor );
+ VectorMA( targOrigin, targ->r.mins[ 2 ], normal, floor );
VectorSubtract( point, floor, pMINUSfloor );
hitRelative = DotProduct( normal, pMINUSfloor ) / VectorLength( normal );
@@ -716,7 +722,7 @@ static float G_CalcDamageModifier( vec3_t point, gentity_t *targ, gentity_t *att
hitRatio = hitRelative / clientHeight;
- VectorSubtract( targ->r.currentOrigin, point, bulletPath );
+ VectorSubtract( targOrigin, point, bulletPath );
vectoangles( bulletPath, bulletAngle );
clientRotation = targ->client->ps.viewangles[ YAW ];
diff --git a/src/game/g_local.h b/src/game/g_local.h
index a4fe225b..6cf5db75 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -351,6 +351,14 @@ typedef struct
int adminLevel;
} clientPersistant_t;
+#define MAX_UNLAGGED_MARKERS 10
+typedef struct unlagged_s {
+ vec3_t origin;
+ vec3_t mins;
+ vec3_t maxs;
+ qboolean used;
+} unlagged_t;
+
// this structure is cleared on each ClientSpawn(),
// except for 'client->pers' and 'client->sess'
struct gclient_s
@@ -442,6 +450,12 @@ struct gclient_s
#define RAM_FRAMES 1 // number of frames to wait before retriggering
int retriggerArmouryMenu; // frame number to retrigger the armoury menu
+
+ unlagged_t unlaggedHist[ MAX_UNLAGGED_MARKERS ];
+ unlagged_t unlaggedBackup;
+ unlagged_t unlaggedCalc;
+ int unlaggedTime;
+
};
@@ -628,6 +642,9 @@ typedef struct
qboolean uncondHumanWin;
qboolean alienTeamLocked;
qboolean humanTeamLocked;
+
+ int unlaggedIndex;
+ int unlaggedTimes[ MAX_UNLAGGED_MARKERS ];
} level_locals_t;
//
@@ -914,6 +931,11 @@ void ClientCommand( int clientNum );
//
// g_active.c
//
+void G_UnlaggedStore( void );
+void G_UnlaggedClear( gentity_t *ent );
+void G_UnlaggedCalc( int time, gentity_t *skipEnt );
+void G_UnlaggedOn( vec3_t muzzle, float range );
+void G_UnlaggedOff( void );
void ClientThink( int clientNum );
void ClientEndFrame( gentity_t *ent );
void G_RunClient( gentity_t *ent );
@@ -1100,6 +1122,8 @@ extern vmCvar_t g_alienMaxStage;
extern vmCvar_t g_alienStage2Threshold;
extern vmCvar_t g_alienStage3Threshold;
+extern vmCvar_t g_unlagged;
+
extern vmCvar_t g_disabledEquipment;
extern vmCvar_t g_disabledClasses;
extern vmCvar_t g_disabledBuildables;
diff --git a/src/game/g_main.c b/src/game/g_main.c
index c2a4d66a..ab10f15b 100644
--- a/src/game/g_main.c
+++ b/src/game/g_main.c
@@ -103,6 +103,8 @@ vmCvar_t g_alienMaxStage;
vmCvar_t g_alienStage2Threshold;
vmCvar_t g_alienStage3Threshold;
+vmCvar_t g_unlagged;
+
vmCvar_t g_disabledEquipment;
vmCvar_t g_disabledClasses;
vmCvar_t g_disabledBuildables;
@@ -210,6 +212,8 @@ static cvarTable_t gameCvarTable[ ] =
{ &g_alienMaxStage, "g_alienMaxStage", DEFAULT_ALIEN_MAX_STAGE, 0, 0, qfalse },
{ &g_alienStage2Threshold, "g_alienStage2Threshold", DEFAULT_ALIEN_STAGE2_THRESH, 0, 0, qfalse },
{ &g_alienStage3Threshold, "g_alienStage3Threshold", DEFAULT_ALIEN_STAGE3_THRESH, 0, 0, qfalse },
+
+ { &g_unlagged, "g_unlagged", "1", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qfalse },
{ &g_disabledEquipment, "g_disabledEquipment", "", CVAR_ROM, 0, qfalse },
{ &g_disabledClasses, "g_disabledClasses", "", CVAR_ROM, 0, qfalse },
@@ -2138,12 +2142,6 @@ void G_RunFrame( int levelTime )
if( !ent->r.linked && ent->neverFree )
continue;
- if( ent->s.eType == ET_MISSILE )
- {
- G_RunMissile( ent );
- continue;
- }
-
if( ent->s.eType == ET_BUILDABLE )
{
G_BuildableThink( ent, msec );
@@ -2183,6 +2181,25 @@ void G_RunFrame( int levelTime )
ClientEndFrame( ent );
}
+ // save position information for all active clients
+ G_UnlaggedStore( );
+
+ // for missle impacts, move every active client one server frame time back
+ // to compensate for built-in 50ms lag
+ G_UnlaggedCalc( level.previousTime, NULL );
+ G_UnlaggedOn( NULL, 0.0f );
+ for( i = MAX_CLIENTS; i < level.num_entities ; i++)
+ {
+ ent = &g_entities[ i ];
+ if( !ent->inuse )
+ continue;
+ if( ent->freeAfterEvent )
+ continue;
+ if( ent->s.eType == ET_MISSILE )
+ G_RunMissile( ent );
+ }
+ G_UnlaggedOff( );
+
end = trap_Milliseconds();
//TA:
diff --git a/src/game/g_misc.c b/src/game/g_misc.c
index 23a46a3b..9d54033e 100644
--- a/src/game/g_misc.c
+++ b/src/game/g_misc.c
@@ -86,6 +86,7 @@ void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles )
// toggle the teleport bit so the client knows to not lerp
player->client->ps.eFlags ^= EF_TELEPORT_BIT;
+ G_UnlaggedClear( player );
// set angles
SetClientViewAngle( player, angles );
diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c
index 2afa24b7..4496d18a 100644
--- a/src/game/g_weapon.c
+++ b/src/game/g_weapon.c
@@ -179,7 +179,10 @@ void meleeAttack( gentity_t *ent, float range, float width, int damage, meansOfD
VectorMA( muzzle, range, forward, end );
+ G_UnlaggedOn( muzzle, range );
trap_Trace( &tr, muzzle, mins, maxs, end, ent->s.number, MASK_SHOT );
+ G_UnlaggedOff( );
+
if( tr.surfaceFlags & SURF_NOIMPACT )
return;
@@ -223,7 +226,16 @@ void bulletFire( gentity_t *ent, float spread, int damage, int mod )
VectorMA( end, r, right, end );
VectorMA( end, u, up, end );
- trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT );
+ // don't use unlagged if this is not a client (e.g. turret)
+ if( ent->client )
+ {
+ G_UnlaggedOn( muzzle, 8192 * 16 );
+ trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT );
+ G_UnlaggedOff( );
+ }
+ else
+ trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT );
+
if( tr.surfaceFlags & SURF_NOIMPACT )
return;
@@ -308,8 +320,9 @@ void shotgunFire( gentity_t *ent )
SnapVector( tent->s.origin2 );
tent->s.eventParm = rand() & 255; // seed for spread pattern
tent->s.otherEntityNum = ent->s.number;
-
+ G_UnlaggedOn( muzzle, 8192 * 16 );
ShotgunPattern( tent->s.pos.trBase, tent->s.origin2, tent->s.eventParm, ent );
+ G_UnlaggedOff();
}
/*
@@ -329,7 +342,10 @@ void massDriverFire( gentity_t *ent )
VectorMA( muzzle, 8192 * 16, forward, end );
+ G_UnlaggedOn( muzzle, 8192 * 16 );
trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT );
+ G_UnlaggedOff( );
+
if( tr.surfaceFlags & SURF_NOIMPACT )
return;
@@ -482,7 +498,10 @@ void lasGunFire( gentity_t *ent )
VectorMA( muzzle, 8192 * 16, forward, end );
+ G_UnlaggedOn( muzzle, 8192 * 16 );
trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT );
+ G_UnlaggedOff( );
+
if( tr.surfaceFlags & SURF_NOIMPACT )
return;
@@ -534,7 +553,10 @@ void painSawFire( gentity_t *ent )
VectorMA( muzzle, PAINSAW_RANGE, forward, end );
+ G_UnlaggedOn( muzzle, PAINSAW_RANGE );
trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT );
+ G_UnlaggedOff( );
+
if( tr.surfaceFlags & SURF_NOIMPACT )
return;
@@ -805,7 +827,9 @@ qboolean CheckVenomAttack( gentity_t *ent )
VectorMA( muzzle, LEVEL0_BITE_RANGE, forward, end );
+ G_UnlaggedOn( muzzle, LEVEL0_BITE_RANGE );
trap_Trace( &tr, muzzle, mins, maxs, end, ent->s.number, MASK_SHOT );
+ G_UnlaggedOff( );
if( tr.surfaceFlags & SURF_NOIMPACT )
return qfalse;
@@ -939,6 +963,7 @@ void poisonCloud( gentity_t *ent )
VectorAdd( ent->client->ps.origin, range, maxs );
VectorSubtract( ent->client->ps.origin, range, mins );
+ G_UnlaggedOn( ent->client->ps.origin, LEVEL1_PCLOUD_RANGE );
num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
for( i = 0; i < num; i++ )
{
@@ -967,6 +992,7 @@ void poisonCloud( gentity_t *ent )
}
}
}
+ G_UnlaggedOff( );
}
@@ -1231,7 +1257,9 @@ void areaZapFire( gentity_t *ent )
VectorMA( muzzle, LEVEL2_AREAZAP_RANGE, forward, end );
+ G_UnlaggedOn( muzzle, LEVEL2_AREAZAP_RANGE );
trap_Trace( &tr, muzzle, mins, maxs, end, ent->s.number, MASK_SHOT );
+ G_UnlaggedOff( );
if( tr.surfaceFlags & SURF_NOIMPACT )
return;
@@ -1291,7 +1319,9 @@ qboolean CheckPounceAttack( gentity_t *ent )
VectorMA( muzzle, LEVEL3_POUNCE_RANGE, forward, end );
+ G_UnlaggedOn( muzzle, LEVEL3_POUNCE_RANGE );
trap_Trace( &tr, ent->s.origin, mins, maxs, end, ent->s.number, MASK_SHOT );
+ G_UnlaggedOff( );
//miss
if( tr.fraction >= 1.0 )