changeset 561:9afaa1969d6f

Level format 2 support * * * Allow for blank author * * * Fix thinko in write code
author Neil Muller <drnlmuller@gmail.com>
date Tue, 18 Oct 2011 11:41:28 +0200
parents a85993b00fd7
children 8473936c8884
files mamba/constants.py mamba/level.py setup.py
diffstat 3 files changed, 88 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/mamba/constants.py	Mon Oct 17 18:02:49 2011 +0200
+++ b/mamba/constants.py	Tue Oct 18 11:41:28 2011 +0200
@@ -1,5 +1,12 @@
 from pygame.locals import K_ESCAPE, K_q, K_BACKSPACE, K_DELETE
 
+# version tuple for maps
+# NB: We only compare on the first two elements of the version when loading
+# levels - this is so levels saved by later point releases are loadable by
+# older versions. So changing the level format (new sprite, etc.) is not
+# acceptable in a point release
+VERSION = (0, 2, 0)
+
 # Display constants
 SCREEN = (800, 600)
 EDIT_SCREEN = (1000, 600)
--- a/mamba/level.py	Mon Oct 17 18:02:49 2011 +0200
+++ b/mamba/level.py	Tue Oct 18 11:41:28 2011 +0200
@@ -6,7 +6,7 @@
 from pygame.surface import Surface
 from pygame.sprite import RenderUpdates
 
-from mamba.constants import UP, DOWN, LEFT, RIGHT
+from mamba.constants import UP, DOWN, LEFT, RIGHT, VERSION
 from mamba.data import load_file
 from mamba import sprites
 
@@ -93,8 +93,70 @@
         self.level_name = level_name
         self.level_namespace = level_namespace
         self.source = source
+        self.author = ''
         self.load_level_data()
 
+    def load_format_1(self, level_data):
+        """Load the original map format"""
+        self.name = level_data[0].strip()
+        tileset_name = level_data[1].strip()
+        self.tileset = Tileset(tileset_name)
+        self.background_track = level_data[2].strip()
+        tiles_ascii = [line.strip() for line in level_data[3:]]
+        try:
+            end = tiles_ascii.index("end")
+        except ValueError:
+            raise InvalidMapError('Missing "end" marker in level')
+        sprites_ascii = tiles_ascii[end + 1:]
+        tiles_ascii = tiles_ascii[:end]
+        self.tiles_ascii = tiles_ascii
+        self.sprites_ascii = sprites_ascii
+
+    def load_format_2(self, level_data):
+        """Load the second mamba map format"""
+        try:
+            self.name = level_data[1].split('Name:', 1)[1].strip()
+            tileset_name = level_data[3].split('Tileset:', 1)[1].strip()
+            self.background_track = level_data[4].split('Music:', 1)[1].strip()
+        except IndexError:
+            raise InvalidMapError('Incorrectly formatted map header')
+        try:
+            # Missing author isn't fatal
+            self.author = level_data[2].split('Author:', 1)[1].strip()
+        except IndexError:
+            self.author = ''
+        self.tileset = Tileset(tileset_name)
+        tiles_ascii = [line.strip() for line in level_data[5:]]
+        try:
+            end = tiles_ascii.index("end")
+        except ValueError:
+            raise InvalidMapError('Missing "end" marker in level')
+        sprites_ascii = tiles_ascii[end + 1:]
+        tiles_ascii = tiles_ascii[:end]
+        self.tiles_ascii = tiles_ascii
+        self.sprites_ascii = sprites_ascii
+
+    def check_format(self, level_data):
+        """Determine which format to load"""
+        if (level_data[0].startswith('Version: ') and
+                level_data[3].startswith('Tileset: ')):
+            # Looks like a version 2 level file
+            file_version = level_data[0].split('Version: ', 1)[1].strip()
+            try:
+                file_version = tuple([int(x) for x in file_version.split('.')])
+                # We only compare on the first two elements, so point
+                # rleases work as expected
+                if file_version[:2] <= VERSION:
+                    return 2
+                else:
+                    raise InvalidMapError("Unsupported map version")
+            except ValueError:
+                raise InvalidMapError("Unrecognised map version")
+        else:
+            # We assume anything we don't recognise is format 0 and rely on the
+            # error checking there to save us if we're wrong.
+            return 1
+
     def load_level_data(self):
         """
         This file format is potentially yucky.
@@ -103,20 +165,17 @@
             level_data = StringIO(self.source)
         else:
             level_data = load_file('levels/%s.txt' % (self.level_name,))
-        self.name = level_data.readline().strip()
-        tileset_name = level_data.readline().strip()
-        self.tileset = Tileset(tileset_name)
-        self.background_track = level_data.readline().strip()
-        tiles_ascii = [line.strip() for line in level_data.readlines()]
-        try:
-            end = tiles_ascii.index("end")
-        except ValueError:
-            raise InvalidMapError('Missing "end" marker in level')
-        sprites_ascii = tiles_ascii[end + 1:]
-        tiles_ascii = tiles_ascii[:end]
-        self.tiles_ascii = tiles_ascii
-        self.sprites_ascii = sprites_ascii
-        self.setup_level(tiles_ascii, sprites_ascii)
+        # XXX: Should we have some size restriction here?
+        level_data = level_data.readlines()
+        level_format = self.check_format(level_data)
+        if level_format == 2:
+            self.load_format_2(level_data)
+        elif level_format == 1:
+            self.load_format_1(level_data)
+        else:
+            # generic fallback
+            raise InvalidMapError("Unrecognised map version")
+        self.setup_level(self.tiles_ascii, self.sprites_ascii)
         self.make_background()
 
     def validate_level(self):
@@ -136,9 +195,11 @@
                 level_dir = 'levels'
             file_path = '%s/%s.txt' % (level_dir, self.level_name)
             save_file = load_file(file_path, 'wb', is_user_dir=is_user_dir)
-        save_file.write('%s\n' % self.name)
-        save_file.write('%s\n' % self.tileset.name)
-        save_file.write('%s\n' % self.background_track)
+        save_file.write('Version: %d.%d\n' % VERSION[:2])
+        save_file.write('Name: %s\n' % self.name)
+        save_file.write('Author: %s\n' % self.author)
+        save_file.write('Tileset: %s\n' % self.tileset.name)
+        save_file.write('Music: %s\n' % self.background_track)
         self.update_tiles_ascii()
         for tile_row in self.tiles_ascii:
             save_file.write('%s\n' % tile_row)
--- a/setup.py	Mon Oct 17 18:02:49 2011 +0200
+++ b/setup.py	Tue Oct 18 11:41:28 2011 +0200
@@ -11,7 +11,8 @@
 except ImportError:
     pass
 
-VERSION_STR = "0.1"
+# This should probably be pulled from constants.py
+VERSION_STR = "0.2"
 
 setup(   # Metadata
             name="mutable-mamba",