]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Lots and lots more work on votecommand stuff, many commands have been added back...
authorSamual <samual@xonotic.org>
Mon, 5 Dec 2011 02:34:01 +0000 (21:34 -0500)
committerSamual <samual@xonotic.org>
Mon, 5 Dec 2011 02:34:01 +0000 (21:34 -0500)
qcsrc/client/gamecommand.qc
qcsrc/server/autocvars.qh
qcsrc/server/clientcommands.qc
qcsrc/server/gamecommand.qc
qcsrc/server/vote.qc
qcsrc/server/vote.qh

index ab6aa359f7c4ffc3a9fafb698a3bf624ff30f65a..e9dfb496f9198533226b7ab4c79dfd24aba2947d 100644 (file)
@@ -266,16 +266,16 @@ void GameCommand_settemp(float request, float argc)
                                float i = cvar_clientsettemp_restore();
                                
                                if(i)
-                                       print("Restored ", ftos(i), " temporary cvar settings to their original values.\n");
+                                       dprint("Restored ", ftos(i), " temporary cvar settings to their original values.\n");
                                else
-                                       print("Nothing to restore.\n");
+                                       dprint("Nothing to restore.\n");
                        }
                        else
                        {
                                if(cvar_clientsettemp(argv(1), argv(2)))
-                                       print("Creating new settemp tracker for ", argv(1), " and setting it to \"", argv(2), "\" temporarily.\n"); 
+                                       dprint("Creating new settemp tracker for ", argv(1), " and setting it to \"", argv(2), "\" temporarily.\n"); 
                                else
-                                       print("Already had a tracker for ", argv(1), ", updating it to \"", argv(2), "\".\n");
+                                       dprint("Already had a tracker for ", argv(1), ", updating it to \"", argv(2), "\".\n");
                        }
                                
                        return; 
index 175d6dcf16e73fa7695ee530dbb759f186fb9935..8a8c0ee746636b8b5a84fed383697f3835b4ca03 100644 (file)
@@ -1162,6 +1162,7 @@ float autocvar_sv_vote_change;
 string autocvar_sv_vote_commands;
 float autocvar_sv_vote_majority_factor;
 float autocvar_sv_vote_master;
+float autocvar_sv_vote_master_callable;
 string autocvar_sv_vote_master_commands;
 string autocvar_sv_vote_master_password;
 float autocvar_sv_vote_nospectators;
index cfe266bb3416ebdb233c82f38e3511401f975487..19921aae4969f903c4a07960f29e9a7b4a3a9dcb 100644 (file)
@@ -894,7 +894,7 @@ void ClientCommand_(float request)
        CLIENT_COMMAND("timein", ClientCommand_timein(request), "Resume the game from being paused with a timeout") \
        CLIENT_COMMAND("timeout", ClientCommand_timeout(request), "Call a timeout which pauses the game for certain amount of time unless unpaused") \
        CLIENT_COMMAND("voice", ClientCommand_voice(request, arguments, command), "Send voice message via sound") \
-       CLIENT_COMMAND("vote", VoteCommand(request, self, arguments), "Request an action to be voted upon by players") /* handled in server/vote.qc */ \
+       CLIENT_COMMAND("vote", VoteCommand(request, self, arguments, command), "Request an action to be voted upon by players") /* handled in server/vote.qc */ \
        /* nothing */
        
 void ClientCommand_macro_help()
index cd8c623f31a46e961326af70f93d39eccbf6a1cf..0a28ddbf5df0857adb8120663d312cbdbf884998 100644 (file)
@@ -1886,7 +1886,7 @@ void GameCommand_(float request)
 // ==================================
 
 // Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
-#define SERVER_COMMANDS(request,arguments) \
+#define SERVER_COMMANDS(request,arguments,command) \
        SERVER_COMMAND("adminmsg", GameCommand_adminmsg(request, arguments), "Send an admin message to a client directly") \
        SERVER_COMMAND("allready", GameCommand_allready(request), "Restart the server and reset the players") \
        SERVER_COMMAND("allspec", GameCommand_allspec(request, arguments), "Force all players to spectate") \
@@ -1927,7 +1927,7 @@ void GameCommand_(float request)
        SERVER_COMMAND("trace", GameCommand_trace(request, arguments), "Various debugging tools with tracing") \
        SERVER_COMMAND("unlockteams", GameCommand_unlockteams(request), "Enable the ability for players to switch or enter teams") \
        SERVER_COMMAND("warp", GameCommand_warp(request, arguments), "Choose different level in campaign") \
-       SERVER_COMMAND("vote", VoteCommand(request, world, arguments), "Server side control of voting") /* handled in server/vote.qc */ \
+       SERVER_COMMAND("vote", VoteCommand(request, world, arguments, command), "Server side control of voting") /* handled in server/vote.qc */ \
        /* nothing */
 
 void GameCommand_macro_help()
