gamefic 1.5.1 → 1.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.rb +1 -3
- data/lib/gamefic/action.rb +140 -79
- data/lib/gamefic/character.rb +120 -53
- data/lib/gamefic/character/state.rb +12 -0
- data/lib/gamefic/core_ext/array.rb +53 -11
- data/lib/gamefic/core_ext/string.rb +1 -0
- data/lib/gamefic/describable.rb +37 -11
- data/lib/gamefic/engine/base.rb +17 -4
- data/lib/gamefic/engine/tty.rb +4 -0
- data/lib/gamefic/entity.rb +4 -15
- data/lib/gamefic/matchable.rb +50 -0
- data/lib/gamefic/messaging.rb +45 -0
- data/lib/gamefic/node.rb +16 -0
- data/lib/gamefic/plot.rb +27 -33
- data/lib/gamefic/plot/{article_mount.rb → articles.rb} +22 -22
- data/lib/gamefic/plot/callbacks.rb +30 -4
- data/lib/gamefic/plot/{command_mount.rb → commands.rb} +121 -121
- data/lib/gamefic/plot/entities.rb +3 -3
- data/lib/gamefic/plot/host.rb +3 -3
- data/lib/gamefic/plot/playbook.rb +74 -30
- data/lib/gamefic/plot/scenes.rb +149 -0
- data/lib/gamefic/plot/snapshot.rb +14 -39
- data/lib/gamefic/plot/theater.rb +73 -0
- data/lib/gamefic/query.rb +6 -19
- data/lib/gamefic/query/base.rb +127 -246
- data/lib/gamefic/query/children.rb +6 -7
- data/lib/gamefic/query/descendants.rb +15 -0
- data/lib/gamefic/query/family.rb +19 -7
- data/lib/gamefic/query/itself.rb +13 -0
- data/lib/gamefic/query/matches.rb +67 -11
- data/lib/gamefic/query/parent.rb +6 -7
- data/lib/gamefic/query/siblings.rb +10 -7
- data/lib/gamefic/query/text.rb +39 -35
- data/lib/gamefic/scene.rb +1 -1
- data/lib/gamefic/scene/active.rb +12 -6
- data/lib/gamefic/scene/base.rb +56 -5
- data/lib/gamefic/scene/conclusion.rb +3 -0
- data/lib/gamefic/scene/custom.rb +0 -83
- data/lib/gamefic/scene/multiple_choice.rb +54 -32
- data/lib/gamefic/scene/multiple_scene.rb +11 -6
- data/lib/gamefic/scene/pause.rb +3 -4
- data/lib/gamefic/scene/yes_or_no.rb +23 -9
- data/lib/gamefic/script/base.rb +4 -0
- data/lib/gamefic/subplot.rb +22 -19
- data/lib/gamefic/syntax.rb +7 -15
- data/lib/gamefic/user/base.rb +7 -13
- data/lib/gamefic/user/buffer.rb +7 -0
- data/lib/gamefic/user/tty.rb +13 -12
- data/lib/gamefic/version.rb +1 -1
- metadata +11 -37
- data/lib/gamefic/director.rb +0 -23
- data/lib/gamefic/director/delegate.rb +0 -126
- data/lib/gamefic/director/order.rb +0 -17
- data/lib/gamefic/director/parser.rb +0 -137
- data/lib/gamefic/keywords.rb +0 -67
- data/lib/gamefic/plot/query_mount.rb +0 -9
- data/lib/gamefic/plot/scene_mount.rb +0 -182
- data/lib/gamefic/query/ambiguous_children.rb +0 -5
- data/lib/gamefic/query/expression.rb +0 -47
- data/lib/gamefic/query/many_children.rb +0 -7
- data/lib/gamefic/query/plural_children.rb +0 -14
- data/lib/gamefic/query/self.rb +0 -10
- data/lib/gamefic/scene_data.rb +0 -10
- data/lib/gamefic/scene_data/base.rb +0 -12
- data/lib/gamefic/scene_data/multiple_choice.rb +0 -19
- data/lib/gamefic/scene_data/multiple_scene.rb +0 -21
- data/lib/gamefic/scene_data/yes_or_no.rb +0 -18
- data/lib/gamefic/serialized.rb +0 -24
- data/lib/gamefic/stage.rb +0 -106
@@ -8,54 +8,76 @@ module Gamefic
|
|
8
8
|
# instead of a String.
|
9
9
|
#
|
10
10
|
class Scene::MultipleChoice < Scene::Custom
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
attr_reader :index
|
12
|
+
attr_reader :number
|
13
|
+
attr_reader :selection
|
14
|
+
attr_writer :invalid_message
|
14
15
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
do_start_block actor, data
|
19
|
-
tell_options actor, data
|
16
|
+
def post_initialize
|
17
|
+
self.type = 'MultipleChoice'
|
18
|
+
self.prompt = 'Enter a choice:'
|
20
19
|
end
|
20
|
+
|
21
|
+
#def start actor
|
22
|
+
# data = start_data_for(actor)
|
23
|
+
# data.clear
|
24
|
+
# do_start_block actor, data
|
25
|
+
# tell_options
|
26
|
+
#end
|
21
27
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
+
def start
|
29
|
+
super
|
30
|
+
raise "MultipleChoice scene has zero options" if options.empty?
|
31
|
+
end
|
32
|
+
|
33
|
+
def finish
|
34
|
+
#data = finish_data_for(actor, input)
|
35
|
+
get_choice
|
36
|
+
if selection.nil?
|
37
|
+
actor.tell invalid_message
|
38
|
+
tell_options
|
28
39
|
else
|
29
|
-
|
40
|
+
super
|
30
41
|
end
|
31
|
-
|
42
|
+
end
|
43
|
+
|
44
|
+
def options
|
45
|
+
@options ||= []
|
46
|
+
end
|
47
|
+
|
48
|
+
def invalid_message
|
49
|
+
@invalid_message ||= 'That is not a valid choice.'
|
50
|
+
end
|
51
|
+
|
52
|
+
def state
|
53
|
+
super.merge options: options
|
32
54
|
end
|
33
55
|
|
34
56
|
private
|
35
|
-
|
36
|
-
def get_choice
|
37
|
-
if
|
38
|
-
|
39
|
-
|
40
|
-
|
57
|
+
|
58
|
+
def get_choice
|
59
|
+
if input.strip =~ /^[0-9]+$/ and input.to_i > 0
|
60
|
+
@number = input.to_i
|
61
|
+
@index = number - 1
|
62
|
+
@selection = options[index]
|
41
63
|
else
|
42
|
-
|
43
|
-
|
44
|
-
if o.casecmp(
|
45
|
-
|
46
|
-
|
47
|
-
|
64
|
+
i = 0
|
65
|
+
options.each { |o|
|
66
|
+
if o.casecmp(input).zero?
|
67
|
+
@selection = o
|
68
|
+
@index = i
|
69
|
+
@number = index + 1
|
48
70
|
break
|
49
71
|
end
|
50
|
-
|
72
|
+
i += 1
|
51
73
|
}
|
52
74
|
end
|
53
75
|
end
|
54
76
|
|
55
|
-
def tell_options
|
77
|
+
def tell_options
|
56
78
|
list = '<ol class="multiple_choice">'
|
57
|
-
|
58
|
-
list += "<li>#{o}</li>"
|
79
|
+
options.each { |o|
|
80
|
+
list += "<li><a href=\"#\" rel=\"gamefic\" data-command=\"#{o}\">#{o}</a></li>"
|
59
81
|
}
|
60
82
|
list += "</ol>"
|
61
83
|
actor.tell list
|
@@ -1,14 +1,19 @@
|
|
1
1
|
module Gamefic
|
2
2
|
|
3
3
|
class Scene::MultipleScene < Scene::MultipleChoice
|
4
|
-
def
|
5
|
-
|
4
|
+
def option_map
|
5
|
+
@option_map ||= {}
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
def map option, scene
|
9
|
+
options.push option
|
10
|
+
option_map[option] = scene
|
11
|
+
end
|
12
|
+
|
13
|
+
def finish
|
14
|
+
get_choice
|
15
|
+
unless selection.nil?
|
16
|
+
actor.cue option_map[selection]
|
12
17
|
end
|
13
18
|
end
|
14
19
|
end
|
data/lib/gamefic/scene/pause.rb
CHANGED
@@ -3,10 +3,9 @@ module Gamefic
|
|
3
3
|
# Pause for user input.
|
4
4
|
#
|
5
5
|
class Scene::Pause < Scene::Custom
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
do_start_block actor, data
|
6
|
+
def post_initialize
|
7
|
+
self.type = 'Pause'
|
8
|
+
self.prompt = 'Press enter to continue...'
|
10
9
|
end
|
11
10
|
end
|
12
11
|
|
@@ -6,18 +6,32 @@ module Gamefic
|
|
6
6
|
# other scene has been prepared or cued.
|
7
7
|
#
|
8
8
|
class Scene::YesOrNo < Scene::Custom
|
9
|
-
def
|
10
|
-
|
9
|
+
def post_initialize
|
10
|
+
self.type = 'YesOrNo'
|
11
|
+
self.prompt = 'Yes or No?'
|
11
12
|
end
|
12
13
|
|
13
|
-
def
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
def yes?
|
15
|
+
input.to_s[0,1].downcase == 'y'
|
16
|
+
end
|
17
|
+
|
18
|
+
def no?
|
19
|
+
input.to_s[0,1].downcase == 'n'
|
20
|
+
end
|
21
|
+
|
22
|
+
def invalid_message
|
23
|
+
@invalid_message ||= 'Please enter Yes or No.'
|
24
|
+
end
|
25
|
+
|
26
|
+
def prompt
|
27
|
+
@prompt ||= 'Yes or No?'
|
28
|
+
end
|
29
|
+
|
30
|
+
def finish
|
31
|
+
if yes? or no?
|
32
|
+
super
|
19
33
|
else
|
20
|
-
actor.tell
|
34
|
+
actor.tell invalid_message
|
21
35
|
end
|
22
36
|
end
|
23
37
|
end
|
data/lib/gamefic/script/base.rb
CHANGED
@@ -4,6 +4,7 @@ module Gamefic
|
|
4
4
|
def initialize
|
5
5
|
raise "#initialize must be defined in subclasses"
|
6
6
|
end
|
7
|
+
|
7
8
|
# Get the script's text.
|
8
9
|
# The text must be source code suitable for evaluation via Plot#stage.
|
9
10
|
#
|
@@ -11,12 +12,14 @@ module Gamefic
|
|
11
12
|
def read
|
12
13
|
raise "#read must be defined in subclasses"
|
13
14
|
end
|
15
|
+
|
14
16
|
# Get the script's path.
|
15
17
|
#
|
16
18
|
# @return [String]
|
17
19
|
def path
|
18
20
|
raise "#path must be defined in subclasses"
|
19
21
|
end
|
22
|
+
|
20
23
|
# Get the absolute path of the script's original file, or its URL for
|
21
24
|
# sources that are not file-based.
|
22
25
|
#
|
@@ -24,6 +27,7 @@ module Gamefic
|
|
24
27
|
def absolute_path
|
25
28
|
raise "#absolute_path must be defined in subclasses"
|
26
29
|
end
|
30
|
+
|
27
31
|
# Script objects are equal if their relative paths are the same. Note that
|
28
32
|
# they are still considered equal if their absolute paths are different,
|
29
33
|
# or even if they come from different types of sources.
|
data/lib/gamefic/subplot.rb
CHANGED
@@ -3,42 +3,40 @@ require 'gamefic/plot'
|
|
3
3
|
module Gamefic
|
4
4
|
|
5
5
|
class Subplot
|
6
|
-
include Stage
|
7
|
-
|
8
6
|
attr_reader :plot
|
9
7
|
attr_writer :denied_message
|
10
8
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
# @!parse include Plot::SceneMount
|
18
|
-
mount Plot::SceneMount
|
19
|
-
|
20
|
-
expose :plot, :conclude
|
9
|
+
include Plot::Theater
|
10
|
+
include Plot::Entities
|
11
|
+
include Plot::Commands
|
12
|
+
include Plot::Callbacks
|
13
|
+
include Plot::Scenes
|
14
|
+
include Plot::Articles
|
21
15
|
|
22
16
|
class << self
|
23
|
-
|
24
|
-
@start_proc
|
25
|
-
end
|
17
|
+
attr_reader :start_proc
|
26
18
|
|
27
|
-
|
19
|
+
protected
|
28
20
|
|
29
21
|
def on_start &block
|
30
22
|
@start_proc = block
|
31
23
|
end
|
32
24
|
end
|
33
25
|
|
34
|
-
def initialize plot, introduce: nil
|
26
|
+
def initialize plot, introduce: nil, next_cue: nil, busy_cue: nil
|
35
27
|
@plot = plot
|
28
|
+
@next_cue = next_cue
|
29
|
+
@busy_cue = busy_cue
|
36
30
|
@concluded = false
|
37
31
|
stage &self.class.start_proc unless self.class.start_proc.nil?
|
38
32
|
playbook.freeze
|
39
33
|
self.introduce introduce unless introduce.nil?
|
40
34
|
end
|
41
35
|
|
36
|
+
def subplot
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
42
40
|
def default_scene
|
43
41
|
plot.default_scene
|
44
42
|
end
|
@@ -62,7 +60,11 @@ module Gamefic
|
|
62
60
|
|
63
61
|
def introduce player
|
64
62
|
if plot.in_subplot?(player)
|
65
|
-
|
63
|
+
if @busy_cue.nil?
|
64
|
+
player.tell denied_message
|
65
|
+
else
|
66
|
+
player.cue @busy_cue
|
67
|
+
end
|
66
68
|
else
|
67
69
|
super
|
68
70
|
end
|
@@ -70,6 +72,7 @@ module Gamefic
|
|
70
72
|
|
71
73
|
def exeunt player
|
72
74
|
player.playbook = plot.playbook
|
75
|
+
player.cue (@next_cue || default_scene)
|
73
76
|
p_players.delete player
|
74
77
|
end
|
75
78
|
|
@@ -100,5 +103,5 @@ module Gamefic
|
|
100
103
|
call_update
|
101
104
|
end
|
102
105
|
end
|
103
|
-
|
106
|
+
|
104
107
|
end
|
data/lib/gamefic/syntax.rb
CHANGED
@@ -6,8 +6,7 @@ module Gamefic
|
|
6
6
|
attr_reader :token_count, :first_word, :verb, :template, :command
|
7
7
|
@@phrase = '([\w\W\s\S]*?)'
|
8
8
|
|
9
|
-
def initialize template,
|
10
|
-
command = command.join(' ')
|
9
|
+
def initialize template, command
|
11
10
|
words = template.split_words
|
12
11
|
@token_count = words.length
|
13
12
|
command_words = command.split_words
|
@@ -99,19 +98,12 @@ module Gamefic
|
|
99
98
|
result = syntax.tokenize text
|
100
99
|
matches.push(result) if !result.nil?
|
101
100
|
}
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
ca += 1
|
109
|
-
}
|
110
|
-
b.arguments.each { |t|
|
111
|
-
break if t.nil?
|
112
|
-
cb += 1
|
113
|
-
}
|
114
|
-
cb <=> ca
|
101
|
+
matches.sort! { |a,b|
|
102
|
+
if a.arguments.length == b.arguments.length
|
103
|
+
b.verb.to_s <=> a.verb.to_s
|
104
|
+
else
|
105
|
+
b.arguments.length <=> a.arguments.length
|
106
|
+
end
|
115
107
|
}
|
116
108
|
matches
|
117
109
|
end
|
data/lib/gamefic/user/base.rb
CHANGED
@@ -1,21 +1,15 @@
|
|
1
1
|
module Gamefic
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
class User::Base
|
6
|
-
def send message
|
7
|
-
buffer.send message
|
2
|
+
class User::Base
|
3
|
+
def update state
|
4
|
+
raise 'Unimplemented'
|
8
5
|
end
|
9
6
|
|
10
|
-
def
|
11
|
-
|
7
|
+
def save filename, snapshot
|
8
|
+
raise 'Unimplemented'
|
12
9
|
end
|
13
10
|
|
14
|
-
|
15
|
-
|
16
|
-
def buffer
|
17
|
-
@buffer ||= User::Buffer.new
|
11
|
+
def restore filename
|
12
|
+
raise 'Unimplemented'
|
18
13
|
end
|
19
14
|
end
|
20
|
-
|
21
15
|
end
|
data/lib/gamefic/user/buffer.rb
CHANGED
data/lib/gamefic/user/tty.rb
CHANGED
@@ -6,10 +6,17 @@ module Gamefic
|
|
6
6
|
|
7
7
|
# Extend User::Base to convert HTML into ANSI text.
|
8
8
|
#
|
9
|
+
# @note Due to their dependency on io/console, User::Tty and Engine::Tty are
|
10
|
+
# not included in the core Gamefic library. `require gamefic/tty` if you
|
11
|
+
# need them.
|
12
|
+
#
|
9
13
|
class User::Tty < User::Base
|
14
|
+
def update state
|
15
|
+
print Gamefic::Text::Html::Conversions.html_to_ansi(state[:output])
|
16
|
+
end
|
17
|
+
|
10
18
|
def save filename, snapshot
|
11
|
-
|
12
|
-
json = JSON.generate data
|
19
|
+
json = JSON.generate snapshot
|
13
20
|
if json.nil?
|
14
21
|
@character.tell "Nothing to save."
|
15
22
|
end
|
@@ -21,7 +28,6 @@ module Gamefic
|
|
21
28
|
File.open(filename, 'w') do |f|
|
22
29
|
f.write json
|
23
30
|
end
|
24
|
-
@character.tell "Game saved."
|
25
31
|
end
|
26
32
|
end
|
27
33
|
|
@@ -33,21 +39,16 @@ module Gamefic
|
|
33
39
|
if filename != ''
|
34
40
|
if File.exists?(filename)
|
35
41
|
data = JSON.parse File.read(filename), symbolize_names: true
|
36
|
-
if (data[:metadata] != @character.plot.metadata)
|
37
|
-
|
38
|
-
else
|
42
|
+
#if (data[:metadata] != @character.plot.metadata)
|
43
|
+
# @character.tell "The save file is not compatible with this version of the game."
|
44
|
+
#else
|
39
45
|
return data
|
40
|
-
end
|
46
|
+
#end
|
41
47
|
else
|
42
48
|
@character.tell "File \"#{filename}\" not found."
|
43
49
|
end
|
44
50
|
end
|
45
51
|
nil
|
46
52
|
end
|
47
|
-
|
48
|
-
def flush
|
49
|
-
Gamefic::Text::Html::Conversions.html_to_ansi(super)
|
50
|
-
end
|
51
53
|
end
|
52
|
-
|
53
54
|
end
|
data/lib/gamefic/version.rb
CHANGED