gamefic 1.7.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|