gamefic 3.3.0 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 85e6fc4d2b5c4a9abfe20cbbe17affdec1f1badb134e8cad88849a5305fb9bf0
4
- data.tar.gz: 97a29823857d93fafa9e8a3bc4872e27a4a6da480f589535da6abf254eb5aa7a
3
+ metadata.gz: 79b61813b56cbbabb76ecbef9abb370b2fe77b58ea3e155377f8c4dfd2677684
4
+ data.tar.gz: 611c108a0c080796c8308bee5f3e361c60fc4ddd316234bf9468c09742b1a52d
5
5
  SHA512:
6
- metadata.gz: 611c3b366e76a29cd2ffb95f906882a63ac9d73bfb6d1d7aaa505e4470f4526311704c2245285f908247b6248b086914d8a145e1c9b86577e197d8d77c707939
7
- data.tar.gz: dc19cf51ab4edbc1b9f9708eb543c977527e3165a949d948782349e545d0a32fde42f8532c9071e0ddc86b521cc0d1cb778e8e88b1d7b0dcc575d547c5db1df1
6
+ metadata.gz: 85732c76dae467bd5d032462ca23d34b03b7be59c6327202fd9bef307ef3d06bc40af085f32010cfae9dfd93a85b20524785313388964772534632cc95159625
7
+ data.tar.gz: 5c3db85ff44b268bd7604d33e28b92ca454c82c2a812f023af39a3da816a4252dfea01869d313f1ab6d24a1f062782ac002f5bf8fc40fd435efaa0c1ac14d337
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 3.4.0 - September 10, 2024
2
+ - Chapters
3
+ - Subplots and chapters do not repeat plot scripts
4
+ - Scriptable.no_scripts is deprecated
5
+ - Refactoring/removing unused methods
6
+
1
7
  ## 3.3.0 - September 1, 2024
2
8
  - Node#take
3
9
  - Node#include?
@@ -16,12 +16,12 @@ module Gamefic
16
16
  # @param [Array<Symbol>]
17
17
  attr_reader :verbs
18
18
 
19
- # @param [Proc]
20
- attr_reader :block
19
+ # @param [Callback]
20
+ attr_reader :callback
21
21
 
22
- def initialize *verbs, &block
22
+ def initialize verbs, callback
23
23
  @verbs = verbs
24
- @block = block
24
+ @callback = callback
25
25
  end
26
26
 
27
27
  def match?(input)
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ class Callback
5
+ # @param narrative [Narrative]
6
+ # @param code [Proc]
7
+ def initialize narrative, code
8
+ @narrative = narrative
9
+ @code = code
10
+ end
11
+
12
+ def run *args
13
+ Stage.run @narrative, *args, &@code
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ # Chapters are plot extensions that manage their own namespaces. Authors can
5
+ # use them to encapsulate related content in a separate object instead of
6
+ # adding the required instance variables, methods, and attributes to the
7
+ # plot.
8
+ #
9
+ # Chapters are similar to subplots with a few important exceptions:
10
+ # * Chapters persist for the duration of the plot.
11
+ # * Players do not need to be introduced to a chapter.
12
+ # * Scripts in chapters apply to the parent plot's rulebook.
13
+ # * Using `make` to create an entity in a chapter adds it to the parent
14
+ # plot's entity list.
15
+ #
16
+ # @example
17
+ # class MyChapter < Gamefic::Chapter
18
+ # seed do
19
+ # @thing = make Gamefic::Entity, name: 'chapter thing'
20
+ # end
21
+ # end
22
+ #
23
+ # class MyPlot < Gamefic::Plot
24
+ # append MyChapter
25
+ # end
26
+ #
27
+ # plot = MyPlot.new
28
+ # plot.entities #=> [<#Gamefic::Entity a chapter thing>]
29
+ # plot.instance_exec { @thing } #=> nil
30
+ #
31
+ class Chapter
32
+ extend Scriptable
33
+
34
+ include Scriptable::Actions
35
+ include Scriptable::Events
36
+ include Scriptable::Proxy
37
+ include Scriptable::Queries
38
+ include Scriptable::Scenes
39
+
40
+ # @return [Plot]
41
+ attr_reader :plot
42
+
43
+ # @param plot [Plot]
44
+ def initialize plot
45
+ @plot = plot
46
+ end
47
+
48
+ def included_blocks
49
+ self.class.included_blocks - plot.included_blocks
50
+ end
51
+
52
+ def seed
53
+ included_blocks.select(&:seed?).each { |blk| Stage.run self, &blk.code }
54
+ end
55
+
56
+ def script
57
+ included_blocks.select(&:script?).each { |blk| Stage.run self, &blk.code }
58
+ end
59
+
60
+ def rulebook
61
+ plot.rulebook
62
+ end
63
+
64
+ def make klass, **opts
65
+ plot.make klass, **opts
66
+ end
67
+
68
+ def entities
69
+ plot.entities
70
+ end
71
+
72
+ def players
73
+ plot.players
74
+ end
75
+
76
+ def destroy entity
77
+ plot.destroy entity
78
+ end
79
+
80
+ def pick description
81
+ plot.pick description
82
+ end
83
+
84
+ def pick! description
85
+ plot.pick! description
86
+ end
87
+ end
88
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'set'
4
+
3
5
  module Gamefic
