sapling-dialogue 0.1.0 → 0.1.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 +4 -4
- data/lib/sapling.rb +7 -6
- data/lib/sapling/dialogue.rb +39 -37
- data/lib/sapling/gardner.rb +79 -31
- data/lib/sapling/utility.rb +21 -23
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3acc37ddfad7efb3df53deafd404aea470df1fc7
|
|
4
|
+
data.tar.gz: ce6e29ac7f95c6c0db76cfeffb2e3ba86c1ba81f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: efe7c71965dc68be6471cf121102678c9a54a2c77bc379016db257c89a8bbb25d74300fc1eecb5f1cf3be62e01bfc9908a0730fc1951a3e6d3f55f15bb8aaed7
|
|
7
|
+
data.tar.gz: ecfa454ac7df9d6f4e2d21b6a31051a20d690beb2df16a69cfab249e6af97f0d94559be0bc0ce61b1f3652ee2dfbad3624ed4b4c49ef5ba5a4f8f88f5efb7763
|
data/lib/sapling.rb
CHANGED
|
@@ -8,19 +8,20 @@ Dir[File.join(__dir__, 'sapling', '*.rb')].each { |file| require file }
|
|
|
8
8
|
# The main Sapling interface.
|
|
9
9
|
class Sapling < Thor
|
|
10
10
|
desc 'read TREE', 'Load and traverse the TREE'
|
|
11
|
-
def read(
|
|
12
|
-
exit unless verify_tree(tree)
|
|
11
|
+
def read(file)
|
|
13
12
|
puts 'Welcome to Sapling, a Dialogue Tree Utility.'
|
|
14
|
-
|
|
13
|
+
exit unless verify_tree(file)
|
|
14
|
+
tree = Gardner::Plot.new(YAML.load_file(file))
|
|
15
|
+
speaker = Dialogue::Speaker.new(tree, false)
|
|
15
16
|
speaker.conversation
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
desc 'edit TREE', 'Edit a new or existing TREE'
|
|
19
|
-
def edit(
|
|
20
|
+
def edit(file = '')
|
|
20
21
|
puts 'Welcome to Sapling, a Dialogue Tree Utility.'
|
|
21
22
|
if !tree.empty?
|
|
22
|
-
puts "Loading tree: #{
|
|
23
|
-
exit unless verify_tree(
|
|
23
|
+
puts "Loading tree: #{file}"
|
|
24
|
+
exit unless verify_tree(file)
|
|
24
25
|
gardner = Planter::Spade.new(YAML.load_file(tree, false))
|
|
25
26
|
else
|
|
26
27
|
puts 'Creating a new tree!'
|
data/lib/sapling/dialogue.rb
CHANGED
|
@@ -2,16 +2,15 @@ require_relative './gardner'
|
|
|
2
2
|
|
|
3
3
|
# Dialogue is the module for traversing an existing tree.
|
|
4
4
|
module Dialogue
|
|
5
|
-
|
|
6
5
|
# Format and display the trunk
|
|
7
6
|
#
|
|
8
7
|
# @param trunk [Hash] The trunk hash
|
|
9
8
|
# @param debug [Boolean] The status of showing debug information
|
|
10
|
-
def self.display_trunk(trunk, debug=false)
|
|
11
|
-
40.times { print
|
|
9
|
+
def self.display_trunk(trunk, debug = false)
|
|
10
|
+
40.times { print '-' }
|
|
12
11
|
puts "\n[ Trunk ]\n" if debug
|
|
13
|
-
puts "\n#{trunk[
|
|
14
|
-
40.times { print
|
|
12
|
+
puts "\n#{trunk['trunk']}"
|
|
13
|
+
40.times { print '-' }
|
|
15
14
|
puts "\n"
|
|
16
15
|
end
|
|
17
16
|
|
|
@@ -20,11 +19,11 @@ module Dialogue
|
|
|
20
19
|
# @param branch [Hash] A branch data set
|
|
21
20
|
# @param branch_no [Integer] The branch number
|
|
22
21
|
# @param debug [Boolean] Status of showing debug information
|
|
23
|
-
def self.display_branch(branch, branch_no, debug=false)
|
|
22
|
+
def self.display_branch(branch, branch_no, debug = false)
|
|
24
23
|
puts "\n[ Branch: #{branch_no} ]" if debug
|
|
25
|
-
puts "\n#{branch[
|
|
24
|
+
puts "\n#{branch['desc']}\n\n"
|
|
26
25
|
|
|
27
|
-
branch[
|
|
26
|
+
branch['options'].each_pair do |k, v|
|
|
28
27
|
puts "\t#{k}: #{v.keys[0]}"
|
|
29
28
|
puts "\t\t[ Goes to branch #{v.values[0]} ]\n" if debug
|
|
30
29
|
end
|
|
@@ -32,30 +31,27 @@ module Dialogue
|
|
|
32
31
|
|
|
33
32
|
# Speaker holds the functionality for going through a dialogue tree.
|
|
34
33
|
class Speaker
|
|
35
|
-
# The
|
|
36
|
-
|
|
34
|
+
# The tree, an instance of Gardner::Plot
|
|
35
|
+
attr_reader :tree
|
|
37
36
|
# Status of verbose/debug mode. True = on; false = off.
|
|
38
|
-
|
|
37
|
+
attr_reader :debug
|
|
39
38
|
|
|
40
|
-
def initialize(
|
|
41
|
-
@
|
|
39
|
+
def initialize(tree, debug = false)
|
|
40
|
+
@tree = tree
|
|
42
41
|
@debug = debug
|
|
43
42
|
end
|
|
44
43
|
|
|
45
44
|
# Conversation handles navigating the tree, until the option to end is
|
|
46
45
|
# reached.
|
|
47
|
-
def conversation
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
Dialogue.display_trunk(tree[0], false)
|
|
51
|
-
branches = Gardner.prune_branches(tree[1])
|
|
46
|
+
def conversation
|
|
47
|
+
Dialogue.display_trunk(@tree.trunk, @debug)
|
|
52
48
|
|
|
53
49
|
next_branch = 1
|
|
54
|
-
until next_branch
|
|
55
|
-
next_branch = talk(branches[next_branch], next_branch)
|
|
50
|
+
until next_branch.zero?
|
|
51
|
+
next_branch = talk(@tree.branches[next_branch], next_branch)
|
|
56
52
|
end
|
|
57
53
|
|
|
58
|
-
puts "\n#{branches[0][
|
|
54
|
+
puts "\n#{@tree.branches[0]['desc']}"
|
|
59
55
|
exit
|
|
60
56
|
end
|
|
61
57
|
|
|
@@ -65,25 +61,18 @@ module Dialogue
|
|
|
65
61
|
# @param branch_no [Integer] The branch number
|
|
66
62
|
# @return [Integer] The number of the next branch
|
|
67
63
|
def talk(branch, branch_no)
|
|
68
|
-
|
|
69
|
-
# branch. Return 0, and end the program.
|
|
70
|
-
if branch["options"].empty?
|
|
71
|
-
puts "\n#{branch["desc"]}\n\n"
|
|
72
|
-
return 0
|
|
73
|
-
end
|
|
64
|
+
return 0 if terminal?(branch)
|
|
74
65
|
|
|
75
66
|
Dialogue.display_branch(branch, branch_no, @debug)
|
|
76
67
|
|
|
77
68
|
response = get_response(branch)
|
|
78
69
|
|
|
79
|
-
unless response
|
|
80
|
-
puts "
|
|
81
|
-
|
|
82
|
-
puts "\n(Your choice: #{branch["options"][response].keys[0]})"
|
|
83
|
-
response = branch["options"][response].values[0].to_i
|
|
70
|
+
unless response.zero?
|
|
71
|
+
puts "(Your choice: #{branch['options'][response].keys[0]})"
|
|
72
|
+
response = branch['options'][response].values[0].to_i
|
|
84
73
|
end
|
|
85
74
|
|
|
86
|
-
|
|
75
|
+
response
|
|
87
76
|
end
|
|
88
77
|
|
|
89
78
|
# Get a response for the displayed branch
|
|
@@ -91,20 +80,33 @@ module Dialogue
|
|
|
91
80
|
# @param branch [Hash] A branch data set
|
|
92
81
|
# @return [Integer] the next branch
|
|
93
82
|
def get_response(branch)
|
|
94
|
-
valid_options = branch[
|
|
83
|
+
valid_options = branch['options'].keys.join(', ')
|
|
95
84
|
|
|
96
85
|
print "\n[#{valid_options}]> "
|
|
97
86
|
STDOUT.flush
|
|
98
87
|
response = STDIN.gets.chomp.to_i
|
|
99
88
|
|
|
100
|
-
until branch[
|
|
101
|
-
print
|
|
89
|
+
until branch['options'].keys.include?(response) || response.zero?
|
|
90
|
+
print '[## Invalid options. '
|
|
102
91
|
print "Valid options are #{valid_options}, or 0 to exit."
|
|
103
92
|
print "\n[#{valid_options}]> "
|
|
104
93
|
response = STDIN.gets.chomp.to_i
|
|
105
94
|
end
|
|
106
95
|
|
|
107
|
-
|
|
96
|
+
response
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Check if a branch is terminal
|
|
100
|
+
#
|
|
101
|
+
# @param branch [Hash] A branch data set
|
|
102
|
+
# @return [Boolean] true if the branch is terminal, false otherwise
|
|
103
|
+
def terminal?(branch)
|
|
104
|
+
if branch['options'].empty?
|
|
105
|
+
puts "\n#{branch['desc']}\n\n"
|
|
106
|
+
return true
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
false
|
|
108
110
|
end
|
|
109
111
|
end
|
|
110
112
|
end
|
data/lib/sapling/gardner.rb
CHANGED
|
@@ -2,47 +2,95 @@ require 'yaml'
|
|
|
2
2
|
|
|
3
3
|
# Gardner is the module for working with a dialogue tree file
|
|
4
4
|
module Gardner
|
|
5
|
+
# The Plot class handles a specific tree file. It provides functionality for
|
|
6
|
+
# parsing trunks and branches, and provides these as class attributes.
|
|
7
|
+
class Plot
|
|
8
|
+
# The trunk and branches instance variables
|
|
9
|
+
attr_reader :branches, :tree, :trunk
|
|
5
10
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
branches[b["branch"]["number"]] = {
|
|
14
|
-
"desc" => b["branch"]["text"],
|
|
15
|
-
"options" => prune_leaves(b["branch"]["leaf"]) }
|
|
11
|
+
# Initialize a new Plot from a tree file
|
|
12
|
+
#
|
|
13
|
+
# @param tree [File] The dialogue tree file
|
|
14
|
+
def initialize(file)
|
|
15
|
+
@tree = file
|
|
16
|
+
prune_trunk
|
|
17
|
+
prune_branches
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
# Parse the tree array into an array of numbered branches, and ordered
|
|
21
|
+
# leaves.
|
|
22
|
+
#
|
|
23
|
+
# @param tree [File] The dialogue tree
|
|
24
|
+
# @return [Array] An array of numbered branches, with numbered leaves
|
|
25
|
+
def prune_branches
|
|
26
|
+
@branches = { 0 => { 'desc' => 'Thanks for using Sapling!' } }
|
|
27
|
+
@tree.each do |b|
|
|
28
|
+
@branches[b['branch']['number']] = {
|
|
29
|
+
'desc' => b['branch']['text'],
|
|
30
|
+
'options' => prune_leaves(b['branch']['leaf'])
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Parse the leaves of a branch into a numbered hash of options.
|
|
36
|
+
#
|
|
37
|
+
# @param leaves [Array] The option of leaf hashes
|
|
38
|
+
# @return [Hash] A numbered hash of options
|
|
39
|
+
def prune_leaves(leaves)
|
|
40
|
+
x = 1
|
|
41
|
+
options = {}
|
|
20
42
|
|
|
21
|
-
|
|
22
|
-
#
|
|
23
|
-
# @param leaves [Array] The option of leaf hashes
|
|
24
|
-
# @return [Hash] A numbered hash of options
|
|
25
|
-
def self.prune_leaves(leaves)
|
|
26
|
-
x = 1
|
|
27
|
-
options = {}
|
|
43
|
+
return options if leaves.nil?
|
|
28
44
|
|
|
29
|
-
|
|
45
|
+
leaves.each do |l|
|
|
46
|
+
options[x] = { l['text'] => l['branch'] }
|
|
47
|
+
x += 1
|
|
48
|
+
end
|
|
30
49
|
|
|
31
|
-
|
|
32
|
-
options[x] = { l["text"] => l["branch"] }
|
|
33
|
-
x += 1
|
|
50
|
+
options
|
|
34
51
|
end
|
|
35
52
|
|
|
36
|
-
|
|
53
|
+
# Parse the trunk of the tree.
|
|
54
|
+
#
|
|
55
|
+
# @return [Array] The trunk, and the remainder of the tree
|
|
56
|
+
def prune_trunk
|
|
57
|
+
@trunk = @tree.shift
|
|
58
|
+
end
|
|
37
59
|
end
|
|
38
60
|
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
61
|
+
# Digiplot represents a Plot used for editing. The Digiplot functions exactly
|
|
62
|
+
# like a Plot, except with additional functionality for over-writing existing
|
|
63
|
+
# branches, leaves, and the trunk.
|
|
64
|
+
class Digiplot < Plot
|
|
65
|
+
# Duplicate the "old" trunk and branches, for restoration purposes
|
|
66
|
+
attr_reader :old_branches, :old_trunk
|
|
67
|
+
|
|
68
|
+
# Enable editing for the trunk
|
|
69
|
+
attr_writer :trunk
|
|
45
70
|
|
|
46
|
-
|
|
71
|
+
# Initialize a Digiplot just like a Plot, but also copy the trunk and
|
|
72
|
+
# branches to "old" instance variables.
|
|
73
|
+
def initialize
|
|
74
|
+
super
|
|
75
|
+
@old_trunk = @trunk
|
|
76
|
+
@old_branches = @branches
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Change a branch
|
|
80
|
+
#
|
|
81
|
+
# @param branch [Integer] the number of the branch to be edited
|
|
82
|
+
def branch=(branch, text)
|
|
83
|
+
@branches[branch]['desc'] = text
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Change a leaf on a branch, grasshopper
|
|
87
|
+
#
|
|
88
|
+
# @param branch [Integer] the number of the branch to be edited
|
|
89
|
+
# @param leaf [Integer] the number of the leaf to be edited
|
|
90
|
+
# @param text [String] the new text for the leaf
|
|
91
|
+
# @param target [Integer] the branch number target for the leaf option
|
|
92
|
+
def leaf=(branch, leaf, text, target)
|
|
93
|
+
@branches[branch]['options'][leaf] = { text => target }
|
|
94
|
+
end
|
|
47
95
|
end
|
|
48
96
|
end
|
data/lib/sapling/utility.rb
CHANGED
|
@@ -7,34 +7,32 @@
|
|
|
7
7
|
# documentation.
|
|
8
8
|
|
|
9
9
|
# The default trunk text of a new tree
|
|
10
|
-
SKELE_TRUNK_TEXT =
|
|
11
|
-
documentation!
|
|
10
|
+
SKELE_TRUNK_TEXT = 'Welcome to the Sapling Editor. For details, please see the
|
|
11
|
+
documentation!'.freeze
|
|
12
12
|
|
|
13
13
|
# The default first-branch text of a new tree
|
|
14
|
-
SKELE_BRANCH_TEXT =
|
|
15
|
-
as the introduction to the story. From here, the user enters your world!
|
|
14
|
+
SKELE_BRANCH_TEXT = 'The first branch is always shown by default. It should act
|
|
15
|
+
as the introduction to the story. From here, the user enters your world!'.freeze
|
|
16
16
|
|
|
17
17
|
# The default first-leaf text of the first branch of a new tree. The leaf points
|
|
18
18
|
# to it's own branch. The only way out of the program is to either force-quit or
|
|
19
19
|
# reply with option 0.
|
|
20
|
-
SKELE_LEAF_TEXT =
|
|
20
|
+
SKELE_LEAF_TEXT = 'Each branch can have any number of leaves, which represent
|
|
21
21
|
the options a user has on that branch. Each leaf points to another branch, or
|
|
22
|
-
can point to branch 0 to immediately exit.
|
|
22
|
+
can point to branch 0 to immediately exit.'.freeze
|
|
23
23
|
|
|
24
24
|
# The final tree
|
|
25
25
|
SKELETON_TREE = [
|
|
26
|
-
{
|
|
27
|
-
{
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
]
|
|
37
|
-
|
|
26
|
+
{ 'trunk' => SKELE_TRUNK_TEXT.to_s },
|
|
27
|
+
{ 'branch' => {
|
|
28
|
+
'number' => 1,
|
|
29
|
+
'text' => SKELE_BRANCH_TEXT.to_s,
|
|
30
|
+
'leaf' => [{
|
|
31
|
+
'text' => SKELE_LEAF_TEXT.to_s,
|
|
32
|
+
'branch' => 1
|
|
33
|
+
}]
|
|
34
|
+
} }
|
|
35
|
+
].freeze
|
|
38
36
|
|
|
39
37
|
# Verify that a file is a dialogue tree file.
|
|
40
38
|
#
|
|
@@ -44,13 +42,13 @@ def verify_tree(file)
|
|
|
44
42
|
results = []
|
|
45
43
|
begin
|
|
46
44
|
tree = YAML.load_file(file)
|
|
47
|
-
results << tree[0].keys.include?(
|
|
48
|
-
results << tree[1][
|
|
49
|
-
results << tree[1][
|
|
50
|
-
results << tree[1][
|
|
45
|
+
results << tree[0].keys.include?('trunk')
|
|
46
|
+
results << tree[1]['branch'].keys.include?('number')
|
|
47
|
+
results << tree[1]['branch'].keys.include?('text')
|
|
48
|
+
results << tree[1]['branch'].keys.include?('leaf')
|
|
51
49
|
rescue
|
|
52
50
|
puts "Sorry chummer, I don't think this is a tree."
|
|
53
|
-
puts
|
|
51
|
+
puts 'Verify your YAML file is formatted properly.'
|
|
54
52
|
results << false
|
|
55
53
|
end
|
|
56
54
|
|
metadata
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sapling-dialogue
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Bill Niblock
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2017-10-
|
|
11
|
+
date: 2017-10-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
|
-
description: Create, edit, and traverse
|
|
13
|
+
description: Create, edit, and traverse dialogue trees
|
|
14
14
|
email: azulien@gmail.com
|
|
15
15
|
executables:
|
|
16
16
|
- sapling
|