gamefic 1.5.1 → 1.6.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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/lib/gamefic.rb +1 -3
  3. data/lib/gamefic/action.rb +140 -79
  4. data/lib/gamefic/character.rb +120 -53
  5. data/lib/gamefic/character/state.rb +12 -0
  6. data/lib/gamefic/core_ext/array.rb +53 -11
  7. data/lib/gamefic/core_ext/string.rb +1 -0
  8. data/lib/gamefic/describable.rb +37 -11
  9. data/lib/gamefic/engine/base.rb +17 -4
  10. data/lib/gamefic/engine/tty.rb +4 -0
  11. data/lib/gamefic/entity.rb +4 -15
  12. data/lib/gamefic/matchable.rb +50 -0
  13. data/lib/gamefic/messaging.rb +45 -0
  14. data/lib/gamefic/node.rb +16 -0
  15. data/lib/gamefic/plot.rb +27 -33
  16. data/lib/gamefic/plot/{article_mount.rb → articles.rb} +22 -22
  17. data/lib/gamefic/plot/callbacks.rb +30 -4
  18. data/lib/gamefic/plot/{command_mount.rb → commands.rb} +121 -121
  19. data/lib/gamefic/plot/entities.rb +3 -3
  20. data/lib/gamefic/plot/host.rb +3 -3
  21. data/lib/gamefic/plot/playbook.rb +74 -30
  22. data/lib/gamefic/plot/scenes.rb +149 -0
  23. data/lib/gamefic/plot/snapshot.rb +14 -39
  24. data/lib/gamefic/plot/theater.rb +73 -0
  25. data/lib/gamefic/query.rb +6 -19
  26. data/lib/gamefic/query/base.rb +127 -246
  27. data/lib/gamefic/query/children.rb +6 -7
  28. data/lib/gamefic/query/descendants.rb +15 -0
  29. data/lib/gamefic/query/family.rb +19 -7
  30. data/lib/gamefic/query/itself.rb +13 -0
  31. data/lib/gamefic/query/matches.rb +67 -11
  32. data/lib/gamefic/query/parent.rb +6 -7
  33. data/lib/gamefic/query/siblings.rb +10 -7
  34. data/lib/gamefic/query/text.rb +39 -35
  35. data/lib/gamefic/scene.rb +1 -1
  36. data/lib/gamefic/scene/active.rb +12 -6
  37. data/lib/gamefic/scene/base.rb +56 -5
  38. data/lib/gamefic/scene/conclusion.rb +3 -0
  39. data/lib/gamefic/scene/custom.rb +0 -83
  40. data/lib/gamefic/scene/multiple_choice.rb +54 -32
  41. data/lib/gamefic/scene/multiple_scene.rb +11 -6
  42. data/lib/gamefic/scene/pause.rb +3 -4
  43. data/lib/gamefic/scene/yes_or_no.rb +23 -9
  44. data/lib/gamefic/script/base.rb +4 -0
  45. data/lib/gamefic/subplot.rb +22 -19
  46. data/lib/gamefic/syntax.rb +7 -15
  47. data/lib/gamefic/user/base.rb +7 -13
  48. data/lib/gamefic/user/buffer.rb +7 -0
  49. data/lib/gamefic/user/tty.rb +13 -12
  50. data/lib/gamefic/version.rb +1 -1
  51. metadata +11 -37
  52. data/lib/gamefic/director.rb +0 -23
  53. data/lib/gamefic/director/delegate.rb +0 -126
  54. data/lib/gamefic/director/order.rb +0 -17
  55. data/lib/gamefic/director/parser.rb +0 -137
  56. data/lib/gamefic/keywords.rb +0 -67
  57. data/lib/gamefic/plot/query_mount.rb +0 -9
  58. data/lib/gamefic/plot/scene_mount.rb +0 -182
  59. data/lib/gamefic/query/ambiguous_children.rb +0 -5
  60. data/lib/gamefic/query/expression.rb +0 -47
  61. data/lib/gamefic/query/many_children.rb +0 -7
  62. data/lib/gamefic/query/plural_children.rb +0 -14
  63. data/lib/gamefic/query/self.rb +0 -10
  64. data/lib/gamefic/scene_data.rb +0 -10
  65. data/lib/gamefic/scene_data/base.rb +0 -12
  66. data/lib/gamefic/scene_data/multiple_choice.rb +0 -19
  67. data/lib/gamefic/scene_data/multiple_scene.rb +0 -21
  68. data/lib/gamefic/scene_data/yes_or_no.rb +0 -18
  69. data/lib/gamefic/serialized.rb +0 -24
  70. data/lib/gamefic/stage.rb +0 -106
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gamefic
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fred Snyder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-23 00:00:00.000000000 Z
11
+ date: 2017-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -90,20 +90,6 @@ dependencies:
90
90
  - - ">="
