# Pyxel Studio

import pyxel
import pyxel
import math
import random

# =========================================================
# SETTINGS
# =========================================================
WIDTH  = 512
HEIGHT = 512
TILE   = 16
HUD_H  = 48
FIELD_Y = HUD_H
FIELD_H = HEIGHT - HUD_H   # 464
COLS   = WIDTH  // TILE     # 32
ROWS   = FIELD_H // TILE    # 29

SPEED          = 3.2
BULLET_SPEED   = 8.0
MAX_HP         = 3
SHOOT_COOLDOWN = 20
WIN_SCORE      = 5

DIR_RIGHT = 2
DIR_DOWN  = 1
DIR_LEFT  = 3
DIR_UP    = 0

PU_INTERVAL = 420   # frames between power-up spawns
PU_LIFE     = 360   # frames before power-up disappears
PU_SHIELD   = 0
PU_SPEED    = 1
PU_RAPID    = 2
PU_DURATION = [0, 200, 180]  # SHIELD has no timer


# =========================================================
# MAP  32 × 29
# =========================================================
TILEMAP = [
    [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],  # 0
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 1
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 2
    [1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1],  # 3
    [1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1],  # 4
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 5
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 6
    [1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1],  # 7
    [1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1],  # 8
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 9
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 10
    [1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1],  # 11
    [1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1],  # 12
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 13
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 14
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 15
    [1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1],  # 16
    [1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1],  # 17
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 18
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 19
    [1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1],  # 20
    [1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1],  # 21
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 22
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 23
    [1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1],  # 24
    [1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1],  # 25
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 26
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 27
    [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],  # 28
]

MAP2 = [
    [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],  # 0
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 1
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 2
    [1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1],  # 3
    [1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1],  # 4
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 5
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 6
    [1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1],  # 7
    [1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1],  # 8
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 9
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 10
    [1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1],  # 11
    [1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1],  # 12
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 13
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 14
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 15
    [1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1],  # 16
    [1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1],  # 17
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 18
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 19
    [1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1],  # 20
    [1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1],  # 21
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 22
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 23
    [1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1],  # 24
    [1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1],  # 25
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 26
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 27
    [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],  # 28
]

MAP3 = [
    [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],  # 0
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 1
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 2
    [1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1],  # 3
    [1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1],  # 4
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 5
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 6
    [1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1],  # 7
    [1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1],  # 8
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 9
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 10
    [1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1],  # 11
    [1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1],  # 12
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 13
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 14
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 15
    [1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1],  # 16
    [1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1],  # 17
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 18
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 19
    [1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1],  # 20
    [1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1],  # 21
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 22
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 23
    [1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1],  # 24
    [1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1],  # 25
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 26
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],  # 27
    [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],  # 28
]

MAPS = [TILEMAP, MAP2, MAP3]


# =========================================================
# HELPERS
# =========================================================
def wall_at(tx, ty):
    if tx < 0 or ty < 0 or tx >= COLS or ty >= ROWS:
        return True
    return TILEMAP[ty][tx] == 1


def any_key_pressed():
    keys = [
        pyxel.KEY_RETURN, pyxel.KEY_SPACE,
        pyxel.KEY_W, pyxel.KEY_A, pyxel.KEY_S, pyxel.KEY_D, pyxel.KEY_F,
        pyxel.KEY_UP, pyxel.KEY_DOWN, pyxel.KEY_LEFT, pyxel.KEY_RIGHT, pyxel.KEY_L,
    ]
    if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
        return True
    return any(pyxel.btnp(k) for k in keys)


def draw_heart(x, y, col):
    pts = [
        (1,0),(2,0),(4,0),(5,0),
        (0,1),(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),
        (0,2),(1,2),(2,2),(3,2),(4,2),(5,2),(6,2),
        (1,3),(2,3),(3,3),(4,3),(5,3),
        (2,4),(3,4),(4,4),(3,5),
    ]
    for dx, dy in pts:
        pyxel.pset(x + dx, y + dy, col)


