kag-gather 1.3.4 → 1.3.5

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.
@@ -0,0 +1,159 @@
1
+ require 'cinch'
2
+ require 'symboltable'
3
+ require 'kag/config'
4
+ require 'kag/gather/team'
5
+
6
+ module KAG
7
+ module Gather
8
+ class Match < SymbolTable
9
+ def self.type_as_string
10
+ ms = KAG::Config.instance[:match_size].to_i
11
+ ts = (ms / 2).ceil
12
+ "#{ts.to_s}v#{ts.to_s} #{KAG::Config.instance[:match_type]}"
13
+ end
14
+
15
+ def setup_teams
16
+ self[:players].shuffle!
17
+ match_size = KAG::Config.instance[:match_size].to_i
18
+ match_size = 2 if match_size < 2
19
+
20
+ lb = (match_size / 2).ceil.to_i
21
+ lb = 1 if lb < 1
22
+
23
+ debug "MATCH SIZE #{match_size.to_s}"
24
+ debug "LOWER BOUND: #{lb.to_s}"
25
+ debug "PLAYERS: #{self[:players].join(",")}"
26
+
27
+ self[:teams] = []
28
+ self[:teams] << KAG::Gather::Team.new({
29
+ :players => self[:players].slice(0,lb),
30
+ :match => self,
31
+ :color => "\x0312",
32
+ :name => "Blue"
33
+ }).setup
34
+ self[:teams] << KAG::Gather::Team.new({
35
+ :players => self[:players].slice(lb,match_size),
36
+ :match => self,
37
+ :color => "\x0304",
38
+ :name => "Red"
39
+ }).setup
40
+ self[:teams]
41
+ end
42
+
43
+ def start
44
+ self[:end_votes] = 0 unless self[:end_votes]
45
+ self[:subs_needed] = []
46
+ setup_teams
47
+ restart_map
48
+ end
49
+
50
+ def text_for_match_start
51
+ msg = "MATCH: #{KAG::Gather::Match.type_as_string} - "
52
+ self[:teams].each do |team|
53
+ msg = msg+" "+team.text_for_match_start
54
+ end
55
+ msg+" \x0301(!end when done)"
56
+ end
57
+
58
+ def notify_teams_of_match_start
59
+ messages = {}
60
+ self[:teams].each do |t|
61
+ ms = t.notify_of_match_start
62
+ ms.each do |nick,msg|
63
+ messages[nick] = msg
64
+ end
65
+ end
66
+ messages
67
+ end
68
+
69
+ def add_end_vote
70
+ self[:end_votes] = 0 unless self[:end_votes] > 0
71
+ self[:end_votes] = self[:end_votes] + 1
72
+ end
73
+
74
+ def voted_to_end?
75
+ evt = KAG::Config.instance[:end_vote_threshold].to_i
76
+ evt = 3 if evt < 1
77
+ self[:end_votes] >= evt
78
+ end
79
+
80
+ def get_needed_end_votes_left
81
+ evt = KAG::Config.instance[:end_vote_threshold].to_i
82
+ evt - self[:end_votes]
83
+ end
84
+
85
+ def has_player?(nick)
86
+ playing = false
87
+ self[:teams].each do |team|
88
+ playing = true if team.has_player?(nick)
89
+ end
90
+ playing
91
+ end
92
+
93
+ def cease
94
+ if self.server
95
+ if self.server.has_rcon?
96
+ self[:teams].each do |team|
97
+ team.kick_all
98
+ end
99
+ else
100
+ debug "NO RCON, so could not kick!"
101
+ end
102
+ self.server.disconnect
103
+ self.server.delete(:match)
104
+ true
105
+ else
106
+ debug "No server for match defined!"
107
+ false
108
+ end
109
+ end
110
+
111
+ def restart_map
112
+ if self.server.has_rcon?
113
+ self.server.restart_map
114
+ else
115
+ debug "Cannot restart map, no RCON defined"
116
+ end
117
+ end
118
+
119
+ def remove_player(nick)
120
+ sub = false
121
+ self[:teams].each do |team|
122
+ if team.has_player?(nick)
123
+ sub = team.remove_player(nick)
124
+ end
125
+ end
126
+ if sub
127
+ self[:subs_needed] << sub
128
+ end
129
+ sub
130
+ end
131
+
132
+ def needs_sub?
133
+ self[:subs_needed].length > 0
134
+ end
135
+
136
+ def sub_in(nick)
137
+ placement = false
138
+ if needs_sub?
139
+ placement = self[:subs_needed].shift
140
+ end
141
+ placement
142
+ end
143
+
144
+ def rename_player(last_nick,new_nick)
145
+ self[:teams].each do |team|
146
+ if team.has_player?(last_nick)
147
+ team.rename_player(last_nick,new_nick)
148
+ end
149
+ end
150
+ end
151
+
152
+ def debug(msg)
153
+ if KAG::Config.instance[:debug]
154
+ puts msg
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,354 @@
1
+ require 'cinch'
2
+ require 'kag/common'
3
+ require 'commands/help'
4
+ require 'kag/bot/bot'
5
+ require 'kag/bans/report'
6
+ require 'kag/server'
7
+ require 'kag/gather/match'
8
+
9
+ module KAG
10
+ module Gather
11
+ class Plugin
12
+ include Cinch::Plugin
13
+ include Cinch::Commands
14
+ include KAG::Common
15
+
16
+ attr_accessor :queue,:servers
17
+
18
+ def initialize(*args)
19
+ super
20
+ @queue = {}
21
+ @matches = {}
22
+ _load_servers
23
+ end
24
+
25
+ def _load_servers
26
+ @servers = {}
27
+ KAG::Config.instance[:servers].each do |k,s|
28
+ s[:key] = k
29
+ @servers[k] = KAG::Server.new(s)
30
+ end
31
+ end
32
+
33
+ #listen_to :channel, method: :channel_listen
34
+ #def channel_listen(m)
35
+ #end
36
+
37
+ listen_to :leaving, :method => :on_leaving
38
+ def on_leaving(m,nick)
39
+ unless is_banned?(m.user)
40
+ nick = nick.to_s
41
+ match = get_match_in(nick)
42
+ if match
43
+ sub = match.remove_player(nick)
44
+ if sub
45
+ m.channel.msg sub[:msg]
46
+ end
47
+ elsif @queue.key?(nick)
48
+ remove_user_from_queue(nick)
49
+ end
50
+ end
51
+ end
52
+
53
+ listen_to :nick, :method => :on_nick
54
+ def on_nick(m)
55
+ unless is_banned?(m.user)
56
+ match = get_match_in(m.user.last_nick)
57
+ if match
58
+ match.rename_player(m.user.last_nick,m.user.nick)
59
+ elsif @queue.key?(m.user.last_nick)
60
+ @queue[m.user.nick] = @queue[m.user.last_nick]
61
+ @queue.delete(m.user.last_nick)
62
+ end
63
+ end
64
+ end
65
+
66
+ match "sub", :method => :evt_sub
67
+ def evt_sub(m)
68
+ unless is_banned?(m.user)
69
+ @matches.each do |k,match|
70
+ if match.needs_sub?
71
+ placement = match.sub_in(m.user.nick)
72
+ if placement
73
+ reply m,placement[:channel_msg]
74
+ User(m.user.nick).send placement[:private_msg]
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ command :add,{},
82
+ summary: "Add yourself to the active queue for the next match"
83
+ def add(m)
84
+ unless is_banned?(m.user)
85
+ add_user_to_queue(m,m.user.nick)
86
+ end
87
+ end
88
+
89
+ command :rem,{},
90
+ summary: "Remove yourself from the active queue for the next match"
91
+ def rem(m)
92
+ unless is_banned?(m.user)
93
+ match = get_match_in(m.user.nick)
94
+ if match
95
+ match.remove_player(m.user.nick)
96
+ send_channels_msg "#{m.user.nick} has left the match at #{match.server[:key]}! You can sub in by typing !sub"
97
+ elsif @queue.key?(m.user.nick)
98
+ unless remove_user_from_queue(m.user.nick)
99
+ debug "#{nick} is not in the queue."
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+ command :list,{},
106
+ summary: "List the users signed up for the next match"
107
+ def list(m)
108
+ unless is_banned?(m.user)
109
+ users = []
110
+ @queue.each do |n,u|
111
+ users << n
112
+ end
113
+ m.user.send "Queue (#{KAG::Gather::Match.type_as_string}) [#{@queue.length}] #{users.join(", ")}"
114
+ end
115
+ end
116
+
117
+ command :status,{},
118
+ summary: "Show the number of ongoing matches"
119
+ def status(m)
120
+ unless is_banned?(m.user)
121
+ reply m,"Matches in progress: #{@matches.length.to_s}"
122
+ end
123
+ end
124
+
125
+ command :end,{},
126
+ summary: "End the current match",
127
+ description: "End the current match. This will only work if you are in the match. After !end is called by 3 different players, the match will end."
128
+ def end(m)
129
+ unless is_banned?(m.user)
130
+ match = get_match_in(m.user.nick)
131
+ if match
132
+ match.add_end_vote
133
+ if match.voted_to_end?
134
+ match.cease
135
+ @matches.delete(match.server[:key])
136
+ send_channels_msg("Match at #{match.server[:key]} finished!")
137
+ else
138
+ reply m,"End vote started, #{match.get_needed_end_votes_left} more votes to end match at #{match.server[:key]}"
139
+ end
140
+ else
141
+ reply m,"You're not in a match, silly! Stop trying to hack me."
142
+ end
143
+ end
144
+ end
145
+
146
+ def add_user_to_queue(m,nick,send_msg = true)
147
+ if @queue.key?(nick)
148
+ reply m,"#{nick} is already in the queue!"
149
+ elsif get_match_in(nick)
150
+ reply m,"#{nick} is already in a match!"
151
+ else
152
+ @queue[nick] = SymbolTable.new({
153
+ :user => User(nick),
154
+ :irc => m.channel,
155
+ :message => m.message,
156
+ :joined_at => Time.now
157
+ })
158
+ send_channels_msg "Added #{nick} to queue (#{KAG::Gather::Match.type_as_string}) [#{@queue.length}]" if send_msg
159
+ check_for_new_match
160
+ end
161
+ end
162
+
163
+ def remove_user_from_queue(nick,send_msg = true)
164
+ if @queue.key?(nick)
165
+ @queue.delete(nick)
166
+ send_channels_msg "Removed #{nick} from queue (#{KAG::Gather::Match.type_as_string}) [#{@queue.length}]" if send_msg
167
+ true
168
+ else
169
+ false
170
+ end
171
+ end
172
+
173
+ def get_match_in(nick)
174
+ m = false
175
+ @matches.each do |k,match|
176
+ if match.has_player?(nick)
177
+ m = match
178
+ end
179
+ end
180
+ m
181
+ end
182
+
183
+ def check_for_new_match
184
+ if @queue.length >= KAG::Config.instance[:match_size]
185
+ players = []
186
+ @queue.each do |n,i|
187
+ players << n
188
+ end
189
+
190
+ server = get_unused_server
191
+ unless server
192
+ send_channels_msg "Could not find any available servers!"
193
+ debug "FAILED TO FIND UNUSED SERVER"
194
+ return false
195
+ end
196
+
197
+ # reset queue first to prevent 11-player load
198
+ @queue = {}
199
+
200
+ match = KAG::Gather::Match.new(SymbolTable.new({
201
+ :server => server,
202
+ :players => players
203
+ }))
204
+ match.start # prepare match data
205
+ messages = match.notify_teams_of_match_start # gather texts for private messages
206
+ send_channels_msg(match.text_for_match_start,false) # send channel-wide first
207
+ messages.each do |nick,msg|
208
+ User(nick.to_s).send(msg) unless nick.to_s.include?("player")
209
+ sleep(2) # prevent excess flood stuff
210
+ end
211
+ @matches[server[:key]] = match
212
+ end
213
+ end
214
+
215
+ def get_unused_server
216
+ server = false
217
+ @servers.shuffle!
218
+ @servers.each do |k,s|
219
+ server = s unless s.in_use?
220
+ end
221
+ server
222
+ end
223
+
224
+ # admin methods
225
+
226
+ command :clear,{},
227
+ summary: "Clear (empty) the ongoing queue",
228
+ admin: true
229
+ def clear(m)
230
+ if is_admin(m.user)
231
+ send_channels_msg "Match queue cleared."
232
+ @queue = {}
233
+ end
234
+ end
235
+
236
+ command :rem,{nick: :string},
237
+ summary: "Remove a specific user from the queue",
238
+ method: :rem_admin,
239
+ admin: true
240
+ def rem_admin(m, arg)
241
+ if is_admin(m.user)
242
+ arg = arg.split(" ")
243
+ arg.each do |nick|
244
+ remove_user_from_queue(nick)
245
+ end
246
+ end
247
+ end
248
+
249
+ command :rem_silent,{nick: :string},
250
+ summary: "Remove a specific user from the queue without pinging the user in the channel",
251
+ admin: true
252
+ def rem_silent(m, arg)
253
+ if is_admin(m.user)
254
+ arg = arg.split(" ")
255
+ arg.each do |nick|
256
+ remove_user_from_queue(nick,false)
257
+ end
258
+ end
259
+ end
260
+
261
+ command :add,{nick: :string},
262
+ summary: "Add a specific user to the queue",
263
+ method: :add_admin,
264
+ admin: true
265
+ def add_admin(m, arg)
266
+ if is_admin(m.user)
267
+ arg = arg.split(" ")
268
+ arg.each do |nick|
269
+ add_user_to_queue(m,nick)
270
+ end
271
+ end
272
+ end
273
+
274
+ command :add_silent,{nick: :string},
275
+ summary: "Add a specific user to the queue without pinging the user in the channel",
276
+ admin: true
277
+ def add_silent(m, arg)
278
+ if is_admin(m.user)
279
+ arg = arg.split(" ")
280
+ arg.each do |nick|
281
+ add_user_to_queue(m,nick,false)
282
+ end
283
+ end
284
+ end
285
+
286
+ command :restart_map,{},
287
+ summary: "Restart the map of the match you are in",
288
+ admin: true
289
+ def restart_map(m)
290
+ if is_admin(m.user)
291
+ match = get_match_in(m.user.nick)
292
+ if match and match.server
293
+ match.server.restart_map
294
+ end
295
+ end
296
+ end
297
+
298
+ command :restart_map,{server: :string},
299
+ summary: "Restart the map of a given server",
300
+ method: :restart_map_specify,
301
+ admin: true
302
+ def restart_map_specify(m,server)
303
+ if is_admin(m.user)
304
+ if @servers[server.to_sym]
305
+ @servers[server.to_sym].restart_map
306
+ else
307
+ m.reply "No server found with key #{server.to_s}"
308
+ end
309
+ end
310
+ end
311
+
312
+ command :restart_map,{},
313
+ summary: "Next map the match of the server you are in",
314
+ admin: true
315
+ def next_map(m)
316
+ if is_admin(m.user)
317
+ match = get_match_in(m.user.nick)
318
+ if match and match.server
319
+ match.server.next_map
320
+ end
321
+ end
322
+ end
323
+
324
+ command :next_map,{server: :string},
325
+ summary: "Next map a given server",
326
+ method: :next_map_specify,
327
+ admin: true
328
+ def next_map_specify(m,arg)
329
+ if is_admin(m.user)
330
+ if @servers[key]
331
+ @servers[key].next_map
332
+ else
333
+ m.reply "No server found with key #{arg}"
334
+ end
335
+ end
336
+ end
337
+
338
+ command :kick_from_match,{nick: :string},
339
+ summary: "Actually kick a user from a match",
340
+ admin: true
341
+ def kick_from_match(m,nick)
342
+ if is_admin(m.user)
343
+ match = get_match_in(nick)
344
+ if match
345
+ match.remove_player(nick)
346
+ m.reply "#{nick} has been kicked from the match"
347
+ else
348
+ m.reply "#{nick} is not in a match!"
349
+ end
350
+ end
351
+ end
352
+ end
353
+ end
354
+ end
@@ -0,0 +1,84 @@
1
+ require 'cinch'
2
+ require 'cinch/user'
3
+ require 'symboltable'
4
+ require 'kag/config'
5
+
6
+ module KAG
7
+ module Gather
8
+ class Team < SymbolTable
9
+
10
+ def setup
11
+ setup_classes
12
+ self
13
+ end
14
+
15
+ def setup_classes
16
+ classes = KAG::Config.instance[:classes].clone
17
+ classes.shuffle!
18
+ players = self[:players].clone
19
+ self[:players] = {}
20
+ players.each do |p|
21
+ self[:players][p.to_sym] = classes.shift
22
+ end
23
+ self
24
+ end
25
+
26
+ def notify_of_match_start
27
+ server = self.match.server
28
+ msg = "Join \x0305#{server[:key]} - #{server[:ip]}:#{server[:port]} \x0306password #{server[:password]}\x0301 | Visit kag://#{server[:ip]}/#{server[:password]} | "
29
+ msg = msg + " \x0303Class: " if KAG::Config.instance[:pick_classes]
30
+
31
+ messages = {}
32
+ self[:players].each do |nick,cls|
33
+ player_msg = msg.clone
34
+ player_msg = player_msg+cls if KAG::Config.instance[:pick_classes] and cls and !cls.empty?
35
+ player_msg = player_msg+" #{self[:color]}#{self[:name]} with: #{self[:players].keys.join(", ")}"
36
+ messages[nick] = player_msg
37
+ end
38
+ messages
39
+ end
40
+
41
+ def text_for_match_start
42
+ "#{self[:color]}#{self[:players].keys.join(", ")} (#{self[:name]})"
43
+ end
44
+
45
+ def has_player?(nick)
46
+ self[:players].keys.include?(nick.to_sym)
47
+ end
48
+
49
+ def rename_player(last_nick,new_nick)
50
+ if has_player?(nick)
51
+ cls = self[:players][last_nick.to_sym]
52
+ self[:players].delete(last_nick.to_sym)
53
+ self[:players][new_nick.to_sym] = cls
54
+ end
55
+ end
56
+
57
+ def remove_player(nick)
58
+ if has_player?(nick)
59
+ sub = {}
60
+ sub[:cls] = self[:players][nick]
61
+ sub[:team] = self.clone
62
+ sub[:msg] = "Sub needed at #{self.match.server[:ip]} for #{sub[:team][:name]}, #{sub[:cls]} Class! Type !sub to claim it!"
63
+ sub[:channel_msg] = "#{nick} is now subbing in for #{self[:name]} at #{self.match.server[:key]}. Subs still needed: #{self.match[:subs_needed].length}"
64
+ sub[:private_msg] = "Please #{self.match.server.text_join} | #{sub[:cls]} on the #{self[:name]} Team"
65
+ self[:players].delete(nick)
66
+
67
+ if self.match and self.match.server
68
+ self.match.server.kick(nick)
69
+ end
70
+
71
+ sub
72
+ else
73
+ false
74
+ end
75
+ end
76
+
77
+ def kick_all
78
+ self[:players].each do |nick,cls|
79
+ self.match.server.kick(nick.to_s)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,101 @@
1
+ require 'cinch'
2
+ require 'kag/common'
3
+ require 'commands/help'
4
+
5
+ module KAG
6
+ module IRC
7
+ class Plugin
8
+ include Cinch::Plugin
9
+ include Cinch::Commands
10
+ include KAG::Common
11
+
12
+ command :hostname,{nick: :string},
13
+ summary: "Get the hostname for a user",
14
+ admin: true
15
+ def hostname(m,nick)
16
+ if is_admin(m.user)
17
+ user = User(nick)
18
+ if user and !user.unknown
19
+ reply m,"Hostname for #{nick} is #{user.host}"
20
+ else
21
+ reply m,"Could not find user #{nick}"
22
+ end
23
+ end
24
+ end
25
+
26
+ command :authname,{nick: :string},
27
+ summary: "Get the AUTH name of a user",
28
+ admin: true
29
+ def authname(m,nick)
30
+ if is_admin(m.user)
31
+ user = User(nick)
32
+ if user and !user.unknown
33
+ reply m,"Authname for #{nick} is #{user.authname}"
34
+ else
35
+ reply m,"Could not find user #{nick}"
36
+ end
37
+ end
38
+ end
39
+
40
+ command :idle,{nick: :string},
41
+ summary: "Return how long a user has been idle",
42
+ admin: true
43
+ def idle(m,nick)
44
+ if is_admin(m.user)
45
+ user = User(nick)
46
+ if user and !user.unknown
47
+ s = user.idle.to_i / 60
48
+ reply m,"#{nick} has been idle #{s} minutes"
49
+ else
50
+ reply m,"Could not find user #{nick}"
51
+ end
52
+ end
53
+ end
54
+
55
+ command :op,{nick: :string},
56
+ summary: "Op a user",
57
+ admin: true
58
+ def op(m,nick)
59
+ if is_admin(m.user)
60
+ m.channel.op(nick)
61
+ end
62
+ end
63
+
64
+ command :deop,{nick: :string},
65
+ summary: "Deop a user",
66
+ admin: true
67
+ def deop(m,nick)
68
+ if is_admin(m.user)
69
+ m.channel.deop(nick)
70
+ end
71
+ end
72
+
73
+ command :voice,{nick: :string},
74
+ summary: "Voice a user",
75
+ admin: true
76
+ def voice(m,nick)
77
+ if is_admin(m.user)
78
+ m.channel.voice(nick)
79
+ end
80
+ end
81
+
82
+ command :devoice,{nick: :string,reason: :string},
83
+ summary: "Devoice a user",
84
+ admin: true
85
+ def devoice(m,nick,reason = '')
86
+ if is_admin(m.user)
87
+ m.channel.devoice(nick)
88
+ end
89
+ end
90
+
91
+ command :kick,{nick: :string,reason: :string},
92
+ summary: "Kick a user",
93
+ admin: true
94
+ def kick(m,nick,reason)
95
+ if is_admin(m.user)
96
+ m.channel.kick(nick,reason)
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
data/lib/kag/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module KAG
2
- VERSION = '1.3.4'
2
+ VERSION = '1.3.5'
3
3
  def self.version
4
4
  VERSION
5
5
  end
data/readme.md CHANGED
@@ -8,4 +8,4 @@ First setup config file by copying config/config.sample.json to config/config.js
8
8
 
9
9
  Then run:
10
10
 
11
- `ruby gather.rb`
11
+ `sh gather.sh`