zetabot 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +281 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +41 -0
  7. data/Rakefile +6 -0
  8. data/Zeta.gemspec +74 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +13 -0
  11. data/bin/zeta +9 -0
  12. data/bin/zeta-setup +13 -0
  13. data/lib/Zeta.rb +13 -0
  14. data/lib/Zeta/access.rb +84 -0
  15. data/lib/Zeta/admin.rb +10 -0
  16. data/lib/Zeta/admin/autojoin.rb +25 -0
  17. data/lib/Zeta/admin/bot.rb +43 -0
  18. data/lib/Zeta/admin/channels.rb +36 -0
  19. data/lib/Zeta/admin/eval.rb +43 -0
  20. data/lib/Zeta/admin/fifo.rb +45 -0
  21. data/lib/Zeta/admin/ignore.rb +112 -0
  22. data/lib/Zeta/admin/oper.rb +50 -0
  23. data/lib/Zeta/admin/plugins.rb +109 -0
  24. data/lib/Zeta/admin/users.rb +5 -0
  25. data/lib/Zeta/blacklist.rb +25 -0
  26. data/lib/Zeta/cache.rb +0 -0
  27. data/lib/Zeta/cinch.rb +35 -0
  28. data/lib/Zeta/config.rb +42 -0
  29. data/lib/Zeta/gems.rb +0 -0
  30. data/lib/Zeta/locale.rb +4 -0
  31. data/lib/Zeta/log.rb +2 -0
  32. data/lib/Zeta/models.rb +5 -0
  33. data/lib/Zeta/models/channel.rb +3 -0
  34. data/lib/Zeta/models/plugin.rb +3 -0
  35. data/lib/Zeta/models/user.rb +3 -0
  36. data/lib/Zeta/plugins.rb +27 -0
  37. data/lib/Zeta/plugins/attack.rb +61 -0
  38. data/lib/Zeta/plugins/botinfo.rb +83 -0
  39. data/lib/Zeta/plugins/darkscience.rb +215 -0
  40. data/lib/Zeta/plugins/dbz.rb +31 -0
  41. data/lib/Zeta/plugins/dcc.rb +25 -0
  42. data/lib/Zeta/plugins/dnsbl.rb +36 -0
  43. data/lib/Zeta/plugins/echo.rb +15 -0
  44. data/lib/Zeta/plugins/eightball.rb +53 -0
  45. data/lib/Zeta/plugins/fml.rb +35 -0
  46. data/lib/Zeta/plugins/fnord.rb +329 -0
  47. data/lib/Zeta/plugins/gem.rb +0 -0
  48. data/lib/Zeta/plugins/gif.rb +73 -0
  49. data/lib/Zeta/plugins/help.rb +32 -0
  50. data/lib/Zeta/plugins/libsecure.rb +34 -0
  51. data/lib/Zeta/plugins/macros.rb +124 -0
  52. data/lib/Zeta/plugins/movie.rb +67 -0
  53. data/lib/Zeta/plugins/pdfinfo.rb +69 -0
  54. data/lib/Zeta/plugins/rainbow.rb +65 -0
  55. data/lib/Zeta/plugins/russian_roulette.rb +90 -0
  56. data/lib/Zeta/plugins/seen.rb +77 -0
  57. data/lib/Zeta/plugins/silly.rb +183 -0
  58. data/lib/Zeta/plugins/snooper.rb +146 -0
  59. data/lib/Zeta/plugins/urban.rb +60 -0
  60. data/lib/Zeta/plugins/weather.rb +203 -0
  61. data/lib/Zeta/plugins/whois.rb +25 -0
  62. data/lib/Zeta/plugins/wiki.rb +75 -0
  63. data/lib/Zeta/plugins/wolfram.rb +46 -0
  64. data/lib/Zeta/tasks/db.rb +0 -0
  65. data/lib/Zeta/version.rb +3 -0
  66. data/lib/generators/config/config.rb +0 -0
  67. data/lib/generators/plugin/new_plugin.rb +0 -0
  68. data/locale/en/8ball.yml +0 -0
  69. data/locale/en/attack.yml +148 -0
  70. data/locale/en/dbz.yml +10 -0
  71. data/locale/en/ircop.yml +5 -0
  72. data/locale/en/macros.yml +98 -0
  73. data/locale/en/meme.yml +27 -0
  74. metadata +636 -0
