gamefic 2.3.0 → 3.0.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.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rspec.yml +41 -0
  3. data/.rspec-opal +2 -0
  4. data/.rubocop.yml +4 -1
  5. data/.solargraph.yml +20 -3
  6. data/CHANGELOG.md +15 -0
  7. data/Gemfile +0 -4
  8. data/Rakefile +11 -1
  9. data/bin/console +14 -0
  10. data/bin/setup +8 -0
  11. data/gamefic.gemspec +5 -2
  12. data/lib/gamefic/action.rb +53 -173
  13. data/lib/gamefic/active/cue.rb +25 -0
  14. data/lib/gamefic/active/epic.rb +68 -0
  15. data/lib/gamefic/active/messaging.rb +43 -0
  16. data/lib/gamefic/active/take.rb +69 -0
  17. data/lib/gamefic/active.rb +97 -192
  18. data/lib/gamefic/actor.rb +2 -0
  19. data/lib/gamefic/block.rb +28 -0
  20. data/lib/gamefic/command.rb +16 -6
  21. data/lib/gamefic/core_ext/array.rb +4 -4
  22. data/lib/gamefic/core_ext/string.rb +10 -5
  23. data/lib/gamefic/describable.rb +39 -65
  24. data/lib/gamefic/dispatcher.rb +67 -29
  25. data/lib/gamefic/entity.rb +44 -19
  26. data/lib/gamefic/logging.rb +32 -0
  27. data/lib/gamefic/messenger.rb +66 -0
  28. data/lib/gamefic/narrative.rb +104 -0
  29. data/lib/gamefic/node.rb +44 -53
  30. data/lib/gamefic/plot.rb +60 -93
  31. data/lib/gamefic/props/default.rb +41 -0
  32. data/lib/gamefic/props/multiple_choice.rb +65 -0
  33. data/lib/gamefic/props/pause.rb +11 -0
  34. data/lib/gamefic/props/yes_or_no.rb +21 -0
  35. data/lib/gamefic/props.rb +10 -0
  36. data/lib/gamefic/query/base.rb +45 -126
  37. data/lib/gamefic/query/general.rb +46 -0
  38. data/lib/gamefic/query/result.rb +20 -0
  39. data/lib/gamefic/query/scoped.rb +41 -0
  40. data/lib/gamefic/query/text.rb +30 -31
  41. data/lib/gamefic/query.rb +7 -15
  42. data/lib/gamefic/response.rb +118 -0
  43. data/lib/gamefic/rulebook/calls.rb +90 -0
  44. data/lib/gamefic/rulebook/events.rb +79 -0
  45. data/lib/gamefic/rulebook/hooks.rb +57 -0
  46. data/lib/gamefic/rulebook/scenes.rb +68 -0
  47. data/lib/gamefic/rulebook.rb +139 -0
  48. data/lib/gamefic/scanner.rb +103 -0
  49. data/lib/gamefic/scene/activity.rb +9 -17
  50. data/lib/gamefic/scene/conclusion.rb +6 -5
  51. data/lib/gamefic/scene/default.rb +88 -0
  52. data/lib/gamefic/scene/multiple_choice.rb +14 -69
  53. data/lib/gamefic/scene/pause.rb +9 -13
  54. data/lib/gamefic/scene/yes_or_no.rb +6 -46
  55. data/lib/gamefic/scene.rb +11 -7
  56. data/lib/gamefic/scope/base.rb +44 -0
  57. data/lib/gamefic/scope/children.rb +16 -0
  58. data/lib/gamefic/scope/family.rb +20 -0
  59. data/lib/gamefic/scope/myself.rb +13 -0
  60. data/lib/gamefic/scope/parent.rb +13 -0
  61. data/lib/gamefic/scope/siblings.rb +14 -0
  62. data/lib/gamefic/scope.rb +8 -0
  63. data/lib/gamefic/scriptable/actions.rb +156 -0
  64. data/lib/gamefic/scriptable/entities.rb +76 -0
  65. data/lib/gamefic/scriptable/events.rb +65 -0
  66. data/lib/gamefic/scriptable/proxy.rb +55 -0
  67. data/lib/gamefic/scriptable/queries.rb +73 -0
  68. data/lib/gamefic/scriptable/scenes.rb +162 -0
  69. data/lib/gamefic/scriptable.rb +167 -68
  70. data/lib/gamefic/snapshot.rb +36 -0
  71. data/lib/gamefic/stage.rb +51 -0
  72. data/lib/gamefic/subplot.rb +51 -79
  73. data/lib/gamefic/syntax/template.rb +67 -0
  74. data/lib/gamefic/syntax.rb +102 -83
  75. data/lib/gamefic/vault.rb +50 -0
  76. data/lib/gamefic/version.rb +3 -1
  77. data/lib/gamefic.rb +26 -15
  78. data/spec-opal/spec_helper.rb +24 -0
  79. metadata +92 -29
  80. data/lib/gamefic/element.rb +0 -46
  81. data/lib/gamefic/keywords.rb +0 -52
  82. data/lib/gamefic/messaging.rb +0 -43
  83. data/lib/gamefic/plot/darkroom.rb +0 -120
  84. data/lib/gamefic/plot/host.rb +0 -42
  85. data/lib/gamefic/plot/snapshot.rb +0 -27
  86. data/lib/gamefic/query/children.rb +0 -9
  87. data/lib/gamefic/query/descendants.rb +0 -15
  88. data/lib/gamefic/query/external.rb +0 -39
  89. data/lib/gamefic/query/family.rb +0 -18
  90. data/lib/gamefic/query/itself.rb +0 -13
  91. data/lib/gamefic/query/matches.rb +0 -75
  92. data/lib/gamefic/query/parent.rb +0 -9
  93. data/lib/gamefic/query/siblings.rb +0 -13
  94. data/lib/gamefic/query/tree.rb +0 -17
  95. data/lib/gamefic/scene/base.rb +0 -142
  96. data/lib/gamefic/scene/multiple_scene.rb +0 -29
  97. data/lib/gamefic/serialize.rb +0 -196
  98. data/lib/gamefic/world/callbacks.rb +0 -135
  99. data/lib/gamefic/world/commands.rb +0 -173
  100. data/lib/gamefic/world/entities.rb +0 -98
  101. data/lib/gamefic/world/playbook.rb +0 -225
  102. data/lib/gamefic/world/players.rb +0 -37
  103. data/lib/gamefic/world/scenes.rb +0 -226
  104. data/lib/gamefic/world.rb +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aa8d74d06ad87105050c1ca487acd976d293f4ca52fa6cc760061ccdbb3a14e7
