[12177] | 1 | # mysaint.tcl |
---|
| 2 | # |
---|
| 3 | # I got the inspiration to write this bot from the SmallSaints |
---|
| 4 | # bot on DalNet and the request of some Malay friends to create a clone. |
---|
| 5 | # |
---|
| 6 | # The bot sits on a channel and simply counts words that each user says. |
---|
| 7 | |
---|
| 8 | package require irk |
---|
| 9 | |
---|
| 10 | namespace eval ::mysaint { |
---|
| 11 | |
---|
| 12 | variable state |
---|
| 13 | |
---|
| 14 | set state(thisdir) [file dir [info script]] |
---|
| 15 | set state(words,save) [file join $state(thisdir) savedwords.dat] |
---|
| 16 | set state(save,interval) 30000 |
---|
| 17 | |
---|
| 18 | # For each identified user, there are several entries in the state array: |
---|
| 19 | # |
---|
| 20 | # state($user,words) How many words they have total. |
---|
| 21 | # state($user,session) How many words they said this time. |
---|
| 22 | # state($user,password) What's their password |
---|
| 23 | # state($user,ident) What's their ident |
---|
| 24 | # |
---|
| 25 | # We also keep a mapping from nicknames to users: |
---|
| 26 | # |
---|
| 27 | # state($nick,user) What's the user mask associated with this |
---|
| 28 | # nick name |
---|
| 29 | |
---|
| 30 | proc initialize {} { |
---|
| 31 | variable state |
---|
| 32 | variable thisdir |
---|
| 33 | |
---|
| 34 | # Set up a timer to save words: |
---|
| 35 | |
---|
| 36 | set state(saver) [after $state(save,interval) ::mysaint::save] |
---|
| 37 | |
---|
| 38 | # See if we have a saved words file. If so, read it in. |
---|
| 39 | |
---|
| 40 | if {[file exists $state(words,save)]} { |
---|
| 41 | uplevel #0 source $state(words,save) |
---|
| 42 | } |
---|
| 43 | } |
---|
| 44 | |
---|
| 45 | proc userSays {token nick user comm dest rest} { |
---|
| 46 | if {[string match "!*" [lindex $rest 0]]} { |
---|
| 47 | userSaysCommand $token $dest $nick $user \ |
---|
| 48 | [lindex $rest 0] [lrange $rest 1 end] |
---|
| 49 | } else { |
---|
| 50 | userSaysWords $nick $user [llength $rest] |
---|
| 51 | } |
---|
| 52 | } |
---|
| 53 | |
---|
| 54 | proc userSaysWords {nick user n} { |
---|
| 55 | variable state |
---|
| 56 | |
---|
| 57 | set seconds [clock seconds] |
---|
| 58 | if {![info exists state($user,session,time)]} { |
---|
| 59 | set state($user,session,time) [clock seconds] |
---|
| 60 | } |
---|
| 61 | set state($user,time) $seconds |
---|
| 62 | |
---|
| 63 | if {![info exists state($user,session)]} { |
---|
| 64 | set state($user,session) $n |
---|
| 65 | } else { |
---|
| 66 | incr state($user,session) $n |
---|
| 67 | } |
---|
| 68 | if {![info exists state($user,words)]} { |
---|
| 69 | set state($user,words) $n |
---|
| 70 | } else { |
---|
| 71 | incr state($user,words) $n |
---|
| 72 | } |
---|
| 73 | |
---|
| 74 | set state($nick,user) $user |
---|
| 75 | } |
---|
| 76 | |
---|
| 77 | proc userSaysCommand {token dest nick user cmd rest} { |
---|
| 78 | variable state |
---|
| 79 | |
---|
| 80 | # Determine destination of any reply we're going to send: |
---|
| 81 | |
---|
| 82 | if {![string compare $dest $state(nick)]} { |
---|
| 83 | set dest $nick |
---|
| 84 | } |
---|
| 85 | |
---|
| 86 | switch -exact $cmd { |
---|
| 87 | "!help" {userAsksHelp $token $nick} |
---|
| 88 | "!time" {userAsksTime $token $nick $user $rest $dest} |
---|
| 89 | "!heard" {userAsksHeard $token $nick $user $rest $dest} |
---|
| 90 | "!words" {userAsksWords $token $nick $user $rest $dest} |
---|
| 91 | "!donate" {userDonates $token $nick $user $rest $dest} |
---|
| 92 | "!pass" {::irk::pass $token mysaint $nick $user $rest} |
---|
| 93 | "!ident" {::irk::id $token mysaint $nick $user $rest} |
---|
| 94 | "!newpass" {::irk::np $token mysaint $nick $user $rest} |
---|
| 95 | } |
---|
| 96 | } |
---|
| 97 | |
---|
| 98 | proc userAsksHelp {token nick} { |
---|
| 99 | ::irk::say $token $nick \ |
---|
| 100 | [list Hello $nick, the following commands are supported: ] |
---|
| 101 | ::irk::say $token $nick "!help ---- prints this message" |
---|
| 102 | ::irk::say $token $nick "!words --- how many words you have" |
---|
| 103 | ::irk::say $token $nick "!donate -- to donate words to someone" |
---|
| 104 | after 2000 [list ::irk::say $token $nick \ |
---|
| 105 | "!heard --- when did some speak last time"] |
---|
| 106 | after 2500 [list ::irk::say $token $nick \ |
---|
| 107 | "!time ---- when someone connected"] |
---|
| 108 | after 5000 [list ::irk::say $token $nick \ |
---|
| 109 | "Note: To donate you have to have a password"] |
---|
| 110 | after 7500 [list ::irk::say $token $nick \ |
---|
| 111 | "Note: You can get a password with !pass"] |
---|
| 112 | } |
---|
| 113 | |
---|
| 114 | proc userAsksWords {token nick user rest dest} { |
---|
| 115 | variable state |
---|
| 116 | |
---|
| 117 | set target [lindex $rest 0] |
---|
| 118 | if {[string compare $target ""]} { |
---|
| 119 | if {[catch {set user $state($target,user)}]} { |
---|
| 120 | set who "The unknown user $target" |
---|
| 121 | set target "The unknown user $target" |
---|
| 122 | } else { |
---|
| 123 | set who $user |
---|
| 124 | } |
---|
| 125 | } else { |
---|
| 126 | set who "" |
---|
| 127 | } |
---|
| 128 | if {[string compare $who ""]} { |
---|
| 129 | if {[catch {set words $state($who,words)}]} { |
---|
| 130 | set words 0 |
---|
| 131 | } |
---|
| 132 | if {[catch {set session $state($who,session)}]} { |
---|
| 133 | set session 0 |
---|
| 134 | } |
---|
| 135 | set reply \ |
---|
| 136 | "$nick, $target has $session words now, total $words words" |
---|
| 137 | } else { |
---|
| 138 | if {[catch {set words $state($user,words)}]} { |
---|
| 139 | set words 0 |
---|
| 140 | } |
---|
| 141 | if {[catch {set session $state($user,session)}]} { |
---|
| 142 | set session 0 |
---|
| 143 | } |
---|
| 144 | set reply \ |
---|
| 145 | "$nick, you have $session words now, $words total words" |
---|
| 146 | } |
---|
| 147 | ::irk::say $token $dest $reply |
---|
| 148 | } |
---|
| 149 | |
---|
| 150 | proc userAsksHeard {token nick user rest dest} { |
---|
| 151 | variable state |
---|
| 152 | |
---|
| 153 | set target [lindex $rest 0] |
---|
| 154 | if {[string compare $target ""]} { |
---|
| 155 | if {[catch {set user $state($target,user)}]} { |
---|
| 156 | set answer "I haven't heard $target speak recently." |
---|
| 157 | } else { |
---|
| 158 | set time $state($user,time) |
---|
| 159 | set time [clock format $time] |
---|
| 160 | set answer "I heard $target speak last at $time" |
---|
| 161 | } |
---|
| 162 | } else { |
---|
| 163 | set answer "I'm talking to you just now, $nick" |
---|
| 164 | } |
---|
| 165 | |
---|
| 166 | ::irk::say $token $dest $answer |
---|
| 167 | } |
---|
| 168 | |
---|
| 169 | proc userAsksTime {token nick user rest dest} { |
---|
| 170 | variable state |
---|
| 171 | |
---|
| 172 | set target [lindex $rest 0] |
---|
| 173 | if {[string compare $target ""]} { |
---|
| 174 | if {[catch {set user $state($target,user)}]} { |
---|
| 175 | set answer "I don't know when $target connected" |
---|
| 176 | } else { |
---|
| 177 | if {[catch {set time $state($user,session,time)}]} { |
---|
| 178 | set answer "I don't know when $target connected" |
---|
| 179 | } else { |
---|
| 180 | set time [clock format $time] |
---|
| 181 | set answer \ |
---|
| 182 | "I first noticed $target at $time" |
---|
| 183 | } |
---|
| 184 | } |
---|
| 185 | } else { |
---|
| 186 | if {[catch {set user $state($nick,user)}]} { |
---|
| 187 | set answer "$nick, I don't know when you connected" |
---|
| 188 | } else { |
---|
| 189 | if {[catch {set time $state($user,session,time)}]} { |
---|
| 190 | set answer "$nick, I don't know when you connected" |
---|
| 191 | } else { |
---|
| 192 | set time [clock format $time] |
---|
| 193 | set answer \ |
---|
| 194 | "$nick, I first noticed you at $time" |
---|
| 195 | } |
---|
| 196 | } |
---|
| 197 | } |
---|
| 198 | |
---|
| 199 | ::irk::say $token $dest $answer |
---|
| 200 | } |
---|
| 201 | |
---|
| 202 | # Start the bot: |
---|
| 203 | |
---|
| 204 | proc start {token} { |
---|
| 205 | variable state |
---|
| 206 | |
---|
| 207 | set state($token,token) $token |
---|
| 208 | |
---|
| 209 | set symsrv $::irk::state($token,symsrv) |
---|
| 210 | set state(nick) $::irk::state(-$symsrv,nick) |
---|
| 211 | set nick $state(nick) |
---|
| 212 | |
---|
| 213 | foreach chan [::irk::onchannels $token] { |
---|
| 214 | ::irk::setaction2 $token PRIVMSG $chan ::mysaint::userSays |
---|
| 215 | } |
---|
| 216 | ::irk::setaction2 $token PRIVMSG $nick ::mysaint::userSays |
---|
| 217 | |
---|
| 218 | # Set up a timer to save the words info. |
---|
| 219 | |
---|
| 220 | if {![info exists state(saver)]} { |
---|
| 221 | initialize |
---|
| 222 | } |
---|
| 223 | |
---|
| 224 | return "" |
---|
| 225 | } |
---|
| 226 | |
---|
| 227 | # Stop the bot: |
---|
| 228 | |
---|
| 229 | proc stop {} { |
---|
| 230 | variable state |
---|
| 231 | |
---|
| 232 | foreach conn [array names state *,token] { |
---|
| 233 | stopcon $state($conn) |
---|
| 234 | } |
---|
| 235 | |
---|
| 236 | after cancel $state(saver) |
---|
| 237 | catch {unset state(saver)} |
---|
| 238 | |
---|
| 239 | return "" |
---|
| 240 | } |
---|
| 241 | proc stopcon {token} { |
---|
| 242 | variable state |
---|
| 243 | |
---|
| 244 | if {[catch {set symsrv $::irk::state($token,symsrv)}]} { |
---|
| 245 | return |
---|
| 246 | } |
---|
| 247 | set nick $state(nick) |
---|
| 248 | |
---|
| 249 | foreach chan [::irk::onchannels $token] { |
---|
| 250 | ::irk::remaction2 $token PRIVMSG $chan ::mysaint::userSays |
---|
| 251 | } |
---|
| 252 | ::irk::remaction2 $token PRIVMSG $nick ::mysaint::userSays |
---|
| 253 | |
---|
| 254 | return "" |
---|
| 255 | } |
---|
| 256 | |
---|
| 257 | # Save words to a disk file: |
---|
| 258 | |
---|
| 259 | proc save {} { |
---|
| 260 | variable state |
---|
| 261 | |
---|
| 262 | puts "Saving words in $state(words,save)" |
---|
| 263 | |
---|
| 264 | # First of all reschedule ourselves: |
---|
| 265 | |
---|
| 266 | set state(saver) [after $state(save,interval) ::mysaint::save] |
---|
| 267 | |
---|
| 268 | # Save the words: |
---|
| 269 | |
---|
| 270 | set pt "*,words" |
---|
| 271 | if {![catch {set fd [open $state(words,save) w]}]} { |
---|
| 272 | puts $fd "array set ::mysaint::state [list [array get state $pt]]" |
---|
| 273 | |
---|
| 274 | catch {close $fd} |
---|
| 275 | } |
---|
| 276 | } |
---|
| 277 | } |
---|