From 6f0d480ae079995a13c37583c4892f3f5af9f4f4 Mon Sep 17 00:00:00 2001 From: Samual Date: Fri, 30 Dec 2011 17:01:29 -0500 Subject: [PATCH] Many many many fixes and usage updates for generic commands/ban commands --- qcsrc/client/mapvoting.qc | 2 +- qcsrc/common/command/generic.qc | 42 +++-- qcsrc/server/command/banning.qc | 21 ++- qcsrc/server/command/cmd.qc | 10 +- qcsrc/server/command/common.qc | 6 +- qcsrc/server/command/common.qh | 4 +- qcsrc/server/g_world.qc | 16 +- qcsrc/server/miscfunctions.qc | 286 -------------------------------- qcsrc/server/progs.src | 2 + 9 files changed, 61 insertions(+), 328 deletions(-) diff --git a/qcsrc/client/mapvoting.qc b/qcsrc/client/mapvoting.qc index fe22c0f4b..769b921a4 100644 --- a/qcsrc/client/mapvoting.qc +++ b/qcsrc/client/mapvoting.qc @@ -280,7 +280,7 @@ void Cmd_MapVote_MapDownload(float argc) return; } else { print(_("Requesting preview...\n")); - localcmd(strcat("\ncmd getmapvotepic ", ftos(id), "\n")); + localcmd(strcat("\ncmd mv_getpicture ", ftos(id), "\n")); } } diff --git a/qcsrc/common/command/generic.qc b/qcsrc/common/command/generic.qc index 5d6398c68..1e7529290 100644 --- a/qcsrc/common/command/generic.qc +++ b/qcsrc/common/command/generic.qc @@ -59,6 +59,7 @@ void GenericCommand_addtolist(float request, float argc) { print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " addtolist variable value")); print(" Where 'variable' is what to add 'value' to.\n"); + print("See also: ^2removefromlist^7\n"); return; } } @@ -150,6 +151,22 @@ void GenericCommand_maplist(float request, float argc) break; // go to usage } + case "cleanup": // scans maplist and only adds back the ones which are really usable + { + MapInfo_Enumerate(); + MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0); + argc = tokenizebyseparator(cvar_string("g_maplist"), " "); + + for(i = 0; i < argc; ++i) + if(MapInfo_CheckMap(argv(i))) + tmp_string = strcat(tmp_string, " ", argv(i)); + + tmp_string = substring(tmp_string, 1, strlen(tmp_string) - 1); + cvar_set("g_maplist", tmp_string); + + return; + } + case "remove": // scans maplist and only adds back whatever maps were not provided in argv(2) { if(argc == 3) @@ -173,22 +190,6 @@ void GenericCommand_maplist(float request, float argc) cvar_set("g_maplist", shufflewords(cvar_string("g_maplist"))); return; } - - case "cleanup": // scans maplist and only adds back the ones which are really usable - { - MapInfo_Enumerate(); - MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0); - argc = tokenizebyseparator(cvar_string("g_maplist"), " "); - - for(i = 0; i < argc; ++i) - if(MapInfo_CheckMap(argv(i))) - tmp_string = strcat(tmp_string, " ", argv(i)); - - tmp_string = substring(tmp_string, 1, strlen(tmp_string) - 1); - cvar_set("g_maplist", tmp_string); - - return; - } default: break; } @@ -198,8 +199,10 @@ void GenericCommand_maplist(float request, float argc) print("Incorrect parameters for ^2maplist^7\n"); case CMD_REQUEST_USAGE: { - print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " maplist command [map]")); // todo - print(" No arguments required.\n"); + print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " maplist action [map]")); + print(" Where 'action' is the command to complete,\n"); + print(" and 'map' is what it acts upon (if required).\n"); + print(" Full list of commands here: \"add, cleanup, remove, shuffle.\"\n"); return; } } @@ -237,6 +240,7 @@ void GenericCommand_removefromlist(float request, float argc) { print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " removefromlist variable value")); print(" Where 'variable' is what cvar to remove 'value' from.\n"); + print("See also: ^2addtolist^7\n"); return; } } @@ -265,6 +269,7 @@ void GenericCommand_settemp(float request, float argc) { print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " settemp \"cvar\" \"arguments\"\n")); print(" Where 'cvar' is the cvar you want to temporarily set with 'arguments'.\n"); + print("See also: ^2settemp_restore^7\n"); return; } } @@ -291,6 +296,7 @@ void GenericCommand_settemp_restore(float request, float argc) { print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " settemp_restore\n")); print(" No arguments required.\n"); + print("See also: ^2settemp^7\n"); return; } } diff --git a/qcsrc/server/command/banning.qc b/qcsrc/server/command/banning.qc index d575cc7f4..2fbdd27a0 100644 --- a/qcsrc/server/command/banning.qc +++ b/qcsrc/server/command/banning.qc @@ -29,8 +29,11 @@ void BanCommand_ban(float request, float argc, string command) print("Incorrect parameters for ^2ban^7\n"); case CMD_REQUEST_USAGE: { - print("\nUsage:^3 sv_cmd ban address [time] [reason]\n"); - print(" No arguments required. todo\n"); + print("\nUsage:^3 sv_cmd ban address [bantime] [reason]\n"); + print(" 'address' is the IP address or range of the player to ban,\n"); + print(" 'bantime' is the amount of time that the ban is active (default if not provided),\n"); + print(" and 'reason' is the string to label the ban with as reason for banning.\n"); + print("See also: ^2banlist, kickban, unban^7\n"); return; } } @@ -51,6 +54,7 @@ void BanCommand_banlist(float request) { print("\nUsage:^3 sv_cmd banlist\n"); print(" No arguments required.\n"); + print("See also: ^2ban, kickban, unban^7\n"); return; } } @@ -93,7 +97,11 @@ void BanCommand_kickban(float request, float argc, string command) case CMD_REQUEST_USAGE: { print("\nUsage:^3 sv_cmd kickban client [bantime] [masksize] [reason]\n"); - print(" No arguments required. todo\n"); + print(" 'client' is the entity number or name of the player to ban,\n"); + print(" 'bantime' is the amount of time that the ban is active (default if not provided),\n"); + print(" 'masksize' is the range of the IP address (1-thru-4, default if not provided),\n"); + print(" and 'reason' is the string to label the ban with as reason for banning.\n"); + print("See also: ^2ban, banlist, unban^7\n"); return; } } @@ -105,11 +113,9 @@ void BanCommand_unban(float request, float argc) { case CMD_REQUEST_COMMAND: { - if(argc >= 2) + if(argv(1)) { - float who; - who = stof(argv(1)); - Ban_Delete(who); + Ban_Delete(stof(argv(1))); return; } } @@ -119,6 +125,7 @@ void BanCommand_unban(float request, float argc) { print("\nUsage:^3 sv_cmd unban banid\n"); print(" Where 'banid' is the ID of the ban of which to remove.\n"); + print("See also: ^2ban, banlist, kickban^7\n"); return; } } diff --git a/qcsrc/server/command/cmd.qc b/qcsrc/server/command/cmd.qc index efdbe95e6..2f38d3e1b 100644 --- a/qcsrc/server/command/cmd.qc +++ b/qcsrc/server/command/cmd.qc @@ -116,7 +116,7 @@ void ClientCommand_clientversion(float request, float argc) // internal command, } } -void ClientCommand_getmapvotepic(float request, float argc) // internal command, used only by code +void ClientCommand_mv_getpicture(float request, float argc) // internal command, used only by code { switch(request) { @@ -132,10 +132,10 @@ void ClientCommand_getmapvotepic(float request, float argc) // internal command, } default: - sprint(self, "Incorrect parameters for ^2getmapvotepic^7\n"); + sprint(self, "Incorrect parameters for ^2mv_getpicture^7\n"); case CMD_REQUEST_USAGE: { - sprint(self, "\nUsage:^3 cmd getmapvotepic mapid\n"); + sprint(self, "\nUsage:^3 cmd mv_getpicture mapid\n"); sprint(self, " Where 'mapid' is the id number of the map to request an image of on the map vote selection menu.\n"); return; } @@ -592,7 +592,7 @@ void ClientCommand_(float request) CLIENT_COMMAND("autoswitch", ClientCommand_autoswitch(request, arguments), "Whether or not to switch automatically when getting a better weapon") \ CLIENT_COMMAND("checkfail", ClientCommand_checkfail(request, command), "Report if a client-side check failed") \ CLIENT_COMMAND("clientversion", ClientCommand_clientversion(request, arguments), "Release version of the game") \ - CLIENT_COMMAND("getmapvotepic", ClientCommand_getmapvotepic(request, arguments), "Retrieve mapshot picture from the server") \ + CLIENT_COMMAND("mv_getpicture", ClientCommand_mv_getpicture(request, arguments), "Retrieve mapshot picture from the server") \ CLIENT_COMMAND("join", ClientCommand_join(request), "Become a player in the game") \ CLIENT_COMMAND("ready", ClientCommand_ready(request), "Qualify as ready to end warmup stage (or restart server if allowed)") \ CLIENT_COMMAND("reportcvar", ClientCommand_reportcvar(request, arguments, command), "Old system for sending a client cvar to the server") \ @@ -671,7 +671,7 @@ void SV_ParseClientCommand(string command) // exempt commands which are not subject to floodcheck case "begin": break; // handled by engine in host_cmd.c case "download": break; // handled by engine in cl_parse.c - case "getmapvotepic": break; // handled by server in this file + case "mv_getpicture": break; // handled by server in this file case "pause": break; // handled by engine in host_cmd.c case "prespawn": break; // handled by engine in host_cmd.c case "reportcvar": break; // handled by server in this file diff --git a/qcsrc/server/command/common.qc b/qcsrc/server/command/common.qc index 83dcc1e54..ce09b4240 100644 --- a/qcsrc/server/command/common.qc +++ b/qcsrc/server/command/common.qc @@ -384,7 +384,7 @@ void CommonCommand_lsnewmaps(float request, entity caller) } } -void CommonCommand_maplist(float request, entity caller) +void CommonCommand_printmaplist(float request, entity caller) { switch(request) { @@ -397,7 +397,7 @@ void CommonCommand_maplist(float request, entity caller) default: case CMD_REQUEST_USAGE: { - print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " maplist")); + print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " printmaplist")); print_to(caller, " No arguments required."); return; } @@ -729,7 +729,7 @@ void CommonCommand_(float request, entity caller) COMMON_COMMAND("ladder", CommonCommand_ladder(request, caller), "Get information about top players if supported") \ COMMON_COMMAND("lsmaps", CommonCommand_lsmaps(request, caller), "List maps which can be used with the current game mode") \ COMMON_COMMAND("lsnewmaps", CommonCommand_lsnewmaps(request, caller), "List maps which have no records or are seemingly unplayed yet") \ - COMMON_COMMAND("maplist", CommonCommand_maplist(request, caller), "Display full server maplist reply") \ + COMMON_COMMAND("printmaplist", CommonCommand_printmaplist(request, caller), "Display full server maplist reply") \ COMMON_COMMAND("rankings", CommonCommand_rankings(request, caller), "Print information about rankings") \ COMMON_COMMAND("records", CommonCommand_records(request, caller), "List top 10 records for the current map") \ COMMON_COMMAND("teamstatus", CommonCommand_teamstatus(request, caller), "Show information about player and team scores") \ diff --git a/qcsrc/server/command/common.qh b/qcsrc/server/command/common.qh index 3ed82b7dd..589388bba 100644 --- a/qcsrc/server/command/common.qh +++ b/qcsrc/server/command/common.qh @@ -1,6 +1,6 @@ // ============================================================ // Shared declarations for server commands, written by Samual -// Last updated: December 27th, 2011 +// Last updated: December 30th, 2011 // ============================================================ // client verification results @@ -15,7 +15,7 @@ #define TIMEOUT_ACTIVE 2 // timeout which pauses the game by setting the slowmo value extremely low. -#define TIMEOUT_SLOWMO_VALUE 0.000001 +#define TIMEOUT_SLOWMO_VALUE 0.0001 // global timeout information declarations entity timeout_caller; // contains the entity of the player who started the last timeout diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc index 86cd669d6..17b68d4f4 100644 --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@ -813,7 +813,8 @@ void spawnfunc_worldspawn (void) next_pingtime = time + 5; detect_maptype(); - + + // set up information replies for clients and server to use lsmaps_reply = "^7Maps available: "; lsnewmaps_reply = "^7Maps without a record set: "; for(i = 0, j = 0; i < MapInfo_count; ++i) @@ -825,18 +826,20 @@ void spawnfunc_worldspawn (void) col = "^2"; else col = "^3"; + ++j; + lsmaps_reply = strcat(lsmaps_reply, col, MapInfo_Map_bspname, " "); + if(g_race && !stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time")))) lsnewmaps_reply = strcat(lsnewmaps_reply, col, MapInfo_Map_bspname, " "); else if(g_cts && !stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time")))) lsnewmaps_reply = strcat(lsnewmaps_reply, col, MapInfo_Map_bspname, " "); } } + lsmaps_reply = strzone(strcat(lsmaps_reply, "\n")); - if (!g_race && !g_cts) - lsnewmaps_reply = "Need to be playing race or CTS for lsnewmaps to work."; - lsnewmaps_reply = strzone(strcat(lsnewmaps_reply, "\n")); + lsnewmaps_reply = strzone(strcat(((!g_race && !g_cts) ? "Need to be playing race or CTS for lsnewmaps to work." : lsnewmaps_reply), "\n")); maplist_reply = "^7Maps in list: "; n = tokenize_console(autocvar_g_maplist); @@ -859,11 +862,12 @@ void spawnfunc_worldspawn (void) { records_reply[i] = strzone(getrecords(i)); } - if(g_cts) - ladder_reply = strzone(getladder()); + + ladder_reply = strzone(getladder()); rankings_reply = strzone(getrankings()); + // begin other init ClientInit_Spawn(); RandomSeed_Spawn(); PingPLReport_Spawn(); diff --git a/qcsrc/server/miscfunctions.qc b/qcsrc/server/miscfunctions.qc index afca843b4..82871d8b2 100644 --- a/qcsrc/server/miscfunctions.qc +++ b/qcsrc/server/miscfunctions.qc @@ -2121,292 +2121,6 @@ string race_placeName(float pos) { else return strcat(ftos(pos), "th"); } -string getrecords(float page) // 50 records per page -{ - float rec; - string h; - float r; - float i; - string s; - - rec = 0; - - s = ""; - - if (g_ctf) - { - for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i) - { - if (MapInfo_Get_ByID(i)) - { - r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time"))); - if (r == 0) - continue; - // TODO: uid2name - h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname")); - s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n"); - ++rec; - } - } - } - - if (g_race) - { - for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i) - { - if (MapInfo_Get_ByID(i)) - { - r = race_readTime(MapInfo_Map_bspname, 1); - if (r == 0) - continue; - h = race_readName(MapInfo_Map_bspname, 1); - s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n"); - ++rec; - } - } - } - - if (g_cts) - { - for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i) - { - if (MapInfo_Get_ByID(i)) - { - r = race_readTime(MapInfo_Map_bspname, 1); - if (r == 0) - continue; - h = race_readName(MapInfo_Map_bspname, 1); - s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n"); - ++rec; - } - } - } - - MapInfo_ClearTemps(); - - if (s == "" && page == 0) - return "No records are available on this server.\n"; - else - return s; -} - -string getrankings() -{ - string n; - float t; - float i; - string s; - string p; - string map; - - s = ""; - - map = GetMapname(); - - for (i = 1; i <= RANKINGS_CNT; ++i) - { - t = race_readTime(map, i); - if (t == 0) - continue; - n = race_readName(map, i); - p = race_placeName(i); - s = strcat(s, strpad(8, p), " ", strpad(-8, TIME_ENCODED_TOSTRING(t)), " ", n, "\n"); - } - - MapInfo_ClearTemps(); - - if (s == "") - return strcat("No records are available for the map: ", map, "\n"); - else - return strcat("Records for ", map, ":\n", s); -} - -#define LADDER_FIRSTPOINT 100 -#define LADDER_CNT 10 - // position X still gives LADDER_FIRSTPOINT/X points -#define LADDER_SIZE 30 - // ladder shows the top X players -string top_uids[LADDER_SIZE]; -float top_scores[LADDER_SIZE]; -string getladder() -{ - float i, j, k, uidcnt; - string s, temp_s; - - s = ""; - temp_s = ""; - - string rr; - if(g_cts) - rr = CTS_RECORD; - else - rr = RACE_RECORD; - - string myuid; - - for (k = 0; k < MapInfo_count; ++k) - { - if (MapInfo_Get_ByID(k)) - { - for (i = 0; i <= LADDER_CNT; ++i) { // i = 0 because it is the speed award - if(i == 0) // speed award - { - if(stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, rr, "speed/speed"))) == 0) - continue; - - myuid = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, rr, "speed/crypto_idfp")); - } - else // normal record, if it exists (else break) - { - if(race_readTime(MapInfo_Map_bspname, i) == 0) - continue; - - myuid = race_readUID(MapInfo_Map_bspname, i); - } - - // string s contains: - // arg 0 = # of speed recs - // arg 1 = # of 1st place recs - // arg 2 = # of 2nd place recs - // ... etc - // LADDER_CNT+1 = total points - - temp_s = db_get(TemporaryDB, strcat("ladder", myuid)); - if (temp_s == "") - { - db_put(TemporaryDB, strcat("uid", ftos(uidcnt)), myuid); - ++uidcnt; - for (j = 0; j <= LADDER_CNT + 1; ++j) - { - if(j != LADDER_CNT + 1) - temp_s = strcat(temp_s, "0 "); - else - temp_s = strcat(temp_s, "0"); - } - } - - tokenize_console(temp_s); - s = ""; - - if(i == 0) // speed award - for (j = 0; j <= LADDER_CNT; ++j) // loop over each arg in the string - { - if(j == 0) // speed award - s = strcat(s, ftos(stof(argv(j)) +1)); // add 1 to speed rec count and write - else - s = strcat(s, " ", argv(j)); // just copy over everything else - } - else // record - for (j = 0; j <= LADDER_CNT; ++j) // loop over each arg in the string - { - if(j == 0) - s = strcat(s, argv(j)); // speed award, dont prefix with " " - else if(j == i) // wanted rec! - s = strcat(s, " ", ftos(stof(argv(j)) +1)); // update argv(j) - else - s = strcat(s, " ", argv(j)); // just copy over everything else - } - - // total points are (by default) calculated like this: - // speedrec = floor(100 / 10) = 10 points - // 1st place = floor(100 / 1) = 100 points - // 2nd place = floor(100 / 2) = 50 points - // 3rd place = floor(100 / 3) = 33 points - // 4th place = floor(100 / 4) = 25 points - // 5th place = floor(100 / 5) = 20 points - // ... etc - - if(i == 0) - s = strcat(s, " ", ftos(stof(argv(LADDER_CNT+1)) + LADDER_FIRSTPOINT / 10)); // speed award, add LADDER_FIRSTPOINT / 10 points - else - s = strcat(s, " ", ftos(stof(argv(LADDER_CNT+1)) + floor(LADDER_FIRSTPOINT / i))); // record, add LADDER_FIRSTPOINT / i points - - db_put(TemporaryDB, strcat("ladder", myuid), s); - } - } - } - - float thiscnt; - string thisuid; - for (i = 0; i <= uidcnt; ++i) // for each known uid - { - thisuid = db_get(TemporaryDB, strcat("uid", ftos(i))); - temp_s = db_get(TemporaryDB, strcat("ladder", thisuid)); - tokenize_console(temp_s); - thiscnt = stof(argv(LADDER_CNT+1)); - - if(thiscnt > top_scores[LADDER_SIZE-1]) - for (j = 0; j < LADDER_SIZE; ++j) // for each place in ladder - { - if(thiscnt > top_scores[j]) - { - for (k = LADDER_SIZE-1; k >= j; --k) - { - top_uids[k] = top_uids[k-1]; - top_scores[k] = top_scores[k-1]; - } - top_uids[j] = thisuid; - top_scores[j] = thiscnt; - break; - } - } - } - - s = "^3-----------------------\n\n"; - - s = strcat(s, "Pos ^3|"); - s = strcat(s, " ^7Total ^3|"); - for (i = 1; i <= LADDER_CNT; ++i) - { - s = strcat(s, " ^7", race_placeName(i), " ^3|"); - } - s = strcat(s, " ^7Speed awards ^3| ^7Name"); - - s = strcat(s, "\n^3----+--------"); - for (i = 1; i <= min(9, LADDER_CNT); ++i) - { - s = strcat(s, "+-----"); - } -#if LADDER_CNT > 9 - for (i = 1; i <= LADDER_CNT - 9; ++i) - { - s = strcat(s, "+------"); - } -#endif - - s = strcat(s, "+--------------+--------------------\n"); - - for (i = 0; i < LADDER_SIZE; ++i) - { - temp_s = db_get(TemporaryDB, strcat("ladder", top_uids[i])); - tokenize_console(temp_s); - if (argv(LADDER_CNT+1) == "") // total is 0, skip - continue; - s = strcat(s, strpad(4, race_placeName(i+1)), "^3| ^7"); // pos - s = strcat(s, strpad(7, argv(LADDER_CNT+1)), "^3| ^7"); // total - for (j = 1; j <= min(9, LADDER_CNT); ++j) - { - s = strcat(s, strpad(4, argv(j)), "^3| ^7"); // 1st, 2nd, 3rd etc cnt - } -#if LADDER_CNT > 9 - for (j = 10; j <= LADDER_CNT; ++j) - { - s = strcat(s, strpad(4, argv(j)), " ^3| ^7"); // 1st, 2nd, 3rd etc cnt - } -#endif - - s = strcat(s, strpad(13, argv(0)), "^3| ^7"); // speed award cnt - s = strcat(s, uid2name(top_uids[i]), "\n"); // name - } - - MapInfo_ClearTemps(); - - if (s == "") - return "No ladder on this server!\n"; - else - return strcat("Top ", ftos(LADDER_SIZE), " ladder rankings:\n", s); -} - float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance) { diff --git a/qcsrc/server/progs.src b/qcsrc/server/progs.src index 98f819754..9a459c5fd 100644 --- a/qcsrc/server/progs.src +++ b/qcsrc/server/progs.src @@ -43,6 +43,7 @@ command/common.qh command/banning.qh command/radarmap.qh command/vote.qh +command/getreplies.qh command/cmd.qh command/sv_cmd.qh @@ -155,6 +156,7 @@ command/common.qc command/banning.qc command/radarmap.qc command/vote.qc +command/getreplies.qc command/cmd.qc command/sv_cmd.qc -- 2.39.2