This is the new home of the egghelp.org community forum.
All data has been migrated (including user logins/passwords) to a new phpBB version.


For more information, see this announcement post. Click the X in the top right-corner of this box to dismiss this message.

[SOLVED] How to Call a Single Variable with Multiple Values

Help for those learning Tcl or writing their own scripts.
Post Reply
S
Seka
Voice
Posts: 18
Joined: Tue Apr 19, 2011 10:21 pm

[SOLVED] How to Call a Single Variable with Multiple Values

Post by Seka »

So, here's my question. If I have a single variable set with multiple values, as sampled below:

Code: Select all

set triggerwords {
mess
messy
mop
shift
crate
lamp
ocean
sea
}
And I want to use the variable $triggerwords to kick off a proc. Will the following code work properly if only one of the values is use in a line of text?

Code: Select all

bind pub - $triggerwords randaction

proc randaction {nick uhost channel hand text} {
putserv "PRIVMSG $channel :\001ACTION $randline."
}
$randline is a variable from another piece of code. I think you can see what I'm going for, with the format.

I keep re-reading it and thinking there's something wrong or missing.
Last edited by Seka on Thu Apr 21, 2011 2:33 pm, edited 1 time in total.
n
nml375
Revered One
Posts: 2860
Joined: Fri Aug 04, 2006 2:09 pm

Post by nml375 »

Technically, triggerwords has a single value. It's just a long string with multiple newlines within it. To some extent, it could also be considered a handcrafted list (though this requires caution).

The "pub" binds, or triggers, are matched against individual lines of text from a channel (and only against the first word of the line), so having multiple words or lines will not provide a suitable mask. However, there is nothing preventing you from creating multiple triggers; one for each word of your crafted list.
Something like this should take care of that:

Code: Select all

...
foreach item $triggerwords {
  bind pub - $item randaction
}
...
Now, for your proc "randaction";
You try to read the local variable randline, though there exists no such local variable within the proc. I would guess you intended to access the globalspace variable randline instead:

Code: Select all

proc randaction {nick host handle channel text} {
  puthelp "PRIVMSG $channel :\001ACTION $::randline\001"
}
This uses the :: fully qualified namespace path to access the variable. You could also use the "global" command to link the localspace variable to the globalspace of the same name though.
I also fixed the order of your parameters to match what the trigger will provide when calling the proc.
NML_375
S
Seka
Voice
Posts: 18
Joined: Tue Apr 19, 2011 10:21 pm

Post by Seka »

Awesome.

I will put this together and give it a try when I get back home.

Thanks for the help!
S
Seka
Voice
Posts: 18
Joined: Tue Apr 19, 2011 10:21 pm

Post by Seka »

The script is working the way it should, but I have one more issue.

The proc only responds when the trigger word is the first word in the post. So, it won't kick off if the word is in an "action" post or if the word is within a statement.

i.e. If the trigger word is "ocean" and a user says:

"The ocean is blue today!"
or
/me looks at the ocean.

Neither of the above posts will trigger the proc.

Any suggestions?
n
nml375
Revered One
Posts: 2860
Joined: Fri Aug 04, 2006 2:09 pm

Post by nml375 »

For actions, you have to remember that they're simple CTCP-action commands. As such, you'll need to use the CTCP binding for those. However, reading the docs, you'll see that the ctcp-bindings only matches against the ctcp-command, not it's arguments.. thus you'll have to bind against ACTION, and do some additional checking within your code:

Code: Select all

