import pyxel
import random
import math

WIDTH = 512
HEIGHT = 512

WAVES_PER_WORLD = 6
TOTAL_WORLDS = 3

# Wie viele Feinde pro Welle muessen besiegt werden, um zur naechsten zu kommen
KILLS_PER_WAVE = 8

WORLD_NAMES = {
    1: "BIRKENWALD",
    2: "FINSTERES DICKICHT",
    3: "RAEUBERLAGER",
}
WORLD_STORY = {
    1: [
        "Raeuberbanden haben dein Dorf ueberfallen!",
        "Als mutiger Zwerg greifst du zur Axt.",
        "ZIEL: Besiege 8 Raeuber pro Welle.",
        "Nach 6 Wellen erscheint der Boss!",
        "Besiege ihn – und der Birkenwald ist frei!",
    ],
    2: [
        "Gut gemacht! Der Birkenwald ist befreit.",
        "Die Raeuber ziehen sich tiefer ins Dickicht.",
        "Dort warten Bogenschuetzen und Soeldner.",
        "ZIEL: Wieder 8 Feinde pro Welle, 6 Wellen.",
        "Dann: der Waldschrat Morbus wartet auf dich!",
    ],
    3: [
        "Du hast zwei Waelder befreit – unglaublich!",
        "Das Raeuberlager liegt vor dir.",
        "Der dunkle Lord Varek erwartet dich.",
        "Das ist dein schwerster Kampf!",
        "Besiege ihn und rette das Dorf fuer immer!",
    ],
}

# =============================================================
#  HELPERS
# =============================================================

