gamefic 0.2.0 → 0.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 (128) hide show
  1. checksums.yaml +4 -4
  2. data/lib/gamefic/action.rb +87 -56
  3. data/lib/gamefic/ansi.rb +55 -0
  4. data/lib/gamefic/character.rb +130 -76
  5. data/lib/gamefic/command.rb +19 -0
  6. data/lib/gamefic/core_ext/array.rb +51 -40
  7. data/lib/gamefic/core_ext/string.rb +4 -0
  8. data/lib/gamefic/describable.rb +108 -46
  9. data/lib/gamefic/direction.rb +46 -0
  10. data/lib/gamefic/director/delegate.rb +91 -0
  11. data/lib/gamefic/director/order.rb +10 -0
  12. data/lib/gamefic/director/parser.rb +119 -0
  13. data/lib/gamefic/director.rb +16 -197
  14. data/lib/gamefic/engine/cgi.rb +221 -0
  15. data/lib/gamefic/engine/tty.rb +237 -0
  16. data/lib/gamefic/engine.rb +88 -67
  17. data/lib/gamefic/entity.rb +96 -69
  18. data/lib/gamefic/grammar/conjugator.rb +20 -0
  19. data/lib/gamefic/grammar/gender.rb +11 -0
  20. data/lib/gamefic/grammar/person.rb +10 -0
  21. data/lib/gamefic/grammar/plural.rb +13 -0
  22. data/lib/gamefic/grammar/pronouns.rb +60 -0
  23. data/lib/gamefic/grammar/tense.rb +6 -0
  24. data/lib/gamefic/grammar/verb_set.rb +43 -0
  25. data/lib/gamefic/grammar/verbs.rb +25 -0
  26. data/lib/gamefic/grammar/word_adapter.rb +36 -0
  27. data/lib/gamefic/grammar.rb +13 -0
  28. data/lib/gamefic/html.rb +53 -0
  29. data/lib/gamefic/keywords.rb +51 -33
  30. data/lib/gamefic/node.rb +65 -58
  31. data/lib/gamefic/plot/article_mount.rb +22 -0
  32. data/lib/gamefic/plot/command_mount.rb +88 -0
  33. data/lib/gamefic/plot/entity_mount.rb +45 -0
  34. data/lib/gamefic/plot/query_mount.rb +9 -0
  35. data/lib/gamefic/plot/scene_mount.rb +181 -0
  36. data/lib/gamefic/plot/you_mount.rb +22 -0
  37. data/lib/gamefic/plot.rb +296 -247
  38. data/lib/gamefic/query/ambiguous_children.rb +5 -0
  39. data/lib/gamefic/query/base.rb +265 -0
  40. data/lib/gamefic/query/children.rb +10 -0
  41. data/lib/gamefic/query/expression.rb +47 -0
  42. data/lib/gamefic/query/family.rb +10 -0
  43. data/lib/gamefic/query/many_children.rb +7 -0
  44. data/lib/gamefic/query/matches.rb +11 -0
  45. data/lib/gamefic/query/parent.rb +10 -0
  46. data/lib/gamefic/query/plural_children.rb +14 -0
  47. data/lib/gamefic/query/self.rb +10 -0
  48. data/lib/gamefic/query/siblings.rb +10 -0
  49. data/lib/gamefic/query/text.rb +43 -0
  50. data/lib/gamefic/query.rb +19 -203
  51. data/lib/gamefic/rule.rb +18 -0
  52. data/lib/gamefic/scene/active.rb +25 -0
  53. data/lib/gamefic/scene/concluded.rb +22 -0
  54. data/lib/gamefic/scene/multiplechoice.rb +74 -0
  55. data/lib/gamefic/scene/paused.rb +26 -0
  56. data/lib/gamefic/scene/yesorno.rb +43 -0
  57. data/lib/gamefic/scene.rb +125 -0
  58. data/lib/gamefic/script/base.rb +33 -0
  59. data/lib/gamefic/script/file.rb +14 -0
  60. data/lib/gamefic/script/text.rb +14 -0
  61. data/lib/gamefic/script.rb +9 -0
  62. data/lib/gamefic/serialized.rb +24 -0
  63. data/lib/gamefic/shell.rb +9 -247
  64. data/lib/gamefic/snapshots.rb +134 -0
  65. data/lib/gamefic/source/base.rb +12 -0
  66. data/lib/gamefic/source/file.rb +23 -0
  67. data/lib/gamefic/source/text.rb +16 -0
  68. data/lib/gamefic/source.rb +9 -0
  69. data/lib/gamefic/stage.rb +75 -0
  70. data/lib/gamefic/syntax.rb +106 -124
  71. data/lib/gamefic/tester.rb +20 -0
  72. data/lib/gamefic/version.rb +3 -0
  73. data/lib/gamefic.rb +18 -12
  74. metadata +102 -70
  75. data/lib/gamefic/base.rb +0 -10
  76. data/lib/gamefic/before.rb +0 -12
  77. data/lib/gamefic/import/basics/actions/close.rb +0 -16
  78. data/lib/gamefic/import/basics/actions/commands.rb +0 -3
  79. data/lib/gamefic/import/basics/actions/drop-in.rb +0 -17
  80. data/lib/gamefic/import/basics/actions/drop-on.rb +0 -16
  81. data/lib/gamefic/import/basics/actions/drop.rb +0 -30
  82. data/lib/gamefic/import/basics/actions/enter.rb +0 -16
  83. data/lib/gamefic/import/basics/actions/go.rb +0 -35
  84. data/lib/gamefic/import/basics/actions/inventory.rb +0 -8
  85. data/lib/gamefic/import/basics/actions/leave.rb +0 -29
  86. data/lib/gamefic/import/basics/actions/look-in-at.rb +0 -27
  87. data/lib/gamefic/import/basics/actions/look-under.rb +0 -3
  88. data/lib/gamefic/import/basics/actions/look.rb +0 -71
  89. data/lib/gamefic/import/basics/actions/nil.rb +0 -25
  90. data/lib/gamefic/import/basics/actions/open.rb +0 -23
  91. data/lib/gamefic/import/basics/actions/quit.rb +0 -3
  92. data/lib/gamefic/import/basics/actions/take.rb +0 -107
  93. data/lib/gamefic/import/basics/entities/container.rb +0 -8
  94. data/lib/gamefic/import/basics/entities/entity.rb +0 -11
  95. data/lib/gamefic/import/basics/entities/fixture.rb +0 -5
  96. data/lib/gamefic/import/basics/entities/item.rb +0 -5
  97. data/lib/gamefic/import/basics/entities/portal.rb +0 -40
  98. data/lib/gamefic/import/basics/entities/room.rb +0 -30
  99. data/lib/gamefic/import/basics/entities/scenery.rb +0 -5
  100. data/lib/gamefic/import/basics/entities/supporter.rb +0 -6
  101. data/lib/gamefic/import/basics/entities/thing.rb +0 -16
  102. data/lib/gamefic/import/basics/queries/reachable.rb +0 -38
  103. data/lib/gamefic/import/basics/queries/room.rb +0 -8
  104. data/lib/gamefic/import/basics/queries/visible.rb +0 -32
  105. data/lib/gamefic/import/basics/rules/has-enough-light.rb +0 -14
  106. data/lib/gamefic/import/basics.old/actions/container.rb +0 -112
  107. data/lib/gamefic/import/basics.old/actions/inventory.rb +0 -50
  108. data/lib/gamefic/import/basics.old/actions/look.rb +0 -53
  109. data/lib/gamefic/import/basics.old/actions/meta.rb +0 -6
  110. data/lib/gamefic/import/basics.old/actions/traversal.rb +0 -35
  111. data/lib/gamefic/import/basics.old/actions.rb +0 -1
  112. data/lib/gamefic/import/basics.old/entities/container.rb +0 -3
  113. data/lib/gamefic/import/basics.old/entities/fixture.rb +0 -3
  114. data/lib/gamefic/import/basics.old/entities/item.rb +0 -3
  115. data/lib/gamefic/import/basics.old/entities/portal.rb +0 -43
  116. data/lib/gamefic/import/basics.old/entities/room.rb +0 -27
  117. data/lib/gamefic/import/basics.old/entities/scenery.rb +0 -3
  118. data/lib/gamefic/import/basics.old/entities/supporter.rb +0 -3
  119. data/lib/gamefic/import/basics.old/entities.rb +0 -1
  120. data/lib/gamefic/import/basics.old/room_modes.rb +0 -48
  121. data/lib/gamefic/import/basics.rb +0 -6
  122. data/lib/gamefic/import/room_modes.rb +0 -48
  123. data/lib/gamefic/import/standard.rb +0 -1
  124. data/lib/gamefic/meta.rb +0 -12
  125. data/lib/gamefic/optionset.rb +0 -114
  126. data/lib/gamefic/requirement.rb +0 -14
  127. data/lib/gamefic/story.rb +0 -14
  128. data/lib/gamefic/thing.rb +0 -7
