artaius 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,3 @@
1
+ module Artaius
2
+ VERSION = '0.2.0'
3
+ 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