2001-12-31 16:16:59 +00:00
//-----------------------------------------------------------------------------
//
// $Id$
//
//-----------------------------------------------------------------------------
//
2001-12-31 16:28:42 +00:00
// $Log$
2003-04-19 15:27:31 +00:00
// Revision 1.99 2003/04/19 15:27:30 jbravo
// Backing out of most of unlagged. Only optimized prediction and smooth clients
// remains.
//
2003-03-22 20:29:26 +00:00
// Revision 1.98 2003/03/22 20:29:26 jbravo
// wrapping linkent and unlinkent calls
//
2003-03-10 07:07:58 +00:00
// Revision 1.97 2003/03/10 07:07:58 jbravo
// Small unlagged fixes and voting delay added.
//
2003-03-09 21:30:39 +00:00
// Revision 1.96 2003/03/09 21:30:38 jbravo
// Adding unlagged. Still needs work.
//
2002-11-13 00:50:38 +00:00
// Revision 1.95 2002/11/13 00:50:38 jbravo
// Fixed item dropping, specmode selection on death and helmet probs.
//
2002-10-30 21:24:47 +00:00
// Revision 1.94 2002/10/30 21:24:47 jbravo
// Minor helmet tweaking
//
2002-10-30 20:04:34 +00:00
// Revision 1.93 2002/10/30 20:04:34 jbravo
// Adding helmet
//
2002-10-26 22:03:43 +00:00
// Revision 1.92 2002/10/26 22:03:43 jbravo
// Made TeamDM work RQ3 style.
//
2002-10-26 00:37:18 +00:00
// Revision 1.91 2002/10/26 00:37:18 jbravo
// New multiple item code and added PB support to the UI
//
2002-09-29 16:06:45 +00:00
// Revision 1.90 2002/09/29 16:06:44 jbravo
// Work done at the HPWorld expo
//
2002-09-24 05:06:17 +00:00
// Revision 1.89 2002/09/24 05:06:16 blaze
// fixed spectating so ref\'s can now use all the chasecam modes.
//
2002-08-30 01:09:06 +00:00
// Revision 1.88 2002/08/30 01:09:06 jbravo
// Semi fixed the bodies thing in CTB
//
2002-08-21 07:00:07 +00:00
// Revision 1.87 2002/08/21 07:00:07 jbravo
// Added CTB respawn queue and fixed game <-> cgame synch problem in CTB
//
2002-07-24 02:17:38 +00:00
// Revision 1.86 2002/07/24 02:17:38 jbravo
// Added a respawn delay for CTB
//
2002-07-22 06:35:03 +00:00
// Revision 1.85 2002/07/22 06:33:04 niceass
// cleaned up the powerup code
//
2002-07-21 18:52:39 +00:00
// Revision 1.84 2002/07/21 18:48:06 niceass
// weapon prediction stuff
//
2002-07-07 18:36:13 +00:00
// Revision 1.83 2002/07/07 18:36:13 jbravo
// Added an AntiIdle system. Can play insane sounds for idle players, drop them
// from teams or kick them. Upped version to Beta 2.1
//
2002-07-02 19:15:17 +00:00
// Revision 1.82 2002/07/02 19:15:17 jbravo
// Drop weapon with akimbos now behaves like AQ, plus no suicides during LCA
//
2002-06-23 19:27:52 +00:00
// Revision 1.81 2002/06/23 19:27:52 niceass
// bandage bug fix
//
2002-06-19 18:13:57 +00:00
// Revision 1.80 2002/06/19 18:13:57 jbravo
// New TNG spawning system :)
//
2002-06-18 06:15:30 +00:00
// Revision 1.79 2002/06/18 06:15:30 niceass
// m4 kick now smooth
//
2002-06-17 00:27:29 +00:00
// Revision 1.78 2002/06/17 00:27:29 jbravo
// Cleanup
//
2002-06-16 20:06:15 +00:00
// Revision 1.77 2002/06/16 20:06:14 jbravo
// Reindented all the source files with "indent -kr -ut -i8 -l120 -lc120 -sob -bad -bap"
//
2002-06-16 17:38:00 +00:00
// Revision 1.76 2002/06/16 17:38:00 jbravo
// Removed the MISSIONPACK ifdefs and missionpack only code.
//
2002-06-05 15:17:51 +00:00
// Revision 1.75 2002/06/05 15:17:51 jbravo
// Gibbed players now vanish (gibs with them tho :() and suicide is no
// longer -2 frags. Added Obit handling for telefrags and better handling
// for unhandled mod's
//
2002-06-03 05:25:37 +00:00
// Revision 1.74 2002/06/03 05:25:37 niceass
// spectator changes
//
2002-05-21 04:58:28 +00:00
// Revision 1.73 2002/05/21 04:58:27 blaze
// kicked the reload bugs ass!
//
2002-05-06 21:41:01 +00:00
// Revision 1.72 2002/05/06 21:41:01 slicer
// Added rq3_cmd
//
2002-04-13 15:37:54 +00:00
// Revision 1.71 2002/04/13 15:37:53 jbravo
// limchasecam has been redone with new spec system
//
2002-04-03 15:29:24 +00:00
// Revision 1.70 2002/04/03 15:29:24 jbravo
// Those __ZCAM__ ifdefs keep creaping back in :)
//
2002-04-03 03:13:49 +00:00
// Revision 1.69 2002/04/03 03:13:16 blaze
// NEW BREAKABLE CODE - will break all old breakables(wont appear in maps)
//
2002-04-02 20:23:12 +00:00
// Revision 1.68 2002/04/02 20:23:12 jbravo
// Bots dont get to use any specmode other than FREE and the recive radio cmds
// as text and not sounds.
//
2002-04-01 22:23:14 +00:00
// Revision 1.67 2002/04/01 22:23:14 slicer
// Added "weapon" command buffering | Solved Gren Mode Bug
//
2002-03-30 21:51:42 +00:00
// Revision 1.66 2002/03/30 21:51:42 jbravo
// Removed all those ifdefs for zcam.
//
2002-03-30 17:37:49 +00:00
// Revision 1.65 2002/03/30 17:37:48 jbravo
// Added damage tracking to the server. Added zcam flic mode. cleaned up g_damage.
//
2002-03-30 02:54:24 +00:00
// Revision 1.64 2002/03/30 02:54:24 jbravo
// MOre spec tweaks and a scoreboard fix
//
2002-03-30 02:29:43 +00:00
// Revision 1.63 2002/03/30 02:29:43 jbravo
// Lots of spectator code updates. Removed debugshit, added some color.
//
2002-03-26 11:32:05 +00:00
// Revision 1.62 2002/03/26 11:32:04 jbravo
// Remember specstate between rounds.
//
2002-03-23 21:29:42 +00:00
// Revision 1.61 2002/03/23 21:29:42 jbravo
// I finally fixed snipers spawning with pistol up. g_RQ3_sniperup has been
// reinstated.
//
2002-03-23 05:17:43 +00:00
// Revision 1.60 2002/03/23 05:17:42 jbravo
// Major cleanup of game -> cgame communication with LCA vars.
//
2002-03-18 19:19:08 +00:00
// Revision 1.59 2002/03/18 19:18:39 slicer
// Fixed bandage bugs ( i hope )
//
2002-03-02 12:24:30 +00:00
// Revision 1.58 2002/03/02 12:24:30 jbravo
// Removed some debugging messages
//
2002-02-27 01:54:29 +00:00
// Revision 1.57 2002/02/27 01:54:29 jbravo
// More spectatorfixes and finally stopped all fallingdamage anims and
// sounds during LCA.
//
2002-02-26 02:58:47 +00:00
// Revision 1.56 2002/02/26 02:58:47 jbravo
// Fixing the spectator_free mode not being predicted in the client.
//
2002-02-25 19:41:53 +00:00
// Revision 1.55 2002/02/25 19:41:53 jbravo
// Fixed the use ESC and join menu to join teams when dead players are
// spectating in TP mode.
// Tuned the autorespawn system a bit. Now dead ppl. are dead for a very
// small time before they are made into spectators.
//
2002-02-23 16:55:09 +00:00
// Revision 1.54 2002/02/23 16:55:09 jbravo
// Added debugging to help find what was going with can't find item for weapon
// error that crash the server.
//
2002-02-22 02:13:13 +00:00
// Revision 1.53 2002/02/22 02:13:13 jbravo
// Fixed a few bugs and did some cleanups
//
2002-02-10 21:21:23 +00:00
// Revision 1.52 2002/02/10 21:21:22 slicer
// Saving persistant and other data on some events..
//
2002-02-10 18:38:42 +00:00
// Revision 1.51 2002/02/10 18:38:42 jbravo
// Added new SPECTATOR_ZCAM spec mode.
//
2002-02-10 17:20:45 +00:00
// Revision 1.50 2002/02/10 17:20:45 jbravo
// Attempting to fix the camera freeze in the begining of the game
//
2002-02-09 18:27:44 +00:00
// Revision 1.49 2002/02/09 18:27:44 slicer
// Spectator code: +attack button to change view, and jump to switch player
//
2002-02-09 00:10:12 +00:00
// Revision 1.48 2002/02/09 00:10:12 jbravo
// Fixed spectator follow and free and updated zcam to 1.04 and added the
// missing zcam files.
//
2002-02-08 18:59:01 +00:00
// Revision 1.47 2002/02/08 18:59:01 slicer
// Spec code changes
//
2002-02-06 12:06:48 +00:00
// Revision 1.46 2002/02/06 12:06:48 slicer
// TP Scores bug fix
//
2002-02-06 03:10:43 +00:00
// Revision 1.45 2002/02/06 03:10:43 jbravo
// Fix the instant spectate on death and an attempt to fix the scores
//
2002-01-29 03:13:45 +00:00
// Revision 1.44 2002/01/29 03:13:45 jbravo
// Further fixes to antistick
//
2002-01-27 13:33:28 +00:00
// Revision 1.43 2002/01/27 13:33:28 jbravo
// Teamplay antistick system.
//
2002-01-11 20:20:58 +00:00
// Revision 1.42 2002/01/11 20:20:58 jbravo
// Adding TP to main branch
//
2002-01-11 19:48:33 +00:00
// Revision 1.41 2002/01/11 19:48:30 jbravo
// Formatted the source in non DOS format.
//
2001-12-31 16:28:42 +00:00
// Revision 1.40 2001/12/31 16:28:42 jbravo
// I made a Booboo with the Log tag.
//
2001-12-31 16:16:59 +00:00
//
//-----------------------------------------------------------------------------
2001-05-06 20:50:27 +00:00
// Copyright (C) 1999-2000 Id Software, Inc.
//
# include "g_local.h"
2001-12-17 15:08:34 +00:00
# include "zcam.h"
2001-07-16 01:40:33 +00:00
//Elder: moved kick to g_weapon.c where it belongs
2001-05-06 20:50:27 +00:00
/*
= = = = = = = = = = = = = = =
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 .
= = = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void P_DamageFeedback ( gentity_t * player )
{
gclient_t * client ;
float count , side ;
vec3_t angles , v ;
vec3_t forward , right , up ;
2001-05-06 20:50:27 +00:00
client = player - > client ;
2002-06-16 20:06:15 +00:00
if ( client - > ps . pm_type = = PM_DEAD ) {
2001-05-06 20:50:27 +00:00
return ;
}
2001-07-09 00:32:10 +00:00
2002-06-17 00:27:29 +00:00
// total points of damage shot at the player this frame
2001-05-06 20:50:27 +00:00
count = client - > damage_blood + client - > damage_armor ;
2002-06-16 20:06:15 +00:00
if ( count = = 0 ) {
2001-05-06 20:50:27 +00:00
return ; // didn't take any damage
}
2002-06-16 20:06:15 +00:00
if ( count > 255 ) {
2001-05-06 20:50:27 +00:00
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
2002-06-16 20:06:15 +00:00
if ( client - > damage_fromWorld ) {
2001-05-06 20:50:27 +00:00
client - > ps . damagePitch = 255 ;
client - > ps . damageYaw = 255 ;
client - > damage_fromWorld = qfalse ;
} else {
2002-06-16 20:06:15 +00:00
vectoangles ( client - > damage_from , angles ) ;
2001-11-11 23:59:17 +00:00
2001-06-30 23:17:08 +00:00
// new RQ3 view-kick code, needs more tweaking (the 50 needs to be replaces with that below calcuation
// from the AQ2 code.
2001-11-11 23:59:17 +00:00
2001-07-16 01:40:33 +00:00
// set aiming directions
2002-06-16 20:06:15 +00:00
AngleVectors ( client - > ps . viewangles , forward , right , up ) ;
2001-07-16 01:40:33 +00:00
2002-06-16 20:06:15 +00:00
VectorSubtract ( client - > damage_from , player - > s . origin , v ) ;
2001-06-30 23:17:08 +00:00
VectorNormalize ( v ) ;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
side = - DotProduct ( v , forward ) ;
client - > ps . damagePitch = 50 * side * 0.3 ;
2001-06-30 23:17:08 +00:00
2002-06-16 20:06:15 +00:00
side = - DotProduct ( v , right ) ;
client - > ps . damageYaw = 50 * side * 0.3 ;
2001-11-11 23:59:17 +00:00
2001-06-30 23:17:08 +00:00
}
2001-06-10 06:46:06 +00:00
// play an appropriate pain sound
2002-06-16 20:06:15 +00:00
if ( ( level . time > player - > pain_debounce_time ) & & ! ( player - > flags & FL_GODMODE ) ) {
2001-06-26 02:06:50 +00:00
//Elder: reduced pain debounce time so we can have a few more sounds :)
player - > pain_debounce_time = level . time + 250 ;
2001-11-11 23:59:17 +00:00
2002-06-16 20:06:15 +00:00
switch ( client - > lasthurt_location & ~ ( LOCATION_BACK | LOCATION_LEFT | LOCATION_RIGHT | LOCATION_FRONT ) ) {
//Elder: headshot sound
case LOCATION_HEAD :
case LOCATION_FACE :
2001-08-13 17:26:53 +00:00
if ( client - > lasthurt_mod = = MOD_KNIFE | | client - > lasthurt_mod = = MOD_KNIFE_THROWN )
2002-06-16 20:06:15 +00:00
G_AddEvent ( player , EV_RQ3_SOUND , RQ3_SOUND_KNIFEDEATH ) ;
2001-06-10 06:46:06 +00:00
break ;
default :
2002-06-16 20:06:15 +00:00
G_AddEvent ( player , EV_PAIN , player - > health ) ;
2001-06-10 06:46:06 +00:00
break ;
}
2001-11-11 23:59:17 +00:00
2001-05-06 20:50:27 +00:00
client - > ps . damageEvent + + ;
}
client - > ps . damageCount = count ;
2001-08-30 09:47:39 +00:00
// Elder: HC Smoke
if ( client - > lasthurt_mod = = MOD_HANDCANNON & &
2002-06-16 20:06:15 +00:00
client - > damage_blood > = 120 & & client - > damage_knockback > = RQ3_HANDCANNON_KICK * 6 ) {
2001-08-30 09:47:39 +00:00
client - > ps . eFlags | = EF_HANDCANNON_SMOKED ;
}
2001-05-06 20:50:27 +00:00
//
// clear totals
//
client - > damage_blood = 0 ;
client - > damage_armor = 0 ;
client - > damage_knockback = 0 ;
}
/*
= = = = = = = = = = = = =
P_WorldEffects
Check for lava / slime contents and drowning
= = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void P_WorldEffects ( gentity_t * ent )
{
int waterlevel ;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
if ( ent - > client - > noclip ) {
2001-05-06 20:50:27 +00:00
ent - > client - > airOutTime = level . time + 12000 ; // don't need air
return ;
}
waterlevel = ent - > waterlevel ;
//
// check for drowning
//
2002-06-16 20:06:15 +00:00
if ( waterlevel = = 3 ) {
2002-07-22 06:35:03 +00:00
2001-05-06 20:50:27 +00:00
// if out of air, start drowning
2002-06-16 20:06:15 +00:00
if ( ent - > client - > airOutTime < level . time ) {
2001-05-06 20:50:27 +00:00
// drown!
ent - > client - > airOutTime + = 1000 ;
2002-06-16 20:06:15 +00:00
if ( ent - > health > 0 ) {
2001-05-06 20:50:27 +00:00
// 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
if ( ent - > health < = ent - > damage ) {
G_Sound ( ent , CHAN_VOICE , G_SoundIndex ( " *drown.wav " ) ) ;
2002-06-16 20:06:15 +00:00
} else if ( rand ( ) & 1 ) {
2001-05-06 20:50:27 +00:00
G_Sound ( ent , CHAN_VOICE , G_SoundIndex ( " sound/player/gurp1.wav " ) ) ;
} else {
G_Sound ( ent , CHAN_VOICE , G_SoundIndex ( " sound/player/gurp2.wav " ) ) ;
}
// don't play a normal pain sound
ent - > pain_debounce_time = level . time + 200 ;
2002-06-16 20:06:15 +00:00
G_Damage ( ent , NULL , NULL , NULL , NULL , ent - > damage , DAMAGE_NO_ARMOR , MOD_WATER ) ;
2001-05-06 20:50:27 +00:00
}
}
} else {
ent - > client - > airOutTime = level . time + 12000 ;
ent - > damage = 2 ;
}
//
// check for sizzle damage (move to pmove?)
//
2002-06-16 20:06:15 +00:00
if ( waterlevel & & ( ent - > watertype & ( CONTENTS_LAVA | CONTENTS_SLIME ) ) ) {
2001-10-11 22:52:43 +00:00
// Elder: changed around a bit -- using timestamp variable
2002-06-16 20:06:15 +00:00
if ( ent - > health > 0 & & level . time > ent - > timestamp ) {
2002-07-22 06:35:03 +00:00
if ( ent - > watertype & CONTENTS_LAVA ) {
G_Damage ( ent , NULL , NULL , NULL , NULL , 3 * waterlevel , 0 , MOD_LAVA ) ;
}
2001-05-06 20:50:27 +00:00
2002-07-22 06:35:03 +00:00
if ( ent - > watertype & CONTENTS_SLIME ) {
G_Damage ( ent , NULL , NULL , NULL , NULL , waterlevel , 0 , MOD_SLIME ) ;
2001-05-06 20:50:27 +00:00
}
2002-07-22 06:35:03 +00:00
// Elder: added
ent - > timestamp = level . time + FRAMETIME ;
2001-05-06 20:50:27 +00:00
}
}
}
/*
= = = = = = = = = = = = = = =
G_SetClientSound
= = = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void G_SetClientSound ( gentity_t * ent )
{
if ( ent - > waterlevel & & ( ent - > watertype & ( CONTENTS_LAVA | CONTENTS_SLIME ) ) ) {
2001-05-06 20:50:27 +00:00
ent - > client - > ps . loopSound = level . snd_fry ;
} else {
ent - > client - > ps . loopSound = 0 ;
}
}
//==============================================================
/*
= = = = = = = = = = = = = =
ClientImpacts
= = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
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 ] ) {
2001-05-06 20:50:27 +00:00
break ;
}
}
if ( j ! = i ) {
continue ; // duplicated
}
2002-09-24 05:06:17 +00:00
//Blaze: Print out some debug info
if ( & g_entities [ pm - > touchents [ i ] ] = = NULL ) G_Printf ( " Ln 0377 \n " ) ;
2002-06-16 20:06:15 +00:00
other = & g_entities [ pm - > touchents [ i ] ] ;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
if ( ( ent - > r . svFlags & SVF_BOT ) & & ( ent - > touch ) ) {
ent - > touch ( ent , other , & trace ) ;
2001-05-06 20:50:27 +00:00
}
2002-06-16 20:06:15 +00:00
if ( ! other - > touch ) {
2001-05-06 20:50:27 +00:00
continue ;
}
2002-06-16 20:06:15 +00:00
other - > touch ( other , ent , & trace ) ;
2001-05-06 20:50:27 +00:00
}
}
/*
= = = = = = = = = = = =
G_TouchTriggers
Find all trigger entities that ent ' s current position touches .
2001-12-17 15:08:34 +00:00
Spectators will only interact with teleporters ( and door triggers for spectators )
2001-05-06 20:50:27 +00:00
= = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void G_TouchTriggers ( gentity_t * ent )
{
int i , num ;
int touch [ MAX_GENTITIES ] ;
gentity_t * hit ;
trace_t trace ;
vec3_t mins , maxs ;
static vec3_t range = { 40 , 40 , 52 } ;
if ( ! ent - > client ) {
2001-05-06 20:50:27 +00:00
return ;
}
// dead clients don't activate triggers!
2002-06-16 20:06:15 +00:00
if ( ent - > client - > ps . stats [ STAT_HEALTH ] < = 0 ) {
2001-05-06 20:50:27 +00:00
return ;
}
2002-06-16 20:06:15 +00:00
VectorSubtract ( ent - > client - > ps . origin , range , mins ) ;
VectorAdd ( ent - > client - > ps . origin , range , maxs ) ;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
num = trap_EntitiesInBox ( mins , maxs , touch , MAX_GENTITIES ) ;
2001-05-06 20:50:27 +00:00
// can't use ent->absmin, because that has a one unit pad
2002-06-16 20:06:15 +00:00
VectorAdd ( ent - > client - > ps . origin , ent - > r . mins , mins ) ;
VectorAdd ( ent - > client - > ps . origin , ent - > r . maxs , maxs ) ;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
for ( i = 0 ; i < num ; i + + ) {
2002-09-24 05:06:17 +00:00
//Blaze: Print out some debug info
if ( & g_entities [ touch [ i ] ] = = NULL ) G_Printf ( " Ln 0429 \n " ) ;
2001-05-06 20:50:27 +00:00
hit = & g_entities [ touch [ i ] ] ;
2002-06-16 20:06:15 +00:00
if ( ! hit - > touch & & ! ent - > touch ) {
2001-05-06 20:50:27 +00:00
continue ;
}
2002-06-16 20:06:15 +00:00
if ( ! ( hit - > r . contents & CONTENTS_TRIGGER ) ) {
2001-05-06 20:50:27 +00:00
continue ;
}
// ignore most entities if a spectator
2002-06-16 20:06:15 +00:00
if ( ent - > client - > sess . sessionTeam = = TEAM_SPECTATOR ) {
if ( hit - > s . eType ! = ET_TELEPORT_TRIGGER ) { //&&
2001-05-06 20:50:27 +00:00
// this is ugly but adding a new ET_? type will
// most likely cause network incompatibilities
2001-11-11 23:59:17 +00:00
// NiceAss: changed Touch_DoorTrigger to Touch_DoorTriggerSpectator
2002-06-03 05:25:37 +00:00
// hit->touch != Touch_DoorTriggerSpectator) {
2001-05-06 20:50:27 +00:00
continue ;
}
}
// use seperate code for determining if an item is picked up
// so you don't have to actually contact its bounding box
2002-06-16 20:06:15 +00:00
if ( hit - > s . eType = = ET_ITEM ) {
if ( ! BG_PlayerTouchesItem ( & ent - > client - > ps , & hit - > s , level . time ) ) {
2001-05-06 20:50:27 +00:00
continue ;
}
} else {
2002-06-16 20:06:15 +00:00
if ( ! trap_EntityContact ( mins , maxs , hit ) ) {
2001-05-06 20:50:27 +00:00
continue ;
}
}
2002-06-16 20:06:15 +00:00
memset ( & trace , 0 , sizeof ( trace ) ) ;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
if ( hit - > touch ) {
hit - > touch ( hit , ent , & trace ) ;
2001-05-06 20:50:27 +00:00
}
2002-06-16 20:06:15 +00:00
if ( ( ent - > r . svFlags & SVF_BOT ) & & ( ent - > touch ) ) {
ent - > touch ( ent , hit , & trace ) ;
2001-05-06 20:50:27 +00:00
}
}
// if we didn't touch a jump pad this pmove frame
2002-06-16 20:06:15 +00:00
if ( ent - > client - > ps . jumppad_frame ! = ent - > client - > ps . pmove_framecount ) {
2001-05-06 20:50:27 +00:00
ent - > client - > ps . jumppad_frame = 0 ;
ent - > client - > ps . jumppad_ent = 0 ;
}
2001-12-17 15:08:34 +00:00
if ( ent - > client - > openDoor = = 2 ) {
ent - > client - > openDoor = qfalse ;
ent - > client - > openDoorTime = 0 ;
}
2001-05-06 20:50:27 +00:00
}
/*
= = = = = = = = = = = = = = = = =
SpectatorThink
2001-12-17 15:08:34 +00:00
NiceAss : Heavy modifications will be here for AQ2 - like spectator mode and zcam ! ?
2001-05-06 20:50:27 +00:00
= = = = = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void SpectatorThink ( gentity_t * ent , usercmd_t * ucmd )
{
pmove_t pm ;
gclient_t * client ;
int clientNum ;
2001-05-06 20:50:27 +00:00
client = ent - > client ;
2002-02-09 00:10:12 +00:00
clientNum = client - level . clients ;
2001-12-17 15:08:34 +00:00
2002-02-10 18:38:42 +00:00
if ( client - > sess . spectatorState = = SPECTATOR_ZCAM ) {
2002-03-30 02:29:43 +00:00
client - > ps . commandTime = ucmd - > serverTime ;
camera_think ( ent ) ;
2001-12-17 15:08:34 +00:00
}
2002-03-30 02:29:43 +00:00
if ( client - > sess . spectatorState = = SPECTATOR_FREE ) {
2002-09-29 16:06:45 +00:00
if ( g_gametype . integer = = GT_CTF & & level . team_round_going & &
2002-08-21 07:00:07 +00:00
( client - > sess . savedTeam = = TEAM_RED | | client - > sess . savedTeam = = TEAM_BLUE ) )
client - > ps . pm_type = PM_FREEZE ;
else
client - > ps . pm_type = PM_SPECTATOR ;
2001-05-06 20:50:27 +00:00
client - > ps . speed = 400 ; // faster than normal
// set up for pmove
2002-06-16 20:06:15 +00:00
memset ( & pm , 0 , sizeof ( pm ) ) ;
2001-05-06 20:50:27 +00:00
pm . ps = & client - > ps ;
pm . cmd = * ucmd ;
2002-06-03 05:25:37 +00:00
pm . tracemask = 0 ; // spectators can fly through bodies
2001-05-06 20:50:27 +00:00
pm . trace = trap_Trace ;
pm . pointcontents = trap_PointContents ;
2002-07-21 18:52:39 +00:00
pm . predict = qtrue ;
2001-05-06 20:50:27 +00:00
// perform a pmove
2002-06-16 20:06:15 +00:00
Pmove ( & pm ) ;
2001-05-06 20:50:27 +00:00
// save results of pmove
2002-06-16 20:06:15 +00:00
VectorCopy ( client - > ps . origin , ent - > s . origin ) ;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
G_TouchTriggers ( ent ) ;
2003-03-22 20:29:26 +00:00
trap_RQ3UnlinkEntity ( ent , __LINE__ , __FILE__ ) ;
2001-05-06 20:50:27 +00:00
}
2002-04-02 20:23:12 +00:00
// JBravo: Lets not allow bots to use any specmode other than FREE
if ( ent - > r . svFlags & SVF_BOT )
return ;
2002-03-30 02:29:43 +00:00
//Slicer - Changing this for aq2 way
// Jump button cycles throught spectators
2002-06-16 20:06:15 +00:00
if ( client - > sess . spectatorState = = SPECTATOR_FOLLOW | | client - > sess . spectatorState = = SPECTATOR_ZCAM ) {
if ( ucmd - > upmove > = 10 ) {
2002-03-30 02:29:43 +00:00
if ( ! ( client - > ps . pm_flags & PMF_JUMP_HELD ) ) {
client - > ps . pm_flags | = PMF_JUMP_HELD ;
2002-03-30 17:37:49 +00:00
if ( client - > sess . spectatorState = = SPECTATOR_ZCAM ) {
if ( client - > camera - > mode = = CAMERA_MODE_SWING )
CameraSwingCycle ( ent , 1 ) ;
} else
2002-03-30 02:29:43 +00:00
Cmd_FollowCycle_f ( ent , 1 ) ;
}
2002-06-16 20:06:15 +00:00
} else
2002-03-30 02:29:43 +00:00
client - > ps . pm_flags & = ~ PMF_JUMP_HELD ;
}
client - > oldbuttons = client - > buttons ;
client - > buttons = ucmd - > buttons ;
2002-08-21 07:00:07 +00:00
if ( g_gametype . integer = = GT_CTF & & client - > sess . spectatorState = = SPECTATOR_FREE & &
( client - > sess . savedTeam = = TEAM_RED | | client - > sess . savedTeam = = TEAM_BLUE ) )
return ;
2002-03-30 02:29:43 +00:00
// Attack Button cycles throught free view, follow or zcam
2002-06-16 20:06:15 +00:00
if ( ( ucmd - > buttons & BUTTON_ATTACK ) & & ! ( client - > oldbuttons & BUTTON_ATTACK ) ) {
2002-09-24 05:06:17 +00:00
if ( g_gametype . integer = = GT_TEAMPLAY & & g_RQ3_limchasecam . integer ! = 0 & & client - > sess . referee = = 0 ) {
2002-06-16 20:06:15 +00:00
if ( ! OKtoFollow ( clientNum ) )
return ;
2002-04-13 15:37:54 +00:00
if ( client - > sess . spectatorState ! = SPECTATOR_FOLLOW ) {
client - > sess . spectatorState = SPECTATOR_FOLLOW ;
client - > specMode = SPECTATOR_FOLLOW ;
client - > ps . pm_flags | = PMF_FOLLOW ;
client - > ps . stats [ STAT_RQ3 ] & = ~ RQ3_ZCAM ;
}
return ;
} else if ( client - > sess . spectatorState = = SPECTATOR_FREE & & OKtoFollow ( clientNum ) ) {
2002-03-30 02:29:43 +00:00
client - > sess . spectatorState = SPECTATOR_ZCAM ;
client - > specMode = SPECTATOR_ZCAM ;
2002-03-30 17:37:49 +00:00
client - > camera - > mode = CAMERA_MODE_SWING ;
2002-03-30 02:29:43 +00:00
client - > ps . stats [ STAT_RQ3 ] | = RQ3_ZCAM ;
client - > ps . pm_flags & = ~ PMF_FOLLOW ;
CameraSwingCycle ( ent , 1 ) ;
RQ3_SpectatorMode ( ent ) ;
2002-03-30 17:37:49 +00:00
} else if ( client - > sess . spectatorState = = SPECTATOR_ZCAM & & client - > camera - > mode = = CAMERA_MODE_SWING
2002-06-16 20:06:15 +00:00
& & OKtoFollow ( clientNum ) ) {
2002-03-30 17:37:49 +00:00
client - > sess . spectatorState = SPECTATOR_ZCAM ;
client - > specMode = SPECTATOR_ZCAM ;
client - > camera - > mode = CAMERA_MODE_FLIC ;
client - > ps . stats [ STAT_RQ3 ] | = RQ3_ZCAM ;
client - > ps . pm_flags & = ~ PMF_FOLLOW ;
2002-06-16 20:06:15 +00:00
CameraFlicBegin ( ent ) ;
2002-03-30 17:37:49 +00:00
RQ3_SpectatorMode ( ent ) ;
2002-03-30 02:29:43 +00:00
} else if ( client - > sess . spectatorState = = SPECTATOR_ZCAM & & OKtoFollow ( clientNum ) ) {
client - > sess . spectatorState = SPECTATOR_FOLLOW ;
client - > specMode = SPECTATOR_FOLLOW ;
client - > ps . pm_flags | = PMF_FOLLOW ;
client - > ps . stats [ STAT_RQ3 ] & = ~ RQ3_ZCAM ;
Cmd_FollowCycle_f ( ent , 1 ) ;
RQ3_SpectatorMode ( ent ) ;
2002-03-30 02:54:24 +00:00
} else if ( client - > sess . spectatorState = = SPECTATOR_FOLLOW ) {
2002-03-30 02:29:43 +00:00
client - > sess . spectatorState = SPECTATOR_FREE ;
client - > specMode = SPECTATOR_FREE ;
client - > ps . pm_flags & = ~ PMF_FOLLOW ;
client - > ps . stats [ STAT_RQ3 ] & = ~ RQ3_ZCAM ;
StopFollowing ( ent ) ;
RQ3_SpectatorMode ( ent ) ;
}
}
}
2001-05-06 20:50:27 +00:00
/*
= = = = = = = = = = = = = = = = =
ClientInactivityTimer
Returns qfalse if the client is dropped
= = = = = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
qboolean ClientInactivityTimer ( gclient_t * client )
{
if ( ! g_inactivity . integer ) {
2001-05-06 20:50:27 +00:00
// 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 ;
2002-06-16 20:06:15 +00:00
} else if ( client - > pers . cmd . forwardmove | |
client - > pers . cmd . rightmove | |
client - > pers . cmd . upmove | | ( client - > pers . cmd . buttons & BUTTON_ATTACK ) ) {
2001-05-06 20:50:27 +00:00
client - > inactivityTime = level . time + g_inactivity . integer * 1000 ;
client - > inactivityWarning = qfalse ;
2002-06-16 20:06:15 +00:00
} else if ( ! client - > pers . localClient ) {
if ( level . time > client - > inactivityTime ) {
trap_DropClient ( client - level . clients , " Dropped due to inactivity " ) ;
2001-05-06 20:50:27 +00:00
return qfalse ;
}
2002-06-16 20:06:15 +00:00
if ( level . time > client - > inactivityTime - 10000 & & ! client - > inactivityWarning ) {
2001-05-06 20:50:27 +00:00
client - > inactivityWarning = qtrue ;
2002-06-16 20:06:15 +00:00
trap_SendServerCommand ( client - level . clients , " cp \" Ten seconds until inactivity drop! \n \" " ) ;
2001-05-06 20:50:27 +00:00
}
}
return qtrue ;
}
/*
= = = = = = = = = = = = = = = = = =
ClientTimerActions
Actions that happen once a second
= = = = = = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void ClientTimerActions ( gentity_t * ent , int msec )
{
2001-05-06 20:50:27 +00:00
gclient_t * client ;
client = ent - > client ;
client - > timeResidual + = msec ;
2002-06-16 20:06:15 +00:00
while ( client - > timeResidual > = 1000 ) {
2001-05-06 20:50:27 +00:00
client - > timeResidual - = 1000 ;
2002-07-22 06:35:03 +00:00
// count down health when over max
if ( ent - > health > 100 ) { //max is 100 client->ps.stats[STAT_MAX_HEALTH] ) {
ent - > health - - ;
2001-05-06 20:50:27 +00:00
}
// count down armor when over max
2002-06-16 20:06:15 +00:00
if ( client - > ps . stats [ STAT_ARMOR ] > 100 ) { // max is 100 client->ps.stats[STAT_MAX_HEALTH] ) {
2001-05-06 20:50:27 +00:00
client - > ps . stats [ STAT_ARMOR ] - - ;
}
//Blaze: Do bandaging stuff
2002-06-16 20:06:15 +00:00
if ( ent - > client - > bleedtick > 1 ) {
2001-07-24 01:50:01 +00:00
//G_Printf("Bleedtick (%d) getting lowered by one (%d)\n", ent->client->bleedtick, client->timeResidual);
2001-05-06 20:50:27 +00:00
ent - > client - > bleedtick - - ;
2002-06-16 20:06:15 +00:00
} else if ( ent - > client - > bleedtick = = 1 ) {
2001-05-06 20:50:27 +00:00
ent - > client - > bleed_remain = 0 ;
ent - > client - > bleeding = 0 ;
ent - > client - > bleedtick = 0 ;
2001-06-11 23:23:46 +00:00
//Elder: moved from somewhere - err, g_cmds.c I think
ent - > client - > ps . stats [ STAT_RQ3 ] & = ~ RQ3_LEGDAMAGE ;
2001-11-25 23:04:08 +00:00
// NiceAss: clear last player to hit you.
ent - > client - > lasthurt_mod = 0 ;
2001-05-06 20:50:27 +00:00
}
}
}
/*
= = = = = = = = = = = = = = = = = = = =
ClientIntermissionThink
= = = = = = = = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void ClientIntermissionThink ( gclient_t * client )
{
2001-05-06 20:50:27 +00:00
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 ;
2002-06-16 20:06:15 +00:00
if ( client - > buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) & ( client - > oldbuttons ^ client - > buttons ) ) {
2001-05-06 20:50:27 +00:00
// 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
= = = = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void ClientEvents ( gentity_t * ent , int oldEventSequence )
{
int i , j ;
int event ;
2001-05-06 20:50:27 +00:00
gclient_t * client ;
2002-06-16 20:06:15 +00:00
int damage ;
vec3_t dir ;
vec3_t origin , angles ;
2001-05-06 20:50:27 +00:00
gitem_t * item ;
gentity_t * drop ;
client = ent - > client ;
2002-06-16 20:06:15 +00:00
if ( oldEventSequence < client - > ps . eventSequence - MAX_PS_EVENTS ) {
2001-05-06 20:50:27 +00:00
oldEventSequence = client - > ps . eventSequence - MAX_PS_EVENTS ;
}
2002-06-16 20:06:15 +00:00
for ( i = oldEventSequence ; i < client - > ps . eventSequence ; i + + ) {
event = client - > ps . events [ i & ( MAX_PS_EVENTS - 1 ) ] ;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
switch ( event ) {
2001-05-06 20:50:27 +00:00
case EV_FALL_MEDIUM :
case EV_FALL_FAR :
2002-06-16 20:06:15 +00:00
if ( ent - > s . eType ! = ET_PLAYER ) {
break ; // not in the player model
2001-05-06 20:50:27 +00:00
}
2002-06-16 20:06:15 +00:00
if ( g_dmflags . integer & DF_NO_FALLING ) {
2001-05-06 20:50:27 +00:00
break ;
}
2002-02-22 02:13:13 +00:00
// JBravo: fix falling pain during lca
2002-10-26 22:03:43 +00:00
if ( g_gametype . integer > = GT_TEAM & & level . lights_camera_action ) {
2002-02-22 02:13:13 +00:00
break ;
}
2001-05-06 20:50:27 +00:00
damage = ent - > client - > ps . stats [ STAT_FALLDAMAGE ] ;
2002-06-16 20:06:15 +00:00
VectorSet ( dir , 0 , 0 , 1 ) ;
2001-05-06 20:50:27 +00:00
ent - > pain_debounce_time = level . time + 200 ; // no normal pain sound
2001-07-09 00:32:10 +00:00
//Elder: added so we can trigger AQ2 pain blends
ent - > client - > ps . damageEvent + + ;
2001-08-01 18:28:38 +00:00
ent - > client - > ps . damageCount + = damage ;
2002-06-16 20:06:15 +00:00
if ( ent - > client - > lasthurt_mod ! = 0 ) {
2002-09-24 05:06:17 +00:00
//Blaze: Print out some debug info
if ( & g_entities [ ent - > client - > lasthurt_client ] = = NULL ) G_Printf ( " Ln 0748 \n " ) ;
G_Damage ( ent , & g_entities [ ent - > client - > lasthurt_client ] ,
2002-06-16 20:06:15 +00:00
& g_entities [ ent - > client - > lasthurt_client ] , NULL , NULL , damage , 0 , MOD_FALLING ) ;
} else {
G_Damage ( ent , NULL , NULL , NULL , NULL , damage , 0 , MOD_FALLING ) ;
2001-10-28 01:17:03 +00:00
}
2001-11-11 23:59:17 +00:00
2001-05-06 20:50:27 +00:00
break ;
2001-07-27 00:21:23 +00:00
case EV_FALL_FAR_NOSOUND :
2002-06-16 20:06:15 +00:00
if ( ent - > s . eType ! = ET_PLAYER ) {
break ; // not in the player model
2001-07-27 00:21:23 +00:00
}
2002-06-16 20:06:15 +00:00
if ( g_dmflags . integer & DF_NO_FALLING ) {
2001-07-27 00:21:23 +00:00
break ;
}
2002-02-22 02:13:13 +00:00
// JBravo: fix falling pain during lca again
2002-10-26 22:03:43 +00:00
if ( g_gametype . integer > = GT_TEAM & & level . lights_camera_action ) {
2002-02-22 02:13:13 +00:00
break ;
}
2001-07-27 00:21:23 +00:00
damage = ent - > client - > ps . stats [ STAT_FALLDAMAGE ] ;
2002-06-16 20:06:15 +00:00
VectorSet ( dir , 0 , 0 , 1 ) ;
2001-07-27 00:21:23 +00:00
ent - > pain_debounce_time = level . time + 200 ; // no normal pain sound
//Elder: added so we can trigger AQ2 pain blends
ent - > client - > ps . damageEvent + + ;
2001-08-01 18:28:38 +00:00
ent - > client - > ps . damageCount + = damage ;
2002-06-16 20:06:15 +00:00
if ( ent - > client - > lasthurt_mod ! = 0 ) {
2002-09-24 05:06:17 +00:00
//Blaze: Print out some debug info
if ( & g_entities [ ent - > client - > lasthurt_client ] = = NULL ) G_Printf ( " Ln 0779 \n " ) ;
2002-06-16 20:06:15 +00:00
G_Damage ( ent , & g_entities [ ent - > client - > lasthurt_client ] ,
& g_entities [ ent - > client - > lasthurt_client ] , NULL , NULL , damage , 0 , MOD_FALLING ) ;
} else {
G_Damage ( ent , NULL , NULL , NULL , NULL , damage , 0 , MOD_FALLING ) ;
2001-10-28 01:17:03 +00:00
}
2001-11-11 23:59:17 +00:00
2001-07-27 00:21:23 +00:00
break ;
2001-05-06 20:50:27 +00:00
case EV_FIRE_WEAPON :
2002-06-16 20:06:15 +00:00
FireWeapon ( ent ) ;
2001-08-30 09:47:39 +00:00
break ;
case EV_RELOAD_WEAPON1 :
2002-06-16 20:06:15 +00:00
ReloadWeapon ( ent , 1 ) ;
2001-08-30 09:47:39 +00:00
break ;
case EV_RELOAD_WEAPON2 :
2002-06-16 20:06:15 +00:00
ReloadWeapon ( ent , 2 ) ;
2001-08-30 09:47:39 +00:00
break ;
2001-05-06 20:50:27 +00:00
case EV_CHANGE_WEAPON :
2001-06-08 04:47:30 +00:00
//Elder: not a good place to put stuff
2001-05-06 20:50:27 +00:00
break ;
2002-06-16 20:06:15 +00:00
case EV_USE_ITEM1 : // teleporter
2001-05-06 20:50:27 +00:00
// drop flags in CTF
item = NULL ;
j = 0 ;
2002-06-16 20:06:15 +00:00
if ( ent - > client - > ps . powerups [ PW_REDFLAG ] ) {
item = BG_FindItemForPowerup ( PW_REDFLAG ) ;
2001-05-06 20:50:27 +00:00
j = PW_REDFLAG ;
2002-06-16 20:06:15 +00:00
} else if ( ent - > client - > ps . powerups [ PW_BLUEFLAG ] ) {
item = BG_FindItemForPowerup ( PW_BLUEFLAG ) ;
2001-05-06 20:50:27 +00:00
j = PW_BLUEFLAG ;
2002-06-16 20:06:15 +00:00
} else if ( ent - > client - > ps . powerups [ PW_NEUTRALFLAG ] ) {
item = BG_FindItemForPowerup ( PW_NEUTRALFLAG ) ;
2001-05-06 20:50:27 +00:00
j = PW_NEUTRALFLAG ;
}
2002-06-16 20:06:15 +00:00
if ( item ) {
drop = Drop_Item ( ent , item , 0 ) ;
2001-05-06 20:50:27 +00:00
// decide how many seconds it has left
2002-06-16 20:06:15 +00:00
drop - > count = ( ent - > client - > ps . powerups [ j ] - level . time ) / 1000 ;
if ( drop - > count < 1 ) {
2001-05-06 20:50:27 +00:00
drop - > count = 1 ;
}
2002-06-16 20:06:15 +00:00
ent - > client - > ps . powerups [ j ] = 0 ;
2001-05-06 20:50:27 +00:00
}
2002-06-16 20:06:15 +00:00
SelectSpawnPoint ( ent - > client - > ps . origin , origin , angles ) ;
TeleportPlayer ( ent , origin , angles ) ;
2001-05-06 20:50:27 +00:00
break ;
2002-06-16 20:06:15 +00:00
case EV_USE_ITEM2 : // medkit
ent - > health = 125 ; //ent->client->ps.stats[STAT_MAX_HEALTH] + 25;
2001-05-06 20:50:27 +00:00
break ;
default :
break ;
}
}
}
2001-08-01 19:52:17 +00:00
void BotTestSolid ( vec3_t origin ) ;
2002-06-16 20:06:15 +00:00
2001-05-06 20:50:27 +00:00
/*
= = = = = = = = = = = = =
ThrowWeapon
XRAY FMJ
2001-08-13 17:26:53 +00:00
Returns the number of the weapon thrown
2001-05-06 20:50:27 +00:00
= = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
int ThrowWeapon ( gentity_t * ent , qboolean forceThrow )
2001-05-06 20:50:27 +00:00
{
2002-06-16 20:06:15 +00:00
gclient_t * client ;
usercmd_t * ucmd ;
gitem_t * xr_item ;
gentity_t * xr_drop ;
2001-05-06 20:50:27 +00:00
int weap ;
client = ent - > client ;
ucmd = & ent - > client - > pers . cmd ;
2001-08-13 17:26:53 +00:00
if ( ! forceThrow )
2002-03-23 21:29:42 +00:00
if ( ( ucmd - > buttons & BUTTON_ATTACK ) | | client - > ps . weaponTime > 0 )
2001-08-13 17:26:53 +00:00
return 0 ;
2001-11-11 07:24:27 +00:00
//Elder: remove zoom bits
Cmd_Unzoom ( ent ) ;
2001-11-11 23:59:17 +00:00
2002-07-02 19:15:17 +00:00
// JBravo: simulate AQ drop weapon for akimbo with no special weap
if ( client - > ps . weapon = = WP_AKIMBO & & client - > uniqueWeapons = = 0 ) {
trap_SendServerCommand ( ent - g_entities , va ( " stuff weapon %i \n " , WP_PISTOL ) ) ;
return 0 ;
}
2001-06-10 06:46:06 +00:00
weap = 0 ;
2002-06-16 20:06:15 +00:00
if ( client - > uniqueWeapons > 0 ) {
if ( client - > ps . weapon = = WP_AKIMBO | | client - > ps . weapon = = WP_PISTOL | | client - > ps . weapon = = WP_GRENADE | | client - > ps . weapon = = WP_KNIFE | | client - > ps . weapon = = WP_NONE ) // shouldn't have to worry about NONE, but just in case
2001-09-11 00:12:29 +00:00
{
weap = client - > ps . stats [ STAT_WEAPONS ] ;
2002-06-16 20:06:15 +00:00
if ( ( client - > ps . stats [ STAT_WEAPONS ] & ( 1 < < WP_M4 ) ) = = ( 1 < < WP_M4 ) )
2001-09-11 00:12:29 +00:00
weap = WP_M4 ;
2002-06-16 20:06:15 +00:00
if ( ( client - > ps . stats [ STAT_WEAPONS ] & ( 1 < < WP_M3 ) ) = = ( 1 < < WP_M3 ) )
2001-09-11 00:12:29 +00:00
weap = WP_M3 ;
2002-06-16 20:06:15 +00:00
if ( ( client - > ps . stats [ STAT_WEAPONS ] & ( 1 < < WP_MP5 ) ) = = ( 1 < < WP_MP5 ) )
2001-09-11 00:12:29 +00:00
weap = WP_MP5 ;
2002-06-16 20:06:15 +00:00
if ( ( client - > ps . stats [ STAT_WEAPONS ] & ( 1 < < WP_HANDCANNON ) ) = = ( 1 < < WP_HANDCANNON ) )
2001-09-11 00:12:29 +00:00
weap = WP_HANDCANNON ;
2002-06-16 20:06:15 +00:00
if ( ( client - > ps . stats [ STAT_WEAPONS ] & ( 1 < < WP_SSG3000 ) ) = = ( 1 < < WP_SSG3000 ) )
2001-09-11 00:12:29 +00:00
weap = WP_SSG3000 ;
2002-06-16 20:06:15 +00:00
if ( weap = = 0 )
2001-09-11 00:12:29 +00:00
return 0 ;
2002-03-23 21:29:42 +00:00
} else {
2001-09-11 00:12:29 +00:00
weap = client - > ps . weapon ;
}
2001-08-13 17:26:53 +00:00
2002-06-16 20:06:15 +00:00
xr_item = BG_FindItemForWeapon ( weap ) ;
2001-11-11 23:59:17 +00:00
2001-06-24 02:08:15 +00:00
client - > pers . hadUniqueWeapon [ weap ] = qtrue ;
2001-11-11 23:59:17 +00:00
2001-08-17 20:48:18 +00:00
//Elder: for immediate weapon drops
2002-06-16 20:06:15 +00:00
if ( client - > ps . weapon = = weap ) {
2001-08-17 20:48:18 +00:00
client - > ps . stats [ STAT_RQ3 ] | = RQ3_THROWWEAPON ;
2002-06-16 20:06:15 +00:00
trap_SendServerCommand ( ent - g_entities , va ( " rq3_cmd %i " , SELECTPISTOL ) ) ;
2001-08-17 20:48:18 +00:00
}
2001-11-11 23:59:17 +00:00
2001-09-11 00:12:29 +00:00
client - > weaponCount [ weap ] - - ;
if ( client - > weaponCount [ weap ] = = 0 )
2002-06-16 20:06:15 +00:00
client - > ps . stats [ STAT_WEAPONS ] & = ~ ( 1 < < weap ) ;
2001-09-11 00:12:29 +00:00
2002-06-16 20:06:15 +00:00
xr_drop = dropWeapon ( ent , xr_item , 0 , FL_DROPPED_ITEM | FL_THROWN_ITEM ) ;
xr_drop - > count = - 1 ; // XRAY FMJ 0 is already taken, -1 means no ammo
2001-11-12 09:01:21 +00:00
// remember who dropped you, child!
xr_drop - > s . otherEntityNum = client - > ps . clientNum ;
2001-07-28 14:12:11 +00:00
client - > uniqueWeapons - - ;
}
2001-08-13 17:26:53 +00:00
return weap ;
2001-07-28 14:12:11 +00:00
}
/*
2001-08-01 19:52:17 +00:00
= = = = = = = = = = = = = =
2001-07-28 14:12:11 +00:00
ThrowItem
Used to toss an item much like weapons except a bit leaner
2001-08-06 19:15:00 +00:00
You can throw items ANY time ( firing , bandaging , etc . )
2001-07-28 14:12:11 +00:00
= = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void ThrowItem ( gentity_t * ent )
2001-07-28 14:12:11 +00:00
{
2002-06-16 20:06:15 +00:00
gclient_t * client ;
gitem_t * xr_item ;
gentity_t * xr_drop ;
2002-10-26 22:03:43 +00:00
// int item;
2001-07-28 14:12:11 +00:00
client = ent - > client ;
//itemonTime > 0 or itemonState == itemon_dropping? Or both?
//item = 0;
2001-08-06 19:15:00 +00:00
2002-10-26 00:37:18 +00:00
// JBravo: New drop item code for multiple items.
2002-06-16 20:06:15 +00:00
if ( client - > uniqueItems > 0 ) {
2002-10-26 00:37:18 +00:00
if ( g_gametype . integer > = GT_TEAM ) {
if ( client - > ps . stats [ STAT_HOLDABLE_ITEM ] & ( 1 < < client - > teamplayItem ) ) {
xr_item = BG_FindItemForHoldable ( client - > teamplayItem ) ;
xr_drop = dropWeapon ( ent , xr_item , 0 , FL_DROPPED_ITEM | FL_THROWN_ITEM ) ;
xr_drop - > count = - 1 ;
client - > ps . stats [ STAT_HOLDABLE_ITEM ] & = ~ ( 1 < < client - > teamplayItem ) ;
client - > uniqueItems - - ;
2002-11-13 00:50:38 +00:00
return ;
2002-10-26 00:37:18 +00:00
}
}
if ( client - > ps . stats [ STAT_HOLDABLE_ITEM ] & ( 1 < < HI_BANDOLIER ) ) {
xr_item = BG_FindItemForHoldable ( HI_BANDOLIER ) ;
xr_drop = dropWeapon ( ent , xr_item , 0 , FL_DROPPED_ITEM | FL_THROWN_ITEM ) ;
xr_drop - > count = - 1 ;
client - > ps . stats [ STAT_HOLDABLE_ITEM ] & = ~ ( 1 < < HI_BANDOLIER ) ;
client - > uniqueItems - - ;
2002-11-13 00:50:38 +00:00
return ;
2002-10-26 00:37:18 +00:00
} else if ( client - > ps . stats [ STAT_HOLDABLE_ITEM ] & ( 1 < < HI_SLIPPERS ) ) {
xr_item = BG_FindItemForHoldable ( HI_SLIPPERS ) ;
xr_drop = dropWeapon ( ent , xr_item , 0 , FL_DROPPED_ITEM | FL_THROWN_ITEM ) ;
xr_drop - > count = - 1 ;
client - > ps . stats [ STAT_HOLDABLE_ITEM ] & = ~ ( 1 < < HI_SLIPPERS ) ;
client - > uniqueItems - - ;
2002-11-13 00:50:38 +00:00
return ;
2002-10-26 00:37:18 +00:00
} else if ( client - > ps . stats [ STAT_HOLDABLE_ITEM ] & ( 1 < < HI_SILENCER ) ) {
xr_item = BG_FindItemForHoldable ( HI_SILENCER ) ;
xr_drop = dropWeapon ( ent , xr_item , 0 , FL_DROPPED_ITEM | FL_THROWN_ITEM ) ;
xr_drop - > count = - 1 ;
client - > ps . stats [ STAT_HOLDABLE_ITEM ] & = ~ ( 1 < < HI_SILENCER ) ;
client - > uniqueItems - - ;
2002-11-13 00:50:38 +00:00
return ;
2002-10-30 21:24:47 +00:00
// JBravo: adding the helmet :)
2002-10-30 20:04:34 +00:00
} else if ( client - > ps . stats [ STAT_HOLDABLE_ITEM ] & ( 1 < < HI_HELMET ) ) {
xr_item = BG_FindItemForHoldable ( HI_HELMET ) ;
xr_drop = dropWeapon ( ent , xr_item , 0 , FL_DROPPED_ITEM | FL_THROWN_ITEM ) ;
xr_drop - > count = - 1 ;
client - > ps . stats [ STAT_HOLDABLE_ITEM ] & = ~ ( 1 < < HI_HELMET ) ;
client - > uniqueItems - - ;
2002-11-13 00:50:38 +00:00
return ;
2002-10-26 00:37:18 +00:00
} else if ( client - > ps . stats [ STAT_HOLDABLE_ITEM ] & ( 1 < < HI_LASER ) ) {
xr_item = BG_FindItemForHoldable ( HI_LASER ) ;
xr_drop = dropWeapon ( ent , xr_item , 0 , FL_DROPPED_ITEM | FL_THROWN_ITEM ) ;
xr_drop - > count = - 1 ;
client - > ps . stats [ STAT_HOLDABLE_ITEM ] & = ~ ( 1 < < HI_LASER ) ;
client - > uniqueItems - - ;
2002-11-13 00:50:38 +00:00
return ;
2002-10-26 00:37:18 +00:00
} else if ( client - > ps . stats [ STAT_HOLDABLE_ITEM ] & ( 1 < < HI_KEVLAR ) ) {
xr_item = BG_FindItemForHoldable ( HI_KEVLAR ) ;
xr_drop = dropWeapon ( ent , xr_item , 0 , FL_DROPPED_ITEM | FL_THROWN_ITEM ) ;
xr_drop - > count = - 1 ;
client - > ps . stats [ STAT_HOLDABLE_ITEM ] & = ~ ( 1 < < HI_KEVLAR ) ;
client - > uniqueItems - - ;
2002-11-13 00:50:38 +00:00
return ;
2002-10-26 00:37:18 +00:00
}
2001-05-06 20:50:27 +00:00
}
}
2001-08-01 19:52:17 +00:00
/*
= = = = = = = = = = = = = =
SendPendingPredictableEvents
= = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void SendPendingPredictableEvents ( playerState_t * ps )
{
2001-08-01 19:52:17 +00:00
gentity_t * t ;
int event , seq ;
int extEvent , number ;
// if there are still events pending
2002-06-16 20:06:15 +00:00
if ( ps - > entityEventSequence < ps - > eventSequence ) {
2001-08-01 19:52:17 +00:00
// create a temporary entity for this event which is sent to everyone
// except the client who generated the event
2002-06-16 20:06:15 +00:00
seq = ps - > entityEventSequence & ( MAX_PS_EVENTS - 1 ) ;
event = ps - > events [ seq ] | ( ( ps - > entityEventSequence & 3 ) < < 8 ) ;
2001-08-01 19:52:17 +00:00
// set external event to zero before calling BG_PlayerStateToEntityState
extEvent = ps - > externalEvent ;
ps - > externalEvent = 0 ;
// create temporary entity for event
2002-06-16 20:06:15 +00:00
t = G_TempEntity ( ps - > origin , event ) ;
2001-08-01 19:52:17 +00:00
number = t - > s . number ;
2002-06-16 20:06:15 +00:00
BG_PlayerStateToEntityState ( ps , & t - > s , qtrue ) ;
2001-08-01 19:52:17 +00:00
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 ;
}
}
2001-05-06 20:50:27 +00:00
/*
= = = = = = = = = = = = = =
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 .
= = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void ClientThink_real ( gentity_t * ent )
{
gclient_t * client ;
pmove_t pm ;
int oldEventSequence ;
int msec ;
usercmd_t * ucmd ;
2001-05-06 20:50:27 +00:00
int bJumping = 0 ;
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
2002-06-16 20:06:15 +00:00
if ( ucmd - > serverTime > level . time + 200 ) {
2001-05-06 20:50:27 +00:00
ucmd - > serverTime = level . time + 200 ;
}
2002-06-16 20:06:15 +00:00
if ( ucmd - > serverTime < level . time - 1000 ) {
2001-05-06 20:50:27 +00:00
ucmd - > serverTime = level . time - 1000 ;
2001-11-11 23:59:17 +00:00
}
2003-03-09 21:30:39 +00:00
client - > lastUpdateFrame = level . framenum ;
2001-05-06 20:50:27 +00:00
msec = ucmd - > serverTime - client - > ps . commandTime ;
// following others may result in bad times, but we still want
// to check for follow toggles
2002-06-16 20:06:15 +00:00
if ( msec < 1 & & client - > sess . spectatorState ! = SPECTATOR_FOLLOW ) {
2001-05-06 20:50:27 +00:00
return ;
}
2002-06-16 20:06:15 +00:00
if ( msec > 200 ) {
2001-05-06 20:50:27 +00:00
msec = 200 ;
}
2002-06-16 20:06:15 +00:00
if ( pmove_msec . integer < 8 ) {
2001-05-06 20:50:27 +00:00
trap_Cvar_Set ( " pmove_msec " , " 8 " ) ;
2002-06-16 20:06:15 +00:00
} else if ( pmove_msec . integer > 33 ) {
2001-05-06 20:50:27 +00:00
trap_Cvar_Set ( " pmove_msec " , " 33 " ) ;
}
2002-06-16 20:06:15 +00:00
if ( pmove_fixed . integer | | client - > pers . pmoveFixed ) {
ucmd - > serverTime =
( ( ucmd - > serverTime + pmove_msec . integer - 1 ) / pmove_msec . integer ) * pmove_msec . integer ;
2001-05-06 20:50:27 +00:00
}
//
// check for exiting intermission
//
2002-06-16 20:06:15 +00:00
if ( level . intermissiontime ) {
ClientIntermissionThink ( client ) ;
2001-05-06 20:50:27 +00:00
return ;
}
// spectators don't do much
2002-06-16 20:06:15 +00:00
if ( client - > sess . sessionTeam = = TEAM_SPECTATOR ) {
if ( client - > sess . spectatorState = = SPECTATOR_SCOREBOARD ) {
2001-05-06 20:50:27 +00:00
return ;
}
2002-06-16 20:06:15 +00:00
SpectatorThink ( ent , ucmd ) ;
2001-05-06 20:50:27 +00:00
return ;
}
// check for inactivity timer, but never drop the local client of a non-dedicated server
2002-06-16 20:06:15 +00:00
if ( ! ClientInactivityTimer ( client ) ) {
2001-05-06 20:50:27 +00:00
return ;
}
// clear the rewards if time
2002-06-16 20:06:15 +00:00
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 ) ;
2001-05-06 20:50:27 +00:00
}
2002-06-16 20:06:15 +00:00
if ( client - > noclip ) {
2001-05-06 20:50:27 +00:00
client - > ps . pm_type = PM_NOCLIP ;
2002-06-16 20:06:15 +00:00
} else if ( client - > ps . stats [ STAT_HEALTH ] < = 0 ) {
2001-05-06 20:50:27 +00:00
client - > ps . pm_type = PM_DEAD ;
} else {
client - > ps . pm_type = PM_NORMAL ;
}
client - > ps . gravity = g_gravity . value ;
// set speed
2001-08-01 19:52:17 +00:00
client - > ps . speed = g_speed . value ;
2001-05-06 20:50:27 +00:00
// set up for pmove
oldEventSequence = client - > ps . eventSequence ;
2002-06-16 20:06:15 +00:00
memset ( & pm , 0 , sizeof ( pm ) ) ;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
if ( ent - > flags & FL_FORCE_GESTURE ) {
2001-05-06 20:50:27 +00:00
ent - > flags & = ~ FL_FORCE_GESTURE ;
ent - > client - > pers . cmd . buttons | = BUTTON_GESTURE ;
}
2001-11-11 07:24:27 +00:00
//Elder: 3rb Code moved to bg_pmove.c (resides in PM_Weapon)
2001-07-24 01:50:01 +00:00
2001-05-06 20:50:27 +00:00
pm . ps = & client - > ps ;
pm . cmd = * ucmd ;
2002-02-08 18:59:01 +00:00
2002-06-16 20:06:15 +00:00
if ( pm . ps - > pm_type = = PM_DEAD ) {
2001-05-06 20:50:27 +00:00
pm . tracemask = MASK_PLAYERSOLID & ~ CONTENTS_BODY ;
2002-06-16 20:06:15 +00:00
} else if ( ent - > r . svFlags & SVF_BOT ) {
2001-05-06 20:50:27 +00:00
pm . tracemask = MASK_PLAYERSOLID | CONTENTS_BOTCLIP ;
2002-06-16 20:06:15 +00:00
} else {
2001-05-06 20:50:27 +00:00
pm . tracemask = MASK_PLAYERSOLID ;
}
2002-01-11 20:20:58 +00:00
// JBravo: fixing telefragging and shit during spawnig. (Thanks NiceAss! :)
2002-11-13 00:50:38 +00:00
if ( ( g_gametype . integer = = GT_TEAMPLAY | | g_gametype . integer = = GT_TEAM ) & &
2002-06-16 20:06:15 +00:00
( ( ent - > client - > ps . stats [ STAT_RQ3 ] & RQ3_PLAYERSOLID ) ! = RQ3_PLAYERSOLID ) & & ! level . lights_camera_action ) {
UnstickPlayer ( ent ) ;
2002-01-29 03:13:45 +00:00
}
2002-11-13 00:50:38 +00:00
if ( ( g_gametype . integer = = GT_TEAMPLAY | | g_gametype . integer = = GT_TEAM ) & &
2002-06-16 20:06:15 +00:00
( ( ent - > client - > ps . stats [ STAT_RQ3 ] & RQ3_PLAYERSOLID ) ! = RQ3_PLAYERSOLID ) ) {
2002-01-11 20:20:58 +00:00
pm . tracemask = MASK_PLAYERSOLID & ~ CONTENTS_BODY ;
}
2001-05-06 20:50:27 +00:00
pm . trace = trap_Trace ;
pm . pointcontents = trap_PointContents ;
pm . debugLevel = g_debugMove . integer ;
2002-06-16 20:06:15 +00:00
pm . noFootsteps = ( g_dmflags . integer & DF_NO_FOOTSTEPS ) > 0 ;
2001-05-06 20:50:27 +00:00
pm . pmove_fixed = pmove_fixed . integer | client - > pers . pmoveFixed ;
pm . pmove_msec = pmove_msec . integer ;
2002-06-16 20:06:15 +00:00
VectorCopy ( client - > ps . origin , client - > oldOrigin ) ;
2001-05-06 20:50:27 +00:00
2002-03-23 05:17:43 +00:00
// JBravo: setting lca in pm if appropriate
2002-06-16 20:06:15 +00:00
if ( g_RQ3_lca . integer = = 1 )
pm . lca = qtrue ;
else
pm . lca = qfalse ;
2002-07-21 18:52:39 +00:00
pm . predict = qtrue ;
2002-06-16 20:06:15 +00:00
Pmove ( & pm ) ;
if ( ( pm . cmd . upmove > 10 ) & &
( pm . waterlevel = = 0 ) & &
ent - > s . groundEntityNum ! = ENTITYNUM_NONE & & pm . ps - > groundEntityNum = = ENTITYNUM_NONE )
bJumping = 1 ;
2001-05-06 20:50:27 +00:00
// save results of pmove
2002-06-16 20:06:15 +00:00
if ( ent - > client - > ps . eventSequence ! = oldEventSequence ) {
2001-05-06 20:50:27 +00:00
ent - > eventTime = level . time ;
}
2003-04-19 15:27:31 +00:00
2003-03-09 21:30:39 +00:00
BG_PlayerStateToEntityState ( & ent - > client - > ps , & ent - > s , qtrue ) ;
2002-06-16 20:06:15 +00:00
SendPendingPredictableEvents ( & ent - > client - > ps ) ;
2001-08-01 19:52:17 +00:00
2002-06-16 20:06:15 +00:00
if ( ! ( ent - > client - > ps . eFlags & EF_FIRING ) ) {
client - > fireHeld = qfalse ; // for grapple
2001-05-06 20:50:27 +00:00
}
// use the snapped origin for linking so it matches client predicted versions
2002-06-16 20:06:15 +00:00
VectorCopy ( ent - > s . pos . trBase , ent - > r . currentOrigin ) ;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
VectorCopy ( pm . mins , ent - > r . mins ) ;
VectorCopy ( pm . maxs , ent - > r . maxs ) ;
2001-05-06 20:50:27 +00:00
ent - > waterlevel = pm . waterlevel ;
ent - > watertype = pm . watertype ;
// execute client events
2002-06-16 20:06:15 +00:00
ClientEvents ( ent , oldEventSequence ) ;
2001-05-06 20:50:27 +00:00
// link entity now, after any personal teleporters have been used
2002-06-05 15:17:51 +00:00
// JBravo: this call reactivates gibbed players.
if ( ! ent - > client - > gibbed )
2011-07-14 18:29:55 +00:00
trap_LinkEntity ( ent ) ;
2002-06-16 20:06:15 +00:00
if ( ! ent - > client - > noclip ) {
G_TouchTriggers ( ent ) ;
2001-05-06 20:50:27 +00:00
}
// NOTE: now copy the exact origin over otherwise clients can be snapped into solid
2002-06-16 20:06:15 +00:00
VectorCopy ( ent - > client - > ps . origin , ent - > r . currentOrigin ) ;
2001-05-06 20:50:27 +00:00
//test for solid areas in the AAS file
BotTestAAS ( ent - > r . currentOrigin ) ;
// touch other objects
2002-06-16 20:06:15 +00:00
ClientImpacts ( ent , & pm ) ;
2001-11-11 23:59:17 +00:00
2001-06-18 01:59:58 +00:00
//Elder: someone added
2002-06-16 20:06:15 +00:00
if ( bJumping )
JumpKick ( ent ) ;
2001-05-06 20:50:27 +00:00
// 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
2002-02-06 03:10:43 +00:00
// JBravo: Lets make dead players into spectators.
if ( client - > ps . stats [ STAT_HEALTH ] < = 0 ) {
2001-05-06 20:50:27 +00:00
// wait for the attack button to be pressed
2002-02-06 03:10:43 +00:00
if ( level . time > client - > respawnTime ) {
2001-05-06 20:50:27 +00:00
// forcerespawn is to prevent users from waiting out powerups
2002-02-06 03:10:43 +00:00
if ( g_forcerespawn . integer > 0 & &
2002-06-16 20:06:15 +00:00
( level . time - client - > respawnTime ) > g_forcerespawn . integer * 1000 & &
2002-07-24 02:17:38 +00:00
g_gametype . integer ! = GT_TEAMPLAY & & g_gametype . integer ! = GT_CTF ) {
2002-06-16 20:06:15 +00:00
respawn ( ent ) ;
return ;
2002-02-25 19:41:53 +00:00
}
2002-08-21 07:00:07 +00:00
if ( ( g_gametype . integer = = GT_TEAMPLAY | | g_gametype . integer = = GT_CTF ) & & level . time > client - > respawnTime ) {
2002-02-25 19:41:53 +00:00
MakeSpectator ( ent ) ;
2001-05-06 20:50:27 +00:00
}
// pressing attack or use is the normal respawn method
2002-02-06 03:10:43 +00:00
// JBravo: make'em spactate
2002-06-16 20:06:15 +00:00
if ( ucmd - > buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) ) {
2002-08-30 01:09:06 +00:00
if ( g_gametype . integer = = GT_TEAMPLAY | | g_gametype . integer = = GT_CTF ) {
2002-02-06 03:10:43 +00:00
MakeSpectator ( ent ) ;
} else {
2002-06-16 20:06:15 +00:00
respawn ( ent ) ;
2002-02-06 03:10:43 +00:00
}
2001-05-06 20:50:27 +00:00
}
}
return ;
}
2002-07-07 18:36:13 +00:00
// JBravo: Idle sounds
if ( g_RQ3_ppl_idletime . integer ) {
if ( ucmd - > forwardmove = = 0 & & ucmd - > rightmove = = 0 ) {
if ( client - > idletime ) {
2002-09-29 16:06:45 +00:00
if ( level . time > = client - > idletime + ( g_RQ3_ppl_idletime . integer * 1000 ) ) {
2002-10-26 22:03:43 +00:00
if ( g_gametype . integer > = GT_TEAM & & g_RQ3_idleaction . integer = = 1 & &
2002-07-07 18:36:13 +00:00
( ent - > client - > sess . sessionTeam = = TEAM_RED | | ent - > client - > sess . sessionTeam = = TEAM_BLUE ) ) {
trap_SendServerCommand ( - 1 , va ( " print \" Removing %s^7 from his team for excessive Idling \n \" " ,
ent - > client - > pers . netname ) ) ;
trap_SendServerCommand ( ent - g_entities , " stuff team none \n " ) ;
2002-10-26 22:03:43 +00:00
} else if ( g_gametype . integer > = GT_TEAM & & g_RQ3_idleaction . integer = = 2 & &
2002-07-07 18:36:13 +00:00
( ent - > client - > sess . sessionTeam = = TEAM_RED | | ent - > client - > sess . sessionTeam = = TEAM_BLUE ) ) {
trap_SendServerCommand ( - 1 , va ( " print \" Kicking %s^7 for excessive Idling \n \" " ,
ent - > client - > pers . netname ) ) ;
trap_DropClient ( ent - g_entities , " Dropped due to excessive Idling " ) ;
} else
G_TempEntity ( ent - > r . currentOrigin , EV_INSANESOUND ) ;
client - > idletime = 0 ;
}
} else {
client - > idletime = level . time ;
}
} else {
client - > idletime = 0 ;
}
}
2001-08-01 19:52:17 +00:00
// perform once-a-second actions
2002-06-16 20:06:15 +00:00
ClientTimerActions ( ent , msec ) ;
2001-05-06 20:50:27 +00:00
}
/*
= = = = = = = = = = = = = = = = = =
ClientThink
A new command has arrived from the client
= = = = = = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void ClientThink ( int clientNum )
{
2001-05-06 20:50:27 +00:00
gentity_t * ent ;
ent = g_entities + clientNum ;
2002-06-16 20:06:15 +00:00
trap_GetUsercmd ( clientNum , & ent - > client - > pers . cmd ) ;
2001-05-06 20:50:27 +00:00
// mark the time we got info, so we can display the
// phone jack if they don't get any for a while
2003-03-09 21:30:39 +00:00
// ent->client->lastCmdTime = level.time;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
/* camera jitter fix (server side) */
2002-02-26 02:58:47 +00:00
// JBravo: Take SPECTATOR_ZCAM into account
2002-06-16 20:06:15 +00:00
if ( ! ( ent - > r . svFlags & SVF_BOT ) & & ! g_synchronousClients . integer & &
( ent - > client - > sess . sessionTeam ! = TEAM_SPECTATOR | |
( ent - > client - > sess . sessionTeam = = TEAM_SPECTATOR & & ent - > client - > sess . spectatorState ! = SPECTATOR_ZCAM ) ) ) {
ClientThink_real ( ent ) ;
2001-05-06 20:50:27 +00:00
}
}
2002-06-16 20:06:15 +00:00
void G_RunClient ( gentity_t * ent )
{
/* camera jitter fix (server side) */
2002-02-26 02:58:47 +00:00
// JBravo: Take SPECTATOR_ZCAM into account
2002-06-16 20:06:15 +00:00
if ( ! ( ent - > r . svFlags & SVF_BOT ) & & ! g_synchronousClients . integer & &
( ent - > client - > sess . sessionTeam ! = TEAM_SPECTATOR | |
( ent - > client - > sess . sessionTeam = = TEAM_SPECTATOR & & ent - > client - > sess . spectatorState ! = SPECTATOR_ZCAM ) ) ) {
2001-05-06 20:50:27 +00:00
return ;
}
ent - > client - > pers . cmd . serverTime = level . time ;
2002-06-16 20:06:15 +00:00
ClientThink_real ( ent ) ;
2001-05-06 20:50:27 +00:00
}
/*
= = = = = = = = = = = = = = = = = =
SpectatorClientEndFrame
= = = = = = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void SpectatorClientEndFrame ( gentity_t * ent )
{
gclient_t * cl ;
int savedPing , savedFlags , i ;
2002-02-10 21:21:23 +00:00
int savedPers [ MAX_PERSISTANT ] ;
2001-05-06 20:50:27 +00:00
// if we are doing a chase cam or a remote view, grab the latest info
2002-06-16 20:06:15 +00:00
if ( ent - > client - > sess . spectatorState = = SPECTATOR_FOLLOW ) {
int clientNum , flags ;
2001-05-06 20:50:27 +00:00
clientNum = ent - > client - > sess . spectatorClient ;
// team follow1 and team follow2 go to whatever clients are playing
2002-06-16 20:06:15 +00:00
if ( clientNum = = - 1 ) {
2001-05-06 20:50:27 +00:00
clientNum = level . follow1 ;
2002-06-16 20:06:15 +00:00
} else if ( clientNum = = - 2 ) {
2001-05-06 20:50:27 +00:00
clientNum = level . follow2 ;
}
2002-06-16 20:06:15 +00:00
if ( clientNum > = 0 ) {
cl = & level . clients [ clientNum ] ;
if ( cl - > pers . connected = = CON_CONNECTED & & cl - > sess . sessionTeam ! = TEAM_SPECTATOR ) {
flags =
( cl - > ps . eFlags & ~ ( EF_VOTED | EF_TEAMVOTED ) ) | ( ent - > client - > ps .
eFlags & ( EF_VOTED | EF_TEAMVOTED ) ) ;
// JBravo: saving score and ping to fix the scoreboard
2002-02-06 03:10:43 +00:00
savedPing = ent - > client - > ps . ping ;
2002-02-10 21:21:23 +00:00
//Slicer saving pm_flags & pers
2002-02-09 18:27:44 +00:00
savedFlags = ent - > client - > ps . pm_flags ;
2002-06-16 20:06:15 +00:00
for ( i = 0 ; i < MAX_PERSISTANT ; i + + )
2002-02-10 21:21:23 +00:00
savedPers [ i ] = ent - > client - > ps . persistant [ i ] ;
//This will make the spectator get the client's stuff
2001-05-06 20:50:27 +00:00
ent - > client - > ps = cl - > ps ;
2002-02-06 12:06:48 +00:00
//Reposting score and ping..
2002-10-26 22:03:43 +00:00
if ( g_gametype . integer > = GT_TEAM ) {
2002-06-16 20:06:15 +00:00
for ( i = 0 ; i < MAX_PERSISTANT ; i + + )
2002-02-10 21:21:23 +00:00
ent - > client - > ps . persistant [ i ] = savedPers [ i ] ;
2002-06-16 20:06:15 +00:00
2002-02-06 12:06:48 +00:00
ent - > client - > ps . ping = savedPing ;
2002-02-09 18:27:44 +00:00
//Slicer reposting pmflags
ent - > client - > ps . pm_flags = savedFlags ;
2002-02-06 12:06:48 +00:00
}
2001-05-06 20:50:27 +00:00
ent - > client - > ps . pm_flags | = PMF_FOLLOW ;
ent - > client - > ps . eFlags = flags ;
return ;
} else {
// drop them to free spectators unless they are dedicated camera followers
2002-06-16 20:06:15 +00:00
if ( ent - > client - > sess . spectatorClient > = 0 ) {
2001-05-06 20:50:27 +00:00
ent - > client - > sess . spectatorState = SPECTATOR_FREE ;
2002-03-26 11:32:05 +00:00
// JBravo: saving spectatorState
ent - > client - > specMode = SPECTATOR_FREE ;
2002-06-16 20:06:15 +00:00
ClientBegin ( ent - > client - level . clients ) ;
2001-05-06 20:50:27 +00:00
}
}
}
}
2002-06-16 20:06:15 +00:00
if ( ent - > client - > sess . spectatorState = = SPECTATOR_SCOREBOARD ) {
2001-05-06 20:50:27 +00:00
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 .
= = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void ClientEndFrame ( gentity_t * ent )
{
2003-04-19 15:27:31 +00:00
int i , frames ;
2002-06-16 20:06:15 +00:00
clientPersistant_t * pers ;
2001-08-01 19:52:17 +00:00
2002-06-16 20:06:15 +00:00
if ( ent - > client - > sess . sessionTeam = = TEAM_SPECTATOR ) {
SpectatorClientEndFrame ( ent ) ;
2001-05-06 20:50:27 +00:00
return ;
}
pers = & ent - > client - > pers ;
// turn off any expired powerups
2002-06-16 20:06:15 +00:00
for ( i = 0 ; i < MAX_POWERUPS ; i + + ) {
if ( ent - > client - > ps . powerups [ i ] < level . time ) {
ent - > client - > ps . powerups [ i ] = 0 ;
2001-05-06 20:50:27 +00:00
}
}
// save network bandwidth
#if 0
2002-06-16 20:06:15 +00:00
if ( ! g_synchronousClients - > integer & & ent - > client - > ps . pm_type = = PM_NORMAL ) {
2001-05-06 20:50:27 +00:00
// FIXME: this must change eventually for non-sync demo recording
2002-06-16 20:06:15 +00:00
VectorClear ( ent - > client - > ps . viewangles ) ;
2001-05-06 20:50:27 +00:00
}
# endif
//
// If the end of unit layout is displayed, don't give
// the player any normal movement attributes
//
2002-06-16 20:06:15 +00:00
if ( level . intermissiontime ) {
2001-05-06 20:50:27 +00:00
return ;
}
2002-06-16 20:06:15 +00:00
if ( ent - > client - > bleeding )
2001-05-06 20:50:27 +00:00
CheckBleeding ( ent ) ; // perform once-a-second actions
// burn from lava, etc
2002-06-16 20:06:15 +00:00
P_WorldEffects ( ent ) ;
2001-05-06 20:50:27 +00:00
// apply all the damage taken this frame
2002-06-16 20:06:15 +00:00
P_DamageFeedback ( ent ) ;
2001-05-06 20:50:27 +00:00
2001-08-30 09:47:39 +00:00
// Update the clips Amount in weapon for the client
2002-06-16 20:06:15 +00:00
ent - > client - > ps . stats [ STAT_CLIPS ] = ent - > client - > numClips [ ent - > client - > ps . weapon ] ;
2001-05-06 20:50:27 +00:00
ent - > client - > ps . stats [ STAT_HEALTH ] = ent - > health ; // FIXME: get rid of ent->health...
2001-06-18 01:59:58 +00:00
//Elder: bleeding notification
2002-06-16 20:06:15 +00:00
if ( ent - > client - > bleeding | | ( ent - > client - > ps . stats [ STAT_RQ3 ] & RQ3_LEGDAMAGE ) = = RQ3_LEGDAMAGE ) {
2001-06-18 01:59:58 +00:00
ent - > client - > ps . stats [ STAT_RQ3 ] | = RQ3_BANDAGE_NEED ;
2002-06-16 20:06:15 +00:00
} else {
2001-06-18 01:59:58 +00:00
ent - > client - > ps . stats [ STAT_RQ3 ] & = ~ RQ3_BANDAGE_NEED ;
2001-06-11 23:23:46 +00:00
}
2001-06-08 04:47:30 +00:00
2001-07-03 10:26:42 +00:00
//Moved to pmove.c
2001-06-24 02:08:15 +00:00
//Elder: M4 ride-up/kick -- condition for non-burst and ammo only
2001-11-11 23:59:17 +00:00
2001-07-03 10:26:42 +00:00
if ( ent - > client - > consecutiveShots & &
2002-06-16 20:06:15 +00:00
( ent - > client - > ps . ammo [ WP_M4 ] < = 0 | | ent - > client - > ps . weaponstate ! = WEAPON_FIRING ) ) {
2001-07-03 10:26:42 +00:00
//Restore view after shots if not firing
2002-06-16 20:06:15 +00:00
ent - > client - > ps . delta_angles [ 0 ] =
2002-06-18 06:15:30 +00:00
ANGLE2SHORT ( SHORT2ANGLE ( ent - > client - > ps . delta_angles [ 0 ] ) - ent - > client - > consecutiveShots * - 0.8 ) ; //-0.7f);
2001-06-24 02:08:15 +00:00
ent - > client - > consecutiveShots = 0 ;
2001-07-01 20:20:56 +00:00
}
2001-08-13 17:26:53 +00:00
// Check to reset our openDoor boolean
2002-06-16 20:06:15 +00:00
if ( ent - > client - > openDoorTime & & level . time - ent - > client - > openDoorTime > MAXDOORTIME ) {
2001-08-13 17:26:53 +00:00
ent - > client - > openDoor = qfalse ;
ent - > client - > openDoorTime = 0 ;
}
2002-10-26 00:37:18 +00:00
// JBravo: multiple items
if ( ent - > client - > ps . stats [ STAT_HOLDABLE_ITEM ] & ( 1 < < HI_LASER ) ) {
2001-08-01 18:28:38 +00:00
//Try to turn the laser on if it's off
if ( ent - > client - > lasersight = = NULL )
2001-07-28 14:12:11 +00:00
Laser_Gen ( ent , qtrue ) ;
2001-11-11 23:59:17 +00:00
}
2002-04-01 22:23:14 +00:00
//Slicer
if ( ent - > client - > weapon_attempts > 0 )
2002-06-16 20:06:15 +00:00
Cmd_Weapon ( ent ) ;
2002-04-01 22:23:14 +00:00
2002-06-16 20:06:15 +00:00
G_SetClientSound ( ent ) ;
2003-03-09 21:30:39 +00:00
BG_PlayerStateToEntityState ( & ent - > client - > ps , & ent - > s , qtrue ) ;
2002-06-16 20:06:15 +00:00
SendPendingPredictableEvents ( & ent - > client - > ps ) ;
2003-03-09 21:30:39 +00:00
// JBravo: unlagged
ent - > client - > ps . eFlags & = ~ EF_CONNECTION ;
frames = level . framenum - ent - > client - > lastUpdateFrame - 1 ;
if ( frames > 2 ) {
frames = 2 ;
ent - > client - > ps . eFlags | = EF_CONNECTION ;
ent - > s . eFlags | = EF_CONNECTION ;
}
if ( frames > 0 & & g_smoothClients . integer ) {
G_PredictPlayerMove ( ent , ( float ) frames / sv_fps . integer ) ;
SnapVector ( ent - > s . pos . trBase ) ;
}
2001-05-06 20:50:27 +00:00
}