import pyxel
import random
import math

# ── Konstanten ───────────────────────────────────────────────────────────────
WIDTH  = 512
HEIGHT = 512

# Farben
COL_BLACK      = 0
COL_DARK_BLUE  = 1
COL_PURPLE     = 2
COL_DARK_GREEN = 3
COL_BROWN      = 4
COL_DARK_GREY  = 5
COL_GREY       = 6
COL_WHITE      = 7
COL_RED        = 8
COL_ORANGE     = 9
COL_YELLOW     = 10
COL_GREEN      = 11
COL_LIGHT_BLUE = 12
COL_BLUE       = 13
COL_PINK       = 14
COL_PEACH      = 15

# Objekttypen
TYPE_APPLE      = 0
TYPE_WATERMELON = 1
TYPE_BOMB       = 2
TYPE_BANANA_S   = 3
TYPE_BANANA_L   = 4
TYPE_LIGHTNING  = 5
TYPE_PEACH      = 6
TYPE_LIFE       = 7
TYPE_STRAWBERRY = 8

SPAWN_POOL = (
    [TYPE_APPLE]      * 42 +
    [TYPE_WATERMELON] * 14 +
    [TYPE_BOMB]       * 20 +
    [TYPE_BANANA_S]   * 7  +
    [TYPE_BANANA_L]   * 5  +
    [TYPE_LIGHTNING]  * 4  +
    [TYPE_PEACH]      * 4  +
    [TYPE_STRAWBERRY] * 2
)

POINTS     = [1, 3, 0, 0, 0, 0, 0, 0, 2]
MISS_LIVES = [1, 1, 0, 0, 0, 0, 0, 0, 1]
OBJ_RADIUS = [7, 10, 7, 5, 8, 6, 7, 7, 6]

LIFE_SPAWN_INTERVAL = 1350
POWERUP_DURATION    = 150
BASKET_BASE_WIDTH   = 34
BASKET_BASE_SPEED   = 3.0

# Evolution
EVO_THRESHOLDS = [0, 10, 25, 50, 80]
EVO_NAMES      = ["Normal", "Gross", "Raeder", "Netz", "Magnet"]
EVO_COLORS     = [COL_BROWN, COL_ORANGE, COL_YELLOW, COL_LIGHT_BLUE, COL_PURPLE]

# Combo
COMBO_NEEDED = 3

# Rezepte: Liste von (frucht_sequenz, bonus_punkte, name)
RECIPES = [
    ([TYPE_APPLE, TYPE_WATERMELON, TYPE_STRAWBERRY], 15, "Leilas Sommer-Bowl"),
    ([TYPE_BANANA_S, TYPE_BANANA_L, TYPE_PEACH],     12, "Tropischer Traum"),
    ([TYPE_STRAWBERRY, TYPE_APPLE, TYPE_BANANA_L],   18, "Meisterrezept!"),
]
RECIPE_PROGRESS = [[False, False, False], [False, False, False], [False, False, False]]

# Wetter
WEATHER_CLEAR = 0
WEATHER_RAIN  = 1
WEATHER_STORM = 2
WEATHER_HEAT  = 3
WEATHER_NIGHT = 4

WEATHER_NAMES = {
    WEATHER_CLEAR: "Sonnig",
    WEATHER_RAIN:  "Regen!",
    WEATHER_STORM: "Sturm!!",
    WEATHER_HEAT:  "Hitze!",
    WEATHER_NIGHT: "Nacht...",
}
WEATHER_COLORS = {
    WEATHER_CLEAR: COL_YELLOW,
    WEATHER_RAIN:  COL_LIGHT_BLUE,
    WEATHER_STORM: COL_PURPLE,
    WEATHER_HEAT:  COL_ORANGE,
    WEATHER_NIGHT: COL_DARK_GREY,
}

WEATHER_DURATION  = 300
WEATHER_WARN_TIME = 60

WIN_SCORE = 100

# ── Sound-Definitionen ────────────────────────────────────────────────────────
def init_sounds():
    # Sound 0: Frucht fangen (kurzer heller Ping)
    pyxel.sounds[0].set("e4e4", "p", "77", "nn", 8)
    # Sound 1: Wassermelone (tiefer, satter)
    pyxel.sounds[1].set("c4g4", "p", "76", "nn", 10)
    # Sound 2: Bombe (tiefer Krach)
    pyxel.sounds[2].set("c2c2", "n", "76", "nn", 20)
    # Sound 3: Leben verloren (absteigende Töne)
    pyxel.sounds[3].set("g3e3c3", "p", "765", "nnn", 12)
    # Sound 4: Power-up (aufsteigend)
    pyxel.sounds[4].set("c4e4g4b4", "p", "6677", "nnnn", 10)
    # Sound 5: Combo / Kettenreaktion
    pyxel.sounds[5].set("c4e4g4b4", "p", "5566", "nnnn", 8)
    # Sound 6: Enterhaken (kurzes Zischen)
    pyxel.sounds[6].set("g4a4", "n", "54", "nn", 6)
    # Sound 7: Rezept abgeschlossen (Fanfare)
    pyxel.sounds[7].set("c4e4g4b4g4e4c4", "p", "6677776", "nnnnnnn", 10)
    # Sound 8: Erdbeere (spezieller Klang)
    pyxel.sounds[8].set("e4g4e4", "p", "767", "nnn", 8)
    # Sound 9: Sieg
    pyxel.sounds[9].set("c4e4g4b4g4e4c4", "p", "6677776", "sssssss", 14)
    # Sound 10: Hintergrundmusik Melodie (dramatisch)
    pyxel.sounds[10].set(
        "c3e3g3b3a3g3f3e3d3f3a3c4b3a3g3e3",
        "p",
        "5566665555665566",
        "nnnnnnnnnnnnnnnn",
        16
    )
    # Sound 11: Hintergrundmusik Bass
    pyxel.sounds[11].set(
        "c2c2g2c2f2c2g2c2",
        "p",
        "44444444",
        "nnnnnnnn",
        16
    )
    # Musik setup
    pyxel.musics[0].set([10], [11], [], [])


def play_music():
    pyxel.playm(0, loop=True)


def stop_music():
    pyxel.stop()


# ── Klassen ───────────────────────────────────────────────────────────────────

