Example #1
0
def render_panel(root_console: tcod.console.Console,
                 panel_console: tcod.console.Console, entities: list,
                 player: Entity, game_map: GameMap, message_log: MessageLog,
                 bar_width: int, panel_width: int, panel_height: int,
                 panel_x: int, panel_y: int, mouse: tuple, fps: float):
    panel_console.default_bg = tcod.black
    panel_console.clear()

    # print message log
    y = 1
    for message in message_log.messages:
        panel_console.default_fg = message.colour
        panel_console.print_(message_log.x, y, message.text, tcod.BKGND_NONE,
                             tcod.LEFT)
        panel_console.print(message_log.x,
                            y,
                            message.text,
                            fg=message.colour,
                            bg=message_log.bg,
                            bg_blend=tcod.BKGND_NONE,
                            alignment=tcod.LEFT)
        y += 1

    render_bar(panel_console, 1, 1, bar_width, 'HP', player.fighter.hp,
               player.fighter.max_hp, tcod.red, tcod.darkest_red)

    panel_console.default_fg = tcod.light_grey
    panel_console.print_(1, 0, get_names_under_mouse(mouse, entities,
                                                     game_map),
                         tcod.BKGND_NONE, tcod.LEFT)
    # panel_console.print(1, 2, 'FPS: {0}'.format(fps), bg_blend=tcod.BKGND_NONE)

    panel_console.blit(root_console, panel_x, panel_y, 0, 0, panel_width,
                       panel_height)
    return
Example #2
0
def blit_and_flush(
        from_console: tcod.console.Console,
        to_console: tcod.console.Console
) -> None:
    from_console.blit(
        to_console,
        width=from_console.width,
        height=from_console.height
    )
    tcod.console_flush()
Example #3
0
def render_map(root_console: tcod.console.Console,
               map_console: tcod.console.Console, game_map: GameMap,
               entities: list, start_x: int, start_y: int, colours: dict,
               fov_recompute: bool):
    # render map tiles only when a change has occurred
    if fov_recompute:
        for y in range(game_map.height):
            for x in range(game_map.width):
                visible = game_map.fov(x, y)
                wall = not game_map.walkable(x, y)

                # if tile can be seen now, light it up
                if visible:
                    if wall:
                        tcod.console_set_char_background(
                            map_console, x, y, colours.get('light_wall'),
                            tcod.BKGND_SET)
                    else:
                        tcod.console_set_char_background(
                            map_console, x, y, colours.get('light_ground'),
                            tcod.BKGND_SET)
                # if we've previously seen this tile
                elif game_map.explored(x, y):
                    if wall:
                        tcod.console_set_char_background(
                            map_console, x, y, colours.get('dark_wall'),
                            tcod.BKGND_SET)
                    else:
                        tcod.console_set_char_background(
                            map_console, x, y, colours.get('dark_ground'),
                            tcod.BKGND_SET)

    # render entities onto map
    entities_in_render_order = sorted(entities,
                                      key=lambda e: e.render_order.value)
    for entity in entities_in_render_order:
        draw_entity(map_console, entity, game_map)

    # copy to the actual screen
    map_console.blit(root_console, start_x, start_y, 0, 0, game_map.width,
                     game_map.height)
    return
Example #4
0
def render_all(root_con: tcod.console.Console, con: tcod.console.Console,
               panel: tcod.console.Console, entities, player, game_map,
               fov_map, fov_recompute: bool, message_log, bar_width,
               panel_y: int, mouse_pos, colors, game_state: GameStates):
    """Render characters on the console screen"""
    render_main_map(con, entities, player, game_map, fov_map, fov_recompute,
                    colors)
    con.blit(root_con)
    render_panel(panel, message_log, bar_width, player, mouse_pos, entities,
                 fov_map, game_map.dungeon_level)
    panel.blit(root_con, 0, panel_y)

    if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY):
        if game_state == GameStates.SHOW_INVENTORY:
            inventory_title = 'Press the key next to an item to use it, or Esc to cancel.\n'
        else:
            inventory_title = 'Press the key next to an item to drop it, or Esc to cancel.\n'
        inventory_menu(root_con, inventory_title, player, 50)
    elif game_state == GameStates.LEVEL_UP:
        level_up_menu(root_con, 'Level up! Choose a stat to raise:', player,
                      40)
    elif game_state == GameStates.CHARACTER_SCREEN:
        character_screen(root_con, player, 30, 10)
