fusionpacker 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.
@@ -0,0 +1,378 @@
1
+ =begin
2
+ Copyright (c) 2013 Howard Jeng
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
5
+ software and associated documentation files (the "Software"), to deal in the Software
6
+ without restriction, including without limitation the rights to use, copy, modify, merge,
7
+ publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
8
+ to whom the Software is furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all copies or
11
+ substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14
+ INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
15
+ PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
16
+ FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
17
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18
+ DEALINGS IN THE SOFTWARE.
19
+ =end
20
+
21
+ require 'RGSS/psych_mods'
22
+ require 'fileutils'
23
+ require 'zlib'
24
+ require 'pp'
25
+ require 'formatador'
26
+ module RGSS
27
+ def self.change_extension(file, new_ext)
28
+ return File.basename(file, '.*') + new_ext
29
+ end
30
+
31
+ def self.sanitize_filename(filename)
32
+ return filename.gsub(/[^0-9A-Za-z]+/, '_')
33
+ end
34
+
35
+ def self.files_with_extension(directory, extension)
36
+ return Dir.entries(directory).select { |file| File.extname(file) == extension }
37
+ end
38
+
39
+ def self.inflate(str)
40
+ text = Zlib::Inflate.inflate(str)
41
+ return text.force_encoding("UTF-8")
42
+ end
43
+
44
+ def self.deflate(str)
45
+ return Zlib::Deflate.deflate(str, Zlib::BEST_COMPRESSION)
46
+ end
47
+
48
+ def self.dump_data_file(file, data, time, options)
49
+ File.open(file, "wb") do |f|
50
+ Marshal.dump(data, f)
51
+ end
52
+ File.utime(time, time, file)
53
+ end
54
+
55
+ def self.dump_yaml_file(file, data, time, options)
56
+ File.open(file, "wb") do |f|
57
+ Psych::dump(data, f, options)
58
+ end
59
+ File.utime(time, time, file)
60
+ end
61
+
62
+ def self.dump_save(file, data, time, options)
63
+ File.open(file, "wb") do |f|
64
+ data.each do |chunk|
65
+ Marshal.dump(chunk, f)
66
+ end
67
+ end
68
+ File.utime(time, time, file)
69
+ end
70
+
71
+ def self.dump_raw_file(file, data, time, options)
72
+ File.open(file, "wb") do |f|
73
+ f.write(data)
74
+ end
75
+ File.utime(time, time, file)
76
+ end
77
+
78
+ def self.dump(dumper, file, data, time, options)
79
+ self.method(dumper).call(file, data, time, options)
80
+ rescue
81
+ warn "Exception dumping #{file}"
82
+ raise
83
+ end
84
+
85
+ def self.load_data_file(file)
86
+ File.open(file, "rb") do |f|
87
+ return Marshal.load(f)
88
+ end
89
+ end
90
+
91
+ def self.load_yaml_file(file)
92
+ formatador = Formatador.new
93
+ obj = nil
94
+ File.open(file, "rb") do |f|
95
+ obj = Psych::load(f)
96
+ end
97
+ max = 0
98
+ return obj unless obj.kind_of?(Array)
99
+ seen = {}
100
+ idx =
101
+ obj.each do |elem|
102
+ next if elem.nil?
103
+ if elem.instance_variable_defined?("@id")
104
+ id = elem.instance_variable_get("@id")
105
+ else
106
+ id = nil
107
+ elem.instance_variable_set("@id", nil)
108
+ end
109
+ next if id.nil?
110
+
111
+ if seen.has_key?(id)
112
+ formatador.display_line("[red]#{file}: Duplicate ID #{id}[/]")
113
+ formatador.indent {
114
+ formatador.indent {
115
+ elem.pretty_inspect.split(/\n/).each do |line|
116
+ formatador.display_line("[red]#{line}[/]")
117
+ end
118
+ }
119
+ formatador.display_line
120
+ formatador.display_line("[red]Last seen at:\n[/]")
121
+ formatador.indent {
122
+ elem.pretty_inspect.split(/\n/).each do |line|
123
+ formatador.display_line("[red]#{line}[/]")
124
+ end
125
+ }
126
+ }
127
+ exit
128
+ end
129
+ seen[id] = elem
130
+ max = ((id + 1) unless id < max)
131
+ end
132
+ obj.each do |elem|
133
+ next if elem.nil?
134
+ id = elem.instance_variable_get("@id")
135
+ if id.nil?
136
+ elem.instance_variable_set("@id", max)
137
+ max += 1
138
+ end
139
+ end
140
+ return obj
141
+ end
142
+
143
+ def self.load_raw_file(file)
144
+ File.open(file, "rb") do |f|
145
+ return f.read
146
+ end
147
+ end
148
+
149
+ def self.load_save(file)
150
+ File.open(file, "rb") do |f|
151
+ data = []
152
+ while not f.eof?
153
+ o = Marshal.load(f)
154
+ data.push(o)
155
+ end
156
+ return data
157
+ end
158
+ end
159
+
160
+ def self.load(loader, file)
161
+ return self.method(loader).call(file)
162
+ rescue
163
+ warn "Exception loading #{file}"
164
+ raise
165
+ end
166
+
167
+ def self.scripts_to_text(dirs, src, dest, options)
168
+ formatador = Formatador.new
169
+ src_file = File.join(dirs[:data], src)
170
+ dest_file = File.join(dirs[:yaml], dest)
171
+ raise "Missing #{src}" unless File.exist?(src_file)
172
+ script_entries = load(:load_data_file, src_file)
173
+ check_time = !options[:force] && File.exist?(dest_file)
174
+ oldest_time = File.mtime(dest_file) if check_time
175
+
176
+ file_map, script_index, script_code = Hash.new(-1), [], {}
177
+
178
+ idx = 0
179
+ script_entries.each do |script|
180
+ idx += 1
181
+ magic_number, script_name, code = idx, script[1], inflate(script[2])
182
+ script_name.force_encoding("UTF-8")
183
+
184
+ if code.length > 0
185
+ filename = script_name.empty? ? 'blank' : sanitize_filename(script_name)
186
+ key = filename.upcase
187
+ value = (file_map[key] += 1)
188
+ actual_filename = filename + (value == 0 ? "" : ".#{value}") + RUBY_EXT
189
+ script_index.push([magic_number, script_name, actual_filename])
190
+ full_filename = File.join(dirs[:script], actual_filename)
191
+ script_code[full_filename] = code
192
+ check_time = false unless File.exist?(full_filename)
193
+ oldest_time = [File.mtime(full_filename), oldest_time].min if check_time
194
+ else
195
+ script_index.push([magic_number, script_name, nil])
196
+ end
197
+ end
198
+
199
+ src_time = File.mtime(src_file)
200
+ if check_time && (src_time - 1) < oldest_time
201
+ formatador.display_line("[yellow]Skipping scripts to text[/]") if $VERBOSE
202
+ else
203
+ formatador.display_line("[green]Converting scripts to text[/]") if $VERBOSE
204
+ dump(:dump_yaml_file, dest_file, script_index, src_time, options)
205
+ script_code.each { |file, code| dump(:dump_raw_file, file, code, src_time, options) }
206
+ end
207
+ end
208
+
209
+ def self.scripts_to_binary(dirs, src, dest, options)
210
+ formatador = Formatador.new
211
+ src_file = File.join(dirs[:yaml], src)
212
+ dest_file = File.join(dirs[:data], dest)
213
+ raise "Missing #{src}" unless File.exist?(src_file)
214
+ check_time = !options[:force] && File.exist?(dest_file)
215
+ newest_time = File.mtime(src_file) if check_time
216
+
217
+ index = load(:load_yaml_file, src_file)
218
+ script_entries = []
219
+ index.each do |entry|
220
+ magic_number, script_name, filename = entry
221
+ code = ''
222
+ if filename
223
+ full_filename = File.join(dirs[:script], filename)
224
+ raise "Missing script file #{filename}" unless File.exist?(full_filename)
225
+ newest_time = [File.mtime(full_filename), newest_time].max if check_time
226
+ code = load(:load_raw_file, full_filename)
227
+ end
228
+ script_entries.push([magic_number, script_name, deflate(code)])
229
+ end
230
+ if check_time && (newest_time - 1) < File.mtime(dest_file)
231
+ formatador.display_line("[yellow]Skipping scripts to binary[/]") if $VERBOSE
232
+ else
233
+ formatador.display_line("[green]Converting scripts to binary[/]") if $VERBOSE
234
+ dump(:dump_data_file, dest_file, script_entries, newest_time, options)
235
+ end
236
+ end
237
+
238
+ def self.process_file(file, src_file, dest_file, dest_ext, loader, dumper, options)
239
+ formatador = Formatador.new
240
+ fbase = File.basename(file, File.extname(file))
241
+ src_time = File.mtime(src_file)
242
+ begin
243
+ if !options[:force] && File.exist?(dest_file) && (src_time - 1) < File.mtime(dest_file)
244
+ formatador.display_line("[yellow]Skipping #{file}[/]") if $VERBOSE
245
+ else
246
+ formatador.display_line("[green]Converting #{file} to #{dest_ext}[/]") if $VERBOSE
247
+ data = load(loader, src_file)
248
+ dump(dumper, dest_file, data, src_time, options)
249
+ end
250
+ rescue ArgumentError
251
+ formatador.display_line("[_yellow_] Could not convert #{file} due to ArgumentError")
252
+ end
253
+ end
254
+
255
+ def self.convert(src, dest, options)
256
+ f = Formatador.new
257
+ f.display_line("[green]#{options[:files].join('|')}")
258
+ files = options[:files]
259
+ files ||= Dir.entries(src[:directory])
260
+ files = files.select { |file| File.extname(file) == src[:ext] }
261
+ files -= src[:exclude]
262
+ files.each do |file|
263
+ src_file = File.join(src[:directory], file)
264
+ dest_file = File.join(dest[:directory], change_extension(file, dest[:ext]))
265
+ process_file(file, src_file, dest_file, dest[:ext], src[:load_file],
266
+ dest[:dump_file], options)
267
+ end
268
+ end
269
+
270
+ def self.convert_saves(base, src, dest, options)
271
+ save_files = files_with_extension(base, src[:ext])
272
+ save_files.each do |file|
273
+ src_file = File.join(base, file)
274
+ dest_file = File.join(base, change_extension(file, dest[:ext]))
275
+
276
+ process_file(file, src_file, dest_file, dest[:ext], src[:load_save],
277
+ dest[:dump_save], options)
278
+ end
279
+ end
280
+
281
+ # [version] one of :ace, :vx, :xp
282
+ # [direction] one of :data_bin_to_text, :data_text_to_bin, :save_bin_to_text,
283
+ # :save_text_to_bin, :scripts_bin_to_text, :scripts_text_to_bin,
284
+ # :all_text_to_bin, :all_bin_to_text
285
+ # [directory] directory that project file is in
286
+ # [options] :force - ignores file dates when converting (default false)
287
+ # :round_trip - create yaml data that matches original marshalled data skips
288
+ # data cleanup operations (default false)
289
+ # :line_width - line width form YAML files, -1 for no line width limit
290
+ # (default 130)
291
+ # :table_width - maximum number of entries per row for table data, -1 for no
292
+ # table row limit (default 20)
293
+ def self.serialize(version, direction, directory, options = {})
294
+ raise "#{directory} not found" unless File.exist?(directory)
295
+
296
+ setup_classes(version, options)
297
+ options = options.clone()
298
+ options[:sort] = true if [:vx, :xp].include?(version)
299
+ options[:flow_classes] = FLOW_CLASSES
300
+ options[:line_width] ||= 130
301
+
302
+ table_width = options[:table_width]
303
+ RGSS::reset_const(Table, :MAX_ROW_LENGTH, table_width ? table_width : 20)
304
+
305
+ base = File.realpath(directory)
306
+
307
+ dirs = {
308
+ :base => base,
309
+ :data => get_data_directory(base),
310
+ :yaml => get_yaml_directory(base),
311
+ :script => get_script_directory(base)
312
+ }
313
+
314
+ dirs.values.each do |d|
315
+ FileUtils.mkdir(d) unless File.exist?(d)
316
+ end
317
+
318
+ exts = {
319
+ :ace => ACE_DATA_EXT,
320
+ :vx => VX_DATA_EXT,
321
+ :xp => XP_DATA_EXT
322
+ }
323
+
324
+ yaml_scripts = SCRIPTS_BASE + YAML_EXT
325
+ yaml = {
326
+ :directory => dirs[:yaml],
327
+ :exclude => [yaml_scripts],
328
+ :ext => YAML_EXT,
329
+ :load_file => :load_yaml_file,
330
+ :dump_file => :dump_yaml_file,
331
+ :load_save => :load_yaml_file,
332
+ :dump_save => :dump_yaml_file
333
+ }
334
+
335
+ scripts = SCRIPTS_BASE + exts[version]
336
+ data = {
337
+ :directory => dirs[:data],
338
+ :exclude => [scripts],
339
+ :ext => exts[version],
340
+ :load_file => :load_data_file,
341
+ :dump_file => :dump_data_file,
342
+ :load_save => :load_save,
343
+ :dump_save => :dump_save
344
+ }
345
+
346
+ convert_saves = options[:database][:saves]
347
+ convert_scripts = options[:database][:scripts]
348
+
349
+ case direction
350
+ # below were not used in rv packer
351
+ when :data_bin_to_text
352
+ convert(data, yaml, options)
353
+ scripts_to_text(dirs, scripts, yaml_scripts, options) if convert_scripts
354
+ when :data_text_to_bin
355
+ convert(yaml, data, options)
356
+ scripts_to_binary(dirs, yaml_scripts, scripts, options) if convert_scripts
357
+ when :save_bin_to_text
358
+ convert_saves(base, data, yaml, options) if convert_saves
359
+ when :save_text_to_bin
360
+ convert_saves(base, yaml, data, options) if convert_saves
361
+ when :scripts_bin_to_text
362
+ scripts_to_text(dirs, scripts, yaml_scripts, options) if convert_scripts
363
+ when :scripts_text_to_bin
364
+ scripts_to_binary(dirs, yaml_scripts, scripts, options) if convert_scripts
365
+ # below are only options used by fusionpacker
366
+ when :all_bin_to_text
367
+ convert(data, yaml, options)
368
+ scripts_to_text(dirs, scripts, yaml_scripts, options) if convert_scripts
369
+ convert_saves(base, data, yaml, options) if convert_saves
370
+ when :all_text_to_bin
371
+ convert(yaml, data, options)
372
+ scripts_to_binary(dirs, yaml_scripts, scripts, options) if convert_scripts
373
+ convert_saves(base, yaml, data, options) if convert_saves
374
+ else
375
+ raise "Unrecognized direction :#{direction}"
376
+ end
377
+ end
378
+ end
data/lib/RGSS.rb ADDED
@@ -0,0 +1,336 @@
1
+ =begin
2
+ Copyright (c) 2013 Howard Jeng
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
5
+ software and associated documentation files (the "Software"), to deal in the Software
6
+ without restriction, including without limitation the rights to use, copy, modify, merge,
7
+ publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
8
+ to whom the Software is furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all copies or
11
+ substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14
+ INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
15
+ PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
16
+ FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
17
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18
+ DEALINGS IN THE SOFTWARE.
19
+ =end
20
+
21
+ require 'scanf'
22
+
23
+ class Table
24
+ def initialize(bytes)
25
+ @dim, @x, @y, @z, items, *@data = bytes.unpack('L5 S*')
26
+ raise "Size mismatch loading Table from data" unless items == @data.length
27
+ raise "Size mismatch loading Table from data" unless @x * @y * @z == items
28
+ end
29
+
30
+ MAX_ROW_LENGTH = 20
31
+
32
+ def encode_with(coder)
33
+ coder.style = Psych::Nodes::Mapping::BLOCK
34
+
35
+ coder['dim'] = @dim
36
+ coder['x'] = @x
37
+ coder['y'] = @y
38
+ coder['z'] = @z
39
+
40
+ if @x * @y * @z > 0
41
+ stride = @x < 2 ? (@y < 2 ? @z : @y) : @x
42
+ rows = @data.each_slice(stride).to_a
43
+ if MAX_ROW_LENGTH != -1 && stride > MAX_ROW_LENGTH
44
+ block_length = (stride + MAX_ROW_LENGTH - 1) / MAX_ROW_LENGTH
45
+ row_length = (stride + block_length - 1) / block_length
46
+ rows = rows.collect{|x| x.each_slice(row_length).to_a}.flatten(1)
47
+ end
48
+ rows = rows.collect{|x| x.collect{|y| "%04x" % y}.join(" ")}
49
+ coder['data'] = rows
50
+ else
51
+ coder['data'] = []
52
+ end
53
+ end
54
+
55
+ def init_with(coder)
56
+ @dim = coder['dim']
57
+ @x = coder['x']
58
+ @y = coder['y']
59
+ @z = coder['z']
60
+ @data = coder['data'].collect{|x| x.split(" ").collect{|y| y.hex}}.flatten
61
+ items = @x * @y * @z
62
+ raise "Size mismatch loading Table from YAML" unless items == @data.length
63
+ end
64
+
65
+ def _dump(*ignored)
66
+ return [@dim, @x, @y, @z, @x * @y * @z, *@data].pack('L5 S*')
67
+ end
68
+
69
+ def self._load(bytes)
70
+ Table.new(bytes)
71
+ end
72
+ end
73
+
74
+ class Color
75
+ def initialize(bytes, g = nil, b = nil)
76
+ # massive hack to support triple param color
77
+ if g && b
78
+ @r = bytes
79
+ @g = g
80
+ @b = b
81
+ @a = 255
82
+ else
83
+ @r, @g, @b, @a = *bytes.unpack('D4')
84
+ end
85
+ end
86
+
87
+ def _dump(*ignored)
88
+ return [@r, @g, @b, @a].pack('D4')
89
+ end
90
+
91
+ def self._load(bytes)
92
+ Color.new(bytes)
93
+ end
94
+ end
95
+
96
+ class Tone
97
+ def initialize(bytes)
98
+ @r, @g, @b, @a = *bytes.unpack('D4')
99
+ end
100
+
101
+ def _dump(*ignored)
102
+ return [@r, @g, @b, @a].pack('D4')
103
+ end
104
+
105
+ def self._load(bytes)
106
+ Tone.new(bytes)
107
+ end
108
+ end
109
+
110
+ class Rect
111
+ def initialize(bytes)
112
+ @x, @y, @width, @height = *bytes.unpack('i4')
113
+ end
114
+
115
+ def _dump(*ignored)
116
+ return [@x, @y, @width, @height].pack('i4')
117
+ end
118
+
119
+ def self._load(bytes)
120
+ Rect.new(bytes)
121
+ end
122
+ end
123
+
124
+ module RGSS
125
+ def self.remove_defined_method(scope, name)
126
+ scope.send(:remove_method, name) if scope.instance_methods(false).include?(name)
127
+ end
128
+
129
+ def self.reset_method(scope, name, method)
130
+ remove_defined_method(scope, name)
131
+ scope.send(:define_method, name, method)
132
+ end
133
+
134
+ def self.reset_const(scope, sym, value)
135
+ scope.send(:remove_const, sym) if scope.const_defined?(sym)
136
+ scope.send(:const_set, sym, value)
137
+ end
138
+
139
+ def self.array_to_hash(arr, &block)
140
+ h = {}
141
+ arr.each_with_index do |val, index|
142
+ r = block_given? ? block.call(val) : val
143
+ h[index] = r unless r.nil?
144
+ end
145
+ if arr.length > 0
146
+ last = arr.length - 1
147
+ h[last] = nil unless h.has_key?(last)
148
+ end
149
+ return h
150
+ end
151
+
152
+ def self.hash_to_array(hash)
153
+ arr = []
154
+ hash.each do |k, v|
155
+ arr[k] = v
156
+ end
157
+ return arr
158
+ end
159
+
160
+ require 'RGSS/BasicCoder'
161
+ require 'RPG'
162
+
163
+ # creates an empty class in a potentially nested scope
164
+ def self.process(root, name, *args)
165
+ if args.length > 0
166
+ process(root.const_get(name), *args)
167
+ else
168
+ root.const_set(name, Class.new) unless root.const_defined?(name, false)
169
+ end
170
+ end
171
+
172
+ # require 'infinitefusion/fusion'
173
+
174
+ # Object.const_set(:PokemonDataBox, PokemonDataBox) unless Object.const_defined?(name, false)
175
+ # other classes that don't need definitions
176
+ [ # RGSS data structures
177
+ [:RPG, :Actor], [:RPG, :Animation], [:RPG, :Animation, :Frame],
178
+ [:RPG, :Animation, :Timing], [:RPG, :Area], [:RPG, :Armor], [:RPG, :AudioFile],
179
+ [:RPG, :BaseItem], [:RPG, :BaseItem, :Feature], [:RPG, :BGM], [:RPG, :BGS],
180
+ [:RPG, :Class], [:RPG, :Class, :Learning], [:RPG, :CommonEvent], [:RPG, :Enemy],
181
+ [:RPG, :Enemy, :Action], [:RPG, :Enemy, :DropItem], [:RPG, :EquipItem],
182
+ [:RPG, :Event], [:RPG, :Event, :Page], [:RPG, :Event, :Page, :Condition],
183
+ [:RPG, :Event, :Page, :Graphic], [:RPG, :Item], [:RPG, :Map],
184
+ [:RPG, :Map, :Encounter], [:RPG, :MapInfo], [:RPG, :ME], [:RPG, :MoveCommand],
185
+ [:RPG, :MoveRoute], [:RPG, :SE], [:RPG, :Skill], [:RPG, :State],
186
+ [:RPG, :System, :Terms], [:RPG, :System, :TestBattler], [:RPG, :System, :Vehicle],
187
+ [:RPG, :System, :Words], [:RPG, :Tileset], [:RPG, :Troop], [:RPG, :Troop, :Member],
188
+ [:RPG, :Troop, :Page], [:RPG, :Troop, :Page, :Condition], [:RPG, :UsableItem],
189
+ [:RPG, :UsableItem, :Damage], [:RPG, :UsableItem, :Effect], [:RPG, :Weapon],
190
+ # Script classes serialized in save game files
191
+ [:Game_ActionResult], [:Game_Actor], [:Game_Actors], [:Game_BaseItem],
192
+ [:Game_BattleAction], [:Game_CommonEvent], [:Game_Enemy], [:Game_Event],
193
+ [:Game_Follower], [:Game_Followers], [:Game_Interpreter], [:Game_Map],
194
+ [:Game_Message], [:Game_Party], [:Game_Picture], [:Game_Pictures], [:Game_Player],
195
+ [:Game_System], [:Game_Timer], [:Game_Troop], [:Game_Screen], [:Game_Vehicle],
196
+ [:Interpreter],
197
+ [:PokemonDataCopy],
198
+ [:PBAnimations]
199
+ # coughing up classes for fusion
200
+ # [:PokemonDataBox, :Graphic]
201
+ ].each {|x| process(Object, *x)}
202
+
203
+
204
+ def self.setup_system(version, options)
205
+ # convert variable and switch name arrays to a hash when serialized
206
+ # if round_trip isn't set change version_id to fixed number
207
+ if options[:round_trip]
208
+ iso = ->(val) { return val }
209
+ reset_method(RPG::System, :reduce_string, iso)
210
+ reset_method(RPG::System, :map_version, iso)
211
+ reset_method(Game_System, :map_version, iso)
212
+ else
213
+ reset_method(RPG::System, :reduce_string, ->(str) {
214
+ return nil if str.nil?
215
+ stripped = str.strip
216
+ return stripped.empty? ? nil : stripped
217
+ })
218
+ # These magic numbers should be different. If they are the same, the saved version
219
+ # of the map in save files will be used instead of any updated version of the map
220
+ reset_method(RPG::System, :map_version, ->(ignored) { return 12345678 })
221
+ reset_method(Game_System, :map_version, ->(ignored) { return 87654321 })
222
+ end
223
+ end
224
+
225
+ def self.setup_interpreter(version)
226
+ # Game_Interpreter is marshalled differently in VX Ace
227
+ if version == :ace
228
+ reset_method(Game_Interpreter, :marshal_dump, ->{
229
+ return @data
230
+ })
231
+ reset_method(Game_Interpreter, :marshal_load, ->(obj) {
232
+ @data = obj
233
+ })
234
+ else
235
+ remove_defined_method(Game_Interpreter, :marshal_dump)
236
+ remove_defined_method(Game_Interpreter, :marshal_load)
237
+ end
238
+ end
239
+
240
+ def self.setup_event_command(version, options)
241
+ # format event commands to flow style for the event codes that aren't move commands
242
+ if options[:round_trip]
243
+ reset_method(RPG::EventCommand, :clean, ->{})
244
+ else
245
+ reset_method(RPG::EventCommand, :clean, ->{
246
+ @parameters[0].rstrip! if @code == 401
247
+ })
248
+ end
249
+ reset_const(RPG::EventCommand, :MOVE_LIST_CODE, version == :xp ? 209 : 205)
250
+ end
251
+
252
+ def self.setup_classes(version, options)
253
+ setup_system(version, options)
254
+ setup_interpreter(version)
255
+ setup_event_command(version, options)
256
+ BasicCoder.set_ivars_methods(version)
257
+ end
258
+
259
+ FLOW_CLASSES = [Color, Tone, RPG::BGM, RPG::BGS, RPG::MoveCommand, RPG::SE]
260
+
261
+ SCRIPTS_BASE = 'Scripts'
262
+
263
+ ACE_DATA_EXT = '.rvdata2'
264
+ VX_DATA_EXT = '.rvdata'
265
+ XP_DATA_EXT = '.rxdata'
266
+ YAML_EXT = '.yaml'
267
+ RUBY_EXT = '.rb'
268
+
269
+ def self.get_data_directory(base)
270
+ return File.join(base, 'Data')
271
+ end
272
+
273
+ def self.get_yaml_directory(base)
274
+ return File.join(base, 'YAML')
275
+ end
276
+
277
+ def self.get_script_directory(base)
278
+ return File.join(base, 'Scripts')
279
+ end
280
+
281
+ class Game_Switches
282
+ include RGSS::BasicCoder
283
+
284
+ def encode(name, value)
285
+ return array_to_hash(value)
286
+ end
287
+
288
+ def decode(name, value)
289
+ return hash_to_array(value)
290
+ end
291
+ end
292
+
293
+ class Game_Variables
294
+ include RGSS::BasicCoder
295
+
296
+ def encode(name, value)
297
+ return array_to_hash(value)
298
+ end
299
+
300
+ def decode(name, value)
301
+ return hash_to_array(value)
302
+ end
303
+ end
304
+
305
+ class Game_SelfSwitches
306
+ include RGSS::BasicCoder
307
+
308
+ def encode(name, value)
309
+ return Hash[value.collect {|pair|
310
+ key, value = pair
311
+ next ["%03d %03d %s" % key, value]
312
+ }]
313
+ end
314
+
315
+ def decode(name, value)
316
+ return Hash[value.collect {|pair|
317
+ key, value = pair
318
+ next [key.scanf("%d %d %s"), value]
319
+ }]
320
+ end
321
+ end
322
+
323
+ class Game_System
324
+ include RGSS::BasicCoder
325
+
326
+ def encode(name, value)
327
+ if name == 'version_id'
328
+ return map_version(value)
329
+ else
330
+ return value
331
+ end
332
+ end
333
+ end
334
+
335
+ require 'RGSS/serialize'
336
+ end