gamefic 2.3.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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