diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/cgame/cg_local.h | 7 | ||||
-rw-r--r-- | src/cgame/cg_servercmds.c | 40 | ||||
-rw-r--r-- | src/game/g_active.c | 2 | ||||
-rw-r--r-- | src/game/g_client.c | 3 | ||||
-rw-r--r-- | src/game/g_cmds.c | 99 | ||||
-rw-r--r-- | src/game/g_local.h | 58 | ||||
-rw-r--r-- | src/game/g_main.c | 2 | ||||
-rw-r--r-- | src/ui/ui_main.c | 21 |
9 files changed, 211 insertions, 23 deletions
@@ -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) { |