91
91
  - !ruby/object:Gem::Version
92
92
  version: 11.3.0
93
- - !ruby/object:Gem::Dependency
94
- name: poltergeist
95
- requirement: !ruby/object:Gem::Requirement
96
- requirements:
97
- - - "~>"
98
- - !ruby/object:Gem::Version
99
- version: '1.11'
100
- type: :development
101
- prerelease: false
102
- version_requirements: !ruby/object:Gem::Requirement
103
- requirements:
104
- - - "~>"
105
- - !ruby/object:Gem::Version
106
- version: '1.11'
107
93
  - !ruby/object:Gem::Dependency
108
94
  name: codeclimate-test-reporter
109
95
  requirement: !ruby/object:Gem::Requirement
@@ -135,14 +121,11 @@ files:
135
121
  - lib/gamefic.rb
136
122
  - lib/gamefic/action.rb
137
123
  - lib/gamefic/character.rb
124
+ - lib/gamefic/character/state.rb
138
125
  - lib/gamefic/command.rb
139
126
  - lib/gamefic/core_ext/array.rb
140
127
  - lib/gamefic/core_ext/string.rb
141
128
  - lib/gamefic/describable.rb
142
- - lib/gamefic/director.rb
143
- - lib/gamefic/director/delegate.rb
144
- - lib/gamefic/director/order.rb
145
- - lib/gamefic/director/parser.rb
146
129
  - lib/gamefic/engine.rb
147
130
  - lib/gamefic/engine/base.rb
148
131
  - lib/gamefic/engine/tty.rb
@@ -157,31 +140,29 @@ files:
157
140
  - lib/gamefic/grammar/verb_set.rb
158
141
  - lib/gamefic/grammar/verbs.rb
159
142
  - lib/gamefic/grammar/word_adapter.rb
160
- - lib/gamefic/keywords.rb
143
+ - lib/gamefic/matchable.rb
144
+ - lib/gamefic/messaging.rb
161
145
  - lib/gamefic/node.rb
162
146
  - lib/gamefic/plot.rb
163
- - lib/gamefic/plot/article_mount.rb
147
+ - lib/gamefic/plot/articles.rb
164
148
  - lib/gamefic/plot/callbacks.rb
165
- - lib/gamefic/plot/command_mount.rb
149
+ - lib/gamefic/plot/commands.rb
166
150
  - lib/gamefic/plot/entities.rb
167
151
  - lib/gamefic/plot/host.rb
168
152
  - lib/gamefic/plot/playbook.rb
169
153
  - lib/gamefic/plot/players.rb
170
- - lib/gamefic/plot/query_mount.rb
171
- - lib/gamefic/plot/scene_mount.rb
154
+ - lib/gamefic/plot/scenes.rb
172
155
  - lib/gamefic/plot/snapshot.rb
156
+ - lib/gamefic/plot/theater.rb
173
157
  - lib/gamefic/plot/you_mount.rb
174
158
  - lib/gamefic/query.rb
175
- - lib/gamefic/query/ambiguous_children.rb
176
159
  - lib/gamefic/query/base.rb
177
160
  - lib/gamefic/query/children.rb
178
- - lib/gamefic/query/expression.rb
161
+ - lib/gamefic/query/descendants.rb
179
162
  - lib/gamefic/query/family.rb
180
- - lib/gamefic/query/many_children.rb
163
+ - lib/gamefic/query/itself.rb
181
164
  - lib/gamefic/query/matches.rb
182
165
  - lib/gamefic/query/parent.rb