class FallingObject:
    def __init__(self, score, weather, wind):
        self.obj_type = random.choice(SPAWN_POOL)
        self.radius   = OBJ_RADIUS[self.obj_type]
        self.x        = float(random.randint(-5, WIDTH + 5))
        self.y        = float(-self.radius)
        speed_v       = min(0.7 + score * 0.013 + random.uniform(0, 0.5), 4.5)
        if weather == WEATHER_RAIN:
            speed_v *= 1.5
        if weather == WEATHER_STORM:
            speed_v *= random.uniform(0.8, 1.8)
        self.vx = random.uniform(0.4, 1.6) * random.choice([-1, 1])
        if weather == WEATHER_STORM:
            self.vx += wind * 0.5
        self.vy     = speed_v
        self.caught = False
        # Glitzer-Timer für Erdbeere
        self.sparkle = 0

    def update(self, weather, wind):
        if weather == WEATHER_STORM:
            self.vx += wind * 0.04
        self.x += self.vx
        self.y += self.vy
        if self.x - self.radius < 0:
            self.x  = float(self.radius)
            self.vx = abs(self.vx)
        elif self.x + self.radius > WIDTH:
            self.x  = float(WIDTH - self.radius)
            self.vx = -abs(self.vx)
        if self.obj_type == TYPE_STRAWBERRY:
            self.sparkle = (self.sparkle + 1) % 12

    def off_screen(self):
        return self.y - self.radius > HEIGHT

    def draw(self):
        x = int(self.x)
        y = int(self.y)
        r = self.radius
        t = self.obj_type

        if t == TYPE_APPLE:
            pyxel.circ(x, y, r, COL_RED)
            pyxel.pset(x - 2, y - 2, 15)
            pyxel.line(x, y - r, x, y - r - 3, COL_DARK_GREEN)
            pyxel.pset(x + 1, y - r - 2, COL_DARK_GREEN)
            pyxel.line(x + 1, y - r - 1, x + 4, y - r - 3, COL_GREEN)

        elif t == TYPE_WATERMELON:
            pyxel.circ(x, y, r, COL_GREEN)
            pyxel.circ(x, y, r - 1, COL_DARK_GREEN)
            pyxel.circ(x, y, r - 3, COL_RED)
            for kx, ky in [(-3,-1),(0,-2),(3,-1),(-2,2),(2,2),(0,3)]:
                pyxel.pset(x + kx, y + ky, COL_BLACK)
            pyxel.pset(x - 3, y - 3, COL_WHITE)

        elif t == TYPE_BOMB:
            pyxel.circ(x, y, r, COL_DARK_GREY)
            pyxel.circ(x, y, r - 1, COL_BLACK)
            pyxel.line(x, y - r, x + 2, y - r - 4, COL_BROWN)
            pyxel.pset(x + 2, y - r - 4, COL_ORANGE)
            pyxel.pset(x + 3, y - r - 5, COL_YELLOW)
            pyxel.pset(x - 2, y - 2, COL_DARK_GREY)

        elif t == TYPE_BANANA_S:
            pyxel.line(x - 4, y + 3, x - 2, y - 1, COL_YELLOW)
            pyxel.line(x - 2, y - 1, x + 1, y - 3, COL_YELLOW)
            pyxel.line(x + 1, y - 3, x + 4, y - 1, COL_YELLOW)
            pyxel.line(x + 4, y - 1, x + 4, y + 2, COL_YELLOW)
            pyxel.line(x - 3, y + 4, x - 1, y,     COL_YELLOW)
            pyxel.line(x - 1, y,     x + 2, y - 2, COL_YELLOW)
            pyxel.line(x + 2, y - 2, x + 5, y,     COL_YELLOW)
            pyxel.pset(x - 4, y + 4, COL_ORANGE)
            pyxel.pset(x - 5, y + 3, COL_ORANGE)
            pyxel.pset(x + 5, y + 2, COL_ORANGE)
            pyxel.pset(x + 5, y + 3, COL_ORANGE)
            pyxel.pset(x, y - 2, COL_WHITE)

        elif t == TYPE_BANANA_L:
            pyxel.line(x - r,     y + 4, x - r + 2, y - 2, COL_YELLOW)
            pyxel.line(x - r + 2, y - 2, x,         y - 5, COL_YELLOW)
            pyxel.line(x,         y - 5, x + r - 2, y - 2, COL_YELLOW)
            pyxel.line(x + r - 2, y - 2, x + r,     y + 3, COL_YELLOW)
            pyxel.line(x - r + 2, y + 5, x - r + 4, y,     COL_YELLOW)
            pyxel.line(x - r + 4, y,     x,         y - 3, COL_YELLOW)
            pyxel.line(x,         y - 3, x + r - 4, y,     COL_YELLOW)
            pyxel.line(x + r - 4, y,     x + r - 1, y + 4, COL_YELLOW)
            pyxel.rect(x - r - 1, y + 3, 3, 3, COL_ORANGE)
            pyxel.rect(x + r - 1, y + 2, 3, 3, COL_ORANGE)
            pyxel.line(x - 3, y - 4, x + 3, y - 4, COL_WHITE)

        elif t == TYPE_LIGHTNING:
            pyxel.line(x + 3, y - r,     x - 2, y - 1,  COL_YELLOW)
            pyxel.line(x - 2, y - 1,     x + 3, y - 1,  COL_YELLOW)
            pyxel.line(x + 3, y - 1,     x - 2, y + r,  COL_YELLOW)
            pyxel.pset(x + 3, y - r,    COL_WHITE)
            pyxel.pset(x - 2, y + r,    COL_WHITE)

        elif t == TYPE_PEACH:
            pyxel.circ(x, y, r, COL_ORANGE)
            pyxel.circ(x, y, r - 1, COL_PINK)
            pyxel.circ(x, y, r - 2, COL_PEACH)
            pyxel.line(x, y - r, x, y - r + 2, COL_ORANGE)
            pyxel.line(x, y - r, x + 1, y - r - 3, COL_DARK_GREEN)
            pyxel.line(x + 1, y - r - 1, x + 4, y - r - 4, COL_GREEN)
            pyxel.pset(x - 2, y - 2, COL_WHITE)

        elif t == TYPE_LIFE:
            pyxel.pset(x - 4, y - 1, COL_YELLOW)
            pyxel.pset(x + 4, y - 1, COL_YELLOW)
            pyxel.pset(x,     y + 5, COL_YELLOW)
            heart = [
                (-3,-1),(-2,-1),(2,-1),(3,-1),
                (-4,0),(-3,0),(-2,0),(-1,0),(0,0),(1,0),(2,0),(3,0),(4,0),
                (-4,1),(-3,1),(-2,1),(-1,1),(0,1),(1,1),(2,1),(3,1),(4,1),
                (-3,2),(-2,2),(-1,2),(0,2),(1,2),(2,2),(3,2),
                (-2,3),(-1,3),(0,3),(1,3),(2,3),
                (-1,4),(0,4),(1,4),
            ]
            for hx2, hy2 in heart:
                pyxel.pset(x + hx2, y + hy2, COL_RED)
            pyxel.pset(x - 2, y - 1, COL_WHITE)

        elif t == TYPE_STRAWBERRY:
            # Rote Erdbeere mit Glanzeffekt und Glitzer
            pyxel.circ(x, y, r, COL_RED)
            pyxel.circ(x, y, r - 1, COL_RED)
            # Samen (kleine gelbe Punkte)
            for sx, sy in [(-2,-1),(1,-2),(3,0),(-1,2),(2,2),(0,3),(-3,1)]:
                pyxel.pset(x + sx, y + sy, COL_YELLOW)
            # Blätterkrone
            pyxel.line(x - 2, y - r, x - 4, y - r - 4, COL_DARK_GREEN)
            pyxel.line(x,     y - r, x,     y - r - 5, COL_GREEN)
            pyxel.line(x + 2, y - r, x + 4, y - r - 4, COL_DARK_GREEN)
            pyxel.line(x - 1, y - r, x - 3, y - r - 3, COL_GREEN)
            pyxel.line(x + 1, y - r, x + 3, y - r - 3, COL_GREEN)
            # Glanz
            pyxel.pset(x - 2, y - 2, COL_WHITE)
            pyxel.pset(x - 1, y - 3, COL_WHITE)
            # Glitzer-Effekt (animiert)
            if self.sparkle < 6:
                pyxel.pset(x + r + 1, y,     COL_YELLOW)
                pyxel.pset(x - r - 1, y - 1, COL_YELLOW)
                pyxel.pset(x,         y - r - 2, COL_WHITE)
            else:
                pyxel.pset(x + r,     y - 1, COL_WHITE)
                pyxel.pset(x - r,     y,     COL_YELLOW)


class Raindrop:
    def __init__(self):
        self.reset()

    def reset(self):
        self.x   = random.randint(0, WIDTH)
        self.y   = random.randint(-HEIGHT, 0)
        self.spd = random.uniform(4.0, 7.0)
        self.len = random.randint(3, 6)

    def update(self):
        self.y += self.spd
        self.x += 0.8
        if self.y > HEIGHT:
            self.reset()

    def draw(self):
        pyxel.line(int(self.x), int(self.y), int(self.x) + 1, int(self.y) + self.len, COL_LIGHT_BLUE)


class StormParticle:
    def __init__(self, wind):
        self.x    = float(random.randint(0, WIDTH))
        self.y    = float(random.randint(0, HEIGHT))
        self.spd  = random.uniform(1.5, 3.5)
        self.col  = COL_GREY if random.random() > 0.5 else COL_WHITE
        self.size = random.randint(1, 2)

    def update(self, wind):
        self.x += wind * 2.0 + random.uniform(-0.3, 0.3)
        self.y += self.spd
        if self.y > HEIGHT:
            self.y = 0.0
            self.x = float(random.randint(0, WIDTH))
        if self.x < -10:
            self.x = float(WIDTH + 10)
        elif self.x > WIDTH + 10:
            self.x = -10.0

    def draw(self):
        x = int(self.x)
        y = int(self.y)
        if self.size == 1:
            pyxel.pset(x, y, self.col)
        else:
            pyxel.rect(x, y, 2, 1, self.col)


