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.

"Tip of the day"

Issues often discussed about Tcl scripting. Check before posting a scripting question.
User avatar
slennox
Owner
Posts: 593
Joined: Sat Sep 22, 2001 8:00 pm
Contact:

Post by slennox »

I agree--let's call it the Tcl FAQ :) The big posts appearing here should have their own topics, but I suppose having to request a mod create the topic discourages this. So I've created a new FAQ Maintainers group whose members can create new topics. The members added are people who've made large posts here:

^DooM^
Sir_Fz
greenbear
Linux
sKy
demond

You should be able to split a topic you've posted here into a separate one (if you can't, let me know and I'll check the permissions).
User avatar
Sir_Fz
Revered One
Posts: 3793
Joined: Sun Apr 27, 2003 3:10 pm
Location: Lebanon
Contact:

Post by Sir_Fz »

Nice, that's a good idea. And it works fine with me, I can split :)
User avatar
sKy
Op
Posts: 194
Joined: Thu Apr 14, 2005 5:58 pm
Location: Germany

Post by sKy »

Oh well, it is like some kind of 'honours' that you put my name with all those other profis in 1 group. My knownage about tcl is only 10 of 100 percent and my english isn`t good too. But i have some experience with forum moderation. I like this communty and try to support if i can.
User avatar
Sir_Fz
Revered One
Posts: 3793
Joined: Sun Apr 27, 2003 3:10 pm
Location: Lebanon
Contact:

Post by Sir_Fz »

When using if-else statements you should know that you can't use more than 1 else. For example:

Code: Select all

if {[botisop $chan]} {
 pushmode $chan -o $nick
} else {
 puthelp "PRIVMSG $chan :I'm not oped."
}
But you can use several elseifs, for example:

Code: Select all

if {[botisop $chan]} {
 pushmode $chan -o $nick
} elseif {[isop $other $chan]} {
 puthelp "PRIVMSG $other :please deop $nick on $chan."
} elseif {[isop $other2 $chan]} {
 puthelp "PRIVMSG $other2 :please deop $nick on $chan."
} else {
 puthelp "PRIVMSG $chan :neither me, $other or $other2 are oped on $chan."
}
User avatar
Sir_Fz
Revered One
Posts: 3793
Joined: Sun Apr 27, 2003 3:10 pm
Location: Lebanon
Contact:

Post by Sir_Fz »

In an if statement, || stands for 'or' and && stands for 'and'. So this statement

Code: Select all

if {[botisop $chan] || [isop $nick $chan]} {
 putlog "Either the bot or $nick is oped on $chan."
}
is satisfied if either the bot or $nick is oped on $chan (atleast 1 of the conditions should be satisfied so if both are oped it's satisfied as well), if neither are oped then it will not putlog anything. While this statement

Code: Select all

if {[botisop $chan] && [isop $nick $chan]} {
 putlog "Both the bot and $nick are oped on $chan."
}
is satisfied if both the bot and $nick are oped on $chan (all conditions should be satisfied), if neither or only 1 is oped then it will not putlog anything.
User avatar
demond
Revered One
Posts: 3073
Joined: Sat Jun 12, 2004 9:58 am
Location: San Francisco, CA
Contact:

Post by demond »

it should be noted that Tcl implements so-called "lazy evaluation" of boolean expressions (just like C/C++ and other languages); what does that mean?

if you happen to have (pseudo code):

Code: Select all

if {<expr1> || <expr2>} {
   ...
}
and <expr1> evaluates to non-zero value (i.e. true), <expr2> will not be evaluated at all (because if's result doesn't depend on it, and will always be true, regardless of <expr2> being zero or non-zero) and execution will proceed within if's body; similarly, if you have:

Code: Select all

if {<expr1> && <expr2>} {
   ...
}
if's body will be immediately skipped if <expr1> evaluates to zero (<expr2> will not be evaluated since the if's result doesn't depend on it)

that makes possible constructions like this:

Code: Select all

if {[info exists foo] && ($foo == $bar)} {
   # do something
}
which will check whether $foo==$bar only if foo exists
User avatar
Sir_Fz
Revered One
Posts: 3793
Joined: Sun Apr 27, 2003 3:10 pm
Location: Lebanon
Contact:

Post by Sir_Fz »

<owner> .set errorInfo
<bot> What? You need '.help'
That means dcc .set command is unbound. To make it work, go to your .conf file and change the line that says:
unbind dcc n set *dcc:set
to
#unbind dcc n set *dcc:set
And that applies to the tcl command as well (the bind that's before it).

Remember that if you have must-be-owner set to 1 then you should put your handle in the owner variable
set owner "<your handle>"
PS: All those variables are documented, read them.
User avatar
sKy
Op
Posts: 194
Joined: Thu Apr 14, 2005 5:58 pm
Location: Germany

recovering tcl files

Post by sKy »

Once a day i have deleted a .tcl file by error. This wasn`t the end of days becuase it was still in the memory.

