Mercurial > touhou
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 |