data/lib/gamefic/plot.rb CHANGED
@@ -1,238 +1,297 @@
1
+ # TODO: JSON support is currently experimental.
2
+ #require 'gamefic/entityloader'
3
+ require 'gamefic/stage'
4
+ require 'gamefic/tester'
5
+ require 'gamefic/source'
6
+ require 'gamefic/script'
7
+ require 'gamefic/query'
8
+ require 'gamefic/plot/article_mount'
9
+ require 'gamefic/plot/you_mount'
10
+
1
11
  module Gamefic
2
12
 
3
- def self.bind(plot)
4
- mod = Module.new do
5
- def self.bind(plot)
6
- @@plot = plot
7
- end
8
- def self.get_binding
9
- binding
10
- end
11
- def self.method_missing(name, *args, &block)
12
- if @@plot.respond_to?(name)
13
- @@plot.send name, *args, &block
14
- elsif Gamefic.respond_to?(name)
15
- Gamefic.send name, *args, &block
16
- end
17
- end
13
+ class Plot
14
+ autoload :SceneMount, 'gamefic/plot/scene_mount'
15
+ autoload :CommandMount, 'gamefic/plot/command_mount'
16
+ autoload :EntityMount, 'gamefic/plot/entity_mount'
17
+ autoload :QueryMount, 'gamefic/plot/query_mount'
18
+ #autoload :ArticleMount, 'gamefic/plot/article_mount'
19
+ #autoload :YouMount, 'gamefic/plot/you_mount'
20
+ attr_reader :commands, :imported_scripts, :rules, :asserts, :source
21
+ attr_accessor :default_scene
22
+ include Stage
23
+ # TODO This include is only here to make the module's methods visible in the IDE.
24
+ # Gamefic Studio has a PlotStageMetaMapper that handles it, but it doesn't run if
25
+ # the plugin isn't activated.
26
+ include Gamefic, Tester, SceneMount, CommandMount, EntityMount, QueryMount, ArticleMount, YouMount
27
+ mount Gamefic, Tester, SceneMount, CommandMount, EntityMount, QueryMount, ArticleMount, YouMount
28
+ expose :script, :introduction, :assert_action, :on_update, :on_player_update, :entities, :on_ready, :on_player_ready, :players
29
+
30
+ # @param [Source::Base]
31
+ def initialize(source = nil)
32
+ @source = source || Source::Text.new({})
33
+ @commands = Hash.new
34
+ @syntaxes = Array.new
35
+ @ready_procs = Array.new
36
+ @update_procs = Array.new
37
+ @player_ready = Array.new
38
+ @player_procs = Array.new
39
+ @working_scripts = Array.new
40
+ @imported_scripts = Array.new
41
+ @entities = Array.new
42
+ @players = Array.new
43
+ @asserts = Hash.new
44
+ @default_scene = :active
45
+ post_initialize
18
46
  end
