gamefic 2.0.0 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,22 +4,30 @@ module Gamefic
4
4
  class Subplot #< Container
5
5
  include World
6
6
  include Scriptable
7
+ include Gamefic::Serialize
7
8
  # @!parse extend Scriptable::ClassMethods
8
9
 
9
10
  # @return [Gamefic::Plot]
10
11
  attr_reader :plot
11
12
 
12
13
  # @param plot [Gamefic::Plot]
13
- # @param introduce [Gamefic::Actor]
14
- # @param next_cue [Class<Gamefic::Scene::Base>]
14
+ # @param introduce [Gamefic::Actor, nil]
15
+ # @param next_cue [Class<Gamefic::Scene::Base>, nil]
16
+ # @param more [Hash]
15
17
  def initialize plot, introduce: nil, next_cue: nil, **more
16
18
  @plot = plot
17
19
  @next_cue = next_cue
18
20
  @concluded = false
21
+ @more = more
19
22
  configure more
20
23
  run_scripts
21
24
  playbook.freeze
22
25
  self.introduce introduce unless introduce.nil?
26
+ @static = [self] + scene_classes + entities
27
+ end
28
+
29
+ def static
30
+ plot.static
23
31
  end
24
32
 
25
33
  def players
@@ -63,6 +71,7 @@ module Gamefic
63
71
  # @todo I'm not sure why rejecting nils is necessary here. It's only an
64
72
  # issue in Opal.
65
73
  entities.reject(&:nil?).each { |e| destroy e }
74
+ # plot.static.remove(scene_classes + entities)
66
75
  end
67
76
 
68
77
  def concluded?
@@ -86,6 +86,7 @@ module Gamefic
86
86
  end
87
87
 
88
88
  def ==(other)
89
+ return false unless other.is_a?(Syntax)
89
90
  signature == other.signature
90
91
  end
91
92
 
@@ -1,3 +1,3 @@
1
1
  module Gamefic
2
- VERSION = '2.0.0'
2
+ VERSION = '2.1.1'
3
3
  end
data/lib/gamefic/world.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  module Gamefic
2
+ # A collection of classes and modules related to generating a world model.
3
+ #
2
4
  module World
3
5
  autoload :Playbook, 'gamefic/world/playbook'
4
6
  autoload :Entities, 'gamefic/world/entities'
@@ -96,7 +96,7 @@ module Gamefic
96
96
  end
97
97
 
98
98
  # Declare a dismabiguation response for actions.
99
- # The disambigurator is executed when an action expects an argument to
99
+ # The disambiguator is executed when an action expects an argument to
100
100
  # reference a specific entity but its query matched more than one. For
101
101
  # example, "red" might refer to either a red key or a red book.
102
102
  #
@@ -144,7 +144,7 @@ module Gamefic
144
144
  #
145
145
  # @return [Array<String>]
146
146
  def verbs
147
- playbook.verbs.map { |v| v.to_s }.reject{ |v| v.start_with?('_') }
147
+ playbook.verbs.map(&:to_s).reject { |v| v.start_with?('_') }
148
148
  end
149
149
 
150
150
  # Get an Array of all Actions defined in the Plot.
@@ -164,20 +164,20 @@ module Gamefic
164
164
 
165
165
  private
166
166
 
167
+ # @param queries [Array]
168
+ # @return [Array<Query::Base>]
167
169
  def map_response_args queries
168
- result = []
169
- queries.each do |q|
170
+ queries.map do |q|
170
171
  if q.is_a?(Regexp)
171
- result.push Gamefic::Query::Text.new(q)
172
+ Gamefic::Query::Text.new(q)
172
173
  elsif q.is_a?(Gamefic::Query::Base)
173
- result.push q
174
+ q
174
175
  elsif q.is_a?(Gamefic::Element) || (q.is_a?(Class) && q <= Gamefic::Element)
175
- result.push get_default_query.new(q)
176
+ get_default_query.new(q)
176
177
  else
177
178
  raise ArgumentError.new("Invalid argument for response: #{q}")
178
179
  end
179
180
  end
180
- result
181
181
  end
182
182
  end
183
183
  end
@@ -43,11 +43,18 @@ module Gamefic
43
43
  # @param [Gamefic::Entity] The entity to remove
44
44
  def destroy entity
45
45
  entity.parent = nil
46
- index = entities.index(entity)
47
- return if index.nil? || index < static_entity_length - 1
48
- entities.delete_at index
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
49
57
  players.delete entity
50
- entity.destroy
51
58
  end
52
59
 
53
60
  # Pick an entity based on its description.
