/***************************************************************************
 * plugin_join_notify  v1.20
 *      Oct 23, 2004 -- Now WORKS with AdminMod v2.50.58
 *      Dec 28, 2003 -- Updated for Steam & AdminMod v2.50.58
 *	Apr 13, 2003 -- Fixed timer bugs for AdminMod v2.50.52
 *	Mar 31, 2003 -- Modified "playsoundall" to "speak" ALL sounds
 *	Nov 25, 2002 -- Compatible with AdminMod v2.50.50 (AuthID instead
 *			of WonID)
 *		     -- File location moved to "addons\adminmod\config"
 *	Nov 25, 2002 -- More efficient notification system (fewer timers)
 *
 * This plugin will read from a text file Player/sound file combinations
 * and when someone with a matching Name, AuthID, or IP Address connects to
 * the server, the specified wav file will be played for everyone to hear.
 * This allows players to have a custom sound that will play every time they
 * connect so everyone knows who is joining the game.
 *
 * Much of the code for the file parsing and the playsoundall function was
 * borrowed from plugin_sank_sounds, by Luke Sankey <sank@spu.edu>
 * while the general structure of this plugin was modeled after my
 * plugin_pager, and is in fact almost identical.  Forgive me if I don't
 * specify, but some smaller chunks of code may have been borrowed from
 * plugin_sank_sounds as well.
 *
 * Functions included in this plugin:
 *  admin_join_off
 *  admin_join_on
 *  admin_join_reload
 *  admin_join_list
 *  admin_join_lock <on | off>
 *  admin_join_add
 *  admin_join_delete
 *
 *
 * Bill Bateman aka "HunteR"
 * http://thepit.shacknet.nu
 * huntercc@hotmail.com
 ***************************************************************************/
 
 
#include <core>
#include <console>
#include <string>
#include <admin>
#include <adminlib>
 
#define ACCESS_JOIN 512+64    // Access level required for all commands
#define MAX_LINES 25          // Maximum number of lines in FILENAME
#define MAX_IPADDRESS 21+1    // xxx.xxx.xxx.xxx:xxxxx = 21 characters + null character
#define NUM_TO_LIST 8         // number of messages to list at a time for admin_join_list
#define LIST_CHARS 16         // max number of characters to show of Message in admin_join_list
#define CONN_DELAY 10         // delay to announce after player finishes connecting
 
new STRING_VERSION[MAX_COMMAND_LENGTH] = "2.50.58, plugin v1.20";
new FILENAME[MAX_DATA_LENGTH] = "addons\adminmod\config\JOIN.CFG";  // name of file to be parsed
new JoinEnabled = 1;      // 1 = enabled, 0 = disabled
new bLocked = 1;          // 1 = full name matches will work only for those with ACCESS_JOIN
new NOTIFY_DELAY = 5;     // the minimum amount of time between wavs
new NumOfLines = 0;       // total number of lines parsed from config file
new bChanged = 0;         // flag used in deletion of messages
new NumInQueue = 0;       // number of users waiting to be announced, contained in Queue[]
 
// determines how to identify the target:
// 1=Exact Name, 2=Partial Name, 3=IP Address, 4=AuthID
new MatchMethod[MAX_LINES];
 
new Sounds[MAX_LINES][MAX_DATA_LENGTH];       // contains list of sounds to play per StoredUser
new Queue[MAX_PLAYERS][MAX_NAME_LENGTH];      // list of users waiting to be announced
new WholeIP[MAX_PLAYERS][MAX_IPADDRESS];      // IP of current player, with the port number
new Messages[MAX_LINES][MAX_DATA_LENGTH];     // contains list of messages to be displayed, from FILENAME
new StoredUser[MAX_LINES][MAX_NAME_LENGTH];   // contains users to be announced, in the form of Name, AuthID, or IP Address, from FILENAME
new IsConnected[MAX_PLAYERS+1] = {0,...};     // connection status of each player
 
