X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fcommand%2Fvote.qc;h=3367ef310c2e1eb5d97852b34964f1aa5188ab02;hb=613663cc624d93b575bbb2e1402ab673d94d02c7;hp=ffc81c4685794480cf749cea7b87129134b8de71;hpb=ad328f3deda4a9825f27a878ca81dc7f339e6d30;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/command/vote.qc b/qcsrc/server/command/vote.qc index ffc81c468..3367ef310 100644 --- a/qcsrc/server/command/vote.qc +++ b/qcsrc/server/command/vote.qc @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,7 @@ #include #include #include +#include #include // ============================================= @@ -335,12 +337,19 @@ void VoteThink() // ======================= // Resets the state of all clients, items, weapons, waypoints, ... of the map. -void reset_map(bool dorespawn) +void reset_map(bool dorespawn, bool is_fake_round_start) { if (time <= game_starttime) { if (game_stopped) return; + + if (!is_fake_round_start) + { + Score_ClearAll(); + PlayerStats_GameReport_Reset_All(); + } + if (round_handler_IsActive()) round_handler_Reset(game_starttime); } @@ -351,8 +360,11 @@ void reset_map(bool dorespawn) shuffleteams_on_reset_map = false; } - FOREACH_CLIENT(IS_PLAYER(it), - { + FOREACH_CLIENT(true, { + if (time <= game_starttime) + accuracy_reset(it); // for spectators too because weapon accuracy is persistent + if (!IS_PLAYER(it)) + continue; if (STAT(FROZEN, it)) Unfreeze(it, false); player_powerups_remove_all(it); @@ -390,25 +402,16 @@ void reset_map(bool dorespawn) { if (!MUTATOR_CALLHOOK(reset_map_players)) { - if (restart_mapalreadyrestarted || (time < game_starttime)) + FOREACH_CLIENT(IS_PLAYER(it), { - FOREACH_CLIENT(IS_PLAYER(it), - { - /* - only reset players if a restart countdown is active - this can either be due to cvar sv_ready_restart_after_countdown having set - restart_mapalreadyrestarted to 1 after the countdown ended or when - sv_ready_restart_after_countdown is not used and countdown is still running - */ - // PlayerScore_Clear(it); - CS(it).killcount = 0; - // stop the player from moving so that he stands still once he gets respawned - it.velocity = '0 0 0'; - it.avelocity = '0 0 0'; - CS(it).movement = '0 0 0'; - PutClientInServer(it); - }); - } + // PlayerScore_Clear(it); + CS(it).killcount = 0; + // stop the player from moving so that he stands still once he gets respawned + it.velocity = '0 0 0'; + it.avelocity = '0 0 0'; + CS(it).movement = '0 0 0'; + PutClientInServer(it); + }); } } } @@ -416,44 +419,41 @@ void reset_map(bool dorespawn) // Restarts the map after the countdown is over (and cvar sv_ready_restart_after_countdown is set) void ReadyRestart_think(entity this) { - restart_mapalreadyrestarted = true; - reset_map(true); - Score_ClearAll(); + reset_map(true, false); delete(this); } // Forces a restart of the game without actually reloading the map // this is a mess... -void ReadyRestart_force() +void ReadyRestart_force(bool is_fake_round_start) { if (time <= game_starttime && game_stopped) return; - - bprint("^1Server is restarting...\n"); + if (!is_fake_round_start) + bprint("^1Match is restarting...\n"); VoteReset(); // clear overtime, we have to decrease timelimit to its original value again. if (checkrules_overtimesadded > 0 && g_race_qualifying != 2) cvar_set("timelimit", ftos(autocvar_timelimit - (checkrules_overtimesadded * autocvar_timelimit_overtime))); - checkrules_suddendeathend = checkrules_overtimesadded = checkrules_suddendeathwarning = 0; + checkrules_suddendeathend = checkrules_overtimesadded = checkrules_suddendeathwarning = overtimes = 0; - readyrestart_happened = true; - game_starttime = time + RESTART_COUNTDOWN; + if(warmup_stage) + game_starttime = time; // Warmup: No countdown in warmup + else if (autocvar_g_campaign) + game_starttime = time + 3; + else + game_starttime = time + RESTART_COUNTDOWN; // Go into match mode // clear player attributes FOREACH_CLIENT(IS_PLAYER(it), { it.alivetime = 0; CS(it).killcount = 0; - float val = PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_ALIVETIME, 0); - PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_ALIVETIME, -val); }); - restart_mapalreadyrestarted = false; // reset this var, needed when cvar sv_ready_restart_repeatable is in use - - // disable the warmup global for the server - if(warmup_stage) + // if we're ending the warmup stage call the corresponding hook + if(!is_fake_round_start && !warmup_stage) localcmd("\nsv_hook_warmupend\n"); - warmup_stage = 0; // once the game is restarted the game is in match stage // reset the .ready status of all players (also spectators) FOREACH_CLIENT(IS_REAL_CLIENT(it), { it.ready = false; }); @@ -462,13 +462,10 @@ void ReadyRestart_force() // lock teams with lockonrestart if (autocvar_teamplay_lockonrestart && teamplay) - { - lockteams = true; - bprint("^1The teams are now locked.\n"); - } + lockteams = !warmup_stage; // initiate the restart-countdown-announcer entity - if (sv_ready_restart_after_countdown) + if (!is_fake_round_start && sv_ready_restart_after_countdown && !warmup_stage) { entity restart_timer = new_pure(restart_timer); setthink(restart_timer, ReadyRestart_think); @@ -481,40 +478,75 @@ void ReadyRestart_force() FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), { CS(it).allowed_timeouts = autocvar_sv_timeout_number; }); } - if (!sv_ready_restart_after_countdown) reset_map(true); + if (!sv_ready_restart_after_countdown || warmup_stage) + reset_map(true, is_fake_round_start); + if (autocvar_sv_eventlog) GameLogEcho(":restart"); } -void ReadyRestart() +void ReadyRestart(bool forceWarmupEnd) { - if (MUTATOR_CALLHOOK(ReadyRestart_Deny) || intermission_running || race_completing) localcmd("restart\n"); + if (MUTATOR_CALLHOOK(ReadyRestart_Deny) || intermission_running || race_completing) + { + // NOTE: ReadyRestart support is mandatory in campaign + if (autocvar_g_campaign) + error("ReadyRestart must be supported in campaign mode!"); + localcmd("restart\n"); // if ReadyRestart is denied, restart the server + } else localcmd("\nsv_hook_readyrestart\n"); - // Reset ALL scores, but only do that at the beginning of the countdown if sv_ready_restart_after_countdown is off! - // Otherwise scores could be manipulated during the countdown. - if (!sv_ready_restart_after_countdown) Score_ClearAll(); - ReadyRestart_force(); + if(forceWarmupEnd || autocvar_g_campaign) + warmup_stage = 0; // forcefully end warmup and go to match stage + else + warmup_stage = cvar("g_warmup"); // go into warmup if it's enabled, otherwise restart into match stage + + ReadyRestart_force(false); } -// Count the players who are ready and determine whether or not to restart the match +/* Count the players who are ready and determine whether or not to restart the match when: + * a player presses F4 server/command/cmd.qc ClientCommand_ready() + * a player switches from players to specs server/client.qc PutObserverInServer() + * a player joins (from specs or directly) server/client.qc PutPlayerInServer() + * a player disconnects server/client.qc ClientDisconnect() */ void ReadyCount() { + // cannot reset the game while a timeout is active or pending + if (timeout_status) return; + float ready_needed_factor, ready_needed_count; - float t_ready = 0, t_players = 0; + float t_players = 0; + readycount = 0; - FOREACH_CLIENT(IS_REAL_CLIENT(it) && (IS_PLAYER(it) || it.caplayer == 1), { + FOREACH_CLIENT(IS_REAL_CLIENT(it) && (IS_PLAYER(it) || INGAME_JOINED(it)), { ++t_players; - if (it.ready) ++t_ready; + if (it.ready) ++readycount; }); - readycount = t_ready; - Nagger_ReadyCounted(); + if (t_players < map_minplayers) // map_minplayers will only be set if g_warmup -1 at worldspawn + { + // TODO: handle player spectating/disconnecting during countdown + if (warmup_limit > 0) + warmup_limit = -1; + return; // don't ReadyRestart if players are ready but too few + } + else if (map_minplayers && warmup_limit <= 0) + { + // there's enough players now but we're still in infinite warmup + warmup_limit = cvar("g_warmup_limit"); + if (warmup_limit == 0) + warmup_limit = autocvar_timelimit * 60; + if (warmup_limit > 0) + game_starttime = time; + // implicit else: g_warmup -1 && g_warmup_limit -1 means + // warmup continues until enough players AND enough RUPs (no time limit) + } + ready_needed_factor = bound(0.5, cvar("g_warmup_majority_factor"), 0.999); ready_needed_count = floor(t_players * ready_needed_factor) + 1; - if (readycount >= ready_needed_count) ReadyRestart(); + if (readycount >= ready_needed_count) ReadyRestart(true); } @@ -773,6 +805,18 @@ int VoteCommand_parse(entity caller, string vote_command, string vote_list, floa break; } + case "allready": + { + if(!warmup_stage) { + print_to(caller, "Game already started. Use the resetmatch command to restart the match."); + return -1; + } + + vote_parsed_command = vote_command; + vote_parsed_display = strzone(strcat("^1", vote_command)); + break; + } + default: { vote_parsed_command = vote_command;