@@ -86,16 +93,6 @@ module Gamefic
86
93
  def players
87
94
  @players ||= []
88
95
  end
89
-
90
- private
91
-
92
- def mark_static_entities
93
- @static_entity_length ||= entities.length
94
- end
95
-
96
- def static_entity_length
97
- @static_entity_length || 0
98
- end
99
96
  end
100
97
  end
101
98
  end
@@ -3,6 +3,16 @@ module Gamefic
3
3
  # A collection of rules for performing commands.
4
4
  #
5
5
  class Playbook
6
+ # An array of available syntaxes.
7
+ #
8
+ # @return [Array<Gamefic::Syntax>]
9
+ attr_reader :syntaxes
10
+
11
+ # An array of defined validators.
12
+ #
13
+ # @return [Array<Proc>]
14
+ attr_reader :validators
15
+
6
16
  def initialize commands: {}, syntaxes: [], validators: [], disambiguator: nil
7
17
  @commands = commands
8
18
  @syntaxes = syntaxes
@@ -10,13 +20,6 @@ module Gamefic
10
20
  @disambiguator = disambiguator
11
21
  end
12
22
 
13
- # An array of available syntaxes.
14
- #
15
- # @return [Array<Gamefic::Syntax>]
16
- def syntaxes
17
- @syntaxes
18
- end
19
-
20
23
  # An array of available actions.
21
24
  #
22
25
  # @return [Array<Gamefic::Action>]
@@ -31,21 +34,14 @@ module Gamefic
31
34
  @commands.keys
32
35
  end
33
36
 
34
- # An array of defined validators.
35
- #
36
- # @return [Array<Proc>]
37
- def validators
38
- @validators
39
- end
40
-
41
37
  # Get the action for handling ambiguous entity references.
42
38
  #
43
39
  def disambiguator
44
40
  @disambiguator ||= Action.subclass(nil, Query::Base.new) do |actor, entities|
45
41
  definites = []
46
- entities.each { |entity|
42
+ entities.each do |entity|
47
43
  definites.push entity.definitely
48
- }
44
+ end
49
45
  actor.tell "I don't know which you mean: #{definites.join_or}."
50
46
  end
51
47
  end
@@ -66,7 +62,7 @@ module Gamefic
66
62
  # Get an Array of all Actions associated with the specified verb.
67
63
  #
68
64
  # @param verb [Symbol] The Symbol for the verb (e.g., :go or :look)
69
- # @return [Array<Action>] The verb's associated Actions
65
+ # @return [Array<Class<Action>>] The verb's associated Actions
70
66
  def actions_for verb
71
67
  @commands[verb] || []
72
68
  end
@@ -150,12 +146,8 @@ module Gamefic
150
146
  # @return [Array<Gamefic::Action>]
151
147
  def dispatch(actor, *command)
152
148
  result = []
153
- if command.length > 1
154
- result.concat dispatch_from_params(actor, command[0], command[1..-1])
155
- end
156
- if result.empty?
157
- result.concat dispatch_from_string(actor, command.join(' '))
158
- end
149
+ result.concat dispatch_from_params(actor, command[0], command[1..-1]) if command.length > 1
150
+ result.concat dispatch_from_string(actor, command.join(' ')) if result.empty?
159
151
  result
160
152
  end
161
153
 
@@ -167,14 +159,13 @@ module Gamefic
167
159
  def dispatch_from_string actor, text
168
160
  result = []
169
161
  commands = Syntax.tokenize(text, actor.syntaxes)
170
- commands.each { |c|
171
- available = actions_for(c.verb)
172
- available.each { |a|
162
+ commands.each do |c|
163
+ actions_for(c.verb).each do |a|
173
164
  next if a.hidden?
174
165
  o = a.attempt(actor, c.arguments)
175
166
  result.unshift o unless o.nil?
176
- }
177
- }
167
+ end
168
+ end
178
169
  sort_and_reduce_actions result
179
170
  end
180
171
 
@@ -185,9 +176,9 @@ module Gamefic
185
176
  def dispatch_from_params actor, verb, params
186
177
  result = []
187
178
  available = actions_for(verb)
188
- available.each { |a|
179
+ available.each do |a|
189
180
  result.unshift a.new(actor, params) if a.valid?(actor, params)
190
- }
181
+ end
191
182
  sort_and_reduce_actions result
192
183
  end
193
184
 
@@ -217,38 +208,37 @@ module Gamefic
217
208
  user_friendly = action.verb.to_s.gsub(/_/, ' ')
218
209
  args = []
219
210
  used_names = []
