extends RefCounted ## Logical map: artwork is never used as collision geometry. const ROWS := [ "############################", "#............##............#", "#.####.#####.##.#####.####.#", "#o####.#####.##.#####.####o#", "#.####.#####.##.#####.####.#", "#..........................#", "#.####.##.########.##.####.#", "#.####.##.########.##.####.#", "#......##....##....##......#", "######.##### ## #####.######", " #.##### ## #####.# ", " #.## ##.# ", " #.## ###--### ##.# ", "######.## # # ##.######", " . # # . ", "######.## # # ##.######", " #.## ######## ##.# ", " #.## ##.# ", " #.## ######## ##.# ", "######.## ######## ##.######", "#............##............#", "#.####.#####.##.#####.####.#", "#.####.#####.##.#####.####.#", "#o..##....... .......##..o#", "###.##.##.########.##.##.###", "###.##.##.########.##.##.###", "#......##....##....##......#", "#.##########.##.##########.#", "#.##########.##.##########.#", "#..........................#", "############################", ] const DIRS := [Vector2i.UP, Vector2i.LEFT, Vector2i.DOWN, Vector2i.RIGHT] const PLAYER_START := Vector2i(13, 23) const DOOR := Vector2i(13, 11) static func neighbor(tile: Vector2i, direction: Vector2i) -> Vector2i: var result := tile + direction if result.y == 14: result.x = posmod(result.x, 28) return result static func walkable(tile: Vector2i, eyes := false) -> bool: if tile.x < 0 or tile.x >= 28 or tile.y < 0 or tile.y >= 31: return false # Blank regions outside the maze are not corridors. if tile.y != 14 and tile.y >= 9 and tile.y <= 19 and (tile.x < 5 or tile.x > 22): return false var cell: String = ROWS[tile.y][tile.x] return cell != "#" and (cell != "-" or eyes) static func pellets() -> Dictionary: var result := {} for y in range(31): for x in range(28): if ROWS[y][x] in [".", "o"]: result[Vector2i(x, y)] = ROWS[y][x] == "o" return result static func actor(tile: Vector2i, direction: Vector2i) -> Dictionary: return { "tile": tile, "next": tile, "progress": 0.0, "dir": direction, "spawn_offset": Vector2.ZERO, } static func position(actor_data: Dictionary) -> Vector2: var offset := Vector2(actor_data.next - actor_data.tile) if abs(offset.x) > 1.0: offset.x = float(actor_data.dir.x) # Actor centers use the logical maze lane. Rendering and collision share # this exact position so a sprite cannot be shifted into a neighboring wall. return Vector2(actor_data.tile) + actor_data.get("spawn_offset", Vector2.ZERO) + offset * actor_data.progress