4
- data.tar.gz: f791519291a168cf31045d6bc2f136d4829f5ddce2fa7c370d6c4887f83f560e
3
+ metadata.gz: 6647dc3319080277826fecd19b8466cfbe82a42f4f4c68aeb89fa74bd0de4319
4
+ data.tar.gz: 0dc0680cb42b981d6e93c12d03e95b4ffcce0a98acb0678595723ab2d5ae7db9
5
5
  SHA512:
6
- metadata.gz: e8abcf0f9ca24db9b8bc3f61be5d0d28dcd86c24f047e420eb117bd09411b70d5f3ae7e9c2c5d2277062c4c72a970d2c9144eb0990a46872eb80b7a7bd75369e
7
- data.tar.gz: 2bdec46fe7d946a05c3d9bf258314db25c61f32459993f03f1c2096dd31b0056917332fcd5c05ee011e3c352e373a1dcaa74f670d069398e481334ff64c07f1d
6
+ metadata.gz: 1ec19185367b63b0ebe352e620af403e0aef00bdd7afac7135801551568ef5c35c923b45092cb4d781cd8458bba71776b042efe9837a0e9d2f144141b6b8d606
7
+ data.tar.gz: 300d2c30b05993ee4689f14ce8daeeec3585bfdf1cd7636ec6a931bfc568e8227a97771fdf6d20ec859080f3792b914a29ba1fc6a7246c9f9ef9eb563d81920c
@@ -0,0 +1,41 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with rspec.
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: RSpec
9
+
10
+ on:
11
+ push:
12
+ branches: [ master ]
13
+ pull_request:
14
+ branches: [ master ]
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ jobs:
20
+ test:
21
+
22
+ runs-on: ubuntu-latest
23
+ strategy:
24
+ matrix:
25
+ ruby-version: ['2.7', '3.0', '3.1']
26
+
27
+ steps:
28
+ - uses: actions/checkout@v3
29
+ - name: Set up Ruby
30
+ uses: ruby/setup-ruby@v1
31
+ with:
32
+ ruby-version: ${{ matrix.ruby-version }}
33
+ bundler-cache: false
34
+ - name: Set up Node
35
+ uses: actions/setup-node@v3
36
+ - name: Install dependencies
37
+ run: bundle install
38
+ - name: Run Ruby tests
39
+ run: bundle exec rspec
40
+ - name: Run Opal tests
41
+ run: bundle exec rake opal
data/.rspec-opal ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.rubocop.yml CHANGED
@@ -10,4 +10,7 @@ Style/StringLiterals:
10
10
 
