import pygame
import math
import random

pygame.init()

WIDTH, HEIGHT = 800, 600
HALF_WIDTH = WIDTH // 2
HALF_HEIGHT = HEIGHT // 2
FPS = 60

screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()

MAP_WIDTH, MAP_HEIGHT = 50, 50
map_data = []

def generate_forest():
    global map_data
    map_data = []
    for y in range(MAP_HEIGHT):
        row = []
        for x in range(MAP_WIDTH):
            # Randomly place trees with a certain density
            if random.random() < 0.2:  # 20% chance of a tree
                row.append(1)
            else:
                row.append(0)
            # Ensure border cells are empty to prevent out-of-bounds errors
            if x == 0 or y == 0 or x == MAP_WIDTH - 1 or y == MAP_HEIGHT - 1:
                row[-1] = 0
        map_data.append(row)

# Load the tree texture
tree_texture = pygame.image.load('tree.png').convert_alpha()

player_x, player_y = MAP_WIDTH // 2, MAP_HEIGHT // 2
player_angle = 0

def handle_input():
    global player_x, player_y, player_angle
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        player_angle -= 0.05
    if keys[pygame.K_RIGHT]:
        player_angle += 0.05
    if keys[pygame.K_UP]:
        move_x = math.cos(player_angle) * 0.1
        move_y = math.sin(player_angle) * 0.1
        new_x = player_x + move_x
        new_y = player_y + move_y
        # Boundary check to prevent moving outside the map
        if 0 <= int(new_x) < MAP_WIDTH and 0 <= int(new_y) < MAP_HEIGHT:
            player_x = new_x
            player_y = new_y
    if keys[pygame.K_DOWN]:
        move_x = -math.cos(player_angle) * 0.1
        move_y = -math.sin(player_angle) * 0.1
        new_x = player_x + move_x
        new_y = player_y + move_y
        # Boundary check to prevent moving outside the map
        if 0 <= int(new_x) < MAP_WIDTH and 0 <= int(new_y) < MAP_HEIGHT:
            player_x = new_x
            player_y = new_y

def render_scene():
    # Darken the sky color
    screen.fill((20, 20, 40))  # Dark blue sky

    # Draw dark ground
    pygame.draw.rect(screen, (10, 30, 10), (0, HALF_HEIGHT, WIDTH, HALF_HEIGHT))

    # List to store trees to render (distance, x position, y position, size)
    tree_sprites = []

    FOV = math.radians(60)
    half_FOV = FOV / 2

    # For each tree in the map, compute distance and angle to player
    for y in range(MAP_HEIGHT):
        for x in range(MAP_WIDTH):
            if map_data[y][x] == 1:  # Tree at this position
                # Position of tree center
                tree_x = x + 0.5
                tree_y = y + 0.5

                # Distance from player to tree
                dx = tree_x - player_x
                dy = tree_y - player_y
                dist = math.hypot(dx, dy)

                # Angle between player direction and tree
                theta = math.atan2(dy, dx)

                # Delta angle between player direction and tree
                delta_angle = theta - player_angle

                # Adjust delta_angle to be between -pi to pi
                delta_angle = (delta_angle + math.pi) % (2 * math.pi) - math.pi

                # If tree is within FOV
                if -half_FOV <= delta_angle <= half_FOV and dist > 0.5:
                    # Projected size depends on distance
                    proj_height = HEIGHT / (dist * math.cos(delta_angle) + 0.0001)

                    # Ensure projected height is positive and not too big
                    if proj_height <= 0 or proj_height > HEIGHT * 2:
                        continue

                    # Screen position
                    screen_x = HALF_WIDTH + (delta_angle) * (WIDTH / FOV) - proj_height / 2
                    screen_y = HALF_HEIGHT - proj_height / 2

                    # Append to list of sprites to render
                    tree_sprites.append((dist, screen_x, screen_y, proj_height))

    # Sort sprites by distance, farthest first
    tree_sprites.sort(key=lambda s: -s[0])

    # Draw the sprites
    for dist, screen_x, screen_y, proj_height in tree_sprites:
        # Scale the tree texture
        tree_image = pygame.transform.scale(tree_texture, (int(proj_height), int(proj_height)))
        tree_rect = tree_image.get_rect()
        tree_rect.x = int(screen_x)
        tree_rect.y = int(screen_y)

        # Darken the tree texture based on distance
        darkness = min(dist * 0.1, 0.7)  # Cap the darkness factor
        dark_surface = pygame.Surface(tree_image.get_size(), flags=pygame.SRCALPHA)
        dark_surface.fill((0, 0, 0, int(255 * darkness)))
        tree_image.blit(dark_surface, (0, 0), special_flags=pygame.BLEND_RGBA_SUB)

        # Blit the image if it's on the screen
        if tree_rect.right >= 0 and tree_rect.left <= WIDTH:
            screen.blit(tree_image, tree_rect)

generate_forest()

running = True
while running:
    clock.tick(FPS)
    handle_input()

    render_scene()

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    pygame.display.flip()

pygame.quit()

Add fog to the game, add lantern that our character equip and holding in hand (file: lantern.png), everything else keep the same without changes