wolftrans 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,12 @@
1
- require 'wolfrpg/io'
1
+ require 'stringio'
2
2
 
3
3
  module WolfRpg
4
4
  class GameDat
5
+ attr_reader :legacy
6
+ alias_method :legacy?, :legacy
7
+
5
8
  attr_accessor :unknown1
9
+ attr_accessor :unknown4
6
10
  attr_accessor :title
7
11
  attr_accessor :unknown2
8
12
  attr_accessor :font
@@ -12,65 +16,123 @@ module WolfRpg
12
16
  attr_accessor :unknown3
13
17
 
14
18
  def initialize(filename)
15
- File.open(filename, 'rb') do |file|
16
- IO.verify(file, MAGIC_NUMBER)
19
+ FileCoder.open(filename, :read) do |coder|
20
+ if (first_byte = coder.read_byte) == 0
21
+ @legacy = false
22
+ coder.verify(MAGIC_NUMBER)
23
+ else
24
+ @legacy = true
25
+ @seeds = Array.new(3)
26
+ @xseeds = Array.new(3)
27
+ @seeds[0] = first_byte
28
+ coder.skip(1) # garbage
29
+ @xseeds[0] = coder.read_byte
30
+ @xseeds[1] = coder.read_byte
31
+ @xseeds[2] = coder.read_byte
32
+ coder.skip(1) # garbage
33
+ @seeds[2] = coder.read_byte
34
+ coder.skip(1) # garbage
35
+ @seeds[1] = coder.read_byte
36
+ coder.skip(1) # garbage
37
+ coder = FileCoder.new(StringIO.new(crypt(coder.read)))
38
+ end
39
+
17
40
  #TODO what is most of the junk in this file?
18
- @unknown1 = IO.read(file, 25)
41
+ unknown1_size = coder.read_int
42
+ @unknown1 = coder.read(unknown1_size)
43
+ @unknown4 = coder.read_int
19
44
 
20
- @title = IO.read_string(file)
21
- if (magic_string = IO.read_string(file)) != MAGIC_STRING
45
+ @title = coder.read_string
46
+ if (magic_string = coder.read_string) != MAGIC_STRING
22
47
  raise "magic string invalid (got #{magic_string})"
23
48
  end
24
49
 
25
- unknown2_size = IO.read_int(file)
26
- @unknown2 = IO.read(file, unknown2_size)
50
+ unknown2_size = coder.read_int
51
+ @unknown2 = coder.read(unknown2_size)
27
52
 
28
- #IO.dump(file, 64)
29
- #abort
30
- @font = IO.read_string(file)
53
+ @font = coder.read_string
31
54
  @subfonts = Array.new(3)
32
55
  @subfonts.each_index do |i|
33
- @subfonts[i] = IO.read_string(file)
56
+ @subfonts[i] = coder.read_string
34
57
  end
35
58
 
36
- @default_pc_graphic = IO.read_string(file)
37
- @version = IO.read_string(file)
59
+ @default_pc_graphic = coder.read_string
60
+ @version = coder.read_string
38
61
 
39
62
  # This is the size of the file minus one.
40
63
  # We don't need it, so discard it.
41
- file.seek(4, :CUR)
64
+ coder.skip(4)
42
65
 
43
66
  # We don't care about the rest of this file for translation
44
67
  # purposes.
45
68
  # Someday we will know what the hell is stored in here... But not today.
46
- @unknown3 = file.read
69
+ @unknown3 = coder.read
47
70
  end
48
71
  end
49
72
 
50
73
  def dump(filename)
51
- File.open(filename, 'wb') do |file|
52
- IO.write(file, MAGIC_NUMBER)
53
- IO.write(file, @unknown1)
54
- IO.write_string(file, @title)
55
- IO.write_string(file, MAGIC_STRING)
56
- IO.write_int(file, @unknown2.bytesize)
57
- IO.write(file, @unknown2)
58
- IO.write_string(file, @font)
74
+ begin
75
+ if @legacy
76
+ coder = FileCoder.new(StringIO.new('', 'wb'))
77
+ else
78
+ coder = FileCoder.open(filename, :write)
79
+ coder.write_byte(0)
80
+ coder.write(MAGIC_NUMBER)
81
+ end
82
+
83
+ coder.write_int(@unknown1.size)
84
+ coder.write(@unknown1)
85
+ coder.write_int(@unknown4)
86
+ coder.write_string(@title)
87
+ coder.write_string(MAGIC_STRING)
88
+ coder.write_int(@unknown2.bytesize)
89
+ coder.write(@unknown2)
90
+ coder.write_string(@font)
59
91
  @subfonts.each do |subfont|
