Changing text color based on identifier

Posted by forral on Sun 11 Jul 2010 06:13 AM — 19 posts, 85,271 views.

USA #0
Hi,

I often find myself engaging in multiple conversations through private messages while playing, and its sometimes hard to keep track of which conversation is what when every private message is the same dark red color.

To make things easier for myself, I'd like some assistance in coding a plugin or script that changes text colors either every time I'm sent a message, or perhaps based on a table of some sort. If I were doing a table I might have administrators be colored white, clannies magenta, allies blue, and friends green, while everyone else gets a yellow color of some sort.

I'm not too tech savy so any help is appreciated. The string I would need to match is:

* tells you '*'

I'm not sure if it's actually possible to change the color of the text on the output screen itself, but that is basically want I'm wanting to do.

Thanks for any help/suggestions,
Forral
Australia Forum Administrator #1
You would need to omit the matching line from output, and then in a script (send to script after omit) use ColourNote to re-add that line, in a colour you choose, after doing a table-lookup of the names. This is all quite easy in Lua.
USA #2
The downside is that if two triggers fire on the same line and try to "modify" it like this, both echoes will appear.

Something else you might want to try is use one trigger as a selective "gate", and another partial trigger as the highlighter. Lets take the line "I like pie.", even though I don't, and lets assume we want to make only the "pie" in this line highlighted and no other pie.

<triggers>
 <trigger
  enabled="y"
  keep_evaluating="y"
  match="^I like pie\.$"
  regexp="y"
  send_to="12"
  sequence="100"
 >
 <send>Note("one")
EnableTrigger("pie_high", true)</send>
 </trigger>
 <trigger
  custom_colour="7"
  keep_evaluating="y"
  match="\bpie\b"
  name="pie_high"
  regexp="y"
  repeat="y"
  send_to="12"
  sequence="101"
 >
 <send>Note("two")
EnableTrigger("pie_high", false)</send>
 </trigger>
</triggers>


The first trigger simply says, "Hey, this is a line I'm interested in", and enables the highlighter. The highlighter matches a single word (rather than a full line), so its color changes are applied only to "pie" on that line. Then it disables itself, so no other "pie" is highlighted.
Amended on Sun 11 Jul 2010 11:11 PM by Twisol
USA #3
You can get even more creative with this by having multiple highlighters. Depending on the order you put them in (the Sequence of each one), you'll get different results, of course. Here's a modified version:

<triggers>
 <trigger
  enabled="y"
  keep_evaluating="y"
  match="^I like pie\.$"
  regexp="y"
  send_to="12"
  sequence="100"
 >
 <send>EnableTriggerGroup("pie_high", true)</send>
 </trigger>
 <trigger
  custom_colour="7"
  group="pie_high"
  ignore_case="y"
  keep_evaluating="y"
  match="\bpie\b"
  regexp="y"
  repeat="y"
  sequence="101"
 >
 </trigger>
 <trigger
  custom_colour="8"
  group="pie_high"
  ignore_case="y"
  keep_evaluating="y"
  match="i"
  regexp="y"
  repeat="y"
  send_to="12"
  sequence="102"
 >
 <send>EnableTriggerGroup("pie_high", false)</send>
 </trigger>
</triggers>


In this case, it colors "pie" red everywhere, then "i" blue everywhere. So the P and E in "pie" are now red, and the "i" is blue (because I "painted" over the red). If you reversed the highlighters, "pie" would be solid red, but other "i"s would still be blue.
Amended on Sun 11 Jul 2010 11:22 PM by Twisol
USA #4
make 4 triggers like.

<triggers>
<trigger
custom_colour="7"
enabled="y"
expand_variables="y"
match="^(!@Admins) tells you \: \'*'$"
regexp="y"
sequence="100"
>
</trigger>
</triggers>


And then make Variables like Admins (in the above example) in the format:

Joe|Jim|Bob|Nick

Give Admins a sequence number lower than 100 if you want them to be more important in your coloring...
USA #5
I got this to work. but it's kind of clunky if these lists are going to change.

<triggers>
  <trigger
   enabled="y"
   match="^(.*?) tells you '(.*?)'$"
   omit_from_output="y"
   regexp="y"
   send_to="14"
   sequence="90"
  >
  <send>

Administrators_Color = "white"
Clannies_Color = "magenta"
Allies_Color = "blue"
Friends_Color = "green"
Others_Color = "yellow"

