import pyxel
import random
import math

# 10 Blöcke breite Mine + 2 Blöcke Rand = 12 Blöcke Breite
W, H, T = 160, 120, 8
MW, MH = 12, 1200  
SPD = 0.25

# Layer-Grenzen für Erzvorkommen
DIRT_END     = 50
COPPER_END   = 150
IRON_END     = 300
GOLD_END     = 600
DIAMOND_END  = 1100

# Abbau-Zeiten (0=Hand, 1=Schaufel, 2=Holz, 3=Stein, 4=Eisen, 5=Gold, 6=Prisma, 7=Diamant)
MT = {
    4: [10,5,3,1,1,1,1,1],      # Gras
    5: [20,10,5,2,1,1,1,1],     # Erde
    1: [999,60,20,10,4,2,1,1],  # Stein
    3: [999,999,30,15,6,3,2,1], # Tiefenstein
    7: [999,999,40,20,8,4,2,1], # Kohle
    9: [999,999,999,35,12,6,3,1],# Eisen
    10:[999,999,999,999,25,12,5,1],# Gold
    11:[999,999,999,999,50,20,8,1],# Smaragd
    12:[999,999,999,999,999,30,12,1],# Diamant
    13:[999,999,999,999,999,999,999,999], # Lava (unzerstörbar)
    22:[999,999,999,999,999,999,999,999], # Bedrock/Rand (unzerstörbar)
}

# Erz-Werte (Verkaufspreise)
BV = {4:1, 5:2, 1:4, 3:8, 7:15, 9:40, 10:100, 11:250, 12:750, 13:0, 22:0}
P_COLOR = {4:11, 5:4, 1:6, 3:5, 7:0, 9:10, 10:14, 11:11, 12:10}
TOOL_COLORS = [7, 4, 11, 6, 10, 9, 12, 11]

WIN_ROW = 1195

# Startposition (Mitte der 10er Mine)
px, py = 5.0, 13.0
cam = 0
money = pending = inv = 0
inv_max = 10
tool = 0
shop = False
shop_scroll = 0
fv = 0.0 # Fallgeschwindigkeit
mining = False
mx = my = mp = mt_val = 0
won = False
shake = 0

msg = ["", 0, 7]
particles = []

def solid(x, y):
    ix, iy = int(x), int(y)
    if ix < 0 or ix >= MW: return True
    if iy < 0: return False
    if iy >= MH: return True
    if world[iy][ix] == 13: return False 
    return world[iy][ix] != 0

def on_gnd():
    return solid(int(px), int(py) + 1) or solid(int(px + 0.99), int(py) + 1)

def spawn_particles(x, y, color):
    for _ in range(5):
        particles.append([x, y, (random.random()-0.5)*3, (random.random()-1)*3, random.randint(8,15), color])

# Welt generieren
world = []
for _y in range(MH):
    row = []
    for _x in range(MW):
        if _x == 0 or _x == MW - 1:
            row.append(22) 
        elif _y < 14:
            row.append(0)
        elif _y == 14:
            row.append(22 if 4 <= _x <= 6 else 4) 
        elif _y < DIRT_END:
            row.append(4 if random.random() < 0.4 else 5)
        elif _y < COPPER_END:
            row.append(1 if random.random() < 0.2 else (7 if random.random() < 0.1 else 5))
        elif _y < IRON_END:
            row.append(1 if random.random() < 0.7 else (9 if random.random() < 0.08 else 7))
        elif _y < GOLD_END:
            r = random.random()
            if r < 0.6: row.append(3)
            elif r < 0.8: row.append(1)
            elif r < 0.88: row.append(10 if r < 0.84 else 9)
            else: row.append(13) 
        elif _y < DIAMOND_END:
            r = random.random()
            if r < 0.5: row.append(3)
            elif r < 0.7: row.append(13) 
            elif r < 0.9: row.append(11 if r < 0.85 else 10)
            else: row.append(1)
        elif _y < WIN_ROW:
            r = random.random()
            if r < 0.4: row.append(13) 
            elif r < 0.7: row.append(12) 
            else: row.append(3)
        elif _y == WIN_ROW:
            row.append(14) 
        else:
            row.append(0)
    world.append(row)