220
- action.queries.each { |c|
211
+ action.queries.each do |_c|
221
212
  num = 1
222
213
  new_name = ":var"
223
214
  while used_names.include? new_name
224
- num = num + 1
215
+ num += 1
225
216
  new_name = ":var#{num}"
226
217
  end
227
218
  used_names.push new_name
228
219
  user_friendly += " #{new_name}"
229
220
  args.push new_name
230
- }
221
+ end
231
222
  add_syntax Syntax.new(user_friendly.strip, "#{action.verb} #{args.join(' ')}") unless action.verb.to_s.start_with?('_')
232
223
  end
233
224
 
234
225
  def add_syntax syntax
235
- if @commands[syntax.verb] == nil
236
- raise "No actions exist for \"#{syntax.verb}\""
237
- end
226
+ raise "No actions exist for \"#{syntax.verb}\"" if @commands[syntax.verb].nil?
227
+
238
228
  @syntaxes.unshift syntax
239
- @syntaxes.uniq! &:signature
240
- @syntaxes.sort! { |a, b|
229
+ @syntaxes.uniq!(&:signature)
230
+ @syntaxes.sort! do |a, b|
241
231
  if a.token_count == b.token_count
242
232
  # For syntaxes of the same length, length of action takes precedence
243
233
  b.first_word <=> a.first_word
244
234
  else
245
235
  b.token_count <=> a.token_count
246
236
  end
247
- }
237
+ end
248
238
  end
249
239
 
250
240
  def sort_and_reduce_actions arr
251
- arr.sort_by.with_index{|a, i| [a.rank, -i]}.reverse.uniq(&:class)
241
+ arr.sort_by.with_index { |a, i| [a.rank, -i]}.reverse.uniq(&:class)
252
242
  end
253
243
  end
254
244
  end
@@ -2,6 +2,7 @@ module Gamefic
2
2
  module World
3
3
  module Players
4
4
  include Gamefic::World::Entities
5
+ include Gamefic::World::Commands
5
6
 
6
7
  # An array of entities that are currently connected to users.
7
8
  #
@@ -10,12 +11,27 @@ module Gamefic
10
11
  @players ||= []
11
12
  end
12
13
 
13
- # Get the character that the player will control on introduction.
14
+ def player_class cls = nil
15
+ STDERR.puts "Modifying player_class this way is deprecated. Use set_player_class instead" unless cls.nil?
16
+ @player_class = cls unless cls.nil?
17
+ @player_class ||= Gamefic::Actor
18
+ end
19
+
20
+ # @param cls [Class]
21
+ def set_player_class cls
22
+ unless cls < Gamefic::Active && cls <= Gamefic::Entity
23
+ raise ArgumentError, "Player class must be an active entity"
24
+ end
25
+ @player_class = cls
26
+ end
27
+
28
+ # Make a character that a player will control on introduction.
14
29
  #
15
30
  # @return [Gamefic::Actor]
16
- def get_player_character
31
+ def make_player_character
17
32
  cast player_class, name: 'yourself', synonyms: 'self myself you me', proper_named: true
18
33
  end
34
+ alias get_player_character make_player_character
19
35
  end
20
36
  end
21
37
  end
@@ -35,7 +35,7 @@ module Gamefic
35
35
  players.push player
36
36
  @introduction.call(player) unless @introduction.nil?
37
37
  # @todo Find a better way to persist player characters
38
- Gamefic::Index.stick
38
+ # Gamefic::Index.stick
39
39
  end
40
40
 
41
41
  # Create a multiple-choice scene.
@@ -95,10 +95,10 @@ module Gamefic
95
95
  #
96
96
  # @param prompt [String]
97
97
  # @yieldparam [Gamefic::Actor]
98
- # @yieldparam [Gamefic::Scene::Custom]
99
- # @return [Class<Gamefic::Scene::Custom>]
98
+ # @yieldparam [Gamefic::Scene::Base]
99
+ # @return [Class<Gamefic::Scene::Base>]
100
100
  def question prompt = 'What is your answer?', &block
101
- s = Scene::Custom.subclass do |actor, scene|
101
+ s = Scene::Base.subclass do |actor, scene|
102
102
  scene.prompt = prompt
103
103
  scene.on_finish &block
104
104
  end
@@ -144,29 +144,29 @@ module Gamefic
144
144
  scene_classes.push s
145
145
  s
146
146
  end
147
-
147
+
148
148
  # Create a custom scene.
149
149
  #
150
150
  # Custom scenes should always specify the next scene to be cued or
