gamefic 3.0.0 → 3.2.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/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
|