Administrators = {
  ["Duende"] = true,
  ["Vassago"] =	true,
  ["add name here"] = true,
}

Clannies = {
  ["Deacla"] = true,
  ["Tuck"] = true,
  ["add name here"] = true,
}

Allies = {
  ["Alyce"] = true,
  ["Deathsmasher"] = true,
  ["add name here"] = true,
}

Friends = {
  ["add friends name"] = true,
  ["add friends name"] = true,
  ["add friends name"] = true,
}




if Administrators["%1"] then
  for _,v in ipairs(TriggerStyleRuns) do
    ColourTell(Administrators_Color, RGBColourToName(v.backcolour), v.text)
  end
elseif Clannies["%1"] then
  for _,v in ipairs(TriggerStyleRuns) do
    ColourTell(Clannies_Color, RGBColourToName(v.backcolour), v.text)
  end
elseif Allies["%1"] then
  for _,v in ipairs(TriggerStyleRuns) do
    ColourTell(Allies_Color, RGBColourToName(v.backcolour), v.text)
  end
elseif Friends["%1"] then
  for _,v in ipairs(TriggerStyleRuns) do
    ColourTell(Friends_Color, RGBColourToName(v.backcolour), v.text)
  end
else
  for _,v in ipairs(TriggerStyleRuns) do
    ColourTell(Others_Color, RGBColourToName(v.backcolour), v.text)
  end
end


Note() -- finish the line

</send>
 
 </trigger>

</triggers>

