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.
- 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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f89e42b74949fc2f51e9e5b277ab1c2cf8278f62
|
|
4
|
+
data.tar.gz: 94b6aed64c5b1805c98fde960a125b9c1f716cda
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3279a5663b92106d222f2468d9a0add3c05fedeceedcc2077f050764d5c6c5077ae38c72a1bdd475ee04bb734c57046c1976311569626246a2299e6cd22249c5
|
|
7
|
+
data.tar.gz: 9f32e56986a439a517d7d5783a4f37cf05e8e6884caf60caff044015c40baf8754c830b5f29bb3c98fac430e0c69419cf9dd09bf4e96b80666b1c0599f4fe2bc
|
data/lib/gamefic/action.rb
CHANGED
|
@@ -1,65 +1,96 @@
|
|
|
1
1
|
module Gamefic
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
# Actions manage the execution of commands that Characters can perform.
|
|
4
|
+
#
|
|
5
|
+
class Action
|
|
6
|
+
attr_reader :order_key, :queries
|
|
7
|
+
attr_writer :meta
|
|
6
8
|
@@order_key_seed = 0
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
|
|
10
|
+
def initialize(plot, verb, *queries, &proc)
|
|
11
|
+
if !verb.kind_of?(Symbol)
|
|
12
|
+
verb = verb.to_s
|
|
13
|
+
verb = nil if verb == ''
|
|
14
|
+
end
|
|
15
|
+
@plot = plot
|
|
9
16
|
@order_key = @@order_key_seed
|
|
10
17
|
@@order_key_seed += 1
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
18
|
+
@proc = proc
|
|
19
|
+
if (verb.kind_of?(Symbol) == false and !verb.nil?)
|
|
20
|
+
raise "Action verbs must be symbols"
|
|
21
|
+
end
|
|
22
|
+
if !@proc.nil?
|
|
23
|
+
if (queries.length + 1 != @proc.arity) and (queries.length == 0 and @proc.arity != -1)
|
|
24
|
+
raise "Number of queries is not compatible with proc arguments"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
@verb = verb
|
|
28
|
+
@queries = queries
|
|
29
|
+
if !plot.nil?
|
|
30
|
+
plot.send :add_action, self
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Get the specificity of the Action.
|
|
35
|
+
# Specificity indicates how narrowly the Action's queries filter matches.
|
|
36
|
+
# Actions with higher specificity are given higher priority when searching
|
|
37
|
+
# for the Action that matches a character command. For example, an Action
|
|
38
|
+
# with a Query that filters for a specific class of Entity has a higher
|
|
39
|
+
# specificity than an Action with a Query that accepts arbitrary text.
|
|
40
|
+
#
|
|
41
|
+
# @return [Fixnum]
|
|
42
|
+
def specificity
|
|
43
|
+
spec = 0
|
|
44
|
+
if verb.nil?
|
|
45
|
+
spec = -100
|
|
46
|
+
end
|
|
47
|
+
magnitude = 1
|
|
48
|
+
@queries.each { |q|
|
|
49
|
+
if q.kind_of?(Query::Base)
|
|
50
|
+
spec += (q.specificity * magnitude)
|
|
51
|
+
else
|
|
52
|
+
spec += magnitude
|
|
53
|
+
end
|
|
54
|
+
#magnitude = magnitude * 10
|
|
55
|
+
}
|
|
56
|
+
return spec
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Get the verb associated with this Action.
|
|
60
|
+
# The verb is represented by a Symbol in the imperative form, such as
|
|
61
|
+
# :take or :look_under.
|
|
62
|
+
#
|
|
63
|
+
# @return [Symbol] The Symbol representing the verb.
|
|
64
|
+
def verb
|
|
65
|
+
@verb
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Execute this Action. This method is typically called by the Plot when
|
|
69
|
+
# a Character performs a command.
|
|
48
70
|
def execute *args
|
|
49
|
-
@proc.call
|
|
71
|
+
@proc.call(*args)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def signature
|
|
75
|
+
sig = ["#{@verb}"]
|
|
76
|
+
@queries.each { |q|
|
|
77
|
+
sig.push q.signature
|
|
78
|
+
}
|
|
79
|
+
"#{sig.join(', ').gsub(/Gamefic::(Query::)?/, '')}(#{specificity})"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Is this a meta Action?
|
|
83
|
+
# If an Action is flagged meta, it usually means that it provides
|
|
84
|
+
# information about the game or manages some aspect of the user interface.
|
|
85
|
+
# It shouldn't represent an Action that the player's character performs in
|
|
86
|
+
# the game world. Examples include Actions to display credits or
|
|
87
|
+
# instructions.
|
|
88
|
+
#
|
|
89
|
+
# @return [Boolean]
|
|
90
|
+
def meta?
|
|
91
|
+
@meta ||= false
|
|
50
92
|
end
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
arr = Array.new
|
|
54
|
-
arr.push entity
|
|
55
|
-
cls = entity.class
|
|
56
|
-
while cls != Object
|
|
57
|
-
arr.push cls
|
|
58
|
-
cls = cls.superclass
|
|
59
|
-
end
|
|
60
|
-
arr.push String
|
|
61
|
-
arr.push nil
|
|
62
|
-
end
|
|
63
|
-
end
|
|
93
|
+
|
|
94
|
+
end
|
|
64
95
|
|
|
65
96
|
end
|
data/lib/gamefic/ansi.rb
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Gamefic
|
|
2
|
+
|
|
3
|
+
# Constants for ANSI codes, plus Extras for custom formatting.
|
|
4
|
+
module Ansi
|
|
5
|
+
module Code
|
|
6
|
+
class Nonstandard < String
|
|
7
|
+
|
|
8
|
+
end
|
|
9
|
+
module Attribute
|
|
10
|
+
NORMAL = 0
|
|
11
|
+
BOLD = 1
|
|
12
|
+
UNDERSCORE = 4
|
|
13
|
+
BLINK = 5
|
|
14
|
+
REVERSE = 7
|
|
15
|
+
CONCEALED = 8
|
|
16
|
+
end
|
|
17
|
+
module Foreground
|
|
18
|
+
BLACK = 30
|
|
19
|
+
RED = 31
|
|
20
|
+
GREEN = 32
|
|
21
|
+
YELLOW = 33
|
|
22
|
+
BLUE = 34
|
|
23
|
+
MAGENTA = 35
|
|
24
|
+
CYAN = 36
|
|
25
|
+
WHITE = 37
|
|
26
|
+
end
|
|
27
|
+
module Background
|
|
28
|
+
BLACK = 40
|
|
29
|
+
RED = 41
|
|
30
|
+
GREEN = 42
|
|
31
|
+
YELLOW = 43
|
|
32
|
+
BLUE = 44
|
|
33
|
+
MAGENTA = 45
|
|
34
|
+
CYAN = 46
|
|
35
|
+
WHITE = 47
|
|
36
|
+
end
|
|
37
|
+
module Extra
|
|
38
|
+
BLOCK = Nonstandard.new("block")
|
|
39
|
+
HREF = Nonstandard.new("href")
|
|
40
|
+
IMAGE = Nonstandard.new("image")
|
|
41
|
+
SRC = Nonstandard.new("src")
|
|
42
|
+
UPPERCASE = Nonstandard.new("uppercase")
|
|
43
|
+
COMMAND = Nonstandard.new("command")
|
|
44
|
+
IGNORED = Nonstandard.new("ignored")
|
|
45
|
+
LINE = Nonstandard.new("line")
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
def self.graphics_mode(*settings)
|
|
49
|
+
ansi = settings.flatten.that_are_not(Code::Nonstandard)
|
|
50
|
+
return '' if ansi.length == 0
|
|
51
|
+
"\e[#{ansi.join(';')}m"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
end
|
data/lib/gamefic/character.rb
CHANGED
|
@@ -1,82 +1,136 @@
|
|
|
1
|
-
|
|
1
|
+
require 'gamefic/director'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
module Gamefic
|
|
4
|
+
class Character < Entity
|
|
5
|
+
attr_reader :queue, :user
|
|
6
|
+
# @return [Gamefic::Director::Order]
|
|
7
|
+
attr_reader :last_order
|
|
8
|
+
# @return [Entity,nil]
|
|
9
|
+
attr_reader :last_object
|
|
10
|
+
attr_accessor :object_of_pronoun, :scene
|
|
11
|
+
|
|
12
|
+
def initialize(plot, args = {})
|
|
13
|
+
@queue = Array.new
|
|
14
|
+
super
|
|
15
|
+
@buffer_stack = 0
|
|
16
|
+
@buffer = ""
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Connect a User.
|
|
20
|
+
#
|
|
21
|
+
# @param user [User]
|
|
22
|
+
def connect(user)
|
|
23
|
+
@user = user
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Disconnect the current User.
|
|
27
|
+
#
|
|
28
|
+
def disconnect
|
|
29
|
+
# TODO: We might need some cleanup here. Like, move the character out of the game, or set a timeout to allow dropped users to reconnect... figure it out.
|
|
30
|
+
@user = nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Perform a command.
|
|
34
|
+
# The command can be specified as a String or a set of tokens. Either form
|
|
35
|
+
# should yield the same result, but using tokens can yield better
|
|
36
|
+
# performance since it doesn't need to parse the command first.
|
|
37
|
+
#
|
|
38
|
+
# The command will be executed immediately regardless of game state.
|
|
39
|
+
#
|
|
40
|
+
# @example Send a command as a string
|
|
41
|
+
# character.perform "take the key"
|
|
42
|
+
#
|
|
43
|
+
# @example Send a command as a set of tokens
|
|
44
|
+
# character.perform :take, @key
|
|
45
|
+
#
|
|
46
|
+
def perform(*command)
|
|
47
|
+
Director.dispatch(self, *command)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Quietly perform a command.
|
|
51
|
+
# This method executes the command exactly as #perform does, except it
|
|
52
|
+
# buffers the resulting output instead of sending it to the user.
|
|
53
|
+
#
|
|
54
|
+
# @return [String] The output that resulted from performing the command.
|
|
55
|
+
def quietly(*command)
|
|
56
|
+
if @buffer_stack == 0
|
|
57
|
+
@buffer = ""
|
|
58
|
+
end
|
|
59
|
+
@buffer_stack += 1
|
|
60
|
+
self.perform *command
|
|
61
|
+
@buffer_stack -= 1
|
|
62
|
+
@buffer
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Send a message to the Character.
|
|
66
|
+
# This method will automatically wrap the message in HTML paragraphs.
|
|
67
|
+
# To send a message without paragraph formatting, use #stream instead.
|
|
68
|
+
#
|
|
69
|
+
# @param message [String]
|
|
70
|
+
def tell(message)
|
|
71
|
+
if user != nil and message.to_s != ''
|
|
72
|
+
if @buffer_stack > 0
|
|
73
|
+
@buffer += message
|
|
74
|
+
else
|
|
75
|
+
message = "<p>#{message}</p>"
|
|
76
|
+
# This method uses String#gsub instead of String#gsub! for
|
|
77
|
+
# compatibility with Opal.
|
|
78
|
+
message = message.gsub(/\n\n/, '</p><p>')
|
|
79
|
+
message = message.gsub(/\n/, '<br/>')
|
|
80
|
+
user.stream.send message
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Send a message to the Character as raw text.
|
|
86
|
+
# Unlike #tell, this method will not wrap the message in HTML paragraphs.
|
|
87
|
+
#
|
|
88
|
+
# @param message [String]
|
|
89
|
+
def stream(message)
|
|
90
|
+
user.stream.send message
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def destroy
|
|
94
|
+
if @user != nil
|
|
95
|
+
@user.quit
|
|
96
|
+
end
|
|
9
97
|
super
|
|
10
|
-
end
|
|
11
|
-
def connect(user)
|
|
12
|
-
@user = user
|
|
13
|
-
end
|
|
14
|
-
def disconnect
|
|
15
|
-
# TODO: We might need some cleanup here. Like, move the character out of the game, or set a timeout to allow dropped users to reconnect... figure it out.
|
|
16
|
-
@user = nil
|
|
17
|
-
end
|
|
18
|
-
def perform(command)
|
|
19
|
-
#if command != nil
|
|
20
|
-
# @queue.push command
|
|
21
|
-
#end
|
|
22
|
-
@last_command = command
|
|
23
|
-
if state.busy? == false
|
|
24
|
-
Director.dispatch(self, command)
|
|
25
|
-
else
|
|
26
|
-
@queue.push command
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
#def inject(command)
|
|
30
|
-
# Director.dispatch(self, command)
|
|
31
|
-
#end
|
|
32
|
-
def tell(message, refresh = false)
|
|
33
|
-
if user != nil and message.to_s != ''
|
|
34
|
-
user.stream.send "#{message}\n"
|
|
35
|
-
if (refresh == true)
|
|
36
|
-
user.refresh
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
def state=(new_state)
|
|
41
|
-
@state = new_state
|
|
42
|
-
end
|
|
43
|
-
def destroy
|
|
44
|
-
if @user != nil
|
|
45
|
-
@user.quit
|
|
46
|
-
end
|
|
47
|
-
super
|
|
48
|
-
end
|
|
49
|
-
def update
|
|
50
|
-
super
|
|
51
|
-
@state.update
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
class CharacterState
|
|
55
|
-
def initialize(character)
|
|
56
|
-
@character = character
|
|
57
|
-
post_initialize
|
|
58
|
-
end
|
|
59
|
-
def post_initialize
|
|
60
|
-
# TODO: Required by subclasses?
|
|
61
|
-
end
|
|
62
|
-
def busy?
|
|
63
|
-
false
|
|
64
|
-
end
|
|
65
|
-
def update
|
|
66
|
-
while (line = @character.queue.shift)
|
|
67
|
-
@character.perform line
|
|
68
|
-
if @character.state != self
|
|
69
|
-
break
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
def prompt
|
|
74
|
-
"> "
|
|
75
98
|
end
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
99
|
+
|
|
100
|
+
# Proceed to the next Action in the current stack.
|
|
101
|
+
# This method is typically used in Action blocks to cascade through
|
|
102
|
+
# multiple implementations of the same verb.
|
|
103
|
+
#
|
|
104
|
+
# @example Proceed through two implementations of a verb
|
|
105
|
+
# introduction do |actor|
|
|
106
|
+
# actor[:has_eaten] = false # Initial value
|
|
107
|
+
# end
|
|
108
|
+
# respond :eat do |actor|
|
|
109
|
+
# actor[:has_eaten] = true
|
|
110
|
+
# end
|
|
111
|
+
# respond :eat do |actor|
|
|
112
|
+
# # This version will be executed first because it was implemented last
|
|
113
|
+
# actor.tell "You eat something."
|
|
114
|
+
# actor[:has_eaten] # Will be false on the first run
|
|
115
|
+
# actor.proceed # Execute the previous implementation
|
|
116
|
+
# actor[:has_eaten] #=> true
|
|
117
|
+
# end
|
|
118
|
+
#
|
|
119
|
+
def proceed
|
|
120
|
+
return if delegate_stack.last.nil?
|
|
121
|
+
delegate_stack.last.proceed
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
private
|
|
125
|
+
def delegate_stack
|
|
126
|
+
@delegate_stack ||= []
|
|
127
|
+
end
|
|
128
|
+
def last_order=(order)
|
|
129
|
+
return if order.nil?
|
|
130
|
+
@last_order = order
|
|
131
|
+
if !order.action.meta? and !order.arguments[0].nil? and !order.arguments[0][0].nil? and order.arguments[0][0].kind_of?(Entity)
|
|
132
|
+
@last_object = order.arguments[0][0]
|
|
133
|
+
end
|
|
80
134
|
end
|
|
81
135
|
end
|
|
82
136
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Gamefic
|
|
2
|
+
# A Command is a collection of tokens parsed from a Syntax.
|
|
3
|
+
# The Director uses Commands to find and execute corresponding Actions.
|
|
4
|
+
#
|
|
5
|
+
class Command
|
|
6
|
+
# @!attribute [r] verb
|
|
7
|
+
# @return [Symbol] A Symbol representing the command's verb or verbal phrase.
|
|
8
|
+
attr_reader :verb
|
|
9
|
+
|
|
10
|
+
# @!attribute [r] arguments
|
|
11
|
+
# @return [Array<String>] An Array of arguments to be mapped to an Action's Queries.
|
|
12
|
+
attr_reader :arguments
|
|
13
|
+
|
|
14
|
+
def initialize verb, arguments
|
|
15
|
+
@verb = verb
|
|
16
|
+
@arguments = arguments
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -1,47 +1,58 @@
|
|
|
1
1
|
class Array
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
# @return [Array]
|
|
3
|
+
def that_are(cls)
|
|
4
|
+
if (cls.kind_of?(Class) or cls.kind_of?(Module))
|
|
5
|
+
return self.clone.delete_if { |i| i.kind_of?(cls) == false }
|
|
5
6
|
elsif cls.kind_of?(Symbol)
|
|
6
|
-
return self.clone.delete_if { |i| i.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
return self.clone.delete_if { |i| i.send(cls) == false }
|
|
8
|
+
else
|
|
9
|
+
if self.include?(cls)
|
|
10
|
+
return [cls]
|
|
11
|
+
end
|
|
12
|
+
return Array.new
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
# @return [Array]
|
|
16
|
+
def that_are_not(cls)
|
|
17
|
+
if (cls.kind_of?(Class) or cls.kind_of?(Module))
|
|
18
|
+
return self.clone.delete_if { |i| i.kind_of?(cls) == true }
|
|
17
19
|
elsif cls.kind_of?(Symbol)
|
|
18
|
-
return self.clone.delete_if { |i| i.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
return self.clone.delete_if { |i| i.send(cls) == true }
|
|
21
|
+
else
|
|
22
|
+
return self.clone - [cls]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
def random
|
|
26
|
+
return self[rand(self.length)]
|
|
27
|
+
end
|
|
26
28
|
def pop_random
|
|
27
29
|
delete_at(rand(self.length))
|
|
28
30
|
end
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
31
|
+
# @return [Array]
|
|
32
|
+
def shuffle
|
|
33
|
+
self.sort { |a, b|
|
|
34
|
+
rand(3) <=> rand(3)
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
# @return [Array]
|
|
38
|
+
def shuffle!
|
|
39
|
+
self.sort! { |a, b|
|
|
40
|
+
rand(3) <=> rand(3)
|
|
41
|
+
}
|
|
42
|
+
end
|
|
43
|
+
# Get a string representation of the array that separated elements with
|
|
44
|
+
# commas and adds a conjunction before the last element.
|
|
45
|
+
# @return [String]
|
|
46
|
+
def join_and(sep = ', ', andSep = ' and ', serial = true)
|
|
47
|
+
if self.length < 3
|
|
48
|
+
self.join(andSep)
|
|
49
|
+
else
|
|
50
|
+
start = self - [self.last]
|
|
51
|
+
start.join(sep) + "#{serial ? sep.strip : ''}#{andSep}#{self.last}"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
# @return [String]
|
|
55
|
+
def join_or(sep = ', ', orSep = ' or ', serial = true)
|
|
56
|
+
join_and(sep, orSep, serial)
|
|
57
|
+
end
|
|
47
58
|
end
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
class String
|
|
2
|
+
# Capitalize the first letter without changing the rest of the string.
|
|
3
|
+
# (String#capitalize makes the rest of the string lower-case.)
|
|
2
4
|
def capitalize_first
|
|
3
5
|
"#{self[0,1].upcase}#{self[1,self.length]}"
|
|
4
6
|
end
|
|
7
|
+
# @return [String]
|
|
5
8
|
def cap_first
|
|
6
9
|
self.capitalize_first
|
|
7
10
|
end
|
|
11
|
+
# @return [Array]
|
|
8
12
|
def split_words
|
|
9
13
|
self.gsub(/ +/, ' ').strip.split
|
|
10
14
|
end
|