Plugin Request: Zombies

Posted by Fevix on Tue 23 Jan 2018 11:05 PM — 26 posts, 92,419 views.

#0
I'd like a plugin that watches for incoming lines with a certain prefix and moves that line to a miniwindow. Optimally, that miniwindow would have a textbox that would send text entered there back to the MUCK with a preprogrammed prefix as well (The 'send this to the zombie' prefix)

The plugin should be able to handle many miniwindows at the same time. I don't mind if I have to set things up for it to work, but I'll answer any questions people have.
Australia Forum Administrator #1
The stuff described in the post below covers most of that:

Template:post=12855
Please see the forum thread: http://gammon.com.au/forum/?id=12855.
#2
Okay, I installed all of that given the instructions in the second post, made a trigger in the .MCL file, but it's not moving the requested output to another window.

------

EDIT: Okay I got it to SOMEWHAT work, but now I've got "Trigger function "chattrigger" not found or had a previous error." whenever a message should be moved.

Also, from the looks of things there's only one communications box? I was hoping for several, as I have many puppets and would like one for each. There also doesn't appear to be a place for me to input a command in the communication box.

------

Edit2: Got it working fully, but is there a way to both hide the message in the main menu and hide the prefix used to 'capture' the message in the miniwindow?

While the issues in this edit are much easier to ignore, the lack of multiple boxes and lack of text entry are both critical 'flaws to the use case I'm trying to get out of it, and I lack the skills necessary to rectify ANY of these issues.

My use case in more detail: I control several zombies/puppets, each of which can be interacting with another player at any time. Currently, all puppets report everything they see to the main window, which can lead to actions getting buried quickly, especially if I'm using a puppet's menus to update/change settings on it. It gets even worse when multiple puppets are interacting with the same player(s) in the same room, as each puppet will report what it sees individually, so when something happens in that room, I get it once for each puppet even though the player only sent one message:

Puppet1> Player does something
Puppet2> Player does something
Puppet3> Player does something
Puppet1> You do something
Puppet2> Puppet1 does something
Puppet3> Puppet1 does something

In this case, I'd like to be able to have each puppet's 'reports' (Denoted by their name, then ">" then a space) sent to their own window, and each puppet's window should have a chatbox that takes what I type there and prefixes it with my preconfigured "send force to puppetX" command.
Amended on Wed 24 Jan 2018 03:05 PM by Fevix
USA Global Moderator #3
Quote:
There also doesn't appear to be a place for me to input a command in the communication box.


I think Nick was thrown off by you describing how you think something should work rather than what you actually want to accomplish. Miniwindows just aren't good for this. Next time post your use case scenario first and we'll understand better how to help.

You'll find that the many worlds interpretation of quantum MUCK theory more closely fits your scenario.

Read the first post in this thread:
https://www.mushclient.com/forum/bbshowpost.php?id=7991

You'll want an output world per zombie, and your main world redirect trigger should set the value of chat_world according to whichever zombie has been captured.
Amended on Wed 24 Jan 2018 04:12 PM by Fiendish
#4
So I would just put the "chat_world=whatever" on the trigger?
Australia Forum Administrator #5
That would probably do it.
#6
How do I add the plugin to just one world?
Amended on Fri 26 Jan 2018 10:54 PM by Fevix
Australia Forum Administrator #7
File Menu -> Plugins -> Add.
#8
I've been sitting here waiting for 15 minutes because I hit some sort of timer that prevented me from posting.... (Edit: I post this and get a 27 minute mute? Come on, how is anyone supposed to have a conversation)
Anyways, now that I can finally say something:

What do I change this line to if I want to, say, prefix all commands sent back to the main world with "Pup1 " to control Puppet1?
"w:Execute (command)"

Additionally, when I added the plugin, I got a warning for each of the triggers. Here's one:
[WARNING] C:\Program Files (x86)\MUSHclient\worlds\plugins\Chat Redirector.xml
Line 44: Attribute not used: chat_world="Keith" (trigger)
Amended on Fri 26 Jan 2018 11:12 PM by Fevix
Australia Forum Administrator #9
I've marked you as a trusted user so you shouldn't get the timeout again.