new MatchTimer[MAX_PLAYERS];                  // timer to delay retrieval of the target's AuthID
new LastNotifyTime = 0;                       // used to prevent notifications from overlapping
 
 
public plugin_init()
{
	plugin_registerinfo("HunteR's Join Notify Plugin", "Plays custom wav files when certain players connect.", STRING_VERSION);
	plugin_registercmd("specmode",		"HandleSpecMode",	ACCESS_ALL);
	plugin_registercmd("admin_join_off",	"admin_join_off",	ACCESS_JOIN, "admin_join_off:  Turns off custom wav files.");
	plugin_registercmd("admin_join_on",	"admin_join_on",	ACCESS_JOIN, "admin_join_on:  Turns on custom wav files.");
	plugin_registercmd("admin_join_reload", "admin_join_reload",	ACCESS_JOIN, "admin_join_reload: Reloads the custom wav config file.");
	plugin_registercmd("admin_join_list",	"admin_join_list",	ACCESS_JOIN, "admin_join_list: Displays indexed list of users in the config file.");
	plugin_registercmd("admin_join_lock",	"admin_join_lock",	ACCESS_JOIN, "admin_join_lock <on | off>:  When on, full-name matching only for users with ACCESS_JOIN.");
	plugin_registercmd("admin_join_add",	"admin_join_add",	ACCESS_JOIN, "admin_join_add ^"<MatchType>;<Target>;<Csay>;<Sound>^":  Adds to the list.");
	plugin_registercmd("admin_join_delete",	"admin_join_delete",	ACCESS_JOIN, "admin_join_delete <index>:  Deletes from the list.  See admin_join_list");
 
	bChanged = 0;
	parse_file(FILENAME);
 
	return PLUGIN_CONTINUE;
}
 
public admin_join_delete(HLCommand,HLData,HLUserName,UserIndex) {
	new Command[MAX_COMMAND_LENGTH];
	new Text[MAX_TEXT_LENGTH];
	new Data[MAX_DATA_LENGTH];
	new User[MAX_NAME_LENGTH];                    // Name of current player
 
 	convert_string(HLCommand,Command,MAX_COMMAND_LENGTH);
	convert_string(HLUserName,User,MAX_NAME_LENGTH);
	convert_string(HLData,Data,MAX_DATA_LENGTH);
 
	if ( NumOfLines < 1 )
	{
		selfmessage("[JOIN] No notifications to delete.");
		return PLUGIN_HANDLED;
	}
 
	if ( !strlen(Data) )
	{
		selfmessage("[JOIN] You must specify an <index>, see ^"admin_join_list^"");
		selfmessage("[JOIN] Nothing was deleted.");
	}
	else
	{
		new delIndex = strtonum(Data);
 
		if ( delIndex < 0 || delIndex >= NumOfLines) {
			snprintf(Text, MAX_TEXT_LENGTH, "[JOIN] Index is out of range.  Index must be from 0 to %i", NumOfLines-1);
			selfmessage(Text);
		} else {
			snprintf(Text, MAX_TEXT_LENGTH, "[JOIN] Notification number %i now being deleted:", delIndex);
			selfmessage(Text);
			snprintf(Text, MAX_TEXT_LENGTH, "[JOIN]   <search_type> = %i", MatchMethod[delIndex]);
			selfmessage(Text);
			MatchMethod[delIndex] = -1;
			snprintf(Text, MAX_TEXT_LENGTH, "[JOIN]   <target> = %s", StoredUser[delIndex]);
			selfmessage(Text);
			StoredUser[delIndex] = "";
			snprintf(Text, MAX_TEXT_LENGTH, "[JOIN]   <csay> = %s", Messages[delIndex]);
			selfmessage(Text);
			Messages[delIndex] = "";
			snprintf(Text, MAX_TEXT_LENGTH, "[JOIN]   <sound> = %s", Sounds[delIndex]);
			selfmessage(Text);
			Sounds[delIndex] = "";
			write_list();
		}
		log_command(User,Command,Data);
		return PLUGIN_HANDLED;
	}
 
	return PLUGIN_HANDLED;
}
 
