gamefic 1.4.1 → 1.5.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.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.
|