60
- IO.write_string(file, subfont)
92
+ coder.write_string(subfont)
93
+ end
94
+ coder.write_string(@default_pc_graphic)
95
+ coder.write_string(@version)
96
+ coder.write_int(coder.tell + 4 + @unknown3.bytesize - 1 + (@legacy ? 10 : 0))
97
+ coder.write(@unknown3)
98
+
99
+ if @legacy
100
+ data = crypt(coder.io.string)
101
+ FileCoder.open(filename, :write) do |coder|
102
+ coder.write_byte(@seeds[0])
103
+ coder.write_byte(0) # garbage
104
+ coder.write_byte(@xseeds[0])
105
+ coder.write_byte(@xseeds[1])
106
+ coder.write_byte(@xseeds[2])
107
+ coder.write_byte(0) # garbage
108
+ coder.write_byte(@seeds[2])
109
+ coder.write_byte(0) # garbage
110
+ coder.write_byte(@seeds[1])
111
+ coder.write_byte(0) # garbage
112
+ coder.write(data)
113
+ end
114
+ end
115
+ ensure
116
+ coder.close
117
+ end
118
+ end
119
+
120
+ def crypt(data_str)
121
+ data = data_str.unpack('C*')
122
+ @seeds.each_with_index do |seed, s|
123
+ (0...data.size).step(DECRYPT_INTERVALS[s]) do |i|
124
+ seed = (seed * 0x343FD + 0x269EC3) & 0xFFFFFFFF
125
+ data[i] ^= (seed >> 28) & 7
61
126
  end
62
- IO.write_string(file, @default_pc_graphic)
63
- IO.write_string(file, @version)
64
- IO.write_int(file, file.tell + 4 + @unknown3.bytesize - 1)
65
- IO.write(file, @unknown3)
66
127
  end
128
+ return data.pack('C*')
67
129
  end
68
130
 
69
131
  private
70
132
  MAGIC_NUMBER = [
71
- 0x00, 0x57, 0x00, 0x00, 0x4f, 0x4c, 0x00, 0x46, 0x4d, 0x00,
72
- 0x15, 0x00, 0x00, 0x00, # likely an integer
133
+ 0x57, 0x00, 0x00, 0x4f, 0x4c, 0x00, 0x46, 0x4d, 0x00
73
134
  ].pack('C*')
74
135
  MAGIC_STRING = "0000-0000" # who knows what this is supposed to be
136
+ DECRYPT_INTERVALS = [1, 2, 5]
75
137
  end
76
138
  end
@@ -1,7 +1,3 @@
1
- require 'wolfrpg/io'
2
- require 'wolfrpg/route'
3
- require 'wolfrpg/command'
4
-
5
1
  module WolfRpg
6
2
  class Map
7
3
  attr_reader :tileset_id
@@ -14,48 +10,48 @@ module WolfRpg
14
10
 
15
11
  def initialize(filename)
16
12
  @filename = File.basename(filename, '.*')
17
- File.open(filename, 'rb') do |file|
18
- IO.verify(file, MAGIC_NUMBER)
13
+ FileCoder.open(filename, :read) do |coder|
14
+ coder.verify(MAGIC_NUMBER)
19
15
 
20
- @tileset_id = IO.read_int(file)
16
+ @tileset_id = coder.read_int
21
17
 
22
18
  # Read basic data
23
- @width = IO.read_int(file)
24
- @height = IO.read_int(file)
25
- @events = Array.new(IO.read_int(file))
19
+ @width = coder.read_int
20
+ @height = coder.read_int
21
+ @events = Array.new(coder.read_int)
26
22
 
27
23
  # Read tiles
28
24
  #TODO: interpret this data later
29
- @tiles = IO.read(file, @width * @height * 3 * 4)
25
+ @tiles = coder.read(@width * @height * 3 * 4)
30
26
 
31
27
  # Read events
32
- while (indicator = IO.read_byte(file)) == 0x6F
33
- event = Event.new(file)
28
+ while (indicator = coder.read_byte) == 0x6F
29
+ event = Event.new(coder)
34
30
  @events[event.id] = event
35
31
  end
36
32
  if indicator != 0x66
37
33
  raise "unexpected event indicator: #{indicator.to_s(16)}"
38
34
  end
39
- unless file.eof?
35
+ unless coder.eof?
40
36
  raise "file not fully parsed"
41
37
  end
42
38
  end
43
39
  end
44
40
 
45
41
  def dump(filename)
46
- File.open(filename, 'wb') do |file|
47
- IO.write(file, MAGIC_NUMBER)
48
- IO.write_int(file, @tileset_id)
49
- IO.write_int(file, @width)
50
- IO.write_int(file, @height)
51
- IO.write_int(file, @events.size)
52
- IO.write(file, @tiles)
42
+ FileCoder.open(filename, :write) do |coder|
43
+ coder.write(MAGIC_NUMBER)
44
+ coder.write_int(@tileset_id)
45
+ coder.write_int(@width)
46
+ coder.write_int(@height)
47
+ coder.write_int(@events.size)
48
+ coder.write(@tiles)
53
49
  @events.each do |event|
