rvpacker 1.0.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +34 -34
- data/Gemfile +4 -4
- data/LICENSE +17 -17
- data/README.md +78 -29
- data/Rakefile +2 -2
- data/bin/rvpacker +3 -1
- data/lib/RGSS.rb +320 -320
- data/lib/RGSS/BasicCoder.rb +0 -0
- data/lib/RGSS/psych_mods.rb +129 -129
- data/lib/RGSS/serialize.rb +384 -371
- data/lib/RPG.rb +0 -0
- data/lib/rvpacker/version.rb +3 -3
- data/rvpacker.gemspec +25 -25
- metadata +3 -3
data/.gitignore
CHANGED
@@ -1,34 +1,34 @@
|
|
1
|
-
*.gem
|
2
|
-
*.rbc
|
3
|
-
/.config
|
4
|
-
/coverage/
|
5
|
-
/InstalledFiles
|
6
|
-
/pkg/
|
7
|
-
/spec/reports/
|
8
|
-
/test/tmp/
|
9
|
-
/test/version_tmp/
|
10
|
-
/tmp/
|
11
|
-
|
12
|
-
## Specific to RubyMotion:
|
13
|
-
.dat*
|
14
|
-
.repl_history
|
15
|
-
build/
|
16
|
-
|
17
|
-
## Documentation cache and generated files:
|
18
|
-
/.yardoc/
|
19
|
-
/_yardoc/
|
20
|
-
/doc/
|
21
|
-
/rdoc/
|
22
|
-
|
23
|
-
## Environment normalisation:
|
24
|
-
/.bundle/
|
25
|
-
/lib/bundler/man/
|
26
|
-
|
27
|
-
# for a library or gem, you might want to ignore these files since the code is
|
28
|
-
# intended to run in multiple environments; otherwise, check them in:
|
29
|
-
# Gemfile.lock
|
30
|
-
# .ruby-version
|
31
|
-
# .ruby-gemset
|
32
|
-
|
33
|
-
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
34
|
-
.rvmrc
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/test/tmp/
|
9
|
+
/test/version_tmp/
|
10
|
+
/tmp/
|
11
|
+
|
12
|
+
## Specific to RubyMotion:
|
13
|
+
.dat*
|
14
|
+
.repl_history
|
15
|
+
build/
|
16
|
+
|
17
|
+
## Documentation cache and generated files:
|
18
|
+
/.yardoc/
|
19
|
+
/_yardoc/
|
20
|
+
/doc/
|
21
|
+
/rdoc/
|
22
|
+
|
23
|
+
## Environment normalisation:
|
24
|
+
/.bundle/
|
25
|
+
/lib/bundler/man/
|
26
|
+
|
27
|
+
# for a library or gem, you might want to ignore these files since the code is
|
28
|
+
# intended to run in multiple environments; otherwise, check them in:
|
29
|
+
# Gemfile.lock
|
30
|
+
# .ruby-version
|
31
|
+
# .ruby-gemset
|
32
|
+
|
33
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
34
|
+
.rvmrc
|
data/Gemfile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
source 'https://rubygems.org'
|
2
|
-
|
3
|
-
# Specify your gem's dependencies in rvpacker.gemspec
|
4
|
-
gemspec
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in rvpacker.gemspec
|
4
|
+
gemspec
|
data/LICENSE
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
Copyright (c) 2013 Howard Jeng
|
2
|
-
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
4
|
-
software and associated documentation files (the "Software"), to deal in the Software
|
5
|
-
without restriction, including without limitation the rights to use, copy, modify, merge,
|
6
|
-
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
7
|
-
to whom the Software is furnished to do so, subject to the following conditions:
|
8
|
-
|
9
|
-
The above copyright notice and this permission notice shall be included in all copies or
|
10
|
-
substantial portions of the Software.
|
11
|
-
|
12
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
13
|
-
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
14
|
-
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
15
|
-
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
16
|
-
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
17
|
-
DEALINGS IN THE SOFTWARE.
|
1
|
+
Copyright (c) 2013 Howard Jeng
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
4
|
+
software and associated documentation files (the "Software"), to deal in the Software
|
5
|
+
without restriction, including without limitation the rights to use, copy, modify, merge,
|
6
|
+
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
7
|
+
to whom the Software is furnished to do so, subject to the following conditions:
|
8
|
+
|
9
|
+
The above copyright notice and this permission notice shall be included in all copies or
|
10
|
+
substantial portions of the Software.
|
11
|
+
|
12
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
13
|
+
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
14
|
+
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
15
|
+
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
16
|
+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
17
|
+
DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,29 +1,78 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
1
|
+
rvpacker
|
2
|
+
======================
|
3
|
+
|
4
|
+
A tool to unpack & pack RPGMaker data files into text so they can be version controlled & collaborated on
|
5
|
+
|
6
|
+
rvpacker consists of 3 parts:
|
7
|
+
|
8
|
+
* RPG library (stub classes for serialization of RPGMaker game data)
|
9
|
+
* RGSS library (some more classes for RPGMaker serialization)
|
10
|
+
* rvpacker (the script you call on the frontend)
|
11
|
+
|
12
|
+
Credit to SiCrane
|
13
|
+
=================
|
14
|
+
|
15
|
+
The RPG and RGSS libraries were originally taken from SiCrane's YAML importer/exporter on the gamedev forums. I initially just put them in github so I wouldn't lose them, and added the rvpacker script frontend. They are starting to drift a bit, but SiCrane still gets original credit for the grand majority of the work that rvpacker does.
|
16
|
+
|
17
|
+
http://www.gamedev.net/topic/646333-rpg-maker-vx-ace-data-conversion-utility/
|
18
|
+
|
19
|
+
Installation
|
20
|
+
============
|
21
|
+
|
22
|
+
rvpacker is bundled as a rubygem
|
23
|
+
|
24
|
+
[]$ gem install rvpacker
|
25
|
+
|
26
|
+
... dependencies will be handled automatically.
|
27
|
+
|
28
|
+
If you are a windows user and rvpacker complains about being unable to install psych, try downloading the rvpacker source and doing 'bundle install'. That, for some reason, works. (Don't ask me, I think ruby is retarded here.)
|
29
|
+
|
30
|
+
Usage
|
31
|
+
=====
|
32
|
+
|
33
|
+
$ rvpacker --help
|
34
|
+
Options:
|
35
|
+
--action, -a <s>: Action to perform on project (unpack|pack)
|
36
|
+
--project, -d <s>: RPG Maker Project directory
|
37
|
+
--force, -f: Update target even when source is older than target
|
38
|
+
--project-type, -t <s>: Project type (vx|ace|xp)
|
39
|
+
--help, -h: Show this message
|
40
|
+
|
41
|
+
For example, to unpack a RPG Maker VX Ace project in ~/Documents/RPGVXAce/Project1:
|
42
|
+
|
43
|
+
rvpacker --action unpack --project ~/Documents/RPGVXAce/Project1 --project-type ace
|
44
|
+
|
45
|
+
... This will expand all Data/* files into (PROJECT)/YAML/ as YAML files (YAML is used because the object serialization data is retained, which ruby's YAML parser is very good at - otherwise I would have changed it to JSON). The Scripts will be unpacked as individual .rb files into (PROJECT)/Scripts/.
|
46
|
+
|
47
|
+
To take a previously unpacked project, and pack it back up:
|
48
|
+
|
49
|
+
rvpacker --action pack --project ~/Documents/RPGVXAce/Project1 --project-type ace
|
50
|
+
|
51
|
+
... This will take all of the yaml files in (PROJECT)/YAML and all the scripts in (PROJECT)/Scripts, and repack all of your (PROJECT)/Data/* files. You can trust this to completely reassemble your Data/ directory, so long as the Scripts/ and YAML/ directories remain intact.
|
52
|
+
|
53
|
+
Workflow
|
54
|
+
========
|
55
|
+
|
56
|
+
This is great for teams that are collaborating on an RPG Maker project. Just add a few steps to your existing workflow:
|
57
|
+
|
58
|
+
* Checkout the project from version control
|
59
|
+
* Run 'rvpacker --action pack' on the project to repack it for the RPG Maker tool
|
60
|
+
* Load up RPG Maker and do whatever you're going to do; save the project
|
61
|
+
* Run 'rvpacker --action unpack' on the project
|
62
|
+
* Commit everything to version control (ignore the Data directory since you don't need it anymore; use .gitignore or .hgignore or whatever)
|
63
|
+
|
64
|
+
... Now your project can be forked/merged in a much more safe/sane way, and you don't have to have someone bottlenecking the entire process.
|
65
|
+
|
66
|
+
Automatic ID generation
|
67
|
+
=======================
|
68
|
+
|
69
|
+
You can add new elements to the YAML files manually, and leave their 'id:' field set to 'null'. This will cause the rvpacker pack action to automatically assign them a new ID number at the end of the sequence (e.g., if you have 17 items, the new one becomes ID 18). This is mainly handy for adding new scripts to the project without having to open the RPG maker and paste the script in; just make the new script file, add its entry in YAML/Scripts.yaml, and the designer will have your script accessible the next time they repack and open the project.
|
70
|
+
|
71
|
+
Also, the rvpacker tool sets the ID of script files to an autoincrementing integer. The scripts exist in the database with a magic number that I can't recreate, and nothing in the editor (RPG VX Ace anyway) seems to care if the magic number changes. It doesn't even affect the ordering. So in order to support adding new scripts with null IDs, like everything else, the magic numbers on scripts are disregarded and a new ID number is forced on the scripts when the rvpacker pack action occurs.
|
72
|
+
|
73
|
+
Psych 2.0.0 Dependency
|
74
|
+
======================
|
75
|
+
|
76
|
+
From SiCrane:
|
77
|
+
|
78
|
+
I used cygwin's ruby 1.9.3 and the Psych 2.0.0 ruby gem, which appears to be the most recent version. However, Psych 2.0.0 has some bugs that impacted the generated YAML (one major and one minor) which I monkey patched, and since I was already rewriting the Psych code, I added some functionality to make the generated YAML prettier. Long story short, this code probably won't work with any version of Psych but 2.0.0.
|
data/Rakefile
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
require "bundler/gem_tasks"
|
2
|
-
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
data/bin/rvpacker
CHANGED
@@ -10,6 +10,7 @@ opts = Trollop::options do
|
|
10
10
|
opt :force, "Update target even when source is older than target", :short => "f"
|
11
11
|
opt :project_type, "Project type (vx|ace|xp)", :short => "t", :type => String
|
12
12
|
opt :verbose, "Print verbose information while processing", :short => "V"
|
13
|
+
opt :database, "Only work on the given database", :short => "D", :type => String
|
13
14
|
end
|
14
15
|
|
15
16
|
directions = {
|
@@ -28,7 +29,8 @@ RGSS.serialize(projecttypes[opts[:project_type]],
|
|
28
29
|
opts[:project],
|
29
30
|
{ :force => (opts[:force] ? true : false),
|
30
31
|
:line_width => -1,
|
31
|
-
:table_width => -1
|
32
|
+
:table_width => -1,
|
33
|
+
:database => opts[:database]
|
32
34
|
}
|
33
35
|
)
|
34
36
|
|
data/lib/RGSS.rb
CHANGED
@@ -1,320 +1,320 @@
|
|
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)
|
76
|
-
@r, @g, @b, @a = *bytes.unpack('D4')
|
77
|
-
end
|
78
|
-
|
79
|
-
def _dump(*ignored)
|
80
|
-
return [@r, @g, @b, @a].pack('D4')
|
81
|
-
end
|
82
|
-
|
83
|
-
def self._load(bytes)
|
84
|
-
Color.new(bytes)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
class Tone
|
89
|
-
def initialize(bytes)
|
90
|
-
@r, @g, @b, @a = *bytes.unpack('D4')
|
91
|
-
end
|
92
|
-
|
93
|
-
def _dump(*ignored)
|
94
|
-
return [@r, @g, @b, @a].pack('D4')
|
95
|
-
end
|
96
|
-
|
97
|
-
def self._load(bytes)
|
98
|
-
Tone.new(bytes)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
class Rect
|
103
|
-
def initialize(bytes)
|
104
|
-
@x, @y, @width, @height = *bytes.unpack('i4')
|
105
|
-
end
|
106
|
-
|
107
|
-
def _dump(*ignored)
|
108
|
-
return [@x, @y, @width, @height].pack('i4')
|
109
|
-
end
|
110
|
-
|
111
|
-
def self._load(bytes)
|
112
|
-
Rect.new(bytes)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
module RGSS
|
117
|
-
def self.remove_defined_method(scope, name)
|
118
|
-
scope.send(:remove_method, name) if scope.instance_methods(false).include?(name)
|
119
|
-
end
|
120
|
-
|
121
|
-
def self.reset_method(scope, name, method)
|
122
|
-
remove_defined_method(scope, name)
|
123
|
-
scope.send(:define_method, name, method)
|
124
|
-
end
|
125
|
-
|
126
|
-
def self.reset_const(scope, sym, value)
|
127
|
-
scope.send(:remove_const, sym) if scope.const_defined?(sym)
|
128
|
-
scope.send(:const_set, sym, value)
|
129
|
-
end
|
130
|
-
|
131
|
-
def self.array_to_hash(arr, &block)
|
132
|
-
h = {}
|
133
|
-
arr.each_with_index do |val, index|
|
134
|
-
r = block_given? ? block.call(val) : val
|
135
|
-
h[index] = r unless r.nil?
|
136
|
-
end
|
137
|
-
if arr.length > 0
|
138
|
-
last = arr.length - 1
|
139
|
-
h[last] = nil unless h.has_key?(last)
|
140
|
-
end
|
141
|
-
return h
|
142
|
-
end
|
143
|
-
|
144
|
-
def self.hash_to_array(hash)
|
145
|
-
arr = []
|
146
|
-
hash.each do |k, v|
|
147
|
-
arr[k] = v
|
148
|
-
end
|
149
|
-
return arr
|
150
|
-
end
|
151
|
-
|
152
|
-
require 'RGSS/BasicCoder'
|
153
|
-
require 'RPG'
|
154
|
-
|
155
|
-
# creates an empty class in a potentially nested scope
|
156
|
-
def self.process(root, name, *args)
|
157
|
-
if args.length > 0
|
158
|
-
process(root.const_get(name), *args)
|
159
|
-
else
|
160
|
-
root.const_set(name, Class.new) unless root.const_defined?(name, false)
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
# other classes that don't need definitions
|
165
|
-
[ # RGSS data structures
|
166
|
-
[:RPG, :Actor], [:RPG, :Animation], [:RPG, :Animation, :Frame],
|
167
|
-
[:RPG, :Animation, :Timing], [:RPG, :Area], [:RPG, :Armor], [:RPG, :AudioFile],
|
168
|
-
[:RPG, :BaseItem], [:RPG, :BaseItem, :Feature], [:RPG, :BGM], [:RPG, :BGS],
|
169
|
-
[:RPG, :Class], [:RPG, :Class, :Learning], [:RPG, :CommonEvent], [:RPG, :Enemy],
|
170
|
-
[:RPG, :Enemy, :Action], [:RPG, :Enemy, :DropItem], [:RPG, :EquipItem],
|
171
|
-
[:RPG, :Event], [:RPG, :Event, :Page], [:RPG, :Event, :Page, :Condition],
|
172
|
-
[:RPG, :Event, :Page, :Graphic], [:RPG, :Item], [:RPG, :Map],
|
173
|
-
[:RPG, :Map, :Encounter], [:RPG, :MapInfo], [:RPG, :ME], [:RPG, :MoveCommand],
|
174
|
-
[:RPG, :MoveRoute], [:RPG, :SE], [:RPG, :Skill], [:RPG, :State],
|
175
|
-
[:RPG, :System, :Terms], [:RPG, :System, :TestBattler], [:RPG, :System, :Vehicle],
|
176
|
-
[:RPG, :System, :Words], [:RPG, :Tileset], [:RPG, :Troop], [:RPG, :Troop, :Member],
|
177
|
-
[:RPG, :Troop, :Page], [:RPG, :Troop, :Page, :Condition], [:RPG, :UsableItem],
|
178
|
-
[:RPG, :UsableItem, :Damage], [:RPG, :UsableItem, :Effect], [:RPG, :Weapon],
|
179
|
-
# Script classes serialized in save game files
|
180
|
-
[:Game_ActionResult], [:Game_Actor], [:Game_Actors], [:Game_BaseItem],
|
181
|
-
[:Game_BattleAction], [:Game_CommonEvent], [:Game_Enemy], [:Game_Event],
|
182
|
-
[:Game_Follower], [:Game_Followers], [:Game_Interpreter], [:Game_Map],
|
183
|
-
[:Game_Message], [:Game_Party], [:Game_Picture], [:Game_Pictures], [:Game_Player],
|
184
|
-
[:Game_System], [:Game_Timer], [:Game_Troop], [:Game_Screen], [:Game_Vehicle],
|
185
|
-
[:Interpreter]
|
186
|
-
].each {|x| process(Object, *x)}
|
187
|
-
|
188
|
-
def self.setup_system(version, options)
|
189
|
-
# convert variable and switch name arrays to a hash when serialized
|
190
|
-
# if round_trip isn't set change version_id to fixed number
|
191
|
-
if options[:round_trip]
|
192
|
-
iso = ->(val) { return val }
|
193
|
-
reset_method(RPG::System, :reduce_string, iso)
|
194
|
-
reset_method(RPG::System, :map_version, iso)
|
195
|
-
reset_method(Game_System, :map_version, iso)
|
196
|
-
else
|
197
|
-
reset_method(RPG::System, :reduce_string, ->(str) {
|
198
|
-
return nil if str.nil?
|
199
|
-
stripped = str.strip
|
200
|
-
return stripped.empty? ? nil : stripped
|
201
|
-
})
|
202
|
-
# These magic numbers should be different. If they are the same, the saved version
|
203
|
-
# of the map in save files will be used instead of any updated version of the map
|
204
|
-
reset_method(RPG::System, :map_version, ->(ignored) { return 12345678 })
|
205
|
-
reset_method(Game_System, :map_version, ->(ignored) { return 87654321 })
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
def self.setup_interpreter(version)
|
210
|
-
# Game_Interpreter is marshalled differently in VX Ace
|
211
|
-
if version == :ace
|
212
|
-
reset_method(Game_Interpreter, :marshal_dump, ->{
|
213
|
-
return @data
|
214
|
-
})
|
215
|
-
reset_method(Game_Interpreter, :marshal_load, ->(obj) {
|
216
|
-
@data = obj
|
217
|
-
})
|
218
|
-
else
|
219
|
-
remove_defined_method(Game_Interpreter, :marshal_dump)
|
220
|
-
remove_defined_method(Game_Interpreter, :marshal_load)
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
def self.setup_event_command(version, options)
|
225
|
-
# format event commands to flow style for the event codes that aren't move commands
|
226
|
-
if options[:round_trip]
|
227
|
-
reset_method(RPG::EventCommand, :clean, ->{})
|
228
|
-
else
|
229
|
-
reset_method(RPG::EventCommand, :clean, ->{
|
230
|
-
@parameters[0].rstrip! if @code == 401
|
231
|
-
})
|
232
|
-
end
|
233
|
-
reset_const(RPG::EventCommand, :MOVE_LIST_CODE, version == :xp ? 209 : 205)
|
234
|
-
end
|
235
|
-
|
236
|
-
def self.setup_classes(version, options)
|
237
|
-
setup_system(version, options)
|
238
|
-
setup_interpreter(version)
|
239
|
-
setup_event_command(version, options)
|
240
|
-
BasicCoder.set_ivars_methods(version)
|
241
|
-
end
|
242
|
-
|
243
|
-
FLOW_CLASSES = [Color, Tone, RPG::BGM, RPG::BGS, RPG::MoveCommand, RPG::SE]
|
244
|
-
|
245
|
-
SCRIPTS_BASE = 'Scripts'
|
246
|
-
|
247
|
-
ACE_DATA_EXT = '.rvdata2'
|
248
|
-
VX_DATA_EXT = '.rvdata'
|
249
|
-
XP_DATA_EXT = '.rxdata'
|
250
|
-
YAML_EXT = '.yaml'
|
251
|
-
RUBY_EXT = '.rb'
|
252
|
-
|
253
|
-
def self.get_data_directory(base)
|
254
|
-
return File.join(base, 'Data')
|
255
|
-
end
|
256
|
-
|
257
|
-
def self.get_yaml_directory(base)
|
258
|
-
return File.join(base, 'YAML')
|
259
|
-
end
|
260
|
-
|
261
|
-
def self.get_script_directory(base)
|
262
|
-
return File.join(base, 'Scripts')
|
263
|
-
end
|
264
|
-
|
265
|
-
class Game_Switches
|
266
|
-
include RGSS::BasicCoder
|
267
|
-
|
268
|
-
def encode(name, value)
|
269
|
-
return array_to_hash(value)
|
270
|
-
end
|
271
|
-
|
272
|
-
def decode(name, value)
|
273
|
-
return hash_to_array(value)
|
274
|
-
end
|
275
|
-
end
|
276
|
-
|
277
|
-
class Game_Variables
|
278
|
-
include RGSS::BasicCoder
|
279
|
-
|
280
|
-
def encode(name, value)
|
281
|
-
return array_to_hash(value)
|
282
|
-
end
|
283
|
-
|
284
|
-
def decode(name, value)
|
285
|
-
return hash_to_array(value)
|
286
|
-
end
|
287
|
-
end
|
288
|
-
|
289
|
-
class Game_SelfSwitches
|
290
|
-
include RGSS::BasicCoder
|
291
|
-
|
292
|
-
def encode(name, value)
|
293
|
-
return Hash[value.collect {|pair|
|
294
|
-
key, value = pair
|
295
|
-
next ["%03d %03d %s" % key, value]
|
296
|
-
}]
|
297
|
-
end
|
298
|
-
|
299
|
-
def decode(name, value)
|
300
|
-
return Hash[value.collect {|pair|
|
301
|
-
key, value = pair
|
302
|
-
next [key.scanf("%d %d %s"), value]
|
303
|
-
}]
|
304
|
-
end
|
305
|
-
end
|
306
|
-
|
307
|
-
class Game_System
|
308
|
-
include RGSS::BasicCoder
|
309
|
-
|
310
|
-
def encode(name, value)
|
311
|
-
if name == 'version_id'
|
312
|
-
return map_version(value)
|
313
|
-
else
|
314
|
-
return value
|
315
|
-
end
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
require 'RGSS/serialize'
|
320
|
-
end
|
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)
|
76
|
+
@r, @g, @b, @a = *bytes.unpack('D4')
|
77
|
+
end
|
78
|
+
|
79
|
+
def _dump(*ignored)
|
80
|
+
return [@r, @g, @b, @a].pack('D4')
|
81
|
+
end
|
82
|
+
|
83
|
+
def self._load(bytes)
|
84
|
+
Color.new(bytes)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class Tone
|
89
|
+
def initialize(bytes)
|
90
|
+
@r, @g, @b, @a = *bytes.unpack('D4')
|
91
|
+
end
|
92
|
+
|
93
|
+
def _dump(*ignored)
|
94
|
+
return [@r, @g, @b, @a].pack('D4')
|
95
|
+
end
|
96
|
+
|
97
|
+
def self._load(bytes)
|
98
|
+
Tone.new(bytes)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class Rect
|
103
|
+
def initialize(bytes)
|
104
|
+
@x, @y, @width, @height = *bytes.unpack('i4')
|
105
|
+
end
|
106
|
+
|
107
|
+
def _dump(*ignored)
|
108
|
+
return [@x, @y, @width, @height].pack('i4')
|
109
|
+
end
|
110
|
+
|
111
|
+
def self._load(bytes)
|
112
|
+
Rect.new(bytes)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
module RGSS
|
117
|
+
def self.remove_defined_method(scope, name)
|
118
|
+
scope.send(:remove_method, name) if scope.instance_methods(false).include?(name)
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.reset_method(scope, name, method)
|
122
|
+
remove_defined_method(scope, name)
|
123
|
+
scope.send(:define_method, name, method)
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.reset_const(scope, sym, value)
|
127
|
+
scope.send(:remove_const, sym) if scope.const_defined?(sym)
|
128
|
+
scope.send(:const_set, sym, value)
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.array_to_hash(arr, &block)
|
132
|
+
h = {}
|
133
|
+
arr.each_with_index do |val, index|
|
134
|
+
r = block_given? ? block.call(val) : val
|
135
|
+
h[index] = r unless r.nil?
|
136
|
+
end
|
137
|
+
if arr.length > 0
|
138
|
+
last = arr.length - 1
|
139
|
+
h[last] = nil unless h.has_key?(last)
|
140
|
+
end
|
141
|
+
return h
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.hash_to_array(hash)
|
145
|
+
arr = []
|
146
|
+
hash.each do |k, v|
|
147
|
+
arr[k] = v
|
148
|
+
end
|
149
|
+
return arr
|
150
|
+
end
|
151
|
+
|
152
|
+
require 'RGSS/BasicCoder'
|
153
|
+
require 'RPG'
|
154
|
+
|
155
|
+
# creates an empty class in a potentially nested scope
|
156
|
+
def self.process(root, name, *args)
|
157
|
+
if args.length > 0
|
158
|
+
process(root.const_get(name), *args)
|
159
|
+
else
|
160
|
+
root.const_set(name, Class.new) unless root.const_defined?(name, false)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# other classes that don't need definitions
|
165
|
+
[ # RGSS data structures
|
166
|
+
[:RPG, :Actor], [:RPG, :Animation], [:RPG, :Animation, :Frame],
|
167
|
+
[:RPG, :Animation, :Timing], [:RPG, :Area], [:RPG, :Armor], [:RPG, :AudioFile],
|
168
|
+
[:RPG, :BaseItem], [:RPG, :BaseItem, :Feature], [:RPG, :BGM], [:RPG, :BGS],
|
169
|
+
[:RPG, :Class], [:RPG, :Class, :Learning], [:RPG, :CommonEvent], [:RPG, :Enemy],
|
170
|
+
[:RPG, :Enemy, :Action], [:RPG, :Enemy, :DropItem], [:RPG, :EquipItem],
|
171
|
+
[:RPG, :Event], [:RPG, :Event, :Page], [:RPG, :Event, :Page, :Condition],
|
172
|
+
[:RPG, :Event, :Page, :Graphic], [:RPG, :Item], [:RPG, :Map],
|
173
|
+
[:RPG, :Map, :Encounter], [:RPG, :MapInfo], [:RPG, :ME], [:RPG, :MoveCommand],
|
174
|
+
[:RPG, :MoveRoute], [:RPG, :SE], [:RPG, :Skill], [:RPG, :State],
|
175
|
+
[:RPG, :System, :Terms], [:RPG, :System, :TestBattler], [:RPG, :System, :Vehicle],
|
176
|
+
[:RPG, :System, :Words], [:RPG, :Tileset], [:RPG, :Troop], [:RPG, :Troop, :Member],
|
177
|
+
[:RPG, :Troop, :Page], [:RPG, :Troop, :Page, :Condition], [:RPG, :UsableItem],
|
178
|
+
[:RPG, :UsableItem, :Damage], [:RPG, :UsableItem, :Effect], [:RPG, :Weapon],
|
179
|
+
# Script classes serialized in save game files
|
180
|
+
[:Game_ActionResult], [:Game_Actor], [:Game_Actors], [:Game_BaseItem],
|
181
|
+
[:Game_BattleAction], [:Game_CommonEvent], [:Game_Enemy], [:Game_Event],
|
182
|
+
[:Game_Follower], [:Game_Followers], [:Game_Interpreter], [:Game_Map],
|
183
|
+
[:Game_Message], [:Game_Party], [:Game_Picture], [:Game_Pictures], [:Game_Player],
|
184
|
+
[:Game_System], [:Game_Timer], [:Game_Troop], [:Game_Screen], [:Game_Vehicle],
|
185
|
+
[:Interpreter]
|
186
|
+
].each {|x| process(Object, *x)}
|
187
|
+
|
188
|
+
def self.setup_system(version, options)
|
189
|
+
# convert variable and switch name arrays to a hash when serialized
|
190
|
+
# if round_trip isn't set change version_id to fixed number
|
191
|
+
if options[:round_trip]
|
192
|
+
iso = ->(val) { return val }
|
193
|
+
reset_method(RPG::System, :reduce_string, iso)
|
194
|
+
reset_method(RPG::System, :map_version, iso)
|
195
|
+
reset_method(Game_System, :map_version, iso)
|
196
|
+
else
|
197
|
+
reset_method(RPG::System, :reduce_string, ->(str) {
|
198
|
+
return nil if str.nil?
|
199
|
+
stripped = str.strip
|
200
|
+
return stripped.empty? ? nil : stripped
|
201
|
+
})
|
202
|
+
# These magic numbers should be different. If they are the same, the saved version
|
203
|
+
# of the map in save files will be used instead of any updated version of the map
|
204
|
+
reset_method(RPG::System, :map_version, ->(ignored) { return 12345678 })
|
205
|
+
reset_method(Game_System, :map_version, ->(ignored) { return 87654321 })
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def self.setup_interpreter(version)
|
210
|
+
# Game_Interpreter is marshalled differently in VX Ace
|
211
|
+
if version == :ace
|
212
|
+
reset_method(Game_Interpreter, :marshal_dump, ->{
|
213
|
+
return @data
|
214
|
+
})
|
215
|
+
reset_method(Game_Interpreter, :marshal_load, ->(obj) {
|
216
|
+
@data = obj
|
217
|
+
})
|
218
|
+
else
|
219
|
+
remove_defined_method(Game_Interpreter, :marshal_dump)
|
220
|
+
remove_defined_method(Game_Interpreter, :marshal_load)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def self.setup_event_command(version, options)
|
225
|
+
# format event commands to flow style for the event codes that aren't move commands
|
226
|
+
if options[:round_trip]
|
227
|
+
reset_method(RPG::EventCommand, :clean, ->{})
|
228
|
+
else
|
229
|
+
reset_method(RPG::EventCommand, :clean, ->{
|
230
|
+
@parameters[0].rstrip! if @code == 401
|
231
|
+
})
|
232
|
+
end
|
233
|
+
reset_const(RPG::EventCommand, :MOVE_LIST_CODE, version == :xp ? 209 : 205)
|
234
|
+
end
|
235
|
+
|
236
|
+
def self.setup_classes(version, options)
|
237
|
+
setup_system(version, options)
|
238
|
+
setup_interpreter(version)
|
239
|
+
setup_event_command(version, options)
|
240
|
+
BasicCoder.set_ivars_methods(version)
|
241
|
+
end
|
242
|
+
|
243
|
+
FLOW_CLASSES = [Color, Tone, RPG::BGM, RPG::BGS, RPG::MoveCommand, RPG::SE]
|
244
|
+
|
245
|
+
SCRIPTS_BASE = 'Scripts'
|
246
|
+
|
247
|
+
ACE_DATA_EXT = '.rvdata2'
|
248
|
+
VX_DATA_EXT = '.rvdata'
|
249
|
+
XP_DATA_EXT = '.rxdata'
|
250
|
+
YAML_EXT = '.yaml'
|
251
|
+
RUBY_EXT = '.rb'
|
252
|
+
|
253
|
+
def self.get_data_directory(base)
|
254
|
+
return File.join(base, 'Data')
|
255
|
+
end
|
256
|
+
|
257
|
+
def self.get_yaml_directory(base)
|
258
|
+
return File.join(base, 'YAML')
|
259
|
+
end
|
260
|
+
|
261
|
+
def self.get_script_directory(base)
|
262
|
+
return File.join(base, 'Scripts')
|
263
|
+
end
|
264
|
+
|
265
|
+
class Game_Switches
|
266
|
+
include RGSS::BasicCoder
|
267
|
+
|
268
|
+
def encode(name, value)
|
269
|
+
return array_to_hash(value)
|
270
|
+
end
|
271
|
+
|
272
|
+
def decode(name, value)
|
273
|
+
return hash_to_array(value)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
class Game_Variables
|
278
|
+
include RGSS::BasicCoder
|
279
|
+
|
280
|
+
def encode(name, value)
|
281
|
+
return array_to_hash(value)
|
282
|
+
end
|
283
|
+
|
284
|
+
def decode(name, value)
|
285
|
+
return hash_to_array(value)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
class Game_SelfSwitches
|
290
|
+
include RGSS::BasicCoder
|
291
|
+
|
292
|
+
def encode(name, value)
|
293
|
+
return Hash[value.collect {|pair|
|
294
|
+
key, value = pair
|
295
|
+
next ["%03d %03d %s" % key, value]
|
296
|
+
}]
|
297
|
+
end
|
298
|
+
|
299
|
+
def decode(name, value)
|
300
|
+
return Hash[value.collect {|pair|
|
301
|
+
key, value = pair
|
302
|
+
next [key.scanf("%d %d %s"), value]
|
303
|
+
}]
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
class Game_System
|
308
|
+
include RGSS::BasicCoder
|
309
|
+
|
310
|
+
def encode(name, value)
|
311
|
+
if name == 'version_id'
|
312
|
+
return map_version(value)
|
313
|
+
else
|
314
|
+
return value
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
require 'RGSS/serialize'
|
320
|
+
end
|