ssc.nob 0.1.0-java → 0.1.1-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 500e06b390d4d053753c4af5c3705c842337bbad484f95c23d793705fdcd36d3
4
- data.tar.gz: a210ea5add620381a0da1cc7ae4ab0898f2d0b88e0403e1283d8569f9a31ac16
3
+ metadata.gz: 117249d42951cfad97ccdd6559ddd9c219d2312e1031d6266b7c722305f7cf2d
4
+ data.tar.gz: b8127bf53f430a319fe0ff86f675f852f7d7e1c724f96976b714b295f62c6ca6
5
5
  SHA512:
6
- metadata.gz: c953166b9e8aa1cf0cbe50fa94cdb8582eaeec462488b1b23067061029436f289620cd148e9f39154ba42cb5bddbf854051a98095f34301a6bc5fe53fe19f96a
7
- data.tar.gz: c1b4a35daf3aba33aff03afd3e449948f0374908a031bcc199f37b0bed87d48abd5e21fbec448ddd243b27c0b9a8d8f551d6ae5e14f99a8f68dbb2f632c9ed12
6
+ metadata.gz: 5674914d7979994e94ecd3bf4f4682033aa5c54b133c536b2c1922f88de4fb0829d1e3bb9ed212f28ddd56b81995454b53e2b1dccc504b75bf089134c6fbc012
7
+ data.tar.gz: efff233badf0e0ff8e5fad4934b3fa22876ec6c4304e81375611a02fcc3442701d2d5abf88f4e95954d46fa7646fbec11a1aa890056da03f90504865a98fbb60
data/CHANGELOG.md CHANGED
@@ -1,9 +1,37 @@
1
1
  # Changelog | SSC.Nob
2
2
 
