plugins/include/helpers.inc
author Michael McKoy <ferret99gt@gmail.com>
Thu Oct 18 01:16:42 2007 +0000 (2007-10-18)
changeset 1606 4fb3959c2c96
parent 1423 e73b3563f254
child 1627 de86e6e12204
permissions -rw-r--r--
Added new stock to helpers.inc: LoadMaps()
Adjusted all plugins that use LoadMaps()
Nextmap no longer worries about mapcyclefile until the map changes
RTV/MC/RC use OnConfigsExecuted() instead of OnMapStart() now
RTV/MC/RC will no longer "permanently" exclude the current map being played when the map file is loaded.
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * =============================================================================
     6  *
     7  * This file is part of the SourceMod/SourcePawn SDK.
     8  *
     9  * This program is free software; you can redistribute it and/or modify it under
    10  * the terms of the GNU General Public License, version 3.0, as published by the
    11  * Free Software Foundation.
    12  * 
    13  * This program is distributed in the hope that it will be useful, but WITHOUT
    14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    15  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    16  * details.
    17  *
    18  * You should have received a copy of the GNU General Public License along with
    19  * this program.  If not, see <http://www.gnu.org/licenses/>.
    20  *
    21  * As a special exception, AlliedModders LLC gives you permission to link the
    22  * code of this program (as well as its derivative works) to "Half-Life 2," the
    23  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    24  * by the Valve Corporation.  You must obey the GNU General Public License in
    25  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    26  * this exception to all derivative works.  AlliedModders LLC defines further
    27  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    28  * or <http://www.sourcemod.net/license.php>.
    29  *
    30  * Version: $Id$
    31  */
    32  
    33 #if defined _helpers_included
    34  #endinput
    35 #endif
    36 #define _helpers_included
    37 
    38 /**
    39  * Formats a user's info as log text.  This is usually not needed because
    40  * %L can be used to auto-format client information into a string.
    41  *
    42  * @param client		Client index.
    43  * @param buffer		Buffer for text.
    44  * @param maxlength		Maximum length of text.
    45  */
    46 stock FormatUserLogText(client, String:buffer[], maxlength)
    47 {
    48 	decl String:auth[32];
    49 	decl String:name[40];
    50 	
    51 	new userid = GetClientUserId(client);
    52 	if (!GetClientAuthString(client, auth, sizeof(auth)))
    53 	{
    54 		strcopy(auth, sizeof(auth), "UNKNOWN");
    55 	}
    56 	if (!GetClientName(client, name, sizeof(name)))
    57 	{
    58 		strcopy(name, sizeof(name), "UNKNOWN");
    59 	}
    60 	
    61 	/** Currently, no team stuff ... */
    62 	
    63 	Format(buffer, maxlength, "\"%s<%d><%s><>\"", name, userid, auth);
    64 }
    65 
    66 /**
    67  * Returns plugin handle from plugin filename.
    68  *
    69  * @param filename		Filename of the plugin to search for.
    70  * @return				Handle to plugin if found, INVALID_HANDLE otherwise.
    71  */
    72 stock Handle:FindPluginByFile(const String:filename[])
    73 {
    74 	decl String:buffer[256];
    75 	
    76 	new Handle:iter = GetPluginIterator();
    77 	new Handle:pl;
    78 	
    79 	while (MorePlugins(iter))
    80 	{
    81 		pl = ReadPlugin(iter);
    82 		
    83 		GetPluginFilename(pl, buffer, sizeof(buffer));
    84 		if (strcmp(buffer, filename, false) == 0)
    85 		{
    86 			CloseHandle(iter);
    87 			return pl;
    88 		}
    89 	}
    90 	
    91 	CloseHandle(iter);
    92 	
    93 	return INVALID_HANDLE;
    94 }
    95 
    96 /**
    97  * Searches for clients that match an input string.
    98  *
    99  * Allowed patterns: 
   100  *  1) #<userid> or #<exact name>
   101  *  2) <partial or full name>
   102  *
   103  * @param pattern		Pattern to search for.
   104  * @param clients		Array to store matching clients in.
   105  * @param maxClients	Maximum clients in the array.
   106  * @return				Number of clients found.
   107  */
   108 stock SearchForClients(const String:pattern[], clients[], maxClients)
   109 {
   110 	new maxclients = GetMaxClients();
   111 	new total = 0;
   112 	
   113 	if (maxClients == 0)
   114 	{
   115 		return 0;
   116 	}
   117 	
   118 	if (pattern[0] == '#')
   119 	{
   120 		new input = StringToInt(pattern[1]);
   121 		if (!input)
   122 		{
   123 			decl String:name[65]
   124 			for (new i=1; i<=maxclients; i++)
   125 			{
   126 				if (!IsClientInGame(i))
   127 				{
   128 					continue;
   129 				}
   130 				GetClientName(i, name, sizeof(name));
   131 				if (strcmp(name, pattern, false) == 0)
   132 				{
   133 					clients[0] = i;
   134 					return 1;
   135 				}
   136 			}
   137 		} else {
   138 			new client = GetClientOfUserId(input);
   139 			if (client)
   140 			{
   141 				clients[0] = client;
   142 				return 1;
   143 			}
   144 		}
   145 	}
   146 	
   147 	decl String:name[65]
   148 	for (new i=1; i<=maxclients; i++)
   149 	{
   150 		if (!IsClientInGame(i))
   151 		{
   152 			continue;
   153 		}
   154 		GetClientName(i, name, sizeof(name));
   155 		if (StrContains(name, pattern, false) != -1)
   156 		{
   157 			clients[total++] = i;
   158 			if (total >= maxClients)
   159 			{
   160 				break;
   161 			}
   162 		}
   163 	}
   164 	
   165 	return total;
   166 }
   167 
   168 /**
   169  * Wraps SearchForClients and handles producing error messages for
   170  * bad targets.
   171  *
   172  * @param client	Client who issued command
   173  * @param target	Client's target argument
   174  * @param nobots	Optional. Set to true if bots should NOT be targetted
   175  * @param immunity	Optional. Set to false to ignore target immunity.
   176  * @return		Index of target client, or -1 on error.
   177  */
   178 stock FindTarget(client, const String:target[], bool:nobots = false, bool:immunity = true)
   179 {
   180 	new clients[2];
   181 	new numClients = SearchForClients(target, clients, 2);
   182 	
   183 	if (numClients == 0)
   184 	{
   185 		ReplyToCommand(client, "[SM] %t", "No matching client");
   186 		return -1;
   187 	}
   188 	else if (numClients > 1)
   189 	{
   190 		ReplyToCommand(client, "[SM] %t", "More than one client matches", target);
   191 		return -1;
   192 	}
   193 	else if (immunity && !CanUserTarget(client, clients[0]))
   194 	{
   195 		ReplyToCommand(client, "[SM] %t", "Unable to target");
   196 		return -1;
   197 	}
   198 	else if (nobots && IsFakeClient(clients[0]))
   199 	{
   200 		ReplyToCommand(client, "[SM] %t", "Cannot target bot");
   201 		return -1;
   202 	}
   203 	
   204 	return clients[0];
   205 }
   206 
   207 
   208 /**
   209  * Loads a specified array with maps. The maps will be either loaded from mapcyclefile, or if supplied
   210  * a cvar containing a file name. If the file in the cvar is bad, it will use mapcyclefile. The fileTime
   211  * parameter is used to store a timestamp of the file. If specified, the file will only be reloaded if it
   212  * has changed.
   213  *
   214  * @param array		Valid array handle, should be created with CreateArray(33) or larger. 
   215  * @param fileTime	Variable containing the "last changed" time of the file. Used to avoid needless reloading.
   216  * @param fileCvar	CVAR set to the file to be loaded. Optional.
   217  * @return		Number of maps loaded or 0 if in error.
   218  */
   219  stock LoadMaps(Handle:array, &fileTime = 0, Handle:fileCvar = INVALID_HANDLE)
   220  { 
   221  	decl String:mapPath[256], String:mapFile[64];
   222  	new bool:fileFound = false;
   223  	
   224  	if (fileCvar != INVALID_HANDLE)
   225  	{
   226  		GetConVarString(fileCvar, mapFile, 64);
   227 	 	BuildPath(Path_SM, mapPath, sizeof(mapPath), mapFile);
   228  		fileFound = FileExists(mapPath);
   229  	}
   230  
   231  	if (!fileFound)
   232  	{
   233  		new Handle:mapCycleFile = FindConVar("mapcyclefile");
   234  		GetConVarString(mapCycleFile, mapPath, sizeof(mapPath));
   235  		fileFound = FileExists(mapPath);
   236  	}
   237  	
   238  	if (!fileFound)
   239  	{
   240  		LogError("Failed to find a file to load maps from. No maps loaded.");
   241  		ClearArray(array);
   242  		
   243  		return 0;		
   244  	}
   245  
   246  	// If the file hasn't changed, there's no reason to reload
   247  	// all of the maps.
   248  	new newTime =  GetFileTime(mapPath, FileTime_LastChange);
   249  	if (fileTime == newTime)
   250  	{
   251  		return GetArraySize(array);
   252  	}
   253  	
   254  	fileTime = newTime;
   255  	
   256  	ClearArray(array);
   257  
   258  	new Handle:file = OpenFile(mapPath, "rt");
   259  	if (file == INVALID_HANDLE)
   260  	{
   261  		LogError("Could not open file: %s", mapPath);
   262  		
   263  		return 0;
   264  	}
   265  
   266 	LogMessage("Loading maps from file: %s", mapPath);
   267 	
   268  	decl String:buffer[64], len;
   269  	while (!IsEndOfFile(file) && ReadFileLine(file, buffer, sizeof(buffer)))
   270  	{
   271  		TrimString(buffer);
   272  
   273  		if ((len = StrContains(buffer, ".bsp", false)) != -1)
   274  		{
   275  			buffer[len] = '\0';
   276  		}
   277  
   278  		if (buffer[0] == '\0' || !IsValidConVarChar(buffer[0]) || !IsMapValid(buffer))
   279  		{
   280  			continue;
   281  		}
   282  
   283  		PushArrayString(array, buffer);
   284  	}
   285  
   286  	CloseHandle(file);
   287  	return GetArraySize(array);
   288 }