Example #1
0
    def setUp(self):

        self.map_size = 10

        self.active_map = DungeonMap(self.map_size)
        self.player = Player(self.active_map)

        self.loaded_map = DungeonMap(0, False)
        self.loaded_player = Player(self.loaded_map)

        self.file_path = 'test_save.dat'
def start_game():
    """
    Start game dialog
    :return: None
    """

    global active_map
    global active_player
    global thread_enemy

    active_map = DungeonMap(0, False)
    active_player = Player(active_map)

    response = utils.get_input(
        validator_response, "Do you wish to load last saved game? [Y\\N]: ")

    if response.lower() == 'y':

        if not utils.load_game(SAVE_PATH, active_map, active_player):

            print("Failed to load saved game! Starting new game")
            init_game()

    else:

        logger.info("Starting new game.")
        init_game()

    thread_enemy = ThreadEnemyWrapper(active_map, active_player)
    thread_enemy.start()
Example #3
0
def make_map(player, height, width):
    #fill map with "blocked" tiles
    dmap = DungeonMap(width, height)

    num_rooms = 0

    for r in range(MAX_ROOMS):
        #random width and height
        w = libtcod.random_get_int(0, ROOM_MIN_SIZE, ROOM_MAX_SIZE)
        h = libtcod.random_get_int(0, ROOM_MIN_SIZE, ROOM_MAX_SIZE)
        #random position without going out of the boundaries of the map
        x = libtcod.random_get_int(0, 0, width - w - 1)
        y = libtcod.random_get_int(0, 0, height - h - 1)

        #"Rect" class makes rectangles easier to work with
        new_room = Rect(x, y, w, h)

        #run through the other rooms and see if they intersect with this one
        failed = False
        for other_room in dmap.rooms:
            if new_room.intersect(other_room):
                failed = True
                break

        if not failed:
            #this means there are no intersections, so this room is valid

            #"paint" it to the map's tiles
            create_room(dmap, new_room)

            #center coordinates of new room, will be useful later
            (new_x, new_y) = new_room.center()

            if num_rooms == 0:
                #this is the first room, where the player starts at
                player.x = new_x
                player.y = new_y
            else:
                #all rooms after the first:
                #connect it to the previous room with a tunnel

                #center coordinates of previous room
                (prev_x, prev_y) = dmap.rooms[num_rooms - 1].center()

                #draw a coin (random number that is either 0 or 1)
                if libtcod.random_get_int(0, 0, 1) == 1:
                    #first move horizontally, then vertically
                    create_h_tunnel(dmap, prev_x, new_x, prev_y)
                    create_v_tunnel(dmap, prev_y, new_y, new_x)
                else:
                    #first move vertically, then horizontally
                    create_v_tunnel(dmap, prev_y, new_y, prev_x)
                    create_h_tunnel(dmap, prev_x, new_x, new_y)

            #finally, append the new room to the list
            dmap.rooms.append(new_room)
            num_rooms += 1

    return dmap
 def __init__(self):
     """
     Constructor of Player class
     """
     super().__init__()
     self.bag = 0
     self.name = ""
     self.proficiency = ""
     self.discovered_map = DungeonMap()
Example #5
0
class Application:
    def __init__(self, window):
        self.window = window
        self.initialize_gl()

        self.dungeon_map = DungeonMap()

    def update(self, dt):
        pass

    def initialize_gl(self):
        self.program = GlProgram(shaders.vertex_sprite, shaders.fragment_sprite)
        self.program.uniform2f(b'offset', 0, 0)

        self.buffer = gl.GLuint(0)
        gl.glGenBuffers(1, ctypes.pointer(self.buffer))

        gl.glActiveTexture(gl.GL_TEXTURE0)
        self.sprite_texture = gltexture.make_texture('sprites.png')
        gl.glBindTexture(gl.GL_TEXTURE_2D, self.sprite_texture)
        self.program.uniform1i(b'tex', 0)

        gl.glEnable(gl.GL_BLEND)
        gl.glEnable(gl.GL_DEPTH_TEST)
        gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)

    def on_resize(self, width, height):
        logging.debug('window resized to %sx%s', width, height)
        gl.glViewport(0, 0, width, height)
        TILE_SIZE = 64
        self.program.uniform2f(b'scale', 2*TILE_SIZE/width, 2*TILE_SIZE/height)
        self.vp_width = width
        self.vp_height = height

    def on_draw(self):
        gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)

        STRIDE = 8

        self.program.use()
        self.program.vertex_attrib_pointer(self.buffer, b'position', 4, stride=STRIDE * ctypes.sizeof(gl.GLfloat))
        self.program.vertex_attrib_pointer(self.buffer, b'tex_coord', 4, stride=STRIDE * ctypes.sizeof(gl.GLfloat), offset=4 * ctypes.sizeof(gl.GLfloat))

        nb_vertices = 6*40*40
        data = self.dungeon_map.vertex_data()
        data = (gl.GLfloat * (STRIDE * nb_vertices))(*data)
        gl.glBufferData(gl.GL_ARRAY_BUFFER, ctypes.sizeof(data), data, gl.GL_DYNAMIC_DRAW)
        gl.glDrawArrays(gl.GL_TRIANGLES, 0, nb_vertices)

    def on_key_press(self, symbol, modifiers):
        logging.debug('Key Press {} {}'.format(symbol, modifiers))
        if symbol == key.I:
            logging.info('FPS: {}'.format(pyglet.clock.get_fps()))