Quote:

What do I change this line to if I want to, say, prefix all commands sent back to the main world with "Pup1 " to control Puppet1?
"w:Execute (command)"


Well:


w:Execute ("Pup1 " .. command)





Quote:

So I would just put the "chat_world=whatever" on the trigger?
...
Additionally, when I added the plugin, I got a warning for each of the triggers. Here's one:


When you said "on the trigger" I thought you were going to do that in the script section.

So for example, if your trigger is:

*> *

Then the first wildcard is the puppet name. You would then put that into the variable (in the function 'redirect') like this:


function redirect (name, line, wildcards, styles)

  chat_world = wildcards [1]  -- change which world to send to

...
#10
The wildcard version won't work. The > symbol appears in many places (primarily in exit names, to denote a shortcut, eg "Go <deeper> into the dark cave"(And making sure there's no space won't work either, because "Go" is sometimes omitted, eg "<Deeper> into the dark cave")).

There, the wildcard would attempt to match something that isn't a puppet name.

Currently I just have each puppet report prefix in it's own trigger. Is there a way to figure out which trigger (index?) called the function? I'm not really a programmer but I tend to come up with multiple solutions.

One such solution could be to parse the string after it's been called to the function, get the first word, knock off the greater than symbol, and set chat_world to the word. This could allow me to trim the triggers down to just one of the same trigger can have multiple strings to match

-----

Edit: I've implemented the solution mentioned above (Added a line before your original first line in the redirect function to call a parsing script that returns everything before the first ">") so now all of the triggers can just call the same function.

Now I just need to figure out if I can combine the triggers all into one (Cause the only difference is the search string)

-----

Edit2: Okay, it's... "working". The plugin will open the correct world, but immediately it tells me "can't open chat world file ___________" for each line despite the fact that the chat world is open and properly named.

Here's a screenshot (I disabled the bit that only showed the error the first time around because I have so many bots and don't want the error to hide if I have more than one puppet messed up)

https://gyazo.com/f5c8dcfa823a906a7848bbc6081a63b2
Amended on Sat 27 Jan 2018 04:55 AM by Fevix
Australia Forum Administrator #11
That link served up a blank page for me. Looks like an authentication issue. Can't you use imgur or something like that? Check that the resulting image works even if you aren't logged in (make a private Firefox/etc. window to do that).
#12
Gyazo has never done that to anyone else I've sent the links to but okay.

https://imgur.com/a/ovG9K
I have an idea as to what it might be...

Does MUSHclient look at that name field in the properties or does it look at the window titles?
Amended on Sat 27 Jan 2018 05:17 AM by Fevix
Australia Forum Administrator #13
That's odd. The world seems to be there. Can you find the world list? Open an Immediate scripting window (Ctrl+I) and paste this:


for k, v in pairs (GetWorldList()) do 
  print (k, v) 
end


And maybe this as well:


for k, v in pairs (GetWorldIdList()) do 
  print (k, v) 
end


Paste the results you get here.
Australia Forum Administrator #14
Fevix said:

Does MUSHclient look at that name field in the properties or does it look at the window titles?


It's the world name in the configuration (that you showed). So "Keith" would be OK. Maybe it is capitalization.
#15
I've just gone to bed, I'll work on this in the morning

Thank you for spending so much time helping me get this working.
#16
Alright, it's the morning now. And somehow, it's working just fine with zero changes between last night and now.