19
- mod.bind plot
20
- mod.get_binding
21
- end
22
-
23
- def self.safe_level
24
- @@safe_level ||= (RUBY_VERSION.split('.')[0].to_i < 2 ? 2 : 3)
25
- end
26
-
27
- class Plot
28
- attr_reader :scenes, :commands, :conclusions, :imported_scripts, :rules
29
- attr_accessor :story
30
- include OptionMap
31
- def commandwords
32
- words = Array.new
33
- @syntaxes.each { |s|
34
- word = s.template[0]
35
- words.push(word) if !word.kind_of?(Symbol)
36
- }
37
- words.uniq
38
- end
39
- def initialize
40
- @scenes = Hash.new
41
- @commands = Hash.new
42
- @syntaxes = Array.new
43
- @conclusions = Hash.new
44
- @update_procs = Array.new
45
- @available_scripts = Hash.new
46
- @imported_scripts = Array.new
47
- @entities = Array.new
48
- @rules = Hash.new
49
- post_initialize
50
- end
51
- def assert name, &block
52
- @rules[name] = Requirement.new self, name, &block
47
+
48
+ # Get an Array of all Actions defined in the Plot.
49
+ #
50
+ # @return Array[Action]
51
+ def actions
52
+ @commands.values.flatten
53
53
  end