@@ -1935,18 +1935,18 @@ void GameCommand_macro_help()
        #define SERVER_COMMAND(name,function,description) \
                { print("  ^2", name, "^7: ", description, "\n"); }
                
-       SERVER_COMMANDS(0, 0)
+       SERVER_COMMANDS(0, 0, "")
        #undef SERVER_COMMAND
        
        return;
 }
 
-float GameCommand_macro_command(float argc)
+float GameCommand_macro_command(float argc, string command)
 {
        #define SERVER_COMMAND(name,function,description) \
                { if(name == strtolower(argv(0))) { function; return TRUE; } }
                
-       SERVER_COMMANDS(GC_REQUEST_COMMAND, argc)
+       SERVER_COMMANDS(GC_REQUEST_COMMAND, argc, command)
        #undef SERVER_COMMAND
        
        return FALSE;
@@ -1957,7 +1957,7 @@ float GameCommand_macro_usage(float argc)
        #define SERVER_COMMAND(name,function,description) \
                { if(name == strtolower(argv(1))) { function; return TRUE; } }
                
-       SERVER_COMMANDS(GC_REQUEST_USAGE, argc)
+       SERVER_COMMANDS(GC_REQUEST_USAGE, argc, "")
        #undef SERVER_COMMAND
        
        return FALSE;
@@ -1998,7 +1998,7 @@ void GameCommand(string command)
        {
                return; // handled by common/gamecommand.qc
        }
-       else if(GameCommand_macro_command(argc)) // continue as usual and scan for normal commands
+       else if(GameCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
        {
                return; // handled by one of the above GameCommand_* functions
        }
index 1e6a33549a00b76b640a118babda5c0ed28ccf1b..0f48ea1db0f83d74230394a5be5433f3809a49c3 100644 (file)
 #define VOTE_SELECT_NULL 0
 #define VOTE_SELECT_ACCEPT 1
 
-// ============================
-//  Misc. Supporting Functions
-// ============================
+string GetKickVoteVictim_newcommand;
+string GetKickVoteVictim_reason;
 
-float Votecommand_check_assignment(entity caller, float assignment)
-{
-       float from_server = (!caller);
-       
-       if((assignment == VC_ASGNMNT_BOTH) 
-               || ((!from_server && assignment == VC_ASGNMNT_CLIENTONLY) 
-               || (from_server && assignment == VC_ASGNMNT_SERVERONLY)))
-       {
-               return TRUE;
-       }
+string RemapVote_display;
+string RemapVote_vote;
 
-       return FALSE;
-}
 
-string VoteCommand_getprefix(entity caller)
-{
-       if(caller)
-               return "cmd";
-       else
-               return "sv_cmd";
-}
+// =============================================
+//  Nagger for players to know status of voting
+// =============================================
 
 float Nagger_SendEntity(entity to, float sendflags)
 {
@@ -132,144 +117,84 @@ void Nagger_ReadyCounted()
                nagger.SendFlags |= 1;
 }
 
-void ReadyRestartForce()
-{
-       local entity e;
-
-       bprint("^1Server is restarting...\n");
-
-       VoteReset();
-
-       // clear overtime
-       if (checkrules_overtimesadded > 0 && g_race_qualifying != 2) {
-               //we have to decrease timelimit to its original value again!!
-               float newTL;
-               newTL = autocvar_timelimit;
-               newTL -= checkrules_overtimesadded * autocvar_timelimit_overtime;
-               cvar_set("timelimit", ftos(newTL));
-       }
 
-       checkrules_suddendeathend = checkrules_overtimesadded = checkrules_suddendeathwarning = 0;
-
-
-       readyrestart_happened = 1;
-       game_starttime = time;
-       if(!g_ca && !g_arena)
-               game_starttime += RESTART_COUNTDOWN;
-       restart_mapalreadyrestarted = 0; //reset this var, needed when cvar sv_ready_restart_repeatable is in use
+// =======================
+//  Game logic for voting
+// =======================
 
-       inWarmupStage = 0; //once the game is restarted the game is in match stage
+void VoteStop(entity stopper) 
+{
+       bprint("\{1}^2* ^3", VoteCommand_getname(stopper), "^2 stopped ^3", VoteCommand_getname(votecaller), "^2's vote\n");
+       if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vstop:", ftos(stopper.playerid))); }
+       
+       // Don't force them to wait for next vote, this way they can e.g. correct their vote.
+       if(votecaller)
+               if(stopper == votecaller) 
+                       votecaller.vote_next = time + autocvar_sv_vote_stop;
 
-       //reset the .ready status of all players (also spectators)
-       FOR_EACH_CLIENTSLOT(e)
-               e.ready = 0;
-       readycount = 0;
-       Nagger_ReadyCounted(); // NOTE: this causes a resend of that entity, and will also turn off warmup state on the client
+       VoteReset();
+}
 
-       if(autocvar_teamplay_lockonrestart && teamplay) {
-               lockteams = 1;
-               bprint("^1The teams are now locked.\n");
-       }
 
-       //initiate the restart-countdown-announcer entity
-       if(autocvar_sv_ready_restart_after_countdown && !g_ca && !g_arena)
-       {
-               restartTimer = spawn();
-               restartTimer.think = restartTimer_Think;
-               restartTimer.nextthink = game_starttime;
-       }
+// ============================================
+//  Misc. supporting functions for votecommand
+// ============================================
 
-       //after a restart every players number of allowed timeouts gets reset, too
-       if(autocvar_sv_timeout)
+float Votecommand_check_assignment(entity caller, float assignment)
+{
+       float from_server = (!caller);
+       
+       if((assignment == VC_ASGNMNT_BOTH) 
+               || ((!from_server && assignment == VC_ASGNMNT_CLIENTONLY) 
+               || (from_server && assignment == VC_ASGNMNT_SERVERONLY)))
        {
-               FOR_EACH_REALPLAYER(e)
-                       e.allowedTimeouts = autocvar_sv_timeout_number;
+               return TRUE;
        }
 
-       //reset map immediately if this cvar is not set
-       if (!autocvar_sv_ready_restart_after_countdown)
-               reset_map(TRUE);
-
-       if(autocvar_sv_eventlog)
-               GameLogEcho(":restart");
+       return FALSE;
 }
 
-void ReadyRestart()
+string VoteCommand_getprefix(entity caller)
 {
-       // no arena, assault support yet...
-       if(g_arena | g_assault | gameover | intermission_running | race_completing)
-               localcmd("restart\n");
+       if(caller)
+               return "cmd";
        else
-               localcmd("\nsv_hook_gamerestart\n");
-
-       ReadyRestartForce();
-
-       // 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();
+               return "sv_cmd";
 }
 
-/**
- * Counts how many players are ready. If not enough players are ready, the function
- * does nothing. If all players are ready, the timelimit will be extended and the
- * restart_countdown variable is set to allow other functions like PlayerPostThink
- * to detect that the countdown is now active. If the cvar sv_ready_restart_after_countdown
- * is not set the map will be resetted.
- *
- * Function is called after the server receives a 'ready' sign from a player.
- */
-void ReadyCount()
+string VoteCommand_getname(entity caller)
 {
-       entity tmp_player;
-       float t_ready, t_players;
-
-       FOR_EACH_REALPLAYER(tmp_player)
-       {
-               ++t_players;
-               if(tmp_player.ready) { ++t_ready; }
-       }
-
-       readycount = t_ready;
-
-       Nagger_ReadyCounted();
-
-       // TODO: Add ability to 
-       if(t_ready) // at least one is ready
-       if(t_ready == t_players) // and, everyone is ready
-               ReadyRestart();
+       if(caller)
+               return caller.netname;
+       else
+               return ((autocvar_sv_adminnick != "") ? autocvar_sv_adminnick : autocvar_hostname);
 }
 
-
-// Restarts the map after the countdown is over (and cvar sv_ready_restart_after_countdown is set)
-void restartTimer_Think() 
+string VoteCommand_extractcommand(string input, float startpos, float argc) 
 {
-       restart_mapalreadyrestarted = 1;
-       reset_map(TRUE);
-       Score_ClearAll();
-       remove(self);
-       return;
+       string output;
+       
+       if((argc - 1) < startpos)
+               output = "";
+       else
+               output = substring(input, argv_start_index(startpos), argv_end_index(-1) - argv_start_index(startpos));
+               
+       print("VoteCommand_parse: '", output, "'. \n");
+       return output;
 }
 
-float VoteCheckNasty(string cmd)
+float VoteCommand_checknasty(string vote_command)
 {
-       if(strstrofs(cmd, ";", 0) >= 0)
-               return TRUE;
-       if(strstrofs(cmd, "\n", 0) >= 0)
-               return TRUE;
-       if(strstrofs(cmd, "\r", 0) >= 0)
-               return TRUE;
-       if(strstrofs(cmd, "$", 0) >= 0)
+       if((strstrofs(vote_command, ";", 0) >= 0)
+               || (strstrofs(vote_command, "\n", 0) >= 0)
+               || (strstrofs(vote_command, "\r", 0) >= 0)
+               || (strstrofs(vote_command, "$", 0) >= 0))
                return TRUE;
                
        return FALSE;
 }
 
-string GetKickVoteVictim_newcommand;
-string GetKickVoteVictim_reason;
-
-entity GetKickVoteVictim(string vote, string cmd, entity caller)
+entity GetKickVoteVictim(string vote, string cmd, entity caller) // todo re-write this
 {
        float tokens;
        string ns;
@@ -323,8 +248,6 @@ entity GetKickVoteVictim(string vote, string cmd, entity caller)
        return world;
 }
 
-string RemapVote_display;
-string Remapvote_selection;
 float RemapVote(string vote, string cmd, entity e)
 {
        float vote_argc;
@@ -359,12 +282,12 @@ float RemapVote(string vote, string cmd, entity e)
        {
                if(!(victim = GetKickVoteVictim(vote, cmd, e)))
                        return FALSE;
-               Remapvote_selection = GetKickVoteVictim_newcommand;
+               RemapVote_vote = GetKickVoteVictim_newcommand;
                RemapVote_display = strcat("^1", vote, " (^7", victim.netname, "^1): ", GetKickVoteVictim_reason);
        }
        else
        {
-               Remapvote_selection = vote;
+               RemapVote_vote = vote;
                RemapVote_display = strzone(strcat("^1", vote));
        }
 
@@ -376,24 +299,22 @@ float RemapVote(string vote, string cmd, entity e)
 //  Command Sub-Functions
 // =======================
 
-void VoteCommand_abstain(float request, entity caller)
+void VoteCommand_abstain(float request, entity caller) // CLIENT ONLY
 {
        switch(request)
        {
                case VC_REQUEST_COMMAND:
                {
-                       if(votecalled)
+                       if not(votecalled) { print_to(caller, "^1No vote called."); }
+                       else if not(caller.vote_selection == VOTE_SELECT_NULL || autocvar_sv_vote_change) { print_to(caller, "^1You have already voted."); }
+                       
+                       else // everything went okay, continue changing vote
                        {
-                               if(caller.vote_selection == VOTE_SELECT_NULL || autocvar_sv_vote_change)
-                               {
-                                       print_to(caller, "^1You abstained from your vote.");
-                                       caller.vote_selection = VOTE_SELECT_ABSTAIN;
-                                       msg_entity = caller;
-                                       if(!autocvar_sv_vote_singlecount) { VoteCount(); }
-                               }
-                               else { print_to(caller, "^1You have already voted."); }
-                       } 
-                       else { print_to(caller, "^1No vote called."); }
+                               print_to(caller, "^1You abstained from your vote.");
+                               caller.vote_selection = VOTE_SELECT_ABSTAIN;
+                               msg_entity = caller;
+                               if(!autocvar_sv_vote_singlecount) { VoteCount(); }
+                       }
                        
                        return;
                }
@@ -408,7 +329,7 @@ void VoteCommand_abstain(float request, entity caller)
        }
 }
 
-void VoteCommand_call(float request, entity caller, float argc)
+void VoteCommand_call(float request, entity caller, float argc, string vote_command) // BOTH
 {
        switch(request)
        {
@@ -428,7 +349,7 @@ void VoteCommand_call(float request, entity caller, float argc)
        }
 }
 
-void VoteCommand_force(float request, float argc)
+void VoteCommand_force(float request, float argc, string vote_command) // SERVER ONLY
 {
        switch(request)
        {
@@ -441,19 +362,87 @@ void VoteCommand_force(float request, float argc)
                default:
                case VC_REQUEST_USAGE:
                {
-                       print("\nUsage:^3 vote \n");
+                       print("\nUsage:^3 vote force result\n");
                        print("  No arguments required.\n");
                        return;
                }
        }
 }
 
-void VoteCommand_master(float request, entity caller, float argc)
+void VoteCommand_master(float request, entity caller, float argc, string vote_command) // CLIENT ONLY
 {
        switch(request)
        {
                case VC_REQUEST_COMMAND:
                {
+                       if(autocvar_sv_vote_master)
+                       {
+                               switch(strtolower(argv(2)))
+                               {
+                                       case "do":
+                                       {
+                                               vote_command = VoteCommand_extractcommand(vote_command, 3, argc);
+                                               
+                                               if not(caller.vote_master) { print_to(caller, "^1You do not have vote master privelages."); }
+                                               else if not(VoteCommand_checknasty(vote_command)) { print_to(caller, "^1Syntax error in command, see 'vhelp' for more info."); }
+                                               else if not(RemapVote(vote_command, "vdo", caller)) { print_to(caller, "^1This command is not acceptable, see 'vhelp' for more info."); }
+                                               
+                                               else // everything went okay, proceed with command
+                                               {
+                                                       localcmd(strcat(RemapVote_vote, "\n"));
+                                                       print_to(caller, strcat("Executing command '", RemapVote_display, "' on server."));
+                                                       bprint("\{1}^2* ^3", VoteCommand_getname(caller), "^2 used their ^3master^2 status to do \"^2", RemapVote_display, "^2\".\n");
+                                                       if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vdo:", ftos(caller.playerid), ":", RemapVote_display)); }
+                                               }
+                                               
+                                               return;
+                                       }
+                                       
+                                       case "login":
+                                       {
+                                               if not(autocvar_sv_vote_master_password != "") { print_to(caller, "^1Login to vote master is not allowed."); }
+                                               else if(caller.vote_master) { print_to(caller, "^1You are already logged in as vote master."); }
+                                               else if not(autocvar_sv_vote_master_password == argv(3)) { print_to(caller, strcat("Rejected vote master login from ", VoteCommand_getname(caller))); }
+
+                                               else // everything went okay, proceed with giving this player master privilages
+                                               {
+                                                       caller.vote_master = TRUE;
+                                                       print_to(caller, strcat("Accepted vote master login from ", VoteCommand_getname(caller)));
+                                                       bprint("\{1}^2* ^3", VoteCommand_getname(caller), "^2 logged in as ^3master^2\n");
+                                                       if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vlogin:", ftos(caller.playerid))); }
+                                               }
+                                               
+                                               return;
+                                       }
+                                       
+                                       default: // calling a vote for master
+                                       {
+                                               if not(autocvar_sv_vote_master_callable) { print_to(caller, "^1Vote to become vote master is not allowed."); } // todo update this description in defaultXonotic.cfg
+                                               else if(votecalled) { print_to(caller, "^1There is already a vote called."); }
+                                               
+                                               else // everything went okay, continue with creating vote
+                                               {
+                                                       votecalled = TRUE;
+                                                       votecalledmaster = TRUE;
+                                                       votecalledvote = strzone("XXX");
+                                                       votecalledvote_display = strzone("^3master");
+                                                       votefinished = time + autocvar_sv_vote_timeout;
+                                                       votecaller = caller;
+                                                       
+                                                       caller.vote_selection = VOTE_SELECT_ACCEPT;
+                                                       caller.vote_next = time + autocvar_sv_vote_wait;
+                                                       
+                                                       bprint("\{1}^2* ^3", VoteCommand_getname(votecaller), "^2 calls a vote to become ^3master^2.\n");
+                                                       if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vcall:", ftos(votecaller.playerid), ":", votecalledvote_display)); }
+                                                       Nagger_VoteChanged();
+                                                       VoteCount(); // needed if you are the only one
+                                               }
+                                               
+                                               return;
+                                       }
+                               }
+                       }
+                       else { print_to(caller, "^1Master control of voting is not allowed."); }
                        
                        return;
                }
@@ -462,30 +451,28 @@ void VoteCommand_master(float request, entity caller, float argc)
                case VC_REQUEST_USAGE:
                {
                        print("\nUsage:^3 vote master action [arguments]\n");
-                       print("  No arguments required.\n");
+                       print("  TODO.\n");
                        return;
                }
        }
 }
 
-void VoteCommand_no(float request, entity caller)
+void VoteCommand_no(float request, entity caller) // CLIENT ONLY
 {
        switch(request)
        {
                case VC_REQUEST_COMMAND:
                {
-                       if(votecalled)
+                       if not(votecalled) { print_to(caller, "^1No vote called."); }
+                       else if not(caller.vote_selection == VOTE_SELECT_NULL || autocvar_sv_vote_change) { print_to(caller, "^1You have already voted."); }
+                       
+                       else // everything went okay, continue changing vote
                        {
-                               if(caller.vote_selection == VOTE_SELECT_NULL || autocvar_sv_vote_change)
-                               {
-                                       print_to(caller, "^1You rejected the vote.");
-                                       caller.vote_selection = VOTE_SELECT_REJECT;
-                                       msg_entity = caller;
-                                       if(!autocvar_sv_vote_singlecount) { VoteCount(); }
-                               }
-                               else { print_to(caller, "^1You have already voted."); }
-                       } 
-                       else { print_to(caller, "^1No vote called."); }
+                               print_to(caller, "^1You rejected the vote.");
+                               caller.vote_selection = VOTE_SELECT_REJECT;
+                               msg_entity = caller;
+                               if(!autocvar_sv_vote_singlecount) { VoteCount(); }
+                       }
                        
                        return;
                }
@@ -500,7 +487,7 @@ void VoteCommand_no(float request, entity caller)
        }
 }
 
-void VoteCommand_status(float request, entity caller)
+void VoteCommand_status(float request, entity caller) // BOTH
 {
        switch(request)
        {
@@ -520,12 +507,15 @@ void VoteCommand_status(float request, entity caller)
        }
 }
 
-void VoteCommand_stop(float request, entity caller)
+void VoteCommand_stop(float request, entity caller) // BOTH
 {
        switch(request)
        {
                case VC_REQUEST_COMMAND:
                {
+                       if not(votecalled) { print_to(caller, "^1No vote called."); }
+                       else if((caller == votecaller) || !caller || caller.vote_master) { VoteStop(caller); }
+                       else { print_to(caller, "^1You are not allowed to stop that Vote."); }
                        
                        return;
                }
@@ -540,24 +530,22 @@ void VoteCommand_stop(float request, entity caller)
        }
 }
 
-void VoteCommand_yes(float request, entity caller)
+void VoteCommand_yes(float request, entity caller) // CLIENT ONLY
 {
        switch(request)
        {
                case VC_REQUEST_COMMAND:
                {
-                       if(votecalled)
+                       if not(votecalled) { print_to(caller, "^1No vote called."); }
+                       if not(caller.vote_selection == VOTE_SELECT_NULL || autocvar_sv_vote_change) { print_to(caller, "^1You have already voted."); }
+                       
+                       else // everything went okay, continue changing vote
                        {
-                               if(caller.vote_selection == VOTE_SELECT_NULL || autocvar_sv_vote_change)
-                               {
-                                       print_to(caller, "^1You accepted the vote.");
-                                       caller.vote_selection = VOTE_SELECT_ACCEPT;
-                                       msg_entity = caller;
-                                       if(!autocvar_sv_vote_singlecount) { VoteCount(); }
-                               }
-                               else { print_to(caller, "^1You have already voted."); }
-                       } 
-                       else { print_to(caller, "^1No vote called."); }
+                               print_to(caller, "^1You accepted the vote.");
+                               caller.vote_selection = VOTE_SELECT_ACCEPT;
+                               msg_entity = caller;
+                               if(!autocvar_sv_vote_singlecount) { VoteCount(); }
+                       }
                        
                        return;
                }
@@ -600,12 +588,12 @@ void VoteCommand_(float request)
 // ================================
 
 // Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
-#define VOTE_COMMANDS(request,caller,arguments) \
+#define VOTE_COMMANDS(request,caller,arguments,command) \
        VOTE_COMMAND("abstain", VoteCommand_abstain(request, caller), "Abstain your vote in current vote", VC_ASGNMNT_CLIENTONLY) \
-       VOTE_COMMAND("call", VoteCommand_call(request, caller, arguments), "Create a new vote for players to decide on", VC_ASGNMNT_BOTH) \
-       VOTE_COMMAND("force", VoteCommand_force(request, arguments), "Force the result of a vote", VC_ASGNMNT_SERVERONLY) \
+       VOTE_COMMAND("call", VoteCommand_call(request, caller, arguments, command), "Create a new vote for players to decide on", VC_ASGNMNT_BOTH) \
+       VOTE_COMMAND("force", VoteCommand_force(request, arguments, command), "Force the result of a vote", VC_ASGNMNT_SERVERONLY) \
        VOTE_COMMAND("help", VoteCommand_macro_help(caller, arguments), "Shows this information", VC_ASGNMNT_BOTH) \
-       VOTE_COMMAND("master", VoteCommand_master(request, caller, arguments), "", VC_ASGNMNT_CLIENTONLY) \
+       VOTE_COMMAND("master", VoteCommand_master(request, caller, arguments, command), "", VC_ASGNMNT_CLIENTONLY) \
        VOTE_COMMAND("no", VoteCommand_no(request, caller), "Select no in current vote", VC_ASGNMNT_CLIENTONLY) \
        VOTE_COMMAND("status", VoteCommand_status(request, caller), "Prints information about current vote", VC_ASGNMNT_BOTH) \
        VOTE_COMMAND("stop", VoteCommand_stop(request, caller), "Immediately end a vote", VC_ASGNMNT_BOTH) \
@@ -623,7 +611,7 @@ void VoteCommand_macro_help(entity caller, float argc)
                #define VOTE_COMMAND(name,function,description,assignment) \
                        { if(Votecommand_check_assignment(caller, assignment)) { print("  ^2", name, "^7: ", description, "\n"); } }
                        
-               VOTE_COMMANDS(0, caller, 0)
+               VOTE_COMMANDS(0, caller, 0, "")
                #undef VOTE_COMMAND
                
                print("For help about specific commands, type ", command_origin, " vote help COMMAND\n");
@@ -633,19 +621,19 @@ void VoteCommand_macro_help(entity caller, float argc)
                #define VOTE_COMMAND(name,function,description,assignment) \
                        { if(Votecommand_check_assignment(caller, assignment)) { if(name == strtolower(argv(2))) { function; return; } } }
                        
-               VOTE_COMMANDS(VC_REQUEST_USAGE, caller, argc)
+               VOTE_COMMANDS(VC_REQUEST_USAGE, caller, argc, "")
                #undef VOTE_COMMAND
        }
        
        return;
 }
 
-float VoteCommand_macro_command(entity caller, float argc)
+float VoteCommand_macro_command(entity caller, float 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; } } }
                
