2011-02-18 14:31:32 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Copyright ( C ) 1999 - 2005 Id Software , Inc .
Copyright ( C ) 2002 - 2009 Q3Rally Team ( Per Thormann - perle @ q3rally . com )
This file is part of q3rally source code .
q3rally source code 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 ,
or ( at your option ) any later version .
q3rally source code is distributed in the hope that it will be
useful , but WITHOUT ANY WARRANTY ; without even the implied warranty of
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 q3rally ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2011-03-08 09:07:05 +00:00
//
2011-02-18 14:31:32 +00:00
# include "g_local.h"
// STONELANCE
/*
= = = = = = = = = = = = = = = = =
Com_LogPrintf
Print to the logfile
= = = = = = = = = = = = = = = = =
*/
2011-07-26 08:52:24 +00:00
static __attribute__ ( ( format ( printf , 1 , 2 ) ) ) void QDECL Com_LogPrintf ( const char * fmt , . . . ) {
2011-02-18 14:31:32 +00:00
va_list argptr ;
char string [ 1024 ] ;
fileHandle_t logFile ;
trap_FS_FOpenFile ( " g_physics.log " , & logFile , FS_APPEND ) ;
va_start ( argptr , fmt ) ;
Q_vsnprintf ( string , sizeof ( string ) , fmt , argptr ) ;
va_end ( argptr ) ;
trap_FS_Write ( string , strlen ( string ) , logFile ) ;
trap_FS_FCloseFile ( logFile ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
G_DebugDynamics
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
void G_DebugDynamics ( carBody_t * body , carPoint_t * points , int i ) {
Com_LogPrintf ( " \n " ) ;
Com_LogPrintf ( " PM_DebugDynamics: point ORIGIN - %.3f, %.3f, %.3f \n " , points [ i ] . r [ 0 ] , points [ i ] . r [ 1 ] , points [ i ] . r [ 2 ] ) ;
Com_LogPrintf ( " PM_DebugDynamics: point VELOCITY - %.3f, %.3f, %.3f \n " , points [ i ] . v [ 0 ] , points [ i ] . v [ 1 ] , points [ i ] . v [ 2 ] ) ;
Com_LogPrintf ( " PM_DebugDynamics: point ONGROUND - %i \n " , points [ i ] . onGround ) ;
Com_LogPrintf ( " PM_DebugDynamics: point NORMAL 1- %.3f, %.3f, %.3f \n " , points [ i ] . normals [ 0 ] [ 0 ] , points [ i ] . normals [ 0 ] [ 1 ] , points [ i ] . normals [ 0 ] [ 2 ] ) ;
Com_LogPrintf ( " PM_DebugDynamics: point NORMAL 2- %.3f, %.3f, %.3f \n " , points [ i ] . normals [ 1 ] [ 0 ] , points [ i ] . normals [ 1 ] [ 1 ] , points [ i ] . normals [ 1 ] [ 2 ] ) ;
Com_LogPrintf ( " PM_DebugDynamics: point NORMAL 3- %.3f, %.3f, %.3f \n " , points [ i ] . normals [ 2 ] [ 0 ] , points [ i ] . normals [ 2 ] [ 1 ] , points [ i ] . normals [ 2 ] [ 2 ] ) ;
// Com_LogPrintf("PM_DebugDynamics: point MASS - %.3f\n", points[pm->pDebug-1].mass);
Com_LogPrintf ( " PM_DebugDynamics: body ORIGIN - %.3f, %.3f, %.3f \n " , body - > r [ 0 ] , body - > r [ 1 ] , body - > r [ 2 ] ) ;
Com_LogPrintf ( " PM_DebugDynamics: body VELOCITY - %.3f, %.3f, %.3f \n " , body - > v [ 0 ] , body - > v [ 1 ] , body - > v [ 2 ] ) ;
Com_LogPrintf ( " PM_DebugDynamics: body ANG VELOCITY - %.3f, %.3f, %.3f \n " , body - > w [ 0 ] , body - > w [ 1 ] , body - > w [ 2 ] ) ;
// Com_LogPrintf("PM_DebugDynamics: body COM - %.3f, %.3f, %.3f\n", body->CoM[0], body->CoM[1], body->CoM[2]);
// Com_LogPrintf("PM_DebugDynamics: body MASS - %.3f\n", body->mass);
Com_LogPrintf ( " Direction vectors ---------------------------------------- \n " ) ;
Com_LogPrintf ( " PM_DebugDynamics: body FORWARD - %.3f, %.3f, %.3f \n " , body - > forward [ 0 ] , body - > forward [ 1 ] , body - > forward [ 2 ] ) ;
Com_LogPrintf ( " PM_DebugDynamics: body RIGHT - %.3f, %.3f, %.3f \n " , body - > right [ 0 ] , body - > right [ 1 ] , body - > right [ 2 ] ) ;
Com_LogPrintf ( " PM_DebugDynamics: body UP - %.3f, %.3f, %.3f \n " , body - > up [ 0 ] , body - > up [ 1 ] , body - > up [ 2 ] ) ;
Com_LogPrintf ( " \n " ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
G_DebugForces
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
void G_DebugForces ( carBody_t * body , carPoint_t * points , int i ) {
Com_LogPrintf ( " \n " ) ;
Com_LogPrintf ( " PM_DebugForces: point GRAVITY - %.3f, %.3f, %.3f \n " , points [ i ] . forces [ GRAVITY ] [ 0 ] , points [ i ] . forces [ GRAVITY ] [ 1 ] , points [ i ] . forces [ GRAVITY ] [ 2 ] ) ;
Com_LogPrintf ( " PM_DebugForces: point NORMAL - %.3f, %.3f, %.3f \n " , points [ i ] . forces [ NORMAL ] [ 0 ] , points [ i ] . forces [ NORMAL ] [ 1 ] , points [ i ] . forces [ NORMAL ] [ 2 ] ) ;
Com_LogPrintf ( " PM_DebugForces: point SHOCK - %.3f, %.3f, %.3f \n " , points [ i ] . forces [ SHOCK ] [ 0 ] , points [ i ] . forces [ SHOCK ] [ 1 ] , points [ i ] . forces [ SHOCK ] [ 2 ] ) ;
Com_LogPrintf ( " PM_DebugForces: point SPRING - %.3f, %.3f, %.3f \n " , points [ i ] . forces [ SPRING ] [ 0 ] , points [ i ] . forces [ SPRING ] [ 1 ] , points [ i ] . forces [ SPRING ] [ 2 ] ) ;
Com_LogPrintf ( " PM_DebugForces: point SWAY_BAR - %.3f, %.3f, %.3f \n " , points [ i ] . forces [ SWAY_BAR ] [ 0 ] , points [ i ] . forces [ SWAY_BAR ] [ 1 ] , points [ i ] . forces [ SWAY_BAR ] [ 2 ] ) ;
Com_LogPrintf ( " PM_DebugForces: point ROAD - %.3f, %.3f, %.3f \n " , points [ i ] . forces [ ROAD ] [ 0 ] , points [ i ] . forces [ ROAD ] [ 1 ] , points [ i ] . forces [ ROAD ] [ 2 ] ) ;
Com_LogPrintf ( " PM_DebugForces: point INTERNAL - %.3f, %.3f, %.3f \n " , points [ i ] . forces [ INTERNAL ] [ 0 ] , points [ i ] . forces [ INTERNAL ] [ 1 ] , points [ i ] . forces [ INTERNAL ] [ 2 ] ) ;
Com_LogPrintf ( " PM_DebugForces: point AIR_FRICTION - %.3f, %.3f, %.3f \n " , points [ i ] . forces [ AIR_FRICTION ] [ 0 ] , points [ i ] . forces [ AIR_FRICTION ] [ 1 ] , points [ i ] . forces [ AIR_FRICTION ] [ 2 ] ) ;
Com_LogPrintf ( " PM_DebugForces: point NETFORCE - %.3f, %.3f, %.3f \n " , points [ i ] . netForce [ 0 ] , points [ i ] . netForce [ 1 ] , points [ i ] . netForce [ 2 ] ) ;
Com_LogPrintf ( " PM_DebugForces: point fluidDensity - %.6f \n " , points [ i ] . fluidDensity ) ;
Com_LogPrintf ( " PM_DebugForces: body netForce - %.3f, %.3f, %.3f \n " , body - > netForce [ 0 ] , body - > netForce [ 1 ] , body - > netForce [ 2 ] ) ;
Com_LogPrintf ( " PM_DebugForces: body netMoment - %.3f, %.3f, %.3f \n " , body - > netMoment [ 0 ] , body - > netMoment [ 1 ] , body - > netMoment [ 2 ] ) ;
Com_LogPrintf ( " \n " ) ;
}
// END
/*
= = = = = = = = = = = = = = =
G_DamageFeedback
Called just before a snapshot is sent to the given player .
Totals up all damage and generates both the player_state_t
damage values to that client for pain blends and kicks , and
global pain sound events for all clients .
= = = = = = = = = = = = = = =
*/
void P_DamageFeedback ( gentity_t * player ) {
gclient_t * client ;
float count ;
// STONELANCE
// vec3_t angles;
// END
client = player - > client ;
if ( client - > ps . pm_type = = PM_DEAD ) {
return ;
}
// total points of damage shot at the player this frame
count = client - > damage_blood + client - > damage_armor ;
if ( count = = 0 ) {
return ; // didn't take any damage
}
if ( count > 255 ) {
count = 255 ;
}
// send the information to the client
// world damage (falling, slime, etc) uses a special code
// to make the blend blob centered instead of positional
// STONELANCE
/*
if ( client - > damage_fromWorld ) {
client - > ps . damagePitch = 255 ;
client - > ps . damageYaw = 255 ;
client - > damage_fromWorld = qfalse ;
} else {
vectoangles ( client - > damage_from , angles ) ;
client - > ps . damagePitch = angles [ PITCH ] / 360.0 * 256 ;
client - > ps . damageYaw = angles [ YAW ] / 360.0 * 256 ;
}
*/
// END
// play an apropriate pain sound
if ( ( level . time > player - > pain_debounce_time ) & & ! ( player - > flags & FL_GODMODE ) ) {
player - > pain_debounce_time = level . time + 700 ;
G_AddEvent ( player , EV_PAIN , player - > health ) ;
// STONELANCE
// client->ps.damageEvent++;
// END
}
// STONELANCE
// client->ps.damageCount = count;
// END
//
// clear totals
//
client - > damage_blood = 0 ;
client - > damage_armor = 0 ;
client - > damage_knockback = 0 ;
}
/*
= = = = = = = = = = = = =
P_WorldEffects
Check for lava / slime contents and drowning
= = = = = = = = = = = = =
*/
void P_WorldEffects ( gentity_t * ent ) {
qboolean envirosuit ;
int waterlevel ;
if ( ent - > client - > noclip ) {
ent - > client - > airOutTime = level . time + 12000 ; // don't need air
return ;
}
waterlevel = ent - > waterlevel ;
envirosuit = ent - > client - > ps . powerups [ PW_BATTLESUIT ] > level . time ;
//
// check for drowning
//
if ( waterlevel = = 3 ) {
// envirosuit give air
// STONELANCE envirosuit doesnt help a car
/*
if ( envirosuit ) {
ent - > client - > airOutTime = level . time + 10000 ;
}
*/
// END
// if out of air, start drowning
if ( ent - > client - > airOutTime < level . time ) {
// drown!
// STONELANCE - damage a lot fast for a car
// ent->client->airOutTime += 1000;
ent - > client - > airOutTime + = 200 ;
// END
if ( ent - > health > 0 ) {
// take more damage the longer underwater
ent - > damage + = 2 ;
if ( ent - > damage > 15 )
ent - > damage = 15 ;
// play a gurp sound instead of a normal pain sound
2011-08-07 03:56:14 +00:00
// if (ent->health <= ent->damage) {
2011-02-18 14:31:32 +00:00
// STONELANCE
// G_Sound(ent, CHAN_VOICE, G_SoundIndex("*drown.wav"));
2011-08-06 22:44:15 +00:00
// G_Sound(ent, CHAN_VOICE, G_SoundIndex("sound/rally/car/drown.wav"));
2011-02-18 14:31:32 +00:00
// END
2011-08-06 22:44:15 +00:00
// } else if (rand()&1) {
// G_Sound(ent, CHAN_VOICE, G_SoundIndex("sound/player/gurp1.wav"));
// } else {
// G_Sound(ent, CHAN_VOICE, G_SoundIndex("sound/player/gurp2.wav"));
// }
2011-02-18 14:31:32 +00:00
// don't play a normal pain sound
ent - > pain_debounce_time = level . time + 200 ;
G_Damage ( ent , NULL , NULL , NULL , NULL ,
ent - > damage , DAMAGE_NO_ARMOR , MOD_WATER ) ;
}
}
} else {
// STONELANCE
// ent->client->airOutTime = level.time + 12000;
ent - > client - > airOutTime = level . time + 200 ;
ent - > damage = 2 ;
// END
}
//
// check for sizzle damage (move to pmove?)
//
if ( waterlevel & &
( ent - > watertype & ( CONTENTS_LAVA | CONTENTS_SLIME ) ) ) {
if ( ent - > health > 0
& & ent - > pain_debounce_time < = level . time ) {
if ( envirosuit ) {
G_AddEvent ( ent , EV_POWERUP_BATTLESUIT , 0 ) ;
} else {
if ( ent - > watertype & CONTENTS_LAVA ) {
G_Damage ( ent , NULL , NULL , NULL , NULL ,
30 * waterlevel , 0 , MOD_LAVA ) ;
}
if ( ent - > watertype & CONTENTS_SLIME ) {
G_Damage ( ent , NULL , NULL , NULL , NULL ,
10 * waterlevel , 0 , MOD_SLIME ) ;
}
}
}
}
}
/*
= = = = = = = = = = = = = = =
G_SetClientSound
= = = = = = = = = = = = = = =
*/
void G_SetClientSound ( gentity_t * ent ) {
# ifdef MISSIONPACK
if ( ent - > s . eFlags & EF_TICKING ) {
ent - > client - > ps . loopSound = G_SoundIndex ( " sound/weapons/proxmine/wstbtick.wav " ) ;
}
else
# endif
if ( ent - > waterlevel & & ( ent - > watertype & ( CONTENTS_LAVA | CONTENTS_SLIME ) ) ) {
ent - > client - > ps . loopSound = level . snd_fry ;
} else {
ent - > client - > ps . loopSound = 0 ;
}
}
//==============================================================
/*
= = = = = = = = = = = = = =
ClientImpacts
= = = = = = = = = = = = = =
*/
void ClientImpacts ( gentity_t * ent , pmove_t * pm ) {
int i , j ;
trace_t trace ;
gentity_t * other ;
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
}
2011-03-08 09:12:02 +00:00
other = & g_entities [ pm - > touchents [ i ] ] ;
// STONELANCE
2011-02-18 14:31:32 +00:00
VectorSubtract ( other - > s . origin , pm - > touchPos [ i ] , trace . plane . normal ) ;
VectorNormalize ( trace . plane . normal ) ;
VectorCopy ( pm - > touchPos [ i ] , trace . endpos ) ;
// END
if ( ( ent - > r . svFlags & SVF_BOT ) & & ( ent - > touch ) ) {
ent - > touch ( ent , other , & trace ) ;
}
if ( ! other - > touch ) {
continue ;
}
other - > touch ( other , ent , & trace ) ;
}
}
/*
int entitiesInTracedBox ( const vec3_t mins , const vec3_t maxs , const vec3_t start , const vec3_t end , int * list , int maxcount )
{
int num ;
int ents [ MAX_GENTITIES ] ;
int numInMovingBox ;
vec3_t curMins ;
vec3_t curMaxs ;
vecCopy ( mins , curMins ) ;
vecCopy ( maxs , curMaxs ) ;
num = trap_EntitiesInBox ( curMins , curMaxs , ents , MAX_GENTITIES ) ;
}
*/
/*
= = = = = = = = = = = =
G_TouchTriggers
Find all trigger entities that ent ' s current position touches .
Spectators will only interact with teleporters .
= = = = = = = = = = = =
*/
void G_TouchTriggers ( gentity_t * ent ) {
int i , num ;
int touch [ MAX_GENTITIES ] ;
gentity_t * hit ;
trace_t trace ;
vec3_t mins , maxs ;
2011-03-08 09:07:05 +00:00
static vec3_t range = { 40 , 40 , 52 } ;
2011-02-18 14:31:32 +00:00
if ( ! ent - > client ) {
return ;
}
// dead clients don't activate triggers!
if ( ent - > client - > ps . stats [ STAT_HEALTH ] < = 0 ) {
return ;
}
VectorSubtract ( ent - > client - > ps . origin , range , mins ) ;
VectorAdd ( ent - > client - > ps . origin , range , maxs ) ;
// STONELANCE
AddPointToBounds ( ent - > client - > car . tBody . r , mins , maxs ) ;
// END
num = trap_EntitiesInBox ( mins , maxs , touch , MAX_GENTITIES ) ;
// can't use ent->absmin, because that has a one unit pad
VectorAdd ( ent - > client - > ps . origin , ent - > r . mins , mins ) ;
VectorAdd ( ent - > client - > ps . origin , ent - > r . maxs , maxs ) ;
for ( i = 0 ; i < num ; i + + ) {
hit = & g_entities [ touch [ i ] ] ;
if ( ! hit - > touch & & ! ent - > touch ) {
continue ;
}
if ( ! ( hit - > r . contents & CONTENTS_TRIGGER ) ) {
continue ;
}
// ignore most entities if a spectator
// STONELANCE
// if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
if ( ent - > client - > sess . sessionTeam = = TEAM_SPECTATOR
| | isRaceObserver ( ent - > s . number ) ) {
// END
if ( hit - > s . eType ! = ET_TELEPORT_TRIGGER & &
// this is ugly but adding a new ET_? type will
// most likely cause network incompatibilities
hit - > touch ! = Touch_DoorTrigger ) {
continue ;
}
}
// use seperate code for determining if an item is picked up
// so you don't have to actually contact its bounding box
if ( hit - > s . eType = = ET_ITEM ) {
if ( ! BG_PlayerTouchesItem ( & ent - > client - > ps , & hit - > s , level . time ) ) {
continue ;
}
} else {
if ( ! trap_EntityContact ( mins , maxs , hit ) ) {
continue ;
}
}
memset ( & trace , 0 , sizeof ( trace ) ) ;
if ( hit - > touch ) {
hit - > touch ( hit , ent , & trace ) ;
}
if ( ( ent - > r . svFlags & SVF_BOT ) & & ( ent - > touch ) ) {
ent - > touch ( ent , hit , & trace ) ;
}
}
// if we didn't touch a jump pad this pmove frame
if ( ent - > client - > ps . jumppad_frame ! = ent - > client - > ps . pmove_framecount ) {
ent - > client - > ps . jumppad_frame = 0 ;
ent - > client - > ps . jumppad_ent = 0 ;
}
}
/*
= = = = = = = = = = = = = = = = =
SpectatorThink
= = = = = = = = = = = = = = = = =
*/
void SpectatorThink ( gentity_t * ent , usercmd_t * ucmd ) {
pmove_t pm ;
gclient_t * client ;
client = ent - > client ;
// STONELANCE
// if ( client->sess.spectatorState != SPECTATOR_FOLLOW ) {
if ( client - > sess . spectatorState = = SPECTATOR_FREE ) {
// END
client - > ps . pm_type = PM_SPECTATOR ;
// STONELANCE
// client->ps.speed = 400; // faster than normal
client - > ps . speed = 800 ; // faster than normal
// END
// set up for pmove
memset ( & pm , 0 , sizeof ( pm ) ) ;
pm . ps = & client - > ps ;
pm . cmd = * ucmd ;
pm . tracemask = MASK_PLAYERSOLID & ~ CONTENTS_BODY ; // spectators can fly through bodies
pm . trace = trap_Trace ;
pm . pointcontents = trap_PointContents ;
// perform a pmove
Pmove ( & pm ) ;
// save results of pmove
VectorCopy ( client - > ps . origin , ent - > s . origin ) ;
G_TouchTriggers ( ent ) ;
trap_UnlinkEntity ( ent ) ;
}
// STONELANCE
if ( client - > sess . spectatorState = = SPECTATOR_OBSERVE )
{
client - > ps . commandTime = ucmd - > serverTime ;
UpdateObserverSpot ( ent , qfalse ) ;
}
// END
client - > oldbuttons = client - > buttons ;
client - > buttons = ucmd - > buttons ;
// attack button cycles through spectators
// STONELANCE
// if ( ( client->buttons & BUTTON_ATTACK ) && ! ( client->oldbuttons & BUTTON_ATTACK ) ) {
if ( ( client - > buttons & BUTTON_ATTACK ) & & ! ( client - > oldbuttons & BUTTON_ATTACK )
& & ! ( ent - > r . svFlags & SVF_BOT ) ) {
// END
Cmd_FollowCycle_f ( ent , 1 ) ;
}
// STONELANCE
if ( ( client - > buttons & BUTTON_REARATTACK ) & & ! ( client - > oldbuttons & BUTTON_REARATTACK ) ) {
int newState ;
vec3_t origin , angles ;
int clientNum ;
if ( client - > sess . spectatorState = = SPECTATOR_FREE )
newState = SPECTATOR_OBSERVE ;
else
newState = client - > sess . spectatorState + 1 ;
switch ( newState ) {
default :
case SPECTATOR_FOLLOW :
trap_SendServerCommand ( ent - g_entities , " print \" Spectator Mode: Follow \n \" " ) ;
client - > sess . spectatorState = SPECTATOR_FOLLOW ;
break ;
case SPECTATOR_OBSERVE :
trap_SendServerCommand ( ent - g_entities , " print \" Spectator Mode: Observe \n \" " ) ;
StopFollowing ( ent ) ;
clientNum = ent - > client - > sess . spectatorClient ;
// team follow1 and team follow2 go to whatever clients are playing
if ( clientNum = = - 1 ) {
clientNum = level . follow1 ;
} else if ( clientNum = = - 2 ) {
clientNum = level . follow2 ;
}
if ( clientNum < 0 )
Cmd_FollowCycle_f ( ent , 1 ) ;
if ( clientNum < 0 )
break ;
client - > sess . spectatorState = SPECTATOR_OBSERVE ;
// ent->s.eType = ET_INVISIBLE;
if ( FindBestObserverSpot ( ent , & g_entities [ client - > sess . spectatorClient ] , origin , angles ) )
{
G_SetOrigin ( ent , origin ) ;
VectorCopy ( origin , ent - > client - > ps . origin ) ;
VectorCopy ( angles , ent - > client - > ps . viewangles ) ;
}
else
client - > sess . spectatorState = SPECTATOR_FOLLOW ;
break ;
}
}
// END
}
/*
= = = = = = = = = = = = = = = = =
ClientInactivityTimer
Returns qfalse if the client is dropped
= = = = = = = = = = = = = = = = =
*/
qboolean ClientInactivityTimer ( gclient_t * client ) {
if ( ! g_inactivity . integer ) {
// give everyone some time, so if the operator sets g_inactivity during
// gameplay, everyone isn't kicked
client - > inactivityTime = level . time + 60 * 1000 ;
client - > inactivityWarning = qfalse ;
} else if ( client - > pers . cmd . forwardmove | |
client - > pers . cmd . rightmove | |
client - > pers . cmd . upmove | |
( client - > pers . cmd . buttons & BUTTON_ATTACK ) ) {
client - > inactivityTime = level . time + g_inactivity . integer * 1000 ;
client - > inactivityWarning = qfalse ;
} else if ( ! client - > pers . localClient ) {
if ( level . time > client - > inactivityTime ) {
trap_DropClient ( client - level . clients , " Dropped due to inactivity " ) ;
return qfalse ;
}
if ( level . time > client - > inactivityTime - 10000 & & ! client - > inactivityWarning ) {
client - > inactivityWarning = qtrue ;
trap_SendServerCommand ( client - level . clients , " cp \" Ten seconds until inactivity drop! \n \" " ) ;
}
}
return qtrue ;
}
/*
= = = = = = = = = = = = = = = = = =
ClientTimerActions
Actions that happen once a second
= = = = = = = = = = = = = = = = = =
*/
void ClientTimerActions ( gentity_t * ent , int msec ) {
gclient_t * client ;
# ifdef MISSIONPACK
int maxHealth ;
# endif
client = ent - > client ;
client - > timeResidual + = msec ;
while ( client - > timeResidual > = 1000 ) {
client - > timeResidual - = 1000 ;
// regenerate
# ifdef MISSIONPACK
if ( bg_itemlist [ client - > ps . stats [ STAT_PERSISTANT_POWERUP ] ] . giTag = = PW_GUARD ) {
maxHealth = client - > ps . stats [ STAT_MAX_HEALTH ] / 2 ;
}
else if ( client - > ps . powerups [ PW_REGEN ] ) {
maxHealth = client - > ps . stats [ STAT_MAX_HEALTH ] ;
}
else {
maxHealth = 0 ;
}
if ( maxHealth ) {
if ( ent - > health < maxHealth ) {
ent - > health + = 15 ;
if ( ent - > health > maxHealth * 1.1 ) {
ent - > health = maxHealth * 1.1 ;
}
G_AddEvent ( ent , EV_POWERUP_REGEN , 0 ) ;
} else if ( ent - > health < maxHealth * 2 ) {
ent - > health + = 5 ;
if ( ent - > health > maxHealth * 2 ) {
ent - > health = maxHealth * 2 ;
}
G_AddEvent ( ent , EV_POWERUP_REGEN , 0 ) ;
}
# else
if ( client - > ps . powerups [ PW_REGEN ] ) {
if ( ent - > health < client - > ps . stats [ STAT_MAX_HEALTH ] ) {
ent - > health + = 15 ;
if ( ent - > health > client - > ps . stats [ STAT_MAX_HEALTH ] * 1.1 ) {
ent - > health = client - > ps . stats [ STAT_MAX_HEALTH ] * 1.1 ;
}
G_AddEvent ( ent , EV_POWERUP_REGEN , 0 ) ;
} else if ( ent - > health < client - > ps . stats [ STAT_MAX_HEALTH ] * 2 ) {
ent - > health + = 5 ;
if ( ent - > health > client - > ps . stats [ STAT_MAX_HEALTH ] * 2 ) {
ent - > health = client - > ps . stats [ STAT_MAX_HEALTH ] * 2 ;
}
G_AddEvent ( ent , EV_POWERUP_REGEN , 0 ) ;
}
# endif
} else {
// count down health when over max
// STONELANCE
// if ( ent->health > client->ps.stats[STAT_MAX_HEALTH] ) {
if ( ( ( ! isRallyRace ( ) & & ! g_gametype . integer = = GT_DERBY )
| | level . startRaceTime ) & & ent - > health > client - > ps . stats [ STAT_MAX_HEALTH ] ) {
// END
ent - > health - - ;
}
}
// count down armor when over max
// STONELANCE
// if ( client->ps.stats[STAT_ARMOR] > client->ps.stats[STAT_MAX_HEALTH] ) {
if ( ( ( ! isRallyRace ( ) & & ! g_gametype . integer = = GT_DERBY ) | | level . startRaceTime )
& & client - > ps . stats [ STAT_ARMOR ] > client - > ps . stats [ STAT_MAX_HEALTH ] ) {
// END
client - > ps . stats [ STAT_ARMOR ] - - ;
}
}
# ifdef MISSIONPACK
if ( bg_itemlist [ client - > ps . stats [ STAT_PERSISTANT_POWERUP ] ] . giTag = = PW_AMMOREGEN ) {
int w , max , inc , t , i ;
int weapList [ ] = { WP_MACHINEGUN , WP_SHOTGUN , WP_GRENADE_LAUNCHER , WP_ROCKET_LAUNCHER , WP_LIGHTNING , WP_RAILGUN , WP_PLASMAGUN , WP_BFG , WP_NAILGUN , WP_PROX_LAUNCHER , WP_CHAINGUN , WP_FLAME_THROWER } ;
2011-07-26 08:52:24 +00:00
int weapCount = ARRAY_LEN ( weapList ) ;
2011-02-18 14:31:32 +00:00
//
for ( i = 0 ; i < weapCount ; i + + ) {
w = weapList [ i ] ;
switch ( w ) {
case WP_MACHINEGUN : max = 50 ; inc = 4 ; t = 1000 ; break ;
case WP_SHOTGUN : max = 10 ; inc = 1 ; t = 1500 ; break ;
case WP_GRENADE_LAUNCHER : max = 10 ; inc = 1 ; t = 2000 ; break ;
case WP_ROCKET_LAUNCHER : max = 10 ; inc = 1 ; t = 1750 ; break ;
case WP_LIGHTNING : max = 50 ; inc = 5 ; t = 1500 ; break ;
case WP_RAILGUN : max = 10 ; inc = 1 ; t = 1750 ; break ;
case WP_PLASMAGUN : max = 50 ; inc = 5 ; t = 1500 ; break ;
case WP_BFG : max = 10 ; inc = 1 ; t = 4000 ; break ;
case WP_NAILGUN : max = 10 ; inc = 1 ; t = 1250 ; break ;
case WP_PROX_LAUNCHER : max = 5 ; inc = 1 ; t = 2000 ; break ;
case WP_CHAINGUN : max = 100 ; inc = 5 ; t = 1000 ; break ;
case WP_FLAME_THROWER : max = 100 ; inc = 5 ; t = 1000 ; break ;
default : max = 0 ; inc = 0 ; t = 1000 ; break ;
}
client - > ammoTimes [ w ] + = msec ;
if ( client - > ps . ammo [ w ] > = max ) {
client - > ammoTimes [ w ] = 0 ;
}
if ( client - > ammoTimes [ w ] > = t ) {
while ( client - > ammoTimes [ w ] > = t )
client - > ammoTimes [ w ] - = t ;
client - > ps . ammo [ w ] + = inc ;
if ( client - > ps . ammo [ w ] > max ) {
client - > ps . ammo [ w ] = max ;
}
}
}
}
# endif
}
/*
= = = = = = = = = = = = = = = = = = = =
ClientIntermissionThink
= = = = = = = = = = = = = = = = = = = =
*/
void ClientIntermissionThink ( gclient_t * client ) {
client - > ps . eFlags & = ~ EF_TALK ;
client - > ps . eFlags & = ~ EF_FIRING ;
// the level will exit when everyone wants to or after timeouts
// swap and latch button actions
client - > oldbuttons = client - > buttons ;
client - > buttons = client - > pers . cmd . buttons ;
if ( client - > buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) & ( client - > oldbuttons ^ client - > buttons ) ) {
// this used to be an ^1 but once a player says ready, it should stick
client - > readyToExit = 1 ;
}
}
/*
= = = = = = = = = = = = = = = =
ClientEvents
Events will be passed on to the clients for presentation ,
but any server game effects are handled here
= = = = = = = = = = = = = = = =
*/
void ClientEvents ( gentity_t * ent , int oldEventSequence ) {
int i , j ;
int event ;
gclient_t * client ;
int damage ;
vec3_t origin , angles ;
// qboolean fired;
gitem_t * item ;
gentity_t * drop ;
client = ent - > client ;
if ( oldEventSequence < client - > ps . eventSequence - MAX_PS_EVENTS ) {
oldEventSequence = client - > ps . eventSequence - MAX_PS_EVENTS ;
}
for ( i = oldEventSequence ; i < client - > ps . eventSequence ; i + + ) {
event = client - > ps . events [ i & ( MAX_PS_EVENTS - 1 ) ] ;
switch ( event ) {
case EV_FALL_MEDIUM :
case EV_FALL_FAR :
if ( ent - > s . eType ! = ET_PLAYER ) {
break ; // not in the player model
}
if ( g_dmflags . integer & DF_NO_FALLING ) {
break ;
}
if ( event = = EV_FALL_FAR ) {
damage = 10 ;
} else {
damage = 5 ;
}
ent - > pain_debounce_time = level . time + 200 ; // no normal pain sound
G_Damage ( ent , NULL , NULL , NULL , NULL , damage , 0 , MOD_FALLING ) ;
break ;
2011-03-08 09:07:05 +00:00
2011-02-18 14:31:32 +00:00
case EV_FIRE_WEAPON :
FireWeapon ( ent ) ;
break ;
2011-03-08 09:07:05 +00:00
case EV_ALTFIRE_WEAPON :
FireAltWeapon ( ent ) ;
break ;
2011-02-18 14:31:32 +00:00
// STONELANCE
case EV_FIRE_REARWEAPON :
FireRearWeapon ( ent ) ;
break ;
// END
case EV_USE_ITEM1 : // teleporter
// drop flags in CTF
item = NULL ;
j = 0 ;
if ( ent - > client - > ps . powerups [ PW_REDFLAG ] ) {
item = BG_FindItemForPowerup ( PW_REDFLAG ) ;
j = PW_REDFLAG ;
} else if ( ent - > client - > ps . powerups [ PW_BLUEFLAG ] ) {
item = BG_FindItemForPowerup ( PW_BLUEFLAG ) ;
j = PW_BLUEFLAG ;
} else if ( ent - > client - > ps . powerups [ PW_NEUTRALFLAG ] ) {
item = BG_FindItemForPowerup ( PW_NEUTRALFLAG ) ;
j = PW_NEUTRALFLAG ;
}
if ( item ) {
drop = Drop_Item ( ent , item , 0 ) ;
// decide how many seconds it has left
drop - > count = ( ent - > client - > ps . powerups [ j ] - level . time ) / 1000 ;
if ( drop - > count < 1 ) {
drop - > count = 1 ;
}
ent - > client - > ps . powerups [ j ] = 0 ;
}
# ifdef MISSIONPACK
if ( g_gametype . integer = = GT_HARVESTER ) {
if ( ent - > client - > ps . generic1 > 0 ) {
if ( ent - > client - > sess . sessionTeam = = TEAM_RED ) {
item = BG_FindItem ( " Blue Cube " ) ;
} else {
item = BG_FindItem ( " Red Cube " ) ;
}
if ( item ) {
for ( j = 0 ; j < ent - > client - > ps . generic1 ; j + + ) {
drop = Drop_Item ( ent , item , 0 ) ;
if ( ent - > client - > sess . sessionTeam = = TEAM_RED ) {
drop - > spawnflags = TEAM_BLUE ;
} else {
drop - > spawnflags = TEAM_RED ;
}
}
}
ent - > client - > ps . generic1 = 0 ;
}
}
# endif
2011-03-08 09:07:05 +00:00
SelectSpawnPoint ( ent - > client - > ps . origin , origin , angles , qfalse ) ;
2011-02-18 14:31:32 +00:00
TeleportPlayer ( ent , origin , angles ) ;
break ;
case EV_USE_ITEM2 : // medkit
ent - > health = ent - > client - > ps . stats [ STAT_MAX_HEALTH ] + 25 ;
break ;
# ifdef MISSIONPACK
case EV_USE_ITEM3 : // kamikaze
// make sure the invulnerability is off
ent - > client - > invulnerabilityTime = 0 ;
// start the kamikze
G_StartKamikaze ( ent ) ;
break ;
case EV_USE_ITEM4 : // portal
if ( ent - > client - > portalID ) {
DropPortalSource ( ent ) ;
}
else {
DropPortalDestination ( ent ) ;
}
break ;
case EV_USE_ITEM5 : // invulnerability
ent - > client - > invulnerabilityTime = level . time + 10000 ;
break ;
# endif
default :
break ;
}
}
}
# ifdef MISSIONPACK
/*
= = = = = = = = = = = = = =
StuckInOtherClient
= = = = = = = = = = = = = =
*/
static int StuckInOtherClient ( gentity_t * ent ) {
int i ;
gentity_t * ent2 ;
ent2 = & g_entities [ 0 ] ;
for ( i = 0 ; i < MAX_CLIENTS ; i + + , ent2 + + ) {
if ( ent2 = = ent ) {
continue ;
}
if ( ! ent2 - > inuse ) {
continue ;
}
if ( ! ent2 - > client ) {
continue ;
}
if ( ent2 - > health < = 0 ) {
continue ;
}
//
if ( ent2 - > r . absmin [ 0 ] > ent - > r . absmax [ 0 ] )
continue ;
if ( ent2 - > r . absmin [ 1 ] > ent - > r . absmax [ 1 ] )
continue ;
if ( ent2 - > r . absmin [ 2 ] > ent - > r . absmax [ 2 ] )
continue ;
if ( ent2 - > r . absmax [ 0 ] < ent - > r . absmin [ 0 ] )
continue ;
if ( ent2 - > r . absmax [ 1 ] < ent - > r . absmin [ 1 ] )
continue ;
if ( ent2 - > r . absmax [ 2 ] < ent - > r . absmin [ 2 ] )
continue ;
return qtrue ;
}
return qfalse ;
}
# endif
void BotTestSolid ( vec3_t origin ) ;
/*
= = = = = = = = = = = = = =
SendPendingPredictableEvents
= = = = = = = = = = = = = =
*/
void SendPendingPredictableEvents ( playerState_t * ps ) {
gentity_t * t ;
int event , seq ;
int extEvent , number ;
// if there are still events pending
if ( ps - > entityEventSequence < ps - > eventSequence ) {
// create a temporary entity for this event which is sent to everyone
// except the client who generated the event
seq = ps - > entityEventSequence & ( MAX_PS_EVENTS - 1 ) ;
event = ps - > events [ seq ] | ( ( ps - > entityEventSequence & 3 ) < < 8 ) ;
// set external event to zero before calling BG_PlayerStateToEntityState
extEvent = ps - > externalEvent ;
ps - > externalEvent = 0 ;
// create temporary entity for event
t = G_TempEntity ( ps - > origin , event ) ;
number = t - > s . number ;
BG_PlayerStateToEntityState ( ps , & t - > s , qtrue ) ;
t - > s . number = number ;
t - > s . eType = ET_EVENTS + event ;
t - > s . eFlags | = EF_PLAYER_EVENT ;
t - > s . otherEntityNum = ps - > clientNum ;
// send to everyone except the client who generated the event
t - > r . svFlags | = SVF_NOTSINGLECLIENT ;
t - > r . singleClient = ps - > clientNum ;
// set back external event
ps - > externalEvent = extEvent ;
}
}
/*
= = = = = = = = = = = = = =
ClientThink
This will be called once for each client frame , which will
usually be a couple times for each server frame on fast clients .
If " g_synchronousClients 1 " is set , this will be called exactly
once for each server frame , which makes for smooth demo recording .
= = = = = = = = = = = = = =
*/
void ClientThink_real ( gentity_t * ent ) {
gclient_t * client ;
pmove_t pm ;
int oldEventSequence ;
int msec ;
usercmd_t * ucmd ;
// STONELANCE
vec3_t origin , forward ;
int i ;
int start , frametime ;
vec3_t oldAngles ;
int oldTime ;
// END
client = ent - > client ;
// don't think if the client is not yet connected (and thus not yet spawned in)
if ( client - > pers . connected ! = CON_CONNECTED ) {
return ;
}
// mark the time, so the connection sprite can be removed
ucmd = & ent - > client - > pers . cmd ;
// 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" );
}
msec = ucmd - > serverTime - client - > ps . commandTime ;
// following others may result in bad times, but we still want
// to check for follow toggles
if ( msec < 1 & & client - > sess . spectatorState ! = SPECTATOR_FOLLOW ) {
return ;
}
if ( msec > 200 ) {
msec = 200 ;
}
if ( pmove_msec . integer < 8 ) {
trap_Cvar_Set ( " pmove_msec " , " 8 " ) ;
}
else if ( pmove_msec . integer > 33 ) {
trap_Cvar_Set ( " pmove_msec " , " 33 " ) ;
}
if ( pmove_fixed . integer | | client - > pers . pmoveFixed ) {
ucmd - > serverTime = ( ( ucmd - > serverTime + pmove_msec . integer - 1 ) / pmove_msec . integer ) * pmove_msec . integer ;
//if (ucmd->serverTime - client->ps.commandTime <= 0)
// return;
}
//
// check for exiting intermission
//
if ( level . intermissiontime ) {
ClientIntermissionThink ( client ) ;
return ;
}
// spectators don't do much
if ( client - > sess . sessionTeam = = TEAM_SPECTATOR ) {
if ( client - > sess . spectatorState = = SPECTATOR_SCOREBOARD ) {
return ;
}
SpectatorThink ( ent , ucmd ) ;
return ;
}
// STONELANCE
else if ( isRaceObserver ( ent - > s . number ) ) {
if ( client - > sess . spectatorState = = SPECTATOR_NOT ) {
client - > sess . spectatorState = SPECTATOR_OBSERVE ;
UpdateObserverSpot ( ent , qtrue ) ;
}
SpectatorThink ( ent , ucmd ) ;
return ;
}
// END
// check for inactivity timer, but never drop the local client of a non-dedicated server
if ( ! ClientInactivityTimer ( client ) ) {
return ;
}
// clear the rewards if time
if ( level . time > client - > rewardTime ) {
client - > ps . eFlags & = ~ ( EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP ) ;
}
if ( client - > noclip ) {
client - > ps . pm_type = PM_NOCLIP ;
} else if ( client - > ps . stats [ STAT_HEALTH ] < = 0 ) {
client - > ps . pm_type = PM_DEAD ;
} else {
client - > ps . pm_type = PM_NORMAL ;
}
client - > ps . gravity = g_gravity . value ;
// set speed
client - > ps . speed = g_speed . value ;
# ifdef MISSIONPACK
if ( bg_itemlist [ client - > ps . stats [ STAT_PERSISTANT_POWERUP ] ] . giTag = = PW_SCOUT ) {
client - > ps . speed * = 1.5 ;
}
else
# endif
// STONELANCE - haste changes fire rate now
/*
if ( client - > ps . powerups [ PW_HASTE ] ) {
client - > ps . speed * = 1.3 ;
}
*/
// END
// Let go of the hook if we aren't firing
// STONELANCE - no more hook
/*
if ( client - > ps . weapon = = WP_GRAPPLING_HOOK & &
client - > hook & & ! ( ucmd - > buttons & BUTTON_ATTACK ) ) {
Weapon_HookFree ( client - > hook ) ;
}
*/
// STONELANCE
// check for car reset
G_ResetCar ( ent ) ;
if ( ! level . startRaceTime & & ( isRallyRace ( ) | | g_gametype . integer = = GT_DERBY ) ) {
if ( ucmd - > buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) & & ! ent - > ready ) {
trap_SendServerCommand ( ent - > s . clientNum , " cp \" Waiting for other players... \n \" " ) ;
ent - > ready = qtrue ;
}
else if ( ! ent - > ready & & level . time < level . startTime + ( g_forceEngineStart . integer * 1000 ) - 10000 ) {
if ( ent - > updateTime < level . time ) {
trap_SendServerCommand ( ent - > s . clientNum , " cp \" Press FIRE or USE when ready to race. \n \" " ) ;
ent - > updateTime = level . time + 2000 ;
}
}
ucmd - > buttons = BUTTON_HANDBRAKE ;
ucmd - > forwardmove = 0 ;
// ucmd->rightmove = 0;
ucmd - > upmove = 0 ;
}
if ( ent - > client - > finishRaceTime & & ent - > client - > finishRaceTime + 500 < level . time
& & ! level . intermissiontime ) {
ent - > s . weapon = WP_NONE ;
ent - > s . powerups = 0 ;
ent - > r . contents = CONTENTS_CORPSE ;
ucmd - > weapon = ent - > s . weapon ;
ucmd - > buttons = BUTTON_HANDBRAKE ;
ucmd - > forwardmove = 0 ;
// ucmd->rightmove = 0;
ucmd - > upmove = 0 ;
}
if ( ent - > client - > finishRaceTime & & ent - > client - > finishRaceTime + RACE_OBSERVER_DELAY < level . time ) {
gentity_t * tent ;
tent = G_TempEntity ( ent - > client - > ps . origin , EV_PLAYER_TELEPORT_OUT ) ;
tent - > s . clientNum = ent - > s . clientNum ;
SelectSpectatorSpawnPoint ( ent - > client - > ps . origin , ent - > client - > ps . viewangles ) ;
VectorCopy ( ent - > client - > ps . origin , ent - > r . currentOrigin ) ;
VectorCopy ( ent - > client - > ps . origin , ent - > s . pos . trBase ) ;
VectorCopy ( ent - > client - > ps . viewangles , ent - > r . currentAngles ) ;
VectorCopy ( ent - > client - > ps . viewangles , ent - > s . apos . trBase ) ;
ent - > raceObserver = qtrue ;
if ( ent - > frontBounds )
trap_UnlinkEntity ( ent - > frontBounds ) ;
if ( ent - > rearBounds )
trap_UnlinkEntity ( ent - > rearBounds ) ;
trap_UnlinkEntity ( client - > carPoints [ 0 ] ) ;
trap_UnlinkEntity ( client - > carPoints [ 1 ] ) ;
trap_UnlinkEntity ( client - > carPoints [ 2 ] ) ;
trap_UnlinkEntity ( client - > carPoints [ 3 ] ) ;
return ;
}
/*
if ( client - > sess . sessionTeam ! = TEAM_SPECTATOR & & ent - > finishRaceTime & &
ent - > finishRaceTime + 10000 < level . time ) {
SetTeam ( ent , " racerSpectator " ) ;
}
*/
if ( isRallyNonDMRace ( ) /* TEMP DERBY || g_gametype.integer == GT_DERBY*/ ) {
ent - > s . weapon = WP_NONE ;
ucmd - > weapon = ent - > s . weapon ;
}
// UPDATE - enable this
// sound horn
if ( client - > sess . sessionTeam ! = TEAM_SPECTATOR & & ! level . intermissiontime & &
ucmd - > buttons & BUTTON_HORN & & client - > horn_sound_time < level . time ) {
G_Sound ( ent , CHAN_AUTO , G_SoundIndex ( " *horn.wav " ) ) ;
client - > horn_sound_time = level . time + 100 ;
}
// use turbo
if ( ( ucmd - > buttons & BUTTON_TURBO ) & & ! ( client - > oldbuttons & BUTTON_TURBO )
& & client - > ps . powerups [ PW_TURBO ] < 0 ) {
client - > ps . powerups [ PW_TURBO ] = level . time + ( - client - > ps . powerups [ PW_TURBO ] ) ;
}
else if ( ! ( ucmd - > buttons & BUTTON_TURBO ) & & ( client - > oldbuttons & BUTTON_TURBO )
& & ent - > client - > ps . powerups [ PW_TURBO ] > level . time ) {
client - > ps . powerups [ PW_TURBO ] = - ( client - > ps . powerups [ PW_TURBO ] - level . time ) ;
}
// END
// set up for pmove
oldEventSequence = client - > ps . eventSequence ;
memset ( & pm , 0 , sizeof ( pm ) ) ;
// check for the hit-scan gauntlet, don't let the action
// go through as an attack unless it actually hits something
if ( client - > ps . weapon = = WP_GAUNTLET & & ! ( ucmd - > buttons & BUTTON_TALK ) & &
// STONELANCE
// ( ucmd->buttons & BUTTON_ATTACK ) && client->ps.weaponTime <= 0 ) {
( ucmd - > buttons & BUTTON_ATTACK ) & & ( client - > ps . weaponTime & NORMAL_WEAPON_TIME_MASK ) < = 0 ) {
// END
pm . gauntletHit = CheckGauntletAttack ( ent ) ;
}
// STONELANCE
/*
if ( ent - > flags & FL_FORCE_GESTURE ) {
ent - > flags & = ~ FL_FORCE_GESTURE ;
ent - > client - > pers . cmd . buttons | = BUTTON_GESTURE ;
}
*/
// END
# ifdef MISSIONPACK
// check for invulnerability expansion before doing the Pmove
if ( client - > ps . powerups [ PW_INVULNERABILITY ] ) {
if ( ! ( client - > ps . pm_flags & PMF_INVULEXPAND ) ) {
vec3_t mins = { - 42 , - 42 , - 42 } ;
vec3_t maxs = { 42 , 42 , 42 } ;
vec3_t oldmins , oldmaxs ;
VectorCopy ( ent - > r . mins , oldmins ) ;
VectorCopy ( ent - > r . maxs , oldmaxs ) ;
// expand
VectorCopy ( mins , ent - > r . mins ) ;
VectorCopy ( maxs , ent - > r . maxs ) ;
trap_LinkEntity ( ent ) ;
// check if this would get anyone stuck in this player
if ( ! StuckInOtherClient ( ent ) ) {
// set flag so the expanded size will be set in PM_CheckDuck
client - > ps . pm_flags | = PMF_INVULEXPAND ;
}
// set back
VectorCopy ( oldmins , ent - > r . mins ) ;
VectorCopy ( oldmaxs , ent - > r . maxs ) ;
trap_LinkEntity ( ent ) ;
}
}
# endif
pm . ps = & client - > ps ;
pm . cmd = * ucmd ;
// STONELANCE - dead cars can still hit things
/*
if ( pm . ps - > pm_type = = PM_DEAD ) {
pm . tracemask = MASK_PLAYERSOLID & ~ CONTENTS_BODY ;
}
else
*/
// END
if ( ent - > r . svFlags & SVF_BOT ) {
pm . tracemask = MASK_PLAYERSOLID | CONTENTS_BOTCLIP ;
}
else {
pm . tracemask = MASK_PLAYERSOLID ;
}
pm . trace = trap_Trace ;
pm . pointcontents = trap_PointContents ;
pm . frictionFunc = G_FrictionCalc ;
pm . debugLevel = g_debugMove . integer ;
pm . noFootsteps = ( g_dmflags . integer & DF_NO_FOOTSTEPS ) > 0 ;
pm . pmove_fixed = pmove_fixed . integer | client - > pers . pmoveFixed ;
pm . pmove_msec = pmove_msec . integer ;
// STONELANCE
// TEMP used to move car around
/*
client - > car . sBody . r [ 2 ] + = 3.0f * ( pm . cmd . upmove * msec / 1000.0f ) ;
client - > car . sBody . CoM [ 2 ] + = 3.0f * ( pm . cmd . upmove * msec / 1000.0f ) ;
for ( i = 0 ; i < 8 ; i + + ) {
client - > car . sPoints [ i ] . r [ 2 ] + = 3.0f * ( pm . cmd . upmove * msec / 1000.0f ) ;
}
*/
// END TEMP
// load car position etc into pmove
level . cars [ ent - > s . clientNum ] = & client - > car ;
pm . car = & client - > car ;
pm . cars = level . cars ;
pm . pDebug = ent - > pDebug ;
pm . controlMode = client - > pers . controlMode ;
pm . manualShift = client - > pers . manualShift ;
pm . client = qfalse ;
if ( ent - > pDebug > 0 ) {
Com_LogPrintf ( " Server Time: %i \n " , pm . cmd . serverTime ) ;
Com_LogPrintf ( " Source: Debug %d \n " , ent - > pDebug ) ;
G_DebugForces ( & pm . car - > sBody , pm . car - > sPoints , ent - > pDebug - 1 ) ;
G_DebugDynamics ( & pm . car - > sBody , pm . car - > sPoints , ent - > pDebug - 1 ) ;
}
start = trap_Milliseconds ( ) ;
frametime = pm . cmd . serverTime - pm . ps - > commandTime ;
oldTime = client - > ps . commandTime ;
VectorCopy ( client - > ps . viewangles , oldAngles ) ;
pm . car_spring = car_spring . value ;
pm . car_shock_up = car_shock_up . value ;
pm . car_shock_down = car_shock_down . value ;
pm . car_swaybar = car_swaybar . value ;
pm . car_wheel = car_wheel . value ;
pm . car_wheel_damp = car_wheel_damp . value ;
pm . car_frontweight_dist = car_frontweight_dist . value ;
pm . car_IT_xScale = car_IT_xScale . value ;
pm . car_IT_yScale = car_IT_yScale . value ;
pm . car_IT_zScale = car_IT_zScale . value ;
pm . car_body_elasticity = car_body_elasticity . value ;
pm . car_air_cof = car_air_cof . value ;
pm . car_air_frac_to_df = car_air_frac_to_df . value ;
pm . car_friction_scale = car_friction_scale . value ;
// END
VectorCopy ( client - > ps . origin , client - > oldOrigin ) ;
# ifdef MISSIONPACK
if ( level . intermissionQueued ! = 0 & & g_singlePlayer . integer ) {
if ( level . time - level . intermissionQueued > = 1000 ) {
pm . cmd . buttons = 0 ;
pm . cmd . forwardmove = 0 ;
pm . cmd . rightmove = 0 ;
pm . cmd . upmove = 0 ;
if ( level . time - level . intermissionQueued > = 2000 & & level . time - level . intermissionQueued < = 2500 ) {
trap_SendConsoleCommand ( EXEC_APPEND , " centerview \n " ) ;
}
ent - > client - > ps . pm_type = PM_SPINTERMISSION ;
}
}
Pmove ( & pm ) ;
# else
Pmove ( & pm ) ;
# endif
// STONELANCE
AnglesSubtract ( client - > ps . viewangles , oldAngles , ent - > s . apos . trDelta ) ;
VectorScale ( ent - > s . apos . trDelta , 1000.0f / ( client - > ps . commandTime - oldTime ) , ent - > s . apos . trDelta ) ;
if ( level . time > 2000 ) {
client - > frameNum + + ;
client - > pmoveTime = ( ( client - > frameNum - 1 ) / ( float ) client - > frameNum ) * client - > pmoveTime + ( trap_Milliseconds ( ) - start ) / ( float ) client - > frameNum ;
}
// Com_Printf("Average pmoveTime %f, Instantanious pmoveTime %d, n=%d\n", client->pmoveTime, (trap_Milliseconds() - start), client->frameNum);
AngleVectors ( client - > ps . viewangles , forward , NULL , NULL ) ;
if ( ent - > frontBounds ) {
VectorMA ( client - > ps . origin , ( CAR_LENGTH - CAR_WIDTH ) / 2 , forward , origin ) ;
G_SetOrigin ( ent - > frontBounds , origin ) ;
trap_LinkEntity ( ent - > frontBounds ) ;
}
if ( ent - > rearBounds ) {
VectorMA ( client - > ps . origin , - ( CAR_LENGTH - CAR_WIDTH ) / 2 , forward , origin ) ;
G_SetOrigin ( ent - > rearBounds , origin ) ;
trap_LinkEntity ( ent - > rearBounds ) ;
}
if ( ent - > pDebug > 0 ) {
Com_LogPrintf ( " Target \n " ) ;
G_DebugDynamics ( & pm . car - > tBody , pm . car - > tPoints , ent - > pDebug - 1 ) ;
}
for ( i = 0 ; i < FIRST_FRAME_POINT ; i + + ) {
if ( client - > carPoints [ i ] ) {
// client->carPoints[i]->s.modelindex = G_ModelIndex( "models/test/sphere01.md3" );
// G_SetOrigin(client->carPoints[i], client->car.sPoints[i].r);
ent - > s . pos . trType = TR_LINEAR ;
ent - > s . pos . trTime = level . time ;
client - > carPoints [ i ] - > s . otherEntityNum = ent - > s . clientNum ;
client - > carPoints [ i ] - > s . otherEntityNum2 = i ;
client - > carPoints [ i ] - > s . apos . trDelta [ 0 ] = client - > car . sPoints [ i ] . w ;
client - > carPoints [ i ] - > s . apos . trDelta [ 1 ] = client - > car . wheelAngle ;
client - > carPoints [ i ] - > s . frame = client - > car . sPoints [ i ] . slipping ;
VectorCopy ( client - > car . sPoints [ i ] . r , client - > carPoints [ i ] - > s . pos . trBase ) ;
VectorCopy ( client - > car . sPoints [ i ] . r , ent - > r . currentOrigin ) ;
VectorCopy ( client - > car . sPoints [ i ] . v , client - > carPoints [ i ] - > s . pos . trDelta ) ;
VectorCopy ( client - > car . sPoints [ i ] . normals [ 0 ] , client - > carPoints [ i ] - > s . origin2 ) ;
client - > carPoints [ i ] - > s . groundEntityNum = client - > car . sPoints [ i ] . onGround ;
// FIXME: remove this for bandwidth
// client->carPoints[i]->r.svFlags |= SVF_BROADCAST;
// send to owner only and ignore PVS ( SVF_BROADCAST )
client - > carPoints [ i ] - > r . svFlags | = SVF_SINGLECLIENT | SVF_BROADCAST ;
client - > carPoints [ i ] - > r . singleClient = ent - > s . number ;
trap_LinkEntity ( client - > carPoints [ i ] ) ;
}
else
Com_Printf ( " Warning: no carpoint entities \n " ) ;
}
/*
if ( ent - > pDebug = = - 1 ) {
Com_LogPrintf ( " server time %d \n " , pm . ps - > commandTime ) ;
Com_LogPrintf ( " wheelAngle %f \n " , client - > car . wheelAngle ) ;
Com_LogPrintf ( " throttle %f \n " , client - > car . throttle ) ;
Com_LogPrintf ( " gear %d \n " , client - > car . gear ) ;
Com_LogPrintf ( " rpm %f \n " , client - > car . rpm ) ;
// Body
Com_LogPrintf ( " r %f, %f, %f \n " , client - > car . sBody . r [ 0 ] , client - > car . sBody . r [ 1 ] , client - > car . sBody . r [ 2 ] ) ;
Com_LogPrintf ( " v %f, %f, %f \n " , client - > car . sBody . v [ 0 ] , client - > car . sBody . v [ 1 ] , client - > car . sBody . v [ 2 ] ) ;
Com_LogPrintf ( " L %f, %f, %f \n " , client - > car . sBody . L [ 0 ] , client - > car . sBody . L [ 1 ] , client - > car . sBody . L [ 2 ] ) ;
Com_LogPrintf ( " viewangles: %f, %f, %f \n " , pm . ps - > viewangles [ 0 ] , pm . ps - > viewangles [ 1 ] , pm . ps - > viewangles [ 2 ] ) ;
// Point
for ( i = 0 ; i < 4 ; i + + ) {
Com_LogPrintf ( " wheel %d \n " , i ) ;
Com_LogPrintf ( " r %f, %f, %f \n " , client - > car . sPoints [ i ] . r [ 0 ] , client - > car . sPoints [ i ] . r [ 1 ] , client - > car . sPoints [ i ] . r [ 2 ] ) ;
Com_LogPrintf ( " v %f, %f, %f \n " , client - > car . sPoints [ i ] . v [ 0 ] , client - > car . sPoints [ i ] . v [ 1 ] , client - > car . sPoints [ i ] . v [ 2 ] ) ;
Com_LogPrintf ( " w %f \n " , client - > car . sPoints [ i ] . w ) ;
Com_LogPrintf ( " normals %f, %f, %f \n " , client - > car . sPoints [ i ] . normals [ 0 ] [ 0 ] , client - > car . sPoints [ i ] . normals [ 0 ] [ 1 ] , client - > car . sPoints [ i ] . normals [ 0 ] [ 2 ] ) ;
Com_LogPrintf ( " fluidDensity %f \n " , client - > car . sPoints [ i ] . fluidDensity ) ;
Com_LogPrintf ( " onGround %d \n " , client - > car . sPoints [ i ] . onGround ) ;
Com_LogPrintf ( " slipping %d \n " , client - > car . sPoints [ i ] . slipping ) ;
}
ent - > pDebug = 0 ;
}
*/
/* Car
Com_Printf ( " springStrength %f \n " , client - > car . springStrength ) ;
Com_Printf ( " springMaxLength %f \n " , client - > car . springMaxLength ) ;
Com_Printf ( " springMinLength %f \n " , client - > car . springMinLength ) ;
Com_Printf ( " shockStrength %f \n " , client - > car . shockStrength ) ;
Com_Printf ( " wheelAngle %f \n " , client - > car . wheelAngle ) ;
Com_Printf ( " throttle %f \n " , client - > car . throttle ) ;
Com_Printf ( " gear %d \n " , client - > car . gear ) ;
Com_Printf ( " rpm %f \n " , client - > car . rpm ) ;
Com_Printf ( " aCOF %f \n " , client - > car . aCOF ) ;
Com_Printf ( " sCOF %f \n " , client - > car . sCOF ) ;
Com_Printf ( " kCOF %f \n " , client - > car . kCOF ) ;
Com_Printf ( " dfCOF %f \n " , client - > car . dfCOF ) ;
Com_Printf ( " ewCOF %f \n " , client - > car . ewCOF ) ;
Com_Printf ( " inverseBodyInertiaTensor: \n " ) ;
Com_Printf ( " %f, %f, %f \n " , client - > car . inverseBodyInertiaTensor [ 0 ] [ 0 ] , client - > car . inverseBodyInertiaTensor [ 0 ] [ 1 ] , client - > car . inverseBodyInertiaTensor [ 0 ] [ 2 ] ) ;
Com_Printf ( " %f, %f, %f \n " , client - > car . inverseBodyInertiaTensor [ 1 ] [ 0 ] , client - > car . inverseBodyInertiaTensor [ 1 ] [ 1 ] , client - > car . inverseBodyInertiaTensor [ 1 ] [ 2 ] ) ;
Com_Printf ( " %f, %f, %f \n " , client - > car . inverseBodyInertiaTensor [ 2 ] [ 0 ] , client - > car . inverseBodyInertiaTensor [ 2 ] [ 1 ] , client - > car . inverseBodyInertiaTensor [ 2 ] [ 2 ] ) ;
*/
/* Body
Com_Printf ( " r %f, %f, %f \n " , client - > car . sBody . r [ 0 ] , client - > car . sBody . r [ 1 ] , client - > car . sBody . r [ 2 ] ) ;
Com_Printf ( " v %f, %f, %f \n " , client - > car . sBody . v [ 0 ] , client - > car . sBody . v [ 1 ] , client - > car . sBody . v [ 2 ] ) ;
Com_Printf ( " w %f, %f, %f \n " , client - > car . sBody . w [ 0 ] , client - > car . sBody . w [ 1 ] , client - > car . sBody . w [ 2 ] ) ;
Com_Printf ( " L %f, %f, %f \n " , client - > car . sBody . L [ 0 ] , client - > car . sBody . L [ 1 ] , client - > car . sBody . L [ 2 ] ) ;
Com_Printf ( " CoM %f, %f, %f \n " , client - > car . sBody . CoM [ 0 ] , client - > car . sBody . CoM [ 1 ] , client - > car . sBody . CoM [ 2 ] ) ;
Com_Printf ( " t: \n " ) ;
Com_Printf ( " %f, %f, %f \n " , client - > car . sBody . t [ 0 ] [ 0 ] , client - > car . sBody . t [ 0 ] [ 1 ] , client - > car . sBody . t [ 0 ] [ 2 ] ) ;
Com_Printf ( " %f, %f, %f \n " , client - > car . sBody . t [ 1 ] [ 0 ] , client - > car . sBody . t [ 1 ] [ 1 ] , client - > car . sBody . t [ 1 ] [ 2 ] ) ;
Com_Printf ( " %f, %f, %f \n " , client - > car . sBody . t [ 2 ] [ 0 ] , client - > car . sBody . t [ 2 ] [ 1 ] , client - > car . sBody . t [ 2 ] [ 2 ] ) ;
*/
/* Point
i = 4 ;
Com_Printf ( " r %f, %f, %f \n " , client - > car . sPoints [ i ] . r [ 0 ] , client - > car . sPoints [ i ] . r [ 1 ] , client - > car . sPoints [ i ] . r [ 2 ] ) ;
Com_Printf ( " v %f, %f, %f \n " , client - > car . sPoints [ i ] . v [ 0 ] , client - > car . sPoints [ i ] . v [ 1 ] , client - > car . sPoints [ i ] . v [ 2 ] ) ;
Com_Printf ( " w %f \n " , client - > car . sPoints [ i ] . w ) ;
Com_Printf ( " netForce %f, %f, %f \n " , client - > car . sPoints [ i ] . netForce [ 0 ] , client - > car . sPoints [ i ] . netForce [ 1 ] , client - > car . sPoints [ i ] . netForce [ 2 ] ) ;
Com_Printf ( " netMoment %f \n " , client - > car . sPoints [ i ] . netMoment ) ;
Com_Printf ( " normals %f, %f, %f \n " , client - > car . sPoints [ i ] . normals [ 0 ] [ 0 ] , client - > car . sPoints [ i ] . normals [ 0 ] [ 1 ] , client - > car . sPoints [ i ] . normals [ 0 ] [ 2 ] ) ;
Com_Printf ( " mass %f \n " , client - > car . sPoints [ i ] . mass ) ;
Com_Printf ( " elasticity %f \n " , client - > car . sPoints [ i ] . elasticity ) ;
Com_Printf ( " kcof %f \n " , client - > car . sPoints [ i ] . kcof ) ;
Com_Printf ( " scof %f \n " , client - > car . sPoints [ i ] . scof ) ;
Com_Printf ( " fluidDensity %f \n " , client - > car . sPoints [ i ] . fluidDensity ) ;
Com_Printf ( " onGround %d \n " , client - > car . sPoints [ i ] . onGround ) ;
Com_Printf ( " slipping %d \n " , client - > car . sPoints [ i ] . slipping ) ;
*/
// END
// save results of pmove
if ( ent - > client - > ps . eventSequence ! = oldEventSequence ) {
ent - > eventTime = level . time ;
}
if ( g_smoothClients . integer ) {
// STONELANCE
// BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue );
BG_PlayerStateToEntityStateExtraPolate ( & ent - > client - > ps , & ent - > s , ent - > client - > ps . commandTime , trap_Cvar_VariableIntegerValue ( " sv_fps " ) , qtrue ) ;
// BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, 2000, qtrue );
// END
}
else {
BG_PlayerStateToEntityState ( & ent - > client - > ps , & ent - > s , qtrue ) ;
}
SendPendingPredictableEvents ( & ent - > client - > ps ) ;
if ( ! ( ent - > client - > ps . eFlags & EF_FIRING ) ) {
client - > fireHeld = qfalse ; // for grapple
}
// use the snapped origin for linking so it matches client predicted versions
VectorCopy ( ent - > s . pos . trBase , ent - > r . currentOrigin ) ;
VectorCopy ( pm . mins , ent - > r . mins ) ;
VectorCopy ( pm . maxs , ent - > r . maxs ) ;
ent - > waterlevel = pm . waterlevel ;
ent - > watertype = pm . watertype ;
// execute client events
ClientEvents ( ent , oldEventSequence ) ;
// STONELANCE - do damage from pmove
if ( pm . damage . damage )
{
if ( ! ( pm . damage . dflags & DAMAGE_NO_PROTECTION ) )
pm . damage . damage * = g_damageScale . value ;
if ( pm . damage . damage > 0 )
{
if ( pm . damage . otherEnt > = 0 ) {
G_Damage ( ent , NULL , & g_entities [ pm . damage . otherEnt ] , pm . damage . dir , pm . damage . origin , pm . damage . damage , pm . damage . dflags , pm . damage . mod ) ;
VectorInverse ( pm . damage . dir ) ;
G_Damage ( & g_entities [ pm . damage . otherEnt ] , NULL , ent , pm . damage . dir , pm . damage . origin , pm . damage . damage , pm . damage . dflags , pm . damage . mod ) ;
}
else
G_Damage ( ent , NULL , NULL , pm . damage . dir , pm . damage . origin , pm . damage . damage , pm . damage . dflags , pm . damage . mod ) ;
}
}
// END
// link entity now, after any personal teleporters have been used
trap_LinkEntity ( ent ) ;
if ( ! ent - > client - > noclip ) {
G_TouchTriggers ( ent ) ;
}
// NOTE: now copy the exact origin over otherwise clients can be snapped into solid
VectorCopy ( ent - > client - > ps . origin , ent - > r . currentOrigin ) ;
//test for solid areas in the AAS file
BotTestAAS ( ent - > r . currentOrigin ) ;
// touch other objects
ClientImpacts ( ent , & pm ) ;
// save results of triggers and client events
if ( ent - > client - > ps . eventSequence ! = oldEventSequence ) {
ent - > eventTime = level . time ;
}
// swap and latch button actions
client - > oldbuttons = client - > buttons ;
client - > buttons = ucmd - > buttons ;
client - > latched_buttons | = client - > buttons & ~ client - > oldbuttons ;
// check for respawning
if ( client - > ps . stats [ STAT_HEALTH ] < = 0 ) {
// wait for the attack button to be pressed
if ( level . time > client - > respawnTime ) {
// forcerespawn is to prevent users from waiting out powerups
if ( g_forcerespawn . integer > 0 & &
( level . time - client - > respawnTime ) > g_forcerespawn . integer * 1000 ) {
// STONELANCE
if ( g_gametype . integer ! = GT_DERBY | | ! ent - > client - > finishRaceTime )
// END
2011-08-06 22:44:15 +00:00
ClientRespawn ( ent ) ;
2011-02-18 14:31:32 +00:00
return ;
}
// pressing attack or use is the normal respawn method
if ( ucmd - > buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) ) {
// STONELANCE
if ( g_gametype . integer ! = GT_DERBY | | ! ent - > client - > finishRaceTime )
// END
2011-08-06 22:44:15 +00:00
ClientRespawn ( ent ) ;
2011-02-18 14:31:32 +00:00
}
}
return ;
}
// perform once-a-second actions
ClientTimerActions ( ent , msec ) ;
// STONELANCE - UPDATE: enable this (use flags instead?)
/*
if ( ( client - > ps . stats [ STAT_HEALTH ] < 25 & & ent - > prevHealth > = 25 ) | |
( client - > ps . stats [ STAT_HEALTH ] < 50 & & ent - > prevHealth > = 50 ) | |
( client - > ps . stats [ STAT_HEALTH ] > = 50 & & ent - > prevHealth < 50 ) ) {
BG_AddPredictableEventToPlayerstate ( EV_ENGINE_SMOKE , client - > ps . stats [ STAT_HEALTH ] , & ent - > client - > ps ) ;
}
ent - > prevHealth = client - > ps . stats [ STAT_HEALTH ] ;
*/
// END
}
/*
= = = = = = = = = = = = = = = = = =
ClientThink
A new command has arrived from the client
= = = = = = = = = = = = = = = = = =
*/
void ClientThink ( int clientNum ) {
gentity_t * ent ;
ent = g_entities + clientNum ;
trap_GetUsercmd ( clientNum , & ent - > client - > pers . cmd ) ;
// mark the time we got info, so we can display the
// phone jack if they don't get any for a while
ent - > client - > lastCmdTime = level . time ;
if ( ! ( ent - > r . svFlags & SVF_BOT ) & & ! g_synchronousClients . integer ) {
ClientThink_real ( ent ) ;
}
}
void G_RunClient ( gentity_t * ent ) {
if ( ! ( ent - > r . svFlags & SVF_BOT ) & & ! g_synchronousClients . integer ) {
return ;
}
ent - > client - > pers . cmd . serverTime = level . time ;
ClientThink_real ( ent ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SpectatorClientEndFrame
= = = = = = = = = = = = = = = = = =
*/
void SpectatorClientEndFrame ( gentity_t * ent ) {
gclient_t * cl ;
// STONELANCE
int i ;
int savedDmgDealt ;
int savedDmgTaken ;
// Com_Printf( "Spectator Mode: %i\n", ent->client->sess.spectatorState );
// END
// if we are doing a chase cam or a remote view, grab the latest info
if ( ent - > client - > sess . spectatorState = = SPECTATOR_FOLLOW ) {
int clientNum , flags ;
clientNum = ent - > client - > sess . spectatorClient ;
// team follow1 and team follow2 go to whatever clients are playing
if ( clientNum = = - 1 ) {
clientNum = level . follow1 ;
} else if ( clientNum = = - 2 ) {
clientNum = level . follow2 ;
}
if ( clientNum > = 0 ) {
cl = & level . clients [ clientNum ] ;
// STONELANCE
// if ( cl->pers.connected == CON_CONNECTED && cl->sess.sessionTeam != TEAM_SPECTATOR ) {
if ( cl - > pers . connected = = CON_CONNECTED & & cl - > sess . sessionTeam ! = TEAM_SPECTATOR
& & ! isRaceObserver ( clientNum ) ) {
// END
flags = ( cl - > ps . eFlags & ~ ( EF_VOTED | EF_TEAMVOTED ) ) | ( ent - > client - > ps . eFlags & ( EF_VOTED | EF_TEAMVOTED ) ) ;
// STONELANCE - FIXME: dont overwrite stats if the player was in the race or derby
// ent->client->ps = cl->ps;
savedDmgDealt = ent - > client - > ps . stats [ STAT_DAMAGE_DEALT ] ;
savedDmgTaken = ent - > client - > ps . stats [ STAT_DAMAGE_TAKEN ] ;
memcpy ( & ent - > client - > ps , & cl - > ps , sizeof ( playerState_t ) ) ;
ent - > client - > ps . stats [ STAT_DAMAGE_DEALT ] = savedDmgDealt ;
ent - > client - > ps . stats [ STAT_DAMAGE_TAKEN ] = savedDmgTaken ;
/*
VectorCopy ( cl - > ps . origin , ent - > client - > ps . origin ) ;
VectorCopy ( cl - > ps . velocity , ent - > client - > ps . velocity ) ;
VectorCopy ( cl - > ps . angularMomentum , ent - > client - > ps . angularMomentum ) ;
VectorCopy ( cl - > ps . viewangles , ent - > client - > ps . viewangles ) ;
ent - > client - > ps . commandTime = cl - > ps . commandTime ;
ent - > client - > ps . clientNum = cl - > ps . clientNum ;
ent - > client - > ps . pm_flags = cl - > ps . pm_flags ;
ent - > client - > ps . pm_type = cl - > ps . pm_type ;
ent - > client - > ps . damagePitch = cl - > ps . damagePitch ;
ent - > client - > ps . damageYaw = cl - > ps . damageYaw ;
ent - > client - > ps . delta_angles [ 0 ] = cl - > ps . delta_angles [ 0 ] ;
ent - > client - > ps . delta_angles [ 1 ] = cl - > ps . delta_angles [ 1 ] ;
ent - > client - > ps . delta_angles [ 2 ] = cl - > ps . delta_angles [ 2 ] ;
ent - > client - > ps . legsAnim = cl - > ps . legsAnim ;
ent - > client - > ps . legsTimer = cl - > ps . legsTimer ;
ent - > client - > ps . torsoAnim = cl - > ps . torsoAnim ;
ent - > client - > ps . torsoTimer = cl - > ps . torsoTimer ;
*/
// END
ent - > client - > ps . pm_flags | = PMF_FOLLOW ;
ent - > client - > ps . eFlags = flags ;
// STONELANCE
// FIXME: could this fuck some shit up with entity numbers or anything like that?
// TODO: optimize this so it only copies the fields that change and not everything
for ( i = 0 ; i < 4 ; i + + )
{
memcpy ( ent - > client - > carPoints [ i ] , cl - > carPoints [ i ] , sizeof ( gentity_t ) ) ;
ent - > client - > carPoints [ i ] - > r . singleClient = ent - > s . number ;
}
// END
return ;
} else {
// drop them to free spectators unless they are dedicated camera followers
if ( ent - > client - > sess . spectatorClient > = 0 ) {
// STONELANCE
// try cycling to a new client
clientNum = ent - > client - > sess . spectatorClient ;
Cmd_FollowCycle_f ( ent , 1 ) ;
// Com_Printf( "Cycle target\n" );
if ( clientNum = = ent - > client - > sess . spectatorClient )
{
// Com_Printf( "Follow Cam: drop back to free\n" );
// G_DebugLogPrintf( "Follow Cam: drop back to free\n" );
// ent->client->sess.spectatorState = SPECTATOR_FREE;
// ClientBegin( ent->client - level.clients );
// ent->client->ps.clientNum = ent->client - level.clients;
StopFollowing ( ent ) ;
}
// END
}
}
}
}
// STONELANCE
else if ( ent - > client - > sess . spectatorState = = SPECTATOR_OBSERVE )
{
int clientNum ;
vec3_t angles , delta ;
float dist ;
clientNum = ent - > client - > sess . spectatorClient ;
if ( clientNum = = - 1 ) {
clientNum = level . follow1 ;
} else if ( clientNum = = - 2 ) {
clientNum = level . follow2 ;
}
if ( clientNum > = 0 ) {
// ent->client->ps.clientNum = clientNum;
cl = & level . clients [ clientNum ] ;
if ( cl - > pers . connected = = CON_CONNECTED & & cl - > sess . sessionTeam ! = TEAM_SPECTATOR
& & ! isRaceObserver ( clientNum ) ) {
VectorClear ( delta ) ;
if ( ! ( ent - > spotflags & OBSERVERCAM_FIXED ) ) {
VectorSubtract ( cl - > ps . origin , ent - > client - > ps . origin , delta ) ;
vectoangles ( delta , angles ) ;
VectorCopy ( angles , ent - > client - > ps . viewangles ) ;
}
VectorClear ( ent - > client - > ps . velocity ) ;
if ( ent - > spotflags & OBSERVERCAM_ZOOM ) {
dist = VectorLength ( delta ) ;
// zoom in closer to target if too far away
if ( dist > 300 )
{
dist - = 300 ;
VectorSet ( ent - > client - > ps . velocity , dist , 0 , 0 ) ;
}
}
ent - > client - > ps . damagePitch = ANGLE2SHORT ( ent - > client - > ps . viewangles [ PITCH ] ) ;
ent - > client - > ps . damageYaw = ANGLE2SHORT ( ent - > client - > ps . viewangles [ YAW ] ) ;
ent - > client - > ps . pm_flags | = PMF_OBSERVE ;
}
else {
// drop them to free spectators unless they are dedicated camera followers
if ( ent - > client - > sess . spectatorClient > = 0 ) {
// try cycling to a new client
clientNum = ent - > client - > sess . spectatorClient ;
Cmd_FollowCycle_f ( ent , 1 ) ;
// Com_Printf( "Cycle target\n" );
if ( clientNum = = ent - > client - > sess . spectatorClient )
{
// Com_Printf( "Observer Cam: drop back to free\n" );
// G_DebugLogPrintf( "Observer Cam: drop back to free\n" );
// ent->client->sess.spectatorState = SPECTATOR_FREE;
// ClientBegin( ent->client - level.clients );
// ent->client->ps.clientNum = ent->client - level.clients;
StopFollowing ( ent ) ;
}
}
}
}
// else
// G_DebugLogPrintf( "Observer Cam: Target client %i\n", clientNum );
}
// END
if ( ent - > client - > sess . spectatorState = = SPECTATOR_SCOREBOARD ) {
ent - > client - > ps . pm_flags | = PMF_SCOREBOARD ;
} else {
ent - > client - > ps . pm_flags & = ~ PMF_SCOREBOARD ;
}
}
/*
= = = = = = = = = = = = = =
ClientEndFrame
Called at the end of each server frame for each connected client
A fast client will have multiple ClientThink for each ClientEdFrame ,
while a slow client may have multiple ClientEndFrame between ClientThink .
= = = = = = = = = = = = = =
*/
void ClientEndFrame ( gentity_t * ent ) {
int i ;
// STONELANCE
// if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
if ( ent - > client - > sess . sessionTeam = = TEAM_SPECTATOR | | isRaceObserver ( ent - > s . number ) ) {
// END
SpectatorClientEndFrame ( ent ) ;
return ;
}
// turn off any expired powerups
for ( i = 0 ; i < MAX_POWERUPS ; i + + ) {
// STONELANCE
if ( i = = PW_TURBO & & ent - > client - > ps . powerups [ i ] < level . time & &
ent - > client - > ps . powerups [ i ] > 0 ) {
ent - > client - > ps . powerups [ i ] = 0 ;
}
else if ( i ! = PW_TURBO & & ent - > client - > ps . powerups [ i ] < level . time ) {
// if ( ent->client->ps.powerups[ i ] < level.time ) {
// END
ent - > client - > ps . powerups [ i ] = 0 ;
}
}
# ifdef MISSIONPACK
// set powerup for player animation
if ( bg_itemlist [ ent - > client - > ps . stats [ STAT_PERSISTANT_POWERUP ] ] . giTag = = PW_GUARD ) {
ent - > client - > ps . powerups [ PW_GUARD ] = level . time ;
}
if ( bg_itemlist [ ent - > client - > ps . stats [ STAT_PERSISTANT_POWERUP ] ] . giTag = = PW_SCOUT ) {
ent - > client - > ps . powerups [ PW_SCOUT ] = level . time ;
}
if ( bg_itemlist [ ent - > client - > ps . stats [ STAT_PERSISTANT_POWERUP ] ] . giTag = = PW_DOUBLER ) {
ent - > client - > ps . powerups [ PW_DOUBLER ] = level . time ;
}
if ( bg_itemlist [ ent - > client - > ps . stats [ STAT_PERSISTANT_POWERUP ] ] . giTag = = PW_AMMOREGEN ) {
ent - > client - > ps . powerups [ PW_AMMOREGEN ] = level . time ;
}
if ( ent - > client - > invulnerabilityTime > level . time ) {
ent - > client - > ps . powerups [ PW_INVULNERABILITY ] = level . time ;
}
# endif
// save network bandwidth
#if 0
if ( ! g_synchronousClients - > integer & & ent - > client - > ps . pm_type = = PM_NORMAL ) {
// FIXME: this must change eventually for non-sync demo recording
VectorClear ( ent - > client - > ps . viewangles ) ;
}
# endif
//
// If the end of unit layout is displayed, don't give
// the player any normal movement attributes
//
if ( level . intermissiontime ) {
return ;
}
// burn from lava, etc
P_WorldEffects ( ent ) ;
// apply all the damage taken this frame
P_DamageFeedback ( ent ) ;
// add the EF_CONNECTION flag if we haven't gotten commands recently
if ( level . time - ent - > client - > lastCmdTime > 1000 ) {
ent - > s . eFlags | = EF_CONNECTION ;
} else {
ent - > s . eFlags & = ~ EF_CONNECTION ;
}
ent - > client - > ps . stats [ STAT_HEALTH ] = ent - > health ; // FIXME: get rid of ent->health...
G_SetClientSound ( ent ) ;
// set the latest infor
if ( g_smoothClients . integer ) {
// STONELANCE
// BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue );
BG_PlayerStateToEntityStateExtraPolate ( & ent - > client - > ps , & ent - > s , ent - > client - > ps . commandTime , trap_Cvar_VariableIntegerValue ( " sv_fps " ) , qtrue ) ;
// BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, 2000, qtrue );
// Com_Printf( "Extrapolating playerstate, trType %i\n", ent->s.pos.trType );
// END
}
else {
BG_PlayerStateToEntityState ( & ent - > client - > ps , & ent - > s , qtrue ) ;
}
SendPendingPredictableEvents ( & ent - > client - > ps ) ;
/*
if ( g_entities [ 0 ] . client )
{
int rearTime ;
g_entities [ 0 ] . client - > ps . weaponTime | = 0x7fff ;
rearTime = ( g_entities [ 0 ] . client - > ps . weaponTime & REAR_WEAPON_TIME_MASK ) > > 16 ;
Com_Printf ( " g forward: cur weapon time %i \n " , g_entities [ 0 ] . client - > ps . weaponTime & NORMAL_WEAPON_TIME_MASK ) ;
Com_Printf ( " g rear: cur weapon time %i \n " , rearTime ) ;
Com_Printf ( " g: cur weapon time %i \n " , g_entities [ 0 ] . client - > ps . weaponTime ) ;
}
*/
// set the bit for the reachability area the client is currently in
// i = trap_AAS_PointReachabilityAreaIndex( ent->client->ps.origin );
// ent->client->areabits[i >> 3] |= 1 << (i & 7);
}