gamefic 0.2.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/gamefic/action.rb +87 -56
- data/lib/gamefic/ansi.rb +55 -0
- data/lib/gamefic/character.rb +130 -76
- data/lib/gamefic/command.rb +19 -0
- data/lib/gamefic/core_ext/array.rb +51 -40
- data/lib/gamefic/core_ext/string.rb +4 -0
- data/lib/gamefic/describable.rb +108 -46
- data/lib/gamefic/direction.rb +46 -0
- data/lib/gamefic/director/delegate.rb +91 -0
- data/lib/gamefic/director/order.rb +10 -0
- data/lib/gamefic/director/parser.rb +119 -0
- data/lib/gamefic/director.rb +16 -197
- data/lib/gamefic/engine/cgi.rb +221 -0
- data/lib/gamefic/engine/tty.rb +237 -0
- data/lib/gamefic/engine.rb +88 -67
- data/lib/gamefic/entity.rb +96 -69
- data/lib/gamefic/grammar/conjugator.rb +20 -0
- data/lib/gamefic/grammar/gender.rb +11 -0
- data/lib/gamefic/grammar/person.rb +10 -0
- data/lib/gamefic/grammar/plural.rb +13 -0
- data/lib/gamefic/grammar/pronouns.rb +60 -0
- data/lib/gamefic/grammar/tense.rb +6 -0
- data/lib/gamefic/grammar/verb_set.rb +43 -0
- data/lib/gamefic/grammar/verbs.rb +25 -0
- data/lib/gamefic/grammar/word_adapter.rb +36 -0
- data/lib/gamefic/grammar.rb +13 -0
- data/lib/gamefic/html.rb +53 -0
- data/lib/gamefic/keywords.rb +51 -33
- data/lib/gamefic/node.rb +65 -58
- data/lib/gamefic/plot/article_mount.rb +22 -0
- data/lib/gamefic/plot/command_mount.rb +88 -0
- data/lib/gamefic/plot/entity_mount.rb +45 -0
- data/lib/gamefic/plot/query_mount.rb +9 -0
- data/lib/gamefic/plot/scene_mount.rb +181 -0
- data/lib/gamefic/plot/you_mount.rb +22 -0
- data/lib/gamefic/plot.rb +296 -247
- data/lib/gamefic/query/ambiguous_children.rb +5 -0
- data/lib/gamefic/query/base.rb +265 -0
- data/lib/gamefic/query/children.rb +10 -0
- data/lib/gamefic/query/expression.rb +47 -0
- data/lib/gamefic/query/family.rb +10 -0
- data/lib/gamefic/query/many_children.rb +7 -0
- data/lib/gamefic/query/matches.rb +11 -0
- data/lib/gamefic/query/parent.rb +10 -0
- data/lib/gamefic/query/plural_children.rb +14 -0
- data/lib/gamefic/query/self.rb +10 -0
- data/lib/gamefic/query/siblings.rb +10 -0
- data/lib/gamefic/query/text.rb +43 -0
- data/lib/gamefic/query.rb +19 -203
- data/lib/gamefic/rule.rb +18 -0
- data/lib/gamefic/scene/active.rb +25 -0
- data/lib/gamefic/scene/concluded.rb +22 -0
- data/lib/gamefic/scene/multiplechoice.rb +74 -0
- data/lib/gamefic/scene/paused.rb +26 -0
- data/lib/gamefic/scene/yesorno.rb +43 -0
- data/lib/gamefic/scene.rb +125 -0
- data/lib/gamefic/script/base.rb +33 -0
- data/lib/gamefic/script/file.rb +14 -0
- data/lib/gamefic/script/text.rb +14 -0
- data/lib/gamefic/script.rb +9 -0
- data/lib/gamefic/serialized.rb +24 -0
- data/lib/gamefic/shell.rb +9 -247
- data/lib/gamefic/snapshots.rb +134 -0
- data/lib/gamefic/source/base.rb +12 -0
- data/lib/gamefic/source/file.rb +23 -0
- data/lib/gamefic/source/text.rb +16 -0
- data/lib/gamefic/source.rb +9 -0
- data/lib/gamefic/stage.rb +75 -0
- data/lib/gamefic/syntax.rb +106 -124
- data/lib/gamefic/tester.rb +20 -0
- data/lib/gamefic/version.rb +3 -0
- data/lib/gamefic.rb +18 -12
- metadata +102 -70
- data/lib/gamefic/base.rb +0 -10
- data/lib/gamefic/before.rb +0 -12
- data/lib/gamefic/import/basics/actions/close.rb +0 -16
- data/lib/gamefic/import/basics/actions/commands.rb +0 -3
- data/lib/gamefic/import/basics/actions/drop-in.rb +0 -17
- data/lib/gamefic/import/basics/actions/drop-on.rb +0 -16
- data/lib/gamefic/import/basics/actions/drop.rb +0 -30
- data/lib/gamefic/import/basics/actions/enter.rb +0 -16
- data/lib/gamefic/import/basics/actions/go.rb +0 -35
- data/lib/gamefic/import/basics/actions/inventory.rb +0 -8
- data/lib/gamefic/import/basics/actions/leave.rb +0 -29
- data/lib/gamefic/import/basics/actions/look-in-at.rb +0 -27
- data/lib/gamefic/import/basics/actions/look-under.rb +0 -3
- data/lib/gamefic/import/basics/actions/look.rb +0 -71
- data/lib/gamefic/import/basics/actions/nil.rb +0 -25
- data/lib/gamefic/import/basics/actions/open.rb +0 -23
- data/lib/gamefic/import/basics/actions/quit.rb +0 -3
- data/lib/gamefic/import/basics/actions/take.rb +0 -107
- data/lib/gamefic/import/basics/entities/container.rb +0 -8
- data/lib/gamefic/import/basics/entities/entity.rb +0 -11
- data/lib/gamefic/import/basics/entities/fixture.rb +0 -5
- data/lib/gamefic/import/basics/entities/item.rb +0 -5
- data/lib/gamefic/import/basics/entities/portal.rb +0 -40
- data/lib/gamefic/import/basics/entities/room.rb +0 -30
- data/lib/gamefic/import/basics/entities/scenery.rb +0 -5
- data/lib/gamefic/import/basics/entities/supporter.rb +0 -6
- data/lib/gamefic/import/basics/entities/thing.rb +0 -16
- data/lib/gamefic/import/basics/queries/reachable.rb +0 -38
- data/lib/gamefic/import/basics/queries/room.rb +0 -8
- data/lib/gamefic/import/basics/queries/visible.rb +0 -32
- data/lib/gamefic/import/basics/rules/has-enough-light.rb +0 -14
- data/lib/gamefic/import/basics.old/actions/container.rb +0 -112
- data/lib/gamefic/import/basics.old/actions/inventory.rb +0 -50
- data/lib/gamefic/import/basics.old/actions/look.rb +0 -53
- data/lib/gamefic/import/basics.old/actions/meta.rb +0 -6
- data/lib/gamefic/import/basics.old/actions/traversal.rb +0 -35
- data/lib/gamefic/import/basics.old/actions.rb +0 -1
- data/lib/gamefic/import/basics.old/entities/container.rb +0 -3
- data/lib/gamefic/import/basics.old/entities/fixture.rb +0 -3
- data/lib/gamefic/import/basics.old/entities/item.rb +0 -3
- data/lib/gamefic/import/basics.old/entities/portal.rb +0 -43
- data/lib/gamefic/import/basics.old/entities/room.rb +0 -27
- data/lib/gamefic/import/basics.old/entities/scenery.rb +0 -3
- data/lib/gamefic/import/basics.old/entities/supporter.rb +0 -3
- data/lib/gamefic/import/basics.old/entities.rb +0 -1
- data/lib/gamefic/import/basics.old/room_modes.rb +0 -48
- data/lib/gamefic/import/basics.rb +0 -6
- data/lib/gamefic/import/room_modes.rb +0 -48
- data/lib/gamefic/import/standard.rb +0 -1
- data/lib/gamefic/meta.rb +0 -12
- data/lib/gamefic/optionset.rb +0 -114
- data/lib/gamefic/requirement.rb +0 -14
- data/lib/gamefic/story.rb +0 -14
- data/lib/gamefic/thing.rb +0 -7
data/lib/gamefic/describable.rb
CHANGED
@@ -1,40 +1,76 @@
|
|
1
|
-
require
|
1
|
+
require 'gamefic/keywords'
|
2
|
+
require 'gamefic/grammar'
|
2
3
|
|
3
4
|
module Gamefic
|
4
5
|
|
5
|
-
|
6
|
+
# Add a variety of text properties for naming, describing, and properly
|
7
|
+
# referencing objects.
|
8
|
+
module Describable
|
9
|
+
include Grammar::Person, Grammar::Plural
|
6
10
|
attr_reader :name
|
7
|
-
|
11
|
+
attr_accessor :synonyms, :indefinite_article
|
8
12
|
attr_writer :definite_article
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
|
14
|
+
# Get a set of Keywords associated with the object.
|
15
|
+
# Keywords are typically the words in the object's name plus its synonyms.
|
16
|
+
#
|
17
|
+
# @return [Keywords]
|
18
|
+
def keywords
|
19
|
+
Keywords.new "#{name} #{synonyms}"
|
20
|
+
end
|
21
|
+
|
22
|
+
# Get the name of the object with an indefinite article.
|
23
|
+
# Note: proper-named objects never append an article, though an article
|
24
|
+
# may be included in its proper name.
|
25
|
+
#
|
26
|
+
# @return [String]
|
15
27
|
def indefinitely
|
16
|
-
(proper_named? ? '' : "#{indefinite_article} ") + name
|
28
|
+
((proper_named? or indefinite_article == '') ? '' : "#{indefinite_article} ") + name
|
17
29
|
end
|
30
|
+
|
31
|
+
# Get the name of the object with a definite article.
|
32
|
+
# Note: proper-named objects never append an article, though an article
|
33
|
+
# may be included in its proper name.
|
18
34
|
def definitely
|
19
|
-
(proper_named? ? '' : "#{definite_article} ") + name
|
35
|
+
((proper_named? or definite_article == '') ? '' : "#{definite_article} ") + name
|
20
36
|
end
|
37
|
+
|
38
|
+
# Get the definite article for this object.
|
39
|
+
#
|
40
|
+
# @return [String]
|
21
41
|
def definite_article
|
22
42
|
@definite_article || "the"
|
23
43
|
end
|
44
|
+
|
45
|
+
# Is the object proper-named?
|
46
|
+
# Proper-named objects typically do not add articles to their names when
|
47
|
+
# referenced #definitely or #indefinitely, e.g., "Jane Doe" instead of
|
48
|
+
# "a Jane Doe" or "the Jane Doe."
|
49
|
+
#
|
50
|
+
# @return [Boolean]
|
24
51
|
def proper_named?
|
25
52
|
(@proper_named == true)
|
26
53
|
end
|
27
|
-
|
28
|
-
|
54
|
+
|
55
|
+
# Set whether the object has a proper name.
|
56
|
+
#
|
57
|
+
# @param [Boolean]
|
58
|
+
def proper_named=(bool)
|
59
|
+
if bool == true
|
29
60
|
if @definite_article != nil
|
30
61
|
@name = "#{@definite_article} #{@name}"
|
31
62
|
@definite_article = nil
|
32
63
|
end
|
33
64
|
end
|
34
|
-
@proper_named =
|
65
|
+
@proper_named = bool
|
35
66
|
end
|
67
|
+
|
68
|
+
# Set the name of the object.
|
69
|
+
# Setting the name performs some magic to determine how to handle
|
70
|
+
# articles ("an object" and "the object").
|
71
|
+
#
|
72
|
+
# @param value [String]
|
36
73
|
def name=(value)
|
37
|
-
# TODO: Split article from name
|
38
74
|
words = value.split_words
|
39
75
|
if ['a','an'].include?(words[0].downcase)
|
40
76
|
@indefinite_article = words[0].downcase
|
@@ -42,8 +78,12 @@ module Gamefic
|
|
42
78
|
value = value[words[0].length+1..-1].strip
|
43
79
|
else
|
44
80
|
if words[0].downcase == 'the'
|
45
|
-
|
46
|
-
|
81
|
+
if proper_named?
|
82
|
+
@definite_article = nil
|
83
|
+
else
|
84
|
+
@definite_article = 'the'
|
85
|
+
value = value[4..-1].strip
|
86
|
+
end
|
47
87
|
end
|
48
88
|
# Try to guess the indefinite article
|
49
89
|
if ['a','e','i','o','u'].include?(value[0,1].downcase)
|
@@ -54,34 +94,56 @@ module Gamefic
|
|
54
94
|
end
|
55
95
|
@name = value
|
56
96
|
end
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
97
|
+
|
98
|
+
# Does the object have a description?
|
99
|
+
#
|
100
|
+
# @return [Boolean]
|
101
|
+
def has_description?
|
102
|
+
(@description.to_s != '')
|
103
|
+
end
|
104
|
+
|
105
|
+
# Get the object's description.
|
106
|
+
#
|
107
|
+
# @return [String]
|
108
|
+
def description
|
109
|
+
@description || (Describable.default_description % { :name => self.definitely, :Name => self.definitely.capitalize_first })
|
110
|
+
end
|
111
|
+
|
112
|
+
# Set the object's description.
|
113
|
+
#
|
114
|
+
# @param text [String]
|
115
|
+
def description=(text)
|
116
|
+
if text != (Describable.default_description % { :name => self.definitely, :Name => self.definitely.capitalize_first })
|
117
|
+
@description = text
|
118
|
+
else
|
119
|
+
@description = nil
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Set the object's default description.
|
124
|
+
# The default description is typically set in an object's initialization
|
125
|
+
# to ensure that a non-empty string is available when a instance-specific
|
126
|
+
# description is not provided
|
127
|
+
#
|
128
|
+
# @param text [String]
|
129
|
+
def self.default_description=(text)
|
130
|
+
@default_description = text
|
131
|
+
end
|
132
|
+
|
133
|
+
# Get the object's default description.
|
134
|
+
#
|
135
|
+
# @return [String]
|
136
|
+
def self.default_description
|
137
|
+
@default_description || "There's nothing special about %{name}."
|
138
|
+
end
|
139
|
+
|
140
|
+
# Get a String representation of the object. By default, this is the
|
141
|
+
# object's name with an indefinite article, e.g., "a person" or "a red
|
142
|
+
# dog."
|
143
|
+
#
|
144
|
+
# @return [String]
|
145
|
+
def to_s
|
146
|
+
indefinitely
|
147
|
+
end
|
85
148
|
end
|
86
|
-
|
87
149
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Gamefic
|
2
|
+
|
3
|
+
class Direction
|
4
|
+
attr_accessor :name, :adjective, :adverb, :reverse
|
5
|
+
def initialize args = {}
|
6
|
+
args.each { |key, value|
|
7
|
+
send "#{key}=", value
|
8
|
+
}
|
9
|
+
if !reverse.nil?
|
10
|
+
reverse.reverse = self
|
11
|
+
end
|
12
|
+
proper_named = true
|
13
|
+
end
|
14
|
+
def adjective
|
15
|
+
@adjective || @name
|
16
|
+
end
|
17
|
+
def adverb
|
18
|
+
@adverb || @name
|
19
|
+
end
|
20
|
+
def reverse=(dir)
|
21
|
+
@reverse = dir
|
22
|
+
end
|
23
|
+
def synonyms
|
24
|
+
"#{adjective} #{adverb}"
|
25
|
+
end
|
26
|
+
def to_s
|
27
|
+
@name
|
28
|
+
end
|
29
|
+
def self.find(str)
|
30
|
+
x = { "north" => NORTH, "south" => SOUTH, "west" => WEST, "east" => EAST, "up" => UP, "down" => DOWN, "northwest" => NORTHWEST, "northeast" => NORTHEAST, "southwest" => SOUTHWEST, "southeast" => SOUTHEAST }
|
31
|
+
x[str]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
NORTH = Direction.new(:name => 'north', :adjective => 'northern')
|
36
|
+
SOUTH = Direction.new(:name => 'south', :adjective => 'southern', :reverse => NORTH)
|
37
|
+
WEST = Direction.new(:name => 'west', :adjective => 'western')
|
38
|
+
EAST = Direction.new(:name => 'east', :adjective => 'eastern', :reverse => WEST)
|
39
|
+
NORTHWEST = Direction.new(:name => 'northwest', :adjective => 'northwestern')
|
40
|
+
SOUTHEAST = Direction.new(:name => 'southeast', :adjective => 'southeastern', :reverse => NORTHWEST)
|
41
|
+
NORTHEAST = Direction.new(:name => 'northeast', :adjective => 'northeastern')
|
42
|
+
SOUTHWEST = Direction.new(:name => 'southwest', :adjective => 'southwestern', :reverse => NORTHEAST)
|
43
|
+
UP = Direction.new(:name => 'up', :adjective => 'upwards')
|
44
|
+
DOWN = Direction.new(:name => 'down', :adjective => 'downwards', :reverse => UP)
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Gamefic
|
2
|
+
module Director
|
3
|
+
class Delegate
|
4
|
+
# If we use Query::Base.new in the @disambiguator declaration, Opal
|
5
|
+
# passes the block to the query instead of the action.
|
6
|
+
base = Query::Base.new
|
7
|
+
@@disambiguator = Action.new nil, nil, base do |actor, entities|
|
8
|
+
definites = []
|
9
|
+
entities.each { |entity|
|
10
|
+
definites.push entity.definitely
|
11
|
+
}
|
12
|
+
actor.tell "I don't know which you mean: #{definites.join_or}."
|
13
|
+
end
|
14
|
+
@@disambiguator.meta = true
|
15
|
+
def initialize(actor, orders)
|
16
|
+
@actor = actor
|
17
|
+
@orders = orders
|
18
|
+
end
|
19
|
+
def proceed
|
20
|
+
return if @orders.length == 0
|
21
|
+
@actor.send(:delegate_stack).push self
|
22
|
+
executed = false
|
23
|
+
while !executed
|
24
|
+
order = @orders.shift
|
25
|
+
break if order.nil?
|
26
|
+
arg_i = 0
|
27
|
+
final_arguments = []
|
28
|
+
order.arguments.each { |argument|
|
29
|
+
if argument.length > 1 and !order.action.queries[arg_i].allow_many?
|
30
|
+
if argument[0].kind_of?(Array)
|
31
|
+
# This thing refers to multiple items. Just keep going.
|
32
|
+
final_arguments = nil
|
33
|
+
break
|
34
|
+
else
|
35
|
+
ambiguous = argument
|
36
|
+
end
|
37
|
+
order = Order.new(@actor, @@disambiguator, [])
|
38
|
+
final_arguments = [ambiguous]
|
39
|
+
break
|
40
|
+
end
|
41
|
+
valid = []
|
42
|
+
if order.action.queries[arg_i].allow_ambiguous?
|
43
|
+
valid = argument.flatten
|
44
|
+
else
|
45
|
+
argument.each { |m|
|
46
|
+
if order.action.queries[arg_i].validate(@actor, m)
|
47
|
+
valid.push m
|
48
|
+
else
|
49
|
+
final_arguments = nil
|
50
|
+
break
|
51
|
+
end
|
52
|
+
}
|
53
|
+
end
|
54
|
+
if order.action == @@disambiguator or final_arguments.nil?
|
55
|
+
break
|
56
|
+
end
|
57
|
+
if order.action.queries[arg_i].allow_many?
|
58
|
+
final_arguments.push valid.flatten
|
59
|
+
elsif valid.length == 1
|
60
|
+
final_arguments.push valid[0]
|
61
|
+
else
|
62
|
+
final_arguments = nil
|
63
|
+
break
|
64
|
+
end
|
65
|
+
arg_i += 1
|
66
|
+
}
|
67
|
+
if !final_arguments.nil?
|
68
|
+
# The actor is always the first argument to an Action proc
|
69
|
+
final_arguments.unshift @actor
|
70
|
+
order.action.execute(*final_arguments)
|
71
|
+
executed = true
|
72
|
+
end
|
73
|
+
end
|
74
|
+
@actor.send(:delegate_stack).pop
|
75
|
+
end
|
76
|
+
def execute
|
77
|
+
return if @orders.length == 0
|
78
|
+
if !@orders[0].action.meta?
|
79
|
+
@actor.plot.asserts.each_pair { |name, rule|
|
80
|
+
result = rule.test(@actor, @orders[0].action.verb, @orders[0].arguments)
|
81
|
+
if result == false
|
82
|
+
return
|
83
|
+
end
|
84
|
+
}
|
85
|
+
end
|
86
|
+
proceed
|
87
|
+
end
|
88
|
+
private
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,119 @@
|
|
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.plot.actions_with_verb(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
|
+
options
|
35
|
+
end
|
36
|
+
def self.from_string(actor, command)
|
37
|
+
options = []
|
38
|
+
if command.to_s == ''
|
39
|
+
return options
|
40
|
+
end
|
41
|
+
matches = Syntax.tokenize(command, actor.plot.syntaxes)
|
42
|
+
matches.each { |match|
|
43
|
+
actions = actor.plot.actions_with_verb(match.verb)
|
44
|
+
actions.each { |action|
|
45
|
+
options.concat bind_contexts_in_result(actor, match.arguments, action)
|
46
|
+
}
|
47
|
+
}
|
48
|
+
options
|
49
|
+
end
|
50
|
+
class << self
|
51
|
+
private
|
52
|
+
def bind_contexts_in_result(actor, handler, action)
|
53
|
+
queries = action.queries.clone
|
54
|
+
objects = execute_query(actor, handler.clone, queries, action)
|
55
|
+
num_nil = 0
|
56
|
+
while objects.length == 0 and queries.last.optional?
|
57
|
+
num_nil +=1
|
58
|
+
queries.pop
|
59
|
+
objects = execute_query(actor, handler.clone, queries, action, num_nil)
|
60
|
+
end
|
61
|
+
return objects
|
62
|
+
end
|
63
|
+
def execute_query(actor, arguments, queries, action, num_nil = 0)
|
64
|
+
# If the action verb is nil, treat the first argument as a query
|
65
|
+
arguments.shift unless action.verb.nil?
|
66
|
+
prepared = Array.new
|
67
|
+
objects = Array.new
|
68
|
+
valid = true
|
69
|
+
last_remainder = nil
|
70
|
+
queries.clone.each { |context|
|
71
|
+
arg = arguments.shift.to_s
|
72
|
+
if last_remainder.to_s > ''
|
73
|
+
arg = (last_remainder + " " + arg).strip
|
74
|
+
end
|
75
|
+
if arg.nil? or arg == ''
|
76
|
+
valid = false
|
77
|
+
next
|
78
|
+
end
|
79
|
+
if context == String
|
80
|
+
prepared.push [arg]
|
81
|
+
elsif context.kind_of?(Query::Base)
|
82
|
+
result = context.execute(actor, arg)
|
83
|
+
if result.objects.length == 0
|
84
|
+
valid = false
|
85
|
+
next
|
86
|
+
else
|
87
|
+
prepared.push result.objects
|
88
|
+
last_remainder = result.remainder
|
89
|
+
end
|
90
|
+
else
|
91
|
+
raise TypeError.new("Action parameters must inherit from Query::Base")
|
92
|
+
end
|
93
|
+
}
|
94
|
+
if valid == true
|
95
|
+
if last_remainder.nil? or last_remainder.empty?
|
96
|
+
prepared.each { |p|
|
97
|
+
p.uniq!
|
98
|
+
}
|
99
|
+
num_nil.times do
|
100
|
+
prepared.push [nil]
|
101
|
+
end
|
102
|
+
objects.push Order.new(actor, action, prepared)
|
103
|
+
else
|
104
|
+
if !action.queries.last.allow_many? or action.queries.last.allow_ambiguous?
|
105
|
+
misunderstood = Action.new nil, nil, Query::Text.new do |actor, text|
|
106
|
+
actor.tell "I understand the first part of your command but not \"#{text}.\""
|
107
|
+
end
|
108
|
+
misunderstood.meta = true
|
109
|
+
objects.push Order.new(actor, misunderstood, [[last_remainder]])
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
objects
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
data/lib/gamefic/director.rb
CHANGED
@@ -1,204 +1,23 @@
|
|
1
1
|
module Gamefic
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
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)
|
8
12
|
end
|
9
|
-
|
10
|
-
|
11
|
-
rescue Exception => e
|
12
|
-
puts "#{e}"
|
13
|
-
return
|
13
|
+
if orders.length == 0
|
14
|
+
orders = Parser.from_string(actor, args.join(' ').strip)
|
14
15
|
end
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
if actions != nil
|
20
|
-
actions.each { |action|
|
21
|
-
if action.queries.length == 0 and handler.arguments.length > 0
|
22
|
-
next
|
23
|
-
end
|
24
|
-
orders = bind_contexts_in_result(actor, handler, action)
|
25
|
-
orders.each { |order|
|
26
|
-
args = Array.new
|
27
|
-
args.push actor
|
28
|
-
order.arguments.each { |a|
|
29
|
-
if a.length > 1
|
30
|
-
longnames = Array.new
|
31
|
-
a.each { |b|
|
32
|
-
longnames.push "#{b.definitely}"
|
33
|
-
}
|
34
|
-
actor.tell "I don't know which you mean: #{longnames.join_and(', ', ' or ')}."
|
35
|
-
return
|
36
|
-
end
|
37
|
-
args.push a[0]
|
38
|
-
}
|
39
|
-
if order.action.kind_of?(Before)
|
40
|
-
befores.push [order.action, args]
|
41
|
-
else
|
42
|
-
options.push [order.action, args]
|
43
|
-
end
|
44
|
-
}
|
45
|
-
}
|
46
|
-
end
|
47
|
-
}
|
48
|
-
del = Delegate.new(actor, befores, options)
|
49
|
-
del.execute
|
50
|
-
end
|
51
|
-
private
|
52
|
-
def self.bind_contexts_in_result(actor, handler, action)
|
53
|
-
queries = action.queries.clone
|
54
|
-
objects = self.execute_query(actor, handler.arguments.clone, queries, action)
|
55
|
-
num_nil = 0
|
56
|
-
while objects.length == 0 and queries.last.optional?
|
57
|
-
num_nil +=1
|
58
|
-
queries.pop
|
59
|
-
objects = self.execute_query(actor, handler.arguments.clone, queries, action, num_nil)
|
60
|
-
end
|
61
|
-
return objects
|
62
|
-
end
|
63
|
-
def self.execute_query(actor, arguments, queries, action, num_nil = 0)
|
64
|
-
prepared = Array.new
|
65
|
-
objects = Array.new
|
66
|
-
valid = true
|
67
|
-
queries.clone.each { |context|
|
68
|
-
arg = arguments.shift
|
69
|
-
if arg == nil or arg == ''
|
70
|
-
valid = false
|
71
|
-
next
|
72
|
-
end
|
73
|
-
if context == String
|
74
|
-
prepared.push [arg]
|
75
|
-
elsif context.kind_of?(Query::Base)
|
76
|
-
if arg == 'it' and actor.object_of_pronoun != nil
|
77
|
-
result = context.execute(actor, "#{actor.object_of_pronoun.name}")
|
78
|
-
else
|
79
|
-
result = context.execute(actor, arg)
|
80
|
-
end
|
81
|
-
if result.objects.length == 0
|
82
|
-
valid = false
|
83
|
-
next
|
84
|
-
else
|
85
|
-
prepared.push result.objects
|
86
|
-
if result.remainder
|
87
|
-
arguments.push result.remainder
|
88
|
-
end
|
89
|
-
end
|
90
|
-
else
|
91
|
-
# TODO: Better message
|
92
|
-
raise "Invalid object"
|
93
|
-
end
|
94
|
-
}
|
95
|
-
if valid == true
|
96
|
-
prepared.each { |p|
|
97
|
-
p.uniq!
|
98
|
-
}
|
99
|
-
num_nil.times do
|
100
|
-
prepared.push [nil]
|
101
|
-
end
|
102
|
-
objects.push Order.new(action, prepared)
|
103
|
-
end
|
104
|
-
objects
|
16
|
+
first_order = orders[0]
|
17
|
+
del = Delegate.new(actor, orders)
|
18
|
+
del.execute
|
19
|
+
first_order
|
105
20
|
end
|
106
|
-
|
107
|
-
|
108
|
-
class Director
|
109
|
-
class Delegate
|
110
|
-
@@assertion_stack = Array.new
|
111
|
-
@@delegation_stack = Array.new
|
112
|
-
def initialize(actor, befores, actions)
|
113
|
-
@actor = actor
|
114
|
-
@befores = befores
|
115
|
-
@actions = actions
|
116
|
-
end
|
117
|
-
def execute
|
118
|
-
@@assertion_stack.push Hash.new
|
119
|
-
@@delegation_stack.push @befores
|
120
|
-
handle @befores
|
121
|
-
@@delegation_stack.pop
|
122
|
-
if @@assertion_stack.last[:everything] == false
|
123
|
-
@@assertion_stack.pop
|
124
|
-
return
|
125
|
-
end
|
126
|
-
result = true
|
127
|
-
@@delegation_stack.push @actions
|
128
|
-
# Nil commands pass assertions to facilitate error messages.
|
129
|
-
if @@assertion_stack.last[:everything] != true and Director::Delegate.next_command != nil
|
130
|
-
@actor.plot.rules.each { |k, v|
|
131
|
-
if @@assertion_stack.last[k] == true
|
132
|
-
next
|
133
|
-
elsif @@assertion_stack.last[k] == false
|
134
|
-
result = false
|
135
|
-
break
|
136
|
-
end
|
137
|
-
result = v.test(@actor)
|
138
|
-
if result == false
|
139
|
-
break
|
140
|
-
end
|
141
|
-
result = true
|
142
|
-
}
|
143
|
-
end
|
144
|
-
@@assertion_stack.pop
|
145
|
-
if result == true
|
146
|
-
handle @actions
|
147
|
-
end
|
148
|
-
@@delegation_stack.pop
|
149
|
-
end
|
150
|
-
def handle options
|
151
|
-
if options.length > 0
|
152
|
-
opt = options.shift
|
153
|
-
if opt[1].length == 1
|
154
|
-
opt[0].execute(opt[1][0])
|
155
|
-
opt[1][0].object_of_pronoun = nil
|
156
|
-
else
|
157
|
-
if opt[1].length == 2 and opt[1][1].kind_of?(Entity) and opt[1][0].parent != opt[1][1]
|
158
|
-
opt[1][0].object_of_pronoun = opt[1][1]
|
159
|
-
elsif opt[1][0].parent == opt[1][1]
|
160
|
-
opt[1][0].object_of_pronoun = nil
|
161
|
-
end
|
162
|
-
opt[0].execute(opt[1])
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
def self.pass requirement
|
167
|
-
@@assertion_stack.last[requirement] = true
|
168
|
-
end
|
169
|
-
def self.deny requirement
|
170
|
-
@@assertion_stack.last[requirement] = false
|
171
|
-
end
|
172
|
-
def self.next_command
|
173
|
-
return nil if @@delegation_stack.last.nil? or @@delegation_stack.last[0].length == 0
|
174
|
-
return @@delegation_stack.last[0][0].command
|
175
|
-
end
|
176
|
-
def self.passthru
|
177
|
-
if @@delegation_stack.last != nil
|
178
|
-
if @@delegation_stack.last.length > 0
|
179
|
-
opt = @@delegation_stack.last.shift
|
180
|
-
if opt[1].length == 1
|
181
|
-
opt[0].execute(opt[1][0])
|
182
|
-
opt[1][0].object_of_pronoun = nil
|
183
|
-
else
|
184
|
-
if opt[1].length == 2 and opt[1][1].kind_of?(Entity) and opt[1][0].parent != opt[1][1]
|
185
|
-
opt[1][0].object_of_pronoun = opt[1][1]
|
186
|
-
elsif opt[1][0].parent == opt[1][1]
|
187
|
-
opt[1][0].object_of_pronoun = nil
|
188
|
-
end
|
189
|
-
opt[0].execute(opt[1])
|
190
|
-
end
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
195
|
-
class Order
|
196
|
-
attr_reader :action, :arguments
|
197
|
-
def initialize(action, arguments)
|
198
|
-
@action = action
|
199
|
-
@arguments = arguments
|
200
|
-
end
|
201
|
-
end
|
202
|
-
end
|
21
|
+
end
|
203
22
|
|
204
23
|
end
|