diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/cgame/cg_draw.c | 31 | ||||
| -rw-r--r-- | src/game/g_active.c | 31 | ||||
| -rw-r--r-- | src/game/g_client.c | 11 | ||||
| -rw-r--r-- | src/game/g_cmds.c | 255 | ||||
| -rw-r--r-- | src/game/g_local.h | 2 | ||||
| -rw-r--r-- | src/game/g_main.c | 4 | 
6 files changed, 298 insertions, 36 deletions
diff --git a/src/cgame/cg_draw.c b/src/cgame/cg_draw.c index fa046dbb..2158379c 100644 --- a/src/cgame/cg_draw.c +++ b/src/cgame/cg_draw.c @@ -2844,6 +2844,36 @@ static void CG_DrawIntermission( void )    cg.scoreBoardShowing = CG_DrawScoreboard( );  } +#define FOLLOWING_STRING "following " + +/* +================= +CG_DrawFollow +================= +*/ +static qboolean CG_DrawFollow( void ) +{ +  float       w; +  vec4_t      color; +  char        buffer[ MAX_STRING_CHARS ]; + +  if( !( cg.snap->ps.pm_flags & PMF_FOLLOW ) ) +    return qfalse; + +  color[ 0 ] = 1; +  color[ 1 ] = 1; +  color[ 2 ] = 1; +  color[ 3 ] = 1; + +  strcpy( buffer, FOLLOWING_STRING ); +  strcat( buffer, cgs.clientinfo[ cg.snap->ps.clientNum ].name ); + +  w = CG_Text_Width( buffer, 0.7f, 0 ); +  CG_Text_Paint( 320 - w / 2, 400, 0.7f, color, buffer, 0, 0, ITEM_TEXTSTYLE_SHADOWED ); + +  return qtrue; +} +  //==================================================================================  #define SPECTATOR_STRING "SPECTATOR" @@ -2901,6 +2931,7 @@ static void CG_Draw2D( void )    CG_DrawVote( );    CG_DrawTeamVote( ); +  CG_DrawFollow( );    // don't draw center string if scoreboard is up    cg.scoreBoardShowing = CG_DrawScoreboard( ); diff --git a/src/game/g_active.c b/src/game/g_active.c index cad4a2cf..7ef3c810 100644 --- a/src/game/g_active.c +++ b/src/game/g_active.c @@ -317,6 +317,9 @@ void SpectatorThink( gentity_t *ent, usercmd_t *ucmd )    client = ent->client; +  client->oldbuttons = client->buttons; +  client->buttons = ucmd->buttons; +    if( client->sess.spectatorState != SPECTATOR_FOLLOW )    {      if( client->sess.spectatorState == SPECTATOR_LOCKED ) @@ -342,23 +345,23 @@ void SpectatorThink( gentity_t *ent, usercmd_t *ucmd )      G_TouchTriggers( ent );      trap_UnlinkEntity( ent ); -  } - -  client->oldbuttons = client->buttons; -  client->buttons = ucmd->buttons; - -  if( ( client->buttons & BUTTON_ATTACK ) && !( client->oldbuttons & BUTTON_ATTACK ) ) -  { -    if( client->pers.classSelection == PCL_NONE ) +   +    if( ( client->buttons & BUTTON_ATTACK ) && !( client->oldbuttons & BUTTON_ATTACK ) )      { -      if( client->pers.teamSelection == PTE_NONE ) -        G_TriggerMenu( client->ps.clientNum, MN_TEAM ); -      else if( client->pers.teamSelection == PTE_ALIENS ) -        G_TriggerMenu( client->ps.clientNum, MN_A_CLASS ); -      else if( client->pers.teamSelection == PTE_HUMANS ) -        G_TriggerMenu( client->ps.clientNum, MN_H_SPAWN ); +      if( client->pers.classSelection == PCL_NONE ) +      { +        if( client->pers.teamSelection == PTE_NONE ) +          G_TriggerMenu( client->ps.clientNum, MN_TEAM ); +        else if( client->pers.teamSelection == PTE_ALIENS ) +          G_TriggerMenu( client->ps.clientNum, MN_A_CLASS ); +        else if( client->pers.teamSelection == PTE_HUMANS ) +          G_TriggerMenu( client->ps.clientNum, MN_H_SPAWN ); +      }      }    } + +  if( ( client->buttons & BUTTON_ATTACK2 ) && !( client->oldbuttons & BUTTON_ATTACK2 ) ) +    Cmd_FollowCycle_f( ent, 1 );  } diff --git a/src/game/g_client.c b/src/game/g_client.c index 4645780c..35b68f1a 100644 --- a/src/game/g_client.c +++ b/src/game/g_client.c @@ -1497,6 +1497,17 @@ void ClientDisconnect( int clientNum )    if( !ent->client )      return; +  // stop any following clients +  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 ) +    { +      G_StopFollowing( &g_entities[ i ] ); +    } +  } +    // send effect if they were completely connected    if( ent->client->pers.connected == CON_CONNECTED &&        ent->client->sess.sessionTeam != TEAM_SPECTATOR ) diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c index d9d9922c..1145bad1 100644 --- a/src/game/g_cmds.c +++ b/src/game/g_cmds.c @@ -18,6 +18,90 @@  /*  ================== +G_SanitiseName + +Remove case and control characters from a player name +================== +*/ +void G_SanitiseName( char *in, char *out ) +{ +  while( *in ) +  { +    if( *in == 27 ) +    { +      in += 2;    // skip color code +      continue; +    } +     +    if( *in < 32 ) +    { +      in++; +      continue; +    } +     +    *out++ = tolower( *in++ ); +  } + +  *out = 0; +} + +/* +================== +G_ClientNumberFromString + +Returns a player number for either a number or name string +Returns -1 if invalid +================== +*/ +int G_ClientNumberFromString( gentity_t *to, char *s ) +{ +  gclient_t *cl; +  int       idnum; +  char      s2[ MAX_STRING_CHARS ]; +  char      n2[ MAX_STRING_CHARS ]; + +  // numeric values are just slot numbers +  if( s[ 0 ] >= '0' && s[ 0 ] <= '9' ) +  { +    idnum = atoi( s ); +     +    if( idnum < 0 || idnum >= level.maxclients ) +    { +      trap_SendServerCommand( to - g_entities, va( "print \"Bad client slot: %i\n\"", idnum ) ); +      return -1; +    } + +    cl = &level.clients[ idnum ]; +     +    if( cl->pers.connected != CON_CONNECTED ) +    { +      trap_SendServerCommand( to - g_entities, va( "print \"Client %i is not active\n\"", idnum ) ); +      return -1; +    } +     +    return idnum; +  } + +  // check for a name match +  G_SanitiseName( s, s2 ); +   +  for( idnum = 0, cl = level.clients; idnum < level.maxclients; idnum++, cl++ ) +  { +    if( cl->pers.connected != CON_CONNECTED ) +      continue; +     +    G_SanitiseName( cl->pers.netname, n2 ); +     +    if( !strcmp( n2, s2 ) ) +      return idnum; +  } + +  trap_SendServerCommand( to - g_entities, va( "print \"User %s is not on the server\n\"", s ) ); +  return -1; +} + +/* +==================  ScoreboardMessage  ================== @@ -336,17 +420,36 @@ void Cmd_Kill_f( gentity_t *ent )  /*  ================= -Cmd_Team_f +G_ChangeTeam  =================  */ -void Cmd_Team_f( gentity_t *ent ) +void G_ChangeTeam( gentity_t *ent, pTeam_t newTeam )  { -  int     oldTeam; -  char    s[MAX_TOKEN_CHARS]; +  pTeam_t oldTeam = ent->client->pers.teamSelection; -  //TA: rip out the q3a team system :) +  ent->client->pers.teamSelection = newTeam; -  oldTeam = ent->client->pers.teamSelection; +  if( oldTeam != newTeam ) +  { +    level.bankCredits[ ent->client->ps.clientNum ] = 0; +    ent->client->ps.persistant[ PERS_CREDIT ] = 0; +    ent->client->pers.classSelection = PCL_NONE; +    ClientSpawn( ent, NULL, NULL, NULL ); +  } +   +  //update ClientInfo +  ClientUserinfoChanged( ent->client->ps.clientNum ); +} + +/* +================= +Cmd_Team_f +================= +*/ +void Cmd_Team_f( gentity_t *ent ) +{ +  pTeam_t team; +  char    s[ MAX_TOKEN_CHARS ];    trap_Argv( 1, s, sizeof( s ) ); @@ -357,7 +460,7 @@ void Cmd_Team_f( gentity_t *ent )    }    if( !Q_stricmp( s, "spectate" ) ) -    ent->client->pers.teamSelection = PTE_NONE; +    team = PTE_NONE;    else if( !Q_stricmp( s, "aliens" ) )    {      if( g_teamForceBalance.integer && level.numAlienClients > level.numHumanClients ) @@ -367,7 +470,7 @@ void Cmd_Team_f( gentity_t *ent )        return;      } -    ent->client->pers.teamSelection = PTE_ALIENS; +    team = PTE_ALIENS;    }    else if( !Q_stricmp( s, "humans" ) )    { @@ -378,28 +481,19 @@ void Cmd_Team_f( gentity_t *ent )        return;      } -    ent->client->pers.teamSelection = PTE_HUMANS; +    team = PTE_HUMANS;    }    else if( !Q_stricmp( s, "auto" ) )    {      if( level.numHumanClients > level.numAlienClients ) -      ent->client->pers.teamSelection = PTE_ALIENS; +      team = PTE_ALIENS;      else if( level.numHumanClients < level.numAlienClients ) -      ent->client->pers.teamSelection = PTE_HUMANS; +      team = PTE_HUMANS;      else -      ent->client->pers.teamSelection = PTE_ALIENS + ( rand( ) % 2 ); +      team = PTE_ALIENS + ( rand( ) % 2 );    } -  if( oldTeam != ent->client->pers.teamSelection ) -  { -    level.bankCredits[ ent->client->ps.clientNum ] = 0; -    ent->client->ps.persistant[ PERS_CREDIT ] = 0; -    ent->client->pers.classSelection = PCL_NONE; -    ClientSpawn( ent, NULL, NULL, NULL ); -  } - -  //update ClientInfo -  ClientUserinfoChanged( ent->client->ps.clientNum ); +  G_ChangeTeam( ent, team );    //FIXME: put some team change broadcast code here.  } @@ -1715,6 +1809,117 @@ void Cmd_Reload_f( gentity_t *ent )  /*  ================= +G_StopFollowing + +If the client being followed leaves the game, or you just want to drop +to free floating spectator mode +================= +*/ +void G_StopFollowing( gentity_t *ent ) +{ +  ent->client->ps.persistant[ PERS_TEAM ] = TEAM_SPECTATOR;  +  ent->client->sess.sessionTeam = TEAM_SPECTATOR;  +  ent->client->sess.spectatorState = SPECTATOR_FREE; +  ent->client->ps.pm_flags &= ~PMF_FOLLOW; +  ent->r.svFlags &= ~SVF_BOT; +  ent->client->ps.clientNum = ent - g_entities; +} + +/* +================= +Cmd_Follow_f +================= +*/ +void Cmd_Follow_f( gentity_t *ent ) +{ +  int   i; +  char  arg[ MAX_TOKEN_CHARS ]; + +  if( trap_Argc( ) != 2 ) +  { +    if( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) +      G_StopFollowing( ent ); +     +    return; +  } + +  trap_Argv( 1, arg, sizeof( arg ) ); +  i = G_ClientNumberFromString( ent, arg ); +   +  if( i == -1 ) +    return; + +  // can't follow self +  if( &level.clients[ i ] == ent->client ) +    return; + +  // can't follow another spectator +  if( level.clients[ i ].sess.sessionTeam == TEAM_SPECTATOR ) +    return; + +  // first set them to spectator +  if( ent->client->sess.sessionTeam != TEAM_SPECTATOR ) +    G_ChangeTeam( ent, PTE_NONE ); + +  ent->client->sess.spectatorState = SPECTATOR_FOLLOW; +  ent->client->sess.spectatorClient = i; +} + +/* +================= +Cmd_FollowCycle_f +================= +*/ +void Cmd_FollowCycle_f( gentity_t *ent, int dir ) +{ +  int clientnum; +  int original; + +  // first set them to spectator +  if( ent->client->sess.spectatorState == SPECTATOR_NOT ) +    G_ChangeTeam( ent, PTE_NONE ); + +  if( dir != 1 && dir != -1 ) +    G_Error( "Cmd_FollowCycle_f: bad dir %i", dir ); + +  clientnum = ent->client->sess.spectatorClient; +  original = clientnum; +   +  do +  { +    clientnum += dir; +     +    if( clientnum >= level.maxclients ) +      clientnum = 0; +     +    if( clientnum < 0 ) +      clientnum = level.maxclients - 1; + +    // can't follow self +    if( &level.clients[ clientnum ] == ent->client ) +      continue; + +    // can only follow connected clients +    if( level.clients[ clientnum ].pers.connected != CON_CONNECTED ) +      continue; + +    // can't follow another spectator +    if( level.clients[ clientnum ].sess.sessionTeam == TEAM_SPECTATOR ) +      continue; + +    // this is good, we can use it +    ent->client->sess.spectatorClient = clientnum; +    ent->client->sess.spectatorState = SPECTATOR_FOLLOW; +    return; +     +  } while( clientnum != original ); + +  // leave it where it was +} + + +/* +=================  Cmd_Test_f  =================  */ @@ -1826,6 +2031,12 @@ void ClientCommand( int clientNum )      Cmd_Vote_f( ent );    else if( Q_stricmp( cmd, "callteamvote" ) == 0 )      Cmd_CallTeamVote_f( ent ); +	else if( Q_stricmp( cmd, "follow" ) == 0 ) +		Cmd_Follow_f( ent ); +	else if( Q_stricmp (cmd, "follownext") == 0) +		Cmd_FollowCycle_f( ent, 1 ); +	else if( Q_stricmp( cmd, "followprev" ) == 0 ) +		Cmd_FollowCycle_f( ent, -1 );    else if( Q_stricmp( cmd, "teamvote" ) == 0 )      Cmd_TeamVote_f( ent );    else if( Q_stricmp( cmd, "setviewpos" ) == 0 ) diff --git a/src/game/g_local.h b/src/game/g_local.h index 926cecb0..99f6ebf4 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -564,6 +564,8 @@ char      *G_NewString( const char *string );  // g_cmds.c  //  void Cmd_Score_f( gentity_t *ent ); +void G_StopFollowing( gentity_t *ent ); +void Cmd_FollowCycle_f( gentity_t *ent, int dir );  //  // g_physics.c diff --git a/src/game/g_main.c b/src/game/g_main.c index eb81594d..37cd9a01 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -1153,6 +1153,10 @@ If a new client connects, this will be called after the spawn function.  */  void MoveClientToIntermission( gentity_t *ent )  { +	// take out of follow mode if needed +	if( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) +		G_StopFollowing( ent ); +      // move to the spot    VectorCopy( level.intermission_origin, ent->s.origin );    VectorCopy( level.intermission_origin, ent->client->ps.origin );  | 
