Index: src/game/g_local.h =================================================================== --- src/game/g_local.h (revision 939) +++ src/game/g_local.h (working copy) @@ -675,7 +675,7 @@ void Cmd_Score_f( gentity_t *ent ); void G_StopFollowing( gentity_t *ent ); qboolean G_FollowNewClient( gentity_t *ent, int dir ); -void Cmd_Follow_f( gentity_t *ent, qboolean toggle ); +void G_ToggleFollow( gentity_t *ent ); qboolean G_MatchOnePlayer( int *plist, char *err, int len ); int G_ClientNumbersFromString( char *s, int *plist ); int G_SayArgc( void ); Index: src/game/g_active.c =================================================================== --- src/game/g_active.c (revision 939) +++ src/game/g_active.c (working copy) @@ -454,7 +454,7 @@ } if( ( client->buttons & BUTTON_USE_HOLDABLE ) && !( client->oldbuttons & BUTTON_USE_HOLDABLE ) ) - Cmd_Follow_f( ent, qtrue ); + G_ToggleFollow( ent ); } Index: src/game/g_cmds.c =================================================================== --- src/game/g_cmds.c (revision 939) +++ src/game/g_cmds.c (working copy) @@ -320,32 +320,8 @@ } - /* ================== -CheatsOk -================== -*/ -qboolean CheatsOk( gentity_t *ent ) -{ - if( !g_cheats.integer ) - { - trap_SendServerCommand( ent-g_entities, va( "print \"Cheats are not enabled on this server\n\"" ) ); - return qfalse; - } - - if( ent->health <= 0 ) - { - trap_SendServerCommand( ent-g_entities, va( "print \"You must be alive to use this command\n\"" ) ); - return qfalse; - } - - return qtrue; -} - - -/* -================== ConcatArgs ================== */ @@ -395,9 +371,6 @@ char *name; qboolean give_all; - if( !CheatsOk( ent ) ) - return; - name = ConcatArgs( 1 ); give_all = !Q_stricmp( name, "all" ); @@ -455,9 +428,6 @@ { char *msg; - if( !CheatsOk( ent ) ) - return; - ent->flags ^= FL_GODMODE; if( !( ent->flags & FL_GODMODE ) ) @@ -482,9 +452,6 @@ { char *msg; - if( !CheatsOk( ent ) ) - return; - ent->flags ^= FL_NOTARGET; if( !( ent->flags & FL_NOTARGET ) ) @@ -507,9 +474,6 @@ { char *msg; - if( !CheatsOk( ent ) ) - return; - if( ent->client->noclip ) msg = "noclip OFF\n"; else @@ -533,9 +497,6 @@ */ void Cmd_LevelShot_f( gentity_t *ent ) { - if( !CheatsOk( ent ) ) - return; - BeginIntermission( ); trap_SendServerCommand( ent - g_entities, "clientLevelShot" ); } @@ -970,21 +931,20 @@ Cmd_Say_f ================== */ -static void Cmd_Say_f( gentity_t *ent, int mode, qboolean arg0 ) +static void Cmd_Say_f( gentity_t *ent ) { char *p; char *args; + int mode = SAY_ALL; - if( ent->client->pers.muted ) - { - return; - } + args = G_SayConcatArgs( 0 ); + if( !Q_stricmpn( args, "say_team ", 9 ) ) + mode = SAY_TEAM; // support parsing /m out of say text since some people have a hard // time figuring out what the console is. if( g_privateMessages.integer ) { - args = G_SayConcatArgs(0); if( !Q_stricmpn( args, "say /m ", 7 ) || !Q_stricmpn( args, "say_team /m ", 12 ) || !Q_stricmpn( args, "say /mt ", 8 ) || @@ -995,13 +955,10 @@ } } - if( trap_Argc( ) < 2 && !arg0 ) + if( trap_Argc( ) < 2 ) return; - if( arg0 ) - p = ConcatArgs( 0 ); - else - p = ConcatArgs( 1 ); + p = ConcatArgs( 1 ); G_Say( ent, NULL, mode, p ); } @@ -1559,12 +1516,6 @@ char buffer[ MAX_TOKEN_CHARS ]; int i; - if( !g_cheats.integer ) - { - trap_SendServerCommand( ent-g_entities, va( "print \"Cheats are not enabled on this server\n\"" ) ); - return; - } - if( trap_Argc( ) != 5 ) { trap_SendServerCommand( ent-g_entities, va( "print \"usage: setviewpos x y z yaw\n\"" ) ); @@ -1843,7 +1794,7 @@ Cmd_Destroy_f ================= */ -void Cmd_Destroy_f( gentity_t *ent, qboolean deconstruct ) +void Cmd_Destroy_f( gentity_t *ent ) { vec3_t forward, end; trace_t tr; @@ -1934,10 +1885,7 @@ ent->client->pers.netname, BG_FindNameForBuildable( traceEnt->s.modelindex ) ); - if( !deconstruct && CheatsOk( ent ) ) - G_Damage( traceEnt, ent, ent, forward, tr.endpos, 10000, 0, MOD_SUICIDE ); - else - G_FreeEntity( traceEnt ); + G_FreeEntity( traceEnt ); if( !g_cheats.integer ) ent->client->ps.stats[ STAT_MISC ] += @@ -2679,21 +2627,31 @@ /* ================= +G_ToggleFollow +================= +*/ +void G_ToggleFollow( gentity_t *ent ) +{ + if( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) + G_StopFollowing( ent ); + else if( ent->client->sess.spectatorState == SPECTATOR_FREE ) + G_FollowNewClient( ent, 1 ); +} + +/* +================= Cmd_Follow_f ================= */ -void Cmd_Follow_f( gentity_t *ent, qboolean toggle ) +void Cmd_Follow_f( gentity_t *ent ) { int i; int pids[ MAX_CLIENTS ]; char arg[ MAX_TOKEN_CHARS ]; - if( trap_Argc( ) != 2 || toggle ) + if( trap_Argc( ) != 2 ) { - if( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) - G_StopFollowing( ent ); - else if( ent->client->sess.spectatorState == SPECTATOR_FREE ) - G_FollowNewClient( ent, 1 ); + G_ToggleFollow( ent ); } else if( ent->client->sess.spectatorState == SPECTATOR_FREE || ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) @@ -2733,17 +2691,20 @@ Cmd_FollowCycle_f ================= */ -void Cmd_FollowCycle_f( gentity_t *ent, int dir ) +void Cmd_FollowCycle_f( gentity_t *ent ) { + char args[ 11 ]; + int dir; + + trap_Argv( 0, args, sizeof( args ) ); + dir = Q_stricmp( args, "follownext" ) ? -1 : 1; + // won't work unless spectating if( ent->client->pers.teamSelection != PTE_NONE ) return; if( ent->client->sess.spectatorState == SPECTATOR_NOT ) return; - if( dir != 1 && dir != -1 ) - G_Error( "Cmd_FollowCycle_f: bad dir %i", dir ); - G_FollowNewClient( ent, dir ); } @@ -2841,35 +2802,17 @@ } } -/* -================= -Cmd_Test_f -================= -*/ -void Cmd_Test_f( gentity_t *ent ) +static void Cmd_Ignore_f( gentity_t *ent ) { - if( !CheatsOk( ent ) ) - return; - -/* ent->client->ps.stats[ STAT_STATE ] |= SS_POISONCLOUDED; - ent->client->lastPoisonCloudedTime = level.time; - ent->client->lastPoisonCloudedClient = ent; - trap_SendServerCommand( ent->client->ps.clientNum, "poisoncloud" );*/ - -/* ent->client->ps.stats[ STAT_STATE ] |= SS_POISONED; - ent->client->lastPoisonTime = level.time; - ent->client->lastPoisonClient = ent;*/ -} - -static void Cmd_Ignore_f( gentity_t *ent, qboolean ignore ) -{ int pids[ MAX_CLIENTS ]; char name[ MAX_NAME_LENGTH ]; - const char *cmd; + char cmd[ 9 ]; int matches = 0; int i; + qboolean ignore; - cmd = ( ignore ) ? "ignore" : "unignore"; + trap_Argv( 1, cmd, sizeof( cmd ) ); + ignore = Q_stricmp( cmd, "ignore" ); if( trap_Argc() < 2 ) { @@ -2926,15 +2869,87 @@ } } +#define CMD_CHEAT 0x01 // this is a cheat +#define CMD_SAY 0x02 // sends message to others (skip when muted) +// CMD_TEAM|CMD_NOTEAM CMD_NOTEAM|CMD_ALIEN|CMD_HUMAN +#define CMD_TEAM 0x04 // must be on a team +#define CMD_NOTEAM 0x08 // must not be on a team +#define CMD_ALIEN 0x10 // must be an alien +#define CMD_HUMAN 0x20 // must be a human +#define CMD_LIVING 0x40 // must be living +#define CMD_NOGAME 0x80 // valid during intermission +typedef struct +{ + char *cmdName; + int cmdFlags; + void ( *cmdHandler )( gentity_t *ent ); +} commands_t; + +commands_t cmds[ ] = { + // use-whenever commands + { "vote", 0, Cmd_Vote_f }, + { "ignore", 0, Cmd_Ignore_f }, + { "unignore", 0, Cmd_Ignore_f }, + { "ptrcverify", 0, Cmd_PTRCVerify_f }, + { "ptrcrestore", 0, Cmd_PTRCRestore_f }, + + // cannot be used when muted + { "tell", CMD_SAY, Cmd_Tell_f }, + { "callvote", CMD_SAY, Cmd_CallVote_f }, + { "callteamvote", CMD_SAY|CMD_TEAM, Cmd_CallTeamVote_f }, + // can be used even during intermission + { "say", CMD_SAY|CMD_NOGAME, Cmd_Say_f }, + { "say_team", CMD_SAY|CMD_NOGAME, Cmd_Say_f }, + { "m", CMD_SAY|CMD_NOGAME, G_PrivateMessage }, + { "mt", CMD_SAY|CMD_NOGAME, G_PrivateMessage }, + + { "score", CMD_NOGAME, Cmd_Score_f }, + + // cheats + { "give", CMD_CHEAT|CMD_TEAM|CMD_LIVING, Cmd_Give_f }, + { "god", CMD_CHEAT|CMD_TEAM|CMD_LIVING, Cmd_God_f }, + { "notarget", CMD_CHEAT|CMD_TEAM|CMD_LIVING, Cmd_Notarget_f }, + { "noclip", CMD_CHEAT|CMD_TEAM|CMD_LIVING, Cmd_Noclip_f }, + { "levelshot", CMD_CHEAT, Cmd_LevelShot_f }, // ? + { "setviewpos", CMD_CHEAT, Cmd_SetViewpos_f }, // ? + + { "kill", CMD_TEAM|CMD_LIVING, Cmd_Kill_f }, + + // game commands + { "team", CMD_NOTEAM, Cmd_Team_f }, + { "follow", CMD_NOTEAM, Cmd_Follow_f }, // wrong prototype + { "follownext", CMD_NOTEAM, Cmd_FollowCycle_f }, + { "followprev", CMD_NOTEAM, Cmd_FollowCycle_f }, + + { "build", CMD_TEAM|CMD_LIVING, Cmd_Build_f }, + { "destroy", CMD_TEAM|CMD_LIVING, Cmd_Destroy_f }, + { "deconstruct", CMD_TEAM|CMD_LIVING, Cmd_Destroy_f }, + { "where", CMD_TEAM, Cmd_Where_f }, // ? + { "teamvote", CMD_TEAM, Cmd_TeamVote_f }, + { "class", CMD_TEAM, Cmd_Class_f }, + + { "buy", CMD_HUMAN, Cmd_Buy_f }, + { "sell", CMD_HUMAN, Cmd_Sell_f }, + { "itemact", CMD_HUMAN, Cmd_ActivateItem_f }, + { "itemdeact", CMD_HUMAN, Cmd_DeActivateItem_f }, + { "itemtoggle", CMD_HUMAN, Cmd_ToggleItem_f }, + { "reload", CMD_HUMAN, Cmd_Reload_f }, + { "boost", CMD_HUMAN, Cmd_Boost_f } +}; +static int numCmds = sizeof( cmds ) / sizeof( cmds[ 0 ] ); + /* ================= ClientCommand + +This is the only entry point for most client commands ================= */ void ClientCommand( int clientNum ) { gentity_t *ent; char cmd[ MAX_TOKEN_CHARS ]; + int i; ent = g_entities + clientNum; if( !ent->client ) @@ -2942,117 +2957,75 @@ trap_Argv( 0, cmd, sizeof( cmd ) ); - if( Q_stricmp( cmd, "say" ) == 0 ) + for( i = 0; i < numCmds; i++ ) { - Cmd_Say_f( ent, SAY_ALL, qfalse ); - return; + if( Q_stricmp( cmd, cmds[ i ].cmdName ) == 0 ) + break; } - if( Q_stricmp( cmd, "say_team" ) == 0 ) + if( i == numCmds && !G_admin_cmd_check( ent, qfalse ) ) { - Cmd_Say_f( ent, SAY_TEAM, qfalse ); + trap_SendServerCommand( clientNum, + va( "print \"Unknown command %s\n\"", cmd ) ); return; } - if( Q_stricmp( cmd, "tell" ) == 0 ) + // do tests here to reduce the amount of repeated code + + if( !( cmds[ i ].cmdFlags & CMD_NOGAME ) && level.intermissiontime ) + return; + + if( cmds[ i ].cmdFlags & CMD_CHEAT && !g_cheats.integer ) { - Cmd_Tell_f( ent ); + trap_SendServerCommand( clientNum, + "print \"Cheats are not enabled on this server\n\"" ); return; } - - if( !Q_stricmp( cmd, "m" ) || !Q_stricmp( cmd, "mt" ) ) + + if( cmds[ i ].cmdFlags & CMD_SAY && ent->client->pers.muted ) + return; + + if( cmds[ i ].cmdFlags & CMD_TEAM && + ent->client->pers.teamSelection == PTE_NONE ) { - G_PrivateMessage( ent ); + trap_SendServerCommand( clientNum, "print \"Join a team first\n\"" ); return; } - if( Q_stricmp( cmd, "score" ) == 0 ) + if( cmds[ i ].cmdFlags & CMD_NOTEAM && + ent->client->pers.teamSelection != PTE_NONE ) { - Cmd_Score_f( ent ); + trap_SendServerCommand( clientNum, + "print \"Cannot use this command when on a team\n\"" ); return; } - if( !Q_stricmp( cmd, "ignore" ) ) + if( cmds[ i ].cmdFlags & CMD_ALIEN && + ent->client->pers.teamSelection != PTE_ALIENS ) { - Cmd_Ignore_f( ent, qtrue ); + trap_SendServerCommand( clientNum, + "print \"Must be alien to use this command\n\"" ); return; } - - if( !Q_stricmp( cmd, "unignore" ) ) + + if( cmds[ i ].cmdFlags & CMD_HUMAN && + ent->client->pers.teamSelection != PTE_HUMANS ) { - Cmd_Ignore_f( ent, qfalse ); + trap_SendServerCommand( clientNum, + "print \"Must be human to use this command\n\"" ); return; } - if( G_admin_cmd_check( ent, qfalse ) ) + if( cmds[ i ].cmdFlags & CMD_LIVING && + ( ent->client->ps.stats[ STAT_HEALTH ] <= 0 || + ent->client->sess.sessionTeam == TEAM_SPECTATOR ) ) + { + trap_SendServerCommand( clientNum, + "print \"Must be living to use this command\n\"" ); return; + } - // ignore all other commands when at intermission - if( level.intermissiontime ) - return; - - if( Q_stricmp( cmd, "give" ) == 0 ) - Cmd_Give_f( ent ); - else if( Q_stricmp( cmd, "god" ) == 0 ) - Cmd_God_f( ent ); - else if( Q_stricmp( cmd, "notarget" ) == 0 ) - Cmd_Notarget_f( ent ); - else if( Q_stricmp( cmd, "noclip" ) == 0 ) - Cmd_Noclip_f( ent ); - else if( Q_stricmp( cmd, "kill" ) == 0 ) - Cmd_Kill_f( ent ); - else if( Q_stricmp( cmd, "levelshot" ) == 0 ) - Cmd_LevelShot_f( ent ); - else if( Q_stricmp( cmd, "team" ) == 0 ) - Cmd_Team_f( ent ); - else if( Q_stricmp( cmd, "class" ) == 0 ) - Cmd_Class_f( ent ); - else if( Q_stricmp( cmd, "build" ) == 0 ) - Cmd_Build_f( ent ); - else if( Q_stricmp( cmd, "buy" ) == 0 ) - Cmd_Buy_f( ent ); - else if( Q_stricmp( cmd, "sell" ) == 0 ) - Cmd_Sell_f( ent ); - else if( Q_stricmp( cmd, "itemact" ) == 0 ) - Cmd_ActivateItem_f( ent ); - else if( Q_stricmp( cmd, "itemdeact" ) == 0 ) - Cmd_DeActivateItem_f( ent ); - else if( Q_stricmp( cmd, "itemtoggle" ) == 0 ) - Cmd_ToggleItem_f( ent ); - else if( Q_stricmp( cmd, "destroy" ) == 0 ) - Cmd_Destroy_f( ent, qfalse ); - else if( Q_stricmp( cmd, "deconstruct" ) == 0 ) - Cmd_Destroy_f( ent, qtrue ); - else if( Q_stricmp( cmd, "reload" ) == 0 ) - Cmd_Reload_f( ent ); - else if( Q_stricmp( cmd, "boost" ) == 0 ) - Cmd_Boost_f( ent ); - else if( Q_stricmp( cmd, "where" ) == 0 ) - Cmd_Where_f( ent ); - else if( Q_stricmp( cmd, "callvote" ) == 0 ) - Cmd_CallVote_f( ent ); - else if( Q_stricmp( cmd, "vote" ) == 0 ) - 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, qfalse ); - 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 ) - 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 - trap_SendServerCommand( clientNum, va( "print \"unknown cmd %s\n\"", cmd ) ); + cmds[ i ].cmdHandler( ent ); } int G_SayArgc()