54
- def post_initialize
54
+
55
+ # Get an Array of all Actions associated with the specified verb.
56
+ #
57
+ # @param verb [Symbol] The Symbol for the verb (e.g., :go or :look)
58
+ # @return Array<Action> The verb's associated Actions
59
+ def actions_with_verb(verb)
60
+ @commands[verb].clone || []
61
+ end
62
+
63
+ # Get an Array of all scripts that have been imported into the Plot.
64
+ #
65
+ # @return [Array<Script>] The imported scripts
66
+ def imported_scripts
67
+ @imported_scripts ||= []
68
+ end
69
+
70
+ # Add a Block to be executed for the given verb.
71
+ # If the block returns false, the Action is cancelled.
72
+ #
73
+ # @example Require the player to have a property enabled before performing the Action.
74
+ # assert_action :authorize do |actor, verb, arguments|
75
+ # if actor[:can_authorize] == true
76
+ # true
77
+ # else
78
+ # actor.tell "You don't have permission to use the authorize command."
79
+ # false
80
+ # end
81
+ # end
82
+ #
83
+ # @yieldparam [Character] The character performing the Action.
84
+ # @yieldparam [Symbol] The verb associated with the Action.
85
+ # @yieldparam [Array] The arguments that will be passed to the Action's #execute method.
86
+ def assert_action name, &block
87
+ @asserts[name] = Assert.new(name, &block)
88
+ end
89
+
90
+ def post_initialize
55
91
  # TODO: Should this method be required by extended classes?
56
- end
57
- def meta(command, *queries, &proc)
58
- act = Meta.new(self, command, *queries, &proc)
59
- end
60
- def action(command, *queries, &proc)
61
- act = Action.new(self, command, *queries, &proc)
62
- end
63
- def respond(command, *queries, &proc)
64
- self.action(command, *queries, &proc)
65
- end
66
- def before(command, *queries, &proc)
67
- bef = Before.new(self, command, *queries, &proc)
68
- end
69
- def make(cls, args = {})
70
- ent = cls.new(self, args)
71
- if ent.kind_of?(Entity) == false
72
- raise "Invalid entity class"
73
- end
74
- ent
75
- end
76
- def syntax(*args)
77
- xlate *args
78
- end
79
- def xlate(*args)
80
- syn = Syntax.new(self, *args)
81
- @syntaxes.push syn
82
- syn
83
- end
84
- def entities
85
- @entities.clone
86
- end
87
- def syntaxes
88
- @syntaxes.clone
89
- end
90
- def on_update(&block)
91
- @update_procs.push block
92
- end
93
- def introduction (&proc)
94
- @introduction = proc
95
- end
96
- def conclusion(key, &proc)
97
- @conclusions[key] = proc
98
- end
99
- def scene(key, &proc)
100
- @scenes[key] = proc
101
- end
102
- def introduce(player)
103
- if @introduction != nil
104
- @introduction.call(player)
105
- end
106
- end
107
- def conclude(player, key = nil)
108
- if key != nil and @conclusions[key]
109
- @conclusions[key].call(player)
110
- player.state = GameOverState.new(player)
111
- end
112
- end
113
- def cue scene
114
- @scenes[scene].call
115
- end
116
- def passthru
117
- Director::Delegate.passthru
118
- end
119
- def pass requirement
120
- Director::Delegate.pass requirement
121
92
  end
