2001-12-31 16:16:59 +00:00
//-----------------------------------------------------------------------------
//
// $Id$
//
//-----------------------------------------------------------------------------
//
2001-12-31 16:28:42 +00:00
// $Log$
2002-08-23 14:25:05 +00:00
// Revision 1.112 2002/08/23 14:25:05 slicer
// Added a new Referee System with multiple ref support
//
2002-08-21 07:00:07 +00:00
// Revision 1.111 2002/08/21 07:00:07 jbravo
// Added CTB respawn queue and fixed game <-> cgame synch problem in CTB
//
2002-08-07 03:35:57 +00:00
// Revision 1.110 2002/08/07 03:35:57 jbravo
// Added dynamic radio and stopped all radio usage during lca
//
2002-07-26 22:28:38 +00:00
// Revision 1.109 2002/07/26 22:28:38 jbravo
// Fixed the server about menu, made the UI handle illegal models and skins
// better.
//
2002-07-26 06:21:43 +00:00
// Revision 1.108 2002/07/26 06:21:43 jbravo
// Fixed the MM settings stuff so it works on remote servers also.
// Removed the MM_NAMES_COLOR since it broke on nicks with color in them.
//
2002-07-16 04:09:14 +00:00
// Revision 1.107 2002/07/16 04:09:14 niceass
// stupid team scoreboard fix
//
2002-07-11 04:32:24 +00:00
// Revision 1.106 2002/07/11 04:32:24 niceass
// misc CTB changes for joining a team or becoming a spectator on map load. Also team check before weapon equip
//
2002-07-09 05:42:18 +00:00
// Revision 1.105 2002/07/09 05:42:18 niceass
// small change to userinfo
//
2002-07-02 03:41:59 +00:00
// Revision 1.104 2002/07/02 03:41:59 jbravo
// Fixed a 2 frags pr kill bug, the use cmd now cancels weaponchanges in progress
// and fixed the captain status lingering on people after switching from MM
//
2002-06-30 17:33:01 +00:00
// Revision 1.103 2002/06/30 17:33:01 jbravo
// New radio sounds and the 0wned sound was added.
//
2002-06-26 15:58:13 +00:00
// Revision 1.102 2002/06/26 15:58:13 makro
// Fixed a crash bug in the spawning code
// (happenned on maps with one spawn point)
//
2002-06-24 05:51:51 +00:00
// Revision 1.101 2002/06/24 05:51:51 jbravo
// CTF mode is now semi working
//
2002-06-23 23:32:29 +00:00
// Revision 1.100 2002/06/23 23:32:29 jbravo
// Fixed logging of clients IP addresses.
//
2002-06-21 11:55:32 +00:00
// Revision 1.99 2002/06/21 11:55:32 freud
// Changed spawning system to move spawns up 9 pixels (q3 style)
//
2002-06-20 22:32:43 +00:00
// Revision 1.98 2002/06/20 22:32:43 jbravo
// Added last damaged player and fixed a test2 model problem (atrimum my ass :)
// Changed g_RQ3_printOwnObits to g_RQ3_showOwnKills and it also controls $K
//
2002-06-19 18:18:09 +00:00
// Revision 1.97 2002/06/19 18:18:09 jbravo
// Small cleanups for compiler warnings
//
2002-06-19 18:13:57 +00:00
// Revision 1.96 2002/06/19 18:13:57 jbravo
// New TNG spawning system :)
//
2002-06-17 00:23:59 +00:00
// Revision 1.95 2002/06/17 00:23:59 slicer
// Lasersight problem fixed
//
2002-06-16 20:06:15 +00:00
// Revision 1.94 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.93 2002/06/16 17:38:00 jbravo
// Removed the MISSIONPACK ifdefs and missionpack only code.
//
2002-06-13 20:59:35 +00:00
// Revision 1.92 2002/06/13 20:59:35 slicer
// Setting ( for real ) gender on DM
//
2002-06-12 22:32:24 +00:00
// Revision 1.91 2002/06/12 22:32:24 slicer
// Even better way to improve the Cvar Anti-Cheat System
//
2002-06-12 15:30:24 +00:00
// Revision 1.90 2002/06/12 15:29:53 slicer
// Improved and fixed the Anti-Cheat System
//
2002-06-12 03:37:38 +00:00
// Revision 1.89 2002/06/12 03:37:38 blaze
// some fixes for the add bot code
//
2002-06-11 23:37:27 +00:00
// Revision 1.88 2002/06/11 23:37:27 blaze
// moved the cheat cvars to be sent at a different time, should work better
//
2002-06-11 01:43:08 +00:00
// Revision 1.87 2002/06/11 01:43:08 blaze
// g_rq3_cvarfile allows you to change which file holds the restricted cvars
//
2002-06-07 19:07:08 +00:00
// Revision 1.86 2002/06/07 19:07:08 slicer
// removed cvars for teamXready, replaced by level.teamXready
//
2002-06-05 22:09:21 +00:00
// Revision 1.85 2002/06/05 22:09:21 niceass
// bot fix. NOT MY FAULT
//
2002-06-04 08:25:44 +00:00
// Revision 1.84 2002/06/04 08:25:44 niceass
// cgame team fix. (when you change your name, etc)
//
2002-06-04 07:12:32 +00:00
// Revision 1.83 2002/06/04 07:12:32 niceass
// spectators spawn where you are rather than at a spawnpoint
//
2002-05-31 17:32:11 +00:00
// Revision 1.82 2002/05/31 17:32:11 jbravo
// HC gibs almost working :)
//
2002-05-28 04:46:12 +00:00
// Revision 1.81 2002/05/28 04:46:12 niceass
// headless fix
//
2002-05-28 01:17:01 +00:00
// Revision 1.80 2002/05/28 01:17:01 jbravo
// More gib fixes. g_RQ3_gib added
//
2002-05-27 06:50:01 +00:00
// Revision 1.79 2002/05/27 06:50:01 niceass
// further spawning and removed kamakazi
//
2002-05-25 16:31:18 +00:00
// Revision 1.78 2002/05/25 16:31:18 blaze
// moved breakable stuff over to config strings
//
2002-05-21 23:16:30 +00:00
// Revision 1.77 2002/05/21 23:16:30 blaze
// Only send cheat vars on client connect instead of every spawn
//
2002-05-20 04:59:33 +00:00
// Revision 1.76 2002/05/20 04:59:33 jbravo
// Lots of small fixes.
//
2002-05-19 21:27:51 +00:00
// Revision 1.75 2002/05/19 21:27:28 blaze
// added force and buoyancy to breakables
//
2002-05-13 07:29:14 +00:00
// Revision 1.74 2002/05/13 07:29:14 jbravo
// Fixed server chrasing on incorrect models in TP and also added default skins
//
2002-05-10 13:21:53 +00:00
// Revision 1.73 2002/05/10 13:21:53 makro
// Mainly bot stuff. Also fixed a couple of crash bugs
//
2002-05-05 15:51:16 +00:00
// Revision 1.72 2002/05/05 15:51:16 slicer
// Captain and subs get saved on map_restarts ( moved to "sess" )
//
2002-05-03 18:09:20 +00:00
// Revision 1.71 2002/05/03 18:09:20 makro
// Bot stuff. Jump kicks
//
2002-04-30 11:54:37 +00:00
// Revision 1.70 2002/04/30 11:54:37 makro
// Bots rule ! Also, added clips to give all. Maybe some other things
//
2002-04-30 01:23:05 +00:00
// Revision 1.69 2002/04/30 01:23:05 jbravo
// Changed the server logging to be more like a normal AQ server. Cleaned
// all colors from the logs.
//
2002-04-23 00:21:44 +00:00
// Revision 1.68 2002/04/23 00:21:44 jbravo
// Cleanups of the new model code. Removed the spectator bar for zcam modes.
//
2002-04-22 02:27:57 +00:00
// Revision 1.67 2002/04/22 02:27:57 jbravo
// Dynamic model recognition
//
2002-04-18 16:13:23 +00:00
// Revision 1.66 2002/04/18 16:13:23 jbravo
// Scoreboard now shows green for live players and white for dead.
// Time should not get reset on deaths any more.
//
2002-04-09 14:30:10 +00:00
// Revision 1.65 2002/04/09 14:30:10 jbravo
// Made cg_thirdPerson a CVAR_ROM, Made bots understand team aliases (1 and 2) and
// made TP spawns more random.
//
2002-04-07 17:51:49 +00:00
// Revision 1.64 2002/04/07 17:50:54 makro
// Abbey
//
2002-04-07 12:49:53 +00:00
// Revision 1.63 2002/04/07 12:49:10 slicer
// Added 'teamname' command for MM, and tweaked the cvar system.
//
2002-04-07 03:22:48 +00:00
// Revision 1.62 2002/04/07 03:22:48 jbravo
// Tweaks and crashbug fixes
//
2002-04-05 18:53:26 +00:00
// Revision 1.61 2002/04/05 18:53:26 jbravo
// Warning fixes
//
2002-04-03 03:13:49 +00:00
// Revision 1.60 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.59 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.58 2002/04/01 22:23:14 slicer
// Added "weapon" command buffering | Solved Gren Mode Bug
//
2002-03-31 03:31:24 +00:00
// Revision 1.57 2002/03/31 03:31:24 jbravo
// Compiler warning cleanups
//
2002-03-30 21:51:42 +00:00
// Revision 1.56 2002/03/30 21:51:42 jbravo
// Removed all those ifdefs for zcam.
//
2002-03-30 02:29:43 +00:00
// Revision 1.55 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.54 2002/03/26 11:32:04 jbravo
// Remember specstate between rounds.
//
2002-03-26 10:32:52 +00:00
// Revision 1.53 2002/03/26 10:32:52 jbravo
// Bye bye LCA lag
//
2002-03-17 23:43:43 +00:00
// Revision 1.52 2002/03/17 23:43:43 slicer
// Made Bots visible again at DM
//
2002-03-17 02:03:48 +00:00
// Revision 1.51 2002/03/17 02:03:48 jbravo
// Fixed a bug where a players laser would stay in the map after he disconnects
//
2002-03-17 01:44:39 +00:00
// Revision 1.50 2002/03/17 01:44:39 jbravo
// Fixed the "xxx died" fraglines, did some code cleanups andalmost fixed
// DM. Only DM problem I can see is that bots are invisible.
//
2002-03-14 23:54:12 +00:00
// Revision 1.49 2002/03/14 23:54:12 jbravo
// Added a variable system from AQ. Works the same except it uses $ for %
//
2002-03-14 02:24:39 +00:00
// Revision 1.48 2002/03/14 02:24:39 jbravo
// Adding radio :)
//
2002-03-11 18:02:33 +00:00
// Revision 1.47 2002/03/11 18:02:33 slicer
// Fixed team changes and scoreboard bugs
//
2002-03-07 01:38:36 +00:00
// Revision 1.46 2002/03/07 01:38:36 assimon
// Changed Ref System. New cvar added - g_RQ3_RefID. Now referee is peserved even on map changes or map_restarts.
//
2002-03-03 13:49:28 +00:00
// Revision 1.45 2002/03/03 13:49:28 jbravo
// Initializing weapon modes on connect.
//
2002-03-03 03:11:37 +00:00
// Revision 1.44 2002/03/03 03:11:37 jbravo
// Use propper weapon anims on TP spawns
//
2002-03-02 15:39:34 +00:00
// Revision 1.43 2002/03/02 15:39:34 jbravo
// Fixed team auto (PickTeam) up for TP
//
2002-03-02 14:54:24 +00:00
// Revision 1.42 2002/03/02 14:54:24 jbravo
// Added the skin and model names to the name of the player thats being
// followed, as in AQ
//
2002-03-01 18:21:26 +00:00
// Revision 1.41 2002/03/01 18:21:26 jbravo
// Cleanups and removal of g_RQ3_sniperup
//
2002-02-27 01:54:29 +00:00
// Revision 1.40 2002/02/27 01:54:29 jbravo
// More spectatorfixes and finally stopped all fallingdamage anims and
// sounds during LCA.
//
2002-02-26 21:59:10 +00:00
// Revision 1.39 2002/02/26 21:59:10 jbravo
// Fixed death on switching teams while dead
//
2002-02-26 02:58:47 +00:00
// Revision 1.38 2002/02/26 02:58:47 jbravo
// Fixing the spectator_free mode not being predicted in the client.
//
2002-02-10 21:21:23 +00:00
// Revision 1.37 2002/02/10 21:21:22 slicer
// Saving persistant and other data on some events..
//
2002-02-10 16:26:55 +00:00
// Revision 1.36 2002/02/10 16:26:55 jbravo
// Attempting to intergrate zcam better into rq3 and a fix for lights.wav
//
2002-02-07 23:01:07 +00:00
// Revision 1.35 2002/02/07 23:01:07 slicer
// Small fix..
//
2002-02-06 12:06:48 +00:00
// Revision 1.34 2002/02/06 12:06:48 slicer
// TP Scores bug fix
//
2002-02-06 03:10:43 +00:00
// Revision 1.33 2002/02/06 03:10:43 jbravo
// Fix the instant spectate on death and an attempt to fix the scores
//
2002-02-05 23:42:06 +00:00
// Revision 1.32 2002/02/05 23:41:27 slicer
// More on matchmode..
//
2002-02-04 00:11:12 +00:00
// Revision 1.31 2002/02/04 00:10:49 slicer
// Matchmode: Teams Ready/Not Ready goes by cvar MM_team1/2
2002-02-02 20:39:09 +00:00
//
2002-02-01 01:00:36 +00:00
// Revision 1.28 2002/02/01 01:00:36 slicer
// Adding Matchmode: just a few basics and files...
//
2002-01-27 13:33:28 +00:00
// Revision 1.27 2002/01/27 13:33:28 jbravo
// Teamplay antistick system.
//
2002-01-23 15:26:31 +00:00
// Revision 1.26 2002/01/23 15:26:31 niceass
// body sinkage removed
// weapon reset fixed
//
2002-01-11 20:20:58 +00:00
// Revision 1.25 2002/01/11 20:20:58 jbravo
// Adding TP to main branch
//
2002-01-11 19:48:33 +00:00
// Revision 1.24 2002/01/11 19:48:30 jbravo
// Formatted the source in non DOS format.
//
2001-12-31 16:28:42 +00:00
// Revision 1.23 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-05-06 20:50:27 +00:00
2002-01-11 20:20:58 +00:00
// JBravo: fixme. Hack to use SelectInitialSpawnPoint() in ClientSpawn.
2002-06-16 20:06:15 +00:00
gentity_t * SelectInitialSpawnPoint ( vec3_t origin , vec3_t angles ) ;
2002-01-11 20:20:58 +00:00
2002-05-19 21:27:51 +00:00
//Blaze: for the breakables
breakable_t rq3_breakables [ RQ3_MAX_BREAKABLES ] ;
2002-04-03 03:13:49 +00:00
2001-06-08 04:47:30 +00:00
# define RQ3_NONAMEPLAYER "Nameless"
2002-04-22 02:27:57 +00:00
// JBravo: for models
2002-06-16 20:06:15 +00:00
extern legitmodel_t legitmodels [ MAXMODELS ] ;
int RQ3_Validatemodel ( char * model ) ;
2002-04-22 02:27:57 +00:00
2002-07-26 06:21:43 +00:00
extern char * settings [ ] ;
extern char * settings2 [ ] ;
2001-05-06 20:50:27 +00:00
// g_client.c -- client functions that don't happen every frame
2002-06-16 20:06:15 +00:00
static vec3_t playerMins = { - 15 , - 15 , - 24 } ;
static vec3_t playerMaxs = { 15 , 15 , 32 } ;
2001-05-06 20:50:27 +00:00
/*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 32) initial
potential spawning position for deathmatch games .
The first time a player enters the game , they will be at an ' initial ' spot .
Targets will be fired when someone spawns in on them .
" nobots " will prevent bots from using this spot .
" nohumans " will prevent non - bots from using this spot .
*/
2002-06-16 20:06:15 +00:00
void SP_info_player_deathmatch ( gentity_t * ent )
{
int i ;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
G_SpawnInt ( " nobots " , " 0 " , & i ) ;
if ( i ) {
2001-05-06 20:50:27 +00:00
ent - > flags | = FL_NO_BOTS ;
}
2002-06-16 20:06:15 +00:00
G_SpawnInt ( " nohumans " , " 0 " , & i ) ;
if ( i ) {
2001-05-06 20:50:27 +00:00
ent - > flags | = FL_NO_HUMANS ;
}
}
/*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32)
equivelant to info_player_deathmatch
*/
2002-06-16 20:06:15 +00:00
void SP_info_player_start ( gentity_t * ent )
{
2001-05-06 20:50:27 +00:00
ent - > classname = " info_player_deathmatch " ;
2002-06-16 20:06:15 +00:00
SP_info_player_deathmatch ( ent ) ;
2001-05-06 20:50:27 +00:00
}
/*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32)
The intermission will be viewed from this point . Target an info_notnull for the view direction .
*/
2002-06-16 20:06:15 +00:00
void SP_info_player_intermission ( gentity_t * ent )
{
2001-05-06 20:50:27 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
SelectSpawnPoint
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = =
SpotWouldTelefrag
= = = = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
qboolean SpotWouldTelefrag ( gentity_t * spot )
{
int i , num ;
int touch [ MAX_GENTITIES ] ;
gentity_t * hit ;
vec3_t mins , maxs ;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
VectorAdd ( spot - > s . origin , playerMins , mins ) ;
VectorAdd ( spot - > s . origin , playerMaxs , maxs ) ;
num = trap_EntitiesInBox ( mins , maxs , touch , MAX_GENTITIES ) ;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
for ( i = 0 ; i < num ; i + + ) {
2001-05-06 20:50:27 +00:00
hit = & g_entities [ touch [ i ] ] ;
//if ( hit->client && hit->client->ps.stats[STAT_HEALTH] > 0 ) {
2002-06-16 20:06:15 +00:00
if ( hit - > client ) {
2001-05-06 20:50:27 +00:00
return qtrue ;
}
}
return qfalse ;
}
/*
= = = = = = = = = = = = = = = =
SelectNearestDeathmatchSpawnPoint
Find the spot that we DON ' T want to use
= = = = = = = = = = = = = = = =
*/
2002-06-19 18:13:57 +00:00
// Moved to g_local.h
//#define MAX_SPAWN_POINTS 128
2002-06-16 20:06:15 +00:00
gentity_t * SelectNearestDeathmatchSpawnPoint ( vec3_t from )
{
gentity_t * spot ;
vec3_t delta ;
float dist , nearestDist ;
gentity_t * nearestSpot ;
2001-05-06 20:50:27 +00:00
nearestDist = 999999 ;
nearestSpot = NULL ;
spot = NULL ;
2002-06-16 20:06:15 +00:00
while ( ( spot = G_Find ( spot , FOFS ( classname ) , " info_player_deathmatch " ) ) ! = NULL ) {
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
VectorSubtract ( spot - > s . origin , from , delta ) ;
dist = VectorLength ( delta ) ;
if ( dist < nearestDist ) {
2001-05-06 20:50:27 +00:00
nearestDist = dist ;
nearestSpot = spot ;
}
}
return nearestSpot ;
}
/*
= = = = = = = = = = = = = = = =
SelectRandomDeathmatchSpawnPoint
go to a random point that doesn ' t telefrag
= = = = = = = = = = = = = = = =
*/
2002-06-19 18:13:57 +00:00
// Moved to g_local.h
//#define MAX_SPAWN_POINTS 128
2002-06-16 20:06:15 +00:00
gentity_t * SelectRandomDeathmatchSpawnPoint ( void )
{
gentity_t * spot ;
int count ;
int selection ;
gentity_t * spots [ MAX_SPAWN_POINTS ] ;
2001-05-06 20:50:27 +00:00
count = 0 ;
spot = NULL ;
2002-06-16 20:06:15 +00:00
while ( ( spot = G_Find ( spot , FOFS ( classname ) , " info_player_deathmatch " ) ) ! = NULL ) {
if ( SpotWouldTelefrag ( spot ) ) {
2001-05-06 20:50:27 +00:00
continue ;
}
2002-06-16 20:06:15 +00:00
spots [ count ] = spot ;
2001-05-06 20:50:27 +00:00
count + + ;
}
2002-06-16 20:06:15 +00:00
if ( ! count ) { // no spots that won't telefrag
return G_Find ( NULL , FOFS ( classname ) , " info_player_deathmatch " ) ;
2001-05-06 20:50:27 +00:00
}
selection = rand ( ) % count ;
2002-06-16 20:06:15 +00:00
return spots [ selection ] ;
2001-05-06 20:50:27 +00:00
}
/*
= = = = = = = = = = =
SelectRandomFurthestSpawnPoint
Chooses a player start , deathmatch start , etc
= = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
gentity_t * SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint , vec3_t origin , vec3_t angles )
{
gentity_t * spot ;
vec3_t delta ;
float dist ;
float list_dist [ 64 ] ;
gentity_t * list_spot [ 64 ] ;
int numSpots , rnd , i , j ;
2001-05-06 20:50:27 +00:00
numSpots = 0 ;
spot = NULL ;
2002-06-16 20:06:15 +00:00
while ( ( spot = G_Find ( spot , FOFS ( classname ) , " info_player_deathmatch " ) ) ! = NULL ) {
if ( SpotWouldTelefrag ( spot ) ) {
2001-05-06 20:50:27 +00:00
continue ;
}
2002-06-16 20:06:15 +00:00
VectorSubtract ( spot - > s . origin , avoidPoint , delta ) ;
dist = VectorLength ( delta ) ;
2001-05-06 20:50:27 +00:00
for ( i = 0 ; i < numSpots ; i + + ) {
2002-06-16 20:06:15 +00:00
if ( dist > list_dist [ i ] ) {
if ( numSpots > = 64 )
numSpots = 64 - 1 ;
2001-05-06 20:50:27 +00:00
for ( j = numSpots ; j > i ; j - - ) {
2002-06-16 20:06:15 +00:00
list_dist [ j ] = list_dist [ j - 1 ] ;
list_spot [ j ] = list_spot [ j - 1 ] ;
2001-05-06 20:50:27 +00:00
}
list_dist [ i ] = dist ;
list_spot [ i ] = spot ;
numSpots + + ;
if ( numSpots > 64 )
numSpots = 64 ;
break ;
}
}
if ( i > = numSpots & & numSpots < 64 ) {
list_dist [ numSpots ] = dist ;
list_spot [ numSpots ] = spot ;
numSpots + + ;
}
}
2002-05-27 06:50:01 +00:00
/* NICEASS WAY:
2002-06-16 20:06:15 +00:00
gentity_t * spot ;
vec3_t delta ;
float dist , furthestDist ;
gentity_t * furthestSpot ;
furthestDist = 0 ;
furthestSpot = NULL ;
spot = NULL ;
while ( ( spot = G_Find ( spot , FOFS ( classname ) , " info_player_deathmatch " ) ) ! = NULL ) {
VectorSubtract ( spot - > s . origin , from , delta ) ;
dist = VectorLength ( delta ) ;
if ( dist > furthestDist ) {
furthestDist = dist ;
furthestSpot = spot ;
}
}
if ( ! furthestSpot ) {
spot = G_Find ( NULL , FOFS ( classname ) , " info_player_deathmatch " ) ;
if ( ! spot )
G_Error ( " Couldn't find a spawn point " ) ;
VectorCopy ( spot - > s . origin , origin ) ;
origin [ 2 ] + = 9 ;
VectorCopy ( spot - > s . angles , angles ) ;
return spot ;
}
else {
return furthestSpot ;
}
*/
2001-05-06 20:50:27 +00:00
2002-06-26 15:58:13 +00:00
//Makro - on a map with one spawn point, if one player has to respawn and someone is
//already near the spawnpoint, Q3 crashes; added check
if ( numSpots ! = 0 ) {
// select a random spot from the spawn points furthest away
rnd = random ( ) * ( numSpots / 3 ) ; // NiceAss: divided by 2 changed to 3 to cut down on close spawns
VectorCopy ( list_spot [ rnd ] - > s . origin , origin ) ;
origin [ 2 ] + = 9 ;
VectorCopy ( list_spot [ rnd ] - > s . angles , angles ) ;
return list_spot [ rnd ] ;
} else {
//Makro - added; note - plenty of room for improvement here, I just wanted to get rid of the crash bug
spot = G_Find ( NULL , FOFS ( classname ) , " info_player_deathmatch " ) ;
if ( ! spot ) {
G_Error ( " Couldn't find a spawn point " ) ;
}
VectorCopy ( spot - > s . origin , origin ) ;
origin [ 2 ] + = 9 ;
VectorCopy ( spot - > s . angles , angles ) ;
return spot ;
}
2001-05-06 20:50:27 +00:00
}
/*
= = = = = = = = = = =
SelectSpawnPoint
Chooses a player start , deathmatch start , etc
= = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
gentity_t * SelectSpawnPoint ( vec3_t avoidPoint , vec3_t origin , vec3_t angles )
{
return SelectRandomFurthestSpawnPoint ( avoidPoint , origin , angles ) ;
2001-05-06 20:50:27 +00:00
/*
2002-06-16 20:06:15 +00:00
gentity_t * spot ;
gentity_t * nearestSpot ;
nearestSpot = SelectNearestDeathmatchSpawnPoint ( avoidPoint ) ;
spot = SelectRandomDeathmatchSpawnPoint ( ) ;
if ( spot = = nearestSpot ) {
// roll again if it would be real close to point of death
spot = SelectRandomDeathmatchSpawnPoint ( ) ;
if ( spot = = nearestSpot ) {
// last try
spot = SelectRandomDeathmatchSpawnPoint ( ) ;
}
}
// find a single player start spot
if ( ! spot ) {
G_Error ( " Couldn't find a spawn point " ) ;
}
VectorCopy ( spot - > s . origin , origin ) ;
origin [ 2 ] + = 9 ;
VectorCopy ( spot - > s . angles , angles ) ;
return spot ;
*/
2001-05-06 20:50:27 +00:00
}
/*
= = = = = = = = = = =
SelectInitialSpawnPoint
Try to find a spawn point marked ' initial ' , otherwise
use normal spawn selection .
= = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
gentity_t * SelectInitialSpawnPoint ( vec3_t origin , vec3_t angles )
{
gentity_t * spot ;
2001-05-06 20:50:27 +00:00
spot = NULL ;
2002-06-16 20:06:15 +00:00
while ( ( spot = G_Find ( spot , FOFS ( classname ) , " info_player_deathmatch " ) ) ! = NULL ) {
if ( spot - > spawnflags & 1 ) {
2001-05-06 20:50:27 +00:00
break ;
}
}
2002-06-16 20:06:15 +00:00
if ( ! spot | | SpotWouldTelefrag ( spot ) ) {
return SelectSpawnPoint ( vec3_origin , origin , angles ) ;
2001-05-06 20:50:27 +00:00
}
2002-06-16 20:06:15 +00:00
VectorCopy ( spot - > s . origin , origin ) ;
2001-05-06 20:50:27 +00:00
origin [ 2 ] + = 9 ;
2002-06-16 20:06:15 +00:00
VectorCopy ( spot - > s . angles , angles ) ;
2001-05-06 20:50:27 +00:00
return spot ;
}
/*
= = = = = = = = = = =
SelectSpectatorSpawnPoint
= = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
gentity_t * SelectSpectatorSpawnPoint ( vec3_t origin , vec3_t angles )
{
2001-05-06 20:50:27 +00:00
FindIntermissionPoint ( ) ;
2002-06-16 20:06:15 +00:00
VectorCopy ( level . intermission_origin , origin ) ;
VectorCopy ( level . intermission_angle , angles ) ;
2001-05-06 20:50:27 +00:00
return NULL ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
BODYQUE
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = =
InitBodyQue
= = = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void InitBodyQue ( void )
{
int i ;
gentity_t * ent ;
2001-05-06 20:50:27 +00:00
level . bodyQueIndex = 0 ;
2002-06-16 20:06:15 +00:00
for ( i = 0 ; i < BODY_QUEUE_SIZE ; i + + ) {
2001-05-06 20:50:27 +00:00
ent = G_Spawn ( ) ;
ent - > classname = " bodyque " ;
ent - > neverFree = qtrue ;
level . bodyQue [ i ] = ent ;
}
}
2002-01-23 15:26:31 +00:00
/*
= = = = = = = = = = = = = = =
ClearBodyQue - By NiceAss
= = = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void ClearBodyQue ( void )
{
int i ;
gentity_t * ent ;
2002-01-23 15:26:31 +00:00
level . bodyQueIndex = 0 ;
2002-06-16 20:06:15 +00:00
for ( i = 0 ; i < BODY_QUEUE_SIZE ; i + + ) {
2002-01-23 15:26:31 +00:00
ent = level . bodyQue [ i ] ;
2002-06-16 20:06:15 +00:00
trap_UnlinkEntity ( ent ) ;
2002-01-23 15:26:31 +00:00
ent - > physicsObject = qfalse ;
}
}
2001-05-06 20:50:27 +00:00
/*
= = = = = = = = = = = = =
BodySink
After sitting around for five seconds , fall into the ground and dissapear
= = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void BodySink ( gentity_t * ent )
{
2002-01-23 15:26:31 +00:00
// NiceAss: Prevent body sink in TP. Bodies will be removed at before LCA
if ( g_gametype . integer = = GT_TEAMPLAY )
return ;
2002-06-16 20:06:15 +00:00
if ( level . time - ent - > timestamp > 6500 ) {
2001-05-06 20:50:27 +00:00
// the body ques are never actually freed, they are just unlinked
2002-06-16 20:06:15 +00:00
trap_UnlinkEntity ( ent ) ;
2001-05-06 20:50:27 +00:00
ent - > physicsObject = qfalse ;
2001-11-25 23:04:08 +00:00
return ;
2001-05-06 20:50:27 +00:00
}
ent - > nextthink = level . time + 100 ;
ent - > s . pos . trBase [ 2 ] - = 1 ;
}
/*
= = = = = = = = = = = = =
CopyToBodyQue
A player is respawning , so make an entity that looks
just like the existing corpse to leave behind .
= = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void CopyToBodyQue ( gentity_t * ent )
{
gentity_t * body ;
int contents ;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
trap_UnlinkEntity ( ent ) ;
2001-05-06 20:50:27 +00:00
// if client is in a nodrop area, don't leave the body
2002-06-16 20:06:15 +00:00
contents = trap_PointContents ( ent - > s . origin , - 1 ) ;
if ( contents & CONTENTS_NODROP ) {
2001-05-06 20:50:27 +00:00
return ;
}
// grab a body que and cycle to the next one
2002-06-16 20:06:15 +00:00
body = level . bodyQue [ level . bodyQueIndex ] ;
2001-05-06 20:50:27 +00:00
level . bodyQueIndex = ( level . bodyQueIndex + 1 ) % BODY_QUEUE_SIZE ;
2002-06-16 20:06:15 +00:00
trap_UnlinkEntity ( body ) ;
2001-05-06 20:50:27 +00:00
body - > s = ent - > s ;
2002-05-28 04:46:12 +00:00
// clear EF_TALK, etc
if ( body - > s . eFlags & EF_HEADLESS )
body - > s . eFlags = EF_DEAD | EF_HEADLESS ;
else
body - > s . eFlags = EF_DEAD ;
2001-05-06 20:50:27 +00:00
body - > s . powerups = 0 ; // clear powerups
body - > s . loopSound = 0 ; // clear lava burning
body - > s . number = body - g_entities ;
body - > timestamp = level . time ;
body - > physicsObject = qtrue ;
2002-06-16 20:06:15 +00:00
body - > physicsBounce = 0 ; // don't bounce
if ( body - > s . groundEntityNum = = ENTITYNUM_NONE ) {
2001-05-06 20:50:27 +00:00
body - > s . pos . trType = TR_GRAVITY ;
body - > s . pos . trTime = level . time ;
2002-06-16 20:06:15 +00:00
VectorCopy ( ent - > client - > ps . velocity , body - > s . pos . trDelta ) ;
2001-05-06 20:50:27 +00:00
} else {
body - > s . pos . trType = TR_STATIONARY ;
}
body - > s . event = 0 ;
// change the animation to the last-frame only, so the sequence
// doesn't repeat anew for the body
2002-06-16 20:06:15 +00:00
switch ( body - > s . legsAnim & ~ ANIM_TOGGLEBIT ) {
2001-05-06 20:50:27 +00:00
case BOTH_DEATH1 :
case BOTH_DEAD1 :
body - > s . torsoAnim = body - > s . legsAnim = BOTH_DEAD1 ;
break ;
case BOTH_DEATH2 :
case BOTH_DEAD2 :
body - > s . torsoAnim = body - > s . legsAnim = BOTH_DEAD2 ;
break ;
case BOTH_DEATH3 :
case BOTH_DEAD3 :
default :
body - > s . torsoAnim = body - > s . legsAnim = BOTH_DEAD3 ;
break ;
}
body - > r . svFlags = ent - > r . svFlags ;
2002-06-16 20:06:15 +00:00
VectorCopy ( ent - > r . mins , body - > r . mins ) ;
VectorCopy ( ent - > r . maxs , body - > r . maxs ) ;
VectorCopy ( ent - > r . absmin , body - > r . absmin ) ;
VectorCopy ( ent - > r . absmax , body - > r . absmax ) ;
2001-05-06 20:50:27 +00:00
body - > clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP ;
body - > r . contents = CONTENTS_CORPSE ;
body - > r . ownerNum = ent - > s . number ;
body - > nextthink = level . time + 5000 ;
2002-06-16 20:06:15 +00:00
2002-01-23 15:26:31 +00:00
// NiceAss: Prevent sinkage of the body in TP
2001-05-06 20:50:27 +00:00
body - > think = BodySink ;
body - > die = body_die ;
// don't take more damage if already gibbed
2002-06-16 20:06:15 +00:00
if ( ent - > health < = GIB_HEALTH ) {
2001-05-06 20:50:27 +00:00
body - > takedamage = qfalse ;
} else {
body - > takedamage = qtrue ;
}
2002-06-16 20:06:15 +00:00
VectorCopy ( body - > s . pos . trBase , body - > r . currentOrigin ) ;
trap_LinkEntity ( body ) ;
2001-05-06 20:50:27 +00:00
}
//======================================================================
/*
= = = = = = = = = = = = = = = = = =
SetClientViewAngle
= = = = = = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void SetClientViewAngle ( gentity_t * ent , vec3_t angle )
{
int i ;
2001-05-06 20:50:27 +00:00
// set the delta angle
2002-06-16 20:06:15 +00:00
for ( i = 0 ; i < 3 ; i + + ) {
int cmdAngle ;
2001-05-06 20:50:27 +00:00
cmdAngle = ANGLE2SHORT ( angle [ i ] ) ;
ent - > client - > ps . delta_angles [ i ] = cmdAngle - ent - > client - > pers . cmd . angles [ i ] ;
}
2002-06-16 20:06:15 +00:00
VectorCopy ( angle , ent - > s . angles ) ;
VectorCopy ( ent - > s . angles , ent - > client - > ps . viewangles ) ;
2001-05-06 20:50:27 +00:00
}
/*
= = = = = = = = = = = = = = = =
respawn
= = = = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void respawn ( gentity_t * ent )
{
//gentity_t *tent;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
CopyToBodyQue ( ent ) ;
2001-05-06 20:50:27 +00:00
ClientSpawn ( ent ) ;
// add a teleportation effect
2001-06-08 04:47:30 +00:00
//Elder: removed
//tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN );
//tent->s.clientNum = ent->s.clientNum;
2001-05-06 20:50:27 +00:00
}
/*
= = = = = = = = = = = = = = = =
TeamCount
Returns number of players on a team
= = = = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
team_t TeamCount ( int ignoreClientNum , int team )
{
int i ;
int count = 0 ;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
for ( i = 0 ; i < level . maxclients ; i + + ) {
if ( i = = ignoreClientNum ) {
2001-05-06 20:50:27 +00:00
continue ;
}
2002-06-16 20:06:15 +00:00
if ( level . clients [ i ] . pers . connected = = CON_DISCONNECTED ) {
2001-05-06 20:50:27 +00:00
continue ;
}
2002-06-16 20:06:15 +00:00
if ( level . clients [ i ] . sess . sessionTeam = = team ) {
2001-05-06 20:50:27 +00:00
count + + ;
}
}
return count ;
}
/*
= = = = = = = = = = = = = = = =
TeamLeader
Returns the client number of the team leader
= = = = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
int TeamLeader ( int team )
{
int i ;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
for ( i = 0 ; i < level . maxclients ; i + + ) {
if ( level . clients [ i ] . pers . connected = = CON_DISCONNECTED ) {
2001-05-06 20:50:27 +00:00
continue ;
}
2002-06-16 20:06:15 +00:00
if ( level . clients [ i ] . sess . sessionTeam = = team ) {
if ( level . clients [ i ] . sess . teamLeader )
2001-05-06 20:50:27 +00:00
return i ;
}
}
return - 1 ;
}
/*
= = = = = = = = = = = = = = = =
PickTeam
= = = = = = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
team_t PickTeam ( int ignoreClientNum )
{
int counts [ TEAM_NUM_TEAMS ] ;
2001-05-06 20:50:27 +00:00
2002-03-02 15:39:34 +00:00
if ( g_gametype . integer = = GT_TEAMPLAY ) {
2002-06-16 20:06:15 +00:00
counts [ TEAM_BLUE ] = RQ3TeamCount ( ignoreClientNum , TEAM_BLUE ) ;
counts [ TEAM_RED ] = RQ3TeamCount ( ignoreClientNum , TEAM_RED ) ;
2002-03-02 15:39:34 +00:00
} else {
2002-06-16 20:06:15 +00:00
counts [ TEAM_BLUE ] = TeamCount ( ignoreClientNum , TEAM_BLUE ) ;
counts [ TEAM_RED ] = TeamCount ( ignoreClientNum , TEAM_RED ) ;
2002-03-02 15:39:34 +00:00
}
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
if ( counts [ TEAM_BLUE ] > counts [ TEAM_RED ] ) {
2001-05-06 20:50:27 +00:00
return TEAM_RED ;
}
2002-06-16 20:06:15 +00:00
if ( counts [ TEAM_RED ] > counts [ TEAM_BLUE ] ) {
2001-05-06 20:50:27 +00:00
return TEAM_BLUE ;
}
// equal team count, so join the team with the lowest score
2002-06-16 20:06:15 +00:00
if ( level . teamScores [ TEAM_BLUE ] > level . teamScores [ TEAM_RED ] ) {
2001-05-06 20:50:27 +00:00
return TEAM_RED ;
}
return TEAM_BLUE ;
}
/*
= = = = = = = = = = =
ForceClientSkin
Forces a client ' s skin ( for teamplay )
= = = = = = = = = = =
*/
2001-08-01 19:52:17 +00:00
/*
2001-05-06 20:50:27 +00:00
static void ForceClientSkin ( gclient_t * client , char * model , const char * skin ) {
char * p ;
if ( ( p = Q_strrchr ( model , ' / ' ) ) ! = 0 ) {
* p = 0 ;
}
Q_strcat ( model , MAX_QPATH , " / " ) ;
Q_strcat ( model , MAX_QPATH , skin ) ;
}
2001-08-01 19:52:17 +00:00
*/
2001-05-06 20:50:27 +00:00
/*
= = = = = = = = = = =
ClientCheckName
= = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
static void ClientCleanName ( const char * in , char * out , int outSize )
{
int len , colorlessLen ;
char ch ;
char * p ;
int spaces ;
2001-05-06 20:50:27 +00:00
//save room for trailing null byte
outSize - - ;
len = 0 ;
colorlessLen = 0 ;
p = out ;
* p = 0 ;
spaces = 0 ;
2002-06-16 20:06:15 +00:00
while ( 1 ) {
2001-05-06 20:50:27 +00:00
ch = * in + + ;
2002-06-16 20:06:15 +00:00
if ( ! ch ) {
2001-05-06 20:50:27 +00:00
break ;
}
// don't allow leading spaces
2002-06-16 20:06:15 +00:00
if ( ! * p & & ch = = ' ' ) {
2001-05-06 20:50:27 +00:00
continue ;
}
// check colors
2002-06-16 20:06:15 +00:00
if ( ch = = Q_COLOR_ESCAPE ) {
2001-05-06 20:50:27 +00:00
// solo trailing carat is not a color prefix
2002-06-16 20:06:15 +00:00
if ( ! * in ) {
2001-05-06 20:50:27 +00:00
break ;
}
// don't allow black in a name, period
2002-06-16 20:06:15 +00:00
if ( ColorIndex ( * in ) = = 0 ) {
2001-05-06 20:50:27 +00:00
in + + ;
continue ;
}
// make sure room in dest for both chars
2002-06-16 20:06:15 +00:00
if ( len > outSize - 2 ) {
2001-05-06 20:50:27 +00:00
break ;
}
* out + + = ch ;
* out + + = * in + + ;
len + = 2 ;
continue ;
}
// don't allow too many consecutive spaces
2002-06-16 20:06:15 +00:00
if ( ch = = ' ' ) {
2001-05-06 20:50:27 +00:00
spaces + + ;
2002-06-16 20:06:15 +00:00
if ( spaces > 3 ) {
2001-05-06 20:50:27 +00:00
continue ;
}
2002-06-16 20:06:15 +00:00
} else {
2001-05-06 20:50:27 +00:00
spaces = 0 ;
}
2002-06-16 20:06:15 +00:00
if ( len > outSize - 1 ) {
2001-05-06 20:50:27 +00:00
break ;
}
* out + + = ch ;
colorlessLen + + ;
len + + ;
}
* out = 0 ;
// don't allow empty names
2002-06-16 20:06:15 +00:00
if ( * p = = 0 | | colorlessLen = = 0 ) {
2001-06-08 04:47:30 +00:00
//Elder: change to what we want
2002-06-16 20:06:15 +00:00
Q_strncpyz ( p , RQ3_NONAMEPLAYER , outSize ) ;
2001-05-06 20:50:27 +00:00
}
}
/*
= = = = = = = = = = =
ClientUserInfoChanged
Called from ClientConnect when the player first connects and
directly by the server system when the player updates a userinfo variable .
The game can override any of the settings and call trap_SetUserinfo
if desired .
= = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void ClientUserinfoChanged ( int clientNum )
{
2001-05-06 20:50:27 +00:00
gentity_t * ent ;
2002-06-16 20:06:15 +00:00
int teamTask , teamLeader , team , health ;
char * s ;
char model [ MAX_QPATH ] ;
char headModel [ MAX_QPATH ] ;
char oldname [ MAX_STRING_CHARS ] ;
gclient_t * client ;
char c1 [ MAX_INFO_STRING ] ;
char c2 [ MAX_INFO_STRING ] ;
char redTeam [ MAX_INFO_STRING ] ;
char blueTeam [ MAX_INFO_STRING ] ;
char userinfo [ MAX_INFO_STRING ] ;
2001-12-17 15:08:34 +00:00
// NiceAss: Added the following. Needed to prevent all models but "grunt"
2002-06-16 20:06:15 +00:00
char * skin2 , model2 [ MAX_STRING_CHARS ] ;
int gender ;
2001-05-06 20:50:27 +00:00
ent = g_entities + clientNum ;
client = ent - > client ;
2002-06-16 20:06:15 +00:00
trap_GetUserinfo ( clientNum , userinfo , sizeof ( userinfo ) ) ;
2001-05-06 20:50:27 +00:00
// check for malformed or illegal info strings
2002-06-16 20:06:15 +00:00
if ( ! Info_Validate ( userinfo ) ) {
strcpy ( userinfo , " \\ name \\ badinfo " ) ;
2001-05-06 20:50:27 +00:00
}
// check for local client
2002-06-16 20:06:15 +00:00
s = Info_ValueForKey ( userinfo , " ip " ) ;
if ( ! strcmp ( s , " localhost " ) ) {
2001-05-06 20:50:27 +00:00
client - > pers . localClient = qtrue ;
}
// check the item prediction
2002-06-16 20:06:15 +00:00
s = Info_ValueForKey ( userinfo , " cg_predictItems " ) ;
if ( ! atoi ( s ) ) {
2001-05-06 20:50:27 +00:00
client - > pers . predictItemPickup = qfalse ;
} else {
client - > pers . predictItemPickup = qtrue ;
}
// set name
2002-06-16 20:06:15 +00:00
Q_strncpyz ( oldname , client - > pers . netname , sizeof ( oldname ) ) ;
s = Info_ValueForKey ( userinfo , " name " ) ;
ClientCleanName ( s , client - > pers . netname , sizeof ( client - > pers . netname ) ) ;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
if ( client - > sess . sessionTeam = = TEAM_SPECTATOR ) {
if ( client - > sess . spectatorState = = SPECTATOR_SCOREBOARD ) {
Q_strncpyz ( client - > pers . netname , " scoreboard " , sizeof ( client - > pers . netname ) ) ;
2001-05-06 20:50:27 +00:00
}
}
2002-06-16 20:06:15 +00:00
if ( client - > pers . connected = = CON_CONNECTED ) {
if ( strcmp ( oldname , client - > pers . netname ) ) {
trap_SendServerCommand ( - 1 , va ( " print \" %s " S_COLOR_WHITE " renamed to %s \n \" " , oldname ,
client - > pers . netname ) ) ;
2001-05-06 20:50:27 +00:00
}
}
// set max health
2002-06-16 20:06:15 +00:00
health = atoi ( Info_ValueForKey ( userinfo , " handicap " ) ) ;
2001-05-06 20:50:27 +00:00
client - > pers . maxHealth = health ;
2002-06-16 20:06:15 +00:00
if ( client - > pers . maxHealth < 1 | | client - > pers . maxHealth > 100 ) {
2001-05-06 20:50:27 +00:00
client - > pers . maxHealth = 100 ;
}
//client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth;
// set model
2002-06-16 20:06:15 +00:00
if ( g_gametype . integer > = GT_TEAM ) {
Q_strncpyz ( model , Info_ValueForKey ( userinfo , " team_model " ) , sizeof ( model ) ) ;
Q_strncpyz ( headModel , Info_ValueForKey ( userinfo , " team_headmodel " ) , sizeof ( headModel ) ) ;
2001-05-06 20:50:27 +00:00
} else {
2002-06-16 20:06:15 +00:00
Q_strncpyz ( model , Info_ValueForKey ( userinfo , " model " ) , sizeof ( model ) ) ;
Q_strncpyz ( headModel , Info_ValueForKey ( userinfo , " headmodel " ) , sizeof ( headModel ) ) ;
2001-05-06 20:50:27 +00:00
}
2002-08-07 03:35:57 +00:00
// JBravo: set the radiosoundset
s = Info_ValueForKey ( userinfo , " cg_RQ3_radiovoice_male " ) ;
if ( ! atoi ( s ) ) {
client - > radioSetMale = 0 ;
} else {
client - > radioSetMale = atoi ( s ) ;
}
s = Info_ValueForKey ( userinfo , " cg_RQ3_radiovoice_female " ) ;
if ( ! atoi ( s ) ) {
client - > radioSetFemale = 0 ;
} else {
client - > radioSetFemale = atoi ( s ) ;
}
2002-06-24 05:51:51 +00:00
if ( g_gametype . integer = = GT_TEAMPLAY | | g_gametype . integer = = GT_CTF ) {
2002-04-22 02:27:57 +00:00
if ( client - > sess . sessionTeam = = TEAM_RED ) {
2002-05-13 07:29:14 +00:00
Q_strncpyz ( model2 , g_RQ3_team1model . string , sizeof ( model ) ) ;
skin2 = Q_strrchr ( model2 , ' / ' ) ;
if ( skin2 ) {
* skin2 + + = ' \0 ' ;
} else {
skin2 = " chowda " ;
}
2002-06-16 20:06:15 +00:00
if ( RQ3_Validatemodel ( model2 ) ! = - 1 ) {
Com_sprintf ( model , sizeof ( model ) , " %s/%s " , model2 , skin2 ) ;
Com_sprintf ( headModel , sizeof ( headModel ) , " %s/%s " , model2 , skin2 ) ;
2002-05-13 07:29:14 +00:00
} else {
2002-06-16 20:06:15 +00:00
Com_sprintf ( model , sizeof ( model ) , " grunt/chowda " ) ;
Com_sprintf ( headModel , sizeof ( headModel ) , " grunt/chowda " ) ;
2002-05-13 07:29:14 +00:00
}
2002-04-22 02:27:57 +00:00
} else {
2002-05-13 07:29:14 +00:00
Q_strncpyz ( model2 , g_RQ3_team2model . string , sizeof ( model ) ) ;
skin2 = Q_strrchr ( model2 , ' / ' ) ;
if ( skin2 ) {
* skin2 + + = ' \0 ' ;
} else {
skin2 = " cyrus " ;
}
2002-06-20 22:32:43 +00:00
if ( RQ3_Validatemodel ( model2 ) ! = - 1 ) {
2002-06-16 20:06:15 +00:00
Com_sprintf ( model , sizeof ( model ) , " %s/%s " , model2 , skin2 ) ;
Com_sprintf ( headModel , sizeof ( headModel ) , " %s/%s " , model2 , skin2 ) ;
2002-05-13 07:29:14 +00:00
} else {
2002-06-16 20:06:15 +00:00
Com_sprintf ( model , sizeof ( model ) , " grunt/cyrus " ) ;
Com_sprintf ( headModel , sizeof ( headModel ) , " grunt/cyrus " ) ;
2002-05-13 07:29:14 +00:00
}
2002-04-22 02:27:57 +00:00
}
2001-12-17 15:08:34 +00:00
} else {
2002-04-22 02:27:57 +00:00
Q_strncpyz ( model2 , model , sizeof ( model ) ) ;
2002-06-16 20:06:15 +00:00
skin2 = Q_strrchr ( model2 , ' / ' ) ;
if ( skin2 ) {
2002-04-22 02:27:57 +00:00
* skin2 + + = ' \0 ' ;
} else {
skin2 = " default " ;
}
2001-12-17 15:08:34 +00:00
2002-04-22 02:27:57 +00:00
// Makro - adding abbey
2002-06-16 20:06:15 +00:00
// if ( Q_stricmpn(model2, "grunt", sizeof(model2)) && Q_stricmpn(model2, "abbey", sizeof(model2))) {
2002-04-23 00:21:44 +00:00
// JBravo: Validating the model
2002-06-13 20:59:35 +00:00
gender = RQ3_Validatemodel ( model2 ) ;
if ( gender = = - 1 ) {
2002-06-16 20:06:15 +00:00
trap_SendServerCommand ( ent - g_entities ,
va ( " print \" Illegal player model (%s). Forcing change on server. \n \" " ,
model2 ) ) ;
2002-04-22 02:27:57 +00:00
Q_strncpyz ( model , " grunt/resdog " , sizeof ( " grunt/resdog " ) ) ;
Q_strncpyz ( headModel , " grunt/resdog " , sizeof ( " grunt/resdog " ) ) ;
2002-06-16 20:06:15 +00:00
client - > radioGender = 0 ; // Male
} else if ( gender ! = GENDER_NEUTER )
client - > radioGender = gender ;
2001-12-17 15:08:34 +00:00
}
2001-05-06 20:50:27 +00:00
// bots set their team a few frames later
if ( g_gametype . integer > = GT_TEAM & & g_entities [ clientNum ] . r . svFlags & SVF_BOT ) {
2002-06-16 20:06:15 +00:00
s = Info_ValueForKey ( userinfo , " team " ) ;
2002-04-09 14:30:10 +00:00
if ( ! Q_stricmp ( s , " red " ) | | ! Q_stricmp ( s , " r " ) | | ! Q_stricmp ( s , " 1 " ) ) {
2001-05-06 20:50:27 +00:00
team = TEAM_RED ;
2002-04-09 14:30:10 +00:00
} else if ( ! Q_stricmp ( s , " blue " ) | | ! Q_stricmp ( s , " b " ) | | ! Q_stricmp ( s , " 2 " ) ) {
2001-05-06 20:50:27 +00:00
team = TEAM_BLUE ;
} else {
// pick the team with the least number of players
2002-06-16 20:06:15 +00:00
team = PickTeam ( clientNum ) ;
2001-05-06 20:50:27 +00:00
}
2002-06-16 20:06:15 +00:00
} else {
2002-06-05 22:09:21 +00:00
team = client - > sess . sessionTeam ;
2001-05-06 20:50:27 +00:00
}
2002-06-12 15:30:24 +00:00
//Slicer: for the anti-cheat system
2002-06-12 22:32:24 +00:00
/* s = Info_ValueForKey( userinfo, "cg_RQ3_auth" );
2002-06-12 15:30:24 +00:00
if ( ! atoi ( s ) ) {
//Blaze: Send cheat cvars to client
if ( ! G_SendCheatVars ( clientNum ) )
{
Com_Printf ( " Error loading cvar cfg \n " ) ;
//return "Error_loading_cvar_cfg";
}
else {
// This didn't really worked...
2002-06-19 18:18:09 +00:00
/ * G_Printf ( " Sending changed userinfo \n " ) ;
2002-06-12 15:30:24 +00:00
Info_SetValueForKey ( userinfo , " cg_RQ3_auth " , " 1 " ) ;
// register the userinfo
2002-06-12 22:32:24 +00:00
trap_SetUserinfo ( clientNum , userinfo ) ;
2002-06-12 15:30:24 +00:00
trap_SendServerCommand ( clientNum , va ( " rq3_cmd %i " , AUTH ) ) ;
}
2002-06-12 22:32:24 +00:00
2002-06-12 15:30:24 +00:00
}
2002-06-12 22:32:24 +00:00
*/
2002-06-12 15:30:24 +00:00
2001-08-01 19:52:17 +00:00
/* NOTE: all client side now
2001-05-06 20:50:27 +00:00
// team
switch ( team ) {
case TEAM_RED :
ForceClientSkin ( client , model , " red " ) ;
2001-08-01 19:52:17 +00:00
// ForceClientSkin(client, headModel, "red");
2001-05-06 20:50:27 +00:00
break ;
case TEAM_BLUE :
ForceClientSkin ( client , model , " blue " ) ;
2001-08-01 19:52:17 +00:00
// ForceClientSkin(client, headModel, "blue");
2001-05-06 20:50:27 +00:00
break ;
}
// don't ever use a default skin in teamplay, it would just waste memory
// however bots will always join a team but they spawn in as spectator
if ( g_gametype . integer > = GT_TEAM & & team = = TEAM_SPECTATOR ) {
ForceClientSkin ( client , model , " red " ) ;
2001-08-01 19:52:17 +00:00
// ForceClientSkin(client, headModel, "red");
2001-05-06 20:50:27 +00:00
}
2001-08-01 19:52:17 +00:00
*/
2001-05-06 20:50:27 +00:00
// teamInfo
2002-06-16 20:06:15 +00:00
s = Info_ValueForKey ( userinfo , " teamoverlay " ) ;
if ( ! * s | | atoi ( s ) ! = 0 ) {
2001-05-06 20:50:27 +00:00
client - > pers . teamInfo = qtrue ;
} else {
client - > pers . teamInfo = qfalse ;
}
/*
2002-06-16 20:06:15 +00:00
s = Info_ValueForKey ( userinfo , " cg_pmove_fixed " ) ;
if ( ! * s | | atoi ( s ) = = 0 ) {
client - > pers . pmoveFixed = qfalse ;
}
else {
client - > pers . pmoveFixed = qtrue ;
}
*/
2001-05-06 20:50:27 +00:00
// team task (0 = none, 1 = offence, 2 = defence)
teamTask = atoi ( Info_ValueForKey ( userinfo , " teamtask " ) ) ;
// team Leader (1 = leader, 0 is normal player)
teamLeader = client - > sess . teamLeader ;
// colors
2002-06-16 20:06:15 +00:00
strcpy ( c1 , Info_ValueForKey ( userinfo , " color1 " ) ) ;
strcpy ( c2 , Info_ValueForKey ( userinfo , " color2 " ) ) ;
2001-08-01 19:52:17 +00:00
2002-06-16 20:06:15 +00:00
strcpy ( redTeam , Info_ValueForKey ( userinfo , " g_redteam " ) ) ;
strcpy ( blueTeam , Info_ValueForKey ( userinfo , " g_blueteam " ) ) ;
2001-05-06 20:50:27 +00:00
// send over a subset of the userinfo keys so other clients can
// print scoreboards, display models, and play custom sounds
2002-06-16 20:06:15 +00:00
if ( ent - > r . svFlags & SVF_BOT ) {
2002-05-10 13:21:53 +00:00
//Makro - adding teamplay weapon/item info for bots
//s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s\\tt\\%d\\tl\\%d",
2002-06-16 20:06:15 +00:00
s = va
( " n \\ %s \\ t \\ %i \\ model \\ %s \\ hmodel \\ %s \\ c1 \\ %s \\ c2 \\ %s \\ hc \\ %i \\ w \\ %i \\ l \\ %i \\ skill \\ %s \\ tt \\ %d \\ tl \\ %d \\ tpw \\ %s \\ tpi \\ %s " ,
client - > pers . netname , team , model , headModel , c1 , c2 , client - > pers . maxHealth , client - > sess . wins ,
client - > sess . losses ,
//Info_ValueForKey( userinfo, "skill" ), teamTask, teamLeader );
Info_ValueForKey ( userinfo , " skill " ) , teamTask , teamLeader , Info_ValueForKey ( userinfo , " tpw " ) ,
Info_ValueForKey ( userinfo , " tpi " ) ) ;
2001-05-06 20:50:27 +00:00
} else {
2002-06-16 20:06:15 +00:00
s = va
( " n \\ %s \\ t \\ %i \\ model \\ %s \\ hmodel \\ %s \\ g_redteam \\ %s \\ g_blueteam \\ %s \\ c1 \\ %s \\ c2 \\ %s \\ hc \\ %i \\ w \\ %i \\ l \\ %i \\ tt \\ %d \\ tl \\ %d " ,
2002-07-16 04:09:14 +00:00
client - > pers . netname , client - > sess . savedTeam , model , headModel , redTeam , blueTeam , c1 , c2 ,
2002-06-16 20:06:15 +00:00
client - > pers . maxHealth , client - > sess . wins , client - > sess . losses , teamTask , teamLeader ) ;
2001-05-06 20:50:27 +00:00
}
2002-06-16 20:06:15 +00:00
trap_SetConfigstring ( CS_PLAYERS + clientNum , s ) ;
2001-05-06 20:50:27 +00:00
2002-04-30 01:23:05 +00:00
// JBravo: ugly in the logs. Enable to debug if necessary
2002-06-16 20:06:15 +00:00
// G_LogPrintf( "ClientUserinfoChanged: %i %s\n", clientNum, s );
2001-05-06 20:50:27 +00:00
}
2002-06-16 20:06:15 +00:00
2001-09-16 04:04:31 +00:00
/*
= = = = = = = = = = =
G_SendCheatVars ( int )
2001-05-06 20:50:27 +00:00
2001-09-16 04:04:31 +00:00
Send which cvars are cheats , and the acceptable values
= = = = = = = = = = =
*/
int G_SendCheatVars ( int clientNum )
{
char * text_p ;
int len ;
int i ;
int skip ;
char * token ;
char text [ 20000 ] ;
fileHandle_t f ;
2002-06-11 01:43:08 +00:00
2001-09-16 04:04:31 +00:00
char cheatVar [ 40 ] , cl_cheatvar [ 128 ] ;
float lowval , highval ;
2001-12-17 15:08:34 +00:00
//NiceAss: Added so /devmap will not have the client check cvars. Lie to the server that it loaded fine =)
2002-06-16 20:06:15 +00:00
if ( g_cheats . integer )
return qtrue ;
2001-09-16 04:04:31 +00:00
// load the file
2002-06-16 20:06:15 +00:00
len = trap_FS_FOpenFile ( g_RQ3_cvarfile . string , & f , FS_READ ) ;
if ( len < = 0 ) {
2001-09-16 04:04:31 +00:00
return qfalse ;
}
2002-06-16 20:06:15 +00:00
if ( len > = sizeof ( text ) - 1 ) {
G_Printf ( " File %s too long \n " , g_RQ3_cvarfile . string ) ;
2001-09-16 04:04:31 +00:00
return qfalse ;
}
2002-06-16 20:06:15 +00:00
trap_FS_Read ( text , len , f ) ;
2001-09-16 04:04:31 +00:00
text [ len ] = 0 ;
2002-06-16 20:06:15 +00:00
trap_FS_FCloseFile ( f ) ;
2001-11-25 23:04:08 +00:00
2001-09-16 04:04:31 +00:00
// parse the text
text_p = text ;
2002-06-16 20:06:15 +00:00
skip = 0 ; // quite the compiler warning
2001-11-25 23:04:08 +00:00
2002-06-16 20:06:15 +00:00
for ( i = 0 ; i < 30 ; i + + ) {
token = COM_Parse ( & text_p ) ;
if ( ! token )
break ;
if ( strlen ( token ) > = 40 ) {
Com_Printf ( " Cheatvar %s is too long \n " , token ) ;
2001-09-16 04:04:31 +00:00
return qfalse ;
}
2002-06-16 20:06:15 +00:00
Q_strncpyz ( cheatVar , token , sizeof ( cheatVar ) ) ;
2002-01-11 20:20:58 +00:00
// Fix from hal9000. Was NULL in that strcmp
2002-06-16 20:06:15 +00:00
if ( ! strcmp ( token , " " ) )
return qtrue ;
token = COM_Parse ( & text_p ) ;
if ( ! token )
break ;
lowval = atof ( token ) ;
token = COM_Parse ( & text_p ) ;
if ( ! token )
break ;
highval = atof ( token ) ;
Com_sprintf ( cl_cheatvar , sizeof ( cl_cheatvar ) , " addCheatVar %s %f %f \n " , cheatVar , lowval , highval ) ;
2001-09-16 04:04:31 +00:00
//Com_Printf("%s", cl_cheatvar);
2002-06-16 20:06:15 +00:00
trap_SendServerCommand ( clientNum , va ( " %s " , cl_cheatvar ) ) ;
2001-09-16 04:04:31 +00:00
}
return qtrue ;
}
2001-05-06 20:50:27 +00:00
/*
= = = = = = = = = = =
ClientConnect
Called when a player begins connecting to the server .
Called again for every map change or tournement restart .
The session information will be valid after exit .
Return NULL if the client should be allowed , otherwise return
a string with the reason for denial .
Otherwise , the client will be sent the current gamestate
and will eventually get to ClientBegin .
firstTime will be qtrue the very first time a client connects
to the server machine , but qfalse on map changes and tournement
restarts .
= = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
char * ClientConnect ( int clientNum , qboolean firstTime , qboolean isBot )
{
char * value , * ip ;
gclient_t * client ;
2002-06-23 23:32:29 +00:00
char userinfo [ MAX_INFO_STRING ] , ipaddr [ 64 ] ;
2002-06-16 20:06:15 +00:00
gentity_t * ent ;
2001-05-06 20:50:27 +00:00
2002-04-02 20:23:12 +00:00
ent = & g_entities [ clientNum ] ;
trap_GetUserinfo ( clientNum , userinfo , sizeof ( userinfo ) ) ;
2001-05-06 20:50:27 +00:00
// check to see if they are on the banned IP list
2002-06-16 20:06:15 +00:00
ip = Info_ValueForKey ( userinfo , " ip " ) ;
2002-06-23 23:32:29 +00:00
strcpy ( ipaddr , ip ) ;
2002-04-30 01:23:05 +00:00
if ( G_FilterPacket ( ip ) ) {
2001-05-06 20:50:27 +00:00
return " Banned. " ;
}
2002-06-16 20:06:15 +00:00
if ( ! ( ent - > r . svFlags & SVF_BOT ) ) {
2001-08-01 19:52:17 +00:00
// check for a password
2002-06-16 20:06:15 +00:00
value = Info_ValueForKey ( userinfo , " password " ) ;
2002-04-02 20:23:12 +00:00
if ( g_password . string [ 0 ] & & Q_stricmp ( g_password . string , " none " ) & &
2002-06-16 20:06:15 +00:00
strcmp ( g_password . string , value ) ! = 0 ) {
2001-08-01 19:52:17 +00:00
return " Invalid password " ;
}
2001-05-06 20:50:27 +00:00
}
// they can connect
ent - > client = level . clients + clientNum ;
client = ent - > client ;
2002-04-02 20:23:12 +00:00
memset ( client , 0 , sizeof ( * client ) ) ;
2001-05-06 20:50:27 +00:00
client - > pers . connected = CON_CONNECTING ;
2002-01-27 13:33:28 +00:00
// JBravo: Antistick
client - > ps . stats [ STAT_RQ3 ] & = ~ RQ3_PLAYERSOLID ;
2002-02-26 21:59:10 +00:00
// JBravo: Clear zcam flag for cgame
2002-02-26 02:58:47 +00:00
client - > ps . stats [ STAT_RQ3 ] & = ~ RQ3_ZCAM ;
2002-01-27 13:33:28 +00:00
2001-05-06 20:50:27 +00:00
// read or initialize the session data
2002-04-02 20:23:12 +00:00
if ( firstTime | | level . newSession ) {
G_InitSessionData ( client , userinfo ) ;
2001-05-06 20:50:27 +00:00
}
2002-04-02 20:23:12 +00:00
G_ReadSessionData ( client ) ;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
if ( isBot ) {
2001-05-06 20:50:27 +00:00
ent - > r . svFlags | = SVF_BOT ;
ent - > inuse = qtrue ;
2002-06-16 20:06:15 +00:00
if ( ! G_BotConnect ( clientNum , ! firstTime ) ) {
2001-05-06 20:50:27 +00:00
return " BotConnectfailed " ;
}
}
2002-04-02 20:23:12 +00:00
// slicer : make sessionTeam = to savedTeam for scoreboard on cgame
2002-03-17 01:44:39 +00:00
// JBravo: only for teamplay. Could break DM
if ( g_gametype . integer = = GT_TEAMPLAY ) {
2002-04-02 20:23:12 +00:00
client - > sess . sessionTeam = client - > sess . savedTeam ;
ClientUserinfoChanged ( clientNum ) ;
2002-06-16 20:06:15 +00:00
} else
2002-04-02 20:23:12 +00:00
ClientUserinfoChanged ( clientNum ) ;
2001-05-06 20:50:27 +00:00
// don't do the "xxx connected" messages if they were caried over from previous level
2002-04-02 20:23:12 +00:00
if ( firstTime ) {
trap_SendServerCommand ( - 1 , va ( " print \" %s " S_COLOR_WHITE " connected \n \" " , client - > pers . netname ) ) ;
2002-06-23 23:32:29 +00:00
G_LogPrintf ( " %s@%s connected (clientNum %i) \n " , client - > pers . netname , ipaddr , clientNum ) ;
2001-05-06 20:50:27 +00:00
}
2002-07-11 04:32:24 +00:00
if ( g_gametype . integer > = GT_TEAM & & g_gametype . integer ! = GT_TEAMPLAY & & g_gametype . integer ! = GT_CTF & &
2002-06-16 20:06:15 +00:00
client - > sess . sessionTeam ! = TEAM_SPECTATOR ) {
2002-04-02 20:23:12 +00:00
BroadcastTeamChange ( client , - 1 ) ;
2001-05-06 20:50:27 +00:00
}
// count current clients and rank for scoreboard
CalculateRanks ( ) ;
2002-02-26 21:59:10 +00:00
// JBravo: clients in TP begin as spectators
if ( g_gametype . integer = = GT_TEAMPLAY ) {
client - > sess . sessionTeam = TEAM_SPECTATOR ;
client - > ps . persistant [ PERS_TEAM ] = TEAM_SPECTATOR ;
2002-04-02 20:23:12 +00:00
client - > sess . spectatorState = SPECTATOR_FREE ;
client - > specMode = SPECTATOR_FREE ;
client - > ps . pm_flags & = ~ PMF_FOLLOW ;
client - > ps . stats [ STAT_RQ3 ] & = ~ RQ3_ZCAM ;
2002-04-07 03:22:48 +00:00
camera_begin ( ent ) ;
2002-04-02 20:23:12 +00:00
client - > camera - > mode = CAMERA_MODE_SWING ;
2002-02-26 21:59:10 +00:00
}
2002-04-18 16:13:23 +00:00
// JBravo: moved from ClientBegin
client - > pers . enterTime = level . time ;
2002-08-23 14:25:05 +00:00
/* Slicer - no no !! this can't be here !
2002-07-02 03:41:59 +00:00
// JBravo: cleaning up stuff
client - > sess . sub = TEAM_FREE ;
2002-08-23 14:25:05 +00:00
client - > sess . captain = TEAM_FREE ; */
2001-05-06 20:50:27 +00:00
return NULL ;
}
/*
= = = = = = = = = = =
ClientBegin
called when a client has finished connecting , and is ready
to be placed into the level . This will happen every level load ,
and on transition between teams , but doesn ' t happen on respawns
= = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void ClientBegin ( int clientNum )
{
gentity_t * ent ;
gclient_t * client ;
int flags , savedPing = 0 , i ;
int savedPers [ MAX_PERSISTANT ] ;
2002-07-26 22:28:38 +00:00
char str [ 256 ] ;
2001-05-06 20:50:27 +00:00
ent = g_entities + clientNum ;
client = level . clients + clientNum ;
2002-04-02 20:23:12 +00:00
if ( ent - > r . linked ) {
trap_UnlinkEntity ( ent ) ;
2001-05-06 20:50:27 +00:00
}
2002-03-17 01:44:39 +00:00
2002-04-02 20:23:12 +00:00
G_InitGentity ( ent ) ;
2001-05-06 20:50:27 +00:00
ent - > touch = 0 ;
ent - > pain = 0 ;
ent - > client = client ;
2002-02-01 01:00:36 +00:00
//Slicer : Reseting matchmode vars
//Note: Each time a player changes team, this will also be called..
2002-05-05 15:51:16 +00:00
//if(g_RQ3_matchmode.integer && g_gametype.integer == GT_TEAMPLAY) {
2002-06-16 20:06:15 +00:00
// client->sess.captain = TEAM_FREE;
// client->sess.sub = TEAM_FREE;
2002-05-05 15:51:16 +00:00
//}
2002-02-01 01:00:36 +00:00
2002-02-10 21:21:23 +00:00
//Slicer: Saving persistant and ping
2002-08-21 07:00:07 +00:00
if ( g_gametype . integer = = GT_TEAMPLAY | | g_gametype . integer = = GT_CTF ) {
2002-03-17 01:44:39 +00:00
savedPing = client - > ps . ping ;
2002-06-16 20:06:15 +00:00
for ( i = 0 ; i < MAX_PERSISTANT ; i + + )
savedPers [ i ] = client - > ps . persistant [ i ] ;
2002-03-17 01:44:39 +00:00
}
2002-02-06 12:06:48 +00:00
2001-05-06 20:50:27 +00:00
client - > pers . connected = CON_CONNECTED ;
2002-06-16 20:06:15 +00:00
// client->pers.enterTime = level.time;
2001-05-06 20:50:27 +00:00
client - > pers . teamState . state = TEAM_BEGIN ;
// save eflags around this, because changing teams will
// cause this to happen with a valid entity, and we
// want to make sure the teleport bit is set right
// so the viewpoint doesn't interpolate through the
// world to the new position
flags = client - > ps . eFlags ;
2002-04-02 20:23:12 +00:00
memset ( & client - > ps , 0 , sizeof ( client - > ps ) ) ;
2001-05-06 20:50:27 +00:00
client - > ps . eFlags = flags ;
2002-02-06 12:06:48 +00:00
//Slicer: Repost score and ping
2002-08-21 07:00:07 +00:00
if ( g_gametype . integer = = GT_TEAMPLAY | | g_gametype . integer = = GT_CTF ) {
2002-02-06 12:06:48 +00:00
client - > ps . ping = savedPing ;
2002-04-02 20:23:12 +00:00
for ( i = 0 ; i < MAX_PERSISTANT ; i + + )
2002-02-10 21:21:23 +00:00
client - > ps . persistant [ i ] = savedPers [ i ] ;
2002-02-06 12:06:48 +00:00
}
2002-06-30 17:33:01 +00:00
2001-05-06 20:50:27 +00:00
// locate ent at a spawn point
2002-04-02 20:23:12 +00:00
ClientSpawn ( ent ) ;
2001-05-06 20:50:27 +00:00
2002-01-11 20:20:58 +00:00
// JBravo: if teamplay and the client has not been on teams, make them a spectator.
2002-07-11 04:32:24 +00:00
if ( ( g_gametype . integer = = GT_TEAMPLAY & & client - > sess . savedTeam ! = TEAM_RED & & client - > sess . savedTeam ! = TEAM_BLUE ) | |
( g_gametype . integer = = GT_CTF & & client - > sess . sessionTeam ! = TEAM_RED & & client - > sess . sessionTeam ! = TEAM_BLUE ) ) {
2002-01-11 20:20:58 +00:00
client - > sess . sessionTeam = TEAM_SPECTATOR ;
2002-02-27 01:54:29 +00:00
client - > ps . persistant [ PERS_SAVEDTEAM ] = TEAM_SPECTATOR ;
client - > ps . persistant [ PERS_TEAM ] = TEAM_SPECTATOR ;
2002-02-10 16:26:55 +00:00
client - > sess . spectatorState = SPECTATOR_FREE ;
2002-04-02 20:23:12 +00:00
client - > specMode = SPECTATOR_FREE ;
client - > ps . pm_flags & = ~ PMF_FOLLOW ;
client - > ps . stats [ STAT_RQ3 ] & = ~ RQ3_ZCAM ;
RQ3_SpectatorMode ( ent ) ;
2002-03-03 13:49:28 +00:00
// JBravo: Set grenades to short, and the other weapons to full automatic on connect.
client - > ps . persistant [ PERS_WEAPONMODES ] | = RQ3_GRENSHORT ;
client - > ps . persistant [ PERS_WEAPONMODES ] & = ~ RQ3_GRENMED ;
client - > ps . persistant [ PERS_WEAPONMODES ] | = RQ3_KNIFEMODE ;
client - > ps . persistant [ PERS_WEAPONMODES ] & = ~ RQ3_MP5MODE ;
client - > ps . persistant [ PERS_WEAPONMODES ] & = ~ RQ3_M4MODE ;
client - > ps . persistant [ PERS_WEAPONMODES ] & = ~ RQ3_MK23MODE ;
2002-02-26 21:59:10 +00:00
client - > camera - > mode = CAMERA_MODE_SWING ;
2002-01-11 20:20:58 +00:00
}
2001-07-03 10:26:42 +00:00
2002-02-26 21:59:10 +00:00
if ( client - > sess . sessionTeam ! = TEAM_SPECTATOR & & g_gametype . integer ! = GT_TEAMPLAY ) {
2002-06-16 20:06:15 +00:00
client - > ps . persistant [ PERS_WEAPONMODES ] | = RQ3_GRENSHORT ; //set to short range
client - > ps . persistant [ PERS_WEAPONMODES ] | = RQ3_KNIFEMODE ; //set to slash attack
2001-05-06 20:50:27 +00:00
2002-04-02 20:23:12 +00:00
if ( g_gametype . integer ! = GT_TOURNAMENT ) {
2002-06-16 20:06:15 +00:00
trap_SendServerCommand ( - 1 ,
va ( " print \" %s " S_COLOR_WHITE " entered the game \n \" " ,
client - > pers . netname ) ) ;
2001-05-06 20:50:27 +00:00
}
}
2002-04-02 20:23:12 +00:00
G_LogPrintf ( " ClientBegin: %i \n " , clientNum ) ;
2001-05-06 20:50:27 +00:00
2002-07-26 06:21:43 +00:00
// JBravo: synching the cvars over to clients for the MM ingame menu.
if ( g_gametype . integer = = GT_TEAMPLAY & & g_RQ3_matchmode . integer ) {
for ( i = 0 ; i < 9 ; + + i ) {
trap_SendServerCommand ( ent - g_entities , va ( " rq3_cmd %i %s %i " , CVARSET , settings2 [ i ] ,
trap_Cvar_VariableIntegerValue ( settings [ i ] ) ) ) ;
}
2002-07-26 22:28:38 +00:00
trap_SendServerCommand ( ent - g_entities , va ( " rq3_cmd %i cg_RQ3_capturelimit %i " , CVARSET ,
trap_Cvar_VariableIntegerValue ( " capturelimit " ) ) ) ;
2002-07-26 06:21:43 +00:00
}
2002-07-26 22:28:38 +00:00
// JBravo: setting cvars for the about menu
trap_Cvar_VariableStringBuffer ( " sv_hostname " , str , sizeof ( str ) ) ;
trap_SendServerCommand ( ent - g_entities , va ( " rq3_cmd %i cg_RQ3_hostname %s " , CVARSET , str ) ) ;
trap_SendServerCommand ( ent - g_entities , va ( " rq3_cmd %i cg_RQ3_needpass %i " , CVARSET , g_needpass . integer ) ) ;
trap_SendServerCommand ( ent - g_entities , va ( " rq3_cmd %i cg_RQ3_dmflags %i " , CVARSET , g_dmflags . integer ) ) ;
trap_SendServerCommand ( ent - g_entities , va ( " rq3_cmd %i cg_RQ3_showOwnKills %i " , CVARSET , g_RQ3_showOwnKills . integer ) ) ;
trap_SendServerCommand ( ent - g_entities , va ( " rq3_cmd %i cg_RQ3_timelimit %i " , CVARSET , g_timelimit . integer ) ) ;
trap_SendServerCommand ( ent - g_entities , va ( " rq3_cmd %i cg_RQ3_fraglimit %i " , CVARSET , g_fraglimit . integer ) ) ;
trap_SendServerCommand ( ent - g_entities , va ( " rq3_cmd %i cg_RQ3_bot_minplayers %i " , CVARSET ,
trap_Cvar_VariableIntegerValue ( " bot_minplayers " ) ) ) ;
2002-07-26 06:21:43 +00:00
2001-05-06 20:50:27 +00:00
// count current clients and rank for scoreboard
CalculateRanks ( ) ;
2001-09-16 04:04:31 +00:00
2002-01-11 20:20:58 +00:00
// JBravo: default weapons
2002-06-24 05:51:51 +00:00
if ( g_gametype . integer = = GT_TEAMPLAY | | g_gametype . integer = = GT_CTF ) {
2002-01-23 15:26:31 +00:00
// NiceAss: Only set it if there is no value. Fix for going into spectator resetting values.
2002-04-07 03:22:48 +00:00
if ( ent - > r . svFlags & SVF_BOT ) {
2002-05-03 18:09:20 +00:00
//Makro - changed to m4/laser from pistol/kevlar
2002-06-16 20:06:15 +00:00
if ( ! client - > teamplayWeapon )
client - > teamplayWeapon = WP_M4 ;
if ( ! client - > teamplayItem )
client - > teamplayItem = HI_LASER ;
2002-04-07 03:22:48 +00:00
} else {
2002-06-16 20:06:15 +00:00
if ( ! client - > teamplayWeapon )
client - > teamplayWeapon = WP_MP5 ;
if ( ! client - > teamplayItem )
client - > teamplayItem = HI_KEVLAR ;
2002-04-07 03:22:48 +00:00
}
2002-06-16 20:06:15 +00:00
i = RQ3TeamCount ( - 1 , client - > sess . sessionTeam ) ;
2002-01-11 20:20:58 +00:00
}
2002-06-11 23:37:27 +00:00
2001-05-06 20:50:27 +00:00
}
/*
= = = = = = = = = = =
ClientSpawn
Called every time a client is placed fresh in the world :
after the first ClientBegin , and after each respawn
Initializes all non - persistant parts of playerState
= = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void ClientSpawn ( gentity_t * ent )
{
int index ;
vec3_t spawn_origin , spawn_angles ;
gclient_t * client ;
int i ;
clientPersistant_t saved ;
clientSession_t savedSess ;
int persistant [ MAX_PERSISTANT ] ;
gentity_t * spawnPoint ;
int flags ;
int savedPing ;
// char *savedAreaBits;
int accuracy_hits , accuracy_shots ;
int eventSequence ;
int savedWeapon , savedItem , savedSpec ; // JBravo: to save weapon/item info
int savedRadiopower , savedRadiogender ; // JBravo: for radio.
2002-08-07 03:35:57 +00:00
int savedMaleSet , savedFemaleSet ; // JBravo: for soundset saves.
2002-06-16 20:06:15 +00:00
camera_t savedCamera ; // JBravo: to save camera stuff
char userinfo [ MAX_INFO_STRING ] ;
2002-08-21 07:00:07 +00:00
char * classname ;
2001-05-06 20:50:27 +00:00
2002-06-17 00:23:59 +00:00
//Slicer : Laser FIX
//Try to turn the laser off if it's on
if ( ent - > client - > lasersight )
Laser_Gen ( ent , qfalse ) ;
2001-05-06 20:50:27 +00:00
index = ent - g_entities ;
client = ent - > client ;
// find a spawn point
// do it before setting health back up, so farthest
// ranging doesn't count this client
2002-06-16 20:06:15 +00:00
if ( client - > sess . sessionTeam = = TEAM_SPECTATOR ) {
2002-08-21 07:00:07 +00:00
if ( g_gametype . integer = = GT_CTF & & ( client - > sess . savedTeam = = TEAM_RED | | client - > sess . savedTeam = = TEAM_BLUE ) ) {
spawnPoint = NULL ;
if ( client - > sess . savedTeam = = TEAM_RED )
classname = " team_CTF_redflag " ;
else if ( client - > sess . savedTeam = = TEAM_BLUE )
classname = " team_CTF_blueflag " ;
else
G_Printf ( " Wtf ? What team are U on boy ? \n " ) ;
while ( ( spawnPoint = G_Find ( spawnPoint , FOFS ( classname ) , classname ) ) ! = NULL ) {
if ( ! ( spawnPoint - > flags & FL_DROPPED_ITEM ) )
break ;
}
if ( spawnPoint ) {
VectorCopy ( spawnPoint - > r . currentOrigin , spawn_origin ) ;
VectorCopy ( spawnPoint - > s . angles , spawn_angles ) ;
spawn_origin [ 2 ] + = 30 ;
}
} else if ( VectorLength ( ent - > client - > ps . origin ) = = 0.0f ) {
2002-06-04 07:12:32 +00:00
// Origin is not set yet? Use a spawn point
2002-06-16 20:06:15 +00:00
spawnPoint = SelectSpectatorSpawnPoint ( spawn_origin , spawn_angles ) ;
} // Have a set origin already? Use it. (where you died or changed to spectator)
2002-06-04 07:12:32 +00:00
else {
spawnPoint = NULL ;
2002-06-16 20:06:15 +00:00
VectorCopy ( ent - > client - > ps . origin , spawn_origin ) ;
VectorCopy ( ent - > client - > ps . viewangles , spawn_angles ) ;
2002-06-04 07:12:32 +00:00
}
2002-06-16 20:06:15 +00:00
} else if ( g_gametype . integer > = GT_CTF ) {
2001-05-06 20:50:27 +00:00
// all base oriented team games use the CTF spawn points
2002-06-16 20:06:15 +00:00
spawnPoint = SelectCTFSpawnPoint ( client - > sess . sessionTeam ,
client - > pers . teamState . state , spawn_origin , spawn_angles ) ;
2002-01-11 20:20:58 +00:00
// JBravo: If we are in Teamplay mode, use the teamspawnpoints.
2002-06-16 20:06:15 +00:00
} else if ( g_gametype . integer = = GT_TEAMPLAY ) {
2002-06-19 18:13:57 +00:00
// Freud: Assign the spawns from the spawning system (g_teamplay.c)
level . team1spawnpoint = level . teamplay_spawns [ 0 ] ;
level . team2spawnpoint = level . teamplay_spawns [ 1 ] ;
2002-01-11 20:20:58 +00:00
if ( client - > sess . sessionTeam = = TEAM_RED ) {
client - > sess . spawnPoint = level . team1spawnpoint ;
spawnPoint = level . team1spawnpoint ;
2002-06-19 18:13:57 +00:00
VectorCopy ( level . team1spawnpoint - > s . angles , spawn_angles ) ;
VectorCopy ( level . team1spawnpoint - > s . origin , spawn_origin ) ;
2002-01-11 20:20:58 +00:00
} else {
client - > sess . spawnPoint = level . team2spawnpoint ;
spawnPoint = level . team2spawnpoint ;
2002-06-19 18:13:57 +00:00
VectorCopy ( level . team2spawnpoint - > s . angles , spawn_angles ) ;
VectorCopy ( level . team2spawnpoint - > s . origin , spawn_origin ) ;
2002-01-11 20:20:58 +00:00
}
2002-06-21 11:55:32 +00:00
// Freud: Quake3 moves spawns up 9 pixs?
spawn_origin [ 2 ] + = 9 ;
2002-01-11 20:20:58 +00:00
// End JBravo.
2001-05-06 20:50:27 +00:00
} else {
do {
// the first spawn should be at a good looking spot
2002-06-16 20:06:15 +00:00
if ( ! client - > pers . initialSpawn & & client - > pers . localClient ) {
2001-05-06 20:50:27 +00:00
client - > pers . initialSpawn = qtrue ;
2002-06-16 20:06:15 +00:00
spawnPoint = SelectInitialSpawnPoint ( spawn_origin , spawn_angles ) ;
2001-05-06 20:50:27 +00:00
} else {
// don't spawn near existing origin if possible
2002-06-16 20:06:15 +00:00
spawnPoint = SelectSpawnPoint ( client - > ps . origin , spawn_origin , spawn_angles ) ;
2001-05-06 20:50:27 +00:00
}
// Tim needs to prevent bots from spawning at the initial point
// on q3dm0...
2002-06-16 20:06:15 +00:00
if ( ( spawnPoint - > flags & FL_NO_BOTS ) & & ( ent - > r . svFlags & SVF_BOT ) ) {
2001-05-06 20:50:27 +00:00
continue ; // try again
}
// just to be symetric, we have a nohumans option...
2002-06-16 20:06:15 +00:00
if ( ( spawnPoint - > flags & FL_NO_HUMANS ) & & ! ( ent - > r . svFlags & SVF_BOT ) ) {
2001-05-06 20:50:27 +00:00
continue ; // try again
}
break ;
2002-06-16 20:06:15 +00:00
} while ( 1 ) ;
2001-05-06 20:50:27 +00:00
}
client - > pers . teamState . state = TEAM_ACTIVE ;
// toggle the teleport bit so the client knows to not lerp
// and never clear the voted flag
flags = ent - > client - > ps . eFlags & ( EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED ) ;
flags ^ = EF_TELEPORT_BIT ;
// clear everything but the persistant data
saved = client - > pers ;
savedSess = client - > sess ;
savedPing = client - > ps . ping ;
2002-06-16 20:06:15 +00:00
// savedAreaBits = client->areabits;
2001-05-06 20:50:27 +00:00
accuracy_hits = client - > accuracy_hits ;
accuracy_shots = client - > accuracy_shots ;
2001-08-03 22:46:49 +00:00
2002-06-16 20:06:15 +00:00
for ( i = 0 ; i < MAX_PERSISTANT ; i + + ) {
2001-05-06 20:50:27 +00:00
persistant [ i ] = client - > ps . persistant [ i ] ;
}
eventSequence = client - > ps . eventSequence ;
2002-01-11 20:20:58 +00:00
// JBravo: save weapon/item info
savedWeapon = client - > teamplayWeapon ;
savedItem = client - > teamplayItem ;
2002-03-26 11:32:05 +00:00
savedSpec = client - > specMode ;
2002-03-14 02:24:39 +00:00
// JBravo: save radiosettings
savedRadiopower = client - > radioOff ;
savedRadiogender = client - > radioGender ;
2002-08-07 03:35:57 +00:00
savedMaleSet = client - > radioSetMale ;
savedFemaleSet = client - > radioSetFemale ;
2002-06-16 20:06:15 +00:00
memcpy ( & savedCamera , & client - > camera , sizeof ( camera_t ) ) ;
2002-01-11 20:20:58 +00:00
2002-06-16 20:06:15 +00:00
memset ( client , 0 , sizeof ( * client ) ) ; // bk FIXME: Com_Memset?
2001-05-06 20:50:27 +00:00
2002-01-11 20:20:58 +00:00
// JBravo: restore weapon/item info
client - > teamplayWeapon = savedWeapon ;
client - > teamplayItem = savedItem ;
2002-03-26 11:32:05 +00:00
client - > specMode = savedSpec ;
2002-03-14 02:24:39 +00:00
// JBravo: restore radiosettings
client - > radioOff = savedRadiopower ;
client - > radioGender = savedRadiogender ;
2002-08-07 03:35:57 +00:00
client - > radioSetMale = savedMaleSet ;
client - > radioSetFemale = savedFemaleSet ;
2002-06-16 20:06:15 +00:00
memcpy ( & client - > camera , & savedCamera , sizeof ( camera_t ) ) ;
2002-01-11 20:20:58 +00:00
2001-05-06 20:50:27 +00:00
client - > pers = saved ;
client - > sess = savedSess ;
client - > ps . ping = savedPing ;
client - > accuracy_hits = accuracy_hits ;
client - > accuracy_shots = accuracy_shots ;
2002-03-14 23:54:12 +00:00
client - > lastkilled_client [ 0 ] = NULL ;
2002-04-01 22:23:14 +00:00
//Slicer
client - > weapon_attempts = 0 ;
client - > weapon_after_bandage_warned = qfalse ;
2002-05-31 17:32:11 +00:00
client - > gibbed = qfalse ;
2001-11-25 23:04:08 +00:00
2002-06-16 20:06:15 +00:00
for ( i = 0 ; i < MAX_PERSISTANT ; i + + ) {
2001-05-06 20:50:27 +00:00
client - > ps . persistant [ i ] = persistant [ i ] ;
}
client - > ps . eventSequence = eventSequence ;
// increment the spawncount so the client will detect the respawn
client - > ps . persistant [ PERS_SPAWN_COUNT ] + + ;
client - > ps . persistant [ PERS_TEAM ] = client - > sess . sessionTeam ;
client - > airOutTime = level . time + 12000 ;
2002-06-16 20:06:15 +00:00
trap_GetUserinfo ( index , userinfo , sizeof ( userinfo ) ) ;
2001-05-06 20:50:27 +00:00
// set max health
2002-06-16 20:06:15 +00:00
client - > pers . maxHealth = atoi ( Info_ValueForKey ( userinfo , " handicap " ) ) ;
if ( client - > pers . maxHealth < 1 | | client - > pers . maxHealth > 100 ) {
2001-05-06 20:50:27 +00:00
client - > pers . maxHealth = 100 ;
}
// clear entity values
//client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth;
client - > ps . eFlags = flags ;
ent - > s . groundEntityNum = ENTITYNUM_NONE ;
ent - > client = & level . clients [ index ] ;
ent - > takedamage = qtrue ;
ent - > inuse = qtrue ;
ent - > classname = " player " ;
ent - > r . contents = CONTENTS_BODY ;
ent - > clipmask = MASK_PLAYERSOLID ;
ent - > die = player_die ;
ent - > waterlevel = 0 ;
ent - > watertype = 0 ;
ent - > flags = 0 ;
2001-11-25 23:04:08 +00:00
2002-06-16 20:06:15 +00:00
VectorCopy ( playerMins , ent - > r . mins ) ;
VectorCopy ( playerMaxs , ent - > r . maxs ) ;
2001-05-06 20:50:27 +00:00
client - > ps . clientNum = index ;
2001-12-17 15:08:34 +00:00
2002-06-16 20:06:15 +00:00
camera_begin ( ent ) ;
2001-12-17 15:08:34 +00:00
2001-05-06 20:50:27 +00:00
//Blaze: changed WP_MACHINEGUN to WP_PISTOL, makes the base weapon you start with the pistol
2002-01-11 20:20:58 +00:00
// JBravo: Not in TP
2002-06-24 05:51:51 +00:00
if ( g_gametype . integer ! = GT_TEAMPLAY & & g_gametype . integer ! = GT_CTF ) {
2002-06-16 20:06:15 +00:00
client - > ps . stats [ STAT_WEAPONS ] = ( 1 < < WP_PISTOL ) ;
2002-03-01 18:21:26 +00:00
client - > numClips [ WP_PISTOL ] = 0 ;
2002-01-11 20:20:58 +00:00
client - > ps . ammo [ WP_PISTOL ] = ClipAmountForAmmo ( WP_PISTOL ) ;
}
2001-05-06 20:50:27 +00:00
//Blaze: Changed WP_GAUNTLET to WP_KNIFE
2002-06-16 20:06:15 +00:00
client - > ps . stats [ STAT_WEAPONS ] | = ( 1 < < WP_KNIFE ) ;
2001-05-06 20:50:27 +00:00
//Blaze: 1 knife to start with
client - > ps . ammo [ WP_KNIFE ] = 1 ;
//Blaze: No Grappling Hook in reaction
2002-06-16 20:06:15 +00:00
// client->ps.ammo[WP_GRAPPLING_HOOK] = -1;
2001-05-06 20:50:27 +00:00
//Blaze: Set the bandage variable to 0
2002-06-16 20:06:15 +00:00
client - > bleedtick = 0 ;
2001-05-06 20:50:27 +00:00
// health will count down towards max_health
2002-06-16 20:06:15 +00:00
ent - > health = client - > ps . stats [ STAT_HEALTH ] = 100 ; // max health of 100 client->ps.stats[STAT_MAX_HEALTH];//Blaze: removed * 1.25 becase we wanna start at 100 health
2001-06-25 23:46:12 +00:00
// reset streak count
2001-08-30 09:47:39 +00:00
client - > killStreak = 0 ;
2002-06-04 07:12:32 +00:00
2002-06-16 20:06:15 +00:00
G_SetOrigin ( ent , spawn_origin ) ;
VectorCopy ( spawn_origin , client - > ps . origin ) ;
2001-05-06 20:50:27 +00:00
2002-06-05 22:09:21 +00:00
// the respawned flag will be cleared after the attack and jump keys come up
client - > ps . pm_flags | = PMF_RESPAWNED ;
2001-05-06 20:50:27 +00:00
2002-06-16 20:06:15 +00:00
trap_GetUsercmd ( client - level . clients , & ent - > client - > pers . cmd ) ;
SetClientViewAngle ( ent , spawn_angles ) ;
2002-06-04 07:12:32 +00:00
2002-06-16 20:06:15 +00:00
if ( ent - > client - > sess . sessionTeam = = TEAM_SPECTATOR ) {
2001-05-06 20:50:27 +00:00
} else {
2002-06-16 20:06:15 +00:00
G_KillBox ( ent ) ;
trap_LinkEntity ( ent ) ;
2001-05-06 20:50:27 +00:00
// force the base weapon up
//Blaze: Changed WP_MACHINEGUN to WP_PISTOL
2002-01-11 20:20:58 +00:00
// JBravo: we dont want the endless pistol in TP
2002-06-16 20:06:15 +00:00
if ( g_gametype . integer ! = GT_TEAMPLAY ) {
2002-03-01 18:21:26 +00:00
client - > ps . weapon = WP_PISTOL ;
client - > ps . weaponstate = WEAPON_READY ;
2002-01-11 20:20:58 +00:00
}
2001-05-06 20:50:27 +00:00
}
//Blaze: Set the opendoor flag to 0
client - > openDoor = qfalse ;
2001-08-13 17:26:53 +00:00
client - > openDoorTime = 0 ;
2001-05-06 20:50:27 +00:00
// don't allow full run speed for a bit
client - > ps . pm_flags | = PMF_TIME_KNOCKBACK ;
client - > ps . pm_time = 100 ;
client - > respawnTime = level . time ;
client - > inactivityTime = level . time + g_inactivity . integer * 1000 ;
client - > latched_buttons = 0 ;
2001-06-18 01:59:58 +00:00
//Elder: reset all RQ3 non-persistent stats
ent - > client - > ps . stats [ STAT_RQ3 ] = 0 ;
2001-11-25 23:04:08 +00:00
2002-03-30 02:29:43 +00:00
// JBravo: remember saved specmodes.
if ( g_gametype . integer = = GT_TEAMPLAY & & client - > sess . sessionTeam = = TEAM_SPECTATOR ) {
if ( client - > specMode = = SPECTATOR_FOLLOW | | client - > specMode = = SPECTATOR_FREE ) {
client - > sess . spectatorState = client - > specMode ;
client - > ps . stats [ STAT_RQ3 ] & = ~ RQ3_ZCAM ;
}
if ( client - > specMode = = SPECTATOR_ZCAM & & client - > sess . sessionTeam = = TEAM_SPECTATOR ) {
client - > sess . spectatorState = client - > specMode ;
client - > ps . stats [ STAT_RQ3 ] | = RQ3_ZCAM ;
client - > ps . pm_flags & = ~ PMF_FOLLOW ;
}
}
2001-06-18 01:59:58 +00:00
//Elder: set weaponfireNextTime amount
client - > weaponfireNextTime = 0 ;
2001-07-03 10:26:42 +00:00
2001-06-24 02:08:15 +00:00
//Elder: Initialize fast reloads stuff
client - > fastReloads = 0 ;
client - > lastReloadTime = 0 ;
//Elder: initialize consecutive shots for M4 ride-up
client - > consecutiveShots = 0 ;
2001-05-06 20:50:27 +00:00
// set default animations
client - > ps . torsoAnim = TORSO_STAND ;
client - > ps . legsAnim = LEGS_IDLE ;
2001-08-17 20:48:18 +00:00
// weapon animations
2002-06-24 05:51:51 +00:00
if ( g_gametype . integer ! = GT_TEAMPLAY & & g_gametype . integer ! = GT_CTF )
2002-06-16 20:06:15 +00:00
client - > ps . generic1 = ( ( client - > ps . generic1 & ANIM_TOGGLEBIT )
^ ANIM_TOGGLEBIT ) | WP_ANIM_IDLE ;
2001-11-25 23:04:08 +00:00
2002-06-16 20:06:15 +00:00
if ( level . intermissiontime ) {
MoveClientToIntermission ( ent ) ;
2001-05-06 20:50:27 +00:00
} else {
// fire the targets of the spawn point
2002-06-16 20:06:15 +00:00
if ( spawnPoint )
G_UseTargets ( spawnPoint , ent ) ;
2001-05-06 20:50:27 +00:00
// select the highest weapon number available, after any
// spawn given items have fired
2002-01-23 15:26:31 +00:00
// JBravo: Lets make sure we have the right weapons
2002-07-11 04:32:24 +00:00
if ( ( g_gametype . integer = = GT_TEAMPLAY | | g_gametype . integer = = GT_CTF ) & &
( client - > sess . sessionTeam = = TEAM_RED | | client - > sess . sessionTeam = = TEAM_BLUE ) ) {
2002-01-11 20:20:58 +00:00
EquipPlayer ( ent ) ;
} else {
2002-01-23 15:26:31 +00:00
client - > ps . weapon = 1 ;
2002-06-16 20:06:15 +00:00
for ( i = WP_NUM_WEAPONS - 1 ; i > 0 ; i - - ) {
if ( i = = WP_KNIFE )
2002-01-23 15:26:31 +00:00
continue ;
2002-06-16 20:06:15 +00:00
if ( client - > ps . stats [ STAT_WEAPONS ] & ( 1 < < i ) ) {
2002-01-23 15:26:31 +00:00
client - > ps . weapon = i ;
break ;
}
2001-05-06 20:50:27 +00:00
}
}
}
// run a client frame to drop exactly to the floor,
// initialize animations and other things
client - > ps . commandTime = level . time - 100 ;
ent - > client - > pers . cmd . serverTime = level . time ;
2002-03-26 10:32:52 +00:00
// JBravo: We should not have to call this during TP spawns
if ( g_gametype . integer ! = GT_TEAMPLAY )
2002-06-16 20:06:15 +00:00
ClientThink ( ent - g_entities ) ;
2001-05-06 20:50:27 +00:00
// positively link the client, even if the command times are weird
2002-06-16 20:06:15 +00:00
if ( ent - > client - > sess . sessionTeam ! = TEAM_SPECTATOR ) {
BG_PlayerStateToEntityState ( & client - > ps , & ent - > s , qtrue ) ;
VectorCopy ( ent - > client - > ps . origin , ent - > r . currentOrigin ) ;
trap_LinkEntity ( ent ) ;
2001-05-06 20:50:27 +00:00
}
// run the presend to set anything else
2002-03-26 10:32:52 +00:00
// JBravo: We should not have to call this during TP spawns
if ( g_gametype . integer ! = GT_TEAMPLAY )
2002-06-16 20:06:15 +00:00
ClientEndFrame ( ent ) ;
ent - > client - > noHead = qfalse ;
2001-05-06 20:50:27 +00:00
2002-08-21 07:00:07 +00:00
// JBravo: lock the player down
if ( g_gametype . integer = = GT_CTF & & ent - > client - > sess . sessionTeam = = TEAM_SPECTATOR & &
( ent - > client - > sess . savedTeam = = TEAM_RED | | ent - > client - > sess . savedTeam = = TEAM_BLUE ) )
ent - > client - > ps . pm_type = PM_FREEZE ;
2001-05-06 20:50:27 +00:00
// clear entity state values
2002-06-16 20:06:15 +00:00
BG_PlayerStateToEntityState ( & client - > ps , & ent - > s , qtrue ) ;
2001-05-06 20:50:27 +00:00
}
/*
= = = = = = = = = = =
ClientDisconnect
Called when a player drops from the server .
Will not be called between levels .
This should NOT be called directly by any game logic ,
call trap_DropClient ( ) , which will call this and do
server system housekeeping .
= = = = = = = = = = = =
*/
2002-06-16 20:06:15 +00:00
void ClientDisconnect ( int clientNum )
{
gentity_t * ent ;
gentity_t * tent ;
int oldTeam = 0 , i ;
2001-05-06 20:50:27 +00:00
// cleanup if we are kicking a bot that
// hasn't spawned yet
2002-06-16 20:06:15 +00:00
G_RemoveQueuedBotBegin ( clientNum ) ;
2001-05-06 20:50:27 +00:00
ent = g_entities + clientNum ;
2002-06-16 20:06:15 +00:00
if ( ! ent - > client ) {
2001-05-06 20:50:27 +00:00
return ;
}
2002-03-02 14:54:24 +00:00
// JBravo: to keep the ui teamcount cvars right.
if ( g_gametype . integer = = GT_TEAMPLAY ) {
oldTeam = ent - > client - > sess . sessionTeam ;
}
2002-02-03 21:23:51 +00:00
//Slicer: matchmode
2002-06-16 20:06:15 +00:00
if ( g_RQ3_matchmode . integer ) {
switch ( ent - > client - > sess . captain ) {
case TEAM_RED :
level . team1ready = qfalse ;
break ;
case TEAM_BLUE :
level . team2ready = qfalse ;
break ;
default :
break ;
2002-02-03 21:23:51 +00:00
}
}
2002-03-07 01:38:36 +00:00
// aasimon: Referee. If player is referee, clean ref
2002-08-23 14:25:05 +00:00
/*if (clientNum == g_RQ3_RefID.integer)
trap_Cvar_Set ( " g_RQ3_RefID " , " -1 " ) ; */
2002-03-17 02:03:48 +00:00
// JBravo: if the client had a laser, turn it off so it doesnt stay there forever.
if ( ent - > client - > lasersight ) {
G_FreeEntity ( ent - > client - > lasersight ) ;
ent - > client - > lasersight = NULL ;
}
2001-05-06 20:50:27 +00:00
// stop any following clients
2002-06-16 20:06:15 +00:00
for ( i = 0 ; i < level . maxclients ; i + + ) {
if ( level . clients [ i ] . sess . sessionTeam = = TEAM_SPECTATOR
& & level . clients [ i ] . sess . spectatorState = = SPECTATOR_FOLLOW
& & level . clients [ i ] . sess . spectatorClient = = clientNum ) {
StopFollowing ( & g_entities [ i ] ) ;
2001-05-06 20:50:27 +00:00
}
}
2002-06-16 20:06:15 +00:00
camera_disconnect ( ent ) ;
2001-12-17 15:08:34 +00:00
2001-05-06 20:50:27 +00:00
// send effect if they were completely connected
2002-06-16 20:06:15 +00:00
if ( ent - > client - > pers . connected = = CON_CONNECTED & & ent - > client - > sess . sessionTeam ! = TEAM_SPECTATOR ) {
tent = G_TempEntity ( ent - > client - > ps . origin , EV_PLAYER_TELEPORT_OUT ) ;
2001-05-06 20:50:27 +00:00
tent - > s . clientNum = ent - > s . clientNum ;
// They don't get to take powerups with them!
// Especially important for stuff like CTF flags
2002-06-16 20:06:15 +00:00
TossClientItems ( ent ) ;
2001-05-06 20:50:27 +00:00
}
2002-04-30 01:23:05 +00:00
// JBravo: Make this more like AQ
2002-06-16 20:06:15 +00:00
// G_LogPrintf( "ClientDisconnect: %i\n", clientNum );
G_LogPrintf ( " %s disconnected (clientNum %i) \n " , ent - > client - > pers . netname , clientNum ) ;
2001-05-06 20:50:27 +00:00
// if we are playing in tourney mode and losing, give a win to the other player
2002-06-16 20:06:15 +00:00
if ( ( g_gametype . integer = = GT_TOURNAMENT )
& & ! level . intermissiontime & & ! level . warmupTime & & level . sortedClients [ 1 ] = = clientNum ) {
level . clients [ level . sortedClients [ 0 ] ] . sess . wins + + ;
ClientUserinfoChanged ( level . sortedClients [ 0 ] ) ;
2001-05-06 20:50:27 +00:00
}
2002-06-16 20:06:15 +00:00
trap_UnlinkEntity ( ent ) ;
2001-05-06 20:50:27 +00:00
ent - > s . modelindex = 0 ;
ent - > inuse = qfalse ;
ent - > classname = " disconnected " ;
ent - > client - > pers . connected = CON_DISCONNECTED ;
ent - > client - > ps . persistant [ PERS_TEAM ] = TEAM_FREE ;
ent - > client - > sess . sessionTeam = TEAM_FREE ;
2002-06-16 20:06:15 +00:00
trap_SetConfigstring ( CS_PLAYERS + clientNum , " " ) ;
2001-05-06 20:50:27 +00:00
CalculateRanks ( ) ;
2002-03-02 14:54:24 +00:00
// JBravo: to keep the ui teamcount cvars right.
if ( g_gametype . integer = = GT_TEAMPLAY ) {
2002-06-16 20:06:15 +00:00
i = RQ3TeamCount ( - 1 , oldTeam ) ;
2002-03-02 14:54:24 +00:00
}
2002-06-16 20:06:15 +00:00
if ( ent - > r . svFlags & SVF_BOT ) {
BotAIShutdownClient ( clientNum , qfalse ) ;
2001-05-06 20:50:27 +00:00
}
}