COMMUNICATION LIBRARY FOR JMC Built for JMC version 3.26 with VBScript enabled. (c) Rashnak 2003-01-17 1 INTRODUCTION 2 INSTALLATION 3 INTERFACE 3.1 Recording 3.2 Viewing show 3.3 Clearing clear 3.4 Characters char 4 COMPATIBILITY 4.1 JMC events 5 SUMMARY 6 VBSCRIPT CODE 1. INTRODUCTION This module will save data on MUME communication channels to files on your PC, allowing you to view them later. In addition it contains other features which are described along this document. The beginning of this file describes the functionality and structure of the module in detail, followed by a summary of the JMC aliases for a quick copy paste, and last but not least the VBScript code. The module records communication on these channels: - tells - narrates - says - prays - songs 2. INSTALLATION You should first read through the entire INTERFACE part of this document to see what kind of features there are and how to configure and use them. Then you should edit the SETTINGS part of the VBScript code (end of this document) to your needs, and copy the code to file "settings\commonlib.scr" in your JMC directory. You will need to create some subdirectories in the mumeDirectory (see SETTINGS). Using the default directory (c:\mume): c:\mume\data\char c:\mume\data\com Now you can copy the JMC aliases from the SUMMARY part to your macro files or directly to your JMC session. The module should then be functional. 3. INTERFACE In this part the command interface (JMC macros) of the module is described. 3.1 Recording When a communication pattern is received, it is stored in the script's memory. Every now and then, both automatically and by certain user actions, the data is saved to file(s). If JMC crashes, any communication data not yet saved to the file is lost. In the SETTINGS part of the VBScript code there is a variable named "comChannelMaxRows", which sets the number of communication lines that can be received before the buffer is automatically saved to a file. By default all data will be saved under directory "c:\mume", but you can change this in the SETTINGS. From all communication the following three fields are extracted: - actor (the character communicating) - verb (narrates, tells you) - sentence (the sentence communicated) See also: 3.4 Characters 3.2 Viewing To view recorded communication data, use this alias: #alias show #script ComShow("%0") Example: >show narrates ---[narrates:]---------------------------------------------------- [15.11.2002-12:52:01] Lealon narrates 'but there are only corpse' [15.11.2002-12:52:03] Moloko narrates 'out' [15.11.2002-12:52:04] Moloko narrates 'out' [15.11.2002-12:52:11] Horas narrates 'enzo has no mvs?' [15.11.2002-12:52:15] Tromb narrates 'bob enzo' ------------------------------------------------------------------ The channel names can be abbreviated (narrates=nar=n, songs=so, says=sa, etc). Optionally you can search the channel for a keyword like this: >com prays newbie This will search the recorded data on "pray" channel for "newbie" keyword and display only the matching prays. Dates and times will be formatted according to your operating system settings and locale. This command will first save (append) the data buffer to the channel file, and then display the contents of that file. 3.3 Clearing The basic functionality of the script is designed for only short term usage, for example when getting lots of tells from different persons, having a long conversation, or when you are away from keyboard. Following alias can be used to clear the channel file when it is no longer needed: #alias clear #script ComClear("%0") This alias accepts same arguments as "show" described above. Example: >clear p Channel 'prays' cleared. The "clear" command will also backup the cleared data from the temporary channel file to permanent archives so you will always have access to old communication by viewing the files in "data\com" folder with your favourite text editor. 3.4 Characters The script can also record (in real-time) communication per actor to the folder "data\char" in character files. Under SETTINGS part of the VBScript code you can configure which channels use this function and how. The three options are Never, Always, and Only: Never: Never record the channel to character files Always: Always record Only: Only record if the character file already exists Be aware that this feature can create thousands of files on your computer, which can create performance problems if you have limited disk space. By default only the tell channel is always recorded in character files. Narrates, says, and prays are recorded only if the character file already exists, which is if you have received a tell from the person before or created a note for the character (see below). To view a character file in-game, use this alias: #alias {char} {#script ComChar "%0"} For example, >char tutti ---[character: Tutti]--------------------------------------------- [15.11.2002-12:57:15] Tutti narrates 'Anyone want to sell a blue scroll?' ------------------------------------------------------------------ You can also add your own notes to the character files by appending the one line note after the character's name, like this: >char tutti He is buying blue scrolls. When viewing a character file, the display order is 1. communication 2. notes 4. COMPATIBILITY This section should only be of interest to those who want to address compatibility issues with their existing scripts. 4.1 JMC events Every string that arrives from MUME triggers "Jmc_Incoming" event. This script implements the "Jmc_Incoming" function, which contains a function call to "ComIncoming". If your existing script already implements the "Jmc_Incoming" function, you can just add the "ComIncoming" function call to your existing "Jmc_Incoming" function. The same applies to the function "Jmc_ConnectLost" implemented in this script. 5. SUMMARY Here are all the JMC macros for this module: #alias show #script ComShow "%0" #alias clear #script ComClear "%0" #alias char #script ComChar "%0" 6. VBSCRIPT CODE '******************************************************* ' COMMUNICATION LIBRARY: VBSCRIPT CODE STARTS HERE '******************************************************* ' SETTINGS, MODIFY THESE IF YOU WANT: Const mumeDirectory = "c:\mume" Const comPerCharacter = True ' Creates Dictionary (assosiative array) objects for dealing ' with the channels. Set comChannelVerbs = CreateObject("Scripting.Dictionary") Set comChannels = CreateObject("Scripting.Dictionary") ' This will map a verb into channel identifier comChannelVerbs.Add "tells you", "tells" comChannelVerbs.Add "narrates", "narrates" comChannelVerbs.Add "says", "says" comChannelVerbs.Add "prays", "prays" comChannelVerbs.Add "sings", "songs" ' Channel properties for each channel identifier ' .char: Const comSettingCharNever = 0 ' 0 Never save to character files Const comSettingCharAlways = 1 ' 1 Always save to character files Const comSettingCharOnly = 2 ' 2 Only save if character file already exists ' These are internal channel data identifiers: ' .data: The actual communication data is stored in this string ' .rows: Number of rows currently in .data string ' This sets the limit after which the .data string is automatically ' saved to a file and cleared. Const comChannelMaxRows = 100 comChannels.Add "tells.verb", "tells you" comChannels.Add "tells.char", comSettingCharAlways comChannels.Add "tells.data", "" comChannels.Add "tells.rows", 0 comChannels.Add "narrates.verb", "narrates" comChannels.Add "narrates.char", comSettingCharOnly comChannels.Add "narrates.data", "" comChannels.Add "narrates.rows", 0 comChannels.Add "says.verb", "says" comChannels.Add "says.char", comSettingCharOnly comChannels.Add "says.data", "" comChannels.Add "says.rows", 0 comChannels.Add "prays.verb", "prays" comChannels.Add "prays.char", comSettingCharOnly comChannels.Add "prays.data", "" comChannels.Add "prays.rows", 0 comChannels.Add "songs.verb", "sings" comChannels.Add "songs.char", comSettingCharNever comChannels.Add "songs.data", "" comChannels.Add "songs.rows", 0 ' INTERNAL VARIABLES: ' File open modes Const ForReading = 1, ForWriting = 2, ForAppending = 8 ' These variables are used to track multi-line sentences correctly: Dim comIncomingReceiving Dim comIncomingActor Dim comIncomingSentence Dim comIncomingVerb dim comIncomingLines comIncomingLines = 0 comIncomingReceiving = False ' Set's the max size for a multi-line communication pattern ' This is to prevent titles and other non-ending communication ' patterns from fooling the script too much. Const comIncomingLinesMax = 10 Sub Jmc_ConnectLost ' Save communication ComChannelSaveAll End Sub '******************************************************* ' COMMUNICATION LIBRARY: Jmc_Incoming ' This is the event handler for all lines coming from MUME. ' I try to separate my modules by category, so if a line from mud ' is identified as a herb, for example, there is no need to look ' for a match in other categories. This may, in the long run, ' make up for the processing required by complex searches. ' The "HerbalIncoming" call is presented as an example, use it ' if have my Herbal Kit module installed, otherwise leave it ' commented out. '****************************************************** Sub Jmc_Incoming (line) dim match match = false ' if (not match) then ' match = HerbalIncoming(line) ' end if if (not match) then match = ComIncoming(line) end if End sub '******************************************************* ' COMMUNICATION LIBRARY: ComIncoming (line) ' Checks the incoming line for any relevant information. '****************************************************** Function ComIncoming (line) retVal = true if (not ComIncomingCommunicationData(line)) then retVal = false end if ComIncoming = retVal End Function '******************************************************* ' COMMUNICATION LIBRARY: ComIncomingCommunicationData (line) ' Checks input line for communication data '****************************************************** Function ComIncomingCommunicationData(line) Dim regEx, Match, Matches, retVal retVal = False Set regEx = New RegExp ' Remove all ANSI codes regEx.Pattern = "\x1B\[[\d;]*m" regEx.Global = true line = regEx.Replace(line, "") regEx.Pattern = "^(.*?) (tells\syou|narrates|says|prays|sings) '(.*)$" if (comIncomingReceiving) then ' Receiving multi-line data comIncomingSentence = comIncomingSentence & " " & line comIncomingLines = comIncomingLines + 1 else ' Not receiving, check for start of new data if (regEx.Test(line)) then ' New data incoming comIncomingReceiving = True comIncomingLines = 1 Set matches = regEx.Execute(line) Set match = matches(0) comIncomingActor = match.SubMatches(0) verb = match.SubMatches(1) comIncomingVerb = verb comIncomingSentence = "'" & match.SubMatches(2) end if end if if (comIncomingReceiving) then retVal = True ' Received a sentence, check if it ends here if (comIncomingLines >= comIncomingLinesMax) then ' Force end sequence comIncomingSentence = comIncomingSentence & "'" comIncomingLines = 0 end if if (right(comIncomingSentence, 1) = "'") then ' Finished receiving comIncomingReceiving = False ' Remove quotes comIncomingSentence = right(left(comIncomingSentence, len(comIncomingSentence)-1), len(comIncomingSentence)-2) ' Save it ComSave comIncomingActor, comIncomingVerb, comIncomingSentence else end if end if ComIncomingCommunicationData = retVal End Function '******************************************************* ' COMMUNICATION LIBRARY: ComGetFilteredActor (actor) ' Filters unwanted phrases from actor's name ' - MUME label, if any ' - Cross-race actors not allowed ' - Capitalize the first character '****************************************************** Function ComGetFilteredActor(actor) Dim regEx Set regEx = New RegExp ' Remove label regEx.Pattern = "\s\(.*\)" actor = regEx.Replace(actor, "") ' Fix bug: * CRW Mana:Hot>Newbie prays 'kit' regEx.Pattern = ">" if (regEx.Test(actor)) then Dim lineArr lineArr = Split(actor, ">", 2) actor = lineArr(1) end if ' Capitalize the first letter actor = UCase(Left(actor, 1)) & Right(actor, Len(Actor)-1) ' Convert *Name the X* into Name regEx.Pattern = "\*(\w*?)\sthe\s.*\*" if (regEx.Test(actor)) then Set matches = regEx.Execute(actor) Set match = matches(0) actor = match.SubMatches(0) end if ' Convert -Name the X- into Name regEx.Pattern = "-(\w*?)\sthe\s.*-" if (regEx.Test(actor)) then Set matches = regEx.Execute(actor) Set match = matches(0) actor = match.SubMatches(0) end if ' Convert *A Race* and *An Race* to Race regEx.Pattern = "\*(A|An)\s(.*?)\*" If (regEx.Test(actor)) Then Set matches = regEx.Execute(actor) Set match = matches(0) actor = match.SubMatches(1) End if ' Convert -A Race- and -An Race- to Race regEx.Pattern = "-(A|An)\s(.*?)-" If (regEx.Test(actor)) Then Set matches = regEx.Execute(actor) Set match = matches(0) actor = match.SubMatches(1) End if ' Whoises: No : allowed in actor regEx.Pattern = ":" if (regEx.Test(actor)) then actor = "" end if ' Ainur titles: No [ allowed in actor regEx.Pattern = "\[" if (regEx.Test(actor)) then actor = "" end if ComGetFilteredActor = actor End Function '******************************************************* ' COMMUNICATION LIBRARY: ComGetChannelByChannel (channel) ' Finds a matching channel for an abbreviation, ' Returns empty string on error, '****************************************************** Function ComGetChannelByChannel(channel) dim matches matches = 0 Dim regEx Set regEx = New RegExp regEx.pattern = "^" & channel regEx.IgnoreCase = True dim channels channels = comChannelVerbs.Items For i = 0 To comChannelVerbs.Count-1 if (regEx.Test(channels(i))) then channel = channels(i) matches = matches + 1 end if Next if (matches <> 1) then channel = "" end if ComGetChannelByChannel = channel End Function '******************************************************* ' COMMUNICATION LIBRARY: ComChannelSave (channel) ' Saves the data on a channel to a file and clears the ' buffer. '****************************************************** Sub ComChannelSave(channel) if (comChannels.item(channel & ".data") <> "") then Dim fn fn = mumeDirectory & "\com_" & channel & ".txt" Set fso = CreateObject("Scripting.FileSystemObject") Set stream = fso.OpenTextFile(fn, ForAppending, True) stream.Write comChannels.item(channel & ".data") stream.Close() comChannels.item(channel & ".data") = "" comChannels.item(channel & ".rows") = 0 end if End Sub '******************************************************* ' COMMUNICATION LIBRARY: ComChannelSaveAll ' Saves data on all channels to files and clears the ' buffers. '****************************************************** Sub ComChannelSaveAll dim channels channels = comChannelVerbs.Items For i = 0 To comChannelVerbs.Count-1 channel = channels(i) ComChannelSave(channel) Next End Sub '******************************************************* ' COMMUNICATION LIBRARY: ComSave (actor, verb, sentence) ' Saves a communication line to channel's .data buffer. '****************************************************** Sub ComSave(actor, verb, sentence) Dim channel, realActor channel = comChannelVerbs.item(verb) realActor = actor actor = ComGetFilteredActor(actor) If (actor = "" or channel = "") Then ' Something was wrong with actor or channel, don't save! Exit Sub End If ' String to save Dim saveStr saveStr = "[" & FormatDateTime(Date) & "-" & FormatDateTime(Time) & "] " & realActor & " " & comChannels.item(channel & ".verb") & " '" & sentence & "'" ' Print to output window jmc.output saveStr ' Save to channel.data comChannels.item(channel & ".data") = comChannels.item(channel & ".data") & saveStr & vbNewLine comChannels.item(channel & ".rows") = comChannels.item(channel & ".rows") + 1 if (comChannels.item(channel & ".rows") >= comChannelMaxRows) then ' Buffer size exceeded ComChannelSave(channel) end if ' Save to character file (if must) Dim fnChar saveStr = channel & " " & saveStr fnChar = mumeDirectory & "\data\char\" & actor & ".txt" Set fso = CreateObject("Scripting.FileSystemObject") if ((comChannels.item(channel & ".char") = comSettingCharAlways) or _ (fso.FileExists(fnChar) and comChannels.item(channel & ".char") = comSettingCharOnly)) _ Then Set stream = fso.OpenTextFile(fnChar, ForAppending, True) stream.WriteLine saveStr stream.Close() End If End Sub '******************************************************* ' COMMUNICATION LIBRARY: ComSep (title) ' Returns a separating line with a possible title '****************************************************** Function ComSep(title) dim line line = "---" if (title <> "") then line = line & "[" & title & "]" end if do while (len(line) < 79) line = line & "-" loop ComSep = line End Function '******************************************************* ' COMMUNICATION LIBRARY: ComShow (line) ' Displays recent communication on a channel ' >com prays newbie '****************************************************** Sub comShow(line) Dim channel Dim keyword channel = line keyword = "" ' Check for search keyword Dim regEx Set regEx = New RegExp regEx.Pattern = "\s" If (regEx.Test(line)) Then Dim lineArr lineArr = Split(line, " ", 2) channel = lineArr(0) keyword = lineArr(1) End if channel = ComGetChannelByChannel(channel) if (channel = "") then jmc.showme "Channel not found!" exit sub end if ComChannelSave(channel) Dim fn fn = mumeDirectory & "\com_" & channel & ".txt" jmc.ShowMe("") jmc.showme ComSep(channel & ": " & keyword) Set fso = CreateObject("Scripting.FileSystemObject") If (fso.FileExists(fn) = False) Then jmc.ShowMe "Channel '" & channel & "' has no recorded data." Exit Sub End if Set stream = fso.OpenTextFile(fn, ForReading, False) ' build search regEx.Pattern = keyword regEx.IgnoreCase = True Do While stream.AtEndOfStream <> True line = stream.ReadLine if (keyword="" or regEx.Test(line)) then jmc.ShowMe(line) end if Loop stream.Close jmc.ShowMe(comSep("")) End Sub '******************************************************* ' COMMUNICATION LIBRARY: ComClear (channel) ' Moves recent communication to archive and clears short ' term storage. '****************************************************** Sub comClear(channel) Dim fn, fnAll channel = ComGetChannelByChannel(channel) ComChannelSave(channel) fn = mumeDirectory & "\com_" & channel & ".txt" fnAll = mumeDirectory & "\data\com\all_" & channel & ".txt" Set fso = CreateObject("Scripting.FileSystemObject") If (fso.FileExists(fn) = False) Then jmc.ShowMe "Channel '" & channel & "' has no recorded data!" Exit Sub End if Set stream = fso.OpenTextFile(fn, ForReading, False) dim delData delData = stream.ReadAll stream.Close fso.DeleteFile(fn) Set stream = fso.OpenTextFile(fnAll, ForAppending, True) stream.Write(delData) stream.Close() jmc.ShowMe "Channel '" & channel & "' cleared." End Sub '******************************************************* ' COMMUNICATION LIBRARY: ComChar (line) ' Displays a character file. '****************************************************** Sub ComChar(line) If (line = "") Then jmc.ShowMe("char [note]") Exit Sub End if Dim lineArr, actor, newInfo newInfo = "" actor = line Dim regEx Set regEx = New RegExp regEx.Pattern = "\s" If (regEx.Test(line)) Then lineArr = Split(line, " ", 2) actor = lineArr(0) actor = ComGetFilteredActor(actor) Select Case left(lineArr(1), 1) case "+" ComCharVarSet actor, right(lineArr(1), len(lineArr(1))-1) case "-" ComCharVarRemove actor, right(lineArr(1), len(lineArr(1))-1) case else newInfo = "* [" & FormatDateTime(Date) & "-" & FormatDateTime(Time) & "] " & lineArr(1) end select End if actor = ComGetFilteredActor(actor) Dim fnChar fnChar = mumeDirectory & "\data\char\" & actor & ".txt" jmc.ShowMe("") jmc.ShowMe(comSep("character: " & actor)) Set fso = CreateObject("Scripting.FileSystemObject") If (newInfo <> "") Then ' Append new info row Set stream = fso.OpenTextFile(fnChar, ForAppending, True) stream.WriteLine(newInfo) stream.Close End if If (fso.FileExists(fnChar) = true) Then Set stream = fso.OpenTextFile(fnChar, ForReading, False) dim infoData infoData = "" Do While stream.AtEndOfStream <> True dim channel, arr line = stream.ReadLine arr = Split(line, " ", 2) channel = arr(0) line = arr(1) select case channel case "*" infoData = infoData & vbNewLine & line case else jmc.ShowMe(line) end select Loop stream.Close End if if (infoData <> "") then jmc.ShowMe(comSep("")) jmc.ShowMe(infoData) end if jmc.ShowMe(comSep("")) End Sub