gamefic 1.6.0 → 1.7.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 +4 -1
- data/lib/gamefic/action.rb +4 -0
- data/lib/gamefic/{character.rb → active.rb} +280 -232
- data/lib/gamefic/actor.rb +5 -0
- data/lib/gamefic/core_ext/string.rb +12 -12
- data/lib/gamefic/describable.rb +18 -1
- data/lib/gamefic/element.rb +31 -0
- data/lib/gamefic/engine/base.rb +17 -24
- data/lib/gamefic/entity.rb +18 -36
- data/lib/gamefic/grammar/gender.rb +1 -1
- data/lib/gamefic/grammar/pronouns.rb +3 -2
- data/lib/gamefic/messaging.rb +0 -1
- data/lib/gamefic/plot.rb +14 -4
- data/lib/gamefic/plot/callbacks.rb +1 -2
- data/lib/gamefic/plot/commands.rb +3 -4
- data/lib/gamefic/plot/darkroom.rb +264 -0
- data/lib/gamefic/plot/entities.rb +13 -1
- data/lib/gamefic/plot/host.rb +10 -8
- data/lib/gamefic/plot/playbook.rb +17 -13
- data/lib/gamefic/plot/scenes.rb +50 -12
- data/lib/gamefic/plot/snapshot.rb +15 -210
- data/lib/gamefic/query.rb +1 -0
- data/lib/gamefic/query/base.rb +15 -19
- data/lib/gamefic/query/external.rb +14 -0
- data/lib/gamefic/scene.rb +2 -4
- data/lib/gamefic/scene/{active.rb → activity.rb} +26 -26
- data/lib/gamefic/scene/base.rb +12 -7
- data/lib/gamefic/scene/multiple_choice.rb +0 -13
- data/lib/gamefic/scene/multiple_scene.rb +1 -1
- data/lib/gamefic/subplot.rb +16 -23
- data/lib/gamefic/user.rb +0 -1
- data/lib/gamefic/user/base.rb +15 -1
- data/lib/gamefic/user/tty.rb +15 -31
- data/lib/gamefic/version.rb +1 -1
- metadata +8 -26
- data/lib/gamefic/character/state.rb +0 -12
- data/lib/gamefic/user/buffer.rb +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3811a2f448c91712eaa8eec46000577c7d38f7a
|
4
|
+
data.tar.gz: 6cb83cb93b14fd5c94401367e51828bad90a8960
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 12f2199a4d803e7a179b49e1d50f6e83571f21d601e67828546de918c65b3da0ee97790e66ee5f73f34b1a901d515284e3c8bd030ff0dc5d816678b7c9a0ba48
|
7
|
+
data.tar.gz: 31118c91be341821662fe8624b85924b196c52f9b2bcd0c758f5af13fc9d1dceaa76f204d6f6f3d2e274ef049153b416dcd2648a207e4ad07ea02ea4b9b440c4
|
data/lib/gamefic.rb
CHANGED
@@ -3,8 +3,11 @@ require 'gamefic/core_ext/array'
|
|
3
3
|
require 'gamefic/core_ext/string'
|
4
4
|
|
5
5
|
require 'gamefic/grammar'
|
6
|
+
require 'gamefic/describable'
|
7
|
+
require 'gamefic/element'
|
6
8
|
require 'gamefic/entity'
|
7
|
-
require 'gamefic/
|
9
|
+
require 'gamefic/active'
|
10
|
+
require 'gamefic/actor'
|
8
11
|
require "gamefic/scene"
|
9
12
|
require "gamefic/query"
|
10
13
|
require "gamefic/action"
|
data/lib/gamefic/action.rb
CHANGED
@@ -1,232 +1,280 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
# @return [Gamefic::
|
13
|
-
attr_reader :
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
attr_reader :next_scene
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
@
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
#
|
33
|
-
#
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
#
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
#
|
118
|
-
#
|
119
|
-
#
|
120
|
-
#
|
121
|
-
#
|
122
|
-
#
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
#
|
130
|
-
#
|
131
|
-
#
|
132
|
-
#
|
133
|
-
#
|
134
|
-
#
|
135
|
-
#
|
136
|
-
# end
|
137
|
-
#
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
#
|
172
|
-
#
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
def
|
202
|
-
|
203
|
-
|
204
|
-
end
|
205
|
-
|
206
|
-
#
|
207
|
-
#
|
208
|
-
# @return [
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
def
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
1
|
+
module Gamefic
|
2
|
+
class NotConclusionError < Exception
|
3
|
+
end
|
4
|
+
|
5
|
+
# The Active module gives entities the ability to perform actions and
|
6
|
+
# participate in scenes.
|
7
|
+
#
|
8
|
+
module Active
|
9
|
+
# @return [Gamefic::Action]
|
10
|
+
attr_reader :last_action
|
11
|
+
|
12
|
+
# @return [Gamefic::User::Base]
|
13
|
+
attr_reader :user
|
14
|
+
|
15
|
+
# @return [Gamefic::Scene::Base]
|
16
|
+
attr_reader :scene
|
17
|
+
|
18
|
+
attr_reader :next_scene
|
19
|
+
|
20
|
+
# @return [Gamefic::Plot::Playbook]
|
21
|
+
#attr_accessor :playbook
|
22
|
+
|
23
|
+
# @return [Array<Gamefic::Plot::Playbook>]
|
24
|
+
def playbooks
|
25
|
+
@playbooks ||= []
|
26
|
+
end
|
27
|
+
|
28
|
+
def connect user
|
29
|
+
@user = user
|
30
|
+
end
|
31
|
+
|
32
|
+
# An array of actions waiting to be performed.
|
33
|
+
#
|
34
|
+
# @return [Array<String>]
|
35
|
+
def queue
|
36
|
+
@queue ||= []
|
37
|
+
end
|
38
|
+
|
39
|
+
# A hash of values representing the state of a performing entity.
|
40
|
+
#
|
41
|
+
# @return [Hash]
|
42
|
+
def state
|
43
|
+
@state = {}
|
44
|
+
@state.merge! scene.state unless scene.nil?
|
45
|
+
@state[:output] = messages
|
46
|
+
@state
|
47
|
+
end
|
48
|
+
|
49
|
+
# Send a message to the entity.
|
50
|
+
# This method will automatically wrap the message in HTML paragraphs.
|
51
|
+
# To send a message without paragraph formatting, use #stream instead.
|
52
|
+
#
|
53
|
+
# @param message [String]
|
54
|
+
def tell(message)
|
55
|
+
if buffer_stack > 0
|
56
|
+
append_buffer message
|
57
|
+
else
|
58
|
+
super
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Send a message to the Character as raw text.
|
63
|
+
# Unlike #tell, this method will not wrap the message in HTML paragraphs.
|
64
|
+
#
|
65
|
+
# @param message [String]
|
66
|
+
def stream(message)
|
67
|
+
if buffer_stack > 0
|
68
|
+
append_buffer message
|
69
|
+
else
|
70
|
+
super
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Perform a command.
|
75
|
+
# The command can be specified as a String or a verb with a list of
|
76
|
+
# parameters. Either form should yield the same result, but the
|
77
|
+
# verb/parameter form can yield better performance since it bypasses the
|
78
|
+
# parser.
|
79
|
+
#
|
80
|
+
# The command will be executed immediately regardless of the entity's
|
81
|
+
# state.
|
82
|
+
#
|
83
|
+
# @example Send a command as a string
|
84
|
+
# character.perform "take the key"
|
85
|
+
#
|
86
|
+
# @example Send a command as a verb with parameters
|
87
|
+
# character.perform :take, @key
|
88
|
+
#
|
89
|
+
# @return [Gamefic::Action]
|
90
|
+
def perform(*command)
|
91
|
+
actions = []
|
92
|
+
playbooks.reverse.each { |p| actions.concat p.dispatch(self, *command) }
|
93
|
+
execute_stack actions
|
94
|
+
end
|
95
|
+
|
96
|
+
# Quietly perform a command.
|
97
|
+
# This method executes the command exactly as #perform does, except it
|
98
|
+
# buffers the resulting output instead of sending it to the user.
|
99
|
+
#
|
100
|
+
# @return [String] The output that resulted from performing the command.
|
101
|
+
def quietly(*command)
|
102
|
+
if buffer_stack == 0
|
103
|
+
clear_buffer
|
104
|
+
end
|
105
|
+
set_buffer_stack buffer_stack + 1
|
106
|
+
self.perform *command
|
107
|
+
set_buffer_stack buffer_stack - 1
|
108
|
+
buffer
|
109
|
+
end
|
110
|
+
|
111
|
+
# Perform an action.
|
112
|
+
# This is functionally identical to the `perform` method, except the
|
113
|
+
# action must be declared as a verb with a list of parameters. Use
|
114
|
+
# `perform` if you need to parse a string as a command.
|
115
|
+
#
|
116
|
+
# The command will be executed immediately regardless of the entity's
|
117
|
+
# state.
|
118
|
+
#
|
119
|
+
# @example
|
120
|
+
# character.execute :take, @key
|
121
|
+
#
|
122
|
+
# @return [Gamefic::Action]
|
123
|
+
def execute(verb, *params, quietly: false)
|
124
|
+
actions = []
|
125
|
+
playbooks.reverse.each { |p| actions.concat p.dispatch_from_params(self, verb, params) }
|
126
|
+
execute_stack actions, quietly: quietly
|
127
|
+
end
|
128
|
+
|
129
|
+
# Proceed to the next Action in the current stack.
|
130
|
+
# This method is typically used in Action blocks to cascade through
|
131
|
+
# multiple implementations of the same verb.
|
132
|
+
#
|
133
|
+
# @example Proceed through two implementations of a verb
|
134
|
+
# introduction do |actor|
|
135
|
+
# actor[:has_eaten] = false # Initial value
|
136
|
+
# end
|
137
|
+
# respond :eat do |actor|
|
138
|
+
# actor.tell "You eat something."
|
139
|
+
# actor[:has_eaten] = true
|
140
|
+
# end
|
141
|
+
# respond :eat do |actor|
|
142
|
+
# # This version will be executed first because it was implemented last
|
143
|
+
# if actor[:has_eaten]
|
144
|
+
# actor.tell "You already ate."
|
145
|
+
# else
|
146
|
+
# actor.proceed # Execute the previous implementation
|
147
|
+
# end
|
148
|
+
# end
|
149
|
+
#
|
150
|
+
def proceed quietly: false
|
151
|
+
#Director::Delegate.proceed_for self
|
152
|
+
return if performance_stack.empty?
|
153
|
+
a = performance_stack.last.shift
|
154
|
+
unless a.nil?
|
155
|
+
if quietly
|
156
|
+
if @buffer_stack == 0
|
157
|
+
@buffer = ""
|
158
|
+
end
|
159
|
+
@buffer_stack += 1
|
160
|
+
end
|
161
|
+
a.execute
|
162
|
+
if quietly
|
163
|
+
@buffer_stack -= 1
|
164
|
+
@buffer
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Immediately start a new scene for the character.
|
170
|
+
# Use #prepare if you want to declare a scene to be started at the
|
171
|
+
# beginning of the next turn.
|
172
|
+
#
|
173
|
+
def cue new_scene
|
174
|
+
@next_scene = nil
|
175
|
+
if new_scene.nil?
|
176
|
+
@scene = nil
|
177
|
+
else
|
178
|
+
@scene = new_scene.new(self)
|
179
|
+
@scene.start
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# Prepare a scene to be started for this character at the beginning of the
|
184
|
+
# next turn.
|
185
|
+
#
|
186
|
+
def prepare s
|
187
|
+
@next_scene = s
|
188
|
+
end
|
189
|
+
|
190
|
+
# Return true if the character is expected to be in the specified scene on
|
191
|
+
# the next turn.
|
192
|
+
#
|
193
|
+
# @return [Boolean]
|
194
|
+
def will_cue? scene
|
195
|
+
(@scene.class == scene and @next_scene.nil?) or @next_scene == scene
|
196
|
+
end
|
197
|
+
|
198
|
+
# Cue a conclusion. This method works like #cue, except it will raise a
|
199
|
+
# NotConclusionError if the scene is not a Scene::Conclusion.
|
200
|
+
#
|
201
|
+
def conclude scene
|
202
|
+
raise NotConclusionError unless scene <= Scene::Conclusion
|
203
|
+
cue scene
|
204
|
+
end
|
205
|
+
|
206
|
+
# True if the character is in a conclusion.
|
207
|
+
#
|
208
|
+
# @return [Boolean]
|
209
|
+
def concluded?
|
210
|
+
!scene.nil? and scene.kind_of?(Scene::Conclusion)
|
211
|
+
end
|
212
|
+
|
213
|
+
def performed order
|
214
|
+
order.freeze
|
215
|
+
@last_action = order
|
216
|
+
end
|
217
|
+
|
218
|
+
def accessible?
|
219
|
+
false
|
220
|
+
end
|
221
|
+
|
222
|
+
def inspect
|
223
|
+
to_s
|
224
|
+
end
|
225
|
+
|
226
|
+
private
|
227
|
+
|
228
|
+
def execute_stack actions, quietly: false
|
229
|
+
return nil if actions.empty?
|
230
|
+
a = actions.first
|
231
|
+
okay = true
|
232
|
+
unless a.meta?
|
233
|
+
playbooks.reverse.each do |playbook|
|
234
|
+
okay = validate_playbook playbook, a
|
235
|
+
break unless okay
|
236
|
+
end
|
237
|
+
end
|
238
|
+
if okay
|
239
|
+
performance_stack.push actions
|
240
|
+
proceed quietly: quietly
|
241
|
+
performance_stack.pop
|
242
|
+
end
|
243
|
+
a
|
244
|
+
end
|
245
|
+
|
246
|
+
def validate_playbook playbook, action
|
247
|
+
okay = true
|
248
|
+
playbook.validators.each { |v|
|
249
|
+
result = v.call(self, action.verb, action.parameters)
|
250
|
+
okay = (result != false)
|
251
|
+
break unless okay
|
252
|
+
}
|
253
|
+
okay
|
254
|
+
end
|
255
|
+
|
256
|
+
def buffer_stack
|
257
|
+
@buffer_stack ||= 0
|
258
|
+
end
|
259
|
+
|
260
|
+
def set_buffer_stack num
|
261
|
+
@buffer_stack = num
|
262
|
+
end
|
263
|
+
|
264
|
+
def buffer
|
265
|
+
@buffer ||= ''
|
266
|
+
end
|
267
|
+
|
268
|
+
def append_buffer str
|
269
|
+
@buffer += str
|
270
|
+
end
|
271
|
+
|
272
|
+
def clear_buffer
|
273
|
+
@buffer = '' unless @buffer.empty?
|
274
|
+
end
|
275
|
+
|
276
|
+
def performance_stack
|
277
|
+
@performance_stack ||= []
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|