122
- def deny requirement
123
- Director::Delegate.deny requirement
93
+
94
+ # Get an Array of the Plot's current Entities.
95
+ #
96
+ # @return [Array<Entity>]
97
+ def entities
98
+ @entities.clone
124
99
  end
125
- def update
126
- @update_procs.each { |p|
127
- p.call
128
- }
129
- @entities.each { |e|
130
- e.update
131
- }
132
- end
133
-
134
- def tell entities, message, refresh = false
135
- entities.each { |entity|
136
- entity.tell message, refresh
137
- }
138
- end
139
-
140
- def load script, with_libs = true
141
- code = File.read(script)
142
- code.untaint
143
- @source_directory = File.dirname(script)
144
- if with_libs == true
145
- $LOAD_PATH.reverse.each { |path|
146
- get_scripts path + '/gamefic/import'
147
- }
100
+
101
+ # Get an Array of the Plot's current Syntaxes.
102
+ #
103
+ # @return [Array<Syntax>]
104
+ def syntaxes
105
+ @syntaxes.clone
106
+ end
107
+
108
+ # Get an Array of current players.
109
+ #
110
+ # @return [Array<Character>] The players.
111
+ def players
112
+ @players.clone
113
+ end
114
+
115
+ # Add a block to be executed on preparation of every turn.
116
+ # Each on_ready block is executed once per turn, as opposed to
117
+ # on_player_ready blocks, which are executed once for each player.
118
+ #
119
+ # @example Increment a turn counter
120
+ # turn = 0
121
+ # on_ready do
122
+ # turn += 1
123
+ # end
124
+ #
125
+ def on_ready(&block)
126
+ @ready_procs.push block
127
+ end
128
+
129
+ # Add a block to be executed after the Plot is finished updating a turn.
130
+ # Each on_update block is executed once per turn, as opposed to
131
+ # on_player_update blocks, which are executed once for each player.
132
+ def on_update(&block)
133
+ @update_procs.push block
134
+ end
135
+
136
+ # Add a block to be executed when a player is added to the game.
137
+ # Each Plot can only have one introduction. Subsequent calls will
138
+ # overwrite the existing one.
139
+ #
140
+ # @example Welcome the player to the game
141
+ # introduction do |actor|
142
+ # actor.tell "Welcome to the game!"
143
+ # end
144
+ #
145
+ # @yieldparam [Character]
146
+ def introduction (&proc)
147
+ @introduction = proc
148
+ end
149
+
150
+ # Introduce a player to the game.
151
+ # This method is typically called by the Engine that manages game execution.
152
+ def introduce(player)
153
+ @players.push player
154
+ if @introduction != nil
155
+ @introduction.call(player)
156
+ end
157
+ # TODO: There should probably be a default state specified
158
+ # by the plot, which would be :active by default. We could
159
+ # get it like player.cue nil.
160
+ if player.scene.nil?
161
+ cue player, default_scene
162
+ ready
163
+ update
148
164
  end
149
- get_scripts @source_directory + '/import'
150
- proc {
151
- $SAFE = Gamefic.safe_level
152
- eval code, ::Gamefic.bind(self), script, 1
153
- }.call
154
165
  end
155
166
 
