import pyxel
import math
import random

# ── Constants ─────────────────────────────────────────────────────────────────
W, H         = 400, 400  
TILE         = 16                
COLS         = W // TILE        
ROWS         = H // TILE        
FPS          = 30

MAX_ECHOES   = 1
ECHO_SPEED   = 2.8              
ECHO_MAX_R   = 240              
LIT_FRAMES   = 8                # Increased slightly for better visibility

PLAYER_ECHO_CD = 35            
ENEMY_ECHO_CD  = 220            # Enemies pulse a bit faster for challenge

# ── Tile IDs ──────────────────────────────────────────────────────────────────
T_FLOOR  = 0
T_WALL   = 1
T_DOOR_A = 2    
T_DOOR_B = 3    
T_BABY   = 4
T_SPAWN  = 5

# ── Level Data (All 25x25) ────────────────────────────────────────────────────
RAW_LEVELS = [
    [ # Level 1: Redesigned - Branching, Corrected paths, Full utilization
        "#########################",
        "#S......#.......#.......#",
        "#.#####.#.#####.#.#####.#",
        "#.#...#...#...#...#...#.#",
        "#.#.#.#######.#######.#.#",
        "#...#.#.....#.......#...#",
        "#####.#.###.#.#####.#####",
        "#.....#.#.#.#.#...#.....#",
        "#.#####.#.#.###.#.#####.#",
        "#.#.......#.....#.......#",
        "#.#.#######.#####.#####.#",
        "#.#.#.....#.....#.#...#.#",
        "#.#.#.###.#####.#.#.#.#.#",
        "#...#.#.#.......#...#.#.#",
        "#####.#.#########.###.#.#",
        "#.....#.........#.#...#.#",
        "#.#######.#####.#.#.###.#",
        "#.#.......#...#.#.#.....#",
        "#.#.#######.#.#.#######.#",
        "#.#.#.......#.#.......#.#",
        "#.#.#.#######.#######.#.#",
        "#...#.#...............#.#",
        "#####.#.###############.#",
        "#.......#..............X#",
        "#########################"
    ],
    [ # Level 2: Design 3.1
        "#########################",
        "#S.#...........#A.......#",
        "##.#.###########.######.#",
        "#..#.#....B....#......#.#",
        "#.##.#.#######.######.#.#",
        "#..#.#.#.....#......#.#.#",
        "##.#.#.#.###.######.B.#.#",
        "#....#.#...#.#X.....#...#",
        "#.####.###.#.#.######.###",
        "#.#......#...#......#...#",
        "#.#.####.###########.##.#",
        "#.#.##.#.....#.....#..#.#",
        "#.#.#..#####.#.###.##.#.#",
        "#.#.##.....#...#.#B.#.#.#",
        "#.#..#####.#####.#..#.#.#",
        "#.##.......#...#.#.##.#.#",
        "#..#########A#.#.A.#..#.#",
        "##...........#...#.#.##.#",
        "##############B###.#..#.#",
        "#................#A##.#.#",
        "#.################..#.#.#",
        "#B.............#....#.B.#",
        "#########B####.#.####.#.#",
        "#..............#A.....#.#",
        "#########################"
    ],
    [ # Level 3: The Crossroads
        "#########################",
        "#S.#........2#2.......#.#",
        "##.#.#######.#.######.#.#",
        "#..#.#.....#.#.#......#.#",
        "#.##.#.###.#.#.#.####.#.#",
        "#.#..#...#.#.#.#.#....#.#",
        "#.#.####.#.#.#.#.#.##.#.#",
        "#.#....#.#.#.#.#.#..#.#.#",
        "#.####.#.#.#.#.#.##.#.#.#",
        "#....#...#.#.#.#....#.#.#",
        "####.#####.#.#.######.#.#",
        "#..........#.#..........#",
        "#1......................#",
        "#..........#.#..........#",
        "####.#######.#.######.#.#",
        "#....#.....#.#.#....#.#.#",
        "#.####.###.#.#.#.##.#.#.#",
        "#.#....#...#.#.#..#.#.#.#",
        "#.#.####.###.#.##.#.#.#.#",
        "#.#.#....#...#....#.#.#.#",
        "#.###.####.########.###.#",
        "#...#.#....#......#...#.#",
        "###.#.#.####.####.###.#.#",
        "#.....#.............X.#.#",
        "#########################"
    ],
    [ # Level 4: Blend of Doors and Enemies
        "#########################",
        "#S#.....#.......#.......#",
        "#..###..#.#.###.###.#.#.#",
        "#.....#.#.#.#.....#.#.#.#",
        "#####.#.#A#.#####.#.#.#.#",
        "#.B.#.#...#.....#...#...#",
        "#.#.#.###.###.#.######..#",
        "#.#.....#.....#.......#.#",
        "#..###..#########A#.#.#.#",
        "#.....#...#.......#.#.#.#",
        "#.#.#.###.#A#####.###.#.#",
        "#...#.#...#.#...#.....#.#",
        "#.#.###.###.#.#B#######.#",
        "#.#.....#...#.#.......#.#",
        "#.###.###.#####.#####.#B#",
        "#.#...........#...#.#...#",
        "#.#######.###.###...#####",
        "#.......#...#.#...#.....#",
        "#######.#####.#.#######.#",
        "#.A...#...#...#.#.......#",
        "#.#######.#.###.###.###.#",
        "#.#.....#.....#.........#",
        "#B#.#.#######.#######.###",
        "#...#..................X#",
        "#########################"
    ],
    [ # Level 5: The Grand Finale
        "#########################",
        "#S..#.........#.........#",
        "###A#.###.##..#..######.#",
        "#...#.#.......#.......#.#",
        "#.###.###.#.#.###.###.#.#",
        "#.#.#.B...#.#...B.#...#.#",
        "#.#.#B###A#######.#.#.#.#",
        "#.#.......#.....#...#.#.#",
        "#.#..######..##.#.###.#.#",
        "#.#.......#...#.B.#.....#",
        "#.###.#####.#.#####..##.#",
        "#.........#.#.#.....#...#",
        "###.#.###.###.##..###.###",
        "#.#...#.#...#.A.#...#...#",
        "#.##.##.###.#.#.###.#.#.#",
        "#.....#.....#.#...#.....#",
        "#.###.#..####.###.#.#####",
        "#...#...#.#.....#A#...B.#",
        "###.#.#.#.#.#####.#.#.#.#",
        "#...#...#...#...#.#.#.#.#",
        "#.#####.###.#...#.#.#.###",
        "#.#...#...#.#.#...#.#...#",
        "#.#.#A###.###.#####A###.#",
        "#...#.........#..B.....X#",
        "#########################"
    ]
]

