import pyxel
import random
import math

class Game:
    def __init__(self):
        pyxel.init(160, 120, title="Brain & Beauty")
        pyxel.load("res2.pyxres")

        # Sound-IDs fuer Effekte. Wir erzeugen die Sounds hier direkt im
        # Code (statt sie aus der .pyxres zu laden), damit sie garantiert
        # existieren, egal was in res2.pyxres an Sound-Slots vorhanden ist.
        self.SOUND_CRASH = 1
        self.SOUND_STAR = 2

        # Crash-Sound: kurzer, fallender "Plopp" (Pulse-Welle, tiefe Toene)
        pyxel.sound(self.SOUND_CRASH).set(
            notes="f2d2a1f1",
            tones="pppp",
            volumes="7774",
            effects="nnnn",
            speed=12
        )

        # Stern-Sound: aufsteigender, heller "Ping" (Triangle-Welle).
        # Hinweis: Pyxel erlaubt nur Oktaven 0-4, daher c3e3g3c4 statt c4..c5.
        pyxel.sound(self.SOUND_STAR).set(
            notes="c3e3g3c4",
            tones="tttt",
            volumes="7765",
            effects="nnnn",
            speed=20
        )

        # ╔═══════════════════════════════════════════════════════════╗
        # ║  HINTERGRUNDMUSIK – HIER KANNST DU DIE MELODIE ANPASSEN!  ║
        # ╚═══════════════════════════════════════════════════════════╝
        #
        # Die Musik wird komplett im Code erzeugt (nicht aus res2.pyxres
        # geladen), damit sie sich leicht aendern laesst.
        #
        # AUFBAU – 3 Stimmen gleichzeitig:
        #   melody_notes = die Melodie, die man am meisten hoert
        #   bass_notes   = tiefe Grundtoene, geben der Musik "Fundament"
        #   perc_notes   = leiser Rhythmus-Klick im Hintergrund
        #
        # NOTEN-SCHREIBWEISE (Pyxel-Format):
        #   Jede Note = Buchstabe (a-g) + optional '#' fuer Halbton-erhoeht
        #               + Ziffer 0-4 fuer die Oktave (0=ganz tief, 4=ganz hoch)
        #   Beispiele: "c3" = mittleres C, "g2" = tiefes G, "f#3" = Fis
        #   "r" = Pause (kein Ton)
        #   WICHTIG: Jede Stimme (melody/bass/perc) muss gleich viele
        #   Noten haben, sonst verschieben sich die Stimmen zueinander!
        #   Aktuell sind es 32 Noten pro Stimme (8 Takte à 4 Noten).
        #
        # SCHNELLE AENDERUNGEN, DIE DU SELBST MACHEN KANNST:
        #   - TEMPO aendern: "speed=30" weiter unten anpassen.
        #     Kleinere Zahl = schneller, groessere Zahl = langsamer.
        #     (speed=18 ist ziemlich schnell, speed=45 ist gemaechlich)
        #   - LAUTSTAERKE aendern: die "volumes"-Strings, Ziffern 0(leise)-7(laut)
        #   - INSTRUMENT/KLANGFARBE aendern: die "tones"-Strings:
        #       't' = Triangle (weich, rund)   'p' = Pulse (helles Quietschen)
        #       's' = Square (klassischer 8-Bit-Sound)  'n' = Noise (Rauschen/Percussion)
        #   - EIGENE MELODIE schreiben: melody_notes einfach durch eine neue
        #     Notenfolge ersetzen. Tipp: bleib in der gleichen Tonart wie der
        #     Bass darunter, dann klingt es automatisch stimmig. Aktuell ist
        #     der Bass C-F-G-C (Takt 1-4) dann Am-Em-F-G (Takt 5-8) – jede
        #     Melodie-Note sollte zum jeweiligen Akkord passen:
        #       Takt mit Bass 'c' -> Melodie-Toene c, e, g passen gut
        #       Takt mit Bass 'f' -> Melodie-Toene f, a, c passen gut
        #       Takt mit Bass 'g' -> Melodie-Toene g, b, d passen gut
        #       Takt mit Bass 'a' (Moll) -> Melodie-Toene a, c, e passen gut
        #       Takt mit Bass 'e' (Moll) -> Melodie-Toene e, g, b passen gut
        #
        # Aktuelle Akkordfolge: C-F-G-C (Teil A) dann Am-Em-F-G (Teil B),
        # eine sehr gebraeuchliche, garantiert angenehm klingende Folge.

        melody_notes = (
            "c3e3g3e3" "f3a3c4a3" "g3b3d4b3" "c4g3e3c3"   # Teil A: C-F-G-C
            "a3c4e4c4" "e3g3b3g3" "f3a3c4f3" "g3e3c3g2"   # Teil B: Am-Em-F-G
        )
        bass_notes = (
            "c2c2c2c2" "f2f2f2f2" "g2g2g2g2" "c2c2c2c2"
            "a1a1a1a1" "e1e1e1e1" "f1f1f1f1" "g1g1g1g1"
        )
        # Dezenter Rhythmus-Akzent auf Schlag 2 und 4 jedes Takts
        perc_notes = ("r" "a3" "r" "a3") * 8

        self.MUSIC_MELODY = 10
        self.MUSIC_BASS = 11
        self.MUSIC_PERC = 12

        pyxel.sound(self.MUSIC_MELODY).set(
            notes=melody_notes,
            tones="t" * 32,    # Triangle-Welle: weicher Melodie-Klang
            volumes="6" * 32,
            effects="n" * 32,
            speed=30           # <- TEMPO HIER AeNDERN (kleiner=schneller)
        )
        pyxel.sound(self.MUSIC_BASS).set(
            notes=bass_notes,
            tones="p" * 32,    # Pulse-Welle: praesenter Bass-Klang
            volumes="5" * 32,
            effects="n" * 32,
            speed=30           # muss zum Tempo der Melodie passen!
        )
        pyxel.sound(self.MUSIC_PERC).set(
            notes=perc_notes,
            tones="n" * 32,    # Noise: klingt wie ein dezenter Klick/Hi-Hat
            volumes="2" * 32,  # bewusst leise, nur als Akzent gedacht
            effects="n" * 32,
            speed=30           # muss zum Tempo der Melodie passen!
        )

        # Die drei Stimmen zu einem Musik-Track zusammensetzen und abspielen.
        # pyxel.music(0) ist der Music-Slot, den playm(0, ...) unten startet.
        pyxel.music(0).set(
            [self.MUSIC_MELODY],
            [self.MUSIC_BASS],
            [self.MUSIC_PERC]
        )
        pyxel.playm(0, loop=True)

        self.level = 1

        self.story_stages = ["Casting", "Vorrunde", "Halbfinale", "Mathe", "Geographie", "Sternenregen", "Sprung-Challenge", "Finale"]
        self.story_index = 0

        self.lanes = [30, 60, 90]
        self.current_lane = 1
        self.player_x = 20
        self.player_y = self.lanes[self.current_lane]
        self.outfit = 0

        # ── Driving shared state ──────────────────────────────
        self.lives = 3
        self.speed = 1
        self.has_helmet = False
        self.cars = []
        self.items = []
        self.timer = 0
        self.max_time = 600
        self.show_level_complete_text = False
        self.level_complete_timer = 0
        self.hit_flash = 0          # red flash frames on collision

        self.level3_cars = []
        self.level3_items = []
        self.level3_timer = 0
        self.level3_max_time = 550
        self.level3_has_helmet = False
        self.level3_speed = 1
        self.level3_current_lane = 1
        self.level3_player_y = self.lanes[1]
        self.show_level3_complete_text = False
        self.level3_complete_timer = 0
        self.level3_lives = 3
        self.level3_hit_flash = 0

        # ── Quiz shared state ─────────────────────────────────
        self.quiz_total = 6
        self.quiz_count = 0
        self.quiz_question = ""
        self.quiz_choices = []
        self.quiz_correct_index = 0
        self.quiz_selected = -1
        self.quiz_feedback_timer = 0
        self.quiz_score_mathe = 0
        self.quiz_score_geo = 0

        # Streak system
        self.quiz_streak = 0
        self.quiz_bonus = 0
        self.quiz_show_bonus = 0
        self.quiz_time_limit = 180      # frames per question
        self.quiz_time_left = 180
        self.quiz_timed_out = False

        # Geo-Quiz: bereits gestellte Fragen merken, damit sich nichts
        # wiederholt, solange noch unverbrauchte Fragen im Pool sind
        self.geo_asked_questions = []
        self.geo_pool_order = []   # gemischte Reihenfolge fuer den aktuellen Durchlauf

        # Mathe typing
        self.mathe_answer = ""
        self.mathe_correct_answer = 0
        self.mathe_answer_color = 7
        self.mathe_correct_timer = 0
        self.mathe_wrong_timer = 0

        # ── Sternenregen-Finale ───────────────────────────────
        self.starrain_player_x = 80
        self.starrain_stars = []       # {"x","y","speed"}
        self.starrain_timer = 0
        self.starrain_max_time = 450
        self.starrain_score = 0
        self.starrain_missed = 0
        self.starrain_combo = 0
        self.starrain_best_combo = 0
        self.starrain_show_combo = 0
        self.starrain_done = False
        self.starrain_done_timer = 0

        # ── Jump-Level: Plattformen & Sterne ──────────────────
        self.jump_platforms = []       # {"x","y","w"}
        self.jump_stars = []           # {"x","y","taken"}
        self.jump_px = 76.0            # Spieler-Weltposition X
        self.jump_py = 0.0             # Spieler-Weltposition Y (0 = Boden)
        self.jump_vy = 0.0             # vertikale Geschwindigkeit
        self.jump_vx = 0.0
        self.jump_on_ground = True
        self.jump_camera_y = 0.0       # Kamera-Offset (scrollt nach oben)
        self.jump_score = 0
        self.jump_target = 30
        self.jump_lives = 3
        self.jump_done = False
        self.jump_done_timer = 0
        self.jump_fail_flash = 0
        self.jump_next_platform_y = 0  # naechste Hoehe, an der eine Plattform generiert wird
        self.jump_highest_y = 0        # hoechster je erreichter Punkt (fuer Generierung)
        self.jump_current_platform_y = 0.0  # y der Plattform, auf der der Spieler aktuell steht (fuer Kamera)

        # ── Confetti ─────────────────────────────────────────
        self.confetti = []

        # ── Particle effects ─────────────────────────────────
        self.particles = []     # {"x","y","dx","dy","color","life"}

        # ── Instruction blink ────────────────────────────────
        self.blink = 0

        # ── Screen shake (Politur) ────────────────────────────
        self.shake_timer = 0
        self.shake_strength = 0

        pyxel.run(self.update, self.draw)

    # =========================================================
    #  PARTICLES
    # =========================================================
    def spawn_particles(self, x, y, color, count=8):
        for _ in range(count):
            angle = random.uniform(0, 2 * math.pi)
            speed = random.uniform(0.5, 2.5)
            self.particles.append({
                "x": float(x), "y": float(y),
                "dx": math.cos(angle) * speed,
                "dy": math.sin(angle) * speed,
                "color": color,
                "life": random.randint(12, 25)
            })

    def update_particles(self):
        for p in self.particles:
            p["x"] += p["dx"]
            p["y"] += p["dy"]
            p["dy"] += 0.08   # gravity
            p["life"] -= 1
        self.particles = [p for p in self.particles if p["life"] > 0]

    def trigger_shake(self, strength=3, duration=8):
        self.shake_timer = duration
        self.shake_strength = strength

    # =========================================================
    #  SOUND HELPER
    # =========================================================
    def play_sfx(self, sound_id):
        """Spielt einen Soundeffekt ab. Die Sounds (SOUND_CRASH/SOUND_STAR)
        werden in __init__ direkt im Code erzeugt, existieren also immer.
        Kanal 3 ist fuer Sound-Effekte reserviert (0-2 nutzt die Musik)."""
        try:
            pyxel.play(3, sound_id)
        except Exception:
            pass

    # =========================================================
    #  UPDATE
    # =========================================================
    def update(self):
        self.blink = (self.blink + 1) % 60
        self.update_particles()
        if self.shake_timer > 0:
            self.shake_timer -= 1

        if self.level == 1:
            if pyxel.btnp(pyxel.KEY_RIGHT):
                self.outfit = (self.outfit + 1) % 3
            if pyxel.btnp(pyxel.KEY_LEFT):
                self.outfit = (self.outfit - 1) % 3
            if pyxel.btnp(pyxel.KEY_RETURN):
                self.level = 1.5

        elif self.level == 1.5:
            if pyxel.btnp(pyxel.KEY_RETURN):
                self.level = 2

        elif self.level == 2:
            self._update_driving(
                timer_attr="timer", max_time_attr="max_time",
                cars_attr="cars", items_attr="items",
                lane_attr="current_lane", py_attr="player_y",
                speed_attr="speed", helmet_attr="has_helmet",
                lives_attr="lives", flash_attr="hit_flash",
                complete_attr="show_level_complete_text",
                ctimer_attr="level_complete_timer",
                next_level=2.5, story_idx=1,
                reset_fn=self.reset_level2,
                car_interval=30, car_speed=3, item_interval=80
            )

        elif self.level == 2.5:
            if pyxel.btnp(pyxel.KEY_RETURN):
                self.level = 3
                self.reset_level3()

        elif self.level == 3:
            self._update_level3()

        elif self.level == 3.5:
            if pyxel.btnp(pyxel.KEY_RETURN):
                self.level = 4
                self.story_index = 3
                self.quiz_count = 0
                self.quiz_score_mathe = 0
                self.quiz_streak = 0
                self.quiz_bonus = 0
                self.mathe_answer = ""
                self.generate_quiz_mathe()
                self.quiz_time_left = self.quiz_time_limit

        elif self.level == 4:
            self._update_mathe()

        elif self.level == 4.5:
            if pyxel.btnp(pyxel.KEY_RETURN):
                self.level = 5
                self.story_index = 4
                self.quiz_count = 0
                self.quiz_score_geo = 0
                self.quiz_streak = 0
                self.geo_asked_questions = []
                self.geo_pool_order = []
                self.generate_quiz_mc("geo")
                self.quiz_time_left = self.quiz_time_limit

        elif self.level == 5:
            self._update_mc_quiz("geo")
            if self.quiz_count >= self.quiz_total:
                self.level = 5.5

        elif self.level == 5.5:
            if pyxel.btnp(pyxel.KEY_RETURN):
                self.level = 6.5
                self.story_index = 5
                self._init_starrain()

        elif self.level == 6.5:
            self._update_starrain()

        elif self.level == 7:
            if pyxel.btnp(pyxel.KEY_RETURN):
                self.level = 7.5
                self.story_index = 6
                self._init_jump()

        elif self.level == 7.5:
            self._update_jump()

        elif self.level == 8:
            self._update_finale()

    # ─── Unified driving update ───────────────────────────────
    def _update_driving(self, timer_attr, max_time_attr, cars_attr, items_attr,
                        lane_attr, py_attr, speed_attr, helmet_attr, lives_attr,
                        flash_attr, complete_attr, ctimer_attr,
                        next_level, story_idx, reset_fn,
                        car_interval, car_speed, item_interval):
        if getattr(self, flash_attr) > 0:
            setattr(self, flash_attr, getattr(self, flash_attr) - 1)

        timer = getattr(self, timer_attr) + 1
        setattr(self, timer_attr, timer)

        if timer > getattr(self, max_time_attr) and not getattr(self, complete_attr):
            setattr(self, complete_attr, True)
            setattr(self, ctimer_attr, 90)
            self.story_index = story_idx
            self.spawn_particles(80, 60, 10, 20)
            return

        if getattr(self, complete_attr):
            ct = getattr(self, ctimer_attr) - 1
            setattr(self, ctimer_attr, ct)
            if ct <= 0:
                self.level = next_level
                setattr(self, complete_attr, False)
            return

        # Input
        if pyxel.btnp(pyxel.KEY_UP):
            setattr(self, lane_attr, max(0, getattr(self, lane_attr) - 1))
        if pyxel.btnp(pyxel.KEY_DOWN):
            setattr(self, lane_attr, min(2, getattr(self, lane_attr) + 1))
        setattr(self, py_attr, self.lanes[getattr(self, lane_attr)])

        # Cars
        spd = car_speed + (1 if getattr(self, speed_attr) > 1 else 0)
        cars = getattr(self, cars_attr)
        for car in cars:
            car["x"] -= spd
        setattr(self, cars_attr, [c for c in cars if c["x"] > -40])

        if pyxel.frame_count % car_interval == 0:
            getattr(self, cars_attr).append({"x": 160, "lane": random.randint(0, 2)})

        # Items
        items = getattr(self, items_attr)
        for item in items:
            item["x"] -= 2
        setattr(self, items_attr, [i for i in items if i["x"] > -20])

        if pyxel.frame_count % item_interval == 0:
            # Sterne kommen jetzt deutlich haeufiger vor als Schuh/Helm
            getattr(self, items_attr).append({
                "x": 160, "lane": random.randint(0, 2),
                "type": random.choices(
                    ["shoe", "helmet", "star"],
                    weights=[1, 1, 3]
                )[0]
            })

        # Collision with cars
        cur_lane = getattr(self, lane_attr)
        lives = getattr(self, lives_attr)
        cars = getattr(self, cars_attr)
        to_remove = []
        for car in cars:
            if car["lane"] == cur_lane and abs(car["x"] - self.player_x) < 18:
                if getattr(self, helmet_attr):
                    setattr(self, helmet_attr, False)
                    to_remove.append(car)
                    self.spawn_particles(self.player_x, getattr(self, py_attr), 9, 12)
                    self.play_sfx(self.SOUND_CRASH)
                    self.trigger_shake(2, 6)
                else:
                    lives -= 1
                    setattr(self, lives_attr, lives)
                    setattr(self, flash_attr, 30)
                    to_remove.append(car)
                    self.spawn_particles(self.player_x, getattr(self, py_attr), 8, 15)
                    self.play_sfx(self.SOUND_CRASH)
                    self.trigger_shake(4, 10)
                    if lives <= 0:
                        reset_fn()
                        return
        for car in to_remove:
            if car in getattr(self, cars_attr):
                getattr(self, cars_attr).remove(car)

        # Item pickup
        items = getattr(self, items_attr)
        to_remove = []
        for item in items:
            if item["lane"] == cur_lane and abs(item["x"] - self.player_x) < 15:
                self.spawn_particles(item["x"], self.lanes[item["lane"]], 10, 8)
                if item["type"] == "shoe":
                    setattr(self, speed_attr, 2)
                elif item["type"] == "helmet":
                    setattr(self, helmet_attr, True)
                elif item["type"] == "star":
                    if lives < 3:
                        setattr(self, lives_attr, min(3, lives + 1))
                    self.play_sfx(self.SOUND_STAR)
                to_remove.append(item)
        for item in to_remove:
            if item in getattr(self, items_attr):
                getattr(self, items_attr).remove(item)

    def _update_level3(self):
        if self.level3_hit_flash > 0:
            self.level3_hit_flash -= 1

        self.level3_timer += 1
        if self.level3_timer > self.level3_max_time and not self.show_level3_complete_text:
            self.show_level3_complete_text = True
            self.level3_complete_timer = 90
            self.story_index = 2
            self.spawn_particles(80, 60, 10, 20)
            return

        if self.show_level3_complete_text:
            self.level3_complete_timer -= 1
            if self.level3_complete_timer <= 0:
                self.level = 3.5
                self.show_level3_complete_text = False
            return

        if pyxel.btnp(pyxel.KEY_UP):
            self.level3_current_lane = max(0, self.level3_current_lane - 1)
        if pyxel.btnp(pyxel.KEY_DOWN):
            self.level3_current_lane = min(2, self.level3_current_lane + 1)
        self.level3_player_y = self.lanes[self.level3_current_lane]

        for car in self.level3_cars:
            car["x"] -= 5
            if pyxel.frame_count % 40 == car.get("id", 0) % 40:
                if random.random() < 0.4:
                    car["target_lane"] = random.randint(0, 2)
            target_y = float(self.lanes[car["target_lane"]])
            car["visual_y"] += (target_y - car["visual_y"]) * 0.1
            if abs(car["visual_y"] - self.lanes[car["target_lane"]]) < 3:
                car["lane"] = car["target_lane"]
        self.level3_cars = [c for c in self.level3_cars if c["x"] > -40]

        if pyxel.frame_count % 22 == 0:
            car_id = pyxel.frame_count
            sl = random.randint(0, 2)
            self.level3_cars.append({"x": 160, "lane": sl, "target_lane": sl,
                                     "visual_y": float(self.lanes[sl]), "id": car_id})

        for item in self.level3_items:
            item["x"] -= 3
        self.level3_items = [i for i in self.level3_items if i["x"] > -20]
        if pyxel.frame_count % 70 == 0:
            # Sterne kommen jetzt deutlich haeufiger vor als Schuh/Helm
            self.level3_items.append({
                "x": 160, "lane": random.randint(0, 2),
                "type": random.choices(
                    ["shoe", "helmet", "star"],
                    weights=[1, 1, 3]
                )[0]
            })

        to_remove = []
        for car in self.level3_cars:
            if car["lane"] == self.level3_current_lane and abs(car["x"] - self.player_x) < 18:
                if self.level3_has_helmet:
                    self.level3_has_helmet = False
                    to_remove.append(car)
                    self.spawn_particles(self.player_x, self.level3_player_y, 9, 12)
                    self.play_sfx(self.SOUND_CRASH)
                    self.trigger_shake(2, 6)
                else:
                    self.level3_lives -= 1
                    self.level3_hit_flash = 30
                    to_remove.append(car)
                    self.spawn_particles(self.player_x, self.level3_player_y, 8, 15)
                    self.play_sfx(self.SOUND_CRASH)
                    self.trigger_shake(4, 10)
                    if self.level3_lives <= 0:
                        self.reset_level3()
                        return
        for car in to_remove:
            if car in self.level3_cars:
                self.level3_cars.remove(car)

        to_remove = []
        for item in self.level3_items:
            if item["lane"] == self.level3_current_lane and abs(item["x"] - self.player_x) < 15:
                self.spawn_particles(item["x"], self.lanes[item["lane"]], 10, 8)
                if item["type"] == "shoe":
                    self.level3_speed = 2
                elif item["type"] == "helmet":
                    self.level3_has_helmet = True
                elif item["type"] == "star":
                    self.level3_lives = min(3, self.level3_lives + 1)
                    self.play_sfx(self.SOUND_STAR)
                to_remove.append(item)
        for item in to_remove:
            if item in self.level3_items:
                self.level3_items.remove(item)

    def _update_mathe(self):
        # Timer
        if self.mathe_correct_timer == 0 and self.mathe_wrong_timer == 0 and not self.quiz_timed_out:
            self.quiz_time_left -= 1
            if self.quiz_time_left <= 0:
                self.quiz_timed_out = True
                self.mathe_answer_color = 8
                self.mathe_wrong_timer = 45
                self.quiz_count += 1
                self.quiz_streak = 0

        if self.mathe_correct_timer > 0:
            self.mathe_correct_timer -= 1
            if self.mathe_correct_timer == 0:
                if self.quiz_count < self.quiz_total:
                    self.generate_quiz_mathe()
                    self.quiz_time_left = self.quiz_time_limit
                    self.quiz_timed_out = False

        if self.mathe_wrong_timer > 0:
            self.mathe_wrong_timer -= 1
            if self.mathe_wrong_timer == 0:
                self.mathe_answer = ""
                self.mathe_answer_color = 7
                self.quiz_timed_out = False
                if self.quiz_count < self.quiz_total:
                    self.generate_quiz_mathe()
                    self.quiz_time_left = self.quiz_time_limit

        if self.mathe_correct_timer == 0 and self.mathe_wrong_timer == 0 and not self.quiz_timed_out:
            for i in range(10):
                if pyxel.btnp(getattr(pyxel, f"KEY_{i}")):
                    self.mathe_answer += str(i)
            if pyxel.btnp(pyxel.KEY_BACKSPACE):
                self.mathe_answer = self.mathe_answer[:-1]
            if self.mathe_answer != "":
                try:
                    val = int(self.mathe_answer)
                    if val == self.mathe_correct_answer:
                        self.mathe_answer_color = 10
                        self.mathe_correct_timer = 35
                        self.quiz_score_mathe += 1
                        self.quiz_streak += 1
                        if self.quiz_streak >= 3:
                            self.quiz_bonus += 1
                            self.quiz_show_bonus = 40
                        self.quiz_count += 1
                        self.spawn_particles(80, 60, 10, 10)
                    elif len(self.mathe_answer) >= len(str(self.mathe_correct_answer)):
                        self.mathe_answer_color = 8
                        self.mathe_wrong_timer = 35
                        self.quiz_count += 1
                        self.quiz_streak = 0
                except ValueError:
                    pass

        if self.quiz_show_bonus > 0:
            self.quiz_show_bonus -= 1

        if self.quiz_count >= self.quiz_total:
            self.level = 4.5

    def _update_mc_quiz(self, fach):
        if self.quiz_show_bonus > 0:
            self.quiz_show_bonus -= 1

        if self.quiz_feedback_timer > 0:
            self.quiz_feedback_timer -= 1
            if self.quiz_feedback_timer == 0:
                self.quiz_selected = -1
                self.quiz_timed_out = False
                if self.quiz_count < self.quiz_total:
                    self.generate_quiz_mc(fach)
                    self.quiz_time_left = self.quiz_time_limit
            return

        # Time limit
        self.quiz_time_left -= 1
        if self.quiz_time_left <= 0 and not self.quiz_timed_out:
            self.quiz_timed_out = True
            self.quiz_selected = -1
            self.quiz_count += 1
            self.quiz_streak = 0
            self.quiz_feedback_timer = 50
            return

        if pyxel.btnp(pyxel.KEY_A):
            self.quiz_selected = 0
            self._check_mc(fach)
        elif pyxel.btnp(pyxel.KEY_B):
            self.quiz_selected = 1
            self._check_mc(fach)
        elif pyxel.btnp(pyxel.KEY_C):
            self.quiz_selected = 2
            self._check_mc(fach)

    def _check_mc(self, fach):
        self.quiz_count += 1
        correct = (self.quiz_selected == self.quiz_correct_index)
        if correct:
            self.quiz_score_geo += 1
            self.quiz_streak += 1
            if self.quiz_streak >= 3:
                self.quiz_bonus += 1
                self.quiz_show_bonus = 50
            self.spawn_particles(80, 70, 10, 12)
        else:
            self.quiz_streak = 0
            self.spawn_particles(80, 70, 8, 8)
        self.quiz_feedback_timer = 50

    def _init_starrain(self):
        self.starrain_player_x = 76
        self.starrain_stars = []
        self.starrain_timer = 0
        self.starrain_score = 0
        self.starrain_missed = 0
        self.starrain_combo = 0
        self.starrain_best_combo = 0
        self.starrain_show_combo = 0
        self.starrain_done = False
        self.starrain_done_timer = 0

    def _update_starrain(self):
        if self.starrain_done:
            self.starrain_done_timer -= 1
            if self.starrain_done_timer <= 0:
                self.level = 7
            return

        self.starrain_timer += 1
        if self.starrain_show_combo > 0:
            self.starrain_show_combo -= 1

        if self.starrain_timer >= self.starrain_max_time:
            self.starrain_done = True
            self.starrain_done_timer = 90
            self.story_index = 6
            self.spawn_particles(80, 60, 10, 25)
            return

        # Spielerbewegung (links/rechts, schnelle Reaktion)
        move_speed = 4
        if pyxel.btn(pyxel.KEY_LEFT):
            self.starrain_player_x = max(4, self.starrain_player_x - move_speed)
        if pyxel.btn(pyxel.KEY_RIGHT):
            self.starrain_player_x = min(128, self.starrain_player_x + move_speed)

        # Schwierigkeit steigt mit der Zeit
        progress = self.starrain_timer / self.starrain_max_time
        spawn_chance = 0.10 + progress * 0.12
        fall_speed_base = 1.3 + progress * 1.4

        if random.random() < spawn_chance:
            self.starrain_stars.append({
                "x": float(random.randint(5, 150)),
                "y": -5.0,
                "speed": fall_speed_base + random.uniform(-0.3, 0.5)
            })

        catch_y_min, catch_y_max = 95, 115
        remaining = []
        for star in self.starrain_stars:
            star["y"] += star["speed"]
            # Eingefangen?
            if (catch_y_min <= star["y"] <= catch_y_max and
                    abs(star["x"] - (self.starrain_player_x + 16)) < 14):
                self.starrain_score += 1
                self.starrain_combo += 1
                self.starrain_best_combo = max(self.starrain_best_combo, self.starrain_combo)
                if self.starrain_combo % 5 == 0:
                    self.starrain_show_combo = 35
                self.spawn_particles(star["x"], star["y"], 10, 10)
                self.play_sfx(self.SOUND_STAR)
                continue
            if star["y"] > 122:
                self.starrain_missed += 1
                self.starrain_combo = 0
                continue
            remaining.append(star)
        self.starrain_stars = remaining

    # =========================================================
    #  JUMP-LEVEL: Plattform-Spruenge nach oben
    # =========================================================
    def _init_jump(self):
        self.jump_platforms = []
        self.jump_stars = []
        self.jump_px = 76.0
        self.jump_py = -30.0   # Fuesse (py+30) stehen exakt auf der Start-Plattform bei y=0
        self.jump_vy = 0.0
        self.jump_vx = 0.0
        self.jump_on_ground = True
        self.jump_camera_y = 85.0   # Start so, dass Boden-Plattform sichtbar ist (passt zu py=-30)
        self.jump_score = 0
        self.jump_target = 30
        self.jump_lives = 3
        self.jump_done = False
        self.jump_done_timer = 0
        self.jump_fail_flash = 0
        self.jump_highest_y = 0
        self.jump_current_platform_y = 0.0
        self.jump_drop_through_y = None   # y der Plattform, die gerade durchfallen wird (None = keine)
        self.jump_floor_y = 0.0           # y der untersten (Start-)Plattform, dort ist Durchfallen gesperrt

        # Start-Plattform (breit, sicher)
        self.jump_platforms.append({"x": 56.0, "y": 0.0, "w": 48})

        # Erste Reihe von Plattformen generieren
        self.jump_next_platform_y = 0.0
        for _ in range(14):
            self._spawn_jump_platform()

    def _spawn_jump_platform(self):
        """Erzeugt die naechste Plattform weiter oben, zunehmend schwieriger
        (schmaler & weiter versetzt), plus mit Chance einen schwebenden Stern.
        Werte sind bewusst grosszuegig gewaehlt, damit bei der aktuellen
        Sprungkraft (siehe _update_jump) JEDE Plattform und JEDER Stern
        mit deutlicher Sicherheitsmarge erreichbar bleibt."""
        gap = random.uniform(18, 26)
        self.jump_next_platform_y -= gap
        y = self.jump_next_platform_y

        # Schwierigkeit steigt mit der Hoehe (negativere y = hoeher),
        # aber Plattformen bleiben immer breit genug zum sicheren Landen
        difficulty = min(abs(y) / 800.0, 1.0)
        width = max(22, int(34 - difficulty * 8))
        x = random.uniform(8, 160 - 8 - width)

        self.jump_platforms.append({"x": x, "y": y, "w": width})

        # Stern niedriger ueber der Plattform schweben lassen, damit er
        # immer sicher im Sprungbogen liegt (hohe Chance auf einen Stern)
        if random.random() < 0.8:
            star_x = x + width / 2 + random.uniform(-5, 5)
            star_y = y - random.uniform(8, 12)
            self.jump_stars.append({"x": star_x, "y": star_y, "taken": False})

    def _update_jump(self):
        if self.jump_done:
            self.jump_done_timer -= 1
            if self.jump_done_timer <= 0:
                self.level = 8
            return

        if self.jump_fail_flash > 0:
            self.jump_fail_flash -= 1

        GRAVITY = 0.42
        JUMP_VELOCITY = -9.2
        MOVE_SPEED = 2.2
        MAX_FALL = 8.0

        # Horizontale Bewegung
        self.jump_vx = 0.0
        if pyxel.btn(pyxel.KEY_LEFT):
            self.jump_vx = -MOVE_SPEED
        if pyxel.btn(pyxel.KEY_RIGHT):
            self.jump_vx = MOVE_SPEED
        self.jump_px += self.jump_vx
        self.jump_px = max(2, min(160 - 18, self.jump_px))

        # Springen
        if self.jump_on_ground and (pyxel.btnp(pyxel.KEY_SPACE) or pyxel.btnp(pyxel.KEY_UP)):
            self.jump_vy = JUMP_VELOCITY
            self.jump_on_ground = False

        # Bewusst nach unten durchfallen: haelt man UNTEN gedrueckt,
        # faellt der Spieler durch die aktuelle Plattform durch, um
        # gezielt wieder nach unten gehen zu koennen. Wir merken uns NUR
        # diese eine Plattform als "durchlaessig" (per y-Koordinate), damit
        # tiefer liegende Plattformen weiterhin normal zum Landen genutzt
        # werden koennen. Auf der untersten (Start-)Plattform ist das
        # Durchfallen gesperrt, da dort nichts zum Landen mehr kommt.
        drop_through = pyxel.btn(pyxel.KEY_DOWN)
        on_floor = abs(self.jump_current_platform_y - self.jump_floor_y) < 1
        if drop_through and self.jump_on_ground and not on_floor:
            self.jump_drop_through_y = self.jump_current_platform_y
            self.jump_on_ground = False
            self.jump_vy = 1.5
        else:
            drop_through = False

        # Schwerkraft
        self.jump_vy += GRAVITY
        self.jump_vy = min(self.jump_vy, MAX_FALL)
        self.jump_py += self.jump_vy

        # Spielerfuesse (fuer Kollision mit Plattformen)
        feet_y = self.jump_py + 30
        player_w = 16
        landed_this_frame = False

        if self.jump_vy >= 0:  # nur beim Fallen auf Plattformen pruefen
            for plat in self.jump_platforms:
                plat_top = plat["y"]
                # Die Plattform, durch die wir gerade gezielt durchfallen,
                # wird ignoriert, bis wir sie tatsaechlich verlassen haben
                if (self.jump_drop_through_y is not None and
                        abs(plat_top - self.jump_drop_through_y) < 1):
                    continue
                if (feet_y >= plat_top and feet_y <= plat_top + 8 and
                        self.jump_px + player_w > plat["x"] and
                        self.jump_px < plat["x"] + plat["w"]):
                    if drop_through:
                        # Taste wird weiterhin gehalten: sofort auch durch
                        # diese Plattform durchfallen, statt erst kurz zu
                        # landen (verhindert "Treppen-Ruckeln" und falsche
                        # Absturz-Wertung beim laengeren Herabsteigen)
                        self.jump_drop_through_y = plat_top
                        continue
                    # gelandet!
                    self.jump_py = plat_top - 30
                    self.jump_vy = 0.0
                    self.jump_on_ground = True
                    landed_this_frame = True
                    self.jump_current_platform_y = plat_top
                    self.jump_drop_through_y = None
                    break

        if not landed_this_frame and self.jump_on_ground:
            # War auf einer Plattform, prueft ob er sie verlassen hat (Fall beginnt)
            still_on_any = False
            for plat in self.jump_platforms:
                plat_top = plat["y"]
                if (abs((self.jump_py + 30) - plat_top) < 2 and
                        self.jump_px + player_w > plat["x"] and
                        self.jump_px < plat["x"] + plat["w"]):
                    still_on_any = True
                    self.jump_current_platform_y = plat_top
                    break
            if not still_on_any:
                self.jump_on_ground = False

        # Absturz-Check: faellt zu tief unter die hoechste je erreichte Plattform.
        # Toleranz vergroessert, da man jetzt bewusst mit UNTEN durch
        # Plattformen fallen und sich freier nach unten bewegen kann.
        if not self.jump_on_ground and (self.jump_py + 30) > (self.jump_highest_y + 220):
            self.jump_lives -= 1
            self.jump_fail_flash = 25
            self.play_sfx(self.SOUND_CRASH)
            self.spawn_particles(self.jump_px + 8, 60, 8, 14)
            self.trigger_shake(4, 10)
            if self.jump_lives <= 0:
                self.jump_done = True
                self.jump_done_timer = 90
                self.story_index = 7
                return
            # Auf die zuletzt sichere Plattform respawnen
            safe_y = self.jump_highest_y
            self.jump_py = safe_y - 30
            self.jump_vy = 0.0
            self.jump_on_ground = True
            self.jump_current_platform_y = safe_y
            self.jump_drop_through_y = None

        # Hoechsten Punkt tracken (fuer Fail-Distanz & Kamera)
        if self.jump_py < self.jump_highest_y:
            self.jump_highest_y = self.jump_py

        # ── Kamera: Spieler UND aktuelle Standplattform bleiben immer sichtbar ──
        # Wir berechnen einen Zielwert, der den Spieler bei ~45% der Bildhoehe
        # haelt, begrenzen die Bewegung aber so, dass die Plattform, auf der er
        # zuletzt stand (oder gerade steht), nicht aus dem Sichtfeld faellt.
        # Das verhindert sowohl ein zu schnelles "Wegscrollen" nach oben als
        # auch ein Haengenbleiben weit ausserhalb des Bildes nach einem Sturz.
        desired_camera = -self.jump_py + 55

        # Referenzplattform: die, auf der der Spieler aktuell steht, sonst
        # die letzte sichere (jump_current_platform_y)
        ref_platform_y = self.jump_current_platform_y
        # Kamera darf die Referenzplattform nicht ueber screen_y=100 schieben
        # (zu weit unten) und nicht unter screen_y=15 (zu weit oben/raus)
        min_camera_for_platform = 15 - ref_platform_y   # Plattform nicht zu weit oben
        max_camera_for_platform = 100 - ref_platform_y  # Plattform nicht zu weit unten

        desired_camera = max(min_camera_for_platform, min(max_camera_for_platform, desired_camera))

        # Sanftes Nachfuehren statt hartem Sprung, fuehlt sich besser an
        cam_diff = desired_camera - self.jump_camera_y
        self.jump_camera_y += cam_diff * 0.18

        # Sicherheitsnetz: Spieler selbst darf NIE komplett aus dem Bild
        # verschwinden, egal was die Plattform-Logik oben berechnet hat.
        player_screen_y = self.jump_py + self.jump_camera_y
        if player_screen_y < -10:
            self.jump_camera_y += (-10 - player_screen_y)
        elif player_screen_y > 95:
            self.jump_camera_y += (95 - player_screen_y)

        # Sterne einsammeln
        for star in self.jump_stars:
            if star["taken"]:
                continue
            dx = (self.jump_px + 8) - star["x"]
            dy = (self.jump_py + 16) - star["y"]
            if dx * dx + dy * dy < 13 * 13:
                star["taken"] = True
                self.jump_score += 1
                self.spawn_particles(star["x"], star["y"], 10, 12)
                self.play_sfx(self.SOUND_STAR)
                if self.jump_score >= self.jump_target:
                    self.jump_done = True
                    self.jump_done_timer = 100
                    self.story_index = 7
                    self.spawn_particles(80, 60, 10, 30)
                    return

        # Neue Plattformen nachgenerieren, wenn Spieler sich naehert
        while self.jump_next_platform_y > self.jump_py - 500:
            self._spawn_jump_platform()

        # Alte Plattformen/Sterne weit unterhalb entfernen (Performance)
        cutoff = self.jump_py + 250
        self.jump_platforms = [p for p in self.jump_platforms if p["y"] < cutoff]
        self.jump_stars = [s for s in self.jump_stars if s["y"] < cutoff]

    def _update_finale(self):
        for _ in range(4):
            self.confetti.append({
                "x": random.randint(0, pyxel.width - 1),
                "y": 0,
                "color": random.randint(8, 15),
                "speed": random.uniform(1, 2.5)
            })
        for p in self.confetti:
            p["y"] += p["speed"]
        self.confetti = [p for p in self.confetti if p["y"] < pyxel.height]

        if pyxel.btnp(pyxel.KEY_R):
            self._full_reset()

    def _full_reset(self):
        self.level = 1
        self.outfit = 0
        self.story_index = 0
        self.lives = 3
        self.level3_lives = 3
        self.timer = 0
        self.level3_timer = 0
        self.quiz_count = 0
        self.quiz_score_mathe = 0
        self.quiz_score_geo = 0
        self.quiz_streak = 0
        self.quiz_bonus = 0
        self.geo_asked_questions = []
        self.geo_pool_order = []
        self.starrain_score = 0
        self.starrain_missed = 0
        self.starrain_combo = 0
        self.starrain_best_combo = 0
        self.starrain_done = False
        self.starrain_stars = []
        self.jump_score = 0
        self.jump_lives = 3
        self.jump_done = False
        self.jump_platforms = []
        self.jump_stars = []
        self.confetti = []
        self.particles = []
        self.cars = []
        self.items = []
        self.level3_cars = []
        self.level3_items = []
        self.reset_level2()
        self.reset_level3()

    # =========================================================
    #  DRAW
    # =========================================================
    def draw(self):
        pyxel.cls(0)

        # Screen-Shake: kleiner Kamera-Versatz bei Treffern, macht Crashes
        # spuerbarer ohne das Spiel unspielbar zu machen.
        shake_x, shake_y = 0, 0
        if self.shake_timer > 0:
            shake_x = random.randint(-self.shake_strength, self.shake_strength)
            shake_y = random.randint(-self.shake_strength, self.shake_strength)
            pyxel.camera(shake_x, shake_y)
        else:
            pyxel.camera(0, 0)

        if self.level == 1:
            self._draw_title()

        elif self.level == 1.5:
            self._draw_instruction("CASTING",
                ["Weiche den Autos aus!",
                 "Helm = extra Schutzschild",
                 "Schuh = Geschwindigkeit",
                 "Stern = Leben +1",
                 "Du hast 3 Leben!"])

        elif self.level == 2:
            self._draw_driving(
                timer_attr="timer", max_time_attr="max_time",
                cars_attr="cars", items_attr="items",
                lane_attr="current_lane", py_attr="player_y",
                helmet_attr="has_helmet", speed_attr="speed",
                lives_attr="lives", flash_attr="hit_flash",
                complete_attr="show_level_complete_text",
                next_stage_name="Vorrunde!"
            )

        elif self.level == 2.5:
            self._draw_instruction("VORRUNDE",
                ["Die Autos kommen",
                 "jetzt viel schneller!",
                 "und wechseln die Spur!",
                 "Bleib am Leben!"])

        elif self.level == 3:
            self._draw_level3()

        elif self.level == 3.5:
            self._draw_instruction("HALBFINALE",
                ["Jetzt kommen 2 Faecher:",
                 "Mathe: Antwort eintippen",
                 "Geographie:",
                 "A / B / C druecken",
                 "Streak x3 = Bonuspunkt!"])

        elif self.level == 4:
            self._draw_mathe()

        elif self.level == 4.5:
            self._draw_score_transition("GEOGRAPHIE",
                f"Mathe: {self.quiz_score_mathe}/{self.quiz_total} Punkte",
                f"Bonus: +{self.quiz_bonus}")

        elif self.level == 5:
            self._draw_mc_screen("Geographie")

        elif self.level == 5.5:
            self._draw_score_transition("STERNENREGEN",
                f"Geo: {self.quiz_score_geo}/{self.quiz_total} Punkte",
                "Du musst alle Sterne fangen!",
                control_lines=["Pfeiltasten Links/Rechts", "um dich zu bewegen!"])

        elif self.level == 6.5:
            self._draw_starrain()

        elif self.level == 7:
            self._draw_score_transition("SPRUNG-CHALLENGE",
                f"Sterne gefangen: {self.starrain_score}",
                "Springe und fange die Sterne ein!",
                control_lines=["Links/Rechts laufen,", "LEERTASTE = springen!"])

        elif self.level == 7.5:
            self._draw_jump()

        elif self.level == 8:
            self._draw_zeugnis()

        # Particles always on top
        self._draw_particles()

        if self.shake_timer > 0:
            pyxel.camera(0, 0)

    # ─── Title Screen ─────────────────────────────────────────
    def _draw_title(self):
        pyxel.bltm(0, 0, 0, 0, 0, 1024, 1024, 0)
        pyxel.text(53, 2, "BRAIN & BEAUTY", 1)
        pyxel.text(53, 25, "Outfit waehlen:", 1)
        pyxel.text(53, 107, "ENTER = Start", 7)
        px, py = 64, 40
        pyxel.blt(px, py, 0, 0, 16, 32, 32, 8)
        pyxel.blt(px + 8, py + 16, 0, self.outfit * 16, 48, 16, 16, 7)
        mid_y = py + 16
        pyxel.line(px - 8, mid_y - 4, px - 12, mid_y, 7)
        pyxel.line(px - 8, mid_y + 4, px - 12, mid_y, 7)
        pyxel.line(px + 40, mid_y - 4, px + 44, mid_y, 7)
        pyxel.line(px + 40, mid_y + 4, px + 44, mid_y, 7)

    # ─── Generic instruction screen ───────────────────────────
    def _draw_instruction(self, title, lines):
        pyxel.rectb(2, 2, 156, 116, 7)
        pyxel.rectb(3, 3, 154, 114, 1)
        cx = (160 - len(f"-- {title} --") * 4) // 2
        pyxel.text(cx, 8, f"-- {title} --", 10)
        for i, line in enumerate(lines):
            pyxel.text(8, 24 + i * 12, line, 7)
        if self.blink < 40:
            pyxel.text(40, 108, "ENTER = Start", 7)

    # ─── Score transition screen ──────────────────────────────
    def _draw_score_transition(self, title, score_line, hint_line, control_lines=None):
        pyxel.rectb(2, 2, 156, 116, 7)
        pyxel.rectb(3, 3, 154, 114, 1)
        cx = (160 - len(f"-- {title} --") * 4) // 2
        pyxel.text(cx, 8, f"-- {title} --", 10)
        pyxel.text(10, 40, score_line, 7)
        pyxel.text(10, 55, hint_line, 10)
        if control_lines is None:
            control_lines = ["Druecke A / B / C", "fuer deine Antwort!"]
        for i, line in enumerate(control_lines):
            pyxel.text(10, 70 + i * 10, line, 7)
        if self.blink < 40:
            pyxel.text(40, 108, "ENTER = Start", 7)

    # ─── Driving draw ─────────────────────────────────────────
    def _draw_driving(self, timer_attr, max_time_attr, cars_attr, items_attr,
                      lane_attr, py_attr, helmet_attr, speed_attr,
                      lives_attr, flash_attr, complete_attr, next_stage_name):
        if not getattr(self, complete_attr):
            # Flash overlay on hit
            if getattr(self, flash_attr) > 0 and (getattr(self, flash_attr) // 5) % 2 == 0:
                pyxel.cls(8)
            else:
                pyxel.bltm(0, 0, 1, 0, 0, 256, 256)

            stage = self.story_stages[self.story_index]
            pyxel.text(35, 2, stage, 0)

            # Player sprite
            py = getattr(self, py_attr)
            pyxel.blt(self.player_x, py, 0, 0, 16, 32, 32, 8)
            pyxel.blt(self.player_x + 8, py + 16, 0, self.outfit * 16, 48, 16, 16, 7)

            # Cars
            for car in getattr(self, cars_attr):
                pyxel.blt(car["x"], self.lanes[car["lane"]], 0, 32, 16, 32, 32, 8)

            # Items
            for item in getattr(self, items_attr):
                iy = self.lanes[item["lane"]]
                if item["type"] == "shoe":
                    pyxel.blt(item["x"], iy + 4, 0, 64, 32, 16, 16, 8)
                elif item["type"] == "helmet":
                    pyxel.blt(item["x"], iy + 4, 0, 48, 48, 16, 16, 8)
                elif item["type"] == "star":
                    # Draw a simple star with pixels
                    sx, sy = item["x"], iy + 8
                    pyxel.pset(sx + 4, sy, 10)
                    pyxel.pset(sx + 4, sy + 2, 10)
                    pyxel.pset(sx + 4, sy + 4, 10)
                    pyxel.pset(sx + 2, sy + 2, 10)
                    pyxel.pset(sx + 6, sy + 2, 10)

            # HUD – Zeit: nur der farbige Balken wird angezeigt,
            # der Text "Zeit: X" bleibt ausgeblendet.
            elapsed = getattr(self, timer_attr)
            total = getattr(self, max_time_attr)
            remaining = total - elapsed
            bar_w = int((remaining / total) * 80)
            pyxel.rect(75, 2, 80, 4, 1)
            pyxel.rect(75, 2, bar_w, 4, 10 if remaining > total // 3 else 8)

            # Lives (3 grosse, gut sichtbare Herzen oben links)
            for i in range(3):
                hx = 3 + i * 9
                hy = 2
                if i < getattr(self, lives_attr):
                    # Gefuelltes Herz: rot mit weisser Umrandung
                    pyxel.rect(hx, hy, 7, 6, 8)
                    pyxel.pset(hx, hy - 1, 8)
                    pyxel.pset(hx + 6, hy - 1, 8)
                    pyxel.rectb(hx - 1, hy - 1, 9, 8, 7)
                else:
                    # Leeres Herz: nur dunkler Umriss
                    pyxel.rectb(hx - 1, hy - 1, 9, 8, 1)

            # Power-up-Status sauber untereinander (schwarze Schrift)
            hud_y = 14
            if getattr(self, helmet_attr):
                pyxel.text(3, hud_y, "[HELM]", 0)
                hud_y += 8
            if getattr(self, speed_attr) > 1:
                pyxel.text(3, hud_y, "[BOOST]", 0)
        else:
            pyxel.rectb(2, 2, 156, 116, 7)
            pyxel.rectb(3, 3, 154, 114, 10)
            t = "LEVEL GESCHAFFT!"
            pyxel.text((160 - len(t) * 4) // 2, 50, t, 10)
            pyxel.text(20, 65, f"Weiter: {next_stage_name}", 7)

    def _draw_level3(self):
        if not self.show_level3_complete_text:
            if self.level3_hit_flash > 0 and (self.level3_hit_flash // 5) % 2 == 0:
                pyxel.cls(8)
            else:
                pyxel.bltm(0, 0, 1, 0, 0, 256, 256)

            pyxel.text(35, 2, self.story_stages[self.story_index], 0)
            py = self.level3_player_y
            pyxel.blt(self.player_x, py, 0, 0, 16, 32, 32, 8)
            pyxel.blt(self.player_x + 8, py + 16, 0, self.outfit * 16, 48, 16, 16, 7)

            for car in self.level3_cars:
                pyxel.blt(car["x"], int(car["visual_y"]), 0, 32, 16, 32, 32, 8)

            for item in self.level3_items:
                iy = self.lanes[item["lane"]]
                if item["type"] == "shoe":
                    pyxel.blt(item["x"], iy + 4, 0, 64, 32, 16, 16, 8)
                elif item["type"] == "helmet":
                    pyxel.blt(item["x"], iy + 4, 0, 48, 48, 16, 16, 8)
                elif item["type"] == "star":
                    sx, sy = item["x"], iy + 8
                    pyxel.pset(sx + 4, sy, 10)
                    pyxel.pset(sx + 4, sy + 2, 10)
                    pyxel.pset(sx + 4, sy + 4, 10)
                    pyxel.pset(sx + 2, sy + 2, 10)
                    pyxel.pset(sx + 6, sy + 2, 10)

            # Zeit: nur der farbige Balken wird angezeigt,
            # der Text "Zeit: X" bleibt ausgeblendet.
            elapsed = self.level3_timer
            total = self.level3_max_time
            remaining = total - elapsed
            bar_w = int((remaining / total) * 80)
            pyxel.rect(75, 2, 80, 4, 1)
            pyxel.rect(75, 2, bar_w, 4, 10 if remaining > total // 3 else 8)

            # Lives (3 grosse, gut sichtbare Herzen)
            for i in range(3):
                hx = 3 + i * 9
                hy = 2
                if i < self.level3_lives:
                    pyxel.rect(hx, hy, 7, 6, 8)
                    pyxel.pset(hx, hy - 1, 8)
                    pyxel.pset(hx + 6, hy - 1, 8)
                    pyxel.rectb(hx - 1, hy - 1, 9, 8, 7)
                else:
                    pyxel.rectb(hx - 1, hy - 1, 9, 8, 1)

            # Power-ups untereinander (schwarze Schrift)
            hud_y = 14
            if self.level3_has_helmet:
                pyxel.text(3, hud_y, "[HELM]", 0)
                hud_y += 8
            if self.level3_speed > 1:
                pyxel.text(3, hud_y, "[BOOST]", 0)
        else:
            pyxel.rectb(2, 2, 156, 116, 7)
            pyxel.rectb(3, 3, 154, 114, 10)
            t = "LEVEL GESCHAFFT!"
            pyxel.text((160 - len(t) * 4) // 2, 50, t, 10)
            pyxel.text(15, 65, "Weiter zum Halbfinale!", 7)

    # ─── Mathe screen ─────────────────────────────────────────
    def _draw_mathe(self):
        pyxel.bltm(0, 0, 2, 0, 0, 256, 256)
        pyxel.text(5, 2, "-- MATHEMATIK --", 10)
        pyxel.text(5, 10, f"Frage: {min(self.quiz_count+1, self.quiz_total)}/{self.quiz_total}", 7)

        # Progress bar
        pyxel.rect(5, 18, 150, 3, 1)
        pyxel.rect(5, 18, min(self.quiz_count, self.quiz_total) * 25, 3, 10)

        # Time bar
        tbar = int((self.quiz_time_left / self.quiz_time_limit) * 150)
        tcolor = 10 if self.quiz_time_left > self.quiz_time_limit // 3 else 8
        pyxel.rect(5, 22, 150, 3, 1)
        pyxel.rect(5, 22, tbar, 3, tcolor)

        # Spielfigur rechts, ausserhalb der Frage-Box
        fig_x = 122
        pyxel.blt(fig_x, 70, 0, 0, 16, 32, 32, 8)
        pyxel.blt(fig_x + 8, 86, 0, self.outfit * 16, 48, 16, 16, 7)

        if self.quiz_count < self.quiz_total:
            pyxel.rect(4, 36, 112, 30, 1)
            pyxel.rectb(4, 36, 112, 30, 7)
            pyxel.text(8, 40, self.quiz_question, 7)
            if self.quiz_timed_out:
                pyxel.text(8, 52, f"Zeit! Antwort: {self.mathe_correct_answer}", 8)
            else:
                pyxel.text(8, 52, "Antwort: " + self.mathe_answer + ("_" if self.blink < 30 else " "), self.mathe_answer_color)

            # Streak display
            if self.quiz_streak >= 2:
                pyxel.text(5, 70, f"Streak: {self.quiz_streak}!", 9)
            if self.quiz_show_bonus > 0:
                pyxel.text(5, 80, "BONUS +1!", 10)

    # ─── MC Quiz screen ───────────────────────────────────────
    def _draw_mc_screen(self, fach):
        pyxel.bltm(0, 0, 2, 0, 0, 256, 256)
        pyxel.text(5, 2, f"-- {fach.upper()} --", 10)
        pyxel.text(5, 10, f"Frage: {min(self.quiz_count+1, self.quiz_total)}/{self.quiz_total}", 7)

        # Progress bar
        pyxel.rect(5, 18, 150, 3, 1)
        pyxel.rect(5, 18, min(self.quiz_count, self.quiz_total) * 25, 3, 10)

        # Time bar
        tbar = int((self.quiz_time_left / self.quiz_time_limit) * 150)
        tcolor = 10 if self.quiz_time_left > self.quiz_time_limit // 3 else 8
        pyxel.rect(5, 22, 150, 3, 1)
        pyxel.rect(5, 22, tbar, 3, tcolor)

        if self.quiz_count < self.quiz_total:
            # Question box
            pyxel.rect(2, 27, 156, 14, 1)
            pyxel.rectb(2, 27, 156, 14, 7)
            # Word wrap question if needed
            q = self.quiz_question
            if len(q) > 28:
                pyxel.text(5, 30, q[:28], 7)
                pyxel.text(5, 37, q[28:], 7)
            else:
                pyxel.text(5, 32, q, 7)

            # Spielfigur rechts neben den Antwortfeldern
            fig_x = 110
            pyxel.blt(fig_x, 44, 0, 0, 16, 32, 32, 8)
            pyxel.blt(fig_x + 8, 60, 0, self.outfit * 16, 48, 16, 16, 7)

            choices_data = [
                (self.quiz_choices[0], 0),
                (self.quiz_choices[1], 1),
                (self.quiz_choices[2], 2),
            ]
            y_positions = [46, 64, 82]
            labels_abc = ["A)", "B)", "C)"]
            box_w = 100

            for (text, cidx), y in zip(choices_data, y_positions):
                # Background color
                if self.quiz_selected == cidx and self.quiz_feedback_timer > 0:
                    bg = 3 if cidx == self.quiz_correct_index else 2
                elif cidx == self.quiz_correct_index and self.quiz_selected != -1 and self.quiz_feedback_timer > 0:
                    bg = 3
                elif self.quiz_timed_out and cidx == self.quiz_correct_index:
                    bg = 3
                else:
                    bg = 1
                txt_col = 7 if bg != 7 else 0
                pyxel.rect(2, y, box_w, 15, bg)
                pyxel.rectb(2, y, box_w, 15, 7)
                pyxel.text(5, y + 4, labels_abc[choices_data.index((text, cidx))] + " " + text, txt_col)

            if self.quiz_timed_out:
                pyxel.text(15, 100, "ZEIT ABGELAUFEN!", 8)
            else:
                pyxel.text(5, 100, "A / B / C druecken", 7)

            # Streak
            if self.quiz_streak >= 2:
                pyxel.text(5, 108, f"Streak {self.quiz_streak}x!", 9)
            if self.quiz_show_bonus > 0:
                pyxel.text(90, 108, "BONUS +1!", 10)

    # ─── Sternenregen-Finale Screen ────────────────────────────
    def _draw_starrain(self):
        # Nachthimmel-Hintergrund (Verlauf simuliert durch zwei Farben)
        pyxel.rect(0, 0, 160, 90, 1)
        pyxel.rect(0, 90, 160, 30, 0)

        if not self.starrain_done:
            # Hintergrund-Deko-Sterne (statisch, schimmern leicht)
            for i in range(12):
                sx = (i * 37 + 11) % 155 + 2
                sy = (i * 23 + 5) % 70 + 3
                if (pyxel.frame_count // 8 + i) % 5 != 0:
                    pyxel.pset(sx, sy, 7)

            # Fallende Sterne (Fangobjekte)
            for star in self.starrain_stars:
                sx, sy = int(star["x"]), int(star["y"])
                col = 10
                pyxel.pset(sx, sy - 2, col)
                pyxel.pset(sx, sy + 2, col)
                pyxel.pset(sx - 2, sy, col)
                pyxel.pset(sx + 2, sy, col)
                pyxel.pset(sx, sy, col)
                pyxel.pset(sx - 1, sy - 1, col)
                pyxel.pset(sx + 1, sy - 1, col)
                pyxel.pset(sx - 1, sy + 1, col)
                pyxel.pset(sx + 1, sy + 1, col)

            # Boden-Streifen, damit klar ist wo man faengt
            pyxel.rect(0, 95, 160, 1, 5)

            # Spielfigur (folgt starrain_player_x)
            px = self.starrain_player_x
            pyxel.blt(px, 88, 0, 0, 16, 32, 32, 8)
            pyxel.blt(px + 8, 104, 0, self.outfit * 16, 48, 16, 16, 7)

            # HUD oben
            pyxel.rect(0, 0, 160, 11, 1)
            pyxel.text(3, 2, f"Sterne: {self.starrain_score}", 10)
            remaining = max(0, self.starrain_max_time - self.starrain_timer)
            pyxel.text(85, 2, f"Zeit: {remaining // 60 + 1}s", 7)

            # Zeit-Fortschrittsbalken
            bar_w = int((remaining / self.starrain_max_time) * 150)
            pyxel.rect(5, 9, 150, 2, 5)
            pyxel.rect(5, 9, bar_w, 2, 10 if remaining > self.starrain_max_time // 3 else 8)

            # Combo-Anzeige
            if self.starrain_combo >= 3:
                pyxel.text(3, 14, f"Combo x{self.starrain_combo}!", 9)
            if self.starrain_show_combo > 0:
                pyxel.text(55, 50, "SUPER!", 10)

            pyxel.text(3, 112, "<- Links / Rechts ->", 7)
        else:
            # Ergebnis-Anzeige
            pyxel.rectb(2, 2, 156, 116, 7)
            pyxel.rectb(3, 3, 154, 114, 10)
            t = "STERNENREGEN VORBEI!"
            pyxel.text((160 - len(t) * 4) // 2, 30, t, 10)
            pyxel.text(35, 50, f"Sterne gefangen: {self.starrain_score}", 7)
            pyxel.text(35, 62, f"Beste Combo: {self.starrain_best_combo}", 7)
            pyxel.text(35, 74, f"Verpasst: {self.starrain_missed}", 7)
            pyxel.text(20, 92, "Weiter zum Zeugnis...", 7)

    # ─── Sprung-Challenge Screen ────────────────────────────────
    def _draw_jump(self):
        # Himmel-Hintergrund mit Hoehen-Verlauf (heller je hoeher gesprungen)
        pyxel.rect(0, 0, 160, 120, 6)
        pyxel.rect(0, 60, 160, 60, 12)

        if not self.jump_done:
            cam = self.jump_camera_y

            # Deko-Wolken im Hintergrund (leicht parallax, looped)
            for i in range(6):
                wx = (i * 53 + 17) % 170 - 10
                wy = (i * 41 + int(cam * 0.3)) % 140 - 10
                pyxel.rect(wx, wy, 14, 5, 7)
                pyxel.rect(wx + 3, wy - 2, 8, 4, 7)

            # Plattformen zeichnen
            for plat in self.jump_platforms:
                screen_y = plat["y"] + cam
                if -10 <= screen_y <= 130:
                    px = int(plat["x"])
                    pw = int(plat["w"])
                    # Aktuelle Standplattform deutlich hervorheben, damit
                    # immer klar ist, wo der Spieler steht
                    is_current = (abs(plat["y"] - self.jump_current_platform_y) < 1
                                  and self.jump_on_ground)
                    base_col = 11 if is_current else 3
                    top_col = 7 if is_current else 11
                    pyxel.rect(px, int(screen_y), pw, 6, base_col)
                    pyxel.rect(px, int(screen_y), pw, 2, top_col)

            # Sterne zeichnen
            for star in self.jump_stars:
                if star["taken"]:
                    continue
                screen_y = star["y"] + cam
                if -10 <= screen_y <= 130:
                    sx, sy = int(star["x"]), int(screen_y)
                    col = 10
                    pyxel.pset(sx, sy - 3, col)
                    pyxel.pset(sx, sy - 1, col)
                    pyxel.pset(sx, sy + 1, col)
                    pyxel.pset(sx - 2, sy - 1, col)
                    pyxel.pset(sx + 2, sy - 1, col)
                    pyxel.pset(sx - 1, sy - 2, col)
                    pyxel.pset(sx + 1, sy - 2, col)
                    pyxel.pset(sx - 1, sy, col)
                    pyxel.pset(sx + 1, sy, col)

            # Spieler zeichnen (mit rotem Flash bei Sturz)
            screen_py = self.jump_py + cam
            if self.jump_fail_flash > 0 and (self.jump_fail_flash // 4) % 2 == 0:
                pyxel.pal(8, 8)
            pyxel.blt(int(self.jump_px), int(screen_py), 0, 0, 16, 32, 32, 8)
            pyxel.blt(int(self.jump_px) + 8, int(screen_py) + 16, 0, self.outfit * 16, 48, 16, 16, 7)
            pyxel.pal()

            # Kleiner Pfeil-Indikator am Bildschirmrand, falls der Spieler
            # (z.B. beim sehr hohen Sprung) trotzdem mal knapp aus dem
            # sichtbaren Bereich geraet – zeigt, in welche Richtung er ist.
            if screen_py < -4:
                pyxel.tri(int(self.jump_px) + 8, 2, int(self.jump_px) + 2, 8,
                          int(self.jump_px) + 14, 8, 10)
            elif screen_py > 112:
                pyxel.tri(int(self.jump_px) + 8, 118, int(self.jump_px) + 2, 112,
                          int(self.jump_px) + 14, 112, 8)

            # HUD oben
            pyxel.rect(0, 0, 160, 11, 1)
            pyxel.text(3, 2, f"Sterne: {self.jump_score}/{self.jump_target}", 10)

            # Sterne-Fortschrittsbalken
            bar_w = int((self.jump_score / self.jump_target) * 60)
            pyxel.rect(95, 3, 60, 4, 5)
            pyxel.rect(95, 3, bar_w, 4, 10)

            # Leben (Herzen) oben rechts-mittig im HUD
            for i in range(3):
                hx = 3 + i * 9
                hy = 13
                if i < self.jump_lives:
                    pyxel.rect(hx, hy, 7, 6, 8)
                    pyxel.pset(hx, hy - 1, 8)
                    pyxel.pset(hx + 6, hy - 1, 8)
                    pyxel.rectb(hx - 1, hy - 1, 9, 8, 7)
                else:
                    pyxel.rectb(hx - 1, hy - 1, 9, 8, 1)

            pyxel.text(3, 112, "<-Links/Rechts-> SPACE=Springen", 0)
        else:
            pyxel.rect(2, 2, 156, 116, 0)
            pyxel.rectb(2, 2, 156, 116, 7)
            pyxel.rectb(3, 3, 154, 114, 10)
            success = self.jump_score >= self.jump_target
            t = "GESCHAFFT!" if success else "LEBEN VERLOREN!"
            pyxel.text((160 - len(t) * 4) // 2, 30, t, 10 if success else 8)
            pyxel.text(35, 50, f"Sterne gefangen: {self.jump_score}", 7)
            pyxel.text(35, 62, f"Ziel: {self.jump_target} Sterne", 7)
            pyxel.text(20, 84, "Weiter zum Zeugnis...", 7)

    # ─── Particles ────────────────────────────────────────────
    def _draw_particles(self):
        for p in self.particles:
            if 0 <= p["x"] < pyxel.width and 0 <= p["y"] < pyxel.height:
                pyxel.pset(int(p["x"]), int(p["y"]), p["color"])

    # ─── Zeugnis (final score) ────────────────────────────────
    def _draw_zeugnis(self):
        pyxel.rect(5, 5, 150, 110, 7)
        pyxel.rectb(5, 5, 150, 110, 1)
        pyxel.rectb(7, 7, 146, 106, 1)
        pyxel.text(50, 9, "ZEUGNIS", 1)
        pyxel.text(22, 16, "Brain & Beauty Show", 1)
        pyxel.line(10, 22, 150, 22, 1)

        def note(score, total):
            pct = score / total if total > 0 else 0
            if pct >= 0.9:    return "1"
            elif pct >= 0.75: return "2"
            elif pct >= 0.6:  return "3"
            elif pct >= 0.45: return "4"
            elif pct >= 0.3:  return "5"
            else:             return "6"

        # Bonuspunkte gleichmaessig auf die zwei Faecher verteilen
        bonus = self.quiz_bonus
        mathe_score = min(self.quiz_score_mathe + (bonus // 2), self.quiz_total)
        geo_score   = min(self.quiz_score_geo   + (bonus - bonus // 2), self.quiz_total)

        mathe_n  = note(mathe_score, self.quiz_total)
        geo_n    = note(geo_score,   self.quiz_total)

        pyxel.text(10, 26, "Fach",  1)
        pyxel.text(88, 26, "Pkt",   1)
        pyxel.text(118, 26, "Note", 1)
        pyxel.line(10, 33, 150, 33, 1)

        faecher = [
            ("Mathematik", mathe_score, self.quiz_total, mathe_n),
            ("Geographie", geo_score,   self.quiz_total, geo_n),
        ]
        y = 37
        for name, score, total, n in faecher:
            pyxel.text(10, y, name, 0)
            pyxel.text(88, y, f"{score}/{total}", 0)
            pyxel.text(120, y, n, 0)
            y += 9

        if bonus > 0:
            pyxel.text(10, y, f"Bonus-Punkte: +{bonus}", 2)
            y += 8

        pyxel.line(10, y + 1, 150, y + 1, 1)
        y += 5

        # Sternenregen & Sprung-Challenge als Highscore-Mini-Games
        pyxel.text(10, y, f"Sternenregen: {self.starrain_score} Sterne", 0)
        y += 8
        pyxel.text(10, y, f"(Beste Combo: {self.starrain_best_combo}x)", 0)
        y += 8
        jump_status = "GESCHAFFT!" if self.jump_score >= self.jump_target else "Nicht geschafft"
        pyxel.text(10, y, f"Sprung-Challenge: {self.jump_score}/{self.jump_target}", 0)
        y += 8
        pyxel.text(10, y, f"({jump_status})", 2 if self.jump_score >= self.jump_target else 8)
        y += 9

        pyxel.line(10, y, 150, y, 1)
        gesamt = mathe_score + geo_score
        gesamt_total = self.quiz_total * 2
        gesamt_note = note(gesamt, gesamt_total)
        pyxel.text(10, y + 4, "Gesamt", 1)
        pyxel.text(88, y + 4, f"{gesamt}/{gesamt_total}", 1)
        pyxel.text(120, y + 4, gesamt_note, 1)

        titles = {
            "1": "Miss Brain & Beauty!",
            "2": "Vizemeisterin!",
            "3": "Gut gemacht!",
            "4": "Weiter ueben!",
            "5": "Nicht aufgeben!",
            "6": "Naechstes Mal!"
        }
        msg = titles.get(gesamt_note, "Toll gemacht!")
        cx = (160 - len(msg) * 4) // 2
        pyxel.text(cx, y + 13, msg, 11 if gesamt_note in ["1","2"] else 8)

        if self.blink < 35:
            pyxel.text(25, 110, "R = Nochmal spielen", 1)

        for p in self.confetti:
            pyxel.pset(int(p["x"]), int(p["y"]), p["color"])

    # =========================================================
    #  RESET HELPERS
    # =========================================================
    def reset_level2(self):
        self.cars = []
        self.items = []
        self.speed = 1
        self.has_helmet = False
        self.current_lane = 1
        self.player_y = self.lanes[self.current_lane]
        self.timer = 0
        # don't reset lives here – they persist within the level

    def reset_level3(self):
        self.level3_cars = []
        self.level3_items = []
        self.level3_speed = 1
        self.level3_has_helmet = False
        self.level3_current_lane = 1
        self.level3_player_y = self.lanes[1]
        self.level3_timer = 0
        self.level3_lives = 3

    # =========================================================
    #  QUESTION GENERATORS
    # =========================================================
    def generate_quiz_mathe(self):
        difficulty = min(self.quiz_count, 4)
        op = random.choice(["*", "+", "-"] if difficulty < 3 else ["*", "+", "-", "+"])
        if op == "-":
            a = random.randint(1, 10 + difficulty * 2)
            b = random.randint(1, a)
            self.mathe_correct_answer = a - b
        elif op == "*":
            a = random.randint(1, 6 + difficulty)
            b = random.randint(1, 6 + difficulty)
            self.mathe_correct_answer = a * b
        else:
            a = random.randint(1, 15 + difficulty * 3)
            b = random.randint(1, 15 + difficulty * 3)
            self.mathe_correct_answer = a + b
        self.quiz_question = f"{a} {op} {b} = ?"
        self.mathe_answer = ""
        self.mathe_answer_color = 7
        self.quiz_timed_out = False

    def generate_quiz_mc(self, fach):
        pool = [
            ("Hoechster Berg der Schweiz?",
             ["Matterhorn", "Dufourspitze", "Jungfrau"], 1),
            ("Hauptstadt von Australien?",
             ["Sydney", "Melbourne", "Canberra"], 2),
            ("Laengster Fluss der Erde?",
             ["Amazonas", "Nil", "Jangtse"], 1),
            ("Groesster Ozean?",
             ["Atlantik", "Pazifik", "Indik"], 1),
            ("Wo liegt die Sahara?",
             ["Asien", "Afrika", "Amerika"], 1),
            ("Wie viele Kontinente?",
             ["5", "6", "7"], 2),
            ("Hauptstadt von Japan?",
             ["Osaka", "Tokio", "Kyoto"], 1),
            ("Land mit den Pyramiden?",
             ["Marokko", "Sudan", "Aegypten"], 2),
            ("Groesstes Land der Erde?",
             ["Kanada", "Russland", "China"], 1),
            ("Hauptstadt der Schweiz?",
             ["Zuerich", "Genf", "Bern"], 2),
            ("In welchem Land ist der Amazonas?",
             ["Kolumbien", "Brasilien", "Peru"], 1),
            ("Welcher Kontinent ist am groessten?",
             ["Amerika", "Asien", "Afrika"], 1),
            ("Wo liegt Island?",
             ["Atlantik", "Pazifik", "Arktis"], 0),
            ("Hauptstadt von Brasilien?",
             ["Sao Paulo", "Rio de Janeiro", "Brasilia"], 2),
            ("Welcher Berg ist am hoechsten?",
             ["K2", "Mont Blanc", "Mount Everest"], 2),
            ("Hauptstadt von Frankreich?",
             ["Lyon", "Marseille", "Paris"], 2),
            ("Kleinster Kontinent?",
             ["Europa", "Australien", "Antarktis"], 1),
            ("Welches Land hat die meisten Einwohner?",
             ["USA", "Indien", "Russland"], 1),
            ("Wo liegt der Mount Everest?",
             ["Nepal", "Indien", "China"], 0),
            ("Hauptstadt von Italien?",
             ["Mailand", "Rom", "Venedig"], 1),
        ]

        # Wenn beim letzten Lauf alle Fragen einmal verwendet wurden
        # (oder es der allererste Aufruf ist), Pool neu mischen und die
        # Liste der gestellten Fragen leeren – so kommen erst alle Fragen
        # einmal vor, bevor sich etwas wiederholt.
        if not self.geo_pool_order or len(self.geo_asked_questions) >= len(pool):
            self.geo_pool_order = list(range(len(pool)))
            random.shuffle(self.geo_pool_order)
            self.geo_asked_questions = []

        # Naechste noch nicht in diesem Durchlauf gestellte Frage finden
        for idx in self.geo_pool_order:
            if idx not in self.geo_asked_questions:
                q, choices, correct = pool[idx]
                self.geo_asked_questions.append(idx)

                # Antwortreihenfolge zusaetzlich zufaellig mischen, damit
                # die richtige Antwort nicht immer an derselben Position
                # auftaucht, auch wenn dieselbe Frage spaeter wiederkommt.
                shuffled = list(enumerate(choices))
                random.shuffle(shuffled)
                new_choices = [c for _, c in shuffled]
                new_correct = next(new_i for new_i, (orig_i, _) in enumerate(shuffled) if orig_i == correct)

                self.quiz_question = q
                self.quiz_choices = new_choices
                self.quiz_correct_index = new_correct
                self.quiz_selected = -1
                self.quiz_feedback_timer = 0
                self.quiz_timed_out = False
                return


Game()