Compare commits
No commits in common. "master" and "gh-pages" have entirely different histories.
48 changed files with 0 additions and 1020 deletions
61
.gitignore
vendored
61
.gitignore
vendored
|
@ -1,61 +0,0 @@
|
||||||
# Global gitignore file
|
|
||||||
# bill_niblock@yahoo.com
|
|
||||||
|
|
||||||
##
|
|
||||||
# Stolen from octocat: https://gist.github.com/octocat/9257657
|
|
||||||
##
|
|
||||||
|
|
||||||
# Compiled source #
|
|
||||||
###################
|
|
||||||
*.com
|
|
||||||
*.class
|
|
||||||
*.dll
|
|
||||||
*.exe
|
|
||||||
*.o
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Packages #
|
|
||||||
############
|
|
||||||
# it's better to unpack these files and commit the raw source
|
|
||||||
# git has its own built in compression methods
|
|
||||||
*.7z
|
|
||||||
*.dmg
|
|
||||||
*.gz
|
|
||||||
*.iso
|
|
||||||
*.jar
|
|
||||||
*.rar
|
|
||||||
*.tar
|
|
||||||
*.zip
|
|
||||||
|
|
||||||
# Logs and databases #
|
|
||||||
######################
|
|
||||||
*.log
|
|
||||||
*.sql
|
|
||||||
*.sqlite
|
|
||||||
|
|
||||||
# OS generated files #
|
|
||||||
######################
|
|
||||||
.DS_Store
|
|
||||||
.DS_Store?
|
|
||||||
._*
|
|
||||||
.Spotlight-V100
|
|
||||||
.Trashes
|
|
||||||
ehthumbs.db
|
|
||||||
Thumbs.db
|
|
||||||
|
|
||||||
##
|
|
||||||
# Additions
|
|
||||||
##
|
|
||||||
|
|
||||||
# Vim Related #
|
|
||||||
###############
|
|
||||||
*.swp
|
|
||||||
.netrwhist
|
|
||||||
*.un~
|
|
||||||
|
|
||||||
# YARD Related #
|
|
||||||
################
|
|
||||||
# doc/ is the generated documentation for Yard, which can easily be generated
|
|
||||||
# locally with yardoc
|
|
||||||
# .yardoc/ is yard metadata, not necessary to be uploaded to GH
|
|
||||||
.yardoc/
|
|
|
@ -1,4 +0,0 @@
|
||||||
language: ruby
|
|
||||||
sudo: false
|
|
||||||
rvm:
|
|
||||||
- 2.2
|
|
|
@ -1,9 +0,0 @@
|
||||||
--title "Sapling Documentation"
|
|
||||||
-
|
|
||||||
README.md
|
|
||||||
var/docs/config_file.md
|
|
||||||
var/docs/config_file_example.md
|
|
||||||
var/docs/editor.md
|
|
||||||
CONTRIBUTING.md
|
|
||||||
LICENSE
|
|
||||||
lib/**.*.rb
|
|
|
@ -1,14 +0,0 @@
|
||||||
# Contributing to Sapling
|
|
||||||
|
|
||||||
If you actually want to contribute to this software, first off: Thanks! Sapling
|
|
||||||
is just a side-project, unintended for any significant use.
|
|
||||||
|
|
||||||
Sapling is written in Ruby, and adheres to the standard Rubocop rules. So long
|
|
||||||
as your code passes those rules, it should be good. At time of writing, Sapling
|
|
||||||
has no testing, because I honestly have very little experience writing tests.
|
|
||||||
Hopefully this changes soon!
|
|
||||||
|
|
||||||
If you don't know how to program in Ruby, but wish to improve this software,
|
|
||||||
feel free to submit an issue or reach out to me directly.
|
|
||||||
|
|
||||||
Thanks again for your interest in Sapling!
|
|
12
Gemfile
12
Gemfile
|
@ -1,12 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
source "https://rubygems.org"
|
|
||||||
|
|
||||||
# Documentation
|
|
||||||
gem "rdoc"
|
|
||||||
gem "redcarpet"
|
|
||||||
gem "thor"
|
|
||||||
gem "yard"
|
|
||||||
gem "yard-ghpages"
|
|
||||||
|
|
||||||
# Testing
|
|
||||||
gem "rubocop"
|
|
41
Gemfile.lock
41
Gemfile.lock
|
@ -1,41 +0,0 @@
|
||||||
GEM
|
|
||||||
remote: https://rubygems.org/
|
|
||||||
specs:
|
|
||||||
ast (2.3.0)
|
|
||||||
git (1.3.0)
|
|
||||||
parser (2.4.0.0)
|
|
||||||
ast (~> 2.2)
|
|
||||||
powerpack (0.1.1)
|
|
||||||
rainbow (2.2.2)
|
|
||||||
rake
|
|
||||||
rake (11.3.0)
|
|
||||||
rdoc (5.1.0)
|
|
||||||
redcarpet (3.4.0)
|
|
||||||
rubocop (0.48.1)
|
|
||||||
parser (>= 2.3.3.1, < 3.0)
|
|
||||||
powerpack (~> 0.1)
|
|
||||||
rainbow (>= 1.99.1, < 3.0)
|
|
||||||
ruby-progressbar (~> 1.7)
|
|
||||||
unicode-display_width (~> 1.0, >= 1.0.1)
|
|
||||||
ruby-progressbar (1.8.1)
|
|
||||||
thor (0.20.0)
|
|
||||||
unicode-display_width (1.2.1)
|
|
||||||
yard (0.9.9)
|
|
||||||
yard-ghpages (0.0.2)
|
|
||||||
git (~> 1.3)
|
|
||||||
rake (~> 11.1)
|
|
||||||
yard (~> 0.8)
|
|
||||||
|
|
||||||
PLATFORMS
|
|
||||||
ruby
|
|
||||||
|
|
||||||
DEPENDENCIES
|
|
||||||
rdoc
|
|
||||||
redcarpet
|
|
||||||
rubocop
|
|
||||||
thor
|
|
||||||
yard
|
|
||||||
yard-ghpages
|
|
||||||
|
|
||||||
BUNDLED WITH
|
|
||||||
1.14.6
|
|
21
LICENSE
21
LICENSE
|
@ -1,21 +0,0 @@
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2017 Bill Niblock
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
85
README.md
85
README.md
|
@ -1,85 +0,0 @@
|
||||||
<!--
|
|
||||||
# @markup markdown
|
|
||||||
# @title README
|
|
||||||
-->
|
|
||||||
|
|
||||||
# Sapling: A Dialogue Tree CLI Utility
|
|
||||||
|
|
||||||
[](
|
|
||||||
https://badge.fury.io/rb/sapling-dialogue) [](
|
|
||||||
https://travis-ci.org/VagabondAzulien/sapling)
|
|
||||||
|
|
||||||
Sapling allows for easy creation and use of dialogue trees.
|
|
||||||
|
|
||||||
A dialogue tree is a series of dialogues which follow sequentially, though with
|
|
||||||
branching options. Examples include "Choose Your Own Adventure" games, or the
|
|
||||||
dialogues seen in many video games.
|
|
||||||
|
|
||||||
## Structure
|
|
||||||
|
|
||||||
A dialogue tree can be broken down into three distinct parts: the trunk,
|
|
||||||
branches, and leafs. The trunk represents the main structure of the tree. Unlike
|
|
||||||
a branch, which displays content and options, the trunk provides metadata.
|
|
||||||
Generally speaking, it is a branch, with the exception that it has no options. A
|
|
||||||
branch represents a choice taken in the dialogue. Branches flow to each other
|
|
||||||
through leafs, which are the actual choices.
|
|
||||||
|
|
||||||
You can experience this yourself, by loading "Example Quest! - A Meta Dialogue
|
|
||||||
Tree!". You can find the tree itself at [var/trees/example\_quest.yaml](
|
|
||||||
https://github.com/VagabondAzulien/sapling/blob/master/var/trees/example_quest.yaml).
|
|
||||||
To run it, just type `sapling read path/to/example_quest.yaml`.
|
|
||||||
|
|
||||||
## Building a New Tree
|
|
||||||
|
|
||||||
To build a new tree, you have two options. You can manually edit a configuration
|
|
||||||
file, or go through the construction wizard. Either way, the end result is a
|
|
||||||
plain-text configuration file, which can be easily shared, edited, and viewed.
|
|
||||||
For more details on the configuration file itself, check out the [Configuration
|
|
||||||
File documentation](
|
|
||||||
http://www.theinternetvagabond.com/sapling/file.config_file.html), or the
|
|
||||||
self-documented [configuration file example](
|
|
||||||
http://www.theinternetvagabond.com/sapling/file.config_file_example.html).
|
|
||||||
Alternatively, you can checkout [Example Quest](
|
|
||||||
https://github.com/VagabondAzulien/sapling/blob/master/var/trees/example_quest.yaml)
|
|
||||||
for a complete tree.
|
|
||||||
|
|
||||||
### Manual Edit
|
|
||||||
|
|
||||||
1. Open your preferred text editor.
|
|
||||||
2. Refer to the [Configuration File documentation](
|
|
||||||
http://www.theinternetvagabond.com/sapling/file.config_file.html)
|
|
||||||
3. Make your changes.
|
|
||||||
4. Save your changes.
|
|
||||||
|
|
||||||
### Automatic Edit -- Coming Soon(tm)!
|
|
||||||
|
|
||||||
1. Run the configuration editor: `sapling edit [TREE]`
|
|
||||||
2. If you don't include a TREE, `sapling` will create a new tree in the current
|
|
||||||
directory.
|
|
||||||
3. If you choose to modify an existing file, `sapling` will open the tree at the
|
|
||||||
trunk, and show you the first branch.
|
|
||||||
4. Make your changes.
|
|
||||||
5. Save your changes.
|
|
||||||
|
|
||||||
More details on the editor can be found in the [Editor
|
|
||||||
documentation](
|
|
||||||
http://www.theinternetvagabond.com/sapling/file.editor.html).
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
You can contribute to Sapling by following these instructions:
|
|
||||||
1. Fork this repository.
|
|
||||||
2. In your fork, make your changes.
|
|
||||||
3. Make sure your changes respect the [contribution
|
|
||||||
guidelines](
|
|
||||||
http://www.theinternetvagabond.com/sapling/file.CONTRIBUTING.html).
|
|
||||||
4. Submit a pull request.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
Sapling is licensed under the MIT license. The full text can be found in
|
|
||||||
[LICENSE](
|
|
||||||
http://www.theinternetvagabond.com/sapling/file.LICENSE.html).
|
|
3
Rakefile
3
Rakefile
|
@ -1,3 +0,0 @@
|
||||||
require 'yard-ghpages'
|
|
||||||
|
|
||||||
Yard::GHPages::Tasks.install_tasks
|
|
|
@ -1,5 +0,0 @@
|
||||||
#!/usr/bin/env ruby
|
|
||||||
|
|
||||||
require 'sapling'
|
|
||||||
|
|
||||||
Sapling.start(ARGV)
|
|
0
doc/js/jquery.js → js/jquery.js
vendored
0
doc/js/jquery.js → js/jquery.js
vendored
|
@ -1,44 +0,0 @@
|
||||||
#!/usr/bin/env ruby
|
|
||||||
|
|
||||||
require 'thor'
|
|
||||||
require 'yaml'
|
|
||||||
|
|
||||||
Dir[File.join(__dir__, 'sapling', '*.rb')].each { |file| require file }
|
|
||||||
|
|
||||||
# The main Sapling interface.
|
|
||||||
class Sapling < Thor
|
|
||||||
desc 'read TREE', 'Load and traverse the TREE'
|
|
||||||
def read(file)
|
|
||||||
puts 'Welcome to Sapling, a Dialogue Tree Utility.'
|
|
||||||
exit unless verify_tree(file)
|
|
||||||
tree = Gardner::Plot.new(YAML.load_file(file))
|
|
||||||
speaker = Dialogue::Speaker.new(tree, false)
|
|
||||||
speaker.conversation
|
|
||||||
end
|
|
||||||
|
|
||||||
desc 'edit TREE', 'Edit a new or existing TREE'
|
|
||||||
def edit(file = '')
|
|
||||||
puts 'Welcome to Sapling, a Dialogue Tree Utility.'
|
|
||||||
if !tree.empty?
|
|
||||||
puts "Loading tree: #{file}"
|
|
||||||
exit unless verify_tree(file)
|
|
||||||
gardner = Planter::Spade.new(YAML.load_file(tree, false))
|
|
||||||
else
|
|
||||||
puts 'Creating a new tree!'
|
|
||||||
gardner = Planter::Spade.new(SKELETON_TREE)
|
|
||||||
end
|
|
||||||
gardner.plant
|
|
||||||
end
|
|
||||||
|
|
||||||
desc 'serve TREE', 'Load TREE in a web-based interface'
|
|
||||||
def serve(tree)
|
|
||||||
exit unless verify_tree(tree)
|
|
||||||
puts 'Sinatra will be cool.'
|
|
||||||
end
|
|
||||||
|
|
||||||
desc 'export TREE', 'Save a portable HTML version of TREE'
|
|
||||||
def export(tree)
|
|
||||||
exit unless verify_tree(tree)
|
|
||||||
puts 'Cool feature, bro!'
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,111 +0,0 @@
|
||||||
require_relative './gardner'
|
|
||||||
|
|
||||||
# Dialogue is the module for traversing an existing tree.
|
|
||||||
module Dialogue
|
|
||||||
# Format and display the trunk
|
|
||||||
#
|
|
||||||
# @param trunk [Hash] The trunk hash
|
|
||||||
# @param debug [Boolean] The status of showing debug information
|
|
||||||
def self.display_trunk(trunk, debug = false)
|
|
||||||
40.times { print '-' }
|
|
||||||
puts "\n[ Trunk ]\n" if debug
|
|
||||||
puts "\n#{trunk['trunk']}"
|
|
||||||
40.times { print '-' }
|
|
||||||
puts "\n"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Format and display a branch and the options
|
|
||||||
#
|
|
||||||
# @param branch [Hash] A branch data set
|
|
||||||
# @param branch_no [Integer] The branch number
|
|
||||||
# @param debug [Boolean] Status of showing debug information
|
|
||||||
def self.display_branch(branch, branch_no, debug = false)
|
|
||||||
puts "\n[ Branch: #{branch_no} ]" if debug
|
|
||||||
puts "\n#{branch['desc']}\n\n"
|
|
||||||
|
|
||||||
branch['options'].each_pair do |k, v|
|
|
||||||
puts "\t#{k}: #{v.keys[0]}"
|
|
||||||
puts "\t\t[ Goes to branch #{v.values[0]} ]\n" if debug
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Speaker holds the functionality for going through a dialogue tree.
|
|
||||||
class Speaker
|
|
||||||
# The tree, an instance of Gardner::Plot
|
|
||||||
attr_reader :tree
|
|
||||||
# Status of verbose/debug mode. True = on; false = off.
|
|
||||||
attr_reader :debug
|
|
||||||
|
|
||||||
def initialize(tree, debug = false)
|
|
||||||
@tree = tree
|
|
||||||
@debug = debug
|
|
||||||
end
|
|
||||||
|
|
||||||
# Conversation handles navigating the tree, until the option to end is
|
|
||||||
# reached.
|
|
||||||
def conversation
|
|
||||||
Dialogue.display_trunk(@tree.trunk, @debug)
|
|
||||||
|
|
||||||
next_branch = 1
|
|
||||||
until next_branch.zero?
|
|
||||||
next_branch = talk(@tree.branches[next_branch], next_branch)
|
|
||||||
end
|
|
||||||
|
|
||||||
puts "\n#{@tree.branches[0]['desc']}"
|
|
||||||
exit
|
|
||||||
end
|
|
||||||
|
|
||||||
# Talk displays a branch, the options, and prompts for a response.
|
|
||||||
#
|
|
||||||
# @param branch [Hash] A branch data set
|
|
||||||
# @param branch_no [Integer] The branch number
|
|
||||||
# @return [Integer] The number of the next branch
|
|
||||||
def talk(branch, branch_no)
|
|
||||||
return 0 if terminal?(branch)
|
|
||||||
|
|
||||||
Dialogue.display_branch(branch, branch_no, @debug)
|
|
||||||
|
|
||||||
response = get_response(branch)
|
|
||||||
|
|
||||||
unless response.zero?
|
|
||||||
puts "(Your choice: #{branch['options'][response].keys[0]})"
|
|
||||||
response = branch['options'][response].values[0].to_i
|
|
||||||
end
|
|
||||||
|
|
||||||
response
|
|
||||||
end
|
|
||||||
|
|
||||||
# Get a response for the displayed branch
|
|
||||||
#
|
|
||||||
# @param branch [Hash] A branch data set
|
|
||||||
# @return [Integer] the next branch
|
|
||||||
def get_response(branch)
|
|
||||||
valid_options = branch['options'].keys.join(', ')
|
|
||||||
|
|
||||||
print "\n[#{valid_options}]> "
|
|
||||||
STDOUT.flush
|
|
||||||
response = STDIN.gets.chomp
|
|
||||||
|
|
||||||
until valid_options.include?(response) || response.to_i.zero?
|
|
||||||
print "[## Invalid options. Valid options are #{valid_options}," \
|
|
||||||
"or 0 to exit.\n[#{valid_options}]> "
|
|
||||||
response = STDIN.gets.chomp
|
|
||||||
end
|
|
||||||
|
|
||||||
response.to_i
|
|
||||||
end
|
|
||||||
|
|
||||||
# Check if a branch is terminal
|
|
||||||
#
|
|
||||||
# @param branch [Hash] A branch data set
|
|
||||||
# @return [Boolean] true if the branch is terminal, false otherwise
|
|
||||||
def terminal?(branch)
|
|
||||||
if branch['options'].empty?
|
|
||||||
puts "\n#{branch['desc']}\n\n"
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,96 +0,0 @@
|
||||||
require 'yaml'
|
|
||||||
|
|
||||||
# Gardner is the module for working with a dialogue tree file
|
|
||||||
module Gardner
|
|
||||||
# The Plot class handles a specific tree file. It provides functionality for
|
|
||||||
# parsing trunks and branches, and provides these as class attributes.
|
|
||||||
class Plot
|
|
||||||
# The trunk and branches instance variables
|
|
||||||
attr_reader :branches, :tree, :trunk
|
|
||||||
|
|
||||||
# Initialize a new Plot from a tree file
|
|
||||||
#
|
|
||||||
# @param tree [File] The dialogue tree file
|
|
||||||
def initialize(file)
|
|
||||||
@tree = file
|
|
||||||
prune_trunk
|
|
||||||
prune_branches
|
|
||||||
end
|
|
||||||
|
|
||||||
# Parse the tree array into an array of numbered branches, and ordered
|
|
||||||
# leaves.
|
|
||||||
#
|
|
||||||
# @param tree [File] The dialogue tree
|
|
||||||
# @return [Array] An array of numbered branches, with numbered leaves
|
|
||||||
def prune_branches
|
|
||||||
@branches = { 0 => { 'desc' => 'Thanks for using Sapling!' } }
|
|
||||||
@tree.each do |b|
|
|
||||||
@branches[b['branch']['number']] = {
|
|
||||||
'desc' => b['branch']['text'],
|
|
||||||
'options' => prune_leaves(b['branch']['leaf'])
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Parse the leaves of a branch into a numbered hash of options.
|
|
||||||
#
|
|
||||||
# @param leaves [Array] The option of leaf hashes
|
|
||||||
# @return [Hash] A numbered hash of options
|
|
||||||
def prune_leaves(leaves)
|
|
||||||
x = 1
|
|
||||||
options = {}
|
|
||||||
|
|
||||||
return options if leaves.nil?
|
|
||||||
|
|
||||||
leaves.each do |l|
|
|
||||||
options[x] = { l['text'] => l['branch'] }
|
|
||||||
x += 1
|
|
||||||
end
|
|
||||||
|
|
||||||
options
|
|
||||||
end
|
|
||||||
|
|
||||||
# Parse the trunk of the tree.
|
|
||||||
#
|
|
||||||
# @return [Array] The trunk, and the remainder of the tree
|
|
||||||
def prune_trunk
|
|
||||||
@trunk = @tree.shift
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Digiplot represents a Plot used for editing. The Digiplot functions exactly
|
|
||||||
# like a Plot, except with additional functionality for over-writing existing
|
|
||||||
# branches, leaves, and the trunk.
|
|
||||||
class Digiplot < Plot
|
|
||||||
# Duplicate the "old" trunk and branches, for restoration purposes
|
|
||||||
attr_reader :old_branches, :old_trunk
|
|
||||||
|
|
||||||
# Enable editing for the trunk
|
|
||||||
attr_writer :trunk
|
|
||||||
|
|
||||||
# Initialize a Digiplot just like a Plot, but also copy the trunk and
|
|
||||||
# branches to "old" instance variables.
|
|
||||||
def initialize
|
|
||||||
super
|
|
||||||
@old_trunk = @trunk
|
|
||||||
@old_branches = @branches
|
|
||||||
end
|
|
||||||
|
|
||||||
# Change a branch
|
|
||||||
#
|
|
||||||
# @param branch [Integer] the number of the branch to be edited
|
|
||||||
def branch=(branch, text)
|
|
||||||
@branches[branch]['desc'] = text
|
|
||||||
end
|
|
||||||
|
|
||||||
# Change a leaf on a branch, grasshopper
|
|
||||||
#
|
|
||||||
# @param branch [Integer] the number of the branch to be edited
|
|
||||||
# @param leaf [Integer] the number of the leaf to be edited
|
|
||||||
# @param text [String] the new text for the leaf
|
|
||||||
# @param target [Integer] the branch number target for the leaf option
|
|
||||||
def leaf=(branch, leaf, text, target)
|
|
||||||
@branches[branch]['options'][leaf] = { text => target }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,210 +0,0 @@
|
||||||
require_relative './dialogue'
|
|
||||||
require_relative './gardner'
|
|
||||||
require_relative './utility'
|
|
||||||
|
|
||||||
# Planter is the module for creating or editing a tree.
|
|
||||||
module Planter
|
|
||||||
|
|
||||||
# In-memory tree
|
|
||||||
class Plot
|
|
||||||
|
|
||||||
# The tree, trunk, and branches
|
|
||||||
attr_accessor :tree, :trunk, :branches
|
|
||||||
|
|
||||||
# Edit the trunk of the tree
|
|
||||||
def edit_trunk
|
|
||||||
puts "Current Trunk:\n"
|
|
||||||
Dialogue.display_trunk(@trunk, true)
|
|
||||||
print "\n[ =EDITING= ](CTRL-C to abort)> "
|
|
||||||
STDOUT.flush
|
|
||||||
begin
|
|
||||||
new_trunk = STDIN.gets.to_s
|
|
||||||
rescue Interrupt
|
|
||||||
puts "\n**Aborting edit**\n\n"
|
|
||||||
new_trunk = @trunk["trunk"]
|
|
||||||
end
|
|
||||||
@trunk["trunk"] = new_trunk
|
|
||||||
end
|
|
||||||
|
|
||||||
# Edit a branch on the tree
|
|
||||||
#
|
|
||||||
# @param branch [Integer] The number of the branch to be edited.
|
|
||||||
def edit_branch(branch_no)
|
|
||||||
puts "Current Branch:\n"
|
|
||||||
Dialogue.display_branch(@branches[branch_no], branch_no, true)
|
|
||||||
print "\n[ =EDITING= ](CTRL-C to abort)> "
|
|
||||||
STDOUT.flush
|
|
||||||
begin
|
|
||||||
new_branch = STDIN.gets.to_s
|
|
||||||
rescue Interrupt
|
|
||||||
puts "\n**Aborting edit**\n\n"
|
|
||||||
new_branch = @branches[branch_no]["desc"]
|
|
||||||
end
|
|
||||||
@branches[branch_no]["desc"] = new_branch
|
|
||||||
end
|
|
||||||
|
|
||||||
# Edit a leaf on a branch, grasshopper
|
|
||||||
#
|
|
||||||
# @param branch [Integer] The number of the branch to be edited.
|
|
||||||
# @param leaf [Hash] The leaf hash to be edited.
|
|
||||||
def edit_leaf(branch, leaf)
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Utilities for editing specific parts of a tree.
|
|
||||||
class Spade
|
|
||||||
|
|
||||||
# The file we parse into a tree
|
|
||||||
attr_writer :file
|
|
||||||
|
|
||||||
def initialize(file)
|
|
||||||
@file = file
|
|
||||||
end
|
|
||||||
|
|
||||||
# Establish and populate a new Plot (in-memory tree), then control the flow
|
|
||||||
# of editing the Plot
|
|
||||||
def plant
|
|
||||||
@plot = Plot.new
|
|
||||||
@plot.tree = @file
|
|
||||||
@plot.trunk = @file.shift
|
|
||||||
@plot.branches = Gardner.prune_branches(@file)
|
|
||||||
|
|
||||||
next_branch = dig(1)
|
|
||||||
until next_branch == 0 do
|
|
||||||
next_branch = dig(next_branch)
|
|
||||||
end
|
|
||||||
|
|
||||||
puts "\n#{@plot.branches[0]["desc"]}"
|
|
||||||
exit
|
|
||||||
end
|
|
||||||
|
|
||||||
# Function for displaying a single branch in debug mode. We also always
|
|
||||||
# display the trunk, since otherwise it's displayed a single time then gone
|
|
||||||
# forever (until next time).
|
|
||||||
#
|
|
||||||
# @param branch_no [Integer] The number of the branch to be displayed.
|
|
||||||
def dig(branch_no)
|
|
||||||
branch = @plot.branches[branch_no]
|
|
||||||
|
|
||||||
Dialogue.display_trunk(@plot.trunk, true)
|
|
||||||
Dialogue.display_branch(branch, branch_no, true)
|
|
||||||
|
|
||||||
response = get_response(branch)
|
|
||||||
to_branch = parse_response(response, branch_no)
|
|
||||||
|
|
||||||
return to_branch
|
|
||||||
end
|
|
||||||
|
|
||||||
# Get a response for the displayed branch
|
|
||||||
#
|
|
||||||
# @param branch [Hash] A branch data set
|
|
||||||
# @return [Integer] the next branch
|
|
||||||
def get_response(branch)
|
|
||||||
total_branches = @plot.branches.count - 1
|
|
||||||
valid_options = ["1-#{total_branches}","t","a","b","x","l","s","q"]
|
|
||||||
print_options = valid_options.join(",")
|
|
||||||
|
|
||||||
print "\n[#{print_options}]> "
|
|
||||||
STDOUT.flush
|
|
||||||
response = STDIN.gets.chomp.to_s.downcase
|
|
||||||
|
|
||||||
until valid_options.include?(response) or response.to_i.between?(1,total_branches)
|
|
||||||
print "[## Invalid response. "
|
|
||||||
print "Valid options are #{print_options}"
|
|
||||||
print "\n[#{print_options}]> "
|
|
||||||
response = STDIN.gets.chomp.to_s.downcase
|
|
||||||
end
|
|
||||||
|
|
||||||
return response
|
|
||||||
end
|
|
||||||
|
|
||||||
# Parse the response from get_response
|
|
||||||
#
|
|
||||||
# @param response [String] The option selected
|
|
||||||
# @param branch_no [Integer] The currently-displayed branch
|
|
||||||
# @return [Integer] the branch to display
|
|
||||||
def parse_response(response, branch_no)
|
|
||||||
10.times { print "*" }
|
|
||||||
print "\n(Your choice: "
|
|
||||||
|
|
||||||
if response.to_i >= 1
|
|
||||||
print "Change to branch #{response.to_i})\n\n"
|
|
||||||
return response.to_i
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
case response.to_s.downcase
|
|
||||||
when "t"
|
|
||||||
print "Edit the trunk.)\n\n"
|
|
||||||
@plot.edit_trunk
|
|
||||||
return branch_no
|
|
||||||
when "a"
|
|
||||||
print "Add a new branch.)\n\n"
|
|
||||||
return branch_no
|
|
||||||
when "b"
|
|
||||||
print "Edit the current branch.)\n\n"
|
|
||||||
@plot.edit_branch(branch_no)
|
|
||||||
return branch_no
|
|
||||||
when "x"
|
|
||||||
print "Delete the current branch.)\n\n"
|
|
||||||
return branch_no
|
|
||||||
when "l"
|
|
||||||
print "Edit leaves of current branch.)\n\n"
|
|
||||||
return branch_no
|
|
||||||
when "s"
|
|
||||||
print "Save changes.)\n\n"
|
|
||||||
return branch_no
|
|
||||||
when "q"
|
|
||||||
print "Quit without saving.)\n\n"
|
|
||||||
print "Unsaved changes will be lost. Still quit? [y/n]> "
|
|
||||||
verify = STDIN.gets.chomp.to_s.downcase
|
|
||||||
|
|
||||||
return 0 if verify == "y"
|
|
||||||
return branch_no
|
|
||||||
else
|
|
||||||
print "Unknown option. Returning to current branch.)\n\n"
|
|
||||||
return branch_no
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
=begin
|
|
||||||
|
|
||||||
Process:
|
|
||||||
- User selects to create/edit a tree
|
|
||||||
- If the user presented a file, use it as the tree file
|
|
||||||
- If the user failed to provide a file, create a new tree file in the current directory
|
|
||||||
|
|
||||||
- Check if the file is empty.
|
|
||||||
- If so, assume a new tree
|
|
||||||
- If not, verify formatting
|
|
||||||
|
|
||||||
- If new tree, prompt for trunk
|
|
||||||
- If existing tree, display trunk and first branch
|
|
||||||
|
|
||||||
- At this point, editing is the same
|
|
||||||
- Prompt provides options:
|
|
||||||
- #: Go to that branch number
|
|
||||||
- T: Modify the tree trunk
|
|
||||||
- A: Add a new branch (append to list of branches)
|
|
||||||
- B: Modify the current branch description
|
|
||||||
- X: Delete the current branch (does this renumber branches?)
|
|
||||||
- L: Modify the current leaves, respond with leaf prompt
|
|
||||||
- S: Save changes
|
|
||||||
- Q: Quit
|
|
||||||
|
|
||||||
- Example prompt:
|
|
||||||
[ 0-5,T,A,B,X,L,S,Q ]>
|
|
||||||
- Leaf prompt:
|
|
||||||
|
|
||||||
Details:
|
|
||||||
|
|
||||||
- Regardless of the file existing, the user will be editing a Hash, not the actual YAML file
|
|
||||||
- Use Gardner to build and interact with the tree
|
|
||||||
- Use Planter to modify the tree "in memory" (aka, the hash)
|
|
||||||
- Use Dialog to interact with the tree "in memory", to test-run it
|
|
||||||
- After each edit option, display the current branch with the new changes.
|
|
||||||
|
|
||||||
=end
|
|
|
@ -1,56 +0,0 @@
|
||||||
# Utility functionality for all of Sapling to reference
|
|
||||||
|
|
||||||
# Constants
|
|
||||||
|
|
||||||
# A series of constants for handing a brand new tree. The skeleton tree provides
|
|
||||||
# a very basic introduction to Sapling. More details can be found in the
|
|
||||||
# documentation.
|
|
||||||
|
|
||||||
# The default trunk text of a new tree
|
|
||||||
SKELE_TRUNK_TEXT = 'Welcome to the Sapling Editor. For details, please see the
|
|
||||||
documentation!'.freeze
|
|
||||||
|
|
||||||
# The default first-branch text of a new tree
|
|
||||||
SKELE_BRANCH_TEXT = 'The first branch is always shown by default. It should act
|
|
||||||
as the introduction to the story. From here, the user enters your world!'.freeze
|
|
||||||
|
|
||||||
# The default first-leaf text of the first branch of a new tree. The leaf points
|
|
||||||
# to it's own branch. The only way out of the program is to either force-quit or
|
|
||||||
# reply with option 0.
|
|
||||||
SKELE_LEAF_TEXT = 'Each branch can have any number of leaves, which represent
|
|
||||||
the options a user has on that branch. Each leaf points to another branch, or
|
|
||||||
can point to branch 0 to immediately exit.'.freeze
|
|
||||||
|
|
||||||
# The final tree
|
|
||||||
SKELETON_TREE = [
|
|
||||||
{ 'trunk' => SKELE_TRUNK_TEXT.to_s },
|
|
||||||
{ 'branch' => {
|
|
||||||
'number' => 1,
|
|
||||||
'text' => SKELE_BRANCH_TEXT.to_s,
|
|
||||||
'leaf' => [{
|
|
||||||
'text' => SKELE_LEAF_TEXT.to_s,
|
|
||||||
'branch' => 1
|
|
||||||
}]
|
|
||||||
} }
|
|
||||||
].freeze
|
|
||||||
|
|
||||||
# Verify that a file is a dialogue tree file.
|
|
||||||
#
|
|
||||||
# @param file [File] The provided file
|
|
||||||
# @return [Boolean] True if the file is a tree; false otherwise
|
|
||||||
def verify_tree(file)
|
|
||||||
results = []
|
|
||||||
begin
|
|
||||||
tree = YAML.load_file(file)
|
|
||||||
results << tree[0].keys.include?('trunk')
|
|
||||||
results << tree[1]['branch'].keys.include?('number')
|
|
||||||
results << tree[1]['branch'].keys.include?('text')
|
|
||||||
results << tree[1]['branch'].keys.include?('leaf')
|
|
||||||
rescue
|
|
||||||
puts "Sorry chummer, I don't think this is a tree."
|
|
||||||
puts 'Verify your YAML file is formatted properly.'
|
|
||||||
results << false
|
|
||||||
end
|
|
||||||
|
|
||||||
results.include?(false) ? false : true
|
|
||||||
end
|
|
|
@ -1,13 +0,0 @@
|
||||||
Gem::Specification.new do |s|
|
|
||||||
s.name = 'sapling-dialogue'
|
|
||||||
s.version = '0.1.2'
|
|
||||||
s.executables << 'sapling'
|
|
||||||
s.date = '2017-10-19'
|
|
||||||
s.summary = 'A Dialogue Tree Utility'
|
|
||||||
s.description = 'Create, edit, and traverse dialogue trees'
|
|
||||||
s.authors = ['Bill Niblock']
|
|
||||||
s.email = 'azulien@gmail.com'
|
|
||||||
s.files = Dir['lib/**/*.rb'] + Dir['bin/*']
|
|
||||||
s.homepage = 'http://www.theinternetvagabond.com/sapling/'
|
|
||||||
s.license = 'MIT'
|
|
||||||
end
|
|
|
@ -1,66 +0,0 @@
|
||||||
<!--
|
|
||||||
# @markup markdown
|
|
||||||
# @title Configuration File
|
|
||||||
-->
|
|
||||||
|
|
||||||
# Configuration File Documentation
|
|
||||||
|
|
||||||
The configuration file for `sapling` is a standard YAML file. The general
|
|
||||||
outline looks something like this:
|
|
||||||
|
|
||||||
---
|
|
||||||
-
|
|
||||||
trunk: "This is a description of the dialogue tree."
|
|
||||||
-
|
|
||||||
branch:
|
|
||||||
number: 1
|
|
||||||
text: "This is the overall text for the branch."
|
|
||||||
leaf:
|
|
||||||
-
|
|
||||||
text: "This is option 1."
|
|
||||||
branch: 2
|
|
||||||
-
|
|
||||||
text: "This is option 2."
|
|
||||||
branch: 3
|
|
||||||
-
|
|
||||||
branch:
|
|
||||||
number: 2
|
|
||||||
text: "This is the overall text for the branch."
|
|
||||||
leaf:
|
|
||||||
-
|
|
||||||
text: "This is option 1."
|
|
||||||
branch: 1
|
|
||||||
-
|
|
||||||
text: "This is option 2."
|
|
||||||
branch: 3
|
|
||||||
-
|
|
||||||
branch:
|
|
||||||
number: 3
|
|
||||||
text: "This is the overall text for the branch."
|
|
||||||
|
|
||||||
## Outline
|
|
||||||
|
|
||||||
#### Trunk
|
|
||||||
|
|
||||||
The `trunk` is a metadata list. Currently, the only information we really care
|
|
||||||
about is a general description for the tree. Because of this, `trunk` is the
|
|
||||||
key, and the description is the value.
|
|
||||||
|
|
||||||
#### Branch
|
|
||||||
|
|
||||||
Branches are the content of a dialogue tree. Each `branch` has the following
|
|
||||||
options:
|
|
||||||
|
|
||||||
- `number`: The branch number. This is how leaves get around. It must be unique.
|
|
||||||
- `text`: The text provided by getting to this branch. The first branch is shown
|
|
||||||
by default when the tree is opened.
|
|
||||||
- `leaf`: [Optional] The list of options for the branch. Details for leaves are
|
|
||||||
below. If no leaves are provided, the branch is considered a "terminal
|
|
||||||
branch", and the program will end after reaching it.
|
|
||||||
|
|
||||||
#### Leaf
|
|
||||||
|
|
||||||
Leaves are the options of a branch. Each `leaf` has the following options:
|
|
||||||
|
|
||||||
- `text`: The text shown as the option.
|
|
||||||
- `branch`: The branch this option takes the user to.
|
|
|
@ -1,42 +0,0 @@
|
||||||
<!--
|
|
||||||
# @markup markdown
|
|
||||||
# @title Example YAML File
|
|
||||||
-->
|
|
||||||
# Example Dialogue Tree
|
|
||||||
---
|
|
||||||
# The trunk is a general introduction to the tree. It shouldn't include any
|
|
||||||
# thematic details, rather a one-liner to let the user know what they're getting
|
|
||||||
# into.
|
|
||||||
-
|
|
||||||
trunk: "This is a general introduction to the dialogue tree."
|
|
||||||
|
|
||||||
# Branches are the content of a dialogue tree. Each branch is numbered, and that
|
|
||||||
# number is used as the primary means of navigation. The text of a branch is the
|
|
||||||
# story provided to the user; the result of getting to the branch. The leaves
|
|
||||||
# (the section titled leaf) represent the options. Options are displayed in the
|
|
||||||
# order they appear. Within a leaf, the text is what the option says, and the
|
|
||||||
# branch is the branch number which this option will lead to. Leading to branch
|
|
||||||
# number 0 will immediately exit the program.
|
|
||||||
#
|
|
||||||
# You can have as many branches and leaves as you wish, though having too many
|
|
||||||
# leaves may lead to both display problems, and paralyzing indecision.
|
|
||||||
-
|
|
||||||
branch:
|
|
||||||
number: 1
|
|
||||||
text: "The first branch. Displayed first, by default."
|
|
||||||
leaf:
|
|
||||||
-
|
|
||||||
text: "The first option for this branch. It leads to branch 2"
|
|
||||||
branch: 2
|
|
||||||
-
|
|
||||||
text: "The second branch. It immediately exits the program."
|
|
||||||
branch: 0
|
|
||||||
|
|
||||||
# A terminal branch is a branch which has no leaves. This represents an ending.
|
|
||||||
# Once a user hits a terminal branch, the program will display the branch text,
|
|
||||||
# and then redirect the user to branch 0, to exit.
|
|
||||||
-
|
|
||||||
branch:
|
|
||||||
number: 2
|
|
||||||
text: "This is a terminal branch. After displaying this text,
|
|
||||||
the program will exit."
|
|
|
@ -1,37 +0,0 @@
|
||||||
# @title Example YAML File
|
|
||||||
---
|
|
||||||
# The trunk is a general introduction to the tree. It shouldn't include any
|
|
||||||
# thematic details, rather a one-liner to let the user know what they're getting
|
|
||||||
# into.
|
|
||||||
- trunk: "This is a general introduction to the dialogue tree."
|
|
||||||
|
|
||||||
# Branches are the content of a dialogue tree. Each branch is numbered, and that
|
|
||||||
# number is used as the primary means of navigation. The text of a branch is the
|
|
||||||
# story provided to the user; the result of getting to the branch. The leaves
|
|
||||||
# (the section titled leaf) represent the options. Options are displayed in the
|
|
||||||
# order they appear. Within a leaf, the text is what the option says, and the
|
|
||||||
# branch is the branch number which this option will lead to. Leading to branch
|
|
||||||
# number 0 will immediately exit the program.
|
|
||||||
#
|
|
||||||
# You can have as many branches and leaves as you wish, though having too many
|
|
||||||
# leaves may lead to both display problems, and paralyzing indecision.
|
|
||||||
-
|
|
||||||
branch:
|
|
||||||
number: 1
|
|
||||||
text: "The first branch. Displayed first, by default."
|
|
||||||
leaf:
|
|
||||||
-
|
|
||||||
text: "The first option for this branch. It leads to branch 2"
|
|
||||||
branch: 2
|
|
||||||
-
|
|
||||||
text: "The second branch. It immediately exits the program."
|
|
||||||
branch: 0
|
|
||||||
|
|
||||||
# A terminal branch is a branch which has no leaves. This represents an ending.
|
|
||||||
# Once a user hits a terminal branch, the program will display the branch text,
|
|
||||||
# and then redirect the user to branch 0, to exit.
|
|
||||||
-
|
|
||||||
branch:
|
|
||||||
number: 2
|
|
||||||
text: "This is a terminal branch. After displaying this text,
|
|
||||||
the program will exit."
|
|
|
@ -1,16 +0,0 @@
|
||||||
<!--
|
|
||||||
# @markup markdown
|
|
||||||
# @title Using the Editor
|
|
||||||
-->
|
|
||||||
# Sapling Editor
|
|
||||||
|
|
||||||
Sapling provides an editor for creating and modifying dialogue trees. The editor
|
|
||||||
allows for editing all parts of a tree, from the trunk to the leaves.
|
|
||||||
|
|
||||||
## Creating a new tree
|
|
||||||
|
|
||||||
Pending
|
|
||||||
|
|
||||||
## Editing an existing tree
|
|
||||||
|
|
||||||
Pending
|
|
|
@ -1,74 +0,0 @@
|
||||||
---
|
|
||||||
- trunk: "Example Quest: Learn what it looks like to use Sapling!"
|
|
||||||
|
|
||||||
-
|
|
||||||
branch:
|
|
||||||
number: 1
|
|
||||||
text: "You stumble upon the first branch of a dialogue tree.
|
|
||||||
You find yourself at a junction..."
|
|
||||||
leaf:
|
|
||||||
-
|
|
||||||
text: "Go to the next branch."
|
|
||||||
branch: 2
|
|
||||||
-
|
|
||||||
text: "Go to the frigid north-lands, because there's always a
|
|
||||||
frigid north-lands."
|
|
||||||
branch: 3
|
|
||||||
-
|
|
||||||
text: "Leave this silly place, but with a reason."
|
|
||||||
branch: 5
|
|
||||||
-
|
|
||||||
text: "Leave this silly place immediately, without any reason."
|
|
||||||
branch: 0
|
|
||||||
-
|
|
||||||
branch:
|
|
||||||
number: 2
|
|
||||||
text: "Ye find ye-self at branch 2. Your options are north, south
|
|
||||||
or Dennis."
|
|
||||||
leaf:
|
|
||||||
-
|
|
||||||
text: "North, to frigidity!"
|
|
||||||
branch: 3
|
|
||||||
-
|
|
||||||
text: "South, back the way you came!"
|
|
||||||
branch: 1
|
|
||||||
-
|
|
||||||
text: "Dennis"
|
|
||||||
branch: 6
|
|
||||||
-
|
|
||||||
branch:
|
|
||||||
number: 3
|
|
||||||
text: "It's cold up here. You decide to go someplace else!"
|
|
||||||
leaf:
|
|
||||||
-
|
|
||||||
text: "Head on home."
|
|
||||||
branch: 4
|
|
||||||
-
|
|
||||||
text: "Head south (back the way you came)"
|
|
||||||
branch: 2
|
|
||||||
-
|
|
||||||
branch:
|
|
||||||
number: 4
|
|
||||||
text: "You head on home! Bye bye!"
|
|
||||||
-
|
|
||||||
branch:
|
|
||||||
number: 5
|
|
||||||
text: "You leave the dialogue tree, and all its textual glory, behind
|
|
||||||
and go find a nice GUI to settle down with."
|
|
||||||
-
|
|
||||||
branch:
|
|
||||||
number: 6
|
|
||||||
text: "Dennis appreciates your interest, but is really just trying to
|
|
||||||
hangout and play video games."
|
|
||||||
leaf:
|
|
||||||
-
|
|
||||||
text: "Join Dennis, and play video games with him."
|
|
||||||
branch: 7
|
|
||||||
-
|
|
||||||
text: "Reconsider your options."
|
|
||||||
branch: 2
|
|
||||||
-
|
|
||||||
branch:
|
|
||||||
number: 7
|
|
||||||
text: "You sit down next to Dennis, and together you conquer all sorts of
|
|
||||||
realms and wizards and stuff. Nice!"
|
|
Loading…
Reference in a new issue