write_list() {
	// Write everything to the default file:
	new Text[MAX_TEXT_LENGTH];
	new saveIndex = 0;
	new TimeStamp[MAX_TEXT_LENGTH];
	servertime(TimeStamp, MAX_TEXT_LENGTH);
 
	resetfile(FILENAME);
	writefile(FILENAME, "# Config File for Join Notify Plugin, by HunteR <huntercc@hotmail.com>");
	writefile(FILENAME, "# Last modified:");
	snprintf(Text, MAX_TEXT_LENGTH, "# %s", TimeStamp);
	writefile(FILENAME, Text);
	writefile(FILENAME, "#");
	writefile(FILENAME, "# 1 = exact-name match only works with ACCESS_JOIN:");
	snprintf(Text, MAX_TEXT_LENGTH, "NAME_LOCK;%s", bLocked);
	writefile(FILENAME, Text);
	writefile(FILENAME, "# Minimum number of seconds between notifications:");
	snprintf(Text, MAX_TEXT_LENGTH, "NOTIFY_DELAY;%s", NOTIFY_DELAY);
	writefile(FILENAME, Text);
	writefile(FILENAME, "#");
	writefile(FILENAME, "# 1=Exact Name, 2=Partial Name, 3=IP Address, 4=AuthID");
 
	for ( saveIndex=0; saveIndex<NumOfLines; saveIndex++ )
	{
		// Write non-blank lines to the default file.
		// Blank lines are defined as having a Message of zero characters, instead of at least one: " "
		if ( strlen(Messages[saveIndex]) != 0 ) {
			snprintf(Text, MAX_TEXT_LENGTH, "%i;%s;%s;%s", MatchMethod[saveIndex], StoredUser[saveIndex], Messages[saveIndex], Sounds[saveIndex]);
			writefile(FILENAME, Text);
		}
	}
 
	bChanged = 1;
	parse_file(FILENAME);
	bChanged = 0;
 
	return 1;
}
 
