Looks like HighV has already done most of the groundwork for you, though he's not showing some of the code involved, particularly with tell interception/checking. Anyway, here's the post I finsihed typing up before I reloaded the page to see his post.
'>
=============
You do know SIMTools is almost entirely just chat functions, right? The overhead involved with installing just !ignore/unignore will be nearly as great as installing the whole thing. The bigger potential issue is with compiling, since the identifiers in it are so numerous that it comes close to breaking the standard bioware compiler by itself, even before you add other module scripts on the events it uses. If you're already using an improved compiler, that's a non-issue.
Further, you can't use this particular method with the standard bioware chat event, for a couple of reasons. First, you need the player to be able to target his tormentor. That involves either having them being in the same area (not likely to be the case all that often, depending on mod size) and use of an item, which involves borrowing a LOT of other SIMTools architecture, or using tell targeting, which the default bioware chat event cannot do - only the NWNX-based chat event can. Likewise, you also need to be able to intercept and suppress offending tells, which the bioware event just can't do.
If you want to elaborate on your reasons for not wanting to use the whole scriptset, I could probably give you better advice, but using it all is by far the simplest approach, for reasons you'll see below.
There are two scripts you'll want to look at. fky_chat has the overall structure breaking down chat.
//::////////////////////////////////////////////////////////////////////////:://
//:: SIMTools V3.0 Speech Integration & Management Tools Version 3.0 :://
//:: Created By: FunkySwerve :://
//:: Created On: April 4 2006 :://
//:: Last Updated: March 27 2007 :://
//:: With Thanks To: :://
//:: Dumbo - for his amazing plugin :://
//:: Virusman - for Linux versions, and for the reset plugin, and for :://
//:: his excellent events plugin, without which this update would not :://
//:: be possible :://
//:: Dazzle - for his script samples :://
//:: Butch - for the emote wand scripts :://
//:: The DMFI project - for the languages conversions and many of the emotes:://
//:: Lanessar and the players of the Myth Drannor PW - for the new languages:://
//:: The players and DMs of Higher Ground for their input and playtesting :://
//::////////////////////////////////////////////////////////////////////////:://
#include "fky_chat_inc"
void main()
{
//////////////////////////////////Declarations//////////////////////////////////
object oPC = OBJECT_SELF, oTarget;// Speaker = oPC
string sText, sLogMessage, sLogMessageTarget, sType, sSort;
int nChannel, nTarget;
/////////////////////////Gather Message and Target Data/////////////////////////
SetLocalString(oPC, "NWNX!CHAT!TEXT", Speech_GetSpacer()); // Query for chattext
sText = GetLocalString(oPC, "NWNX!CHAT!TEXT"); // Get chattext
nChannel = StringToInt(GetStringLeft(sText, 2)); // Get channel
nTarget = StringToInt(GetSubString(sText, 2, 10)); // Target ID - Return value of -1 is no target. IE, not a tell/privatemessage
sText = GetStringRight(sText, GetStringLength(sText) - 12);// Remove Target & Channel Info
if( nTarget != -1 )// Acquire possible target
{
oTarget = Speech_GetPlayer(nTarget);
sLogMessageTarget = "->" + GetName(oTarget) + "(" + GetPCPlayerName(oTarget) + ")";
///////////////////////////////////DM Stealth///////////////////////////////////
if (GetLocalInt(oTarget, "FKY_CHAT_DMSTEALTH") && (oTarget != oPC)) {DoStealth(oPC, oTarget, sText, nChannel, sLogMessageTarget); return;}
}
sType = GetSubString(sText, 0, 1);//this is the primary sorting string, the leftmost letter of the text
///////////////////////////////Command Completion///////////////////////////////
int nCompletion = GetLocalInt(oPC, "FKY_CHAT_COMMAND_COMPLETE");
if (nCompletion) DoCommandCompletion(oPC, sText, nCompletion);
////////////////////////////////Speech Processing///////////////////////////////
else if (sType == EMOTE_SYMBOL) HandleEmotes(oPC, sText, nChannel);//emotes - taken from Emote-Wand V1000 UpDate Scripted By: Butch (with edits)
else if (sType == COMMAND_SYMBOL) HandleCommands(oPC, oTarget, sText, nChannel);//commands
else if (sType == "/")// metachannels and languages
{
SetLocalString(oPC, "NWNX!CHAT!SUPRESS", "1");
sText = GetStringRight(sText, GetStringLength(sText) - 1);
sSort = GetStringLeft(sText, 2);
if (ENABLE_LANGUAGES && sSort == "l ") HandleOneLiners(sText, oPC, nChannel);//must be a space after the /l
else if (ENABLE_METACHANNELS && sSort == "m ") HandleMetaMessage(sText, oPC);//must be a space after the /m
else if ((VerifyDMKey(oPC) || VerifyAdminKey(oPC)) && sSort == "v ") HandleVentrilo(sText, oPC);//must be a space after the /m
else FloatingTextStringOnCreature(COLOR_RED+BADCHANNEL+COLOR_END, oPC, FALSE);
}
else if ((GetStringLowerCase(GetStringLeft(sText, 3)) == "dm_") && (VerifyDMKey(oPC) || VerifyAdminKey(oPC)))
{
//HandleDMTraffic(oPC, oTarget, sText);//this has been moved to a new script to allow compiler to digest it
SetLocalObject(oPC, "FKY_CHAT_DMSHUNT_TARGET", oTarget);//these locals pass the needed values to the new script
SetLocalString(oPC, "FKY_CHAT_DMSHUNT_TEXT", sText);
ExecuteScript("fky_chat_dm_comm", oPC);
}
else HandleOtherSpeech(oPC, oTarget, sText, nChannel, sLogMessageTarget);
////////////////////////////////////Logging/////////////////////////////////////
if (TEXT_LOGGING_ENABLED) DoLogging(oPC, sLogMessageTarget, nChannel, sText);
////////////////////////////////////Cleanup/////////////////////////////////////
DoCleanup(oPC);
}
From that, you would want the command handling, which is done with HandleCommands. You can find that in fky_chat_inc. I'm not going to post the whole function here, since it's around 900 lines, but here's the beginning, which shows the switch architecture:
void HandleCommands(object oCPC, object oCTarget, string sCText, int nCChannel)
{
string sSort, sTarget, sPlayer, sInvite, sKey, sNormalCase;
int nText, nCount, nPos, nLang, nCheck;
object oItem;
location lLoc;
SetLocalString(oCPC, "NWNX!CHAT!SUPRESS", "1");//suppress command speech no matter what, helps avoid circumvention of shout ban
if (!GetIsDead(oCPC))
{
sNormalCase = GetStringRight(sCText, GetStringLength(sCText) - 1); //preserve caps for setname command
sCText = GetStringLowerCase(sNormalCase); //case insensitive
WriteTimestampedLogEntry(sCText);
sSort = GetStringLeft(sCText, 1);
nText = FindSubString("a d h i l m p s t u w", sSort);
switch (nText) //0 2 4 6 8 101214161820
{
case -1: CommandRedirect(oCPC, 1); break;
/*a*/ case 0:
if (sCText == "anon")
{
SetLocalInt(oCPC, "FKY_CHAT_ANON", 1);
SendMessageToPC(oCPC, COLOR_RED+ANON+COLOR_END);
}
else if (GetStringLeft(sCText, 2) == "an") CommandRedirect(oCPC, 2);
else CommandRedirect(oCPC, 1);
break;
/*d*/ case 2:
The ignore functionality is here:
/*i*/ case 6:
if (sCText == "ignore")
{
if (!GetIsObjectValid(oCTarget))//target verification - do they need to use the command targeter?
{
oCTarget = GetLocalObject(oCPC, "FKY_CHAT_TARGET"); //have they already used the targeter?
if (!GetIsObjectValid(oCTarget))
{
FloatingTextStringOnCreature(COLOR_GOLD+REQUIRES_TARGET+COLOR_END, oCPC, FALSE);//tell them
SetLocalString(oCPC, "FKY_CHAT_COMMAND", OBJECT_TARGET+COMMAND_SYMBOL + sNormalCase);//mark them for the targeter
if (!GetIsObjectValid(GetItemPossessedBy(oCPC, "fky_chat_target"))) CreateItemOnObject("fky_chat_target", oCPC);//give them a targeter if they need one
return;
}
else DeleteLocalObject(oCPC, "FKY_CHAT_TARGET");//variable cleanup
}
//if (((nCChannel == 4) ||(nCChannel == 20)) && GetIsObjectValid(oCTarget))//can now target with command targeter
if (GetIsPC(oCTarget))
{
if ((!VerifyDMKey(oCTarget)) && (!VerifyAdminKey(oCTarget)))//can't ignore DMs or Admins
{
if (oCPC != oCTarget)
{
sTarget = GetPCPlayerName(oCTarget);
if (GetLocalInt(oCPC, "FKY_CHT_IGNORE" + sTarget) == FALSE)
{
sPlayer = GetPCPlayerName(oCPC);
SetLocalInt(oCPC, "FKY_CHT_IGNORE" + sTarget, TRUE);//ignore list stored on PC ignoring
SendMessageToPC(oCPC, COLOR_RED+IGNORE3+ sTarget + "."+COLOR_END);
SendMessageToPC(oCTarget, COLOR_RED + sPlayer +IGNORE4+COLOR_END);
}
else FloatingTextStringOnCreature(COLOR_RED+IGNORE5+ sTarget + "!"+COLOR_END, oCPC, FALSE);
}
else FloatingTextStringOnCreature(COLOR_RED+IGNORE6+COLOR_END, oCPC, FALSE);
}
else FloatingTextStringOnCreature(COLOR_RED+IGNORE7+COLOR_END, oCPC, FALSE);
}
else FloatingTextStringOnCreature(COLOR_RED+PC_ONLY+COLOR_END, oCPC, FALSE);
//else FloatingTextStringOnCreature(COLOR_RED+IGNORE8+COLOR_END, oCPC, FALSE);
}
else if (GetStringLeft(sCText, 2) == "ig") CommandRedirect(oCPC, ;
else CommandRedirect(oCPC, 1);
break;
Here's unignore:
/*u*/ case 18:
if (sCText == "unignore")
{
//if (((nCChannel == 4) ||(nCChannel == 20)) && GetIsObjectValid(oCTarget))//can now be targeted with the command targeter
//{
if (!GetIsObjectValid(oCTarget))//target verification - do they need to use the command targeter?
{
oCTarget = GetLocalObject(oCPC, "FKY_CHAT_TARGET"); //have they already used the targeter?
if (!GetIsObjectValid(oCTarget))
{
FloatingTextStringOnCreature(COLOR_GOLD+REQUIRES_TARGET+COLOR_END, oCPC, FALSE);//tell them
SetLocalString(oCPC, "FKY_CHAT_COMMAND", OBJECT_TARGET+COMMAND_SYMBOL + sNormalCase);//mark them for the targeter
if (!GetIsObjectValid(GetItemPossessedBy(oCPC, "fky_chat_target"))) CreateItemOnObject("fky_chat_target", oCPC);//give them a targeter if they need one
return;
}
else DeleteLocalObject(oCPC, "FKY_CHAT_TARGET");//variable cleanup
}
if (GetIsPC(oCTarget))
{
sTarget = GetPCPlayerName(oCTarget);
if (GetLocalInt(oCPC, "FKY_CHT_IGNORE" + sTarget) == TRUE)
{
sPlayer = GetPCPlayerName(oCPC);
DeleteLocalInt(oCPC, "FKY_CHT_IGNORE" + sTarget);//ignore list stored on PC ignoring
SendMessageToPC(oCPC, COLOR_RED+UNIGNORE1+ sTarget + "."+COLOR_END);
SendMessageToPC(oCTarget, COLOR_RED + sPlayer+UNIGNORE2+COLOR_END);
}
else FloatingTextStringOnCreature(COLOR_RED+UNIGNORE3+ sTarget + "!"+COLOR_END, oCPC, FALSE);
}
else FloatingTextStringOnCreature(COLOR_RED+PC_ONLY+COLOR_END, oCPC, FALSE);
//}
//else FloatingTextStringOnCreature(COLOR_RED+UNIGNORE4+COLOR_END, oCPC, FALSE);
}
else if (GetStringLeft(sCText, 3) == "uni") CommandRedirect(oCPC, ;
else if (sCText == "unanon")
{
DeleteLocalInt(oCPC, "FKY_CHAT_ANON");
SendMessageToPC(oCPC, COLOR_RED+UNANON+COLOR_END);
}
else if (GetStringLeft(sCText, 3) == "una") CommandRedirect(oCPC, 2);
else CommandRedirect(oCPC, 1);
break;
Lastly, there's the actual muting of the communication itself, which is done in HandleOtherSpeech, found at the bottom of fky_chat_inc:
void HandleOtherSpeech(object oHOPC, object oHOTarget, string sHOText, int nHOChannel, string sHOLogMessageTarget)
{
string sHOTarget, sEscape;
switch(nHOChannel)//all speech besides emotes, player commands, and metachannels - sort by channel
{
////////////Player speaker channels from 1-14
/*talk*/ case 1:
if (ENABLE_METALANGUAGE_CONVERSION)
{
if (GetStringLowerCase(sHOText) == "lol" )
{
SpeakString(LOL);
SetLocalString(oHOPC, "NWNX!CHAT!SUPRESS", "1");
}
else if (ENABLE_LANGUAGES) HandleTalkSpeak(sHOText, oHOPC);
}
else if (ENABLE_LANGUAGES) HandleTalkSpeak(sHOText, oHOPC);
break;
/*shout*/ case 2:
if (GetLocalInt(oHOPC, "FKY_CHT_BANSHOUT"))//check for shout ban
{
SetLocalString(oHOPC, "NWNX!CHAT!SUPRESS", "1");//mute em
SendMessageToPC(oHOPC, COLOR_RED+BANNEDSHT+COLOR_END);//tell em
}
else if (GetIsSpam(sHOText) && SPAMBLOCK_ENABLED && (!VerifyDMKey(oHOPC)) && (!VerifyAdminKey(oHOPC))) DoSpamBan(oHOPC, sHOText);//check for advertising spam
break;
/*whisper*/ case 3:
if (ENABLE_LANGUAGES) HandleTalkSpeak(sHOText, oHOPC, TALKVOLUME_WHISPER);
break;
/*tell*/ case 4:
sHOTarget = GetPCPlayerName(oHOPC);
if (GetLocalInt(oHOTarget, "FKY_CHT_IGNORE" + sHOTarget))//check for ignore
{
SetLocalString(oHOPC, "NWNX!CHAT!SUPRESS", "1");//mute em
SendMessageToPC(oHOPC, COLOR_RED + GetName(oHOTarget)+ISIGNORED+COLOR_END);//tell em
}
//HandleDMTraffic(oHOPC, oHOTarget, sHOText, sHOLogMessageTarget, nHOChannel);//handles dm traffic and tell forwarding//now handled earlier
DMTellForwarding(oHOPC, sHOLogMessageTarget, sHOText, nHOChannel); //check for tell options
break;
/*party*/ case 6:
if (ENABLE_LANGUAGES) HandlePartySpeak(sHOText, oHOPC);
break;
/*dm*/ case 14:
if (GetLocalInt(oHOPC, "FKY_CHT_BANDM"))//check for DM ban
{
SetLocalString(oHOPC, "NWNX!CHAT!SUPRESS", "1");//mute em
SendMessageToPC(oHOPC, COLOR_RED+BANNEDDM+COLOR_END);//tell em
}
if (DM_PLAYERS_HEAR_DM) DMChannelForwardToDMs(oHOPC, sHOText);//check for dm players hearing dm
if (ADMIN_PLAYERS_HEAR_DM) DMChannelForwardToAdmins(oHOPC, sHOText);//check for admin players hearing dm
break;
////////////DM speaker channels from 17-30
/*talk*/ //case 17:
/*shout*/ //case 18:
/*whisper*/ //case 19:
/*tell*/ case 20:
//HandleDMTraffic(oHOPC, oHOTarget, sHOText, sHOLogMessageTarget, nHOChannel);//handles dm traffic and tell forwarding//now handled earlier
DMTellForwarding(oHOPC, sHOLogMessageTarget, sHOText, nHOChannel); //check for tell options
break;
/*party*/ //case 22:
/*dm*/ case 30:
if (DM_PLAYERS_HEAR_DM) DMChannelForwardToDMs(oHOPC, sHOText); //check for dm players hearing dm
if (ADMIN_PLAYERS_HEAR_DM) DMChannelForwardToAdmins(oHOPC, sHOText);//check for admin players hearing dm
break;
}
if (ENABLE_PERMANENT_CHANNEL_MUTING && GetIsChannelSuppressed(nHOChannel) && (!VerifyDMKey(oHOPC)) && (!VerifyAdminKey(oHOPC)) && (GetIsPC(oHOPC) || (!PERMANENT_CHANNEL_MUTING_FOR_PC_ONLY))) SetLocalString(oHOPC, "NWNX!CHAT!SUPRESS", "1");//if the channel is always suppressed then suppress it
else if (DISALLOW_SPEECH_WHILE_DEAD && GetIsChannelDeadSuppressed(nHOChannel) && GetIsDead(oHOPC) && (!VerifyDMKey(oHOPC)) && (!VerifyAdminKey(oHOPC))) SetLocalString(oHOPC, "NWNX!CHAT!SUPRESS", "1");//otherwise suppress it when they are dead if it is deadsuppressed
else if (DISALLOW_SPEECH_WHILE_SILENCED && GetIsChannelSilencedSuppressed(nHOChannel) && GetIsSilenced(oHOPC) && (!VerifyDMKey(oHOPC)) && (!VerifyAdminKey(oHOPC))) SetLocalString(oHOPC, "NWNX!CHAT!SUPRESS", "1");//otherwise suppress it when they are silenced if it is silencedsuppressed
}
In conclusion, you can certainly manage to cut out just the ignore functionality, but it involves a lot of reinventing the wheel, and doesn't save you much overhead. I didn't even bother touching on the item which would allow you to target in-area without tells, since that would involve even more scripts, and a ton of extra work for little additional gain.
Funky