import pyxel
import os

pyxel.init(128, 128, title="Bobby Fischer Jumper")
pyxel.load("ress.pyxres")

# Joueur
perso_x = 40
perso_y = 2030
perso_vx = 0
perso_vy = 0
perso_largeur = 8
perso_hauteur = 8
gravity = 0.5
jump_strength = -6
jump_counter = 2
is_dashing = False
dash_speed = 10
dash_duration = 5
dash_timer = 0
dash_cooldown_timer = 0

# Boost
TILE_BOOST = [6, 10]
TILE_BOOST_UP = [8]
BOOST_SPEED = 8
BOOST_JUMP = -8
BOOST_UP_FORCE = -10
BOOST_DURATION = 10
boost_timer = 0

# Caméra
camera_x = 0
camera_y = 0

# Tuiles spéciales
TILE_COLLISION = [1, 2, 3, 4, 9, 11]
TILE_FINISH = [11]

# Game Over & Fin de course
game_over = False
finished = False

# Animation
animation_frame = 0
animation_timer = 0
perso_direction = 1

# Timer
game_timer = 0
best_time = None

# Fichier de sauvegarde
BEST_TIME_FILE = "best_time.txt"

def load_best_time():
    global best_time
    if os.path.exists(BEST_TIME_FILE):
        with open(BEST_TIME_FILE, "r") as f:
            try:
                best_time = int(f.read().strip())
            except:
                best_time = None

def save_best_time():
    with open(BEST_TIME_FILE, "w") as f:
        f.write(str(best_time))

def reset_game():
    global perso_x, perso_y, perso_vx, perso_vy, jump_counter
    global is_dashing, dash_timer, boost_timer, game_over
    global animation_frame, animation_timer, perso_direction
    global dash_cooldown_timer, game_timer, finished
    perso_x = 40
    perso_y = 2030
    perso_vx = 0
    perso_vy = 0
    jump_counter = 2
    is_dashing = False
    dash_timer = 0
    boost_timer = 0
    game_over = False
    finished = False
    animation_frame = 0
    animation_timer = 0
    perso_direction = 1
    dash_cooldown_timer = 0
    game_timer = 0