183
- - lib/gamefic/query/plural_children.rb
184
- - lib/gamefic/query/self.rb
185
166
  - lib/gamefic/query/siblings.rb
186
167
  - lib/gamefic/query/text.rb
187
168
  - lib/gamefic/scene.rb
@@ -193,22 +174,15 @@ files:
193
174
  - lib/gamefic/scene/multiple_scene.rb
194
175
  - lib/gamefic/scene/pause.rb
195
176
  - lib/gamefic/scene/yes_or_no.rb
196
- - lib/gamefic/scene_data.rb
197
- - lib/gamefic/scene_data/base.rb
198
- - lib/gamefic/scene_data/multiple_choice.rb
199
- - lib/gamefic/scene_data/multiple_scene.rb
200
- - lib/gamefic/scene_data/yes_or_no.rb
201
177
  - lib/gamefic/script.rb
202
178
  - lib/gamefic/script/base.rb
203
179
  - lib/gamefic/script/file.rb
204
180
  - lib/gamefic/script/text.rb
205
- - lib/gamefic/serialized.rb
206
181
  - lib/gamefic/shell.rb
207
182
  - lib/gamefic/source.rb
208
183
  - lib/gamefic/source/base.rb
209
184
  - lib/gamefic/source/file.rb
210
185
  - lib/gamefic/source/text.rb
211
- - lib/gamefic/stage.rb
212
186
  - lib/gamefic/subplot.rb
213
187
  - lib/gamefic/syntax.rb
214
188
  - lib/gamefic/tester.rb