...
if {[string match -nocase -- "*ocean*" $the_text]} {
  #Stuff to do if the action contains "ocean"
Next, for normal messages, this is a little simpler; you'll have to replace the pub binding with a pubm (matching binding), along with a proper mask. Something like this should do the trick:

Code: Select all

bind pubm - "% *ocean*" pubm::randaction
Needless to say, since we're changing the bindings, make sure you adapt your proc(s) to the new bindings. Also, don't use the same proc for multiple bindings of different kinds unless you are absolutely sure on what you're doing - generally, it's a better idea to create a separate proc for each kind of binding.
NML_375
S
Seka
Voice
Posts: 18
Joined: Tue Apr 19, 2011 10:21 pm

Post by Seka »

Instead of using "*ocean*" since I stored the trigger words in $item, can I use that variable in the statement? Like below:

Code: Select all

bind pubm - $item pubm::randaction
Or will that rip a whole in the universe?

I can see that getting this script to do what I want is going to be a lot more effort than I'd planned for.
n
nml375
Revered One
Posts: 2860
Joined: Fri Aug 04, 2006 2:09 pm

Post by nml375 »

You could use $item to replace the ocean part of the mask (assuming that the variable exists in the given context).
The mask has to match against "#channel text spoken", so at a minimum you'd have to use "% *${item}*" or "*${item}*" (the latter would also match if the "trigger-word" is present in the channel name, which is why I recommend the first one).
NML_375
S
Seka
Voice
Posts: 18
Joined: Tue Apr 19, 2011 10:21 pm

Post by Seka »

Ok. Here is what I have for both of my binds and procs. They're also both present in the same script. I'm not sure if that is going to cause a problem, in itself.

I apologize for the lack of formatting. My editor doesn't appreciate TCL.

Code: Select all

foreach item $triggerwords {
 bind pubm - "% *${item}*" pubm:randaction
}

proc pubm:randaction {nick host hand channel text} {
putserv "PRIVMSG $channel ":\001ACTION $randline \001"
}
I omitted the lines that generate the $randline variable, for the sake of space.

Here is the ctcp bind:

Code: Select all

bind ctcp - "ACTION" action_randaction

proc action_randaction {nick host hand dest keyword text} {
if {[string index $dest 0] !="#"} {return 0} then {
 if {[string match -nocase -- "*$::item*" $text]} {
  putserv "PRIVMSG $channel :\001ACTION $randline \001"
  }
 }
}
Same deal here. The code for $randline does exist in the script. It's just missing here for the sake of space.
n
nml375
Revered One
Posts: 2860
Joined: Fri Aug 04, 2006 2:09 pm

Post by nml375 »

The first part looks ok.

As for the second part, your if-conditional is not proper; you can't have the "then" keyword in it's current position. The proper syntax is as follows:

Code: Select all

if {test} then {true-code} else {false-code}

#To ease readability, newlines may be added like this:
if {test} then {
  true-code
} else {
  false-code
}

#Further, the "then" and "else" keywords are optional:
if {test} {
  true-code
} {
  false-code
}

#Finally, we could also leave out the false-code part if it's not needed:
if {test} {
  true-code
}
In the above code, "test" would be a test that returns true or false;
true-code is a block of tcl-code that is to be evaluated if the test returns true;
false-code is a block of tcl-code that is to be evaluated if the test returns false
NML_375
S
Seka
Voice
Posts: 18
Joined: Tue Apr 19, 2011 10:21 pm

Post by Seka »

Ah, I see.

I dropped the "then" from the statement. The part that concerns me is the string match:

Code: Select all

if {[string match -nocase -- "*$::item*" $text]} { 
Is the variable formatted properly to generate a positive match? "*$::item*" seems so convoluted.
n
nml375
Revered One
Posts: 2860
Joined: Fri Aug 04, 2006 2:09 pm

Post by nml375 »

Oh, overlooked that part..
In this case, $::item would only hold the value of the last item of $triggerwords. You would have to use a similar foreach-loop within the proc to test each item in the list. You would also have to use break or return to prevent multiple responses if one line contains several of the triggers.
NML_375
S
Seka
Voice
Posts: 18
Joined: Tue Apr 19, 2011 10:21 pm

Post by Seka »

That piece may be a little beyond my means, then.

I really do appreciate all of the help you've given me with all of my requests! If there was a way to bump your ID to "guru" status, I would cast my vote! :)

Thank you again, for all of your help and patience. I've learned a lot about TCL.
Post Reply