def draw_explosion(ex, ey, frame):
    t = frame % 40
    if t < 5:
        pyxel.circ(ex, ey, 6, 7)
        pyxel.circ(ex, ey, 3, 10)
    elif t < 12:
        r = (t - 5) * 4
        pyxel.circ(ex, ey, r + 9, 9)
        pyxel.circ(ex, ey, r + 6, 10)
        pyxel.circ(ex, ey, r + 2, 7)
        for i in range(8):
            ang = i * math.pi / 4 + t * 0.2
            fx = ex + int(math.cos(ang) * (r + 12))
            fy = ey + int(math.sin(ang) * (r + 12))
            if 0 <= fx < WIDTH and 0 <= fy < HEIGHT:
                pyxel.pset(fx, fy, 10)
                pyxel.pset(fx + 1, fy, 9)
    elif t < 22:
        r = 28 + (t - 12) % 3
        pyxel.circ(ex, ey, r + 4, 4)
        pyxel.circ(ex, ey, r,     9)
        pyxel.circ(ex, ey, r - 6, 10)
        pyxel.circ(ex, ey, r - 12, 9)
        pyxel.circ(ex, ey, r - 16, 7)
        for i in range(12):
            ang = i * math.pi / 6 + t * 0.15
            dist = r + 8 + (i % 3) * 3
            fx = ex + int(math.cos(ang) * dist)
            fy = ey + int(math.sin(ang) * dist)
            if 0 <= fx < WIDTH and 0 <= fy < HEIGHT:
                col = 10 if i % 2 == 0 else 9
                pyxel.pset(fx, fy, col)
    elif t < 32:
        r = max(4, 28 - (t - 22) * 2)
        pyxel.circ(ex, ey, r + 6, 4)
        pyxel.circ(ex, ey, r + 2, 5)
        pyxel.circ(ex, ey, r - 2, 9)
        pyxel.circ(ex, ey, r - 6, 4)
        smoke_y = ey - (t - 22) * 4
        pyxel.circ(ex - 5, smoke_y, 5, 4)
        pyxel.circ(ex + 4, smoke_y - 6, 4, 5)
        pyxel.circ(ex,     smoke_y - 12, 5, 4)
    else:
        smoke_y = ey - 30 - (t - 32) * 2
        pyxel.circ(ex, smoke_y, 5, 4)
        pyxel.circ(ex + 4, smoke_y - 8, 3, 5)


