gamefic 3.3.0 → 3.5.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/CHANGELOG.md +20 -0
- data/README.md +1 -1
- data/lib/gamefic/action.rb +4 -4
- data/lib/gamefic/active/epic.rb +1 -0
- data/lib/gamefic/active.rb +4 -0
- data/lib/gamefic/callback.rb +16 -0
- data/lib/gamefic/chapter.rb +71 -0
- data/lib/gamefic/command.rb +40 -1
- data/lib/gamefic/dispatcher.rb +5 -31
- data/lib/gamefic/entity.rb +26 -0
- data/lib/gamefic/narrative.rb +30 -8
- data/lib/gamefic/plot.rb +28 -1
- data/lib/gamefic/proxy.rb +46 -0
- data/lib/gamefic/query/base.rb +28 -12
- data/lib/gamefic/query/general.rb +3 -12
- data/lib/gamefic/query/result.rb +4 -1
- data/lib/gamefic/query/scoped.rb +1 -18
- data/lib/gamefic/query/text.rb +13 -12
- data/lib/gamefic/response.rb +66 -38
- data/lib/gamefic/rulebook/calls.rb +0 -4
- data/lib/gamefic/rulebook/events.rb +10 -24
- data/lib/gamefic/rulebook/hooks.rb +10 -10
- data/lib/gamefic/rulebook.rb +8 -22
- data/lib/gamefic/scanner/base.rb +44 -0
- data/lib/gamefic/scanner/fuzzy.rb +17 -0
- data/lib/gamefic/scanner/fuzzy_nesting.rb +14 -0
- data/lib/gamefic/scanner/nesting.rb +39 -0
- data/lib/gamefic/scanner/result.rb +50 -0
- data/lib/gamefic/scanner/strict.rb +31 -0
- data/lib/gamefic/scanner.rb +33 -111
- data/lib/gamefic/scope/descendants.rb +16 -0
- data/lib/gamefic/scope/family.rb +31 -8
- data/lib/gamefic/scope.rb +1 -0
- data/lib/gamefic/scriptable/actions.rb +8 -27
- data/lib/gamefic/scriptable/entities.rb +4 -1
- data/lib/gamefic/scriptable/events.rb +13 -7
- data/lib/gamefic/scriptable/plot_proxies.rb +16 -0
- data/lib/gamefic/scriptable/proxies.rb +31 -0
- data/lib/gamefic/scriptable/queries.rb +15 -7
- data/lib/gamefic/scriptable/scenes.rb +10 -4
- data/lib/gamefic/scriptable.rb +73 -42
- data/lib/gamefic/stage.rb +2 -2
- data/lib/gamefic/subplot.rb +31 -7
- data/lib/gamefic/version.rb +1 -1
- data/lib/gamefic.rb +3 -1
- metadata +14 -4
- data/lib/gamefic/composer.rb +0 -70
- data/lib/gamefic/scriptable/proxy.rb +0 -69
data/lib/gamefic/scriptable.rb
CHANGED
@@ -23,14 +23,14 @@ module Gamefic
|
|
23
23
|
# end
|
24
24
|
#
|
25
25
|
module Scriptable
|
26
|
-
autoload :Actions,
|
27
|
-
autoload :Entities,
|
28
|
-
autoload :Events,
|
29
|
-
autoload :Queries,
|
30
|
-
autoload :
|
31
|
-
autoload :Scenes,
|
32
|
-
|
33
|
-
|
26
|
+
autoload :Actions, 'gamefic/scriptable/actions'
|
27
|
+
autoload :Entities, 'gamefic/scriptable/entities'
|
28
|
+
autoload :Events, 'gamefic/scriptable/events'
|
29
|
+
autoload :Queries, 'gamefic/scriptable/queries'
|
30
|
+
autoload :Proxies, 'gamefic/scriptable/proxies'
|
31
|
+
autoload :Scenes, 'gamefic/scriptable/scenes'
|
32
|
+
autoload :PlotProxies, 'gamefic/scriptable/plot_proxies'
|
33
|
+
|
34
34
|
include Queries
|
35
35
|
# @!parse
|
36
36
|
# include Scriptable::Actions
|
@@ -101,10 +101,10 @@ module Gamefic
|
|
101
101
|
# make_seed Gamefic::Entity, name: 'thing'
|
102
102
|
#
|
103
103
|
# @param klass [Class<Gamefic::Entity>]
|
104
|
+
# @return [void]
|
104
105
|
def make_seed klass, **opts
|
105
|
-
@count ||= 0
|
106
106
|
seed { make(klass, **opts) }
|
107
|
-
|
107
|
+
nil
|
108
108
|
end
|
109
109
|
|
110
110
|
# Seed an entity with an attribute method.
|
@@ -117,16 +117,69 @@ module Gamefic
|
|
117
117
|
# plot = Plot.new
|
118
118
|
# plot.thing #=> #<Gamefic::Entity a thing>
|
119
119
|
#
|
120
|
+
# @param name [Symbol] The attribute name
|
120
121
|
# @param klass [Class<Gamefic::Entity>]
|
122
|
+
# @return [Proxy]
|
121
123
|
def attr_seed name, klass, **opts
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
124
|
+
ivname = "@#{name}"
|
125
|
+
define_method(name) do
|
126
|
+
return instance_variable_get(ivname) if instance_variable_defined?(ivname)
|
127
|
+
|
128
|
+
instance_variable_set(ivname, make(klass, **opts))
|
129
|
+
end
|
130
|
+
seed { send name }
|
131
|
+
Proxy.new(:attr, name)
|
132
|
+
end
|
133
|
+
|
134
|
+
# @param symbol [Symbol]
|
135
|
+
# @return [Proxy]
|
136
|
+
def proxy symbol
|
137
|
+
Logging.logger.warn "#proxy is deprecated. Use lazy_attr, lazy_ivar, or lazy_pick instead"
|
138
|
+
if symbol.to_s.start_with?('@')
|
139
|
+
lazy_ivar(symbol)
|
140
|
+
else
|
141
|
+
lazy_attr(symbol)
|
126
142
|
end
|
127
|
-
Proxy::Agent.new(@count.tap { @count += 1 })
|
128
143
|
end
|
129
144
|
|
145
|
+
# Lazy reference an entity by its instance variable.
|
146
|
+
#
|
147
|
+
# @example
|
148
|
+
# lazy_ivar(:@variable)
|
149
|
+
#
|
150
|
+
# @param key [Symbol]
|
151
|
+
# @return [Proxy]
|
152
|
+
def lazy_ivar key
|
153
|
+
Proxy.new(:ivar, key)
|
154
|
+
end
|
155
|
+
alias _ivar lazy_ivar
|
156
|
+
|
157
|
+
# Lazy reference an entity by its attribute or method.
|
158
|
+
#
|
159
|
+
# @example
|
160
|
+
# lazy_attr(:method)
|
161
|
+
#
|
162
|
+
# @param key [Symbol]
|
163
|
+
# @return [Proxy]
|
164
|
+
def lazy_attr key
|
165
|
+
Proxy.new(:attr, key)
|
166
|
+
end
|
167
|
+
alias _attr lazy_attr
|
168
|
+
|
169
|
+
# Lazy reference an entity by its description.
|
170
|
+
#
|
171
|
+
# @example
|
172
|
+
# lazy_pick('the red box')
|
173
|
+
#
|
174
|
+
# @raise [RuntimeError] if a unique match could not be found.
|
175
|
+
#
|
176
|
+
# @param description [String]
|
177
|
+
# @return [Proxy]
|
178
|
+
def lazy_pick description
|
179
|
+
Proxy.new(:pick, description)
|
180
|
+
end
|
181
|
+
alias _pick lazy_pick
|
182
|
+
|
130
183
|
if RUBY_ENGINE == 'opal'
|
131
184
|
# :nocov:
|
132
185
|
def method_missing method, *args, &block
|
@@ -154,35 +207,13 @@ module Gamefic
|
|
154
207
|
# This can be useful when you need access to the Scriptable's constants and
|
155
208
|
# instance methods, but you don't want to duplicate its rules.
|
156
209
|
#
|
157
|
-
# @
|
158
|
-
#
|
159
|
-
# # only Plot will implement the `think` action.
|
210
|
+
# @deprecated Removing script blocks is no longer necessary. This method
|
211
|
+
# will simply return self until it's removed.
|
160
212
|
#
|
161
|
-
#
|
162
|
-
# extend Gamefic::Scriptable
|
163
|
-
#
|
164
|
-
# def info
|
165
|
-
# "This method was added by the Shared module."
|
166
|
-
# end
|
167
|
-
#
|
168
|
-
# respond :think do |actor|
|
169
|
-
# actor.tell 'You ponder your predicament.'
|
170
|
-
# end
|
171
|
-
# end
|
172
|
-
#
|
173
|
-
# class Plot < Gamefic::Plot
|
174
|
-
# include Shared
|
175
|
-
# end
|
176
|
-
#
|
177
|
-
# class Subplot < Gamefic::Subplot
|
178
|
-
# include Shared.no_scripts
|
179
|
-
# end
|
180
|
-
#
|
181
|
-
# @return [Module]
|
213
|
+
# @return [Module<self>]
|
182
214
|
def no_scripts
|
183
|
-
|
184
|
-
|
185
|
-
end
|
215
|
+
Logging.logger.warn 'Calling `no_scripts` on Scriptable modules is no longer necessary.'
|
216
|
+
self
|
186
217
|
end
|
187
218
|
end
|
188
219
|
end
|
data/lib/gamefic/stage.rb
CHANGED
@@ -14,7 +14,7 @@ module Gamefic
|
|
14
14
|
|
15
15
|
OVERWRITEABLE_CLASSES = [String, Numeric, Symbol].freeze
|
16
16
|
|
17
|
-
SWAPPABLE_VALUES = [true, false
|
17
|
+
SWAPPABLE_VALUES = [true, false].freeze
|
18
18
|
|
19
19
|
class << self
|
20
20
|
private
|
@@ -37,7 +37,7 @@ module Gamefic
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def overwriteable? cval, nval
|
40
|
-
return true if swappable?(cval, nval)
|
40
|
+
return true if cval.nil? || swappable?(cval, nval)
|
41
41
|
|
42
42
|
allowed = OVERWRITEABLE_CLASSES.find { |klass| cval.is_a?(klass) }
|
43
43
|
allowed && cval.is_a?(allowed)
|
data/lib/gamefic/subplot.rb
CHANGED
@@ -7,6 +7,8 @@ module Gamefic
|
|
7
7
|
# started and concluded at any time during the parent plot's runtime.
|
8
8
|
#
|
9
9
|
class Subplot < Narrative
|
10
|
+
extend Scriptable::PlotProxies
|
11
|
+
|
10
12
|
# @return [Hash]
|
11
13
|
attr_reader :config
|
12
14
|
|
@@ -22,7 +24,24 @@ module Gamefic
|
|
22
24
|
configure
|
23
25
|
@config.freeze
|
24
26
|
super()
|
25
|
-
|
27
|
+
@concluded = false
|
28
|
+
[introduce].flatten.each { |plyr| self.introduce plyr }
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.persist!
|
32
|
+
@persistent = true
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.persistent?
|
36
|
+
@persistent ||= false
|
37
|
+
end
|
38
|
+
|
39
|
+
def persistent?
|
40
|
+
self.class.persistent?
|
41
|
+
end
|
42
|
+
|
43
|
+
def included_blocks
|
44
|
+
super - plot.included_blocks
|
26
45
|
end
|
27
46
|
|
28
47
|
def ready
|
@@ -37,6 +56,7 @@ module Gamefic
|
|
37
56
|
uncast plyr
|
38
57
|
end
|
39
58
|
entities.each { |ent| destroy ent }
|
59
|
+
@concluded = true
|
40
60
|
end
|
41
61
|
|
42
62
|
# Make an entity that persists in the subplot's parent plot.
|
@@ -65,14 +85,18 @@ module Gamefic
|
|
65
85
|
#
|
66
86
|
def configure; end
|
67
87
|
|
68
|
-
def
|
69
|
-
|
88
|
+
def concluding?
|
89
|
+
return super unless persistent?
|
90
|
+
|
91
|
+
@concluded
|
70
92
|
end
|
71
93
|
|
72
|
-
def
|
73
|
-
@
|
74
|
-
|
75
|
-
|
94
|
+
def introduce player
|
95
|
+
@concluded ? player : super
|
96
|
+
end
|
97
|
+
|
98
|
+
def inspect
|
99
|
+
"#<#{self.class}>"
|
76
100
|
end
|
77
101
|
end
|
78
102
|
end
|
data/lib/gamefic/version.rb
CHANGED
data/lib/gamefic.rb
CHANGED
@@ -8,6 +8,7 @@ require 'gamefic/core_ext/string'
|
|
8
8
|
require 'gamefic/syntax'
|
9
9
|
require 'gamefic/response'
|
10
10
|
require 'gamefic/rulebook'
|
11
|
+
require 'gamefic/callback'
|
11
12
|
require 'gamefic/query'
|
12
13
|
require 'gamefic/scanner'
|
13
14
|
require 'gamefic/scope'
|
@@ -16,19 +17,20 @@ require 'gamefic/command'
|
|
16
17
|
require 'gamefic/action'
|
17
18
|
require 'gamefic/props'
|
18
19
|
require 'gamefic/scene'
|
20
|
+
require 'gamefic/proxy'
|
19
21
|
require 'gamefic/scriptable'
|
20
22
|
require 'gamefic/block'
|
21
23
|
require 'gamefic/stage'
|
22
24
|
require 'gamefic/vault'
|
23
25
|
require 'gamefic/narrative'
|
24
26
|
require 'gamefic/plot'
|
27
|
+
require 'gamefic/chapter'
|
25
28
|
require 'gamefic/subplot'
|
26
29
|
require 'gamefic/snapshot'
|
27
30
|
require 'gamefic/node'
|
28
31
|
require 'gamefic/describable'
|
29
32
|
require 'gamefic/messenger'
|
30
33
|
require 'gamefic/entity'
|
31
|
-
require 'gamefic/composer'
|
32
34
|
require 'gamefic/dispatcher'
|
33
35
|
require 'gamefic/active'
|
34
36
|
require 'gamefic/active/cue'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gamefic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fred Snyder
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: opal
|
@@ -135,8 +135,9 @@ files:
|
|
135
135
|
- lib/gamefic/active/take.rb
|
136
136
|
- lib/gamefic/actor.rb
|
137
137
|
- lib/gamefic/block.rb
|
138
|
+
- lib/gamefic/callback.rb
|
139
|
+
- lib/gamefic/chapter.rb
|
138
140
|
- lib/gamefic/command.rb
|
139
|
-
- lib/gamefic/composer.rb
|
140
141
|
- lib/gamefic/core_ext/array.rb
|
141
142
|
- lib/gamefic/core_ext/string.rb
|
142
143
|
- lib/gamefic/describable.rb
|
@@ -154,6 +155,7 @@ files:
|
|
154
155
|
- lib/gamefic/props/output.rb
|
155
156
|
- lib/gamefic/props/pause.rb
|
156
157
|
- lib/gamefic/props/yes_or_no.rb
|
158
|
+
- lib/gamefic/proxy.rb
|
157
159
|
- lib/gamefic/query.rb
|
158
160
|
- lib/gamefic/query/base.rb
|
159
161
|
- lib/gamefic/query/general.rb
|
@@ -167,6 +169,12 @@ files:
|
|
167
169
|
- lib/gamefic/rulebook/hooks.rb
|
168
170
|
- lib/gamefic/rulebook/scenes.rb
|
169
171
|
- lib/gamefic/scanner.rb
|
172
|
+
- lib/gamefic/scanner/base.rb
|
173
|
+
- lib/gamefic/scanner/fuzzy.rb
|
174
|
+
- lib/gamefic/scanner/fuzzy_nesting.rb
|
175
|
+
- lib/gamefic/scanner/nesting.rb
|
176
|
+
- lib/gamefic/scanner/result.rb
|
177
|
+
- lib/gamefic/scanner/strict.rb
|
170
178
|
- lib/gamefic/scene.rb
|
171
179
|
- lib/gamefic/scene/activity.rb
|
172
180
|
- lib/gamefic/scene/conclusion.rb
|
@@ -177,6 +185,7 @@ files:
|
|
177
185
|
- lib/gamefic/scope.rb
|
178
186
|
- lib/gamefic/scope/base.rb
|
179
187
|
- lib/gamefic/scope/children.rb
|
188
|
+
- lib/gamefic/scope/descendants.rb
|
180
189
|
- lib/gamefic/scope/family.rb
|
181
190
|
- lib/gamefic/scope/myself.rb
|
182
191
|
- lib/gamefic/scope/parent.rb
|
@@ -185,7 +194,8 @@ files:
|
|
185
194
|
- lib/gamefic/scriptable/actions.rb
|
186
195
|
- lib/gamefic/scriptable/entities.rb
|
187
196
|
- lib/gamefic/scriptable/events.rb
|
188
|
-
- lib/gamefic/scriptable/
|
197
|
+
- lib/gamefic/scriptable/plot_proxies.rb
|
198
|
+
- lib/gamefic/scriptable/proxies.rb
|
189
199
|
- lib/gamefic/scriptable/queries.rb
|
190
200
|
- lib/gamefic/scriptable/scenes.rb
|
191
201
|
- lib/gamefic/snapshot.rb
|
data/lib/gamefic/composer.rb
DELETED
@@ -1,70 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Gamefic
|
4
|
-
# A function module for creating commands from expressions.
|
5
|
-
#
|
6
|
-
module Composer
|
7
|
-
# Create a command from the first expression that matches a response.
|
8
|
-
#
|
9
|
-
# @param actor [Actor]
|
10
|
-
# @param expressions [Array<Expression>]
|
11
|
-
# @return [Command]
|
12
|
-
def self.compose actor, expressions
|
13
|
-
%i[strict fuzzy].each do |method|
|
14
|
-
result = match_expressions_to_response actor, expressions, method
|
15
|
-
return result if result
|
16
|
-
end
|
17
|
-
Command.new(nil, [])
|
18
|
-
end
|
19
|
-
|
20
|
-
class << self
|
21
|
-
private
|
22
|
-
|
23
|
-
def match_expressions_to_response actor, expressions, method
|
24
|
-
expressions.each do |expression|
|
25
|
-
result = match_response_arguments actor, expression, method
|
26
|
-
return result if result
|
27
|
-
end
|
28
|
-
nil
|
29
|
-
end
|
30
|
-
|
31
|
-
def match_response_arguments actor, expression, method
|
32
|
-
actor.epic.responses_for(expression.verb).each do |response|
|
33
|
-
next unless response.queries.length >= expression.tokens.length
|
34
|
-
|
35
|
-
result = match_query_arguments(actor, expression, response, method)
|
36
|
-
return result if result
|
37
|
-
end
|
38
|
-
nil
|
39
|
-
end
|
40
|
-
|
41
|
-
def match_query_arguments actor, expression, response, method
|
42
|
-
remainder = response.verb ? '' : expression.verb.to_s
|
43
|
-
arguments = []
|
44
|
-
response.queries.each_with_index do |query, idx|
|
45
|
-
result = Scanner.send(method, query.select(actor), "#{remainder} #{expression.tokens[idx]}".strip)
|
46
|
-
break unless valid_result_from_query?(result, query)
|
47
|
-
|
48
|
-
if query.ambiguous?
|
49
|
-
arguments.push result.matched
|
50
|
-
else
|
51
|
-
arguments.push result.matched.first
|
52
|
-
end
|
53
|
-
remainder = result.remainder
|
54
|
-
end
|
55
|
-
|
56
|
-
return nil if arguments.length != response.queries.length || remainder != ''
|
57
|
-
|
58
|
-
Command.new(response.verb, arguments)
|
59
|
-
end
|
60
|
-
|
61
|
-
# @param result [Scanner::Result]
|
62
|
-
# @param query [Query::Base]
|
63
|
-
def valid_result_from_query? result, query
|
64
|
-
return false if result.matched.empty?
|
65
|
-
|
66
|
-
result.matched.length == 1 || query.ambiguous?
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,69 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Gamefic
|
4
|
-
module Scriptable
|
5
|
-
# Functions that provide proxies for referencing a narrative's entities
|
6
|
-
# from class-level scripts.
|
7
|
-
#
|
8
|
-
module Proxy
|
9
|
-
# The object that fetches a proxied entity.
|
10
|
-
#
|
11
|
-
class Agent
|
12
|
-
attr_reader :symbol
|
13
|
-
|
14
|
-
# @param symbol [Symbol, Integer]
|
15
|
-
def initialize symbol
|
16
|
-
@symbol = symbol
|
17
|
-
end
|
18
|
-
|
19
|
-
def fetch container
|
20
|
-
result = safe_fetch(container)
|
21
|
-
raise ArgumentError, "Unable to fetch entity from proxy agent symbol `#{symbol}`" unless result
|
22
|
-
|
23
|
-
result
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def safe_fetch container
|
29
|
-
if symbol.to_s =~ /^\d+$/
|
30
|
-
Stage.run(container, symbol) { |sym| entities[sym] }
|
31
|
-
elsif symbol.to_s.start_with?('@')
|
32
|
-
Stage.run(container, symbol) { |sym| instance_variable_get(sym) }
|
33
|
-
else
|
34
|
-
Stage.run(container, symbol) { |sym| send(sym) }
|
35
|
-
end
|
36
|
-
rescue NoMethodError
|
37
|
-
nil
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
# Proxy a method or instance variable.
|
42
|
-
#
|
43
|
-
# @example
|
44
|
-
# proxy(:method_name)
|
45
|
-
# proxy(:@instance_variable_name)
|
46
|
-
#
|
47
|
-
# @param symbol [Symbol]
|
48
|
-
# @return [Agent]
|
49
|
-
def proxy symbol
|
50
|
-
Agent.new(symbol)
|
51
|
-
end
|
52
|
-
|
53
|
-
# @param object [Object]
|
54
|
-
# @return [Object]
|
55
|
-
def unproxy object
|
56
|
-
case object
|
57
|
-
when Agent
|
58
|
-
object.fetch self
|
59
|
-
when Array
|
60
|
-
object.map { |obj| unproxy obj }
|
61
|
-
when Hash
|
62
|
-
object.transform_values { |val| unproxy val }
|
63
|
-
else
|
64
|
-
object
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|