gamefic 1.3.2 → 1.4.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.
@@ -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