// USAGE: admin_join_add "<search_type>;<target>;<csay>;<sound>"
public admin_join_add(HLCommand, HLData, HLUserName, UserIndex) {
	new Data[MAX_DATA_LENGTH];
	new User[MAX_NAME_LENGTH];
	new sMethod[15];
	new Method;
	new Target[MAX_NAME_LENGTH];
	new Msg[MAX_DATA_LENGTH];
	new Snd[MAX_DATA_LENGTH];
	new Text[MAX_TEXT_LENGTH];
 
	if ( NumOfLines >= MAX_LINES )
	{
		selfmessage("No room for new messages. Either increase MAX_LINES or remove old messages.");
		return PLUGIN_HANDLED;
	}
 
	// See if file_access_write is on or off:
	if ( getvar("file_access_write") == 0 )
	{
		snprintf(Text, MAX_TEXT_LENGTH, "Join Notify Plugin >> Cannot write to %s", FILENAME);
		selfmessage(Text);
		selfmessage("Join Notify Plugin >> file_access_write must be set to 1.");
 
		return PLUGIN_HANDLED;
	}
 
	convert_string(HLData, Data, MAX_DATA_LENGTH);
	convert_string(HLUserName, User, MAX_NAME_LENGTH);
 
	strstripquotes(Data);
	strsplit(Data, ";", sMethod, 15, Target, MAX_NAME_LENGTH, Msg, MAX_DATA_LENGTH, Snd, MAX_DATA_LENGTH);
	Method = strtonum(sMethod);
 
	// Check if the parameters are valid or not:
	if( Method < 1 || Method > 4 || strlen(Target) == 0 )
	{
		selfmessage("Invalid format.");
		selfmessage("USAGE: admin_join_add ^"<search_type>;<target>;<csay>;<sound>^"");
		selfmessage("where <search_type> is 1 through 4: 1=Exact Name, 2=Partial Name, 3=IP Address, 4=AuthID");
		return PLUGIN_HANDLED;
	}
 
	if ( strlen(Msg) == 0 ) Msg = " ";
 
	new TimeStamp[MAX_TEXT_LENGTH];
	servertime(TimeStamp, MAX_TEXT_LENGTH);
 
	snprintf(Text, MAX_TEXT_LENGTH, "# %s: Message added by ^"%s^"", TimeStamp, User);
	writefile(FILENAME, Text);
	snprintf(Text, MAX_TEXT_LENGTH, "%i;%s;%s;%s", Method, Target, Msg, Snd);
	writefile(FILENAME, Text);
 
	switch (Method)
	{
		case 1: strcpy(sMethod, "Exact Name", MAX_TEXT_LENGTH);
		case 2: strcpy(sMethod, "Partial Name", MAX_TEXT_LENGTH);
		case 3: strcpy(sMethod, "IP Address", MAX_TEXT_LENGTH);
		case 4: strcpy(sMethod, "AuthID", MAX_TEXT_LENGTH);
	}
 
	snprintf(Text, MAX_TEXT_LENGTH, " >> Search type:^t^"%i^"  (%s)", Method, sMethod);
	selfmessage(Text);
	snprintf(Text, MAX_TEXT_LENGTH, " >> Target user:^t^"%s^"", Target);
	selfmessage(Text);
	snprintf(Text, MAX_TEXT_LENGTH, " >> Csay added:  ^t^"%s^"", Msg);
	selfmessage(Text);
	snprintf(Text, MAX_TEXT_LENGTH, " >> Sound added:^t^"%s^"", Snd);
	selfmessage(Text);
	snprintf(Text, MAX_TEXT_LENGTH, "New message successfully added to ^"%s^" file.", FILENAME);
	selfmessage(Text);
 
	NumOfLines++;
	bChanged = 1;
	parse_file(FILENAME);
	bChanged = 0;
 
	return PLUGIN_HANDLED;
}
 
public admin_join_lock(HLCommand, HLData, HLUserName, UserIndex)
{
	new Data[MAX_DATA_LENGTH];
	new Text[MAX_TEXT_LENGTH];
 
	if ( check_param(Data) == 1 ) {
		bLocked = 1;
		snprintf(Text, MAX_TEXT_LENGTH, "[JOIN] Full-name matches will now only work for those with access level %i", ACCESS_JOIN);
		selfmessage(Text);
	} else {
		bLocked = 0;
		selfmessage("[JOIN] Full-name matches will now work for players with any access level.");
	}
 
	return PLUGIN_HANDLED;
}
 
// Turns off the playing of personal wav files (for this plugin only)
public admin_join_off(HLCommand, HLData, HLUserName, UserIndex)
{
	new Name[MAX_NAME_LENGTH];
	convert_string(HLUserName,Name,MAX_NAME_LENGTH);
	JoinEnabled = 0;
	say("HunteR's Join Notify Plugin has been disabled!");
	playsoundall("fvox/alert vitalsigns_on(e68) deactivated");
 
	return PLUGIN_HANDLED;
}
 
public admin_join_on(HLCommand, HLData, HLUserName, UserIndex)
{
	new Name[MAX_NAME_LENGTH];
	convert_string(HLUserName,Name,MAX_NAME_LENGTH);
	JoinEnabled = 1;
	say("HunteR's Join Notify Plugin has been enabled!");
	playsoundall("fvox/vitalsigns_on");
 
	return PLUGIN_HANDLED;
}
 
