plugins/nextmap.sp
author Scott Ehlert <ds@alliedmods.net>
Wed Aug 15 06:19:30 2007 +0000 (2007-08-15)
changeset 1330 ab94316bb52b
parent 1187 85c0934305bd
child 1366 c1d3a4831ef9
permissions -rw-r--r--
Updated license headers on virtually all files with extremely minor changes in the name of some sort of strange consistency.
All plugin and include file headers also have been changed to say about GPL3 instead of GPL2.

(This day shall henceforth be known as the Eighty Column Massacre of '07)
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod Nextmap Plugin
     5  * Adds sm_nextmap cvar for changing map and nextmap chat trigger.
     6  *
     7  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     8  * =============================================================================
     9  *
    10  * This program is free software; you can redistribute it and/or modify it under
    11  * the terms of the GNU General Public License, version 3.0, as published by the
    12  * Free Software Foundation.
    13  * 
    14  * This program is distributed in the hope that it will be useful, but WITHOUT
    15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    16  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    17  * details.
    18  *
    19  * You should have received a copy of the GNU General Public License along with
    20  * this program.  If not, see <http://www.gnu.org/licenses/>.
    21  *
    22  * As a special exception, AlliedModders LLC gives you permission to link the
    23  * code of this program (as well as its derivative works) to "Half-Life 2," the
    24  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    25  * by the Valve Corporation.  You must obey the GNU General Public License in
    26  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    27  * this exception to all derivative works.  AlliedModders LLC defines further
    28  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    29  * or <http://www.sourcemod.net/license.php>.
    30  *
    31  * Version: $Id$
    32  */
    33 
    34 #pragma semicolon 1
    35 
    36 #include <sourcemod>
    37  
    38 public Plugin:myinfo = 
    39 {
    40 	name = "Nextmap",
    41 	author = "AlliedModders LLC",
    42 	description = "Provides nextmap and sm_nextmap",
    43 	version = SOURCEMOD_VERSION,
    44 	url = "http://www.sourcemod.net/"
    45 };
    46 
    47 new bool:g_IntermissionCalled;
    48 new UserMsg:g_VGUIMenu;
    49  
    50 new Handle:g_Cvar_Chattime;
    51 new Handle:g_Cvar_Nextmap;
    52 new Handle:g_Cvar_Mapcycle;
    53 
    54 new g_MapPos = -1;
    55 new Handle:g_MapList = INVALID_HANDLE;
    56 
    57 #if 0
    58 new bool:g_INS = false;
    59 #endif
    60  
    61 public OnPluginStart()
    62 {
    63 	LoadTranslations("nextmap.phrases");
    64 	
    65 	g_VGUIMenu = GetUserMessageId("VGUIMenu");
    66 	if (g_VGUIMenu == INVALID_MESSAGE_ID)
    67 	{
    68 		LogMessage("FATAL: Cannot find VGUIMenu user message id. Nextmap not loaded.");
    69 		return;	
    70 	}
    71 	
    72 	g_Cvar_Chattime = FindConVar("mp_chattime");
    73 	g_Cvar_Mapcycle = FindConVar("mapcyclefile");
    74 	
    75 	g_MapList = CreateArray(32);
    76 	
    77 	decl String:mapCycle[64];
    78 	GetConVarString(g_Cvar_Mapcycle, mapCycle, 64);
    79 	if (LoadMaps(mapCycle) == 0)
    80 	{
    81 		LogMessage("FATAL: Cannot load map cycle. Nextmap not loaded.");
    82 		return;
    83 	}	
    84 	
    85 	HookUserMessage(g_VGUIMenu, UserMsg_VGUIMenu);
    86 	HookConVarChange(g_Cvar_Mapcycle, ConVarChange_Mapcyclefile);
    87 	
    88 	g_Cvar_Nextmap = CreateConVar("sm_nextmap", "", "Sets the Next Map", FCVAR_NOTIFY);
    89 	
    90 	RegConsoleCmd("say", Command_Say);
    91 	RegConsoleCmd("say_team", Command_Say);
    92 	
    93 	#if 0
    94 	decl String:modname[64];
    95 	GetGameFolderName(modname, sizeof(modname));
    96 	
    97 	if (strcmp(modname, "ins") == 0)
    98 	{
    99 		RegConsoleCmd("say2", Command_SayChat);
   100 		g_INS = true;
   101 	}
   102 	#endif
   103 
   104 	RegConsoleCmd("listmaps", Command_List);
   105 	
   106 	/* Set to the current map so OnMapStart() will know what to do */
   107 	decl String:currentMap[64];
   108 	GetCurrentMap(currentMap, 64);
   109 	SetConVarString(g_Cvar_Nextmap, currentMap);
   110 }
   111  
   112 public OnMapStart()
   113 {
   114 	decl String:lastMap[64], String:currentMap[64];
   115 	GetConVarString(g_Cvar_Nextmap, lastMap, 64);
   116 	GetCurrentMap(currentMap, 64);
   117 	
   118 	// Why am I doing this? If we switched to a new map, but it wasn't what we expected (Due to sm_map, sm_votemap, or
   119 	// some other plugin/command), we don't want to scramble the map cycle. Or for example, admin switches to a custom map
   120 	// not in mapcyclefile. So we keep it set to the last expected nextmap. - ferret
   121 	if (strcmp(lastMap, currentMap) == 0)
   122 	{
   123 		FindAndSetNextMap();
   124 	}
   125 }
   126  
   127 public OnMapEnd()
   128 {
   129 	g_IntermissionCalled = false;
   130 }
   131  
   132 public ConVarChange_Mapcyclefile(Handle:convar, const String:oldValue[], const String:newValue[])
   133 {
   134 	if (strcmp(oldValue, newValue, false) != 0)
   135 	{
   136 		LoadMaps(newValue);
   137 	}
   138 }
   139  
   140 public Action:Command_Say(client, args)
   141 {
   142 	decl String:text[192];
   143 	GetCmdArgString(text, sizeof(text));
   144 	
   145 	new startidx;
   146 	if (text[strlen(text)-1] == '"')
   147 	{
   148 		text[strlen(text)-1] = '\0';
   149 		startidx = 1;
   150 	}
   151 	
   152 	#if 0
   153 	if (g_INS)
   154 	{
   155 		startidx += 4;
   156 	}
   157 	#endif
   158 	
   159 	decl String:message[8];
   160 	BreakString(text[startidx], message, sizeof(message));
   161 	
   162 	if (strcmp(message, "nextmap", false) == 0)
   163 	{
   164 		decl String:map[32];
   165 		GetConVarString(g_Cvar_Nextmap, map, sizeof(map));
   166 		
   167 		PrintToChatAll("%t", "Next Map", map);
   168 	}
   169 	
   170 	return Plugin_Continue;	
   171 }
   172  
   173 public Action:UserMsg_VGUIMenu(UserMsg:msg_id, Handle:bf, const players[], playersNum, bool:reliable, bool:init)
   174 {
   175 	if (g_IntermissionCalled)
   176 	{
   177 		return Plugin_Handled;
   178 	}
   179 	
   180 	decl String:type[15];
   181 	BfReadString(bf, type, sizeof(type));
   182  
   183 	if (BfReadByte(bf) == 1 && BfReadByte(bf) == 0 && (strcmp(type, "scores", false) == 0))
   184 	{
   185 		g_IntermissionCalled = true;
   186 		
   187 		decl String:map[32];
   188 		new Float:fChatTime = GetConVarFloat(g_Cvar_Chattime);
   189 		
   190 		GetConVarString(g_Cvar_Nextmap, map, sizeof(map));
   191 		
   192 		if (fChatTime < 2.0)
   193 			SetConVarFloat(g_Cvar_Chattime, 2.0);
   194 		
   195 		new Handle:dp;
   196 		CreateDataTimer(fChatTime - 1.0, Timer_ChangeMap, dp);
   197 		WritePackString(dp, map);
   198 	}
   199 	
   200 	return Plugin_Handled;
   201 }
   202  
   203 public Action:Timer_ChangeMap(Handle:timer, Handle:dp)
   204 {
   205 	new String:map[32];
   206 	
   207 	ResetPack(dp);
   208 	ReadPackString(dp, map, sizeof(map));
   209  
   210 	InsertServerCommand("changelevel \"%s\"", map);
   211 	ServerExecute();
   212 	
   213 	LogMessage("Nextmap changed map to \"%s\"", map);
   214 	
   215 	return Plugin_Stop;
   216 }
   217  
   218 public Action:Command_List(client, args) 
   219 {
   220 	PrintToConsole(client, "Map Cycle:");
   221 	
   222 	new mapCount = GetArraySize(g_MapList);
   223 	decl String:mapName[32];
   224 	for (new i = 0; i < mapCount; i++)
   225 	{
   226 		GetArrayString(g_MapList, i, mapName, sizeof(mapName));
   227 		PrintToConsole(client, "%s", mapName);
   228 	}
   229  
   230 	return Plugin_Handled;
   231 }
   232  
   233 LoadMaps(const String:path[])
   234 {
   235 	if (!FileExists(path))
   236 	{
   237 		return 0;
   238 	}
   239  
   240 	new Handle:file = OpenFile(path, "r");
   241 	
   242 	if (file == INVALID_HANDLE)
   243 	{
   244 		LogError("[SM] Could not open file: %s", path);
   245 		return 0;
   246 	}
   247 	
   248 	ClearArray(g_MapList);
   249 	g_MapPos = -1;
   250 	
   251 	decl String:buffer[255];
   252 	while (!IsEndOfFile(file) && ReadFileLine(file, buffer, sizeof(buffer)))
   253 	{
   254 		TrimString(buffer);
   255 		if (buffer[0] == '\0' || buffer[0] == ';')
   256 		{
   257 			continue;
   258 		}
   259 		
   260 		if (IsMapValid(buffer))
   261 		{
   262 			PushArrayString(g_MapList, buffer);
   263 		}
   264 	}
   265 	
   266 	CloseHandle(file);
   267 
   268 	return GetArraySize(g_MapList);
   269 }
   270  
   271 FindAndSetNextMap()
   272 {
   273 	new mapCount = GetArraySize(g_MapList);
   274 	decl String:mapName[32];
   275 	
   276 	if (g_MapPos == -1)
   277 	{
   278 		decl String:current[64];
   279 		GetCurrentMap(current, 64);
   280 		
   281 
   282 		for (new i = 0; i < mapCount; i++)
   283 		{
   284 			GetArrayString(g_MapList, i, mapName, sizeof(mapName));
   285 			if (strcmp(current, mapName, false) == 0)
   286 			{
   287 				g_MapPos = i;
   288 				break;
   289 			}
   290 		}
   291 		
   292 		if (g_MapPos == -1)
   293 			g_MapPos = 0;
   294 	}
   295 	
   296 	g_MapPos++;
   297 	if (g_MapPos >= mapCount)
   298 		g_MapPos = 0;	
   299  
   300  	GetArrayString(g_MapList, g_MapPos, mapName, sizeof(mapName));
   301 	SetConVarString(g_Cvar_Nextmap, mapName);
   302 }