changeset 365:ab77047aca69

resolved
author Adrianna Pińska <adrianna.pinska@gmail.com>
date Sat, 17 Sep 2011 00:09:29 +0200
parents 21caf90f604e (diff) 17865fe52f1a (current diff)
children d759f49c477d
files data/levels/index.txt
diffstat 16 files changed, 159 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
--- a/data/levels/dev.txt	Sat Sep 17 00:08:07 2011 +0200
+++ b/data/levels/dev.txt	Sat Sep 17 00:09:29 2011 +0200
@@ -34,3 +34,5 @@
 end
 10, 10: TunnelSprite t1 t2 east
 20, 10: TunnelSprite t2 t1 west
+38, 3: GateSprite t4 
+11, 6: ButtonSprite t3 t4
--- a/data/levels/index.txt	Sat Sep 17 00:08:07 2011 +0200
+++ b/data/levels/index.txt	Sat Sep 17 00:09:29 2011 +0200
@@ -5,4 +5,5 @@
 elements
 noms
 arrows
+puzzle
 seriesoftubes
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/levels/puzzle.txt	Sat Sep 17 00:09:29 2011 +0200
@@ -0,0 +1,34 @@
+Puzzle Level
+lab
+test.ogg
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+X...M.............m..............b.....X
+X.......m.......M........mm............X
+X..XXXXXXXXXXXXXXXXX.............@.....X
+X..X.......X&......X...........m.......X
+XM.X...b...X.......X.M.....M...m.y.M...X
+X..X......>>>......X..XXXXXXXXXXXXXXXXXX
+X..Rl..r..>>>..s.ylY..X................X
+X..X......>>>......X..X.........M..m...X
+X.mX...y...X.......X..X...M....M...m...X
+X..X......&X.......X.mX...MMM..M.MM....X
+X..XXXXXXXXXXXXXXXXX..X........M..MM...X
+XM.X.......X&......X..X........M....m..X
+X..X...b...X.......XM.XXXXX...m.mmm....X
+X..X......~~~......X..R$$$>.mmm........E
+X..Bl..r..~~~..@.rlR..R$$$>.......MM...X
+X.mX......~~~......X..R$$$>...M..m...M.X
+X..X...y...X.......X..XXXXX...m..m..m..X
+X.MX......&X.......X..X................X
+X..XXXXXXXXXXXXXXXXX..X......M.........X
+X..X.......X&......Xm.X.....MM..mm.....X
+X..X...b...X.......X..X..mmm.....~~~...X
+X..X......$$$......X.MX..m.m....~~~~~~~X
+X..Yl..r..$$$..f.blB..X....M...~~~~~~~~X
+XM.X......$$$......X..X.......~~~~~~~~~X
+X..X...y...X.......X..X....m..~~~~~~~~~X
+Xm.X......&X.......X..X...m...~~~~~~~~~X
+X..XXXXXXXXXXXXXXXXXm.X.......~~~~~~~~~X
+X.........M...M.......X........~~~~~~~~X
+XeXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+end
Binary file data/tiles/lab/button.png has changed
Binary file data/tiles/lab/closed_gate.png has changed
--- a/mamba/__main__.py	Sat Sep 17 00:08:07 2011 +0200
+++ b/mamba/__main__.py	Sat Sep 17 00:09:29 2011 +0200
@@ -10,6 +10,8 @@
 from mamba.gamestate import load_state, load_levels
 from mamba.sound import SoundSystem
 from mamba.habitats.mainmenu import MainMenu
+from mamba.habitats.levelmenu import LevelMenu
+from mamba.habitats.userlevelmenu import UserLevelApi
 from mamba.habitats.level import LevelHabitat
 from mamba.habitats.editor import EditorHabitat
 from mamba.level import Level
@@ -31,9 +33,14 @@
     load_levels()
 
     if options.edit:
-        start = EditorHabitat(Level(options.level))
+        start = EditorHabitat(Level(options.level, 'official'))
     elif options.level is not None:
-        start = LevelHabitat(Level(options.level))
+        start = LevelHabitat(Level(options.level, 'official'),
+                             LevelMenu.go_menu)
+    elif options.uncurated is not None:
+        api = UserLevelApi("uncurated")
+        start = LevelHabitat(api.get_level(options.uncurated),
+                             sys.exit)
     else:
         start = MainMenu()
 
--- a/mamba/constants.py	Sat Sep 17 00:08:07 2011 +0200
+++ b/mamba/constants.py	Sat Sep 17 00:09:29 2011 +0200
@@ -39,6 +39,7 @@
     'debug': False,
     'sound': True,
     'level': None,
+    'uncurated': None,
     'edit': False,
     'save_location': None,  # Determined by a function in options
 }
--- a/mamba/gamestate.py	Sat Sep 17 00:08:07 2011 +0200
+++ b/mamba/gamestate.py	Sat Sep 17 00:09:29 2011 +0200
@@ -14,21 +14,18 @@
 
 
 def level_done(level_name):
-    assert level_name in levels
     done_levels.add(level_name)
     save_state()
 
 
 def load_state():
