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 +4 -4
- data/CHANGELOG.md +30 -2
- data/Gemfile +1 -19
- data/Gemfile.lock +49 -0
- data/README.md +56 -8
- data/Rakefile +52 -25
- data/bin/ssc.nob +3 -14
- data/lib/ssc.nob.rb +743 -156
- data/lib/ssc.nob/config.rb +94 -59
- data/lib/ssc.nob/error.rb +5 -17
- data/lib/ssc.nob/ssc_bot.rb +67 -88
- data/lib/ssc.nob/ssc_chat_log.rb +34 -46
- data/lib/ssc.nob/ssc_chat_log/message.rb +15 -27
- data/lib/ssc.nob/ssc_chat_log/message_parser.rb +39 -51
- data/lib/ssc.nob/userface.rb +33 -45
- data/lib/ssc.nob/util.rb +14 -26
- data/lib/ssc.nob/version.rb +4 -16
- data/ssc.nob.gemspec +24 -43
- metadata +45 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 117249d42951cfad97ccdd6559ddd9c219d2312e1031d6266b7c722305f7cf2d
|
4
|
+
data.tar.gz: b8127bf53f430a319fe0ff86f675f852f7d7e1c724f96976b714b295f62c6ca6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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'
|
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
|
+
[](https://badge.fury.io/rb/ssc.nob)
|
4
|
+
[](https://github.com/esotericpig/ssc.nob)
|
5
|
+
[](CHANGELOG.md)
|
6
|
+
[](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
|
-
##
|
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
|
-
|
42
|
+
Run the app with JRuby...
|
27
43
|
|
28
|
-
|
44
|
+
Either from RubyGems:
|
29
45
|
|
30
46
|
```
|
31
|
-
$
|
32
|
-
$
|
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
|
-
[](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
|
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
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
8
|
-
#
|
9
|
-
#
|
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
|
8
|
-
#
|
9
|
-
#
|
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 = ($
|
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
|
32
|
+
# @author Jonathan Bradley Whited
|
55
33
|
# @since 0.1.0
|
56
34
|
###
|
57
35
|
module SSCNob
|
58
|
-
def self.run
|
59
|
-
nober =
|
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
|
-
|
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
|
62
|
+
|
63
|
+
def initialize
|
82
64
|
super()
|
83
|
-
|
84
|
-
@
|
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 =
|
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
|
-
@
|
108
|
-
|
109
|
-
|
110
|
-
@chat_log.
|
111
|
-
|
112
|
-
@chat_log.
|
113
|
-
|
114
|
-
|
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
|
-
|
115
|
+
HELP
|
120
116
|
puts
|
121
|
-
|
117
|
+
|
122
118
|
while true
|
123
|
-
cmd = uface.ask(uface.gt
|
124
|
-
cmd = Util.strip(cmd.to_s
|
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.
|
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
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
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
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
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
|
-
|
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 =>
|
727
|
+
@nob => Player.new(@nob,nobs: 1)
|
190
728
|
}
|
191
|
-
|
192
|
-
if !@thread.nil?
|
193
|
-
@thread.kill
|
194
|
-
|
729
|
+
|
730
|
+
if !@thread.nil?
|
731
|
+
@thread.kill if @thread.alive?
|
732
|
+
|
195
733
|
@thread = nil
|
196
734
|
end
|
197
|
-
|
198
|
-
|
199
|
-
|
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
|
205
|
-
sleep(
|
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
|
211
|
-
|
212
|
-
tops = @players.values.sort
|
213
|
-
p2
|
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..
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
tops.each_with_index
|
222
|
-
msg = sprintf("
|
223
|
-
top
|
224
|
-
|
225
|
-
|
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
|
-
|
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
|
-
|
779
|
+
elsif cmd.include?('!nob.stop')
|
233
780
|
@nobing = false
|
234
781
|
@players = {}
|
235
|
-
|
236
|
-
if !@thread.nil?
|
237
|
-
@thread.kill
|
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
|
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
|
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
|
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
|