import tkinter as tk
from tkinter import ttk, messagebox, filedialog, simpledialog
import json
import math
#import os

# --- Constants ---
GRID_WIDTH = 40
GRID_HEIGHT = 25
PIXEL_ASPECT_RATIO = 1.2 # Taller than wide, like Atari 800
MAX_ROOMS = 100
COORDS_BAR_SIZE = 25 # Size of the coordinate ruler
SPRITE_DIMENSION = 8
STATUS_BAR_HEIGHT = 25

# --- Pyramid Selector Constants ---
PYRAMID_SQUARE_SIZE = 20
PYRAMID_SQUARE_PADDING = 2
PYRAMID_COLOR_CURRENT = "#FFD700"  # Gold
PYRAMID_COLOR_EMPTY = "#4a4a4a"
PYRAMID_COLOR_NON_EMPTY = "#5c78a0"
PYRAMID_FONT = ("Arial", 8)

def create_hardcoded_default_screen():
    """Returns a list of objects defining the default screen layout."""
    return [
        {"type": "point", "subtype": "frame_bottom", "x": 1, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 2, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 3, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 4, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 5, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 6, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 7, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 8, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 9, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 10, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 26, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 27, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 28, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 29, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 30, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 31, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 32, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 33, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 34, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 35, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 36, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 37, "y": 3},
        {"type": "point", "subtype": "frame_bottom", "x": 38, "y": 3},
        {"type": "point", "subtype": "frame_v", "x": 0, "y": 3},
        {"type": "point", "subtype": "frame_v", "x": 0, "y": 2},
        {"type": "point", "subtype": "frame_v", "x": 0, "y": 1},
        {"type": "point", "subtype": "frame_v", "x": 0, "y": 0},
        {"type": "point", "subtype": "frame_v", "x": 11, "y": 3},
        {"type": "point", "subtype": "frame_v", "x": 11, "y": 2},
        {"type": "point", "subtype": "frame_v", "x": 11, "y": 1},
        {"type": "point", "subtype": "frame_v", "x": 11, "y": 0},
        {"type": "point", "subtype": "frame_v", "x": 25, "y": 3},
        {"type": "point", "subtype": "frame_v", "x": 25, "y": 2},
        {"type": "point", "subtype": "frame_v", "x": 25, "y": 1},
        {"type": "point", "subtype": "frame_v", "x": 25, "y": 0},
        {"type": "point", "subtype": "frame_v", "x": 39, "y": 3},
        {"type": "point", "subtype": "frame_v", "x": 39, "y": 2},
        {"type": "point", "subtype": "frame_v", "x": 39, "y": 1},
        {"type": "point", "subtype": "frame_v", "x": 39, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 1, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 2, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 3, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 4, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 5, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 6, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 7, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 8, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 9, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 10, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 26, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 27, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 28, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 29, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 30, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 31, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 32, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 33, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 34, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 35, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 36, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 37, "y": 0},
        {"type": "point", "subtype": "frame_h", "x": 38, "y": 0},
        {"type": "rect", "subtype": "wall", "x": 12, "y": 0, "w": 13, "h": 4},
        {"type": "rect", "subtype": "wall", "x": 0, "y": 4, "w": 1, "h": 1},
        {"type": "rect", "subtype": "wall", "x": 2, "y": 4, "w": 1, "h": 1},
        {"type": "rect", "subtype": "wall", "x": 4, "y": 4, "w": 1, "h": 1},
        {"type": "rect", "subtype": "wall", "x": 6, "y": 4, "w": 1, "h": 1},
        {"type": "rect", "subtype": "wall", "x": 8, "y": 4, "w": 1, "h": 1},
        {"type": "rect", "subtype": "wall", "x": 10, "y": 4, "w": 1, "h": 1},
        {"type": "rect", "subtype": "wall", "x": 12, "y": 4, "w": 1, "h": 1},
        {"type": "rect", "subtype": "wall", "x": 14, "y": 4, "w": 1, "h": 1},
        {"type": "rect", "subtype": "wall", "x": 16, "y": 4, "w": 1, "h": 1},
        {"type": "rect", "subtype": "wall", "x": 18, "y": 4, "w": 1, "h": 1},
        {"type": "rect", "subtype": "wall", "x": 20, "y": 4, "w": 1, "h": 1},
        {"type": "rect", "subtype": "wall", "x": 22, "y": 4, "w": 1, "h": 1},
        {"type": "rect", "subtype": "wall", "x": 24, "y": 4, "w": 1, "h": 1},
        {"type": "rect", "subtype": "wall", "x": 26, "y": 4, "w": 1, "h": 1},
        {"type": "rect", "subtype": "wall", "x": 28, "y": 4, "w": 1, "h": 1},
        {"type": "rect", "subtype": "wall", "x": 30, "y": 4, "w": 1, "h": 1},
        {"type": "rect", "subtype": "wall", "x": 32, "y": 4, "w": 1, "h": 1},
        {"type": "rect", "subtype": "wall", "x": 34, "y": 4, "w": 1, "h": 1},
        {"type": "rect", "subtype": "wall", "x": 36, "y": 4, "w": 1, "h": 1},
        {"type": "rect", "subtype": "wall", "x": 38, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 1, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 3, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 5, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 7, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 9, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 11, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 13, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 15, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 17, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 19, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 21, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 23, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 25, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 27, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 29, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 31, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 33, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 35, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 37, "y": 4, "w": 1, "h": 1},
        {"type": "line", "subtype": "bricks", "x": 39, "y": 4, "w": 1, "h": 1}
    ]

