class Game: """ Main game class Contains other game classes: dungeon map, player map, player itself """ def __init__(self): self.dungeon_map = DungeonMap() self.player_map = PlayerMap() self.player = Player() @log_decorator def setup_game(self): """ Game startup method: user should choose between playing new game or loading save """ my_logger.debug("Game start choice") start_game_choice = input( 'Enter "y" if you want to play a new game or\n"load" if you want to load existing game:\n' ) my_logger.debug("Game start choice handling") if start_game_choice == "load": self.load_game() else: map_request = input( 'Enter preferable map size in format "width:height", or just press enter to play with default map:\n' ) my_logger.info("Generating map...") if not len(map_request): map_size = [20, 10] else: map_size = [int(token) for token in map_request.split(':')] self.dungeon_map.set_map_size(*map_size) self.dungeon_map.generate_map() my_logger.info("Map has been generated successfully!") self.player_map.set_map_size(*map_size) self.player_map.init_map() self.player.reset() self.player.randomize_initial_position(self.dungeon_map) self.player_map.update_map(self.dungeon_map, self.player.player_x, self.player.player_y) self.player_map.draw_map() @log_decorator def load_game(self): """ Game load (pickle!) """ my_logger.info("Loading game...") in_file = open('dungeon.sav', 'rb') data = pickle.load(in_file) [ self.dungeon_map.dungeon_map, self.dungeon_map.map_size, self.player_map.dungeon_map, self.player.player_x, self.player.player_y, self.player.health, self.player.treasures ] = data my_logger.info("Game has been loaded!") @log_decorator def save_game(self): """ Game save (pickle!) """ data = [ self.dungeon_map.dungeon_map, self.dungeon_map.map_size, self.player_map.dungeon_map, self.player.player_x, self.player.player_y, self.player.health, self.player.treasures ] out_file = open('dungeon.sav', 'wb') pickle.dump(data, out_file) @log_decorator def run_farame(self): """ Game frame. Returns true if game could be resumed and false otherwise """ ret_value = True move = input( '\nEnter your move, please (w - up, d - right, s - down, a - left), or "save" for save game:\n' ) if move == "save": self.save_game() ret_value = False self.player.make_move(move, *self.dungeon_map.map_size) self.player_map.update_map(self.dungeon_map, self.player.player_x, self.player.player_y) self.player_map.draw_map() if self.dungeon_map.get_cell_content(self.player.player_x, self.player.player_y) == 'T': self.dungeon_map.set_cell_content(self.player.player_x, self.player.player_y, '-') self.player.add_treasure() elif self.dungeon_map.get_cell_content(self.player.player_x, self.player.player_y) == 'X': self.dungeon_map.set_cell_content(self.player.player_x, self.player.player_y, '-') self.player.apply_damage() self.player.draw_character() if self.player.is_dead(): my_logger.info("\n}}}This is a trap! You loose!{{{\n") ret_value = False elif self.player.is_winner(): my_logger.info("\n>>>This is a treasure! You are victorious!<<<\n") ret_value = False return ret_value
class Game: """ Main game class Contains other game classes: dungeon map, player map, player itself """ def __init__(self): self.dungeon_map = DungeonMap() self.player_map = PlayerMap() self.player = Player() @log_decorator def setup_new_game(self): """ This function is used to generate new map of size, specified by user """ while True: map_request = input( 'Enter preferable map size in format "width:height", or just press enter to play with default map:\n' ) my_logger.info("Generating map...") if not len(map_request): map_size = [20, 10] break else: try: map_size = [int(token) for token in map_request.split(':')] break except ValueError as val_error: my_logger.exception(val_error) my_logger.error("Try to enter map size once again!") self.dungeon_map.set_map_size(*map_size) self.dungeon_map.generate_map() my_logger.info("Map has been generated successfully!") self.player_map.set_map_size(*map_size) self.player_map.init_map() self.player.reset() self.player.randomize_initial_position(self.dungeon_map) @log_decorator def setup_game(self): """ Game startup method: user should choose between playing new game or loading save """ my_logger.debug("Game start choice") start_game_choice = input( 'Enter "y" if you want to play a new game or\n"load" if you want to load existing game:\n' ) my_logger.debug("Game start choice handling") if start_game_choice == "load": try: self.load_game() except (FileNotFoundError, pickle.UnpicklingError) as file_error: my_logger.exception(file_error) if isinstance(file_error, FileNotFoundError): my_logger.error( "There is no dungeon.sav file! Start a new game instead!" ) elif isinstance(file_error, pickle.UnpicklingError): my_logger.error( "dungeon.sav file is corrupted! Start a new game instead!" ) self.setup_new_game() else: self.setup_new_game() self.player_map.update_map(self.dungeon_map, self.player.player_x, self.player.player_y) self.player_map.draw_map() @log_decorator def load_game(self): """ Game load (pickle!) """ my_logger.info("Loading game...") in_file = open('dungeon.sav', 'rb') data = pickle.load(in_file) [ self.dungeon_map.dungeon_map, self.dungeon_map.map_size, self.player_map.dungeon_map, self.player.player_x, self.player.player_y, self.player.health, self.player.treasures ] = data my_logger.info("Game has been loaded!") @log_decorator def save_game(self): """ Game save (pickle!) """ data = [ self.dungeon_map.dungeon_map, self.dungeon_map.map_size, self.player_map.dungeon_map, self.player.player_x, self.player.player_y, self.player.health, self.player.treasures ] try: out_file = open('dungeon.sav', 'wb') except PermissionError as premission_error: my_logger.exception(premission_error) my_logger.error( "Unable to save game! So sorry! But you can play again!") pickle.dump(data, out_file) @log_decorator def run_farame(self): """ Game frame. Returns true if game could be resumed and false otherwise """ ret_value = True move = input( '\nEnter your move, please (w - up, d - right, s - down, a - left), or "save" for save game:\n' ) if move == "save": self.save_game() ret_value = False self.player.make_move(move, *self.dungeon_map.map_size) self.player_map.update_map(self.dungeon_map, self.player.player_x, self.player.player_y) self.player_map.draw_map() if self.dungeon_map.get_cell_content(self.player.player_x, self.player.player_y) == 'T': self.dungeon_map.set_cell_content(self.player.player_x, self.player.player_y, '-') self.player.add_treasure() elif self.dungeon_map.get_cell_content(self.player.player_x, self.player.player_y) == 'X': self.dungeon_map.set_cell_content(self.player.player_x, self.player.player_y, '-') self.player.apply_damage() self.player.draw_character() if self.player.is_dead(): my_logger.info("\n}}}This is a trap! You loose!{{{\n") ret_value = False elif self.player.is_winner(): my_logger.info("\n>>>This is a treasure! You are victorious!<<<\n") ret_value = False return ret_value
class Game_session: """ a class to keep track of a single game run (active game session) """ def __init__(self, game): """ Initialise game run """ self.game = game self.screen = self.game.screen self.settings = self.game.settings # create and draw grid self.grid = Grid(self) # create sprite groups self.characters_group = pygame.sprite.Group( ) # used for all characters (player and enemies) self.hp_counters_group = pygame.sprite.Group( ) # used for all HP counter (player and enemies) self.enemies_group = pygame.sprite.Group( ) # used for enemy characters only # create player self.player = Player(self, self.grid.tiles_dict["player_tile"][0]) self.characters_group.add(self.player) # EVENT HANDLING def check_events(self): """Checks for and responds to mouse and kb events""" for event in pygame.event.get(): if event.type == pygame.QUIT: self.game.quit_game() elif event.type == pygame.KEYDOWN: # key down events if event.key == self.settings.key_quit: # quit game TODO remove or change quit key self.game.quit_game() elif event.type == pygame.KEYUP: # key up events if event.key == self.settings.key_keep_wp: # if player kept weapon self.keep_wp() elif event.key == self.settings.key_change_wp: # if player changed weapon self.change_wp() def keep_wp(self): """ player keeps current weapon, and fights with adjacent enemies """ self.settings.sfx_kp_wp.play() # keep_weapon sound sleep(self.settings.sfx_kp_wp.get_length()) # small wait if self.player.get_adj_enemies() != [None, None]: # everyone deals damage for en in self.player.get_adj_enemies(): if en: en.apply_damage(self.player) self.player.apply_damage(en) self.settings.sfx_fight.play() # fighting sound sleep(self.settings.sfx_fight.get_length()) self.update_screen() def change_wp(self): """ player swaps to next weapon, receives damage according to new weapon but deals none """ self.player.change_weapon() self.player.update() self.settings.sfx_ch_wp.play() # change_weapon sound sleep(self.settings.sfx_ch_wp.get_length()) # small wait if self.player.get_adj_enemies() != [None, None]: # enemies deal damage (player does not) for en in self.player.get_adj_enemies(): if en: en.apply_damage(self.player) self.settings.sfx_fight.play() # fighting sound sleep(self.settings.sfx_fight.get_length()) self.update_screen() # TURN CHANGE ACTIONS def update_screen(self): """ updates the screens with all turn changes before it can be refreshed""" # updates existing characters self.characters_group.update() # spawns new enemies if possible self._spawn_enemies() def _spawn_enemies(self): """ has chance to spawn enemies on outermost tiles, if they are free """ outer_tiles = [ self.grid.tiles_dict["left_tiles"][-1], self.grid.tiles_dict["right_tiles"][-1] ] for tile in outer_tiles: if not tile.get_character(): if random() < self.settings.enemy_spawn_prob: new_enemy = Enemy(self, tile) self.enemies_group.add(new_enemy) self.characters_group.add(new_enemy) # DRAWING def draw_screen(self): """ draws the current game situation to the screen """ self.screen.fill(self.settings.bg_color) self.grid.blit_tiles() self.characters_group.draw(self.screen) self.hp_counters_group.draw(self.screen)