def init_game():
    """
    Initializes game map and player position
    :return: None
    """

    global active_map
    global active_player

    while True:

        map_size = utils.get_input(validator_map_size,
                                   "Input map size [5 - 100]: ")

        try:
            active_map = DungeonMap(int(map_size))
        except MapInitError as exc:
            print(f"Failed to create map! Error: f{str(exc)}")
        else:
            break

    active_player = Player(active_map)
Example #7
0
    def __init__(self, window):
        self.window = window
        self.initialize_gl()

        self.dungeon_map = DungeonMap()
class DungeonGame:

    MIN_MAP_WIDTH = 5
    MAX_MAP_WIDTH = 50

    MIN_MAP_HEIGHT = 1
    MAX_MAP_HEIGHT= 50

    default_health = 3
    treasure_to_win = 3

    trap_rarity = 0.2
    treasure_rarity = 0.05

    enemy_turn_time = 3.0


    actions = {"go north":'w',
             "go east":'d',
             "go south":'s',
             "go west":'a',
             "check health":"h",
             "check bag":"b",
             "view map":'m',
             "view map legend":"lg",
             "save":'sv',
             "load":'ld',
             "exit":"e"}

    actions_cheat = {"go north":'w',
             "go east":'d',
             "go south":'s',
             "go west":'a',
             "check health":"h",
             "check bag":"b",
             "view map":'m',
             "view map legend":"lg",
             "save":'sv',
             "load":'ld',
             "exit":"e",
             "cheat view map":"cheat"}

    action_to_position = {
    "w":Position(0, 1),
    "d":Position(1,0),
    "s":Position(0, -1),
    "a":Position(-1, 0)
    }

    position_directions = [Position(0, 1), Position(1,0), Position(0, -1), Position(-1, 0)]

    dmap = DungeonMap()
    player = Player()
    enemy = choice(enemies_list)

    is_room_being_processed = False
    is_enemy_encounter_being_processed = False


    @debug_decorator
    def __init__(self):
        pass


    @debug_decorator
    def is_game_ended(self):
        """
        Checks if one of conditions for ending game is met:
        currently they are:
        1) Player collects treasure_to_win number of treasures.
        2) Player's health reaches zero.
        """
        is_game_over = (DungeonGame.player.bag >= DungeonGame.treasure_to_win
        or DungeonGame.player.health <= 0)

        return is_game_over


    @debug_decorator
    def init_new_game(self):
        """
        Initializes new games
        """
        logger.info(text.new_game_start)
        input()
        logger.info(text.administration)
        input()
        logger.info(text.enter_proficiency_prompt)
        user_input = input().lower()

        if user_input in DungeonGame.player.proficiencies:
            DungeonGame.player.proficiency = user_input
        else:
            DungeonGame.player.proficiency = "none"

        logger.info(text.enter_dungeon_width_prompt)
        width = input_number_from_boundaries(DungeonGame.MIN_MAP_WIDTH,\
         DungeonGame.MAX_MAP_WIDTH)

        logger.info(text.enter_dungeon_height_prompt)
        height = input_number_from_boundaries(DungeonGame.MIN_MAP_HEIGHT,\
         DungeonGame.MAX_MAP_HEIGHT)

        size = width * height

        number_of_treasures = max (size * DungeonGame.treasure_rarity,\
         DungeonGame.treasure_to_win)
        number_of_traps = min (size - number_of_treasures - 1, size * DungeonGame.trap_rarity)

        traps = Trap.generate_traps(number_of_traps)

        starting_position = Position.generate_random_position(width, height)

        DungeonGame.dmap.initialize(height, width, number_of_treasures, traps, starting_position)

        DungeonGame.player.health = DungeonGame.default_health
        DungeonGame.player.bag = 0
        DungeonGame.player.position = starting_position
        DungeonGame.player.discovered_map.initialize_discovered_map(height, width,\
         starting_position)

        self.respawn_enemy()


    @debug_decorator
    def process_player_commands(self):
        """
        Process player commands.
        """
        logger.info(text.action_prompt)
        user_input = input().lower()

        while (not user_input in DungeonGame.actions_cheat.keys()
         and not user_input in DungeonGame.actions_cheat.values()):
            logger.info(text.action_wrong)
            print_dictionary(DungeonGame.actions)
            user_input = input().lower()

        if user_input in DungeonGame.actions_cheat.keys():
            user_input = DungeonGame.actions_cheat[user_input]

        if user_input in DungeonGame.action_to_position.keys():
            move_position = DungeonGame.player.position + DungeonGame.action_to_position[user_input]

            if not DungeonGame.dmap.is_position_in_map(move_position):
                logger.info(choice(text.no_passage))
            else:
                DungeonGame.player.position = move_position
                self.process_room()

        elif user_input == "m":
            map_to_print = deepcopy(DungeonGame.player.discovered_map)
            map_to_print.assign_cell(DungeonGame.player.position, "p")
            map_to_print.print_map()

        elif user_input == "lg":
            print_dictionary(DungeonMap.discovery_dict)

        elif user_input == "h":
            logger.info(text.health_check)
            logger.info(text.health_description[DungeonGame.player.health])

        elif user_input == "b":
            logger.info(text.treasure_check.format(DungeonGame.player.bag))

        elif user_input == "ld":
            if isfile("./{}.pickle".format(DungeonGame.player.name)):
                self.load_game()
                logger.info(choice(text.load_ingame))
            else:
                logger.info(choice(text.on_no_save_file))

        elif user_input == "sv":
            logger.info(choice(text.on_save_1))
            self.save_game()
            logger.info(choice(text.on_save_2))

        elif user_input == "e":
            logger.info(choice(text.lets_end_this))
            while DungeonGame.player.is_alive():
                DungeonGame.player.take_damage()

        elif user_input == "cheat":
            map_to_print = deepcopy(DungeonGame.dmap)
            map_to_print.assign_cell(DungeonGame.player.position, "p")
            map_to_print.print_map()


    @debug_decorator
    def process_room(self):
        """
        Resolves possible trap encounters and prints feedback.
        """

        #to prevent room and enemy encounter texts from mixing
        while DungeonGame.is_enemy_encounter_being_processed:
            pass

        if not self.player.is_alive():
            return        

        logger.info(text.tell_position.format(DungeonGame.player.position.x,\
         DungeonGame.player.position.y))

        current_cell = DungeonGame.dmap.cell(DungeonGame.player.position)

        if not current_cell:
            logger.debug("processing non-existant room!")
            return

        logger.debug("entered cell {}".format(current_cell))


        current_cell = DungeonMap.cells_dict[current_cell]

        if current_cell.legend in trap_legends:
            self.process_hostile_encounter(current_cell)

            if not self.player.is_alive():
                return
        else:
            logger.info(choice(current_cell.encounter_description))

            if current_cell.legend == treasure_cell.legend:
                DungeonGame.player.bag += 1

        if DungeonGame.dmap.cell(DungeonGame.player.position) != entrance_cell.legend:
            DungeonGame.dmap.assign_cell(DungeonGame.player.position, empty_cell.legend)

        is_trap_nearby = DungeonGame.dmap.check_for_adjacent_types(DungeonGame.player.position,\
         trap_legends)

        is_treasure_nearby = DungeonGame.dmap.check_for_adjacent_types(DungeonGame.player.position,\
         treasure_cell.legend)

        if is_trap_nearby and not is_treasure_nearby:
            logger.info(choice(text.adjacent_trap))
            DungeonGame.player.discovered_map.assign_cell(DungeonGame.player.position,\
             DungeonMap.discovery_dict["trap near"])

        elif not is_trap_nearby and is_treasure_nearby:
            logger.info(choice(text.adjacent_treasure))
            DungeonGame.player.discovered_map.assign_cell(DungeonGame.player.position,\
             DungeonMap.discovery_dict["treasure near"])

        elif is_trap_nearby and is_treasure_nearby:
            logger.info(choice(text.adjacent_trap))
            logger.info(choice(text.also))
            logger.info(choice(text.adjacent_treasure))
            DungeonGame.player.discovered_map.assign_cell(DungeonGame.player.position,\
             DungeonMap.discovery_dict["treasure and trap near"])

        elif DungeonGame.dmap.cell(DungeonGame.player.position) == entrance_cell.legend:
            DungeonGame.player.discovered_map.assign_cell(DungeonGame.player.position,\
            DungeonMap.discovery_dict["entrance"])
        else:
            DungeonGame.player.discovered_map.assign_cell(DungeonGame.player.position,\
             DungeonMap.discovery_dict["empty"])


    @debug_decorator
    def save_game(self):
        """
        Saves current game.
        """
        hash = hashlib.md5(str(DungeonGame.player.name).encode());
        current_data = (str(hash), DungeonGame.player, DungeonGame.enemy, DungeonGame.dmap)
        save_file_name = "".join([DungeonGame.player.name, ".pickle"])

        logger.debug("saving to {}".format(save_file_name))

        with open(save_file_name, 'wb') as save_file:
            dump(current_data, save_file)


    @debug_decorator
    def load_game(self):
        """
        Loading game data from file.

        returns True on succsessful load, False on failed
        """


        save_file_name = "".join([DungeonGame.player.name, ".pickle"])

        logger.debug("loading from {}".format(save_file_name))

        with open(save_file_name, 'rb') as save_file:
            try:
                game_data = load(save_file)

            except UnpicklingError as error:
                try:
                    raise NotValidSaveFileError("UnpicklingError:{}".\
                    format(str(error)), save_file_name)
                except NotValidSaveFileError as custom_error:
                    logger.debug(str(custom_error))
                    return False

        hash = hashlib.md5(str(DungeonGame.player.name).encode());

        if str(hash) == game_data[0]:
            _, DungeonGame.player, DungeonGame.enemy, DungeonGame.dmap = game_data
            return True

        else:
            try:
                raise NotValidSaveFileError("Save file hash not verified.", save_file_name)
            except NotValidSaveFileError as custom_error:
                logger.debug(str(custom_error))
                return False


    @debug_decorator
    def respawn_enemy(self):
        """
        Respawns enemy at random not occupied by Player cell.
        """

        DungeonMap.enemy = choice(enemies_list)

        enemy_position = Position.generate_random_position(DungeonGame.dmap.width,\
        DungeonGame.dmap.height)

        while enemy_position == DungeonGame.player.position:
            enemy_position = Position.generate_random_position(DungeonGame.dmap.width,\
            DungeonGame.dmap.height)

        DungeonMap.enemy.position = enemy_position

        logger.debug("enemy spawned at {},{}".format(DungeonGame.enemy.position.x,\
        DungeonGame.enemy.position.y))


    @debug_decorator
    def process_enemy_turn(self):
        """
        Moves enemy to random ajucent cell
        """
        new_position = DungeonGame.enemy.position + choice(DungeonGame.position_directions)

        while not self.dmap.is_position_in_map(new_position):
            new_position = DungeonGame.enemy.position + choice(DungeonGame.position_directions)

        DungeonGame.enemy.position = new_position

        logger.debug("enemy moves to {},{}".format(DungeonGame.enemy.position.x,\
        DungeonGame.enemy.position.y))


    @debug_decorator
    def process_enemy(self):
        """
        Process enemy turns, which are made in enemy_turn_time intervals.
        """
        time_of_last_turn = time.time()

        while not self.is_game_ended():

            if (DungeonGame.enemy.position == DungeonGame.player.position
            and not DungeonGame.is_room_being_processed):
                logger.debug("enemy finds player")
                DungeonGame.is_enemy_encounter_being_processed = True
                self.process_hostile_encounter(DungeonGame.enemy)
                DungeonGame.is_enemy_encounter_being_processed = False
                self.respawn_enemy()

            current_time = time.time()

            if current_time - time_of_last_turn > DungeonGame.enemy_turn_time:
                self.process_enemy_turn()
                time_of_last_turn = current_time


    @debug_decorator
    @thread_lock_decorator
    def process_hostile_encounter(self, hostile_entity):
        """
        Resolves Player's encounter with Trap or Enemy.
        """
        logger.info(choice(hostile_entity.encounter_description))

        if DungeonGame.player.proficiency in hostile_entity.fight_description.keys():
            logger.info(choice(hostile_entity.fight_description[DungeonGame.player.proficiency]))
        else:
            logger.info(choice(hostile_entity.fight_description["other"]))

        is_damaged = DungeonGame.player.proficiency_immunity[DungeonGame.player.proficiency]\
         != hostile_entity.enemy_type

        if is_damaged:
            DungeonGame.player.take_damage()

        if DungeonGame.player.is_alive():
            if DungeonGame.player.proficiency in hostile_entity.survive_description.keys():
                logger.info(choice(hostile_entity.survive_description[DungeonGame.player.proficiency]))
            else:
                logger.info(choice(hostile_entity.survive_description["other"]))

        else:
            if DungeonGame.player.proficiency in hostile_entity.defeat_description.keys():
                logger.info(choice(hostile_entity.defeat_description[DungeonGame.player.proficiency]))
            else:
                logger.info(choice(hostile_entity.defeat_description["other"]))


    @debug_decorator
    def game_loop(self):
        """
        Game loop.
        """

        while True:

            logger.info(text.enter_name_prompt)

            name = input()
            name = list(filter(lambda c: c.isalpha(), name))
            name = "".join(name)

            if not name:
                name = "Anonymous"

            DungeonGame.player.name = name

            is_load_game = False

            if isfile("./{}.pickle".format(DungeonGame.player.name)):
                logger.info(text.load_game_on_start_prompt)
                is_load_game = process_yes_no_input()

            if is_load_game:
                self.load_game()
                logger.info(choice(text.load_on_start))
            else:
                self.init_new_game()

            threading.Thread(target=self.process_enemy).start()

            self.process_room()

            while not self.is_game_ended():
                self.process_player_commands()


            if DungeonGame.player.is_alive():
                logger.info(choice(text.won))
                logger.debug("DungeonGame.player won")
            else:
                logger.info(choice(text.lost))
                logger.debug("DungeonGame.player lost")

            input()

            logger.info(text.end_map_description)
            map_to_print = deepcopy(DungeonGame.dmap)
            map_to_print.assign_cell(DungeonGame.player.position, "p")
            map_to_print.print_map()
            print_dictionary(DungeonMap.cells_dict_explained)
            input()

            logger.info(text.play_again_prompt)

            is_play_again = process_yes_no_input()

            if not is_play_again:
                logger.debug("user exits game")
                break

            logger.debug("user decides to play again")
