/**
* vim: set ts=4 :
* =============================================================================
* MapChooser Extended
* Creates a map vote at appropriate times, setting sm_nextmap to the winning
* vote. Includes extra options not present in the SourceMod MapChooser
*
* MapChooser Extended (C)2011-2013 Powerlord (Ross Bemrose)
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program 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
* this program. If not, see .
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or .
*
* Version: $Id$
*/
//#define DEBUG
#if defined DEBUG
#define assert(%1) if(!(%1)) ThrowError("Debug Assertion Failed");
#define assert_msg(%1,%2) if(!(%1)) ThrowError(%2);
#else
#define assert(%1)
#define assert_msg(%1,%2)
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#pragma semicolon 1
#pragma newdecls required
#define MCE_VERSION "1.3.1"
enum RoundCounting
{
RoundCounting_Standard = 0,
RoundCounting_MvM,
RoundCounting_ArmsRace,
}
// CSGO requires two cvars to get the game type
enum
{
GameType_Classic = 0,
GameType_GunGame = 1,
GameType_Training = 2,
GameType_Custom = 3,
}
enum
{
GunGameMode_ArmsRace = 0,
GunGameMode_Demolition = 1,
GunGameMode_DeathMatch = 2,
}
public Plugin myinfo =
{
name = "MapChooser Extended",
author = "Powerlord, Zuko, BotoX and AlliedModders LLC",
description = "Automated Map Voting with Extensions",
version = MCE_VERSION,
url = ""
};
/* Valve ConVars */
ConVar g_Cvar_Winlimit;
ConVar g_Cvar_Maxrounds;
ConVar g_Cvar_Fraglimit;
ConVar g_Cvar_Bonusroundtime;
ConVar g_Cvar_GameType;
ConVar g_Cvar_GameMode;
/* Plugin ConVars */
ConVar g_Cvar_StartTime;
ConVar g_Cvar_StartRounds;
ConVar g_Cvar_StartFrags;
ConVar g_Cvar_ExtendTimeStep;
ConVar g_Cvar_ExtendRoundStep;
ConVar g_Cvar_ExtendFragStep;
ConVar g_Cvar_ExcludeMaps;
ConVar g_Cvar_ExcludeMapsTime;
ConVar g_Cvar_IncludeMaps;
ConVar g_Cvar_IncludeMapsReserved;
ConVar g_Cvar_NoVoteMode;
ConVar g_Cvar_Extend;
ConVar g_Cvar_DontChange;
ConVar g_Cvar_EndOfMapVote;
ConVar g_Cvar_VoteDuration;
Handle g_VoteTimer = INVALID_HANDLE;
Handle g_RetryTimer = INVALID_HANDLE;
Handle g_WarningTimer = INVALID_HANDLE;
/* Data Handles */
Handle g_MapList = INVALID_HANDLE;
Handle g_NominateList[MAXPLAYERS + 1];
Handle g_NominateOwners = INVALID_HANDLE;
StringMap g_OldMapList;
StringMap g_TimeMapList;
Handle g_NextMapList = INVALID_HANDLE;
Handle g_VoteMenu = INVALID_HANDLE;
KeyValues g_Config;
int g_Extends;
int g_TotalRounds;
bool g_HasVoteStarted;
bool g_WaitingForVote;
bool g_MapVoteCompleted;
bool g_ChangeMapAtRoundEnd;
bool g_ChangeMapInProgress;
bool g_HasIntermissionStarted = false;
bool g_SaveCDOnMapEnd = true;
bool g_DidNotExtend = false;
bool g_DidRoundTerminate = false;
bool g_IniatedLastVote = false;
int g_mapFileSerial = -1;
int g_iPlayerCount_excludeSpec;
int g_iMapsFromCasualPool;
int g_iPlayerAFKTime;
int g_NominateCount = 0;
int g_NominateReservedCount = 0;
int g_iInterval;
float player_mapvote_worth[MAXPLAYERS + 1];
char player_mapvote[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
MapChange g_ChangeTime;
//check if autismbot
bool is_bot_player[MAXPLAYERS + 1];
Handle g_NominationsResetForward = INVALID_HANDLE;
Handle g_MapVoteStartedForward = INVALID_HANDLE;
/* Mapchooser Extended Plugin ConVars */
ConVar g_Cvar_RunOff;
ConVar g_Cvar_RunOffPercent;
ConVar g_Cvar_BlockSlots;
ConVar g_Cvar_MaxRunOffs;
ConVar g_Cvar_StartTimePercent;
ConVar g_Cvar_StartTimePercentEnable;
ConVar g_Cvar_WarningTime;
ConVar g_Cvar_RunOffWarningTime;
ConVar g_Cvar_TimerLocation;
ConVar g_Cvar_ExtendPosition;
ConVar g_Cvar_MarkCustomMaps;
ConVar g_Cvar_RandomizeNominations;
ConVar g_Cvar_HideTimer;
ConVar g_Cvar_NoVoteOption;
ConVar g_Cvar_ShufflePerClient;
ConVar g_Cvar_NoRestrictionTimeframeEnable;
ConVar g_Cvar_NoRestrictionTimeframeMinTime;
ConVar g_Cvar_NoRestrictionTimeframeMaxTime;
/* Mapchooser Extended Data Handles */
Handle g_OfficialList = INVALID_HANDLE;
/* Mapchooser Extended Forwards */
Handle g_MapVoteWarningStartForward = INVALID_HANDLE;
Handle g_MapVoteWarningTickForward = INVALID_HANDLE;
Handle g_MapVoteStartForward = INVALID_HANDLE;
Handle g_MapVoteEndForward = INVALID_HANDLE;
Handle g_MapVoteRunoffStartForward = INVALID_HANDLE;
/* Mapchooser Extended Globals */
int g_RunoffCount = 0;
int g_mapOfficialFileSerial = -1;
char g_GameModName[64];
bool g_WarningInProgress = false;
bool g_AddNoVote = false;
RoundCounting g_RoundCounting = RoundCounting_Standard;
/* Upper bound of how many team there could be */
#define MAXTEAMS 10
int g_winCount[MAXTEAMS];
bool g_BlockedSlots = false;
int g_ObjectiveEnt = -1;
enum TimerLocation
{
TimerLocation_Hint = 0,
TimerLocation_Center = 1,
TimerLocation_Chat = 2,
}
enum WarningType
{
WarningType_Vote,
WarningType_Revote,
}
#define VOTE_EXTEND "##extend##"
#define VOTE_DONTCHANGE "##dontchange##"
/* Mapchooser Extended Defines */
#define LINE_ONE "##lineone##"
#define LINE_TWO "##linetwo##"
#define LINE_SPACER "##linespacer##"
#define FAILURE_TIMER_LENGTH 5
//call forward to reset all nominations
public void OnPluginEnd()
{
for (int i = 0; i < MaxClients; i++)
{
int index = FindValueInArray(g_NominateOwners, i);
if (index == -1) continue;
for (int j = 0; j < GetArraySize(g_NominateList[i]); j++)
{
char oldmap[PLATFORM_MAX_PATH];
Call_StartForward(g_NominationsResetForward);
GetArrayString(g_NominateList[i], j, oldmap, PLATFORM_MAX_PATH);
Call_PushString(oldmap);
Call_PushCell(i);
Call_Finish();
}
}
}
public void OnPluginStart()
{
LoadTranslations("mapchooser_extended.phrases");
LoadTranslations("basevotes.phrases");
LoadTranslations("common.phrases");
int arraySize = ByteCountToCells(PLATFORM_MAX_PATH);
g_MapList = CreateArray(arraySize);
g_NominateOwners = CreateArray(1);
g_OldMapList = new StringMap();
g_TimeMapList = new StringMap();
g_NextMapList = CreateArray(arraySize);
g_OfficialList = CreateArray(arraySize);
for (int i = 0; i < MaxClients; i++)
{
g_NominateList[i] = CreateArray(arraySize);
if (IsValidClient(i))
{
OnClientPostAdminCheck(i);
}
}
GetGameFolderName(g_GameModName, sizeof(g_GameModName));
g_Cvar_EndOfMapVote = CreateConVar("mce_endvote", "1", "Specifies if MapChooser should run an end of map vote", _, true, 0.0, true, 1.0);
g_Cvar_StartTime = CreateConVar("mce_starttime", "10.0", "Specifies when to start the vote based on time remaining.", _, true, 1.0);
g_Cvar_StartRounds = CreateConVar("mce_startround", "2.0", "Specifies when to start the vote based on rounds remaining. Use 0 on DoD:S, CS:S, and TF2 to start vote during bonus round time", _, true, 0.0);
g_Cvar_StartFrags = CreateConVar("mce_startfrags", "5.0", "Specifies when to start the vote base on frags remaining.", _, true, 1.0);
g_Cvar_ExtendTimeStep = CreateConVar("mce_extend_timestep", "15", "Specifies how much many more minutes each extension makes", _, true, 5.0);
g_Cvar_ExtendRoundStep = CreateConVar("mce_extend_roundstep", "5", "Specifies how many more rounds each extension makes", _, true, 1.0);
g_Cvar_ExtendFragStep = CreateConVar("mce_extend_fragstep", "10", "Specifies how many more frags are allowed when map is extended.", _, true, 5.0);
g_Cvar_ExcludeMaps = CreateConVar("mce_exclude", "5", "Specifies how many past maps to exclude from the vote.", _, true, 0.0);
g_Cvar_ExcludeMapsTime = CreateConVar("mce_exclude_time", "5h", "Specifies how long in minutes an old map is excluded from the vote.");
g_Cvar_IncludeMaps = CreateConVar("mce_include", "5", "Specifies how many maps to include in the vote.", _, true, 2.0, true, 9.0);
g_Cvar_IncludeMapsReserved = CreateConVar("mce_include_reserved", "2", "Specifies how many private/random maps to include in the vote.", _, true, 0.0, true, 5.0);
g_Cvar_NoVoteMode = CreateConVar("mce_novote", "1", "Specifies whether or not MapChooser should pick a map if no votes are received.", _, true, 0.0, true, 1.0);
g_Cvar_Extend = CreateConVar("mce_extend", "0", "Number of extensions allowed each map.", _, true, 0.0);
g_Cvar_DontChange = CreateConVar("mce_dontchange", "1", "Specifies if a 'Don't Change option should be added to early votes", _, true, 0.0);
g_Cvar_VoteDuration = CreateConVar("mce_voteduration", "20", "Specifies how long the mapvote should be available for.", _, true, 5.0);
ConVar cvar2;
HookConVarChange((cvar2 = CreateConVar("mce_randomized_maps_from_casual_pool", "2", "f we have space left over for randomized maps at the mapvote. how many should be prioritized from the casual pool?")), Cvar_mapsFromCasualPool);
g_iMapsFromCasualPool = cvar2.IntValue;
delete cvar2;
ConVar cvar1;
HookConVarChange((cvar1 = CreateConVar("sm_active_players_required", "15", "Amount of players required to be considered active before any restrictions are enabled at all.")), Cvar_playerExcludeSpec);
g_iPlayerCount_excludeSpec = cvar1.IntValue;
delete cvar1;
ConVar cvar;
HookConVarChange((cvar = CreateConVar("sm_mapchooser_afk_time", "120", "Time in seconds until a player is considered as AFK and therefore excluded from player average")), Cvar_playerAFKTime);
g_iPlayerAFKTime = cvar.IntValue;
delete cvar;
// MapChooser Extended cvars
CreateConVar("mce_version", MCE_VERSION, "MapChooser Extended Version", FCVAR_SPONLY|FCVAR_NOTIFY|FCVAR_DONTRECORD);
g_Cvar_RunOff = CreateConVar("mce_runoff", "1", "Hold run off votes if winning choice has less than a certain percentage of votes", _, true, 0.0, true, 1.0);
g_Cvar_RunOffPercent = CreateConVar("mce_runoffpercent", "50", "If winning choice has less than this percent of votes, hold a runoff", _, true, 0.0, true, 100.0);
g_Cvar_BlockSlots = CreateConVar("mce_blockslots", "0", "Block slots to prevent accidental votes. Only applies when Voice Command style menus are in use.", _, true, 0.0, true, 1.0);
//g_Cvar_BlockSlotsCount = CreateConVar("mce_blockslots_count", "2", "Number of slots to block.", _, true, 1.0, true, 3.0);
g_Cvar_MaxRunOffs = CreateConVar("mce_maxrunoffs", "1", "Number of run off votes allowed each map.", _, true, 0.0);
g_Cvar_StartTimePercent = CreateConVar("mce_start_percent", "35.0", "Specifies when to start the vote based on percents.", _, true, 0.0, true, 100.0);
g_Cvar_StartTimePercentEnable = CreateConVar("mce_start_percent_enable", "0", "Enable or Disable percentage calculations when to start vote.", _, true, 0.0, true, 1.0);
g_Cvar_WarningTime = CreateConVar("mce_warningtime", "15.0", "Warning time in seconds.", _, true, 0.0, true, 60.0);
g_Cvar_RunOffWarningTime = CreateConVar("mce_runoffvotewarningtime", "5.0", "Warning time for runoff vote in seconds.", _, true, 0.0, true, 30.0);
g_Cvar_TimerLocation = CreateConVar("mce_warningtimerlocation", "0", "Location for the warning timer text. 0 is HintBox, 1 is Center text, 2 is Chat. Defaults to HintBox.", _, true, 0.0, true, 2.0);
g_Cvar_MarkCustomMaps = CreateConVar("mce_markcustommaps", "1", "Mark custom maps in the vote list. 0 = Disabled, 1 = Mark with *, 2 = Mark with phrase.", _, true, 0.0, true, 2.0);
g_Cvar_ExtendPosition = CreateConVar("mce_extendposition", "0", "Position of Extend/Dont Change options. 0 = at end, 1 = at start.", _, true, 0.0, true, 1.0);
g_Cvar_RandomizeNominations = CreateConVar("mce_randomizeorder", "0", "Randomize map order?", _, true, 0.0, true, 1.0);
g_Cvar_HideTimer = CreateConVar("mce_hidetimer", "0", "Hide the MapChooser Extended warning timer", _, true, 0.0, true, 1.0);
g_Cvar_NoVoteOption = CreateConVar("mce_addnovote", "1", "Add \"No Vote\" to vote menu?", _, true, 0.0, true, 1.0);
g_Cvar_ShufflePerClient = CreateConVar("mce_shuffle_per_client", "1", "Random shuffle map vote menu per client?", _, true, 0.0, true, 1.0);
g_Cvar_NoRestrictionTimeframeEnable = CreateConVar("mce_no_restriction_timeframe_enable", "1", "Enable timeframe where all nomination restrictions and cooldowns are disabled?", _, true, 0.0, true, 1.0);
g_Cvar_NoRestrictionTimeframeMinTime = CreateConVar("mce_no_restriction_timeframe_mintime", "0100", "Start of the timeframe where all nomination restrictions and cooldowns are disabled (Format: HHMM)", _, true, 0000.0, true, 2359.0);
g_Cvar_NoRestrictionTimeframeMaxTime = CreateConVar("mce_no_restriction_timeframe_maxtime", "0700", "End of the timeframe where all nomination restrictions and cooldowns are disabled (Format: HHMM)", _, true, 0000.0, true, 2359.0);
RegAdminCmd("sm_mapvote", Command_Mapvote, ADMFLAG_CHANGEMAP, "sm_mapvote - Forces MapChooser to attempt to run a map vote now.");
RegAdminCmd("sm_setnextmap", Command_SetNextmap, ADMFLAG_CHANGEMAP, "sm_setnextmap