zetabot 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +281 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +6 -0
- data/Zeta.gemspec +74 -0
- data/bin/console +14 -0
- data/bin/setup +13 -0
- data/bin/zeta +9 -0
- data/bin/zeta-setup +13 -0
- data/lib/Zeta.rb +13 -0
- data/lib/Zeta/access.rb +84 -0
- data/lib/Zeta/admin.rb +10 -0
- data/lib/Zeta/admin/autojoin.rb +25 -0
- data/lib/Zeta/admin/bot.rb +43 -0
- data/lib/Zeta/admin/channels.rb +36 -0
- data/lib/Zeta/admin/eval.rb +43 -0
- data/lib/Zeta/admin/fifo.rb +45 -0
- data/lib/Zeta/admin/ignore.rb +112 -0
- data/lib/Zeta/admin/oper.rb +50 -0
- data/lib/Zeta/admin/plugins.rb +109 -0
- data/lib/Zeta/admin/users.rb +5 -0
- data/lib/Zeta/blacklist.rb +25 -0
- data/lib/Zeta/cache.rb +0 -0
- data/lib/Zeta/cinch.rb +35 -0
- data/lib/Zeta/config.rb +42 -0
- data/lib/Zeta/gems.rb +0 -0
- data/lib/Zeta/locale.rb +4 -0
- data/lib/Zeta/log.rb +2 -0
- data/lib/Zeta/models.rb +5 -0
- data/lib/Zeta/models/channel.rb +3 -0
- data/lib/Zeta/models/plugin.rb +3 -0
- data/lib/Zeta/models/user.rb +3 -0
- data/lib/Zeta/plugins.rb +27 -0
- data/lib/Zeta/plugins/attack.rb +61 -0
- data/lib/Zeta/plugins/botinfo.rb +83 -0
- data/lib/Zeta/plugins/darkscience.rb +215 -0
- data/lib/Zeta/plugins/dbz.rb +31 -0
- data/lib/Zeta/plugins/dcc.rb +25 -0
- data/lib/Zeta/plugins/dnsbl.rb +36 -0
- data/lib/Zeta/plugins/echo.rb +15 -0
- data/lib/Zeta/plugins/eightball.rb +53 -0
- data/lib/Zeta/plugins/fml.rb +35 -0
- data/lib/Zeta/plugins/fnord.rb +329 -0
- data/lib/Zeta/plugins/gem.rb +0 -0
- data/lib/Zeta/plugins/gif.rb +73 -0
- data/lib/Zeta/plugins/help.rb +32 -0
- data/lib/Zeta/plugins/libsecure.rb +34 -0
- data/lib/Zeta/plugins/macros.rb +124 -0
- data/lib/Zeta/plugins/movie.rb +67 -0
- data/lib/Zeta/plugins/pdfinfo.rb +69 -0
- data/lib/Zeta/plugins/rainbow.rb +65 -0
- data/lib/Zeta/plugins/russian_roulette.rb +90 -0
- data/lib/Zeta/plugins/seen.rb +77 -0
- data/lib/Zeta/plugins/silly.rb +183 -0
- data/lib/Zeta/plugins/snooper.rb +146 -0
- data/lib/Zeta/plugins/urban.rb +60 -0
- data/lib/Zeta/plugins/weather.rb +203 -0
- data/lib/Zeta/plugins/whois.rb +25 -0
- data/lib/Zeta/plugins/wiki.rb +75 -0
- data/lib/Zeta/plugins/wolfram.rb +46 -0
- data/lib/Zeta/tasks/db.rb +0 -0
- data/lib/Zeta/version.rb +3 -0
- data/lib/generators/config/config.rb +0 -0
- data/lib/generators/plugin/new_plugin.rb +0 -0
- data/locale/en/8ball.yml +0 -0
- data/locale/en/attack.yml +148 -0
- data/locale/en/dbz.yml +10 -0
- data/locale/en/ircop.yml +5 -0
- data/locale/en/macros.yml +98 -0
- data/locale/en/meme.yml +27 -0
- 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,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
|