/*************************************************************************** * plugin_sank_sounds.sma * Author: Luke Sankey * March 21, 2001 - Original hard-coded version released. * July 2, 2001 - Rewrote to be text file configurable * November 18, 2001 - Added admin_sound_play command, new variables SND_DELAY, * SND_SPLIT and EXACT_MATCH, as well as the ability to have admin-only * sounds, like the original version had. * March 30, 2002 - Fixed zero-length-speech bug. * May 30, 2002 - Updated for use with new playerinfo function (beta only) * November 15, 2002 - Moved snd-list.cfg file to new location, and made it all * lower-case. Sorry, linux guys, if it confuses you. Fixed admin_sound_add * bug when trying to change SND_* parameters. Added some ideas from Bill * Bateman: * 1.) added SND_PUNISH and changed SND_KICK to SND_MAX * 2.) ability to either speak or play sounds * * This plugin will read from a text file keyword/wav file combinations * and when a player says one of the keywords, it will trigger HL to play * that wav file to all players. It allows reloading of the file without * restarting the current level, as well as adding keyword/wav combinations * from the console during gameplay. * * My most deepest thanks goes to William Bateman (aka HunteR) * http://thepit.shacknet.nu * huntercc@hotmail.com * For he was the one who got me motivated once again to write this plugin * since I don't run a server anymore. And besides that, he helped write * parts of it. * * For technical assistance with this plugin, please see the README.TXT file * that was bundled in the zip file. If it fails you, email Bill Bateman or * me. * * I hope you enjoy this new functionality on the old plugin_sank_sounds! * * Luke Sankey * sank@spu.edu *************************************************************************** * edit by Sir D.: * - new override function for executing punish commands * - max keywords 200 */ // Functions included in this plugin // admin_sound_add "<keyword>;<dir\wav>" // admin_sound_help // admin_sound_off // admin_sound_on // admin_sound_play <dir\wav> // admin_sound_reload [filename] // admin_sound_remove "<keyword>;[dir\wav]" // admin_sound_write <filename> #include <core> #include <console> #include <string> #include <admin> #include <adminlib> #define ACCESS_CONSOLE 131072 #define ACCESS_SOUND 512+64 // Access level for advanced sound commands. #define ACCESS_ADMINSOUNDS 512+64 // Access level for playing admin sounds new FILENAME[MAX_DATA_LENGTH] = "addons/adminmod/config/snd-list.cfg"; // Name of file to parse. new punishfile[] = "addons/adminmod/config/sounds_punish.cfg"; //execute punish command #define MAX_KEYWORDS 200 // Maximum number of keywords #define MAX_RANDOM 10 // Maximum number of wavs per keyword #define TOK_LENGTH 50 // Maximum length of keyword and wav file strings #define NUM_PER_LINE 4 // Number of words per line from admin_sound_help #define DEBUG 0 /****************************************************************************/ /****************************************************************************/ /************** DO NOT MODIFY CONTENTS BELOW THIS LINE !!! ******************/ /************** DO NOT MODIFY CONTENTS BELOW THIS LINE !!! ******************/ /************** DO NOT MODIFY CONTENTS BELOW THIS LINE !!! ******************/ /****************************************************************************/ /****************************************************************************/ new STRING_VERSION[MAX_DATA_LENGTH] = "2.50.50_sd"; /****************************************************************************/ /* Holds the number telling how many sounds a player has played */ new SndCount[MAX_PLAYERS] = {0,...}; /* The number at which a player will get warned for playing too many sounds */ new SND_WARN = 0; /* The number at which a player will get kicked for playing too many sounds */ new SND_MAX = 0; /* The wav to play when a person joins the game */ new SND_JOIN[TOK_LENGTH] = ""; /* The wav to play when a person exits the game */ new SND_EXIT[TOK_LENGTH] = ""; /* The command to execute when a person exceeds the quota */ new SND_PUNISH[TOK_LENGTH] = ""; /* Minimum delay between sounds */ new SND_DELAY = 0; /* Determines if sounds play to all, or isolate dead and alive */ new SND_SPLIT = 0; /* Determines if plugin triggers on exact match, or partial speech match */ new EXACT_MATCH = 1; /****************************************************************************/ /****************************************************************************/ /* First column is the indentifier of the Word-Wav Combination */ /* Second column is the token identifier */ /* Third column is the token (string) */ /* Empty tokens are delimited by empty strings */ /****************************************************************************/ /* [0] [TOK_LENGTH*0] ["crap"] [0] [TOK_LENGTH*1] ["misc/awwcrap.wav"] [0] [TOK_LENGTH*2] ["misc/awwcrap2.wav"] [0] [TOK_LENGTH*3] [""] [1] [TOK_LENGTH*0] ["woohoo"] [1] [TOK_LENGTH*1] ["misc/woohoo.wav"] [1] [TOK_LENGTH*2] [""] [2] [TOK_LENGTH*0] ["ha ha"] [2] [TOK_LENGTH*1] ["misc/haha.wav"] [2] [TOK_LENGTH*2] [""] [3] [TOK_LENGTH*0] ["doh"] [3] [TOK_LENGTH*1] ["misc/doh.wav"] [3] [TOK_LENGTH*2] ["misc/doh2.wav"] [3] [TOK_LENGTH*3] ["misc/doh3.wav"] [3] [TOK_LENGTH*4] ["misc/doh4.wav"] [3] [TOK_LENGTH*5] [""] [4] [TOK_LENGTH*0] [""] ... */ new WordWavCombo[MAX_KEYWORDS][TOK_LENGTH*(MAX_RANDOM+1)]; /****************************************************************************/ new LastSoundTime = 0; // Very limited spam protection new bSoundsEnabled = 1; // admin_sound_on and admin_sound_off stock playsoundall(sound[], IfDead = -1); /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ new g_User[MAX_PLAYERS]; public plugin_init() { plugin_registerinfo("Sank Sounds Plugin", "Responds to certain chat messages by playing a sound.", STRING_VERSION); plugin_registercmd("say", "HandleSay", ACCESS_ALL); plugin_registercmd("specmode", "HandleSpecMode", ACCESS_ALL); plugin_registercmd("admin_sound_add", "admin_sound_add", ACCESS_SOUND, "admin_sound_add ^"<keyword>;<dir\wav>^" : Adds a word/wav combo to the sound list. Must use quotes."); plugin_registercmd("admin_sound_help", "admin_sound_help", ACCESS_ALL, "admin_sound_help: Lists all sounds and commands"); plugin_registercmd("admin_sound_off", "admin_sound_off", ACCESS_SOUND, "admin_sound_off: Turns off sounds."); plugin_registercmd("admin_sound_on", "admin_sound_on", ACCESS_SOUND, "admin_sound_on: Turns on sounds."); plugin_registercmd("admin_sound_play", "admin_sound_play", ACCESS_SOUND, "admin_sound_play <dir\wav> : Plays sound to all users."); plugin_registercmd("admin_sound_reload", "admin_sound_reload", ACCESS_SOUND, "admin_sound_reload: Reloads config file. Filename is optional"); plugin_registercmd("admin_sound_remove", "admin_sound_remove", ACCESS_SOUND, "admin_sound_remove ^"<keyword>;[dir\wav]^" : Removes a word/wav combo from the sound list. Must use quotes."); plugin_registercmd("admin_sound_write", "admin_sound_write", ACCESS_SOUND, "admin_sound_write: Writes current sound configuration to file."); plugin_registercmd("snd_punish", "snd_punish", ACCESS_CONSOLE); #if DEBUG plugin_registercmd("admin_sound_debug", "print_matrix", ACCESS_SOUND, "admin_sound_debug"); #endif parse_sound_file(); return PLUGIN_CONTINUE; } public plugin_connect(HLUserName, HLIP, UserIndex) { if (UserIndex >= 1 && UserIndex <= MAX_PLAYERS){ SndCount[UserIndex] = 0; g_User[UserIndex]=0; } return PLUGIN_CONTINUE; } public plugin_disconnect(HLUserName, UserIndex) { if (UserIndex >= 1 && UserIndex <= MAX_PLAYERS){ SndCount[UserIndex] = 0; g_User[UserIndex]=0; } playsoundall(SND_EXIT); return PLUGIN_CONTINUE; } /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ ////////////////////////////////////////////////////////////////////////////// // Adds a Word/Wav combo to the list. If it is a valid line in the config // file, then it is a valid parameter here. The only difference is you can // only specify one .wav file at a time with this command. // // Usage: admin_sound_add "<keyword>;<dir\wav>" // Usage: admin_sound_add "<setting>;<value>" ////////////////////////////////////////////////////////////////////////////// public admin_sound_add(HLCommand, HLData, HLUserName, UserIndex) { new Data[MAX_DATA_LENGTH]; new User[MAX_NAME_LENGTH]; new Word[TOK_LENGTH]; new Wav[TOK_LENGTH]; new Text[MAX_TEXT_LENGTH]; new bGotOne = 0; new i; new j; convert_string(HLData, Data, MAX_DATA_LENGTH); convert_string(HLUserName, User, MAX_NAME_LENGTH); // Remove outside quotes strstripquotes(Data); // Parse command line strsplit(Data, ";", Word, TOK_LENGTH, Wav, TOK_LENGTH); // Remove whitespace strtrim(Word, " ^t"); strtrim(Wav, " ^t"); if (strlen(Word) == 0 || strlen(Wav) == 0) { selfmessage("Invalid format."); selfmessage("USAGE: admin_sound_add ^"<keyword>;<dir\wav>^""); selfmessage("USAGE: admin_sound_add ^"<parameter>;<value>^""); return PLUGIN_HANDLED; } // First look for special parameters if (!strcasecmp(Word, "SND_KICK") || !strcasecmp(Word, "SND_MAX")) // backwards compatibility { SND_MAX = strtonum(Wav); bGotOne = 1; } else if (!strcasecmp(Word, "SND_WARN")) { SND_WARN = strtonum(Wav); bGotOne = 1; } else if (!strcasecmp(Word, "SND_JOIN")) { strcpy(SND_JOIN, Wav, TOK_LENGTH); bGotOne = 1; } else if (!strcasecmp(Word, "SND_EXIT")) { strcpy(SND_EXIT, Wav, TOK_LENGTH); bGotOne = 1; } else if (!strcasecmp(Word, "SND_PUNISH")) { strcpy(SND_PUNISH, Wav, TOK_LENGTH); bGotOne = 1; } else if (!strcasecmp(Word, "SND_DELAY")) { SND_DELAY = strtonum(Wav); bGotOne = 1; } else if (!strcasecmp(Word, "SND_SPLIT")) { SND_SPLIT = strtonum(Wav); bGotOne = 1; } else if (!strcasecmp(Word, "EXACT_MATCH")) { EXACT_MATCH = strtonum(Wav); bGotOne = 1; } if (bGotOne) { // Do some error checking on the user-input numbers ErrorCheck(); return PLUGIN_HANDLED; } // Loop once for each keyword for (i=0; i<MAX_KEYWORDS; i++) { // If an empty string, then break this loop if (strlen(WordWavCombo[i]) == 0) break; // If we find a match, then add on the new wav data if (strncmp(Word, WordWavCombo[i], TOK_LENGTH) == 0) { // See if the wav already exists for (j = 1; j <= MAX_RANDOM; j++) { // If an empty string, then break this loop if (strlen(WordWavCombo[i][TOK_LENGTH*j]) == 0) break; // See if this is the same as the new wav if (strncmp(Wav, WordWavCombo[i][TOK_LENGTH*j], TOK_LENGTH) == 0) { snprintf(Text, MAX_TEXT_LENGTH, "%s; %s already exists.", Word, Wav); selfmessage(Text); return PLUGIN_HANDLED; } } // If we reached the end, then there is no room if (j >= MAX_RANDOM) selfmessage("No room for new wav. Increase MAX_RANDOM and recompile."); else { // Word exists, but Wav is new to the list, so add entry strcpy(WordWavCombo[i][TOK_LENGTH*j], Wav, TOK_LENGTH); snprintf(Text, MAX_TEXT_LENGTH, "%s successfully added to %s", Wav, Word); selfmessage(Text); } return PLUGIN_HANDLED; } } // If we reached the end, then there is no room if (i == MAX_KEYWORDS) selfmessage("No room for new Word/Wav combo. Increase MAX_KEYWORDS and recompile."); else { // Word/Wav combo is new to the list, so make a new entry strcpy(WordWavCombo[i][TOK_LENGTH*0], Word, TOK_LENGTH); strcpy(WordWavCombo[i][TOK_LENGTH*1], Wav, TOK_LENGTH); snprintf(Text, MAX_TEXT_LENGTH, "%s; %s successfully added.", Word, Wav); selfmessage(Text); } return PLUGIN_HANDLED; } ////////////////////////////////////////////////////////////////////////////// // Instead of using admin_help, which uses static data, admin_sound_help // always lists the most up-to-date information because the Word/Wav list can // change the middle of gameplay. admin_sound_help lists all admin_sound // commands and keywords to the user. // // Usage: admin_sound_help ////////////////////////////////////////////////////////////////////////////// public admin_sound_help(HLCommand,HLData,HLUserName,UserIndex) { new User[MAX_NAME_LENGTH]; new Text[MAX_TEXT_LENGTH] = ""; new i = 0; new j = 0; convert_string(HLUserName, User, MAX_NAME_LENGTH); /* selfmessage("admin_sound_add ^"<keyword>;<dir\wav>^" : Adds a Word/Wav combo to the sound list. Must use quotes."); selfmessage("admin_sound_help: Shows this text."); selfmessage("admin_sound_off: Turns off sounds."); selfmessage("admin_sound_on: Turns on sounds."); selfmessage("admin_sound_play <dir\wav> : Plays sound to all users."); selfmessage("admin_sound_reload [filename] : Reloads config file. Filename is optional."); selfmessage("admin_sound_remove ^"<keyword>;[dir\wav]^" : Removes a Word/Wav combo from the sound list. Must use quotes."); selfmessage("admin_sound_write <filename> : Writes the current sound configuration to filename."); */ selfmessage("say <keyword>: Plays a sound. Keywords are listed below:"); // Loop once for each keyword for (i = 0; i < MAX_KEYWORDS; i++) { // If an invalid string, then break this loop if ((strlen(WordWavCombo[i]) == 0) || (strlen(WordWavCombo[i]) > TOK_LENGTH)) break; if ((WordWavCombo[i][0] != '@') || (access(ACCESS_ADMINSOUNDS, User))) { strcat(Text, WordWavCombo[i], MAX_TEXT_LENGTH); strcat(Text, " ^t ^t", MAX_TEXT_LENGTH); j++; } if (j % NUM_PER_LINE == NUM_PER_LINE - 1) { // We got NUM_PER_LINE on this line, // so print it and start on the next line selfmessage(Text); Text[0] = 0; } } if (strlen(Text) != 0) selfmessage(Text); return PLUGIN_HANDLED; } ////////////////////////////////////////////////////////////////////////////// // Turns off the playing of the wav files for this plugin only. // // Usage: admin_sound_off ////////////////////////////////////////////////////////////////////////////// public admin_sound_off(HLCommand, HLData, HLUserName, UserIndex) { bSoundsEnabled = 0; say("Sank Sounds Plugin has been deactivated!"); // playsoundall("fvox/six(e50) safe_day(s90) ten(s65) (t30) communications_on(e1)"); playsoundall("^"fvox/south(e70) seconds(s60) (p96) deactivated^""); return PLUGIN_HANDLED; } ////////////////////////////////////////////////////////////////////////////// // Turns on the playing of the wav files for this plugin only. // // Usage: admin_sound_on ////////////////////////////////////////////////////////////////////////////// public admin_sound_on(HLCommand, HLData, HLUserName, UserIndex) { bSoundsEnabled = 1; say("Sank Sounds Plugin has been activated!"); // playsoundall("fvox/six(e50) safe_day(s90) ten(s65) (t30) communications_on(e1) (t1) south(e70) seconds(s60) (p96) activated"); playsoundall("^"fvox/south(e70) seconds(s60) (p96) activated^""); return PLUGIN_HANDLED; } ////////////////////////////////////////////////////////////////////////////// // Plays a sound to all players // // Usage: admin_sound_play <dir\wav> ////////////////////////////////////////////////////////////////////////////// public admin_sound_play(HLCommand, HLData, HLUserName, UserIndex) { new Data[MAX_DATA_LENGTH]; convert_string(HLData, Data, MAX_DATA_LENGTH); playsoundall(Data); return PLUGIN_HANDLED; } ////////////////////////////////////////////////////////////////////////////// // Reloads the Word/Wav combos from filename. // // Usage: admin_sound_reload [filename] ////////////////////////////////////////////////////////////////////////////// public admin_sound_reload(HLCommand, HLData, HLUserName, UserIndex) { new parsefile[MAX_DATA_LENGTH]; convert_string(HLData, parsefile, MAX_DATA_LENGTH); // Initialize WordWavCombo[][][] array new i; for (i = 0; i < MAX_KEYWORDS; i++) WordWavCombo[i][0] = 0; parse_sound_file(parsefile); return PLUGIN_HANDLED; } ////////////////////////////////////////////////////////////////////////////// // Removes a Word/Wav combo from the list. You must specify a keyword, but it // is not necessary to specify a wav if you want to remove all wavs associated // with that keyword. Surrounding quotes are required. // // Usage: admin_sound_remove "<keyword>;[wav]" ////////////////////////////////////////////////////////////////////////////// public admin_sound_remove(HLCommand, HLData, HLUserName, UserIndex) { new Data[MAX_DATA_LENGTH]; new User[MAX_NAME_LENGTH]; new Word[TOK_LENGTH]; new Wav[TOK_LENGTH]; new Text[MAX_TEXT_LENGTH]; new iCurWord; new jCurWav; convert_string(HLData, Data, MAX_DATA_LENGTH); convert_string(HLUserName, User, MAX_NAME_LENGTH); // Parse command line strsplit(Data, ";", Word, TOK_LENGTH, Wav, TOK_LENGTH); // Remove whitespace strtrim(Word, " ^t"); strtrim(Wav, " ^t"); if (strlen(Data) == 0) { selfmessage("Invalid format."); selfmessage("USAGE: admin_sound_remove ^"<keyword>;[dir\wav]^""); return PLUGIN_HANDLED; } // Loop once for each keyword for (iCurWord = 0; iCurWord < MAX_KEYWORDS; iCurWord++) { // If an empty string, then break this loop, we're at the end if (strlen(WordWavCombo[iCurWord]) == 0) break; // Look for a Word match if (strncmp(Word, WordWavCombo[iCurWord], TOK_LENGTH) == 0) { // If no wav was specified, then remove the whole word's entry if (strlen(Wav) == 0) { // Keep looping i, copying the next into the current for (; iCurWord < MAX_KEYWORDS; iCurWord++) { // If we're about to copy a string that doesn't exist, // then just erase the last string instead of copying. if (iCurWord >= MAX_KEYWORDS - 1) { // Delete the last word string WordWavCombo[iCurWord][0] = 0; // We reached the end snprintf(Text, MAX_TEXT_LENGTH, "%s successfully removed.", Word); selfmessage(Text); return PLUGIN_HANDLED; } else { // Copy the next string over the current string for (jCurWav = 0; jCurWav < TOK_LENGTH * (MAX_RANDOM+1); jCurWav++) WordWavCombo[iCurWord][jCurWav] = WordWavCombo[iCurWord+1][jCurWav]; } } } else { // Just remove the one wav, if it exists for (jCurWav = 1; jCurWav <= MAX_RANDOM; jCurWav++) { // If an empty string, then break this loop, we're at the end if (strlen(WordWavCombo[iCurWord][TOK_LENGTH*jCurWav]) == 0) break; // Look for a Wav match if (strncmp(Wav, WordWavCombo[iCurWord][TOK_LENGTH*jCurWav], TOK_LENGTH) == 0) { for (; jCurWav <= MAX_RANDOM; jCurWav++) { // If this is the only wav entry, then remove the entry altogether if ((jCurWav == 1) && (strlen(WordWavCombo[iCurWord][TOK_LENGTH*(jCurWav+1)]) == 0)) { // Keep looping i, copying the next into the current for (; iCurWord < MAX_KEYWORDS; iCurWord++) { // If we're about to copy a string that doesn't exist, // then just erase the last string instead of copying. if (iCurWord >= MAX_KEYWORDS-1) { // Delete the last word string WordWavCombo[iCurWord][0] = 0; // We reached the end snprintf(Text, MAX_TEXT_LENGTH, "%s successfully removed.", Word); selfmessage(Text); return PLUGIN_HANDLED; } else { // Copy the next string over the current string for (jCurWav = 0; jCurWav < TOK_LENGTH * (MAX_RANDOM+1); jCurWav++) WordWavCombo[iCurWord][jCurWav] = WordWavCombo[iCurWord+1][jCurWav]; } } } // If we're about to copy a string that doesn't exist, // then just erase the last string instead of copying. if (jCurWav >= MAX_RANDOM) { // Delete the last wav string WordWavCombo[iCurWord][TOK_LENGTH*jCurWav] = 0; // We reached the end snprintf(Text, MAX_TEXT_LENGTH, "%s successfully removed from %s.", Wav, Word); selfmessage(Text); return PLUGIN_HANDLED; } else { // Copy the next string over the current string strcpy(WordWavCombo[iCurWord][TOK_LENGTH*jCurWav], WordWavCombo[iCurWord][TOK_LENGTH*(jCurWav+1)], TOK_LENGTH); } } } } // We reached the end for this word, and the wav didn't exist snprintf(Text, MAX_TEXT_LENGTH, "%s not found.", Wav); selfmessage(Text); return PLUGIN_HANDLED; } } } // We reached the end, and the word didn't exist snprintf(Text, MAX_TEXT_LENGTH, "%s not found.", Word); selfmessage(Text); return PLUGIN_HANDLED; } ////////////////////////////////////////////////////////////////////////////// // Saves the current configuration of Word/Wav combos to filename for possible // reloading at a later time. You cannot overwrite the default file. // // Usage: admin_sound_write <filename> ////////////////////////////////////////////////////////////////////////////// public admin_sound_write(HLCommand, HLData, HLUserName, UserIndex) { new savefile[MAX_DATA_LENGTH]; new User[MAX_NAME_LENGTH]; new Text[MAX_TEXT_LENGTH]; new TimeStamp[MAX_TEXT_LENGTH]; new bSuccess = 1; new i; new j; convert_string(HLData, savefile, MAX_DATA_LENGTH); convert_string(HLUserName, User, MAX_NAME_LENGTH); servertime(TimeStamp, MAX_TEXT_LENGTH, "%H:%M %B %d, %Y"); // If the filename is NULL, then that's bad. if (strlen(savefile) == 0) { selfmessage("[plugin_sank_sounds] You must specify a filename."); return PLUGIN_HANDLED; } // If the filename is the same as the default FILENAME, then that's bad. if (strcasecmp(savefile, FILENAME) == 0) { selfmessage("[plugin_sank_sounds] Illegal write to default sound config file."); selfmessage("[plugin_sank_sounds] Specify a different filename."); return PLUGIN_HANDLED; } /************ File should have the following format: ************** # TimeStamp: 07:15 January 15, 2001 # File created by: [SPU]Crazy_Chevy # Important parameters: SND_MAX; 20 SND_WARN; 17 SND_JOIN; SND_EXIT; misc\comeagain.wav # Word/Wav combinations: crap; misc\awwcrap.wav;misc\awwcrap2.wav woohoo; misc\woohoo.wav @ha ha; misc\haha.wav doh; misc\doh.wav;misc\doh2.wav;@misc\doh3.wav ******************************************************************/ // See if we have file_access_write if (getvar("file_access_write") == 0) { snprintf(Text, MAX_TEXT_LENGTH, "[plugin_sank_sounds] CVAR file_access_write is set incorrectly for admin_sound_write."); selfmessage(Text); return PLUGIN_HANDLED; } // check for other file errors if (!resetfile(savefile)) { snprintf(Text, MAX_TEXT_LENGTH, "[plugin_sank_sounds] unknown file error with %s", savefile); selfmessage(Text); return PLUGIN_HANDLED; } // We now assume that we can write to the file, so here we go! snprintf(Text, MAX_TEXT_LENGTH, "# TimeStamp:^t^t%s", TimeStamp); writefile(savefile, Text); snprintf(Text, MAX_TEXT_LENGTH, "# File created by:^t%s", User); writefile(savefile, Text); writefile(savefile, ""); // blank line writefile(savefile, "# Important parameters:"); snprintf(Text, MAX_TEXT_LENGTH, "SND_MAX;^t%d", SND_MAX); writefile(savefile, Text); snprintf(Text, MAX_TEXT_LENGTH, "SND_WARN;^t%d", SND_WARN); writefile(savefile, Text); snprintf(Text, MAX_TEXT_LENGTH, "SND_JOIN;^t%s", SND_JOIN); writefile(savefile, Text); snprintf(Text, MAX_TEXT_LENGTH, "SND_EXIT;^t%s", SND_EXIT); writefile(savefile, Text); snprintf(Text, MAX_TEXT_LENGTH, "SND_PUNISH;^t%s", SND_PUNISH); writefile(savefile, Text); snprintf(Text, MAX_TEXT_LENGTH, "SND_DELAY;^t%d", SND_DELAY); writefile(savefile, Text); snprintf(Text, MAX_TEXT_LENGTH, "SND_SPLIT;^t%d", SND_SPLIT); writefile(savefile, Text); snprintf(Text, MAX_TEXT_LENGTH, "EXACT_MATCH;^t%d", EXACT_MATCH); writefile(savefile, Text); writefile(savefile, ""); // blank line writefile(savefile, "# Word/Wav combinations:"); for (i = 0; i < MAX_KEYWORDS && bSuccess; i++) { // See if we reached the end if (strlen(WordWavCombo[i]) == 0) break; // I guess not, so format up a string to write // First, add the keyword snprintf(Text, MAX_TEXT_LENGTH, "%s;^t", WordWavCombo[i]); // Then add all the wavs for (j = 1; j < MAX_RANDOM && strlen(WordWavCombo[i][TOK_LENGTH*j]); j++) snprintf(Text, MAX_TEXT_LENGTH, "%s%s;", Text, WordWavCombo[i][TOK_LENGTH*j]); // Now write the formatted string to the file bSuccess = writefile(savefile, Text); // And loop for the next wav } snprintf(Text, MAX_TEXT_LENGTH, "[plugin_sank_sounds] Configuration successfully written to %s.", savefile); selfmessage(Text); return PLUGIN_HANDLED; } ////////////////////////////////////////////////////////////////////////////// // Checks the input variables for invalid values ////////////////////////////////////////////////////////////////////////////// ErrorCheck() { // Can't have negative delay between sounds if (SND_DELAY < 0) { log("[plugin_sank_sounds] SND_DELAY cannot be negative."); log("[plugin_sank_sounds] SND_DELAY set to default value."); SND_DELAY = 0; } // If SND_PUNISH is blank or zero, set to default command: admin_kick if (strlen(SND_PUNISH) == 0 || SND_PUNISH[0] == '0') log("[plugin_sank_sounds] SND_PUNISH set to default: admin_kick"); // If SND_MAX is zero, then sounds quota is disabled. if (SND_MAX <= 0) { SND_MAX = 0; // in case it was negative log("Sound quota disabled."); } // If SND_WARN is zero, then we can't have warning every // time a keyword is said, so we default to 3 less than max else if (SND_WARN <= 0) { if (SND_MAX > 3) SND_WARN = SND_MAX - 3; else SND_WARN = SND_MAX - 1; log("[plugin_sank_sounds] SND_WARN cannot be set to zero."); log("[plugin_sank_sounds] SND_WARN set to default value."); } // And finally, if they want to warn after a person has been // kicked, that's silly, so we'll fix it. else if (SND_MAX < SND_WARN) { if (SND_MAX > 3) SND_WARN = SND_MAX - 3; else SND_WARN = SND_MAX - 1; log("[plugin_sank_sounds] SND_WARN cannot be higher than SND_MAX."); log("[plugin_sank_sounds] SND_WARN set to default value."); } } ////////////////////////////////////////////////////////////////////////////// // Everything a person says goes through here, and we determine if we want to // play a sound or not. // // Usage: say <anything> ////////////////////////////////////////////////////////////////////////////// public HandleSay(HLCommand, HLData, HLUserName, UserIndex) { // If sounds are not enabled, then skip this whole thing if (!bSoundsEnabled) return PLUGIN_CONTINUE; new i; new Speech[MAX_DATA_LENGTH]; new User[MAX_NAME_LENGTH]; new Text[MAX_TEXT_LENGTH]; new ListIndex = -1; convert_string(HLData, Speech, MAX_DATA_LENGTH); convert_string(HLUserName, User, MAX_NAME_LENGTH); strstripquotes(Speech); if (strlen(Speech) == 0) return PLUGIN_CONTINUE; if (systemtime() - LastSoundTime < SND_DELAY) { messageex(User, "Minimum sound delay time not yet reached.", print_console); return PLUGIN_CONTINUE; } // Remove @ from user's speech, incase non-admin is trying to impersonate real admin strtrim(Speech, "@", 0); // Check to see if what the player said is a trigger for a sound for (i = 0; i < MAX_KEYWORDS; i++) { strcpy(Text, WordWavCombo[i], TOK_LENGTH); // Remove the possible @ sign from beginning (for admins only). if (access(ACCESS_ADMINSOUNDS, User)) strtrim(Text, "@", 0); if ((!strcasecmp(Speech, Text)) || // exact string match ((EXACT_MATCH == 0) && (strcasestrx(Speech, Text) != -1))) // string within string match { ListIndex = i; break; } } // If what the player said is a sound trigger, then handle it. if (ListIndex != -1) { #if DEBUG printf("Checking Quota for %s: %s in %s^n", User, Text, Speech); #endif // If the user has not exceeded their quota, then play a wav if (!QuotaExceeded(User, UserIndex)) { new rand = random(MAX_RANDOM); new timeout; new playWav[TOK_LENGTH]; new iDead; // This for loop runs around until it finds a real file to play // Defaults to the first wav file, if no file is found at random. for (timeout = MAX_RANDOM; // Initial condition timeout >= 0 && strlen(playWav) == 0; // While these are true timeout--, rand = random(MAX_RANDOM)) // Update each iteration { // If for some reason we never find a file // then default to the first wav entry if (!timeout) rand = 0; strcpy(playWav, WordWavCombo[ListIndex][(rand+1)*TOK_LENGTH], TOK_LENGTH); // If this wav was an admin-only wav, but User is not an admin, then skip this one if ((strtrim(playWav, "@", 0) == 1) && !access(ACCESS_ADMINSOUNDS, User)) playWav[0] = 0; } LastSoundTime = systemtime(); if (SND_SPLIT) { if (playerinfo(UserIndex, Text, MAX_TEXT_LENGTH, _, _, _, iDead, _) == 1) playsoundall(playWav, iDead); return PLUGIN_CONTINUE; } else { snprintf(Text, MAX_TEXT_LENGTH, "%s : %s", User, Speech); say(Text); playsoundall(playWav); return PLUGIN_HANDLED; } } } else if ((!strcasecmp(Speech, "aybabtu")) || // exact string match ((EXACT_MATCH == 0) && (strcasestrx(Speech, "aybabtu") != -1))) // string within string match { playsoundall("^"(p96) all(t20) your(t20) base(t10) are(t20) be(t40) lock(e50) handling(s70) to us us(s75) us(s75)^""); return PLUGIN_HANDLED; } return PLUGIN_CONTINUE; } ////////////////////////////////////////////////////////////////////////////// // This is called when the player leaves the console after connection is // complete. This allows the connecting player to hear the sound as well as // the players already in the game. ////////////////////////////////////////////////////////////////////////////// public HandleSpecMode(HLCommand, HLData, HLUserName, UserIndex) { playsoundall(SND_JOIN); } ////////////////////////////////////////////////////////////////////////////// // Parses the sound file specified by loadfile. If loadfile is empty, then // it parses the default FILENAME. // // Returns 0 if parsing was successful // Returns 1 if parsing failed // Returns -1 otherwise // // Usage: // admin_sound_reload <filename> ////////////////////////////////////////////////////////////////////////////// parse_sound_file(loadfile[MAX_TEXT_LENGTH] = "") { new GotLine; new iLineNum = 0; new strLineBuf[MAX_TEXT_LENGTH]; new WadOstrings[(MAX_RANDOM+1)*TOK_LENGTH]; // same as [MAX_RANDOM][TOK_LENGTH] new ListIndex = 0; new Text[MAX_TEXT_LENGTH]; /************ File should have the following format: ************** # Set the necessary variables SND_MAX; 20 SND_WARN; 17 SND_EXIT; misc\comeagain.wav # Now give the sound list crap; misc\awwcrap.wav;misc\awwcrap2.wav woohoo; misc\woohoo.wav @ha ha; misc\haha.wav doh; misc\doh.wav;misc\doh2.wav;@misc\doh3.wav ******************************************************************/ if (strlen(loadfile) == 0) { // No file specified, use default file strcpy(loadfile, FILENAME, MAX_TEXT_LENGTH); if (!fileexists(loadfile)) strcpy(loadfile, "SND-LIST.CFG", MAX_TEXT_LENGTH); // backwards compatibility } if (fileexists(loadfile)) { new i; 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, "[plugin_sank_sounds] Unable to read from %s file.", loadfile); else snprintf(Text, MAX_TEXT_LENGTH, "[plugin_sank_sounds] CVAR file_access_read is set incorrectly."); log(Text); return -1; } // Initialize WordWavCombo[][][] array before using it for(i = 0; i < MAX_KEYWORDS; i++) WordWavCombo[i][0] = 0; while (GotLine > 0) { if (ListIndex >= MAX_KEYWORDS) { log("[plugin_sank_sounds] Sound list truncated. Increase MAX_KEYWORDS."); printf("[plugin_sank_sounds] 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)) { // Take up to MAX_RANDOM wav files for each keyword, each separated by a ';' // Right now we fill the big WadOstrings[] with the information from the file. for(i = 0; i <= MAX_RANDOM; i++) strsep(strLineBuf, ";", WadOstrings[TOK_LENGTH*i], TOK_LENGTH, strLineBuf, MAX_TEXT_LENGTH); // If we finished MAX_RANDOM times, and strRest still has contents // then we should have a bigger MAX_RANDOM if(strlen(strLineBuf) != 0) { log("[plugin_sank_sounds] Sound list partially truncated. Increase MAX_RANDOM."); printf("[plugin_sank_sounds] Continuing to parse %s file.^n", loadfile); } // Now remove any spaces or tabs from around the strings -- clean them up for (i = 0; i < MAX_RANDOM; i++) strtrim(WadOstrings[TOK_LENGTH*i], " ^t"); // First look for special parameters if (!strcasecmp(WadOstrings, "SND_MAX") || !strcasecmp(WadOstrings, "SND_KICK")) // backwards compatibility SND_MAX = strtonum(WadOstrings[TOK_LENGTH*1]); else if (!strcasecmp(WadOstrings, "SND_WARN")) SND_WARN = strtonum(WadOstrings[TOK_LENGTH*1]); else if (!strcasecmp(WadOstrings, "SND_JOIN")) strcpy(SND_JOIN, WadOstrings[TOK_LENGTH*1], TOK_LENGTH); else if (!strcasecmp(WadOstrings, "SND_EXIT")) strcpy(SND_EXIT, WadOstrings[TOK_LENGTH*1], TOK_LENGTH); else if (!strcasecmp(WadOstrings, "SND_PUNISH")) strcpy(SND_PUNISH, WadOstrings[TOK_LENGTH*1], TOK_LENGTH); else if (!strcasecmp(WadOstrings, "SND_DELAY")) SND_DELAY = strtonum(WadOstrings[TOK_LENGTH*1]); else if (!strcasecmp(WadOstrings, "SND_SPLIT")) SND_SPLIT = strtonum(WadOstrings[TOK_LENGTH*1]); else if (!strcasecmp(WadOstrings, "EXACT_MATCH")) EXACT_MATCH = strtonum(WadOstrings[TOK_LENGTH*1]); // If it wasn't one of those essential parameters, then it should be // a Keyword/Wav combo, so we'll treat it as such by copying it from our // temporary structure into our global structure, WordWavCombo[][][] else { // Now we must transfer the contents of WadOstrings[] to // our global data structure, WordWavCombo[Index][] // with a really tricky "string copy" for (i = 0; i < MAX_RANDOM*TOK_LENGTH; i++) WordWavCombo[ListIndex][i] = WadOstrings[i]; ListIndex++; } } // Initialize variables for next time by clearing all the // strings in the WadOstrings[] for (i = 0; i < MAX_RANDOM; i++) WadOstrings[i*TOK_LENGTH] = 0; // Read in the next line from the file GotLine = readfile(loadfile, strLineBuf, ++iLineNum, MAX_TEXT_LENGTH); } // Now we have all of the data from the text file in our data structures. // Next we do some error checking, some setup, and we're done parsing! ErrorCheck(); // Log some info for the nosey admin snprintf(Text, MAX_TEXT_LENGTH, "[plugin_sank_sounds] Sound quota set to %i", SND_MAX); selfmessage(Text); #if DEBUG print_matrix(); printf("[plugin_sank_sounds] Done parsing %s file.^n", loadfile); #endif } else // file exists returned false, meaning the file didn't exist { snprintf(Text, MAX_TEXT_LENGTH, "[plugin_sank_sounds] Cannot find %s file.", loadfile); log(Text); selfmessage(Text); return 1; } snprintf(Text, MAX_TEXT_LENGTH, "[plugin_sank_sounds] %s successfully loaded.", loadfile); selfmessage(Text); return 0; } ////////////////////////////////////////////////////////////////////////////// // This function used to be in the SOUND.INC file, but too many people emailed // me asking where to put the sound.inc file, so I stopped using the file, as // its usefulness was outlived anyway. // // Usage: // playsoundall("misc/doh.wav"); // play // playsoundall("^"target destroyed^""); // speak ////////////////////////////////////////////////////////////////////////////// stock playsoundall(sound[], IfDead = -1) { new maxplayers = maxplayercount(); new Name[MAX_NAME_LENGTH]; new i; if (sound[0] == '^"') { for (i = 1; i <= maxplayers; i++) { new iDead; if (playerinfo(i, Name, MAX_NAME_LENGTH, _, _, _, iDead, _) == 1) { // Use the "speak" command if (IfDead == -1) speakto(Name, sound); else if (IfDead == iDead) speakto(Name, sound); } } } else { for (i = 1; i <= maxplayers; i++) { new iDead; if (playerinfo(i, Name, MAX_NAME_LENGTH, _, _, _, iDead, _) == 1) { // Use the "play" command if (IfDead == -1) playsound(Name, sound); else if (IfDead == iDead) playsound(Name, sound); } } } } #if DEBUG ////////////////////////////////////////////////////////////////////////////// // Prints out word wav combo matrix for debugging purposes. Kinda cool, even // if you're not really debugging. // // Usage: // admin_sound_debug // admin_sound_reload <filename> ////////////////////////////////////////////////////////////////////////////// public print_matrix() { printf("SND_MAX: %d^n", SND_MAX); printf("SND_WARN: %d^n", SND_WARN); printf("SND_JOIN: %s^n", SND_JOIN); printf("SND_EXIT: %s^n", SND_EXIT); printf("SND_PUNISH: %s^n", SND_PUNISH); printf("SND_DELAY: %d^n", SND_DELAY); printf("SND_SPLIT: %d^n", SND_SPLIT); printf("EXACT_MATCH: %d^n", EXACT_MATCH); new i; new j; // Print out the matrix of sound data, so we got what we think we did for (i = 0; i < MAX_KEYWORDS; i++) { if (strlen(WordWavCombo[i]) != 0) { // printf("^n"); printf("^n[%d] ^"%s^"", i, WordWavCombo[i][0]); for (j = 1; j < MAX_RANDOM+1; j++) { if (strlen(WordWavCombo[i][j*TOK_LENGTH]) != 0) // printf("[%d] [%d] ^"%s^"^n", i, j, WordWavCombo[i][j*TOK_LENGTH]); printf(" ^"%s^"", WordWavCombo[i][j*TOK_LENGTH]); } } } printf("^n"); return PLUGIN_HANDLED; } #endif ////////////////////////////////////////////////////////////////////////////// // Returns 0 if the user is allowed to say things // Returns 1 and kicks the user if the quota has been exceeded. ////////////////////////////////////////////////////////////////////////////// QuotaExceeded(User[], UserIndex) { // If the sound limitation is disabled, then return happily. if (SND_MAX == 0) return 0; // If the user is not really a user, then maybe a bot, maybe a bug...? if (UserIndex < 1 || UserIndex > MAX_PLAYERS) return 0; new Text[MAX_TEXT_LENGTH] = ""; new HowManyLeft = SND_MAX - SndCount[UserIndex]; if (check_immunity(User) == 0) { // Increment their playsound count SndCount[UserIndex] = SndCount[UserIndex] + 1; if (SndCount[UserIndex] >= SND_MAX) { message(User, "You were warned, but did not quit playing sounds"); snprintf(Text, MAX_TEXT_LENGTH, "Punished %s for saying too much", User); say(Text); if (strlen(SND_PUNISH)!=0) { g_User[UserIndex]=1; //If we have custom SND_PUNISH command, then try to execute it if (getvar("file_access_write") == 0) { //If custom punish specified, but file access write is set incorrectly... snprintf(Text, MAX_TEXT_LENGTH, "[plugin_sank_sounds] CVAR file_access_write is set incorrectly for SND_PUNISH."); log(Text); kick(User); } else { if(!fileexists(punishfile)){ //If custom punish specified, then check each file access function snprintf(Text, MAX_TEXT_LENGTH, "admin_command snd_punish"); if (!writefile(punishfile, Text,1)) { log("[plugin_sank_sounds] unknown file error while executing SND_PUNISH command"); kick(User); }else{ snprintf(Text, MAX_TEXT_LENGTH, "exec %s", punishfile); exec(Text); } } else { snprintf(Text, MAX_TEXT_LENGTH, "exec %s", punishfile); exec(Text); } } } else { //If we have no custom SND_PUNISH command, then use the default kick kick(User); } return 1; } else if (SndCount[UserIndex] >= SND_WARN) { messageex(User, "You have almost used up your sound quota. Stop.", print_center); messageex(User, "You have almost used up your sound quota. Stop.", print_console); snprintf(Text, MAX_TEXT_LENGTH, "You have %d left before you get punished.", HowManyLeft); messageex(User, Text, print_center); messageex(User, Text, print_console); } } return 0; } public snd_punish(HLCommand,HLData,HLUserName,UserIndex) { new Player[MAX_NAME_LENGTH]; new i; new maxplayers=maxplayercount(); for(i=1;i<=maxplayers;i++){ if(g_User[i]==1){ if(playerinfo(i,Player,MAX_NAME_LENGTH)){ plugin_exec(SND_PUNISH,Player); g_User[i]=0; break; } } } return PLUGIN_HANDLED; }