Example #5
0
def render_viewport(root_console: tcod.console.Console,
                    viewport_console: tcod.console.Console, viewport_x: int,
                    viewport_y: int, viewport_width: int, viewport_height: int,
                    game_map: GameMap, entities: list, colours: dict,
                    player_x: float, player_y: float, player_rot: float,
                    fov_radius: int, rerender: bool, wall_texture):
    """
    Raycasting algorithm based on javidx9's excellent YouTube video, 'Code-It-Yourself! First Person Shooter (Quick and Simple C++)'

    """
    if rerender:
        texture_width = 32
        # pi/4 rad = 45 deg (pi/3=60, pi/2=90, pi=180)
        fov = math.pi / 3.0
        cam_x = player_x + 0.5
        cam_y = player_y + 0.5
        ground_colour = colours.get('light_ground')
        wall_colour = colours.get('light_wall')
        viewport_console.clear()

        for x in range(viewport_width):
            # render a column based on raycasting
            ray_angle = (player_rot +
                         fov / 2.0) - (x / float(viewport_width)) * fov
            eye_x = math.sin(ray_angle)
            eye_y = math.cos(ray_angle)

            distance_to_wall = 0.0
            hit_wall = False
            distance_to_entity = 0.0
            hit_entity = False
            entity: Entity = None
            wall_x = 0.0
            entity_x = 0.0

            ray_step = 0.2
            prev_test_x = 0.0
            prev_test_y = 0.0

            while not hit_wall and distance_to_wall < fov_radius:
                distance_to_wall += ray_step
                if not hit_entity:
                    distance_to_entity += ray_step
                test_x = cam_x + eye_x * distance_to_wall
                test_y = cam_y + eye_y * distance_to_wall
                i_test_x = int(test_x)
                i_test_y = int(test_y)

                # if outside of game map
                if i_test_x < 0 or i_test_x >= game_map.width or i_test_y < 0 or i_test_y >= game_map.height:
                    hit_wall = True
                    distance_to_wall = fov_radius
                # else
                else:
                    # have we hit a wall yet
                    if not game_map.walkable(i_test_x, i_test_y):
                        hit_wall = True
                        # where on the wall have we hit?
                        if abs(prev_test_x - test_x) > abs(prev_test_y -
                                                           test_y):
                            wall_x = test_y - i_test_y
                        else:
                            wall_x = test_x - i_test_x

                    # if we haven't seen an entity yet
                    if not hit_entity and abs(distance_to_entity) > 0.6:
                        # can we see an entity
                        entities_in_render_order = sorted(
                            entities, key=lambda e: 4 - e.render_order.value)
                        e = get_first_entity_at_location(
                            entities_in_render_order, i_test_x, i_test_y)
                        if e is not None:
                            hit_entity = True
                            entity = e

                            # vector maths adapted from https://stackoverflow.com/a/58542694
                            # find the point where the ray meets the entity's centre line
                            P = (cam_x, cam_y)  # player point
                            Q = (i_test_x + 0.5, i_test_y + 0.5
                                 )  # entity centre point
                            R = (eye_x, eye_y)  # dir of player vision
                            S = (eye_y, -eye_x
                                 )  # entity plane is perpendicular
                            PQ = numpy.subtract(Q,
                                                P)  # vector between two points
                            PQ_mag = math.sqrt(PQ[0]**2 + PQ[1]**2)
                            # t = PQ_mag * 0.707
                            t = float(
                                numpy.vdot(PQ, R) /
                                numpy.vdot(R, (S[1], -S[0])))
                            X = numpy.add(
                                P, (t * R[0], t * R[1])
                            )  # point where we hit a line through the centre of the entity's tile

                            a = (
                                Q[0] - (0.5 * S[0]), Q[1] - (0.5 * S[1])
                            )  # approximation of the start of the entity's line
                            b = (
                                Q[0] + (0.5 * S[0]), Q[1] + (0.5 * S[1])
                            )  # approximation of the end of the entity's line
                            c = (old_lerp(a[0], b[0],
                                          X[0]), old_lerp(a[1], b[1], X[1]))
                            entity_x = math.sqrt((X[0] - int(X[0]))**2 +
                                                 (X[1] - int(X[1]))**2)
                            # entity_x = math.sqrt(c[0]**2 + c[1]**2)
                            distance_to_entity = math.sqrt(PQ[0]**2 + PQ[1]**2)
                prev_test_x = test_x
                prev_test_y = test_y
            # end_while

            # draw this column of the room
            ceiling = float(viewport_height /
                            2.0) - viewport_height / float(distance_to_wall)
            floor = viewport_height - ceiling
            wall_brightness = 1.0 - slerp_float(0, fov_radius,
                                                distance_to_wall / fov_radius)
            if wall_brightness < 0.0:
                wall_brightness = 1.0
            elif wall_brightness > 1.0:
                wall_brightness = 1.0
            out_of_view = distance_to_wall >= fov_radius
            x_cell = x  # viewport_width - x - 1
            half_viewport_height = viewport_height / 2
            for y in range(viewport_height):
                # ceiling
                if y < ceiling:
                    brightness = 1.0 - slerp_float(0, half_viewport_height,
                                                   y / half_viewport_height)
                    tcod.console_set_char_background(viewport_console, x_cell,
                                                     y,
                                                     wall_colour * brightness,
                                                     tcod.BKGND_SET)
                # wall
                elif y < floor:
                    if out_of_view:
                        tcod.console_set_char_background(
                            viewport_console, x_cell, y, tcod.black,
                            tcod.BKGND_SET)
                    elif hit_wall:
                        u = int(wall_x * texture_width)
                        if u >= 32:
                            u = 31
                        v = int(((y - ceiling) / (floor - ceiling)) *
                                texture_width)
                        pixel = wall_texture.getpixel((u, v))
                        tex_col = (int(pixel[0] * wall_brightness),
                                   int(pixel[1] * wall_brightness),
                                   int(pixel[2] * wall_brightness))
                        tcod.console_set_char_background(
                            viewport_console, x_cell, y, tex_col,
                            tcod.BKGND_SET)
                # floor
                else:
                    brightness = slerp_float(
                        half_viewport_height, viewport_height,
                        (y - half_viewport_height) / half_viewport_height)
                    tcod.console_set_char_background(
                        viewport_console, x_cell, y,
                        ground_colour * brightness, tcod.BKGND_SET)

            # draw this column of entity (if we found one)
            if hit_entity and entity.texture:
                height = (viewport_height /
                          min(max(float(distance_to_entity), 0.0), 1.0))
                start = int((viewport_height - height) / 2.0)
                entity_brightness = 1.0 - slerp_float(
                    0, fov_radius, distance_to_entity / fov_radius)
                for y in range(int(height)):
                    u = int(entity_x * texture_width)
                    if u >= 32:
                        u = 31
                    v = int((y / height) * texture_width)
                    pixel = entity.texture.getpixel((u, v))
                    # ignore transparent texels
                    if pixel[3] != 0:
                        tex_col = (int(pixel[0] * entity_brightness),
                                   int(pixel[1] * entity_brightness),
                                   int(pixel[2] * entity_brightness))
                        tcod.console_set_char_background(
                            viewport_console, x_cell, start + y, tex_col,
                            tcod.BKGND_SET)
        # end_for x
    viewport_console.blit(root_console, viewport_x, viewport_y, 0, 0,
                          viewport_width, viewport_height)
    return
