gamefic 2.0.0 → 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -1
- data/CHANGELOG.md +13 -0
- data/lib/gamefic.rb +1 -2
- data/lib/gamefic/action.rb +34 -38
- data/lib/gamefic/active.rb +18 -12
- data/lib/gamefic/core_ext/array.rb +3 -0
- data/lib/gamefic/element.rb +6 -2
- data/lib/gamefic/plot.rb +10 -12
- data/lib/gamefic/plot/darkroom.rb +49 -61
- data/lib/gamefic/plot/snapshot.rb +13 -5
- data/lib/gamefic/query.rb +1 -0
- data/lib/gamefic/query/base.rb +25 -24
- data/lib/gamefic/query/descendants.rb +2 -2
- data/lib/gamefic/query/family.rb +2 -0
- data/lib/gamefic/query/text.rb +10 -11
- data/lib/gamefic/query/tree.rb +17 -0
- data/lib/gamefic/scene.rb +0 -1
- data/lib/gamefic/scene/base.rb +7 -2
- data/lib/gamefic/scene/conclusion.rb +1 -1
- data/lib/gamefic/scene/multiple_choice.rb +2 -12
- data/lib/gamefic/scene/pause.rb +1 -1
- data/lib/gamefic/scene/yes_or_no.rb +1 -1
- data/lib/gamefic/scriptable.rb +1 -0
- data/lib/gamefic/serialize.rb +172 -17
- data/lib/gamefic/subplot.rb +11 -2
- data/lib/gamefic/syntax.rb +1 -0
- data/lib/gamefic/version.rb +1 -1
- data/lib/gamefic/world.rb +2 -0
- data/lib/gamefic/world/commands.rb +8 -8
- data/lib/gamefic/world/entities.rb +11 -14
- data/lib/gamefic/world/playbook.rb +30 -40
- data/lib/gamefic/world/players.rb +18 -2
- data/lib/gamefic/world/scenes.rb +13 -13
- metadata +18 -18
- data/lib/gamefic/index.rb +0 -121
- data/lib/gamefic/scene/custom.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d4af1f6add0c467fce62acde7d4903e2165a0007312720ac0a43fb324e2a594
|
4
|
+
data.tar.gz: fe6adad9a8c85fd9eac1b9b6921e13f356da73489e9d82c95b63974f94f45df0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b2b0fda9b69825c655f6dfa90fa4c1bca78a6a53ea625946d54f9981d11104660f1e4f312bc53086559345f0c211edf979f237e18fd4bf95d83a2755e7b1cc9b
|
7
|
+
data.tar.gz: b1c85ff6f5c103354af38588bc129c989929c259ef4062abd8e9a0e5f92100fcf2134e1d16f3d8e3180bbcacd672d85b3cf5d1f162a8ff19217a64dc419e9bd7
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# 2.1.1 - July 23, 2021
|
2
|
+
- Remove gamefic/scene/custom autoload
|
3
|
+
|
4
|
+
# 2.1.0 - June 21, 2021
|
5
|
+
- Remove redundant MultipleChoice prompt
|
6
|
+
- Deprecate Scene::Custom
|
7
|
+
|
8
|
+
# 2.0.3 - December 14, 2020
|
9
|
+
- Remove unused Index class
|
10
|
+
- Active#conclude accepts data argument
|
11
|
+
|
12
|
+
# 2.0.2 - April 25, 2020
|
13
|
+
- Improved snapshot serialization
|
data/lib/gamefic.rb
CHANGED
@@ -5,7 +5,6 @@ require 'gamefic/core_ext/array'
|
|
5
5
|
require 'gamefic/core_ext/string'
|
6
6
|
|
7
7
|
require 'gamefic/describable'
|
8
|
-
require 'gamefic/index'
|
9
8
|
require 'gamefic/serialize'
|
10
9
|
require 'gamefic/element'
|
11
10
|
require 'gamefic/entity'
|
@@ -17,5 +16,5 @@ require "gamefic/action"
|
|
17
16
|
require "gamefic/syntax"
|
18
17
|
require 'gamefic/world'
|
19
18
|
require 'gamefic/scriptable'
|
20
|
-
require
|
19
|
+
require 'gamefic/plot'
|
21
20
|
require 'gamefic/subplot'
|
data/lib/gamefic/action.rb
CHANGED
@@ -1,9 +1,4 @@
|
|
1
1
|
module Gamefic
|
2
|
-
# Exception raised when the Action's proc arity is not compatible with the
|
3
|
-
# number of queries
|
4
|
-
class ActionArgumentError < ArgumentError
|
5
|
-
end
|
6
|
-
|
7
2
|
class Action
|
8
3
|
# An array of objects on which the action will operate, e.g., an entity
|
9
4
|
# that is a direct object of a command.
|
@@ -54,25 +49,32 @@ module Gamefic
|
|
54
49
|
self.class.meta?
|
55
50
|
end
|
56
51
|
|
57
|
-
|
52
|
+
# @param verb [Symbol]
|
53
|
+
# @param queries [Array<Gamefic::Query::Base>]
|
54
|
+
# @param meta [Boolean]
|
55
|
+
# @return [Class<Action>]
|
56
|
+
def self.subclass verb, *queries, meta: false, &block
|
58
57
|
act = Class.new(self) do
|
59
58
|
self.verb = verb
|
60
59
|
self.meta = meta
|
61
|
-
|
60
|
+
queries.each do |q|
|
62
61
|
add_query q
|
63
|
-
|
62
|
+
end
|
64
63
|
on_execute &block
|
65
64
|
end
|
66
|
-
if !block.nil?
|
67
|
-
raise
|
65
|
+
if !block.nil? && act.queries.length + 1 != block.arity && block.arity > 0
|
66
|
+
raise ArgumentError.new("Number of parameters is not compatible with proc arguments")
|
68
67
|
end
|
69
68
|
act
|
70
69
|
end
|
71
70
|
|
72
71
|
class << self
|
73
|
-
|
74
|
-
|
75
|
-
|
72
|
+
attr_reader :verb
|
73
|
+
|
74
|
+
# The proc to call when the action is executed
|
75
|
+
#
|
76
|
+
# @return [Proc]
|
77
|
+
attr_reader :executor
|
76
78
|
|
77
79
|
def meta?
|
78
80
|
@meta ||= false
|
@@ -93,7 +95,7 @@ module Gamefic
|
|
93
95
|
|
94
96
|
def signature
|
95
97
|
# @todo This is clearly unfinished
|
96
|
-
"#{verb} #{queries.map{|m| m.signature}.join(', ')}"
|
98
|
+
"#{verb} #{queries.map {|m| m.signature}.join(', ')}"
|
97
99
|
end
|
98
100
|
|
99
101
|
# True if this action is not intended to be performed directly by a
|
@@ -107,19 +109,13 @@ module Gamefic
|
|
107
109
|
verb.to_s.start_with?('_')
|
108
110
|
end
|
109
111
|
|
110
|
-
#
|
111
|
-
#
|
112
|
-
# @return [Proc]
|
113
|
-
def executor
|
114
|
-
@executor
|
115
|
-
end
|
116
|
-
|
112
|
+
# @return [Integer]
|
117
113
|
def rank
|
118
114
|
if @rank.nil?
|
119
115
|
@rank = 0
|
120
|
-
queries.each
|
116
|
+
queries.each do |q|
|
121
117
|
@rank += (q.rank + 1)
|
122
|
-
|
118
|
+
end
|
123
119
|
@rank -= 1000 if verb.nil?
|
124
120
|
end
|
125
121
|
@rank
|
@@ -128,22 +124,27 @@ module Gamefic
|
|
128
124
|
def valid? actor, objects
|
129
125
|
return false if objects.length != queries.length
|
130
126
|
i = 0
|
131
|
-
queries.each
|
127
|
+
queries.each do |p|
|
132
128
|
return false unless p.include?(actor, objects[i])
|
133
129
|
i += 1
|
134
|
-
|
130
|
+
end
|
135
131
|
true
|
136
132
|
end
|
137
133
|
|
134
|
+
# Return an instance of this Action if the actor can execute it with the
|
135
|
+
# provided tokens, or nil if the tokens are invalid.
|
136
|
+
#
|
137
|
+
# @param action [Gamefic::Entity]
|
138
|
+
# @param tokens [Array<String>]
|
139
|
+
# @return [self, nil]
|
138
140
|
def attempt actor, tokens
|
139
|
-
i = 0
|
140
141
|
result = []
|
141
142
|
matches = Gamefic::Query::Matches.new([], '', '')
|
142
|
-
queries.
|
143
|
-
return nil if tokens[i].nil?
|
143
|
+
queries.each_with_index do |p, i|
|
144
|
+
return nil if tokens[i].nil? && matches.remaining == ''
|
144
145
|
matches = p.resolve(actor, "#{matches.remaining} #{tokens[i]}".strip, continued: (i < queries.length - 1))
|
145
146
|
return nil if matches.objects.empty?
|
146
|
-
accepted = matches.objects.select{|o| p.accept?(o)}
|
147
|
+
accepted = matches.objects.select { |o| p.accept?(o) }
|
147
148
|
return nil if accepted.empty?
|
148
149
|
if p.ambiguous?
|
149
150
|
result.push accepted
|
@@ -151,20 +152,15 @@ module Gamefic
|
|
151
152
|
return nil if accepted.length != 1
|
152
153
|
result.push accepted.first
|
153
154
|
end
|
154
|
-
|
155
|
-
|
156
|
-
self.new(actor, result)
|
155
|
+
end
|
156
|
+
new(actor, result)
|
157
157
|
end
|
158
158
|
|
159
159
|
protected
|
160
160
|
|
161
|
-
|
162
|
-
@verb = sym
|
163
|
-
end
|
161
|
+
attr_writer :verb
|
164
162
|
|
165
|
-
|
166
|
-
@meta = bool
|
167
|
-
end
|
163
|
+
attr_writer :meta
|
168
164
|
end
|
169
165
|
end
|
170
166
|
end
|
data/lib/gamefic/active.rb
CHANGED
@@ -117,9 +117,7 @@ module Gamefic
|
|
117
117
|
#
|
118
118
|
# @return [String] The output that resulted from performing the command.
|
119
119
|
def quietly(*command)
|
120
|
-
if buffer_stack == 0
|
121
|
-
clear_buffer
|
122
|
-
end
|
120
|
+
clear_buffer if buffer_stack == 0
|
123
121
|
set_buffer_stack buffer_stack + 1
|
124
122
|
self.perform *command
|
125
123
|
set_buffer_stack buffer_stack - 1
|
@@ -152,10 +150,12 @@ module Gamefic
|
|
152
150
|
# introduction do |actor|
|
153
151
|
# actor[:has_eaten] = false # Initial value
|
154
152
|
# end
|
153
|
+
#
|
155
154
|
# respond :eat do |actor|
|
156
155
|
# actor.tell "You eat something."
|
157
156
|
# actor[:has_eaten] = true
|
158
157
|
# end
|
158
|
+
#
|
159
159
|
# respond :eat do |actor|
|
160
160
|
# # This version will be executed first because it was implemented last
|
161
161
|
# if actor[:has_eaten]
|
@@ -187,13 +187,14 @@ module Gamefic
|
|
187
187
|
# Use #prepare if you want to declare a scene to be started at the
|
188
188
|
# beginning of the next turn.
|
189
189
|
#
|
190
|
-
# @param new_scene [Class]
|
191
|
-
|
190
|
+
# @param new_scene [Class<Scene::Base>]
|
191
|
+
# @param data [Hash] Additional scene data
|
192
|
+
def cue new_scene, **data
|
192
193
|
@next_scene = nil
|
193
194
|
if new_scene.nil?
|
194
195
|
@scene = nil
|
195
196
|
else
|
196
|
-
@scene = new_scene.new(self, **
|
197
|
+
@scene = new_scene.new(self, **data)
|
197
198
|
@scene.start
|
198
199
|
end
|
199
200
|
end
|
@@ -202,10 +203,11 @@ module Gamefic
|
|
202
203
|
# next turn. As opposed to #cue, a prepared scene will not start until the
|
203
204
|
# current scene finishes.
|
204
205
|
#
|
205
|
-
# @param new_scene [Class]
|
206
|
-
|
206
|
+
# @param new_scene [Class<Scene::Base>]
|
207
|
+
# @oaram data [Hash] Additional scene data
|
208
|
+
def prepare new_scene, **data
|
207
209
|
@next_scene = new_scene
|
208
|
-
@next_options =
|
210
|
+
@next_options = data
|
209
211
|
end
|
210
212
|
|
211
213
|
# Return true if the character is expected to be in the specified scene on
|
@@ -219,9 +221,11 @@ module Gamefic
|
|
219
221
|
# Cue a conclusion. This method works like #cue, except it will raise a
|
220
222
|
# NotConclusionError if the scene is not a Scene::Conclusion.
|
221
223
|
#
|
222
|
-
|
223
|
-
|
224
|
-
|
224
|
+
# @param new_scene [Class<Scene::Base>]
|
225
|
+
# @oaram data [Hash] Additional scene data
|
226
|
+
def conclude new_scene, **data
|
227
|
+
raise NotConclusionError unless new_scene <= Scene::Conclusion
|
228
|
+
cue new_scene, **data
|
225
229
|
end
|
226
230
|
|
227
231
|
# True if the character is in a conclusion.
|
@@ -269,6 +273,8 @@ module Gamefic
|
|
269
273
|
@entered_scenes ||= []
|
270
274
|
end
|
271
275
|
|
276
|
+
# @param actions [Array<Gamefic::Action>]
|
277
|
+
# @param quietly [Boolean]
|
272
278
|
def execute_stack actions, quietly: false
|
273
279
|
return nil if actions.empty?
|
274
280
|
a = actions.first
|
@@ -44,6 +44,9 @@ class Array
|
|
44
44
|
# animals = ['a dog', 'a cat', 'a mouse']
|
45
45
|
# animals.join_and #=> 'a dog, a cat, and a mouse'
|
46
46
|
#
|
47
|
+
# @param sep [String] The separator for all but the last element
|
48
|
+
# @param andSep [String] The separator for the last element
|
49
|
+
# @param serial [Boolean] Use serial separators (e.g., serial commas)
|
47
50
|
# @return [String]
|
48
51
|
def join_and(sep = ', ', andSep = ' and ', serial = true)
|
49
52
|
if self.length < 3
|
data/lib/gamefic/element.rb
CHANGED
@@ -7,11 +7,15 @@ module Gamefic
|
|
7
7
|
#
|
8
8
|
class Element
|
9
9
|
include Gamefic::Describable
|
10
|
-
include Gamefic::Index
|
10
|
+
# include Gamefic::Index
|
11
|
+
include Gamefic::Serialize
|
11
12
|
|
12
13
|
# @todo It would be nice if this initialization wasn't necessary.
|
13
14
|
def initialize(args = {})
|
14
|
-
super self.class.default_attributes.merge(args)
|
15
|
+
# super self.class.default_attributes.merge(args)
|
16
|
+
self.class.default_attributes.merge(args).each_pair do |k, v|
|
17
|
+
public_send "#{k}=", v
|
18
|
+
end
|
15
19
|
post_initialize
|
16
20
|
yield self if block_given?
|
17
21
|
end
|
data/lib/gamefic/plot.rb
CHANGED
@@ -16,25 +16,22 @@ module Gamefic
|
|
16
16
|
# @return [Hash]
|
17
17
|
attr_reader :metadata
|
18
18
|
|
19
|
+
attr_reader :static
|
20
|
+
|
19
21
|
include World
|
20
22
|
include Scriptable
|
21
23
|
# @!parse extend Scriptable::ClassMethods
|
22
24
|
include Snapshot
|
23
25
|
include Host
|
26
|
+
include Serialize
|
27
|
+
|
28
|
+
exclude_from_serial [:@static]
|
24
29
|
|
25
|
-
# @param structure [Gamefic::Structure]
|
26
30
|
# @param metadata [Hash]
|
27
31
|
def initialize metadata: {}
|
28
|
-
Gamefic::Index.clear
|
29
32
|
@metadata = metadata
|
30
33
|
run_scripts
|
31
|
-
|
32
|
-
Gamefic::Index.stick
|
33
|
-
end
|
34
|
-
|
35
|
-
def player_class cls = nil
|
36
|
-
@player_class = cls unless cls.nil?
|
37
|
-
@player_class ||= Gamefic::Actor
|
34
|
+
@static = [self] + scene_classes + entities
|
38
35
|
end
|
39
36
|
|
40
37
|
# Get an Array of the Plot's current Syntaxes.
|
@@ -59,7 +56,8 @@ module Gamefic
|
|
59
56
|
.merge({
|
60
57
|
messages: p.messages,
|
61
58
|
last_prompt: p.last_prompt,
|
62
|
-
last_input: p.last_input
|
59
|
+
last_input: p.last_input,
|
60
|
+
queue: p.queue
|
63
61
|
})
|
64
62
|
.merge(p.state)
|
65
63
|
)
|
@@ -89,8 +87,8 @@ module Gamefic
|
|
89
87
|
end
|
90
88
|
call_player_update
|
91
89
|
call_update
|
92
|
-
subplots.
|
93
|
-
subplots.
|
90
|
+
subplots.delete_if(&:concluded?)
|
91
|
+
subplots.each(&:update)
|
94
92
|
end
|
95
93
|
|
96
94
|
# Send a message to a group of entities.
|
@@ -13,14 +13,21 @@ module Gamefic
|
|
13
13
|
# Create a snapshot of the plot.
|
14
14
|
#
|
15
15
|
# @return [Hash]
|
16
|
-
def save
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
'
|
21
|
-
'
|
22
|
-
|
23
|
-
|
16
|
+
def save
|
17
|
+
index = plot.static + plot.players
|
18
|
+
plot.to_serial(index)
|
19
|
+
{
|
20
|
+
'program' => {}, # @todo Metadata for version control, etc.
|
21
|
+
'index' => index.map do |i|
|
22
|
+
if i.is_a?(Gamefic::Serialize)
|
23
|
+
{
|
24
|
+
'class' => i.class.to_s,
|
25
|
+
'ivars' => i.serialize_instance_variables(index)
|
26
|
+
}
|
27
|
+
else
|
28
|
+
i.to_serial(index)
|
29
|
+
end
|
30
|
+
end
|
24
31
|
}
|
25
32
|
end
|
26
33
|
|
@@ -28,64 +35,45 @@ module Gamefic
|
|
28
35
|
#
|
29
36
|
# @param snapshot [Hash]
|
30
37
|
def restore snapshot
|
31
|
-
|
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
|
38
|
+
# @todo Use `program` for verification
|
37
39
|
|
38
|
-
|
39
|
-
|
40
|
-
next if v == "#<UNKNOWN>"
|
41
|
-
plot.theater.instance_variable_set(k, v)
|
42
|
-
end
|
40
|
+
plot.subplots.each(&:conclude)
|
41
|
+
plot.subplots.clear
|
43
42
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
43
|
+
index = plot.static + plot.players
|
44
|
+
snapshot['index'].each_with_index do |obj, idx|
|
45
|
+
next if index[idx]
|
46
|
+
elematch = obj['class'].match(/^#<ELE_([\d]+)>$/)
|
47
|
+
if elematch
|
48
|
+
klass = index[elematch[1].to_i]
|
49
|
+
else
|
50
|
+
klass = Gamefic::Serialize.string_to_constant(obj['class'])
|
51
|
+
end
|
52
|
+
index.push klass.allocate
|
53
53
|
end
|
54
|
-
space
|
55
|
-
end
|
56
54
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
'
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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)
|
55
|
+
snapshot['index'].each_with_index do |obj, idx|
|
56
|
+
if index[idx].class.to_s != obj['class']
|
57
|
+
STDERR.puts "MISMATCH: #{index[idx].class} is not #{obj['class']}"
|
58
|
+
STDERR.puts obj.inspect
|
59
|
+
end
|
60
|
+
obj['ivars'].each_pair do |k, v|
|
61
|
+
next if k == '@subplots'
|
62
|
+
uns = v.from_serial(index)
|
63
|
+
next if uns == "#<UNKNOWN>"
|
64
|
+
index[idx].instance_variable_set(k, uns)
|
65
|
+
end
|
66
|
+
if index[idx].is_a?(Gamefic::Subplot)
|
67
|
+
index[idx].extend Gamefic::Scriptable
|
68
|
+
index[idx].instance_variable_set(:@theater, nil)
|
69
|
+
index[idx].send(:run_scripts)
|
70
|
+
index[idx].players.each do |pl|
|
71
|
+
pl.playbooks.push index[idx].playbook unless pl.playbooks.include?(index[idx].playbook)
|
72
|
+
end
|
73
|
+
index[idx].instance_variable_set(:@static, [index[idx]] + index[idx].scene_classes + index[idx].entities)
|
74
|
+
plot.subplots.push index[idx]
|
75
|
+
end
|
87
76
|
end
|
88
|
-
sp
|
89
77
|
end
|
90
78
|
end
|
91
79
|
end
|