Here's the code of my tetris game : 
import pygame
import random
import os

# Initialize Pygame and Mixer for sounds
pygame.init()
pygame.mixer.init()

# Define grid size
GRID_WIDTH = 10    # Standard Tetris has 10 columns
GRID_HEIGHT = 20   # Standard Tetris has 20 rows
BLOCK_SIZE = 30    # Size of the grid block

# Define margins and offsets
TITLE_HEIGHT = 80
SIDE_PANEL_MARGIN_TOP = 100
SIDE_PANEL_MARGIN_LEFT = GRID_WIDTH * BLOCK_SIZE + 40  # 10 columns * 30 + 40 for margin

# Screen dimensions (grid + side panel + margins)
SIDE_PANEL_WIDTH = 200
SCREEN_WIDTH = GRID_WIDTH * BLOCK_SIZE + SIDE_PANEL_WIDTH + 60  # Additional margin for aesthetics
SCREEN_HEIGHT = TITLE_HEIGHT + GRID_HEIGHT * BLOCK_SIZE + 40   # Additional margin for aesthetics

# Set up the display
win = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption('Tetris')

# Load Sounds (Ensure you have these sound files in a 'Sounds' directory)
MOVE_SOUND = pygame.mixer.Sound(os.path.join('Sounds', 'move.wav'))
ROTATE_SOUND = pygame.mixer.Sound(os.path.join('Sounds', 'rotate.wav'))
CLEAR_SOUND = pygame.mixer.Sound(os.path.join('Sounds', 'clear.wav'))
GAME_OVER_SOUND = pygame.mixer.Sound(os.path.join('Sounds', 'game_over.wav'))
BACKGROUND_MUSIC = os.path.join('Sounds', 'game.mp3')  # Path to background music

# Define paths for high score
HIGHSCORE_FILE = 'high_score.txt'

# Initialize high_score globally
high_score = 0

# Define shapes and their rotations
SHAPES = [
    [['.....',
      '..0..',
      '..0..',
      '..0..',
      '..0..'],
     ['.....',
      '0000.',
      '.....',
      '.....',
      '.....']],

    [['.....',
      '..00.',
      '..00.',
      '.....',
      '.....']],

    [['.....',
      '...0.',
      '.000.',
      '.....',
      '.....'],
     ['.....',
      '..0..',
      '..0..',
      '..00.',
      '.....'],
     ['.....',
      '.....',
      '.000.',
      '.0...',
      '.....'],
     ['.....',
      '.00..',
      '..0..',
      '..0..',
      '.....']],

    [['.....',
      '.0...',
      '.000.',
      '.....',
      '.....'],
     ['.....',
      '..00.',
      '..0..',
      '..0..',
      '.....'],
     ['.....',
      '.....',
      '.000.',
      '...0.',
      '.....'],
     ['.....',
      '..0..',
      '..0..',
      '.00..',
      '.....']],

    [['.....',
      '..0..',
      '.000.',
      '.....',
      '.....'],
     ['.....',
      '..0..',
      '..00.',
      '..0..',
      '.....'],
     ['.....',
      '.....',
      '.000.',
      '..0..',
      '.....'],
     ['.....',
      '..0..',
      '.00..',
      '..0..',
      '.....']],

    [['.....',
      '..0..',
      '..00.',
      '...0.',
      '.....'],
     ['.....',
      '...00',
      '..00.',
      '.....',
      '.....']],

    [['.....',
      '...0.',
      '..00.',
      '..0..',
      '.....'],
     ['.....',
      '..00.',
      '...00',
      '.....',
      '.....']]
]

# Define colors for each shape
SHAPE_COLORS = [
    (0, 255, 255),   # Cyan
    (255, 255, 0),   # Yellow
    (255, 165, 0),   # Orange
    (0, 0, 255),     # Blue
    (128, 0, 128),   # Purple
    (0, 255, 0),     # Green
    (255, 0, 0)       # Red
]

# Volume settings (0-10 scale)
music_volume = 5
sfx_volume = 5

class Piece:
    def __init__(self, x, y, shape):
        self.x = x
        self.y = y
        self.shape = shape
        self.color = SHAPE_COLORS[SHAPES.index(shape)]
        self.rotation = 0

def load_high_score():
    global high_score
    if os.path.exists(HIGHSCORE_FILE):
        with open(HIGHSCORE_FILE, 'r') as file:
            try:
                high_score = int(file.read())
            except:
                high_score = 0
    else:
        high_score = 0
    return high_score

def save_high_score(high_score):
    with open(HIGHSCORE_FILE, 'w') as file:
        file.write(str(high_score))