# Enemy patrol paths scaled for the new maze dimensions
LEVEL_ENEMIES = {
    3: [ 
        ([(1, 12), (23, 12)], 1.6),  # Horizontal sweep crossing the center
        ([(12, 1), (12, 23)], 1.1),  # Vertical left (slow)
        ([(14, 1), (14, 23)], 2.5)   # Vertical right (fast, dangerous)
    ],
    4: [ ([(4, 15), (13, 15)], 1.6), ([(17, 21), (23, 21)], 1.6) ],
    5: [ ([(9, 2), (9, 7)], 1.6), ([(3, 9), (9, 9)], 1.6), ([(19, 13), (19, 23)], 1.6), ([(7, 17), (7, 21)], 1.6) ]
}

def parse_level(raw):
    grid, spawn, baby = [], (1, 1), (1, 1)
    for r, row in enumerate(raw):
        line = []
        for c, ch in enumerate(row):
            if   ch == '#': line.append(T_WALL)
            elif ch == 'A': line.append(T_DOOR_A)
            elif ch == 'B': line.append(T_DOOR_B)
            elif ch == 'X': line.append(T_BABY); baby = (c, r)
            elif ch == 'S': line.append(T_SPAWN); spawn = (c, r)
            else: line.append(T_FLOOR)
        grid.append(line)
    return grid, spawn, baby

