Source code for usf.main

#!/usr/bin/env python
# -*- coding: utf-8 -*-
################################################################################
# copyright 2008-2011 Gabriel Pettier <gabriel.pettier@gmail.com>              #
#                                                                              #
# This file is part of UltimateSmashFriends                                    #
#                                                                              #
# UltimateSmashFriends is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by         #
# the Free Software Foundation, either version 3 of the License, or            #
# (at your option) any later version.                                          #
#                                                                              #
# UltimateSmashFriends is distributed in the hope that it will be useful,      #
# but WITHOUT ANY WARRANTY; without even the implied warranty of               #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                #
# GNU General Public License for more details.                                 #
#                                                                              #
# You should have received a copy of the GNU General Public License            #
# along with UltimateSmashFriends.  If not, see <http://www.gnu.org/licenses/>.#
################################################################################

'''
This is the main file for ultimate-smash-friends, that initiate configs, parse
parameters, and initiate games

'''


import logging
import os

from pygame.locals import QUIT
import pygame
from optparse import OptionParser
import threading

from usf.game import Game, NetworkServerGame #, NetworkClientGame
from usf.gui import Gui
from usf.controls import Controls

from usf.music import Music
from usf.font import fonts
from usf.ai import AI

from usf.translation import _


from usf import loaders
from usf import CONFIG

logging.basicConfig(
        filename=os.path.join(
            CONFIG.user_path,
            CONFIG.debug.LOG_FILENAME),
        level=(CONFIG.debug.LOG_LEVEL))

logging.debug("""Paths:
        Config:
        System: {0}
        User: {1}

        Filename: {2}""".format(*CONFIG.paths.keys() + [CONFIG.filename]))

