gamefic 1.7.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +12 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +13 -0
  5. data/.solargraph.yml +5 -0
  6. data/Gemfile +7 -0
  7. data/LICENSE +20 -0
  8. data/README.md +28 -0
  9. data/Rakefile +10 -0
  10. data/gamefic.gemspec +27 -0
  11. data/lib/gamefic.rb +7 -6
  12. data/lib/gamefic/action.rb +38 -28
  13. data/lib/gamefic/active.rb +325 -280
  14. data/lib/gamefic/actor.rb +8 -5
  15. data/lib/gamefic/command.rb +9 -7
  16. data/lib/gamefic/core_ext/array.rb +24 -49
  17. data/lib/gamefic/core_ext/string.rb +25 -16
  18. data/lib/gamefic/describable.rb +21 -23
  19. data/lib/gamefic/element.rb +43 -31
  20. data/lib/gamefic/entity.rb +6 -12
  21. data/lib/gamefic/index.rb +121 -0
  22. data/lib/gamefic/{matchable.rb → keywords.rb} +52 -50
  23. data/lib/gamefic/messaging.rb +43 -44
  24. data/lib/gamefic/node.rb +14 -5
  25. data/lib/gamefic/plot.rb +69 -89
  26. data/lib/gamefic/plot/darkroom.rb +92 -264
  27. data/lib/gamefic/plot/host.rb +42 -48
  28. data/lib/gamefic/plot/snapshot.rb +5 -18
  29. data/lib/gamefic/query.rb +14 -18
  30. data/lib/gamefic/query/base.rb +30 -18
  31. data/lib/gamefic/query/children.rb +0 -0
  32. data/lib/gamefic/query/external.rb +18 -14
  33. data/lib/gamefic/query/family.rb +1 -7
  34. data/lib/gamefic/query/matches.rb +75 -67
  35. data/lib/gamefic/query/parent.rb +0 -0
  36. data/lib/gamefic/query/siblings.rb +0 -0
  37. data/lib/gamefic/query/text.rb +2 -1
  38. data/lib/gamefic/scene.rb +0 -2
  39. data/lib/gamefic/scene/activity.rb +24 -26
  40. data/lib/gamefic/scene/base.rb +64 -8
  41. data/lib/gamefic/scene/conclusion.rb +0 -2
  42. data/lib/gamefic/scene/custom.rb +0 -2
  43. data/lib/gamefic/scene/multiple_choice.rb +18 -3
  44. data/lib/gamefic/scene/multiple_scene.rb +29 -20
  45. data/lib/gamefic/scene/pause.rb +7 -2
  46. data/lib/gamefic/scene/yes_or_no.rb +21 -9
  47. data/lib/gamefic/scriptable.rb +87 -0
  48. data/lib/gamefic/serialize.rb +68 -0
  49. data/lib/gamefic/subplot.rb +29 -35
  50. data/lib/gamefic/syntax.rb +14 -13
  51. data/lib/gamefic/version.rb +3 -3
  52. data/lib/gamefic/world.rb +16 -0
  53. data/lib/gamefic/world/callbacks.rb +135 -0
  54. data/lib/gamefic/world/commands.rb +184 -0
  55. data/lib/gamefic/{plot → world}/entities.rb +30 -29
  56. data/lib/gamefic/{plot → world}/playbook.rb +255 -240
  57. data/lib/gamefic/world/players.rb +21 -0
  58. data/lib/gamefic/world/scenes.rb +226 -0
  59. metadata +41 -92
  60. data/bin/gamefic +0 -9
  61. data/lib/gamefic/engine.rb +0 -7
  62. data/lib/gamefic/engine/base.rb +0 -59
  63. data/lib/gamefic/engine/tty.rb +0 -24
  64. data/lib/gamefic/grammar.rb +0 -13
  65. data/lib/gamefic/grammar/conjugator.rb +0 -20
  66. data/lib/gamefic/grammar/gender.rb +0 -11
  67. data/lib/gamefic/grammar/person.rb +0 -10
  68. data/lib/gamefic/grammar/plural.rb +0 -13
  69. data/lib/gamefic/grammar/pronouns.rb +0 -106
  70. data/lib/gamefic/grammar/tense.rb +0 -6
  71. data/lib/gamefic/grammar/verb_set.rb +0 -43
  72. data/lib/gamefic/grammar/verbs.rb +0 -26
  73. data/lib/gamefic/grammar/word_adapter.rb +0 -49
  74. data/lib/gamefic/plot/articles.rb +0 -22
  75. data/lib/gamefic/plot/callbacks.rb +0 -126
  76. data/lib/gamefic/plot/commands.rb +0 -120
  77. data/lib/gamefic/plot/players.rb +0 -15
  78. data/lib/gamefic/plot/scenes.rb +0 -187
  79. data/lib/gamefic/plot/theater.rb +0 -73
  80. data/lib/gamefic/plot/you_mount.rb +0 -22
  81. data/lib/gamefic/script.rb +0 -13
  82. data/lib/gamefic/script/base.rb +0 -42
  83. data/lib/gamefic/script/file.rb +0 -14
  84. data/lib/gamefic/script/text.rb +0 -14
  85. data/lib/gamefic/shell.rb +0 -76
  86. data/lib/gamefic/source.rb +0 -14
  87. data/lib/gamefic/source/base.rb +0 -12
  88. data/lib/gamefic/source/file.rb +0 -23
  89. data/lib/gamefic/source/text.rb +0 -16
  90. data/lib/gamefic/tester.rb +0 -19
  91. data/lib/gamefic/text.rb +0 -8
  92. data/lib/gamefic/text/ansi.rb +0 -53
  93. data/lib/gamefic/text/html.rb +0 -68
  94. data/lib/gamefic/text/html/conversions.rb +0 -250
  95. data/lib/gamefic/text/html/entities.rb +0 -9
  96. data/lib/gamefic/tty.rb +0 -10
  97. data/lib/gamefic/user.rb +0 -7
  98. data/lib/gamefic/user/base.rb +0 -29
  99. 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::Darkroom
