def add_item(self, item_to_add):
        results = []

        if len(self.items) >= self.capacity:
            results.append({
                'item_added':
                None,
                'message':
                Message('You cannot carry any more, your inventory is full')
            })
        else:
            results.append({
                'item_added':
                item_to_add,
                'message':
                Message(
                    'You pick up {0} {1}!'.format(item_to_add.number,
                                                  item_to_add.name),
                    colors.get('green'))
            })

            item_added = False
            for item in self.items:
                if item.name == item_to_add.name:
                    item.number += item_to_add.number
                    item_added = True

            if not item_added:
                self.items.append(item_to_add)

        return results
    def use(self, item_entity, **kwargs):
        results = []

        item_component = item_entity.item

        if item_component.use_function is None:
            equippable_component = item_entity.equippable

            if equippable_component:
                results.append({'equip': item_entity})
            else:
                results.append({
                    'message':
                    Message('The {0} cannot be used'.format(item_entity.name),
                            colors.get('red'))
                })
        else:
            if item_component.targeting and not (kwargs.get('target_x')
                                                 or kwargs.get('target_y')):
                results.append({'targeting': item_entity})
            else:
                kwargs = {**item_component.function_kwargs, **kwargs}
                item_use_results = item_component.use_function(
                    self.owner, **kwargs)

                for item_use_result in item_use_results:
                    if item_use_result.get('consumed'):
                        self.remove_item(item_entity)

                results.extend(item_use_results)

        return results
Exemple #3
0
def main_menu(con, background_image, screen_width, screen_height,
              window_title):
    libtcod.image_blit_2x(background_image, 0, 0, 0)
    libtcod.console_set_default_foreground(0, colors.get('light'))

    menu(con, window_title, ['Play a new game', 'Continue last game', 'Quit'],
         int(screen_width / 2) - 8, int(screen_width / 2), screen_height,
         'dark', 'light')
Exemple #4
0
def menu(con,
         header,
         options,
         width,
         screen_width,
         screen_height,
         background='light',
         foreground='dark'):
    if len(options) > 26:
        raise ValueError('Cannot have a menu with more than 26 options.')

    # calculate total height for the header (after auto-wrap) and one line per option
    header_height = libtcod.console_get_height_rect(con, 0, 0, width,
                                                    screen_height, header) + 2
    height = len(options) + header_height + 1

    # create an off-screen console that represents the menu's window
    window = libtcod.console_new(width, height)

    # print the header, with auto-wrap
    libtcod.console_set_default_foreground(window, colors.get(foreground))
    libtcod.console_set_default_background(window, colors.get(background))
    libtcod.console_clear(window)
    libtcod.console_print_rect_ex(window, 1, 1, width, height,
                                  libtcod.BKGND_SET, libtcod.LEFT, header)

    # print all the options
    y = header_height
    letter_index = ord('a')
    for option_text in options:
        text = '(' + chr(letter_index) + ') ' + option_text
        libtcod.console_print_ex(window, 1, y, libtcod.BKGND_SET, libtcod.LEFT,
                                 text)
        y += 1
        letter_index += 1
    libtcod.console_print_ex(window, 1, y, libtcod.BKGND_SET, libtcod.LEFT,
                             " ")

    # blit the contents of "window" to the root console
    x = int(screen_width / 2 - width / 2)
    y = int(screen_height / 2 - height / 2)
    libtcod.console_blit(window, 0, 0, width, height, 0, x, y, 1.0, 1.0)
Exemple #5
0
def character_screen(player, character_screen_width, character_screen_height,
                     screen_width, screen_height):
    window = libtcod.console_new(character_screen_width,
                                 character_screen_height)

    libtcod.console_set_default_foreground(window, colors.get('dark'))
    libtcod.console_set_default_background(window, colors.get('light'))
    libtcod.console_clear(window)

    libtcod.console_print_rect_ex(window, 1, 1, character_screen_width + 2,
                                  character_screen_height, libtcod.BKGND_SET,
                                  libtcod.LEFT, 'CHARACTER INFORMATION')
    libtcod.console_print_rect_ex(
        window, 1, 2, character_screen_width + 2, character_screen_height,
        libtcod.BKGND_SET, libtcod.LEFT,
        'Level: {0}'.format(player.level.current_level))
    libtcod.console_print_rect_ex(
        window, 1, 3, character_screen_width + 2, character_screen_height,
        libtcod.BKGND_SET, libtcod.LEFT,
        'Experience: {0}'.format(player.level.current_xp))
    libtcod.console_print_rect_ex(
        window, 1, 4, character_screen_width + 2, character_screen_height,
        libtcod.BKGND_SET, libtcod.LEFT, 'Experience to Level: {0}'.format(
            player.level.experience_to_next_level))
    libtcod.console_print_rect_ex(
        window, 1, 6, character_screen_width + 2, character_screen_height,
        libtcod.BKGND_SET, libtcod.LEFT,
        'Maximum HP: {0}'.format(player.fighter.max_hp))
    libtcod.console_print_rect_ex(window, 1, 7, character_screen_width + 2,
                                  character_screen_height, libtcod.BKGND_SET,
                                  libtcod.LEFT,
                                  'Attack: {0}'.format(player.fighter.power))
    libtcod.console_print_rect_ex(
        window, 1, 8, character_screen_width + 2, character_screen_height,
        libtcod.BKGND_SET, libtcod.LEFT,
        'Defense: {0}'.format(player.fighter.defense))

    x = screen_width // 2 - character_screen_width // 2
    y = screen_height // 2 - character_screen_height // 2
    libtcod.console_blit(window, 0, 0, character_screen_width,
                         character_screen_height, 0, x, y, 1.0, 1.0)
