view pyntnclick/main.py @ 599:2d2ea51b73ad pyntnclick

Move menu.py and endscreen.py to gamelib. Add default versions for new games
author Neil Muller <neil@dip.sun.ac.za>
date Sat, 11 Feb 2012 18:46:19 +0200
parents c1b5e982809b
children fabce47e542f
line wrap: on
line source

'''Game main module.

Contains the entry point used by the run_game.py script.

'''

# Albow looks for stuff in os.path[0], which isn't always where it expects.
# The following horribleness fixes this.
import sys
import os.path
right_path = os.path.dirname(os.path.dirname(__file__))
sys.path.insert(0, right_path)
from optparse import OptionParser

import pygame
from pygame.locals import SWSURFACE
from albow.shell import Shell

from pyntnclick.gamescreen import GameScreen, DefMenuScreen, DefEndScreen
from pyntnclick.constants import GameConstants, DEBUG_ENVVAR
from pyntnclick.resources import Resources
from pyntnclick.sound import Sound
from pyntnclick import state

from pyntnclick.tools.rect_drawer import RectApp, make_rect_display
from pyntnclick.tools.utils import list_scenes


class MainShell(Shell):
    # Should we allow the menu not to be the opening screen?
    def __init__(self, display, game_description, menu_screen, end_screen):
        Shell.__init__(self, display)
        if menu_screen:
            self.menu_screen = menu_screen(self, game_description)
        else:
            self.menu_screen = DefMenuScreen(self, game_description)
        self.game_screen = GameScreen(self, game_description)
        if end_screen:
            self.end_screen = end_screen(self, game_description)
        else:
            self.end_screen = DefEndScreen(self, game_description)
        self.set_timer(game_description.constants.frame_rate)
        self.show_screen(self.menu_screen)


class GameDescriptionError(Exception):
    """Raised when an GameDescription is invalid."""


class GameDescription(object):

    # initial scene for start of game (unless overridden by debug)
    INITIAL_SCENE = None

    # list of game scenes
    SCENE_LIST = None

    # starting menu
    MENU_SCREEN = None

    # game over screen
    END_SCREEN = None


    # resource module
    RESOURCE_MODULE = "Resources"

    def __init__(self):
        if self.INITIAL_SCENE is None:
            raise GameDescriptionError("A game must have an initial scene.")
        if not self.SCENE_LIST:
            raise GameDescriptionError("A game must have a non-empty list"
                                       " of scenes.")
        self._initial_scene = self.INITIAL_SCENE
        self._scene_list = self.SCENE_LIST
        self._resource_module = self.RESOURCE_MODULE
        self._debug_rects = False
        self.resource = Resources(self._resource_module)
        self.sound = Sound(self.resource)
        self.constants = self.game_constants()
        self.debug_options = []

    def initial_state(self):
        """Create a copy of the initial game state."""
        initial_state = state.GameState(self)
        initial_state.set_debug_rects(self._debug_rects)
        for scene in self._scene_list:
            initial_state.load_scenes(scene)
        initial_state.set_current_scene(self._initial_scene)
        initial_state.set_do_enter_leave()
        return initial_state

    def game_constants(self):
        return GameConstants()

    def option_parser(self):
        parser = OptionParser()
        parser.add_option("--no-sound", action="store_false", default=True,
                dest="sound", help="disable sound")
        # We flag these, so we can warn the user that these require debug mode
        self.debug_options = ['--scene', '--no-rects', '--rect-drawer',
                '--list-scenes', '--details']
        if self.constants.debug:
            parser.add_option("--scene", type="str", default=None,
                dest="scene", help="initial scene")
            parser.add_option("--no-rects", action="store_false", default=True,
                dest="rects", help="disable debugging rects")
            parser.add_option("--rect-drawer", action="store_true",
                    default=False, dest="rect_drawer",
                    help="Launch the rect drawing helper tool. Specify the"
                    " scene with --scene")
            parser.add_option("--list-scenes", action="store_true",
                    default=False, dest='list_scenes', help="List all scenes"
                    " that can be used with --scene and exit.")
            parser.add_option("--detail", type="str", default=None,
                    dest="detail", help="Detailed view for rect_drawer")
        return parser

    def warn_debug(self, option):
        """Warn the user that he needs debug mode"""
        print '%s is only valid in debug mode' % option
        print 'set %s to enable debug mode' % DEBUG_ENVVAR
        print

    def main(self):
        parser = self.option_parser()
        # This is a bit hack'ish, but works
        if not self.constants.debug:
            for option in self.debug_options:
                if option in sys.argv:
                    self.warn_debug(option)
        opts, _ = parser.parse_args(sys.argv)
        pygame.display.init()
        pygame.font.init()
        if opts.sound:
            self.sound.enable_sound(self.constants)
        else:
            self.sound.disable_sound()
        if self.constants.debug:
            if opts.scene is not None:
                # debug the specified scene
                self._initial_scene = opts.scene
            self._debug_rects = opts.rects
        if self.constants.debug and opts.list_scenes:
            # FIXME: Horrible hack to avoid image loading issues for
            # now
            display = pygame.display.set_mode(self.constants.screen,
                                              SWSURFACE)
            list_scenes(self.initial_state)
            sys.exit(0)
        if self.constants.debug and opts.rect_drawer:
            if opts.scene is None:
                print 'Need to supply a scene to use the rect drawer'
                sys.exit(1)
            display = make_rect_display()
            try:
                shell = RectApp(display, self.initial_state, opts.scene,
                        opts.detail)
            except KeyError:
                print 'Invalid scene: %s' % opts.scene
                sys.exit(1)
        else:
            display = pygame.display.set_mode(self.constants.screen,
                                              SWSURFACE)
            pygame.display.set_icon(self.resource.get_image(
                    'suspended_sentence24x24.png', basedir='icons'))
            pygame.display.set_caption("Suspended Sentence")

            shell = MainShell(display, self, self.MENU_SCREEN,
                    self.END_SCREEN)
        try:
            shell.run()
        except KeyboardInterrupt:
            pass