-    global done_levels
+    done_levels.clear()
     fn = os.path.join(options.save_location, 'gamestate.json')
     if os.access(fn, os.R_OK):
         f = open(fn, 'r')
         state = json.load(f)
         f.close()
-        done_levels = set(state['done_levels'])
-    else:
-        done_levels = set((0,))
+        done_levels.update(state['done_levels'])
 
 
 def save_state():
@@ -43,9 +40,8 @@
 
 
 def load_levels():
-    global levels
     f = open(filepath('levels/index.txt'))
-    levels = []
+    del levels[:]
     for line in f.readlines():
         line = line.strip()
         if line and line[0] != '#':
--- a/mamba/habitats/editor.py	Sat Sep 17 00:08:07 2011 +0200
+++ b/mamba/habitats/editor.py	Sat Sep 17 00:09:29 2011 +0200
@@ -201,6 +201,10 @@
             message = MessageBox((300, 300), 'Please enter a name')
         elif self.level.level_name in RESERVED_NAMES:
             message = MessageBox((300, 300), 'Reserved level name')
+        try:
+            self.level.validate_level()
+        except InvalidMapError, error:
+            message = MessageBox((300, 300), "Map isn't valid\n%s" % error)
         if message:
             self.container.paused = True
             self.container.add(message)
@@ -230,7 +234,7 @@
 
     def load_level(self, ev, widget, level_name):
         try:
-            new_level = Level(level_name)
+            new_level = Level(level_name, 'official')
         except (IOError, InvalidMapError, pygame.error), error:
             message = MessageBox((300, 300),
                     'Loading Level Failed: %s' % error, color='red')
--- a/mamba/habitats/level.py	Sat Sep 17 00:08:07 2011 +0200
+++ b/mamba/habitats/level.py	Sat Sep 17 00:09:29 2011 +0200
@@ -32,5 +32,5 @@
                                 self.go_menu)
         self.container.add(messagebox)
         messagebox.grab_focus()
-        level_done(self.world.level.level_name)
+        level_done(self.world.level.unique_name())
         return True
--- a/mamba/habitats/levelmenu.py	Sat Sep 17 00:08:07 2011 +0200
+++ b/mamba/habitats/levelmenu.py	Sat Sep 17 00:09:29 2011 +0200
@@ -12,6 +12,8 @@
 
 class LevelMenu(Habitat):
 
+    level_namespace = 'official'
+
     def __init__(self):
         super(LevelMenu, self).__init__()
         self.level_buttons = {}