// originally only added for debugging purposes, but is still useful
public admin_join_list(HLCommand, HLData, HLUserName, UserIndex)
{
	new Data[MAX_DATA_LENGTH];
	new Text[MAX_TEXT_LENGTH];
	new sTemp[MAX_TEXT_LENGTH];
	convert_string(HLData, Data, MAX_DATA_LENGTH);
 
	if ( NumOfLines < 1 )
	{
		selfmessage("[JOIN] No notifications to list.");
		return PLUGIN_HANDLED;
	}
 
	if ( strlen(Data) == 0 ) Data = "0";
	new msgIndex = strtonum(Data);
	if ( msgIndex < 0 || msgIndex >= NumOfLines)
	{
		snprintf(Text, MAX_TEXT_LENGTH, "[JOIN] Index is out of range.  Index must be from 0 to %i", NumOfLines-1);
		selfmessage(Text);
	}
	else
	{
		selfmessage("[Index] - [MatchType] : [User] - [Message]");
		new i;
		new Range = msgIndex + NUM_TO_LIST;
		if ( Range > NumOfLines ) Range = NumOfLines;
		for ( i=msgIndex; i<Range; i++ )
		{
			strcpy(sTemp, Messages[i], LIST_CHARS);
			if ( MatchMethod[i] == 1 ) {
				snprintf(Text, MAX_TEXT_LENGTH, "%i - Exact Name :^t%s - %s", i, StoredUser[i], sTemp);
			} else if ( MatchMethod[i] == 2 ) {
				snprintf(Text, MAX_TEXT_LENGTH, "%i - Partial Name :^t%s - %s", i, StoredUser[i], sTemp);
			} else if ( MatchMethod[i] == 3 ) {
				snprintf(Text, MAX_TEXT_LENGTH, "%i - IP Address :^t%s - %s", i, StoredUser[i], sTemp);
			} else if ( MatchMethod[i] == 4 ) {
				snprintf(Text, MAX_TEXT_LENGTH, "%i - AuthID : ^t%s - %s", i, StoredUser[i], sTemp);
			}
			selfmessage(Text);
		}
		if ( (msgIndex+NUM_TO_LIST) < NumOfLines ) {
			snprintf(Text, MAX_TEXT_LENGTH, "  Type admin_join_list %i for more", Range+1);
			selfmessage(Text);
		}
	}
 
	return PLUGIN_HANDLED;
}
 
public admin_join_reload(HLCommand, HLData, HLUserName, UserIndex)
{
	bChanged = 0;
	parse_file(FILENAME);
	return PLUGIN_HANDLED;
}
 
public MatchTrigger(Timer,WaitCount,RepeatCount,User)
{
	new UserIndex;
	new Name[MAX_NAME_LENGTH];     // Name of current player
	new NotifyIndex = 0;
 
	convert_string(User, Name, MAX_NAME_LENGTH);
	get_userindex(Name, UserIndex);
 
	NotifyIndex = matchTest( Name );
	if ( NotifyIndex > -1 )
		addToQueue(Name,NotifyIndex);
}
 
addToQueue( Name[], NotifyIndex )
{
	// If not already at end of Queue, add to Queue
	if ( strcasecmp(Queue[NumInQueue],Name) != 0 )
	{
		strcpy(Queue[NumInQueue],Name,MAX_NAME_LENGTH);
		NumInQueue++;
		// if this is only person in Queue[], call join_notify
		if ( NumInQueue == 1 ) join_notify(NotifyIndex);
		return 1;
	}
 
	// Otherwise, do nothing
	return -1;
}
 
