wolftrans 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/bin/wolftrans +1 -0
- data/lib/wolfrpg/command.rb +8 -0
- data/lib/wolfrpg/common_events.rb +16 -0
- data/lib/wolfrpg/database.rb +43 -24
- data/lib/wolfrpg/game_dat.rb +4 -0
- data/lib/wolfrpg/map.rb +25 -0
- data/lib/wolftrans/patch_data.rb +117 -63
- data/lib/wolftrans/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04ff8773a7b8a4af514f481410befe41e922aaf2
|
4
|
+
data.tar.gz: 80e7cb14b2a9337ef34b687df85cbff1e4cf60a6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95a928ce6271aa3bfa37c8f842e92a9fee8c117c06849a52545f49fd2abd33ef64a7277b01342bcd188b1abcb7f36a78213161bd90411c1b42558fab05c0c03a
|
7
|
+
data.tar.gz: 7f3ed861199acd6c26fe2ac173892470ab061886b75332fe89d280e59fcf251df47be4a2eab4903670dcc6af2f869249fab874ae416e5981db19a786ca96ba69
|
data/README.md
CHANGED
@@ -36,6 +36,8 @@ Currently, Wolf Trans can be invoked with the command line:
|
|
36
36
|
|
37
37
|
If `patch_dir` does not exist, it will be automatically generated with the text contained in the data files of the game in `game_dir`. `out_dir` will contain the patched game.
|
38
38
|
|
39
|
+
**WARNING: OUT_DIR WILL BE *DELETED* IF IT EXISTS. USE CAUTION.**
|
40
|
+
|
39
41
|
The behavior of the command line arguments will almost certainly be revised in a future version.
|
40
42
|
|
41
43
|
## Todo
|
data/bin/wolftrans
CHANGED
data/lib/wolfrpg/command.rb
CHANGED
@@ -413,6 +413,14 @@ module WolfRpg
|
|
413
413
|
dump_terminator(coder)
|
414
414
|
end
|
415
415
|
|
416
|
+
def each_filename
|
417
|
+
@string_args.each do |str|
|
418
|
+
str.scan(/^[^ ]*?[\/\\].*?\.[a-zA-Z0-9]+$/).each do |filename|
|
419
|
+
yield filename.gsub('\\', '/')
|
420
|
+
end
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
416
424
|
private
|
417
425
|
def initialize(cid, args, string_args, indent)
|
418
426
|
@cid = cid
|
@@ -27,6 +27,14 @@ module WolfRpg
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
def each_filename
|
31
|
+
@events.each do |event|
|
32
|
+
event.each_filename do |fn|
|
33
|
+
yield fn
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
30
38
|
def grep(needle)
|
31
39
|
end
|
32
40
|
|
@@ -149,6 +157,14 @@ module WolfRpg
|
|
149
157
|
end
|
150
158
|
end
|
151
159
|
|
160
|
+
def each_filename
|
161
|
+
@commands.each do |command|
|
162
|
+
command.each_filename do |fn|
|
163
|
+
yield fn
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
152
168
|
private
|
153
169
|
MAGIC_NUMBER = [
|
154
170
|
0x0A, 0x00, 0x00, 0x00
|
data/lib/wolfrpg/database.rb
CHANGED
@@ -33,36 +33,46 @@ module WolfRpg
|
|
33
33
|
STDERR.puts "warning: no C1 terminator at the end of '#{dat_filename}'"
|
34
34
|
end
|
35
35
|
end
|
36
|
+
end
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
end
|
38
|
+
def dump(project_filename, dat_filename)
|
39
|
+
FileCoder.open(project_filename, :write) do |coder|
|
40
|
+
coder.write_int(@types.size)
|
41
|
+
@types.each do |type|
|
42
|
+
type.dump_project(coder)
|
43
43
|
end
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
44
|
+
end
|
45
|
+
FileCoder.open(dat_filename, :write, DAT_SEED_INDICES, @crypt_header) do |coder|
|
46
|
+
if encrypted?
|
47
|
+
coder.write_byte(@unknown_encrypted_1)
|
48
|
+
else
|
49
|
+
coder.write(DAT_MAGIC_NUMBER)
|
50
|
+
end
|
51
|
+
coder.write_int(@types.size)
|
52
|
+
@types.each do |type|
|
53
|
+
type.dump_dat(coder)
|
54
|
+
end
|
55
|
+
coder.write_byte(0xC1)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def each_filename
|
60
|
+
@types.each do |type|
|
61
|
+
type.data.each do |datum|
|
62
|
+
datum.each_filename do |fn|
|
63
|
+
yield fn
|
53
64
|
end
|
54
|
-
coder.write_byte(0xC1)
|
55
65
|
end
|
56
66
|
end
|
67
|
+
end
|
57
68
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
69
|
+
def grep(needle)
|
70
|
+
@types.each_with_index do |type, type_index|
|
71
|
+
type.data.each_with_index do |datum, datum_index|
|
72
|
+
datum.each_translatable do |value, field|
|
73
|
+
next unless value =~ needle
|
74
|
+
puts "DB:[#{type_index}]#{type.name}/[#{datum_index}]#{datum.name}/[#{field.index}]#{field.name}"
|
75
|
+
puts "\t" + value
|
66
76
|
end
|
67
77
|
end
|
68
78
|
end
|
@@ -312,6 +322,15 @@ module WolfRpg
|
|
312
322
|
yield [value, field] unless value.empty? || value.include?("\n")
|
313
323
|
end
|
314
324
|
end
|
325
|
+
|
326
|
+
def each_filename
|
327
|
+
@fields.each do |field|
|
328
|
+
next unless field.string?
|
329
|
+
self[field].scan(/^[^ ]*?[\/\\].*?\.[a-zA-Z0-9]+$/).each do |filename|
|
330
|
+
yield filename.gsub('\\', '/')
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
315
334
|
end
|
316
335
|
|
317
336
|
DAT_MAGIC_NUMBER = [
|
data/lib/wolfrpg/game_dat.rb
CHANGED
data/lib/wolfrpg/map.rb
CHANGED
@@ -55,6 +55,14 @@ module WolfRpg
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
+
def each_filename
|
59
|
+
@events.each do |event|
|
60
|
+
event.each_filename do |fn|
|
61
|
+
yield fn
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
58
66
|
#DEBUG method that searches for a string somewhere in the map
|
59
67
|
def grep(needle)
|
60
68
|
@events.each do |event|
|
@@ -128,6 +136,14 @@ module WolfRpg
|
|
128
136
|
coder.write_byte(0x70)
|
129
137
|
end
|
130
138
|
|
139
|
+
def each_filename
|
140
|
+
@pages.each do |page|
|
141
|
+
page.each_filename do |fn|
|
142
|
+
yield fn
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
131
147
|
class Page
|
132
148
|
attr_accessor :id
|
133
149
|
attr_accessor :unknown1
|
@@ -219,6 +235,15 @@ module WolfRpg
|
|
219
235
|
coder.write_byte(0x7A)
|
220
236
|
end
|
221
237
|
|
238
|
+
def each_filename
|
239
|
+
yield @graphic_name.gsub('\\', '/') unless @graphic_name.empty?
|
240
|
+
@commands.each do |command|
|
241
|
+
command.each_filename do |fn|
|
242
|
+
yield fn
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
222
247
|
COMMANDS_TERMINATOR = [
|
223
248
|
0x03, 0x00, 0x00, 0x00,
|
224
249
|
].pack('C*')
|
data/lib/wolftrans/patch_data.rb
CHANGED
@@ -3,6 +3,7 @@ require 'wolfrpg'
|
|
3
3
|
|
4
4
|
require 'fileutils'
|
5
5
|
require 'find'
|
6
|
+
require 'set'
|
6
7
|
|
7
8
|
#####################
|
8
9
|
# Loading Game data #
|
@@ -15,38 +16,29 @@ module WolfTrans
|
|
15
16
|
end
|
16
17
|
@game_data_dir = Util.join_path_nocase(@game_dir, 'data')
|
17
18
|
if @game_data_dir == nil
|
18
|
-
raise "could not find
|
19
|
+
raise "could not find Data folder in '#{@game_dir}'"
|
19
20
|
end
|
20
21
|
|
21
|
-
|
22
|
+
# Load databases, Game.dat, and common events
|
22
23
|
@databases = {}
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
elsif extension == '.project'
|
42
|
-
next if basename_downcase == 'sysdatabasebasic.project'
|
43
|
-
dat_filename = Util.join_path_nocase(parent_path, "#{basename_noext}.dat")
|
44
|
-
next if dat_filename == nil
|
45
|
-
load_game_database(filename, dat_filename)
|
46
|
-
elsif basename_downcase == 'commonevent.dat'
|
47
|
-
load_common_events(filename)
|
48
|
-
end
|
49
|
-
end
|
24
|
+
basicdata_dir = Util.join_path_nocase(@game_data_dir, 'basicdata')
|
25
|
+
if basicdata_dir == nil
|
26
|
+
raise "could not find BasicData folder in '#{@game_data_dir}'"
|
27
|
+
end
|
28
|
+
Dir.entries(basicdata_dir).each do |entry|
|
29
|
+
entry_downcase = entry.downcase
|
30
|
+
filename = "#{basicdata_dir}/#{entry}"
|
31
|
+
if entry_downcase == 'game.dat'
|
32
|
+
@game_dat_filename = 'Data/BasicData/Game.dat'
|
33
|
+
load_game_dat(filename)
|
34
|
+
elsif entry_downcase.end_with?('.project')
|
35
|
+
next if entry_downcase == 'sysdatabasebasic.project'
|
36
|
+
basename = File.basename(entry_downcase, '.*')
|
37
|
+
dat_filename = Util.join_path_nocase(basicdata_dir, "#{basename}.dat")
|
38
|
+
next if dat_filename == nil
|
39
|
+
load_game_database(filename, dat_filename)
|
40
|
+
elsif entry_downcase == 'commonevent.dat'
|
41
|
+
load_common_events(filename)
|
50
42
|
end
|
51
43
|
end
|
52
44
|
|
@@ -60,13 +52,62 @@ module WolfTrans
|
|
60
52
|
end
|
61
53
|
end
|
62
54
|
end
|
55
|
+
|
56
|
+
# Gather list of asset and map filenames
|
57
|
+
map_names = Set.new
|
58
|
+
@assets = {}
|
59
|
+
@databases.each_value do |db|
|
60
|
+
db.each_filename do |fn|
|
61
|
+
fn_downcase = fn.downcase
|
62
|
+
@assets[fn_downcase] = fn
|
63
|
+
if fn_downcase.end_with?('.mps')
|
64
|
+
map_names.add(File.basename(fn_downcase, '.*'))
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
@game_dat.each_filename do |fn|
|
69
|
+
@assets[fn.downcase] = fn
|
70
|
+
end
|
71
|
+
@common_events.each_filename do |fn|
|
72
|
+
@assets[fn.downcase] = fn
|
73
|
+
end
|
74
|
+
|
75
|
+
# Load maps
|
76
|
+
maps_path = Util.join_path_nocase(@game_data_dir, 'mapdata')
|
77
|
+
if maps_path == nil
|
78
|
+
raise "could not find MapData folder in '#{@game_data_dir}'"
|
79
|
+
end
|
80
|
+
@maps = {}
|
81
|
+
map_names.each do |name|
|
82
|
+
map_path = Util.join_path_nocase(maps_path, name + '.mps')
|
83
|
+
if map_path == nil
|
84
|
+
STDERR.puts "warn: could not find map '#{name}'"
|
85
|
+
next
|
86
|
+
end
|
87
|
+
load_map(map_path)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Gather remaining asset filenames
|
91
|
+
@maps.each_value do |map|
|
92
|
+
map.each_filename do |fn|
|
93
|
+
@assets[fn.downcase] = fn
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Make sure not to treat certain kinds of filenames as assets
|
98
|
+
@assets.reject! { |k, v| k.start_with?('save/') }
|
99
|
+
|
100
|
+
# Rewrite asset filenames
|
101
|
+
extcounts = Hash.new(0)
|
102
|
+
@assets.keys.sort.each do |fn|
|
103
|
+
ext = File.extname(fn)[1..-1]
|
104
|
+
@assets[fn] = '%04d.%s' % [extcounts[ext], ext]
|
105
|
+
extcounts[ext] += 1
|
106
|
+
end
|
63
107
|
end
|
64
108
|
|
65
109
|
# Apply the patch to the files in the game path and write them to the
|
66
110
|
# output directory
|
67
|
-
DATA_FILE_EXTENSIONS = ['png','jpg','jpeg','bmp','ogg',
|
68
|
-
'mp3','wav','mid','midi',
|
69
|
-
'dat','project','xxxxx']
|
70
111
|
def apply(out_dir)
|
71
112
|
out_dir = Util.sanitize_path(out_dir)
|
72
113
|
out_data_dir = "#{out_dir}/Data"
|
@@ -74,21 +115,8 @@ module WolfTrans
|
|
74
115
|
# Clear out directory
|
75
116
|
FileUtils.rm_rf(out_dir)
|
76
117
|
FileUtils.mkdir_p("#{out_data_dir}/BasicData")
|
77
|
-
FileUtils.mkdir_p("#{out_data_dir}/MapData")
|
78
118
|
|
79
|
-
#
|
80
|
-
@maps.each do |map_name, map|
|
81
|
-
map.events.each do |event|
|
82
|
-
next unless event
|
83
|
-
event.pages.each do |page|
|
84
|
-
page.commands.each_with_index do |command, cmd_index|
|
85
|
-
context = Context::MapEvent.from_data(map_name, event, page, cmd_index, command)
|
86
|
-
patch_command(command, context)
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
map.dump("#{out_data_dir}/MapData/#{map_name}.mps")
|
91
|
-
end
|
119
|
+
#TODO create directories for each asset
|
92
120
|
|
93
121
|
# Patch the databases
|
94
122
|
@databases.each do |db_name, db|
|
@@ -120,26 +148,33 @@ module WolfTrans
|
|
120
148
|
patch_game_dat
|
121
149
|
@game_dat.dump("#{out_dir}/#{@game_dat_filename}")
|
122
150
|
|
123
|
-
#
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
FileUtils.mkdir_p(out_path)
|
151
|
+
# Patch all the maps
|
152
|
+
@maps.each do |map_name, map|
|
153
|
+
map.events.each do |event|
|
154
|
+
next unless event
|
155
|
+
event.pages.each do |page|
|
156
|
+
page.commands.each_with_index do |command, cmd_index|
|
157
|
+
context = Context::MapEvent.from_data(map_name, event, page, cmd_index, command)
|
158
|
+
patch_command(command, context)
|
159
|
+
end
|
160
|
+
end
|
134
161
|
end
|
162
|
+
# Translate path
|
163
|
+
assetpath = @assets["mapdata/#{map_name.downcase}.mps"]
|
164
|
+
fullpath = "#{out_data_dir}/#{assetpath}"
|
165
|
+
map.dump(fullpath)
|
166
|
+
end
|
135
167
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
168
|
+
# Copy remaining BasicData files
|
169
|
+
copy_data_files(Util.join_path_nocase(@game_data_dir, 'basicdata'),
|
170
|
+
['xxxxx', 'dat', 'project', 'png'],
|
171
|
+
"#{out_data_dir}/BasicData")
|
140
172
|
|
141
|
-
|
142
|
-
|
173
|
+
# Copy remaining assets
|
174
|
+
@assets.each_pair do |fn, newfn|
|
175
|
+
filename = get_asset_filename(fn)
|
176
|
+
next unless filename
|
177
|
+
FileUtils.cp(filename, "#{out_data_dir}/#{newfn}")
|
143
178
|
end
|
144
179
|
|
145
180
|
# Copy fonts
|
@@ -345,5 +380,24 @@ module WolfTrans
|
|
345
380
|
FileUtils.cp(path, "#{out_dir}/#{entry}")
|
346
381
|
end
|
347
382
|
end
|
383
|
+
|
384
|
+
# Get a full filename based on a short asset filename
|
385
|
+
def get_asset_filename(fn)
|
386
|
+
# Find the correct filename case
|
387
|
+
dirname, basename = fn.split('/')
|
388
|
+
if @patch_data_dir
|
389
|
+
path = Util.join_path_nocase(@patch_data_dir, dirname)
|
390
|
+
if path
|
391
|
+
path = Util.join_path_nocase(path, basename)
|
392
|
+
return path if path
|
393
|
+
end
|
394
|
+
end
|
395
|
+
path = Util.join_path_nocase(@game_data_dir, dirname)
|
396
|
+
if path
|
397
|
+
path = Util.join_path_nocase(path, basename)
|
398
|
+
return path if path
|
399
|
+
end
|
400
|
+
return nil
|
401
|
+
end
|
348
402
|
end
|
349
403
|
end
|
data/lib/wolftrans/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wolftrans
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mathew Velasquez
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-11-30 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A utility to translate Wolf RPG Editor games
|
14
14
|
email: mathewvq@gmail.com
|
@@ -60,7 +60,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
60
60
|
version: '0'
|
61
61
|
requirements: []
|
62
62
|
rubyforge_project:
|
63
|
-
rubygems_version: 2.
|
63
|
+
rubygems_version: 2.6.13
|
64
64
|
signing_key:
|
65
65
|
specification_version: 4
|
66
66
|
summary: A utility to translate Wolf RPG Editor games
|