Die fettgedruckte 40 könnt ihr nach belieben ändern. Das ist die Anzahl der Sounds, die man auf dem Server abfragen kann...
/***************************************************************************
* plugin_sank_sounds.sma
* Author: Luke Sankey
* Date: March 21, 2001 - Original hard-coded version
* Date: July 2, 2001 - Rewrote to be text file configurable
* Date: 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.
* Last Updated: January 19, 2001
*
* 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. If it finds it can't read the file, it
* will automagically set file_access_read to 1 and then set it back to 0
* when it's done.
*
* 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. When that fails (and it will, because
* I'm the one who wrote it) then please see the adminmod forums at
*
http://www.adminmod.org If they still fail you, email Bill Bateman.
* As a very last final resort, email me:
sank@spu.edu
*
* I hope you enjoy this new functionality on the old plugin_sank_sounds!
*
* Luke Sankey
*
sank@spu.edu
***************************************************************************/
// 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_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] = "SND-LIST.CFG"; // Name of file to parse.
#define
MAX_KEYWORDS 40 // Maximum number of keywords
#define MAX_RANDOM 10 // Maximum number of wavs per keyword
#define TOK_LENGTH 30 // 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.51";
/****************************************************************************/
/* 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_KICK = 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] = "";
/* 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
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
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("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.");
#if DEBUG
plugin_registercmd("admin_sound_debug", "print_matrix", ACCESS_SOUND, "admin_sound_debug");
#endif
parse_sound_file(FILENAME);
return PLUGIN_CONTINUE;
}
public plugin_connect(HLUserName, HLIP, UserIndex)
{
playsoundall(SND_JOIN);
if (UserIndex >= 1 && UserIndex <= MAX_PLAYERS)
SndCount[UserIndex] = 0;
return PLUGIN_CONTINUE;
}
public plugin_disconnect(HLUserName, UserIndex)
{
if (UserIndex >= 1 && UserIndex <= MAX_PLAYERS)
SndCount[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);
// 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>^"");
return PLUGIN_HANDLED;
}
// First look for special parameters
if (!strcasecmp(Word, "SND_KICK"))
{
SND_KICK = 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_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
) == 0)
break;
// If we find a match, then add on the new wav data
if(strncmp(Word, WordWavCombo, 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[TOK_LENGTH*j]) == 0)
break;
// See if this is the same as the new wav
if(strncmp(Wav, WordWavCombo[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[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[TOK_LENGTH*0], Word, TOK_LENGTH);
strcpy(WordWavCombo[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) == 0) || (strlen(WordWavCombo) > TOK_LENGTH) )
break;
if ( (WordWavCombo[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 disabled!");
playsoundall("misc\awwcrap.wav");
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 enabled!");
playsoundall("misc\woohoo.wav");
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("Sound Plugin >> 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("Sound Plugin >> Illegal write to default sound config file.");
selfmessage("Sound Plugin >> 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_KICK; 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 (!resetfile(savefile))
{
snprintf(Text, MAX_TEXT_LENGTH, "Sound Plugin >> Cannot write to %s", savefile);
selfmessage(Text);
selfmessage("Sound Plugin >> Make sure file_access_write is set to 1.");
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_KICK;^t%d", SND_KICK);
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_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, "Sound Plugin >> 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("Sound Plugin >> SND_DELAY cannot be negative.");
log(" >> SND_DELAY set to default value.");
SND_DELAY = 0;
}
// If SND_KICK is zero, then sounds quota is disabled.
if (SND_KICK <= 0)
{
SND_KICK = 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_KICK > 3)
SND_WARN = SND_KICK - 3;
else
SND_WARN = SND_KICK - 1;
log("Sound Plugin >> SND_WARN cannot be set to zero.");
log(" >> 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_KICK < SND_WARN)
{
if (SND_KICK > 3)
SND_WARN = SND_KICK - 3;
else
SND_WARN = SND_KICK - 1;
log("Sound Plugin >> SND_WARN cannot be higher than SND_KICK.");
log(" >> SND_WARN set to default value.");
}
}
//////////////////////////////////////////////////////////////////////////////
// This function exists in order to call parse_sound_file from a timer, which
// becomes necessary when file_access_read is set to 0.
//////////////////////////////////////////////////////////////////////////////
public parse_file_timer(Timer, Repeat, HLUser, HLParam)
{
new param[MAX_TEXT_LENGTH];
convert_string(HLParam, param, MAX_TEXT_LENGTH);
parse_sound_file(param);
return PLUGIN_HANDLED;
}
//////////////////////////////////////////////////////////////////////////////
// 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[] = "")
{
new GotLine;
new iLineNum = 0;
new strLineBuf[MAX_TEXT_LENGTH];
new WadOstrings[MAX_RANDOM*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_KICK; 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)
strcpy(loadfile, FILENAME, MAX_TEXT_LENGTH);
if (fileexists(loadfile) > 0)
{
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, "Sound Plugin >> Unable to read from %s file.", loadfile);
log(Text);
selfmessage(Text);
// If we set the file access last time, then set it back
get_serverinfo("SNDSetAccess", Text, MAX_TEXT_LENGTH);
if(strcmp(Text, "1") == 0)
exec("file_access_read 0");
set_serverinfo("SNDSetAccess", "0");
return 1;
}
// else set it correctly and try again
exec("file_access_read 1");
// flag ourselves to set it back later
set_serverinfo("SNDSetAccess", "1");
set_timer("parse_file_timer", 1, 0, loadfile);
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("Sound Plugin >> Sound list truncated. Increase MAX_KEYWORDS.");
printf("Sound Plugin >> 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("Sound Plugin >> Sound list partially truncated. Increase MAX_RANDOM.");
printf("Sound Plugin >> 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_KICK"))
SND_KICK = 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_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, "Sound quota set to %i", SND_KICK);
log(Text);
#if DEBUG
print_matrix();
printf("Sound Plugin >> Done parsing %s file.^n", loadfile);
#endif
}
else // file exists returned false, meaning the file didn't exist
{
snprintf(Text, MAX_TEXT_LENGTH, "Sound Plugin >> Cannot find %s file.", loadfile);
log(Text);
selfmessage(Text);
return 1;
}
// If we set the file access last time, then set it back
get_serverinfo("SNDSetAccess", Text, MAX_TEXT_LENGTH);
if(strcmp(Text, "1") == 0)
{
exec("file_access_read 0");
set_serverinfo("SNDSetAccess", "0");
}
snprintf(Text, MAX_TEXT_LENGTH, "Sound Plugin >> %s successfully loaded.", loadfile);
log(Text);
selfmessage(Text);
return 0;
}
#if DEBUG
//////////////////////////////////////////////////////////////////////////////
// Prints out word wav combo matrix for debugging purposes. Kinda cool, even
// if you're not really debugging.
//
// Usage: admin_sound_debug
// Usage: admin_sound_reload <filename>
//////////////////////////////////////////////////////////////////////////////
public print_matrix()
{
printf("SND_WARN: %d^n", SND_WARN);
printf("SND_KICK: %d^n", SND_KICK);
printf("SND_JOIN: %s^n", SND_JOIN);
printf("SND_EXIT: %s^n", SND_EXIT);
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_KICK == 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_KICK - SndCount[UserIndex];
if (check_immunity(User) == 0)
{
if (SndCount[UserIndex] >= SND_KICK)
{
message(User, "You were warned, but did not quit playing sounds");
snprintf(Text, MAX_TEXT_LENGTH, "Kicked %s for saying too much", User);
say(Text);
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 kicked.", HowManyLeft);
messageex(User, Text, print_center);
messageex(User, Text, print_console);
}
// Increment their playsound count
SndCount[UserIndex] = SndCount[UserIndex] + 1;
}
return 0;
}
//////////////////////////////////////////////////////////////////////////////
// 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 (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 playFile[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(playFile) == 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(playFile, 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(playFile, "@", 0) == 1) && !access(ACCESS_ADMINSOUNDS, User) )
playFile[0] = 0;
}
LastSoundTime = systemtime();
if (SND_SPLIT)
{
new dummy;
if (playerinfo(UserIndex, Text, MAX_TEXT_LENGTH, dummy, dummy, dummy, iDead) == 1)
playsoundall(playFile, iDead);
return PLUGIN_CONTINUE;
}
else
{
snprintf(Text, MAX_TEXT_LENGTH, "%s : %s", User, Speech);
say(Text);
playsoundall(playFile);
return PLUGIN_HANDLED;
}
}
}
return PLUGIN_CONTINUE;
}
//////////////////////////////////////////////////////////////////////////////
// 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.
//////////////////////////////////////////////////////////////////////////////
stock playsoundall(sound[], IfDead = -1)
{
new maxplayers = maxplayercount();
new Name[MAX_NAME_LENGTH];
new i;
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)
playsound(Name, sound);
else if (IfDead == iDead)
playsound(Name, sound);
}
}
}