Example #9
0
def generate_city_map(width, height, district):
    # generates a grid-based city map

    dmap = DungeonMap(width, height)

    def draw_street(start, end, size=2):
        # draws a street from start to end, inclusive
        # there are size street tiles both left and right of center
        start_x, start_y = start
        end_x, end_y = end

        do_barrier = random.random() < BARRIER_PROBABILITY

        if start_x == end_x:
            barrier_position = random.randint(start_y,
                                              end_y) if do_barrier else -100
            for y in range(start_y, end_y + 1):
                for x in range(start_x - size, start_x + size + 1):
                    if not dmap.within_map(x, y):
                        continue
                    if random.random() < (3 - abs(y - barrier_position)
                                          ) * BARRIER_DENSITY / 3.0:
                        dmap[x][y] = create_tile(TileType.rock)
                    else:
                        dmap[x][y] = create_tile(TileType.street)
        elif start_y == end_y:
            # (I'm sure there's a nice way to deduplicate this code, but s/x/y is easier)
            barrier_position = random.randint(start_x,
                                              end_x) if do_barrier else -100
            for x in range(start_x, end_x + 1):
                for y in range(start_y - size, start_y + size + 1):
                    if not dmap.within_map(x, y):
                        continue
                    if random.random() < (3 - abs(x - barrier_position)
                                          ) * BARRIER_DENSITY / 3.0:
                        dmap[x][y] = create_tile(TileType.rock)
                    else:
                        dmap[x][y] = create_tile(TileType.street)

    blocks = []

    dmap.spawn = None

    def streetify_rect(rect):
        if rect.w < 2 * MIN_BLOCK_SIZE and rect.h < 2 * MIN_BLOCK_SIZE:
            # find the adjacent streets
            x1, y1 = rect.center()
            x2, y2 = x1, y1
            while dmap.within_map(
                    x1, y1) and dmap[x1][y1].tile_type not in STREET_TILES:
                x1 -= 1
            x1 += 1
            while dmap.within_map(
                    x1, y1) and dmap[x1][y1].tile_type not in STREET_TILES:
                y1 -= 1
            y1 += 1
            while dmap.within_map(
                    x2, y2) and dmap[x2][y2].tile_type not in STREET_TILES:
                x2 += 1
            x2 -= 1
            while dmap.within_map(
                    x2, y2) and dmap[x2][y2].tile_type not in STREET_TILES:
                y2 += 1
            y2 -= 1
            blocks.append(Rect(x1, y1, x2 - x1 + 1, y2 - y1 + 1))
            return
        vertical = random.randint(0, 1) == 1
        if rect.w < 2 * MIN_BLOCK_SIZE:
            vertical = False
        elif rect.h < 2 * MIN_BLOCK_SIZE:
            vertical = True

        if vertical:
            street_x = random.randint(rect.x1 + MIN_BLOCK_SIZE,
                                      rect.x2 - MIN_BLOCK_SIZE)
            if not dmap.spawn:
                dmap.spawn = (street_x, (rect.y1 + rect.y2) / 2)
            draw_street((street_x, rect.y1), (street_x, rect.y2))
            streetify_rect(Rect(rect.x1, rect.y1, street_x - rect.x1, rect.h))
            streetify_rect(Rect(street_x, rect.y1, rect.x2 - street_x, rect.h))
        else:
            street_y = random.randint(rect.y1 + MIN_BLOCK_SIZE,
                                      rect.y2 - MIN_BLOCK_SIZE)
            if not dmap.spawn:
                dmap.spawn = ((rect.x1 + rect.x2) / 2, street_y)
            draw_street((rect.x1, street_y), (rect.x2, street_y))
            streetify_rect(Rect(rect.x1, rect.y1, rect.w, street_y - rect.y1))
            streetify_rect(Rect(rect.x1, street_y, rect.w, rect.y2 - street_y))

    for x in range(0, width):
        for y in range(0, height):
            if x < 3 or y < 3 or width - x <= 3 or height - y <= 3:
                dmap[x][y] = create_tile(TileType.street)
    streetify_rect(Rect(3, 3, width - 6, height - 6))

    # clear any rocks around the spawn
    spawn_x, spawn_y = dmap.spawn
    for dx in range(-2, 3):
        for dy in range(-2, 3):
            if dmap[spawn_x + dx][spawn_y + dy].tile_type == TileType.rock:
                dmap[spawn_x + dx][spawn_y + dy] = create_tile(TileType.street)

    dmap.rooms = []

    def create_room(rect):
        for y in range(rect.y1, rect.y2):
            for x in range(rect.x1, rect.x2):
                if x == rect.x1 or x == rect.x2 - 1 or y == rect.y1 or y == rect.y2 - 1:
                    dmap[x][y] = create_tile(TileType.wall)
                else:
                    dmap[x][y] = create_tile(TileType.floor)
        dmap.rooms.append(
            Room(Rect(rect.x1 + 1, rect.y1 + 1, rect.w - 2, rect.h - 2), None))

    def fill_block(block):
        # used to make sure rooms don't intersect each other
        room_hitboxes = []
        block_rooms = []

        top_divs = divide_line(block.w - 1, MIN_BIZ_SIZE, MAX_BIZ_SIZE)
        bottom_divs = divide_line(block.w - 1, MIN_BIZ_SIZE, MAX_BIZ_SIZE)
        left_divs = divide_line(block.h - 1, MIN_BIZ_SIZE, MAX_BIZ_SIZE)
        right_divs = divide_line(block.h - 1, MIN_BIZ_SIZE, MAX_BIZ_SIZE)

        # place corner rooms first
        room = Rect(block.x1, block.y1, top_divs[0] + 1, left_divs[0] + 1)
        room_hitboxes.append(Rect(room.x1, room.y1, room.w - 1, room.h - 1))
        create_room(room)
        room = Rect(block.x1 + top_divs[-1], block.y1, block.w - top_divs[-1],
                    right_divs[0] + 1)
        room_hitboxes.append(Rect(room.x1, room.y1, room.w - 1, room.h - 1))
        create_room(room)
        room = Rect(block.x1, block.y1 + left_divs[-1], bottom_divs[0] + 1,
                    block.h - left_divs[-1])
        room_hitboxes.append(Rect(room.x1, room.y1, room.w - 1, room.h - 1))
        create_room(room)
        room = Rect(block.x1 + bottom_divs[-1], block.y1 + right_divs[-1],
                    block.w - bottom_divs[-1], block.h - right_divs[-1])
        room_hitboxes.append(Rect(room.x1, room.y1, room.w - 1, room.h - 1))
        create_room(room)

        for left, right in zip(top_divs, top_divs[1:]):
            collide = True
            while collide:
                height = random.randint(MIN_BIZ_SIZE, MAX_BIZ_SIZE)
                hitbox = Rect(block.x1 + left, block.y1, right - left, height)
                collide = False
                for other_hitbox in room_hitboxes:
                    if hitbox.intersect(other_hitbox):
                        collide = True
                        break
            room_hitboxes.append(hitbox)
            room = Rect(hitbox.x1, hitbox.y1, hitbox.w + 1, hitbox.h + 1)
            create_room(room)
        for left, right in zip(bottom_divs, bottom_divs[1:]):
            collide = True
            while collide:
                height = random.randint(MIN_BIZ_SIZE, MAX_BIZ_SIZE)
                hitbox = Rect(block.x1 + left, block.y2 - height - 1,
                              right - left, height)
                collide = False
                for other_hitbox in room_hitboxes:
                    if hitbox.intersect(other_hitbox):
                        collide = True
                        break
            room_hitboxes.append(hitbox)
            height = random.randint(MIN_BIZ_SIZE, MAX_BIZ_SIZE)
            room = Rect(hitbox.x1, hitbox.y1, hitbox.w + 1, hitbox.h + 1)
            create_room(room)
        for top, bottom in zip(left_divs, left_divs[1:]):
            collide = True
            while collide:
                width = random.randint(MIN_BIZ_SIZE, MAX_BIZ_SIZE)
                hitbox = Rect(block.x1, block.y1 + top, width, bottom - top)
                collide = False
                for other_hitbox in room_hitboxes:
                    if hitbox.intersect(other_hitbox):
                        collide = True
                        break
            room_hitboxes.append(hitbox)
            room = Rect(hitbox.x1, hitbox.y1, hitbox.w + 1, hitbox.h + 1)
            create_room(room)
        for top, bottom in zip(right_divs, right_divs[1:]):
            collide = True
            while collide:
                width = random.randint(MIN_BIZ_SIZE, MAX_BIZ_SIZE)
                hitbox = Rect(block.x2 - width - 1, block.y1 + top, width,
                              bottom - top)
                collide = False
                for other_hitbox in room_hitboxes:
                    if hitbox.intersect(other_hitbox):
                        collide = True
                        break
            room_hitboxes.append(hitbox)
            height = random.randint(MIN_BIZ_SIZE, MAX_BIZ_SIZE)
            room = Rect(hitbox.x1, hitbox.y1, hitbox.w + 1, hitbox.h + 1)
            create_room(room)

    for block in blocks:
        fill_block(block)

    # create doors for all the rooms
    for room in dmap.rooms:
        rect = room.rect
        good_spots = []
        cx, cy = rect.center()
        for y in range(rect.y1 + 1, rect.y2):
            if dmap[rect.x1 - 2][y].tile_type == TileType.street:
                good_spots.append((rect.x1 - 1, y))
            if dmap[rect.x2 + 1][y].tile_type == TileType.street:
                good_spots.append((rect.x2, y))
        for x in range(rect.x1 + 1, rect.x2):
            if dmap[x][rect.y1 - 2].tile_type == TileType.street:
                good_spots.append((x, rect.y1 - 1))
            if dmap[x][rect.y2 + 1].tile_type == TileType.street:
                good_spots.append((x, rect.y2))
        if len(good_spots) > 0:
            door_x, door_y = random.choice(good_spots)
            room.door = (door_x, door_y)
            dmap[door_x][door_y] = create_tile(TileType.wall)

    dmap.rooms = filter(lambda x: x.door, dmap.rooms)
    random.shuffle(dmap.rooms)

    # assign businesses to rooms
    rooms_to_generate = int(len(dmap.rooms) * BIZ_IN_ROOM_PROPORTION)
    for room in dmap.rooms[:rooms_to_generate]:
        biz = district.add_business(room)
        if room.door:
            door_x, door_y = room.door
            dmap[door_x][door_y] = create_tile(TileType.door)
            if biz.owner:
                # spawn the owner inside the business
                biz.owner.x, biz.owner.y = biz.room.rect.center()
                dmap.objects.append(biz.owner)

    return dmap
