summaryrefslogtreecommitdiff
path: root/src/game/g_active.c
diff options
context:
space:
mode:
authorIronClawTrem <louie.nutman@gmail.com>2020-02-16 03:40:06 +0000
committerIronClawTrem <louie.nutman@gmail.com>2020-02-16 03:40:06 +0000
commit425decdf7e9284d15aa726e3ae96b9942fb0e3ea (patch)
tree6c0dd7edfefff1be7b9e75fe0b3a0a85fe1595f3 /src/game/g_active.c
parentccb0b2e4d6674a7a00c9bf491f08fc73b6898c54 (diff)
create tremded branch
Diffstat (limited to 'src/game/g_active.c')
-rw-r--r--src/game/g_active.c1329
1 files changed, 565 insertions, 764 deletions
diff --git a/src/game/g_active.c b/src/game/g_active.c
index b5df273..d978a4a 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
@@ -40,7 +41,7 @@ void P_DamageFeedback( gentity_t *player )
vec3_t angles;
client = player->client;
- if( client->ps.pm_type == PM_DEAD )
+ if( !PM_Alive( client->ps.pm_type ) )
return;
// total points of damage shot at the player this frame
@@ -129,7 +130,7 @@ void P_WorldEffects( gentity_t *ent )
// play a gurp sound instead of a normal pain sound
if( ent->health <= ent->damage )
G_Sound( ent, CHAN_VOICE, G_SoundIndex( "*drown.wav" ) );
- else if( rand( ) & 1 )
+ else if( rand( ) < RAND_MAX / 2 + 1 )
G_Sound( ent, CHAN_VOICE, G_SoundIndex( "sound/player/gurp1.wav" ) );
else
G_Sound( ent, CHAN_VOICE, G_SoundIndex( "sound/player/gurp2.wav" ) );
@@ -191,59 +192,74 @@ void G_SetClientSound( gentity_t *ent )
//==============================================================
-static void G_ClientShove( gentity_t *ent, gentity_t *victim )
+/*
+==============
+ClientShove
+==============
+*/
+static int GetClientMass( gentity_t *ent )
{
- vec3_t dir, push;
- int entMass = 200, vicMass = 200;
-
- // shoving enemies changes gameplay too much
- if( !OnSameTeam( ent, victim ) )
- return;
+ int entMass = 100;
- if ( ( victim->client->ps.weapon >= WP_ABUILD ) &&
- ( victim->client->ps.weapon <= WP_HBUILD ) &&
- ( victim->client->ps.stats[ STAT_BUILDABLE ] != BA_NONE ) )
- return;
-
- // alien mass is directly related to their health points
- // human mass is 200, double for bsuit
- if( ent->client->pers.teamSelection == PTE_ALIENS )
- {
- entMass = BG_FindHealthForClass( ent->client->pers.classSelection );
- }
- else if( ent->client->pers.teamSelection == PTE_HUMANS )
+ if( ent->client->pers.teamSelection == TEAM_ALIENS )
+ entMass = BG_Class( ent->client->pers.classSelection )->health;
+ else if( ent->client->pers.teamSelection == TEAM_HUMANS )
{
if( BG_InventoryContainsUpgrade( UP_BATTLESUIT, ent->client->ps.stats ) )
entMass *= 2;
}
else
+ return 0;
+ return entMass;
+}
+
+static void ClientShove( gentity_t *ent, gentity_t *victim )
+{
+ vec3_t dir, push;
+ float force;
+ int entMass, vicMass;
+
+ // Don't push if the entity is not trying to move
+ if( !ent->client->pers.cmd.rightmove && !ent->client->pers.cmd.forwardmove &&
+ !ent->client->pers.cmd.upmove )
return;
- if( victim->client->pers.teamSelection == PTE_ALIENS )
- {
- vicMass = BG_FindHealthForClass( victim->client->pers.classSelection );
- }
- else if( BG_InventoryContainsUpgrade( UP_BATTLESUIT,
- victim->client->ps.stats ) )
- {
- vicMass *= 2;
- }
+ // Cannot push enemy players unless they are walking on the player
+ if( !OnSameTeam( ent, victim ) &&
+ victim->client->ps.groundEntityNum != ent - g_entities )
+ return;
+ // Shove force is scaled by relative mass
+ entMass = GetClientMass( ent );
+ vicMass = GetClientMass( victim );
if( vicMass <= 0 || entMass <= 0 )
return;
+ force = g_shove.value * entMass / vicMass;
+ if( force < 0 )
+ force = 0;
+ if( force > 150 )
+ force = 150;
+ // Give the victim some shove velocity
VectorSubtract( victim->r.currentOrigin, ent->r.currentOrigin, dir );
VectorNormalizeFast( dir );
-
- // don't break the dretch elevator
- if( fabs( dir[ 2 ] ) > fabs( dir[ 0 ] ) && fabs( dir[ 2 ] ) > fabs( dir[ 1 ] ) )
- return;
-
- VectorScale( dir,
- ( g_shove.value * ( ( float )entMass / ( float )vicMass ) ), push );
- VectorAdd( victim->client->ps.velocity, push,
- victim->client->ps.velocity );
-
+ VectorScale( dir, force, push );
+ VectorAdd( victim->client->ps.velocity, push, victim->client->ps.velocity );
+
+ // Set the pmove timer so that the other client can't cancel
+ // out the movement immediately
+ if( !victim->client->ps.pm_time )
+ {
+ int time;
+
+ time = force * 2 + 0.5f;
+ if( time < 50 )
+ time = 50;
+ if( time > 200 )
+ time = 200;
+ victim->client->ps.pm_time = time;
+ victim->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
+ }
}
/*
@@ -253,45 +269,38 @@ ClientImpacts
*/
void ClientImpacts( gentity_t *ent, pmove_t *pm )
{
- int i, j;
+ int i;
trace_t trace;
gentity_t *other;
+ // clear a fake trace struct for touch function
memset( &trace, 0, sizeof( trace ) );
for( i = 0; i < pm->numtouch; i++ )
{
- for( j = 0; j < i; j++ )
- {
- if( pm->touchents[ j ] == pm->touchents[ i ] )
- break;
- }
-
- if( j != i )
- continue; // duplicated
-
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
+ // 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 &&
- ent->client->charging )
- ChargeAttack( ent, other );
+ // tyrant impact attacks
+ if( ent->client->ps.weapon == WP_ALEVEL4 )
+ {
+ G_ChargeAttack( ent, other );
+ G_CrushAttack( ent, other );
+ }
+ // shove players
if( ent->client && other->client )
- G_ClientShove( ent, other );
-
- if( !other->touch )
- continue;
+ ClientShove( ent, other );
- other->touch( other, ent, &trace );
+ // touch triggers
+ if( other->touch )
+ other->touch( other, ent, &trace );
}
}
@@ -316,11 +325,15 @@ void G_TouchTriggers( gentity_t *ent )
if( !ent->client )
return;
+ // noclipping clients don't activate triggers!
+ if( ent->client->noclip )
+ return;
+
// dead clients don't activate triggers!
if( ent->client->ps.stats[ STAT_HEALTH ] <= 0 )
return;
- BG_FindBBoxForClass( ent->client->ps.stats[ STAT_PCLASS ],
+ BG_ClassBoundingBox( ent->client->ps.stats[ STAT_CLASS ],
pmins, pmaxs, NULL, NULL, NULL );
VectorAdd( ent->client->ps.origin, pmins, mins );
@@ -346,9 +359,7 @@ void G_TouchTriggers( gentity_t *ent )
continue;
// ignore most entities if a spectator
- if( ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) ||
- ( ent->client->ps.stats[ STAT_STATE ] & SS_INFESTING ) ||
- ( ent->client->ps.stats[ STAT_STATE ] & SS_HOVELING ) )
+ if( ent->client->sess.spectatorState != SPECTATOR_NOT )
{
if( hit->s.eType != ET_TELEPORT_TRIGGER &&
// this is ugly but adding a new ET_? type will
@@ -380,136 +391,123 @@ void SpectatorThink( gentity_t *ent, usercmd_t *ucmd )
{
pmove_t pm;
gclient_t *client;
- qboolean attack1, attack3;
- qboolean doPmove = qtrue;
+ int clientNum;
+ qboolean attack1, following, queued;
client = ent->client;
client->oldbuttons = client->buttons;
client->buttons = ucmd->buttons;
- attack1 = ( ( client->buttons & BUTTON_ATTACK ) &&
- !( client->oldbuttons & BUTTON_ATTACK ) );
- attack3 = ( ( client->buttons & BUTTON_USE_HOLDABLE ) &&
- !( client->oldbuttons & BUTTON_USE_HOLDABLE ) );
-
- if( level.mapRotationVoteTime )
+ attack1 = ( client->buttons & BUTTON_ATTACK ) &&
+ !( client->oldbuttons & BUTTON_ATTACK );
+
+ // We are in following mode only if we are following a non-spectating client
+ following = client->sess.spectatorState == SPECTATOR_FOLLOW;
+ if( following )
{
- if( attack1 )
- {
- G_IntermissionMapVoteCommand( ent, qtrue, qfalse );
- attack1 = qfalse;
- }
- if( ( client->buttons & BUTTON_ATTACK2 ) && !( client->oldbuttons & BUTTON_ATTACK2 ) )
- G_IntermissionMapVoteCommand( ent, qfalse, qfalse );
+ clientNum = client->sess.spectatorClient;
+ if( clientNum < 0 || clientNum > level.maxclients ||
+ !g_entities[ clientNum ].client ||
+ g_entities[ clientNum ].client->sess.spectatorState != SPECTATOR_NOT )
+ following = qfalse;
}
-
- if( client->sess.spectatorState == SPECTATOR_LOCKED || client->sess.spectatorState == SPECTATOR_FOLLOW )
- client->ps.pm_type = PM_FREEZE;
+
+ // Check to see if we are in the spawn queue
+ if( client->pers.teamSelection == TEAM_ALIENS )
+ queued = G_SearchSpawnQueue( &level.alienSpawnQueue, ent - g_entities );
+ else if( client->pers.teamSelection == TEAM_HUMANS )
+ queued = G_SearchSpawnQueue( &level.humanSpawnQueue, ent - g_entities );
else
- client->ps.pm_type = PM_SPECTATOR;
+ queued = qfalse;
- if ( client->sess.spectatorState == SPECTATOR_FOLLOW )
+ // Wants to get out of spawn queue
+ if( attack1 && queued )
{
- gclient_t *cl;
- if ( client->sess.spectatorClient >= 0 )
- {
- cl = &level.clients[ client->sess.spectatorClient ];
- if ( cl->sess.sessionTeam != TEAM_SPECTATOR )
- doPmove = qfalse;
- }
+ if( client->sess.spectatorState == SPECTATOR_FOLLOW )
+ G_StopFollowing( ent );
+ if( client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
+ G_RemoveFromSpawnQueue( &level.alienSpawnQueue, client->ps.clientNum );
+ else if( client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
+ G_RemoveFromSpawnQueue( &level.humanSpawnQueue, client->ps.clientNum );
+ client->pers.classSelection = PCL_NONE;
+ client->pers.humanItemSelection = WP_NONE;
+ client->ps.stats[ STAT_CLASS ] = PCL_NONE;
+ client->ps.pm_flags &= ~PMF_QUEUED;
+ queued = qfalse;
+ }
+ else if( attack1 )
+ {
+ // Wants to get into spawn queue
+ if( client->sess.spectatorState == SPECTATOR_FOLLOW )
+ G_StopFollowing( ent );
+ if( client->pers.teamSelection == TEAM_NONE )
+ G_TriggerMenu( client->ps.clientNum, MN_TEAM );
+ else if( client->pers.teamSelection == TEAM_ALIENS )
+ G_TriggerMenu( client->ps.clientNum, MN_A_CLASS );
+ else if( client->pers.teamSelection == TEAM_HUMANS )
+ G_TriggerMenu( client->ps.clientNum, MN_H_SPAWN );
}
- if (doPmove)
+ // We are either not following anyone or following a spectator
+ if( !following )
{
- client->ps.speed = BG_FindSpeedForClass( client->ps.stats[ STAT_PCLASS ] );
-
- // in case the client entered the queue while following a teammate
- if( ( client->pers.teamSelection == PTE_ALIENS &&
- G_SearchSpawnQueue( &level.alienSpawnQueue, ent-g_entities ) ) ||
- ( client->pers.teamSelection == PTE_HUMANS &&
- G_SearchSpawnQueue( &level.humanSpawnQueue, ent-g_entities ) ) )
- {
- client->ps.pm_flags |= PMF_QUEUED;
- }
-
+ if( client->sess.spectatorState == SPECTATOR_LOCKED ||
+ client->sess.spectatorState == SPECTATOR_FOLLOW )
+ client->ps.pm_type = PM_FREEZE;
+ else if( client->noclip )
+ client->ps.pm_type = PM_NOCLIP;
+ else
+ client->ps.pm_type = PM_SPECTATOR;
+
+ if( queued )
+ client->ps.pm_flags |= PMF_QUEUED;
+ client->ps.speed = client->pers.flySpeed;
client->ps.stats[ STAT_STAMINA ] = 0;
client->ps.stats[ STAT_MISC ] = 0;
- client->ps.stats[ STAT_BUILDABLE ] = 0;
- client->ps.stats[ STAT_PCLASS ] = PCL_NONE;
+ client->ps.stats[ STAT_BUILDABLE ] = BA_NONE;
+ client->ps.stats[ STAT_CLASS ] = PCL_NONE;
client->ps.weapon = WP_NONE;
- // set up for pmove
+ // Set up for pmove
memset( &pm, 0, sizeof( pm ) );
pm.ps = &client->ps;
+ pm.pmext = &client->pmext;
pm.cmd = *ucmd;
- pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY; // spectators can fly through bodies
+ pm.tracemask = ent->clipmask;
pm.trace = trap_Trace;
pm.pointcontents = trap_PointContents;
- // perform a pmove
+ // Perform a pmove
Pmove( &pm );
- // save results of pmove
- VectorCopy( client->ps.origin, ent->s.origin );
+ // Save results of pmove
+ VectorCopy( client->ps.origin, ent->s.pos.trBase );
+ VectorCopy( client->ps.origin, ent->r.currentOrigin );
+ VectorCopy( client->ps.viewangles, ent->r.currentAngles );
+ VectorCopy( client->ps.viewangles, ent->s.pos.trBase );
G_TouchTriggers( ent );
trap_UnlinkEntity( ent );
- if( ( attack1 ) && ( client->ps.pm_flags & PMF_QUEUED ) )
- {
- if( client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
- G_RemoveFromSpawnQueue( &level.alienSpawnQueue, client->ps.clientNum );
- else if( client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
- G_RemoveFromSpawnQueue( &level.humanSpawnQueue, client->ps.clientNum );
-
- client->pers.classSelection = PCL_NONE;
- client->ps.stats[ STAT_PCLASS ] = PCL_NONE;
- }
-
- if( attack1 && client->pers.classSelection == PCL_NONE )
- {
- if( client->pers.teamSelection == PTE_NONE )
- G_TriggerMenu( client->ps.clientNum, MN_TEAM );
- else if( client->pers.teamSelection == PTE_ALIENS )
- G_TriggerMenu( client->ps.clientNum, MN_A_CLASS );
- else if( client->pers.teamSelection == PTE_HUMANS )
- G_TriggerMenu( client->ps.clientNum, MN_H_SPAWN );
- }
-
- //set the queue position for the client side
+ // Set the queue position and spawn count for the client side
if( client->ps.pm_flags & PMF_QUEUED )
{
- if( client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
+ if( client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
{
client->ps.persistant[ PERS_QUEUEPOS ] =
G_GetPosInSpawnQueue( &level.alienSpawnQueue, client->ps.clientNum );
+ client->ps.persistant[ PERS_SPAWNS ] = level.numAlienSpawns;
}
- else if( client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ else if( client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
{
client->ps.persistant[ PERS_QUEUEPOS ] =
G_GetPosInSpawnQueue( &level.humanSpawnQueue, client->ps.clientNum );
+ client->ps.persistant[ PERS_SPAWNS ] = level.numHumanSpawns;
}
}
}
-
- else if( attack1 && ent->client->sess.spectatorState == SPECTATOR_FOLLOW )
- {
- G_StopFollowing( ent );
- client->pers.classSelection = PCL_NONE;
- if( client->pers.teamSelection == PTE_NONE )
- G_TriggerMenu( ent-g_entities, MN_TEAM );
- else if( client->pers.teamSelection == PTE_ALIENS )
- G_TriggerMenu( ent-g_entities, MN_A_CLASS );
- else if( client->pers.teamSelection == PTE_HUMANS )
- G_TriggerMenu( ent-g_entities, MN_H_SPAWN );
- }
-
- if( attack3 )
- {
- G_ToggleFollow( ent );
- }
}
@@ -521,8 +519,10 @@ ClientInactivityTimer
Returns qfalse if the client is dropped
=================
*/
-qboolean ClientInactivityTimer( gclient_t *client )
+qboolean ClientInactivityTimer( gentity_t *ent )
{
+ gclient_t *client = ent->client;
+
if( ! g_inactivity.integer )
{
// give everyone some time, so if the operator sets g_inactivity during
@@ -540,13 +540,16 @@ qboolean ClientInactivityTimer( gclient_t *client )
}
else if( !client->pers.localClient )
{
- if( level.time > client->inactivityTime )
+ if( level.time > client->inactivityTime &&
+ !G_admin_permission( ent, ADMF_ACTIVITY ) )
{
trap_DropClient( client - level.clients, "Dropped due to inactivity" );
return qfalse;
}
- if( level.time > client->inactivityTime - 10000 && !client->inactivityWarning )
+ if( level.time > client->inactivityTime - 10000 &&
+ !client->inactivityWarning &&
+ !G_admin_permission( ent, ADMF_ACTIVITY ) )
{
client->inactivityWarning = qtrue;
trap_SendServerCommand( client - level.clients, "cp \"Ten seconds until inactivity drop!\n\"" );
@@ -569,203 +572,100 @@ void ClientTimerActions( gentity_t *ent, int msec )
usercmd_t *ucmd;
int aForward, aRight;
qboolean walking = qfalse, stopped = qfalse,
- crouched = qfalse, jumping = qfalse,
- strafing = qfalse;
+ crouched = qfalse;
+ int i;
ucmd = &ent->client->pers.cmd;
aForward = abs( ucmd->forwardmove );
aRight = abs( ucmd->rightmove );
- client = ent->client;
- client->time100 += msec;
- client->time1000 += msec;
- client->time10000 += msec;
-
if( aForward == 0 && aRight == 0 )
stopped = qtrue;
else if( aForward <= 64 && aRight <= 64 )
walking = qtrue;
- if( aRight > 0 )
- strafing = qtrue;
-
- if( ucmd->upmove > 0 )
- jumping = qtrue;
- else if( ent->client->ps.pm_flags & PMF_DUCKED )
+ if( ucmd->upmove <= 0 && ent->client->ps.pm_flags & PMF_DUCKED )
crouched = qtrue;
+ client = ent->client;
+ client->time100 += msec;
+ client->time1000 += msec;
+ client->time10000 += msec;
+
while ( client->time100 >= 100 )
{
+ weapon_t weapon = BG_GetPlayerWeapon( &client->ps );
+
client->time100 -= 100;
- //if not trying to run then not trying to sprint
- if( walking || stopped )
- client->ps.stats[ STAT_STATE ] &= ~SS_SPEEDBOOST;
-
- if( BG_InventoryContainsUpgrade( UP_JETPACK, client->ps.stats ) && BG_UpgradeIsActive( UP_JETPACK, client->ps.stats ) )
- client->ps.stats[ STAT_STATE ] &= ~SS_SPEEDBOOST;
-
- if( ( client->ps.stats[ STAT_STATE ] & SS_SPEEDBOOST ) && !crouched )
- {
- //subtract stamina
- if( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, client->ps.stats ) )
- client->ps.stats[ STAT_STAMINA ] -= STAMINA_LARMOUR_TAKE;
- else
- client->ps.stats[ STAT_STAMINA ] -= STAMINA_SPRINT_TAKE;
-
- if( client->ps.stats[ STAT_STAMINA ] < -MAX_STAMINA )
- client->ps.stats[ STAT_STAMINA ] = -MAX_STAMINA;
- }
-
- if( walking || crouched )
- {
- //restore stamina
- client->ps.stats[ STAT_STAMINA ] += STAMINA_WALK_RESTORE;
-
- if( client->ps.stats[ STAT_STAMINA ] > MAX_STAMINA )
- client->ps.stats[ STAT_STAMINA ] = MAX_STAMINA;
- }
- else if( stopped )
- {
- //restore stamina faster
+ // Restore or subtract stamina
+ if( stopped || client->ps.pm_type == PM_JETPACK )
client->ps.stats[ STAT_STAMINA ] += STAMINA_STOP_RESTORE;
-
- if( client->ps.stats[ STAT_STAMINA ] > MAX_STAMINA )
- client->ps.stats[ STAT_STAMINA ] = MAX_STAMINA;
- }
-
- //client is charging up for a pounce
- if( client->ps.weapon == WP_ALEVEL3 || client->ps.weapon == WP_ALEVEL3_UPG )
- {
- int pounceSpeed = 0;
-
- if( client->ps.weapon == WP_ALEVEL3 )
- pounceSpeed = LEVEL3_POUNCE_SPEED;
- else if( client->ps.weapon == WP_ALEVEL3_UPG )
- pounceSpeed = LEVEL3_POUNCE_UPG_SPEED;
-
- if( client->ps.stats[ STAT_MISC ] < pounceSpeed && ucmd->buttons & BUTTON_ATTACK2 )
- client->ps.stats[ STAT_MISC ] += ( 100.0f / (float)LEVEL3_POUNCE_CHARGE_TIME ) * pounceSpeed;
-
- if( !( ucmd->buttons & BUTTON_ATTACK2 ) )
- {
- if( client->pmext.pouncePayload > 0 )
- client->allowedToPounce = qtrue;
- }
-
- if( client->ps.stats[ STAT_MISC ] > pounceSpeed )
- client->ps.stats[ STAT_MISC ] = pounceSpeed;
- }
-
- //client is charging up for a... charge
- if( client->ps.weapon == WP_ALEVEL4 )
+ else if( ( client->ps.stats[ STAT_STATE ] & SS_SPEEDBOOST ) &&
+ !( client->buttons & BUTTON_WALKING ) ) // walk overrides sprint
+ client->ps.stats[ STAT_STAMINA ] -= STAMINA_SPRINT_TAKE;
+ else if( walking || crouched )
+ client->ps.stats[ STAT_STAMINA ] += STAMINA_WALK_RESTORE;
+
+ // Check stamina limits
+ if( client->ps.stats[ STAT_STAMINA ] > STAMINA_MAX )
+ client->ps.stats[ STAT_STAMINA ] = STAMINA_MAX;
+ else if( client->ps.stats[ STAT_STAMINA ] < -STAMINA_MAX )
+ client->ps.stats[ STAT_STAMINA ] = -STAMINA_MAX;
+
+ if( weapon == WP_ABUILD || weapon == WP_ABUILD2 ||
+ client->ps.stats[ STAT_WEAPON ] == WP_HBUILD )
{
- if( client->ps.stats[ STAT_MISC ] < LEVEL4_CHARGE_TIME && ucmd->buttons & BUTTON_ATTACK2 &&
- !client->charging )
- {
- client->charging = qfalse; //should already be off, just making sure
- client->ps.stats[ STAT_STATE ] &= ~SS_CHARGING;
-
- if( ucmd->forwardmove > 0 )
- {
- //trigger charge sound...is quite annoying
- //if( client->ps.stats[ STAT_MISC ] <= 0 )
- // G_AddEvent( ent, EV_LEV4_CHARGE_PREPARE, 0 );
-
- client->ps.stats[ STAT_MISC ] += (int)( 100 * (float)LEVEL4_CHARGE_CHARGE_RATIO );
-
- if( client->ps.stats[ STAT_MISC ] > LEVEL4_CHARGE_TIME )
- client->ps.stats[ STAT_MISC ] = LEVEL4_CHARGE_TIME;
- }
- else
- client->ps.stats[ STAT_MISC ] = 0;
- }
-
- if( !( ucmd->buttons & BUTTON_ATTACK2 ) || client->charging ||
- client->ps.stats[ STAT_MISC ] == LEVEL4_CHARGE_TIME )
- {
- if( client->ps.stats[ STAT_MISC ] > LEVEL4_MIN_CHARGE_TIME )
- {
+ // Update build timer
+ if( client->ps.stats[ STAT_MISC ] > 0 )
client->ps.stats[ STAT_MISC ] -= 100;
- if( client->charging == qfalse )
- G_AddEvent( ent, EV_LEV4_CHARGE_START, 0 );
-
- client->charging = qtrue;
- client->ps.stats[ STAT_STATE ] |= SS_CHARGING;
-
- //if the charger has stopped moving take a chunk of charge away
- if( VectorLength( client->ps.velocity ) < 64.0f || aRight )
- client->ps.stats[ STAT_MISC ] = client->ps.stats[ STAT_MISC ] / 2;
-
- //can't charge backwards
- if( ucmd->forwardmove < 0 )
- client->ps.stats[ STAT_MISC ] = 0;
- }
- else
- client->ps.stats[ STAT_MISC ] = 0;
-
-
- if( client->ps.stats[ STAT_MISC ] <= 0 )
- {
+ if( client->ps.stats[ STAT_MISC ] < 0 )
client->ps.stats[ STAT_MISC ] = 0;
- client->charging = qfalse;
- client->ps.stats[ STAT_STATE ] &= ~SS_CHARGING;
- }
- }
- }
-
- //client is charging up an lcannon
- if( client->ps.weapon == WP_LUCIFER_CANNON )
- {
- int ammo;
-
- ammo = client->ps.ammo;
-
- if( client->ps.stats[ STAT_MISC ] < LCANNON_TOTAL_CHARGE && ucmd->buttons & BUTTON_ATTACK )
- client->ps.stats[ STAT_MISC ] += ( 100.0f / LCANNON_CHARGE_TIME ) * LCANNON_TOTAL_CHARGE;
-
- if( client->ps.stats[ STAT_MISC ] > LCANNON_TOTAL_CHARGE )
- client->ps.stats[ STAT_MISC ] = LCANNON_TOTAL_CHARGE;
-
- if( client->ps.stats[ STAT_MISC ] > ( ammo * LCANNON_TOTAL_CHARGE ) / 10 )
- client->ps.stats[ STAT_MISC ] = ammo * LCANNON_TOTAL_CHARGE / 10;
}
- switch( client->ps.weapon )
+ switch( weapon )
{
case WP_ABUILD:
case WP_ABUILD2:
case WP_HBUILD:
- case WP_HBUILD2:
- //set validity bit on buildable
+
+ // Set validity bit on buildable
if( ( client->ps.stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) > BA_NONE )
{
- int dist = BG_FindBuildDistForClass( ent->client->ps.stats[ STAT_PCLASS ] );
- vec3_t dummy;
+ int dist = BG_Class( ent->client->ps.stats[ STAT_CLASS ] )->buildDist;
+ vec3_t dummy, dummy2;
+ int dummy3;
if( G_CanBuild( ent, client->ps.stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT,
- dist, dummy ) == IBE_NONE )
+ dist, dummy, dummy2, &dummy3 ) == IBE_NONE )
client->ps.stats[ STAT_BUILDABLE ] |= SB_VALID_TOGGLEBIT;
else
client->ps.stats[ STAT_BUILDABLE ] &= ~SB_VALID_TOGGLEBIT;
- }
- case WP_BLASTER:
- //update build timer
- if( client->ps.stats[ STAT_MISC ] > 0 )
- client->ps.stats[ STAT_MISC ] -= 100;
-
- if( client->ps.stats[ STAT_MISC ] < 0 )
- client->ps.stats[ STAT_MISC ] = 0;
+ // Let the client know which buildables will be removed by building
+ for( i = 0; i < MAX_MISC; i++ )
+ {
+ if( i < level.numBuildablesForRemoval )
+ client->ps.misc[ i ] = level.markedBuildables[ i ]->s.number;
+ else
+ client->ps.misc[ i ] = 0;
+ }
+ }
+ else
+ {
+ for( i = 0; i < MAX_MISC; i++ )
+ client->ps.misc[ i ] = 0;
+ }
break;
default:
break;
}
- if( client->ps.stats[ STAT_STATE ] & SS_MEDKIT_ACTIVE )
+ if( ent->client->pers.teamSelection == TEAM_HUMANS &&
+ ( client->ps.stats[ STAT_STATE ] & SS_HEALING_2X ) )
{
int remainingStartupTime = MEDKIT_STARTUP_TIME - ( level.time - client->lastMedKitTime );
@@ -777,9 +677,10 @@ void ClientTimerActions( gentity_t *ent, int msec )
{
ent->client->medKitHealthToRestore--;
ent->health++;
+ ent->client->ps.stats[ STAT_HEALTH ] = ent->health;
}
else
- ent->client->ps.stats[ STAT_STATE ] &= ~SS_MEDKIT_ACTIVE;
+ ent->client->ps.stats[ STAT_STATE ] &= ~SS_HEALING_2X;
}
else
{
@@ -792,13 +693,14 @@ void ClientTimerActions( gentity_t *ent, int msec )
{
ent->client->medKitHealthToRestore--;
ent->health++;
+ ent->client->ps.stats[ STAT_HEALTH ] = ent->health;
client->medKitIncrementTime = level.time +
( remainingStartupTime / MEDKIT_STARTUP_SPEED );
}
}
else
- ent->client->ps.stats[ STAT_STATE ] &= ~SS_MEDKIT_ACTIVE;
+ ent->client->ps.stats[ STAT_STATE ] &= ~SS_HEALING_2X;
}
}
}
@@ -807,20 +709,17 @@ void ClientTimerActions( gentity_t *ent, int msec )
{
client->time1000 -= 1000;
- //client is poison clouded
- if( client->ps.stats[ STAT_STATE ] & SS_POISONCLOUDED )
- G_Damage( ent, client->lastPoisonCloudedClient, client->lastPoisonCloudedClient, NULL, NULL,
- LEVEL1_PCLOUD_DMG, 0, MOD_LEVEL1_PCLOUD );
-
//client is poisoned
if( client->ps.stats[ STAT_STATE ] & SS_POISONED )
{
- int damage = ALIEN_POISON_DMG;
-
+ int damage = ALIEN_POISON_DMG;
+
if( BG_InventoryContainsUpgrade( UP_BATTLESUIT, client->ps.stats ) )
damage -= BSUIT_POISON_PROTECTION;
+
if( BG_InventoryContainsUpgrade( UP_HELMET, client->ps.stats ) )
damage -= HELMET_POISON_PROTECTION;
+
if( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, client->ps.stats ) )
damage -= LIGHTARMOUR_POISON_PROTECTION;
@@ -828,135 +727,37 @@ void ClientTimerActions( gentity_t *ent, int msec )
0, damage, 0, MOD_POISON );
}
- //replenish alien health
- if( client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS &&
- level.surrenderTeam != PTE_ALIENS )
- {
- int entityList[ MAX_GENTITIES ];
- vec3_t range = { LEVEL1_REGEN_RANGE, LEVEL1_REGEN_RANGE, LEVEL1_REGEN_RANGE };
- vec3_t mins, maxs;
- int i, num;
- gentity_t *boostEntity;
- float modifier = 1.0f;
-
- VectorAdd( client->ps.origin, range, maxs );
- VectorSubtract( client->ps.origin, range, mins );
-
- num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
- for( i = 0; i < num; i++ )
- {
- boostEntity = &g_entities[ entityList[ i ] ];
-
- if( boostEntity->client && boostEntity->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS &&
- boostEntity->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_LEVEL1_UPG )
- {
- modifier = LEVEL1_REGEN_MOD;
- break;
- }
- else if( boostEntity->s.eType == ET_BUILDABLE &&
- boostEntity->s.modelindex == BA_A_BOOSTER &&
- boostEntity->spawned && boostEntity->health > 0 )
- {
- modifier = BOOSTER_REGEN_MOD;
- break;
- }
- }
-
- if( ent->health > 0 && ent->health < client->ps.stats[ STAT_MAX_HEALTH ] &&
- !level.paused &&
- ( ent->lastDamageTime + ALIEN_REGEN_DAMAGE_TIME ) < level.time )
- {
- ent->health += BG_FindRegenRateForClass( client->ps.stats[ STAT_PCLASS ] ) * modifier;
-
- // if completely healed, cancel retribution
- if( ent->health >= client->ps.stats[ STAT_MAX_HEALTH ] )
- {
- for( i = 0; i < MAX_CLIENTS; i++ )
- ent->client->tkcredits[ i ] = 0;
- }
- }
-
- if( ent->health > client->ps.stats[ STAT_MAX_HEALTH ] )
- ent->health = client->ps.stats[ STAT_MAX_HEALTH ];
- }
-
-
- if( ent->client->ps.stats[ STAT_HEALTH ] > 0 && ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
- {
- ent->client->pers.statscounters.timealive++;
- level.alienStatsCounters.timealive++;
- if( G_BuildableRange( ent->client->ps.origin, 900, BA_A_OVERMIND ) )
- {
- ent->client->pers.statscounters.timeinbase++;
- level.alienStatsCounters.timeinbase++;
- }
- if( BG_ClassHasAbility( ent->client->ps.stats[ STAT_PCLASS ], SCA_WALLCLIMBER ) )
- {
- ent->client->pers.statscounters.dretchbasytime++;
- level.alienStatsCounters.dretchbasytime++;
- if( ent->client->ps.stats[ STAT_STATE ] & SS_WALLCLIMBING || ent->client->ps.stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING)
- {
- ent->client->pers.statscounters.jetpackusewallwalkusetime++;
- level.alienStatsCounters.jetpackusewallwalkusetime++;
- }
- }
- }
- else if( ent->client->ps.stats[ STAT_HEALTH ] > 0 && ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
- {
- ent->client->pers.statscounters.timealive++;
- level.humanStatsCounters.timealive++;
- if( G_BuildableRange( ent->client->ps.origin, 900, BA_H_REACTOR ) )
- {
- ent->client->pers.statscounters.timeinbase++;
- level.humanStatsCounters.timeinbase++;
- }
- if( BG_InventoryContainsUpgrade( UP_JETPACK, client->ps.stats ) )
- {
- if( client->ps.pm_type == PM_JETPACK )
- {
- ent->client->pers.statscounters.jetpackusewallwalkusetime++;
- level.humanStatsCounters.jetpackusewallwalkusetime++;
- }
- }
- }
-
- // turn off life support when a team admits defeat
- if( client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS &&
- level.surrenderTeam == PTE_ALIENS )
+ // turn off life support when a team admits defeat
+ if( client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS &&
+ level.surrenderTeam == TEAM_ALIENS )
{
G_Damage( ent, NULL, NULL, NULL, NULL,
- BG_FindRegenRateForClass( client->ps.stats[ STAT_PCLASS ] ),
+ BG_Class( client->ps.stats[ STAT_CLASS ] )->regenRate,
DAMAGE_NO_ARMOR, MOD_SUICIDE );
}
- else if( client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS &&
- level.surrenderTeam == PTE_HUMANS )
+ else if( client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS &&
+ level.surrenderTeam == TEAM_HUMANS )
{
G_Damage( ent, NULL, NULL, NULL, NULL, 5, DAMAGE_NO_ARMOR, MOD_SUICIDE );
}
- //my new jetpack code
- if( mod_jetpackFuel.value >= 10.0f ) {
- //if we have jetpack and its on
- if( BG_InventoryContainsUpgrade( UP_JETPACK, client->ps.stats ) && BG_UpgradeIsActive( UP_JETPACK, client->ps.stats ) ) {
- //check if fuels 0 if so deactivate it if not give a 10 second fuel low warning and take JETPACK_USE_RATE from fuel
- if( client->jetpackfuel <= 0.0f ) {
- BG_DeactivateUpgrade( UP_JETPACK, client->ps.stats );
- } else if( client->jetpackfuel < 10.0f && client->jetpackfuel > 0.0f) {
- client->jetpackfuel = client->jetpackfuel - mod_jetpackConsume.value;
- trap_SendServerCommand( client - level.clients, "cp \"^3Fuel ^1Low!!!!!^7\nLand now.\"" );
- } else {
- client->jetpackfuel = client->jetpackfuel - mod_jetpackConsume.value;
- }
+ // lose some voice enthusiasm
+ if( client->voiceEnthusiasm > 0.0f )
+ client->voiceEnthusiasm -= VOICE_ENTHUSIASM_DECAY;
+ else
+ client->voiceEnthusiasm = 0.0f;
- //if jetpack isnt active regenerate fuel and give a message when its full
- } else if( BG_InventoryContainsUpgrade( UP_JETPACK, client->ps.stats ) && !BG_UpgradeIsActive( UP_JETPACK, client->ps.stats ) ) {
- if( client->jetpackfuel > ( mod_jetpackFuel.value - 10.0f ) && client->jetpackfuel <= mod_jetpackFuel.value ) {
- client->jetpackfuel = client->jetpackfuel + mod_jetpackRegen.value;
- trap_SendServerCommand( client - level.clients, "cp \"^3Fuel Status: ^2Full!^7\n\"" );
- } else if( client->jetpackfuel < mod_jetpackFuel.value ) {
- //regenerate some fuel
- client->jetpackfuel = client->jetpackfuel + mod_jetpackRegen.value;
- }
+ client->pers.secondsAlive++;
+ if( g_freeFundPeriod.integer > 0 &&
+ client->pers.secondsAlive % g_freeFundPeriod.integer == 0 )
+ {
+ // Give clients some credit periodically
+ if( G_TimeTilSuddenDeath( ) > 0 )
+ {
+ if( client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
+ G_AddCreditToClient( client, FREEKILL_ALIEN, qtrue );
+ else if( client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
+ G_AddCreditToClient( client, FREEKILL_HUMAN, qtrue );
}
}
}
@@ -965,21 +766,42 @@ void ClientTimerActions( gentity_t *ent, int msec )
{
client->time10000 -= 10000;
- if( client->ps.weapon == WP_ALEVEL3_UPG )
+ if( ent->client->ps.weapon == WP_ABUILD ||
+ ent->client->ps.weapon == WP_ABUILD2 )
{
- int ammo, maxAmmo;
+ AddScore( ent, ALIEN_BUILDER_SCOREINC );
+ }
+ else if( ent->client->ps.weapon == WP_HBUILD )
+ {
+ AddScore( ent, HUMAN_BUILDER_SCOREINC );
+ }
- BG_FindAmmoForWeapon( WP_ALEVEL3_UPG, &maxAmmo, NULL );
- ammo = client->ps.ammo;
+ // Give score to basis that healed other aliens
+ if( ent->client->pers.hasHealed )
+ {
+ if( client->ps.weapon == WP_ALEVEL1 )
+ AddScore( ent, LEVEL1_REGEN_SCOREINC );
+ else if( client->ps.weapon == WP_ALEVEL1_UPG )
+ AddScore( ent, LEVEL1_UPG_REGEN_SCOREINC );
+
+ ent->client->pers.hasHealed = qfalse;
+ }
+ }
- if( ammo < maxAmmo )
+ // Regenerate Adv. Dragoon barbs
+ if( client->ps.weapon == WP_ALEVEL3_UPG )
+ {
+ if( client->ps.ammo < BG_Weapon( WP_ALEVEL3_UPG )->maxAmmo )
+ {
+ if( ent->timestamp + LEVEL3_BOUNCEBALL_REGEN < level.time )
{
- ammo++;
- client->ps.ammo = ammo;
- client->ps.clips = 0;
+ client->ps.ammo++;
+ ent->timestamp = level.time;
}
}
- }
+ else
+ ent->timestamp = level.time;
+ }
}
/*
@@ -989,7 +811,6 @@ ClientIntermissionThink
*/
void ClientIntermissionThink( gclient_t *client )
{
- client->ps.eFlags &= ~EF_TALK;
client->ps.eFlags &= ~EF_FIRING;
client->ps.eFlags &= ~EF_FIRING2;
@@ -1020,10 +841,10 @@ void ClientEvents( gentity_t *ent, int oldEventSequence )
vec3_t dir;
vec3_t point, mins;
float fallDistance;
- pClass_t class;
+ class_t class;
client = ent->client;
- class = client->ps.stats[ STAT_PCLASS ];
+ class = client->ps.stats[ STAT_CLASS ];
if( oldEventSequence < client->ps.eventSequence - MAX_PS_EVENTS )
oldEventSequence = client->ps.eventSequence - MAX_PS_EVENTS;
@@ -1047,11 +868,11 @@ void ClientEvents( gentity_t *ent, int oldEventSequence )
else if( fallDistance > 1.0f )
fallDistance = 1.0f;
- damage = (int)( (float)BG_FindHealthForClass( class ) *
- BG_FindFallDamageForClass( class ) * fallDistance );
+ damage = (int)( (float)BG_Class( class )->health *
+ BG_Class( class )->fallDamage * fallDistance );
VectorSet( dir, 0, 0, 1 );
- BG_FindBBoxForClass( class, mins, NULL, NULL, NULL, NULL );
+ BG_ClassBoundingBox( class, mins, NULL, NULL, NULL, NULL );
mins[ 0 ] = mins[ 1 ] = 0.0f;
VectorAdd( client->ps.origin, mins, point );
@@ -1122,8 +943,8 @@ 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[].
+ 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()
==============
*/
@@ -1132,24 +953,24 @@ void G_UnlaggedStore( void )
int i = 0;
gentity_t *ent;
unlagged_t *save;
-
+
if( !g_unlagged.integer )
return;
- level.unlaggedIndex++;
+ 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;
+ save->used = qfalse;
if( !ent->r.linked || !( ent->r.contents & CONTENTS_BODY ) )
continue;
if( ent->client->pers.connected != CON_CONNECTED )
- continue;
+ continue;
VectorCopy( ent->r.mins, save->mins );
VectorCopy( ent->r.maxs, save->maxs );
VectorCopy( ent->s.pos.trBase, save->origin );
@@ -1160,7 +981,7 @@ void G_UnlaggedStore( void )
/*
==============
G_UnlaggedClear
-
+
Mark all unlaggedHist[] markers for this client invalid. Useful for
preventing teleporting and death.
==============
@@ -1185,14 +1006,14 @@ 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;
+ int startIndex;
+ int stopIndex;
+ int frameMsec;
+ float lerp;
if( !g_unlagged.integer )
return;
-
+
// clear any calculated values from a previous run
for( i = 0; i < level.maxclients; i++ )
{
@@ -1200,13 +1021,18 @@ void G_UnlaggedCalc( int time, gentity_t *rewindEnt )
ent->client->unlaggedCalc.used = qfalse;
}
- for( i = 0; i < MAX_UNLAGGED_MARKERS; i++ )
+ // client is on the current frame, no need for unlagged
+ if( level.unlaggedTimes[ level.unlaggedIndex ] <= time )
+ return;
+
+ startIndex = level.unlaggedIndex;
+ for( i = 1; i < MAX_UNLAGGED_MARKERS; i++ )
{
- if( level.unlaggedTimes[ startIndex ] <= time )
- break;
stopIndex = startIndex;
if( --startIndex < 0 )
startIndex = MAX_UNLAGGED_MARKERS - 1;
+ if( level.unlaggedTimes[ startIndex ] <= time )
+ break;
}
if( i == MAX_UNLAGGED_MARKERS )
{
@@ -1214,20 +1040,13 @@ void G_UnlaggedCalc( int time, gentity_t *rewindEnt )
// 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 )
+ else
{
- lerp = ( float )( time - level.unlaggedTimes[ startIndex ] )
- / ( float )frameMsec;
+ // lerp between two markers
+ frameMsec = level.unlaggedTimes[ stopIndex ] - level.unlaggedTimes[ startIndex ];
+ lerp = ( float )( time - level.unlaggedTimes[ startIndex ] ) / ( float )frameMsec;
}
-
+
for( i = 0; i < level.maxclients; i++ )
{
ent = &g_entities[ i ];
@@ -1243,13 +1062,13 @@ void G_UnlaggedCalc( int time, gentity_t *rewindEnt )
continue;
// between two unlagged markers
- VectorLerp( lerp, ent->client->unlaggedHist[ startIndex ].mins,
+ VectorLerp2( lerp, ent->client->unlaggedHist[ startIndex ].mins,
ent->client->unlaggedHist[ stopIndex ].mins,
ent->client->unlaggedCalc.mins );
- VectorLerp( lerp, ent->client->unlaggedHist[ startIndex ].maxs,
+ VectorLerp2( lerp, ent->client->unlaggedHist[ startIndex ].maxs,
ent->client->unlaggedHist[ stopIndex ].maxs,
ent->client->unlaggedCalc.maxs );
- VectorLerp( lerp, ent->client->unlaggedHist[ startIndex ].origin,
+ VectorLerp2( lerp, ent->client->unlaggedHist[ startIndex ].origin,
ent->client->unlaggedHist[ stopIndex ].origin,
ent->client->unlaggedCalc.origin );
@@ -1268,10 +1087,10 @@ 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 ];
@@ -1304,13 +1123,13 @@ void G_UnlaggedOn( gentity_t *attacker, vec3_t muzzle, float range )
int i = 0;
gentity_t *ent;
unlagged_t *calc;
-
+
if( !g_unlagged.integer )
return;
if( !attacker->client->pers.useUnlagged )
return;
-
+
for( i = 0; i < level.maxclients; i++ )
{
ent = &g_entities[ i ];
@@ -1331,7 +1150,7 @@ void G_UnlaggedOn( gentity_t *attacker, vec3_t muzzle, float range )
float maxRadius = ( r1 > r2 ) ? r1 : r2;
if( Distance( muzzle, calc->origin ) > range + maxRadius )
- continue;
+ continue;
}
// create a backup of the real positions
@@ -1355,7 +1174,7 @@ void G_UnlaggedOn( gentity_t *attacker, vec3_t muzzle, float range )
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
+ 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.
@@ -1378,6 +1197,7 @@ static void G_UnlaggedDetectCollisions( gentity_t *ent )
if( !g_unlagged.integer )
return;
+
if( !ent->client->pers.useUnlagged )
return;
@@ -1400,49 +1220,13 @@ static void G_UnlaggedDetectCollisions( gentity_t *ent )
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_entities[ tr.entityNum ].client->unlaggedCalc.used = qfalse;
G_UnlaggedOff( );
}
/*
==============
-ClientGradualFunds
-
-g_gradualFreeFunds values:
-0 - disabled
-1 - vanilla behavior
-2 - 1 and counters don't reset on death or evolution
-3 - 2 and funds are given even during SD
-==============
-*/
-static void ClientGradualFunds( gentity_t *ent )
-{
- if( !g_gradualFreeFunds.integer )
- return;
-
- if( ent->client->pers.lastFreekillTime + FREEKILL_PERIOD >= level.time )
- return;
-
- if( g_suddenDeath.integer && g_gradualFreeFunds.integer < 3 )
- return;
-
- switch ( ent->client->ps.stats[ STAT_PTEAM ] )
- {
- case PTE_ALIENS:
- G_AddCreditToClient( ent->client, FREEKILL_ALIEN, qtrue );
- break;
-
- case PTE_HUMANS:
- G_AddCreditToClient( ent->client, FREEKILL_HUMAN, qtrue );
- break;
- }
-
- ent->client->pers.lastFreekillTime += FREEKILL_PERIOD;
-}
-
-/*
-==============
ClientThink
This will be called once for each client frame, which will
@@ -1459,7 +1243,6 @@ void ClientThink_real( gentity_t *ent )
int oldEventSequence;
int msec;
usercmd_t *ucmd;
- int real_pm_type;
client = ent->client;
@@ -1470,34 +1253,12 @@ void ClientThink_real( gentity_t *ent )
// mark the time, so the connection sprite can be removed
ucmd = &ent->client->pers.cmd;
- if( client->pers.paused )
- ucmd->forwardmove = ucmd->rightmove = ucmd->upmove = ucmd->buttons = 0;
-
// sanity check the command time to prevent speedup cheating
if( ucmd->serverTime > level.time + 200 )
- {
ucmd->serverTime = level.time + 200;
-// G_Printf("serverTime <<<<<\n" );
- }
if( ucmd->serverTime < level.time - 1000 )
- {
ucmd->serverTime = level.time - 1000;
-// G_Printf("serverTime >>>>>\n" );
- }
-
- // ucmd->serverTime is a client predicted value, but it works for making a
- // replacement for client->ps.ping when in SPECTATOR_FOLLOW
- client->pers.ping = level.time - ucmd->serverTime;
-
- // account for the one frame of delay on client side
- client->pers.ping -= level.time - level.previousTime;
-
- // account for the time that's elapsed since the last ClientEndFrame()
- client->pers.ping += trap_Milliseconds( ) - level.frameMsec;
-
- if( client->pers.ping < 0 )
- client->pers.ping = 0;
msec = ucmd->serverTime - client->ps.commandTime;
// following others may result in bad times, but we still want
@@ -1511,9 +1272,15 @@ void ClientThink_real( gentity_t *ent )
client->unlaggedTime = ucmd->serverTime;
if( pmove_msec.integer < 8 )
+ {
trap_Cvar_Set( "pmove_msec", "8" );
+ trap_Cvar_Update(&pmove_msec);
+ }
else if( pmove_msec.integer > 33 )
+ {
trap_Cvar_Set( "pmove_msec", "33" );
+ trap_Cvar_Update(&pmove_msec);
+ }
if( pmove_fixed.integer || client->pers.pmoveFixed )
{
@@ -1527,21 +1294,12 @@ void ClientThink_real( gentity_t *ent )
//
if( level.intermissiontime )
{
- if( level.mapRotationVoteTime )
- {
- SpectatorThink( ent, ucmd );
- return;
- }
-
ClientIntermissionThink( client );
return;
}
- if( client->pers.teamSelection != PTE_NONE && client->pers.joinedATeam )
- G_UpdatePTRConnection( client );
-
// spectators don't do much
- if( client->sess.sessionTeam == TEAM_SPECTATOR )
+ if( client->sess.spectatorState != SPECTATOR_NOT )
{
if( client->sess.spectatorState == SPECTATOR_SCOREBOARD )
return;
@@ -1550,20 +1308,19 @@ void ClientThink_real( gentity_t *ent )
return;
}
+ G_namelog_update_score( client );
+
// check for inactivity timer, but never drop the local client of a non-dedicated server
- if( !ClientInactivityTimer( client ) )
+ if( !ClientInactivityTimer( ent ) )
return;
- // calculate where ent is currently seeing all the other active clients
+ // 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 )
client->ps.pm_type = PM_DEAD;
- else if( client->ps.stats[ STAT_STATE ] & SS_INFESTING ||
- client->ps.stats[ STAT_STATE ] & SS_HOVELING )
- client->ps.pm_type = PM_FREEZE;
else if( client->ps.stats[ STAT_STATE ] & SS_BLOBLOCKED ||
client->ps.stats[ STAT_STATE ] & SS_GRABBED )
client->ps.pm_type = PM_GRABBED;
@@ -1572,31 +1329,33 @@ void ClientThink_real( gentity_t *ent )
else
client->ps.pm_type = PM_NORMAL;
- // paused
- real_pm_type = client->ps.pm_type;
- if ( level.paused ) client->ps.pm_type = PM_SPECTATOR;
-
- if( client->ps.stats[ STAT_STATE ] & SS_GRABBED &&
+ if( ( client->ps.stats[ STAT_STATE ] & SS_GRABBED ) &&
client->grabExpiryTime < level.time )
client->ps.stats[ STAT_STATE ] &= ~SS_GRABBED;
- if( client->ps.stats[ STAT_STATE ] & SS_BLOBLOCKED &&
+ if( ( client->ps.stats[ STAT_STATE ] & SS_BLOBLOCKED ) &&
client->lastLockTime + LOCKBLOB_LOCKTIME < level.time )
client->ps.stats[ STAT_STATE ] &= ~SS_BLOBLOCKED;
- if( client->ps.stats[ STAT_STATE ] & SS_SLOWLOCKED &&
+ if( ( client->ps.stats[ STAT_STATE ] & SS_SLOWLOCKED ) &&
client->lastSlowTime + ABUILDER_BLOB_TIME < level.time )
client->ps.stats[ STAT_STATE ] &= ~SS_SLOWLOCKED;
- client->ps.stats[ STAT_BOOSTTIME ] = level.time - client->lastBoostedTime;
-
- if( client->ps.stats[ STAT_STATE ] & SS_BOOSTED &&
- client->lastBoostedTime + BOOST_TIME < level.time )
- client->ps.stats[ STAT_STATE ] &= ~SS_BOOSTED;
+ // Update boosted state flags
+ client->ps.stats[ STAT_STATE ] &= ~SS_BOOSTEDWARNING;
+ if( client->ps.stats[ STAT_STATE ] & SS_BOOSTED )
+ {
+ if( level.time - client->boostedTime >= BOOST_TIME )
+ client->ps.stats[ STAT_STATE ] &= ~SS_BOOSTED;
+ else if( level.time - client->boostedTime >= BOOST_WARN_TIME )
+ client->ps.stats[ STAT_STATE ] |= SS_BOOSTEDWARNING;
+ }
- if( client->ps.stats[ STAT_STATE ] & SS_POISONCLOUDED &&
- client->lastPoisonCloudedTime + LEVEL1_PCLOUD_TIME < level.time )
- client->ps.stats[ STAT_STATE ] &= ~SS_POISONCLOUDED;
+ // Check if poison cloud has worn off
+ if( ( client->ps.eFlags & EF_POISONCLOUDED ) &&
+ BG_PlayerPoisonCloudTime( &client->ps ) - level.time +
+ client->lastPoisonCloudedTime <= 0 )
+ client->ps.eFlags &= ~EF_POISONCLOUDED;
if( client->ps.stats[ STAT_STATE ] & SS_POISONED &&
client->lastPoisonTime + ALIEN_POISON_TIME < level.time )
@@ -1608,13 +1367,13 @@ void ClientThink_real( gentity_t *ent )
BG_UpgradeIsActive( UP_MEDKIT, client->ps.stats ) )
{
//if currently using a medkit or have no need for a medkit now
- if( client->ps.stats[ STAT_STATE ] & SS_MEDKIT_ACTIVE ||
+ if( client->ps.stats[ STAT_STATE ] & SS_HEALING_2X ||
( client->ps.stats[ STAT_HEALTH ] == client->ps.stats[ STAT_MAX_HEALTH ] &&
!( client->ps.stats[ STAT_STATE ] & SS_POISONED ) ) )
{
BG_DeactivateUpgrade( UP_MEDKIT, client->ps.stats );
}
- else if( client->ps.stats[ STAT_HEALTH ] > 0 && !level.paused )
+ else if( client->ps.stats[ STAT_HEALTH ] > 0 )
{
//remove anti toxin
BG_DeactivateUpgrade( UP_MEDKIT, client->ps.stats );
@@ -1623,7 +1382,7 @@ void ClientThink_real( gentity_t *ent )
client->ps.stats[ STAT_STATE ] &= ~SS_POISONED;
client->poisonImmunityTime = level.time + MEDKIT_POISON_IMMUNITY_TIME;
- client->ps.stats[ STAT_STATE ] |= SS_MEDKIT_ACTIVE;
+ client->ps.stats[ STAT_STATE ] |= SS_HEALING_2X;
client->lastMedKitTime = level.time;
client->medKitHealthToRestore =
client->ps.stats[ STAT_MAX_HEALTH ] - client->ps.stats[ STAT_HEALTH ];
@@ -1634,6 +1393,102 @@ void ClientThink_real( gentity_t *ent )
}
}
+ // Replenish alien health
+ if( level.surrenderTeam != client->pers.teamSelection &&
+ ent->nextRegenTime >= 0 && ent->nextRegenTime < level.time )
+ {
+ float regenRate =
+ BG_Class( ent->client->ps.stats[ STAT_CLASS ] )->regenRate;
+
+ if( ent->health <= 0 || ent->nextRegenTime < 0 || regenRate == 0 )
+ ent->nextRegenTime = -1; // no regen
+ else
+ {
+ int entityList[ MAX_GENTITIES ];
+ int i, num;
+ int count, interval;
+ vec3_t range, mins, maxs;
+ float modifier = 1.0f;
+
+ VectorSet( range, REGEN_BOOST_RANGE, REGEN_BOOST_RANGE,
+ REGEN_BOOST_RANGE );
+ VectorAdd( client->ps.origin, range, maxs );
+ VectorSubtract( client->ps.origin, range, mins );
+
+ num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
+ for( i = 0; i < num; i++ )
+ {
+ gentity_t *boost = &g_entities[ entityList[ i ] ];
+
+ if( Distance( client->ps.origin, boost->r.currentOrigin ) > REGEN_BOOST_RANGE )
+ continue;
+
+ if( modifier < BOOSTER_REGEN_MOD && boost->s.eType == ET_BUILDABLE &&
+ boost->s.modelindex == BA_A_BOOSTER && boost->spawned &&
+ boost->health > 0 && boost->powered )
+ {
+ modifier = BOOSTER_REGEN_MOD;
+ continue;
+ }
+
+ if( boost->s.eType == ET_PLAYER && boost->client &&
+ boost->client->pers.teamSelection ==
+ ent->client->pers.teamSelection && boost->health > 0 )
+ {
+ class_t class = boost->client->ps.stats[ STAT_CLASS ];
+ qboolean didBoost = qfalse;
+
+ if( class == PCL_ALIEN_LEVEL1 && modifier < LEVEL1_REGEN_MOD )
+ {
+ modifier = LEVEL1_REGEN_MOD;
+ didBoost = qtrue;
+ }
+ else if( class == PCL_ALIEN_LEVEL1_UPG &&
+ modifier < LEVEL1_UPG_REGEN_MOD )
+ {
+ modifier = LEVEL1_UPG_REGEN_MOD;
+ didBoost = qtrue;
+ }
+
+ if( didBoost && ent->health < client->ps.stats[ STAT_MAX_HEALTH ] )
+ boost->client->pers.hasHealed = qtrue;
+ }
+ }
+
+ // Transmit heal rate to the client so it can be displayed on the HUD
+ client->ps.stats[ STAT_STATE ] |= SS_HEALING_ACTIVE;
+ client->ps.stats[ STAT_STATE ] &= ~( SS_HEALING_2X | SS_HEALING_3X );
+ if( modifier == 1.0f && !G_FindCreep( ent ) )
+ {
+ client->ps.stats[ STAT_STATE ] &= ~SS_HEALING_ACTIVE;
+ modifier *= ALIEN_REGEN_NOCREEP_MOD;
+ }
+ else if( modifier >= 3.0f )
+ client->ps.stats[ STAT_STATE ] |= SS_HEALING_3X;
+ else if( modifier >= 2.0f )
+ client->ps.stats[ STAT_STATE ] |= SS_HEALING_2X;
+
+ interval = 1000 / ( regenRate * modifier );
+ // if recovery interval is less than frametime, compensate
+ count = 1 + ( level.time - ent->nextRegenTime ) / interval;
+ ent->nextRegenTime += count * interval;
+
+ if( ent->health < client->ps.stats[ STAT_MAX_HEALTH ] )
+ {
+ ent->health += count;
+ client->ps.stats[ STAT_HEALTH ] = ent->health;
+
+ // if at max health, clear damage counters
+ if( ent->health >= client->ps.stats[ STAT_MAX_HEALTH ] )
+ {
+ ent->health = client->ps.stats[ STAT_HEALTH ] = client->ps.stats[ STAT_MAX_HEALTH ];
+ for( i = 0; i < MAX_CLIENTS; i++ )
+ ent->credits[ i ] = 0;
+ }
+ }
+ }
+ }
+
if( BG_InventoryContainsUpgrade( UP_GRENADE, client->ps.stats ) &&
BG_UpgradeIsActive( UP_GRENADE, client->ps.stats ) )
{
@@ -1650,10 +1505,11 @@ void ClientThink_real( gentity_t *ent )
}
// set speed
- client->ps.speed = g_speed.value * BG_FindSpeedForClass( client->ps.stats[ STAT_PCLASS ] );
-
- if( client->pers.paused )
- client->ps.speed = 0;
+ if( client->ps.pm_type == PM_NOCLIP )
+ client->ps.speed = client->pers.flySpeed;
+ else
+ client->ps.speed = g_speed.value *
+ BG_Class( client->ps.stats[ STAT_CLASS ] )->speed;
if( client->lastCreepSlowTime + CREEP_TIMEOUT < level.time )
client->ps.stats[ STAT_STATE ] &= ~SS_CREEPSLOWED;
@@ -1669,7 +1525,7 @@ void ClientThink_real( gentity_t *ent )
}
//switch jetpack off if no reactor
- if( !level.reactorPresent )
+ if( !G_Reactor( ) )
BG_DeactivateUpgrade( UP_JETPACK, client->ps.stats );
}
@@ -1678,50 +1534,19 @@ void ClientThink_real( gentity_t *ent )
memset( &pm, 0, sizeof( pm ) );
- if( !( ucmd->buttons & BUTTON_TALK ) && !( client->ps.pm_flags & PMF_RESPAWNED ) )
- {
- switch( client->ps.weapon )
- {
- case WP_ALEVEL0:
- if( client->ps.weaponTime <= 0 )
- pm.autoWeaponHit[ client->ps.weapon ] = CheckVenomAttack( ent );
- break;
-
- case WP_ALEVEL1:
- case WP_ALEVEL1_UPG:
- CheckGrabAttack( ent );
- break;
-
- case WP_ALEVEL3:
- case WP_ALEVEL3_UPG:
- if( client->ps.weaponTime <= 0 )
- pm.autoWeaponHit[ client->ps.weapon ] = CheckPounceAttack( ent );
- break;
-
- default:
- break;
- }
- }
-
if( ent->flags & FL_FORCE_GESTURE )
{
ent->flags &= ~FL_FORCE_GESTURE;
ent->client->pers.cmd.buttons |= BUTTON_GESTURE;
}
+
+ // clear fall velocity before every pmove
+ client->pmext.fallVelocity = 0.0f;
pm.ps = &client->ps;
pm.pmext = &client->pmext;
pm.cmd = *ucmd;
-
- if( pm.ps->pm_type == PM_DEAD )
- pm.tracemask = MASK_PLAYERSOLID; // & ~CONTENTS_BODY;
-
- if( pm.ps->stats[ STAT_STATE ] & SS_INFESTING ||
- pm.ps->stats[ STAT_STATE ] & SS_HOVELING )
- pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
- else
- pm.tracemask = MASK_PLAYERSOLID;
-
+ pm.tracemask = ent->clipmask;
pm.trace = trap_Trace;
pm.pointcontents = trap_PointContents;
pm.debugLevel = g_debugMove.integer;
@@ -1734,8 +1559,7 @@ void ClientThink_real( gentity_t *ent )
// moved from after Pmove -- potentially the cause of
// future triggering bugs
- if( !ent->client->noclip )
- G_TouchTriggers( ent );
+ G_TouchTriggers( ent );
Pmove( &pm );
@@ -1745,13 +1569,61 @@ void ClientThink_real( gentity_t *ent )
if( ent->client->ps.eventSequence != oldEventSequence )
ent->eventTime = level.time;
- if ( level.paused ) client->ps.pm_type = real_pm_type;
-
+ VectorCopy( ent->client->ps.viewangles, ent->r.currentAngles );
if( g_smoothClients.integer )
BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue );
else
BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue );
+ switch( client->ps.weapon )
+ {
+ case WP_ALEVEL0:
+ if( !CheckVenomAttack( ent ) )
+ {
+ client->ps.weaponstate = WEAPON_READY;
+ }
+ else
+ {
+ client->ps.generic1 = WPM_PRIMARY;
+ G_AddEvent( ent, EV_FIRE_WEAPON, 0 );
+ }
+ break;
+
+ case WP_ALEVEL1:
+ case WP_ALEVEL1_UPG:
+ CheckGrabAttack( ent );
+ break;
+
+ case WP_ALEVEL3:
+ case WP_ALEVEL3_UPG:
+ if( !CheckPounceAttack( ent ) )
+ {
+ client->ps.weaponstate = WEAPON_READY;
+ }
+ else
+ {
+ client->ps.generic1 = WPM_SECONDARY;
+ G_AddEvent( ent, EV_FIRE_WEAPON2, 0 );
+ }
+ break;
+
+ case WP_ALEVEL4:
+ // If not currently in a trample, reset the trample bookkeeping data
+ if( !( client->ps.pm_flags & PMF_CHARGE ) && client->trampleBuildablesHitPos )
+ {
+ ent->client->trampleBuildablesHitPos = 0;
+ memset( ent->client->trampleBuildablesHit, 0, sizeof( ent->client->trampleBuildablesHit ) );
+ }
+ break;
+
+ case WP_HBUILD:
+ CheckCkitRepair( ent );
+ break;
+
+ default:
+ break;
+ }
+
SendPendingPredictableEvents( &ent->client->ps );
if( !( ent->client->ps.eFlags & EF_FIRING ) )
@@ -1770,7 +1642,7 @@ void ClientThink_real( gentity_t *ent )
// touch other objects
ClientImpacts( ent, &pm );
-
+
// execute client events
ClientEvents( ent, oldEventSequence );
@@ -1779,12 +1651,12 @@ void ClientThink_real( gentity_t *ent )
// NOTE: now copy the exact origin over otherwise clients can be snapped into solid
VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );
- VectorCopy( ent->client->ps.origin, ent->s.origin );
+ VectorCopy( ent->client->ps.origin, ent->s.pos.trBase );
// save results of triggers and client events
if( ent->client->ps.eventSequence != oldEventSequence )
ent->eventTime = level.time;
-
+
// Don't think anymore if dead
if( client->ps.stats[ STAT_HEALTH ] <= 0 )
return;
@@ -1794,121 +1666,84 @@ void ClientThink_real( gentity_t *ent )
client->buttons = ucmd->buttons;
client->latched_buttons |= client->buttons & ~client->oldbuttons;
- if( ( client->buttons & BUTTON_GETFLAG ) && !( client->oldbuttons & BUTTON_GETFLAG ) &&
+ if( ( client->buttons & BUTTON_USE_EVOLVE ) && !( client->oldbuttons & BUTTON_USE_EVOLVE ) &&
client->ps.stats[ STAT_HEALTH ] > 0 )
{
trace_t trace;
vec3_t view, point;
gentity_t *traceEnt;
- if( client->ps.stats[ STAT_STATE ] & SS_HOVELING )
- {
- gentity_t *hovel = client->hovel;
+#define USE_OBJECT_RANGE 64
- //only let the player out if there is room
- if( !AHovel_Blocked( hovel, ent, qtrue ) )
- {
- //prevent lerping
- client->ps.eFlags ^= EF_TELEPORT_BIT;
- client->ps.eFlags &= ~EF_NODRAW;
- G_UnlaggedClear( ent );
+ int entityList[ MAX_GENTITIES ];
+ vec3_t range = { USE_OBJECT_RANGE, USE_OBJECT_RANGE, USE_OBJECT_RANGE };
+ vec3_t mins, maxs;
+ int i, num;
- //client leaves hovel
- client->ps.stats[ STAT_STATE ] &= ~SS_HOVELING;
+ // look for object infront of player
+ AngleVectors( client->ps.viewangles, view, NULL, NULL );
+ VectorMA( client->ps.origin, USE_OBJECT_RANGE, view, point );
+ trap_Trace( &trace, client->ps.origin, NULL, NULL, point, ent->s.number, MASK_SHOT );
- //hovel is empty
- G_SetBuildableAnim( hovel, BANIM_ATTACK2, qfalse );
- hovel->active = qfalse;
- }
- else
- {
- //exit is blocked
- G_TriggerMenu( ent->client->ps.clientNum, MN_A_HOVEL_BLOCKED );
- }
- }
+ traceEnt = &g_entities[ trace.entityNum ];
+
+ if( traceEnt && traceEnt->buildableTeam == client->ps.stats[ STAT_TEAM ] && traceEnt->use )
+ traceEnt->use( traceEnt, ent, ent ); //other and activator are the same in this context
else
{
-#define USE_OBJECT_RANGE 64
-
- int entityList[ MAX_GENTITIES ];
- vec3_t range = { USE_OBJECT_RANGE, USE_OBJECT_RANGE, USE_OBJECT_RANGE };
- vec3_t mins, maxs;
- int i, num;
+ //no entity in front of player - do a small area search
- //TA: look for object infront of player
- AngleVectors( client->ps.viewangles, view, NULL, NULL );
- VectorMA( client->ps.origin, USE_OBJECT_RANGE, view, point );
- trap_Trace( &trace, client->ps.origin, NULL, NULL, point, ent->s.number, MASK_SHOT );
-
- traceEnt = &g_entities[ trace.entityNum ];
+ VectorAdd( client->ps.origin, range, maxs );
+ VectorSubtract( client->ps.origin, range, mins );
- if( traceEnt && traceEnt->biteam == client->ps.stats[ STAT_PTEAM ] && traceEnt->use )
- traceEnt->use( traceEnt, ent, ent ); //other and activator are the same in this context
- else
+ num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
+ for( i = 0; i < num; i++ )
{
- //no entity in front of player - do a small area search
-
- VectorAdd( client->ps.origin, range, maxs );
- VectorSubtract( client->ps.origin, range, mins );
+ traceEnt = &g_entities[ entityList[ i ] ];
- num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
- for( i = 0; i < num; i++ )
+ if( traceEnt && traceEnt->buildableTeam == client->ps.stats[ STAT_TEAM ] && traceEnt->use )
{
- traceEnt = &g_entities[ entityList[ i ] ];
-
- if( traceEnt && traceEnt->biteam == client->ps.stats[ STAT_PTEAM ] && traceEnt->use )
- {
- traceEnt->use( traceEnt, ent, ent ); //other and activator are the same in this context
- break;
- }
+ traceEnt->use( traceEnt, ent, ent ); //other and activator are the same in this context
+ break;
}
+ }
- if( i == num && client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
+ if( i == num && client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
+ {
+ if( BG_AlienCanEvolve( client->ps.stats[ STAT_CLASS ],
+ client->pers.credit,
+ g_alienStage.integer ) )
{
- if( BG_UpgradeClassAvailable( &client->ps ) )
- {
- //no nearby objects and alien - show class menu
- G_TriggerMenu( ent->client->ps.clientNum, MN_A_INFEST );
- }
- else
- {
- //flash frags
- G_AddEvent( ent, EV_ALIEN_EVOLVE_FAILED, 0 );
- }
+ //no nearby objects and alien - show class menu
+ G_TriggerMenu( ent->client->ps.clientNum, MN_A_INFEST );
+ }
+ else
+ {
+ //flash frags
+ G_AddEvent( ent, EV_ALIEN_EVOLVE_FAILED, 0 );
}
}
}
}
- if( level.framenum > client->retriggerArmouryMenu && client->retriggerArmouryMenu )
- {
- G_TriggerMenu( client->ps.clientNum, MN_H_ARMOURY );
-
- client->retriggerArmouryMenu = 0;
- }
+ client->ps.persistant[ PERS_BP ] = G_GetBuildPoints( client->ps.origin,
+ client->ps.stats[ STAT_TEAM ] );
+ client->ps.persistant[ PERS_MARKEDBP ] = G_GetMarkedBuildPoints( client->ps.origin,
+ client->ps.stats[ STAT_TEAM ] );
- // Give clients some credit periodically
- ClientGradualFunds( ent );
+ if( client->ps.persistant[ PERS_BP ] < 0 )
+ client->ps.persistant[ PERS_BP ] = 0;
// perform once-a-second actions
ClientTimerActions( ent, msec );
-
+
if( ent->suicideTime > 0 && ent->suicideTime < level.time )
{
- ent->flags &= ~FL_GODMODE;
ent->client->ps.stats[ STAT_HEALTH ] = ent->health = 0;
player_die( ent, ent, ent, 100000, MOD_SUICIDE );
ent->suicideTime = 0;
}
- if( client->pers.bubbleTime && client->pers.bubbleTime < level.time )
- {
- gentity_t *bubble;
-
- client->pers.bubbleTime = level.time + 500;
- bubble = G_TempEntity( client->ps.origin, EV_PLAYER_TELEPORT_OUT );
- bubble->s.clientNum = ent->s.clientNum;
- }
}
/*
@@ -1953,52 +1788,30 @@ SpectatorClientEndFrame
void SpectatorClientEndFrame( gentity_t *ent )
{
gclient_t *cl;
- int clientNum, flags;
+ int clientNum;
int score, ping;
- vec3_t spawn_origin, spawn_angles;
// if we are doing a chase cam or a remote view, grab the latest info
if( ent->client->sess.spectatorState == SPECTATOR_FOLLOW )
{
clientNum = ent->client->sess.spectatorClient;
-
- if( clientNum >= 0 )
+ if( clientNum >= 0 && clientNum < level.maxclients )
{
cl = &level.clients[ clientNum ];
-
if( cl->pers.connected == CON_CONNECTED )
{
-
- if( cl -> sess.spectatorState != SPECTATOR_FOLLOW )
- {
- flags = ( cl->ps.eFlags & ~( EF_VOTED | EF_TEAMVOTED ) ) |
- ( ent->client->ps.eFlags & ( EF_VOTED | EF_TEAMVOTED ) );
- score = ent->client->ps.persistant[ PERS_SCORE ];
- ping = ent->client->ps.ping;
- ent->client->ps = cl->ps;
- ent->client->ps.persistant[ PERS_SCORE ] = score;
- ent->client->ps.ping = ping;
- ent->client->ps.eFlags = flags;
- ent->client->ps.pm_flags |= PMF_FOLLOW;
- ent->client->ps.pm_flags &= ~PMF_QUEUED;
- }
- else //we are stickyspec-spectating someone who is spectating someone else
- {
- ent->client->ps.clientNum = (g_entities + clientNum)->s.number;
- ent->client->ps.commandTime = cl->ps.commandTime;
- ent->client->ps.weapon = 0;
- ent->client->ps.pm_flags |= PMF_FOLLOW;
- ent->client->ps.stats[ STAT_PCLASS ] = PCL_NONE;
-
- if( cl->pers.teamSelection == PTE_ALIENS )
- G_SelectAlienLockSpawnPoint( spawn_origin, spawn_angles );
- else if( cl->pers.teamSelection == PTE_HUMANS )
- G_SelectHumanLockSpawnPoint( spawn_origin, spawn_angles );
-
- G_SetOrigin( ent, spawn_origin );
- VectorCopy( spawn_origin, ent->client->ps.origin );
- G_SetClientViewAngle( ent, spawn_angles );
- }
+ score = ent->client->ps.persistant[ PERS_SCORE ];
+ ping = ent->client->ps.ping;
+
+ // Copy
+ ent->client->ps = cl->ps;
+
+ // Restore
+ ent->client->ps.persistant[ PERS_SCORE ] = score;
+ ent->client->ps.ping = ping;
+
+ ent->client->ps.pm_flags |= PMF_FOLLOW;
+ ent->client->ps.pm_flags &= ~PMF_QUEUED;
}
}
}
@@ -2015,20 +1828,12 @@ while a slow client may have multiple ClientEndFrame between ClientThink.
*/
void ClientEndFrame( gentity_t *ent )
{
- clientPersistant_t *pers;
-
- if( ent->client->sess.sessionTeam == TEAM_SPECTATOR )
+ if( ent->client->sess.spectatorState != SPECTATOR_NOT )
{
SpectatorClientEndFrame( ent );
return;
}
- pers = &ent->client->pers;
-
- // save a copy of certain playerState values in case of SPECTATOR_FOLLOW
- pers->score = ent->client->ps.persistant[ PERS_SCORE ];
- pers->credit = ent->client->ps.persistant[ PERS_CREDIT ];
-
//
// If the end of unit layout is displayed, don't give
// the player any normal movement attributes
@@ -2048,8 +1853,6 @@ void ClientEndFrame( gentity_t *ent )
else
ent->s.eFlags &= ~EF_CONNECTION;
- ent->client->ps.stats[ STAT_HEALTH ] = ent->health; // FIXME: get rid of ent->health...
-
// respawn if dead
if( ent->client->ps.stats[ STAT_HEALTH ] <= 0 && level.time >= ent->client->respawnTime )
respawn( ent );
@@ -2064,5 +1867,3 @@ void ClientEndFrame( gentity_t *ent )
SendPendingPredictableEvents( &ent->client->ps );
}
-
-