]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/command/vote.qc
Merge branch 'master' into terencehill/bot_waypoints
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / command / vote.qc
index 1ed78ad7c3ea01dac3f6470e7fcb8eca4359b018..d79c2418d7adec421473ee7534ea01b9fe553c8c 100644 (file)
 
 #include "../g_damage.qh"
 #include "../g_world.qh"
+#include "../teamplay.qh"
 #include "../race.qh"
 #include "../round_handler.qh"
 #include "../scores.qh"
 
-#include "../mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
+#include <common/gamemodes/_mod.qh>
 
 #include <common/constants.qh>
 #include <common/net_linked.qh>
@@ -128,19 +130,15 @@ void VoteReset()
 
        if (vote_called)
        {
-               strunzone(vote_called_command);
-               strunzone(vote_called_display);
-               strunzone(vote_caller_name);
+               strfree(vote_called_command);
+               strfree(vote_called_display);
+               strfree(vote_caller_name);
        }
 
        vote_called = VOTE_NULL;
        vote_caller = NULL;
-       vote_caller_name = string_null;
        vote_endtime = 0;
 
-       vote_called_command = string_null;
-       vote_called_display = string_null;
-
        vote_parsed_command = string_null;
        vote_parsed_display = string_null;
 
@@ -347,6 +345,11 @@ void reset_map(bool dorespawn)
                        round_handler_Reset(game_starttime);
        }
 
+       if (shuffleteams_on_reset_map)
+       {
+               shuffleteams();
+               shuffleteams_on_reset_map = false;
+       }
        MUTATOR_CALLHOOK(reset_map_global);
 
        FOREACH_ENTITY_FLOAT_ORDERED(pure_data, false,
@@ -367,7 +370,7 @@ void reset_map(bool dorespawn)
                if (it.reset2) it.reset2(it);
        });
 
-       FOREACH_CLIENT(IS_PLAYER(it) && STAT(FROZEN, it), { Unfreeze(it); });
+       FOREACH_CLIENT(IS_PLAYER(it) && STAT(FROZEN, it), { Unfreeze(it, false); });
 
        // Moving the player reset code here since the player-reset depends
        // on spawnpoint entities which have to be reset first --blub
@@ -430,7 +433,8 @@ void ReadyRestart_force()
        FOREACH_CLIENT(IS_PLAYER(it), {
                it.alivetime = 0;
                CS(it).killcount = 0;
-               PS_GR_P_ADDVAL(it, PLAYERSTATS_ALIVETIME, -PS_GR_P_ADDVAL(it, PLAYERSTATS_ALIVETIME, 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
@@ -451,7 +455,7 @@ void ReadyRestart_force()
        }
 
        // initiate the restart-countdown-announcer entity
-       if (autocvar_sv_ready_restart_after_countdown)
+       if (sv_ready_restart_after_countdown)
        {
                entity restart_timer = new_pure(restart_timer);
                setthink(restart_timer, ReadyRestart_think);
@@ -463,8 +467,8 @@ void ReadyRestart_force()
        {
                FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), { CS(it).allowed_timeouts = autocvar_sv_timeout_number; });
        }
-    // reset map immediately if this cvar is not set
-    if (!autocvar_sv_ready_restart_after_countdown) reset_map(true);
+
+       if (!sv_ready_restart_after_countdown) reset_map(true);
        if (autocvar_sv_eventlog) GameLogEcho(":restart");
 }
 
@@ -475,7 +479,7 @@ void ReadyRestart()
 
        // 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 (!autocvar_sv_ready_restart_after_countdown) Score_ClearAll();
+       if (!sv_ready_restart_after_countdown) Score_ClearAll();
        ReadyRestart_force();
 }
 
@@ -516,7 +520,7 @@ float Votecommand_check_assignment(entity caller, float assignment)
        return false;
 }
 