54
50
  next unless event
55
- IO.write_byte(file, 0x6F)
56
- event.dump(file)
51
+ coder.write_byte(0x6F)
52
+ event.dump(coder)
57
53
  end
58
- IO.write_byte(file, 0x66)
54
+ coder.write_byte(0x66)
59
55
  end
60
56
  end
61
57
 
@@ -94,19 +90,19 @@ module WolfRpg
94
90
  attr_accessor :y
95
91
  attr_accessor :pages
96
92
 
97
- def initialize(file)
98
- IO.verify(file, MAGIC_NUMBER1)
99
- @id = IO.read_int(file)
100
- @name = IO.read_string(file)
101
- @x = IO.read_int(file)
102
- @y = IO.read_int(file)
103
- @pages = Array.new(IO.read_int(file))
104
- IO.verify(file, MAGIC_NUMBER2)
93
+ def initialize(coder)
94
+ coder.verify(MAGIC_NUMBER1)
95
+ @id = coder.read_int
96
+ @name = coder.read_string
97
+ @x = coder.read_int
98
+ @y = coder.read_int
99
+ @pages = Array.new(coder.read_int)
100
+ coder.verify(MAGIC_NUMBER2)
105
101
 
106
102
  # Read pages
107
103
  page_id = 0
108
- while (indicator = IO.read_byte(file)) == 0x79
109
- page = Page.new(file, page_id)
104
+ while (indicator = coder.read_byte) == 0x79
105
+ page = Page.new(coder, page_id)
110
106
  @pages[page_id] = page
111
107
  page_id += 1
112
108
  end
@@ -115,21 +111,21 @@ module WolfRpg
115
111
  end
116
112
  end
117
113
 
118
- def dump(file)
119
- IO.write(file, MAGIC_NUMBER1)
120
- IO.write_int(file, @id)
121
- IO.write_string(file, @name)
122
- IO.write_int(file, @x)
123
- IO.write_int(file, @y)
124
- IO.write_int(file, @pages.size)
125
- IO.write(file, MAGIC_NUMBER2)
114
+ def dump(coder)
115
+ coder.write(MAGIC_NUMBER1)
116
+ coder.write_int(@id)
117
+ coder.write_string(@name)
118
+ coder.write_int(@x)
119
+ coder.write_int(@y)
120
+ coder.write_int(@pages.size)
121
+ coder.write(MAGIC_NUMBER2)
126
122
 
127
123
  # Write pages
128
124
  @pages.each do |page|
129
- IO.write_byte(file, 0x79)
130
- page.dump(file)
125
+ coder.write_byte(0x79)
126
+ page.dump(coder)
131
127
  end
132
- IO.write_byte(file, 0x70)
128
+ coder.write_byte(0x70)
133
129
  end
134
130
 
135
131
  class Page
@@ -150,77 +146,77 @@ module WolfRpg
150
146
  attr_accessor :collision_width
151
147
  attr_accessor :collision_height
152
148
 
153
- def initialize(file, id)
149
+ def initialize(coder, id)
154
150
  @id = id
155
151
 
156
152
  #TODO ???
157
- @unknown1 = IO.read_int(file)
153
+ @unknown1 = coder.read_int
158
154
 
159
155
  #TODO further abstract graphics options
160
- @graphic_name = IO.read_string(file)
161
- @graphic_direction = IO.read_byte(file)
162
- @graphic_frame = IO.read_byte(file)
163
- @graphic_opacity = IO.read_byte(file)
164
- @graphic_render_mode = IO.read_byte(file)
156
+ @graphic_name = coder.read_string
157
+ @graphic_direction = coder.read_byte
158
+ @graphic_frame = coder.read_byte
159
+ @graphic_opacity = coder.read_byte
160
+ @graphic_render_mode = coder.read_byte
165
161
 
166
162
  #TODO parse conditions later
167
- @conditions = IO.read(file, 1 + 4 + 4*4 + 4*4)
163
+ @conditions = coder.read(1 + 4 + 4*4 + 4*4)
168
164
  #TODO parse movement options later
169
- @movement = IO.read(file, 4)
165
+ @movement = coder.read(4)
170
166
 
171
167
  #TODO further abstract flags
172
- @flags = IO.read_byte(file)
168
+ @flags = coder.read_byte
173
169
 
174
170
  #TODO further abstract flags
175
- @route_flags = IO.read_byte(file)
171
+ @route_flags = coder.read_byte
176
172
 
177
173
  # Parse move route