Example #10
0
    def setUp(self):

        self.game_map = DungeonMap(10)
        self.player = Player(self.game_map)
Example #11
0
class TestPlayer(unittest.TestCase):
    def setUp(self):

        self.game_map = DungeonMap(10)
        self.player = Player(self.game_map)

    def test_init_position(self):

        self.assertTrue(self.game_map.is_index_valid(self.player.position))
        self.assertTrue(self.game_map.game_map[self.player.position[0]][
            self.player.position[1]] == DungeonMap.SYMBOL_TILE)

    def test_move(self):

        move_directions = ["U", "L", "R", "D"]
        move_coords = {"U": [-1, 0], "L": [0, -1], "R": [0, +1], "D": [+1, 0]}

        direction = random.choice(move_directions)

        player_pos = self.player.position

        if self.player.move(direction, self.game_map):

            self.assertTrue(self.player.position[0] == player_pos[0] +
                            move_coords[direction][0])
            self.assertTrue(self.player.position[1] == player_pos[1] +
                            move_coords[direction][1])

    def test_mark_last_pos(self):

        self.player.mark_last_pos(self.game_map)
        self.assertTrue(self.game_map.game_map[self.player.position[0]][
            self.player.position[1]] == DungeonMap.SYMBOL_LASTPOS)

    def test_is_dead(self):

        self.assertFalse(self.player.is_dead())
        self.player.decrease_hitpoints(5)
        self.assertTrue(self.player.is_dead())

    def test_is_bag_full(self):

        self.assertFalse(self.player.is_bag_full())
        self.player.bag += 1
        self.assertFalse(self.player.is_bag_full())
        self.player.bag += 2
        self.assertTrue(self.player.is_bag_full())

    def test_get_hitpoints(self):

        self.assertTrue(self.player.get_hitpoints() == self.player.hitpoints)

    def test_decrease_hitpoints(self):

        player_hitpoints = self.player.get_hitpoints()
        damage = 1

        self.player.decrease_hitpoints(damage)

        self.assertTrue(self.player.get_hitpoints() == (player_hitpoints -
                                                        damage))

    def tearDown(self):
        del self.player