SHOP_X, SHOP_Y, SHOP_W, SHOP_H = 10, 15, 140, 90
SHOP_INNER_Y, SHOP_INNER_H = 30, 50
ITEM_H = 12

SHOP_ITEMS = [
    ("WAREN VERKAUFEN", 0, "sell", 0),
    ("Schaufel (15g)", 15, "tool", 1),
    ("Holz-Picke (50g)", 50, "tool", 2),
    ("Stein-Picke (150g)", 150, "tool", 3),
    ("Eisen-Picke (500g)", 500, "tool", 4),
    ("Gold-Picke (1500g)", 1500, "tool", 5),
    ("Prisma-Picke (5000g)", 5000, "tool", 6),
    ("Diamant-Picke (20000g)", 20000, "tool", 7),
    ("Rucksack Med (100g)", 100, "bag", 25),
    ("Rucksack Big (500g)", 500, "bag", 100)
]

def update():
    global px, py, cam, money, pending, inv, inv_max, tool, shop, shop_scroll
    global fv, mining, mx, my, mp, mt_val, won, msg, shake
    
    if won:
        if pyxel.btnp(pyxel.KEY_R):
            won = False; px, py = 5.0, 13.0; money = pending = inv = 0; tool = 0; inv_max = 10
        return

    if msg[1] > 0: msg[1] -= 1
    if shake > 0: shake -= 1

    for p in particles[:]:
        p[0] += p[2]; p[1] += p[3]; p[3] += 0.2; p[4] -= 1
        if p[4] <= 0: particles.remove(p)

    ctx, cty = int(px + 0.5), int(py + 0.5)
    if 0 <= ctx < MW and 0 <= cty < MH and world[cty][ctx] == 13:
        px, py = 5.0, 13.0; fv = 0.0; inv = pending = 0
        msg = ["LAVA-TOD! Inventar verloren", 60, 8]; shake = 15
        for _ in range(15): spawn_particles(px*T, py*T, 8)

    gnd = on_gnd()
    if gnd:
        if fv > 4.0: 
            px, py = 5.0, 13.0; inv = pending = 0
            msg = ["FALLSCHADEN! Rucksack leer", 60, 12]; shake = 15
            for _ in range(15): spawn_particles(px*T, py*T, 8)
        fv = 0.0
        if int(py) + 1 == WIN_ROW: won = True; return
    else:
        fv = min(fv + 0.25, 6.0)
        for _ in range(int(fv) + 1):
            if not solid(int(px), int(py) + 1) and not solid(int(px + 0.99), int(py) + 1):
                py += 0.25
            else:
                break

    if not shop:
        if pyxel.btn(pyxel.KEY_A) or pyxel.btn(pyxel.KEY_LEFT):
            nx = px - SPD
            if not solid(nx, py) and not solid(nx, py + 0.99): px = nx; mining = False
        if pyxel.btn(pyxel.KEY_D) or pyxel.btn(pyxel.KEY_RIGHT):
            nx = px + SPD
            if not solid(nx + 0.99, py) and not solid(nx + 0.99, py + 0.99): px = nx; mining = False

    if pyxel.btnp(pyxel.KEY_W) and gnd and fv == 0.0:
        jump = 0
        for j in range(1, 4):
            if not solid(int(px), int(py) - j) and not solid(int(px + 0.99), int(py) - j): jump += 1
            else: break
        py -= float(jump)

    if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
        if W - 32 <= pyxel.mouse_x <= W - 4 and 2 <= pyxel.mouse_y <= 10:
            loss = int(pending * 0.20)
            pending -= loss
            px, py = 5.0, 13.0; fv = 0.0; mining = False; shop = False
            msg = [f"Teleport! Gebuehr: -{loss}g", 45, 11]
            return

    near = math.sqrt((px - 5)**2 + (py - 12)**2) < 3.5
    if near and pyxel.btnp(pyxel.KEY_E): shop = not shop; shop_scroll = 0
    if not near: shop = False

    if shop:
        if pyxel.btn(pyxel.KEY_S) or pyxel.btn(pyxel.KEY_DOWN): shop_scroll = min(shop_scroll + 2, max(0, len(SHOP_ITEMS)*ITEM_H - SHOP_INNER_H))
        if pyxel.btn(pyxel.KEY_W) or pyxel.btn(pyxel.KEY_UP): shop_scroll = max(shop_scroll - 2, 0)
        if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
            mx_c, my_c = pyxel.mouse_x, pyxel.mouse_y
            if SHOP_X <= mx_c <= SHOP_X + SHOP_W and SHOP_INNER_Y <= my_c <= SHOP_INNER_Y + SHOP_INNER_H:
                idx = (my_c - SHOP_INNER_Y + shop_scroll) // ITEM_H
                if 0 <= idx < len(SHOP_ITEMS):
                    lbl, cost, itype, param = SHOP_ITEMS[idx]
                    if itype == 'sell' and inv > 0: money += pending; pending = inv = 0
                    elif itype == 'tool' and money >= cost and tool == param - 1: money -= cost; tool = param
                    elif itype == 'bag' and money >= cost:
                        if param == 25 and inv_max == 10: money -= cost; inv_max = 25
                        elif param == 100 and inv_max == 25: money -= cost; inv_max = 100

    if pyxel.btn(pyxel.MOUSE_BUTTON_LEFT) and not shop:
        tx = pyxel.mouse_x // T
        ty = int((pyxel.mouse_y + cam) // T)
        if 0 <= tx < MW and 0 <= ty < MH:
            b = world[ty][tx]
            if b not in [0, 13, 14, 22] and math.sqrt((px + 0.5 - tx - 0.5)**2 + (py + 0.5 - ty - 0.5)**2) < 4:
                if mining and mx == tx and my == ty:
                    mp += 1
                    if mp >= mt_val:
                        world[ty][tx] = 0; mining = False
                        spawn_particles(tx*T + 4, ty*T + 4, P_COLOR.get(b, 7))
                        pending += BV.get(b, 0); inv = min(inv_max, inv + 1)
                else:
                    times = MT.get(b, [999]*8)
                    mt_val = times[tool]
                    if mt_val < 999 and inv < inv_max: mining = True; mx, my, mp = tx, ty, 0

    if not pyxel.btn(pyxel.MOUSE_BUTTON_LEFT): mining = False
    cam = max(0, min(MH * T - H, int(py * T) - H // 2))

def draw_block(x, y, c1, c2, noise=True):
    pyxel.rect(x, y, T, T, c1); pyxel.rectb(x, y, T, T, c2)
    if noise and (x * 3 + y * 7) % 5 == 0: pyxel.pset(x + 2, y + 2, c2)

def draw_ore(x, y, c1, c2, ore_c):
    draw_block(x, y, c1, c2, True)
    pyxel.pset(x+3, y+2, ore_c); pyxel.pset(x+5, y+5, ore_c)

def draw():
    pyxel.cls(6)
    cx = random.randint(-1, 1) if shake > 0 else 0
    cy = random.randint(-1, 1) if shake > 0 else 0
    pyxel.camera(cx, cy)
    
    for r in range(cam // T, (cam + H) // T + 1):
        if r >= MH: break
        for c in range(MW):
            b = world[r][c]
            if b == 0: continue
            x, y = c * T, r * T - cam
            
            if b == 4: draw_block(x, y, 4, 13)
            elif b == 5: draw_block(x, y, 4, 3)
            elif b == 1: draw_block(x, y, 6, 7)
            elif b == 3: draw_block(x, y, 5, 1)
            elif b == 7: draw_ore(x, y, 6, 7, 0) 
            elif b == 9: draw_ore(x, y, 6, 7, 10) 
            elif b == 10: draw_ore(x, y, 5, 1, 14) 
            elif b == 11: draw_ore(x, y, 5, 1, 11) 
            elif b == 12: draw_ore(x, y, 2, 0, 12) 
            elif b == 13: 
                pyxel.rect(x, y + (pyxel.frame_count//10)%2, T, T, 8) 
            elif b == 14: draw_block(x, y, 10, 9, False)
            elif b == 22: draw_block(x, y, 13, 5, False) 

    if mining:
        bx, by = mx * T, my * T - cam
        p = mp / mt_val
        if p > 0.2: pyxel.line(bx+1, by+1, bx+3, by+3, 0)
        if p > 0.6: pyxel.line(bx+3, by+3, bx+6, by+5, 0)

    if cam < 40:
        nx, ny = 5 * T, 12 * T - cam
        pyxel.rect(nx + 1, ny + 4, 6, 12, 1)
        pyxel.rect(nx + 2, ny + 1, 4, 4, 14)
        pyxel.rect(nx + 2, ny + 4, 4, 4, 7) 
        pyxel.rect(nx + 1, ny - 2, 6, 3, 4) 
        pyxel.line(nx - 1, ny, nx + 8, ny, 4)
        pyxel.text(nx - 16, ny - 10, "STORE [E]", 7)

    px_s, py_s = int(px * T), int(py * T) - cam
    pyxel.rect(px_s+1, py_s+2, 6, 5, 9)
    pyxel.pset(px_s+2, py_s+1, 9); pyxel.pset(px_s+5, py_s+1, 9)

    for p in particles: pyxel.pset(int(p[0]), int(p[1]) - cam, p[5])

    pyxel.camera(0, 0)
    pyxel.rect(0, 0, W, 12, 0)
    pyxel.text(4, 3, f"GOLD:{money}", 10)
    if pending > 0: pyxel.text(42, 3, f"+{pending}", 9)
    
    pyxel.text(78, 3, f"BAG:{inv}/{inv_max}", 8 if inv >= inv_max else 7)
    
    pyxel.rect(W - 32, 2, 28, 8, 1)
    pyxel.rectb(W - 32, 2, 28, 8, 12)
    pyxel.text(W - 26, 4, "UP ^", 7)

    pyxel.text(4, H - 10, f"Tiefe: {max(0, int(py)-14)}m", 7)
    if tool > 0: pyxel.text(W - 55, H - 10, "PICK", TOOL_COLORS[tool])

    if msg[1] > 0:
        pyxel.rect(W//2 - len(msg[0])*2 - 4, H//2 - 4, len(msg[0])*4 + 8, 11, 0)
        pyxel.text(W//2 - len(msg[0])*2, H//2, msg[0], msg[2])

    if shop:
        pyxel.rect(SHOP_X, SHOP_Y, SHOP_W, SHOP_H, 1)
        pyxel.rectb(SHOP_X, SHOP_Y, SHOP_W, SHOP_H, 9)
        pyxel.text(SHOP_X+30, SHOP_Y+4, "== UPGRADES ==", 10)
        for i, (lbl, cost, itype, param) in enumerate(SHOP_ITEMS):
            item_top = SHOP_INNER_Y + i * ITEM_H - shop_scroll
            if item_top + ITEM_H < SHOP_INNER_Y or item_top > SHOP_INNER_Y + SHOP_INNER_H: continue
            col = 5 if itype == 'sell' and inv > 0 else 2
            if itype == 'tool': col = 11 if tool >= param else (3 if money >= cost and tool == param-1 else 2)
            if itype == 'bag': col = 11 if (param==25 and inv_max>=25) or (param==100 and inv_max==100) else (3 if money >= cost else 2)
            pyxel.rect(SHOP_X+8, item_top, SHOP_W-24, ITEM_H-2, col)
            disp = f"VERKAUFEN (+{pending}g)" if itype == 'sell' else lbl
            pyxel.text(SHOP_X+12, item_top+2, disp, 7)

    if won:
        pyxel.rect(20, 40, 120, 40, 0); pyxel.rectb(20, 40, 120, 40, 10)
        pyxel.text(45, 50, "GEWONNEN!", 10); pyxel.text(30, 65, "Druecke 'R' fuer Restart", 7)

pyxel.init(W, H, title="Narrow Mine", fps=30)
pyxel.mouse(True) # <--- HIERMIT WIRD DIE MAUS SICHTBAR GEMACHT!
pyxel.run(update, draw)