Code: Select all

# the new file
set ::proc_recover(setting,file) recoverfile.tcl

proc recover { pattern } {
	set file [open $::proc_recover(setting,file) a]
	foreach proc [lsort [info commands]] {
		if { [string match -nocase $pattern $proc] || [string equal -nocase $pattern $proc] } {
			puts $file "\n"
			puts $file "############################################################################################################################"
			puts $file "# $proc"
			puts $file "############################################################################################################################"
			puts $file "\n"
			puts $file "proc $proc \{ [info args $proc] \} \{"
			puts $file "[info body $proc]"
			puts $file "\}"
		}
	}
	close $file
}

# .tcl recover $pattern
# the pattern must be the exact procname or match it (wildcards possible)
Perhaps you want to change somethings to you own needs. The only thing you miss will be binds, global variables and comments.
.tcl foreach var [lsort [info globals]] { putlog $var }
.tcl foreach bind [binds] { putlog $bind }
.tcl foreach bind [binds pub] { putlog $bind }
If you restarted the bot after then you have to google for "undelete" (depends on your platform).
User avatar
awyeah
Revered One
Posts: 1580
Joined: Mon Apr 26, 2004 2:37 am
Location: Switzerland
Contact:

Post by awyeah »

A lot of people I have seen request simple AI scripts which they can use on their bots and configure themselves later.

Basically what we need to do here is to bind on specific keywords in the text or match on all and let the bot spit on a random reply from a list.

(1) For this the 'rand' function can help.

Code: Select all

set reply [rand 5]
#This would return a random integer between 0 and 4 for the variable $reply.

(2) First check the length of your list so that the random number generated doesn't exceed the length of your list, which 'llength' does:

Code: Select all

set reply [rand [llength $replies]]
#This would return a random integer between limits of your list for the variable $reply.


(3) Then we can continue to retrieve an element from the list by using lindex.

Code: Select all

set reply [lindex $replies [rand [llength $replies]]]
#This would retrieve a random element from the list and save it in the variable $reply.

Code: Select all

#In short here is an example script:

set replies {
{hi!}
{how are you?}
{whats up}
}

bind pubm - "*" auto:reply

proc auto:reply {nick uhost hand chan text} {
 global replies
 putserv "PRIVMSG $chan :[lindex $replies [rand [llength $replies]]]"
}
·­awyeah·

==================================
Facebook: jawad@idsia.ch (Jay Dee)
PS: Guys, I don't accept script helps or requests personally anymore.
==================================
User avatar
demond
Revered One
Posts: 3073
Joined: Sat Jun 12, 2004 9:58 am
Location: San Francisco, CA
Contact:

Post by demond »

you can embed inline, instead of the proc name argument of [bind], any code that doesn't depend on arguments passed by [bind]:

Code: Select all

