gamefic 3.0.0 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -1
- data/lib/gamefic/action.rb +9 -1
- data/lib/gamefic/active/epic.rb +8 -3
- data/lib/gamefic/active/messaging.rb +2 -0
- data/lib/gamefic/active/take.rb +3 -5
- data/lib/gamefic/active.rb +32 -13
- data/lib/gamefic/command.rb +4 -15
- data/lib/gamefic/composer.rb +70 -0
- data/lib/gamefic/dispatcher.rb +47 -40
- data/lib/gamefic/entity.rb +3 -5
- data/lib/gamefic/expression.rb +31 -0
- data/lib/gamefic/plot.rb +1 -1
- data/lib/gamefic/props/default.rb +10 -4
- data/lib/gamefic/props/output.rb +107 -0
- data/lib/gamefic/props/pause.rb +2 -0
- data/lib/gamefic/props.rb +1 -0
- data/lib/gamefic/query/base.rb +24 -0
- data/lib/gamefic/query/general.rb +4 -0
- data/lib/gamefic/query/scoped.rb +5 -0
- data/lib/gamefic/query/text.rb +16 -5
- data/lib/gamefic/response.rb +19 -25
- data/lib/gamefic/rulebook/events.rb +7 -7
- data/lib/gamefic/rulebook.rb +2 -2
- data/lib/gamefic/scanner.rb +54 -25
- data/lib/gamefic/scene/default.rb +3 -3
- data/lib/gamefic/scene/multiple_choice.rb +1 -1
- data/lib/gamefic/scriptable/entities.rb +8 -5
- data/lib/gamefic/scriptable/proxy.rb +13 -0
- data/lib/gamefic/scriptable/queries.rb +2 -2
- data/lib/gamefic/scriptable/scenes.rb +6 -6
- data/lib/gamefic/snapshot.rb +9 -1
- data/lib/gamefic/syntax.rb +4 -4
- data/lib/gamefic/vault.rb +2 -0
- data/lib/gamefic/version.rb +1 -1
- data/lib/gamefic.rb +2 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ac4f50caef9bd101bf90447e3ab289b05a29470e8f722ad391f7f0c9d8c4a921
|
4
|
+
data.tar.gz: 926b7d40dc87036e3759a1a464d3db3c82187da4f829731d0d82b053ac5e52a4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a4b426b4703a29717dbcc59bfee2e3f5d3b1b2ceeb6121741f52111e5fe2d8165e0946f8c3a085f1a3c4094edab11e2966f751dbc3cfc1541809ebc3a9ad970
|
7
|
+
data.tar.gz: ba3f3e82bd772ae392ffb23b056b62de2c1b5bebb0e810fea81bd59449d3e64c8c848f748803ac36f155ad3a2891b0e42d76ca48e4e74239a776670f19fdcc0e
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,17 @@
|
|
1
|
-
## 3.
|
1
|
+
## 3.2.0 - April 9, 2024
|
2
|
+
- Bug fix for marshal of structs in Opal
|
3
|
+
- Add last_input and last_prompt at start of take
|
4
|
+
|
5
|
+
## 3.1.0 - April 8, 2024
|
6
|
+
- Dispatcher prioritizes strict token matches
|
7
|
+
- Scanner builds commands
|
8
|
+
- Tokenize expressions and execute commands
|
9
|
+
- Delete concluded subplots last in Plot#ready
|
10
|
+
- Fix plot conclusion check after subplots conclude
|
11
|
+
- Correct contexts for conclude and output blocks
|
12
|
+
- Reinstate Active#last_input
|
13
|
+
|
14
|
+
## 3.0.0 - January 27, 2024
|
2
15
|
- Instantiate subplots from snapshots
|
3
16
|
- Split Action into Response and Action
|
4
17
|
- Logging
|
data/lib/gamefic/action.rb
CHANGED
@@ -13,8 +13,10 @@ module Gamefic
|
|
13
13
|
# action's performance.
|
14
14
|
#
|
15
15
|
class Hook
|
16
|
+
# @param [Array<Symbol>]
|
16
17
|
attr_reader :verbs
|
17
18
|
|
19
|
+
# @param [Proc]
|
18
20
|
attr_reader :block
|
19
21
|
|
20
22
|
def initialize *verbs, &block
|
@@ -45,11 +47,13 @@ module Gamefic
|
|
45
47
|
@response = response
|
46
48
|
end
|
47
49
|
|
50
|
+
# @return [self]
|
48
51
|
def execute
|
49
|
-
return if cancelled?
|
52
|
+
return self if cancelled? || executed?
|
50
53
|
|
51
54
|
@executed = true
|
52
55
|
response.execute actor, *arguments
|
56
|
+
self
|
53
57
|
end
|
54
58
|
|
55
59
|
# True if the response has been executed. False typically means that the
|
@@ -75,6 +79,10 @@ module Gamefic
|
|
75
79
|
response.verb
|
76
80
|
end
|
77
81
|
|
82
|
+
def narrative
|
83
|
+
response.narrative
|
84
|
+
end
|
85
|
+
|
78
86
|
def meta?
|
79
87
|
response.meta?
|
80
88
|
end
|
data/lib/gamefic/active/epic.rb
CHANGED
@@ -47,9 +47,14 @@ module Gamefic
|
|
47
47
|
narratives.one?
|
48
48
|
end
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
def syntaxes
|
51
|
+
rulebooks.flat_map(&:syntaxes)
|
52
|
+
end
|
53
|
+
|
54
|
+
def responses_for(*verbs)
|
55
|
+
rulebooks.to_a
|
56
|
+
.reverse
|
57
|
+
.flat_map { |rb| rb.responses_for(*verbs) }
|
53
58
|
end
|
54
59
|
|
55
60
|
# @param name [Symbol]
|
data/lib/gamefic/active/take.rb
CHANGED
@@ -16,7 +16,7 @@ module Gamefic
|
|
16
16
|
|
17
17
|
# @param actor [Active]
|
18
18
|
# @param cue [Active::Cue]
|
19
|
-
# @param props [Props::Default]
|
19
|
+
# @param props [Props::Default, nil]
|
20
20
|
def initialize actor, cue, props = nil
|
21
21
|
@actor = actor
|
22
22
|
@cue = cue
|
@@ -31,12 +31,11 @@ module Gamefic
|
|
31
31
|
|
32
32
|
# @return [Props::Default]
|
33
33
|
def start
|
34
|
-
actor.output[:scene] = scene.to_hash
|
35
34
|
scene.run_start_blocks actor, props
|
36
35
|
scene.start actor, props
|
37
36
|
# @todo See if this can be handled better
|
38
|
-
actor.epic.rulebooks.each { |rlbk| rlbk.run_player_output_blocks actor,
|
39
|
-
|
37
|
+
actor.epic.rulebooks.each { |rlbk| rlbk.run_player_output_blocks actor, props.output }
|
38
|
+
props.output.merge!({
|
40
39
|
messages: actor.messages,
|
41
40
|
queue: actor.queue
|
42
41
|
})
|
@@ -47,7 +46,6 @@ module Gamefic
|
|
47
46
|
def finish
|
48
47
|
actor.flush
|
49
48
|
scene.finish(actor, props)
|
50
|
-
actor.output.replace(last_prompt: props.prompt, last_input: props.input)
|
51
49
|
scene.run_finish_blocks actor, props
|
52
50
|
end
|
53
51
|
|
data/lib/gamefic/active.rb
CHANGED
@@ -21,6 +21,9 @@ module Gamefic
|
|
21
21
|
# @return [Active::Cue, nil]
|
22
22
|
attr_reader :next_cue
|
23
23
|
|
24
|
+
# @return [String, nil]
|
25
|
+
attr_reader :last_input
|
26
|
+
|
24
27
|
# @return [Symbol, nil]
|
25
28
|
def next_scene
|
26
29
|
next_cue&.scene
|
@@ -48,12 +51,22 @@ module Gamefic
|
|
48
51
|
@queue ||= []
|
49
52
|
end
|
50
53
|
|
51
|
-
#
|
52
|
-
#
|
54
|
+
# Data that will be sent to the user. The output is typically sent after a
|
55
|
+
# scene has started and before the user is prompted for input.
|
56
|
+
#
|
57
|
+
# The output object attached to the actor is always frozen. Authors should
|
58
|
+
# use on_player_output blocks to modify output to be sent to the user.
|
53
59
|
#
|
54
|
-
# @return [
|
60
|
+
# @return [Props::Output]
|
55
61
|
def output
|
56
|
-
@output ||=
|
62
|
+
@output ||= Props::Output.new.freeze
|
63
|
+
end
|
64
|
+
|
65
|
+
# The output from the previous turn.
|
66
|
+
#
|
67
|
+
# @return [Props::Output]
|
68
|
+
def last_output
|
69
|
+
@last_output ||= output
|
57
70
|
end
|
58
71
|
|
59
72
|
# Perform a command.
|
@@ -65,11 +78,10 @@ module Gamefic
|
|
65
78
|
# character.perform "take the key"
|
66
79
|
#
|
67
80
|
# @param command [String]
|
68
|
-
# @return [
|
81
|
+
# @return [Action, nil]
|
69
82
|
def perform(command)
|
70
83
|
dispatchers.push Dispatcher.dispatch(self, command)
|
71
|
-
dispatchers.last.execute
|
72
|
-
dispatchers.pop
|
84
|
+
dispatchers.last.execute.tap { dispatchers.pop }
|
73
85
|
end
|
74
86
|
|
75
87
|
# Quietly perform a command.
|
@@ -95,11 +107,10 @@ module Gamefic
|
|
95
107
|
#
|
96
108
|
# @param verb [Symbol]
|
97
109
|
# @param params [Array]
|
98
|
-
# @return [
|
110
|
+
# @return [Action, nil]
|
99
111
|
def execute(verb, *params)
|
100
112
|
dispatchers.push Dispatcher.dispatch_from_params(self, verb, params)
|
101
|
-
dispatchers.last.execute
|
102
|
-
dispatchers.pop
|
113
|
+
dispatchers.last.execute.tap { dispatchers.pop }
|
103
114
|
end
|
104
115
|
|
105
116
|
# Proceed to the next Action in the current stack.
|
@@ -125,9 +136,9 @@ module Gamefic
|
|
125
136
|
# end
|
126
137
|
# end
|
127
138
|
#
|
128
|
-
# @return [
|
139
|
+
# @return [Action, nil]
|
129
140
|
def proceed
|
130
|
-
dispatchers.last&.proceed
|
141
|
+
dispatchers.last&.proceed
|
131
142
|
end
|
132
143
|
|
133
144
|
# Cue a scene to start in the next turn.
|
@@ -146,17 +157,24 @@ module Gamefic
|
|
146
157
|
end
|
147
158
|
alias prepare cue
|
148
159
|
|
160
|
+
# @return [void]
|
149
161
|
def start_take
|
150
162
|
ensure_cue
|
151
163
|
@last_cue = @next_cue
|
152
164
|
cue :default_scene
|
153
165
|
@props = Take.start(self, @last_cue)
|
166
|
+
@last_output = self.output
|
167
|
+
@props.output[:last_prompt] = @last_output.prompt
|
168
|
+
@props.output[:last_input] = @last_input
|
169
|
+
@output = @props.output.dup.freeze
|
154
170
|
end
|
155
171
|
|
172
|
+
# @return [void]
|
156
173
|
def finish_take
|
157
174
|
return unless @last_cue
|
158
175
|
|
159
176
|
Take.finish(self, @last_cue, @props)
|
177
|
+
@last_input = @props.input
|
160
178
|
end
|
161
179
|
|
162
180
|
# Restart the scene from the most recent cue.
|
@@ -175,6 +193,7 @@ module Gamefic
|
|
175
193
|
#
|
176
194
|
# @param new_scene [Symbol]
|
177
195
|
# @oaram context [Hash] Additional scene data
|
196
|
+
# @return [Cue]
|
178
197
|
def conclude scene, **context
|
179
198
|
cue scene, **context
|
180
199
|
available = epic.select_scene(scene)
|
@@ -186,7 +205,7 @@ module Gamefic
|
|
186
205
|
# True if the actor is ready to leave the game.
|
187
206
|
#
|
188
207
|
def concluding?
|
189
|
-
epic.empty? || (
|
208
|
+
epic.empty? || @props&.scene&.fetch(:type) == 'Conclusion'
|
190
209
|
end
|
191
210
|
|
192
211
|
def accessible?
|
data/lib/gamefic/command.rb
CHANGED
@@ -1,31 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Gamefic
|
4
|
-
# A
|
5
|
-
#
|
6
|
-
# Commands are typically derived from tokenization against syntaxes.
|
4
|
+
# A concrete representation of an input as a verb and an array of arguments.
|
7
5
|
#
|
8
6
|
class Command
|
9
7
|
# @return [Symbol]
|
10
8
|
attr_reader :verb
|
11
9
|
|
12
|
-
# @return [Array<String>]
|
10
|
+
# @return [Array<Array<Entity>, Entity, String>]
|
13
11
|
attr_reader :arguments
|
14
12
|
|
13
|
+
# @param verb [Symbol]
|
14
|
+
# @param arguments [Array<Array<Entity>, Entity, String>]
|
15
15
|
def initialize verb, arguments
|
16
16
|
@verb = verb
|
17
17
|
@arguments = arguments
|
18
18
|
end
|
19
|
-
|
20
|
-
# Compare two syntaxes for the purpose of ordering them by relevance while
|
21
|
-
# dispatching.
|
22
|
-
#
|
23
|
-
def compare other
|
24
|
-
if verb == other.verb
|
25
|
-
other.arguments.compact.length <=> arguments.compact.length
|
26
|
-
else
|
27
|
-
(other.verb ? 1 : 0) <=> (verb ? 1 : 0)
|
28
|
-
end
|
29
|
-
end
|
30
19
|
end
|
31
20
|
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gamefic
|
4
|
+
# A function module for creating commands from expressions.
|
5
|
+
#
|
6
|
+
module Composer
|
7
|
+
# Create a command from the first expression that matches a response.
|
8
|
+
#
|
9
|
+
# @param actor [Actor]
|
10
|
+
# @param expressions [Array<Expression>]
|
11
|
+
# @return [Command]
|
12
|
+
def self.compose actor, expressions
|
13
|
+
%i[strict fuzzy].each do |method|
|
14
|
+
result = match_expressions_to_response actor, expressions, method
|
15
|
+
return result if result
|
16
|
+
end
|
17
|
+
Command.new(nil, [])
|
18
|
+
end
|
19
|
+
|
20
|
+
class << self
|
21
|
+
private
|
22
|
+
|
23
|
+
def match_expressions_to_response actor, expressions, method
|
24
|
+
expressions.each do |expression|
|
25
|
+
result = match_response_arguments actor, expression, method
|
26
|
+
return result if result
|
27
|
+
end
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def match_response_arguments actor, expression, method
|
32
|
+
actor.epic.responses_for(expression.verb).each do |response|
|
33
|
+
next unless response.queries.length >= expression.tokens.length
|
34
|
+
|
35
|
+
result = match_query_arguments(actor, expression, response, method)
|
36
|
+
return result if result
|
37
|
+
end
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def match_query_arguments actor, expression, response, method
|
42
|
+
remainder = response.verb ? '' : expression.verb.to_s
|
43
|
+
arguments = []
|
44
|
+
response.queries.each_with_index do |query, idx|
|
45
|
+
result = Scanner.send(method, query.select(actor), "#{remainder} #{expression.tokens[idx]}".strip)
|
46
|
+
break unless validate_result_from_query(result, query)
|
47
|
+
|
48
|
+
if query.ambiguous?
|
49
|
+
arguments.push result.matched
|
50
|
+
else
|
51
|
+
arguments.push result.matched.first
|
52
|
+
end
|
53
|
+
remainder = result.remainder
|
54
|
+
end
|
55
|
+
|
56
|
+
return nil if arguments.length != response.queries.length || remainder != ''
|
57
|
+
|
58
|
+
Command.new(response.verb, arguments)
|
59
|
+
end
|
60
|
+
|
61
|
+
# @param result [Scanner::Result]
|
62
|
+
# @param query [Query::Base]
|
63
|
+
def validate_result_from_query result, query
|
64
|
+
return false if result.matched.empty?
|
65
|
+
|
66
|
+
result.matched.length == 1 || query.ambiguous?
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/gamefic/dispatcher.rb
CHANGED
@@ -1,63 +1,54 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Gamefic
|
4
|
-
# The action
|
4
|
+
# The action executor for character commands.
|
5
5
|
#
|
6
6
|
class Dispatcher
|
7
7
|
# @param actor [Actor]
|
8
|
-
# @param
|
9
|
-
|
10
|
-
def initialize actor, commands = [], responses = []
|
8
|
+
# @param command [Command]
|
9
|
+
def initialize actor, command
|
11
10
|
@actor = actor
|
12
|
-
@
|
13
|
-
@responses = responses
|
11
|
+
@command = command
|
14
12
|
@executed = false
|
13
|
+
@finalized = false
|
15
14
|
end
|
16
15
|
|
17
16
|
# Run the dispatcher.
|
18
17
|
#
|
18
|
+
# @return [Action, nil]
|
19
19
|
def execute
|
20
20
|
return if @executed
|
21
21
|
|
22
|
-
|
22
|
+
@executed = true
|
23
|
+
action = next_action
|
23
24
|
return unless action
|
24
25
|
|
25
|
-
@executed = action.arguments
|
26
26
|
run_before_action_hooks action
|
27
27
|
return if action.cancelled?
|
28
28
|
|
29
29
|
action.execute
|
30
30
|
run_after_action_hooks action
|
31
|
+
action
|
31
32
|
end
|
32
33
|
|
33
|
-
#
|
34
|
+
# Execute the next available action.
|
35
|
+
#
|
36
|
+
# Actors should run #execute first.
|
34
37
|
#
|
35
38
|
# @return [Action, nil]
|
36
39
|
def proceed
|
37
|
-
|
38
|
-
commands.each do |cmd|
|
39
|
-
action = response.attempt(actor, cmd)
|
40
|
-
next unless action && arguments_match?(action.arguments)
|
40
|
+
return unless @executed
|
41
41
|
|
42
|
-
|
43
|
-
end
|
44
|
-
end
|
45
|
-
nil # Without this, return value in Opal is undefined
|
42
|
+
next_action&.execute
|
46
43
|
end
|
47
44
|
|
48
45
|
# @param actor [Active]
|
49
46
|
# @param input [String]
|
50
47
|
# @return [Dispatcher]
|
51
48
|
def self.dispatch actor, input
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
.rulebooks
|
56
|
-
.to_a
|
57
|
-
.reverse
|
58
|
-
.flat_map { |pb| pb.responses_for(*verbs) }
|
59
|
-
.reject(&:hidden?)
|
60
|
-
new(actor, commands, responses)
|
49
|
+
expressions = Syntax.tokenize(input, actor.epic.syntaxes)
|
50
|
+
command = Composer.compose(actor, expressions)
|
51
|
+
new(actor, command)
|
61
52
|
end
|
62
53
|
|
63
54
|
# @param actor [Active]
|
@@ -66,12 +57,7 @@ module Gamefic
|
|
66
57
|
# @return [Dispatcher]
|
67
58
|
def self.dispatch_from_params actor, verb, params
|
68
59
|
command = Command.new(verb, params)
|
69
|
-
|
70
|
-
.rulebooks
|
71
|
-
.to_a
|
72
|
-
.reverse
|
73
|
-
.flat_map { |pb| pb.responses_for(verb) }
|
74
|
-
new(actor, [command], responses)
|
60
|
+
new(actor, command)
|
75
61
|
end
|
76
62
|
|
77
63
|
protected
|
@@ -79,27 +65,48 @@ module Gamefic
|
|
79
65
|
# @return [Actor]
|
80
66
|
attr_reader :actor
|
81
67
|
|
82
|
-
# @return [
|
83
|
-
attr_reader :
|
68
|
+
# @return [Command]
|
69
|
+
attr_reader :command
|
84
70
|
|
85
71
|
# @return [Array<Response>]
|
86
|
-
|
72
|
+
def responses
|
73
|
+
@responses ||= actor.epic.responses_for(command.verb)
|
74
|
+
end
|
87
75
|
|
88
76
|
private
|
89
77
|
|
90
|
-
#
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
78
|
+
# @return [Action, nil]
|
79
|
+
def next_action
|
80
|
+
while (response = responses.shift)
|
81
|
+
next if response.queries.length < @command.arguments.length
|
82
|
+
|
83
|
+
return Action.new(actor, @command.arguments, response) if response.accept?(actor, @command)
|
84
|
+
end
|
85
|
+
finalize
|
95
86
|
end
|
96
87
|
|
88
|
+
# @return [void]
|
97
89
|
def run_before_action_hooks action
|
98
90
|
actor.epic.rulebooks.flat_map { |rlbk| rlbk.run_before_actions action }
|
99
91
|
end
|
100
92
|
|
93
|
+
# @return [void]
|
101
94
|
def run_after_action_hooks action
|
102
95
|
actor.epic.rulebooks.flat_map { |rlbk| rlbk.run_after_actions action }
|
103
96
|
end
|
97
|
+
|
98
|
+
# If the dispatcher proceeds through all possible responses, it can fall
|
99
|
+
# back to a nil response as a catchall for commands that could not be
|
100
|
+
# completed.
|
101
|
+
#
|
102
|
+
# @return [Action, nil]
|
103
|
+
def finalize
|
104
|
+
return nil if @finalized
|
105
|
+
|
106
|
+
@finalized = true
|
107
|
+
@command = Command.new(nil, ["#{command.verb} #{command.arguments.join(' ').strip}"])
|
108
|
+
@responses = actor.epic.responses_for(nil)
|
109
|
+
next_action
|
110
|
+
end
|
104
111
|
end
|
105
112
|
end
|
data/lib/gamefic/entity.rb
CHANGED
@@ -9,7 +9,6 @@ module Gamefic
|
|
9
9
|
class Entity
|
10
10
|
include Describable
|
11
11
|
include Node
|
12
|
-
# include Messaging
|
13
12
|
|
14
13
|
def initialize **args
|
15
14
|
klass = self.class
|
@@ -57,14 +56,13 @@ module Gamefic
|
|
57
56
|
end
|
58
57
|
|
59
58
|
class << self
|
60
|
-
# Set or update the default
|
59
|
+
# Set or update the default attributes for new instances.
|
61
60
|
#
|
62
|
-
|
63
|
-
def set_default attrs = {}
|
61
|
+
def set_default **attrs
|
64
62
|
default_attributes.merge! attrs
|
65
63
|
end
|
66
64
|
|
67
|
-
# A hash of default
|
65
|
+
# A hash of default attributes when creating an instance.
|
68
66
|
#
|
69
67
|
# @return [Hash]
|
70
68
|
def default_attributes
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gamefic
|
4
|
+
# A tokenization of an input from available syntaxes.
|
5
|
+
#
|
6
|
+
class Expression
|
7
|
+
# @return [Symbol]
|
8
|
+
attr_reader :verb
|
9
|
+
|
10
|
+
# @return [Array<String>]
|
11
|
+
attr_reader :tokens
|
12
|
+
|
13
|
+
# @param verb [Symbol, nil]
|
14
|
+
# @param tokens [Array<String>]
|
15
|
+
def initialize verb, tokens
|
16
|
+
@verb = verb
|
17
|
+
@tokens = tokens
|
18
|
+
end
|
19
|
+
|
20
|
+
# Compare two syntaxes for the purpose of ordering them by relevance while
|
21
|
+
# dispatching.
|
22
|
+
#
|
23
|
+
def compare other
|
24
|
+
if verb == other.verb
|
25
|
+
other.tokens.compact.length <=> tokens.compact.length
|
26
|
+
else
|
27
|
+
(other.verb ? 1 : 0) <=> (verb ? 1 : 0)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/gamefic/plot.rb
CHANGED
@@ -9,8 +9,8 @@ module Gamefic
|
|
9
9
|
super
|
10
10
|
subplots.each(&:ready)
|
11
11
|
players.each(&:start_take)
|
12
|
-
subplots.delete_if(&:concluding?)
|
13
12
|
players.select(&:concluding?).each { |plyr| rulebook.run_player_conclude_blocks plyr }
|
13
|
+
subplots.delete_if(&:concluding?)
|
14
14
|
end
|
15
15
|
|
16
16
|
def update
|
@@ -25,17 +25,23 @@ module Gamefic
|
|
25
25
|
attr_reader :context
|
26
26
|
alias data context
|
27
27
|
|
28
|
-
# @
|
28
|
+
# @return [Hash]
|
29
|
+
attr_reader :scene
|
30
|
+
|
31
|
+
# @param scene [Scene]
|
29
32
|
# @param context [Hash]
|
30
|
-
def initialize
|
31
|
-
@
|
32
|
-
@scene_type = type
|
33
|
+
def initialize scene, **context
|
34
|
+
@scene = { name: scene.name, type: scene.type }
|
33
35
|
@context = context
|
34
36
|
end
|
35
37
|
|
36
38
|
def prompt
|
37
39
|
@prompt ||= '>'
|
38
40
|
end
|
41
|
+
|
42
|
+
def output
|
43
|
+
@output ||= Props::Output.new
|
44
|
+
end
|
39
45
|
end
|
40
46
|
end
|
41
47
|
end
|