// return (searchIndex) of match found, return (-1) if no match found:
matchTest( Name[] )
{
	new matchFound = 0;
	new searchIndex = -1;
	new IP[MAX_IPADDRESS-6];
	new UserIndex;
	new AuthID[MAX_DATA_LENGTH];
 
	get_userindex(Name, UserIndex);
	get_userAuthID(Name, AuthID);
 
	strtok(WholeIP[UserIndex], ":", IP, MAX_IPADDRESS-6);  // strip the port number from the IP
 
	while ( searchIndex < (MAX_LINES-1) && !matchFound )
	{
		searchIndex++;
 
		if ( MatchMethod[searchIndex] < 1 || strlen(StoredUser[searchIndex]) == 0 || MatchMethod[searchIndex] > 4 )
		{
			matchFound = 0;
			searchIndex = MAX_LINES;
		}
 
		else if ( MatchMethod[searchIndex] == 1 && strcasecmp(Name,StoredUser[searchIndex]) == 0 )
		{
			// got a full-name match, now check for Lock status and Access level
			if ( (bLocked == 1) && (access(ACCESS_JOIN,Name) == 0) )
				matchFound = 0;
			else
				matchFound = 1;
		}
 
		else if ( MatchMethod[searchIndex] == 2 && strcasestr(Name,StoredUser[searchIndex]) != -1 )
			matchFound = 1;
 
		else if ( MatchMethod[searchIndex] == 3 && streq(IP,StoredUser[searchIndex]) == 1 )
			matchFound = 1;
 
		else if ( MatchMethod[searchIndex] == 4 && streq(AuthID,StoredUser[searchIndex]) == 1 )
			matchFound = 1;
	}
 
	if ( matchFound )
		return searchIndex;
 
	return -1;
}
 
// removes from Queue the most recently announced user:
deleteRecent()
{
	new i;
	new UpperLim = NumInQueue;
 
	if ( UpperLim >= MAX_PLAYERS ) UpperLim = MAX_PLAYERS - 1;
 
	strinit(Queue[0]);
	for ( i=0; i<UpperLim; i++ )
	{
		strcpy(Queue[i],Queue[i+1],MAX_NAME_LENGTH);
		strinit(Queue[i+1]);
	}
 
	NumInQueue--;
}
 
// Display custom message and play sound file.
// This assumes MatchMethod has already been checked for validity
join_notify( NotifyIndex )
{
	new Text[MAX_TEXT_LENGTH];
	new sParam[MAX_DATA_LENGTH];
 
	// If too soon, come back later to prevent overlapping
	if ( (systemtime() - LastNotifyTime) < NOTIFY_DELAY )
	{
		numtostr(NotifyIndex, sParam);
		set_timer("NotifyTrigger",NOTIFY_DELAY,0,sParam);
		return 0;
	} else {
		LastNotifyTime = systemtime();
	}
 
	// error checking on index value
	if ( NumInQueue < 1 || NumInQueue > MAX_PLAYERS )
	{
		log("[ERROR] Join Notify Plugin >> Can't notify, NumInQueue out of range.");
		return 0;
	}
 
	// if a name in Queue is not valid, remove it and check the next one
	// (could happen if someone connects, then disconnects)
	// but if the name is valid, continue:
	new i;
	new Name[MAX_NAME_LENGTH];
	for ( i=0; i<NumInQueue; i++ )
	{
		if ( !check_user(Queue[0]) ) {
			deleteRecent();
		} else {
			strcpy(Name, Queue[0], MAX_NAME_LENGTH);
			break;
		}
	}
 
	if ( !check_user(Name) )
	{
		snprintf(Text, MAX_TEXT_LENGTH, "[JOIN] Failed, can't announce: %s", Name);
		log(Text);
		return 0;
	}
 
	new UserIndex;
	get_userindex(Name,UserIndex);
	new strTemp[MAX_DATA_LENGTH];
	strTemp = Messages[NotifyIndex];
	strtrim(strTemp, " ^t");
 
	// display the text message if present:
	if ( strlen(strTemp) > 0 && !streq(strTemp," ") )
	{
		// replace all instances of %n with user's name; if none to replace, leave alone:
		if ( strsubst(strTemp,"%n",Name,MAX_DATA_LENGTH) == -1 )
			strTemp = Messages[NotifyIndex];
 
		new Color[MAX_DATA_LENGTH];
		new Data[MAX_DATA_LENGTH];
		strbreak(strTemp,Color,Data,MAX_DATA_LENGTH);
		if ( streq(Color,"red")==1 ) {
			centersay(Data,15,250,10,10);
		} else if ( streq(Color, "blue")==1 ) {
			centersay(Data,15,10,10,250);
		} else if ( streq(Color, "green")==1 ) {
			centersay(Data,15,10,250,10);
		} else if ( streq(Color, "white")==1 ) {
			centersay(Data,15,250,250,250);
		} else if ( streq(Color, "yellow")==1 ) {
			centersay(Data,15,250,250,10);
		} else if ( streq(Color, "purple")==1 ) {
			centersay(Data,15,250,10,250);
		} else if ( streq(Color, "random")==1) {
			centersay(Data,15,random(100),random(100),random(100));
		} else {
			centersay(strTemp,15,15,250,15);
		}
	}
 
	strTemp = Sounds[NotifyIndex];
	strstripquotes(strTemp);
 
	if ( strlen(strTemp) > 0 )
	{
		playsoundall(strTemp);
 
		deleteRecent();
		if ( NumInQueue > 0 )
		{
			// need to re-retrieve the NotifyIndex so that it matches with next user
			NotifyIndex = matchTest(Name);
			numtostr(NotifyIndex, sParam);
			set_timer("NotifyTrigger",NOTIFY_DELAY,0,sParam);
		}
 
		return 1;
	}
 
	return 0;
}
 
