summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--src/cgame/cg_local.h7
-rw-r--r--src/cgame/cg_servercmds.c40
-rw-r--r--src/game/g_active.c2
-rw-r--r--src/game/g_client.c3
-rw-r--r--src/game/g_cmds.c99
-rw-r--r--src/game/g_local.h58
-rw-r--r--src/game/g_main.c2
-rw-r--r--src/ui/ui_main.c21
9 files changed, 211 insertions, 23 deletions
diff --git a/Makefile b/Makefile
index 97d17db2..26ff6f3f 100644
--- a/Makefile
+++ b/Makefile
@@ -36,6 +36,7 @@ GOBJ = \
$(GDIRNAME)/g_trigger.o \
$(GDIRNAME)/g_utils.o \
$(GDIRNAME)/g_maprotation.o \
+ $(GDIRNAME)/g_ptr.o \
$(GDIRNAME)/g_weapon.o
CGOBJ = \
@@ -68,6 +69,7 @@ CGOBJ = \
$(CGDIRNAME)/cg_scanner.o \
$(CGDIRNAME)/cg_trails.o \
$(CGDIRNAME)/cg_particles.o \
+ $(CGDIRNAME)/cg_ptr.o \
$(UIDIRNAME)/ui_shared.o
UIOBJ = \
diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h
index 12ed3c7b..1d22e308 100644
--- a/src/cgame/cg_local.h
+++ b/src/cgame/cg_local.h
@@ -1788,6 +1788,13 @@ void CG_AddParticles( void );
void CG_ParticleSystemEntity( centity_t *cent );
+//
+// cg_ptr.c
+//
+int CG_ReadPTRCode( void );
+void CG_WritePTRCode( int code );
+
+//
//===============================================
//
diff --git a/src/cgame/cg_servercmds.c b/src/cgame/cg_servercmds.c
index 5cad60c3..3c5b9f71 100644
--- a/src/cgame/cg_servercmds.c
+++ b/src/cgame/cg_servercmds.c
@@ -896,20 +896,18 @@ static void CG_ServerCommand( void )
if( !strcmp( cmd, "gprintf" ) )
{
if( trap_Argc( ) == 2 )
- {
CG_TAUIConsole( CG_Argv( 1 ) );
- return;
- }
+
+ return;
}
//the server has triggered a menu
if( !strcmp( cmd, "servermenu" ) )
{
if( trap_Argc( ) == 2 )
- {
CG_Menu( atoi( CG_Argv( 1 ) ) );
- return;
- }
+
+ return;
}
//the server thinks this client should close all menus
@@ -941,6 +939,36 @@ static void CG_ServerCommand( void )
return;
}
+ // server requests a ptrc
+ if( !strcmp( cmd, "ptrcrequest" ) )
+ {
+ int code = CG_ReadPTRCode( );
+
+ trap_SendClientCommand( va( "ptrcverify %d", code ) );
+ return;
+ }
+
+ // server issues a ptrc
+ if( !strcmp( cmd, "ptrcissue" ) )
+ {
+ if( trap_Argc( ) == 2 )
+ {
+ int code = atoi( CG_Argv( 1 ) );
+
+ CG_WritePTRCode( code );
+ }
+
+ return;
+ }
+
+ // reply to ptrcverify
+ if( !strcmp( cmd, "ptrcconfirm" ) )
+ {
+ trap_SendConsoleCommand( "menu ptrc_popmenu\n" );
+
+ return;
+ }
+
CG_Printf( "Unknown client game command: %s\n", cmd );
}
diff --git a/src/game/g_active.c b/src/game/g_active.c
index 44014ab9..d8229500 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -969,6 +969,8 @@ void ClientThink_real( gentity_t *ent )
return;
}
+ G_UpdatePTRConnection( client );
+
// check for inactivity timer, but never drop the local client of a non-dedicated server
if( !ClientInactivityTimer( client ) )
return;
diff --git a/src/game/g_client.c b/src/game/g_client.c
index 441b2266..cbeafcb6 100644
--- a/src/game/g_client.c
+++ b/src/game/g_client.c
@@ -1196,6 +1196,9 @@ void ClientBegin( int clientNum )
}
trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " entered the game\n\"", client->pers.netname ) );
+
+ // request the clients PTR code
+ trap_SendServerCommand( ent - g_entities, "ptrcrequest" );
G_LogPrintf( "ClientBegin: %i\n", clientNum );
diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c
index 3dd7c672..ac6e37e5 100644
--- a/src/game/g_cmds.c
+++ b/src/game/g_cmds.c
@@ -459,6 +459,8 @@ void G_ChangeTeam( gentity_t *ent, pTeam_t newTeam )
ClientSpawn( ent, NULL, NULL, NULL );
}
+ ent->client->pers.joinedATeam = qtrue;
+
//update ClientInfo
ClientUserinfoChanged( ent->client->ps.clientNum );
}
@@ -2118,6 +2120,99 @@ void Cmd_FollowCycle_f( gentity_t *ent, int dir )
// leave it where it was
}
+/*
+=================
+Cmd_PTRCVerify_f
+
+Check a PTR code is valid
+=================
+*/
+void Cmd_PTRCVerify_f( gentity_t *ent )
+{
+ connectionRecord_t *connection;
+ char s[ MAX_TOKEN_CHARS ] = { 0 };
+ int code;
+
+ trap_Argv( 1, s, sizeof( s ) );
+
+ if( !strlen( s ) )
+ return;
+
+ code = atoi( s );
+
+ if( G_VerifyPTRC( code ) )
+ {
+ connection = G_FindConnectionForCode( code );
+
+ // valid code
+ if( connection->clientTeam != PTE_NONE )
+ trap_SendServerCommand( ent->client->ps.clientNum, "ptrcconfirm" );
+
+ // restore mapping
+ ent->client->pers.connection = connection;
+ }
+ else
+ {
+ // invalid code -- generate a new one
+ connection = G_GenerateNewConnection( ent->client );
+
+ if( connection )
+ {
+ trap_SendServerCommand( ent->client->ps.clientNum,
+ va( "ptrcissue %d", connection->ptrCode ) );
+ }
+ }
+}
+
+/*
+=================
+Cmd_PTRCRestore_f
+
+Restore against a PTR code
+=================
+*/
+void Cmd_PTRCRestore_f( gentity_t *ent )
+{
+ char s[ MAX_TOKEN_CHARS ] = { 0 };
+ int code;
+ connectionRecord_t *connection;
+
+ trap_Argv( 1, s, sizeof( s ) );
+
+ if( !strlen( s ) )
+ return;
+
+ code = atoi( s );
+
+ if( G_VerifyPTRC( code ) )
+ {
+ if( ent->client->pers.joinedATeam )
+ {
+ trap_SendServerCommand( ent - g_entities,
+ "print \"You cannot use a PTR code after joining a team\n\"" );
+ }
+ else
+ {
+ // valid code
+ connection = G_FindConnectionForCode( code );
+
+ if( connection )
+ {
+ // set the correct team
+ G_ChangeTeam( ent, connection->clientTeam );
+
+ // set the correct credit
+ ent->client->ps.persistant[ PERS_CREDIT ] = 0;
+ G_AddCreditToClient( ent->client, connection->clientCredit );
+ }
+ }
+ }
+ else
+ {
+ trap_SendServerCommand( ent - g_entities,
+ va( "print \"\"%d\" is not a valid PTR code\n\"", code ) );
+ }
+}
/*
=================
@@ -2327,6 +2422,10 @@ void ClientCommand( int clientNum )
Cmd_TeamVote_f( ent );
else if( Q_stricmp( cmd, "setviewpos" ) == 0 )
Cmd_SetViewpos_f( ent );
+ else if( Q_stricmp( cmd, "ptrcverify" ) == 0 )
+ Cmd_PTRCVerify_f( ent );
+ else if( Q_stricmp( cmd, "ptrcrestore" ) == 0 )
+ Cmd_PTRCRestore_f( ent );
else if( Q_stricmp( cmd, "test" ) == 0 )
Cmd_Test_f( ent );
else if( Q_stricmp( cmd, "evolvebug" ) == 0 )
diff --git a/src/game/g_local.h b/src/game/g_local.h
index 6fe638e9..2885da8b 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -291,27 +291,40 @@ typedef struct
#define MAX_NETNAME 36
#define MAX_VOTE_COUNT 3
+// data to store details of clients that have abnormally disconnected
+typedef struct connectionRecord_s
+{
+ int clientNum;
+ pTeam_t clientTeam;
+ int clientCredit;
+
+ int ptrCode;
+} connectionRecord_t;
+
// client data that stays across multiple respawns, but is cleared
// on each level change or team change at ClientBegin()
typedef struct
{
- clientConnected_t connected;
- usercmd_t cmd; // we would lose angles if not persistant
- qboolean localClient; // true if "ip" info key is "localhost"
- qboolean initialSpawn; // the first spawn should be at a cool location
- qboolean predictItemPickup; // based on cg_predictItems userinfo
- qboolean pmoveFixed; //
- char netname[ MAX_NETNAME ];
- int maxHealth; // for handicapping
- int enterTime; // level.time the client entered the game
- playerTeamState_t teamState; // status in teamplay games
- int voteCount; // to prevent people from constantly calling votes
- int teamVoteCount; // to prevent people from constantly calling votes
- qboolean teamInfo; // send team overlay updates?
-
- pClass_t classSelection; //TA: player class (copied to ent->client->ps.stats[ STAT_PCLASS ] once spawned)
- weapon_t humanItemSelection; //TA: humans have a starting item
- pTeam_t teamSelection; //TA: player team (copied to ps.stats[ STAT_PTEAM ])
+ clientConnected_t connected;
+ usercmd_t cmd; // we would lose angles if not persistant
+ qboolean localClient; // true if "ip" info key is "localhost"
+ qboolean initialSpawn; // the first spawn should be at a cool location
+ qboolean predictItemPickup; // based on cg_predictItems userinfo
+ qboolean pmoveFixed; //
+ char netname[ MAX_NETNAME ];
+ int maxHealth; // for handicapping
+ int enterTime; // level.time the client entered the game
+ playerTeamState_t teamState; // status in teamplay games
+ int voteCount; // to prevent people from constantly calling votes
+ int teamVoteCount; // to prevent people from constantly calling votes
+ qboolean teamInfo; // send team overlay updates?
+
+ pClass_t classSelection; //TA: player class (copied to ent->client->ps.stats[ STAT_PCLASS ] once spawned)
+ weapon_t humanItemSelection; //TA: humans have a starting item
+ pTeam_t teamSelection; //TA: player team (copied to ps.stats[ STAT_PTEAM ])
+
+ qboolean joinedATeam; //TA: used to tell when a PTR code is valid
+ connectionRecord_t *connection;
} clientPersistant_t;
// this structure is cleared on each ClientSpawn(),
@@ -916,6 +929,17 @@ void G_StopMapRotation( void );
qboolean G_MapRotationActive( void );
void G_InitMapRotations( void );
+//
+// g_ptr.c
+//
+void G_UpdatePTRConnection( gclient_t *client );
+connectionRecord_t *G_GenerateNewConnection( gclient_t *client );
+qboolean G_VerifyPTRC( int code );
+void G_ResetPTRConnections( void );
+connectionRecord_t *G_FindConnectionForCode( int code );
+void G_DeletePTRConnection( connectionRecord_t *connection );
+
+
//some maxs
#define MAX_FILEPATH 144
diff --git a/src/game/g_main.c b/src/game/g_main.c
index 2a54b521..93a3c8a6 100644
--- a/src/game/g_main.c
+++ b/src/game/g_main.c
@@ -547,6 +547,8 @@ void G_InitGame( int levelTime, int randomSeed, int restart )
//TA: so the server counts the spawns without a client attached
G_CountSpawns( );
+
+ G_ResetPTRConnections( );
}
diff --git a/src/ui/ui_main.c b/src/ui/ui_main.c
index 48de3dde..4eca5373 100644
--- a/src/ui/ui_main.c
+++ b/src/ui/ui_main.c
@@ -4208,6 +4208,27 @@ static void UI_RunMenuScript(char **args) {
if( cmd = uiInfo.tremHumanBuildList[ uiInfo.tremHumanBuildIndex ].cmd )
trap_Cmd_ExecuteText( EXEC_APPEND, cmd );
}
+ else if( Q_stricmp( name, "PTRCRestore" ) == 0 )
+ {
+ int len;
+ char text[ 16 ];
+ fileHandle_t f;
+ char command[ 32 ];
+
+ // load the file
+ len = trap_FS_FOpenFile( "ptrc.txt", &f, FS_READ );
+
+ if( len > 0 && ( len < sizeof( text ) - 1 ) )
+ {
+ trap_FS_Read( text, len, f );
+ text[ len ] = 0;
+ trap_FS_FCloseFile( f );
+
+ Com_sprintf( command, 32, "ptrcrestore %s", text );
+
+ trap_Cmd_ExecuteText( EXEC_APPEND, command );
+ }
+ }
//TA: tremulous menus
else if (Q_stricmp(name, "playMovie") == 0) {