# HG changeset patch # User Simon Cross # Date 1259357300 0 # Node ID 0667189a5973873bc5d5fe9466bbdced9b17a573 # Parent 452cde9af2a2b540b92a851a3e87e1f21c4f9005 New load level dialog. diff -r 452cde9af2a2 -r 0667189a5973 gamelib/engine.py --- a/gamelib/engine.py Fri Nov 27 21:18:18 2009 +0000 +++ b/gamelib/engine.py Fri Nov 27 21:28:20 2009 +0000 @@ -9,7 +9,6 @@ import constants import mainmenu import helpscreen -import loadlevel import level from misc import check_exit @@ -20,14 +19,13 @@ self.level = level.Level(level_name) self._open_window = None self.gameboard = None - self.level_loader = None def tick(self): """Tic toc.""" pygame.time.wait(10) - def load_new_level(self): - self.level = self.level_loader.cur_level + def load_new_level(self, new_level): + self.level = new_level def open_window(self, window): """Open a widget as the main window.""" @@ -42,9 +40,9 @@ self.level) self.open_window(self.gameboard.get_top_widget()) - def switch_gameboard(self, gameboard): + def switch_gameboard(self, new_gameboard): """Switch over to a new gameboard.""" - self.gameboard = gameboard + self.gameboard = new_gameboard self.gameboard.disp = self.main_app self.gameboard.create_display() self.open_window(self.gameboard.get_top_widget()) @@ -52,7 +50,6 @@ def set_main_menu(self): """Open the main menu""" self.scoreboard = gameover.ScoreTable(self.level) - self.level_loader = None main_menu = mainmenu.make_main_menu(self.level) self.open_window(main_menu) @@ -61,11 +58,6 @@ help_screen = helpscreen.make_help_screen(self.level) self.open_window(help_screen) - def set_level_screen(self): - """Open the Load Level screen""" - level_screen, self.level_loader = loadlevel.make_load_screen(self.level) - self.open_window(level_screen) - def create_game_over(self): """Create and open the Game Over window""" level = self.gameboard.level @@ -93,8 +85,6 @@ return DayState(self.game) elif events_equal(e, GO_HELP_SCREEN): return HelpScreenState(self.game) - elif events_equal(e, GO_LEVEL_SCREEN): - return LevelScreenState(self.game) elif e.type is KEYDOWN: if e.key == K_ESCAPE: return Quit(self.game) @@ -103,6 +93,9 @@ return DayState(self.game) elif e.key == K_i: return HelpScreenState(self.game) + elif e.type is DO_LOAD_LEVEL: + self.game.load_new_level(e.level) + return elif e.type is DO_LOAD_SAVEGAME: self.game.switch_gameboard(e.gameboard) e.gameboard.skip_next_start_day() @@ -142,32 +135,6 @@ pygame.display.update(update) -class LevelScreenState(State): - def init(self): - sound.stop_background_music() - self.game.set_level_screen() - - def event(self, e): - if e.type is KEYDOWN and e.key == K_ESCAPE: - return MainMenuState(self.game) - elif events_equal(e, GO_MAIN_MENU): - return MainMenuState(self.game) - elif events_equal(e, DO_LOAD_LEVEL): - self.game.load_new_level() - return MainMenuState(self.game) - elif e.type is not QUIT: - self.game.main_app.event(e) - - def paint(self, screen): - screen.fill((0,0,0)) - self.game.main_app.paint(screen) - pygame.display.flip() - - def update(self, screen): - update = self.game.main_app.update(screen) - pygame.display.update(update) - - class DayState(State): def init(self): """Add some chickens to the farm""" @@ -329,12 +296,11 @@ START_NIGHT = pygame.event.Event(USEREVENT, name="START_NIGHT") GO_MAIN_MENU = pygame.event.Event(USEREVENT, name="GO_MAIN_MENU") GO_HELP_SCREEN = pygame.event.Event(USEREVENT, name="GO_HELP_SCREEN") -GO_LEVEL_SCREEN = pygame.event.Event(USEREVENT, name="GO_LEVEL_SCREEN") -DO_LOAD_LEVEL = pygame.event.Event(USEREVENT, name="DO_LEVEL_SCREEN") FAST_FORWARD = pygame.event.Event(USEREVENT, name="FAST_FORWARD") MOVE_FOX_ID = USEREVENT + 1 MOVE_FOXES = pygame.event.Event(MOVE_FOX_ID, name="MOVE_FOXES") DO_LOAD_SAVEGAME = USEREVENT + 2 +DO_LOAD_LEVEL = USEREVENT + 3 QUIT = pygame.event.Event(QUIT) # Due to the way pgu's loop timing works, these will only get proceesed diff -r 452cde9af2a2 -r 0667189a5973 gamelib/loadlevel.py --- a/gamelib/loadlevel.py Fri Nov 27 21:18:18 2009 +0000 +++ b/gamelib/loadlevel.py Fri Nov 27 21:28:20 2009 +0000 @@ -4,98 +4,88 @@ import os import pygame import level -import engine import data -import imagecache import gameboard import constants -def make_load_screen(level): - """Create a screen for selecting the levels""" - load_screen = LoadScreen(level, width=600) - c = LoadContainer(align=0, valign=0) - c.add(load_screen, 0, 0) - - return c, load_screen +class LoadLevelDialog(gui.Dialog): + """Load level dialog.""" -class LoadContainer(gui.Container): - def paint(self, s): - pygame.display.set_caption('Load Level') - splash = imagecache.load_image("images/splash.png", ["lighten_most"]) - pygame.display.get_surface().blit(splash, (0, 0)) - gui.Container.paint(self, s) + def __init__(self, curr_level, load_func, cls="dialog"): + self.value = None + self.levels = self._populate_levels() -class LoadScreen(gui.Document): - def __init__(self, start_level, **params): - gui.Document.__init__(self, **params) + self.main_style = { + 'width': 300, 'height': 350 + } - self.levels = [] - self.cur_level = None - for name in os.listdir(data.filepath('levels/')): - if name.endswith('.conf'): - try: - this_level = level.Level(name) - except RuntimeError: - continue # Skip levels that fail to load - if os.path.exists(this_level.map): - # Skip level if we can't see the map - self.levels.append(this_level) - if this_level.level_name == start_level.level_name: - self.cur_level = this_level + td_style = { + 'padding_left': 4, + 'padding_right': 4, + 'padding_top': 2, + 'padding_bottom': 2, + } - if not self.cur_level: - self.cur_level = self.levels[0] + self.level_list = gui.List(**self.main_style) + level_names = self.levels.keys() + level_names.sort() + for name in level_names: + self.level_list.add(name, value=name) + self.level_list.set_vertical_scroll(0) + self.level_list.connect(gui.CHANGE, self._level_list_change) + self.image_container = gui.Container() - def done_pressed(): - pygame.event.post(engine.DO_LOAD_LEVEL) + button_ok = gui.Button("Load Level") + button_ok.connect(gui.CLICK, self._click_ok) + + button_cancel = gui.Button("Cancel") + button_cancel.connect(gui.CLICK, self._click_cancel) - def cancel_pressed(): - pygame.event.post(engine.GO_MAIN_MENU) - - def next_pressed(): - self.next_level() - - def prev_pressed(): - self.prev_level() + body = gui.Table() + body.tr() + list_style = dict(self.main_style) + list_style.update(td_style) + body.td(self.level_list, style=list_style, valign=-1, rowspan=2) + body.td(self.image_container, style=td_style, colspan=2) + body.tr() + # putting in the extra spacer squashes the ok and cancel button + # up nicely + body.td(gui.Spacer(0, 0), style=td_style) + body.td(button_ok, style=td_style, align=1) + body.td(button_cancel, style=td_style, align=1) - self.next_button = gui.Button("Next Level >>") - self.next_button.connect(gui.CLICK, next_pressed) - - self.prev_button = gui.Button("<< Prev Level") - self.prev_button.connect(gui.CLICK, prev_pressed) + title = gui.Label("Load Level ...", cls=cls + ".title.label") + gui.Dialog.__init__(self, title, body) - self.cancel_button = gui.Button("Cancel") - self.cancel_button.connect(gui.CLICK, cancel_pressed) - - self.done_button = gui.Button("Load This Level") - self.done_button.connect(gui.CLICK, done_pressed) - - self.render_level() + if curr_level.level_name in self.levels: + self.level_list.group.value = curr_level.level_name + elif level_names: + self.level_list.group.value = level_names[0] - - def next_level(self): - pos = self.levels.index(self.cur_level) + 1 - if pos == len(self.levels): - pos = 0 - self.cur_level = self.levels[pos] - self.render_level() + self.connect(gui.CHANGE, self._load_level, load_func) - def prev_level(self): - pos = self.levels.index(self.cur_level) - 1 - if pos == -1: - pos = len(self.levels) - 1 - self.cur_level = self.levels[pos] - self.render_level() + def _populate_levels(self): + """Read list of levels from disk.""" + levels = {} + for name in os.listdir(data.filepath('levels/')): + if not name.endswith('.conf'): + continue + try: + this_level = level.Level(name) + except RuntimeError: + # Skip levels that fail to load + continue + if not os.path.exists(this_level.map): + # Skip level if we can't see the map + continue + levels[this_level.level_name] = (this_level, None) + return levels - def render_level(self): - self.clear() - self.repaint() - - board = gameboard.GameBoard(None, self.cur_level) - - space = self.style.font.size(" ") + def _create_image_widget(self, curr_level): + """Create an image showing the contents of level file.""" + board = gameboard.GameBoard(None, curr_level) w, h = board.tv.size map_image = pygame.Surface((constants.TILE_DIMENSIONS[0] * w, @@ -104,35 +94,62 @@ board.tv.paint(map_image) style = { - 'width' : min(300, 7*w), - 'height' : min(300, 7*h), - } + 'width' : min(300, 7*w), + 'height' : min(300, 7*h), + } + + doc = gui.Document(style=self.main_style) + space = doc.style.font.size(" ") + + doc.block(align=0) + doc.add(gui.Image(map_image, style=style)) - image = gui.Image(map_image, style=style) + doc.block(align=0) + doc.add(gui.Label(curr_level.level_name, style={ + 'border_bottom': 1, + 'margin_bottom': 5, + 'margin_top': 5, + })) - self.block(align=0) - self.add(image) + doc.block(align=0) + for word in curr_level.goal.split(): + doc.add(gui.Label(word)) + doc.space(space) + + return doc + + def _level_list_change(self): + for w in self.image_container.widgets: + self.image_container.remove(w) - self.block(align=-1) - self.add(gui.Label(self.cur_level.level_name)) - self.block(align=-1) - for word in self.cur_level.goal.split(): - self.add(gui.Label(word)) - self.space(space) + name = self.level_list.value + curr_level, widget = self.levels[name] + if widget is None: + widget = self._create_image_widget(curr_level) + self.levels[name] = (curr_level, widget) + + self.image_container.add(widget, 0, 0) + + def _click_ok(self): + self.value = self.level_list.value + if self.value: + self.send(gui.CHANGE) + self.close() - self.block(align=0) - # NB: pgu 's layout engine is sensitive to ordering here - self.add(self.prev_button, align=-1) - self.add(self.next_button, align=1) - self.add(self.done_button) - self.add(self.cancel_button) + def _click_cancel(self): + self.value = None + self.send(gui.CHANGE) + self.close() - def clear(self): - """Clear the document""" - for widget in self.widgets[:]: - self.remove(widget) - self.layout._widgets = [] - self.layout.init() + def _load_level(self, load_func): + level = self.get_level() + if level is not None: + load_func(level) + + def get_level(self): + if self.value is None: + return None + return self.levels[self.value][0] diff -r 452cde9af2a2 -r 0667189a5973 gamelib/mainmenu.py --- a/gamelib/mainmenu.py Fri Nov 27 21:18:18 2009 +0000 +++ b/gamelib/mainmenu.py Fri Nov 27 21:28:20 2009 +0000 @@ -7,6 +7,7 @@ import imagecache import gameboard import savegame +import loadlevel def make_main_menu(level): """Create a main menu""" @@ -31,6 +32,7 @@ def __init__(self, level, **params): gui.Table.__init__(self, **params) self.mode = None + self.level_name = level.level_name def fullscreen_toggled(): pygame.display.toggle_fullscreen() @@ -42,7 +44,11 @@ pygame.event.post(engine.START_DAY) def choose_level(): - pygame.event.post(engine.GO_LEVEL_SCREEN) + def load_func(new_level): + pygame.event.post(pygame.event.Event(engine.DO_LOAD_LEVEL, level=new_level)) + self.level_name = new_level.level_name + self.redraw() + loadlevel.LoadLevelDialog(level, load_func).open() def load_game(): savegame.RestoreDialog(gameboard.GameBoard.restore_game).open() @@ -63,10 +69,10 @@ self.tr() self.td(change_button, **td_kwargs) - start_button = gui.Button(level.level_name) - start_button.connect(gui.CLICK, start_game) + self.start_button = gui.Button(level.level_name) + self.start_button.connect(gui.CLICK, start_game) self.tr() - self.td(start_button, **td_kwargs) + self.td(self.start_button, **td_kwargs) loadgame_button = gui.Button('Restore Game') loadgame_button.connect(gui.CLICK, load_game) @@ -90,3 +96,6 @@ self.tr() self.td(quit_button, **td_kwargs) + + def redraw(self): + self.start_button.value = self.level_name