-string VoteCommand_extractcommand(string input, float startpos, float argc)
+string VoteCommand_extractcommand(string input, float startpos, int argc)
 {
        string output;
 
@@ -573,7 +577,7 @@ string ValidateMap(string validated_map, entity caller)
        return validated_map;
 }
 
-float VoteCommand_checkargs(float startpos, float argc)
+float VoteCommand_checkargs(float startpos, int argc)
 {
        float p, q, check, minargs;
        string cvarname = strcat("sv_vote_command_restriction_", argv(startpos));
@@ -647,7 +651,7 @@ float VoteCommand_checkargs(float startpos, float argc)
        return true;
 }
 
-int VoteCommand_parse(entity caller, string vote_command, string vote_list, float startpos, float argc)
+int VoteCommand_parse(entity caller, string vote_command, string vote_list, float startpos, int argc)
 {
        string first_command = argv(startpos);
        int missing_chars = argv_start_index(startpos);
@@ -659,6 +663,14 @@ int VoteCommand_parse(entity caller, string vote_command, string vote_list, floa
 
        if (!VoteCommand_checkargs(startpos, argc)) return 0;
 
+       switch (MUTATOR_CALLHOOK(VoteCommand_Parse, caller, first_command, vote_command, startpos, argc))
+       {
+               case MUT_VOTEPARSE_CONTINUE: { break; }
+               case MUT_VOTEPARSE_SUCCESS: { return 1; }
+               case MUT_VOTEPARSE_INVALID: { return -1; }
+               case MUT_VOTEPARSE_UNACCEPTABLE: { return 0; }
+       }
+
        switch (first_command) // now go through and parse the proper commands to adjust as needed.
        {
                case "kick":
@@ -697,6 +709,26 @@ int VoteCommand_parse(entity caller, string vote_command, string vote_list, floa
                        break;
                }
 
+               case "nextmap": // TODO: replicate the old behaviour of being able to vote for maps from different modes on multimode servers (possibly support it in gotomap too), maybe fallback instead of aborting if map name is invalid?
+               {
+                       vote_command = ValidateMap(argv(startpos + 1), caller);
+                       if (!vote_command)  return -1;
+                       vote_parsed_command = strcat("nextmap ", vote_command);
+                       vote_parsed_display = strzone(strcat("^1", vote_parsed_command));
+
+                       break;
+               }
+
+               case "restart":
+               {
+                       // add a delay so that vote result can be seen and announcer can be heard
+                       // if the vote is accepted
+                       vote_parsed_command = strcat("defer 1 ", vote_command);
+                       vote_parsed_display = strzone(strcat("^1", vote_command));
+
+                       break;
+               }
+
                default:
                {
                        vote_parsed_command = vote_command;
@@ -714,7 +746,7 @@ int VoteCommand_parse(entity caller, string vote_command, string vote_list, floa
 //  Command Sub-Functions
 // =======================
 
-void VoteCommand_abstain(float request, entity caller)  // CLIENT ONLY
+void VoteCommand_abstain(int request, entity caller)  // CLIENT ONLY
 {
        switch (request)
        {
@@ -746,7 +778,7 @@ void VoteCommand_abstain(float request, entity caller)  // CLIENT ONLY
        }
 }
 
-void VoteCommand_call(float request, entity caller, float argc, string vote_command)  // BOTH
+void VoteCommand_call(int request, entity caller, int argc, string vote_command)  // BOTH
 {
        switch (request)
        {
@@ -808,14 +840,15 @@ void VoteCommand_call(float request, entity caller, float argc, string vote_comm
                                }
 
                                FOREACH_CLIENT(IS_REAL_CLIENT(it), { ++tmp_playercount; });
-                               if (tmp_playercount > 1)
-                                       Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_VOTE_CALL);
 
                                bprint("\{1}^2* ^3", OriginalCallerName(), "^2 calls a vote for ", vote_called_display, "\n");
                                if (autocvar_sv_eventlog)
                                        GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display));
                                Nagger_VoteChanged();
                                VoteCount(true);  // needed if you are the only one
+
+                               if (tmp_playercount > 1 && vote_called != VOTE_NULL)
+                                       Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_VOTE_CALL);
                        }
 
                        return;
@@ -833,7 +866,7 @@ void VoteCommand_call(float request, entity caller, float argc, string vote_comm
        }
 }
 
-void VoteCommand_master(float request, entity caller, float argc, string vote_command)  // CLIENT ONLY
+void VoteCommand_master(int request, entity caller, int argc, string vote_command)  // CLIENT ONLY
 {
        switch (request)
        {
@@ -948,7 +981,7 @@ void VoteCommand_master(float request, entity caller, float argc, string vote_co
        }
 }
 
-void VoteCommand_no(float request, entity caller)  // CLIENT ONLY
+void VoteCommand_no(int request, entity caller)  // CLIENT ONLY
 {
        switch (request)
        {
@@ -986,7 +1019,7 @@ void VoteCommand_no(float request, entity caller)  // CLIENT ONLY
        }
 }
 
-void VoteCommand_status(float request, entity caller)  // BOTH
+void VoteCommand_status(int request, entity caller)  // BOTH
 {
        switch (request)
        {
@@ -1008,7 +1041,7 @@ void VoteCommand_status(float request, entity caller)  // BOTH
        }
 }
 
-void VoteCommand_stop(float request, entity caller)  // BOTH
+void VoteCommand_stop(int request, entity caller)  // BOTH
 {
        switch (request)
        {
@@ -1030,7 +1063,7 @@ void VoteCommand_stop(float request, entity caller)  // BOTH
        }
 }
 
-void VoteCommand_yes(float request, entity caller)  // CLIENT ONLY
+void VoteCommand_yes(int request, entity caller)  // CLIENT ONLY
 {
        switch (request)
        {
@@ -1065,7 +1098,7 @@ void VoteCommand_yes(float request, entity caller)  // CLIENT ONLY
 
 /* use this when creating a new command, making sure to place it in alphabetical order... also,
 ** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
-void VoteCommand_(float request)
+void VoteCommand_(int request)
 {
     switch(request)
     {
@@ -1103,7 +1136,7 @@ void VoteCommand_(float request)
        VOTE_COMMAND("yes", VoteCommand_yes(request, caller), "Select yes in current vote", VC_ASGNMNT_CLIENTONLY) \
        /* nothing */
 
-void VoteCommand_macro_help(entity caller, float argc)
+void VoteCommand_macro_help(entity caller, int argc)
 {
        string command_origin = GetCommandPrefix(caller);
 
@@ -1127,10 +1160,16 @@ void VoteCommand_macro_help(entity caller, float argc)
 
                VOTE_COMMANDS(CMD_REQUEST_USAGE, caller, argc, "");
 #undef VOTE_COMMAND
+
+               string cvarname = strcat("sv_vote_command_help_", argv(2));
+               if(cvar_type(cvarname) & CVAR_TYPEFLAG_EXISTS)
+                       wordwrap_sprint(caller, cvar_string(cvarname), 1000);
+               else
+                       print_to(caller, "No documentation exists for this vote");
        }
 }
 
-float VoteCommand_macro_command(entity caller, float argc, string vote_command)
+float VoteCommand_macro_command(entity caller, int argc, string vote_command)
 {
        #define VOTE_COMMAND(name, function, description, assignment) \
                { if (Votecommand_check_assignment(caller, assignment)) { if (name == strtolower(argv(1))) { function; return true; } } }
@@ -1146,7 +1185,7 @@ float VoteCommand_macro_command(entity caller, float argc, string vote_command)
 //  Main function handling vote commands
 // ======================================
 
-void VoteCommand(float request, entity caller, float argc, string vote_command)
+void VoteCommand(int request, entity caller, int argc, string vote_command)
 {
        // Guide for working with argc arguments by example:
        // argc:   1    - 2      - 3     - 4