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