gamefic 1.3.2 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,7 +10,7 @@ module Gamefic
10
10
  def run_test name, actor
11
11
  queue = []
12
12
  actor.plot.stage actor, queue, &test_procs[name]
13
- actor[:test_queue] = queue
13
+ actor.queue.push *queue
14
14
  actor[:test_queue_length] = queue.length
15
15
  actor[:test_queue_scene] = actor.scene
16
16
  end
@@ -0,0 +1,8 @@
1
+ module Gamefic
2
+ module Engine
3
+ autoload :Tty, 'gamefic/engine/tty'
4
+ end
5
+ module User
6
+ autoload :Tty, 'gamefic/user/tty'
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Gamefic
2
+
3
+ module User
4
+ autoload :Base, 'gamefic/user/base'
5
+ autoload :Buffer, 'gamefic/user/buffer'
6
+ end
7
+
8
+ end
@@ -0,0 +1,21 @@
1
+ module Gamefic
2
+
3
+ # The base user provides methods for handling messages received from plots.
4
+ #
5
+ class User::Base
6
+ def send message
7
+ buffer.send message
8
+ end
9
+
10
+ def flush
11
+ buffer.flush
12
+ end
13
+
14
+ private
15
+
16
+ def buffer
17
+ @buffer ||= User::Buffer.new
18
+ end
19
+ end
20
+
21
+ end
@@ -0,0 +1,25 @@
1
+ module Gamefic
2
+
3
+ # A simple buffer class for collecting and returning data received from
4
+ # plots.
5
+ class User::Buffer
6
+ def initialize
7
+ @data = ''
8
+ end
9
+
10
+ # Append a message to the buffer.
11
+ def send message
12
+ @data += message
13
+ end
14
+
15
+ # Get the current data and clear the buffer.
16
+ #
17
+ # @return [String]
18
+ def flush
19
+ tmp = @data
20
+ @data = ''
21
+ tmp
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,55 @@
1
+ require 'gamefic/engine'
2
+ require 'json'
3
+ require 'gamefic/html_to_ansi'
4
+
5
+ module Gamefic
6
+
7
+ # Extend User::Base to convert HTML into ANSI text.
8
+ #
9
+ class User::Tty < User::Base
10
+ include HtmlToAnsi
11
+
12
+ def save filename, snapshot
13
+ data = snapshot.merge(:metadata => @character.plot.metadata)
14
+ json = JSON.generate data
15
+ if json.nil?
16
+ @character.tell "Nothing to save."
17
+ end
18
+ if filename.nil?
19
+ stream.select "Enter the filename to save:"
20
+ filename = stream.queue.pop
21
+ end
22
+ if filename != ''
23
+ File.open(filename, 'w') do |f|
24
+ f.write json
25
+ end
26
+ @character.tell "Game saved."
27
+ end
28
+ end
29
+
30
+ def restore filename
31
+ if filename.nil?
32
+ stream.select "Enter the filename to restore:"
33
+ filename = stream.queue.pop
34
+ end
35
+ if filename != ''
36
+ if File.exists?(filename)
37
+ data = JSON.parse File.read(filename), symbolize_names: true
38
+ if (data[:metadata] != @character.plot.metadata)
39
+ @character.tell "The save file is not compatible with this version of the game."
40
+ else
41
+ return data
42
+ end
43
+ else
44
+ @character.tell "File \"#{filename}\" not found."
45
+ end
46
+ end
47
+ nil
48
+ end
49
+
50
+ def flush
51
+ html_to_ansi(super)
52
+ end
53
+ end
54
+
55
+ end
@@ -1,3 +1,3 @@
1
1
  module Gamefic
2
- VERSION = '1.3.2'
2
+ VERSION = '1.4.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gamefic
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.2
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fred Snyder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-02 00:00:00.000000000 Z
11
+ date: 2017-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -146,7 +146,7 @@ files:
146
146
  - lib/gamefic/director/order.rb
147
147
  - lib/gamefic/director/parser.rb
148
148
  - lib/gamefic/engine.rb
149
- - lib/gamefic/engine/cgi.rb
149
+ - lib/gamefic/engine/base.rb
150
150
  - lib/gamefic/engine/tty.rb
151
151
  - lib/gamefic/entity.rb
152
152
  - lib/gamefic/grammar.rb
@@ -160,6 +160,7 @@ files:
160
160
  - lib/gamefic/grammar/verbs.rb
161
161
  - lib/gamefic/grammar/word_adapter.rb
162
162
  - lib/gamefic/html.rb
163
+ - lib/gamefic/html_to_ansi.rb
163
164
  - lib/gamefic/keywords.rb