5
- attr_reader :plot
6
-
7
- def initialize plot
8
- @plot = plot
9
- end
10
-
11
- # Create a snapshot of the plot.
12
- #
13
- # @return [Hash]
14
- def save
15
- result = { entities: [], players: [], subplots: [], instance_variables: {} }
16
- entity_store.clear
17
- player_store.clear
18
- entity_store.concat plot.entities
19
- player_store.concat plot.players
20
- plot.subplots.each { |s| entity_store.concat s.entities }
21
- entity_store.uniq!
22
- entity_store.each do |e|
23
- result[:entities].push hash_entity(e)
24
- end
25
- player_store.each do |p|
26
- result[:players].push hash_entity(p)
27
- end
28
- plot.theater.instance_variables.each { |i|
29
- v = plot.theater.instance_variable_get(i)
30
- result[:instance_variables][i] = serialize(v) if can_serialize?(v)
31
- }
32
- plot.subplots.each { |s|
33
- result[:subplots].push hash_subplot(s)
34
- }
35
- result
36
- end
37
-
38
- # Restore a snapshot.
39
- #
40
- def restore snapshot
41
- entity_store.clear
42
- player_store.clear
43
- plot.subplots.each { |s| s.conclude }
44
- plot.entities[plot.initial_state[:entities].length..-1].each { |e| plot.destroy e }
45
- entity_store.concat plot.entities[0..plot.initial_state[:entities].length-1]
46
- entity_store.uniq!
47
- player_store.concat plot.players
48
- i = 0
49
- snapshot[:entities].each { |h|
50
- if entity_store[i].nil?
51
- e = plot.stage do
52
- cls = self.const_get(h[:class])
53
- make cls
54
- end
55
- entity_store.push e
56
- end
57
- i += 1
58
- }
59
- snapshot[:subplots].each { |s|
60
- sp = plot.stage do
61
- cls = const_get(s[:class])
62
- branch cls
63
- end
64
- # @todo Assuming one player
65
- sp.introduce player_store[0] unless player_store.empty?
66
- rebuild_subplot sp, s
67
- }
68
- i = 0
69
- snapshot[:entities].each { |h|
70
- rebuild1 entity_store[i], h
71
- i += 1
72
- }
73
- i = 0
74
- snapshot[:players].each { |p|
75
- rebuild1 player_store[i], p
76
- i += 1
77
- }
78
- i = 0
79
- snapshot[:entities].each { |h|
80
- rebuild2 entity_store[i], h
81
- i += 1
82
- }
83
- i = 0
84
- snapshot[:players].each { |h|
85
- rebuild2 player_store[i], h
86
- i += 1
87
- }
88
- snapshot[:instance_variables].each_pair { |k, v|
89
- plot.theater.instance_variable_set(k, unserialize(v))
90
- }
91
- end
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
@@ -1,48 +1,42 @@
1
- require 'gamefic/subplot'
2
-
3
- module Gamefic
4
-
5
- module Plot::Host
6
- # Get an array of all the current subplots.
7
- #
8
- # @return [Array<Subplot>]
9
- def subplots
10
- p_subplots.clone
11
- end
12
-
13
- # Start a new subplot based on the provided class.
14
- #
15
- # @param subplot_class [Class] The class of the subplot to be created (Subplot by default)
16
- # @return [Subplot]
17
- def branch subplot_class = Gamefic::Subplot, introduce: nil, next_cue: nil
18
- subplot = subplot_class.new(self, introduce: introduce, next_cue: next_cue)
19
- p_subplots.push subplot
20
- subplot
21
- end
22
-
23
- # Get the player's current subplots.
24
- #
25
- # @return [Array<Subplot>]
26
- def subplots_featuring player
27
- result = []
28
- subplots.each { |s|
29
- result.push s if s.players.include?(player)
30
- }
31
- result
32
- end
33
-
34
- # Determine whether the player is involved in a subplot.
35
- #
36
- # @return [Boolean]
37
- def in_subplot? player
38
- !subplots_featuring(player).empty?
39
- end
40
-
41
- private
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
- initial_state
8
- internal_save
7
+ Gamefic::Plot::Darkroom.new(self).save
9
8
  end
10
9
 
11
10
  def restore snapshot
12
- # HACK Force conclusion of current subplots
13
- p_subplots.each { |s| s.conclude }
14
- p_subplots.clear
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