/*************************************************************************** * 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); } } }