164
165
  - lib/gamefic/node.rb
165
166
  - lib/gamefic/plot.rb
@@ -190,11 +191,14 @@ files:
190
191
  - lib/gamefic/scene/conclusion.rb
191
192
  - lib/gamefic/scene/custom.rb
192
193
  - lib/gamefic/scene/multiple_choice.rb
193
- - lib/gamefic/scene/multiple_choice/input.rb
194
- - lib/gamefic/scene/passive.rb
194
+ - lib/gamefic/scene/multiple_scene.rb
195
195
  - lib/gamefic/scene/pause.rb
196
- - lib/gamefic/scene/question.rb
197
196
  - lib/gamefic/scene/yes_or_no.rb
197
+ - lib/gamefic/scene_data.rb
198
+ - lib/gamefic/scene_data/base.rb
199
+ - lib/gamefic/scene_data/multiple_choice.rb
200
+ - lib/gamefic/scene_data/multiple_scene.rb
201
+ - lib/gamefic/scene_data/yes_or_no.rb
198
202
  - lib/gamefic/script.rb
199
203
  - lib/gamefic/script/base.rb
200
204
  - lib/gamefic/script/file.rb
@@ -209,6 +213,11 @@ files:
209
213
  - lib/gamefic/subplot.rb
210
214
  - lib/gamefic/syntax.rb
211
215
  - lib/gamefic/tester.rb
216
+ - lib/gamefic/tty.rb
217
+ - lib/gamefic/user.rb
218
+ - lib/gamefic/user/base.rb
219
+ - lib/gamefic/user/buffer.rb
220
+ - lib/gamefic/user/tty.rb
212
221
  - lib/gamefic/version.rb
213
222
  homepage: http://gamefic.com
214
223
  licenses:
@@ -1,221 +0,0 @@
1
- require 'rubygems'
2
- require 'json'
3
-
4
- module Gamefic
5
-
6
- class Entity
7
- attr_reader :cgi_key
8
- @@cgi_key_index = 0
9
- alias_method :orig_post_initialize, :post_initialize
10
- def post_initialize
11
- orig_post_initialize
12
- @cgi_key = "entity_#{@@cgi_key_index}"
13
- @@cgi_key_index += 1
14
- end
15
- end
16
-
17
- module Cgi
18
-
19
- class Key
20
- def initialize(key_value)
21
- @value = key_value
22
- end
23
- def value
24
- @value
25
- end
26
- end
27
-
28
- class Engine < Gamefic::Engine
29
- attr_reader :user
30
- def initialize(plot, args = {})
31
- super(plot)
32
- @session_file = args[:session_file] || 'save.dat'
33
- @message_format = args[:message_format] || :html
34
- @response_format = args[:response_format] || :json
35
- @new_game = args[:new_game] || false
36
- @entity_keys = Hash.new
37
- @introducing = true
38
- end
39
- def post_initialize
40
- @user = Cgi::User.new @plot
41
- end
42
- def begin_session
43
- # Initialize keys for all entities
44
- @plot.entities.each { |e|
45
- @entity_keys[e.cgi_key] = e
46
- }
47
- @entity_keys['yourself'] = @user.character
48
- if !@new_game and @session_file != nil
49
- if File.exist?(@session_file)
50
- load @session_file
51
- @introducing = false
52
- end
53
- end
54
- end
55
- def run
56
- if @introducing == true
57
- @plot.introduce @user.character
58
- else
59
- @plot.instance_variable_get(:@players).push @user.character
60
- tick
61
- end
62
- response = Hash.new
63
- response[:output] = @user.stream.flush
64
- response[:prompt] = @user.character.state.prompt
65
- response[:state] = @user.character.state.class.to_s.split('::').last
66
- return JSON.generate(response)
67
- end
68
- def end_session
69
- save @session_file
70
- end
71
- private
72
- def load(filename)
73
- x = File.open(filename, "r")
74
- ser = x.read
75
- x.close
76
- data = Marshal.restore(ser)
77
- data.each { |k, h|
78
- if k == 'yourself'
79
- entity = @entity_keys['yourself']
80
- else
81
- entity = @entity_keys[k]
82
- end
83
- h.each { |s, v|
84
- if s == :session
85
- entity.instance_variable_set(:@session, v)
86
- elsif s == :state
87
- entity.state = v
88
- elsif s == :options
89
- v.each { |opt|
90
- entity.is opt
91
- }
92
- else
93
- writer = "#{s.to_s[1..-1]}="
94
- writer.untaint
95
- if entity.respond_to?(writer)
96
- if v.kind_of?(Key)
97
- entity.send(writer, @entity_keys[v.value])
98
- elsif v.kind_of?(CharacterState::Base)
99
- v.instance_variable_set(:@character, entity)
100
- entity.instance_variable_set(s, v)
101
- elsif v.kind_of?(Array)
102
- entity.send(writer, decode_array(v))
103
- else
104
- entity.send(writer, v)
105
- end
106
- end
107
- end
108
- }
109
- }
110
- @restored = true
111
- end
112
- def save(filename)
113
- data = Hash.new
114
- @plot.entities.each { |e|
115
- data[e.cgi_key] = entity_hash(e)
116
- }
117
- f = File.new(filename, "w")
118
- f.write Marshal.dump data
119
- f.close
120
- end
121
- def entity_hash(e)
122
- hash = Hash.new
123
- e.instance_variables.each { |v|
124
- next if v == :@state or v == :@option_array or v == :@update_procs
125
- writer = "#{v.to_s[1..-1]}="
126
- if e.respond_to?(writer)
127
- value = e.instance_variable_get(v)
128
- if value.kind_of?(String) or value.kind_of?(Numeric) or value.kind_of?(TrueClass) or value.kind_of?(FalseClass) or value.kind_of?(Entity) or value.kind_of?(Character) or value == nil or value.kind_of?(Array)
129
- if value.kind_of?(Entity)
130
- if value == @user.character
131
- hash[v] = Key.new('yourself')
132
- else
133
- hash[v] = Key.new(value.cgi_key)
134
- end
135
- elsif value.kind_of?(CharacterState::Base)
136
- value.instance_variable_set(:@character, nil)
137
- hash[v] = value
138
- elsif value.kind_of?(Array)
139
- hash[v] = encode_array(value)
140
- else
141
- hash[v] = value
142
- end
143
- end
144
- end
145
- }
146
- if e.respond_to?("state")
147
- hash[:state] = e.state_name
148
- end
149
- if e.respond_to?("option_array")
150
- hash[:options] = e.option_array
151
- end
152
- hash[:session] = Hash.new
153
- e.session.each { |k, v|
154
- if v.kind_of?(Entity)
155
- hash[:session][k] = Key.new(v.cgi_key)
156
- elsif v.kind_of?(Array)
157
- hash[:session][k] = encode_array(v)
158
- else
159
- hash[:session][k] = v
160
- end
161
- }
162
- hash
163
- end
164
- def encode_array(array)
165
- result = Array.new
166
- array.each { |item|
167
- if item.kind_of?(Entity)
168
- result.push Key.new(item.cgi_key)
169
- else
170
- result.push item
171
- end
172
- }
173
- result
174
- end
175
- def decode_array(array)
176
- result = Array.new
177
- array.each { |item|
178
- if item.kind_of?(Key)
179
- result.push @entity_keys[item.value]
180
- else
181
- result.push item
182
- end
183
- }
184
- result
185
- end
186
- end
187
-
188
- class User < Gamefic::User
189
- def post_initialize
190
- @stream = Cgi::UserStream.new
191
- @state = UserState.new self
192
- #@character = @plot.make Character, :name => 'pWlayer'
193
- end
194
- end
195
-
196
- class UserStream < Gamefic::UserStream
197
- def initialize
198
- super
199
- @output = ''
200
- end
201
- def flush
202
- buffer = "#{@output}"
203
- @output.clear
204
- buffer
205
- end
206
- def send(data)
207
- #if data.start_with?(Ansi::NEL)
208
- # data = "<p>#{data[Ansi::NEL.length..-1].rstrip}</p>"
209
- #end
210
- @output = "#{@output}#{data}"
211
- end
212
- def select(prompt)
213
- # TODO: non-blocking read
214
- line = STDIN.gets
215
- @queue.push line
216
- end
217
- end
218
-
219
- end
220
-
221
- end
@@ -1,11 +0,0 @@
1
- module Gamefic
2
- class Gamefic::Scene::MultipleChoice::Input
3
- attr_reader :raw, :number, :index, :choice
4
- def initialize raw, index, choice
5
- @raw = raw
6
- @index = index
7
- @number = index + 1
8
- @choice = choice
9
- end
10
- end
11
- end
@@ -1,17 +0,0 @@
1
- module Gamefic
2
-
3
- # Passive Scenes immediately cue another scene after they're finished. If no
4
- # scene has been cued or prepared, it defaults to the :active scene.
5
- #
6
- class Scene::Passive < Scene::Custom
7
- def initialize &block
8
- @start = block
9
- end
10
- def start actor
11
- this_scene = actor.scene
12
- super
13
- actor.cue :active if (actor.scene == this_scene and actor.next_scene.nil?)
14
- end
15
- end
16
-
17
- end