import pyxel
import random

WIDTH = 160
HEIGHT = 120
TILE = 8
ROWS = HEIGHT // TILE


class Game:
    def __init__(self):
        pyxel.init(WIDTH, HEIGHT, title="Survive The Streets")

        # Sound-Effekte definieren
        pyxel.sounds[0].set(
            notes="C3",
            tones="P",
            volumes="3",
            effects="N",
            speed=5
        )
        
        pyxel.sounds[1].set(
            notes="G3G3F3E3D3C3B2A2G2F2E2D2C2C2",
            tones="N",
            volumes="777666555444333",
            effects="SSSSSSSSSSSSSSS",
            speed=14
        )

        self.title_screen = True

        self.player_x = WIDTH // 2
        self.player_y = HEIGHT - TILE

        self.rows = []
        self.obstacles = []
        self.logs = []
        self.crystals = []

        for i in range(ROWS):
            self.rows.append(self.random_row())

        self.rows[-1] = "grass"
        self.rows[-2] = "grass"

        self.score = 0
        self.game_over = False
        self.slow_timer = 0
        self.death_timer = 0

        pyxel.run(self.update, self.draw)

    def random_row(self):
        r = random.random()
        if r < 0.5:
            return "grass"
        elif r < 0.75:
            return "road"
        elif r < 0.9:
            return "rail"
        else:
            return "water"

    def scroll_world(self):
        self.rows.pop()
        self.rows.insert(0, self.random_row())

        for o in self.obstacles:
            o[1] += TILE
        for l in self.logs:
            l[1] += TILE
        for c in self.crystals:
            c[1] += TILE

        if random.random() < 0.15:
            x = random.randrange(0, WIDTH, TILE)
            self.crystals.append([x, 0])

    def play_step_sound(self):
        pyxel.play(0, 0)

    def play_death_sound(self):
        pyxel.play(0, 1)

    def update(self):
        if self.title_screen:
            if pyxel.btnp(pyxel.KEY_SPACE):
                self.title_screen = False
            return

        if self.game_over:
            if self.death_timer > 0:
                self.death_timer -= 1

            if pyxel.btnp(pyxel.KEY_R):
                self.__init__()
            return

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

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

        moved = False
        
        if pyxel.btnp(pyxel.KEY_LEFT):
            self.player_x -= TILE
            moved = True
        if pyxel.btnp(pyxel.KEY_RIGHT):
            self.player_x += TILE
            moved = True
        if pyxel.btnp(pyxel.KEY_UP):
            self.score += 1
            self.scroll_world()
            moved = True
        if pyxel.btnp(pyxel.KEY_DOWN):
            if self.player_y < HEIGHT - TILE:
                self.player_y += TILE
                moved = True

        if moved:
            self.play_step_sound()

        self.player_x = max(0, min(WIDTH - TILE, self.player_x))

        # ✅ NEUES GESCHWINDIGKEITSSYSTEM
        base_speed = 1 + min(self.score * 0.03, 2.5)

        if self.slow_timer > 0:
            base_speed *= 0.3

        for i, row in enumerate(self.rows):
            y = i * TILE

            if row == "road" and random.random() < 0.05:
                direction = random.choice([-1, 1])
                x = -20 if direction == 1 else WIDTH + 20
                self.obstacles.append([x, y, direction, "car"])

            if row == "rail" and random.random() < 0.025:
                direction = random.choice([-1, 1])
                x = -40 if direction == 1 else WIDTH + 40
                self.obstacles.append([x, y, direction, "train"])

            if row == "water" and random.random() < 0.05:
                direction = random.choice([-1, 1])
                x = -20 if direction == 1 else WIDTH + 20
                self.logs.append([x, y, direction])

        player_w = 8
        player_h = 8

        for o in self.obstacles:
            if o[3] == "car":
                o[0] += o[2] * 1.5 * base_speed
                ow, oh = 16, 6

            if o[3] == "train":
                o[0] += o[2] * 4 * base_speed
                ow, oh = 16, 6

            if (self.player_x < o[0]+ow and
                self.player_x + player_w > o[0] and
                self.player_y < o[1]+oh and
                self.player_y + player_h > o[1]):
                if not self.game_over:
                    self.play_death_sound()
                self.game_over = True
                self.death_timer = 20

        on_log = False
        for l in self.logs:
            l[0] += l[2] * 0.8 * base_speed
            if abs(l[0]-self.player_x) < 16 and abs(l[1]-self.player_y) < 6:
                on_log = True

        row_index = int(self.player_y / TILE)
        if row_index < len(self.rows):
            if self.rows[row_index] == "water" and not on_log:
                if not self.game_over:
                    self.play_death_sound()
                self.game_over = True
                self.death_timer = 20

        for c in self.crystals[:]:
            if abs(c[0]-self.player_x) < 6 and abs(c[1]-self.player_y) < 6:
                self.slow_timer = 150
                self.crystals.remove(c)

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

        if self.title_screen:
            pyxel.cls(1)

            pyxel.text(40, 20, "SURVIVE THE", 10)
            pyxel.text(35, 30, "STREETS", 10)

            cx = 75
            cy = 65

            pyxel.rect(cx, cy, 10, 8, 7)
            pyxel.rect(cx+7, cy+2, 2, 1, 0)
            pyxel.tri(cx+10, cy+4, cx+14, cy+3, cx+14, cy+6, 9)

            pyxel.rect(cx+2, cy-2, 6, 2, 8)
            pyxel.rect(cx+2, cy+2, 6, 2, 0)

            pyxel.pset(cx+4, cy+8, 10)
            pyxel.pset(cx+6, cy+8, 10)

            if pyxel.frame_count % 30 < 15:
                pyxel.text(25, 100, "PRESS SPACE", 7)

            return

        if self.death_timer > 0:
            flash_color = 8 if self.death_timer % 2 == 0 else 2
            pyxel.rect(0, 0, WIDTH, HEIGHT, flash_color)

        for i, row in enumerate(self.rows):
            y = i * TILE

            if row == "grass":
                pyxel.rect(0, y, WIDTH, TILE, 3)

            elif row == "road":
                pyxel.rect(0, y, WIDTH, TILE, 5)
                offset = (pyxel.frame_count // 4) % 16
                for x in range(-offset, WIDTH, 16):
                    pyxel.rect(x, y+3, 8, 2, 7)
                pyxel.line(0, y, WIDTH, y, 1)
                pyxel.line(0, y+TILE-1, WIDTH, y+TILE-1, 1)

            elif row == "rail":
                pyxel.rect(0, y, WIDTH, TILE, 13)
                pyxel.line(0, y+2, WIDTH, y+2, 0)
                pyxel.line(0, y+6, WIDTH, y+6, 0)

            elif row == "water":
                pyxel.rect(0, y, WIDTH, TILE, 12)
                for x in range(0, WIDTH, 16):
                    wave = (pyxel.frame_count + x) % 16
                    pyxel.line(x, y + (wave//4), x+8, y + (wave//4), 7)

        for o in self.obstacles:
            x, y, d, t = o

            if t == "car":
                pyxel.rect(x, y, 16, 6, 8)
                pyxel.rect(x+3, y+1, 5, 3, 7)
                pyxel.rect(x+2, y-1, 10, 2, 8)
                pyxel.rect(x+2, y+5, 3, 2, 0)
                pyxel.rect(x+11, y+5, 3, 2, 0)

                if d == 1:
                    pyxel.pset(x+15, y+2, 10)
                else:
                    pyxel.pset(x, y+2, 10)

            if t == "train":
                pyxel.rect(x, y-2, 32, 10, 2)
                pyxel.rect(x+4, y, 5, 4, 7)
                pyxel.rect(x+12, y, 5, 4, 7)
                pyxel.rect(x+20, y, 5, 4, 7)
                pyxel.line(x, y-2, x+32, y-2, 7)
                pyxel.rect(x+4, y+8, 4, 2, 0)
                pyxel.rect(x+20, y+8, 4, 2, 0)

                if d == 1:
                    pyxel.pset(x+31, y+2, 10)
                else:
                    pyxel.pset(x, y+2, 10)

        for l in self.logs:
            x, y = l[0], l[1]
            pyxel.rect(x, y, 20, 6, 4)
            pyxel.line(x+2, y+1, x+2, y+4, 3)
            pyxel.line(x+6, y+1, x+6, y+4, 3)
            pyxel.line(x+10, y+1, x+10, y+4, 3)
            pyxel.line(x+14, y+1, x+14, y+4, 3)
            pyxel.line(x, y, x+20, y, 7)
            pyxel.line(x, y+5, x+20, y+5, 1)
            pyxel.pset(x+5, y+2, 1)
            pyxel.pset(x+12, y+3, 1)

        for c in self.crystals:
            cx, cy = c[0], c[1]

            pyxel.line(cx+4, cy-1, cx+1, cy+4, 7)
            pyxel.line(cx+1, cy+4, cx+4, cy+9, 7)
            pyxel.line(cx+4, cy+9, cx+7, cy+4, 7)
            pyxel.line(cx+7, cy+4, cx+4, cy-1, 7)

            pyxel.tri(cx+4, cy, cx+2, cy+4, cx+4, cy+8, 7)
            pyxel.tri(cx+4, cy, cx+6, cy+4, cx+4, cy+8, 12)

            pyxel.line(cx+4, cy-1, cx+6, cy+4, 7)

            if pyxel.frame_count % 10 == 0:
                sx = cx + random.randint(-1, 9)
                sy = cy + random.randint(-2, 10)
                if 0 <= sx < WIDTH and 0 <= sy < HEIGHT:
                    pyxel.pset(sx, sy, random.choice([7, 12]))

        x = self.player_x
        y = self.player_y

        if not self.game_over:
            pyxel.rect(x, y, 8, 8, 7)
            pyxel.pset(x+2, y+2, 0)
            pyxel.rect(x+5, y+3, 2, 2, 9)
            pyxel.rect(x+2, y-1, 3, 2, 8)
            pyxel.rect(x+1, y-3, 6, 2, 4)
            pyxel.rect(x+2, y-5, 4, 3, 1)

        else:
            t = max(self.death_timer, 1)
            radius = (20 - t) * 3
            if self.death_timer <= 0:
                radius = 30

            for r in range(0, radius, 4):
                for a in range(0, 360, 20):
                    sx = int(x + 4 + r * pyxel.cos(a))
                    sy = int(y + 4 + r * pyxel.sin(a))
                    if 0 <= sx < WIDTH and 0 <= sy < HEIGHT:
                        pyxel.rect(sx, sy, 3, 3, 13)

            for i in range(120):
                ex = x + random.randint(-radius, radius)
                ey = y + random.randint(-radius, radius)
                if 0 <= ex < WIDTH and 0 <= ey < HEIGHT:
                    pyxel.pset(ex, ey, random.choice([8, 2, 1, 14]))

            for i in range(80):
                angle = random.randint(0, 360)
                dist = random.randint(0, radius)
                bx = int(x + 4 + dist * pyxel.cos(angle))
                by = int(y + 4 + dist * pyxel.sin(angle))
                if 0 <= bx < WIDTH and 0 <= by < HEIGHT:
                    pyxel.pset(bx, by, random.choice([8, 2, 1]))

        pyxel.text(5, 5, f"Score {self.score}", 7)

        if self.slow_timer > 0:
            pyxel.text(5, 15, "SLOW!", 10)

        if self.game_over:
            text = "GAME OVER"
            for dx in range(-1, 2):
                for dy in range(-1, 2):
                    pyxel.text(WIDTH//2 - 40 + dx, HEIGHT//2 + dy, text, 8)
            pyxel.text(WIDTH//2 - 40, HEIGHT//2, text, 7)
            pyxel.text(WIDTH//2 - 48, HEIGHT//2 + 10, "Press R", 7)


Game()