151
151
  # prepared. If not, the scene will get repeated on the next turn.
152
152
  #
153
- # This method creates a Scene::Custom by default. You can customize other
153
+ # This method creates a Scene::Base by default. You can customize other
154
154
  # scene types by specifying the class to create.
155
155
  #
156
156
  # @example Ask the user for a name
157
- # @scene = custom do |scene|
158
- # data.prompt = "What's your name?"
159
- # scene.on_finish do |actor, data|
160
- # actor.name = data.input
157
+ # @scene = custom do |actor, scene|
158
+ # scene.prompt = "What's your name?"
159
+ # scene.on_finish do
160
+ # actor.name = scene.input
161
161
  # actor.tell "Hello, #{actor.name}!"
162
- # actor.cue :active
162
+ # actor.cue default_scene
163
163
  # end
164
164
  # end
165
165
  #
166
166
  # @param cls [Class] The class of scene to be instantiated.
167
167
  # @yieldparam [Gamefic::Actor]
168
- # @return [Class<Gamefic::Scene::Custom>]
169
- def custom cls = Scene::Custom, &block
168
+ # @return [Class<Gamefic::Scene::Base>]
169
+ def custom cls = Scene::Base, &block
170
170
  s = cls.subclass &block
171
171
  scene_classes.push s
172
172
  s
metadata CHANGED
@@ -1,55 +1,55 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gamefic
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fred Snyder
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-24 00:00:00.000000000 Z
11
+ date: 2021-07-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '12.3'
20
- - - "~>"
20
+ - - ">="
21
21
  - !ruby/object:Gem::Version
22
22
  version: '12.3'
23
23
  type: :development
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
- - - ">="
27
+ - - "~>"
28
28
  - !ruby/object:Gem::Version
29
29
  version: '12.3'
30
- - - "~>"
30
+ - - ">="
31
31
  - !ruby/object:Gem::Version
32
32
  version: '12.3'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: rspec
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - ">="
38
- - !ruby/object:Gem::Version
39
- version: 3.5.0
40
37
  - - "~>"
41
38
  - !ruby/object:Gem::Version
42
39
  version: '3.5'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 3.5.0
43
43
  type: :development
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
46
46
  requirements:
47
- - - ">="
48
- - !ruby/object:Gem::Version
49
- version: 3.5.0
50
47
  - - "~>"
51
48
  - !ruby/object:Gem::Version
52
49
  version: '3.5'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 3.5.0
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: simplecov
55
55
  requirement: !ruby/object:Gem::Requirement
@@ -74,6 +74,7 @@ files:
74
74
  - ".rspec"
75
75
  - ".rubocop.yml"
76
76
  - ".solargraph.yml"
77
+ - CHANGELOG.md
77
78
  - Gemfile
78
79
  - LICENSE
79
80
  - README.md
@@ -89,7 +90,6 @@ files:
89
90
  - lib/gamefic/describable.rb
90
91
  - lib/gamefic/element.rb
91
92
  - lib/gamefic/entity.rb
92
- - lib/gamefic/index.rb
93
93
  - lib/gamefic/keywords.rb
94
94
  - lib/gamefic/messaging.rb
95
95
  - lib/gamefic/node.rb
@@ -108,11 +108,11 @@ files:
108
108
  - lib/gamefic/query/parent.rb
109
109
  - lib/gamefic/query/siblings.rb
110
110
  - lib/gamefic/query/text.rb
111
+ - lib/gamefic/query/tree.rb
111
112
  - lib/gamefic/scene.rb
112
113
  - lib/gamefic/scene/activity.rb
113
114
  - lib/gamefic/scene/base.rb
114
115
  - lib/gamefic/scene/conclusion.rb
115
- - lib/gamefic/scene/custom.rb
116
116
  - lib/gamefic/scene/multiple_choice.rb
117
117
  - lib/gamefic/scene/multiple_scene.rb
118
118
  - lib/gamefic/scene/pause.rb
@@ -133,7 +133,7 @@ homepage: http://gamefic.com
133
133
  licenses:
134
134
  - MIT
135
135
  metadata: {}
136
- post_install_message:
136
+ post_install_message:
137
137
  rdoc_options: []
138
138
  require_paths:
139
139
  - lib
@@ -148,8 +148,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
148
148
  - !ruby/object:Gem::Version
149
149
  version: '0'
150
150
  requirements: []
151
- rubygems_version: 3.0.3
152
- signing_key:
151
+ rubygems_version: 3.1.6
152
+ signing_key:
153
153
  specification_version: 4
154
154
  summary: Gamefic
155
155
  test_files: []