def kill_monster(monster):
    death_message = Message('{0} is dead!'.format(monster.name.capitalize()),
                            colors.get('green'))

    #    monster.color = colors.get('dark')
    monster.blocks = False
    monster.fighter = None
    monster.ai = None
    monster.name = 'remains of ' + monster.name
    monster.render_order = RenderOrder.CORPSE

    return death_message
    def next_floor(self, player, message_log, constants):
        self.dungeon_level += 1
        entities = [player]

        self.tiles = self.initialize_tiles()
        self.make_map(constants['max_rooms'], constants['room_min_size'],
                      constants['room_max_size'], constants['map_width'],
                      constants['map_height'], player, entities)

        player.fighter.heal(player.fighter.max_hp // 2)

        message_log.add_message(
            Message('You take a moment to rest, and recover your strength.',
                    colors.get('green')))

        return entities
    def drop_item(self, item):
        results = []

        if self.owner.equipment.main_hand == item or self.owner.equipment.off_hand == item:
            self.owner.equipment.toggle_equip(item)

        item.x = self.owner.x
        item.y = self.owner.y

        self.remove_item(item)
        results.append({
            'item_dropped':
            item,
            'message':
            Message('You dropped the {0}'.format(item.name),
                    colors.get('dark'))
        })

        return results
 def __init__(self, text, color=colors.get('dark')):
     self.text = text
     self.color = color
def render_all(con, panel, tooltip, messages_pane, inventory_pane, entities,
               player, game_map, fov_map, fov_recompute, message_log,
               screen_width, screen_height, map_width, map_height, panel_width,
               panel_height, panel_x, mouse, colors, cam_x, cam_y, anim_frame,
               game_state, targeting_item, log_scroll, log_height, inv_scroll,
               inv_height, inv_selected):

    libtcod.console_clear(0)

    if fov_recompute or game_state == GameStates.TARGETING:
        # Draw all the tiles in the game map
        libtcod.console_set_default_foreground(con, libtcod.white)
        for y in range(game_map.height):
            for x in range(game_map.width):
                visible = libtcod.map_is_in_fov(fov_map, x, y)
                wall = game_map.tiles[x][y].block_sight
                if visible:
                    if game_state == GameStates.TARGETING and distanceBetween(
                            math.floor((mouse.cx + cam_x) / 3),
                            math.ceil((mouse.cy + cam_y) / 2), x,
                            y) <= targeting_item.item.targeting_radius:
                        backcolor = colors.get('red')
                    else:
                        backcolor = colors.get('light')
                    game_map.tiles[x][y].explored = True
                else:
                    backcolor = colors.get('dark')

                libtcod.console_set_char_background(con, x * 3, y * 2,
                                                    backcolor,
                                                    libtcod.BKGND_SET)
                libtcod.console_set_char_background(con, x * 3 + 1, y * 2,
                                                    backcolor,
                                                    libtcod.BKGND_SET)
                libtcod.console_set_char_background(con, x * 3 + 2, y * 2,
                                                    backcolor,
                                                    libtcod.BKGND_SET)
                libtcod.console_set_char_background(con, x * 3, y * 2 + 1,
                                                    backcolor,
                                                    libtcod.BKGND_SET)
                libtcod.console_set_char_background(con, x * 3 + 1, y * 2 + 1,
                                                    backcolor,
                                                    libtcod.BKGND_SET)
                libtcod.console_set_char_background(con, x * 3 + 2, y * 2 + 1,
                                                    backcolor,
                                                    libtcod.BKGND_SET)

                if (game_map.tiles[x][y].explored or visible) and wall:
                    libtcod.console_put_char(con, x * 3, y * 2,
                                             tiles.get('wall_tile'),
                                             libtcod.BKGND_NONE)
                    libtcod.console_put_char(con, x * 3 + 1, y * 2,
                                             tiles.get('wall_tile') + 1,
                                             libtcod.BKGND_NONE)
                    libtcod.console_put_char(con, x * 3 + 2, y * 2,
                                             tiles.get('wall_tile') + 2,
                                             libtcod.BKGND_NONE)
                    libtcod.console_put_char(con, x * 3, y * 2 + 1,
                                             tiles.get('wall_tile') + 32,
                                             libtcod.BKGND_NONE)
                    libtcod.console_put_char(con, x * 3 + 1, y * 2 + 1,
                                             tiles.get('wall_tile') + 33,
                                             libtcod.BKGND_NONE)
                    libtcod.console_put_char(con, x * 3 + 2, y * 2 + 1,
                                             tiles.get('wall_tile') + 34,
                                             libtcod.BKGND_NONE)

    # Draw all entities in the list

    entities_in_render_order = sorted(entities,
                                      key=lambda x: x.render_order.value)

    for entity in entities_in_render_order:
        draw_entity(con, entity, fov_map, anim_frame, game_map, game_state)

    libtcod.console_blit(con, 0, 0, map_width * 3, map_height * 2, 0, -cam_x,
                         -cam_y)

    libtcod.console_set_default_background(panel, colors.get('light'))
    libtcod.console_set_default_foreground(panel, colors.get('dark'))
    libtcod.console_clear(panel)

    # Print the game messages, one line at a time
    libtcod.console_print_ex(panel, int(panel_width / 2), 3, libtcod.BKGND_SET,
                             libtcod.CENTER, "-------- Messages --------")

    libtcod.console_set_default_background(messages_pane, colors.get('light'))
    libtcod.console_clear(messages_pane)
    y = 1
    for message in message_log.messages:
        libtcod.console_set_default_foreground(messages_pane, message.color)
        libtcod.console_print_ex(messages_pane, message_log.x, y,
                                 libtcod.BKGND_NONE, libtcod.LEFT,
                                 message.text)
        y += 1


#    if log_scroll > y - log_height:
#        log_scroll = y - log_height
    libtcod.console_blit(messages_pane, 0, y - log_height - log_scroll,
                         panel_width - 3, log_height, panel, 2, 4)

    #    libtcod.console_set_default_background(panel, colors.get('dark'))
    #    libtcod.console_set_default_foreground(panel, colors.get('light'))
    #    libtcod.console_put_char(panel, panel_width-1, 5, " ", libtcod.BKGND_SET)
    libtcod.console_put_char(panel, panel_width - 2, 4, tiles.get('up_tile'),
                             libtcod.BKGND_SET)
    #    libtcod.console_put_char(panel, panel_width-3, 5, " ", libtcod.BKGND_SET)
    #    libtcod.console_put_char(panel, panel_width-1, 5+log_height, " ", libtcod.BKGND_SET)
    libtcod.console_put_char(panel, panel_width - 2, 4 + log_height,
                             tiles.get('down_tile'), libtcod.BKGND_SET)
    #    libtcod.console_put_char(panel, panel_width-3, 5+log_height, " ", libtcod.BKGND_SET)

    # Print the inventory items
    #    libtcod.console_set_default_background(panel, colors.get('light'))
    #    libtcod.console_set_default_foreground(panel, colors.get('dark'))
    libtcod.console_print_ex(panel, int(panel_width / 2), 5 + log_height,
                             libtcod.BKGND_SET, libtcod.CENTER,
                             "-------- Backpack --------")
    libtcod.console_set_default_foreground(panel, colors.get('green'))
    libtcod.console_print_ex(panel, int(panel_width / 2), 6 + log_height,
                             libtcod.BKGND_SET, libtcod.CENTER,
                             "<> select | [u]se | [d]rop")

    libtcod.console_set_default_background(inventory_pane, colors.get('light'))
    libtcod.console_clear(inventory_pane)
    y = 1
    for item in player.inventory.items:
        if y == inv_selected + 1:
            libtcod.console_set_default_background(inventory_pane,
                                                   colors.get('dark'))
            libtcod.console_set_default_foreground(inventory_pane,
                                                   colors.get('light'))
        else:
            libtcod.console_set_default_background(inventory_pane,
                                                   colors.get('light'))
            libtcod.console_set_default_foreground(inventory_pane,
                                                   colors.get('dark'))
        if player.equipment.main_hand == item:
            libtcod.console_print_ex(
                inventory_pane, 0, y, libtcod.BKGND_SET, libtcod.LEFT,
                '{0} ({1}) (main)'.format(item.name, item.number))
        elif player.equipment.off_hand == item:
            libtcod.console_print_ex(
                inventory_pane, 0, y, libtcod.BKGND_SET, libtcod.LEFT,
                '{0} ({1}) (off)'.format(item.name, item.number))
        else:
            libtcod.console_print_ex(
                inventory_pane, 0, y, libtcod.BKGND_SET, libtcod.LEFT,
                '{0} ({1})'.format(item.name, item.number))
        y += 1
    libtcod.console_blit(inventory_pane, 0, y - inv_height, panel_width - 3,
                         inv_height, panel, 2, 7 + log_height)

    render_bar(panel, 2, 1, panel_width - 4, 'Health', player.fighter.hp,
               player.fighter.max_hp, colors.get('green'), colors.get('dark'),
               colors.get('light'))
    libtcod.console_set_default_foreground(panel, colors.get('dark'))
    #    libtcod.console_print_ex(panel, 1, 3, libtcod.BKGND_NONE, libtcod.LEFT, 'Dungeon level: {0}'.format(game_map.dungeon_level))

    libtcod.console_set_default_background(panel, colors.get('light'))
    libtcod.console_set_default_foreground(panel, colors.get('dark'))
    for y in range(0, screen_height):
        libtcod.console_put_char(panel, 0, y, tiles.get('gradient_tile'),
                                 libtcod.BKGND_SET)

    libtcod.console_set_default_foreground(panel, colors.get('dark'))
    libtcod.console_set_default_background(panel, colors.get('light'))

    libtcod.console_blit(panel, 0, 0, panel_width, panel_height, 0, panel_x, 0)

    tooltip_text = get_names_under_mouse(cam_x, cam_y, mouse, entities,
                                         fov_map)
    tooltip_len = len(tooltip_text)
    libtcod.console_set_default_background(tooltip, libtcod.black)
    libtcod.console_clear(tooltip)
    libtcod.console_set_default_foreground(tooltip, colors.get('light'))
    libtcod.console_set_default_background(tooltip, colors.get('dark'))
    libtcod.console_print_ex(tooltip, 0, 0, libtcod.BKGND_SET, libtcod.LEFT,
                             tooltip_text)

    libtcod.console_set_key_color(tooltip, libtcod.black)
    libtcod.console_blit(tooltip, 0, 0, tooltip_len, 1, 0, mouse.cx + 2,
                         mouse.cy + 1)

    if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY):
        if game_state == GameStates.SHOW_INVENTORY:
            inventory_title = 'Use or equip item.\n'
        else:
            inventory_title = 'Drop an item.\n'

        inventory_menu(con, inventory_title, player, 50, screen_width,
                       screen_height)

    elif game_state == GameStates.LEVEL_UP:
        level_up_menu(con, 'Level up! Choose a stat to raise:', player, 40,
                      screen_width, screen_height)

    elif game_state == GameStates.CHARACTER_SCREEN:
        character_screen(player, 30, 10, screen_width, screen_height)