4
6
  # A base class for building and managing the resources that compose a story.
5
7
  # The Plot and Subplot classes inherit from Narrative and provide additional
@@ -19,10 +21,27 @@ module Gamefic
19
21
  attr_reader :rulebook
20
22
 
21
23
  def initialize
22
- self.class.included_blocks.select(&:seed?).each { |blk| Stage.run self, &blk.code }
24
+ seed
25
+ script
26
+ post_initialize
27
+ end
28
+
29
+ def seed
30
+ included_blocks.select(&:seed?).each { |blk| Stage.run self, &blk.code }
31
+ end
32
+
33
+ def script
34
+ @rulebook = Rulebook.new
35
+ included_blocks.select(&:script?).each { |blk| Stage.run self, &blk.code }
36
+ end
37
+
38
+ def included_blocks
39
+ self.class.included_blocks
40
+ end
41
+
42
+ def post_initialize
23
43
  entity_vault.lock
24
- @rulebook = nil
25
- hydrate
44
+ rulebook.freeze
26
45
  end
27
46
 
28
47
  def scenes
@@ -91,9 +110,8 @@ module Gamefic
91
110
  end
92
111
 
93
112
  def hydrate
94
- @rulebook = Rulebook.new(self)
95
- @rulebook.script_with_defaults
96
- @rulebook.freeze
113
+ script
114
+ post_initialize
97
115
  end
98
116
 
99
117
  def self.inherited klass
data/lib/gamefic/plot.rb CHANGED
@@ -5,12 +5,26 @@ module Gamefic
5
5
  # methods for creating entities, actions, scenes, and hooks.
6
6
  #
7
7
  class Plot < Narrative
8
+ def seed
9
+ super
10
+ chapters.each(&:seed)
11
+ end
12
+
13
+ def script
14
+ super
15
+ chapters.each(&:script)
16
+ rulebook.scenes.with_defaults self
17
+ end
18
+
19
+ def chapters
20
+ @chapters ||= self.class.appended_chapters.map { |klass| klass.new(self) }
21
+ end
22
+
8
23
  def ready
9
24
  super
10
25
  subplots.each(&:ready)
11
26
  players.each(&:start_take)
12
27
  subplots.each(&:conclude) if concluding?
13
-
14
28
  players.select(&:concluding?).each { |plyr| rulebook.run_player_conclude_blocks plyr }
15
29
  subplots.delete_if(&:concluding?)
16
30
  end
@@ -76,6 +90,14 @@ module Gamefic
76
90
  subplots.each(&:hydrate)
77
91
  end
78
92
 
93
+ def self.append chapter
94
+ appended_chapters.add chapter
95
+ end
96
+
97
+ def self.appended_chapters
98
+ @appended_chapters ||= Set.new
99
+ end
100
+
79
101
  def self.restore data
80
102
  Snapshot.restore data
81
103
  end
@@ -11,9 +11,6 @@ module Gamefic
11
11
  # @return [Array<Query::Base>]
12
12
  attr_reader :queries
13
13
 
14
- # @return [Narrative]
15
- attr_reader :narrative
16
-
17
14
  # @param verb [Symbol]
18
15
  # @param narrative [Narrative]
19
16
  # @param queries [Array<Query::Base>]
@@ -21,10 +18,10 @@ module Gamefic
21
18
  # @param block [Proc]
22
19
  def initialize verb, narrative, *queries, meta: false, &block
23
20
  @verb = verb
24
- @narrative = narrative
25
21
  @queries = map_queryable_objects(queries)
26
22
  @meta = meta
27
23
  @block = block
24
+ @callback = Callback.new(narrative, block)
28
25
  end
29
26
 
30
27
  # The `meta?` flag is just a way for authors to identify responses that
@@ -70,7 +67,7 @@ module Gamefic
70
67
  end
71
68
 
72
69
  def execute *args
