HERBAL KIT FOR JMC Built for JMC version 3.26+ with VBScript enabled. (c) Rashnak 2003-01-17 This module helps to identify and use herbs and herblores. The herblores of Clearthought and Orc-draught and their ingredients are included as example, but other herbs and lores I have left out on purpose. In the beginning of the code there are data structures to store all information about herblores and herbs, where you can add your own data following the preset examples. After you pick up herbs, they are often prepared by crushing them, and then put in a container like a backpack or a sack. When you look in a container (not examine, as it produces different output), the script reads the herb rows and stores inventory values for each herb: >look in pack backpack (used) : 5 a cluster of hard, round, black berries (juniper) 1 a handful of narrow leaves (tarragon) 9 some grey-green leaves (sage) 5 some scented crushed leaves (thyme) 7 some sweet-smelling dried mauve petals (mauve) Here is the alias to use the stored information: #alias {kit} {#script HerbalKit "%0"} Without parameters, it returns a list of those herblores for which you have all or some ingredients ready, for example: >kit 0 a flask of orkish draught (draught) (Missing: fur tail blood) 5 a pungent brew (clearthought) The script only counts the ingredients which are already prepared (crushed) to the form in which they are to be used. For example, you may have thyme plants in your backpack, but the script will not count them as clearthought ingredients because they are not crushed. You can also use the same alias to see how many potions of a specific lore you can mix: >kit count draught You have ingredients for 2 potions of a flask of orkish draught Or to mix the potion: >kit mix draught Mixing a flask of orkish draught... To reset the inventory values(after using or dropping herbs): >kit reset Herb inventory values cleared. Below is the VBScript code, copy it to "settings/commonlib.scr". ' ************************************************************************ ' VBScript code starts here ' ************************************************************************ ' ' DATA FIELDS: ' ' "key" is the keyword for the herb. It is not necessarily same as the ' MUME keyword for the herb/lore. For example, butchering a grey spider ' produces "a grey fluid-sack", with MUME keywords "sack" and "grey". ' ' For purposes of this module, both "sack" and "grey" are inadequate, ' so in this module the defined keyword for this item is "greysack". ' ' But to handle the item, the MUME keyword must also be defined, and for ' "greysack", it is defined as "greysack.keyword". ' ' It COULD be handy to also have a variable "greysack.label", which would ' identify the item to player: "a grey fluid-sack (grey spider sack)". ' ' But I decided to avoid any more variables, and just use the module's ' keyword (greysack) as the label also: "a grey fluid-sack (greysack)". ' ' To summarize, here are all the data definitons for the herb "greysack": ' ' herbalHerbName.Add "greysack", "a grey fluid-sack" ' herbalHerbData.Add "greysack.keyword", "grey" ' herbalHerbData.Add "greysack.plural", "grey fluid-sacks" ' herbalHerbData.Add "greysack.long", "A grey and slimy fluid-sack has been left here." ' ' ' ' HERB DEFINITIONS: ' example: greysack ' ' key = short description ' example: "a grey fluid-sack" ' ' key.plural = plural description ' example: "grey fluid-sacks" ' ' key.long = long description ' example: "A grey and slimy fluid-sack has been left here." ' ' key.keyword = keyword to handle the herb when mixing lore, if needed. ' example: "grey" ' Set herbalHerbName = CreateObject("Scripting.Dictionary") Set herbalHerbData = CreateObject("Scripting.Dictionary") herbalHerbName.Add "fur", "some short, black fur" herbalHerbData.Add "fur.plural", "piles of short, black fur" herbalHerbData.Add "fur.long", "A patch of short black fur lies on the ground." herbalHerbName.Add "tail", "a short, moist tail" herbalHerbData.Add "tail.plural", "short, moist tails" herbalHerbData.Add "tail.long", "A detached tail, moist and slimy, lies here." herbalHerbName.Add "tarragon", "a handful of narrow leaves" herbalHerbData.Add "tarragon.plural", "handfuls of narrow leaves" herbalHerbData.Add "tarragon.long", "A small pile of narrow, fragrant leaves has been left here." herbalHerbName.Add "tarragon-plant", "a woody, stemmed plant" herbalHerbData.Add "tarragon-plant.keyword", "plant" herbalHerbData.Add "tarragon-plant.plural", "woody, stemmed plants" herbalHerbData.Add "tarragon-plant.long", "A small evergreen plant grows here, its woody stems reaching two feet." herbalHerbName.Add "blood", "a vial of preserved blood" herbalHerbData.Add "blood.plural", "vials of preserved blood" herbalHerbData.Add "blood.long", "A vial, full of a reddish fluid, has been left here." herbalHerbName.Add "juniper", "a cluster of hard, round, black berries" herbalHerbData.Add "juniper.plural", "clusters of hard, round, black berries" herbalHerbData.Add "juniper.long", "A small cluster of hard, round, blue-black berries has been left here." herbalHerbName.Add "juniper-bush", "a short evergreen plant" herbalHerbData.Add "juniper-bush.plural", "short evergreen plants" herbalHerbData.Add "juniper-bush.long", "A short evergreen plant, with slightly bluish needles, grows here." herbalHerbName.Add "mauve", "some sweet-smelling dried mauve petals" herbalHerbData.Add "mauve.plural", "piles of sweet-smelling dried mauve petals" herbalHerbData.Add "mauve.long", "Some dried mauve petals can be found here." herbalHerbName.Add "sage", "some grey-green leaves" herbalHerbData.Add "sage.plural", "piles of grey-green leaves" herbalHerbData.Add "sage.long", "A handful of grey-green leaves have been left here." herbalHerbName.Add "sage-bush", "an evergreen shrub" herbalHerbData.Add "sage-bush.plural", "evergreen shrubs" herbalHerbData.Add "sage-bush.long", "A waist-high evergreen shrub grows here, with thick, reaching branches." herbalHerbName.Add "thyme", "some scented crushed leaves" herbalHerbData.Add "thyme.plural", "piles of scented crushed leaves" herbalHerbData.Add "thyme.long", "A small pile of crushed leaves gives off a pleasant scent." herbalHerbName.Add "thyme-plant", "a many-branched shrub" herbalHerbData.Add "thyme-plant.plural", "many-branched shrubs" herbalHerbData.Add "thyme-plant.long", "A low, many-branched shrub covers the ground here." ' HERBLORE DEFINITIONS: ' ' key = short description of the finished potion ' example: "a pungent brew" ' ' key.long = long description of the finished potion ' example: "A cup of pungent-smelling brew is here" ' ' key.ingredients = ingredients required for the lore ' example: "mauve thyme sage juniper" ' ' key.herbcontainer = where you prefer to put the ingredients for the lore ' example: "backpack" ' Set herbalLoreName = CreateObject("Scripting.Dictionary") Set herbalLoreData = CreateObject("Scripting.Dictionary") herbalLoreName.Add "draught", "a flask of orkish draught" herbalLoreData.Add "draught.plural", "flasks of orkish draught" herbalLoreData.Add "draught.long", "A flask of orkish draught is here." herbalLoreData.Add "draught.ingredients", "fur tail tarragon blood" herbalLoreData.Add "draught.herbcontainer", "backpack" herbalLoreName.Add "clearthought", "a pungent brew" herbalLoreData.Add "clearthought.plural", "pungent brews" herbalLoreData.Add "clearthought.long", "A cup of pungent-smelling brew is here." herbalLoreData.Add "clearthought.ingredients", "mauve thyme sage juniper" herbalLoreData.Add "clearthought.herbcontainer", "backpack" ' --- internal global variables --- dim herbalLoreInKit herbalLoreInKit = "" ' --- code starts here --- ' 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 "ComIncoming" call is presented as an example, use it ' if you use my Communication Library. 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 ' This function tests the input line for any herb-related data. ' Returns True if there was a match. Function HerbalIncoming(line) dim match, regEx, herbs, herbCount, stockMatch, herb, stock match = false ' indicate any herb match stockMatch = false ' indicate a match for herb with inventory value Set regEx = New RegExp ' LOOP THE HERB LIST FOR MATCH herbs = herbalHerbName.Keys herbCount = herbalHerbName.Count-1 For i = 0 To herbCount ' shortcut the herb we are searching for herb = herbs(i) ' herb(s) carried: if (not match) then if (line = herbalHerbName.item(herb)) then ' MATCH: short description match = true stock = 1 stockMatch = true end if end if if (not match) then if (herbalHerbData.exists(herb & ".plural")) then regEx.pattern = "^(.*)\s" & herbalHerbData.item(herb & ".plural") & "$" if (regEx.test(line)) then ' MATCH: plural description match = true Set m_matches = regEx.Execute(line) Set m_match = m_matches(0) text = m_match.SubMatches(0) stock = FormatTextToInteger(text) stockMatch = true end if end if end if ' herb(s) on ground: if (not match) then if (herbalHerbData.exists(herb & ".long")) then if (line = herbalHerbData.item(herb & ".long")) then ' MATCH: long description match = true jmc.event = line & " (" & herb & ")" end if end if end if if (not match) then if (herbalHerbData.exists(herb & ".plural")) then regEx.pattern = "^(On the ground, there are|There are|You see)\s(.*)\s" & herbalHerbData.item(herb & ".plural") if (regEx.test(line)) then ' MATCH: plural description match = true jmc.event = line & " (" & herb & ")" end if end if end if ' herb(s) in shop list: if (not match) then regEx.pattern = "^\s*(\d*)\.\s" & herbalHerbName.item(herb) if (regEx.test(line)) then ' MATCH: short description match = true jmc.event = line & " (" & herb & ")" end if end if if (not match) then if (herbalHerbData.exists(herb & ".plural")) then regEx.pattern = "^\s*(\d*)\.\s(.*)\s" & herbalHerbData.item(herb & ".plural") if (regEx.test(line)) then ' MATCH: plural description match = true jmc.event = line & " (" & herb & ")" end if end if end if if (match) then ' match found, stop searching further i = herbCount end if Next if (match) then if (stockMatch) then herbalHerbData.item(herb & ".stock") = stock jmc.event = string(2-len(stock), " ") & stock & " " & herbalHerbName.item(herb) & " (" & herb & ")" end if end if if (not match) then ' LOOP THE LORE LIST FOR POTION MATCH lores = herbalLoreName.Keys loreCount = herbalLoreName.Count-1 For i = 0 To loreCount ' shortcut the lore we are searching for lore = lores(i) ' potion carried if (not match) then if (line = herbalLoreName.item(lore)) then ' MATCH: short description match = true jmc.event = line & " (" & lore & ")" end if end if ' potion(s) on ground: if (not match) then if (herbalLoreData.exists(lore & ".long")) then if (line = herbalLoreData.item(lore & ".long")) then ' MATCH: long description match = true jmc.event = line & " (" & lore & ")" end if end if end if if (not match) then if (herbalLoreData.exists(lore & ".plural")) then regEx.pattern = "^(On the ground, there are|There are|You see)\s(.*)\s" & herbalLoreData.item(lore & ".plural") if (regEx.test(line)) then ' MATCH: plural description match = true jmc.event = line & " (" & lore & ")" end if end if end if ' potion(s) in shop list: if (not match) then regEx.pattern = "^\s*(\d*)\.\s" & herbalLoreName.item(lore) if (regEx.test(line)) then ' MATCH: short description match = true jmc.event = line & " (" & lore & ")" end if end if if (not match) then if (herbalLoreData.exists(lore & ".plural")) then regEx.pattern = "^\s*(\d*)\.\s(.*)\s" & herbalLoreData.item(lore & ".plural") if (regEx.test(line)) then ' MATCH: plural description match = true jmc.event = line & " (" & lore & ")" end if end if end if if (match) then ' match found, stop searching further i = loreCount end if Next end if ' MISCELLANEOUS HERB MATCHES: if (not match) then if (line = "You have finished mixing the contents of a fragrant-smelling bag." or _ line = "You empty a fragrant-smelling bag on the ground.") then match = true herbalLoreInKit = "" end if end if HerbalIncoming = match End Function Sub HerbalKitMix(lore) dim name, ingredients, RegExp, key Set regEx = New RegExp if (herbalLoreInKit = "") then name = herbalLoreName.item(lore) herbalLoreInKit = lore ingredients = herbalLoreData.item(lore & ".ingredients") container = herbalLoreData.item(lore & ".herbcontainer") regEx.Pattern = "(\S*)" regEx.Global = true Set matches = regEx.Execute(ingredients) For Each Match in Matches if (match.value <> "") then ingredient = match.value key = ingredient if (herbalHerbData.exists(ingredient & ".keyword")) then key = herbalHerbData.item(ingredient & ".keyword") end if jmc.parse "get " & key & " from " & container jmc.parse "put " & key & " to kit" end if Next else jmc.showme "Your previous mix was aborted, restarting it now. Abort and empty kit to mix a new lore." lore = herbalLoreInKit end if jmc.showme "Mixing " & herbalLoreName.item(lore) & " (" & lore & ") ..." jmc.parse "mix kit" End Sub Function HerbalKitGetPotionCount(lore) dim ingredients, RegExp, potions, partialPotions Set regEx = New RegExp ingredients = herbalLoreData.item(lore & ".ingredients") regEx.Pattern = "(\S*)" regEx.Global = true Set matches = regEx.Execute(ingredients) potions = 100 partialPotions = 0 Set usedHerbs = CreateObject("Scripting.Dictionary") For Each Match in Matches if (match.value <> "") then ingredient = match.value if (not usedHerbs.Exists(ingredient)) then usedHerbs.add ingredient, 0 end if if (herbalHerbData.exists(ingredient & ".stock")) then if (herbalHerbData.item(ingredient & ".stock") - usedHerbs.item(ingredient) < potions) then potions = herbalHerbData.item(ingredient & ".stock") - usedHerbs.item(ingredient) end if if (herbalHerbData.item(ingredient & ".stock") - usedHerbs.item(ingredient) > 0) then partialPotions = partialPotions + 1 end if usedHerbs.item(ingredient) = usedHerbs.item(ingredient) + 1 else potions = 0 end if end if Next if (potions = 0) then potions = -1 * partialPotions end if HerbalKitGetPotionCount = potions End Function Function HerbalKitGetMissingIngredients(lore) dim ingredients, RegExp, missing Set regEx = New RegExp ingredients = herbalLoreData.item(lore & ".ingredients") regEx.Pattern = "(\S*)" regEx.Global = true Set matches = regEx.Execute(ingredients) missing = "" Set usedHerbs = CreateObject("Scripting.Dictionary") For Each Match in Matches if (match.value <> "") then ingredient = match.value if (not usedHerbs.Exists(ingredient)) then usedHerbs.add ingredient, 0 end if if (herbalHerbData.exists(ingredient & ".stock")) then if (herbalHerbData.item(ingredient & ".stock") - usedHerbs.item(ingredient) < 1) then if (missing <> "") then missing = missing & " " end if missing = missing & ingredient end if usedHerbs.item(ingredient) = usedHerbs.item(ingredient) + 1 else if (missing <> "") then missing = missing & " " end if missing = missing & ingredient end if end if Next HerbalKitGetMissingIngredients = missing End Function Sub HerbalKitReset herbs = herbalHerbName.Keys herbCount = herbalHerbName.Count-1 For i = 0 To herbCount ' shortcut the herb we are searching for if (herbalHerbData.exists(herbs(i) & ".stock")) then herbalHerbData.item(herbs(i) & ".stock") = 0 end if Next jmc.showme "Herb inventory values cleared." End Sub Sub HerbalKit(line) dim cmd, lore, name, ingredients, RegExp, potionsFull, potionsPartial Set regEx = New RegExp If (line = "") Then lores = herbalLoreName.Keys loreCount = herbalLoreName.Count-1 potionsFull = "" potionsPartial = "" For i = 0 To loreCount potions = HerbalKitGetPotionCount(lores(i)) if (potions > 0) then potionsFull = potionsFull & string(2-len(potions), " ") & potions & " " & herbalLoreName.item(lores(i)) & " (" & lores(i) & ")" & vbNewLine end if if (potions < 0) then potionsPartial = potionsPartial & " 0 " & herbalLoreName.item(lores(i)) & " (" & lores(i) & ") (Missing: " & HerbalKitGetMissingIngredients(lores(i)) & ")" & vbNewLine end if Next jmc.showme potionsPartial & potionsFull Exit Sub End if if (line = "reset") then HerbalKitReset exit sub end if regEx.Pattern = "\s" cmd = line lore = "" if (regEx.test(line)) then lineArr = Split(line, " ", 2) cmd = lineArr(0) lore = lineArr(1) end if if (cmd = "mix") then HerbalKitMix(lore) end if if (cmd = "count") then potions = HerbalKitGetPotionCount(lore) if (potions < 0) then potions = 0 end if jmc.showme "You have ingredients for " & potions & " potions of " & herbalLoreName.item(lore) end if End Sub Set formatNumbers = CreateObject("Scripting.Dictionary") formatNumbers.Add "zero", 0 formatNumbers.Add "one", 1 formatNumbers.Add "two", 2 formatNumbers.Add "three", 3 formatNumbers.Add "four", 4 formatNumbers.Add "five", 5 formatNumbers.Add "six", 6 formatNumbers.Add "seven", 7 formatNumbers.Add "eight", 8 formatNumbers.Add "nine", 9 formatNumbers.Add "ten", 10 formatNumbers.Add "eleven", 11 formatNumbers.Add "a dozen", 12 formatNumbers.Add "thirteen", 13 formatNumbers.Add "fourteen", 14 formatNumbers.Add "fifteen", 15 formatNumbers.Add "sixteen", 16 formatNumbers.Add "seventeen", 17 formatNumbers.Add "eighteen", 18 formatNumbers.Add "nineteen", 19 formatNumbers.Add "twenty", 20 formatNumbers.Add "thirty", 30 formatNumbers.Add "forty", 40 formatNumbers.Add "fifty", 50 formatNumbers.Add "sixty", 60 formatNumbers.Add "seventy", 70 formatNumbers.Add "eighty", 80 formatNumbers.Add "ninety", 90 Function FormatTextToInteger(text) dim int, tens, ones int = "" Set regEx = New RegExp regEx.Pattern = "-" if (regEx.test(text)) then lineArr = Split(text, "-", 2) tens = lineArr(0) ones = lineArr(1) int = formatNumbers.item(tens) + formatNumbers.item(ones) else int = formatNumbers.item(text) end if if (int = "") then int = text end if FormatTextToInteger = int End Function