# Nuss-Mission DELUXE v5 – 512×512, Story, Boss, animierte Sprites
import pyxel, random, math
 
SCREEN_W = 512
SCREEN_H = 512
GRAVITY   = 0.32
WALK_SPEED= 2.2
JUMP_PWR  = -7.2
WALL_JUMP_X = 5.0
WALL_JUMP_Y = -5.8
STAMINA_MAX = 100
COYOTE_TIME = 8
JUMP_BUFFER = 8
 
# ═══════════════════════════════════════════════════════════════
#  STORY-TEXTE
# ═══════════════════════════════════════════════════════════════
STORY_INTRO = [
    "Der Winter naht...",
    "Eichhörnchen NUSS sucht",
    "die legendaere",
    "GOLDENE EICHEL!",
    "Sie soll im Inferno-",
    "Gipfel verborgen sein.",
]
LEVEL_STORY = [
    ["Nuss betritt den Wald.", "Opa Eichhorn warnt:", "'Huete dich vor dem", "roten Krieger!'"],
    ["Kristall-Fee Glitzer", "friert den Pfad ein.", "'Nur die Tapferste", "geht weiter!'"],
    ["Tempel-Waechter Magmor", "blockiert den Weg.", "'Kein Sterblicher", "passiert hier!'"],
    ["Windgeist Zephira", "tanzt im Sturm.", "'Ich bringe dich zum", "Gipfel!'"],
    ["Geister-Koenig Mortis", "lacht eisig kalt.", "'Deine Nuss wirst du", "nie finden!'"],
    ["ENDGEGNER: INFERNO-REX!", "Das Feuer-Monster", "bewacht die GOLDENE", "EICHEL! Bewaeltige es!"],
]
NPC_DIALOGUE = [
    "Opa Eichhorn: Sammle alle\nNuesse fuer die Kraft!\nDash mit Z!",
    "Glitzer-Fee: Klettre an\nEis-Waenden hoch!\nStamina im Blick!",
    "Feuerwaechter: Spring\nueber die Lava-Stacheln!\nTiming ist alles!",
    "Zephira: Der Wind ist\ndein Freund - oder Feind.\nHalte die Balance!",
    "Schattenbote: Mortis\nhat Angst vor dem Licht!\nSuche die Goldene!",
    "INFERNO-REX: ICH BIN\nDAS FEUER DER WELT!\nDU KANNST MICH NICHT\nBESTEHEN!",
]
 
# ═══════════════════════════════════════════════════════════════
#  NPC-HELFER-KLASSE
# ═══════════════════════════════════════════════════════════════
class NPC:
    def __init__(self, x, y, col=9):
        self.x = x
        self.y = y
        self.sprite_col = col
        self.talking = False
 
# ═══════════════════════════════════════════════════════════════
#  PARTIKEL
# ═══════════════════════════════════════════════════════════════
class Particle:
    def __init__(self, x=None, y=None, vx=0, vy=0, col=7, life=30, kind="dust"):
        self.x   = x if x is not None else random.randint(0, SCREEN_W)
        self.y   = y if y is not None else random.randint(0, SCREEN_H)
        self.vx  = vx; self.vy = vy; self.col = col
        self.life = life; self.max_life = life; self.kind = kind
 
    def update(self, wind=0):
        k = self.kind
        if k == "leaf":
            self.x += self.vx + wind*1.5; self.y += self.vy
            self.vx = math.sin(self.life*0.3)*0.6
            self.vy = min(self.vy+0.05, 0.8)
            if self.x < -5: self.x = SCREEN_W+5
            if self.x > SCREEN_W+5: self.x = -5
            if self.y > SCREEN_H+5: self.y = -5
        elif k == "snow":
            self.x += self.vx + wind*2 + math.sin(self.life*0.1)*0.3; self.y += self.vy
            if self.x > SCREEN_W+5: self.x = -5
            if self.x < -5: self.x = SCREEN_W+5
            if self.y > SCREEN_H+5: self.y = -5
        elif k == "ice_drip":
            self.x += self.vx; self.y += self.vy
            self.vy = min(self.vy+0.04, 1.5)
            if self.y > SCREEN_H+5: self.life = 0
        elif k == "rain":
            self.x += self.vx + wind*1.2; self.y += self.vy
            if self.y > SCREEN_H+5: self.y = -5; self.x = random.randint(0, SCREEN_W)
        elif k == "ember":
            self.x += self.vx + math.sin(self.life*0.2)*0.4; self.y += self.vy
            self.vy -= 0.025
            if self.y < -5: self.y = SCREEN_H+5; self.x = random.randint(0, SCREEN_W)
        elif k == "cloud_wisp":
            self.x += self.vx + wind*0.5; self.y += self.vy
            if self.x > SCREEN_W+20: self.x = -20
            if self.x < -20: self.x = SCREEN_W+20
        elif k == "firefly":
            self.x += self.vx + math.sin(self.life*0.07)*0.5
            self.y += self.vy + math.cos(self.life*0.05)*0.4
            if self.x < -5: self.x = SCREEN_W+5
            if self.x > SCREEN_W+5: self.x = -5
            if self.y < 0: self.y = SCREEN_H
            if self.y > SCREEN_H: self.y = 0
        elif k == "spore":
            self.x += self.vx + math.sin(self.life*0.12)*0.3; self.y += self.vy
            if self.y > SCREEN_H: self.y = 0
            if self.x < -5: self.x = SCREEN_W+5
            if self.x > SCREEN_W+5: self.x = -5
        elif k == "ghost_wisp":
            self.x += self.vx + math.sin(self.life*0.04)*0.8
            self.y += self.vy + math.cos(self.life*0.03)*0.4
            if self.x < -10: self.x = SCREEN_W+10
            if self.x > SCREEN_W+10: self.x = -10
            if self.y < 0: self.vy = abs(self.vy)
            if self.y > SCREEN_H: self.vy = -abs(self.vy)
        else:
            self.x += self.vx; self.y += self.vy
            self.vy += 0.12; self.vx *= 0.92
        self.life -= 1
 
    def is_alive(self): return self.life > 0
 
 
# ═══════════════════════════════════════════════════════════════
#  PLATTFORMEN
# ═══════════════════════════════════════════════════════════════
class Platform:
    def __init__(self, x, y, w, h, p_type, move_range=0, move_speed=0, move_vert=False):
        self.x=x; self.ox=x; self.y=y; self.oy=y
        self.w=w; self.h=h; self.p_type=p_type
        self.move_range=move_range; self.move_speed=move_speed; self.move_vert=move_vert
        self.phase=random.uniform(0, math.pi*2)
 
    def update(self, t):
        if self.move_range:
            if self.move_vert:
                self.y = self.oy + math.sin(t*self.move_speed+self.phase)*self.move_range
            else:
                self.x = self.ox + math.sin(t*self.move_speed+self.phase)*self.move_range
 
 
# ═══════════════════════════════════════════════════════════════
#  ITEMS
# ═══════════════════════════════════════════════════════════════
class Item:
    def __init__(self, x, y, kind="nut"):
        self.x=x; self.y=y; self.kind=kind; self.alive=True
        self.bob=random.uniform(0, math.pi*2)
 
    def update(self): self.bob += 0.08
 
    def screen_y(self): return self.y + math.sin(self.bob)*2
 
 