73
- Stage.run(narrative, *args, &@block)
70
+ @callback.run *args
74
71
  end
75
72
 
76
73
  def precision
@@ -67,10 +67,6 @@ module Gamefic
67
67
  verb_response_map.empty? && synonym_syntax_map.empty?
68
68
  end
69
69
 
70
- def self.new_array_map
71
- Hash.new { |hash, key| hash[key] = [] }
72
- end
73
-
74
70
  private
75
71
 
76
72
  attr_reader :verb_response_map
@@ -35,44 +35,30 @@ module Gamefic
35
35
  end
36
36
 
37
37
  # @return [void]
38
- def on_ready &block
39
- @ready_blocks.push block
38
+ def on_ready callback
39
+ @ready_blocks.push callback
40
40
  end
41
41
 
42
- # @yieldparam [Actor]
43
- # @return [void]
44
- def on_player_ready &block
45
- @ready_blocks.push(proc do
46
- players.each { |plyr| instance_exec plyr, &block }
47
- end)
48
- end
49
-
50
- def on_update &block
51
- @update_blocks.push block
52
- end
53
-
54
- def on_player_update &block
55
- @update_blocks.push(proc do
56
- players.each { |plyr| instance_exec plyr, &block }
57
- end)
42
+ def on_update callback
43
+ @update_blocks.push callback
58
44
  end
59
45
 
60
46
  # @return [void]
61
- def on_conclude &block
62
- @conclude_blocks.push block
47
+ def on_conclude callback
48
+ @conclude_blocks.push callback
63
49
  end
64
50
 
65
51
  # @yieldparam [Actor]
66
52
  # @return [void]
67
- def on_player_conclude &block
68
- @player_conclude_blocks.push block
53
+ def on_player_conclude callback
54
+ @player_conclude_blocks.push callback
69
55
  end
70
56
 
71
57
  # @yieldparam [Actor]
72
58
  # @yieldparam [Hash]
73
59
  # @return [void]
74
- def on_player_output &block
75
- @player_output_blocks.push block
60
+ def on_player_output callback
61
+ @player_output_blocks.push callback
76
62
  end
77
63
  end
78
64
  end
@@ -21,35 +21,35 @@ module Gamefic
21
21
  self
22
22
  end
23
23
 
24
- def before_action *verbs, &block
25
- before_actions.push Action::Hook.new(*verbs, &block)
24
+ def before_action narrative, *verbs, &block
25
+ before_actions.push Action::Hook.new(verbs, Callback.new(narrative, block))
26
26
  end
27
27
 
28
- def after_action *verbs, &block
29
- after_actions.push Action::Hook.new(*verbs, &block)
28
+ def after_action narrative, *verbs, &block
29
+ after_actions.push Action::Hook.new(verbs, Callback.new(narrative, block))
30
30
  end
31
31
 
32
32
  def empty?
33
33
  before_actions.empty? && after_actions.empty?
34
34
  end
35
35
 
36
- def run_before action, narrative
37
- run_action_hooks action, narrative, before_actions
36
+ def run_before action
37
+ run_action_hooks action, before_actions
38
38
  end
39
39
 
40
- def run_after action, narrative
41
- run_action_hooks action, narrative, after_actions
40
+ def run_after action
41
+ run_action_hooks action, after_actions
42
42
  end
43
43
 
44
44
  private
45
45
 
46
- def run_action_hooks action, narrative, hooks
46
+ def run_action_hooks action, hooks
47
47
  hooks.each do |hook|
48
48
  break if action.cancelled?
49
49
 
50
50
  next unless hook.match?(action.verb)
51
51
 
52
- Stage.run(narrative) { instance_exec(action, &hook.block) }
52
+ hook.callback.run action
53
53
  end
54
54
  end
55
55
  end
@@ -25,12 +25,7 @@ module Gamefic
25
25
  # @return [Scenes]
26
26
  attr_reader :scenes
27
27
 
28
- # @return [Narrative]
29
- attr_reader :narrative
30
-
31
- # @param narrative [Narrative]
32
- def initialize(narrative)
33
- @narrative = narrative
28
+ def initialize
34
29
  @calls = Calls.new
35
30
  @events = Events.new
36
31
  @hooks = Hooks.new
@@ -96,44 +91,35 @@ module Gamefic
96
91
  end
97
92
 
98
93
  def run_ready_blocks
99
- events.ready_blocks.each { |blk| Stage.run narrative, &blk }
94
+ events.ready_blocks.each(&:run)
100
95
  end
101
96
 
102
97
  def run_update_blocks