@@ -0,0 +1,215 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+ require 'ostruct'
4
+ require 'action_view'
5
+
6
+ module Plugins
7
+ class DarkScience
8
+ include Cinch::Plugin
9
+ include Cinch::Helpers
10
+ include ActionView::Helpers::DateHelper
11
+
12
+ enable_acl(:nobody)
13
+
14
+ self.plugin_name = 'DarkScience API'
15
+ self.help = '?finger <nick>, ?peek <#channel>, ?stats <nick>, ?quote, ?addquote <quote>, ?quote <id>'
16
+
17
+ # Triggers
18
+ match /peek (.+)/, method: :peek
19
+ match /finger (.+)/, method: :finger
20
+ match /stats (.+)/, method: :stats
21
+ match /addquote (.+)/i, method: :addquote
22
+ match /quote (.+)/i, method: :quote
23
+ match 'quote', method: :randomquote
24
+
25
+
26
+ # Methods
27
+ #########
28
+ def peek(msg, channel)
29
+ chan = channel || msg.user.channel
30
+
31
+ # JSON Request
32
+ begin
33
+ RestClient.proxy = ENV['http_proxy']
34
+ data = JSON.parse(
35
+ RestClient.post(
36
+ 'https://darchoods.net/api/irc/channel/view',
37
+ {
38
+ auth_token: Config.secrets[:darkscience],
39
+ channel: chan,
40
+ }
41
+ )
42
+ )
43
+ rescue RestClient::Unauthorized
44
+ msg.action_reply "isn't currently authorized to do that"
45
+ end
46
+
47
+ # Turn JSON into an object
48
+ request = Hashie::Mash.new(data)
49
+
50
+ # Error Code replies
51
+ return msg.reply("Peek → #{request.message}") if request.status_code == 500
52
+ return msg.reply('Peek → Service Down') if request.status_code != 200
53
+ return msg.reply('Peek → Channel Not Found') if request.data.channel.empty?
54
+
55
+ msg.reply "Peek → #{request.data.channel.name} (#{request.data.channel.modes}) ~ " \
56
+ "Users: #{request.data.channel.stats.current_users} (#{request.data.channel.stats.peak_users}x̄) ~ " \
57
+ "Last Topic set by #{request.data.channel.topic.author} @ #{Time.at(request.data.channel.topic.time).strftime("%D")}"
58
+ end
59
+
60
+
61
+ def finger(msg, nickname)
62
+ nick = nickname || msg.user.nick
63
+
64
+ # JSON request
65
+ begin
66
+ RestClient.proxy = ENV['http_proxy']
67
+ data = JSON.parse(
68
+ RestClient.post(
69
+ 'https://darchoods.net/api/irc/user/view',
70
+ {
71
+ auth_token: Config.secrets[:darkscience],
72
+ username: nick,
73
+ }
74
+ )
75
+ )
76
+ rescue RestClient::Unauthorized
77
+ msg.action_reply "isn't currently authorized to do that"
78
+ end
79
+
80
+ # Turn JSON into an object
81
+ # request = Hashie::Mash.new(data)
82
+
83
+
84
+ # Error code replies
85
+ return msg.reply('Finger → User Not Found') if data['data']['user'].empty?
86
+ return msg.reply('Finger → Service Down') if data['status_code'] != 200
87
+
88
+ user = data['data']['user']
89
+ stats = data['data']['stats']
90
+ away_msg = data['data']['user']['away_msg'] || "No Message"
91
+ online_last = data['data']['user']['online_last'] || 0
92
+
93
+ msg.reply "Finger → #{user['userstring']} ~ " \
94
+ "#{user['identified'] ? 'Identified' : 'Not Identified'} ~ " \
95
+ "Currently in #{stats['channel_count']} channels ~ " \
96
+ "Seen #{user['online'] ? 'Now' : time_ago_in_words(Time.at(online_last))+ " ago"} ~ " \
97
+ "Geo: #{user['country']} ~ " \
98
+ "#{user['away'] ? 'Away: ' + away_msg : 'Available' } ~ " \
99
+ "Client: #{user['version']} ~ "
100
+ end
101
+
102
+
103
+ def stats(msg, nickname)
104
+ nick = nickname || msg.user.nick
105
+
106
+ # JSON request
107
+ begin
108
+ data = JSON.parse(
109
+ RestClient.post(
110
+ 'https://darchoods.net/api/irc/user/view',
111
+ {
112
+ auth_token: Config.secrets[:darkscience],
113
+ username: nick,
114
+ }
115
+ )
116
+ )
117
+ rescue RestClient::Unauthorized
118
+ msg.action_reply "isn't currently authorized to do that"
119
+ end
120
+
121
+ # Turn JSON into an object
122
+ # request = Hashie::Mash.new(data)
123
+
124
+
125
+ # Error code replies
126
+ return msg.reply('Statistics → User Not Found') if data['data']['user'].empty?
127
+ return msg.reply('Statistics → Service Down') if data['status_code'] != 200
128
+
129
+ user = data['data']['user']
130
+ stats = data['data']['stats']
131
+
132
+ msg.reply "Statistics → #{user['nick']} ~ " \
133
+ "Currently in #{stats['channel_count']} ~ " \
134
+ "Owner of #{stats['mode_counts']['q']} channels ~ " \
135
+ "Admin of #{stats['mode_counts']['a']} channels ~ " \
136
+ "Operator(halfop) of #{stats['mode_counts']['o']}(#{stats['mode_counts']['h']}) channels ~ " \
137
+ "and finally voiced in #{stats['mode_counts']['v']} channels"
138
+
139
+ end
140
+
141
+ def addquote(m, quote)
142
+ begin
143
+ request = JSON.parse(
144
+ RestClient.post(
145
+ 'https://darchoods.net/api/qdb/create',
146
+ {
147
+ auth_token: Config.secrets[:darkscience],
148
+ channel: m.channel,
149
+ author: m.user,
150
+ quote: quote
151
+ }
152
+ )
153
+ )
154
+ quote = Hashie::Mash.new(request)
155
+
156
+ m.reply "Quote ##{quote.data.quote.quote_id} added by #{m.user}!"
157
+ rescue RestClient::Unauthorized
158
+ m.action_reply "isn't currently authorized to do that"
159
+ rescue
160
+ m.reply 'QDB is unavailable right now'
161
+ end
162
+ end
163
+
164
+ def quote(m, search)
165
+ begin
166
+ request = JSON.parse(
167
+ RestClient.post(
168
+ 'https://darchoods.net/api/qdb/search/byId',
169
+ {
170
+ auth_token: Config.secrets[:darkscience],
171
+ channel: m.channel,
172
+ quote_id: search
173
+ }
174
+ )
175
+ )
176
+ quote = Hashie::Mash.new(request)
177
+
178
+ return m.reply 'There is no quote by that ID' unless quote.data.quote
179
+
180
+ m.reply "QDB##{quote.data.quote.quote_id}: #{quote.data.quote.content}"
181
+ rescue RestClient::Unauthorized
182
+ m.action_reply "isn't currently authorized to do that"
183
+ rescue
184
+ m.reply "QDB is unavailable right now"
185
+ end
186
+
187
+ end
188
+
189
+ def randomquote(m)
190
+ begin
191
+ request = JSON.parse(
192
+ RestClient.post(
193
+ 'https://darchoods.net/api/qdb/random',
194
+ { auth_token: Config.secrets[:darkscience],
195
+ channel: m.channel
196
+ }
197
+ )
198
+ )
199
+ quote = Hashie::Mash.new(request)
200
+
201
+ m.reply "QDB##{quote.data.quote.quote_id}: #{quote.data.quote.content}"
202
+ rescue RestClient::Unauthorized
203
+ m.action_reply "isn't currently authorized to do that"
204
+ rescue
205
+ m.reply "QDB is unavailable right now"
206
+ end
207
+
208
+ end
209
+
210
+
211
+ end
212
+ end
213
+
214
+ # AutoLoad
215
+ Bot.config.plugins.plugins.push Plugins::DarkScience
@@ -0,0 +1,31 @@
1
+ module Plugins
2
+ class DBZ
3
+ include Cinch::Plugin
4
+ include Cinch::Helpers
5
+
6
+ enable_acl
7
+
8
+ self.plugin_name = 'DragonBall Z!'
9
+ self.help = "It's Over Nine Thousand!"
10
+
11
+ # Regex
12
+ match /(^9000$|overninethousand|ninethousand|Over\ Nine\ Thousand|Over\ 9000)/,
13
+ use_prefix: false, method: :randomquote
14
+
15
+ # Initialization
16
+ def initialize(*args)
17
+ @sample = load_locale('dbz')
18
+ super
19
+ end
20
+
21
+ # Methods
22
+ def randomquote(msg)
23
+ msg.reply @sample['over9k'].sample
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+
30
+ # AutoLoad
31
+ Bot.config.plugins.plugins.push Plugins::DBZ
@@ -0,0 +1,25 @@
1
+ # module Plugins
2
+ # class DCC
3
+ # include Cinch::Plugin
4
+ # set(
5
+ # plugin_name: "DCC",
6
+ # help: "Darkscience Code Contest.\nUsage: `~nick [channel]`;",
7
+ # prefix: /^!/
8
+ # )
9
+ # match /dcc/, method: :dcc
10
+ # match /dcc list/, method: :dcc_list
11
+ #
12
+ # def dcc
13
+ #
14
+ # end
15
+ #
16
+ # private
17
+ # def github()
18
+ # github = Github.new oauth_token: Zsec.keys.github
19
+ # end
20
+ #
21
+ # end
22
+ # end
23
+ #
24
+ # # AutoLoad
25
+ # Bot.config.plugins.plugins.push Plugins::DCC
@@ -0,0 +1,36 @@
1
+ require 'dnsbl/client'
2
+
3
+ module Plugins
4
+ class DNSBL
5
+ include Cinch::Plugin
6
+ include Cinch::Helpers
7
+
8
+ enable_acl
9
+
10
+ self.plugin_name = 'DNS Blacklist'
11
+ self.help = '?dnsbl <host>'
12
+
13
+ # Regex
14
+ match /dnsbl (.+)/, method: :dnsbl_lookup
15
+ match /blacklist (.+)/, method: :dnsbl_lookup
16
+
17
+ # Methods
18
+ def dnsbl_lookup(m, host)
19
+ client = DNSBL::Client.new
20
+ query = client.lookup(host.rstrip)
21
+
22
+ if query.empty?
23
+ m.reply "No Results Found (#{host})"
24
+ elsif query.last.dnsbl == 'URIBL' && query.last.meaning == '127.0.0.1'
25
+ m.reply "No Results Found (#{host})"
26
+ else
27
+ m.reply "Listed ⁘ #{host} ⁜ #{query.last.meaning} ⁜ Hits: #{query.count}"
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+
35
+ # AutoLoad
36
+ Bot.config.plugins.plugins.push Plugins::DNSBL
@@ -0,0 +1,15 @@
1
+ module Plugins
2
+ class Echo
3
+ include Cinch::Plugin
4
+
5
+ enable_acl(:voice)
6
+
7
+ match /echo (.+)/, method: :echoed
8
+
9
+ def echoed(m,s)
10
+ m.reply s
11
+ end
12
+
13
+ end
14
+ end
15
+ Bot.config.plugins.plugins.push Plugins::Echo
@@ -0,0 +1,53 @@
1
+ module Plugins
2
+ class Eightball
3
+ include Cinch::Plugin
4
+ include Cinch::Helpers
5
+
6
+ enable_acl
7
+
8
+ set(
9
+ plugin_name: "8ball",
10
+ help: "The Magic 8ball has all the answers!\nUsage: `?8ball [question? <question? <...>>]`",
11
+ react_on: :channel)
12
+
13
+ # Variables
14
+ @@eightball = [
15
+ "It is certain",
16
+ "It is decidedly so",
17
+ "Without a doubt",
18
+ "Yes - definitely",
19
+ "You may rely on it",
20
+ "As I see it, yes",
21
+ "Most likely",
22
+ "Outlook good",
23
+ "Signs point to yes",
24
+ "Yes",
25
+ "Reply hazy, try again",
26
+ "Ask again later",
27
+ "Better not tell you now",
28
+ "Cannot predict now",
29
+ "Concentrate and ask again",
30
+ "Don't count on it",
31
+ "My reply is no",
32
+ "My sources say no",
33
+ "Outlook not so good",
34
+ "Very doubtful"
35
+ ]
36
+
37
+ # Regex
38
+ match /8ball (.+)/
39
+
40
+ # Methods
41
+ def shake!
42
+ @@eightball.sample
43
+ end
44
+
45
+ def execute(m, s)
46
+ m.safe_reply @@eightball.sample, true
47
+ end
48
+
49
+ end
50
+ end
51
+
52
+ # AutoLoad
53
+ Bot.config.plugins.plugins.push Plugins::Eightball
@@ -0,0 +1,35 @@
1
+ # This plugin is brought to you by aburdette/cinch-fmylife
2
+ # Thank You!
3
+
4
+ module Plugins
5
+ class Fml
6
+ include Cinch::Plugin
7
+ include Cinch::Helpers
8
+
9
+ enable_acl(:nobody)
10
+
11
+ set(
12
+ plugin_name: "FuckMyLife",
13
+ help: "Get a random FML.\nUsage: `?fml`",
14
+ )
15
+
16
+ match /fml/
17
+
18
+ def execute(m)
19
+ m.reply fetch_random_fml, true
20
+ end
21
+
22
+ private
23
+ def fetch_random_fml
24
+ url = 'http://www.fmylife.com/random'
25
+ # fml_story = Nokogiri.HTML(RestClient.get(url)).at('div.article').text.strip
26
+ fml_story = Nokogiri.HTML(open(url).read).at('div.article').text.strip
27
+ fml_story[/^Today, (.+) FML/]
28
+ rescue => e
29
+ e.message
30
+ end
31
+ end
32
+ end
33
+
34
+ # AutoLoad
35
+ Bot.config.plugins.plugins.push Plugins::Fml
@@ -0,0 +1,329 @@
1
+ require 'cinch'
2
+ require 'chronic'
3
+
4
+ module Plugins
5
+ class Fnord
6
+ include Cinch::Plugin
7
+ include Cinch::Helpers
8
+ enable_acl
9
+
10
+ @help="fnord: ?fnord - Creates a fnord"
11
+ @plugin_name="fnord"
12
+ ADJECTIVES =
13
+ ["23rd", "acceptable", "acrobatic", "alien", "amiable",
14
+ "amoeboid", "ancient", "arbitrary", "atomic", "avenging",
15
+ "awesome", "balanced", "besotted", "best", "black", "blue",
16
+ "calculating", "cast iron", "cat-like", "cautious", "Chinese",
17
+ "cold", "communist", "corrupt", "dead", "deadly", "dehydrated",
18
+ "disguised", "dizzy", "drug-crazed", "drunken", "easy",
19
+ "electric", "embossed", "enormous", "expensive", "explosive",
20
+ "extraterrestrial", "ferocious", "frozen", "furry", "gelatinous",
21
+ "glowing", "gnarly", "gold", "granular", "greedy", "green",
22
+ "high", "highest", "hot", "humming", "illuminated", "imitation",
23
+ "impotent", "impudent", "impulsive", "indictable", "innocent",
24
+ "insane", "Japanese", "lecherous", "lizard-like", "lovely",
25
+ "maniacal", "mauve", "medium-sized", "morbid", "most influential",
26
+ "mutant", "naughty", "nuclear", "oily", "oozing", "opaque",
27
+ "opulent", "orbital", "persuasive", "pickled", "poor",
28
+ "pregnant", "protozoan", "puce", "pulsating", "purple",
29
+ "putrid", "radical", "radioactive", "red", "reformed",
30
+ "reincarnated", "rubber", "Russian", "screaming", "sexy",
31
+ "shiftless", "shifty", "Siamese", "silver", "sin-ridden",
32
+ "sinister", "sizzling", "skeptical", "slack-producing",
33
+ "sleeping", "slick", "slime-dripping", "slimy", "slippery",
34
+ "sluggish", "smoking", "solid gold", "splendid", "squamous",
35
+ "stoned", "sweet", "temporary", "throbbing", "tin-plated",
36
+ "tiny", "transient", "treacherous", "tubular", "ugly",
37
+ "untouchable", "user-friendly", "user-serviceable", "vacant",
38
+ "vacillating", "vampiric", "vibrant", "virginal", "vivid",
39
+ "wealthy", "well-dressed", "white", "wimpy", "worthless",
40
+ "young", "illegal", "tax-free", "drugged", "polluted",
41
+ "flaming", "diseased", "agnostic", "anorexic", "conquering",
42
+ "cosmic", "dancing", "dyslexic", "frenzied", "lumpy", "musical",
43
+ "plump", "perfectly ordinary", "French", "Martian",
44
+ "beautiful", "broken", "corruscating", "enhanced", "frightening",
45
+ "horrific", "mythical", "rugose", "upgraded"]
46
+
47
+ NAMES =
48
+ ["007", "a dead relative", "a long-lost uncle", "a dead rock star",
49
+ "Abdul Al-Azrad", "Abraham Lincoln", "Bill Gates",
50
+ "Albert Einstein", "Ali Baba", "Aladdin",
51
+ "Batman", "Blackrat", "Blackrat Prime", "Buck Rogers",
52
+ "Bullwinkle", "Captain Ahab", "Captain America", "Captain Kirk",
53
+ "Captain Nemo", "Charlie Brown", "Cthulhu", "Dilbert",
54
+ "Darth Vader", "Dave Letterman", "Uncle Bob",
55
+ "Dracula", "Elvis",
56
+ "Erik Bloodaxe", "Evil Stevie", "Fearless Leader",
57
+ "Flaming Carrot",
58
+ "George Lucas", "Gerald Ford",
59
+ "Gandhi", "Grandmother", "Gumby", "Hamlet",
60
+ "Han Solo", "Hitler", "Hulk Hogan",
61
+ "Hunter S. Thompson", "Internal Security",
62
+ "Isaac Asimov", "Jack the Ripper",
63
+ "Jimmy Carter", "Johnny-B-Gud",
64
+ "Joseph Stalin", "King Arthur", "King Tut",
65
+ "Lex Luthor", "Luke Skywalker",
66
+ "Michael Jordan", "Mick Jagger",
67
+ "Mr. Bill", "Mr. Ed", "Mr. Science",
68
+ "Mr. Spock", "Nelson Mandela", "Nixon",
69
+ "Norman Bates", "Obi-Wan Kenobi", "Oliver North",
70
+ "Paul Newman", "Perry Mason", "Princess Leia",
71
+ "Rambo", "Ringo", "Robby the Robot",
72
+ "Robert Heinlein", "Rocky", "Roger Rabbit", "Ronald Reagan",
73
+ "Scrooge", "Sir Lancelot", "Snoopy",
74
+ "Spiderman", "Squad 23", "Steve", "Steven Spielberg", "Superman",
75
+ "the A.C.L.U.", "The Computer", "the Discordian", "Sir Paul",
76
+ "the Hand", "The Illuminati", "the Joker", "the Legion of Doom",
77
+ "the ninja",
78
+ "the Secret Master",
79
+ "the Secret Service", "the vice squad", "Thor",
80
+ "Tiny Tim", "Tweety-Bird", "Uncle Duke", "Weird Al",
81
+ "Winston Churchill", "yo' mama", "your brother",
82
+ "your evil twin", "your father", "your mother", "your sister",
83
+ "Zaphod Beeblebrox", "Zeus", "Zonker", "Donovan's Brain",
84
+ "Jimmy Hoffa", "Tristero", "the Archdean", "Asmodeus",
85
+ "Archangel Gabriel", "Al-Qaeda", "Angel", "Arnold Schwarzenegger",
86
+ "Barry Bonds", "Bill Clinton", "Bill O'Reilly", "Britney Spears",
87
+ "Bud Selig", "Buffy", "Captain Archer", "Condoleeza Rice",
88
+ "Dick Cheney", "Harry Potter", "Harvey Birdman", "Hillary Clinton",
89
+ "Jacques Chirac", "Jay Leno", "Joe Montana", "John Ashcroft",
90
+ "Jon Stewart", "Karl Rove", "LeBron James", "Neo",
91
+ "Osama bin-Laden", "Peter Jackson", "President Bartlett",
92
+ "President Bush", "Saddam Hussein", "Sponge Bob Square Pants",
93
+ "T'Pol", "Tony Blair", "the American Idol", "the Bachelor",
94
+ "the Bachelorette", "the Crocodile Hunter", "the Dixie Chicks",
95
+ "the Powerpuff Girls"
96
+ ]
97
+
98
+ PLACES= ["(not available at your clearance)", "Afghanistan",
99
+ "Alpha Centauri",
100
+ "Alpha Complex", "Atlantis", "Austin", "Baghdad", "Berkeley", "Berlin",
101
+ "Buckingham Palace", "Callahan's Place", "Cheyenne Mountain",
102
+ "Chicago", "Cyberworld", "Dallas", "Death Valley", "Dime Box",
103
+ "Endsville", "Gasoline Alley", "Gotham City", "headquarters", "Hell",
104
+ "Hollywood", "Hong Kong", "Iran", "Iraq", "Israel",
105
+ "Joe's Bar and Grill", "Kabul", "Katmandu", "Lake Geneva", "Las Vegas",
106
+ "left field", "Lithuania", "London", "Los Angeles", "Main Street",
107
+ "Mars", "Middle-earth", "Mission Control", "Mordor", "Moscow",
108
+ "Munich", "my back yard", "Peking", "Poland",
109
+ "San Francisco", "Siberia", "Sixth Street", "SJ Games",
110
+ "Switzerland", "Tel Aviv", "the back forty", "the Bastille",
111
+ "the bathroom", "the best place possible", "the brewery",
112
+ "the Bat Cave", "the corner bar", "the dentists' convention",
113
+ "the doghouse", "the dumpster", "the editorial department",
114
+ "the Empire State Building", "the hackers' convention",
115
+ "the home of a trusted friend", "the Hotel California",
116
+ "the Last National Bank", "the North Pole", "the ocean",
117
+ "the outback", "the Phoenix Project", "the river",
118
+ "the same place as before", "the service station", "the South Pole",
119
+ "the Super Bowl", "the tavern", "the toxic waste dump",
120
+ "the U.S. Attorney's Office", "the Vatican", "the Watergate Hotel",
121
+ "the White House", "Toledo", "Topeka", "Uranus", "Wall Street",
122
+ "you-know-where", "your place", "Yrth", "the Death Star",
123
+ "beautiful downtown Burbank", "Smallville", "the Shire"]
124
+
125
+ PREPOSITIONS=
126
+ ["assumes responsibility for", "avoids servants of",
127
+ "deals with", "elopes with", "evades agents of", "flees from",
128
+ "flees to", "flies to", "flies toward", "goes for", "goes to",
129
+ "has finished in", "has left with", "hides in", "is attacked by",
130
+ "is commanded by", "is concerned about", "is contaminated by",
131
+ "is destroyed by", "is distressed by", "is financed by",
132
+ "is fondled by", "is found by", "is imitated by", "is infiltrated by",
133
+ "is joined by", "is like a god to", "is removed by",
134
+ "is the patron of", "is threatened by", "listens to", "makes fun of",
135
+ "may not visit", "moves to", "originates from", "reports to",
136
+ "retreats from", "returns to", "shoots henchmen of",
137
+ "should watch for", "steals from", "takes blame for",
138
+ "takes control of", "takes no notice of", "takes refuge in",
139
+ "travels to", "walks to", "was eliminated by", "was seen in",
140
+ "will go to", "withdraws from", "assumed responsibility for",
141
+ "avoided servants of", "has dealt with", "eloped with",
142
+ "evaded agents of", "fled from", "fled to", "flew to",
143
+ "flew toward", "has gone for", "went to", "hides in",
144
+ "was attacked by", "was commanded by", "was concerned about",
145
+ "was contaminated by", "was destroyed by", "was distressed by",
146
+ "was financed by", "was fondled by", "was found by",
147
+ "was imitated by", "was infiltrated by", "was joined by",
148
+ "was removed by", "was the patron of", "was threatened by",
149
+ "listened to", "made fun of", "moved to", "originated from",
150
+ "reported to", "retreated from", "returned to", "shot henchmen of",
151
+ "watched for", "stole from", "took blame for", "took control of",
152
+ "took no notice of", "took refuge in", "traveled to",
153
+ "walked to", "withdrew from", "plays with", "played with",
154
+ "is assassinated by", "was assassinated by", "is boggled by",
155
+ "was boggled by", "performs surgical alternations on"]
156
+
157
+ ACTIONS=
158
+ ["amuses", "avoids", "berates", "boggles", "bothers",
159
+ "buries", "catches", "commands", "contaminates", "controls",
160
+ "converts", "delivers", "destroys", "disfigures", "eats", "enters",
161
+ "fondles", "handles", "harasses", "hassles", "helps",
162
+ "imitates", "infiltrates", "inherits", "joins", "kills", "leaves",
163
+ "massages", "molests", "persuades", "perverts", "pitches",
164
+ "rebuilds", "reinforces", "removes", "replaces", "resurrects",
165
+ "saves", "serves", "spanks", "squeezes", "strokes", "subverts",
166
+ "swallows", "swats", "torments", "tortures", "transforms",
167
+ "whips", "teases", "stomps", "mates with", "tickles", "audits",
168
+ "beats", "defeats", "outwits", "manipulates", "defects to",
169
+ "titillates", "perverts", "defenestrates", "discards",
170
+ "abandons", "talks to", "talks back to", "allies with",
171
+ "discovers", "betrays", "assassinates", "promotes",
172
+ "pretends to be", "disguises", "disobeys", "alters",
173
+ "intimidates"]
174
+
175
+ PRONOUNS= ["his", "my", "our", "the", "your"]
176
+
177
+ INTROS=
178
+ ["4 out of 5 dentists recommend that", "Abort immediately unless",
179
+ "Abort previous sequence.", "Advance code sequence.",
180
+ "Alert all stations!", "Confirmed report:",
181
+ "Contrary to popular belief,", "Delete all evidence that",
182
+ "Determine whether", "E.F. Hutton says", "Effective immediately,",
183
+ "Enemy agents now know that", "Fnord!", "Follow plan x if",
184
+ "Ignore previous message.", "Ignore this message.", "Imperative that",
185
+ "It appears that", "It is not true that",
186
+ "Most people surveyed believe that", "Observe and report if",
187
+ "Oral Roberts dreamed that", "Our foes believe that",
188
+ "Our reporters claim that", "Pentagon officials deny that",
189
+ "Please investigate report that", "Step up operation.",
190
+ "Terminate operation if", "The surgeon general warns that",
191
+ "Unsubstantiated rumor:", "Urgent!", "Usual sources confirm that",
192
+ "Warning!", "We suspect that"]
193
+
194
+ NOUNS=
195
+ ["911 file", "(censored)", "amethyst",
196
+ "amulet", "ash tray", "baby", "BBS", "beer bottle", "blueprint",
197
+ "boat", "book", "bowling ball", "business card", "button", "cable",
198
+ "cactus", "cannibal", "capsule", "carnation", "cash", "cat",
199
+ "cauliflower", "chainsaw", "chair", "chicken", "club", "cockroach",
200
+ "code wheel", "coke can", "compact disc", "computer", "cork",
201
+ "couch", "cow", "crystal", "cummerbund",
202
+ "cyberdeck", "demon", "devil", "diamond", "dictaphone", "dictator",
203
+ "dinosaur", "disk drive", "document", "dragon", "drug", "duck",
204
+ "elephant", "engine", "eye", "file", "flag", "floppy disk",
205
+ "fly", "football", "frame", "frog", "geographer", "goldfish",
206
+ "grasshopper", "grimoire", "gyroslugger", "hammer", "hat",
207
+ "hat-rack", "helmet", "hemisphere", "hot tub", "hypodermic",
208
+ "ice cream", "ID card", "iguana", "implement", "infant", "insect",
209
+ "jellybean", "jet", "jet ski", "jukebox", "kitten", "Klingon",
210
+ "krugerrand", "kumquat", "lamp", "light bulb", "machine gun",
211
+ "mallet", "manuscript", "mason jar", "message", "mosquito",
212
+ "motorcycle", "mouse", "oar", "octopus", "olive", "ostrich",
213
+ "paddle", "paintbrush", "paper clip", "passport", "password file",
214
+ "password", "pendant", "penguin", "petunia", "phased plasma rifle",
215
+ "phone", "photocopy", "piranha", "pistol", "pit viper", "plant",
216
+ "playtester", "pop tart", "power drill", "ptarmigan", "pterodactyl",
217
+ "puppy", "pyramid", "racquetball", "radio", "railroad", "razor",
218
+ "rescuer", "ring", "rom chip", "saber", "saxophone", "scenario",
219
+ "scraper", "screwdriver", "scuba mask", "sculpture", "sex toy",
220
+ "shark", "shoggoth", "skateboard", "ski lift", "skillet",
221
+ "spark plug", "spider", "submarine", "surfboard", "sword",
222
+ "teddy bear", "telegram", "television", "tennis ball", "termite",
223
+ "textbook", "toast", "tornado", "traitor", "transmitter",
224
+ "treasure chest", "tree", "trolley", "trumpet", "typewriter",
225
+ "user's manual", "Uzi", "van", "virus", "volleyball", "wand",
226
+ "wheel", "whip", "yak", "Zulu", "INWO deck", "ukelele", "icon",
227
+ "amphibian", "toad", "terminal", "additive", "piccolo", "tuba",
228
+ "angel", "demon", "CD-ROM", "DVD", "Deep One", "Handheld", "MP3",
229
+ "Segway", "dog", "iMac", "laptop", "nanite"]
230
+
231
+ class Fnord
232
+ #Parts of speech functions to return a random word from the arrays and return it if chance==0
233
+ #or if a random integer between 0 and chance-1 equals 0. The (chance==0) check is to optimize
234
+ #by preventing the rand(chance) call when not required. So for a 1 in 7 chance call with chance=7.
235
+ def self.adjective(chance=0)
236
+ (chance==0 or rand(chance)<1) ? ADJECTIVES[rand(ADJECTIVES.length)] : ""
237
+ end
238
+
239
+ def self.name(chance=0)
240
+ (chance==0 or rand(chance)<1) ? NAMES[rand(NAMES.length)] : ""
241
+ end
242
+
243
+ def self.place(chance=0)
244
+ (chance==0 or rand(chance)<1) ? PLACES[rand(PLACES.length)] : ""
245
+ end
246
+
247
+ def self.in_place(chance=0)
248
+ (chance==0 or rand(chance)<1) ? "in #{place}" : ""
249
+ end
250
+
251
+ def self.preposition(chance=0)
252
+ (chance==0 or rand(chance)<1) ? PREPOSITIONS[rand(PREPOSITIONS.length)] : ""
253
+ end
254
+
255
+ def self.action(chance=0)
256
+ (chance==0 or rand(chance)<1) ? ACTIONS[rand(ACTIONS.length)] : ""
257
+ end
258
+
259
+ def self.pronoun(chance=0)
260
+ (chance==0 or rand(chance)<1) ? PRONOUNS[rand(PRONOUNS.length)] : ""
261
+ end
262
+
263
+ def self.intro(chance=0)
264
+ (chance==0 or rand(chance)<1) ? INTROS[rand(INTROS.length)] : ""
265
+ end
266
+
267
+ def self.noun(chance=0)
268
+ (chance==0 or rand(chance)<1) ? NOUNS[rand(NOUNS.length)] : ""
269
+ end
270
+
271
+ def self.headline
272
+ number=rand(14)
273
+ msg=case number #Return a generated Fnord as a string
274
+ when 0 then
275
+ "The #{adjective(2)} #{noun} #{in_place(5)} is #{adjective}."
276
+ when 1 then
277
+ "#{name} #{action} the #{adjective} #{noun} and the #{adjective} #{noun}."
278
+ when 2 then
279
+ "The #{noun} from #{place} will go to #{place}."
280
+ when 3 then
281
+ "#{name} must take the #{adjective} #{noun} from #{place}."
282
+ when 4 then
283
+ "#{place} is #{adjective} and the #{noun} is #{adjective}."
284
+ when 5 then
285
+ "#{name} #{preposition} #{place} for the #{adjective} #{noun}."
286
+ when 6 then
287
+ "The #{adjective(2)} #{noun} #{action} the #{adjective} #{noun} #{in_place(5)}."
288
+ when 7 then
289
+ "#{name} #{preposition} #{place} and #{action} the #{noun}."
290
+ when 8 then
291
+ "#{name} takes #{pronoun} #{adjective(2)} #{noun} and #{preposition} #{place}."
292
+ when 9 then
293
+ "#{name} #{action} the #{adjective(2)} #{noun}."
294
+ when 10 then
295
+ "#{name} #{action} #{name} and #{pronoun} #{adjective(2)} #{noun}."
296
+ when 11 then
297
+ "#{name} is the #{adjective(2)} #{noun}; #{name} #{preposition} #{place}."
298
+ when 12 then
299
+ "You must meet #{name} at #{place} and get the #{adjective(2)} #{noun}."
300
+ when 13 then
301
+ "A #{noun} from #{place} #{action} the #{adjective(2)} #{adjective(5)} #{noun}."
302
+ end
303
+ while msg.include?(" ")
304
+ msg.gsub!(/ /, " ") # Collapse multiple spaces into a single one.
305
+ end
306
+ msg.gsub!(/^ /, "") # remove space from the front
307
+ msg.gsub!(/ \./, ".") # remove space from before a "."
308
+ #Extension to allow for placing #{intro} in front of the messages, and keeping
309
+ #the case correct, if required. Not required for the original set of strings,
310
+ #so commented out to prevent unneccessary code execution.
311
+ #while msg[/([^A-Z][\.\!\?\:])\s+([a-z])/]
312
+ # msg[/([^A-Z][\.\!\?\:])\s+([a-z])/]="#{$1} #{$2.upcase}"
313
+ #end
314
+ msg[0]=msg[0, 1].upcase
315
+ msg
316
+ end
317
+ end
318
+
319
+ match /fnord/
320
+
321
+ def execute(m)
322
+ m.reply Fnord.headline
323
+ end
324
+ end
325
+
326
+ end
327
+
328
+ # AutoLoad
329
+ Bot.config.plugins.plugins.push Plugins::Fnord