11
11
  Style/Documentation:
12
12
  Description: 'Document classes and non-namespace modules.'
13
- Enabled: false
13
+ Enabled: false
14
+
15
+ Style/MethodDefParentheses:
16
+ Enabled: false
data/.solargraph.yml CHANGED
@@ -1,5 +1,22 @@
1
+ ---
1
2
  include:
2
- - lib/**/*.rb
3
+ - "**/*.rb"
3
4
  exclude:
4
- - spec/**/*
5
- - test/**/*
5
+ - spec/**/*
6
+ - test/**/*
7
+ - vendor/**/*
8
+ - ".bundle/**/*"
9
+ require: []
10
+ domains: []
11
+ reporters:
12
+ - rubocop
13
+ - require_not_found
14
+ formatter:
15
+ rubocop:
16
+ cops: safe
17
+ except: []
18
+ only: []
19
+ extra_args: []
20
+ require_paths: []
21
+ plugins: []
22
+ max_files: 5000
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## 3.0.0
2
+ - Instantiate subplots from snapshots
3
+ - Split Action into Response and Action
4
+ - Logging
5
+ - Remove deprecated Active#perform behavior
6
+ - Snapshots use single static index
7
+ - Hydration improvements
8
+ - Snapshot metadata validation
9
+
10
+ ## 2.4.0 - February 11, 2023
11
+ - Fix arity of delegated methods in scripts
12
+ - Action hooks accept verb filters
13
+ - Opal exception for delegated methods
14
+ - Support separation of kwargs in Ruby >= 2.7
15
+
1
16
  ## 2.3.0 - January 25, 2023
2
17
  - Remove unused Active#actions method
3
18
  - Add before_action and after_action hooks
data/Gemfile CHANGED
@@ -1,7 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
-
5
- group :test do
6
- gem "simplecov"
7
- end
data/Rakefile CHANGED
@@ -1,5 +1,9 @@
1
- require 'rake'
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
2
5
  require 'rspec/core/rake_task'
6
+ require 'opal/rspec/rake_task'
3
7
 
4
8
  RSpec::Core::RakeTask.new(:spec) do |t|
5
9
  t.pattern = Dir.glob('spec/**/*_spec.rb')
@@ -8,3 +12,9 @@ RSpec::Core::RakeTask.new(:spec) do |t|
8
12
  #t.rcov = true
9
13
  end
10
14
  task :default => :spec
15
+
16
+ Opal::RSpec::RakeTask.new(:opal) do |_, config|
17
+ Opal.append_path File.expand_path('../lib', __FILE__)
18
+ config.pattern = 'spec/**/*_spec.rb'
19
+ config.requires = ['spec_helper']
20
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "gamefic-sdk"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/gamefic.gemspec CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
11
11
  s.description = "An adventure game and interactive fiction framework"
12
12
  s.authors = ["Fred Snyder"]
13
13
  s.email = 'fsnyder@gamefic.com'
14
- s.homepage = 'http://gamefic.com'
14
+ s.homepage = 'https://gamefic.com'
15
15
  s.license = 'MIT'
16
16
 
17
17
  s.files = Dir.chdir(File.expand_path('..', __FILE__)) do
@@ -19,8 +19,11 @@ Gem::Specification.new do |s|
19
19
  end
20
20
  s.require_paths = ['lib']
21
21
 
22
- s.required_ruby_version = '>= 2.1.0'
22
+ s.required_ruby_version = '>= 2.7.0'
23
23
 
24
+ s.add_development_dependency 'opal', '~> 1.7'
25
+ s.add_development_dependency 'opal-rspec', '~> 1.0'
26
+ s.add_development_dependency 'opal-sprockets', '~> 1.0'
24
27
  s.add_development_dependency 'rake', '~> 12.3', '>= 12.3'
