import pyxel
import random
import math

# ══════════════════════════════════════════════
#  OHNE JOB  v5
# ══════════════════════════════════════════════

W, H      = 200, 160
GROUND    = 130
CEILING   = 18
TROPHY_DIST = 12000
ZONE_LEN    = TROPHY_DIST // 5
PENALTY     = 80
CAM_EDGE    = W // 2      # Kamera scrollt wenn Spieler ueber Bildschirmmitte

pyxel.init(W, H, title="Ohne Job v5", fps=60)

# ── Musik ────────────────────────────────────
# Kanal 0-2 = Musik, Kanal 3 = SFX
# Wir bauen eine einfache Loop-Melodie mit 3 Spuren

# Melodie (Kanal 0) – froehlich aber leicht hektisch
pyxel.sounds[8].set(
    "e3e3e3c3 e3e3e3g3 a3a3a3f3 g3g3r r",
    "s", "6655 6655 6655 6655", "n", 20)

# Bass (Kanal 1)
pyxel.sounds[9].set(
    "c2r c2r f2r g2r c2r c2r f2r e2r",
    "t", "7 7 7 7 7 7 7 7", "f", 20)

# Rhythmus (Kanal 2) – kurze Percussion-Noten
pyxel.sounds[10].set(
    "c1c1r c1 c1c1r c1 c1c1r c1 c1c1r c1",
    "n", "7777 7777 7777 7777", "f", 20)

# Musik-Sequenzen
pyxel.musics[0].set([8], [9], [10], [])

# SFX
pyxel.sounds[0].set("c3e3g3c4", "t", "7654", "n", 14)   # Win
pyxel.sounds[1].set("g2e2c2a1", "s", "7654", "f", 12)   # Treffer
pyxel.sounds[2].set("c3e3",     "s", "76",   "f",  8)   # Sprung
pyxel.sounds[3].set("a2g2f2e2", "s", "7654", "f", 20)   # Spezial
pyxel.sounds[4].set("g3c4e4",   "t", "765",  "n", 10)   # Herz
pyxel.sounds[5].set("c2",       "s", "7",    "f",  6)   # Slide

# ── Spielzustand ────────────────────────────
state     = "start"
px        = 30.0
py        = float(GROUND - 14)
pvy       = 0.0
on_ground = True
sliding   = False
slide_t   = 0
lives     = 3
slow_t    = 0
rev_t     = 0
inv_t     = 0
wframe    = 0
wftimer   = 0

cam_x     = 0.0    # Kamera-Position (bestimmt was sichtbar ist)
dist      = 0.0
trophy_spawned = False
frame_count    = 0
shake          = 0

forms  = []
hearts = []
floats = []
parts  = []

spawn_t   = 0
spawn_iv  = 90
add_t     = 0
heart_t   = 0
# Verhindert dass Boden- und Luft-Formular gleichzeitig aktiv sind
last_form_type = "floor"   # "floor" oder "air"
form_cooldown  = 0

clouds = []
warn_air = 0
# ── Hilfsfunktionen ─────────────────────────

def hit(ax, ay, aw, ah, bx, by, bw, bh):
    return ax < bx+bw and ax+aw > bx and ay < by+bh and ay+ah > by

