]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/vote.qc
fix typo; report name changes; don't ignore sv_eventlog at soem places
[divverent/nexuiz.git] / data / qcsrc / server / vote.qc
1 float VoteCheckNasty(string cmd)
2 {
3         if(strstrofs(cmd, ";", 0) >= 0)
4                 return TRUE;
5         if(strstrofs(cmd, "\n", 0) >= 0)
6                 return TRUE;
7         if(strstrofs(cmd, "\r", 0) >= 0)
8                 return TRUE;
9         if(strstrofs(cmd, "$", 0) >= 0)
10                 return TRUE;
11         return FALSE;
12 }
13
14 entity GetKickVoteVictim(string vote, string cmd, entity caller)
15 {
16         float tokens;
17         float i, n, t;
18         string ns;
19         entity e;
20
21         tokens = tokenize(vote);
22         ns = "";
23
24         if(tokens >= 2)
25                 if(substring(argv(1), 0, 1) == "#")
26                 {
27                         ns = substring(argv(1), 1, 999);
28                         t = 2;
29                 }
30
31         if(tokens >= 3)
32                 if(argv(1) == "#")
33                 {
34                         ns = argv(2);
35                         t = 3;
36                 }
37
38         if(ns != "")
39         {
40                 GetKickVoteVictim_reason = "";
41                 for(i = t; i < tokens; ++i)
42                         GetKickVoteVictim_reason = strcat(GetKickVoteVictim_reason, argv(i), " ");
43                 GetKickVoteVictim_reason = substring(GetKickVoteVictim_reason, 0, strlen(GetKickVoteVictim_reason) - 1);
44
45                 n = stof(ns);
46                 if(ns == ftos(n)) if(n >= 1) if(n <= maxclients)
47                 {
48                         e = edict_num(n);
49                         if(clienttype(e) == CLIENTTYPE_REAL)
50                         {
51                                 GetKickVoteVictim_newcommand = strcat(argv(0), " # ", ns);
52                                 return e;
53                         }
54                 }
55         }
56
57         print_to(caller, strcat("Usage: ", cmd, " ", argv(0), " #playernumber (as in \"status\")\n"));
58         return world;
59 }
60
61 float GameCommand_Vote(string s, entity e) {
62         if(argv(0) == "help") {
63                 print_to(e, "  vote COMMANDS ARGUMENTS. See 'vote help' for more info.");
64                 return TRUE;
65         } else if(argv(0) == "vote") {
66                 if(argv(1) == "") {
67                         print_to(e, "^1You have to supply a vote command. See help for more info.");
68                 } else if(argv(1) == "help") {
69                         VoteHelp(e);
70                 } else if(argv(1) == "status") {
71                         if(votecalled) {
72                                 print_to(e, strcat("^7Vote for ", votecalledvote_display, "^7 called by ^7", VoteNetname(votecaller), "^7."));
73                         } else {
74                                 print_to(e, "^1No vote called.");
75                         }
76                 } else if(argv(1) == "call") {
77                         if(!e || cvar("sv_vote_call")) {
78                                 if(tourneyInMatchStage
79                                    && cvar("g_tourney_disable_spec_vote")
80                                    && e.classname != "player") {
81                                         print_to(e, "^1Error: Only players can call a vote during the match-stage.");
82                                 }
83                                 else if(timeoutStatus) { //don't allow a vote call during a timeout
84                                         print_to(e, "^1Error: You can not call a vote while a timeout is active.");
85                                 }
86                                 else if(votecalled) {
87                                         print_to(e, "^1There is already a vote called.");
88                                 } else {
89                                         local string vote;
90                                         vote = VoteParse();
91                                         if(vote == "") {
92                                                 print_to(e, "^1Your vote is empty. See help for more info.");
93                                         } else if(e
94                                                 && time < e.vote_next) {
95                                                         print_to(e, strcat("^1You have to wait ^2", ftos(e.vote_next - time), "^1 seconds before you can again call a vote."));
96                                         } else if(VoteCheckNasty(vote)) {
97                                                 print_to(e, "Syntax error in command. See help for more info.");
98                                         } else if(VoteAllowed(strcat1(argv(2)))) { // strcat seems to be necessary
99                                                 // remap chmap to gotomap (forces intermission)
100                                                 if(vote == "chmap" || vote == "gotomap") // won't work without arguments
101                                                         return TRUE;
102                                                 if(substring(vote, 0, 6) == "chmap ")
103                                                         vote = strcat("gotomap ", substring(vote, 6, strlen(vote) - 6));
104                                                 if(substring(vote, 0, 8) == "gotomap ")
105                                                 {
106                                                         if(!(vote = ValidateMap(substring(vote, 8, strlen(vote) - 8), e)))
107                                                                 return TRUE;
108                                                         vote = strcat("gotomap ", vote);
109                                                 }
110
111                                                 // make kick and kickban votes a bit nicer (and reject them if formatted badly)
112                                                 if(substring(vote, 0, 5) == "kick " || substring(vote, 0, 8) == "kickban ")
113                                                 {
114                                                         if(!(e = GetKickVoteVictim(vote, "vcall", e)))
115                                                                 return TRUE;
116                                                         vote = GetKickVoteVictim_newcommand;
117                                                         votecalledvote_display = strzone(strcat("^1", vote, " (^7", VoteNetname(e), "^1): ", GetKickVoteVictim_reason));
118                                                 }
119                                                 else
120                                                 {
121                                                         votecalledvote_display = strzone(strcat("^1", vote));
122                                                 }
123                                                 votecalledvote = strzone(vote);
124                                                 votecalled = TRUE;
125                                                 votecalledmaster = FALSE;
126                                                 votefinished = time + cvar("sv_vote_timeout");
127                                                 votecaller = e; // remember who called the vote
128                                                 if(e) {
129                                                         e.vote_vote = 1; // of course you vote yes
130                                                         e.vote_next = time + cvar("sv_vote_wait");
131                                                 }
132                                                 bprint("\{1}^2* ^3", VoteNetname(votecaller), "^2 calls a vote for ", votecalledvote_display, "\n");
133                                                 if(cvar("sv_eventlog"))
134                                                         GameLogEcho(strcat(":vote:vcall:", ftos(votecaller.playerid), ":", votecalledvote_display), TRUE);
135                                                 VoteCount(); // needed if you are the only one
136                                         } else {
137                                                 print_to(e, "^1This vote is not ok. See help for more info.");
138                                         }
139                                 }
140                         } else {
141                                 print_to(e, "^1Vote calling is NOT allowed.");
142                         }
143                 } else if(argv(1) == "stop") {
144                         if(!votecalled) {
145                                 print_to(e, "^1No vote called.");
146                         } else if(e == votecaller) { // the votecaller can stop a vote
147                                 VoteStop(e);
148                         } else if(!e) { // server admin / console can too
149                                 VoteStop(e);
150                         } else if(e.vote_master) { // masters can too
151                                 VoteStop(e);
152                         } else {
153                                 print_to(e, "^1You are not allowed to stop that Vote.");
154                         }
155                 } else if(argv(1) == "master") {
156                         if(cvar("sv_vote_master")) {
157                                 if(votecalled) {
158                                         print_to(e, "^1There is already a vote called.");
159                                 } else {
160                                         votecalled = TRUE;
161                                         votecalledmaster = TRUE;
162                                         votecalledvote = strzone("XXX");
163                                         votecalledvote_display = strzone("^3master");
164                                         votefinished = time + cvar("sv_vote_timeout");
165                                         votecaller = e; // remember who called the vote
166                                         if(e) {
167                                                 e.vote_vote = 1; // of course you vote yes
168                                                 e.vote_next = time + cvar("sv_vote_wait");
169                                         }
170                                         bprint("\{1}^2* ^3", VoteNetname(votecaller), "^2 calls a vote to become ^3master^2.\n");
171                                         if(cvar("sv_eventlog"))
172                                                 GameLogEcho(strcat(":vote:vcall:", ftos(votecaller.playerid), ":", votecalledvote_display), FALSE);
173                                         VoteCount(); // needed if you are the only one
174                                 }
175                         } else {
176                                 print_to(e, "^1Vote to become master is NOT allowed.");
177                         }
178                 } else if(argv(1) == "do") {
179                         if(!e || e.vote_master) {
180                                 local string dovote, dovote_display;
181                                 dovote = VoteParse();
182                                 if(dovote == "") {
183                                         print_to(e, "^1Your command was empty. See help for more info.");
184                                 } else if(VoteCheckNasty(dovote)) {
185                                         print_to(e, "Syntax error in command. See help for more info.");
186                                 } else if(VoteAllowed(strcat1(argv(2)))) { // strcat seems to be necessary
187                                         if(dovote == "chmap" || dovote == "gotomap") // won't work without arguments
188                                                 return TRUE;
189                                         if(substring(dovote, 0, 6) == "chmap ")
190                                                 dovote = strcat("gotomap ", substring(dovote, 6, strlen(dovote) - 6));
191                                         if(substring(dovote, 0, 8) == "gotomap ")
192                                         {
193                                                 if(!(dovote = ValidateMap(substring(dovote, 8, strlen(dovote) - 8), e)))
194                                                         return TRUE;
195                                                 dovote = strcat("gotomap ", dovote);
196                                         }
197
198                                         dovote_display = dovote;
199                                         if(substring(dovote, 0, 5) == "kick " || substring(dovote, 0, 8) == "kickban ")
200                                         {
201                                                 if(!(e = GetKickVoteVictim(dovote, "vdo", e)))
202                                                         return TRUE;
203                                                 dovote = GetKickVoteVictim_newcommand;
204                                                 dovote_display = strcat("^1", dovote, " (^7", VoteNetname(e), "^1): ", GetKickVoteVictim_reason);
205                                         }
206                                         bprint("\{1}^2* ^3", VoteNetname(e), "^2 used his ^3master^2 status to do \"^2", dovote_display, "^2\".\n");
207                                         if(cvar("sv_eventlog"))
208                                                 GameLogEcho(strcat(":vote:vdo:", ftos(e.playerid), ":", dovote_display), FALSE);
209                                         localcmd(strcat(dovote, "\n"));
210                                 } else {
211                                         print_to(e, "^1This command is not ok. See help for more info.");
212                                 }
213                         } else {
214                                 print_to(e, "^1You are NOT a master.  You might need to login or vote to become master first. See help for more info.");
215                         }
216                 } else if(argv(1) == "login") {
217                         local string masterpwd;
218                         masterpwd = cvar_string("sv_vote_master_password");
219                         if(masterpwd != "") {
220                                 local float granted;
221                                 granted = (masterpwd == argv(2));
222                                 if (e)
223                                         e.vote_master = granted;
224                                 if(granted) {
225                                         ServerConsoleEcho(strcat("Accepted master login from ", VoteNetname(e)), TRUE);
226                                         bprint("\{1}^2* ^3", VoteNetname(e), "^2 logged in as ^3master^2\n");
227                                         if(cvar("sv_eventlog"))
228                                                 GameLogEcho(strcat(":vote:vlogin:", ftos(e.playerid)), FALSE);
229                                 }
230                                 else
231                                         ServerConsoleEcho(strcat("REJECTED master login from ", VoteNetname(e)), TRUE);
232                         }
233                         else
234                                 print_to(e, "^1Login to become master is NOT allowed.");
235                 } else if(argv(1) == "yes") {
236                         if(!votecalled) {
237                                 print_to(e, "^1No vote called.");
238                         } else if (!e) {
239                                 print_to(e, "^1You can't vote from the server console.");
240                         } else if(e.vote_vote == 0
241                                   || cvar("sv_vote_change")) {
242                                 print_to(e, "^1You accepted the vote.");
243                                 e.vote_vote = 1;
244                                 centerprint_expire(e, CENTERPRIO_VOTE);
245                                 if(!cvar("sv_vote_singlecount")) {
246                                         VoteCount();
247                                 }
248                         } else {
249                                 print_to(e, "^1You have already voted.");
250                         }
251                 } else if(argv(1) == "no") {
252                         if(!votecalled) {
253                                 print_to(e, "^1No vote called.");
254                         } else if (!e) {
255                                 print_to(e, "^1You can't vote from the server console.");
256                         } else if(e.vote_vote == 0
257                                   || cvar("sv_vote_change")) {
258                                 print_to(e, "^1You rejected the vote.");
259                                 e.vote_vote = -1;
260                                 centerprint_expire(e, CENTERPRIO_VOTE);
261                                 if(!cvar("sv_vote_singlecount")) {
262                                         VoteCount();
263                                 }
264                         } else {
265                                 print_to(e, "^1You have already voted.");
266                         }
267                 } else if(argv(1) == "abstain" || argv(1) == "dontcare") {
268                         if(!votecalled) {
269                                 print_to(e, "^1No vote called.");
270                         } else if (!e) {
271                                 print_to(e, "^1You can't vote from the server console.");
272                         } else if(e.vote_vote == 0
273                                   || cvar("sv_vote_change")) {
274                                 print_to(e, "^1You abstained from your vote.");
275                                 e.vote_vote = -2;
276                                 centerprint_expire(e, CENTERPRIO_VOTE);
277                                 if(!cvar("sv_vote_singlecount")) {
278                                         VoteCount();
279                                 }
280                         } else {
281                                 print_to(e, "^1You have already voted.");
282                         }
283                 } else {
284                         // ignore this?
285                         print_to(e, "^1Unknown vote command.");
286                 }
287                 return TRUE;
288         }
289         return FALSE;
290 }
291
292 void VoteHelp(entity e) {
293         local string vmasterdis;
294         if(!cvar("sv_vote_master")) {
295                 vmasterdis = " ^1(disabled)";
296         }
297
298         local string vlogindis;
299         if("" == cvar_string("sv_vote_master_password")) {
300                 vlogindis = " ^1(disabled)";
301         }
302
303         local string vcalldis;
304         if(!cvar("sv_vote_call")) {
305                 vcalldis = " ^1(disabled)";
306         }
307
308         print_to(e, "^7You can use voting with \"^2cmd vote help^7\" \"^2cmd vote status^7\" \"^2cmd vote call ^3COMMAND ARGUMENTS^7\" \"^2cmd vote stop^7\" \"^2cmd vote master^7\" \"^2cmd vote login^7\" \"^2cmd vote do ^3COMMAND ARGUMENTS^7\" \"^2cmd vote yes^7\" \"^2cmd vote no^7\" \"^2cmd vote abstain^7\" \"^2cmd vote dontcare^7\".");
309         print_to(e, "^7Or if your version is up to date you can use these aliases \"^2vhelp^7\" \"^2vstatus^7\" \"^2vcall ^3COMMAND ARGUMENTS^7\" \"^2vstop^7\" \"^2vmaster^7\" \"^2vlogin^7\" \"^2vdo ^3COMMAND ARGUMENTS^7\" \"^2vyes^7\" \"^2vno^7\" \"^2abstain^7\" \"^2vdontcare^7\".");
310         print_to(e, "^7\"^2help^7\" shows this info.");
311         print_to(e, "^7\"^2status^7\" shows if there is a vote called and who called it.");
312         print_to(e, strcat("^7\"^2call^7\" is used to call a vote. See the list of allowed commands.", vcalldis, "^7"));
313         print_to(e, "^7\"^2stop^7\" can be used by the vote caller or an admin to stop a vote and maybe correct it.");
314         print_to(e, strcat("^7\"^2master^7\" call a vote to become master who can execute commands without a vote", vmasterdis, "^7"));
315         print_to(e, strcat("^7\"^2login^7\" login to become master who can execute commands without a vote.", vlogindis, "^7"));
316         print_to(e, "^7\"^2do^7\" executes a command if you are a master. See the list of allowed commands.");
317         print_to(e, "^7\"^2yes^7\", \"^2no^7\", \"^2abstain^7\" and \"^2dontcare^7\" to make your vote.");
318         print_to(e, "^7If enough of the players vote yes the vote is accepted.");
319         print_to(e, "^7If enough of the players vote no the vote is rejected.");
320         print_to(e, strcat("^7If neither the vote will timeout after ", cvar_string("sv_vote_timeout"), "^7 seconds."));
321         print_to(e, "^7You can call a vote for or execute these commands:");
322         print_to(e, strcat("^3", cvar_string("sv_vote_commands"), "^7 and maybe further ^3arguments^7"));
323 }
324
325 string VoteNetname(entity e)
326 {
327         if(e) {
328                 return e.netname;
329         } else {
330                 if(cvar_string("sv_adminnick") != "") {
331                         return cvar_string("sv_adminnick");
332                 } else {
333                         return cvar_string("hostname");
334                 }
335         }
336 }
337
338 string ValidateMap(string m, entity e)
339 {
340 #ifdef MAPINFO
341         m = MapInfo_FixName(m);
342         if(!m)
343         {
344                 print_to(e, "This map is not available on this server.");
345                 return string_null;
346         }
347 #else
348         if(!cvar("sv_vote_change_gametype"))
349                 if(!IsSameGametype(m))
350                 {
351                         print_to(e, "This server does not allow changing the game type by map votes.");
352                         return string_null;
353                 }
354 #endif
355         if(!cvar("sv_vote_override_mostrecent"))
356                 if(Map_IsRecent(m))
357                 {
358                         print_to(e, "This server does not allow for recent maps to be played again. Please be patient for some rounds.");
359                         return string_null;
360                 }
361 #ifdef MAPINFO
362         if(!MapInfo_CheckMap(m))
363         {
364                 print_to(e, strcat("^1Invalid mapname, \"^3", m, "^1\" does not support the current game mode."));
365                 return string_null;
366         }
367 #else
368         if(!TryFile(strcat("maps/", m, ".mapcfg")))
369         {
370                 print_to(e, strcat("^1Invalid mapname, \"^3", m, "^1\" does not exist on this server."));
371                 return string_null;
372         }
373 #endif
374
375         return m;
376 }
377
378
379 void VoteThink() {
380         if(votefinished > 0) // a vote was called
381         if(time > votefinished) // time is up
382         {
383                 VoteCount();
384         }
385 }
386
387 string VoteParse() {
388         local float index;
389         index = 3;
390         local string vote;
391         vote = argv(2);
392         while(argv(index) != "") {
393                 vote = strcat(vote, " ", argv(index));
394                 index++;
395         }
396
397         // necessary for some of the string operations
398         vote = strzone(vote);
399
400         return vote;
401 }
402
403 float VoteAllowed(string votecommand) {
404         tokenize(cvar_string("sv_vote_commands"));
405         local float index;
406         index = 0;
407         while(argv(index) != "") {
408                 if(votecommand == argv(index)) {
409                         return TRUE;
410                 }
411                 index++;
412         }
413         return FALSE;
414 }
415
416 void VoteReset() {
417         local entity player;
418
419         FOR_EACH_CLIENT(player)
420         {
421                 player.vote_vote = 0;
422                 centerprint_expire(player, CENTERPRIO_VOTE);
423         }
424
425         if(votecalled)
426         {
427                 strunzone(votecalledvote);
428                 strunzone(votecalledvote_display);
429         }
430
431         votecalled = FALSE;
432         votecalledmaster = FALSE;
433         votefinished = 0;
434 }
435
436 void VoteAccept() {
437         bprint("\{1}^2* ^3", VoteNetname(votecaller), "^2's vote for ^1", votecalledvote_display, "^2 was accepted\n");
438         if(votecalledmaster)
439         {
440                 if(votecaller) {
441                         votecaller.vote_master = 1;
442                 }
443         } else {
444                 //in g_tourney mode and if the vote is a timelimit-change, don't change it immediately but after restart
445                 if(cvar("g_tourney")
446                    && substring(votecalledvote, 0, 10) == "timelimit ") {
447                         if( stof(substring(votecalledvote, 10, strlen(votecalledvote) - 10)) > 0 ) {
448                                 timelimit_orig = stof(substring(votecalledvote, 10, strlen(votecalledvote) - 10));
449                                 bprint(strcat("The timelimit will be set to ", ftos(timelimit_orig), " minutes after the next restart!\n"));
450                         }
451                         else //calls like "timelimit -1" can pass immediately
452                                 localcmd(strcat(votecalledvote, "\n"));
453                 }
454                 else
455                         localcmd(strcat(votecalledvote, "\n"));
456         }
457         if(votecaller) {
458                 votecaller.vote_next = 0; // people like your votes,
459                                           // no wait for next vote
460         }
461         VoteReset();
462 }
463
464 void VoteReject() {
465         bprint("\{1}^2* ^3", VoteNetname(votecaller), "^2's vote for ", votecalledvote_display, "^2 was rejected\n");
466         VoteReset();
467 }
468
469 void VoteTimeout() {
470         bprint("\{1}^2* ^3", VoteNetname(votecaller), "^2's vote for ", votecalledvote_display, "^2 timed out\n");
471         VoteReset();
472 }
473
474 void VoteStop(entity stopper) {
475         bprint("\{1}^2* ^3", VoteNetname(stopper), "^2 stopped ^3", VoteNetname(votecaller), "^2's vote\n");
476         if(cvar("sv_eventlog"))
477                 GameLogEcho(strcat(":vote:vstop:", ftos(stopper.playerid)), FALSE);
478         if(stopper == votecaller) {
479                 // no wait for next vote so you can correct your vote
480                 if(votecaller) {
481                         votecaller.vote_next = 0;
482                 }
483         }
484         VoteReset();
485 }
486
487 void VoteNag() {
488         if(votecalled)
489         if(self.vote_vote == 0)
490                 centerprint_atprio(self, CENTERPRIO_VOTE, strcat("^7^3", VoteNetname(votecaller), "^2 called a vote for ", votecalledvote_display, "\n\n^2You have not voted yet!\n^2HINT: By default, F1 is yes and F2 is no."));
491 }
492
493 void VoteSpam(float yescount, float nocount, float abstaincount, float notvoters, float mincount, string result)
494 {
495         string s;
496         if(mincount >= 0)
497         {
498                 s = strcat("\{1}^2* vote results: ^1", ftos(yescount), "^2:^1");
499                 s = strcat(s, ftos(nocount), "^2 (^1");
500                 s = strcat(s, ftos(mincount), "^2 needed), ^1");
501                 s = strcat(s, ftos(abstaincount), "^2 didn't care, ^1");
502                 s = strcat(s, ftos(notvoters), "^2 didn't vote\n");
503         }
504         else
505         {
506                 s = strcat("\{1}^2* vote results: ^1", ftos(yescount), "^2:^1");
507                 s = strcat(s, ftos(nocount), "^2, ^1");
508                 s = strcat(s, ftos(abstaincount), "^2 didn't care, ^1");
509                 s = strcat(s, ftos(notvoters), "^2 didn't have to vote\n");
510         }
511         bprint(s);
512         if(cvar("sv_eventlog"))
513         {
514                 s = strcat(":vote:v", result, ":", ftos(yescount));
515                 s = strcat(s, ":", ftos(nocount));
516                 s = strcat(s, ":", ftos(abstaincount));
517                 s = strcat(s, ":", ftos(notvoters));
518                 s = strcat(s, ":", ftos(mincount));
519                 GameLogEcho(s, FALSE);
520         }
521 }
522
523 void VoteCount() {
524         local float playercount;
525         playercount = 0;
526         local float yescount;
527         yescount = 0;
528         local float nocount;
529         nocount = 0;
530         local float abstaincount;
531         abstaincount = 0;
532         local entity player;
533         //same for real players
534         local float realplayercount;
535         local float realplayeryescount;
536         local float realplayernocount;
537         local float realplayerabstaincount;
538         realplayercount = realplayernocount = realplayerabstaincount = realplayeryescount = 0;
539
540         FOR_EACH_REALCLIENT(player)
541         {
542                 if(player.vote_vote == -1) {
543                         nocount++;
544                 } else if(player.vote_vote == 1) {
545                         yescount++;
546                 } else if(player.vote_vote == -2) {
547                         abstaincount++;
548                 }
549                 playercount++;
550                 //do the same for real players
551                 if(player.classname == "player") {
552                         if(player.vote_vote == -1) {
553                                 realplayernocount++;
554                         } else if(player.vote_vote == 1) {
555                                 realplayeryescount++;
556                         } else if(player.vote_vote == -2) {
557                                 realplayerabstaincount++;
558                         }
559                         realplayercount++;
560                 }
561         }
562
563         //in tournament mode, if we have at least one player then don't make the vote dependent on spectators (so specs don't have to press F1)
564         if(cvar("g_tourney"))
565         if(realplayercount > 0) {
566                 yescount = realplayeryescount;
567                 nocount = realplayernocount;
568                 abstaincount = realplayerabstaincount;
569                 playercount = realplayercount;
570         }
571
572
573         if(votecalledmaster
574            && playercount == 1) {
575                 // if only one player is on the server becoming vote
576                 // master is not allowed.  This could be used for
577                 // trolling or worse. 'self' is the user who has
578                 // called the vote because this function is called
579                 // by SV_ParseClientCommand. Maybe all voting should
580                 // be disabled for a single player?
581                 print_to(votecaller, "^1You are the only player on this server so you can not become vote master.");
582                 if(votecaller) {
583                         votecaller.vote_next = 0;
584                 }
585                 VoteReset();
586         } else {
587                 float votefactor;
588                 votefactor = bound(0.5, cvar("sv_vote_majority_factor"), 0.999);
589                 if(yescount > (playercount - abstaincount) * votefactor)
590                 {
591                         VoteSpam(yescount, nocount, abstaincount, playercount - yescount - nocount - abstaincount, -1, "yes");
592                         VoteAccept();
593                 }
594                 else if(nocount >= (playercount - abstaincount) * (1 - votefactor)) // that means, yescount cannot reach minyes any more
595                 {
596                         VoteSpam(yescount, nocount, abstaincount, playercount - yescount - nocount - abstaincount, -1, "no");
597                         VoteReject();
598                 }
599                 else if(time > votefinished)
600                 {
601                         if(cvar("sv_vote_simple_majority"))
602                         {
603                                 string result;
604                                 if(yescount > (yescount + nocount) * votefactor)
605                                         result = "yes";
606                                 else if(yescount + nocount > 0)
607                                         result = "no";
608                                 else
609                                         result = "timeout";
610                                 VoteSpam(yescount, nocount, abstaincount, playercount - yescount - nocount - abstaincount, floor((yescount + nocount) * votefactor) + 1, result);
611                                 if(result == "yes")
612                                         VoteAccept();
613                                 else if(result == "no")
614                                         VoteReject();
615                                 else
616                                         VoteTimeout();
617                         }
618                         else
619                         {
620                                 VoteSpam(yescount, nocount, abstaincount, playercount - yescount - nocount - abstaincount, floor((playercount - abstaincount) * votefactor) + 1, "timeout");
621                                 VoteTimeout();
622                         }
623                 }
624         }
625 }