Now my only issue is the commands adding to the main menu (Ex., when I use "Kei Look" it adds a line with only "Kei Look" to the main screen (Same thing happens when I use the sub-world's plugin))

Other than the above, which is perfectly tolerable, it's working perfectly. Thank you SO MUCH for helping me out!

Edit: And now even that issue is resolved! Thank you again!

Edit2: I'm now wondering if there's some way to strip off the trigger (the "puppet1> " part) before sending it to the chat_world (So that I can set all the windows to 80 columns, the default for this MUCK, and not have the triggers turn that into more than 80 and cause linebreaks where there shouldn't be some)
I COULD just add the length of the trigger to the columns, but then I'd have a buncha different-sized windows.

This is what I'm trying, but it's not changing what's sent to the world:

<script>
<![CDATA[
chat_world = ""

function redirect (name, line, wildcards, styles)

  chat_world = string.sub (string.match (line, "[^ ]->"), 1, -2) -- figure out which world is the chat_world
  line = string.sub(line, string.len(string.match (line, "[^ ]->"))+2, -1) -- Attempt to separate the actual line from the trigger

  -- try to find "chat" world
  local w = GetWorld (chat_world)  -- get "chat" world

  -- if not found, try to open it
  if not w then
    local filename = GetInfo (67) .. chat_world .. ".mcl"
    Open (filename)
    w = GetWorld (chat_world)  -- try again
    if not w then
      ColourNote ("white", "red", "Can't open chat world file: " .. filename)
    end -- can't find world
  end -- can't find world first time around

  if w then  -- if present
    for _, v in ipairs (styles) do
      w:ColourTell (RGBColourToName (v.textcolour),
                    RGBColourToName (v.backcolour),
                    v.text)
    end -- for each style run
    w:Note ("")  -- wrap up line

  end -- world found

end -- function redirect

]]>
</script>


Then only reason I'm calling the redirect function by defining it into a variable is because I couldn't find hide nor hair about just CALLING a function in lua, every site I tried to look up only had information about using functions as variable, not just outright calling them. So rather than experiment and get it wrong 20 times I just used something I knew would work.

Edit3: Changed the script, merged both sub-functions into the main function (Why did I even MAKE them sub-functions?)

Edit4: I tried modifying the colortell to wrap it in an "if not" to just not send the message if v.text was the prefix but then it wouldn't send anything at all

for _, v in ipairs (styles) do
      if not v.text == chat_world .. "> " then
        w:ColourTell (RGBColourToName (v.textcolour),
                      RGBColourToName (v.backcolour),
                      v.text)
      end
    end -- for each style run


Edit5:
Slight issue, not exactly critical but ANSI styles aren't moving over. For example, the OOC command is supposed to render in italics.
Main window (correct): https://gyazo.com/6a81ba8e5dc9f0ac171e21d9ccf6f2a4
Keith's window (incorrect): https://gyazo.com/f5ac650ba7cbd13c2d0a0e69ed95ded0

So to recap (Neither of these are critical)
- Strip the prefix from messages ("Keith> ")
- Transfer ANSI styles (Italics, bold, underline)
Amended on Sat 27 Jan 2018 05:42 PM by Fevix
Australia Forum Administrator #17
Quote:

I'm now wondering if there's some way to strip off the trigger (the "puppet1> " part)


You would need to identify how many style runs it takes (ie. are there multiple colours there?). If it is always in the first style run you could modify that before looping and sending the styles. eg.


styles [1] = string.gsub (styles [1], "^[^>]+", "")





Quote:

I couldn't find hide nor hair about just CALLING a function in lua


Same as in many languages:


function foo (bar)
  print (bar)
end -- function foo

foo (42)  --> call foo


You use the function name and put the arguments after it in parentheses. If there are no arguments you still use the parentheses, eg.


foo ()


Also, if you have an assignment it works like this:


a = foo    --> function foo is copied into 'a'
a ()       --> call 'a' (which effectively calls foo)
a = foo () --> foo is called, and the result of the call copied into 'a'





Quote:

Slight issue, not exactly critical but ANSI styles aren't moving over.


The styles can't be directly output using ColourTell, however you can use NoteStyle at the start of each sequence to change the style.

Template:function=NoteStyle
NoteStyle

The documentation for the NoteStyle script function is available online. It is also in the MUSHclient help file.



You can easily do that by adding one line:


 if w then  -- if present
    for _, v in ipairs (styles) do
      w:NoteStyle (v.style)   --> change to the appropriate style
      w:ColourTell (RGBColourToName (v.textcolour),
                    RGBColourToName (v.backcolour),
                    v.text)
    end -- for each style run
    w:Note ("")  -- wrap up line
  end -- world found
Amended on Sat 27 Jan 2018 10:14 PM by Nick Gammon
#18
Nick Gammon said:
You would need to identify how many style runs it takes (ie. are there multiple colours there?). If it is always in the first style run you could modify that before looping and sending the styles. eg.


styles [1] = string.gsub (styles [1], "^[^>]+", "")


Yes, the whole prefix is always the same color (In my case I just leave it the default white, and I confirmed by adding a debug line "print(v.text)" into the loop and observint the output, the first style in each line is always the prefix and the space) This would go in the for/do loop? Or before it to change the first style before it enters the loop?

[EDIT] I just tried both places and it gave me this error:
[string "Plugin"]:23: bad argument #1 to 'gsub' (string expected, got table)
stack traceback:
	[C]: in function 'gsub'
	[string "Plugin"]:23: in function <[string "Plugin"]:3>

I inserted a similar debug line ("print(styles [1])") just before the loop and got this:
table: 02D87940


-----

Nick Gammon said:
The styles can't be directly output using ColourTell, however you can use NoteStyle at the start of each sequence to change the style.

(function=NoteStyle)

You can easily do that by adding one line:


 if w then  -- if present
    for _, v in ipairs (styles) do
      w:NoteStyle (v.style)   --> change to the appropriate style
      w:ColourTell (RGBColourToName (v.textcolour),
                    RGBColourToName (v.backcolour),
                    v.text)
    end -- for each style run
    w:Note ("")  -- wrap up line
  end -- world found



Thanks! I'll try this!
Amended on Sun 28 Jan 2018 12:14 AM by Fevix
Australia Forum Administrator #19
Fevix said:

Or before it to change the first style before it enters the loop?


Before the loop. If it is in the first style, and that is all the first style has in it, just delete the style:


table.remove (styles, 1)  -- remove first style run


(Before the loop).
#20
That last one only works when the style changes right after the prefix. It'll remove the entire line if there's no style changes anywhere.

Again, this change isn't critical and I'm perfectly fine without it.

Could we make a script for the sub-windows that does this? Every line coming in WILL have the prefix (The line doesn't get sent unless it does) so we can just search it for the first instance of "> " and erase that and anything before it.
Amended on Sun 28 Jan 2018 12:29 AM by Fevix
#21
Okay I'm lost. Suddenly I'm getting errors:

Trigger function "chattrigger" not found or had a previous error.


But no plugin currently loaded even has the word "chattrigger" in it.

How can I see all currently loaded files?
Amended on Sun 28 Jan 2018 01:55 AM by Fevix
Australia Forum Administrator #22
Yes, but does one of your triggers have that word? Try turning on Trace. Game menu -> Trace
#23
None of the plugins visible on EITHER window (main or sub) have the word "chattrigger" anywhere in the file (Opened it up in ST3 and searched, even searched the entire plugins directory for it, no match)

Trace output:

TRACE: Matched trigger "Rylami> *"
TRACE: Matched trigger "Rylami> "
Trigger function "chattrigger" not found or had a previous error.
TRACE: Executing trigger script "redirect"


This doesn't help me at all.
#24
I forgot that when installing the first one I added triggers to the main world file. That's what's calling this.

Sorry for forgetting that.
Australia Forum Administrator #25
Fevix said:

Trace output:

TRACE: Matched trigger "Rylami> *"
TRACE: Matched trigger "Rylami> "
Trigger function "chattrigger" not found or had a previous error.
TRACE: Executing trigger script "redirect"


This doesn't help me at all.


Actually:

  • Two triggers matched (and they are different). That is a clue.
  • The second one caused the error message but not the first


Another clue would have been to disable all your plugins and see if it still happened. (I had guessed you had a rogue trigger in your mail world file, as you said that the trigger was not in the plugin).

Had you done that, it would have confirmed the issue was somewhere other than the plugins. And where else could that be?

(I know you worked it out, but I am showing the debugging process).