def draw_tank_sprite(cx, cy, direction, player, damaged=False):
    mc = 11 if player == 1 else 8
    dc = 3  if player == 1 else 2
    lc = 13 if player == 1 else 9
    if damaged:
        mc = 4
        lc = 9

    hw = 14
    tw = 4
    brl = 11
    brw = 3

    horiz = direction in (DIR_LEFT, DIR_RIGHT)

    if horiz:
        pyxel.rect(cx - hw, cy - hw, hw * 2, tw, dc)
        pyxel.rect(cx - hw, cy + hw - tw, hw * 2, tw, dc)
        for i in range(6):
            tx = cx - hw + 1 + i * 4
            pyxel.line(tx, cy - hw, tx, cy - hw + tw - 1, 1)
            pyxel.line(tx, cy + hw - tw, tx, cy + hw - 1, 1)
        pyxel.rect(cx - hw + 1, cy - hw + tw, hw * 2 - 2, hw * 2 - tw * 2, mc)
        pyxel.line(cx - hw + 2, cy - hw + tw + 1, cx + hw - 3, cy - hw + tw + 1, lc)
        pyxel.line(cx + hw - 3, cy - hw + tw + 2, cx + hw - 3, cy + hw - tw - 2, dc)
    else:
        pyxel.rect(cx - hw, cy - hw, tw, hw * 2, dc)
        pyxel.rect(cx + hw - tw, cy - hw, tw, hw * 2, dc)
        for i in range(6):
            ty = cy - hw + 1 + i * 4
            pyxel.line(cx - hw, ty, cx - hw + tw - 1, ty, 1)
            pyxel.line(cx + hw - tw, ty, cx + hw - 1, ty, 1)
        pyxel.rect(cx - hw + tw, cy - hw + 1, hw * 2 - tw * 2, hw * 2 - 2, mc)
        pyxel.line(cx - hw + tw + 1, cy - hw + 2, cx - hw + tw + 1, cy + hw - 3, lc)
        pyxel.line(cx - hw + tw + 2, cy + hw - 3, cx + hw - tw - 2, cy + hw - 3, dc)

    pyxel.circ(cx, cy, 6, dc)
    pyxel.circ(cx, cy, 5, mc)
    pyxel.pset(cx - 1, cy - 1, lc)
    pyxel.pset(cx - 2, cy - 2, lc)

    if direction == DIR_RIGHT:
        pyxel.rect(cx + 5, cy - brw // 2, brl, brw, dc)
        pyxel.pset(cx + 5 + brl - 1, cy, 1)
    elif direction == DIR_LEFT:
        pyxel.rect(cx - 5 - brl, cy - brw // 2, brl, brw, dc)
        pyxel.pset(cx - 5 - brl, cy, 1)
    elif direction == DIR_DOWN:
        pyxel.rect(cx - brw // 2, cy + 5, brw, brl, dc)
        pyxel.pset(cx, cy + 5 + brl - 1, 1)
    elif direction == DIR_UP:
        pyxel.rect(cx - brw // 2, cy - 5 - brl, brw, brl, dc)
        pyxel.pset(cx, cy - 5 - brl, 1)


# =========================================================
# GAME OBJECTS
# =========================================================
class Tank:
    SIZE = 14

    def __init__(self, x, y, direction, player, keys):
        self.x = float(x)
        self.y = float(y)
        self.direction = direction
        self.player = player
        self.keys = keys
        self.hp = MAX_HP
        self.cooldown = 0
        self.alive = True
        self.shield = False
        self.speed_timer = 0
        self.rapid_timer = 0
        self.hit_flash = 0

    def current_speed(self):
        return SPEED * (1.6 if self.speed_timer > 0 else 1.0)

    def current_cooldown(self):
        return SHOOT_COOLDOWN // 3 if self.rapid_timer > 0 else SHOOT_COOLDOWN

    def move(self, other_tank=None):
        if not self.alive:
            return

        k_up, k_down, k_left, k_right, _ = self.keys
        dx = 0.0
        dy = 0.0
        spd = self.current_speed()

        if pyxel.btn(k_right):
            dx = spd
            self.direction = DIR_RIGHT
        elif pyxel.btn(k_left):
            dx = -spd
            self.direction = DIR_LEFT
        elif pyxel.btn(k_down):
            dy = spd
            self.direction = DIR_DOWN
        elif pyxel.btn(k_up):
            dy = -spd
            self.direction = DIR_UP

        if dx == 0 and dy == 0:
            return

        nx = self.x + dx
        ny = self.y + dy
        r = self.SIZE

        blocked_x = False
        for cx, cy in [(nx - r, self.y - r), (nx + r, self.y - r),
                       (nx - r, self.y + r), (nx + r, self.y + r)]:
            fy = cy - FIELD_Y
            if wall_at(int(cx // TILE), int(fy // TILE)):
                blocked_x = True
                break
        if not blocked_x:
            self.x = max(r, min(WIDTH - r, nx))

        blocked_y = False
        for cx, cy in [(self.x - r, ny - r), (self.x + r, ny - r),
                       (self.x - r, ny + r), (self.x + r, ny + r)]:
            fy = cy - FIELD_Y
            if wall_at(int(cx // TILE), int(fy // TILE)):
                blocked_y = True
                break
        if not blocked_y:
            self.y = max(FIELD_Y + r, min(HEIGHT - r, ny))

        if other_tank and other_tank.alive:
            tdx = self.x - other_tank.x
            tdy = self.y - other_tank.y
            dist = math.sqrt(tdx * tdx + tdy * tdy)
            min_dist = self.SIZE + other_tank.SIZE
            if 0 < dist < min_dist:
                self.x = other_tank.x + tdx / dist * min_dist
                self.y = other_tank.y + tdy / dist * min_dist
                self.x = max(r, min(WIDTH - r, self.x))
                self.y = max(FIELD_Y + r, min(HEIGHT - r, self.y))

    def shoot(self, bullets, owner):
        if not self.alive or self.cooldown > 0:
            return
        angle = {DIR_RIGHT: 0, DIR_DOWN: math.pi / 2,
                 DIR_LEFT: math.pi, DIR_UP: -math.pi / 2}[self.direction]
        bx = self.x + math.cos(angle) * 18
        by = self.y + math.sin(angle) * 18
        bullets.append(Bullet(bx, by, angle, owner))
        self.cooldown = self.current_cooldown()
        pyxel.play(0, 0)

    def tick(self, bullets, owner):
        if self.cooldown > 0:
            self.cooldown -= 1
        if self.speed_timer > 0:
            self.speed_timer -= 1
        if self.rapid_timer > 0:
            self.rapid_timer -= 1
        if self.hit_flash > 0:
            self.hit_flash -= 1
        _, _, _, _, k_shoot = self.keys
        if pyxel.btn(k_shoot):
            self.shoot(bullets, owner)

    def draw(self):
        if not self.alive:
            return
        cx = int(self.x)
        cy = int(self.y)
        damaged = self.hp == 1
        if self.hit_flash > 0 and self.hit_flash % 4 < 2:
            return
        draw_tank_sprite(cx, cy, self.direction, self.player, damaged)

        # Power-up aura indicators
        if self.shield:
            f = pyxel.frame_count
            r = self.SIZE + 3 + (f % 4 > 1)
            pyxel.circb(cx, cy, r, 11 if self.player == 1 else 10)
        if self.speed_timer > 0:
            pyxel.pset(cx - 2, cy - self.SIZE - 5, 10)
            pyxel.pset(cx,     cy - self.SIZE - 7, 10)
            pyxel.pset(cx + 2, cy - self.SIZE - 5, 10)
        if self.rapid_timer > 0:
            pyxel.pset(cx - 3, cy - self.SIZE - 5, 8)
            pyxel.pset(cx,     cy - self.SIZE - 7, 8)
            pyxel.pset(cx + 3, cy - self.SIZE - 5, 8)


class Bullet:
    def __init__(self, x, y, angle, owner):
        self.x = float(x)
        self.y = float(y)
        self.vx = math.cos(angle) * BULLET_SPEED
        self.vy = math.sin(angle) * BULLET_SPEED
        self.owner = owner
        self.active = True
        self.life = 140

    def update(self):
        if not self.active:
            return
        self.x += self.vx
        self.y += self.vy
        self.life -= 1
        if self.life <= 0 or self.x < 0 or self.x > WIDTH \
                or self.y < FIELD_Y or self.y > HEIGHT:
            self.active = False
            return
        fy = self.y - FIELD_Y
        if wall_at(int(self.x // TILE), int(fy // TILE)):
            self.active = False

    def draw(self):
        if not self.active:
            return
        col = 11 if self.owner == 1 else 8
        x, y = int(self.x), int(self.y)
        pyxel.circ(x, y, 3, col)
        pyxel.pset(x, y, 7)


class PowerUp:
    ICONS = [
        [(0,-4),(0,4),(-4,0),(4,0)],            # SHIELD: cross
        [(-5,0),(-2,-3),(2,-3),(5,0),(2,3),(-2,3)],  # SPEED: hexagon
        [(-4,-4),(0,-4),(4,-4),(0,0),(-4,4),(0,4),(4,4)],  # RAPID: spread
    ]
    COLS = [11, 10, 8]
    LABELS = ["SCHILD", "TEMPO", "FEUER"]

    def __init__(self, x, y, kind):
        self.x = x
        self.y = y
        self.kind = kind
        self.life = PU_LIFE
        self.active = True

    def update(self):
        if not self.active:
            return
        self.life -= 1
        if self.life <= 0:
            self.active = False

    def draw(self):
        if not self.active:
            return
        f = pyxel.frame_count
        bob = math.sin(f * 0.08) * 3
        cx = self.x
        cy = int(self.y + bob)
        col = self.COLS[self.kind]
        # Crate box
        pyxel.rect(cx - 10, cy - 10, 20, 20, 5)
        pyxel.rectb(cx - 10, cy - 10, 20, 20, col)
        pyxel.line(cx, cy - 10, cx, cy + 9, col)
        pyxel.line(cx - 10, cy, cx + 9, cy, col)
        # Blink when about to expire
        if self.life > 60 or f % 8 < 4:
            pyxel.text(cx - len(self.LABELS[self.kind]) * 2,
                       cy + 12, self.LABELS[self.kind], col)

    def collect(self, tank):
        if not self.active:
            return False
        if abs(tank.x - self.x) < tank.SIZE + 10 and \
                abs(tank.y - self.y) < tank.SIZE + 10:
            self.active = False
            return True
        return False


# =========================================================
# APP
# =========================================================
class App:
    def __init__(self):
        pyxel.init(WIDTH, HEIGHT, title="Iron Clash", fps=30)
        self._init_sounds()

        self.score1 = 0
        self.score2 = 0
        self.winner = ""
        self.state = "intro"
        self.intro_page = 0
        self.intro_timer = 0
        self.gameover_timer = 0
        self.powerup_timer = PU_INTERVAL
        self.powerups = []
        self.last_map_idx = -1
        self.reset_round()

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

    def _init_sounds(self):
        # 0 – shoot
        pyxel.sounds[0].set("C3E3G3", "PPP", "765", "NNN", 10)
        # 1 – hit
        pyxel.sounds[1].set("G2D2A1", "NNN", "765", "FFF", 8)
        # 2 – victory fanfare
        pyxel.sounds[2].set("C3E3G3C4", "PPPP", "7654", "FFFF", 18)
        # 3 – power-up collect
        pyxel.sounds[3].set("C4E4G4B4", "PPPP", "5677", "NNNN", 8)
        # 4 – background music loop (low bass beat)
        pyxel.sounds[4].set(
            "C1C1G0G0A0A0G0G0F0F0C1C1G0G0C1C1",
            "NNNNNNNNNNNNNNNN",
            "3232222222323232",
            "NNNNNNNNNNNNNNNN",
            28,
        )
        # 5 – championship jingle
        pyxel.sounds[5].set("C3E3G3C4E4G4C4", "PPPPPPP", "5677765", "NNNFFFF", 12)

    def reset_round(self):
        global TILEMAP
        choices = [i for i in range(len(MAPS)) if i != self.last_map_idx]
        self.last_map_idx = random.choice(choices)
        TILEMAP = MAPS[self.last_map_idx]

        keys1 = (pyxel.KEY_W, pyxel.KEY_S, pyxel.KEY_A, pyxel.KEY_D, pyxel.KEY_F)
        keys2 = (pyxel.KEY_UP, pyxel.KEY_DOWN, pyxel.KEY_LEFT, pyxel.KEY_RIGHT, pyxel.KEY_L)
        self.tank1 = Tank(50, FIELD_Y + FIELD_H // 2, DIR_RIGHT, 1, keys1)
        self.tank2 = Tank(WIDTH - 50, FIELD_Y + FIELD_H // 2, DIR_LEFT, 2, keys2)
        self.bullets = []
        self.gameover_timer = 0
        self.powerups = []
        self.powerup_timer = PU_INTERVAL
        pyxel.play(3, 4, loop=True)

    def _try_spawn_powerup(self):
        open_tiles = []
        for ty in range(1, ROWS - 1):
            for tx in range(1, COLS - 1):
                if TILEMAP[ty][tx] == 0:
                    wx = tx * TILE + TILE // 2
                    wy = FIELD_Y + ty * TILE + TILE // 2
                    if abs(wx - self.tank1.x) > 60 and abs(wx - self.tank2.x) > 60:
                        open_tiles.append((wx, wy))
        if not open_tiles:
            return
        wx, wy = random.choice(open_tiles)
        kind = random.randint(0, 2)
        self.powerups.append(PowerUp(wx, wy, kind))
        pyxel.play(1, 1)

    def _check_powerup_collect(self, tank):
        for pu in self.powerups:
            if pu.collect(tank):
                pyxel.play(2, 3)
                if pu.kind == PU_SHIELD:
                    tank.shield = True
                elif pu.kind == PU_SPEED:
                    tank.speed_timer = PU_DURATION[PU_SPEED]
                elif pu.kind == PU_RAPID:
                    tank.rapid_timer = PU_DURATION[PU_RAPID]

    def update(self):
        if self.state == "intro":
            self.intro_timer += 1
            if any_key_pressed() or self.intro_timer > 180:
                self.intro_page += 1
                self.intro_timer = 0
                if self.intro_page >= 2:
                    self.state = "title"
            return

        if self.state == "title":
            if any_key_pressed():
                self.state = "menu"
            return

        if self.state == "menu":
            if any_key_pressed():
                self.state = "playing"
            return

        if self.state == "playing":
            if self.gameover_timer > 0:
                self.gameover_timer -= 1
                if self.gameover_timer == 0:
                    if self.score1 >= WIN_SCORE or self.score2 >= WIN_SCORE:
                        self.state = "champion"
                        pyxel.stop()
                        pyxel.play(0, 5)
                    else:
                        self.state = "gameover"
                return

            self.tank1.move(self.tank2)
            self.tank1.tick(self.bullets, 1)
            self.tank2.move(self.tank1)
            self.tank2.tick(self.bullets, 2)

            self._check_powerup_collect(self.tank1)
            self._check_powerup_collect(self.tank2)

            for b in self.bullets:
                b.update()
                if not b.active:
                    continue
                for tank, owner_id in [(self.tank2, 1), (self.tank1, 2)]:
                    if b.owner != owner_id or not tank.alive:
                        continue
                    dx = b.x - tank.x
                    dy = b.y - tank.y
                    if math.sqrt(dx * dx + dy * dy) < 14:
                        b.active = False
                        pyxel.play(1, 1)
                        if tank.shield:
                            tank.shield = False
                        else:
                            tank.hp -= 1
                            tank.hit_flash = 20
                            if tank.hp <= 0:
                                tank.alive = False
                                if b.owner == 1:
                                    self.score1 += 1
                                    self.winner = "Spieler 1"
                                else:
                                    self.score2 += 1
                                    self.winner = "Spieler 2"
                                pyxel.play(2, 2)
                                self.gameover_timer = 90

            self.bullets = [b for b in self.bullets if b.active]

            for pu in self.powerups:
                pu.update()
            self.powerups = [pu for pu in self.powerups if pu.active]

            self.powerup_timer -= 1
            if self.powerup_timer <= 0:
                self._try_spawn_powerup()
                self.powerup_timer = PU_INTERVAL

            return

        if self.state == "gameover":
            if any_key_pressed():
                self.reset_round()
                self.state = "playing"
            return

        if self.state == "champion":
            if any_key_pressed():
                self.score1 = 0
                self.score2 = 0
                self.winner = ""
                self.state = "intro"
                self.intro_page = 0
                self.intro_timer = 0

    # ----------------------------------------------------------
    # DRAW
    # ----------------------------------------------------------
    def draw(self):
        pyxel.cls(1)

        if self.state == "intro":
            self._draw_intro()
            return

        if self.state == "title":
            self._draw_title()
            return

        if self.state == "menu":
            self._draw_field()
            self._draw_hud()
            self._draw_menu()
            return

        self._draw_field()
        for pu in self.powerups:
            pu.draw()
        for b in self.bullets:
            b.draw()
        self.tank1.draw()
        self.tank2.draw()
        self._draw_hud()

        if self.state == "gameover":
            self._draw_gameover()
        elif self.state == "champion":
            self._draw_champion()

    # ----------------------------------------------------------
    def _draw_intro(self):
        f = pyxel.frame_count
        pyxel.rect(0, 0, WIDTH, HEIGHT, 0)

        if self.intro_page == 0:
            # Story page 1
            title = "IRON CLASH"
            pyxel.rect(56, 80, WIDTH - 112, 20, 5)
            pyxel.rectb(56, 80, WIDTH - 112, 20, 11)
            pyxel.text(WIDTH // 2 - len(title) * 2, 87, title, 11)

            lines = [
                "Im Jahr 2087 sind zwei rivalisierende",
                "Panzerkommandanten aufeinandergetroffen.",
                "",
                "Beide kaempfen um die Kontrolle",
                "ueber die verlassene Eisenfestung.",
                "",
                "Nur einer kann ueberleben.",
            ]
            for i, line in enumerate(lines):
                t = self.intro_timer - i * 12
                if t > 0:
                    alpha = min(t, 10) * 7 // 10
                    col = 7 if t > 10 else alpha
                    pyxel.text(WIDTH // 2 - len(line) * 2, 130 + i * 14, line, 7)

            # Animated tanks facing each other
            if self.intro_timer > 40:
                draw_tank_sprite(100, 400, DIR_RIGHT, 1)
                draw_tank_sprite(WIDTH - 100, 400, DIR_LEFT, 2)
                if f % 20 < 10:
                    pyxel.text(WIDTH // 2 - 44, 390, "VS", 8)

        else:
            # Story page 2 - controls
            pyxel.rect(56, 60, WIDTH - 112, 24, 5)
            pyxel.rectb(56, 60, WIDTH - 112, 24, 7)
            pyxel.text(WIDTH // 2 - 42, 69, "STEUERUNG", 7)

            lines2 = [
                ("Spieler 1:", "WASD = Bewegen  F = Schiessen", 11),
                ("Spieler 2:", "Pfeile = Bewegen  L = Schiessen", 8),
                ("", "", 7),
                ("Power-Ups auf dem Feld sammeln:", "", 7),
                (" SCHILD – blockiert 1 Treffer", "", 11),
                (" TEMPO  – kurzfristiger Speed-Boost", "", 10),
                (" FEUER  – Schnellfeuer-Modus", "", 8),
                ("", "", 7),
                (f"Wer zuerst {WIN_SCORE} Runden gewinnt, ist", "", 7),
                ("der EISERNE CHAMPION!", "", 10),
            ]
            for i, (label, rest, col) in enumerate(lines2):
                y = 105 + i * 14
                if label:
                    pyxel.text(60, y, label, col)
                if rest:
                    pyxel.text(60 + len(label) * 4 + 4, y, rest, 7)

        if f % 30 < 20:
            pyxel.text(WIDTH // 2 - 60, HEIGHT - 24, "Beliebige Taste weiter", 6)

    def _draw_title(self):
        f = pyxel.frame_count

        # Sky
        pyxel.rect(0, 0, WIDTH, HEIGHT, 1)

        # Ground
        pyxel.rect(0, 400, WIDTH, 112, 5)
        for c in range(33):
            wx = c * 16
            pyxel.rect(wx, 400, 15, 15, 5)
            pyxel.line(wx, 400, wx + 14, 400, 12)
            pyxel.line(wx, 400, wx, 414, 12)
            pyxel.line(wx + 14, 400, wx + 14, 414, 1)
            pyxel.rect(wx + 8, 416, 15, 15, 5)
            pyxel.line(wx + 8, 416, wx + 22, 416, 12)
            pyxel.line(wx + 8, 416, wx + 8, 430, 12)

        # Stone walls left and right
        for row in range(26):
            wy = row * 16
            pyxel.rect(0, wy, 28, 14, 5)
            pyxel.line(0, wy, 27, wy, 12)
            pyxel.line(0, wy, 0, wy + 13, 12)
            pyxel.line(27, wy, 27, wy + 13, 1)
            pyxel.rect(WIDTH - 28, wy, 28, 14, 5)
            pyxel.line(WIDTH - 28, wy, WIDTH - 1, wy, 12)
            pyxel.line(WIDTH - 28, wy, WIDTH - 28, wy + 13, 12)
            pyxel.line(WIDTH - 1, wy, WIDTH - 1, wy + 13, 1)

        # Clouds
        def draw_cloud(cx, cy, size):
            pyxel.circ(cx + 2,          cy + 2,      size,     6)
            pyxel.circ(cx + size + 2,   cy + 1,      size + 1, 6)
            pyxel.circ(cx + size * 2 + 2, cy + 2,    size,     6)
            pyxel.circ(cx,              cy,          size,     7)
            pyxel.circ(cx + size,       cy - 4,      size + 3, 7)
            pyxel.circ(cx + size * 2,   cy,          size,     7)
            pyxel.circ(cx + size + 1,   cy + size,   size - 1, 7)

        loop = WIDTH + 200
        ox1 = (f // 4) % loop
        draw_cloud(int((-ox1 + 60)  % loop) - 80, 36,  16)
        draw_cloud(int((-ox1 + 260) % loop) - 80, 20,  12)
        draw_cloud(int((-ox1 + 460) % loop) - 80, 44,  14)
        ox2 = (f // 2) % loop
        draw_cloud(int((-ox2 + 160) % loop) - 80, 60,  10)
        draw_cloud(int((-ox2 + 380) % loop) - 80, 50,  12)

        # Tank P1 (left)
        draw_tank_sprite(110, 370, DIR_RIGHT, 1)
        # Tank P2 (right)
        draw_tank_sprite(WIDTH - 110, 370, DIR_LEFT, 2)

        # Explosion in the middle
        draw_explosion(WIDTH // 2, 360, f)

        # Title box
        box_w = 220
        box_h = 72
        box_x = WIDTH // 2 - box_w // 2
        box_y = 14
        pyxel.rect(box_x, box_y, box_w, box_h, 0)
        pyxel.rectb(box_x, box_y, box_w, box_h, 11)
        pyxel.rectb(box_x + 2, box_y + 2, box_w - 4, box_h - 4, 1)

        iron = "IRON"
        ix = WIDTH // 2 - len(iron) * 4
        for ox in range(2):
            for oy in range(2):
                pyxel.text(ix + ox, box_y + 14 + oy, iron, 3)
        pyxel.text(ix, box_y + 14, iron, 11)

        clash = "CLASH"
        cx2 = WIDTH // 2 - len(clash) * 4
        for ox in range(2):
            for oy in range(2):
                pyxel.text(cx2 + ox, box_y + 42 + oy, clash, 2)
        pyxel.text(cx2, box_y + 42, clash, 8)

        pyxel.text(40, 440, "S1: WASD + F", 11)
        pyxel.text(WIDTH - 90, 440, "S2: Pfeile + L", 8)

        goal = f"Ziel: {WIN_SCORE} Runden gewinnen!"
        pyxel.text(WIDTH // 2 - len(goal) * 2, 460, goal, 10)

        if f % 30 < 20:
            start = "Beliebige Taste = Start"
            pyxel.text(WIDTH // 2 - len(start) * 2, 480, start, 7)

    def _draw_field(self):
        pyxel.rect(0, FIELD_Y, WIDTH, HEIGHT - FIELD_Y, 0)
        for ty in range(ROWS):
            for tx in range(COLS):
                if TILEMAP[ty][tx] == 1:
                    wx = tx * TILE
                    wy = FIELD_Y + ty * TILE
                    pyxel.rect(wx, wy, TILE, TILE, 5)
                    pyxel.line(wx, wy, wx + TILE - 1, wy, 12)
                    pyxel.line(wx, wy, wx, wy + TILE - 1, 12)
                    pyxel.line(wx + TILE - 1, wy, wx + TILE - 1, wy + TILE - 1, 1)
                    pyxel.line(wx, wy + TILE - 1, wx + TILE - 1, wy + TILE - 1, 1)

    def _draw_hud(self):
        pyxel.rect(0, 0, WIDTH, HUD_H, 0)
        pyxel.line(0, HUD_H - 1, WIDTH, HUD_H - 1, 5)
        pyxel.line(0, HUD_H - 2, WIDTH, HUD_H - 2, 1)

        # P1 side
        pyxel.text(4, 4, "SPIELER 1", 11)
        pyxel.text(4, 14, "WASD+F", 6)
        for i in range(MAX_HP):
            draw_heart(4 + i * 10, 26, 11 if i < self.tank1.hp else 2)

        # Center score
        goal_txt = f"BIS {WIN_SCORE}"
        pyxel.text(WIDTH // 2 - len(goal_txt) * 2, 4, goal_txt, 6)
        score_txt = f"{self.score1}  :  {self.score2}"
        pyxel.text(WIDTH // 2 - len(score_txt) * 2, 14, score_txt, 7)
        # Score bar
        if self.score1 + self.score2 > 0:
            bw = 80
            bx = WIDTH // 2 - bw // 2
            pyxel.rectb(bx, 28, bw, 8, 5)
            s1w = int(bw * self.score1 / WIN_SCORE)
            s2w = int(bw * self.score2 / WIN_SCORE)
            if s1w > 0:
                pyxel.rect(bx, 29, s1w, 6, 11)
            if s2w > 0:
                pyxel.rect(bx + bw - s2w, 29, s2w, 6, 8)

        # P2 side
        p2_label = "SPIELER 2"
        p2_ctrl = "Pfeile+L"
        pyxel.text(WIDTH - len(p2_label) * 4 - 4, 4, p2_label, 8)
        pyxel.text(WIDTH - len(p2_ctrl) * 4 - 4, 14, p2_ctrl, 6)
        for i in range(MAX_HP):
            draw_heart(WIDTH - 14 - i * 10, 26, 8 if i < self.tank2.hp else 2)

    def _draw_menu(self):
        x, y, w, h = 80, FIELD_Y + 60, WIDTH - 160, 120
        pyxel.rect(x, y, w, h, 0)
        pyxel.rectb(x, y, w, h, 7)
        pyxel.rectb(x + 2, y + 2, w - 4, h - 4, 5)
        title = "IRON CLASH"
        pyxel.text(WIDTH // 2 - len(title) * 4, y + 16, title, 10)
        sub = "Zwei Spieler - eine Tastatur"
        pyxel.text(WIDTH // 2 - len(sub) * 2, y + 40, sub, 7)
        goal = f"Wer zuerst {WIN_SCORE} Runden gewinnt, ist Champion!"
        pyxel.text(WIDTH // 2 - len(goal) * 2, y + 58, goal, 6)
        cont = "Beliebige Taste = Start"
        pyxel.text(WIDTH // 2 - len(cont) * 2, y + 80, cont, 11)

    def _draw_gameover(self):
        x, y, w, h = 80, FIELD_Y + 80, WIDTH - 160, 100
        pyxel.rect(x, y, w, h, 0)
        pyxel.rectb(x, y, w, h, 7)
        msg = f"{self.winner} GEWINNT!"
        pyxel.text(WIDTH // 2 - len(msg) * 2, y + 12, msg, 10)
        score_txt = f"Stand: {self.score1} : {self.score2}  (Ziel: {WIN_SCORE})"
        pyxel.text(WIDTH // 2 - len(score_txt) * 2, y + 32, score_txt, 7)
        cont = "Beliebige Taste = Naechste Runde"
        pyxel.text(WIDTH // 2 - len(cont) * 2, y + 58, cont, 6)

    def _draw_champion(self):
        f = pyxel.frame_count
        # Confetti effect
        random.seed(42)
        for i in range(30):
            cx2 = random.randint(0, WIDTH)
            cy2 = (random.randint(0, HEIGHT) + f * (i % 3 + 1)) % HEIGHT
            pyxel.pset(cx2, cy2, random.choice([8, 9, 10, 11, 12]))
        random.seed()

        x, y, w, h = 60, FIELD_Y + 60, WIDTH - 120, 160
        pyxel.rect(x, y, w, h, 0)
        pyxel.rectb(x, y, w, h, 10)
        pyxel.rectb(x + 2, y + 2, w - 4, h - 4, 9)

        if f % 20 < 10:
            trophy = "*** CHAMPION ***"
            pyxel.text(WIDTH // 2 - len(trophy) * 2, y + 14, trophy, 10)

        msg = f"{self.winner} IST"
        pyxel.text(WIDTH // 2 - len(msg) * 2, y + 34, msg, 7)
        big = "EISERNER CHAMPION!"
        for ox in range(2):
            for oy in range(2):
                pyxel.text(WIDTH // 2 - len(big) * 2 + ox, y + 52 + oy, big, 2)
        pyxel.text(WIDTH // 2 - len(big) * 2, y + 52, big, 9)

        score_txt = f"Endstand: {self.score1} : {self.score2}"
        pyxel.text(WIDTH // 2 - len(score_txt) * 2, y + 80, score_txt, 7)

        again = "Beliebige Taste = Neues Spiel"
        pyxel.text(WIDTH // 2 - len(again) * 2, y + 108, again, 6)


App()