public NotifyTrigger(Timer,WaitCount,RepeatCount,HLParam)
{
	new param[MAX_TEXT_LENGTH];
	convert_string(HLParam, param, MAX_TEXT_LENGTH);
	new NumIndex = strtonum(param);
	join_notify(NumIndex);
}
 
//*************************************************************************
// Parses the config file specified by loadfile. If loadfile is empty, then
// it parses the default FILENAME.
// (borrowed from plugin_sank_sounds and modified)
//
// Returns 0 if parsing was successful
// Returns 1 if parsing failed
// Returns -1 otherwise
//*************************************************************************/
parse_file(loadfile[] = "")
{
	new GotLine;
	new iLineNum = 0;
	new strLineBuf[MAX_TEXT_LENGTH];
	new ListIndex = 0;
	new Text[MAX_TEXT_LENGTH];
	new sMatchMethod[15];     // temporary string for MatchMethod
	NumOfLines = 0; // reset the count before we parse again
 
	if (strlen(loadfile) == 0)
		strcpy(loadfile, FILENAME, MAX_TEXT_LENGTH);
 
	if (fileexists(loadfile) > 0)
	{
		GotLine = readfile(loadfile, strLineBuf, iLineNum, MAX_TEXT_LENGTH);
		if (GotLine <= 0)
		{
			// If file access is already set correctly...
			if (getvar("file_access_read") == 1)
				snprintf(Text, MAX_TEXT_LENGTH, "Join Notify Plugin >> Unable to read from %s file.", loadfile);
			else
				snprintf(Text, MAX_TEXT_LENGTH, "Join Notify Plugin >> CVAR file_access_read is set incorrectly.");
			log(Text);
			return -1;
		}
 
		new clearIndex = 0;
		for ( clearIndex=0; clearIndex<MAX_LINES; clearIndex++ ) {
			MatchMethod[clearIndex] = 0;
			StoredUser[clearIndex] = "";
			Messages[clearIndex] = "";
			Sounds[clearIndex] = "";
		}
 
		while (GotLine)
		{
			if (ListIndex >= MAX_LINES)
			{
				log("Join Notify Plugin >> Notification list truncated. Increase MAX_LINES and recompile.");
				printf("Join Notify Plugin >> Error - stopped parsing %s file.^n", loadfile);
				break;
			}
 
			// As long as the line isn't commented out, and isn't blank, then process it.
			if ( (strncmp(strLineBuf, "#", 1) != 0) && (strncmp(strLineBuf, "//", 2) != 0) && (strlen(strLineBuf) != 0) )
			{
				strsep(strLineBuf, ";", sMatchMethod, 15, strLineBuf, MAX_TEXT_LENGTH);
				strtrim(sMatchMethod, "^t");
				strtrim(strLineBuf, "^t");
 
				if( !strcasecmp(sMatchMethod, "NAME_LOCK") )
					bLocked = check_param(strLineBuf);
				else if( !strcasecmp(sMatchMethod, "NOTIFY_DELAY"))
					NOTIFY_DELAY = strtonum(strLineBuf);
				else
				{
					strsplit(strLineBuf, ";", StoredUser[ListIndex], MAX_NAME_LENGTH, Messages[ListIndex], MAX_DATA_LENGTH, Sounds[ListIndex], MAX_DATA_LENGTH);
					MatchMethod[ListIndex] = strtonum(sMatchMethod);
 
					if( MatchMethod[ListIndex] > 0 && MatchMethod[ListIndex] < 5 && strlen(StoredUser[ListIndex]) > 0 && (strlen(Messages[ListIndex]) > 0 || strlen(Sounds[ListIndex]) > 0) )
					{
						ListIndex++;
						NumOfLines++;
					} else {
						snprintf(Text, MAX_TEXT_LENGTH, "Join Notify Plugin >> Line %i skipped in file %s for invalid format", iLineNum, FILENAME);
						log(Text);
					}
				}
			}
 
			// Read in the next line from the file
			GotLine = readfile(loadfile, strLineBuf, ++iLineNum, MAX_TEXT_LENGTH);
		}
	}
	else // file exists returned false, meaning the file didn't exist
	{
		snprintf(Text, MAX_TEXT_LENGTH, "[ADMIN] Join Notify Plugin >> Cannot find %s file.", loadfile);
		selfmessage(Text);
		return 1;
	}
 
	if ( !bChanged ) {
		snprintf(Text, MAX_TEXT_LENGTH, "[ADMIN] Join Notify Plugin >> %s successfully loaded.", loadfile);
		selfmessage(Text);
	}
	else bChanged = 0;
 
	return 0;
}
 