103
- events.update_blocks.each { |blk| Stage.run narrative, &blk }
98
+ events.update_blocks.each(&:run)
104
99
  end
105
100
 
106
101
  def run_before_actions action
107
- hooks.run_before action, narrative
102
+ hooks.run_before action
108
103
  end
109
104
 
110
105
  def run_after_actions action
111
- hooks.run_after action, narrative
106
+ hooks.run_after action
112
107
  end
113
108
 
114
109
  def run_conclude_blocks
115
- events.conclude_blocks.each { |blk| Stage.run narrative, &blk }
110
+ events.conclude_blocks.each(&:run)
116
111
  end
117
112
 
118
113
  def run_player_conclude_blocks player
119
- events.player_conclude_blocks.each { |blk| Stage.run(narrative, player, &blk) }
114
+ events.player_conclude_blocks.each { |blk| blk.run(player) }
120
115
  end
121
116
 
122
117
  def run_player_output_blocks player, output
123
- events.player_output_blocks.each { |blk| Stage.run(narrative, player, output, &blk) }
118
+ events.player_output_blocks.each { |blk| blk.run(player, output) }
124
119
  end
125
120
 
126
121
  def empty?
127
122
  calls.empty? && hooks.empty? && scenes.empty? && events.empty?
128
123
  end
129
-
130
- def script
131
- narrative.class.included_blocks.select(&:script?).each { |blk| Stage.run(narrative, &blk.code) }
132
- end
133
-
134
- def script_with_defaults
135
- script
136
- scenes.with_defaults narrative
137
- end
138
124
  end
139
125
  end
@@ -31,7 +31,7 @@ module Gamefic
31
31
  # @return [Symbol]
32
32
  def respond(verb, *queries, &proc)
33
33
  args = map_response_args(queries)
34
- rulebook.calls.add_response Response.new(verb, rulebook.narrative, *args, &proc)
34
+ rulebook.calls.add_response Response.new(verb, self, *args, &proc)
35
35
  verb
36
36
  end
37
37
 
@@ -52,7 +52,7 @@ module Gamefic
52
52
  # @return [Symbol]
53
53
  def meta(verb, *queries, &proc)
54
54
  args = map_response_args(queries)
55
- rulebook.calls.add_response Response.new(verb, rulebook.narrative, *args, meta: true, &proc)
55
+ rulebook.calls.add_response Response.new(verb, self, *args, meta: true, &proc)
56
56
  verb
57
57
  end
58
58
 
@@ -64,7 +64,7 @@ module Gamefic
64
64
  # @yieldparam [Gamefic::Action]
65
65
  # @return [Action::Hook]
66
66
  def before_action *verbs, &block
67
- rulebook.hooks.before_action *verbs, &block
67
+ rulebook.hooks.before_action self, *verbs, &block
68
68
  end
69
69
 
70
70
  # Add a proc to be evaluated after a character executes an action.
@@ -75,7 +75,7 @@ module Gamefic
75
75
  # @yieldparam [Gamefic::Action]
76
76
  # @return [Action::Hook]
77
77
  def after_action *verbs, &block
78
- rulebook.hooks.after_action *verbs, &block
78
+ rulebook.hooks.after_action self, *verbs, &block
79
79
  end
80
80
 
81
81
  # Create an alternate Syntax for a response.
@@ -14,7 +14,7 @@ module Gamefic
14
14
  # end
15
15
  #
16
16
  def on_ready &block
17
- rulebook.events.on_ready(&block)
17
+ rulebook.events.on_ready(Callback.new(self, block))
18
18
  end
19
19
 
20
20
  # Add a block to be executed for each player at the beginning of a turn.
@@ -28,37 +28,43 @@ module Gamefic
28
28
  #
29
29
  # @yieldparam [Gamefic::Actor]
30
30
  def on_player_ready &block
31
- rulebook.events.on_player_ready(&block)
31
+ wrapper = proc do
32
+ players.each { |player| Stage.run(self, player, &block) }
33
+ end
34
+ on_ready &wrapper
32
35
  end
33
36
 
34
37
  # Add a block to be executed after the Plot is finished updating a turn.
35
38
  #
36
39
  def on_update &block
37
- rulebook.events.on_update(&block)
40
+ rulebook.events.on_update(Callback.new(self, block))
38
41
  end
39
42
 
40
43
  # Add a block to be executed for each player at the end of a turn.
41
44
  #
42
45
  # @yieldparam [Gamefic::Actor]
43
46
  def on_player_update &block
