gamefic 3.2.1 → 3.4.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/.github/workflows/rspec.yml +1 -1
- data/CHANGELOG.md +14 -0
- data/Rakefile +4 -4
- data/lib/gamefic/action.rb +4 -4
- data/lib/gamefic/active/messaging.rb +1 -0
- data/lib/gamefic/callback.rb +16 -0
- data/lib/gamefic/chapter.rb +88 -0
- data/lib/gamefic/composer.rb +2 -2
- data/lib/gamefic/describable.rb +3 -2
- data/lib/gamefic/narrative.rb +24 -6
- data/lib/gamefic/node.rb +14 -1
- data/lib/gamefic/plot.rb +24 -0
- data/lib/gamefic/query/base.rb +17 -7
- data/lib/gamefic/query/scoped.rb +0 -1
- data/lib/gamefic/query/text.rb +2 -0
- data/lib/gamefic/response.rb +2 -5
- 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/scriptable/actions.rb +4 -4
- data/lib/gamefic/scriptable/events.rb +13 -7
- data/lib/gamefic/scriptable/proxy.rb +1 -0
- data/lib/gamefic/scriptable/scenes.rb +9 -3
- data/lib/gamefic/scriptable.rb +6 -27
- data/lib/gamefic/subplot.rb +4 -6
- data/lib/gamefic/version.rb +1 -1
- data/lib/gamefic.rb +2 -0
- metadata +4 -3
- data/spec-opal/spec_helper.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 79b61813b56cbbabb76ecbef9abb370b2fe77b58ea3e155377f8c4dfd2677684
|
4
|
+
data.tar.gz: 611c108a0c080796c8308bee5f3e361c60fc4ddd316234bf9468c09742b1a52d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85732c76dae467bd5d032462ca23d34b03b7be59c6327202fd9bef307ef3d06bc40af085f32010cfae9dfd93a85b20524785313388964772534632cc95159625
|
7
|
+
data.tar.gz: 5c3db85ff44b268bd7604d33e28b92ca454c82c2a812f023af39a3da816a4252dfea01869d313f1ab6d24a1f062782ac002f5bf8fc40fd435efaa0c1ac14d337
|
data/.github/workflows/rspec.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
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
|
+
|
7
|
+
## 3.3.0 - September 1, 2024
|
8
|
+
- Node#take
|
9
|
+
- Node#include?
|
10
|
+
- Reject non-string tokens in Text queries
|
11
|
+
|
12
|
+
## 3.2.2 - July 21, 2024
|
13
|
+
- Describable#described?
|
14
|
+
|
1
15
|
## 3.2.1 - July 1, 2024
|
2
16
|
- MultipleChoice accepts shortened text
|
3
17
|
- Return Proxy::Agent from attr_seed and make_seed
|
data/Rakefile
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require "rspec/core/rake_task"
|
3
|
+
require 'bundler/gem_tasks'
|
5
4
|
require 'rspec/core/rake_task'
|
6
5
|
require 'opal/rspec/rake_task'
|
7
6
|
|
@@ -14,7 +13,8 @@ end
|
|
14
13
|
task :default => :spec
|
15
14
|
|
16
15
|
Opal::RSpec::RakeTask.new(:opal) do |_, config|
|
17
|
-
Opal.append_path File.
|
16
|
+
Opal.append_path File.join(__dir__, 'lib')
|
17
|
+
config.default_path = 'spec'
|
18
18
|
config.pattern = 'spec/**/*_spec.rb'
|
19
|
-
config.requires = ['
|
19
|
+
config.requires = ['opal_helper']
|
20
20
|
end
|
data/lib/gamefic/action.rb
CHANGED
@@ -16,12 +16,12 @@ module Gamefic
|
|
16
16
|
# @param [Array<Symbol>]
|
17
17
|
attr_reader :verbs
|
18
18
|
|
19
|
-
# @param [
|
20
|
-
attr_reader :
|
19
|
+
# @param [Callback]
|
20
|
+
attr_reader :callback
|
21
21
|
|
22
|
-
def initialize
|
22
|
+
def initialize verbs, callback
|
23
23
|
@verbs = verbs
|
24
|
-
@
|
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
|
data/lib/gamefic/composer.rb
CHANGED
@@ -43,7 +43,7 @@ module Gamefic
|
|
43
43
|
arguments = []
|
44
44
|
response.queries.each_with_index do |query, idx|
|
45
45
|
result = Scanner.send(method, query.select(actor), "#{remainder} #{expression.tokens[idx]}".strip)
|
46
|
-
break unless
|
46
|
+
break unless valid_result_from_query?(result, query)
|
47
47
|
|
48
48
|
if query.ambiguous?
|
49
49
|
arguments.push result.matched
|
@@ -60,7 +60,7 @@ module Gamefic
|
|
60
60
|
|
61
61
|
# @param result [Scanner::Result]
|
62
62
|
# @param query [Query::Base]
|
63
|
-
def
|
63
|
+
def valid_result_from_query? result, query
|
64
64
|
return false if result.matched.empty?
|
65
65
|
|
66
66
|
result.matched.length == 1 || query.ambiguous?
|
data/lib/gamefic/describable.rb
CHANGED
@@ -112,10 +112,11 @@ module Gamefic
|
|
112
112
|
# Does the object have a description?
|
113
113
|
#
|
114
114
|
# @return [Boolean]
|
115
|
-
def
|
115
|
+
def described?
|
116
116
|
@description.to_s != ''
|
117
117
|
end
|
118
|
-
alias
|
118
|
+
alias description? described?
|
119
|
+
alias has_description? described?
|
119
120
|
|
120
121
|
# Get the object's description.
|
121
122
|
#
|
data/lib/gamefic/narrative.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
95
|
-
|
96
|
-
@rulebook.freeze
|
113
|
+
script
|
114
|
+
post_initialize
|
97
115
|
end
|
98
116
|
|
99
117
|
def self.inherited klass
|
data/lib/gamefic/node.rb
CHANGED
@@ -42,6 +42,15 @@ module Gamefic
|
|
42
42
|
parent&.add_child self
|
43
43
|
end
|
44
44
|
|
45
|
+
# Add children to the node. Return all the node's children.
|
46
|
+
#
|
47
|
+
# @param children [Array<Node, Array<Node>>]
|
48
|
+
# @return [Array<Node>]
|
49
|
+
def take *children
|
50
|
+
children.flatten.each { |child| child.parent = self }
|
51
|
+
children
|
52
|
+
end
|
53
|
+
|
45
54
|
# Determine if external objects can interact with this object's children.
|
46
55
|
# For example, a game can designate that the contents of a bowl are
|
47
56
|
# accessible, while the contents of a locked safe are not.
|
@@ -54,10 +63,14 @@ module Gamefic
|
|
54
63
|
# True if this node is the other's parent.
|
55
64
|
#
|
56
65
|
# @param other [Node]
|
57
|
-
def
|
66
|
+
def include?(other)
|
58
67
|
other.parent == self
|
59
68
|
end
|
60
69
|
|
70
|
+
def adjacent?(other)
|
71
|
+
other.parent == parent
|
72
|
+
end
|
73
|
+
|
61
74
|
protected
|
62
75
|
|
63
76
|
def add_child(node)
|
data/lib/gamefic/plot.rb
CHANGED
@@ -5,10 +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)
|
27
|
+
subplots.each(&:conclude) if concluding?
|
12
28
|
players.select(&:concluding?).each { |plyr| rulebook.run_player_conclude_blocks plyr }
|
13
29
|
subplots.delete_if(&:concluding?)
|
14
30
|
end
|
@@ -74,6 +90,14 @@ module Gamefic
|
|
74
90
|
subplots.each(&:hydrate)
|
75
91
|
end
|
76
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
|
+
|
77
101
|
def self.restore data
|
78
102
|
Snapshot.restore data
|
79
103
|
end
|
data/lib/gamefic/query/base.rb
CHANGED
@@ -24,16 +24,24 @@ module Gamefic
|
|
24
24
|
@ambiguous = ambiguous
|
25
25
|
end
|
26
26
|
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
27
|
+
# Get a query result for a given subject and token.
|
28
|
+
#
|
29
|
+
# @note This method is retained as a convenience for authors. Narratives
|
30
|
+
# should use Composer to build commands, as it provides more precise
|
31
|
+
# matching of tokens to valid response arguments. Authors can use
|
32
|
+
# #query to find entities that match a token regardless of whether the
|
33
|
+
# result matches an available response.
|
34
|
+
#
|
35
|
+
# @example
|
36
|
+
# respond :reds do |actor|
|
37
|
+
# reds = available(ambiguous: true).query(actor, 'red').match
|
38
|
+
# actor.tell "The red things you can see here are #{reds.join_and}."
|
39
|
+
# end
|
32
40
|
#
|
33
41
|
# @param subject [Gamefic::Entity]
|
34
42
|
# @param token [String]
|
35
43
|
# @return [Result]
|
36
|
-
def query(
|
44
|
+
def query(_subject, _token)
|
37
45
|
raise "#query not implemented for #{self.class}"
|
38
46
|
end
|
39
47
|
|
@@ -42,7 +50,7 @@ module Gamefic
|
|
42
50
|
#
|
43
51
|
# @param subject [Entity]
|
44
52
|
# @return [Array<Entity>]
|
45
|
-
def select
|
53
|
+
def select _subject
|
46
54
|
raise "#select not implemented for #{self.class}"
|
47
55
|
end
|
48
56
|
|
@@ -88,12 +96,14 @@ module Gamefic
|
|
88
96
|
depth
|
89
97
|
end
|
90
98
|
|
99
|
+
# @param scan [Scanner::Result]
|
91
100
|
def ambiguous_result scan
|
92
101
|
return Result.new(nil, scan.token) if scan.matched.empty?
|
93
102
|
|
94
103
|
Result.new(scan.matched, scan.remainder)
|
95
104
|
end
|
96
105
|
|
106
|
+
# @param scan [Scanner::Result]
|
97
107
|
def unambiguous_result scan
|
98
108
|
return Result.new(nil, scan.token) unless scan.matched.one?
|
99
109
|
|
data/lib/gamefic/query/scoped.rb
CHANGED
data/lib/gamefic/query/text.rb
CHANGED
data/lib/gamefic/response.rb
CHANGED
@@ -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
|
-
|
70
|
+
@callback.run *args
|
74
71
|
end
|
75
72
|
|
76
73
|
def precision
|
@@ -35,44 +35,30 @@ module Gamefic
|
|
35
35
|
end
|
36
36
|
|
37
37
|
# @return [void]
|
38
|
-
def on_ready
|
39
|
-
@ready_blocks.push
|
38
|
+
def on_ready callback
|
39
|
+
@ready_blocks.push callback
|
40
40
|
end
|
41
41
|
|
42
|
-
|
43
|
-
|
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
|
62
|
-
@conclude_blocks.push
|
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
|
68
|
-
@player_conclude_blocks.push
|
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
|
75
|
-
@player_output_blocks.push
|
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(
|
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(
|
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
|
37
|
-
run_action_hooks action,
|
36
|
+
def run_before action
|
37
|
+
run_action_hooks action, before_actions
|
38
38
|
end
|
39
39
|
|
40
|
-
def run_after action
|
41
|
-
run_action_hooks action,
|
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,
|
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
|
-
|
52
|
+
hook.callback.run action
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
data/lib/gamefic/rulebook.rb
CHANGED
@@ -25,12 +25,7 @@ module Gamefic
|
|
25
25
|
# @return [Scenes]
|
26
26
|
attr_reader :scenes
|
27
27
|
|
28
|
-
|
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
|
94
|
+
events.ready_blocks.each(&:run)
|
100
95
|
end
|
101
96
|
|
102
97
|
def run_update_blocks
|
103
|
-
events.update_blocks.each
|
98
|
+
events.update_blocks.each(&:run)
|
104
99
|
end
|
105
100
|
|
106
101
|
def run_before_actions action
|
107
|
-
hooks.run_before action
|
102
|
+
hooks.run_before action
|
108
103
|
end
|
109
104
|
|
110
105
|
def run_after_actions action
|
111
|
-
hooks.run_after action
|
106
|
+
hooks.run_after action
|
112
107
|
end
|
113
108
|
|
114
109
|
def run_conclude_blocks
|
115
|
-
events.conclude_blocks.each
|
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|
|
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|
|
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,
|
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,
|
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(
|
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
|
-
|
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(
|
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
|
-
|
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(
|
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(
|
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(
|
67
|
+
rulebook.events.on_player_output Callback.new(self, block)
|
62
68
|
end
|
63
69
|
end
|
64
70
|
end
|
@@ -33,11 +33,17 @@ 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,
|
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
|
+
def preface name, klass = Scene::Activity, &start
|
42
|
+
rulebook.scenes.add klass.new(name, self, on_start: start)
|
43
|
+
name
|
44
|
+
end
|
45
|
+
alias precursor preface
|
46
|
+
|
41
47
|
# Add a block to be executed when a player is added to the game.
|
42
48
|
# Each Plot should only have one introduction.
|
43
49
|
#
|
@@ -54,8 +60,8 @@ module Gamefic
|
|
54
60
|
def introduction(&start)
|
55
61
|
rulebook.scenes
|
56
62
|
.introduction Scene::Default.new nil,
|
57
|
-
|
58
|
-
on_start: proc { |actor, _props|
|
63
|
+
self,
|
64
|
+
on_start: proc { |actor, _props| Stage.run(self, actor, &start) }
|
59
65
|
end
|
60
66
|
|
61
67
|
# Create a multiple-choice scene.
|
data/lib/gamefic/scriptable.rb
CHANGED
@@ -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
|
-
# @
|
158
|
-
#
|
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
|
-
#
|
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
|
-
|
184
|
-
|
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
|
data/lib/gamefic/subplot.rb
CHANGED
@@ -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
|
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'
|
@@ -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.
|
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-
|
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
|
@@ -195,7 +197,6 @@ files:
|
|
195
197
|
- lib/gamefic/syntax/template.rb
|
196
198
|
- lib/gamefic/vault.rb
|
197
199
|
- lib/gamefic/version.rb
|
198
|
-
- spec-opal/spec_helper.rb
|
199
200
|
homepage: https://gamefic.com
|
200
201
|
licenses:
|
201
202
|
- MIT
|
data/spec-opal/spec_helper.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'gamefic'
|
4
|
-
require 'ostruct'
|
5
|
-
|
6
|
-
RSpec.configure do |config|
|
7
|
-
# Run specs in random order to surface order dependencies. If you find an
|
8
|
-
# order dependency and want to debug it, you can fix the order by providing
|
9
|
-
# the seed, which is printed after each run.
|
10
|
-
# --seed 1234
|
11
|
-
# config.order = :random
|
12
|
-
|
13
|
-
# Seed global randomization in this process using the `--seed` CLI option.
|
14
|
-
# Setting this allows you to use `--seed` to deterministically reproduce
|
15
|
-
# test failures related to randomization by passing the same `--seed` value
|
16
|
-
# as the one that triggered the failure.
|
17
|
-
# Kernel.srand config.seed
|
18
|
-
|
19
|
-
config.after :each do
|
20
|
-
Gamefic::Narrative.blocks.clear
|
21
|
-
Gamefic::Plot.blocks.clear
|
22
|
-
Gamefic::Subplot.blocks.clear
|
23
|
-
end
|
24
|
-
end
|