public plugin_connect(HLUserName, HLIP, UserIndex)
{
	convert_string(HLIP, WholeIP[UserIndex], MAX_IPADDRESS);
	IsConnected[UserIndex] = 0;
	return PLUGIN_CONTINUE;
}
 
public plugin_disconnect(HLUserName, UserIndex)
{
	if ( UserIndex >= 1 && UserIndex <= MAX_PLAYERS )
	{
		strinit(WholeIP[UserIndex]);
		IsConnected[UserIndex] = 0;
	}
 
	return PLUGIN_CONTINUE;
}
 
public HandleSpecMode(HLCommand, HLData, HLUserName, UserIndex)
{
	if ( (UserIndex >= 1) && (UserIndex <= MAX_PLAYERS) && (JoinEnabled == 1) && (!IsConnected[UserIndex]) ) {
		new MyUserName[MAX_NAME_LENGTH];
		convert_string(HLUserName, MyUserName, MAX_NAME_LENGTH);
		MatchTimer[UserIndex] = set_timer("MatchTrigger",CONN_DELAY,0,MyUserName);
		IsConnected[UserIndex] = 1;
		return PLUGIN_CONTINUE;
	}
 
	return PLUGIN_CONTINUE;
}
 
 
// from plugin_sank_sounds
//
// Modified March 30, 2003 by HunteR
// to "speak" instead of "play"
////////////////////////////////////
playsoundall(sound[], IfDead = -1)
{
	new maxplayers = maxplayercount();
	new Name[MAX_NAME_LENGTH];
	new Text[MAX_TEXT_LENGTH];
	new i;
 
	strstripquotes(sound);
	strtrim(sound," ^t");
 
	snprintf(Text, MAX_TEXT_LENGTH, "speak ^"%s^"", sound);
	for(i=1; i<=maxplayers; i++)
	{
		new iDead;
		new dummy;
		if (playerinfo(i, Name, MAX_NAME_LENGTH, dummy, dummy, dummy, iDead) == 1)
		{
			if (IfDead == -1)
				execclient(Name, Text);
			else if (IfDead == iDead)
				execclient(Name, Text);
		}
	}
}