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
@@ -1,10 +1,9 @@
|
|
1
|
-
module Gamefic
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
subject.children
|
1
|
+
module Gamefic
|
2
|
+
module Query
|
3
|
+
class Children < Base
|
4
|
+
def context_from(subject)
|
5
|
+
subject.children
|
6
|
+
end
|
8
7
|
end
|
9
8
|
end
|
10
9
|
end
|
data/lib/gamefic/query/family.rb
CHANGED
@@ -1,10 +1,22 @@
|
|
1
|
-
module Gamefic
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
1
|
+
module Gamefic
|
2
|
+
module Query
|
3
|
+
class Family < Base
|
4
|
+
def context_from(subject)
|
5
|
+
result = []
|
6
|
+
top = subject.parent
|
7
|
+
unless top.nil?
|
8
|
+
#until top.parent.nil?
|
9
|
+
# top = top.parent
|
10
|
+
#end
|
11
|
+
result.concat subquery_accessible(top)
|
12
|
+
end
|
13
|
+
result.delete subject
|
14
|
+
subject.children.each { |c|
|
15
|
+
result.push c
|
16
|
+
result.concat subquery_accessible(c)
|
17
|
+
}
|
18
|
+
result
|
19
|
+
end
|
8
20
|
end
|
9
21
|
end
|
10
22
|
end
|
@@ -1,11 +1,67 @@
|
|
1
|
-
module Gamefic
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
1
|
+
module Gamefic
|
2
|
+
module Query
|
3
|
+
class Matches
|
4
|
+
attr_accessor :objects, :matching, :remaining
|
5
|
+
|
6
|
+
def initialize objects, matching, remaining
|
7
|
+
@objects = objects
|
8
|
+
@matching = matching
|
9
|
+
@remaining = remaining
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.execute objects, description, continued: false
|
13
|
+
if continued
|
14
|
+
match_with_remainder objects, description
|
15
|
+
else
|
16
|
+
match_without_remainder objects, description
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class << self
|
21
|
+
private
|
22
|
+
|
23
|
+
def match_without_remainder objects, description
|
24
|
+
matches = objects.select{ |e| e.match?(description) }
|
25
|
+
if matches.empty?
|
26
|
+
matching = ''
|
27
|
+
remaining = description
|
28
|
+
else
|
29
|
+
matching = description
|
30
|
+
remaining = ''
|
31
|
+
end
|
32
|
+
Matches.new(matches, matching, remaining)
|
33
|
+
end
|
34
|
+
|
35
|
+
def match_with_remainder objects, description
|
36
|
+
matching_objects = objects
|
37
|
+
matching_text = []
|
38
|
+
words = description.split(Matchable::SPLIT_REGEXP)
|
39
|
+
i = 0
|
40
|
+
#cursor = []
|
41
|
+
words.each { |w|
|
42
|
+
cursor = inner_match matching_objects, words, matching_text, i, w
|
43
|
+
break if cursor.empty? or (cursor & matching_objects).empty?
|
44
|
+
matching_objects = (cursor & matching_objects)
|
45
|
+
i += 1
|
46
|
+
}
|
47
|
+
objects = matching_objects
|
48
|
+
matching = matching_text.uniq.join(' ')
|
49
|
+
remaining = words[i..-1].join(' ')
|
50
|
+
m = Matches.new(objects, matching, remaining)
|
51
|
+
m
|
52
|
+
end
|
53
|
+
|
54
|
+
def inner_match matching_objects, words, matching_text, i, w
|
55
|
+
cursor = []
|
56
|
+
matching_objects.each { |o|
|
57
|
+
if o.match?(words[0..i].join(' '), fuzzy: true)
|
58
|
+
cursor.push o
|
59
|
+
matching_text.push w
|
60
|
+
end
|
61
|
+
}
|
62
|
+
cursor
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/gamefic/query/parent.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
|
-
module Gamefic
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
[subject.parent]
|
1
|
+
module Gamefic
|
2
|
+
module Query
|
3
|
+
class Parent < Base
|
4
|
+
def context_from(subject)
|
5
|
+
subject.parent.nil? ? [] : [subject.parent]
|
6
|
+
end
|
8
7
|
end
|
9
8
|
end
|
10
9
|
end
|
@@ -1,10 +1,13 @@
|
|
1
|
-
module Gamefic
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
1
|
+
module Gamefic
|
2
|
+
module Query
|
3
|
+
class Siblings < Base
|
4
|
+
def context_from(subject)
|
5
|
+
result = []
|
6
|
+
unless subject.parent.nil?
|
7
|
+
result.concat(subject.parent.children - [subject])
|
8
|
+
end
|
9
|
+
result
|
10
|
+
end
|
8
11
|
end
|
9
12
|
end
|
10
13
|
end
|
data/lib/gamefic/query/text.rb
CHANGED
@@ -1,43 +1,47 @@
|
|
1
|
-
module Gamefic
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
if description.include?(word)
|
12
|
-
valid = true
|
13
|
-
break
|
14
|
-
end
|
15
|
-
}
|
16
|
-
valid
|
17
|
-
end
|
18
|
-
def execute(subject, description)
|
19
|
-
if @arguments.length == 0
|
20
|
-
return Matches.new([description], description, '')
|
1
|
+
module Gamefic
|
2
|
+
module Query
|
3
|
+
class Text < Base
|
4
|
+
def initialize *arguments
|
5
|
+
arguments.each { |a|
|
6
|
+
if (a.kind_of?(Symbol) or a.kind_of?(String)) and !a.to_s.end_with?('?')
|
7
|
+
raise ArgumentError.new("Text query arguments can only be boolean method names (:method?) or regular expressions")
|
8
|
+
end
|
9
|
+
}
|
10
|
+
super
|
21
11
|
end
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
12
|
+
def resolve(subject, token, continued: false)
|
13
|
+
parts = token.split(Matchable::SPLIT_REGEXP)
|
14
|
+
cursor = []
|
15
|
+
matches = []
|
16
|
+
i = 0
|
17
|
+
parts.each { |w|
|
18
|
+
cursor.push w
|
19
|
+
matches = cursor if accept?(cursor.join(' '))
|
20
|
+
i += 1
|
21
|
+
}
|
22
|
+
if continued
|
23
|
+
Matches.new([matches.join(' ')], matches.join(' '), parts[i..-1].join(' '))
|
29
24
|
else
|
30
|
-
|
25
|
+
if matches.length == parts.length
|
26
|
+
Matches.new([matches.join(' ')], matches.join(' '), '')
|
27
|
+
else
|
28
|
+
Matches.new([], '', parts.join(' '))
|
29
|
+
end
|
31
30
|
end
|
32
31
|
end
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
32
|
+
|
33
|
+
def include?(subject, token)
|
34
|
+
accept?(token)
|
35
|
+
end
|
36
|
+
|
37
|
+
def accept?(entity)
|
38
|
+
return false unless entity.kind_of?(String) and !entity.empty?
|
39
|
+
super
|
40
|
+
end
|
41
|
+
|
42
|
+
def precision
|
43
|
+
0
|
37
44
|
end
|
38
|
-
end
|
39
|
-
def test_arguments arguments
|
40
|
-
# No test for text
|
41
45
|
end
|
42
46
|
end
|
43
47
|
end
|
data/lib/gamefic/scene.rb
CHANGED
data/lib/gamefic/scene/active.rb
CHANGED
@@ -5,16 +5,22 @@ module Gamefic
|
|
5
5
|
# a Plot.
|
6
6
|
#
|
7
7
|
class Scene::Active < Scene::Base
|
8
|
-
|
9
|
-
|
10
|
-
def initialize plot
|
11
|
-
@plot = plot
|
8
|
+
def post_initialize
|
9
|
+
self.type = 'Active'
|
12
10
|
end
|
13
11
|
|
14
|
-
def finish
|
15
|
-
|
12
|
+
def finish
|
13
|
+
super
|
14
|
+
o = nil
|
15
|
+
o = actor.perform input.strip unless input.nil?
|
16
16
|
actor.performed o
|
17
17
|
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def type
|
21
|
+
'Active'
|
22
|
+
end
|
23
|
+
end
|
18
24
|
end
|
19
25
|
|
20
26
|
end
|
data/lib/gamefic/scene/base.rb
CHANGED
@@ -4,21 +4,72 @@ module Gamefic
|
|
4
4
|
# should inherit from it.
|
5
5
|
#
|
6
6
|
class Scene::Base
|
7
|
-
|
7
|
+
attr_reader :actor
|
8
|
+
attr_writer :type
|
9
|
+
attr_writer :prompt
|
10
|
+
attr_reader :input
|
11
|
+
|
12
|
+
def initialize actor
|
13
|
+
@actor = actor
|
14
|
+
post_initialize
|
15
|
+
end
|
16
|
+
|
17
|
+
def post_initialize
|
18
|
+
end
|
19
|
+
|
20
|
+
def on_finish &block
|
21
|
+
@finish_block = block
|
8
22
|
end
|
9
23
|
|
10
|
-
def
|
24
|
+
def update
|
25
|
+
@input = actor.queue.shift
|
26
|
+
finish
|
27
|
+
end
|
28
|
+
|
29
|
+
def start
|
30
|
+
self.class.initialize_block.call @actor, self unless self.class.initialize_block.nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
def finish
|
34
|
+
@finish_block.call @actor, self unless @finish_block.nil?
|
35
|
+
end
|
36
|
+
|
37
|
+
def flush
|
38
|
+
@state.clear
|
39
|
+
end
|
40
|
+
|
41
|
+
def state
|
42
|
+
{
|
43
|
+
scene: type, prompt: prompt, input: input #, output: actor.messages, busy: !actor.queue.empty?
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.subclass &block
|
48
|
+
c = Class.new(self) do
|
49
|
+
on_initialize &block
|
50
|
+
end
|
51
|
+
c
|
11
52
|
end
|
12
53
|
|
13
54
|
# Get the prompt to be displayed to the user when accepting input.
|
14
55
|
#
|
15
56
|
# @return [String] The text to be displayed.
|
16
|
-
def
|
17
|
-
'>'
|
57
|
+
def prompt
|
58
|
+
@prompt ||= '>'
|
18
59
|
end
|
19
60
|
|
20
61
|
def type
|
21
|
-
|
62
|
+
@type ||= 'Scene'
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.on_initialize &block
|
66
|
+
@initialize_block = block
|
67
|
+
end
|
68
|
+
|
69
|
+
class << self
|
70
|
+
def initialize_block
|
71
|
+
@initialize_block
|
72
|
+
end
|
22
73
|
end
|
23
74
|
end
|
24
75
|
|
data/lib/gamefic/scene/custom.rb
CHANGED
@@ -4,89 +4,6 @@ module Gamefic
|
|
4
4
|
# instantiation. It is suitable for direct instantiation or subclassing.
|
5
5
|
#
|
6
6
|
class Scene::Custom < Scene::Base
|
7
|
-
def initialize
|
8
|
-
yield self if block_given?
|
9
|
-
end
|
10
|
-
|
11
|
-
def data_class
|
12
|
-
SceneData::Base
|
13
|
-
end
|
14
|
-
|
15
|
-
# Define a block to be executed at the start of the scene.
|
16
|
-
# Unlike on_finish, start blocks may be executed more than once per turn,
|
17
|
-
# and more than one scene may be started in a single turn.
|
18
|
-
# It always gets executed in a plot's on_ready event and whenever it gets
|
19
|
-
# cued. (If the character is already in the scene being cued, on_start
|
20
|
-
# does not get repeated.)
|
21
|
-
#
|
22
|
-
# @yieldparam [Character]
|
23
|
-
# @yieldparam [SceneData::Base]
|
24
|
-
def on_start &block
|
25
|
-
@start = block
|
26
|
-
end
|
27
|
-
|
28
|
-
# Define a block to be executed at the end of the scene.
|
29
|
-
# The scene data passed to this block will include the character's input
|
30
|
-
# for this turn.
|
31
|
-
# Unlike on_start, finish only gets executed once per turn, during the
|
32
|
-
# plot's on_update event.
|
33
|
-
#
|
34
|
-
# @yieldparam [Character]
|
35
|
-
# @yieldparam [SceneData::Base]
|
36
|
-
def on_finish &block
|
37
|
-
@finish = block
|
38
|
-
end
|
39
|
-
|
40
|
-
# Start the scene.
|
41
|
-
# This method typically gets called from the plot during the on_ready
|
42
|
-
# event and whenever a character cues a scene.
|
43
|
-
#
|
44
|
-
def start actor
|
45
|
-
data = start_data_for(actor)
|
46
|
-
do_start_block actor, data
|
47
|
-
data
|
48
|
-
end
|
49
|
-
|
50
|
-
# End the scene.
|
51
|
-
# This method typically gets called from the plot during the on_update
|
52
|
-
# event.
|
53
|
-
#
|
54
|
-
def finish actor, input
|
55
|
-
data = finish_data_for(actor, input)
|
56
|
-
do_finish_block actor, data
|
57
|
-
end
|
58
|
-
|
59
|
-
# Get the text to be displayed to the user when receiving input.
|
60
|
-
#
|
61
|
-
# @return [String]
|
62
|
-
def prompt_for actor
|
63
|
-
return character_data[actor].prompt unless character_data[actor].nil?
|
64
|
-
'>'
|
65
|
-
end
|
66
|
-
|
67
|
-
private
|
68
|
-
|
69
|
-
def do_start_block actor, data
|
70
|
-
@start.call actor, data unless @start.nil?
|
71
|
-
end
|
72
|
-
|
73
|
-
def do_finish_block actor, data
|
74
|
-
@finish.call actor, data unless @finish.nil?
|
75
|
-
end
|
76
|
-
|
77
|
-
def character_data
|
78
|
-
@character_data ||= {}
|
79
|
-
end
|
80
|
-
|
81
|
-
def start_data_for actor
|
82
|
-
character_data[actor] ||= data_class.new
|
83
|
-
end
|
84
|
-
|
85
|
-
def finish_data_for actor, input
|
86
|
-
data = character_data[actor]
|
87
|
-
data.input = input.strip
|
88
|
-
data
|
89
|
-
end
|
90
7
|
end
|
91
8
|
|
92
9
|
end
|