petli 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
![image](https://user-images.githubusercontent.com/463193/127347754-a07f71a0-b8c4-4d73-a24f-0bf78fca22b9.png)
|
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: []
|