-       VOTE_COMMANDS(VC_REQUEST_COMMAND, caller, argc)
+       VOTE_COMMANDS(VC_REQUEST_COMMAND, caller, argc, vote_command)
        #undef VOTE_COMMAND
        
        return FALSE;
@@ -656,13 +644,18 @@ float VoteCommand_macro_command(entity caller, float argc)
 //  Main function handling vote commands
 // ======================================
 
-void VoteCommand(float request, entity caller, float argc) 
+void VoteCommand(float request, entity caller, float argc, string vote_command
 {
+       // Guide for working with argc arguments by example:
+       // argc:   1    - 2      - 3     - 4
+       // argv:   0    - 1      - 2     - 3 
+       // cmd     vote - master - login - password
+       
        switch(request)
        {
                case VC_REQUEST_COMMAND:
                {
-                       if(VoteCommand_macro_command(caller, argc))
+                       if(VoteCommand_macro_command(caller, argc, vote_command))
                                return;
                }
                        
@@ -676,6 +669,130 @@ void VoteCommand(float request, entity caller, float argc)
        }
 }
 
+// =======================
+//  Game logic for voting
+// =======================
+
+void ReadyRestartForce()
+{
+       local entity e;
+
+       bprint("^1Server is restarting...\n");
+
+       VoteReset();
+
+       // clear overtime
+       if (checkrules_overtimesadded > 0 && g_race_qualifying != 2) {
+               //we have to decrease timelimit to its original value again!!
+               float newTL;
+               newTL = autocvar_timelimit;
+               newTL -= checkrules_overtimesadded * autocvar_timelimit_overtime;
+               cvar_set("timelimit", ftos(newTL));
+       }
+
+       checkrules_suddendeathend = checkrules_overtimesadded = checkrules_suddendeathwarning = 0;
+
+
+       readyrestart_happened = 1;
+       game_starttime = time;
+       if(!g_ca && !g_arena)
+               game_starttime += RESTART_COUNTDOWN;
+       restart_mapalreadyrestarted = 0; //reset this var, needed when cvar sv_ready_restart_repeatable is in use
+
+       inWarmupStage = 0; //once the game is restarted the game is in match stage
+
+       //reset the .ready status of all players (also spectators)
+       FOR_EACH_CLIENTSLOT(e)
+               e.ready = 0;
+       readycount = 0;
+       Nagger_ReadyCounted(); // NOTE: this causes a resend of that entity, and will also turn off warmup state on the client
+
+       if(autocvar_teamplay_lockonrestart && teamplay) {
+               lockteams = 1;
+               bprint("^1The teams are now locked.\n");
+       }
+
+       //initiate the restart-countdown-announcer entity
+       if(autocvar_sv_ready_restart_after_countdown && !g_ca && !g_arena)
+       {
+               restartTimer = spawn();
+               restartTimer.think = restartTimer_Think;
+               restartTimer.nextthink = game_starttime;
+       }
+
+       //after a restart every players number of allowed timeouts gets reset, too
+       if(autocvar_sv_timeout)
+       {
+               FOR_EACH_REALPLAYER(e)
+                       e.allowedTimeouts = autocvar_sv_timeout_number;
+       }
+
+       //reset map immediately if this cvar is not set
+       if (!autocvar_sv_ready_restart_after_countdown)
+               reset_map(TRUE);
+
+       if(autocvar_sv_eventlog)
+               GameLogEcho(":restart");
+}
+
+void ReadyRestart()
+{
+       // no arena, assault support yet...
+       if(g_arena | g_assault | gameover | intermission_running | race_completing)
+               localcmd("restart\n");
+       else
+               localcmd("\nsv_hook_gamerestart\n");
+
+       ReadyRestartForce();
+
+       // 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();
+}
+
+/**
+ * Counts how many players are ready. If not enough players are ready, the function
+ * does nothing. If all players are ready, the timelimit will be extended and the
+ * restart_countdown variable is set to allow other functions like PlayerPostThink
+ * to detect that the countdown is now active. If the cvar sv_ready_restart_after_countdown
+ * is not set the map will be resetted.
+ *
+ * Function is called after the server receives a 'ready' sign from a player.
+ */
+void ReadyCount()
+{
+       entity tmp_player;
+       float t_ready, t_players;
+
+       FOR_EACH_REALPLAYER(tmp_player)
+       {
+               ++t_players;
+               if(tmp_player.ready) { ++t_ready; }
+       }
+
+       readycount = t_ready;
+
+       Nagger_ReadyCounted();
+
+       // TODO: Add ability to 
+       if(t_ready) // at least one is ready
+       if(t_ready == t_players) // and, everyone is ready
+               ReadyRestart();
+}
+
+
+// Restarts the map after the countdown is over (and cvar sv_ready_restart_after_countdown is set)
+void restartTimer_Think() 
+{
+       restart_mapalreadyrestarted = 1;
+       reset_map(TRUE);
+       Score_ClearAll();
+       remove(self);
+       return;
+}
+
 void VoteHelp(entity e) {
        string vmasterdis;
        if(!autocvar_sv_vote_master) {
@@ -709,19 +826,6 @@ void VoteHelp(entity e) {
        print_to(e, strcat("^3", autocvar_sv_vote_commands, "^7 and maybe further ^3arguments^7"));
 }
 
-string VoteNetname(entity e)
-{
-       if(e) {
-               return e.netname;
-       } else {
-               if(autocvar_sv_adminnick != "") {
-                       return autocvar_sv_adminnick;
-               } else {
-                       return autocvar_hostname;
-               }
-       }
-}
-
 string ValidateMap(string m, entity e)
 {
        m = MapInfo_FixName(m);
@@ -754,12 +858,6 @@ void VoteThink() {
        }
 }
 
-string VoteParse(string all, float argc) {
-       if(argc < 3)
-               return "";
-       return substring(all, argv_start_index(2), argv_end_index(-1) - argv_start_index(2));
-}
-
 float VoteCommandInList(string votecommand, string list)
 {
        string l;
@@ -821,7 +919,7 @@ void VoteReset() {
 }
 
 void VoteAccept() {
-       bprint("\{1}^2* ^3", VoteNetname(votecaller), "^2's vote for ^1", votecalledvote_display, "^2 was accepted\n");
+       bprint("\{1}^2* ^3", VoteCommand_getname(votecaller), "^2's vote for ^1", votecalledvote_display, "^2 was accepted\n");
        if(votecalledmaster)
        {
                if(votecaller) {
@@ -839,30 +937,17 @@ void VoteAccept() {
 }
 
 void VoteReject() {
-       bprint("\{1}^2* ^3", VoteNetname(votecaller), "^2's vote for ", votecalledvote_display, "^2 was rejected\n");
+       bprint("\{1}^2* ^3", VoteCommand_getname(votecaller), "^2's vote for ", votecalledvote_display, "^2 was rejected\n");
        VoteReset();
        Announce("votefail");
 }
 
 void VoteTimeout() {
-       bprint("\{1}^2* ^3", VoteNetname(votecaller), "^2's vote for ", votecalledvote_display, "^2 timed out\n");
+       bprint("\{1}^2* ^3", VoteCommand_getname(votecaller), "^2's vote for ", votecalledvote_display, "^2 timed out\n");
        VoteReset();
        Announce("votefail");
 }
 
-void VoteStop(entity stopper) {
-       bprint("\{1}^2* ^3", VoteNetname(stopper), "^2 stopped ^3", VoteNetname(votecaller), "^2's vote\n");
-       if(autocvar_sv_eventlog)
-               GameLogEcho(strcat(":vote:vstop:", ftos(stopper.playerid)));
-       if(stopper == votecaller) {
-               // no wait for next vote so you can correct your vote
-               if(votecaller) {
-                       votecaller.vote_next = time + autocvar_sv_vote_stop;
-               }
-       }
-       VoteReset();
-}
-
 void VoteSpam(float notvoters, float mincount, string result)
 {
        string s;
index 7a25bda6495e2ccbdcc60067bbaedbed7c21a3e5..a5b25584fca6d7131bf403a080d3564afa965492 100644 (file)
@@ -13,14 +13,12 @@ float vote_abstaincount;
 float vote_needed_absolute;
 float vote_needed_simple;
 
-float VoteCheckNasty(string cmd);
+string VoteCommand_getname(entity caller);
 entity GetKickVoteVictim(string vote, string cmd, entity caller);
-void VoteCommand(float request, entity caller, float argc);
+void VoteCommand(float request, entity caller, float argc, string vote_command);
 void VoteHelp(entity e);
-string VoteNetname(entity e);
 string ValidateMap(string m, entity e);
 void VoteThink();
-string VoteParse(string s, float tokens);
 float VoteAllowed(string vote, string cmd);
 void VoteReset();
 void VoteAccept();