class Hook:
    """Enterhaken-Physik: Pendel an der Decke"""
    def __init__(self, basket_x):
        self.active      = False
        self.rope_x      = float(basket_x)  # Ankerpunkt oben
        self.rope_len    = 0.0
        self.angle       = math.pi / 2      # Winkel (pi/2 = senkrecht)
        self.angle_vel   = 0.0
        self.swinging    = False
        self.rope_target = 80.0             # Seillänge beim Ausfahren

    def shoot(self, basket_x):
        if not self.active and not self.swinging:
            self.active   = True
            self.swinging = False
            self.rope_x   = float(basket_x)
            self.rope_len = 0.0
            self.angle    = math.pi / 2
            self.angle_vel = 0.0
            pyxel.play(2, 6)

    def update(self, basket):
        if self.active and not self.swinging:
            # Seil fährt nach oben aus
            self.rope_len += 6.0
            self.rope_x    = float(basket.x)
            if self.rope_len >= self.rope_target:
                self.swinging = True
                # Startgeschwindigkeit je nach Bewegungsrichtung des Korbs
                self.angle_vel = basket.vel_x * 0.012

        if self.swinging:
            # Pendel-Physik
            gravity         = 0.004
            self.angle_vel -= gravity * math.sin(self.angle)
            self.angle_vel *= 0.995  # leichte Dämpfung
            self.angle     += self.angle_vel

            # Korbposition folgt dem Pendel
            basket.x = self.rope_x + math.cos(self.angle) * self.rope_len
            basket.y = 0 + math.sin(self.angle) * self.rope_len

            # Spieler kann Schwung beeinflussen
            if basket.player == 1:
                if pyxel.btn(pyxel.KEY_A):
                    self.angle_vel -= 0.008
                if pyxel.btn(pyxel.KEY_D):
                    self.angle_vel += 0.008
            else:
                if pyxel.btn(pyxel.KEY_LEFT):
                    self.angle_vel -= 0.008
                if pyxel.btn(pyxel.KEY_RIGHT):
                    self.angle_vel += 0.008

            # Loslassen
            release_key = pyxel.KEY_SPACE if basket.player == 1 else pyxel.KEY_L
            if pyxel.btnp(release_key):
                self.detach(basket)

            # Korb-Grenzen beim Schwingen
            basket.x = max(20.0, min(float(WIDTH - 20), basket.x))
            basket.y = max(20.0, min(float(HEIGHT - 20), basket.y))

    def detach(self, basket):
        self.active   = False
        self.swinging = False
        basket.y      = basket.base_y
        basket.vel_x  = self.angle_vel * self.rope_len * 0.3

    def draw(self):
        if self.active or self.swinging:
            if self.swinging:
                end_x = int(self.rope_x + math.cos(self.angle) * self.rope_len)
                end_y = int(math.sin(self.angle) * self.rope_len)
            else:
                end_x = int(self.rope_x)
                end_y = int(self.rope_len)
            # Seil
            pyxel.line(int(self.rope_x), 0, end_x, end_y, COL_BROWN)
            # Haken-Spitze
            pyxel.pset(int(self.rope_x), 0, COL_GREY)
            pyxel.pset(int(self.rope_x) + 1, 1, COL_GREY)
            pyxel.circ(end_x, end_y, 2, COL_GREY)