@@ -1,23 +0,0 @@
1
- module Gamefic
2
-
3
- module Director
4
- autoload :Parser, 'gamefic/director/parser'
5
- autoload :Delegate, 'gamefic/director/delegate'
6
- autoload :Order, 'gamefic/director/order'
7
-
8
- def self.dispatch(actor, *args)
9
- orders = []
10
- if args.length > 1
11
- orders = Parser.from_tokens(actor, args)
12
- end
13
- if orders.length == 0
14
- orders = Parser.from_string(actor, args.join(' ').strip)
15
- end
16
- first_order = orders[0]
17
- del = Delegate.new(actor, orders)
18
- del.execute
19
- first_order
20
- end
21
- end
22
-
23
- end
@@ -1,126 +0,0 @@
1
- module Gamefic
2
- module Director
3
- class Delegate
4
-
5
- class << self
6
- def proceed_for actor
7
- return if stack_map[actor].nil?
8
- stack_map[actor].last.proceed unless stack_map[actor].last.nil?
9
- end
10
-
11
- private
12
-
13
- def stack_map
14
- @stack_map ||= {}
15
- end
16
- end
17
-
18
- def initialize(actor, orders)
19
- @actor = actor
20
- @orders = orders
21
- @did = []
22
- @validated = false
23
- end
24
-
25
- def proceed
26
- return if @orders.length == 0
27
- executed = false
28
- while !executed
29
- order = @orders.shift
30
- break if order.nil?
31
- # HACK: Make sure Character#proceed does not repeat an action
32
- next if @did.include?(order.action)
33
- @did.push order.action
34
- @last_action = order.action
35
- executed = attempt(order)
36
- return if order.canceled?
37
- end
38
- end
39
-
40
- def execute
41
- return if @orders.length == 0
42
- stack_map[@actor] ||= []
43
- stack_map[@actor].push self
44
- proceed
45
- stack_map[@actor].pop
46
- stack_map.delete @actor if stack_map[@actor].empty?
47
- end
48
-
49
- private
50
-
51
- def attempt order
52
- executed = false
53
- arg_i = 0
54
- final_arguments = []
55
- order.arguments.each { |argument|
56
- if argument.length > 1 and !order.action.queries[arg_i].allow_many?
57
- if argument[0].kind_of?(Array)
58
- # This thing refers to multiple items. Just keep going.
59
- final_arguments = nil
60
- break
61
- else
62
- ambiguous = argument
63
- end
64
- order = Order.new(@actor, @actor.playbook.disambiguator, [])
65
- final_arguments = [ambiguous]
66
- break
67
- end
68
- if order.action.queries[arg_i].allow_ambiguous?
69
- valid = argument.flatten
70
- else
71
- valid = validate(argument, arg_i, order)
72
- if valid.nil?
73
- final_arguments = nil
74
- break
75
- end
76
- end
77
- if order.action == @actor.playbook.disambiguator or final_arguments.nil?
78
- break
79
- end
80
- if order.action.queries[arg_i].allow_many?
81
- final_arguments.push valid.flatten
82
- elsif valid.length == 1
83
- final_arguments.push valid[0]
84
- else
85
- final_arguments = nil
86
- break
87
- end
88
- arg_i += 1
89
- }
90
- if !final_arguments.nil?
91
- unless @validated or order.action.meta?
92
- @actor.playbook.validators.each { |v|
93
- v.call order
94
- return false if order.canceled?
95
- }
96
- end
97
- @validated = true
98
- # The actor is always the first argument to an Action proc
99
- final_arguments.unshift @actor
100
- order.action.execute(*final_arguments)
101
- executed = true
102
- end
103
- executed
104
- end
105
-
106
- def validate argument, arg_i, order
107
- valid = []
108
- argument.each { |m|
109
- if order.action.queries[arg_i].validate(@actor, m)
110
- valid.push m
111
- else
112
- valid = nil
113
- break
114
- end
115
- }
116
- valid
117
- end
118
-
119
- private
120
-
121
- def stack_map
122
- Delegate.send(:stack_map)
123
- end
124
- end
125
- end
126
- end
@@ -1,17 +0,0 @@
1
- module Gamefic
2
- class Director::Order
3
- attr_reader :actor, :action, :arguments
4
- def initialize(actor, action, arguments)
5
- @actor = actor
6
- @action = action
7
- @arguments = arguments
8
- @canceled = false
9
- end
10
- def cancel
11
- @canceled = true
12
- end
13
- def canceled?
14
- @canceled
15
- end
16
- end
17
- end
@@ -1,137 +0,0 @@
1
- require 'gamefic/director/order'
2
-
3
- module Gamefic
4
- module Director
5
-
6
- module Parser
7
- def self.from_tokens(actor, tokens)
8
- options = []
9
- command = tokens.shift
10
- actions = actor.playbook.actions_for(command.to_sym)
11
- actions.each { |action|
12
- if action.queries.length == tokens.length
13
- valid = true
14
- index = 0
15
- action.queries.each { |query|
16
- if query.validate(actor, tokens[index]) == false
17
- valid = false
18
- break
19
- end
20
- index += 1
21
- }
22
- if valid
23
- arguments = []
24
- tokens.each { |token|
25
- arguments.push [token]
26
- }
27
- options.push Order.new(actor, action, arguments)
28
- end
29
- end
30
- }
31
- if options.length == 0
32
- tokens.unshift command
33
- end
34
- # HACK: This sort is necessary for a problem on Windows.
35
- options.sort{ |a,b|
36
- if a.action.specificity == b.action.specificity
37
- # Newer action takes precedence
38
- b.action.order_key <=> a.action.order_key
39
- else
40
- # Higher specificity takes precedence
41
- b.action.specificity <=> a.action.specificity
42
- end
43
- }
44
- end
45
- def self.from_string(actor, command)
46
- options = []
47
- if command.to_s == ''
48
- return options
49
- end
50
- matches = Syntax.tokenize(command, actor.playbook.syntaxes)
51
- matches.each { |match|
52
- actions = actor.playbook.actions_for(match.verb)
53
- actions.each { |action|
54
- options.concat bind_contexts_in_result(actor, match.arguments, action)
55
- }
56
- }
57
- # HACK: This sort is necessary for a problem on Windows.
58
- options.sort{ |a,b|
59
- if a.action.specificity == b.action.specificity
60
- # Newer action takes precedence
61
- b.action.order_key <=> a.action.order_key
62
- else
63
- # Higher specificity takes precedence
64
- b.action.specificity <=> a.action.specificity
65
- end
66
- }
67
- end
68
- class << self
69
- private
70
- def bind_contexts_in_result(actor, handler, action)
71
- queries = action.queries.clone
72
- objects = execute_query(actor, handler.clone, queries, action)
73
- num_nil = 0
74
- #while objects.length == 0 and queries.last.optional?
75
- # num_nil +=1
76
- # queries.pop
77
- # objects = execute_query(actor, handler.clone, queries, action, num_nil)
78
- #end
79
- return objects
80
- end
81
- def execute_query(actor, arguments, queries, action, num_nil = 0)
82
- # If the action verb is nil, treat the first argument as a query
83
- #arguments.shift unless action.verb.nil?
84
- prepared = []
85
- objects = []
86
- valid = true
87
- last_remainder = nil
88
- queries.clone.each { |context|
89
- arg = arguments.shift.to_s
90
- if last_remainder.to_s > ''
91
- arg = (last_remainder + " " + arg).strip
92
- end
93
- if arg.nil? or arg == ''
94
- valid = false
95
- next
96
- end
97
- if context == String
98
- prepared.push [arg]
99
- elsif context.kind_of?(Query::Base)
100
- result = context.execute(actor, arg)
101
- if result.objects.length == 0
102
- valid = false
103
- next
104
- else
105
- prepared.push result.objects
106
- last_remainder = result.remainder
107
- end
108
- else
109
- raise TypeError.new("Action parameters must inherit from Query::Base")
110
- end
111
- }
112
- if valid == true
113
- if last_remainder.nil? or last_remainder.empty?
114
- prepared.each { |p|
115
- p.uniq!
116
- }
117
- num_nil.times do
118
- prepared.push [nil]
119
- end
120
- objects.push Order.new(actor, action, prepared)
121
- else
122
- if !action.queries.last.allow_many? or action.queries.last.allow_ambiguous?
123
- misunderstood = Action.new nil, Query::Text.new do |actor, text|
124
- actor.tell "I understand the first part of your command but not \"#{text}.\""
125
- end
126
- misunderstood.meta = true
127
- objects.push Order.new(actor, misunderstood, [[last_remainder]])
128
- end
129
- end
130
- end
131
- objects
132
- end
133
- end
134
- end
135
-
136
- end
137
- end
@@ -1,67 +0,0 @@
1
- # Arrays of keywords that can be compared for matches.
2
-
3
- module Gamefic
4
-
5
- class Keywords < Array
6
- def initialize(statement = '')
7
- if statement.kind_of?(Keywords)
8
- self.concat statement
9
- else
10
- if statement.kind_of?(Array)
11
- statement = statement.join(' ')
12
- end
13
- self.concat statement.to_s.gsub(/[^a-z0-9]/i, ' ').strip.downcase.split(' ')
14
- end
15
- self
16
- end
17
-
18
- # Count the number of matching words in another Keywords array.
19
- # The total includes partial matches; for example, "gre" is a 0.6 match
20
- # for "green".
21
- #
22
- # @return [Float] The total number of matches
23
- def found_in(other, fuzzy = false)
24
- matches = 0.0
25
- self.each { |my_word|
26
- if other.include?(my_word)
27
- matches = matches + 1.0
28
- else
29
- other.each { |other_word|
30
- if my_word.length < other_word.length
31
- if other_word[0, my_word.length] == my_word and my_word.length > 2
32
- matches = matches + (my_word.length.to_f / other_word.length.to_f)
33
- end
34
- elsif fuzzy
35
- fuzzy_word = fuzzify my_word
36
- if other_word[0, fuzzy_word.length] == fuzzy_word and fuzzy_word.length > 2
37
- matches = matches + (fuzzy_word.length.to_f / other_word.length.to_f)
38
- elsif fuzzy_word[0, other_word.length] == other_word and other_word.length > 2
39
- matches = matches + (fuzzy_word.length.to_f / other_word.length.to_f)
40
- end
41
- end
42
- }
43
- end
44
- }
45
- matches
46
- end
47
-
48
- def to_s
49
- self.join(' ')
50
- end
51
-
52
- private
53
-
54
- def fuzzify word
55
- if word.end_with?('ies')
56
- word[0..-4]
57
- elsif word.end_with?('ae')
58
- word[0..-3]
59
- elsif word.end_with?('s') or word.end_with?('i')
60
- word[0..-2]
61
- else
62
- word
63
- end
64
- end
65
- end
66
-
67
- end