def create_grid(locked_positions={}):
    grid = [[(0, 0, 0) for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]

    for (j, i) in locked_positions:
        if 0 <= i < GRID_HEIGHT and 0 <= j < GRID_WIDTH:
            grid[i][j] = locked_positions[(j, i)]
    return grid

def convert_shape_format(piece):
    positions = []
    format = piece.shape[piece.rotation % len(piece.shape)]

    for i, line in enumerate(format):
        row = list(line)
        for j, column in enumerate(row):
            if column == '0':
                positions.append((piece.x + j - 2, piece.y + i - 4))

    # Normalize positions
    for i, pos in enumerate(positions):
        positions[i] = (pos[0], pos[1])

    return positions

def valid_space(piece, grid):
    accepted_positions = [[(j, i) for j in range(GRID_WIDTH) if grid[i][j] == (0, 0, 0)] for i in range(GRID_HEIGHT)]
    accepted_positions = [j for sub in accepted_positions for j in sub]

    formatted = convert_shape_format(piece)

    for pos in formatted:
        if pos not in accepted_positions:
            if pos[1] > -1:
                return False
    return True

def check_lost(positions):
    for pos in positions:
        x, y = pos
        if y < 1:
            return True
    return False

def get_shape():
    return Piece(GRID_WIDTH // 2, 0, random.choice(SHAPES))

def draw_text_middle(text, size, color, surface, y_offset=0):
    font = pygame.font.SysFont('comicsans', size, bold=True)
    label = font.render(text, 1, color)

    surface.blit(label, (
        (SCREEN_WIDTH / 2) - (label.get_width() / 2),
        (SCREEN_HEIGHT / 2) - (label.get_height() / 2) + y_offset
    ))

def draw_grid(surface, grid, offset_y=80):
    for i in range(GRID_HEIGHT):
        # Horizontal lines
        pygame.draw.line(surface, (128, 128, 128), 
                         (20, i * BLOCK_SIZE + offset_y), 
                         (20 + GRID_WIDTH * BLOCK_SIZE, i * BLOCK_SIZE + offset_y))
        for j in range(GRID_WIDTH):
            # Vertical lines
            pygame.draw.line(surface, (128, 128, 128), 
                             (j * BLOCK_SIZE + 20, offset_y), 
                             (j * BLOCK_SIZE + 20, GRID_HEIGHT * BLOCK_SIZE + offset_y))

def clear_rows(grid, locked):
    inc = 0
    lines_cleared = 0
    for i in range(len(grid)-1, -1, -1):
        row = grid[i]
        if (0, 0, 0) not in row:
            inc += 1
            lines_cleared += 1
            ind = i
            for j in range(len(row)):
                try:
                    del locked[(j, i)]
                except:
                    continue
    if inc > 0:
        # Play line clear sound
        CLEAR_SOUND.play()
        # Shift rows down
        for key in sorted(list(locked), key=lambda x: x[1])[::-1]:
            x, y = key
            if y < ind:
                newKey = (x, y + inc)
                locked[newKey] = locked.pop(key)
    return lines_cleared

def draw_next_shape(piece, surface):
    font = pygame.font.SysFont('comicsans', 30)
    label = font.render('Next Shape', 1, (255, 255, 255))

    sx = SIDE_PANEL_MARGIN_LEFT + 20
    sy = SIDE_PANEL_MARGIN_TOP + 100
    format = piece.shape[piece.rotation % len(piece.shape)]

    surface.blit(label, (sx, sy))
    
    for i, line in enumerate(format):
        row = list(line)
        for j, column in enumerate(row):
            if column == '0':
                # Draw block with shading
                block_rect = pygame.Rect(sx + j * BLOCK_SIZE, sy + 40 + i * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE)
                pygame.draw.rect(surface, piece.color, block_rect)
                pygame.draw.rect(surface, (0,0,0), block_rect, 2)  # Border for better visibility

def draw_window(surface, grid, lines_cleared, level, _):
    surface.fill((30, 30, 30))  # Dark background for better contrast
    
    # Draw the "Tetris" title above the grid
    font_title = pygame.font.SysFont('comicsans', 60, bold=True)
    label_title = font_title.render('Tetris', 1, (255, 255, 255))
    surface.blit(label_title, (SIDE_PANEL_MARGIN_LEFT // 2 - label_title.get_width() / 2, 10))
    
    # Display Score and Level in the side panel
    font_small = pygame.font.SysFont('comicsans', 30, bold=True)
    label_score = font_small.render(f'Score: {lines_cleared}', 1, (255, 255, 255))
    label_level = font_small.render(f'Level: {level}', 1, (255, 255, 255))
    surface.blit(label_score, (SIDE_PANEL_MARGIN_LEFT + 20, SIDE_PANEL_MARGIN_TOP))
    surface.blit(label_level, (SIDE_PANEL_MARGIN_LEFT + 20, SIDE_PANEL_MARGIN_TOP + 50))
    
    # Draw the grid blocks
    for i in range(len(grid)):
        for j in range(len(grid[i])):
            pygame.draw.rect(surface, grid[i][j], 
                             (j * BLOCK_SIZE + 20, i * BLOCK_SIZE + TITLE_HEIGHT, BLOCK_SIZE, BLOCK_SIZE), 0)
            # Add shading to blocks for 3D effect
            if grid[i][j] != (0,0,0):
                pygame.draw.rect(surface, (0,0,0), 
                                 (j * BLOCK_SIZE + 20, i * BLOCK_SIZE + TITLE_HEIGHT, BLOCK_SIZE, BLOCK_SIZE), 2)
    
    draw_grid(surface, grid, offset_y=TITLE_HEIGHT)
    
    # Draw border around the grid
    pygame.draw.rect(surface, (255, 255, 255), 
                     (20, TITLE_HEIGHT, GRID_WIDTH * BLOCK_SIZE, GRID_HEIGHT * BLOCK_SIZE), 5)
    
    # Draw border around side panel
    pygame.draw.rect(surface, (255, 255, 255), 
                     (SIDE_PANEL_MARGIN_LEFT, 0, SIDE_PANEL_WIDTH, SCREEN_HEIGHT), 5)

def play_background_music():
    if os.path.exists(BACKGROUND_MUSIC):
        pygame.mixer.music.load(BACKGROUND_MUSIC)
        pygame.mixer.music.set_volume(music_volume / 10)  # Adjust volume as needed
        pygame.mixer.music.play(-1)  # -1 for infinite loop
    else:
        print(f"Background music file not found: {BACKGROUND_MUSIC}")

def stop_background_music():
    pygame.mixer.music.stop()

# Slider Class for Options Menu
class Slider:
    def __init__(self, x, y, width, height, min_val, max_val, start_val=5, label=''):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.min_val = min_val
        self.max_val = max_val
        self.value = start_val
        self.knob_radius = height // 2
        self.knob_x = self.x + (self.value - self.min_val) / (self.max_val - self.min_val) * self.width
        self.knob_y = self.y + self.height // 2
        self.dragging = False
        self.label = label
    
    def draw(self, surface):
        # Draw the bar
        pygame.draw.rect(surface, (200,200,200), (self.x, self.y + self.height//4, self.width, self.height//2))
        # Draw the knob
        pygame.draw.circle(surface, (255, 255, 255), (int(self.knob_x), int(self.knob_y)), self.knob_radius)
        # Draw value
        font = pygame.font.SysFont('comicsans', 20)
        label = font.render(str(int(self.value)), 1, (255,255,255))
        surface.blit(label, (self.x + self.width + 10, self.y - self.height//2))
        # Draw slider label
        if self.label:
            label_text = font.render(self.label, 1, (255,255,255))
            surface.blit(label_text, (self.x, self.y - 30))  # Position above the slider
    
    def handle_event(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN:
            mouse_x, mouse_y = event.pos
            distance = ((mouse_x - self.knob_x)**2 + (mouse_y - self.knob_y)**2)**0.5
            if distance <= self.knob_radius:
                self.dragging = True
        elif event.type == pygame.MOUSEBUTTONUP:
            self.dragging = False
        elif event.type == pygame.MOUSEMOTION:
            if self.dragging:
                mouse_x = event.pos[0]
                # Clamp mouse_x to the slider bar
                self.knob_x = max(self.x, min(mouse_x, self.x + self.width))
                # Update value accordingly
                ratio = (self.knob_x - self.x) / self.width
                self.value = self.min_val + ratio * (self.max_val - self.min_val)
                # Round to nearest integer
                self.value = int(round(self.value))

def set_sfx_volume(volume):
    global sfx_volume
    sfx_volume = volume
    MOVE_SOUND.set_volume(sfx_volume / 10)
    ROTATE_SOUND.set_volume(sfx_volume / 10)
    CLEAR_SOUND.set_volume(sfx_volume / 10)
    GAME_OVER_SOUND.set_volume(sfx_volume / 10)

def set_music_volume(volume):
    global music_volume
    music_volume = volume
    pygame.mixer.music.set_volume(music_volume / 10)

def main():
    global high_score
    locked_positions = {}
    grid = create_grid(locked_positions)

    change_piece = False
    run = True
    current_piece = get_shape()
    next_piece = get_shape()
    clock = pygame.time.Clock()
    fall_time = 0

    BASE_FALL_SPEED = 0.5  # Base fall speed in seconds
    fall_speed = BASE_FALL_SPEED
    lines_cleared = 0  # Initialize lines cleared counter
    level = 1  # Initialize level

    paused = False  # Game paused state

    # Load high score
    high_score = load_high_score()

    the_music_started = False  # To ensure music starts only once

    while run:
        grid = create_grid(locked_positions)
        fall_time += clock.get_rawtime()
        clock.tick()

        # Calculate current level based on lines cleared
        new_level = (lines_cleared // 10) + 1
        if new_level != level:
            level = new_level
            fall_speed *= 1.15  # Increase speed by 15% each level

        # Adjust fall speed
        current_fall_speed = fall_speed
        keys = pygame.key.get_pressed()

        if keys[pygame.K_DOWN]:
            current_fall_speed = 0.05  # Fast fall when down key is held

        if fall_time / 1000 >= current_fall_speed:
            fall_time = 0
            current_piece.y += 1
            if not valid_space(current_piece, grid) and current_piece.y > 0:
                current_piece.y -= 1
                change_piece = True
                MOVE_SOUND.play()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.display.quit()
                quit()

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    current_piece.x -= 1
                    if not valid_space(current_piece, grid):
                        current_piece.x += 1
                    else:
                        MOVE_SOUND.play()
                elif event.key == pygame.K_RIGHT:
                    current_piece.x += 1
                    if not valid_space(current_piece, grid):
                        current_piece.x -= 1
                    else:
                        MOVE_SOUND.play()
                elif event.key == pygame.K_DOWN:
                    current_piece.y += 1
                    if not valid_space(current_piece, grid):
                        current_piece.y -= 1
                elif event.key == pygame.K_UP:
                    current_piece.rotation = (current_piece.rotation + 1) % len(current_piece.shape)
                    if not valid_space(current_piece, grid):
                        current_piece.rotation = (current_piece.rotation - 1) % len(current_piece.shape)
                    else:
                        ROTATE_SOUND.play()
                elif event.key == pygame.K_SPACE:
                    paused = not paused  # Toggle pause

        if paused:
            pause_screen(win)
            continue  # Skip the rest of the loop to effectively pause

        shape_pos = convert_shape_format(current_piece)

        # Add piece to the grid for drawing
        for i in range(len(shape_pos)):
            x, y = shape_pos[i]
            if y > -1:
                if 0 <= x < GRID_WIDTH and 0 <= y < GRID_HEIGHT:
                    grid[y][x] = current_piece.color

        if change_piece:
            for pos in shape_pos:
                p = (pos[0], pos[1])
                if 0 <= p[0] < GRID_WIDTH and 0 <= p[1] < GRID_HEIGHT:
                    locked_positions[p] = current_piece.color
            current_piece = next_piece
            next_piece = get_shape()
            change_piece = False

            cleared = clear_rows(grid, locked_positions)
            lines_cleared += cleared  # Update lines cleared

        # Start background music once when the game starts
        if not the_music_started:
            play_background_music()
            the_music_started = True

        # Draw window without passing high_score (no display during game)
        draw_window(win, grid, lines_cleared, level, high_score)  # Modify the function to ignore high_score
        draw_next_shape(next_piece, win)
        pygame.display.update()

        if check_lost(locked_positions):
            GAME_OVER_SOUND.play()
            pygame.time.delay(500)
            run = False
            stop_background_music()
            update_high_score_if_needed(lines_cleared)

    game_over_screen(win, lines_cleared, high_score)

def update_high_score_if_needed(current_score):
    global high_score
    if current_score > high_score:
        high_score = current_score
        save_high_score(high_score)

def game_over_screen(surface, final_score, _):
    # Update high score if necessary
    if final_score > high_score:
        high_score = final_score
        save_high_score(high_score)

    pygame.mixer.music.stop()  # Ensure music is stopped on game over

    while True:
        surface.fill((0, 0, 0))
        draw_text_middle("YOU LOST!", 60, (255, 255, 255), surface, y_offset=-50)
        
        # Display final score
        font_small = pygame.font.SysFont('comicsans', 30)
        score_label = font_small.render(f'Your Score: {final_score}', 1, (255, 255, 255))
        surface.blit(score_label, ((SCREEN_WIDTH / 2) - (score_label.get_width() / 2), (SCREEN_HEIGHT / 2) - 10))
        
        # Prompt to return to menu
        prompt_label = font_small.render('Press Space to return to the menu.', 1, (255, 255, 255))
        surface.blit(prompt_label, ((SCREEN_WIDTH / 2) - (prompt_label.get_width() / 2), (SCREEN_HEIGHT / 2) + 30))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    main_menu()  # Return to main menu

def pause_screen(surface):
    pause_font = pygame.font.SysFont('comicsans', 40, bold=True)
    pause_label = pause_font.render('Game Paused', 1, (255, 255, 255))
    prompt_font = pygame.font.SysFont('comicsans', 20)
    prompt_label = prompt_font.render('Press Space to Resume', 1, (255, 255, 255))
    
    surface.blit(pause_label, ((SCREEN_WIDTH / 2) - (pause_label.get_width() / 2), SCREEN_HEIGHT / 2 - 30))
    surface.blit(prompt_label, ((SCREEN_WIDTH / 2) - (prompt_label.get_width() / 2), SCREEN_HEIGHT / 2 + 10))
    pygame.display.update()

def main_menu():
    global high_score
    load_high_score()  # Ensure high_score is loaded before displaying menu
    run = True
    while run:
        win.fill((0, 0, 0))
        
        # Draw the "Tetris" title
        font_title = pygame.font.SysFont('comicsans', 60, bold=True)
        title_label = font_title.render('Tetris', 1, (255, 255, 255))
        win.blit(title_label, (SCREEN_WIDTH / 2 - title_label.get_width() / 2, 100))
        
        # Display High Score
        font_high = pygame.font.SysFont('comicsans', 30, bold=True)
        high_label = font_high.render(f'High Score: {high_score}', 1, (255, 255, 255))
        win.blit(high_label, (SCREEN_WIDTH / 2 - high_label.get_width() / 2, 200))
        
        # Display menu options
        font_options = pygame.font.SysFont('comicsans', 30)
        option1 = font_options.render('1: New Game', 1, (255, 255, 255))
        option2 = font_options.render('2: Options', 1, (255, 255, 255))
        option3 = font_options.render('3: Exit', 1, (255, 255, 255))
        
        win.blit(option1, (SCREEN_WIDTH / 2 - option1.get_width() / 2, 300))
        win.blit(option2, (SCREEN_WIDTH / 2 - option2.get_width() / 2, 350))
        win.blit(option3, (SCREEN_WIDTH / 2 - option3.get_width() / 2, 400))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_1:
                    main()  # Start new game
                elif event.key == pygame.K_2:
                    options_menu()  # Open options menu
                elif event.key == pygame.K_3:
                    run = False
                    pygame.quit()
                    quit()
    pygame.quit()

def options_menu():
    global music_volume, sfx_volume
    run = True
    # Create sliders: (x, y, width, height, min_val, max_val, start_val, label)
    music_slider = Slider(SCREEN_WIDTH / 2 - 100, 150, 200, 20, 0, 10, music_volume, 'Music Volume')
    sfx_slider = Slider(SCREEN_WIDTH / 2 - 100, 250, 200, 20, 0, 10, sfx_volume, 'SFX Volume')
    
    while run:
        win.fill((0, 0, 0))
        
        # Draw the "Options" title
        font_title = pygame.font.SysFont('comicsans', 60, bold=True)
        title_label = font_title.render('Options', 1, (255, 255, 255))
        win.blit(title_label, (SCREEN_WIDTH / 2 - title_label.get_width() / 2, 50))
        
        # Draw sliders
        music_slider.draw(win)
        sfx_slider.draw(win)
        
        # Instructions to return to main menu
        font_instruct = pygame.font.SysFont('comicsans', 25)
        instruct_label = font_instruct.render('Press Esc to return to the main menu.', 1, (255, 255, 255))
        win.blit(instruct_label, (SCREEN_WIDTH / 2 - instruct_label.get_width() / 2, 400))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.display.quit()
                quit()
            # Handle slider events
            music_slider.handle_event(event)
            sfx_slider.handle_event(event)
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    # Update volume settings
                    set_music_volume(music_slider.value)
                    set_sfx_volume(sfx_slider.value)
                    run = False  # Exit options_menu
    # Do NOT call pygame.quit() here. Instead, return to main_menu
    # pygame.quit()  # Removed to prevent crashing

def set_sfx_volume(volume):
    global sfx_volume
    sfx_volume = volume
    MOVE_SOUND.set_volume(sfx_volume / 10)
    ROTATE_SOUND.set_volume(sfx_volume / 10)
    CLEAR_SOUND.set_volume(sfx_volume / 10)
    GAME_OVER_SOUND.set_volume(sfx_volume / 10)

def set_music_volume(volume):
    global music_volume
    music_volume = volume
    pygame.mixer.music.set_volume(music_volume / 10)

def main():
    global high_score
    locked_positions = {}
    grid = create_grid(locked_positions)

    change_piece = False
    run = True
    current_piece = get_shape()
    next_piece = get_shape()
    clock = pygame.time.Clock()
    fall_time = 0

    BASE_FALL_SPEED = 0.5  # Base fall speed in seconds
    fall_speed = BASE_FALL_SPEED
    lines_cleared = 0  # Initialize lines cleared counter
    level = 1  # Initialize level

    paused = False  # Game paused state

    the_music_started = False  # To ensure music starts only once

    while run:
        grid = create_grid(locked_positions)
        fall_time += clock.get_rawtime()
        clock.tick()

        # Calculate current level based on lines cleared
        new_level = (lines_cleared // 10) + 1
        if new_level != level:
            level = new_level
            fall_speed *= 1.15  # Increase speed by 15% each level

        # Adjust fall speed
        current_fall_speed = fall_speed
        keys = pygame.key.get_pressed()

        if keys[pygame.K_DOWN]:
            current_fall_speed = 0.05  # Fast fall when down key is held

        if fall_time / 1000 >= current_fall_speed:
            fall_time = 0
            current_piece.y += 1
            if not valid_space(current_piece, grid) and current_piece.y > 0:
                current_piece.y -= 1
                change_piece = True
                MOVE_SOUND.play()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.display.quit()
                quit()

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    current_piece.x -= 1
                    if not valid_space(current_piece, grid):
                        current_piece.x += 1
                    else:
                        MOVE_SOUND.play()
                elif event.key == pygame.K_RIGHT:
                    current_piece.x += 1
                    if not valid_space(current_piece, grid):
                        current_piece.x -= 1
                    else:
                        MOVE_SOUND.play()
                elif event.key == pygame.K_DOWN:
                    current_piece.y += 1
                    if not valid_space(current_piece, grid):
                        current_piece.y -= 1
                elif event.key == pygame.K_UP:
                    current_piece.rotation = (current_piece.rotation + 1) % len(current_piece.shape)
                    if not valid_space(current_piece, grid):
                        current_piece.rotation = (current_piece.rotation - 1) % len(current_piece.shape)
                    else:
                        ROTATE_SOUND.play()
                elif event.key == pygame.K_SPACE:
                    paused = not paused  # Toggle pause

        if paused:
            pause_screen(win)
            continue  # Skip the rest of the loop to effectively pause

        shape_pos = convert_shape_format(current_piece)

        # Add piece to the grid for drawing
        for i in range(len(shape_pos)):
            x, y = shape_pos[i]
            if y > -1:
                if 0 <= x < GRID_WIDTH and 0 <= y < GRID_HEIGHT:
                    grid[y][x] = current_piece.color

        if change_piece:
            for pos in shape_pos:
                p = (pos[0], pos[1])
                if 0 <= p[0] < GRID_WIDTH and 0 <= p[1] < GRID_HEIGHT:
                    locked_positions[p] = current_piece.color
            current_piece = next_piece
            next_piece = get_shape()
            change_piece = False

            cleared = clear_rows(grid, locked_positions)
            lines_cleared += cleared  # Update lines cleared

        # Start background music once when the game starts
        if not the_music_started:
            play_background_music()
            the_music_started = True

        draw_window(win, grid, lines_cleared, level, high_score)
        draw_next_shape(next_piece, win)
        pygame.display.update()

        if check_lost(locked_positions):
            GAME_OVER_SOUND.play()
            pygame.time.delay(500)
            run = False
            stop_background_music()
            update_high_score_if_needed(lines_cleared)

    game_over_screen(win, lines_cleared, high_score)

def update_high_score_if_needed(current_score):
    global high_score
    if current_score > high_score:
        high_score = current_score
        save_high_score(high_score)

def game_over_screen(surface, final_score, _):
    # Update high score if necessary
    if final_score > high_score:
        high_score = final_score
        save_high_score(high_score)

    pygame.mixer.music.stop()  # Ensure music is stopped on game over

    while True:
        surface.fill((0, 0, 0))
        draw_text_middle("YOU LOST!", 60, (255, 255, 255), surface, y_offset=-50)
        
        # Display final score
        font_small = pygame.font.SysFont('comicsans', 30)
        score_label = font_small.render(f'Your Score: {final_score}', 1, (255, 255, 255))
        surface.blit(score_label, ((SCREEN_WIDTH / 2) - (score_label.get_width() / 2), (SCREEN_HEIGHT / 2) - 10))
        
        # Prompt to return to menu
        prompt_label = font_small.render('Press Space to return to the menu.', 1, (255, 255, 255))
        surface.blit(prompt_label, ((SCREEN_WIDTH / 2) - (prompt_label.get_width() / 2), (SCREEN_HEIGHT / 2) + 30))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    main_menu()  # Return to main menu

def pause_screen(surface):
    pause_font = pygame.font.SysFont('comicsans', 40, bold=True)
    pause_label = pause_font.render('Game Paused', 1, (255, 255, 255))
    prompt_font = pygame.font.SysFont('comicsans', 20)
    prompt_label = prompt_font.render('Press Space to Resume', 1, (255, 255, 255))
    
    surface.blit(pause_label, ((SCREEN_WIDTH / 2) - (pause_label.get_width() / 2), SCREEN_HEIGHT / 2 - 30))
    surface.blit(prompt_label, ((SCREEN_WIDTH / 2) - (prompt_label.get_width() / 2), SCREEN_HEIGHT / 2 + 10))
    pygame.display.update()

def main_menu():
    global high_score
    load_high_score()  # Ensure high_score is loaded before displaying menu
    run = True
    while run:
        win.fill((0, 0, 0))
        
        # Draw the "Tetris" title
        font_title = pygame.font.SysFont('comicsans', 60, bold=True)
        title_label = font_title.render('Tetris', 1, (255, 255, 255))
        win.blit(title_label, (SCREEN_WIDTH / 2 - title_label.get_width() / 2, 100))
        
        # Display High Score
        font_high = pygame.font.SysFont('comicsans', 30, bold=True)
        high_label = font_high.render(f'High Score: {high_score}', 1, (255, 255, 255))
        win.blit(high_label, (SCREEN_WIDTH / 2 - high_label.get_width() / 2, 200))
        
        # Display menu options
        font_options = pygame.font.SysFont('comicsans', 30)
        option1 = font_options.render('1: New Game', 1, (255, 255, 255))
        option2 = font_options.render('2: Options', 1, (255, 255, 255))
        option3 = font_options.render('3: Exit', 1, (255, 255, 255))
        
        win.blit(option1, (SCREEN_WIDTH / 2 - option1.get_width() / 2, 300))
        win.blit(option2, (SCREEN_WIDTH / 2 - option2.get_width() / 2, 350))
        win.blit(option3, (SCREEN_WIDTH / 2 - option3.get_width() / 2, 400))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_1:
                    main()  # Start new game
                elif event.key == pygame.K_2:
                    options_menu()  # Open options menu
                elif event.key == pygame.K_3:
                    run = False
                    pygame.quit()
                    quit()
    pygame.quit()

def options_menu():
    global music_volume, sfx_volume
    run = True
    # Create sliders: (x, y, width, height, min_val, max_val, start_val, label)
    music_slider = Slider(SCREEN_WIDTH / 2 - 100, 150, 200, 20, 0, 10, music_volume, 'Music Volume')
    sfx_slider = Slider(SCREEN_WIDTH / 2 - 100, 250, 200, 20, 0, 10, sfx_volume, 'SFX Volume')
    
    while run:
        win.fill((0, 0, 0))
        
        # Draw the "Options" title
        font_title = pygame.font.SysFont('comicsans', 60, bold=True)
        title_label = font_title.render('Options', 1, (255, 255, 255))
        win.blit(title_label, (SCREEN_WIDTH / 2 - title_label.get_width() / 2, 50))
        
        # Draw sliders
        music_slider.draw(win)
        sfx_slider.draw(win)
        
        # Instructions to return to main menu
        font_instruct = pygame.font.SysFont('comicsans', 25)
        instruct_label = font_instruct.render('Press Esc to return to the main menu.', 1, (255, 255, 255))
        win.blit(instruct_label, (SCREEN_WIDTH / 2 - instruct_label.get_width() / 2, 400))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.display.quit()
                quit()
            # Handle slider events
            music_slider.handle_event(event)
            sfx_slider.handle_event(event)
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    # Update volume settings
                    set_music_volume(music_slider.value)
                    set_sfx_volume(sfx_slider.value)
                    run = False  # Exit options_menu
    # Do NOT call pygame.quit() here. Instead, return to main_menu
    # pygame.quit()  # Removed to prevent crashing

def set_sfx_volume(volume):
    global sfx_volume
    sfx_volume = volume
    MOVE_SOUND.set_volume(sfx_volume / 10)
    ROTATE_SOUND.set_volume(sfx_volume / 10)
    CLEAR_SOUND.set_volume(sfx_volume / 10)
    GAME_OVER_SOUND.set_volume(sfx_volume / 10)

def set_music_volume(volume):
    global music_volume
    music_volume = volume
    pygame.mixer.music.set_volume(music_volume / 10)

def main():
    global high_score
    locked_positions = {}
    grid = create_grid(locked_positions)

    change_piece = False
    run = True
    current_piece = get_shape()
    next_piece = get_shape()
    clock = pygame.time.Clock()
    fall_time = 0

    BASE_FALL_SPEED = 0.5  # Base fall speed in seconds
    fall_speed = BASE_FALL_SPEED
    lines_cleared = 0  # Initialize lines cleared counter
    level = 1  # Initialize level

    paused = False  # Game paused state

    the_music_started = False  # To ensure music starts only once

    while run:
        grid = create_grid(locked_positions)
        fall_time += clock.get_rawtime()
        clock.tick()

        # Calculate current level based on lines cleared
        new_level = (lines_cleared // 10) + 1
        if new_level != level:
            level = new_level
            fall_speed *= 1.15  # Increase speed by 15% each level

        # Adjust fall speed
        current_fall_speed = fall_speed
        keys = pygame.key.get_pressed()

        if keys[pygame.K_DOWN]:
            current_fall_speed = 0.05  # Fast fall when down key is held

        if fall_time / 1000 >= current_fall_speed:
            fall_time = 0
            current_piece.y += 1
            if not valid_space(current_piece, grid) and current_piece.y > 0:
                current_piece.y -= 1
                change_piece = True
                MOVE_SOUND.play()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.display.quit()
                quit()

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    current_piece.x -= 1
                    if not valid_space(current_piece, grid):
                        current_piece.x += 1
                    else:
                        MOVE_SOUND.play()
                elif event.key == pygame.K_RIGHT:
                    current_piece.x += 1
                    if not valid_space(current_piece, grid):
                        current_piece.x -= 1
                    else:
                        MOVE_SOUND.play()
                elif event.key == pygame.K_DOWN:
                    current_piece.y += 1
                    if not valid_space(current_piece, grid):
                        current_piece.y -= 1
                elif event.key == pygame.K_UP:
                    current_piece.rotation = (current_piece.rotation + 1) % len(current_piece.shape)
                    if not valid_space(current_piece, grid):
                        current_piece.rotation = (current_piece.rotation - 1) % len(current_piece.shape)
                    else:
                        ROTATE_SOUND.play()
                elif event.key == pygame.K_SPACE:
                    paused = not paused  # Toggle pause

        if paused:
            pause_screen(win)
            continue  # Skip the rest of the loop to effectively pause

        shape_pos = convert_shape_format(current_piece)

        # Add piece to the grid for drawing
        for i in range(len(shape_pos)):
            x, y = shape_pos[i]
            if y > -1:
                if 0 <= x < GRID_WIDTH and 0 <= y < GRID_HEIGHT:
                    grid[y][x] = current_piece.color

        if change_piece:
            for pos in shape_pos:
                p = (pos[0], pos[1])
                if 0 <= p[0] < GRID_WIDTH and 0 <= p[1] < GRID_HEIGHT:
                    locked_positions[p] = current_piece.color
            current_piece = next_piece
            next_piece = get_shape()
            change_piece = False

            cleared = clear_rows(grid, locked_positions)
            lines_cleared += cleared  # Update lines cleared

        # Start background music once when the game starts
        if not the_music_started:
            play_background_music()
            the_music_started = True

        draw_window(win, grid, lines_cleared, level, high_score)  # Removed high_score from in-game display
        draw_next_shape(next_piece, win)
        pygame.display.update()

        if check_lost(locked_positions):
            GAME_OVER_SOUND.play()
            pygame.time.delay(500)
            run = False
            stop_background_music()
            update_high_score_if_needed(lines_cleared)

    game_over_screen(win, lines_cleared, high_score)

def update_high_score_if_needed(current_score):
    global high_score
    if current_score > high_score:
        high_score = current_score
        save_high_score(high_score)

def game_over_screen(surface, final_score, _):
    # Update high score if necessary
    if final_score > high_score:
        high_score = final_score
        save_high_score(high_score)

    pygame.mixer.music.stop()  # Ensure music is stopped on game over

    while True:
        surface.fill((0, 0, 0))
        draw_text_middle("YOU LOST!", 60, (255, 255, 255), surface, y_offset=-50)
        
        # Display final score
        font_small = pygame.font.SysFont('comicsans', 30)
        score_label = font_small.render(f'Your Score: {final_score}', 1, (255, 255, 255))
        surface.blit(score_label, ((SCREEN_WIDTH / 2) - (score_label.get_width() / 2), (SCREEN_HEIGHT / 2) - 10))
        
        # Prompt to return to menu
        prompt_label = font_small.render('Press Space to return to the menu.', 1, (255, 255, 255))
        surface.blit(prompt_label, ((SCREEN_WIDTH / 2) - (prompt_label.get_width() / 2), (SCREEN_HEIGHT / 2) + 30))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    main_menu()  # Return to main menu

def pause_screen(surface):
    pause_font = pygame.font.SysFont('comicsans', 40, bold=True)
    pause_label = pause_font.render('Game Paused', 1, (255, 255, 255))
    prompt_font = pygame.font.SysFont('comicsans', 20)
    prompt_label = prompt_font.render('Press Space to Resume', 1, (255, 255, 255))
    
    surface.blit(pause_label, ((SCREEN_WIDTH / 2) - (pause_label.get_width() / 2), SCREEN_HEIGHT / 2 - 30))
    surface.blit(prompt_label, ((SCREEN_WIDTH / 2) - (prompt_label.get_width() / 2), SCREEN_HEIGHT / 2 + 10))
    pygame.display.update()

def main_menu():
    global high_score
    load_high_score()  # Ensure high_score is loaded before displaying menu
    run = True
    while run:
        win.fill((0, 0, 0))
        
        # Draw the "Tetris" title
        font_title = pygame.font.SysFont('comicsans', 60, bold=True)
        title_label = font_title.render('Tetris', 1, (255, 255, 255))
        win.blit(title_label, (SCREEN_WIDTH / 2 - title_label.get_width() / 2, 100))
        
        # Display High Score
        font_high = pygame.font.SysFont('comicsans', 30, bold=True)
        high_label = font_high.render(f'High Score: {high_score}', 1, (255, 255, 255))
        win.blit(high_label, (SCREEN_WIDTH / 2 - high_label.get_width() / 2, 200))
        
        # Display menu options
        font_options = pygame.font.SysFont('comicsans', 30)
        option1 = font_options.render('1: New Game', 1, (255, 255, 255))
        option2 = font_options.render('2: Options', 1, (255, 255, 255))
        option3 = font_options.render('3: Exit', 1, (255, 255, 255))
        
        win.blit(option1, (SCREEN_WIDTH / 2 - option1.get_width() / 2, 300))
        win.blit(option2, (SCREEN_WIDTH / 2 - option2.get_width() / 2, 350))
        win.blit(option3, (SCREEN_WIDTH / 2 - option3.get_width() / 2, 400))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_1:
                    main()  # Start new game
                elif event.key == pygame.K_2:
                    options_menu()  # Open options menu
                elif event.key == pygame.K_3:
                    run = False
                    pygame.quit()
                    quit()
    pygame.quit()

def options_menu():
    global music_volume, sfx_volume
    run = True
    # Create sliders: (x, y, width, height, min_val, max_val, start_val, label)
    music_slider = Slider(SCREEN_WIDTH / 2 - 100, 150, 200, 20, 0, 10, music_volume, 'Music Volume')
    sfx_slider = Slider(SCREEN_WIDTH / 2 - 100, 250, 200, 20, 0, 10, sfx_volume, 'SFX Volume')
    
    while run:
        win.fill((0, 0, 0))
        
        # Draw the "Options" title
        font_title = pygame.font.SysFont('comicsans', 60, bold=True)
        title_label = font_title.render('Options', 1, (255, 255, 255))
        win.blit(title_label, (SCREEN_WIDTH / 2 - title_label.get_width() / 2, 50))
        
        # Draw sliders
        music_slider.draw(win)
        sfx_slider.draw(win)
        
        # Instructions to return to main menu
        font_instruct = pygame.font.SysFont('comicsans', 25)
        instruct_label = font_instruct.render('Press Esc to return to the main menu.', 1, (255, 255, 255))
        win.blit(instruct_label, (SCREEN_WIDTH / 2 - instruct_label.get_width() / 2, 400))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.display.quit()
                quit()
            # Handle slider events
            music_slider.handle_event(event)
            sfx_slider.handle_event(event)
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    # Update volume settings
                    set_music_volume(music_slider.value)
                    set_sfx_volume(sfx_slider.value)
                    run = False  # Exit options_menu
    # Do NOT call pygame.quit() here. Instead, return to main_menu
    # pygame.quit()  # Removed to prevent crashing

def set_sfx_volume(volume):
    global sfx_volume
    sfx_volume = volume
    MOVE_SOUND.set_volume(sfx_volume / 10)
    ROTATE_SOUND.set_volume(sfx_volume / 10)
    CLEAR_SOUND.set_volume(sfx_volume / 10)
    GAME_OVER_SOUND.set_volume(sfx_volume / 10)

def set_music_volume(volume):
    global music_volume
    music_volume = volume
    pygame.mixer.music.set_volume(music_volume / 10)

def main():
    global high_score
    locked_positions = {}
    grid = create_grid(locked_positions)

    change_piece = False
    run = True
    current_piece = get_shape()
    next_piece = get_shape()
    clock = pygame.time.Clock()
    fall_time = 0

    BASE_FALL_SPEED = 0.5  # Base fall speed in seconds
    fall_speed = BASE_FALL_SPEED
    lines_cleared = 0  # Initialize lines cleared counter
    level = 1  # Initialize level

    paused = False  # Game paused state

    the_music_started = False  # To ensure music starts only once

    while run:
        grid = create_grid(locked_positions)
        fall_time += clock.get_rawtime()
        clock.tick()

        # Calculate current level based on lines cleared
        new_level = (lines_cleared // 10) + 1
        if new_level != level:
            level = new_level
            fall_speed *= 1.15  # Increase speed by 15% each level

        # Adjust fall speed
        current_fall_speed = fall_speed
        keys = pygame.key.get_pressed()

        if keys[pygame.K_DOWN]:
            current_fall_speed = 0.05  # Fast fall when down key is held

        if fall_time / 1000 >= current_fall_speed:
            fall_time = 0
            current_piece.y += 1
            if not valid_space(current_piece, grid) and current_piece.y > 0:
                current_piece.y -= 1
                change_piece = True
                MOVE_SOUND.play()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.display.quit()
                quit()

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    current_piece.x -= 1
                    if not valid_space(current_piece, grid):
                        current_piece.x += 1
                    else:
                        MOVE_SOUND.play()
                elif event.key == pygame.K_RIGHT:
                    current_piece.x += 1
                    if not valid_space(current_piece, grid):
                        current_piece.x -= 1
                    else:
                        MOVE_SOUND.play()
                elif event.key == pygame.K_DOWN:
                    current_piece.y += 1
                    if not valid_space(current_piece, grid):
                        current_piece.y -= 1
                elif event.key == pygame.K_UP:
                    current_piece.rotation = (current_piece.rotation + 1) % len(current_piece.shape)
                    if not valid_space(current_piece, grid):
                        current_piece.rotation = (current_piece.rotation - 1) % len(current_piece.shape)
                    else:
                        ROTATE_SOUND.play()
                elif event.key == pygame.K_SPACE:
                    paused = not paused  # Toggle pause

        if paused:
            pause_screen(win)
            continue  # Skip the rest of the loop to effectively pause

        shape_pos = convert_shape_format(current_piece)

        # Add piece to the grid for drawing
        for i in range(len(shape_pos)):
            x, y = shape_pos[i]
            if y > -1:
                if 0 <= x < GRID_WIDTH and 0 <= y < GRID_HEIGHT:
                    grid[y][x] = current_piece.color

        if change_piece:
            for pos in shape_pos:
                p = (pos[0], pos[1])
                if 0 <= p[0] < GRID_WIDTH and 0 <= p[1] < GRID_HEIGHT:
                    locked_positions[p] = current_piece.color
            current_piece = next_piece
            next_piece = get_shape()
            change_piece = False

            cleared = clear_rows(grid, locked_positions)
            lines_cleared += cleared  # Update lines cleared

        # Start background music once when the game starts
        if not the_music_started:
            play_background_music()
            the_music_started = True

        draw_window(win, grid, lines_cleared, level, high_score)  # Removed high_score from in-game display
        draw_next_shape(next_piece, win)
        pygame.display.update()

        if check_lost(locked_positions):
            GAME_OVER_SOUND.play()
            pygame.time.delay(500)
            run = False
            stop_background_music()
            update_high_score_if_needed(lines_cleared)

    game_over_screen(win, lines_cleared, high_score)

def update_high_score_if_needed(current_score):
    global high_score
    if current_score > high_score:
        high_score = current_score
        save_high_score(high_score)

def game_over_screen(surface, final_score, _):
    global high_score
    # Update high score if necessary
    if final_score > high_score:
        high_score = final_score
        save_high_score(high_score)

    pygame.mixer.music.stop()  # Ensure music is stopped on game over

    while True:
        surface.fill((0, 0, 0))
        draw_text_middle("YOU LOST!", 60, (255, 255, 255), surface, y_offset=-50)
        
        # Display final score
        font_small = pygame.font.SysFont('comicsans', 30)
        score_label = font_small.render(f'Your Score: {final_score}', 1, (255, 255, 255))
        surface.blit(score_label, ((SCREEN_WIDTH / 2) - (score_label.get_width() / 2), (SCREEN_HEIGHT / 2) - 10))
        
        # Prompt to return to menu
        prompt_label = font_small.render('Press Space to return to the menu.', 1, (255, 255, 255))
        surface.blit(prompt_label, ((SCREEN_WIDTH / 2) - (prompt_label.get_width() / 2), (SCREEN_HEIGHT / 2) + 30))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    main_menu()  # Return to main menu

def pause_screen(surface):
    pause_font = pygame.font.SysFont('comicsans', 40, bold=True)
    pause_label = pause_font.render('Game Paused', 1, (255, 255, 255))
    prompt_font = pygame.font.SysFont('comicsans', 20)
    prompt_label = prompt_font.render('Press Space to Resume', 1, (255, 255, 255))
    
    surface.blit(pause_label, ((SCREEN_WIDTH / 2) - (pause_label.get_width() / 2), SCREEN_HEIGHT / 2 - 30))
    surface.blit(prompt_label, ((SCREEN_WIDTH / 2) - (prompt_label.get_width() / 2), SCREEN_HEIGHT / 2 + 10))
    pygame.display.update()

def main_menu():
    global high_score
    load_high_score()  # Ensure high_score is loaded before displaying menu
    run = True
    while run:
        win.fill((0, 0, 0))
        
        # Draw the "Tetris" title
        font_title = pygame.font.SysFont('comicsans', 60, bold=True)
        title_label = font_title.render('Tetris', 1, (255, 255, 255))
        win.blit(title_label, (SCREEN_WIDTH / 2 - title_label.get_width() / 2, 100))
        
        # Display High Score
        font_high = pygame.font.SysFont('comicsans', 30, bold=True)
        high_label = font_high.render(f'High Score: {high_score}', 1, (255, 255, 255))
        win.blit(high_label, (SCREEN_WIDTH / 2 - high_label.get_width() / 2, 200))
        
        # Display menu options
        font_options = pygame.font.SysFont('comicsans', 30)
        option1 = font_options.render('1: New Game', 1, (255, 255, 255))
        option2 = font_options.render('2: Options', 1, (255, 255, 255))
        option3 = font_options.render('3: Exit', 1, (255, 255, 255))
        
        win.blit(option1, (SCREEN_WIDTH / 2 - option1.get_width() / 2, 300))
        win.blit(option2, (SCREEN_WIDTH / 2 - option2.get_width() / 2, 350))
        win.blit(option3, (SCREEN_WIDTH / 2 - option3.get_width() / 2, 400))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_1:
                    main()  # Start new game
                elif event.key == pygame.K_2:
                    options_menu()  # Open options menu
                elif event.key == pygame.K_3:
                    run = False
                    pygame.quit()
                    quit()
    pygame.quit()

def options_menu():
    global music_volume, sfx_volume
    run = True
    # Create sliders: (x, y, width, height, min_val, max_val, start_val, label)
    music_slider = Slider(SCREEN_WIDTH / 2 - 100, 150, 200, 20, 0, 10, music_volume, 'Music Volume')
    sfx_slider = Slider(SCREEN_WIDTH / 2 - 100, 250, 200, 20, 0, 10, sfx_volume, 'SFX Volume')
    
    while run:
        win.fill((0, 0, 0))
        
        # Draw the "Options" title
        font_title = pygame.font.SysFont('comicsans', 60, bold=True)
        title_label = font_title.render('Options', 1, (255, 255, 255))
        win.blit(title_label, (SCREEN_WIDTH / 2 - title_label.get_width() / 2, 50))
        
        # Draw sliders
        music_slider.draw(win)
        sfx_slider.draw(win)
        
        # Instructions to return to main menu
        font_instruct = pygame.font.SysFont('comicsans', 25)
        instruct_label = font_instruct.render('Press Esc to return to the main menu.', 1, (255, 255, 255))
        win.blit(instruct_label, (SCREEN_WIDTH / 2 - instruct_label.get_width() / 2, 400))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.display.quit()
                quit()
            # Handle slider events
            music_slider.handle_event(event)
            sfx_slider.handle_event(event)
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    # Update volume settings
                    set_music_volume(music_slider.value)
                    set_sfx_volume(sfx_slider.value)
                    run = False  # Exit options_menu
    # Do NOT call pygame.quit() here. Instead, return to main_menu
    # pygame.quit()  # Removed to prevent crashing

def set_sfx_volume(volume):
    global sfx_volume
    sfx_volume = volume
    MOVE_SOUND.set_volume(sfx_volume / 10)
    ROTATE_SOUND.set_volume(sfx_volume / 10)
    CLEAR_SOUND.set_volume(sfx_volume / 10)
    GAME_OVER_SOUND.set_volume(sfx_volume / 10)

def set_music_volume(volume):
    global music_volume
    music_volume = volume
    pygame.mixer.music.set_volume(music_volume / 10)

def main():
    global high_score
    locked_positions = {}
    grid = create_grid(locked_positions)

    change_piece = False
    run = True
    current_piece = get_shape()
    next_piece = get_shape()
    clock = pygame.time.Clock()
    fall_time = 0

    BASE_FALL_SPEED = 0.5  # Base fall speed in seconds
    fall_speed = BASE_FALL_SPEED
    lines_cleared = 0  # Initialize lines cleared counter
    level = 1  # Initialize level

    paused = False  # Game paused state

    the_music_started = False  # To ensure music starts only once

    while run:
        grid = create_grid(locked_positions)
        fall_time += clock.get_rawtime()
        clock.tick()

        # Calculate current level based on lines cleared
        new_level = (lines_cleared // 10) + 1
        if new_level != level:
            level = new_level
            fall_speed *= 1.15  # Increase speed by 15% each level

        # Adjust fall speed
        current_fall_speed = fall_speed
        keys = pygame.key.get_pressed()

        if keys[pygame.K_DOWN]:
            current_fall_speed = 0.05  # Fast fall when down key is held

        if fall_time / 1000 >= current_fall_speed:
            fall_time = 0
            current_piece.y += 1
            if not valid_space(current_piece, grid) and current_piece.y > 0:
                current_piece.y -= 1
                change_piece = True
                MOVE_SOUND.play()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.display.quit()
                quit()

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    current_piece.x -= 1
                    if not valid_space(current_piece, grid):
                        current_piece.x += 1
                    else:
                        MOVE_SOUND.play()
                elif event.key == pygame.K_RIGHT:
                    current_piece.x += 1
                    if not valid_space(current_piece, grid):
                        current_piece.x -= 1
                    else:
                        MOVE_SOUND.play()
                elif event.key == pygame.K_DOWN:
                    current_piece.y += 1
                    if not valid_space(current_piece, grid):
                        current_piece.y -= 1
                elif event.key == pygame.K_UP:
                    current_piece.rotation = (current_piece.rotation + 1) % len(current_piece.shape)
                    if not valid_space(current_piece, grid):
                        current_piece.rotation = (current_piece.rotation - 1) % len(current_piece.shape)
                    else:
                        ROTATE_SOUND.play()
                elif event.key == pygame.K_SPACE:
                    paused = not paused  # Toggle pause

        if paused:
            pause_screen(win)
            continue  # Skip the rest of the loop to effectively pause

        shape_pos = convert_shape_format(current_piece)

        # Add piece to the grid for drawing
        for i in range(len(shape_pos)):
            x, y = shape_pos[i]
            if y > -1:
                if 0 <= x < GRID_WIDTH and 0 <= y < GRID_HEIGHT:
                    grid[y][x] = current_piece.color

        if change_piece:
            for pos in shape_pos:
                p = (pos[0], pos[1])
                if 0 <= p[0] < GRID_WIDTH and 0 <= p[1] < GRID_HEIGHT:
                    locked_positions[p] = current_piece.color
            current_piece = next_piece
            next_piece = get_shape()
            change_piece = False

            cleared = clear_rows(grid, locked_positions)
            lines_cleared += cleared  # Update lines cleared

        # Start background music once when the game starts
        if not the_music_started:
            play_background_music()
            the_music_started = True

        draw_window(win, grid, lines_cleared, level, high_score)  # Removed high_score from in-game display
        draw_next_shape(next_piece, win)
        pygame.display.update()

        if check_lost(locked_positions):
            GAME_OVER_SOUND.play()
            pygame.time.delay(500)
            run = False
            stop_background_music()
            update_high_score_if_needed(lines_cleared)

    game_over_screen(win, lines_cleared, high_score)

def update_high_score_if_needed(current_score):
    global high_score
    if current_score > high_score:
        high_score = current_score
        save_high_score(high_score)

def game_over_screen(surface, final_score, _):
    global high_score
    # Update high score if necessary
    if final_score > high_score:
        high_score = final_score
        save_high_score(high_score)

    pygame.mixer.music.stop()  # Ensure music is stopped on game over

    while True:
        surface.fill((0, 0, 0))
        draw_text_middle("YOU LOST!", 60, (255, 255, 255), surface, y_offset=-50)
        
        # Display final score
        font_small = pygame.font.SysFont('comicsans', 30)
        score_label = font_small.render(f'Your Score: {final_score}', 1, (255, 255, 255))
        surface.blit(score_label, ((SCREEN_WIDTH / 2) - (score_label.get_width() / 2), (SCREEN_HEIGHT / 2) - 10))
        
        # Prompt to return to menu
        prompt_label = font_small.render('Press Space to return to the menu.', 1, (255, 255, 255))
        surface.blit(prompt_label, ((SCREEN_WIDTH / 2) - (prompt_label.get_width() / 2), (SCREEN_HEIGHT / 2) + 30))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    main_menu()  # Return to main menu

def pause_screen(surface):
    pause_font = pygame.font.SysFont('comicsans', 40, bold=True)
    pause_label = pause_font.render('Game Paused', 1, (255, 255, 255))
    prompt_font = pygame.font.SysFont('comicsans', 20)
    prompt_label = prompt_font.render('Press Space to Resume', 1, (255, 255, 255))
    
    surface.blit(pause_label, ((SCREEN_WIDTH / 2) - (pause_label.get_width() / 2), SCREEN_HEIGHT / 2 - 30))
    surface.blit(prompt_label, ((SCREEN_WIDTH / 2) - (prompt_label.get_width() / 2), SCREEN_HEIGHT / 2 + 10))
    pygame.display.update()

def main_menu():
    global high_score
    load_high_score()  # Ensure high_score is loaded before displaying menu
    run = True
    while run:
        win.fill((0, 0, 0))
        
        # Draw the "Tetris" title
        font_title = pygame.font.SysFont('comicsans', 60, bold=True)
        title_label = font_title.render('Tetris', 1, (255, 255, 255))
        win.blit(title_label, (SCREEN_WIDTH / 2 - title_label.get_width() / 2, 100))
        
        # Display High Score
        font_high = pygame.font.SysFont('comicsans', 30, bold=True)
        high_label = font_high.render(f'High Score: {high_score}', 1, (255, 255, 255))
        win.blit(high_label, (SCREEN_WIDTH / 2 - high_label.get_width() / 2, 200))
        
        # Display menu options
        font_options = pygame.font.SysFont('comicsans', 30)
        option1 = font_options.render('1: New Game', 1, (255, 255, 255))
        option2 = font_options.render('2: Options', 1, (255, 255, 255))
        option3 = font_options.render('3: Exit', 1, (255, 255, 255))
        
        win.blit(option1, (SCREEN_WIDTH / 2 - option1.get_width() / 2, 300))
        win.blit(option2, (SCREEN_WIDTH / 2 - option2.get_width() / 2, 350))
        win.blit(option3, (SCREEN_WIDTH / 2 - option3.get_width() / 2, 400))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_1:
                    main()  # Start new game
                elif event.key == pygame.K_2:
                    options_menu()  # Open options menu
                elif event.key == pygame.K_3:
                    run = False
                    pygame.quit()
                    quit()
    pygame.quit()

def options_menu():
    global music_volume, sfx_volume
    run = True
    # Create sliders: (x, y, width, height, min_val, max_val, start_val, label)
    music_slider = Slider(SCREEN_WIDTH / 2 - 100, 150, 200, 20, 0, 10, music_volume, 'Music Volume')
    sfx_slider = Slider(SCREEN_WIDTH / 2 - 100, 250, 200, 20, 0, 10, sfx_volume, 'SFX Volume')
    
    while run:
        win.fill((0, 0, 0))
        
        # Draw the "Options" title
        font_title = pygame.font.SysFont('comicsans', 60, bold=True)
        title_label = font_title.render('Options', 1, (255, 255, 255))
        win.blit(title_label, (SCREEN_WIDTH / 2 - title_label.get_width() / 2, 50))
        
        # Draw sliders
        music_slider.draw(win)
        sfx_slider.draw(win)
        
        # Instructions to return to main menu
        font_instruct = pygame.font.SysFont('comicsans', 25)
        instruct_label = font_instruct.render('Press Esc to return to the main menu.', 1, (255, 255, 255))
        win.blit(instruct_label, (SCREEN_WIDTH / 2 - instruct_label.get_width() / 2, 400))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.display.quit()
                quit()
            # Handle slider events
            music_slider.handle_event(event)
            sfx_slider.handle_event(event)
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    # Update volume settings
                    set_music_volume(music_slider.value)
                    set_sfx_volume(sfx_slider.value)
                    run = False  # Exit options_menu
    # Do NOT call pygame.quit() here. Instead, return to main_menu
    # pygame.quit()  # Removed to prevent crashing

def set_sfx_volume(volume):
    global sfx_volume
    sfx_volume = volume
    MOVE_SOUND.set_volume(sfx_volume / 10)
    ROTATE_SOUND.set_volume(sfx_volume / 10)
    CLEAR_SOUND.set_volume(sfx_volume / 10)
    GAME_OVER_SOUND.set_volume(sfx_volume / 10)

def set_music_volume(volume):
    global music_volume
    music_volume = volume
    pygame.mixer.music.set_volume(music_volume / 10)

def main():
    global high_score
    locked_positions = {}
    grid = create_grid(locked_positions)

    change_piece = False
    run = True
    current_piece = get_shape()
    next_piece = get_shape()
    clock = pygame.time.Clock()
    fall_time = 0

    BASE_FALL_SPEED = 0.5  # Base fall speed in seconds
    fall_speed = BASE_FALL_SPEED
    lines_cleared = 0  # Initialize lines cleared counter
    level = 1  # Initialize level

    paused = False  # Game paused state

    the_music_started = False  # To ensure music starts only once

    while run:
        grid = create_grid(locked_positions)
        fall_time += clock.get_rawtime()
        clock.tick()

        # Calculate current level based on lines cleared
        new_level = (lines_cleared // 10) + 1
        if new_level != level:
            level = new_level
            fall_speed *= 1.15  # Increase speed by 15% each level

        # Adjust fall speed
        current_fall_speed = fall_speed
        keys = pygame.key.get_pressed()

        if keys[pygame.K_DOWN]:
            current_fall_speed = 0.05  # Fast fall when down key is held

        if fall_time / 1000 >= current_fall_speed:
            fall_time = 0
            current_piece.y += 1
            if not valid_space(current_piece, grid) and current_piece.y > 0:
                current_piece.y -= 1
                change_piece = True
                MOVE_SOUND.play()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.display.quit()
                quit()

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    current_piece.x -= 1
                    if not valid_space(current_piece, grid):
                        current_piece.x += 1
                    else:
                        MOVE_SOUND.play()
                elif event.key == pygame.K_RIGHT:
                    current_piece.x += 1
                    if not valid_space(current_piece, grid):
                        current_piece.x -= 1
                    else:
                        MOVE_SOUND.play()
                elif event.key == pygame.K_DOWN:
                    current_piece.y += 1
                    if not valid_space(current_piece, grid):
                        current_piece.y -= 1
                elif event.key == pygame.K_UP:
                    current_piece.rotation = (current_piece.rotation + 1) % len(current_piece.shape)
                    if not valid_space(current_piece, grid):
                        current_piece.rotation = (current_piece.rotation - 1) % len(current_piece.shape)
                    else:
                        ROTATE_SOUND.play()
                elif event.key == pygame.K_SPACE:
                    paused = not paused  # Toggle pause

        if paused:
            pause_screen(win)
            continue  # Skip the rest of the loop to effectively pause

        shape_pos = convert_shape_format(current_piece)

        # Add piece to the grid for drawing
        for i in range(len(shape_pos)):
            x, y = shape_pos[i]
            if y > -1:
                if 0 <= x < GRID_WIDTH and 0 <= y < GRID_HEIGHT:
                    grid[y][x] = current_piece.color

        if change_piece:
            for pos in shape_pos:
                p = (pos[0], pos[1])
                if 0 <= p[0] < GRID_WIDTH and 0 <= p[1] < GRID_HEIGHT:
                    locked_positions[p] = current_piece.color
            current_piece = next_piece
            next_piece = get_shape()
            change_piece = False

            cleared = clear_rows(grid, locked_positions)
            lines_cleared += cleared  # Update lines cleared

        # Start background music once when the game starts
        if not the_music_started:
            play_background_music()
            the_music_started = True

        draw_window(win, grid, lines_cleared, level, high_score)  # Removed high_score from in-game display
        draw_next_shape(next_piece, win)
        pygame.display.update()

        if check_lost(locked_positions):
            GAME_OVER_SOUND.play()
            pygame.time.delay(500)
            run = False
            stop_background_music()
            update_high_score_if_needed(lines_cleared)

    game_over_screen(win, lines_cleared, high_score)

def update_high_score_if_needed(current_score):
    global high_score
    if current_score > high_score:
        high_score = current_score
        save_high_score(high_score)

def game_over_screen(surface, final_score, _):
    global high_score
    # Update high score if necessary
    if final_score > high_score:
        high_score = final_score
        save_high_score(high_score)

    pygame.mixer.music.stop()  # Ensure music is stopped on game over

    while True:
        surface.fill((0, 0, 0))
        draw_text_middle("YOU LOST!", 60, (255, 255, 255), surface, y_offset=-50)
        
        # Display final score
        font_small = pygame.font.SysFont('comicsans', 30)
        score_label = font_small.render(f'Your Score: {final_score}', 1, (255, 255, 255))
        surface.blit(score_label, ((SCREEN_WIDTH / 2) - (score_label.get_width() / 2), (SCREEN_HEIGHT / 2) - 10))
        
        # Prompt to return to menu
        prompt_label = font_small.render('Press Space to return to the menu.', 1, (255, 255, 255))
        surface.blit(prompt_label, ((SCREEN_WIDTH / 2) - (prompt_label.get_width() / 2), (SCREEN_HEIGHT / 2) + 30))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    main_menu()  # Return to main menu

def pause_screen(surface):
    pause_font = pygame.font.SysFont('comicsans', 40, bold=True)
    pause_label = pause_font.render('Game Paused', 1, (255, 255, 255))
    prompt_font = pygame.font.SysFont('comicsans', 20)
    prompt_label = prompt_font.render('Press Space to Resume', 1, (255, 255, 255))
    
    surface.blit(pause_label, ((SCREEN_WIDTH / 2) - (pause_label.get_width() / 2), SCREEN_HEIGHT / 2 - 30))
    surface.blit(prompt_label, ((SCREEN_WIDTH / 2) - (prompt_label.get_width() / 2), SCREEN_HEIGHT / 2 + 10))
    pygame.display.update()

def main_menu():
    global high_score
    load_high_score()  # Ensure high_score is loaded before displaying menu
    run = True
    while run:
        win.fill((0, 0, 0))
        
        # Draw the "Tetris" title
        font_title = pygame.font.SysFont('comicsans', 60, bold=True)
        title_label = font_title.render('Tetris', 1, (255, 255, 255))
        win.blit(title_label, (SCREEN_WIDTH / 2 - title_label.get_width() / 2, 100))
        
        # Display High Score
        font_high = pygame.font.SysFont('comicsans', 30, bold=True)
        high_label = font_high.render(f'High Score: {high_score}', 1, (255, 255, 255))
        win.blit(high_label, (SCREEN_WIDTH / 2 - high_label.get_width() / 2, 200))
        
        # Display menu options
        font_options = pygame.font.SysFont('comicsans', 30)
        option1 = font_options.render('1: New Game', 1, (255, 255, 255))
        option2 = font_options.render('2: Options', 1, (255, 255, 255))
        option3 = font_options.render('3: Exit', 1, (255, 255, 255))
        
        win.blit(option1, (SCREEN_WIDTH / 2 - option1.get_width() / 2, 300))
        win.blit(option2, (SCREEN_WIDTH / 2 - option2.get_width() / 2, 350))
        win.blit(option3, (SCREEN_WIDTH / 2 - option3.get_width() / 2, 400))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_1:
                    main()  # Start new game
                elif event.key == pygame.K_2:
                    options_menu()  # Open options menu
                elif event.key == pygame.K_3:
                    run = False
                    pygame.quit()
                    quit()
    pygame.quit()

def options_menu():
    global music_volume, sfx_volume
    run = True
    # Create sliders: (x, y, width, height, min_val, max_val, start_val, label)
    music_slider = Slider(SCREEN_WIDTH / 2 - 100, 150, 200, 20, 0, 10, music_volume, 'Music Volume')
    sfx_slider = Slider(SCREEN_WIDTH / 2 - 100, 250, 200, 20, 0, 10, sfx_volume, 'SFX Volume')
    
    while run:
        win.fill((0, 0, 0))
        
        # Draw the "Options" title
        font_title = pygame.font.SysFont('comicsans', 60, bold=True)
        title_label = font_title.render('Options', 1, (255, 255, 255))
        win.blit(title_label, (SCREEN_WIDTH / 2 - title_label.get_width() / 2, 50))
        
        # Draw sliders
        music_slider.draw(win)
        sfx_slider.draw(win)
        
        # Instructions to return to main menu
        font_instruct = pygame.font.SysFont('comicsans', 25)
        instruct_label = font_instruct.render('Press Esc to return to the main menu.', 1, (255, 255, 255))
        win.blit(instruct_label, (SCREEN_WIDTH / 2 - instruct_label.get_width() / 2, 400))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.display.quit()
                quit()
            # Handle slider events
            music_slider.handle_event(event)
            sfx_slider.handle_event(event)
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    # Update volume settings
                    set_music_volume(music_slider.value)
                    set_sfx_volume(sfx_slider.value)
                    run = False  # Exit options_menu
    # Do NOT call pygame.quit() here. Instead, return to main_menu
    # pygame.quit()  # Removed to prevent crashing

def set_sfx_volume(volume):
    global sfx_volume
    sfx_volume = volume
    MOVE_SOUND.set_volume(sfx_volume / 10)
    ROTATE_SOUND.set_volume(sfx_volume / 10)
    CLEAR_SOUND.set_volume(sfx_volume / 10)
    GAME_OVER_SOUND.set_volume(sfx_volume / 10)

def set_music_volume(volume):
    global music_volume
    music_volume = volume
    pygame.mixer.music.set_volume(music_volume / 10)

def main():
    global high_score
    locked_positions = {}
    grid = create_grid(locked_positions)

    change_piece = False
    run = True
    current_piece = get_shape()
    next_piece = get_shape()
    clock = pygame.time.Clock()
    fall_time = 0

    BASE_FALL_SPEED = 0.5  # Base fall speed in seconds
    fall_speed = BASE_FALL_SPEED
    lines_cleared = 0  # Initialize lines cleared counter
    level = 1  # Initialize level

    paused = False  # Game paused state

    the_music_started = False  # To ensure music starts only once

    while run:
        grid = create_grid(locked_positions)
        fall_time += clock.get_rawtime()
        clock.tick()

        # Calculate current level based on lines cleared
        new_level = (lines_cleared // 10) + 1
        if new_level != level:
            level = new_level
            fall_speed *= 1.15  # Increase speed by 15% each level

        # Adjust fall speed
        current_fall_speed = fall_speed
        keys = pygame.key.get_pressed()

        if keys[pygame.K_DOWN]:
            current_fall_speed = 0.05  # Fast fall when down key is held

        if fall_time / 1000 >= current_fall_speed:
            fall_time = 0
            current_piece.y += 1
            if not valid_space(current_piece, grid) and current_piece.y > 0:
                current_piece.y -= 1
                change_piece = True
                MOVE_SOUND.play()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.display.quit()
                quit()

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    current_piece.x -= 1
                    if not valid_space(current_piece, grid):
                        current_piece.x += 1
                    else:
                        MOVE_SOUND.play()
                elif event.key == pygame.K_RIGHT:
                    current_piece.x += 1
                    if not valid_space(current_piece, grid):
                        current_piece.x -= 1
                    else:
                        MOVE_SOUND.play()
                elif event.key == pygame.K_DOWN:
                    current_piece.y += 1
                    if not valid_space(current_piece, grid):
                        current_piece.y -= 1
                elif event.key == pygame.K_UP:
                    current_piece.rotation = (current_piece.rotation + 1) % len(current_piece.shape)
                    if not valid_space(current_piece, grid):
                        current_piece.rotation = (current_piece.rotation - 1) % len(current_piece.shape)
                    else:
                        ROTATE_SOUND.play()
                elif event.key == pygame.K_SPACE:
                    paused = not paused  # Toggle pause

        if paused:
            pause_screen(win)
            continue  # Skip the rest of the loop to effectively pause

        shape_pos = convert_shape_format(current_piece)

        # Add piece to the grid for drawing
        for i in range(len(shape_pos)):
            x, y = shape_pos[i]
            if y > -1:
                if 0 <= x < GRID_WIDTH and 0 <= y < GRID_HEIGHT:
                    grid[y][x] = current_piece.color

        if change_piece:
            for pos in shape_pos:
                p = (pos[0], pos[1])
                if 0 <= p[0] < GRID_WIDTH and 0 <= p[1] < GRID_HEIGHT:
                    locked_positions[p] = current_piece.color
            current_piece = next_piece
            next_piece = get_shape()
            change_piece = False

            cleared = clear_rows(grid, locked_positions)
            lines_cleared += cleared  # Update lines cleared

        # Start background music once when the game starts
        if not the_music_started:
            play_background_music()
            the_music_started = True

        draw_window(win, grid, lines_cleared, level, high_score)  # Removed high_score from in-game display
        draw_next_shape(next_piece, win)
        pygame.display.update()

        if check_lost(locked_positions):
            GAME_OVER_SOUND.play()
            pygame.time.delay(500)
            run = False
            stop_background_music()
            update_high_score_if_needed(lines_cleared)

    game_over_screen(win, lines_cleared, high_score)

def update_high_score_if_needed(current_score):
    global high_score
    if current_score > high_score:
        high_score = current_score
        save_high_score(high_score)

def game_over_screen(surface, final_score, _):
    global high_score
    # Update high score if necessary
    if final_score > high_score:
        high_score = final_score
        save_high_score(high_score)

    pygame.mixer.music.stop()  # Ensure music is stopped on game over

    while True:
        surface.fill((0, 0, 0))
        draw_text_middle("YOU LOST!", 60, (255, 255, 255), surface, y_offset=-50)
        
        # Display final score
        font_small = pygame.font.SysFont('comicsans', 30)
        score_label = font_small.render(f'Your Score: {final_score}', 1, (255, 255, 255))
        surface.blit(score_label, ((SCREEN_WIDTH / 2) - (score_label.get_width() / 2), (SCREEN_HEIGHT / 2) - 10))
        
        # Prompt to return to menu
        prompt_label = font_small.render('Press Space to return to the menu.', 1, (255, 255, 255))
        surface.blit(prompt_label, ((SCREEN_WIDTH / 2) - (prompt_label.get_width() / 2), (SCREEN_HEIGHT / 2) + 30))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    main_menu()  # Return to main menu

def pause_screen(surface):
    pause_font = pygame.font.SysFont('comicsans', 40, bold=True)
    pause_label = pause_font.render('Game Paused', 1, (255, 255, 255))
    prompt_font = pygame.font.SysFont('comicsans', 20)
    prompt_label = prompt_font.render('Press Space to Resume', 1, (255, 255, 255))
    
    surface.blit(pause_label, ((SCREEN_WIDTH / 2) - (pause_label.get_width() / 2), SCREEN_HEIGHT / 2 - 30))
    surface.blit(prompt_label, ((SCREEN_WIDTH / 2) - (prompt_label.get_width() / 2), SCREEN_HEIGHT / 2 + 10))
    pygame.display.update()

def main_menu():
    global high_score
    load_high_score()  # Ensure high_score is loaded before displaying menu
    run = True
    while run:
        win.fill((0, 0, 0))
        
        # Draw the "Tetris" title
        font_title = pygame.font.SysFont('comicsans', 60, bold=True)
        title_label = font_title.render('Tetris', 1, (255, 255, 255))
        win.blit(title_label, (SCREEN_WIDTH / 2 - title_label.get_width() / 2, 100))
        
        # Display High Score
        font_high = pygame.font.SysFont('comicsans', 30, bold=True)
        high_label = font_high.render(f'High Score: {high_score}', 1, (255, 255, 255))
        win.blit(high_label, (SCREEN_WIDTH / 2 - high_label.get_width() / 2, 200))
        
        # Display menu options
        font_options = pygame.font.SysFont('comicsans', 30)
        option1 = font_options.render('1: New Game', 1, (255, 255, 255))
        option2 = font_options.render('2: Options', 1, (255, 255, 255))
        option3 = font_options.render('3: Exit', 1, (255, 255, 255))
        
        win.blit(option1, (SCREEN_WIDTH / 2 - option1.get_width() / 2, 300))
        win.blit(option2, (SCREEN_WIDTH / 2 - option2.get_width() / 2, 350))
        win.blit(option3, (SCREEN_WIDTH / 2 - option3.get_width() / 2, 400))
        
        pygame.display.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_1:
                    main()  # Start new game
                elif event.key == pygame.K_2:
                    options_menu()  # Open options menu
                elif event.key == pygame.K_3:
                    run = False
                    pygame.quit()
                    quit()
    pygame.quit()

if __name__ == '__main__':
    main_menu()


Do the following changes : 
- Spacebar show a pause message the screen trop but the game still continue in the background. When I unpause the screen is refresh with the new state. Really pause everything. Including the music.
- When a piece appear at the top it seams to be appearing outside the grid. The whole piece should be visible in the grid when it is added to the screen
- When I hold the down arrow the piece keep going down. Do the same thing for left and right, holding the arrows keep the piece moving in the direction of the arrow.