3
- Format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ Format is based on [Keep a Changelog v1.0.0](https://keepachangelog.com/en/1.0.0),
6
+ and this project adheres to [Semantic Versioning v2.0.0](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [[Unreleased]](https://github.com/esotericpig/ssc.nob/compare/v0.1.1...HEAD)
9
+ -
10
+
11
+
12
+ ## [v0.1.1] - 2021-06-22
13
+
14
+ ### Added
15
+ - Added use of Warbler to create a runnable Jar for release.
16
+ - Added Rake tasks: `jar`, `runjar`
17
+ - Added rough drafts (rough working code) of Lotto, Moka, & Poker bots.
18
+
19
+ ### Changed
20
+ - Changed `Config` to allow non-Tab message keys.
21
+ - Changed to use `SSC.Bot` Gem, instead of internal (old) code for working with Subspace Continuum. For `SSC.Bot`, I basically extracted all of this code, updated it, and put it under a more permissible license (LGPL).
22
+ - Updated Gems.
23
+ - Formatted all files.
24
+ - Formatted all code with RuboCop.
25
+ - Updated Readme to reflect new changes.
4
26
 
5
- ## [[Unreleased]](https://github.com/esotericpig/ssc.nob/compare/v0.1.0...master)
6
27
 
7
28
  ## [v0.1.0] - 2020-04-30
8
29
 
9
30
  Initial working version.
31
+
32
+ ### Added
33
+ ### Changed
34
+ ### Deprecated
35
+ ### Removed
36
+ ### Fixed
37
+ ### Security
data/Gemfile CHANGED
@@ -1,27 +1,9 @@
1
1
  # encoding: UTF-8
2
2
  # frozen_string_literal: true
3
3
 
4
- #--
5
- # This file is part of SSC.Nob.
6
- # Copyright (c) 2020 Jonathan Bradley Whited (@esotericpig)
7
- #
8
- # SSC.Nob is free software: you can redistribute it and/or modify
9
- # it under the terms of the GNU General Public License as published by
10
- # the Free Software Foundation, either version 3 of the License, or
11
- # (at your option) any later version.
12
- #
13
- # SSC.Nob is distributed in the hope that it will be useful,
14
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- # GNU General Public License for more details.
17
- #
18
- # You should have received a copy of the GNU General Public License
19
- # along with SSC.Nob. If not, see <https://www.gnu.org/licenses/>.
20
- #++
21
-
22
4
 
23
5
  source 'https://rubygems.org'
24
6
 
25
- ruby '>= 2.4',:engine => 'jruby',:engine_version => '>= 9.2'
7
+ ruby '>= 2.4',engine: 'jruby',engine_version: '>= 9.2'
26
8
 
27
9
  gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,49 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ssc.nob (0.1.1-java)
5
+ attr_bool (~> 0.2)
6
+ highline (~> 2.0)
7
+ rainbow (~> 3.0)
8
+ ssc.bot (~> 0.2)
9
+ tty-spinner (~> 0.9)
10
+
11
+ GEM
12
+ remote: https://rubygems.org/
13
+ specs:
14
+ attr_bool (0.2.2)
15
+ highline (2.0.3)
16
+ jruby-jars (9.2.19.0)
17
+ jruby-rack (1.1.21)
18
+ minitest (5.14.4)
19
+ rainbow (3.0.0)
20
+ rake (13.0.3)
21
+ rubyzip (1.3.0)
22
+ ssc.bot (0.2.0)
23
+ attr_bool (~> 0.2)
24
+ tty-cursor (0.7.1)
25
+ tty-spinner (0.9.3)
26
+ tty-cursor (~> 0.7)
27
+ warbler (2.0.5)
28
+ jruby-jars (>= 9.0.0.0)
29
+ jruby-rack (>= 1.1.1, < 1.3)
30
+ rake (>= 10.1.0)
31
+ rubyzip (~> 1.0, < 1.4)
32
+
33
+ PLATFORMS
34
+ java
35
+ universal-java-1.8
36
+ universal-java-11
37
+
38
+ DEPENDENCIES
39
+ bundler (~> 2.2)
40
+ minitest (~> 5.14)
41
+ rake (~> 13.0)
42
+ ssc.nob!
43
+ warbler (~> 2.0)
44
+
45
+ RUBY VERSION
46
+ ruby 2.5.7p0 (jruby 9.2.9.0)
47
+
48
+ BUNDLED WITH
49
+ 2.2.20
data/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # SSC.Nob
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/ssc.nob.svg)](https://badge.fury.io/rb/ssc.nob)
4
+ [![Source Code](https://img.shields.io/badge/source-github-%23211F1F.svg)](https://github.com/esotericpig/ssc.nob)
5
+ [![Changelog](https://img.shields.io/badge/changelog-md-%23A0522D.svg)](CHANGELOG.md)
6
+ [![License](https://img.shields.io/github/license/esotericpig/ssc.nob.svg)](LICENSE.txt)
7
+
3
8
  *SSC.Nob* is a simple bot I wrote for the game [Subspace Continuum](https://store.steampowered.com/app/352700/Subspace_Continuum/), just for fun!
4
9
 
5
10
  *SSC* stands for Subspace Continuum. *Nob* stands for Noble One Bot. Noble One (or Nob) is meant to be a gender-neutral version of King of the Hill.
@@ -13,27 +18,50 @@ It's **not** a server bot and can be run & used by any user in any zone & arena.
13
18
 
14
19
  It's currently **not** a [UDP packet](https://www.twcore.org/SubspaceProtocol/) bot. It simply reads a log file for input and uses Java's Robot class for output. For SSC.Nob2 or something, I'd like to read/write packets, but will probably never make it.
15
20
 
16
- ## Running
21
+ ## Run
22
+
23
+ ### From Jar
24
+
25
+ Download the latest Jar from the *Assets* on the [Releases page](https://github.com/esotericpig/ssc.nob/releases).
26
+
27
+ Then simply run the Jar:
28
+
29
+ ```
30
+ $ java -jar ssc.nob.jar
31
+ ```
32
+
33
+ ### From RubyGems or Source
17
34
 
18
35
  JRuby is required. [ruby-install](https://github.com/postmodern/ruby-install) & [chruby](https://github.com/postmodern/chruby) make this easy:
19
36
 
20
37
  ```
21
38
  $ ruby-install jruby
22
39
  $ chruby jruby
23
- $ gem install bundler
24
40
  ```
25
41
 
26
- It's pretty janky at the moment, but works.
42
+ Run the app with JRuby...
27
43
 
28
- Run the app with JRuby:
44
+ Either from RubyGems:
29
45
 
30
46
  ```
31
- $ bundler install
32
- $ ruby ./lib/ssc.nob.rb
47
+ [jruby]$ gem install ssc.nob
48
+ [jruby]$ ssc.nob
49
+ ```
50
+
51
+ Or from source:
52
+
53
+ ```
54
+ [jruby]$ gem install bundler
55
+ [jruby]$ bundler install
56
+ [jruby]$ ruby ./lib/ssc.nob.rb
33
57
  ```
34
58
 
35
59
  **Note:** that's *bundler* with an *r*, not *bundle* (which doesn't work with JRuby).
36
60
 
61
+ ## Setup & Demo
62
+
63
+ It's pretty janky at the moment, but works.
64
+
37
65
  You'll be asked a couple of questions. Then input the `run` command.
38
66
 
39
67
  Current Subspace configuration:
@@ -45,14 +73,34 @@ Current Subspace configuration:
45
73
 
46
74
  Now to run *Nob*, private message yourself `!nob.start`. Private message yourself `!nob.stop` to stop it.
47
75
 
48
- [![asciinema demo](https://asciinema.org/a/325424.png)](https://asciinema.org/a/325424)
76
+ [![asciinema demo](https://asciinema.org/a/326310.png)](https://asciinema.org/a/326310)
77
+
78
+ ## Hack
79
+
80
+ Use this Rake task for creating a Jar for release:
81
+
82
+ ```
83
+ [jruby]$ bundler exec rake jar
84
+ ```
85
+
86
+ There's a task for running as well:
87
+
88
+ ```
89
+ [jruby]$ bundler exec rake runjar
90
+ ```
91
+
92
+ Don't forget to include it in the release:
93
+
94
+ ```
95
+ $ gh release create v0.0.0 pkg/*.jar pkg/*.gem
96
+ ```
49
97
 
50
98
  ## License
51
99
 
52
100
  [GNU GPL v3+](LICENSE.txt)
53
101
 
54
102
  > SSC.Nob (<https://github.com/esotericpig/ssc.nob>)
55
- > Copyright (c) 2020 Jonathan Bradley Whited (@esotericpig)
103
+ > Copyright (c) 2020-2021 Jonathan Bradley Whited
56
104
  >
57
105
  > SSC.Nob is free software: you can redistribute it and/or modify
58
106
  > it under the terms of the GNU General Public License as published by
data/Rakefile CHANGED
@@ -1,42 +1,69 @@
1
1
  # encoding: UTF-8
2
2
  # frozen_string_literal: true
3
3
 
4
- #--
5
- # This file is part of SSC.Nob.
6
- # Copyright (c) 2020 Jonathan Bradley Whited (@esotericpig)
7
- #
8
- # SSC.Nob is free software: you can redistribute it and/or modify
9
- # it under the terms of the GNU General Public License as published by
10
- # the Free Software Foundation, either version 3 of the License, or
11
- # (at your option) any later version.
12
- #
13
- # SSC.Nob is distributed in the hope that it will be useful,
14
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- # GNU General Public License for more details.
17
- #
18
- # You should have received a copy of the GNU General Public License
19
- # along with SSC.Nob. If not, see <https://www.gnu.org/licenses/>.
20
- #++
21
-
22
4
 
23
5
  require 'bundler/gem_tasks'
24
6
 
25
7
  require 'rake/clean'
26
8
  require 'rake/testtask'
27
-
28
9
  require 'ssc.nob/version'
29
10
 
30
11
 
12
+ # If PKG_DIR or JAR_FILE are changed,
13
+ # then 'config/warble.rb' also needs to be changed.
14
+ PKG_DIR = 'pkg'
15
+ JAR_FILE = File.join(PKG_DIR,'ssc.nob.jar')
16
+
31
17
  CLEAN.exclude('.git/','stock/')
32
18
  CLOBBER.include('doc/')
33
19
 
34
20
  task default: [:test]
35
21
 
36
- Rake::TestTask.new() do |task|
37
- task.libs = ['lib','test']
38
- task.pattern = File.join('test','**','*_test.rb')
39
- task.description += ": '#{task.pattern}'"
40
- task.verbose = false
41
- task.warning = true
22
+ Rake::TestTask.new do |t|
23
+ t.libs = ['lib','test']
24
+ t.pattern = File.join('test','**','*_test.rb')
25
+ t.description += ": '#{t.pattern}'"
26
+ t.options = '--pride'
27
+ t.verbose = true
28
+ t.warning = true
29
+ end
30
+
31
+ desc 'Create a runnable Jar using Warbler for release'
32
+ task :jar do |t|
33
+ puts <<~HELP
34
+
35
+ ============================================
36
+ Make sure Warbler is installed:
37
+ [jruby]$ bundler install
38
+ [jruby]$ bundler update
39
+ Or if the above doesn't work:
40
+ [jruby]$ gem install warbler
41
+
42
+ If this task fails, try using Bundler:
43
+ [jruby]$ bundler exec rake jar
44
+ Or try using Warbler directly:
45
+ $ warble
46
+
47
+ Check 'config/warble.rb' for configuration.
48
+ ============================================
49
+
50
+ HELP
51
+
52
+ mkdir(PKG_DIR,verbose: true) unless Dir.exist?(PKG_DIR)
53
+ sh('warble')
54
+ end
55
+
56
+ # This doesn't depend on ':jar' task
57
+ # because Warbler naively deletes and creates a new Jar every time.
58
+ desc 'Run the Jar created by Warbler'
59
+ task :runjar do |t|
60
+ # Manually create the Jar only if it doesn't exist.
61
+ if !File.exist?(JAR_FILE)
62
+ jar_task = Rake::Task[:jar]
63
+
64
+ jar_task.reenable
65
+ jar_task.invoke
66
+ end
67
+
68
+ sh('java','-jar',JAR_FILE)
42
69
  end
data/bin/ssc.nob CHANGED
@@ -4,20 +4,9 @@
4
4
 
5
5
  #--
6
6
  # This file is part of SSC.Nob.
7
- # Copyright (c) 2020 Jonathan Bradley Whited (@esotericpig)
8
- #
9
- # SSC.Nob is free software: you can redistribute it and/or modify
10
- # it under the terms of the GNU General Public License as published by
11
- # the Free Software Foundation, either version 3 of the License, or
12
- # (at your option) any later version.
13
- #
14
- # SSC.Nob is distributed in the hope that it will be useful,
15
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
- # GNU General Public License for more details.
18
- #
19
- # You should have received a copy of the GNU General Public License
20
- # along with SSC.Nob. If not, see <https://www.gnu.org/licenses/>.
7
+ # Copyright (c) 2020-2021 Jonathan Bradley Whited
8
+ #
9
+ # SPDX-License-Identifier: GPL-3.0-or-later
21
10
  #++
22
11
 
23
12
 
data/lib/ssc.nob.rb CHANGED
@@ -1,147 +1,143 @@
1
- #!/usr/bin/env ruby
2
1
  # encoding: UTF-8
3
2
  # frozen_string_literal: true
4
3
 
5
4
  #--
6
5
  # This file is part of SSC.Nob.
7
- # Copyright (c) 2020 Jonathan Bradley Whited (@esotericpig)
8
- #
9
- # SSC.Nob is free software: you can redistribute it and/or modify
10
- # it under the terms of the GNU General Public License as published by
11
- # the Free Software Foundation, either version 3 of the License, or
12
- # (at your option) any later version.
13
- #
14
- # SSC.Nob is distributed in the hope that it will be useful,
15
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
- # GNU General Public License for more details.
18
- #
19
- # You should have received a copy of the GNU General Public License
20
- # along with SSC.Nob. If not, see <https://www.gnu.org/licenses/>.
6
+ # Copyright (c) 2020-2021 Jonathan Bradley Whited
7
+ #
8
+ # SPDX-License-Identifier: GPL-3.0-or-later
21
9
  #++
22
10
 
23
11
 
24
- TESTING = ($0 == __FILE__)
12
+ TESTING = ($PROGRAM_NAME == __FILE__)
25
13
 
26
14
  if TESTING
27
15
  require 'rubygems'
28
16
  require 'bundler/setup'
29
17
  end
30
18
 
31
- require 'attr_bool'
19
+ require 'attr_bool/core_ext'
20
+ require 'ssc.bot'
21
+ require 'ssc.bot/user/jrobot_message_sender'
32
22
  require 'time'
33
23
 
34
24
  require 'ssc.nob/config'
35
25
  require 'ssc.nob/error'
36
- require 'ssc.nob/ssc_bot'
37
- require 'ssc.nob/ssc_chat_log'
38
26
  require 'ssc.nob/userface'
39
27
  require 'ssc.nob/util'
40
28
  require 'ssc.nob/version'
41
29
 
42
- require 'ssc.nob/ssc_chat_log/message'
43
- require 'ssc.nob/ssc_chat_log/message_parser'
44
-
45
-
46
- # TODO: run options
47
- # run:
48
- # - Specify time limit (in seconds?).
49
- # - Specify money donation for winner.
50
- # - Specify who starts as Nob.
51
- # - Specify if testing, so do chat channel messages instead of pub.
52
30
 
53
31
  ###
54
- # @author Jonathan Bradley Whited (@esotericpig)
32
+ # @author Jonathan Bradley Whited
55
33
  # @since 0.1.0
56
34
  ###
57
35
  module SSCNob
58
- def self.run()
59
- nober = SSCNober.new()
60
-
61
- nober.run()
36
+ def self.run
37
+ nober = Nober.new
38
+
39
+ nober.run
62
40
  end
63
-
64
- def self.uface()
41
+
42
+ def self.uface
65
43
  return Userface.instance
66
44
  end
67
-
68
- class SSCNober
45
+
46
+ ###
47
+ # @author Jonathan Bradley Whited
48
+ # @since 0.1.1
49
+ ###
50
+ class Nober
69
51
  include Uface
70
-
71
- attr_reader :bot
52
+
72
53
  attr_reader :chat_log
73
54
  attr_reader :config
55
+ attr_reader :msg_sender
74
56
  attr_reader :nob
75
57
  attr_reader :nob_time
76
58
  attr_reader :nobing
77
59
  attr_reader :players
78
60
  attr_accessor? :testing
79
61
  attr_reader :thread
80
-
81
- def initialize(testing: false)
62
+
63
+ def initialize
82
64
  super()
83
-
84
- @bot = SSCBot.new()
65
+
66
+ @beer = false
85
67
  @chat_log = nil
86
- @config = Config.new()
68
+ @config = Config.new
69
+ @donation = nil
70
+ @msg_sender = SSCBot::User::JRobotMessageSender.new
87
71
  @nob = nil
88
- @nob_time = Time.now()
72
+ @nob_time = Time.now
89
73
  @nobing = false
90
74
  @players = {}
91
- @testing = testing
75
+ @testing = false
92
76
  @thread = nil
77
+
78
+ @lotto_bot = false
79
+ @moka_bot = false
80
+ @poker_bot = false
81
+ @poker_thread = nil
93
82
  end
94
-
95
- def run()
83
+
84
+ def run
96
85
  begin
97
86
  puts
98
- @config.user_init!()
87
+ @config.user_init!
99
88
  puts
100
89
  rescue UserError => e
101
90
  puts
102
91
  puts uface.error(e)
103
-
92
+
104
93
  return
105
94
  end
106
-
107
- @chat_log = SSCChatLog.new(@config)
108
-
109
- @chat_log.add_listener(&method(:kill_message))
110
- @chat_log.add_listener(&method(:private_message))
111
- @chat_log.add_listener(&method(:pub_message))
112
- @chat_log.add_listener(&method(:q_namelen_message))
113
-
114
- puts <<~EOH
95
+
96
+ @msg_sender.msg_key = @config.build_msg_key
97
+ #@msg_sender.warn_user = true
98
+
99
+ @chat_log = SSCBot::ChatLog.new(File.join(@config.build_ssc_log_dir,'nob.log'))
100
+
101
+ @chat_log.add_observer(self,:handle_kill_msg,type: :kill)
102
+ @chat_log.add_observer(self,:handle_msg)
103
+ @chat_log.add_observer(self,:handle_chat_msg,type: :chat)
104
+ @chat_log.add_observer(self,:handle_pub_msg,type: :pub)
105
+ @chat_log.add_observer(self,:handle_q_namelen_msg,type: %s(?namelen))
106
+ @chat_log.add_observer(self,:moka_bot)
107
+ @chat_log.add_observer(self,:lotto_bot)
108
+ @chat_log.add_observer(self,:poker_bot)
109
+
110
+ puts <<~HELP
115
111
  #{uface.title('COMMANDS')}
116
112
  #{uface.cmd('run')} runs Nob
117
113
  #{uface.cmd('stop')} stops Nob
118
114
  #{uface.cmd('exit, quit')} goodbye, user
119
- EOH
115
+ HELP
120
116
  puts
121
-
117
+
122
118
  while true
123
- cmd = uface.ask(uface.gt())
124
- cmd = Util.strip(cmd.to_s()).downcase()
125
-
119
+ cmd = uface.ask(uface.gt)
120
+ cmd = Util.strip(cmd.to_s).downcase
121
+
126
122
  case cmd
127
123
  when 'exit','quit'
128
- @chat_log.stop()
129
-
124
+ @chat_log.stop
125
+
130
126
  puts
131
127
  uface.types("You don't #{uface.love('love')} me? #{uface.love('<3')}")
132
128
  puts
133
-
129
+
134
130
  return
135
131
  when 'run'
136
- if @chat_log.running?()
132
+ if @chat_log.alive?
137
133
  puts
138
134
  puts uface.error('stop the current Nob first, user.')
139
135
  puts
140
136
  else
141
- @chat_log.run()
137
+ @chat_log.run
142
138
  end
143
139
  when 'stop'
144
- @chat_log.stop()
140
+ @chat_log.stop
145
141
  else
146
142
  puts
147
143
  puts uface.error("that's an invalid command, user.")
@@ -149,118 +145,709 @@ module SSCNob
149
145
  end
150
146
  end
151
147
  end
152
-
153
- def kill_message(chat_log,msg)
154
- return unless @nobing
155
- return unless msg.kill?()
156
-
157
- if msg[:killed] == @nob
158
- old_nob = @players[@nob]
159
- old_nob[:time] += (Time.now() - @nob_time)
160
-
161
- killer = msg[:killer]
162
- new_nob = @players[killer]
163
-
164
- if new_nob.nil?()
165
- new_nob = {nobs: 0,time: 0,username: killer}
166
- @players[killer] = new_nob
148
+
149
+ def handle_kill_msg(chat_log,msg)
150
+ killed_username = msg.killed
151
+ killer_username = msg.killer
152
+
153
+ killed = @players[killed_username]
154
+ killer = @players[killer_username]
155
+
156
+ if @nobing && !killed.nil?
157
+ if killed.username == @nob
158
+ killed.time += (Time.now - @nob_time)
159
+ @nob_time = Time.now
160
+
161
+ if killer.nil?
162
+ killer = Player.new(killer_username)
163
+ @players[killer.username] = killer
164
+ end
165
+
166
+ killer.nobs += 1
167
+ @nob = killer.username
168
+
169
+ send_nob_msg("{#{killer.username}} is now the Nob!")
170
+ end
171
+
172
+ # Only increment for people playing.
173
+ if !killer.nil?
174
+ killed.deaths += 1
175
+ killer.kills += 1
176
+ end
177
+ elsif @moka_bot
178
+ if killed.nil?
179
+ killed = Player.new(killed_username)
180
+ @players[killed.username] = killed
181
+ end
182
+
183
+ if killer.nil?
184
+ killer = Player.new(killer_username)
185
+ @players[killer.username] = killer
186
+ end
187
+
188
+ killed.deaths += 1
189
+ killer.kills += 1
190
+ end
191
+ end
192
+
193
+ def handle_msg(chat_log,msg)
194
+ if @beer && msg.line.start_with?(' TEAM: ')
195
+ team = msg.line[8..-1]
196
+
197
+ team.split(/\(\d+\),?/).each do |mem|
198
+ mem = Util.strip(mem)
199
+ @players[mem] = true
200
+ end
201
+ end
202
+ end
203
+
204
+ def moka_bot(chat_log,msg)
205
+ if msg.type_chat?
206
+ channel = msg.channel
207
+ message = msg.message
208
+ username = msg.name
209
+
210
+ if username == @config.username
211
+ cmd = message.downcase
212
+
213
+ case cmd
214
+ when '!moka.start'
215
+ return if @moka_bot
216
+
217
+ @players = {}
218
+ #@testing = true
219
+
220
+ mins = @testing ? 1 : 5
221
+
222
+ if !@thread.nil?
223
+ @thread.kill if @thread.alive?
224
+ @thread = nil
225
+ end
226
+
227
+ send_msg("Moka} Moka (MOst KillA) bot loaded for #{mins} minutes.")
228
+ send_msg('Moka} Top Moka gets a cup of tea!')
229
+
230
+ @moka_bot = true
231
+
232
+ @thread = Thread.new do
233
+ sleep((mins - 1) * 60)
234
+
235
+ tops = @players.values.sort do |p1,p2|
236
+ i = p2.kills <=> p1.kills
237
+ i = p1.deaths <=> p2.deaths if i == 0
238
+ i
239
+ end
240
+ top = tops[0]
241
+
242
+ send_msg('Moka} 1 Moka minute remaining!')
243
+
244
+ if !top.nil?
245
+ send_msg(
246
+ "Moka} c\\#{top.username}/ is the current Moka" \
247
+ " with #{top.kills} kill#{top.kills == 1 ? '' : 's'}" \
248
+ " and #{top.deaths} death#{top.deaths == 1 ? '' : 's'}!"
249
+ )
250
+ end
251
+
252
+ sleep(60) # 1 min
253
+
254
+ @moka_bot = false
255
+
256
+ tops = @players.values.sort do |p1,p2|
257
+ i = p2.kills <=> p1.kills
258
+ i = p1.deaths <=> p2.deaths if i == 0
259
+ i
260
+ end
261
+
262
+ moka_recs = {}
263
+ moka_recs_count = 0
264
+
265
+ tops.each do |t|
266
+ mr = moka_recs[t.rec]
267
+
268
+ if mr.nil?
269
+ moka_recs[t.rec] = mr = []
270
+ moka_recs_count += 1
271
+ end
272
+
273
+ mr << t
274
+
275
+ if moka_recs_count >= 5
276
+ break
277
+ end
278
+ end
279
+
280
+ send_msg('Moka} Moka bot ended!')
281
+ #send_msg(sprintf('Moka} | %-24s | Kills:Deaths','Top 5'))
282
+ #send_msg("Moka} | #{'-' * 24} | #{'-' * 12}")
283
+
284
+ #tops.each_with_index() do |player,i|
285
+ # msg = sprintf("##{i + 1} | %-24s | %-12s",
286
+ # player.username,player.rec,
287
+ # )
288
+ #
289
+ # send_msg("Moka} #{msg}")
290
+ #end
291
+
292
+ msg = []
293
+
294
+ #tops.each_with_index() do |player,i|
295
+ moka_recs.each_with_index do |(rec,players),i|
296
+ if players.length == 1
297
+ player = players[0]
298
+ msg << "##{i + 1} #{player.username}(#{rec})"
299
+ else
300
+ names = []
301
+
302
+ players.each do |p|
303
+ names << p.username
304
+ end
305
+
306
+ msg << "##{i + 1} (#{names.join(', ')})(#{rec})"
307
+ end
308
+ end
309
+
310
+ send_msg("Moka} #{msg.join('; ')}")
311
+
312
+ #top = tops[0]
313
+ top = moka_recs.values[0]
314
+
315
+ if !top.nil?
316
+ send_msg('%10')
317
+
318
+ if top.length == 1
319
+ top = top[0]
320
+
321
+ send_msg("Moka} c\\#{top.username}/ is the Moka! Congrats!")
322
+ send_msg(":TW-PubSystem:!buy tea:#{top.username}")
323
+ else
324
+ top.each do |t|
325
+ send_msg("Moka} c\\#{t.username}/ is a Moka! Congrats!")
326
+ send_msg(":TW-PubSystem:!buy tea:#{t.username}")
327
+ end
328
+ end
329
+ end
330
+ end
331
+ when '!moka.stop'
332
+ @moka_bot = false
333
+ @players = {}
334
+
335
+ if !@thread.nil?
336
+ @thread.kill if @thread.alive?
337
+ @thread = nil
338
+ end
339
+ end
340
+ end
341
+ end
342
+ end
343
+
344
+ def lotto_bot(chat_log,msg)
345
+ if msg.type_chat?
346
+ channel = msg.channel
347
+ message = msg.message
348
+ username = msg.name
349
+
350
+ if username == @config.username
351
+ cmd = message.downcase
352
+
353
+ case cmd
354
+ when '!lotto.start'
355
+ @lotto_bot = true
356
+
357
+ send_chat_msg(0,'lotto bot loaded')
358
+ when '!lotto.stop'
359
+ @lotto_bot = false
360
+
361
+ send_chat_msg(0,'lotto bot ended')
362
+ end
363
+ end
364
+ end
365
+
366
+ # ' [LOTTERY] PM !guess <#> from 1 - 100. Tickets $2,500' \
367
+ # ' Jackpot $300,000 (Within 1=50%,~5=20%) -TW-PubSystem'
368
+ if @lotto_bot && msg.line.start_with?(' [LOTTERY] PM !guess <#> from')
369
+ rand_num = rand(1..100) # 1-100
370
+
371
+ send_pub_msg(":TW-PubSystem:!guess #{rand_num}")
372
+ end
373
+ end
374
+
375
+ def poker_bot(chat_log,msg)
376
+ if msg.type_chat?
377
+ channel = msg.channel
378
+ message = msg.message
379
+ username = msg.name
380
+
381
+ if username == @config.username
382
+ cmd = message.downcase
383
+
384
+ case cmd
385
+ when '!poker.start'
386
+ return if @poker_bot
387
+
388
+ if @poker_thread
389
+ @poker_thread.kill if @poker_thread.alive?
390
+ @poker_thread = nil
391
+ end
392
+
393
+ #send_chat_msg(0,'poker bot loaded')
394
+ puts 'Poker bot loaded!'
395
+
396
+ @poker_bot = true
397
+
398
+ @poker_thread = Thread.new do
399
+ while @poker_bot
400
+ @poker_hand = nil
401
+
402
+ send_pub_msg(':TW-PubSystem:!poker')
403
+
404
+ sleep(15)
405
+
406
+ if @poker_hand.nil?
407
+ puts 'Killing poker bot!'
408
+ @poker_bot = false
409
+ break
410
+ end
411
+
412
+ puts @poker_hand
413
+ ph = PokerHand.new(@poker_hand)
414
+ puts ph
415
+ resp = ph.compute_response
416
+ puts resp
417
+
418
+ send_pub_msg(":TW-PubSystem:!poker #{resp}")
419
+
420
+ sleep(15)
421
+ end
422
+ end
423
+ when '!poker.stop'
424
+ @poker_bot = false
425
+
426
+ if @poker_thread
427
+ @poker_thread.join(5)
428
+ @poker_thread.kill if @poker_thread.alive?
429
+ @poker_thread = nil
430
+ end
431
+
432
+ #send_chat_msg(0,'poker bot killed')
433
+ puts 'Poker bot killed!'
434
+ end
435
+ end
436
+ end
437
+
438
+ # TW-PubSystem> 1) Jh 7s 7h 3h 3c ...
439
+ if @poker_bot && msg.type_private?
440
+ message = msg.message
441
+ username = msg.name
442
+
443
+ if username.casecmp?('TW-PubSystem') && message.start_with?('1)')
444
+ match = /1\)\s+(?<hand>\S+\s+\S+\s+\S+\s+\S+\s+\S+)\s+.*/.match(message)
445
+
446
+ if match
447
+ @poker_hand = match[:hand]
448
+ end
167
449
  end
168
-
169
- new_nob[:nobs] += 1
170
-
171
- @nob = killer
172
- @nob_time = Time.now()
173
-
174
- @bot.pub_message("Nob} {#{killer}} is now the Nob!")
175
450
  end
176
451
  end
177
-
178
- def private_message(chat_log,msg)
179
- return unless msg.private?()
180
-
181
- if msg[:username] == @config.username
182
- case msg[:message]
183
- when '!nob.start'
452
+
453
+ class PokerHand
454
+ attr_accessor :cards
455
+ attr_accessor :value
456
+ attr_accessor :values
457
+
458
+ def initialize(hand)
459
+ super()
460
+
461
+ @cards = []
462
+ @value = 0
463
+ @values = []
464
+
465
+ hand.split(/[[:space:]]+/).each do |card|
466
+ next if card.length != 2
467
+
468
+ value = card[0]
469
+ suit = card[1].to_sym
470
+
471
+ @cards << Card.new(value,suit)
472
+ end
473
+ end
474
+
475
+ def compute_response
476
+ is_flush = true
477
+ flushes = {}
478
+ ofakinds = Array.new(13){0}
479
+ prev_suit = nil
480
+ values = []
481
+ near_flush = false
482
+ near_flush_suit = nil
483
+
484
+ @cards.each do |card|
485
+ ofakinds[card.value - 2] += 1
486
+ values << card.value
487
+
488
+ f = flushes.fetch(card.suit,0)
489
+ f += 1
490
+ flushes[card.suit] = f
491
+
492
+ if flushes[card.suit] >= 3
493
+ near_flush = true
494
+ near_flush_suit = card.suit
495
+ end
496
+
497
+ if !prev_suit.nil? && card.suit != prev_suit
498
+ is_flush = false
499
+ end
500
+
501
+ prev_suit = card.suit
502
+ end
503
+
504
+ is_2ofakind = false
505
+ is_2pair = false
506
+ is_3ofakind = false
507
+ is_4ofakind = false
508
+
509
+ ofakinds.each do |oak|
510
+ case oak
511
+ when 2
512
+ if is_2ofakind
513
+ is_2pair = true
514
+ else
515
+ is_2ofakind = true
516
+ end
517
+ when 3 then is_3ofakind = true
518
+ when 4 then is_4ofakind = true
519
+ end
520
+ end
521
+
522
+ values.sort!
523
+
524
+ is_bicycle = (values[0] == 2 && values[-1] == 14) # 14=Ace
525
+ is_straight = true
526
+ straight_value = values[0]
527
+
528
+ len = values.length - 1
529
+ len -= 1 if is_bicycle
530
+
531
+ bs_values = []
532
+ bs_count = 0
533
+
534
+ 1.upto(len) do |i|
535
+ straight_value += 1
536
+ value = values[i]
537
+
538
+ if value != straight_value
539
+ bs_values << value
540
+ bs_count += 1
541
+ is_straight = false
542
+ end
543
+ end
544
+
545
+ if is_straight && is_bicycle
546
+ # Change Ace value to 1 for a bicycle (wheel) straight.
547
+ values[-1] = 1
548
+
549
+ values.sort!
550
+ end
551
+
552
+ if is_straight || is_flush || (is_3ofakind && is_2ofakind)
553
+ return 'ooooo'
554
+ end
555
+
556
+ if is_4ofakind || is_3ofakind || is_2pair || is_2ofakind
557
+ resp = ''.dup
558
+
559
+ @cards.each do |card|
560
+ oak = ofakinds[card.value - 2]
561
+
562
+ if oak >= 2
563
+ resp << 'o'
564
+ else
565
+ resp << 'x'
566
+ end
567
+ end
568
+
569
+ return resp
570
+ end
571
+
572
+ # Near straight?
573
+ if bs_count == 1 || bs_count == 2
574
+ resp = ''.dup
575
+
576
+ @cards.each do |card|
577
+ if bs_values.include?(card.value)
578
+ resp << 'x'
579
+ else
580
+ resp << 'o'
581
+ end
582
+ end
583
+
584
+ return resp
585
+ end
586
+
587
+ # Near flush?
588
+ if near_flush
589
+ resp = ''.dup
590
+
591
+ @cards.each do |card|
592
+ if card.suit != near_flush_suit
593
+ resp << 'x'
594
+ else
595
+ resp << 'o'
596
+ end
597
+ end
598
+
599
+ return resp
600
+ end
601
+
602
+ # Just do high cards
603
+ high_cards = [values[-1]]
604
+ high_cards << values[-2] if rand(2) == 0
605
+
606
+ resp = ''.dup
607
+
608
+ @cards.each do |card|
609
+ if high_cards.include?(card.value)
610
+ resp << 'o'
611
+ else
612
+ resp << 'x'
613
+ end
614
+ end
615
+
616
+ return resp
617
+ end
618
+
619
+ def valid?
620
+ return @cards.length == 5
621
+ end
622
+
623
+ def to_s
624
+ return @cards.join(' ')
625
+ end
626
+ end
627
+
628
+ class Card
629
+ attr_accessor :norm
630
+ attr_accessor :rank
631
+ attr_accessor :suit
632
+ attr_accessor :value
633
+
634
+ def initialize(rank,suit)
635
+ super()
636
+
637
+ @rank = rank
638
+ @suit = suit
639
+
640
+ case rank
641
+ when 'T' then @value = 10
642
+ when 'J' then @value = 11
643
+ when 'Q' then @value = 12
644
+ when 'K' then @value = 13
645
+ when 'A' then @value = 14
646
+ else
647
+ @value = rank.to_i
648
+ end
649
+
650
+ @norm = @value
651
+
652
+ case suit
653
+ when :c then @norm += 100
654
+ when :d then @norm += 200
655
+ when :h then @norm += 300
656
+ when :s then @norm += 400
657
+ else
658
+ raise ArgumentError,"invalid suit{#{suit}}"
659
+ end
660
+ end
661
+
662
+ def <=>(other)
663
+ c = (@suit <=> other.suit)
664
+ c = @value <=> other.value if c == 0
665
+
666
+ return c
667
+ end
668
+
669
+ def inspect
670
+ return "#{@rank}(#{@value})#{@suit}"
671
+ end
672
+
673
+ def to_s
674
+ return "#{@rank}#{@suit}"
675
+ end
676
+ end
677
+
678
+ def handle_chat_msg(chat_log,msg)
679
+ message = msg.message
680
+ username = msg.name
681
+
682
+ if username == @config.username
683
+ cmd = message.downcase
684
+
685
+ if cmd.include?('!beer.start')
686
+ @beer = true
687
+ elsif cmd.include?('!beer.list')
688
+ send_chat_msg(4,"players: #{@players.length}")
689
+ send_chat_msg(4,@players.keys.join(', '))
690
+ elsif cmd.include?('!beer.me')
691
+ if @beer
692
+ @beer = false
693
+
694
+ @players.each_key do |name|
695
+ next if name == @config.username
696
+
697
+ send_pub_msg(":TW-PubSystem:!buy beer:#{name}")
698
+ sleep(6)
699
+ end
700
+
701
+ @players = {}
702
+ end
703
+ elsif cmd.include?('!beer.stop')
704
+ @beer = false
705
+ @players = {}
706
+ elsif cmd.start_with?('!nob.start')
184
707
  return if @nobing # Already nobing
185
-
186
- @nob = @config.username
187
-
708
+
709
+ opts_msg = Util.strip(message)
710
+ opts_msg = Util.strip(message[10..-1])
711
+ opts_msg = opts_msg.split(',')
712
+
713
+ opts = {}
714
+
715
+ opts_msg.each do |om|
716
+ om = om.split('=',2)
717
+ opts[om[0]] = om[1]
718
+ end
719
+
720
+ @donation = opts['donate']
721
+ @donation = nil if Util.blank?(@donation)
722
+ mins = opts.key?('mins') ? opts['mins'].to_i : 5
723
+ @nob = opts.key?('nob') ? opts['nob'] : @config.username
724
+ @testing = true if opts.key?('test')
725
+
188
726
  @players = {
189
- @nob => {nobs: 1,time: 0,username: @nob}
727
+ @nob => Player.new(@nob,nobs: 1)
190
728
  }
191
-
192
- if !@thread.nil?()
193
- @thread.kill() if @thread.alive?()
194
-
729
+
730
+ if !@thread.nil?
731
+ @thread.kill if @thread.alive?
732
+
195
733
  @thread = nil
196
734
  end
197
-
198
- @bot.pub_message('Nob} Nob bot loaded (Noble One) for 5 min!')
199
- @bot.pub_message("Nob} Kill {#{@nob}} to become the Nob!")
200
-
735
+
736
+ send_nob_msg("Nob bot loaded (Noble One) for #{mins} min.")
737
+ send_nob_msg("Kill {#{@nob}} to become the Nob!")
738
+
739
+ if !@donation.nil?
740
+ send_nob_msg("Top Nob gets #{@donation} pub bux!")
741
+ end
742
+
201
743
  @nobing = true
202
- @nob_time = Time.now()
203
-
204
- @thread = Thread.new() do
205
- sleep(5 * 60)
206
-
744
+ @nob_time = Time.now
745
+
746
+ @thread = Thread.new do
747
+ sleep(mins * 60)
748
+
207
749
  @nobing = false
208
-
750
+
209
751
  nobler = @players[@nob]
210
- nobler[:time] += (Time.now() - @nob_time)
211
-
212
- tops = @players.values.sort() do |p1,p2|
213
- p2[:time] <=> p1[:time]
752
+ nobler.time += (Time.now - @nob_time)
753
+
754
+ tops = @players.values.sort do |p1,p2|
755
+ p2.time <=> p1.time
214
756
  end
215
- tops = tops[0..2]
216
-
217
- @bot.pub_message('Nob} Nob bot ended!')
218
- @bot.pub_message(sprintf('Nob} | %-24s | # of Nobs | Time','Nobler'))
219
- @bot.pub_message("Nob} | #{'-' * 24} | #{'-' * 9} | #{'-' * 8}")
220
-
221
- tops.each_with_index() do |top,i|
222
- msg = sprintf("Nob} ##{i + 1} | %-24s | %-9s | %s secs",
223
- top[:username],top[:nobs],top[:time].round(2))
224
-
225
- @bot.pub_message(msg)
757
+ tops = tops[0..4]
758
+
759
+ send_nob_msg('Nob bot ended!')
760
+ send_nob_msg(sprintf(' | %-24s | # of Nobs | Kills:Deaths | Time','Nobler'))
761
+ send_nob_msg(" | #{'-' * 24} | #{'-' * 9} | #{'-' * 12} | #{'-' * 8}")
762
+
763
+ tops.each_with_index do |top,i|
764
+ msg = sprintf("##{i + 1} | %-24s | %-9s | %-12s | %.2f secs",
765
+ top.username,top.nobs,top.rec,top.time.round(2),
766
+ )
767
+
768
+ send_nob_msg(msg)
226
769
  end
227
-
770
+
228
771
  top = tops[0]
229
-
230
- @bot.pub_message("Nob} {#{top[:username]}} is the top Nob! Congrats!")
772
+
773
+ send_nob_msg("{#{top.username}} is the top Nob! Congrats!")
774
+
775
+ if !@donation.nil?
776
+ send_pub_msg(":TW-PubSystem:!donate #{top.username}:#{@donation}")
777
+ end
231
778
  end
232
- when '!nob.stop'
779
+ elsif cmd.include?('!nob.stop')
233
780
  @nobing = false
234
781
  @players = {}
235
-
236
- if !@thread.nil?()
237
- @thread.kill() if @thread.alive?()
238
-
782
+
783
+ if !@thread.nil?
784
+ @thread.kill if @thread.alive?
785
+
239
786
  @thread = nil
240
787
  end
241
788
  end
242
789
  end
243
790
  end
244
-
245
- def pub_message(chat_log,msg)
246
- return unless @nobing
247
- return unless msg.pub?()
248
-
249
- if msg[:username] == @config.username
250
- @bot.prevent_flooding()
251
- end
791
+
792
+ def handle_pub_msg(chat_log,msg)
252
793
  end
253
-
254
- def q_namelen_message(chat_log,msg)
255
- return unless msg.q_namelen?()
256
-
794
+
795
+ def handle_q_namelen_msg(chat_log,msg)
257
796
  puts
258
- puts "Using namelen{#{msg[:namelen]}}."
259
- print uface.gt()
797
+ puts "Using namelen{#{msg.namelen}}."
798
+ print uface.gt
799
+ end
800
+
801
+ def send_chat_msg(channel,msg)
802
+ @msg_sender.send_chat_to(channel,msg)
803
+ end
804
+
805
+ def send_nob_msg(msg)
806
+ if @testing
807
+ send_chat_msg(0,msg)
808
+ else
809
+ send_pub_msg("nob} #{msg}")
810
+ end
811
+ end
812
+
813
+ def send_pub_msg(msg)
814
+ @msg_sender.send_safe(msg)
815
+ end
816
+
817
+ def send_msg(msg)
818
+ if @testing
819
+ send_chat_msg(0,msg)
820
+ else
821
+ send_pub_msg(msg)
822
+ end
823
+ end
824
+ end
825
+
826
+ ###
827
+ # @author Jonathan Bradley Whited
828
+ # @since 0.1.1
829
+ ###
830
+ class Player
831
+ attr_accessor :deaths
832
+ attr_accessor :kills
833
+ attr_accessor :nobs
834
+ attr_accessor :time
835
+ attr_accessor :username
836
+
837
+ def initialize(username,deaths: 0,kills: 0,nobs: 0,time: 0)
838
+ @deaths = deaths
839
+ @kills = kills
840
+ @nobs = nobs
841
+ @time = time
842
+ @username = username
843
+ end
844
+
845
+ def rec
846
+ return "#{@kills}:#{@deaths}"
260
847
  end
261
848
  end
262
849
  end
263
850
 
264
851
  if TESTING
265
- SSCNob.run()
852
+ SSCNob.run
266
853
  end