def render_all(root_console: tcod.console.Console,
               offscreen_console: tcod.console.Console,
               viewport_console: tcod.console.Console,
               status_console: tcod.console.Console,
               log_console: tcod.console.Console,
               entity_console: tcod.console.Console, player: Entity,
               game_map: GameMap, mouse_tx: int, mouse_ty: int,
               fov_recompute: bool, game_messages: MessageLog, box_text: str,
               game_state: GameState, camera: "Camera") -> None:

    screen_height = const.SCREEN_HEIGHT
    screen_width = const.SCREEN_WIDTH
    bar_width = const.BAR_WIDTH

    status_console.clear()
    log_console.clear()
    entity_console.clear()

    if fov_recompute:

        # Show nothing by default
        viewport_console.ch[:] = 0
        viewport_console.fg[:] = (0, 0, 0)
        viewport_console.bg[:] = (0, 0, 0)

        # Move camera to follow the player
        camera.move_camera(player.x, player.y, game_map.width, game_map.height)
        cam_x, cam_y = camera.x, camera.y
        cam_x2, cam_y2 = camera.x2, camera.y2

        # Translate map coordinates to camera coordinates
        cam_fov = game_map.fov_map.fov[cam_x:cam_x2 + 1, cam_y:cam_y2 + 1]
        cam_explored = game_map.explored[cam_x:cam_x2 + 1, cam_y:cam_y2 + 1]
        cam_glyph = game_map.tile_map.glyph[cam_x:cam_x2 + 1, cam_y:cam_y2 + 1]
        cam_fg = game_map.tile_map.fg[cam_x:cam_x2 + 1, cam_y:cam_y2 + 1]
        cam_bg = game_map.tile_map.bg[cam_x:cam_x2 + 1, cam_y:cam_y2 + 1]

        # If a tile is explored but not visible, render it in dark colors.
        viewport_console.fg[cam_explored == True] = np.multiply(
            cam_fg[cam_explored == True], 0.50).astype(np.int)
        viewport_console.bg[cam_explored == True] = np.multiply(
            cam_bg[cam_explored == True], 0.50).astype(np.int)
        viewport_console.ch[cam_explored == True] = cam_glyph[cam_explored ==
                                                              True]

        # If a tile is visible then render it in light colors.
        viewport_console.fg[cam_fov == True] = cam_fg[cam_fov == True]
        viewport_console.bg[cam_fov == True] = cam_bg[cam_fov == True]
        viewport_console.ch[cam_fov == True] = cam_glyph[cam_fov == True]
        # viewport_console.ch[cam_transparent == False] = 178

        # If a tile is visible, then it is now explored.
        game_map.explored[game_map.fov_map.fov == True] = True

    # Draw all entities in the list
    entities_in_render_order = sorted(game_map.entities,
                                      key=lambda x: x.entity_type.value)

    for entity in entities_in_render_order:
        draw_entity(viewport_console, entity, game_map, camera)

    render_bar(status_console, 1, 1, bar_width, 'HP', player.fighter.hp,
               player.fighter.max_hp, tcod.light_red, tcod.darker_red)
    status_console.print(1, 3, f"Dungeon Level: {game_map.dungeon_level}")

    status_console.print(1,
                         0,
                         get_names_under_mouse(mouse_tx, mouse_ty,
                                               game_map.entities, game_map),
                         fg=(128, 128, 128))

    y = 0
    for message in game_messages.messages:
        log_console.print(game_messages.x, y, message.text, fg=message.color)
        y += 1

    entity_console.print(5, 0, "Visible:", (128, 128, 128))

    visible_entities = [
        entity for entity in entities_in_render_order
        if tcod.map_is_in_fov(game_map.fov_map, entity.x, entity.y)
    ]

    for index, entity in enumerate(visible_entities, start=1):
        if entity.entity_type not in [EntityType.PLAYER, EntityType.CORPSE]:
            entity_str = f"{chr(entity.glyph)}: {entity.name.capitalize()}"
            entity_console.print(1, index, entity_str, entity.fg)

    draw_frames(offscreen_console)

    # offscreen_console.print(0, screen_height - 1, f"{mouse_tx}, {mouse_ty}")

    viewport_console.blit(offscreen_console, 1, 1)
    status_console.blit(offscreen_console, const.VIEWPORT_WIDTH + 2, 1)
    log_console.blit(offscreen_console, 1, const.VIEWPORT_HEIGHT + 2)
    entity_console.blit(offscreen_console, const.VIEWPORT_WIDTH + 2,
                        const.STATUS_HEIGHT + 2)
    offscreen_console.blit(root_console)

    if game_state in [GameState.SHOW_INVENTORY, GameState.DROP_INVENTORY]:
        if game_state == GameState.SHOW_INVENTORY:
            inventory_title = "Press the key next to an item to use it, ESC to cancel.\n"
        else:
            inventory_title = "Press the key next to an item to drop it, ESC to cancel.\n"

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

    elif game_state == GameState.LEVEL_UP:
        level_up_menu(root_console, "Level up! Choose a stat to raise:",
                      player, 40, screen_width, screen_height)

    elif game_state == GameState.CHARACTER_SCREEN:
        character_screen(root_console, player, 30, 10, screen_width,
                         screen_height)

    elif game_state == GameState.MESSAGE_BOX:
        message_box(root_console, box_text, len(box_text),
                    const.VIEWPORT_WIDTH, const.VIEWPORT_HEIGHT)

    if SHOW_STATS:
        fps = tcod.sys_get_fps()
        if fps > 0:
            fps_str = f"FPS: {fps} ({1000 / fps:.2f} ms/frame)"
            root_console.print(0,
                               const.SCREEN_HEIGHT - 1,
                               fps_str,
                               fg=(255, 255, 255))

    tcod.console_flush()