[docs]def author(): """ print credits in the terminal """ if 'CREDITS' not in os.listdir(os.path.join(CONFIG.system_path)): logging.info(CONFIG.system_path) logging.info('\n'.join(os.listdir(os.path.join(CONFIG.system_path)))) logging.debug(CONFIG.system_path +'/CREDITS file not found') else: author_file = open(os.path.join(CONFIG.system_path, 'CREDITS')) logging.info(author_file.read()) author_file.close()
[docs]class Main(object): """ The main class, load some parameters, sets initial states and takes care of the game main loop. """ def __init__(self, init=True, run=True): """ The constructor, create the render surface, set the menu initial state, parse command line params if any, launch the menu or the game depending on parameters. The init parameter determines if the Main object should be initialized once instanciated. The run parameter determines if the game should be run once the object is instantiated and initiated. """ self.lock = threading.Lock() self.stop_thread = False self.game_type = '' self.level = None self.players = [] self.num = None self.address = None self.text_thread = _("Loading...") self.initialized = False self.initate_options_parser() self.parse_options() if init: self.init() if run: self.run()
[docs] def init(self): try: if self.game_type == 'server': self.init_server() elif self.game_type == 'client': self.init_client() else: self.init_standalone() self.initialized = True except: self.stop_thread = True self.initialized = False raise
[docs] def init_server(self): ''' start a server to host a network game ''' self.game = NetworkServerGame()
[docs] def init_client(self): ''' connect to a server to play a network game ''' self.init_screen() self.init_sound() #self.game = NetworkClientGame(level, players) self.state = "game" self.menu = Gui(self.screen)
[docs] def init_standalone(self): ''' start a non network instance of the game ''' self.init_screen() self.text_thread = "Loading sounds and musics..." thread = threading.Thread(None, self.loading_screen) thread.start() self.init_sound() self.ai_instance = AI() # if a level was provided and at least two players in the option # immediatly jump into game mode if len(self.players) > 1 and self.level is not None: self.game = Game(self.screen, self.level, self.players) self.state = "game" self.menu = Gui(self.screen) self.menu.handle_reply({'goto': 'configure'}) else: self.lock.acquire() self.text_thread = "Loading GUI..." self.lock.release() self.menu = Gui(self.screen) self.state = "menu" self.game = None self.level = None self.lock.acquire() self.stop_thread = True self.lock.release() thread.join() # end of loading resources
[docs] def initate_options_parser(self): """ Set options and usage to parse users choices """ usage = ''.join(( 'ultimate-smash-friends [-h] [-a][-l level-name] ', '[-p player1, player2...] [-s num] [-C address] [-t', 'character, level]\n', 'If a level and at least two players are selected, a match is', ' launched immediately.')) version = '%prog 0.1.3' self.parser = OptionParser(usage=usage, version=version) self.parser.add_option('-a', '--authors', action='store_true', dest='author', help='See authors of this game.') self.parser.add_option('-l', '--level', action='store', dest='level', metavar='levelname', help='select level by name') self.parser.add_option('-p', '--players', action='store', dest='players', nargs=1, metavar='player1, player2..', help='select up to 4 players by name') self.parser.add_option('-s', '--server', action='store', dest='server', metavar='num', help="will launch a game server accepting 'num' " \ "players before launching the bame.") self.parser.add_option('-C', '--client', action='store', dest='client', metavar='address', help="will attempt to connect to a game server at " \ "'address'") self.parser.add_option('-t', '--train', action='store', dest='train', metavar='character, level', help=''.join(( "will load 4 times the character in the level,", " and use random moves from every place to ", "find path values and store them")))
[docs] def parse_options(self): """ parse the command line options """ # set up the comand line parser and its options options = self.parser.parse_args()[0] # actually parse the command line options if options.author: author() if options.level: self.level = options.level if options.players: self.players = map( lambda p: 'characters'+os.sep+p, options.players.split(',')) if options.server: self.game_type = 'server' self.num = options.server if options.client: self.game_type = 'client' self.address = options.client if options.train: self.level = options.train.split(',')[1] self.players = (options.train.split(',')[0], )*4 self.game_type = 'training' pygame.init() self.clock = pygame.time.Clock() self.controls = Controls() self.menu = None self.state = ""
[docs] def init_screen(self): """ various screen initialisations """ size = (CONFIG.general.WIDTH, CONFIG.general.HEIGHT) if (CONFIG.general.WIDTH, CONFIG.general.HEIGHT) == (0, 0): if (800, 600) in pygame.display.list_modes(): (CONFIG.general.WIDTH, CONFIG.general.HEIGHT) = (800, 600) else: #the old default value... (CONFIG.general.WIDTH, CONFIG.general.HEIGHT) = (800, 480) CONFIG.display.FULLSCREEN = False size = (CONFIG.general.WIDTH, CONFIG.general.HEIGHT) self.screen = pygame.display.set_mode(size) pygame.display.set_caption('Ultimate Smash Friends') icon = loaders.image(os.path.join(CONFIG.system_path, 'icon', 'icon_50.png'))[0] pygame.display.set_icon(icon) if CONFIG.display.FULLSCREEN: pygame.display.toggle_fullscreen()
[docs] def init_sound(self): """ various audio initialisations """ self.music = Music()
[docs] def manage_menu(self): """ manage input and update menu if we are in the menu state """ # return of the menu update function may contain a new game # instance to switch to. start_loop = pygame.time.get_ticks() menu_was = self.menu.current_screen newgame, game_ = self.menu.update() if menu_was == 'keyboard' and self.menu.current_screen != 'keyboard': self.controls.load_keys() self.controls.load_sequences() if newgame: self.state = 'game' if game_ is not self.game: print "starting game" self.ai_instance = AI() del(self.game) self.game = game_ max_fps = 1000/CONFIG.general.MAX_GUI_FPS if self.menu.current_screen == 'about': self.music_state = 'credits' else: self.music_state = self.state if pygame.time.get_ticks() < max_fps + start_loop: pygame.time.wait(max_fps + start_loop - pygame.time.get_ticks())
[docs] def manage_ai(self): """ update the ai """ for i, p in enumerate(self.game.players): if p.ai and p.present: self.ai_instance.update(self.game, i)
[docs] def manage_game(self, dt): """ call the various submethod to update the whole game and render it to the screen """ #d = self.game.update_clock(was_paused or self.game.first_frame) self.state = self.game.update(dt) self.manage_ai() if self.state in ('game', 'victory'): self.game.draw( debug_params={ 'controls': CONFIG.debug.CONTROLS and self.controls, 'action': CONFIG.debug.ACTIONS, 'hardshape': CONFIG.debug.HARDSHAPES, 'footrect': CONFIG.debug.FOOTRECT, 'current_animation': CONFIG.debug.CURRENT_ANIMATION, 'levelshape': CONFIG.debug.LEVELSHAPES, 'levelmap': CONFIG.debug.LEVELMAP}) self.menu.load = False else: self.menu.current_screen = "main_screen" self.music_state = self.state
[docs] def display_fps(self): """ FPS counter """ if CONFIG.display.SHOW_FPS: self.screen.blit( loaders.text( "FPS: " + str(self.clock.get_fps()), fonts["mono"]["38"]), (10, 5))
[docs] def run(self): """ The main game loop, take care of the state of the game/menu. """ if not self.initialized: return False pygame.mouse.set_visible(False) self.clock.tick() while (True): # poll controls and update informations on current state of the UI state_was = self.state if self.game: dt = self.clock.tick(CONFIG.general.MAX_FPS) / 1000.0 else: dt = self.clock.tick(CONFIG.general.MAX_GUI_FPS) / 1000.0 if self.state != "menu": self.state = self.controls.poll( self.game, self.menu) # this depends on the previous assertion, it's NOT an elif if self.state == "menu": self.manage_menu() else: # update the fps counter if state_was == "menu": dt = 0 self.manage_game(dt) self.display_fps() pygame.display.update() if CONFIG.audio.MUSIC: self.music.update(self.music_state) # verify there is not a QUIT event waiting for us, in case of we # have to quit. self.ended = pygame.event.get(QUIT) if self.ended: logging.debug('fps = '+str(self.clock.get_fps())) pygame.quit() break
[docs] def loading_screen(self): """ update the screen display during loading """ while not self.stop_thread: self.lock.acquire() text = loaders.paragraph(self.text_thread, fonts['mono']['normal']) self.lock.release() x = self.screen.get_width()/2 - text.get_width()/2 y = self.screen.get_height()/2 - text.get_height()/2 self.screen.fill(pygame.color.Color("black")) self.screen.blit(text, (x, y)) pygame.display.update() pygame.time.wait(10)
if __name__ == '__main__': # Entry point of the game, if not imported from another script, launch the # main class with parameters (appart from program self name) if any. m = Main()