gamefic 1.5.1 → 1.6.0
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/gamefic.rb +1 -3
- data/lib/gamefic/action.rb +140 -79
- data/lib/gamefic/character.rb +120 -53
- data/lib/gamefic/character/state.rb +12 -0
- data/lib/gamefic/core_ext/array.rb +53 -11
- data/lib/gamefic/core_ext/string.rb +1 -0
- data/lib/gamefic/describable.rb +37 -11
- data/lib/gamefic/engine/base.rb +17 -4
- data/lib/gamefic/engine/tty.rb +4 -0
- data/lib/gamefic/entity.rb +4 -15
- data/lib/gamefic/matchable.rb +50 -0
- data/lib/gamefic/messaging.rb +45 -0
- data/lib/gamefic/node.rb +16 -0
- data/lib/gamefic/plot.rb +27 -33
- data/lib/gamefic/plot/{article_mount.rb → articles.rb} +22 -22
- data/lib/gamefic/plot/callbacks.rb +30 -4
- data/lib/gamefic/plot/{command_mount.rb → commands.rb} +121 -121
- data/lib/gamefic/plot/entities.rb +3 -3
- data/lib/gamefic/plot/host.rb +3 -3
- data/lib/gamefic/plot/playbook.rb +74 -30
- data/lib/gamefic/plot/scenes.rb +149 -0
- data/lib/gamefic/plot/snapshot.rb +14 -39
- data/lib/gamefic/plot/theater.rb +73 -0
- data/lib/gamefic/query.rb +6 -19
- data/lib/gamefic/query/base.rb +127 -246
- data/lib/gamefic/query/children.rb +6 -7
- data/lib/gamefic/query/descendants.rb +15 -0
- data/lib/gamefic/query/family.rb +19 -7
- data/lib/gamefic/query/itself.rb +13 -0
- data/lib/gamefic/query/matches.rb +67 -11
- data/lib/gamefic/query/parent.rb +6 -7
- data/lib/gamefic/query/siblings.rb +10 -7
- data/lib/gamefic/query/text.rb +39 -35
- data/lib/gamefic/scene.rb +1 -1
- data/lib/gamefic/scene/active.rb +12 -6
- data/lib/gamefic/scene/base.rb +56 -5
- data/lib/gamefic/scene/conclusion.rb +3 -0
- data/lib/gamefic/scene/custom.rb +0 -83
- data/lib/gamefic/scene/multiple_choice.rb +54 -32
- data/lib/gamefic/scene/multiple_scene.rb +11 -6
- data/lib/gamefic/scene/pause.rb +3 -4
- data/lib/gamefic/scene/yes_or_no.rb +23 -9
- data/lib/gamefic/script/base.rb +4 -0
- data/lib/gamefic/subplot.rb +22 -19
- data/lib/gamefic/syntax.rb +7 -15
- data/lib/gamefic/user/base.rb +7 -13
- data/lib/gamefic/user/buffer.rb +7 -0
- data/lib/gamefic/user/tty.rb +13 -12
- data/lib/gamefic/version.rb +1 -1
- metadata +11 -37
- data/lib/gamefic/director.rb +0 -23
- data/lib/gamefic/director/delegate.rb +0 -126
- data/lib/gamefic/director/order.rb +0 -17
- data/lib/gamefic/director/parser.rb +0 -137
- data/lib/gamefic/keywords.rb +0 -67
- data/lib/gamefic/plot/query_mount.rb +0 -9
- data/lib/gamefic/plot/scene_mount.rb +0 -182
- data/lib/gamefic/query/ambiguous_children.rb +0 -5
- data/lib/gamefic/query/expression.rb +0 -47
- data/lib/gamefic/query/many_children.rb +0 -7
- data/lib/gamefic/query/plural_children.rb +0 -14
- data/lib/gamefic/query/self.rb +0 -10
- data/lib/gamefic/scene_data.rb +0 -10
- data/lib/gamefic/scene_data/base.rb +0 -12
- data/lib/gamefic/scene_data/multiple_choice.rb +0 -19
- data/lib/gamefic/scene_data/multiple_scene.rb +0 -21
- data/lib/gamefic/scene_data/yes_or_no.rb +0 -18
- data/lib/gamefic/serialized.rb +0 -24
- data/lib/gamefic/stage.rb +0 -106
@@ -8,54 +8,76 @@ module Gamefic
|
|
8
8
|
# instead of a String.
|
9
9
|
#
|
10
10
|
class Scene::MultipleChoice < Scene::Custom
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
attr_reader :index
|
12
|
+
attr_reader :number
|
13
|
+
attr_reader :selection
|
14
|
+
attr_writer :invalid_message
|
14
15
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
do_start_block actor, data
|
19
|
-
tell_options actor, data
|
16
|
+
def post_initialize
|
17
|
+
self.type = 'MultipleChoice'
|
18
|
+
self.prompt = 'Enter a choice:'
|
20
19
|
end
|
20
|
+
|
21
|
+
#def start actor
|
22
|
+
# data = start_data_for(actor)
|
23
|
+
# data.clear
|
24
|
+
# do_start_block actor, data
|
25
|
+
# tell_options
|
26
|
+
#end
|
21
27
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
+
def start
|
29
|
+
super
|
30
|
+
raise "MultipleChoice scene has zero options" if options.empty?
|
31
|
+
end
|
32
|
+
|
33
|
+
def finish
|
34
|
+
#data = finish_data_for(actor, input)
|
35
|
+
get_choice
|
36
|
+
if selection.nil?
|
37
|
+
actor.tell invalid_message
|
38
|
+
tell_options
|
28
39
|
else
|
29
|
-
|
40
|
+
super
|
30
41
|
end
|
31
|
-
|
42
|
+
end
|
43
|
+
|
44
|
+
def options
|
45
|
+
@options ||= []
|
46
|
+
end
|
47
|
+
|
48
|
+
def invalid_message
|
49
|
+
@invalid_message ||= 'That is not a valid choice.'
|
50
|
+
end
|
51
|
+
|
52
|
+
def state
|
53
|
+
super.merge options: options
|
32
54
|
end
|
33
55
|
|
34
56
|
private
|
35
|
-
|
36
|
-
def get_choice
|
37
|
-
if
|
38
|
-
|
39
|
-
|
40
|
-
|
57
|
+
|
58
|
+
def get_choice
|
59
|
+
if input.strip =~ /^[0-9]+$/ and input.to_i > 0
|
60
|
+
@number = input.to_i
|
61
|
+
@index = number - 1
|
62
|
+
@selection = options[index]
|
41
63
|
else
|
42
|
-
|
43
|
-
|
44
|
-
if o.casecmp(
|
45
|
-
|
46
|
-
|
47
|
-
|
64
|
+
i = 0
|
65
|
+
options.each { |o|
|
66
|
+
if o.casecmp(input).zero?
|
67
|
+
@selection = o
|
68
|
+
@index = i
|
69
|
+
@number = index + 1
|
48
70
|
break
|
49
71
|
end
|
50
|
-
|
72
|
+
i += 1
|
51
73
|
}
|
52
74
|
end
|
53
75
|
end
|
54
76
|
|
55
|
-
def tell_options
|
77
|
+
def tell_options
|
56
78
|
list = '<ol class="multiple_choice">'
|
57
|
-
|
58
|
-
list += "<li>#{o}</li>"
|
79
|
+
options.each { |o|
|
80
|
+
list += "<li><a href=\"#\" rel=\"gamefic\" data-command=\"#{o}\">#{o}</a></li>"
|
59
81
|
}
|
60
82
|
list += "</ol>"
|
61
83
|
actor.tell list
|
@@ -1,14 +1,19 @@
|
|
1
1
|
module Gamefic
|
2
2
|
|
3
3
|
class Scene::MultipleScene < Scene::MultipleChoice
|
4
|
-
def
|
5
|
-
|
4
|
+
def option_map
|
5
|
+
@option_map ||= {}
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
def map option, scene
|
9
|
+
options.push option
|
10
|
+
option_map[option] = scene
|
11
|
+
end
|
12
|
+
|
13
|
+
def finish
|
14
|
+
get_choice
|
15
|
+
unless selection.nil?
|
16
|
+
actor.cue option_map[selection]
|
12
17
|
end
|
13
18
|
end
|
14
19
|
end
|
data/lib/gamefic/scene/pause.rb
CHANGED
@@ -3,10 +3,9 @@ module Gamefic
|
|
3
3
|
# Pause for user input.
|
4
4
|
#
|
5
5
|
class Scene::Pause < Scene::Custom
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
do_start_block actor, data
|
6
|
+
def post_initialize
|
7
|
+
self.type = 'Pause'
|
8
|
+
self.prompt = 'Press enter to continue...'
|
10
9
|
end
|
11
10
|
end
|
12
11
|
|
@@ -6,18 +6,32 @@ module Gamefic
|
|
6
6
|
# other scene has been prepared or cued.
|
7
7
|
#
|
8
8
|
class Scene::YesOrNo < Scene::Custom
|
9
|
-
def
|
10
|
-
|
9
|
+
def post_initialize
|
10
|
+
self.type = 'YesOrNo'
|
11
|
+
self.prompt = 'Yes or No?'
|
11
12
|
end
|
12
13
|
|
13
|
-
def
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
def yes?
|
15
|
+
input.to_s[0,1].downcase == 'y'
|
16
|
+
end
|
17
|
+
|
18
|
+
def no?
|
19
|
+
input.to_s[0,1].downcase == 'n'
|
20
|
+
end
|
21
|
+
|
22
|
+
def invalid_message
|
23
|
+
@invalid_message ||= 'Please enter Yes or No.'
|
24
|
+
end
|
25
|
+
|
26
|
+
def prompt
|
27
|
+
@prompt ||= 'Yes or No?'
|
28
|
+
end
|
29
|
+
|
30
|
+
def finish
|
31
|
+
if yes? or no?
|
32
|
+
super
|
19
33
|
else
|
20
|
-
actor.tell
|
34
|
+
actor.tell invalid_message
|
21
35
|
end
|
22
36
|
end
|
23
37
|
end
|
data/lib/gamefic/script/base.rb
CHANGED
@@ -4,6 +4,7 @@ module Gamefic
|
|
4
4
|
def initialize
|
5
5
|
raise "#initialize must be defined in subclasses"
|
6
6
|
end
|
7
|
+
|
7
8
|
# Get the script's text.
|
8
9
|
# The text must be source code suitable for evaluation via Plot#stage.
|
9
10
|
#
|
@@ -11,12 +12,14 @@ module Gamefic
|
|
11
12
|
def read
|
12
13
|
raise "#read must be defined in subclasses"
|
13
14
|
end
|
15
|
+
|
14
16
|
# Get the script's path.
|
15
17
|
#
|
16
18
|
# @return [String]
|
17
19
|
def path
|
18
20
|
raise "#path must be defined in subclasses"
|
19
21
|
end
|
22
|
+
|
20
23
|
# Get the absolute path of the script's original file, or its URL for
|
21
24
|
# sources that are not file-based.
|
22
25
|
#
|
@@ -24,6 +27,7 @@ module Gamefic
|
|
24
27
|
def absolute_path
|
25
28
|
raise "#absolute_path must be defined in subclasses"
|
26
29
|
end
|
30
|
+
|
27
31
|
# Script objects are equal if their relative paths are the same. Note that
|
28
32
|
# they are still considered equal if their absolute paths are different,
|
29
33
|
# or even if they come from different types of sources.
|
data/lib/gamefic/subplot.rb
CHANGED
@@ -3,42 +3,40 @@ require 'gamefic/plot'
|
|
3
3
|
module Gamefic
|
4
4
|
|
5
5
|
class Subplot
|
6
|
-
include Stage
|
7
|
-
|
8
6
|
attr_reader :plot
|
9
7
|
attr_writer :denied_message
|
10
8
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
# @!parse include Plot::SceneMount
|
18
|
-
mount Plot::SceneMount
|
19
|
-
|
20
|
-
expose :plot, :conclude
|
9
|
+
include Plot::Theater
|
10
|
+
include Plot::Entities
|
11
|
+
include Plot::Commands
|
12
|
+
include Plot::Callbacks
|
13
|
+
include Plot::Scenes
|
14
|
+
include Plot::Articles
|
21
15
|
|
22
16
|
class << self
|
23
|
-
|
24
|
-
@start_proc
|
25
|
-
end
|
17
|
+
attr_reader :start_proc
|
26
18
|
|
27
|
-
|
19
|
+
protected
|
28
20
|
|
29
21
|
def on_start &block
|
30
22
|
@start_proc = block
|
31
23
|
end
|
32
24
|
end
|
33
25
|
|
34
|
-
def initialize plot, introduce: nil
|
26
|
+
def initialize plot, introduce: nil, next_cue: nil, busy_cue: nil
|
35
27
|
@plot = plot
|
28
|
+
@next_cue = next_cue
|
29
|
+
@busy_cue = busy_cue
|
36
30
|
@concluded = false
|
37
31
|
stage &self.class.start_proc unless self.class.start_proc.nil?
|
38
32
|
playbook.freeze
|
39
33
|
self.introduce introduce unless introduce.nil?
|
40
34
|
end
|
41
35
|
|
36
|
+
def subplot
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
42
40
|
def default_scene
|
43
41
|
plot.default_scene
|
44
42
|
end
|
@@ -62,7 +60,11 @@ module Gamefic
|
|
62
60
|
|
63
61
|
def introduce player
|
64
62
|
if plot.in_subplot?(player)
|
65
|
-
|
63
|
+
if @busy_cue.nil?
|
64
|
+
player.tell denied_message
|
65
|
+
else
|
66
|
+
player.cue @busy_cue
|
67
|
+
end
|
66
68
|
else
|
67
69
|
super
|
68
70
|
end
|
@@ -70,6 +72,7 @@ module Gamefic
|
|
70
72
|
|
71
73
|
def exeunt player
|
72
74
|
player.playbook = plot.playbook
|
75
|
+
player.cue (@next_cue || default_scene)
|
73
76
|
p_players.delete player
|
74
77
|
end
|
75
78
|
|
@@ -100,5 +103,5 @@ module Gamefic
|
|
100
103
|
call_update
|
101
104
|
end
|
102
105
|
end
|
103
|
-
|
106
|
+
|
104
107
|
end
|
data/lib/gamefic/syntax.rb
CHANGED
@@ -6,8 +6,7 @@ module Gamefic
|
|
6
6
|
attr_reader :token_count, :first_word, :verb, :template, :command
|
7
7
|
@@phrase = '([\w\W\s\S]*?)'
|
8
8
|
|
9
|
-
def initialize template,
|
10
|
-
command = command.join(' ')
|
9
|
+
def initialize template, command
|
11
10
|
words = template.split_words
|
12
11
|
@token_count = words.length
|
13
12
|
command_words = command.split_words
|
@@ -99,19 +98,12 @@ module Gamefic
|
|
99
98
|
result = syntax.tokenize text
|
100
99
|
matches.push(result) if !result.nil?
|
101
100
|
}
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
ca += 1
|
109
|
-
}
|
110
|
-
b.arguments.each { |t|
|
111
|
-
break if t.nil?
|
112
|
-
cb += 1
|
113
|
-
}
|
114
|
-
cb <=> ca
|
101
|
+
matches.sort! { |a,b|
|
102
|
+
if a.arguments.length == b.arguments.length
|
103
|
+
b.verb.to_s <=> a.verb.to_s
|
104
|
+
else
|
105
|
+
b.arguments.length <=> a.arguments.length
|
106
|
+
end
|
115
107
|
}
|
116
108
|
matches
|
117
109
|
end
|
data/lib/gamefic/user/base.rb
CHANGED
@@ -1,21 +1,15 @@
|
|
1
1
|
module Gamefic
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
class User::Base
|
6
|
-
def send message
|
7
|
-
buffer.send message
|
2
|
+
class User::Base
|
3
|
+
def update state
|
4
|
+
raise 'Unimplemented'
|
8
5
|
end
|
9
6
|
|
10
|
-
def
|
11
|
-
|
7
|
+
def save filename, snapshot
|
8
|
+
raise 'Unimplemented'
|
12
9
|
end
|
13
10
|
|
14
|
-
|
15
|
-
|
16
|
-
def buffer
|
17
|
-
@buffer ||= User::Buffer.new
|
11
|
+
def restore filename
|
12
|
+
raise 'Unimplemented'
|
18
13
|
end
|
19
14
|
end
|
20
|
-
|
21
15
|
end
|
data/lib/gamefic/user/buffer.rb
CHANGED
data/lib/gamefic/user/tty.rb
CHANGED
@@ -6,10 +6,17 @@ module Gamefic
|
|
6
6
|
|
7
7
|
# Extend User::Base to convert HTML into ANSI text.
|
8
8
|
#
|
9
|
+
# @note Due to their dependency on io/console, User::Tty and Engine::Tty are
|
10
|
+
# not included in the core Gamefic library. `require gamefic/tty` if you
|
11
|
+
# need them.
|
12
|
+
#
|
9
13
|
class User::Tty < User::Base
|
14
|
+
def update state
|
15
|
+
print Gamefic::Text::Html::Conversions.html_to_ansi(state[:output])
|
16
|
+
end
|
17
|
+
|
10
18
|
def save filename, snapshot
|
11
|
-
|
12
|
-
json = JSON.generate data
|
19
|
+
json = JSON.generate snapshot
|
13
20
|
if json.nil?
|
14
21
|
@character.tell "Nothing to save."
|
15
22
|
end
|
@@ -21,7 +28,6 @@ module Gamefic
|
|
21
28
|
File.open(filename, 'w') do |f|
|
22
29
|
f.write json
|
23
30
|
end
|
24
|
-
@character.tell "Game saved."
|
25
31
|
end
|
26
32
|
end
|
27
33
|
|
@@ -33,21 +39,16 @@ module Gamefic
|
|
33
39
|
if filename != ''
|
34
40
|
if File.exists?(filename)
|
35
41
|
data = JSON.parse File.read(filename), symbolize_names: true
|
36
|
-
if (data[:metadata] != @character.plot.metadata)
|
37
|
-
|
38
|
-
else
|
42
|
+
#if (data[:metadata] != @character.plot.metadata)
|
43
|
+
# @character.tell "The save file is not compatible with this version of the game."
|
44
|
+
#else
|
39
45
|
return data
|
40
|
-
end
|
46
|
+
#end
|
41
47
|
else
|
42
48
|
@character.tell "File \"#{filename}\" not found."
|
43
49
|
end
|
44
50
|
end
|
45
51
|
nil
|
46
52
|
end
|
47
|
-
|
48
|
-
def flush
|
49
|
-
Gamefic::Text::Html::Conversions.html_to_ansi(super)
|
50
|
-
end
|
51
53
|
end
|
52
|
-
|
53
54
|
end
|
data/lib/gamefic/version.rb
CHANGED