def kill_player(player):
    #player.char = '%'
    #player.color = colors.get('dark')
    return Message('You died!', colors.get('light')), GameStates.PLAYER_DEAD
def play_game(player, entities, game_map, message_log, con, panel, tooltip,
              messages_pane, inventory_pane, constants, cam_x, cam_y,
              anim_frame, anim_time, log_scroll, log_height, inv_scroll,
              inv_height, inv_selected):

    fov_recompute = True
    fov_map = initialize_fov(game_map)

    key = libtcod.Key()
    mouse = libtcod.Mouse()

    game_state = GameStates.PLAYERS_TURN
    previous_game_state = game_state

    targeting_item = None

    while not libtcod.console_is_window_closed():
        anim_frame, anim_time = animation(anim_frame, anim_time)

        libtcod.sys_check_for_event(
            libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse)

        if fov_recompute:
            recompute_fov(fov_map, player.x, player.y, constants['fov_radius'],
                          constants['fov_light_walls'],
                          constants['fov_algorithm'])

        log_height, inv_height = update_panels_heights(
            player, constants['panel_height'])

        render_all(con, panel, tooltip, messages_pane, inventory_pane,
                   entities, player, game_map, fov_map, fov_recompute,
                   message_log, constants['screen_width'],
                   constants['screen_height'], constants['map_width'],
                   constants['map_height'], constants['panel_width'],
                   constants['panel_height'], constants['panel_x'], mouse,
                   colors, cam_x, cam_y, anim_frame, game_state,
                   targeting_item, log_scroll, log_height, inv_scroll,
                   inv_height, inv_selected)

        fov_recompute = False

        libtcod.console_flush()

        clear_all(con, entities)

        action = handle_keys(key, game_state)
        mouse_action = handle_mouse(mouse, cam_x, cam_y)

        move = action.get('move')
        wait = action.get('wait')
        pickup = action.get('pickup')
        #        show_inventory = action.get('show_inventory')
        prev_inventory = action.get('prev_inventory')
        next_inventory = action.get('next_inventory')
        use_inventory = action.get('use_inventory')
        drop_inventory = action.get('drop_inventory')
        #        inventory_index = action.get('inventory_index')
        #        toggle_log = action.get('toggle_log')
        take_stairs = action.get('take_stairs')
        level_up = action.get('level_up')
        show_character_screen = action.get('show_character_screen')
        exit = action.get('exit')
        fullscreen = action.get('fullscreen')

        left_click = mouse_action.get('left_click')
        right_click = mouse_action.get('right_click')

        player_turn_results = []

        #inventory highlight for mouse use
        if mouse.cx > constants['screen_width'] - constants[
                'panel_width'] and mouse.cy >= constants[
                    'panel_height'] - 1 - inv_height and mouse.cy < constants[
                        'panel_height'] - 1:
            inv_selected = mouse.cy - (constants['panel_height'] - 1 -
                                       inv_height)

        if left_click:

            #move
            if mouse.cx < player.x * 3 - cam_x and mouse.cx > player.x * 3 - cam_x - 6 and mouse.cy <= player.y * 2 - cam_y + 1 and mouse.cy >= player.y * 2 - cam_y:
                #move left
                move = (-1, 0)
            if mouse.cx > player.x * 3 - cam_x + 2 and mouse.cx < player.x * 3 - cam_x + 9 and mouse.cy <= player.y * 2 - cam_y + 1 and mouse.cy >= player.y * 2 - cam_y:
                #move right
                move = (1, 0)
            if mouse.cx >= player.x * 3 - cam_x and mouse.cx <= player.x * 3 - cam_x + 2 and mouse.cy < player.y * 2 - cam_y and mouse.cy > player.y * 2 - cam_y - 4:
                #move up
                move = (0, -1)
            if mouse.cx >= player.x * 3 - cam_x and mouse.cx <= player.x * 3 - cam_x + 2 and mouse.cy > player.y * 2 - cam_y + 1 and mouse.cy < player.y * 2 - cam_y + 6:
                #move down
                move = (0, 1)

            #use inventory item
            if mouse.cx > constants['screen_width'] - constants[
                    'panel_width'] and mouse.cy >= constants[
                        'panel_height'] - 1 - inv_height and mouse.cy < constants[
                            'panel_height'] - 1:
                item = player.inventory.items[mouse.cy -
                                              (constants['panel_height'] - 1 -
                                               inv_height)]
                player_turn_results.extend(
                    player.inventory.use(item,
                                         entities=entities,
                                         fov_map=fov_map))
                if inv_selected > len(player.inventory.items) - 1:
                    inv_selected = len(player.inventory.items) - 1
                if inv_selected < 0:
                    inv_selected = 0

            #scroll log
            if mouse.cx == constants[
                    'screen_width'] - 1 or mouse.cx == constants[
                        'screen_width'] - 2 or mouse.cx == constants[
                            'screen_width'] - 3:
                if mouse.cy == 4:
                    #scroll message log up
                    log_scroll += 1
                    if log_scroll > len(message_log.messages) - log_height:
                        log_scroll = len(message_log.messages) - log_height
                elif mouse.cy == 4 + log_height and log_scroll > 0:
                    # scroll message log down
                    log_scroll -= 1

        if right_click:
            #drop inventory item
            if mouse.cx > constants['screen_width'] - constants[
                    'panel_width'] and mouse.cy >= constants[
                        'panel_height'] - 1 - inv_height and mouse.cy < constants[
                            'panel_height'] - 1 and len(
                                player.inventory.items) > 0:
                item = player.inventory.items[mouse.cy -
                                              (constants['panel_height'] - 1 -
                                               inv_height)]
                player_turn_results.extend(player.inventory.drop_item(item))
                if inv_selected > len(player.inventory.items) - 1:
                    inv_selected = len(player.inventory.items) - 1
                if inv_selected < 0:
                    inv_selected = 0

        if next_inventory and inv_selected < len(player.inventory.items) - 1:
            inv_selected += 1

        if prev_inventory and inv_selected > 0:
            inv_selected -= 1

        if use_inventory and game_state != GameStates.PLAYER_DEAD:
            item = player.inventory.items[inv_selected]
            player_turn_results.extend(
                player.inventory.use(item, entities=entities, fov_map=fov_map))
            if inv_selected > len(player.inventory.items) - 1:
                inv_selected = len(player.inventory.items) - 1
            if inv_selected < 0:
                inv_selected = 0

        if drop_inventory and game_state != GameStates.PLAYER_DEAD:
            item = player.inventory.items[inv_selected]
            player_turn_results.extend(player.inventory.drop_item(item))
            if inv_selected > len(player.inventory.items) - 1:
                inv_selected = len(player.inventory.items) - 1
            if inv_selected < 0:
                inv_selected = 0

        if move and game_state == GameStates.PLAYERS_TURN:
            dx, dy = move
            destination_x = player.x + dx
            destination_y = player.y + dy

            if not game_map.is_blocked(destination_x, destination_y):
                target = get_blocking_entities_at_location(
                    entities, destination_x, destination_y)

                if target:
                    attack_results = player.fighter.attack(target)
                    player_turn_results.extend(attack_results)
                else:
                    player.move(dx, dy)
                    cam_x, cam_y = update_cam(player, constants)
                    fov_recompute = True

            else:
                message_log.add_message(
                    Message('You stupidly walk into the wall. Ouch.'))
            game_state = GameStates.ENEMY_TURN

        elif wait:
            game_state = GameStates.ENEMY_TURN

        elif pickup and game_state == GameStates.PLAYERS_TURN:
            for entity in entities:
                if entity.item and entity.x == player.x and entity.y == player.y:
                    pickup_results = player.inventory.add_item(entity)
                    player_turn_results.extend(pickup_results)
                    break
            else:
                message_log.add_message(
                    Message('There is nothing here to pick up.'))