def render_all(
    root_console: tcod.console.Console, con: tcod.console.Console,
    panel: tcod.console.Console, entities: List['Entity'], player: 'Entity',
    game_map: 'GameMap', fov_map: tcod.map.Map, fov_recompute: bool,
    message_log: MessageLog, screen_width: int, screen_height: int,
    bar_width: int, panel_height: int, panel_y: int, mouse: tcod.event.Point,
    colors: Dict[str, tcod.Color], game_state: GameStates,
    target_radius: int = 0,
) -> None:
    # Draw all the tiles in the game map
    for y in range(game_map.height):
        for x in range(game_map.width):
            visible = fov_map.fov[x, y]
            wall = game_map.tiles[x][y].block_sight
            if visible:
                if wall:
                    color = colors['light_wall']
                else:
                    if (game_state == GameStates.TARGETING and
                            math.hypot(x - mouse.x,
                                       y - mouse.y) <= target_radius):
                        color = colors['target_ground']
                    else:
                        color = colors['light_ground']
                game_map.tiles[x][y].explored = True
            elif game_map.tiles[x][y].explored:
                if wall:
                    color = colors['dark_wall']
                else:
                    color = colors['dark_ground']
            else:
                continue
            con.bg[x, y] = cast_to_color(color)

    # Draw all entities in the list
    for entity in sorted(entities, key=attrgetter('render_order.value')):
        draw_entity(con, entity, fov_map, game_map)

    con.blit(root_console, 0, 0, 0, 0, screen_width, screen_height)

    panel.clear(bg=cast_to_color(tcod.black))

    # Print the game messages, one line at a time
    for y, message in enumerate(message_log.messages, 1):
        panel.print(message_log.x, y, message.text,
                    fg=cast_to_color(message.color),
                    bg_blend=tcod.BKGND_NONE,
                    alignment=tcod.LEFT)

    panel.print(1, 0, get_names_under_mouse(mouse, entities, fov_map),
                fg=cast_to_color(tcod.light_gray),
                bg_blend=tcod.BKGND_NONE,
                alignment=tcod.LEFT)

    render_bar(panel, 1, 1, bar_width,
               'HP', player.fighter.hp, player.fighter.max_hp,
               tcod.light_red, tcod.darker_red)

    render_bar(panel, 1, 2, bar_width,
               'XP', player.level.current_xp,
               player.level.experience_to_next_level,
               tcod.light_blue, tcod.darker_blue)

    panel.print(1, 3, f'Player level: {player.level.current_level}',
                fg=cast_to_color(tcod.white),
                bg_blend=tcod.BKGND_NONE,
                alignment=tcod.LEFT)
    panel.print(1, 4, f'Dungeon level: {game_map.dungeon_level}',
                fg=cast_to_color(tcod.white),
                bg_blend=tcod.BKGND_NONE,
                alignment=tcod.LEFT)

    panel.blit(root_console, 0, panel_y, 0, 0, screen_width, panel_height)

    if game_state == GameStates.SHOW_INVENTORY:
        inventory_menu(
            root_console,
            "Press the key next to an item to use it, or Esc to cancel.\n",
            player, 50, screen_width, screen_height,
        )
    elif game_state == GameStates.DROP_INVENTORY:
        inventory_menu(
            root_console,
            "Press the key next to an item to drop it, or Esc to cancel.\n",
            player, 50, screen_width, screen_height,
        )
    elif game_state == GameStates.LEVEL_UP:
        level_up_menu(root_console, 'Level up! Choose a stat to raise:',
                      player, 40, screen_width, screen_height)
    elif game_state == GameStates.CHARACTER_SCREEN:
        character_screen(root_console, player, 30, 10,
                         screen_width, screen_height)