# boktai1_checksum_fix.py -rw-r--r-- 1.4 KiB View raw
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#!/usr/bin/env python3
# Boktai 1 checksum fixer
# Usage: python3 boktai1_checksum_fix.py SAVEGAME.SaveRAM

import struct
import sys

# Memory blocks that are checksummed, array of (start, length) pairs, in bytes
BLOCKS = [
    (0x0000, 0x18),
    (0x00c0, 0x28),
    (0x0200, 0x28),
    (0x0340, 0x400),
    (0x0780, 0x418),
    (0x0dc0, 0x400),
    (0x1200, 0x418),
    (0x1840, 0x168),
    (0x1a40, 0x168),
]

# Calculates checksum of xs, an array of uint16_t's. Returns 4 uint16_t's.
def checksum(xs):
    ck_add = 0
    ck_xor = 0
    for x in xs:
        ck_add = (ck_add + x) & 0xffff
        ck_xor ^= x

    return [
        # Constant
        0xffff,
        # Number of bytes in this block
        len(xs)*2,
        # All halfwords folded with addition
        ck_add,
        # All halfwords folded with XOR
        ck_xor,
    ]

if len(sys.argv) < 2:
    print("Usage: python3 " + sys.argv[0] + " SAVEGAME.SaveRAM")
    sys.exit(1)

with open(sys.argv[1], "r+b") as f:
    for start, length in BLOCKS:
        f.seek(start)
        block = f.read(length)
        # The save is an array of big-endian halfwords, so we use > to convert
        # to native endianess when reading and writing
        halfwords = struct.iter_unpack(">H", block)
        check = checksum([x[0] for x in halfwords])
        for c in check:
            f.write(struct.pack(">H", c))
print("OK")