gamefic 1.7.0 → 2.0.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 +5 -5
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.rubocop.yml +13 -0
- data/.solargraph.yml +5 -0
- data/Gemfile +7 -0
- data/LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +10 -0
- data/gamefic.gemspec +27 -0
- data/lib/gamefic.rb +7 -6
- data/lib/gamefic/action.rb +38 -28
- data/lib/gamefic/active.rb +325 -280
- data/lib/gamefic/actor.rb +8 -5
- data/lib/gamefic/command.rb +9 -7
- data/lib/gamefic/core_ext/array.rb +24 -49
- data/lib/gamefic/core_ext/string.rb +25 -16
- data/lib/gamefic/describable.rb +21 -23
- data/lib/gamefic/element.rb +43 -31
- data/lib/gamefic/entity.rb +6 -12
- data/lib/gamefic/index.rb +121 -0
- data/lib/gamefic/{matchable.rb → keywords.rb} +52 -50
- data/lib/gamefic/messaging.rb +43 -44
- data/lib/gamefic/node.rb +14 -5
- data/lib/gamefic/plot.rb +69 -89
- data/lib/gamefic/plot/darkroom.rb +92 -264
- data/lib/gamefic/plot/host.rb +42 -48
- data/lib/gamefic/plot/snapshot.rb +5 -18
- data/lib/gamefic/query.rb +14 -18
- data/lib/gamefic/query/base.rb +30 -18
- data/lib/gamefic/query/children.rb +0 -0
- data/lib/gamefic/query/external.rb +18 -14
- data/lib/gamefic/query/family.rb +1 -7
- data/lib/gamefic/query/matches.rb +75 -67
- data/lib/gamefic/query/parent.rb +0 -0
- data/lib/gamefic/query/siblings.rb +0 -0
- data/lib/gamefic/query/text.rb +2 -1
- data/lib/gamefic/scene.rb +0 -2
- data/lib/gamefic/scene/activity.rb +24 -26
- data/lib/gamefic/scene/base.rb +64 -8
- data/lib/gamefic/scene/conclusion.rb +0 -2
- data/lib/gamefic/scene/custom.rb +0 -2
- data/lib/gamefic/scene/multiple_choice.rb +18 -3
- data/lib/gamefic/scene/multiple_scene.rb +29 -20
- data/lib/gamefic/scene/pause.rb +7 -2
- data/lib/gamefic/scene/yes_or_no.rb +21 -9
- data/lib/gamefic/scriptable.rb +87 -0
- data/lib/gamefic/serialize.rb +68 -0
- data/lib/gamefic/subplot.rb +29 -35
- data/lib/gamefic/syntax.rb +14 -13
- data/lib/gamefic/version.rb +3 -3
- data/lib/gamefic/world.rb +16 -0
- data/lib/gamefic/world/callbacks.rb +135 -0
- data/lib/gamefic/world/commands.rb +184 -0
- data/lib/gamefic/{plot → world}/entities.rb +30 -29
- data/lib/gamefic/{plot → world}/playbook.rb +255 -240
- data/lib/gamefic/world/players.rb +21 -0
- data/lib/gamefic/world/scenes.rb +226 -0
- metadata +41 -92
- data/bin/gamefic +0 -9
- data/lib/gamefic/engine.rb +0 -7
- data/lib/gamefic/engine/base.rb +0 -59
- data/lib/gamefic/engine/tty.rb +0 -24
- data/lib/gamefic/grammar.rb +0 -13
- data/lib/gamefic/grammar/conjugator.rb +0 -20
- data/lib/gamefic/grammar/gender.rb +0 -11
- data/lib/gamefic/grammar/person.rb +0 -10
- data/lib/gamefic/grammar/plural.rb +0 -13
- data/lib/gamefic/grammar/pronouns.rb +0 -106
- data/lib/gamefic/grammar/tense.rb +0 -6
- data/lib/gamefic/grammar/verb_set.rb +0 -43
- data/lib/gamefic/grammar/verbs.rb +0 -26
- data/lib/gamefic/grammar/word_adapter.rb +0 -49
- data/lib/gamefic/plot/articles.rb +0 -22
- data/lib/gamefic/plot/callbacks.rb +0 -126
- data/lib/gamefic/plot/commands.rb +0 -120
- data/lib/gamefic/plot/players.rb +0 -15
- data/lib/gamefic/plot/scenes.rb +0 -187
- data/lib/gamefic/plot/theater.rb +0 -73
- data/lib/gamefic/plot/you_mount.rb +0 -22
- data/lib/gamefic/script.rb +0 -13
- data/lib/gamefic/script/base.rb +0 -42
- data/lib/gamefic/script/file.rb +0 -14
- data/lib/gamefic/script/text.rb +0 -14
- data/lib/gamefic/shell.rb +0 -76
- data/lib/gamefic/source.rb +0 -14
- data/lib/gamefic/source/base.rb +0 -12
- data/lib/gamefic/source/file.rb +0 -23
- data/lib/gamefic/source/text.rb +0 -16
- data/lib/gamefic/tester.rb +0 -19
- data/lib/gamefic/text.rb +0 -8
- data/lib/gamefic/text/ansi.rb +0 -53
- data/lib/gamefic/text/html.rb +0 -68
- data/lib/gamefic/text/html/conversions.rb +0 -250
- data/lib/gamefic/text/html/entities.rb +0 -9
- data/lib/gamefic/tty.rb +0 -10
- data/lib/gamefic/user.rb +0 -7
- data/lib/gamefic/user/base.rb +0 -29
- data/lib/gamefic/user/tty.rb +0 -38
@@ -1,264 +1,92 @@
|
|
1
|
-
module Gamefic
|
2
|
-
# Create and restore plot snapshots.
|
3
|
-
#
|
4
|
-
class Plot
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
private
|
94
|
-
|
95
|
-
def hash_blacklist
|
96
|
-
[:@parent, :@children, :@last_action, :@scene, :@next_scene, :@playbook, :@performance_stack, :@buffer_stack, :@messages, :@state]
|
97
|
-
end
|
98
|
-
|
99
|
-
def can_serialize? v
|
100
|
-
return true if v.kind_of?(String) or v.kind_of?(Numeric) or v.kind_of?(Symbol) or v.kind_of?(Gamefic::Entity) or is_scene_class?(v) or v == true or v == false or v.nil?
|
101
|
-
if v.kind_of?(Array)
|
102
|
-
v.each do |e|
|
103
|
-
result = can_serialize?(e)
|
104
|
-
return false if result == false
|
105
|
-
end
|
106
|
-
true
|
107
|
-
elsif v.kind_of?(Hash)
|
108
|
-
v.each_pair do |k, v|
|
109
|
-
result = can_serialize?(k)
|
110
|
-
return false if result == false
|
111
|
-
result = can_serialize?(v)
|
112
|
-
return false if result == false
|
113
|
-
end
|
114
|
-
true
|
115
|
-
else
|
116
|
-
false
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
def is_scene_class?(v)
|
121
|
-
if v.kind_of?(Class)
|
122
|
-
s = v
|
123
|
-
until s.nil?
|
124
|
-
return true if s == Gamefic::Scene::Base
|
125
|
-
s = s.superclass
|
126
|
-
end
|
127
|
-
false
|
128
|
-
else
|
129
|
-
false
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def serialize v
|
134
|
-
if v.kind_of?(Array)
|
135
|
-
result = []
|
136
|
-
v.each do |e|
|
137
|
-
result.push serialize(e)
|
138
|
-
end
|
139
|
-
result
|
140
|
-
elsif v.kind_of?(Hash)
|
141
|
-
result = {}
|
142
|
-
v.each_pair do |k, v|
|
143
|
-
result[serialize(k)] = serialize(v)
|
144
|
-
end
|
145
|
-
result
|
146
|
-
elsif is_scene_class?(v)
|
147
|
-
i = plot.scene_classes.index(v)
|
148
|
-
"#<SIN_#{i}>"
|
149
|
-
elsif v.kind_of?(Gamefic::Entity)
|
150
|
-
i = entity_store.index(v)
|
151
|
-
if i.nil?
|
152
|
-
i = player_store.index(v)
|
153
|
-
if i.nil?
|
154
|
-
raise "#{v} not found in plot"
|
155
|
-
nil
|
156
|
-
else
|
157
|
-
"#<PIN_#{i}>"
|
158
|
-
end
|
159
|
-
else
|
160
|
-
"#<EIN_#{i}>"
|
161
|
-
end
|
162
|
-
else
|
163
|
-
v
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
def unserialize v
|
168
|
-
if v.kind_of?(Array)
|
169
|
-
result = []
|
170
|
-
v.each do |e|
|
171
|
-
result.push unserialize(e)
|
172
|
-
end
|
173
|
-
result
|
174
|
-
elsif v.kind_of?(Hash)
|
175
|
-
result = {}
|
176
|
-
v.each_pair do |k, v|
|
177
|
-
result[unserialize(k)] = unserialize(v)
|
178
|
-
end
|
179
|
-
result
|
180
|
-
elsif v.kind_of?(String)
|
181
|
-
if m = v.match(/#<SIN_([0-9]+)>/)
|
182
|
-
plot.scene_classes[m[1].to_i]
|
183
|
-
elsif m = v.match(/#<EIN_([0-9]+)>/)
|
184
|
-
entity_store[m[1].to_i]
|
185
|
-
elsif m = v.match(/#<PIN_([0-9]+)>/)
|
186
|
-
player_store[m[1].to_i]
|
187
|
-
else
|
188
|
-
v
|
189
|
-
end
|
190
|
-
else
|
191
|
-
v
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
def rebuild1 e, h
|
196
|
-
h.each_pair do |k, v|
|
197
|
-
if k.to_s.start_with?('@')
|
198
|
-
e.instance_variable_set(k, unserialize(v))
|
199
|
-
end
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
def rebuild2 e, h
|
204
|
-
h.each_pair do |k, v|
|
205
|
-
if k.to_s != 'class' and !k.to_s.start_with?('@')
|
206
|
-
e.send("#{k}=", unserialize(v))
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
def hash_subplot s
|
212
|
-
result = { entities: [], instance_variables: {}, theater_instance_variables: {} }
|
213
|
-
s.instance_variables.each { |i|
|
214
|
-
v = s.instance_variable_get(i)
|
215
|
-
result[:instance_variables][i] = serialize(v) if can_serialize?(v)
|
216
|
-
}
|
217
|
-
s.theater.instance_variables.each { |i|
|
218
|
-
v = s.theater.instance_variable_get(i)
|
219
|
-
result[:theater_instance_variables][i] = serialize(v) if can_serialize?(v)
|
220
|
-
}
|
221
|
-
s.entities.each { |s|
|
222
|
-
result[:entities].push serialize(s)
|
223
|
-
}
|
224
|
-
result[:class] = s.class.to_s.split('::').last
|
225
|
-
result
|
226
|
-
end
|
227
|
-
|
228
|
-
def rebuild_subplot s, h
|
229
|
-
s.entities.each { |e|
|
230
|
-
s.destroy e
|
231
|
-
}
|
232
|
-
h[:instance_variables].each_pair { |k, v|
|
233
|
-
s.instance_variable_set(k, unserialize(v))
|
234
|
-
}
|
235
|
-
h[:theater_instance_variables].each_pair { |k, v|
|
236
|
-
s.theater.instance_variable_set(k, unserialize(v))
|
237
|
-
}
|
238
|
-
i = 0
|
239
|
-
h[:entities].each { |e|
|
240
|
-
s.add_entity unserialize(e)
|
241
|
-
i += 1
|
242
|
-
}
|
243
|
-
end
|
244
|
-
|
245
|
-
def entity_store
|
246
|
-
@entity_store ||= []
|
247
|
-
end
|
248
|
-
|
249
|
-
def player_store
|
250
|
-
@player_store ||= []
|
251
|
-
end
|
252
|
-
|
253
|
-
def hash_entity e
|
254
|
-
h = {}
|
255
|
-
e.instance_variables.each { |i|
|
256
|
-
v = e.instance_variable_get(i)
|
257
|
-
h[i] = serialize(v) unless hash_blacklist.include?(i) or !can_serialize?(v)
|
258
|
-
}
|
259
|
-
h[:class] = e.class.to_s.split('::').last
|
260
|
-
h[:parent] = serialize(e.parent)
|
261
|
-
h
|
262
|
-
end
|
263
|
-
end
|
264
|
-
end
|
1
|
+
module Gamefic
|
2
|
+
# Create and restore plot snapshots.
|
3
|
+
#
|
4
|
+
class Plot
|
5
|
+
class Darkroom
|
6
|
+
# @return [Gamefic::Plot]
|
7
|
+
attr_reader :plot
|
8
|
+
|
9
|
+
def initialize plot
|
10
|
+
@plot = plot
|
11
|
+
end
|
12
|
+
|
13
|
+
# Create a snapshot of the plot.
|
14
|
+
#
|
15
|
+
# @return [Hash]
|
16
|
+
def save reduce: false
|
17
|
+
result = {
|
18
|
+
'elements' => Gamefic::Index.serials,
|
19
|
+
'entities' => plot.entities.map(&:to_serial),
|
20
|
+
'players' => plot.players.map(&:to_serial),
|
21
|
+
'theater_instance_variables' => plot.theater.serialize_instance_variables,
|
22
|
+
'subplots' => plot.subplots.reject(&:concluded?).map { |s| serialize_subplot(s) },
|
23
|
+
'metadata' => plot.metadata
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
# Restore a snapshot.
|
28
|
+
#
|
29
|
+
# @param snapshot [Hash]
|
30
|
+
def restore snapshot
|
31
|
+
Gamefic::Index.elements.map(&:destroy)
|
32
|
+
Gamefic::Index.unserialize snapshot['elements']
|
33
|
+
plot.entities.clear
|
34
|
+
snapshot['entities'].each do |ser|
|
35
|
+
plot.entities.push Index.from_serial(ser)
|
36
|
+
end
|
37
|
+
|
38
|
+
snapshot['theater_instance_variables'].each_pair do |k, s|
|
39
|
+
v = Gamefic::Index.from_serial(s)
|
40
|
+
next if v == "#<UNKNOWN>"
|
41
|
+
plot.theater.instance_variable_set(k, v)
|
42
|
+
end
|
43
|
+
|
44
|
+
snapshot['subplots'].each { |s| unserialize_subplot(s) }
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def namespace_to_constant string
|
50
|
+
space = Object
|
51
|
+
string.split('::').each do |part|
|
52
|
+
space = space.const_get(part)
|
53
|
+
end
|
54
|
+
space
|
55
|
+
end
|
56
|
+
|
57
|
+
def serialize_subplot s
|
58
|
+
{
|
59
|
+
'class' => s.class.to_s,
|
60
|
+
'entities' => s.entities.map(&:to_serial),
|
61
|
+
'instance_variables' => s.serialize_instance_variables,
|
62
|
+
'theater_instance_variables' => s.theater.serialize_instance_variables
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
def unserialize_subplot s
|
67
|
+
cls = namespace_to_constant(s['class'])
|
68
|
+
sp = cls.allocate
|
69
|
+
sp.instance_variable_set(:@plot, plot)
|
70
|
+
s['entities'].each do |e|
|
71
|
+
sp.entities.push Gamefic::Index.from_serial(e)
|
72
|
+
end
|
73
|
+
s['instance_variables'].each_pair do |k, v|
|
74
|
+
next if v == "#<UNKNOWN>"
|
75
|
+
sp.instance_variable_set(k, Gamefic::Index.from_serial(v))
|
76
|
+
end
|
77
|
+
s['theater_instance_variables'].each_pair do |k, v|
|
78
|
+
next if v == "#<UNKNOWN>"
|
79
|
+
sp.theater.instance_variable_set(k, Gamefic::Index.from_serial(v))
|
80
|
+
end
|
81
|
+
plot.subplots.push sp
|
82
|
+
sp.send(:run_scripts)
|
83
|
+
# @todo Assuming one player
|
84
|
+
if plot.players.first
|
85
|
+
sp.players.push plot.players.first
|
86
|
+
plot.players.first.playbooks.push sp.playbook unless plot.players.first.playbooks.include?(sp.playbook)
|
87
|
+
end
|
88
|
+
sp
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/gamefic/plot/host.rb
CHANGED
@@ -1,48 +1,42 @@
|
|
1
|
-
require 'gamefic/subplot'
|
2
|
-
|
3
|
-
module Gamefic
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
#
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
#
|
16
|
-
# @
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
subplot
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
#
|
25
|
-
#
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
#
|
36
|
-
#
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
def p_subplots
|
44
|
-
@p_subplots ||= []
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
1
|
+
require 'gamefic/subplot'
|
2
|
+
|
3
|
+
module Gamefic
|
4
|
+
# Methods for hosting and managing subplots.
|
5
|
+
#
|
6
|
+
module Plot::Host
|
7
|
+
# Get an array of all the current subplots.
|
8
|
+
#
|
9
|
+
# @return [Array<Subplot>]
|
10
|
+
def subplots
|
11
|
+
@subplots ||= []
|
12
|
+
end
|
13
|
+
|
14
|
+
# Start a new subplot based on the provided class.
|
15
|
+
#
|
16
|
+
# @param subplot_class [Class<Gamefic::Subplot>] The class of the subplot to be created (Subplot by default)
|
17
|
+
# @return [Gamefic::Subplot]
|
18
|
+
def branch subplot_class = Gamefic::Subplot, introduce: nil, next_cue: nil, **more
|
19
|
+
subplot = subplot_class.new(self, introduce: introduce, next_cue: next_cue, **more)
|
20
|
+
subplots.push subplot
|
21
|
+
subplot
|
22
|
+
end
|
23
|
+
|
24
|
+
# Get the player's current subplots.
|
25
|
+
#
|
26
|
+
# @return [Array<Subplot>]
|
27
|
+
def subplots_featuring player
|
28
|
+
result = []
|
29
|
+
subplots.each { |s|
|
30
|
+
result.push s if s.players.include?(player)
|
31
|
+
}
|
32
|
+
result
|
33
|
+
end
|
34
|
+
|
35
|
+
# Determine whether the player is involved in a subplot.
|
36
|
+
#
|
37
|
+
# @return [Boolean]
|
38
|
+
def in_subplot? player
|
39
|
+
!subplots_featuring(player).empty?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -4,29 +4,16 @@ module Gamefic
|
|
4
4
|
module Plot::Snapshot
|
5
5
|
# @return [Hash]
|
6
6
|
def save
|
7
|
-
|
8
|
-
internal_save
|
7
|
+
Gamefic::Plot::Darkroom.new(self).save
|
9
8
|
end
|
10
9
|
|
11
10
|
def restore snapshot
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
snapshot = JSON.parse(snapshot, symbolize_names: false) if snapshot.is_a?(String)
|
12
|
+
# HACK: Force conclusion of current subplots
|
13
|
+
subplots.each { |s| s.conclude }
|
14
|
+
subplots.clear
|
15
15
|
Gamefic::Plot::Darkroom.new(self).restore(snapshot)
|
16
16
|
entities.each { |e| e.flush }
|
17
17
|
end
|
18
|
-
|
19
|
-
def initial_state
|
20
|
-
if @initial_state.nil?
|
21
|
-
@initial_state = internal_save
|
22
|
-
end
|
23
|
-
@initial_state
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def internal_save
|
29
|
-
Gamefic::Plot::Darkroom.new(self).save
|
30
|
-
end
|
31
18
|
end
|
32
19
|
end
|