gamefic 1.4.1 → 1.5.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 -2
- data/lib/gamefic/character.rb +31 -45
- data/lib/gamefic/director/delegate.rb +46 -24
- data/lib/gamefic/director/order.rb +7 -0
- data/lib/gamefic/director/parser.rb +11 -11
- data/lib/gamefic/engine/base.rb +2 -3
- data/lib/gamefic/entity.rb +8 -26
- data/lib/gamefic/plot.rb +38 -242
- data/lib/gamefic/plot/callbacks.rb +101 -0
- data/lib/gamefic/plot/command_mount.rb +70 -40
- data/lib/gamefic/plot/entities.rb +82 -0
- data/lib/gamefic/plot/host.rb +46 -0
- data/lib/gamefic/plot/playbook.rb +192 -0
- data/lib/gamefic/plot/players.rb +15 -0
- data/lib/gamefic/plot/scene_mount.rb +69 -31
- data/lib/gamefic/plot/snapshot.rb +20 -5
- data/lib/gamefic/scene/active.rb +8 -1
- data/lib/gamefic/scene/base.rb +4 -26
- data/lib/gamefic/scene/custom.rb +53 -3
- data/lib/gamefic/scene/multiple_choice.rb +1 -0
- data/lib/gamefic/scene/yes_or_no.rb +1 -1
- data/lib/gamefic/scene_data/multiple_scene.rb +0 -4
- data/lib/gamefic/shell.rb +0 -1
- data/lib/gamefic/source/file.rb +1 -1
- data/lib/gamefic/stage.rb +10 -2
- data/lib/gamefic/subplot.rb +70 -53
- data/lib/gamefic/syntax.rb +9 -2
- data/lib/gamefic/tester.rb +1 -1
- data/lib/gamefic/text.rb +8 -0
- data/lib/gamefic/{ansi.rb → text/ansi.rb} +12 -15
- data/lib/gamefic/text/html.rb +68 -0
- data/lib/gamefic/text/html/conversions.rb +250 -0
- data/lib/gamefic/text/html/entities.rb +9 -0
- data/lib/gamefic/tty.rb +2 -0
- data/lib/gamefic/user/tty.rb +2 -4
- data/lib/gamefic/version.rb +1 -1
- metadata +12 -8
- data/lib/gamefic/direction.rb +0 -46
- data/lib/gamefic/html.rb +0 -68
- data/lib/gamefic/html_to_ansi.rb +0 -185
- data/lib/gamefic/plot/entity_mount.rb +0 -45
- data/lib/gamefic/rule.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 567c41f4ddc68dcf42fcb5952d6279250100f117
|
4
|
+
data.tar.gz: 7d2b9383cc049ab220917377ae7c76a7d4adc694
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ce9c4b0051c2e64591b7a08ce693d2817b9c66e94240e3f4ae52ecb012b0e89355ca692efe01dbd502d1590d18e05755c93d96cd2c695e7a4ae068b6e5f8e66
|
7
|
+
data.tar.gz: 318903449d67116cf8da824a29c845180516de69ba4344d1f45499acef3f6cc5c728e3fb31641010dca3735a8a786835a4447a4dea5405a941dd482dcf014ce3
|
data/lib/gamefic.rb
CHANGED
@@ -10,11 +10,10 @@ require "gamefic/scene"
|
|
10
10
|
require "gamefic/query"
|
11
11
|
require "gamefic/action"
|
12
12
|
require "gamefic/syntax"
|
13
|
-
require "gamefic/rule"
|
14
13
|
require "gamefic/director"
|
15
14
|
require "gamefic/plot"
|
15
|
+
require 'gamefic/subplot'
|
16
16
|
require "gamefic/engine"
|
17
17
|
require "gamefic/user"
|
18
|
-
require "gamefic/direction"
|
19
18
|
|
20
19
|
require 'gamefic/version'
|
data/lib/gamefic/character.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require 'gamefic/director'
|
2
2
|
|
3
|
+
class NotConclusionError < Exception
|
4
|
+
end
|
5
|
+
|
3
6
|
module Gamefic
|
4
7
|
class Character < Entity
|
5
8
|
attr_reader :queue, :user
|
@@ -8,10 +11,11 @@ module Gamefic
|
|
8
11
|
# @return [Entity,nil]
|
9
12
|
attr_reader :last_object
|
10
13
|
attr_accessor :object_of_pronoun
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
attr_reader :scene
|
15
|
+
attr_reader :next_scene
|
16
|
+
attr_accessor :playbook
|
17
|
+
|
18
|
+
def initialize(args = {})
|
15
19
|
@queue = Array.new
|
16
20
|
super
|
17
21
|
@buffer_stack = 0
|
@@ -38,20 +42,14 @@ module Gamefic
|
|
38
42
|
#
|
39
43
|
# The command will be executed immediately regardless of game state.
|
40
44
|
#
|
41
|
-
# If the from_user argument is true, the command is assumed to have come
|
42
|
-
# directly from user input. The character's last_order and last_object
|
43
|
-
# will be updated with the result.
|
44
|
-
#
|
45
45
|
# @example Send a command as a string
|
46
46
|
# character.perform "take the key"
|
47
47
|
#
|
48
48
|
# @example Send a command as a set of tokens
|
49
49
|
# character.perform :take, @key
|
50
50
|
#
|
51
|
-
def perform(*command
|
52
|
-
|
53
|
-
last_order = o if from_user
|
54
|
-
o
|
51
|
+
def perform(*command)
|
52
|
+
Director.dispatch(self, *command)
|
55
53
|
end
|
56
54
|
|
57
55
|
# Quietly perform a command.
|
@@ -97,14 +95,6 @@ module Gamefic
|
|
97
95
|
user.send message.strip unless user.nil?
|
98
96
|
end
|
99
97
|
|
100
|
-
# TODO This might not be necessary. The User#quit method was a noop anyway.
|
101
|
-
#def destroy
|
102
|
-
# if @user != nil
|
103
|
-
# @user.quit
|
104
|
-
# end
|
105
|
-
# super
|
106
|
-
#end
|
107
|
-
|
108
98
|
# Proceed to the next Action in the current stack.
|
109
99
|
# This method is typically used in Action blocks to cascade through
|
110
100
|
# multiple implementations of the same verb.
|
@@ -127,46 +117,42 @@ module Gamefic
|
|
127
117
|
# end
|
128
118
|
#
|
129
119
|
def proceed
|
130
|
-
|
131
|
-
delegate_stack.last.proceed
|
120
|
+
Director::Delegate.proceed_for self
|
132
121
|
end
|
133
122
|
|
134
|
-
def cue
|
135
|
-
@scene = scene_name
|
123
|
+
def cue scene
|
136
124
|
@next_scene = nil
|
137
|
-
|
125
|
+
@scene = scene
|
126
|
+
@scene.start self unless @scene.nil?
|
138
127
|
end
|
139
|
-
|
140
|
-
def prepare
|
141
|
-
@next_scene =
|
128
|
+
|
129
|
+
def prepare scene
|
130
|
+
@next_scene = scene
|
142
131
|
end
|
143
132
|
|
144
|
-
def conclude
|
145
|
-
|
146
|
-
|
147
|
-
cue scene_name
|
133
|
+
def conclude scene
|
134
|
+
raise NotConclusionError if !scene.kind_of?(Scene::Conclusion)
|
135
|
+
cue scene
|
148
136
|
end
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
# @return [Symbol] The name of the scene
|
153
|
-
def scene
|
154
|
-
@scene
|
137
|
+
|
138
|
+
def concluded?
|
139
|
+
!scene.nil? and scene.kind_of?(Scene::Conclusion)
|
155
140
|
end
|
156
141
|
|
157
|
-
|
158
|
-
|
159
|
-
cue key.to_sym
|
142
|
+
def performed order
|
143
|
+
@last_order = order
|
160
144
|
end
|
161
|
-
|
162
|
-
def
|
163
|
-
|
145
|
+
|
146
|
+
def prompt
|
147
|
+
scene.nil? ? '>' : scene.prompt_for(self)
|
164
148
|
end
|
165
|
-
|
149
|
+
|
166
150
|
private
|
151
|
+
|
167
152
|
def delegate_stack
|
168
153
|
@delegate_stack ||= []
|
169
154
|
end
|
155
|
+
|
170
156
|
def last_order=(order)
|
171
157
|
return if order.nil?
|
172
158
|
@last_order = order
|
@@ -1,46 +1,54 @@
|
|
1
1
|
module Gamefic
|
2
2
|
module Director
|
3
3
|
class Delegate
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def proceed_for actor
|
7
|
+
return if stack_map[actor].nil?
|
8
|
+
stack_map[actor].last.proceed unless stack_map[actor].last.nil?
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def stack_map
|
14
|
+
@stack_map ||= {}
|
15
|
+
end
|
13
16
|
end
|
14
|
-
|
17
|
+
|
15
18
|
def initialize(actor, orders)
|
16
19
|
@actor = actor
|
17
20
|
@orders = orders
|
21
|
+
@did = []
|
22
|
+
@validated = false
|
18
23
|
end
|
24
|
+
|
19
25
|
def proceed
|
20
26
|
return if @orders.length == 0
|
21
|
-
@actor.send(:delegate_stack).push self
|
22
27
|
executed = false
|
23
28
|
while !executed
|
24
29
|
order = @orders.shift
|
25
30
|
break if order.nil?
|
26
|
-
|
31
|
+
# HACK: Make sure Character#proceed does not repeat an action
|
32
|
+
next if @did.include?(order.action)
|
33
|
+
@did.push order.action
|
34
|
+
@last_action = order.action
|
35
|
+
executed = attempt(order)
|
36
|
+
return if order.canceled?
|
27
37
|
end
|
28
|
-
@actor.send(:delegate_stack).pop
|
29
38
|
end
|
39
|
+
|
30
40
|
def execute
|
31
41
|
return if @orders.length == 0
|
32
|
-
|
33
|
-
|
34
|
-
result = rule.test(@actor, @orders[0].action.verb, @orders[0].arguments)
|
35
|
-
if result == false
|
36
|
-
return
|
37
|
-
end
|
38
|
-
}
|
39
|
-
end
|
42
|
+
stack_map[@actor] ||= []
|
43
|
+
stack_map[@actor].push self
|
40
44
|
proceed
|
45
|
+
stack_map[@actor].pop
|
46
|
+
stack_map.delete @actor if stack_map[@actor].empty?
|
41
47
|
end
|
48
|
+
|
42
49
|
private
|
43
|
-
|
50
|
+
|
51
|
+
def attempt order
|
44
52
|
executed = false
|
45
53
|
arg_i = 0
|
46
54
|
final_arguments = []
|
@@ -53,7 +61,7 @@ module Gamefic
|
|
53
61
|
else
|
54
62
|
ambiguous = argument
|
55
63
|
end
|
56
|
-
order = Order.new(@actor,
|
64
|
+
order = Order.new(@actor, @actor.playbook.disambiguator, [])
|
57
65
|
final_arguments = [ambiguous]
|
58
66
|
break
|
59
67
|
end
|
@@ -66,7 +74,7 @@ module Gamefic
|
|
66
74
|
break
|
67
75
|
end
|
68
76
|
end
|
69
|
-
if order.action ==
|
77
|
+
if order.action == @actor.playbook.disambiguator or final_arguments.nil?
|
70
78
|
break
|
71
79
|
end
|
72
80
|
if order.action.queries[arg_i].allow_many?
|
@@ -80,6 +88,13 @@ module Gamefic
|
|
80
88
|
arg_i += 1
|
81
89
|
}
|
82
90
|
if !final_arguments.nil?
|
91
|
+
unless @validated or order.action.meta?
|
92
|
+
@actor.playbook.validators.each { |v|
|
93
|
+
v.call order
|
94
|
+
return false if order.canceled?
|
95
|
+
}
|
96
|
+
end
|
97
|
+
@validated = true
|
83
98
|
# The actor is always the first argument to an Action proc
|
84
99
|
final_arguments.unshift @actor
|
85
100
|
order.action.execute(*final_arguments)
|
@@ -87,6 +102,7 @@ module Gamefic
|
|
87
102
|
end
|
88
103
|
executed
|
89
104
|
end
|
105
|
+
|
90
106
|
def validate argument, arg_i, order
|
91
107
|
valid = []
|
92
108
|
argument.each { |m|
|
@@ -99,6 +115,12 @@ module Gamefic
|
|
99
115
|
}
|
100
116
|
valid
|
101
117
|
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def stack_map
|
122
|
+
Delegate.send(:stack_map)
|
123
|
+
end
|
102
124
|
end
|
103
125
|
end
|
104
126
|
end
|
@@ -7,7 +7,7 @@ module Gamefic
|
|
7
7
|
def self.from_tokens(actor, tokens)
|
8
8
|
options = []
|
9
9
|
command = tokens.shift
|
10
|
-
actions = actor.
|
10
|
+
actions = actor.playbook.actions_for(command.to_sym)
|
11
11
|
actions.each { |action|
|
12
12
|
if action.queries.length == tokens.length
|
13
13
|
valid = true
|
@@ -38,9 +38,9 @@ module Gamefic
|
|
38
38
|
if command.to_s == ''
|
39
39
|
return options
|
40
40
|
end
|
41
|
-
matches = Syntax.tokenize(command, actor.
|
41
|
+
matches = Syntax.tokenize(command, actor.playbook.syntaxes)
|
42
42
|
matches.each { |match|
|
43
|
-
actions = actor.
|
43
|
+
actions = actor.playbook.actions_for(match.verb)
|
44
44
|
actions.each { |action|
|
45
45
|
options.concat bind_contexts_in_result(actor, match.arguments, action)
|
46
46
|
}
|
@@ -53,18 +53,18 @@ module Gamefic
|
|
53
53
|
queries = action.queries.clone
|
54
54
|
objects = execute_query(actor, handler.clone, queries, action)
|
55
55
|
num_nil = 0
|
56
|
-
while objects.length == 0 and queries.last.optional?
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end
|
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
61
|
return objects
|
62
62
|
end
|
63
63
|
def execute_query(actor, arguments, queries, action, num_nil = 0)
|
64
64
|
# If the action verb is nil, treat the first argument as a query
|
65
|
-
arguments.shift unless action.verb.nil?
|
66
|
-
prepared =
|
67
|
-
objects =
|
65
|
+
#arguments.shift unless action.verb.nil?
|
66
|
+
prepared = []
|
67
|
+
objects = []
|
68
68
|
valid = true
|
69
69
|
last_remainder = nil
|
70
70
|
queries.clone.each { |context|
|
data/lib/gamefic/engine/base.rb
CHANGED
@@ -29,7 +29,7 @@ module Gamefic
|
|
29
29
|
def run
|
30
30
|
connect
|
31
31
|
@plot.introduce @character
|
32
|
-
turn until @
|
32
|
+
turn until @character.concluded?
|
33
33
|
print @user.flush
|
34
34
|
end
|
35
35
|
|
@@ -44,10 +44,9 @@ module Gamefic
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def receive
|
47
|
-
print @
|
47
|
+
print @character.scene.prompt_for(@character) + ' '
|
48
48
|
input = STDIN.gets
|
49
49
|
@character.queue.push input unless input.nil?
|
50
|
-
puts ''
|
51
50
|
end
|
52
51
|
end
|
53
52
|
|
data/lib/gamefic/entity.rb
CHANGED
@@ -11,58 +11,48 @@ module Gamefic
|
|
11
11
|
extend Serialized::ClassMethods
|
12
12
|
include Grammar::WordAdapter
|
13
13
|
|
14
|
-
attr_reader :session
|
14
|
+
attr_reader :session
|
15
15
|
serialize :name, :parent, :description
|
16
16
|
|
17
|
-
def initialize(
|
18
|
-
if (plot.kind_of?(Plot) == false)
|
19
|
-
raise "First argument must be a Plot"
|
20
|
-
end
|
17
|
+
def initialize(args = {})
|
21
18
|
pre_initialize
|
22
|
-
@plot = plot
|
23
|
-
@plot.send :add_entity, self
|
24
19
|
args.each { |key, value|
|
25
20
|
send "#{key}=", value
|
26
21
|
}
|
27
|
-
@update_procs = Array.new
|
28
22
|
@session = Hash.new
|
29
23
|
yield self if block_given?
|
30
24
|
post_initialize
|
31
25
|
end
|
26
|
+
|
32
27
|
def uid
|
33
28
|
if @uid == nil
|
34
29
|
@uid = self.object_id.to_s
|
35
30
|
end
|
36
31
|
@uid
|
37
32
|
end
|
33
|
+
|
38
34
|
def pre_initialize
|
39
35
|
# raise NotImplementedError, "#{self.class} must implement post_initialize"
|
40
36
|
end
|
37
|
+
|
41
38
|
def post_initialize
|
42
39
|
# raise NotImplementedError, "#{self.class} must implement post_initialize"
|
43
40
|
end
|
41
|
+
|
44
42
|
def tell(message)
|
45
43
|
#TODO: Should this even be here? In all likelihood, only Characters receive tells, right?
|
46
44
|
#TODO: On second thought, it might be interesting to see logs from an npc point of view.
|
47
45
|
end
|
46
|
+
|
48
47
|
def stream(message)
|
49
48
|
# Unlike tell, this method sends raw data without formatting.
|
50
49
|
end
|
51
50
|
|
52
51
|
# Execute the entity's on_update blocks.
|
53
52
|
# This method is typically called by the Engine that manages game execution.
|
53
|
+
# The base method does nothing. Subclasses can override it.
|
54
54
|
#
|
55
55
|
def update
|
56
|
-
@update_procs.each { |p|
|
57
|
-
p.call self
|
58
|
-
}
|
59
|
-
end
|
60
|
-
|
61
|
-
# Add a block to be executed when the game updates a turn.
|
62
|
-
#
|
63
|
-
# @yieldparam [Entity]
|
64
|
-
def on_update(&block)
|
65
|
-
@update_procs.push block
|
66
56
|
end
|
67
57
|
|
68
58
|
# Set the Entity's parent.
|
@@ -75,14 +65,6 @@ module Gamefic
|
|
75
65
|
super
|
76
66
|
end
|
77
67
|
|
78
|
-
# Remove this Entity from its current Plot.
|
79
|
-
#
|
80
|
-
def destroy
|
81
|
-
self.parent = nil
|
82
|
-
# TODO: Need to call this private method here?
|
83
|
-
@plot.send(:rem_entity, self)
|
84
|
-
end
|
85
|
-
|
86
68
|
# Get an extended property.
|
87
69
|
#
|
88
70
|
# @param key [Symbol] The property's name.
|