it would be great if you could add a name to the tables with aliases like 'AddClannie Billy' would add Billy to the Clannie table until you used 'RemoveClannie Billy' to remove him , but i'm not that good yet.
USA #6
Put those table definitions in your script file instead of in the trigger itself. If it's in the trigger, it'll be executed every time, and hence recreated every time. If you put it in the script file (Game -> Edit Script File, or create one if you haven't yet in Game -> Configure -> Scripting), then it'll only be created when the world is loaded or when you explicitly reload it (Game -> Reload Script File).

With that done, you can create aliases that use Clannies["name"] = true and Clannies["name"] = nil to add and remove the names. After that you'll want some way to save the state of the tables between sessions, but one step at a time. :)



As a side-note, I'm working on a highlighting library script that should make it much easier to colour parts of lines. It's an interesting task to tackle and I've already hit some road-bumps, but the core mechanism is hardly any different from what I showcased above.
Amended on Mon 12 Jul 2010 09:43 AM by Twisol
USA #7
Okay i'm trying to solve a different issue using the same basic concept. Following your outline i put this in a script named sacs.lua:

Sac_Items = {
  ["an iron cleaver"] = true
}

I don't really know how this works but it compiled fine. then I have this trigger in a separate plugin file:

<triggers>
  <trigger
   enabled="y"
   match="^You take (?P<item_name>.*) from the corpse of (?:.*)\.$"
   regexp="y"
   send_to="12"
   sequence="90"
  >
  <send>

if Sac_Items["%1"] then
  Send ("drop '" .. "%1" .. "'")
  Send ("sac '" .. "%1" .. "'")
end

  </send>
 
 </trigger>
</triggers>

But I keep getting this error:

Run-time error
Plugin: MM_Auto_Sac (called from world: Materia Magica)
Immediate execution
[string "Trigger: "]:3: attempt to index field 'Sac_Items' (a nil value)
stack traceback:
        [string "Trigger: "]:3: in main chunk

So I'm obviously not defining my variable correctly or passing the data at all...
USA #8
I'm guessing sacs.lua is never even executed. Where is sacs.lua located? What file is shown in the "script file" field at Game -> Configure -> Scripting? The script file is a file you associate with a world, and is run when the world is loaded or when the file itself is manually reloaded. You need to put your Sac_Items definition in that specific file.

EDIT: A bit unrelated, but you're using "%1" there when it seems like you'd want "%<item_name>" instead.
Amended on Tue 13 Jul 2010 09:37 AM by Twisol
USA #9
sacs.lua is located at C:\Program Files\MUSHclient\worlds\plugins\sacs.lua
I created it using the 'new' button in configuration -> scripts. The file name is there in the 'Script File' box. I access it via CTRL+Shift+H, edit it, and when i save it asks if i want to reload it. Should i also put that filename elsewhere? Like in the 'World Events' somewhere?
USA #10
Hm. That's odd. Make sure nothing is overwriting it, like an older alias or trigger. Also make sure the table isn't declared with the 'local' keyword.

World Events is for scripting callbacks, like when the world is connecting or disconnecting and such. It's unnecessary for merely having the file executed when the world starts.
Australia Forum Administrator #11
Deacla said:

Run-time error
Plugin: MM_Auto_Sac (called from world: Materia Magica)


Plugins are in a different script space from the main world script file.

I would look up about serialization in Lua, that is the way to go with saving variables from one session to another.
USA #12
Whoops, I totally missed that "Plugin" bit in the error... Good catch.
USA #13
So going off of what Nick was saying, I ditched the plugin and am now trying to get this idea to work using the 'edit trigger' and 'edit alias' dialog boxes. If i use the little 'copy' buttons it gives me this:

<triggers>
  <trigger
   enabled="y"
   group="sac_items"
   match="^You take (.*?) from the corpse of (?:.*)\.$"
   regexp="y"
   send_to="12"
   sequence="99"
  >
  <send>
if AutoSacItems["%1"] then
  Send ("drop '" .. "%1" .. "'")
  Send ("sac '" .. "%1" .. "'")
end
</send>
  </trigger>
</triggers>

The trigger now works great outside of a plugin.

<aliases>
  <alias
   match="AddSacItem *"
   enabled="y"
   send_to="12"
   sequence="100"
  >
  <send>AutoSacItems["%1"] = true
Note ("Added '" .. "%1" .. "' to AutoSacItems list.")</send>
  </alias>
</aliases>

This alias works great too as does another alias 'DelSacItem *'. I am able to add/remove items from the AutoSacItems table while the world is open. my problem now is getting the save state code to work and where do I put it so the table will still be available when i next load the world?
Australia Forum Administrator #14
Read this about serialization:

Template:post=4960
Please see the forum thread: http://gammon.com.au/forum/?id=4960.


In a plugin it is simple (there is example code in that thread). Basically serialize.save will convert a Lua table into a string, which you can then put in a MUSHclient variable and have that saved. You can also do it in the main script file as there is a world file callback for "world save". But plugins are safer because the plugin state file is always saved. Plus plugins are easier to share between worlds or other players.

To get it back next time outside a plugin, use the "world open" script callback. In a plugin use the OnPluginInstall function callback.
USA #15
Well my first goal is ease of use, and second portability. So I went back to the plugin and dropped the script file. It works while the world is open just like before. but the serialization is either not saving or its loading incorrectly. Does OnPluginInstall load every time the world opens or just the first time the plugin is installed? and now the code.
</plugin>

<triggers>
  <trigger
   enabled="y"
   match="^You take (.*) from the corpse of (?:.*)\.$"
   regexp="y"
   send_to="12"
   sequence="90"
  >
  <send>

  Note("%1") 							-- make a note to see what was captured

  if AutoSacItems["%1"] then			-- check item name for match in table
    Send ("drop '" .. "%1" .. "'")
    Send ("sac '" .. "%1" .. "'")
  end -- if

  </send>
 
 </trigger>
</triggers>
<aliases>
  <alias
   match="AddSacItem (.*)"
   regexp="y"
   enabled="y"
   send_to="12"
   sequence="100"
  >
  <send>AutoSacItems["%1"] = true
Note ("Added '" .. "%1" .. "' to AutoSacItems list.")</send>
  </alias>
</aliases>

<script>
<![CDATA[

require "serialize"  -- needed to serialize table to string

AutoSacItems = {}  -- ensure table exists, if not loaded from variable

-- on plugin install, convert variable into Lua table

function OnPluginInstall ()
  assert (loadstring (GetVariable ("AutoSacItems") or "")) ()
end -- function OnPluginInstall

-- on saving state, convert Lua table back into string variable

-- save_simple is for simple tables that do not have cycles (self-reference)
-- or refer to other tables

function OnPluginSaveState ()
  SetVariable ("AutoSacItems", 
               "AutoSacItems = " .. serialize.save_simple (AutoSacItems))
end -- function OnPluginSaveState

]]>

</script>

I copy/pasted the last bit from your serialization topic and plugged in my own variable name. My plan is to expand on this functionality once the core is working, then passing it on all the other MM'ers on MUSH..
Australia Forum Administrator #16
Deacla said:

Does OnPluginInstall load every time the world opens or just the first time the plugin is installed?


After the plugin is installed, OnPluginInstall is called.

Did you set save_state="y" in the plugin header? Check the save state file (RH-double-click on the plugin in the plugin list).
USA #17
*Smacks forehead*
Doh! It's always something simple. Just had to add that one flag. I'll post the full plugin once I've fleshed out the alias's.
USA #18
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>

<muclient>
<plugin
   name="MM_Auto_Sac"
   author="Deacla"
   id="dc109a6028175ae32994c209"
   language="Lua"
   save_state="y"
   purpose="Auto Sacs Items"
   requires="4.52"
   version="1.0"
   >
<description trim="y">
<![CDATA[

---------------------------------------------------------------------------
---------------------------++++++++++++++++--------------------------------

MUD: Materia Magica
Requires: serialize.lua

This plugin keeps a list of items that are to be automatically
sacrified when you grab them from a corpse. It also saves this list
when MUSHclient is closed. Command line usage is as follows:

ASI item name	(Adds Item 'item name' to the auto-sac list)
RSI item name	(Removes Item 'item name' to the auto-sac list)
sacson			(Turns on all auto-sac triggers)
sacsoff			(Turns off all auto-sac triggers)
sacshelp		(Displays this command list)

---------------------------++++++++++++++++--------------------------------
---------------------------------------------------------------------------

]]>
</description>
</plugin>

<triggers>
  <trigger
   enabled="y"
   group="AutoSacTriggers"
   match="^You take (.*) from the corpse of (?:.*)\.$"
   name="SacFromCorpse"
   regexp="y"
   send_to="12"
   sequence="90"
  >
  <send>

  if AutoSacItems["%1"] then			-- check item name for match in table
    Send ("drop '" .. "%1" .. "'")
    Send ("sac '" .. "%1" .. "'")
  end -- if

  </send>
 
 </trigger>
</triggers>
<aliases>
  <alias
   match="^ASI (.*)$"
   regexp="y"
   enabled="y"
   send_to="12"
   sequence="100"
  >
  <send>AutoSacItems["%1"] = true
Note ()
ColourTell("silver", "black", "Added '" .. "%1" .. "' to AutoSacItems list.")
Send ("")</send>
  </alias>
  <alias
   match="^RSI (.*)$"
   regexp="y"
   enabled="y"
   send_to="12"
   sequence="100"
  >
  <send>AutoSacItems["%1"] = nil
Note ()
ColourTell("silver", "black", "Removed '" .. "%1" .. "' from the AutoSacItems list.")
Send ("")</send>
  </alias>
  <alias
   match="^sacson$"
   regexp="y"
   enabled="y"
   send_to="12"
   sequence="100"
  >
  <send>EnableTriggerGroup ("AutoSacTriggers", true)
Note ()
ColourTell("silver", "black", "Sacs are now ON!.")
Send ("")</send>
  </alias>
  <alias
   match="^sacsoff$"
   regexp="y"
   enabled="y"
   send_to="12"
   sequence="100"
  >
  <send>EnableTriggerGroup ("AutoSacTriggers", false)
Note ()
ColourTell("silver", "black", "Sacs are now OFF!.")
Send ("")</send>
  </alias>
  <alias
   match="^sacshelp$"
   regexp="y"
   enabled="y"
   send_to="12"
   sequence="100"
  >
  <send>
Note ()
ColourTell("white", "black", "Auto_sac commands:")Note()
ColourTell("silver", "black", "ASI item name")Note("    (Adds Item 'item name' to the auto-sac list)")
ColourTell("silver", "black", "RSI item name")Note("    (Removes Item 'item name' to the auto-sac list)")
ColourTell("silver", "black", "sacson")Note("           (Turns on all auto-sac triggers)")
ColourTell("silver", "black", "sacsoff")Note("          (Turns off all auto-sac triggers)")
Send ()</send>
  </alias>
</aliases>

<script>
<![CDATA[

require "serialize"  -- needed to serialize table to string

AutoSacItems = {}  -- ensure table exists, if not loaded from variable

-- on plugin install, convert variable into Lua table

function OnPluginInstall ()
  assert (loadstring (GetVariable ("AutoSacItems") or "")) ()
end -- function OnPluginInstall

-- on saving state, convert Lua table back into string variable

-- save_simple is for simple tables that do not have cycles (self-reference)
-- or refer to other tables

function OnPluginSaveState ()
  SetVariable ("AutoSacItems", 
               "AutoSacItems = " .. serialize.save_simple (AutoSacItems))
end -- function OnPluginSaveState

]]>

</script>
</muclient>