#        if show_inventory:
#            previous_game_state = game_state
#            game_state = GameStates.SHOW_INVENTORY

#        if inventory_index is not None and previous_game_state != GameStates.PLAYER_DEAD and inventory_index < len(
#                player.inventory.items):
#            item = player.inventory.items[inventory_index]

#            if game_state == GameStates.SHOW_INVENTORY:
#                player_turn_results.extend(player.inventory.use(item, entities=entities, fov_map=fov_map))
#            elif game_state == GameStates.DROP_INVENTORY:
#                player_turn_results.extend(player.inventory.drop_item(item))

#        if toggle_log:
#            if constants['panel_height'] == constants['screen_height']:
#                constants['panel_height'] = 5
#            else:
#                constants['panel_height'] = constants['screen_height']

        if take_stairs and game_state == GameStates.PLAYERS_TURN:
            for entity in entities:
                if entity.stairs and entity.x == player.x and entity.y == player.y:
                    entities = game_map.next_floor(player, message_log,
                                                   constants)
                    fov_map = initialize_fov(game_map)
                    fov_recompute = True
                    libtcod.console_clear(con)
                    cam_x, cam_y = update_cam(player, constants)
                    break
            else:
                message_log.add_message(
                    Message('There are no stairs here.', colors.get('red')))

        if level_up:
            if level_up == 'hp':
                player.fighter.base_max_hp += 20
                player.fighter.hp += 20
            elif level_up == 'str':
                player.fighter.base_power += 1
            elif level_up == 'def':
                player.fighter.base_defense += 1

            game_state = previous_game_state

        if show_character_screen:
            previous_game_state = game_state
            game_state = GameStates.CHARACTER_SCREEN

        if game_state == GameStates.TARGETING:
            if left_click:
                target_x, target_y = left_click

                item_use_results = player.inventory.use(targeting_item,
                                                        entities=entities,
                                                        fov_map=fov_map,
                                                        target_x=target_x,
                                                        target_y=target_y)
                player_turn_results.extend(item_use_results)
                fov_recompute = True
            elif right_click:
                player_turn_results.append({'targeting_cancelled': True})
                fov_recompute = True

        if exit:
            if game_state in (GameStates.SHOW_INVENTORY,
                              GameStates.DROP_INVENTORY,
                              GameStates.CHARACTER_SCREEN):
                game_state = previous_game_state
            elif game_state == GameStates.TARGETING:
                player_turn_results.append({'targeting_cancelled': True})
            else:
                save_game(player, entities, game_map, message_log, game_state)
                return True

        if fullscreen:
            libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen())

        for player_turn_result in player_turn_results:
            message = player_turn_result.get('message')
            dead_entity = player_turn_result.get('dead')
            item_added = player_turn_result.get('item_added')
            item_consumed = player_turn_result.get('consumed')
            item_dropped = player_turn_result.get('item_dropped')
            equip = player_turn_result.get('equip')
            targeting = player_turn_result.get('targeting')
            targeting_cancelled = player_turn_result.get('targeting_cancelled')
            xp = player_turn_result.get('xp')

            if message:
                message_log.add_message(message)

            if targeting_cancelled:
                game_state = previous_game_state
                message_log.add_message(Message('Targeting cancelled'))
                fov_recompute = True

            if dead_entity:
                if dead_entity == player:
                    message, game_state = kill_player(dead_entity)
                else:
                    message = kill_monster(dead_entity)

                message_log.add_message(message)

            if item_added:
                entities.remove(item_added)

                game_state = GameStates.ENEMY_TURN

            if item_consumed:
                game_state = GameStates.ENEMY_TURN

            if targeting:
                previous_game_state = GameStates.PLAYERS_TURN
                game_state = GameStates.TARGETING

                targeting_item = targeting

                message_log.add_message(targeting_item.item.targeting_message)

            if item_dropped:
                entities.append(item_dropped)

                game_state = GameStates.ENEMY_TURN

            if equip:
                equip_results = player.equipment.toggle_equip(equip)

                for equip_result in equip_results:
                    equipped = equip_result.get('equipped')
                    dequipped = equip_result.get('dequipped')

                    if equipped:
                        message_log.add_message(
                            Message('You equipped the {0}'.format(
                                equipped.name)))

                    if dequipped:
                        message_log.add_message(
                            Message('You unquipped the {0}'.format(
                                dequipped.name)))

                game_state = GameStates.ENEMY_TURN

            if xp:
                leveled_up = player.level.add_xp(xp)
                message_log.add_message(
                    Message('You gain {0} experience points.'.format(xp)))

                if leveled_up:
                    message_log.add_message(
                        Message(
                            'You reached level {0}'.format(
                                player.level.current_level) + '!',
                            colors.get('green')))
                    previous_game_state = game_state
                    game_state = GameStates.LEVEL_UP

        if game_state == GameStates.ENEMY_TURN:
            for entity in entities:
                if entity.ai:
                    enemy_turn_results = entity.ai.take_turn(
                        player, fov_map, game_map, entities)

                    for enemy_turn_result in enemy_turn_results:
                        message = enemy_turn_result.get('message')
                        dead_entity = enemy_turn_result.get('dead')

                        if message:
                            message_log.add_message(message)

                        if dead_entity:
                            if dead_entity == player:
                                message, game_state = kill_player(dead_entity)
                            else:
                                message = kill_monster(dead_entity)

                            message_log.add_message(message)

                            if game_state == GameStates.PLAYER_DEAD:
                                break

                    if game_state == GameStates.PLAYER_DEAD:
                        break

            else:
                game_state = GameStates.PLAYERS_TURN