25
28
  s.add_development_dependency 'rspec', '~> 3.5', '>= 3.5.0'
26
29
  s.add_development_dependency 'simplecov', '~> 0.14'
@@ -1,202 +1,82 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gamefic
4
+ # The handler for executing responses for a provided actor and array of
5
+ # arguments. It's also responsible for executing before_action and
6
+ # after_action hooks if necessary.
7
+ #
2
8
  class Action
3
- # @return [Gamefic::Actor]
4
- attr_reader :actor
9
+ include Logging
5
10
 
6
- # An array of objects on which the action will operate, e.g., an entity
7
- # that is a direct object of a command.
11
+ # Hooks are blocks of code that get executed before or after an actor
12
+ # performs an action. A before action hook is capable of cancelling the
13
+ # action's performance.
8
14
  #
9
- # @return [Array<Object>]
15
+ class Hook
16
+ attr_reader :verbs
17
+
18
+ attr_reader :block
19
+
20
+ def initialize *verbs, &block
21
+ @verbs = verbs
22
+ @block = block
23
+ end
24
+
25
+ def match?(input)
26
+ verbs.empty? || verbs.include?(input)
27
+ end
28
+ end
29
+
30
+ # @return [Active]
31
+ attr_reader :actor
32
+
33
+ # @return [Array]
10
34
  attr_reader :arguments
11
- alias parameters arguments
12
35
 
13
- # @param actor [Gamefic::Actor]
14
- # @param arguments [Array<Object>]
15
- def initialize actor, arguments, with_callbacks = false
36
+ # @return [Response]
37
+ attr_reader :response
38
+
39
+ # @param actor [Active]
40
+ # @param arguments [Array]
41
+ # @param response [Response]
42
+ def initialize actor, arguments, response
16
43
  @actor = actor
17
44
  @arguments = arguments
18
- @executed = false
19
- @with_callbacks = with_callbacks
45
+ @response = response
20
46
  end
21
47
 
22
- # Perform the action.
23
- #
24
48
  def execute
25
- return if @cancelled
26
- run_before_actions
27
- return if @cancelled
28
- self.class.executor.call(@actor, *arguments) unless self.class.executor.nil?
29
- @executed = true
30
- run_after_actions
31
- end
49
+ return if cancelled?
32
50
 
33
- # Cancel an action. This method can be called in a before_action hook to
34
- # prevent subsequent hooks and the action itself from being executed.
35
- #
36
- def cancel
37
- @cancelled = true
51
+ @executed = true
52
+ response.execute actor, *arguments
38
53
  end
39
54
 
40
- # True if the #execute method has been called for this action.
55
+ # True if the response has been executed. False typically means that the
56
+ # #execute method has not been called or the action was cancelled in a
57
+ # before_action hook.
41
58
  #
42
- # @return [Boolean]
43
59
  def executed?
44
- @executed
60
+ @executed ||= false
45
61
  end
46
62
 
47
- # The verb associated with this action.
63
+ # Cancel an action. This method can be called in an action hook to
64
+ # prevent subsequent hooks and/or the action itself from being executed.
48
65
  #
49
- # @return [Symbol] The symbol representing the verb
50
- def verb
51
- self.class.verb
66
+ def cancel
67
+ @cancelled = true
52
68
  end
53
69
 
54
- def signature
55
- self.class.signature
70
+ def cancelled?
71
+ @cancelled ||= false
56
72
  end
57
73
 
58
- def rank
59
- self.class.rank
74
+ def verb
75
+ response.verb
60
76
  end
61
77
 
62
- # True if the action is flagged as meta.
63
- #
64
- # @return [Boolean]
65
78
  def meta?
