# HG changeset patch # User Gerard Krijgsman # Date 1347483757 -7200 # Wed Sep 12 23:02:37 2012 +0200 # Node ID 9a20923e1767ddf64908e4a53b8c6212cd7a14e8 # Parent 2e045d286c1d22ed3f57242411d1ec1abb3de635 Can generate valid empty TRN file (with no commands) diff --git a/common.py b/common.py --- a/common.py +++ b/common.py @@ -4,6 +4,9 @@ import struct +SIGNATURE = 'VER3.5' +SUBVERSION = ('00', '01',) + class PlanetsData(object): """Base class for all Planets data objects""" FILENAME = None # Default filename @@ -102,4 +105,11 @@ f = open(name,'rb') result = cls.read(f, has_count, count) f.close() - return result \ No newline at end of file + return result + +def get_checksum(data): + """Calculates the sum of all individual bytes in the data string""" + result = 0 + for i in range(0, len(data)): + result += ord(data[i]) + return result \ No newline at end of file diff --git a/result.py b/result.py --- a/result.py +++ b/result.py @@ -3,6 +3,7 @@ """ import struct +from common import SIGNATURE, SUBVERSION from player import (Base, Planet, Ship, ShipXY, Target, read_general, read_messages) @@ -67,13 +68,11 @@ def _get_version(f, filesize): """Analyses RST file to determine if it is DOS-style or WinPlan-style""" - SIGNATURE = 'VER3.5' - VERSIONS = ('00', '01',) TARGETSIG = ('1211', '1120',) # Check first signature (SIGNATURE) at location +32 of RST file f.seek(32) (signature, version, pointer) = struct.unpack('< 6s 2s i', f.read(12)) - if (signature != SIGNATURE) or (version not in VERSIONS): + if (signature != SIGNATURE) or (version not in SUBVERSION): return None, None # Fix BASIC style pointer pointer = int(pointer) - 1 diff --git a/turn.py b/turn.py new file mode 100644 --- /dev/null +++ b/turn.py @@ -0,0 +1,158 @@ +""" +Functions for generating TRN (turn) files. +""" + +import struct +import random +from common import SIGNATURE, SUBVERSION, get_checksum + +CLIENT = 'VGA Planets v3.x library for Python' +URL = 'http://github.com/ghdpro/planets' + +# VPH35.DLL magic numbers, taken from PCC v2's "trn.cc" source file +VPH_MAGIC = (1585242373, + 458484639, 1702713875, 2131768570, 943874411, 1531045611, + 622829488, 660770929, 473301358, 1868910709, 439267666, 1259778247, + 187160419, 205520992, 1162432602, 2048525217, 663275107, 1945076761, + 1912495862, 372583676, 2110506768, 972564220, 1627953855, 1696231547, + 1825551059, 690525357, 1425805634, 1273009202, 1643106825, 1033503714, + 1773067018, 1444056607, 841306782, 1311137219, 472310692, 1658228604, + 214806212, 1638334074, 870981249, 1438230436, 1722981495, 383237037, + 1014208183, 1950729749, 1381216466, 1149684732, 1475271197, 990158844, + 659846975, 131158828, 1269952134, 1929873739, 149943298, 94038386, + 1639179540, 519578396, 649680371, 2139806121, 48126387, 1820750093, + 2002158429, 834011058, 127330762, 1341047341, 45011247, 1210785240, + 102394054, 1033444233, 1452787209, 1636216880, 2001004855, 196571844, + 768753436, 1715639759, 9036553, 550413001, 1195957868, 566073290, + 1386247611, 725117880, 637842515, 782679024, 614960412, 1259473924, + 710893647, 137748852, 808495109, 1174108532, 2141228605, 1298353301, + 1989952843, 607318838, 1868217839, 2046567417, 1297732528, 886928938, + 533473933, 667670866, 1241783877, 1634258231, 1529167548, 1048674755, + 108553737, 442206379, 1427828321, 178793040, 57025576, 1886069810, + 1452681265, 392872129, 1749094387, 1931946557, 610131601, 497923660, + 800378618, 833787008, 1047995126, 867114247, 108316439, 1889137816, + 1566927898, 1606954817, 2129997452, 176508207, 1504084876, 781656333, + 1575411145, 952282888, 1920012969, 725392878, 442033280, 2055008888, + 125996860, 648896510, 1271579722, 734745843, 457213090, 101154514, + 1253209494, 649313503, 665663012, 1284757233, 526008074, 1128559135, + 708376521, 1888247159, 637430572, 1297014774, 84473586, 1938406737, + 278055502, 2082329430, 784004382, 886858342, 487519681, 979889529, + 2118032563, 376523135, 2037399162, 494383465, 1744352698, 533745717, + 752066469, 1518627158, 347571084, 1270232880, 460005993, 1754379254, + 1431354806, 103810045, 676346171, 948969734, 1270441550, 562587328, + 305781542, 48494333, 263492952, 1020466270, 190108896, 1009887493, + 1263640424, 2136294797, 951195719, 1154885409, 533815976, 707619918, + 1293089160, 1565561820, 1424862457, 2024541688, 1849356050, 804648133, + 1041775421, 1752468846, 2051572786, 749910457, 1708669854, 1592915884, + 1123095599, 1460717743, 1948843781, 1082061162, 1152635918, + 1881839283, 760734026, 1910315568, 1258782923, 2051380841, 1725205147, + 585278536, 1106219491, 444629203, 1099824661, 734821072, 2025557656, + 657473172, 255537853, 291983710, 286553905, 42517818, 670349676, + 870581336, 1127381655, 1839475352, 632654867, 547547534, 1471914002, + 1512583684, 890892484, 1857789058, 1587065657, 709203658, 1447182906, + 950862839, 1854232374, 1589606089, 18301536, 700074959, 415606342, + 1405416566, 1289157530, 1227135268, 340764183, 419122630, 1884968096, + 326246210, 540566661, 853062096, 1975701318, 1492562570, 1963382636, + 1075710563, 758982437, 2060895641, 1152739182, 1371354866, 800770398, + 1598945131, 79563287, 694771023, 1704620086, 248109047, 95128540, + 1062172273, 810095152, 2013227291, 1998220334, 1498632230, 1836447618, + 217773428, 986641406, 603013591, 1230144401, 1075426659, 1746848829, + 817629711, 186988432, 1484074762, 843442591, 776096924, 1024866700, + 2027642148, 1049701698, 247896996, 387855251, 857506062, 165410039, + 1748384075, 1958279260, 1593211160, 1998805368, 1633675306, + 2048559498, 1569149953, 1404385053, 784606841, 1589733669, 373455454, + 909199500, 1312922206, 408034973, 997233876, 963117498, 742951874, + 10752697, 574771227, 794412355, 92609016, 392712605, 964282276, + 1732686549) + +def make_turn(general, reginfo, commands): + """Generate complete TRN (turn) file""" + result = '' + # Player + result += struct.pack('< h', general['player']) + # No. of commands + result += struct.pack('< i', len(commands)) + # Timestamp + result += general['timestamp_date'] + general['timestamp_time'] + # Unused + result += struct.pack('< h', 0) + # Timestamp checksum + checksum_timestamp = get_checksum(general['timestamp_date'] + + general['timestamp_time']) + result += struct.pack('< h', checksum_timestamp) + # Include commands (if any) + if len(commands): + # Unused + result += '\x00' + # Build pointer + command blocks + pointers = '' + data = '' + for command in commands: + pointers += struct.pack('< i', len(data)) + data += command + result += pointers + data + # Win-Plan style TRN trailer + result += _get_winplan_trailer(general['turn'], reginfo) + # DOS style TRN trailer follows + checksum_x = get_checksum(result) + (checksum_timestamp * 3) + 13 + result += struct.pack('< i i', checksum_x, 0) + checksum = 0 + for i in range(0, 25): + value = (ord(reginfo[0][i]) * (i+1) * 13) + result += struct.pack('< i', value) + checksum += value + for i in range(0, 25): + value = (ord(reginfo[1][i]) * (i+1) * 13) + result += struct.pack('< i', value) + checksum += value + result += struct.pack('< i', checksum + 668) + # ID block (checksum from TRN file for specific player) + for i in range(0, 11): + if i+1 == general['player']: + result += struct.pack('< i', checksum_x) + elif i+1 == 11: # Oddity when player isn't player 11 + result += struct.pack('< i', int('0x0F31', 0)) + else: + result += struct.pack('< i', 0) + return result + +def get_registration(serial=None, date=None): + """Returns registration data""" + if serial is None: + # Set shareware string + serial = 'VGA Planets shareware' + date = 'V3.5 for windows' + else: + serial = serial.encode('latin1') + date = date.encode('latin1') + return (serial.ljust(25), date.ljust(25), + CLIENT.ljust(50), URL.ljust(50)) + +def _get_winplan_trailer(turn, reginfo): + """Assembles WinPlan-style TRN (turn) file trailer""" + result = SIGNATURE + SUBVERSION[1] + # VPH35.DLL values (encoded similarly as in PCC v2's GTurnfile::setRegInfo) + random.seed() + vph1 = VPH_MAGIC[turn % len(VPH_MAGIC)] + vph2 = random.randint(0, 65535) + vph2 |= random.randint(0, 65535) + vph1 ^= vph2 + vph1 &= int('0x7FFFFFFF', 0) + vph2 &= int('0x7FFFFFFF', 0) + result += struct.pack('< i i', vph1, vph2) + # Registration info + serial_partb = '' + date_partb = '' + for i in range(0, 25): + serial_partb += chr(random.randint(0, 255)) + date_partb += chr(random.randint(0, 255)) + serial_parta = '' + date_parta = '' + for i in range(0, 25): + serial_parta += chr(ord(reginfo[0][i]) ^ ord(serial_partb[i])) + date_parta += chr(ord(reginfo[1][i]) ^ ord(date_partb[i])) + result += serial_parta + serial_partb + date_parta + date_partb + result += reginfo[2] + reginfo[3] + # Unused buffer of 100 bytes + result += '\x00'*100 + return result \ No newline at end of file