bind evnt - init-server {putserv "privmsg nickserv :id password";#}
;# at the end does the trick - it forces any arguments passed by [bind] to be ignored as comment

Tcl supports declaring variable number of arguments with keyword args, which allows you to use the same proc for several binds that would call it with different number of arguments:

Code: Select all

bind msg - hi foo
bind pub - hi foo
proc foo {nick args} {
   putserv "privmsg $nick :hello goober"
}
User avatar
user
&nbsp;
Posts: 1452
Joined: Tue Mar 18, 2003 9:58 pm
Location: Norway

Re: recovering tcl files

Post by user »

sKy wrote:

Code: Select all

			puts $file "proc $proc \{ [info args $proc] \} \{"
			puts $file "[info body $proc]"
			puts $file "\}"
Try this instead:

Code: Select all

proc printproc proc {
	set args {}
	foreach arg [info args $proc] {
		if {[info default $proc $arg val]} {
			lappend args [list $arg $val]
		} {
			lappend args [list $arg]
		}
	}
	list proc $proc $args [info body $proc]
}
+

Code: Select all

puts $file [printproc $proc]
Have you ever read "The Manual"?
User avatar
Linux
Halfop
Posts: 71
Joined: Sun Apr 04, 2004 4:20 pm
Location: Under The Sky

Match characters

Post by Linux »

Match characters

Bindings allow match characters in the arguments. Here are few special characters:

? matches any single character

* matches 0 or more characters of any type

% matches 0 or more non-space characters (can be used to match a single word)

~ matches 1 or more space characters (can be used for whitespace between words)
I'm an idiot, At least this one [bug] took about 5 minutes to find...
User avatar
demond
Revered One
Posts: 3073
Joined: Sat Jun 12, 2004 9:58 am
Location: San Francisco, CA
Contact:

Post by demond »

while most people already learned they have to split the string text argument provided by many eggdrop binds into Tcl list first before using list commands on it, very few are aware that after using [split] extra white space will end up being empty list element(s), which will screw up argument indexing

here is one neat solution to this problem, from Tcler's wiki:

String to list: [split $s] alone operates on each instance of the splitchar (default:space), so sequences of spaces will produce empty list elements. [eval list $s] collapses whitespace sequences in one, but errors on unbalanced braces etc. The following proc should join the best of both worlds:

Code: Select all

 proc string2list s {
        if [catch {eval list $s} res] {
                set res [list]
                foreach i [split $s] {
                        if {$i!=""} {lappend res $i}
                }
        }
        set res
 } ;#RS
 % string2list {a   b c     d}
 a b c d
 % string2list "a   b c  {"
 a b c \{
 % string2list {unbalanced "}
 unbalanced {"}
connection, sharing, dcc problems? click <here>
before asking for scripting help, read <this>
use

Code: Select all

 tag when posting logs, code
User avatar
user
&nbsp;
Posts: 1452
Joined: Tue Mar 18, 2003 9:58 pm
Location: Norway

Post by user »

demond wrote:

Code: Select all

 proc string2list s {
        if [catch {eval list $s} res] {
                set res [list]
                foreach i [split $s] {
                        if {$i!=""} {lappend res $i}
                }
        }
        set res
 } ;#RS
 % string2list {a   b c     d}
 a b c d
 % string2list "a   b c  {"
 a b c \{
 % string2list {unbalanced "}
 unbalanced {"}
Try 'string2list {[exit]}' using that proc :P The catch doesn't make any sense... RS must have created that proc before he learned Tcl :P
Here's how i'd do it:

Code: Select all

proc string2list s {
	set res [list]
	foreach i [split $s] {
		if {$i!=""} {lappend res $i}
	}
	set res
}
Edit: heh..i managed to provide a false solution the first time :P Anyway here's another way to do the same ting:

Code: Select all

proc string2list s {
	split [eval concat [split $s]]
}
Have you ever read "The Manual"?
User avatar
De Kus
Revered One
Posts: 1361
Joined: Sun Dec 15, 2002 11:41 am
Location: Germany

Post by De Kus »

Code: Select all

proc string2list {s {c "\n\t "}} {
   set res [list]
   foreach i [split $s $c] {
      if {$i!=""} {lappend res $i}
   }
   set res
}
If you want to improove split, why not at least include all features of split? :)
I don't know exactly which characters are thread as whitespaces, but I am these 3 are the most common one :D.

Edit: sorry, I wondered why you would need, since lappend creates if neccessary, but didn't think on empty strings :D.

Edit3: final one doesnt work with $c.
Last edited by De Kus on Sat May 27, 2006 4:53 am, edited 4 times in total.
De Kus
StarZ|De_Kus, De_Kus or DeKus on IRC
Copyright © 2005-2009 by De Kus - published under The MIT License
Love hurts, love strengthens...
Post Reply