#!/usr/bin/env python3 # injectDriver.py - write a 4096-byte $E000 opponent-module image into a copy of the Modem Wars disk. # # python3 injectDriver.py # # The module occupies track 18 sector 7 ($E000-$E0FF, stored in the clear because the loader never # encrypts track 18) followed by track 34 sectors 1-15 ($E100-$EFFF, stored with the EA sector cipher). import sys, os SECTORS_PER_TRACK = [21]*17 + [19]*7 + [18]*6 + [17]*5 # tracks 1..35 def trackOffset(track): return sum(SECTORS_PER_TRACK[:track-1]) * 256 def sectorOffset(track, sector): return trackOffset(track) + sector * 256 def encryptSector(track, sector, plain): """The cipher the drive code applies at $0531; track 18 is stored in the clear.""" if track == 18: return bytes(plain) a = (track | 0xC0) << 1 carry = (a >> 8) & 1 a &= 0xFF a = a + sector + carry carry = (a >> 8) & 1 a &= 0xFF out = bytearray(256) key = 0 for y in range(256): if y != 0: a = y ^ key newCarry = (a >> 7) & 1 a = ((a << 1) | carry) & 0xFF carry = newCarry key = a out[y] = plain[y] ^ key return bytes(out) # where each page of the module lives on the disk def placement(): places = [(18, 7)] # $E000-$E0FF places += [(34, s) for s in range(1, 16)] # $E100-$EFFF return places def main(): modulePath, inPath, outPath = sys.argv[1], sys.argv[2], sys.argv[3] module = open(modulePath, "rb").read() if len(module) != 4096: raise SystemExit(f"module must be exactly 4096 bytes, got {len(module)}") image = bytearray(open(inPath, "rb").read()) if len(image) < 174848: raise SystemExit("not a 35-track .d64") for i, (track, sector) in enumerate(placement()): plain = module[i*256:(i+1)*256] off = sectorOffset(track, sector) image[off:off+256] = encryptSector(track, sector, plain) open(outPath, "wb").write(image) print(f"wrote {outPath}: module installed in track 18 sector 7 and track 34 sectors 1-15") if __name__ == "__main__": main()