ssc.nob 0.1.0-java → 0.1.1-java

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.
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