Can read general data (with player & turn number, etc)
2 files changed, 45 insertions(+), 3 deletions(-)

M player.py
M result.py
M player.py +41 -2
@@ 5,6 5,7 @@ Classes for reading player data such as 
 # Disable pylint warnings caused by fields not being explicity defined
 # pylint: disable=W0201,E0203
 
+import os
 import struct
 from common import PlanetsData
 

          
@@ 146,9 147,9 @@ class ShipXY(PlanetsData):
     @classmethod
     def load(cls, data, count=None):
         result = super(ShipXY, cls).load(data, count)
-        # Remove empty objects from result (mass = 0 and owner = 0)
+        # Remove empty objects from result (owner = 0 and mass = 0)
         for key in result.keys():
-            if not result[key].mass and not result[key].owner:
+            if not result[key].owner and not result[key].mass:
                 del result[key]
         return result
 

          
@@ 196,6 197,44 @@ class Target(PlanetsData):
             result[key].fix()
         return result
 
+def read_general(f, from_result=True):
+    """Reads general turn data found in RST and GENx.DAT files"""
+    result = {}
+    # Timestamp
+    (result['timestamp_date'], result['timestamp_time'], ) = struct.unpack(
+        '< 10s 8s', f.read(18))
+    # Score
+    result['score'] = {}
+    for i in range(0, 11):
+        player = i+1
+        result['score'][player] = {}
+        (result['score'][player]['planets'],
+         result['score'][player]['warships'],
+         result['score'][player]['freighters'],
+         result['score'][player]['starbases'],) = struct.unpack('< h h h h',
+                                                                f.read(8))
+    # Player
+    (result['player'],) = struct.unpack('< h', f.read(2))
+    # Password
+    result['password'] = ''
+    (data,) = struct.unpack('< 20s', f.read(20))
+    for i in range(0, 10):
+        result['password'] += chr(ord(data[i]) - ord(data[19-i]) + 32)
+    result['password'].decode('latin1').encode('utf8').rstrip()
+    # Skip unused WORD value
+    if not from_result:
+        f.seek(1, os.SEEK_CUR)
+    # Checksums
+    (result['checksum_ship'], result['checksum_planet'],
+     result['checksum_base'],) = struct.unpack('< iii', f.read(12))
+    # Skip "new password" flag (WORD) and value (10 bytes)
+    if not from_result:
+        f.seek(12, os.SEEK_CUR)
+    # Turn number & timestamp checksum
+    (result['turn'], result['checksum_timestamp'],)  = struct.unpack('< hh',
+                                                                     f.read(4))
+    return result
+
 def read_messages(f):
     """Reads and returns list of messages found in RST and MDATAx.DAT files"""
     result = {}

          
M result.py +4 -1
@@ 3,7 3,8 @@ Functions for reading and parsing RST (r
 """
 
 import struct
-from player import Base, Planet, Ship, ShipXY, Target, read_messages
+from player import (Base, Planet, Ship, ShipXY, Target,
+                    read_general, read_messages)
 
 class InvalidResultFile(Exception):
     """Exception raised when the RST file is invalid or corrupt"""

          
@@ 29,6 30,8 @@ def read(f, filesize):
     result['messages'] = read_messages(f)
     f.seek(pointers['shipxy'])
     result['shipxy'] = ShipXY.read(f)
+    f.seek(pointers['general'])
+    result['general'] = read_general(f)
     return result
     
 def _valid_pointer(pointer, filesize, datasize):