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