285 lines
5.2 KiB
Plaintext
285 lines
5.2 KiB
Plaintext
/*
|
|
* Copyright (c) 2016-2022 Vera Visions LLC.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
var string g_strVoteCmd;
|
|
var float g_flVoteTime;
|
|
var int g_iVoteState;
|
|
var int autocvar_mp_allowvote = TRUE;
|
|
|
|
enum
|
|
{
|
|
VOTE_INACTIVE,
|
|
VOTE_INPROGRESS,
|
|
VOTE_PASSED
|
|
};
|
|
|
|
/*
|
|
=================
|
|
Vote_End
|
|
=================
|
|
*/
|
|
void
|
|
Vote_End(void)
|
|
{
|
|
|
|
localcmd(sprintf("%s\n", g_strVoteCmd));
|
|
g_flVoteTime = 0.0f;
|
|
g_iVoteState = VOTE_INACTIVE;
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
Vote_Reset
|
|
|
|
Make sure all the cached stuff is reset.
|
|
=================
|
|
*/
|
|
void
|
|
Vote_Reset(void)
|
|
{
|
|
forceinfokey(world, "votes_y", "0");
|
|
forceinfokey(world, "votes_n", "0");
|
|
forceinfokey(world, "vote_cmd", "");
|
|
|
|
for (entity e = world; (e = find(e, ::classname, "player"));) {
|
|
NSClientPlayer pl = (NSClientPlayer)e;
|
|
pl.voted = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Vote_Passed
|
|
|
|
Called whenever enough people agreed, or time has run out with enougn YES's
|
|
=================
|
|
*/
|
|
void
|
|
Vote_Passed(void)
|
|
{
|
|
g_flVoteTime = time + 5.0f;
|
|
g_iVoteState = VOTE_PASSED;
|
|
bprint(PRINT_CHAT, "Vote passed.\n");
|
|
g_strVoteCmd = serverkey("vote_cmd");
|
|
Vote_Reset();
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Vote_Failed
|
|
|
|
Called whenever enough people disagreed, or time has run out below the limit
|
|
=================
|
|
*/
|
|
void
|
|
Vote_Failed(void)
|
|
{
|
|
g_flVoteTime = 0.0;
|
|
g_iVoteState = VOTE_INACTIVE;
|
|
bprint(PRINT_CHAT, "Vote failed.\n");
|
|
Vote_Reset();
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Vote_Frame
|
|
|
|
Called in ServerFrame... every single frame.
|
|
=================
|
|
*/
|
|
void
|
|
Vote_Frame(void)
|
|
{
|
|
if (time >= g_flVoteTime) {
|
|
|
|
if (g_iVoteState == VOTE_INPROGRESS) {
|
|
if (serverkeyfloat("votes_y") > serverkeyfloat("votes_n")) {
|
|
Vote_Passed();
|
|
} else {
|
|
Vote_Failed();
|
|
}
|
|
} else if (g_iVoteState == VOTE_PASSED) {
|
|
Vote_End();
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
CSEv_VoteY
|
|
|
|
'vote yes'
|
|
=================
|
|
*/
|
|
void
|
|
CSEv_VoteY(void)
|
|
{
|
|
NSClientPlayer pl = (NSClientPlayer)self;
|
|
|
|
/* No vote is in progress */
|
|
if (g_iVoteState != VOTE_INPROGRESS) {
|
|
return;
|
|
}
|
|
|
|
if (self.classname != "player") {
|
|
return;
|
|
}
|
|
|
|
if (pl.voted) {
|
|
return;
|
|
}
|
|
|
|
forceinfokey(world, "votes_y", ftos(serverkeyfloat("votes_y")+1));
|
|
pl.voted = 1;
|
|
|
|
/* HACK: Is there a better way to do this? */
|
|
float playernums = 0;
|
|
for (entity eFind = world; (eFind = find(eFind, ::classname, "player"));) {
|
|
playernums++;
|
|
}
|
|
|
|
/* We need at least half the players agreeing. */
|
|
if (serverkeyfloat("votes_y") > rint(playernums / 2)) {
|
|
Vote_Passed();
|
|
return;
|
|
}
|
|
|
|
if (serverkeyfloat("votes_n") + serverkeyfloat("votes_y") == playernums) {
|
|
g_flVoteTime = time + 0.0f;
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
CSEv_VoteN
|
|
|
|
'vote no'
|
|
=================
|
|
*/
|
|
void
|
|
CSEv_VoteN(void)
|
|
{
|
|
NSClientPlayer pl = (NSClientPlayer)self;
|
|
|
|
/* No vote is in progress */
|
|
if (g_iVoteState != VOTE_INPROGRESS) {
|
|
return;
|
|
}
|
|
|
|
if (self.classname != "player") {
|
|
return;
|
|
}
|
|
|
|
if (pl.voted) {
|
|
return;
|
|
}
|
|
|
|
forceinfokey(world, "votes_n", ftos(serverkeyfloat("votes_n")+1));
|
|
pl.voted = 1;
|
|
|
|
/* HACK: Is there a better way to do this? */
|
|
float playernums = 0;
|
|
for (entity eFind = world; (eFind = find(eFind, ::classname, "player"));) {
|
|
playernums++;
|
|
}
|
|
|
|
/* We need at least half the players disagreeing. */
|
|
if (serverkeyfloat("votes_n") > rint(playernums / 2)) {
|
|
Vote_Failed();
|
|
return;
|
|
}
|
|
|
|
if (serverkeyfloat("votes_n") + serverkeyfloat("votes_y") == playernums) {
|
|
g_flVoteTime = time + 0.0f;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
Vote_InitiateVote
|
|
|
|
Send the info to the clients and set the timer up
|
|
=================
|
|
*/
|
|
void
|
|
Vote_InitiateVote(string votemsg)
|
|
{
|
|
/* A vote is in progress */
|
|
if (g_iVoteState != VOTE_INACTIVE) {
|
|
return;
|
|
}
|
|
|
|
if (self.classname != "player") {
|
|
return;
|
|
}
|
|
|
|
Vote_Reset();
|
|
|
|
forceinfokey(world, "vote_cmd", votemsg);
|
|
g_flVoteTime = time + 30.0f;
|
|
g_iVoteState = VOTE_INPROGRESS;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
CSEv_CallVote_s
|
|
|
|
Initiates a vote via the 'callvote' client command.
|
|
=================
|
|
*/
|
|
void
|
|
CSEv_CallVote_s(string text)
|
|
{
|
|
if (autocvar_mp_allowvote == FALSE) {
|
|
return;
|
|
}
|
|
|
|
/* No vote is in progress */
|
|
if (g_iVoteState != VOTE_INACTIVE) {
|
|
sprint(self, PRINT_CHAT, "A vote is already in progress.\n");
|
|
return;
|
|
}
|
|
|
|
tokenize(text);
|
|
switch (argv(0)) {
|
|
case "map":
|
|
if (FileExists(sprintf("maps/%s.bsp", argv(1))) == false) {
|
|
sprint(self, PRINT_CHAT, sprintf("Map '%s' not available on server.\n", argv(1)));
|
|
break;
|
|
}
|
|
case "kick":
|
|
case "slowmo":
|
|
case "timelimit":
|
|
case "fraglimit":
|
|
case "map_restart":
|
|
case "nextmap":
|
|
Vote_InitiateVote(sprintf("%s %s", argv(0), argv(1)));
|
|
CSEv_VoteY();
|
|
break;
|
|
default:
|
|
sprint(self, PRINT_CHAT, sprintf("Cannot callvote for '%s'.\n", argv(0)));
|
|
}
|
|
|
|
}
|
|
|
|
void
|
|
Vote_Init(void)
|
|
{
|
|
Vote_Reset();
|
|
}
|