petli 0.0.1
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 +7 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +45 -0
- data/LICENSE +19 -0
- data/README.md +16 -0
- data/Rakefile +4 -0
- data/bin/console +5 -0
- data/bin/petli +37 -0
- data/data/character.json +40 -0
- data/data/face_ref +73 -0
- data/lib/petli/animator.rb +137 -0
- data/lib/petli/db.rb +78 -0
- data/lib/petli/hud.rb +42 -0
- data/lib/petli/pet.rb +129 -0
- data/lib/petli/poop.rb +26 -0
- data/lib/petli/rooms/dice.rb +54 -0
- data/lib/petli/rooms/feed.rb +20 -0
- data/lib/petli/rooms/guess.rb +51 -0
- data/lib/petli/rooms/main.rb +17 -0
- data/lib/petli/rooms/play.rb +16 -0
- data/lib/petli/rooms.rb +69 -0
- data/lib/petli/version.rb +3 -0
- data/lib/petli/watch.rb +30 -0
- data/lib/petli.rb +10 -0
- data/lib/tatty/game.rb +80 -0
- data/petli.gemspec +38 -0
- metadata +172 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8b61cbff590146e315f4361603b20a21e0f42cb5ce939ace8b937a821ec59e79
|
4
|
+
data.tar.gz: 3c902c59a736c9c0500caa56408debc5acb64b2436b3572145e09b4ea5b3a097
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a93f33fa7df2d80631d715f63491bef2487752d6e3442ab4acf72c139bda03e0cb32c8853ee7529de7fe8e3ff27bd6168171e4e48310d9457f5f9bf00508b859
|
7
|
+
data.tar.gz: 334c94c480d5d0026427bdc3884d26cbe277f73c63c2329172706a6dfaa1d0d8dd5f9d2c9a6ad9bad19684ba792ab4e430759f8e8e5876853587cf3db64470d6
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
petli (0.0.1)
|
5
|
+
tty-box (~> 0.7.0)
|
6
|
+
tty-color (~> 0.6.0)
|
7
|
+
tty-config (~> 0.5.0)
|
8
|
+
tty-cursor (~> 0.7.1)
|
9
|
+
tty-reader (~> 0.9.0)
|
10
|
+
tty-screen (~> 0.8.1)
|
11
|
+
|
12
|
+
GEM
|
13
|
+
remote: https://rubygems.org/
|
14
|
+
specs:
|
15
|
+
pastel (0.8.0)
|
16
|
+
tty-color (~> 0.5)
|
17
|
+
strings (0.2.1)
|
18
|
+
strings-ansi (~> 0.2)
|
19
|
+
unicode-display_width (>= 1.5, < 3.0)
|
20
|
+
unicode_utils (~> 1.4)
|
21
|
+
strings-ansi (0.2.0)
|
22
|
+
tty-box (0.7.0)
|
23
|
+
pastel (~> 0.8)
|
24
|
+
strings (~> 0.2.0)
|
25
|
+
tty-cursor (~> 0.7)
|
26
|
+
tty-color (0.6.0)
|
27
|
+
tty-config (0.5.0)
|
28
|
+
tty-cursor (0.7.1)
|
29
|
+
tty-reader (0.9.0)
|
30
|
+
tty-cursor (~> 0.7)
|
31
|
+
tty-screen (~> 0.8)
|
32
|
+
wisper (~> 2.0)
|
33
|
+
tty-screen (0.8.1)
|
34
|
+
unicode-display_width (2.0.0)
|
35
|
+
unicode_utils (1.4.0)
|
36
|
+
wisper (2.0.1)
|
37
|
+
|
38
|
+
PLATFORMS
|
39
|
+
arm64-darwin-20
|
40
|
+
|
41
|
+
DEPENDENCIES
|
42
|
+
petli!
|
43
|
+
|
44
|
+
BUNDLED WITH
|
45
|
+
2.2.3
|
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright 2021 Tim Anema
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
7
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
8
|
+
so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
PETLI
|
2
|
+
-----
|
3
|
+
|
4
|
+
Pet line interface (look I know it should have been command line pet like Clipet? Clet? those just don't sound great)
|
5
|
+
|
6
|
+
This is a little pet that will live in your console. You must feed it, clean up after it, and play with it to keep it happy!
|
7
|
+
|
8
|
+

|
9
|
+
|
10
|
+
### Running the app
|
11
|
+
|
12
|
+
```bash
|
13
|
+
$> bundle install
|
14
|
+
$> rake install
|
15
|
+
$> petli
|
16
|
+
```
|
data/Rakefile
ADDED
data/bin/console
ADDED
data/bin/petli
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'petli'
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
options = {}
|
6
|
+
OptionParser.new do |opts|
|
7
|
+
opts.banner = "Usage: petli [options]"
|
8
|
+
opts.on("-r", "--reset", "Reset button to start over again") {|v| options[:reset] = v }
|
9
|
+
opts.on("-s", "--status", "Dump pet status") {|v| options[:status] = v}
|
10
|
+
opts.on("-b", "--bread", "Feed your pet bread without viewing") {|v| options[:bread] = v}
|
11
|
+
opts.on("-c", "--candy", "Feed your pet candy without viewing") {|v| options[:candy] = v}
|
12
|
+
opts.on("-m", "--medicine", "Feed your pet candy without viewing") {|v| options[:medicine] = v}
|
13
|
+
opts.on("-l", "--clean", "Clean up any 'dirt' without viewing") {|v| options[:clean] = v}
|
14
|
+
opts.on("-p", "--path [PATH]", "path to your pet data (defaults to system config dir)") do |v|
|
15
|
+
$petlidboverride = v
|
16
|
+
end
|
17
|
+
end.parse!
|
18
|
+
|
19
|
+
pet = Petli::Pet.new
|
20
|
+
pet.display # force pet to update first
|
21
|
+
|
22
|
+
if options[:reset]
|
23
|
+
Petli::DB.clear
|
24
|
+
puts "Goodbye. I hope you love your next pet!"
|
25
|
+
elsif options[:status]
|
26
|
+
puts Petli::DB.dump
|
27
|
+
elsif options[:bread]
|
28
|
+
pet.feed(food: :bread)
|
29
|
+
elsif options[:candy]
|
30
|
+
pet.feed(food: :candy)
|
31
|
+
elsif options[:medicine]
|
32
|
+
pet.feed(food: :medicine)
|
33
|
+
elsif options[:clean]
|
34
|
+
pet.clean
|
35
|
+
else
|
36
|
+
Petli::HUD.new.run
|
37
|
+
end
|
data/data/character.json
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
{
|
2
|
+
"eyes": {
|
3
|
+
"default": ["O"],
|
4
|
+
"mezmerized": ["◉", "✧", "☯"],
|
5
|
+
"great": ["^", "O"],
|
6
|
+
"happy": ["O", "o"],
|
7
|
+
"tired": ["ළ", "ತ"],
|
8
|
+
"annoyed": ["⊜", "ಠ"],
|
9
|
+
"angry": ["ಠ"],
|
10
|
+
"embarassed": ["ಥ"],
|
11
|
+
"eating": ["O", ["ᗒ", "ᗕ"]],
|
12
|
+
"sick": [["⨴","⨵"],"ꔸ"]
|
13
|
+
},
|
14
|
+
"mouth": {
|
15
|
+
"default": ["_", "."],
|
16
|
+
"mezmerized": ["ᴥ", "O"],
|
17
|
+
"great": ["▽", "‿"],
|
18
|
+
"happy": ["o", "_"],
|
19
|
+
"tired": ["-", "."],
|
20
|
+
"annoyed": ["_", "-"],
|
21
|
+
"angry": ["益", "෴"],
|
22
|
+
"embarassed": ["◠", "-"],
|
23
|
+
"eating": ["▽", "‿"],
|
24
|
+
"sick": ["▱","﹃"]
|
25
|
+
},
|
26
|
+
"arms": {
|
27
|
+
"default": [["ᕠ", "ᕤ"], ["ᕦ", "ᕡ"]],
|
28
|
+
"plain": ["_", "~"],
|
29
|
+
"tired": ["_", "~"],
|
30
|
+
"embarassed": [["乁","ㄏ"], "_"],
|
31
|
+
"eating": [["\\", "/"], "_"],
|
32
|
+
"sick": ["_", "~"]
|
33
|
+
},
|
34
|
+
"head": {
|
35
|
+
"default": [["(", ")"]]
|
36
|
+
},
|
37
|
+
"bread": "ʕ=ʔ",
|
38
|
+
"candy": "▷☯◁",
|
39
|
+
"medicine": "◖◻◗"
|
40
|
+
}
|
data/data/face_ref
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
☠⚕
|
2
|
+
(o . o)
|
3
|
+
(o _ o)
|
4
|
+
(o _ O)
|
5
|
+
(O _ O)
|
6
|
+
(* ^ *)
|
7
|
+
(O _ o)
|
8
|
+
(ʘ _ ʘ)
|
9
|
+
(u _ u)
|
10
|
+
(^ _ ^)
|
11
|
+
(ಠ _ ಠ)
|
12
|
+
(^ o ^)
|
13
|
+
(◉ ᴥ ◉)
|
14
|
+
(o O o)
|
15
|
+
(o - o)
|
16
|
+
(- _ -)
|
17
|
+
(T _ T)
|
18
|
+
(ಥ _ ಥ)
|
19
|
+
(ಠ 益ಠ)
|
20
|
+
(ಠ ෴ ಠ)
|
21
|
+
(ᴗ □ ᴗ)
|
22
|
+
☆゚☆゚☆゚☆゚
|
23
|
+
(o ‿ o)
|
24
|
+
(ᗒ o ᗕ)
|
25
|
+
(⇀ - ↼)
|
26
|
+
(⨴ _ ⨵)
|
27
|
+
(ꔸ _ ꔸ)
|
28
|
+
(ළ _ ළ) # tired
|
29
|
+
(ತ _ ತ)
|
30
|
+
(⊜ _ ⊜)
|
31
|
+
(✧ _ ✧)
|
32
|
+
(☯ _ ☯)
|
33
|
+
|
34
|
+
\(⇀ O ↼)/ ʕ=ʔ
|
35
|
+
_(O _ O)_ =ʔ
|
36
|
+
\(⇀ O ↼)/ =ʔ
|
37
|
+
_(O _ O)_ ʔ
|
38
|
+
\(⇀ O ↼)/ ʔ
|
39
|
+
_(O _ O)_
|
40
|
+
(◉ ᴥ ◉)
|
41
|
+
(o O o)
|
42
|
+
|
43
|
+
ξꔸ ꔸ)
|
44
|
+
|
45
|
+
☛(O _ O)☛
|
46
|
+
☚(O _ O)☚
|
47
|
+
乁(O _ O)ㄏ
|
48
|
+
_(O _ O)_
|
49
|
+
ᕠ(O _ O)ᕤ
|
50
|
+
ᕦ(O _ O)ᕡ
|
51
|
+
\(O _ O)/
|
52
|
+
/(O _ O)\
|
53
|
+
|
54
|
+
ߍ೧
|
55
|
+
༼ºل͟º༽
|
56
|
+
|
57
|
+
poop friend
|
58
|
+
ı ┐ ┌ ┌ ı ı ı ┌ ┐ ┐ ı ı
|
59
|
+
༼ᵔ◡ᵔ༽ ༼ಠ益ಠ༽ ༼ᵔ◡ᵔ༽ ༼ಠ益ಠ༽
|
60
|
+
|
61
|
+
⚀ ⚁ ⚂ ⚃ ⚄ ⚅
|
62
|
+
|
63
|
+
_
|
64
|
+
(O O)
|
65
|
+
|-|
|
66
|
+
|
67
|
+
☠
|
68
|
+
|
69
|
+
┌───┐
|
70
|
+
│ ☠ │
|
71
|
+
│ │
|
72
|
+
```````
|
73
|
+
|
@@ -0,0 +1,137 @@
|
|
1
|
+
module Petli
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
class Animator
|
5
|
+
ANIMATIONS = {
|
6
|
+
egg: [" _\n / \\\n \\_/", " _\n((/ \\\n \\_/))", " _\n / \\))\n((\\_/"]*5,
|
7
|
+
egg_crack: [" _\n/ \\\n\\_‚/"," _\n/ \\\n\\_¡/"," _\n/ \\\n\\_¦/"," _\n/ ¡\\\n\\_ϟ/"," _\n/ ¦\\\n\\_ϟ/"," _\n/ ϟ\\\n\\_ϟ/","\n/ ϟ\\\n\\_ϟ/"," ☁\n/ ϟ\\\n\\_ϟ/"],
|
8
|
+
stand: ["\n\nahe m eha\n", "\n\nahe m eha\n"],
|
9
|
+
left: ["\n\nahe m e ha\n", "\n\nahe m e ha\n"],
|
10
|
+
right: ["\n\nah e m eha\n", "\n\nah e m eha\n"],
|
11
|
+
item: ["\n\nahe m eha fff\n", "\n\nahe m eha fff\n", "\n\nahe m eha fff\n", "\n\nahe m eha fff\n"],
|
12
|
+
eat: ["\n\nahe m eha fff\n", "\n\nahe m eha ff\n", "\n\nahe m eha ff\n", "\n\nahe m eha f\n", "\n\nahe m eha f\n", "\n\nahe m eha\n"],
|
13
|
+
walk: ["\n\n ahe m eha\n", "\n\nahe m e ha\n", "\n\nahe m eha\n", "\n\nah e m eha\n"],
|
14
|
+
hop: ["\n\n ahe m eha\n", "\nahe m e ha\n\n", "\n\nahe m e ha\n", "\n\nahe m eha\n", "\nah e m eha\n\n", "\n\nah e m eha\n"],
|
15
|
+
death: [" ┌───┐ \n │ ☠ │ \n │ │ \n ```````", " ┌───┐ \n │ ☠ │ \n │ │ \n '''''''"],
|
16
|
+
}
|
17
|
+
|
18
|
+
attr_writer :mood
|
19
|
+
attr_reader :action
|
20
|
+
|
21
|
+
def initialize(hatching:, mood:, action: :walk)
|
22
|
+
@frame = 0
|
23
|
+
@food = :bread
|
24
|
+
@mood = mood
|
25
|
+
@action = action
|
26
|
+
if hatching
|
27
|
+
@mood_stack = [:mezmerized, :mezmerized, :mezmerized, :mezmerized]
|
28
|
+
@action_stack = [:egg, :egg_crack, :stand, :stand]
|
29
|
+
else
|
30
|
+
@mood_stack = []
|
31
|
+
@action_stack = []
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def step
|
36
|
+
self.add_frame
|
37
|
+
leftarm, rightarm = getit(:arms, 2)
|
38
|
+
lefteye, righteye = getit(:eyes, 2)
|
39
|
+
mouth = getit(:mouth)
|
40
|
+
lefthead, righthead = getit(:head, 2)
|
41
|
+
[leftarm,lefthead,lefteye,mouth,righteye,righthead,rightarm]
|
42
|
+
|
43
|
+
food_peices = self.food.split('')
|
44
|
+
|
45
|
+
ANIMATIONS[self.action][self.frame]
|
46
|
+
.sub('a', leftarm.to_s).sub('a', rightarm.to_s)
|
47
|
+
.sub('h', lefthead).sub('h', righthead)
|
48
|
+
.sub('e', lefteye).sub('e', righteye)
|
49
|
+
.sub('m', mouth)
|
50
|
+
.reverse
|
51
|
+
.sub('f', food_peices[2]).sub('f', food_peices[1]).sub('f', food_peices[0])
|
52
|
+
.reverse
|
53
|
+
end
|
54
|
+
|
55
|
+
def eat(food: :bread, &block)
|
56
|
+
@busy = true
|
57
|
+
@frame = 0
|
58
|
+
@food = food
|
59
|
+
@action_stack = [:item, :eat, :stand, :stand, :stand, :stand]
|
60
|
+
@mood_stack = [:mezmerized, :eating, :eating, :mezmerized, :mezmerized]
|
61
|
+
@on_complete = block
|
62
|
+
end
|
63
|
+
|
64
|
+
def celebrate
|
65
|
+
@action_stack = [:stand, :stand, :stand, :stand]
|
66
|
+
@mood_stack = [:mezmerized, :mezmerized, :mezmerized, :mezmerized]
|
67
|
+
@frame = 0
|
68
|
+
end
|
69
|
+
|
70
|
+
def embarass
|
71
|
+
@action_stack = [:stand, :stand, :stand, :stand]
|
72
|
+
@mood_stack = [:embarassed, :embarassed, :embarassed, :embarassed]
|
73
|
+
@frame = 0
|
74
|
+
end
|
75
|
+
|
76
|
+
def busy?
|
77
|
+
@busy
|
78
|
+
end
|
79
|
+
|
80
|
+
def action=(act)
|
81
|
+
@action = act
|
82
|
+
@frame = 0
|
83
|
+
end
|
84
|
+
|
85
|
+
def action
|
86
|
+
@action_stack.count > 0 ? @action_stack[0] : @action
|
87
|
+
end
|
88
|
+
|
89
|
+
def mood
|
90
|
+
@mood_stack.count > 0 ? @mood_stack[0] : @mood
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def add_frame
|
96
|
+
frame_count = ANIMATIONS[self.action].count
|
97
|
+
@frame += 1
|
98
|
+
if self.frame == frame_count
|
99
|
+
@frame = 0
|
100
|
+
@action_stack.shift if @action_stack.count > 0
|
101
|
+
@mood_stack.shift if @mood_stack.count > 0
|
102
|
+
if @action_stack.count == 0 && @mood_stack.count == 0
|
103
|
+
@busy = false
|
104
|
+
@on_complete.call unless @on_complete.nil?
|
105
|
+
@on_complete = nil
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def food
|
111
|
+
self.data[@food]
|
112
|
+
end
|
113
|
+
|
114
|
+
def frame # to control framerate
|
115
|
+
(@frame/3).ceil
|
116
|
+
end
|
117
|
+
|
118
|
+
def getit(part, vals=1)
|
119
|
+
mood_part = self.data[part][self.mood] || self.data[part][:default]
|
120
|
+
part_frame = self.frame % mood_part.count
|
121
|
+
result = mood_part[part_frame]
|
122
|
+
if vals == 2 && result.is_a?(String)
|
123
|
+
[result, result]
|
124
|
+
else
|
125
|
+
result
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def data
|
130
|
+
@data ||= JSON.parse(
|
131
|
+
File.read(File.expand_path('../../data/character.json', __dir__)),
|
132
|
+
{:symbolize_names => true}
|
133
|
+
)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
data/lib/petli/db.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
module Petli
|
2
|
+
require "pstore"
|
3
|
+
require "forwardable"
|
4
|
+
require "tty-platform"
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
class DB
|
8
|
+
module Attributes
|
9
|
+
def db_attr(name, default: nil, readonly: false)
|
10
|
+
name = name.to_sym
|
11
|
+
define_method(name) { DB.get(name, default) }
|
12
|
+
define_method("#{name}=".to_sym) { |val| DB.set(name => val) } unless readonly
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
extend SingleForwardable
|
17
|
+
def_delegators :new, :keys, :exists?, :set, :get, :del, :clear, :dump
|
18
|
+
|
19
|
+
attr_reader :db
|
20
|
+
|
21
|
+
def initialize(path: "petli.pet")
|
22
|
+
config_path = if !$petlidboverride.nil?
|
23
|
+
$petlidboverride
|
24
|
+
elsif TTY::Platform.windows?
|
25
|
+
File.join(ENV["APPDATA"], 'petli', 'data.pet')
|
26
|
+
elsif TTY::Platform.linux?
|
27
|
+
File.join(ENV["XDG_CONFIG_DIRS"] || '/etc/xdg', 'petli', 'data.pet')
|
28
|
+
elsif TTY::Platform.mac?
|
29
|
+
File.join(File.expand_path('~/Library/Application Support'), 'petli', 'data.pet')
|
30
|
+
end
|
31
|
+
FileUtils.mkdir_p(File.dirname(config_path))
|
32
|
+
@db = PStore.new(config_path)
|
33
|
+
end
|
34
|
+
|
35
|
+
def keys
|
36
|
+
db.transaction(true) { db.roots }
|
37
|
+
end
|
38
|
+
|
39
|
+
def exists?(key)
|
40
|
+
db.transaction(true) { db.root?(key) }
|
41
|
+
end
|
42
|
+
|
43
|
+
def set(**args)
|
44
|
+
db.transaction do
|
45
|
+
args.each {|key, val| val.nil? ? db.delete(key) : db[key] = val}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def get(key, default=nil)
|
50
|
+
val = db.transaction(true) { db[key] }
|
51
|
+
if val.nil?
|
52
|
+
val = default unless default.nil?
|
53
|
+
val = yield if block_given?
|
54
|
+
db.transaction { db[key] = val }
|
55
|
+
end
|
56
|
+
val
|
57
|
+
end
|
58
|
+
|
59
|
+
def del(*args)
|
60
|
+
db.transaction { args.each { |key| db.delete(key) } }
|
61
|
+
end
|
62
|
+
|
63
|
+
def clear
|
64
|
+
del(*keys)
|
65
|
+
end
|
66
|
+
|
67
|
+
def dump
|
68
|
+
require 'json'
|
69
|
+
begin
|
70
|
+
file = File.new(@db.path, mode: IO::RDONLY | IO::BINARY, encoding: Encoding::ASCII_8BIT)
|
71
|
+
JSON.dump(Marshal::load(file.read))
|
72
|
+
ensure
|
73
|
+
file.close
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
data/lib/petli/hud.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative '../tatty/game'
|
2
|
+
|
3
|
+
module Petli
|
4
|
+
class HUD < Tatty::Game
|
5
|
+
GAME_WIDTH = 28
|
6
|
+
GAME_HEIGHT = 13
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
super()
|
10
|
+
@pet = Pet.new
|
11
|
+
Rooms.enter(@pet)
|
12
|
+
end
|
13
|
+
|
14
|
+
def keypress(event)
|
15
|
+
exit if event.value == "q"
|
16
|
+
return if @pet.busy? || @pet.dead?
|
17
|
+
Rooms.current.keypress(event)
|
18
|
+
end
|
19
|
+
|
20
|
+
def draw
|
21
|
+
h, w = self.screen_size
|
22
|
+
left, top = ((w-GAME_WIDTH)/2).round, ((h-GAME_HEIGHT)/2).round
|
23
|
+
render_box(
|
24
|
+
title: {
|
25
|
+
top_left: " Petli ",
|
26
|
+
bottom_right: " #{@pet.lifetime} days ",
|
27
|
+
},
|
28
|
+
width: GAME_WIDTH,
|
29
|
+
height: GAME_HEIGHT,
|
30
|
+
left: left,
|
31
|
+
top: top,
|
32
|
+
)
|
33
|
+
Rooms.current.draw(self, left, top)
|
34
|
+
render_at(left+1, top+1, status_bar)
|
35
|
+
render_at(left+1, top+GAME_HEIGHT-2, Rooms.current.action_bar)
|
36
|
+
end
|
37
|
+
|
38
|
+
def status_bar
|
39
|
+
"#{"♥"*@pet.health}#{"♡"*(10-@pet.health)} #{"☺"*(10-@pet.happiness)}#{"☻"*@pet.happiness}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/petli/pet.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
module Petli
|
2
|
+
class Pet
|
3
|
+
include Watch
|
4
|
+
extend DB::Attributes
|
5
|
+
|
6
|
+
MOOD_SCALE = [:angry, :annoyed, :normal, :happy, :great]
|
7
|
+
|
8
|
+
db_attr :birth, default: Time.now, readonly: true
|
9
|
+
db_attr :health, default: 5
|
10
|
+
db_attr :mood, default: :normal
|
11
|
+
db_attr :happiness, default: 5
|
12
|
+
db_attr :sick, default: 0
|
13
|
+
db_attr :died_at
|
14
|
+
db_attr :last_play, default: Time.now
|
15
|
+
db_attr :last_meal, default: Time.now
|
16
|
+
db_attr :poops, default: []
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
super()
|
20
|
+
@animation = Animator.new(
|
21
|
+
hatching: (Time.now - self.birth) < 10,
|
22
|
+
mood: self.mood,
|
23
|
+
action: self.died_at.nil? ? :walk : :death
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def reset
|
28
|
+
@animation.action = :walk
|
29
|
+
end
|
30
|
+
|
31
|
+
def display
|
32
|
+
return @animation.step if self.dead?
|
33
|
+
|
34
|
+
if hours_since(self.last_meal) > 1
|
35
|
+
hours_past = hours_since(self.last_meal)
|
36
|
+
self.last_meal = Time.now
|
37
|
+
(0...hours_past).each do |i|
|
38
|
+
self.health = [1, self.health-1].max
|
39
|
+
self.happiness = [1, self.happiness-1].max
|
40
|
+
self.poop(hours_past - i) if rand <= 0.8
|
41
|
+
end
|
42
|
+
self.sick = self.poops.filter{|poop| hours_since(poop.hatch) > 1 }.count
|
43
|
+
end
|
44
|
+
|
45
|
+
if hours_since(self.last_play) > 1
|
46
|
+
hours_past = hours_since(self.last_play)
|
47
|
+
self.last_play = Time.now
|
48
|
+
(0...hours_past).each do
|
49
|
+
self.happiness = [1, self.happiness-1].max
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
self.happiness = [self.happiness, 5].min if self.health <= 3
|
54
|
+
self.mood = MOOD_SCALE[((self.happiness.to_f/10.0)*(MOOD_SCALE.count - 1)).floor ]
|
55
|
+
|
56
|
+
self.check_if_dead
|
57
|
+
|
58
|
+
@animation.mood = self.sick > 0 ? :sick : self.mood
|
59
|
+
@animation.step
|
60
|
+
end
|
61
|
+
|
62
|
+
def check_if_dead
|
63
|
+
not_happy = self.happiness <= 1
|
64
|
+
not_healthy = self.health <= 1
|
65
|
+
is_sick = self.sick > 2
|
66
|
+
too_much_time = days_since(self.last_meal) >= 1
|
67
|
+
|
68
|
+
if not_happy && not_healthy && (is_sick || too_much_time)
|
69
|
+
self.died_at = Time.now
|
70
|
+
@animation.action = :death
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def feed(food: :bread)
|
75
|
+
return self.embarass if ((food == :medicine && self.sick <= 0) || (self.health == 10 && food != :medicine))
|
76
|
+
self.last_meal = Time.now unless food == :medicine
|
77
|
+
@animation.eat(food: food) do
|
78
|
+
self.health = [10, self.health+1].min unless food == :medicine
|
79
|
+
self.happiness = [10, self.happiness+1].min if food == :candy
|
80
|
+
self.sick = [0, self.sick - 1].max if food == :medicine
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def win
|
85
|
+
self.happiness = [10, self.happiness+1].min
|
86
|
+
end
|
87
|
+
|
88
|
+
def lose
|
89
|
+
# todo I dont really want it to become more unhappy if they lose
|
90
|
+
end
|
91
|
+
|
92
|
+
def play(game: :dice)
|
93
|
+
self.last_play = Time.now
|
94
|
+
@animation.action = :stand
|
95
|
+
end
|
96
|
+
|
97
|
+
def poop(hours_ago)
|
98
|
+
self.poops = self.poops + [Poop.new(hours_ago, *Poop::LOCATIONS[self.poops.count])] if self.poops.count < Poop::LOCATIONS.count
|
99
|
+
end
|
100
|
+
|
101
|
+
def clean
|
102
|
+
self.poops = []
|
103
|
+
end
|
104
|
+
|
105
|
+
def busy?
|
106
|
+
@animation.busy?
|
107
|
+
end
|
108
|
+
|
109
|
+
def dead?
|
110
|
+
@animation.action == :death
|
111
|
+
end
|
112
|
+
|
113
|
+
def celebrate
|
114
|
+
@animation.celebrate
|
115
|
+
end
|
116
|
+
|
117
|
+
def embarass
|
118
|
+
@animation.embarass
|
119
|
+
end
|
120
|
+
|
121
|
+
def lifetime
|
122
|
+
if self.died_at.nil?
|
123
|
+
days_since(self.birth).to_i
|
124
|
+
else
|
125
|
+
days_since(self.birth, self.died_at).to_i
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
data/lib/petli/poop.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Petli
|
2
|
+
class Poop
|
3
|
+
include Watch
|
4
|
+
|
5
|
+
LOCATIONS = [[1,1], [1,4], [1,7], [11,1], [11,7], [20,1], [20,4], [20,7]]
|
6
|
+
ANIMATION = ["ı ı ı\n༼ᵔ◡ᵔ༽", "ϟ ϟ ϟ\n༼ಠ益ಠ༽"]
|
7
|
+
|
8
|
+
attr_accessor :hatch
|
9
|
+
|
10
|
+
def initialize(hrsago)
|
11
|
+
@frame = 0
|
12
|
+
self.hatch = hours_ago(hrsago)
|
13
|
+
end
|
14
|
+
|
15
|
+
def step
|
16
|
+
@frame += 1
|
17
|
+
anim_fram = (@frame/2).ceil
|
18
|
+
@frame = 0 if anim_fram >= ANIMATION.count
|
19
|
+
ANIMATION[anim_fram]
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_json(opts)
|
23
|
+
self.hatch.to_json
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Petli
|
2
|
+
module Rooms
|
3
|
+
class Dice < Room
|
4
|
+
Symbols = %w(⚀ ⚁ ⚂ ⚃ ⚄ ⚅)
|
5
|
+
|
6
|
+
def initialize(pet)
|
7
|
+
super(pet)
|
8
|
+
@value = rand(1..6)
|
9
|
+
@countdown = -1
|
10
|
+
end
|
11
|
+
|
12
|
+
def actions
|
13
|
+
%w(higher lower)
|
14
|
+
end
|
15
|
+
|
16
|
+
def enter
|
17
|
+
pet.play(game: :guess)
|
18
|
+
end
|
19
|
+
|
20
|
+
def leave
|
21
|
+
pet.reset
|
22
|
+
end
|
23
|
+
|
24
|
+
def roll
|
25
|
+
end
|
26
|
+
|
27
|
+
def keypress(event)
|
28
|
+
return if event.value != "h" and event.value != "l"
|
29
|
+
@pickedhigher = event.value == "h"
|
30
|
+
@pick = (1..6).to_a.sample
|
31
|
+
@won = (event.value == "h" && @pick > @value) || (event.value == "l" && @pick < @value)
|
32
|
+
@won ? @pet.celebrate : @pet.embarass
|
33
|
+
@countdown = 20
|
34
|
+
end
|
35
|
+
|
36
|
+
def draw(ctx, ox, oy)
|
37
|
+
ctx.render_at(ox+9, oy+4, @pet.display)
|
38
|
+
if @countdown == -1
|
39
|
+
ctx.render_at(ox+4, oy+6, @value.to_s)
|
40
|
+
ctx.render_at(ox+23, oy+6, Symbols[(0..5).to_a.sample])
|
41
|
+
elsif @countdown == 0
|
42
|
+
@won ? @pet.win : @pet.lose
|
43
|
+
goto("main")
|
44
|
+
else
|
45
|
+
ctx.render_at(ox+4, oy+5, "▲") if @pickedhigher
|
46
|
+
ctx.render_at(ox+4, oy+6, @value.to_s)
|
47
|
+
ctx.render_at(ox+23, oy+6, Symbols[@pick-1])
|
48
|
+
ctx.render_at(ox+4, oy+7, "▼") unless @pickedhigher
|
49
|
+
@countdown -= 1
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Petli
|
2
|
+
module Rooms
|
3
|
+
class Feed < Room
|
4
|
+
def actions
|
5
|
+
%w(bread snack med)
|
6
|
+
end
|
7
|
+
|
8
|
+
def keypress(event)
|
9
|
+
if event.value == "b"
|
10
|
+
@pet.feed(food: :bread)
|
11
|
+
elsif event.value == "s"
|
12
|
+
@pet.feed(food: :candy)
|
13
|
+
elsif event.value == "m"
|
14
|
+
@pet.feed(food: :medicine)
|
15
|
+
end
|
16
|
+
goto("main")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Petli
|
2
|
+
module Rooms
|
3
|
+
class Guess < Room
|
4
|
+
def initialize(pet)
|
5
|
+
super(pet)
|
6
|
+
@left = true
|
7
|
+
@countdown = -1
|
8
|
+
end
|
9
|
+
|
10
|
+
def actions
|
11
|
+
%w(left right)
|
12
|
+
end
|
13
|
+
|
14
|
+
def enter
|
15
|
+
pet.play(game: :guess)
|
16
|
+
end
|
17
|
+
|
18
|
+
def leave
|
19
|
+
pet.reset
|
20
|
+
end
|
21
|
+
|
22
|
+
def keypress(event)
|
23
|
+
return if event.value != "l" and event.value != "r"
|
24
|
+
@petpickedleft = rand(1..2) == 1
|
25
|
+
@pickedleft = event.value == "l"
|
26
|
+
(@petpickedleft == @pickedleft) ? @pet.celebrate : @pet.embarass
|
27
|
+
@countdown = 20
|
28
|
+
end
|
29
|
+
|
30
|
+
def draw(ctx, ox, oy)
|
31
|
+
ctx.render_at(ox+9, oy+4, @pet.display)
|
32
|
+
if @countdown == -1
|
33
|
+
ctx.render_at(ox+4, oy+5, "☟") if @left
|
34
|
+
ctx.render_at(ox+23, oy+5, "☟") unless @left
|
35
|
+
ctx.render_at(ox+4, oy+6, "▒") if @left
|
36
|
+
ctx.render_at(ox+23, oy+6, "▒") unless @left
|
37
|
+
@left = !@left
|
38
|
+
elsif @countdown == 0
|
39
|
+
(@petpickedleft == @pickedleft) ? @pet.win : @pet.lose
|
40
|
+
goto("main")
|
41
|
+
else
|
42
|
+
ctx.render_at(ox+4, oy+5, "☟") if @pickedleft
|
43
|
+
ctx.render_at(ox+23, oy+5, "☟") unless @pickedleft
|
44
|
+
ctx.render_at(ox+4, oy+6, "▒") if @petpickedleft
|
45
|
+
ctx.render_at(ox+23, oy+6, "▒") unless @petpickedleft
|
46
|
+
@countdown -= 1
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Petli
|
2
|
+
module Rooms
|
3
|
+
class Main < Room
|
4
|
+
def actions
|
5
|
+
acts = %w(play feed)
|
6
|
+
acts << "clean" if @pet.poops.count > 0
|
7
|
+
acts
|
8
|
+
end
|
9
|
+
|
10
|
+
def keypress(event)
|
11
|
+
return goto("feed") if event.value == "f"
|
12
|
+
return @pet.clean if event.value == "c"
|
13
|
+
return goto("play") if event.value == "p"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/petli/rooms.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
module Petli
|
2
|
+
module Rooms
|
3
|
+
class Room
|
4
|
+
attr_reader :pet
|
5
|
+
|
6
|
+
def initialize(pet)
|
7
|
+
@pet = pet
|
8
|
+
end
|
9
|
+
|
10
|
+
def enter
|
11
|
+
end
|
12
|
+
|
13
|
+
def goto(room_name)
|
14
|
+
klass = ::Petli.const_get("Rooms::#{room_name.capitalize}")
|
15
|
+
self.leave unless klass.nil?
|
16
|
+
::Petli::Rooms.goto(klass)
|
17
|
+
end
|
18
|
+
|
19
|
+
def leave
|
20
|
+
end
|
21
|
+
|
22
|
+
def actions
|
23
|
+
%w()
|
24
|
+
end
|
25
|
+
|
26
|
+
def action_bar
|
27
|
+
return "" if @pet.dead?
|
28
|
+
self.actions.map {|a| "[#{a[0]}]#{a[1..]}"}.join(" ")
|
29
|
+
end
|
30
|
+
|
31
|
+
def keypress(event)
|
32
|
+
end
|
33
|
+
|
34
|
+
def draw(ctx, ox, oy)
|
35
|
+
poops = @pet.poops
|
36
|
+
poops.each_with_index do |poop, i|
|
37
|
+
x, y = Poop::LOCATIONS[i]
|
38
|
+
ctx.render_at(ox+1+x, oy+1+y, poop.step)
|
39
|
+
end
|
40
|
+
@pet.poops = poops
|
41
|
+
ctx.render_at(ox+9, oy+4, @pet.display)
|
42
|
+
sick = @pet.sick
|
43
|
+
if sick > 0 && !@pet.dead?
|
44
|
+
ctx.render_at(ox+11-sick, oy+4, "[#{'!'*sick}SICK#{'!'*sick}]")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
autoload :Main, "petli/rooms/main"
|
50
|
+
autoload :Feed, "petli/rooms/feed"
|
51
|
+
autoload :Play, "petli/rooms/play"
|
52
|
+
autoload :Guess, "petli/rooms/guess"
|
53
|
+
autoload :Dice, "petli/rooms/dice"
|
54
|
+
|
55
|
+
def self.current
|
56
|
+
@room
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.enter(pet)
|
60
|
+
@pet = pet
|
61
|
+
goto(Main)
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.goto(klass)
|
65
|
+
@room = klass.new(@pet)
|
66
|
+
@room.enter
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/petli/watch.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module Petli
|
2
|
+
DAYS_DIV = 86400
|
3
|
+
HOURS_DIV = 3600
|
4
|
+
MINS_DIV = 60
|
5
|
+
|
6
|
+
module Watch
|
7
|
+
require 'time'
|
8
|
+
private
|
9
|
+
|
10
|
+
def days_since(last, now=Time.now)
|
11
|
+
time_elapsed(last, DAYS_DIV, now)
|
12
|
+
end
|
13
|
+
|
14
|
+
def hours_since(last)
|
15
|
+
time_elapsed(last, HOURS_DIV)
|
16
|
+
end
|
17
|
+
|
18
|
+
def hours_ago(hrs)
|
19
|
+
Time.now - (hrs * 3600)
|
20
|
+
end
|
21
|
+
|
22
|
+
def mins_since(last)
|
23
|
+
time_elapsed(last, MINS_DIV)
|
24
|
+
end
|
25
|
+
|
26
|
+
def time_elapsed(last, div, now=Time.now)
|
27
|
+
((now - Time.parse(last.to_s)) / div)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/petli.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
module Petli
|
2
|
+
autoload :Animator, "petli/animator"
|
3
|
+
autoload :DB, "petli/db"
|
4
|
+
autoload :HUD, "petli/hud"
|
5
|
+
autoload :Pet, "petli/pet"
|
6
|
+
autoload :Poop, "petli/poop"
|
7
|
+
autoload :Rooms, "petli/rooms"
|
8
|
+
autoload :Watch, "petli/watch"
|
9
|
+
autoload :Version, "petli/version"
|
10
|
+
end
|
data/lib/tatty/game.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
module Tatty
|
2
|
+
require 'tty-cursor'
|
3
|
+
require 'tty-config'
|
4
|
+
require 'tty-screen'
|
5
|
+
require 'tty-reader'
|
6
|
+
require 'tty-box'
|
7
|
+
|
8
|
+
class Game
|
9
|
+
attr_accessor :framerate, :config
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@config = TTY::Config.new
|
13
|
+
@cursor = TTY::Cursor
|
14
|
+
@reader = TTY::Reader.new
|
15
|
+
@framerate = 0.1
|
16
|
+
@buffer = ""
|
17
|
+
|
18
|
+
@reader.on(:keypress) do |event|
|
19
|
+
self.keypress(event)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def screen_size
|
24
|
+
TTY::Screen.size
|
25
|
+
end
|
26
|
+
|
27
|
+
def move_to(x, y)
|
28
|
+
render @cursor.move_to(x, y)
|
29
|
+
end
|
30
|
+
|
31
|
+
def render(out)
|
32
|
+
@buffer += out
|
33
|
+
end
|
34
|
+
|
35
|
+
def render_at(x, y, out)
|
36
|
+
out.to_s.each_line do |line|
|
37
|
+
render @cursor.move_to(x, y)
|
38
|
+
render line
|
39
|
+
y += 1
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def keypress(event)
|
44
|
+
end
|
45
|
+
|
46
|
+
def draw
|
47
|
+
render "not implemented"
|
48
|
+
end
|
49
|
+
|
50
|
+
def run
|
51
|
+
begin
|
52
|
+
@cursor.invisible do
|
53
|
+
while true
|
54
|
+
@reader.read_keypress(nonblock: true)
|
55
|
+
last_buffer = @buffer
|
56
|
+
@buffer = ""
|
57
|
+
render @cursor.clear_screen
|
58
|
+
move_to(0, 0)
|
59
|
+
self.draw
|
60
|
+
if last_buffer != @buffer
|
61
|
+
print @buffer
|
62
|
+
end
|
63
|
+
sleep(@framerate)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
rescue Interrupt => e
|
67
|
+
ensure
|
68
|
+
print @cursor.clear_screen
|
69
|
+
print @cursor.move_to(0, 0)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def render_box(*content, **kwargs, &block)
|
74
|
+
render @cursor.save
|
75
|
+
move_to(0, 0)
|
76
|
+
render TTY::Box.frame(*content, **kwargs, &block)
|
77
|
+
render @cursor.restore
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/petli.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
$:.unshift File.expand_path('../lib', __FILE__)
|
4
|
+
require 'petli/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = 'petli'
|
8
|
+
s.version = Petli::VERSION
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.author = 'Tim Anema'
|
11
|
+
s.email = ['timanema@gmail.com']
|
12
|
+
s.homepage = 'https://github.com/tanema/petli'
|
13
|
+
s.license = "MIT"
|
14
|
+
s.summary = 'A little pet in your console'
|
15
|
+
s.description = <<~HERE
|
16
|
+
A virtual pet that will live in your command line!
|
17
|
+
HERE
|
18
|
+
s.post_install_message = <<~HERE
|
19
|
+
I am so happy to meet you!
|
20
|
+
ʕ=ʔ 乁(☯ ᴥ ☯)ㄏ ▷☯◁
|
21
|
+
HERE
|
22
|
+
s.metadata = { "source_code_uri" => "https://github.com/tanema/petli" }
|
23
|
+
|
24
|
+
s.files = Dir.glob('{bin/*,lib/**/*,data/*,[A-Z]*}')
|
25
|
+
s.bindir = "bin"
|
26
|
+
s.executables = ["petli"]
|
27
|
+
s.require_paths = ['lib']
|
28
|
+
|
29
|
+
s.required_ruby_version = ">= 2.6"
|
30
|
+
|
31
|
+
s.add_dependency("tty-cursor", "~> 0.7.1")
|
32
|
+
s.add_dependency("tty-config", "~> 0.5.0")
|
33
|
+
s.add_dependency("tty-screen", "~> 0.8.1")
|
34
|
+
s.add_dependency("tty-reader", "~> 0.9.0")
|
35
|
+
s.add_dependency("tty-color", "~> 0.6.0")
|
36
|
+
s.add_dependency("tty-box", "~> 0.7.0")
|
37
|
+
s.add_dependency("tty-platform", "~> 0.3.0")
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: petli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tim Anema
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-08-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: tty-cursor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.7.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.7.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: tty-config
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.5.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.5.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: tty-screen
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.8.1
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.8.1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: tty-reader
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.9.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.9.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: tty-color
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.6.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.6.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: tty-box
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.7.0
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.7.0
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: tty-platform
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.3.0
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.3.0
|
111
|
+
description: 'A virtual pet that will live in your command line!
|
112
|
+
|
113
|
+
'
|
114
|
+
email:
|
115
|
+
- timanema@gmail.com
|
116
|
+
executables:
|
117
|
+
- petli
|
118
|
+
extensions: []
|
119
|
+
extra_rdoc_files: []
|
120
|
+
files:
|
121
|
+
- Gemfile
|
122
|
+
- Gemfile.lock
|
123
|
+
- LICENSE
|
124
|
+
- README.md
|
125
|
+
- Rakefile
|
126
|
+
- bin/console
|
127
|
+
- bin/petli
|
128
|
+
- data/character.json
|
129
|
+
- data/face_ref
|
130
|
+
- lib/petli.rb
|
131
|
+
- lib/petli/animator.rb
|
132
|
+
- lib/petli/db.rb
|
133
|
+
- lib/petli/hud.rb
|
134
|
+
- lib/petli/pet.rb
|
135
|
+
- lib/petli/poop.rb
|
136
|
+
- lib/petli/rooms.rb
|
137
|
+
- lib/petli/rooms/dice.rb
|
138
|
+
- lib/petli/rooms/feed.rb
|
139
|
+
- lib/petli/rooms/guess.rb
|
140
|
+
- lib/petli/rooms/main.rb
|
141
|
+
- lib/petli/rooms/play.rb
|
142
|
+
- lib/petli/version.rb
|
143
|
+
- lib/petli/watch.rb
|
144
|
+
- lib/tatty/game.rb
|
145
|
+
- petli.gemspec
|
146
|
+
homepage: https://github.com/tanema/petli
|
147
|
+
licenses:
|
148
|
+
- MIT
|
149
|
+
metadata:
|
150
|
+
source_code_uri: https://github.com/tanema/petli
|
151
|
+
post_install_message: |
|
152
|
+
I am so happy to meet you!
|
153
|
+
ʕ=ʔ 乁(☯ ᴥ ☯)ㄏ ▷☯◁
|
154
|
+
rdoc_options: []
|
155
|
+
require_paths:
|
156
|
+
- lib
|
157
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
158
|
+
requirements:
|
159
|
+
- - ">="
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: '2.6'
|
162
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
requirements: []
|
168
|
+
rubygems_version: 3.2.3
|
169
|
+
signing_key:
|
170
|
+
specification_version: 4
|
171
|
+
summary: A little pet in your console
|
172
|
+
test_files: []
|