comparison pytouhou/formats/ecl.py @ 112:e544f9a7966d

Add writing support to pytouhou.formats.ecl!
author Thibaut Girka <thib@sitedethib.com>
date Tue, 06 Sep 2011 22:40:45 +0200
parents 5d9052b9a4e8
children 732c64662f87
comparison
equal deleted inserted replaced
111:340fcda8e64a 112:e544f9a7966d
131 132: ('i', None), 131 132: ('i', None),
132 133: ('', None), 132 133: ('', None),
133 134: ('', None), 133 134: ('', None),
134 135: ('i', None)} #TODO 134 135: ('i', None)} #TODO
135 135
136 _main_instructions = {0: ('ffIhHHH', 'spawn_enemy'),
137 2: ('ffIhHHH', 'spawn_enemy_mirrored'),
138 4: ('ffIhHHH', 'spawn_enemy_random'),
139 6: ('ffIhHHH', 'spawn_enemy_mirrored_random'),
140 8: ('', None),
141 9: ('', None),
142 10: ('II', None),
143 12: ('', None)}
144
145
136 def __init__(self): 146 def __init__(self):
137 self.main = [] 147 self.main = []
138 self.subs = [[]] 148 self.subs = [[]]
139 149
140 150
141 @classmethod 151 @classmethod
142 def read(cls, file): 152 def read(cls, file):
143 sub_count, main_offset = unpack('<II', file.read(8)) 153 sub_count, main_offset = unpack('<II', file.read(8))
144 if file.read(8) != b'\x00\x00\x00\x00\x00\x00\x00\x00': 154 if file.read(8) != b'\x00\x00\x00\x00\x00\x00\x00\x00':
145 raise Exception #TODO 155 raise Exception #TODO
146 sub_offsets = unpack('<%s' % ('I' * sub_count), file.read(4 * sub_count)) 156 sub_offsets = unpack('<%dI' % sub_count, file.read(4 * sub_count))
147 157
148 ecl = cls() 158 ecl = cls()
149 ecl.subs = [] 159 ecl.subs = []
150 ecl.main = [] 160 ecl.main = []
151 161
195 file.seek(main_offset) 205 file.seek(main_offset)
196 while True: 206 while True:
197 time, = unpack('<H', file.read(2)) 207 time, = unpack('<H', file.read(2))
198 if time == 0xffff: 208 if time == 0xffff:
199 break 209 break
200 sub, instr_type, size = unpack('<HHH', file.read(6)) 210
211 sub, opcode, size = unpack('<HHH', file.read(6))
201 data = file.read(size - 8) 212 data = file.read(size - 8)
202 if instr_type in (0, 2, 4, 6): # Enemy spawn 213
203 args = unpack('<ffIhHHH', data) 214 if opcode in cls._main_instructions:
215 args = unpack('<%s' % cls._main_instructions[opcode][0], data)
204 else: 216 else:
205 logger.warn('unknown main opcode %d (data: %r)', instr_type, data)
206 args = (data,) 217 args = (data,)
207 ecl.main.append((time, sub, instr_type, args)) 218 logger.warn('unknown main opcode %d', opcode)
219
220 ecl.main.append((time, sub, opcode, args))
208 221
209 return ecl 222 return ecl
210 223
224
225 def write(self, file):
226 sub_count = len(self.subs)
227 sub_offsets = []
228 main_offset = 0
229
230 # Skip header, it will be written later
231 file.seek(8+8+4*sub_count)
232
233 # Write subs
234 for sub in self.subs:
235 sub_offsets.append(file.tell())
236
237 instruction_offsets = []
238 instruction_datas = []
239 for time, opcode, rank_mask, param_mask, args in sub:
240 format = self._instructions[opcode][0]
241 if format.endswith('s'):
242 args = list(args)
243 args[-1] = args[-1].encode('shift_jis')
244 format = '%s%ds' % (format[:-1], len(args[-1]))
245 format = '<IHHHH%s' % format
246 size = calcsize(format)
247 instruction_offsets.append((instruction_offsets[-1] + len(instruction_datas[-1])) if instruction_offsets else 0)
248 instruction_datas.append(pack(format, time, opcode, size, rank_mask, param_mask, *args))
249
250 #TODO: clean up this mess
251 for instruction, data, offset in zip(sub, instruction_datas, instruction_offsets):
252 time, opcode, rank_mask, param_mask, args = instruction
253 if opcode in (2, 29, 30, 31, 32, 33, 34): # relative_jump
254 frame, index = args
255 args = frame, instruction_offsets[index] - offset
256 format = '<IHHHH%s' % self._instructions[opcode][0]
257 size = calcsize(format)
258 data = pack(format, time, opcode, size, rank_mask, param_mask, *args)
259 elif opcode == 3: # relative_jump_ex
260 frame, index, counter_id = args
261 args = frame, instruction_offsets[index] - offset, counter_id
262 format = '<IHHHH%s' % self._instructions[opcode][0]
263 size = calcsize(format)
264 data = pack(format, time, opcode, size, rank_mask, param_mask, *args)
265 file.write(data)
266 file.write(b'\xff' * 6 + b'\x0c\x00\x00\xff\xff\x00')
267
268 # Write main
269 main_offset = file.tell()
270 for time, sub, opcode, args in self.main:
271 format = '<HHHH%s' % self._main_instructions[opcode][0]
272 size = calcsize(format)
273
274 file.write(pack(format, time, sub, opcode, size, *args))
275 file.write(b'\xff\xff\x04\x00')
276
277 # Patch header
278 file.seek(0)
279 file.write(pack('<IIII%dI' % sub_count, sub_count, main_offset, 0, 0, *sub_offsets))
280