openmohaa/code/fgame/bg_voteoptions.cpp

399 lines
10 KiB
C++

/*
===========================================================================
Copyright (C) 2023 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "bg_voteoptions.h"
#include "../qcommon/script.h"
CLASS_DECLARATION(Class, VoteOptions, NULL) {
{NULL, NULL}
};
VoteOptionListItem::VoteOptionListItem()
: m_pNext(NULL)
{}
SingleVoteOption::SingleVoteOption()
: m_optionType(VOTE_NO_CHOICES)
, m_pListItem(NULL)
, m_pNext(NULL)
{}
SingleVoteOption::~SingleVoteOption()
{
VoteOptionListItem *item;
VoteOptionListItem *next;
for (item = m_pListItem; item; item = next) {
next = item->m_pNext;
delete item;
}
}
VoteOptions::VoteOptions()
{
m_pHeadOption = NULL;
}
VoteOptions::~VoteOptions()
{
ClearOptions();
}
void VoteOptions::ClearOptions()
{
SingleVoteOption *option;
SingleVoteOption *next;
for (option = m_pHeadOption; option; option = next) {
next = option->m_pNext;
delete option;
}
m_pHeadOption = NULL;
}
void VoteOptions::SetupVoteOptions(const char *configFileName)
{
char *buffer;
int compressedLength;
long length;
length = gi.FS_ReadFile(configFileName, (void**)&buffer, qtrue);
if (length == -1 || !length) {
Com_Printf("WARNING: Couldn't find voting options file: %s\n", configFileName);
return;
}
// compress the buffer before setting up
compressedLength = COM_Compress(buffer);
SetupVoteOptions(configFileName, compressedLength, buffer);
gi.FS_FreeFile(buffer);
}
void VoteOptions::SetupVoteOptions(const char *configFileName, int length, const char *buffer)
{
if (length >= MAX_VOTEOPTIONS_BUFFER_LENGTH) {
Com_Error(
ERR_DROP,
"VoteOptions: Options file '%s' is too big. Max size is %i bytes\n",
configFileName,
MAX_VOTEOPTIONS_BUFFER_LENGTH
);
return;
}
m_sFileName = configFileName;
m_sBuffer = buffer;
ParseVoteOptions();
}
void VoteOptions::ParseVoteOptions()
{
SingleVoteOption *option;
SingleVoteOption *newOption;
VoteOptionListItem *listItem;
VoteOptionListItem *newListItem;
str token;
Script script;
ClearOptions();
script.LoadFile(m_sFileName.c_str(), m_sBuffer.length(), m_sBuffer.c_str());
option = m_pHeadOption;
while (script.TokenAvailable(true)) {
token = script.GetToken(true);
if (!str::icmp(token, "{")) {
Com_Error(
ERR_DROP,
"Vote Options %s: Found choices list without option header on line %d.\n",
m_sFileName.c_str(),
script.GetLineNumber()
);
return;
}
if (!str::icmp(token, "}")) {
Com_Error(
ERR_DROP,
"Vote Options %s: Illegal end of choices list without list being started on line %d.\n",
m_sFileName.c_str(),
script.GetLineNumber()
);
return;
}
if (!token.length()) {
Com_Error(
ERR_DROP,
"Vote Options %s: Empty option name on line %d.\n",
m_sFileName.c_str(),
script.GetLineNumber()
);
return;
}
newOption = new SingleVoteOption();
if (option) {
option->m_pNext = newOption;
} else {
m_pHeadOption = newOption;
}
option = newOption;
newOption->m_sOptionName = token;
if (!script.TokenAvailable(false)) {
Com_Error(
ERR_DROP,
"Vote Options %s: Option without a command specified on line %d.\n",
m_sFileName.c_str(),
script.GetLineNumber()
);
return;
}
newOption->m_sCommand = script.GetToken(false);
if (script.TokenAvailable(false)) {
token = script.GetToken(false);
if (!str::icmp(token, "nochoices")) {
newOption->m_optionType = VOTE_NO_CHOICES;
} else if (!str::icmp(token, "list")) {
newOption->m_optionType = VOTE_OPTION_LIST;
} else if (!str::icmp(token, "text")) {
newOption->m_optionType = VOTE_OPTION_TEXT;
} else if (!str::icmp(token, "integer")) {
newOption->m_optionType = VOTE_OPTION_INTEGER;
} else if (!str::icmp(token, "float")) {
newOption->m_optionType = VOTE_OPTION_FLOAT;
} else if (!str::icmp(token, "client")) {
newOption->m_optionType = VOTE_OPTION_CLIENT;
} else if (!str::icmp(token, "clientnotself")) {
newOption->m_optionType = VOTE_OPTION_CLIENT_NOT_SELF;
} else {
Com_Error(
ERR_DROP,
"Vote Options %s: Illegal option type '%s' specified on line %d.\n"
" Valid types are nochoices, list, text, & number.\n",
m_sFileName.c_str(),
token.c_str(),
script.GetLineNumber()
);
return;
}
}
if (newOption->m_optionType == VOTE_OPTION_LIST) {
if (!script.TokenAvailable(true) || Q_stricmp(script.GetToken(true), "{")) {
Com_Error(
ERR_DROP,
"Vote Options %s: Missing '{'. No choices list specified for list option on line %d.\n",
m_sFileName.c_str(),
script.GetLineNumber()
);
return;
}
listItem = NULL;
while (script.TokenAvailable(true)) {
token = script.GetToken(true);
if (!str::icmp(token, "}")) {
break;
}
newListItem = new VoteOptionListItem();
if (listItem) {
listItem->m_pNext = newListItem;
} else {
newOption->m_pListItem = newListItem;
}
listItem = newListItem;
if (!script.TokenAvailable(false)) {
Com_Error(
ERR_DROP,
"Vote Options %s: List choice without vote string specified on line %d.\n",
m_sFileName.c_str(),
script.GetLineNumber()
);
return;
}
newListItem->m_sCommand = script.GetToken(false);
}
} else if (script.TokenAvailable(true)) {
token = script.GetToken(true);
if (!str::icmp(token, "{")) {
Com_Error(
ERR_DROP,
"Vote Options %s: Choices list specified for non-list option on line %d.\n",
m_sFileName.c_str(),
script.GetLineNumber()
);
return;
}
script.UnGetToken();
}
}
}
const char *VoteOptions::GetVoteOptionsFile(int *outLen) const
{
if (outLen) {
*outLen = m_sBuffer.length();
}
return m_sBuffer.c_str();
}
bool VoteOptions::GetVoteOptionsMain(int index, str *outOptionCommand, voteoptiontype_t *outOptionType) const
{
SingleVoteOption *option;
int optionIndex;
if (index < 1) {
return false;
}
optionIndex = 1;
for (option = m_pHeadOption; optionIndex < index && option != NULL; option = option->m_pNext) {
optionIndex++;
}
if (!option) {
return false;
}
*outOptionCommand = option->m_sCommand;
*outOptionType = option->m_optionType;
return true;
}
bool VoteOptions::GetVoteOptionSub(int index, int listIndex, str *outCommand) const
{
SingleVoteOption *option;
VoteOptionListItem *item;
int optionIndex;
int itemIndex;
if (index < 1 || listIndex < 1) {
return false;
}
optionIndex = 1;
for (option = m_pHeadOption; optionIndex < index && option != NULL; option = option->m_pNext) {
optionIndex++;
}
if (!option) {
return false;
}
if (option->m_optionType != VOTE_OPTION_LIST) {
return false;
}
itemIndex = 1;
for (item = option->m_pListItem; itemIndex < listIndex && option != NULL; item = item->m_pNext) {
itemIndex++;
}
if (!item) {
return false;
}
*outCommand = item->m_sCommand;
return true;
}
bool VoteOptions::GetVoteOptionMainName(int index, str *outVoteName) const
{
SingleVoteOption *option;
int optionIndex;
if (index < 1) {
return false;
}
optionIndex = 1;
for (option = m_pHeadOption; optionIndex < index && option != NULL; option = option->m_pNext) {
optionIndex++;
}
if (!option) {
return false;
}
*outVoteName = option->m_sOptionName;
return true;
}
bool VoteOptions::GetVoteOptionSubName(int index, int listIndex, str *outName) const
{
SingleVoteOption *option;
VoteOptionListItem *item;
int optionIndex;
int itemIndex;
if (index < 1 || listIndex < 1) {
return false;
}
optionIndex = 1;
for (option = m_pHeadOption; optionIndex < index && option != NULL; option = option->m_pNext) {
optionIndex++;
}
if (!option) {
return false;
}
if (option->m_optionType != VOTE_OPTION_LIST) {
return false;
}
itemIndex = 1;
for (item = option->m_pListItem; itemIndex < listIndex && option != NULL; item = item->m_pNext) {
itemIndex++;
}
if (!item) {
return false;
}
*outName = item->m_sItemName;
return true;
}