44
- rulebook.events.on_player_update(&block)
47
+ wrapper = proc do
48
+ players.each { |player| Stage.run(self, player, &block) }
49
+ end
50
+ on_update &wrapper
45
51
  end
46
52
 
47
53
  def on_conclude &block
48
- rulebook.events.on_conclude(&block)
54
+ rulebook.events.on_conclude(Callback.new(self, block))
49
55
  end
50
56
 
51
57
  # @yieldparam [Actor]
52
58
  # @return [Proc]
53
59
  def on_player_conclude &block
54
- rulebook.events.on_player_conclude(&block)
60
+ rulebook.events.on_player_conclude(Callback.new(self, block))
55
61
  end
56
62
 
57
63
  # @yieldparam [Actor]
58
64
  # @yieldparam [Hash]
59
65
  # @return [Proc]
60
66
  def on_player_output &block
61
- rulebook.events.on_player_output(&block)
67
+ rulebook.events.on_player_output Callback.new(self, block)
62
68
  end
63
69
  end
64
70
  end
@@ -33,13 +33,13 @@ module Gamefic
33
33
  # @yieldparam [Scene]
34
34
  # @return [Symbol]
35
35
  def block name, klass = Scene::Default, on_start: nil, on_finish: nil, &blk
36
- rulebook.scenes.add klass.new(name, rulebook.narrative, on_start: on_start, on_finish: on_finish, &blk)
36
+ rulebook.scenes.add klass.new(name, self, on_start: on_start, on_finish: on_finish, &blk)
37
37
  name
38
38
  end
39
39
  alias scene block
40
40
 
41
41
  def preface name, klass = Scene::Activity, &start
42
- rulebook.scenes.add klass.new(name, rulebook.narrative, on_start: start)
42
+ rulebook.scenes.add klass.new(name, self, on_start: start)
43
43
  name
44
44
  end
45
45
  alias precursor preface
@@ -60,7 +60,7 @@ module Gamefic
60
60
  def introduction(&start)
61
61
  rulebook.scenes
62
62
  .introduction Scene::Default.new nil,
63
- rulebook.narrative,
63
+ self,
64
64
  on_start: proc { |actor, _props| Stage.run(self, actor, &start) }
65
65
  end
66
66
 
@@ -117,6 +117,7 @@ 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>]
121
122
  def attr_seed name, klass, **opts
122
123
  @count ||= 0
@@ -154,35 +155,13 @@ module Gamefic
154
155
  # This can be useful when you need access to the Scriptable's constants and
155
156
  # instance methods, but you don't want to duplicate its rules.
156
157
  #
157
- # @example
158
- # # Plot and Subplot will both include the `info` method, but
159
- # # only Plot will implement the `think` action.
160
- #
161
- # module Shared
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
158
+ # @deprecated Removing script blocks is no longer necessary. This method
159
+ # will simply return self until it's removed.
172
160
  #
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]
161
+ # @return [Module<self>]
182
162
  def no_scripts
183
- Module.new.tap do |mod|
184
- append_features(mod)
185
- end
163
+ Logging.logger.warn 'Calling `no_scripts` on Scriptable modules is no longer necessary.'
164
+ self
186
165
  end
187
166
  end
188
167
  end
@@ -25,6 +25,10 @@ module Gamefic
25
25
  [introduce].flatten.each { |pl| self.introduce pl }
26
26
  end
27
27
 
28
+ def included_blocks
29
+ super - plot.included_blocks
30
+ end
31
+
28
32
  def ready
29
33
  super
30
34
  conclude if concluding?
@@ -68,11 +72,5 @@ module Gamefic
68
72
  def inspect
69
73
  "#<#{self.class}>"
70
74
  end
71
-
72
- def hydrate
73
- @rulebook = Rulebook.new(self)
74
- @rulebook.script
75
- @rulebook.freeze
76
- end
77
75
  end
78
76
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Gamefic
4
- VERSION = '3.3.0'
4
+ VERSION = '3.4.0'
5
5
  end
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'
@@ -22,6 +23,7 @@ require 'gamefic/stage'
22
23
  require 'gamefic/vault'
23
24
  require 'gamefic/narrative'
24
25
  require 'gamefic/plot'
26
+ require 'gamefic/chapter'
25
27
  require 'gamefic/subplot'
26
28
  require 'gamefic/snapshot'
27
29
  require 'gamefic/node'
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.3.0
4
+ version: 3.4.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-09-01 00:00:00.000000000 Z
11
+ date: 2024-09-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opal
@@ -135,6 +135,8 @@ 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
141
  - lib/gamefic/composer.rb
140
142
  - lib/gamefic/core_ext/array.rb