Persnickety
Active member
- Joined
- Dec 28, 2005
- RedCents
- 0¢
This is a combination of Kuv's MQ2CustomSound and my own MQ2CustomPopup, and now has the ability to display most chat that would otherwise be missed while zoning. This plugin will read all incomming chat and search for matches that the user has specified in the INI file. If a match is found, it will either display an overlay popup on the screen, or play a sound, or both.
Reasons to use this for custom sounds instead of EQ's built-in Audio Triggers:
1. You can hear tell sounds even while zoning (if you set it to look for tells). This works for both normal tells and cross-server tells.
2. Tells from NPCs can be automatically filtered out.
3. It will not play tell sounds unless the text is the user-defined color for tells, or tell-echoes. This means the sound wont trigger if someone says "/gu blahblah tells you blahblah".
In game commands:
/togglepopups : Toggles displaying of custom popups
/togglesounds : Toggles playing of custom sounds
/toggleNPCtellfilter : Toggles the automatic filtering out of tells from an NPC
/missedChatEcho : Toggles echoing of missed chat to your MQ window.
/missedChatPopup : Toggles popup notification after missing chat while zoning.
/sound <key> : Plays the sound from the specified key in the INI file
/chatevents : Displays the in game commands and shows the current settings
MQ2ChatEvents.cpp
Most of the stuff in the INI should be self-explanatory, but I'll describe some of it here anyway.
[Settings]
This stores your toggle settings for sounds, popups, and missed chat echoes/popups.
[Events]
This is the section to list keys to identify events. These key names are just labels for use in the other sections. Separate each key with a | .
[MatchStrings]
This section contains the actual text you want to look for.
[Sounds]
This section contains the path to the sound file you want to play when the text from MatchStrings is found. If nothing is listed for a key, no sound will play. Note that you have to include double backspaces in the path. Example: c:\\mq2\\sounds\\soundfile.wav
[Popups]
This section contains the text that you want displayed as a popup when a match is found. If you set the text to FULLTEXT, it will popup the entire line of text that it finds (helpful when a mob is gating, so you can see the mob's name). If nothing is listed, nothing will popup.
[TextColor]
This section determines what color the popup text is. Included in the INI are examples of which numbers for which colors you can use. If nothing is listed, default color is 15 (yellow).
[DisplayDuration]
This section sets how long the popup will stay on your screen, in milliseconds. 1000 = 1 second. 10000 = 10 seconds, etc. If nothing is listed, default duration is 3000 (3 seconds).
MQ2ChatEvents.ini
Some of the code in here might be a little redundant or unnecessary. I just smushed this together last night and today. I'm sure a lot of it can be cleaned up. I want to eventually add another option to do custom commands when certain chat text is found. Other than that I'm open to suggestions.
Reasons to use this for custom sounds instead of EQ's built-in Audio Triggers:
1. You can hear tell sounds even while zoning (if you set it to look for tells). This works for both normal tells and cross-server tells.
2. Tells from NPCs can be automatically filtered out.
3. It will not play tell sounds unless the text is the user-defined color for tells, or tell-echoes. This means the sound wont trigger if someone says "/gu blahblah tells you blahblah".
In game commands:
/togglepopups : Toggles displaying of custom popups
/togglesounds : Toggles playing of custom sounds
/toggleNPCtellfilter : Toggles the automatic filtering out of tells from an NPC
/missedChatEcho : Toggles echoing of missed chat to your MQ window.
/missedChatPopup : Toggles popup notification after missing chat while zoning.
/sound <key> : Plays the sound from the specified key in the INI file
/chatevents : Displays the in game commands and shows the current settings
MQ2ChatEvents.cpp
Rich (BB code):
/*
MQ2ChatEvents.cpp
by Persnickety
1-30-2006
Credit to Kuv for his MQ2CustomSound plugin on which this was based
-----------------
Usage:
/togglepopups : Toggles displaying of custom popups
/togglesounds : Toggles playing of custom sounds
/toggleNPCtellfilter : Toggles the automatic filtering out of tells from an NPC
/MissedChatEcho : Toggles echoing of missed chat to MQ window
/MissedChatPopup : Toggles popup notification after missing chat while zoning
/sound <key> : Plays the sound from the specified key in the INI file
/chatevents : Displays the in game commands and shows the current settings
*/
#include "../MQ2Plugin.h"
#include <mmsystem.h>
#include <vector>
#pragma comment(lib,"winmm.lib")
vector<string> events;
vector<string> matchStrings;
vector<string> sounds;
vector<string> popups;
vector<string> textColor;
vector<string> displayDuration;
CHAR soundPath[MAX_STRING] = {0};
CHAR popupText[MAX_STRING] = {0};
DWORD popupColor = 0;
DWORD popupTransparency = 100;
DWORD popupFadeIn = 500;
DWORD popupFadeOut = 500;
DWORD popupHold = 3000;
bool popupsEnabled = true;
bool soundsEnabled = true;
bool npcTellFilter = true;
bool missedChatPopup = true;
bool missedChatEcho = true;
bool tellFlag = false;
PreSetup("MQ2ChatEvents");
string GetOnOffLabel( bool val )
{
string s;
if( val ) s = "\agON\ax";
else s = "\auOFF\ax";
return s;
}
// IsNpc - checks for a spawn in the current zone by name and returns TRUE if it is an NPC
bool IsNpc( string strSpawnName )
{
// NPC check: cycle through spawn list
PSPAWNINFO pSpawn = (PSPAWNINFO)pSpawnList;
while (pSpawn){
string tmpName (pSpawn->Name);
if ( tmpName.find(strSpawnName) != string::npos ){
// Found a name match - check if it's an NPC
if ( pSpawn->Type != 0 )
return true;
}
pSpawn = pSpawn->pNext;
}
return false;
}
// InitEvents - loads custom events and match strings from INI file
void InitEvents()
{
CHAR tempSetting[MAX_STRING];
GetPrivateProfileString("Settings","PopupsEnabled","TRUE",tempSetting,MAX_STRING,INIFileName);
if(!strnicmp(tempSetting,"true",4) || !strnicmp(tempSetting,"on",2) || !strnicmp(tempSetting,"1",1)) popupsEnabled = true;
else popupsEnabled = false;
GetPrivateProfileString("Settings","SoundsEnabled","TRUE",tempSetting,MAX_STRING,INIFileName);
if(!strnicmp(tempSetting,"true",4) || !strnicmp(tempSetting,"on",2) || !strnicmp(tempSetting,"1",1)) soundsEnabled = true;
else soundsEnabled = false;
GetPrivateProfileString("Settings","NPCTellFilter","TRUE",tempSetting,MAX_STRING,INIFileName);
if(!strnicmp(tempSetting,"true",4) || !strnicmp(tempSetting,"on",2) || !strnicmp(tempSetting,"1",1)) npcTellFilter = true;
else npcTellFilter = false;
GetPrivateProfileString("Settings","MissedChatEcho","TRUE",tempSetting,MAX_STRING,INIFileName);
if(!strnicmp(tempSetting,"true",4) || !strnicmp(tempSetting,"on",2) || !strnicmp(tempSetting,"1",1)) missedChatEcho = true;
else missedChatEcho = false;
GetPrivateProfileString("Settings","MissedChatPopup","TRUE",tempSetting,MAX_STRING,INIFileName);
if(!strnicmp(tempSetting,"true",4) || !strnicmp(tempSetting,"on",2) || !strnicmp(tempSetting,"1",1)) missedChatPopup = true;
else missedChatPopup = false;
CHAR szAllKeys[MAX_STRING] = {0};
GetPrivateProfileString("Events","keys","MQ2CustomSound_Error",szAllKeys,MAX_STRING,INIFileName);
string strAllKeys( szAllKeys );
string::size_type pos = strAllKeys.find("|",0);
while (pos != string::npos )
{
// Add event name to events vector
string strTempEvent = strAllKeys.substr(0, pos);
events.push_back( strTempEvent );
// Get event match string from INI
CHAR szMatchString[MAX_STRING] = {0};
GetPrivateProfileString("MatchStrings",strTempEvent.c_str(),"MQ2ChatEvents_Error",szMatchString,MAX_STRING,INIFileName);
string strTempMatch ( szMatchString );
matchStrings.push_back( strTempMatch );
// Get sound file from INI
CHAR szSound[MAX_STRING] = {0};
GetPrivateProfileString("Sounds",strTempEvent.c_str(),"MQ2ChatEvents_Error",szSound,MAX_STRING,INIFileName);
string strTempSound ( szSound );
sounds.push_back( strTempSound );
// Get popup message from INI
CHAR szPopup[MAX_STRING] = {0};
GetPrivateProfileString("Popups",strTempEvent.c_str(),"MQ2ChatEvents_Error",szPopup,MAX_STRING,INIFileName);
string strTempPopup ( szPopup );
popups.push_back( strTempPopup );
// Get popup text color from INI
CHAR szTextColor[MAX_STRING] = {0};
GetPrivateProfileString("TextColor",strTempEvent.c_str(), "15",szTextColor,MAX_STRING,INIFileName);
string strTempTextColor ( szTextColor );
textColor.push_back( strTempTextColor );
// Get popup display duration from INI
CHAR szDisplayDuration[MAX_STRING] = {0};
GetPrivateProfileString("DisplayDuration",strTempEvent.c_str(),"3000",szDisplayDuration,MAX_STRING,INIFileName);
string strTempDisplayDuration ( szDisplayDuration );
displayDuration.push_back( strTempDisplayDuration );
// Erase command from AllKeys variable (so we process the next one on next loop)
strAllKeys.erase(0, pos + 1);
pos = strAllKeys.find("|");
}
}
PLUGIN_API DWORD OnIncomingChat(PCHAR Line, DWORD Color)
{
// DebugSpewAlways("MQ2ChatEvents::OnIncomingChat(%s)",Line);
// Only process events if in-game
if (MQ2Globals::gGameState != GAMESTATE_INGAME)
return 0;
string strLine ( Line );
string::size_type pos;
// Process all popup events for matches
for( unsigned int i = 0; i < events.size(); i++ )
{
pos = strLine.find(matchStrings,0);
if ( pos != string::npos ) {
//process popups
sprintf( popupText, "%s", popups.c_str() );
if( popupsEnabled && strcmp( popupText, "MQ2ChatEvents_Error") != 0 ){
popupColor = 0x00 + atoi( textColor.c_str() ) ;
popupHold = (DWORD) atoi( displayDuration.c_str() ); //convert string to int, cast as dword
if( strcmp( popupText, "FULLTEXT") == 0 ){ //if default is defined, display full chat line
strcpy( popupText, Line);
}
DisplayOverlayText(popupText, popupColor, popupTransparency, popupFadeIn, popupFadeOut,popupHold);
}
sprintf( soundPath, "%s", sounds.c_str() );
//process sounds
if( soundsEnabled && strcmp( soundPath, "MQ2ChatEvents_Error") != 0 ){
// Special handling for "tells"
// Should only play sounds if the tell came from a player
if( ( matchStrings.find("tells you") != string::npos)
|| (matchStrings.find("told you") != string::npos)
|| (matchStrings.find("You tell") != string::npos)
|| (matchStrings.find("You told") != string::npos) ) {
// Only need to check if the source is a player if color is USERCOLOR_TELL
if(Color == USERCOLOR_TELL || Color == USERCOLOR_ECHO_TELL) {
if(npcTellFilter){
string strName = strLine.substr(0, pos - 1); // Get tell source
if( IsNpc(strName) ) return 0; // NPC check
}
// Special handling for suspend minion: unsuspend
// Because the pet is not actually in the spawn list when the tell from it
// is received, IsNpc does not catch it - so just filter based on the
// unsuspend message here.
if( strLine.find("tells you, 'I live again...'") != string::npos ) return 0;
}
else return 0;
} // END special 'tells' handling
PlaySound(sounds.c_str(),NULL,SND_FILENAME | SND_ASYNC);
}
}
}
if (!gbInZone && missedChatEcho) {
pos = strLine.find(" tells ",0);
if ( pos != string::npos ) {
WriteChatColor( Line,Color);
tellFlag = true;
}
pos = strLine.find(" told ",0);
if ( pos != string::npos ) {
WriteChatColor( Line,Color);
tellFlag = true;
}
}
//Check for entered a new zone
pos = strLine.find("You have entered ",0);
if ( pos != string::npos && Color == 273) {
if(tellFlag && missedChatPopup) {
DisplayOverlayText( "You missed some chat while zoning! Check MQ window.",
CONCOLOR_YELLOW, 100, 500, 500, 10000);
tellFlag = false;
}
}
return 0;
}
// PlaySound - plays sound events when using the /sound command
// Inspired by the MQ2PlaySound plug-in by Digitalxero
void PlaySoundCmd(PSPAWNINFO pChar, PCHAR szLine)
{
CHAR szSoundName[MAX_STRING] = {0};
CHAR szSoundFile[MAX_STRING] = {0};
// Get sound file from INI
GetArg(szSoundName,szLine,1);
GetPrivateProfileString("Sounds",szSoundName,"default",szSoundFile,MAX_STRING,INIFileName);
if ( !stricmp( szSoundName, "MQ2ChatEvents_Error" )) return;
if ( stricmp( szSoundName, "stop" ) == 0 ) {
PlaySound(NULL,NULL,SND_ASYNC);
} else {
PlaySound(szSoundFile,NULL,SND_FILENAME | SND_ASYNC);
}
}
void TogglePopupsCmd(PSPAWNINFO pChar, PCHAR szLine)
{
CHAR tempString[MAX_STRING];
popupsEnabled = !popupsEnabled;
if(popupsEnabled) sprintf(tempString,"TRUE");
else sprintf(tempString, "FALSE");
WritePrivateProfileString("Settings","PopupsEnabled",tempString,INIFileName);
string enabledTxt = GetOnOffLabel(popupsEnabled);
sprintf(tempString,"Custom popups are now: %s", enabledTxt.c_str());
WriteChatColor(tempString);
if( popupsEnabled == 1) InitEvents();
}
void ToggleSoundsCmd(PSPAWNINFO pChar, PCHAR szLine)
{
CHAR tempString[MAX_STRING];
soundsEnabled = !soundsEnabled;
if(soundsEnabled) sprintf(tempString,"TRUE");
else sprintf(tempString, "FALSE");
WritePrivateProfileString("Settings","SoundsEnabled",tempString,INIFileName);
string enabledTxt = GetOnOffLabel(soundsEnabled);
sprintf(tempString,"Custom sound effects are now: %s", enabledTxt.c_str());
WriteChatColor(tempString);
if( soundsEnabled == 1) InitEvents();
}
// ToggleNpcTellFilter - toggles the NPC tell filter
// TRUE/ON = no tell sound events if source is an NPC
// FALSE/OFF = no special handling for tells - any match will fire sound events
void ToggleNpcTellFilterCmd(PSPAWNINFO pChar, PCHAR szLine)
{
CHAR tempString[MAX_STRING];
npcTellFilter = !npcTellFilter;
if(npcTellFilter) sprintf(tempString,"TRUE");
else sprintf(tempString, "FALSE");
WritePrivateProfileString("Settings","NPCTellFilter",tempString,INIFileName);
string enabledTxt = GetOnOffLabel(npcTellFilter);
sprintf(tempString,"NPC tell sound filter is now: %s",enabledTxt.c_str());
WriteChatColor("NPC tell sound filter suppresses tell events if the source is an NPC.");
WriteChatColor(tempString);
if( npcTellFilter == 1) InitEvents();
}
void ToggleMissedChatEchoCmd(PSPAWNINFO pChar, PCHAR szLine)
{
CHAR tempString[MAX_STRING];
missedChatEcho = !missedChatEcho;
if(missedChatEcho) sprintf(tempString,"TRUE");
else sprintf(tempString, "FALSE");
WritePrivateProfileString("Settings","MissedChatEcho",tempString,INIFileName);
string enabledTxt = GetOnOffLabel(missedChatEcho);
sprintf(tempString,"Missed Chat Echoing to MQ window is now: %s",enabledTxt.c_str());
WriteChatColor(tempString);
if( missedChatEcho == 1) InitEvents();
}
void ToggleMissedChatPopupCmd(PSPAWNINFO pChar, PCHAR szLine)
{
CHAR tempString[MAX_STRING];
missedChatPopup = !missedChatPopup;
if(missedChatPopup) sprintf(tempString,"TRUE");
else sprintf(tempString, "FALSE");
WritePrivateProfileString("Settings","MissedChatPopup",tempString,INIFileName);
string enabledTxt = GetOnOffLabel(missedChatPopup);
sprintf(tempString,"Missed Chat Popups are now: %s",enabledTxt.c_str());
WriteChatColor(tempString);
if( missedChatPopup == 1) InitEvents();
}
void ChatEventsHelpCmd(PSPAWNINFO pChar, PCHAR szLine)
{
char szTemp[MAX_STRING];
string tempStr;
WriteChatColor(" --------------------------------", CONCOLOR_LIGHTBLUE);
WriteChatColor("Custom Chat Events ", CONCOLOR_LIGHTBLUE);
WriteChatColor("by Persnickety ", CONCOLOR_LIGHTBLUE);
WriteChatColor(" --------------------------------", CONCOLOR_LIGHTBLUE);
tempStr = GetOnOffLabel(popupsEnabled);
sprintf(szTemp,"/TogglePopups (%s)", tempStr.c_str() );
WriteChatColor(szTemp);
tempStr = GetOnOffLabel(soundsEnabled);
sprintf(szTemp,"/ToggleSounds (%s)", tempStr.c_str() );
WriteChatColor(szTemp);
tempStr = GetOnOffLabel(npcTellFilter);
sprintf(szTemp,"/ToggleNPCTellFilter (%s)", tempStr.c_str() );
WriteChatColor(szTemp);
tempStr = GetOnOffLabel(missedChatEcho);
sprintf(szTemp,"/MissedChatEcho (%s)", tempStr.c_str() );
WriteChatColor(szTemp);
tempStr = GetOnOffLabel(missedChatPopup);
sprintf(szTemp,"/MissedChatPopup (%s)", tempStr.c_str() );
WriteChatColor(szTemp);
WriteChatColor(" --------------------------------", CONCOLOR_LIGHTBLUE);
}
PLUGIN_API VOID InitializePlugin(VOID)
{
DebugSpewAlways("Initializing MQ2ChatEvents");
AddCommand("/togglepopups",TogglePopupsCmd);
AddCommand("/sound",PlaySoundCmd);
AddCommand("/togglesounds",ToggleSoundsCmd);
AddCommand("/npctellfilter",ToggleNpcTellFilterCmd);
AddCommand("/MissedChatEcho",ToggleMissedChatEchoCmd);
AddCommand("/MissedChatPopup",ToggleMissedChatPopupCmd);
AddCommand("/chatevents",ChatEventsHelpCmd);
InitEvents();
}
PLUGIN_API VOID ShutdownPlugin(VOID)
{
DebugSpewAlways("Shutting down MQ2ChatEvents");
RemoveCommand("/togglepopups");
RemoveCommand("/sound");
RemoveCommand("/togglesounds");
RemoveCommand("/npctellfilter");
RemoveCommand("/MissedChatEcho");
RemoveCommand("/MissedChatPopup");
RemoveCommand("/chatevents");
}
Most of the stuff in the INI should be self-explanatory, but I'll describe some of it here anyway.
[Settings]
This stores your toggle settings for sounds, popups, and missed chat echoes/popups.
[Events]
This is the section to list keys to identify events. These key names are just labels for use in the other sections. Separate each key with a | .
[MatchStrings]
This section contains the actual text you want to look for.
[Sounds]
This section contains the path to the sound file you want to play when the text from MatchStrings is found. If nothing is listed for a key, no sound will play. Note that you have to include double backspaces in the path. Example: c:\\mq2\\sounds\\soundfile.wav
[Popups]
This section contains the text that you want displayed as a popup when a match is found. If you set the text to FULLTEXT, it will popup the entire line of text that it finds (helpful when a mob is gating, so you can see the mob's name). If nothing is listed, nothing will popup.
[TextColor]
This section determines what color the popup text is. Included in the INI are examples of which numbers for which colors you can use. If nothing is listed, default color is 15 (yellow).
[DisplayDuration]
This section sets how long the popup will stay on your screen, in milliseconds. 1000 = 1 second. 10000 = 10 seconds, etc. If nothing is listed, default duration is 3000 (3 seconds).
MQ2ChatEvents.ini
Rich (BB code):
[Settings]
SoundsEnabled=TRUE
PopupsEnabled=TRUE
NPCTellFilter=TRUE
MissedChatEcho=TRUE
MissedChatPopup=TRUE
[Events]
keys=tells|told|youtell|youtold|OMMGaze|gate|Vish|GoM|Bloodeye|
[MatchStrings]
tells=tells you
told=told you
youtell=You tell
youtold=You told
OMMGaze=You feel a gaze of deadly power focusing on you.
gate=begins to cast the gate spell.
Vish=You sense your doom approaching
GoM=You have been granted a gift of mana!
Bloodeye=A dire disease creeps through your veins
[Sounds]
tells=c:\\mq2\\sounds\\message-inbound.wav
told=c:\\mq2\\sounds\\message-inbound.wav
youtell=c:\\mq2\\sounds\\message-outbound.wav
youtold=c:\\mq2\\sounds\\message-outbound.wav
kill=c:\\mq2\\sounds\\ding.wav
GoM=c:\\mq2\\sounds\\hoo-ah1.wav
OMMGaze=c:\\mq2\\sounds\\gaze.wav
Vish=c:\\mq2\\sounds\\deathtouch.wav
Bloodeye=c:\\mq2\\sounds\\deathtouch.wav
[Popups]
OMMGaze=!!! GAZE !!! Click your mask now! ~~~
Vish=~~~~~~~~~~~!!! Creeping Doom !!!~~~~~~~~~~
GoM=~~ Gift of Mana! ~~
Bloodeye=~~ CURSED with DT ~~
gate=FULLTEXT
;--Examples for TextColors--
;DARKGREY 1
;DARKGREEN 2
;DARKBLUE 4
;PURPLE 5
;LIGHTGREY 6
;WHITE 7
;RED 13
;GREEN 14
;YELLOW 15
;BLUE 16
;LIGHTBLUE 18
;BLACK 20
[TextColor]
OMMGaze=14
Vish=13
[DisplayDuration]
OMMGaze=7000
Vish=10000
Some of the code in here might be a little redundant or unnecessary. I just smushed this together last night and today. I'm sure a lot of it can be cleaned up. I want to eventually add another option to do custom commands when certain chat text is found. Other than that I'm open to suggestions.
Last edited:

