/////////////////////////////////////////////////////////////
// Automatic Campaign Switcher for L4D2 //
// Version 1.2.3_vanilla //
// Compiled March 24 2015 //
// Programmed by ChrisP, edited by el_psycho, Mr. //
/////////////////////////////////////////////////////////////
/*==================================================================================================
This plugin was written in response to the server kicking everyone if the vote is not passed
at the end of the campaign. It will automatically switch to the appropriate map at all the
points a vote would be automatically called, by the game, to go to the lobby or play again.
ACS also includes a voting system in which people can vote for their favorite campaign/map
on a finale or scavenge map. The winning campaign/map will become the next map the server
loads.
Supported Game Modes in Left 4 Dead 2
Coop
Realism
Versus
Team Versus
Scavenge
Team Scavenge
Mutation 1-20
Community 1-5
Change Log
v1.2.3_vanilla (March 3 2015) - Removed custom maps and restored vanilla map listing
v1.2.3 (July 1 2014) - Removed the kick all players when switching to 3rd party map
===================================================================================================*/
#include
#include
#define PLUGIN_VERSION "v1.2.3"
//Define the number of campaigns and maps in rotation
#define NUMBER_OF_CAMPAIGNS 39 /* CHANGE TO MATCH THE TOTAL NUMBER OF CAMPAIGNS */
#define NUMBER_OF_SCAVENGE_MAPS 39 /* CHANGE TO MATCH THE TOTAL NUMBER OF SCAVENGE MAPS */
//Define the wait time after round before changing to the next map in each game mode
#define WAIT_TIME_BEFORE_SWITCH_COOP 5.0
#define WAIT_TIME_BEFORE_SWITCH_VERSUS 5.0
#define WAIT_TIME_BEFORE_SWITCH_SCAVENGE 5.0
//Define Game Modes
#define GAMEMODE_UNKNOWN -1
#define GAMEMODE_COOP 0
#define GAMEMODE_VERSUS 1
#define GAMEMODE_SCAVENGE 2
#define GAMEMODE_SURVIVAL 3
#define DISPLAY_MODE_DISABLED 0
#define DISPLAY_MODE_HINT 1
#define DISPLAY_MODE_CHAT 2
#define DISPLAY_MODE_MENU 3
#define AUTOCHANGEMAP_MODE_DISABLED 0
#define AUTOCHANGEMAP_MODE_ROTATION 1
#define AUTOCHANGEMAP_MODE_FIXED 2
#define SOUND_NEW_VOTE_START "ui/Beep_SynthTone01.wav"
#define SOUND_NEW_VOTE_WINNER "ui/alert_clink.wav"
//Global Variables
new g_iGameMode; //Integer to store the gamemode
new g_iRoundEndCounter; //Round end event counter for versus
new g_iCoopFinaleFailureCount; //Number of times the Survivors have lost the current finale
new g_iMaxCoopFinaleFailures = 5; //Amount of times Survivors can fail before ACS switches in coop
new bool:g_bFinaleWon; //Indicates whether a finale has be beaten or not
new g_iMinutesServerEmpty; //How long the server has been empty
new g_iAutoChangeMapMode = AUTOCHANGEMAP_MODE_DISABLED; //The way to automatically change campaing/map when the server is empty
new g_iAutoChangeMapTime = 10; //The time in minutes the server has to be empty to automatically change campaing/map
new String:g_strAutoChangeMapFixedMap[32]; //The map name to switched to if the server has been empty for a period of time and autochange map mode is 2
new String:g_zdiff[12]; //The difficulty to change back to after the server has been empty for a period of time
//Campaign and map strings/names
new String:g_strCampaignFirstMap[NUMBER_OF_CAMPAIGNS][32]; //Array of maps to switch to
new String:g_strCampaignLastMap[NUMBER_OF_CAMPAIGNS][32]; //Array of maps to switch from
new String:g_strCampaignName[NUMBER_OF_CAMPAIGNS][32]; //Array of names of the campaign
new String:g_strScavengeMap[NUMBER_OF_SCAVENGE_MAPS][32]; //Array of scavenge maps
new String:g_strScavengeMapName[NUMBER_OF_SCAVENGE_MAPS][32]; //Name of scaveenge maps
//Voting Variables
new bool:g_bVotingEnabled = true; //Tells if the voting system is on
new g_iVotingAdDisplayMode = DISPLAY_MODE_HINT; //The way to advertise the voting system
new Float:g_fVotingAdDelayTime = 1.0; //Time to wait before showing advertising
new bool:g_bVoteWinnerSoundEnabled = true; //Sound plays when vote winner changes
new g_iNextMapAdDisplayMode = DISPLAY_MODE_HINT; //The way to advertise the next map
new Float:g_fNextMapAdInterval = 600.0; //Interval for ACS next map advertisement
new bool:g_bClientShownVoteAd[MAXPLAYERS + 1]; //If the client has seen the ad already
new bool:g_bClientVoted[MAXPLAYERS + 1]; //If the client has voted on a map
new g_iClientVote[MAXPLAYERS + 1]; //The value of the clients vote
new g_iWinningMapIndex; //Winning map/campaign's index
new g_iWinningMapVotes; //Winning map/campaign's number of votes
new Handle:g_hMenu_Vote[MAXPLAYERS + 1] = INVALID_HANDLE; //Handle for each players vote menu
//Console Variables (CVars)
new Handle:g_hCVar_VotingEnabled = INVALID_HANDLE;
new Handle:g_hCVar_VoteWinnerSoundEnabled = INVALID_HANDLE;
new Handle:g_hCVar_VotingAdMode = INVALID_HANDLE;
new Handle:g_hCVar_VotingAdDelayTime = INVALID_HANDLE;
new Handle:g_hCVar_NextMapAdMode = INVALID_HANDLE;
new Handle:g_hCVar_NextMapAdInterval = INVALID_HANDLE;
new Handle:g_hCVar_MaxFinaleFailures = INVALID_HANDLE;
new Handle:g_hCVar_AutoChangeMapMode = INVALID_HANDLE;
new Handle:g_hCVar_AutoChangeMapTime = INVALID_HANDLE;
new Handle:g_hCVar_AutoChangeMapFixedMap = INVALID_HANDLE;
new Handle:g_hCVar_zdiffculty = INVALID_HANDLE;
/*======================================================================================
################## A C S M A P S T R I N G S #################
========================================================================================
### ###
### *** EDIT THESE STRINGS TO CHANGE THE MAP ROTATIONS TO YOUR LIKING *** ###
### ###
========================================================================================
### ###
### Note: The order these strings are stored is important, so make ###
### sure these match up or it will not work properly. ###
### ###
### Make all three of the string variables match, for example: ###
### ###
### Format(g_strCampaignFirstMap[1], 32, "c1m1_hotel"); ###
### Format(g_strCampaignLastMap[1], 32, "c1m4_atrium"); ###
### Format(g_strCampaignName[1], 32, "Dead Center"); ###
### ###
### Notice, all of the strings corresponding with [1] in the array match. ###
### ###
======================================================================================*/
SetupMapStrings()
{
//The following three variables are for all game modes except Scavenge.
//*IMPORTANT* Before editing these change NUMBER_OF_CAMPAIGNS near the top
//of this plugin to match the total number of campaigns or it will not
//loop through all of them when the check is made to change the campaign.
//Первая миссия карты
Format(g_strCampaignFirstMap[0], 32, "c1m1_hotel");
Format(g_strCampaignFirstMap[1], 32, "c6m1_riverbank");
Format(g_strCampaignFirstMap[2], 32, "c2m1_highway");
Format(g_strCampaignFirstMap[3], 32, "c3m1_plankcountry");
Format(g_strCampaignFirstMap[4], 32, "c4m1_milltown_a");
Format(g_strCampaignFirstMap[5], 32, "c5m1_waterfront");
Format(g_strCampaignFirstMap[6], 32, "c8m1_apartment");
Format(g_strCampaignFirstMap[7], 32, "c9m1_alleys");
Format(g_strCampaignFirstMap[8], 32, "c10m1_caves");
Format(g_strCampaignFirstMap[9], 32, "c11m1_greenhouse");
Format(g_strCampaignFirstMap[10], 32, "c12m1_hilltop");
Format(g_strCampaignFirstMap[11], 32, "c7m1_docks");
Format(g_strCampaignFirstMap[12], 32, "c13m1_alpinecreek");
Format(g_strCampaignFirstMap[13], 32, "C1_mario1_1");
Format(g_strCampaignFirstMap[14], 32, "rmstitanic_m1");
Format(g_strCampaignFirstMap[15], 32, "ddg1_tower_v2_1");
Format(g_strCampaignFirstMap[16], 32, "village_beta408");
Format(g_strCampaignFirstMap[17], 32, "gb_m1_road");
Format(g_strCampaignFirstMap[18], 32, "orc001");
Format(g_strCampaignFirstMap[19], 32, "revenge_m1_office_new");
Format(g_strCampaignFirstMap[20], 32, "cbm1_lake");
Format(g_strCampaignFirstMap[21], 32, "l4d_withoutname_complex");
Format(g_strCampaignFirstMap[22], 32, "tiwei");
Format(g_strCampaignFirstMap[23], 32, "InnesRoadRash01");
Format(g_strCampaignFirstMap[24], 32, "patients");
Format(g_strCampaignFirstMap[25], 32, "l4d2_deadstreet_obahn");
Format(g_strCampaignFirstMap[26], 32, "l4d2_draxmap1");
Format(g_strCampaignFirstMap[27], 32, "l4d_lh_01");
Format(g_strCampaignFirstMap[28], 32, "citystreets1ewc");
Format(g_strCampaignFirstMap[29], 32, "l4d2_trainstation_01");
Format(g_strCampaignFirstMap[30], 32, "l4d2_canals_01");
Format(g_strCampaignFirstMap[31], 32, "l4d2_canals_07");
Format(g_strCampaignFirstMap[32], 32, "neverendingwar_train");
Format(g_strCampaignFirstMap[33], 32, "l4d_yama_1");
Format(g_strCampaignFirstMap[34], 32, "l4d2_mic2_trapmentd");
Format(g_strCampaignFirstMap[35], 32, "l4d2_ravenholmwar_1");
Format(g_strCampaignFirstMap[36], 32, "quart");
Format(g_strCampaignFirstMap[37], 32, "l4d_ilogiccity_01");
Format(g_strCampaignFirstMap[38], 32, "l4d_deathaboard01_prison");
//Финальная миссия карты
Format(g_strCampaignLastMap[0], 32, "c1m4_atrium");
Format(g_strCampaignLastMap[1], 32, "c6m3_port");
Format(g_strCampaignLastMap[2], 32, "c2m5_concert");
Format(g_strCampaignLastMap[3], 32, "c3m4_plantation");
Format(g_strCampaignLastMap[4], 32, "c4m5_milltown_escape");
Format(g_strCampaignLastMap[5], 32, "c5m5_bridge");
Format(g_strCampaignLastMap[6], 32, "c8m5_rooftop");
Format(g_strCampaignLastMap[7], 32, "c9m2_lots");
Format(g_strCampaignLastMap[8], 32, "c10m5_houseboat");
Format(g_strCampaignLastMap[9], 32, "c11m5_runway");
Format(g_strCampaignLastMap[10], 32, "c12m5_cornfield");
Format(g_strCampaignLastMap[11], 32, "c7m3_port");
Format(g_strCampaignLastMap[12], 32, "c13m4_cutthroatcreek");
Format(g_strCampaignLastMap[13], 32, "C1_mario1_4");
Format(g_strCampaignLastMap[14], 32, "rmstitanic_m4");
Format(g_strCampaignLastMap[15], 32, "ddg3_bluff_v2_1");
Format(g_strCampaignLastMap[16], 32, "final_beta408");
Format(g_strCampaignLastMap[17], 32, "gb_m5_burn");
Format(g_strCampaignLastMap[18], 32, "orc003");
Format(g_strCampaignLastMap[19], 32, "revenge_m3b_under");
Format(g_strCampaignLastMap[20], 32, "cbm3_bunker");
Format(g_strCampaignLastMap[21], 32, "l4d_withoutname_town");
Format(g_strCampaignLastMap[22], 32, "shanding");
Format(g_strCampaignLastMap[23], 32, "InnesRoadRash05");
Format(g_strCampaignLastMap[24], 32, "subwayrescue");
Format(g_strCampaignLastMap[25], 32, "l4d2_deadstreet_thepark");
Format(g_strCampaignLastMap[26], 32, "l4d2_draxmap6");
Format(g_strCampaignLastMap[27], 32, "l4d_lh_end_04");
Format(g_strCampaignLastMap[28], 32, "l4d2_helicopterescapeewc");
Format(g_strCampaignLastMap[29], 32, "l4d2_trainstation_06");
Format(g_strCampaignLastMap[30], 32, "l4d2_canals_06");
Format(g_strCampaignLastMap[31], 32, "l4d2_eli_02");
Format(g_strCampaignLastMap[32], 32, "neverendingwar_m4_storage_new");
Format(g_strCampaignLastMap[33], 32, "l4d_yama_5");
Format(g_strCampaignLastMap[34], 32, "l4d2_mic_finale");
Format(g_strCampaignLastMap[35], 32, "l4d2_ravenholmwar_4");
Format(g_strCampaignLastMap[36], 32, "metro_vlc");
Format(g_strCampaignLastMap[37], 32, "l4d_ilogiccity_04");
Format(g_strCampaignLastMap[38], 32, "l4d_deathaboard05_light");
//Название карты
Format(g_strCampaignName[0], 32, "Вымерший Центр");
Format(g_strCampaignName[1], 32, "Переход")
Format(g_strCampaignName[2], 32, "Мрачный Карнавал");
Format(g_strCampaignName[3], 32, "Болотная Лихорадка");
Format(g_strCampaignName[4], 32, "Жуткий Ливень");
Format(g_strCampaignName[5], 32, "Приход");
Format(g_strCampaignName[6], 32, "Нет Милосердию");
Format(g_strCampaignName[7], 32, "Роковой Полёт");
Format(g_strCampaignName[8], 32, "Похоронный звон");
Format(g_strCampaignName[9], 32, "Смерть в воздухе");
Format(g_strCampaignName[10], 32, "Кровавая Жатва");
Format(g_strCampaignName[11], 32, "Жертва");
Format(g_strCampaignName[12], 32, "Холодный Поток");
Format(g_strCampaignName[13], 32, "Left 4 Mario");
Format(g_strCampaignName[14], 32, "RMS Titanic");
Format(g_strCampaignName[15], 32, "drop dead gorges v2.1");
Format(g_strCampaignName[16], 32, "Death Trip v5");
Format(g_strCampaignName[17], 32, "Going Ballistic v5.0");
Format(g_strCampaignName[18], 32, "Ottawa Rock City (1.9)");
Format(g_strCampaignName[19], 32, "Revenge");
Format(g_strCampaignName[20], 32, "Blood Proof");
Format(g_strCampaignName[21], 32, "Zombie Movie Without Name!");
Format(g_strCampaignName[22], 32, "Yanzhou");
Format(g_strCampaignName[23], 32, "Innes Road Rash 2.7");
Format(g_strCampaignName[24], 32, "CursedCity");
Format(g_strCampaignName[25], 32, "Dead Street 2 (2.0)");
Format(g_strCampaignName[26], 32, "Death Strip");
Format(g_strCampaignName[27], 32, "Last HeartBeat (2.0)");
Format(g_strCampaignName[28], 32, "Escape the Devil's Chapel TLM Ver");
Format(g_strCampaignName[29], 32, "Half-Life 2: Trainstation");
Format(g_strCampaignName[30], 32, "Half-Life 2: Route Kanal");
Format(g_strCampaignName[31], 32, "Half-Life 2: Water Hazard");
Format(g_strCampaignName[32], 32, "Never Ending War - Fixed");
Format(g_strCampaignName[33], 32, "Yama");
Format(g_strCampaignName[34], 32, "Military Industrial Complex III v666");
Format(g_strCampaignName[35], 32, "We Don't Go To Ravenholm 2");
Format(g_strCampaignName[36], 32, "Escape From Valencia v2");
Format(g_strCampaignName[37], 32, "Ilogic City of the Dead 2");
Format(g_strCampaignName[38], 32, "Death Aboard II");
//The following string variables are only for Scavenge
//*IMPORTANT* Before editing these change NUMBER_OF_SCAVENGE_MAPS
//near the top of this plugin to match the total number of scavenge
//maps, or it will not loop through all of them when changing maps.
//Scavenge Maps
Format(g_strScavengeMap[0], 32, "c8m1_apartment");
Format(g_strScavengeMap[1], 32, "c8m5_rooftop");
Format(g_strScavengeMap[2], 32, "c1m4_atrium");
Format(g_strScavengeMap[3], 32, "c7m1_docks");
Format(g_strScavengeMap[4], 32, "c7m2_barge");
Format(g_strScavengeMap[5], 32, "c6m1_riverbank");
Format(g_strScavengeMap[6], 32, "c6m2_bedlam");
Format(g_strScavengeMap[7], 32, "c6m3_port");
Format(g_strScavengeMap[8], 32, "c2m1_highway");
Format(g_strScavengeMap[9], 32, "c3m1_plankcountry");
Format(g_strScavengeMap[10], 32, "c4m1_milltown_a");
Format(g_strScavengeMap[11], 32, "c4m2_sugarmill_a");
Format(g_strScavengeMap[12], 32, "c5m2_park");
//Scavenge Map Names
Format(g_strScavengeMapName[0], 32, "Apartments");
Format(g_strScavengeMapName[1], 32, "Rooftop");
Format(g_strScavengeMapName[2], 32, "Mall Atrium");
Format(g_strScavengeMapName[3], 32, "Brick Factory");
Format(g_strScavengeMapName[4], 32, "Barge");
Format(g_strScavengeMapName[5], 32, "Riverbank");
Format(g_strScavengeMapName[6], 32, "Underground");
Format(g_strScavengeMapName[7], 32, "Port");
Format(g_strScavengeMapName[8], 32, "Motel");
Format(g_strScavengeMapName[9], 32, "Plank Country");
Format(g_strScavengeMapName[10], 32, "Milltown");
Format(g_strScavengeMapName[11], 32, "Sugar Mill");
Format(g_strScavengeMapName[12], 32, "Park");
}
/*======================================================================================
##################### P L U G I N I N F O ####################
======================================================================================*/
public Plugin:myinfo =
{
name = "Automatic Campaign Switcher (ACS)",
author = "Chris Pringle, el_psycho",
description = "Automatically switches to the next campaign when the previous campaign is over",
version = PLUGIN_VERSION,
url = "http://forums.allied...d.php?t=156392"
}
/*======================================================================================
################# O N P L U G I N S T A R T #################
======================================================================================*/
public OnPluginStart()
{
//Get the strings for all of the maps that are in rotation
SetupMapStrings();
//Create custom console variables
CreateConVar("acs_version", PLUGIN_VERSION, "Version of Automatic Campaign Switcher (ACS) on this server", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY|FCVAR_DONTRECORD);
g_hCVar_VotingEnabled = CreateConVar("acs_voting_system_enabled", "1", "Enables players to vote for the next map or campaign [0 = DISABLED, 1 = ENABLED]", FCVAR_PLUGIN, true, 0.0, true, 1.0);
g_hCVar_VoteWinnerSoundEnabled = CreateConVar("acs_voting_sound_enabled", "1", "Determines if a sound plays when a new map is winning the vote [0 = DISABLED, 1 = ENABLED]", FCVAR_PLUGIN, true, 0.0, true, 1.0);
g_hCVar_VotingAdMode = CreateConVar("acs_voting_ad_mode", "1", "Sets how to advertise voting at the start of the map [0 = DISABLED, 1 = HINT TEXT, 2 = CHAT TEXT, 3 = OPEN VOTE MENU]\n * Note: This is only displayed once during a finale or scavenge map *", FCVAR_PLUGIN, true, 0.0, true, 3.0);
g_hCVar_VotingAdDelayTime = CreateConVar("acs_voting_ad_delay_time", "5", "Time, in seconds, to wait after a player spawns during a finale or scavenge map starts to advertise voting as defined in acs_voting_ad_mode\n * Note: If the server is up, changing this in the .cfg file takes two map changes before the change takes place *", FCVAR_PLUGIN);
g_hCVar_NextMapAdMode = CreateConVar("acs_next_map_ad_mode", "1", "Sets how the next campaign/map is advertised during a finale or scavenge map [0 = DISABLED, 1 = HINT TEXT, 2 = CHAT TEXT]", FCVAR_PLUGIN, true, 0.0, true, 2.0);
g_hCVar_NextMapAdInterval = CreateConVar("acs_next_map_ad_interval", "180.0", "The time, in seconds, between advertisements for the next campaign/map on finales and scavenge maps", FCVAR_PLUGIN, true, 60.0, false);
g_hCVar_MaxFinaleFailures = CreateConVar("acs_max_coop_finale_failures", "3", "The amount of times the survivors can fail a finale in Coop before it switches to the next campaign [0 = INFINITE FAILURES]", FCVAR_PLUGIN, true, 0.0, false);
g_hCVar_AutoChangeMapMode = CreateConVar("acs_autochangemap", "2", "Determines the mode in which ACS changes to the next campaign or map when the server is empty for a period of time [0 = DISABLED, 1 = NORMAL MAP ROTATION, 2 = FIXED MAP]", FCVAR_PLUGIN);
g_hCVar_AutoChangeMapTime = CreateConVar("acs_autochangemap_time", "10", "Time, in minutes, the server must be empty before ACS changes to next campaign/map", FCVAR_PLUGIN, true, 5.0, false);
g_hCVar_AutoChangeMapFixedMap = CreateConVar("acs_autochangemap_fixedmap", "c1m1_hotel", "Default map to change to once the server has been empty for a period of time specified in acs_autochangemap_time. Used if acs_autochangemap = 2", FCVAR_PLUGIN);
g_hCVar_zdiffculty = CreateConVar("acs_zdifficulty", "", "The Difficulty to change back to after the server has been empty for the time specified. Leave empty to turn off. (values are Easy, Normal, Hard, Impossible)", FCVAR_PLUGIN);
//Hook console variable changes
HookConVarChange(g_hCVar_VotingEnabled, CVarChange_Voting);
HookConVarChange(g_hCVar_VoteWinnerSoundEnabled, CVarChange_NewVoteWinnerSound);
HookConVarChange(g_hCVar_VotingAdMode, CVarChange_VotingAdMode);
HookConVarChange(g_hCVar_VotingAdDelayTime, CVarChange_VotingAdDelayTime);
HookConVarChange(g_hCVar_NextMapAdMode, CVarChange_NewMapAdMode);
HookConVarChange(g_hCVar_NextMapAdInterval, CVarChange_NewMapAdInterval);
HookConVarChange(g_hCVar_MaxFinaleFailures, CVarChange_MaxFinaleFailures);
HookConVarChange(g_hCVar_AutoChangeMapMode, CVarChange_AutoChangeMapMode);
HookConVarChange(g_hCVar_AutoChangeMapTime, CVarChange_AutoChangeMapTime);
HookConVarChange(g_hCVar_AutoChangeMapFixedMap, CVarChange_AutoChangeMapFixedMap);
HookConVarChange(g_hCVar_zdiffculty, CVarChange_zdifficulty);
//Hook the game events
//HookEvent("player_spawn", player_spawn);
//HookEvent("round_start", Event_RoundStart);
//HookEvent("player_left_start_area", Event_PlayerLeftStartArea);
HookEvent("round_end", Event_RoundEnd);
HookEvent("finale_win", Event_FinaleWin);
HookEvent("scavenge_match_finished", Event_ScavengeMapFinished);
HookEvent("player_disconnect", Event_PlayerDisconnect);
//Register custom console commands
RegConsoleCmd("mapvote", MapVote);
RegConsoleCmd("mapvotes", DisplayCurrentVotes);
}
/*======================================================================================
########## C V A R C A L L B A C K F U N C T I O N S ###########
======================================================================================*/
//Callback function for the cvar for voting system
public CVarChange_Voting(Handle:hCVar, const String:strOldValue[], const String:strNewValue[])
{
//If the value was not changed, then do nothing
if(StrEqual(strOldValue, strNewValue) == true)
return;
//If the value was changed, then set it and display a message to the server and players
if (StringToInt(strNewValue) == 1)
{
g_bVotingEnabled = true;
PrintToServer("[ACS] ConVar changed: Voting System ENABLED");
PrintToChatAll("[ACS] ConVar changed: Voting System ENABLED");
}
else
{
g_bVotingEnabled = false;
PrintToServer("[ACS] ConVar changed: Voting System DISABLED");
PrintToChatAll("[ACS] ConVar changed: Voting System DISABLED");
}
}
//Callback function for enabling or disabling the new vote winner sound
public CVarChange_NewVoteWinnerSound(Handle:hCVar, const String:strOldValue[], const String:strNewValue[])
{
//If the value was not changed, then do nothing
if(StrEqual(strOldValue, strNewValue) == true)
return;
//If the value was changed, then set it and display a message to the server and players
if (StringToInt(strNewValue) == 1)
{
g_bVoteWinnerSoundEnabled = true;
PrintToServer("[ACS] ConVar changed: New vote winner sound ENABLED");
PrintToChatAll("[ACS] ConVar changed: New vote winner sound ENABLED");
}
else
{
g_bVoteWinnerSoundEnabled = false;
PrintToServer("[ACS] ConVar changed: New vote winner sound DISABLED");
PrintToChatAll("[ACS] ConVar changed: New vote winner sound DISABLED");
}
}
//Callback function for how the voting system is advertised to the players at the beginning of the round
public CVarChange_VotingAdMode(Handle:hCVar, const String:strOldValue[], const String:strNewValue[])
{
//If the value was not changed, then do nothing
if(StrEqual(strOldValue, strNewValue) == true)
return;
//If the value was changed, then set it and display a message to the server and players
switch(StringToInt(strNewValue))
{
case 0:
{
g_iVotingAdDisplayMode = DISPLAY_MODE_DISABLED;
PrintToServer("[ACS] ConVar changed: Voting display mode: DISABLED");
PrintToChatAll("[ACS] ConVar changed: Voting display mode: DISABLED");
}
case 1:
{
g_iVotingAdDisplayMode = DISPLAY_MODE_HINT;
PrintToServer("[ACS] ConVar changed: Voting display mode: HINT TEXT");
PrintToChatAll("[ACS] ConVar changed: Voting display mode: HINT TEXT");
}
case 2:
{
g_iVotingAdDisplayMode = DISPLAY_MODE_CHAT;
PrintToServer("[ACS] ConVar changed: Voting display mode: CHAT TEXT");
PrintToChatAll("[ACS] ConVar changed: Voting display mode: CHAT TEXT");
}
case 3:
{
g_iVotingAdDisplayMode = DISPLAY_MODE_MENU;
PrintToServer("[ACS] ConVar changed: Voting display mode: OPEN VOTE MENU");
PrintToChatAll("[ACS] ConVar changed: Voting display mode: OPEN VOTE MENU");
}
}
}
//Callback function for the cvar for voting display delay time
public CVarChange_VotingAdDelayTime(Handle:hCVar, const String:strOldValue[], const String:strNewValue[])
{
//If the value was not changed, then do nothing
if(StrEqual(strOldValue, strNewValue) == true)
return;
//Get the new value
new Float:fDelayTime = StringToFloat(strNewValue);
//If the value was changed, then set it and display a message to the server and players
if (fDelayTime > 0.1)
{
g_fVotingAdDelayTime = fDelayTime;
PrintToServer("[ACS] ConVar changed: Voting advertisement delay time changed to %f", fDelayTime);
PrintToChatAll("[ACS] ConVar changed: Voting advertisement delay time changed to %f", fDelayTime);
}
else
{
g_fVotingAdDelayTime = 0.1;
PrintToServer("[ACS] ConVar changed: Voting advertisement delay time changed to 0.1");
PrintToChatAll("[ACS] ConVar changed: Voting advertisement delay time changed to 0.1");
}
}
//Callback function for how ACS and the next map is advertised to the players during a finale
public CVarChange_NewMapAdMode(Handle:hCVar, const String:strOldValue[], const String:strNewValue[])
{
//If the value was not changed, then do nothing
if(StrEqual(strOldValue, strNewValue) == true)
return;
//If the value was changed, then set it and display a message to the server and players
switch(StringToInt(strNewValue))
{
case 0:
{
g_iNextMapAdDisplayMode = DISPLAY_MODE_DISABLED;
PrintToServer("[ACS] ConVar changed: Next map advertisement display mode: DISABLED");
PrintToChatAll("[ACS] ConVar changed: Next map advertisement display mode: DISABLED");
}
case 1:
{
g_iNextMapAdDisplayMode = DISPLAY_MODE_HINT;
PrintToServer("[ACS] ConVar changed: Next map advertisement display mode: HINT TEXT");
PrintToChatAll("[ACS] ConVar changed: Next map advertisement display mode: HINT TEXT");
}
case 2:
{
g_iNextMapAdDisplayMode = DISPLAY_MODE_CHAT;
PrintToServer("[ACS] ConVar changed: Next map advertisement display mode: CHAT TEXT");
PrintToChatAll("[ACS] ConVar changed: Next map advertisement display mode: CHAT TEXT");
}
}
}
//Callback function for the interval that controls the timer that advertises ACS and the next map
public CVarChange_NewMapAdInterval(Handle:hCVar, const String:strOldValue[], const String:strNewValue[])
{
//If the value was not changed, then do nothing
if(StrEqual(strOldValue, strNewValue) == true)
return;
//Get the new value
new Float:fDelayTime = StringToFloat(strNewValue);
//If the value was changed, then set it and display a message to the server and players
if (fDelayTime > 60.0)
{
g_fNextMapAdInterval = fDelayTime;
PrintToServer("[ACS] ConVar changed: Next map advertisement interval changed to %f", fDelayTime);
PrintToChatAll("[ACS] ConVar changed: Next map advertisement interval changed to %f", fDelayTime);
}
else
{
g_fNextMapAdInterval = 60.0;
PrintToServer("[ACS] ConVar changed: Next map advertisement interval changed to 60.0");
PrintToChatAll("[ACS] ConVar changed: Next map advertisement interval changed to 60.0");
}
}
//Callback function for the amount of times the survivors can fail a coop finale map before ACS switches
public CVarChange_MaxFinaleFailures(Handle:hCVar, const String:strOldValue[], const String:strNewValue[])
{
//If the value was not changed, then do nothing
if(StrEqual(strOldValue, strNewValue) == true)
return;
//Get the new value
new iMaxFailures = StringToInt(strNewValue);
//If the value was changed, then set it and display a message to the server and players
if (iMaxFailures > 0)
{
g_iMaxCoopFinaleFailures = iMaxFailures;
PrintToServer("[ACS] ConVar changed: Max Coop finale failures changed to %f", iMaxFailures);
PrintToChatAll("[ACS] ConVar changed: Max Coop finale failures changed to %f", iMaxFailures);
}
else
{
g_iMaxCoopFinaleFailures = 0;
PrintToServer("[ACS] ConVar changed: Max Coop finale failures changed to 0");
PrintToChatAll("[ACS] ConVar changed: Max Coop finale failures changed to 0");
}
}
//Callback function for how ACS Changes campaign/map when the server is empty
public CVarChange_AutoChangeMapMode(Handle:hCVar, const String:strOldValue[], const String:strNewValue[])
{
//If the value was not changed, then do nothing
if(StrEqual(strOldValue, strNewValue) == true)
return;
//If the value was changed, then set it and display a message to the server and players
switch(StringToInt(strNewValue))
{
case 0:
{
g_iAutoChangeMapMode = AUTOCHANGEMAP_MODE_DISABLED;
PrintToServer("[ACS] ConVar changed: Auto Change campaign/map when server empty mode: DISABLED");
PrintToChatAll("[ACS] ConVar changed: Auto Change campaign/map when server empty mode: DISABLED");
}
case 1:
{
g_iAutoChangeMapMode = AUTOCHANGEMAP_MODE_ROTATION;
PrintToServer("[ACS] ConVar changed: Auto Change campaign/map when server empty mode: CAMPAIGN/MAP ROTATION");
PrintToChatAll("[ACS] ConVar changed: Auto Change campaign/map when server empty mode: CAMPAIGN/MAP ROTATION");
}
case 2:
{
g_iAutoChangeMapMode = AUTOCHANGEMAP_MODE_FIXED;
PrintToServer("[ACS] ConVar changed: Auto Change campaign/map when server empty mode: FIXED MAP");
PrintToChatAll("[ACS] ConVar changed: Auto Change campaign/map when server empty mode: FIXED MAP");
}
}
}
//Callback function for the interval that controls the automatic campaign/map change when the server is empty
public CVarChange_AutoChangeMapTime(Handle:hCVar, const String:strOldValue[], const String:strNewValue[])
{
//If the value was not changed, then do nothing
if(StrEqual(strOldValue, strNewValue) == true)
return;
//Get the new value
new iAutoChangeTime = StringToInt(strNewValue);
//If the value was changed, then set it and display a message to the server and players
if (iAutoChangeTime > 5)
{
g_iAutoChangeMapTime = iAutoChangeTime;
PrintToServer("[ACS] ConVar changed: Interval to change campaign/map when server is empty changed to %i minutes", iAutoChangeTime);
PrintToChatAll("[ACS] ConVar changed: Interval to change campaign/map when server is empty changed to %i minutes", iAutoChangeTime);
}
else
{
g_iAutoChangeMapTime = 5;
PrintToServer("[ACS] ConVar changed: Interval to change campaign/map when server is empty changed to 5 minutes");
PrintToChatAll("[ACS] ConVar changed: Interval to change campaign/map when server is empty changed to 5 minutes");
}
}
//Callback function for the interval that controls the automatic campaign/map change when the server is empty
public CVarChange_AutoChangeMapFixedMap(Handle:hCVar, const String:strOldValue[], const String:strNewValue[])
{
//If the value was not changed, then do nothing
if(StrEqual(strOldValue, strNewValue) == true)
return;
//If the value was changed, then set it and display a message to the server and players
else
{
new String:fixedmapstr[32];
strcopy(fixedmapstr, sizeof(fixedmapstr), strNewValue);
g_strAutoChangeMapFixedMap = fixedmapstr;
PrintToServer("[ACS] ConVar changed: The Default map to switch to when server is empty changed to %s", fixedmapstr);
PrintToChatAll("[ACS] ConVar changed: The Default map to switch to when server is empty changed to %s", fixedmapstr);
}
}
//Callback function for the difficulty to chagne back to if the server has been empty for a period of time.
public CVarChange_zdifficulty(Handle:hCVar, const String:strOldValue[], const String:strNewValue[])
{
//If the value was not changed, then do nothing
if(StrEqual(strOldValue, strNewValue) == true)
return;
//If the value was changed, then set it and display a message to the server and players
else
{
new String:zdiff[12];
strcopy(zdiff, sizeof(zdiff), strNewValue);
g_zdiff = zdiff;
PrintToServer("[ACS] ConVar changed: The difficulty to switch to when server is empty changed to %s", zdiff);
PrintToChatAll("[ACS] ConVar changed: The difficulty to switch to when server is empty changed to %s", zdiff);
}
}
/*======================================================================================
################# E V E N T S #################
======================================================================================*/
public OnMapStart()
{
//Execute config file
decl String:strFileName[64];
Format(strFileName, sizeof(strFileName), "Automatic_Campaign_Switcher");
AutoExecConfig(false, strFileName);
//Set all the menu handles to invalid
CleanUpMenuHandles();
//Set the game mode
FindGameMode();
//Precache sounds
PrecacheSound(SOUND_NEW_VOTE_START);
PrecacheSound(SOUND_NEW_VOTE_WINNER);
//Display advertising for the next campaign or map
if(g_iNextMapAdDisplayMode != DISPLAY_MODE_DISABLED)
CreateTimer(g_fNextMapAdInterval, Timer_AdvertiseNextMap, _, TIMER_FLAG_NO_MAPCHANGE);
g_iRoundEndCounter = 0; //Reset the round end counter on every map start
g_iCoopFinaleFailureCount = 0; //Reset the amount of Survivor failures
g_bFinaleWon = false; //Reset the finale won variable
ResetAllVotes(); //Reset every player's vote
}
//Event fired when a player is fully in game
public OnClientPostAdminCheck(iClient)
{
if(IsClientInGame(iClient) && !IsFakeClient(iClient))
{
if(g_bVotingEnabled == true && OnFinaleOrScavengeMap() == true)
CreateTimer(g_fVotingAdDelayTime, Timer_DisplayVoteAdToAll, _, TIMER_FLAG_NO_MAPCHANGE);
}
}
//Event fired when the Round Ends
public Action:Event_RoundEnd(Handle:hEvent, const String:strName[], bool:bDontBroadcast)
{
//Check to see if on a finale map, if so change to the next campaign after two rounds
if(g_iGameMode == GAMEMODE_VERSUS && OnFinaleOrScavengeMap() == true)
{
g_iRoundEndCounter++;
if(g_iRoundEndCounter >= 4) //This event must be fired on the fourth time Round End occurs.
CheckMapForChange(); //This is because it fires twice during each round end for
//some strange reason, and versus has two rounds in it.
}
//If in Coop and on a finale, check to see if the surviors have lost the max amount of times
else if(g_iGameMode == GAMEMODE_COOP && OnFinaleOrScavengeMap() == true &&
g_iMaxCoopFinaleFailures > 0 && g_bFinaleWon == false &&
++g_iCoopFinaleFailureCount >= g_iMaxCoopFinaleFailures)
{
CheckMapForChange();
}
return Plugin_Continue;
}
//Event fired when a finale is won
public Action:Event_FinaleWin(Handle:hEvent, const String:strName[], bool:bDontBroadcast)
{
g_bFinaleWon = true; //This is used so that the finale does not switch twice if this event
//happens to land on a max failure count as well as this
//Change to the next campaign
if(g_iGameMode == GAMEMODE_COOP)
CheckMapForChange();
return Plugin_Continue;
}
//Event fired when a map is finished for scavenge
public Action:Event_ScavengeMapFinished(Handle:hEvent, const String:strName[], bool:bDontBroadcast)
{
//Change to the next Scavenge map
if(g_iGameMode == GAMEMODE_SCAVENGE)
ChangeScavengeMap();
return Plugin_Continue;
}
//Event fired when a player disconnects from the server
public Action:Event_PlayerDisconnect(Handle:hEvent, const String:strName[], bool:bDontBroadcast)
{
new iClient = GetClientOfUserId(GetEventInt(hEvent, "userid"));
if(iClient < 1)
return Plugin_Continue;
//Reset the client's votes
g_bClientVoted[iClient] = false;
g_iClientVote[iClient] = -1;
//Check to see if there is a new vote winner
SetTheCurrentVoteWinner();
return Plugin_Continue;
}
/*======================================================================================
################# F I N D G A M E M O D E #################
======================================================================================*/
//Find the current gamemode and store it into this plugin
FindGameMode()
{
//Get the gamemode string from the game
decl String:strGameMode[20];
GetConVarString(FindConVar("mp_gamemode"), strGameMode, sizeof(strGameMode));
//Set the global gamemode int for this plugin
if(StrEqual(strGameMode, "coop"))
g_iGameMode = GAMEMODE_COOP;
else if(StrEqual(strGameMode, "realism"))
g_iGameMode = GAMEMODE_COOP;
else if(StrEqual(strGameMode,"versus"))
g_iGameMode = GAMEMODE_VERSUS;
else if(StrEqual(strGameMode, "teamversus"))
g_iGameMode = GAMEMODE_VERSUS;
else if(StrEqual(strGameMode, "scavenge"))
g_iGameMode = GAMEMODE_SCAVENGE;
else if(StrEqual(strGameMode, "teamscavenge"))
g_iGameMode = GAMEMODE_SCAVENGE;
else if(StrEqual(strGameMode, "survival"))
g_iGameMode = GAMEMODE_SURVIVAL;
else if(StrEqual(strGameMode, "mutation1")) //Last Man On Earth
g_iGameMode = GAMEMODE_COOP;
else if(StrEqual(strGameMode, "mutation2")) //Headshot!
g_iGameMode = GAMEMODE_COOP;
else if(StrEqual(strGameMode, "mutation3")) //Bleed Out
g_iGameMode = GAMEMODE_COOP;
else if(StrEqual(strGameMode, "mutation4")) //Hard Eight
g_iGameMode = GAMEMODE_COOP;
else if(StrEqual(strGameMode, "mutation5")) //Four Swordsmen
g_iGameMode = GAMEMODE_COOP;
//else if(StrEqual(strGameMode, "mutation6")) //Nothing here
// g_iGameMode = GAMEMODE_COOP;
else if(StrEqual(strGameMode, "mutation7")) //Chainsaw Massacre
g_iGameMode = GAMEMODE_COOP;
else if(StrEqual(strGameMode, "mutation8")) //Ironman
g_iGameMode = GAMEMODE_COOP;
else if(StrEqual(strGameMode, "mutation9")) //Last Gnome On Earth
g_iGameMode = GAMEMODE_COOP;
else if(StrEqual(strGameMode, "mutation10")) //Room For One
g_iGameMode = GAMEMODE_COOP;
else if(StrEqual(strGameMode, "mutation11")) //Healthpackalypse!
g_iGameMode = GAMEMODE_VERSUS;
else if(StrEqual(strGameMode, "mutation12")) //Realism Versus
g_iGameMode = GAMEMODE_VERSUS;
else if(StrEqual(strGameMode, "mutation13")) //Follow the Liter
g_iGameMode = GAMEMODE_SCAVENGE;
else if(StrEqual(strGameMode, "mutation14")) //Gib Fest
g_iGameMode = GAMEMODE_COOP;
else if(StrEqual(strGameMode, "mutation15")) //Versus Survival
g_iGameMode = GAMEMODE_SURVIVAL;
else if(StrEqual(strGameMode, "mutation16")) //Hunting Party
g_iGameMode = GAMEMODE_COOP;
else if(StrEqual(strGameMode, "mutation17")) //Lone Gunman
g_iGameMode = GAMEMODE_COOP;
else if(StrEqual(strGameMode, "mutation18")) //Bleed Out Versus
g_iGameMode = GAMEMODE_VERSUS;
else if(StrEqual(strGameMode, "mutation19")) //Taaannnkk!
g_iGameMode = GAMEMODE_VERSUS;
else if(StrEqual(strGameMode, "mutation20")) //Healing Gnome
g_iGameMode = GAMEMODE_COOP;
else if(StrEqual(strGameMode, "community1")) //Special Delivery
g_iGameMode = GAMEMODE_COOP;
else if(StrEqual(strGameMode, "community2")) //Flu Season
g_iGameMode = GAMEMODE_COOP;
else if(StrEqual(strGameMode, "community3")) //Riding My Survivor
g_iGameMode = GAMEMODE_VERSUS;
else if(StrEqual(strGameMode, "community4")) //Nightmare
g_iGameMode = GAMEMODE_SURVIVAL;
else if(StrEqual(strGameMode, "community5")) //Death's Door
g_iGameMode = GAMEMODE_COOP;
else
g_iGameMode = GAMEMODE_UNKNOWN;
}
/*======================================================================================
################# A C S C H A N G E M A P #################
======================================================================================*/
//Check to see if the current map is a finale, and if so, switch to the next campaign
CheckMapForChange()
{
decl String:strCurrentMap[32];
GetCurrentMap(strCurrentMap,32); //Get the current map from the game
for(new iMapIndex = 0; iMapIndex < NUMBER_OF_CAMPAIGNS; iMapIndex++)
{
if(StrEqual(strCurrentMap, g_strCampaignLastMap[iMapIndex]) == true)
{
//Check to see if someone voted for a campaign, if so, then change to the winning campaign
if(g_bVotingEnabled == true && g_iWinningMapVotes > 0 && g_iWinningMapIndex >= 0)
{
if(IsMapValid(g_strCampaignFirstMap[g_iWinningMapIndex]) == true)
{
PrintToChatAll("\x04[ACS] \x05Следующая кампания выбрана голосованием: \x04%s", g_strCampaignName[g_iWinningMapIndex]);
if(g_iGameMode == GAMEMODE_VERSUS)
CreateTimer(WAIT_TIME_BEFORE_SWITCH_VERSUS, Timer_ChangeCampaign, g_iWinningMapIndex);
else if(g_iGameMode == GAMEMODE_COOP)
CreateTimer(WAIT_TIME_BEFORE_SWITCH_COOP, Timer_ChangeCampaign, g_iWinningMapIndex);
return;
}
else
LogError("Error: %s is an invalid map name, attempting normal map rotation.", g_strCampaignFirstMap[g_iWinningMapIndex]);
}
//If no map was chosen in the vote, then go with the automatic map rotation
if(iMapIndex == NUMBER_OF_CAMPAIGNS - 1) //Check to see if its the end of the array
iMapIndex = -1; //If so, start the array over by setting to -1 + 1 = 0
if(IsMapValid(g_strCampaignFirstMap[iMapIndex + 1]) == true)
{
PrintToChatAll("\x04[ACS] \x05Смена на кампанию: \x04%s", g_strCampaignName[iMapIndex + 1]);
if(g_iGameMode == GAMEMODE_VERSUS)
CreateTimer(WAIT_TIME_BEFORE_SWITCH_VERSUS, Timer_ChangeCampaign, iMapIndex + 1);
else if(g_iGameMode == GAMEMODE_COOP)
CreateTimer(WAIT_TIME_BEFORE_SWITCH_COOP, Timer_ChangeCampaign, iMapIndex + 1);
}
else
LogError("Error: %s is an invalid map name, unable to switch map.", g_strCampaignFirstMap[iMapIndex + 1]);
return;
}
}
}
//Change to the next scavenge map
ChangeScavengeMap()
{
//Check to see if someone voted for a map, if so, then change to the winning map
if(g_bVotingEnabled == true && g_iWinningMapVotes > 0 && g_iWinningMapIndex >= 0)
{
if(IsMapValid(g_strScavengeMap[g_iWinningMapIndex]) == true)
{
PrintToChatAll("\x03[ACS] \x01Switching map to the winning vote: \x04%s", g_strScavengeMapName[g_iWinningMapIndex]);
CreateTimer(WAIT_TIME_BEFORE_SWITCH_SCAVENGE, Timer_ChangeScavengeMap, g_iWinningMapIndex);
return;
}
else
LogError("Error: %s is an invalid map name, attempting normal map rotation.", g_strScavengeMap[g_iWinningMapIndex]);
}
//If no map was chosen in the vote, then go with the automatic map rotation
decl String:strCurrentMap[32];
GetCurrentMap(strCurrentMap, 32); //Get the current map from the game
//Go through all maps and to find which map index it is on, and then switch to the next map
for(new iMapIndex = 0; iMapIndex < NUMBER_OF_SCAVENGE_MAPS; iMapIndex++)
{
if(StrEqual(strCurrentMap, g_strScavengeMap[iMapIndex]) == true)
{
if(iMapIndex == NUMBER_OF_SCAVENGE_MAPS - 1)//Check to see if its the end of the array
iMapIndex = -1; //If so, start the array over by setting to -1 + 1 = 0
//Make sure the map is valid before changing and displaying the message
if(IsMapValid(g_strScavengeMap[iMapIndex + 1]) == true)
{
PrintToChatAll("\x03[ACS] \x01Switching map to the winning vote: \x04%s", g_strScavengeMapName[iMapIndex + 1]);
CreateTimer(WAIT_TIME_BEFORE_SWITCH_SCAVENGE, Timer_ChangeScavengeMap, iMapIndex + 1);
}
else
LogError("Error: %s is an invalid map name, unable to switch map.", g_strScavengeMap[iMapIndex + 1]);
return;
}
}
}
//Change campaign to its index
public Action:Timer_ChangeCampaign(Handle:timer, any:iCampaignIndex)
{
ServerCommand("changelevel %s", g_strCampaignFirstMap[iCampaignIndex]); //Change the campaign
return Plugin_Stop;
}
//Change scavenge map to its index
public Action:Timer_ChangeScavengeMap(Handle:timer, any:iMapIndex)
{
ServerCommand("changelevel %s", g_strScavengeMap[iMapIndex]); //Change the map
return Plugin_Stop;
}
/*======================================================================================
########## ACS EMPTY SERVER AUTOMATIC CAMPAIGN/MAP CHANGE ###########
======================================================================================*/
public OnConfigsExecuted()
{
if(g_iAutoChangeMapMode != AUTOCHANGEMAP_MODE_DISABLED)
{
g_iMinutesServerEmpty = 0;
CreateTimer(60.0, Timer_CheckPlayerCount, _, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
}
}
public Action:Timer_CheckPlayerCount(Handle:timer)
{
new players = 0;
for (new i = 1; i <= MaxClients; i++)
{
if ((IsClientConnected(i) && !IsFakeClient(i)))
players++;
}
if (players == 0)
g_iMinutesServerEmpty++;
else
{
g_iMinutesServerEmpty = 0;
}
if (g_iMinutesServerEmpty >= g_iAutoChangeMapTime)
{
if(!StrEqual(g_zdiff, ""))
ServerCommand("z_difficulty %s", g_zdiff); //Change difficulty back to our preferred one
decl String:strCurrentMap[32];
GetCurrentMap(strCurrentMap, 32); //Get the current map from the game
if(g_iAutoChangeMapMode == AUTOCHANGEMAP_MODE_FIXED)
{
if(IsMapValid(g_strAutoChangeMapFixedMap) == true)
{
if(StrEqual(strCurrentMap, g_strAutoChangeMapFixedMap) == false)
ServerCommand("changelevel %s", g_strAutoChangeMapFixedMap); //Change to the fixed map unless we are already there
}
else
{
LogError("Error: %s is an invalid map name, unable to switch map.", g_strAutoChangeMapFixedMap);
}
}
else if(g_iAutoChangeMapMode == AUTOCHANGEMAP_MODE_ROTATION)
{
if(g_iGameMode == GAMEMODE_SCAVENGE)
{
new LastSM = NUMBER_OF_SCAVENGE_MAPS - 1; //last scavenge map's array number
//Check to see if this is the end of the array
if(StrEqual(strCurrentMap, g_strScavengeMap[LastSM]) == true)
{
if(IsMapValid(g_strScavengeMap[0]) == true)
{
PrintToServer("[ACS] Switching map to %s", g_strScavengeMap[0]);
CreateTimer(0.5, Timer_ChangeCampaign, 0);
}
else
{
LogError("Error: %s is an invalid map name, unable to switch map.", g_strScavengeMap[0]);
}
}
//Go through all maps and to find which map index it is on, and then switch to the next map
else for(new iMapIndex = 0; iMapIndex < NUMBER_OF_SCAVENGE_MAPS; iMapIndex++)
{
if(StrEqual(strCurrentMap, g_strScavengeMap[iMapIndex]) == true)
{
//Make sure the map is valid before changing and displaying the message
if(IsMapValid(g_strScavengeMap[iMapIndex + 1]) == true)
{
PrintToServer("[ACS] Switching map to %s", g_strScavengeMap[iMapIndex + 1]);
CreateTimer(0.5, Timer_ChangeScavengeMap, iMapIndex + 1);
}
else
{
LogError("Error: %s is an invalid map name, unable to switch map.", g_strScavengeMap[iMapIndex + 1]);
}
}
}
}
else
{
new LastCM = NUMBER_OF_CAMPAIGNS - 1; //last g_strCampaignFirstMap array number
//Check to see if this is the end of the array
if(StrEqual(strCurrentMap, g_strCampaignFirstMap[LastCM]) == true)
{
if(IsMapValid(g_strCampaignFirstMap[0]) == true)
{
PrintToServer("[ACS] Switching map to %s", g_strCampaignFirstMap[0]);
CreateTimer(0.5, Timer_ChangeCampaign, 0);
}
else
{
LogError("Error: %s is an invalid map name, unable to switch map.", g_strCampaignFirstMap[0]);
}
}
//Go through all maps and to find which map index it is on, and then switch to the next map
else for(new iMapIndex = 0; iMapIndex < NUMBER_OF_CAMPAIGNS; iMapIndex++)
{
if(StrEqual(strCurrentMap, g_strCampaignFirstMap[iMapIndex]) == true)
{
//Make sure the map is valid before changing and displaying the message
if(IsMapValid(g_strCampaignFirstMap[iMapIndex + 1]) == true)
{
PrintToServer("[ACS] Switching map to %s", g_strCampaignFirstMap[iMapIndex + 1]);
CreateTimer(0.5, Timer_ChangeCampaign, iMapIndex + 1);
}
else
{
LogError("Error: %s is an invalid map name, unable to switch map.", g_strCampaignFirstMap[iMapIndex + 1]);
}
}
}
}
}
}
return Plugin_Continue;
}
/*======================================================================================
################# A C S A D V E R T I S I N G #################
======================================================================================*/
public Action:Timer_AdvertiseNextMap(Handle:timer, any:iMapIndex)
{
//If next map advertising is enabled, display the text and start the timer again
if(g_iNextMapAdDisplayMode != DISPLAY_MODE_DISABLED)
{
DisplayNextMapToAll();
CreateTimer(g_fNextMapAdInterval, Timer_AdvertiseNextMap, _, TIMER_FLAG_NO_MAPCHANGE);
}
return Plugin_Stop;
}
DisplayNextMapToAll()
{
//If there is a winner to the vote display the winner if not display the next map in rotation
if(g_iWinningMapIndex >= 0)
{
if(g_iNextMapAdDisplayMode == DISPLAY_MODE_HINT)
{
//Display the map that is currently winning the vote to all the players using hint text
if(g_iGameMode == GAMEMODE_SCAVENGE)
PrintHintTextToAll("Следующая карта %s", g_strScavengeMapName[g_iWinningMapIndex]);
else
PrintHintTextToAll("Следующая кампания %s", g_strCampaignName[g_iWinningMapIndex]);
}
else if(g_iNextMapAdDisplayMode == DISPLAY_MODE_CHAT)
{
//Display the map that is currently winning the vote to all the players using chat text
if(g_iGameMode == GAMEMODE_SCAVENGE)
PrintToChatAll("\x04[ACS] \x05Следующая карта \x04%s", g_strScavengeMapName[g_iWinningMapIndex]);
else
PrintToChatAll("\x04[ACS] \x05Следующая кампания \x04%s", g_strCampaignName[g_iWinningMapIndex]);
}
}
else
{
decl String:strCurrentMap[32];
GetCurrentMap(strCurrentMap, 32); //Get the current map from the game
if(g_iGameMode == GAMEMODE_SCAVENGE)
{
new LastSM = NUMBER_OF_SCAVENGE_MAPS - 1; //last scavenge map's array number
//Check to see if this is the last scavenge map in the array
if(StrEqual(strCurrentMap, g_strScavengeMap[LastSM]) == true)
{
//Display the next map in the rotation in the appropriate way
if(g_iNextMapAdDisplayMode == DISPLAY_MODE_HINT)
PrintHintTextToAll("Следующая карта %s", g_strScavengeMapName[0]);
else if(g_iNextMapAdDisplayMode == DISPLAY_MODE_CHAT)
PrintToChatAll("\x04[ACS] \x05Следующая карта \x04%s", g_strScavengeMapName[0]);
}
else
{
//Go through all maps and to find which map index it is on, and then switch to the next map
for(new iMapIndex = 0; iMapIndex < NUMBER_OF_SCAVENGE_MAPS; iMapIndex++)
{
if(StrEqual(strCurrentMap, g_strScavengeMap[iMapIndex]) == true)
{
//Display the next map in the rotation in the appropriate way
if(g_iNextMapAdDisplayMode == DISPLAY_MODE_HINT)
PrintHintTextToAll("Следующая кампания %s", g_strScavengeMapName[iMapIndex + 1]);
else if(g_iNextMapAdDisplayMode == DISPLAY_MODE_CHAT)
PrintToChatAll("\x04[ACS] \x05Следующая кампания \x04%s", g_strScavengeMapName[iMapIndex + 1]);
}
}
}
}
else
{
new LastCM = NUMBER_OF_CAMPAIGNS - 1; //last map in last campaign's array number
//Check to see if this is the end of the array
if(StrEqual(strCurrentMap, g_strCampaignLastMap[LastCM]) == true)
{
//Display the next map in the rotation in the appropriate way
if(g_iNextMapAdDisplayMode == DISPLAY_MODE_HINT)
PrintHintTextToAll("Следующая кампания %s", g_strCampaignName[0]);
else if(g_iNextMapAdDisplayMode == DISPLAY_MODE_CHAT)
PrintToChatAll("\x04[ACS] \x05Следующая кампания \x04%s", g_strCampaignName[0]);
}
else
{
//Go through all maps and to find which map index it is on, and then switch to the next map
for(new iMapIndex = 0; iMapIndex < NUMBER_OF_CAMPAIGNS; iMapIndex++)
{
if(StrEqual(strCurrentMap, g_strCampaignLastMap[iMapIndex]) == true)
{
//Display the next map in the rotation in the appropriate way
if(g_iNextMapAdDisplayMode == DISPLAY_MODE_HINT)
PrintHintTextToAll("Следующая кампания %s", g_strCampaignName[iMapIndex + 1]);
else if(g_iNextMapAdDisplayMode == DISPLAY_MODE_CHAT)
PrintToChatAll("\x04[ACS] \x05Следующая кампания \x04%s", g_strCampaignName[iMapIndex + 1]);
}
}
}
}
}
}
/*======================================================================================
################# V O T I N G S Y S T E M #################
======================================================================================*/
/*======================================================================================
################ P L A Y E R C O M M A N D S ################
======================================================================================*/
//Command that a player can use to vote/revote for a map/campaign
public Action:MapVote(iClient, args)
{
if(g_bVotingEnabled == false)
{
PrintToChat(iClient, "\x04[ACS] \x05Голосование отключено на этом сервере.");
return;
}
if(OnFinaleOrScavengeMap() == false)
{
PrintToChat(iClient, "\x04[ACS] \x05Голосование включается только в финале.");
return;
}
//Open the vote menu for the client if they arent using the server console
if(iClient < 1)
PrintToServer("You cannot vote for a map from the server console, use the in-game chat");
else
VoteMenuDraw(iClient);
}
//Command that a player can use to see the total votes for all maps/campaigns
public Action:DisplayCurrentVotes(iClient, args)
{
if(g_bVotingEnabled == false)
{
PrintToChat(iClient, "\x04[ACS] \x05Голосование отключено на этом сервере.");
return;
}
if(OnFinaleOrScavengeMap() == false)
{
PrintToChat(iClient, "\x04[ACS] \x05Голосование включается только в финале.");
return;
}
decl iPlayer, iMap, iNumberOfMaps;
//Get the total number of maps for the current game mode
if(g_iGameMode == GAMEMODE_SCAVENGE)
iNumberOfMaps = NUMBER_OF_SCAVENGE_MAPS;
else
iNumberOfMaps = NUMBER_OF_CAMPAIGNS;
//Display to the client the current winning map
if(g_iWinningMapIndex != -1)
{
if(g_iGameMode == GAMEMODE_SCAVENGE)
PrintToChat(iClient, "\x04[ACS] \x05Большинство голосов за: \x04%s", g_strScavengeMapName[g_iWinningMapIndex]);
else
PrintToChat(iClient, "\x04[ACS] \x05Большинство голосов за: \x04%s", g_strCampaignName[g_iWinningMapIndex]);
}
else
PrintToChat(iClient, "\x04[ACS] \x05Никто еще не проголосовал.");
//Loop through all maps and display the ones that have votes
new iMapVotes[iNumberOfMaps];
for(iMap = 0; iMap < iNumberOfMaps; iMap++)
{
iMapVotes[iMap] = 0;
//Tally votes for the current map
for(iPlayer = 1; iPlayer <= MaxClients; iPlayer++)
if(g_iClientVote[iPlayer] == iMap)
iMapVotes[iMap]++;
//Display this particular map and its amount of votes it has to the client
if(iMapVotes[iMap] > 0)
{
if(g_iGameMode == GAMEMODE_SCAVENGE)
PrintToChat(iClient, "\x01 %s: \x05%d votes", g_strScavengeMapName[iMap], iMapVotes[iMap]);
else
PrintToChat(iClient, "\x01 %s: \x05%d votes", g_strCampaignName[iMap], iMapVotes[iMap]);
}
}
}
/*======================================================================================
############### V O T E M E N U ##############
======================================================================================*/
//Timer to show the menu to the players if they have not voted yet
public Action:Timer_DisplayVoteAdToAll(Handle:hTimer, any:iData)
{
if(g_bVotingEnabled == false || OnFinaleOrScavengeMap() == false)
return Plugin_Stop;
for(new iClient = 1;iClient <= MaxClients; iClient++)
{
if(g_bClientShownVoteAd[iClient] == false && g_bClientVoted[iClient] == false && IsClientInGame(iClient) == true && IsFakeClient(iClient) == false)
{
switch(g_iVotingAdDisplayMode)
{
case DISPLAY_MODE_MENU: VoteMenuDraw(iClient);
case DISPLAY_MODE_HINT: PrintHintText(iClient, "При уходе со сторонней карты, переключи на стоковую!");
case DISPLAY_MODE_CHAT: PrintToChat(iClient, "\x04[ACS] \x05Что бы проголосовать за следующую кампанию напиши: \x04!mv\n \x05Посмотреть статус голосования: \x04!mvs");
}
g_bClientShownVoteAd[iClient] = true;
}
}
return Plugin_Stop;
}
//Draw the menu for voting
public Action:VoteMenuDraw(iClient)
{
if(iClient < 1 || IsClientInGame(iClient) == false || IsFakeClient(iClient) == true)
return Plugin_Handled;
//Create the menu
g_hMenu_Vote[iClient] = CreateMenu(VoteMenuHandler);
//Give the player the option of not choosing a map
AddMenuItem(g_hMenu_Vote[iClient], "option1", "Мне всё равно");
//Populate the menu with the maps in rotation for the corresponding game mode
if(g_iGameMode == GAMEMODE_SCAVENGE)
{
SetMenuTitle(g_hMenu_Vote[iClient], "Выбери следующую карту!!!\n ");
for(new iCampaign = 0; iCampaign < NUMBER_OF_SCAVENGE_MAPS; iCampaign++)
AddMenuItem(g_hMenu_Vote[iClient], g_strScavengeMapName[iCampaign], g_strScavengeMapName[iCampaign]);
}
else
{
SetMenuTitle(g_hMenu_Vote[iClient], "Выбери следующую кампанию!!!\n ");
for(new iCampaign = 0; iCampaign < NUMBER_OF_CAMPAIGNS; iCampaign++)
AddMenuItem(g_hMenu_Vote[iClient], g_strCampaignName[iCampaign], g_strCampaignName[iCampaign]);
}
//Add an exit button
SetMenuExitButton(g_hMenu_Vote[iClient], true);
//And finally, show the menu to the client
DisplayMenu(g_hMenu_Vote[iClient], iClient, MENU_TIME_FOREVER);
//Play a sound to indicate that the user can vote on a map
EmitSoundToClient(iClient, SOUND_NEW_VOTE_START);
return Plugin_Handled;
}
//Handle the menu selection the client chose for voting
public VoteMenuHandler(Handle:hMenu, MenuAction:maAction, iClient, iItemNum)
{
if(maAction == MenuAction_Select)
{
g_bClientVoted[iClient] = true;
//Set the players current vote
if(iItemNum == 0)
g_iClientVote[iClient] = -1;
else
g_iClientVote[iClient] = iItemNum - 1;
//Check to see if theres a new winner to the vote
SetTheCurrentVoteWinner();
//Display the appropriate message to the voter
if(iItemNum == 0)
PrintHintText(iClient, "Вы не голосовали.\nЧтобы проголосовать напиши: !mv");
else if(g_iGameMode == GAMEMODE_SCAVENGE)
PrintHintText(iClient, "Вы проголосовали за %s.\n- Изменить свой голос напиши в чате: !mv\n- Статус голосования: !mvs", g_strScavengeMapName[iItemNum - 1]);
else
PrintHintText(iClient, "Вы проголосовали за %s.\n- Изменить свой голос напиши в чате: !mv\n- Статус голосования: !mvs", g_strCampaignName[iItemNum - 1]);
}
}
//Resets all the menu handles to invalid for every player, until they need it again
CleanUpMenuHandles()
{
for(new iClient = 0; iClient <= MAXPLAYERS; iClient++)
{
if(g_hMenu_Vote[iClient] != INVALID_HANDLE)
{
CloseHandle(g_hMenu_Vote[iClient]);
g_hMenu_Vote[iClient] = INVALID_HANDLE;
}
}
}
/*======================================================================================
######### M I S C E L L A N E O U S V O T E F U N C T I O N S #########
======================================================================================*/
//Resets all the votes for every player
ResetAllVotes()
{
for(new iClient = 1; iClient <= MaxClients; iClient++)
{
g_bClientVoted[iClient] = false;
g_iClientVote[iClient] = -1;
//Reset so that the player can see the advertisement
g_bClientShownVoteAd[iClient] = false;
}
//Reset the winning map to NULL
g_iWinningMapIndex = -1;
g_iWinningMapVotes = 0;
}
//Tally up all the votes and set the current winner
SetTheCurrentVoteWinner()
{
decl iPlayer, iMap, iNumberOfMaps;
//Store the current winnder to see if there is a change
new iOldWinningMapIndex = g_iWinningMapIndex;
//Get the total number of maps for the current game mode
if(g_iGameMode == GAMEMODE_SCAVENGE)
iNumberOfMaps = NUMBER_OF_SCAVENGE_MAPS;
else
iNumberOfMaps = NUMBER_OF_CAMPAIGNS;
//Loop through all maps and get the highest voted map
new iMapVotes[iNumberOfMaps], iCurrentlyWinningMapVoteCounts = 0, bool:bSomeoneHasVoted = false;
for(iMap = 0; iMap < iNumberOfMaps; iMap++)
{
iMapVotes[iMap] = 0;
//Tally votes for the current map
for(iPlayer = 1; iPlayer <= MaxClients; iPlayer++)
if(g_iClientVote[iPlayer] == iMap)
iMapVotes[iMap]++;
//Check if there is at least one vote, if so set the bSomeoneHasVoted to true
if(bSomeoneHasVoted == false && iMapVotes[iMap] > 0)
bSomeoneHasVoted = true;
//Check if the current map has more votes than the currently highest voted map
if(iMapVotes[iMap] > iCurrentlyWinningMapVoteCounts)
{
iCurrentlyWinningMapVoteCounts = iMapVotes[iMap];
g_iWinningMapIndex = iMap;
g_iWinningMapVotes = iMapVotes[iMap];
}
}
//If no one has voted, reset the winning map index and votes
//This is only for if someone votes then their vote is removed
if(bSomeoneHasVoted == false)
{
g_iWinningMapIndex = -1;
g_iWinningMapVotes = 0;
}
//If the vote winner has changed then display the new winner to all the players
if(g_iWinningMapIndex > -1 && iOldWinningMapIndex != g_iWinningMapIndex)
{
//Send sound notification to all players
if(g_bVoteWinnerSoundEnabled == true)
for(iPlayer = 1; iPlayer <= MaxClients; iPlayer++)
if(IsClientInGame(iPlayer) == true && IsFakeClient(iPlayer) == false)
EmitSoundToClient(iPlayer, SOUND_NEW_VOTE_WINNER);
//Show message to all the players of the new vote winner
if(g_iGameMode == GAMEMODE_SCAVENGE)
PrintToChatAll("\x04[ACS] \x04%s \x05выбрана большинством голосов", g_strScavengeMapName[g_iWinningMapIndex]);
else
PrintToChatAll("\x04[ACS] \x04%s \x05выбрана большинством голосов", g_strCampaignName[g_iWinningMapIndex]);
}
}
//Check if the current map is the last in the campaign if not in the Scavenge game mode
bool:OnFinaleOrScavengeMap()
{
if(g_iGameMode == GAMEMODE_SCAVENGE)
return true;
if(g_iGameMode == GAMEMODE_SURVIVAL)
return false;
decl String:strCurrentMap[32];
GetCurrentMap(strCurrentMap,32); //Get the current map from the game
//Run through all the maps, if the current map is a last campaign map, return true
for(new iMapIndex = 0; iMapIndex < NUMBER_OF_CAMPAIGNS; iMapIndex++)
if(StrEqual(strCurrentMap, g_strCampaignLastMap[iMapIndex]) == true)
return true;
return false;
}