@@ -22,7 +24,7 @@
             level = self.get_level(name)
             button = LevelButton((20 + 120 * (i % WIDTH),
                                   20 + 120 * (i // WIDTH)),
-                                 level, done=name in done_levels)
+                                 level)
             button.add_callback('clicked', self.level_selected, name)
             container.add(button)
             self.level_buttons[name] = button
@@ -34,11 +36,11 @@
         return levels
 
     def get_level(self, name):
-        return Level(name)
+        return Level(name, self.level_namespace)
 
     def update_buttons(self):
-        for name, button in self.level_buttons.iteritems():
-            button.done = name in done_levels
+        for button in self.level_buttons.itervalues():
+            button.done = button.level.unique_name() in done_levels
 
     def level_selected(self, ev, widget, name):
         from mamba.habitats.level import LevelHabitat
--- a/mamba/habitats/mainmenu.py	Sat Sep 17 00:08:07 2011 +0200
+++ b/mamba/habitats/mainmenu.py	Sat Sep 17 00:09:29 2011 +0200
@@ -47,7 +47,7 @@
 
     def edit_event(self, ev, widget):
         from mamba.habitats.editor import EditorHabitat
-        NewHabitatEvent.post(EditorHabitat(Level('dev')))
+        NewHabitatEvent.post(EditorHabitat(Level('dev', 'official')))
         return True
 
     def quit_keydown_event(self, ev, widget):
--- a/mamba/habitats/userlevelmenu.py	Sat Sep 17 00:08:07 2011 +0200
+++ b/mamba/habitats/userlevelmenu.py	Sat Sep 17 00:09:29 2011 +0200
@@ -7,39 +7,58 @@
 import urllib2
 
 
-class UserLevelMenu(LevelMenu):
+class UserLevelApi(object):
 
-    LEVEL_SERVER_URL = LEVEL_SERVER + "curated/"
-    TIMEOUT = 5.0  # in seconds
-    CACHE = {}
+    def __init__(self, ctype, url=LEVEL_SERVER, timeout=5):
+        assert ctype in ("curated", "uncurated")
+        assert url.endswith("/")
+        self.ctype = ctype
+        self.level_namespace = ctype
+        self.url = url
+        self.timeout = timeout
+        self.cache = {}
 
-    @classmethod
-    def _url_data(cls, route):
-        url = "%s%s" % (cls.LEVEL_SERVER_URL, route)
-        return urllib2.urlopen(url, timeout=cls.TIMEOUT).read()
+    def _url_data(self, route):
+        url = "%s%s/%s" % (self.url, self.ctype, route)
+        return urllib2.urlopen(url, timeout=self.timeout).read()
 
-    @classmethod
-    def _populate_cache(cls):
+    def _populate_level(self, name):
         try:
-            data = cls._url_data("index")
+            source = self._url_data("level/%s" % name)
+            level = Level(name, self.level_namespace, source)
+        except:
+            print "Failed to download online level %r" % name
+            return
+        self.cache[name] = level
+
+    def _populate_cache(self):
+        try:
+            data = self._url_data("index")
         except:
             print "Failed to download online level index."
             return
         levels = [x.strip() for x in data.splitlines()]
 
         for name in levels:
-            try:
-                source = cls._url_data("level/%s" % name)
-                level = Level(name, source)
-            except:
-                print "Failed to download online level %r" % name
-                continue
-            cls.CACHE[level] = level
+            self._populate_level(name)
 
     def list_levels(self):
-        if not self.CACHE:
+        if not self.cache:
             self._populate_cache()
-        return self.CACHE.keys()
+        return self.cache.keys()
 
     def get_level(self, name):
-        return self.CACHE[name]
+        if name not in self.cache:
+            self._populate_level(name)
+        return self.cache[name]
+
+
+class UserLevelMenu(LevelMenu):
+
+    API = UserLevelApi("curated")
+
+    def list_levels(self):
+        return self.API.list_levels()
+
+    def get_level(self, name):
+        return self.API.get_level(name)
--- a/mamba/level.py	Sat Sep 17 00:08:07 2011 +0200
+++ b/mamba/level.py	Sat Sep 17 00:09:29 2011 +0200
@@ -89,8 +89,9 @@
 
 
 class Level(object):
-    def __init__(self, level_name, source=None):
+    def __init__(self, level_name, level_namespace, source=None):
         self.level_name = level_name
+        self.level_namespace = level_namespace
         self.source = source
         self.load_level_data()
 
@@ -118,6 +119,16 @@
         self.setup_level(tiles_ascii, sprites_ascii)
         self.make_background()
 
+    def validate_level(self):
+        old_tiles_ascii = self.tiles_ascii[:]
+        old_tiles = self.tiles[:]
+        try:
+            self.update_tiles_ascii()
+            self.setup_tiles(self.tiles_ascii)
+        finally:
+            self.tiles = old_tiles
+            self.tiles_ascii = old_tiles_ascii
+
     def save_level(self):
         """Save the current state of the level"""
         save_file = load_file('levels/%s.txt' % (self.level_name,), 'wb')
@@ -131,6 +142,9 @@
         for sprite_ascii in self.sprites_ascii:
             save_file.write('%s\n' % sprite_ascii)
 
+    def unique_name(self):
+        return '/'.join((self.level_namespace, self.level_name))
+
     def update_tiles_ascii(self):
         """Resync tiles and tile_ascii"""
         for i, tile_row in enumerate(self.tiles):
--- a/mamba/options.py	Sat Sep 17 00:08:07 2011 +0200
+++ b/mamba/options.py	Sat Sep 17 00:09:29 2011 +0200
@@ -44,6 +44,9 @@
                 dest="level", help="Initial level")
         parser.add_option('--edit', action="store_true", default=False,
                 dest="edit", help="Edit given level")
+        parser.add_option("--uncurated", type="str", default=None,
+                dest="uncurated", help="Load uncurated level "
+                                       "from the web by name.")
 
     opts, _ = parser.parse_args(args)
 
@@ -52,6 +55,7 @@
 
     if options.debug:
         options.set_option('level', opts.level)
+        options.set_option('uncurated', opts.uncurated)
         options.set_option('edit', opts.edit)
 
     options.finalize()
--- a/mamba/sprites.py	Sat Sep 17 00:08:07 2011 +0200
+++ b/mamba/sprites.py	Sat Sep 17 00:09:29 2011 +0200
@@ -243,6 +243,43 @@
             head.shift_tile_and_pixels((other.tile_pos, self.direction))
 
 
+class ButtonSprite(SingleImageTileSprite):
+    image_name = 'button'
+    name = 'button'
+    tileset = 'lab'
+
+    def __init__(self, other_id):
+        super(ButtonSprite, self).__init__(tile_char=None)
+        self.other_id = other_id
+
+    def interact(self, world, segment):
+        head = world.snake.head
+        if segment is head:
+            other = world.get_sprite(self.other_id)
+            other.button_pushed()
+
+
+class GateSprite(SingleImageTileSprite):
+    closed_name = 'closed_gate'
+    open_image = 'floor'
+    name = 'gate'
+    tileset = 'lab'
+
+    def __init__(self):
+        self.image_name = self.closed_name
+        self.opened = False
+        super(GateSprite, self).__init__(tile_char=None)
+
+    def get_solid(self, snake, segment):
+        return not self.opened
+
+    def button_pushed(self):
+        self.opened = True
+        # Update image
+        self.image_name = self.open_image
+        self.image = self.load_image(self.image_name, mutators=())
+
+
 class PuddleSprite(SingleImageTileSprite):
     image_name = 'puddle'
     name = 'puddle'