# ═══════════════════════════════════════════════════════════════
#  GEGNER
# ═══════════════════════════════════════════════════════════════
class Enemy:
    def __init__(self, x, y, kind="patrol"):
        self.x=x; self.y=y; self.kind=kind
        self.vx=0.8; self.vy=0.0; self.alive=True
        self.timer=0; self.start_x=x; self.start_y=y; self.anim=0
        self.hp = 5 if kind=="boss" else 1
        self.phase = 0
        self.shoot_cd = 0
        self.fireballs = []
        self.stomp_timer = 0
 
    def update(self, px, py):
        self.timer += 1
        self.anim  = (self.timer//8)%4
        if self.kind == "patrol":
            self.x += self.vx
            if abs(self.x-self.start_x) > 40: self.vx *= -1
        elif self.kind == "chase":
            dx=px-self.x; dy=py-self.y
            dist=max(1, math.sqrt(dx*dx+dy*dy))
            if dist < 90: self.x += dx/dist*0.85; self.y += dy/dist*0.5
        elif self.kind == "jumper":
            self.x += self.vx
            if abs(self.x-self.start_x) > 30: self.vx *= -1
            if self.timer%60 == 0: self.vy = -3.5
            self.vy += 0.2; self.y += self.vy
            if self.y >= self.start_y: self.y = self.start_y; self.vy = 0
        elif self.kind == "flyer":
            self.x = self.start_x + math.sin(self.timer*0.04)*50
            self.y = self.start_y + math.sin(self.timer*0.07)*25
        elif self.kind == "boss":
            self._update_boss(px, py)
 
    def _update_boss(self, px, py):
        if   self.hp <= 1: self.phase = 2
        elif self.hp <= 3: self.phase = 1
        else:              self.phase = 0
        speed = [0.8, 1.2, 1.8][self.phase]
        dx = px - self.x
        self.x += math.copysign(speed, dx)
        interval = [90, 60, 40][self.phase]
        if self.timer % interval == 0:
            self.vy = -5.0
            self.stomp_timer = 8
        self.vy += 0.25; self.y += self.vy
        if self.y >= self.start_y: self.y = self.start_y; self.vy = 0
        self.shoot_cd -= 1
        fire_rate = [120, 70, 45][self.phase]
        if self.shoot_cd <= 0:
            self.shoot_cd = fire_rate
            dx2=px-self.x; dy2=py-self.y
            dist=max(1, math.sqrt(dx2*dx2+dy2*dy2))
            spd=2.5+self.phase*0.7
            self.fireballs.append({"x":self.x,"y":self.y-8,"vx":dx2/dist*spd,"vy":dy2/dist*spd})
        nf = []
        for fb in self.fireballs:
            fb["x"] += fb["vx"]; fb["y"] += fb["vy"]
            if 0 <= fb["x"] <= SCREEN_W and 0 <= fb["y"] <= SCREEN_H:
                nf.append(fb)
        self.fireballs = nf
 
 
# ═══════════════════════════════════════════════════════════════
#  HAUPTSPIEL
# ═══════════════════════════════════════════════════════════════
class Game:
    def __init__(self):
        pyxel.init(SCREEN_W, SCREEN_H, title="Nuss-Mission DELUXE v5")
        self._init_sounds()
        self.lvl_idx = 0
        self.hi_score = 0
        self.bg_particles = []
        self.fx_particles = []
        self.state = "TITLE"
        self.title_t = 0
        self.t = 0
        self.aurora_strips = []
        self.lightning_timer = 0
        self.lightning_x = 0
        self.lightning_active = 0
        self.lightning_segs = []
        self.lava_bubbles = [(random.randint(0, SCREEN_W), random.uniform(0, math.pi*2)) for _ in range(12)]
        self.rainbow_phase = 0
        self.inferno_cracks = [(random.randint(20, SCREEN_W-20), random.randint(250, 400),
                                random.randint(-30, 30), random.randint(20, 50)) for _ in range(12)]
        self.story_page = 0
        self.story_timer = 0
        self.story_lines = []
        self.dialog_active = False
        self.dialog_text = ""
        self.dialog_timer = 0
        self.npcs = []
        self.shake = 0
        self._spawn_bg_particles()
        pyxel.run(self.update, self.draw)
 
    def _init_sounds(self):
        pyxel.sound(0).set("a2", "p", "3", "n", 6)
        pyxel.sound(1).set("c3", "t", "6", "n", 5)
        pyxel.sound(2).set("f1", "n", "4", "f", 8)
        pyxel.sound(3).set("g3", "t", "5", "n", 8)
        pyxel.sound(4).set("a1", "n", "2", "f", 4)
        pyxel.sound(5).set("c4e4g4c5", "t", "5", "n", 12)
        pyxel.sound(6).set("g2g2b2b2", "t", "4", "n", 8)
        pyxel.sound(7).set("e3", "p", "4", "n", 5)
        pyxel.sound(8).set("c3e3g3e4", "t", "6", "n", 14)
 
    def _spawn_bg_particles(self):
        self.bg_particles = []
        self.fx_particles = []
        idx = self.lvl_idx
        if idx == 0:
            for _ in range(30):
                c = random.choice([3, 9, 10, 4])
                self.bg_particles.append(Particle(
                    x=random.randint(0, SCREEN_W), y=random.randint(0, SCREEN_H),
                    vx=random.uniform(-0.4, 0.4), vy=random.uniform(0.3, 0.9),
                    col=c, life=9999, kind="leaf"))
            for _ in range(12):
                self.bg_particles.append(Particle(
                    x=random.randint(0, SCREEN_W), y=random.randint(60, 350),
                    vx=random.uniform(-0.2, 0.2), vy=random.uniform(-0.1, 0.1),
                    col=random.choice([9, 10, 7]), life=9999, kind="firefly"))
        elif idx == 1:
            for _ in range(40):
                c = random.choice([6, 7, 12, 13])
                self.bg_particles.append(Particle(
                    x=random.randint(0, SCREEN_W), y=random.randint(0, SCREEN_H),
                    vx=random.uniform(-0.3, 0.3), vy=random.uniform(0.4, 1.0),
                    col=c, life=9999, kind="snow"))
            self.aurora_strips = [
                {"x": random.randint(0, SCREEN_W), "y": random.randint(30, 100),
                 "w": random.randint(60, 160), "col": random.choice([5, 12, 6, 1]),
                 "phase": random.uniform(0, math.pi*2)}
                for _ in range(8)
            ]
        elif idx == 2:
            for _ in range(30):
                c = random.choice([8, 9, 10, 4])
                self.bg_particles.append(Particle(
                    x=random.randint(0, SCREEN_W), y=random.randint(0, SCREEN_H),
                    vx=random.uniform(-0.5, 0.5), vy=random.uniform(-1.5, -0.4),
                    col=c, life=9999, kind="ember"))
        elif idx == 3:
            for _ in range(24):
                c = random.choice([6, 7, 12, 13])
                self.bg_particles.append(Particle(
                    x=random.randint(0, SCREEN_W), y=random.randint(20, 200),
                    vx=random.uniform(0.2, 0.8), vy=random.uniform(-0.1, 0.1),
                    col=c, life=9999, kind="cloud_wisp"))
            self.rainbow_phase = 0
        elif idx == 4:
            for _ in range(55):
                c = random.choice([5, 6, 1])
                self.bg_particles.append(Particle(
                    x=random.randint(0, SCREEN_W), y=random.randint(0, SCREEN_H),
                    vx=random.uniform(-0.5, -0.1), vy=random.uniform(4.0, 6.0),
                    col=c, life=9999, kind="rain"))
            for _ in range(20):
                self.bg_particles.append(Particle(
                    x=random.randint(0, SCREEN_W), y=random.randint(0, SCREEN_H),
                    vx=random.uniform(-0.3, 0.3), vy=random.uniform(-0.2, 0.2),
                    col=random.choice([5, 6, 1, 13]), life=9999, kind="ghost_wisp"))
            self.lightning_timer = random.randint(60, 200)
            self.lightning_active = 0
        else:
            for _ in range(40):
                c = random.choice([8, 9, 10, 2])
                self.bg_particles.append(Particle(
                    x=random.randint(0, SCREEN_W), y=random.randint(0, SCREEN_H),
                    vx=random.uniform(-0.6, 0.6), vy=random.uniform(-2.0, -0.5),
                    col=c, life=9999, kind="ember"))
 
    def init_lvl(self):
        self.px = 30
        self.py = 380
        self.vx = 0
        self.vy = 0
        self.stamina = STAMINA_MAX
        self.cam_x = 0
        self.score = 0
        self.facing = 1
        self.lock_timer = 0
        self.coyote = 0
        self.jump_buffer = 0
        self.state = "PLAY"
        self.wind = 0
        self.t = 0
        self.anim_frame = 0
        self.on_wall = False
        self.on_ceil = False
        self.dash_timer = 0
        self.dash_cd = 0
        self.hurt_timer = 0
        self.lives = 3
        self.enemies = []
        self.npcs = []
        self.dialog_active = False
        self.shake = 0
        self._spawn_bg_particles()
        self._build_level(self.lvl_idx)
 
    def _build_level(self, idx):
        # Scale factor: original was 256×192, now 512×512
        # X coords scaled ~2x, Y coords scaled ~2.5x but keep gameplay feel
        # Ground level ~420, ceiling ~28
        if idx == 0:
            self.bg_col = (1, 2)
            self.goal_x = 1600
            self.plats = [
                Platform(0,   420, 240, 80,  0),
                Platform(220, 0,   40,  480, 1),
                Platform(260, 25,  200, 28,  0),
                Platform(300, 200, 100, 24,  0),
                Platform(430, 0,   32,  480, 1),
                Platform(462, 360, 160, 50,  0),
                Platform(600, 140, 60,  24,  0, 50, 0.04),
                Platform(720, 12,  32,  480, 1),
                Platform(752, 360, 180, 50,  0),
                Platform(840, 180, 100, 24,  0),
                Platform(980, 0,   32,  480, 1),
                Platform(1012,360, 260, 50,  0),
                Platform(1120,220, 60,  24,  0, 40, 0.05),
                Platform(1300,0,   32,  480, 1),
                Platform(1332,360, 200, 50,  0),
            ]
            self.items = [
                Item(290, 160, "nut"), Item(480, 280, "nut"), Item(620, 110, "gem"),
                Item(760, 280, "nut"), Item(860, 130, "star"), Item(1130, 170, "nut"),
                Item(1350, 280, "star"),
            ]
            self.enemies = [Enemy(500, 350, "patrol"), Enemy(800, 350, "patrol")]
            self.npcs = [NPC(280, 390, 9)]
 
        elif idx == 1:
            self.bg_col = (5, 1)
            self.goal_x = 1900
            self.plats = [
                Platform(0,   420, 160, 80,  0),
                Platform(160, 0,   32,  480, 2),
                Platform(192, 12,  200, 28,  0),
                Platform(192, 420, 100, 80,  0),
                Platform(320, 200, 70,  24,  0, 60, 0.04),
                Platform(400, 0,   32,  480, 2),
                Platform(432, 360, 220, 70,  0),
                Platform(580, 120, 60,  24,  0, 70, 0.05),
                Platform(720, 0,   32,  480, 2),
                Platform(752, 420, 110, 80,  0),
                Platform(830, 180, 70,  24,  0, 50, 0.06),
                Platform(920, 0,   32,  480, 2),
                Platform(952, 360, 160, 70,  0),
                Platform(1060,140, 80,  24,  0, 40, 0.07),
                Platform(1200,360, 240, 70,  0),
                Platform(1280,220, 60,  24,  0, 60, 0.04),
                Platform(1500,360, 200, 70,  0),
            ]
            self.items = [
                Item(260, 370, "nut"), Item(460, 280, "nut"), Item(590, 90, "gem"),
                Item(780, 360, "nut"), Item(1080,110, "star"), Item(1240,190, "gem"),
                Item(1520,280, "star"),
            ]
            self.enemies = [
                Enemy(500, 350, "patrol"), Enemy(1000, 350, "chase"), Enemy(1280, 350, "patrol"),
            ]
            self.npcs = [NPC(250, 390, 12)]
 
        elif idx == 2:
            self.bg_col = (2, 8)
            self.goal_x = 2200
            self.plats = [
                Platform(0,   420, 140, 80,  0),
                Platform(140, 0,   32,  480, 1),
                Platform(172, 25,  180, 28,  4),
                Platform(172, 400, 120, 100, 3),
                Platform(320, 220, 70,  24,  0),
                Platform(400, 0,   32,  480, 1),
                Platform(432, 360, 160, 70,  0),
                Platform(550, 120, 60,  24,  0, 80, 0.05),
                Platform(700, 0,   32,  480, 2),
                Platform(732, 400, 90,  90,  3),
                Platform(800, 200, 70,  24,  0, 0, 0.06, True),
                Platform(900, 0,   32,  480, 1),
                Platform(932, 360, 180, 70,  0),
                Platform(1060,100, 80,  24,  0, 60, 0.07),
                Platform(1200,0,   32,  480, 2),
                Platform(1232,360, 110, 70,  0),
                Platform(1310,160, 70,  24,  0, 50, 0.08),
                Platform(1420,400, 160, 80,  0),
                Platform(1520,200, 60,  24,  0, 70, 0.05),
                Platform(1700,360, 200, 70,  0),
            ]
            self.items = [
                Item(300, 10, "nut"), Item(480, 280, "gem"), Item(570, 90, "star"),
                Item(840, 150, "nut"), Item(1080, 50, "gem"), Item(1320,120, "star"),
                Item(1460,310, "star"),
            ]
            self.enemies = [
                Enemy(480, 350, "patrol"), Enemy(960, 350, "chase"),
                Enemy(1300, 350, "chase"), Enemy(1520, 300, "jumper"),
            ]
            self.npcs = [NPC(300, 390, 8)]
 
        elif idx == 3:
            self.bg_col = (12, 6)
            self.goal_x = 2500
            self.plats = [
                Platform(0,   430, 120, 80,  0),
                Platform(120, 0,   32,  480, 1),
                Platform(152, 390, 320, 38,  0),
                Platform(210, 190, 70,  24,  0, 90, 0.035),
                Platform(370, 50,  70,  24,  0, 70, 0.06),
                Platform(512, 0,   32,  480, 2),
                Platform(544, 360, 220, 70,  0),
                Platform(650, 150, 70,  24,  0, 110, 0.045),
                Platform(810, 250, 50,  24,  0, 50, 0.08),
                Platform(910, 0,   32,  480, 1),
                Platform(942, 390, 180, 70,  0),
                Platform(1050,120, 60,  24,  0, 80, 0.065),
                Platform(1200,0,   32,  480, 2),
                Platform(1232,370, 150, 70,  0),
                Platform(1340,180, 80,  24,  0, 70, 0.07),
                Platform(1520,370, 200, 70,  0),
                Platform(1620,200, 60,  24,  0, 60, 0.09),
                Platform(1800,360, 200, 80,  0),
            ]
            self.items = [
                Item(230, 130, "star"), Item(400, 30, "gem"), Item(590, 280, "star"),
                Item(680, 120, "star"), Item(830, 200, "gem"), Item(1080, 80, "star"),
                Item(1370,140, "star"), Item(1640,160, "star"),
            ]
            self.enemies = [
                Enemy(590, 350, "chase"), Enemy(1000, 350, "chase"),
                Enemy(1330, 350, "chase"), Enemy(1640, 260, "flyer"),
            ]
            self.npcs = [NPC(250, 400, 11)]
 
        elif idx == 4:
            self.bg_col = (5, 2)
            self.goal_x = 2800
            self.plats = [
                Platform(0,   430, 110, 80,  0),
                Platform(110, 0,   28,  480, 2),
                Platform(138, 400, 140, 50,  0),
                Platform(200, 200, 56,  24,  0, 60, 0.06, True),
                Platform(340, 75,  56,  24,  0, 80, 0.07),
                Platform(460, 0,   28,  480, 1),
                Platform(488, 380, 200, 70,  0),
                Platform(580, 180, 56,  24,  0, 100, 0.06, True),
                Platform(740, 75,  56,  24,  0, 60, 0.09),
                Platform(840, 0,   28,  480, 2),
                Platform(868, 400, 160, 70,  0),
                Platform(960, 200, 56,  24,  0, 70, 0.07, True),
                Platform(1110,100, 56,  24,  0, 90, 0.08),
                Platform(1220,0,   28,  480, 1),
                Platform(1248,380, 180, 70,  0),
                Platform(1330,190, 56,  24,  0, 80, 0.09),
                Platform(1480,0,   28,  480, 2),
                Platform(1508,400, 140, 70,  0),
                Platform(1600,160, 56,  24,  0, 70, 0.10),
                Platform(1740,380, 200, 70,  0),
                Platform(1840,200, 56,  24,  0, 50, 0.11),
                Platform(1940,390, 160, 70,  0),
            ]
            self.items = [
                Item(220, 150, "star"), Item(510, 300, "gem"), Item(590, 130, "star"),
                Item(750, 50,  "star"), Item(980, 150, "gem"), Item(1120, 50, "star"),
                Item(1360,140, "gem"), Item(1620,120, "star"), Item(1860,150, "star"),
            ]
            self.enemies = [
                Enemy(520, 370, "patrol"), Enemy(900, 370, "chase"),
                Enemy(1280, 370, "chase"), Enemy(1560, 350, "jumper"),
                Enemy(1800, 270, "flyer"),
            ]
            self.npcs = [NPC(250, 400, 5)]
 
        else:  # idx == 5 (boss level)
            self.bg_col = (8, 2)
            self.goal_x = 3100
            self.plats = [
                Platform(0,   430, 100, 80,  0),
                Platform(100, 0,   28,  480, 1),
                Platform(128, 400, 120, 50,  3),
                Platform(160, 210, 48,  24,  0, 60, 0.08),
                Platform(290, 88,  48,  24,  0, 80, 0.10),
                Platform(420, 0,   28,  480, 2),
                Platform(448, 390, 130, 50,  3),
                Platform(480, 210, 48,  24,  0, 70, 0.09, True),
                Platform(630, 100, 48,  24,  0, 90, 0.11),
                Platform(760, 0,   28,  480, 1),
                Platform(788, 400, 130, 50,  3),
                Platform(825, 210, 48,  24,  0, 65, 0.10, True),
                Platform(980, 100, 48,  24,  0, 85, 0.12),
                Platform(1110,0,   28,  480, 2),
                Platform(1138,390, 160, 70,  0),
                Platform(1220,190, 48,  24,  0, 80, 0.10),
                Platform(1400,0,   28,  480, 1),
                Platform(1428,400, 120, 50,  3),
                Platform(1480,200, 48,  24,  0, 70, 0.12),
                Platform(1650,390, 160, 70,  0),
                Platform(1750,200, 48,  24,  0, 55, 0.14),
                Platform(1900,0,   28,  480, 2),
                Platform(1928,400, 120, 50,  3),
                Platform(1980,190, 48,  24,  0, 75, 0.11),
                Platform(2100,390, 160, 70,  0),
                Platform(2200,160, 48,  24,  0, 60, 0.14),
                Platform(2320,390, 180, 70,  0),
            ]
            self.items = [
                Item(180, 160, "star"), Item(310, 60, "gem"), Item(480, 300, "star"),
                Item(650, 70,  "star"), Item(930, 70,  "gem"), Item(1140,300, "star"),
                Item(1310,140, "star"), Item(1560,150, "gem"), Item(1790,150, "star"),
                Item(2020,110, "star"), Item(2240,130, "gem"),
                # Golden nut at the end
                Item(2900, 360, "golden_nut"),
            ]
            self.enemies = [
                Enemy(470, 370,  "chase"), Enemy(880, 370,  "chase"),
                Enemy(1240,370,  "chase"), Enemy(1500,330,  "jumper"),
                Enemy(1740,270,  "flyer"), Enemy(1980,370,  "chase"),
                Enemy(2180,270,  "flyer"),
                # BOSS
                Enemy(2700, 360, "boss"),
            ]
            self.npcs = [NPC(250, 400, 8)]
 
    # ─────────── UPDATE ───────────────────────────────────────
 
    def update(self):
        self.t += 1
        if self.state == "TITLE":
            self.title_t += 1
            for p in self.bg_particles: p.update()
            if pyxel.btnp(pyxel.KEY_SPACE) or pyxel.btnp(pyxel.KEY_RETURN):
                self.lvl_idx = 0
                self.hi_score = 0
                self._show_level_story()
        elif self.state == "INTRO":
            self._update_intro()
        elif self.state == "STORY":
            self._update_story()
        elif self.state == "PLAY":
            self._update_play()
        elif self.state in ("LOSE", "WIN", "GAMEOVER", "FINAL"):
            for p in self.bg_particles: p.update()
            self.fx_particles = [p for p in self.fx_particles if p.is_alive()]
            for p in self.fx_particles: p.update()
            if pyxel.btnp(pyxel.KEY_SPACE) or pyxel.btnp(pyxel.KEY_RETURN):
                if self.state == "FINAL":
                    self.state = "TITLE"
                elif self.state == "WIN" and self.lvl_idx >= 5:
                    self.state = "FINAL"
                elif self.state == "WIN":
                    self.lvl_idx += 1
                    self.hi_score = max(self.hi_score, self.score)
                    self._show_level_story()
                elif self.state == "GAMEOVER":
                    self.state = "TITLE"
                else:
                    self.init_lvl()
 
    def _show_level_story(self):
        self.state = "STORY"
        self.story_lines = LEVEL_STORY[min(self.lvl_idx, 5)]
        self.story_page = 0
        self.story_timer = 0
        self._spawn_bg_particles()
 
    def _update_intro(self):
        self.story_timer += 1
        for p in self.bg_particles: p.update()
        if pyxel.btnp(pyxel.KEY_SPACE) or pyxel.btnp(pyxel.KEY_RETURN) or self.story_timer > 180:
            self.story_page += 1
            self.story_timer = 0
            if self.story_page >= len(STORY_INTRO):
                self.state = "TITLE"
                self.story_page = 0
 
    def _update_story(self):
        self.story_timer += 1
        for p in self.bg_particles: p.update()
        if pyxel.btnp(pyxel.KEY_SPACE) or pyxel.btnp(pyxel.KEY_RETURN) or self.story_timer > 160:
            self.story_page += 1
            self.story_timer = 0
            if self.story_page >= len(self.story_lines):
                self.init_lvl()
 
    def _update_play(self):
        for p in self.bg_particles: p.update(self.wind)
        if self.lvl_idx == 1 and self.t % 40 == 0:
            self.bg_particles.append(Particle(
                x=random.randint(0, SCREEN_W), y=random.randint(0, 20),
                vx=random.uniform(-0.1, 0.1), vy=random.uniform(0.4, 0.9),
                col=random.choice([6, 7, 12]), life=random.randint(80, 200), kind="ice_drip"))
        self.bg_particles = [p for p in self.bg_particles if p.is_alive() or p.life == 9999]
        if self.lvl_idx == 3:
            self.rainbow_phase = (self.rainbow_phase + 1) % 360
        if self.lvl_idx == 4:
            self.lightning_timer -= 1
            if self.lightning_active > 0: self.lightning_active -= 1
            if self.lightning_timer <= 0:
                self.lightning_timer = random.randint(80, 220)
                self.lightning_x = random.randint(40, SCREEN_W - 40)
                self.lightning_active = 6
                lx = self.lightning_x; ly = 28
                self.lightning_segs = []
                for _ in range(9):
                    nx = lx + random.randint(-16, 16)
                    ny = ly + random.randint(20, 40)
                    self.lightning_segs.append((lx, ly, nx, ny))
                    lx = nx; ly = ny
        nfx = [p for p in self.fx_particles if p.is_alive()]
        for p in nfx: p.update()
        self.fx_particles = nfx
        for pl in self.plats: pl.update(self.t)
        if self.t % 180 == 0:
            self.wind = random.uniform(-0.9, 1.2) if random.random() > 0.6 else 0
 
        for e in self.enemies:
            if e.alive:
                e.update(self.px, self.py)
                if e.kind == "boss":
                    for fb in e.fireballs:
                        if abs(self.px+6-fb["x"]) < 12 and abs(self.py+6-fb["y"]) < 12:
                            self._hurt()
                    if e.stomp_timer > 0:
                        e.stomp_timer -= 1
                        if e.stomp_timer == 7: self._screen_shake(6)
                    if (abs(self.px+6-e.x) < 20 and
                            self.py+12 >= e.y-24 and self.py+12 <= e.y-10 and self.vy > 0):
                        e.hp -= 1
                        self.vy = -5.5
                        pyxel.play(0, 7)
                        self._burst(e.x-self.cam_x, e.y-14, "hurt")
                        if e.hp <= 0:
                            e.alive = False
                            pyxel.play(0, 8)
                            self._burst(e.x-self.cam_x, e.y-14, "star")
                            self._burst(e.x-self.cam_x+14, e.y-8, "gem")
                    elif abs(self.px+6-e.x) < 18 and abs(self.py+6-(e.y-12)) < 15:
                        self._hurt()
                else:
                    if abs(self.px-e.x) < 14 and abs(self.py-e.y) < 14:
                        self._hurt()
 
        if not self.dialog_active:
            for npc in self.npcs:
                if abs(self.px-npc.x) < 30 and abs(self.py-npc.y) < 30 and not npc.talking:
                    npc.talking = True
                    self.dialog_active = True
                    self.dialog_text = NPC_DIALOGUE[min(self.lvl_idx, 5)]
                    self.dialog_timer = 280
        if self.dialog_active:
            self.dialog_timer -= 1
            if self.dialog_timer <= 0 or pyxel.btnp(pyxel.KEY_E):
                self.dialog_active = False
 
        for it in self.items:
            if it.alive:
                it.update()
                if abs(self.px+6-it.x) < 14 and abs(self.py+6-it.screen_y()) < 14:
                    it.alive = False
                    if it.kind == "golden_nut": pts = 3000; pyxel.play(0, 5)
                    elif it.kind == "nut":      pts = 100;  pyxel.play(1, 1)
                    elif it.kind == "gem":      pts = 250;  pyxel.play(1, 2)
                    else:                       pts = 500;  pyxel.play(1, 3)
                    self.score += pts
                    self._burst(it.x-self.cam_x, it.screen_y(), it.kind)
 
        for pl in self.plats:
            if pl.p_type == 3:
                if (self.px+12 > pl.x and self.px < pl.x+pl.w and
                        self.py+12 >= pl.y and self.py+12 <= pl.y+14):
                    self._hurt()
 
        self._update_player()
        if abs(self.vx) > 0.3:
            if self.t % 6 == 0: self.anim_frame = (self.anim_frame + 1) % 4
        else:
            self.anim_frame = 0
        if self.shake > 0: self.shake -= 1
 
    def _screen_shake(self, intensity):
        self.shake = max(getattr(self, 'shake', 0), intensity)
 
    def _hurt(self):
        if self.hurt_timer > 0: return
        self.lives -= 1; self.hurt_timer = 60
        pyxel.play(2, 4)
        self._burst(self.px-self.cam_x+6, self.py+6, "hurt")
        if self.lives <= 0: self.state = "GAMEOVER"
 
    def _burst(self, x, y, kind="nut"):
        cols = {"nut":[9,10,4],"gem":[12,7,6],"star":[10,9,7],"hurt":[8,2,3],"golden_nut":[10,9,7,6,12]}
        c_list = cols.get(kind, [7, 13, 6])
        for _ in range(22):
            a = random.uniform(0, math.pi*2); sp = random.uniform(0.6, 3.5)
            self.fx_particles.append(Particle(
                x=x, y=y, vx=math.cos(a)*sp, vy=math.sin(a)*sp-1,
                col=random.choice(c_list), life=random.randint(22, 45), kind="spark"))
 
    def _update_player(self):
        if self.hurt_timer > 0: self.hurt_timer -= 1
        if self.dash_cd > 0: self.dash_cd -= 1
        if self.dash_timer > 0: self.dash_timer -= 1; return
        if self.lock_timer > 0: self.lock_timer -= 1
        else:
            if pyxel.btn(pyxel.KEY_A) or pyxel.btn(pyxel.KEY_LEFT): self.vx = -WALK_SPEED; self.facing = -1
            elif pyxel.btn(pyxel.KEY_D) or pyxel.btn(pyxel.KEY_RIGHT): self.vx = WALK_SPEED; self.facing = 1
            else: self.vx *= 0.75
 
        dash_pressed = False
        try:
            if pyxel.btnp(pyxel.KEY_LSHIFT): dash_pressed = True
        except Exception: pass
        if pyxel.btnp(pyxel.KEY_Z): dash_pressed = True
        if dash_pressed and self.dash_cd == 0:
            self.vx = self.facing * 8; self.vy = 0
            self.dash_timer = 8; self.dash_cd = 40
            pyxel.play(0, 6)
            self._burst(self.px-self.cam_x+6, self.py+6, "gem"); return
 
        self.vx += self.wind * 0.04
        on_ground = self._check_floor()
        at_ceiling = self._check_ceiling()
        wall = self._get_wall()
 
        if on_ground: self.coyote = COYOTE_TIME
        else: self.coyote = max(0, self.coyote - 1)
 
        jump_pressed = (pyxel.btnp(pyxel.KEY_SPACE) or pyxel.btnp(pyxel.KEY_W) or pyxel.btnp(pyxel.KEY_UP))
        if jump_pressed: self.jump_buffer = JUMP_BUFFER
        else: self.jump_buffer = max(0, self.jump_buffer - 1)
 
        self.on_wall = False; self.on_ceil = False
        climb_held = pyxel.btn(pyxel.KEY_W) or pyxel.btn(pyxel.KEY_UP)
 
        if wall and not on_ground:
            self.on_wall = True
            if climb_held and self.stamina > 0: self.vy = -1.5 if wall.p_type == 1 else -0.6; self.stamina -= 0.8
            else: self.vy = min(self.vy + 0.1, 1.2)
            if self.jump_buffer > 0:
                pyxel.play(0, 0); self.vy = WALL_JUMP_Y; self.vx = -self.facing * WALL_JUMP_X
                self.lock_timer = 12; self.stamina -= 5; self.facing *= -1; self.jump_buffer = 0; self._dust_puff()
        elif at_ceiling and climb_held and self.stamina > 0:
            self.on_ceil = True; self.vy = 0; self.stamina -= 0.6
            if self.jump_buffer > 0: self.vy = 2.0; self.jump_buffer = 0
        else:
            self.vy += GRAVITY
            if on_ground:
                self.stamina = min(STAMINA_MAX, self.stamina + 1.5)
                if self.jump_buffer > 0:
                    pyxel.play(0, 0); self.vy = JUMP_PWR; self.jump_buffer = 0; self._dust_puff()
            elif self.coyote > 0 and self.jump_buffer > 0:
                pyxel.play(0, 0); self.vy = JUMP_PWR; self.coyote = 0; self.jump_buffer = 0; self._dust_puff()
 
        self.px += self.vx; self.py += self.vy
        target_cam = self.px - SCREEN_W * 0.35
        self.cam_x += (target_cam - self.cam_x) * 0.12
        if self.cam_x < 0: self.cam_x = 0
 
        if self.py > SCREEN_H + 60: self._hurt(); self.py = 380; self.vy = 0
        if self.px > self.goal_x:
            self.score += self.lives * 500
            pyxel.play(1, 5)
            self.state = "WIN"
 
    def _dust_puff(self):
        for _ in range(9):
            a = random.uniform(math.pi, math.pi*2); sp = random.uniform(0.4, 2.0)
            self.fx_particles.append(Particle(
                x=self.px-self.cam_x+6, y=self.py+12,
                vx=math.cos(a)*sp, vy=math.sin(a)*sp, col=7, life=25, kind="spark"))
 
    def _check_floor(self):
        for p in self.plats:
            if p.p_type in (0, 3, 4):
                if self.px+12 > p.x and self.px+2 < p.x+p.w:
                    if self.py+12 >= p.y and self.py+12 <= p.y+10 and self.vy >= 0:
                        self.py = p.y - 12; self.vy = 0; return True
        return False
 
    def _check_ceiling(self):
        for p in self.plats:
            if p.p_type in (0, 4):
                if self.px+12 > p.x and self.px+2 < p.x+p.w:
                    if self.py <= p.y+p.h and self.py >= p.y+p.h-8 and self.vy <= 0:
                        self.py = p.y+p.h; self.vy = 0; return True
        return False
 
    def _get_wall(self):
        test_x = self.px+12 if self.facing == 1 else self.px
        for p in self.plats:
            if p.p_type in (1, 2):
                if test_x > p.x and test_x < p.x+p.w:
                    if self.py+10 > p.y and self.py < p.y+p.h:
                        return p
        return None
 
    # ═══════════════════════════════════════════════════════════
    #  DRAWING
    # ═══════════════════════════════════════════════════════════
 
    def draw(self):
        sox = random.randint(-2, 2) if self.shake > 0 else 0
        soy = random.randint(-1, 1) if self.shake > 0 else 0
        if sox or soy: pyxel.cls(0)
 
        if   self.state == "TITLE":   self._draw_title()
        elif self.state == "INTRO":   self._draw_intro()
        elif self.state == "STORY":   self._draw_story()
        elif self.state == "PLAY":    self._draw_play(sox, soy)
        elif self.state == "WIN":
            self._draw_play(0, 0)
            won_all = self.lvl_idx >= 5
            self._draw_overlay("NUSS GEFUNDEN!", "Weiter: SPACE" if not won_all else "ENDE! SPACE", 10)
        elif self.state == "GAMEOVER":
            self._draw_play(0, 0)
            self._draw_overlay("SPIEL VORBEI", "Neu: SPACE", 8)
        elif self.state == "LOSE":
            self._draw_play(0, 0)
            self._draw_overlay("ABGESTUERZT!", "Nochmal: SPACE", 8)
        elif self.state == "FINAL":
            self._draw_final_screen()
 
    # ─── TITLE ────────────────────────────────────────────────
 
    def _draw_title(self):
        for row in range(SCREEN_H):
            if row < 140:  c = 1
            elif row < 250: c = 5
            elif row < 340: c = 2
            else:           c = 3
            pyxel.line(0, row, SCREEN_W, row, c)
        for i in range(35):
            sx = (i*71+7) % SCREEN_W; sy = (i*37+5) % 140
            if (self.title_t//18+i) % 3 != 0: pyxel.pset(sx, sy, 7)
        for col, h, factor in [(2, 70, 0.03), (5, 110, 0.08), (3, 80, 0.15)]:
            offset = int(self.title_t * factor * 0.4)
            for i in range(6):
                mx = (i*220 - offset) % (SCREEN_W+220) - 40
                pyxel.tri(mx, SCREEN_H, mx+110, SCREEN_H-h, mx+220, SCREEN_H, col)
        for p in self.bg_particles: pyxel.pset(int(p.x), int(p.y), p.col)
        lx = SCREEN_W//2 - 130; ly = 60
        pyxel.rect(lx-8, ly-8, 276, 58, 0)
        pyxel.rectb(lx-8, ly-8, 276, 58, 9)
        pyxel.rectb(lx-6, ly-6, 272, 54, 5)
        pyxel.text(lx+10, ly+16, "NUSS-MISSION DELUXE", 0)
        pyxel.text(lx+9,  ly+15, "NUSS-MISSION DELUXE", 2)
        pyxel.text(lx+8,  ly+14, "NUSS-MISSION DELUXE", 10)
        pyxel.text(lx+8,  ly+12, "NUSS-MISSION", 9)
        pyxel.text(lx+104, ly+12, "v5", 7)
        sq_x = SCREEN_W//2 - 6 + int(math.sin(self.title_t*0.05)*44)
        self._draw_squirrel_at(sq_x, 160, 1, int(self.title_t*0.3)%4)
        if (self.title_t//22) % 2 == 0:
            pyxel.rect(SCREEN_W//2-78, 218, 156, 14, 0)
            pyxel.text(SCREEN_W//2-72, 221, "SPACE zum Starten", 7)
        pyxel.rect(SCREEN_W//2-52, 240, 104, 14, 5)
        pyxel.rectb(SCREEN_W//2-52, 240, 104, 14, 9)
        pyxel.text(SCREEN_W//2-42, 244, "6 WELTEN + BOSS!", 10)
        pyxel.rect(0, SCREEN_H-30, SCREEN_W, 30, 0)
        pyxel.line(0, SCREEN_H-30, SCREEN_W, SCREEN_H-30, 5)
        pyxel.text(6, SCREEN_H-24, "A/D bewegen  W klettern  SPACE springen  Z Dash  E Dialog", 13)
        if self.hi_score > 0:
            pyxel.text(6, 6, "BESTPUNKTZAHL: " + str(self.hi_score), 9)
 
    def _draw_intro(self):
        pyxel.cls(0)
        for i in range(40):
            sx=(i*55+5)%SCREEN_W; sy=(i*29+3)%160
            c = 7 if (self.t//15+i)%4 != 0 else 13
            pyxel.pset(sx, sy, c)
        pyxel.circ(400, 70, 24, 13); pyxel.circ(400, 70, 20, 7); pyxel.circ(390, 58, 8, 13)
        sx = SCREEN_W//2 - 12; sy = 280
        self._draw_squirrel_at(sx, sy, 1, int(self.t*0.2)%4)
        prog = min(1.0, self.story_timer/60)
        page = min(self.story_page, len(STORY_INTRO)-1)
        txt = STORY_INTRO[page]
        tw = len(txt)*4; tx = SCREEN_W//2 - tw//2
        pyxel.rect(tx-6, 370, tw+12, 16, 0)
        pyxel.text(tx, 374, txt, 7)
        if (self.t//20)%2 == 0:
            pyxel.text(SCREEN_W//2-40, 420, "SPACE weiter", 13)
 
    def _draw_story(self):
        pyxel.cls(0)
        bg = [1, 5, 2, 12, 5, 8][min(self.lvl_idx, 5)]
        for row in range(SCREEN_H//2, SCREEN_H):
            pyxel.line(0, row, SCREEN_W, row, bg)
        self._draw_story_char(self.lvl_idx)
        ox = 20; oy = 340
        pyxel.rect(ox, oy, SCREEN_W-40, 140, 0)
        pyxel.rectb(ox, oy, SCREEN_W-40, 140, 9)
        pyxel.rectb(ox-1, oy-1, SCREEN_W-38, 142, 10)
        page = min(self.story_page, len(self.story_lines)-1)
        txt = self.story_lines[page]
        prog = min(1.0, self.story_timer/40)
        chars = max(1, int(len(txt)*prog))
        pyxel.text(ox+8, oy+10, txt[:chars], 7)
        pyxel.text(ox+8, oy+110, f"{self.story_page+1}/{len(self.story_lines)}", 13)
        if (self.t//18)%2 == 0: pyxel.text(SCREEN_W-80, oy+118, "SPACE >>", 10)
 
    def _draw_story_char(self, idx):
        chars = [
            lambda: self._draw_npc_elder(SCREEN_W//2, 180),
            lambda: self._draw_npc_fairy(SCREEN_W//2, 180),
            lambda: self._draw_npc_guard(SCREEN_W//2, 180),
            lambda: self._draw_npc_wind(SCREEN_W//2, 180),
            lambda: self._draw_npc_shadow(SCREEN_W//2, 180),
            lambda: self._draw_boss_portrait(SCREEN_W//2, 170),
        ]
        chars[min(idx, 5)]()
 
    def _draw_npc_elder(self, x, y):
        pyxel.rect(x-8, y-22, 16, 22, 4)
        pyxel.circ(x, y-28, 11, 9)
        pyxel.pset(x-4, y-29, 0); pyxel.pset(x+4, y-29, 0)
        pyxel.rect(x-6, y-20, 12, 6, 7)
        pyxel.pset(x-8, y-34, 10); pyxel.pset(x-10, y-32, 10)
        pyxel.pset(x+8, y-34, 10); pyxel.pset(x+10, y-32, 10)
        pyxel.line(x+10, y, x+10, y-44, 4); pyxel.circ(x+10, y-44, 3, 9)
        for i in range(5): pyxel.pset(x-8-i, y-16+i, 9)
        pyxel.text(x-28, y+10, "Opa Eichhorn", 13)
 
    def _draw_npc_fairy(self, x, y):
        wing = int(math.sin(self.t*0.15)*6)
        pyxel.tri(x-18, y-16, x-3, y-24+wing, x-3, y-12, 6)
        pyxel.tri(x+18, y-16, x+3, y-24+wing, x+3, y-12, 6)
        pyxel.tri(x-15, y-12, x-3, y-8+wing, x-3, y-3, 12)
        pyxel.tri(x+15, y-12, x+3, y-8+wing, x+3, y-3, 12)
        pyxel.rect(x-4, y-18, 8, 18, 12)
        pyxel.circ(x, y-24, 7, 6)
        pyxel.pset(x-3, y-25, 0); pyxel.pset(x+3, y-25, 0)
        pyxel.line(x+7, y, x+14, y-28, 7); pyxel.circ(x+14, y-28, 4, 10)
        pyxel.text(x-24, y+10, "Glitzer-Fee", 12)
 
    def _draw_npc_guard(self, x, y):
        pyxel.rect(x-8, y-22, 16, 22, 8)
        pyxel.rect(x-10, y-22, 20, 5, 2)
        pyxel.rect(x-7, y-34, 14, 14, 2)
        pyxel.rect(x-6, y-32, 12, 10, 8)
        pyxel.pset(x-3, y-25, 0); pyxel.pset(x+3, y-25, 0)
        pyxel.rect(x-3, y-20, 6, 2, 9)
        pyxel.line(x+12, y-22, x+12, y+3, 8); pyxel.circ(x+12, y-22, 3, 9)
        pyxel.text(x-30, y+10, "Feuerwaechter", 9)
 
    def _draw_npc_wind(self, x, y):
        bob = int(math.sin(self.t*0.1)*5)
        for i in range(5):
            wx = x + int(math.cos(self.t*0.07+i*1.26)*18)
            wy = y - 16 + int(math.sin(self.t*0.07+i*1.26)*9) + bob
            pyxel.pset(wx, wy, 3 if i%2==0 else 11)
            pyxel.pset(wx+1, wy, 11)
        pyxel.circ(x, y-22+bob, 9, 11)
        pyxel.pset(x-3, y-23+bob, 0); pyxel.pset(x+3, y-23+bob, 0)
        pyxel.pset(x, y-21+bob, 3)
        pyxel.rect(x-4, y-12+bob, 8, 12, 3)
        pyxel.text(x-20, y+10+bob, "Zephira", 3)
 
    def _draw_npc_shadow(self, x, y):
        cape_w = int(math.sin(self.t*0.08)*5)
        pyxel.tri(x-14, y-6, x+14, y-6, x-10+cape_w, y+14, 5)
        pyxel.tri(x-14, y-6, x+14, y-6, x+10-cape_w, y+14, 1)
        pyxel.rect(x-6, y-22, 12, 18, 5)
        pyxel.circ(x, y-28, 8, 1)
        ec = (self.t//8)%2
        pyxel.pset(x-3, y-29, 6 if ec else 13); pyxel.pset(x+3, y-29, 6 if ec else 13)
        pyxel.text(x-28, y+10, "Schattenbote", 5)
 
    def _draw_boss_portrait(self, x, y):
        pyxel.rect(x-20, y-14, 40, 28, 8)
        pyxel.rect(x-22, y-14, 44, 8, 2)
        pyxel.rect(x-16, y-36, 32, 24, 2)
        pyxel.rect(x-14, y-34, 28, 20, 8)
        ec = 9 if (self.t//6)%2==0 else 10
        pyxel.circ(x-7, y-27, 5, ec); pyxel.circ(x+7, y-27, 5, ec)
        pyxel.pset(x-7, y-27, 0); pyxel.pset(x+7, y-27, 0)
        pyxel.tri(x-16, y-36, x-10, y-36, x-16, y-50, 9)
        pyxel.tri(x+10, y-36, x+16, y-36, x+16, y-50, 9)
        pyxel.rect(x-10, y-20, 20, 5, 0)
        for i in range(-8, 9, 5): pyxel.rect(x+i, y-20, 3, 4, 7)
        wing = int(math.sin(self.t*0.1)*7)
        pyxel.tri(x-20, y-10, x-44, y-28+wing, x-20, y+4, 2)
        pyxel.tri(x+20, y-10, x+44, y-28+wing, x+20, y+4, 2)
        if (self.t//10)%2 == 0: pyxel.text(x-38, y+22, "INFERNO-REX!", 9)
        else:                    pyxel.text(x-38, y+22, "INFERNO-REX!", 10)
        pyxel.text(x-30, y+34, "Endgegner!", 8)
 
    # ─── PLAY DRAW ────────────────────────────────────────────
 
    def _draw_play(self, ox=0, oy=0):
        idx = self.lvl_idx
        if   idx == 0: self._draw_biome_forest()
        elif idx == 1: self._draw_biome_ice()
        elif idx == 2: self._draw_biome_lava()
        elif idx == 3: self._draw_biome_cloud()
        elif idx == 4: self._draw_biome_ghost()
        else:          self._draw_biome_inferno()
 
        for p in self.bg_particles:
            px2 = int(p.x)+ox; py2 = int(p.y)+oy
            if p.kind == "ice_drip":
                if 0 <= py2 < SCREEN_H:
                    pyxel.pset(px2, py2, p.col)
                    if py2 > 1: pyxel.pset(px2, py2-1, 1 if p.col==12 else 6)
            elif p.kind == "cloud_wisp":
                pyxel.pset(px2, py2, p.col); pyxel.pset(px2+1, py2, 13 if p.col==7 else p.col)
            elif p.kind == "rain":
                pyxel.line(px2, py2, px2-1, py2-5, p.col)
            elif p.kind == "firefly":
                phase = (self.t + int(p.x*7+p.y*3)) % 40
                if phase < 20:
                    pyxel.pset(px2, py2, p.col)
                    if phase < 8: pyxel.pset(px2+1, py2, 7); pyxel.pset(px2-1, py2, 7)
            elif p.kind == "ghost_wisp":
                alpha = (self.t + int(p.x*3)) % 30
                if alpha < 20:
                    pyxel.pset(px2, py2, p.col)
                    if alpha < 10: pyxel.pset(px2+1, py2, 13)
            else:
                pyxel.pset(px2, py2, p.col)
 
        for pl in self.plats: self._draw_platform(pl)
        self._draw_goal()
        self._draw_items()
        self._draw_enemies()
        self._draw_npcs()
 
        for p in self.fx_particles:
            alpha = p.life/p.max_life if p.max_life > 0 else 0
            if alpha > 0.5:   pyxel.pset(int(p.x)+ox, int(p.y)+oy, p.col)
            elif alpha > 0.2: pyxel.pset(int(p.x)+ox, int(p.y)+oy, 13)
 
        inv = self.hurt_timer > 0 and (self.t//4)%2 == 0
        if not inv:
            self._draw_squirrel_at(int(self.px-self.cam_x)+ox, int(self.py)+oy,
                                   self.facing, self.anim_frame, self.on_wall, self.on_ceil)
        self._draw_hud()
        if self.dialog_active: self._draw_dialog(self.dialog_text)
        for e in self.enemies:
            if e.kind == "boss" and e.alive: self._draw_boss_hud(e)
 
    # ─── BIOMES ───────────────────────────────────────────────
 
    def _draw_biome_forest(self):
        for row in range(SCREEN_H):
            if row < 28:    c = 0
            elif row < 80:  c = 2
            elif row < 160: c = 9
            elif row < 250: c = 10
            elif row < 340: c = 4
            elif row < 420: c = 3
            else:           c = 11
            pyxel.line(0, row, SCREEN_W, row, c)
        off_ray = int(self.cam_x * 0.02)
        for i in range(7):
            rx = (i*100+20-off_ray) % (SCREEN_W+100) - 20
            for j in range(0, 160, 4):
                bx = rx+j//2; by = 28+j
                if 0 <= bx < SCREEN_W:
                    pyxel.pset(bx, by, 9 if j%8==0 else 10)
        off1 = int(self.cam_x * 0.07)
        for i in range(8):
            tx = (i*160-off1) % (SCREEN_W+160) - 20
            th = 56+(i*25)%40; tw = 18+(i*8)%12
            pyxel.rect(tx+tw//2-2, SCREEN_H-40, 5, 40, 4)
            for layer in range(3):
                ly2 = SCREEN_H-th+layer*16
                c_tree = [3,9,10,4][i%4]
                pyxel.tri(tx+tw//2, ly2-20, tx-4, ly2+12, tx+tw+4, ly2+12, c_tree)
                pyxel.line(tx+tw//2, ly2-20, tx-4, ly2+12, 0)
        off2 = int(self.cam_x * 0.14)
        for i in range(6):
            tx = (i*200+70-off2) % (SCREEN_W+200) - 30
            th = 80+(i*30)%55; tw = 30+(i*10)%20
            pyxel.rect(tx+tw//2-3, SCREEN_H-55, 7, 55, 4)
            pyxel.rect(tx+tw//2-2, SCREEN_H-55, 2, 55, 3)
            for layer in range(4):
                ly2 = SCREEN_H-th+layer*18
                c_tree = [3,9,10,4][i%4]
                pyxel.tri(tx+tw//2, ly2-26, tx-4, ly2+16, tx+tw+4, ly2+16, c_tree)
                pyxel.line(tx+tw//2, ly2-26, tx-4, ly2+16, 0)
        floor_y = 420
        pyxel.rect(0, floor_y, SCREEN_W, SCREEN_H-floor_y, 11)
        pyxel.rect(0, floor_y, SCREEN_W, 5, 3)
        off_grass = int(self.cam_x * 0.40)
        for i in range(50):
            gx = (i*28+5-off_grass) % SCREEN_W
            gh = 5+(i*5)%7
            pyxel.line(gx, floor_y, gx+1, floor_y-gh, 3 if i%3!=0 else 11)
 
    def _draw_biome_ice(self):
        for row in range(SCREEN_H):
            if row < 28:    c = 0
            elif row < 70:  c = 1
            elif row < 150: c = 5
            elif row < 260: c = 1
            elif row < 380: c = 5
            elif row < 430: c = 6
            else:           c = 12
            pyxel.line(0, row, SCREEN_W, row, c)
        for strip in self.aurora_strips:
            sx = int((strip["x"] - self.cam_x*0.02) % SCREEN_W)
            sy = strip["y"] + int(math.sin(self.t*0.03+strip["phase"])*6)
            alpha = (math.sin(self.t*0.04+strip["phase"])+1)*0.5
            if alpha > 0.3: pyxel.rect(sx, sy, strip["w"], 3, strip["col"])
        off_stl = int(self.cam_x * 0.20)
        for i in range(14):
            sx = (i*140-off_stl) % (SCREEN_W+140) - 16
            sh = 36+(i*38)%70; sw = 10+(i*13)%18; sy0 = 28
            pyxel.tri(sx, sy0, sx+sw, sy0, sx+sw//2, sy0+sh, 1)
            pyxel.line(sx, sy0, sx+sw//2, sy0+sh, 6)
            pyxel.line(sx+sw, sy0, sx+sw//2, sy0+sh, 5)
            pyxel.pset(sx+sw//2, sy0+sh, 7)
            drip_phase = (self.t+i*22) % 90
            if drip_phase < 45:
                dy = sy0+sh+drip_phase//4
                if dy < SCREEN_H: pyxel.pset(sx+sw//2, dy, 12)
        floor_y = 432
        pyxel.rect(0, floor_y, SCREEN_W, 6, 6)
        pyxel.rect(0, floor_y+1, SCREEN_W, 2, 12)
 
    def _draw_biome_lava(self):
        for row in range(SCREEN_H):
            if row < 28:    c = 0
            elif row < 100: c = 0
            elif row < 200: c = 2
            elif row < 310: c = 8
            elif row < 400: c = 9
            else:           c = 2
            pyxel.line(0, row, SCREEN_W, row, c)
        off2 = int(self.cam_x * 0.10)
        for i in range(9):
            lx = (i*160-off2) % (SCREEN_W+160) - 20
            lava_y = 400 + int(math.sin((self.t*0.04)+i*1.1)*6)
            pyxel.rect(lx, lava_y, 120, SCREEN_H-lava_y, 2)
            pyxel.rect(lx, lava_y, 120, 5, 9)
            pyxel.rect(lx, lava_y+2, 120, 2, 10)
        off3 = int(self.cam_x * 0.22)
        for i in range(7):
            cx = (i*200+50-off3) % (SCREEN_W+200) - 20
            ch = 110+(i*25)%60
            flame_h = 10+int(math.sin(self.t*0.1+i)*5)
            pyxel.rect(cx, SCREEN_H-ch, 20, ch, 2)
            pyxel.tri(cx+4, SCREEN_H-ch, cx+10, SCREEN_H-ch-flame_h, cx+16, SCREEN_H-ch, 9)
            pyxel.tri(cx+6, SCREEN_H-ch, cx+10, SCREEN_H-ch-flame_h+4, cx+14, SCREEN_H-ch, 10)
        for bx, phase in self.lava_bubbles:
            bub_y = 405 + int(math.sin(self.t*0.05+phase)*6)
            bub_x = int((bx - self.cam_x*0.15) % SCREEN_W)
            pyxel.circ(bub_x, bub_y, 3, 10)
            pyxel.pset(bub_x, bub_y-1, 7)
        lava_base = 435
        for row in range(lava_base, SCREEN_H):
            c = 9 if (row+self.t//4)%6 < 3 else 8
            pyxel.line(0, row, SCREEN_W, row, c)
        pyxel.rect(0, lava_base, SCREEN_W, 3, 10)
 
    def _draw_biome_cloud(self):
        for row in range(SCREEN_H):
            if row < 28:    c = 1
            elif row < 100: c = 6
            elif row < 200: c = 12
            elif row < 300: c = 13
            elif row < 390: c = 7
            else:           c = 6
            pyxel.line(0, row, SCREEN_W, row, c)
        sun_x = 420 + int(math.sin(self.t*0.005)*16)
        sun_y = 70
        pyxel.circ(sun_x, sun_y, 18, 10); pyxel.circ(sun_x, sun_y, 14, 9); pyxel.circ(sun_x, sun_y, 9, 7)
        for a in range(0, 360, 45):
            rad = math.radians(a)
            pyxel.pset(sun_x+int(math.cos(rad)*22), sun_y+int(math.sin(rad)*22), 10)
        rb_cx = 200; rb_cy = 300
        rb_cols = [8, 9, 10, 11, 12, 6, 1]
        for ri, rc in enumerate(rb_cols):
            rad_r = 100+ri*6
            for a in range(200, 340):
                rx2 = rb_cx + int(math.cos(math.radians(a))*rad_r)
                ry2 = rb_cy + int(math.sin(math.radians(a))*rad_r)
                if 0 <= rx2 < SCREEN_W and 0 <= ry2 < SCREEN_H: pyxel.pset(rx2, ry2, rc)
        off2 = int(self.cam_x * 0.08)
        for i in range(7):
            cx = (i*200-off2) % (SCREEN_W+200) - 40
            cy = 60+(i*33)%110; cw = 100+(i*37)%80
            pyxel.rect(cx, cy, cw, 20, 7)
            pyxel.circ(cx+16, cy-8, 16, 7); pyxel.circ(cx+cw-16, cy-8, 14, 7)
            pyxel.circ(cx+cw//2, cy-14, 22, 7)
            pyxel.rect(cx+5, cy+16, cw-10, 5, 13)
        off_bird = int(self.cam_x * 0.25)
        for i in range(8):
            bx = (i*300+60-off_bird) % (SCREEN_W+300)
            by = 40+(i*21)%80+int(math.sin(self.t*0.04+i)*5)
            wing = int(math.sin(self.t*0.1+i*0.7)*5)
            pyxel.line(bx-6, by-wing, bx, by, 1); pyxel.line(bx, by, bx+6, by-wing, 1)
 
    def _draw_biome_ghost(self):
        for row in range(SCREEN_H):
            if row < 28:    c = 0
            elif row < 90:  c = 1
            elif row < 180: c = 5
            elif row < 270: c = 2
            elif row < 380: c = 1
            else:           c = 0
            pyxel.line(0, row, SCREEN_W, row, c)
        moon_x = 360+int(math.sin(self.t*0.003)*28)
        moon_y = 65
        pyxel.circ(moon_x, moon_y, 22, 7); pyxel.circ(moon_x, moon_y, 18, 13)
        pyxel.circ(moon_x+5, moon_y-5, 7, 7)
        for r in range(28, 38, 3): pyxel.circb(moon_x, moon_y, r, 1)
        if self.lightning_active > 0:
            flash_col = 7 if self.lightning_active > 3 else 13
            for seg in self.lightning_segs:
                lx1, ly1, lx2, ly2 = seg
                pyxel.line(int(lx1), ly1, int(lx2), ly2, flash_col)
                pyxel.line(int(lx1)+1, ly1, int(lx2)+1, ly2, 6)
        off1 = int(self.cam_x * 0.05)
        for i in range(6):
            tx = (i*220-off1) % (SCREEN_W+220) - 30
            th = 130+(i*40)%100; tw = 28+(i*14)%20
            pyxel.rect(tx, SCREEN_H-th, tw, th, 1)
            for brick_y in range(SCREEN_H-th+8, SCREEN_H, 16):
                pyxel.line(tx, brick_y, tx+tw, brick_y, 5)
            pyxel.tri(tx-4, SCREEN_H-th, tx+tw//2, SCREEN_H-th-44, tx+tw+4, SCREEN_H-th, 0)
            win_col = 9 if (self.t//25+i)%5 != 0 else 0
            pyxel.rect(tx+4, SCREEN_H-th+24, 6, 8, win_col)
            pyxel.rect(tx+tw-10, SCREEN_H-th+24, 6, 8, win_col)
        off_fog = int(self.cam_x * 0.08)
        for i in range(12):
            fx = (i*60+10-off_fog) % (SCREEN_W+60) - 20
            fy = SCREEN_H-40+int(math.sin(self.t*0.03+i*0.7)*5)
            pyxel.rect(fx, fy, 40+i*7%28, 12+i%6, 5 if i%2==0 else 1)
 
    def _draw_biome_inferno(self):
        for row in range(SCREEN_H):
            if row < 70:    c = 0
            elif row < 130: c = 2
            elif row < 220: c = 8
            elif row < 310: c = 9
            else:           c = 10
            pyxel.line(0, row, SCREEN_W, row, c)
        off_smoke = int(self.cam_x * 0.03)
        for i in range(8):
            sx = (i*150+40-off_smoke) % (SCREEN_W+150) - 20
            sy = 28+(i*13)%50; c = 0 if i%2==0 else 2
            pyxel.rect(sx, sy, 40+i*11%40, 16, c)
            pyxel.circ(sx+10, sy-4, 10, c)
        off1 = int(self.cam_x * 0.05)
        for i in range(6):
            rx = (i*260-off1) % (SCREEN_W+260) - 40
            rh = 130+(i*33)%100
            pyxel.tri(rx, SCREEN_H, rx+150, SCREEN_H-rh, rx+300, SCREEN_H, 2)
            pyxel.circ(rx+150, SCREEN_H-rh, 12, 0)
            pyxel.circ(rx+150, SCREEN_H-rh, 8, 8)
            pyxel.pset(rx+150, SCREEN_H-rh, 10)
        off3 = int(self.cam_x * 0.22)
        for i in range(6):
            gx = (i*240+100-off3) % (SCREEN_W+240) - 20
            geyser_h = 44+int(math.sin(self.t*0.07+i*1.4)*36)
            gy = SCREEN_H - geyser_h
            pyxel.tri(gx, SCREEN_H, gx+16, gy, gx+32, SCREEN_H, 9)
            pyxel.tri(gx+6, SCREEN_H, gx+16, gy+10, gx+26, SCREEN_H, 10)
            pyxel.pset(gx+16, gy, 7)
        for row in range(440, SCREEN_H):
            c = 9 if (row+self.t//3)%5 < 2 else 8
            pyxel.line(0, row, SCREEN_W, row, c)
        pyxel.rect(0, 440, SCREEN_W, 3, 10)
 
    # ─── PLATFORMS ────────────────────────────────────────────
 
    def _draw_platform(self, pl):
        x = int(pl.x - self.cam_x); y = int(pl.y); w = pl.w; h = pl.h; idx = self.lvl_idx
        if pl.p_type == 0:
            if   idx == 1: self._draw_plat_ice(x, y, w, h)
            elif idx == 2: self._draw_plat_lava_ground(x, y, w, h)
            elif idx == 3: self._draw_plat_cloud_ground(x, y, w, h)
            elif idx == 4: self._draw_plat_ghost_ground(x, y, w, h)
            elif idx == 5: self._draw_plat_inferno_ground(x, y, w, h)
            else:          self._draw_plat_forest_ground(x, y, w, h)
        elif pl.p_type == 1:
            if idx == 1: self._draw_wall_ice(x, y, w, h)
            else:        self._draw_wall_bark(x, y, w, h)
        elif pl.p_type == 2:
            if idx == 1: self._draw_wall_ice(x, y, w, h)
            else:        self._draw_wall_stone(x, y, w, h)
        elif pl.p_type == 3:
            col1 = 8 if (self.t//6)%2==0 else 9
            col2 = 10 if (self.t//6)%2==0 else 8
            pyxel.rect(x, y, w, h, col1)
            i = 0
            while i < w:
                tip_x = x+i+(self.t//5)%3
                pyxel.tri(tip_x, y, tip_x+6, y, tip_x+3, y-8, col2)
                i += 12
        elif pl.p_type == 4:
            pyxel.rect(x, y, w, h, 4)
            pyxel.rect(x, y+h-5, w, 5, 11)
            i = 0
            while i < w:
                pyxel.line(x+i, y+h, x+i+3, y+h+6, 11)
                pyxel.line(x+i+4, y+h, x+i+4, y+h+4, 3)
                i += 10
 
    def _draw_plat_forest_ground(self, x, y, w, h):
        pyxel.rect(x, y, w, h, 4); pyxel.rect(x, y, w, 5, 3); pyxel.rect(x, y+5, w, 4, 11)
        i = 0
        while i < w:
            gh = 4+(i*4+x)%7; pyxel.line(x+i, y, x+i, y-gh, 3 if i%3!=0 else 11); i += 7
        if w > 30:
            mp = x+w//3
            pyxel.rect(mp, y-8, 5, 8, 4); pyxel.circ(mp+2, y-10, 6, 8)
            pyxel.pset(mp, y-13, 7); pyxel.pset(mp+4, y-11, 7)
 
    def _draw_plat_ice(self, x, y, w, h):
        pyxel.rect(x, y, w, h, 1); pyxel.rect(x, y, w, 5, 6); pyxel.rect(x, y, w, 2, 12)
        shimmer_x = x+(self.t//3)%max(w, 1)
        if x <= shimmer_x < x+w: pyxel.pset(shimmer_x, y, 7); pyxel.pset(shimmer_x+1, y, 7)
        i = 0
        while i < w:
            dh = 5+(i*9+int(self.cam_x))%8
            pyxel.rect(x+i, y+h, 3, dh, 6); pyxel.pset(x+i+1, y+h+dh, 12); i += 14
 
    def _draw_plat_lava_ground(self, x, y, w, h):
        pyxel.rect(x, y, w, h, 2); pyxel.rect(x, y, w, 3, 0)
        i = 0
        while i < w:
            c = 8 if (self.t//8+i)%3 != 2 else 9
            pyxel.pset(x+i, y+6+(i*4)%7, c); i += 7
        glow_c = 9 if (self.t//8)%2==0 else 10
        pyxel.pset(x, y+2, glow_c); pyxel.pset(x+w-1, y+2, glow_c)
 
    def _draw_plat_cloud_ground(self, x, y, w, h):
        pyxel.rect(x, y, w, h, 7); pyxel.rect(x, y, w, 3, 13)
        i = 0
        while i < w: pyxel.circ(x+i+8, y-6, 10, 7); i += 16
        pyxel.rect(x+3, y+3, w-6, 6, 13)
        i = 0
        while i < w:
            dy = (self.t//2+i*7)%22
            if dy < 18: pyxel.pset(x+i+5, y+h+dy, 12); i += 12
 
    def _draw_plat_ghost_ground(self, x, y, w, h):
        pyxel.rect(x, y, w, h, 5); pyxel.rect(x, y, w, 3, 0)
        i = 0
        while i < w: pyxel.rect(x+i, y+6, 12, 3, 1); pyxel.rect(x+i+6, y+12, 12, 3, 1); i += 18
        glow_x = x+(self.t//5)%max(w, 1)
        if x <= glow_x < x+w: pyxel.pset(glow_x, y+1, 6)
        pyxel.pset(x, y, 6); pyxel.pset(x+w-1, y, 6)
 
    def _draw_plat_inferno_ground(self, x, y, w, h):
        pyxel.rect(x, y, w, h, 0); pyxel.rect(x, y, w, 3, 2)
        glow_c = 9 if (self.t//6)%2==0 else 8
        pyxel.rect(x, y, w, 2, glow_c)
        i = 0
        while i < w:
            bub_phase = (self.t//4+i*3)%20
            if bub_phase < 8: pyxel.pset(x+i, y+5+bub_phase%5, 9)
            i += 10
        pyxel.pset(x, y, 10); pyxel.pset(x+w-1, y, 10)
 
    def _draw_wall_bark(self, x, y, w, h):
        pyxel.rect(x, y, w, h, 4)
        i = 0
        while i < h: pyxel.rect(x, y+i, w, 1, 9); i += 12
        pyxel.rect(x, y, 4, h, 5); pyxel.rect(x+w-3, y, 3, h, 3)
        for di in range(0, h, 30): pyxel.circ(x+w//2, y+di+8, 3, 9)
        if h > 50: pyxel.rect(x, y+h-9, w, 6, 11)
 
    def _draw_wall_stone(self, x, y, w, h):
        pyxel.rect(x, y, w, h, 6)
        for di in range(0, h, 16): pyxel.line(x, y+di, x+w, y+di, 5)
        for di in range(0, h, 20): pyxel.pset(x+3, y+di+6, 7)
 
    def _draw_wall_ice(self, x, y, w, h):
        pyxel.rect(x, y, w, h, 1)
        i = 0
        while i < h:
            lc = 5 if (i//16)%2==0 else 1
            pyxel.rect(x, y+i, w, min(16, h-i), lc); i += 16
        pyxel.rect(x, y, 3, h, 6); pyxel.rect(x, y, 2, h, 12); pyxel.rect(x+w-3, y, 3, h, 1)
        for di in range(0, h, 22):
            pyxel.pset(x+6, y+di+8, 7); pyxel.pset(x+5, y+di+9, 12)
            if w > 14: pyxel.pset(x+w-8, y+di+12, 12)
            pyxel.line(x+10, y+di, x+13, y+di+12, 6)
 
    # ─── GOAL ─────────────────────────────────────────────────
 
    def _draw_goal(self):
        gx = int(self.goal_x - self.cam_x); gy = 340
        glow_r = 18+(self.t//8)%5
        pyxel.circ(gx, gy, glow_r, self.bg_col[1])
        pyxel.circ(gx, gy, 14, 9); pyxel.circ(gx, gy, 10, 10)
        pyxel.circ(gx, gy, 5, 7)
        if (self.t//8)%2==0: pyxel.circb(gx, gy, 18, 9)
        else:                 pyxel.circb(gx, gy, 18, 10)
        pyxel.text(gx-10, gy-32, "ZIEL!", 10)
 
    # ─── ITEMS ────────────────────────────────────────────────
 
    def _draw_items(self):
        idx = self.lvl_idx
        for it in self.items:
            if not it.alive: continue
            ix = int(it.x - self.cam_x); iy = int(it.screen_y())
            if it.kind == "nut":
                pyxel.circ(ix, iy, 6, 4); pyxel.circ(ix, iy, 5, 9)
                pyxel.circ(ix, iy, 3, 10); pyxel.pset(ix-1, iy-1, 7)
            elif it.kind == "golden_nut":
                r = 8+(self.t//6)%3
                pyxel.circ(ix, iy, r, 9); pyxel.circ(ix, iy, r-2, 10)
                pyxel.circ(ix, iy, r-4, 7)
                if (self.t//5)%3==0: pyxel.circb(ix, iy, r+2, 10)
            elif it.kind == "gem":
                if idx == 1:
                    pyxel.tri(ix, iy-8, ix-6, iy, ix+6, iy, 6)
                    pyxel.tri(ix-6, iy, ix+6, iy, ix, iy+5, 12)
                    pyxel.line(ix-3, iy-5, ix, iy-8, 7)
                else:
                    pyxel.tri(ix, iy-8, ix-6, iy, ix+6, iy, 12)
                    pyxel.tri(ix-6, iy, ix+6, iy, ix, iy+5, 6)
                    pyxel.line(ix-3, iy-5, ix, iy-8, 7)
            else:  # star
                for a in range(5):
                    ang = a*math.pi*2/5 - math.pi/2
                    ang2 = ang + math.pi/5
                    ex2 = int(ix+math.cos(ang)*7); ey2 = int(iy+math.sin(ang)*7)
                    mx2 = int(ix+math.cos(ang2)*3); my2 = int(iy+math.sin(ang2)*3)
                    pyxel.tri(ix, iy, ex2, ey2, mx2, my2, 10)
                pyxel.pset(ix, iy, 9)
 
    # ─── ENEMIES ──────────────────────────────────────────────
 
    def _draw_enemies(self):
        for e in self.enemies:
            if not e.alive: continue
            ex = int(e.x - self.cam_x); ey = int(e.y)
            if e.kind == "patrol":
                col = 8
                pyxel.rect(ex-7, ey-10, 14, 12, col)
                pyxel.rect(ex-5, ey-14, 10, 6, col)
                eye_off = 1 if e.vx > 0 else -1
                pyxel.pset(ex+eye_off*3, ey-8, 0); pyxel.pset(ex+eye_off*3, ey-7, 7)
                leg_a = (e.anim%2)*3
                pyxel.pset(ex-3+leg_a, ey+2, col); pyxel.pset(ex+3-leg_a, ey+2, col)
            elif e.kind == "chase":
                col = 2
                pyxel.rect(ex-7, ey-10, 14, 12, col)
                pyxel.rect(ex-5, ey-15, 10, 6, col)
                ec = 9 if (e.timer//10)%2 else 10
                pyxel.pset(ex-3, ey-8, ec); pyxel.pset(ex+3, ey-8, ec)
            elif e.kind == "jumper":
                col = 3; bob = int(math.sin(e.timer*0.2)*3)
                pyxel.circ(ex, ey-7+bob, 9, col); pyxel.circ(ex, ey-7+bob, 6, 11)
                pyxel.pset(ex-3, ey-9+bob, 0); pyxel.pset(ex+3, ey-9+bob, 0)
            elif e.kind == "flyer":
                col = 5; wing = int(math.sin(e.timer*0.3)*6)
                pyxel.rect(ex-6, ey-7, 12, 10, col)
                pyxel.tri(ex-6, ey-4, ex-15, ey-4-wing, ex-6, ey+2, 6)
                pyxel.tri(ex+6, ey-4, ex+15, ey-4-wing, ex+6, ey+2, 6)
                pyxel.pset(ex-2, ey-5, 0); pyxel.pset(ex+2, ey-5, 0)
            elif e.kind == "boss":
                self._draw_boss(ex, ey, e)
                # Feuerbälle zeichnen
                for fb in e.fireballs:
                    fbx = int(fb["x"]-self.cam_x); fby = int(fb["y"])
                    pyxel.circ(fbx, fby, 4, 9); pyxel.circ(fbx, fby, 2, 10)
                    pyxel.pset(fbx, fby, 7)
 
    def _draw_boss(self, ex, ey, e):
        phase = e.phase
        body_c = [2, 8, 9][phase]; eye_c = [9, 10, 7][phase]
        if e.stomp_timer > 4: pyxel.rect(ex-28, ey-28, 56, 40, 9)
        # Schatten
        pyxel.rect(ex-24, ey+3, 48, 6, 0)
        # Körper
        pyxel.rect(ex-20, ey-28, 40, 30, body_c)
        pyxel.rect(ex-18, ey-26, 36, 26, 2 if phase<2 else 8)
        pyxel.rect(ex-10, ey-20, 20, 14, 0)
        # Rippen
        for i in range(3): pyxel.line(ex-9, ey-19+i*4, ex+9, ey-19+i*4, 2 if phase>0 else 1)
        # Kopf
        pyxel.rect(ex-12, ey-48, 24, 22, body_c)
        pyxel.rect(ex-10, ey-46, 20, 18, 2 if phase<2 else 8)
        # Hörner
        horn_h = 14+phase*5
        pyxel.tri(ex-12, ey-48, ex-6, ey-48, ex-12, ey-48-horn_h, 9)
        pyxel.tri(ex+6, ey-48, ex+12, ey-48, ex+12, ey-48-horn_h, 9)
        if phase >= 1: pyxel.tri(ex-3, ey-48, ex+3, ey-48, ex, ey-48-horn_h+5, 10)
        # Augen
        pupil_off = int(math.sin(e.timer*0.1)*3)
        pyxel.circ(ex-6, ey-40, 6, eye_c); pyxel.circ(ex+6, ey-40, 6, eye_c)
        pyxel.pset(ex-6+pupil_off, ey-40, 0); pyxel.pset(ex+6+pupil_off, ey-40, 0)
        if phase >= 2:
            pyxel.pset(ex-6+pupil_off, ey-40, 8); pyxel.pset(ex+6+pupil_off, ey-40, 8)
        # Mund
        mouth_open = 6 if e.stomp_timer > 0 else 3
        pyxel.rect(ex-8, ey-30, 16, mouth_open, 0)
        for zi in range(-6, 7, 4): pyxel.pset(ex+zi, ey-30, 7)
        # Arme
        arm_swing = int(math.sin(e.timer*0.08)*7)
        pyxel.rect(ex-26, ey-26+arm_swing, 8, 14, body_c)
        pyxel.rect(ex+18, ey-26-arm_swing, 8, 14, body_c)
        for c in range(4):
            pyxel.pset(ex-26+c, ey-12+arm_swing, 9)
            pyxel.pset(ex+18+c, ey-12-arm_swing, 9)
        # Flügel
        wing_flap = int(math.sin(e.timer*0.12)*12)
        pyxel.tri(ex-20, ey-24, ex-44, ey-40+wing_flap, ex-20, ey-10, body_c)
        pyxel.tri(ex-20, ey-24, ex-38, ey-48+wing_flap, ex-20, ey-22, 2)
        pyxel.tri(ex+20, ey-24, ex+44, ey-40+wing_flap, ex+20, ey-10, body_c)
        pyxel.tri(ex+20, ey-24, ex+38, ey-48+wing_flap, ex+20, ey-22, 2)
        # Beine
        leg_l = int(math.sin(e.timer*0.1)*4)
        pyxel.rect(ex-14, ey-3, 8, 6, body_c); pyxel.rect(ex+6, ey-3-leg_l, 8, 6, body_c)
        pyxel.pset(ex-15, ey+3, 9); pyxel.pset(ex-14, ey+3, 9)
        pyxel.pset(ex+6, ey+3-leg_l, 9); pyxel.pset(ex+7, ey+3-leg_l, 9)
        # Feuer-Atem (Phase ≥ 1)
        if phase >= 1:
            fd = 1 if e.x < 1400 else -1
            breath_len = 40+phase*20
            for b in range(0, breath_len, 6):
                bx = ex+fd*(22+b); by = ey-34+int(math.sin(b*0.4+e.timer*0.1)*5)
                bc = 10 if b < breath_len//2 else 9
                pyxel.circ(bx, by, 3-b//breath_len, bc)
        if phase >= 2 and (e.timer//3)%2==0:
            pyxel.rectb(ex-22, ey-50, 44, 30, 10)
 
    # ─── NPCS ─────────────────────────────────────────────────
 
    def _draw_npcs(self):
        for npc in self.npcs:
            nx = int(npc.x - self.cam_x); ny = int(npc.y)
            pyxel.circ(nx, ny-18, 7, npc.sprite_col)
            pyxel.rect(nx-4, ny-10, 8, 10, npc.sprite_col)
            pyxel.pset(nx-3, ny-19, 0); pyxel.pset(nx+3, ny-19, 0)
            if not npc.talking and (self.t//20)%2==0:
                pyxel.text(nx-3, ny-32, "!", 10)
 
    # ─── DIALOG ───────────────────────────────────────────────
 
    def _draw_dialog(self, text):
        ox = 16; oy = SCREEN_H - 130
        pyxel.rect(ox, oy, SCREEN_W-32, 110, 0)
        pyxel.rectb(ox, oy, SCREEN_W-32, 110, 9)
        pyxel.rectb(ox-1, oy-1, SCREEN_W-30, 112, 10)
        lines = text.split("\n")
        for i, ln in enumerate(lines[:6]):
            pyxel.text(ox+8, oy+10+i*14, ln, 7)
        if (self.t//15)%2 == 0: pyxel.text(SCREEN_W-80, oy+90, "E schließen", 13)
 
    # ─── BOSS HUD ─────────────────────────────────────────────
 
    def _draw_boss_hud(self, e):
        bx = SCREEN_W//2 - 80; by = 22
        pyxel.rect(bx, by, 162, 12, 0)
        pyxel.rectb(bx, by, 162, 12, 9)
        bar_w = int(e.hp/5.0*160)
        c = 9 if e.phase==0 else (10 if e.phase==1 else 8)
        pyxel.rect(bx+1, by+1, bar_w, 10, c)
        pyxel.rect(bx+1, by+1, bar_w, 2, 7)
        pyxel.text(bx+2, by-10, "INFERNO-REX", 8 if (self.t//8)%2==0 else 9)
 
    # ─── SQUIRREL ─────────────────────────────────────────────
 
    def _draw_squirrel_at(self, x, y, facing, frame, wall=False, ceil=False):
        body_c = 8; tail_c = 9; acc_c = 10
        if wall:
            pyxel.rect(x+2, y, 8, 12, body_c); pyxel.rect(x+2, y, 8, 3, acc_c)
            claw_x = x+10 if facing==1 else x
            pyxel.pset(claw_x, y+3, 7); pyxel.pset(claw_x, y+7, 7)
            for ti in range(5):
                off = int(math.sin(self.t*0.2+ti*0.5)*2)
                pyxel.pset(x-2+off, y+2+ti*2, tail_c)
        elif ceil:
            pyxel.rect(x+2, y, 8, 12, body_c)
            pyxel.pset(x+3, y, 9); pyxel.pset(x+8, y, 9)
            for ti in range(6): pyxel.pset(x+5, y+13+ti, tail_c)
        else:
            bobs = [0, -1, 0, -1]; bob = bobs[frame]; py2 = y+bob
            if facing == 1:
                tail_pts = [(x-3,py2+2),(x-4,py2+4),(x-4,py2+7),(x-3,py2+9)]
            else:
                tail_pts = [(x+11,py2+2),(x+12,py2+4),(x+12,py2+7),(x+11,py2+9)]
            for ti, (tx2, ty2) in enumerate(tail_pts):
                c = tail_c if ti%2==0 else acc_c
                pyxel.pset(tx2, ty2, c)
                pyxel.pset(tx2+(1 if facing==1 else -1), ty2, tail_c)
            pyxel.rect(x+2, py2, 8, 10, body_c)
            pyxel.rect(x+3, py2+3, 4, 4, 4)
            legs = [(3,7),(2,8),(3,7),(4,6)]; la, lb = legs[frame]
            pyxel.pset(x+la, py2+10, body_c); pyxel.pset(x+lb, py2+10, body_c)
            if self.dash_timer > 0:
                for di in range(1, 4): pyxel.pset(x-(di*facing*3), py2+5, acc_c if di==1 else 13)
        # Kopf
        hd_x = x-5 if facing==1 else x+10
        if facing == 1:
            pyxel.tri(hd_x, y+1, hd_x+3, y+1, hd_x+1, y-3, 9)
            pyxel.tri(hd_x+4, y+1, hd_x+7, y+1, hd_x+5, y-3, 9)
        else:
            pyxel.tri(hd_x, y+1, hd_x+3, y+1, hd_x+1, y-3, 9)
            pyxel.tri(hd_x+4, y+1, hd_x+7, y+1, hd_x+5, y-3, 9)
        pyxel.rect(hd_x, y+1, 7, 7, acc_c)
        eye_x = hd_x+5 if facing==1 else hd_x+1
        pyxel.pset(eye_x, y+3, 0); pyxel.pset(eye_x+(1 if facing==1 else -1), y+3, 7)
        nose_x = hd_x+6 if facing==1 else hd_x
        pyxel.pset(nose_x, y+6, 4); pyxel.pset(nose_x, y+7, 8)
        ear_x = x+7 if facing==1 else x+1
        for ei in range(y-3, y+1): pyxel.pset(ear_x, ei, tail_c)
 
    # ─── HUD ──────────────────────────────────────────────────
 
    def _draw_hud(self):
        pyxel.rect(0, 0, SCREEN_W, 18, 0)
        pyxel.line(0, 18, SCREEN_W, 18, 5)
        pyxel.rect(0, 17, SCREEN_W, 1, 9)
        names = ["Herbst-Wald","Eishoehle","Lava-Tempel","Wolkengipfel","Geistertuerme","Inferno-Gipfel"]
        pyxel.text(4, 4, "LVL"+str(self.lvl_idx+1)+" "+names[self.lvl_idx], 7)
        sc_str = "SCORE:"+str(self.score)
        sc_x = SCREEN_W//2 - len(sc_str)*2
        pyxel.text(sc_x+1, 5, sc_str, 0); pyxel.text(sc_x, 4, sc_str, 10)
        for i in range(self.lives): self._draw_heart(SCREEN_W-14-i*16, 4)
        bar_x, bar_y = 4, SCREEN_H-14
        pyxel.rect(bar_x, bar_y, 70, 8, 0)
        bar_w = int(self.stamina/STAMINA_MAX*68)
        col = 11 if self.stamina>60 else (9 if self.stamina>25 else 8)
        pyxel.rect(bar_x+1, bar_y+1, bar_w, 6, col)
        if bar_w > 2: pyxel.rect(bar_x+1, bar_y+1, bar_w, 2, 7)
        pyxel.rectb(bar_x, bar_y, 70, 8, 5)
        pyxel.text(bar_x+72, bar_y+1, "STM", 13)
        if abs(self.wind) > 0.2:
            pyxel.text(SCREEN_W-30, SCREEN_H-14, ">>" if self.wind>0 else "<<", 12 if self.wind>0 else 6)
        if self.dash_cd > 0:
            fill = int((1-self.dash_cd/40)*28)
            pyxel.rect(100, SCREEN_H-14, fill, 8, 6)
            if fill > 1: pyxel.rect(100, SCREEN_H-14, fill, 2, 7)
            pyxel.rectb(100, SCREEN_H-14, 28, 8, 5)
            pyxel.text(132, SCREEN_H-13, "DASH", 13)
        if self.hurt_timer > 50:
            for ry in range(0, SCREEN_H, 3): pyxel.line(0, ry, SCREEN_W, ry, 8)
 
    def _draw_heart(self, x, y):
        pyxel.pset(x+1, y, 8); pyxel.pset(x+3, y, 8)
        pyxel.rect(x, y+1, 5, 3, 8)
        pyxel.pset(x+1, y+4, 8); pyxel.pset(x+3, y+4, 8)
        pyxel.pset(x+2, y+5, 8); pyxel.pset(x+1, y+1, 4)
 
    def _draw_overlay(self, title, subtitle, col):
        ox = SCREEN_W//2 - 100; oy = SCREEN_H//2 - 50
        pyxel.rect(ox, oy, 200, 100, 0)
        pyxel.rectb(ox, oy, 200, 100, col)
        pyxel.rectb(ox-1, oy-1, 202, 102, 5)
        pyxel.text(ox+12, oy+12, title, col)
        pyxel.text(ox+10, oy+28, subtitle, 7)
        pyxel.text(ox+10, oy+46, "SCORE: "+str(self.score), 10)
        if self.hi_score > 0: pyxel.text(ox+10, oy+62, "BEST:  "+str(self.hi_score), 9)
 
    def _draw_final_screen(self):
        for row in range(SCREEN_H):
            c = 0 if row<100 else (2 if row<220 else (9 if row<360 else 10))
            pyxel.line(0, row, SCREEN_W, row, c)
        cx = SCREEN_W//2; cy = 160
        for r in range(38, 8, -3):
            c = [10,9,4,9,10,7][r%6]; pyxel.circb(cx, cy, r, c)
        pyxel.circ(cx, cy, 20, 9); pyxel.circ(cx, cy, 15, 10); pyxel.circ(cx, cy, 8, 7)
        pyxel.pset(cx-3, cy-3, 7); pyxel.pset(cx+3, cy-3, 7)
        self._draw_squirrel_at(cx+28, cy+8, 1, (self.t//8)%4)
        pyxel.rect(30, 250, SCREEN_W-60, 200, 0)
        pyxel.rectb(30, 250, SCREEN_W-60, 200, 10)
        pyxel.rectb(29, 249, SCREEN_W-58, 202, 9)
        if (self.t//12)%2 == 0:
            pyxel.text(cx-56, 268, "GOLDENE EICHEL GEFUNDEN!", 10)
        else:
            pyxel.text(cx-56, 268, "GOLDENE EICHEL GEFUNDEN!", 9)
        pyxel.text(cx-48, 290, "Nuss hat die Welt gerettet!", 7)
        pyxel.text(cx-38, 312, "Alle 6 Welten bezwungen.", 13)
        pyxel.text(cx-30, 336, "SCORE:  "+str(self.score), 10)
        if self.hi_score > 0: pyxel.text(cx-30, 356, "BEST:   "+str(self.hi_score), 9)
        if (self.t//20)%2 == 0: pyxel.text(cx-44, 396, "SPACE - Neues Spiel", 7)
        for i in range(8):
            fwx = (i*100+40+self.t//2) % SCREEN_W
            fwy = 60+(i*33)%130
            fc = [9,10,7,12,6][i%5]
            pyxel.circb(fwx, fwy, (self.t//3+i*9)%12+2, fc)
 
 
# Pyxel Studio — Nuss-Mission DELUXE v4 (Grafik-Upgrade alle Level)
import pyxel
import random
import math
import pyxel


import pyxel

SCREEN_W = 160
SCREEN_H = 120

class App:
    def __init__(self):                          # ← nur EINMAL
        pyxel.init(SCREEN_W, SCREEN_H, title="Nuss-Mission DELUXE v4")
        self.setup_music()
        self._init_sounds()
        pyxel.run(self.update, self.draw)

    def setup_music(self):                       # ← auf Klassenebene, nicht in __init__
        pyxel.sounds[10].set(
            "e3e3g3g3a3a3g3r e3e3d3d3c3c3c3r e3e3g3g3a3a3b3b3c4c4b3a3g3g3rr",
            "s", "5", "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv", 20
        )
        pyxel.sounds[11].set(
            "c2rg2rc2rg2rf2ra2rg2rb2r",
            "t", "5", "vvvvvvvvvvvvvvvv", 20
        )
        pyxel.sounds[12].set(
            "c3e3g3c4c3e3g3c4f3a3c4f4g3b3d4g4",
            "s", "3", "vvvvvvvvvvvvvvvv", 28
        )
        pyxel.sounds[13].set(
            "c1rc1rc1rc1rc1rc1rc1rc1r",
            "n", "6", "vvvvvvvvvvvvvvvv", 20
        )
        pyxel.musics[0].set(
            [10, 10, 10, 10],
            [11, 11, 11, 11],
            [12, 12, 12, 12],
            [13, 13, 13, 13]
        )
        pyxel.playm(0, loop=True)

    def _init_sounds(self):
        pass                                     # ← dein Sound-Code hier

    def update(self):
        if pyxel.btnp(pyxel.KEY_Q):
            pyxel.quit()

    def draw(self):
        pyxel.cls(1)


SCREEN_W = 256
SCREEN_H = 192
GRAVITY = 0.28
WALK_SPEED = 1.8
JUMP_PWR = -5.8
WALL_JUMP_X = 4.2
WALL_JUMP_Y = -4.8
STAMINA_MAX = 100
COYOTE_TIME = 8
JUMP_BUFFER = 8


class Particle:
    def __init__(self, x=None, y=None, vx=0, vy=0, col=7, life=30, kind="dust"):
        self.x = x if x is not None else random.randint(0, SCREEN_W)
        self.y = y if y is not None else random.randint(0, SCREEN_H)
        self.vx = vx
        self.vy = vy
        self.col = col
        self.life = life
        self.max_life = life
        self.kind = kind

    def update(self, wind=0):
        if self.kind == "leaf":
            self.x += self.vx + wind * 1.5
            self.y += self.vy
            self.vx = math.sin(self.life * 0.3) * 0.6
            self.vy = min(self.vy + 0.05, 0.8)
            if self.x < -5: self.x = SCREEN_W + 5
            if self.x > SCREEN_W + 5: self.x = -5
            if self.y > SCREEN_H + 5: self.y = -5
        elif self.kind == "snow":
            self.x += self.vx + wind * 2 + math.sin(self.life * 0.1) * 0.3
            self.y += self.vy
            if self.x > SCREEN_W + 5: self.x = -5
            if self.x < -5: self.x = SCREEN_W + 5
            if self.y > SCREEN_H + 5: self.y = -5
        elif self.kind == "ice_drip":
            self.x += self.vx
            self.y += self.vy
            self.vy = min(self.vy + 0.04, 1.5)
            if self.y > SCREEN_H + 5:
                self.life = 0
        elif self.kind == "ice_splash":
            self.x += self.vx
            self.y += self.vy
            self.vy += 0.15
            self.vx *= 0.9
            self.life -= 1
        elif self.kind == "rain":
            self.x += self.vx + wind * 1.2
            self.y += self.vy
            if self.y > SCREEN_H + 5:
                self.y = -5
                self.x = random.randint(0, SCREEN_W)
        elif self.kind == "ember":
            self.x += self.vx + math.sin(self.life * 0.2) * 0.4
            self.y += self.vy
            self.vy -= 0.025
            if self.y < -5:
                self.y = SCREEN_H + 5
                self.x = random.randint(0, SCREEN_W)
        elif self.kind == "cloud_wisp":
            self.x += self.vx + wind * 0.5
            self.y += self.vy
            if self.x > SCREEN_W + 20: self.x = -20
            if self.x < -20: self.x = SCREEN_W + 20
        elif self.kind == "aurora":
            self.x += self.vx + wind * 0.3
            self.y += math.sin(self.life * 0.05) * 0.2
            self.life -= 1
        elif self.kind == "firefly":
            self.x += self.vx + math.sin(self.life * 0.07) * 0.5
            self.y += self.vy + math.cos(self.life * 0.05) * 0.4
            if self.x < -5: self.x = SCREEN_W + 5
            if self.x > SCREEN_W + 5: self.x = -5
            if self.y < 0: self.y = SCREEN_H
            if self.y > SCREEN_H: self.y = 0
        elif self.kind == "spore":
            self.x += self.vx + math.sin(self.life * 0.12) * 0.3
            self.y += self.vy
            if self.y > SCREEN_H: self.y = 0
            if self.x < -5: self.x = SCREEN_W + 5
            if self.x > SCREEN_W + 5: self.x = -5
        elif self.kind == "ghost_wisp":
            self.x += self.vx + math.sin(self.life * 0.04) * 0.8
            self.y += self.vy + math.cos(self.life * 0.03) * 0.4
            if self.x < -10: self.x = SCREEN_W + 10
            if self.x > SCREEN_W + 10: self.x = -10
            if self.y < 0: self.vy = abs(self.vy)
            if self.y > SCREEN_H: self.vy = -abs(self.vy)
        else:
            self.x += self.vx
            self.y += self.vy
            self.vy += 0.12
            self.vx *= 0.92
        self.life -= 1

    def is_alive(self):
        return self.life > 0


class Platform:
    def __init__(self, x, y, w, h, p_type, move_range=0, move_speed=0, move_vert=False):
        self.x = x
        self.ox = x
        self.y = y
        self.oy = y
        self.w = w
        self.h = h
        self.p_type = p_type
        self.move_range = move_range
        self.move_speed = move_speed
        self.move_vert = move_vert
        self.phase = random.uniform(0, math.pi * 2)

    def update(self, t):
        if self.move_range:
            if self.move_vert:
                self.y = self.oy + math.sin(t * self.move_speed + self.phase) * self.move_range
            else:
                self.x = self.ox + math.sin(t * self.move_speed + self.phase) * self.move_range


class Item:
    def __init__(self, x, y, kind="nut"):
        self.x = x
        self.y = y
        self.kind = kind
        self.alive = True
        self.bob = random.uniform(0, math.pi * 2)

    def update(self):
        self.bob += 0.08

    def screen_y(self):
        return self.y + math.sin(self.bob) * 2


class Enemy:
    def __init__(self, x, y, kind="patrol"):
        self.x = x
        self.y = y
        self.kind = kind
        self.vx = 0.8
        self.vy = 0.0
        self.alive = True
        self.timer = 0
        self.start_x = x
        self.start_y = y
        self.anim = 0

    def update(self, px, py):
        self.timer += 1
        self.anim = (self.timer // 8) % 4
        if self.kind == "patrol":
            self.x += self.vx
            if abs(self.x - self.start_x) > 40:
                self.vx *= -1
        elif self.kind == "chase":
            dx = px - self.x
            dy = py - self.y
            dist = math.sqrt(dx * dx + dy * dy)
            if dist < 1: dist = 1
            if dist < 90:
                self.x += (dx / dist) * 0.85
                self.y += (dy / dist) * 0.5
        elif self.kind == "jumper":
            self.x += self.vx
            if abs(self.x - self.start_x) > 30:
                self.vx *= -1
            if self.timer % 60 == 0:
                self.vy = -3.5
            self.vy += 0.2
            self.y += self.vy
            if self.y >= self.start_y:
                self.y = self.start_y
                self.vy = 0
        elif self.kind == "flyer":
            self.x = self.start_x + math.sin(self.timer * 0.04) * 50
            self.y = self.start_y + math.sin(self.timer * 0.07) * 25


class Game:
    def __init__(self):
        pyxel.init(SCREEN_W, SCREEN_H, title="Nuss-Mission DELUXE v4")
        self._init_sounds()
        self.lvl_idx = 0
        self.hi_score = 0
        self.bg_particles = []
        self.fx_particles = []
        self.state = "TITLE"
        self.title_t = 0
        self.t = 0
        # Aurora-Streifen Eishoehle
        self.aurora_strips = []
        # Blitz-Timer Geisterwelt
        self.lightning_timer = 0
        self.lightning_x = 0
        self.lightning_active = 0
        self.lightning_segs = []
        # Lava-Blasen
        self.lava_bubbles = [(random.randint(0, SCREEN_W), random.uniform(0, math.pi*2)) for _ in range(8)]
        # Wald: Glühwürmchen + schwebende Sporen
        self.forest_fireflies = [(random.uniform(0, SCREEN_W), random.uniform(40, 160), random.uniform(0, math.pi*2)) for _ in range(12)]
        # Wolken: Regenbogen-Phase
        self.rainbow_phase = 0
        # Inferno: Riss-Linien (statisch)
        self.inferno_cracks = [(random.randint(20, SCREEN_W-20), random.randint(100, 160), random.randint(-20, 20), random.randint(10, 25)) for _ in range(8)]
        self._spawn_bg_particles()
        pyxel.run(self.update, self.draw)

    def _init_sounds(self):
        pyxel.sound(0).set("a2", "p", "3", "n", 6)
        pyxel.sound(1).set("c3", "t", "6", "n", 5)
        pyxel.sound(2).set("f1", "n", "4", "f", 8)
        pyxel.sound(3).set("g3", "t", "5", "n", 8)
        pyxel.sound(4).set("a1", "n", "2", "f", 4)

    def _spawn_bg_particles(self):
        self.bg_particles = []
        self.fx_particles = []
        idx = self.lvl_idx
        if idx == 0:
            # Herbst-Blätter + Glühwürmchen + Sporen
            for _ in range(22):
                c = random.choice([3, 9, 10, 4])
                self.bg_particles.append(Particle(
                    x=random.randint(0, SCREEN_W), y=random.randint(0, SCREEN_H),
                    vx=random.uniform(-0.4, 0.4), vy=random.uniform(0.3, 0.9),
                    col=c, life=9999, kind="leaf"))
            for _ in range(8):
                self.bg_particles.append(Particle(
                    x=random.randint(0, SCREEN_W), y=random.randint(30, 150),
                    vx=random.uniform(-0.2, 0.2), vy=random.uniform(-0.1, 0.1),
                    col=random.choice([9, 10, 7]), life=9999, kind="firefly"))
            for _ in range(10):
                self.bg_particles.append(Particle(
                    x=random.randint(0, SCREEN_W), y=random.randint(0, SCREEN_H),
                    vx=random.uniform(-0.15, 0.15), vy=random.uniform(0.1, 0.4),
                    col=random.choice([7, 9]), life=9999, kind="spore"))
        elif idx == 1:
            for _ in range(30):
                c = random.choice([6, 7, 12, 13])
                self.bg_particles.append(Particle(
                    x=random.randint(0, SCREEN_W), y=random.randint(0, SCREEN_H),
                    vx=random.uniform(-0.3, 0.3), vy=random.uniform(0.4, 1.0),
                    col=c, life=9999, kind="snow"))
            self._spawn_ice_drips()
            self.aurora_strips = [
                {"x": random.randint(0, SCREEN_W), "y": random.randint(18, 50),
                 "w": random.randint(30, 80), "col": random.choice([5, 12, 6, 1]),
                 "phase": random.uniform(0, math.pi * 2)}
                for _ in range(6)
            ]
        elif idx == 2:
            for _ in range(22):
                c = random.choice([8, 9, 10, 4])
                self.bg_particles.append(Particle(
                    x=random.randint(0, SCREEN_W), y=random.randint(0, SCREEN_H),
                    vx=random.uniform(-0.5, 0.5), vy=random.uniform(-1.5, -0.4),
                    col=c, life=9999, kind="ember"))
        elif idx == 3:
            for _ in range(18):
                c = random.choice([6, 7, 12, 13])
                self.bg_particles.append(Particle(
                    x=random.randint(0, SCREEN_W), y=random.randint(10, 100),
                    vx=random.uniform(0.2, 0.8), vy=random.uniform(-0.1, 0.1),
                    col=c, life=9999, kind="cloud_wisp"))
            self.rainbow_phase = 0
        elif idx == 4:
            for _ in range(40):
                c = random.choice([5, 6, 1])
                self.bg_particles.append(Particle(
                    x=random.randint(0, SCREEN_W), y=random.randint(0, SCREEN_H),
                    vx=random.uniform(-0.5, -0.1), vy=random.uniform(4.0, 6.0),
                    col=c, life=9999, kind="rain"))
            for _ in range(15):
                self.bg_particles.append(Particle(
                    x=random.randint(0, SCREEN_W), y=random.randint(0, SCREEN_H),
                    vx=random.uniform(-0.3, 0.3), vy=random.uniform(-0.2, 0.2),
                    col=random.choice([5, 6, 1, 13]), life=9999, kind="ghost_wisp"))
            self.lightning_timer = random.randint(60, 200)
            self.lightning_active = 0
        else:
            for _ in range(30):
                c = random.choice([8, 9, 10, 2])
                self.bg_particles.append(Particle(
                    x=random.randint(0, SCREEN_W), y=random.randint(0, SCREEN_H),
                    vx=random.uniform(-0.6, 0.6), vy=random.uniform(-2.0, -0.5),
                    col=c, life=9999, kind="ember"))

    def _spawn_ice_drips(self):
        for _ in range(14):
            self.bg_particles.append(Particle(
                x=random.randint(0, SCREEN_W), y=random.randint(0, 30),
                vx=random.uniform(-0.1, 0.1), vy=random.uniform(0.3, 0.8),
                col=random.choice([6, 7, 12]), life=random.randint(80, 200),
                kind="ice_drip"))

    def init_lvl(self):
        self.px = 20
        self.py = 140
        self.vx = 0
        self.vy = 0
        self.stamina = STAMINA_MAX
        self.cam_x = 0
        self.score = 0
        self.facing = 1
        self.lock_timer = 0
        self.coyote = 0
        self.jump_buffer  = 0
        self.state = "PLAY"
        self.wind = 0
        self.t = 0
        self.anim_frame = 0
        self.on_wall = False
        self.on_ceil = False
        self.dash_timer = 0
        self.dash_cd = 0
        self.hurt_timer = 0
        self.lives = 3
        self.enemies = []
        self._spawn_bg_particles()
        self._build_level(self.lvl_idx)

    def _build_level(self, idx):
        if idx == 0:
            self.bg_col = (1, 2)
            self.goal_x = 680
            self.plats = [
                Platform(0,160,120,32,0), Platform(110,0,20,192,1),
                Platform(130,10,100,14,0), Platform(150,80,50,10,0),
                Platform(215,0,16,192,1), Platform(231,140,80,20,0),
                Platform(300,60,30,10,0,25,0.04), Platform(360,5,16,192,1),
                Platform(376,140,90,20,0), Platform(420,70,50,10,0),
                Platform(490,0,16,192,1), Platform(506,140,130,20,0),
                Platform(560,90,30,10,0,20,0.05),
            ]
            self.items = [
                Item(145,60,"nut"), Item(240,110,"nut"), Item(310,40,"gem"),
                Item(380,110,"nut"), Item(430,50,"star"), Item(570,70,"nut"),
            ]
            self.enemies = [Enemy(250,130,"patrol"), Enemy(400,130,"patrol")]

        elif idx == 1:
            self.bg_col = (5, 1)
            self.goal_x = 760
            self.plats = [
                Platform(0,160,80,32,0), Platform(80,0,16,192,2),
                Platform(96,5,100,12,0), Platform(96,160,50,32,0),
                Platform(160,80,35,10,0,30,0.04), Platform(200,0,16,192,2),
                Platform(216,140,110,30,0), Platform(290,50,30,10,0,35,0.05),
                Platform(360,0,16,192,2), Platform(376,160,55,32,0),
                Platform(415,70,35,10,0,25,0.06), Platform(460,0,16,192,2),
                Platform(476,140,80,30,0), Platform(530,60,40,10,0,20,0.07),
                Platform(600,140,120,30,0), Platform(640,90,30,10,0,30,0.04),
            ]
            self.items = [
                Item(130,145,"nut"), Item(230,110,"nut"), Item(295,30,"gem"),
                Item(390,140,"nut"), Item(540,40,"star"), Item(620,110,"gem"),
            ]
            self.enemies = [
                Enemy(250,130,"patrol"), Enemy(500,130,"chase"), Enemy(640,130,"patrol"),
            ]

        elif idx == 2:
            self.bg_col = (2, 8)
            self.goal_x = 880
            self.plats = [
                Platform(0,160,70,32,0), Platform(70,0,16,192,1),
                Platform(86,10,90,12,4), Platform(86,150,60,40,3),
                Platform(160,90,35,10,0), Platform(200,0,16,192,1),
                Platform(216,140,80,30,0), Platform(275,50,30,10,0,40,0.05),
                Platform(350,0,16,192,2), Platform(366,150,45,40,3),
                Platform(400,80,35,10,0,0,0.06,True), Platform(450,0,16,192,1),
                Platform(466,140,90,30,0), Platform(530,40,40,10,0,30,0.07),
                Platform(600,0,16,192,2), Platform(616,140,55,30,0),
                Platform(655,65,35,10,0,25,0.08), Platform(710,150,80,30,0),
                Platform(760,80,30,10,0,35,0.05),
            ]
            self.items = [
                Item(120,5,"nut"), Item(240,110,"gem"), Item(285,30,"star"),
                Item(420,60,"nut"), Item(540,20,"gem"), Item(660,45,"star"), Item(730,60,"star"),
            ]
            self.enemies = [
                Enemy(240,130,"patrol"), Enemy(480,130,"chase"),
                Enemy(650,130,"chase"), Enemy(760,120,"jumper"),
            ]

        elif idx == 3:
            self.bg_col = (12, 6)
            self.goal_x = 980
            self.plats = [
                Platform(0,165,60,32,0), Platform(60,0,16,192,1),
                Platform(76,150,160,15,0), Platform(105,75,35,10,0,45,0.035),
                Platform(185,20,35,10,0,35,0.06), Platform(256,0,16,192,2),
                Platform(272,140,110,30,0), Platform(325,60,35,10,0,55,0.045),
                Platform(405,100,25,10,0,25,0.08), Platform(455,0,16,192,1),
                Platform(471,150,90,30,0), Platform(525,50,30,10,0,40,0.065),
                Platform(600,0,16,192,2), Platform(616,145,75,30,0),
                Platform(670,70,40,10,0,35,0.07), Platform(760,145,100,30,0),
                Platform(810,80,30,10,0,30,0.09),
            ]
            self.items = [
                Item(115,55,"star"), Item(200,0,"gem"), Item(295,110,"star"),
                Item(340,40,"star"), Item(415,80,"gem"), Item(540,30,"star"),
                Item(685,50,"star"), Item(820,60,"star"),
            ]
            self.enemies = [
                Enemy(295,130,"chase"), Enemy(500,130,"chase"),
                Enemy(665,130,"chase"), Enemy(820,100,"flyer"),
            ]

        elif idx == 4:
            self.bg_col = (5, 2)
            self.goal_x = 1100
            self.plats = [
                Platform(0,165,55,32,0), Platform(55,0,14,192,2),
                Platform(69,155,70,20,0), Platform(100,80,28,10,0,30,0.06,True),
                Platform(170,30,28,10,0,40,0.07), Platform(230,0,14,192,1),
                Platform(244,145,100,30,0), Platform(290,70,28,10,0,50,0.06,True),
                Platform(370,30,28,10,0,30,0.09), Platform(420,0,14,192,2),
                Platform(434,155,80,30,0), Platform(480,80,28,10,0,35,0.07,True),
                Platform(555,40,28,10,0,45,0.08), Platform(610,0,14,192,1),
                Platform(624,145,90,30,0), Platform(665,75,28,10,0,40,0.09),
                Platform(740,0,14,192,2), Platform(754,155,70,30,0),
                Platform(800,65,28,10,0,35,0.1), Platform(870,145,100,30,0),
                Platform(920,80,28,10,0,25,0.11), Platform(970,150,80,30,0),
            ]
            self.items = [
                Item(110,60,"star"), Item(255,120,"gem"), Item(295,50,"star"),
                Item(375,10,"star"), Item(490,60,"gem"), Item(560,20,"star"),
                Item(680,55,"gem"), Item(810,45,"star"), Item(930,60,"star"),
            ]
            self.enemies = [
                Enemy(260,130,"patrol"), Enemy(450,130,"chase"),
                Enemy(640,130,"chase"), Enemy(780,130,"jumper"), Enemy(900,110,"flyer"),
            ]

        else:
            self.bg_col = (8, 2)
            self.goal_x = 1240
            self.plats = [
                Platform(0,165,50,32,0), Platform(50,0,14,192,1),
                Platform(64,155,60,20,3), Platform(80,85,24,10,0,30,0.08),
                Platform(145,35,24,10,0,40,0.1), Platform(210,0,14,192,2),
                Platform(224,145,90,30,0), Platform(265,75,24,10,0,50,0.08,True),
                Platform(350,30,24,10,0,40,0.12), Platform(410,0,14,192,1),
                Platform(424,155,65,20,3), Platform(455,85,24,10,0,35,0.09,True),
                Platform(525,40,24,10,0,45,0.11), Platform(590,0,14,192,2),
                Platform(604,145,80,30,0), Platform(640,75,24,10,0,40,0.1),
                Platform(715,0,14,192,1), Platform(729,155,60,30,0),
                Platform(770,65,24,10,0,45,0.12,True), Platform(840,145,80,30,0),
                Platform(885,80,24,10,0,35,0.13), Platform(950,0,14,192,2),
                Platform(964,155,60,20,3), Platform(1000,75,24,10,0,40,0.1),
                Platform(1070,145,80,30,0), Platform(1110,65,24,10,0,30,0.14),
                Platform(1160,150,90,30,0),
            ]
            self.items = [
                Item(90,65,"star"), Item(150,15,"gem"), Item(240,120,"star"),
                Item(355,10,"star"), Item(465,65,"gem"), Item(535,20,"star"),
                Item(650,55,"gem"), Item(780,45,"star"), Item(895,60,"star"),
                Item(1010,55,"star"), Item(1120,45,"gem"),
            ]
            self.enemies = [
                Enemy(235,130,"chase"), Enemy(440,130,"chase"),
                Enemy(615,130,"chase"), Enemy(750,120,"jumper"),
                Enemy(870,100,"flyer"), Enemy(990,130,"chase"), Enemy(1090,100,"flyer"),
            ]

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

    def update(self):
        self.t += 1
        if self.state == "TITLE":
            self.title_t += 1
            for p in self.bg_particles:
                p.update()
            if pyxel.btnp(pyxel.KEY_SPACE) or pyxel.btnp(pyxel.KEY_RETURN):
                self.lvl_idx = 0
                self.hi_score = 0
                self.init_lvl()
        elif self.state == "PLAY":
            self._update_play()
        elif self.state in ("LOSE", "WIN", "GAMEOVER"):
            for p in self.bg_particles:
                p.update()
            self.fx_particles = [p for p in self.fx_particles if p.is_alive()]
            for p in self.fx_particles:
                p.update()
            if pyxel.btnp(pyxel.KEY_SPACE) or pyxel.btnp(pyxel.KEY_RETURN):
                if self.state == "WIN" and self.lvl_idx >= 5:
                    self.state = "TITLE"
                elif self.state == "WIN":
                    self.lvl_idx += 1
                    self.hi_score = max(self.hi_score, self.score)
                    self.init_lvl()
                elif self.state == "GAMEOVER":
                    self.state = "TITLE"
                else:
                    self.init_lvl()

    def _update_play(self):
        for p in self.bg_particles:
            p.update(self.wind)

        if self.lvl_idx == 1 and self.t % 40 == 0:
            self.bg_particles.append(Particle(
                x=random.randint(0, SCREEN_W), y=random.randint(0, 10),
                vx=random.uniform(-0.1, 0.1), vy=random.uniform(0.4, 0.9),
                col=random.choice([6, 7, 12]), life=random.randint(60, 160),
                kind="ice_drip"))
        self.bg_particles = [p for p in self.bg_particles if p.is_alive() or p.life == 9999]

        if self.lvl_idx == 3:
            self.rainbow_phase = (self.rainbow_phase + 1) % 360

        # Blitz-Update Geisterwelt
        if self.lvl_idx == 4:
            self.lightning_timer -= 1
            if self.lightning_active > 0:
                self.lightning_active -= 1
            if self.lightning_timer <= 0:
                self.lightning_timer = random.randint(80, 220)
                self.lightning_x = random.randint(20, SCREEN_W - 20)
                self.lightning_active = 6
                # Neue Blitz-Segmente generieren
                lx = self.lightning_x; ly = 14
                self.lightning_segs = []
                for _ in range(7):
                    nx = lx + random.randint(-8, 8)
                    ny = ly + random.randint(12, 22)
                    self.lightning_segs.append((lx, ly, nx, ny))
                    lx = nx; ly = ny

        new_fx = [p for p in self.fx_particles if p.is_alive()]
        for p in new_fx:
            p.update()
        self.fx_particles = new_fx

        for pl in self.plats:
            pl.update(self.t)
        for e in self.enemies:
            if e.alive:
                e.update(self.px, self.py)
                if abs(self.px - e.x) < 9 and abs(self.py - e.y) < 9:
                    self._hurt()
        if self.t % 180 == 0:
            self.wind = random.uniform(-0.9, 1.2) if random.random() > 0.6 else 0

        for it in self.items:
            if it.alive:
                it.update()
                if abs(self.px + 4 - it.x) < 10 and abs(self.py + 4 - it.screen_y()) < 10:
                    it.alive = False
                    pts = {"nut": 100, "gem": 250, "star": 500}
                    self.score += pts.get(it.kind, 100)
                    pyxel.play(1, 1)
                    self._burst(it.x - self.cam_x, it.screen_y(), it.kind)

        for pl in self.plats:
            if pl.p_type == 3:
                if (self.px + 7 > pl.x and self.px < pl.x + pl.w and
                        self.py + 8 >= pl.y and self.py + 8 <= pl.y + 10):
                    self._hurt()

        self._update_player()
        if abs(self.vx) > 0.3:
            if self.t % 8 == 0:
                self.anim_frame = (self.anim_frame + 1) % 4
        else:
            self.anim_frame = 0

    def _hurt(self):
        if self.hurt_timer > 0:
            return
        self.lives -= 1
        self.hurt_timer = 60
        pyxel.play(2, 2)
        self._burst(self.px - self.cam_x + 4, self.py + 4, "hurt")
        if self.lives <= 0:
            self.state = "GAMEOVER"

    def _burst(self, x, y, kind="nut"):
        cols = {"nut": [9, 10, 4], "gem": [12, 7, 6], "star": [10, 9, 7], "hurt": [8, 2, 3]}
        c_list = cols.get(kind, [7, 13, 6])
        for _ in range(18):
            a = random.uniform(0, math.pi * 2)
            sp = random.uniform(0.5, 3.0)
            self.fx_particles.append(Particle(
                x=x, y=y,
                vx=math.cos(a) * sp, vy=math.sin(a) * sp - 1,
                col=random.choice(c_list),
                life=random.randint(20, 40), kind="spark"))

    def _update_player(self):
        if self.hurt_timer > 0: self.hurt_timer -= 1
        if self.dash_cd > 0: self.dash_cd -= 1
        if self.dash_timer > 0:
            self.dash_timer -= 1
            return
        if self.lock_timer > 0:
            self.lock_timer -= 1
        else:
            if pyxel.btn(pyxel.KEY_A) or pyxel.btn(pyxel.KEY_LEFT):
                self.vx = -WALK_SPEED; self.facing = -1
            elif pyxel.btn(pyxel.KEY_D) or pyxel.btn(pyxel.KEY_RIGHT):
                self.vx = WALK_SPEED; self.facing = 1
            else:
                self.vx *= 0.75

        dash_pressed = False
        try:
            if pyxel.btnp(pyxel.KEY_LSHIFT): dash_pressed = True
        except Exception:
            pass
        if pyxel.btnp(pyxel.KEY_Z): dash_pressed = True
        if dash_pressed and self.dash_cd == 0:
            self.vx = self.facing * 6
            self.vy = 0
            self.dash_timer = 8
            self.dash_cd = 40
            self._burst(self.px - self.cam_x + 4, self.py + 4, "gem")
            return

        self.vx += self.wind * 0.04
        on_ground = self._check_floor()
        at_ceiling = self._check_ceiling()
        wall = self._get_wall()

        if on_ground: self.coyote = COYOTE_TIME
        else: self.coyote = max(0, self.coyote - 1)

        jump_pressed = (pyxel.btnp(pyxel.KEY_SPACE) or
                        pyxel.btnp(pyxel.KEY_W) or
                        pyxel.btnp(pyxel.KEY_UP))
        if jump_pressed: self.jump_buffer = JUMP_BUFFER
        else: self.jump_buffer = max(0, self.jump_buffer - 1)

        self.on_wall = False
        self.on_ceil = False
        climb_held = pyxel.btn(pyxel.KEY_W) or pyxel.btn(pyxel.KEY_UP)

        if wall and not on_ground:
            self.on_wall = True
            if climb_held and self.stamina > 0:
                self.vy = -1.2 if wall.p_type == 1 else -0.5
                self.stamina -= 0.8
            else:
                self.vy = min(self.vy + 0.1, 1.0)
            if self.jump_buffer > 0:
                pyxel.play(0, 0)
                self.vy = WALL_JUMP_Y
                self.vx = -self.facing * WALL_JUMP_X
                self.lock_timer = 12
                self.stamina -= 5
                self.facing *= -1
                self.jump_buffer = 0
                self._dust_puff()
        elif at_ceiling and climb_held and self.stamina > 0:
            self.on_ceil = True
            self.vy = 0
            self.stamina -= 0.6
            if self.jump_buffer > 0:
                self.vy = 1.5
                self.jump_buffer = 0
        else:
            self.vy += GRAVITY
            if on_ground:
                self.stamina = min(STAMINA_MAX, self.stamina + 1.5)
                if self.jump_buffer > 0:
                    pyxel.play(0, 0)
                    self.vy = JUMP_PWR
                    self.jump_buffer = 0
                    self._dust_puff()
            elif self.coyote > 0 and self.jump_buffer > 0:
                pyxel.play(0, 0)
                self.vy = JUMP_PWR
                self.coyote = 0
                self.jump_buffer = 0
                self._dust_puff()

        self.px += self.vx
        self.py += self.vy
        target_cam = self.px - SCREEN_W * 0.35
        self.cam_x += (target_cam - self.cam_x) * 0.12
        if self.cam_x < 0: self.cam_x = 0

        if self.py > SCREEN_H + 30:
            self._hurt()
            self.py = 140
            self.vy = 0
        if self.px > self.goal_x:
            self.score += self.lives * 500
            pyxel.play(3, 3)
            self.state = "WIN"

    def _dust_puff(self):
        for _ in range(7):
            a = random.uniform(math.pi, math.pi * 2)
            sp = random.uniform(0.3, 1.5)
            self.fx_particles.append(Particle(
                x=self.px - self.cam_x + 4, y=self.py + 8,
                vx=math.cos(a) * sp, vy=math.sin(a) * sp,
                col=7, life=22, kind="spark"))

    def _check_floor(self):
        for p in self.plats:
            if p.p_type in (0, 3, 4):
                if self.px + 7 > p.x and self.px + 1 < p.x + p.w:
                    if self.py + 8 >= p.y and self.py + 8 <= p.y + 7 and self.vy >= 0:
                        self.py = p.y - 8
                        self.vy = 0
                        return True
        return False

    def _check_ceiling(self):
        for p in self.plats:
            if p.p_type in (0, 4):
                if self.px + 7 > p.x and self.px + 1 < p.x + p.w:
                    if self.py <= p.y + p.h and self.py >= p.y + p.h - 5 and self.vy <= 0:
                        self.py = p.y + p.h
                        self.vy = 0
                        return True
        return False

    def _get_wall(self):
        test_x = self.px + 7 if self.facing == 1 else self.px
        for p in self.plats:
            if p.p_type in (1, 2):
                if test_x > p.x and test_x < p.x + p.w:
                    if self.py + 7 > p.y and self.py < p.y + p.h:
                        return p
        return None

    # ═══════════════════════════════════════
    #               DRAWING
    # ═══════════════════════════════════════

    def draw(self):
        if self.state == "TITLE":
            self._draw_title()
        elif self.state == "PLAY":
            self._draw_play()
        elif self.state == "WIN":
            self._draw_play()
            won_all = self.lvl_idx >= 5
            self._draw_overlay("NUSS GEFUNDEN!", "Weiter: SPACE" if not won_all else "ENDE! SPACE", 10)
        elif self.state == "GAMEOVER":
            self._draw_play()
            self._draw_overlay("SPIEL VORBEI", "Neu: SPACE", 8)
        elif self.state == "LOSE":
            self._draw_play()
            self._draw_overlay("ABGESTUERZT!", "Nochmal: SPACE", 8)

    # ─── TITLE ───

    def _draw_title(self):
        for row in range(SCREEN_H):
            if row < 70:   c = 1
            elif row < 120: c = 5
            elif row < 160: c = 2
            else:           c = 3
            pyxel.line(0, row, SCREEN_W, row, c)
        for i in range(24):
            sx = (i * 41 + 7) % SCREEN_W
            sy = (i * 19 + 5) % 70
            if (self.title_t // 18 + i) % 3 != 0:
                pyxel.pset(sx, sy, 7)
        for col, h, factor in [(2, 35, 0.03), (5, 55, 0.08), (3, 40, 0.15)]:
            offset = int(self.title_t * factor * 0.4)
            for i in range(5):
                mx = (i * 110 - offset) % (SCREEN_W + 110) - 20
                pyxel.tri(mx, SCREEN_H, mx + 55, SCREEN_H - h, mx + 110, SCREEN_H, col)
        for p in self.bg_particles:
            pyxel.pset(int(p.x), int(p.y), p.col)
        lx = SCREEN_W // 2 - 70
        ly = 28
        pyxel.rect(lx - 5, ly - 5, 144, 30, 0)
        pyxel.rectb(lx - 5, ly - 5, 144, 30, 9)
        pyxel.rectb(lx - 4, ly - 4, 142, 28, 5)
        pyxel.text(lx + 6, ly + 9, "NUSS-MISSION DELUXE", 0)
        pyxel.text(lx + 5, ly + 8, "NUSS-MISSION DELUXE", 2)
        pyxel.text(lx + 4, ly + 7, "NUSS-MISSION DELUXE", 10)
        pyxel.text(lx + 4, ly + 6, "NUSS-MISSION", 9)
        sq_x = SCREEN_W // 2 - 4 + int(math.sin(self.title_t * 0.05) * 22)
        self._draw_squirrel_at(sq_x, 74, 1, int(self.title_t * 0.3) % 4)
        if (self.title_t // 22) % 2 == 0:
            pyxel.rect(SCREEN_W // 2 - 44, 106, 88, 10, 0)
            pyxel.text(SCREEN_W // 2 - 40, 108, "SPACE zum Starten", 7)
        pyxel.rect(SCREEN_W // 2 - 26, 120, 52, 10, 5)
        pyxel.rectb(SCREEN_W // 2 - 26, 120, 52, 10, 9)
        pyxel.text(SCREEN_W // 2 - 22, 122, "6 WELTEN!", 10)
        pyxel.rect(0, SCREEN_H - 20, SCREEN_W, 20, 0)
        pyxel.line(0, SCREEN_H - 20, SCREEN_W, SCREEN_H - 20, 5)
        pyxel.text(4, SCREEN_H - 16, "A/D bewegen  W klettern  SPACE springen  Z Dash", 13)
        if self.hi_score > 0:
            pyxel.text(4, 4, "BESTPUNKTZAHL: " + str(self.hi_score), 9)

    # ─── MAIN PLAY DRAW ───

    def _draw_play(self):
        idx = self.lvl_idx
        if   idx == 0: self._draw_biome_forest()
        elif idx == 1: self._draw_biome_ice()
        elif idx == 2: self._draw_biome_lava()
        elif idx == 3: self._draw_biome_cloud()
        elif idx == 4: self._draw_biome_ghost()
        else:          self._draw_biome_inferno()

        for p in self.bg_particles:
            if p.kind == "ice_drip":
                px2 = int(p.x); py2 = int(p.y)
                if 0 <= py2 < SCREEN_H:
                    pyxel.pset(px2, py2, p.col)
                    if py2 > 1: pyxel.pset(px2, py2 - 1, 1 if p.col == 12 else 6)
                    if py2 > SCREEN_H - 30 and p.vy > 1.0:
                        pyxel.pset(px2 - 1, py2, 6)
                        pyxel.pset(px2 + 1, py2, 6)
            elif p.kind == "cloud_wisp":
                px2 = int(p.x); py2 = int(p.y)
                pyxel.pset(px2, py2, p.col)
                pyxel.pset(px2 + 1, py2, 13 if p.col == 7 else p.col)
                pyxel.pset(px2 - 1, py2, 6)
            elif p.kind == "rain":
                px2 = int(p.x); py2 = int(p.y)
                pyxel.line(px2, py2, px2 - 1, py2 - 3, p.col)
            elif p.kind == "aurora":
                px2 = int(p.x); py2 = int(p.y)
                pyxel.pset(px2, py2, p.col)
                pyxel.pset(px2 + 1, py2, 6 if p.col == 12 else 12)
            elif p.kind == "firefly":
                px2 = int(p.x); py2 = int(p.y)
                phase = (self.t + int(p.x * 7 + p.y * 3)) % 40
                if phase < 20:
                    pyxel.pset(px2, py2, p.col)
                    if phase < 8:
                        pyxel.pset(px2 + 1, py2, 7)
                        pyxel.pset(px2 - 1, py2, 7)
            elif p.kind == "spore":
                px2 = int(p.x); py2 = int(p.y)
                pyxel.pset(px2, py2, p.col)
            elif p.kind == "ghost_wisp":
                px2 = int(p.x); py2 = int(p.y)
                alpha = (self.t + int(p.x * 3)) % 30
                if alpha < 20:
                    pyxel.pset(px2, py2, p.col)
                    if alpha < 10:
                        pyxel.pset(px2 + 1, py2, 13)
            else:
                pyxel.pset(int(p.x), int(p.y), p.col)

        for pl in self.plats:
            self._draw_platform(pl)

        self._draw_goal()
        self._draw_items()
        self._draw_enemies()

        for p in self.fx_particles:
            alpha = p.life / p.max_life if p.max_life > 0 else 0
            if alpha > 0.5:   pyxel.pset(int(p.x), int(p.y), p.col)
            elif alpha > 0.2: pyxel.pset(int(p.x), int(p.y), 13)

        inv = self.hurt_timer > 0 and (self.t // 4) % 2 == 0
        if not inv:
            self._draw_squirrel_at(
                int(self.px - self.cam_x), int(self.py),
                self.facing, self.anim_frame, self.on_wall, self.on_ceil)

        self._draw_hud()

    # ═══════════════════════════════════════
    #       BIOME BACKGROUNDS  (verbessert)
    # ═══════════════════════════════════════

    def _draw_biome_forest(self):
        """Herbst-Wald v4: Sonnenstrahlen, detaillierte Bäume, Pilze, Moos, Nebelschichten."""
        # Hintergrund-Farbverlauf
        for row in range(SCREEN_H):
            if row < 14:    c = 0
            elif row < 35:  c = 2
            elif row < 65:  c = 9
            elif row < 100: c = 10
            elif row < 135: c = 4
            elif row < 158: c = 3
            else:           c = 11
            pyxel.line(0, row, SCREEN_W, row, c)

        # NEU: Sonnenstrahlen (diagonale helle Linien von oben links)
        off_ray = int(self.cam_x * 0.02)
        for i in range(5):
            rx = (i * 55 + 10 - off_ray) % (SCREEN_W + 55) - 10
            for j in range(0, 80, 3):
                bx = rx + j // 2
                by = 14 + j
                if 0 <= bx < SCREEN_W:
                    c = 9 if j % 6 == 0 else 10
                    pyxel.pset(bx, by, c)

        # Weit entfernte Bergsilhouetten
        off_bg = int(self.cam_x * 0.03)
        for i in range(4):
            mx = (i * 110 - off_bg) % (SCREEN_W + 110) - 20
            mh = 45 + (i * 23) % 30
            pyxel.tri(mx, SCREEN_H, mx + 65, SCREEN_H - mh, mx + 130, SCREEN_H, 2)
            pyxel.tri(mx + 20, SCREEN_H, mx + 65, SCREEN_H - mh, mx + 110, SCREEN_H, 9)

        # Hintere Bäume (Schicht 1, klein)
        off1 = int(self.cam_x * 0.07)
        for i in range(7):
            tx = (i * 90 - off1) % (SCREEN_W + 90) - 10
            th = 28 + (i * 13) % 20
            tw = 9 + (i * 4) % 6
            # Stamm
            pyxel.rect(tx + tw // 2 - 1, SCREEN_H - 20, 3, 20, 0)
            # Baumkrone (3 Dreiecksschichten)
            for layer in range(3):
                ly2 = SCREEN_H - th + layer * 8
                lw = tw - layer * 1
                pyxel.tri(tx + tw // 2, ly2 - 10, tx, ly2 + 6, tx + tw, ly2 + 6, 0)
                pyxel.line(tx + tw // 2, ly2 - 10, tx, ly2 + 6, 2)
                # Herbstfarb-Highlights
                if i % 3 == 0:
                    pyxel.pset(tx + tw // 2 - 1, ly2 - 5, 9)
                    pyxel.pset(tx + tw // 2 + 2, ly2 - 2, 10)

        # Mittlere Bäume mit Herbstfarben (Schicht 2)
        off2 = int(self.cam_x * 0.14)
        for i in range(6):
            tx = (i * 105 + 35 - off2) % (SCREEN_W + 105) - 15
            th = 42 + (i * 17) % 28
            tw = 16 + (i * 5) % 10
            # Stamm mit Rinde
            pyxel.rect(tx + tw // 2 - 2, SCREEN_H - 28, 5, 28, 4)
            pyxel.rect(tx + tw // 2 - 1, SCREEN_H - 28, 1, 28, 3)
            # Ast links + rechts
            pyxel.line(tx + tw // 2, SCREEN_H - th + 10, tx + tw // 2 - 8, SCREEN_H - th + 4, 4)
            pyxel.line(tx + tw // 2, SCREEN_H - th + 12, tx + tw // 2 + 7, SCREEN_H - th + 6, 4)
            # Baumkrone Hauptdreieck
            for layer in range(4):
                ly2 = SCREEN_H - th + layer * 9
                lw = tw + 4 - layer * 2
                c_tree = [3, 9, 10, 4][i % 4]
                pyxel.tri(tx + tw // 2, ly2 - 14, tx - 2, ly2 + 8, tx + tw + 2, ly2 + 8, c_tree)
                # Rand (dunklere Farbe)
                pyxel.line(tx + tw // 2, ly2 - 14, tx - 2, ly2 + 8, 0)
                if layer == 0:
                    pyxel.pset(tx + tw // 2, ly2 - 14, 9)

        # Vordere Büsche
        off3 = int(self.cam_x * 0.28)
        for i in range(9):
            bx = (i * 68 - off3) % (SCREEN_W + 68) - 8
            bh = 14 + (i * 7) % 10
            bc = [3, 9, 10, 4, 11][i % 5]
            pyxel.tri(bx, SCREEN_H, bx + 20, SCREEN_H - bh, bx + 40, SCREEN_H, bc)
            pyxel.tri(bx + 8, SCREEN_H, bx + 24, SCREEN_H - bh - 4, bx + 40, SCREEN_H, 0 if bc == 3 else bc - 1 if bc > 0 else 0)
            # Pilze neben Büschen
            if i % 3 == 1:
                px2 = bx + 45
                pyxel.rect(px2, SCREEN_H - 7, 3, 7, 4)
                pyxel.circ(px2 + 1, SCREEN_H - 8, 4, 8)
                pyxel.pset(px2, SCREEN_H - 10, 7)
                pyxel.pset(px2 + 2, SCREEN_H - 9, 7)

        # Bodenstreifen (Gras + Moos)
        floor_y = 158
        pyxel.rect(0, floor_y, SCREEN_W, SCREEN_H - floor_y, 11)
        pyxel.rect(0, floor_y, SCREEN_W, 3, 3)
        pyxel.rect(0, floor_y + 1, SCREEN_W, 1, 11)
        # Grashalme
        off_grass = int(self.cam_x * 0.40)
        for i in range(30):
            gx = (i * 18 + 3 - off_grass) % SCREEN_W
            gh = 3 + (i * 3) % 4
            gc = 3 if i % 3 != 0 else 11
            pyxel.line(gx, floor_y, gx + 1, floor_y - gh, gc)
        # Moos-Flecken
        for i in range(6):
            mx = (i * 55 + 12 - off_grass // 2) % SCREEN_W
            pyxel.rect(mx, floor_y + 2, 8, 2, 11)
            pyxel.pset(mx + 4, floor_y + 1, 3)

        # NEU: Nebel am Boden (horizontale Streifen)
        off_fog = int(self.cam_x * 0.05)
        for i in range(8):
            fx = (i * 40 - off_fog) % (SCREEN_W + 40) - 10
            fy = floor_y - 6
            fw = 25 + i * 5 % 15
            c = 13 if i % 2 == 0 else 7
            pyxel.rect(fx, fy, fw, 3, c)

    def _draw_biome_ice(self):
        """Eishöhle v4: Aurora, dichter Stalaktiten-Wald, Eisadern, Kristalle, Bodenreflexion."""
        for row in range(SCREEN_H):
            if row < 14:    c = 0
            elif row < 30:  c = 1
            elif row < 65:  c = 5
            elif row < 105: c = 1
            elif row < 145: c = 5
            elif row < 165: c = 6
            else:           c = 12
            pyxel.line(0, row, SCREEN_W, row, c)

        # Aurora-Schimmer-Bänder
        for strip in self.aurora_strips:
            sx = int((strip["x"] - self.cam_x * 0.02) % SCREEN_W)
            sy = strip["y"] + int(math.sin(self.t * 0.03 + strip["phase"]) * 4)
            sw = strip["w"]
            alpha = (math.sin(self.t * 0.04 + strip["phase"]) + 1) * 0.5
            if alpha > 0.3:
                pyxel.rect(sx, sy, sw, 2, strip["col"])
                pyxel.rect(sx + 2, sy + 2, sw - 4, 1, 1)

        # Hintere Eissäulen
        off_bg = int(self.cam_x * 0.04)
        for i in range(14):
            bx = (i * 70 - off_bg) % (SCREEN_W + 70) - 10
            bh = 20 + (i * 19) % 35
            pyxel.rect(bx + 12, SCREEN_H - bh, 14, bh, 1)
            pyxel.rect(bx + 13, SCREEN_H - bh, 2, bh, 5)
            pyxel.line(bx + 12, SCREEN_H - bh, bx + 19, SCREEN_H - bh - 6, 6)

        # Mittlere Stalagmiten
        off_mid = int(self.cam_x * 0.11)
        for i in range(9):
            bx = (i * 90 + 40 - off_mid) % (SCREEN_W + 90) - 15
            bh = 35 + (i * 23) % 45
            by = SCREEN_H - bh
            pyxel.tri(bx + 8, SCREEN_H, bx + 18, by, bx + 28, SCREEN_H, 5)
            pyxel.line(bx + 8, SCREEN_H, bx + 18, by, 6)
            pyxel.line(bx + 12, SCREEN_H - 6, bx + 17, by + 4, 12)
            pyxel.pset(bx + 18, by, 7)

        # Stalaktiten (Decke) – große Reihe
        off_stl = int(self.cam_x * 0.20)
        for i in range(11):
            sx = (i * 78 - off_stl) % (SCREEN_W + 78) - 8
            sh = 18 + (i * 21) % 38
            sw = 5 + (i * 7) % 9
            sy0 = 14
            pyxel.tri(sx, sy0, sx + sw, sy0, sx + sw // 2, sy0 + sh, 1)
            pyxel.line(sx, sy0, sx + sw // 2, sy0 + sh, 6)
            pyxel.line(sx + sw, sy0, sx + sw // 2, sy0 + sh, 5)
            pyxel.pset(sx + sw // 2, sy0 + sh, 7)
            if sw > 6:
                pyxel.line(sx + 2, sy0 + 3, sx + sw // 2 - 1, sy0 + sh - 4, 12)
            drip_phase = (self.t + i * 22) % 90
            if drip_phase < 45:
                dy = sy0 + sh + drip_phase // 4
                if dy < SCREEN_H:
                    pyxel.pset(sx + sw // 2, dy, 12)
                    if dy + 1 < SCREEN_H:
                        pyxel.pset(sx + sw // 2, dy + 1, 6)

        # Zweite, kleinere Stalaktiten-Reihe
        for i in range(15):
            sx = (i * 58 + 28 - off_stl) % (SCREEN_W + 58) - 5
            sh = 7 + (i * 9) % 14
            sw = 3 + (i * 4) % 4
            sy0 = 14
            pyxel.tri(sx, sy0, sx + sw, sy0, sx + sw // 2, sy0 + sh, 5)
            pyxel.line(sx, sy0, sx + sw // 2, sy0 + sh, 6)
            pyxel.pset(sx + sw // 2, sy0 + sh, 12)

        # Dritte Mini-Stalaktiten-Reihe
        for i in range(20):
            sx = (i * 42 + 14 - off_stl // 2) % (SCREEN_W + 42) - 4
            sh = 3 + (i * 5) % 7
            sy0 = 14
            pyxel.line(sx, sy0, sx, sy0 + sh, 1)
            pyxel.pset(sx, sy0 + sh, 5)

        # NEU: Große Eiskristall-Formationen (Stern)
        off_xtal = int(self.cam_x * 0.09)
        for i in range(6):
            gx = (i * 110 + 60 - off_xtal) % (SCREEN_W + 110) - 10
            gy = 40 + (i * 31) % 80
            size = 4 + (i * 2) % 5
            pulse = (self.t // 6 + i * 7) % 3
            c = [7, 12, 6][pulse]
            pyxel.line(gx - size, gy, gx + size, gy, c)
            pyxel.line(gx, gy - size, gx, gy + size, c)
            pyxel.line(gx - size + 1, gy - size + 1, gx + size - 1, gy + size - 1, 5)
            pyxel.line(gx + size - 1, gy - size + 1, gx - size + 1, gy + size - 1, 5)
            pyxel.pset(gx, gy, 7)

        # Leuchtende Eiskristall-Punkte (pulsierend)
        off_glow = int(self.cam_x * 0.14)
        for i in range(16):
            gx = (i * 65 + 12 - off_glow) % (SCREEN_W + 65) - 5
            gy = 22 + (i * 27) % 130
            phase = (self.t * 2 + i * 33) % 120
            c = 7 if phase < 50 else (12 if phase < 85 else 6)
            pyxel.pset(gx, gy, c)
            if c == 7:
                pyxel.pset(gx + 1, gy, 12)
                pyxel.pset(gx - 1, gy, 12)
                pyxel.pset(gx, gy + 1, 12)
                pyxel.pset(gx, gy - 1, 12)

        # Eisadern
        off_vein = int(self.cam_x * 0.17)
        for i in range(6):
            vx = (i * 100 + 18 - off_vein) % (SCREEN_W + 100) - 10
            py2 = 20
            for seg in range(7):
                ny = py2 + 14 + seg * 5 % 8
                nx = vx + math.sin((self.t * 0.005 + i + seg) * 2.2) * 2.5
                c = 12 if (self.t // 28 + i + seg) % 3 == 0 else 6
                pyxel.line(int(nx), py2, int(nx), ny, c)
                py2 = ny
                if py2 > SCREEN_H - 20: break

        # Horizontale Eis-Schichtlinien
        off_layer = int(self.cam_x * 0.07)
        for i in range(4):
            ly2 = 55 + i * 28
            for x2 in range(0, SCREEN_W, 3):
                noise = int(math.sin((x2 + off_layer) * 0.08 + i * 1.5) * 2)
                c = 12 if (x2 // 12 + i) % 4 == 0 else 6
                pyxel.pset(x2, ly2 + noise, c)

        # Bodenreflexion
        floor_y = 163
        pyxel.rect(0, floor_y, SCREEN_W, 4, 6)
        pyxel.rect(0, floor_y + 1, SCREEN_W, 1, 12)
        off_ref = int(self.cam_x * 0.32)
        for i in range(22):
            rx = (i * 28 - off_ref) % SCREEN_W
            rw = 3 + i % 6
            c = 7 if (self.t * 3 + i * 17) % 38 < 8 else 6
            pyxel.rect(rx, floor_y + 2, rw, 1, c)

        # Eisboden-Risse
        off_crack = int(self.cam_x * 0.35)
        for i in range(10):
            cx = (i * 35 + 8 - off_crack) % SCREEN_W
            pyxel.line(cx, floor_y + 2, cx + 3, floor_y + 3, 1)
            pyxel.line(cx + 3, floor_y + 3, cx + 6, floor_y + 2, 5)

    def _draw_biome_lava(self):
        """Lava-Tempel v4: Glühende Wände, Lavafälle, Magma-Blasen, Hitze-Wellen."""
        for row in range(SCREEN_H):
            if row < 14:    c = 0
            elif row < 40:  c = 0
            elif row < 75:  c = 2
            elif row < 115: c = 8
            elif row < 150: c = 9
            else:           c = 2
            pyxel.line(0, row, SCREEN_W, row, c)

        # NEU: Glühender Schein von der Lava oben
        for row in range(150, SCREEN_H):
            if (row // 2 + self.t // 5) % 3 == 0:
                pyxel.line(0, row, SCREEN_W, row, 9)

        # Hintere Fels-Säulen
        off1 = int(self.cam_x * 0.05)
        for i in range(5):
            rx = (i * 130 - off1) % (SCREEN_W + 130) - 20
            rh = 50 + (i * 19) % 40
            rw = 20 + (i * 11) % 15
            pyxel.rect(rx, SCREEN_H - rh, rw, rh, 0)
            # Risse in Fels
            for z in range(rw // 5):
                pyxel.rect(rx + z * 5, SCREEN_H - rh - 5, 3, 5, 0)
            pyxel.line(rx, SCREEN_H - rh, rx + rw - 1, SCREEN_H - rh, 2)
            # Glühende Risse
            gc = 8 if (self.t // 8 + i) % 3 != 0 else 9
            pyxel.pset(rx + rw // 2, SCREEN_H - rh // 2, gc)
            pyxel.pset(rx + rw // 3, SCREEN_H - rh // 3, gc)

        # NEU: Lavafälle von Fels-Simsen
        off_fall = int(self.cam_x * 0.08)
        for i in range(4):
            fx = (i * 150 + 60 - off_fall) % (SCREEN_W + 150) - 10
            for seg in range(8):
                fy = 80 + seg * 10
                fw = 4 - seg // 3
                fc = 9 if (self.t // 3 + seg + i * 5) % 3 == 0 else 8
                if fw > 0:
                    pyxel.rect(fx, fy, fw, 8, fc)
                    pyxel.pset(fx + fw // 2, fy, 10)

        # Mittlere Lavabecken
        off2 = int(self.cam_x * 0.10)
        for i in range(7):
            lx = (i * 80 - off2) % (SCREEN_W + 80) - 10
            lava_y = 150 + int(math.sin((self.t * 0.04) + i * 1.1) * 4)
            pyxel.rect(lx, lava_y, 60, SCREEN_H - lava_y, 2)
            pyxel.rect(lx, lava_y, 60, 3, 9)
            pyxel.rect(lx, lava_y + 1, 60, 1, 10)
            # Wellen-Muster auf Lava
            for wx in range(0, 60, 6):
                wc = 10 if (self.t // 4 + wx + i * 3) % 5 == 0 else 9
                pyxel.pset(lx + wx, lava_y + 2, wc)

        # Vordere Fels-Zacken
        off3 = int(self.cam_x * 0.22)
        for i in range(6):
            cx = (i * 100 + 25 - off3) % (SCREEN_W + 100) - 10
            ch = 55 + (i * 13) % 30
            pyxel.rect(cx, SCREEN_H - ch, 10, ch, 2)
            pyxel.line(cx, SCREEN_H - ch, cx + 9, SCREEN_H - ch, 8)
            flame_h = 5 + int(math.sin(self.t * 0.1 + i) * 3)
            # Flammen-Schichten
            pyxel.tri(cx + 2, SCREEN_H - ch, cx + 5, SCREEN_H - ch - flame_h, cx + 8, SCREEN_H - ch, 9)
            pyxel.tri(cx + 3, SCREEN_H - ch, cx + 5, SCREEN_H - ch - flame_h + 2, cx + 7, SCREEN_H - ch, 10)
            pyxel.pset(cx + 5, SCREEN_H - ch - flame_h, 7)

        # NEU: Hitze-Wellen (Luftverzerrung, animiert)
        off_heat = int(self.cam_x * 0.15)
        for i in range(12):
            hx = (i * 30 + 8 - off_heat) % SCREEN_W
            hy = 135 + int(math.sin(self.t * 0.07 + i * 0.8) * 5)
            hw = 8 + i % 5
            pyxel.line(hx, hy, hx + hw, hy, 2)

        # Animierte Lava-Blasen
        for bx, phase in self.lava_bubbles:
            bub_y = 155 + int(math.sin(self.t * 0.05 + phase) * 4)
            bub_x = int((bx - self.cam_x * 0.15) % SCREEN_W)
            pyxel.circ(bub_x, bub_y, 2, 10)
            pyxel.pset(bub_x, bub_y - 1, 7)
            # Blasen-Pop wenn oben
            if int(math.sin(self.t * 0.05 + phase) * 4) < -3:
                pyxel.pset(bub_x - 2, bub_y - 2, 9)
                pyxel.pset(bub_x + 2, bub_y - 2, 9)

        lava_base = 165
        for row in range(lava_base, SCREEN_H):
            c = 9 if (row + self.t // 4) % 6 < 3 else 8
            pyxel.line(0, row, SCREEN_W, row, c)
        pyxel.rect(0, lava_base, SCREEN_W, 2, 10)

        # NEU: Tempel-Säulen-Ornamente oben
        off_col = int(self.cam_x * 0.25)
        for i in range(5):
            px2 = (i * 70 - off_col) % (SCREEN_W + 70)
            pyxel.rect(px2, 14, 6, 30, 0)
            pyxel.rect(px2, 14, 6, 3, 2)
            pyxel.rect(px2, 41, 6, 3, 2)
            pyxel.pset(px2 + 3, 20, 8)
            pyxel.pset(px2 + 3, 28, 8)

    def _draw_biome_cloud(self):
        """Wolkengipfel v4: Regenbogen, Sonnenstrahlen, Schneegipfel, Vögel, Wolken-Schichten."""
        # Himmel mit Farbverlauf
        for row in range(SCREEN_H):
            if row < 14:    c = 1
            elif row < 40:  c = 6
            elif row < 80:  c = 12
            elif row < 120: c = 13
            elif row < 148: c = 7
            else:           c = 6
            pyxel.line(0, row, SCREEN_W, row, c)

        # NEU: Sonne oben rechts
        sun_x = 210 + int(math.sin(self.t * 0.005) * 8)
        sun_y = 30
        pyxel.circ(sun_x, sun_y, 10, 10)
        pyxel.circ(sun_x, sun_y, 8, 9)
        pyxel.circ(sun_x, sun_y, 5, 7)
        # Sonnenstrahlen
        for a in range(0, 360, 45):
            rad = math.radians(a)
            sx2 = sun_x + int(math.cos(rad) * 13)
            sy2 = sun_y + int(math.sin(rad) * 13)
            pyxel.pset(sx2, sy2, 10)
            pyxel.pset(sx2 + int(math.cos(rad)), sy2 + int(math.sin(rad)), 9)

        # NEU: Regenbogen-Bogen
        rb_cx = 100; rb_cy = 120
        rb_cols = [8, 9, 10, 11, 12, 6, 1]
        for ri, rc in enumerate(rb_cols):
            rad = 50 + ri * 3
            phase = math.radians(self.rainbow_phase * 0.5)
            for a in range(200, 340):
                rx2 = rb_cx + int(math.cos(math.radians(a)) * rad)
                ry2 = rb_cy + int(math.sin(math.radians(a)) * rad)
                if 0 <= rx2 < SCREEN_W and 0 <= ry2 < SCREEN_H:
                    pyxel.pset(rx2, ry2, rc)

        # Hintere Bergsilhouetten (Schneegipfel)
        off_bg = int(self.cam_x * 0.04)
        for i in range(4):
            mx = (i * 140 - off_bg) % (SCREEN_W + 140) - 30
            mh = 70 + (i * 23) % 50
            pyxel.tri(mx, SCREEN_H, mx + 80, SCREEN_H - mh, mx + 160, SCREEN_H, 6)
            # Schneegipfel
            snow_w = 22 + (i * 7) % 18
            pyxel.tri(mx + 80 - snow_w // 2, SCREEN_H - mh + snow_w // 3,
                      mx + 80, SCREEN_H - mh,
                      mx + 80 + snow_w // 2, SCREEN_H - mh + snow_w // 3, 7)
            pyxel.tri(mx + 80 - snow_w // 4, SCREEN_H - mh + snow_w // 6,
                      mx + 80, SCREEN_H - mh,
                      mx + 80 + snow_w // 4, SCREEN_H - mh + snow_w // 6, 13)

        # Hintergrund-Wolken
        off2 = int(self.cam_x * 0.08)
        for i in range(6):
            cx = (i * 110 - off2) % (SCREEN_W + 110) - 20
            cy = 30 + (i * 17) % 55
            cw = 50 + (i * 19) % 40
            ch = 10 + (i * 7) % 14
            pyxel.rect(cx, cy, cw, ch, 7)
            pyxel.circ(cx + 8, cy - 4, 9, 7)
            pyxel.circ(cx + cw - 8, cy - 4, 7, 7)
            pyxel.circ(cx + cw // 2, cy - 7, 11, 7)
            # Schatten-Unterseite
            pyxel.rect(cx + 3, cy + ch - 2, cw - 6, 3, 13)
            # Regentropfen von Wolke
            if i % 2 == 0:
                for d in range(3):
                    dx = cx + 10 + d * 12
                    dy = cy + ch + (self.t // 3 + d * 8) % 20
                    if dy < cy + ch + 20:
                        pyxel.pset(dx, dy, 12)

        # Mittlere große Wolken
        off3 = int(self.cam_x * 0.18)
        for i in range(4):
            cx = (i * 160 + 50 - off3) % (SCREEN_W + 160) - 20
            cy = 95 + (i * 11) % 30
            pyxel.rect(cx, cy, 80, 14, 7)
            pyxel.circ(cx + 12, cy - 6, 11, 7)
            pyxel.circ(cx + 35, cy - 9, 14, 7)
            pyxel.circ(cx + 58, cy - 6, 10, 7)
            pyxel.rect(cx + 5, cy + 12, 70, 4, 13)
            # Innen heller
            pyxel.circ(cx + 35, cy - 5, 8, 13)

        # Vögel (animiert)
        off4 = int(self.cam_x * 0.25)
        for i in range(6):
            bx = (i * 180 + 30 - off4) % (SCREEN_W + 180)
            by = 20 + (i * 11) % 40 + int(math.sin(self.t * 0.04 + i) * 3)
            wing = int(math.sin(self.t * 0.1 + i * 0.7) * 3)
            pyxel.line(bx - 4, by - wing, bx, by, 1)
            pyxel.line(bx, by, bx + 4, by - wing, 1)
            pyxel.pset(bx, by, 0)

        # NEU: Fliegende Insel (Boden-Element)
        off_isl = int(self.cam_x * 0.12)
        for i in range(3):
            ix = (i * 200 + 80 - off_isl) % (SCREEN_W + 200) - 20
            iy = 130 + (i * 17) % 30
            pyxel.rect(ix, iy, 40, 8, 3)
            pyxel.rect(ix + 2, iy, 36, 3, 11)
            pyxel.circ(ix + 10, iy - 4, 5, 7)
            pyxel.circ(ix + 25, iy - 3, 4, 7)

    def _draw_biome_ghost(self):
        """Geistertürme v4: Vollmond, Blitz, Geisterschatten, Grabsteine, Nebel, Fledermäuse."""
        for row in range(SCREEN_H):
            if row < 14:    c = 0
            elif row < 45:  c = 1
            elif row < 90:  c = 5
            elif row < 130: c = 2
            elif row < 160: c = 1
            else:           c = 0
            pyxel.line(0, row, SCREEN_W, row, c)

        # Mond mit Halo
        moon_x = 180 + int(math.sin(self.t * 0.003) * 15)
        moon_y = 32
        for r in range(18, 22, 2):
            pyxel.circb(moon_x, moon_y, r, 1 if r < 20 else 5)
        pyxel.circ(moon_x, moon_y, 12, 7)
        pyxel.circ(moon_x, moon_y, 10, 13)
        pyxel.circ(moon_x + 3, moon_y - 3, 4, 7)
        # Mondkrater
        pyxel.pset(moon_x - 3, moon_y + 2, 13)
        pyxel.pset(moon_x - 4, moon_y + 3, 6)
        pyxel.pset(moon_x + 4, moon_y + 4, 13)
        for r in range(14, 18, 2):
            alpha_col = 6 if r < 16 else 1
            pyxel.circb(moon_x, moon_y, r, alpha_col)

        # NEU: Sterne
        off_star = int(self.cam_x * 0.01)
        for i in range(20):
            sx2 = (i * 37 + 5 + off_star // 2) % SCREEN_W
            sy2 = 15 + (i * 19) % 55
            if (self.t // 20 + i) % 4 != 0:
                pyxel.pset(sx2, sy2, 7)
            else:
                pyxel.pset(sx2, sy2, 13)

        # Blitz-Effekt (aus gespeicherten Segmenten)
        if self.lightning_active > 0:
            flash_col = 7 if self.lightning_active > 3 else 13
            for seg in self.lightning_segs:
                lx1, ly1, lx2, ly2 = seg
                sx2 = int(lx1 - self.cam_x * 0.0)
                nx2 = int(lx2 - self.cam_x * 0.0)
                pyxel.line(sx2, ly1, nx2, ly2, flash_col)
                pyxel.line(sx2 + 1, ly1, nx2 + 1, ly2, 6)
            # Boden-Aufprall
            if len(self.lightning_segs) > 0:
                lx_end = self.lightning_segs[-1][2]
                ly_end = self.lightning_segs[-1][3]
                pyxel.circ(lx_end, ly_end, 3, 7)
                pyxel.circb(lx_end, ly_end, 5, 13)

        # Hintere Geistertürme
        off1 = int(self.cam_x * 0.05)
        for i in range(5):
            tx = (i * 120 - off1) % (SCREEN_W + 120) - 15
            th = 65 + (i * 21) % 50
            tw = 14 + (i * 7) % 10
            # Turm-Körper mit Mauerwerk
            pyxel.rect(tx, SCREEN_H - th, tw, th, 1)
            # Ziegelstreifen
            for brick_y in range(SCREEN_H - th + 4, SCREEN_H, 8):
                pyxel.line(tx, brick_y, tx + tw, brick_y, 5)
            # Turmspitze
            pyxel.tri(tx - 2, SCREEN_H - th, tx + tw // 2, SCREEN_H - th - 22, tx + tw + 2, SCREEN_H - th, 0)
            pyxel.line(tx + tw // 2, SCREEN_H - th - 22, tx + tw // 2, SCREEN_H - th - 28, 5)
            # Leuchtende Fenster (animiert)
            win_col = 9 if (self.t // 25 + i) % 5 != 0 else 0
            win_col2 = 10 if (self.t // 35 + i * 2) % 4 == 0 else win_col
            pyxel.rect(tx + 2, SCREEN_H - th + 12, 3, 4, win_col)
            pyxel.rect(tx + tw - 5, SCREEN_H - th + 12, 3, 4, win_col2)
            pyxel.rect(tx + tw // 2 - 1, SCREEN_H - th + 28, 3, 4, win_col)
            # Efeu
            for eff_y in range(0, th, 6):
                pyxel.pset(tx, SCREEN_H - th + eff_y, 3 if eff_y % 12 == 0 else 11)

        # NEU: Grabsteine
        off_grave = int(self.cam_x * 0.18)
        for i in range(7):
            gx = (i * 80 + 20 - off_grave) % (SCREEN_W + 80) - 10
            gy = SCREEN_H - 24
            pyxel.rect(gx, gy, 10, 12, 5)
            pyxel.circ(gx + 5, gy, 5, 5)
            pyxel.pset(gx + 5, gy - 2, 1)
            pyxel.pset(gx + 3, gy + 3, 1)
            pyxel.pset(gx + 7, gy + 3, 1)

        # Kahle Bäume
        off2 = int(self.cam_x * 0.14)
        for i in range(7):
            bx = (i * 85 + 20 - off2) % (SCREEN_W + 85) - 10
            bh = 40 + (i * 13) % 30
            # Stamm
            pyxel.line(bx + 5, SCREEN_H, bx + 5, SCREEN_H - bh, 0)
            pyxel.line(bx + 6, SCREEN_H, bx + 6, SCREEN_H - bh, 5)
            # Äste mit mehr Details
            pyxel.line(bx + 5, SCREEN_H - bh, bx - 10, SCREEN_H - bh - 12, 0)
            pyxel.line(bx + 5, SCREEN_H - bh, bx + 20, SCREEN_H - bh - 14, 0)
            pyxel.line(bx + 5, SCREEN_H - bh + 10, bx - 6, SCREEN_H - bh - 2, 0)
            pyxel.line(bx + 5, SCREEN_H - bh + 10, bx + 14, SCREEN_H - bh, 0)
            # Kleine Äste
            pyxel.line(bx - 8, SCREEN_H - bh - 9, bx - 12, SCREEN_H - bh - 15, 0)
            pyxel.line(bx + 18, SCREEN_H - bh - 11, bx + 14, SCREEN_H - bh - 17, 0)

        # NEU: Fledermäuse
        off_bat = int(self.cam_x * 0.20)
        for i in range(4):
            bx = (i * 110 + 40 - off_bat) % (SCREEN_W + 110)
            by = 50 + (i * 13) % 45 + int(math.sin(self.t * 0.06 + i) * 6)
            wing = int(math.sin(self.t * 0.12 + i * 1.5) * 4)
            # Fledermaus-Körper
            pyxel.pset(bx, by, 0)
            pyxel.pset(bx + 1, by, 0)
            # Flügel
            pyxel.line(bx - 5, by + wing, bx, by, 0)
            pyxel.line(bx + 1, by, bx + 6, by + wing, 0)
            pyxel.pset(bx - 4, by + wing + 1, 5)
            pyxel.pset(bx + 5, by + wing + 1, 5)

        # NEU: Bodennebel
        off_fog = int(self.cam_x * 0.08)
        for i in range(10):
            fx = (i * 35 + 5 - off_fog) % (SCREEN_W + 35) - 10
            fy = SCREEN_H - 20 + int(math.sin(self.t * 0.03 + i * 0.7) * 3)
            fw = 20 + i * 4 % 15
            fh = 6 + i % 4
            c = 5 if i % 2 == 0 else 1
            pyxel.rect(fx, fy, fw, fh, c)

    def _draw_biome_inferno(self):
        """Inferno-Gipfel v4: Risse, Magma-Geysire, Funkenregen, Rauch, Lava-Seen."""
        for row in range(SCREEN_H):
            if row < 14:    c = 0
            elif row < 35:  c = 0
            elif row < 65:  c = 2
            elif row < 105: c = 8
            elif row < 140: c = 9
            else:           c = 10
            pyxel.line(0, row, SCREEN_W, row, c)

        # NEU: Rauchwolken oben
        off_smoke = int(self.cam_x * 0.03)
        for i in range(6):
            sx = (i * 80 + 20 - off_smoke) % (SCREEN_W + 80) - 10
            sy = 14 + (i * 7) % 25
            sw = 20 + i * 6 % 20
            c = 0 if i % 2 == 0 else 2
            pyxel.rect(sx, sy, sw, 8, c)
            pyxel.circ(sx + 5, sy - 2, 5, c)
            pyxel.circ(sx + sw - 5, sy - 3, 4, c)

        # Hintere Vulkane
        off1 = int(self.cam_x * 0.05)
        for i in range(5):
            rx = (i * 130 - off1) % (SCREEN_W + 130) - 20
            rh = 65 + (i * 17) % 50
            pyxel.tri(rx, SCREEN_H, rx + 75, SCREEN_H - rh, rx + 150, SCREEN_H, 2)
            pyxel.line(rx, SCREEN_H, rx + 75, SCREEN_H - rh, 8)
            pyxel.line(rx + 75, SCREEN_H - rh, rx + 150, SCREEN_H, 9)
            # Krater oben
            pyxel.circ(rx + 75, SCREEN_H - rh, 6, 0)
            pyxel.circ(rx + 75, SCREEN_H - rh, 4, 8)
            pyxel.pset(rx + 75, SCREEN_H - rh, 10)

        # NEU: Boden-Risse mit Glut
        off_crack = int(self.cam_x * 0.30)
        for cx, cy, cd, cl in self.inferno_cracks:
            real_cx = (cx - int(off_crack)) % SCREEN_W
            real_cy = cy
            pyxel.line(real_cx, real_cy, real_cx + cd, real_cy + cl, 0)
            gc = 9 if (self.t // 6 + cx) % 3 != 0 else 10
            pyxel.line(real_cx + 1, real_cy, real_cx + cd + 1, real_cy + cl, gc)

        # Magma-Geysire
        off2 = int(self.cam_x * 0.13)
        for i in range(8):
            mx = (i * 95 + 30 - off2) % (SCREEN_W + 95) - 10
            mag_y = SCREEN_H - 20 + int(math.sin(self.t * 0.06 + i) * 5)
            pyxel.rect(mx, mag_y, 8, SCREEN_H - mag_y, 8)
            pyxel.rect(mx + 1, mag_y, 6, 2, 10)
            pyxel.rect(mx + 2, mag_y + 1, 4, 1, 7)

        # Vordere Geysire
        off3 = int(self.cam_x * 0.22)
        for i in range(5):
            gx = (i * 120 + 50 - off3) % (SCREEN_W + 120) - 10
            geyser_h = 22 + int(math.sin(self.t * 0.07 + i * 1.4) * 18)
            gy = SCREEN_H - geyser_h
            pyxel.tri(gx, SCREEN_H, gx + 8, gy, gx + 16, SCREEN_H, 9)
            pyxel.tri(gx + 3, SCREEN_H, gx + 8, gy + 5, gx + 13, SCREEN_H, 10)
            pyxel.pset(gx + 8, gy, 7)
            # Funken vom Geysir
            for spark in range(4):
                sa = math.radians(270 + spark * 25 - 30)
                sd = 3 + spark * 2
                spx = gx + 8 + int(math.cos(sa) * sd)
                spy = gy - 1 + int(math.sin(sa) * sd)
                sc = 10 if (self.t + spark + i * 3) % 3 == 0 else 9
                if 0 <= spx < SCREEN_W and 0 <= spy < SCREEN_H:
                    pyxel.pset(spx, spy, sc)

        # NEU: Lava-Seen am Boden mit Wellen
        off_lava = int(self.cam_x * 0.18)
        for i in range(4):
            lx = (i * 100 + 15 - off_lava) % (SCREEN_W + 100) - 10
            ly = 155 + int(math.sin(self.t * 0.04 + i * 0.8) * 3)
            lw = 45 + i * 8
            pyxel.rect(lx, ly, lw, 10, 8)
            pyxel.rect(lx, ly, lw, 2, 9)
            for wx in range(0, lw, 5):
                wc = 10 if (self.t // 3 + wx + i * 4) % 4 == 0 else 9
                pyxel.pset(lx + wx, ly + 1, wc)

        for row in range(165, SCREEN_H):
            c = 9 if (row + self.t // 3) % 5 < 2 else 8
            pyxel.line(0, row, SCREEN_W, row, c)
        pyxel.rect(0, 165, SCREEN_W, 2, 10)

    # ─── PLATFORMS ───

    def _draw_platform(self, pl):
        x = int(pl.x - self.cam_x)
        y = int(pl.y)
        w = pl.w
        h = pl.h
        idx = self.lvl_idx

        if pl.p_type == 0:
            if idx == 1:   self._draw_plat_ice(x, y, w, h)
            elif idx == 2: self._draw_plat_lava_ground(x, y, w, h)
            elif idx == 3: self._draw_plat_cloud_ground(x, y, w, h)
            elif idx == 4: self._draw_plat_ghost_ground(x, y, w, h)
            elif idx == 5: self._draw_plat_inferno_ground(x, y, w, h)
            else:          self._draw_plat_forest_ground(x, y, w, h)

        elif pl.p_type == 1:
            if idx == 1:   self._draw_wall_ice(x, y, w, h)
            elif idx == 2: self._draw_wall_lava(x, y, w, h)
            else:          self._draw_wall_bark(x, y, w, h)

        elif pl.p_type == 2:
            if idx == 1:   self._draw_wall_ice(x, y, w, h)
            else:          self._draw_wall_stone(x, y, w, h)

        elif pl.p_type == 3:
            col1 = 8 if (self.t // 6) % 2 == 0 else 9
            col2 = 10 if (self.t // 6) % 2 == 0 else 8
            pyxel.rect(x, y, w, h, col1)
            tip_off = (self.t // 5) % 3
            i = 0
            while i < w:
                tip_x = x + i + tip_off
                pyxel.tri(tip_x, y, tip_x + 4, y, tip_x + 2, y - 5, col2)
                i += 8

        elif pl.p_type == 4:
            if idx == 1:
                pyxel.rect(x, y, w, h, 1)
                pyxel.rect(x, y + h - 3, w, 3, 6)
                pyxel.rect(x, y + h - 1, w, 1, 12)
                i = 0
                while i < w:
                    dh = 2 + (i * 5) % 4
                    pyxel.rect(x + i, y + h, 2, dh, 6)
                    pyxel.pset(x + i + 1, y + h + dh, 12)
                    i += 9
            else:
                pyxel.rect(x, y, w, h, 4)
                pyxel.rect(x, y + h - 3, w, 3, 11)
                i = 0
                while i < w:
                    pyxel.line(x + i, y + h, x + i + 2, y + h + 4, 11)
                    pyxel.line(x + i + 3, y + h, x + i + 3, y + h + 3, 3)
                    i += 7

    def _draw_plat_forest_ground(self, x, y, w, h):
        """Herbst-Waldboden: Erde, Moos, Grashalme, Pilze."""
        pyxel.rect(x, y, w, h, 4)
        pyxel.rect(x, y, w, 3, 3)
        pyxel.rect(x, y + 3, w, 2, 11)
        # Grashalme
        i = 0
        while i < w:
            gh = 2 + (i * 3 + x) % 4
            gc = 3 if i % 3 != 0 else 11
            pyxel.line(x + i, y, x + i, y - gh, gc)
            i += 5
        # Bodenstruktur
        i = 0
        while i < w:
            pyxel.rect(x + i, y + 6, 10, 3, 3)
            pyxel.rect(x + i + 5, y + 10, 10, 3, 3)
            i += 14
        # Pilze auf der Plattform
        if w > 20:
            mp = x + w // 3
            pyxel.rect(mp, y - 5, 3, 5, 4)
            pyxel.circ(mp + 1, y - 6, 4, 8)
            pyxel.pset(mp, y - 8, 7)
            pyxel.pset(mp + 2, y - 7, 7)
        pyxel.pset(x, y, 7)
        pyxel.pset(x + w - 1, y, 7)

    def _draw_plat_ice(self, x, y, w, h):
        """Eis-Plattform: Risse, Glanz, Eiszapfen, Shimmer."""
        pyxel.rect(x, y, w, h, 1)
        pyxel.rect(x, y, w, 3, 6)
        pyxel.rect(x, y, w, 1, 12)
        pyxel.rect(x, y + 4, w, 2, 5)
        # Risse
        crack_off = int(self.cam_x * 0.5)
        i = 0
        while i < w:
            cx = x + i + (crack_off % 8)
            pyxel.line(cx, y + 2, cx + 3, y + 6, 1)
            pyxel.line(cx + 7, y + 1, cx + 5, y + 5, 5)
            i += 18
        # Eiszapfen
        i = 0
        while i < w:
            dh = 3 + (i * 7 + int(self.cam_x)) % 5
            pyxel.rect(x + i, y + h, 2, dh, 6)
            pyxel.pset(x + i + 1, y + h + dh, 12)
            i += 10
        # Glanz-Shimmer
        shimmer_x = x + (self.t // 3) % max(w, 1)
        if x <= shimmer_x < x + w:
            pyxel.pset(shimmer_x, y, 7)
            pyxel.pset(shimmer_x + 1, y, 7)
        # Kristall-Dekoration oben
        if w > 15:
            kx = x + w // 2
            pyxel.pset(kx, y - 1, 12)
            pyxel.pset(kx + 1, y - 1, 7)
        pyxel.pset(x, y, 7)
        pyxel.pset(x + w - 1, y, 7)

    def _draw_plat_lava_ground(self, x, y, w, h):
        """Lava-Tempel-Boden: Obsidian, Glut-Risse, glühende Ränder."""
        pyxel.rect(x, y, w, h, 2)
        pyxel.rect(x, y, w, 2, 0)
        # Glühende Risse
        i = 0
        while i < w:
            crack_y = y + 4 + (i * 3) % 4
            c = 8 if (self.t // 8 + i) % 3 != 2 else 9
            pyxel.pset(x + i, crack_y, c)
            i += 5
        # Rand-Glut
        glow_c = 9 if (self.t // 8) % 2 == 0 else 10
        pyxel.pset(x, y + 1, glow_c)
        pyxel.pset(x + w - 1, y + 1, glow_c)
        # Ornament-Linie
        i = 0
        while i < w:
            pyxel.pset(x + i, y + h - 2, 8 if (i // 4) % 2 == 0 else 2)
            i += 4
        pyxel.pset(x, y, 8)
        pyxel.pset(x + w - 1, y, 8)

    def _draw_plat_cloud_ground(self, x, y, w, h):
        """Wolken-Plattform: fluffig, Schatten, Regentropfen."""
        pyxel.rect(x, y, w, h, 7)
        pyxel.rect(x, y, w, 2, 13)
        # Wolken-Puffs oben
        i = 0
        while i < w:
            pyxel.circ(x + i + 5, y - 4, 6, 7)
            i += 10
        # Innere Aufhellung
        pyxel.rect(x + 2, y + 2, w - 4, 4, 13)
        # Regentropfen (animiert)
        i = 0
        while i < w:
            dy = (self.t // 2 + i * 5) % 16
            if dy < 14:
                pyxel.pset(x + i + 3, y + h + dy, 12)
            i += 8
        pyxel.rect(x + 2, y + h - 2, w - 4, 2, 13)

    def _draw_plat_ghost_ground(self, x, y, w, h):
        """Geister-Plattform: verwitterter Stein, Moos, Geister-Schimmer."""
        pyxel.rect(x, y, w, h, 5)
        pyxel.rect(x, y, w, 2, 0)
        # Mauerwerk-Muster
        i = 0
        while i < w:
            pyxel.rect(x + i, y + 4, 8, 2, 1)
            pyxel.rect(x + i + 4, y + 8, 8, 2, 1)
            i += 12
        # Moos
        i = 0
        while i < w:
            if (i // 8 + x // 8) % 3 == 0:
                pyxel.pset(x + i, y, 3)
                pyxel.pset(x + i + 1, y - 1, 11)
            i += 8
        # Geister-Schimmer
        glow_x = x + (self.t // 5) % max(w, 1)
        if x <= glow_x < x + w:
            pyxel.pset(glow_x, y + 1, 6)
        pyxel.pset(x, y, 6)
        pyxel.pset(x + w - 1, y, 6)

    def _draw_plat_inferno_ground(self, x, y, w, h):
        """Inferno-Boden: Magma-Risse, glühende Oberfläche, Funken."""
        pyxel.rect(x, y, w, h, 0)
        pyxel.rect(x, y, w, 2, 2)
        glow_c = 9 if (self.t // 6) % 2 == 0 else 8
        pyxel.rect(x, y, w, 1, glow_c)
        # Magma-Blasen
        i = 0
        while i < w:
            bub_phase = (self.t // 4 + i * 3) % 20
            if bub_phase < 8:
                pyxel.pset(x + i, y + 3 + bub_phase % 4, 9)
                if bub_phase < 3:
                    pyxel.pset(x + i - 1, y + 2, 10)
                    pyxel.pset(x + i + 1, y + 2, 10)
            i += 7
        # Risse
        i = 0
        while i < w:
            pyxel.line(x + i, y + 5, x + i + 3, y + h - 2, 2)
            c = 8 if (self.t // 10 + i) % 3 != 0 else 9
            pyxel.pset(x + i + 1, y + 6, c)
            i += 15
        pyxel.pset(x, y, 10)
        pyxel.pset(x + w - 1, y, 10)

    def _draw_wall_bark(self, x, y, w, h):
        """Baum-Rinde: detailliert mit Astnarben und Moos."""
        pyxel.rect(x, y, w, h, 4)
        i = 0
        while i < h:
            pyxel.rect(x, y + i, w, 1, 9)
            i += 8
        pyxel.rect(x, y, 3, h, 5)
        pyxel.rect(x + w - 2, y, 2, h, 3)
        # Astnarben
        for di in range(0, h, 20):
            pyxel.pset(x + w // 2, y + di + 5, 3)
            pyxel.circ(x + w // 2, y + di + 5, 2, 9)
        # Moos an der Basis
        if h > 30:
            pyxel.rect(x, y + h - 6, w, 4, 11)
            pyxel.rect(x, y + h - 6, w, 1, 3)

    def _draw_wall_stone(self, x, y, w, h):
        """Stein-Wand: Mauerwerk mit Moos, Rissen."""
        pyxel.rect(x, y, w, h, 6)
        i = 0
        while i < h:
            pyxel.rect(x, y + i, w, 1, 7)
            i += 8
        # Horizontale Fugen
        for di in range(0, h, 12):
            pyxel.line(x, y + di, x + w, y + di, 5)
        # Vertikale Fugen (versetzt)
        for di in range(0, h, 24):
            pyxel.pset(x + w // 2, y + di + 6, 5)
        # Moos und Kristalle
        for di in range(0, h, 14):
            pyxel.pset(x + 3, y + di + 4, 7)
            pyxel.pset(x + w - 4, y + di + 10, 12)
            if di % 28 == 0:
                pyxel.pset(x + 1, y + di + 8, 11)

    def _draw_wall_ice(self, x, y, w, h):
        """Eis-Kletterwand: Schichten, Kristalle, Shimmer, Risse."""
        pyxel.rect(x, y, w, h, 1)
        i = 0
        while i < h:
            lc = 5 if (i // 12) % 2 == 0 else 1
            pyxel.rect(x, y + i, w, min(12, h - i), lc)
            i += 12
        pyxel.rect(x, y, 2, h, 6)
        pyxel.rect(x, y, 1, h, 12)
        pyxel.rect(x + w - 2, y, 2, h, 1)
        # Kristall-Einschlüsse
        for di in range(0, h, 16):
            pyxel.pset(x + 4, y + di + 5, 7)
            pyxel.pset(x + 3, y + di + 6, 12)
            pyxel.pset(x + 5, y + di + 6, 12)
            pyxel.pset(x + 4, y + di + 7, 6)
            if w > 10:
                pyxel.pset(x + w - 5, y + di + 8, 12)
                pyxel.pset(x + w - 5, y + di + 9, 7)
        # Shimmer links + rechts
        for di in range(0, h, 24):
            shimmer = (self.t // 8 + di) % 24
            if shimmer < 6:
                pyxel.pset(x + 6, y + di + shimmer, 7)
        for di in range(0, h, 30):
            shimmer2 = (self.t // 10 + di + 12) % 30
            if shimmer2 < 5 and w > 8:
                pyxel.pset(x + w - 4, y + di + shimmer2, 12)
        # Risse
        for di in range(0, h, 22):
            pyxel.line(x + 7, y + di, x + 9, y + di + 8, 6)

    def _draw_wall_lava(self, x, y, w, h):
        """Lava-Wand: glühende Adern, flackernde Risse."""
        pyxel.rect(x, y, w, h, 0)
        i = 0
        while i < h:
            c = 8 if (self.t // 12 + i) % 3 == 0 else 2
            pyxel.rect(x, y + i, w, 1, c)
            i += 10
        pyxel.rect(x, y, 2, h, 2)
        pyxel.rect(x + w - 2, y, 2, h, 8)
        # Glühende Punkte
        for di in range(0, h, 14):
            gc = 9 if (self.t // 8 + di) % 3 == 0 else 8
            pyxel.pset(x + w // 2, y + di + 5, gc)

    # ─── GOAL ───

    def _draw_goal(self):
        gx = int(self.goal_x - self.cam_x)
        gy = 128
        glow_r = 9 + (self.t // 8) % 3
        pyxel.circ(gx, gy, glow_r, self.bg_col[1])
        pyxel.circ(gx, gy, 8, 9)
        pyxel.circ(gx, gy, 6, 10)
        pyxel.circ(gx, gy, 3, 7)
        pyxel.pset(gx - 1, gy - 1, 7)
        if (self.t // 8) % 2 == 0:
            pyxel.circb(gx, gy, 10, 9)
        else:
            pyxel.circb(gx, gy, 10, 10)
        pyxel.text(gx - 7, gy - 18, "ZIEL!", 10)

    # ─── ITEMS ───

    def _draw_items(self):
        idx = self.lvl_idx
        for it in self.items:
            if not it.alive:
                continue
            ix = int(it.x - self.cam_x)
            iy = int(it.screen_y())
            if it.kind == "nut":
                pyxel.circ(ix, iy, 4, 4)
                pyxel.circ(ix, iy, 3, 9)
                pyxel.circ(ix, iy, 2, 10)
                pyxel.pset(ix - 1, iy - 1, 7)
            elif it.kind == "gem":
                if idx == 1:
                    pyxel.tri(ix, iy - 5, ix - 4, iy, ix + 4, iy, 6)
                    pyxel.tri(ix - 4, iy, ix + 4, iy, ix, iy + 3, 12)
                    pyxel.line(ix - 2, iy - 3, ix, iy - 5, 7)
                    if (self.t // 6) % 3 == 0:
                        pyxel.pset(ix + 2, iy - 4, 7)
                else:
                    pyxel.tri(ix, iy - 5, ix - 4, iy, ix + 4, iy, 12)
                    pyxel.tri(ix - 4, iy, ix + 4, iy, ix, iy + 3, 6)
                    pyxel.line(ix - 2, iy - 3, ix, iy - 5, 7)
            else:
                for a in range(5):
                    ang = a * math.pi * 2 / 5 - math.pi / 2
                    ang2 = ang + math.pi / 5
                    ex2 = int(ix + math.cos(ang) * 5)
                    ey2 = int(iy + math.sin(ang) * 5)
                    mx2 = int(ix + math.cos(ang2) * 2)
                    my2 = int(iy + math.sin(ang2) * 2)
                    pyxel.tri(ix, iy, ex2, ey2, mx2, my2, 10)
                pyxel.pset(ix, iy, 9)

    # ─── ENEMIES ───

    def _draw_enemies(self):
        for e in self.enemies:
            if not e.alive:
                continue
            ex = int(e.x - self.cam_x)
            ey = int(e.y)
            if e.kind == "patrol":
                col = 8
                pyxel.rect(ex - 5, ey - 7, 10, 9, col)
                pyxel.rect(ex - 3, ey - 9, 6, 4, col)
                eye_off = 1 if e.vx > 0 else -1
                pyxel.pset(ex + eye_off * 2, ey - 5, 0)
                pyxel.pset(ex + eye_off * 2, ey - 4, 7)
                leg_a = (e.anim % 2) * 2
                pyxel.pset(ex - 2 + leg_a, ey + 2, col)
                pyxel.pset(ex + 2 - leg_a, ey + 2, col)
                pyxel.line(ex - 3, ey - 8, ex - 1, ey - 7, 2)
                pyxel.line(ex + 1, ey - 7, ex + 3, ey - 8, 2)
            elif e.kind == "chase":
                col = 2
                pyxel.rect(ex - 5, ey - 7, 10, 9, col)
                pyxel.rect(ex - 3, ey - 10, 6, 4, col)
                pyxel.pset(ex - 2, ey - 12, col)
                pyxel.pset(ex, ey - 13, col)
                pyxel.pset(ex + 2, ey - 12, col)
                ec = 9 if (e.timer // 10) % 2 else 10
                pyxel.pset(ex - 2, ey - 5, ec)
                pyxel.pset(ex + 2, ey - 5, ec)
            elif e.kind == "jumper":
                col = 3
                bob = int(math.sin(e.timer * 0.2) * 2)
                pyxel.circ(ex, ey - 5 + bob, 6, col)
                pyxel.circ(ex, ey - 5 + bob, 4, 11)
                pyxel.pset(ex - 2, ey - 6 + bob, 0)
                pyxel.pset(ex + 2, ey - 6 + bob, 0)
                pyxel.line(ex - 3, ey + 1, ex - 4, ey + 3 + bob, col)
                pyxel.line(ex + 3, ey + 1, ex + 4, ey + 3 + bob, col)
            elif e.kind == "flyer":
                col = 5
                wing = int(math.sin(e.timer * 0.3) * 4)
                pyxel.rect(ex - 4, ey - 5, 8, 7, col)
                pyxel.tri(ex - 4, ey - 3, ex - 10, ey - 3 - wing, ex - 4, ey + 1, 6)
                pyxel.tri(ex + 4, ey - 3, ex + 10, ey - 3 - wing, ex + 4, ey + 1, 6)
                pyxel.pset(ex - 1, ey - 3, 0)
                pyxel.pset(ex + 1, ey - 3, 0)

    # ─── SQUIRREL ───

    def _draw_squirrel_at(self, x, y, facing, frame, wall=False, ceil=False):
        body_col = 8
        tail_col = 9
        if wall:
            pyxel.rect(x + 1, y, 6, 8, body_col)
            pyxel.rect(x + 1, y, 6, 2, 9)
            claw_x = x + 7 if facing == 1 else x
            pyxel.pset(claw_x, y + 2, 7)
            pyxel.pset(claw_x, y + 5, 7)
            for tx2, ty2 in [(x - 2, y + 2), (x - 3, y + 4), (x - 2, y + 6)]:
                pyxel.pset(tx2, ty2, tail_col)
        elif ceil:
            pyxel.rect(x + 1, y, 6, 8, body_col)
            pyxel.pset(x + 2, y, 7)
            pyxel.pset(x + 5, y, 7)
            for ti in range(4):
                pyxel.pset(x + 3, y + 9 + ti, tail_col)
        else:
            bobs = [0, -1, 0, -1]
            bob = bobs[frame]
            py2 = y + bob
            tail_pts = ([(x-2,py2+1,tail_col),(x-3,py2+3,tail_col),(x-3,py2+5,10),(x-2,py2+6,tail_col)]
                        if facing == 1 else
                        [(x+8,py2+1,tail_col),(x+9,py2+3,tail_col),(x+9,py2+5,10),(x+8,py2+6,tail_col)])
            for tx2, ty2, tc in tail_pts:
                pyxel.pset(tx2, ty2, tc)
            pyxel.rect(x + 1, py2, 6, 7, body_col)
            pyxel.rect(x + 2, py2 + 2, 3, 3, 4)
            legs = [(2, 5), (3, 4), (2, 5), (1, 6)]
            la, lb = legs[frame]
            pyxel.pset(x + la, py2 + 7, body_col)
            pyxel.pset(x + lb, py2 + 7, body_col)
        tx = x - 4 if facing == 1 else x + 8
        pyxel.rect(tx, y + 1, 5, 5, 9)
        pyxel.pset(tx if facing == 1 else tx + 4, y + 4, 10)
        ex2 = x + 5 if facing == 1 else x + 1
        for ey2 in range(y - 2, y + 1):
            pyxel.pset(ex2, ey2, tail_col)
        eye_x = x + 4 if facing == 1 else x + 2
        pyxel.pset(eye_x, y + 2, 0)
        pyxel.pset(eye_x + (1 if facing == 1 else -1), y + 2, 7)
        nose_x = x + 7 if facing == 1 else x
        pyxel.pset(nose_x, y + 4, 4)
        pyxel.pset(nose_x, y + 5, 8)

    # ─── HUD ───

    def _draw_hud(self):
        pyxel.rect(0, 0, SCREEN_W, 13, 0)
        pyxel.line(0, 13, SCREEN_W, 13, 5)
        pyxel.rect(0, 12, SCREEN_W, 1, 9)
        names = ["Herbst-Wald", "Eishoehle", "Lava-Tempel", "Wolkengipfel",
                 "Geistertuerme", "Inferno-Gipfel"]
        pyxel.text(3, 3, "LVL" + str(self.lvl_idx + 1) + " " + names[self.lvl_idx], 7)
        sc_str = "SCORE:" + str(self.score)
        sc_x = SCREEN_W // 2 - len(sc_str) * 2
        pyxel.text(sc_x + 1, 4, sc_str, 0)
        pyxel.text(sc_x, 3, sc_str, 10)
        for i in range(self.lives):
            self._draw_heart(SCREEN_W - 10 - i * 12, 3)
        bar_x, bar_y = 3, SCREEN_H - 9
        pyxel.rect(bar_x, bar_y, 52, 6, 0)
        bar_w = int(self.stamina / STAMINA_MAX * 50)
        col = 11 if self.stamina > 60 else (9 if self.stamina > 25 else 8)
        pyxel.rect(bar_x + 1, bar_y + 1, bar_w, 4, col)
        if bar_w > 2:
            pyxel.rect(bar_x + 1, bar_y + 1, bar_w, 1, 7)
        pyxel.rectb(bar_x, bar_y, 52, 6, 5)
        pyxel.text(bar_x + 54, bar_y + 1, "STM", 13)
        if abs(self.wind) > 0.2:
            arrows = ">>" if self.wind > 0 else "<<"
            pyxel.text(SCREEN_W - 22, SCREEN_H - 9, arrows, 12 if self.wind > 0 else 6)
        if self.dash_cd > 0:
            fill = int((1 - self.dash_cd / 40) * 20)
            pyxel.rect(60, SCREEN_H - 9, fill, 6, 6)
            if fill > 1:
                pyxel.rect(60, SCREEN_H - 9, fill, 1, 7)
            pyxel.rectb(60, SCREEN_H - 9, 20, 6, 5)
            pyxel.text(82, SCREEN_H - 8, "DASH", 13)
        if self.hurt_timer > 50:
            for ry in range(0, SCREEN_H, 2):
                pyxel.line(0, ry, SCREEN_W, ry, 8)

    def _draw_heart(self, x, y):
        pyxel.pset(x + 1, y, 8); pyxel.pset(x + 3, y, 8)
        pyxel.rect(x, y + 1, 5, 2, 8)
        pyxel.pset(x + 1, y + 3, 8); pyxel.pset(x + 3, y + 3, 8)
        pyxel.pset(x + 2, y + 4, 8)
        pyxel.pset(x + 1, y + 1, 4)

    def _draw_overlay(self, title, subtitle, col):
        ox = SCREEN_W // 2 - 58
        oy = SCREEN_H // 2 - 20
        pyxel.rect(ox, oy + 2, 120, 44, 0)
        pyxel.rect(ox - 2, oy - 2, 120, 44, 0)
        pyxel.rectb(ox - 2, oy - 2, 120, 44, col)
        pyxel.rectb(ox - 3, oy - 3, 122, 46, 5)
        pyxel.rectb(ox - 1, oy - 1, 118, 42, col)
        pyxel.text(ox + 6, oy + 6, title, 0)
        pyxel.text(ox + 5, oy + 5, title, col)
        pyxel.text(ox + 5, oy + 14, subtitle, 7)
        pyxel.text(ox + 5, oy + 23, "SCORE: " + str(self.score), 10)
        if self.hi_score > 0:
            pyxel.text(ox + 5, oy + 31, "BEST:  " + str(self.hi_score), 9)


Game()