66
- self.class.meta?
67
- end
68
-
69
- # @param verb [Symbol]
70
- # @param queries [Array<Gamefic::Query::Base>]
71
- # @param meta [Boolean]
72
- # @return [Class<Action>]
73
- def self.subclass verb, *queries, meta: false, &block
74
- act = Class.new(self) do
75
- self.verb = verb
76
- self.meta = meta
77
- queries.each do |q|
78
- add_query q
79
- end
80
- on_execute &block
81
- end
82
- if !block.nil? && act.queries.length + 1 != block.arity && block.arity > 0
83
- raise ArgumentError.new("Number of parameters is not compatible with proc arguments")
84
- end
85
- act
86
- end
87
-
88
- private
89
-
90
- def run_before_actions
91
- return unless @with_callbacks
92
- @actor.playbooks
93
- .flat_map(&:before_actions)
94
- .each do |block|
95
- block.call(self)
96
- break if @cancelled
97
- end
98
- end
99
-
100
- def run_after_actions
101
- return unless @with_callbacks
102
- @actor.playbooks
103
- .flat_map(&:after_actions)
104
- .each { |block| block.call(self) }
105
- end
106
-
107
- class << self
108
- attr_reader :verb
109
-
110
- # The proc to call when the action is executed
111
- #
112
- # @return [Proc]
113
- attr_reader :executor
114
-
115
- def meta?
116
- @meta ||= false
117
- end
118
-
119
- def add_query q
120
- @specificity = nil
121
- queries.push q
122
- end
123
-
124
- def queries
125
- @queries ||= []
126
- end
127
-
128
- def on_execute &block
129
- @executor = block
130
- end
131
-
132
- def signature
133
- # @todo This is clearly unfinished
134
- "#{verb} #{queries.map {|m| m.signature}.join(', ')}"
135
- end
136
-
137
- # True if this action is not intended to be performed directly by a
138
- # character.
139
- # If the action is hidden, users should not be able to perform it with a
140
- # direct command. By default, any action whose verb starts with an
141
- # underscore is hidden.
142
- #
143
- # @return [Boolean]
144
- def hidden?
145
- verb.to_s.start_with?('_')
146
- end
147
-
148
- # @return [Integer]
149
- def rank
150
- if @rank.nil?
151
- @rank = 0
152
- queries.each do |q|
153
- @rank += (q.rank + 1)
154
- end
155
- @rank -= 1000 if verb.nil?
156
- end
157
- @rank
158
- end
159
-
160
- def valid? actor, objects
161
- return false if objects.length != queries.length
162
- queries.each_with_index do |p, i|
163
- return false unless p.include?(actor, objects[i])
164
- end
165
- true
166
- end
167
-
168
- # Return an instance of this Action if the actor can execute it with the
169
- # provided tokens, or nil if the tokens are invalid.
170
- #
171
- # @param action [Gamefic::Entity]
172
- # @param command [Command]
173
- # @return [self, nil]
174
- def attempt actor, command, with_callbacks = false
175
- return nil if command.verb != verb
176
- tokens = command.arguments
177
- result = []
178
- matches = Gamefic::Query::Matches.new([], '', '')
179
- queries.each_with_index do |p, i|
180
- return nil if tokens[i].nil? && matches.remaining == ''
181
- matches = p.resolve(actor, "#{matches.remaining} #{tokens[i]}".strip, continued: (i < queries.length - 1))
182
- return nil if matches.objects.empty?
183
- accepted = matches.objects.select { |o| p.accept?(o) }
184
- return nil if accepted.empty?
185
- if p.ambiguous?
186
- result.push accepted
187
- else
188
- return nil if accepted.length != 1
189
- result.push accepted.first
190
- end
191
- end
192
- new(actor, result, with_callbacks)
193
- end
194
-
195
- protected
196
-
197
- attr_writer :verb
198
-
199
- attr_writer :meta
79
+ response.meta?
200
80
  end
201
81
  end
