gamefic 2.4.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/rspec.yml +41 -40
- data/.rspec-opal +2 -0
- data/.solargraph.yml +20 -3
- data/CHANGELOG.md +9 -0
- data/Rakefile +11 -1
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/gamefic.gemspec +5 -2
- data/lib/gamefic/action.rb +52 -183
- data/lib/gamefic/active/cue.rb +25 -0
- data/lib/gamefic/active/epic.rb +68 -0
- data/lib/gamefic/active/messaging.rb +43 -0
- data/lib/gamefic/active/take.rb +69 -0
- data/lib/gamefic/active.rb +95 -192
- data/lib/gamefic/actor.rb +2 -0
- data/lib/gamefic/block.rb +28 -0
- data/lib/gamefic/command.rb +16 -6
- data/lib/gamefic/core_ext/array.rb +4 -4
- data/lib/gamefic/core_ext/string.rb +10 -5
- data/lib/gamefic/describable.rb +39 -65
- data/lib/gamefic/dispatcher.rb +63 -32
- data/lib/gamefic/entity.rb +44 -19
- data/lib/gamefic/logging.rb +32 -0
- data/lib/gamefic/messenger.rb +66 -0
- data/lib/gamefic/narrative.rb +104 -0
- data/lib/gamefic/node.rb +44 -53
- data/lib/gamefic/plot.rb +60 -93
- data/lib/gamefic/props/default.rb +41 -0
- data/lib/gamefic/props/multiple_choice.rb +65 -0
- data/lib/gamefic/props/pause.rb +11 -0
- data/lib/gamefic/props/yes_or_no.rb +21 -0
- data/lib/gamefic/props.rb +10 -0
- data/lib/gamefic/query/base.rb +45 -126
- data/lib/gamefic/query/general.rb +46 -0
- data/lib/gamefic/query/result.rb +20 -0
- data/lib/gamefic/query/scoped.rb +41 -0
- data/lib/gamefic/query/text.rb +30 -31
- data/lib/gamefic/query.rb +7 -15
- data/lib/gamefic/response.rb +118 -0
- data/lib/gamefic/rulebook/calls.rb +90 -0
- data/lib/gamefic/rulebook/events.rb +79 -0
- data/lib/gamefic/rulebook/hooks.rb +57 -0
- data/lib/gamefic/rulebook/scenes.rb +68 -0
- data/lib/gamefic/rulebook.rb +139 -0
- data/lib/gamefic/scanner.rb +103 -0
- data/lib/gamefic/scene/activity.rb +9 -17
- data/lib/gamefic/scene/conclusion.rb +6 -5
- data/lib/gamefic/scene/default.rb +88 -0
- data/lib/gamefic/scene/multiple_choice.rb +14 -69
- data/lib/gamefic/scene/pause.rb +9 -13
- data/lib/gamefic/scene/yes_or_no.rb +6 -46
- data/lib/gamefic/scene.rb +11 -7
- data/lib/gamefic/scope/base.rb +44 -0
- data/lib/gamefic/scope/children.rb +16 -0
- data/lib/gamefic/scope/family.rb +20 -0
- data/lib/gamefic/scope/myself.rb +13 -0
- data/lib/gamefic/scope/parent.rb +13 -0
- data/lib/gamefic/scope/siblings.rb +14 -0
- data/lib/gamefic/scope.rb +8 -0
- data/lib/gamefic/scriptable/actions.rb +156 -0
- data/lib/gamefic/scriptable/entities.rb +76 -0
- data/lib/gamefic/scriptable/events.rb +65 -0
- data/lib/gamefic/scriptable/proxy.rb +55 -0
- data/lib/gamefic/scriptable/queries.rb +73 -0
- data/lib/gamefic/scriptable/scenes.rb +162 -0
- data/lib/gamefic/scriptable.rb +167 -73
- data/lib/gamefic/snapshot.rb +36 -0
- data/lib/gamefic/stage.rb +51 -0
- data/lib/gamefic/subplot.rb +51 -79
- data/lib/gamefic/syntax/template.rb +67 -0
- data/lib/gamefic/syntax.rb +102 -83
- data/lib/gamefic/vault.rb +50 -0
- data/lib/gamefic/version.rb +1 -1
- data/lib/gamefic.rb +26 -15
- data/spec-opal/spec_helper.rb +24 -0
- metadata +91 -29
- data/lib/gamefic/element.rb +0 -46
- data/lib/gamefic/keywords.rb +0 -52
- data/lib/gamefic/messaging.rb +0 -43
- data/lib/gamefic/plot/darkroom.rb +0 -120
- data/lib/gamefic/plot/host.rb +0 -42
- data/lib/gamefic/plot/snapshot.rb +0 -27
- data/lib/gamefic/query/children.rb +0 -9
- data/lib/gamefic/query/descendants.rb +0 -15
- data/lib/gamefic/query/external.rb +0 -39
- data/lib/gamefic/query/family.rb +0 -18
- data/lib/gamefic/query/itself.rb +0 -13
- data/lib/gamefic/query/matches.rb +0 -75
- data/lib/gamefic/query/parent.rb +0 -9
- data/lib/gamefic/query/siblings.rb +0 -13
- data/lib/gamefic/query/tree.rb +0 -17
- data/lib/gamefic/scene/base.rb +0 -142
- data/lib/gamefic/scene/multiple_scene.rb +0 -29
- data/lib/gamefic/serialize.rb +0 -196
- data/lib/gamefic/world/callbacks.rb +0 -135
- data/lib/gamefic/world/commands.rb +0 -181
- data/lib/gamefic/world/entities.rb +0 -98
- data/lib/gamefic/world/playbook.rb +0 -233
- data/lib/gamefic/world/players.rb +0 -37
- data/lib/gamefic/world/scenes.rb +0 -228
- data/lib/gamefic/world.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6647dc3319080277826fecd19b8466cfbe82a42f4f4c68aeb89fa74bd0de4319
|
4
|
+
data.tar.gz: 0dc0680cb42b981d6e93c12d03e95b4ffcce0a98acb0678595723ab2d5ae7db9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1ec19185367b63b0ebe352e620af403e0aef00bdd7afac7135801551568ef5c35c923b45092cb4d781cd8458bba71776b042efe9837a0e9d2f144141b6b8d606
|
7
|
+
data.tar.gz: 300d2c30b05993ee4689f14ce8daeeec3585bfdf1cd7636ec6a931bfc568e8227a97771fdf6d20ec859080f3792b914a29ba1fc6a7246c9f9ef9eb563d81920c
|
data/.github/workflows/rspec.yml
CHANGED
@@ -1,40 +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.
|
26
|
-
|
27
|
-
steps:
|
28
|
-
- uses: actions/checkout@v3
|
29
|
-
- name: Set up Ruby
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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
data/.solargraph.yml
CHANGED
@@ -1,5 +1,22 @@
|
|
1
|
+
---
|
1
2
|
include:
|
2
|
-
|
3
|
+
- "**/*.rb"
|
3
4
|
exclude:
|
4
|
-
|
5
|
-
|
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,12 @@
|
|
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
|
+
|
1
10
|
## 2.4.0 - February 11, 2023
|
2
11
|
- Fix arity of delegated methods in scripts
|
3
12
|
- Action hooks accept verb filters
|
data/Rakefile
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
-
|
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
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 = '
|
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.
|
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'
|
data/lib/gamefic/action.rb
CHANGED
@@ -1,213 +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
|
-
|
4
|
-
attr_reader :actor
|
9
|
+
include Logging
|
5
10
|
|
6
|
-
#
|
7
|
-
#
|
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
|
-
|
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
|
-
# @
|
14
|
-
|
15
|
-
|
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
|
-
@
|
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
|
26
|
-
|
27
|
-
return if @cancelled
|
28
|
-
self.class.executor.call(@actor, *arguments) unless self.class.executor.nil?
|
49
|
+
return if cancelled?
|
50
|
+
|
29
51
|
@executed = true
|
30
|
-
|
52
|
+
response.execute actor, *arguments
|
31
53
|
end
|
32
54
|
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
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.
|
36
58
|
#
|
37
|
-
def
|
38
|
-
|
39
|
-
# executed
|
40
|
-
@cancelled = true
|
59
|
+
def executed?
|
60
|
+
@executed ||= false
|
41
61
|
end
|
42
62
|
|
43
|
-
#
|
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.
|
44
65
|
#
|
45
|
-
|
46
|
-
|
47
|
-
@executed
|
66
|
+
def cancel
|
67
|
+
@cancelled = true
|
48
68
|
end
|
49
69
|
|
50
70
|
def cancelled?
|
51
|
-
|
71
|
+
@cancelled ||= false
|
52
72
|
end
|
53
73
|
|
54
|
-
# The verb associated with this action.
|
55
|
-
#
|
56
|
-
# @return [Symbol] The symbol representing the verb
|
57
74
|
def verb
|
58
|
-
|
59
|
-
end
|
60
|
-
|
61
|
-
def signature
|
62
|
-
self.class.signature
|
63
|
-
end
|
64
|
-
|
65
|
-
def rank
|
66
|
-
self.class.rank
|
75
|
+
response.verb
|
67
76
|
end
|
68
77
|
|
69
|
-
# True if the action is flagged as meta.
|
70
|
-
#
|
71
|
-
# @return [Boolean]
|
72
78
|
def meta?
|
73
|
-
|
74
|
-
end
|
75
|
-
|
76
|
-
# @param verb [Symbol]
|
77
|
-
# @param queries [Array<Gamefic::Query::Base>]
|
78
|
-
# @param meta [Boolean]
|
79
|
-
# @return [Class<Action>]
|
80
|
-
def self.subclass verb, *queries, meta: false, &block
|
81
|
-
act = Class.new(self) do
|
82
|
-
self.verb = verb
|
83
|
-
self.meta = meta
|
84
|
-
queries.each do |q|
|
85
|
-
add_query q
|
86
|
-
end
|
87
|
-
on_execute &block
|
88
|
-
end
|
89
|
-
if !block.nil? && act.queries.length + 1 != block.arity && block.arity > 0
|
90
|
-
raise ArgumentError.new("Number of parameters is not compatible with proc arguments")
|
91
|
-
end
|
92
|
-
act
|
93
|
-
end
|
94
|
-
|
95
|
-
private
|
96
|
-
|
97
|
-
def run_before_actions
|
98
|
-
return unless @with_callbacks
|
99
|
-
@actor.playbooks
|
100
|
-
.flat_map(&:before_actions)
|
101
|
-
.each do |hook|
|
102
|
-
next unless hook.verb.nil? || hook.verb == verb
|
103
|
-
hook.block.call(self)
|
104
|
-
break if @cancelled
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def run_after_actions
|
109
|
-
return unless @with_callbacks
|
110
|
-
@actor.playbooks
|
111
|
-
.flat_map(&:after_actions)
|
112
|
-
.each do |hook|
|
113
|
-
next unless hook.verb.nil? || hook.verb == verb
|
114
|
-
hook.block.call(self)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
class << self
|
119
|
-
attr_reader :verb
|
120
|
-
|
121
|
-
# The proc to call when the action is executed
|
122
|
-
#
|
123
|
-
# @return [Proc]
|
124
|
-
attr_reader :executor
|
125
|
-
|
126
|
-
def meta?
|
127
|
-
@meta ||= false
|
128
|
-
end
|
129
|
-
|
130
|
-
def add_query q
|
131
|
-
@specificity = nil
|
132
|
-
queries.push q
|
133
|
-
end
|
134
|
-
|
135
|
-
def queries
|
136
|
-
@queries ||= []
|
137
|
-
end
|
138
|
-
|
139
|
-
def on_execute &block
|
140
|
-
@executor = block
|
141
|
-
end
|
142
|
-
|
143
|
-
def signature
|
144
|
-
# @todo This is clearly unfinished
|
145
|
-
"#{verb} #{queries.map {|m| m.signature}.join(', ')}"
|
146
|
-
end
|
147
|
-
|
148
|
-
# True if this action is not intended to be performed directly by a
|
149
|
-
# character.
|
150
|
-
# If the action is hidden, users should not be able to perform it with a
|
151
|
-
# direct command. By default, any action whose verb starts with an
|
152
|
-
# underscore is hidden.
|
153
|
-
#
|
154
|
-
# @return [Boolean]
|
155
|
-
def hidden?
|
156
|
-
verb.to_s.start_with?('_')
|
157
|
-
end
|
158
|
-
|
159
|
-
# @return [Integer]
|
160
|
-
def rank
|
161
|
-
if @rank.nil?
|
162
|
-
@rank = 0
|
163
|
-
queries.each do |q|
|
164
|
-
@rank += (q.rank + 1)
|
165
|
-
end
|
166
|
-
@rank -= 1000 if verb.nil?
|
167
|
-
end
|
168
|
-
@rank
|
169
|
-
end
|
170
|
-
|
171
|
-
def valid? actor, objects
|
172
|
-
return false if objects.length != queries.length
|
173
|
-
queries.each_with_index do |p, i|
|
174
|
-
return false unless p.include?(actor, objects[i])
|
175
|
-
end
|
176
|
-
true
|
177
|
-
end
|
178
|
-
|
179
|
-
# Return an instance of this Action if the actor can execute it with the
|
180
|
-
# provided tokens, or nil if the tokens are invalid.
|
181
|
-
#
|
182
|
-
# @param action [Gamefic::Entity]
|
183
|
-
# @param command [Command]
|
184
|
-
# @return [self, nil]
|
185
|
-
def attempt actor, command, with_callbacks = false
|
186
|
-
return nil if command.verb != verb
|
187
|
-
tokens = command.arguments
|
188
|
-
result = []
|
189
|
-
matches = Gamefic::Query::Matches.new([], '', '')
|
190
|
-
queries.each_with_index do |p, i|
|
191
|
-
return nil if tokens[i].nil? && matches.remaining == ''
|
192
|
-
matches = p.resolve(actor, "#{matches.remaining} #{tokens[i]}".strip, continued: (i < queries.length - 1))
|
193
|
-
return nil if matches.objects.empty?
|
194
|
-
accepted = matches.objects.select { |o| p.accept?(o) }
|
195
|
-
return nil if accepted.empty?
|
196
|
-
if p.ambiguous?
|
197
|
-
result.push accepted
|
198
|
-
else
|
199
|
-
return nil if accepted.length != 1
|
200
|
-
result.push accepted.first
|
201
|
-
end
|
202
|
-
end
|
203
|
-
new(actor, result, with_callbacks)
|
204
|
-
end
|
205
|
-
|
206
|
-
protected
|
207
|
-
|
208
|
-
attr_writer :verb
|
209
|
-
|
210
|
-
attr_writer :meta
|
79
|
+
response.meta?
|
211
80
|
end
|
212
81
|
end
|
213
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
|