rbot 0.9.14 → 0.9.15
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +6 -2
- data/REQUIREMENTS +7 -1
- data/Rakefile +10 -32
- data/bin/rbot +6 -1
- data/bin/svnwatch-postcommit-hook +68 -0
- data/data/rbot/contrib/plugins/stats.rb +3 -3
- data/data/rbot/contrib/plugins/vandale.rb +1 -1
- data/data/rbot/filters/rss.rb +72 -0
- data/data/rbot/languages/finnish.lang +50 -0
- data/data/rbot/plugins/alias.rb +6 -6
- data/data/rbot/plugins/autorejoin.rb +41 -2
- data/data/rbot/plugins/bans.rb +100 -6
- data/data/rbot/plugins/bash.rb +9 -4
- data/data/rbot/plugins/cal.rb +1 -1
- data/data/rbot/plugins/chucknorris.rb +6 -6
- data/data/rbot/plugins/debugger.rb +7 -3
- data/data/rbot/plugins/deepthoughts.rb +1 -1
- data/data/rbot/plugins/delicious.rb +6 -2
- data/data/rbot/plugins/dice.rb +7 -7
- data/data/rbot/plugins/dict.rb +4 -3
- data/data/rbot/plugins/dictclient.rb +17 -13
- data/data/rbot/plugins/digg.rb +3 -3
- data/data/rbot/plugins/eightball.rb +1 -1
- data/data/rbot/plugins/factoids.rb +13 -4
- data/data/rbot/plugins/figlet.rb +4 -4
- data/data/rbot/plugins/forecast.rb +3 -3
- data/data/rbot/plugins/fortune.rb +14 -8
- data/data/rbot/plugins/freshmeat.rb +2 -2
- data/data/rbot/plugins/games/azgame.rb +72 -19
- data/data/rbot/plugins/games/hangman.rb +499 -0
- data/data/rbot/plugins/games/quiz.rb +15 -13
- data/data/rbot/plugins/games/roshambo.rb +1 -1
- data/data/rbot/plugins/games/roulette.rb +4 -4
- data/data/rbot/plugins/games/shiritori.rb +31 -31
- data/data/rbot/plugins/games/uno.rb +28 -6
- data/data/rbot/plugins/games/wheelfortune.rb +1 -3
- data/data/rbot/plugins/geoip.rb +83 -28
- data/data/rbot/plugins/googlefight.rb +64 -0
- data/data/rbot/plugins/greet.rb +45 -0
- data/data/rbot/plugins/grouphug.rb +40 -12
- data/data/rbot/plugins/imdb.rb +4 -4
- data/data/rbot/plugins/insult.rb +2 -2
- data/data/rbot/plugins/karma.rb +6 -5
- data/data/rbot/plugins/keywords.rb +26 -22
- data/data/rbot/plugins/lart.rb +5 -6
- data/data/rbot/plugins/lastfm.rb +488 -125
- data/data/rbot/plugins/lib_spotify.rb +84 -0
- data/data/rbot/plugins/linkbot.rb +1 -1
- data/data/rbot/plugins/markov.rb +567 -78
- data/data/rbot/plugins/math.rb +3 -3
- data/data/rbot/plugins/modes.rb +1 -1
- data/data/rbot/plugins/nickrecover.rb +1 -1
- data/data/rbot/plugins/nickserv.rb +7 -7
- data/data/rbot/plugins/note.rb +55 -0
- data/data/rbot/plugins/nslookup.rb +2 -2
- data/data/rbot/plugins/quakeauth.rb +4 -4
- data/data/rbot/plugins/quotes.rb +53 -19
- data/data/rbot/plugins/reaction.rb +76 -19
- data/data/rbot/plugins/remind.rb +3 -96
- data/data/rbot/plugins/ri.rb +1 -1
- data/data/rbot/plugins/rot13.rb +1 -1
- data/data/rbot/plugins/rss.rb +296 -190
- data/data/rbot/plugins/salut.rb +8 -8
- data/data/rbot/plugins/script.rb +48 -11
- data/data/rbot/plugins/search.rb +124 -28
- data/data/rbot/plugins/seen.rb +162 -31
- data/data/rbot/plugins/shortenurls.rb +1 -1
- data/data/rbot/plugins/slashdot.rb +19 -6
- data/data/rbot/plugins/spotify.rb +78 -0
- data/data/rbot/plugins/theyfightcrime.rb +10 -10
- data/data/rbot/plugins/time.rb +2 -2
- data/data/rbot/plugins/translator.rb +161 -85
- data/data/rbot/plugins/tube.rb +2 -2
- data/data/rbot/plugins/tumblr.rb +143 -0
- data/data/rbot/plugins/twitter.rb +25 -6
- data/data/rbot/plugins/urban.rb +6 -4
- data/data/rbot/plugins/url.rb +49 -10
- data/data/rbot/plugins/weather.rb +6 -6
- data/data/rbot/plugins/wserver.rb +5 -5
- data/data/rbot/plugins/youtube.rb +12 -12
- data/data/rbot/templates/lart/larts-italian +1 -1
- data/launch_here.rb +68 -0
- data/lib/rbot/botuser.rb +1 -1
- data/lib/rbot/compat19.rb +70 -0
- data/lib/rbot/config.rb +8 -6
- data/lib/rbot/core/auth.rb +37 -21
- data/lib/rbot/core/basics.rb +33 -2
- data/lib/rbot/core/config.rb +24 -17
- data/lib/rbot/core/filters_ui.rb +2 -2
- data/lib/rbot/core/irclog.rb +20 -11
- data/lib/rbot/core/remote.rb +9 -9
- data/lib/rbot/core/unicode.rb +4 -0
- data/lib/rbot/core/userdata.rb +16 -1
- data/lib/rbot/core/utils/extends.rb +76 -0
- data/lib/rbot/core/utils/filters.rb +47 -0
- data/lib/rbot/core/utils/httputil.rb +36 -26
- data/lib/rbot/core/utils/parse_time.rb +193 -0
- data/lib/rbot/core/utils/utils.rb +81 -56
- data/lib/rbot/core/utils/wordlist.rb +66 -0
- data/lib/rbot/core/wordlist_ui.rb +27 -0
- data/lib/rbot/irc.rb +59 -19
- data/lib/rbot/ircbot.rb +190 -58
- data/lib/rbot/ircsocket.rb +14 -8
- data/lib/rbot/language.rb +4 -3
- data/lib/rbot/load-gettext.rb +22 -9
- data/lib/rbot/message.rb +89 -18
- data/lib/rbot/messagemapper.rb +71 -19
- data/lib/rbot/plugins.rb +112 -44
- data/lib/rbot/{registry.rb → registry/bdb.rb} +226 -22
- data/lib/rbot/registry/tc.rb +531 -0
- data/lib/rbot/rfc2812.rb +33 -8
- data/lib/rbot/timer.rb +12 -20
- data/po/en_US/rbot-autorejoin.po +3 -0
- data/po/en_US/rbot-azgame.po +51 -43
- data/po/en_US/rbot-bash.po +15 -0
- data/po/en_US/rbot-dictclient.po +20 -20
- data/po/en_US/rbot-factoids.po +9 -9
- data/po/en_US/rbot-geoip.po +0 -0
- data/po/en_US/rbot-googlefight.po +24 -0
- data/po/en_US/rbot-grouphug.po +4 -4
- data/po/en_US/rbot-hangman.po +114 -0
- data/po/en_US/rbot-keywords.po +3 -3
- data/po/en_US/rbot-lastfm.po +268 -70
- data/po/en_US/rbot-markov.po +73 -2
- data/po/en_US/rbot-quotes.po +21 -21
- data/po/en_US/rbot-rss.po +6 -2
- data/po/en_US/rbot-script.po +3 -0
- data/po/en_US/rbot-seen.po +72 -0
- data/po/en_US/rbot-spell.po +2 -2
- data/po/en_US/rbot-translator.po +13 -13
- data/po/en_US/rbot-twitter.po +3 -3
- data/po/en_US/rbot-uno.po +131 -114
- data/po/en_US/rbot-wall.po +12 -13
- data/po/en_US/rbot-wheelfortune.po +41 -41
- data/po/en_US/rbot.po +254 -194
- data/po/fi/rbot-alias.po +82 -0
- data/po/fi/rbot-autoop.po +0 -0
- data/po/fi/rbot-autorejoin.po +20 -0
- data/po/fi/rbot-azgame.po +194 -0
- data/po/fi/rbot-bans.po +0 -0
- data/po/fi/rbot-bash.po +32 -0
- data/po/fi/rbot-botsnack.po +0 -0
- data/po/fi/rbot-cal.po +20 -0
- data/po/fi/rbot-chanserv.po +0 -0
- data/po/fi/rbot-chucknorris.po +0 -0
- data/po/fi/rbot-debugger.po +0 -0
- data/po/fi/rbot-deepthoughts.po +0 -0
- data/po/fi/rbot-delicious.po +0 -0
- data/po/fi/rbot-dice.po +0 -0
- data/po/fi/rbot-dict.po +0 -0
- data/po/fi/rbot-dictclient.po +111 -0
- data/po/fi/rbot-digg.po +0 -0
- data/po/fi/rbot-eightball.po +0 -0
- data/po/fi/rbot-excuse.po +0 -0
- data/po/fi/rbot-factoids.po +107 -0
- data/po/fi/rbot-figlet.po +36 -0
- data/po/fi/rbot-fish.po +0 -0
- data/po/fi/rbot-forecast.po +0 -0
- data/po/fi/rbot-fortune.po +0 -0
- data/po/fi/rbot-freshmeat.po +0 -0
- data/po/fi/rbot-geoip.po +0 -0
- data/po/fi/rbot-googlefight.po +24 -0
- data/po/fi/rbot-grouphug.po +35 -0
- data/po/fi/rbot-hangman.po +121 -0
- data/po/fi/rbot-hl2.po +0 -0
- data/po/fi/rbot-host.po +20 -0
- data/po/fi/rbot-imdb.po +0 -0
- data/po/fi/rbot-insult.po +0 -0
- data/po/fi/rbot-iplookup.po +0 -0
- data/po/fi/rbot-karma.po +0 -0
- data/po/fi/rbot-keywords.po +24 -0
- data/po/fi/rbot-lart.po +0 -0
- data/po/fi/rbot-lastfm.po +377 -0
- data/po/fi/rbot-linkbot.po +0 -0
- data/po/fi/rbot-markov.po +91 -0
- data/po/fi/rbot-math.po +0 -0
- data/po/fi/rbot-modes.po +0 -0
- data/po/fi/rbot-nickrecover.po +36 -0
- data/po/fi/rbot-nickserv.po +104 -0
- data/po/fi/rbot-nslookup.po +0 -0
- data/po/fi/rbot-quakeauth.po +0 -0
- data/po/fi/rbot-quiz.po +0 -0
- data/po/fi/rbot-quotes.po +108 -0
- data/po/fi/rbot-reaction.po +0 -0
- data/po/fi/rbot-remind.po +0 -0
- data/po/fi/rbot-remotectl.po +0 -0
- data/po/fi/rbot-ri.po +0 -0
- data/po/fi/rbot-roshambo.po +0 -0
- data/po/fi/rbot-rot13.po +0 -0
- data/po/fi/rbot-roulette.po +0 -0
- data/po/fi/rbot-rss.po +24 -0
- data/po/fi/rbot-salut.po +0 -0
- data/po/fi/rbot-script.po +20 -0
- data/po/fi/rbot-search.po +0 -0
- data/po/fi/rbot-seen.po +92 -0
- data/po/fi/rbot-shiritori.po +102 -0
- data/po/fi/rbot-shortenurls.po +0 -0
- data/po/fi/rbot-slashdot.po +0 -0
- data/po/fi/rbot-spell.po +54 -0
- data/po/fi/rbot-theyfightcrime.po +0 -0
- data/po/fi/rbot-threat.po +0 -0
- data/po/fi/rbot-time.po +0 -0
- data/po/fi/rbot-topic.po +0 -0
- data/po/fi/rbot-translator.po +77 -0
- data/po/fi/rbot-tube.po +0 -0
- data/po/fi/rbot-twitter.po +24 -0
- data/po/fi/rbot-uno.po +529 -0
- data/po/fi/rbot-urban.po +0 -0
- data/po/fi/rbot-url.po +0 -0
- data/po/fi/rbot-usermodes.po +0 -0
- data/po/fi/rbot-wall.po +32 -0
- data/po/fi/rbot-weather.po +0 -0
- data/po/fi/rbot-wheelfortune.po +205 -0
- data/po/fi/rbot-wow.po +0 -0
- data/po/fi/rbot-wserver.po +0 -0
- data/po/fi/rbot-youtube.po +58 -0
- data/po/fi/rbot.po +1152 -0
- data/po/fr/rbot-autorejoin.po +3 -0
- data/po/fr/rbot-azgame.po +51 -43
- data/po/fr/rbot-bash.po +15 -0
- data/po/fr/rbot-dictclient.po +20 -20
- data/po/fr/rbot-factoids.po +9 -9
- data/po/fr/rbot-geoip.po +0 -0
- data/po/fr/rbot-googlefight.po +24 -0
- data/po/fr/rbot-grouphug.po +4 -4
- data/po/fr/rbot-hangman.po +114 -0
- data/po/fr/rbot-keywords.po +3 -3
- data/po/fr/rbot-lastfm.po +268 -70
- data/po/fr/rbot-markov.po +74 -2
- data/po/fr/rbot-quotes.po +21 -21
- data/po/fr/rbot-rss.po +6 -2
- data/po/fr/rbot-script.po +3 -0
- data/po/fr/rbot-seen.po +72 -0
- data/po/fr/rbot-spell.po +2 -2
- data/po/fr/rbot-translator.po +13 -13
- data/po/fr/rbot-twitter.po +3 -3
- data/po/fr/rbot-uno.po +132 -114
- data/po/fr/rbot-wall.po +8 -9
- data/po/fr/rbot-wheelfortune.po +41 -41
- data/po/fr/rbot.po +268 -197
- data/po/it/rbot-autorejoin.po +3 -0
- data/po/it/rbot-azgame.po +50 -42
- data/po/it/rbot-bash.po +15 -0
- data/po/it/rbot-dictclient.po +20 -20
- data/po/it/rbot-factoids.po +9 -9
- data/po/it/rbot-geoip.po +0 -0
- data/po/it/rbot-googlefight.po +24 -0
- data/po/it/rbot-grouphug.po +4 -4
- data/po/it/rbot-hangman.po +114 -0
- data/po/it/rbot-keywords.po +3 -3
- data/po/it/rbot-lastfm.po +268 -70
- data/po/it/rbot-markov.po +75 -3
- data/po/it/rbot-quotes.po +21 -21
- data/po/it/rbot-rss.po +7 -3
- data/po/it/rbot-script.po +19 -0
- data/po/it/rbot-seen.po +72 -0
- data/po/it/rbot-spell.po +2 -2
- data/po/it/rbot-translator.po +13 -13
- data/po/it/rbot-twitter.po +3 -3
- data/po/it/rbot-uno.po +137 -116
- data/po/it/rbot-wall.po +8 -9
- data/po/it/rbot-wheelfortune.po +41 -41
- data/po/it/rbot.po +265 -208
- data/po/ja/rbot-autorejoin.po +3 -0
- data/po/ja/rbot-azgame.po +51 -43
- data/po/ja/rbot-bash.po +15 -0
- data/po/ja/rbot-dictclient.po +20 -20
- data/po/ja/rbot-factoids.po +9 -9
- data/po/ja/rbot-geoip.po +0 -0
- data/po/ja/rbot-googlefight.po +24 -0
- data/po/ja/rbot-grouphug.po +4 -4
- data/po/ja/rbot-hangman.po +114 -0
- data/po/ja/rbot-keywords.po +3 -3
- data/po/ja/rbot-lastfm.po +268 -70
- data/po/ja/rbot-markov.po +73 -2
- data/po/ja/rbot-quotes.po +21 -21
- data/po/ja/rbot-rss.po +6 -2
- data/po/ja/rbot-script.po +3 -0
- data/po/ja/rbot-seen.po +72 -0
- data/po/ja/rbot-spell.po +2 -2
- data/po/ja/rbot-translator.po +13 -13
- data/po/ja/rbot-twitter.po +3 -3
- data/po/ja/rbot-uno.po +131 -114
- data/po/ja/rbot-wall.po +8 -9
- data/po/ja/rbot-wheelfortune.po +41 -41
- data/po/ja/rbot.po +248 -192
- data/po/rbot-alias.pot +2 -2
- data/po/rbot-autorejoin.pot +21 -0
- data/po/rbot-azgame.pot +51 -43
- data/po/rbot-bash.pot +33 -0
- data/po/rbot-cal.pot +2 -2
- data/po/rbot-dictclient.pot +21 -21
- data/po/rbot-factoids.pot +10 -10
- data/po/rbot-figlet.pot +2 -2
- data/po/rbot-geoip.pot +0 -0
- data/po/rbot-googlefight.pot +25 -0
- data/po/rbot-grouphug.pot +6 -6
- data/po/rbot-hangman.pot +115 -0
- data/po/rbot-host.pot +2 -2
- data/po/rbot-keywords.pot +4 -4
- data/po/rbot-lastfm.pot +270 -72
- data/po/rbot-markov.pot +74 -3
- data/po/rbot-nickrecover.pot +2 -2
- data/po/rbot-nickserv.pot +2 -2
- data/po/rbot-quotes.pot +22 -22
- data/po/rbot-rss.pot +7 -3
- data/po/rbot-script.pot +21 -0
- data/po/rbot-seen.pot +90 -0
- data/po/rbot-shiritori.pot +2 -2
- data/po/rbot-spell.pot +3 -3
- data/po/rbot-translator.pot +14 -14
- data/po/rbot-twitter.pot +4 -4
- data/po/rbot-uno.pot +132 -115
- data/po/rbot-wall.pot +2 -2
- data/po/rbot-wheelfortune.pot +42 -42
- data/po/rbot-youtube.pot +2 -2
- data/po/rbot.pot +249 -193
- data/po/zh_CN/rbot-autorejoin.po +3 -0
- data/po/zh_CN/rbot-azgame.po +50 -42
- data/po/zh_CN/rbot-bash.po +15 -0
- data/po/zh_CN/rbot-dictclient.po +20 -20
- data/po/zh_CN/rbot-factoids.po +9 -9
- data/po/zh_CN/rbot-geoip.po +0 -0
- data/po/zh_CN/rbot-googlefight.po +24 -0
- data/po/zh_CN/rbot-grouphug.po +4 -4
- data/po/zh_CN/rbot-hangman.po +114 -0
- data/po/zh_CN/rbot-keywords.po +3 -3
- data/po/zh_CN/rbot-lastfm.po +268 -70
- data/po/zh_CN/rbot-markov.po +73 -2
- data/po/zh_CN/rbot-quotes.po +21 -21
- data/po/zh_CN/rbot-rss.po +6 -2
- data/po/zh_CN/rbot-script.po +3 -0
- data/po/zh_CN/rbot-seen.po +72 -0
- data/po/zh_CN/rbot-spell.po +2 -2
- data/po/zh_CN/rbot-translator.po +13 -13
- data/po/zh_CN/rbot-twitter.po +3 -3
- data/po/zh_CN/rbot-uno.po +131 -114
- data/po/zh_CN/rbot-wall.po +7 -8
- data/po/zh_CN/rbot-wheelfortune.po +41 -41
- data/po/zh_CN/rbot.po +248 -192
- data/po/zh_TW/rbot-autorejoin.po +3 -0
- data/po/zh_TW/rbot-azgame.po +50 -42
- data/po/zh_TW/rbot-bash.po +15 -0
- data/po/zh_TW/rbot-dictclient.po +20 -20
- data/po/zh_TW/rbot-factoids.po +9 -9
- data/po/zh_TW/rbot-geoip.po +0 -0
- data/po/zh_TW/rbot-googlefight.po +24 -0
- data/po/zh_TW/rbot-grouphug.po +4 -4
- data/po/zh_TW/rbot-hangman.po +114 -0
- data/po/zh_TW/rbot-keywords.po +3 -3
- data/po/zh_TW/rbot-lastfm.po +268 -70
- data/po/zh_TW/rbot-markov.po +73 -2
- data/po/zh_TW/rbot-quotes.po +21 -21
- data/po/zh_TW/rbot-rss.po +6 -2
- data/po/zh_TW/rbot-script.po +3 -0
- data/po/zh_TW/rbot-seen.po +72 -0
- data/po/zh_TW/rbot-spell.po +2 -2
- data/po/zh_TW/rbot-translator.po +13 -13
- data/po/zh_TW/rbot-twitter.po +3 -3
- data/po/zh_TW/rbot-uno.po +131 -114
- data/po/zh_TW/rbot-wall.po +7 -8
- data/po/zh_TW/rbot-wheelfortune.po +41 -41
- data/po/zh_TW/rbot.po +253 -194
- data/setup.rb +4 -4
- metadata +127 -18
- data/README +0 -43
- data/data/rbot/plugins/fish.rb +0 -121
- data/lib/rbot/dbhash.rb +0 -199
data/data/rbot/plugins/digg.rb
CHANGED
@@ -9,7 +9,7 @@ class DiggPlugin < Plugin
|
|
9
9
|
def help(plugin, topic="")
|
10
10
|
"digg [<max>=5] => show digg headlines, [<max>=5] => return up to <max> headlines (use a negative number to show all the headlines on one line)"
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
def digg(m, params)
|
14
14
|
max = params[:limit].to_i
|
15
15
|
debug "max is #{max}"
|
@@ -32,11 +32,11 @@ class DiggPlugin < Plugin
|
|
32
32
|
max = 8 if max > 8
|
33
33
|
matches = Array.new
|
34
34
|
doc.elements.each("rss/channel/item") {|e|
|
35
|
-
matches << [ e.elements["title"].text,
|
35
|
+
matches << [ e.elements["title"].text,
|
36
36
|
Time.parse(e.elements["pubDate"].text).strftime('%a @ %I:%M%p') ]
|
37
37
|
done += 1
|
38
38
|
break if done >= max
|
39
|
-
}
|
39
|
+
}
|
40
40
|
if oneline
|
41
41
|
m.reply matches.collect{|mat| mat[0]}.join(" | ")
|
42
42
|
else
|
@@ -10,7 +10,7 @@ class EightBallPlugin < Plugin
|
|
10
10
|
end
|
11
11
|
def eightball(m, params)
|
12
12
|
answers = @answers[rand(@answers.length)]
|
13
|
-
action = "shakes the magic 8-ball... #{answers}"
|
13
|
+
action = "shakes the magic 8-ball for #{m.source} ... #{answers}"
|
14
14
|
@bot.action m.replyto, action
|
15
15
|
end
|
16
16
|
end
|
@@ -120,7 +120,7 @@ class FactoidsPlugin < Plugin
|
|
120
120
|
super
|
121
121
|
|
122
122
|
# TODO config
|
123
|
-
@dir =
|
123
|
+
@dir = datafile
|
124
124
|
@filename = "factoids.rbot"
|
125
125
|
@factoids = FactoidList.new
|
126
126
|
@triggers = Set.new
|
@@ -341,7 +341,7 @@ class FactoidsPlugin < Plugin
|
|
341
341
|
if params[:words].nil_or_empty? and params[:rx].nil_or_empty?
|
342
342
|
m.reply _("I know %{total} facts" % { :total => total })
|
343
343
|
else
|
344
|
-
|
344
|
+
unless params.key? :words and not params[:words].empty?
|
345
345
|
rx = Regexp.new(params[:rx].to_s, true)
|
346
346
|
else
|
347
347
|
rx = words2rx(params[:words])
|
@@ -349,7 +349,11 @@ class FactoidsPlugin < Plugin
|
|
349
349
|
known = @factoids.grep(rx)
|
350
350
|
reply = []
|
351
351
|
if known.empty?
|
352
|
-
|
352
|
+
if params.key? :words
|
353
|
+
reply << _("I know nothing about %{words}" % params)
|
354
|
+
else params.key? :rx
|
355
|
+
reply << _("I know nothing matching %{rx}" % params)
|
356
|
+
end
|
353
357
|
else
|
354
358
|
max_facts = @bot.config['factoids.search_results']
|
355
359
|
len = known.length
|
@@ -379,7 +383,12 @@ class FactoidsPlugin < Plugin
|
|
379
383
|
return if @triggers.empty?
|
380
384
|
query = $1.strip.downcase
|
381
385
|
if @triggers.include?(query)
|
382
|
-
|
386
|
+
words = query.split
|
387
|
+
words.instance_variable_set(:@string_value, query)
|
388
|
+
def words.to_s
|
389
|
+
@string_value
|
390
|
+
end
|
391
|
+
facts(m, :words => words)
|
383
392
|
end
|
384
393
|
else
|
385
394
|
return if m.address? # we don't learn stuff directed at us which is not an explicit learn command
|
data/data/rbot/plugins/figlet.rb
CHANGED
@@ -58,10 +58,10 @@ class FigletPlugin < Plugin
|
|
58
58
|
|
59
59
|
def test_figlet
|
60
60
|
#check that figlet is present
|
61
|
-
@has[:figlet] =
|
61
|
+
@has[:figlet] = Utils.try_exec("#{figlet_path} -v")
|
62
62
|
|
63
63
|
# check that figlet actually has the font installed
|
64
|
-
@has[:figlet_font] =
|
64
|
+
@has[:figlet_font] = Utils.try_exec("#{figlet_path} -f #{figlet_font} test test test")
|
65
65
|
|
66
66
|
# set the commandline params
|
67
67
|
@params[:figlet] = ['-k', '-w', MAX_WIDTH.to_s, '-C', 'utf8']
|
@@ -72,10 +72,10 @@ class FigletPlugin < Plugin
|
|
72
72
|
|
73
73
|
def test_toilet
|
74
74
|
#check that toilet is present
|
75
|
-
@has[:toilet] =
|
75
|
+
@has[:toilet] = Utils.try_exec("#{toilet_path} -v")
|
76
76
|
|
77
77
|
# check that toilet actually has the font installed
|
78
|
-
@has[:toilet_font] =
|
78
|
+
@has[:toilet_font] = Utils.try_exec("#{toilet_path} -f #{toilet_font} test test test")
|
79
79
|
|
80
80
|
# set the commandline params
|
81
81
|
@params[:toilet] = ['-k', '-w', MAX_WIDTH.to_s, '-E', 'utf8', '--irc']
|
@@ -8,7 +8,7 @@
|
|
8
8
|
|
9
9
|
require 'soap/wsdlDriver'
|
10
10
|
# TODO why not use HttpUtil instead of open-uri?
|
11
|
-
require 'open-uri'
|
11
|
+
require 'open-uri'
|
12
12
|
require 'rexml/document'
|
13
13
|
require 'erb'
|
14
14
|
|
@@ -48,7 +48,7 @@ class Forecast
|
|
48
48
|
return parse(retrieve),Time.new
|
49
49
|
end
|
50
50
|
private
|
51
|
-
def retrieve
|
51
|
+
def retrieve
|
52
52
|
forecast = @forecaster.NDFDgenByDay(
|
53
53
|
@lat,@long,Time.now.strftime("%Y-%m-%d"),2,"24 hourly")
|
54
54
|
(REXML::Document.new(forecast)).root
|
@@ -105,7 +105,7 @@ class ForecastPlugin < Plugin
|
|
105
105
|
end
|
106
106
|
end
|
107
107
|
end
|
108
|
-
|
108
|
+
|
109
109
|
def get_forecast(m,loc)
|
110
110
|
begin
|
111
111
|
@cache_mutex.synchronize do
|
@@ -7,14 +7,17 @@ class FortunePlugin < Plugin
|
|
7
7
|
Config.register Config::StringValue.new('fortune.path',
|
8
8
|
:default => '',
|
9
9
|
:desc => "Full path to the fortune executable")
|
10
|
+
Config.register Config::ArrayValue.new('fortune.options',
|
11
|
+
:default => ['-n', '350', '-s'],
|
12
|
+
:desc => "Options to be passed on to fortune")
|
10
13
|
|
11
14
|
def help(plugin, topic="")
|
12
15
|
"fortune [<category>] => get a (short) fortune, optionally specifying fortune category || fortune categories => show categories"
|
13
16
|
end
|
14
17
|
|
15
|
-
def find_fortune
|
18
|
+
def find_fortune(m)
|
16
19
|
fortune = @bot.config['fortune.path']
|
17
|
-
return fortune if fortune
|
20
|
+
return fortune if fortune and not fortune.empty?
|
18
21
|
|
19
22
|
["/usr/bin/fortune",
|
20
23
|
"/usr/share/bin/fortune",
|
@@ -28,7 +31,7 @@ class FortunePlugin < Plugin
|
|
28
31
|
end
|
29
32
|
|
30
33
|
return nil unless fortune
|
31
|
-
|
34
|
+
|
32
35
|
# Try setting the config entry
|
33
36
|
config_par = {:key => 'fortune.path', :value => [fortune], :silent => true }
|
34
37
|
debug "Setting fortune.path to #{fortune}"
|
@@ -44,12 +47,15 @@ class FortunePlugin < Plugin
|
|
44
47
|
|
45
48
|
## Pick a fortune
|
46
49
|
def fortune(m, params)
|
47
|
-
|
48
|
-
fortune = find_fortune
|
50
|
+
fortune = find_fortune(m)
|
49
51
|
m.reply "fortune executable not found (try setting the 'fortune.path' variable)" unless fortune
|
50
52
|
|
53
|
+
command = [fortune] + @bot.config['fortune.options']
|
54
|
+
command << params[:db]
|
55
|
+
command.compact!
|
56
|
+
|
51
57
|
begin
|
52
|
-
ret = Utils.safe_exec(
|
58
|
+
ret = Utils.safe_exec(*command)
|
53
59
|
|
54
60
|
## cleanup ret
|
55
61
|
ret = ret.split(/\n+/).map do |l|
|
@@ -75,7 +81,7 @@ class FortunePlugin < Plugin
|
|
75
81
|
|
76
82
|
# Print the fortune categories
|
77
83
|
def categories(m, params)
|
78
|
-
fortune = find_fortune
|
84
|
+
fortune = find_fortune(m)
|
79
85
|
m.reply "fortune executable not found (try setting the 'fortune.path' variable)" unless fortune
|
80
86
|
|
81
87
|
## list all fortune databases
|
@@ -88,7 +94,7 @@ class FortunePlugin < Plugin
|
|
88
94
|
## say 'em!
|
89
95
|
m.reply "Fortune categories: #{categories.join ', '}"
|
90
96
|
end
|
91
|
-
|
97
|
+
|
92
98
|
end
|
93
99
|
plugin = FortunePlugin.new
|
94
100
|
plugin.map 'fortune categories', :action => "categories"
|
@@ -88,7 +88,7 @@ class FreshmeatPlugin < Plugin
|
|
88
88
|
m.reply reply
|
89
89
|
}
|
90
90
|
end
|
91
|
-
|
91
|
+
|
92
92
|
def freshmeat(m, params)
|
93
93
|
max = params[:limit].to_i
|
94
94
|
max = 8 if max > 8
|
@@ -134,5 +134,5 @@ end
|
|
134
134
|
plugin = FreshmeatPlugin.new
|
135
135
|
plugin.map 'freshmeat search :limit *search', :action => 'search_freshmeat',
|
136
136
|
:defaults => {:limit => 4}, :requirements => {:limit => /^\d+$/}
|
137
|
-
plugin.map 'freshmeat :limit', :defaults => {:limit => 4},
|
137
|
+
plugin.map 'freshmeat :limit', :defaults => {:limit => 4},
|
138
138
|
:requirements => {:limit => /^\d+$/}
|
@@ -35,6 +35,34 @@ class AzGame
|
|
35
35
|
def @range.to_s
|
36
36
|
return "%s -- %s" % self
|
37
37
|
end
|
38
|
+
if @rules[:list]
|
39
|
+
@check_method = "is_#{@rules[:addlang]}?"
|
40
|
+
# trick: if addlang was not in rules, this will be is_? which is
|
41
|
+
# not a method of the plugin
|
42
|
+
if @check_method and not @plugin.respond_to? @check_method
|
43
|
+
@check_method = nil
|
44
|
+
end
|
45
|
+
@check = Proc.new do |w|
|
46
|
+
wl = @rules[:list].include?(w)
|
47
|
+
if !wl and @check_method
|
48
|
+
if wl = @plugin.send(@check_method, w)
|
49
|
+
debug "adding #{w} to #{@rules[:addfile]}"
|
50
|
+
begin
|
51
|
+
File.open(@rules[:addfile], "a") do |f|
|
52
|
+
f.puts w
|
53
|
+
end
|
54
|
+
rescue Exception => e
|
55
|
+
error "failed to add #{w} to #{@rules[:addfile]}"
|
56
|
+
error e
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
wl
|
61
|
+
end
|
62
|
+
else
|
63
|
+
@check_method = "is_#{@lang}?"
|
64
|
+
@check = Proc.new { |w| @plugin.send(@check_method, w) }
|
65
|
+
end
|
38
66
|
end
|
39
67
|
|
40
68
|
def check(word)
|
@@ -47,7 +75,7 @@ class AzGame
|
|
47
75
|
return [:out, @range] if w < @range.first or w > @range.last
|
48
76
|
return [:ignore, @range] if w == @range.first or w == @range.last
|
49
77
|
# This is potentially slow (for languages that check online)
|
50
|
-
return [:noexist, @range] unless @
|
78
|
+
return [:noexist, @range] unless @check.call(w)
|
51
79
|
debug "we like it"
|
52
80
|
# Check again if there was a winner in the mean time,
|
53
81
|
# and bail out if there was
|
@@ -122,21 +150,36 @@ class AzGamePlugin < Plugin
|
|
122
150
|
},
|
123
151
|
}
|
124
152
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
153
|
+
@autoadd_base = datafile "autoadd-"
|
154
|
+
end
|
155
|
+
|
156
|
+
def initialize_wordlist(params)
|
157
|
+
lang = params[:lang]
|
158
|
+
addlang = params[:addlang]
|
159
|
+
autoadd = @autoadd_base + addlang.to_s
|
160
|
+
if Wordlist.exist?(lang)
|
161
|
+
# wordlists are assumed to be UTF-8, but we need to strip the BOM, if present
|
162
|
+
words = Wordlist.get(lang)
|
163
|
+
if addlang and File.exist?(autoadd)
|
164
|
+
word += File.readlines(autoadd).map {|line| line.sub("\xef\xbb\xbf",'').strip}
|
165
|
+
end
|
166
|
+
words.uniq!
|
167
|
+
words.sort!
|
129
168
|
if(words.length >= 4) # something to guess
|
130
|
-
|
169
|
+
rules = {
|
131
170
|
:good => /^\S+$/,
|
132
171
|
:list => words,
|
133
172
|
:first => words[0],
|
134
173
|
:last => words[-1],
|
174
|
+
:addlang => addlang,
|
175
|
+
:addfile => autoadd,
|
135
176
|
:listener => /^\S+$/
|
136
177
|
}
|
137
|
-
debug "
|
178
|
+
debug "#{lang} wordlist loaded, #{rules[:list].length} lines; first word: #{rules[:first]}, last word: #{rules[:last]}"
|
179
|
+
return rules
|
138
180
|
end
|
139
181
|
end
|
182
|
+
return false
|
140
183
|
end
|
141
184
|
|
142
185
|
def save
|
@@ -233,12 +276,20 @@ class AzGamePlugin < Plugin
|
|
233
276
|
m.reply _("couldn't think of anything ...")
|
234
277
|
return
|
235
278
|
end
|
279
|
+
m.reply _("got it!")
|
280
|
+
@games[k] = AzGame.new(self, lang, @rules[lang], word)
|
281
|
+
elsif !@rules.has_key?(lang) and rules = initialize_wordlist(params)
|
282
|
+
word = random_pick_wordlist(rules)
|
283
|
+
if word.empty?
|
284
|
+
m.reply _("couldn't think of anything ...")
|
285
|
+
return
|
286
|
+
end
|
287
|
+
m.reply _("got it!")
|
288
|
+
@games[k] = AzGame.new(self, lang, rules, word)
|
236
289
|
else
|
237
290
|
m.reply _("I can't play A-Z in %{lang}, sorry") % {:lang => lang}
|
238
291
|
return
|
239
292
|
end
|
240
|
-
m.reply _("got it!")
|
241
|
-
@games[k] = AzGame.new(self, lang, @rules[lang], word)
|
242
293
|
end
|
243
294
|
tr = @games[k].total_tries
|
244
295
|
# this message building code is rewritten to make translation easier
|
@@ -304,10 +355,10 @@ class AzGamePlugin < Plugin
|
|
304
355
|
if wc[word].key?(:when)
|
305
356
|
tr = _("%{word} learned from %{user} on %{date}") % {:word => word, :user => wc[word][:who], :date => wc[word][:when]}
|
306
357
|
else
|
307
|
-
tr = _("%{word} learned from %{user}") % {:word => word, :user => wc[word][:who]}
|
358
|
+
tr = _("%{word} learned from %{user}") % {:word => word, :user => wc[word][:who]}
|
308
359
|
end
|
309
360
|
m.reply tr
|
310
|
-
when :delete
|
361
|
+
when :delete
|
311
362
|
if pars.empty?
|
312
363
|
m.reply _("provide a word")
|
313
364
|
return
|
@@ -335,17 +386,12 @@ class AzGamePlugin < Plugin
|
|
335
386
|
end
|
336
387
|
end
|
337
388
|
|
338
|
-
def is_japanese?(word)
|
339
|
-
@rules[:japanese][:list].include?(word)
|
340
|
-
end
|
341
|
-
|
342
389
|
# return integer between min and max, inclusive
|
343
390
|
def rand_between(min, max)
|
344
391
|
rand(max - min + 1) + min
|
345
392
|
end
|
346
393
|
|
347
|
-
def
|
348
|
-
rules = @rules[:japanese]
|
394
|
+
def random_pick_wordlist(rules, min=nil, max=nil)
|
349
395
|
min = rules[:first] if min.nil_or_empty?
|
350
396
|
max = rules[:last] if max.nil_or_empty?
|
351
397
|
debug "Randomly picking word between #{min} and #{max}"
|
@@ -552,7 +598,14 @@ class AzGamePlugin < Plugin
|
|
552
598
|
when 'play'
|
553
599
|
return _("az => start a game if none is running, show the current word range otherwise; you can say 'az <language>' if you want to play in a language different from the current bot default")
|
554
600
|
end
|
555
|
-
|
601
|
+
langs = @rules.keys
|
602
|
+
wls = Wordlist.list
|
603
|
+
return [
|
604
|
+
_("az topics: play, rules, cancel, manage, check"),
|
605
|
+
_("available languages: %{langs}") % { :langs => langs.join(", ") },
|
606
|
+
wls.empty? ? nil : _("available wordlists: %{wls}") % { :wls => wls.join(", ") },
|
607
|
+
].compact.join(". ")
|
608
|
+
|
556
609
|
end
|
557
610
|
|
558
611
|
end
|
@@ -561,5 +614,5 @@ plugin = AzGamePlugin.new
|
|
561
614
|
plugin.map 'az [:lang] word :cmd *params', :action=>'wordlist', :defaults => { :lang => nil, :cmd => 'count', :params => [] }, :auth_path => '!az::edit!'
|
562
615
|
plugin.map 'az cancel', :action=>'stop_game', :private => false
|
563
616
|
plugin.map 'az check :word', :action => 'manual_word_check', :private => false
|
564
|
-
plugin.map 'az [play] [:lang]', :action=>'start_game', :private => false, :defaults => { :lang => nil }
|
617
|
+
plugin.map 'az [play] [:lang] [autoadd :addlang]', :action=>'start_game', :private => false, :defaults => { :lang => nil, :addlang => nil }
|
565
618
|
|
@@ -0,0 +1,499 @@
|
|
1
|
+
#-- vim:sw=2:et
|
2
|
+
#++
|
3
|
+
#
|
4
|
+
# :title: Hangman Plugin
|
5
|
+
#
|
6
|
+
# Author:: Raine Virta <rane@kapsi.fi>
|
7
|
+
# Copyright:: (C) 2009 Raine Virta
|
8
|
+
# License:: GPL v2
|
9
|
+
#
|
10
|
+
# Description:: Hangman game for rbot
|
11
|
+
#
|
12
|
+
# TODO:: some sort of turn-basedness, maybe
|
13
|
+
|
14
|
+
module RandomWord
|
15
|
+
SITE = "http://coyotecult.com/tools/randomwordgenerator.php"
|
16
|
+
|
17
|
+
def self.get(count=1)
|
18
|
+
res = Net::HTTP.post_form(URI.parse(SITE), {'numwords' => count})
|
19
|
+
words = res.body.scan(%r{<a.*?\?w=(.*?)\n}).flatten
|
20
|
+
|
21
|
+
count == 1 ? words.first : words
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module Google
|
26
|
+
URL = "http://www.google.com/wml/search?hl=en&q=define:"
|
27
|
+
REGEX = %r{Web definitions for .*?<br/>(.*?)<br/>}
|
28
|
+
|
29
|
+
def self.define(phrase)
|
30
|
+
raw = Net::HTTP.get(URI.parse(URL+CGI.escape(phrase)))
|
31
|
+
res = raw.scan(REGEX).flatten.map { |e| e.strip }
|
32
|
+
|
33
|
+
res.empty? ? false : res.last
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Hangman
|
38
|
+
LETTER_VALUE = 5
|
39
|
+
|
40
|
+
module Scoring
|
41
|
+
def self.correct_word_guess(game)
|
42
|
+
# (2 - (amt of visible chars / word length)) * (amt of chars not visible * 5)
|
43
|
+
length = game.word.size
|
44
|
+
visible = game.visible_characters.size
|
45
|
+
invisible = length - visible
|
46
|
+
score = (2-(visible/length.to_f))*(invisible*5)
|
47
|
+
score *= 1.5
|
48
|
+
score.round
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.incorrect_word_guess(game)
|
52
|
+
incorrect_letter(game)
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.correct_letter(game)
|
56
|
+
((1/Math.log(game.word.size))+1) * LETTER_VALUE
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.incorrect_letter(game)
|
60
|
+
Math.log(game.word.size) * -LETTER_VALUE
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class Hangman
|
66
|
+
attr_reader :misses, :guesses, :word, :scores
|
67
|
+
|
68
|
+
STAGES = [' (x_x) ', ' (;_;) ', ' (>_<) ', ' (-_-) ', ' (o_~) ', ' (^_^) ', '\(^o^)/']
|
69
|
+
HEALTH = STAGES.size-1
|
70
|
+
LETTER = /[^\W0-9_]/u
|
71
|
+
|
72
|
+
def initialize(word)
|
73
|
+
@word = word
|
74
|
+
@guesses = []
|
75
|
+
@misses = []
|
76
|
+
@health = HEALTH
|
77
|
+
@canceled = false
|
78
|
+
@solved = false
|
79
|
+
@scores = {}
|
80
|
+
end
|
81
|
+
|
82
|
+
def visible_characters
|
83
|
+
# array of visible characters
|
84
|
+
characters.reject { |c| !@guesses.include?(c) && c =~ LETTER }
|
85
|
+
end
|
86
|
+
|
87
|
+
def letters
|
88
|
+
# array of the letters in the word
|
89
|
+
characters.reject { |c| c !~ LETTER }.map { |c| c.downcase }
|
90
|
+
end
|
91
|
+
|
92
|
+
def characters
|
93
|
+
@word.split(//u)
|
94
|
+
end
|
95
|
+
|
96
|
+
def face
|
97
|
+
STAGES[@health]
|
98
|
+
end
|
99
|
+
|
100
|
+
def to_s
|
101
|
+
# creates a string that presents the word with unknown letters shown as underscores
|
102
|
+
characters.map { |c|
|
103
|
+
@guesses.include?(c.downcase) || c !~ LETTER ? c : "_"
|
104
|
+
}.join
|
105
|
+
end
|
106
|
+
|
107
|
+
def guess(player, str)
|
108
|
+
@scores[player] ||= 0
|
109
|
+
|
110
|
+
str.downcase!
|
111
|
+
# full word guess
|
112
|
+
if str !~ /^#{LETTER}$/u
|
113
|
+
if word.downcase == str
|
114
|
+
@scores[player] += Scoring::correct_word_guess(self)
|
115
|
+
@solved = true
|
116
|
+
else
|
117
|
+
@scores[player] += Scoring::incorrect_word_guess(self)
|
118
|
+
punish
|
119
|
+
end
|
120
|
+
else # single letter guess
|
121
|
+
return false if @guesses.include?(str) # letter has been guessed before
|
122
|
+
|
123
|
+
unless letters.include?(str)
|
124
|
+
@scores[player] += Scoring::incorrect_letter(self)
|
125
|
+
@misses << str
|
126
|
+
punish
|
127
|
+
else
|
128
|
+
@scores[player] += Scoring::correct_letter(self)
|
129
|
+
end
|
130
|
+
|
131
|
+
@guesses << str
|
132
|
+
end
|
133
|
+
|
134
|
+
return true
|
135
|
+
end
|
136
|
+
|
137
|
+
def over?
|
138
|
+
won? || lost? || @canceled
|
139
|
+
end
|
140
|
+
|
141
|
+
def won?
|
142
|
+
(letters - @guesses).empty? || @solved
|
143
|
+
end
|
144
|
+
|
145
|
+
def lost?
|
146
|
+
@health.zero?
|
147
|
+
end
|
148
|
+
|
149
|
+
def punish
|
150
|
+
@health -= 1
|
151
|
+
end
|
152
|
+
|
153
|
+
def cancel
|
154
|
+
@canceled = true
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
class GameManager
|
159
|
+
def initialize
|
160
|
+
@games = {}
|
161
|
+
end
|
162
|
+
|
163
|
+
def current(target)
|
164
|
+
game = all(target).last
|
165
|
+
game if game && !game.over?
|
166
|
+
end
|
167
|
+
|
168
|
+
def all(target)
|
169
|
+
@games[target] || @games[target] = []
|
170
|
+
end
|
171
|
+
|
172
|
+
def previous(target)
|
173
|
+
all(target).select { |game| game.over? }.last
|
174
|
+
end
|
175
|
+
|
176
|
+
def new(game)
|
177
|
+
all(game.channel) << game
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
define_structure :HangmanPlayerStats, :played, :score
|
182
|
+
define_structure :HangmanPrivateStats, :played, :score
|
183
|
+
|
184
|
+
class StatsHandler
|
185
|
+
def initialize(registry)
|
186
|
+
@registry = registry
|
187
|
+
end
|
188
|
+
|
189
|
+
def save_gamestats(game)
|
190
|
+
target = game.channel
|
191
|
+
|
192
|
+
if target.is_a?(User)
|
193
|
+
stats = priv_reg[target]
|
194
|
+
stats.played += 1
|
195
|
+
stats.score += game.scores.values.last.round
|
196
|
+
priv_reg[target] = stats
|
197
|
+
elsif target.is_a?(Channel)
|
198
|
+
stats = chan_stats(target)
|
199
|
+
stats['played'] += 1
|
200
|
+
|
201
|
+
reg = player_stats(target)
|
202
|
+
game.scores.each do |user, score|
|
203
|
+
pstats = reg[user]
|
204
|
+
pstats.played += 1
|
205
|
+
pstats.score += score.round
|
206
|
+
reg[user] = pstats
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def player_stats(channel)
|
212
|
+
reg = chan_reg(channel).sub_registry('player')
|
213
|
+
reg.set_default(HangmanPlayerStats.new(0,0))
|
214
|
+
reg
|
215
|
+
end
|
216
|
+
|
217
|
+
def chan_stats(channel)
|
218
|
+
reg = chan_reg(channel).sub_registry('stats')
|
219
|
+
reg.set_default(0)
|
220
|
+
reg
|
221
|
+
end
|
222
|
+
|
223
|
+
def chan_reg(channel)
|
224
|
+
@registry.sub_registry(channel.downcase)
|
225
|
+
end
|
226
|
+
|
227
|
+
def priv_reg
|
228
|
+
reg = @registry.sub_registry('private')
|
229
|
+
reg.set_default(HangmanPrivateStats.new(0,0))
|
230
|
+
reg
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
class HangmanPlugin < Plugin
|
235
|
+
def initialize
|
236
|
+
super
|
237
|
+
@games = GameManager.new
|
238
|
+
@stats = StatsHandler.new(@registry)
|
239
|
+
@settings = {}
|
240
|
+
end
|
241
|
+
|
242
|
+
def help(plugin, topic="")
|
243
|
+
case topic
|
244
|
+
when ""
|
245
|
+
return _("hangman game plugin - topics: play, stop")
|
246
|
+
when "play"
|
247
|
+
return [_("hangman play on <channel> with word <word> => use in private chat with the bot to start a game with custom word\n"),
|
248
|
+
_("hangman play random [with [max|min] length [<|>|== <length>]] => hangman with a random word from %{site}\n"),
|
249
|
+
_("hangman play with wordlist <wordlist> => hangman with random word from <wordlist>")].join % { :site => RandomWord::SITE }
|
250
|
+
when "stop"
|
251
|
+
return _("hangman stop => quits the current game")
|
252
|
+
when "define"
|
253
|
+
return _("define => seeks a definition for the previous answer using google")
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
def get_word(params)
|
258
|
+
if params[:word]
|
259
|
+
params[:word].join(" ")
|
260
|
+
elsif params[:wordlist]
|
261
|
+
begin
|
262
|
+
wordlist = Wordlist.get(params[:wordlist].join("/"), :spaces => true)
|
263
|
+
rescue
|
264
|
+
raise _("no such wordlist")
|
265
|
+
end
|
266
|
+
|
267
|
+
wordlist[rand(wordlist.size)]
|
268
|
+
else # getting a random word
|
269
|
+
words = RandomWord::get(100)
|
270
|
+
|
271
|
+
if adj = params[:adj]
|
272
|
+
words = words.sort_by { |e| e.size }
|
273
|
+
|
274
|
+
if adj == "max"
|
275
|
+
words.last
|
276
|
+
else
|
277
|
+
words.first
|
278
|
+
end
|
279
|
+
elsif params[:relation] && params[:size]
|
280
|
+
words = words.select { |w| w.size.send(params[:relation], params[:size].to_i) }
|
281
|
+
|
282
|
+
unless words.empty?
|
283
|
+
words.first
|
284
|
+
else
|
285
|
+
m.reply _("suitable word not found in the set")
|
286
|
+
nil
|
287
|
+
end
|
288
|
+
else
|
289
|
+
words.first
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
def start(m, params)
|
295
|
+
begin
|
296
|
+
word = get_word(params) || return
|
297
|
+
rescue => e
|
298
|
+
m.reply e.message
|
299
|
+
return
|
300
|
+
end
|
301
|
+
|
302
|
+
if params[:channel] || m.public?
|
303
|
+
target = if m.public?
|
304
|
+
m.channel
|
305
|
+
else
|
306
|
+
params[:channel]
|
307
|
+
end
|
308
|
+
|
309
|
+
# is the bot on the channel?
|
310
|
+
unless @bot.server.channels.names.include?(target.to_s)
|
311
|
+
m.reply _("i'm not on that channel")
|
312
|
+
return
|
313
|
+
end
|
314
|
+
|
315
|
+
if @games.current(target)
|
316
|
+
m.reply _("there's already a hangman game in progress on the channel")
|
317
|
+
return
|
318
|
+
end
|
319
|
+
|
320
|
+
@bot.say target, _("%{nick} has started a hangman -- join the fun!") % {
|
321
|
+
:nick => m.source
|
322
|
+
}
|
323
|
+
else
|
324
|
+
target = m.source
|
325
|
+
end
|
326
|
+
|
327
|
+
game = Hangman.new(word)
|
328
|
+
|
329
|
+
class << game = Hangman.new(word)
|
330
|
+
attr_accessor :channel
|
331
|
+
end
|
332
|
+
|
333
|
+
game.channel = target
|
334
|
+
|
335
|
+
@games.new(game)
|
336
|
+
@settings[target] = params
|
337
|
+
|
338
|
+
@bot.say target, game_status(@games.current(target))
|
339
|
+
end
|
340
|
+
|
341
|
+
def stop(m, params)
|
342
|
+
target = m.replyto
|
343
|
+
if game = @games.current(target)
|
344
|
+
@bot.say target, _("oh well, the answer would've been %{answer}") % {
|
345
|
+
:answer => Bold + game.word + Bold
|
346
|
+
}
|
347
|
+
|
348
|
+
game.cancel
|
349
|
+
@stats.save_gamestats(game)
|
350
|
+
else
|
351
|
+
@bot.say target, _("no ongoing game")
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
def message(m)
|
356
|
+
target = m.replyto
|
357
|
+
|
358
|
+
if game = @games.current(target)
|
359
|
+
return unless m.message =~ /^[^\W0-9_]$/u || m.message =~ prepare_guess_regex(game)
|
360
|
+
|
361
|
+
if game.guess(m.source, m.message)
|
362
|
+
m.reply game_status(game)
|
363
|
+
else
|
364
|
+
return
|
365
|
+
end
|
366
|
+
|
367
|
+
if game.over?
|
368
|
+
sentence = if game.won?
|
369
|
+
_("you nailed it!")
|
370
|
+
elsif game.lost?
|
371
|
+
_("you've killed the poor guy :(")
|
372
|
+
end
|
373
|
+
|
374
|
+
again = _("go %{b}again%{b}?") % { :b => Bold }
|
375
|
+
|
376
|
+
scores = []
|
377
|
+
game.scores.each do |user, score|
|
378
|
+
str = "#{user.nick}: "
|
379
|
+
str << if score > 0
|
380
|
+
Irc.color(:green)+'+'
|
381
|
+
elsif score < 0
|
382
|
+
Irc.color(:brown)
|
383
|
+
end.to_s
|
384
|
+
|
385
|
+
str << score.round.to_s
|
386
|
+
str << Irc.color
|
387
|
+
|
388
|
+
scores << str
|
389
|
+
end
|
390
|
+
|
391
|
+
m.reply _("%{sentence} %{again} %{scores}") % {
|
392
|
+
:sentence => sentence, :again => again, :scores => scores.join(' ')
|
393
|
+
}, :nick => true
|
394
|
+
|
395
|
+
if rand(5).zero?
|
396
|
+
m.reply _("wondering what that means? try ´%{prefix}define´") % {
|
397
|
+
:prefix => @bot.config['core.address_prefix']
|
398
|
+
}
|
399
|
+
end
|
400
|
+
|
401
|
+
@stats.save_gamestats(game)
|
402
|
+
end
|
403
|
+
elsif @settings[target] && m.message =~ /^(?:again|more!?$)/i
|
404
|
+
start(m, @settings[target])
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
def prepare_guess_regex(game)
|
409
|
+
Regexp.new("^#{game.characters.map { |c|
|
410
|
+
game.guesses.include?(c) || c !~ Hangman::LETTER ? c : '[^\W0-9_]'
|
411
|
+
}.join("")}$")
|
412
|
+
end
|
413
|
+
|
414
|
+
def game_status(game)
|
415
|
+
str = "%{word} %{face}" % {
|
416
|
+
:word => game.over? ? "#{Bold}#{game.word}#{Bold}" : game.to_s,
|
417
|
+
:face => game.face,
|
418
|
+
:misses => game.misses.map { |e| e.upcase }.join(" ")
|
419
|
+
}
|
420
|
+
|
421
|
+
str << " %{misses}" % {
|
422
|
+
:misses => game.misses.map { |e| e.upcase }.join(" ")
|
423
|
+
} unless game.misses.empty?
|
424
|
+
|
425
|
+
str
|
426
|
+
end
|
427
|
+
|
428
|
+
def score(m, params)
|
429
|
+
target = m.replyto
|
430
|
+
|
431
|
+
unless params[:nick]
|
432
|
+
stats = if m.private?
|
433
|
+
@stats.priv_reg[target]
|
434
|
+
else
|
435
|
+
@stats.player_stats(target)[m.source]
|
436
|
+
end
|
437
|
+
|
438
|
+
unless stats.played.zero?
|
439
|
+
m.reply _("you got %{score} points after %{games} games") % {
|
440
|
+
:score => stats.score.round,
|
441
|
+
:games => stats.played
|
442
|
+
}
|
443
|
+
else
|
444
|
+
m.reply _("you haven't played hangman, how about playing it right now? :)")
|
445
|
+
end
|
446
|
+
else
|
447
|
+
return unless m.public?
|
448
|
+
|
449
|
+
nick = params[:nick]
|
450
|
+
stats = @stats.player_stats(target)[nick]
|
451
|
+
|
452
|
+
unless stats.played.zero?
|
453
|
+
m.reply _("%{nick} has %{score} points after %{games} games") % {
|
454
|
+
:nick => nick,
|
455
|
+
:score => stats.score.round,
|
456
|
+
:games => stats.played
|
457
|
+
}
|
458
|
+
else
|
459
|
+
m.reply _("%{nick} hasn't played hangman :(") % {
|
460
|
+
:nick => nick
|
461
|
+
}
|
462
|
+
end
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
def stats(m, params)
|
467
|
+
target = m.replyto
|
468
|
+
stats = @stats.chan_stats(target)
|
469
|
+
|
470
|
+
if m.public?
|
471
|
+
m.reply _("%{games} games have been played on %{channel}") % {
|
472
|
+
:games => stats['played'],
|
473
|
+
:channel => target.to_s
|
474
|
+
}
|
475
|
+
else
|
476
|
+
score(m, params)
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
480
|
+
def define(m, params)
|
481
|
+
if game = @games.previous(m.replyto)
|
482
|
+
return unless res = Google.define(game.word)
|
483
|
+
m.reply "#{Bold}#{game.word}#{Bold} -- #{res}"
|
484
|
+
end
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
plugin = HangmanPlugin.new
|
489
|
+
plugin.map "hangman [play] with wordlist *wordlist", :action => 'start'
|
490
|
+
plugin.map "hangman [play] on :channel with word *word", :action => 'start'
|
491
|
+
plugin.map "hangman [play] [random] [with [:adj] length [:relation :size]]",
|
492
|
+
:action => 'start',
|
493
|
+
:requirements => { :adj => /min|max/, :relation => /<|<=|>=|>|==/, :size => /\d+/ }
|
494
|
+
|
495
|
+
plugin.map "hangman stop", :action => 'stop'
|
496
|
+
|
497
|
+
plugin.map "hangman score [:nick]", :action => 'score'
|
498
|
+
plugin.map "hangman stats", :action => 'stats'
|
499
|
+
plugin.map "define", :action => 'define'
|