202
82
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Active
5
+ # The data that actors use to configure a Take.
6
+ #
7
+ class Cue
8
+ # @return [Symbol]
9
+ attr_reader :scene
10
+
11
+ # @return [Hash]
12
+ attr_reader :context
13
+
14
+ # @param scene [Symbol]
15
+ def initialize scene, **context
16
+ @scene = scene
17
+ @context = context
18
+ end
19
+
20
+ def to_s
21
+ scene.to_s
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Active
5
+ # A collection of narratives.
6
+ #
7
+ class Epic
8
+ include Logging
9
+
10
+ # @return [Set<Narrative>]
11
+ attr_reader :narratives
12
+
13
+ def initialize
14
+ @narratives = Set.new
15
+ end
16
+
17
+ # @param narrative [Narrative]
18
+ def add narrative
19
+ narratives.add narrative
20
+ end
21
+
22
+ # @param narrative [Narrative]
23
+ def delete narrative
24
+ narratives.delete narrative
25
+ end
26
+
27
+ # @return [Array<Rulebook>]
28
+ def rulebooks
29
+ narratives.map(&:rulebook)
30
+ end
31
+
32
+ # @return [Array<Symbol>]
33
+ def verbs
34
+ rulebooks.flat_map(&:verbs).uniq
35
+ end
36
+
37
+ # @return [Array<Symbol>]
38
+ def synonyms
39
+ rulebooks.flat_map(&:synonyms).uniq
40
+ end
41
+
42
+ def empty?
43
+ narratives.empty?
44
+ end
45
+
46
+ def one?
47
+ narratives.one?
48
+ end
49
+
50
+ # @param name [Symbol]
51
+ def conclusion? name
52
+ select_scene(name).conclusion?
53
+ end
54
+
55
+ # @param name [Symbol]
56
+ # @return [Scene]
57
+ def select_scene name
58
+ scenes = rulebooks.map { |rlbk| rlbk.scenes[name] }
59
+ .compact
60
+ raise ArgumentError, "Scene named `#{name}` does not exist" if scenes.empty?
61
+
62
+ logger.warn "Found #{scenes.length} scenes named `#{name}`" unless scenes.one?
63
+
64
+ scenes.last
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,43 @@
1
+ module Gamefic
2
+ module Active
3
+ # A module for active entities that provides a default Messenger with
4
+ # a few shortcuts.
5
+ #
6
+ module Messaging
7
+ def messenger
8
+ @messenger ||= Messenger.new
9
+ end
10
+
11
+ # Send a message to the entity.
12
+ #
13
+ # This method will automatically wrap the message in HTML paragraphs.
14
+ # To send a message without paragraph formatting, use #stream instead.
15
+ #
16
+ # @param message [String]
17
+ def tell(message)
18
+ messenger.tell message
19
+ end
20
+
21
+ # Send a message to the entity as raw text.
22
+ #
23
+ # Unlike #tell, this method will not wrap the message in HTML paragraphs.
24
+ #
25
+ # @param message [String]
26
+ def stream(message)
27
+ messenger.stream message
28
+ end
29
+
30
+ def messages
31
+ messenger.messages
32
+ end
33
+
34
+ def buffer &block
35
+ messenger.buffer(&block)
36
+ end
37
+
38
+ def flush
39
+ messenger.flush
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Active
5
+ # The combination of an actor and a scene to be performed in a plot turn.
6
+ #
7
+ class Take
8
+ # @return [Active]
9
+ attr_reader :actor
10
+
11
+ # @return [Active::Cue]
12
+ attr_reader :cue
13
+
14
+ # @return [Scene::Default]
15
+ attr_reader :scene
16
+
17
+ # @param actor [Active]
18
+ # @param cue [Active::Cue]
19
+ # @param props [Props::Default]
20
+ def initialize actor, cue, props = nil
21
+ @actor = actor
22
+ @cue = cue
23
+ @scene = actor.epic.select_scene(cue.scene)
24
+ @props = props
25
+ end
26
+
27
+ # @return [Props::Default]
28
+ def props
29
+ @props ||= @scene.new_props(**cue.context)
30
+ end
31
+
32
+ # @return [Props::Default]
33
+ def start
34
+ actor.output[:scene] = scene.to_hash
35
+ scene.run_start_blocks actor, props
36
+ scene.start actor, props
37
+ # @todo See if this can be handled better
38
+ actor.epic.rulebooks.each { |rlbk| rlbk.run_player_output_blocks actor, actor.output }
39
+ actor.output.merge!({
40
+ messages: actor.messages,
41
+ queue: actor.queue
42
+ })
43
+ props
44
+ end
45
+
46
+ # @return [void]
47
+ def finish
48
+ actor.flush
49
+ scene.finish(actor, props)
50
+ actor.output.replace(last_prompt: props.prompt, last_input: props.input)
51
+ scene.run_finish_blocks actor, props
52
+ end
53
+
54
+ # @param actor [Active]
55
+ # @param cue [Active::Cue]
56
+ # @return [Props::Default]
57
+ def self.start actor, cue
58
+ Take.new(actor, cue).start
59
+ end
60
+
61
+ # @param actor [Active]
62
+ # @param cue [Active::Cue]
63
+ # @return [void]
64
+ def self.finish actor, cue, props
65
+ Take.new(actor, cue, props).finish
66
+ end
67
+ end
68
+ end
69
+ end