class Echo:
    def __init__(self, x, y, owner="player"):
        self.x, self.y, self.r, self.owner, self.dead = float(x), float(y), 0.0, owner, False
    def update(self):
        self.r += ECHO_SPEED
        if self.r >= ECHO_MAX_R: self.dead = True
    def hits_tile(self, tc, tr):
        # Calculate center point of tile to check collision with circular wave
        d = math.hypot(tc * TILE + TILE // 2 - self.x, tr * TILE + TILE // 2 - self.y)
        return abs(d - self.r) < (TILE * 1.2)

class VisBuffer:
    def __init__(self): self.buf = [[0]*COLS for _ in range(ROWS)]
    def reset(self): self.buf = [[0]*COLS for _ in range(ROWS)]
    def illuminate(self, tc, tr):
        if 0 <= tr < ROWS and 0 <= tc < COLS: self.buf[tr][tc] = LIT_FRAMES
    def tick(self):
        for r in range(ROWS):
            for c in range(COLS):
                if self.buf[r][c] > 0: self.buf[r][c] -= 1
    def is_lit(self, tc, tr): return self.buf[tr][tc] > 0 if 0 <= tr < ROWS and 0 <= tc < COLS else False

class DarkBuffer:
    def __init__(self): self.buf = [[0]*COLS for _ in range(ROWS)]
    def reset(self): self.buf = [[0]*COLS for _ in range(ROWS)]
    def darken(self, tc, tr):
        if 0 <= tr < ROWS and 0 <= tc < COLS: self.buf[tr][tc] = LIT_FRAMES
    def tick(self):
        for r in range(ROWS):
            for c in range(COLS):
                if self.buf[r][c] > 0: self.buf[r][c] -= 1
    def is_dark(self, tc, tr): return self.buf[tr][tc] > 0 if 0 <= tr < ROWS and 0 <= tc < COLS else False

class Player:
    SPEED = 2.4
    def __init__(self, tx, ty): self.x, self.y = float(tx * TILE + TILE // 2), float(ty * TILE + TILE // 2)
    def reset_to(self, tx, ty): self.x, self.y = float(tx * TILE + TILE // 2), float(ty * TILE + TILE // 2)
    def update(self, grid, any_echo):
        dx = dy = 0.0
        if pyxel.btn(pyxel.KEY_LEFT) or pyxel.btn(pyxel.KEY_A): dx -= self.SPEED
        if pyxel.btn(pyxel.KEY_RIGHT) or pyxel.btn(pyxel.KEY_D): dx += self.SPEED
        if pyxel.btn(pyxel.KEY_UP) or pyxel.btn(pyxel.KEY_W): dy -= self.SPEED
        if pyxel.btn(pyxel.KEY_DOWN) or pyxel.btn(pyxel.KEY_S): dy += self.SPEED
        if dx and dy: dx *= 0.707; dy *= 0.707
        nx, ny = self.x + dx, self.y + dy
        if not self._collides(nx, self.y, grid, any_echo): self.x = nx
        if not self._collides(self.x, ny, grid, any_echo): self.y = ny
    def _collides(self, nx, ny, grid, any_echo):
        # Small hitbox check around the player center
        for ox, oy in [(-3, -3), (-3, 3), (3, -3), (3, 3)]:
            tc, tr = int((nx + ox) // TILE), int((ny + oy) // TILE)
            if not (0 <= tr < ROWS and 0 <= tc < COLS): return True
            tile = grid[tr][tc]
            # T_DOOR_A: Only open when echo is active
            # T_DOOR_B: Only open when echo is inactive
            if tile == T_WALL: return True
            if tile == T_DOOR_A and not any_echo: return True
            if tile == T_DOOR_B and any_echo: return True
        return False
    def tile_pos(self): return int(self.x // TILE), int(self.y // TILE)
    def draw(self):
        x, y = int(self.x), int(self.y)
        flap = math.sin(pyxel.frame_count * 0.6) * 4
        # Bat wings
        pyxel.tri(x, y, x - 12, y - flap, x - 4, y + 4, 5)
        pyxel.tri(x, y, x + 12, y - flap, x + 4, y + 4, 5)
        pyxel.circ(x, y, 2, 1) # Bat head

class Enemy:
    def __init__(self, path_data):
        if isinstance(path_data, tuple):
            self.path, self.SPEED = path_data
        else:
            self.path, self.SPEED = path_data, 1.6
        self.pidx, self.echo_cd = 0, random.randint(0, ENEMY_ECHO_CD)
        self.x, self.y = float(self.path[0][0] * TILE + TILE // 2), float(self.path[0][1] * TILE + TILE // 2)
    def update(self, echoes):
        tx, ty = self.path[self.pidx]
        gx, gy = tx * TILE + TILE // 2, ty * TILE + TILE // 2
        dx, dy = gx - self.x, gy - self.y
        dist = math.hypot(dx, dy)
        if dist < self.SPEED + 1:
            self.pidx = (self.pidx + 1) % len(self.path)
        else:
            self.x += dx / dist * self.SPEED
            self.y += dy / dist * self.SPEED
       
        self.echo_cd -= 1
        if self.echo_cd <= 0:
            echoes.append(Echo(self.x, self.y, owner="enemy"))
            self.echo_cd = ENEMY_ECHO_CD
    def draw(self):
        x, y = int(self.x), int(self.y)
        flap = math.sin(pyxel.frame_count * 0.8) * 5
        pyxel.tri(x, y, x - 10, y - flap, x - 3, y + 3, 2)
        pyxel.tri(x, y, x + 10, y - flap, x + 3, y + 3, 2)
        pyxel.circ(x, y, 2, 0)
        pyxel.pset(x-1, y, 8)
        pyxel.pset(x+1, y, 8)

class Game:
    ST_TITLE, ST_PLAY, ST_WIN, ST_NEXT, ST_FINISH, ST_RESPAWN = 0, 1, 2, 3, 4, 5
    def __init__(self):
        pyxel.init(W, H, title="Echo-Location", fps=FPS)
        self.level_idx, self.state, self.win_timer, self.pulse_r, self.flash, self.respawn_timer = 0, self.ST_TITLE, 0, 0.0, 0, 0
        
        # SFX
        pyxel.sounds[0].set("a3f3", "p", "6", "f", 10)     # Echo ping
        pyxel.sounds[1].set("c2a1c1a0", "n", "7", "f", 15) # Death hiss
        pyxel.sounds[2].set("c3e3g3c4", "s", "6", "s", 8)  # Win jingle
        
        # BGM
        pyxel.sounds[3].set("a2c3e3a3 c3e3a3c4", "t", "4", "n", 15)
        pyxel.sounds[4].set("g2b2d3g3 b2d3g3b3", "t", "4", "n", 15)
        pyxel.sounds[5].set("f2a2c3f3 a2c3f3a3", "t", "4", "n", 15)
        pyxel.sounds[6].set("e2g2b2e3 g2b2e3g3", "t", "4", "n", 15)
        pyxel.sounds[7].set("a1a1a1a1 a1a1a1a1", "s", "2", "n", 15)
        pyxel.sounds[8].set("g1g1g1g1 g1g1g1g1", "s", "2", "n", 15)
        pyxel.sounds[9].set("f1f1f1f1 f1f1f1f1", "s", "2", "n", 15)
        pyxel.sounds[10].set("e1e1e1e1 e1e1e1e1", "s", "2", "n", 15)
        pyxel.musics[0].set([3, 4, 5, 6], [7, 8, 9, 10], [], [])
        
        pyxel.playm(0, loop=True)
        self._load_level(0)
        pyxel.run(self.update, self.draw)

    def _load_level(self, idx):
        self.grid, self.spawn, baby = parse_level(RAW_LEVELS[idx])
        self.baby_tx, self.baby_ty = baby[0], baby[1]
        self.player = Player(*self.spawn)
        self.echoes, self.enemies = [], []
        self.vis, self.dark, self.echo_cd = VisBuffer(), DarkBuffer(), 0
        if idx+1 in LEVEL_ENEMIES:
            for path in LEVEL_ENEMIES[idx+1]:
                self.enemies.append(Enemy(path))

    def update(self):
        self.flash = (self.flash + 1) % 60
        if self.state == self.ST_TITLE:
            if pyxel.btnp(pyxel.KEY_SPACE) or pyxel.btnp(pyxel.KEY_RETURN): self.state = self.ST_PLAY
            return
        if self.state == self.ST_RESPAWN:
            self.respawn_timer += 1
            if self.respawn_timer > 40:
                self.player.reset_to(*self.spawn)
                self.echoes, self.echo_cd, self.respawn_timer, self.state = [], 0, 0, self.ST_PLAY
                self.vis.reset(); self.dark.reset()
            return
        if self.state == self.ST_WIN:
            self.win_timer += 1; self.pulse_r += 4.0
            if self.win_timer > 100:
                if self.level_idx < len(RAW_LEVELS) - 1: self.state, self.win_timer = self.ST_NEXT, 0
                else: self.state = self.ST_FINISH
            return
        if self.state == self.ST_NEXT:
            self.win_timer += 1
            if self.win_timer > 30:
                self.level_idx += 1; self._load_level(self.level_idx)
                self.state, self.win_timer, self.pulse_r = self.ST_PLAY, 0, 0.0
            return
        if self.state == self.ST_FINISH:
            if pyxel.btnp(pyxel.KEY_SPACE) or pyxel.btnp(pyxel.KEY_RETURN):
                self.level_idx = 0; self._load_level(0); self.state = self.ST_TITLE
            return
        
        # Debug skip level
        if pyxel.btnp(pyxel.KEY_N):
            self.state, self.win_timer, self.pulse_r = self.ST_WIN, 99, 0.0
       
        p_echoes = [e for e in self.echoes if e.owner == "player" and not e.dead]
        e_echoes = [e for e in self.echoes if e.owner == "enemy" and not e.dead]
       
        # Check echo collision (Silent the player if enemy echo touches theirs)
        for pe in p_echoes:
            for ne in e_echoes:
                dist = math.hypot(pe.x - ne.x, pe.y - ne.y)
                # If waves cross each other
                if abs(pe.r + ne.r - dist) < 12:
                    pe.dead = True
                    self.echo_cd = 10 # Allow a faster recovery pulse if silenced

        # Input handling
        self.echo_cd = max(0, self.echo_cd - 1)
        if pyxel.btnp(pyxel.KEY_SPACE) and len(p_echoes) < MAX_ECHOES and self.echo_cd == 0:
            self.echoes.append(Echo(self.player.x, self.player.y, "player"))
            self.echo_cd = PLAYER_ECHO_CD
            pyxel.play(0, 0)
       
        # Update echoes and buffers
        for e in self.echoes:
            e.update()
            if not e.dead:
                # Optimized: Only check tiles near the current radius
                for tr in range(ROWS):
                    for tc in range(COLS):
                        if e.hits_tile(tc, tr):
                            if e.owner == "player": self.vis.illuminate(tc, tr)
                            else: self.dark.darken(tc, tr)
       
        # Enemy collision and update
        for en in self.enemies:
            if math.hypot(self.player.x - en.x, self.player.y - en.y) < 10:
                pyxel.play(1, 1)
                self.state, self.respawn_timer = self.ST_RESPAWN, 0
                return
            en.update(self.echoes)
           
        self.echoes = [e for e in self.echoes if not e.dead]
        self.vis.tick(); self.dark.tick()
        self.player.update(self.grid, any(e.owner == "player" for e in self.echoes))
       
        # Win condition
        ptx, pty = self.player.tile_pos()
        if ptx == self.baby_tx and pty == self.baby_ty:
            pyxel.play(2, 2)
            self.state, self.win_timer, self.pulse_r = self.ST_WIN, 0, 0.0
       
    def draw(self):
        pyxel.cls(0)
        if self.state == self.ST_TITLE: self._draw_title(); return
        if self.state == self.ST_FINISH: self._draw_finish(); return
       
        any_p_echo = any(e.owner == "player" for e in self.echoes)
       
        # Draw tiles based on visibility
        for tr in range(ROWS):
            for tc in range(COLS):
                if self.vis.is_lit(tc, tr) and not self.dark.is_dark(tc, tr):
                    tile, bx, by = self.grid[tr][tc], tc * TILE, tr * TILE
                    if tile == T_WALL:
                        pyxel.rect(bx, by, TILE, TILE, 1)
                        pyxel.rect(bx+1, by+1, TILE-2, TILE-2, 5)
                    elif tile in (T_FLOOR, T_SPAWN):
                        pyxel.rect(bx, by, TILE, TILE, 1)
                    elif tile == T_DOOR_A:
                        pyxel.rect(bx, by, TILE, TILE, 10 if any_p_echo else 2)
                    elif tile == T_DOOR_B:
                        pyxel.rect(bx, by, TILE, TILE, 10 if not any_p_echo else 2)
                    elif tile == T_BABY:
                        pyxel.rect(bx, by, TILE, TILE, 1)
                        self._draw_baby(bx+8, by+8)
       
        # Draw Echo rings
        for e in self.echoes:
            if not e.dead and e.r > 2:
                col = 12 if e.owner == "player" else 8
                pyxel.circb(int(self.player.x) if e.owner == "player" else int(e.x),
                             int(self.player.y) if e.owner == "player" else int(e.y),
                             int(e.r), col)
       
        self.player.draw()
        for en in self.enemies: en.draw()
       
        if self.state == self.ST_WIN: self._draw_win()
        if self.state == self.ST_RESPAWN: self._draw_respawn()
        if self.state == self.ST_NEXT:
            pyxel.rect(0, 0, W, H, 0)
            pyxel.text(W//2-20, H//2, "DESCENDING...", 7)

        self._draw_hud()

    def _draw_baby(self, x, y):
        pyxel.circ(x, y, 4, 10)
        pyxel.tri(x-4, y, x-9, y-3, x-9, y+3, 9)
        pyxel.tri(x+4, y, x+9, y-3, x+9, y+3, 9)

    def _draw_win(self):
        pyxel.circb(int(self.player.x), int(self.player.y), int(self.pulse_r) % 100, 10)
        if self.win_timer > 30:
            pyxel.rect(W//2-100, H//2-25, 200, 50, 0)
            pyxel.text(W//2-45, H//2-5, "FOUND YOUR BABY!", 10)

    def _draw_respawn(self):
        if self.respawn_timer % 6 < 3: pyxel.cls(2)
        pyxel.rect(W//2-80, H//2-20, 160, 40, 0)
        pyxel.text(W//2-30, H//2-5, "ENEMY BAT!", 8)

    def _draw_hud(self):
        pyxel.text(5, 5, "ECHO READY" if self.echo_cd == 0 else "...", 5 if self.echo_cd == 0 else 1)
        pyxel.text(W-45, 5, f"LEVEL {self.level_idx+1}/5", 7)

    def _draw_title(self):
        t = pyxel.frame_count
        for i in range(3):
            r = (t * 2 + i * 60) % 250
            pyxel.circb(W // 2, H // 2, r, 5 if r < 120 else 1)
       
        title_text = "E C H O - L O C A T I O N"
        tx, ty = W // 2 - 60, H // 2 - 60
        pyxel.text(tx+1, ty, title_text, 1)
        pyxel.text(tx-1, ty, title_text, 1)
        pyxel.text(tx, ty+1, title_text, 1)
        pyxel.text(tx, ty-1, title_text, 1)
        pyxel.text(tx, ty, title_text, 13)

        pyxel.text(W // 2 - 35, H // 2 - 45, "THE BLIND BAT", 5)
        self._draw_bat_icon(W // 2 - 90, H // 2 - 55)
        self._draw_bat_icon(W // 2 + 80, H // 2 - 55)

        pyxel.rect(W // 2 - 100, H // 2 - 5, 200, 45, 0)
        pyxel.rectb(W // 2 - 100, H // 2 - 5, 200, 45, 1)
        pyxel.text(W // 2 - 70, H // 2 + 5, "MOVE:  WASD / ARROWS", 7)
        pyxel.text(W // 2 - 70, H // 2 + 20, "ECHO:  SPACEBAR", 12)
        pyxel.text(W // 2 - 70, H // 2 + 30, "GOAL:  FIND THE BABY", 10)
       
        if self.flash < 40:
            pyxel.text(W // 2 - 40, H // 2 + 70, ">> PRESS START <<", 7)

    def _draw_bat_icon(self, x, y):
        pyxel.tri(x, y, x - 6, y - 4, x - 2, y + 2, 13)
        pyxel.tri(x, y, x + 6, y - 4, x + 2, y + 2, 13)
        pyxel.circ(x, y, 1, 7)

    def _draw_finish(self):
        pyxel.cls(0)
        bx, by = W // 2, H // 2 - 40
        pyxel.circ(bx, by, 6, 10)
        pyxel.circ(bx - 10, by - 5, 4, 10)
        self._draw_bat_icon(bx + 15, by - 15)
        self._draw_bat_icon(bx - 25, by - 20)
        t = pyxel.frame_count
        if t % 5 == 0:
            for i in range(15):
                angle = random.uniform(0, math.pi * 2)
                d = random.uniform(20, 100)
                px, py = bx + math.cos(angle) * d, by + math.sin(angle) * d
                pyxel.pset(px, py, random.choice([10, 12, 13]))
       
        finish_msg = "FAMILY REUNITED!"
        fx, fy = W // 2 - 45, H // 2 + 20
        pyxel.text(fx+1, fy, finish_msg, 1)
        pyxel.text(fx, fy, finish_msg, 10)
       
        if self.flash < 38:
            pyxel.text(W // 2 - 35, H // 2 + 50, "SPACE TO REPLAY", 6)

Game()