277 lines
8.3 KiB
C++
277 lines
8.3 KiB
C++
|
#include <STDInclude.hpp>
|
||
|
|
||
|
using namespace Utils::String;
|
||
|
|
||
|
namespace Components
|
||
|
{
|
||
|
std::unordered_map<std::string, Vote::CommandHandler> Vote::VoteCommands =
|
||
|
{
|
||
|
{"map_restart", HandleMapRestart},
|
||
|
{"map_rotate", HandleMapRotate},
|
||
|
{"typemap", HandleTypemap},
|
||
|
{"map", HandleMap},
|
||
|
{"g_gametype", HandleGametype},
|
||
|
};
|
||
|
|
||
|
void Vote::DisplayVote(const Game::gentity_s* ent)
|
||
|
{
|
||
|
Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_CALLEDAVOTE\x15%s\"", 0x65, ent->client->sess.cs.name));
|
||
|
Game::level->voteNo = 0;
|
||
|
Game::level->voteYes = 1;
|
||
|
Game::level->voteTime = Game::level->time + 30000;
|
||
|
|
||
|
for (auto i = 0; i < Game::level->maxclients; ++i)
|
||
|
{
|
||
|
Game::level->clients[i].ps.eFlags &= ~Game::EF_VOTED;
|
||
|
}
|
||
|
|
||
|
ent->client->ps.eFlags |= Game::EF_VOTED;
|
||
|
Game::SV_SetConfigstring(Game::CS_VOTE_TIME, VA("%i %i", Game::level->voteTime, *Game::sv_serverId_value));
|
||
|
Game::SV_SetConfigstring(Game::CS_VOTE_STRING, Game::level->voteDisplayString);
|
||
|
Game::SV_SetConfigstring(Game::CS_VOTE_YES, VA("%i", Game::level->voteYes));
|
||
|
Game::SV_SetConfigstring(Game::CS_VOTE_NO, VA("%i", Game::level->voteNo));
|
||
|
}
|
||
|
|
||
|
bool Vote::IsInvalidVoteString(const std::string& input)
|
||
|
{
|
||
|
static const char* separators[] = { "\n", "\r", ";" };
|
||
|
|
||
|
return std::ranges::any_of(separators,
|
||
|
[&](const std::string& str) { return input.find(str) != std::string::npos; });
|
||
|
}
|
||
|
|
||
|
bool Vote::HandleMapRestart([[maybe_unused]] const Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params)
|
||
|
{
|
||
|
sprintf_s(Game::level->voteString, "fast_restart");
|
||
|
sprintf_s(Game::level->voteDisplayString, "GAME_VOTE_MAPRESTART");
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool Vote::HandleMapRotate([[maybe_unused]] const Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params)
|
||
|
{
|
||
|
sprintf_s(Game::level->voteString, "%s", params->get(1));
|
||
|
sprintf_s(Game::level->voteDisplayString, "GAME_VOTE_NEXTMAP");
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool Vote::HandleTypemap([[maybe_unused]] const Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params)
|
||
|
{
|
||
|
char arg2[0x100]{};
|
||
|
char arg3[0x100]{};
|
||
|
|
||
|
strncpy_s(arg2, params->get(2), _TRUNCATE);
|
||
|
strncpy_s(arg3, params->get(3), _TRUNCATE);
|
||
|
|
||
|
if (!Game::Scr_IsValidGameType(arg2))
|
||
|
{
|
||
|
Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_INVALIDGAMETYPE\"", 0x65));
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (!std::strcmp(arg2, (*Game::g_gametype)->current.string))
|
||
|
{
|
||
|
arg2[0] = '\0';
|
||
|
}
|
||
|
|
||
|
const auto* mapname = Game::Dvar_RegisterString("mapname", "", Game::DVAR_ROM | Game::DVAR_SERVERINFO, "Current map name");
|
||
|
if (!std::strcmp(arg3, mapname->current.string))
|
||
|
{
|
||
|
arg3[0] = '\0';
|
||
|
}
|
||
|
|
||
|
if (!arg2[0] && !arg3[0])
|
||
|
{
|
||
|
Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_TYPEMAP_NOCHANGE\"", 0x65));
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (arg3[0])
|
||
|
{
|
||
|
if (arg2[0])
|
||
|
{
|
||
|
sprintf_s(Game::level->voteString, "g_gametype %s; map %s", arg2, arg3);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf_s(Game::level->voteString, "map %s", arg3);
|
||
|
}
|
||
|
|
||
|
if (arg2[0])
|
||
|
{
|
||
|
sprintf_s(Game::level->voteDisplayString, "GAME_VOTE_GAMETYPE\x14%s\x15 - \x14GAME_VOTE_MAP\x15%s", Game::Scr_GetGameTypeNameForScript(arg2), arg3);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf_s(Game::level->voteDisplayString, "GAME_VOTE_MAP\x15%s", arg3);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf_s(Game::level->voteString, "g_gametype %s; map_restart", arg2);
|
||
|
sprintf_s(Game::level->voteDisplayString, "GAME_VOTE_GAMETYPE\x14%s", Game::Scr_GetGameTypeNameForScript(arg2));
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool Vote::HandleMap([[maybe_unused]] const Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params)
|
||
|
{
|
||
|
sprintf_s(Game::level->voteString, "%s %s", params->get(1), params->get(2));
|
||
|
sprintf_s(Game::level->voteDisplayString, "GAME_VOTE_MAP\x15%s", params->get(2));
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool Vote::HandleGametype([[maybe_unused]] const Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params)
|
||
|
{
|
||
|
if (!Game::Scr_IsValidGameType(params->get(2)))
|
||
|
{
|
||
|
Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_INVALIDGAMETYPE\"", 0x65));
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
sprintf_s(Game::level->voteString, "%s %s; map_restart", params->get(2), params->get(3));
|
||
|
sprintf_s(Game::level->voteDisplayString, "GAME_VOTE_GAMETYPE\x14%s", Game::Scr_GetGameTypeNameForScript(params->get(2)));
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void Vote::Scr_VoteCalled(Game::gentity_s* self, const char* command, const char* param1, const char* param2)
|
||
|
{
|
||
|
Game::Scr_AddString(param2);
|
||
|
Game::Scr_AddString(param1);
|
||
|
Game::Scr_AddString(command);
|
||
|
Game::Scr_Notify(self, Game::scr_const->call_vote, 3);
|
||
|
}
|
||
|
|
||
|
void Vote::Scr_PlayerVote(Game::gentity_s* self, const char* option)
|
||
|
{
|
||
|
Game::Scr_AddString(option);
|
||
|
Game::Scr_Notify(self, Game::scr_const->vote, 1);
|
||
|
}
|
||
|
|
||
|
void Vote::Cmd_CallVote_f(Game::gentity_s* ent, const Command::ServerParams* params)
|
||
|
{
|
||
|
if (!(*Game::g_allowVote)->current.enabled)
|
||
|
{
|
||
|
Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_VOTINGNOTENABLED\"", 0x65));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (Game::level->numConnectedClients < 2)
|
||
|
{
|
||
|
Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_VOTINGNOTENOUGHPLAYERS\"", 0x65));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ((*Game::g_oldVoting)->current.enabled)
|
||
|
{
|
||
|
if (Game::level->voteTime)
|
||
|
{
|
||
|
Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_VOTEALREADYINPROGRESS\"", 0x65));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (ent->client->sess.voteCount >= 3)
|
||
|
{
|
||
|
Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_MAXVOTESCALLED\"", 0x65));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (ent->client->sess.cs.team == Game::TEAM_SPECTATOR)
|
||
|
{
|
||
|
Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_NOSPECTATORCALLVOTE\"", 0x65));
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (IsInvalidVoteString(params->get(1)) ||
|
||
|
IsInvalidVoteString(params->get(2)) ||
|
||
|
IsInvalidVoteString(params->get(3)))
|
||
|
{
|
||
|
Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_INVALIDVOTESTRING\"", 0x65));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!(*Game::g_oldVoting)->current.enabled)
|
||
|
{
|
||
|
Scr_VoteCalled(ent, params->get(1), params->get(2), params->get(3));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const auto got = VoteCommands.find(params->get(1));
|
||
|
if (got == VoteCommands.end())
|
||
|
{
|
||
|
Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_INVALIDVOTESTRING\"", 0x65));
|
||
|
Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA(CallVoteDesc, 0x65));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (Game::level->voteExecuteTime)
|
||
|
{
|
||
|
Game::level->voteExecuteTime = 0;
|
||
|
Game::Cbuf_AddText(0, VA("%s\n", Game::level->voteString));
|
||
|
}
|
||
|
|
||
|
const auto shouldDisplay = got->second(ent, params);
|
||
|
if (shouldDisplay)
|
||
|
{
|
||
|
DisplayVote(ent);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Vote::Cmd_Vote_f(Game::gentity_s* ent, const Command::ServerParams* params)
|
||
|
{
|
||
|
char arg1[0x100]{};
|
||
|
|
||
|
if ((*Game::g_oldVoting)->current.enabled)
|
||
|
{
|
||
|
if (!Game::level->voteTime)
|
||
|
{
|
||
|
Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_NOVOTEINPROGRESS\"", 0x65));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ((ent->client->ps.eFlags & Game::EF_VOTED) != 0)
|
||
|
{
|
||
|
Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_VOTEALREADYCAST\"", 0x65));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (ent->client->sess.cs.team == Game::TEAM_SPECTATOR)
|
||
|
{
|
||
|
Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_NOSPECTATORVOTE\"", 0x65));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_VOTECAST\"", 0x65));
|
||
|
ent->client->ps.eFlags |= Game::EF_VOTED;
|
||
|
}
|
||
|
|
||
|
strncpy_s(arg1, params->get(1), _TRUNCATE);
|
||
|
if (arg1[0] == 'y' || arg1[0] == 'Y' || arg1[0] == '1')
|
||
|
{
|
||
|
if ((*Game::g_oldVoting)->current.enabled)
|
||
|
{
|
||
|
Game::SV_SetConfigstring(Game::CS_VOTE_YES, VA("%i", ++Game::level->voteYes));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Scr_PlayerVote(ent, "yes");
|
||
|
}
|
||
|
}
|
||
|
else if ((*Game::g_oldVoting)->current.enabled)
|
||
|
{
|
||
|
Game::SV_SetConfigstring(Game::CS_VOTE_NO, VA("%i", ++Game::level->voteNo));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Scr_PlayerVote(ent, "no");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Vote::Vote()
|
||
|
{
|
||
|
ClientCommand::Add("callvote", Cmd_CallVote_f);
|
||
|
ClientCommand::Add("vote", Cmd_Vote_f);
|
||
|
}
|
||
|
}
|