artaius 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -0
- data/Gemfile +2 -0
- data/LICENSE +19 -0
- data/README.md +19 -0
- data/Rakefile +3 -0
- data/artaius.gemspec +36 -0
- data/bin/artaius +5 -0
- data/config/locales/en.yml +40 -0
- data/config/locales/ru.yml +47 -0
- data/config/plugins/.gitignore +1 -0
- data/db/.gitignore +1 -0
- data/db/migrations/001_create_players.rb +35 -0
- data/lib/artaius.rb +16 -0
- data/lib/artaius/bot.rb +50 -0
- data/lib/artaius/database.rb +36 -0
- data/lib/artaius/models/player.rb +16 -0
- data/lib/artaius/plugins/archivarius.rb +62 -0
- data/lib/artaius/plugins/identify.rb +56 -0
- data/lib/artaius/plugins/mixer.rb +335 -0
- data/lib/artaius/version.rb +3 -0
- data/spec/lib/artaius/bot_spec.rb +54 -0
- data/spec/lib/artaius/plugins/archivarius_spec.rb +59 -0
- data/spec/lib/artaius/plugins/identify_spec.rb +94 -0
- data/spec/lib/artaius/plugins/mixer_spec.rb +199 -0
- data/spec/lib/artaius/version_spec.rb +0 -0
- data/spec/spec_helper.rb +7 -0
- data/tasks/db.rake +15 -0
- data/tasks/environment.rake +3 -0
- data/tasks/test.rake +6 -0
- metadata +213 -0
@@ -0,0 +1,335 @@
|
|
1
|
+
module Artaius
|
2
|
+
module Plugins
|
3
|
+
# The plugins allows to create game mixes in IRC.
|
4
|
+
class Mixer
|
5
|
+
include Cinch::Plugin
|
6
|
+
|
7
|
+
# Internal: Create a new game.
|
8
|
+
#
|
9
|
+
# players - The Enumerable of players (Set or Array).
|
10
|
+
# limit - The Integer, describes the needed quantity of players, in
|
11
|
+
# order to start the game.
|
12
|
+
# time - The Time, when the game was created.
|
13
|
+
#
|
14
|
+
# Returns Game Struct object.
|
15
|
+
Game = Struct.new(:players, :limit, :time)
|
16
|
+
|
17
|
+
# Internal: Create a new gamer. Gamer is a player, which wants to play a
|
18
|
+
# mix.
|
19
|
+
#
|
20
|
+
# irc_nick - The String, representing gamer's IRC nickname.
|
21
|
+
# irc_authname - The String, representing gamer's IRC authname.
|
22
|
+
# role - The Integer, representing KAG player's role
|
23
|
+
#
|
24
|
+
# Returns Gamer object.
|
25
|
+
Gamer = Struct.new(:irc_nick, :irc_authname, :premium?, :role)
|
26
|
+
|
27
|
+
# Internal: Limit to be used, when the op didn't specify the number of
|
28
|
+
# players in the mix.
|
29
|
+
DEFAULT_LIMIT = 10
|
30
|
+
|
31
|
+
# Internal: Minimal number of slots needed to be able to play the game.
|
32
|
+
MIN_SLOTS = 2
|
33
|
+
|
34
|
+
# Internal: Delay between the beginning of game and its ending (in
|
35
|
+
# seconds).
|
36
|
+
PENDING_DELAY = 300
|
37
|
+
|
38
|
+
|
39
|
+
set react_on: :channel
|
40
|
+
|
41
|
+
match /#{I18n.mixer.m.game}(\s([2-9]|[1-9][0-9]))?$/,
|
42
|
+
method: :start_game,
|
43
|
+
use_suffix: false
|
44
|
+
|
45
|
+
# Internal: Create new game and add the creator to that game, so he/she
|
46
|
+
# will be the first player in that game.
|
47
|
+
#
|
48
|
+
# m - The recieved Message.
|
49
|
+
# limit - The Integer, which sets the limit of the players in the mix.
|
50
|
+
#
|
51
|
+
# Returns nothing.
|
52
|
+
def start_game(m, limit)
|
53
|
+
return if @game or !Player.exists?(m.user.authname)
|
54
|
+
|
55
|
+
@limit = if limit && !limit.empty?
|
56
|
+
limit.to_i
|
57
|
+
else
|
58
|
+
DEFAULT_LIMIT
|
59
|
+
end
|
60
|
+
|
61
|
+
@game = Game.new([], limit, Time.now)
|
62
|
+
@initiator = create_gamer(m)
|
63
|
+
add_player(m)
|
64
|
+
end
|
65
|
+
|
66
|
+
match /#{I18n.mixer.m.play}$/,
|
67
|
+
method: :add_player,
|
68
|
+
use_suffix: false
|
69
|
+
|
70
|
+
# Internal: Add a new player to the game.
|
71
|
+
#
|
72
|
+
# m - The recieved Message.
|
73
|
+
#
|
74
|
+
# Returns nothing.
|
75
|
+
def add_player(m)
|
76
|
+
return if !@game or !Player.exists?(m.user.authname)
|
77
|
+
|
78
|
+
unless @game.players.map(&:irc_authname).include?(m.user.authname)
|
79
|
+
@game.players << create_gamer(m)
|
80
|
+
|
81
|
+
need_players = @limit - @game.players.size
|
82
|
+
|
83
|
+
if ready_to_begin?
|
84
|
+
each_team { |blue, red| begin_game!(m, blue, red) }
|
85
|
+
else
|
86
|
+
m.reply I18n.mixer.players(show_players)
|
87
|
+
m.reply I18n.mixer.need_players(need_players)
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
@timer.stop if @timer
|
93
|
+
|
94
|
+
@timer = Timer(PENDING_DELAY, :shots => 1) do
|
95
|
+
@game = nil
|
96
|
+
Channel(m.channel.name).send I18n.mixer.game_cancelled
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
match /#{I18n.mixer.m.cancel}$/,
|
101
|
+
method: :cancel,
|
102
|
+
use_suffix: false
|
103
|
+
|
104
|
+
# Internal: Remove the user from the game. If the user is the last user in
|
105
|
+
# the game, automatically revoke that game.
|
106
|
+
#
|
107
|
+
# m - The recieved Message.
|
108
|
+
#
|
109
|
+
# Returns nothing.
|
110
|
+
def cancel(m)
|
111
|
+
player = @game.players.find { |p| p.irc_authname == m.user.authname}
|
112
|
+
@game.players.delete(player)
|
113
|
+
|
114
|
+
@initiator = @game.players[0]
|
115
|
+
m.reply I18n.mixer.cancel(m.user.nick)
|
116
|
+
|
117
|
+
unless @initiator
|
118
|
+
@timer.stop
|
119
|
+
@game = nil
|
120
|
+
m.reply I18n.mixer.last_left
|
121
|
+
else
|
122
|
+
m.reply I18n.mixer.new_initiator(@initiator.irc_nick)
|
123
|
+
m.reply show_players
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
match /#{I18n.mixer.m.roster}$/,
|
128
|
+
method: :roster,
|
129
|
+
use_suffix: false
|
130
|
+
|
131
|
+
# Internal: Send message about current roster in the mix, if there is any.
|
132
|
+
#
|
133
|
+
# m - The recieved Message.
|
134
|
+
#
|
135
|
+
# Returns nothing.
|
136
|
+
def roster(m)
|
137
|
+
return unless @game
|
138
|
+
|
139
|
+
m.reply I18n.mixer.roster(show_players)
|
140
|
+
end
|
141
|
+
|
142
|
+
match /#{I18n.mixer.m.start}$/,
|
143
|
+
method: :force_start,
|
144
|
+
use_suffix: false
|
145
|
+
|
146
|
+
# Internal: Start the game by all means.
|
147
|
+
#
|
148
|
+
# m - The recieved Message.
|
149
|
+
#
|
150
|
+
# Returns nothing.
|
151
|
+
def force_start(m)
|
152
|
+
return unless @game && m.user.authname == @initiator.irc_authname
|
153
|
+
|
154
|
+
each_team { |blue, red| begin_game!(m, blue, red) }
|
155
|
+
end
|
156
|
+
|
157
|
+
match /#{I18n.mixer.m.slot}(\+|-)(\s([2-9]|[1-9][0-9]))?$/,
|
158
|
+
method: :slot_dispatcher,
|
159
|
+
use_suffix: false
|
160
|
+
|
161
|
+
# Internal: Add or remove slot from the current game.
|
162
|
+
#
|
163
|
+
# m - The recieved Message.
|
164
|
+
# sign - The + or - sign, indicates adding on removing a slot
|
165
|
+
# respectively.
|
166
|
+
# slots - The Integer, reperesenting number of slots to be added or
|
167
|
+
# removed from the game.
|
168
|
+
#
|
169
|
+
def slot_dispatcher(m, sign, slots)
|
170
|
+
return unless @game && m.user.authname == @initiator.irc_authname
|
171
|
+
|
172
|
+
case sign
|
173
|
+
when '+'
|
174
|
+
|
175
|
+
if slots
|
176
|
+
slots.to_i.times { add_slot }
|
177
|
+
m.reply I18n.mixer.n_slots_added(slots, slots_message)
|
178
|
+
else
|
179
|
+
if @limit >= MIN_SLOTS
|
180
|
+
add_slot
|
181
|
+
m.reply I18n.mixer.slot_added(slots_message)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
when '-'
|
186
|
+
|
187
|
+
if slots
|
188
|
+
removed_slots = 0
|
189
|
+
slots.to_i.times { |i|
|
190
|
+
remove_slot
|
191
|
+
removed_slots = i+1
|
192
|
+
break unless @limit > MIN_SLOTS
|
193
|
+
}
|
194
|
+
m.reply I18n.mixer.n_slots_removed(removed_slots, slots_message)
|
195
|
+
else
|
196
|
+
if @limit > MIN_SLOTS
|
197
|
+
remove_slot
|
198
|
+
m.reply I18n.mixer.slot_removed(slots_message)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
|
204
|
+
if ready_to_begin?
|
205
|
+
each_team { |blue, red| begin_game!(m, blue, red) }
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
match /#{I18n.mixer.m.slots}$/,
|
210
|
+
method: :slots,
|
211
|
+
use_suffix: false
|
212
|
+
|
213
|
+
# Internal: Display information about slots of the current game.
|
214
|
+
#
|
215
|
+
# m - The recieved Message.
|
216
|
+
#
|
217
|
+
# Returns nothing.
|
218
|
+
def slots(m)
|
219
|
+
return unless @game
|
220
|
+
|
221
|
+
m.reply I18n.mixer.slot_stats(@game.players.size, @limit)
|
222
|
+
end
|
223
|
+
|
224
|
+
protected
|
225
|
+
|
226
|
+
# Internal: Show all players in the game. Colorize some nicks.
|
227
|
+
#
|
228
|
+
# Returns nothing.
|
229
|
+
def show_players
|
230
|
+
@game.players.map do |gamer|
|
231
|
+
colorize_nick(gamer)
|
232
|
+
end.join ', '
|
233
|
+
end
|
234
|
+
|
235
|
+
# Internal: Colorize the nick of given gamer. Based on role of the gamer.
|
236
|
+
# Golds are yellow, guards are green and normal are untouched.
|
237
|
+
#
|
238
|
+
# nick - The Gamer, which nick should be colorized.
|
239
|
+
#
|
240
|
+
# Returns colorized nick.
|
241
|
+
def colorize_nick(gamer)
|
242
|
+
if gamer[:premium?]
|
243
|
+
case gamer.role
|
244
|
+
when 2
|
245
|
+
Format(:green, gamer.irc_nick)
|
246
|
+
else
|
247
|
+
Format(:yellow, gamer.irc_nick)
|
248
|
+
end
|
249
|
+
else
|
250
|
+
gamer.irc_nick
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
# Internal: Iterate over each team.
|
255
|
+
#
|
256
|
+
# Yields the Array of the Red team and the Array of the Blue team
|
257
|
+
# respectively.
|
258
|
+
#
|
259
|
+
# Returns nothing.
|
260
|
+
def each_team
|
261
|
+
players = @game.players.shuffle
|
262
|
+
|
263
|
+
blue = players.pop(@limit / 2)
|
264
|
+
red = players
|
265
|
+
|
266
|
+
yield blue, red
|
267
|
+
end
|
268
|
+
|
269
|
+
# Internal: Send messages with team rosters and destroy game object.
|
270
|
+
#
|
271
|
+
# m - The recieved Message.
|
272
|
+
# blue - The Array of Blue team.
|
273
|
+
# red - The Array of Red team.
|
274
|
+
#
|
275
|
+
# Returns nil.
|
276
|
+
def begin_game!(m, blue, red)
|
277
|
+
@timer.stop
|
278
|
+
|
279
|
+
blue = blue.map { |gamer| colorize_nick(gamer) }.join(', ')
|
280
|
+
red = red.map { |gamer| colorize_nick(gamer) }.join(', ')
|
281
|
+
|
282
|
+
m.reply I18n.mixer.blue_team(blue)
|
283
|
+
m.reply I18n.mixer.red_team(red)
|
284
|
+
m.reply I18n.mixer.glhf
|
285
|
+
|
286
|
+
@game = nil
|
287
|
+
end
|
288
|
+
|
289
|
+
# Internal: Display slots used/overall number information.
|
290
|
+
#
|
291
|
+
# Returns String.
|
292
|
+
def slots_message
|
293
|
+
I18n.mixer.slots_overall(@limit)
|
294
|
+
end
|
295
|
+
|
296
|
+
# Internal: Increments game slot.
|
297
|
+
#
|
298
|
+
# Returns incremented Integer, representing limit.
|
299
|
+
def add_slot
|
300
|
+
@limit += 1
|
301
|
+
end
|
302
|
+
|
303
|
+
# Internal: Decrements game slot.
|
304
|
+
#
|
305
|
+
# Returns decremented Integer, representing limit.
|
306
|
+
def remove_slot
|
307
|
+
@limit -= 1
|
308
|
+
end
|
309
|
+
|
310
|
+
# Internal: Check if the quantity of players reached the limit. If so,
|
311
|
+
# that means, we can say "Let's get ready to rumble!".
|
312
|
+
#
|
313
|
+
# Returns true if the quantity of players, that are in game, equals to the
|
314
|
+
# slot limit or false otherwise.
|
315
|
+
def ready_to_begin?
|
316
|
+
@game.players.size == @limit
|
317
|
+
end
|
318
|
+
|
319
|
+
# Internal: Create a new gamer. Gamers are persons, that want to play mix.
|
320
|
+
#
|
321
|
+
# Returns Gamer object.
|
322
|
+
def create_gamer(m)
|
323
|
+
player = Player.filter(:irc_authname => m.user.authname).first
|
324
|
+
|
325
|
+
Gamer.new(
|
326
|
+
m.user.nick,
|
327
|
+
m.user.authname,
|
328
|
+
player[:premium],
|
329
|
+
player[:role]
|
330
|
+
)
|
331
|
+
end
|
332
|
+
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe Artaius::Bot do
|
4
|
+
let(:bot) { Artaius::Bot.new }
|
5
|
+
|
6
|
+
describe 'bot IRC configuration' do
|
7
|
+
|
8
|
+
it 'must have correct nick' do
|
9
|
+
bot.config.nick.must_equal 'Artaius'
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'must have correct realname' do
|
13
|
+
bot.config.realname.must_equal 'Artaius Lucius'
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'must have correct username' do
|
17
|
+
bot.config.user.must_equal 'Artaius Lucius'
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'must have correct server to join' do
|
21
|
+
bot.config.server.must_equal 'irc.quakenet.org'
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'must have correct port of a server' do
|
25
|
+
bot.config.port.must_equal 6667
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'must have correct channels to join' do
|
29
|
+
bot.config.channels.must_equal %w{ #kag2d.ru }
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'plugins' do
|
33
|
+
|
34
|
+
describe 'identify plugin' do
|
35
|
+
it 'must contain identify' do
|
36
|
+
bot.config.plugins.plugins.must_include Artaius::Plugins::Identify
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'must have correct username option' do
|
40
|
+
bot.config.plugins
|
41
|
+
.options[Artaius::Plugins::Identify][:username].must_equal 'Artaius'
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'must have password option' do
|
45
|
+
bot.config.plugins
|
46
|
+
.options[Artaius::Plugins::Identify][:password]
|
47
|
+
.must_be_instance_of String
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end # plugins
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative '../../../spec_helper'
|
2
|
+
|
3
|
+
describe Artaius::Plugins::Archivarius do
|
4
|
+
|
5
|
+
Archivarius = Artaius::Plugins::Archivarius
|
6
|
+
|
7
|
+
it 'must include required modules' do
|
8
|
+
Archivarius.must_include Cinch::Plugin
|
9
|
+
end
|
10
|
+
|
11
|
+
it "must use correct plugin's name" do
|
12
|
+
Archivarius.plugin_name.must_equal 'archivarius'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'must react on private messages' do
|
16
|
+
Archivarius.react_on.must_equal :private
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'matchers' do
|
20
|
+
let(:reg) { Archivarius.matchers.find { |m| m.method == :sign_up } }
|
21
|
+
|
22
|
+
it 'must have correct number of matchers' do
|
23
|
+
Archivarius.matchers.size.must_equal 1
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'reg matcher' do
|
27
|
+
it 'must exist' do
|
28
|
+
reg.wont_be_nil
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'must match the pattern' do
|
32
|
+
reg.pattern.must_match 'reg lol'
|
33
|
+
reg.pattern.must_match 'reg nick'
|
34
|
+
reg.pattern.must_match 'reg nickname'
|
35
|
+
reg.pattern.must_match 'reg awesomenick'
|
36
|
+
reg.pattern.must_match 'reg 10nicks'
|
37
|
+
reg.pattern.must_match 'reg nicks10'
|
38
|
+
reg.pattern.must_match 'reg ni10cks'
|
39
|
+
reg.pattern.must_match 'reg yadda_yadda'
|
40
|
+
reg.pattern.must_match 'reg IaMiDiOt'
|
41
|
+
|
42
|
+
reg.pattern.wont_match 'reg blah'
|
43
|
+
reg.pattern.wont_match 'reg me'
|
44
|
+
reg.pattern.wont_match 'reg i'
|
45
|
+
reg.pattern.wont_match 'reg averylongnicknamereally'
|
46
|
+
reg.pattern.wont_match 'reg supernick '
|
47
|
+
reg.pattern.wont_match 'reg fancy 10'
|
48
|
+
reg.pattern.wont_match 'reg ps[E]udo_player'
|
49
|
+
reg.pattern.wont_match "reg don'ttellmymother"
|
50
|
+
reg.pattern.wont_match 'reg yadda-yadda'
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'does not have suffix' do
|
54
|
+
reg.suffix.must_be_nil
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|