178
- @route = Array.new(IO.read_int(file))
174
+ @route = Array.new(coder.read_int)
179
175
  @route.each_index do |i|
180
- @route[i] = RouteCommand.create(file)
176
+ @route[i] = RouteCommand.create(coder)
181
177
  end
182
178
 
183
179
  # Parse commands
184
- @commands = Array.new(IO.read_int(file))
180
+ @commands = Array.new(coder.read_int)
185
181
  @commands.each_index do |i|
186
- @commands[i] = Command.create(file)
182
+ @commands[i] = Command.create(coder)
187
183
  end
188
- IO.verify(file, COMMANDS_TERMINATOR)
184
+ coder.verify(COMMANDS_TERMINATOR)
189
185
 
190
186
  #TODO abstract these options later
191
- @shadow_graphic_num = IO.read_byte(file)
192
- @collision_width = IO.read_byte(file)
193
- @collision_height = IO.read_byte(file)
187
+ @shadow_graphic_num = coder.read_byte
188
+ @collision_width = coder.read_byte
189
+ @collision_height = coder.read_byte
194
190
 
195
- if (terminator = IO.read_byte(file)) != 0x7A
191
+ if (terminator = coder.read_byte) != 0x7A
196
192
  raise "page terminator not 7A (found #{terminator.to_s(16)})"
197
193
  end
198
194
  end
199
195
 
200
- def dump(file)
201
- IO.write_int(file, @unknown1)
202
- IO.write_string(file, @graphic_name)
203
- IO.write_byte(file, @graphic_direction)
204
- IO.write_byte(file, @graphic_frame)
205
- IO.write_byte(file, @graphic_opacity)
206
- IO.write_byte(file, @graphic_render_mode)
207
- IO.write(file, @conditions)
208
- IO.write(file, @movement)
209
- IO.write_byte(file, @flags)
210
- IO.write_byte(file, @route_flags)
211
- IO.write_int(file, @route.size)
196
+ def dump(coder)
197
+ coder.write_int(@unknown1)
198
+ coder.write_string(@graphic_name)
199
+ coder.write_byte(@graphic_direction)
200
+ coder.write_byte(@graphic_frame)
201
+ coder.write_byte(@graphic_opacity)
202
+ coder.write_byte(@graphic_render_mode)
203
+ coder.write(@conditions)
204
+ coder.write(@movement)
205
+ coder.write_byte(@flags)
206
+ coder.write_byte(@route_flags)
207
+ coder.write_int(@route.size)
212
208
  @route.each do |cmd|
213
- cmd.dump(file)
209
+ cmd.dump(coder)
214
210
  end
215
- IO.write_int(file, @commands.size)
211
+ coder.write_int(@commands.size)
216
212
  @commands.each do |cmd|
217
- cmd.dump(file)
213
+ cmd.dump(coder)
218
214
  end
219
- IO.write(file, COMMANDS_TERMINATOR)
220
- IO.write_byte(file, @shadow_graphic_num)
221
- IO.write_byte(file, @collision_width)
222
- IO.write_byte(file, @collision_height)
223
- IO.write_byte(file, 0x7A)
215
+ coder.write(COMMANDS_TERMINATOR)
216
+ coder.write_byte(@shadow_graphic_num)
217
+ coder.write_byte(@collision_width)
218
+ coder.write_byte(@collision_height)
219
+ coder.write_byte(0x7A)
224
220
  end
225
221
 
226
222
  COMMANDS_TERMINATOR = [
@@ -1,25 +1,25 @@
1
1
  module WolfRpg
2
2
  class RouteCommand
3
- def self.create(file)
3
+ def self.create(coder)
4
4
  # Read all data for this movement command from file
5
- id = IO.read_byte(file)
6
- args = Array.new(IO.read_byte(file))
5
+ id = coder.read_byte
6
+ args = Array.new(coder.read_byte)
7
7
  args.each_index do |i|
8
- args[i] = IO.read_int(file)
8
+ args[i] = coder.read_int
9
9
  end
10
- IO.verify(file, TERMINATOR)
10
+ coder.verify(TERMINATOR)
11
11
 
12
12
  #TODO Create proper route command
13
13
  return RouteCommand.new(id, args)
14
14
  end
15
15
 
16
- def dump(file)
17
- IO.write_byte(file, @id)
18
- IO.write_byte(file, @args.size)
16
+ def dump(coder)
17
+ coder.write_byte(@id)
18
+ coder.write_byte(@args.size)
19
19
  @args.each do |arg|
20
- IO.write_int(file, arg)
20
+ coder.write_int(arg)
21
21
  end
22
- IO.write(file, TERMINATOR)
22
+ coder.write(TERMINATOR)
23
23
  end
24
24
 
25
25
  attr_accessor :id