gamefic 2.4.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.
- 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
data/lib/gamefic/serialize.rb
DELETED
@@ -1,196 +0,0 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
|
-
module Gamefic
|
4
|
-
module Serialize
|
5
|
-
def to_serial(index = [])
|
6
|
-
if index.include?(self)
|
7
|
-
{
|
8
|
-
'instance' => "#<ELE_#{index.index(self)}>",
|
9
|
-
'ivars' => {}
|
10
|
-
}
|
11
|
-
else
|
12
|
-
if self.class == Class && self.name
|
13
|
-
{
|
14
|
-
'class' => 'Class',
|
15
|
-
'name' => name
|
16
|
-
}
|
17
|
-
else
|
18
|
-
{
|
19
|
-
'class' => serialized_class(index),
|
20
|
-
'ivars' => serialize_instance_variables(index)
|
21
|
-
}
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def serialized_class index
|
27
|
-
if index.include?(self.class)
|
28
|
-
"#<ELE_#{index.index(self.class)}>"
|
29
|
-
else
|
30
|
-
self.class.to_s
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# @param string [String]
|
35
|
-
# @return [Object]
|
36
|
-
def self.string_to_constant string
|
37
|
-
space = Object
|
38
|
-
string.split('::').each do |part|
|
39
|
-
space = space.const_get(part)
|
40
|
-
end
|
41
|
-
space
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
class Object
|
47
|
-
class << self
|
48
|
-
def exclude_from_serial ary
|
49
|
-
@excluded_from_serial = ary
|
50
|
-
end
|
51
|
-
|
52
|
-
def excluded_from_serial
|
53
|
-
@excluded_from_serial ||= []
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def to_serial(_index)
|
58
|
-
return self if [true, false, nil].include?(self)
|
59
|
-
# @todo This warning is a little too spammy. Set up a logger so it can be
|
60
|
-
# limited to an info or debug level.
|
61
|
-
# STDERR.puts "Unable to convert #{self} to element"
|
62
|
-
"#<UNKNOWN>"
|
63
|
-
end
|
64
|
-
|
65
|
-
def from_serial(index = [])
|
66
|
-
if self.is_a?(Hash)
|
67
|
-
if self['instance']
|
68
|
-
elematch = self['instance'].match(/^#<ELE_([\d]+)>$/)
|
69
|
-
object = index[elematch[1].to_i]
|
70
|
-
raise "Unable to load indexed element ##{elematch[1]} #{self}" if object.nil?
|
71
|
-
elsif self['class']
|
72
|
-
if self['class'] == 'Hash'
|
73
|
-
object = {}
|
74
|
-
self['data'].each do |arr|
|
75
|
-
object[arr[0].from_serial(index)] = arr[1].from_serial(index)
|
76
|
-
end
|
77
|
-
return object
|
78
|
-
elsif self['class'] == 'Class'
|
79
|
-
return Gamefic::Serialize.string_to_constant(self['name'])
|
80
|
-
elsif self['class'] == 'Set'
|
81
|
-
return Set.new(self['data'].map { |el| el.from_serial(index) })
|
82
|
-
else
|
83
|
-
elematch = self['class'].match(/^#<ELE_([\d]+)>$/)
|
84
|
-
if elematch
|
85
|
-
klass = index[elematch[1].to_i]
|
86
|
-
else
|
87
|
-
klass = Gamefic::Serialize.string_to_constant(self['class'])
|
88
|
-
end
|
89
|
-
raise "Unable to find class #{self['class']} #{self}" if klass.nil?
|
90
|
-
object = klass.allocate
|
91
|
-
end
|
92
|
-
end
|
93
|
-
self['ivars'].each_pair do |k, v|
|
94
|
-
object.instance_variable_set(k, v.from_serial(index))
|
95
|
-
end
|
96
|
-
object
|
97
|
-
elsif self.is_a?(Numeric)
|
98
|
-
self
|
99
|
-
elsif self.is_a?(String)
|
100
|
-
match = self.match(/#<ELE_([0-9]+)>/)
|
101
|
-
return index.index(match[1].to_i) if match
|
102
|
-
match = self.match(/#<SYM:([a-z0-9_\?\!]+)>/i)
|
103
|
-
return match[1].to_sym if match
|
104
|
-
self
|
105
|
-
else
|
106
|
-
# true, false, or nil
|
107
|
-
self
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
def serialize_instance_variables(index)
|
112
|
-
result = {}
|
113
|
-
instance_variables.each do |k|
|
114
|
-
next if self.class.excluded_from_serial.include?(k)
|
115
|
-
val = instance_variable_get(k)
|
116
|
-
if index.include?(val)
|
117
|
-
result[k.to_s] = {
|
118
|
-
'instance' => "#<ELE_#{index.index(val)}>",
|
119
|
-
'ivars' => {}
|
120
|
-
}
|
121
|
-
else
|
122
|
-
result[k.to_s] = val.to_serial(index)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
result
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
class Class
|
130
|
-
def to_serial(index = [])
|
131
|
-
if name.nil?
|
132
|
-
super
|
133
|
-
else
|
134
|
-
{
|
135
|
-
'class' => 'Class',
|
136
|
-
'name' => name
|
137
|
-
}
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
class Symbol
|
143
|
-
def to_serial(_index = [])
|
144
|
-
"#<SYM:#{self}>"
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
class String
|
149
|
-
def to_serial(_index = [])
|
150
|
-
self
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
class Numeric
|
155
|
-
def to_serial(_index = [])
|
156
|
-
self
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
class Array
|
161
|
-
def to_serial(index = [])
|
162
|
-
map do |e|
|
163
|
-
s = e.to_serial(index)
|
164
|
-
return "#<UNKNOWN>" if s == "#<UNKNOWN>"
|
165
|
-
s
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
def from_serial(index = [])
|
170
|
-
result = map { |e| e.from_serial(index) }
|
171
|
-
result = "#<UNKNOWN>" if result.any? { |e| e == "#<UNKNOWN>" }
|
172
|
-
result
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
class Hash
|
177
|
-
def to_serial(index = [])
|
178
|
-
result = {'class' => 'Hash', 'data' => []}
|
179
|
-
each_pair do |key, value|
|
180
|
-
k2 = key.to_serial(index)
|
181
|
-
v2 = value.to_serial(index)
|
182
|
-
return "#<UNKNOWN>" if k2 == "#<UNKNOWN>" || v2 == "#<UNKNOWN>"
|
183
|
-
result['data'].push [k2, v2]
|
184
|
-
end
|
185
|
-
result
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
class Set
|
190
|
-
def to_serial(index = [])
|
191
|
-
{
|
192
|
-
'class' => 'Set',
|
193
|
-
'data' => to_a.map { |el| el.to_serial(index) }
|
194
|
-
}
|
195
|
-
end
|
196
|
-
end
|
@@ -1,135 +0,0 @@
|
|
1
|
-
module Gamefic
|
2
|
-
module World
|
3
|
-
module Callbacks
|
4
|
-
# Add a block to be executed on preparation of every turn.
|
5
|
-
#
|
6
|
-
# @example Increment a turn counter
|
7
|
-
# turn = 0
|
8
|
-
# on_ready do
|
9
|
-
# turn += 1
|
10
|
-
# end
|
11
|
-
#
|
12
|
-
def on_ready &block
|
13
|
-
ready_procs.push block
|
14
|
-
end
|
15
|
-
|
16
|
-
# Add a block to be executed after the Plot is finished updating a turn.
|
17
|
-
#
|
18
|
-
def on_update &block
|
19
|
-
update_procs.push block
|
20
|
-
end
|
21
|
-
|
22
|
-
# Add a block to be executed for each player at the beginning of a turn.
|
23
|
-
#
|
24
|
-
# @example Tell the player how many turns they've played.
|
25
|
-
# on_player_ready do |player|
|
26
|
-
# player[:turns] ||= 0
|
27
|
-
# if player[:turns] > 0
|
28
|
-
# player.tell "Turn #{player[:turns]}"
|
29
|
-
# end
|
30
|
-
# player[:turns] += 1
|
31
|
-
# end
|
32
|
-
#
|
33
|
-
# @yieldparam [Gamefic::Actor]
|
34
|
-
def on_player_ready &block
|
35
|
-
player_ready_procs.push block
|
36
|
-
end
|
37
|
-
|
38
|
-
# Add a block to be executed for each player before an update.
|
39
|
-
#
|
40
|
-
# @yieldparam[Gamefic::Actor]
|
41
|
-
def before_player_update &block
|
42
|
-
before_player_update_procs.push block
|
43
|
-
end
|
44
|
-
|
45
|
-
# Add a block to be executed for each player at the end of a turn.
|
46
|
-
#
|
47
|
-
# @yieldparam [Gamefic::Actor]
|
48
|
-
def on_player_update &block
|
49
|
-
player_update_procs.push block
|
50
|
-
end
|
51
|
-
|
52
|
-
# Add a block to be executed at the conclusion of the plot.
|
53
|
-
#
|
54
|
-
# @yieldparam [Gamefic::Actor]
|
55
|
-
def on_player_conclude &block
|
56
|
-
player_conclude_procs.push block
|
57
|
-
end
|
58
|
-
|
59
|
-
def player_conclude_procs
|
60
|
-
@player_conclude_procs ||= []
|
61
|
-
end
|
62
|
-
|
63
|
-
def ready_procs
|
64
|
-
@ready_procs ||= []
|
65
|
-
end
|
66
|
-
|
67
|
-
def update_procs
|
68
|
-
@update_procs ||= []
|
69
|
-
end
|
70
|
-
|
71
|
-
def player_ready_procs
|
72
|
-
@player_ready_procs ||= []
|
73
|
-
end
|
74
|
-
|
75
|
-
def before_player_update_procs
|
76
|
-
@before_player_update_procs ||= []
|
77
|
-
end
|
78
|
-
|
79
|
-
def player_update_procs
|
80
|
-
@player_update_procs ||= []
|
81
|
-
end
|
82
|
-
|
83
|
-
private
|
84
|
-
|
85
|
-
# Execute the on_ready blocks. This method is typically called by the
|
86
|
-
# Plot while beginning a turn.
|
87
|
-
#
|
88
|
-
def call_ready
|
89
|
-
ready_procs.each { |p| p.call }
|
90
|
-
end
|
91
|
-
|
92
|
-
# Execute the on_update blocks. This method is typically called by the
|
93
|
-
# Plot while ending a turn.
|
94
|
-
#
|
95
|
-
def call_update
|
96
|
-
update_procs.each { |p| p.call }
|
97
|
-
end
|
98
|
-
|
99
|
-
# Execute the before_player_update blocks for each player. This method is
|
100
|
-
# typically called by the Plot while updating a turn, immediately before
|
101
|
-
# processing player input.
|
102
|
-
#
|
103
|
-
def call_before_player_update
|
104
|
-
players.each { |player|
|
105
|
-
player.flush
|
106
|
-
before_player_update_procs.each { |block| block.call player }
|
107
|
-
}
|
108
|
-
end
|
109
|
-
|
110
|
-
# Execute the on_player_ready blocks for each player. This method is
|
111
|
-
# typically called by the Plot while beginning a turn, immediately after
|
112
|
-
# the on_ready blocks.
|
113
|
-
#
|
114
|
-
def call_player_ready
|
115
|
-
players.each { |player|
|
116
|
-
unless player.next_scene.nil? || !player.scene.finished?
|
117
|
-
player.cue player.next_scene, **player.next_options
|
118
|
-
end
|
119
|
-
player.cue default_scene if player.scene.nil?
|
120
|
-
player_ready_procs.each { |block| block.call player }
|
121
|
-
}
|
122
|
-
end
|
123
|
-
|
124
|
-
# Execute the on_player_update blocks for each player. This method is
|
125
|
-
# typically called by the Plot while ending a turn, immediately before the
|
126
|
-
# on_ready blocks.
|
127
|
-
#
|
128
|
-
def call_player_update
|
129
|
-
players.each { |player|
|
130
|
-
player_update_procs.each { |block| block.call player }
|
131
|
-
}
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
@@ -1,181 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'gamefic/action'
|
4
|
-
|
5
|
-
module Gamefic
|
6
|
-
module World
|
7
|
-
module Commands
|
8
|
-
include Gamefic::World::Entities
|
9
|
-
|
10
|
-
# @return [Gamefic::World::Playbook]
|
11
|
-
def playbook
|
12
|
-
@playbook ||= Gamefic::World::Playbook.new
|
13
|
-
end
|
14
|
-
|
15
|
-
# Create an Action that responds to a command.
|
16
|
-
# An Action uses the command argument to identify the imperative verb that
|
17
|
-
# triggers the action.
|
18
|
-
# It can also accept queries to tokenize the remainder of the input and
|
19
|
-
# filter for particular entities or properties.
|
20
|
-
# The block argument contains the code to be executed when the input
|
21
|
-
# matches all of the Action's criteria (i.e., verb and queries).
|
22
|
-
#
|
23
|
-
# @example A simple Action.
|
24
|
-
# respond :salute do |actor|
|
25
|
-
# actor.tell "Hello, sir!"
|
26
|
-
# end
|
27
|
-
# # The command "salute" will respond "Hello, sir!"
|
28
|
-
#
|
29
|
-
# @example An Action that accepts a Character
|
30
|
-
# respond :salute, Use.visible(Character) do |actor, character|
|
31
|
-
# actor.tell "#{The character} returns your salute."
|
32
|
-
# end
|
33
|
-
#
|
34
|
-
# @param command [Symbol] An imperative verb for the command
|
35
|
-
# @param queries [Array<Query::Base>] Filters for the command's tokens
|
36
|
-
# @yieldparam [Gamefic::Actor]
|
37
|
-
# @return [Class] The resulting Action subclass
|
38
|
-
def respond(command, *queries, &proc)
|
39
|
-
playbook.respond(command, *map_response_args(queries), &proc)
|
40
|
-
end
|
41
|
-
alias action respond
|
42
|
-
|
43
|
-
# Parse a verb and a list of arguments into an action.
|
44
|
-
# This method serves as a shortcut to creating an action with one or more
|
45
|
-
# arguments that identify specific entities.
|
46
|
-
#
|
47
|
-
# @example
|
48
|
-
# @thing = make Entity, name: 'a thing'
|
49
|
-
# parse "use", "the thing" do |actor, thing|
|
50
|
-
# actor.tell "You use it."
|
51
|
-
# end
|
52
|
-
#
|
53
|
-
# @raise [ArgumentError] if tokens are unrecognized or ambiguous
|
54
|
-
#
|
55
|
-
# @param verb [String, Symbol] The command's verb
|
56
|
-
# @param tokens [Array<String>] The arguments passed to the action
|
57
|
-
# @return [Class] The resulting Action subclass
|
58
|
-
def parse verb, *tokens, &proc
|
59
|
-
query = Query::External.new(entities)
|
60
|
-
params = []
|
61
|
-
tokens.each do |arg|
|
62
|
-
matches = query.resolve(nil, arg)
|
63
|
-
raise ArgumentError, "Unable to resolve token '#{arg}'" if matches.objects.empty?
|
64
|
-
raise ArgumentError, "Ambiguous results for '#{arg}'" if matches.objects.length > 1
|
65
|
-
params.push Query::Family.new(matches.objects[0])
|
66
|
-
end
|
67
|
-
respond(verb.to_sym, *params, &proc)
|
68
|
-
end
|
69
|
-
|
70
|
-
# Tokenize and parse a command to create a new Action subclass.
|
71
|
-
#
|
72
|
-
# @param command [String] The command
|
73
|
-
# @yieldparam [Gamefic::Actor]
|
74
|
-
# @return [Class] the resulting Action subclass
|
75
|
-
def override(command, &proc)
|
76
|
-
cmd = Syntax.tokenize(command, playbook.syntaxes).first
|
77
|
-
raise "Unable to tokenize command '#{command}'" if cmd.nil?
|
78
|
-
parse cmd.verb, *cmd.arguments, &proc
|
79
|
-
end
|
80
|
-
|
81
|
-
# Create a Meta Action that responds to a command.
|
82
|
-
# Meta Actions are very similar to standard Actions, except the Plot
|
83
|
-
# understands them to be commands that operate above and/or outside of the
|
84
|
-
# actual game world. Examples of Meta Actions are commands that report the
|
85
|
-
# player's current score, save and restore saved games, or list the game's
|
86
|
-
# credits.
|
87
|
-
#
|
88
|
-
# @example A simple Meta Action
|
89
|
-
# meta :credits do |actor|
|
90
|
-
# actor.tell "This game was written by John Smith."
|
91
|
-
# end
|
92
|
-
#
|
93
|
-
# @param command [Symbol] An imperative verb for the command
|
94
|
-
# @param queries [Array<Query::Base>] Filters for the command's tokens
|
95
|
-
# @yieldparam [Gamefic::Actor]
|
96
|
-
def meta(command, *queries, &block)
|
97
|
-
playbook.meta command, *queries, &block
|
98
|
-
end
|
99
|
-
|
100
|
-
# Add a proc to be evaluated before a character executes an action.
|
101
|
-
# When a verb is specified, the proc will only be evaluated if the
|
102
|
-
# action's verb matches it.
|
103
|
-
#
|
104
|
-
# @param verb [Symbol, nil]
|
105
|
-
# @yieldparam [Gamefic::Action]
|
106
|
-
def before_action verb = nil, &block
|
107
|
-
playbook.before_action verb, &block
|
108
|
-
end
|
109
|
-
alias validate before_action
|
110
|
-
|
111
|
-
# Add a proc to be evaluated after a character executes an action.
|
112
|
-
# When a verb is specified, the proc will only be evaluated if the
|
113
|
-
# action's verb matches it.
|
114
|
-
#
|
115
|
-
# @param [Symbol, nil]
|
116
|
-
# @yieldparam [Gamefic::Action]
|
117
|
-
def after_action verb = nil, &block
|
118
|
-
playbook.after_action verb, &block
|
119
|
-
end
|
120
|
-
|
121
|
-
# Create an alternate Syntax for an Action.
|
122
|
-
# The command and its translation can be parameterized.
|
123
|
-
#
|
124
|
-
# @example Create a synonym for the Inventory Action.
|
125
|
-
# interpret "catalogue", "inventory"
|
126
|
-
# # The command "catalogue" will be translated to "inventory"
|
127
|
-
#
|
128
|
-
# @example Create a parameterized synonym for the Look Action.
|
129
|
-
# interpret "scrutinize :entity", "look :entity"
|
130
|
-
# # The command "scrutinize chair" will be translated to "look chair"
|
131
|
-
#
|
132
|
-
# @param command [String] The format of the original command
|
133
|
-
# @param translation [String] The format of the translated command
|
134
|
-
# @return [Syntax] the Syntax object
|
135
|
-
def interpret command, translation
|
136
|
-
playbook.interpret command, translation
|
137
|
-
end
|
138
|
-
alias xlate interpret
|
139
|
-
|
140
|
-
# Get an Array of available verbs.
|
141
|
-
#
|
142
|
-
# @return [Array<String>]
|
143
|
-
def verbs
|
144
|
-
playbook.verbs.map(&:to_s).reject { |v| v.start_with?('_') }
|
145
|
-
end
|
146
|
-
|
147
|
-
# Get an Array of all Actions defined in the Plot.
|
148
|
-
#
|
149
|
-
# @return [Array<Action>]
|
150
|
-
def actions
|
151
|
-
playbook.actions
|
152
|
-
end
|
153
|
-
|
154
|
-
def get_default_query
|
155
|
-
@default_query_class ||= Gamefic::Query::Family
|
156
|
-
end
|
157
|
-
|
158
|
-
def set_default_query cls
|
159
|
-
@default_query_class = cls
|
160
|
-
end
|
161
|
-
|
162
|
-
private
|
163
|
-
|
164
|
-
# @param queries [Array]
|
165
|
-
# @return [Array<Query::Base>]
|
166
|
-
def map_response_args queries
|
167
|
-
queries.map do |q|
|
168
|
-
if q.is_a?(Regexp)
|
169
|
-
Gamefic::Query::Text.new(q)
|
170
|
-
elsif q.is_a?(Gamefic::Query::Base)
|
171
|
-
q
|
172
|
-
elsif q.is_a?(Gamefic::Element) || (q.is_a?(Class) && q <= Gamefic::Element)
|
173
|
-
get_default_query.new(q)
|
174
|
-
else
|
175
|
-
raise ArgumentError, "Invalid argument for response: #{q.inspect}"
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
181
|
-
end
|
@@ -1,98 +0,0 @@
|
|
1
|
-
module Gamefic
|
2
|
-
module World
|
3
|
-
module Entities
|
4
|
-
# Make a new Entity with the provided properties.
|
5
|
-
#
|
6
|
-
# @example Create an Entity
|
7
|
-
# chair = make Entity, name: 'red chair'
|
8
|
-
# chair.name #=> 'red chair'
|
9
|
-
#
|
10
|
-
# @raise [ArgumentError] if class is not an Entity
|
11
|
-
#
|
12
|
-
# @param cls [Class] The Class of the Entity to be created.
|
13
|
-
# @param args [Hash] The entity's properties.
|
14
|
-
# @!macro [attach] make_entity
|
15
|
-
# @return [$1]
|
16
|
-
def make cls, args = {}, &block
|
17
|
-
raise ArgumentError, "Invalid Entity class" unless cls.is_a?(Class) && cls <= Entity
|
18
|
-
ent = cls.new args, &block
|
19
|
-
entities.push ent
|
20
|
-
ent
|
21
|
-
end
|
22
|
-
|
23
|
-
# Cast an active entity.
|
24
|
-
# This method is similar to make, but it also provides the plot's
|
25
|
-
# playbook to the entity so it can perform actions. The entity should
|
26
|
-
# either be a kind of Gamefic::Actor or include the Gamefic::Active
|
27
|
-
# module.
|
28
|
-
#
|
29
|
-
# @return [Gamefic::Actor, Gamefic::Active]
|
30
|
-
def cast cls, args = {}, &block
|
31
|
-
ent = make cls, args, &block
|
32
|
-
ent.playbooks.push playbook
|
33
|
-
ent
|
34
|
-
end
|
35
|
-
|
36
|
-
# Safely remove an entity from a plot.
|
37
|
-
#
|
38
|
-
# If the entity is dynamic (e.g., created after a plot is already
|
39
|
-
# running), it is safe to delete it completely. Otherwise the entity
|
40
|
-
# will still be referenced in the entities array, but its parent will be
|
41
|
-
# set to nil.
|
42
|
-
#
|
43
|
-
# @param [Gamefic::Entity] The entity to remove
|
44
|
-
def destroy entity
|
45
|
-
entity.parent = nil
|
46
|
-
# index = entities.index(entity)
|
47
|
-
# return if index.nil? || index < static_entity_length - 1
|
48
|
-
# entities.delete_at index
|
49
|
-
# players.delete entity
|
50
|
-
# entity.destroy
|
51
|
-
|
52
|
-
# @todo It might make sense to destroy the entity completely now. It
|
53
|
-
# will still have a reference in the index, but that shouldn't impact
|
54
|
-
# the current state of the plot.
|
55
|
-
return if static.include?(entity)
|
56
|
-
entities.delete entity
|
57
|
-
players.delete entity
|
58
|
-
end
|
59
|
-
|
60
|
-
# Pick an entity based on its description.
|
61
|
-
# The description provided must match exactly one entity; otherwise
|
62
|
-
# an error is raised.
|
63
|
-
#
|
64
|
-
# @example Select the Entity that matches the description
|
65
|
-
# red_chair = make Entity, :name => 'red chair'
|
66
|
-
# blue_chair = make Entity, :name => 'blue chair'
|
67
|
-
# pick "red chair" #=> red_chair
|
68
|
-
# pick "blue chair" #=> blue_chair
|
69
|
-
# pick "chair" #=> IndexError: description is ambiguous
|
70
|
-
#
|
71
|
-
# @param description [String] The description of the entity
|
72
|
-
# @return [Gamefic::Entity] The entity that matches the description
|
73
|
-
def pick(description)
|
74
|
-
result = Query::Matches.execute(entities, description)
|
75
|
-
if result.objects.length == 0
|
76
|
-
raise IndexError.new("Unable to find entity from '#{description}'")
|
77
|
-
elsif result.objects.length > 1
|
78
|
-
raise IndexError.new("Ambiguous entities found from '#{description}'")
|
79
|
-
end
|
80
|
-
result.objects[0]
|
81
|
-
end
|
82
|
-
|
83
|
-
# Get an array of entities associated with this plot.
|
84
|
-
#
|
85
|
-
# @return [Array<Gamefic::Entity>]
|
86
|
-
def entities
|
87
|
-
@entities ||= []
|
88
|
-
end
|
89
|
-
|
90
|
-
# Get an array of players associated with this plot.
|
91
|
-
#
|
92
|
-
# @return [Array<Gamefic::Actor>]
|
93
|
-
def players
|
94
|
-
@players ||= []
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|