comparison pytouhou/formats/t6rp.py @ 188:008f90ebfdc0

Fix replay handling and add support for encrypted replays
author Thibaut Girka <thib@sitedethib.com>
date Thu, 27 Oct 2011 14:24:07 +0200
parents 46793ccfedca
children ba3297ab3bde
comparison
equal deleted inserted replaced
187:46793ccfedca 188:008f90ebfdc0
11 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ## GNU General Public License for more details. 12 ## GNU General Public License for more details.
13 ## 13 ##
14 14
15 from struct import unpack 15 from struct import unpack
16 from io import BytesIO
17
18 from pytouhou.utils.random import Random
16 from pytouhou.utils.helpers import read_string 19 from pytouhou.utils.helpers import read_string
17 20
18 from pytouhou.utils.helpers import get_logger 21 from pytouhou.utils.helpers import get_logger
19 22
20 logger = get_logger(__name__) 23 logger = get_logger(__name__)
21 24
22 25
23 class Level(object): 26 class Level(object):
24 def __init__(self): 27 def __init__(self):
28 self.score = 0
29 self.random_seed = 0
30
31 self.power = 0
32 self.lives = 2
33 self.bombs = 3
34 self.difficulty = 16
25 self.keys = [] 35 self.keys = []
26 36
27 37
28 class T6RP(object): 38 class T6RP(object):
29 def __init__(self): 39 def __init__(self):
40 self.version = 0x102
41 self.character = 0
42 self.rank = 0
43 self.key = 0
30 self.levels = [] 44 self.levels = []
31 45
32 46
33 @classmethod 47 @classmethod
34 def read(cls, file): 48 def read(cls, file, decrypt=True, verify=True):
35 if file.read(4) != b'T6RP': 49 if file.read(4) != b'T6RP':
36 raise Exception
37 if file.read(2) != b'\x02\x01':
38 raise Exception 50 raise Exception
39 51
40 replay = cls() 52 replay = cls()
41 53
42 replay.character, replay.rank, checksum, unknown, key, unknown = unpack('<BBHIBB', file.read(10)) 54 replay.version, replay.character, replay.rank = unpack('<HBB', file.read(4))
55 checksum, replay.unknown1, replay.unknown2, replay.key = unpack('<IBBB', file.read(7))
56
57 # Decrypt data
58 if decrypt:
59 decrypted_file = BytesIO()
60 file.seek(0)
61 decrypted_file.write(file.read(15))
62 decrypted_file.write(b''.join(chr((ord(c) - replay.key - 7*i) & 0xff) for i, c in enumerate(file.read())))
63 file = decrypted_file
64 file.seek(15)
65
66 # Verify checksum
67 if verify:
68 data = file.read()
69 file.seek(15)
70 if checksum != (sum(ord(c) for c in data) + 0x3f000318 + replay.key) & 0xffffffff:
71 raise Exception #TODO
72
73 replay.unknown3 = unpack('<B', file.read(1))
43 replay.date = read_string(file, 9, 'ascii') 74 replay.date = read_string(file, 9, 'ascii')
44 replay.name = read_string(file, 9, 'ascii').rstrip() 75 replay.name = read_string(file, 9, 'ascii').rstrip()
45 unknown, replay.score, unknown, replay.slowdown, unknown = unpack('<HIIfI', file.read(18)) 76 replay.unknown4, replay.score, replay.unknown5, replay.slowdown, replay.unknown6 = unpack('<HIIfI', file.read(18))
46 77
47 stages_offsets = unpack('<7I', file.read(28)) 78 stages_offsets = unpack('<7I', file.read(28))
48 79
49 replay.levels = [] 80 replay.levels = []
50 81
51 for offset in stages_offsets: 82 for offset in stages_offsets:
52 replay.levels.append(None)
53
54 if offset == 0: 83 if offset == 0:
55 continue 84 continue
56 85
57 level = Level() 86 level = Level()
58 replay.levels[-1] = level 87 replay.levels.append(level)
59 88
60 file.seek(offset) 89 file.seek(offset)
61 level.score, level.random_seed, unknown, level.power, level.lives, level.bombs, level.difficulty, unknown = unpack('<IHHBbbBI', file.read(16)) 90 (level.score, level.random_seed, level.unknown1, level.power,
91 level.lives, level.bombs, level.difficulty, level.unknown2) = unpack('<IHHBbbBI', file.read(16))
62 92
63 while True: 93 while True:
64 time, keys, unknown = unpack('<IHH', file.read(8)) 94 time, keys, unknown = unpack('<IHH', file.read(8))
65 95
66 if time == 9999999: 96 if time == 9999999:
67 break 97 break
68 98
69 level.keys.append((time, keys)) 99 level.keys.append((time, keys, unknown))
70 100
101 return replay