def get_tile_id(x, y):
    tile_x = int(x // 8)
    tile_y = int(y // 8)
    if tile_x < 0 or tile_y < 0 or tile_x >= pyxel.tilemap(0).width or tile_y >= pyxel.tilemap(0).height:
        return -1
    tile = pyxel.tilemap(0).pget(tile_x, tile_y)
    return tile[0] + tile[1] * 16

def get_tile_collision(x, y):
    return get_tile_id(x, y) in TILE_COLLISION

def check_side_collision(x, y):
    return (
        get_tile_collision(x, y) or
        get_tile_collision(x + perso_largeur - 1, y) or
        get_tile_collision(x, y + perso_hauteur - 1) or
        get_tile_collision(x + perso_largeur - 1, y + perso_hauteur - 1)
    )

def update():
    global perso_x, perso_y, perso_vx, perso_vy
    global jump_counter, is_dashing, dash_timer
    global camera_x, camera_y, boost_timer, game_over, finished
    global animation_frame, animation_timer, perso_direction
    global dash_cooldown_timer, game_timer, best_time

    if game_over or finished:
        if pyxel.btnp(pyxel.KEY_R):
            reset_game()
        return

    # Timer actif uniquement si pas terminé
    if not finished:
        game_timer += 1

    # Tuiles spéciales sous les pieds
    tile_below_x = perso_x + perso_largeur // 2
    tile_below_y = perso_y + perso_hauteur
    tile_id = get_tile_id(tile_below_x, tile_below_y)

    if tile_id in TILE_BOOST and not finished:
        boost_timer = BOOST_DURATION
        perso_vx = BOOST_SPEED
        perso_vy += BOOST_JUMP

    elif tile_id in TILE_BOOST_UP and not finished:
        perso_vy = BOOST_UP_FORCE
        jump_counter = 1

    elif tile_id in TILE_FINISH and not finished:
        finished = True
        if best_time is None or game_timer < best_time:
            best_time = game_timer
            save_best_time()

    move_speed = BOOST_SPEED if boost_timer > 0 else (dash_speed if is_dashing else 2)

    if pyxel.btn(pyxel.KEY_D):
        perso_vx = move_speed
        perso_direction = 1
    elif pyxel.btn(pyxel.KEY_Q):
        perso_vx = -move_speed
        perso_direction = -1
    else:
        perso_vx = 0

    if boost_timer > 0:
        boost_timer -= 1

    if pyxel.btnp(pyxel.KEY_SHIFT) and not is_dashing and dash_cooldown_timer == 0:
        is_dashing = True
        dash_timer = dash_duration
        dash_cooldown_timer = 60

    if is_dashing:
        dash_timer -= 1
        if dash_timer <= 0:
            is_dashing = False

    if pyxel.btnp(pyxel.KEY_SPACE) and jump_counter > 0:
        perso_vy = jump_strength
        jump_counter -= 1

    perso_vy += gravity

    new_x = perso_x + perso_vx
    if not check_side_collision(new_x, perso_y):
        perso_x = new_x

    new_y = perso_y + perso_vy
    on_ground = False

    if perso_vy > 0:
        for dy in range(int(perso_vy) + 1):
            if get_tile_collision(perso_x, perso_y + dy + perso_hauteur) or get_tile_collision(perso_x + perso_largeur - 1, perso_y + dy + perso_hauteur):
                perso_vy = 0
                jump_counter = 2
                new_y = ((perso_y + dy + perso_hauteur) // 8) * 8 - perso_hauteur
                on_ground = True
                break
        else:
            new_y = perso_y + perso_vy
    elif perso_vy < 0:
        for dy in range(int(-perso_vy) + 1):
            if get_tile_collision(perso_x, perso_y - dy) or get_tile_collision(perso_x + perso_largeur - 1, perso_y - dy):
                perso_vy = 0
                new_y = ((perso_y - dy) // 8 + 1) * 8
                break
        else:
            new_y = perso_y + perso_vy

    perso_y = new_y

    if on_ground:
        dash_cooldown_timer = 0
    elif dash_cooldown_timer > 0:
        dash_cooldown_timer -= 1

    if perso_y > pyxel.tilemap(0).height * 8:
        game_over = True

    if is_dashing:
        animation_frame = 4
    elif perso_vy < -1 or perso_vy > 1:
        animation_frame = 3
    elif perso_vx != 0:
        animation_timer += 1
        if animation_timer > 5:
            animation_timer = 0
            animation_frame = 1 if animation_frame == 2 else 2
    else:
        animation_frame = 0

    target_camera_x = perso_x - pyxel.width // 2
    target_camera_y = perso_y - pyxel.height // 2
    max_camera_x = pyxel.tilemap(0).width * 8 - pyxel.width
    max_camera_y = pyxel.tilemap(0).height * 8 - pyxel.height
    target_camera_x = max(0, min(target_camera_x, max_camera_x))
    target_camera_y = max(0, min(target_camera_y, max_camera_y))
    camera_x += (target_camera_x - camera_x) * 0.15
    camera_y += (target_camera_y - camera_y) * 0.15

def draw():
    pyxel.cls(0)
    pyxel.camera(int(camera_x), int(camera_y))
    pyxel.bltm(0, 0, 0, 0, 0, pyxel.tilemap(0).width * 8, pyxel.tilemap(0).height * 8)

    frame_coords = [(0,0), (0,8), (8,8), (16,8), (24,8)]
    u, v = frame_coords[animation_frame]
    flip = -1 if perso_direction == -1 else 1
    pyxel.blt(perso_x, perso_y, 0, u, v, 8 * flip, 8, 0)

    pyxel.camera(0, 0)

    # Timer en haut
    seconds = game_timer // 30
    centiseconds = int((game_timer % 30) * (100 / 30))
    pyxel.text(4, 4, f"Time: {seconds}.{centiseconds:02}", 7)

    # Meilleur temps
    if best_time is not None:
        best_sec = best_time // 30
        best_centi = int((best_time % 30) * (100 / 30))
        pyxel.text(4, 14, f"Best: {best_sec}.{best_centi:02}", 6)

    # Game Over
    if game_over:
        pyxel.rect(20, 50, 88, 30, 0)
        pyxel.text(35, 60, "GAME OVER", 8)
        pyxel.text(25, 70, "Press R to retry", 7)

    # Écran de fin
    if finished:
        pyxel.rect(10, 50, 108, 40, 0)
        pyxel.text(25, 55, f"Your time is: {seconds}.{centiseconds:02}", 10)
        pyxel.text(14, 65, "   You can press R to", 7)
        pyxel.text(14, 72, "  try to beat your time.", 7)

load_best_time()
pyxel.run(update, draw)