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
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
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
|
-
|
|
123
|
-
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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
|
-
|
|
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
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
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.
|
|
320
|
+
@commands[action.verb].delete(action)
|
|
264
321
|
end
|
|
265
322
|
def rem_syntax(syntax)
|
|
266
323
|
@syntaxes.delete syntax
|
|
267
324
|
end
|
|
268
|
-
|
|
269
|
-
|
|
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
|
|