gamefic 1.7.0 → 2.0.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 +5 -5
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.rubocop.yml +13 -0
- data/.solargraph.yml +5 -0
- data/Gemfile +7 -0
- data/LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +10 -0
- data/gamefic.gemspec +27 -0
- data/lib/gamefic.rb +7 -6
- data/lib/gamefic/action.rb +38 -28
- data/lib/gamefic/active.rb +325 -280
- data/lib/gamefic/actor.rb +8 -5
- data/lib/gamefic/command.rb +9 -7
- data/lib/gamefic/core_ext/array.rb +24 -49
- data/lib/gamefic/core_ext/string.rb +25 -16
- data/lib/gamefic/describable.rb +21 -23
- data/lib/gamefic/element.rb +43 -31
- data/lib/gamefic/entity.rb +6 -12
- data/lib/gamefic/index.rb +121 -0
- data/lib/gamefic/{matchable.rb → keywords.rb} +52 -50
- data/lib/gamefic/messaging.rb +43 -44
- data/lib/gamefic/node.rb +14 -5
- data/lib/gamefic/plot.rb +69 -89
- data/lib/gamefic/plot/darkroom.rb +92 -264
- data/lib/gamefic/plot/host.rb +42 -48
- data/lib/gamefic/plot/snapshot.rb +5 -18
- data/lib/gamefic/query.rb +14 -18
- data/lib/gamefic/query/base.rb +30 -18
- data/lib/gamefic/query/children.rb +0 -0
- data/lib/gamefic/query/external.rb +18 -14
- data/lib/gamefic/query/family.rb +1 -7
- data/lib/gamefic/query/matches.rb +75 -67
- data/lib/gamefic/query/parent.rb +0 -0
- data/lib/gamefic/query/siblings.rb +0 -0
- data/lib/gamefic/query/text.rb +2 -1
- data/lib/gamefic/scene.rb +0 -2
- data/lib/gamefic/scene/activity.rb +24 -26
- data/lib/gamefic/scene/base.rb +64 -8
- data/lib/gamefic/scene/conclusion.rb +0 -2
- data/lib/gamefic/scene/custom.rb +0 -2
- data/lib/gamefic/scene/multiple_choice.rb +18 -3
- data/lib/gamefic/scene/multiple_scene.rb +29 -20
- data/lib/gamefic/scene/pause.rb +7 -2
- data/lib/gamefic/scene/yes_or_no.rb +21 -9
- data/lib/gamefic/scriptable.rb +87 -0
- data/lib/gamefic/serialize.rb +68 -0
- data/lib/gamefic/subplot.rb +29 -35
- data/lib/gamefic/syntax.rb +14 -13
- data/lib/gamefic/version.rb +3 -3
- data/lib/gamefic/world.rb +16 -0
- data/lib/gamefic/world/callbacks.rb +135 -0
- data/lib/gamefic/world/commands.rb +184 -0
- data/lib/gamefic/{plot → world}/entities.rb +30 -29
- data/lib/gamefic/{plot → world}/playbook.rb +255 -240
- data/lib/gamefic/world/players.rb +21 -0
- data/lib/gamefic/world/scenes.rb +226 -0
- metadata +41 -92
- data/bin/gamefic +0 -9
- data/lib/gamefic/engine.rb +0 -7
- data/lib/gamefic/engine/base.rb +0 -59
- data/lib/gamefic/engine/tty.rb +0 -24
- data/lib/gamefic/grammar.rb +0 -13
- data/lib/gamefic/grammar/conjugator.rb +0 -20
- data/lib/gamefic/grammar/gender.rb +0 -11
- data/lib/gamefic/grammar/person.rb +0 -10
- data/lib/gamefic/grammar/plural.rb +0 -13
- data/lib/gamefic/grammar/pronouns.rb +0 -106
- data/lib/gamefic/grammar/tense.rb +0 -6
- data/lib/gamefic/grammar/verb_set.rb +0 -43
- data/lib/gamefic/grammar/verbs.rb +0 -26
- data/lib/gamefic/grammar/word_adapter.rb +0 -49
- data/lib/gamefic/plot/articles.rb +0 -22
- data/lib/gamefic/plot/callbacks.rb +0 -126
- data/lib/gamefic/plot/commands.rb +0 -120
- data/lib/gamefic/plot/players.rb +0 -15
- data/lib/gamefic/plot/scenes.rb +0 -187
- data/lib/gamefic/plot/theater.rb +0 -73
- data/lib/gamefic/plot/you_mount.rb +0 -22
- data/lib/gamefic/script.rb +0 -13
- data/lib/gamefic/script/base.rb +0 -42
- data/lib/gamefic/script/file.rb +0 -14
- data/lib/gamefic/script/text.rb +0 -14
- data/lib/gamefic/shell.rb +0 -76
- data/lib/gamefic/source.rb +0 -14
- data/lib/gamefic/source/base.rb +0 -12
- data/lib/gamefic/source/file.rb +0 -23
- data/lib/gamefic/source/text.rb +0 -16
- data/lib/gamefic/tester.rb +0 -19
- data/lib/gamefic/text.rb +0 -8
- data/lib/gamefic/text/ansi.rb +0 -53
- data/lib/gamefic/text/html.rb +0 -68
- data/lib/gamefic/text/html/conversions.rb +0 -250
- data/lib/gamefic/text/html/entities.rb +0 -9
- data/lib/gamefic/tty.rb +0 -10
- data/lib/gamefic/user.rb +0 -7
- data/lib/gamefic/user/base.rb +0 -29
- data/lib/gamefic/user/tty.rb +0 -38
data/lib/gamefic/syntax.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
require 'gamefic/command'
|
2
2
|
|
3
3
|
module Gamefic
|
4
|
-
|
5
4
|
class Syntax
|
6
5
|
attr_reader :token_count, :first_word, :verb, :template, :command
|
7
|
-
|
8
|
-
|
6
|
+
|
9
7
|
def initialize template, command
|
10
8
|
words = template.split_words
|
11
9
|
@token_count = words.length
|
@@ -15,8 +13,8 @@ module Gamefic
|
|
15
13
|
@token_count -= 1
|
16
14
|
@first_word = ''
|
17
15
|
else
|
18
|
-
@verb = command_words[0].to_sym if !command_words[0].nil?
|
19
16
|
@first_word = words[0].to_s
|
17
|
+
@verb = command_words[0].to_sym
|
20
18
|
end
|
21
19
|
@command = command_words.join(' ')
|
22
20
|
@template = words.join(' ')
|
@@ -29,7 +27,7 @@ module Gamefic
|
|
29
27
|
if last_token_is_reg
|
30
28
|
next
|
31
29
|
else
|
32
|
-
tokens.push
|
30
|
+
tokens.push '([\w\W\s\S]*?)'
|
33
31
|
last_token_is_reg = true
|
34
32
|
end
|
35
33
|
else
|
@@ -50,11 +48,11 @@ module Gamefic
|
|
50
48
|
@replace = subs.join(' ')
|
51
49
|
@regexp = Regexp.new("^#{tokens.join(' ')}$", Regexp::IGNORECASE)
|
52
50
|
end
|
53
|
-
|
51
|
+
|
54
52
|
# Convert a String into a Command.
|
55
53
|
#
|
56
54
|
# @param text [String]
|
57
|
-
# @return [Command]
|
55
|
+
# @return [Gamefic::Command]
|
58
56
|
def tokenize text
|
59
57
|
m = text.match(@regexp)
|
60
58
|
return nil if m.nil?
|
@@ -71,7 +69,11 @@ module Gamefic
|
|
71
69
|
}
|
72
70
|
Command.new @verb, arguments
|
73
71
|
end
|
74
|
-
|
72
|
+
|
73
|
+
# Determine if the specified text matches the syntax's expected pattern.
|
74
|
+
#
|
75
|
+
# @param text [String]
|
76
|
+
# @return [Boolean]
|
75
77
|
def accept? text
|
76
78
|
!text.match(@regexp).nil?
|
77
79
|
end
|
@@ -82,16 +84,16 @@ module Gamefic
|
|
82
84
|
def signature
|
83
85
|
[@regexp, @replace]
|
84
86
|
end
|
85
|
-
|
87
|
+
|
86
88
|
def ==(other)
|
87
89
|
signature == other.signature
|
88
90
|
end
|
89
|
-
|
91
|
+
|
90
92
|
# Tokenize an Array of Commands from the specified text.
|
91
93
|
#
|
92
94
|
# @param text [String] The text to tokenize.
|
93
|
-
# @param syntaxes [Array<Syntax>] The Syntaxes to use.
|
94
|
-
# @return [Array<Command>] The tokenized commands.
|
95
|
+
# @param syntaxes [Array<Gamefic::Syntax>] The Syntaxes to use.
|
96
|
+
# @return [Array<Gamefic::Command>] The tokenized commands.
|
95
97
|
def self.tokenize text, syntaxes
|
96
98
|
matches = []
|
97
99
|
syntaxes.each { |syntax|
|
@@ -108,5 +110,4 @@ module Gamefic
|
|
108
110
|
matches
|
109
111
|
end
|
110
112
|
end
|
111
|
-
|
112
113
|
end
|
data/lib/gamefic/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module Gamefic
|
2
|
-
VERSION = '
|
3
|
-
end
|
1
|
+
module Gamefic
|
2
|
+
VERSION = '2.0.0'
|
3
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Gamefic
|
2
|
+
module World
|
3
|
+
autoload :Playbook, 'gamefic/world/playbook'
|
4
|
+
autoload :Entities, 'gamefic/world/entities'
|
5
|
+
autoload :Commands, 'gamefic/world/commands'
|
6
|
+
autoload :Callbacks, 'gamefic/world/callbacks'
|
7
|
+
autoload :Scenes, 'gamefic/world/scenes'
|
8
|
+
autoload :Players, 'gamefic/world/players'
|
9
|
+
|
10
|
+
include Entities
|
11
|
+
include Commands
|
12
|
+
include Callbacks
|
13
|
+
include Scenes
|
14
|
+
include Players
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
module Gamefic
|
2
|
+
module World
|
3
|
+
module Callbacks
|
4
|
+
# Add a block to be executed on preparation of every turn.
|
5
|
+
#
|
6
|
+
# @example Increment a turn counter
|
7
|
+
# turn = 0
|
8
|
+
# on_ready do
|
9
|
+
# turn += 1
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
def on_ready &block
|
13
|
+
ready_procs.push block
|
14
|
+
end
|
15
|
+
|
16
|
+
# Add a block to be executed after the Plot is finished updating a turn.
|
17
|
+
#
|
18
|
+
def on_update &block
|
19
|
+
update_procs.push block
|
20
|
+
end
|
21
|
+
|
22
|
+
# Add a block to be executed for each player at the beginning of a turn.
|
23
|
+
#
|
24
|
+
# @example Tell the player how many turns they've played.
|
25
|
+
# on_player_ready do |player|
|
26
|
+
# player[:turns] ||= 0
|
27
|
+
# if player[:turns] > 0
|
28
|
+
# player.tell "Turn #{player[:turns]}"
|
29
|
+
# end
|
30
|
+
# player[:turns] += 1
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# @yieldparam [Gamefic::Actor]
|
34
|
+
def on_player_ready &block
|
35
|
+
player_ready_procs.push block
|
36
|
+
end
|
37
|
+
|
38
|
+
# Add a block to be executed for each player before an update.
|
39
|
+
#
|
40
|
+
# @yieldparam[Gamefic::Actor]
|
41
|
+
def before_player_update &block
|
42
|
+
before_player_update_procs.push block
|
43
|
+
end
|
44
|
+
|
45
|
+
# Add a block to be executed for each player at the end of a turn.
|
46
|
+
#
|
47
|
+
# @yieldparam [Gamefic::Actor]
|
48
|
+
def on_player_update &block
|
49
|
+
player_update_procs.push block
|
50
|
+
end
|
51
|
+
|
52
|
+
# Add a block to be executed at the conclusion of the plot.
|
53
|
+
#
|
54
|
+
# @yieldparam [Gamefic::Actor]
|
55
|
+
def on_player_conclude &block
|
56
|
+
player_conclude_procs.push block
|
57
|
+
end
|
58
|
+
|
59
|
+
def player_conclude_procs
|
60
|
+
@player_conclude_procs ||= []
|
61
|
+
end
|
62
|
+
|
63
|
+
def ready_procs
|
64
|
+
@ready_procs ||= []
|
65
|
+
end
|
66
|
+
|
67
|
+
def update_procs
|
68
|
+
@update_procs ||= []
|
69
|
+
end
|
70
|
+
|
71
|
+
def player_ready_procs
|
72
|
+
@player_ready_procs ||= []
|
73
|
+
end
|
74
|
+
|
75
|
+
def before_player_update_procs
|
76
|
+
@before_player_update_procs ||= []
|
77
|
+
end
|
78
|
+
|
79
|
+
def player_update_procs
|
80
|
+
@player_update_procs ||= []
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
# Execute the on_ready blocks. This method is typically called by the
|
86
|
+
# Plot while beginning a turn.
|
87
|
+
#
|
88
|
+
def call_ready
|
89
|
+
ready_procs.each { |p| p.call }
|
90
|
+
end
|
91
|
+
|
92
|
+
# Execute the on_update blocks. This method is typically called by the
|
93
|
+
# Plot while ending a turn.
|
94
|
+
#
|
95
|
+
def call_update
|
96
|
+
update_procs.each { |p| p.call }
|
97
|
+
end
|
98
|
+
|
99
|
+
# Execute the before_player_update blocks for each player. This method is
|
100
|
+
# typically called by the Plot while updating a turn, immediately before
|
101
|
+
# processing player input.
|
102
|
+
#
|
103
|
+
def call_before_player_update
|
104
|
+
players.each { |player|
|
105
|
+
player.flush
|
106
|
+
before_player_update_procs.each { |block| block.call player }
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
# Execute the on_player_ready blocks for each player. This method is
|
111
|
+
# typically called by the Plot while beginning a turn, immediately after
|
112
|
+
# the on_ready blocks.
|
113
|
+
#
|
114
|
+
def call_player_ready
|
115
|
+
players.each { |player|
|
116
|
+
unless player.next_scene.nil? || !player.scene.finished?
|
117
|
+
player.cue player.next_scene, **player.next_options
|
118
|
+
end
|
119
|
+
player.cue default_scene if player.scene.nil?
|
120
|
+
player_ready_procs.each { |block| block.call player }
|
121
|
+
}
|
122
|
+
end
|
123
|
+
|
124
|
+
# Execute the on_player_update blocks for each player. This method is
|
125
|
+
# typically called by the Plot while ending a turn, immediately before the
|
126
|
+
# on_ready blocks.
|
127
|
+
#
|
128
|
+
def call_player_update
|
129
|
+
players.each { |player|
|
130
|
+
player_update_procs.each { |block| block.call player }
|
131
|
+
}
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'gamefic/action'
|
2
|
+
|
3
|
+
module Gamefic
|
4
|
+
module World
|
5
|
+
module Commands
|
6
|
+
include Gamefic::World::Entities
|
7
|
+
|
8
|
+
# @return [Gamefic::World::Playbook]
|
9
|
+
def playbook
|
10
|
+
@playbook ||= Gamefic::World::Playbook.new
|
11
|
+
end
|
12
|
+
|
13
|
+
# Create an Action that responds to a command.
|
14
|
+
# An Action uses the command argument to identify the imperative verb that
|
15
|
+
# triggers the action.
|
16
|
+
# It can also accept queries to tokenize the remainder of the input and
|
17
|
+
# filter for particular entities or properties.
|
18
|
+
# The block argument contains the code to be executed when the input
|
19
|
+
# matches all of the Action's criteria (i.e., verb and queries).
|
20
|
+
#
|
21
|
+
# @example A simple Action.
|
22
|
+
# respond :salute do |actor|
|
23
|
+
# actor.tell "Hello, sir!"
|
24
|
+
# end
|
25
|
+
# # The command "salute" will respond "Hello, sir!"
|
26
|
+
#
|
27
|
+
# @example An Action that accepts a Character
|
28
|
+
# respond :salute, Use.visible(Character) do |actor, character|
|
29
|
+
# actor.tell "#{The character} returns your salute."
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# @param command [Symbol] An imperative verb for the command
|
33
|
+
# @param queries [Array<Query::Base>] Filters for the command's tokens
|
34
|
+
# @yieldparam [Gamefic::Actor]
|
35
|
+
# @return [Class] The resulting Action subclass
|
36
|
+
def respond(command, *queries, &proc)
|
37
|
+
playbook.respond(command, *map_response_args(queries), &proc)
|
38
|
+
end
|
39
|
+
alias action respond
|
40
|
+
|
41
|
+
# Parse a verb and a list of arguments into an action.
|
42
|
+
# This method serves as a shortcut to creating an action with one or more
|
43
|
+
# arguments that identify specific entities.
|
44
|
+
#
|
45
|
+
# @example
|
46
|
+
# @thing = make Entity, name: 'a thing'
|
47
|
+
# parse "use", "the thing" do |actor, thing|
|
48
|
+
# actor.tell "You use it."
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# @raise [ArgumentError] if tokens are unrecognized or ambiguous
|
52
|
+
#
|
53
|
+
# @param verb [String, Symbol] The command's verb
|
54
|
+
# @param tokens [Array<String>] The arguments passed to the action
|
55
|
+
# @return [Class] The resulting Action subclass
|
56
|
+
def parse verb, *tokens, &proc
|
57
|
+
query = Query::External.new(entities)
|
58
|
+
params = []
|
59
|
+
tokens.each do |arg|
|
60
|
+
matches = query.resolve(nil, arg)
|
61
|
+
raise ArgumentError, "Unable to resolve token '#{arg}'" if matches.objects.empty?
|
62
|
+
raise ArgumentError, "Ambiguous results for '#{arg}'" if matches.objects.length > 1
|
63
|
+
params.push Query::Family.new(matches.objects[0])
|
64
|
+
end
|
65
|
+
respond(verb.to_sym, *params, &proc)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Tokenize and parse a command to create a new Action subclass.
|
69
|
+
#
|
70
|
+
# @param command [String] The command
|
71
|
+
# @yieldparam [Gamefic::Actor]
|
72
|
+
# @return [Class] the resulting Action subclass
|
73
|
+
def override(command, &proc)
|
74
|
+
cmd = Syntax.tokenize(command, playbook.syntaxes).first
|
75
|
+
raise "Unable to tokenize command '#{command}'" if cmd.nil?
|
76
|
+
parse cmd.verb, *cmd.arguments, &proc
|
77
|
+
end
|
78
|
+
|
79
|
+
# Create a Meta Action that responds to a command.
|
80
|
+
# Meta Actions are very similar to standard Actions, except the Plot
|
81
|
+
# understands them to be commands that operate above and/or outside of the
|
82
|
+
# actual game world. Examples of Meta Actions are commands that report the
|
83
|
+
# player's current score, save and restore saved games, or list the game's
|
84
|
+
# credits.
|
85
|
+
#
|
86
|
+
# @example A simple Meta Action
|
87
|
+
# meta :credits do |actor|
|
88
|
+
# actor.tell "This game was written by John Smith."
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# @param command [Symbol] An imperative verb for the command
|
92
|
+
# @param queries [Array<Query::Base>] Filters for the command's tokens
|
93
|
+
# @yieldparam [Gamefic::Actor]
|
94
|
+
def meta(command, *queries, &proc)
|
95
|
+
playbook.meta command, *queries, &proc
|
96
|
+
end
|
97
|
+
|
98
|
+
# Declare a dismabiguation response for actions.
|
99
|
+
# The disambigurator is executed when an action expects an argument to
|
100
|
+
# reference a specific entity but its query matched more than one. For
|
101
|
+
# example, "red" might refer to either a red key or a red book.
|
102
|
+
#
|
103
|
+
# If a disambiguator is not defined, the playbook will use its default
|
104
|
+
# implementation.
|
105
|
+
#
|
106
|
+
# @example Tell the player the list of ambiguous entities.
|
107
|
+
# disambiguate do |actor, entities|
|
108
|
+
# actor.tell "I don't know which you mean: #{entities.join_or}."
|
109
|
+
# end
|
110
|
+
#
|
111
|
+
# @yieldparam [Gamefic::Actor]
|
112
|
+
# @yieldparam [Array<Gamefic::Entity>]
|
113
|
+
def disambiguate &block
|
114
|
+
playbook.disambiguate &block
|
115
|
+
end
|
116
|
+
|
117
|
+
# Validate an order before a character can execute its command.
|
118
|
+
#
|
119
|
+
# @yieldparam [Gamefic::Director::Order]
|
120
|
+
def validate &block
|
121
|
+
playbook.validate &block
|
122
|
+
end
|
123
|
+
|
124
|
+
# Create an alternate Syntax for an Action.
|
125
|
+
# The command and its translation can be parameterized.
|
126
|
+
#
|
127
|
+
# @example Create a synonym for the Inventory Action.
|
128
|
+
# interpret "catalogue", "inventory"
|
129
|
+
# # The command "catalogue" will be translated to "inventory"
|
130
|
+
#
|
131
|
+
# @example Create a parameterized synonym for the Look Action.
|
132
|
+
# interpret "scrutinize :entity", "look :entity"
|
133
|
+
# # The command "scrutinize chair" will be translated to "look chair"
|
134
|
+
#
|
135
|
+
# @param command [String] The format of the original command
|
136
|
+
# @param translation [String] The format of the translated command
|
137
|
+
# @return [Syntax] the Syntax object
|
138
|
+
def interpret command, translation
|
139
|
+
playbook.interpret command, translation
|
140
|
+
end
|
141
|
+
alias xlate interpret
|
142
|
+
|
143
|
+
# Get an Array of available verbs.
|
144
|
+
#
|
145
|
+
# @return [Array<String>]
|
146
|
+
def verbs
|
147
|
+
playbook.verbs.map { |v| v.to_s }.reject{ |v| v.start_with?('_') }
|
148
|
+
end
|
149
|
+
|
150
|
+
# Get an Array of all Actions defined in the Plot.
|
151
|
+
#
|
152
|
+
# @return [Array<Action>]
|
153
|
+
def actions
|
154
|
+
playbook.actions
|
155
|
+
end
|
156
|
+
|
157
|
+
def get_default_query
|
158
|
+
@default_query_class ||= Gamefic::Query::Family
|
159
|
+
end
|
160
|
+
|
161
|
+
def set_default_query cls
|
162
|
+
@default_query_class = cls
|
163
|
+
end
|
164
|
+
|
165
|
+
private
|
166
|
+
|
167
|
+
def map_response_args queries
|
168
|
+
result = []
|
169
|
+
queries.each do |q|
|
170
|
+
if q.is_a?(Regexp)
|
171
|
+
result.push Gamefic::Query::Text.new(q)
|
172
|
+
elsif q.is_a?(Gamefic::Query::Base)
|
173
|
+
result.push q
|
174
|
+
elsif q.is_a?(Gamefic::Element) || (q.is_a?(Class) && q <= Gamefic::Element)
|
175
|
+
result.push get_default_query.new(q)
|
176
|
+
else
|
177
|
+
raise ArgumentError.new("Invalid argument for response: #{q}")
|
178
|
+
end
|
179
|
+
end
|
180
|
+
result
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module Gamefic
|
2
|
-
|
3
|
-
class Plot
|
2
|
+
module World
|
4
3
|
module Entities
|
5
4
|
# Make a new Entity with the provided properties.
|
6
5
|
#
|
@@ -8,16 +7,16 @@ module Gamefic
|
|
8
7
|
# chair = make Entity, name: 'red chair'
|
9
8
|
# chair.name #=> 'red chair'
|
10
9
|
#
|
10
|
+
# @raise [ArgumentError] if class is not an Entity
|
11
|
+
#
|
11
12
|
# @param cls [Class] The Class of the Entity to be created.
|
12
13
|
# @param args [Hash] The entity's properties.
|
13
|
-
#
|
14
|
+
# @!macro [attach] make_entity
|
15
|
+
# @return [$1]
|
14
16
|
def make cls, args = {}, &block
|
17
|
+
raise ArgumentError, "Invalid Entity class" unless cls.is_a?(Class) && cls <= Entity
|
15
18
|
ent = cls.new args, &block
|
16
|
-
|
17
|
-
raise "Invalid entity class"
|
18
|
-
end
|
19
|
-
p_entities.push ent
|
20
|
-
p_dynamic.push ent if running?
|
19
|
+
entities.push ent
|
21
20
|
ent
|
22
21
|
end
|
23
22
|
|
@@ -34,13 +33,21 @@ module Gamefic
|
|
34
33
|
ent
|
35
34
|
end
|
36
35
|
|
36
|
+
# Safely remove an entity from a plot.
|
37
|
+
#
|
38
|
+
# If the entity is dynamic (e.g., created after a plot is already
|
39
|
+
# running), it is safe to delete it completely. Otherwise the entity
|
40
|
+
# will still be referenced in the entities array, but its parent will be
|
41
|
+
# set to nil.
|
42
|
+
#
|
43
|
+
# @param [Gamefic::Entity] The entity to remove
|
37
44
|
def destroy entity
|
38
|
-
if p_dynamic.include?(entity)
|
39
|
-
p_entities.delete entity
|
40
|
-
p_dynamic.delete entity
|
41
|
-
p_players.delete entity
|
42
|
-
end
|
43
45
|
entity.parent = nil
|
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
|
44
51
|
end
|
45
52
|
|
46
53
|
# Pick an entity based on its description.
|
@@ -49,7 +56,7 @@ module Gamefic
|
|
49
56
|
#
|
50
57
|
# @example Select the Entity that matches the description
|
51
58
|
# red_chair = make Entity, :name => 'red chair'
|
52
|
-
# blue_chair make Entity, :name => 'blue chair'
|
59
|
+
# blue_chair = make Entity, :name => 'blue chair'
|
53
60
|
# pick "red chair" #=> red_chair
|
54
61
|
# pick "blue chair" #=> blue_chair
|
55
62
|
# pick "chair" #=> IndexError: description is ambiguous
|
@@ -57,8 +64,7 @@ module Gamefic
|
|
57
64
|
# @param description [String] The description of the entity
|
58
65
|
# @return [Gamefic::Entity] The entity that matches the description
|
59
66
|
def pick(description)
|
60
|
-
|
61
|
-
result = query.match(description, entities)
|
67
|
+
result = Query::Matches.execute(entities, description)
|
62
68
|
if result.objects.length == 0
|
63
69
|
raise IndexError.new("Unable to find entity from '#{description}'")
|
64
70
|
elsif result.objects.length > 1
|
@@ -69,32 +75,27 @@ module Gamefic
|
|
69
75
|
|
70
76
|
# Get an array of entities associated with this plot.
|
71
77
|
#
|
72
|
-
# @return [Array<Entity>]
|
78
|
+
# @return [Array<Gamefic::Entity>]
|
73
79
|
def entities
|
74
|
-
|
80
|
+
@entities ||= []
|
75
81
|
end
|
76
82
|
|
77
83
|
# Get an array of players associated with this plot.
|
78
84
|
#
|
79
|
-
# @return [Array<
|
85
|
+
# @return [Array<Gamefic::Actor>]
|
80
86
|
def players
|
81
|
-
|
87
|
+
@players ||= []
|
82
88
|
end
|
83
89
|
|
84
90
|
private
|
85
91
|
|
86
|
-
def
|
87
|
-
@
|
88
|
-
end
|
89
|
-
|
90
|
-
def p_players
|
91
|
-
@p_players ||= []
|
92
|
+
def mark_static_entities
|
93
|
+
@static_entity_length ||= entities.length
|
92
94
|
end
|
93
95
|
|
94
|
-
def
|
95
|
-
@
|
96
|
+
def static_entity_length
|
97
|
+
@static_entity_length || 0
|
96
98
|
end
|
97
99
|
end
|
98
100
|
end
|
99
|
-
|
100
101
|
end
|