def create_hardcoded_tile_definitions():
    """Creates a dictionary of all tile types and their hardcoded sprites."""
    return {
        "empty": {"name": "Empty Space", "sprite": [["#000000"] * 8] * 8},
        "wall": {"name": "Wall", "sprite": [["#ad5216", "#ad5216", "#7f8e00", "#7f8e00", "#ad5216", "#ad5216", "#ad5216", "#ad5216"], ["#ad5216", "#ad5216", "#7f8e00", "#7f8e00", "#ad5216", "#ad5216", "#ad5216", "#ad5216"], ["#ad5216", "#ad5216", "#7f8e00", "#7f8e00", "#ad5216", "#ad5216", "#ad5216", "#ad5216"], ["#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00"], ["#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#7f8e00", "#7f8e00"], ["#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#7f8e00", "#7f8e00"], ["#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#7f8e00", "#7f8e00"], ["#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00"]]},
        "bricks": {"name": "Bricks", "sprite": [["#ad5216", "#ad5216", "#7f8e00", "#7f8e00", "#ad5216", "#ad5216", "#ad5216", "#ad5216"], ["#ad5216", "#ad5216", "#7f8e00", "#7f8e00", "#ad5216", "#ad5216", "#ad5216", "#ad5216"], ["#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00"], ["#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#7f8e00", "#7f8e00"], ["#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#7f8e00", "#7f8e00"], ["#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00"], ["#000000"] * 8, ["#000000"] * 8]},
        "door_red": {"name": "Red Door", "sprite": [["#ad5216"] * 8] * 8},
        "door_blue": {"name": "Blue Door", "sprite": [["#006ec5", "#006ec5", "#006ec5", "#006ec5", "#006ec5", "#006ec5", "#ad5216", "#ad5216"]] * 8},
        "door_white": {"name": "White Door", "sprite": [["#aaa4ad", "#aaa4ad", "#aaa4ad", "#aaa4ad", "#aaa4ad", "#aaa4ad", "#ad5216", "#ad5216"]] * 8},
        "item_amulet": {"name": "Amulet", "sprite": [["#000000"] * 16, ["#000000"] * 6 + ["#7f8e00"] * 4 + ["#000000"] * 6, ["#000000"] * 4 + ["#7f8e00"] * 8 + ["#000000"] * 4, ["#000000"] * 4 + ["#ad5216"] * 8 + ["#000000"] * 4, ["#000000"] * 4 + ["#ad5216"] * 8 + ["#000000"] * 4, ["#000000"] * 4 + ["#7f8e00"] * 8 + ["#000000"] * 4, ["#000000"] * 6 + ["#ad5216"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#ad5216"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#ad5216"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#ad5216"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#ad5216"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#ad5216"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#ad5216"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#006ec5"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#ad5216"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#ad5216"] * 4 + ["#000000"] * 6]},
        "item_shield": {"name": "Shield", "sprite": [["#000000"] * 16, ["#000000", "#000000"] + ["#ad5216"] * 11 + ["#000000", "#000000", "#000000"], ["#ad5216", "#ad5216", "#000000", "#000000"] + ["#ad5216"] * 7 + ["#000000", "#000000", "#ad5216", "#ad5216", "#000000"], ["#ad5216"] * 4 + ["#000000"] * 7 + ["#ad5216"] * 4 + ["#000000"], ["#ad5216", "#ad5216", "#000000", "#000000"] + ["#ad5216"] * 7 + ["#000000", "#000000", "#ad5216", "#ad5216", "#000000"], ["#ad5216", "#ad5216", "#000000", "#000000"] + ["#ad5216"] * 7 + ["#000000", "#000000", "#ad5216", "#ad5216", "#000000"], ["#ad5216", "#ad5216", "#000000", "#000000"] + ["#ad5216"] * 7 + ["#000000", "#000000", "#ad5216", "#ad5216", "#000000"], ["#ad5216", "#ad5216", "#000000", "#000000"] + ["#ad5216"] * 7 + ["#000000", "#000000", "#ad5216", "#ad5216", "#000000"], ["#ad5216", "#ad5216", "#000000", "#000000"] + ["#ad5216"] * 7 + ["#000000", "#000000", "#ad5216", "#ad5216", "#000000"], ["#ad5216", "#ad5216", "#000000", "#000000"] + ["#ad5216"] * 7 + ["#000000", "#000000", "#ad5216", "#ad5216", "#000000"], ["#ad5216", "#ad5216", "#000000", "#000000"] + ["#ad5216"] * 7 + ["#000000", "#000000", "#ad5216", "#ad5216", "#000000"], ["#ad5216"] * 4 + ["#000000"] * 7 + ["#ad5216"] * 4 + ["#000000"], ["#ad5216", "#ad5216", "#000000", "#000000"] + ["#ad5216"] * 7 + ["#000000", "#000000", "#ad5216", "#ad5216", "#000000"], ["#000000", "#000000"] + ["#ad5216"] * 11 + ["#000000", "#000000", "#000000"], ["#000000"] * 16, ["#000000"] * 16]},
        "item_sword": {"name": "Sword", "sprite": [["#000000"] * 6 + ["#aaa4ad"] * 2 + ["#000000"] * 8, ["#000000"] * 6 + ["#aaa4ad"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#aaa4ad"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#aaa4ad"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#aaa4ad"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#aaa4ad"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#aaa4ad"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#aaa4ad"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#aaa4ad"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#aaa4ad"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#aaa4ad"] * 4 + ["#000000"] * 6, ["#000000", "#000000"] + ["#ad5216"] * 12 + ["#000000", "#000000"], ["#000000", "#000000"] + ["#ad5216"] * 12 + ["#000000", "#000000"], ["#000000"] * 6 + ["#ad5216"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#ad5216"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#ad5216"] * 4 + ["#000000"] * 6]},
        "item_torch": {"name": "Torch", "sprite": [["#000000"] * 16, ["#000000"] * 8 + ["#ad5216"] * 2 + ["#000000"] * 6, ["#000000"] * 6 + ["#ad5216"] * 4 + ["#000000"] * 6, ["#000000"] * 6 + ["#ad5216"] * 4 + ["#000000"] * 6, ["#000000"] * 4 + ["#ad5216"] * 4 + ["#006ec5"] * 2 + ["#ad5216"] * 2 + ["#000000"] * 4, ["#000000"] * 4 + ["#ad5216"] * 8 + ["#000000"] * 4, ["#000000"] * 4 + ["#ad5216"] * 8 + ["#000000"] * 4, ["#000000"] * 6 + ["#ad5216"] * 6 + ["#000000"] * 4, ["#000000"] * 4 + ["#ad5216"] * 8 + ["#000000"] * 4, ["#000000"] * 4 + ["#ad5216"] * 8 + ["#000000"] * 4, ["#000000", "#000000"] + ["#006ec5"] * 4 + ["#ad5216"] * 4 + ["#006ec5"] * 4 + ["#000000", "#000000"], ["#000000"] * 5 + ["#006ec5"] * 6 + ["#000000"] * 5, ["#000000"] * 16, ["#000000"] * 6 + ["#006ec5"] * 2 + ["#ad5216"] * 2 + ["#000000"] * 6, ["#000000"] * 16, ["#000000"] * 16]},
        "item_key_red": {"name": "Red Key", "sprite": [["#000000"] * 16, ["#000000"] * 6 + ["#ad5216"] * 6 + ["#000000"] * 4, ["#000000"] * 4 + ["#ad5216"] * 10 + ["#000000"] * 2, ["#000000", "#000000", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#ad5216", "#ad5216", "#ad5216", "#ad5216"], ["#000000", "#000000", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#ad5216", "#ad5216", "#ad5216", "#ad5216"], ["#000000"] * 4 + ["#ad5216"] * 10 + ["#000000"] * 2, ["#000000"] * 6 + ["#ad5216"] * 6 + ["#000000"] * 4, ["#000000"] * 6 + ["#ad5216"] * 6 + ["#000000"] * 4, ["#000000"] * 8 + ["#ad5216"] * 2 + ["#000000"] * 6, ["#000000"] * 8 + ["#ad5216"] * 2 + ["#000000"] * 6, ["#000000"] * 8 + ["#ad5216"] * 2 + ["#000000"] * 6, ["#000000"] * 6 + ["#ad5216"] * 4 + ["#000000"] * 6, ["#000000"] * 8 + ["#ad5216"] * 2 + ["#000000"] * 6, ["#000000"] * 6 + ["#ad5216"] * 4 + ["#000000"] * 6, ["#000000"] * 8 + ["#ad5216"] * 2 + ["#000000"] * 6, ["#000000"] * 16]},
        "item_key_blue": {"name": "Blue Key", "sprite": [["#000000"] * 16, ["#000000"] * 6 + ["#006ec5"] * 6 + ["#000000"] * 4, ["#000000"] * 4 + ["#006ec5"] * 10 + ["#000000"] * 2, ["#000000", "#000000", "#006ec5", "#006ec5", "#006ec5", "#006ec5", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#006ec5", "#006ec5", "#006ec5", "#006ec5"], ["#000000", "#000000", "#006ec5", "#006ec5", "#006ec5", "#006ec5", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#006ec5", "#006ec5", "#006ec5", "#006ec5"], ["#000000"] * 4 + ["#006ec5"] * 10 + ["#000000"] * 2, ["#000000"] * 6 + ["#006ec5"] * 6 + ["#000000"] * 4, ["#000000"] * 6 + ["#006ec5"] * 6 + ["#000000"] * 4, ["#000000"] * 8 + ["#006ec5"] * 2 + ["#000000"] * 6, ["#000000"] * 8 + ["#006ec5"] * 2 + ["#000000"] * 6, ["#000000"] * 8 + ["#006ec5"] * 2 + ["#000000"] * 6, ["#000000"] * 6 + ["#006ec5"] * 4 + ["#000000"] * 6, ["#000000"] * 8 + ["#006ec5"] * 2 + ["#000000"] * 6, ["#000000"] * 6 + ["#006ec5"] * 4 + ["#000000"] * 6, ["#000000"] * 8 + ["#006ec5"] * 2 + ["#000000"] * 6, ["#000000"] * 16]},
        "item_key_white": {"name": "White Key", "sprite": [["#000000"] * 16, ["#000000"] * 6 + ["#aaa4ad"] * 6 + ["#000000"] * 4, ["#000000"] * 4 + ["#aaa4ad"] * 10 + ["#000000"] * 2, ["#000000", "#000000", "#aaa4ad", "#aaa4ad", "#aaa4ad", "#aaa4ad", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#aaa4ad", "#aaa4ad", "#aaa4ad", "#aaa4ad"], ["#000000", "#000000", "#aaa4ad", "#aaa4ad", "#aaa4ad", "#aaa4ad", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#aaa4ad", "#aaa4ad", "#aaa4ad", "#aaa4ad"], ["#000000"] * 4 + ["#aaa4ad"] * 10 + ["#000000"] * 2, ["#000000"] * 6 + ["#aaa4ad"] * 6 + ["#000000"] * 4, ["#000000"] * 6 + ["#aaa4ad"] * 6 + ["#000000"] * 4, ["#000000"] * 8 + ["#aaa4ad"] * 2 + ["#000000"] * 6, ["#000000"] * 8 + ["#aaa4ad"] * 2 + ["#000000"] * 6, ["#000000"] * 8 + ["#aaa4ad"] * 2 + ["#000000"] * 6, ["#000000"] * 6 + ["#aaa4ad"] * 4 + ["#000000"] * 6, ["#000000"] * 8 + ["#aaa4ad"] * 2 + ["#000000"] * 6, ["#000000"] * 6 + ["#aaa4ad"] * 4 + ["#000000"] * 6, ["#000000"] * 8 + ["#aaa4ad"] * 2 + ["#000000"] * 6, ["#000000"] * 16]},
        "enemy_skull": {"name": "Skull", "sprite": [["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 4 + ["#e0e7ff"] * 4 + ["#000000"] * 8, ["#000000", "#000000", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000"], ["#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000", "#000000", "#000000", "#000000"], ["#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000", "#000000", "#e0e7ff", "#e0e7ff", "#000000", "#000000", "#000000", "#000000"], ["#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000", "#000000", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000", "#000000"], ["#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000", "#000000", "#e0e7ff", "#e0e7ff"], ["#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000", "#000000", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000", "#000000", "#e0e7ff", "#e0e7ff"], ["#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000", "#000000", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000", "#000000", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff"], ["#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000", "#000000", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff"], ["#000000", "#000000", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000", "#000000", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000", "#000000"], ["#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000", "#000000"]]},
        "enemy_skull_f": {"name": "Fast Skull", "sprite": [["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 4 + ["#8effff"] * 4 + ["#000000"] * 8, ["#000000", "#000000", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000"], ["#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000", "#000000", "#000000"], ["#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000", "#8effff", "#8effff", "#000000", "#000000", "#000000", "#000000"], ["#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000", "#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000"], ["#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000", "#8effff", "#8effff"], ["#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000", "#8effff", "#8effff"], ["#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000", "#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000", "#8effff", "#8effff", "#8effff", "#8effff"], ["#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000", "#8effff", "#8effff", "#8effff", "#8effff"], ["#000000", "#000000", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000", "#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000"], ["#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000"]]},
        "enemy_b_skull": {"name": "Bouncing Skull", "sprite": [["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 5 + ["#e0e7ff"] * 6 + ["#000000"] * 5, ["#000000"] * 3 + ["#e0e7ff"] * 10 + ["#000000"] * 3, ["#000000", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000"], ["#000000", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000"], ["#000000", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000", "#000000", "#e0e7ff", "#e0e7ff", "#000000", "#000000", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000"], ["#000000", "#e0e7ff", "#e0e7ff", "#000000", "#000000", "#000000", "#000000", "#e0e7ff", "#e0e7ff", "#000000", "#000000", "#000000", "#000000", "#e0e7ff", "#e0e7ff", "#000000"], ["#000000", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000"], ["#000000", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#e0e7ff", "#000000"], ["#000000"] * 3 + ["#e0e7ff"] * 10 + ["#000000"] * 3, ["#000000"] * 3 + ["#e0e7ff"] * 10 + ["#000000"] * 3, ["#000000"] * 3 + ["#e0e7ff", "#e0e7ff", "#000000", "#000000", "#e0e7ff", "#e0e7ff", "#000000", "#000000", "#e0e7ff", "#e0e7ff"] + ["#000000"] * 3, ["#000000"] * 5 + ["#e0e7ff", "#e0e7ff", "#000000", "#000000", "#e0e7ff", "#e0e7ff"] + ["#000000"] * 5, ["#000000"] * 3 + ["#e0e7ff"] * 10 + ["#000000"] * 3, ["#000000"] * 5 + ["#e0e7ff"] * 6 + ["#000000"] * 5]},
        "enemy_b_skull_f": {"name": "Fast Bouncing Skull", "sprite": [["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 5 + ["#ffea8f"] * 6 + ["#000000"] * 5, ["#000000"] * 3 + ["#ffea8f"] * 10 + ["#000000"] * 3, ["#000000", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#000000"], ["#000000", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#000000"], ["#000000", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#000000", "#000000", "#ffea8f", "#ffea8f", "#000000", "#000000", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#000000"], ["#000000", "#ffea8f", "#ffea8f", "#000000", "#000000", "#000000", "#000000", "#ffea8f", "#ffea8f", "#000000", "#000000", "#000000", "#000000", "#ffea8f", "#ffea8f", "#000000"], ["#000000", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#000000"], ["#000000", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#ffea8f", "#000000"], ["#000000"] * 3 + ["#ffea8f"] * 10 + ["#000000"] * 3, ["#000000"] * 3 + ["#ffea8f"] * 10 + ["#000000"] * 3, ["#000000"] * 3 + ["#ffea8f", "#ffea8f", "#000000", "#000000", "#ffea8f", "#ffea8f", "#000000", "#000000", "#ffea8f", "#ffea8f"] + ["#000000"] * 3, ["#000000"] * 5 + ["#ffea8f", "#ffea8f", "#000000", "#000000", "#ffea8f", "#ffea8f"] + ["#000000"] * 5, ["#000000"] * 3 + ["#ffea8f"] * 10 + ["#000000"] * 3, ["#000000"] * 5 + ["#ffea8f"] * 6 + ["#000000"] * 5]},
        "enemy_spider": {"name": "Spider", "sprite": [["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 16, ["#000000", "#000000", "#537900", "#537900", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#537900", "#537900", "#000000", "#000000"], ["#537900", "#537900", "#537900", "#537900", "#537900", "#537900", "#000000", "#000000", "#000000", "#000000", "#537900", "#537900", "#537900", "#537900", "#537900", "#537900"], ["#537900", "#537900", "#000000", "#000000", "#537900", "#537900", "#537900", "#537900", "#537900", "#537900", "#537900", "#537900", "#000000", "#000000", "#537900", "#537900"], ["#000000", "#000000", "#537900", "#537900", "#000000", "#000000", "#537900", "#537900", "#537900", "#537900", "#000000", "#000000", "#537900", "#537900", "#000000", "#000000"], ["#537900"] * 16, ["#537900", "#537900", "#000000", "#000000", "#537900", "#537900", "#537900", "#537900", "#537900", "#537900", "#537900", "#537900", "#000000", "#000000", "#537900", "#537900"], ["#000000", "#000000", "#537900", "#537900", "#537900", "#537900", "#537900", "#537900", "#537900", "#537900", "#537900", "#537900", "#537900", "#537900", "#000000", "#000000"], ["#537900"] * 16, ["#537900", "#537900", "#000000", "#000000", "#537900", "#537900", "#537900", "#537900", "#537900", "#537900", "#537900", "#537900", "#000000", "#000000", "#537900", "#537900"], ["#537900", "#537900", "#000000", "#000000", "#000000", "#000000", "#537900", "#537900", "#537900", "#537900", "#000000", "#000000", "#000000", "#000000", "#537900", "#537900"]]},
        "enemy_spider_f": {"name": "Fast Spider", "sprite": [["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 16, ["#000000", "#000000", "#8effff", "#8effff", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#8effff", "#8effff", "#000000", "#000000"], ["#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000", "#000000", "#000000", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff"], ["#8effff", "#8effff", "#000000", "#000000", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000", "#8effff", "#8effff"], ["#000000", "#000000", "#8effff", "#8effff", "#000000", "#000000", "#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000", "#8effff", "#8effff", "#000000", "#000000"], ["#8effff"] * 16, ["#8effff", "#8effff", "#000000", "#000000", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000", "#8effff", "#8effff"], ["#000000", "#000000", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000"], ["#8effff"] * 16, ["#8effff", "#8effff", "#000000", "#000000", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000", "#8effff", "#8effff"], ["#8effff", "#8effff", "#000000", "#000000", "#000000", "#000000", "#8effff", "#8effff", "#8effff", "#8effff", "#000000", "#000000", "#000000", "#000000", "#8effff", "#8effff"]]},
        "enemy_snake": {"name": "Snake", "sprite": [["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 16, ["#000000"] * 6 + ["#00799d"] * 4 + ["#000000"] * 6, ["#000000"] * 4 + ["#00799d"] * 2 + ["#000000"] * 2 + ["#00799d"] * 4 + ["#000000"] * 4, ["#000000"] * 4 + ["#00799d"] * 8 + ["#000000"] * 4, ["#000000"] * 4 + ["#00799d"] * 2 + ["#000000"] * 4 + ["#00799d"] * 2 + ["#000000"] * 4, ["#000000"] * 8 + ["#00799d"] * 4 + ["#000000"] * 4, ["#000000"] * 4 + ["#00799d"] * 6 + ["#000000"] * 6, ["#000000", "#000000", "#00799d", "#00799d", "#00799d", "#00799d", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000"], ["#000000", "#000000", "#00799d", "#00799d", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000"], ["#000000", "#000000", "#00799d", "#00799d", "#00799d", "#00799d", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000"], ["#000000"] * 4 + ["#00799d"] * 2 + ["#000000"] * 6 + ["#00799d"] * 2 + ["#000000"] * 2, ["#000000"] * 4 + ["#00799d"] * 2 + ["#000000"] * 6 + ["#00799d"] * 2 + ["#000000"] * 2, ["#000000"] * 4 + ["#00799d"] * 4 + ["#000000"] * 4 + ["#00799d"] * 4, ["#000000"] * 6 + ["#00799d"] * 8 + ["#000000"] * 2]},
        "rope": {"name": "Rope", "sprite": [["#aaa4ad"] * 8, ["#aaa4ad"] * 8, ["#000000", "#000000", "#aaa4ad", "#aaa4ad", "#aaa4ad", "#aaa4ad", "#000000", "#000000"], ["#000000", "#000000", "#000000", "#000000", "#aaa4ad", "#aaa4ad", "#000000", "#000000"], ["#000000", "#000000", "#000000", "#000000", "#aaa4ad", "#aaa4ad", "#000000", "#000000"], ["#000000", "#000000", "#aaa4ad", "#aaa4ad", "#000000", "#000000", "#000000", "#000000"], ["#000000", "#000000", "#aaa4ad", "#aaa4ad", "#000000", "#000000", "#000000", "#000000"], ["#000000", "#000000", "#aaa4ad", "#aaa4ad", "#000000", "#000000", "#000000", "#000000"], ["#000000", "#000000", "#aaa4ad", "#aaa4ad", "#000000", "#000000", "#000000", "#000000"], ["#000000", "#000000", "#aaa4ad", "#aaa4ad", "#000000", "#000000", "#000000", "#000000"], ["#000000", "#000000", "#000000", "#000000", "#aaa4ad", "#aaa4ad", "#000000", "#000000"], ["#000000", "#000000", "#000000", "#000000", "#aaa4ad", "#aaa4ad", "#000000", "#000000"], ["#000000", "#000000", "#000000", "#000000", "#aaa4ad", "#aaa4ad", "#000000", "#000000"], ["#000000", "#000000", "#000000", "#000000", "#aaa4ad", "#aaa4ad", "#000000", "#000000"], ["#000000", "#000000", "#aaa4ad", "#aaa4ad", "#000000", "#000000", "#000000", "#000000"], ["#000000", "#000000", "#aaa4ad", "#aaa4ad", "#000000", "#000000", "#000000", "#000000"]]},
        "tube": {"name": "Tube", "sprite": [["#000000", "#000000", "#aaa4ad", "#aaa4ad", "#aaa4ad", "#aaa4ad", "#ad5216", "#ad5216"]] * 8},
        "chain": {"name": "Chain", "sprite": [["#000000", "#000000", "#ad5216", "#ad5216", "#000000", "#000000", "#ad5216", "#ad5216"], ["#000000", "#000000", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216"], ["#000000", "#000000", "#000000", "#000000", "#ad5216", "#ad5216", "#000000", "#000000"], ["#000000", "#000000", "#000000", "#000000", "#ad5216", "#ad5216", "#000000", "#000000"], ["#000000", "#000000", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216"], ["#000000", "#000000", "#ad5216", "#ad5216", "#000000", "#000000", "#ad5216", "#ad5216"], ["#000000", "#000000", "#ad5216", "#ad5216", "#000000", "#000000", "#ad5216", "#ad5216"], ["#000000", "#000000", "#ad5216", "#ad5216", "#000000", "#000000", "#ad5216", "#ad5216"]]},
        "ladder": {"name": "Ladder", "sprite": [["#006ec5", "#006ec5", "#7f8e00", "#7f8e00", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#7f8e00", "#7f8e00", "#ad5216", "#ad5216", "#006ec5", "#006ec5"], ["#006ec5", "#006ec5", "#7f8e00", "#7f8e00", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#7f8e00", "#7f8e00", "#ad5216", "#ad5216", "#006ec5", "#006ec5"], ["#006ec5", "#006ec5", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#7f8e00", "#006ec5", "#006ec5"], ["#006ec5", "#006ec5", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#7f8e00", "#7f8e00", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#006ec5", "#006ec5"], ["#006ec5", "#006ec5", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#7f8e00", "#7f8e00", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#006ec5", "#006ec5"], ["#006ec5", "#006ec5", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#006ec5", "#006ec5"], ["#006ec5", "#006ec5", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#006ec5", "#006ec5"], ["#006ec5", "#006ec5", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#006ec5", "#006ec5"], ["#006ec5"] * 16, ["#006ec5", "#006ec5", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#006ec5", "#006ec5"], ["#006ec5", "#006ec5", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#006ec5", "#006ec5"], ["#006ec5", "#006ec5", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#006ec5", "#006ec5"], ["#006ec5", "#006ec5", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#006ec5", "#006ec5"], ["#006ec5", "#006ec5", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#006ec5", "#006ec5"], ["#006ec5", "#006ec5", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#006ec5", "#006ec5"], ["#006ec5", "#006ec5", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#006ec5", "#006ec5"]]},
        "platform": {"name": "Disappearing Platform", "sprite": [["#006ec5", "#006ec5", "#ad5216", "#ad5216", "#006ec5", "#006ec5", "#ad5216", "#ad5216"], ["#000000", "#000000", "#006ec5", "#006ec5", "#ad5216", "#ad5216", "#006ec5", "#006ec5"], ["#006ec5", "#006ec5", "#000000", "#000000", "#ad5216", "#ad5216", "#000000", "#000000"], ["#006ec5", "#006ec5", "#ad5216", "#ad5216", "#006ec5", "#006ec5", "#ad5216", "#ad5216"], ["#000000"] * 8, ["#000000"] * 8, ["#000000"] * 8, ["#000000"] * 8]},
        "treadmill_left": {"name": "Treadmill Left", "sprite": [["#000000"] * 8 + ["#006ec5"] * 2 + ["#000000"] * 6 + ["#006ec5"] * 2 + ["#000000"] * 6, ["#000000"] * 8 + ["#006ec5"] * 2 + ["#000000"] * 6 + ["#006ec5"] * 2 + ["#000000"] * 6, ["#000000"] * 4 + ["#ad5216"] * 16 + ["#000000"] * 4, ["#FFFF00", "#FFFF00"] + ["#ad5216"] * 20 + ["#006ec5", "#006ec5"], ["#FFFF00", "#FFFF00"] + ["#ad5216"] * 20 + ["#006ec5", "#006ec5"], ["#000000"] * 4 + ["#ad5216"] * 16 + ["#000000"] * 4, ["#000000"] * 6 + ["#006ec5"] * 2 + ["#000000"] * 6 + ["#006ec5"] * 2 + ["#000000"] * 8, ["#000000"] * 6 + ["#006ec5"] * 2 + ["#000000"] * 6 + ["#006ec5"] * 2 + ["#000000"] * 8]},
        "treadmill_right": {"name": "Treadmill Right", "sprite": [["#000000"] * 8 + ["#006ec5"] * 2 + ["#000000"] * 6 + ["#006ec5"] * 2 + ["#000000"] * 6, ["#000000"] * 8 + ["#006ec5"] * 2 + ["#000000"] * 6 + ["#006ec5"] * 2 + ["#000000"] * 6, ["#000000"] * 4 + ["#ad5216"] * 16 + ["#000000"] * 4, ["#006ec5", "#006ec5"] + ["#ad5216"] * 20 + ["#FFFF00", "#FFFF00"], ["#006ec5", "#006ec5"] + ["#ad5216"] * 20 + ["#FFFF00", "#FFFF00"], ["#000000"] * 4 + ["#ad5216"] * 16 + ["#000000"] * 4, ["#000000"] * 6 + ["#006ec5"] * 2 + ["#000000"] * 6 + ["#006ec5"] * 2 + ["#000000"] * 8, ["#000000"] * 6 + ["#006ec5"] * 2 + ["#000000"] * 6 + ["#006ec5"] * 2 + ["#000000"] * 8]},
        "fire": {"name": "Fire", "sprite": [["#000000"] * 32, ["#000000"] * 6 + ["#ad5216"] * 2 + ["#000000"] * 24, ["#000000"] * 4 + ["#ad5216"] * 2 + ["#000000"] * 26, ["#000000", "#000000", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#ad5216", "#ad5216", "#000000", "#000000", "#ad5216", "#ad5216", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000"], ["#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#ad5216", "#ad5216", "#000000", "#000000", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000"], ["#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#000000", "#000000", "#000000", "#000000", "#ad5216", "#ad5216", "#000000", "#000000", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000"], ["#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#000000", "#000000", "#0b6cba", "#0b6cba", "#ad5216", "#ad5216", "#000000", "#000000", "#000000", "#000000", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#ad5216", "#ad5216", "#000000", "#000000"], ["#000000", "#000000", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#000000", "#000000", "#0b6cba", "#0b6cba", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#000000", "#000000", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#000000", "#000000", "#000000", "#000000", "#ad5216", "#ad5216", "#ad5216", "#ad5216"], ["#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#0b6cba", "#0b6cba", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#0b6cba", "#0b6cba", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#0b6cba", "#0b6cba"], ["#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#0b6cba", "#0b6cba", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#0b6cba", "#0b6cba", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#0b6cba", "#0b6cba"], ["#ad5216"] * 32, ["#ad5216"] * 32, ["#ad5216"] * 32, ["#ad5216"] * 32, ["#ad5216"] * 32, ["#ad5216"] * 32]},
        "frame_h": {"name": "Horizontal Frame", "sprite": [["#006ec5"] * 8, ["#7f8e00"] * 8, ["#ad5216"] * 8, ["#006ec5"] * 8, ["#000000"] * 8, ["#000000"] * 8, ["#000000"] * 8, ["#000000"] * 8]},
        "frame_v": {"name": "Vertical Frame", "sprite": [["#006ec5", "#006ec5", "#ad5216", "#ad5216", "#ad5216", "#ad5216", "#006ec5", "#006ec5"]] * 8},
        "frame_bottom": {"name": "Bottom Frame", "sprite": [["#000000"] * 8, ["#006ec5"] * 8, ["#006ec5"] * 8, ["#7f8e00"] * 8, ["#ad5216"] * 8, ["#7f8e00"] * 8, ["#006ec5"] * 8, ["#006ec5"] * 8]},
    }

TILE_DATA = create_hardcoded_tile_definitions()

class TileMapEditor:
    def __init__(self, root):
        self.root = root
        self.root.title("Montezuma's Revenge Level Editor 1.0")
        try:
            self.root.state('zoomed')
        except tk.TclError:
            self.root.attributes('-zoomed', True)


        self.rooms = {i: [] for i in range(MAX_ROOMS + 1)}
        self.default_screen_objects = create_hardcoded_default_screen()
        self.current_room_id = 0
        self.tile_cache = {}
        
        self.tile_width = 20
        self.tile_height = int(self.tile_width * PIXEL_ASPECT_RATIO)
        self.resize_job = None

        self.active_tool = None
        self.tool_subtype = None
        self.triangle_points = []
        self.selected_object_index = None
        
        self.ENEMY_X_POS = [2, 4, 6, 8, 10, 12, 16, 17, 20, 22, 26, 28, 30, 32, 34, 36]

        self.grid_visible = tk.BooleanVar(value=False)
        self.coords_visible = tk.BooleanVar(value=True)
        self.level_view_var = tk.StringVar(value="Level 1")

        self.original_xex = bytearray()

        self._setup_ui()
        self.generate_all_tile_images()
        self.root.update_idletasks()
        self.load_room(0)
        self._update_ui_visibility()

    def _setup_ui(self):
        self.root.grid_rowconfigure(1, weight=1)
        self.root.grid_columnconfigure(0, weight=1)
        self._create_menubar()

        status_frame = ttk.Frame(self.root, height=STATUS_BAR_HEIGHT)
        status_frame.grid(row=2, column=0, columnspan=2, sticky="ew", padx=5, pady=(0,5))
        self.coords_label = ttk.Label(status_frame, text="Coords: (-, -)")
        self.coords_label.pack(side="left")

        main_frame = ttk.Frame(self.root)
        main_frame.grid(row=1, column=0, sticky="nsew", padx=10, pady=10)
        main_frame.grid_rowconfigure(0, weight=1)
        main_frame.grid_columnconfigure(0, weight=1)
        
        canvas_container = ttk.Frame(main_frame)
        canvas_container.grid(row=0, column=0, sticky="nsew")
        canvas_container.grid_rowconfigure(1, weight=1)
        canvas_container.grid_columnconfigure(1, weight=1)

        self.coords_top_canvas = tk.Canvas(canvas_container, height=COORDS_BAR_SIZE, bg="#333", highlightthickness=0)
        self.coords_left_canvas = tk.Canvas(canvas_container, width=COORDS_BAR_SIZE, bg="#333", highlightthickness=0)

        self.canvas = tk.Canvas(canvas_container, bg="#222222", highlightthickness=0)
        self.canvas.grid(row=1, column=1, sticky="nsew")
        self.canvas.bind("<Button-1>", self.on_canvas_press)
        self.canvas.bind("<B1-Motion>", self.on_canvas_drag)
        self.canvas.bind("<ButtonRelease-1>", self.on_canvas_release)
        self.canvas.bind("<Motion>", self._on_mouse_hover)
        self.canvas.bind("<Leave>", self._on_mouse_leave)
        self.canvas.bind("<Configure>", self._on_resize)

        controls_frame = ttk.Frame(main_frame, padding=10)
        controls_frame.grid(row=0, column=1, sticky="ns")
        controls_frame.grid_rowconfigure(3, weight=1) 
        controls_frame.grid_columnconfigure(0, weight=1)

        pyramid_total_width = (PYRAMID_SQUARE_SIZE + PYRAMID_SQUARE_PADDING) * 19
        pyramid_total_height = (PYRAMID_SQUARE_SIZE + PYRAMID_SQUARE_PADDING) * 11
        self.pyramid_canvas = tk.Canvas(controls_frame, width=pyramid_total_width, height=pyramid_total_height, bg="#333", highlightthickness=0)
        self.pyramid_canvas.grid(row=0, column=0, columnspan=2, pady=(0, 10))
        self.pyramid_canvas.bind("<Button-1>", self._on_pyramid_click)
        
        ttk.Label(controls_frame, text="Drawn Objects").grid(row=2, column=0, columnspan=2, sticky="w")
        
        self.object_listbox = tk.Listbox(controls_frame, height=15, width=35)
        self.object_listbox.grid(row=3, column=0, sticky="nsew")
        self.object_listbox.bind("<<ListboxSelect>>", self._on_object_select)
        self.object_listbox.bind("<Button-3>", self._deselect_object)
        self.root.bind("<Escape>", self._deselect_object)

        side_controls_frame = ttk.Frame(controls_frame)
        side_controls_frame.grid(row=3, column=1, sticky="nw", padx=(10, 0))

        btn_up = ttk.Button(side_controls_frame, text="Move Up", command=lambda: self.move_object(-1))
        btn_up.pack(fill="x", padx=2, pady=(0, 2))
        btn_down = ttk.Button(side_controls_frame, text="Move Down", command=lambda: self.move_object(1))
        btn_down.pack(fill="x", padx=2, pady=2)
        
        btn_del = ttk.Button(side_controls_frame, text="Delete", command=self.delete_object)
        btn_del.pack(fill="x", padx=2, pady=2)
        
        btn_clear = ttk.Button(side_controls_frame, text="Clear Room", command=self.clear_room)
        btn_clear.pack(fill="x", padx=2, pady=2)
    
        level_view_frame = ttk.Frame(side_controls_frame)
        level_view_frame.pack(pady=(8, 0))
        ttk.Label(level_view_frame, text="Level View:").pack()
        level_chooser = ttk.Combobox(level_view_frame, textvariable=self.level_view_var, 
                                     values=["Level 1", "Level 2", "Level 3", "Level 4"],
                                     state="readonly", width=12)
        level_chooser.pack()
        level_chooser.bind("<<ComboboxSelected>>", self._on_level_view_change)
    
    def _on_resize(self, event):
        if self.resize_job:
            self.root.after_cancel(self.resize_job)
        self.resize_job = self.root.after(200, self._perform_resize)

    def _perform_resize(self):
        canvas_w = self.canvas.winfo_width()
        canvas_h = self.canvas.winfo_height()
        
        w_ratio = canvas_w / GRID_WIDTH
        h_ratio = canvas_h / (GRID_HEIGHT * PIXEL_ASPECT_RATIO)
        
        new_tile_w = math.floor(min(w_ratio, h_ratio))

        if new_tile_w < 4: return

        if new_tile_w != self.tile_width:
            self.tile_width = new_tile_w
            self.tile_height = int(self.tile_width * PIXEL_ASPECT_RATIO)

            self.generate_all_tile_images()
            self.render_and_draw()
            self._draw_coordinates()
            
    def _update_ui_visibility(self):
        if self.coords_visible.get():
            self.coords_top_canvas.grid(row=0, column=1, sticky="ew")
            self.coords_left_canvas.grid(row=1, column=0, sticky="ns")
            self._draw_coordinates()
        else:
            self.coords_top_canvas.grid_remove()
            self.coords_left_canvas.grid_remove()
        self.render_and_draw()

    def _draw_coordinates(self):
        self.coords_top_canvas.delete("all")
        self.coords_left_canvas.delete("all")
        for i in range(GRID_WIDTH):
            x = i * self.tile_width + self.tile_width / 2
            self.coords_top_canvas.create_text(x, COORDS_BAR_SIZE/2, text=str(i+1), fill="white", font=("Arial", 8))
        for i in range(GRID_HEIGHT):
            y = i * self.tile_height + self.tile_height / 2
            self.coords_left_canvas.create_text(COORDS_BAR_SIZE/2, y, text=str(i+1), fill="white", font=("Arial", 8))
    
    def _create_menubar(self):
        menubar = tk.Menu(self.root)
        self.root.config(menu=menubar)
        
        self.file_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="File", menu=self.file_menu)
        self.file_menu.add_command(label="Load Pyramid", command=self.load_maps_from_file)
        self.file_menu.add_command(label="Save Pyramid", command=self.save_maps_to_file)
        self.file_menu.add_separator()
        self.file_menu.add_command(label = "Import Original XEX File", command=self._import_original_XEX_file)
        self.file_menu.add_command(label="Export XEX File", command=self._export_final_XEX_file, state=tk.DISABLED)

        view_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="View", menu=view_menu)
        view_menu.add_checkbutton(label="Show Grid", onvalue=True, offvalue=False, variable=self.grid_visible, command=self._update_ui_visibility)
        view_menu.add_checkbutton(label="Show Coordinates", onvalue=True, offvalue=False, variable=self.coords_visible, command=self._update_ui_visibility)

        tools_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="Tools", menu=tools_menu)
        tools_menu.add_command(label="Space", command=lambda: self.set_tool("rect", "empty"))
        tools_menu.add_command(label="Wall", command=lambda: self.set_tool("rect", "wall"))
        tools_menu.add_command(label="Space triangle", command=lambda: self.set_tool("triangle", "empty"))
        tools_menu.add_command(label="Wall triangle", command=lambda: self.set_tool("triangle", "wall"))
        tools_menu.add_command(label="Bricks", command=lambda: self.set_tool("line", "bricks"))

        item_menu = tk.Menu(tools_menu, tearoff=0)
        tools_menu.add_cascade(label="Items", menu=item_menu)
        for key in sorted(TILE_DATA.keys()):
            if key.startswith("item_"):
                item_name = TILE_DATA[key]['name']
                item_menu.add_command(label=item_name, command=lambda k=key: self.set_tool("item", k))

        enemy_menu = tk.Menu(tools_menu, tearoff=0)
        tools_menu.add_cascade(label="Enemies", menu=enemy_menu)
        enemy_order = [
            "enemy_skull", "enemy_b_skull", "enemy_spider", "enemy_snake",
            "enemy_skull_f", "enemy_b_skull_f", "enemy_spider_f"
        ]
        for key in enemy_order:
            if key in TILE_DATA:
                enemy_name = TILE_DATA[key]['name']
                enemy_menu.add_command(label=enemy_name, command=lambda k=key: self.set_tool("enemy", k))
        
        door_menu = tk.Menu(tools_menu, tearoff=0)
        tools_menu.add_cascade(label="Doors", menu=door_menu)
        door_menu.add_command(label="Red Door", command=lambda: self.set_tool("door", "door_red"))
        door_menu.add_command(label="Blue Door", command=lambda: self.set_tool("door", "door_blue"))
        door_menu.add_command(label="White Door", command=lambda: self.set_tool("door", "door_white"))
        
        tools_menu.add_separator()
        tools_menu.add_command(label="Rope", command=lambda: self.set_tool("vline", "rope"))
        tools_menu.add_command(label="Tube", command=lambda: self.set_tool("vline", "tube"))
        tools_menu.add_command(label="Chain", command=lambda: self.set_tool("chain", "chain"))
        tools_menu.add_command(label="Ladder", command=lambda: self.set_tool("ladder", "ladder"))
        tools_menu.add_command(label="Platform", command=lambda: self.set_tool("hline", "platform"))
        
        tread_menu = tk.Menu(tools_menu, tearoff=0)
        tools_menu.add_cascade(label="Treadmill", menu=tread_menu)
        tread_menu.add_command(label="Left", command=lambda: self.set_tool("hline", "treadmill_left"))
        tread_menu.add_command(label="Right", command=lambda: self.set_tool("hline", "treadmill_right"))

        tools_menu.add_command(label="Fire", command=lambda: self.set_tool("rect", "fire"))
        
        tools_menu.add_separator()
        tools_menu.add_command(label="Copy", command=lambda: self.add_special_command("copy"))
        tools_menu.add_command(label="Mirrored Copy", command=lambda: self.add_special_command("copy_m"))
        tools_menu.add_command(label="Level", command=lambda: self.add_special_command("level"))
        
        help_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="Help", menu=help_menu)
        help_menu.add_command(label="FAQ", command=self._show_faq)

    def _show_faq(self):
        faq_window = tk.Toplevel(self.root)
        faq_window.title("FAQ")
        faq_window.geometry("600x450")

        frame = ttk.Frame(faq_window)
        frame.pack(fill="both", expand=True, padx=10, pady=10)

        scrollbar = ttk.Scrollbar(frame)
        scrollbar.pack(side="right", fill="y")

        text_widget = tk.Text(frame, wrap="word", yscrollcommand=scrollbar.set, font=("Arial", 10), relief="flat")
        text_widget.pack(side="left", fill="both", expand=True)
        
        scrollbar.config(command=text_widget.yview)

        faq_text = (
            "WELCOME\n\n"

            "This is a level editor for the Atari 800 game Montezuma's Revenge. "
            "Here you can create all the rooms of the game from scratch, using the "
            "same drawing tools that were used in the original game. "
            "This programme does not change any of the code though, and focuses only on "
            "overwriting the rooms' data.\n\n"

            "The tools are generally very straightforward; they let you draw rectangles "
            "and triangles of wall, space, and fire, and let you insert many items, platforms, "
            "enemies, &c. directly into the screen.\n\n"

            "---------------------------\n\n"

            "HOW TO USE\n\n"

            "All you need to do to get started, is to choose the room you want to edit in "
            "the diagram at the top right of the screen. Then choose one of the options of "
            "the Tools menu and click somewhere on the room. As your pyramid is being built "
            "you can save your progress by going to \"File -> Save Pyramid\" and then later "
            "continue building by loading from \"File -> Load Pyramid\". Once you have finished "
            "your pyramid, or if you want to test your progress in-game, you can export it "
            "directly to a .XEX file, but first you'll need to import the original game's .XEX. "
            "Go to \"File -> Import Original XEX File\" and locate the Montezuma's Revenge game "
            "(usually called \"Preliminary Monty.XEX\" for reasons) and then you will be able "
            "to save to a new .XEX file, or overwrite one you've already created, by going to "
            "\"File -> Export XEX File\" and entering a new name for your game (just make sure you "
            "don't overwrite the original game). So far, this programme "
            "only uses the .XEX format, other formats are not supported."

            "\n\n---------------------------\n\n"

            "THE TOOLS\n\n"

            "SPACE: Creates a rectangle of space in the screen. Useful to carve inside a wall. All "
            "rectangle tools are click-drag-release.\n\n"
            "WALL: Creates a rectangle of wall in the screen.\n\n"
            "SPACE TRIANGLE: Creates a triangle of space.\n\n"
            "WALL TRIANGLE: Creates a triangle of wall. The way triangles work is, after you click, "
            "the vertical side of the triangle is drawn first, the horizontal last. This tool is very useful "
            "to give the room that typical pyramid feel that is prevalent in the game.\n\n"
            "BRICKS: Draws a horizontal line of small bricks.\n\n"
            "ITEMS: Inserts an item at a specific location on the room. The tile you click is the "
            "top left tile of the 2x2 sprite\n\n"
            "ENEMIES: Inserts an enemy the same way as the items above. Read the guidelines below "
            "to check the allowed coordinates for enemies.\n\n"
            "DOORS: Inserts a door of the desired colour in the room. The tile you click is the top "
            "of the door, however the game will also insert a wall tile on top.\n\n"
            "ROPE: Inserts a rope of arbitrary length.\n\n"
            "TUBE: Same as the rope tool.\n\n"
            "CHAIN: Inserts a 1x4 chain.\n\n"
            "LADDER: Creates a ladder of the desired length.\n\n"
            "PLATFORM: Inserts a disappearing horizontal platform of an arbitraty length.\n\n"
            "TREADMILL: Inserts a treadmill of the desired length. It can move left or right.\n\n"
            "FIRE: Creates a rectangle of fire in the screen, the top of which displays flames.\n\n"
            "COPY: A special command that lets you copy another room, in order to save ROM space. "
            "Only the structure of the room is copied; items, doors, and enemies are ignored. "
            "Note that if you later change the copied room, then this room will also change accordingly.\n\n"
            "MIRRORED COPY: Same as above but the copied room is flipped horizontally.\n\n"
            "LEVEL: This is a modifier that makes subsequent objects drawn in the room to apperar only "
            "from the chosen level. You can always choose which level is displayed using the \"Level View\" "
            "combo at the bottom right.\n\n"

            "---------------------------\n\n"

            "GUIDELINES\n\n"

            "Since this programme does not modify any of the game's logic, some guidelines are "
            "necessary for creating rooms:\n\n"
            "1. You will have surely noticed that in the original game, horizontal screen transitions "
            "happen always at the same level (when the floor is at y-coordinate 10). And while "
            "this is not mandatory and you can safely transition at any height in the room, if you were "
            "to die, you will respawn at Y coordinate 10, and not at the location where you came into the "
            "room, which can cause unexpected results. An easy workaround this problem is to simple make it "
            "impossible to die in rooms where you transition at levels other than 10. Maybe in a second "
            "version of this programme a custom behaviour could be patched into the code, but for now "
            "it is solely focused on creating room data.\n\n"

            "2. Similarly to the horizontal room transitions, vertical transitions always happen "
            "through a ladder drawn at x-coordinates 20-21. Again, there is nothing stopping you from "
            "creating a different transition, but if you die the player may respawn on a freefall or "
            "a softlock. The best way to check if a setup will work as you intend is to experiment.\n\n"

            "3. The game uses only half a byte for the x-coordinate of enemies, and another half a byte for "
            "the y-coordinate. In other words, there are only 16 positions for each coordinate. In the case "
            "of the y-coordinate the allowed positions are the bottom 16, so no enemies above coordinate 8. "
            "The allowed positions for the x-coordinate are 3, 5, 7, 9, 11, 13, 17, 18, 21, 23, 27, 29, 31, "
            "33, 35 and 37. That covers most of the screen so unless you want an enemy on a very precise "
            "location you'll be fine. You don't really need to worry about this though, because the programme "
            "will automatically snap your enemies to the closest allowed location.\n\n"

            "4. The game has 8 slots for items and doors, so in any room "
            "you can't have more than 8 items or doors, placing more than 8 will cause glitches. In the case "
            "of enemies there is also 8 slots and placing too many of them, or close to one another causes problems. "
            "In particular, snakes and spiders in the same room are a bad idea. There is only one room in the "
            "original game where there is a snake and a spider, and the latter is glitched.\n\n"

            "5. Always try to be efficient with the use of the tools. For example, it's usually better "
            "to carve out space inside a wall rather than drawing all the walls around that space. Also, "
            "never draw the level tile by tile, the game can draw a huge block of wall, space, or fire with "
            "a single instruction. The final size of the file depends on the number of tools used, not in the "
            "amount of tiles drawn on the screen. Nevertheless, this programme relocates the room data from "
            "its original address at $B495 to the new one at $4000 where there is ample space for about 4 full "
            "pyramids, so don't worry too much about this.\n\n"

            "6. In general if you are unsure about something, you don't lose anything by experimenting. "
            "This programme is very small and simple and there is a lot of room for improvement. If you "
            "have any doubts you can find me as @lewdaney6373 (Lew Daney) on YouTube."
            

        )
        text_widget.insert("1.0", faq_text)
        text_widget.config(state="disabled")

        faq_window.transient(self.root)
        faq_window.grab_set()
        self.root.wait_window(faq_window)

    def set_tool(self, tool, subtype):
        self.active_tool = tool; self.tool_subtype = subtype
        self.triangle_points = []
        tool_text = f"[Tool: {tool} - {subtype}]" if tool else ""
        self.root.title(f"Montezuma's Revenge Level Editor 1.0 - Room {self.current_room_id} {tool_text}")

    def generate_all_tile_images(self):
        self.tile_cache = {}
        if self.tile_width < 1 or self.tile_height < 1: return

        for key, data in TILE_DATA.items():
            sprite = data['sprite']; h, w = len(sprite), len(sprite[0])
            for y in range(0, h, SPRITE_DIMENSION):
                for x in range(0, w, SPRITE_DIMENSION):
                    img = tk.PhotoImage(width=self.tile_width, height=self.tile_height)
                    chunk = [row[x:x+SPRITE_DIMENSION] for row in sprite[y:y+SPRITE_DIMENSION]]
                    
                    pixel_w = self.tile_width / SPRITE_DIMENSION
                    pixel_h = self.tile_height / SPRITE_DIMENSION

                    for sy in range(SPRITE_DIMENSION):
                        for sx in range(SPRITE_DIMENSION):
                            color = chunk[sy][sx]
                            x1, y1 = int(sx * pixel_w), int(sy * pixel_h)
                            x2, y2 = int((sx + 1) * pixel_w), int((sy + 1) * pixel_h)
                            if x2 > x1 and y2 > y1:
                                img.put(color, to=(x1, y1, x2, y2))
                    self.tile_cache[f"{key}_{y//8}_{x//8}"] = img
    
    def _render_object_list(self, object_list, grid, mirror=False, exclude_movables=False, recursion_depth=0, view_level=4):
        if recursion_depth > 5: return
        tile_map = {key: f"{key}_0_0" for key in TILE_DATA}
        
        current_level = 1

        for obj in object_list:
            if obj['type'] == 'special' and obj['subtype'] == 'level':
                current_level = obj.get('target_room', 1)
                continue

            if current_level > view_level:
                continue

            st = obj.get('subtype', '')
            if exclude_movables and (st.startswith('item_') or st.startswith('enemy_') or st.startswith('door_')):
                continue

            if obj['type'] == 'special' and obj['subtype'] in ['copy', 'copy_m']:
                target_room = obj.get('target_room')
                if target_room is not None and target_room in self.rooms:
                    is_mirror = obj['subtype'] == 'copy_m'
                    self._render_object_list(self.rooms[target_room], grid, mirror=is_mirror, exclude_movables=True, recursion_depth=recursion_depth+1, view_level=view_level)
                continue

            obj_x, obj_y = obj.get('x',0), obj.get('y',0)
            if mirror:
                obj_w = obj.get('w',1)
                obj_x = GRID_WIDTH - obj_x - obj_w

            t = obj['type']
            if t == 'rect':
                w, h = obj['w'], obj['h']
                for y_offset in range(h):
                    for x_offset in range(w):
                        x, y = obj_x + x_offset, obj_y + y_offset
                        if 0 <= x < GRID_WIDTH and 0 <= y < GRID_HEIGHT:
                            if st == 'fire':
                                sprite_x_chunk = x_offset % 4
                                sprite_y_chunk = 0 if y == obj_y else 1
                                grid[y][x] = f"{st}_{sprite_y_chunk}_{sprite_x_chunk}"
                            else:
                                grid[y][x] = tile_map[st]
            elif t in ['line', 'hline']:
                    w = obj['w']
                    for x_offset in range(w):
                        x = obj_x + (w - 1 - x_offset if mirror else x_offset)
                        if 0 <= x < GRID_WIDTH and 0 <= obj_y < GRID_HEIGHT:
                            if st.startswith("treadmill"):
                                if x_offset == 0: grid[obj_y][x] = f"{st}_0_2" if mirror else f"{st}_0_0"
                                elif x_offset == w - 1: grid[obj_y][x] = f"{st}_0_0" if mirror else f"{st}_0_2"
                                else: grid[obj_y][x] = f"{st}_0_1"
                            else: grid[obj_y][x] = tile_map[st]
            elif t in ['point', 'vline', 'chain']:
                    h = 4 if t == 'chain' else obj.get('h', 1)
                    for y in range(obj_y, obj_y + h):
                        if 0 <= obj_x < GRID_WIDTH and 0 <= y < GRID_HEIGHT:
                            if st == 'rope': grid[y][obj_x] = tile_map[st] if y == obj_y else f"{st}_1_0"
                            else: grid[y][obj_x] = tile_map[st]
            elif t == 'ladder':
                h = obj['h']
                for y_offset in range(h):
                    for x_offset in range(2):
                        x = obj_x + x_offset
                        y = obj_y + y_offset
                        if 0 <= x < GRID_WIDTH and 0 <= y < GRID_HEIGHT:
                            is_top = (y == obj_y and y > 0); sprite_y = 0 if is_top else 1
                            grid[y][x] = f"{st}_{sprite_y}_{x_offset}"
            elif t in ['item', 'enemy']:
                for y_offset in range(2):
                    for x_offset in range(2):
                        y, x = obj_y + y_offset, obj_x + x_offset
                        if 0 <= x < GRID_WIDTH and 0 <= y < GRID_HEIGHT:
                            grid[y][x] = f"{st}_{y_offset}_{x_offset}"
            elif t == 'door':
                if 0 <= obj_x < GRID_WIDTH and obj_y > 0: grid[obj_y-1][obj_x] = tile_map['wall']
                for y_offset in range(4):
                    y = obj_y + y_offset
                    if 0 <= obj_x < GRID_WIDTH and 0 <= y < GRID_HEIGHT: grid[y][obj_x] = tile_map[st]
            elif t == 'triangle':
                x0, y0, d, s = obj['x'], obj['y'], obj['dir'], obj['size']
                y_dir = -1 if 'u' in d else 1
                x_dir = -1 if 'l' in d else 1
                
                p1 = (x0, y0)
                p2 = (x0, y0 + (s - 1) * y_dir)
                p3 = (x0 + (s - 1) * x_dir, y0 + (s - 1) * y_dir)

                if mirror:
                    p1 = (GRID_WIDTH - 1 - p1[0], p1[1])
                    p2 = (GRID_WIDTH - 1 - p2[0], p2[1])
                    p3 = (GRID_WIDTH - 1 - p3[0], p3[1])

                min_x = max(0, min(p1[0], p2[0], p3[0]))
                max_x = min(GRID_WIDTH - 1, max(p1[0], p2[0], p3[0]))
                min_y = max(0, min(p1[1], p2[1], p3[1]))
                max_y = min(GRID_HEIGHT - 1, max(p1[1], p2[1], p3[1]))

                for y in range(min_y, max_y + 1):
                    for x in range(min_x, max_x + 1):
                        d_val = ((p2[1]-p3[1])*(p1[0]-p3[0]) + (p3[0]-p2[0])*(p1[1]-p3[1]))
                        if d_val == 0: continue
                        w1 = ((p2[1]-p3[1])*(x-p3[0]) + (p3[0]-p2[0])*(y-p3[1])) / d_val
                        w2 = ((p3[1]-p1[1])*(x-p3[0]) + (p1[0]-p3[0])*(y-p3[1])) / d_val
                        w3 = 1 - w1 - w2
                        if w1 >= -1e-9 and w2 >= -1e-9 and w3 >= -1e-9:
                            grid[y][x] = tile_map[st]

    def _draw_background(self):
        self.canvas.delete("all")

    def _draw_grid_overlay(self):
        if self.grid_visible.get():
            canvas_w = GRID_WIDTH * self.tile_width
            canvas_h = GRID_HEIGHT * self.tile_height
            for x in range(0, canvas_w + 1, self.tile_width): 
                self.canvas.create_line(x, 0, x, canvas_h, fill="#484848", tags="grid")
            for y in range(0, canvas_h + 1, self.tile_height): 
                self.canvas.create_line(0, y, canvas_w, y, fill="#484848", tags="grid")

    def _draw_highlight(self):
        self.canvas.delete("highlight")
        if self.selected_object_index is None: return

        try:
            obj = self.rooms[self.current_room_id][self.selected_object_index]
        except (IndexError, KeyError):
            return

        def get_bbox(o):
            x, y = o.get('x', 0), o.get('y', 0)
            w, h = o.get('w', 1), o.get('h', 1)
            t, st = o['type'], o.get('subtype', '')

            if t == 'triangle':
                s = o['size']
                y_dir = -1 if 'u' in o['dir'] else 1
                x_dir = -1 if 'l' in o['dir'] else 1
                p1 = (x, y)
                p2 = (x, y + (s - 1) * y_dir)
                p3 = (x + (s - 1) * x_dir, y + (s - 1) * y_dir)
                min_x = min(p1[0], p2[0], p3[0])
                max_x = max(p1[0], p2[0], p3[0])
                min_y = min(p1[1], p2[1], p3[1])
                max_y = max(p1[1], p2[1], p3[1])
                return [min_x, min_y, max_x + 1, max_y + 1]
            elif t in ['item', 'enemy']: return [x, y, x + 2, y + 2]
            elif t == 'door': return [x, y, x + 1, y + 4]
            elif t == 'ladder': return [x, y, x + 2, y + h]
            elif t == 'chain': return [x, y, x + 1, y + 4]
            elif st in ['rope', 'tube']:
                return [x, y, x + 1, y + h]
            elif st in ['bricks', 'platform', 'treadmill_left', 'treadmill_right']:
                return [x, y, x + w, y + 1]
            elif t == 'special': return None
            else: return [x, y, x + w, y + h]

        bbox = get_bbox(obj)
        if bbox:
            x1, y1 = bbox[0] * self.tile_width, bbox[1] * self.tile_height
            x2, y2 = bbox[2] * self.tile_width, bbox[3] * self.tile_height
            self.canvas.create_rectangle(x1, y1, x2, y2, outline="#FFD700", width=2, tags="highlight")

    def render_and_draw(self):
        self._draw_background()
        grid = [[0 for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]
        
        try:
            view_level = int(self.level_view_var.get().split(" ")[1])
        except (ValueError, IndexError):
            view_level = 1
        
        default_objects_to_draw = self.default_screen_objects
        if self.current_room_id == 100:
            default_objects_to_draw = [
                obj for obj in self.default_screen_objects 
                if obj.get('subtype', '').startswith('frame_')
            ]

        self._render_object_list(default_objects_to_draw, grid, view_level=view_level)
        self._render_object_list(self.rooms.get(self.current_room_id, []), grid, view_level=view_level)

        self.empty_tile_id = 'empty_0_0'
        for y in range(GRID_HEIGHT):
            for x in range(GRID_WIDTH):
                tile_key = grid[y][x] if grid[y][x] != 0 else self.empty_tile_id
                img = self.tile_cache.get(tile_key)
                if img: self.canvas.create_image(x*self.tile_width, y*self.tile_height, image=img, anchor="nw")
        
        self._draw_grid_overlay()
        self._draw_highlight()

    def _format_object_as_string(self, obj):
        keyword_map = {
            "empty": "space", "wall": "wall", "bricks": "bricks", 
            "door_white": "door_w", "door_blue": "door_b", "door_red": "door_r",
            "item_key_white": "key_w", "item_key_blue": "key_b", "item_key_red": "key_r", 
            "ladder": "ladder", "tube": "tube", "rope": "rope", "chain": "chain",
            "platform": "plat", "treadmill_left": "tread_l", "treadmill_right": "tread_r",
            "enemy_skull": "skull", "enemy_skull_f": "skull_f", 
            "enemy_b_skull": "b_skull", "enemy_b_skull_f": "b_skull_f",
            "enemy_spider": "spider", "enemy_spider_f": "spider_f", "enemy_snake": "snake"
        }
        
        t, st = obj['type'], obj.get('subtype', '')
        keyword = keyword_map.get(st, st.replace("item_","").replace("enemy_",""))
        parts = [keyword]

        if t == 'triangle':
            parts[0] = "space_t" if st == "empty" else "wall_t"
            parts.append(str(obj['x'] + 1))
            parts.append(str(obj['y'] + 1))
            parts.append(obj['dir'])
            parts.append(str(obj['size']))
        elif t == 'special':
            parts.append(str(obj.get('target_room', 0)))
        else:
            x, y = obj.get('x', -1) + 1, obj.get('y', -1) + 1
            w, h = obj.get('w', 0), obj.get('h', 0)

            if st.startswith("enemy_"): y += 1

            parts.append(str(x)); parts.append(str(y))

            if st in ["empty", "wall", "fire"]:
                parts.append(str(w)); parts.append(str(h))
            elif st in ["rope", "tube", "ladder"]:
                parts.append(str(h))
            elif st in ["bricks", "platform", "treadmill_left", "treadmill_right"]:
                parts.append(str(w))
            elif t in ['line', 'hline', 'vline']:
                if w > 1: parts.append(str(w))
                if h > 1: parts.append(str(h))
                
        return " ".join(parts)

    def update_object_listbox(self):
        self.object_listbox.delete(0, tk.END)
        current_objects = self.rooms.get(self.current_room_id, [])
        for obj in current_objects:
            self.object_listbox.insert(tk.END, self._format_object_as_string(obj))

    def _snap_to_closest(self, value, targets):
        return min(targets, key=lambda x: abs(x - value))

    def on_canvas_press(self, event):
        if not self.active_tool:
            self._deselect_object()
            return
            
        pos = self.get_grid_coords(event)
        if not pos: return

        if self.active_tool == 'ladder' and pos[0] >= GRID_WIDTH - 1:
            return

        if self.active_tool in ['item', 'enemy']:
            if pos[0] >= GRID_WIDTH - 1 or pos[1] >= GRID_HEIGHT - 1:
                return
        elif self.active_tool in ['door', 'chain']:
            if pos[1] >= GRID_HEIGHT - 3:
                return
        
        if self.active_tool.startswith('enemy'):
            if pos[1] < 7:
                return
            snapped_x = self._snap_to_closest(pos[0], self.ENEMY_X_POS)
            pos = (snapped_x, pos[1])
        
        if self.active_tool in ['item', 'enemy', 'door', 'chain', 'point']:
            selection = self.object_listbox.curselection()
            insert_idx = selection[0] + 1 if selection else len(self.rooms[self.current_room_id])
            obj_to_add = {'type': self.active_tool, 'subtype': self.tool_subtype, 'x': pos[0], 'y': pos[1]}
            
            self.rooms[self.current_room_id].insert(insert_idx, obj_to_add)
            self.update_object_listbox()
            self.object_listbox.selection_set(insert_idx)
            self.object_listbox.see(insert_idx)
            self._on_object_select()
            self._draw_pyramid_selector()
        else:
            self.triangle_points = [pos]

    def on_canvas_drag(self, event):
        if not self.triangle_points: return
        self.render_and_draw()
        
        start_pos = self.triangle_points[0]
        
        if self.active_tool == 'triangle':
            current_pos = self.get_grid_coords(event)
            if not current_pos: return

            side_len_tiles = abs(current_pos[1] - start_pos[1])
            y_dir = 1 if current_pos[1] >= start_pos[1] else -1
            x_dir = 1 if current_pos[0] >= start_pos[0] else -1

            p2_grid = (start_pos[0], start_pos[1] + side_len_tiles * y_dir)
            p3_grid = (start_pos[0] + side_len_tiles * x_dir, p2_grid[1])

            p1_px = (start_pos[0] * self.tile_width + self.tile_width / 2, start_pos[1] * self.tile_height + self.tile_height / 2)
            p2_px = (p2_grid[0] * self.tile_width + self.tile_width / 2, p2_grid[1] * self.tile_height + self.tile_height / 2)
            p3_px = (p3_grid[0] * self.tile_width + self.tile_width / 2, p3_grid[1] * self.tile_height + self.tile_height / 2)

            self.canvas.create_line(p1_px, p2_px, fill="white", dash=(4, 4))
            self.canvas.create_line(p2_px, p3_px, fill="white", dash=(4, 4))
            self.canvas.create_line(p3_px, p1_px, fill="yellow", dash=(4, 4))
        else:
            start_px_x, start_px_y = start_pos[0] * self.tile_width, start_pos[1] * self.tile_height
            self.canvas.create_rectangle(start_px_x, start_px_y, event.x, event.y, outline="white", dash=(4,4))

    def on_canvas_release(self, event):
        if not self.triangle_points: return
        
        start_pos = self.triangle_points[0]
        end_pos = self.get_grid_coords(event)
        if not end_pos: return
        
        obj = None

        if self.active_tool == 'triangle':
            size = abs(end_pos[1] - start_pos[1]) + 1
            y_dir_str = 'd' if end_pos[1] >= start_pos[1] else 'u'
            x_dir_str = 'r' if end_pos[0] >= start_pos[0] else 'l'
            obj = {
                'type': 'triangle', 'subtype': self.tool_subtype, 
                'x': start_pos[0], 'y': start_pos[1], 
                'dir': y_dir_str + x_dir_str, 'size': size
            }
        else:
            x1, y1 = start_pos; x2, y2 = end_pos
            min_x, max_x = min(x1, x2), max(x1, x2)
            min_y, max_y = min(y1, y2), max(y1, y2)
            obj = {'type': self.active_tool, 'subtype': self.tool_subtype, 
                   'x': min_x, 'y': min_y, 
                   'w': max_x - min_x + 1, 'h': max_y - min_y + 1}
        
        if obj:
            selection = self.object_listbox.curselection()
            insert_idx = selection[0] + 1 if selection else len(self.rooms[self.current_room_id])
            
            self.rooms[self.current_room_id].insert(insert_idx, obj)
            self.update_object_listbox()
            self.object_listbox.selection_set(insert_idx)
            self.object_listbox.see(insert_idx)
            self._on_object_select()
            self._draw_pyramid_selector()
            
        self.triangle_points = []

    def get_grid_coords(self, event):
        if self.tile_width <= 0 or self.tile_height <= 0: return None
        x = max(0, min(GRID_WIDTH - 1, event.x // self.tile_width))
        y = max(0, min(GRID_HEIGHT - 1, event.y // self.tile_height))
        return (x, y)
    
    def _on_mouse_hover(self, event):
        coords = self.get_grid_coords(event)
        if coords:
            self.coords_label.config(text=f"Coords: ({coords[0] + 1}, {coords[1] + 1})")
        else:
            self.coords_label.config(text="Coords: (-, -)")

    def _on_mouse_leave(self, event):
        self.coords_label.config(text="Coords: (-, -)")
    
    def _on_object_select(self, event=None):
        selection = self.object_listbox.curselection()
        if selection:
            self.selected_object_index = selection[0]
        else:
            self.selected_object_index = None
        self.render_and_draw()

    def _deselect_object(self, event=None):
        if self.selected_object_index is not None:
            self.selected_object_index = None
            self.object_listbox.selection_clear(0, tk.END)
            self.render_and_draw()
        return "break"

    def _on_level_view_change(self, event):
        self.render_and_draw()

    def load_room(self, room_id):
        self.current_room_id = room_id
        self.selected_object_index = None
        self.render_and_draw()
        self.update_object_listbox()
        self._draw_pyramid_selector()
        tool_text = f"[Tool: {self.active_tool} - {self.tool_subtype}]" if self.active_tool else ""
        self.root.title(f"Montezuma's Revenge Level Editor 1.0 - Room {self.current_room_id} {tool_text}")
    
    def clear_room(self):
        if messagebox.askyesno("Clear Room", f"Revert Room {self.current_room_id} to default?"): 
            view = self.object_listbox.yview()
            self.rooms[self.current_room_id] = []
            self._deselect_object()
            self.render_and_draw(); self.update_object_listbox(); self._draw_pyramid_selector()
            self.object_listbox.yview_moveto(view[0])
            
    def delete_object(self):
        selection = self.object_listbox.curselection()
        if selection: 
            view = self.object_listbox.yview()
            self.rooms[self.current_room_id].pop(selection[0])
            self._deselect_object()
            self.render_and_draw(); self.update_object_listbox(); self._draw_pyramid_selector()
            self.object_listbox.yview_moveto(view[0])
            
    def move_object(self, direction):
        selection = self.object_listbox.curselection()
        if not selection: return
        
        idx = selection[0]
        new_idx = idx + direction

        if 0 <= new_idx < len(self.rooms[self.current_room_id]):
            obj = self.rooms[self.current_room_id].pop(idx)
            self.rooms[self.current_room_id].insert(new_idx, obj)
            self.selected_object_index = new_idx
            self.update_object_listbox()
            self.object_listbox.selection_set(new_idx)
            self.object_listbox.see(new_idx)
            self.render_and_draw()

    def add_special_command(self, subtype):
        prompt = f"Enter level number (2-4):" if subtype == 'level' else f"Enter room number for '{subtype}':"
        min_val = 2 if subtype == 'level' else 0
        max_val = 4 if subtype == 'level' else MAX_ROOMS
        
        num = simpledialog.askinteger("Input", prompt, parent=self.root, minvalue=min_val, maxvalue=max_val)
        if num is not None:
            obj = {'type': 'special', 'subtype': subtype, 'target_room': num}
            selection = self.object_listbox.curselection()
            insert_idx = selection[0] + 1 if selection else len(self.rooms[self.current_room_id])
            
            self.rooms[self.current_room_id].insert(insert_idx, obj)
            self.update_object_listbox()
            self.object_listbox.selection_set(insert_idx)
            self.object_listbox.see(insert_idx)
            self._on_object_select()
            self._draw_pyramid_selector()

    def _import_original_XEX_file(self):

        filepath = filedialog.askopenfilename(filetypes=[("XEX Files", "*.xex")], title="Open original XEX file")
        if not filepath:
            return
        try:
            with open(filepath, 'rb') as file:
                self.original_xex = bytearray(file.read())
        except Exception as e:
            messagebox.showerror("Import Error", f"Couldn't open file. Error: {e}")

        self.file_menu.entryconfig("Export XEX File", state="normal")
            
    def _export_final_XEX_file(self):
        output_lines = []
        for room_id in range(MAX_ROOMS + 1):
            output_lines.append(f"room {room_id}")
            room_objects = self.rooms.get(room_id, [])
            if room_objects:
                for obj in room_objects:
                    output_lines.append(self._format_object_as_string(obj))
            output_lines.append("")
        
        output_lines.append("room 101")
        final_text = "\n".join(output_lines)
        self.ExportXEX(final_text, self.original_xex)

    def _draw_pyramid_selector(self):
        self.pyramid_canvas.delete("all")
        canvas_width = self.pyramid_canvas.winfo_width()
        if canvas_width <= 1: return
        
        full_square_size = PYRAMID_SQUARE_SIZE + PYRAMID_SQUARE_PADDING

        for room_id in range(MAX_ROOMS):
            level = int(math.sqrt(room_id))
            pos_in_level = room_id - level**2
            level_width_rooms = 2 * level + 1
            
            x_start = (canvas_width / 2) - (level_width_rooms / 2 * full_square_size)
            
            x1 = x_start + pos_in_level * full_square_size
            y1 = level * full_square_size
            x2 = x1 + PYRAMID_SQUARE_SIZE
            y2 = y1 + PYRAMID_SQUARE_SIZE

            color = PYRAMID_COLOR_EMPTY
            if room_id == self.current_room_id:
                color = PYRAMID_COLOR_CURRENT
            elif self.rooms.get(room_id):
                color = PYRAMID_COLOR_NON_EMPTY

            tag = f"room_{room_id}"
            self.pyramid_canvas.create_rectangle(x1, y1, x2, y2, fill=color, outline="#222", tags=(tag, "room_square"))
            self.pyramid_canvas.create_text(x1 + PYRAMID_SQUARE_SIZE / 2, y1 + PYRAMID_SQUARE_SIZE / 2, text=str(room_id), font=PYRAMID_FONT, tags=(tag, "room_text"))

        level9_width_rooms = 19
        room90_pos_in_level = 90 - 9**2
        x_start_level9 = (canvas_width / 2) - (level9_width_rooms / 2 * full_square_size)
        x1_room100 = x_start_level9 + room90_pos_in_level * full_square_size
        y1_room100 = 10 * full_square_size
        x2_room100 = x1_room100 + PYRAMID_SQUARE_SIZE
        y2_room100 = y1_room100 + PYRAMID_SQUARE_SIZE

        color = PYRAMID_COLOR_EMPTY
        if 100 == self.current_room_id: color = PYRAMID_COLOR_CURRENT
        elif self.rooms.get(100): color = PYRAMID_COLOR_NON_EMPTY

        tag = "room_100"
        self.pyramid_canvas.create_rectangle(x1_room100, y1_room100, x2_room100, y2_room100, fill=color, outline="#222", tags=(tag, "room_square"))
        self.pyramid_canvas.create_text(x1_room100 + PYRAMID_SQUARE_SIZE / 2, y1_room100 + PYRAMID_SQUARE_SIZE / 2, text="100", font=PYRAMID_FONT, tags=(tag, "room_text"))

    def _on_pyramid_click(self, event):
        self._deselect_object()
        item = self.pyramid_canvas.find_closest(event.x, event.y)
        if not item: return
        
        tags = self.pyramid_canvas.gettags(item[0])
        for tag in tags:
            if tag.startswith("room_"):
                try:
                    room_id = int(tag.split("_")[1])
                    if room_id != self.current_room_id:
                        self.load_room(room_id)
                except (ValueError, IndexError):
                    continue
                break

    def save_maps_to_file(self):
        filepath = filedialog.asksaveasfilename(defaultextension=".json", filetypes=[("JSON Files", "*.json")], title="Save Pyramid File")
        if not filepath: return
        try:
            with open(filepath, 'w') as f:
                json.dump(self.rooms, f, indent=2)
            messagebox.showinfo("Success", f"Room data saved to {filepath}")
        except Exception as e:
            messagebox.showerror("Error", f"Failed to save maps: {e}")

    def load_maps_from_file(self):
        filepath = filedialog.askopenfilename(filetypes=[("JSON Files", "*.json")], title="Load Pyramid File")
        if not filepath: return
        try:
            with open(filepath, 'r') as f:
                loaded_data = json.load(f)

            self.rooms = {int(k): v for k, v in loaded_data.items()}

            self.generate_all_tile_images()
            self.load_room(self.current_room_id)
            messagebox.showinfo("Success", f"Pyramid data loaded from {filepath}")
        except Exception as e:
            messagebox.showerror("Error", f"Failed to load maps: {e}")

    def ExportXEX(self, data_string, original_xex_file):
        dec = Decoder(data_string, original_xex_file)
        dec.Export()

class Decoder:

    def __init__(self, text, original_xex_file):
        self.data = text
        self.original_game = original_xex_file
        #self.MONTEZUMA = bytearray()
        self.hack = bytearray()
        self.room_data = bytearray()
        self.address_data = bytearray()
        self.n_bytes = list()
        self.bra = 0x4000
        #self.bra = 0xB495
        self.baa = 0x8F20
        self.enemy_pos = (3,5,7,9,11,13,17,18,21,23,27,29,31,33,35,37)

    def Export(self):
        self.CreateRoomData()
        self.CreateAddressData()
        self.CreateHack()
        self.CreateXEXFile()

    def CreateRoomData(self):
        data_size = 0
        for line in self.data.splitlines():
            if "room" in line:
                self.n_bytes.append(len(self.room_data) - data_size)
                data_size = len(self.room_data)
            else:
                tokens = line.split()
                if len(tokens) == 0:
                    continue
                else:
                    bytes_in_the_command_line = self.GetBytes(tokens)
                    for b in bytes_in_the_command_line:
                        self.room_data.append(b)
        self.n_bytes.append(len(self.room_data) - data_size)

    def CreateAddressData(self):
        bra_aux = self.bra
        if len(self.n_bytes) == 0:
            return
        for n in self.n_bytes:
            bra_aux = bra_aux + n
            self.address_data.append(bra_aux & 0xFF)
            self.address_data.append(bra_aux >> 8)
        last = self.address_data[len(self.address_data) - 1]
        prev = self.address_data[len(self.address_data) - 2]

        for i in range(len(self.address_data) + 1, 203, 2):
            self.address_data.append(prev)
            self.address_data.append(last)

    def CreateHack(self):
        ead = self.baa + len(self.address_data) - 1

        self.hack.append(self.baa & 0xFF)
        self.hack.append(self.baa >> 8)
        self.hack.append(ead & 0xFF)
        self.hack.append(ead >> 8)

        for b in self.address_data:
            self.hack.append(b)

        erd = self.bra + len(self.room_data) - 1

        self.hack.append(self.bra & 0xFF)
        self.hack.append(self.bra >> 8)
        self.hack.append(erd & 0xFF)
        self.hack.append(erd >> 8)

        for b in self.room_data:
            self.hack.append(b)

    def CreateXEXFile(self):
        aux_data = bytearray()
        for b in self.original_game:
            aux_data.append(b)
        for b in self.hack:
            aux_data.append(b)
        try:
            filepath = filedialog.asksaveasfilename(defaultextension=".xex", filetypes=[("XEX Files", "*.xex")], title="Save new XEX file")
            if not filepath:
                return
            with open(filepath, 'wb') as file:
                file.write(aux_data)
            messagebox.showinfo("Export Successful", "New file created.")
        except Exception as e:
            messagebox.showerror("Export Error", f"An unexpected error occurred: {e}")

    def GetTwoBytesForAddress(self, x, y, c):
        if c == "door_r" or c == "door_b" or c == "door_w":
            y = y - 1
        ad = 0x3800
        ad = ad + (x - 1) + 40 * (y - 1)
        hi = ((ad >> 8) - (0x3800 >> 8)) << 6
        lo = ad & 0xFF
        bytes = bytearray()
        bytes.append(hi)
        bytes.append(lo)
        return bytes

    def GetClosestEnemyIndex(self, i):
        min_dif = 100
        index = 0
        for j in range(len(self.enemy_pos)):
            x = self.enemy_pos[j]
            dif = x - i
            if dif < 0:
                dif = -dif
            if (dif < min_dif):
                index = j
                min_dif = dif
        return index

    def Loc(self, v, pos, f):
        v.append(pos[0] + f)
        v.append(pos[1])

    def Dim(self, v, dim, n):
        for i in range(n):
            v.append(dim[i])

    def GetBytes(self, t):

        command = t[0]
        res = bytearray()
        pos = bytearray([0,0])
        dim = bytearray()

        if len(t) >= 3:
            pos = self.GetTwoBytesForAddress(int(t[1]), int(t[2]),command);
        if len(t) >= 4 and command != "wall_t" and command != "space_t":
            dim.append(int(t[3]))
        if len(t) >= 5 and command != "wall_t" and command != "space_t":
            dim.append(int(t[4]))

        match command:

            case "wall":
                if dim[0] <= 15 and dim[1] <= 15:
                    self.Loc(res, pos, 3)
                    res.append((dim[0] << 4) + (dim[1] & 0x0F))
                else:
                    self.Loc(res, pos, 2)
                    self.Dim(res, dim, 2)

            case "space":
                if dim[0] <= 15 and dim[1] <= 15:
                    self.Loc(res, pos, 1)
                    res.append((dim[0] << 4) + (dim[1] & 0x0F))
                else:
                    self.Loc(res, pos, 0)
                    self.Dim(res, dim, 2)

            case "bricks":
                self.Loc(res, pos, 4)
                self.Dim(res, dim, 1)

            case "amulet":
                self.Loc(res, pos, 5)

            case "shield":
                self.Loc(res, pos, 6)

            case "sword":
                self.Loc(res, pos, 7)

            case "torch":
                self.Loc(res, pos, 8)

            case "key_r":
                self.Loc(res, pos, 9)

            case "key_b":
                self.Loc(res, pos, 10)

            case "key_w":
                self.Loc(res, pos, 11)

            case "door_r":
                self.Loc(res, pos, 12)

            case "door_b":
                self.Loc(res, pos, 13)

            case "door_w":
                self.Loc(res, pos, 14)

            case "rope":
                self.Loc(res, pos, 15)
                self.Dim(res, dim, 1)

            case "tube":
                self.Loc(res, pos, 16)
                self.Dim(res, dim, 1)

            case "chain":
                self.Loc(res, pos, 17)

            case "plat":
                self.Loc(res, pos, 18)
                self.Dim(res, dim, 1)

            case "tread_l":
                self.Loc(res, pos, 19)
                self.Dim(res, dim, 1)

            case "tread_r":
                self.Loc(res, pos, 20)
                self.Dim(res, dim, 1)

            case "ladder":
                if int(t[2]) > 1:
                    self.Loc(res, pos, 21)
                else:
                    self.Loc(res, pos, 22)
                self.Dim(res, dim, 1)

            case "wall_t":
                self.Loc(res, pos, 23)
                b = int(t[4])
                if t[3] == "ur":
                    b = b + 16
                elif t[3] == "dr":
                    b = b + 32
                elif t[3] == "dl":
                    b = b + 48
                res.append(b)

            case "space_t":
                self.Loc(res, pos, 24)
                b = int(t[4])
                if t[3] == "ur":
                    b = b + 16
                elif t[3] == "dr":
                    b = b + 32
                elif t[3] == "dl":
                    b = b + 48
                res.append(b)

            case "fire":
                self.Loc(res, pos, 25)
                self.Dim(res, dim, 2)

            case "skull":
                res.append(0x20)
                p = (int(t[2]) - 9) << 4
                p = p + (self.GetClosestEnemyIndex(int(t[1])) & 0x0F)
                res.append(p)

            case "skull_f":
                res.append(0x24)
                p = (int(t[2]) - 9) << 4
                p = p + (self.GetClosestEnemyIndex(int(t[1])) & 0x0F)
                res.append(p)

            case "b_skull":
                res.append(0x21)
                p = (int(t[2]) - 9) << 4
                p = p + (self.GetClosestEnemyIndex(int(t[1])) & 0x0F)
                res.append(p)

            case "b_skull_f":
                res.append(0x25)
                p = (int(t[2]) - 9) << 4
                p = p + (self.GetClosestEnemyIndex(int(t[1])) & 0x0F)
                res.append(p)

            case "spider":
                res.append(0x62)
                p = (int(t[2]) - 9) << 4
                p = p + (self.GetClosestEnemyIndex(int(t[1])) & 0x0F)
                res.append(p)

            case "spider_f":
                res.append(0x66)
                p = (int(t[2]) - 9) << 4
                p = p + (self.GetClosestEnemyIndex(int(t[1])) & 0x0F)
                res.append(p)

            case "snake":
                res.append(0x63)
                p = (int(t[2]) - 9) << 4
                p = p + (self.GetClosestEnemyIndex(int(t[1])) & 0x0F)
                res.append(p)

            case "level":
                res.append(3 * 16 + int(t[1]) - 1)

            case "copy":
                res.append(0x3F)
                res.append(int(t[1]))

            case "copy_m":
                res.append(0x3E)
                res.append(int(t[1]))

        return res

if __name__ == "__main__":
    root = tk.Tk()
    app = TileMapEditor(root)
    root.mainloop()