def cur_zone():
    return min(4, int(dist // ZONE_LEN))

ZONE_COLS = [
    [1,  5, 6,  2,  7],
    [9,  5, 6, 13,  9],
    [0,  2, 5,  4,  5],
    [2,  3, 4,  8, 14],
    [1, 13, 5,  1,  6],
]
def zone_col(idx): return ZONE_COLS[cur_zone()][idx]

def init_clouds():
    clouds.clear()
    for i in range(7):
        clouds.append({
            "x": float(random.randint(0, W)),
            "y": float(random.randint(12, 55)),
            "spd": 0.2 + random.random() * 0.3,
            "w":  random.randint(20, 40),
        })

def new_form_floor():
    """Bodenformular: kommt von rechts, landet am Boden -> muss drueberspringen."""
    special = random.random() < 0.28
    kind = ("slow" if random.random() < 0.5 else "rev") if special else "norm"
    spd_bonus = min(dist / 3000, 1.2)
    return {
        "x":   float(cam_x + W + random.randint(10, 60)),
        "y":   float(GROUND - 13),
        "vx":  -(0.8 + random.random() * 0.8 + spd_bonus * 0.5),
        "vy":  0.0,
        "wb":  random.random() * 6.28,
        "kind": kind,
        "type": "floor",  # Am Boden -> springen
    }

def new_form_air():
    """Luft-Formular: schwebt in Kopfhoehe -> muss sliden."""
    special = random.random() < 0.20
    kind = ("slow" if random.random() < 0.5 else "rev") if special else "norm"
    spd_bonus = min(dist / 3000, 1.0)
    # Schwebt auf Hoehe wo der Spieler steht wenn er aufrecht ist
    # Spieler-Koerper geht von py bis py+14, Kopf bei py
    # Luft-Formular: auf Hoehe py bis py+10 (also Koerper/Kopf-Bereich)
    air_y = float(GROUND - 14 - 10)
    return {
        "x":   float(cam_x + W + random.randint(10, 60)),
        "y":   air_y,
        "vx":  -(0.7 + random.random() * 0.7 + spd_bonus * 0.5),
        "vy":  0.0,
        "wb":  random.random() * 6.28,
        "kind": kind,
        "type": "air",   # In der Luft -> sliden
    }

def new_heart():
    return {
        "x":  float(cam_x + W + random.randint(20, 80)),
        "y":  float(GROUND - 25 - random.randint(5, 30)),
        "wb": random.random() * 6.28,
    }

def boom(x, y, c, n=12):
    for _ in range(n):
        a = random.random() * 6.28
        s = 1 + random.random() * 3
        parts.append({
            "x": float(x), "y": float(y),
            "vx": math.cos(a)*s, "vy": math.sin(a)*s - 2,
            "c": c, "l": 22 + random.randint(0, 12),
        })

def add_float(txt, x, y, col):
    floats.append({"t": txt, "x": float(x), "y": float(y), "c": col, "l": 55})

def spawn_next_form():
    """Spawnt abwechselnd Boden- und Luft-Formulare, nie gleichzeitig."""
    global last_form_type
    # Schau ob noch ein aktives Formular auf dem Bildschirm ist
    active = [f for f in forms if f["x"] < cam_x + W + 20]
    has_floor = any(f["type"] == "floor" for f in active)
    has_air   = any(f["type"] == "air"   for f in active)

    # Nie beide gleichzeitig
    if has_floor or has_air:
        return

    # Abwechseln
    if last_form_type == "floor":
        forms.append(new_form_air())
        last_form_type = "air"
        global warn_air
        warn_air = 40   # ca. 0.6 Sekunden Warnung
    else:
        forms.append(new_form_floor())
        last_form_type = "floor"

def reset():
    global state, px, py, pvy, on_ground, sliding, slide_t, lives
    global slow_t, rev_t, inv_t, wframe, wftimer
    global forms, hearts, floats, parts
    global spawn_t, spawn_iv, add_t, heart_t
    global frame_count, shake, dist, trophy_spawned
    global cam_x, last_form_type, form_cooldown

    state = "play"
    px, py = 30.0, float(GROUND - 14)
    pvy = 0.0; on_ground = True
    sliding = False; slide_t = 0; lives = 3
    slow_t = rev_t = inv_t = wframe = wftimer = 0
    cam_x = 0.0; dist = 0.0
    trophy_spawned = False; frame_count = 0; shake = 0
    last_form_type = "floor"; form_cooldown = 0
    forms = [new_form_floor()]
    hearts = []; floats = []; parts = []
    spawn_t = 0; spawn_iv = 90; add_t = 0; heart_t = 0
    init_clouds()
    pyxel.playm(0, loop=True)

# ── UPDATE ──────────────────────────────────

def update():
    global state, px, py, pvy, on_ground, sliding, slide_t, lives
    global slow_t, rev_t, inv_t, wframe, wftimer
    global forms, hearts, floats, parts
    global spawn_t, spawn_iv, add_t, heart_t
    global frame_count, shake, dist, trophy_spawned
    global cam_x, last_form_type, form_cooldown

    if state == "start":
        if pyxel.btnp(pyxel.KEY_SPACE) or pyxel.btnp(pyxel.KEY_RETURN):
            reset()
        return

    if state in ("win", "over"):
        pyxel.stop()
        if pyxel.btnp(pyxel.KEY_SPACE) or pyxel.btnp(pyxel.KEY_RETURN):
            reset()
        for p in parts[:]:
            p["x"] += p["vx"]; p["y"] += p["vy"]
            p["vy"] += 0.12;   p["l"]  -= 1
            if p["l"] <= 0: parts.remove(p)
        return

    frame_count += 1
    if shake > 0: shake -= 1
    global warn_air
    if warn_air > 0:
        warn_air -= 1
    if form_cooldown > 0: form_cooldown -= 1

    if dist >= TROPHY_DIST and not trophy_spawned:
        trophy_spawned = True
        add_float("TROPHAEE ERSCHEINT!", W//2 - 40, GROUND - 50, 10)

    # ── Spielerbewegung ─────────────────────
    spd = 1.3 if slow_t > 0 else 2.3
    rev = -1 if rev_t > 0 else 1
    dx  = 0
    if pyxel.btn(pyxel.KEY_LEFT)  or pyxel.btn(pyxel.KEY_A): dx = -1
    if pyxel.btn(pyxel.KEY_RIGHT) or pyxel.btn(pyxel.KEY_D): dx =  1
    dx *= rev

    # Slide
    if (pyxel.btnp(pyxel.KEY_DOWN) or pyxel.btnp(pyxel.KEY_S)) and on_ground and not sliding:
        sliding = True; slide_t = 35
        pyxel.play(3, 5)
    if slide_t > 0: slide_t -= 1
    else: sliding = False

    # Spieler bewegt sich
    px += dx * spd
    
    # AUTO-SCROLL
    auto_spd = 1.2
    cam_x += auto_spd
    dist  += auto_spd
    px += auto_spd * 0.5

    # Spieler darf nicht hinter linken Kamerarand
    if px < cam_x + 10:
        px = cam_x + 10.0
    # Spieler darf nicht zu weit rechts
    if px > cam_x + W - 10:
        px = cam_x + W - 10.0

    if dx != 0 and not sliding:
        wftimer += 1
        if wftimer >= 7: wframe = 1 - wframe; wftimer = 0
    else:
        wframe = 0

    # Springen
    if not sliding:
        if (pyxel.btnp(pyxel.KEY_UP) or pyxel.btnp(pyxel.KEY_W)
                or pyxel.btnp(pyxel.KEY_SPACE)) and on_ground:
            pvy = -7.5; on_ground = False
            pyxel.play(3, 2)

    pvy += 0.38
    py  += pvy
    if py >= GROUND - 14:
        py = float(GROUND - 14); pvy = 0.0; on_ground = True
    if py < float(CEILING):
        py = float(CEILING); pvy = 0.0

    if slow_t > 0: slow_t -= 1
    if rev_t  > 0: rev_t  -= 1
    if inv_t  > 0: inv_t  -= 1

    # ── Wolken ──────────────────────────────
    for c in clouds:
        c["x"] -= c["spd"]
        if c["x"] < -c["w"] - 10:
            c["x"] = float(W + 5)
            c["y"] = float(random.randint(12, 55))
            c["w"] = random.randint(20, 40)

    # ── Spawn ───────────────────────────────
    spawn_t += 1
    if spawn_t >= spawn_iv:
        spawn_t = 0
        spawn_iv = max(60, spawn_iv - 1)
        spawn_next_form()

    heart_t += 1
    if heart_t >= 900:
        heart_t = 0
        if lives < 3 and random.random() < 0.7:
            hearts.append(new_heart())
        elif random.random() < 0.3:
            hearts.append(new_heart())

    # ── Herzen ──────────────────────────────
    for h in hearts[:]:
        h["wb"] += 0.08
        h["x"]  -= 1.5
        if h["x"] < cam_x - 12: hearts.remove(h); continue
        sx = h["x"] - cam_x
        if hit(px - cam_x + 2, py+2, 7, 12, sx-5, h["y"]-5, 12, 12):
            hearts.remove(h)
            if lives < 3:
                lives += 1
                pyxel.play(3, 4)
                add_float("+1 LEBEN!", int(px - cam_x), int(py) - 12, 8)
                boom(int(sx), int(h["y"]), 8, 8)
            else:
                add_float("VOLL!", int(px - cam_x), int(py) - 10, 7)

    # ── Formulare ───────────────────────────
    spx = px - cam_x   # Spieler auf Bildschirm

    for f in forms[:]:
        f["wb"] += 0.06
        f["x"]  += f["vx"]
        sfx = f["x"] - cam_x   # Formular auf Bildschirm

        if sfx < -20:
            forms.remove(f); continue

        if inv_t <= 0:
            if f["type"] == "floor":
                # Boden-Formular: liegt am Boden, Spieler muss springen
                # Kollision normal wenn aufrecht, slide macht Hitbox kleiner
                if sliding:
                    phit = hit(spx+3, py+8, 5, 6, sfx, f["y"], 11, 13)
                else:
                    phit = hit(spx+2, py+2, 7, 12, sfx, f["y"], 11, 13)
                if phit:
                    forms.remove(f)
                    _form_hit(f); continue

            elif f["type"] == "air":
                # Luft-Formular: schwebt in Kopfhoehe
                # Slide = Spieler duckt sich -> kein Treffer moeglich
                if not sliding:
                    phit = hit(spx+2, py, 7, 10, sfx, f["y"], 11, 13)
                    if phit:
                        forms.remove(f)
                        _form_hit(f); continue

    # Trophae
    if trophy_spawned:
        tscreen_x = (cam_x + W - 22) - cam_x   # immer rechts sichtbar
        if hit(spx, py, 10, 14, W-22, GROUND-22, 14, 22):
            state = "win"; pyxel.play(3, 0)
            boom(W-15, GROUND-11, 10, 20)
            boom(W-15, GROUND-11, 9, 12)

    for ft in floats[:]:
        ft["y"] -= 0.55; ft["l"] -= 1
        if ft["l"] <= 0: floats.remove(ft)
    for p in parts[:]:
        p["x"] += p["vx"]; p["y"] += p["vy"]
        p["vy"] += 0.12;   p["l"]  -= 1
        if p["l"] <= 0: parts.remove(p)

def _form_hit(f):
    global lives, slow_t, rev_t, inv_t, shake, state, dist
    kind = f["kind"]
    if kind == "slow":
        slow_t = 160; inv_t = 60
        pyxel.play(3, 3)
        add_float("SLOW!", int(px - cam_x), int(py) - 10, 9)
    elif kind == "rev":
        rev_t = 110; inv_t = 60
        pyxel.play(3, 3)
        add_float("UMGEKEHRT!", int(px - cam_x) - 8, int(py) - 10, 14)
    else:
        lives -= 1
        dist = max(0.0, dist - PENALTY)
        pyxel.play(3, 1)
        shake = 10
        boom(int(px - cam_x + 5), int(py+7), 8)
        add_float("AU! -" + str(PENALTY) + "m", int(px - cam_x) - 8, int(py) - 10, 8)
        if lives <= 0:
            state = "over"
        else:
            inv_t = 90

# ── DRAW-HELFER ─────────────────────────────

def draw_cloud(cx, cy, cw, col):
    pyxel.rect(cx,       cy+3, cw,      5, col)
    pyxel.rect(cx+3,     cy+1, cw-6,    4, col)
    pyxel.rect(cx+cw//3, cy,   cw//3+1, 4, col)

def draw_bush(x, y):
    pyxel.rect(x-1, y-1, 3, 2, 3)
    pyxel.rect(x-4, y-5, 9, 5, 11)
    pyxel.rect(x-3, y-7, 7, 3, 11)
    pyxel.rect(x-1, y-8, 3, 2, 11)

def draw_stone(x, y):
    pyxel.rect(x-3, y-2, 7, 3, 13)
    pyxel.rect(x-2, y-4, 5, 3, 13)
    pyxel.pset(x-1, y-3, 7)

def draw_lamp(x, y):
    pyxel.rect(x,   y-12, 2, 12, 5)
    pyxel.rect(x-3, y-15, 8,  4, 5)
    pyxel.rect(x-2, y-14, 6,  3, 10)
    pyxel.pset(x+1, y-13, 7)

def draw_heart_pickup(hx, hy, wb):
    sc = 1 if int(wb * 2) % 2 == 0 else 0
    pyxel.rect(hx-2+sc, hy-3, 3, 2, 8)
    pyxel.rect(hx+1+sc, hy-3, 3, 2, 8)
    pyxel.rect(hx-3+sc, hy-1, 7, 3, 8)
    pyxel.rect(hx-2+sc, hy+2, 5, 2, 8)
    pyxel.rect(hx-1+sc, hy+4, 3, 1, 8)
    pyxel.pset(hx+sc,   hy-2, 14)

def draw_form(f, sfx):
    fy = int(f["y"] + math.sin(f["wb"]) * 1.5)
    fx = int(sfx)
    kind = f["kind"]
    ftype = f["type"]

    if kind == "slow":
        bg = 12; border = 7; lbl_bg = 1; lbl = "SL"
    elif kind == "rev":
        bg = 14; border = 7; lbl_bg = 2; lbl = "RV"
    else:
        bg = 7;  border = 0; lbl_bg = 8; lbl = ""

    # Luft-Formulare haben orangen Rahmen als Warnung
    if ftype == "air":
        border = 9

    # Schatten
    pyxel.rect(fx+2, fy+2, 11, 13, 0)
    # Papier
    pyxel.rect(fx, fy, 11, 13, bg)
    pyxel.rectb(fx, fy, 11, 13, border)
    # Eselsohr
    pyxel.tri(fx+7, fy, fx+11, fy, fx+11, fy+4, 13)
    pyxel.line(fx+7, fy, fx+11, fy+4, border)
    # Linien
    for li in range(3):
        pyxel.rect(fx+2, fy+4+li*3, 6, 1, border)
    # Label-Hintergrund
    pyxel.rect(fx+1, fy+1, 9, 6, lbl_bg)
    pyxel.text(fx+1, fy+1, "JOB", bg if kind != "norm" else 7)
    # Sonder-Label
    if lbl:
        pyxel.rect(fx+1, fy+8, 9, 4, border)
        pyxel.text(fx+2, fy+8, lbl, bg)

    # Hinweis-Pfeil: Boden = Pfeil hoch (springen), Luft = Pfeil runter (sliden)
    if ftype == "floor":
        # Pfeil nach oben
        pyxel.tri(fx+5, fy-7, fx+2, fy-3, fx+8, fy-3, 10)
    else:
        # Pfeil nach unten + schwebt (keine Schwerkraft)
        pyxel.tri(fx+5, fy+16, fx+2, fy+12, fx+8, fy+12, 9)

def draw_trophy():
    tx = W - 22; ty = GROUND - 22
    gc = 10 if (frame_count // 8) % 2 == 0 else 9
    pyxel.rectb(tx-3, ty-3, 20, 28, gc)
    pyxel.rectb(tx-4, ty-4, 22, 30, 0)
    pyxel.rect(tx,    ty+20, 14, 2, 6)
    pyxel.rect(tx+2,  ty+22, 10, 3, 5)
    pyxel.rect(tx+5,  ty+15, 4,  6, 9)
    pyxel.rect(tx+2,  ty+2,  10,13, 10)
    pyxel.rect(tx+1,  ty+4,  12,10, 10)
    pyxel.rectb(tx-1, ty+4,  3,  7, 9)
    pyxel.rectb(tx+12,ty+4,  3,  7, 9)
    pyxel.line(tx+4,  ty+3,  tx+4, ty+8, 7)
    pyxel.rect(tx+5,  ty-1,  4,   4, 10)
    pyxel.pset(tx+6, ty, 7)
    lc = 10 if (frame_count//15)%2==0 else 7
    pyxel.text(tx-8, ty-10, "!!!ZIEL!!!", lc)

def draw_player():
    if inv_t > 0 and (inv_t // 4) % 2 == 1:
        return

    # Spieler-Position auf Bildschirm
    ipx = int(px - cam_x)
    ipy = int(py)

    # ── Farben: Cyan (12) Koerper, schwarz Haare/Schuhe ──
    # Cyan ist auf ALLEN Hintergruenden (blau, orange, rot, schwarz) sichtbar
    body  = 12   # Cyan  – Koerper/Jacke
    hair  = 0    # Schwarz – Haare
    shoe  = 0    # Schwarz – Schuhe
    leg   = 5    # Grau – Hose
    tie   = 8    # Rot – Krawatte
    eye   = 0    # Schwarz – Augen
    arm   = 12   # Cyan – Arme

    if slow_t > 0: body = arm = 9    # Orange wenn slow
    if rev_t  > 0: body = arm = 14   # Pink wenn rev

    if sliding:
        # Ducken: kompakter Koerper, nur 7px hoch
        pyxel.rect(ipx,   ipy+10, 12, 4, body)   # Koerper
        pyxel.rect(ipx+1, ipy+9,  7,  2, hair)   # Haare
        pyxel.rect(ipx+8, ipy+9,  5,  5, body)   # Kopf
        pyxel.pset(ipx+10,ipy+10, eye)            # Auge
        pyxel.rect(ipx,   ipy+12, 5,  3, leg)    # Bein
        pyxel.rect(ipx,   ipy+13, 4,  2, shoe)   # Schuh
        return

    lo = 3 if wframe == 1 else 0

    # Beine
    pyxel.rect(ipx+2, ipy+11, 4, 3+lo,     leg)
    pyxel.rect(ipx+6, ipy+11, 4, 3+(3-lo), leg)
    # Schuhe
    pyxel.rect(ipx+1, ipy+13+lo,     5, 2, shoe)
    pyxel.rect(ipx+5, ipy+13+(3-lo), 5, 2, shoe)
    # Koerper
    pyxel.rect(ipx+2, ipy+5, 7, 7, body)
    # Krawatte
    pyxel.rect(ipx+5, ipy+6, 1, 5, tie)
    pyxel.pset(ipx+5, ipy+11, tie)
    # Kragen
    pyxel.rect(ipx+3, ipy+5, 5, 2, 7)
    # Arme
    pyxel.rect(ipx,   ipy+5, 2, 6, arm)
    pyxel.rect(ipx+9, ipy+5, 2, 6, arm)
    # Haende
    pyxel.rect(ipx,   ipy+10, 2, 2, shoe)
    pyxel.rect(ipx+9, ipy+10, 2, 2, shoe)
    # Kopf
    pyxel.rect(ipx+2, ipy, 7, 6, body)
    # Haare
    pyxel.rect(ipx+2, ipy-1, 7, 2, hair)
    pyxel.rect(ipx+2, ipy,   2, 2, hair)
    # Augen
    ec = tie if inv_t > 0 else eye
    pyxel.pset(ipx+4, ipy+2, ec)
    pyxel.pset(ipx+7, ipy+2, ec)
    # Mund
    pyxel.pset(ipx+5, ipy+4, eye)
    pyxel.pset(ipx+6, ipy+4, eye)

    # Status
    if slow_t > 0:
        pyxel.text(ipx-2, ipy-11, "SLOW", 0)
        pyxel.text(ipx-3, ipy-12, "SLOW", 9)
    if rev_t > 0:
        pyxel.text(ipx-2, ipy-11, "REV!", 0)
        pyxel.text(ipx-3, ipy-12, "REV!", 14)

def draw_bg(sx, sy):
    z = cur_zone()
    sky = zone_col(0)
    pyxel.rect(0, 0, W, GROUND, sky)

    bg_scroll = int(dist * 0.08)

    if z == 0:   # Nacht
        for i in range(18):
            pyxel.pset((i*41 + bg_scroll) % W, (i*23) % (GROUND-20), 7)
        mx = (bg_scroll // 3 + 140) % W
        pyxel.rect(mx+sx, 10+sy, 10, 10, 7)
        pyxel.rect(mx+3+sx, 13+sy, 6, 6, sky)

    elif z == 1:  # Daemmerung
        pyxel.rect(0, GROUND//2, W, GROUND//2, 9)
        for i in range(3):
            pyxel.rect(0, GROUND-28+i*9, W, 9, [9,8,2][i])
        sx2 = (bg_scroll//4 + 100) % W
        pyxel.rect(sx2+sx-6, 14+sy, 12, 12, 9)
        pyxel.rect(sx2+sx-4, 12+sy, 8, 16, 9)
        pyxel.rect(sx2+sx-8, 18+sy, 16, 4, 9)
        pyxel.rect(sx2+sx-4, 16+sy, 8, 8, 10)

    elif z == 2:  # Gewitter
        if frame_count % 120 < 5:
            lx = (frame_count * 37) % (W-20) + 10
            pyxel.rect(lx+sx, 0+sy, 2, GROUND, 7)
        for i in range(6):
            cx2 = (i*45 + bg_scroll//2) % W
            cy2 = 5 + (i*13) % 35
            pyxel.rect(cx2+sx, cy2+sy, 35, 9, 5)
            pyxel.rect(cx2+4+sx, cy2-3+sy, 27, 7, 5)

    elif z == 3:  # Buero-Hoelle
        for i in range(0, GROUND, 20):
            c = 8 if (i//20)%2==0 else 2
            pyxel.rect(0, i, W, 10, c)
        sx2 = (bg_scroll//5 + 80) % W
        pyxel.rect(sx2+sx-7, 12+sy, 14, 14, 14)
        pyxel.rect(sx2+sx-5, 10+sy, 10, 18, 14)
        pyxel.rect(sx2+sx-9, 16+sy, 18,  6, 14)
        pyxel.rect(sx2+sx-4, 15+sy, 8,   8,  8)

    else:         # Endspurt
        for i in range(20):
            pyxel.pset((i*31 + bg_scroll) % W, (i*17) % (GROUND-20), 14)
            pyxel.pset((i*53 + bg_scroll//2) % W, (i*29) % (GROUND-20), 8)
        for i in range(4):
            cx2 = (i*60 + bg_scroll//3) % W
            pyxel.rect(cx2+sx, 10+i*8+sy, 50, 12, 2)

    if z in (0, 1, 4):
        cc = zone_col(4)
        for c in clouds:
            draw_cloud(int(c["x"])+sx, int(c["y"])+sy, c["w"], cc)

def draw_ground_and_buildings(sx, sy):
    gc = zone_col(1)
    lc = zone_col(2)
    bc = zone_col(3)

    bg_scroll = int(dist * 0.05)
    bld_data = [
        (0,35,55),(38,28,40),(70,42,70),(115,25,45),
        (143,38,60),(185,30,50),(218,45,75),(268,32,55),
    ]
    for (bx, bw, bh) in bld_data:
        rx = int((bx - bg_scroll) % (W+80) + W+80) % (W+80) - 80
        pyxel.rect(rx+sx, GROUND-bh+sy, bw, bh, bc)
        pyxel.rectb(rx+sx, GROUND-bh+sy, bw, bh, 0)
        for wy in range(GROUND-bh+5, GROUND-4, 9):
            for wx in range(rx+3, rx+bw-3, 7):
                lit = (wx*3 + wy*7 + bg_scroll//40) % 7 == 0
                fc  = 6 if lit else 0
                pyxel.rect(wx+sx, wy+sy, 3, 4, fc)

    pyxel.rect(sx, GROUND+sy, W, H-GROUND, gc)
    pyxel.rect(sx, GROUND+sy, W, 2, lc)
    for x in range(int(-dist*0.3 % 25), W, 25):
        pyxel.line(x+sx, GROUND+sy, x+sx, GROUND+6+sy, lc)

    deco_positions = [20, 55, 95, 140, 170]
    deco_kinds     = ["lamp","bush","stone","lamp","bush"]
    for i, bx in enumerate(deco_positions):
        rx = int((bx - int(dist*0.3)) % (W+30) + W+30) % (W+30) - 30
        ddy = GROUND + sy
        if deco_kinds[i] == "bush":    draw_bush(rx+sx, ddy)
        elif deco_kinds[i] == "stone": draw_stone(rx+sx, ddy)
        elif deco_kinds[i] == "lamp":  draw_lamp(rx+sx, ddy)

# ── DRAW ────────────────────────────────────

def draw():
    global warn_air
    
    pyxel.cls(0)

    if state == "start": draw_start(); return
    if state == "win":   draw_end(True); return
    if state == "over":  draw_end(False); return

    sx = random.randint(-2, 2) if shake > 0 else 0
    sy = random.randint(-1, 1) if shake > 0 else 0

    draw_bg(sx, sy)
    draw_ground_and_buildings(sx, sy)
    # WARNUNG für Luft-Formular
    if warn_air > 0:
        if (warn_air // 5) % 2 == 0:
            pyxel.text(W//2 - 10, 20, "SLIDE!", 9)
            pyxel.tri(W//2, 35, W//2 - 5, 28, W//2 + 5, 28, 9)

    if trophy_spawned:
        draw_trophy()

    # Formulare
    for f in forms:
        sfx = f["x"] - cam_x
        if -20 < sfx < W + 20:
            draw_form(f, sfx)

    # Herzen
    for h in hearts:
        hsx = h["x"] - cam_x
        if -15 < hsx < W + 15:
            draw_heart_pickup(int(hsx), int(h["y"]), h["wb"])

    # Partikel
    for p in parts:
        pyxel.pset(int(p["x"]), int(p["y"]), p["c"])

    # Spieler
    draw_player()

    # Schwebende Texte
    for ft in floats:
        pyxel.text(int(ft["x"])+1, int(ft["y"])+1, ft["t"], 0)
        pyxel.text(int(ft["x"]),   int(ft["y"]),   ft["t"], ft["c"])

    # ── HUD ─────────────────────────────────
    pyxel.rect(0, 0, W, 11, 0)
    pyxel.rect(0, 11, W, 1, 5)

    pyxel.text(2, 2, "HP:", 7)
    for i in range(3):
        pyxel.text(20+i*11, 2, "<3", 8 if i < lives else 2)

    prog_pct = int(min(dist / TROPHY_DIST, 1.0) * 100)
    t_col = 8 if prog_pct > 80 else (9 if prog_pct > 50 else 10)
    pyxel.text(W//2-12, 2, str(prog_pct)+"%", t_col)

    dist_str = str(int(dist)) + "m"
    pyxel.text(W - len(dist_str)*4 - 2, 2, dist_str, 9)

    prog = min(1.0, dist / TROPHY_DIST)
    pyxel.rect(0, 12, int(W*prog), 3, 10)
    pyxel.rectb(0, 12, W, 3, 5)

    if slow_t > 0: pyxel.rect(0, 15, int((slow_t/160)*W), 2, 9)
    if rev_t  > 0: pyxel.rect(0, 15, int((rev_t/110)*W),  2, 14)

    z_names = ["ZONE 1: NACHT","ZONE 2: DAEMMERUNG",
               "ZONE 3: GEWITTER","ZONE 4: BUERO-HOELLE","ZONE 5: ENDSPURT"]
    z_cols  = [7, 9, 6, 8, 14]
    z = cur_zone()
    pyxel.rect(0, H-9, W, 9, 0)
    pyxel.text(2, H-8, z_names[z], z_cols[z])

    if sliding:
        pyxel.text(W-42, H-8, "SLIDE!", 12)
    elif trophy_spawned:
        lc = 10 if (frame_count//15)%2==0 else 9
        pyxel.text(W-38, H-8, "->ZIEL!", lc)
    else:
        pyxel.text(W-46, H-8, "S=SLIDE", 6)

# ── SCREENS ─────────────────────────────────

def draw_start():
    pyxel.rect(0, 0, W, H, 1)
    for i, (bx, bw, bh, bc) in enumerate([
        (0,28,55,2),(30,22,42,13),(55,35,70,2),(93,20,45,13),
        (116,30,62,2),(150,25,50,13),(177,28,65,2)]):
        pyxel.rect(bx, GROUND-bh, bw, bh, bc)
        pyxel.rectb(bx, GROUND-bh, bw, bh, 0)
        for wy in range(GROUND-bh+4, GROUND-4, 8):
            for wx in range(bx+3, bx+bw-3, 6):
                if (wx+wy)%3!=0: pyxel.rect(wx, wy, 3, 4, 10)
    pyxel.rect(0, GROUND, W, H-GROUND, 5)

    pyxel.rect(W//2-40, 14, 80, 16, 0)
    pyxel.rectb(W//2-40, 14, 80, 16, 10)
    pyxel.text(W//2-28, 18, "OHNE JOB", 10)
    pyxel.text(W//2-29, 19, "OHNE JOB", 9)

    pyxel.rect(4, 36, W-8, 100, 0)
    pyxel.rectb(4, 36, W-8, 100, 5)

    pyxel.text(8, 39, "A/D   = Laufen",              7)
    pyxel.text(8, 47, "W / Leertaste = Springen",     7)
    pyxel.text(8, 55, "S / Unten     = Sliden",       12)
    pyxel.rect(8, 63, W-18, 1, 5)
    pyxel.text(8, 66, "Weiss JOB am BODEN -> Springen!", 7)
    pyxel.text(8, 74, "Oran. JOB in LUFT  -> Sliden!",   9)
    pyxel.rect(8, 82, W-18, 1, 5)
    pyxel.text(8, 85, "SL = Verlangsamt dich",        12)
    pyxel.text(8, 93, "RV = Dreht Steuerung um",      14)
    pyxel.rect(8,101, W-18, 1, 5)
    pyxel.text(8,104, "<3 Herz    = +1 Leben",        8)
    pyxel.text(8,112, "Treffer    = -" + str(PENALTY) + "m Strecke!", 9)
    pyxel.text(8,120, "Ziel: " + str(TROPHY_DIST) + "m zuruecklegen!", 10)

    if (pyxel.frame_count//30)%2==0:
        pyxel.rect(W//2-54, 142, 108, 11, 0)
        pyxel.rectb(W//2-54, 142, 108, 11, 10)
        pyxel.text(W//2-51, 145, "[ LEERTASTE zum Starten ]", 10)

def draw_end(won):
    z = min(4, int(dist // ZONE_LEN))
    pyxel.rect(0, 0, W, H, [1,0,2,2,1][z])
    for p in parts:
        pyxel.pset(int(p["x"]), int(p["y"]), p["c"])

    secs = frame_count // 60
    m = secs // 60; s = secs % 60
    t_str = str(m) + ":" + ("0"+str(s) if s < 10 else str(s))

    if won:
        pyxel.rect(W//2-44, 26, 88, 16, 0)
        pyxel.rectb(W//2-44, 26, 88, 16, 10)
        pyxel.text(W//2-30, 30, "FREIHEIT!", 10)
        pyxel.text(W//2-31, 31, "FREIHEIT!", 9)
        pyxel.rect(4, 50, W-8, 60, 0)
        pyxel.rectb(4, 50, W-8, 60, 10)
        pyxel.text(8, 54, "Trophaee erreicht!", 7)
        pyxel.text(8, 64, "Zeit:    " + t_str, 10)
        pyxel.text(8, 74, "Strecke: " + str(int(dist)) + "m", 9)
        pyxel.text(8, 84, "Du bist frei, mein Akh!", 8)
    else:
        pyxel.rect(W//2-44, 26, 88, 16, 0)
        pyxel.rectb(W//2-44, 26, 88, 16, 8)
        pyxel.text(W//2-29, 30, "GAME OVER", 8)
        pyxel.text(W//2-30, 31, "GAME OVER", 7)
        pyxel.rect(4, 50, W-8, 60, 0)
        pyxel.rectb(4, 50, W-8, 60, 8)
        pyxel.text(8, 54, "Formulare haben gewonnen!", 7)
        pyxel.text(8, 64, "Zeit:    " + t_str, 9)
        pyxel.text(8, 74, "Strecke: " + str(int(dist)) + "m", 6)
        pyxel.text(8, 84, "Fehlten: " + str(max(0, int(TROPHY_DIST-dist))) + "m", 8)

    if (pyxel.frame_count//30)%2==0:
        pyxel.rect(W//2-54, 120, 108, 11, 0)
        pyxel.rectb(W//2-54, 120, 108, 11, 7)
        pyxel.text(W//2-51, 123, "[ LEERTASTE zum Neustart ]", 7)

pyxel.run(update, draw)