156
- def import script
157
- if script[-2, 2] == '/*'
158
- directory = script[0..-3]
159
- resolved = directory
160
- @available_scripts.each { |f, c|
161
- if f.start_with?(resolved)
162
- self.import f
163
- end
167
+ # Prepare the Plot for the next turn of gameplay.
168
+ # This method is typically called by the Engine that manages game execution.
169
+ def ready
170
+ @ready_procs.each { |p|
171
+ p.call
172
+ }
173
+ # Prepare player scenes for the update.
174
+ @players.each { |player|
175
+ @player_ready.each { |block|
176
+ block.call player
164
177
  }
178
+ player.scene.start player
179
+ }
180
+ end
181
+
182
+ # Update the Plot's current turn of gameplay.
183
+ # This method is typically called by the Engine that manages game execution.
184
+ def update
185
+ # Update the plot.
186
+ @players.each { |player|
187
+ process_input player
188
+ }
189
+ @entities.each { |e|
190
+ e.update
191
+ }
192
+ @players.each { |player|
193
+ update_player player
194
+ cue player, player.scene.data.next_cue if !player.scene.data.next_cue.nil?
195
+ }
196
+ @update_procs.each { |p|
197
+ p.call
198
+ }
199
+ end
200
+
201
+ def tell entities, message, refresh = false
202
+ entities.each { |entity|
203
+ entity.tell message, refresh
204
+ }
205
+ end
206
+
207
+ # Load a script into the current Plot.
208
+ # This method is similar to Kernel#require, except that the script is
209
+ # evaluated within the Plot's context via #stage.
210
+ #
211
+ # @param path [String] The path to the script being evaluated
212
+ # @return [Boolean] true if the script was loaded by this call or false if it was already loaded.
213
+ def script path
214
+ imported_script = source.export(path)
215
+ if imported_script.nil?
216
+ raise "Script not found: #{path}"
217
+ end
218
+ if !@working_scripts.include?(imported_script) and !imported_scripts.include?(imported_script)
219
+ @working_scripts.push imported_script
220
+ stage imported_script.read, imported_script.absolute_path
221
+ @working_scripts.pop
222
+ imported_scripts.push imported_script
223
+ true
165
224
  else
166
- resolved = script
167
- if !@available_scripts.has_key?(resolved)
168
- if @available_scripts.has_key?(resolved + '.rb')
169
- resolved = resolved + '.rb'
170
- end
171
- end
172
- if @available_scripts.has_key?(resolved)
173
- if @available_scripts[resolved] != nil
174
- script_object = @available_scripts[resolved]
175
- @available_scripts[resolved] = nil
176
- proc {
177
- $SAFE = Gamefic.safe_level
178
- @imported_scripts.push script_object
179
- eval script_object.code, Gamefic.bind(self), script_object.filename, 1
180
- }.call
181
- end
182
- else
183
- raise "Unavailable import: #{resolved}"
184
- end
225
+ false
185
226
  end
186
227
  end
187
228
 
188
- private
189
- def get_scripts(directory)
190
- Dir[directory + '/*'].each { |f|
191
- if File.directory?(f)
192
- get_scripts f
193
- else
194
- relative = f[(f.index('/import/')+8)..-1]
195
- @available_scripts[relative] = Script.new(f)
196
- end
229
+ # Add a block to be executed for each player when the Plot prepares them
230
+ # for the next turn in the game.
231
+ #
232
+ # @yieldparam [Character]
233
+ def on_player_ready &block
234
+ @player_ready.push block
235
+ end
236
+
237
+ # Add a block to be executed for each player after they have completed a
238
+ # turn in the game.
239
+ #
240
+ # @yieldparam [Character]
241
+ def on_player_update &block
242
+ @player_procs.push block
243
+ end
244
+
245
+ private
246
+ def process_input player
247
+ line = player.queue.shift
248
+ if !line.nil?
249
+ player.scene.finish player, line
250
+ #cue player, player.scene.data.next_cue if !player.scene.data.next_cue.nil?
251
+ end
252
+ end
253
+ def update_player player
254
+ @player_procs.each { |proc|
255
+ proc.call player
197
256
  }
257
+ # HACK Exception for running tests
258
+ if player[:testing] == true
259
+ cue player, :test
260
+ end
198
261
  end
199
- def rem_entity(entity)
200
- @entities.delete(entity)
201
- end
202
- def recursive_update(entity)
203
- entity.update
204
- entity.children.each { |e|
205
- recursive_update e
206
- }
207
- end
208
- def add_syntax syntax
209
- if @commands[syntax.command] == nil
210
- raise "Action \"#{syntax.command}\" does not exist"
211
- end
212
- @syntaxes.unshift syntax
213
- @syntaxes.sort! { |a, b|
214
- al = a.template.length
215
- if (a.command.nil?)
216
- al -= 1
217
- end
218
- bl = b.template.length
219
- if (b.command.nil?)
220
- bl -= 1
262
+ def rem_entity(entity)
263
+ @entities.delete(entity)
264
+ end
265
+ def recursive_update(entity)
266
+ entity.update
267
+ entity.children.each { |e|
268
+ recursive_update e
269
+ }
270
+ end
271
+ def add_syntax syntax
272
+ if @commands[syntax.verb] == nil
273
+ raise "Action \"#{syntax.verb}\" does not exist."
274
+ end
275
+ # Delete duplicate syntaxes
276
+ @syntaxes = @syntaxes.delete_if { |existing|
277
+ existing == syntax
278
+ }
279
+ @syntaxes.unshift syntax
280
+ @syntaxes.sort! { |a, b|
281
+ if a.token_count == b.token_count
282
+ # For syntaxes of the same length, length of action takes precedence
283
+ b.first_word <=> a.first_word
284
+ else
285
+ b.token_count <=> a.token_count
221
286
  end
222
- if al == bl
223
- # For syntaxes of the same length, creation order takes precedence
224
- 0
225
- else
226
- bl <=> al
227
- end
228
- }
229
- end
230
- def add_action(action)
231
- if (@commands[action.command] == nil)
232
- @commands[action.command] = Array.new
233
- end
234
- @commands[action.command].unshift action
235
- @commands[action.command].sort! { |a, b|
287
+ }
288
+ end
289
+ def add_action(action)
290
+ if (@commands[action.verb] == nil)
291
+ @commands[action.verb] = Array.new
292
+ end
293
+ @commands[action.verb].unshift action
294
+ @commands[action.verb].sort! { |a, b|
236
295
  if a.specificity == b.specificity
237
296
  # Newer action takes precedence
238
297
  b.order_key <=> a.order_key
@@ -240,41 +299,31 @@ module Gamefic
240
299
  # Higher specificity takes precedence
241
300
  b.specificity <=> a.specificity
242
301
  end
243
- }
244
- #if action.command != nil
245
- user_friendly = action.command.to_s.sub(/_/, ' ')
246
- args = Array.new
247
- used_names = Array.new
248
- action.queries.each { |c|
249
- num = 1
250
- new_name = "var"
251
- while used_names.include? new_name
252
- num = num + 1
253
- new_name = "var#{num}"
254
- end
255
- used_names.push new_name
256
- user_friendly += " :#{new_name}"
257
- args.push new_name.to_sym
258
- }
259
- Syntax.new self, *[user_friendly.strip, action.command] + args
260
- #end
261
- end
302
+ }
303
+ user_friendly = action.verb.to_s.gsub(/_/, ' ')
304
+ args = Array.new
305
+ used_names = Array.new
306
+ action.queries.each { |c|
307
+ num = 1
308
+ new_name = ":var"
309
+ while used_names.include? new_name
310
+ num = num + 1
311
+ new_name = ":var#{num}"
312
+ end
313
+ used_names.push new_name
314
+ user_friendly += " #{new_name}"
315
+ args.push new_name
316
+ }
317
+ Syntax.new self, user_friendly.strip, "#{action.verb} #{args.join(' ')}"
318
+ end
262
319
  def rem_action(action)
263
- @commands[action.command].delete(action)
320
+ @commands[action.verb].delete(action)
264
321
  end
265
322
  def rem_syntax(syntax)
266
323
  @syntaxes.delete syntax
267
324
  end
268
- def add_entity(entity)
269
- @entities.push entity
270
- end
271
- class Script
272
- attr_reader :filename, :code
273
- def initialize filename
274
- @filename = filename
275
- @code = File.read(filename)
276
- @code.untaint
277
- end
325
+ def add_entity(entity)
326
+ @entities.push entity
278
327
  end
279
328
  end
280
329
 
@@ -0,0 +1,5 @@
1
+ class Gamefic::Query::AmbiguousChildren < Gamefic::Query::ManyChildren
2
+ def allow_ambiguous?
3
+ true
4
+ end
5
+ end