def main():
    constants = get_constants()

    libtcod.sys_set_fps(30)

    # Animate
    anim_time = libtcod.sys_elapsed_milli()
    anim_frame = 0

    libtcod.console_set_custom_font(
        'sprite-font.png',
        libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD, 32, 48)
    libtcod.console_init_root(constants['screen_width'],
                              constants['screen_height'],
                              constants['window_title'], False)
    libtcod.console_set_default_background(0, colors.get('dark'))

    load_customfont()

    con = libtcod.console_new(constants['map_width'] * 3,
                              constants['map_height'] * 2)
    panel = libtcod.console_new(constants['panel_width'],
                                constants['screen_height'])
    tooltip = libtcod.console_new(constants['screen_width'], 1)
    messages_pane = libtcod.console_new(constants['message_width'], 1000)
    inventory_pane = libtcod.console_new(constants['message_width'], 40)

    player = None
    entities = []
    game_map = None
    message_log = None
    game_state = None

    show_main_menu = True
    show_load_error_message = False

    main_menu_background_image_0 = libtcod.image_load('menu_background_0.png')
    main_menu_background_image_1 = libtcod.image_load('menu_background_1.png')
    main_menu_background_image_2 = libtcod.image_load('menu_background_2.png')
    main_menu_background_image_3 = libtcod.image_load('menu_background_3.png')

    log_scroll = 0
    inv_scroll = 0

    key = libtcod.Key()
    mouse = libtcod.Mouse()

    while not libtcod.console_is_window_closed():

        anim_frame, anim_time = animation(anim_frame, anim_time)

        if anim_frame == 0:
            main_menu_background_image = main_menu_background_image_0
        elif anim_frame == 1:
            main_menu_background_image = main_menu_background_image_1
        elif anim_frame == 2:
            main_menu_background_image = main_menu_background_image_2
        else:
            main_menu_background_image = main_menu_background_image_3

        libtcod.sys_check_for_event(
            libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse)

        if show_main_menu:
            main_menu(con, main_menu_background_image,
                      constants['screen_width'], constants['screen_height'],
                      constants['window_title'])

            if show_load_error_message:
                message_box(con, 'No save game to load', 50,
                            constants['screen_width'],
                            constants['screen_height'])

            libtcod.console_flush()

            action = handle_main_menu(key)

            new_game = action.get('new_game')
            load_saved_game = action.get('load_game')
            exit_game = action.get('exit')

            if show_load_error_message and (new_game or load_saved_game
                                            or exit_game):
                show_load_error_message = False
            elif new_game:
                player, entities, game_map, message_log, game_state = get_game_variables(
                    constants)
                game_state = GameStates.PLAYERS_TURN

                show_main_menu = False
            elif load_saved_game:
                try:
                    player, entities, game_map, message_log, game_state = load_game(
                    )
                    show_main_menu = False
                except FileNotFoundError:
                    show_load_error_message = True
            elif exit_game:
                break

        else:
            libtcod.console_clear(con)
            cam_x, cam_y = update_cam(player, constants)

            log_height, inv_height = update_panels_heights(
                player, constants['panel_height'])
            log_scroll = 0
            inv_scroll = 0
            inv_selected = 0

            play_game(player, entities, game_map, message_log, con, panel,
                      tooltip, messages_pane, inventory_pane, constants, cam_x,
                      cam_y, anim_frame, anim_time, log_scroll, log_height,
                      inv_scroll, inv_height, inv_selected)

            show_main_menu = True
    def place_entities(self, room, entities):
        max_monsters_per_room = from_dungeon_level([[2, 1], [3, 4], [5, 6]],
                                                   self.dungeon_level)
        max_items_per_room = from_dungeon_level([[1, 1], [2, 4]],
                                                self.dungeon_level)

        number_of_monsters = randint(0, max_monsters_per_room)
        number_of_items = randint(0, max_items_per_room)

        monster_chances = {
            'orc':
            80,
            'troll':
            from_dungeon_level([[15, 3], [30, 5], [60, 7]], self.dungeon_level)
        }

        item_chances = {
            'healing_potion': 35,
            'sword': from_dungeon_level([[10, 5]], self.dungeon_level),
            'shield': from_dungeon_level([[10, 6]], self.dungeon_level),
            'lightning_scroll': from_dungeon_level([[25, 4]],
                                                   self.dungeon_level),
            'fireball_scroll': from_dungeon_level([[25, 6]],
                                                  self.dungeon_level),
            'confusion_scroll': from_dungeon_level([[10, 2]],
                                                   self.dungeon_level)
        }

        for i in range(number_of_monsters):
            # Choose a random location in the room
            x = randint(room.x1 + 1, room.x2 - 1)
            y = randint(room.y1 + 1, room.y2 - 1)

            # Check if an entity is already in that location
            if not any([
                    entity
                    for entity in entities if entity.x == x and entity.y == y
            ]):
                monster_choice = random_choice_from_dict(monster_chances)

                if monster_choice == 'orc':
                    fighter_component = Fighter(hp=20,
                                                defense=0,
                                                power=4,
                                                xp=35)
                    ai_component = BasicMonster()
                    monster = Entity(x,
                                     y,
                                     tiles.get('orc_tile'),
                                     libtcod.white,
                                     'Orc',
                                     blocks=True,
                                     render_order=RenderOrder.ACTOR,
                                     fighter=fighter_component,
                                     ai=ai_component)
                else:
                    fighter_component = Fighter(hp=30,
                                                defense=2,
                                                power=8,
                                                xp=100)
                    ai_component = BasicMonster()
                    monster = Entity(x,
                                     y,
                                     tiles.get('troll_tile'),
                                     libtcod.white,
                                     'Troll',
                                     blocks=True,
                                     render_order=RenderOrder.ACTOR,
                                     fighter=fighter_component,
                                     ai=ai_component)

                entities.append(monster)

        for i in range(number_of_items):
            x = randint(room.x1 + 1, room.x2 - 1)
            y = randint(room.y1 + 1, room.y2 - 1)

            if not any([
                    entity
                    for entity in entities if entity.x == x and entity.y == y
            ]):
                item_choice = random_choice_from_dict(item_chances)

                if item_choice == 'healing_potion':
                    item_component = Item(use_function=heal, amount=40)
                    item = Entity(x,
                                  y,
                                  tiles.get('healingpotion_tile'),
                                  libtcod.white,
                                  'Healing Potion',
                                  render_order=RenderOrder.ITEM,
                                  item=item_component)
                elif item_choice == 'sword':
                    equippable_component = Equippable(EquipmentSlots.MAIN_HAND,
                                                      power_bonus=3)
                    item = Entity(x,
                                  y,
                                  tiles.get('sword_tile'),
                                  libtcod.white,
                                  'Sword',
                                  render_order=RenderOrder.ITEM,
                                  equippable=equippable_component,
                                  sprite_main_shift=576)
                elif item_choice == 'shield':
                    equippable_component = Equippable(EquipmentSlots.OFF_HAND,
                                                      defense_bonus=1)
                    item = Entity(x,
                                  y,
                                  tiles.get('shield_tile'),
                                  libtcod.white,
                                  'Shield',
                                  render_order=RenderOrder.ITEM,
                                  equippable=equippable_component,
                                  sprite_off_shift=320)
                elif item_choice == 'fireball_scroll':
                    item_component = Item(
                        use_function=cast_fireball,
                        targeting=True,
                        targeting_message=Message(
                            'Left-click a target tile for the fireball, or right-click to cancel.',
                            colors.get('dark')),
                        targeting_radius=3,
                        damage=25,
                        radius=3)
                    item = Entity(x,
                                  y,
                                  tiles.get('scroll_tile'),
                                  libtcod.white,
                                  'Fireball Scroll',
                                  render_order=RenderOrder.ITEM,
                                  item=item_component)
                elif item_choice == 'confusion_scroll':
                    item_component = Item(
                        use_function=cast_confuse,
                        targeting=True,
                        targeting_message=Message(
                            'Left-click an enemy to confuse it, or right-click to cancel.',
                            colors.get('dark')),
                        targeting_radius=0)
                    item = Entity(x,
                                  y,
                                  tiles.get('scroll_tile'),
                                  libtcod.white,
                                  'Confusion Scroll',
                                  render_order=RenderOrder.ITEM,
                                  item=item_component)
                else:
                    item_component = Item(use_function=cast_lightning,
                                          damage=40,
                                          maximum_range=5)
                    item = Entity(x,
                                  y,
                                  tiles.get('scroll_tile'),
                                  libtcod.white,
                                  'Lightning Scroll',
                                  render_order=RenderOrder.ITEM,
                                  item=item_component)
                entities.append(item)