X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fserver%2Fcommand%2Fvote.qc;h=199e3265a8f75672ea0fe9ce53ffea1ddfb8853a;hp=1e43564001d58957a7fafb6c278a8672e7af067d;hb=565a9526738602d1e62040b4406dc9412aaeb9ef;hpb=20194b24b0b3a019e53ce08ed100b78f79f5652b diff --git a/qcsrc/server/command/vote.qc b/qcsrc/server/command/vote.qc index 1e43564001..199e3265a8 100644 --- a/qcsrc/server/command/vote.qc +++ b/qcsrc/server/command/vote.qc @@ -148,21 +148,21 @@ void VoteAccept() if(vote_caller) { vote_caller.vote_waittime = 0; } // people like your votes, you don't need to wait to vote again VoteReset(); - Announce("voteaccept"); + Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_ACCEPT); } void VoteReject() { bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2's vote for ", vote_called_display, "^2 was rejected\n"); VoteReset(); - Announce("votefail"); + Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_FAIL); } void VoteTimeout() { bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2's vote for ", vote_called_display, "^2 timed out\n"); VoteReset(); - Announce("votefail"); + Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_FAIL); } void VoteSpam(float notvoters, float mincount, string result) @@ -172,7 +172,7 @@ void VoteSpam(float notvoters, float mincount, string result) strcat("^2:^1", ftos(vote_reject_count)), ((mincount >= 0) ? strcat("^2 (^1", ftos(mincount), "^2 needed)") : "^2"), strcat(", ^1", ftos(vote_abstain_count), "^2 didn't care"), - strcat(", ^1", ftos(notvoters), strcat("^2 didn't ", ((mincount >= 0) ? string_null : "have to "), "vote\n")))); + strcat(", ^1", ftos(notvoters), strcat("^2 didn't ", ((mincount >= 0) ? "" : "have to "), "vote\n")))); if(autocvar_sv_eventlog) { @@ -194,9 +194,9 @@ void VoteCount(float first_count) || ((autocvar_sv_vote_nospectators == 1) && (inWarmupStage || gameover)) || (autocvar_sv_vote_nospectators == 0)); - float vote_player_count, is_player, notvoters; - float vote_real_player_count, vote_real_accept_count; - float vote_real_reject_count, vote_real_abstain_count; + float vote_player_count = 0, is_player, notvoters = 0; + float vote_real_player_count = 0, vote_real_accept_count = 0; + float vote_real_reject_count = 0, vote_real_abstain_count = 0; float vote_needed_of_voted, final_needed_votes; float vote_factor_overall, vote_factor_of_voted; @@ -347,7 +347,15 @@ void ReadyRestart_force() readyrestart_happened = 1; game_starttime = time; if(!g_ca && !g_arena) { game_starttime += RESTART_COUNTDOWN; } - + + // clear player attributes + FOR_EACH_CLIENT(tmp_player) + { + tmp_player.alivetime = 0; + tmp_player.killcount = 0; + PlayerStats_Event(tmp_player, PLAYERSTATS_ALIVETIME, -PlayerStats_Event(tmp_player, PLAYERSTATS_ALIVETIME, 0)); + } + restart_mapalreadyrestarted = 0; // reset this var, needed when cvar sv_ready_restart_repeatable is in use // disable the warmup global for the server @@ -404,7 +412,7 @@ void ReadyCount() { entity tmp_player; float ready_needed_factor, ready_needed_count; - float t_ready, t_players; + float t_ready = 0, t_players = 0; FOR_EACH_REALPLAYER(tmp_player) { @@ -476,15 +484,6 @@ float VoteCommand_checkinlist(string vote_command, string list) if(strstrofs(l, strcat(" ", vote_command, " "), 0) >= 0) return TRUE; - // if gotomap is allowed, chmap is too, and vice versa - if(vote_command == "gotomap") - if(strstrofs(l, " chmap ", 0) >= 0) - return TRUE; - - if(vote_command == "chmap") - if(strstrofs(l, " gotomap ", 0) >= 0) - return TRUE; - return FALSE; } @@ -492,7 +491,7 @@ string ValidateMap(string validated_map, entity caller) { validated_map = MapInfo_FixName(validated_map); - if(!validated_map) + if not(validated_map) { print_to(caller, "This map is not available on this server."); return string_null; @@ -516,30 +515,92 @@ string ValidateMap(string validated_map, entity caller) return validated_map; } -float VoteCommand_parse(entity caller, string vote_command, string vote_list, float startpos, float argc) +float VoteCommand_checkargs(float startpos, float argc) { - string first_command; - - first_command = argv(startpos); + float p, q, check, minargs; + string cvarname = strcat("sv_vote_command_restriction_", argv(startpos)); + string cmdrestriction = cvar_string(cvarname); // note: this warns on undefined cvar. We want that. + string charlist, arg; + float checkmate; - if not(VoteCommand_checkinlist(first_command, vote_list)) + if(cmdrestriction == "") + return TRUE; + + ++startpos; // skip command name + + // check minimum arg count + + // 0 args: argc == startpos + // 1 args: argc == startpos + 1 + // ... + + minargs = stof(cmdrestriction); + if(argc - startpos < minargs) return FALSE; - if(argc < startpos) // These commands won't work without arguments + p = strstrofs(cmdrestriction, ";", 0); // find first semicolon + + for(;;) { - switch(first_command) + // we know that at any time, startpos <= argc - minargs + // so this means: argc-minargs >= startpos >= argc, thus + // argc-minargs >= argc, thus minargs <= 0, thus all minargs + // have been seen already + + if(startpos >= argc) // all args checked? GOOD + break; + + if(p < 0) // no more args? FAIL { - case "map": - case "chmap": - case "gotomap": - case "kick": - case "kickban": - return FALSE; - - default: { break; } + // exception: exactly minargs left, this one included + if(argc - startpos == minargs) + break; + + // otherwise fail + return FALSE; + } + + // cut to next semicolon + q = strstrofs(cmdrestriction, ";", p+1); // find next semicolon + if(q < 0) + charlist = substring(cmdrestriction, p+1, -1); + else + charlist = substring(cmdrestriction, p+1, q - (p+1)); + + // in case we ever want to allow semicolons in VoteCommand_checknasty + // charlist = strreplace("^^", ";", charlist); + + if(charlist != "") + { + // verify the arg only contains allowed chars + arg = argv(startpos); + checkmate = strlen(arg); + for(check = 0; check < checkmate; ++check) + if(strstrofs(charlist, substring(arg, check, 1), 0) < 0) + return FALSE; // not allowed character + // all characters are allowed. FINE. } + + ++startpos; + --minargs; + p = q; } + + return TRUE; +} + +float VoteCommand_parse(entity caller, string vote_command, string vote_list, float startpos, float argc) +{ + string first_command; + first_command = argv(startpos); + + if not(VoteCommand_checkinlist(first_command, vote_list)) + return FALSE; + + if not(VoteCommand_checkargs(startpos, argc)) + return FALSE; + switch(first_command) // now go through and parse the proper commands to adjust as needed. { case "kick": @@ -635,12 +696,13 @@ void VoteCommand_call(float request, entity caller, float argc, string vote_comm || ((autocvar_sv_vote_nospectators == 1) && inWarmupStage) || (autocvar_sv_vote_nospectators == 0)); - float tmp_playercount; + float tmp_playercount = 0; entity tmp_player; vote_command = VoteCommand_extractcommand(vote_command, 2, argc); if not(autocvar_sv_vote_call || !caller) { print_to(caller, "^1Vote calling is not allowed."); } + else if(!autocvar_sv_vote_gamestart && time < game_starttime) { print_to(caller, "^1Vote calling is not allowed before the match has started."); } else if(vote_called) { print_to(caller, "^1There is already a vote called."); } else if(!spectators_allowed && (caller && (caller.classname != "player"))) { print_to(caller, "^1Only players can call a vote."); } else if(timeout_status) { print_to(caller, "^1You can not call a vote while a timeout is active."); } @@ -664,7 +726,7 @@ void VoteCommand_call(float request, entity caller, float argc, string vote_comm } FOR_EACH_REALCLIENT(tmp_player) { ++tmp_playercount; } - if(tmp_playercount > 1) { Announce("votecall"); } // don't announce a "vote now" sound if player is alone + if(tmp_playercount > 1) { Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_CALL); } // don't announce a "vote now" sound if player is alone bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2 calls a vote for ", vote_called_display, "\n"); if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display)); }