gamefic 0.0.5 → 0.1.1
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/bin/gamefic +7 -0
- data/lib/gamefic/character.rb +2 -0
- data/lib/gamefic/core_ext/string.rb +2 -2
- data/lib/gamefic/director.rb +36 -3
- data/lib/gamefic/engine.rb +9 -5
- data/lib/gamefic/entity.rb +1 -1
- data/lib/gamefic/import/basics.rb +2 -0
- data/lib/gamefic/import/basics/actions.rb +1 -0
- data/lib/gamefic/import/basics/actions/container.rb +111 -0
- data/lib/gamefic/import/basics/actions/inventory.rb +49 -0
- data/lib/gamefic/import/basics/actions/look.rb +67 -0
- data/lib/gamefic/import/basics/actions/meta.rb +6 -0
- data/lib/gamefic/import/basics/actions/traversal.rb +35 -0
- data/lib/gamefic/import/basics/entities.rb +1 -0
- data/lib/gamefic/import/basics/entities/container.rb +24 -0
- data/lib/gamefic/import/basics/entities/fixture.rb +5 -0
- data/lib/gamefic/import/basics/entities/item.rb +7 -0
- data/lib/gamefic/import/basics/entities/itemized.rb +3 -0
- data/lib/gamefic/import/basics/entities/portable.rb +3 -0
- data/lib/gamefic/import/basics/entities/portal.rb +43 -0
- data/lib/gamefic/import/basics/entities/room.rb +24 -0
- data/lib/gamefic/import/basics/entities/scenery.rb +3 -0
- data/lib/gamefic/import/basics/room_modes.rb +48 -0
- data/lib/gamefic/plot.rb +89 -16
- data/lib/gamefic/shell.rb +317 -0
- data/lib/gamefic/syntax.rb +1 -1
- data/lib/gamefic/user.rb +3 -3
- metadata +23 -18
- data/lib/gamefic/action_ext.rb +0 -7
- data/lib/gamefic/action_ext/container.rb +0 -114
- data/lib/gamefic/action_ext/inventory.rb +0 -53
- data/lib/gamefic/action_ext/look.rb +0 -52
- data/lib/gamefic/action_ext/meta.rb +0 -10
- data/lib/gamefic/action_ext/traversal.rb +0 -39
- data/lib/gamefic/entity_ext.rb +0 -7
- data/lib/gamefic/entity_ext/container.rb +0 -28
- data/lib/gamefic/entity_ext/fixture.rb +0 -9
- data/lib/gamefic/entity_ext/item.rb +0 -11
- data/lib/gamefic/entity_ext/itemized.rb +0 -7
- data/lib/gamefic/entity_ext/portable.rb +0 -33
- data/lib/gamefic/entity_ext/portal.rb +0 -47
- data/lib/gamefic/entity_ext/room.rb +0 -28
- data/lib/gamefic/entity_ext/scenery.rb +0 -7
@@ -0,0 +1,43 @@
|
|
1
|
+
class Portal < Entity
|
2
|
+
attr_accessor :destination
|
3
|
+
#def initialize
|
4
|
+
# super
|
5
|
+
# @destination = nil
|
6
|
+
#end
|
7
|
+
def find_reverse
|
8
|
+
rev = Portal.reverse(self.name)
|
9
|
+
if rev != nil
|
10
|
+
destination.children.that_are(Portal).each { |c|
|
11
|
+
if c.name == rev
|
12
|
+
return c
|
13
|
+
end
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
def self.reverse(direction)
|
18
|
+
case direction.downcase
|
19
|
+
when "north"
|
20
|
+
"south"
|
21
|
+
when "south"
|
22
|
+
"north"
|
23
|
+
when "west"
|
24
|
+
"east"
|
25
|
+
when "east"
|
26
|
+
"west"
|
27
|
+
when "northwest"
|
28
|
+
"southeast"
|
29
|
+
when "southeast"
|
30
|
+
"northwest"
|
31
|
+
when "northeast"
|
32
|
+
"southwest"
|
33
|
+
when "southwest"
|
34
|
+
"northeast"
|
35
|
+
when "up"
|
36
|
+
"down"
|
37
|
+
when "down"
|
38
|
+
"up"
|
39
|
+
else
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import 'basics/entities/portal'
|
2
|
+
|
3
|
+
class Room < Entity
|
4
|
+
def connect(destination, direction, type = Portal, two_way = true)
|
5
|
+
portal = type.new self.plot, :name => direction, :parent => self, :destination => destination
|
6
|
+
if two_way == true
|
7
|
+
reverse = Portal.reverse(direction)
|
8
|
+
if reverse == nil
|
9
|
+
raise "\"#{direction.cap_first}\" does not have an opposite direction"
|
10
|
+
end
|
11
|
+
portal2 = type.new(self.plot, {
|
12
|
+
:name => reverse,
|
13
|
+
:parent => destination,
|
14
|
+
:destination => self
|
15
|
+
})
|
16
|
+
end
|
17
|
+
portal
|
18
|
+
end
|
19
|
+
def tell(message, refresh = false)
|
20
|
+
children.each { |c|
|
21
|
+
c.tell message, refresh
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module RoomModes
|
2
|
+
attr_writer :description_mode
|
3
|
+
def description_seen
|
4
|
+
@description_seen ||= Array.new
|
5
|
+
end
|
6
|
+
def description_seen=(value)
|
7
|
+
if value.kind_of?(Array)
|
8
|
+
@description_seen = value
|
9
|
+
else
|
10
|
+
raise "Character#visited must be an Array"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
def description_mode
|
14
|
+
@description_mode ||= "brief"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Character
|
19
|
+
include RoomModes
|
20
|
+
end
|
21
|
+
|
22
|
+
respond :go, Query.new(:siblings, Portal) do |actor, portal|
|
23
|
+
actor.tell "You go #{portal.name}."
|
24
|
+
actor.parent = portal.destination
|
25
|
+
if actor.description_mode == "superbrief" or (actor.description_mode == "brief" and actor.description_seen.include?(actor.parent))
|
26
|
+
actor.perform "itemize room"
|
27
|
+
else
|
28
|
+
actor.perform "itemize room full"
|
29
|
+
end
|
30
|
+
if actor.description_seen.include?(actor.parent) == false
|
31
|
+
actor.description_seen.push actor.parent
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
respond :brief do |actor|
|
36
|
+
actor.description_mode = "brief"
|
37
|
+
actor.tell "You are now in BRIEF mode. Detailed descriptions of rooms will only be displayed the first time you visit them. Other options are SUPERBRIEF and VERBOSE."
|
38
|
+
end
|
39
|
+
|
40
|
+
respond :verbose do |actor|
|
41
|
+
actor.description_mode = "verbose"
|
42
|
+
actor.tell "You are now in VERBOSE mode. Detailed descriptions will be displayed every time you enter a room. Other options are BRIEF and SUPERBRIEF."
|
43
|
+
end
|
44
|
+
|
45
|
+
respond :superbrief do |actor|
|
46
|
+
actor.description_mode = "superbrief"
|
47
|
+
actor.tell "You are now in VERBOSE mode. Detailed room descriptions will never be displayed unless you LOOK AROUND. Other options are BRIEF and VERBOSE."
|
48
|
+
end
|
data/lib/gamefic/plot.rb
CHANGED
@@ -1,7 +1,25 @@
|
|
1
1
|
module Gamefic
|
2
2
|
|
3
|
+
def self.bind(plot)
|
4
|
+
mod = Module.new do
|
5
|
+
def self.bind(plot)
|
6
|
+
@@plot = plot
|
7
|
+
end
|
8
|
+
def self.get_binding
|
9
|
+
binding
|
10
|
+
end
|
11
|
+
def self.method_missing(name, *args, &block)
|
12
|
+
if @@plot.respond_to?(name)
|
13
|
+
@@plot.send name, *args, &block
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
mod.bind plot
|
18
|
+
mod.get_binding
|
19
|
+
end
|
20
|
+
|
3
21
|
class Plot
|
4
|
-
attr_reader :scenes, :commands, :conclusions, :
|
22
|
+
attr_reader :scenes, :commands, :conclusions, :imported_scripts
|
5
23
|
attr_accessor :story
|
6
24
|
def commandwords
|
7
25
|
words = Array.new
|
@@ -16,7 +34,8 @@ module Gamefic
|
|
16
34
|
@syntaxes = Array.new
|
17
35
|
@conclusions = Hash.new
|
18
36
|
@update_procs = Array.new
|
19
|
-
|
37
|
+
@available_scripts = Hash.new
|
38
|
+
@imported_scripts = Array.new
|
20
39
|
@entities = Array.new
|
21
40
|
post_initialize
|
22
41
|
end
|
@@ -82,30 +101,76 @@ module Gamefic
|
|
82
101
|
@update_procs.each { |p|
|
83
102
|
p.call
|
84
103
|
}
|
85
|
-
#@entities.flatten.each { |e|
|
86
104
|
@entities.each { |e|
|
87
|
-
#recursive_update e
|
88
105
|
e.update
|
89
106
|
}
|
90
107
|
end
|
108
|
+
|
91
109
|
def tell entities, message, refresh = false
|
92
110
|
entities.each { |entity|
|
93
111
|
entity.tell message, refresh
|
94
112
|
}
|
95
113
|
end
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
114
|
+
|
115
|
+
def load script, with_libs = true
|
116
|
+
code = File.read(script)
|
117
|
+
code.untaint
|
118
|
+
@source_directory = File.dirname(script)
|
119
|
+
if with_libs == true
|
120
|
+
$LOAD_PATH.reverse.each { |path|
|
121
|
+
get_scripts path + '/gamefic/import'
|
122
|
+
}
|
123
|
+
end
|
124
|
+
get_scripts @source_directory + '/import'
|
125
|
+
proc {
|
126
|
+
$SAFE = 3
|
127
|
+
eval code, ::Gamefic.bind(self), script, 1
|
128
|
+
}.call
|
129
|
+
end
|
106
130
|
|
107
|
-
|
131
|
+
def import script
|
132
|
+
if script[-2, 2] == '/*'
|
133
|
+
directory = script[0..-3]
|
134
|
+
resolved = directory
|
135
|
+
@available_scripts.each { |f, c|
|
136
|
+
if f.start_with?(resolved)
|
137
|
+
self.import f
|
138
|
+
end
|
139
|
+
}
|
140
|
+
else
|
141
|
+
resolved = script
|
142
|
+
if !@available_scripts.has_key?(resolved)
|
143
|
+
if @available_scripts.has_key?(resolved + '.rb')
|
144
|
+
resolved = resolved + '.rb'
|
145
|
+
end
|
146
|
+
end
|
147
|
+
if @available_scripts.has_key?(resolved)
|
148
|
+
if @available_scripts[resolved] != nil
|
149
|
+
script_object = @available_scripts[resolved]
|
150
|
+
@available_scripts[resolved] = nil
|
151
|
+
proc {
|
152
|
+
$SAFE = 3
|
153
|
+
@imported_scripts.push script_object
|
154
|
+
eval script_object.code, Gamefic.bind(self), script_object.filename, 1
|
155
|
+
}.call
|
156
|
+
end
|
157
|
+
else
|
158
|
+
raise "Unavailable import: #{resolved}"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
108
162
|
|
163
|
+
private
|
164
|
+
def get_scripts(directory)
|
165
|
+
Dir[directory + '/*'].each { |f|
|
166
|
+
if File.directory?(f)
|
167
|
+
get_scripts f
|
168
|
+
else
|
169
|
+
relative = f[(f.index('/import/')+8)..-1]
|
170
|
+
@available_scripts[relative] = Script.new(f)
|
171
|
+
end
|
172
|
+
}
|
173
|
+
end
|
109
174
|
def rem_entity(entity)
|
110
175
|
@entities.delete(entity)
|
111
176
|
end
|
@@ -170,6 +235,14 @@ module Gamefic
|
|
170
235
|
def add_entity(entity)
|
171
236
|
@entities.push entity
|
172
237
|
end
|
173
|
-
|
238
|
+
class Script
|
239
|
+
attr_reader :filename, :code
|
240
|
+
def initialize filename
|
241
|
+
@filename = filename
|
242
|
+
@code = File.read(filename)
|
243
|
+
@code.untaint
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
174
247
|
|
175
248
|
end
|
@@ -0,0 +1,317 @@
|
|
1
|
+
require 'rubygems/package'
|
2
|
+
require 'zlib'
|
3
|
+
require 'tmpdir'
|
4
|
+
require 'getoptlong'
|
5
|
+
|
6
|
+
# Crazy hack to set file mtimes in tar file
|
7
|
+
class Gem::Package::TarHeader
|
8
|
+
@@mtime = Time.now
|
9
|
+
def self.set_mtime(time)
|
10
|
+
@@mtime = time
|
11
|
+
end
|
12
|
+
alias :initialize_orig :initialize
|
13
|
+
def initialize(vals)
|
14
|
+
initialize_orig(vals)
|
15
|
+
@mtime = @@mtime
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module Gamefic
|
20
|
+
|
21
|
+
class Shell
|
22
|
+
attr_accessor :argv
|
23
|
+
def initialize
|
24
|
+
|
25
|
+
end
|
26
|
+
def execute
|
27
|
+
if ARGV.length == 0
|
28
|
+
ARGV.push 'help'
|
29
|
+
end
|
30
|
+
cmd = ARGV.shift
|
31
|
+
case cmd
|
32
|
+
when 'play'
|
33
|
+
play ARGV.shift
|
34
|
+
when 'test'
|
35
|
+
test ARGV.shift
|
36
|
+
when 'init'
|
37
|
+
init ARGV.shift
|
38
|
+
when 'build'
|
39
|
+
build ARGV.shift
|
40
|
+
when 'fetch'
|
41
|
+
fetch ARGV.shift
|
42
|
+
when 'help'
|
43
|
+
help ARGV.shift
|
44
|
+
else
|
45
|
+
play cmd
|
46
|
+
end
|
47
|
+
end
|
48
|
+
private
|
49
|
+
def play file
|
50
|
+
if !File.exist?(file)
|
51
|
+
puts "'#{file}' does not exist."
|
52
|
+
exit 1
|
53
|
+
end
|
54
|
+
if File.directory?(file)
|
55
|
+
puts "'#{file}' is not a Gamefic file."
|
56
|
+
exit 1
|
57
|
+
end
|
58
|
+
Dir.mktmpdir 'gamefic_' do |dir|
|
59
|
+
puts "Loading..."
|
60
|
+
story = Story.new
|
61
|
+
begin
|
62
|
+
decompress file, dir
|
63
|
+
rescue Exception => e
|
64
|
+
puts "'#{file}' does not appear to be a valid Gamefic file."
|
65
|
+
puts "#{e}"
|
66
|
+
exit 1
|
67
|
+
end
|
68
|
+
story.load dir + '/main.rb'
|
69
|
+
engine = Engine.new story
|
70
|
+
puts "\n"
|
71
|
+
engine.run
|
72
|
+
end
|
73
|
+
end
|
74
|
+
def test path
|
75
|
+
puts "Loading..."
|
76
|
+
story = Story.new
|
77
|
+
#begin
|
78
|
+
if File.directory?(path)
|
79
|
+
if !File.file?(path + '/main.rb')
|
80
|
+
raise "#{path}/main.rb does not exist"
|
81
|
+
end
|
82
|
+
story.load path + '/main.rb', true
|
83
|
+
else
|
84
|
+
story.load path
|
85
|
+
end
|
86
|
+
#rescue Exception => e
|
87
|
+
# puts "An error occurred in #{path}:"
|
88
|
+
# puts "#{e.inspect}"
|
89
|
+
# exit 1
|
90
|
+
#end
|
91
|
+
engine = Engine.new story
|
92
|
+
engine.run
|
93
|
+
end
|
94
|
+
def init directory
|
95
|
+
if directory.to_s == ''
|
96
|
+
puts "No directory specified."
|
97
|
+
exit 1
|
98
|
+
elsif File.exist?(directory)
|
99
|
+
if !File.directory?(directory)
|
100
|
+
files = Dir[directory + '/*']
|
101
|
+
if files.length > 0
|
102
|
+
puts "'#{directory}' is not an empty directory."
|
103
|
+
exit 1
|
104
|
+
end
|
105
|
+
else
|
106
|
+
puts "'#{directory}' is not an empty directory."
|
107
|
+
exit 1
|
108
|
+
end
|
109
|
+
else
|
110
|
+
Dir.mkdir(directory)
|
111
|
+
end
|
112
|
+
Dir.mkdir(directory + '/import')
|
113
|
+
main_rb = File.new(directory + '/main.rb', 'w')
|
114
|
+
main_rb.write <<EOS
|
115
|
+
import 'basics'
|
116
|
+
|
117
|
+
room = make Room, :name => 'room'
|
118
|
+
|
119
|
+
introduction do |player|
|
120
|
+
player.parent = room
|
121
|
+
player.perform "look"
|
122
|
+
end
|
123
|
+
EOS
|
124
|
+
main_rb.close
|
125
|
+
fetch directory
|
126
|
+
puts "Game directory '#{directory}' initialized."
|
127
|
+
end
|
128
|
+
def fetch directory
|
129
|
+
if directory.to_s == ''
|
130
|
+
puts "No source directory was specified."
|
131
|
+
exit 1
|
132
|
+
end
|
133
|
+
if !File.directory?(directory)
|
134
|
+
puts "#{directory} is not a directory."
|
135
|
+
exit 1
|
136
|
+
end
|
137
|
+
puts "Loading game data..."
|
138
|
+
story = Story.new
|
139
|
+
begin
|
140
|
+
story.load directory + '/main.rb', true
|
141
|
+
rescue Exception => e
|
142
|
+
puts "'#{directory}' has errors or is not a valid source directory."
|
143
|
+
puts "#{e}"
|
144
|
+
exit 1
|
145
|
+
end
|
146
|
+
puts "Checking for external script references..."
|
147
|
+
fetched = 0
|
148
|
+
story.imported_scripts.each { |script|
|
149
|
+
if !script.filename.start_with?(directory)
|
150
|
+
base = script.filename[(script.filename.rindex('import/') + 7)..-1]
|
151
|
+
puts "Fetching #{base}"
|
152
|
+
FileUtils.mkdir_p directory + '/import/' + File.dirname(base)
|
153
|
+
FileUtils.copy script.filename, directory + '/import/' + base
|
154
|
+
fetched += 1
|
155
|
+
end
|
156
|
+
}
|
157
|
+
if fetched == 0
|
158
|
+
puts "Nothing to fetch."
|
159
|
+
else
|
160
|
+
puts "Done."
|
161
|
+
end
|
162
|
+
end
|
163
|
+
def build directory
|
164
|
+
if directory.to_s == ''
|
165
|
+
puts "No source directory was specified."
|
166
|
+
exit 1
|
167
|
+
end
|
168
|
+
if !File.directory?(directory)
|
169
|
+
puts "#{directory} is not a directory."
|
170
|
+
exit 1
|
171
|
+
end
|
172
|
+
filename = File.basename(directory) + '.gfic'
|
173
|
+
opts = GetoptLong.new(
|
174
|
+
[ '-o', '--output', GetoptLong::REQUIRED_ARGUMENT ]
|
175
|
+
)
|
176
|
+
opts.quiet = true
|
177
|
+
begin
|
178
|
+
opts.each { |opt, arg|
|
179
|
+
case opt
|
180
|
+
when '-o'
|
181
|
+
filename = arg
|
182
|
+
end
|
183
|
+
}
|
184
|
+
rescue Exception => e
|
185
|
+
puts "#{e}"
|
186
|
+
exit 1
|
187
|
+
end
|
188
|
+
if File.exist?(filename)
|
189
|
+
puts "The file #{filename} already exists."
|
190
|
+
exit 1
|
191
|
+
end
|
192
|
+
story = Story.new
|
193
|
+
puts "Loading game data..."
|
194
|
+
begin
|
195
|
+
story.load directory + '/main.rb', true
|
196
|
+
rescue Exception => e
|
197
|
+
puts "'#{directory}' has errors or is not a valid source directory."
|
198
|
+
puts "#{e}"
|
199
|
+
exit 1
|
200
|
+
end
|
201
|
+
puts "Building file..."
|
202
|
+
stream = StringIO.new("")
|
203
|
+
Gem::Package::TarWriter.new(stream) do |tar|
|
204
|
+
Gem::Package::TarHeader.set_mtime Time.now
|
205
|
+
tar.add_file('main.rb', 0600) do |io|
|
206
|
+
File.open(directory + '/main.rb', "rb") { |f| io.write f.read }
|
207
|
+
end
|
208
|
+
if story.imported_scripts.length > 0
|
209
|
+
Gem::Package::TarHeader.set_mtime Time.now
|
210
|
+
tar.mkdir('import', 0700)
|
211
|
+
story.imported_scripts.each { |script|
|
212
|
+
base = script.filename[script.filename.rindex('import/') + 7..-1]
|
213
|
+
Gem::Package::TarHeader.set_mtime Time.now
|
214
|
+
tar.add_file('import/' + base, 0700) do |io|
|
215
|
+
io.write script.code
|
216
|
+
end
|
217
|
+
}
|
218
|
+
end
|
219
|
+
end
|
220
|
+
gz = StringIO.new("")
|
221
|
+
z = Zlib::GzipWriter.new(gz)
|
222
|
+
z.mtime = Time.now
|
223
|
+
z.write stream.string
|
224
|
+
z.close
|
225
|
+
file = File.new(filename, "w")
|
226
|
+
file.write gz.string
|
227
|
+
file.close
|
228
|
+
puts "Gamefic file '#{filename}' complete."
|
229
|
+
end
|
230
|
+
def help command
|
231
|
+
shell_script = File.basename($0)
|
232
|
+
case command
|
233
|
+
when "play"
|
234
|
+
puts <<EOS
|
235
|
+
#{shell_script} play [file]
|
236
|
+
Play a Gamefic file on the command line.
|
237
|
+
EOS
|
238
|
+
when "test"
|
239
|
+
puts <<EOS
|
240
|
+
#{shell_script} test [path]
|
241
|
+
Test a Gamefic source directory or script.
|
242
|
+
EOS
|
243
|
+
when "init"
|
244
|
+
puts <<EOS
|
245
|
+
#{shell_script} init [directory]
|
246
|
+
Initialize a Gamefic source directory. The resulting directory will contain
|
247
|
+
source files ready to build into a Gamefic file.
|
248
|
+
EOS
|
249
|
+
when "fetch"
|
250
|
+
puts <<EOS
|
251
|
+
#{shell_script} fetch [directory]
|
252
|
+
Copy shared scripts to the source directory.
|
253
|
+
If the specified game directory imnports external scripts, such as the ones
|
254
|
+
that are distributed with the Gamefic gem, this command will copy them into
|
255
|
+
the game's import directory. Fetching can be useful if you want to customize
|
256
|
+
common features.
|
257
|
+
EOS
|
258
|
+
when "build"
|
259
|
+
puts <<EOS
|
260
|
+
#{shell_script} build [directory] [-o | --output filename]
|
261
|
+
Build a distributable Gamefic file from the source directory. The default
|
262
|
+
filename is [directory].gfic. You can change the filename with the -o option.
|
263
|
+
EOS
|
264
|
+
when nil, "help"
|
265
|
+
puts <<EOS
|
266
|
+
#{shell_script} play [file] - play a Gamefic file
|
267
|
+
#{shell_script} init [dir] - initialize a Gamefic source directory
|
268
|
+
#{shell_script} test [path] - test a Gamefic source directory or script
|
269
|
+
#{shell_script} fetch [directory] - copy shared scripts into directory
|
270
|
+
#{shell_script} build [directory] - build a Gamefic file
|
271
|
+
#{shell_script} help - display this message
|
272
|
+
#{shell_script} help [command] - display info about command
|
273
|
+
EOS
|
274
|
+
else
|
275
|
+
puts "Unrecognized command '#{command}'"
|
276
|
+
exit 1
|
277
|
+
end
|
278
|
+
end
|
279
|
+
def decompress(tarfile, destination)
|
280
|
+
tar_longlink = '././@LongLink'
|
281
|
+
Gem::Package::TarReader.new( Zlib::GzipReader.open tarfile ) do |tar|
|
282
|
+
dest = nil
|
283
|
+
tar.each do |entry|
|
284
|
+
if entry.full_name == tar_longlink
|
285
|
+
dest = File.join destination, entry.read.strip
|
286
|
+
next
|
287
|
+
end
|
288
|
+
dest ||= File.join destination, entry.full_name
|
289
|
+
if entry.directory?
|
290
|
+
FileUtils.rm_rf dest unless File.directory? dest
|
291
|
+
FileUtils.mkdir_p dest, :mode => entry.header.mode, :verbose => false
|
292
|
+
elsif entry.file?
|
293
|
+
cur_stack = dest.split('/')
|
294
|
+
cur_stack.pop
|
295
|
+
cur_dir = ''
|
296
|
+
while cur_stack.length > 0
|
297
|
+
cur_dir += '/' + cur_stack.shift
|
298
|
+
if !File.exist?(destination + cur_dir)
|
299
|
+
FileUtils.mkdir_p dest, :mode => 0700, :verbose => false
|
300
|
+
end
|
301
|
+
end
|
302
|
+
FileUtils.mkdir_p dest, :mode => entry.header.mode, :verbose => false
|
303
|
+
FileUtils.rm_rf dest unless File.file? dest
|
304
|
+
File.open dest, "wb" do |f|
|
305
|
+
f.print entry.read
|
306
|
+
end
|
307
|
+
FileUtils.chmod entry.header.mode, dest, :verbose => false
|
308
|
+
elsif entry.header.typeflag == '2' #Symlink!
|
309
|
+
File.symlink entry.header.linkname, dest
|
310
|
+
end
|
311
|
+
dest = nil
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
end
|