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