Example #12
0
class DungeonGame:

    MIN_MAP_WIDTH = 5
    MAX_MAP_WIDTH = 50

    MIN_MAP_HEIGHT = 1
    MAX_MAP_HEIGHT = 50

    default_health = 3
    treasure_to_win = 3

    trap_rarity = 0.2
    treasure_rarity = 0.05

    actions = {
        "go north": 'w',
        "go east": 'd',
        "go south": 's',
        "go west": 'a',
        "check health": "h",
        "check bag": "b",
        "view map": 'm',
        "view map legend": "lg",
        "save": 'sv',
        "load": 'ld',
        "exit": "e"
    }

    actions_cheat = {
        "go north": 'w',
        "go east": 'd',
        "go south": 's',
        "go west": 'a',
        "check health": "h",
        "check bag": "b",
        "view map": 'm',
        "view map legend": "lg",
        "save": 'sv',
        "load": 'ld',
        "exit": "e",
        "cheat view map": "cheat"
    }

    action_to_position = {
        "w": Position(0, 1),
        "d": Position(1, 0),
        "s": Position(0, -1),
        "a": Position(-1, 0)
    }

    dmap = DungeonMap()
    player = Player()

    @debug_decorator
    def __init__(self):
        pass

    @debug_decorator
    def init_new_game(self):
        """
        Initializes new games
        """
        logger.info(text.new_game_start)
        input()
        logger.info(text.administration)
        input()
        logger.info(text.enter_proficiency_prompt)
        user_input = input().lower()

        if user_input in DungeonGame.player.proficiencies:
            DungeonGame.player.proficiency = user_input
        else:
            DungeonGame.player.proficiency = "none"

        logger.info(text.enter_dungeon_width_prompt)
        width = input_number_from_boundaries(DungeonGame.MIN_MAP_WIDTH,\
         DungeonGame.MAX_MAP_WIDTH)

        logger.info(text.enter_dungeon_height_prompt)
        height = input_number_from_boundaries(DungeonGame.MIN_MAP_HEIGHT,\
         DungeonGame.MAX_MAP_HEIGHT)

        size = width * height

        number_of_treasures = max (size * DungeonGame.treasure_rarity,\
         DungeonGame.treasure_to_win)
        number_of_traps = min(size - number_of_treasures - 1,
                              size * DungeonGame.trap_rarity)

        traps = Trap.generate_traps(number_of_traps)

        starting_position = Position.generate_random_position(width, height)

        DungeonGame.dmap.initialize(height, width, number_of_treasures, traps,
                                    starting_position)

        DungeonGame.player.health = DungeonGame.default_health
        DungeonGame.player.bag = 0
        DungeonGame.player.position = starting_position
        DungeonGame.player.discovered_map.initialize_discovered_map(height, width,\
         starting_position)

    @debug_decorator
    def process_player_commands(self):
        """
        Process player commands.
        """
        logger.info(text.action_prompt)
        user_input = input().lower()

        while (not user_input in DungeonGame.actions_cheat.keys()
               and not user_input in DungeonGame.actions_cheat.values()):
            logger.info(text.action_wrong)
            print_dictionary(DungeonGame.actions)
            user_input = input().lower()

        if user_input in DungeonGame.actions_cheat.keys():
            user_input = DungeonGame.actions_cheat[user_input]

        if user_input in DungeonGame.action_to_position.keys():
            move_position = DungeonGame.player.position + DungeonGame.action_to_position[
                user_input]

            if not DungeonGame.dmap.is_position_in_map(move_position):
                logger.info(choice(text.no_passage))
            else:
                DungeonGame.player.position = move_position
                self.process_room()

        elif user_input == "m":
            map_to_print = deepcopy(DungeonGame.player.discovered_map)
            map_to_print.assign_cell(DungeonGame.player.position, "p")
            map_to_print.print_map()

        elif user_input == "lg":
            print_dictionary(DungeonMap.discovery_dict)

        elif user_input == "h":
            logger.info(text.health_check)
            logger.info(text.health_description[DungeonGame.player.health])

        elif user_input == "b":
            logger.info(text.treasure_check.format(DungeonGame.player.bag))

        elif user_input == "ld":
            if isfile("./{}.pickle".format(DungeonGame.player.name)):
                self.load_game()
                logger.info(choice(text.load_ingame))
            else:
                logger.info(choice(text.on_no_save_file))

        elif user_input == "sv":
            logger.info(choice(text.on_save_1))
            self.save_game()
            logger.info(choice(text.on_save_2))

        elif user_input == "e":
            logger.info(choice(text.lets_end_this))
            while DungeonGame.player.is_alive():
                DungeonGame.player.take_damage()

        elif user_input == "cheat":
            map_to_print = deepcopy(DungeonGame.dmap)
            map_to_print.assign_cell(DungeonGame.player.position, "p")
            map_to_print.print_map()

    @debug_decorator
    def process_room(self):
        """
        Resolves possible trap encounters and prints feedback.
        """
        logger.info(text.tell_position.format(DungeonGame.player.position.x,\
         DungeonGame.player.position.y))

        current_cell = DungeonGame.dmap.cell(DungeonGame.player.position)

        if not current_cell:
            logger.debug("processing non-existant room!")
            return

        logger.debug("entered cell {}".format(current_cell))

        current_cell = DungeonMap.cells_dict[current_cell]

        logger.info(choice(current_cell.description))
        input()

        if current_cell.legend == treasure_cell.legend:
            DungeonGame.player.bag += 1

        elif current_cell.legend in trap_legends:
            if DungeonGame.player.proficiency in current_cell.fight_description.keys(
            ):
                logger.info(
                    choice(current_cell.fight_description[
                        DungeonGame.player.proficiency]))
            else:
                logger.info(choice(current_cell.fight_description["other"]))
            input()

            is_damaged = DungeonGame.player.proficiency_immunity[
                DungeonGame.player.proficiency] != current_cell.trap_type

            if is_damaged:
                DungeonGame.player.take_damage()

            if DungeonGame.player.is_alive():
                if DungeonGame.player.proficiency in current_cell.survive_description.keys(
                ):
                    logger.info(
                        choice(current_cell.survive_description[
                            DungeonGame.player.proficiency]))
                else:
                    logger.info(
                        choice(current_cell.survive_description["other"]))
                input()

            else:
                if DungeonGame.player.proficiency in current_cell.defeat_description.keys(
                ):
                    logger.info(
                        choice(current_cell.defeat_description[
                            DungeonGame.player.proficiency]))
                else:
                    logger.info(
                        choice(current_cell.defeat_description["other"]))
                input()
                return

        if DungeonGame.dmap.cell(
                DungeonGame.player.position) != entrance_cell.legend:
            DungeonGame.dmap.assign_cell(DungeonGame.player.position,
                                         empty_cell.legend)

        is_trap_nearby = DungeonGame.dmap.check_for_adjacent_types(DungeonGame.player.position,\
         trap_legends)

        is_treasure_nearby = DungeonGame.dmap.check_for_adjacent_types(DungeonGame.player.position,\
         treasure_cell.legend)

        if is_trap_nearby and not is_treasure_nearby:
            logger.info(choice(text.adjacent_trap))
            DungeonGame.player.discovered_map.assign_cell(DungeonGame.player.position,\
             DungeonMap.discovery_dict["trap near"])
            input()

        elif not is_trap_nearby and is_treasure_nearby:
            logger.info(choice(text.adjacent_treasure))
            DungeonGame.player.discovered_map.assign_cell(DungeonGame.player.position,\
             DungeonMap.discovery_dict["treasure near"])
            input()

        elif is_trap_nearby and is_treasure_nearby:
            logger.info(choice(text.adjacent_trap))
            logger.info(choice(text.also))
            logger.info(choice(text.adjacent_treasure))
            DungeonGame.player.discovered_map.assign_cell(DungeonGame.player.position,\
             DungeonMap.discovery_dict["treasure and trap near"])
            input()

        else:
            DungeonGame.player.discovered_map.assign_cell(DungeonGame.player.position,\
             DungeonMap.discovery_dict["empty"])

    @debug_decorator
    def save_game(self):
        """
        Saves current game.
        """
        current_data = (DungeonGame.player, DungeonGame.dmap)
        save_file_name = "".join([DungeonGame.player.name, ".pickle"])

        logger.debug("saving to {}".format(save_file_name))

        with open(save_file_name, 'wb') as save_file:
            dump(current_data, save_file)

    @debug_decorator
    def load_game(self):
        """
        Loading game data from file.
        """

        save_file_name = "".join([DungeonGame.player.name, ".pickle"])

        logger.debug("loading from {}".format(save_file_name))

        with open(save_file_name, 'rb') as save_file:
            game_data = load(save_file)

        DungeonGame.player, DungeonGame.dmap = game_data

    @debug_decorator
    def game_loop(self):
        """
        Game loop.
        """

        while True:

            logger.info(text.enter_name_prompt)

            name = input()
            name = list(filter(lambda c: c.isalpha(), name))
            name = "".join(name)

            if not name:
                name = "Anonymous"

            DungeonGame.player.name = name

            is_load_game = False

            if isfile("./{}.pickle".format(DungeonGame.player.name)):
                logger.info(text.load_game_on_start_prompt)
                is_load_game = process_yes_no_input()

            if is_load_game:
                self.load_game()
                logger.info(choice(text.load_on_start))
            else:
                self.init_new_game()

            self.process_room()

            while DungeonGame.player.is_alive(
            ) and DungeonGame.player.bag < DungeonGame.treasure_to_win:
                self.process_player_commands()

            if DungeonGame.player.is_alive():
                logger.info(choice(text.won))
                logger.debug("DungeonGame.player won")
            else:
                logger.info(choice(text.lost))
                logger.debug("DungeonGame.player lost")

            input()

            logger.info(text.end_map_description)
            map_to_print = deepcopy(DungeonGame.dmap)
            map_to_print.assign_cell(DungeonGame.player.position, "p")
            map_to_print.print_map()
            print_dictionary(DungeonMap.cells_dict_explained)
            input()

            logger.info(text.play_again_prompt)

            is_play_again = process_yes_no_input()

            if not is_play_again:
                logger.debug("user exits game")
                break

            logger.debug("user decides to play again")