def draw_text_centered(text, y, color):
    pyxel.text(WIDTH // 2 - len(text) * 2, y, text, color)


def draw_tree(x, y, h=30, trunk_col=4, leaf_col=3):
    pyxel.rect(x - 2, y, 4, h // 2, trunk_col)
    pyxel.tri(x, y - h, x - h // 2, y + 4, x + h // 2, y + 4, leaf_col)
    pyxel.tri(x, y - h + 6, x - h // 2 + 4, y + 10, x + h // 2 - 4, y + 10, 11)


# =============================================================
#  SOUND SETUP  (Pyxel built-in chiptune engine)
# =============================================================
# Sound-Slots:
#   0 = Schuss (Axt werfen)
#   1 = Treffer / Explosion klein
#   2 = Feind-Boss stirbt (grosse Explosion)
#   3 = Power-up einsammeln
#   4 = Spieler trifft (Schmerz)
#   5 = Wellen-Fanfare
# Musik-Sounds:
#   10 = BGM Melodie Welt 1
#   11 = BGM Bass  Welt 1
#   12 = BGM Melodie Welt 2
#   13 = BGM Bass  Welt 2
#   14 = BGM Melodie Welt 3 / Boss
#   15 = BGM Bass  Welt 3
# Musik-Tracks:
#   0 = Welt 1
#   1 = Welt 2
#   2 = Welt 3 / Boss

def setup_audio():
    # --- SFX ---

    # 0: Schuss – kurzes, hohes Knacken (Pulse)
    s = pyxel.sound(0)
    s.set_notes("c3r")
    s.set_tones("ps")
    s.set_volumes("72")
    s.set_effects("fn")
    s.speed = 6

    # 1: Kleiner Treffer / Explosion
    s = pyxel.sound(1)
    s.set_notes("c1r")
    s.set_tones("ns")
    s.set_volumes("62")
    s.set_effects("fn")
    s.speed = 6

    # 2: Boss-Explosion (tief, lang)
    s = pyxel.sound(2)
    s.set_notes("c1c1c1")
    s.set_tones("nnn")
    s.set_volumes("765")
    s.set_effects("fff")
    s.speed = 8

    # 3: Power-up (freundlich, aufsteigend)
    s = pyxel.sound(3)
    s.set_notes("c3e3g3c4")
    s.set_tones("tttt")
    s.set_volumes("5678")
    s.set_effects("nnnn")
    s.speed = 8

    # 4: Spieler-Schmerz (tief, unangenehm)
    s = pyxel.sound(4)
    s.set_notes("f1r")
    s.set_tones("ns")
    s.set_volumes("72")
    s.set_effects("fn")
    s.speed = 8

    # 5: Wellen-Fanfare (kleine Melodie)
    s = pyxel.sound(5)
    s.set_notes("c3e3g3c4r")
    s.set_tones("sssss")
    s.set_volumes("56785")
    s.set_effects("nnnnn")
    s.speed = 10

    # --- BGM WELT 1: Leichte Waldmelodie (Triangel + Sinus-Bass) ---
    # Melodie: fröhlich, mittleres Tempo, C-Dur pentatonisch
    s = pyxel.sound(10)
    s.set_notes("c3e3g3e3d3f3a3f3c3e3g3e3d3g3f3d3")
    s.set_tones("tttttttttttttttt")
    s.set_volumes("5656565656565656")
    s.set_effects("nnnnnnnnnnnnnnnn")
    s.speed = 14

    # Bass Welt 1
    s = pyxel.sound(11)
    s.set_notes("c2rg2rc2rg2r")
    s.set_tones("ssssssss")
    s.set_volumes("53535353")
    s.set_effects("nnnnnnnn")
    s.speed = 28

    # --- BGM WELT 2: Dunkler, bedrohlicher (Moll) ---
    s = pyxel.sound(12)
    s.set_notes("a2c3e3c3g2b2d3b2a2c3e3c3f2a2c3a2")
    s.set_tones("tttttttttttttttt")
    s.set_volumes("6767676767676767")
    s.set_effects("nnnnnnnnnnnnnnnn")
    s.speed = 12

    # Bass Welt 2
    s = pyxel.sound(13)
    s.set_notes("a1re1ra1re1r")
    s.set_tones("ssssssss")
    s.set_volumes("64646464")
    s.set_effects("nnnnnnnn")
    s.speed = 24

    # --- BGM WELT 3 / Boss: Dramatisch, schnell ---
    s = pyxel.sound(14)
    s.set_notes("e3g3b3g3f3a3c4a3e3g3b3g3d3f3a3f3")
    s.set_tones("pppppppppppppppp")
    s.set_volumes("7676767676767676")
    s.set_effects("nnnnnnnnnnnnnnnn")
    s.speed = 10

    # Bass Welt 3
    s = pyxel.sound(15)
    s.set_notes("e1rr b1rr e1rr a1rr")
    s.set_tones("ssssssss")
    s.set_volumes("75757575")
    s.set_effects("nnnnnnnn")
    s.speed = 20

    # --- Musik-Tracks ---
    m = pyxel.music(0)   # Welt 1
    m.set([10], [11], [], [])

    m = pyxel.music(1)   # Welt 2
    m.set([12], [13], [], [])

    m = pyxel.music(2)   # Welt 3
    m.set([14], [15], [], [])


def play_sfx(snd_id):
    """SFX auf Channel 3 (lässt Musik auf 0-2 laufen)."""
    try:
        pyxel.play(3, snd_id)
    except Exception:
        pass


def play_music(track_id):
    try:
        pyxel.playm(track_id, loop=True)
    except Exception:
        pass


def stop_music():
    try:
        pyxel.stop(0)
        pyxel.stop(1)
    except Exception:
        pass


# =============================================================
#  BULLET  (Axt des Zwergs)
# =============================================================
class Bullet:
    def __init__(self, x, y, dx=0, dy=-9, color=8, dmg=1, big=False, owner=None):
        self.x = float(x)
        self.y = float(y)
        self.dx = dx
        self.dy = dy
        self.color = color
        self.dmg = dmg
        self.big = big
        self.owner = owner
        self.alive = True
        self.angle = 0

    def update(self):
        self.x += self.dx
        self.y += self.dy
        self.angle = (self.angle + 22) % 360
        if self.y < -20 or self.y > HEIGHT + 20 or self.x < -20 or self.x > WIDTH + 20:
            self.alive = False

    def draw(self):
        cx, cy = int(self.x), int(self.y)
        if self.big:
            pyxel.rect(cx - 4, cy - 9, 8, 18, self.color)
            pyxel.rect(cx - 2, cy - 9, 4, 18, 7)
            pyxel.rect(cx - 7, cy - 5, 14, 6, self.color)
            pyxel.rectb(cx - 7, cy - 5, 14, 6, 7)
        else:
            a = math.radians(self.angle)
            # Axt-Körper
            pyxel.rect(cx - 2, cy - 4, 4, 8, self.color)
            pyxel.rect(cx - 1, cy - 4, 2, 8, 7)
            # Axt-Klinge (rotierend)
            blade_x = cx + int(math.cos(a) * 5)
            blade_y = cy + int(math.sin(a) * 5)
            pyxel.rect(blade_x - 2, blade_y - 2, 5, 4, self.color)
            pyxel.pset(blade_x, blade_y, 7)


# =============================================================
#  ENEMY-BULLET
# =============================================================
class EnemyBullet:
    def __init__(self, x, y, dx, dy, color=8, kind="stone"):
        self.x = float(x)
        self.y = float(y)
        self.dx = dx
        self.dy = dy
        self.color = color
        self.kind = kind
        self.alive = True

    def update(self):
        self.x += self.dx
        self.y += self.dy
        if self.y < -20 or self.y > HEIGHT + 20 or self.x < -20 or self.x > WIDTH + 20:
            self.alive = False

    def draw(self):
        cx, cy = int(self.x), int(self.y)
        if self.kind == "arrow":
            ang = math.atan2(self.dy, self.dx)
            for i in range(7):
                px2 = cx + int(math.cos(ang) * i)
                py2 = cy + int(math.sin(ang) * i)
                pyxel.pset(px2, py2, 4 if i < 5 else 7)
            pyxel.pset(cx, cy, 9)
        else:
            pyxel.circ(cx, cy, 3, self.color)
            pyxel.circb(cx, cy, 4, 0)


# =============================================================
#  PARTICLE
# =============================================================
class Particle:
    def __init__(self, x, y, color, kind="spark"):
        self.x = float(x)
        self.y = float(y)
        self.kind = kind
        ang = random.uniform(0, math.pi * 2)
        spd = random.uniform(1.5, 5)
        self.dx = math.cos(ang) * spd
        self.dy = math.sin(ang) * spd
        self.color = color
        self.life = random.randint(10, 28)
        self.max_life = self.life

    def update(self):
        self.x += self.dx
        self.y += self.dy
        self.dx *= 0.88
        self.dy *= 0.88
        self.life -= 1

    @property
    def alive(self):
        return self.life > 0

    def draw(self):
        if self.kind == "leaf":
            size = max(1, int(self.life / self.max_life * 4))
            pyxel.rect(int(self.x), int(self.y), size, size,
                       3 if self.life % 3 == 0 else 11)
        else:
            size = max(1, self.life // 7)
            pyxel.rect(int(self.x), int(self.y), size, size, self.color)


# =============================================================
#  POWER-UP
# =============================================================
class PowerUp:
    TYPES  = ["heal", "rapid", "shield", "spread"]
    LABELS = {"heal": "H", "rapid": "P", "shield": "S", "spread": "R"}
    NAMES  = {"heal": "HEILTRANK", "rapid": "PILZKRAFT", "shield": "SCHILD", "spread": "RUNENWURF"}
    COLORS = {"heal": 11, "rapid": 10, "shield": 12, "spread": 14}

    def __init__(self, x, y):
        self.x = float(x)
        self.y = float(y)
        self.dy = 1.2
        self.type = random.choice(PowerUp.TYPES)
        self.alive = True
        self.timer = 0

    def update(self):
        self.y += self.dy
        self.timer += 1
        if self.y > HEIGHT + 10:
            self.alive = False

    def draw(self):
        col = PowerUp.COLORS[self.type]
        lbl = PowerUp.LABELS[self.type]
        name = PowerUp.NAMES[self.type]
        bob = int(math.sin(self.timer * 0.18) * 3)
        cx, cy = int(self.x), int(self.y) + bob
        glow = 7 if (self.timer // 4) % 2 == 0 else col
        pyxel.rect(cx - 6, cy - 6, 12, 12, 4)
        pyxel.rect(cx - 5, cy - 5, 10, 10, col)
        pyxel.rectb(cx - 6, cy - 6, 12, 12, glow)
        pyxel.text(cx - 2, cy - 3, lbl, 7)
        # kleiner Name-Hinweis wenn nah
        pyxel.text(cx - len(name) * 2, cy + 9, name, col)


# =============================================================
#  ENEMIES  (Raeuberthema)
# =============================================================

class Enemy:
    """Normaler Räuber."""
    KIND = "raeuber"

    def __init__(self, world, wave, x=None):
        self.x = float(x if x is not None else random.randint(30, WIDTH - 30))
        self.y = float(-24)
        self.world = world
        self.wave = wave
        # Einfacher als vorher: etwas weniger HP
        self.max_hp = 2 + world + wave // 4
        self.hp = self.max_hp
        self.timer = random.randint(50, 110)
        # Etwas langsamer als vorher
        self.speed = 0.8 + world * 0.18 + wave * 0.03
        self.alive = True
        self.score_value = 10

    def update(self, bullets, player):
        self.y += self.speed
        self.timer -= 1
        if self.timer <= 0:
            self.timer = random.randint(60, 120)
            bullets.append(EnemyBullet(self.x, self.y, 0,
                                       2.8 + self.world * 0.25, color=4, kind="stone"))
        if self.y > HEIGHT + 24:
            self.alive = False

    def draw(self):
        cx, cy = int(self.x), int(self.y)
        world_col = [5, 2, 13][self.world - 1]
        pyxel.tri(cx, cy - 14, cx - 10, cy + 10, cx + 10, cy + 10, world_col)
        pyxel.circ(cx, cy - 16, 6, 7)
        pyxel.rect(cx - 5, cy - 24, 10, 4, 0)
        pyxel.rect(cx - 7, cy - 21, 14, 3, 0)
        pyxel.pset(cx - 2, cy - 17, 8)
        pyxel.pset(cx + 2, cy - 17, 8)
        if self.hp < self.max_hp:
            pyxel.rect(cx - 8, cy - 30, 16, 2, 1)
            pyxel.rect(cx - 8, cy - 30, int(16 * self.hp / self.max_hp), 2, 11)


class Bogenschuetze(Enemy):
    """Bogenschütze – bewegt sich zickzack, schießt Pfeile."""
    KIND = "bogenschuetze"

    def __init__(self, world, wave, x=None):
        super().__init__(world, wave, x)
        self.max_hp = 1 + world
        self.hp = self.max_hp
        self.dir = random.choice([-1, 1])
        self.speed = 1.1 + world * 0.15
        self.score_value = 18

    def update(self, bullets, player):
        self.y += self.speed
        self.x += self.dir * 2
        if self.x < 20 or self.x > WIDTH - 20:
            self.dir *= -1
        self.timer -= 1
        if self.timer <= 0:
            self.timer = random.randint(65, 120)
            dx = player.x - self.x
            dy = player.y - self.y
            dist = max(1, math.hypot(dx, dy))
            spd = 4.5
            bullets.append(EnemyBullet(self.x, self.y,
                                       dx / dist * spd, dy / dist * spd,
                                       color=9, kind="arrow"))
        if self.y > HEIGHT + 24:
            self.alive = False

    def draw(self):
        cx, cy = int(self.x), int(self.y)
        pyxel.tri(cx, cy - 13, cx - 8, cy + 9, cx + 8, cy + 9, 3)
        pyxel.circ(cx, cy - 15, 5, 7)
        pyxel.pset(cx + 3, cy - 20, 10)
        pyxel.rect(cx - 4, cy - 20, 8, 3, 3)
        pyxel.line(cx - 8, cy - 6, cx - 6, cy + 6, 4)
        pyxel.pset(cx - 2, cy - 17, 8)
        pyxel.pset(cx + 2, cy - 17, 8)
        if self.hp < self.max_hp:
            pyxel.rect(cx - 8, cy - 28, 16, 2, 1)
            pyxel.rect(cx - 8, cy - 28, int(16 * self.hp / self.max_hp), 2, 11)


class Soelder(Enemy):
    """Gepanzerter Söldner – viel HP, gezielter Wurf."""
    KIND = "soelder"

    def __init__(self, world, wave, x=None):
        super().__init__(world, wave, x)
        self.max_hp = 7 + world * 2 + wave // 2
        self.hp = self.max_hp
        self.speed = 0.5 + world * 0.08
        self.score_value = 40

    def update(self, bullets, player):
        self.y += self.speed
        self.timer -= 1
        if self.timer <= 0:
            self.timer = random.randint(70, 120)
            dx = player.x - self.x
            dy = player.y - self.y
            dist = max(1, math.hypot(dx, dy))
            bullets.append(EnemyBullet(self.x, self.y,
                                       dx / dist * 4, dy / dist * 4,
                                       color=14, kind="stone"))
        if self.y > HEIGHT + 30:
            self.alive = False

    def draw(self):
        cx, cy = int(self.x), int(self.y)
        pyxel.rect(cx - 11, cy - 11, 22, 22, 5)
        pyxel.rect(cx - 11, cy - 11, 22, 6, 6)
        pyxel.rectb(cx - 11, cy - 11, 22, 22, 0)
        pyxel.rect(cx - 7, cy - 20, 14, 9, 6)
        pyxel.rectb(cx - 7, cy - 20, 14, 9, 0)
        pyxel.rect(cx - 4, cy - 17, 3, 2, 0)
        pyxel.rect(cx + 1, cy - 17, 3, 2, 0)
        if self.hp < self.max_hp:
            pyxel.rect(cx - 11, cy - 27, 22, 2, 1)
            pyxel.rect(cx - 11, cy - 27, int(22 * self.hp / self.max_hp), 2, 11)


class Schnellraeub(Enemy):
    """Flinker Räuber – läuft schnell, kein Schuss."""
    KIND = "schnell"

    def __init__(self, world, wave, x=None):
        super().__init__(world, wave, x)
        self.max_hp = 1
        self.hp = 1
        self.speed = 2.4 + world * 0.25
        self.dx = random.choice([-1, 1]) * 1.3
        self.score_value = 8

    def update(self, bullets, player):
        self.y += self.speed
        self.x += self.dx
        if self.x < 15 or self.x > WIDTH - 15:
            self.dx *= -1
        if self.y > HEIGHT + 24:
            self.alive = False

    def draw(self):
        cx, cy = int(self.x), int(self.y)
        pyxel.circ(cx, cy, 7, 9)
        pyxel.circ(cx, cy - 2, 3, 7)
        pyxel.pset(cx - 1, cy - 3, 8)
        pyxel.pset(cx + 1, cy - 3, 8)


class BossRaeuberchef(Enemy):
    """Welt-Boss."""
    KIND = "boss"
    BOSS_NAMES = {1: "HAUPTMANN GRIMM", 2: "WALDSCHRAT MORBUS", 3: "DUNKLER LORD VAREK"}

    def __init__(self, world, wave):
        super().__init__(world, wave, x=WIDTH // 2)
        self.y = float(-50)
        self.max_hp = 70 + world * 35
        self.hp = self.max_hp
        self.speed = 0.7
        self.phase_timer = 0
        self.attack_timer = 70
        self.entering = True
        self.score_value = 600
        self.move_dir = 1
        self.name = self.BOSS_NAMES[world]

    def update(self, bullets, player):
        if self.entering:
            self.y += 1.2
            if self.y >= 80:
                self.entering = False
            return

        self.x += self.move_dir * (1.2 + self.world * 0.18)
        if self.x < 80 or self.x > WIDTH - 80:
            self.move_dir *= -1

        self.attack_timer -= 1
        if self.attack_timer <= 0:
            self.attack_timer = max(32, 95 - self.world * 10)
            self.phase_timer += 1
            pattern = self.phase_timer % 3

            if pattern == 0:
                for i in range(-3, 4):
                    ang = math.pi / 2 + i * 0.22
                    bullets.append(EnemyBullet(self.x, self.y,
                        math.cos(ang) * 3, math.sin(ang) * 3, color=8, kind="arrow"))
            elif pattern == 1:
                dx = player.x - self.x
                dy = player.y - self.y
                dist = max(1, math.hypot(dx, dy))
                for ox in [-25, 0, 25]:
                    bullets.append(EnemyBullet(self.x + ox, self.y,
                        dx / dist * 4.5, dy / dist * 4.5, color=14, kind="stone"))
            else:
                for i in range(10):
                    ang = (i / 10) * math.pi * 2
                    bullets.append(EnemyBullet(self.x, self.y,
                        math.cos(ang) * 2.5, math.sin(ang) * 2.5, color=10, kind="stone"))

    def draw(self):
        cx, cy = int(self.x), int(self.y)
        pulse_r = 2 + int(math.sin(pyxel.frame_count * 0.12) * 3)
        world_col = [2, 4, 13][self.world - 1]

        pyxel.tri(cx, cy - 30, cx - 28, cy + 22, cx + 28, cy + 22, world_col)
        pyxel.tri(cx, cy - 28, cx - 18, cy + 10, cx + 18, cy + 10, 0)
        pyxel.circ(cx, cy - 33, 12, 7)
        pyxel.rect(cx - 10, cy - 48, 20, 8, world_col)
        pyxel.rect(cx - 13, cy - 44, 26, 4, world_col)
        for zx in [-10, -4, 2, 8]:
            pyxel.rect(cx + zx, cy - 52, 3, 6, world_col)
        ecol = 8 + pulse_r % 4
        pyxel.circ(cx - 5, cy - 34, 3, ecol)
        pyxel.circ(cx + 5, cy - 34, 3, ecol)
        pyxel.rect(cx + 20, cy - 20, 4, 38, 5)
        pyxel.rect(cx + 18, cy - 22, 14, 12, world_col)
        pyxel.rectb(cx + 18, cy - 22, 14, 12, 7)

        # Lebensbalken oben
        bar_w = 280
        bx = WIDTH // 2 - bar_w // 2
        pyxel.rect(bx, 8, bar_w, 10, 0)
        ratio = max(0, self.hp / self.max_hp)
        bar_col = 8 if ratio > 0.5 else (9 if ratio > 0.25 else 8)
        pyxel.rect(bx, 8, int(bar_w * ratio), 10, bar_col)
        pyxel.rectb(bx, 8, bar_w, 10, 7)
        draw_text_centered(self.name, 20, 7)

        if self.hp < self.max_hp:
            pyxel.rect(cx - 28, cy - 60, 56, 3, 1)
            pyxel.rect(cx - 28, cy - 60, int(56 * ratio), 3, 11)


# =============================================================
#  PLAYER  (Zwerg – jetzt ROT)
# =============================================================
class Player:
    RAGE_MAX = 100

    CONTROLS = {
        1: dict(
            left=[pyxel.KEY_LEFT, pyxel.KEY_A],
            right=[pyxel.KEY_RIGHT, pyxel.KEY_D],
            up=[pyxel.KEY_UP, pyxel.KEY_W],
            down=[pyxel.KEY_DOWN, pyxel.KEY_S],
            shoot=[pyxel.KEY_SPACE, pyxel.KEY_Z],
            dash=[pyxel.KEY_SHIFT],
            rage=[pyxel.KEY_R],
        ),
        2: dict(
            left=[pyxel.KEY_J],
            right=[pyxel.KEY_L],
            up=[pyxel.KEY_I],
            down=[pyxel.KEY_K],
            shoot=[pyxel.KEY_M],
            dash=[pyxel.KEY_N],
            rage=[pyxel.KEY_O],
        ),
    }

    # FARBEN: Spieler 1 = ROT, Spieler 2 = BLAU
    COLORS = {
        1: dict(body=8,  head=7, beard=6,  glow1=8, glow2=9,  rage_body=9,  armor=2,  boot=0),
        2: dict(body=12, head=7, beard=13, glow1=12, glow2=6, rage_body=6,  armor=5,  boot=0),
    }

    def __init__(self, pid=1, x=None, y=None):
        self.pid = pid
        self.keys = Player.CONTROLS[pid]
        self.colors = Player.COLORS[pid]
        self.x = float(x if x is not None else WIDTH // 2)
        self.y = float(y if y is not None else HEIGHT - 50)
        self.cooldown = 0
        self.dash = 0
        self.dash_cd = 0
        self.invincible = 0
        self.max_hp = 6        # etwas mehr HP = einfacher
        self.hp = self.max_hp
        self.alive = True
        self.combo = 0
        self.combo_timer = 0
        self.rapid_timer = 0
        self.shield_timer = 0
        self.spread_timer = 0
        self.rage = 0
        self.rage_active = 0
        self.rage_ready_flash = 0

    def _down(self, name):
        return any(pyxel.btn(k) for k in self.keys[name])

    def _pressed(self, name):
        return any(pyxel.btnp(k) for k in self.keys[name])

    def update(self):
        if not self.alive:
            return
        speed = 4

        if self._pressed("dash") and self.dash_cd == 0:
            self.dash = 8
            self.dash_cd = 40
            self.invincible = max(self.invincible, 10)

        if self.dash > 0:
            speed = 11
            self.dash -= 1
        if self.dash_cd > 0:
            self.dash_cd -= 1

        if self._pressed("rage") and self.rage >= Player.RAGE_MAX and self.rage_active == 0:
            self.rage_active = 90
            self.rage = 0

        if self.rage_active > 0:
            self.rage_active -= 1

        if self._down("left"):   self.x -= speed
        if self._down("right"):  self.x += speed
        if self._down("up"):     self.y -= speed
        if self._down("down"):   self.y += speed

        self.x = max(14, min(WIDTH - 14, self.x))
        self.y = max(56, min(HEIGHT - 14, self.y))

        if self.cooldown > 0:    self.cooldown -= 1
        if self.invincible > 0:  self.invincible -= 1
        if self.combo_timer > 0: self.combo_timer -= 1
        else: self.combo = 0
        if self.rapid_timer > 0: self.rapid_timer -= 1
        if self.shield_timer > 0: self.shield_timer -= 1
        if self.spread_timer > 0: self.spread_timer -= 1
        if self.rage_ready_flash > 0: self.rage_ready_flash -= 1
        if self.rage >= Player.RAGE_MAX: self.rage_ready_flash = 10

    def wants_to_shoot(self):
        return self._down("shoot")

    def shoot(self):
        """Gibt Liste neuer Bullets zurück; spielt SFX wenn gefeuert."""
        if self.rage_active > 0:
            if self.cooldown > 0:
                return []
            self.cooldown = 2
            play_sfx(0)
            c = self.colors["rage_body"]
            return [
                Bullet(self.x, self.y - 10, dy=-14, color=c, dmg=3, big=True, owner=self),
                Bullet(self.x - 14, self.y - 4, dx=-1.5, dy=-12, color=c, dmg=2, big=True, owner=self),
                Bullet(self.x + 14, self.y - 4, dx=1.5, dy=-12, color=c, dmg=2, big=True, owner=self),
            ]

        cd = 5 if self.rapid_timer > 0 else 10
        if self.cooldown > 0:
            return []
        self.cooldown = cd
        play_sfx(0)
        bcol = self.colors["body"]
        bullets = [Bullet(self.x, self.y - 10, color=bcol, owner=self)]
        if self.spread_timer > 0:
            bullets.append(Bullet(self.x, self.y - 8, dx=-2.5, dy=-7, color=bcol, owner=self))
            bullets.append(Bullet(self.x, self.y - 8, dx=2.5, dy=-7, color=bcol, owner=self))
        return bullets

    def gain_rage(self, amount):
        if self.rage_active == 0:
            self.rage = min(Player.RAGE_MAX, self.rage + amount)

    def apply_powerup(self, ptype):
        play_sfx(3)
        if ptype == "heal":
            self.hp = min(self.max_hp, self.hp + 2)  # +2 HP statt +1
        elif ptype == "rapid":
            self.rapid_timer = 300
        elif ptype == "shield":
            self.shield_timer = 300
        elif ptype == "spread":
            self.spread_timer = 300

    def take_hit(self):
        if not self.alive or self.invincible > 0:
            return False
        if self.rage_active > 0:
            return False
        if self.shield_timer > 0:
            self.shield_timer = 0
            self.invincible = 40
            return False
        play_sfx(4)
        self.hp -= 1
        self.invincible = 70   # längere Unverwundbarkeit nach Treffer
        if self.hp <= 0:
            self.alive = False
        return True

    def draw(self):
        cx, cy = int(self.x), int(self.y)
        if not self.alive:
            pyxel.circb(cx, cy, 10, 1)
            return

        cols = self.colors

        if self.rage_active > 0:
            gc = cols["glow1"] if (pyxel.frame_count // 2) % 2 == 0 else cols["glow2"]
            pyxel.circb(cx, cy, 18, gc)
            pyxel.circb(cx, cy, 22, gc)
            color = cols["rage_body"]
        else:
            color = cols["body"]

        if self.invincible > 0 and self.invincible % 8 < 4 and self.rage_active == 0:
            return

        # ---- ZWERG-SPRITE (rot / blau je nach Spieler) ----
        # Beine
        pyxel.rect(cx - 7, cy + 8, 5, 6, color)
        pyxel.rect(cx + 2, cy + 8, 5, 6, color)
        # Stiefel
        pyxel.rect(cx - 8, cy + 13, 7, 4, cols["boot"])
        pyxel.rect(cx + 1, cy + 13, 7, 4, cols["boot"])
        # Körper (Rüstung)
        pyxel.rect(cx - 9, cy - 8, 18, 17, color)
        # Rüstungs-Highlight oben
        pyxel.rect(cx - 9, cy - 8, 18, 5, cols["armor"])
        # Schulterpolster
        pyxel.rect(cx - 12, cy - 6, 5, 6, cols["armor"])
        pyxel.rect(cx + 7, cy - 6, 5, 6, cols["armor"])
        # Gürtel
        pyxel.rect(cx - 9, cy + 5, 18, 3, cols["boot"])
        pyxel.pset(cx, cy + 6, 7)   # Gürtelschnalle
        # Kopf
        pyxel.circ(cx, cy - 12, 8, cols["head"])
        # Helm (dunkelrot / passend)
        pyxel.rect(cx - 8, cy - 22, 16, 6, color)
        pyxel.rect(cx - 10, cy - 19, 20, 3, color)
        # Helm-Zier
        pyxel.rect(cx - 1, cy - 25, 2, 5, 7)
        # Augen
        pyxel.pset(cx - 3, cy - 13, 0)
        pyxel.pset(cx + 3, cy - 13, 0)
        # Nase
        pyxel.pset(cx, cy - 10, 9)
        # Bart (grau, voll)
        pyxel.rect(cx - 5, cy - 8, 10, 4, cols["beard"])
        pyxel.rect(cx - 4, cy - 4, 8, 4, cols["beard"])
        pyxel.rect(cx - 3, cy, 6, 3, cols["beard"])
        # Axt (in der rechten Hand)
        pyxel.rect(cx + 10, cy - 6, 3, 16, 5)          # Stiel
        pyxel.rect(cx + 8, cy - 8, 10, 8, color)        # Klinge
        pyxel.rectb(cx + 8, cy - 8, 10, 8, 7)           # Klinge-Rand
        pyxel.line(cx + 10, cy - 8, cx + 10, cy + 10, 7) # Mitte-Linie

        # Schild oben links (kleines Symbol)
        if self.shield_timer > 0:
            pyxel.circb(cx, cy, 18, 12)
            pyxel.circb(cx, cy, 19, 0)

        if self.pid == 2:
            pyxel.text(cx - 2, cy - 32, "2", cols["body"])


# =============================================================
#  GAME
# =============================================================
class Game:
    STATE_MENU        = "menu"
    STATE_STORY       = "story"
    STATE_PLAY        = "play"
    STATE_BOSS_IN     = "boss_incoming"
    STATE_WORLD_CLEAR = "world_clear"
    STATE_VICTORY     = "victory"
    STATE_GAME_OVER   = "game_over"

    def __init__(self):
        pyxel.init(WIDTH, HEIGHT, title="Zwerg im Wald – Rette das Dorf!")
        setup_audio()
        self._reset_all()
        pyxel.run(self.update, self.draw)

    def _reset_all(self):
        self.state = self.STATE_MENU
        self.world = 1
        self.num_players = 1
        self.menu_select = 0
        self.players = []
        self.bullets = []
        self.enemy_bullets = []
        self.enemies = []
        self.particles = []
        self.powerups = []
        self.wave = 1
        self.spawn_timer = 0
        self.boss_active = False
        self.shake = 0
        self.score = 0
        self.story_page = 0
        self.story_timer = 0
        self.boss_incoming_timer = 0
        self.world_clear_timer = 0
        # Kills pro Welle zählen
        self.wave_kills = 0        # aktuell besiegt in dieser Welle
        self.total_spawned = 0     # gesamt gespawnte normale Feinde diese Welle
        self.current_music = -1

        self.bg_leaves = [
            (random.randint(0, WIDTH), random.randint(0, HEIGHT), random.uniform(0.3, 1.5))
            for _ in range(30)
        ]
        self.bg_trees = [
            (random.randint(0, WIDTH), random.randint(HEIGHT // 2, HEIGHT - 10),
             random.randint(20, 45))
            for _ in range(12)
        ]

    # ---------------------------------------------------------------- start
    def start_world(self, world):
        self.world = world
        self.bullets = []
        self.enemy_bullets = []
        self.enemies = []
        self.particles = []
        self.powerups = []
        self.wave = 1
        self.wave_kills = 0
        self.total_spawned = 0
        self.spawn_timer = 0
        self.boss_active = False
        self.shake = 0

        if self.num_players == 2:
            self.players = [
                Player(pid=1, x=WIDTH // 2 - 40, y=HEIGHT - 55),
                Player(pid=2, x=WIDTH // 2 + 40, y=HEIGHT - 55),
            ]
        else:
            self.players = [Player(pid=1)]

        self.state = self.STATE_PLAY
        music_id = min(world - 1, 2)
        if self.current_music != music_id:
            self.current_music = music_id
            play_music(music_id)

    def begin_story(self, world):
        self.world = world
        self.story_page = 0
        self.story_timer = 0
        self.state = self.STATE_STORY
        stop_music()
        self.current_music = -1

    def next_world(self):
        if self.world >= TOTAL_WORLDS:
            stop_music()
            self.state = self.STATE_VICTORY
        else:
            self.world_clear_timer = 180
            self.state = self.STATE_WORLD_CLEAR

    def advance_wave(self):
        """Neue Welle starten (nach KILLS_PER_WAVE Kills)."""
        self.wave += 1
        self.wave_kills = 0
        self.total_spawned = 0
        self.score += 75
        play_sfx(5)
        self.spawn_particles(WIDTH // 2, HEIGHT // 2, 11, 20, "leaf")

    def all_players_dead(self):
        return all(not p.alive for p in self.players)

    def get_target_player(self):
        alive = [p for p in self.players if p.alive]
        if not alive:
            return self.players[0]
        return alive[pyxel.frame_count % len(alive)]

    # --------------------------------------------------------------- spawn
    def spawn_enemy(self):
        """Spawne normalen Feind oder triggere Boss."""
        if self.wave > WAVES_PER_WORLD:
            if not self.boss_active and len(self.enemies) == 0:
                self.boss_incoming_timer = 90
                self.state = self.STATE_BOSS_IN
                stop_music()
            return

        roll = random.random()
        w, wv = self.world, self.wave
        if roll < 0.42:
            e = Enemy(w, wv)
        elif roll < 0.62:
            e = Bogenschuetze(w, wv)
        elif roll < 0.80:
            e = Schnellraeub(w, wv)
        else:
            e = Soelder(w, wv)
        self.enemies.append(e)
        self.total_spawned += 1

    def spawn_particles(self, x, y, color, count=8, kind="spark"):
        for _ in range(count):
            self.particles.append(Particle(x, y, color, kind))

    # --------------------------------------------------------------- update
    def update(self):
        if self.state == self.STATE_MENU:
            self._update_menu()
            return
        if self.state == self.STATE_STORY:
            self._update_story()
            return
        if self.state == self.STATE_BOSS_IN:
            self.boss_incoming_timer -= 1
            if self.boss_incoming_timer <= 0:
                self.enemies.append(BossRaeuberchef(self.world, self.wave))
                self.boss_active = True
                self.state = self.STATE_PLAY
                play_music(2)  # Boss-Musik immer Welt-3-Thema
            return
        if self.state == self.STATE_WORLD_CLEAR:
            self.world_clear_timer -= 1
            if self.world_clear_timer <= 0:
                self.begin_story(self.world + 1)
            return
        if self.state == self.STATE_VICTORY:
            if pyxel.btnp(pyxel.KEY_RETURN) or pyxel.btnp(pyxel.KEY_SPACE):
                self._reset_all()
            return
        if self.state == self.STATE_GAME_OVER:
            if pyxel.btnp(pyxel.KEY_RETURN) or pyxel.btnp(pyxel.KEY_SPACE):
                self._reset_all()
            return

        # === PLAY ===
        if self.shake > 0:
            self.shake -= 1

        for p in self.players:
            p.update()
            if p.wants_to_shoot():
                self.bullets += p.shoot()

        # Spawn-Takt
        self.spawn_timer += 1
        spawn_delay = max(18, 65 - self.wave * 2 - self.world * 3)
        if (self.spawn_timer > spawn_delay and
                not (self.boss_active and len(self.enemies) > 0) and
                self.state == self.STATE_PLAY):
            self.spawn_timer = 0
            self.spawn_enemy()

        # Spieler-Bullets
        for b in self.bullets[:]:
            b.update()
            if not b.alive:
                self.bullets.remove(b)

        # Gegner-Bullets
        for eb in self.enemy_bullets[:]:
            eb.update()
            if not eb.alive:
                self.enemy_bullets.remove(eb)
                continue
            for p in self.players:
                if not p.alive:
                    continue
                if abs(eb.x - p.x) < 11 and abs(eb.y - p.y) < 11:
                    eb.alive = False
                    if eb in self.enemy_bullets:
                        self.enemy_bullets.remove(eb)
                    if p.take_hit():
                        self.shake = 14
                        self.spawn_particles(p.x, p.y, 8, 10)
                    break

        # Enemies
        target = self.get_target_player()
        for e in self.enemies[:]:
            e.update(self.enemy_bullets, target)

            # Körperkollision
            for p in self.players:
                if not p.alive:
                    continue
                if abs(e.x - p.x) < 14 and abs(e.y - p.y) < 14:
                    if p.take_hit():
                        self.shake = 14
                        self.spawn_particles(p.x, p.y, 8, 10)
                    if e.KIND != "boss":
                        e.alive = False
                        self.spawn_particles(e.x, e.y, 8, 12, "leaf")
                    elif p.rage_active > 0:
                        e.hp -= 1

            # Bullet-Treffer
            for b in self.bullets[:]:
                if not b.alive:
                    continue
                if abs(b.x - e.x) < 12 and abs(b.y - e.y) < 14:
                    e.hp -= b.dmg
                    b.alive = False
                    if b in self.bullets:
                        self.bullets.remove(b)
                    self.spawn_particles(b.x, b.y, 10, 4, "spark")
                    owner = b.owner if b.owner is not None else self.players[0]

                    if e.hp <= 0 and e.alive:
                        e.alive = False
                        play_sfx(2 if e.KIND == "boss" else 1)
                        kind = "leaf" if e.KIND not in ("boss", "soelder") else "spark"
                        self.spawn_particles(e.x, e.y, 9, 18 if e.KIND == "boss" else 10, kind)
                        owner.combo += 1
                        owner.combo_timer = 90
                        combo_mult = 1 + owner.combo // 5
                        self.score += e.score_value * combo_mult
                        rage_gain = 5 if e.KIND == "boss" else (1 if e.KIND == "schnell" else 2)
                        owner.gain_rage(rage_gain)

                        if e.KIND == "boss":
                            self.boss_active = False
                            self.shake = 30
                            for i in range(4):
                                self.powerups.append(PowerUp(e.x - 30 + i * 20, e.y))
                            self.next_world()
                            return
                        else:
                            # Kill zählen für Wellen-Fortschritt
                            self.wave_kills += 1
                            if random.random() < 0.10:
                                self.powerups.append(PowerUp(e.x, e.y))

            if not e.alive and e in self.enemies:
                self.enemies.remove(e)

        # Particles
        for pt in self.particles[:]:
            pt.update()
            if not pt.alive:
                self.particles.remove(pt)

        # Power-ups
        for pu in self.powerups[:]:
            pu.update()
            for p in self.players:
                if not p.alive:
                    continue
                if abs(pu.x - p.x) < 15 and abs(pu.y - p.y) < 15:
                    p.apply_powerup(pu.type)
                    pu.alive = False
                    self.spawn_particles(pu.x, pu.y, 11, 8, "spark")
                    break
            if not pu.alive and pu in self.powerups:
                self.powerups.remove(pu)

        # WELLEN-FORTSCHRITT: nach KILLS_PER_WAVE Kills -> nächste Welle
        if (not self.boss_active and
                self.wave <= WAVES_PER_WORLD and
                self.wave_kills >= KILLS_PER_WAVE and
                self.state == self.STATE_PLAY):
            self.advance_wave()

        # Tod
        if self.all_players_dead():
            self.shake = 30
            stop_music()
            self.state = self.STATE_GAME_OVER

    # --------------------------------------------------------------- menu update
    def _update_menu(self):
        if pyxel.btnp(pyxel.KEY_UP) or pyxel.btnp(pyxel.KEY_W):
            self.menu_select = (self.menu_select - 1) % 3
        if pyxel.btnp(pyxel.KEY_DOWN) or pyxel.btnp(pyxel.KEY_S):
            self.menu_select = (self.menu_select + 1) % 3

        if self.menu_select == 2:
            if (pyxel.btnp(pyxel.KEY_RETURN) or pyxel.btnp(pyxel.KEY_SPACE) or
                    pyxel.btnp(pyxel.KEY_LEFT) or pyxel.btnp(pyxel.KEY_RIGHT)):
                self.num_players = 2 if self.num_players == 1 else 1
        else:
            if pyxel.btnp(pyxel.KEY_RETURN) or pyxel.btnp(pyxel.KEY_SPACE):
                self.score = 0
                self.begin_story(1)

    def _update_story(self):
        self.story_timer += 1
        if self.story_timer > 40 and (pyxel.btnp(pyxel.KEY_RETURN) or
                                       pyxel.btnp(pyxel.KEY_SPACE) or
                                       pyxel.btnp(pyxel.KEY_Z)):
            self.story_page += 1
            self.story_timer = 0
            lines = WORLD_STORY.get(self.world, [])
            if self.story_page >= len(lines):
                self.start_world(self.world)

    # --------------------------------------------------------------- DRAW
    def draw(self):
        ox, oy = 0, 0
        if self.shake > 0:
            ox = random.randint(-self.shake // 3, self.shake // 3)
            oy = random.randint(-self.shake // 3, self.shake // 3)
            pyxel.camera(ox, oy)
        else:
            pyxel.camera(0, 0)

        self._draw_bg()

        if self.state == self.STATE_MENU:
            pyxel.camera(0, 0)
            self._draw_menu()
            return
        if self.state == self.STATE_STORY:
            pyxel.camera(0, 0)
            self._draw_story()
            return
        if self.state == self.STATE_BOSS_IN:
            self._draw_game_entities()
            pyxel.camera(0, 0)
            f = pyxel.frame_count
            col = 8 if (f // 6) % 2 == 0 else 7
            boss_name = BossRaeuberchef.BOSS_NAMES.get(self.world, "BOSS")
            pyxel.rect(0, HEIGHT // 2 - 35, WIDTH, 70, 0)
            pyxel.rectb(0, HEIGHT // 2 - 35, WIDTH, 70, col)
            draw_text_centered("!! ACHTUNG !!", HEIGHT // 2 - 22, col)
            draw_text_centered(boss_name + " ERSCHEINT!", HEIGHT // 2 - 8, 7)
            draw_text_centered("Bereite dich vor, Zwerg!", HEIGHT // 2 + 10, 6)
            return
        if self.state == self.STATE_WORLD_CLEAR:
            self._draw_game_entities()
            pyxel.camera(0, 0)
            pyxel.rect(WIDTH // 2 - 150, HEIGHT // 2 - 40, 300, 80, 0)
            pyxel.rectb(WIDTH // 2 - 150, HEIGHT // 2 - 40, 300, 80, 11)
            draw_text_centered("WELT BEFREIT!  \\o/", HEIGHT // 2 - 26, 10)
            draw_text_centered(WORLD_NAMES[self.world] + " ist gerettet!", HEIGHT // 2 - 10, 11)
            draw_text_centered("Punkte: " + str(self.score), HEIGHT // 2 + 8, 7)
            draw_text_centered("Weiter in den naechsten Wald...", HEIGHT // 2 + 24, 6)
            return
        if self.state == self.STATE_VICTORY:
            pyxel.camera(0, 0)
            self._draw_victory()
            return
        if self.state == self.STATE_GAME_OVER:
            pyxel.camera(0, 0)
            self._draw_game_entities()
            self._draw_gameover()
            return

        # === PLAY ===
        self._draw_game_entities()
        pyxel.camera(0, 0)
        self._draw_hud()

    # --------------------------------------------------------------- background
    def _draw_bg(self):
        w = self.world if self.world in (1, 2, 3) else 1

        if w == 1:
            for y in range(0, HEIGHT // 2, 2):
                col = 3 if (y // 2) % 2 == 0 else 11
                pyxel.rect(0, y, WIDTH, 2, col if y < HEIGHT // 4 else 3)
            pyxel.rect(0, HEIGHT // 2, WIDTH, HEIGHT // 2, 3)
        elif w == 2:
            pyxel.cls(1)
            for y in range(0, HEIGHT, 6):
                pyxel.rect(0, y, WIDTH, 1, 0 if y % 12 == 0 else 1)
        else:
            pyxel.cls(0)
            for y in range(0, HEIGHT, 8):
                pyxel.rect(0, y, WIDTH, 1, 1 if y % 16 == 0 else 0)

        tree_cols = [(4, 3), (5, 1), (2, 13)]
        tc, lc = tree_cols[w - 1]
        for tx, ty, th in self.bg_trees:
            draw_tree(tx, ty, th, tc, lc)

        if w == 1:
            for gx in range(0, WIDTH, 8):
                pyxel.rect(gx, HEIGHT - 6, 4, 6, 3)
                pyxel.rect(gx + 2, HEIGHT - 9, 2, 9, 11)
            for i, (lx, ly, spd) in enumerate(self.bg_leaves):
                new_ly = (ly + spd) % HEIGHT
                self.bg_leaves[i] = (lx, new_ly, spd)
                pyxel.pset(int(lx), int(new_ly), 3 if i % 3 else 11)
        elif w == 2:
            pyxel.rect(0, HEIGHT - 5, WIDTH, 5, 0)
        else:
            pyxel.rect(0, HEIGHT - 5, WIDTH, 5, 2)

    def _draw_game_entities(self):
        for p in self.players:
            p.draw()
        for b in self.bullets:
            b.draw()
        for eb in self.enemy_bullets:
            eb.draw()
        for e in self.enemies:
            e.draw()
        for pu in self.powerups:
            pu.draw()
        for pt in self.particles:
            pt.draw()

    # --------------------------------------------------------------- HUD
    def _draw_hud(self):
        # Oberer Streifen
        pyxel.rect(0, 0, WIDTH, 56, 0)
        pyxel.rect(0, 54, WIDTH, 2, 3)

        # Welt + Waldname
        wname = WORLD_NAMES.get(self.world, "WALD")
        pyxel.text(6, 4, "WELT " + str(self.world) + "/" + str(TOTAL_WORLDS)
                   + "   " + wname, 11)

        # ---- WELLEN-FORTSCHRITTS-ANZEIGE ----
        if self.wave <= WAVES_PER_WORLD:
            # Kills-Fortschritt als Balken + Text
            remaining = max(0, KILLS_PER_WAVE - self.wave_kills)
            bar_total = 180
            bar_filled = int(bar_total * min(self.wave_kills, KILLS_PER_WAVE) / KILLS_PER_WAVE)
            pyxel.text(6, 14,
                       "WELLE " + str(self.wave) + "/" + str(WAVES_PER_WORLD)
                       + "   Noch " + str(remaining) + " Raeuber besiegen!", 7)
            pyxel.rect(6, 24, bar_total, 6, 1)
            pyxel.rect(6, 24, bar_filled, 6, 10)
            pyxel.rectb(6, 24, bar_total, 6, 7)
            # Kleine Markierungen für jeden Kill
            for i in range(KILLS_PER_WAVE):
                mx = 6 + int(bar_total * i / KILLS_PER_WAVE)
                pyxel.pset(mx, 24, 0)
                pyxel.pset(mx, 29, 0)
            pyxel.text(6, 34, "Nach " + str(KILLS_PER_WAVE)
                       + " Kills: naechste Welle. "
                       + "Nach Welle 6: BOSS!", 6)
        else:
            pyxel.text(6, 14, "!! BOSS-KAMPF !! Besiege den Hauptmann!", 8)
            pyxel.text(6, 26, "Danach ist dieser Wald befreit!", 6)

        pyxel.text(6, 44, "PUNKTE: " + str(self.score), 9)

        # Pro-Spieler HP + Powerups (rechte Seite)
        def draw_player_hud(p, hx):
            for i in range(p.max_hp):
                col = p.colors["body"] if i < p.hp else 1
                hpx = hx - i * 12
                pyxel.rect(hpx, 5, 10, 10, col)
                pyxel.rectb(hpx, 5, 10, 10, 0)
                pyxel.pset(hpx + 1, 5, 0)
                pyxel.pset(hpx + 8, 5, 0)

            sx = hx - (p.max_hp - 1) * 12
            pyxel.text(sx, 18, "KOMBO x" + str(p.combo), 11)
            py2 = 28
            for attr, col, lbl in [
                ("rapid_timer", 10, "PILZKRAFT"),
                ("shield_timer", 12, "SCHILD"),
                ("spread_timer", 14, "RUNENWURF"),
            ]:
                if getattr(p, attr) > 0:
                    pyxel.text(sx, py2, lbl, col)
                    py2 += 9

        if len(self.players) == 1:
            draw_player_hud(self.players[0], WIDTH - 10)
        else:
            draw_player_hud(self.players[0], WIDTH - 90)
            draw_player_hud(self.players[1], WIDTH - 10)
            pyxel.text(WIDTH - 90 - (self.players[0].max_hp - 1) * 12, 4,
                       "P1", self.players[0].colors["body"])
            pyxel.text(WIDTH - 10 - (self.players[1].max_hp - 1) * 12, 4,
                       "P2", self.players[1].colors["body"])

        # Untere Leiste: Dash + Rage
        def draw_bars(p, bx, lbl):
            dash_ratio = 1 - p.dash_cd / 40
            pyxel.rect(bx, HEIGHT - 30, 60, 6, 1)
            pyxel.rect(bx, HEIGHT - 30, int(60 * dash_ratio), 6,
                       6 if p.dash_cd > 0 else 11)
            pyxel.rectb(bx, HEIGHT - 30, 60, 6, 7)
            pyxel.text(bx, HEIGHT - 40, lbl + "DASH [SHIFT]", 6)

            rage_w = 160 if len(self.players) == 1 else 110
            rage_ratio = p.rage / Player.RAGE_MAX
            bc = (p.colors["glow1"]
                  if p.rage_ready_flash > 0 and (pyxel.frame_count % 4 < 2)
                  else 9)
            pyxel.rect(bx, HEIGHT - 16, rage_w, 10, 1)
            pyxel.rect(bx, HEIGHT - 16, int(rage_w * rage_ratio), 10, bc)
            pyxel.rectb(bx, HEIGHT - 16, rage_w, 10, 7)
            if p.rage >= Player.RAGE_MAX and p.rage_active == 0:
                pyxel.text(bx + 4, HEIGHT - 13, "WUTANFALL BEREIT! [R]", 10)
            elif p.rage_active > 0:
                pyxel.text(bx + 4, HEIGHT - 13, "WUTANFALL AKTIV!", 8)
            else:
                pyxel.text(bx, HEIGHT - 26, lbl + "ZORN [R]", 6)

        if len(self.players) == 1:
            draw_bars(self.players[0], 8, "")
        else:
            draw_bars(self.players[0], 8, "P1 ")
            draw_bars(self.players[1], WIDTH - 120, "P2 ")

    # --------------------------------------------------------------- MENU
    def _draw_menu(self):
        self._draw_bg()

        pyxel.rect(WIDTH // 2 - 145, 38, 290, 60, 0)
        pyxel.rectb(WIDTH // 2 - 145, 38, 290, 60, 3)
        pyxel.rectb(WIDTH // 2 - 144, 39, 288, 58, 11)
        draw_text_centered("ZWERG IM WALD", 48, 8)
        draw_text_centered("Rette das Dorf vor den Raeubern!", 62, 7)
        draw_text_centered("3 Welten  |  immer schwerer  |  1-2 Spieler", 76, 6)

        options = [("NEUES SPIEL  (ENTER)", 10), ("Wie spielt man?", 6)]
        for i, (txt, col) in enumerate(options):
            y = 120 + i * 22
            if i == self.menu_select:
                pyxel.rect(WIDTH // 2 - 110, y - 4, 220, 16, 5)
                pyxel.rectb(WIDTH // 2 - 110, y - 4, 220, 16, 7)
                pyxel.text(WIDTH // 2 - 98, y, "> " + txt, col)
            else:
                pyxel.text(WIDTH // 2 - 98, y, "  " + txt, col)

        y4 = 120 + 2 * 22
        pm = "1 ZWERG" if self.num_players == 1 else "2 ZWERGE (KOOP)"
        pm_c = 11 if self.num_players == 1 else 10
        if self.menu_select == 2:
            pyxel.rect(WIDTH // 2 - 110, y4 - 4, 220, 16, 5)
            pyxel.rectb(WIDTH // 2 - 110, y4 - 4, 220, 16, 7)
            pyxel.text(WIDTH // 2 - 98, y4, "> MODUS: " + pm, pm_c)
        else:
            pyxel.text(WIDTH // 2 - 98, y4, "  MODUS: " + pm, pm_c)

        # Erklaer-Box
        pyxel.rect(WIDTH // 2 - 148, 198, 296, 168, 0)
        pyxel.rectb(WIDTH // 2 - 148, 198, 296, 168, 11)
        pyxel.text(WIDTH // 2 - 138, 206, "SO FUNKTIONIERT ES:", 11)
        mission_lines = [
            "Du bist ein roter Zwerg und wirfst Aexte.",
            "Raeuber fallen von oben ein – töte sie!",
            "",
            "WELLEN-SYSTEM:",
            "  Besiege 8 Raeuber -> naechste Welle",
            "  Nach 6 Wellen erscheint der BOSS",
            "  Besiege den Boss -> naechste Welt!",
            "",
            "3 WELTEN: Birkenwald -> Dickicht -> Lager",
            "Jede Welt wird schwerer. Viel Erfolg!",
        ]
        for i, ln in enumerate(mission_lines):
            col = 10 if ln.startswith("WELLEN") or ln.startswith("3 WELTEN") else 7
            if ln == "":
                continue
            pyxel.text(WIDTH // 2 - 138, 218 + i * 10, ln, col)

        # Steuerung
        pyxel.rect(WIDTH // 2 - 148, 374, 296, 108, 0)
        pyxel.rectb(WIDTH // 2 - 148, 374, 296, 108, 6)
        pyxel.text(WIDTH // 2 - 138, 382, "STEUERUNG:", 6)
        ctrl = [
            "Bewegen:  WASD oder Pfeiltasten",
            "Axt werfen:  LEERTASTE (dauerhaft)",
            "Dash/Ausweichen:  SHIFT",
            "Wutanfall (wenn Zorn voll):  R",
            "Power-ups einfach beruehren!",
        ]
        for i, ln in enumerate(ctrl):
            pyxel.text(WIDTH // 2 - 138, 394 + i * 10, ln, 7)
        pyxel.text(WIDTH // 2 - 138, 452, "Spieler 2: I/J/K/L  M  N  O", 10)
        pyxel.text(WIDTH // 2 - 138, 464, "ENTER oder SPACE: Auswaehlen", 6)

    # --------------------------------------------------------------- STORY
    def _draw_story(self):
        self._draw_bg()
        lines = WORLD_STORY.get(self.world, [])
        wname = WORLD_NAMES.get(self.world, "")

        pyxel.rect(WIDTH // 2 - 168, HEIGHT // 2 - 90, 336, 180, 0)
        pyxel.rectb(WIDTH // 2 - 168, HEIGHT // 2 - 90, 336, 180, 11)
        pyxel.rectb(WIDTH // 2 - 167, HEIGHT // 2 - 89, 334, 178, 3)

        draw_text_centered("WELT " + str(self.world) + " - " + wname,
                           HEIGHT // 2 - 78, 11)
        pyxel.line(WIDTH // 2 - 155, HEIGHT // 2 - 66,
                   WIDTH // 2 + 155, HEIGHT // 2 - 66, 3)

        for i in range(min(self.story_page + 1, len(lines))):
            col = 7 if i < self.story_page else (7 if self.story_timer < 20 else 10)
            draw_text_centered(lines[i], HEIGHT // 2 - 52 + i * 18, col)

        if self.story_timer > 40:
            blink = 7 if (pyxel.frame_count // 10) % 2 == 0 else 6
            draw_text_centered("[ LEERTASTE / ENTER ] weiter",
                               HEIGHT // 2 + 72, blink)

    # --------------------------------------------------------------- GAMEOVER / VICTORY
    def _draw_gameover(self):
        pyxel.rect(WIDTH // 2 - 130, HEIGHT // 2 - 65, 260, 130, 0)
        pyxel.rectb(WIDTH // 2 - 130, HEIGHT // 2 - 65, 260, 130, 8)
        draw_text_centered("GAME OVER", HEIGHT // 2 - 50, 8)
        draw_text_centered("Die Raeuber haben gewonnen...", HEIGHT // 2 - 32, 6)
        draw_text_centered("Welt " + str(self.world)
                           + "  Welle " + str(self.wave)
                           + "  Kills " + str(self.wave_kills)
                           + "/" + str(KILLS_PER_WAVE),
                           HEIGHT // 2 - 14, 7)
        draw_text_centered("Punkte: " + str(self.score), HEIGHT // 2 + 4, 9)
        draw_text_centered("ENTER: Zum Hauptmenu", HEIGHT // 2 + 32, 6)

    def _draw_victory(self):
        self._draw_bg()
        f = pyxel.frame_count
        for i in range(40):
            px2 = (f * 7 + i * 30) % WIDTH
            py2 = (f * 5 + i * 22) % HEIGHT
            pyxel.pset(px2, py2, random.choice([7, 10, 11, 9, 3, 8]))

        pyxel.rect(WIDTH // 2 - 160, HEIGHT // 2 - 85, 320, 170, 0)
        pyxel.rectb(WIDTH // 2 - 160, HEIGHT // 2 - 85, 320, 170, 10)
        pyxel.rectb(WIDTH // 2 - 159, HEIGHT // 2 - 84, 318, 168, 8)
        draw_text_centered("DAS DORF IST GERETTET!", HEIGHT // 2 - 72, 8)
        draw_text_centered("Du hast alle 3 Waelder befreit!", HEIGHT // 2 - 54, 10)
        draw_text_centered("Der dunkle Lord Varek ist besiegt.", HEIGHT // 2 - 36, 11)
        draw_text_centered("Du bist der heldenhafteste", HEIGHT // 2 - 18, 7)
        draw_text_centered("Zwerg des ganzen Waldes!", HEIGHT // 2 - 2, 7)
        draw_text_centered("ENDPUNKTE: " + str(self.score), HEIGHT // 2 + 22, 9)
        draw_text_centered("Danke fuer das Spielen!", HEIGHT // 2 + 42, 6)
        draw_text_centered("ENTER: Zum Hauptmenu", HEIGHT // 2 + 62, 6)


Game()