class Basket:
    def __init__(self, player=1, two_player=False):
        self.player      = player
        self.two_player  = two_player
        if two_player and player == 2:
            self.x = float(WIDTH * 3 // 4)
        else:
            self.x = float(WIDTH // 2)
        self.y           = float(HEIGHT - 12)
        self.base_y      = float(HEIGHT - 12)
        self.vel_x       = 0.0
        self.jumping     = False
        self.jump_vy     = 0.0
        self.small_timer = 0
        self.large_timer = 0
        self.fast_timer  = 0
        self.jump_timer  = 0
        self.hook        = Hook(self.x)

    @property
    def eff_width(self):
        evo_bonus = [0, 10, 10, 16, 16]
        base = BASKET_BASE_WIDTH + evo_bonus[evo_level]
        if self.small_timer > 0:
            return max(14, base - 12)
        if self.large_timer > 0:
            return min(70, base + 20)
        return base

    @property
    def eff_speed(self):
        evo_spd = [1.0, 1.0, 1.3, 1.3, 1.3]
        base    = BASKET_BASE_SPEED * evo_spd[evo_level]
        return base * (2.2 if self.fast_timer > 0 else 1.0)

    def _btn_left(self):
        if self.player == 1:
            return pyxel.btn(pyxel.KEY_A) if self.two_player else pyxel.btn(pyxel.KEY_LEFT)
        else:
            return pyxel.btn(pyxel.KEY_LEFT)

    def _btn_right(self):
        if self.player == 1:
            return pyxel.btn(pyxel.KEY_D) if self.two_player else pyxel.btn(pyxel.KEY_RIGHT)
        else:
            return pyxel.btn(pyxel.KEY_RIGHT)

    def _btn_up(self):
        if self.player == 1:
            return pyxel.btnp(pyxel.KEY_W) if self.two_player else pyxel.btnp(pyxel.KEY_UP)
        else:
            return pyxel.btnp(pyxel.KEY_UP)

    def _btn_hook(self):
        if self.player == 1:
            return pyxel.btnp(pyxel.KEY_SPACE)
        else:
            return pyxel.btnp(pyxel.KEY_L)

    def update(self, weather, wind):
        if self.small_timer > 0: self.small_timer -= 1
        if self.large_timer > 0: self.large_timer -= 1
        if self.fast_timer  > 0: self.fast_timer  -= 1
        if self.jump_timer  > 0: self.jump_timer  -= 1

        # Haken
        if self._btn_hook():
            if self.hook.swinging:
                self.hook.detach(self)
            elif not self.hook.active:
                self.hook.shoot(self.x)

        if self.hook.active or self.hook.swinging:
            self.hook.update(self)
            half = self.eff_width // 2
            self.x = max(float(half), min(float(WIDTH - half), self.x))
            return

        spd = self.eff_speed

        if weather == WEATHER_RAIN:
            if self._btn_left():
                self.vel_x -= 0.5
            elif self._btn_right():
                self.vel_x += 0.5
            else:
                self.vel_x *= 0.88
            self.vel_x = max(-spd * 1.4, min(spd * 1.4, self.vel_x))
            self.x += self.vel_x
        elif weather == WEATHER_STORM:
            if self._btn_left():
                self.x -= spd
            if self._btn_right():
                self.x += spd
            self.x += wind * 0.3
            self.vel_x = 0.0
        else:
            if self._btn_left():
                self.x -= spd
            if self._btn_right():
                self.x += spd
            self.vel_x = 0.0

        if self.jump_timer > 0 and not self.jumping:
            if self._btn_up():
                self.jumping = True
                self.jump_vy = -5.0

        if self.jumping:
            self.y      += self.jump_vy
            self.jump_vy += 0.3
            if self.y >= self.base_y:
                self.y       = self.base_y
                self.jumping = False
                self.jump_vy = 0.0

        half   = self.eff_width // 2
        self.x = max(float(half), min(float(WIDTH - half), self.x))

    def catches(self, obj):
        half = self.eff_width // 2
        oy   = obj.y + obj.radius
        return (self.x - half - obj.radius <= obj.x <= self.x + half + obj.radius
                and self.y - 6 <= oy <= self.y + 8)

    def draw(self, weather):
        half = self.eff_width // 2
        bx   = int(self.x)
        by   = int(self.y)
        w    = self.eff_width
        ecol = EVO_COLORS[evo_level]

        # Haken zeichnen
        self.hook.draw()

        # Leila-Figur (Köchin über dem Korb)
        # Körper
        pyxel.rect(bx - 3, by - 18, 6, 8, COL_PEACH)
        # Kochschürze
        pyxel.rect(bx - 2, by - 16, 5, 6, COL_WHITE)
        # Kopf
        pyxel.circ(bx, by - 22, 5, COL_PEACH)
        # Kochmütze
        pyxel.rect(bx - 4, by - 28, 9, 3, COL_WHITE)
        pyxel.rect(bx - 3, by - 32, 7, 5, COL_WHITE)
        # Augen
        pyxel.pset(bx - 2, by - 23, COL_BLACK)
        pyxel.pset(bx + 2, by - 23, COL_BLACK)
        # Lächeln
        pyxel.pset(bx - 1, by - 20, COL_DARK_GREEN)
        pyxel.pset(bx,     by - 20, COL_DARK_GREEN)
        pyxel.pset(bx + 1, by - 20, COL_DARK_GREEN)
        # Arme
        pyxel.line(bx - 3, by - 16, bx - 7, by - 13, COL_PEACH)
        pyxel.line(bx + 3, by - 16, bx + 7, by - 13, COL_PEACH)

        # Korb-Schatten
        pyxel.rect(bx - half + 2, by + 5, w, 4, COL_BLACK)
        # Korb-Boden
        pyxel.rect(bx - half, by, w, 5, ecol)
        # Seiten
        pyxel.rect(bx - half,     by - 7, 4, 7, ecol)
        pyxel.rect(bx + half - 4, by - 7, 4, 7, ecol)
        pyxel.rect(bx - 2, by - 7, 4, 7, ecol)

        # Gitter
        grid_cols = w // 6
        for i in range(1, grid_cols):
            lx = bx - half + i * 6
            pyxel.line(lx, by, lx, by + 5, COL_DARK_GREY)
        pyxel.line(bx - half, by + 2, bx + half, by + 2, COL_DARK_GREY)

        if evo_level >= 2:
            pyxel.circ(bx - half + 3, by + 6, 3, COL_DARK_GREY)
            pyxel.circ(bx - half + 3, by + 6, 2, COL_GREY)
            pyxel.circ(bx + half - 3, by + 6, 3, COL_DARK_GREY)
            pyxel.circ(bx + half - 3, by + 6, 2, COL_GREY)

        if evo_level >= 3:
            for i in range(0, w, 4):
                lx = bx - half + i
                pyxel.line(lx, by - 7, lx + 2, by - 12, COL_LIGHT_BLUE)
            pyxel.line(bx - half, by - 12, bx + half, by - 12, COL_LIGHT_BLUE)

        if evo_level >= 4:
            pyxel.circ(bx - 6, by - 14, 4, COL_PURPLE)
            pyxel.circ(bx - 6, by - 14, 2, COL_BLACK)
            pyxel.circ(bx + 6, by - 14, 4, COL_PURPLE)
            pyxel.circ(bx + 6, by - 14, 2, COL_BLACK)
            pyxel.rect(bx - 8, by - 14, 16, 3, COL_PURPLE)
            pyxel.rect(bx - 6, by - 10, 3, 4, COL_RED)
            pyxel.rect(bx + 3, by - 10, 3, 4, COL_BLUE)

        if weather == WEATHER_RAIN:
            for i in range(0, w, 6):
                pyxel.pset(bx - half + i, by + 6, COL_LIGHT_BLUE)

        # Spieler-Label im 2P-Modus
        if self.two_player:
            label = "P1" if self.player == 1 else "P2"
            col   = COL_YELLOW if self.player == 1 else COL_PINK
            pyxel.text(bx - 4, by - 38, label, col)

        # Power-up Rahmen
        if self.fast_timer > 0:
            pyxel.rectb(bx - half - 2, by - 9, w + 4, 16, COL_YELLOW)
        elif self.jump_timer > 0:
            pyxel.rectb(bx - half - 2, by - 9, w + 4, 16, COL_PINK)
        elif self.small_timer > 0:
            pyxel.rectb(bx - half - 2, by - 9, w + 4, 16, COL_RED)
        elif self.large_timer > 0:
            pyxel.rectb(bx - half - 2, by - 9, w + 4, 16, COL_GREEN)


class Particle:
    def __init__(self, x, y, color):
        self.x    = float(x)
        self.y    = float(y)
        self.vx   = random.uniform(-2.0, 2.0)
        self.vy   = random.uniform(-3.0, -0.8)
        self.col  = color
        self.life = random.randint(14, 28)
        self.size = random.randint(1, 2)

    def update(self):
        self.x    += self.vx
        self.y    += self.vy
        self.vy   += 0.15
        self.life -= 1

    def draw(self):
        if self.life > 0:
            x = int(self.x)
            y = int(self.y)
            if self.size == 1:
                pyxel.pset(x, y, self.col)
            else:
                pyxel.rect(x, y, 2, 2, self.col)


# ── Globaler Zustand ──────────────────────────────────────────────────────────

basket            = None
basket2           = None
objects           = []
particles         = []
score_anim        = []
raindrops         = []
storm_particles   = []
score             = 0
score2            = 0
lives             = 3
lives2            = 3
frame_count       = 0
flash             = 0
flash_col         = COL_RED
bomb_hit          = False
powerup_msg       = ""
powerup_msg_timer = 0
state             = "title"
two_player        = False
winner            = 0

weather           = WEATHER_CLEAR
weather_timer     = WEATHER_DURATION
next_weather      = WEATHER_CLEAR
weather_warning   = 0
weather_announce  = 0
wind              = 0.0
wind_target       = 0.0
heat_flicker      = 0

evo_level         = 0
evo_announce      = 0

combo_count       = 0
combo_last_type   = -1
combo_announce    = 0

# Rezept-Fortschritt: letzte 3 gefangene Früchte (für Sequenz-Check)
recent_fruits     = []
recipe_announce   = 0
recipe_name       = ""
recipes_done      = [False, False, False]

title_cursor      = 0  # 0 = Einzelspieler, 1 = Zweispieler


def init_game(tp=False):
    global basket, basket2, objects, particles, score_anim, raindrops, storm_particles
    global score, score2, lives, lives2, frame_count, flash, flash_col, bomb_hit
    global powerup_msg, powerup_msg_timer, state
    global weather, weather_timer, next_weather, weather_warning, weather_announce
    global wind, wind_target, heat_flicker
    global evo_level, evo_announce
    global combo_count, combo_last_type, combo_announce
    global recent_fruits, recipe_announce, recipe_name, recipes_done
    global two_player, winner

    two_player        = tp
    basket            = Basket(player=1, two_player=tp)
    basket2           = Basket(player=2, two_player=tp) if tp else None
    objects           = []
    particles         = []
    score_anim        = []
    raindrops         = [Raindrop() for _ in range(50)]
    storm_particles   = [StormParticle(0) for _ in range(60)]
    score             = 0
    score2            = 0
    lives             = 3
    lives2            = 3
    frame_count       = 0
    flash             = 0
    flash_col         = COL_RED
    bomb_hit          = False
    powerup_msg       = ""
    powerup_msg_timer = 0
    state             = "playing"
    weather           = WEATHER_CLEAR
    weather_timer     = WEATHER_DURATION
    next_weather      = pick_next_weather(WEATHER_CLEAR)
    weather_warning   = WEATHER_DURATION - WEATHER_WARN_TIME
    weather_announce  = 0
    wind              = 0.0
    wind_target       = 0.0
    heat_flicker      = 0
    evo_level         = 0
    evo_announce      = 0
    combo_count       = 0
    combo_last_type   = -1
    combo_announce    = 0
    recent_fruits     = []
    recipe_announce   = 0
    recipe_name       = ""
    recipes_done      = [False, False, False]
    winner            = 0
    play_music()


def pick_next_weather(current):
    choices = [w for w in range(5) if w != current]
    return random.choice(choices)


def spawn_particles(x, y, color, n):
    for _ in range(n):
        particles.append(Particle(x, y, color))


def check_recipes(fruit_type):
    """Prüft ob die letzten Früchte ein Rezept ergeben"""
    global recent_fruits, recipe_announce, recipe_name, lives, lives2, score, score2

    recent_fruits.append(fruit_type)
    if len(recent_fruits) > 3:
        recent_fruits = recent_fruits[-3:]

    if len(recent_fruits) < 3:
        return

    for i, (seq, bonus, name) in enumerate(RECIPES):
        if recipes_done[i]:
            continue
        if recent_fruits == seq:
            recipes_done[i]  = True
            recipe_announce  = 150
            recipe_name      = name
            score           += bonus
            if two_player:
                score2 += bonus // 2
            # Alle Leben auffüllen
            lives  = 3
            if two_player:
                lives2 = 3
            spawn_particles(WIDTH // 2, HEIGHT // 2, COL_PINK, 40)
            spawn_particles(WIDTH // 2, HEIGHT // 2, COL_YELLOW, 30)
            spawn_particles(WIDTH // 2, HEIGHT // 2, COL_RED, 20)
            pyxel.play(3, 7)
            recent_fruits = []
            break


# ── Update ────────────────────────────────────────────────────────────────────

def update():
    global state, frame_count, flash, flash_col, score, score2, lives, lives2
    global bomb_hit, powerup_msg, powerup_msg_timer
    global weather, weather_timer, next_weather, weather_warning, weather_announce
    global wind, wind_target, heat_flicker
    global evo_level, evo_announce
    global combo_count, combo_last_type, combo_announce
    global recipe_announce, title_cursor, winner, two_player

    if state == "title":
        if pyxel.btnp(pyxel.KEY_UP) or pyxel.btnp(pyxel.KEY_W):
            title_cursor = 0
        if pyxel.btnp(pyxel.KEY_DOWN) or pyxel.btnp(pyxel.KEY_S):
            title_cursor = 1
        if pyxel.btnp(pyxel.KEY_RETURN) or pyxel.btnp(pyxel.KEY_SPACE):
            init_game(tp=(title_cursor == 1))

    elif state == "playing":
        frame_count += 1

        # Wetter
        weather_timer -= 1
        wind += (wind_target - wind) * 0.05
        if weather == WEATHER_STORM and frame_count % 90 == 0:
            wind_target = random.uniform(-2.5, 2.5)
        if weather == WEATHER_HEAT:
            heat_flicker = (heat_flicker + 1) % 8
        if weather_timer == WEATHER_WARN_TIME:
            weather_warning  = WEATHER_WARN_TIME
            weather_announce = 0
        if weather_warning > 0:
            weather_warning -= 1
        if weather_timer <= 0:
            weather          = next_weather
            weather_timer    = WEATHER_DURATION
            next_weather     = pick_next_weather(weather)
            weather_warning  = 0
            weather_announce = 90
            if weather == WEATHER_STORM:
                wind_target = random.uniform(-2.5, 2.5)
            else:
                wind_target = 0.0
        if weather_announce > 0:
            weather_announce -= 1

        if weather == WEATHER_RAIN:
            for rd in raindrops:
                rd.update()
        elif weather == WEATHER_STORM:
            for sp in storm_particles:
                sp.update(wind)

        basket.update(weather, wind)
        if basket2:
            basket2.update(weather, wind)

        interval = max(22, 50 - score // 5)
        if frame_count % interval == 0:
            objects.append(FallingObject(score, weather, wind))

        if frame_count % LIFE_SPAWN_INTERVAL == 0:
            life_obj          = FallingObject.__new__(FallingObject)
            life_obj.obj_type = TYPE_LIFE
            life_obj.radius   = OBJ_RADIUS[TYPE_LIFE]
            life_obj.x        = float(random.randint(20, WIDTH - 20))
            life_obj.y        = float(-life_obj.radius)
            life_obj.vx       = random.uniform(-0.6, 0.6)
            life_obj.vy       = 1.2
            life_obj.caught   = False
            life_obj.sparkle  = 0
            objects.append(life_obj)

        for p in particles:
            p.update()
        particles[:]  = [p for p in particles if p.life > 0]
        score_anim[:] = [(x, y, t, ti - 1) for x, y, t, ti in score_anim if ti > 1]
        if powerup_msg_timer > 0:
            powerup_msg_timer -= 1
        if recipe_announce > 0:
            recipe_announce -= 1

        # Evolution
        new_evo = 0
        for lvl, threshold in enumerate(EVO_THRESHOLDS):
            if score >= threshold:
                new_evo = lvl
        if new_evo > evo_level:
            evo_level    = new_evo
            evo_announce = 120
        if evo_announce > 0:
            evo_announce -= 1
        if combo_announce > 0:
            combo_announce -= 1

        # Sieg prüfen
        if score >= WIN_SCORE:
            state  = "win"
            winner = 1
            stop_music()
            pyxel.play(3, 9)
            return
        if two_player and score2 >= WIN_SCORE:
            state  = "win"
            winner = 2
            stop_music()
            pyxel.play(3, 9)
            return

        to_remove   = []
        extra_bombs = []

        def process_catch(obj, bskt, is_p2=False):
            nonlocal to_remove, extra_bombs
            global score, score2, lives, lives2, combo_count, combo_last_type
            global combo_announce, bomb_hit, flash, flash_col, state
            global powerup_msg, powerup_msg_timer

            to_remove.append(obj)
            t  = obj.obj_type
            ox = int(obj.x)
            oy = int(obj.y)
            sc = score2 if is_p2 else score

            if t == TYPE_APPLE:
                pts = 2 if weather == WEATHER_CLEAR else 1
                if is_p2: score2 += pts
                else: score += pts
                spawn_particles(ox, oy, COL_RED, 8)
                score_anim.append((ox, oy - 8, "+" + str(pts), 35))
                pyxel.play(0, 0)
                check_recipes(TYPE_APPLE)
                if not is_p2:
                    if combo_last_type == TYPE_APPLE:
                        combo_count += 1
                    else:
                        combo_count     = 1
                        combo_last_type = TYPE_APPLE
                    if combo_count >= COMBO_NEEDED:
                        combo_count    = 0
                        combo_announce = 90
                        objects[:] = [o for o in objects if o.obj_type != TYPE_BOMB]
                        spawn_particles(WIDTH // 2, HEIGHT // 2, COL_ORANGE, 30)
                        pyxel.play(1, 5)

            elif t == TYPE_WATERMELON:
                pts = 5 if weather == WEATHER_CLEAR else 3
                if is_p2: score2 += pts
                else: score += pts
                spawn_particles(ox, oy, COL_GREEN, 14)
                score_anim.append((ox, oy - 8, "+" + str(pts), 45))
                pyxel.play(0, 1)
                check_recipes(TYPE_WATERMELON)
                if not is_p2:
                    if combo_last_type == TYPE_WATERMELON:
                        combo_count += 1
                    else:
                        combo_count     = 1
                        combo_last_type = TYPE_WATERMELON
                    if combo_count >= COMBO_NEEDED:
                        combo_count    = 0
                        combo_announce = 90
                        objects[:] = [o for o in objects if o.obj_type != TYPE_BOMB]
                        spawn_particles(WIDTH // 2, HEIGHT // 2, COL_GREEN, 30)
                        pyxel.play(1, 5)

            elif t == TYPE_STRAWBERRY:
                pts = 4
                if is_p2: score2 += pts
                else: score += pts
                spawn_particles(ox, oy, COL_RED, 12)
                spawn_particles(ox, oy, COL_PINK, 8)
                score_anim.append((ox, oy - 8, "+4 ERDBEERE!", 50))
                pyxel.play(0, 8)
                check_recipes(TYPE_STRAWBERRY)

            elif t == TYPE_BOMB:
                bomb_hit  = True
                flash     = 20
                flash_col = COL_RED
                state     = "gameover"
                stop_music()
                pyxel.play(3, 2)

            elif t == TYPE_BANANA_S:
                bskt.small_timer = POWERUP_DURATION
                bskt.large_timer = 0
                spawn_particles(ox, oy, COL_YELLOW, 8)
                powerup_msg       = "Korb kleiner!"
                powerup_msg_timer = 90
                pyxel.play(0, 4)

            elif t == TYPE_BANANA_L:
                bskt.large_timer = POWERUP_DURATION
                bskt.small_timer = 0
                spawn_particles(ox, oy, COL_YELLOW, 10)
                powerup_msg       = "Korb groesser!"
                powerup_msg_timer = 90
                pyxel.play(0, 4)
                check_recipes(TYPE_BANANA_L)

            elif t == TYPE_LIGHTNING:
                bskt.fast_timer = POWERUP_DURATION
                spawn_particles(ox, oy, COL_YELLOW, 10)
                powerup_msg       = "Turbo-Speed!"
                powerup_msg_timer = 90
                pyxel.play(0, 4)

            elif t == TYPE_PEACH:
                bskt.jump_timer = POWERUP_DURATION
                spawn_particles(ox, oy, COL_PINK, 10)
                powerup_msg       = "Sprung aktiv!"
                powerup_msg_timer = 90
                pyxel.play(0, 4)
                check_recipes(TYPE_PEACH)

            elif t == TYPE_LIFE:
                if is_p2:
                    if lives2 < 3: lives2 += 1
                else:
                    if lives < 3: lives += 1
                spawn_particles(ox, oy, COL_RED, 14)
                score_anim.append((ox, oy - 8, "+LEBEN!", 50))
                pyxel.play(0, 4)

        for obj in objects:
            obj.update(weather, wind)

            if evo_level >= 4 and obj.obj_type not in (TYPE_BOMB, TYPE_LIFE):
                dx   = basket.x - obj.x
                dy   = basket.y - obj.y
                dist = max(1.0, (dx * dx + dy * dy) ** 0.5)
                if dist < 80:
                    obj.x += dx / dist * 1.2
                    obj.y += dy / dist * 0.8

            if state != "playing":
                break

            if basket.catches(obj):
                process_catch(obj, basket, is_p2=False)
            elif basket2 and basket2.catches(obj):
                process_catch(obj, basket2, is_p2=True)
            elif obj.off_screen():
                to_remove.append(obj)
                cost = MISS_LIVES[obj.obj_type]
                if cost > 0:
                    lives    -= cost
                    flash     = 8
                    flash_col = COL_RED
                    pyxel.play(3, 3)
                if weather == WEATHER_HEAT and obj.obj_type == TYPE_BOMB:
                    for _ in range(2):
                        nb          = FallingObject.__new__(FallingObject)
                        nb.obj_type = TYPE_BOMB
                        nb.radius   = OBJ_RADIUS[TYPE_BOMB]
                        nb.x        = float(random.randint(20, WIDTH - 20))
                        nb.y        = 0.0
                        nb.vx       = random.uniform(-1.0, 1.0)
                        nb.vy       = random.uniform(1.5, 3.0)
                        nb.caught   = False
                        nb.sparkle  = 0
                        extra_bombs.append(nb)

        for obj in to_remove:
            if obj in objects:
                objects.remove(obj)
        objects.extend(extra_bombs)

        if lives <= 0 and state == "playing":
            lives     = 0
            flash     = 20
            flash_col = COL_DARK_GREY
            state     = "gameover"
            stop_music()

        if two_player and lives2 <= 0 and state == "playing":
            lives2    = 0
            flash     = 20
            flash_col = COL_DARK_GREY
            state     = "gameover"
            stop_music()

    elif state in ("gameover", "win"):
        if flash > 0:
            flash -= 1
        if pyxel.btnp(pyxel.KEY_RETURN) or pyxel.btnp(pyxel.KEY_SPACE):
            state = "title"
            play_music()
        if pyxel.btnp(pyxel.KEY_R):
            init_game(tp=two_player)


# ── Draw ──────────────────────────────────────────────────────────────────────

def draw():
    if state == "title":
        draw_title()
    elif state == "playing":
        draw_playing()
    elif state == "gameover":
        draw_gameover()
    elif state == "win":
        draw_win()


def draw_title():
    pyxel.cls(COL_BLACK)

    # Sterne
    random.seed(42)
    for _ in range(80):
        sx  = random.randint(0, WIDTH - 1)
        sy  = random.randint(0, HEIGHT - 1)
        col = COL_WHITE if random.random() > 0.5 else COL_GREY
        pyxel.pset(sx, sy, col)
    random.seed()

    # Mond
    pyxel.circ(WIDTH - 40, 35, 20, COL_YELLOW)
    pyxel.circ(WIDTH - 30, 28, 16, COL_BLACK)

    # Titel
    tx = WIDTH // 2 - 52
    pyxel.text(tx + 1, 17, "LEILAS MEISTERREZEPT", COL_DARK_GREY)
    pyxel.text(tx,     16, "LEILAS MEISTERREZEPT", COL_ORANGE)
    pyxel.text(tx - 1, 15, "LEILAS MEISTERREZEPT", COL_YELLOW)

    # Story-Einleitung (episch & dramatisch)
    story_lines = [
        "Leila Kaira, die legendaere Huhnkoeichin,",
        "steht vor ihrer groessten Herausforderung.",
        "Nur die seltensten Fruechte koennen ihr",
        "episches Meisterrezept vollenden.",
        "Fange 100 Punkte Fruechte — rette das Rezept!",
    ]
    for i, line in enumerate(story_lines):
        col = COL_WHITE if i < 4 else COL_YELLOW
        pyxel.text(WIDTH // 2 - len(line) * 2, 32 + i * 9, line, col)

    pyxel.line(20, 80, WIDTH - 20, 80, COL_DARK_GREY)

    # Leila-Vorschau (groessere Figur auf Titelscreen)
    lx = WIDTH // 2
    ly = 110
    pyxel.rect(lx - 5, ly - 22, 10, 12, COL_PEACH)
    pyxel.rect(lx - 4, ly - 20, 8, 9, COL_WHITE)
    pyxel.circ(lx, ly - 26, 7, COL_PEACH)
    pyxel.rect(lx - 6, ly - 34, 13, 4, COL_WHITE)
    pyxel.rect(lx - 4, ly - 40, 9, 7, COL_WHITE)
    pyxel.pset(lx - 2, ly - 27, COL_BLACK)
    pyxel.pset(lx + 2, ly - 27, COL_BLACK)
    pyxel.pset(lx - 1, ly - 24, COL_DARK_GREEN)
    pyxel.pset(lx,     ly - 24, COL_DARK_GREEN)
    pyxel.pset(lx + 1, ly - 24, COL_DARK_GREEN)
    pyxel.line(lx - 5, ly - 18, lx - 10, ly - 14, COL_PEACH)
    pyxel.line(lx + 5, ly - 18, lx + 10, ly - 14, COL_PEACH)
    # Kochloeffel
    pyxel.line(lx + 10, ly - 14, lx + 14, ly - 8, COL_BROWN)
    pyxel.circ(lx + 14, ly - 7, 3, COL_BROWN)

    pyxel.text(lx - 20, ly + 4, "Leila Kaira", COL_PEACH)

    pyxel.line(20, 120, WIDTH - 20, 120, COL_DARK_GREY)

    # Rezept-Vorschau
    pyxel.text(20, 125, "Die 3 Meisterrezepte:", COL_WHITE)
    pyxel.text(20, 134, "1. Apfel + Melone + Erdbeere = Sommer-Bowl (+15)", COL_RED)
    pyxel.text(20, 143, "2. Kl.Banane + Gr.Banane + Pfirsich = Tropisch (+12)", COL_YELLOW)
    pyxel.text(20, 152, "3. Erdbeere + Apfel + Gr.Banane = MEISTERREZEPT (+18)", COL_PINK)

    pyxel.line(20, 162, WIDTH - 20, 162, COL_DARK_GREY)

    # Steuerung
    pyxel.text(20, 167, "Steuerung Enterhaken: SPACE (P1) / L (P2)", COL_LIGHT_BLUE)
    pyxel.text(20, 176, "Ziel: 100 Punkte = Meisterrezept gerettet!", COL_GREEN)

    pyxel.line(20, 186, WIDTH - 20, 186, COL_DARK_GREY)

    # Menü-Auswahl
    opts = ["Einzelspieler", "Zweispieler (P1=WASD, P2=Pfeile)"]
    for i, opt in enumerate(opts):
        y   = 194 + i * 14
        sel = (i == title_cursor)
        if sel:
            pyxel.rect(14, y - 2, WIDTH - 28, 12, COL_DARK_BLUE)
            pyxel.rectb(14, y - 2, WIDTH - 28, 12, COL_YELLOW)
            arrow = ">"
        else:
            arrow = " "
        col = COL_YELLOW if sel else COL_GREY
        pyxel.text(22, y, arrow + " " + opt, col)

    if (pyxel.frame_count // 15) % 2 == 0:
        pyxel.text(WIDTH // 2 - 44, 228, "ENTER oder SPACE: Starten", COL_WHITE)


def draw_playing():
    global flash

    if flash > 0:
        pyxel.cls(flash_col)
        flash -= 1
        return

    # Hintergrund
    if weather == WEATHER_NIGHT:
        pyxel.cls(COL_BLACK)
    elif weather == WEATHER_RAIN:
        pyxel.cls(COL_DARK_BLUE)
    elif weather == WEATHER_STORM:
        pyxel.cls(COL_PURPLE)
    elif weather == WEATHER_HEAT:
        bg = COL_BROWN if heat_flicker < 4 else COL_DARK_GREY
        pyxel.cls(bg)
    else:
        pyxel.cls(COL_DARK_BLUE)

    if weather == WEATHER_RAIN:
        for rd in raindrops:
            rd.draw()
    elif weather == WEATHER_STORM:
        for sp in storm_particles:
            sp.draw()
        arrow     = "  >>>  " if wind > 0 else "  <<<  "
        intensity = min(int(abs(wind) * 1.5), 3)
        w_cols    = [COL_DARK_GREY, COL_GREY, COL_WHITE, COL_YELLOW]
        pyxel.text(WIDTH // 2 - 16, HEIGHT // 2 - 4, arrow, w_cols[intensity])
    elif weather == WEATHER_HEAT:
        pyxel.circ(WIDTH - 20, 20, 14, COL_YELLOW)
        pyxel.circ(WIDTH - 20, 20, 11, COL_ORANGE)
        pyxel.circ(WIDTH - 20, 20,  8, COL_YELLOW)
        for i in range(8):
            a   = i * (math.pi / 4)
            sx1 = int((WIDTH - 20) + 15 * math.cos(a))
            sy1 = int(20 + 15 * math.sin(a))
            sx2 = int((WIDTH - 20) + 20 * math.cos(a))
            sy2 = int(20 + 20 * math.sin(a))
            pyxel.line(sx1, sy1, sx2, sy2, COL_YELLOW)
    elif weather == WEATHER_NIGHT:
        random.seed(77)
        for _ in range(60):
            sx  = random.randint(0, WIDTH - 1)
            sy  = random.randint(0, HEIGHT - 30)
            col = COL_WHITE if random.random() > 0.6 else COL_GREY
            pyxel.pset(sx, sy, col) if random.random() > 0.1 else pyxel.rect(sx, sy, 2, 2, col)
        random.seed()
        pyxel.circ(24, 20, 12, COL_YELLOW)
        pyxel.circ(29, 16, 10, COL_BLACK)
    else:
        random.seed(99)
        for _ in range(35):
            sx  = random.randint(0, WIDTH - 1)
            sy  = random.randint(0, HEIGHT - 30)
            col = COL_GREY if (pyxel.frame_count // 30 + sx) % 3 == 0 else COL_DARK_GREY
            pyxel.pset(sx, sy, col)
        random.seed()

    pyxel.line(0, HEIGHT - 2, WIDTH - 1, HEIGHT - 2, COL_DARK_GREY)
    pyxel.line(0, HEIGHT - 1, WIDTH - 1, HEIGHT - 1, COL_DARK_GREY)

    # Objekte zeichnen
    if weather == WEATHER_NIGHT:
        bx      = int(basket.x)
        by      = int(basket.y)
        light_r = 90
        for obj in objects:
            dx = int(obj.x) - bx
            dy = int(obj.y) - by
            if dx * dx + dy * dy < light_r * light_r:
                obj.draw()
        for angle_step in range(0, 360, 6):
            a  = angle_step * math.pi / 180
            lx = bx + int(light_r * math.cos(a))
            ly = by + int(light_r * math.sin(a))
            if 0 <= lx < WIDTH and 0 <= ly < HEIGHT:
                pyxel.pset(lx, ly, COL_DARK_GREY)
    else:
        for obj in objects:
            obj.draw()

    for p in particles:
        p.draw()

    basket.draw(weather)
    if basket2:
        basket2.draw(weather)

    # ── HUD ──────────────────────────────────────────────────────────────────
    # Score
    pyxel.rect(0, 0, 95, 13, COL_BLACK)
    pyxel.rectb(0, 0, 95, 13, COL_DARK_GREY)
    pyxel.text(4, 3, "LEILA: " + str(score) + "/100", COL_YELLOW)

    if two_player:
        pyxel.rect(WIDTH - 100, 0, 100, 13, COL_BLACK)
        pyxel.rectb(WIDTH - 100, 0, 100, 13, COL_PINK)
        pyxel.text(WIDTH - 96, 3, "P2: " + str(score2) + "/100", COL_PINK)

    # Evolution
    evo_txt = "EVO:" + EVO_NAMES[evo_level]
    ecol    = EVO_COLORS[evo_level]
    pyxel.rect(0, 13, len(evo_txt) * 4 + 8, 11, COL_BLACK)
    pyxel.rectb(0, 13, len(evo_txt) * 4 + 8, 11, ecol)
    pyxel.text(4, 16, evo_txt, ecol)

    if evo_level < 4:
        next_thresh = EVO_THRESHOLDS[evo_level + 1]
        bar_w       = 60
        filled      = int((score - EVO_THRESHOLDS[evo_level]) /
                          max(1, next_thresh - EVO_THRESHOLDS[evo_level]) * bar_w)
        filled      = min(bar_w, filled)
        pyxel.rect( 0, 25, bar_w, 4, COL_DARK_GREY)
        pyxel.rect( 0, 25, filled, 4, ecol)
        pyxel.rectb(0, 25, bar_w, 4, COL_BLACK)
        pyxel.text( bar_w + 2, 24, str(next_thresh), COL_GREY)

    # Wetter Mitte
    w_name = WEATHER_NAMES[weather]
    w_col  = WEATHER_COLORS[weather]
    wt_x   = WIDTH // 2 - len(w_name) * 2
    pyxel.rect(wt_x - 4, 0, len(w_name) * 4 + 8, 13, COL_BLACK)
    pyxel.rectb(wt_x - 4, 0, len(w_name) * 4 + 8, 13, w_col)
    pyxel.text(wt_x, 3, w_name, w_col)

    # Leben
    for i in range(3):
        col = COL_RED if i < lives else COL_DARK_GREY
        hx  = WIDTH - 10 - i * 14
        hy  = 2
        heart = [
            (-2,0),(-1,0),(1,0),(2,0),
            (-3,1),(-2,1),(-1,1),(0,1),(1,1),(2,1),(3,1),
            (-3,2),(-2,2),(-1,2),(0,2),(1,2),(2,2),(3,2),
            (-2,3),(-1,3),(0,3),(1,3),(2,3),
            (-1,4),(0,4),(1,4),(0,5),
        ]
        for dx, dy in heart:
            pyxel.pset(hx + dx, hy + dy, col)

    # Rezept-Fortschritt (rechts unten)
    rx = WIDTH - 130
    ry = HEIGHT - 55
    pyxel.rect(rx, ry, 128, 52, COL_BLACK)
    pyxel.rectb(rx, ry, 128, 52, COL_PINK)
    pyxel.text(rx + 3, ry + 2, "Leilas Rezepte:", COL_PINK)
    recipe_short = ["Sommer-Bowl", "Tropisch", "MEISTER"]
    recipe_cols  = [COL_RED, COL_YELLOW, COL_PINK]
    for i, (rname, rcol) in enumerate(zip(recipe_short, recipe_cols)):
        done = recipes_done[i]
        mark = "[X]" if done else "[ ]"
        col  = COL_GREEN if done else rcol
        pyxel.text(rx + 3, ry + 12 + i * 13, mark + " " + rname, col)

    # Letzte Früchte Sequenz anzeigen
    fruit_icons = {
        TYPE_APPLE:      "A",
        TYPE_WATERMELON: "M",
        TYPE_STRAWBERRY: "E",
        TYPE_BANANA_S:   "b",
        TYPE_BANANA_L:   "B",
        TYPE_PEACH:      "P",
    }
    seq_txt = "Seq: " + " > ".join(fruit_icons.get(f, "?") for f in recent_fruits)
    pyxel.text(rx + 3, ry + 42, seq_txt, COL_GREY)

    # Wetter-Vorwarnung
    if weather_warning > 0:
        nxt_name = WEATHER_NAMES[next_weather]
        nxt_col  = WEATHER_COLORS[next_weather]
        if (weather_warning // 8) % 2 == 0:
            warn_txt = "Kommt: " + nxt_name + "!"
            wx_pos   = WIDTH // 2 - len(warn_txt) * 2
            pyxel.rect( wx_pos - 3, 15, len(warn_txt) * 4 + 6, 11, COL_BLACK)
            pyxel.rectb(wx_pos - 3, 15, len(warn_txt) * 4 + 6, 11, nxt_col)
            pyxel.text( wx_pos, 18, warn_txt, nxt_col)

    # Wetter-Ankündigung
    if weather_announce > 0:
        ann_txt = ">>> " + WEATHER_NAMES[weather] + " <<<"
        ax_pos  = WIDTH // 2 - len(ann_txt) * 2
        pyxel.rect( ax_pos - 4, HEIGHT // 2 - 10, len(ann_txt) * 4 + 8, 14, COL_BLACK)
        pyxel.rectb(ax_pos - 4, HEIGHT // 2 - 10, len(ann_txt) * 4 + 8, 14, WEATHER_COLORS[weather])
        pyxel.text( ax_pos,     HEIGHT // 2 - 6,  ann_txt, WEATHER_COLORS[weather])

    # Score-Animationen
    for x, y, text, timer in score_anim:
        col = COL_YELLOW if "+" in text else COL_RED
        ay  = y - (35 - timer) // 4
        pyxel.text(x - len(text) * 2, ay, text, col)

    # Rezept-Abschluss Banner
    if recipe_announce > 0:
        rtxt = "*** " + recipe_name + " ***"
        rx2  = WIDTH // 2 - len(rtxt) * 2
        pyxel.rect( rx2 - 6, HEIGHT // 3 - 18, len(rtxt) * 4 + 12, 36, COL_BLACK)
        pyxel.rectb(rx2 - 6, HEIGHT // 3 - 18, len(rtxt) * 4 + 12, 36, COL_PINK)
        pyxel.rectb(rx2 - 7, HEIGHT // 3 - 19, len(rtxt) * 4 + 14, 38, COL_YELLOW)
        pyxel.text( rx2, HEIGHT // 3 - 14, "REZEPT VOLLENDET!", COL_YELLOW)
        pyxel.text( rx2, HEIGHT // 3 - 4,  rtxt, COL_PINK)
        pyxel.text( rx2 - 4, HEIGHT // 3 + 6, "Bonus + Alle Leben voll!", COL_GREEN)

    # Combo-Banner
    if combo_announce > 0:
        ktxt = "*** KETTENREAKTION! ***"
        kx   = WIDTH // 2 - len(ktxt) * 2
        pyxel.rect( kx - 4, HEIGHT // 3 - 8, len(ktxt) * 4 + 8, 14, COL_BLACK)
        pyxel.rectb(kx - 4, HEIGHT // 3 - 8, len(ktxt) * 4 + 8, 14, COL_ORANGE)
        pyxel.text( kx,     HEIGHT // 3 - 4, ktxt, COL_YELLOW)

    # Evolution-Banner
    if evo_announce > 0:
        etxt = "EVOLUTION: " + EVO_NAMES[evo_level] + "!"
        ex   = WIDTH // 2 - len(etxt) * 2
        ecl  = EVO_COLORS[evo_level]
        pyxel.rect( ex - 4, HEIGHT // 2 - 12, len(etxt) * 4 + 8, 14, COL_BLACK)
        pyxel.rectb(ex - 4, HEIGHT // 2 - 12, len(etxt) * 4 + 8, 14, ecl)
        pyxel.text( ex,     HEIGHT // 2 - 8,  etxt, ecl)
        evo_descs = ["", "Korb groesser!", "Raeder: schneller!", "Netz: hoeher!", "Magnet: zieht Fruechte!"]
        pyxel.text(WIDTH // 2 - len(evo_descs[evo_level]) * 2, HEIGHT // 2 + 4, evo_descs[evo_level], ecl)

    # Power-up Nachricht
    if powerup_msg_timer > 0:
        msg = powerup_msg
        px  = WIDTH // 2 - len(msg) * 2
        pyxel.rect( px - 4, HEIGHT // 2 + 6, len(msg) * 4 + 8, 13, COL_BLACK)
        pyxel.rectb(px - 4, HEIGHT // 2 + 6, len(msg) * 4 + 8, 13, COL_YELLOW)
        pyxel.text( px,     HEIGHT // 2 + 10, msg, COL_YELLOW)

    # Power-up Balken
    bars   = [(basket.fast_timer, COL_YELLOW, "SPD"), (basket.jump_timer, COL_PINK, "JMP"),
              (basket.small_timer, COL_RED, "SML"), (basket.large_timer, COL_GREEN, "LRG")]
    offset = 0
    for timer, col, label in bars:
        if timer > 0:
            bx2  = 4 + offset * 50
            bby  = HEIGHT - 22
            pyxel.text(bx2, bby, label, col)
            w2   = int((timer / POWERUP_DURATION) * 44)
            pyxel.rect(bx2, bby + 8, 44, 5, COL_DARK_GREY)
            pyxel.rect(bx2, bby + 8, w2,  5, col)
            offset += 1

    # Wetter-Timer
    t_pct = int((weather_timer / WEATHER_DURATION) * 50)
    pyxel.text(WIDTH - 56, HEIGHT - 22, "Wetter", WEATHER_COLORS[weather])
    pyxel.rect( WIDTH - 56, HEIGHT - 13, 50, 5, COL_DARK_GREY)
    pyxel.rect( WIDTH - 56, HEIGHT - 13, t_pct, 5, WEATHER_COLORS[weather])
    pyxel.rectb(WIDTH - 56, HEIGHT - 13, 50, 5, COL_BLACK)

    # Haken-Hinweis
    hook_hint = "SPACE=Haken" if not two_player else "SPACE=P1-Haken  L=P2-Haken"
    pyxel.text(WIDTH // 2 - len(hook_hint) * 2, HEIGHT - 10, hook_hint, COL_DARK_GREY)


def draw_gameover():
    if flash > 10:
        pyxel.cls(flash_col)
        return

    pyxel.cls(COL_BLACK)

    # Dramatischer Game-Over Text
    if bomb_hit:
        t1 = "KATASTROPHE!"
        t2 = "Die Bombe hat Leilas Kueche zerstoert!"
    else:
        t1 = "REZEPT GESCHEITERT"
        t2 = "Leila hat alle Zutaten verloren..."

    pyxel.text(WIDTH // 2 - len(t1) * 2 + 1, 23, t1, COL_DARK_GREY)
    pyxel.text(WIDTH // 2 - len(t1) * 2,     22, t1, COL_RED)
    pyxel.text(WIDTH // 2 - len(t2) * 2,     34, t2, COL_ORANGE)

    # Leila traurig (Mund nach unten)
    lx = WIDTH // 2
    ly = 70
    pyxel.rect(lx - 5, ly - 22, 10, 12, COL_PEACH)
    pyxel.circ(lx, ly - 26, 7, COL_PEACH)
    pyxel.rect(lx - 6, ly - 34, 13, 4, COL_WHITE)
    pyxel.rect(lx - 4, ly - 40, 9, 7, COL_WHITE)
    pyxel.pset(lx - 2, ly - 27, COL_BLACK)
    pyxel.pset(lx + 2, ly - 27, COL_BLACK)
    # Trauriger Mund
    pyxel.pset(lx - 1, ly - 21, COL_DARK_GREEN)
    pyxel.pset(lx,     ly - 22, COL_DARK_GREEN)
    pyxel.pset(lx + 1, ly - 21, COL_DARK_GREEN)
    # Träne
    pyxel.pset(lx + 3, ly - 24, COL_LIGHT_BLUE)
    pyxel.pset(lx + 3, ly - 23, COL_LIGHT_BLUE)

    pyxel.line(30, 85, WIDTH - 30, 85, COL_DARK_GREY)

    score_text = "Punkte: " + str(score) + " / 100"
    pyxel.text(WIDTH // 2 - len(score_text) * 2, 90, score_text, COL_YELLOW)

    if two_player:
        s2txt = "P2-Punkte: " + str(score2) + " / 100"
        pyxel.text(WIDTH // 2 - len(s2txt) * 2, 100, s2txt, COL_PINK)

    # Rezepte erreicht
    pyxel.text(WIDTH // 2 - 40, 114, "Vollendete Rezepte:", COL_WHITE)
    r_names = ["Sommer-Bowl", "Tropischer Traum", "MEISTERREZEPT"]
    for i, rn in enumerate(r_names):
        col  = COL_GREEN if recipes_done[i] else COL_DARK_GREY
        mark = "✓ " if recipes_done[i] else "✗ "
        pyxel.text(WIDTH // 2 - 40, 124 + i * 10, mark + rn, col)

    pyxel.line(30, 160, WIDTH - 30, 160, COL_DARK_GREY)

    if score >= 80:
        rating, rcol = "Fast geschafft! Weiter so!", COL_ORANGE
    elif score >= 50:
        rating, rcol = "Gutes Ergebnis!", COL_GREEN
    elif score >= 20:
        rating, rcol = "Leila braucht mehr Uebung...", COL_GREY
    else:
        rating, rcol = "Die Kueche weint.", COL_DARK_GREY

    pyxel.text(WIDTH // 2 - len(rating) * 2, 166, rating, rcol)

    pyxel.line(30, 178, WIDTH - 30, 178, COL_DARK_GREY)

    if (pyxel.frame_count // 15) % 2 == 0:
        pyxel.text(WIDTH // 2 - 56, 186, "ENTER: Titelscreen  R: Nochmal", COL_WHITE)


def draw_win():
    if flash > 10:
        pyxel.cls(COL_YELLOW)
        return

    pyxel.cls(COL_DARK_BLUE)

    # Sterne-Regen
    random.seed(pyxel.frame_count // 4)
    for _ in range(30):
        sx = random.randint(0, WIDTH - 1)
        sy = random.randint(0, HEIGHT - 1)
        pyxel.pset(sx, sy, COL_YELLOW)
    random.seed()

    t1 = "DAS MEISTERREZEPT IST GERETTET!"
    pyxel.text(WIDTH // 2 - len(t1) * 2 + 1, 19, t1, COL_DARK_GREY)
    pyxel.text(WIDTH // 2 - len(t1) * 2,     18, t1, COL_YELLOW)

    if two_player:
        wt = "Spieler " + str(winner) + " hat gewonnen!"
        pyxel.text(WIDTH // 2 - len(wt) * 2, 30, wt, COL_PINK if winner == 2 else COL_YELLOW)

    # Leila glücklich (grössere Figur)
    lx = WIDTH // 2
    ly = 90
    # Jubel-Arme
    pyxel.line(lx - 5, ly - 18, lx - 12, ly - 26, COL_PEACH)
    pyxel.line(lx + 5, ly - 18, lx + 12, ly - 26, COL_PEACH)
    pyxel.rect(lx - 5, ly - 22, 10, 12, COL_PEACH)
    pyxel.rect(lx - 4, ly - 20, 8, 9, COL_WHITE)
    pyxel.circ(lx, ly - 26, 7, COL_PEACH)
    pyxel.rect(lx - 6, ly - 34, 13, 4, COL_WHITE)
    pyxel.rect(lx - 4, ly - 40, 9, 7, COL_WHITE)
    pyxel.pset(lx - 2, ly - 27, COL_BLACK)
    pyxel.pset(lx + 2, ly - 27, COL_BLACK)
    # Breites Lächeln
    for smile_x in range(-2, 3):
        pyxel.pset(lx + smile_x, ly - 21, COL_DARK_GREEN)
    pyxel.pset(lx - 2, ly - 22, COL_DARK_GREEN)
    pyxel.pset(lx + 2, ly - 22, COL_DARK_GREEN)
    # Sternchen um Leila
    for i in range(6):
        a  = i * math.pi / 3 + pyxel.frame_count * 0.05
        sx = lx + int(25 * math.cos(a))
        sy = (ly - 20) + int(18 * math.sin(a))
        pyxel.pset(sx, sy, COL_YELLOW)
        pyxel.pset(sx + 1, sy, COL_ORANGE)

    pyxel.text(lx - 20, ly + 6, "Leila Kaira", COL_PEACH)

    pyxel.line(30, 110, WIDTH - 30, 110, COL_YELLOW)

    # Abschluss-Story
    story = [
        "Leila hat alle Zutaten gesammelt!",
        "Das legendaere Meisterrezept ist vollbracht.",
        "Die ganze Stadt feiert — das Bankett beginnt!",
    ]
    for i, line in enumerate(story):
        pyxel.text(WIDTH // 2 - len(line) * 2, 118 + i * 10, line, COL_WHITE)

    pyxel.line(30, 152, WIDTH - 30, 152, COL_YELLOW)

    # Endpunktestand
    sc_txt = "Endpunktestand: " + str(score)
    pyxel.text(WIDTH // 2 - len(sc_txt) * 2, 158, sc_txt, COL_YELLOW)

    # Alle Rezepte
    pyxel.text(WIDTH // 2 - 44, 170, "Vollendete Rezepte:", COL_GREEN)
    r_names = ["Sommer-Bowl", "Tropischer Traum", "MEISTERREZEPT"]
    for i, rn in enumerate(r_names):
        col  = COL_GREEN if recipes_done[i] else COL_DARK_GREY
        mark = "[X] " if recipes_done[i] else "[ ] "
        pyxel.text(WIDTH // 2 - 40, 180 + i * 10, mark + rn, col)

    pyxel.line(30, 214, WIDTH - 30, 214, COL_YELLOW)

    if (pyxel.frame_count // 15) % 2 == 0:
        pyxel.text(WIDTH // 2 - 56, 222, "ENTER: Titelscreen  R: Nochmal", COL_WHITE)

    if pyxel.btnp(pyxel.KEY_R):
        init_game(tp=two_player)


# ── Start ──────────────────────────────────────────────────────────────────────

pyxel.init(WIDTH, HEIGHT, title="Leilas Meisterrezept", fps=30)
init_sounds()

# Initiale Titelscreen-Musik
basket    = Basket()
objects   = []
particles = []
raindrops = [Raindrop() for _ in range(50)]
storm_particles = [StormParticle(0) for _ in range(60)]
play_music()

pyxel.run(update, draw)