# HG changeset patch # User Adrianna PiƄska # Date 1316210969 -7200 # Node ID ab77047aca691e602c8193f14ccba4a57db52e78 # Parent 21caf90f604ea37d519e13498ae566bf31838334# Parent 17865fe52f1ad6f6d12795fc8c6f48bd44242448 resolved diff -r 17865fe52f1a -r ab77047aca69 data/levels/dev.txt --- 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 diff -r 17865fe52f1a -r ab77047aca69 data/levels/index.txt --- 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 diff -r 17865fe52f1a -r ab77047aca69 data/levels/puzzle.txt --- /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 diff -r 17865fe52f1a -r ab77047aca69 data/tiles/lab/button.png Binary file data/tiles/lab/button.png has changed diff -r 17865fe52f1a -r ab77047aca69 data/tiles/lab/closed_gate.png Binary file data/tiles/lab/closed_gate.png has changed diff -r 17865fe52f1a -r ab77047aca69 mamba/__main__.py --- 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() diff -r 17865fe52f1a -r ab77047aca69 mamba/constants.py --- 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 } diff -r 17865fe52f1a -r ab77047aca69 mamba/gamestate.py --- 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] != '#': diff -r 17865fe52f1a -r ab77047aca69 mamba/habitats/editor.py --- 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') diff -r 17865fe52f1a -r ab77047aca69 mamba/habitats/level.py --- 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 diff -r 17865fe52f1a -r ab77047aca69 mamba/habitats/levelmenu.py --- 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 diff -r 17865fe52f1a -r ab77047aca69 mamba/habitats/mainmenu.py --- 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): diff -r 17865fe52f1a -r ab77047aca69 mamba/habitats/userlevelmenu.py --- 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) diff -r 17865fe52f1a -r ab77047aca69 mamba/level.py --- 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): diff -r 17865fe52f1a -r ab77047aca69 mamba/options.py --- 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() diff -r 17865fe52f1a -r ab77047aca69 mamba/sprites.py --- 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'